Skip to content

Commit

Permalink
[Bitcode][Asm] Teach LLVM to read and write operand bundles.
Browse files Browse the repository at this point in the history
Summary:
This also adds the first set of tests for operand bundles.

The optimizer has not been audited to ensure that it does the right
thing with operand bundles.

Depends on D12456.

Reviewers: reames, chandlerc, majnemer, dexonsmith, kmod, JosephTremoulet, rnk, bogner

Subscribers: maksfb, llvm-commits

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

llvm-svn: 248551
  • Loading branch information
sanjoy committed Sep 24, 2015
1 parent f021808 commit b513a9f
Show file tree
Hide file tree
Showing 10 changed files with 650 additions and 14 deletions.
52 changes: 51 additions & 1 deletion llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,53 @@ example:
the ELF x86-64 abi, but it can be disabled for some compilation
units.


.. _opbundles:

Operand Bundles
---------------

Note: operand bundles are a work in progress, and they should be
considered experimental at this time.

Operand bundles are tagged sets of SSA values that can be associated
with certain LLVM instructions (currently only ``call``s and
``invoke``s). In a way they are like metadata, but dropping them is
incorrect and will change program semantics.
Syntax::
operand bundle set ::= '[' operand bundle ']'
operand bundle ::= tag '(' [ bundle operand ] (, bundle operand )* ')'
bundle operand ::= SSA value
tag ::= string constant
Operand bundles are **not** part of a function's signature, and a
given function may be called from multiple places with different kinds
of operand bundles. This reflects the fact that the operand bundles
are conceptually a part of the ``call`` (or ``invoke``), not the
callee being dispatched to.

Operand bundles are a generic mechanism intended to support
runtime-introspection-like functionality for managed languages. While
the exact semantics of an operand bundle depend on the bundle tag,
there are certain limitations to how much the presence of an operand
bundle can influence the semantics of a program. These restrictions
are described as the semantics of an "unknown" operand bundle. As
long as the behavior of an operand bundle is describable within these
restrictions, LLVM does not need to have special knowledge of the
operand bundle to not miscompile programs containing it.

- The bundle operands for an unknown operand bundle escape in unknown
ways before control is transferred to the callee or invokee.

- Calls and invokes with operand bundles have unknown read / write
effect on the heap on entry and exit (even if the call target is
``readnone`` or ``readonly``).

- An operand bundle at a call site cannot change the implementation
of the called function. Inter-procedural optimizations work as
usual as long as they take into account the first two properties.

.. _moduleasm:

Module-Level Inline Assembly
Expand Down Expand Up @@ -5061,7 +5108,7 @@ Syntax:
::

<result> = invoke [cconv] [ret attrs] <ptr to function ty> <function ptr val>(<function args>) [fn attrs]
to label <normal label> unwind label <exception label>
[operand bundles] to label <normal label> unwind label <exception label>

Overview:
"""""""""
Expand Down Expand Up @@ -5115,6 +5162,7 @@ This instruction requires several arguments:
#. The optional :ref:`function attributes <fnattrs>` list. Only
'``noreturn``', '``nounwind``', '``readonly``' and '``readnone``'
attributes are valid here.
#. The optional :ref:`operand bundles <opbundles>` list.

Semantics:
""""""""""
Expand Down Expand Up @@ -8310,6 +8358,7 @@ Syntax:
::

<result> = [tail | musttail] call [cconv] [ret attrs] <ty> [<fnty>*] <fnptrval>(<function args>) [fn attrs]
[ operand bundles ]

Overview:
"""""""""
Expand Down Expand Up @@ -8389,6 +8438,7 @@ This instruction requires several arguments:
#. The optional :ref:`function attributes <fnattrs>` list. Only
'``noreturn``', '``nounwind``', '``readonly``' and '``readnone``'
attributes are valid here.
#. The optional :ref:`operand bundles <opbundles>` list.

Semantics:
""""""""""
Expand Down
11 changes: 11 additions & 0 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ namespace bitc {
TYPE_BLOCK_ID_NEW,

USELIST_BLOCK_ID,

MODULE_STRTAB_BLOCK_ID,
FUNCTION_SUMMARY_BLOCK_ID,

OPERAND_BUNDLE_TAGS_BLOCK_ID
};


Expand Down Expand Up @@ -131,6 +136,10 @@ namespace bitc {
TYPE_CODE_TOKEN = 22 // TOKEN
};

enum OperandBundleTagCode {
OPERAND_BUNDLE_TAG = 1, // TAG: [strchr x N]
};

// The type symbol table only has one code (TST_ENTRY_CODE).
enum TypeSymtabCodes {
TST_CODE_ENTRY = 1 // TST_ENTRY: [typeid, namechar x N]
Expand Down Expand Up @@ -369,6 +378,8 @@ namespace bitc {
FUNC_CODE_INST_CLEANUPPAD = 52, // CLEANUPPAD: [num,args...]
FUNC_CODE_INST_CATCHENDPAD = 53, // CATCHENDPAD: [] or [bb#]
FUNC_CODE_INST_CLEANUPENDPAD = 54, // CLEANUPENDPAD: [val] or [val,bb#]

FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...]
};

