Initial submission for the attribute group feature.

Attribute groups are of the form:

  #0 = attributes { noinline "no-sse" "cpu"="cortex-a8" alignstack=4 }

Target-dependent attributes are represented as strings. Attributes can have
optional values associated with them. E.g., the "cpu" attribute has the value
"cortex-a8".

Target-independent attributes are listed as enums inside the attribute classes.

Multiple attribute groups can be referenced by the same object. In that case,
the attributes are merged together.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@174493 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bill Wendling 2013-02-06 06:52:58 +00:00
parent 97fe3d9511
commit 95ce4c2ffb
6 changed files with 197 additions and 41 deletions

View File

@ -737,6 +737,36 @@ The compiler declares the supported values of *name*. Specifying a
collector which will cause the compiler to alter its output in order to
support the named garbage collection algorithm.
.. _attrgrp:
Attribute Groups
----------------
Attribute groups are groups of attributes that are referenced by objects within
the IR. They are important for keeping ``.ll`` files readable, because a lot of
functions will use the same set of attributes. In the degenerative case of a
``.ll`` file that corresponds to a single ``.c`` file, the single attribute
group will capture the important command line flags used to build that file.
An attribute group is a module-level object. To use an attribute group, an
object references the attribute group's ID (e.g. ``#37``). An object may refer
to more than one attribute group. In that situation, the attributes from the
different groups are merged.
Here is an example of attribute groups for a function that should always be
inlined, has a stack alignment of 4, and which shouldn't use SSE instructions:
.. code-block:: llvm
; Target-independent attributes:
#0 = attributes { alwaysinline alignstack=4 }
; Target-dependent attributes:
#1 = attributes { "no-sse" }
; Function @f has attributes: alwaysinline, alignstack=4, and "no-sse".
define void @f() #0 #1 { ... }
.. _fnattrs:
Function Attributes

View File

