xref: /llvm-project/mlir/lib/Transforms/LocationSnapshot.cpp (revision 1fb98b5a7e964efd77a735148e8c8704ca8728db)
1abe3e5baSRiver Riddle //===- LocationSnapshot.cpp - Location Snapshot Utilities -----------------===//
2abe3e5baSRiver Riddle //
3abe3e5baSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4abe3e5baSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5abe3e5baSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6abe3e5baSRiver Riddle //
7abe3e5baSRiver Riddle //===----------------------------------------------------------------------===//
8abe3e5baSRiver Riddle 
9abe3e5baSRiver Riddle #include "mlir/Transforms/LocationSnapshot.h"
1067d0d7acSMichele Scuttari 
11abe3e5baSRiver Riddle #include "mlir/IR/AsmState.h"
12abe3e5baSRiver Riddle #include "mlir/IR/Builders.h"
13*1fb98b5aSMichael Jungmair #include "mlir/IR/OperationSupport.h"
1467d0d7acSMichele Scuttari #include "mlir/Pass/Pass.h"
15abe3e5baSRiver Riddle #include "mlir/Support/FileUtilities.h"
16abe3e5baSRiver Riddle #include "llvm/Support/FileSystem.h"
17abe3e5baSRiver Riddle #include "llvm/Support/ToolOutputFile.h"
18a1fe1f5fSKazu Hirata #include <optional>
19abe3e5baSRiver Riddle 
2067d0d7acSMichele Scuttari namespace mlir {
2167d0d7acSMichele Scuttari #define GEN_PASS_DEF_LOCATIONSNAPSHOT
2267d0d7acSMichele Scuttari #include "mlir/Transforms/Passes.h.inc"
2367d0d7acSMichele Scuttari } // namespace mlir
2467d0d7acSMichele Scuttari 
25abe3e5baSRiver Riddle using namespace mlir;
26abe3e5baSRiver Riddle 
27abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
28abe3e5baSRiver Riddle /// IR to the given stream, and using the printed locations within that stream.
29abe3e5baSRiver Riddle /// If a 'tag' is non-empty, the generated locations are represented as a
30abe3e5baSRiver Riddle /// NameLoc with the given tag as the name, and then fused with the existing
31abe3e5baSRiver Riddle /// locations. Otherwise, the existing locations are replaced.
32abe3e5baSRiver Riddle static void generateLocationsFromIR(raw_ostream &os, StringRef fileName,
332c0f1798SItai Zukerman                                     Operation *op, const OpPrintingFlags &flags,
34abe3e5baSRiver Riddle                                     StringRef tag) {
35abe3e5baSRiver Riddle   // Print the IR to the stream, and collect the raw line+column information.
36abe3e5baSRiver Riddle   AsmState::LocationMap opToLineCol;
372c0f1798SItai Zukerman   AsmState state(op, flags, &opToLineCol);
38988a3ba0SSergei Grechanik   op->print(os, state);
39abe3e5baSRiver Riddle 
40abe3e5baSRiver Riddle   Builder builder(op->getContext());
410a81ace0SKazu Hirata   std::optional<StringAttr> tagIdentifier;
42abe3e5baSRiver Riddle   if (!tag.empty())
43195730a6SRiver Riddle     tagIdentifier = builder.getStringAttr(tag);
44abe3e5baSRiver Riddle 
45abe3e5baSRiver Riddle   // Walk and generate new locations for each of the operations.
46195730a6SRiver Riddle   StringAttr file = builder.getStringAttr(fileName);
47abe3e5baSRiver Riddle   op->walk([&](Operation *opIt) {
48abe3e5baSRiver Riddle     // Check to see if this operation has a mapped location. Some operations may
49abe3e5baSRiver Riddle     // be elided from the printed form, e.g. the body terminators of some region
50abe3e5baSRiver Riddle     // operations.
51abe3e5baSRiver Riddle     auto it = opToLineCol.find(opIt);
52abe3e5baSRiver Riddle     if (it == opToLineCol.end())
53abe3e5baSRiver Riddle       return;
54abe3e5baSRiver Riddle     const std::pair<unsigned, unsigned> &lineCol = it->second;
55e6260ad0SRiver Riddle     auto newLoc = FileLineColLoc::get(file, lineCol.first, lineCol.second);
56abe3e5baSRiver Riddle 
57abe3e5baSRiver Riddle     // If we don't have a tag, set the location directly
58abe3e5baSRiver Riddle     if (!tagIdentifier) {
59abe3e5baSRiver Riddle       opIt->setLoc(newLoc);
60abe3e5baSRiver Riddle       return;
61abe3e5baSRiver Riddle     }
62abe3e5baSRiver Riddle 
63abe3e5baSRiver Riddle     // Otherwise, build a fused location with the existing op loc.
64abe3e5baSRiver Riddle     opIt->setLoc(builder.getFusedLoc(
65abe3e5baSRiver Riddle         {opIt->getLoc(), NameLoc::get(*tagIdentifier, newLoc)}));
66abe3e5baSRiver Riddle   });
67abe3e5baSRiver Riddle }
68abe3e5baSRiver Riddle 
69abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
70abe3e5baSRiver Riddle /// IR to the given file, and using the printed locations within that file. If
71abe3e5baSRiver Riddle /// `filename` is empty, a temporary file is generated instead.
72abe3e5baSRiver Riddle static LogicalResult generateLocationsFromIR(StringRef fileName, Operation *op,
73abe3e5baSRiver Riddle                                              OpPrintingFlags flags,
74abe3e5baSRiver Riddle                                              StringRef tag) {
75abe3e5baSRiver Riddle   // If a filename wasn't provided, then generate one.
76abe3e5baSRiver Riddle   SmallString<32> filepath(fileName);
77abe3e5baSRiver Riddle   if (filepath.empty()) {
78abe3e5baSRiver Riddle     if (std::error_code error = llvm::sys::fs::createTemporaryFile(
79abe3e5baSRiver Riddle             "mlir_snapshot", "tmp.mlir", filepath)) {
80abe3e5baSRiver Riddle       return op->emitError()
81abe3e5baSRiver Riddle              << "failed to generate temporary file for location snapshot: "
82abe3e5baSRiver Riddle              << error.message();
83abe3e5baSRiver Riddle     }
84abe3e5baSRiver Riddle   }
85abe3e5baSRiver Riddle 
86abe3e5baSRiver Riddle   // Open the output file for emission.
87abe3e5baSRiver Riddle   std::string error;
88abe3e5baSRiver Riddle   std::unique_ptr<llvm::ToolOutputFile> outputFile =
89abe3e5baSRiver Riddle       openOutputFile(filepath, &error);
90abe3e5baSRiver Riddle   if (!outputFile)
91abe3e5baSRiver Riddle     return op->emitError() << error;
92abe3e5baSRiver Riddle 
93abe3e5baSRiver Riddle   // Generate the intermediate locations.
94abe3e5baSRiver Riddle   generateLocationsFromIR(outputFile->os(), filepath, op, flags, tag);
95abe3e5baSRiver Riddle   outputFile->keep();
96abe3e5baSRiver Riddle   return success();
97abe3e5baSRiver Riddle }
98abe3e5baSRiver Riddle 
99abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
100abe3e5baSRiver Riddle /// IR to the given stream, and using the printed locations within that stream.
101abe3e5baSRiver Riddle /// The generated locations replace the current operation locations.
102abe3e5baSRiver Riddle void mlir::generateLocationsFromIR(raw_ostream &os, StringRef fileName,
103abe3e5baSRiver Riddle                                    Operation *op, OpPrintingFlags flags) {
104abe3e5baSRiver Riddle   ::generateLocationsFromIR(os, fileName, op, flags, /*tag=*/StringRef());
105abe3e5baSRiver Riddle }
106abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
107abe3e5baSRiver Riddle /// IR to the given file, and using the printed locations within that file. If
108abe3e5baSRiver Riddle /// `filename` is empty, a temporary file is generated instead.
109abe3e5baSRiver Riddle LogicalResult mlir::generateLocationsFromIR(StringRef fileName, Operation *op,
110abe3e5baSRiver Riddle                                             OpPrintingFlags flags) {
111abe3e5baSRiver Riddle   return ::generateLocationsFromIR(fileName, op, flags, /*tag=*/StringRef());
112abe3e5baSRiver Riddle }
113abe3e5baSRiver Riddle 
114abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
115abe3e5baSRiver Riddle /// IR to the given stream, and using the printed locations within that stream.
116abe3e5baSRiver Riddle /// The generated locations are represented as a NameLoc with the given tag as
117abe3e5baSRiver Riddle /// the name, and then fused with the existing locations.
118abe3e5baSRiver Riddle void mlir::generateLocationsFromIR(raw_ostream &os, StringRef fileName,
119abe3e5baSRiver Riddle                                    StringRef tag, Operation *op,
120abe3e5baSRiver Riddle                                    OpPrintingFlags flags) {
121abe3e5baSRiver Riddle   ::generateLocationsFromIR(os, fileName, op, flags, tag);
122abe3e5baSRiver Riddle }
123abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
124abe3e5baSRiver Riddle /// IR to the given file, and using the printed locations within that file. If
125abe3e5baSRiver Riddle /// `filename` is empty, a temporary file is generated instead.
126abe3e5baSRiver Riddle LogicalResult mlir::generateLocationsFromIR(StringRef fileName, StringRef tag,
127abe3e5baSRiver Riddle                                             Operation *op,
128abe3e5baSRiver Riddle                                             OpPrintingFlags flags) {
129abe3e5baSRiver Riddle   return ::generateLocationsFromIR(fileName, op, flags, tag);
130abe3e5baSRiver Riddle }
131abe3e5baSRiver Riddle 
132abe3e5baSRiver Riddle namespace {
13380aca1eaSRiver Riddle struct LocationSnapshotPass
13467d0d7acSMichele Scuttari     : public impl::LocationSnapshotBase<LocationSnapshotPass> {
135*1fb98b5aSMichael Jungmair   using impl::LocationSnapshotBase<LocationSnapshotPass>::LocationSnapshotBase;
136abe3e5baSRiver Riddle 
137abe3e5baSRiver Riddle   void runOnOperation() override {
138abe3e5baSRiver Riddle     Operation *op = getOperation();
139*1fb98b5aSMichael Jungmair     if (failed(generateLocationsFromIR(fileName, op, getFlags(), tag)))
140abe3e5baSRiver Riddle       return signalPassFailure();
141abe3e5baSRiver Riddle   }
142abe3e5baSRiver Riddle 
143*1fb98b5aSMichael Jungmair private:
144*1fb98b5aSMichael Jungmair   /// build the flags from the command line arguments to the pass
145*1fb98b5aSMichael Jungmair   OpPrintingFlags getFlags() {
146abe3e5baSRiver Riddle     OpPrintingFlags flags;
147*1fb98b5aSMichael Jungmair     flags.enableDebugInfo(enableDebugInfo, printPrettyDebugInfo);
148*1fb98b5aSMichael Jungmair     flags.printGenericOpForm(printGenericOpForm);
149*1fb98b5aSMichael Jungmair     if (useLocalScope)
150*1fb98b5aSMichael Jungmair       flags.useLocalScope();
151*1fb98b5aSMichael Jungmair     return flags;
152*1fb98b5aSMichael Jungmair   }
153abe3e5baSRiver Riddle };
154be0a7e9fSMehdi Amini } // namespace
155