5 changes: 4 additions & 1 deletion docs/BitCodeFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,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, prefix, offset, dllstorageclass]``

The ``FUNCTION`` record (code 8) marks the declaration or definition of a
function. The operand fields are:
Expand Down Expand Up @@ -773,6 +773,9 @@ function. The operand fields are:
* *prefix*: If non-zero, the value index of the prefix data for this function,
plus 1.

* *offset*: The offset of the symbol value relative to the beginning
of the function.

* *dllstorageclass*: An encoding of the `dllstorageclass`_ of this function

MODULE_CODE_ALIAS Record
Expand Down
23 changes: 19 additions & 4 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,9 @@ an optional ``unnamed_addr`` attribute, a return type, an optional
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:`garbage
collector name <gc>`, an optional :ref:`prefix <prefixdata>`, an opening
curly brace, a list of basic blocks, and a closing curly brace.
collector name <gc>`, an optional :ref:`prefix <prefixdata>`, an optional
:ref:`symbol_offset <symboloffset>`, an opening curly brace, a list of
basic blocks, and a closing curly brace.

LLVM function declarations consist of the "``declare``" keyword, an
optional :ref:`linkage type <linkage>`, an optional :ref:`visibility
Expand All @@ -621,7 +622,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:`symbol_offset <symbolofffset>`.

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 @@ -657,7 +659,7 @@ Syntax::
[cconv] [ret attrs]
<ResultType> @<FunctionName> ([argument list])
[unnamed_addr] [fn Attrs] [section "name"] [align N]
[gc] [prefix Constant] { ... }
[gc] [prefix Constant] [symbol_offset N] { ... }

.. _langref_aliases:

Expand Down Expand Up @@ -893,6 +895,9 @@ 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.

Alternatively, the :ref:`symbol_offset` attribute can be used to move
the function entry point to after the prefix data.

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
Expand All @@ -919,6 +924,16 @@ 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.

.. _symboloffset:

Symbol Offset
-------------

The `symbol_offset` attribute allows the value of the symbol in the
produced object file to be offset from the beginning of the function
definition. This can be used in conjunction with the :ref:`prefix`
attribute to insert prefix data before the definition of a function.

.. _attrgrp:

Attribute Groups
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 : HasSymbolOffset
* 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 @@ -159,11 +162,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 @@ -439,12 +442,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 hasSymbolOffset() const {
return getSubclassDataFromValue() & (1<<2);
}

Constant *getSymbolOffset() const;
void setSymbolOffset(Constant *Offset);

/// 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 @@ -548,6 +548,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(inteldialect);
KEYWORD(gc);
KEYWORD(prefix);
KEYWORD(symbol_offset);

KEYWORD(ccc);
KEYWORD(fastcc);
Expand Down
21 changes: 19 additions & 2 deletions lib/AsmParser/LLParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,19 @@ bool LLParser::ParseStringConstant(std::string &Result) {
return false;
}

/// ParseInt32
/// ::= int32
bool LLParser::ParseInt32(signed &Val) {
if (Lex.getKind() != lltok::APSInt)
return TokError("expected integer");
int64_t Val64 = Lex.getAPSIntVal().getLimitedValue(0x7FFFFFFFULL+1);
if (Val64 != signed(Val64))
return TokError("expected 32-bit integer (too large)");
Val = Val64;
Lex.Lex();
return false;
}

/// ParseUInt32
/// ::= uint32
bool LLParser::ParseUInt32(unsigned &Val) {
Expand Down Expand Up @@ -3016,7 +3029,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 OptionalSymbolOffset
bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
// Parse the linkage.
LocTy LinkageLoc = Lex.getLoc();
Expand Down Expand Up @@ -3097,6 +3110,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
bool UnnamedAddr;
LocTy UnnamedAddrLoc;
Constant *Prefix = nullptr;
Constant *Offset = nullptr;

if (ParseArgumentList(ArgList, isVarArg) ||
ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr,
Expand All @@ -3109,7 +3123,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_symbol_offset) &&
ParseGlobalTypeAndValue(Offset)))
return true;

