[llvm] 4ebfd43 - [InstCombine] Always treat inner and/or as bitwise (#121766)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 6 08:03:18 PST 2025
Author: Yingwei Zheng
Date: 2025-01-07T00:03:13+08:00
New Revision: 4ebfd43cf008b941d88a61a2c549e9a5291ee017
URL: https://github.com/llvm/llvm-project/commit/4ebfd43cf008b941d88a61a2c549e9a5291ee017
DIFF: https://github.com/llvm/llvm-project/commit/4ebfd43cf008b941d88a61a2c549e9a5291ee017.diff
LOG: [InstCombine] Always treat inner and/or as bitwise (#121766)
In https://github.com/llvm/llvm-project/pull/116065, we pass `IsLogical`
into `foldBooleanAndOr` when folding inner and/or ops. But it is always
safe to treat them as bitwise if the outer ops are bitwise.
Alive2: https://alive2.llvm.org/ce/z/hULrgH
Closes https://github.com/llvm/llvm-project/issues/121701.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/lib/Transforms/InstCombine/InstCombineInternal.h
llvm/test/Transforms/InstCombine/and-or-icmps.ll
llvm/test/Transforms/InstCombine/bit-checks.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 37a7c4d88b234d..e9bb2b8847563c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2363,6 +2363,26 @@ static Value *simplifyAndOrWithOpReplaced(Value *V, Value *Op, Value *RepOp,
return IC.Builder.CreateBinOp(I->getOpcode(), NewOp0, NewOp1);
}
+/// Reassociate and/or expressions to see if we can fold the inner and/or ops.
+/// TODO: Make this recursive; it's a little tricky because an arbitrary
+/// number of and/or instructions might have to be created.
+Value *InstCombinerImpl::reassociateBooleanAndOr(Value *LHS, Value *X, Value *Y,
+ Instruction &I, bool IsAnd,
+ bool RHSIsLogical) {
+ Instruction::BinaryOps Opcode = IsAnd ? Instruction::And : Instruction::Or;
+ // LHS bop (X lop Y) --> (LHS bop X) lop Y
+ // LHS bop (X bop Y) --> (LHS bop X) bop Y
+ if (Value *Res = foldBooleanAndOr(LHS, X, I, IsAnd, /*IsLogical=*/false))
+ return RHSIsLogical ? Builder.CreateLogicalOp(Opcode, Res, Y)
+ : Builder.CreateBinOp(Opcode, Res, Y);
+ // LHS bop (X bop Y) --> X bop (LHS bop Y)
+ // LHS bop (X lop Y) --> X lop (LHS bop Y)
+ if (Value *Res = foldBooleanAndOr(LHS, Y, I, IsAnd, /*IsLogical=*/false))
+ return RHSIsLogical ? Builder.CreateLogicalOp(Opcode, X, Res)
+ : Builder.CreateBinOp(Opcode, X, Res);
+ return nullptr;
+}
+
// FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
// here. We should standardize that construct where it is needed or choose some
// other way to ensure that commutated variants of patterns are not missed.
@@ -2746,31 +2766,17 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
foldBooleanAndOr(Op0, Op1, I, /*IsAnd=*/true, /*IsLogical=*/false))
return replaceInstUsesWith(I, Res);
- // TODO: Make this recursive; it's a little tricky because an arbitrary
- // number of 'and' instructions might have to be created.
if (match(Op1, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) {
bool IsLogical = isa<SelectInst>(Op1);
- // Op0 & (X && Y) --> (Op0 && X) && Y
- if (Value *Res = foldBooleanAndOr(Op0, X, I, /* IsAnd */ true, IsLogical))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(Res, Y)
- : Builder.CreateAnd(Res, Y));
- // Op0 & (X && Y) --> X && (Op0 & Y)
- if (Value *Res = foldBooleanAndOr(Op0, Y, I, /* IsAnd */ true,
- /* IsLogical */ false))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(X, Res)
- : Builder.CreateAnd(X, Res));
+ if (auto *V = reassociateBooleanAndOr(Op0, X, Y, I, /*IsAnd=*/true,
+ /*RHSIsLogical=*/IsLogical))
+ return replaceInstUsesWith(I, V);
}
if (match(Op0, m_OneUse(m_LogicalAnd(m_Value(X), m_Value(Y))))) {
bool IsLogical = isa<SelectInst>(Op0);
- // (X && Y) & Op1 --> (X && Op1) && Y
- if (Value *Res = foldBooleanAndOr(X, Op1, I, /* IsAnd */ true, IsLogical))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(Res, Y)
- : Builder.CreateAnd(Res, Y));
- // (X && Y) & Op1 --> X && (Y & Op1)
- if (Value *Res = foldBooleanAndOr(Y, Op1, I, /* IsAnd */ true,
- /* IsLogical */ false))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalAnd(X, Res)
- : Builder.CreateAnd(X, Res));
+ if (auto *V = reassociateBooleanAndOr(Op1, X, Y, I, /*IsAnd=*/true,
+ /*RHSIsLogical=*/IsLogical))
+ return replaceInstUsesWith(I, V);
}
if (Instruction *FoldedFCmps = reassociateFCmps(I, Builder))
@@ -3831,31 +3837,17 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
foldBooleanAndOr(Op0, Op1, I, /*IsAnd=*/false, /*IsLogical=*/false))
return replaceInstUsesWith(I, Res);
- // TODO: Make this recursive; it's a little tricky because an arbitrary
- // number of 'or' instructions might have to be created.
if (match(Op1, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) {
bool IsLogical = isa<SelectInst>(Op1);
- // Op0 | (X || Y) --> (Op0 || X) || Y
- if (Value *Res = foldBooleanAndOr(Op0, X, I, /* IsAnd */ false, IsLogical))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(Res, Y)
- : Builder.CreateOr(Res, Y));
- // Op0 | (X || Y) --> X || (Op0 | Y)
- if (Value *Res = foldBooleanAndOr(Op0, Y, I, /* IsAnd */ false,
- /* IsLogical */ false))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(X, Res)
- : Builder.CreateOr(X, Res));
+ if (auto *V = reassociateBooleanAndOr(Op0, X, Y, I, /*IsAnd=*/false,
+ /*RHSIsLogical=*/IsLogical))
+ return replaceInstUsesWith(I, V);
}
if (match(Op0, m_OneUse(m_LogicalOr(m_Value(X), m_Value(Y))))) {
bool IsLogical = isa<SelectInst>(Op0);
- // (X || Y) | Op1 --> (X || Op1) || Y
- if (Value *Res = foldBooleanAndOr(X, Op1, I, /* IsAnd */ false, IsLogical))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(Res, Y)
- : Builder.CreateOr(Res, Y));
- // (X || Y) | Op1 --> X || (Y | Op1)
- if (Value *Res = foldBooleanAndOr(Y, Op1, I, /* IsAnd */ false,
- /* IsLogical */ false))
- return replaceInstUsesWith(I, IsLogical ? Builder.CreateLogicalOr(X, Res)
- : Builder.CreateOr(X, Res));
+ if (auto *V = reassociateBooleanAndOr(Op1, X, Y, I, /*IsAnd=*/false,
+ /*RHSIsLogical=*/IsLogical))
+ return replaceInstUsesWith(I, V);
}
if (Instruction *FoldedFCmps = reassociateFCmps(I, Builder))
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 3a074ee70dc487..b31ae374540bbd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -429,6 +429,9 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Value *foldBooleanAndOr(Value *LHS, Value *RHS, Instruction &I, bool IsAnd,
bool IsLogical);
+ Value *reassociateBooleanAndOr(Value *LHS, Value *X, Value *Y, Instruction &I,
+ bool IsAnd, bool RHSIsLogical);
+
Instruction *
canonicalizeConditionalNegationViaMathToSelect(BinaryOperator &i);
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index fffe1f8426690b..9651858a0caefb 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -1445,8 +1445,7 @@ define i1 @bitwise_and_logical_and_icmps_comm2(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @bitwise_and_logical_and_icmps_comm2(
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[Y:%.*]], 42
; CHECK-NEXT: [[Z_SHIFT:%.*]] = shl nuw i8 1, [[Z:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = freeze i8 [[Z_SHIFT]]
-; CHECK-NEXT: [[TMP2:%.*]] = or i8 [[TMP1]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = or i8 [[Z_SHIFT]], 1
; CHECK-NEXT: [[TMP3:%.*]] = and i8 [[X:%.*]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i8 [[TMP3]], [[TMP2]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[TMP4]], i1 [[C1]], i1 false
@@ -1796,8 +1795,7 @@ define i1 @bitwise_or_logical_or_icmps_comm2(i8 %x, i8 %y, i8 %z) {
; CHECK-LABEL: @bitwise_or_logical_or_icmps_comm2(
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[Y:%.*]], 42
; CHECK-NEXT: [[Z_SHIFT:%.*]] = shl nuw i8 1, [[Z:%.*]]
-; CHECK-NEXT: [[TMP1:%.*]] = freeze i8 [[Z_SHIFT]]
-; CHECK-NEXT: [[TMP2:%.*]] = or i8 [[TMP1]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = or i8 [[Z_SHIFT]], 1
; CHECK-NEXT: [[TMP3:%.*]] = and i8 [[X:%.*]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i8 [[TMP3]], [[TMP2]]
; CHECK-NEXT: [[OR2:%.*]] = select i1 [[TMP4]], i1 true, i1 [[C1]]
@@ -2068,12 +2066,10 @@ define i1 @bitwise_and_logical_and_masked_icmp_allzeros_poison1(i1 %c, i32 %x, i
define i1 @bitwise_and_logical_and_masked_icmp_allzeros_poison2(i1 %c, i32 %x, i32 %y) {
; CHECK-LABEL: @bitwise_and_logical_and_masked_icmp_allzeros_poison2(
-; CHECK-NEXT: [[X_M1:%.*]] = and i32 [[X:%.*]], 8
-; CHECK-NEXT: [[C1:%.*]] = icmp eq i32 [[X_M1]], 0
-; CHECK-NEXT: [[AND1:%.*]] = select i1 [[C1]], i1 [[C:%.*]], i1 false
-; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[Y:%.*]] = or i32 [[Y1:%.*]], 8
+; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X_M2]], 0
-; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C2]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[C2]], i1 [[C:%.*]], i1 false
; CHECK-NEXT: ret i1 [[AND2]]
;
%x.m1 = and i32 %x, 8
@@ -2120,12 +2116,10 @@ define i1 @bitwise_and_logical_and_masked_icmp_allones_poison1(i1 %c, i32 %x, i3
define i1 @bitwise_and_logical_and_masked_icmp_allones_poison2(i1 %c, i32 %x, i32 %y) {
; CHECK-LABEL: @bitwise_and_logical_and_masked_icmp_allones_poison2(
-; CHECK-NEXT: [[X_M1:%.*]] = and i32 [[X:%.*]], 8
-; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[X_M1]], 0
-; CHECK-NEXT: [[AND1:%.*]] = select i1 [[C1]], i1 [[C:%.*]], i1 false
-; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT: [[Y:%.*]] = or i32 [[Y1:%.*]], 8
+; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X:%.*]], [[Y]]
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X_M2]], [[Y]]
-; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C2]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[C2]], i1 [[C:%.*]], i1 false
; CHECK-NEXT: ret i1 [[AND2]]
;
%x.m1 = and i32 %x, 8
diff --git a/llvm/test/Transforms/InstCombine/bit-checks.ll b/llvm/test/Transforms/InstCombine/bit-checks.ll
index 43cd6dd1211b00..936c02c9f90527 100644
--- a/llvm/test/Transforms/InstCombine/bit-checks.ll
+++ b/llvm/test/Transforms/InstCombine/bit-checks.ll
@@ -1335,6 +1335,22 @@ define i1 @no_masks_with_logical_or(i32 %a, i32 %b, i32 noundef %c) {
ret i1 %or2
}
+define i1 @no_masks_with_logical_or_commuted(i32 %a, i32 %b, i32 noundef %c) {
+; CHECK-LABEL: @no_masks_with_logical_or_commuted(
+; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[B:%.*]], 63
+; CHECK-NEXT: [[C:%.*]] = or i32 [[C1:%.*]], [[A:%.*]]
+; CHECK-NEXT: [[CMP3:%.*]] = icmp ne i32 [[C]], 0
+; CHECK-NEXT: [[OR2:%.*]] = select i1 [[CMP3]], i1 true, i1 [[CMP2]]
+; CHECK-NEXT: ret i1 [[OR2]]
+;
+ %cmp1 = icmp ne i32 %a, 0
+ %cmp2 = icmp ne i32 %b, 63
+ %or1 = select i1 %cmp1, i1 true, i1 %cmp2
+ %cmp3 = icmp ne i32 %c, 0
+ %or2 = or i1 %cmp3, %or1
+ ret i1 %or2
+}
+
define i1 @no_masks_with_logical_or2(i32 %a, i32 %b, i32 noundef %c) {
; CHECK-LABEL: @no_masks_with_logical_or2(
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[B:%.*]], 63
More information about the llvm-commits
mailing list