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