1 //===- LocationSnapshot.cpp - Location Snapshot Utilities -----------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "mlir/Transforms/LocationSnapshot.h"
11 #include "mlir/IR/AsmState.h"
12 #include "mlir/IR/Builders.h"
13 #include "mlir/Pass/Pass.h"
14 #include "mlir/Support/FileUtilities.h"
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/ToolOutputFile.h"
20 #define GEN_PASS_DEF_LOCATIONSNAPSHOT
21 #include "mlir/Transforms/Passes.h.inc"
26 /// This function generates new locations from the given IR by snapshotting the
27 /// IR to the given stream, and using the printed locations within that stream.
28 /// If a 'tag' is non-empty, the generated locations are represented as a
29 /// NameLoc with the given tag as the name, and then fused with the existing
30 /// locations. Otherwise, the existing locations are replaced.
31 static void generateLocationsFromIR(raw_ostream
&os
, StringRef fileName
,
32 Operation
*op
, const OpPrintingFlags
&flags
,
34 // Print the IR to the stream, and collect the raw line+column information.
35 AsmState::LocationMap opToLineCol
;
36 AsmState
state(op
, flags
, &opToLineCol
);
39 Builder
builder(op
->getContext());
40 std::optional
<StringAttr
> tagIdentifier
;
42 tagIdentifier
= builder
.getStringAttr(tag
);
44 // Walk and generate new locations for each of the operations.
45 StringAttr file
= builder
.getStringAttr(fileName
);
46 op
->walk([&](Operation
*opIt
) {
47 // Check to see if this operation has a mapped location. Some operations may
48 // be elided from the printed form, e.g. the body terminators of some region
50 auto it
= opToLineCol
.find(opIt
);
51 if (it
== opToLineCol
.end())
53 const std::pair
<unsigned, unsigned> &lineCol
= it
->second
;
54 auto newLoc
= FileLineColLoc::get(file
, lineCol
.first
, lineCol
.second
);
56 // If we don't have a tag, set the location directly
62 // Otherwise, build a fused location with the existing op loc.
63 opIt
->setLoc(builder
.getFusedLoc(
64 {opIt
->getLoc(), NameLoc::get(*tagIdentifier
, newLoc
)}));
68 /// This function generates new locations from the given IR by snapshotting the
69 /// IR to the given file, and using the printed locations within that file. If
70 /// `filename` is empty, a temporary file is generated instead.
71 static LogicalResult
generateLocationsFromIR(StringRef fileName
, Operation
*op
,
72 OpPrintingFlags flags
,
74 // If a filename wasn't provided, then generate one.
75 SmallString
<32> filepath(fileName
);
76 if (filepath
.empty()) {
77 if (std::error_code error
= llvm::sys::fs::createTemporaryFile(
78 "mlir_snapshot", "tmp.mlir", filepath
)) {
79 return op
->emitError()
80 << "failed to generate temporary file for location snapshot: "
85 // Open the output file for emission.
87 std::unique_ptr
<llvm::ToolOutputFile
> outputFile
=
88 openOutputFile(filepath
, &error
);
90 return op
->emitError() << error
;
92 // Generate the intermediate locations.
93 generateLocationsFromIR(outputFile
->os(), filepath
, op
, flags
, tag
);
98 /// This function generates new locations from the given IR by snapshotting the
99 /// IR to the given stream, and using the printed locations within that stream.
100 /// The generated locations replace the current operation locations.
101 void mlir::generateLocationsFromIR(raw_ostream
&os
, StringRef fileName
,
102 Operation
*op
, OpPrintingFlags flags
) {
103 ::generateLocationsFromIR(os
, fileName
, op
, flags
, /*tag=*/StringRef());
105 /// This function generates new locations from the given IR by snapshotting the
106 /// IR to the given file, and using the printed locations within that file. If
107 /// `filename` is empty, a temporary file is generated instead.
108 LogicalResult
mlir::generateLocationsFromIR(StringRef fileName
, Operation
*op
,
109 OpPrintingFlags flags
) {
110 return ::generateLocationsFromIR(fileName
, op
, flags
, /*tag=*/StringRef());
113 /// This function generates new locations from the given IR by snapshotting the
114 /// IR to the given stream, and using the printed locations within that stream.
115 /// The generated locations are represented as a NameLoc with the given tag as
116 /// the name, and then fused with the existing locations.
117 void mlir::generateLocationsFromIR(raw_ostream
&os
, StringRef fileName
,
118 StringRef tag
, Operation
*op
,
119 OpPrintingFlags flags
) {
120 ::generateLocationsFromIR(os
, fileName
, op
, flags
, tag
);
122 /// This function generates new locations from the given IR by snapshotting the
123 /// IR to the given file, and using the printed locations within that file. If
124 /// `filename` is empty, a temporary file is generated instead.
125 LogicalResult
mlir::generateLocationsFromIR(StringRef fileName
, StringRef tag
,
127 OpPrintingFlags flags
) {
128 return ::generateLocationsFromIR(fileName
, op
, flags
, tag
);
132 struct LocationSnapshotPass
133 : public impl::LocationSnapshotBase
<LocationSnapshotPass
> {
134 LocationSnapshotPass() = default;
135 LocationSnapshotPass(OpPrintingFlags flags
, StringRef fileName
, StringRef tag
)
137 this->fileName
= fileName
.str();
138 this->tag
= tag
.str();
141 void runOnOperation() override
{
142 Operation
*op
= getOperation();
143 if (failed(generateLocationsFromIR(fileName
, op
, OpPrintingFlags(), tag
)))
144 return signalPassFailure();
147 /// The printing flags to use when creating the snapshot.
148 OpPrintingFlags flags
;
152 std::unique_ptr
<Pass
> mlir::createLocationSnapshotPass(OpPrintingFlags flags
,
155 return std::make_unique
<LocationSnapshotPass
>(flags
, fileName
, tag
);
157 std::unique_ptr
<Pass
> mlir::createLocationSnapshotPass() {
158 return std::make_unique
<LocationSnapshotPass
>();