diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -1976,14 +1976,27 @@ } } + auto isImplicitNullCheckCmp = [](const CmpInst &I) { + for (auto *User : I.users()) + if (auto *Instr = dyn_cast(User)) + if (!Instr->getMetadata(LLVMContext::MD_make_implicit)) + return false; + return true; + }; + // If the comparison is an equality comparison with null, we can simplify it // if we know the value (argument) can't be null - if (I.isEquality() && isa(I.getOperand(1)) && - isKnownNonNullInCallee(I.getOperand(0))) { - bool IsNotEqual = I.getPredicate() == CmpInst::ICMP_NE; - SimplifiedValues[&I] = IsNotEqual ? ConstantInt::getTrue(I.getType()) - : ConstantInt::getFalse(I.getType()); - return true; + if (I.isEquality() && isa(I.getOperand(1))) { + if (isKnownNonNullInCallee(I.getOperand(0))) { + bool IsNotEqual = I.getPredicate() == CmpInst::ICMP_NE; + SimplifiedValues[&I] = IsNotEqual ? ConstantInt::getTrue(I.getType()) + : ConstantInt::getFalse(I.getType()); + return true; + } + // Implicit null checks act as unconditional branches and their comparisons + // should be treated as simplified and free of cost. + if (isImplicitNullCheckCmp(I)) + return true; } return handleSROA(I.getOperand(0), isa(I.getOperand(1))); } @@ -2265,6 +2278,7 @@ // inliner more regular and predictable. Interestingly, conditional branches // which will fold away are also free. return BI.isUnconditional() || isa(BI.getCondition()) || + BI.getMetadata(LLVMContext::MD_make_implicit) || isa_and_nonnull( SimplifiedValues.lookup(BI.getCondition())); } diff --git a/llvm/test/Transforms/Inline/implicit-null-check.ll b/llvm/test/Transforms/Inline/implicit-null-check.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Inline/implicit-null-check.ll @@ -0,0 +1,24 @@ +; RUN: opt -passes=inline -inline-threshold=10 -S < %s | FileCheck %s + +declare void @foo() + +; CHECK-LABEL: @caller +; CHECK-NOT: %res = call i64 @callee(ptr %p) +define i64 @caller(ptr %p) { + %res = call i64 @callee(ptr %p) + ret i64 %res +} + +define i64 @callee(ptr %p) { + %null_check = icmp eq ptr %p, null + br i1 %null_check, label %is_null, label %non_null, !make.implicit !0 + +is_null: + call void @foo() + ret i64 0 + +non_null: + ret i64 1 +} + +!0 = !{}