[InlineCost] Consider branches with !make.implicit metadata as free.
authorDenis Antrushin <dantrushin@gmail.com>
Tue, 2 May 2023 17:16:42 +0000 (00:16 +0700)
committerDenis Antrushin <dantrushin@gmail.com>
Thu, 25 May 2023 15:43:16 +0000 (18:43 +0300)
!make.implicit metadata attached to branch means it will very likely
be eliminated (together with associated cmp instruction).

Reviewed By: apilipenko

Differential Revision: https://reviews.llvm.org/D149747

llvm/lib/Analysis/InlineCost.cpp
llvm/test/Transforms/Inline/implicit-null-check.ll [new file with mode: 0644]

index 09d4b81..02871aa 100644 (file)
@@ -1976,14 +1976,27 @@ bool CallAnalyzer::visitCmpInst(CmpInst &I) {
     }
   }
 
+  auto isImplicitNullCheckCmp = [](const CmpInst &I) {
+    for (auto *User : I.users())
+      if (auto *Instr = dyn_cast<Instruction>(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<ConstantPointerNull>(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<ConstantPointerNull>(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<ConstantPointerNull>(I.getOperand(1)));
 }
@@ -2265,6 +2278,7 @@ bool CallAnalyzer::visitBranchInst(BranchInst &BI) {
   // inliner more regular and predictable. Interestingly, conditional branches
   // which will fold away are also free.
   return BI.isUnconditional() || isa<ConstantInt>(BI.getCondition()) ||
+         BI.getMetadata(LLVMContext::MD_make_implicit) ||
          isa_and_nonnull<ConstantInt>(
              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 (file)
index 0000000..06e6ae6
--- /dev/null
@@ -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 = !{}