[llvm] r335602 - [ThinLTO] Parse module summary index from assembly
Teresa Johnson via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 26 06:56:49 PDT 2018
Author: tejohnson
Date: Tue Jun 26 06:56:49 2018
New Revision: 335602
URL: http://llvm.org/viewvc/llvm-project?rev=335602&view=rev
Log:
[ThinLTO] Parse module summary index from assembly
Summary:
Adds assembly parsing support for the module summary index (follow on
to r333335 which added the assembly writing support).
I added support to llvm-as to invoke the index parsing, so that it can
create either a bitcode file with a Module and a per-module index, or
a combined index without a Module.
I will send follow on patches soon to do the following:
- add support to tools such as llvm-lto2 to parse the per-module indexes
from assembly instead of bitcode when testing the thin link.
- verification support.
Depends on D47844 and D47842.
Reviewers: pcc, dexonsmith, mehdi_amini
Subscribers: inglorion, eraman, steven_wu, llvm-commits
Differential Revision: https://reviews.llvm.org/D47905
Added:
llvm/trunk/test/Assembler/thinlto-summary.ll
Modified:
llvm/trunk/include/llvm/AsmParser/Parser.h
llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
llvm/trunk/lib/AsmParser/LLLexer.cpp
llvm/trunk/lib/AsmParser/LLLexer.h
llvm/trunk/lib/AsmParser/LLParser.cpp
llvm/trunk/lib/AsmParser/LLParser.h
llvm/trunk/lib/AsmParser/LLToken.h
llvm/trunk/lib/AsmParser/Parser.cpp
llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
llvm/trunk/test/Assembler/thinlto-bad-summary1.ll
llvm/trunk/test/Assembler/thinlto-bad-summary2.ll
llvm/trunk/test/Assembler/thinlto-bad-summary3.ll
llvm/trunk/test/Bitcode/thinlto-alias.ll
llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll
llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll
llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll
llvm/trunk/test/Bitcode/thinlto-type-tests.ll
llvm/trunk/test/Bitcode/thinlto-type-vcalls.ll
llvm/trunk/tools/llvm-as/llvm-as.cpp
Modified: llvm/trunk/include/llvm/AsmParser/Parser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/AsmParser/Parser.h?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/include/llvm/AsmParser/Parser.h (original)
+++ llvm/trunk/include/llvm/AsmParser/Parser.h Tue Jun 26 06:56:49 2018
@@ -21,11 +21,12 @@ namespace llvm {
class Constant;
class LLVMContext;
class Module;
+class ModuleSummaryIndex;
struct SlotMapping;
class SMDiagnostic;
class Type;
-/// This function is the main interface to the LLVM Assembly Parser. It parses
+/// This function is a main interface to the LLVM Assembly Parser. It parses
/// an ASCII file that (presumably) contains LLVM Assembly code. It returns a
/// Module (intermediate representation) with the corresponding features. Note
/// that this does not verify that the generated Module is valid, so you should
@@ -67,6 +68,46 @@ std::unique_ptr<Module> parseAssemblyStr
bool UpgradeDebugInfo = true,
StringRef DataLayoutString = "");
+/// Holds the Module and ModuleSummaryIndex returned by the interfaces
+/// that parse both.
+struct ParsedModuleAndIndex {
+ std::unique_ptr<Module> Mod;
+ std::unique_ptr<ModuleSummaryIndex> Index;
+};
+
+/// This function is a main interface to the LLVM Assembly Parser. It parses
+/// an ASCII file that (presumably) contains LLVM Assembly code, including
+/// a module summary. It returns a Module (intermediate representation) and
+/// a ModuleSummaryIndex with the corresponding features. Note that this does
+/// not verify that the generated Module or Index are valid, so you should
+/// run the verifier after parsing the file to check that they are okay.
+/// Parse LLVM Assembly from a file
+/// \param Filename The name of the file to parse
+/// \param Error Error result info.
+/// \param Context Context in which to allocate globals info.
+/// \param Slots The optional slot mapping that will be initialized during
+/// parsing.
+/// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier.
+/// This option should only be set to false by llvm-as
+/// for use inside the LLVM testuite!
+/// \param DataLayoutString Override datalayout in the llvm assembly.
+ParsedModuleAndIndex
+parseAssemblyFileWithIndex(StringRef Filename, SMDiagnostic &Error,
+ LLVMContext &Context, SlotMapping *Slots = nullptr,
+ bool UpgradeDebugInfo = true,
+ StringRef DataLayoutString = "");
+
+/// This function is a main interface to the LLVM Assembly Parser. It parses
+/// an ASCII file that (presumably) contains LLVM Assembly code for a module
+/// summary. It returns a a ModuleSummaryIndex with the corresponding features.
+/// Note that this does not verify that the generated Index is valid, so you
+/// should run the verifier after parsing the file to check that it is okay.
+/// Parse LLVM Assembly Index from a file
+/// \param Filename The name of the file to parse
+/// \param Error Error result info.
+std::unique_ptr<ModuleSummaryIndex>
+parseSummaryIndexAssemblyFile(StringRef Filename, SMDiagnostic &Error);
+
/// parseAssemblyFile and parseAssemblyString are wrappers around this function.
/// Parse LLVM Assembly from a MemoryBuffer.
/// \param F The MemoryBuffer containing assembly
@@ -83,6 +124,34 @@ std::unique_ptr<Module> parseAssembly(Me
bool UpgradeDebugInfo = true,
StringRef DataLayoutString = "");
+/// Parse LLVM Assembly including the summary index from a MemoryBuffer.
+///
+/// \param F The MemoryBuffer containing assembly with summary
+/// \param Err Error result info.
+/// \param Slots The optional slot mapping that will be initialized during
+/// parsing.
+/// \param UpgradeDebugInfo Run UpgradeDebugInfo, which runs the Verifier.
+/// This option should only be set to false by llvm-as
+/// for use inside the LLVM testuite!
+/// \param DataLayoutString Override datalayout in the llvm assembly.
+///
+/// parseAssemblyFileWithIndex is a wrapper around this function.
+ParsedModuleAndIndex parseAssemblyWithIndex(MemoryBufferRef F,
+ SMDiagnostic &Err,
+ LLVMContext &Context,
+ SlotMapping *Slots = nullptr,
+ bool UpgradeDebugInfo = true,
+ StringRef DataLayoutString = "");
+
+/// Parse LLVM Assembly for summary index from a MemoryBuffer.
+///
+/// \param F The MemoryBuffer containing assembly with summary
+/// \param Err Error result info.
+///
+/// parseSummaryIndexAssemblyFile is a wrapper around this function.
+std::unique_ptr<ModuleSummaryIndex>
+parseSummaryIndexAssembly(MemoryBufferRef F, SMDiagnostic &Err);
+
/// This function is the low-level interface to the LLVM Assembly Parser.
/// This is kept as an independent function instead of being inlined into
/// parseAssembly for the convenience of interactive users that want to add
@@ -90,6 +159,7 @@ std::unique_ptr<Module> parseAssembly(Me
///
/// \param F The MemoryBuffer containing assembly
/// \param M The module to add data to.
+/// \param Index The index to add data to.
/// \param Err Error result info.
/// \param Slots The optional slot mapping that will be initialized during
/// parsing.
@@ -98,8 +168,8 @@ std::unique_ptr<Module> parseAssembly(Me
/// This option should only be set to false by llvm-as
/// for use inside the LLVM testuite!
/// \param DataLayoutString Override datalayout in the llvm assembly.
-bool parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err,
- SlotMapping *Slots = nullptr,
+bool parseAssemblyInto(MemoryBufferRef F, Module *M, ModuleSummaryIndex *Index,
+ SMDiagnostic &Err, SlotMapping *Slots = nullptr,
bool UpgradeDebugInfo = true,
StringRef DataLayoutString = "");
Modified: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h (original)
+++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h Tue Jun 26 06:56:49 2018
@@ -373,6 +373,8 @@ public:
void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; }
void setAliaseeGUID(GlobalValue::GUID GUID) { AliaseeGUID = GUID; }
+ bool hasAliasee() const { return !!AliaseeSummary; }
+
const GlobalValueSummary &getAliasee() const {
assert(AliaseeSummary && "Unexpected missing aliasee summary");
return *AliaseeSummary;
Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLLexer.cpp Tue Jun 26 06:56:49 2018
@@ -159,7 +159,8 @@ static const char *isLabelTail(const cha
LLLexer::LLLexer(StringRef StartBuf, SourceMgr &sm, SMDiagnostic &Err,
LLVMContext &C)
- : CurBuf(StartBuf), ErrorInfo(Err), SM(sm), Context(C), APFloatVal(0.0) {
+ : CurBuf(StartBuf), ErrorInfo(Err), SM(sm), Context(C), APFloatVal(0.0),
+ IgnoreColonInIdentifiers(false) {
CurPtr = CurBuf.begin();
}
@@ -221,6 +222,8 @@ lltok::Kind LLLexer::LexToken() {
case '!': return LexExclaim();
case '^':
return LexCaret();
+ case ':':
+ return lltok::colon;
case '#': return LexHash();
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
@@ -461,8 +464,9 @@ lltok::Kind LLLexer::LexIdentifier() {
KeywordEnd = CurPtr;
}
- // If we stopped due to a colon, this really is a label.
- if (*CurPtr == ':') {
+ // If we stopped due to a colon, unless we were directed to ignore it,
+ // this really is a label.
+ if (!IgnoreColonInIdentifiers && *CurPtr == ':') {
StrVal.assign(StartChar-1, CurPtr++);
return lltok::LabelStr;
}
@@ -715,6 +719,73 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(catch);
KEYWORD(filter);
+ // Summary index keywords.
+ KEYWORD(path);
+ KEYWORD(hash);
+ KEYWORD(gv);
+ KEYWORD(guid);
+ KEYWORD(name);
+ KEYWORD(summaries);
+ KEYWORD(flags);
+ KEYWORD(linkage);
+ KEYWORD(notEligibleToImport);
+ KEYWORD(live);
+ KEYWORD(dsoLocal);
+ KEYWORD(function);
+ KEYWORD(insts);
+ KEYWORD(funcFlags);
+ KEYWORD(readNone);
+ KEYWORD(readOnly);
+ KEYWORD(noRecurse);
+ KEYWORD(returnDoesNotAlias);
+ KEYWORD(calls);
+ KEYWORD(callee);
+ KEYWORD(hotness);
+ KEYWORD(unknown);
+ KEYWORD(hot);
+ KEYWORD(critical);
+ KEYWORD(relbf);
+ KEYWORD(variable);
+ KEYWORD(aliasee);
+ KEYWORD(refs);
+ KEYWORD(typeIdInfo);
+ KEYWORD(typeTests);
+ KEYWORD(typeTestAssumeVCalls);
+ KEYWORD(typeCheckedLoadVCalls);
+ KEYWORD(typeTestAssumeConstVCalls);
+ KEYWORD(typeCheckedLoadConstVCalls);
+ KEYWORD(vFuncId);
+ KEYWORD(offset);
+ KEYWORD(args);
+ KEYWORD(typeid);
+ KEYWORD(summary);
+ KEYWORD(typeTestRes);
+ KEYWORD(kind);
+ KEYWORD(unsat);
+ KEYWORD(byteArray);
+ KEYWORD(inline);
+ KEYWORD(single);
+ KEYWORD(allOnes);
+ KEYWORD(sizeM1BitWidth);
+ KEYWORD(alignLog2);
+ KEYWORD(sizeM1);
+ KEYWORD(bitMask);
+ KEYWORD(inlineBits);
+ KEYWORD(wpdResolutions);
+ KEYWORD(wpdRes);
+ KEYWORD(indir);
+ KEYWORD(singleImpl);
+ KEYWORD(branchFunnel);
+ KEYWORD(singleImplName);
+ KEYWORD(resByArg);
+ KEYWORD(byArg);
+ KEYWORD(uniformRetVal);
+ KEYWORD(uniqueRetVal);
+ KEYWORD(virtualConstProp);
+ KEYWORD(info);
+ KEYWORD(byte);
+ KEYWORD(bit);
+
#undef KEYWORD
// Keywords for types.
Modified: llvm/trunk/lib/AsmParser/LLLexer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.h?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLLexer.h (original)
+++ llvm/trunk/lib/AsmParser/LLLexer.h Tue Jun 26 06:56:49 2018
@@ -42,6 +42,10 @@ namespace llvm {
APFloat APFloatVal;
APSInt APSIntVal;
+ // When false (default), an identifier ending in ':' is a label token.
+ // When true, the ':' is treated as a separate token.
+ bool IgnoreColonInIdentifiers;
+
public:
explicit LLLexer(StringRef StartBuf, SourceMgr &SM, SMDiagnostic &,
LLVMContext &C);
@@ -59,6 +63,9 @@ namespace llvm {
const APSInt &getAPSIntVal() const { return APSIntVal; }
const APFloat &getAPFloatVal() const { return APFloatVal; }
+ void setIgnoreColonInIdentifiers(bool val) {
+ IgnoreColonInIdentifiers = val;
+ }
bool Error(LocTy L, const Twine &Msg) const;
bool Error(const Twine &Msg) const { return Error(getLoc(), Msg); }
Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Tue Jun 26 06:56:49 2018
@@ -71,8 +71,8 @@ bool LLParser::Run() {
Lex.getLoc(),
"Can't read textual IR with a Context that discards named Values");
- return ParseTopLevelEntities() ||
- ValidateEndOfModule();
+ return ParseTopLevelEntities() || ValidateEndOfModule() ||
+ ValidateEndOfIndex();
}
bool LLParser::parseStandaloneConstantValue(Constant *&C,
@@ -120,6 +120,8 @@ void LLParser::restoreParsingState(const
/// ValidateEndOfModule - Do final validity and sanity checks at the end of the
/// module.
bool LLParser::ValidateEndOfModule() {
+ if (!M)
+ return false;
// Handle any function attribute group forward references.
for (const auto &RAG : ForwardRefAttrGroups) {
Value *V = RAG.first;
@@ -258,11 +260,54 @@ bool LLParser::ValidateEndOfModule() {
return false;
}
+/// Do final validity and sanity checks at the end of the index.
+bool LLParser::ValidateEndOfIndex() {
+ if (!Index)
+ return false;
+
+ if (!ForwardRefValueInfos.empty())
+ return Error(ForwardRefValueInfos.begin()->second.front().second,
+ "use of undefined summary '^" +
+ Twine(ForwardRefValueInfos.begin()->first) + "'");
+
+ if (!ForwardRefAliasees.empty())
+ return Error(ForwardRefAliasees.begin()->second.front().second,
+ "use of undefined summary '^" +
+ Twine(ForwardRefAliasees.begin()->first) + "'");
+
+ if (!ForwardRefTypeIds.empty())
+ return Error(ForwardRefTypeIds.begin()->second.front().second,
+ "use of undefined type id summary '^" +
+ Twine(ForwardRefTypeIds.begin()->first) + "'");
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Top-Level Entities
//===----------------------------------------------------------------------===//
bool LLParser::ParseTopLevelEntities() {
+ // If there is no Module, then parse just the summary index entries.
+ if (!M) {
+ while (true) {
+ switch (Lex.getKind()) {
+ case lltok::Eof:
+ return false;
+ case lltok::SummaryID:
+ if (ParseSummaryEntry())
+ return true;
+ break;
+ case lltok::kw_source_filename:
+ if (ParseSourceFileName())
+ return true;
+ break;
+ default:
+ // Skip everything else
+ Lex.Lex();
+ }
+ }
+ }
while (true) {
switch (Lex.getKind()) {
default: return TokError("expected top-level entity");
@@ -341,12 +386,12 @@ bool LLParser::ParseTargetDefinition() {
/// ::= 'source_filename' '=' STRINGCONSTANT
bool LLParser::ParseSourceFileName() {
assert(Lex.getKind() == lltok::kw_source_filename);
- std::string Str;
Lex.Lex();
if (ParseToken(lltok::equal, "expected '=' after source_filename") ||
- ParseStringConstant(Str))
+ ParseStringConstant(SourceFileName))
return true;
- M->setSourceFileName(Str);
+ if (M)
+ M->setSourceFileName(SourceFileName);
return false;
}
@@ -721,8 +766,12 @@ bool LLParser::SkipModuleSummaryEntry()
// type, followed by a colon, then the fields surrounded by nested sets of
// parentheses. The "tag:" looks like a Label. Once parsing support is
// in place we will look for the tokens corresponding to the expected tags.
- if (ParseToken(lltok::LabelStr,
- "expected 'label' at start of summary entry") ||
+ if (Lex.getKind() != lltok::kw_gv && Lex.getKind() != lltok::kw_module &&
+ Lex.getKind() != lltok::kw_typeid)
+ return TokError(
+ "Expected 'gv', 'module', or 'typeid' at the start of summary entry");
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':' at start of summary entry") ||
ParseToken(lltok::lparen, "expected '(' at start of summary entry"))
return true;
// Now walk through the parenthesized entry, until the number of open
@@ -747,20 +796,36 @@ bool LLParser::SkipModuleSummaryEntry()
return false;
}
-/// ParseSummaryEntry:
-/// ::= SummaryID '=' ...
+/// SummaryEntry
+/// ::= SummaryID '=' GVEntry | ModuleEntry | TypeIdEntry
bool LLParser::ParseSummaryEntry() {
assert(Lex.getKind() == lltok::SummaryID);
- // unsigned SummaryID = Lex.getUIntVal();
+ unsigned SummaryID = Lex.getUIntVal();
+
+ // For summary entries, colons should be treated as distinct tokens,
+ // not an indication of the end of a label token.
+ Lex.setIgnoreColonInIdentifiers(true);
Lex.Lex();
if (ParseToken(lltok::equal, "expected '=' here"))
return true;
- // TODO: Support parsing into a ModuleSummaryIndex object saved in
- // the LLParser. For now, skip the summary entry.
- if (SkipModuleSummaryEntry())
- return true;
+ // If we don't have an index object, skip the summary entry.
+ if (!Index)
+ return SkipModuleSummaryEntry();
+
+ switch (Lex.getKind()) {
+ case lltok::kw_gv:
+ return ParseGVEntry(SummaryID);
+ case lltok::kw_module:
+ return ParseModuleEntry(SummaryID);
+ case lltok::kw_typeid:
+ return ParseTypeIdEntry(SummaryID);
+ break;
+ default:
+ return Error(Lex.getLoc(), "unexpected summary kind");
+ }
+ Lex.setIgnoreColonInIdentifiers(false);
return false;
}
@@ -6922,3 +6987,1170 @@ bool LLParser::ParseUseListOrderBB() {
return sortUseListOrder(V, Indexes, Loc);
}
+
+/// ModuleEntry
+/// ::= 'module' ':' '(' 'path' ':' STRINGCONSTANT ',' 'hash' ':' Hash ')'
+/// Hash ::= '(' UInt32 ',' UInt32 ',' UInt32 ',' UInt32 ',' UInt32 ')'
+bool LLParser::ParseModuleEntry(unsigned ID) {
+ assert(Lex.getKind() == lltok::kw_module);
+ Lex.Lex();
+
+ std::string Path;
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseToken(lltok::kw_path, "expected 'path' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseStringConstant(Path) ||
+ ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_hash, "expected 'hash' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ ModuleHash Hash;
+ if (ParseUInt32(Hash[0]) || ParseToken(lltok::comma, "expected ',' here") ||
+ ParseUInt32(Hash[1]) || ParseToken(lltok::comma, "expected ',' here") ||
+ ParseUInt32(Hash[2]) || ParseToken(lltok::comma, "expected ',' here") ||
+ ParseUInt32(Hash[3]) || ParseToken(lltok::comma, "expected ',' here") ||
+ ParseUInt32(Hash[4]))
+ return true;
+
+ if (ParseToken(lltok::rparen, "expected ')' here") ||
+ ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ auto ModuleEntry = Index->addModule(Path, ID, Hash);
+ ModuleIdMap[ID] = ModuleEntry->first();
+
+ return false;
+}
+
+/// TypeIdEntry
+/// ::= 'typeid' ':' '(' 'name' ':' STRINGCONSTANT ',' TypeIdSummary ')'
+bool LLParser::ParseTypeIdEntry(unsigned ID) {
+ assert(Lex.getKind() == lltok::kw_typeid);
+ Lex.Lex();
+
+ std::string Name;
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseToken(lltok::kw_name, "expected 'name' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseStringConstant(Name))
+ return true;
+
+ TypeIdSummary &TIS = Index->getOrInsertTypeIdSummary(Name);
+ if (ParseToken(lltok::comma, "expected ',' here") ||
+ ParseTypeIdSummary(TIS) || ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ // Check if this ID was forward referenced, and if so, update the
+ // corresponding GUIDs.
+ auto FwdRefTIDs = ForwardRefTypeIds.find(ID);
+ if (FwdRefTIDs != ForwardRefTypeIds.end()) {
+ for (auto TIDRef : FwdRefTIDs->second) {
+ assert(!*TIDRef.first &&
+ "Forward referenced type id GUID expected to be 0");
+ *TIDRef.first = GlobalValue::getGUID(Name);
+ }
+ ForwardRefTypeIds.erase(FwdRefTIDs);
+ }
+
+ return false;
+}
+
+/// TypeIdSummary
+/// ::= 'summary' ':' '(' TypeTestResolution [',' OptionalWpdResolutions]? ')'
+bool LLParser::ParseTypeIdSummary(TypeIdSummary &TIS) {
+ if (ParseToken(lltok::kw_summary, "expected 'summary' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseTypeTestResolution(TIS.TTRes))
+ return true;
+
+ if (EatIfPresent(lltok::comma)) {
+ // Expect optional wpdResolutions field
+ if (ParseOptionalWpdResolutions(TIS.WPDRes))
+ return true;
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// TypeTestResolution
+/// ::= 'typeTestRes' ':' '(' 'kind' ':'
+/// ( 'unsat' | 'byteArray' | 'inline' | 'single' | 'allOnes' ) ','
+/// 'sizeM1BitWidth' ':' SizeM1BitWidth [',' 'alignLog2' ':' UInt64]?
+/// [',' 'sizeM1' ':' UInt64]? [',' 'bitMask' ':' UInt8]?
+/// [',' 'inlinesBits' ':' UInt64]? ')'
+bool LLParser::ParseTypeTestResolution(TypeTestResolution &TTRes) {
+ if (ParseToken(lltok::kw_typeTestRes, "expected 'typeTestRes' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseToken(lltok::kw_kind, "expected 'kind' here") ||
+ ParseToken(lltok::colon, "expected ':' here"))
+ return true;
+
+ switch (Lex.getKind()) {
+ case lltok::kw_unsat:
+ TTRes.TheKind = TypeTestResolution::Unsat;
+ break;
+ case lltok::kw_byteArray:
+ TTRes.TheKind = TypeTestResolution::ByteArray;
+ break;
+ case lltok::kw_inline:
+ TTRes.TheKind = TypeTestResolution::Inline;
+ break;
+ case lltok::kw_single:
+ TTRes.TheKind = TypeTestResolution::Single;
+ break;
+ case lltok::kw_allOnes:
+ TTRes.TheKind = TypeTestResolution::AllOnes;
+ break;
+ default:
+ return Error(Lex.getLoc(), "unexpected TypeTestResolution kind");
+ }
+ Lex.Lex();
+
+ if (ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_sizeM1BitWidth, "expected 'sizeM1BitWidth' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseUInt32(TTRes.SizeM1BitWidth))
+ return true;
+
+ // Parse optional fields
+ while (EatIfPresent(lltok::comma)) {
+ switch (Lex.getKind()) {
+ case lltok::kw_alignLog2:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") ||
+ ParseUInt64(TTRes.AlignLog2))
+ return true;
+ break;
+ case lltok::kw_sizeM1:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") || ParseUInt64(TTRes.SizeM1))
+ return true;
+ break;
+ case lltok::kw_bitMask: {
+ unsigned Val;
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") || ParseUInt32(Val))
+ return true;
+ assert(Val <= 0xff);
+ TTRes.BitMask = (uint8_t)Val;
+ break;
+ }
+ case lltok::kw_inlineBits:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") ||
+ ParseUInt64(TTRes.InlineBits))
+ return true;
+ break;
+ default:
+ return Error(Lex.getLoc(), "expected optional TypeTestResolution field");
+ }
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// OptionalWpdResolutions
+/// ::= 'wpsResolutions' ':' '(' WpdResolution [',' WpdResolution]* ')'
+/// WpdResolution ::= '(' 'offset' ':' UInt64 ',' WpdRes ')'
+bool LLParser::ParseOptionalWpdResolutions(
+ std::map<uint64_t, WholeProgramDevirtResolution> &WPDResMap) {
+ if (ParseToken(lltok::kw_wpdResolutions, "expected 'wpdResolutions' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ do {
+ uint64_t Offset;
+ WholeProgramDevirtResolution WPDRes;
+ if (ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseToken(lltok::kw_offset, "expected 'offset' here") ||
+ ParseToken(lltok::colon, "expected ':' here") || ParseUInt64(Offset) ||
+ ParseToken(lltok::comma, "expected ',' here") || ParseWpdRes(WPDRes) ||
+ ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+ WPDResMap[Offset] = WPDRes;
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// WpdRes
+/// ::= 'wpdRes' ':' '(' 'kind' ':' 'indir'
+/// [',' OptionalResByArg]? ')'
+/// ::= 'wpdRes' ':' '(' 'kind' ':' 'singleImpl'
+/// ',' 'singleImplName' ':' STRINGCONSTANT ','
+/// [',' OptionalResByArg]? ')'
+/// ::= 'wpdRes' ':' '(' 'kind' ':' 'branchFunnel'
+/// [',' OptionalResByArg]? ')'
+bool LLParser::ParseWpdRes(WholeProgramDevirtResolution &WPDRes) {
+ if (ParseToken(lltok::kw_wpdRes, "expected 'wpdRes' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseToken(lltok::kw_kind, "expected 'kind' here") ||
+ ParseToken(lltok::colon, "expected ':' here"))
+ return true;
+
+ switch (Lex.getKind()) {
+ case lltok::kw_indir:
+ WPDRes.TheKind = WholeProgramDevirtResolution::Indir;
+ break;
+ case lltok::kw_singleImpl:
+ WPDRes.TheKind = WholeProgramDevirtResolution::SingleImpl;
+ break;
+ case lltok::kw_branchFunnel:
+ WPDRes.TheKind = WholeProgramDevirtResolution::BranchFunnel;
+ break;
+ default:
+ return Error(Lex.getLoc(), "unexpected WholeProgramDevirtResolution kind");
+ }
+ Lex.Lex();
+
+ // Parse optional fields
+ while (EatIfPresent(lltok::comma)) {
+ switch (Lex.getKind()) {
+ case lltok::kw_singleImplName:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseStringConstant(WPDRes.SingleImplName))
+ return true;
+ break;
+ case lltok::kw_resByArg:
+ if (ParseOptionalResByArg(WPDRes.ResByArg))
+ return true;
+ break;
+ default:
+ return Error(Lex.getLoc(),
+ "expected optional WholeProgramDevirtResolution field");
+ }
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// OptionalResByArg
+/// ::= 'wpdRes' ':' '(' ResByArg[, ResByArg]* ')'
+/// ResByArg ::= Args ',' 'byArg' ':' '(' 'kind' ':'
+/// ( 'indir' | 'uniformRetVal' | 'UniqueRetVal' |
+/// 'virtualConstProp' )
+/// [',' 'info' ':' UInt64]? [',' 'byte' ':' UInt32]?
+/// [',' 'bit' ':' UInt32]? ')'
+bool LLParser::ParseOptionalResByArg(
+ std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg>
+ &ResByArg) {
+ if (ParseToken(lltok::kw_resByArg, "expected 'resByArg' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ do {
+ std::vector<uint64_t> Args;
+ if (ParseArgs(Args) || ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_byArg, "expected 'byArg here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseToken(lltok::kw_kind, "expected 'kind' here") ||
+ ParseToken(lltok::colon, "expected ':' here"))
+ return true;
+
+ WholeProgramDevirtResolution::ByArg ByArg;
+ switch (Lex.getKind()) {
+ case lltok::kw_indir:
+ ByArg.TheKind = WholeProgramDevirtResolution::ByArg::Indir;
+ break;
+ case lltok::kw_uniformRetVal:
+ ByArg.TheKind = WholeProgramDevirtResolution::ByArg::UniformRetVal;
+ break;
+ case lltok::kw_uniqueRetVal:
+ ByArg.TheKind = WholeProgramDevirtResolution::ByArg::UniqueRetVal;
+ break;
+ case lltok::kw_virtualConstProp:
+ ByArg.TheKind = WholeProgramDevirtResolution::ByArg::VirtualConstProp;
+ break;
+ default:
+ return Error(Lex.getLoc(),
+ "unexpected WholeProgramDevirtResolution::ByArg kind");
+ }
+ Lex.Lex();
+
+ // Parse optional fields
+ while (EatIfPresent(lltok::comma)) {
+ switch (Lex.getKind()) {
+ case lltok::kw_info:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseUInt64(ByArg.Info))
+ return true;
+ break;
+ case lltok::kw_byte:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseUInt32(ByArg.Byte))
+ return true;
+ break;
+ case lltok::kw_bit:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseUInt32(ByArg.Bit))
+ return true;
+ break;
+ default:
+ return Error(Lex.getLoc(),
+ "expected optional whole program devirt field");
+ }
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ ResByArg[Args] = ByArg;
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// OptionalResByArg
+/// ::= 'args' ':' '(' UInt64[, UInt64]* ')'
+bool LLParser::ParseArgs(std::vector<uint64_t> &Args) {
+ if (ParseToken(lltok::kw_args, "expected 'args' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ do {
+ uint64_t Val;
+ if (ParseUInt64(Val))
+ return true;
+ Args.push_back(Val);
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+static ValueInfo EmptyVI =
+ ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);
+
+/// Stores the given Name/GUID and associated summary into the Index.
+/// Also updates any forward references to the associated entry ID.
+void LLParser::AddGlobalValueToIndex(
+ std::string Name, GlobalValue::GUID GUID, GlobalValue::LinkageTypes Linkage,
+ unsigned ID, std::unique_ptr<GlobalValueSummary> Summary) {
+ // First create the ValueInfo utilizing the Name or GUID.
+ ValueInfo VI;
+ if (GUID != 0) {
+ assert(Name.empty());
+ VI = Index->getOrInsertValueInfo(GUID);
+ } else {
+ assert(!Name.empty());
+ if (M) {
+ auto *GV = M->getNamedValue(Name);
+ assert(GV);
+ VI = Index->getOrInsertValueInfo(GV);
+ } else {
+ assert(
+ (!GlobalValue::isLocalLinkage(Linkage) || !SourceFileName.empty()) &&
+ "Need a source_filename to compute GUID for local");
+ GUID = GlobalValue::getGUID(
+ GlobalValue::getGlobalIdentifier(Name, Linkage, SourceFileName));
+ VI = Index->getOrInsertValueInfo(GUID, Index->saveString(Name));
+ }
+ }
+
+ // Add the summary if one was provided.
+ if (Summary)
+ Index->addGlobalValueSummary(VI, std::move(Summary));
+
+ // Resolve forward references from calls/refs
+ auto FwdRefVIs = ForwardRefValueInfos.find(ID);
+ if (FwdRefVIs != ForwardRefValueInfos.end()) {
+ for (auto VIRef : FwdRefVIs->second) {
+ assert(*VIRef.first == EmptyVI &&
+ "Forward referenced ValueInfo expected to be empty");
+ *VIRef.first = VI;
+ }
+ ForwardRefValueInfos.erase(FwdRefVIs);
+ }
+
+ // Resolve forward references from aliases
+ auto FwdRefAliasees = ForwardRefAliasees.find(ID);
+ if (FwdRefAliasees != ForwardRefAliasees.end()) {
+ for (auto AliaseeRef : FwdRefAliasees->second) {
+ assert(!AliaseeRef.first->hasAliasee() &&
+ "Forward referencing alias already has aliasee");
+ AliaseeRef.first->setAliasee(VI.getSummaryList().front().get());
+ }
+ ForwardRefAliasees.erase(FwdRefAliasees);
+ }
+
+ // Save the associated ValueInfo for use in later references by ID.
+ if (ID == NumberedValueInfos.size())
+ NumberedValueInfos.push_back(VI);
+ else {
+ // Handle non-continuous numbers (to make test simplification easier).
+ if (ID > NumberedValueInfos.size())
+ NumberedValueInfos.resize(ID + 1);
+ NumberedValueInfos[ID] = VI;
+ }
+}
+
+/// ParseGVEntry
+/// ::= 'gv' ':' '(' ('name' ':' STRINGCONSTANT | 'guid' ':' UInt64)
+/// [',' 'summaries' ':' Summary[',' Summary]* ]? ')'
+/// Summary ::= '(' (FunctionSummary | VariableSummary | AliasSummary) ')'
+bool LLParser::ParseGVEntry(unsigned ID) {
+ assert(Lex.getKind() == lltok::kw_gv);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ std::string Name;
+ GlobalValue::GUID GUID = 0;
+ switch (Lex.getKind()) {
+ case lltok::kw_name:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseStringConstant(Name))
+ return true;
+ // Can't create GUID/ValueInfo until we have the linkage.
+ break;
+ case lltok::kw_guid:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':' here") || ParseUInt64(GUID))
+ return true;
+ break;
+ default:
+ return Error(Lex.getLoc(), "expected name or guid tag");
+ }
+
+ if (!EatIfPresent(lltok::comma)) {
+ // No summaries. Wrap up.
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+ // This was created for a call to an external or indirect target.
+ // A GUID with no summary came from a VALUE_GUID record, dummy GUID
+ // created for indirect calls with VP. A Name with no GUID came from
+ // an external definition. We pass ExternalLinkage since that is only
+ // used when the GUID must be computed from Name, and in that case
+ // the symbol must have external linkage.
+ AddGlobalValueToIndex(Name, GUID, GlobalValue::ExternalLinkage, ID,
+ nullptr);
+ return false;
+ }
+
+ // Have a list of summaries
+ if (ParseToken(lltok::kw_summaries, "expected 'summaries' here") ||
+ ParseToken(lltok::colon, "expected ':' here"))
+ return true;
+
+ do {
+ if (ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+ switch (Lex.getKind()) {
+ case lltok::kw_function:
+ if (ParseFunctionSummary(Name, GUID, ID))
+ return true;
+ break;
+ case lltok::kw_variable:
+ if (ParseVariableSummary(Name, GUID, ID))
+ return true;
+ break;
+ case lltok::kw_alias:
+ if (ParseAliasSummary(Name, GUID, ID))
+ return true;
+ break;
+ default:
+ return Error(Lex.getLoc(), "expected summary type");
+ }
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// FunctionSummary
+/// ::= 'function' ':' '(' 'module' ':' ModuleReference ',' GVFlags
+/// ',' 'insts' ':' UInt32 [',' OptionalFFlags]? [',' OptionalCalls]?
+/// [',' OptionalTypeIdInfo]? [',' OptionalRefs]? ')'
+bool LLParser::ParseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
+ unsigned ID) {
+ assert(Lex.getKind() == lltok::kw_function);
+ Lex.Lex();
+
+ StringRef ModulePath;
+ GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags(
+ /*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
+ /*Live=*/false, /*IsLocal=*/false);
+ unsigned InstCount;
+ std::vector<FunctionSummary::EdgeTy> Calls;
+ FunctionSummary::TypeIdInfo TypeIdInfo;
+ std::vector<ValueInfo> Refs;
+ // Default is all-zeros (conservative values).
+ FunctionSummary::FFlags FFlags = {};
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseModuleReference(ModulePath) ||
+ ParseToken(lltok::comma, "expected ',' here") || ParseGVFlags(GVFlags) ||
+ ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_insts, "expected 'insts' here") ||
+ ParseToken(lltok::colon, "expected ':' here") || ParseUInt32(InstCount))
+ return true;
+
+ // Parse optional fields
+ while (EatIfPresent(lltok::comma)) {
+ switch (Lex.getKind()) {
+ case lltok::kw_funcFlags:
+ if (ParseOptionalFFlags(FFlags))
+ return true;
+ break;
+ case lltok::kw_calls:
+ if (ParseOptionalCalls(Calls))
+ return true;
+ break;
+ case lltok::kw_typeIdInfo:
+ if (ParseOptionalTypeIdInfo(TypeIdInfo))
+ return true;
+ break;
+ case lltok::kw_refs:
+ if (ParseOptionalRefs(Refs))
+ return true;
+ break;
+ default:
+ return Error(Lex.getLoc(), "expected optional function summary field");
+ }
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ auto FS = llvm::make_unique<FunctionSummary>(
+ GVFlags, InstCount, FFlags, std::move(Refs), std::move(Calls),
+ std::move(TypeIdInfo.TypeTests),
+ std::move(TypeIdInfo.TypeTestAssumeVCalls),
+ std::move(TypeIdInfo.TypeCheckedLoadVCalls),
+ std::move(TypeIdInfo.TypeTestAssumeConstVCalls),
+ std::move(TypeIdInfo.TypeCheckedLoadConstVCalls));
+
+ FS->setModulePath(ModulePath);
+
+ AddGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,
+ ID, std::move(FS));
+
+ return false;
+}
+
+/// VariableSummary
+/// ::= 'variable' ':' '(' 'module' ':' ModuleReference ',' GVFlags
+/// [',' OptionalRefs]? ')'
+bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID,
+ unsigned ID) {
+ assert(Lex.getKind() == lltok::kw_variable);
+ Lex.Lex();
+
+ StringRef ModulePath;
+ GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags(
+ /*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
+ /*Live=*/false, /*IsLocal=*/false);
+ std::vector<ValueInfo> Refs;
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseModuleReference(ModulePath) ||
+ ParseToken(lltok::comma, "expected ',' here") || ParseGVFlags(GVFlags))
+ return true;
+
+ // Parse optional refs field
+ if (EatIfPresent(lltok::comma)) {
+ if (ParseOptionalRefs(Refs))
+ return true;
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ auto GS = llvm::make_unique<GlobalVarSummary>(GVFlags, std::move(Refs));
+
+ GS->setModulePath(ModulePath);
+
+ AddGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,
+ ID, std::move(GS));
+
+ return false;
+}
+
+/// AliasSummary
+/// ::= 'alias' ':' '(' 'module' ':' ModuleReference ',' GVFlags ','
+/// 'aliasee' ':' GVReference ')'
+bool LLParser::ParseAliasSummary(std::string Name, GlobalValue::GUID GUID,
+ unsigned ID) {
+ assert(Lex.getKind() == lltok::kw_alias);
+ LocTy Loc = Lex.getLoc();
+ Lex.Lex();
+
+ StringRef ModulePath;
+ GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags(
+ /*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false,
+ /*Live=*/false, /*IsLocal=*/false);
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseModuleReference(ModulePath) ||
+ ParseToken(lltok::comma, "expected ',' here") || ParseGVFlags(GVFlags) ||
+ ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_aliasee, "expected 'aliasee' here") ||
+ ParseToken(lltok::colon, "expected ':' here"))
+ return true;
+
+ ValueInfo AliaseeVI;
+ unsigned GVId;
+ if (ParseGVReference(AliaseeVI, GVId))
+ return true;
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ auto AS = llvm::make_unique<AliasSummary>(GVFlags);
+
+ AS->setModulePath(ModulePath);
+
+ // Record forward reference if the aliasee is not parsed yet.
+ if (AliaseeVI == EmptyVI) {
+ auto FwdRef = ForwardRefAliasees.insert(
+ std::make_pair(GVId, std::vector<std::pair<AliasSummary *, LocTy>>()));
+ FwdRef.first->second.push_back(std::make_pair(AS.get(), Loc));
+ } else
+ AS->setAliasee(AliaseeVI.getSummaryList().front().get());
+
+ AddGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,
+ ID, std::move(AS));
+
+ return false;
+}
+
+/// Flag
+/// ::= [0|1]
+bool LLParser::ParseFlag(unsigned &Val) {
+ if (Lex.getKind() != lltok::APSInt || Lex.getAPSIntVal().isSigned())
+ return TokError("expected integer");
+ Val = (unsigned)Lex.getAPSIntVal().getBoolValue();
+ Lex.Lex();
+ return false;
+}
+
+/// OptionalFFlags
+/// := 'funcFlags' ':' '(' ['readNone' ':' Flag]?
+/// [',' 'readOnly' ':' Flag]? [',' 'noRecurse' ':' Flag]?
+/// [',' 'returnDoesNotAlias' ':' Flag]? ')'
+bool LLParser::ParseOptionalFFlags(FunctionSummary::FFlags &FFlags) {
+ assert(Lex.getKind() == lltok::kw_funcFlags);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' in funcFlags") |
+ ParseToken(lltok::lparen, "expected '(' in funcFlags"))
+ return true;
+
+ do {
+ unsigned Val;
+ switch (Lex.getKind()) {
+ case lltok::kw_readNone:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") || ParseFlag(Val))
+ return true;
+ FFlags.ReadNone = Val;
+ break;
+ case lltok::kw_readOnly:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") || ParseFlag(Val))
+ return true;
+ FFlags.ReadOnly = Val;
+ break;
+ case lltok::kw_noRecurse:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") || ParseFlag(Val))
+ return true;
+ FFlags.NoRecurse = Val;
+ break;
+ case lltok::kw_returnDoesNotAlias:
+ Lex.Lex();
+ if (ParseToken(lltok::colon, "expected ':'") || ParseFlag(Val))
+ return true;
+ FFlags.ReturnDoesNotAlias = Val;
+ break;
+ default:
+ return Error(Lex.getLoc(), "expected function flag type");
+ }
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' in funcFlags"))
+ return true;
+
+ return false;
+}
+
+/// OptionalCalls
+/// := 'calls' ':' '(' Call [',' Call]* ')'
+/// Call ::= '(' 'callee' ':' GVReference
+/// [( ',' 'hotness' ':' Hotness | ',' 'relbf' ':' UInt32 )]? ')'
+bool LLParser::ParseOptionalCalls(std::vector<FunctionSummary::EdgeTy> &Calls) {
+ assert(Lex.getKind() == lltok::kw_calls);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' in calls") |
+ ParseToken(lltok::lparen, "expected '(' in calls"))
+ return true;
+
+ IdToIndexMapType IdToIndexMap;
+ // Parse each call edge
+ do {
+ ValueInfo VI;
+ if (ParseToken(lltok::lparen, "expected '(' in call") ||
+ ParseToken(lltok::kw_callee, "expected 'callee' in call") ||
+ ParseToken(lltok::colon, "expected ':'"))
+ return true;
+
+ LocTy Loc = Lex.getLoc();
+ unsigned GVId;
+ if (ParseGVReference(VI, GVId))
+ return true;
+
+ CalleeInfo::HotnessType Hotness = CalleeInfo::HotnessType::Unknown;
+ unsigned RelBF = 0;
+ if (EatIfPresent(lltok::comma)) {
+ // Expect either hotness or relbf
+ if (EatIfPresent(lltok::kw_hotness)) {
+ if (ParseToken(lltok::colon, "expected ':'") || ParseHotness(Hotness))
+ return true;
+ } else {
+ if (ParseToken(lltok::kw_relbf, "expected relbf") ||
+ ParseToken(lltok::colon, "expected ':'") || ParseUInt32(RelBF))
+ return true;
+ }
+ }
+ // Keep track of the Call array index needing a forward reference.
+ // We will save the location of the ValueInfo needing an update, but
+ // can only do so once the std::vector is finalized.
+ if (VI == EmptyVI)
+ IdToIndexMap[GVId].push_back(std::make_pair(Calls.size(), Loc));
+ Calls.push_back(FunctionSummary::EdgeTy{VI, CalleeInfo(Hotness, RelBF)});
+
+ if (ParseToken(lltok::rparen, "expected ')' in call"))
+ return true;
+ } while (EatIfPresent(lltok::comma));
+
+ // Now that the Calls vector is finalized, it is safe to save the locations
+ // of any forward GV references that need updating later.
+ for (auto I : IdToIndexMap) {
+ for (auto P : I.second) {
+ assert(Calls[P.first].first == EmptyVI &&
+ "Forward referenced ValueInfo expected to be empty");
+ auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(
+ I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));
+ FwdRef.first->second.push_back(
+ std::make_pair(&Calls[P.first].first, P.second));
+ }
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' in calls"))
+ return true;
+
+ return false;
+}
+
+/// Hotness
+/// := ('unknown'|'cold'|'none'|'hot'|'critical')
+bool LLParser::ParseHotness(CalleeInfo::HotnessType &Hotness) {
+ switch (Lex.getKind()) {
+ case lltok::kw_unknown:
+ Hotness = CalleeInfo::HotnessType::Unknown;
+ break;
+ case lltok::kw_cold:
+ Hotness = CalleeInfo::HotnessType::Cold;
+ break;
+ case lltok::kw_none:
+ Hotness = CalleeInfo::HotnessType::None;
+ break;
+ case lltok::kw_hot:
+ Hotness = CalleeInfo::HotnessType::Hot;
+ break;
+ case lltok::kw_critical:
+ Hotness = CalleeInfo::HotnessType::Critical;
+ break;
+ default:
+ return Error(Lex.getLoc(), "invalid call edge hotness");
+ }
+ Lex.Lex();
+ return false;
+}
+
+/// OptionalRefs
+/// := 'refs' ':' '(' GVReference [',' GVReference]* ')'
+bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) {
+ assert(Lex.getKind() == lltok::kw_refs);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' in refs") |
+ ParseToken(lltok::lparen, "expected '(' in refs"))
+ return true;
+
+ IdToIndexMapType IdToIndexMap;
+ // Parse each ref edge
+ do {
+ ValueInfo VI;
+ LocTy Loc = Lex.getLoc();
+ unsigned GVId;
+ if (ParseGVReference(VI, GVId))
+ return true;
+
+ // Keep track of the Refs array index needing a forward reference.
+ // We will save the location of the ValueInfo needing an update, but
+ // can only do so once the std::vector is finalized.
+ if (VI == EmptyVI)
+ IdToIndexMap[GVId].push_back(std::make_pair(Refs.size(), Loc));
+ Refs.push_back(VI);
+ } while (EatIfPresent(lltok::comma));
+
+ // Now that the Refs vector is finalized, it is safe to save the locations
+ // of any forward GV references that need updating later.
+ for (auto I : IdToIndexMap) {
+ for (auto P : I.second) {
+ assert(Refs[P.first] == EmptyVI &&
+ "Forward referenced ValueInfo expected to be empty");
+ auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(
+ I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));
+ FwdRef.first->second.push_back(std::make_pair(&Refs[P.first], P.second));
+ }
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' in refs"))
+ return true;
+
+ return false;
+}
+
+/// OptionalTypeIdInfo
+/// := 'typeidinfo' ':' '(' [',' TypeTests]? [',' TypeTestAssumeVCalls]?
+/// [',' TypeCheckedLoadVCalls]? [',' TypeTestAssumeConstVCalls]?
+/// [',' TypeCheckedLoadConstVCalls]? ')'
+bool LLParser::ParseOptionalTypeIdInfo(
+ FunctionSummary::TypeIdInfo &TypeIdInfo) {
+ assert(Lex.getKind() == lltok::kw_typeIdInfo);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' in typeIdInfo"))
+ return true;
+
+ do {
+ switch (Lex.getKind()) {
+ case lltok::kw_typeTests:
+ if (ParseTypeTests(TypeIdInfo.TypeTests))
+ return true;
+ break;
+ case lltok::kw_typeTestAssumeVCalls:
+ if (ParseVFuncIdList(lltok::kw_typeTestAssumeVCalls,
+ TypeIdInfo.TypeTestAssumeVCalls))
+ return true;
+ break;
+ case lltok::kw_typeCheckedLoadVCalls:
+ if (ParseVFuncIdList(lltok::kw_typeCheckedLoadVCalls,
+ TypeIdInfo.TypeCheckedLoadVCalls))
+ return true;
+ break;
+ case lltok::kw_typeTestAssumeConstVCalls:
+ if (ParseConstVCallList(lltok::kw_typeTestAssumeConstVCalls,
+ TypeIdInfo.TypeTestAssumeConstVCalls))
+ return true;
+ break;
+ case lltok::kw_typeCheckedLoadConstVCalls:
+ if (ParseConstVCallList(lltok::kw_typeCheckedLoadConstVCalls,
+ TypeIdInfo.TypeCheckedLoadConstVCalls))
+ return true;
+ break;
+ default:
+ return Error(Lex.getLoc(), "invalid typeIdInfo list type");
+ }
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' in typeIdInfo"))
+ return true;
+
+ return false;
+}
+
+/// TypeTests
+/// ::= 'typeTests' ':' '(' (SummaryID | UInt64)
+/// [',' (SummaryID | UInt64)]* ')'
+bool LLParser::ParseTypeTests(std::vector<GlobalValue::GUID> &TypeTests) {
+ assert(Lex.getKind() == lltok::kw_typeTests);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' in typeIdInfo"))
+ return true;
+
+ IdToIndexMapType IdToIndexMap;
+ do {
+ GlobalValue::GUID GUID = 0;
+ if (Lex.getKind() == lltok::SummaryID) {
+ unsigned ID = Lex.getUIntVal();
+ LocTy Loc = Lex.getLoc();
+ // Keep track of the TypeTests array index needing a forward reference.
+ // We will save the location of the GUID needing an update, but
+ // can only do so once the std::vector is finalized.
+ IdToIndexMap[ID].push_back(std::make_pair(TypeTests.size(), Loc));
+ Lex.Lex();
+ } else if (ParseUInt64(GUID))
+ return true;
+ TypeTests.push_back(GUID);
+ } while (EatIfPresent(lltok::comma));
+
+ // Now that the TypeTests vector is finalized, it is safe to save the
+ // locations of any forward GV references that need updating later.
+ for (auto I : IdToIndexMap) {
+ for (auto P : I.second) {
+ assert(TypeTests[P.first] == 0 &&
+ "Forward referenced type id GUID expected to be 0");
+ auto FwdRef = ForwardRefTypeIds.insert(std::make_pair(
+ I.first, std::vector<std::pair<GlobalValue::GUID *, LocTy>>()));
+ FwdRef.first->second.push_back(
+ std::make_pair(&TypeTests[P.first], P.second));
+ }
+ }
+
+ if (ParseToken(lltok::rparen, "expected ')' in typeIdInfo"))
+ return true;
+
+ return false;
+}
+
+/// VFuncIdList
+/// ::= Kind ':' '(' VFuncId [',' VFuncId]* ')'
+bool LLParser::ParseVFuncIdList(
+ lltok::Kind Kind, std::vector<FunctionSummary::VFuncId> &VFuncIdList) {
+ assert(Lex.getKind() == Kind);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ IdToIndexMapType IdToIndexMap;
+ do {
+ FunctionSummary::VFuncId VFuncId;
+ if (ParseVFuncId(VFuncId, IdToIndexMap, VFuncIdList.size()))
+ return true;
+ VFuncIdList.push_back(VFuncId);
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ // Now that the VFuncIdList vector is finalized, it is safe to save the
+ // locations of any forward GV references that need updating later.
+ for (auto I : IdToIndexMap) {
+ for (auto P : I.second) {
+ assert(VFuncIdList[P.first].GUID == 0 &&
+ "Forward referenced type id GUID expected to be 0");
+ auto FwdRef = ForwardRefTypeIds.insert(std::make_pair(
+ I.first, std::vector<std::pair<GlobalValue::GUID *, LocTy>>()));
+ FwdRef.first->second.push_back(
+ std::make_pair(&VFuncIdList[P.first].GUID, P.second));
+ }
+ }
+
+ return false;
+}
+
+/// ConstVCallList
+/// ::= Kind ':' '(' ConstVCall [',' ConstVCall]* ')'
+bool LLParser::ParseConstVCallList(
+ lltok::Kind Kind,
+ std::vector<FunctionSummary::ConstVCall> &ConstVCallList) {
+ assert(Lex.getKind() == Kind);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ IdToIndexMapType IdToIndexMap;
+ do {
+ FunctionSummary::ConstVCall ConstVCall;
+ if (ParseConstVCall(ConstVCall, IdToIndexMap, ConstVCallList.size()))
+ return true;
+ ConstVCallList.push_back(ConstVCall);
+ } while (EatIfPresent(lltok::comma));
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ // Now that the ConstVCallList vector is finalized, it is safe to save the
+ // locations of any forward GV references that need updating later.
+ for (auto I : IdToIndexMap) {
+ for (auto P : I.second) {
+ assert(ConstVCallList[P.first].VFunc.GUID == 0 &&
+ "Forward referenced type id GUID expected to be 0");
+ auto FwdRef = ForwardRefTypeIds.insert(std::make_pair(
+ I.first, std::vector<std::pair<GlobalValue::GUID *, LocTy>>()));
+ FwdRef.first->second.push_back(
+ std::make_pair(&ConstVCallList[P.first].VFunc.GUID, P.second));
+ }
+ }
+
+ return false;
+}
+
+/// ConstVCall
+/// ::= VFuncId, Args
+bool LLParser::ParseConstVCall(FunctionSummary::ConstVCall &ConstVCall,
+ IdToIndexMapType &IdToIndexMap, unsigned Index) {
+ if (ParseVFuncId(ConstVCall.VFunc, IdToIndexMap, Index) ||
+ ParseToken(lltok::comma, "expected ',' here") ||
+ ParseArgs(ConstVCall.Args))
+ return true;
+
+ return false;
+}
+
+/// VFuncId
+/// ::= 'vFuncId' ':' '(' (SummaryID | 'guid' ':' UInt64) ','
+/// 'offset' ':' UInt64 ')'
+bool LLParser::ParseVFuncId(FunctionSummary::VFuncId &VFuncId,
+ IdToIndexMapType &IdToIndexMap, unsigned Index) {
+ assert(Lex.getKind() == lltok::kw_vFuncId);
+ Lex.Lex();
+
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here"))
+ return true;
+
+ if (Lex.getKind() == lltok::SummaryID) {
+ VFuncId.GUID = 0;
+ unsigned ID = Lex.getUIntVal();
+ LocTy Loc = Lex.getLoc();
+ // Keep track of the array index needing a forward reference.
+ // We will save the location of the GUID needing an update, but
+ // can only do so once the caller's std::vector is finalized.
+ IdToIndexMap[ID].push_back(std::make_pair(Index, Loc));
+ Lex.Lex();
+ } else if (ParseToken(lltok::kw_guid, "expected 'guid' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseUInt64(VFuncId.GUID))
+ return true;
+
+ if (ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_offset, "expected 'offset' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseUInt64(VFuncId.Offset) ||
+ ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// GVFlags
+/// ::= 'flags' ':' '(' 'linkage' ':' OptionalLinkageAux ','
+/// 'notEligibleToImport' ':' Flag ',' 'live' ':' Flag ','
+/// 'dsoLocal' ':' Flag ')'
+bool LLParser::ParseGVFlags(GlobalValueSummary::GVFlags &GVFlags) {
+ assert(Lex.getKind() == lltok::kw_flags);
+ Lex.Lex();
+
+ bool HasLinkage;
+ if (ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::lparen, "expected '(' here") ||
+ ParseToken(lltok::kw_linkage, "expected 'linkage' here") ||
+ ParseToken(lltok::colon, "expected ':' here"))
+ return true;
+
+ GVFlags.Linkage = parseOptionalLinkageAux(Lex.getKind(), HasLinkage);
+ assert(HasLinkage && "Linkage not optional in summary entry");
+ Lex.Lex();
+
+ unsigned Flag;
+ if (ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_notEligibleToImport,
+ "expected 'notEligibleToImport' here") ||
+ ParseToken(lltok::colon, "expected ':' here") || ParseFlag(Flag))
+ return true;
+ GVFlags.NotEligibleToImport = Flag;
+
+ if (ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_live, "expected 'live' here") ||
+ ParseToken(lltok::colon, "expected ':' here") || ParseFlag(Flag))
+ return true;
+ GVFlags.Live = Flag;
+
+ if (ParseToken(lltok::comma, "expected ',' here") ||
+ ParseToken(lltok::kw_dsoLocal, "expected 'dsoLocal' here") ||
+ ParseToken(lltok::colon, "expected ':' here") || ParseFlag(Flag))
+ return true;
+ GVFlags.DSOLocal = Flag;
+
+ if (ParseToken(lltok::rparen, "expected ')' here"))
+ return true;
+
+ return false;
+}
+
+/// ModuleReference
+/// ::= 'module' ':' UInt
+bool LLParser::ParseModuleReference(StringRef &ModulePath) {
+ // Parse module id.
+ if (ParseToken(lltok::kw_module, "expected 'module' here") ||
+ ParseToken(lltok::colon, "expected ':' here") ||
+ ParseToken(lltok::SummaryID, "expected module ID"))
+ return true;
+
+ unsigned ModuleID = Lex.getUIntVal();
+ auto I = ModuleIdMap.find(ModuleID);
+ // We should have already parsed all module IDs
+ assert(I != ModuleIdMap.end());
+ ModulePath = I->second;
+ return false;
+}
+
+/// GVReference
+/// ::= SummaryID
+bool LLParser::ParseGVReference(ValueInfo &VI, unsigned &GVId) {
+ if (ParseToken(lltok::SummaryID, "expected GV ID"))
+ return true;
+
+ GVId = Lex.getUIntVal();
+
+ // Check if we already have a VI for this GV
+ if (GVId < NumberedValueInfos.size()) {
+ assert(NumberedValueInfos[GVId] != EmptyVI);
+ VI = NumberedValueInfos[GVId];
+ } else
+ // We will create a forward reference to the stored location.
+ VI = EmptyVI;
+
+ return false;
+}
Modified: llvm/trunk/lib/AsmParser/LLParser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.h?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.h (original)
+++ llvm/trunk/lib/AsmParser/LLParser.h Tue Jun 26 06:56:49 2018
@@ -20,6 +20,7 @@
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/ValueHandle.h"
@@ -90,7 +91,10 @@ namespace llvm {
private:
LLVMContext &Context;
LLLexer Lex;
+ // Module being parsed, null if we are only parsing summary index.
Module *M;
+ // Summary index being parsed, null if we are only parsing Module.
+ ModuleSummaryIndex *Index;
SlotMapping *Slots;
// Instruction metadata resolution. Each instruction can have a list of
@@ -139,6 +143,20 @@ namespace llvm {
std::map<Value*, std::vector<unsigned> > ForwardRefAttrGroups;
std::map<unsigned, AttrBuilder> NumberedAttrBuilders;
+ // Summary global value reference information.
+ std::map<unsigned, std::vector<std::pair<ValueInfo *, LocTy>>>
+ ForwardRefValueInfos;
+ std::map<unsigned, std::vector<std::pair<AliasSummary *, LocTy>>>
+ ForwardRefAliasees;
+ std::vector<ValueInfo> NumberedValueInfos;
+
+ // Summary type id reference information.
+ std::map<unsigned, std::vector<std::pair<GlobalValue::GUID *, LocTy>>>
+ ForwardRefTypeIds;
+
+ // Map of module ID to path.
+ std::map<unsigned, StringRef> ModuleIdMap;
+
/// Only the llvm-as tool may set this to false to bypass
/// UpgradeDebuginfo so it can generate broken bitcode.
bool UpgradeDebugInfo;
@@ -146,11 +164,14 @@ namespace llvm {
/// DataLayout string to override that in LLVM assembly.
StringRef DataLayoutStr;
+ std::string SourceFileName;
+
public:
LLParser(StringRef F, SourceMgr &SM, SMDiagnostic &Err, Module *M,
+ ModuleSummaryIndex *Index, LLVMContext &Context,
SlotMapping *Slots = nullptr, bool UpgradeDebugInfo = true,
StringRef DataLayoutString = "")
- : Context(M->getContext()), Lex(F, SM, Err, M->getContext()), M(M),
+ : Context(Context), Lex(F, SM, Err, Context), M(M), Index(Index),
Slots(Slots), BlockAddressPFS(nullptr),
UpgradeDebugInfo(UpgradeDebugInfo), DataLayoutStr(DataLayoutString) {
if (!DataLayoutStr.empty())
@@ -239,6 +260,7 @@ namespace llvm {
Loc = Lex.getLoc();
return ParseUInt64(Val);
}
+ bool ParseFlag(unsigned &Val);
bool ParseStringAttribute(AttrBuilder &B);
@@ -281,6 +303,7 @@ namespace llvm {
// Top-Level Entities
bool ParseTopLevelEntities();
bool ValidateEndOfModule();
+ bool ValidateEndOfIndex();
bool ParseTargetDefinition();
bool ParseModuleAsm();
bool ParseSourceFileName();
@@ -312,8 +335,48 @@ namespace llvm {
bool ParseFnAttributeValuePairs(AttrBuilder &B,
std::vector<unsigned> &FwdRefAttrGrps,
bool inAttrGrp, LocTy &BuiltinLoc);
+
+ // Module Summary Index Parsing.
bool SkipModuleSummaryEntry();
bool ParseSummaryEntry();
+ bool ParseModuleEntry(unsigned ID);
+ bool ParseModuleReference(StringRef &ModulePath);
+ bool ParseGVReference(ValueInfo &VI, unsigned &GVId);
+ bool ParseGVEntry(unsigned ID);
+ bool ParseFunctionSummary(std::string Name, GlobalValue::GUID, unsigned ID);
+ bool ParseVariableSummary(std::string Name, GlobalValue::GUID, unsigned ID);
+ bool ParseAliasSummary(std::string Name, GlobalValue::GUID, unsigned ID);
+ bool ParseGVFlags(GlobalValueSummary::GVFlags &GVFlags);
+ bool ParseOptionalFFlags(FunctionSummary::FFlags &FFlags);
+ bool ParseOptionalCalls(std::vector<FunctionSummary::EdgeTy> &Calls);
+ bool ParseHotness(CalleeInfo::HotnessType &Hotness);
+ bool ParseOptionalTypeIdInfo(FunctionSummary::TypeIdInfo &TypeIdInfo);
+ bool ParseTypeTests(std::vector<GlobalValue::GUID> &TypeTests);
+ bool ParseVFuncIdList(lltok::Kind Kind,
+ std::vector<FunctionSummary::VFuncId> &VFuncIdList);
+ bool ParseConstVCallList(
+ lltok::Kind Kind,
+ std::vector<FunctionSummary::ConstVCall> &ConstVCallList);
+ using IdToIndexMapType =
+ std::map<unsigned, std::vector<std::pair<unsigned, LocTy>>>;
+ bool ParseConstVCall(FunctionSummary::ConstVCall &ConstVCall,
+ IdToIndexMapType &IdToIndexMap, unsigned Index);
+ bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId,
+ IdToIndexMapType &IdToIndexMap, unsigned Index);
+ bool ParseOptionalRefs(std::vector<ValueInfo> &Refs);
+ bool ParseTypeIdEntry(unsigned ID);
+ bool ParseTypeIdSummary(TypeIdSummary &TIS);
+ bool ParseTypeTestResolution(TypeTestResolution &TTRes);
+ bool ParseOptionalWpdResolutions(
+ std::map<uint64_t, WholeProgramDevirtResolution> &WPDResMap);
+ bool ParseWpdRes(WholeProgramDevirtResolution &WPDRes);
+ bool ParseOptionalResByArg(
+ std::map<std::vector<uint64_t>, WholeProgramDevirtResolution::ByArg>
+ &ResByArg);
+ bool ParseArgs(std::vector<uint64_t> &Args);
+ void AddGlobalValueToIndex(std::string Name, GlobalValue::GUID,
+ GlobalValue::LinkageTypes Linkage, unsigned ID,
+ std::unique_ptr<GlobalValueSummary> Summary);
// Type Parsing.
bool ParseType(Type *&Result, const Twine &Msg, bool AllowVoid = false);
Modified: llvm/trunk/lib/AsmParser/LLToken.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLToken.h (original)
+++ llvm/trunk/lib/AsmParser/LLToken.h Tue Jun 26 06:56:49 2018
@@ -36,6 +36,7 @@ enum Kind {
rparen, // ( )
exclaim, // !
bar, // |
+ colon, // :
kw_x,
kw_true,
@@ -347,6 +348,73 @@ enum Kind {
kw_uselistorder,
kw_uselistorder_bb,
+ // Summary index keywords
+ kw_path,
+ kw_hash,
+ kw_gv,
+ kw_guid,
+ kw_name,
+ kw_summaries,
+ kw_flags,
+ kw_linkage,
+ kw_notEligibleToImport,
+ kw_live,
+ kw_dsoLocal,
+ kw_function,
+ kw_insts,
+ kw_funcFlags,
+ kw_readNone,
+ kw_readOnly,
+ kw_noRecurse,
+ kw_returnDoesNotAlias,
+ kw_calls,
+ kw_callee,
+ kw_hotness,
+ kw_unknown,
+ kw_hot,
+ kw_critical,
+ kw_relbf,
+ kw_variable,
+ kw_aliasee,
+ kw_refs,
+ kw_typeIdInfo,
+ kw_typeTests,
+ kw_typeTestAssumeVCalls,
+ kw_typeCheckedLoadVCalls,
+ kw_typeTestAssumeConstVCalls,
+ kw_typeCheckedLoadConstVCalls,
+ kw_vFuncId,
+ kw_offset,
+ kw_args,
+ kw_typeid,
+ kw_summary,
+ kw_typeTestRes,
+ kw_kind,
+ kw_unsat,
+ kw_byteArray,
+ kw_inline,
+ kw_single,
+ kw_allOnes,
+ kw_sizeM1BitWidth,
+ kw_alignLog2,
+ kw_sizeM1,
+ kw_bitMask,
+ kw_inlineBits,
+ kw_wpdResolutions,
+ kw_wpdRes,
+ kw_indir,
+ kw_singleImpl,
+ kw_branchFunnel,
+ kw_singleImplName,
+ kw_resByArg,
+ kw_byArg,
+ kw_uniformRetVal,
+ kw_uniqueRetVal,
+ kw_virtualConstProp,
+ kw_info,
+ kw_byte,
+ kw_bit,
+
// Unsigned Valued tokens (UIntVal).
GlobalID, // @42
LocalVarID, // %42
Modified: llvm/trunk/lib/AsmParser/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/Parser.cpp?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/Parser.cpp (original)
+++ llvm/trunk/lib/AsmParser/Parser.cpp Tue Jun 26 06:56:49 2018
@@ -15,6 +15,7 @@
#include "LLParser.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
@@ -22,14 +23,17 @@
#include <system_error>
using namespace llvm;
-bool llvm::parseAssemblyInto(MemoryBufferRef F, Module &M, SMDiagnostic &Err,
+bool llvm::parseAssemblyInto(MemoryBufferRef F, Module *M,
+ ModuleSummaryIndex *Index, SMDiagnostic &Err,
SlotMapping *Slots, bool UpgradeDebugInfo,
StringRef DataLayoutString) {
SourceMgr SM;
std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F);
SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
- return LLParser(F.getBuffer(), SM, Err, &M, Slots, UpgradeDebugInfo,
+ LLVMContext Context;
+ return LLParser(F.getBuffer(), SM, Err, M, Index,
+ M ? M->getContext() : Context, Slots, UpgradeDebugInfo,
DataLayoutString)
.Run();
}
@@ -41,7 +45,8 @@ llvm::parseAssembly(MemoryBufferRef F, S
std::unique_ptr<Module> M =
make_unique<Module>(F.getBufferIdentifier(), Context);
- if (parseAssemblyInto(F, *M, Err, Slots, UpgradeDebugInfo, DataLayoutString))
+ if (parseAssemblyInto(F, M.get(), nullptr, Err, Slots, UpgradeDebugInfo,
+ DataLayoutString))
return nullptr;
return M;
@@ -63,6 +68,37 @@ llvm::parseAssemblyFile(StringRef Filena
UpgradeDebugInfo, DataLayoutString);
}
+ParsedModuleAndIndex llvm::parseAssemblyWithIndex(
+ MemoryBufferRef F, SMDiagnostic &Err, LLVMContext &Context,
+ SlotMapping *Slots, bool UpgradeDebugInfo, StringRef DataLayoutString) {
+ std::unique_ptr<Module> M =
+ make_unique<Module>(F.getBufferIdentifier(), Context);
+ std::unique_ptr<ModuleSummaryIndex> Index =
+ make_unique<ModuleSummaryIndex>(/*HaveGVs=*/true);
+
+ if (parseAssemblyInto(F, M.get(), Index.get(), Err, Slots, UpgradeDebugInfo,
+ DataLayoutString))
+ return {nullptr, nullptr};
+
+ return {std::move(M), std::move(Index)};
+}
+
+ParsedModuleAndIndex llvm::parseAssemblyFileWithIndex(
+ StringRef Filename, SMDiagnostic &Err, LLVMContext &Context,
+ SlotMapping *Slots, bool UpgradeDebugInfo, StringRef DataLayoutString) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ if (std::error_code EC = FileOrErr.getError()) {
+ Err = SMDiagnostic(Filename, SourceMgr::DK_Error,
+ "Could not open input file: " + EC.message());
+ return {nullptr, nullptr};
+ }
+
+ return parseAssemblyWithIndex(FileOrErr.get()->getMemBufferRef(), Err,
+ Context, Slots, UpgradeDebugInfo,
+ DataLayoutString);
+}
+
std::unique_ptr<Module>
llvm::parseAssemblyString(StringRef AsmString, SMDiagnostic &Err,
LLVMContext &Context, SlotMapping *Slots,
@@ -72,13 +108,50 @@ llvm::parseAssemblyString(StringRef AsmS
DataLayoutString);
}
+static bool parseSummaryIndexAssemblyInto(MemoryBufferRef F,
+ ModuleSummaryIndex &Index,
+ SMDiagnostic &Err) {
+ SourceMgr SM;
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(F);
+ SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
+
+ // The parser holds a reference to a context that is unused when parsing the
+ // index, but we need to initialize it.
+ LLVMContext unusedContext;
+ return LLParser(F.getBuffer(), SM, Err, nullptr, &Index, unusedContext).Run();
+}
+
+std::unique_ptr<ModuleSummaryIndex>
+llvm::parseSummaryIndexAssembly(MemoryBufferRef F, SMDiagnostic &Err) {
+ std::unique_ptr<ModuleSummaryIndex> Index =
+ make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false);
+
+ if (parseSummaryIndexAssemblyInto(F, *Index, Err))
+ return nullptr;
+
+ return Index;
+}
+
+std::unique_ptr<ModuleSummaryIndex>
+llvm::parseSummaryIndexAssemblyFile(StringRef Filename, SMDiagnostic &Err) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ if (std::error_code EC = FileOrErr.getError()) {
+ Err = SMDiagnostic(Filename, SourceMgr::DK_Error,
+ "Could not open input file: " + EC.message());
+ return nullptr;
+ }
+
+ return parseSummaryIndexAssembly(FileOrErr.get()->getMemBufferRef(), Err);
+}
+
Constant *llvm::parseConstantValue(StringRef Asm, SMDiagnostic &Err,
const Module &M, const SlotMapping *Slots) {
SourceMgr SM;
std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm);
SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
Constant *C;
- if (LLParser(Asm, SM, Err, const_cast<Module *>(&M))
+ if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext())
.parseStandaloneConstantValue(C, Slots))
return nullptr;
return C;
@@ -107,7 +180,7 @@ Type *llvm::parseTypeAtBeginning(StringR
std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Asm);
SM.AddNewSourceBuffer(std::move(Buf), SMLoc());
Type *Ty;
- if (LLParser(Asm, SM, Err, const_cast<Module *>(&M))
+ if (LLParser(Asm, SM, Err, const_cast<Module *>(&M), nullptr, M.getContext())
.parseTypeAtBeginning(Ty, Read, Slots))
return nullptr;
return Ty;
Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Tue Jun 26 06:56:49 2018
@@ -197,7 +197,7 @@ public:
// otherwise we would have a Value for it). If so, synthesize
// a value id.
for (auto &CallEdge : FS->calls())
- if (!CallEdge.first.getValue())
+ if (!CallEdge.first.haveGVs() || !CallEdge.first.getValue())
assignValueId(CallEdge.first.getGUID());
}
@@ -230,7 +230,7 @@ private:
// Helper to get the valueId for the type of value recorded in VI.
unsigned getValueId(ValueInfo VI) {
- if (!VI.getValue())
+ if (!VI.haveGVs() || !VI.getValue())
return getValueId(VI.getGUID());
return VE.getValueID(VI.getValue());
}
Modified: llvm/trunk/test/Assembler/thinlto-bad-summary1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/thinlto-bad-summary1.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Assembler/thinlto-bad-summary1.ll (original)
+++ llvm/trunk/test/Assembler/thinlto-bad-summary1.ll Tue Jun 26 06:56:49 2018
@@ -1,8 +1,8 @@
; Test that we get appropriate error when parsing summary with a missing
; summary type label.
-; RUN: not llvm-as %s 2>&1 | FileCheck %s
+; RUN: not opt %s 2>&1 | FileCheck %s
-; CHECK: error: expected 'label' at start of summary entry
+; CHECK: error: Expected 'gv', 'module', or 'typeid' at the start of summary entry
; ModuleID = 'thinlto-function-summary-callgraph.ll'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
Modified: llvm/trunk/test/Assembler/thinlto-bad-summary2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/thinlto-bad-summary2.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Assembler/thinlto-bad-summary2.ll (original)
+++ llvm/trunk/test/Assembler/thinlto-bad-summary2.ll Tue Jun 26 06:56:49 2018
@@ -1,6 +1,6 @@
; Test that we get appropriate error when parsing summary that doesn't
; have a '(' after the summary type label.
-; RUN: not llvm-as %s 2>&1 | FileCheck %s
+; RUN: not opt %s 2>&1 | FileCheck %s
; CHECK: error: expected '(' at start of summary entry
Modified: llvm/trunk/test/Assembler/thinlto-bad-summary3.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/thinlto-bad-summary3.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Assembler/thinlto-bad-summary3.ll (original)
+++ llvm/trunk/test/Assembler/thinlto-bad-summary3.ll Tue Jun 26 06:56:49 2018
@@ -1,6 +1,6 @@
; Test that we get appropriate error when parsing summary with unbalanced
; parentheses.
-; RUN: not llvm-as %s 2>&1 | FileCheck %s
+; RUN: not opt %s 2>&1 | FileCheck %s
; CHECK: error: found end of file while parsing summary entry
Added: llvm/trunk/test/Assembler/thinlto-summary.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/thinlto-summary.ll?rev=335602&view=auto
==============================================================================
--- llvm/trunk/test/Assembler/thinlto-summary.ll (added)
+++ llvm/trunk/test/Assembler/thinlto-summary.ll Tue Jun 26 06:56:49 2018
@@ -0,0 +1,96 @@
+; Test summary parsing (tests all types/fields in various combinations).
+; RUN: llvm-as %s -o - | llvm-dis -o - | FileCheck %s
+
+; ModuleID = 'thinlto-summary.thinlto.bc'
+
+^0 = module: (path: "thinlto-summary1.o", hash: (1369602428, 2747878711, 259090915, 2507395659, 1141468049))
+^1 = module: (path: "thinlto-summary2.o", hash: (2998369023, 4283347029, 1195487472, 2757298015, 1852134156))
+
+; Check a function that makes several calls with various profile hotness, and a
+; reference (also tests forward references to function and variables in calls
+; and refs).
+^2 = gv: (guid: 1, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 10, calls: ((callee: ^15, hotness: hot), (callee: ^17, hotness: cold), (callee: ^16, hotness: none)), refs: (^13))))
+
+; Function with a call that has relative block frequency instead of profile
+; hotness.
+^3 = gv: (guid: 2, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 10, calls: ((callee: ^15, relbf: 256)))))
+
+; Summaries with different linkage types.
+^4 = gv: (guid: 3, summaries: (function: (module: ^0, flags: (linkage: internal, notEligibleToImport: 0, live: 0, dsoLocal: 1), insts: 1)))
+; Make this one an alias with a forward reference to aliasee.
+^5 = gv: (guid: 4, summaries: (alias: (module: ^0, flags: (linkage: private, notEligibleToImport: 0, live: 0, dsoLocal: 1), aliasee: ^14)))
+^6 = gv: (guid: 5, summaries: (function: (module: ^0, flags: (linkage: available_externally, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+^7 = gv: (guid: 6, summaries: (function: (module: ^0, flags: (linkage: linkonce, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+^8 = gv: (guid: 7, summaries: (function: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+^9 = gv: (guid: 8, summaries: (function: (module: ^0, flags: (linkage: weak_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+^10 = gv: (guid: 9, summaries: (function: (module: ^0, flags: (linkage: weak, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0))))
+; Test appending globel variable with reference (tests backward reference on
+; refs).
+^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0), refs: (^4))))
+
+; Test a referenced global variable.
+^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0))))
+
+; Test a dsoLocal variable.
+^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1))))
+
+; Functions with various flag combinations (notEligibleToImport, Live,
+; combinations of optional function flags).
+^15 = gv: (guid: 14, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 1, live: 1, dsoLocal: 0), insts: 1)))
+^16 = gv: (guid: 15, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1, funcFlags: (readNone: 1, noRecurse: 1))))
+; This one also tests backwards reference in calls.
+^17 = gv: (guid: 16, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1, funcFlags: (readOnly: 1, returnDoesNotAlias: 1), calls: ((callee: ^15)))))
+
+; Alias summary with backwards reference to aliasee.
+^18 = gv: (guid: 17, summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), aliasee: ^14)))
+
+; Test all types of TypeIdInfo on function summaries.
+^19 = gv: (guid: 18, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 4, typeIdInfo: (typeTests: (^24, ^26)))))
+^20 = gv: (guid: 19, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 8, typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (^27, offset: 16))))))
+^21 = gv: (guid: 20, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (^25, offset: 16))))))
+^22 = gv: (guid: 21, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 15, typeIdInfo: (typeTestAssumeConstVCalls: (vFuncId: (^27, offset: 16), args: (42), vFuncId: (^27, offset: 24), args: (43))))))
+^23 = gv: (guid: 22, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadConstVCalls: (vFuncId: (^27, offset: 16), args: (42))))))
+
+; Test TypeId summaries:
+
+; Test the AllOnes resolution, and all kinds of WholeProgramDevirtResolution
+; types, including all optional resolution by argument kinds.
+^24 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: allOnes, sizeM1BitWidth: 7), wpdResolutions: ((offset: 0, wpdRes: (kind: branchFunnel)), (offset: 8, wpdRes: (kind: singleImpl, singleImplName: "_ZN1A1nEi")), (offset: 16, wpdRes: (kind: indir, resByArg: (args: (1, 2), byArg: (kind: indir, byte: 2, bit: 3), args: (3), byArg: (kind: uniformRetVal, info: 1), args: (4), byArg: (kind: uniqueRetVal, info: 1), args: (5), byArg: (kind: virtualConstProp)))))))
+; Test TypeId with other optional fields (alignLog2/sizeM1/bitMask/inlineBits)
+^25 = typeid: (name: "_ZTS1B", summary: (typeTestRes: (kind: inline, sizeM1BitWidth: 0, alignLog2: 1, sizeM1: 2, bitMask: 3, inlineBits: 4)))
+; Test the other kinds of type test resoultions
+^26 = typeid: (name: "_ZTS1C", summary: (typeTestRes: (kind: single, sizeM1BitWidth: 0)))
+^27 = typeid: (name: "_ZTS1D", summary: (typeTestRes: (kind: byteArray, sizeM1BitWidth: 0)))
+^28 = typeid: (name: "_ZTS1E", summary: (typeTestRes: (kind: unsat, sizeM1BitWidth: 0)))
+
+; Make sure we get back from llvm-dis essentially what we put in via llvm-as.
+; CHECK: ^0 = module: (path: "thinlto-summary1.o", hash: (1369602428, 2747878711, 259090915, 2507395659, 1141468049))
+; CHECK: ^1 = module: (path: "thinlto-summary2.o", hash: (2998369023, 4283347029, 1195487472, 2757298015, 1852134156))
+; CHECK: ^2 = gv: (guid: 1, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 10, calls: ((callee: ^15, hotness: hot), (callee: ^17, hotness: cold), (callee: ^16, hotness: none)), refs: (^13))))
+; CHECK: ^3 = gv: (guid: 2, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 10, calls: ((callee: ^15)))))
+; CHECK: ^4 = gv: (guid: 3, summaries: (function: (module: ^0, flags: (linkage: internal, notEligibleToImport: 0, live: 0, dsoLocal: 1), insts: 1)))
+; CHECK: ^5 = gv: (guid: 4, summaries: (alias: (module: ^0, flags: (linkage: private, notEligibleToImport: 0, live: 0, dsoLocal: 1), aliasee: ^14)))
+; CHECK: ^6 = gv: (guid: 5, summaries: (function: (module: ^0, flags: (linkage: available_externally, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+; CHECK: ^7 = gv: (guid: 6, summaries: (function: (module: ^0, flags: (linkage: linkonce, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+; CHECK: ^8 = gv: (guid: 7, summaries: (function: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+; CHECK: ^9 = gv: (guid: 8, summaries: (function: (module: ^0, flags: (linkage: weak_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+; CHECK: ^10 = gv: (guid: 9, summaries: (function: (module: ^0, flags: (linkage: weak, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1)))
+; CHECK: ^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0))))
+; CHECK: ^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0), refs: (^4))))
+; CHECK: ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0))))
+; CHECK: ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1))))
+; CHECK: ^15 = gv: (guid: 14, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 1, live: 1, dsoLocal: 0), insts: 1)))
+; CHECK: ^16 = gv: (guid: 15, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1, funcFlags: (readNone: 1, readOnly: 0, noRecurse: 1, returnDoesNotAlias: 0))))
+; CHECK: ^17 = gv: (guid: 16, summaries: (function: (module: ^1, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1, funcFlags: (readNone: 0, readOnly: 1, noRecurse: 0, returnDoesNotAlias: 1), calls: ((callee: ^15)))))
+; CHECK: ^18 = gv: (guid: 17, summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), aliasee: ^14)))
+; CHECK: ^19 = gv: (guid: 18, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 4, typeIdInfo: (typeTests: (^24, ^26)))))
+; CHECK: ^20 = gv: (guid: 19, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 8, typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (^27, offset: 16))))))
+; CHECK: ^21 = gv: (guid: 20, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (^25, offset: 16))))))
+; CHECK: ^22 = gv: (guid: 21, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 15, typeIdInfo: (typeTestAssumeConstVCalls: (vFuncId: (^27, offset: 16), args: (42), vFuncId: (^27, offset: 24), args: (43))))))
+; CHECK: ^23 = gv: (guid: 22, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadConstVCalls: (vFuncId: (^27, offset: 16), args: (42))))))
+; CHECK: ^24 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: allOnes, sizeM1BitWidth: 7), wpdResolutions: ((offset: 0, wpdRes: (kind: branchFunnel)), (offset: 8, wpdRes: (kind: singleImpl, singleImplName: "_ZN1A1nEi")), (offset: 16, wpdRes: (kind: indir, resByArg: (args: (1, 2), byArg: (kind: indir, byte: 2, bit: 3), args: (3), byArg: (kind: uniformRetVal, info: 1), args: (4), byArg: (kind: uniqueRetVal, info: 1), args: (5), byArg: (kind: virtualConstProp))))))) ; guid = 7004155349499253778
+; CHECK: ^25 = typeid: (name: "_ZTS1B", summary: (typeTestRes: (kind: inline, sizeM1BitWidth: 0, alignLog2: 1, sizeM1: 2, bitMask: 3, inlineBits: 4))) ; guid = 6203814149063363976
+; CHECK: ^26 = typeid: (name: "_ZTS1C", summary: (typeTestRes: (kind: single, sizeM1BitWidth: 0))) ; guid = 1884921850105019584
+; CHECK: ^27 = typeid: (name: "_ZTS1D", summary: (typeTestRes: (kind: byteArray, sizeM1BitWidth: 0))) ; guid = 9614786172484273522
+; CHECK: ^28 = typeid: (name: "_ZTS1E", summary: (typeTestRes: (kind: unsat, sizeM1BitWidth: 0))) ; guid = 17437243864166745132
Modified: llvm/trunk/test/Bitcode/thinlto-alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-alias.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-alias.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-alias.ll Tue Jun 26 06:56:49 2018
@@ -3,9 +3,13 @@
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
; RUN: opt -module-summary %p/Inputs/thinlto-alias.ll -o %t2.o
; RUN: llvm-dis -o - %t2.o | FileCheck %s --check-prefix=DIS
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t2.o | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
; RUN: llvm-dis -o - %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED-DIS
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t3.thinlto.bc | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=COMBINED-DIS
; CHECK: <SOURCE_FILENAME
; "main"
@@ -47,7 +51,7 @@ entry:
declare void @analias(...)
-; DIS: ^0 = module: (path: "{{.*}}thinlto-alias.ll.tmp2.o", hash: (0, 0, 0, 0, 0))
+; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0))
; DIS: ^1 = gv: (name: "analias", summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), aliasee: ^2))) ; guid = 12695095382722328222
; DIS: ^2 = gv: (name: "aliasee", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 1))) ; guid = 17407585008595848568
Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll Tue Jun 26 06:56:49 2018
@@ -6,17 +6,23 @@
; Make sure the assembler doesn't error when parsing the summary
; RUN: llvm-as %t.o.ll
-; RUN: ls %t.o.bc
+
+; Check assembled summary.
+; RUN: llvm-dis %t.o.bc -o - | FileCheck %s --check-prefix=DIS
; RUN: opt -module-summary %p/Inputs/thinlto-function-summary-callgraph-profile-summary.ll -o %t2.o
; RUN: llvm-lto -thinlto -o %t3 %t.o %t2.o
; RUN: llvm-bcanalyzer -dump %t3.thinlto.bc | FileCheck %s --check-prefix=COMBINED
; RUN: llvm-dis %t3.thinlto.bc
; RUN: cat %t3.thinlto.ll | FileCheck %s --check-prefix=COMBINED-DIS
+; Round trip it through llvm-as
+; RUN: cat %t3.thinlto.ll | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=COMBINED-DIS
; Make sure the assembler doesn't error when parsing the combined summary
; RUN: llvm-as %t3.thinlto.ll -o %t3.thinlto.o
-; RUN: ls %t3.thinlto.o
+
+; Check assembled combined summary.
+; RUN: llvm-dis %t3.thinlto.o -o - | FileCheck %s --check-prefix=COMBINED-DIS
; CHECK: <SOURCE_FILENAME
@@ -134,7 +140,7 @@ declare void @none3() #1
!14 = !{i32 999999, i64 1, i32 2}
!15 = !{!"branch_weights", i32 100}
-; DIS: ^0 = module: (path: "{{.*}}thinlto-function-summary-callgraph-profile-summary.ll.tmp.o", hash: (0, 0, 0, 0, 0))
+; DIS: ^0 = module: (path: "{{.*}}thinlto-function-summary-callgraph-profile-summary.ll.tmp.o{{.*}}", hash: (0, 0, 0, 0, 0))
; DIS: ^1 = gv: (guid: 123)
; DIS: ^2 = gv: (name: "none2") ; guid = 3741006263754194003
; DIS: ^3 = gv: (name: "hot3") ; guid = 5026609803865204483
Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll Tue Jun 26 06:56:49 2018
@@ -2,7 +2,8 @@
; RUN: opt -write-relbf-to-summary -module-summary %s -o %t.o
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
; RUN: llvm-dis -o - %t.o | FileCheck %s --check-prefix=DIS
-
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t.o | llvm-as -write-relbf-to-summary -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
; CHECK: <SOURCE_FILENAME
; CHECK-NEXT: <GLOBALVAR
@@ -35,7 +36,7 @@ declare void @func(...) #1
; OLD: Index {{.*}} contains 1 nodes (1 functions, 0 alias, 0 globals) and 1 edges (0 refs and 1 calls)
-; DIS: ^0 = module: (path: "{{.*}}thinlto-function-summary-callgraph-relbf.ll.tmp.o", hash: (0, 0, 0, 0, 0))
+; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0))
; DIS: ^1 = gv: (name: "func") ; guid = 7289175272376759421
; DIS: ^2 = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 3, calls: ((callee: ^1, relbf: 256)), refs: (^3)))) ; guid = 15822663052811949562
; DIS: ^3 = gv: (name: "undefinedglob") ; guid = 18036901804029949403
Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll Tue Jun 26 06:56:49 2018
@@ -2,6 +2,8 @@
; RUN: opt -module-summary %s -o %t.o
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
; RUN: llvm-dis -o - %t.o | FileCheck %s --check-prefix=DIS
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t.o | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
; CHECK: <SOURCE_FILENAME
; "bar"
@@ -145,7 +147,7 @@ entry:
; Don't try to match summary IDs. The numbering depends on the map iteration
; order, which depends on GUID, and the private function Y GUID will depend
; on the path to the test.
-; DIS: ^0 = module: (path: "{{.*}}thinlto-function-summary-refgraph.ll.tmp.o", hash: (0, 0, 0, 0, 0))
+; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0))
; DIS-DAG: = gv: (name: "Z", summaries: (function: (module: ^0, flags: (linkage: linkonce_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 2, calls: ((callee: ^{{.*}}))))) ; guid = 104084381700047393
; DIS-DAG: = gv: (name: "X", summaries: (function: (module: ^0, flags: (linkage: available_externally, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 2, calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ; guid = 1881667236089500162
; DIS-DAG: = gv: (name: "W", summaries: (function: (module: ^0, flags: (linkage: weak_odr, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 2, calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ; guid = 5790125716599269729
Modified: llvm/trunk/test/Bitcode/thinlto-type-tests.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-type-tests.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-type-tests.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-type-tests.ll Tue Jun 26 06:56:49 2018
@@ -1,9 +1,13 @@
; RUN: opt -module-summary %s -o %t.o
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
; RUN: llvm-dis -o - %t.o | FileCheck %s --check-prefix=DIS
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t.o | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
; RUN: llvm-lto -thinlto -o %t2 %t.o
; RUN: llvm-bcanalyzer -dump %t2.thinlto.bc | FileCheck --check-prefix=COMBINED %s
; RUN: llvm-dis -o - %t2.thinlto.bc | FileCheck %s --check-prefix=COMBINED-DIS
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t2.thinlto.bc | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=COMBINED-DIS
; COMBINED: <TYPE_TESTS op0=-2012135647395072713/>
; COMBINED: <TYPE_TESTS op0=6699318081062747564 op1=-2012135647395072713/>
@@ -31,7 +35,7 @@ define i1 @h() {
declare i1 @llvm.type.test(i8*, metadata) nounwind readnone
-; DIS: ^0 = module: (path: "{{.*}}thinlto-type-tests.ll.tmp.o", hash: (0, 0, 0, 0, 0))
+; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0))
; DIS: ^1 = gv: (name: "llvm.type.test") ; guid = 608142985856744218
; DIS: ^2 = gv: (name: "h", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 2, typeIdInfo: (typeTests: (16434608426314478903))))) ; guid = 8124147457056772133
; DIS: ^3 = gv: (name: "g", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 4, typeIdInfo: (typeTests: (6699318081062747564, 16434608426314478903))))) ; guid = 13146401226427987378
Modified: llvm/trunk/test/Bitcode/thinlto-type-vcalls.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-type-vcalls.ll?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-type-vcalls.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-type-vcalls.ll Tue Jun 26 06:56:49 2018
@@ -1,9 +1,13 @@
; RUN: opt -module-summary %s -o %t.o
; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
; RUN: llvm-dis -o - %t.o | FileCheck %s --check-prefix=DIS
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t.o | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
; RUN: llvm-lto -thinlto -o %t2 %t.o
; RUN: llvm-bcanalyzer -dump %t2.thinlto.bc | FileCheck --check-prefix=COMBINED %s
; RUN: llvm-dis -o - %t2.thinlto.bc | FileCheck %s --check-prefix=COMBINED-DIS
+; Round trip it through llvm-as
+; RUN: llvm-dis -o - %t2.thinlto.bc | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=COMBINED-DIS
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
@@ -106,7 +110,7 @@ declare i1 @llvm.type.test(i8*, metadata
declare void @llvm.assume(i1)
declare {i8*, i1} @llvm.type.checked.load(i8*, i32, metadata)
-; DIS: ^0 = module: (path: "{{.*}}thinlto-type-vcalls.ll.tmp.o", hash: (0, 0, 0, 0, 0))
+; DIS: ^0 = module: (path: "{{.*}}", hash: (0, 0, 0, 0, 0))
; DIS: ^1 = gv: (name: "llvm.type.test") ; guid = 608142985856744218
; DIS: ^2 = gv: (name: "f1", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 8, typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) ; guid = 2072045998141807037
; DIS: ^3 = gv: (name: "f3", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (guid: 6699318081062747564, offset: 16)))))) ; guid = 4197650231481825559
Modified: llvm/trunk/tools/llvm-as/llvm-as.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-as/llvm-as.cpp?rev=335602&r1=335601&r2=335602&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-as/llvm-as.cpp (original)
+++ llvm/trunk/tools/llvm-as/llvm-as.cpp Tue Jun 26 06:56:49 2018
@@ -19,6 +19,7 @@
#include "llvm/Bitcode/BitcodeWriter.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -63,7 +64,7 @@ static cl::opt<std::string> ClDataLayout
cl::value_desc("layout-string"),
cl::init(""));
-static void WriteOutputFile(const Module *M) {
+static void WriteOutputFile(const Module *M, const ModuleSummaryIndex *Index) {
// Infer the output filename if needed.
if (OutputFilename.empty()) {
if (InputFilename == "-") {
@@ -83,9 +84,24 @@ static void WriteOutputFile(const Module
exit(1);
}
- if (Force || !CheckBitcodeOutputToConsole(Out->os(), true))
- WriteBitcodeToFile(*M, Out->os(), PreserveBitcodeUseListOrder, nullptr,
- EmitModuleHash);
+ if (Force || !CheckBitcodeOutputToConsole(Out->os(), true)) {
+ const ModuleSummaryIndex *IndexToWrite = nullptr;
+ // Don't attempt to write a summary index unless it contains any entries.
+ // Otherwise we get an empty summary section.
+ if (Index && Index->begin() != Index->end())
+ IndexToWrite = Index;
+ if (!IndexToWrite || (M && (!M->empty() || !M->global_empty())))
+ // If we have a non-empty Module, then we write the Module plus
+ // any non-null Index along with it as a per-module Index.
+ // If both are empty, this will give an empty module block, which is
+ // the expected behavior.
+ WriteBitcodeToFile(*M, Out->os(), PreserveBitcodeUseListOrder,
+ IndexToWrite, EmitModuleHash);
+ else
+ // Otherwise, with an empty Module but non-empty Index, we write a
+ // combined index.
+ WriteIndexToFile(*IndexToWrite, Out->os());
+ }
// Declare success.
Out->keep();
@@ -98,12 +114,14 @@ int main(int argc, char **argv) {
// Parse the file now...
SMDiagnostic Err;
- std::unique_ptr<Module> M = parseAssemblyFile(
+ auto ModuleAndIndex = parseAssemblyFileWithIndex(
InputFilename, Err, Context, nullptr, !DisableVerify, ClDataLayout);
+ std::unique_ptr<Module> M = std::move(ModuleAndIndex.Mod);
if (!M.get()) {
Err.print(argv[0], errs());
return 1;
}
+ std::unique_ptr<ModuleSummaryIndex> Index = std::move(ModuleAndIndex.Index);
if (!DisableVerify) {
std::string ErrorStr;
@@ -114,13 +132,17 @@ int main(int argc, char **argv) {
errs() << OS.str();
return 1;
}
+ // TODO: Implement and call summary index verifier.
}
- if (DumpAsm)
+ if (DumpAsm) {
errs() << "Here's the assembly:\n" << *M.get();
+ if (Index.get() && Index->begin() != Index->end())
+ Index->print(errs());
+ }
if (!DisableOutput)
- WriteOutputFile(M.get());
+ WriteOutputFile(M.get(), Index.get());
return 0;
}
More information about the llvm-commits
mailing list