@@ -59,6 +59,113 @@ using namespace mlir::LLVM::detail;
59
59
60
60
#include " mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
61
61
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
+
62
169
// / Translates the given data layout spec attribute to the LLVM IR data layout.
63
170
// / Only integer, float, pointer and endianness entries are currently supported.
64
171
static FailureOr<llvm::DataLayout>
@@ -631,21 +738,23 @@ llvm::CallInst *mlir::LLVM::detail::createIntrinsicCall(
631
738
632
739
// / Given a single MLIR operation, create the corresponding LLVM IR operation
633
740
// / 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 ) {
637
744
const LLVMTranslationDialectInterface *opIface = iface.getInterfaceFor (&op);
638
745
if (!opIface)
639
746
return op.emitError (" cannot be converted to LLVM IR: missing "
640
747
" `LLVMTranslationDialectInterface` registration for "
641
748
" dialect for op: " )
642
749
<< op.getName ();
643
750
751
+ InstructionCapturingInserter::CollectionScope scope (builder,
752
+ recordInsertions);
644
753
if (failed (opIface->convertOperation (&op, builder, *this )))
645
754
return op.emitError (" LLVM Translation failed for operation: " )
646
755
<< op.getName ();
647
756
648
- return convertDialectAttributes (&op);
757
+ return convertDialectAttributes (&op, scope. getCapturedInstructions () );
649
758
}
650
759
651
760
// / Convert block to LLVM IR. Unless `ignoreArguments` is set, emit PHI nodes
@@ -655,8 +764,10 @@ ModuleTranslation::convertOperation(Operation &op,
655
764
// / been created for `bb` and included in the block mapping. Inserts new
656
765
// / instructions at the end of the block and leaves `builder` in a state
657
766
// / 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) {
660
771
builder.SetInsertPoint (lookupBlock (&bb));
661
772
auto *subprogram = builder.GetInsertBlock ()->getParent ()->getSubprogram ();
662
773
@@ -687,7 +798,7 @@ LogicalResult ModuleTranslation::convertBlock(Block &bb, bool ignoreArguments,
687
798
builder.SetCurrentDebugLocation (
688
799
debugTranslation->translateLoc (op.getLoc (), subprogram));
689
800
690
- if (failed (convertOperation (op, builder)))
801
+ if (failed (convertOperation (op, builder, recordInsertions )))
691
802
return failure ();
692
803
693
804
// Set the branch weight metadata on the translated instruction.
@@ -844,7 +955,7 @@ LogicalResult ModuleTranslation::convertGlobals() {
844
955
}
845
956
846
957
for (auto op : getModuleBody (mlirModule).getOps <LLVM::GlobalOp>())
847
- if (failed (convertDialectAttributes (op)))
958
+ if (failed (convertDialectAttributes (op, {} )))
848
959
return failure ();
849
960
850
961
// Finally, update the compile units their respective sets of global variables
@@ -997,8 +1108,9 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
997
1108
// converted before uses.
998
1109
auto blocks = getTopologicallySortedBlocks (func.getBody ());
999
1110
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 )))
1002
1114
return failure ();
1003
1115
}
1004
1116
@@ -1007,12 +1119,13 @@ LogicalResult ModuleTranslation::convertOneFunction(LLVMFuncOp func) {
1007
1119
detail::connectPHINodes (func.getBody (), *this );
1008
1120
1009
1121
// Finally, convert dialect attributes attached to the function.
1010
- return convertDialectAttributes (func);
1122
+ return convertDialectAttributes (func, {} );
1011
1123
}
1012
1124
1013
- LogicalResult ModuleTranslation::convertDialectAttributes (Operation *op) {
1125
+ LogicalResult ModuleTranslation::convertDialectAttributes (
1126
+ Operation *op, ArrayRef<llvm::Instruction *> instructions) {
1014
1127
for (NamedAttribute attribute : op->getDialectAttrs ())
1015
- if (failed (iface.amendOperation (op, attribute, *this )))
1128
+ if (failed (iface.amendOperation (op, instructions, attribute, *this )))
1016
1129
return failure ();
1017
1130
return success ();
1018
1131
}
@@ -1134,7 +1247,7 @@ LogicalResult ModuleTranslation::convertFunctions() {
1134
1247
// Do not convert external functions, but do process dialect attributes
1135
1248
// attached to them.
1136
1249
if (function.isExternal ()) {
1137
- if (failed (convertDialectAttributes (function)))
1250
+ if (failed (convertDialectAttributes (function, {} )))
1138
1251
return failure ();
1139
1252
continue ;
1140
1253
}
0 commit comments