enum UseListCodes {
Expand Down
75 changes: 65 additions & 10 deletions llvm/lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1942,7 +1942,61 @@ bool LLParser::ParseParameterList(SmallVectorImpl<ParamInfo> &ArgList,
return false;
}

/// ParseOptionalOperandBundles
/// ::= /*empty*/
/// ::= '[' OperandBundle [, OperandBundle ]* ']'
///
/// OperandBundle
/// ::= bundle-tag '(' ')'
/// ::= bundle-tag '(' Type Value [, Type Value ]* ')'
///
/// bundle-tag ::= String Constant
bool LLParser::ParseOptionalOperandBundles(
SmallVectorImpl<OperandBundleDef> &BundleList, PerFunctionState &PFS) {
LocTy BeginLoc = Lex.getLoc();
if (!EatIfPresent(lltok::lsquare))
return false;

while (Lex.getKind() != lltok::rsquare) {
// If this isn't the first operand bundle, we need a comma.
if (!BundleList.empty() &&
ParseToken(lltok::comma, "expected ',' in input list"))
return true;

std::string Tag;
if (ParseStringConstant(Tag))
return true;

BundleList.emplace_back();
auto &OBI = BundleList.back();

OBI.Tag = std::move(Tag);

if (ParseToken(lltok::lparen, "expected '(' in operand bundle"))
return true;

while (Lex.getKind() != lltok::rparen) {
// If this isn't the first input, we need a comma.
if (!OBI.Inputs.empty() &&
ParseToken(lltok::comma, "expected ',' in input list"))
return true;

Type *Ty = nullptr;
Value *Input = nullptr;
if (ParseType(Ty) || ParseValue(Ty, Input, PFS))
return true;
OBI.Inputs.push_back(Input);
}

Lex.Lex(); // Lex the ')'.
}

if (BundleList.empty())
return Error(BeginLoc, "operand bundle set must not be empty");

Lex.Lex(); // Lex the ']'.
return false;
}

/// ParseArgumentList - Parse the argument list for a function type or function
/// prototype.
Expand Down Expand Up @@ -4991,15 +5045,15 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
LocTy RetTypeLoc;
ValID CalleeID;
SmallVector<ParamInfo, 16> ArgList;
SmallVector<OperandBundleDef, 2> BundleList;

BasicBlock *NormalBB, *UnwindBB;
if (ParseOptionalCallingConv(CC) ||
ParseOptionalReturnAttrs(RetAttrs) ||
if (ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) ||
ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) ||
ParseParameterList(ArgList, PFS) ||
ParseValID(CalleeID) || ParseParameterList(ArgList, PFS) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
NoBuiltinLoc) ||
ParseOptionalOperandBundles(BundleList, PFS) ||
ParseToken(lltok::kw_to, "expected 'to' in invoke") ||
ParseTypeAndBasicBlock(NormalBB, PFS) ||
ParseToken(lltok::kw_unwind, "expected 'unwind' in invoke") ||
Expand Down Expand Up @@ -5075,7 +5129,8 @@ bool LLParser::ParseInvoke(Instruction *&Inst, PerFunctionState &PFS) {
// Finish off the Attribute and check them
AttributeSet PAL = AttributeSet::get(Context, Attrs);

InvokeInst *II = InvokeInst::Create(Ty, Callee, NormalBB, UnwindBB, Args);
InvokeInst *II =
InvokeInst::Create(Ty, Callee, NormalBB, UnwindBB, Args, BundleList);
II->setCallingConv(CC);
II->setAttributes(PAL);
ForwardRefAttrGroups[II] = FwdRefAttrGrps;
Expand Down Expand Up @@ -5589,18 +5644,18 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
LocTy RetTypeLoc;
ValID CalleeID;
SmallVector<ParamInfo, 16> ArgList;
SmallVector<OperandBundleDef, 2> BundleList;
LocTy CallLoc = Lex.getLoc();

if ((TCK != CallInst::TCK_None &&
ParseToken(lltok::kw_call, "expected 'tail call'")) ||
ParseOptionalCallingConv(CC) ||
ParseOptionalReturnAttrs(RetAttrs) ||
ParseOptionalCallingConv(CC) || ParseOptionalReturnAttrs(RetAttrs) ||
ParseType(RetType, RetTypeLoc, true /*void allowed*/) ||
ParseValID(CalleeID) ||
ParseParameterList(ArgList, PFS, TCK == CallInst::TCK_MustTail,
PFS.getFunction().isVarArg()) ||
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false,
BuiltinLoc))
ParseFnAttributeValuePairs(FnAttrs, FwdRefAttrGrps, false, BuiltinLoc) ||
ParseOptionalOperandBundles(BundleList, PFS))
return true;

// If RetType is a non-function pointer type, then this is the short syntax
Expand Down Expand Up @@ -5672,7 +5727,7 @@ bool LLParser::ParseCall(Instruction *&Inst, PerFunctionState &PFS,
// Finish off the Attribute and check them
AttributeSet PAL = AttributeSet::get(Context, Attrs);

CallInst *CI = CallInst::Create(Ty, Callee, Args);
CallInst *CI = CallInst::Create(Ty, Callee, Args, BundleList);
CI->setTailCallKind(TCK);
CI->setCallingConv(CC);
CI->setAttributes(PAL);
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@ namespace llvm {
bool IsMustTailCall = false,
bool InVarArgsFunc = false);

bool
ParseOptionalOperandBundles(SmallVectorImpl<OperandBundleDef> &BundleList,
PerFunctionState &PFS);

bool ParseExceptionArgs(SmallVectorImpl<Value *> &Args,
PerFunctionState &PFS);

Expand Down
Loading

0 comments on commit b513a9f

Please sign in to comment.