diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -288,8 +288,8 @@ /// Print the basic block to an output stream with an optional /// AssemblyAnnotationWriter. void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW = nullptr, - bool ShouldPreserveUseListOrder = false, - bool IsForDebug = false) const; + bool ShouldPreserveUseListOrder = false, bool IsForDebug = false, + bool AnnotateUsers = false) const; //===--------------------------------------------------------------------===// /// Instruction iterator methods diff --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h --- a/llvm/include/llvm/IR/Function.h +++ b/llvm/include/llvm/IR/Function.h @@ -803,8 +803,8 @@ /// Print the function to an output stream with an optional /// AssemblyAnnotationWriter. void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW = nullptr, - bool ShouldPreserveUseListOrder = false, - bool IsForDebug = false) const; + bool ShouldPreserveUseListOrder = false, bool IsForDebug = false, + bool AnnotateUsers = false) const; /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -802,8 +802,8 @@ /// uselistorder directives so that use-lists can be recreated when reading /// the assembly. void print(raw_ostream &OS, AssemblyAnnotationWriter *AAW, - bool ShouldPreserveUseListOrder = false, - bool IsForDebug = false) const; + bool ShouldPreserveUseListOrder = false, bool IsForDebug = false, + bool AnnotateUsers = false) const; /// Dump the module to stderr (for debugging). void dump() const; diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -664,6 +664,9 @@ bool FunctionProcessed = false; bool ShouldInitializeAllMetadata; + /// Assign slot numbers for void type instructions + bool IncludeVoidInstructions; + std::function ProcessModuleHookFn; std::function @@ -707,7 +710,8 @@ /// functions, giving correct numbering for metadata referenced only from /// within a function (even if no functions have been initialized). explicit SlotTracker(const Module *M, - bool ShouldInitializeAllMetadata = false); + bool ShouldInitializeAllMetadata = false, + bool IncludeVoidInstructions = false); /// Construct from a function, starting out in incorp state. /// @@ -715,7 +719,8 @@ /// functions, giving correct numbering for metadata referenced only from /// within a function (even if no functions have been initialized). explicit SlotTracker(const Function *F, - bool ShouldInitializeAllMetadata = false); + bool ShouldInitializeAllMetadata = false, + bool IncludeVoidInstructions = false); /// Construct from a module summary index. explicit SlotTracker(const ModuleSummaryIndex *Index); @@ -911,17 +916,22 @@ // Module level constructor. Causes the contents of the Module (sans functions) // to be added to the slot table. -SlotTracker::SlotTracker(const Module *M, bool ShouldInitializeAllMetadata) - : TheModule(M), ShouldInitializeAllMetadata(ShouldInitializeAllMetadata) {} +SlotTracker::SlotTracker(const Module *M, bool ShouldInitializeAllMetadata, + bool IncludeVoidInstructions) + : TheModule(M), ShouldInitializeAllMetadata(ShouldInitializeAllMetadata), + IncludeVoidInstructions(IncludeVoidInstructions) {} // 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, bool ShouldInitializeAllMetadata) +SlotTracker::SlotTracker(const Function *F, bool ShouldInitializeAllMetadata, + bool IncludeVoidInstructions) : TheModule(F ? F->getParent() : nullptr), TheFunction(F), - ShouldInitializeAllMetadata(ShouldInitializeAllMetadata) {} + ShouldInitializeAllMetadata(ShouldInitializeAllMetadata), + IncludeVoidInstructions(IncludeVoidInstructions) {} SlotTracker::SlotTracker(const ModuleSummaryIndex *Index) - : TheModule(nullptr), ShouldInitializeAllMetadata(false), TheIndex(Index) {} + : TheModule(nullptr), ShouldInitializeAllMetadata(false), + IncludeVoidInstructions(false), TheIndex(Index) {} inline void SlotTracker::initializeIfNeeded() { if (TheModule) { @@ -1016,7 +1026,7 @@ CreateFunctionSlot(&BB); for (auto &I : BB) { - if (!I.getType()->isVoidTy() && !I.hasName()) + if ((!I.getType()->isVoidTy() || IncludeVoidInstructions) && !I.hasName()) CreateFunctionSlot(&I); // We allow direct calls to any llvm.foo function here, because the @@ -2529,6 +2539,7 @@ SetVector Comdats; bool IsForDebug; bool ShouldPreserveUseListOrder; + bool AnnotateUsers; UseListOrderMap UseListOrders; SmallVector MDNames; /// Synchronization scope names registered with LLVMContext. @@ -2539,7 +2550,8 @@ /// Construct an AssemblyWriter with an external SlotTracker AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const Module *M, AssemblyAnnotationWriter *AAW, bool IsForDebug, - bool ShouldPreserveUseListOrder = false); + bool ShouldPreserveUseListOrder = false, + bool AnnotateUsers = false); AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const ModuleSummaryIndex *Index, bool IsForDebug); @@ -2616,6 +2628,10 @@ // which slot it occupies. void printInfoComment(const Value &V); + // printUsersComment - Print a comment indicating the users of the result of + // this value + void printUsersComment(const Value &V); + // printGCRelocateComment - print comment after call to the gc.relocate // intrinsic indicating base and derived pointer names. void printGCRelocateComment(const GCRelocateInst &Relocate); @@ -2625,10 +2641,12 @@ AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const Module *M, AssemblyAnnotationWriter *AAW, - bool IsForDebug, bool ShouldPreserveUseListOrder) + bool IsForDebug, bool ShouldPreserveUseListOrder, + bool AnnotateUsers) : Out(o), TheModule(M), Machine(Mac), TypePrinter(M), AnnotationWriter(AAW), IsForDebug(IsForDebug), - ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) { + ShouldPreserveUseListOrder(ShouldPreserveUseListOrder), + AnnotateUsers(AnnotateUsers) { if (!TheModule) return; for (const GlobalObject &GO : TheModule->global_objects()) @@ -2639,7 +2657,8 @@ AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const ModuleSummaryIndex *Index, bool IsForDebug) : Out(o), TheIndex(Index), Machine(Mac), TypePrinter(/*Module=*/nullptr), - IsForDebug(IsForDebug), ShouldPreserveUseListOrder(false) {} + IsForDebug(IsForDebug), ShouldPreserveUseListOrder(false), + AnnotateUsers(false) {} void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType) { if (!Operand) { @@ -3787,6 +3806,17 @@ printMetadataAttachments(MDs, " "); Out << " {"; + + // Print users comments for arguments + if (AnnotateUsers) { + for (auto &Arg : F->args()) { + Out << "\n"; + int SlotNum = Machine.getLocalSlot(&Arg); + Out << "; %" << SlotNum; + printUsersComment(Arg); + } + } + // Output all of the function's basic blocks. for (const BasicBlock &BB : *F) printBasicBlock(&BB); @@ -4343,6 +4373,40 @@ // Print a nice comment. printInfoComment(I); + + // Print out slot number for void instructions and users otherwise + if (AnnotateUsers) { + if (I.getType()->isVoidTy()) { + Out.PadToColumn(50); + Out << "; id = %"; + if (I.hasName()) + Out << I.getName(); + else + Out << Machine.getLocalSlot(&I); + } else { + printUsersComment(I); + } + } +} + +void AssemblyWriter::printUsersComment(const Value &V) { + + if (V.user_empty()) + return; + + Out.PadToColumn(50); + Out << "; " << (V.hasOneUser() ? "user" : "users") << " = "; + for (auto U = V.user_begin(); U != V.user_end(); U++) { + if (U != V.user_begin()) + Out << ", "; + + Out << "%"; + if (U->hasName()) { + Out << U->getName(); + } else { + Out << Machine.getLocalSlot(*U); + } + } } void AssemblyWriter::printMetadataAttachments( @@ -4467,33 +4531,32 @@ //===----------------------------------------------------------------------===// void Function::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW, - bool ShouldPreserveUseListOrder, - bool IsForDebug) const { - SlotTracker SlotTable(this->getParent()); + bool ShouldPreserveUseListOrder, bool IsForDebug, + bool AnnotateUsers) const { + SlotTracker SlotTable(this->getParent(), false, AnnotateUsers); formatted_raw_ostream OS(ROS); - AssemblyWriter W(OS, SlotTable, this->getParent(), AAW, - IsForDebug, - ShouldPreserveUseListOrder); + AssemblyWriter W(OS, SlotTable, this->getParent(), AAW, IsForDebug, + ShouldPreserveUseListOrder, AnnotateUsers); W.printFunction(this); } void BasicBlock::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW, - bool ShouldPreserveUseListOrder, - bool IsForDebug) const { - SlotTracker SlotTable(this->getParent()); + bool ShouldPreserveUseListOrder, bool IsForDebug, + bool AnnotateUsers) const { + SlotTracker SlotTable(this->getParent(), false, AnnotateUsers); formatted_raw_ostream OS(ROS); - AssemblyWriter W(OS, SlotTable, this->getModule(), AAW, - IsForDebug, - ShouldPreserveUseListOrder); + AssemblyWriter W(OS, SlotTable, this->getModule(), AAW, IsForDebug, + ShouldPreserveUseListOrder, AnnotateUsers); W.printBasicBlock(this); } void Module::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW, - bool ShouldPreserveUseListOrder, bool IsForDebug) const { - SlotTracker SlotTable(this); + bool ShouldPreserveUseListOrder, bool IsForDebug, + bool AnnotateUsers) const { + SlotTracker SlotTable(this, false, AnnotateUsers); formatted_raw_ostream OS(ROS); AssemblyWriter W(OS, SlotTable, this, AAW, IsForDebug, - ShouldPreserveUseListOrder); + ShouldPreserveUseListOrder, AnnotateUsers); W.printModule(this); }