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() = default;
30     MyLocation(int id) : id(id) {}
31     int getId() { return id; }
32 
33     int id{42};
34   };
35 
36   void runOnOperation() override {
37     std::vector<std::unique_ptr<MyLocation>> myLocs;
38     int lastIt = 0;
39 
40     getOperation().getBody()->walk([&](Operation *op) {
41       myLocs.push_back(std::make_unique<MyLocation>(lastIt++));
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 *opCloned1 = builder.clone(*op);
58       opCloned1->setLoc(OpaqueLoc::get<MyLocation *>(myLocs.back().get(), loc));
59 
60       /// Add the same operation but with void* instead of MyLocation* to test
61       /// getUnderlyingLocationOrNull method.
62       Operation *opCloned2 = builder.clone(*op);
63       opCloned2->setLoc(OpaqueLoc::get<void *>(nullptr, loc));
64     });
65 
66     ScopedDiagnosticHandler diagHandler(&getContext(), [](Diagnostic &diag) {
67       auto &os = llvm::outs();
68       if (diag.getLocation().isa<OpaqueLoc>()) {
69         MyLocation *loc = OpaqueLoc::getUnderlyingLocationOrNull<MyLocation *>(
70             diag.getLocation());
71         if (loc)
72           os << "MyLocation: " << loc->id;
73         else
74           os << "nullptr";
75       }
76       os << ": " << diag << '\n';
77       os.flush();
78     });
79 
80     getOperation().walk([&](Operation *op) { op->emitOpError(); });
81   }
82 };
83 
84 } // namespace
85 
86 namespace mlir {
87 namespace test {
88 void registerTestOpaqueLoc() { PassRegistration<TestOpaqueLoc>(); }
89 } // namespace test
90 } // namespace mlir
91