Index: lib/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -30,6 +30,7 @@ #include "llvm/IR/InstVisitor.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -122,6 +123,10 @@ /// inlined through this particular callsite. bool isKnownNonNullInCallee(Value *V); + + /// Return true if all users of the comparison are marked as make_implicit. + bool isImplicitNullCheckCmp(CmpInst &I) ; + // Custom analysis routines. bool analyzeBlock(BasicBlock *BB, SmallPtrSetImpl &EphValues); @@ -541,6 +546,17 @@ return false; } +bool CallAnalyzer::isImplicitNullCheckCmp(CmpInst &I) { + for (auto User : I.users()) { + if (auto Instr = dyn_cast(User)) + if (Instr->getMetadata(LLVMContext::MD_make_implicit)) + continue; + + return false; + } + return true; +} + bool CallAnalyzer::visitCmpInst(CmpInst &I) { Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); // First try to handle simplified comparisons. @@ -602,6 +618,13 @@ disableSROA(CostIt); } + // Implicit null checks act as unconditional branches, and + // their comparisons should be treated as simplified and + // free of cost. See the comments in visitBranchInst. + if (I.isEquality() && isa(I.getOperand(1)) + && isImplicitNullCheckCmp(I)) + return true; + return false; } @@ -853,9 +876,10 @@ // shouldn't exist at all, but handling them makes the behavior of the // inliner more regular and predictable. Interestingly, conditional branches // which will fold away are also free. - return BI.isUnconditional() || isa(BI.getCondition()) || - dyn_cast_or_null( - SimplifiedValues.lookup(BI.getCondition())); + return BI.isUnconditional() || isa(BI.getCondition()) || + BI.getMetadata(LLVMContext::MD_make_implicit) || + dyn_cast_or_null( + SimplifiedValues.lookup(BI.getCondition())); } bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { Index: test/Transforms/Inline/implicit_null_check.ll =================================================================== --- /dev/null +++ test/Transforms/Inline/implicit_null_check.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -inline -inline-threshold=6 -S | FileCheck %s + +define i32 @callee(i32* %x) { +entry: +; The comparison and implicit null check should be free. +; The only cost is the load instruction and it is 5. + %cond = icmp eq i32* %x, null + br i1 %cond, label %is_null, label %not_null, !make.implicit !0 + +is_null: + ret i32 42 + +not_null: + %t = load i32, i32* %x + ret i32 %t +} + +define i32 @caller(i32* %arg) { +; CHECK-LABEL: @caller +; CHECK: %cond.i = icmp eq i32* %arg, null + %r = call i32 @callee(i32* %arg) + ret i32 %r +} + +!0 = !{} +