diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2799,8 +2799,10 @@ if (isa(Op)) return eraseInstFromFunction(FI); - // If we free a pointer we've been explicitly told won't be freed, this - // would be full UB and thus we can conclude this is unreachable. Cases: + + // If we free a non-null pointer we've been explicitly told won't be freed, + // this would be full UB and thus we can conclude that the argument must + // be null at the point of the free. Cases: // 1) freeing a pointer which is explicitly nofree // 2) calling free from a call site marked nofree (TODO: can generalize // for non-arguments) @@ -2810,8 +2812,9 @@ if (A->hasAttribute(Attribute::NoFree) || FI.hasFnAttr(Attribute::NoFree) || FI.getFunction()->hasFnAttribute(Attribute::NoFree)) { - // Leave a marker since we can't modify the CFG here. - CreateNonTerminatorUnreachable(&FI); + Value *Null = ConstantPointerNull::get(cast(A->getType())); + Value *Cond = Builder.CreateICmpEQ(A, Null); + Builder.CreateAssumption(Cond); return eraseInstFromFunction(FI); } diff --git a/llvm/test/Transforms/InstCombine/malloc-free-delete.ll b/llvm/test/Transforms/InstCombine/malloc-free-delete.ll --- a/llvm/test/Transforms/InstCombine/malloc-free-delete.ll +++ b/llvm/test/Transforms/InstCombine/malloc-free-delete.ll @@ -391,32 +391,45 @@ ret void } -; Freeing a no-free pointer -> full UB +; Freeing a no-free pointer -> %foo must be null define void @test13(i8* nofree %foo) { ; CHECK-LABEL: @test13( -; CHECK-NEXT: store i1 true, i1* undef, align 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* [[FOO:%.*]], null +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]]) ; CHECK-NEXT: ret void ; call void @free(i8* %foo) ret void } -; Freeing a no-free pointer -> full UB +; Freeing a no-free pointer -> %foo must be null define void @test14(i8* %foo) nofree { ; CHECK-LABEL: @test14( -; CHECK-NEXT: store i1 true, i1* undef, align 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* [[FOO:%.*]], null +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]]) ; CHECK-NEXT: ret void ; call void @free(i8* %foo) ret void } -; free call marked no-free -> full UB +; free call marked no-free -> %foo must be null define void @test15(i8* %foo) { ; CHECK-LABEL: @test15( -; CHECK-NEXT: store i1 true, i1* undef, align 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8* [[FOO:%.*]], null +; CHECK-NEXT: call void @llvm.assume(i1 [[TMP1]]) ; CHECK-NEXT: ret void ; call void @free(i8* %foo) nofree ret void } + +; freeing a nonnull nofree pointer -> full UB +define void @test16(i8* nonnull nofree %foo) { +; CHECK-LABEL: @test16( +; CHECK-NEXT: call void @llvm.assume(i1 false) +; CHECK-NEXT: ret void +; + call void @free(i8* %foo) + ret void +}