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 |