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<ModuleOp>(op->getParentOp()) ||
51           op->hasTrait<OpTrait::IsTerminator>())
52         return;
53 
54       OpBuilder builder(op);
55 
56       /// Add the same operation but with fallback location to test the
57       /// corresponding get method and serialization.
58       Operation *opCloned1 = builder.clone(*op);
59       opCloned1->setLoc(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 *opCloned2 = builder.clone(*op);
64       opCloned2->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 } // namespace
86 
87 namespace mlir {
88 namespace test {
89 void registerTestOpaqueLoc() { PassRegistration<TestOpaqueLoc>(); }
90 } // namespace test
91 } // namespace mlir
92