Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -55,6 +55,34 @@ //===----------------------------------------------------------------------===// namespace { + +// Like Optional, but lazily initializes its underlying type before operator* or +// operator->. +template class Lazy { +public: + Lazy() : Lazy([] { return T(); }) {} + explicit Lazy(std::function Init) : Initializer(Init) {} + + T &operator*() { + EnsureInitialized(); + return *Obj; + } + + T *operator->() { + EnsureInitialized(); + return &*Obj; + } + +private: + void EnsureInitialized() { + if (!Obj) + Obj.emplace(Initializer()); + } + + std::function Initializer; + Optional Obj; +}; + struct OrderMap { DenseMap> IDs; @@ -406,20 +434,29 @@ namespace { +// Instances of this class are sometimes created very frequently -- e.g. on +// every call to Instruction::operator<< -- so we lazily initialize our +// expensive data structures, in the hopes we won't need them. class TypePrinting { TypePrinting(const TypePrinting &) = delete; void operator=(const TypePrinting&) = delete; + + // Initializers for lazy members. + TypeFinder BuildAllTypes(); + std::vector BuildNamedTypes(); + DenseMap BuildNumberedTypes(); + + const Module *TheModule; // May be null. + + Lazy AllTypes{std::bind(&TypePrinting::BuildAllTypes, this)}; + public: + explicit TypePrinting(const Module *M = nullptr) : TheModule(M) {} - /// NamedTypes - The named types that are used by the current module. - TypeFinder NamedTypes; - - /// NumberedTypes - The numbered types, along with their value. - DenseMap NumberedTypes; - - TypePrinting() = default; - - void incorporateTypes(const Module &M); + Lazy> NamedTypes{ + std::bind(&TypePrinting::BuildNamedTypes, this)}; + Lazy> NumberedTypes{ + std::bind(&TypePrinting::BuildNumberedTypes, this)}; void print(Type *Ty, raw_ostream &OS); @@ -427,30 +464,33 @@ }; } // namespace -void TypePrinting::incorporateTypes(const Module &M) { - NamedTypes.run(M, false); - - // The list of struct types we got back includes all the struct types, split - // the unnamed ones out to a numbering and remove the anonymous structs. - unsigned NextNumber = 0; - - std::vector::iterator NextToUse = NamedTypes.begin(), I, E; - for (I = NamedTypes.begin(), E = NamedTypes.end(); I != E; ++I) { - StructType *STy = *I; - - // Ignore anonymous types. - if (STy->isLiteral()) - continue; - - if (STy->getName().empty()) - NumberedTypes[STy] = NextNumber++; - else - *NextToUse++ = STy; - } - - NamedTypes.erase(NextToUse, NamedTypes.end()); +TypeFinder TypePrinting::BuildAllTypes() { + TypeFinder Ret; + if (TheModule) + Ret.run(*TheModule, false); + return Ret; } +DenseMap TypePrinting::BuildNumberedTypes() { + DenseMap Ret; + int I = 0; + for (StructType *Sty : *AllTypes) { + // Ignore anonymous and named types. + if (!Sty->isLiteral() && Sty->getName().empty()) + Ret[Sty] = I++; + } + return Ret; +} + +std::vector TypePrinting::BuildNamedTypes() { + std::vector Ret; + for (StructType *Sty : *AllTypes) { + // Ignore anonymous types and types without names. + if (!Sty->isLiteral() && !Sty->getName().empty()) + Ret.push_back(Sty); + } + return Ret; +} /// CalcTypeName - Write the specified type to the specified raw_ostream, making /// use of type names or up references to shorten the type name where possible. @@ -497,8 +537,8 @@ if (!STy->getName().empty()) return PrintLLVMName(OS, STy->getName(), LocalPrefix); - DenseMap::iterator I = NumberedTypes.find(STy); - if (I != NumberedTypes.end()) + auto I = NumberedTypes->find(STy); + if (I != NumberedTypes->end()) OS << '%' << I->second; else // Not enumerated, print the hex address. OS << "%\"type " << STy << '\"'; @@ -2003,6 +2043,9 @@ } namespace { +// New instances of this class are created frequently -- e.g. we get a new one +// every time we run Instruction::operator<<. So we do as much lazy +// initialization as is reasonable. class AssemblyWriter { formatted_raw_ostream &Out; const Module *TheModule; @@ -2010,12 +2053,17 @@ SlotTracker &Machine; TypePrinting TypePrinter; AssemblyAnnotationWriter *AnnotationWriter; - SetVector Comdats; bool IsForDebug; bool ShouldPreserveUseListOrder; UseListOrderStack UseListOrders; SmallVector MDNames; + SetVector BuildComdats(); + + // Lazily initialized to the value of BuildComdats(). + Lazy> Comdats{ + std::bind(&AssemblyWriter::BuildComdats, this)}; + public: /// Construct an AssemblyWriter with an external SlotTracker AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const Module *M, @@ -2071,18 +2119,19 @@ AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const Module *M, AssemblyAnnotationWriter *AAW, bool IsForDebug, bool ShouldPreserveUseListOrder) - : Out(o), TheModule(M), Machine(Mac), AnnotationWriter(AAW), + : Out(o), TheModule(M), Machine(Mac), TypePrinter(M), AnnotationWriter(AAW), IsForDebug(IsForDebug), - ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) { - if (!TheModule) - return; - TypePrinter.incorporateTypes(*TheModule); + ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) {} + +SetVector AssemblyWriter::BuildComdats() { + SetVector Ret; for (const Function &F : *TheModule) if (const Comdat *C = F.getComdat()) - Comdats.insert(C); + Ret.insert(C); for (const GlobalVariable &GV : TheModule->globals()) if (const Comdat *C = GV.getComdat()) - Comdats.insert(C); + Ret.insert(C); + return Ret; } void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType) { @@ -2247,11 +2296,11 @@ printTypeIdentities(); // Output all comdats. - if (!Comdats.empty()) + if (!Comdats->empty()) Out << '\n'; - for (const Comdat *C : Comdats) { + for (const Comdat *C : *Comdats) { printComdat(C); - if (C != Comdats.back()) + if (C != Comdats->back()) Out << '\n'; } @@ -2483,39 +2532,38 @@ } void AssemblyWriter::printTypeIdentities() { - if (TypePrinter.NumberedTypes.empty() && - TypePrinter.NamedTypes.empty()) + const auto &NumberedTypes = *TypePrinter.NumberedTypes; + const auto &NamedTypes = *TypePrinter.NamedTypes; + if (NumberedTypes.empty() && NamedTypes.empty()) return; Out << '\n'; // We know all the numbers that each type is used and we know that it is a // dense assignment. Convert the map to an index table. - std::vector NumberedTypes(TypePrinter.NumberedTypes.size()); - for (DenseMap::iterator I = - TypePrinter.NumberedTypes.begin(), E = TypePrinter.NumberedTypes.end(); - I != E; ++I) { - assert(I->second < NumberedTypes.size() && "Didn't get a dense numbering?"); - NumberedTypes[I->second] = I->first; + std::vector NumberedTypesVec(NumberedTypes.size()); + for (const auto &KV : NumberedTypes) { + assert(KV.second < NumberedTypes.size() && "Didn't get a dense numbering?"); + NumberedTypesVec[KV.second] = KV.first; } // Emit all numbered types. - for (unsigned i = 0, e = NumberedTypes.size(); i != e; ++i) { + for (unsigned i = 0, e = NumberedTypesVec.size(); i != e; ++i) { Out << '%' << i << " = type "; // Make sure we print out at least one level of the type structure, so // that we do not get %2 = type %2 - TypePrinter.printStructBody(NumberedTypes[i], Out); + TypePrinter.printStructBody(NumberedTypesVec[i], Out); Out << '\n'; } - for (unsigned i = 0, e = TypePrinter.NamedTypes.size(); i != e; ++i) { - PrintLLVMName(Out, TypePrinter.NamedTypes[i]->getName(), LocalPrefix); + for (StructType *STy : NamedTypes) { + PrintLLVMName(Out, STy->getName(), LocalPrefix); Out << " = type "; // Make sure we print out at least one level of the type structure, so // that we do not get %FILE = type %FILE - TypePrinter.printStructBody(TypePrinter.NamedTypes[i], Out); + TypePrinter.printStructBody(STy, Out); Out << '\n'; } } @@ -3370,9 +3418,7 @@ static void printAsOperandImpl(const Value &V, raw_ostream &O, bool PrintType, ModuleSlotTracker &MST) { - TypePrinting TypePrinter; - if (const Module *M = MST.getModule()) - TypePrinter.incorporateTypes(*M); + TypePrinting TypePrinter(MST.getModule()); if (PrintType) { TypePrinter.print(V.getType(), O); O << ' '; @@ -3411,10 +3457,7 @@ bool OnlyAsOperand) { formatted_raw_ostream OS(ROS); - TypePrinting TypePrinter; - if (M) - TypePrinter.incorporateTypes(*M); - + TypePrinting TypePrinter(M); WriteAsOperandInternal(OS, &MD, &TypePrinter, MST.getMachine(), M, /* FromValue */ true);