From 95ce4c2ffb0ff31a79b060fb112659322a5be3bf Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Wed, 6 Feb 2013 06:52:58 +0000 Subject: [PATCH] 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 --- docs/LangRef.rst | 30 ++++++++++++ lib/AsmParser/LLLexer.cpp | 60 +++++++++++++++-------- lib/AsmParser/LLLexer.h | 1 + lib/AsmParser/LLParser.cpp | 99 +++++++++++++++++++++++++++++++++++++- lib/AsmParser/LLParser.h | 5 ++ lib/AsmParser/LLToken.h | 43 +++++++++-------- 6 files changed, 197 insertions(+), 41 deletions(-) diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 8fd92f97f40..d702cfb02c3 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -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 diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 72136d058e0..2256124043e 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -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); diff --git a/lib/AsmParser/LLLexer.h b/lib/AsmParser/LLLexer.h index 1a307a8becd..85703c766b0 100644 --- a/lib/AsmParser/LLLexer.h +++ b/lib/AsmParser/LLLexer.h @@ -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); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 2b6b165837b..22c21c62b92 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -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 +/// ::= | '=' +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. diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index d8de77908cc..131331a5bc6 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -125,6 +125,9 @@ namespace llvm { std::map > > ForwardRefBlockAddresses; + // Attribute builder reference information. + std::map 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); diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index c9ecd21470c..8c18a3be602 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -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: -- 2.34.1