27 #include "llvm/ADT/ScopeExit.h"
28 #include "llvm/ADT/StringRef.h"
29 #include "llvm/Support/Debug.h"
30 #include "llvm/Support/FileSystem.h"
31 #include "llvm/Support/FormatVariadic.h"
32 #include "llvm/Support/Mutex.h"
33 #include "llvm/Support/Path.h"
34 #include "llvm/Support/SourceMgr.h"
35 #include "llvm/Support/raw_ostream.h"
39 #define DEBUG_TYPE "transform-dialect-interpreter"
40 #define DBGS() (llvm::dbgs() << "[" DEBUG_TYPE << "]: ")
41 #define DEBUG_TYPE_DUMP_STDERR "transform-dialect-dump-repro"
42 #define DEBUG_TYPE_DUMP_FILE "transform-dialect-save-repro"
47 "transform.target_tag";
53 constexpr
static llvm::StringLiteral
63 ::mlir::transform::TransformOpInterface topLevelTransform =
nullptr;
65 [&](::mlir::transform::TransformOpInterface transformOp) {
67 ->hasTrait<transform::PossibleTopLevelTransformOpTrait>())
69 if (!topLevelTransform) {
70 topLevelTransform = transformOp;
73 if (
options.getEnforceSingleToplevelTransformOp()) {
74 auto diag = transformOp.emitError()
75 <<
"more than one top-level transform op";
76 diag.attachNote(topLevelTransform.getLoc())
77 <<
"previous top-level transform op";
82 if (!topLevelTransform) {
84 <<
"could not find a nested top-level transform op";
85 diag.attachNote() <<
"use the '" << filenameOption
86 <<
"' option to provide transform as external file";
89 return topLevelTransform;
99 [tagKey, tagValue, &found, root](
Operation *op) {
101 if (!attr || attr.getValue() != tagValue)
106 <<
"more than one operation with " << tagKey
107 <<
"=\"" << tagValue <<
"\" attribute";
108 diag.attachNote(found->
getLoc()) <<
"first operation";
109 diag.attachNote(op->
getLoc()) <<
"other operation";
120 root->
emitError() <<
"could not find the operation with " << tagKey <<
"=\""
121 << tagValue <<
"\" attribute";
137 static llvm::raw_ostream &
141 StringRef binaryName) {
143 "{6} --pass-pipeline=\"{0}({1}{{{2}={3} {4}={5}})\"", rootOpName,
144 passName, debugPayloadRootTag.getArgStr(),
145 debugPayloadRootTag.empty()
147 : debugPayloadRootTag,
148 debugTransformRootTag.getArgStr(),
149 debugTransformRootTag.empty()
151 : debugTransformRootTag,
163 transform->
print(os);
169 [[maybe_unused]]
static void
171 Operation *transform, StringRef passName,
175 StringRef binaryName) {
176 using llvm::sys::fs::TempFile;
180 llvm::sys::path::system_temp_directory(
true, tmpPath);
181 llvm::sys::path::append(tmpPath,
"transform_dialect_%%%%%%.mlir");
184 os <<
"could not open temporary file to save the repro\n";
188 llvm::raw_fd_ostream fout(tempFile->FD,
false);
191 std::string filename = tempFile->TmpName;
193 if (tempFile->keep()) {
194 os <<
"could not preserve the temporary file with the repro\n";
198 os <<
"=== Transform Interpreter Repro ===\n";
200 debugPayloadRootTag, debugTransformRootTag, binaryName)
201 <<
" " << filename <<
"\n";
202 os <<
"===================================\n";
212 StringRef binaryName) {
216 bool hasDebugFlags =
false;
228 llvm::sys::SmartScopedLock<true> lock(dbgStreamMutex);
229 llvm::dbgs() <<
"=======================================================\n";
230 llvm::dbgs() <<
"| Transform reproducers cannot be produced |\n";
231 llvm::dbgs() <<
"| in multi-threaded mode! |\n";
232 llvm::dbgs() <<
"=======================================================\n";
239 if (debugPayloadRootTag.empty()) {
244 if (debugTransformRootTag.empty()) {
251 llvm::dbgs() <<
"=== Transform Interpreter Repro ===\n";
254 debugPayloadRootTag, debugTransformRootTag, binaryName)
257 llvm::dbgs() <<
"\nEOF\n";
258 llvm::dbgs() <<
"===================================\n";
263 debugPayloadRootTag, debugTransformRootTag,
264 transformLibraryPaths, binaryName);
268 if (debugPayloadRootTag.empty())
270 if (debugTransformRootTag.empty())
284 StringRef binaryName) {
285 bool hasSharedTransformModule =
286 sharedTransformModule && *sharedTransformModule;
287 bool hasTransformLibraryModule =
288 transformLibraryModule && *transformLibraryModule;
289 assert((!hasSharedTransformModule || !hasTransformLibraryModule) &&
290 "at most one of shared or library transform module can be set");
298 if (!debugPayloadRootTag.empty()) {
300 debugPayloadRootTag);
312 hasSharedTransformModule ? sharedTransformModule->get() : target;
314 debugTransformRootTag.empty()
316 transformFileName.getArgStr(),
options)
318 debugTransformRootTag);
324 <<
"expected the transform entry point to be a top-level transform "
333 if (hasTransformLibraryModule) {
337 <<
"cannot inject transform definitions next to pass anchor op";
338 diag.attachNote(target->
getLoc()) <<
"pass anchor op";
343 transformLibraryModule->get()->
clone());
346 <<
"failed to merge library symbols into transform root";
356 debugPayloadRootTag, debugTransformRootTag,
357 transformLibraryPaths, binaryName);
362 return applyTransforms(payloadRoot, cast<TransformOpInterface>(transformRoot),
381 return emitError(loc) <<
"failed to parse transform module";
383 return emitError(loc) <<
"failed to verify transform module";
394 for (
const std::string &libraryFileName : libraryFileNames) {
399 return emitError(loc) <<
"failed to parse transform library module";
401 return emitError(loc) <<
"failed to verify transform library module";
402 parsedLibraries.push_back(std::move(parsedLibrary));
406 if (moduleFromFile) {
407 sharedTransformModule =
408 std::make_shared<OwningOpRef<ModuleOp>>(std::move(moduleFromFile));
409 }
else if (moduleBuilder) {
411 auto localModule = std::make_shared<OwningOpRef<ModuleOp>>(
412 ModuleOp::create(unknownLoc,
"__transform"));
415 b.setInsertionPointToEnd(localModule->get().getBody());
416 if (std::optional<LogicalResult> result = moduleBuilder(b, loc)) {
418 return (*localModule)->emitError()
419 <<
"failed to create shared transform module";
420 sharedTransformModule = std::move(localModule);
424 if (parsedLibraries.empty())
430 ModuleOp::create(loc,
"__transform");
432 mergedParsedLibraries.
get()->setAttr(
"transform.with_named_sequence",
438 std::move(parsedLibrary))))
439 return mergedParsedLibraries->emitError()
440 <<
"failed to verify merged transform module";
446 if (sharedTransformModule && *sharedTransformModule) {
448 std::move(mergedParsedLibraries))))
449 return (*sharedTransformModule)->emitError()
450 <<
"failed to merge symbols from library files "
451 "into shared transform module";
453 transformLibraryModule = std::make_shared<OwningOpRef<ModuleOp>>(
454 std::move(mergedParsedLibraries));
static std::string diag(const llvm::Value &value)
static llvm::ManagedStatic< PassManagerOptions > options
This class coordinates rewriting a piece of IR outside of a pattern rewrite, providing a way to keep ...
This class represents a diagnostic that is inflight and set to be reported.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
bool isMultithreadingEnabled()
Return true if multi-threading is enabled by the context.
This class helps build Operations.
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
Operation is the basic unit of execution within MLIR.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
AttrClass getAttrOfType(StringAttr name)
Operation * clone(IRMapping &mapper, CloneOptions options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
void print(raw_ostream &os, const OpPrintingFlags &flags=std::nullopt)
MLIRContext * getContext()
Return the context this operation is associated with.
Location getLoc()
The source location the operation was defined or derived from.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
OperationName getName()
The name of an operation is the key identifier for it.
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
Attribute removeAttr(StringAttr name)
Remove the attribute with the specified name if it exists.
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
OpTy get() const
Allow accessing the internal op.
A 2D array where each row may have different length.
static Operation * getNearestSymbolTable(Operation *from)
Returns the nearest symbol table from a given operation from.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
bool wasInterrupted() const
Returns true if the walk was interrupted.
static WalkResult interrupt()
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
This class represents an efficient way to signal success or failure.
This class represents a specific pass option that contains a list of values of the provided data type...
This class represents a specific pass option, with a provided data type.