Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- llvm/CodeGen/GlobalISel/CSEInfo.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 | /// Provides analysis for continuously CSEing during GISel passes. |
||
10 | /// |
||
11 | //===----------------------------------------------------------------------===// |
||
12 | #ifndef LLVM_CODEGEN_GLOBALISEL_CSEINFO_H |
||
13 | #define LLVM_CODEGEN_GLOBALISEL_CSEINFO_H |
||
14 | |||
15 | #include "llvm/ADT/FoldingSet.h" |
||
16 | #include "llvm/CodeGen/CSEConfigBase.h" |
||
17 | #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" |
||
18 | #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" |
||
19 | #include "llvm/CodeGen/MachineFunctionPass.h" |
||
20 | #include "llvm/Support/Allocator.h" |
||
21 | #include "llvm/Support/CodeGen.h" |
||
22 | |||
23 | namespace llvm { |
||
24 | class MachineBasicBlock; |
||
25 | |||
26 | /// A class that wraps MachineInstrs and derives from FoldingSetNode in order to |
||
27 | /// be uniqued in a CSEMap. The tradeoff here is extra memory allocations for |
||
28 | /// UniqueMachineInstr vs making MachineInstr bigger. |
||
29 | class UniqueMachineInstr : public FoldingSetNode { |
||
30 | friend class GISelCSEInfo; |
||
31 | const MachineInstr *MI; |
||
32 | explicit UniqueMachineInstr(const MachineInstr *MI) : MI(MI) {} |
||
33 | |||
34 | public: |
||
35 | void Profile(FoldingSetNodeID &ID); |
||
36 | }; |
||
37 | |||
38 | // A CSE config for fully optimized builds. |
||
39 | class CSEConfigFull : public CSEConfigBase { |
||
40 | public: |
||
41 | virtual ~CSEConfigFull() = default; |
||
42 | bool shouldCSEOpc(unsigned Opc) override; |
||
43 | }; |
||
44 | |||
45 | // Commonly used for O0 config. |
||
46 | class CSEConfigConstantOnly : public CSEConfigBase { |
||
47 | public: |
||
48 | virtual ~CSEConfigConstantOnly() = default; |
||
49 | bool shouldCSEOpc(unsigned Opc) override; |
||
50 | }; |
||
51 | |||
52 | // Returns the standard expected CSEConfig for the given optimization level. |
||
53 | // We have this logic here so targets can make use of it from their derived |
||
54 | // TargetPassConfig, but can't put this logic into TargetPassConfig directly |
||
55 | // because the CodeGen library can't depend on GlobalISel. |
||
56 | std::unique_ptr<CSEConfigBase> |
||
57 | getStandardCSEConfigForOpt(CodeGenOpt::Level Level); |
||
58 | |||
59 | /// The CSE Analysis object. |
||
60 | /// This installs itself as a delegate to the MachineFunction to track |
||
61 | /// new instructions as well as deletions. It however will not be able to |
||
62 | /// track instruction mutations. In such cases, recordNewInstruction should be |
||
63 | /// called (for eg inside MachineIRBuilder::recordInsertion). |
||
64 | /// Also because of how just the instruction can be inserted without adding any |
||
65 | /// operands to the instruction, instructions are uniqued and inserted lazily. |
||
66 | /// CSEInfo should assert when trying to enter an incomplete instruction into |
||
67 | /// the CSEMap. There is Opcode level granularity on which instructions can be |
||
68 | /// CSE'd and for now, only Generic instructions are CSEable. |
||
69 | class GISelCSEInfo : public GISelChangeObserver { |
||
70 | // Make it accessible only to CSEMIRBuilder. |
||
71 | friend class CSEMIRBuilder; |
||
72 | |||
73 | BumpPtrAllocator UniqueInstrAllocator; |
||
74 | FoldingSet<UniqueMachineInstr> CSEMap; |
||
75 | MachineRegisterInfo *MRI = nullptr; |
||
76 | MachineFunction *MF = nullptr; |
||
77 | std::unique_ptr<CSEConfigBase> CSEOpt; |
||
78 | /// Keep a cache of UniqueInstrs for each MachineInstr. In GISel, |
||
79 | /// often instructions are mutated (while their ID has completely changed). |
||
80 | /// Whenever mutation happens, invalidate the UniqueMachineInstr for the |
||
81 | /// MachineInstr |
||
82 | DenseMap<const MachineInstr *, UniqueMachineInstr *> InstrMapping; |
||
83 | |||
84 | /// Store instructions that are not fully formed in TemporaryInsts. |
||
85 | /// Also because CSE insertion happens lazily, we can remove insts from this |
||
86 | /// list and avoid inserting and then removing from the CSEMap. |
||
87 | GISelWorkList<8> TemporaryInsts; |
||
88 | |||
89 | // Only used in asserts. |
||
90 | DenseMap<unsigned, unsigned> OpcodeHitTable; |
||
91 | |||
92 | bool isUniqueMachineInstValid(const UniqueMachineInstr &UMI) const; |
||
93 | |||
94 | void invalidateUniqueMachineInstr(UniqueMachineInstr *UMI); |
||
95 | |||
96 | UniqueMachineInstr *getNodeIfExists(FoldingSetNodeID &ID, |
||
97 | MachineBasicBlock *MBB, void *&InsertPos); |
||
98 | |||
99 | /// Allocate and construct a new UniqueMachineInstr for MI and return. |
||
100 | UniqueMachineInstr *getUniqueInstrForMI(const MachineInstr *MI); |
||
101 | |||
102 | void insertNode(UniqueMachineInstr *UMI, void *InsertPos = nullptr); |
||
103 | |||
104 | /// Get the MachineInstr(Unique) if it exists already in the CSEMap and the |
||
105 | /// same MachineBasicBlock. |
||
106 | MachineInstr *getMachineInstrIfExists(FoldingSetNodeID &ID, |
||
107 | MachineBasicBlock *MBB, |
||
108 | void *&InsertPos); |
||
109 | |||
110 | /// Use this method to allocate a new UniqueMachineInstr for MI and insert it |
||
111 | /// into the CSEMap. MI should return true for shouldCSE(MI->getOpcode()) |
||
112 | void insertInstr(MachineInstr *MI, void *InsertPos = nullptr); |
||
113 | |||
114 | public: |
||
115 | GISelCSEInfo() = default; |
||
116 | |||
117 | virtual ~GISelCSEInfo(); |
||
118 | |||
119 | void setMF(MachineFunction &MF); |
||
120 | |||
121 | Error verify(); |
||
122 | |||
123 | /// Records a newly created inst in a list and lazily insert it to the CSEMap. |
||
124 | /// Sometimes, this method might be called with a partially constructed |
||
125 | /// MachineInstr, |
||
126 | // (right after BuildMI without adding any operands) - and in such cases, |
||
127 | // defer the hashing of the instruction to a later stage. |
||
128 | void recordNewInstruction(MachineInstr *MI); |
||
129 | |||
130 | /// Use this callback to inform CSE about a newly fully created instruction. |
||
131 | void handleRecordedInst(MachineInstr *MI); |
||
132 | |||
133 | /// Use this callback to insert all the recorded instructions. At this point, |
||
134 | /// all of these insts need to be fully constructed and should not be missing |
||
135 | /// any operands. |
||
136 | void handleRecordedInsts(); |
||
137 | |||
138 | /// Remove this inst from the CSE map. If this inst has not been inserted yet, |
||
139 | /// it will be removed from the Tempinsts list if it exists. |
||
140 | void handleRemoveInst(MachineInstr *MI); |
||
141 | |||
142 | void releaseMemory(); |
||
143 | |||
144 | void setCSEConfig(std::unique_ptr<CSEConfigBase> Opt) { |
||
145 | CSEOpt = std::move(Opt); |
||
146 | } |
||
147 | |||
148 | bool shouldCSE(unsigned Opc) const; |
||
149 | |||
150 | void analyze(MachineFunction &MF); |
||
151 | |||
152 | void countOpcodeHit(unsigned Opc); |
||
153 | |||
154 | void print(); |
||
155 | |||
156 | // Observer API |
||
157 | void erasingInstr(MachineInstr &MI) override; |
||
158 | void createdInstr(MachineInstr &MI) override; |
||
159 | void changingInstr(MachineInstr &MI) override; |
||
160 | void changedInstr(MachineInstr &MI) override; |
||
161 | }; |
||
162 | |||
163 | class TargetRegisterClass; |
||
164 | class RegisterBank; |
||
165 | |||
166 | // Simple builder class to easily profile properties about MIs. |
||
167 | class GISelInstProfileBuilder { |
||
168 | FoldingSetNodeID &ID; |
||
169 | const MachineRegisterInfo &MRI; |
||
170 | |||
171 | public: |
||
172 | GISelInstProfileBuilder(FoldingSetNodeID &ID, const MachineRegisterInfo &MRI) |
||
173 | : ID(ID), MRI(MRI) {} |
||
174 | // Profiling methods. |
||
175 | const GISelInstProfileBuilder &addNodeIDOpcode(unsigned Opc) const; |
||
176 | const GISelInstProfileBuilder &addNodeIDRegType(const LLT Ty) const; |
||
177 | const GISelInstProfileBuilder &addNodeIDRegType(const Register) const; |
||
178 | |||
179 | const GISelInstProfileBuilder & |
||
180 | addNodeIDRegType(const TargetRegisterClass *RC) const; |
||
181 | const GISelInstProfileBuilder &addNodeIDRegType(const RegisterBank *RB) const; |
||
182 | |||
183 | const GISelInstProfileBuilder &addNodeIDRegNum(Register Reg) const; |
||
184 | |||
185 | const GISelInstProfileBuilder &addNodeIDReg(Register Reg) const; |
||
186 | |||
187 | const GISelInstProfileBuilder &addNodeIDImmediate(int64_t Imm) const; |
||
188 | const GISelInstProfileBuilder & |
||
189 | addNodeIDMBB(const MachineBasicBlock *MBB) const; |
||
190 | |||
191 | const GISelInstProfileBuilder & |
||
192 | addNodeIDMachineOperand(const MachineOperand &MO) const; |
||
193 | |||
194 | const GISelInstProfileBuilder &addNodeIDFlag(unsigned Flag) const; |
||
195 | const GISelInstProfileBuilder &addNodeID(const MachineInstr *MI) const; |
||
196 | }; |
||
197 | |||
198 | /// Simple wrapper that does the following. |
||
199 | /// 1) Lazily evaluate the MachineFunction to compute CSEable instructions. |
||
200 | /// 2) Allows configuration of which instructions are CSEd through CSEConfig |
||
201 | /// object. Provides a method called get which takes a CSEConfig object. |
||
202 | class GISelCSEAnalysisWrapper { |
||
203 | GISelCSEInfo Info; |
||
204 | MachineFunction *MF = nullptr; |
||
205 | bool AlreadyComputed = false; |
||
206 | |||
207 | public: |
||
208 | /// Takes a CSEConfigBase object that defines what opcodes get CSEd. |
||
209 | /// If CSEConfig is already set, and the CSE Analysis has been preserved, |
||
210 | /// it will not use the new CSEOpt(use Recompute to force using the new |
||
211 | /// CSEOpt). |
||
212 | GISelCSEInfo &get(std::unique_ptr<CSEConfigBase> CSEOpt, |
||
213 | bool ReCompute = false); |
||
214 | void setMF(MachineFunction &MFunc) { MF = &MFunc; } |
||
215 | void setComputed(bool Computed) { AlreadyComputed = Computed; } |
||
216 | void releaseMemory() { Info.releaseMemory(); } |
||
217 | }; |
||
218 | |||
219 | /// The actual analysis pass wrapper. |
||
220 | class GISelCSEAnalysisWrapperPass : public MachineFunctionPass { |
||
221 | GISelCSEAnalysisWrapper Wrapper; |
||
222 | |||
223 | public: |
||
224 | static char ID; |
||
225 | GISelCSEAnalysisWrapperPass(); |
||
226 | |||
227 | void getAnalysisUsage(AnalysisUsage &AU) const override; |
||
228 | |||
229 | const GISelCSEAnalysisWrapper &getCSEWrapper() const { return Wrapper; } |
||
230 | GISelCSEAnalysisWrapper &getCSEWrapper() { return Wrapper; } |
||
231 | |||
232 | bool runOnMachineFunction(MachineFunction &MF) override; |
||
233 | |||
234 | void releaseMemory() override { |
||
235 | Wrapper.releaseMemory(); |
||
236 | Wrapper.setComputed(false); |
||
237 | } |
||
238 | }; |
||
239 | |||
240 | } // namespace llvm |
||
241 | |||
242 | #endif |