Index: llvm/lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -3115,7 +3115,8 @@ /// beginning of DestBlock, which can only happen if it's safe to move the /// instruction past all of the instructions between it and the end of its /// block. -static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) { +static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock, + InstCombiner::BuilderTy &Builder) { assert(I->hasOneUse() && "Invariants didn't hold!"); BasicBlock *SrcBlock = I->getParent(); @@ -3149,6 +3150,24 @@ if (Scan->mayWriteToMemory()) return false; } + + // If this instruction was providing nonnull guarantees insert assumptions for + // nonnull arguments. + if (auto CS = CallSite(I)) { + auto *CalledFunc = CS.getCalledFunction(); + for (unsigned Idx = 0; Idx != CS.getNumArgOperands(); Idx++) + if (!isa(CS.getArgument(Idx)) && + ((CalledFunc && CalledFunc->getArg(Idx)->hasNonNullAttr()) || + CS.paramHasAttr(Idx, Attribute::NonNull) || + (CS.paramHasAttr(Idx, Attribute::Dereferenceable) && + CS.getAttributes().getParamDereferenceableBytes(Idx) > 0))) { + Value *V = CS.getArgument(Idx); + + Builder.SetInsertPoint(I->getParent(), I->getIterator()); + Builder.CreateAssumption(Builder.CreateIsNotNull(V)); + } + } + BasicBlock::iterator InsertPos = DestBlock->getFirstInsertionPt(); I->moveBefore(&*InsertPos); ++NumSunkInst; @@ -3283,7 +3302,7 @@ // otherwise), we can keep going. if (UserIsSuccessor && UserParent->getUniquePredecessor()) { // Okay, the CFG is simple enough, try to sink this instruction. - if (TryToSinkInstruction(I, UserParent)) { + if (TryToSinkInstruction(I, UserParent, Builder)) { LLVM_DEBUG(dbgs() << "IC: Sink: " << *I << '\n'); MadeIRChange = true; // We'll add uses of the sunk instruction below, but since sinking Index: llvm/test/Transforms/InstCombine/Assume-Remplacing-Call.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/Assume-Remplacing-Call.ll @@ -0,0 +1,92 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i32 @test_sink_remplacement1(i8* %p) { +;CHECK-LABEL: @test_sink_remplacement1( +;CHECK-NEXT: {{.*}}: +;CHECK-NEXT: [[CMP0:%.*]] = icmp ne i8* [[P:%.*]], null +;CHECK-NEXT: call void @llvm.assume(i1 [[CMP0]]) +;CHECK-NEXT: {{%.*}} = icmp eq i8* [[P]], null + +;CHECK: %call = call i64 @func_test(i8* nonnull [[P]]) #2 +;CHECK: } + +entry: + %call = call i64 @func_test(i8* nonnull %p) #2 + %conv = trunc i64 %call to i32 + %tobool = icmp ne i8* %p, null + br i1 %tobool, label %if.end, label %if.then + +if.then: + br label %cleanup + +if.end: + br label %cleanup + +cleanup: + %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] + ret i32 %retval.0 +} + +define i32 @test_sink_remplacement2(i8* %p) { +;CHECK-LABEL: @test_sink_remplacement2( +;CHECK-NEXT: {{.*}}: +;CHECK-NEXT: [[CMP0:%.*]] = icmp ne i8* [[P:%.*]], null +;CHECK-NEXT: call void @llvm.assume(i1 [[CMP0]]) +;CHECK-NEXT: {{%.*}} = icmp eq i8* [[P]], null + +;CHECK: %call = call i64 @func_test(i8* {{.*}} [[P]]) #2 +;CHECK: } + +entry: + %call = call i64 @func_test(i8* dereferenceable(1) %p) #2 + %conv = trunc i64 %call to i32 + %tobool = icmp ne i8* %p, null + br i1 %tobool, label %if.end, label %if.then + +if.then: + br label %cleanup + +if.end: + br label %cleanup + +cleanup: + %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] + ret i32 %retval.0 +} + +define i32 @test_sink_remplacement3(i8* %p) { +;CHECK-LABEL: @test_sink_remplacement3( +;CHECK-NEXT: {{.*}}: +;CHECK-NEXT: [[CMP0:%.*]] = icmp ne i8* [[P:%.*]], null +;CHECK-NEXT: call void @llvm.assume(i1 [[CMP0]]) +;CHECK-NEXT: {{%.*}} = icmp eq i8* [[P]], null + +;CHECK: %call = call i64 @func_test1(i8* [[P]]) #2 +;CHECK: } + +entry: + %call = call i64 @func_test1(i8* %p) #2 + %conv = trunc i64 %call to i32 + %tobool = icmp ne i8* %p, null + br i1 %tobool, label %if.end, label %if.then + +if.then: + br label %cleanup + +if.end: + br label %cleanup + +cleanup: + %retval.0 = phi i32 [ %conv, %if.end ], [ -1, %if.then ] + ret i32 %retval.0 +} + +declare i64 @func_test(i8* %0) #1 + +declare i64 @func_test1(i8* nonnull %0) #3 + +attributes #1 = { readonly } +attributes #2 = { nounwind } +attributes #3 = { readonly }