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