Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
Implementation of asm-goto support in LLVM
Browse files Browse the repository at this point in the history
This patch accompanies the RFC posted here:
http://lists.llvm.org/pipermail/llvm-dev/2018-October/127239.html

This patch adds a new CallBr IR instruction to support asm-goto
inline assembly like gcc as used by the linux kernel. This
instruction is both a call instruction and a terminator
instruction with multiple successors. Only inline assembly
usage is supported today.

This also adds a new INLINEASM_BR opcode to SelectionDAG and
MachineIR to represent an INLINEASM block that is also
considered a terminator instruction.

There will likely be more bug fixes and optimizations to follow
this, but we felt it had reached a point where we would like to
switch to an incremental development model.

Patch by Craig Topper, Alexander Ivchenko, Mikhail Dvoretckii

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@353563 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
topperc committed Feb 8, 2019
1 parent 9025db3 commit e369611
Show file tree
Hide file tree
Showing 87 changed files with 1,812 additions and 219 deletions.
80 changes: 80 additions & 0 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6513,6 +6513,7 @@ control flow, not values (the one exception being the
The terminator instructions are: ':ref:`ret <i_ret>`',
':ref:`br <i_br>`', ':ref:`switch <i_switch>`',
':ref:`indirectbr <i_indirectbr>`', ':ref:`invoke <i_invoke>`',
':ref:`callbr <i_callbr>`'
':ref:`resume <i_resume>`', ':ref:`catchswitch <i_catchswitch>`',
':ref:`catchret <i_catchret>`',
':ref:`cleanupret <i_cleanupret>`',
Expand Down Expand Up @@ -6837,6 +6838,85 @@ Example:
%retval = invoke coldcc i32 %Testfnptr(i32 15) to label %Continue
unwind label %TestCleanup ; i32:retval set

.. _i_callbr:

'``callbr``' Instruction
^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

::

<result> = callbr [cconv] [ret attrs] [addrspace(<num>)] [<ty>|<fnty> <fnptrval>(<function args>) [fn attrs]
[operand bundles] to label <normal label> or jump [other labels]

Overview:
"""""""""

The '``callbr``' instruction causes control to transfer to a specified
function, with the possibility of control flow transfer to either the
'``normal``' label or one of the '``other``' labels.

This instruction should only be used to implement the "goto" feature of gcc
style inline assembly. Any other usage is an error in the IR verifier.

Arguments:
""""""""""

This instruction requires several arguments:

#. The optional "cconv" marker indicates which :ref:`calling
convention <callingconv>` the call should use. If none is
specified, the call defaults to using C calling conventions.
#. The optional :ref:`Parameter Attributes <paramattrs>` list for return
values. Only '``zeroext``', '``signext``', and '``inreg``' attributes
are valid here.
#. The optional addrspace attribute can be used to indicate the address space
of the called function. If it is not specified, the program address space
from the :ref:`datalayout string<langref_datalayout>` will be used.
#. '``ty``': the type of the call instruction itself which is also the
type of the return value. Functions that return no value are marked
``void``.
#. '``fnty``': shall be the signature of the function being called. The
argument types must match the types implied by this signature. This
type can be omitted if the function is not varargs.
#. '``fnptrval``': An LLVM value containing a pointer to a function to
be called. In most cases, this is a direct function call, but
indirect ``callbr``'s are just as possible, calling an arbitrary pointer
to function value.
#. '``function args``': argument list whose types match the function
signature argument types and parameter attributes. All arguments must
be of :ref:`first class <t_firstclass>` type. If the function signature
indicates the function accepts a variable number of arguments, the
extra arguments can be specified.
#. '``normal label``': the label reached when the called function
executes a '``ret``' instruction.
#. '``other labels``': the labels reached when a callee transfers control
to a location other than the normal '``normal label``'
#. The optional :ref:`function attributes <fnattrs>` list.
#. The optional :ref:`operand bundles <opbundles>` list.

Semantics:
""""""""""

This instruction is designed to operate as a standard '``call``'
instruction in most regards. The primary difference is that it
establishes an association with additional labels to define where control
flow goes after the call.

The only use of this today is to implement the "goto" feature of gcc inline
assembly where additional labels can be provided as locations for the inline
assembly to jump to.

Example:
""""""""

.. code-block:: llvm

callbr void asm "", "r,x"(i32 %x, i8 *blockaddress(@foo, %fail))
to label %normal or jump [label %fail]

.. _i_resume:

'``resume``' Instruction
Expand Down
1 change: 1 addition & 0 deletions include/llvm-c/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ typedef enum {
LLVMInvoke = 5,
/* removed 6 due to API changes */
LLVMUnreachable = 7,
LLVMCallBr = 67,

/* Standard Unary Operators */
LLVMFNeg = 66,
Expand Down
8 changes: 2 additions & 6 deletions include/llvm/Analysis/SparsePropagation.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,8 @@ void SparseSolver<LatticeKey, LatticeVal, KeyInfo>::getFeasibleSuccessors(
return;
}

if (TI.isExceptionalTerminator()) {
Succs.assign(Succs.size(), true);
return;
}

if (isa<IndirectBrInst>(TI)) {
if (TI.isExceptionalTerminator() ||
TI.isIndirectTerminator()) {
Succs.assign(Succs.size(), true);
return;
}
Expand Down
2 changes: 2 additions & 0 deletions include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ enum FunctionCodes {
// 54 is unused.
FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...]
FUNC_CODE_INST_UNOP = 56, // UNOP: [opcode, ty, opval]
FUNC_CODE_INST_CALLBR = 57, // CALLBR: [attr, cc, norm, transfs,
// fnty, fnid, args...]
};

enum UseListCodes {
Expand Down
2 changes: 2 additions & 0 deletions include/llvm/CodeGen/GlobalISel/IRTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ class IRTranslator : public MachineFunctionPass {

bool translateInvoke(const User &U, MachineIRBuilder &MIRBuilder);

bool translateCallBr(const User &U, MachineIRBuilder &MIRBuilder);

bool translateLandingPad(const User &U, MachineIRBuilder &MIRBuilder);

/// Translate one of LLVM's cast instructions into MachineInstrs, with the
Expand Down
3 changes: 3 additions & 0 deletions include/llvm/CodeGen/ISDOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,9 @@ namespace ISD {
/// SDOperands.
INLINEASM,

/// INLINEASM_BR - Terminator version of inline asm. Used by asm-goto.
INLINEASM_BR,

/// EH_LABEL - Represents a label in mid basic block used to track
/// locations needed for debug and exception handling tables. These nodes
/// take a chain as input and return a chain.
Expand Down
5 changes: 4 additions & 1 deletion include/llvm/CodeGen/MachineInstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,10 @@ class MachineInstr
}
bool isKill() const { return getOpcode() == TargetOpcode::KILL; }
bool isImplicitDef() const { return getOpcode()==TargetOpcode::IMPLICIT_DEF; }
bool isInlineAsm() const { return getOpcode() == TargetOpcode::INLINEASM; }
bool isInlineAsm() const {
return getOpcode() == TargetOpcode::INLINEASM ||
getOpcode() == TargetOpcode::INLINEASM_BR;
}

bool isMSInlineAsm() const {
return isInlineAsm() && getInlineAsmDialect() == InlineAsm::AD_Intel;
Expand Down
2 changes: 1 addition & 1 deletion include/llvm/CodeGen/SelectionDAGISel.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ class SelectionDAGISel : public MachineFunctionPass {
private:

// Calls to these functions are generated by tblgen.
void Select_INLINEASM(SDNode *N);
void Select_INLINEASM(SDNode *N, bool Branch);
void Select_READ_REGISTER(SDNode *Op);
void Select_WRITE_REGISTER(SDNode *Op);
void Select_UNDEF(SDNode *N);
Expand Down

0 comments on commit e369611

Please sign in to comment.