diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Analysis/ModuleSummaryAnalysis.cpp | 122 | ||||
| -rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 57 | ||||
| -rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 47 | ||||
| -rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 32 | ||||
| -rw-r--r-- | llvm/lib/IR/AsmWriter.cpp | 5 | ||||
| -rw-r--r-- | llvm/lib/IR/ModuleSummaryIndex.cpp | 141 | ||||
| -rw-r--r-- | llvm/lib/LTO/LTO.cpp | 21 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/FunctionImport.cpp | 12 | ||||
| -rw-r--r-- | llvm/lib/Transforms/Utils/FunctionImportUtils.cpp | 13 |
9 files changed, 143 insertions, 307 deletions
diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp index e25eb290a66..914561f0f3f 100644 --- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp +++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -231,13 +231,6 @@ static bool isNonVolatileLoad(const Instruction *I) { return false; } -static bool isNonVolatileStore(const Instruction *I) { - if (const auto *SI = dyn_cast<StoreInst>(I)) - return !SI->isVolatile(); - - return false; -} - static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, const Function &F, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT, @@ -252,7 +245,7 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, // Map from callee ValueId to profile count. Used to accumulate profile // counts for all static calls to a given callee. MapVector<ValueInfo, CalleeInfo> CallGraphEdges; - SetVector<ValueInfo> RefEdges, LoadRefEdges, StoreRefEdges; + SetVector<ValueInfo> RefEdges; SetVector<GlobalValue::GUID> TypeTests; SetVector<FunctionSummary::VFuncId> TypeTestAssumeVCalls, TypeCheckedLoadVCalls; @@ -265,7 +258,6 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, // list. findRefEdges(Index, &F, RefEdges, Visited); std::vector<const Instruction *> NonVolatileLoads; - std::vector<const Instruction *> NonVolatileStores; bool HasInlineAsmMaybeReferencingInternal = false; for (const BasicBlock &BB : F) @@ -273,34 +265,12 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, if (isa<DbgInfoIntrinsic>(I)) continue; ++NumInsts; - // Regular LTO module doesn't participate in ThinLTO import, - // so no reference from it can be read/writeonly, since this - // would require importing variable as local copy - if (IsThinLTO) { - if (isNonVolatileLoad(&I)) { - // Postpone processing of non-volatile load instructions - // See comments below - Visited.insert(&I); - NonVolatileLoads.push_back(&I); - continue; - } else if (isNonVolatileStore(&I)) { - Visited.insert(&I); - NonVolatileStores.push_back(&I); - // All references from second operand of store (destination address) - // can be considered write-only if they're not referenced by any - // non-store instruction. References from first operand of store - // (stored value) can't be treated either as read- or as write-only - // so we add them to RefEdges as we do with all other instructions - // except non-volatile load. - Value *Stored = I.getOperand(0); - if (auto *GV = dyn_cast<GlobalValue>(Stored)) - // findRefEdges will try to examine GV operands, so instead - // of calling it we should add GV to RefEdges directly. - RefEdges.insert(Index.getOrInsertValueInfo(GV)); - else if (auto *U = dyn_cast<User>(Stored)) - findRefEdges(Index, U, RefEdges, Visited); - continue; - } + if (isNonVolatileLoad(&I)) { + // Postpone processing of non-volatile load instructions + // See comments below + Visited.insert(&I); + NonVolatileLoads.push_back(&I); + continue; } findRefEdges(Index, &I, RefEdges, Visited); auto CS = ImmutableCallSite(&I); @@ -391,61 +361,24 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, } } - std::vector<ValueInfo> Refs; - if (IsThinLTO) { - auto AddRefEdges = [&](const std::vector<const Instruction *> &Instrs, - SetVector<ValueInfo> &Edges, - SmallPtrSet<const User *, 8> &Cache) { - for (const auto *I : Instrs) { - Cache.erase(I); - findRefEdges(Index, I, Edges, Cache); - } - }; - - // By now we processed all instructions in a function, except - // non-volatile loads and non-volatile value stores. Let's find - // ref edges for both of instruction sets - AddRefEdges(NonVolatileLoads, LoadRefEdges, Visited); - // We can add some values to the Visited set when processing load - // instructions which are also used by stores in NonVolatileStores. - // For example this can happen if we have following code: - // - // store %Derived* @foo, %Derived** bitcast (%Base** @bar to %Derived**) - // %42 = load %Derived*, %Derived** bitcast (%Base** @bar to %Derived**) - // - // After processing loads we'll add bitcast to the Visited set, and if - // we use the same set while processing stores, we'll never see store - // to @bar and @bar will be mistakenly treated as readonly. - SmallPtrSet<const llvm::User *, 8> StoreCache; - AddRefEdges(NonVolatileStores, StoreRefEdges, StoreCache); - - // If both load and store instruction reference the same variable - // we won't be able to optimize it. Add all such reference edges - // to RefEdges set. - for (auto &VI : StoreRefEdges) - if (LoadRefEdges.remove(VI)) - RefEdges.insert(VI); - - unsigned RefCnt = RefEdges.size(); - // All new reference edges inserted in two loops below are either - // read or write only. They will be grouped in the end of RefEdges - // vector, so we can use a single integer value to identify them. - for (auto &VI : LoadRefEdges) - RefEdges.insert(VI); - - unsigned FirstWORef = RefEdges.size(); - for (auto &VI : StoreRefEdges) - RefEdges.insert(VI); - - Refs = RefEdges.takeVector(); - for (; RefCnt < FirstWORef; ++RefCnt) + // By now we processed all instructions in a function, except + // non-volatile loads. All new refs we add in a loop below + // are obviously constant. All constant refs are grouped in the + // end of RefEdges vector, so we can use a single integer value + // to identify them. + unsigned RefCnt = RefEdges.size(); + for (const Instruction *I : NonVolatileLoads) { + Visited.erase(I); + findRefEdges(Index, I, RefEdges, Visited); + } + std::vector<ValueInfo> Refs = RefEdges.takeVector(); + // Regular LTO module doesn't participate in ThinLTO import, + // so no reference from it can be readonly, since this would + // require importing variable as local copy + if (IsThinLTO) + for (; RefCnt < Refs.size(); ++RefCnt) Refs[RefCnt].setReadOnly(); - for (; RefCnt < Refs.size(); ++RefCnt) - Refs[RefCnt].setWriteOnly(); - } else { - Refs = RefEdges.takeVector(); - } // Explicit add hot edges to enforce importing for designated GUIDs for // sample PGO, to enable the same inlines as the profiled optimized binary. for (auto &I : F.getImportGUIDs()) @@ -593,11 +526,10 @@ static void computeVariableSummary(ModuleSummaryIndex &Index, } } - // Don't mark variables we won't be able to internalize as read/write-only. - bool CanBeInternalized = + // Don't mark variables we won't be able to internalize as read-only. + GlobalVarSummary::GVarFlags VarFlags( !V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() && - !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass(); - GlobalVarSummary::GVarFlags VarFlags(CanBeInternalized, CanBeInternalized); + !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass()); auto GVarSummary = llvm::make_unique<GlobalVarSummary>(Flags, VarFlags, RefEdges.takeVector()); if (NonRenamableLocal) @@ -715,7 +647,7 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex( } else { std::unique_ptr<GlobalVarSummary> Summary = llvm::make_unique<GlobalVarSummary>( - GVFlags, GlobalVarSummary::GVarFlags(false, false), + GVFlags, GlobalVarSummary::GVarFlags(), ArrayRef<ValueInfo>{}); Index.addGlobalValueSummary(*GV, std::move(Summary)); } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 085f3bd2999..9bfce74eb0b 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -7860,13 +7860,9 @@ static const auto FwdVIRef = (GlobalValueSummaryMapTy::value_type *)-8; static void resolveFwdRef(ValueInfo *Fwd, ValueInfo &Resolved) { bool ReadOnly = Fwd->isReadOnly(); - bool WriteOnly = Fwd->isWriteOnly(); - assert(!(ReadOnly && WriteOnly)); *Fwd = Resolved; if (ReadOnly) Fwd->setReadOnly(); - if (WriteOnly) - Fwd->setWriteOnly(); } /// Stores the given Name/GUID and associated summary into the Index. @@ -8096,8 +8092,7 @@ bool LLParser::ParseVariableSummary(std::string Name, GlobalValue::GUID GUID, GlobalValueSummary::GVFlags GVFlags = GlobalValueSummary::GVFlags( /*Linkage=*/GlobalValue::ExternalLinkage, /*NotEligibleToImport=*/false, /*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false); - GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false, - /* WriteOnly */ false); + GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false); std::vector<ValueInfo> Refs; VTableFuncList VTableFuncs; if (ParseToken(lltok::colon, "expected ':' here") || @@ -8438,11 +8433,10 @@ bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) { VContexts.push_back(VC); } while (EatIfPresent(lltok::comma)); - // Sort value contexts so that ones with writeonly - // and readonly ValueInfo are at the end of VContexts vector. - // See FunctionSummary::specialRefCounts() + // 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, [](const ValueContext &VC1, const ValueContext &VC2) { - return VC1.VI.getAccessSpecifier() < VC2.VI.getAccessSpecifier(); + return VC1.VI.isReadOnly() < VC2.VI.isReadOnly(); }); IdToIndexMapType IdToIndexMap; @@ -8760,41 +8754,24 @@ bool LLParser::ParseGVFlags(GlobalValueSummary::GVFlags &GVFlags) { } /// GVarFlags -/// ::= 'varFlags' ':' '(' 'readonly' ':' Flag -/// ',' 'writeonly' ':' Flag ')' +/// ::= 'varFlags' ':' '(' 'readonly' ':' Flag ')' bool LLParser::ParseGVarFlags(GlobalVarSummary::GVarFlags &GVarFlags) { assert(Lex.getKind() == lltok::kw_varFlags); Lex.Lex(); + unsigned Flag = 0; if (ParseToken(lltok::colon, "expected ':' here") || - ParseToken(lltok::lparen, "expected '(' here")) + ParseToken(lltok::lparen, "expected '(' here") || + ParseToken(lltok::kw_readonly, "expected 'readonly' here") || + ParseToken(lltok::colon, "expected ':' here")) return true; - auto ParseRest = [this](unsigned int &Val) { - Lex.Lex(); - if (ParseToken(lltok::colon, "expected ':'")) - return true; - return ParseFlag(Val); - }; + ParseFlag(Flag); + GVarFlags.ReadOnly = Flag; - do { - unsigned Flag = 0; - switch (Lex.getKind()) { - case lltok::kw_readonly: - if (ParseRest(Flag)) - return true; - GVarFlags.MaybeReadOnly = Flag; - break; - case lltok::kw_writeonly: - if (ParseRest(Flag)) - return true; - GVarFlags.MaybeWriteOnly = Flag; - break; - default: - return Error(Lex.getLoc(), "expected gvar flag type"); - } - } while (EatIfPresent(lltok::comma)); - return ParseToken(lltok::rparen, "expected ')' here"); + if (ParseToken(lltok::rparen, "expected ')' here")) + return true; + return false; } /// ModuleReference @@ -8817,9 +8794,7 @@ bool LLParser::ParseModuleReference(StringRef &ModulePath) { /// GVReference /// ::= SummaryID bool LLParser::ParseGVReference(ValueInfo &VI, unsigned &GVId) { - bool WriteOnly = false, ReadOnly = EatIfPresent(lltok::kw_readonly); - if (!ReadOnly) - WriteOnly = EatIfPresent(lltok::kw_writeonly); + bool ReadOnly = EatIfPresent(lltok::kw_readonly); if (ParseToken(lltok::SummaryID, "expected GV ID")) return true; @@ -8834,7 +8809,5 @@ bool LLParser::ParseGVReference(ValueInfo &VI, unsigned &GVId) { if (ReadOnly) VI.setReadOnly(); - if (WriteOnly) - VI.setWriteOnly(); return false; } diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index a339f6eb710..affbe4cee79 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -984,8 +984,7 @@ static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags, // Decode the flags for GlobalVariable in the summary static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) { - return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false, - (RawFlags & 0x2) ? true : false); + return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { @@ -5684,16 +5683,10 @@ void ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableSummaryRecord( parseTypeIdCompatibleVtableInfo(Record, Slot, TypeId); } -static void setSpecialRefs(std::vector<ValueInfo> &Refs, unsigned ROCnt, - unsigned WOCnt) { - // Readonly and writeonly refs are in the end of the refs list. - assert(ROCnt + WOCnt <= Refs.size()); - unsigned FirstWORef = Refs.size() - WOCnt; - unsigned RefNo = FirstWORef - ROCnt; - for (; RefNo < FirstWORef; ++RefNo) +static void setImmutableRefs(std::vector<ValueInfo> &Refs, unsigned Count) { + // Read-only refs are in the end of the refs list. + for (unsigned RefNo = Refs.size() - Count; RefNo < Refs.size(); ++RefNo) Refs[RefNo].setReadOnly(); - for (; RefNo < Refs.size(); ++RefNo) - Refs[RefNo].setWriteOnly(); } // Eagerly parse the entire summary block. This populates the GlobalValueSummary @@ -5720,9 +5713,9 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { } const uint64_t Version = Record[0]; const bool IsOldProfileFormat = Version == 1; - if (Version < 1 || Version > 7) + if (Version < 1 || Version > 6) return error("Invalid summary version " + Twine(Version) + - ". Version should be in the range [1-7]."); + ". Version should be in the range [1-6]."); Record.clear(); // Keep around the last seen summary to be used when we see an optional @@ -5821,19 +5814,15 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { unsigned InstCount = Record[2]; uint64_t RawFunFlags = 0; unsigned NumRefs = Record[3]; - unsigned NumRORefs = 0, NumWORefs = 0; + unsigned NumImmutableRefs = 0; int RefListStartIndex = 4; if (Version >= 4) { RawFunFlags = Record[3]; NumRefs = Record[4]; RefListStartIndex = 5; if (Version >= 5) { - NumRORefs = Record[5]; + NumImmutableRefs = Record[5]; RefListStartIndex = 6; - if (Version >= 7) { - NumWORefs = Record[6]; - RefListStartIndex = 7; - } } } @@ -5853,7 +5842,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { std::vector<FunctionSummary::EdgeTy> Calls = makeCallList( ArrayRef<uint64_t>(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, HasRelBF); - setSpecialRefs(Refs, NumRORefs, NumWORefs); + setImmutableRefs(Refs, NumImmutableRefs); auto FS = llvm::make_unique<FunctionSummary>( Flags, InstCount, getDecodedFFlags(RawFunFlags), /*EntryCount=*/0, std::move(Refs), std::move(Calls), std::move(PendingTypeTests), @@ -5904,8 +5893,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { unsigned ValueID = Record[0]; uint64_t RawFlags = Record[1]; unsigned RefArrayStart = 2; - GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, - /* WriteOnly */ false); + GlobalVarSummary::GVarFlags GVF; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[2]); @@ -5962,7 +5950,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { uint64_t RawFunFlags = 0; uint64_t EntryCount = 0; unsigned NumRefs = Record[4]; - unsigned NumRORefs = 0, NumWORefs = 0; + unsigned NumImmutableRefs = 0; int RefListStartIndex = 5; if (Version >= 4) { @@ -5970,19 +5958,13 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { RefListStartIndex = 6; size_t NumRefsIndex = 5; if (Version >= 5) { - unsigned NumRORefsOffset = 1; RefListStartIndex = 7; if (Version >= 6) { NumRefsIndex = 6; EntryCount = Record[5]; RefListStartIndex = 8; - if (Version >= 7) { - RefListStartIndex = 9; - NumWORefs = Record[8]; - NumRORefsOffset = 2; - } } - NumRORefs = Record[RefListStartIndex - NumRORefsOffset]; + NumImmutableRefs = Record[RefListStartIndex - 1]; } NumRefs = Record[NumRefsIndex]; } @@ -5998,7 +5980,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { ArrayRef<uint64_t>(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile, false); ValueInfo VI = getValueInfoFromValueId(ValueID).first; - setSpecialRefs(Refs, NumRORefs, NumWORefs); + setImmutableRefs(Refs, NumImmutableRefs); auto FS = llvm::make_unique<FunctionSummary>( Flags, InstCount, getDecodedFFlags(RawFunFlags), EntryCount, std::move(Refs), std::move(Edges), std::move(PendingTypeTests), @@ -6045,8 +6027,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { uint64_t ModuleId = Record[1]; uint64_t RawFlags = Record[2]; unsigned RefArrayStart = 3; - GlobalVarSummary::GVarFlags GVF(/* ReadOnly */ false, - /* WriteOnly */ false); + GlobalVarSummary::GVarFlags GVF; auto Flags = getDecodedGVSummaryFlags(RawFlags, Version); if (Version >= 5) { GVF = getDecodedGVarFlags(Record[3]); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 547889f82c7..3812481139e 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1020,7 +1020,7 @@ static uint64_t getEncodedGVSummaryFlags(GlobalValueSummary::GVFlags Flags) { } static uint64_t getEncodedGVarFlags(GlobalVarSummary::GVarFlags Flags) { - uint64_t RawFlags = Flags.MaybeReadOnly | (Flags.MaybeWriteOnly << 1); + uint64_t RawFlags = Flags.ReadOnly; return RawFlags; } @@ -3632,13 +3632,11 @@ void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord( FunctionSummary *FS = cast<FunctionSummary>(Summary); writeFunctionTypeMetadataRecords(Stream, FS); - auto SpecialRefCnts = FS->specialRefCounts(); NameVals.push_back(getEncodedGVSummaryFlags(FS->flags())); NameVals.push_back(FS->instCount()); NameVals.push_back(getEncodedFFlags(FS->fflags())); NameVals.push_back(FS->refs().size()); - NameVals.push_back(SpecialRefCnts.first); // rorefcnt - NameVals.push_back(SpecialRefCnts.second); // worefcnt + NameVals.push_back(FS->immutableRefCount()); for (auto &RI : FS->refs()) NameVals.push_back(VE.getValueID(RI.getValue())); @@ -3712,7 +3710,7 @@ void ModuleBitcodeWriterBase::writeModuleLevelReferences( // Current version for the summary. // This is bumped whenever we introduce changes in the way some record are // interpreted, like flags for instance. -static const uint64_t INDEX_VERSION = 7; +static const uint64_t INDEX_VERSION = 6; /// Emit the per-module summary section alongside the rest of /// the module's bitcode. @@ -3754,8 +3752,7 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() { Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt // numrefs x valueid, n x (valueid, hotness) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); @@ -3772,8 +3769,7 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() { Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // instcount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt // numrefs x valueid, n x (valueid [, rel_block_freq]) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); @@ -3905,8 +3901,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() { Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // entrycount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt // numrefs x valueid, n x (valueid) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); @@ -3922,8 +3917,7 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() { Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // fflags Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // entrycount Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // rorefcnt - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // worefcnt + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // immutablerefcnt // numrefs x valueid, n x (valueid, hotness) Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); @@ -4025,24 +4019,20 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() { // Fill in below NameVals.push_back(0); // numrefs - NameVals.push_back(0); // rorefcnt - NameVals.push_back(0); // worefcnt + NameVals.push_back(0); // immutablerefcnt - unsigned Count = 0, RORefCnt = 0, WORefCnt = 0; + unsigned Count = 0, ImmutableRefCnt = 0; for (auto &RI : FS->refs()) { auto RefValueId = getValueId(RI.getGUID()); if (!RefValueId) continue; NameVals.push_back(*RefValueId); if (RI.isReadOnly()) - RORefCnt++; - else if (RI.isWriteOnly()) - WORefCnt++; + ImmutableRefCnt++; Count++; } NameVals[6] = Count; - NameVals[7] = RORefCnt; - NameVals[8] = WORefCnt; + NameVals[7] = ImmutableRefCnt; bool HasProfileData = false; for (auto &EI : FS->calls()) { diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index eb5760daecb..51b1a0339ee 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2891,8 +2891,7 @@ void AssemblyWriter::printAliasSummary(const AliasSummary *AS) { } void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) { - Out << ", varFlags: (readonly: " << GS->VarFlags.MaybeReadOnly << ", " - << "writeonly: " << GS->VarFlags.MaybeWriteOnly << ")"; + Out << ", varFlags: (readonly: " << GS->VarFlags.ReadOnly << ")"; auto VTableFuncs = GS->vTableFuncs(); if (!VTableFuncs.empty()) { @@ -3102,8 +3101,6 @@ void AssemblyWriter::printSummary(const GlobalValueSummary &Summary) { Out << FS; if (Ref.isReadOnly()) Out << "readonly "; - else if (Ref.isWriteOnly()) - Out << "writeonly "; Out << "^" << Machine.getGUIDSlot(Ref.getGUID()); } Out << ")"; diff --git a/llvm/lib/IR/ModuleSummaryIndex.cpp b/llvm/lib/IR/ModuleSummaryIndex.cpp index 9f347d8da01..18b7ac09388 100644 --- a/llvm/lib/IR/ModuleSummaryIndex.cpp +++ b/llvm/lib/IR/ModuleSummaryIndex.cpp @@ -23,8 +23,6 @@ using namespace llvm; STATISTIC(ReadOnlyLiveGVars, "Number of live global variables marked read only"); -STATISTIC(WriteOnlyLiveGVars, - "Number of live global variables marked write only"); FunctionSummary FunctionSummary::ExternalNode = FunctionSummary::makeDummyFunctionSummary({}); @@ -47,18 +45,15 @@ bool ValueInfo::canAutoHide() const { }); } -// Gets the number of readonly and writeonly refs in RefEdgeList -std::pair<unsigned, unsigned> FunctionSummary::specialRefCounts() const { - // Here we take advantage of having all readonly and writeonly references +// Gets the number of immutable refs in RefEdgeList +unsigned FunctionSummary::immutableRefCount() const { + // Here we take advantage of having all readonly references // located in the end of the RefEdgeList. auto Refs = refs(); - unsigned RORefCnt = 0, WORefCnt = 0; - int I; - for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I) - WORefCnt++; - for (; I >= 0 && Refs[I].isReadOnly(); --I) - RORefCnt++; - return {RORefCnt, WORefCnt}; + unsigned ImmutableRefCnt = 0; + for (int I = Refs.size() - 1; I >= 0 && Refs[I].isReadOnly(); --I) + ImmutableRefCnt++; + return ImmutableRefCnt; } // Collect for the given module the list of function it defines @@ -104,56 +99,48 @@ bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const { return false; } -static void propagateAttributesToRefs(GlobalValueSummary *S) { - // If reference is not readonly or writeonly then referenced summary is not - // read/writeonly either. Note that: +static void propagateConstantsToRefs(GlobalValueSummary *S) { + // If reference is not readonly then referenced summary is not + // readonly either. Note that: // - All references from GlobalVarSummary are conservatively considered as - // not readonly or writeonly. Tracking them properly requires more complex - // analysis then we have now. + // not readonly. Tracking them properly requires more complex analysis + // then we have now. // // - AliasSummary objects have no refs at all so this function is a no-op // for them. for (auto &VI : S->refs()) { - assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S)); + if (VI.isReadOnly()) { + // We only mark refs as readonly when computing function summaries on + // analysis phase. + assert(isa<FunctionSummary>(S)); + continue; + } for (auto &Ref : VI.getSummaryList()) - // If references to alias is not read/writeonly then aliasee - // is not read/writeonly - if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) { - if (!VI.isReadOnly()) - GVS->setReadOnly(false); - if (!VI.isWriteOnly()) - GVS->setWriteOnly(false); - } + // If references to alias is not readonly then aliasee is not readonly + if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) + GVS->setReadOnly(false); } } -// Do the access attribute propagation in combined index. -// The goal of attribute propagation is internalization of readonly (RO) -// or writeonly (WO) variables. To determine which variables are RO or WO -// and which are not we take following steps: -// - During analysis we speculatively assign readonly and writeonly -// attribute to all variables which can be internalized. When computing -// function summary we also assign readonly or writeonly attribute to a -// reference if function doesn't modify referenced variable (readonly) -// or doesn't read it (writeonly). -// -// - After computing dead symbols in combined index we do the attribute -// propagation. During this step we: -// a. clear RO and WO attributes from variables which are preserved or -// can't be imported -// b. clear RO and WO attributes from variables referenced by any global -// variable initializer -// c. clear RO attribute from variable referenced by a function when -// reference is not readonly -// d. clear WO attribute from variable referenced by a function when -// reference is not writeonly +// Do the constant propagation in combined index. +// The goal of constant propagation is internalization of readonly +// variables. To determine which variables are readonly and which +// are not we take following steps: +// - During analysis we speculatively assign readonly attribute to +// all variables which can be internalized. When computing function +// summary we also assign readonly attribute to a reference if +// function doesn't modify referenced variable. // -// Because of (c, d) we don't internalize variables read by function A -// and modified by function B. +// - After computing dead symbols in combined index we do the constant +// propagation. During this step we clear readonly attribute from +// all variables which: +// a. are preserved or can't be imported +// b. referenced by any global variable initializer +// c. referenced by a function and reference is not readonly // // Internalization itself happens in the backend after import is finished -// See internalizeGVsAfterImport. -void ModuleSummaryIndex::propagateAttributes( +// See internalizeImmutableGVs. +void ModuleSummaryIndex::propagateConstants( const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { for (auto &P : *this) for (auto &S : P.second.SummaryList) { @@ -161,36 +148,29 @@ void ModuleSummaryIndex::propagateAttributes( // We don't examine references from dead objects continue; - // Global variable can't be marked read/writeonly if it is not eligible - // to import since we need to ensure that all external references get - // a local (imported) copy. It also can't be marked read/writeonly if - // it or any alias (since alias points to the same memory) are preserved - // or notEligibleToImport, since either of those means there could be - // writes (or reads in case of writeonly) that are not visible (because - // preserved means it could have external to DSO writes or reads, and - // notEligibleToImport means it could have writes or reads via inline - // assembly leading it to be in the @llvm.*used). + // Global variable can't be marked read only if it is not eligible + // to import since we need to ensure that all external references + // get a local (imported) copy. It also can't be marked read only + // if it or any alias (since alias points to the same memory) are + // preserved or notEligibleToImport, since either of those means + // there could be writes that are not visible (because preserved + // means it could have external to DSO writes, and notEligibleToImport + // means it could have writes via inline assembly leading it to be + // in the @llvm.*used). if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject())) // Here we intentionally pass S.get() not GVS, because S could be // an alias. - if (!canImportGlobalVar(S.get()) || - GUIDPreservedSymbols.count(P.first)) { + if (!canImportGlobalVar(S.get()) || GUIDPreservedSymbols.count(P.first)) GVS->setReadOnly(false); - GVS->setWriteOnly(false); - } - propagateAttributesToRefs(S.get()); + propagateConstantsToRefs(S.get()); } if (llvm::AreStatisticsEnabled()) for (auto &P : *this) if (P.second.SummaryList.size()) if (auto *GVS = dyn_cast<GlobalVarSummary>( P.second.SummaryList[0]->getBaseObject())) - if (isGlobalValueLive(GVS)) { - if (GVS->maybeReadOnly()) - ReadOnlyLiveGVars++; - if (GVS->maybeWriteOnly()) - WriteOnlyLiveGVars++; - } + if (isGlobalValueLive(GVS) && GVS->isReadOnly()) + ReadOnlyLiveGVars++; } // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot) @@ -353,13 +333,7 @@ static void defineExternalNode(raw_ostream &OS, const char *Pfx, static bool hasReadOnlyFlag(const GlobalValueSummary *S) { if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) - return GVS->maybeReadOnly(); - return false; -} - -static bool hasWriteOnlyFlag(const GlobalValueSummary *S) { - if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) - return GVS->maybeWriteOnly(); + return GVS->isReadOnly(); return false; } @@ -384,14 +358,12 @@ void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const { // 0 - alias // 1 - reference // 2 - constant reference - // 3 - writeonly reference - // Other value: (hotness - 4). - TypeOrHotness += 4; + // Other value: (hotness - 3). + TypeOrHotness += 3; static const char *EdgeAttrs[] = { " [style=dotted]; // alias", " [style=dashed]; // ref", " [style=dashed,color=forestgreen]; // const-ref", - " [style=dashed,color=violetred]; // writeOnly-ref", " // call (hotness : Unknown)", " [color=blue]; // call (hotness : Cold)", " // call (hotness : None)", @@ -436,8 +408,6 @@ void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const { A.add("shape", "Mrecord", "variable"); if (Flags.Live && hasReadOnlyFlag(SummaryIt.second)) A.addComment("immutable"); - if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second)) - A.addComment("writeOnly"); } if (Flags.DSOLocal) A.addComment("dsoLocal"); @@ -459,11 +429,10 @@ void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const { for (auto &SummaryIt : GVSMap) { auto *GVS = SummaryIt.second; for (auto &R : GVS->refs()) - Draw(SummaryIt.first, R.getGUID(), - R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3)); + Draw(SummaryIt.first, R.getGUID(), R.isReadOnly() ? -1 : -2); if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) { - Draw(SummaryIt.first, AS->getAliaseeGUID(), -4); + Draw(SummaryIt.first, AS->getAliaseeGUID(), -3); continue; } diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 64506890956..4ed13701aa9 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -192,10 +192,8 @@ void llvm::computeLTOCacheKey( AddUnsigned(VI.isDSOLocal()); AddUsedCfiGlobal(VI.getGUID()); } - if (auto *GVS = dyn_cast<GlobalVarSummary>(GS)) { - AddUnsigned(GVS->maybeReadOnly()); - AddUnsigned(GVS->maybeWriteOnly()); - } + if (auto *GVS = dyn_cast<GlobalVarSummary>(GS)) + AddUnsigned(GVS->isReadOnly()); if (auto *FS = dyn_cast<FunctionSummary>(GS)) { for (auto &TT : FS->type_tests()) UsedTypeIds.insert(TT); @@ -373,9 +371,9 @@ void llvm::thinLTOResolvePrevailingInIndex( GUIDPreservedSymbols); } -static bool isWeakObjectWithRWAccess(GlobalValueSummary *GVS) { +static bool isWeakWriteableObject(GlobalValueSummary *GVS) { if (auto *VarSummary = dyn_cast<GlobalVarSummary>(GVS->getBaseObject())) - return !VarSummary->maybeReadOnly() && !VarSummary->maybeWriteOnly() && + return !VarSummary->isReadOnly() && (VarSummary->linkage() == GlobalValue::WeakODRLinkage || VarSummary->linkage() == GlobalValue::LinkOnceODRLinkage); return false; @@ -396,12 +394,11 @@ static void thinLTOInternalizeAndPromoteGUID( // We can't internalize available_externally globals because this // can break function pointer equality. S->linkage() != GlobalValue::AvailableExternallyLinkage && - // Functions and read-only variables with linkonce_odr and - // weak_odr linkage can be internalized. We can't internalize - // linkonce_odr and weak_odr variables which are both modified - // and read somewhere in the program because reads and writes - // will become inconsistent. - !isWeakObjectWithRWAccess(S.get())) + // Functions and read-only variables with linkonce_odr and weak_odr + // linkage can be internalized. We can't internalize linkonce_odr + // and weak_odr variables which are modified somewhere in the + // program because reads and writes will become inconsistent. + !isWeakWriteableObject(S.get())) S->setLinkage(GlobalValue::InternalLinkage); } } diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp index 62c7fbd0722..9207f5fe0ef 100644 --- a/llvm/lib/Transforms/IPO/FunctionImport.cpp +++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -850,16 +850,14 @@ void llvm::computeDeadSymbolsWithConstProp( bool ImportEnabled) { computeDeadSymbols(Index, GUIDPreservedSymbols, isPrevailing); if (ImportEnabled) { - Index.propagateAttributes(GUIDPreservedSymbols); + Index.propagateConstants(GUIDPreservedSymbols); } else { - // If import is disabled we should drop read/write-only attribute + // If import is disabled we should drop read-only attribute // from all summaries to prevent internalization. for (auto &P : Index) for (auto &S : P.second.SummaryList) - if (auto *GVS = dyn_cast<GlobalVarSummary>(S.get())) { + if (auto *GVS = dyn_cast<GlobalVarSummary>(S.get())) GVS->setReadOnly(false); - GVS->setWriteOnly(false); - } } } @@ -1066,7 +1064,7 @@ static Function *replaceAliasWithAliasee(Module *SrcModule, GlobalAlias *GA) { // Internalize values that we marked with specific attribute // in processGlobalForThinLTO. -static void internalizeGVsAfterImport(Module &M) { +static void internalizeImmutableGVs(Module &M) { for (auto &GV : M.globals()) // Skip GVs which have been converted to declarations // by dropDeadSymbols. @@ -1199,7 +1197,7 @@ Expected<bool> FunctionImporter::importFunctions( NumImportedModules++; } - internalizeGVsAfterImport(DestModule); + internalizeImmutableGVs(DestModule); NumImportedFunctions += (ImportedCount - ImportedGVCount); NumImportedGlobalVars += ImportedGVCount; diff --git a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp index c9cc0990f23..8e80ee2c549 100644 --- a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp +++ b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp @@ -229,11 +229,11 @@ void FunctionImportGlobalProcessing::processGlobalForThinLTO(GlobalValue &GV) { } } - // Mark read/write-only variables which can be imported with specific - // attribute. We can't internalize them now because IRMover will fail - // to link variable definitions to their external declarations during - // ThinLTO import. We'll internalize read-only variables later, after - // import is finished. See internalizeGVsAfterImport. + // Mark read-only variables which can be imported with specific attribute. + // We can't internalize them now because IRMover will fail to link variable + // definitions to their external declarations during ThinLTO import. We'll + // internalize read-only variables later, after import is finished. + // See internalizeImmutableGVs. // // If global value dead stripping is not enabled in summary then // propagateConstants hasn't been run. We can't internalize GV @@ -241,8 +241,7 @@ void FunctionImportGlobalProcessing::processGlobalForThinLTO(GlobalValue &GV) { if (!GV.isDeclaration() && VI && ImportIndex.withGlobalValueDeadStripping()) { const auto &SL = VI.getSummaryList(); auto *GVS = SL.empty() ? nullptr : dyn_cast<GlobalVarSummary>(SL[0].get()); - // At this stage "maybe" is "definitely" - if (GVS && (GVS->maybeReadOnly() || GVS->maybeWriteOnly())) + if (GVS && GVS->isReadOnly()) cast<GlobalVariable>(&GV)->addAttribute("thinlto-internalize"); } |

