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"
101834ad4aSRiver Riddle #include "PassDetail.h"
11abe3e5baSRiver Riddle #include "mlir/IR/AsmState.h"
12abe3e5baSRiver Riddle #include "mlir/IR/Builders.h"
13abe3e5baSRiver Riddle #include "mlir/Support/FileUtilities.h"
14abe3e5baSRiver Riddle #include "llvm/Support/FileSystem.h"
15abe3e5baSRiver Riddle #include "llvm/Support/ToolOutputFile.h"
16abe3e5baSRiver Riddle
17abe3e5baSRiver Riddle using namespace mlir;
18abe3e5baSRiver Riddle
19abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
20abe3e5baSRiver Riddle /// IR to the given stream, and using the printed locations within that stream.
21abe3e5baSRiver Riddle /// If a 'tag' is non-empty, the generated locations are represented as a
22abe3e5baSRiver Riddle /// NameLoc with the given tag as the name, and then fused with the existing
23abe3e5baSRiver Riddle /// locations. Otherwise, the existing locations are replaced.
generateLocationsFromIR(raw_ostream & os,StringRef fileName,Operation * op,const OpPrintingFlags & flags,StringRef tag)24abe3e5baSRiver Riddle static void generateLocationsFromIR(raw_ostream &os, StringRef fileName,
252c0f1798SItai Zukerman Operation *op, const OpPrintingFlags &flags,
26abe3e5baSRiver Riddle StringRef tag) {
27abe3e5baSRiver Riddle // Print the IR to the stream, and collect the raw line+column information.
28abe3e5baSRiver Riddle AsmState::LocationMap opToLineCol;
292c0f1798SItai Zukerman AsmState state(op, flags, &opToLineCol);
30*988a3ba0SSergei Grechanik op->print(os, state);
31abe3e5baSRiver Riddle
32abe3e5baSRiver Riddle Builder builder(op->getContext());
33195730a6SRiver Riddle Optional<StringAttr> tagIdentifier;
34abe3e5baSRiver Riddle if (!tag.empty())
35195730a6SRiver Riddle tagIdentifier = builder.getStringAttr(tag);
36abe3e5baSRiver Riddle
37abe3e5baSRiver Riddle // Walk and generate new locations for each of the operations.
38195730a6SRiver Riddle StringAttr file = builder.getStringAttr(fileName);
39abe3e5baSRiver Riddle op->walk([&](Operation *opIt) {
40abe3e5baSRiver Riddle // Check to see if this operation has a mapped location. Some operations may
41abe3e5baSRiver Riddle // be elided from the printed form, e.g. the body terminators of some region
42abe3e5baSRiver Riddle // operations.
43abe3e5baSRiver Riddle auto it = opToLineCol.find(opIt);
44abe3e5baSRiver Riddle if (it == opToLineCol.end())
45abe3e5baSRiver Riddle return;
46abe3e5baSRiver Riddle const std::pair<unsigned, unsigned> &lineCol = it->second;
47e6260ad0SRiver Riddle auto newLoc = FileLineColLoc::get(file, lineCol.first, lineCol.second);
48abe3e5baSRiver Riddle
49abe3e5baSRiver Riddle // If we don't have a tag, set the location directly
50abe3e5baSRiver Riddle if (!tagIdentifier) {
51abe3e5baSRiver Riddle opIt->setLoc(newLoc);
52abe3e5baSRiver Riddle return;
53abe3e5baSRiver Riddle }
54abe3e5baSRiver Riddle
55abe3e5baSRiver Riddle // Otherwise, build a fused location with the existing op loc.
56abe3e5baSRiver Riddle opIt->setLoc(builder.getFusedLoc(
57abe3e5baSRiver Riddle {opIt->getLoc(), NameLoc::get(*tagIdentifier, newLoc)}));
58abe3e5baSRiver Riddle });
59abe3e5baSRiver Riddle }
60abe3e5baSRiver Riddle
61abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
62abe3e5baSRiver Riddle /// IR to the given file, and using the printed locations within that file. If
63abe3e5baSRiver Riddle /// `filename` is empty, a temporary file is generated instead.
generateLocationsFromIR(StringRef fileName,Operation * op,OpPrintingFlags flags,StringRef tag)64abe3e5baSRiver Riddle static LogicalResult generateLocationsFromIR(StringRef fileName, Operation *op,
65abe3e5baSRiver Riddle OpPrintingFlags flags,
66abe3e5baSRiver Riddle StringRef tag) {
67abe3e5baSRiver Riddle // If a filename wasn't provided, then generate one.
68abe3e5baSRiver Riddle SmallString<32> filepath(fileName);
69abe3e5baSRiver Riddle if (filepath.empty()) {
70abe3e5baSRiver Riddle if (std::error_code error = llvm::sys::fs::createTemporaryFile(
71abe3e5baSRiver Riddle "mlir_snapshot", "tmp.mlir", filepath)) {
72abe3e5baSRiver Riddle return op->emitError()
73abe3e5baSRiver Riddle << "failed to generate temporary file for location snapshot: "
74abe3e5baSRiver Riddle << error.message();
75abe3e5baSRiver Riddle }
76abe3e5baSRiver Riddle }
77abe3e5baSRiver Riddle
78abe3e5baSRiver Riddle // Open the output file for emission.
79abe3e5baSRiver Riddle std::string error;
80abe3e5baSRiver Riddle std::unique_ptr<llvm::ToolOutputFile> outputFile =
81abe3e5baSRiver Riddle openOutputFile(filepath, &error);
82abe3e5baSRiver Riddle if (!outputFile)
83abe3e5baSRiver Riddle return op->emitError() << error;
84abe3e5baSRiver Riddle
85abe3e5baSRiver Riddle // Generate the intermediate locations.
86abe3e5baSRiver Riddle generateLocationsFromIR(outputFile->os(), filepath, op, flags, tag);
87abe3e5baSRiver Riddle outputFile->keep();
88abe3e5baSRiver Riddle return success();
89abe3e5baSRiver Riddle }
90abe3e5baSRiver Riddle
91abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
92abe3e5baSRiver Riddle /// IR to the given stream, and using the printed locations within that stream.
93abe3e5baSRiver Riddle /// The generated locations replace the current operation locations.
generateLocationsFromIR(raw_ostream & os,StringRef fileName,Operation * op,OpPrintingFlags flags)94abe3e5baSRiver Riddle void mlir::generateLocationsFromIR(raw_ostream &os, StringRef fileName,
95abe3e5baSRiver Riddle Operation *op, OpPrintingFlags flags) {
96abe3e5baSRiver Riddle ::generateLocationsFromIR(os, fileName, op, flags, /*tag=*/StringRef());
97abe3e5baSRiver Riddle }
98abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
99abe3e5baSRiver Riddle /// IR to the given file, and using the printed locations within that file. If
100abe3e5baSRiver Riddle /// `filename` is empty, a temporary file is generated instead.
generateLocationsFromIR(StringRef fileName,Operation * op,OpPrintingFlags flags)101abe3e5baSRiver Riddle LogicalResult mlir::generateLocationsFromIR(StringRef fileName, Operation *op,
102abe3e5baSRiver Riddle OpPrintingFlags flags) {
103abe3e5baSRiver Riddle return ::generateLocationsFromIR(fileName, op, flags, /*tag=*/StringRef());
104abe3e5baSRiver Riddle }
105abe3e5baSRiver Riddle
106abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
107abe3e5baSRiver Riddle /// IR to the given stream, and using the printed locations within that stream.
108abe3e5baSRiver Riddle /// The generated locations are represented as a NameLoc with the given tag as
109abe3e5baSRiver Riddle /// the name, and then fused with the existing locations.
generateLocationsFromIR(raw_ostream & os,StringRef fileName,StringRef tag,Operation * op,OpPrintingFlags flags)110abe3e5baSRiver Riddle void mlir::generateLocationsFromIR(raw_ostream &os, StringRef fileName,
111abe3e5baSRiver Riddle StringRef tag, Operation *op,
112abe3e5baSRiver Riddle OpPrintingFlags flags) {
113abe3e5baSRiver Riddle ::generateLocationsFromIR(os, fileName, op, flags, tag);
114abe3e5baSRiver Riddle }
115abe3e5baSRiver Riddle /// This function generates new locations from the given IR by snapshotting the
116abe3e5baSRiver Riddle /// IR to the given file, and using the printed locations within that file. If
117abe3e5baSRiver Riddle /// `filename` is empty, a temporary file is generated instead.
generateLocationsFromIR(StringRef fileName,StringRef tag,Operation * op,OpPrintingFlags flags)118abe3e5baSRiver Riddle LogicalResult mlir::generateLocationsFromIR(StringRef fileName, StringRef tag,
119abe3e5baSRiver Riddle Operation *op,
120abe3e5baSRiver Riddle OpPrintingFlags flags) {
121abe3e5baSRiver Riddle return ::generateLocationsFromIR(fileName, op, flags, tag);
122abe3e5baSRiver Riddle }
123abe3e5baSRiver Riddle
124abe3e5baSRiver Riddle namespace {
12580aca1eaSRiver Riddle struct LocationSnapshotPass
1261834ad4aSRiver Riddle : public LocationSnapshotBase<LocationSnapshotPass> {
127abe3e5baSRiver Riddle LocationSnapshotPass() = default;
LocationSnapshotPass__anon232a03400211::LocationSnapshotPass128abe3e5baSRiver Riddle LocationSnapshotPass(OpPrintingFlags flags, StringRef fileName, StringRef tag)
129abe3e5baSRiver Riddle : flags(flags) {
130abe3e5baSRiver Riddle this->fileName = fileName.str();
131abe3e5baSRiver Riddle this->tag = tag.str();
132abe3e5baSRiver Riddle }
133abe3e5baSRiver Riddle
runOnOperation__anon232a03400211::LocationSnapshotPass134abe3e5baSRiver Riddle void runOnOperation() override {
135abe3e5baSRiver Riddle Operation *op = getOperation();
136abe3e5baSRiver Riddle if (failed(generateLocationsFromIR(fileName, op, OpPrintingFlags(), tag)))
137abe3e5baSRiver Riddle return signalPassFailure();
138abe3e5baSRiver Riddle }
139abe3e5baSRiver Riddle
140abe3e5baSRiver Riddle /// The printing flags to use when creating the snapshot.
141abe3e5baSRiver Riddle OpPrintingFlags flags;
142abe3e5baSRiver Riddle };
143be0a7e9fSMehdi Amini } // namespace
144abe3e5baSRiver Riddle
createLocationSnapshotPass(OpPrintingFlags flags,StringRef fileName,StringRef tag)145abe3e5baSRiver Riddle std::unique_ptr<Pass> mlir::createLocationSnapshotPass(OpPrintingFlags flags,
146abe3e5baSRiver Riddle StringRef fileName,
147abe3e5baSRiver Riddle StringRef tag) {
148abe3e5baSRiver Riddle return std::make_unique<LocationSnapshotPass>(flags, fileName, tag);
149abe3e5baSRiver Riddle }
createLocationSnapshotPass()1508155e41aSRiver Riddle std::unique_ptr<Pass> mlir::createLocationSnapshotPass() {
1518155e41aSRiver Riddle return std::make_unique<LocationSnapshotPass>();
1528155e41aSRiver Riddle }
153