Skip to content

Commit

Permalink
Prologue support
Browse files Browse the repository at this point in the history
Patch by Ben Gamari!

This redefines the `prefix` attribute introduced previously and
introduces a `prologue` attribute.  There are a two primary usecases
that these attributes aim to serve,

  1. Function prologue sigils

  2. Function hot-patching: Enable the user to insert `nop` operations
     at the beginning of the function which can later be safely replaced
     with a call to some instrumentation facility

  3. Runtime metadata: Allow a compiler to insert data for use by the
     runtime during execution. GHC is one example of a compiler that
     needs this functionality for its tables-next-to-code functionality.

Previously `prefix` served cases (1) and (2) quite well by allowing the user
to introduce arbitrary data at the entrypoint but before the function
body. Case (3), however, was poorly handled by this approach as it
required that prefix data was valid executable code.

Here we redefine the notion of prefix data to instead be data which
occurs immediately before the function entrypoint (i.e. the symbol
address). Since prefix data now occurs before the function entrypoint,
there is no need for the data to be valid code.

The previous notion of prefix data now goes under the name "prologue
data" to emphasize its duality with the function epilogue.

The intention here is to handle cases (1) and (2) with prologue data and
case (3) with prefix data.

References
----------

This idea arose out of discussions[1] with Reid Kleckner in response to a
proposal to introduce the notion of symbol offsets to enable handling of
case (3).

[1] http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-May/073235.html

Test Plan: testsuite

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223189 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
pcc committed Dec 3, 2014
1 parent 8cc929e commit bb660fc
Show file tree
Hide file tree
Showing 23 changed files with 306 additions and 65 deletions.
10 changes: 8 additions & 2 deletions docs/BitCodeFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ global variable. The operand fields are:
MODULE_CODE_FUNCTION Record
^^^^^^^^^^^^^^^^^^^^^^^^^^^

``[FUNCTION, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prefix, dllstorageclass]``
``[FUNCTION, type, callingconv, isproto, linkage, paramattr, alignment, section, visibility, gc, prologuedata, dllstorageclass, comdat, prefixdata]``

The ``FUNCTION`` record (code 8) marks the declaration or definition of a
function. The operand fields are:
Expand Down Expand Up @@ -784,12 +784,18 @@ function. The operand fields are:
* *unnamed_addr*: If present and non-zero, indicates that the function has
``unnamed_addr``

* *prefix*: If non-zero, the value index of the prefix data for this function,
* *prologuedata*: If non-zero, the value index of the prologue data for this function,
plus 1.

* *dllstorageclass*: An encoding of the
:ref:`dllstorageclass<bcdllstorageclass>` of this function

* *comdat*: An encoding of the COMDAT of this function

* *prefixdata*: If non-zero, the value index of the prefix data for this function,
plus 1.


MODULE_CODE_ALIAS Record
^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
86 changes: 60 additions & 26 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,8 @@ name, a (possibly empty) argument list (each with optional :ref:`parameter
attributes <paramattrs>`), optional :ref:`function attributes <fnattrs>`,
an optional section, an optional alignment,
an optional :ref:`comdat <langref_comdats>`,
an optional :ref:`garbage collector name <gc>`, an optional :ref:`prefix <prefixdata>`, an opening
an optional :ref:`garbage collector name <gc>`, an optional :ref:`prefix <prefixdata>`,
an optional :ref:`prologue <prologuedata>`, an opening
curly brace, a list of basic blocks, and a closing curly brace.

LLVM function declarations consist of the "``declare``" keyword, an
Expand All @@ -643,7 +644,8 @@ an optional :ref:`calling convention <callingconv>`,
an optional ``unnamed_addr`` attribute, a return type, an optional
:ref:`parameter attribute <paramattrs>` for the return type, a function
name, a possibly empty list of arguments, an optional alignment, an optional
:ref:`garbage collector name <gc>` and an optional :ref:`prefix <prefixdata>`.
:ref:`garbage collector name <gc>`, an optional :ref:`prefix <prefixdata>`,
and an optional :ref:`prologue <prologuedata>`.

A function definition contains a list of basic blocks, forming the CFG (Control
Flow Graph) for the function. Each basic block may optionally start with a label
Expand Down Expand Up @@ -680,7 +682,7 @@ Syntax::
[cconv] [ret attrs]
<ResultType> @<FunctionName> ([argument list])
[unnamed_addr] [fn Attrs] [section "name"] [comdat $<ComdatName>]
[align N] [gc] [prefix Constant] { ... }
[align N] [gc] [prefix Constant] [prologue Constant] { ... }

