forked from OSchip/llvm-project
Introduce deoptimization operand bundles
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 llvm-svn: 252806
This commit is contained in:
parent
77ef54288a
commit
cdafd8490a
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue