1353358Sdim//===----- llvm/CodeGen/GlobalISel/GISelChangeObserver.h --------*- C++ -*-===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim// 9343171Sdim/// This contains common code to allow clients to notify changes to machine 10343171Sdim/// instr. 11343171Sdim// 12343171Sdim//===----------------------------------------------------------------------===// 13343171Sdim#ifndef LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H 14343171Sdim#define LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H 15343171Sdim 16343171Sdim#include "llvm/ADT/SmallPtrSet.h" 17343171Sdim#include "llvm/CodeGen/MachineFunction.h" 18343171Sdim 19343171Sdimnamespace llvm { 20343171Sdimclass MachineInstr; 21343171Sdimclass MachineRegisterInfo; 22343171Sdim 23343171Sdim/// Abstract class that contains various methods for clients to notify about 24343171Sdim/// changes. This should be the preferred way for APIs to notify changes. 25343171Sdim/// Typically calling erasingInstr/createdInstr multiple times should not affect 26343171Sdim/// the result. The observer would likely need to check if it was already 27343171Sdim/// notified earlier (consider using GISelWorkList). 28343171Sdimclass GISelChangeObserver { 29343171Sdim SmallPtrSet<MachineInstr *, 4> ChangingAllUsesOfReg; 30343171Sdim 31343171Sdimpublic: 32343171Sdim virtual ~GISelChangeObserver() {} 33343171Sdim 34343171Sdim /// An instruction is about to be erased. 35343171Sdim virtual void erasingInstr(MachineInstr &MI) = 0; 36353358Sdim 37353358Sdim /// An instruction has been created and inserted into the function. 38353358Sdim /// Note that the instruction might not be a fully fledged instruction at this 39353358Sdim /// point and won't be if the MachineFunction::Delegate is calling it. This is 40353358Sdim /// because the delegate only sees the construction of the MachineInstr before 41353358Sdim /// operands have been added. 42343171Sdim virtual void createdInstr(MachineInstr &MI) = 0; 43353358Sdim 44343171Sdim /// This instruction is about to be mutated in some way. 45343171Sdim virtual void changingInstr(MachineInstr &MI) = 0; 46353358Sdim 47343171Sdim /// This instruction was mutated in some way. 48343171Sdim virtual void changedInstr(MachineInstr &MI) = 0; 49343171Sdim 50343171Sdim /// All the instructions using the given register are being changed. 51343171Sdim /// For convenience, finishedChangingAllUsesOfReg() will report the completion 52343171Sdim /// of the changes. The use list may change between this call and 53343171Sdim /// finishedChangingAllUsesOfReg(). 54343171Sdim void changingAllUsesOfReg(const MachineRegisterInfo &MRI, unsigned Reg); 55343171Sdim /// All instructions reported as changing by changingAllUsesOfReg() have 56343171Sdim /// finished being changed. 57343171Sdim void finishedChangingAllUsesOfReg(); 58343171Sdim 59343171Sdim}; 60343171Sdim 61343171Sdim/// Simple wrapper observer that takes several observers, and calls 62343171Sdim/// each one for each event. If there are multiple observers (say CSE, 63343171Sdim/// Legalizer, Combiner), it's sufficient to register this to the machine 64343171Sdim/// function as the delegate. 65343171Sdimclass GISelObserverWrapper : public MachineFunction::Delegate, 66343171Sdim public GISelChangeObserver { 67343171Sdim SmallVector<GISelChangeObserver *, 4> Observers; 68343171Sdim 69343171Sdimpublic: 70343171Sdim GISelObserverWrapper() = default; 71343171Sdim GISelObserverWrapper(ArrayRef<GISelChangeObserver *> Obs) 72343171Sdim : Observers(Obs.begin(), Obs.end()) {} 73343171Sdim // Adds an observer. 74343171Sdim void addObserver(GISelChangeObserver *O) { Observers.push_back(O); } 75343171Sdim // Removes an observer from the list and does nothing if observer is not 76343171Sdim // present. 77343171Sdim void removeObserver(GISelChangeObserver *O) { 78343171Sdim auto It = std::find(Observers.begin(), Observers.end(), O); 79343171Sdim if (It != Observers.end()) 80343171Sdim Observers.erase(It); 81343171Sdim } 82343171Sdim // API for Observer. 83343171Sdim void erasingInstr(MachineInstr &MI) override { 84343171Sdim for (auto &O : Observers) 85343171Sdim O->erasingInstr(MI); 86343171Sdim } 87343171Sdim void createdInstr(MachineInstr &MI) override { 88343171Sdim for (auto &O : Observers) 89343171Sdim O->createdInstr(MI); 90343171Sdim } 91343171Sdim void changingInstr(MachineInstr &MI) override { 92343171Sdim for (auto &O : Observers) 93343171Sdim O->changingInstr(MI); 94343171Sdim } 95343171Sdim void changedInstr(MachineInstr &MI) override { 96343171Sdim for (auto &O : Observers) 97343171Sdim O->changedInstr(MI); 98343171Sdim } 99343171Sdim // API for MachineFunction::Delegate 100343171Sdim void MF_HandleInsertion(MachineInstr &MI) override { createdInstr(MI); } 101343171Sdim void MF_HandleRemoval(MachineInstr &MI) override { erasingInstr(MI); } 102343171Sdim}; 103343171Sdim 104343171Sdim/// A simple RAII based CSEInfo installer. 105343171Sdim/// Use this in a scope to install a delegate to the MachineFunction and reset 106343171Sdim/// it at the end of the scope. 107343171Sdimclass RAIIDelegateInstaller { 108343171Sdim MachineFunction &MF; 109343171Sdim MachineFunction::Delegate *Delegate; 110343171Sdim 111343171Sdimpublic: 112343171Sdim RAIIDelegateInstaller(MachineFunction &MF, MachineFunction::Delegate *Del); 113343171Sdim ~RAIIDelegateInstaller(); 114343171Sdim}; 115343171Sdim 116343171Sdim} // namespace llvm 117343171Sdim#endif 118