The argument list is a comma seperated sequence of arguments where each
argument is of the following form
Expand Down Expand Up @@ -1021,47 +1023,79 @@ support the named garbage collection algorithm.
Prefix Data
-----------

Prefix data is data associated with a function which the code generator
will emit immediately before the function body. The purpose of this feature
is to allow frontends to associate language-specific runtime metadata with
specific functions and make it available through the function pointer while
still allowing the function pointer to be called. To access the data for a
given function, a program may bitcast the function pointer to a pointer to
the constant's type. This implies that the IR symbol points to the start
of the prefix data.
Prefix data is data associated with a function which the code
generator will emit immediately before the function's entrypoint.
The purpose of this feature is to allow frontends to associate
language-specific runtime metadata with specific functions and make it
available through the function pointer while still allowing the
function pointer to be called.

To maintain the semantics of ordinary function calls, the prefix data must
To access the data for a given function, a program may bitcast the
function pointer to a pointer to the constant's type and dereference
index -1. This implies that the IR symbol points just past the end of
the prefix data. For instance, take the example of a function annotated
with a single ``i32``,

.. code-block:: llvm
define void @f() prefix i32 123 { ... }
The prefix data can be referenced as,

.. code-block:: llvm
%0 = bitcast *void () @f to *i32
%a = getelementptr inbounds *i32 %0, i32 -1
%b = load i32* %a
Prefix data is laid out as if it were an initializer for a global variable
of the prefix data's type. The function will be placed such that the
beginning of the prefix data is aligned. This means that if the size
of the prefix data is not a multiple of the alignment size, the
function's entrypoint will not be aligned. If alignment of the
function's entrypoint is desired, padding must be added to the prefix
data.

A function may have prefix data but no body. This has similar semantics
to the ``available_externally`` linkage in that the data may be used by the
optimizers but will not be emitted in the object file.

.. _prologuedata:

Prologue Data
-------------

The ``prologue`` attribute allows arbitrary code (encoded as bytes) to
be inserted prior to the function body. This can be used for enabling
function hot-patching and instrumentation.

To maintain the semantics of ordinary function calls, the prologue data must
have a particular format. Specifically, it must begin with a sequence of
bytes which decode to a sequence of machine instructions, valid for the
module's target, which transfer control to the point immediately succeeding
the prefix data, without performing any other visible action. This allows
the prologue data, without performing any other visible action. This allows
the inliner and other passes to reason about the semantics of the function
definition without needing to reason about the prefix data. Obviously this
makes the format of the prefix data highly target dependent.
definition without needing to reason about the prologue data. Obviously this
makes the format of the prologue data highly target dependent.

Prefix data is laid out as if it were an initializer for a global variable
of the prefix data's type. No padding is automatically placed between the
prefix data and the function body. If padding is required, it must be part
of the prefix data.

A trivial example of valid prefix data for the x86 architecture is ``i8 144``,
A trivial example of valid prologue data for the x86 architecture is ``i8 144``,
which encodes the ``nop`` instruction:

.. code-block:: llvm
define void @f() prefix i8 144 { ... }
define void @f() prologue i8 144 { ... }
Generally prefix data can be formed by encoding a relative branch instruction
which skips the metadata, as in this example of valid prefix data for the
Generally prologue data can be formed by encoding a relative branch instruction
which skips the metadata, as in this example of valid prologue data for the
x86_64 architecture, where the first two bytes encode ``jmp .+10``:

.. code-block:: llvm
%0 = type <{ i8, i8, i8* }>
define void @f() prefix %0 <{ i8 235, i8 8, i8* @md}> { ... }
define void @f() prologue %0 <{ i8 235, i8 8, i8* @md}> { ... }
A function may have prefix data but no body. This has similar semantics
A function may have prologue data but no body. This has similar semantics
to the ``available_externally`` linkage in that the data may be used by the
optimizers but will not be emitted in the object file.

Expand Down
44 changes: 44 additions & 0 deletions docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,50 @@ Non-comprehensive list of changes in this release
Makes programs 10x faster by doing Special New Thing.
Prefix data rework
------------------

The semantics of the ``prefix`` attribute have been changed. Users
that want the previous ``prefix`` semantics should instead use
``prologue``. To motivate this change, let's examine the primary
usecases that these attributes aim to serve,

1. Code sanitization metadata (e.g. Clang's undefined behavior
sanitizer)

2. Function hot-patching: Enable the user to insert ``nop`` operations
at the beginning of the function which can later be safely replaced
with a call to some instrumentation facility.

