Files
clang-p2996/llvm/test/CodeGen/PowerPC/pr45448.ll
Nikita Popov 060de415af Reapply [InstCombine] Simplify and/or of icmp eq with op replacement (#70335)
Relative to the first attempt, this contains two changes:

First, we only handle the case where one side simplifies to true or
false, instead of calling simplification recursively. The previous
approach would return poison if one operand simplified to poison
(under the equality assumption), which is incorrect.

Second, we do not fold llvm.is.constant in simplifyWithOpReplaced().
We may be assuming that a value is constant, if the equality holds,
but it may not actually be constant. This is nominally just a QoI
issue, but the std::list implementation in libstdc++ relies on the
precise behavior in a way that causes miscompiles.

-----

and/or in logical (select) form benefit from generic simplifications via
simplifyWithOpReplaced(). However, the corresponding fold for plain
and/or currently does not exist.

Similar to selects, there are two general cases for this fold
(illustrated with `and`, but there are `or` conjugates).

The basic case is something like `(a == b) & c`, where the replacement
of a with b or b with a inside c allows it to fold to true or false.
Then the whole operation will fold to either false or `a == b`.

The second case is something like `(a != b) & c`, where the replacement
inside c allows it to fold to false. In that case, the operand can be
replaced with c, because in the case where a == b (and thus the icmp is
false), c itself will already be false.

As the test diffs show, this catches quite a lot of patterns in existing
test coverage. This also obsoletes quite a few existing special-case
and/or of icmp folds we have (e.g. simplifyAndOrOfICmpsWithLimitConst),
but I haven't removed anything as part of this patch in the interest of
risk mitigation.

Fixes #69050.
Fixes #69091.
2023-11-03 10:16:15 +01:00

83 lines
2.7 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
; RUN: -mcpu=pwr9 -ppc-asm-full-reg-names -ppc-vsr-nums-as-vr < %s | \
; RUN: FileCheck %s
define hidden void @julia_tryparse_internal_45896() #0 {
; CHECK-LABEL: julia_tryparse_internal_45896:
; CHECK: # %bb.0: # %top
; CHECK-NEXT: ld r3, 0(r3)
; CHECK-NEXT: cmpldi r3, 0
; CHECK-NEXT: beq cr0, .LBB0_6
; CHECK-NEXT: # %bb.1: # %top
; CHECK-NEXT: cmpldi r3, 10
; CHECK-NEXT: beq cr0, .LBB0_3
; CHECK-NEXT: # %bb.2: # %top
; CHECK-NEXT: .LBB0_3: # %L294
; CHECK-NEXT: bc 12, 4*cr5+lt, .LBB0_5
; CHECK-NEXT: # %bb.4: # %L294
; CHECK-NEXT: bc 4, 4*cr5+lt, .LBB0_7
; CHECK-NEXT: .LBB0_5: # %L1057.preheader
; CHECK-NEXT: .LBB0_6: # %fail194
; CHECK-NEXT: .LBB0_7: # %L670
; CHECK-NEXT: li r5, -3
; CHECK-NEXT: sradi r4, r3, 63
; CHECK-NEXT: rldic r5, r5, 4, 32
; CHECK-NEXT: mulhdu r3, r3, r5
; CHECK-NEXT: maddld r6, r4, r5, r3
; CHECK-NEXT: cmpld cr1, r6, r3
; CHECK-NEXT: mulhdu. r3, r4, r5
; CHECK-NEXT: crorc 4*cr5+lt, 4*cr1+lt, eq
; CHECK-NEXT: bc 4, 4*cr5+lt, .LBB0_9
; CHECK-NEXT: # %bb.8: # %L917
; CHECK-NEXT: .LBB0_9: # %L994
top:
%0 = load i64, ptr undef, align 8
%1 = icmp ne i64 %0, 0
%2 = sext i64 %0 to i128
switch i64 %0, label %pass195 [
i64 10, label %L294
i64 16, label %L294.fold.split
i64 0, label %fail194
]
L294.fold.split: ; preds = %top
unreachable
L294: ; preds = %top
%3 = add nsw i32 0, -48
%4 = zext i32 %3 to i128
%5 = add i128 %4, 0
switch i32 undef, label %L670 [
i32 -1031471104, label %L1057.preheader
i32 536870912, label %L1057.preheader
]
L670: ; preds = %L294
br label %L898
L1057.preheader: ; preds = %L294, %L294
unreachable
L898: ; preds = %L670
%umul = call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %2, i128 %5)
%umul.ov = extractvalue { i128, i1 } %umul, 1
%value_phi102 = and i1 %1, %umul.ov
%6 = or i1 %value_phi102, false
br i1 %6, label %L917, label %L994
L917: ; preds = %L898
unreachable
L994: ; preds = %L898
unreachable
fail194: ; preds = %top
unreachable
pass195: ; preds = %top
unreachable
}
; Function Attrs: nounwind readnone speculatable willreturn
declare { i128, i1 } @llvm.umul.with.overflow.i128(i128, i128) #1