| 1 | //===- TestOpaqueLoc.cpp - Pass to test opaque locations ------------------===// |
| 2 | // |
| 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 |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "mlir/IR/Builders.h" |
| 10 | #include "mlir/IR/BuiltinOps.h" |
| 11 | #include "mlir/Pass/Pass.h" |
| 12 | |
| 13 | using namespace mlir; |
| 14 | |
| 15 | namespace { |
| 16 | /// A simple structure which is used for testing as an underlying location in |
| 17 | /// OpaqueLoc. |
| 18 | struct MyLocation { |
| 19 | MyLocation() = default; |
| 20 | MyLocation(int id) : id(id) {} |
| 21 | int getId() { return id; } |
| 22 | |
| 23 | int id{42}; |
| 24 | }; |
| 25 | } // namespace |
| 26 | |
| 27 | MLIR_DECLARE_EXPLICIT_TYPE_ID(MyLocation *) |
| 28 | MLIR_DEFINE_EXPLICIT_TYPE_ID(MyLocation *) |
| 29 | |
| 30 | namespace { |
| 31 | /// Pass that changes locations to opaque locations for each operation. |
| 32 | /// It also takes all operations that are not function operations or |
| 33 | /// terminators and clones them with opaque locations which store the initial |
| 34 | /// locations. |
| 35 | struct TestOpaqueLoc |
| 36 | : public PassWrapper<TestOpaqueLoc, OperationPass<ModuleOp>> { |
| 37 | MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOpaqueLoc) |
| 38 | |
| 39 | StringRef getArgument() const final { return "test-opaque-loc" ; } |
| 40 | StringRef getDescription() const final { |
| 41 | return "Changes all leaf locations to opaque locations" ; |
| 42 | } |
| 43 | |
| 44 | void runOnOperation() override { |
| 45 | std::vector<std::unique_ptr<MyLocation>> myLocs; |
| 46 | int lastIt = 0; |
| 47 | |
| 48 | getOperation().getBody()->walk([&](Operation *op) { |
| 49 | myLocs.push_back(x: std::make_unique<MyLocation>(args: lastIt++)); |
| 50 | |
| 51 | Location loc = op->getLoc(); |
| 52 | |
| 53 | /// Set opaque location without fallback location to test the |
| 54 | /// corresponding get method. |
| 55 | op->setLoc( |
| 56 | OpaqueLoc::get<MyLocation *>(myLocs.back().get(), &getContext())); |
| 57 | |
| 58 | if (isa<ModuleOp>(Val: op->getParentOp()) || |
| 59 | op->hasTrait<OpTrait::IsTerminator>()) |
| 60 | return; |
| 61 | |
| 62 | OpBuilder builder(op); |
| 63 | |
| 64 | /// Add the same operation but with fallback location to test the |
| 65 | /// corresponding get method and serialization. |
| 66 | Operation *opCloned1 = builder.clone(op&: *op); |
| 67 | opCloned1->setLoc(OpaqueLoc::get<MyLocation *>(myLocs.back().get(), loc)); |
| 68 | |
| 69 | /// Add the same operation but with void* instead of MyLocation* to test |
| 70 | /// getUnderlyingLocationOrNull method. |
| 71 | Operation *opCloned2 = builder.clone(op&: *op); |
| 72 | opCloned2->setLoc(OpaqueLoc::get<void *>(nullptr, loc)); |
| 73 | }); |
| 74 | |
| 75 | ScopedDiagnosticHandler diagHandler(&getContext(), [](Diagnostic &diag) { |
| 76 | auto &os = llvm::outs(); |
| 77 | if (isa<OpaqueLoc>(diag.getLocation())) { |
| 78 | MyLocation *loc = OpaqueLoc::getUnderlyingLocationOrNull<MyLocation *>( |
| 79 | diag.getLocation()); |
| 80 | if (loc) |
| 81 | os << "MyLocation: " << loc->id; |
| 82 | else |
| 83 | os << "nullptr" ; |
| 84 | } |
| 85 | os << ": " << diag << '\n'; |
| 86 | os.flush(); |
| 87 | }); |
| 88 | |
| 89 | getOperation().walk([&](Operation *op) { op->emitOpError(); }); |
| 90 | } |
| 91 | }; |
| 92 | |
| 93 | } // namespace |
| 94 | |
| 95 | namespace mlir { |
| 96 | namespace test { |
| 97 | void registerTestOpaqueLoc() { PassRegistration<TestOpaqueLoc>(); } |
| 98 | } // namespace test |
| 99 | } // namespace mlir |
| 100 | |