109467b48Spatrick //===- llvm/CodeGen/GlobalISel/CSEInfo.h ------------------*- C++ -*-===// 209467b48Spatrick // 309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information. 509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 609467b48Spatrick // 709467b48Spatrick //===----------------------------------------------------------------------===// 873471bf0Spatrick /// \file 909467b48Spatrick /// Provides analysis for continuously CSEing during GISel passes. 1073471bf0Spatrick /// 1109467b48Spatrick //===----------------------------------------------------------------------===// 1209467b48Spatrick #ifndef LLVM_CODEGEN_GLOBALISEL_CSEINFO_H 1309467b48Spatrick #define LLVM_CODEGEN_GLOBALISEL_CSEINFO_H 1409467b48Spatrick 1509467b48Spatrick #include "llvm/ADT/FoldingSet.h" 1609467b48Spatrick #include "llvm/CodeGen/CSEConfigBase.h" 1709467b48Spatrick #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" 1809467b48Spatrick #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" 1909467b48Spatrick #include "llvm/CodeGen/MachineFunctionPass.h" 2009467b48Spatrick #include "llvm/Support/Allocator.h" 2173471bf0Spatrick #include "llvm/Support/CodeGen.h" 2209467b48Spatrick 2309467b48Spatrick namespace llvm { 2473471bf0Spatrick class MachineBasicBlock; 2509467b48Spatrick 2609467b48Spatrick /// A class that wraps MachineInstrs and derives from FoldingSetNode in order to 2709467b48Spatrick /// be uniqued in a CSEMap. The tradeoff here is extra memory allocations for 2809467b48Spatrick /// UniqueMachineInstr vs making MachineInstr bigger. 2909467b48Spatrick class UniqueMachineInstr : public FoldingSetNode { 3009467b48Spatrick friend class GISelCSEInfo; 3109467b48Spatrick const MachineInstr *MI; UniqueMachineInstr(const MachineInstr * MI)3209467b48Spatrick explicit UniqueMachineInstr(const MachineInstr *MI) : MI(MI) {} 3309467b48Spatrick 3409467b48Spatrick public: 3509467b48Spatrick void Profile(FoldingSetNodeID &ID); 3609467b48Spatrick }; 3709467b48Spatrick 3809467b48Spatrick // A CSE config for fully optimized builds. 3909467b48Spatrick class CSEConfigFull : public CSEConfigBase { 4009467b48Spatrick public: 4109467b48Spatrick virtual ~CSEConfigFull() = default; 42*d415bd75Srobert bool shouldCSEOpc(unsigned Opc) override; 4309467b48Spatrick }; 4409467b48Spatrick 4509467b48Spatrick // Commonly used for O0 config. 4609467b48Spatrick class CSEConfigConstantOnly : public CSEConfigBase { 4709467b48Spatrick public: 4809467b48Spatrick virtual ~CSEConfigConstantOnly() = default; 49*d415bd75Srobert bool shouldCSEOpc(unsigned Opc) override; 5009467b48Spatrick }; 5109467b48Spatrick 5209467b48Spatrick // Returns the standard expected CSEConfig for the given optimization level. 5309467b48Spatrick // We have this logic here so targets can make use of it from their derived 5409467b48Spatrick // TargetPassConfig, but can't put this logic into TargetPassConfig directly 5509467b48Spatrick // because the CodeGen library can't depend on GlobalISel. 5609467b48Spatrick std::unique_ptr<CSEConfigBase> 5709467b48Spatrick getStandardCSEConfigForOpt(CodeGenOpt::Level Level); 5809467b48Spatrick 5909467b48Spatrick /// The CSE Analysis object. 6009467b48Spatrick /// This installs itself as a delegate to the MachineFunction to track 6109467b48Spatrick /// new instructions as well as deletions. It however will not be able to 6209467b48Spatrick /// track instruction mutations. In such cases, recordNewInstruction should be 6309467b48Spatrick /// called (for eg inside MachineIRBuilder::recordInsertion). 6409467b48Spatrick /// Also because of how just the instruction can be inserted without adding any 6509467b48Spatrick /// operands to the instruction, instructions are uniqued and inserted lazily. 6609467b48Spatrick /// CSEInfo should assert when trying to enter an incomplete instruction into 6709467b48Spatrick /// the CSEMap. There is Opcode level granularity on which instructions can be 6809467b48Spatrick /// CSE'd and for now, only Generic instructions are CSEable. 6909467b48Spatrick class GISelCSEInfo : public GISelChangeObserver { 7009467b48Spatrick // Make it accessible only to CSEMIRBuilder. 7109467b48Spatrick friend class CSEMIRBuilder; 7209467b48Spatrick 7309467b48Spatrick BumpPtrAllocator UniqueInstrAllocator; 7409467b48Spatrick FoldingSet<UniqueMachineInstr> CSEMap; 7509467b48Spatrick MachineRegisterInfo *MRI = nullptr; 7609467b48Spatrick MachineFunction *MF = nullptr; 7709467b48Spatrick std::unique_ptr<CSEConfigBase> CSEOpt; 7809467b48Spatrick /// Keep a cache of UniqueInstrs for each MachineInstr. In GISel, 7909467b48Spatrick /// often instructions are mutated (while their ID has completely changed). 8009467b48Spatrick /// Whenever mutation happens, invalidate the UniqueMachineInstr for the 8109467b48Spatrick /// MachineInstr 8209467b48Spatrick DenseMap<const MachineInstr *, UniqueMachineInstr *> InstrMapping; 8309467b48Spatrick 8409467b48Spatrick /// Store instructions that are not fully formed in TemporaryInsts. 8509467b48Spatrick /// Also because CSE insertion happens lazily, we can remove insts from this 8609467b48Spatrick /// list and avoid inserting and then removing from the CSEMap. 8709467b48Spatrick GISelWorkList<8> TemporaryInsts; 8809467b48Spatrick 8909467b48Spatrick // Only used in asserts. 9009467b48Spatrick DenseMap<unsigned, unsigned> OpcodeHitTable; 9109467b48Spatrick 9209467b48Spatrick bool isUniqueMachineInstValid(const UniqueMachineInstr &UMI) const; 9309467b48Spatrick 9409467b48Spatrick void invalidateUniqueMachineInstr(UniqueMachineInstr *UMI); 9509467b48Spatrick 9609467b48Spatrick UniqueMachineInstr *getNodeIfExists(FoldingSetNodeID &ID, 9709467b48Spatrick MachineBasicBlock *MBB, void *&InsertPos); 9809467b48Spatrick 9909467b48Spatrick /// Allocate and construct a new UniqueMachineInstr for MI and return. 10009467b48Spatrick UniqueMachineInstr *getUniqueInstrForMI(const MachineInstr *MI); 10109467b48Spatrick 10209467b48Spatrick void insertNode(UniqueMachineInstr *UMI, void *InsertPos = nullptr); 10309467b48Spatrick 10409467b48Spatrick /// Get the MachineInstr(Unique) if it exists already in the CSEMap and the 10509467b48Spatrick /// same MachineBasicBlock. 10609467b48Spatrick MachineInstr *getMachineInstrIfExists(FoldingSetNodeID &ID, 10709467b48Spatrick MachineBasicBlock *MBB, 10809467b48Spatrick void *&InsertPos); 10909467b48Spatrick 11009467b48Spatrick /// Use this method to allocate a new UniqueMachineInstr for MI and insert it 11109467b48Spatrick /// into the CSEMap. MI should return true for shouldCSE(MI->getOpcode()) 11209467b48Spatrick void insertInstr(MachineInstr *MI, void *InsertPos = nullptr); 11309467b48Spatrick 11409467b48Spatrick public: 11509467b48Spatrick GISelCSEInfo() = default; 11609467b48Spatrick 11709467b48Spatrick virtual ~GISelCSEInfo(); 11809467b48Spatrick 11909467b48Spatrick void setMF(MachineFunction &MF); 12009467b48Spatrick 121097a140dSpatrick Error verify(); 122097a140dSpatrick 12309467b48Spatrick /// Records a newly created inst in a list and lazily insert it to the CSEMap. 12409467b48Spatrick /// Sometimes, this method might be called with a partially constructed 12509467b48Spatrick /// MachineInstr, 12609467b48Spatrick // (right after BuildMI without adding any operands) - and in such cases, 12709467b48Spatrick // defer the hashing of the instruction to a later stage. 12809467b48Spatrick void recordNewInstruction(MachineInstr *MI); 12909467b48Spatrick 13009467b48Spatrick /// Use this callback to inform CSE about a newly fully created instruction. 13109467b48Spatrick void handleRecordedInst(MachineInstr *MI); 13209467b48Spatrick 13309467b48Spatrick /// Use this callback to insert all the recorded instructions. At this point, 13409467b48Spatrick /// all of these insts need to be fully constructed and should not be missing 13509467b48Spatrick /// any operands. 13609467b48Spatrick void handleRecordedInsts(); 13709467b48Spatrick 13809467b48Spatrick /// Remove this inst from the CSE map. If this inst has not been inserted yet, 13909467b48Spatrick /// it will be removed from the Tempinsts list if it exists. 14009467b48Spatrick void handleRemoveInst(MachineInstr *MI); 14109467b48Spatrick 14209467b48Spatrick void releaseMemory(); 14309467b48Spatrick setCSEConfig(std::unique_ptr<CSEConfigBase> Opt)14409467b48Spatrick void setCSEConfig(std::unique_ptr<CSEConfigBase> Opt) { 14509467b48Spatrick CSEOpt = std::move(Opt); 14609467b48Spatrick } 14709467b48Spatrick 14809467b48Spatrick bool shouldCSE(unsigned Opc) const; 14909467b48Spatrick 15009467b48Spatrick void analyze(MachineFunction &MF); 15109467b48Spatrick 15209467b48Spatrick void countOpcodeHit(unsigned Opc); 15309467b48Spatrick 15409467b48Spatrick void print(); 15509467b48Spatrick 15609467b48Spatrick // Observer API 15709467b48Spatrick void erasingInstr(MachineInstr &MI) override; 15809467b48Spatrick void createdInstr(MachineInstr &MI) override; 15909467b48Spatrick void changingInstr(MachineInstr &MI) override; 16009467b48Spatrick void changedInstr(MachineInstr &MI) override; 16109467b48Spatrick }; 16209467b48Spatrick 16309467b48Spatrick class TargetRegisterClass; 16409467b48Spatrick class RegisterBank; 16509467b48Spatrick 16609467b48Spatrick // Simple builder class to easily profile properties about MIs. 16709467b48Spatrick class GISelInstProfileBuilder { 16809467b48Spatrick FoldingSetNodeID &ID; 16909467b48Spatrick const MachineRegisterInfo &MRI; 17009467b48Spatrick 17109467b48Spatrick public: GISelInstProfileBuilder(FoldingSetNodeID & ID,const MachineRegisterInfo & MRI)17209467b48Spatrick GISelInstProfileBuilder(FoldingSetNodeID &ID, const MachineRegisterInfo &MRI) 17309467b48Spatrick : ID(ID), MRI(MRI) {} 17409467b48Spatrick // Profiling methods. 17509467b48Spatrick const GISelInstProfileBuilder &addNodeIDOpcode(unsigned Opc) const; 176097a140dSpatrick const GISelInstProfileBuilder &addNodeIDRegType(const LLT Ty) const; 177097a140dSpatrick const GISelInstProfileBuilder &addNodeIDRegType(const Register) const; 17809467b48Spatrick 17909467b48Spatrick const GISelInstProfileBuilder & 18009467b48Spatrick addNodeIDRegType(const TargetRegisterClass *RC) const; 18109467b48Spatrick const GISelInstProfileBuilder &addNodeIDRegType(const RegisterBank *RB) const; 18209467b48Spatrick 183097a140dSpatrick const GISelInstProfileBuilder &addNodeIDRegNum(Register Reg) const; 18409467b48Spatrick 18573471bf0Spatrick const GISelInstProfileBuilder &addNodeIDReg(Register Reg) const; 18673471bf0Spatrick 18709467b48Spatrick const GISelInstProfileBuilder &addNodeIDImmediate(int64_t Imm) const; 18809467b48Spatrick const GISelInstProfileBuilder & 18909467b48Spatrick addNodeIDMBB(const MachineBasicBlock *MBB) const; 19009467b48Spatrick 19109467b48Spatrick const GISelInstProfileBuilder & 19209467b48Spatrick addNodeIDMachineOperand(const MachineOperand &MO) const; 19309467b48Spatrick 19409467b48Spatrick const GISelInstProfileBuilder &addNodeIDFlag(unsigned Flag) const; 19509467b48Spatrick const GISelInstProfileBuilder &addNodeID(const MachineInstr *MI) const; 19609467b48Spatrick }; 19709467b48Spatrick 19809467b48Spatrick /// Simple wrapper that does the following. 19909467b48Spatrick /// 1) Lazily evaluate the MachineFunction to compute CSEable instructions. 20009467b48Spatrick /// 2) Allows configuration of which instructions are CSEd through CSEConfig 20109467b48Spatrick /// object. Provides a method called get which takes a CSEConfig object. 20209467b48Spatrick class GISelCSEAnalysisWrapper { 20309467b48Spatrick GISelCSEInfo Info; 20409467b48Spatrick MachineFunction *MF = nullptr; 20509467b48Spatrick bool AlreadyComputed = false; 20609467b48Spatrick 20709467b48Spatrick public: 20809467b48Spatrick /// Takes a CSEConfigBase object that defines what opcodes get CSEd. 20909467b48Spatrick /// If CSEConfig is already set, and the CSE Analysis has been preserved, 21009467b48Spatrick /// it will not use the new CSEOpt(use Recompute to force using the new 21109467b48Spatrick /// CSEOpt). 21209467b48Spatrick GISelCSEInfo &get(std::unique_ptr<CSEConfigBase> CSEOpt, 21309467b48Spatrick bool ReCompute = false); setMF(MachineFunction & MFunc)21409467b48Spatrick void setMF(MachineFunction &MFunc) { MF = &MFunc; } setComputed(bool Computed)21509467b48Spatrick void setComputed(bool Computed) { AlreadyComputed = Computed; } releaseMemory()21609467b48Spatrick void releaseMemory() { Info.releaseMemory(); } 21709467b48Spatrick }; 21809467b48Spatrick 21909467b48Spatrick /// The actual analysis pass wrapper. 22009467b48Spatrick class GISelCSEAnalysisWrapperPass : public MachineFunctionPass { 22109467b48Spatrick GISelCSEAnalysisWrapper Wrapper; 22209467b48Spatrick 22309467b48Spatrick public: 22409467b48Spatrick static char ID; 22509467b48Spatrick GISelCSEAnalysisWrapperPass(); 22609467b48Spatrick 22709467b48Spatrick void getAnalysisUsage(AnalysisUsage &AU) const override; 22809467b48Spatrick getCSEWrapper()22909467b48Spatrick const GISelCSEAnalysisWrapper &getCSEWrapper() const { return Wrapper; } getCSEWrapper()23009467b48Spatrick GISelCSEAnalysisWrapper &getCSEWrapper() { return Wrapper; } 23109467b48Spatrick 23209467b48Spatrick bool runOnMachineFunction(MachineFunction &MF) override; 23309467b48Spatrick releaseMemory()23409467b48Spatrick void releaseMemory() override { 23509467b48Spatrick Wrapper.releaseMemory(); 23609467b48Spatrick Wrapper.setComputed(false); 23709467b48Spatrick } 23809467b48Spatrick }; 23909467b48Spatrick 24009467b48Spatrick } // namespace llvm 24109467b48Spatrick 24209467b48Spatrick #endif 243