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
21namespace llvm {
22
23class TargetRegisterInfo;
24
25class 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.
31class MipsRegisterBankInfo final : public MipsGenRegisterBankInfo {
32public:
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
50private:
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 bool isInteger_64(InstType InstTy, unsigned OpSize) const {
117 return InstTy == InstType::Integer && OpSize == 64;
118 }
119
120 /// Some generic instructions have operands that can be mapped to either fprb
121 /// or gprb e.g. for G_LOAD we consider only operand 0 as ambiguous, operand 1
122 /// is always gprb since it is a pointer.
123 /// This class provides containers for MI's ambiguous:
124 /// DefUses : MachineInstrs that use one of MI's ambiguous def operands.
125 /// UseDefs : MachineInstrs that define MI's ambiguous use operands.
126 class AmbiguousRegDefUseContainer {
127 SmallVector<MachineInstr *, 2> DefUses;
128 SmallVector<MachineInstr *, 2> UseDefs;
129
130 void addDefUses(Register Reg, const MachineRegisterInfo &MRI);
131 void addUseDef(Register Reg, const MachineRegisterInfo &MRI);
132
133 /// Skip copy instructions until we get to a non-copy instruction or to a
134 /// copy with phys register as def. Used during search for DefUses.
135 /// MI : %5 = COPY %4
136 /// %6 = COPY %5
137 /// $v0 = COPY %6 <- we want this one.
138 MachineInstr *skipCopiesOutgoing(MachineInstr *MI) const;
139
140 /// Skip copy instructions until we get to a non-copy instruction or to a
141 /// copy with phys register as use. Used during search for UseDefs.
142 /// %1 = COPY $a1 <- we want this one.
143 /// %2 = COPY %1
144 /// MI = %3 = COPY %2
145 MachineInstr *skipCopiesIncoming(MachineInstr *MI) const;
146
147 public:
148 AmbiguousRegDefUseContainer(const MachineInstr *MI);
149 SmallVectorImpl<MachineInstr *> &getDefUses() { return DefUses; }
150 SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; }
151 };
152
153 class TypeInfoForMF {
154 /// MachineFunction name is used to recognise when MF changes.
155 std::string MFName;
156 /// <key, value> : value is vector of all MachineInstrs that are waiting for
157 /// key to figure out type of some of its ambiguous operands.
158 DenseMap<const MachineInstr *, SmallVector<const MachineInstr *, 2>>
159 WaitingQueues;
160 /// Recorded InstTypes for visited instructions.
161 DenseMap<const MachineInstr *, InstType> Types;
162
163 /// Recursively visit MI's adjacent instructions and find MI's InstType.
164 bool visit(const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI,
165 InstType &AmbiguousTy);
166
167 /// Visit MI's adjacent UseDefs or DefUses.
168 bool visitAdjacentInstrs(const MachineInstr *MI,
169 SmallVectorImpl<MachineInstr *> &AdjacentInstrs,
170 bool isDefUse, InstType &AmbiguousTy);
171
172 /// Set type for MI, and recursively for all instructions that are
173 /// waiting for MI's type.
174 void setTypes(const MachineInstr *MI, InstType ITy);
175
176 /// InstType for MI is determined, set it to InstType that corresponds to
177 /// physical regisiter that is operand number Op in CopyInst.
178 void setTypesAccordingToPhysicalRegister(const MachineInstr *MI,
179 const MachineInstr *CopyInst,
180 unsigned Op);
181
182 /// Set default values for MI in order to start visit.
183 void startVisit(const MachineInstr *MI) {
184 Types.try_emplace(Key: MI, Args: InstType::NotDetermined);
185 WaitingQueues.try_emplace(Key: MI);
186 }
187
188 /// Returns true if instruction was already visited. Type might not be
189 /// determined at this point but will be when visit(..., nullptr) finishes.
190 bool wasVisited(const MachineInstr *MI) const { return Types.count(Val: MI); };
191
192 /// Returns recorded type for instruction.
193 const InstType &getRecordedTypeForInstr(const MachineInstr *MI) const {
194 assert(wasVisited(MI) && "Instruction was not visited!");
195 return Types.find(Val: MI)->getSecond();
196 };
197
198 /// Change recorded type for instruction.
199 void changeRecordedTypeForInstr(const MachineInstr *MI, InstType InstTy) {
200 assert(wasVisited(MI) && "Instruction was not visited!");
201 Types.find(Val: MI)->getSecond() = InstTy;
202 };
203
204 /// Returns WaitingQueue for instruction.
205 const SmallVectorImpl<const MachineInstr *> &
206 getWaitingQueueFor(const MachineInstr *MI) const {
207 assert(WaitingQueues.count(MI) && "Instruction was not visited!");
208 return WaitingQueues.find(Val: MI)->getSecond();
209 };
210
211 /// Add WaitingForMI to MI's WaitingQueue.
212 void addToWaitingQueue(const MachineInstr *MI,
213 const MachineInstr *WaitingForMI) {
214 assert(WaitingQueues.count(MI) && "Instruction was not visited!");
215 WaitingQueues.find(Val: MI)->getSecond().push_back(Elt: WaitingForMI);
216 };
217
218 public:
219 InstType determineInstType(const MachineInstr *MI);
220
221 void cleanupIfNewFunction(llvm::StringRef FunctionName);
222
223 /// MI is about to get destroyed (using narrow scalar). Internal data is
224 /// saved based on MI's address, clear it since it is no longer valid.
225 void clearTypeInfoData(const MachineInstr *MI) {
226 Types.erase(Val: MI);
227 WaitingQueues.erase(Val: MI);
228 };
229 };
230};
231} // end namespace llvm
232#endif
233