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 @@ -2900,6 +2900,16 @@ return nullptr; } +static bool callPassesUndefToNoUndefParam(CallBase &Call) { + for (unsigned I = 0; I < Call.arg_size(); ++I) { + if (Call.paramHasAttr(I, Attribute::NoUndef) && + isa(Call.getArgOperand(I))) { + return true; + } + } + return false; +} + bool InstCombinerImpl::annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI) { // Note: We only handle cases which can't be driven from generic attributes @@ -3026,9 +3036,10 @@ // Calling a null function pointer is undefined if a null address isn't // dereferenceable. + // Passing an undef/poison argument to a noundef parameter is undefined. if ((isa(Callee) && !NullPointerIsDefined(Call.getFunction())) || - isa(Callee)) { + isa(Callee) || callPassesUndefToNoUndefParam(Call)) { // If Call does not return void then replaceInstUsesWith poison. // This allows ValueHandlers and custom metadata to adjust itself. if (!Call.getType()->isVoidTy()) diff --git a/llvm/test/Transforms/InstCombine/call-undef.ll b/llvm/test/Transforms/InstCombine/call-undef.ll --- a/llvm/test/Transforms/InstCombine/call-undef.ll +++ b/llvm/test/Transforms/InstCombine/call-undef.ll @@ -6,7 +6,7 @@ define void @test1() { ; CHECK-LABEL: @test1( -; CHECK-NEXT: call void @c(i32 undef) +; CHECK-NEXT: store i1 true, ptr poison, align 1 ; CHECK-NEXT: ret void ; call void @c(i32 undef) @@ -15,7 +15,7 @@ define void @test2() { ; CHECK-LABEL: @test2( -; CHECK-NEXT: call void @c(i32 poison) +; CHECK-NEXT: store i1 true, ptr poison, align 1 ; CHECK-NEXT: ret void ; call void @c(i32 poison) @@ -24,7 +24,7 @@ define void @test3() { ; CHECK-LABEL: @test3( -; CHECK-NEXT: call void @d(i32 noundef undef) +; CHECK-NEXT: store i1 true, ptr poison, align 1 ; CHECK-NEXT: ret void ; call void @d(i32 noundef undef) @@ -33,7 +33,7 @@ define void @test4() { ; CHECK-LABEL: @test4( -; CHECK-NEXT: call void @d(i32 noundef poison) +; CHECK-NEXT: store i1 true, ptr poison, align 1 ; CHECK-NEXT: ret void ; call void @d(i32 noundef poison) diff --git a/llvm/test/Transforms/InstCombine/out-of-bounds-indexes.ll b/llvm/test/Transforms/InstCombine/out-of-bounds-indexes.ll --- a/llvm/test/Transforms/InstCombine/out-of-bounds-indexes.ll +++ b/llvm/test/Transforms/InstCombine/out-of-bounds-indexes.ll @@ -6,7 +6,7 @@ ; CHECK-LABEL: @test_out_of_bounds( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[AND1:%.*]] = and i32 [[A:%.*]], 3 -; CHECK-NEXT: tail call void @llvm.assume(i1 poison) +; CHECK-NEXT: store i1 true, ptr poison, align 1 ; CHECK-NEXT: ret i32 [[AND1]] ; entry: @@ -20,7 +20,7 @@ define i128 @test_non64bit(i128 %a) { ; CHECK-LABEL: @test_non64bit( ; CHECK-NEXT: [[AND1:%.*]] = and i128 [[A:%.*]], 3 -; CHECK-NEXT: tail call void @llvm.assume(i1 poison) +; CHECK-NEXT: store i1 true, ptr poison, align 1 ; CHECK-NEXT: ret i128 [[AND1]] ; %and1 = and i128 %a, 3