xref: /llvm-project/llvm/lib/Target/Mips/MipsRegisterBankInfo.h (revision a79db96ec0decca4fe45579e039cf5589345b3ed)
1 //===- MipsRegisterBankInfo.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 /// This file declares the targeting of the RegisterBankInfo class for Mips.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H
14 #define LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H
15 
16 #include "llvm/CodeGen/RegisterBankInfo.h"
17 
18 #define GET_REGBANK_DECLARATIONS
19 #include "MipsGenRegisterBank.inc"
20 
21 namespace llvm {
22 
23 class TargetRegisterInfo;
24 
25 class MipsGenRegisterBankInfo : public RegisterBankInfo {
26 #define GET_TARGET_REGBANK_CLASS
27 #include "MipsGenRegisterBank.inc"
28 };
29 
30 /// This class provides the information for the target register banks.
31 class MipsRegisterBankInfo final : public MipsGenRegisterBankInfo {
32 public:
33   MipsRegisterBankInfo(const TargetRegisterInfo &TRI);
34 
35   const InstructionMapping &
36   getInstrMapping(const MachineInstr &MI) const override;
37 
38   /// Here we have to narrowScalar s64 operands to s32, combine away G_MERGE or
39   /// G_UNMERGE and erase instructions that became dead in the process. We
40   /// manually assign bank to def operand of all new instructions that were
41   /// created in the process since they will not end up in RegBankSelect loop.
42   void applyMappingImpl(MachineIRBuilder &Builder,
43                         const OperandsMapper &OpdMapper) const override;
44 
45   /// RegBankSelect determined that s64 operand is better to be split into two
46   /// s32 operands in gprb. Here we manually set register banks of def operands
47   /// of newly created instructions since they will not get regbankselected.
48   void setRegBank(MachineInstr &MI, MachineRegisterInfo &MRI) const;
49 
50 private:
51   /// Some instructions are used with both floating point and integer operands.
52   /// We assign InstType to such instructions as it helps us to avoid cross bank
53   /// copies. InstType deppends on context.
54   enum InstType {
55     /// Temporary type, when visit(..., nullptr) finishes will convert to one of
56     /// the remaining types: Integer, FloatingPoint or Ambiguous.
57     NotDetermined,
58     /// Connected with instruction that interprets 'bags of bits' as integers.
59     /// Select gprb to avoid cross bank copies.
60     Integer,
61     /// Connected with instruction that interprets 'bags of bits' as floating
62     /// point numbers. Select fprb to avoid cross bank copies.
63     FloatingPoint,
64     /// Represents moving 'bags of bits' around. Select same bank for entire
65     /// chain to avoid cross bank copies. Currently we select fprb for s64 and
66     /// gprb for s32 Ambiguous operands.
67     Ambiguous,
68     /// Only used for s64. Unlike Ambiguous s64, AmbiguousWithMergeOrUnmerge s64
69     /// is mapped to gprb (legalized using narrow scalar to s32).
70     AmbiguousWithMergeOrUnmerge
71   };
72 
73   bool isAmbiguous_64(InstType InstTy, unsigned OpSize) const {
74     if (InstTy == InstType::Ambiguous && OpSize == 64)
75       return true;
76     return false;
77   }
78 
79   bool isAmbiguous_32(InstType InstTy, unsigned OpSize) const {
80     if (InstTy == InstType::Ambiguous && OpSize == 32)
81       return true;
82     return false;
83   }
84 
85   bool isAmbiguous_32or64(InstType InstTy, unsigned OpSize) const {
86     if (InstTy == InstType::Ambiguous && (OpSize == 32 || OpSize == 64))
87       return true;
88     return false;
89   }
90 
91   bool isAmbiguousWithMergeOrUnmerge_64(InstType InstTy,
92                                         unsigned OpSize) const {
93     if (InstTy == InstType::AmbiguousWithMergeOrUnmerge && OpSize == 64)
94       return true;
95     return false;
96   }
97 
98   bool isFloatingPoint_32or64(InstType InstTy, unsigned OpSize) const {
99     if (InstTy == InstType::FloatingPoint && (OpSize == 32 || OpSize == 64))
100       return true;
101     return false;
102   }
103 
104   bool isFloatingPoint_64(InstType InstTy, unsigned OpSize) const {
105     if (InstTy == InstType::FloatingPoint && OpSize == 64)
106       return true;
107     return false;
108   }
109 
110   bool isInteger_32(InstType InstTy, unsigned OpSize) const {
111     if (InstTy == InstType::Integer && OpSize == 32)
112       return true;
113     return false;
114   }
115 
116   /// Some generic instructions have operands that can be mapped to either fprb
117   /// or gprb e.g. for G_LOAD we consider only operand 0 as ambiguous, operand 1
118   /// is always gprb since it is a pointer.
119   /// This class provides containers for MI's ambiguous:
120   /// DefUses : MachineInstrs that use one of MI's ambiguous def operands.
121   /// UseDefs : MachineInstrs that define MI's ambiguous use operands.
122   class AmbiguousRegDefUseContainer {
123     SmallVector<MachineInstr *, 2> DefUses;
124     SmallVector<MachineInstr *, 2> UseDefs;
125 
126     void addDefUses(Register Reg, const MachineRegisterInfo &MRI);
127     void addUseDef(Register Reg, const MachineRegisterInfo &MRI);
128 
129     /// Skip copy instructions until we get to a non-copy instruction or to a
130     /// copy with phys register as def. Used during search for DefUses.
131     /// MI :  %5 = COPY %4
132     ///       %6 = COPY %5
133     ///       $v0 = COPY %6 <- we want this one.
134     MachineInstr *skipCopiesOutgoing(MachineInstr *MI) const;
135 
136     /// Skip copy instructions until we get to a non-copy instruction or to a
137     /// copy with phys register as use. Used during search for UseDefs.
138     ///       %1 = COPY $a1 <- we want this one.
139     ///       %2 = COPY %1
140     /// MI =  %3 = COPY %2
141     MachineInstr *skipCopiesIncoming(MachineInstr *MI) const;
142 
143   public:
144     AmbiguousRegDefUseContainer(const MachineInstr *MI);
145     SmallVectorImpl<MachineInstr *> &getDefUses() { return DefUses; }
146     SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; }
147   };
148 
149   class TypeInfoForMF {
150     /// MachineFunction name is used to recognise when MF changes.
151     std::string MFName;
152     /// <key, value> : value is vector of all MachineInstrs that are waiting for
153     /// key to figure out type of some of its ambiguous operands.
154     DenseMap<const MachineInstr *, SmallVector<const MachineInstr *, 2>>
155         WaitingQueues;
156     /// Recorded InstTypes for visited instructions.
157     DenseMap<const MachineInstr *, InstType> Types;
158 
159     /// Recursively visit MI's adjacent instructions and find MI's InstType.
160     bool visit(const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI,
161                InstType &AmbiguousTy);
162 
163     /// Visit MI's adjacent UseDefs or DefUses.
164     bool visitAdjacentInstrs(const MachineInstr *MI,
165                              SmallVectorImpl<MachineInstr *> &AdjacentInstrs,
166                              bool isDefUse, InstType &AmbiguousTy);
167 
168     /// Set type for MI, and recursively for all instructions that are
169     /// waiting for MI's type.
170     void setTypes(const MachineInstr *MI, InstType ITy);
171 
172     /// InstType for MI is determined, set it to InstType that corresponds to
173     /// physical regisiter that is operand number Op in CopyInst.
174     void setTypesAccordingToPhysicalRegister(const MachineInstr *MI,
175                                              const MachineInstr *CopyInst,
176                                              unsigned Op);
177 
178     /// Set default values for MI in order to start visit.
179     void startVisit(const MachineInstr *MI) {
180       Types.try_emplace(MI, InstType::NotDetermined);
181       WaitingQueues.try_emplace(MI);
182     }
183 
184     /// Returns true if instruction was already visited. Type might not be
185     /// determined at this point but will be when visit(..., nullptr) finishes.
186     bool wasVisited(const MachineInstr *MI) const { return Types.count(MI); };
187 
188     /// Returns recorded type for instruction.
189     const InstType &getRecordedTypeForInstr(const MachineInstr *MI) const {
190       assert(wasVisited(MI) && "Instruction was not visited!");
191       return Types.find(MI)->getSecond();
192     };
193 
194     /// Change recorded type for instruction.
195     void changeRecordedTypeForInstr(const MachineInstr *MI, InstType InstTy) {
196       assert(wasVisited(MI) && "Instruction was not visited!");
197       Types.find(MI)->getSecond() = InstTy;
198     };
199 
200     /// Returns WaitingQueue for instruction.
201     const SmallVectorImpl<const MachineInstr *> &
202     getWaitingQueueFor(const MachineInstr *MI) const {
203       assert(WaitingQueues.count(MI) && "Instruction was not visited!");
204       return WaitingQueues.find(MI)->getSecond();
205     };
206 
207     /// Add WaitingForMI to MI's WaitingQueue.
208     void addToWaitingQueue(const MachineInstr *MI,
209                            const MachineInstr *WaitingForMI) {
210       assert(WaitingQueues.count(MI) && "Instruction was not visited!");
211       WaitingQueues.find(MI)->getSecond().push_back(WaitingForMI);
212     };
213 
214   public:
215     InstType determineInstType(const MachineInstr *MI);
216 
217     void cleanupIfNewFunction(llvm::StringRef FunctionName);
218 
219     /// MI is about to get destroyed (using narrow scalar). Internal data is
220     /// saved based on MI's address, clear it since it is no longer valid.
221     void clearTypeInfoData(const MachineInstr *MI) {
222       Types.erase(MI);
223       WaitingQueues.erase(MI);
224     };
225   };
226 };
227 } // end namespace llvm
228 #endif
229