diff options
| -rw-r--r-- | llvm/lib/AsmParser/LLLexer.cpp | 1 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 92 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLParser.h | 1 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLToken.h | 1 | ||||
| -rw-r--r-- | llvm/lib/IR/AsmWriter.cpp | 4 | ||||
| -rw-r--r-- | llvm/test/Assembler/thinlto-summary.ll | 20 | ||||
| -rw-r--r-- | llvm/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll | 2 | ||||
| -rw-r--r-- | llvm/test/Bitcode/thinlto-function-summary-refgraph.ll | 4 |
8 files changed, 88 insertions, 37 deletions
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index 4f8ce3ddc7b..045214590d8 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -788,6 +788,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(info); KEYWORD(byte); KEYWORD(bit); + KEYWORD(varFlags); #undef KEYWORD diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index c945a8ea95e..165d01dc8b4 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -7470,8 +7470,14 @@ bool LLParser::ParseArgs(std::vector<uint64_t> &Args) { return false; } -static ValueInfo EmptyVI = - ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8); +auto FwdVIRef = (GlobalValueSummaryMapTy::value_type *)-8; + +static void resolveFwdRef(ValueInfo *Fwd, ValueInfo &Resolved) { + bool ReadOnly = Fwd->isReadOnly(); + *Fwd = Resolved; + if (ReadOnly) + Fwd->setReadOnly(); +} /// Stores the given Name/GUID and associated summary into the Index. /// Also updates any forward references to the associated entry ID. @@ -7507,9 +7513,9 @@ void LLParser::AddGlobalValueToIndex( auto FwdRefVIs = ForwardRefValueInfos.find(ID); if (FwdRefVIs != ForwardRefValueInfos.end()) { for (auto VIRef : FwdRefVIs->second) { - assert(*VIRef.first == EmptyVI && + assert(VIRef.first->getRef() == FwdVIRef && "Forward referenced ValueInfo expected to be empty"); - *VIRef.first = VI; + resolveFwdRef(VIRef.first, VI); } ForwardRefValueInfos.erase(FwdRefVIs); } @@ -7699,11 +7705,14 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID, GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags( /*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false, /*Live=*/false, /*IsLocal=*/false); + GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ 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)) + ParseToken(lltok::comma, "expected ',' here") || ParseGVFlags(GVFlags) || + ParseToken(lltok::comma, "expected ',' here") || + ParseGVarFlags(GVarFlags)) return true; // Parse optional refs field @@ -7715,8 +7724,8 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID, if (ParseToken(lltok::rparen, "expected ')' here")) return true; - auto GS = llvm::make_unique<GlobalVarSummary>( - GVFlags, GlobalVarSummary::GVarFlags(), std::move(Refs)); + auto GS = + llvm::make_unique<GlobalVarSummary>(GVFlags, GVarFlags, std::move(Refs)); GS->setModulePath(ModulePath); @@ -7761,7 +7770,7 @@ bool LLParser::ParseAliasSummary(std::string Name, GlobalValue::GUID GUID, AS->setModulePath(ModulePath); // Record forward reference if the aliasee is not parsed yet. - if (AliaseeVI == EmptyVI) { + if (AliaseeVI.getRef() == FwdVIRef) { 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)); @@ -7883,7 +7892,7 @@ bool LLParser::ParseOptionalCalls(std::vector<FunctionSummary::EdgeTy> &Calls) { // 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) + if (VI.getRef() == FwdVIRef) IdToIndexMap[GVId].push_back(std::make_pair(Calls.size(), Loc)); Calls.push_back(FunctionSummary::EdgeTy{VI, CalleeInfo(Hotness, RelBF)}); @@ -7895,7 +7904,7 @@ bool LLParser::ParseOptionalCalls(std::vector<FunctionSummary::EdgeTy> &Calls) { // of any forward GV references that need updating later. for (auto I : IdToIndexMap) { for (auto P : I.second) { - assert(Calls[P.first].first == EmptyVI && + assert(Calls[P.first].first.getRef() == FwdVIRef && "Forward referenced ValueInfo expected to be empty"); auto FwdRef = ForwardRefValueInfos.insert(std::make_pair( I.first, std::vector<std::pair<ValueInfo *, LocTy>>())); @@ -7946,28 +7955,42 @@ bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) { ParseToken(lltok::lparen, "expected '(' in refs")) return true; - IdToIndexMapType IdToIndexMap; - // Parse each ref edge - do { + struct ValueContext { ValueInfo VI; - LocTy Loc = Lex.getLoc(); unsigned GVId; - if (ParseGVReference(VI, GVId)) + LocTy Loc; + }; + std::vector<ValueContext> VContexts; + // Parse each ref edge + do { + ValueContext VC; + VC.Loc = Lex.getLoc(); + if (ParseGVReference(VC.VI, VC.GVId)) return true; + VContexts.push_back(VC); + } while (EatIfPresent(lltok::comma)); + // Sort value contexts so that ones with readonly ValueInfo are at the end + // of VContexts vector. This is needed to match immutableRefCount() behavior. + llvm::sort(VContexts, [](ValueContext &VC1, ValueContext &VC2) { + return VC1.VI.isReadOnly() < VC2.VI.isReadOnly(); + }); + + IdToIndexMapType IdToIndexMap; + for (auto &VC : VContexts) { // 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)); + if (VC.VI.getRef() == FwdVIRef) + IdToIndexMap[VC.GVId].push_back(std::make_pair(Refs.size(), VC.Loc)); + Refs.push_back(VC.VI); + } // 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 && + assert(Refs[P.first].getRef() == FwdVIRef && "Forward referenced ValueInfo expected to be empty"); auto FwdRef = ForwardRefValueInfos.insert(std::make_pair( I.first, std::vector<std::pair<ValueInfo *, LocTy>>())); @@ -8253,6 +8276,27 @@ bool LLParser::ParseGVFlags(GlobalValueSummary::GVFlags &GVFlags) { return false; } +/// GVarFlags +/// ::= 'varFlags' ':' '(' 'readonly' ':' Flag ')' +bool LLParser::ParseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags) { + assert(Lex.getKind() == lltok::kw_varFlags); + Lex.Lex(); + + unsigned Flag; + if (ParseToken(lltok::colon, "expected ':' here") || + ParseToken(lltok::lparen, "expected '(' here") || + ParseToken(lltok::kw_readonly, "expected 'readonly' here") || + ParseToken(lltok::colon, "expected ':' here")) + return true; + + ParseFlag(Flag); + GVarFlags.ReadOnly = Flag; + + if (ParseToken(lltok::rparen, "expected ')' here")) + return true; + return false; +} + /// ModuleReference /// ::= 'module' ':' UInt bool LLParser::ParseModuleReference(StringRef &ModulePath) { @@ -8273,18 +8317,20 @@ bool LLParser::ParseModuleReference(StringRef &ModulePath) { /// GVReference /// ::= SummaryID bool LLParser::ParseGVReference(ValueInfo &VI, unsigned &GVId) { + bool ReadOnly = EatIfPresent(lltok::kw_readonly); 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); + assert(NumberedValueInfos[GVId].getRef() != FwdVIRef); VI = NumberedValueInfos[GVId]; } else // We will create a forward reference to the stored location. - VI = EmptyVI; + VI = ValueInfo(false, FwdVIRef); + if (ReadOnly) + VI.setReadOnly(); return false; } diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index 6f8962b6d4e..5a0fc297265 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -352,6 +352,7 @@ namespace llvm { bool ParseVariableSummary(std::string Name, GlobalValue::GUID, unsigned ID); bool ParseAliasSummary(std::string Name, GlobalValue::GUID, unsigned ID); bool ParseGVFlags(GlobalValueSummary::GVFlags &GVFlags); + bool ParseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags); bool ParseOptionalFFlags(FunctionSummary::FFlags &FFlags); bool ParseOptionalCalls(std::vector<FunctionSummary::EdgeTy> &Calls); bool ParseHotness(CalleeInfo::HotnessType &Hotness); diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index dae1d41fd8c..836d9a06562 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -418,6 +418,7 @@ enum Kind { kw_info, kw_byte, kw_bit, + kw_varFlags, // Unsigned Valued tokens (UIntVal). GlobalID, // @42 diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 8cfbf6da7fb..b74b158def8 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2821,7 +2821,7 @@ void AssemblyWriter::printAliasSummary(const AliasSummary *AS) { } void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) { - // Nothing for now + Out << ", varFlags: (readonly: " << GS->VarFlags.ReadOnly << ")"; } static std::string getLinkageName(GlobalValue::LinkageTypes LT) { @@ -3015,6 +3015,8 @@ void AssemblyWriter::printSummary(const GlobalValueSummary &Summary) { FieldSeparator FS; for (auto &Ref : RefList) { Out << FS; + if (Ref.isReadOnly()) + Out << "readonly "; Out << "^" << Machine.getGUIDSlot(Ref.getGUID()); } Out << ")"; diff --git a/llvm/test/Assembler/thinlto-summary.ll b/llvm/test/Assembler/thinlto-summary.ll index 64af835ae2b..4d1c0dd74d2 100644 --- a/llvm/test/Assembler/thinlto-summary.ll +++ b/llvm/test/Assembler/thinlto-summary.ll @@ -9,7 +9,7 @@ ; 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)))) +^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: (readonly ^13, ^14)))) ; Function with a call that has relative block frequency instead of profile ; hotness. @@ -24,16 +24,16 @@ ^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)))) +^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 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)))) +^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 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)))) +^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 1)))) ; Test a dsoLocal variable. -^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1)))) +^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), varFlags: (readonly: 0)))) ; Functions with various flag combinations (notEligibleToImport, Live, ; combinations of optional function flags). @@ -67,7 +67,7 @@ ; 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: ^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: (^14, readonly ^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))) @@ -76,10 +76,10 @@ ; 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: ^11 = gv: (guid: 10, summaries: (variable: (module: ^0, flags: (linkage: common, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 0)))) +; CHECK: ^12 = gv: (guid: 11, summaries: (variable: (module: ^0, flags: (linkage: appending, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 0), refs: (^4)))) +; CHECK: ^13 = gv: (guid: 12, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 1)))) +; CHECK: ^14 = gv: (guid: 13, summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), varFlags: (readonly: 0)))) ; 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, noInline: 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, noInline: 0), calls: ((callee: ^15))))) diff --git a/llvm/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll b/llvm/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll index 04f28c95730..6c144652225 100644 --- a/llvm/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll +++ b/llvm/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll @@ -38,5 +38,5 @@ declare void @func(...) #1 ; 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: ^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: (readonly ^3)))) ; guid = 15822663052811949562 ; DIS: ^3 = gv: (name: "undefinedglob") ; guid = 18036901804029949403 diff --git a/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll b/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll index 419becae062..e8a2a770f61 100644 --- a/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll +++ b/llvm/test/Bitcode/thinlto-function-summary-refgraph.ll @@ -154,11 +154,11 @@ entry: ; DIS-DAG: = gv: (name: "foo") ; guid = 6699318081062747564 ; DIS-DAG: = gv: (name: "func") ; guid = 7289175272376759421 ; DIS-DAG: = gv: (name: "func3") ; guid = 11517462787082255043 -; DIS-DAG: = gv: (name: "globalvar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0)))) ; guid = 12887606300320728018 +; DIS-DAG: = gv: (name: "globalvar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 1)))) ; guid = 12887606300320728018 ; DIS-DAG: = gv: (name: "func2") ; guid = 14069196320850861797 ; DIS-DAG: = gv: (name: "llvm.ctpop.i8") ; guid = 15254915475081819833 ; DIS-DAG: = gv: (name: "main", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 9, calls: ((callee: ^{{.*}})), refs: (^{{.*}})))) ; guid = 15822663052811949562 -; DIS-DAG: = gv: (name: "bar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), refs: (^{{.*}})))) ; guid = 16434608426314478903 +; DIS-DAG: = gv: (name: "bar", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 1), refs: (^{{.*}})))) ; guid = 16434608426314478903 ; Don't try to match the exact GUID. Since it is private, the file path ; will get hashed, and that will be test dependent. ; DIS-DAG: = gv: (name: "Y", summaries: (function: (module: ^0, flags: (linkage: private, notEligibleToImport: 0, live: 0, dsoLocal: 1), insts: 14, calls: ((callee: ^{{.*}}))))) ; guid = |

