Introduce deoptimization operand bundles
authorSanjoy Das <sanjoy@playingwithpointers.com>
Wed, 11 Nov 2015 21:38:02 +0000 (21:38 +0000)
committerSanjoy Das <sanjoy@playingwithpointers.com>
Wed, 11 Nov 2015 21:38:02 +0000 (21:38 +0000)
Summary:
This change introduces the notion of "deoptimization" operand bundles.
LLVM can recognize and optimize these in more precise ways than it can a
generic "unknown" operand bundles.

The current form of this special recognition / optimization is an enum
entry in LLVMContext, a LangRef blurb and a verifier rule.  Over time we
will teach LLVM to do more aggressive optimization around deoptimization
operand bundles, exploiting known facts about kinds of state
deoptimization operand bundles are allowed to track.

Reviewers: reames, majnemer, chandlerc, dexonsmith

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D14551

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252806 91177308-0d34-0410-b5e6-96231b3b80d8

docs/LangRef.rst
include/llvm/IR/LLVMContext.h
lib/IR/LLVMContext.cpp
lib/IR/Verifier.cpp
test/Verifier/operand-bundles.ll

index d58b7b2e4df720c691de1c898d6986bc9dffdd2b..c66df4ef6e92c9c555b1e37766d0a525cd11bcda 100644 (file)
@@ -1488,6 +1488,27 @@ operand bundle to not miscompile programs containing it.
   of the called function.  Inter-procedural optimizations work as
   usual as long as they take into account the first two properties.
 
+More specific types of operand bundles are described below.
+
+Deoptimization Operand Bundles
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Deoptimization operand bundles are characterized by the ``"deopt``
+operand bundle tag.  These operand bundles represent an alternate
+"safe" continuation for the call site they're attached to, and can be
+used by a suitable runtime to deoptimize the compiled frame at the
+specified call site.  Exact details of deoptimization is out of scope
+for the language reference, but it usually involves rewriting a
+compiled frame into a set of interpreted frames.
+
+From the compiler's perspective, deoptimization operand bundles make
+the call sites they're attached to at least ``readonly``.  They read
+through all of their pointer typed operands (even if they're not
+otherwise escaped) and the entire visible heap.  Deoptimization
+operand bundles do not capture their operands except during
+deoptimization, in which case control will not be returned to the
+compiled frame.
+
 .. _moduleasm:
 
 Module-Level Inline Assembly
index 24e95f6a62fd80828c18ca092a40e45bee3fe67b..c00e3052b592d4033bcc61642b20e6cd773a5c68 100644 (file)
@@ -67,6 +67,14 @@ public:
     MD_align = 17 // "align"
   };
 
+  /// Known operand bundle tag IDs, which always have the same value.  All
+  /// operand bundle tags that LLVM has special knowledge of are listed here.
+  /// Additionally, this scheme allows LLVM to efficiently check for specific
+  /// operand bundle tags without comparing strings.
+  enum {
+    OB_deopt = 0,  // "deopt"
+  };
+
   /// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
   /// This ID is uniqued across modules in the current LLVMContext.
   unsigned getMDKindID(StringRef Name) const;
index cecc6335ef1bd8b865d912f3a401c09a6d931635..af998c861357121ee5732cdcc3395dd714bda180 100644 (file)
@@ -127,6 +127,11 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
   unsigned AlignID = getMDKindID("align");
   assert(AlignID == MD_align && "align kind id drifted");
   (void)AlignID;
+
+  auto *DeoptEntry = pImpl->getOrInsertBundleTag("deopt");
+  assert(DeoptEntry->second == LLVMContext::OB_deopt &&
+         "deopt operand bundle id drifted!");
+  (void)DeoptEntry;
 }
 LLVMContext::~LLVMContext() { delete pImpl; }
 
index 0fce50e8440191612b911aba3be579fd819d6b80..63b91957519c8e30a1c0a9bb75f8813d921c9956 100644 (file)
@@ -2324,6 +2324,15 @@ void Verifier::VerifyCallSite(CallSite CS) {
     if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
       visitIntrinsicCallSite(ID, CS);
 
+  // Verify that a callsite has at most one "deopt" operand bundle.
+  bool FoundDeoptBundle = false;
+  for (unsigned i = 0, e = CS.getNumOperandBundles(); i < e; ++i) {
+    if (CS.getOperandBundleAt(i).getTagID() == LLVMContext::OB_deopt) {
+      Assert(!FoundDeoptBundle, "Multiple deopt operand bundles", I);
+      FoundDeoptBundle = true;
+    }
+  }
+
   visitInstruction(*I);
 }
 
index 0aba61cccb81c5202e03ebb63cee30229ddc0fd2..d822568a0445502d53d5a9b637ebf84cf1237475 100644 (file)
@@ -34,3 +34,16 @@ normal:
   %x = add i32 42, 1
   ret void
 }
+
+define void @f_deopt(i32* %ptr) {
+; CHECK: Multiple deopt operand bundles
+; CHECK-NEXT: call void @g() [ "deopt"(i32 42, i64 100, i32 %x), "deopt"(float 0.000000e+00, i64 100, i32 %l) ]
+; CHECK-NOT: call void @g() [ "deopt"(i32 42, i64 120, i32 %x) ]
+
+ entry:
+  %l = load i32, i32* %ptr
+  call void @g() [ "deopt"(i32 42, i64 100, i32 %x), "deopt"(float 0.0, i64 100, i32 %l) ]
+  call void @g() [ "deopt"(i32 42, i64 120) ]  ;; The verifier should not complain about this one
+  %x = add i32 42, 1
+  ret void
+}