diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 715cdaff97279..50b5fdb567207 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -62,6 +62,7 @@ STATISTIC(NumAShrsConverted, "Number of ashr converted to lshr"); STATISTIC(NumAShrsRemoved, "Number of ashr removed"); STATISTIC(NumSRems, "Number of srem converted to urem"); STATISTIC(NumSExt, "Number of sext converted to zext"); +STATISTIC(NumSIToFP, "Number of sitofp converted to uitofp"); STATISTIC(NumSICmps, "Number of signed icmp preds simplified to unsigned"); STATISTIC(NumAnd, "Number of ands removed"); STATISTIC(NumNW, "Number of no-wrap deductions"); @@ -89,7 +90,7 @@ STATISTIC(NumSMinMax, "Number of llvm.s{min,max} intrinsics simplified to unsigned"); STATISTIC(NumUDivURemsNarrowedExpanded, "Number of bound udiv's/urem's expanded"); -STATISTIC(NumZExt, "Number of non-negative deductions"); +STATISTIC(NumNNeg, "Number of zext/uitofp non-negative deductions"); static Constant *getConstantAt(Value *V, Instruction *At, LazyValueInfo *LVI) { if (Constant *C = LVI->getConstant(V, At)) @@ -1075,20 +1076,49 @@ static bool processSExt(SExtInst *SDI, LazyValueInfo *LVI) { return true; } -static bool processZExt(ZExtInst *ZExt, LazyValueInfo *LVI) { - if (ZExt->getType()->isVectorTy()) +static bool processPossibleNonNeg(PossiblyNonNegInst *I, LazyValueInfo *LVI) { + if (I->getType()->isVectorTy()) return false; - if (ZExt->hasNonNeg()) + if (I->hasNonNeg()) return false; - const Use &Base = ZExt->getOperandUse(0); + const Use &Base = I->getOperandUse(0); if (!LVI->getConstantRangeAtUse(Base, /*UndefAllowed*/ false) .isAllNonNegative()) return false; - ++NumZExt; - ZExt->setNonNeg(); + ++NumNNeg; + I->setNonNeg(); + + return true; +} + +static bool processZExt(ZExtInst *ZExt, LazyValueInfo *LVI) { + return processPossibleNonNeg(cast(ZExt), LVI); +} + +static bool processUIToFP(UIToFPInst *UIToFP, LazyValueInfo *LVI) { + return processPossibleNonNeg(cast(UIToFP), LVI); +} + +static bool processSIToFP(SIToFPInst *SIToFP, LazyValueInfo *LVI) { + if (SIToFP->getType()->isVectorTy()) + return false; + + const Use &Base = SIToFP->getOperandUse(0); + if (!LVI->getConstantRangeAtUse(Base, /*UndefAllowed*/ false) + .isAllNonNegative()) + return false; + + ++NumSIToFP; + auto *UIToFP = CastInst::Create(Instruction::UIToFP, Base, SIToFP->getType(), + "", SIToFP->getIterator()); + UIToFP->takeName(SIToFP); + UIToFP->setDebugLoc(SIToFP->getDebugLoc()); + UIToFP->setNonNeg(); + SIToFP->replaceAllUsesWith(UIToFP); + SIToFP->eraseFromParent(); return true; } @@ -1197,6 +1227,12 @@ static bool runImpl(Function &F, LazyValueInfo *LVI, DominatorTree *DT, case Instruction::ZExt: BBChanged |= processZExt(cast(&II), LVI); break; + case Instruction::UIToFP: + BBChanged |= processUIToFP(cast(&II), LVI); + break; + case Instruction::SIToFP: + BBChanged |= processSIToFP(cast(&II), LVI); + break; case Instruction::Add: case Instruction::Sub: case Instruction::Mul: diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp index c6029b428ed39..ce40e8b31b767 100644 --- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -143,7 +143,7 @@ static bool refineInstruction(SCCPSolver &Solver, Changed = true; } } - } else if (isa(Inst) && !Inst.hasNonNeg()) { + } else if (isa(Inst) && !Inst.hasNonNeg()) { auto Range = GetRange(Inst.getOperand(0)); if (Range.isAllNonNegative()) { Inst.setNonNeg(); @@ -191,14 +191,16 @@ static bool replaceSignedInst(SCCPSolver &Solver, Instruction *NewInst = nullptr; switch (Inst.getOpcode()) { - // Note: We do not fold sitofp -> uitofp here because that could be more - // expensive in codegen and may not be reversible in the backend. + case Instruction::SIToFP: case Instruction::SExt: { - // If the source value is not negative, this is a zext. + // If the source value is not negative, this is a zext/uitofp. Value *Op0 = Inst.getOperand(0); if (InsertedValues.count(Op0) || !isNonNegative(Op0)) return false; - NewInst = new ZExtInst(Op0, Inst.getType(), "", Inst.getIterator()); + NewInst = CastInst::Create(Inst.getOpcode() == Instruction::SExt + ? Instruction::ZExt + : Instruction::UIToFP, + Op0, Inst.getType(), "", Inst.getIterator()); NewInst->setNonNeg(); break; } diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/sitofp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/sitofp.ll new file mode 100644 index 0000000000000..83533290e2f61 --- /dev/null +++ b/llvm/test/Transforms/CorrelatedValuePropagation/sitofp.ll @@ -0,0 +1,99 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s + +declare void @use.f32(float) + +define void @test1(i32 %n) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], -1 +; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]] +; CHECK: bb: +; CHECK-NEXT: [[EXT_WIDE:%.*]] = uitofp nneg i32 [[N]] to float +; CHECK-NEXT: call void @use.f32(float [[EXT_WIDE]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %cmp = icmp sgt i32 %n, -1 + br i1 %cmp, label %bb, label %exit + +bb: + %ext.wide = sitofp i32 %n to float + call void @use.f32(float %ext.wide) + br label %exit + +exit: + ret void +} + + +define void @test2_fail(i32 %n) { +; CHECK-LABEL: @test2_fail( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], -2 +; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]] +; CHECK: bb: +; CHECK-NEXT: [[EXT_WIDE:%.*]] = sitofp i32 [[N]] to float +; CHECK-NEXT: call void @use.f32(float [[EXT_WIDE]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %cmp = icmp sgt i32 %n, -2 + br i1 %cmp, label %bb, label %exit + +bb: + %ext.wide = sitofp i32 %n to float + call void @use.f32(float %ext.wide) + br label %exit + +exit: + ret void +} + +define float @may_including_undef(i1 %c.1, i1 %c.2) { +; CHECK-LABEL: @may_including_undef( +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[TRUE_1:%.*]], label [[FALSE:%.*]] +; CHECK: true.1: +; CHECK-NEXT: br i1 [[C_2:%.*]], label [[TRUE_2:%.*]], label [[EXIT:%.*]] +; CHECK: true.2: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: false: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[TRUE_1]] ], [ 1, [[TRUE_2]] ], [ undef, [[FALSE]] ] +; CHECK-NEXT: [[EXT:%.*]] = sitofp i32 [[P]] to float +; CHECK-NEXT: ret float [[EXT]] +; + br i1 %c.1, label %true.1, label %false + +true.1: + br i1 %c.2, label %true.2, label %exit + +true.2: + br label %exit + +false: + br label %exit + +exit: + %p = phi i32 [ 0, %true.1 ], [ 1, %true.2], [ undef, %false ] + %ext = sitofp i32 %p to float + ret float %ext +} + +define double @test_infer_at_use(i32 noundef %n) { +; CHECK-LABEL: @test_infer_at_use( +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], -1 +; CHECK-NEXT: [[EXT:%.*]] = uitofp nneg i32 [[N]] to double +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], double [[EXT]], double 0.000000e+00 +; CHECK-NEXT: ret double [[SELECT]] +; + %cmp = icmp sgt i32 %n, -1 + %ext = sitofp i32 %n to double + %select = select i1 %cmp, double %ext, double 0.0 + ret double %select +} diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/uitofp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/uitofp.ll new file mode 100644 index 0000000000000..32d0f5b4d3382 --- /dev/null +++ b/llvm/test/Transforms/CorrelatedValuePropagation/uitofp.ll @@ -0,0 +1,98 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s + +declare void @use.f32(float) + +define void @test1(i32 %n) { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], -1 +; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]] +; CHECK: bb: +; CHECK-NEXT: [[EXT_WIDE:%.*]] = uitofp nneg i32 [[N]] to float +; CHECK-NEXT: call void @use.f32(float [[EXT_WIDE]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %cmp = icmp sgt i32 %n, -1 + br i1 %cmp, label %bb, label %exit + +bb: + %ext.wide = uitofp i32 %n to float + call void @use.f32(float %ext.wide) + br label %exit + +exit: + ret void +} + +define void @test2_fail(i32 %n) { +; CHECK-LABEL: @test2_fail( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], -2 +; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]] +; CHECK: bb: +; CHECK-NEXT: [[EXT_WIDE:%.*]] = uitofp i32 [[N]] to float +; CHECK-NEXT: call void @use.f32(float [[EXT_WIDE]]) +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: ret void +; +entry: + %cmp = icmp sgt i32 %n, -2 + br i1 %cmp, label %bb, label %exit + +bb: + %ext.wide = uitofp i32 %n to float + call void @use.f32(float %ext.wide) + br label %exit + +exit: + ret void +} + +define float @may_including_undef(i1 %c.1, i1 %c.2) { +; CHECK-LABEL: @may_including_undef( +; CHECK-NEXT: br i1 [[C_1:%.*]], label [[TRUE_1:%.*]], label [[FALSE:%.*]] +; CHECK: true.1: +; CHECK-NEXT: br i1 [[C_2:%.*]], label [[TRUE_2:%.*]], label [[EXIT:%.*]] +; CHECK: true.2: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: false: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[TRUE_1]] ], [ 1, [[TRUE_2]] ], [ undef, [[FALSE]] ] +; CHECK-NEXT: [[EXT:%.*]] = uitofp i32 [[P]] to float +; CHECK-NEXT: ret float [[EXT]] +; + br i1 %c.1, label %true.1, label %false + +true.1: + br i1 %c.2, label %true.2, label %exit + +true.2: + br label %exit + +false: + br label %exit + +exit: + %p = phi i32 [ 0, %true.1 ], [ 1, %true.2], [ undef, %false ] + %ext = uitofp i32 %p to float + ret float %ext +} + +define double @test_infer_at_use(i32 noundef %n) { +; CHECK-LABEL: @test_infer_at_use( +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], -1 +; CHECK-NEXT: [[EXT:%.*]] = uitofp nneg i32 [[N]] to double +; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], double [[EXT]], double 0.000000e+00 +; CHECK-NEXT: ret double [[SELECT]] +; + %cmp = icmp sgt i32 %n, -1 + %ext = uitofp i32 %n to double + %select = select i1 %cmp, double %ext, double 0.0 + ret double %select +} diff --git a/llvm/test/Transforms/SCCP/ip-ranges-casts.ll b/llvm/test/Transforms/SCCP/ip-ranges-casts.ll index 05fa04a9fbe06..e8d417546def8 100644 --- a/llvm/test/Transforms/SCCP/ip-ranges-casts.ll +++ b/llvm/test/Transforms/SCCP/ip-ranges-casts.ll @@ -167,7 +167,7 @@ define i1 @caller.sext() { define internal i1 @f.fptosi(i32 %x) { ; CHECK-LABEL: define internal i1 @f.fptosi( ; CHECK-SAME: i32 [[X:%.*]]) { -; CHECK-NEXT: [[TO_DOUBLE:%.*]] = sitofp i32 [[X]] to double +; CHECK-NEXT: [[TO_DOUBLE:%.*]] = uitofp nneg i32 [[X]] to double ; CHECK-NEXT: [[ADD:%.*]] = fadd double 0.000000e+00, [[TO_DOUBLE]] ; CHECK-NEXT: [[TO_I32:%.*]] = fptosi double [[ADD]] to i32 ; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i32 [[TO_I32]], 300 @@ -209,7 +209,7 @@ define i1 @caller.fptosi() { define internal i1 @f.fpext(i16 %x) { ; CHECK-LABEL: define internal i1 @f.fpext( ; CHECK-SAME: i16 [[X:%.*]]) { -; CHECK-NEXT: [[TO_FLOAT:%.*]] = sitofp i16 [[X]] to float +; CHECK-NEXT: [[TO_FLOAT:%.*]] = uitofp nneg i16 [[X]] to float ; CHECK-NEXT: [[TO_DOUBLE:%.*]] = fpext float [[TO_FLOAT]] to double ; CHECK-NEXT: [[TO_I64:%.*]] = fptoui float [[TO_FLOAT]] to i64 ; CHECK-NEXT: [[C_1:%.*]] = icmp sgt i64 [[TO_I64]], 300 @@ -293,7 +293,7 @@ define i1 @int_range_to_double_cast(i32 %a) { ; CHECK-LABEL: define i1 @int_range_to_double_cast( ; CHECK-SAME: i32 [[A:%.*]]) { ; CHECK-NEXT: [[R:%.*]] = and i32 [[A]], 255 -; CHECK-NEXT: [[T4:%.*]] = sitofp i32 [[R]] to double +; CHECK-NEXT: [[T4:%.*]] = uitofp nneg i32 [[R]] to double ; CHECK-NEXT: [[T10:%.*]] = fadd double 0.000000e+00, [[T4]] ; CHECK-NEXT: [[T11:%.*]] = fcmp olt double [[T4]], [[T10]] ; CHECK-NEXT: ret i1 [[T11]] diff --git a/llvm/test/Transforms/SCCP/sitofp.ll b/llvm/test/Transforms/SCCP/sitofp.ll index b635263a5726c..24f04ae1fccb9 100644 --- a/llvm/test/Transforms/SCCP/sitofp.ll +++ b/llvm/test/Transforms/SCCP/sitofp.ll @@ -4,7 +4,7 @@ define float @sitofp_and(i8 %x) { ; CHECK-LABEL: @sitofp_and( ; CHECK-NEXT: [[PX:%.*]] = and i8 [[X:%.*]], 127 -; CHECK-NEXT: [[R:%.*]] = sitofp i8 [[PX]] to float +; CHECK-NEXT: [[R:%.*]] = uitofp nneg i8 [[PX]] to float ; CHECK-NEXT: ret float [[R]] ; %px = and i8 %x, 127 @@ -23,7 +23,7 @@ define half @sitofp_const(i8 %x) { define double @sitofp_zext(i7 %x) { ; CHECK-LABEL: @sitofp_zext( ; CHECK-NEXT: [[PX:%.*]] = zext i7 [[X:%.*]] to i8 -; CHECK-NEXT: [[R:%.*]] = sitofp i8 [[PX]] to double +; CHECK-NEXT: [[R:%.*]] = uitofp nneg i8 [[PX]] to double ; CHECK-NEXT: ret double [[R]] ; %px = zext i7 %x to i8 @@ -52,7 +52,7 @@ define float @dominating_condition(i32 %x) { ; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]] ; CHECK: t: -; CHECK-NEXT: [[A:%.*]] = sitofp i32 [[X]] to float +; CHECK-NEXT: [[A:%.*]] = uitofp nneg i32 [[X]] to float ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: f: ; CHECK-NEXT: br label [[EXIT]] @@ -86,7 +86,7 @@ define float @dominating_condition_alt(i32 %x) { ; CHECK: t: ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: f: -; CHECK-NEXT: [[A:%.*]] = sitofp i32 [[X]] to float +; CHECK-NEXT: [[A:%.*]] = uitofp nneg i32 [[X]] to float ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: [[COND:%.*]] = phi float [ -4.200000e+01, [[T]] ], [ [[A]], [[F]] ]