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