@ -226,6 +226,7 @@ lltok::Kind LLLexer::LexToken() {
SkipLineComment();
return LexToken();
case '!': return LexExclaim();
case '#': return LexHash();
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '-':
@ -394,6 +395,24 @@ lltok::Kind LLLexer::LexExclaim() {
return lltok::exclaim;
}
/// LexHash - Lex all tokens that start with a # character:
/// AttrGrpID ::= #[0-9]+
lltok::Kind LLLexer::LexHash() {
// Handle AttrGrpID: #[0-9]+
if (isdigit(CurPtr[0])) {
for (++CurPtr; isdigit(CurPtr[0]); ++CurPtr)
/*empty*/;
uint64_t Val = atoull(TokStart+1, CurPtr);
if ((unsigned)Val != Val)
Error("invalid value number (too large)!");
UIntVal = unsigned(Val);
return lltok::AttrGrpID;
}
return lltok::Error;
}
/// LexIdentifier: Handle several related productions:
/// Label [-a-zA-Z$._0-9]+:
/// IntegerType i[0-9]+
@ -531,35 +550,36 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(cc);
KEYWORD(c);
KEYWORD(signext);
KEYWORD(zeroext);
KEYWORD(attributes);
KEYWORD(address_safety);
KEYWORD(alwaysinline);
KEYWORD(byval);
KEYWORD(inlinehint);
KEYWORD(inreg);
KEYWORD(sret);
KEYWORD(nounwind);
KEYWORD(noreturn);
KEYWORD(minsize);
KEYWORD(naked);
KEYWORD(nest);
KEYWORD(noalias);
KEYWORD(nocapture);
KEYWORD(byval);
KEYWORD(nest);
KEYWORD(noduplicate);
KEYWORD(noimplicitfloat);
KEYWORD(noinline);
KEYWORD(nonlazybind);
KEYWORD(noredzone);
KEYWORD(noreturn);
KEYWORD(nounwind);
KEYWORD(optsize);
KEYWORD(readnone);
KEYWORD(readonly);
KEYWORD(uwtable);
KEYWORD(returns_twice);
KEYWORD(inlinehint);
KEYWORD(noinline);
KEYWORD(alwaysinline);
KEYWORD(optsize);
KEYWORD(signext);
KEYWORD(sret);
KEYWORD(ssp);
KEYWORD(sspreq);
KEYWORD(sspstrong);
KEYWORD(noredzone);
KEYWORD(noimplicitfloat);
KEYWORD(naked);
KEYWORD(nonlazybind);
KEYWORD(address_safety);
KEYWORD(minsize);
KEYWORD(noduplicate);
KEYWORD(uwtable);
KEYWORD(zeroext);
KEYWORD(type);
KEYWORD(opaque);

View File

@ -81,6 +81,7 @@ namespace llvm {
lltok::Kind LexPercent();
lltok::Kind LexQuote();
lltok::Kind Lex0x();
lltok::Kind LexHash();
uint64_t atoull(const char *Buffer, const char *End);
uint64_t HexIntToVal(const char *Buffer, const char *End);

View File

@ -174,7 +174,8 @@ bool LLParser::ParseTopLevelEntities() {
case lltok::GlobalID: if (ParseUnnamedGlobal()) return true; break;
case lltok::GlobalVar: if (ParseNamedGlobal()) return true; break;
case lltok::exclaim: if (ParseStandaloneMetadata()) return true; break;
case lltok::MetadataVar: if (ParseNamedMetadata()) return true; break;
case lltok::MetadataVar:if (ParseNamedMetadata()) return true; break;
case lltok::AttrGrpID: if (ParseUnnamedAttrGrp()) return true; break;
// The Global variable production with no name can have many different
// optional leading prefixes, the production is:
@ -740,6 +741,102 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc,
return false;
}
/// ParseUnnamedAttrGrp
/// ::= AttrGrpID '=' '{' AttrValPair+ '}'
bool LLParser::ParseUnnamedAttrGrp() {
assert(Lex.getKind() == lltok::AttrGrpID);
LocTy AttrGrpLoc = Lex.getLoc();
unsigned VarID = Lex.getUIntVal();
Lex.Lex();
if (ParseToken(lltok::equal, "expected '=' here") ||
ParseToken(lltok::kw_attributes, "expected 'attributes' keyword here") ||
ParseToken(lltok::lbrace, "expected '{' here") ||
ParseAttributeValuePairs(ForwardRefAttrBuilder[VarID]) ||
ParseToken(lltok::rbrace, "expected end of attribute group"))
return true;
if (!ForwardRefAttrBuilder[VarID].hasAttributes())
return Error(AttrGrpLoc, "attribute group has no attributes");
return false;
}
/// ParseAttributeValuePairs
/// ::= <attr> | <attr> '=' <value>
bool LLParser::ParseAttributeValuePairs(AttrBuilder &B) {
while (true) {
lltok::Kind Token = Lex.getKind();
switch (Token) {
default:
return Error(Lex.getLoc(), "unterminated attribute group");
case lltok::rbrace:
// Finished.
return false;
// Target-dependent attributes:
case lltok::StringConstant: {
std::string Attr = Lex.getStrVal();
Lex.Lex();
std::string Val;
if (EatIfPresent(lltok::equal) &&
ParseStringConstant(Val))
return true;
B.addAttribute(Attr, Val);
break;
}
// Target-independent attributes:
case lltok::kw_align: {
unsigned Alignment;
if (ParseToken(lltok::equal, "expected '=' here") ||
ParseUInt32(Alignment))
return true;
B.addAlignmentAttr(Alignment);
break;
}
case lltok::kw_alignstack: {
unsigned Alignment;
if (ParseToken(lltok::equal, "expected '=' here") ||
ParseUInt32(Alignment))
return true;
B.addStackAlignmentAttr(Alignment);
break;
}
case lltok::kw_address_safety: B.addAttribute(Attribute::AddressSafety); break;
case lltok::kw_alwaysinline: B.addAttribute(Attribute::AlwaysInline); break;
case lltok::kw_byval: B.addAttribute(Attribute::ByVal); break;
case lltok::kw_inlinehint: B.addAttribute(Attribute::InlineHint); break;
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break;
case lltok::kw_naked: B.addAttribute(Attribute::Naked); break;
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break;
case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break;
case lltok::kw_noduplicate: B.addAttribute(Attribute::NoDuplicate); break;
case lltok::kw_noimplicitfloat: B.addAttribute(Attribute::NoImplicitFloat); break;
case lltok::kw_noinline: B.addAttribute(Attribute::NoInline); break;
case lltok::kw_nonlazybind: B.addAttribute(Attribute::NonLazyBind); break;
case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break;
case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break;
case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break;
case lltok::kw_optsize: B.addAttribute(Attribute::OptimizeForSize); break;
case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break;
case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break;
case lltok::kw_returns_twice: B.addAttribute(Attribute::ReturnsTwice); break;
case lltok::kw_signext: B.addAttribute(Attribute::SExt); break;
case lltok::kw_sret: B.addAttribute(Attribute::StructRet); break;
case lltok::kw_ssp: B.addAttribute(Attribute::StackProtect); break;
case lltok::kw_sspreq: B.addAttribute(Attribute::StackProtectReq); break;
case lltok::kw_sspstrong: B.addAttribute(Attribute::StackProtectStrong); break;
case lltok::kw_uwtable: B.addAttribute(Attribute::UWTable); break;
case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break;
}
Lex.Lex();
}
}
//===----------------------------------------------------------------------===//
// GlobalValue Reference/Resolution Routines.

View File

@ -125,6 +125,9 @@ namespace llvm {
std::map<ValID, std::vector<std::pair<ValID, GlobalValue*> > >
ForwardRefBlockAddresses;
// Attribute builder reference information.
std::map<unsigned, AttrBuilder> ForwardRefAttrBuilder;
public:
LLParser(MemoryBuffer *F, SourceMgr &SM, SMDiagnostic &Err, Module *m) :
Context(m->getContext()), Lex(F, SM, Err, m->getContext()),
@ -236,6 +239,8 @@ namespace llvm {
bool ParseMDString(MDString *&Result);
bool ParseMDNodeID(MDNode *&Result);
bool ParseMDNodeID(MDNode *&Result, unsigned &SlotNo);
bool ParseUnnamedAttrGrp();
bool ParseAttributeValuePairs(AttrBuilder &B);
// Type Parsing.
bool ParseType(Type *&Result, bool AllowVoid = false);

View File

@ -30,6 +30,7 @@ namespace lltok {
lparen, rparen, // ( )
backslash, // \ (not /)
exclaim, // !
hash, // #
kw_x,
kw_true, kw_false,
@ -90,35 +91,36 @@ namespace lltok {
kw_ptx_kernel, kw_ptx_device,
kw_spir_kernel, kw_spir_func,
kw_signext,
kw_zeroext,
// Attributes:
kw_attributes,
kw_alwaysinline,
kw_address_safety,
kw_byval,
kw_inlinehint,
kw_inreg,
kw_sret,
kw_nounwind,
kw_noreturn,
kw_minsize,
kw_naked,
kw_nest,
kw_noalias,
kw_nocapture,
kw_byval,
kw_nest,
kw_noduplicate,
kw_noimplicitfloat,
kw_noinline,
kw_nonlazybind,
kw_noredzone,
kw_noreturn,
kw_nounwind,
kw_optsize,
kw_readnone,
kw_readonly,
kw_uwtable,
kw_returns_twice,
kw_inlinehint,
kw_noinline,
kw_alwaysinline,
kw_optsize,
kw_signext,
kw_ssp,
kw_sspreq,
kw_sspstrong,
kw_noredzone,
kw_noimplicitfloat,
kw_naked,
kw_nonlazybind,
kw_address_safety,
kw_minsize,
kw_noduplicate,
kw_sret,
kw_uwtable,
kw_zeroext,
kw_type,
kw_opaque,
@ -155,6 +157,7 @@ namespace lltok {
// Unsigned Valued tokens (UIntVal).
GlobalID, // @42
LocalVarID, // %42
AttrGrpID, // #42
// String valued tokens (StrVal).
LabelStr, // foo: