diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -505,6 +505,21 @@ return cast(Result); } +static bool isGuaranteedDoNotViolateRangeMetadata(Instruction *I, + unsigned KnownMin, + unsigned KnownMax) { + if (MDNode *Node = I->getMetadata(LLVMContext::MD_range)) + if (mdconst::extract(Node->getOperand(0)) + ->equalsInt(KnownMin) && + mdconst::extract(Node->getOperand(1))->equalsInt(KnownMax)) + if (!canCreateUndefOrPoison(cast(I), + /*ConsiderFlagsAndMetadata*/ false) && + all_of(I->operands(), + [&](Value *V) { return isGuaranteedNotToBeUndefOrPoison(V); })) + return true; + return false; +} + static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) { assert((II.getIntrinsicID() == Intrinsic::cttz || II.getIntrinsicID() == Intrinsic::ctlz) && @@ -602,6 +617,12 @@ return &II; } + if (!II.getMetadata(LLVMContext::MD_noundef) && + isGuaranteedDoNotViolateRangeMetadata(&II, DefiniteZeros, + PossibleZeros + 1)) + II.setMetadata(LLVMContext::MD_noundef, + MDNode::get(II.getContext(), nullptr)); + return nullptr; } @@ -683,6 +704,11 @@ return &II; } + if (!II.getMetadata(LLVMContext::MD_noundef) && + isGuaranteedDoNotViolateRangeMetadata(&II, MinCount, MaxCount + 1)) + II.setMetadata(LLVMContext::MD_noundef, + MDNode::get(II.getContext(), nullptr)); + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/ctpop.ll b/llvm/test/Transforms/InstCombine/ctpop.ll --- a/llvm/test/Transforms/InstCombine/ctpop.ll +++ b/llvm/test/Transforms/InstCombine/ctpop.ll @@ -475,3 +475,12 @@ %i5 = xor i32 %i2, %i4 ret i32 %i5 } + +define i8 @arg_noundef(i8 noundef %arg) { +; CHECK-LABEL: @arg_noundef( +; CHECK-NEXT: [[CNT:%.*]] = call i8 @llvm.ctpop.i8(i8 [[ARG:%.*]]), !range [[RNG0]], !noundef !6 +; CHECK-NEXT: ret i8 [[CNT]] +; + %cnt = call i8 @llvm.ctpop.i8(i8 %arg) + ret i8 %cnt +} diff --git a/llvm/test/Transforms/InstCombine/cttz.ll b/llvm/test/Transforms/InstCombine/cttz.ll --- a/llvm/test/Transforms/InstCombine/cttz.ll +++ b/llvm/test/Transforms/InstCombine/cttz.ll @@ -118,3 +118,25 @@ %tz = tail call <2 x i64> @llvm.cttz.v2i64(<2 x i64> %s, i1 false) ret <2 x i64> %tz } + +define i32 @cttz_arg_noundef_zero_poison(i16 noundef %x) { +; CHECK-LABEL: @cttz_arg_noundef_zero_poison( +; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.cttz.i16(i16 [[X:%.*]], i1 true), !range [[RNG0]] +; CHECK-NEXT: [[TZ:%.*]] = zext i16 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[TZ]] +; + %z = zext i16 %x to i32 + %tz = call i32 @llvm.cttz.i32(i32 %z, i1 true) + ret i32 %tz +} + +define i32 @cttz_arg_noundef(i16 noundef %x) { +; CHECK-LABEL: @cttz_arg_noundef( +; CHECK-NEXT: [[Z:%.*]] = zext i16 [[X:%.*]] to i32 +; CHECK-NEXT: [[TZ:%.*]] = call i32 @llvm.cttz.i32(i32 [[Z]], i1 false), !range [[RNG1]], !noundef !3 +; CHECK-NEXT: ret i32 [[TZ]] +; + %z = zext i16 %x to i32 + %tz = call i32 @llvm.cttz.i32(i32 %z, i1 false) + ret i32 %tz +}