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