Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:23

0001 //===- llvm/CodeGen/GlobalISel/CSEInfo.h ------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 /// Provides analysis for continuously CSEing during GISel passes.
0010 ///
0011 //===----------------------------------------------------------------------===//
0012 #ifndef LLVM_CODEGEN_GLOBALISEL_CSEINFO_H
0013 #define LLVM_CODEGEN_GLOBALISEL_CSEINFO_H
0014 
0015 #include "llvm/ADT/FoldingSet.h"
0016 #include "llvm/CodeGen/CSEConfigBase.h"
0017 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
0018 #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
0019 #include "llvm/CodeGen/MachineFunctionPass.h"
0020 #include "llvm/CodeGen/MachineRegisterInfo.h"
0021 #include "llvm/Support/Allocator.h"
0022 #include "llvm/Support/CodeGen.h"
0023 
0024 namespace llvm {
0025 class MachineBasicBlock;
0026 
0027 /// A class that wraps MachineInstrs and derives from FoldingSetNode in order to
0028 /// be uniqued in a CSEMap. The tradeoff here is extra memory allocations for
0029 /// UniqueMachineInstr vs making MachineInstr bigger.
0030 class UniqueMachineInstr : public FoldingSetNode {
0031   friend class GISelCSEInfo;
0032   const MachineInstr *MI;
0033   explicit UniqueMachineInstr(const MachineInstr *MI) : MI(MI) {}
0034 
0035 public:
0036   void Profile(FoldingSetNodeID &ID);
0037 };
0038 
0039 // A CSE config for fully optimized builds.
0040 class CSEConfigFull : public CSEConfigBase {
0041 public:
0042   virtual ~CSEConfigFull() = default;
0043   bool shouldCSEOpc(unsigned Opc) override;
0044 };
0045 
0046 // Commonly used for O0 config.
0047 class CSEConfigConstantOnly : public CSEConfigBase {
0048 public:
0049   virtual ~CSEConfigConstantOnly() = default;
0050   bool shouldCSEOpc(unsigned Opc) override;
0051 };
0052 
0053 // Returns the standard expected CSEConfig for the given optimization level.
0054 // We have this logic here so targets can make use of it from their derived
0055 // TargetPassConfig, but can't put this logic into TargetPassConfig directly
0056 // because the CodeGen library can't depend on GlobalISel.
0057 std::unique_ptr<CSEConfigBase>
0058 getStandardCSEConfigForOpt(CodeGenOptLevel Level);
0059 
0060 /// The CSE Analysis object.
0061 /// This installs itself as a delegate to the MachineFunction to track
0062 /// new instructions as well as deletions. It however will not be able to
0063 /// track instruction mutations. In such cases, recordNewInstruction should be
0064 /// called (for eg inside MachineIRBuilder::recordInsertion).
0065 /// Also because of how just the instruction can be inserted without adding any
0066 /// operands to the instruction, instructions are uniqued and inserted lazily.
0067 /// CSEInfo should assert when trying to enter an incomplete instruction into
0068 /// the CSEMap. There is Opcode level granularity on which instructions can be
0069 /// CSE'd and for now, only Generic instructions are CSEable.
0070 class GISelCSEInfo : public GISelChangeObserver {
0071   // Make it accessible only to CSEMIRBuilder.
0072   friend class CSEMIRBuilder;
0073 
0074   BumpPtrAllocator UniqueInstrAllocator;
0075   FoldingSet<UniqueMachineInstr> CSEMap;
0076   MachineRegisterInfo *MRI = nullptr;
0077   MachineFunction *MF = nullptr;
0078   std::unique_ptr<CSEConfigBase> CSEOpt;
0079   /// Keep a cache of UniqueInstrs for each MachineInstr. In GISel,
0080   /// often instructions are mutated (while their ID has completely changed).
0081   /// Whenever mutation happens, invalidate the UniqueMachineInstr for the
0082   /// MachineInstr
0083   DenseMap<const MachineInstr *, UniqueMachineInstr *> InstrMapping;
0084 
0085   /// Store instructions that are not fully formed in TemporaryInsts.
0086   /// Also because CSE insertion happens lazily, we can remove insts from this
0087   /// list and avoid inserting and then removing from the CSEMap.
0088   GISelWorkList<8> TemporaryInsts;
0089 
0090   // Only used in asserts.
0091   DenseMap<unsigned, unsigned> OpcodeHitTable;
0092 
0093   bool isUniqueMachineInstValid(const UniqueMachineInstr &UMI) const;
0094 
0095   void invalidateUniqueMachineInstr(UniqueMachineInstr *UMI);
0096 
0097   UniqueMachineInstr *getNodeIfExists(FoldingSetNodeID &ID,
0098                                       MachineBasicBlock *MBB, void *&InsertPos);
0099 
0100   /// Allocate and construct a new UniqueMachineInstr for MI and return.
0101   UniqueMachineInstr *getUniqueInstrForMI(const MachineInstr *MI);
0102 
0103   void insertNode(UniqueMachineInstr *UMI, void *InsertPos = nullptr);
0104 
0105   /// Get the MachineInstr(Unique) if it exists already in the CSEMap and the
0106   /// same MachineBasicBlock.
0107   MachineInstr *getMachineInstrIfExists(FoldingSetNodeID &ID,
0108                                         MachineBasicBlock *MBB,
0109                                         void *&InsertPos);
0110 
0111   /// Use this method to allocate a new UniqueMachineInstr for MI and insert it
0112   /// into the CSEMap. MI should return true for shouldCSE(MI->getOpcode())
0113   void insertInstr(MachineInstr *MI, void *InsertPos = nullptr);
0114 
0115   bool HandlingRecordedInstrs = false;
0116 
0117 public:
0118   GISelCSEInfo() = default;
0119 
0120   virtual ~GISelCSEInfo();
0121 
0122   void setMF(MachineFunction &MF);
0123 
0124   Error verify();
0125 
0126   /// Records a newly created inst in a list and lazily insert it to the CSEMap.
0127   /// Sometimes, this method might be called with a partially constructed
0128   /// MachineInstr,
0129   //  (right after BuildMI without adding any operands) - and in such cases,
0130   //  defer the hashing of the instruction to a later stage.
0131   void recordNewInstruction(MachineInstr *MI);
0132 
0133   /// Use this callback to inform CSE about a newly fully created instruction.
0134   void handleRecordedInst(MachineInstr *MI);
0135 
0136   /// Use this callback to insert all the recorded instructions. At this point,
0137   /// all of these insts need to be fully constructed and should not be missing
0138   /// any operands.
0139   void handleRecordedInsts();
0140 
0141   /// Remove this inst from the CSE map. If this inst has not been inserted yet,
0142   /// it will be removed from the Tempinsts list if it exists.
0143   void handleRemoveInst(MachineInstr *MI);
0144 
0145   void releaseMemory();
0146 
0147   void setCSEConfig(std::unique_ptr<CSEConfigBase> Opt) {
0148     CSEOpt = std::move(Opt);
0149   }
0150 
0151   bool shouldCSE(unsigned Opc) const;
0152 
0153   void analyze(MachineFunction &MF);
0154 
0155   void countOpcodeHit(unsigned Opc);
0156 
0157   void print();
0158 
0159   // Observer API
0160   void erasingInstr(MachineInstr &MI) override;
0161   void createdInstr(MachineInstr &MI) override;
0162   void changingInstr(MachineInstr &MI) override;
0163   void changedInstr(MachineInstr &MI) override;
0164 };
0165 
0166 class TargetRegisterClass;
0167 class RegisterBank;
0168 
0169 // Simple builder class to easily profile properties about MIs.
0170 class GISelInstProfileBuilder {
0171   FoldingSetNodeID &ID;
0172   const MachineRegisterInfo &MRI;
0173 
0174 public:
0175   GISelInstProfileBuilder(FoldingSetNodeID &ID, const MachineRegisterInfo &MRI)
0176       : ID(ID), MRI(MRI) {}
0177   // Profiling methods.
0178   const GISelInstProfileBuilder &addNodeIDOpcode(unsigned Opc) const;
0179   const GISelInstProfileBuilder &addNodeIDRegType(const LLT Ty) const;
0180   const GISelInstProfileBuilder &addNodeIDRegType(const Register) const;
0181   const GISelInstProfileBuilder &
0182       addNodeIDRegType(MachineRegisterInfo::VRegAttrs) const;
0183 
0184   const GISelInstProfileBuilder &
0185   addNodeIDRegType(const TargetRegisterClass *RC) const;
0186   const GISelInstProfileBuilder &addNodeIDRegType(const RegisterBank *RB) const;
0187 
0188   const GISelInstProfileBuilder &addNodeIDRegNum(Register Reg) const;
0189 
0190   const GISelInstProfileBuilder &addNodeIDReg(Register Reg) const;
0191 
0192   const GISelInstProfileBuilder &addNodeIDImmediate(int64_t Imm) const;
0193   const GISelInstProfileBuilder &
0194   addNodeIDMBB(const MachineBasicBlock *MBB) const;
0195 
0196   const GISelInstProfileBuilder &
0197   addNodeIDMachineOperand(const MachineOperand &MO) const;
0198 
0199   const GISelInstProfileBuilder &addNodeIDFlag(unsigned Flag) const;
0200   const GISelInstProfileBuilder &addNodeID(const MachineInstr *MI) const;
0201 };
0202 
0203 /// Simple wrapper that does the following.
0204 /// 1) Lazily evaluate the MachineFunction to compute CSEable instructions.
0205 /// 2) Allows configuration of which instructions are CSEd through CSEConfig
0206 /// object. Provides a method called get which takes a CSEConfig object.
0207 class GISelCSEAnalysisWrapper {
0208   GISelCSEInfo Info;
0209   MachineFunction *MF = nullptr;
0210   bool AlreadyComputed = false;
0211 
0212 public:
0213   /// Takes a CSEConfigBase object that defines what opcodes get CSEd.
0214   /// If CSEConfig is already set, and the CSE Analysis has been preserved,
0215   /// it will not use the new CSEOpt(use Recompute to force using the new
0216   /// CSEOpt).
0217   GISelCSEInfo &get(std::unique_ptr<CSEConfigBase> CSEOpt,
0218                     bool ReCompute = false);
0219   void setMF(MachineFunction &MFunc) { MF = &MFunc; }
0220   void setComputed(bool Computed) { AlreadyComputed = Computed; }
0221   void releaseMemory() { Info.releaseMemory(); }
0222 };
0223 
0224 /// The actual analysis pass wrapper.
0225 class GISelCSEAnalysisWrapperPass : public MachineFunctionPass {
0226   GISelCSEAnalysisWrapper Wrapper;
0227 
0228 public:
0229   static char ID;
0230   GISelCSEAnalysisWrapperPass();
0231 
0232   void getAnalysisUsage(AnalysisUsage &AU) const override;
0233 
0234   const GISelCSEAnalysisWrapper &getCSEWrapper() const { return Wrapper; }
0235   GISelCSEAnalysisWrapper &getCSEWrapper() { return Wrapper; }
0236 
0237   bool runOnMachineFunction(MachineFunction &MF) override;
0238 
0239   void releaseMemory() override {
0240     Wrapper.releaseMemory();
0241     Wrapper.setComputed(false);
0242   }
0243 };
0244 
0245 } // namespace llvm
0246 
0247 #endif