[llvm] b400dde - [InstSimplify] Use dominate condtion to simplify instructions
via llvm-commits
llvm-commits at lists.llvm.org
Sat Nov 26 05:41:55 PST 2022
Author: chenglin.bi
Date: 2022-11-26T21:41:41+08:00
New Revision: b400dde4739f1868e1d4eb2b6c782e2dca235aba
URL: https://github.com/llvm/llvm-project/commit/b400dde4739f1868e1d4eb2b6c782e2dca235aba
DIFF: https://github.com/llvm/llvm-project/commit/b400dde4739f1868e1d4eb2b6c782e2dca235aba.diff
LOG: [InstSimplify] Use dominate condtion to simplify instructions
Fix #56795
Reviewed By: spatel
Differential Revision: https://reviews.llvm.org/D138542
Added:
Modified:
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll
llvm/test/Transforms/InstSimplify/domcondition.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 0f0c0bcb96e17..0db6b85318ddd 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -741,6 +741,42 @@ static Constant *computePointerDifference(const DataLayout &DL, Value *LHS,
return Res;
}
+/// Test if there is a dominating equivalence condition for the
+/// two operands. If there is, try to reduce the binary operation
+/// between the two operands.
+/// Example: Op0 - Op1 --> 0 when Op0 == Op1
+static Value *simplifyByDomEq(unsigned Opcode, Value *Op0, Value *Op1,
+ const SimplifyQuery &Q, unsigned MaxRecurse) {
+ // Recursive run it can not get any benefit
+ if (MaxRecurse != RecursionLimit)
+ return nullptr;
+
+ Optional<bool> Imp =
+ isImpliedByDomCondition(CmpInst::ICMP_EQ, Op0, Op1, Q.CxtI, Q.DL);
+ if (Imp && *Imp) {
+ Type *Ty = Op0->getType();
+ switch (Opcode) {
+ case Instruction::Sub:
+ case Instruction::Xor:
+ case Instruction::URem:
+ case Instruction::SRem:
+ return Constant::getNullValue(Ty);
+
+ case Instruction::SDiv:
+ case Instruction::UDiv:
+ return ConstantInt::get(Ty, 1);
+
+ case Instruction::And:
+ case Instruction::Or:
+ // Could be either one - choose Op1 since that's more likely a constant.
+ return Op1;
+ default:
+ break;
+ }
+ }
+ return nullptr;
+}
+
/// Given operands for a Sub, see if we can fold the result.
/// If not, this returns null.
static Value *simplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
@@ -872,6 +908,9 @@ static Value *simplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
// "A-B" and "A-C" thus gains nothing, but costs compile time. Similarly
// for threading over phi nodes.
+ if (Value *V = simplifyByDomEq(Instruction::Sub, Op0, Op1, Q, MaxRecurse))
+ return V;
+
return nullptr;
}
@@ -947,7 +986,8 @@ Value *llvm::simplifyMulInst(Value *Op0, Value *Op1, const SimplifyQuery &Q) {
/// Check for common or similar folds of integer division or integer remainder.
/// This applies to all 4 opcodes (sdiv/udiv/srem/urem).
static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0,
- Value *Op1, const SimplifyQuery &Q) {
+ Value *Op1, const SimplifyQuery &Q,
+ unsigned MaxRecurse) {
bool IsDiv = (Opcode == Instruction::SDiv || Opcode == Instruction::UDiv);
bool IsSigned = (Opcode == Instruction::SDiv || Opcode == Instruction::SRem);
@@ -1022,6 +1062,9 @@ static Value *simplifyDivRem(Instruction::BinaryOps Opcode, Value *Op0,
}
}
+ if (Value *V = simplifyByDomEq(Opcode, Op0, Op1, Q, MaxRecurse))
+ return V;
+
return nullptr;
}
@@ -1103,7 +1146,7 @@ static Value *simplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
if (Constant *C = foldOrCommuteConstant(Opcode, Op0, Op1, Q))
return C;
- if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q))
+ if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q, MaxRecurse))
return V;
bool IsSigned = Opcode == Instruction::SDiv;
@@ -1147,7 +1190,7 @@ static Value *simplifyRem(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1,
if (Constant *C = foldOrCommuteConstant(Opcode, Op0, Op1, Q))
return C;
- if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q))
+ if (Value *V = simplifyDivRem(Opcode, Op0, Op1, Q, MaxRecurse))
return V;
// (X % Y) % Y -> X % Y
@@ -2191,6 +2234,9 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
}
}
+ if (Value *V = simplifyByDomEq(Instruction::And, Op0, Op1, Q, MaxRecurse))
+ return V;
+
return nullptr;
}
@@ -2450,6 +2496,9 @@ static Value *simplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
}
}
+ if (Value *V = simplifyByDomEq(Instruction::Or, Op0, Op1, Q, MaxRecurse))
+ return V;
+
return nullptr;
}
@@ -2525,6 +2574,9 @@ static Value *simplifyXorInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
// "A^B" and "A^C" thus gains nothing, but costs compile time. Similarly
// for threading over phi nodes.
+ if (Value *V = simplifyByDomEq(Instruction::Xor, Op0, Op1, Q, MaxRecurse))
+ return V;
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll b/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll
index eb83865e3e5cc..90ca39a70a0bb 100644
--- a/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll
+++ b/llvm/test/Transforms/InstCombine/usub-overflow-known-by-implied-cond.ll
@@ -123,8 +123,7 @@ define i32 @test5(i32 %a, i32 %b) {
; CHECK: bb1:
; CHECK-NEXT: br i1 false, label [[BB3]], label [[BB2:%.*]]
; CHECK: bb2:
-; CHECK-NEXT: [[SUB1:%.*]] = sub nuw i32 [[A]], [[B]]
-; CHECK-NEXT: ret i32 [[SUB1]]
+; CHECK-NEXT: ret i32 0
; CHECK: bb3:
; CHECK-NEXT: ret i32 0
;
diff --git a/llvm/test/Transforms/InstSimplify/domcondition.ll b/llvm/test/Transforms/InstSimplify/domcondition.ll
index 3977cbfd98ab3..b6508c329e3c4 100644
--- a/llvm/test/Transforms/InstSimplify/domcondition.ll
+++ b/llvm/test/Transforms/InstSimplify/domcondition.ll
@@ -7,11 +7,9 @@ define i32 @xor_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[XOR]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 0
;
entry:
%cmp = icmp eq i32 %x, %y
@@ -32,11 +30,9 @@ define i32 @sub_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[SUB]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 0
;
entry:
%cmp = icmp eq i32 %x, %y
@@ -57,10 +53,9 @@ define i32 @udiv_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[UDIV:%.*]] = udiv i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[UDIV]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
@@ -82,10 +77,9 @@ define i32 @sdiv_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[SDIV:%.*]] = sdiv i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[SDIV]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
@@ -107,11 +101,9 @@ define i32 @urem_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[UREM:%.*]] = urem i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[UREM]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 0
;
entry:
%cmp = icmp eq i32 %x, %y
@@ -132,11 +124,9 @@ define i32 @srem_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[SREM]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 0
;
entry:
%cmp = icmp eq i32 %x, %y
@@ -158,10 +148,9 @@ define i32 @and_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[AND]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[Y]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
@@ -184,10 +173,9 @@ define i32 @or_domcondition(i32 %x, i32 %y) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
; CHECK: cond.true:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
; CHECK-NEXT: br label [[COND_END]]
; CHECK: cond.end:
-; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[OR]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[Y]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
More information about the llvm-commits
mailing list