@@ -59,6 +59,113 @@ using namespace mlir::LLVM::detail;
5959
6060#include " mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
6161
62+ namespace {
63+ // / A customized inserter for LLVM's IRBuilder that captures all LLVM IR
64+ // / instructions that are created for future reference.
65+ // /
66+ // / This is intended to be used with the `CollectionScope` RAII object:
67+ // /
68+ // / llvm::IRBuilder<..., InstructionCapturingInserter> builder;
69+ // / {
70+ // / InstructionCapturingInserter::CollectionScope scope(builder);
71+ // / // Call IRBuilder methods as usual.
72+ // /
73+ // / // This will return a list of all instructions created by the builder,
74+ // / // in order of creation.
75+ // / builder.getInserter().getCapturedInstructions();
76+ // / }
77+ // / // This will return an empty list.
78+ // / builder.getInserter().getCapturedInstructions();
79+ // /
80+ // / The capturing functionality is _disabled_ by default for performance
81+ // / consideration. It needs to be explicitly enabled, which is achieved by
82+ // / creating a `CollectionScope`.
83+ class InstructionCapturingInserter : public llvm ::IRBuilderCallbackInserter {
84+ public:
85+ // / Constructs the inserter.
86+ InstructionCapturingInserter ()
87+ : llvm::IRBuilderCallbackInserter([this ](llvm::Instruction *instruction) {
88+ if (LLVM_LIKELY (enabled))
89+ capturedInstructions.push_back (instruction);
90+ }) {}
91+
92+ // / Returns the list of LLVM IR instructions captured since the last cleanup.
93+ ArrayRef<llvm::Instruction *> getCapturedInstructions () const {
94+ return capturedInstructions;
95+ }
96+
97+ // / Clears the list of captured LLVM IR instructions.
98+ void clearCapturedInstructions () { capturedInstructions.clear (); }
99+
100+ // / RAII object enabling the capture of created LLVM IR instructions.
101+ class CollectionScope {
102+ public:
103+ // / Creates the scope for the given inserter.
104+ CollectionScope (llvm::IRBuilderBase &irBuilder, bool isBuilderCapturing);
105+
106+ // / Ends the scope.
107+ ~CollectionScope ();
108+
109+ ArrayRef<llvm::Instruction *> getCapturedInstructions () {
110+ if (!inserter)
111+ return {};
112+ return inserter->getCapturedInstructions ();
113+ }
114+
115+ private:
116+ // / Back reference to the inserter.
117+ InstructionCapturingInserter *inserter = nullptr ;
118+
119+ // / List of instructions in the inserter prior to this scope.
120+ SmallVector<llvm::Instruction *> previouslyCollectedInstructions;
121+
122+ // / Whether the inserter was enabled prior to this scope.
123+ bool wasEnabled;
124+ };
125+
126+ // / Enable or disable the capturing mechanism.
127+ void setEnabled (bool enabled = true ) { this ->enabled = enabled; }
128+
129+ private:
130+ // / List of captured instructions.
131+ SmallVector<llvm::Instruction *> capturedInstructions;
132+
133+ // / Whether the collection is enabled.
134+ bool enabled = false ;
135+ };
136+
137+ using CapturingIRBuilder =
138+ llvm::IRBuilder<llvm::ConstantFolder, InstructionCapturingInserter>;
139+ } // namespace
140+
141+ InstructionCapturingInserter::CollectionScope::CollectionScope (
142+ llvm::IRBuilderBase &irBuilder, bool isBuilderCapturing) {
143+
144+ if (!isBuilderCapturing)
145+ return ;
146+
147+ auto &capturingIRBuilder = static_cast <CapturingIRBuilder &>(irBuilder);
148+ inserter = &capturingIRBuilder.getInserter ();
149+ wasEnabled = inserter->enabled ;
150+ if (wasEnabled)
151+ previouslyCollectedInstructions.swap (inserter->capturedInstructions );
152+ inserter->setEnabled (true );
153+ }
154+
155+ InstructionCapturingInserter::CollectionScope::~CollectionScope () {
156+ if (!inserter)
157+ return ;
158+
159+ previouslyCollectedInstructions.swap (inserter->capturedInstructions );
160+ // If collection was enabled (likely in another, surrounding scope), keep
161+ // the instructions collected in this scope.
162+ if (wasEnabled) {
163+ llvm::append_range (inserter->capturedInstructions ,
164+ previouslyCollectedInstructions);
165+ }
166+ inserter->setEnabled (wasEnabled);
167+ }
168+
62169// / Translates the given data layout spec attribute to the LLVM IR data layout.
63170// / Only integer, float, pointer and endianness entries are currently supported.
64171static FailureOr<llvm::DataLayout>
@@ -631,21 +738,23 @@ llvm::CallInst *mlir::LLVM::detail::createIntrinsicCall(
631738
632739// / Given a single MLIR operation, create the corresponding LLVM IR operation
633740// / using the `builder`.
634- LogicalResult
635- ModuleTranslation::convertOperation (Operation &op ,
636- llvm::IRBuilderBase &builder ) {
741+ LogicalResult ModuleTranslation::convertOperation (Operation &op,
742+ llvm::IRBuilderBase &builder ,
743+ bool recordInsertions ) {
637744 const LLVMTranslationDialectInterface *opIface = iface.getInterfaceFor (&op);
638745 if (!opIface)
639746 return op.emitError (" cannot be converted to LLVM IR: missing "
640747 " `LLVMTranslationDialectInterface` registration for "
641748 " dialect for op: " )
642749 << op.getName ();
643750
751+ InstructionCapturingInserter::CollectionScope scope (builder,
752+ recordInsertions);
644753 if (failed (opIface->convertOperation (&op, builder, *this )))
645754 return op.emitError (" LLVM Translation failed for operation: " )
646755 << op.getName ();
647756
648- return convertDialectAttributes (&op);
757+ return convertDialectAttributes (&op, scope. getCapturedInstructions () );
649758}
650759
651760// / Convert block to LLVM IR. Unless `ignoreArguments` is set, emit PHI nodes
@@ -655,8 +764,10 @@ ModuleTranslation::convertOperation(Operation &op,
655764// / been created for `bb` and included in the block mapping. Inserts new
656765// / instructions at the end of the block and leaves `builder` in a state
657766// / suitable for further insertion into the end of the block.
658- LogicalResult ModuleTranslation::convertBlock (Block &bb, bool ignoreArguments,
659- llvm::IRBuilderBase &builder) {
767+ LogicalResult ModuleTranslation::convertBlockImpl (Block &bb,
768+ bool ignoreArguments,
769+ llvm::IRBuilderBase &builder,
770+ bool recordInsertions) {
660771 builder.SetInsertPoint (lookupBlock (&bb));
661772 auto *subprogram = builder.GetInsertBlock ()->getParent ()->getSubprogram ();
662773
@@ -687,7 +798,7 @@ LogicalResult ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments,
687798 builder.SetCurrentDebugLocation (
688799 debugTranslation->translateLoc (op.getLoc (), subprogram));
689800
690- if (failed (convertOperation (op, builder)))
801+ if (failed (convertOperation (op, builder, recordInsertions )))
691802 return failure ();
692803
693804 // Set the branch weight metadata on the translated instruction.
@@ -844,7 +955,7 @@ LogicalResult ModuleTranslation::convertGlobals() {
844955 }
845956
846957 for (auto op : getModuleBody (mlirModule).getOps <LLVM::GlobalOp>())
847- if (failed (convertDialectAttributes (op)))
958+ if (failed (convertDialectAttributes (op, {} )))
848959 return failure ();
849960
850961 // Finally, update the compile units their respective sets of global variables
@@ -997,8 +1108,9 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
9971108 // converted before uses.
9981109 auto blocks = getTopologicallySortedBlocks (func.getBody ());
9991110 for (Block *bb : blocks) {
1000- llvm::IRBuilder<> builder (llvmContext);
1001- if (failed (convertBlock (*bb, bb->isEntryBlock (), builder)))
1111+ CapturingIRBuilder builder (llvmContext);
1112+ if (failed (convertBlockImpl (*bb, bb->isEntryBlock (), builder,
1113+ /* recordInsertions=*/ true )))
10021114 return failure ();
10031115 }
10041116
@@ -1007,12 +1119,13 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
10071119 detail::connectPHINodes (func.getBody (), *this );
10081120
10091121 // Finally, convert dialect attributes attached to the function.
1010- return convertDialectAttributes (func);
1122+ return convertDialectAttributes (func, {} );
10111123}
10121124
1013- LogicalResult ModuleTranslation::convertDialectAttributes (Operation *op) {
1125+ LogicalResult ModuleTranslation::convertDialectAttributes (
1126+ Operation *op, ArrayRef<llvm::Instruction *> instructions) {
10141127 for (NamedAttribute attribute : op->getDialectAttrs ())
1015- if (failed (iface.amendOperation (op, attribute, *this )))
1128+ if (failed (iface.amendOperation (op, instructions, attribute, *this )))
10161129 return failure ();
10171130 return success ();
10181131}
@@ -1134,7 +1247,7 @@ LogicalResult ModuleTranslation::convertFunctions() {
11341247 // Do not convert external functions, but do process dialect attributes
11351248 // attached to them.
11361249 if (function.isExternal ()) {
1137- if (failed (convertDialectAttributes (function)))
1250+ if (failed (convertDialectAttributes (function, {} )))
11381251 return failure ();
11391252 continue ;
11401253 }
0 commit comments