#### IR Printing
-Note: The IR Printing instrumentation should only be used when multi-threading
-is disabled(`-disable-pass-threading`)
-
When debugging it is often useful to dump the IR at various stages of a pass
pipeline. This is where the IR printing instrumentation comes into play. This
instrumentation allows for conditionally printing the IR before and after pass
* Print the IR before every pass in the pipeline.
```shell
-$ mlir-opt foo.mlir -disable-pass-threading -cse -print-ir-before=cse
+$ mlir-opt foo.mlir -cse -print-ir-before=cse
*** IR Dump Before CSE ***
func @simple_constant() -> (i32, i32) {
* Print the IR after every pass in the pipeline.
```shell
-$ mlir-opt foo.mlir -disable-pass-threading -cse -print-ir-after=cse
+$ mlir-opt foo.mlir -cse -print-ir-after=cse
*** IR Dump After CSE ***
func @simple_constant() -> (i32, i32) {
* `print-ir-module-scope`
* Always print the top-level module operation, regardless of pass type or
operation nesting level.
+ * Note: Printing at module scope should only be used when multi-threading
+ is disabled(`-disable-pass-threading`)
```shell
$ mlir-opt foo.mlir -disable-pass-threading -cse -print-ir-after=cse -print-ir-module-scope
/// Always print operations in the generic form.
OpPrintingFlags &printGenericOpForm();
+ /// Use local scope when printing the operation. This allows for using the
+ /// printer in a more localized and thread-safe setting, but may not
+ /// necessarily be identical to what the IR will look like when dumping
+ /// the full module.
+ OpPrintingFlags &useLocalScope();
+
/// Return if the given ElementsAttr should be elided.
bool shouldElideElementsAttr(ElementsAttr attr) const;
/// Return if operations should be printed in the generic form.
bool shouldPrintGenericOpForm() const;
+ /// Return if the printer should use local scope when dumping the IR.
+ bool shouldUseLocalScope() const;
+
private:
/// Elide large elements attributes if the number of elements is larger than
/// the upper limit.
/// Print operations in the generic form.
bool printGenericOpFormFlag : 1;
+
+ /// Print operations with numberings local to the current operation.
+ bool printLocalScope : 1;
};
} // end namespace mlir
: Optional<int64_t>()),
printDebugInfoFlag(printDebugInfoOpt),
printDebugInfoPrettyFormFlag(printPrettyDebugInfoOpt),
- printGenericOpFormFlag(printGenericOpFormOpt) {}
+ printGenericOpFormFlag(printGenericOpFormOpt), printLocalScope(false) {}
/// Enable the elision of large elements attributes, by printing a '...'
/// instead of the element data, when the number of elements is greater than
return *this;
}
+/// Use local scope when printing the operation. This allows for using the
+/// printer in a more localized and thread-safe setting, but may not necessarily
+/// be identical of what the IR will look like when dumping the full module.
+OpPrintingFlags &OpPrintingFlags::useLocalScope() {
+ printLocalScope = true;
+ return *this;
+}
+
/// Return if the given ElementsAttr should be elided.
bool OpPrintingFlags::shouldElideElementsAttr(ElementsAttr attr) const {
return elementsAttrElementLimit.hasValue() &&
return printGenericOpFormFlag;
}
+/// Return if the printer should use local scope when dumping the IR.
+bool OpPrintingFlags::shouldUseLocalScope() const { return printLocalScope; }
+
//===----------------------------------------------------------------------===//
// ModuleState
//===----------------------------------------------------------------------===//
OperationPrinter::OperationPrinter(Operation *op, ModulePrinter &other)
: ModulePrinter(other) {
+ llvm::ScopedHashTable<StringRef, char>::ScopeTy usedNamesScope(usedNames);
if (op->getNumResults() != 0)
numberValueID(op->getResult(0));
+
for (auto ®ion : op->getRegions())
numberValuesInRegion(region);
}
auto it = valueIDs.find(lookupValue);
if (it == valueIDs.end()) {
- stream << "<<INVALID SSA VALUE>>";
+ stream << "<<UNKNOWN SSA VALUE>>";
return;
}
}
void Operation::print(raw_ostream &os, OpPrintingFlags flags) {
- // Handle top-level operations.
- if (!getParent()) {
- ModulePrinter modulePrinter(os, flags);
+ // Handle top-level operations or local printing.
+ if (!getParent() || flags.shouldUseLocalScope()) {
+ ModuleState state(getContext());
+ ModulePrinter modulePrinter(os, flags, &state);
OperationPrinter(this, modulePrinter).print(this);
return;
}
}
void Operation::dump() {
- print(llvm::errs());
+ print(llvm::errs(), OpPrintingFlags().useLocalScope());
llvm::errs() << "\n";
}
os << getAsInteger();
break;
case DiagnosticArgumentKind::Operation:
- os << getAsOperation();
+ getAsOperation().print(os, OpPrintingFlags().useLocalScope());
break;
case DiagnosticArgumentKind::String:
os << getAsString();
// Otherwise, check to see if we are not printing at module scope.
if (!printModuleScope)
- return op->print(out << "\n", flags);
+ return op->print(out << "\n", flags.useLocalScope());
// Otherwise, we are printing at module scope.
out << " ('" << op->getName() << "' operation";