Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2981,6 +2981,18 @@ return nullptr; } +static bool isProfitableToSink(CallInst &CI) { + // If the function is called some nonnull argument, we should not sink it. + // Later passes can be more powerful (e.g. optimize null checks) + for (auto &Arg : CI.getCalledFunction()->args()) { + auto *FArg = dyn_cast(CI.getArgOperand(Arg.getArgNo())); + if (FArg && FArg->hasNonNullAttr()) { + return false; + } + } + return true; +} + /// Try to move the specified instruction from its current block into the /// 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 @@ -3005,7 +3017,7 @@ // Do not sink convergent call instructions. if (auto *CI = dyn_cast(I)) { - if (CI->isConvergent()) + if (CI->isConvergent() || !isProfitableToSink(*CI)) return false; } // We can only sink load instructions if there is nothing between the load and Index: test/Transforms/InstCombine/no-sink-nonnull-args.ll =================================================================== --- test/Transforms/InstCombine/no-sink-nonnull-args.ll +++ test/Transforms/InstCombine/no-sink-nonnull-args.ll @@ -0,0 +1,56 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +define i32 @no_sink_nonnull(i8* nonnull readonly %s) { +; CHECK-LABEL: @no_sink_nonnull( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @foo(i8* nonnull [[S:%.*]]) +; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: unreachable +; CHECK: if.end: +; CHECK-NEXT: ret i32 [[CALL]] +; +entry: + %call = tail call i32 @foo(i8* nonnull %s) + %tobool = icmp eq i8* %s, null + br i1 %tobool, label %if.then, label %if.end + +if.then: + tail call void @abort() + unreachable + +if.end: + ret i32 %call +} + +define i32 @sink(i8* readonly %s) { +; CHECK-LABEL: @sink( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[S:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: tail call void @abort() +; CHECK-NEXT: unreachable +; CHECK: if.end: +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @foo(i8* nonnull [[S]]) +; CHECK-NEXT: ret i32 [[CALL]] +; +entry: + %call = tail call i32 @foo(i8* %s) + %tobool = icmp eq i8* %s, null + br i1 %tobool, label %if.then, label %if.end + +if.then: + tail call void @abort() + unreachable + +if.end: + ret i32 %call +} + +; Function Attrs: argmemonly nounwind readonly +declare i32 @foo(i8* nocapture) local_unnamed_addr #1 +declare void @abort() + +attributes #1 = { argmemonly nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }