aboutsummaryrefslogtreecommitdiff
path: root/llvm/include/llvm/CodeGen/GlobalISel/GISelChangeObserver.h
blob: 79d71b2c89820f7aa2e96579f8b10bf9f60ec504 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//===----- llvm/CodeGen/GlobalISel/GISelChangeObserver.h --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This contains common code to allow clients to notify changes to machine
/// instr.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H
#define LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H

#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/CodeGen/MachineFunction.h"

namespace llvm {
class MachineInstr;
class MachineRegisterInfo;

/// Abstract class that contains various methods for clients to notify about
/// changes. This should be the preferred way for APIs to notify changes.
/// Typically calling erasingInstr/createdInstr multiple times should not affect
/// the result. The observer would likely need to check if it was already
/// notified earlier (consider using GISelWorkList).
class GISelChangeObserver {
  SmallPtrSet<MachineInstr *, 4> ChangingAllUsesOfReg;

public:
  virtual ~GISelChangeObserver() {}

  /// An instruction is about to be erased.
  virtual void erasingInstr(MachineInstr &MI) = 0;

  /// An instruction has been created and inserted into the function.
  /// Note that the instruction might not be a fully fledged instruction at this
  /// point and won't be if the MachineFunction::Delegate is calling it. This is
  /// because the delegate only sees the construction of the MachineInstr before
  /// operands have been added.
  virtual void createdInstr(MachineInstr &MI) = 0;

  /// This instruction is about to be mutated in some way.
  virtual void changingInstr(MachineInstr &MI) = 0;

  /// This instruction was mutated in some way.
  virtual void changedInstr(MachineInstr &MI) = 0;

  /// All the instructions using the given register are being changed.
  /// For convenience, finishedChangingAllUsesOfReg() will report the completion
  /// of the changes. The use list may change between this call and
  /// finishedChangingAllUsesOfReg().
  void changingAllUsesOfReg(const MachineRegisterInfo &MRI, Register Reg);
  /// All instructions reported as changing by changingAllUsesOfReg() have
  /// finished being changed.
  void finishedChangingAllUsesOfReg();

};

/// Simple wrapper observer that takes several observers, and calls
/// each one for each event. If there are multiple observers (say CSE,
/// Legalizer, Combiner), it's sufficient to register this to the machine
/// function as the delegate.
class GISelObserverWrapper : public MachineFunction::Delegate,
                             public GISelChangeObserver {
  SmallVector<GISelChangeObserver *, 4> Observers;

public:
  GISelObserverWrapper() = default;
  GISelObserverWrapper(ArrayRef<GISelChangeObserver *> Obs)
      : Observers(Obs.begin(), Obs.end()) {}
  // Adds an observer.
  void addObserver(GISelChangeObserver *O) { Observers.push_back(O); }
  // Removes an observer from the list and does nothing if observer is not
  // present.
  void removeObserver(GISelChangeObserver *O) {
    auto It = std::find(Observers.begin(), Observers.end(), O);
    if (It != Observers.end())
      Observers.erase(It);
  }
  // API for Observer.
  void erasingInstr(MachineInstr &MI) override {
    for (auto &O : Observers)
      O->erasingInstr(MI);
  }
  void createdInstr(MachineInstr &MI) override {
    for (auto &O : Observers)
      O->createdInstr(MI);
  }
  void changingInstr(MachineInstr &MI) override {
    for (auto &O : Observers)
      O->changingInstr(MI);
  }
  void changedInstr(MachineInstr &MI) override {
    for (auto &O : Observers)
      O->changedInstr(MI);
  }
  // API for MachineFunction::Delegate
  void MF_HandleInsertion(MachineInstr &MI) override { createdInstr(MI); }
  void MF_HandleRemoval(MachineInstr &MI) override { erasingInstr(MI); }
};

/// A simple RAII based Delegate installer.
/// Use this in a scope to install a delegate to the MachineFunction and reset
/// it at the end of the scope.
class RAIIDelegateInstaller {
  MachineFunction &MF;
  MachineFunction::Delegate *Delegate;

public:
  RAIIDelegateInstaller(MachineFunction &MF, MachineFunction::Delegate *Del);
  ~RAIIDelegateInstaller();
};

/// A simple RAII based Observer installer.
/// Use this in a scope to install the Observer to the MachineFunction and reset
/// it at the end of the scope.
class RAIIMFObserverInstaller {
  MachineFunction &MF;

public:
  RAIIMFObserverInstaller(MachineFunction &MF, GISelChangeObserver &Observer);
  ~RAIIMFObserverInstaller();
};

/// Class to install both of the above.
class RAIIMFObsDelInstaller {
  RAIIDelegateInstaller DelI;
  RAIIMFObserverInstaller ObsI;

public:
  RAIIMFObsDelInstaller(MachineFunction &MF, GISelObserverWrapper &Wrapper)
      : DelI(MF, &Wrapper), ObsI(MF, Wrapper) {}
  ~RAIIMFObsDelInstaller() = default;
};

} // namespace llvm
#endif