if (FuncAttrs.contains(Attribute::Builtin))
Expand Down Expand Up @@ -3209,6 +3225,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) {
Fn->setSection(Section);
if (!GC.empty()) Fn->setGC(GC.c_str());
Fn->setPrefixData(Prefix);
Fn->setSymbolOffset(Offset);
ForwardRefAttrGroups[Fn] = FwdRefAttrGrps;

// Add all of the arguments we parsed to the function.
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ namespace llvm {
return false;
}
bool ParseStringConstant(std::string &Result);
bool ParseInt32(signed &Val);
bool ParseUInt32(unsigned &Val);
bool ParseUInt32(unsigned &Val, LocTy &Loc) {
Loc = Lex.getLoc();
Expand Down
1 change: 1 addition & 0 deletions lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ namespace lltok {
kw_inteldialect,
kw_gc,
kw_prefix,
kw_symbol_offset,
kw_c,

kw_cc, kw_ccc, kw_fastcc, kw_coldcc,
Expand Down
23 changes: 20 additions & 3 deletions lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1122,10 +1122,12 @@ 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> > FunctionOffsetWorklist;

GlobalInitWorklist.swap(GlobalInits);
AliasInitWorklist.swap(AliasInits);
FunctionPrefixWorklist.swap(FunctionPrefixes);
FunctionOffsetWorklist.swap(FunctionOffsets);

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

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

return error_code::success();
}

Expand Down Expand Up @@ -1934,7 +1949,7 @@ error_code BitcodeReader::ParseModule(bool Resume) {
}
// FUNCTION: [type, callingconv, isproto, linkage, paramattr,
// alignment, section, visibility, gc, unnamed_addr,
// dllstorageclass]
// offset, dllstorageclass]
case bitc::MODULE_CODE_FUNCTION: {
if (Record.size() < 8)
return Error(InvalidRecord);
Expand Down Expand Up @@ -1977,9 +1992,11 @@ error_code BitcodeReader::ParseModule(bool Resume) {
Func->setUnnamedAddr(UnnamedAddr);
if (Record.size() > 10 && Record[10] != 0)
FunctionPrefixes.push_back(std::make_pair(Func, Record[10]-1));
if (Record.size() > 11 && Record[11] != 0)
FunctionOffsets.push_back(std::make_pair(Func, Record[11]-1));

if (Record.size() > 11)
Func->setDLLStorageClass(GetDecodedDLLStorageClass(Record[11]));
if (Record.size() > 12)
Func->setDLLStorageClass(GetDecodedDLLStorageClass(Record[12]));
else
UpgradeDLLImportExportLinkage(Func, Record[3]);

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 @@ -142,6 +142,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> > FunctionOffsets;

SmallVector<Instruction*, 64> InstsWithTBAATag;

Expand Down
4 changes: 3 additions & 1 deletion lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
// Emit the function proto information.
for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) {
// FUNCTION: [type, callingconv, isproto, linkage, paramattrs, alignment,
// section, visibility, gc, unnamed_addr, prefix]
// section, visibility, gc, unnamed_addr, prefix, offset]
Vals.push_back(VE.getTypeID(F->getType()));
Vals.push_back(F->getCallingConv());
Vals.push_back(F->isDeclaration());
Expand All @@ -655,6 +655,8 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
Vals.push_back(F->hasUnnamedAddr());
Vals.push_back(F->hasPrefixData() ? (VE.getValueID(F->getPrefixData()) + 1)
: 0);
Vals.push_back(F->hasSymbolOffset() ? (VE.getValueID(F->getSymbolOffset()) + 1)
: 0);
Vals.push_back(getEncodedDLLStorageClass(F));

unsigned AbbrevToUse = 0;
Expand Down
5 changes: 5 additions & 0 deletions lib/Bitcode/Writer/ValueEnumerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ ValueEnumerator::ValueEnumerator(const Module *M) {
if (I->hasPrefixData())
EnumerateValue(I->getPrefixData());

// Enumerate the symbol offset constants.
for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I)
if (I->hasSymbolOffset())
EnumerateValue(I->getSymbolOffset());

// Insert constants and metadata that are named at module level into the slot
// pool so that the module symbol table can refer to them...
EnumerateValueSymbolTable(M->getValueSymbolTable());
Expand Down
20 changes: 18 additions & 2 deletions lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ STATISTIC(EmittedInsts, "Number of machine instrs printed");

char AsmPrinter::ID = 0;

static const MCExpr *lowerConstant(const Constant *CV, AsmPrinter &AP);

typedef DenseMap<GCStrategy*, std::unique_ptr<GCMetadataPrinter>> gcp_map_type;
static gcp_map_type &getGCMap(void *&P) {
if (!P)
Expand Down Expand Up @@ -556,10 +558,24 @@ void AsmPrinter::EmitFunctionHeader() {
/// EmitFunctionEntryLabel - Emit the label that is the entrypoint for the
/// function. This can be overridden by targets as required to do custom stuff.
void AsmPrinter::EmitFunctionEntryLabel() {
const Function *F = MF->getFunction();

// The function label could have already been emitted if two symbols end up
// conflicting due to asm renaming. Detect this and emit an error.
if (CurrentFnSym->isUndefined())
return OutStreamer.EmitLabel(CurrentFnSym);
if (CurrentFnSym->isUndefined()) {
if (F->hasSymbolOffset()) {
MCSymbol *dummySym = OutContext.CreateTempSymbol();
OutStreamer.EmitLabel(dummySym);

const MCExpr *symRefExpr = MCSymbolRefExpr::Create(dummySym, OutContext);
const MCExpr *offsetExpr = lowerConstant(F->getSymbolOffset(), *this);
const MCExpr *sumExpr = MCBinaryExpr::CreateAdd(symRefExpr, offsetExpr, OutContext);
OutStreamer.EmitAssignment(CurrentFnSym, sumExpr);
return;
} else {
return OutStreamer.EmitLabel(CurrentFnSym);
}
}

report_fatal_error("'" + Twine(CurrentFnSym->getName()) +
"' label emitted multiple times to assembly file");
Expand Down
5 changes: 5 additions & 0 deletions lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,11 @@ void AssemblyWriter::printFunction(const Function *F) {
Out << " prefix ";
writeOperand(F->getPrefixData(), true);
}
if (F->hasSymbolOffset()) {
Out << " symbol_offset ";
writeOperand(F->getSymbolOffset(), true);
}

if (F->isDeclaration()) {
Out << '\n';
} else {
Expand Down
Loading