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