diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp index 4535f86f9d68b..1a2e422356270 100644 --- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -20,6 +20,7 @@ #include "llvm/Analysis/ValueLatticeUtils.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/InstVisitor.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -30,6 +31,7 @@ #include using namespace llvm; +using namespace PatternMatch; #define DEBUG_TYPE "sccp" @@ -83,20 +85,28 @@ bool SCCPSolver::tryToReplaceWithConstant(Value *V) { return true; } +/// Helper for getting ranges from \p Solver. Instructions inserted during +/// simplification are unavailable in the solver, so we return a full range for +/// them. +static ConstantRange getRange(Value *Op, SCCPSolver &Solver, + const SmallPtrSetImpl &InsertedValues) { + if (auto *Const = dyn_cast(Op)) + return Const->toConstantRange(); + if (InsertedValues.contains(Op)) { + unsigned Bitwidth = Op->getType()->getScalarSizeInBits(); + return ConstantRange::getFull(Bitwidth); + } + return Solver.getLatticeValueFor(Op).asConstantRange(Op->getType(), + /*UndefAllowed=*/false); +} + /// Try to use \p Inst's value range from \p Solver to infer the NUW flag. static bool refineInstruction(SCCPSolver &Solver, const SmallPtrSetImpl &InsertedValues, Instruction &Inst) { bool Changed = false; auto GetRange = [&Solver, &InsertedValues](Value *Op) { - if (auto *Const = dyn_cast(Op)) - return Const->toConstantRange(); - if (InsertedValues.contains(Op)) { - unsigned Bitwidth = Op->getType()->getScalarSizeInBits(); - return ConstantRange::getFull(Bitwidth); - } - return Solver.getLatticeValueFor(Op).asConstantRange( - Op->getType(), /*UndefAllowed=*/false); + return getRange(Op, Solver, InsertedValues); }; if (isa(Inst)) { @@ -167,16 +177,8 @@ static bool replaceSignedInst(SCCPSolver &Solver, SmallPtrSetImpl &InsertedValues, Instruction &Inst) { // Determine if a signed value is known to be >= 0. - auto isNonNegative = [&Solver](Value *V) { - // If this value was constant-folded, it may not have a solver entry. - // Handle integers. Otherwise, return false. - if (auto *C = dyn_cast(V)) { - auto *CInt = dyn_cast(C); - return CInt && !CInt->isNegative(); - } - const ValueLatticeElement &IV = Solver.getLatticeValueFor(V); - return IV.isConstantRange(/*UndefAllowed=*/false) && - IV.getConstantRange().isAllNonNegative(); + auto isNonNegative = [&Solver, &InsertedValues](Value *V) { + return getRange(V, Solver, InsertedValues).isAllNonNegative(); }; Instruction *NewInst = nullptr; @@ -185,7 +187,7 @@ static bool replaceSignedInst(SCCPSolver &Solver, case Instruction::SExt: { // If the source value is not negative, this is a zext/uitofp. Value *Op0 = Inst.getOperand(0); - if (InsertedValues.count(Op0) || !isNonNegative(Op0)) + if (!isNonNegative(Op0)) return false; NewInst = CastInst::Create(Inst.getOpcode() == Instruction::SExt ? Instruction::ZExt @@ -197,7 +199,7 @@ static bool replaceSignedInst(SCCPSolver &Solver, case Instruction::AShr: { // If the shifted value is not negative, this is a logical shift right. Value *Op0 = Inst.getOperand(0); - if (InsertedValues.count(Op0) || !isNonNegative(Op0)) + if (!isNonNegative(Op0)) return false; NewInst = BinaryOperator::CreateLShr(Op0, Inst.getOperand(1), "", Inst.getIterator()); NewInst->setIsExact(Inst.isExact()); @@ -207,8 +209,7 @@ static bool replaceSignedInst(SCCPSolver &Solver, case Instruction::SRem: { // If both operands are not negative, this is the same as udiv/urem. Value *Op0 = Inst.getOperand(0), *Op1 = Inst.getOperand(1); - if (InsertedValues.count(Op0) || InsertedValues.count(Op1) || - !isNonNegative(Op0) || !isNonNegative(Op1)) + if (!isNonNegative(Op0) || !isNonNegative(Op1)) return false; auto NewOpcode = Inst.getOpcode() == Instruction::SDiv ? Instruction::UDiv : Instruction::URem; @@ -232,6 +233,26 @@ static bool replaceSignedInst(SCCPSolver &Solver, return true; } +/// Try to use \p Inst's value range from \p Solver to simplify it. +static Value *simplifyInstruction(SCCPSolver &Solver, + SmallPtrSetImpl &InsertedValues, + Instruction &Inst) { + auto GetRange = [&Solver, &InsertedValues](Value *Op) { + return getRange(Op, Solver, InsertedValues); + }; + + Value *X; + const APInt *RHSC; + // Remove masking operations. + if (match(&Inst, m_And(m_Value(X), m_LowBitMask(RHSC)))) { + ConstantRange LRange = GetRange(Inst.getOperand(0)); + if (LRange.getUnsignedMax().ule(*RHSC)) + return X; + } + + return nullptr; +} + bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB, SmallPtrSetImpl &InsertedValues, Statistic &InstRemovedStat, @@ -251,6 +272,11 @@ bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB, ++InstReplacedStat; } else if (refineInstruction(*this, InsertedValues, Inst)) { MadeChanges = true; + } else if (auto *V = simplifyInstruction(*this, InsertedValues, Inst)) { + Inst.replaceAllUsesWith(V); + Inst.eraseFromParent(); + ++InstRemovedStat; + MadeChanges = true; } } return MadeChanges; diff --git a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll index 8b4dea462757e..b49a40abaaeb1 100644 --- a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll +++ b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll @@ -36,8 +36,6 @@ false: declare void @use.i32(i32) -; It is not allowed to use the range information from the condition to remove -; %a.127 = and ... in the true block, as %a could be undef. define void @val_undef_range() { ; CHECK-LABEL: @val_undef_range( ; CHECK-NEXT: entry: @@ -46,8 +44,7 @@ define void @val_undef_range() { ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: ; CHECK-NEXT: call void @use(i1 false) -; CHECK-NEXT: [[A_127:%.*]] = and i32 [[A]], 127 -; CHECK-NEXT: call void @use.i32(i32 [[A_127]]) +; CHECK-NEXT: call void @use.i32(i32 [[A]]) ; CHECK-NEXT: ret void ; CHECK: false: ; CHECK-NEXT: ret void @@ -82,8 +79,7 @@ define void @val_singlecrfromundef_range(i1 %cond) { ; CHECK-NEXT: br label [[TRUE:%.*]] ; CHECK: true: ; CHECK-NEXT: call void @use(i1 false) -; CHECK-NEXT: [[P_127:%.*]] = and i32 10, 127 -; CHECK-NEXT: call void @use.i32(i32 [[P_127]]) +; CHECK-NEXT: call void @use.i32(i32 10) ; CHECK-NEXT: ret void ; entry: @@ -113,9 +109,6 @@ false: ret void } - -; It is not allowed to use the information from the condition ([0, 128)) -; to remove a.127.2 = and i32 %p, 127, as %p might be undef. define void @val_undef_to_cr_to_overdef_range(i32 %a, i1 %cond) { ; CHECK-LABEL: @val_undef_to_cr_to_overdef_range( ; CHECK-NEXT: entry: @@ -131,8 +124,7 @@ define void @val_undef_to_cr_to_overdef_range(i32 %a, i1 %cond) { ; CHECK-NEXT: br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]] ; CHECK: true: ; CHECK-NEXT: call void @use(i1 false) -; CHECK-NEXT: [[P_127:%.*]] = and i32 [[P]], 127 -; CHECK-NEXT: call void @use.i32(i32 [[P_127]]) +; CHECK-NEXT: call void @use.i32(i32 [[P]]) ; CHECK-NEXT: ret void ; CHECK: false: ; CHECK-NEXT: ret void @@ -164,6 +156,43 @@ false: ret void } +; It is not allowed to use the range information from the condition to remove +; %p.127 = and i32 %p, 127, as %p could be undef. +define void @masked_incoming_val_with_undef(i32 %a, i1 %cond) { +; CHECK-LABEL: @masked_incoming_val_with_undef( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[A_127:%.*]] = and i32 [[A:%.*]], 127 +; CHECK-NEXT: br i1 [[COND:%.*]], label [[INC1:%.*]], label [[INC2:%.*]] +; CHECK: inc1: +; CHECK-NEXT: br label [[IF:%.*]] +; CHECK: inc2: +; CHECK-NEXT: br label [[IF]] +; CHECK: if: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ [[A_127]], [[INC1]] ], [ undef, [[INC2]] ] +; CHECK-NEXT: [[P_127:%.*]] = and i32 [[P]], 127 +; CHECK-NEXT: call void @use.i32(i32 [[P_127]]) +; CHECK-NEXT: ret void +; +entry: + %a.127 = and i32 %a, 127 + br i1 %cond, label %inc1, label %inc2 + +inc1: + br label %if + +inc2: + br label %if + +if: + %p = phi i32 [ %a.127, %inc1 ], [ undef, %inc2 ] + %p.127 = and i32 %p, 127 + call void @use.i32(i32 %p.127) + ret void + +false: + ret void +} + ; All uses of %p can be replaced by a constant (10), we are allowed to use it ; as a bound too. define void @bound_singlecrfromundef(i32 %a, i1 %cond) { diff --git a/llvm/test/Transforms/SCCP/range-and.ll b/llvm/test/Transforms/SCCP/range-and.ll index ef8758fcba9e2..f3452f45e1c02 100644 --- a/llvm/test/Transforms/SCCP/range-and.ll +++ b/llvm/test/Transforms/SCCP/range-and.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --verbose +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -passes=sccp %s | FileCheck %s declare void @use(i1) @@ -140,9 +140,8 @@ define i64 @constant_range_and_255_100(i1 %cond, i64 %a) { ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: ; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R_1]], [[BB1]] ], [ [[R_2]], [[BB2]] ] -; CHECK-NEXT: [[P_AND:%.*]] = and i64 [[P]], 255 ; CHECK-NEXT: call void @use(i1 true) -; CHECK-NEXT: ret i64 [[P_AND]] +; CHECK-NEXT: ret i64 [[P]] ; entry: br i1 %cond, label %bb1, label %bb2 diff --git a/llvm/test/Transforms/SCCP/range-with-undef.ll b/llvm/test/Transforms/SCCP/range-with-undef.ll index 9b8d415171140..774d95ceff428 100644 --- a/llvm/test/Transforms/SCCP/range-with-undef.ll +++ b/llvm/test/Transforms/SCCP/range-with-undef.ll @@ -12,8 +12,7 @@ define i8 @test_binop(i1 %cond, i8 %a) { ; CHECK-NEXT: [[A_EXT:%.*]] = zext i8 [[A]] to i16 ; CHECK-NEXT: br label %[[JOIN]] ; CHECK: [[JOIN]]: -; CHECK-NEXT: [[PHI:%.*]] = phi i16 [ undef, %[[ENTRY]] ], [ [[A_EXT]], %[[IF]] ] -; CHECK-NEXT: [[AND:%.*]] = and i16 [[PHI]], -1 +; CHECK-NEXT: [[AND:%.*]] = phi i16 [ undef, %[[ENTRY]] ], [ [[A_EXT]], %[[IF]] ] ; CHECK-NEXT: [[TRUNC:%.*]] = trunc i16 [[AND]] to i8 ; CHECK-NEXT: ret i8 [[TRUNC]] ;