diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index bfd26fadd237b..79ed66316da37 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -9687,12 +9687,12 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned, unsigned Depth) { assert(V->getType()->isIntOrIntVectorTy() && "Expected integer instruction"); - if (Depth == MaxAnalysisRecursionDepth) - return ConstantRange::getFull(V->getType()->getScalarSizeInBits()); - if (auto *C = dyn_cast(V)) return C->toConstantRange(); + if (Depth == MaxAnalysisRecursionDepth) + return ConstantRange::getFull(V->getType()->getScalarSizeInBits()); + unsigned BitWidth = V->getType()->getScalarSizeInBits(); InstrInfoQuery IIQ(UseInstrInfo); ConstantRange CR = ConstantRange::getFull(BitWidth); @@ -9728,6 +9728,17 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned, if (const auto *CB = dyn_cast(V)) if (std::optional Range = CB->getRange()) CR = CR.intersectWith(*Range); + + if (const auto *II = dyn_cast(V)) { + Intrinsic::ID IID = II->getIntrinsicID(); + if (ConstantRange::isIntrinsicSupported(IID)) { + SmallVector OpRanges; + for (Value *Op : II->args()) + OpRanges.push_back(computeConstantRange(Op, ForSigned, UseInstrInfo, + AC, CtxI, DT, Depth + 1)); + CR = CR.intersectWith(ConstantRange::intrinsic(IID, OpRanges)); + } + } } if (CtxI && AC) { diff --git a/llvm/test/Analysis/ValueTracking/constant-ranges.ll b/llvm/test/Analysis/ValueTracking/constant-ranges.ll index c440cfad889d3..bc9d78f4473b3 100644 --- a/llvm/test/Analysis/ValueTracking/constant-ranges.ll +++ b/llvm/test/Analysis/ValueTracking/constant-ranges.ll @@ -230,3 +230,72 @@ define i1 @srem_negC_fail1(i8 %x) { %r = icmp sge i8 %val, -33 ret i1 %r } + +define i1 @intrinsic_test1(i64 %x, i32 %y, i64 %z) { +; CHECK-LABEL: @intrinsic_test1( +; CHECK-NEXT: ret i1 false +; + %sh_prom = zext nneg i32 %y to i64 + %shl = shl nuw i64 1, %sh_prom + %cmp1 = icmp eq i64 %z, 0 + %umin1 = call i64 @llvm.umin.i64(i64 %shl, i64 %z) + %sel = select i1 %cmp1, i64 1, i64 %umin1 + %umin2 = call i64 @llvm.umin.i64(i64 %x, i64 %sel) + %cmp = icmp ugt i64 %umin2, -71777214294589697 + ret i1 %cmp +} + +define i1 @intrinsic_test2(i32 %x, i32 %y) { +; CHECK-LABEL: @intrinsic_test2( +; CHECK-NEXT: [[SH:%.*]] = shl nuw nsw i32 16, [[X:%.*]] +; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[SH]], i32 64) +; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[Y:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[ADD]], [[UMIN]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %sh = shl nuw nsw i32 16, %x + %umin = call i32 @llvm.umin.i32(i32 %sh, i32 64) + %umax = call i32 @llvm.umax.i32(i32 %umin, i32 1) + %add = add nuw nsw i32 %y, 1 + %cmp = icmp eq i32 %add, %umax + ret i1 %cmp +} + +define i1 @constant_test(i64 %x, i1 %cond) { +; CHECK-LABEL: @constant_test( +; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], i64 2147483647, i64 18446744073709551 +; CHECK-NEXT: [[CMP2:%.*]] = icmp ugt i64 [[X:%.*]], [[SEL]] +; CHECK-NEXT: ret i1 [[CMP2]] +; + %sel = select i1 %cond, i64 2147483647, i64 18446744073709551 + %cmp1 = icmp slt i64 %x, 0 + %cmp2 = icmp ugt i64 %x, %sel + %or.cond = or i1 %cmp1, %cmp2 + ret i1 %or.cond +} + +; Make sure that we don't return a full range for an imm arg. +define i1 @immarg_test(i32 %x, i32 %y, i1 %c1, i1 %c2, i1 %c3, i1 %c4, i1 %c5, i1 %c6, i1 %c7) { +; CHECK-LABEL: @immarg_test( +; CHECK-NEXT: [[ABS:%.*]] = call i32 @llvm.abs.i32(i32 [[Y:%.*]], i1 true) +; CHECK-NEXT: [[M1:%.*]] = select i1 [[C1:%.*]], i32 [[ABS]], i32 0 +; CHECK-NEXT: [[M2:%.*]] = select i1 [[C2:%.*]], i32 [[M1]], i32 1 +; CHECK-NEXT: [[M3:%.*]] = select i1 [[C3:%.*]], i32 [[M2]], i32 2 +; CHECK-NEXT: [[M4:%.*]] = select i1 [[C4:%.*]], i32 [[M3]], i32 3 +; CHECK-NEXT: [[M5:%.*]] = select i1 [[C5:%.*]], i32 [[M4]], i32 4 +; CHECK-NEXT: [[M6:%.*]] = select i1 [[C6:%.*]], i32 [[M5]], i32 5 +; CHECK-NEXT: [[M7:%.*]] = select i1 [[C7:%.*]], i32 [[M6]], i32 6 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[M7]], 1 +; CHECK-NEXT: ret i1 [[CMP]] +; + %abs = call i32 @llvm.abs.i32(i32 %y, i1 true) + %m1 = select i1 %c1, i32 %abs, i32 0 + %m2 = select i1 %c2, i32 %m1, i32 1 + %m3 = select i1 %c3, i32 %m2, i32 2 + %m4 = select i1 %c4, i32 %m3, i32 3 + %m5 = select i1 %c5, i32 %m4, i32 4 + %m6 = select i1 %c6, i32 %m5, i32 5 + %m7 = select i1 %c7, i32 %m6, i32 6 + %cmp = icmp eq i32 %m7, 1 + ret i1 %cmp +} diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll index cb308ab66b093..1070b9ff745a7 100644 --- a/llvm/test/Transforms/InstCombine/sub.ll +++ b/llvm/test/Transforms/InstCombine/sub.ll @@ -1329,7 +1329,7 @@ define <2 x i32> @test68(<2 x i32> %x) { define <2 x i32> @test69(<2 x i32> %x) { ; CHECK-LABEL: @test69( ; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.smin.v2i32(<2 x i32> [[X:%.*]], <2 x i32> ) -; CHECK-NEXT: [[DOTNEG:%.*]] = add <2 x i32> [[TMP1]], +; CHECK-NEXT: [[DOTNEG:%.*]] = add nsw <2 x i32> [[TMP1]], ; CHECK-NEXT: ret <2 x i32> [[DOTNEG]] ; %1 = xor <2 x i32> %x, diff --git a/llvm/test/Transforms/InstSimplify/call.ll b/llvm/test/Transforms/InstSimplify/call.ll index c6f6b65f89dc2..503be81c65645 100644 --- a/llvm/test/Transforms/InstSimplify/call.ll +++ b/llvm/test/Transforms/InstSimplify/call.ll @@ -1582,9 +1582,7 @@ define i1 @ctlz_i1_non_poison_eq_false(i1 %x) { define i1 @ctlz_i1_poison_eq_false(i1 %x) { ; CHECK-LABEL: @ctlz_i1_poison_eq_false( -; CHECK-NEXT: [[CT:%.*]] = call i1 @llvm.ctlz.i1(i1 [[X:%.*]], i1 true) -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i1 [[CT]], false -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %ct = call i1 @llvm.ctlz.i1(i1 %x, i1 true) %cmp = icmp eq i1 %ct, false @@ -1604,9 +1602,7 @@ define i1 @cttz_i1_non_poison_eq_false(i1 %x) { define i1 @cttz_i1_poison_eq_false(i1 %x) { ; CHECK-LABEL: @cttz_i1_poison_eq_false( -; CHECK-NEXT: [[CT:%.*]] = call i1 @llvm.cttz.i1(i1 [[X:%.*]], i1 true) -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i1 [[CT]], false -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 true ; %ct = call i1 @llvm.cttz.i1(i1 %x, i1 true) %cmp = icmp eq i1 %ct, false