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