3. Language runtime metadata: Allow a compiler to insert data for
use by the runtime during execution. GHC is one example of a
compiler that needs this functionality for its
tables-next-to-code functionality.

Previously ``prefix`` served cases (1) and (2) quite well by allowing the user
to introduce arbitrary data at the entrypoint but before the function
body. Case (3), however, was poorly handled by this approach as it
required that prefix data was valid executable code.

In this release the concept of prefix data has been redefined to be
data which occurs immediately before the function entrypoint (i.e. the
symbol address). Since prefix data now occurs before the function
entrypoint, there is no need for the data to be valid code.

The previous notion of prefix data now goes under the name "prologue
data" to emphasize its duality with the function epilogue.

The intention here is to handle cases (1) and (2) with prologue data and
case (3) with prefix data. See the language reference for further details
on the semantics of these attributes.

This refactoring arose out of discussions_ with Reid Kleckner in
response to a proposal to introduce the notion of symbol offsets to
enable handling of case (3).

.. _discussions: http://lists.cs.uiuc.edu/pipermail/llvmdev/2014-May/073235.html


Changes to the ARM Backend
--------------------------

Expand Down
30 changes: 20 additions & 10 deletions include/llvm/IR/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,14 @@ class Function : public GlobalObject, public ilist_node<Function> {
ValueSymbolTable *SymTab; ///< Symbol table of args/instructions
AttributeSet AttributeSets; ///< Parameter attributes

// HasLazyArguments is stored in Value::SubclassData.
/*bool HasLazyArguments;*/

// The Calling Convention is stored in Value::SubclassData.
/*CallingConv::ID CallingConvention;*/
/*
* Value::SubclassData
*
* bit 0 : HasLazyArguments
* bit 1 : HasPrefixData
* bit 2 : HasPrologueData
* bit 3-6: CallingConvention
*/

friend class SymbolTableListTraits<Function, Module>;

Expand All @@ -102,7 +105,7 @@ class Function : public GlobalObject, public ilist_node<Function> {
/// needs it. The hasLazyArguments predicate returns true if the arg list
/// hasn't been set up yet.
bool hasLazyArguments() const {
return getSubclassDataFromValue() & 1;
return getSubclassDataFromValue() & (1<<0);
}
void CheckLazyArguments() const {
if (hasLazyArguments())
Expand Down Expand Up @@ -162,11 +165,11 @@ class Function : public GlobalObject, public ilist_node<Function> {
/// calling convention of this function. The enum values for the known
/// calling conventions are defined in CallingConv.h.
CallingConv::ID getCallingConv() const {
return static_cast<CallingConv::ID>(getSubclassDataFromValue() >> 2);
return static_cast<CallingConv::ID>(getSubclassDataFromValue() >> 3);
}
void setCallingConv(CallingConv::ID CC) {
setValueSubclassData((getSubclassDataFromValue() & 3) |
(static_cast<unsigned>(CC) << 2));
setValueSubclassData((getSubclassDataFromValue() & 7) |
(static_cast<unsigned>(CC) << 3));
}

/// @brief Return the attribute list for this Function.
Expand Down Expand Up @@ -448,12 +451,19 @@ class Function : public GlobalObject, public ilist_node<Function> {
bool arg_empty() const;

bool hasPrefixData() const {
return getSubclassDataFromValue() & 2;
return getSubclassDataFromValue() & (1<<1);
}

Constant *getPrefixData() const;
void setPrefixData(Constant *PrefixData);

bool hasPrologueData() const {
return getSubclassDataFromValue() & (1<<2);
}

Constant *getPrologueData() const;
void setPrologueData(Constant *PrologueData);

/// viewCFG - This function is meant for use from the debugger. You can just
/// say 'call F->viewCFG()' and a ghostview window should pop up from the
/// program, displaying the CFG of the current function with the code for each
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(inteldialect);
KEYWORD(gc);
KEYWORD(prefix);
KEYWORD(prologue);

KEYWORD(ccc);
KEYWORD(fastcc);
Expand Down
8 changes: 6 additions & 2 deletions lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3122,7 +3122,7 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc,
/// FunctionHeader
/// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs
/// OptUnnamedAddr Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection
/// OptionalAlign OptGC OptionalPrefix
/// OptionalAlign OptGC OptionalPrefix OptionalPrologue
bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
// Parse the linkage.
LocTy LinkageLoc = Lex.getLoc();
Expand Down Expand Up @@ -3203,6 +3203,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
bool UnnamedAddr;
LocTy UnnamedAddrLoc;
Constant *Prefix = nullptr;
Constant *Prologue = nullptr;
Comdat *C;

if (ParseArgumentList(ArgList, isVarArg) ||
Expand All @@ -3217,7 +3218,9 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
(EatIfPresent(lltok::kw_gc) &&
ParseStringConstant(GC)) ||
(EatIfPresent(lltok::kw_prefix) &&
ParseGlobalTypeAndValue(Prefix)))
ParseGlobalTypeAndValue(Prefix)) ||
(EatIfPresent(lltok::kw_prologue) &&
ParseGlobalTypeAndValue(Prologue)))
return true;

if (FuncAttrs.contains(Attribute::Builtin))
Expand Down Expand Up @@ -3318,6 +3321,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
Fn->setComdat(C);
if (!GC.empty()) Fn->setGC(GC.c_str());
Fn->setPrefixData(Prefix);
Fn->setPrologueData(Prologue);
ForwardRefAttrGroups[Fn] = FwdRefAttrGrps;

// Add all of the arguments we parsed to the function.
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ namespace lltok {
kw_inteldialect,
kw_gc,
kw_prefix,
kw_prologue,
kw_c,

kw_cc, kw_ccc, kw_fastcc, kw_coldcc,
Expand Down
22 changes: 20 additions & 2 deletions lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1152,10 +1152,12 @@ std::error_code BitcodeReader::ResolveGlobalAndAliasInits() {
std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist;
std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist;
std::vector<std::pair<Function*, unsigned> > FunctionPrefixWorklist;
std::vector<std::pair<Function*, unsigned> > FunctionPrologueWorklist;

GlobalInitWorklist.swap(GlobalInits);
AliasInitWorklist.swap(AliasInits);
FunctionPrefixWorklist.swap(FunctionPrefixes);
FunctionPrologueWorklist.swap(FunctionPrologues);

while (!GlobalInitWorklist.empty()) {
unsigned ValID = GlobalInitWorklist.back().second;
Expand Down Expand Up @@ -1197,6 +1199,19 @@ std::error_code BitcodeReader::ResolveGlobalAndAliasInits() {
FunctionPrefixWorklist.pop_back();
}

while (!FunctionPrologueWorklist.empty()) {
unsigned ValID = FunctionPrologueWorklist.back().second;
if (ValID >= ValueList.size()) {
FunctionPrologues.push_back(FunctionPrologueWorklist.back());
} else {
if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID]))
FunctionPrologueWorklist.back().first->setPrologueData(C);
else
return Error(BitcodeError::ExpectedConstant);
}
FunctionPrologueWorklist.pop_back();
}

return std::error_code();
}

Expand Down Expand Up @@ -2011,7 +2026,7 @@ std::error_code BitcodeReader::ParseModule(bool Resume) {
}
// FUNCTION: [type, callingconv, isproto, linkage, paramattr,
// alignment, section, visibility, gc, unnamed_addr,
// dllstorageclass]
// prologuedata, dllstorageclass, comdat, prefixdata]
case bitc::MODULE_CODE_FUNCTION: {
if (Record.size() < 8)
return Error(BitcodeError::InvalidRecord);
Expand Down Expand Up @@ -2053,7 +2068,7 @@ std::error_code BitcodeReader::ParseModule(bool Resume) {
UnnamedAddr = Record[9];
Func->setUnnamedAddr(UnnamedAddr);
if (Record.size() > 10 && Record[10] != 0)
FunctionPrefixes.push_back(std::make_pair(Func, Record[10]-1));
FunctionPrologues.push_back(std::make_pair(Func, Record[10]-1));

if (Record.size() > 11)
Func->setDLLStorageClass(GetDecodedDLLStorageClass(Record[11]));
Expand All @@ -2066,6 +2081,9 @@ std::error_code BitcodeReader::ParseModule(bool Resume) {
Func->setComdat(ComdatList[ComdatID - 1]);
}

if (Record.size() > 13 && Record[13] != 0)
FunctionPrefixes.push_back(std::make_pair(Func, Record[13]-1));

ValueList.push_back(Func);

// If this is a function with a body, remember the prototype we are
Expand Down
1 change: 1 addition & 0 deletions lib/Bitcode/Reader/BitcodeReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class BitcodeReader : public GVMaterializer {
std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits;
std::vector<std::pair<Function*, unsigned> > FunctionPrefixes;
std::vector<std::pair<Function*, unsigned> > FunctionPrologues;

SmallVector<Instruction*, 64> InstsWithTBAATag;

Expand Down
Loading

0 comments on commit bb660fc

Please sign in to comment.