xref: /openbsd-src/gnu/llvm/llvm/include/llvm/CodeGen/GlobalISel/CSEInfo.h (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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