diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -67,6 +67,7 @@ STATISTIC(NumAShrs, "Number of ashr converted to lshr"); STATISTIC(NumSRems, "Number of srem converted to urem"); STATISTIC(NumSExt, "Number of sext converted to zext"); +STATISTIC(NumSICmps, "Number of signed icmp preds simplified to unsigned"); STATISTIC(NumAnd, "Number of ands removed"); STATISTIC(NumNW, "Number of no-wrap deductions"); STATISTIC(NumNSW, "Number of no-signed-wrap deductions"); @@ -295,11 +296,39 @@ return true; } +static bool processICmp(ICmpInst *Cmp, LazyValueInfo *LVI) { + // Only for signed relational comparisons of scalar integers. + if (Cmp->getType()->isVectorTy() || + !Cmp->getOperand(0)->getType()->isIntegerTy()) + return false; + + if (!Cmp->isSigned()) + return false; + + ICmpInst::Predicate UnsignedPred = + ConstantRange::getEquivalentPredWithFlippedSignedness( + Cmp->getPredicate(), LVI->getConstantRange(Cmp->getOperand(0), Cmp), + LVI->getConstantRange(Cmp->getOperand(1), Cmp)); + + if (UnsignedPred == ICmpInst::Predicate::BAD_ICMP_PREDICATE) + return false; + + ++NumSICmps; + Instruction *UnsignedCmp = + ICmpInst::Create(Instruction::ICmp, UnsignedPred, Cmp->getOperand(0), + Cmp->getOperand(1), Cmp->getName(), Cmp); + UnsignedCmp->setDebugLoc(Cmp->getDebugLoc()); + Cmp->replaceAllUsesWith(UnsignedCmp); + Cmp->eraseFromParent(); + + return true; +} + /// See if LazyValueInfo's ability to exploit edge conditions or range /// information is sufficient to prove this comparison. Even for local /// conditions, this can sometimes prove conditions instcombine can't by /// exploiting range information. -static bool processCmp(CmpInst *Cmp, LazyValueInfo *LVI) { +static bool constantFoldNonLocalCmp(CmpInst *Cmp, LazyValueInfo *LVI) { Value *Op0 = Cmp->getOperand(0); auto *C = dyn_cast(Cmp->getOperand(1)); if (!C) @@ -318,6 +347,17 @@ return true; } +static bool processCmp(CmpInst *Cmp, LazyValueInfo *LVI) { + if (constantFoldNonLocalCmp(Cmp, LVI)) + return true; + + if (auto *ICmp = dyn_cast(Cmp)) + if (processICmp(ICmp, LVI)) + return true; + + return false; +} + /// Simplify a switch instruction by removing cases which can never fire. If the /// uselessness of a case could be determined locally then constant propagation /// would already have figured it out. Instead, walk the predecessors and diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll b/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/basic.ll @@ -532,8 +532,8 @@ ; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[B:%.*]], 20 ; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]] ; CHECK: b_guard: -; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sle i32 [[A]], [[B]] -; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]] +; CHECK-NEXT: [[SEL_CMP1:%.*]] = icmp ule i32 [[A]], [[B]] +; CHECK-NEXT: [[MIN:%.*]] = select i1 [[SEL_CMP1]], i32 [[A]], i32 [[B]] ; CHECK-NEXT: ret i1 false ; CHECK: out: ; CHECK-NEXT: ret i1 false @@ -564,8 +564,8 @@ ; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[B:%.*]], 20 ; CHECK-NEXT: br i1 [[CMP2]], label [[B_GUARD:%.*]], label [[OUT]] ; CHECK: b_guard: -; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sge i32 [[A]], [[B]] -; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP]], i32 [[A]], i32 [[B]] +; CHECK-NEXT: [[SEL_CMP1:%.*]] = icmp uge i32 [[A]], [[B]] +; CHECK-NEXT: [[MAX:%.*]] = select i1 [[SEL_CMP1]], i32 [[A]], i32 [[B]] ; CHECK-NEXT: ret i1 false ; CHECK: out: ; CHECK-NEXT: ret i1 false @@ -737,9 +737,9 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A:%.*]], 5 ; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]] ; CHECK: a_guard: -; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sgt i32 [[A]], 5 +; CHECK-NEXT: [[SEL_CMP1:%.*]] = icmp ugt i32 [[A]], 5 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 [[ADD]], i32 5 +; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP1]], i32 [[ADD]], i32 5 ; CHECK-NEXT: ret i1 false ; CHECK: out: ; CHECK-NEXT: ret i1 false @@ -764,9 +764,9 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A:%.*]], 5 ; CHECK-NEXT: br i1 [[CMP]], label [[A_GUARD:%.*]], label [[OUT:%.*]] ; CHECK: a_guard: -; CHECK-NEXT: [[SEL_CMP:%.*]] = icmp sle i32 [[A]], 5 +; CHECK-NEXT: [[SEL_CMP1:%.*]] = icmp ule i32 [[A]], 5 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], -1 -; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP]], i32 5, i32 [[ADD]] +; CHECK-NEXT: [[SEL:%.*]] = select i1 [[SEL_CMP1]], i32 5, i32 [[ADD]] ; CHECK-NEXT: ret i1 false ; CHECK: out: ; CHECK-NEXT: ret i1 false @@ -933,11 +933,11 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], 0 ; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 [[A]] ; CHECK-NEXT: store i1 true, i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[ABS]], 19 -; CHECK-NEXT: store i1 [[C2]], i1* [[P]], align 1 +; CHECK-NEXT: [[C21:%.*]] = icmp ult i32 [[ABS]], 19 +; CHECK-NEXT: store i1 [[C21]], i1* [[P]], align 1 ; CHECK-NEXT: store i1 true, i1* [[P]], align 1 -; CHECK-NEXT: [[C4:%.*]] = icmp sge i32 [[ABS]], 1 -; CHECK-NEXT: store i1 [[C4]], i1* [[P]], align 1 +; CHECK-NEXT: [[C42:%.*]] = icmp uge i32 [[ABS]], 1 +; CHECK-NEXT: store i1 [[C42]], i1* [[P]], align 1 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void @@ -978,11 +978,11 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[A]], 0 ; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[A]], i32 [[SUB]] ; CHECK-NEXT: store i1 true, i1* [[P:%.*]], align 1 -; CHECK-NEXT: [[C2:%.*]] = icmp slt i32 [[ABS]], 19 -; CHECK-NEXT: store i1 [[C2]], i1* [[P]], align 1 +; CHECK-NEXT: [[C21:%.*]] = icmp ult i32 [[ABS]], 19 +; CHECK-NEXT: store i1 [[C21]], i1* [[P]], align 1 ; CHECK-NEXT: store i1 true, i1* [[P]], align 1 -; CHECK-NEXT: [[C4:%.*]] = icmp sge i32 [[ABS]], 1 -; CHECK-NEXT: store i1 [[C4]], i1* [[P]], align 1 +; CHECK-NEXT: [[C42:%.*]] = icmp uge i32 [[ABS]], 1 +; CHECK-NEXT: store i1 [[C42]], i1* [[P]], align 1 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll b/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/deopt.ll @@ -97,8 +97,8 @@ ; CHECK-LABEL: @test3( ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C:%.*]], i64 0, i64 1 ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C2:%.*]], i64 [[SEL]], i64 2 -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[SEL2]], 1 -; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[SEL2]], 1 +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] ; CHECK: taken: ; CHECK-NEXT: call void @use() [ "deopt"(i64 2) ] ; CHECK-NEXT: ret void @@ -122,8 +122,8 @@ ; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C2:%.*]], i64 0, i64 1 ; CHECK-NEXT: [[ADD1:%.*]] = add nuw nsw i64 0, [[SEL]] ; CHECK-NEXT: [[ADD2:%.*]] = add nuw nsw i64 [[ADD1]], [[SEL2]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[ADD2]], 1 -; CHECK-NEXT: br i1 [[CMP]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] +; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[ADD2]], 1 +; CHECK-NEXT: br i1 [[CMP1]], label [[TAKEN:%.*]], label [[UNTAKEN:%.*]] ; CHECK: taken: ; CHECK-NEXT: call void @use() [ "deopt"(i64 2) ] ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll b/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/minmaxabs.ll @@ -60,8 +60,8 @@ ; CHECK-LABEL: @test_smax( ; CHECK-NEXT: [[M:%.*]] = call i32 @llvm.smax.i32(i32 [[X:%.*]], i32 10) ; CHECK-NEXT: call void @use(i1 true) -; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[M]], 10 -; CHECK-NEXT: call void @use(i1 [[C2]]) +; CHECK-NEXT: [[C21:%.*]] = icmp ugt i32 [[M]], 10 +; CHECK-NEXT: call void @use(i1 [[C21]]) ; CHECK-NEXT: ret void ; %m = call i32 @llvm.smax.i32(i32 %x, i32 10) @@ -110,8 +110,8 @@ ; CHECK-LABEL: @test_abs3( ; CHECK-NEXT: [[A:%.*]] = call i32 @llvm.abs.i32(i32 [[X:%.*]], i1 true) ; CHECK-NEXT: call void @use(i1 true) -; CHECK-NEXT: [[C2:%.*]] = icmp sgt i32 [[A]], 0 -; CHECK-NEXT: call void @use(i1 [[C2]]) +; CHECK-NEXT: [[C21:%.*]] = icmp ugt i32 [[A]], 0 +; CHECK-NEXT: call void @use(i1 [[C21]]) ; CHECK-NEXT: ret void ; %a = call i32 @llvm.abs.i32(i32 %x, i1 true) diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll b/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/overflow_predicate.ll @@ -113,8 +113,8 @@ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: -; CHECK-NEXT: [[C1:%.*]] = icmp sgt i8 [[X]], 28 -; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 +; CHECK-NEXT: [[C11:%.*]] = icmp ugt i8 [[X]], 28 +; CHECK-NEXT: store i1 [[C11]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() @@ -241,8 +241,8 @@ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[VAL_OV]], 1 ; CHECK-NEXT: br i1 [[OV]], label [[OVERFLOW:%.*]], label [[TRAP:%.*]] ; CHECK: overflow: -; CHECK-NEXT: [[C1:%.*]] = icmp slt i8 [[X]], -29 -; CHECK-NEXT: store i1 [[C1]], i1* [[PC:%.*]], align 1 +; CHECK-NEXT: [[C11:%.*]] = icmp ult i8 [[X]], -29 +; CHECK-NEXT: store i1 [[C11]], i1* [[PC:%.*]], align 1 ; CHECK-NEXT: ret i1 true ; CHECK: trap: ; CHECK-NEXT: call void @llvm.trap() diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll @@ -64,8 +64,8 @@ ; CHECK: if.then: ; CHECK-NEXT: ret i32 1 ; CHECK: if.end: -; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[C]], 3 -; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END8:%.*]] +; CHECK-NEXT: [[CMP11:%.*]] = icmp ult i32 [[C]], 3 +; CHECK-NEXT: br i1 [[CMP11]], label [[IF_THEN2:%.*]], label [[IF_END8:%.*]] ; CHECK: if.then2: ; CHECK-NEXT: br i1 true, label [[IF_THEN4:%.*]], label [[IF_END6:%.*]] ; CHECK: if.end6: diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll b/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll @@ -127,12 +127,12 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP:%.*]], label [[EXIT:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[DIV1:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[A]], 4 -; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) -; CHECK-NEXT: [[DIV1]] = udiv i32 [[A]], 6 -; CHECK-NEXT: [[LOOPCOND:%.*]] = icmp sgt i32 [[DIV1]], 8 -; CHECK-NEXT: br i1 [[LOOPCOND]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[DIV2:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[COND1:%.*]] = icmp ugt i32 [[A]], 4 +; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]]) +; CHECK-NEXT: [[DIV2]] = udiv i32 [[A]], 6 +; CHECK-NEXT: [[LOOPCOND3:%.*]] = icmp ugt i32 [[DIV2]], 8 +; CHECK-NEXT: br i1 [[LOOPCOND3]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/srem.ll @@ -40,12 +40,12 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[N:%.*]], 0 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP:%.*]], label [[EXIT:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[REM1:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[A]], 4 -; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) -; CHECK-NEXT: [[REM1]] = urem i32 [[A]], 17 -; CHECK-NEXT: [[LOOPCOND:%.*]] = icmp sgt i32 [[REM1]], 8 -; CHECK-NEXT: br i1 [[LOOPCOND]], label [[LOOP]], label [[EXIT]] +; CHECK-NEXT: [[A:%.*]] = phi i32 [ [[N]], [[ENTRY:%.*]] ], [ [[REM2:%.*]], [[LOOP]] ] +; CHECK-NEXT: [[COND1:%.*]] = icmp ugt i32 [[A]], 4 +; CHECK-NEXT: call void @llvm.assume(i1 [[COND1]]) +; CHECK-NEXT: [[REM2]] = urem i32 [[A]], 17 +; CHECK-NEXT: [[LOOPCOND3:%.*]] = icmp ugt i32 [[REM2]], 8 +; CHECK-NEXT: br i1 [[LOOPCOND3]], label [[LOOP]], label [[EXIT]] ; CHECK: exit: ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/PhaseOrdering/X86/vector-reductions-logical.ll b/llvm/test/Transforms/PhaseOrdering/X86/vector-reductions-logical.ll --- a/llvm/test/Transforms/PhaseOrdering/X86/vector-reductions-logical.ll +++ b/llvm/test/Transforms/PhaseOrdering/X86/vector-reductions-logical.ll @@ -583,13 +583,13 @@ ; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i4 [[TMP1]], 0 ; CHECK-NEXT: br i1 [[DOTNOT]], label [[IF_END:%.*]], label [[RETURN:%.*]] ; CHECK: if.end: -; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt <4 x i32> [[T_FR]], +; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt <4 x i32> [[T_FR]], ; CHECK-NEXT: [[TMP3:%.*]] = bitcast <4 x i1> [[TMP2]] to i4 -; CHECK-NEXT: [[DOTNOT7:%.*]] = icmp eq i4 [[TMP3]], 0 +; CHECK-NEXT: [[DOTNOT11:%.*]] = icmp eq i4 [[TMP3]], 0 ; CHECK-NEXT: [[SHIFT:%.*]] = shufflevector <4 x i32> [[T_FR]], <4 x i32> poison, <4 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = add nuw nsw <4 x i32> [[SHIFT]], [[T_FR]] ; CHECK-NEXT: [[ADD:%.*]] = extractelement <4 x i32> [[TMP4]], i32 0 -; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[DOTNOT7]], i32 [[ADD]], i32 0 +; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[DOTNOT11]], i32 [[ADD]], i32 0 ; CHECK-NEXT: br label [[RETURN]] ; CHECK: return: ; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[IF_END]] ]