1 | //===----- llvm/CodeGen/GlobalISel/GISelChangeObserver.h --------*- C++ -*-===// |
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 | /// \file |
9 | /// This contains common code to allow clients to notify changes to machine |
10 | /// instr. |
11 | /// |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H |
15 | #define LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H |
16 | |
17 | #include "llvm/ADT/SmallPtrSet.h" |
18 | #include "llvm/CodeGen/MachineFunction.h" |
19 | |
20 | namespace llvm { |
21 | class MachineInstr; |
22 | class MachineRegisterInfo; |
23 | |
24 | /// Abstract class that contains various methods for clients to notify about |
25 | /// changes. This should be the preferred way for APIs to notify changes. |
26 | /// Typically calling erasingInstr/createdInstr multiple times should not affect |
27 | /// the result. The observer would likely need to check if it was already |
28 | /// notified earlier (consider using GISelWorkList). |
29 | class GISelChangeObserver { |
30 | SmallPtrSet<MachineInstr *, 4> ChangingAllUsesOfReg; |
31 | |
32 | public: |
33 | virtual ~GISelChangeObserver() = default; |
34 | |
35 | /// An instruction is about to be erased. |
36 | virtual void erasingInstr(MachineInstr &MI) = 0; |
37 | |
38 | /// An instruction has been created and inserted into the function. |
39 | /// Note that the instruction might not be a fully fledged instruction at this |
40 | /// point and won't be if the MachineFunction::Delegate is calling it. This is |
41 | /// because the delegate only sees the construction of the MachineInstr before |
42 | /// operands have been added. |
43 | virtual void createdInstr(MachineInstr &MI) = 0; |
44 | |
45 | /// This instruction is about to be mutated in some way. |
46 | virtual void changingInstr(MachineInstr &MI) = 0; |
47 | |
48 | /// This instruction was mutated in some way. |
49 | virtual void changedInstr(MachineInstr &MI) = 0; |
50 | |
51 | /// All the instructions using the given register are being changed. |
52 | /// For convenience, finishedChangingAllUsesOfReg() will report the completion |
53 | /// of the changes. The use list may change between this call and |
54 | /// finishedChangingAllUsesOfReg(). |
55 | void changingAllUsesOfReg(const MachineRegisterInfo &MRI, Register Reg); |
56 | /// All instructions reported as changing by changingAllUsesOfReg() have |
57 | /// finished being changed. |
58 | void finishedChangingAllUsesOfReg(); |
59 | |
60 | }; |
61 | |
62 | /// Simple wrapper observer that takes several observers, and calls |
63 | /// each one for each event. If there are multiple observers (say CSE, |
64 | /// Legalizer, Combiner), it's sufficient to register this to the machine |
65 | /// function as the delegate. |
66 | class GISelObserverWrapper : public MachineFunction::Delegate, |
67 | public GISelChangeObserver { |
68 | SmallVector<GISelChangeObserver *, 4> Observers; |
69 | |
70 | public: |
71 | GISelObserverWrapper() = default; |
72 | GISelObserverWrapper(ArrayRef<GISelChangeObserver *> Obs) |
73 | : Observers(Obs.begin(), Obs.end()) {} |
74 | // Adds an observer. |
75 | void addObserver(GISelChangeObserver *O) { Observers.push_back(Elt: O); } |
76 | // Removes an observer from the list and does nothing if observer is not |
77 | // present. |
78 | void removeObserver(GISelChangeObserver *O) { |
79 | auto It = llvm::find(Range&: Observers, Val: O); |
80 | if (It != Observers.end()) |
81 | Observers.erase(CI: It); |
82 | } |
83 | // API for Observer. |
84 | void erasingInstr(MachineInstr &MI) override { |
85 | for (auto &O : Observers) |
86 | O->erasingInstr(MI); |
87 | } |
88 | void createdInstr(MachineInstr &MI) override { |
89 | for (auto &O : Observers) |
90 | O->createdInstr(MI); |
91 | } |
92 | void changingInstr(MachineInstr &MI) override { |
93 | for (auto &O : Observers) |
94 | O->changingInstr(MI); |
95 | } |
96 | void changedInstr(MachineInstr &MI) override { |
97 | for (auto &O : Observers) |
98 | O->changedInstr(MI); |
99 | } |
100 | // API for MachineFunction::Delegate |
101 | void MF_HandleInsertion(MachineInstr &MI) override { createdInstr(MI); } |
102 | void MF_HandleRemoval(MachineInstr &MI) override { erasingInstr(MI); } |
103 | }; |
104 | |
105 | /// A simple RAII based Delegate installer. |
106 | /// Use this in a scope to install a delegate to the MachineFunction and reset |
107 | /// it at the end of the scope. |
108 | class RAIIDelegateInstaller { |
109 | MachineFunction &MF; |
110 | MachineFunction::Delegate *Delegate; |
111 | |
112 | public: |
113 | RAIIDelegateInstaller(MachineFunction &MF, MachineFunction::Delegate *Del); |
114 | ~RAIIDelegateInstaller(); |
115 | }; |
116 | |
117 | /// A simple RAII based Observer installer. |
118 | /// Use this in a scope to install the Observer to the MachineFunction and reset |
119 | /// it at the end of the scope. |
120 | class RAIIMFObserverInstaller { |
121 | MachineFunction &MF; |
122 | |
123 | public: |
124 | RAIIMFObserverInstaller(MachineFunction &MF, GISelChangeObserver &Observer); |
125 | ~RAIIMFObserverInstaller(); |
126 | }; |
127 | |
128 | /// Class to install both of the above. |
129 | class RAIIMFObsDelInstaller { |
130 | RAIIDelegateInstaller DelI; |
131 | RAIIMFObserverInstaller ObsI; |
132 | |
133 | public: |
134 | RAIIMFObsDelInstaller(MachineFunction &MF, GISelObserverWrapper &Wrapper) |
135 | : DelI(MF, &Wrapper), ObsI(MF, Wrapper) {} |
136 | ~RAIIMFObsDelInstaller() = default; |
137 | }; |
138 | |
139 | } // namespace llvm |
140 | #endif |
141 | |