X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=lib%2FIR%2FAsmWriter.cpp;h=449225ae8c34073037c38c09d931ad8ef269597d;hp=c9ea49b22248c0656e8c322222115ca274811a26;hb=d5de327da0b174c5d44f776f827c1ea8bfe99095;hpb=39a09d2b7cf3a547df4a92c91280d5dc3b02318f diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index c9ea49b2224..449225ae8c3 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -49,21 +49,228 @@ AssemblyAnnotationWriter::~AssemblyAnnotationWriter() {} // Helper Functions //===----------------------------------------------------------------------===// +namespace { +struct OrderMap { + DenseMap> IDs; + + unsigned size() const { return IDs.size(); } + std::pair &operator[](const Value *V) { return IDs[V]; } + std::pair lookup(const Value *V) const { + return IDs.lookup(V); + } + void index(const Value *V) { + // Explicitly sequence get-size and insert-value operations to avoid UB. + unsigned ID = IDs.size() + 1; + IDs[V].first = ID; + } +}; +} + +static void orderValue(const Value *V, OrderMap &OM) { + if (OM.lookup(V).first) + return; + + if (const Constant *C = dyn_cast(V)) + if (C->getNumOperands() && !isa(C)) + for (const Value *Op : C->operands()) + if (!isa(Op) && !isa(Op)) + orderValue(Op, OM); + + // Note: we cannot cache this lookup above, since inserting into the map + // changes the map's size, and thus affects the other IDs. + OM.index(V); +} + +static OrderMap orderModule(const Module *M) { + // This needs to match the order used by ValueEnumerator::ValueEnumerator() + // and ValueEnumerator::incorporateFunction(). + OrderMap OM; + + for (const GlobalVariable &G : M->globals()) { + if (G.hasInitializer()) + if (!isa(G.getInitializer())) + orderValue(G.getInitializer(), OM); + orderValue(&G, OM); + } + for (const GlobalAlias &A : M->aliases()) { + if (!isa(A.getAliasee())) + orderValue(A.getAliasee(), OM); + orderValue(&A, OM); + } + for (const Function &F : *M) { + if (F.hasPrefixData()) + if (!isa(F.getPrefixData())) + orderValue(F.getPrefixData(), OM); + orderValue(&F, OM); + + if (F.isDeclaration()) + continue; + + for (const Argument &A : F.args()) + orderValue(&A, OM); + for (const BasicBlock &BB : F) { + orderValue(&BB, OM); + for (const Instruction &I : BB) { + for (const Value *Op : I.operands()) + if ((isa(*Op) && !isa(*Op)) || + isa(*Op)) + orderValue(Op, OM); + orderValue(&I, OM); + } + } + } + return OM; +} + +static void predictValueUseListOrderImpl(const Value *V, const Function *F, + unsigned ID, const OrderMap &OM, + UseListOrderStack &Stack) { + // Predict use-list order for this one. + typedef std::pair Entry; + SmallVector List; + for (const Use &U : V->uses()) + // Check if this user will be serialized. + if (OM.lookup(U.getUser()).first) + List.push_back(std::make_pair(&U, List.size())); + + if (List.size() < 2) + // We may have lost some users. + return; + + bool GetsReversed = + !isa(V) && !isa(V) && !isa(V); + if (auto *BA = dyn_cast(V)) + ID = OM.lookup(BA->getBasicBlock()).first; + std::sort(List.begin(), List.end(), [&](const Entry &L, const Entry &R) { + const Use *LU = L.first; + const Use *RU = R.first; + if (LU == RU) + return false; + + auto LID = OM.lookup(LU->getUser()).first; + auto RID = OM.lookup(RU->getUser()).first; + + // If ID is 4, then expect: 7 6 5 1 2 3. + if (LID < RID) { + if (GetsReversed) + if (RID <= ID) + return true; + return false; + } + if (RID < LID) { + if (GetsReversed) + if (LID <= ID) + return false; + return true; + } + + // LID and RID are equal, so we have different operands of the same user. + // Assume operands are added in order for all instructions. + if (GetsReversed) + if (LID <= ID) + return LU->getOperandNo() < RU->getOperandNo(); + return LU->getOperandNo() > RU->getOperandNo(); + }); + + if (std::is_sorted( + List.begin(), List.end(), + [](const Entry &L, const Entry &R) { return L.second < R.second; })) + // Order is already correct. + return; + + // Store the shuffle. + Stack.emplace_back(V, F, List.size()); + assert(List.size() == Stack.back().Shuffle.size() && "Wrong size"); + for (size_t I = 0, E = List.size(); I != E; ++I) + Stack.back().Shuffle[I] = List[I].second; +} + +static void predictValueUseListOrder(const Value *V, const Function *F, + OrderMap &OM, UseListOrderStack &Stack) { + auto &IDPair = OM[V]; + assert(IDPair.first && "Unmapped value"); + if (IDPair.second) + // Already predicted. + return; + + // Do the actual prediction. + IDPair.second = true; + if (!V->use_empty() && std::next(V->use_begin()) != V->use_end()) + predictValueUseListOrderImpl(V, F, IDPair.first, OM, Stack); + + // Recursive descent into constants. + if (const Constant *C = dyn_cast(V)) + if (C->getNumOperands()) // Visit GlobalValues. + for (const Value *Op : C->operands()) + if (isa(Op)) // Visit GlobalValues. + predictValueUseListOrder(Op, F, OM, Stack); +} + +static UseListOrderStack predictUseListOrder(const Module *M) { + OrderMap OM = orderModule(M); + + // Use-list orders need to be serialized after all the users have been added + // to a value, or else the shuffles will be incomplete. Store them per + // function in a stack. + // + // Aside from function order, the order of values doesn't matter much here. + UseListOrderStack Stack; + + // We want to visit the functions backward now so we can list function-local + // constants in the last Function they're used in. Module-level constants + // have already been visited above. + for (auto I = M->rbegin(), E = M->rend(); I != E; ++I) { + const Function &F = *I; + if (F.isDeclaration()) + continue; + for (const BasicBlock &BB : F) + predictValueUseListOrder(&BB, &F, OM, Stack); + for (const Argument &A : F.args()) + predictValueUseListOrder(&A, &F, OM, Stack); + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + for (const Value *Op : I.operands()) + if (isa(*Op) || isa(*Op)) // Visit GlobalValues. + predictValueUseListOrder(Op, &F, OM, Stack); + for (const BasicBlock &BB : F) + for (const Instruction &I : BB) + predictValueUseListOrder(&I, &F, OM, Stack); + } + + // Visit globals last. + for (const GlobalVariable &G : M->globals()) + predictValueUseListOrder(&G, nullptr, OM, Stack); + for (const Function &F : *M) + predictValueUseListOrder(&F, nullptr, OM, Stack); + for (const GlobalAlias &A : M->aliases()) + predictValueUseListOrder(&A, nullptr, OM, Stack); + for (const GlobalVariable &G : M->globals()) + if (G.hasInitializer()) + predictValueUseListOrder(G.getInitializer(), nullptr, OM, Stack); + for (const GlobalAlias &A : M->aliases()) + predictValueUseListOrder(A.getAliasee(), nullptr, OM, Stack); + for (const Function &F : *M) + if (F.hasPrefixData()) + predictValueUseListOrder(F.getPrefixData(), nullptr, OM, Stack); + + return Stack; +} + static const Module *getModuleFromVal(const Value *V) { if (const Argument *MA = dyn_cast(V)) - return MA->getParent() ? MA->getParent()->getParent() : 0; + return MA->getParent() ? MA->getParent()->getParent() : nullptr; if (const BasicBlock *BB = dyn_cast(V)) - return BB->getParent() ? BB->getParent()->getParent() : 0; + return BB->getParent() ? BB->getParent()->getParent() : nullptr; if (const Instruction *I = dyn_cast(V)) { - const Function *M = I->getParent() ? I->getParent()->getParent() : 0; - return M ? M->getParent() : 0; + const Function *M = I->getParent() ? I->getParent()->getParent() : nullptr; + return M ? M->getParent() : nullptr; } if (const GlobalValue *GV = dyn_cast(V)) return GV->getParent(); - return 0; + return nullptr; } static void PrintCallingConv(unsigned cc, raw_ostream &Out) { @@ -78,7 +285,7 @@ static void PrintCallingConv(unsigned cc, raw_ostream &Out) { case CallingConv::X86_StdCall: Out << "x86_stdcallcc"; break; case CallingConv::X86_FastCall: Out << "x86_fastcallcc"; break; case CallingConv::X86_ThisCall: Out << "x86_thiscallcc"; break; - case CallingConv::X86_CDeclMethod:Out << "x86_cdeclmethodcc"; break; + case CallingConv::X86_VectorCall:Out << "x86_vectorcallcc"; break; case CallingConv::Intel_OCL_BI: Out << "intel_ocl_bicc"; break; case CallingConv::ARM_APCS: Out << "arm_apcscc"; break; case CallingConv::ARM_AAPCS: Out << "arm_aapcscc"; break; @@ -107,6 +314,7 @@ static void PrintEscapedString(StringRef Name, raw_ostream &Out) { enum PrefixType { GlobalPrefix, + ComdatPrefix, LabelPrefix, LocalPrefix, NoPrefix @@ -120,6 +328,7 @@ static void PrintLLVMName(raw_ostream &OS, StringRef Name, PrefixType Prefix) { switch (Prefix) { case NoPrefix: break; case GlobalPrefix: OS << '@'; break; + case ComdatPrefix: OS << '$'; break; case LabelPrefix: break; case LocalPrefix: OS << '%'; break; } @@ -346,6 +555,8 @@ public: FunctionProcessed = false; } + const Function *getFunction() const { return TheFunction; } + /// After calling incorporateFunction, use this method to remove the /// most recently incorporated function from the SlotTracker. This /// will reset the state of the machine back to just the module contents. @@ -421,10 +632,10 @@ static SlotTracker *createSlotTracker(const Value *V) { if (!MD->isFunctionLocal()) return new SlotTracker(MD->getFunction()); - return new SlotTracker((Function *)0); + return new SlotTracker((Function *)nullptr); } - return 0; + return nullptr; } #if 0 @@ -436,21 +647,21 @@ static SlotTracker *createSlotTracker(const Value *V) { // Module level constructor. Causes the contents of the Module (sans functions) // to be added to the slot table. SlotTracker::SlotTracker(const Module *M) - : TheModule(M), TheFunction(0), FunctionProcessed(false), + : TheModule(M), TheFunction(nullptr), FunctionProcessed(false), mNext(0), fNext(0), mdnNext(0), asNext(0) { } // Function level constructor. Causes the contents of the Module and the one // function provided to be added to the slot table. SlotTracker::SlotTracker(const Function *F) - : TheModule(F ? F->getParent() : 0), TheFunction(F), FunctionProcessed(false), - mNext(0), fNext(0), mdnNext(0), asNext(0) { + : TheModule(F ? F->getParent() : nullptr), TheFunction(F), + FunctionProcessed(false), mNext(0), fNext(0), mdnNext(0), asNext(0) { } inline void SlotTracker::initialize() { if (TheModule) { processModule(); - TheModule = 0; ///< Prevent re-processing next time we're called. + TheModule = nullptr; ///< Prevent re-processing next time we're called. } if (TheFunction && !FunctionProcessed) @@ -560,7 +771,7 @@ void SlotTracker::processFunction() { void SlotTracker::purgeFunction() { ST_DEBUG("begin purgeFunction!\n"); fMap.clear(); // Simply discard the function level map - TheFunction = 0; + TheFunction = nullptr; FunctionProcessed = false; ST_DEBUG("end purgeFunction!\n"); } @@ -811,8 +1022,8 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, // output the string in hexadecimal format! Note that loading and storing // floating point types changes the bits of NaNs on some hosts, notably // x86, so we must not use these types. - assert(sizeof(double) == sizeof(uint64_t) && - "assuming that double is 64 bits!"); + static_assert(sizeof(double) == sizeof(uint64_t), + "assuming that double is 64 bits!"); char Buffer[40]; APFloat apf = CFP->getValueAPF(); // Halves and floats are represented in ASCII IR as double, convert. @@ -1048,7 +1259,7 @@ static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node, Out << "!{"; for (unsigned mi = 0, me = Node->getNumOperands(); mi != me; ++mi) { const Value *V = Node->getOperand(mi); - if (V == 0) + if (!V) Out << "null"; else { TypePrinter->print(V->getType(), Out); @@ -1126,12 +1337,6 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, return; } - if (V->getValueID() == Value::PseudoSourceValueVal || - V->getValueID() == Value::FixedStackPseudoSourceValueVal) { - V->print(Out); - return; - } - char Prefix = '%'; int Slot; // If we have a SlotTracker, use it. @@ -1160,7 +1365,7 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, Slot = Machine->getLocalSlot(V); } delete Machine; - Machine = 0; + Machine = nullptr; } else { Slot = -1; } @@ -1172,8 +1377,15 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, } void AssemblyWriter::init() { - if (TheModule) - TypePrinter.incorporateTypes(*TheModule); + if (!TheModule) + return; + TypePrinter.incorporateTypes(*TheModule); + for (const Function &F : *TheModule) + if (const Comdat *C = F.getComdat()) + Comdats.insert(C); + for (const GlobalVariable &GV : TheModule->globals()) + if (const Comdat *C = GV.getComdat()) + Comdats.insert(C); } @@ -1194,7 +1406,7 @@ AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, const Module *M, AssemblyWriter::~AssemblyWriter() { } void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType) { - if (Operand == 0) { + if (!Operand) { Out << ""; return; } @@ -1226,9 +1438,40 @@ void AssemblyWriter::writeAtomic(AtomicOrdering Ordering, } } +void AssemblyWriter::writeAtomicCmpXchg(AtomicOrdering SuccessOrdering, + AtomicOrdering FailureOrdering, + SynchronizationScope SynchScope) { + assert(SuccessOrdering != NotAtomic && FailureOrdering != NotAtomic); + + switch (SynchScope) { + case SingleThread: Out << " singlethread"; break; + case CrossThread: break; + } + + switch (SuccessOrdering) { + default: Out << " "; break; + case Unordered: Out << " unordered"; break; + case Monotonic: Out << " monotonic"; break; + case Acquire: Out << " acquire"; break; + case Release: Out << " release"; break; + case AcquireRelease: Out << " acq_rel"; break; + case SequentiallyConsistent: Out << " seq_cst"; break; + } + + switch (FailureOrdering) { + default: Out << " "; break; + case Unordered: Out << " unordered"; break; + case Monotonic: Out << " monotonic"; break; + case Acquire: Out << " acquire"; break; + case Release: Out << " release"; break; + case AcquireRelease: Out << " acq_rel"; break; + case SequentiallyConsistent: Out << " seq_cst"; break; + } +} + void AssemblyWriter::writeParamOperand(const Value *Operand, AttributeSet Attrs, unsigned Idx) { - if (Operand == 0) { + if (!Operand) { Out << ""; return; } @@ -1246,6 +1489,9 @@ void AssemblyWriter::writeParamOperand(const Value *Operand, void AssemblyWriter::printModule(const Module *M) { Machine.initialize(); + if (shouldPreserveAssemblyUseListOrder()) + UseListOrders = predictUseListOrder(M); + if (!M->getModuleIdentifier().empty() && // Don't print the ID if it will start a new line (which would // require a comment char before it). @@ -1284,6 +1530,15 @@ void AssemblyWriter::printModule(const Module *M) { printTypeIdentities(); + // Output all comdats. + if (!Comdats.empty()) + Out << '\n'; + for (const Comdat *C : Comdats) { + printComdat(C); + if (C != Comdats.back()) + Out << '\n'; + } + // Output all globals. if (!M->global_empty()) Out << '\n'; for (Module::const_global_iterator I = M->global_begin(), E = M->global_end(); @@ -1297,9 +1552,13 @@ void AssemblyWriter::printModule(const Module *M) { I != E; ++I) printAlias(I); + // Output global use-lists. + printUseLists(nullptr); + // Output all of the functions. for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) printFunction(I); + assert(UseListOrders.empty() && "All use-lists should have been consumed"); // Output all attribute groups. if (!Machine.as_empty()) { @@ -1360,10 +1619,6 @@ static void PrintLinkage(GlobalValue::LinkageTypes LT, switch (LT) { case GlobalValue::ExternalLinkage: break; case GlobalValue::PrivateLinkage: Out << "private "; break; - case GlobalValue::LinkerPrivateLinkage: Out << "linker_private "; break; - case GlobalValue::LinkerPrivateWeakLinkage: - Out << "linker_private_weak "; - break; case GlobalValue::InternalLinkage: Out << "internal "; break; case GlobalValue::LinkOnceAnyLinkage: Out << "linkonce "; break; case GlobalValue::LinkOnceODRLinkage: Out << "linkonce_odr "; break; @@ -1431,10 +1686,11 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) { PrintVisibility(GV->getVisibility(), Out); PrintDLLStorageClass(GV->getDLLStorageClass(), Out); PrintThreadLocalModel(GV->getThreadLocalMode(), Out); + if (GV->hasUnnamedAddr()) + Out << "unnamed_addr "; if (unsigned AddressSpace = GV->getType()->getAddressSpace()) Out << "addrspace(" << AddressSpace << ") "; - if (GV->hasUnnamedAddr()) Out << "unnamed_addr "; if (GV->isExternallyInitialized()) Out << "externally_initialized "; Out << (GV->isConstant() ? "constant " : "global "); TypePrinter.print(GV->getType()->getElementType(), Out); @@ -1449,6 +1705,10 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) { PrintEscapedString(GV->getSection(), Out); Out << '"'; } + if (GV->hasComdat()) { + Out << ", comdat "; + PrintLLVMName(Out, GV->getComdat()->getName(), ComdatPrefix); + } if (GV->getAlignment()) Out << ", align " << GV->getAlignment(); @@ -1466,16 +1726,18 @@ void AssemblyWriter::printAlias(const GlobalAlias *GA) { PrintLLVMName(Out, GA); Out << " = "; } + PrintLinkage(GA->getLinkage(), Out); PrintVisibility(GA->getVisibility(), Out); PrintDLLStorageClass(GA->getDLLStorageClass(), Out); + PrintThreadLocalModel(GA->getThreadLocalMode(), Out); + if (GA->hasUnnamedAddr()) + Out << "unnamed_addr "; Out << "alias "; - PrintLinkage(GA->getLinkage(), Out); - const Constant *Aliasee = GA->getAliasee(); - if (Aliasee == 0) { + if (!Aliasee) { TypePrinter.print(GA->getType(), Out); Out << " <>"; } else { @@ -1486,6 +1748,10 @@ void AssemblyWriter::printAlias(const GlobalAlias *GA) { Out << '\n'; } +void AssemblyWriter::printComdat(const Comdat *C) { + C->print(Out); +} + void AssemblyWriter::printTypeIdentities() { if (TypePrinter.NumberedTypes.empty() && TypePrinter.NamedTypes.empty()) @@ -1623,6 +1889,10 @@ void AssemblyWriter::printFunction(const Function *F) { PrintEscapedString(F->getSection(), Out); Out << '"'; } + if (F->hasComdat()) { + Out << " comdat "; + PrintLLVMName(Out, F->getComdat()->getName(), ComdatPrefix); + } if (F->getAlignment()) Out << " align " << F->getAlignment(); if (F->hasGC()) @@ -1639,6 +1909,9 @@ void AssemblyWriter::printFunction(const Function *F) { for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I) printBasicBlock(I); + // Output the function's use-lists. + printUseLists(F); + Out << "}\n"; } @@ -1680,7 +1953,7 @@ void AssemblyWriter::printBasicBlock(const BasicBlock *BB) { Out << ""; } - if (BB->getParent() == 0) { + if (!BB->getParent()) { Out.PadToColumn(50); Out << "; Error: Block without parent!"; } else if (BB != &BB->getParent()->getEntryBlock()) { // Not the entry block? @@ -1747,8 +2020,12 @@ void AssemblyWriter::printInstruction(const Instruction &I) { Out << '%' << SlotNum << " = "; } - if (isa(I) && cast(I).isTailCall()) - Out << "tail "; + if (const CallInst *CI = dyn_cast(&I)) { + if (CI->isMustTailCall()) + Out << "musttail "; + else if (CI->isTailCall()) + Out << "tail "; + } // Print out the opcode... Out << I.getOpcodeName(); @@ -1758,6 +2035,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) { (isa(I) && cast(I).isAtomic())) Out << " atomic"; + if (isa(I) && cast(I).isWeak()) + Out << " weak"; + // If this is a volatile operation, print out the volatile marker. if ((isa(I) && cast(I).isVolatile()) || (isa(I) && cast(I).isVolatile()) || @@ -1777,7 +2057,7 @@ void AssemblyWriter::printInstruction(const Instruction &I) { writeAtomicRMWOperation(Out, RMWI->getOperation()); // Print out the type of the operands... - const Value *Operand = I.getNumOperands() ? I.getOperand(0) : 0; + const Value *Operand = I.getNumOperands() ? I.getOperand(0) : nullptr; // Special case conditional branches to swizzle the condition out to the front if (isa(I) && cast(I).isConditional()) { @@ -1895,6 +2175,14 @@ void AssemblyWriter::printInstruction(const Instruction &I) { Out << ", "; writeParamOperand(CI->getArgOperand(op), PAL, op + 1); } + + // Emit an ellipsis if this is a musttail call in a vararg function. This + // is only to aid readability, musttail calls forward varargs by default. + if (CI->isMustTailCall() && CI->getParent() && + CI->getParent()->getParent() && + CI->getParent()->getParent()->isVarArg()) + Out << ", ..."; + Out << ')'; if (PAL.hasAttributes(AttributeSet::FunctionIndex)) Out << " #" << Machine.getAttributeGroupSlot(PAL.getFnAttributes()); @@ -2018,7 +2306,8 @@ void AssemblyWriter::printInstruction(const Instruction &I) { if (SI->getAlignment()) Out << ", align " << SI->getAlignment(); } else if (const AtomicCmpXchgInst *CXI = dyn_cast(&I)) { - writeAtomic(CXI->getOrdering(), CXI->getSynchScope()); + writeAtomicCmpXchg(CXI->getSuccessOrdering(), CXI->getFailureOrdering(), + CXI->getSynchScope()); } else if (const AtomicRMWInst *RMWI = dyn_cast(&I)) { writeAtomic(RMWI->getOrdering(), RMWI->getSynchScope()); } else if (const FenceInst *FI = dyn_cast(&I)) { @@ -2052,7 +2341,7 @@ static void WriteMDNodeComment(const MDNode *Node, return; Value *Op = Node->getOperand(0); - if (!Op || !isa(Op) || cast(Op)->getBitWidth() < 32) + if (!Op || !isa(Op)) return; DIDescriptor Desc(Node); @@ -2108,6 +2397,45 @@ void AssemblyWriter::writeAllAttributeGroups() { } // namespace llvm +void AssemblyWriter::printUseListOrder(const UseListOrder &Order) { + bool IsInFunction = Machine.getFunction(); + if (IsInFunction) + Out << " "; + + Out << "uselistorder"; + if (const BasicBlock *BB = + IsInFunction ? nullptr : dyn_cast(Order.V)) { + Out << "_bb "; + writeOperand(BB->getParent(), false); + Out << ", "; + writeOperand(BB, false); + } else { + Out << " "; + writeOperand(Order.V, true); + } + Out << ", { "; + + assert(Order.Shuffle.size() >= 2 && "Shuffle too small"); + Out << Order.Shuffle[0]; + for (unsigned I = 1, E = Order.Shuffle.size(); I != E; ++I) + Out << ", " << Order.Shuffle[I]; + Out << " }\n"; +} + +void AssemblyWriter::printUseLists(const Function *F) { + auto hasMore = + [&]() { return !UseListOrders.empty() && UseListOrders.back().F == F; }; + if (!hasMore()) + // Nothing to do. + return; + + Out << "\n; uselistorder directives\n"; + while (hasMore()) { + printUseListOrder(UseListOrders.back()); + UseListOrders.pop_back(); + } +} + //===----------------------------------------------------------------------===// // External Interface declarations //===----------------------------------------------------------------------===// @@ -2119,18 +2447,39 @@ void Module::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW) const { W.printModule(this); } -void NamedMDNode::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW) const { +void NamedMDNode::print(raw_ostream &ROS) const { SlotTracker SlotTable(getParent()); formatted_raw_ostream OS(ROS); - AssemblyWriter W(OS, SlotTable, getParent(), AAW); + AssemblyWriter W(OS, SlotTable, getParent(), nullptr); W.printNamedMDNode(this); } -void Type::print(raw_ostream &OS) const { - if (this == 0) { - OS << ""; - return; +void Comdat::print(raw_ostream &ROS) const { + PrintLLVMName(ROS, getName(), ComdatPrefix); + ROS << " = comdat "; + + switch (getSelectionKind()) { + case Comdat::Any: + ROS << "any"; + break; + case Comdat::ExactMatch: + ROS << "exactmatch"; + break; + case Comdat::Largest: + ROS << "largest"; + break; + case Comdat::NoDuplicates: + ROS << "noduplicates"; + break; + case Comdat::SameSize: + ROS << "samesize"; + break; } + + ROS << '\n'; +} + +void Type::print(raw_ostream &OS) const { TypePrinting TP; TP.print(const_cast(this), OS); @@ -2142,24 +2491,20 @@ void Type::print(raw_ostream &OS) const { } } -void Value::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW) const { - if (this == 0) { - ROS << "printing a value\n"; - return; - } +void Value::print(raw_ostream &ROS) const { formatted_raw_ostream OS(ROS); if (const Instruction *I = dyn_cast(this)) { - const Function *F = I->getParent() ? I->getParent()->getParent() : 0; + const Function *F = I->getParent() ? I->getParent()->getParent() : nullptr; SlotTracker SlotTable(F); - AssemblyWriter W(OS, SlotTable, getModuleFromVal(I), AAW); + AssemblyWriter W(OS, SlotTable, getModuleFromVal(I), nullptr); W.printInstruction(*I); } else if (const BasicBlock *BB = dyn_cast(this)) { SlotTracker SlotTable(BB->getParent()); - AssemblyWriter W(OS, SlotTable, getModuleFromVal(BB), AAW); + AssemblyWriter W(OS, SlotTable, getModuleFromVal(BB), nullptr); W.printBasicBlock(BB); } else if (const GlobalValue *GV = dyn_cast(this)) { SlotTracker SlotTable(GV->getParent()); - AssemblyWriter W(OS, SlotTable, GV->getParent(), AAW); + AssemblyWriter W(OS, SlotTable, GV->getParent(), nullptr); if (const GlobalVariable *V = dyn_cast(GV)) W.printGlobal(V); else if (const Function *F = dyn_cast(GV)) @@ -2169,20 +2514,18 @@ void Value::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW) const { } else if (const MDNode *N = dyn_cast(this)) { const Function *F = N->getFunction(); SlotTracker SlotTable(F); - AssemblyWriter W(OS, SlotTable, F ? F->getParent() : 0, AAW); + AssemblyWriter W(OS, SlotTable, F ? F->getParent() : nullptr, nullptr); W.printMDNodeBody(N); } else if (const Constant *C = dyn_cast(this)) { TypePrinting TypePrinter; TypePrinter.print(C->getType(), OS); OS << ' '; - WriteConstantInternal(OS, C, TypePrinter, 0, 0); + WriteConstantInternal(OS, C, TypePrinter, nullptr, nullptr); } else if (isa(this) || isa(this) || isa(this)) { this->printAsOperand(OS); } else { - // Otherwise we don't know what it is. Call the virtual function to - // allow a subclass to print itself. - printCustom(OS); + llvm_unreachable("Unknown value to print out!"); } } @@ -2192,7 +2535,7 @@ void Value::printAsOperand(raw_ostream &O, bool PrintType, const Module *M) cons if (!PrintType && ((!isa(this) && !isa(this)) || hasName() || isa(this))) { - WriteAsOperandInternal(O, this, 0, 0, M); + WriteAsOperandInternal(O, this, nullptr, nullptr, M); return; } @@ -2207,22 +2550,20 @@ void Value::printAsOperand(raw_ostream &O, bool PrintType, const Module *M) cons O << ' '; } - WriteAsOperandInternal(O, this, &TypePrinter, 0, M); -} - -// Value::printCustom - subclasses should override this to implement printing. -void Value::printCustom(raw_ostream &OS) const { - llvm_unreachable("Unknown value to print out!"); + WriteAsOperandInternal(O, this, &TypePrinter, nullptr, M); } // Value::dump - allow easy printing of Values from the debugger. void Value::dump() const { print(dbgs()); dbgs() << '\n'; } // Type::dump - allow easy printing of Types from the debugger. -void Type::dump() const { print(dbgs()); } +void Type::dump() const { print(dbgs()); dbgs() << '\n'; } // Module::dump() - Allow printing of Modules from the debugger. -void Module::dump() const { print(dbgs(), 0); } +void Module::dump() const { print(dbgs(), nullptr); } + +// \brief Allow printing of Comdats from the debugger. +void Comdat::dump() const { print(dbgs()); } // NamedMDNode::dump() - Allow printing of NamedMDNodes from the debugger. -void NamedMDNode::dump() const { print(dbgs(), 0); } +void NamedMDNode::dump() const { print(dbgs()); }