Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1488,6 +1488,27 @@ 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: include/llvm/IR/LLVMContext.h =================================================================== --- include/llvm/IR/LLVMContext.h +++ include/llvm/IR/LLVMContext.h @@ -67,6 +67,14 @@ 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: lib/IR/LLVMContext.cpp =================================================================== --- lib/IR/LLVMContext.cpp +++ lib/IR/LLVMContext.cpp @@ -127,6 +127,11 @@ 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: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -2324,6 +2324,15 @@ 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: test/Verifier/operand-bundles.ll =================================================================== --- test/Verifier/operand-bundles.ll +++ test/Verifier/operand-bundles.ll @@ -34,3 +34,16 @@ %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 +}