/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- AArch64RegisterBankInfo.cpp ----------------------------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// \file |
10 | | /// This file implements the targeting of the RegisterBankInfo class for |
11 | | /// AArch64. |
12 | | /// \todo This should be generated by TableGen. |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "AArch64RegisterBankInfo.h" |
16 | | #include "AArch64InstrInfo.h" |
17 | | #include "llvm/ADT/SmallVector.h" |
18 | | #include "llvm/CodeGen/GlobalISel/RegisterBank.h" |
19 | | #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" |
20 | | #include "llvm/CodeGen/LowLevelType.h" |
21 | | #include "llvm/CodeGen/MachineFunction.h" |
22 | | #include "llvm/CodeGen/MachineInstr.h" |
23 | | #include "llvm/CodeGen/MachineOperand.h" |
24 | | #include "llvm/CodeGen/MachineRegisterInfo.h" |
25 | | #include "llvm/Support/ErrorHandling.h" |
26 | | #include "llvm/Target/TargetOpcodes.h" |
27 | | #include "llvm/Target/TargetRegisterInfo.h" |
28 | | #include "llvm/Target/TargetSubtargetInfo.h" |
29 | | #include <algorithm> |
30 | | #include <cassert> |
31 | | |
32 | | #define GET_TARGET_REGBANK_IMPL |
33 | | #include "AArch64GenRegisterBank.inc" |
34 | | |
35 | | // This file will be TableGen'ed at some point. |
36 | | #include "AArch64GenRegisterBankInfo.def" |
37 | | |
38 | | using namespace llvm; |
39 | | |
40 | | AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI) |
41 | 13.9k | : AArch64GenRegisterBankInfo() { |
42 | 13.9k | static bool AlreadyInit = false; |
43 | 13.9k | // We have only one set of register banks, whatever the subtarget |
44 | 13.9k | // is. Therefore, the initialization of the RegBanks table should be |
45 | 13.9k | // done only once. Indeed the table of all register banks |
46 | 13.9k | // (AArch64::RegBanks) is unique in the compiler. At some point, it |
47 | 13.9k | // will get tablegen'ed and the whole constructor becomes empty. |
48 | 13.9k | if (AlreadyInit) |
49 | 10 | return; |
50 | 13.9k | AlreadyInit = true; |
51 | 13.9k | |
52 | 13.9k | const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID); |
53 | 13.9k | (void)RBGPR; |
54 | 13.9k | assert(&AArch64::GPRRegBank == &RBGPR && |
55 | 13.9k | "The order in RegBanks is messed up"); |
56 | 13.9k | |
57 | 13.9k | const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); |
58 | 13.9k | (void)RBFPR; |
59 | 13.9k | assert(&AArch64::FPRRegBank == &RBFPR && |
60 | 13.9k | "The order in RegBanks is messed up"); |
61 | 13.9k | |
62 | 13.9k | const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID); |
63 | 13.9k | (void)RBCCR; |
64 | 13.9k | assert(&AArch64::CCRRegBank == &RBCCR && |
65 | 13.9k | "The order in RegBanks is messed up"); |
66 | 13.9k | |
67 | 13.9k | // The GPR register bank is fully defined by all the registers in |
68 | 13.9k | // GR64all + its subclasses. |
69 | 13.9k | assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) && |
70 | 13.9k | "Subclass not added?"); |
71 | 13.9k | assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit"); |
72 | 13.9k | |
73 | 13.9k | // The FPR register bank is fully defined by all the registers in |
74 | 13.9k | // GR64all + its subclasses. |
75 | 13.9k | assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) && |
76 | 13.9k | "Subclass not added?"); |
77 | 13.9k | assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) && |
78 | 13.9k | "Subclass not added?"); |
79 | 13.9k | assert(RBFPR.getSize() == 512 && |
80 | 13.9k | "FPRs should hold up to 512-bit via QQQQ sequence"); |
81 | 13.9k | |
82 | 13.9k | assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) && |
83 | 13.9k | "Class not added?"); |
84 | 13.9k | assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit"); |
85 | 13.9k | |
86 | 13.9k | // Check that the TableGen'ed like file is in sync we our expectations. |
87 | 13.9k | // First, the Idx. |
88 | 13.9k | assert(checkPartialMappingIdx(PMI_FirstGPR, PMI_LastGPR, |
89 | 13.9k | {PMI_GPR32, PMI_GPR64}) && |
90 | 13.9k | "PartialMappingIdx's are incorrectly ordered"); |
91 | 13.9k | assert(checkPartialMappingIdx( |
92 | 13.9k | PMI_FirstFPR, PMI_LastFPR, |
93 | 13.9k | {PMI_FPR32, PMI_FPR64, PMI_FPR128, PMI_FPR256, PMI_FPR512}) && |
94 | 13.9k | "PartialMappingIdx's are incorrectly ordered"); |
95 | 13.9k | // Now, the content. |
96 | 13.9k | // Check partial mapping. |
97 | 13.9k | #define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \ |
98 | 97.6k | do 97.6k { \ |
99 | 97.6k | assert( \ |
100 | 97.6k | checkPartialMap(PartialMappingIdx::Idx, ValStartIdx, ValLength, RB) && \ |
101 | 97.6k | #Idx " is incorrectly initialized"); \ |
102 | 97.6k | } while (false) |
103 | 13.9k | |
104 | 13.9k | CHECK_PARTIALMAP(PMI_GPR32, 0, 32, RBGPR); |
105 | 13.9k | CHECK_PARTIALMAP(PMI_GPR64, 0, 64, RBGPR); |
106 | 13.9k | CHECK_PARTIALMAP(PMI_FPR32, 0, 32, RBFPR); |
107 | 13.9k | CHECK_PARTIALMAP(PMI_FPR64, 0, 64, RBFPR); |
108 | 13.9k | CHECK_PARTIALMAP(PMI_FPR128, 0, 128, RBFPR); |
109 | 13.9k | CHECK_PARTIALMAP(PMI_FPR256, 0, 256, RBFPR); |
110 | 13.9k | CHECK_PARTIALMAP(PMI_FPR512, 0, 512, RBFPR); |
111 | 13.9k | |
112 | 13.9k | // Check value mapping. |
113 | 13.9k | #define CHECK_VALUEMAP_IMPL(RBName, Size, Offset) \ |
114 | 390k | do 390k { \ |
115 | 390k | assert(checkValueMapImpl(PartialMappingIdx::PMI_##RBName##Size, \ |
116 | 390k | PartialMappingIdx::PMI_First##RBName, Size, \ |
117 | 390k | Offset) && \ |
118 | 390k | #RBName #Size " " #Offset " is incorrectly initialized"); \ |
119 | 390k | } while (false) |
120 | 13.9k | |
121 | 97.6k | #define CHECK_VALUEMAP(RBName, Size) CHECK_VALUEMAP_IMPL(RBName, Size, 0) |
122 | 13.9k | |
123 | 13.9k | CHECK_VALUEMAP(GPR, 32); |
124 | 13.9k | CHECK_VALUEMAP(GPR, 64); |
125 | 13.9k | CHECK_VALUEMAP(FPR, 32); |
126 | 13.9k | CHECK_VALUEMAP(FPR, 64); |
127 | 13.9k | CHECK_VALUEMAP(FPR, 128); |
128 | 13.9k | CHECK_VALUEMAP(FPR, 256); |
129 | 13.9k | CHECK_VALUEMAP(FPR, 512); |
130 | 13.9k | |
131 | 13.9k | // Check the value mapping for 3-operands instructions where all the operands |
132 | 13.9k | // map to the same value mapping. |
133 | 13.9k | #define CHECK_VALUEMAP_3OPS(RBName, Size) \ |
134 | 97.6k | do 97.6k { \ |
135 | 97.6k | CHECK_VALUEMAP_IMPL(RBName, Size, 0); \ |
136 | 97.6k | CHECK_VALUEMAP_IMPL(RBName, Size, 1); \ |
137 | 97.6k | CHECK_VALUEMAP_IMPL(RBName, Size, 2); \ |
138 | 97.6k | } while (false) |
139 | 13.9k | |
140 | 13.9k | CHECK_VALUEMAP_3OPS(GPR, 32); |
141 | 13.9k | CHECK_VALUEMAP_3OPS(GPR, 64); |
142 | 13.9k | CHECK_VALUEMAP_3OPS(FPR, 32); |
143 | 13.9k | CHECK_VALUEMAP_3OPS(FPR, 64); |
144 | 13.9k | CHECK_VALUEMAP_3OPS(FPR, 128); |
145 | 13.9k | CHECK_VALUEMAP_3OPS(FPR, 256); |
146 | 13.9k | CHECK_VALUEMAP_3OPS(FPR, 512); |
147 | 13.9k | |
148 | 13.9k | #define CHECK_VALUEMAP_CROSSREGCPY(RBNameDst, RBNameSrc, Size) \ |
149 | 111k | do 111k { \ |
150 | 111k | unsigned PartialMapDstIdx = PMI_##RBNameDst##Size - PMI_Min; \ |
151 | 111k | unsigned PartialMapSrcIdx = PMI_##RBNameSrc##Size - PMI_Min; \ |
152 | 111k | (void)PartialMapDstIdx; \ |
153 | 111k | (void)PartialMapSrcIdx; \ |
154 | 111k | const ValueMapping *Map = getCopyMapping( \ |
155 | 111k | AArch64::RBNameDst##RegBankID, AArch64::RBNameSrc##RegBankID, Size); \ |
156 | 111k | (void)Map; \ |
157 | 111k | assert(Map[0].BreakDown == \ |
158 | 111k | &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \ |
159 | 111k | Map[0].NumBreakDowns == 1 && #RBNameDst #Size \ |
160 | 111k | " Dst is incorrectly initialized"); \ |
161 | 111k | assert(Map[1].BreakDown == \ |
162 | 111k | &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \ |
163 | 111k | Map[1].NumBreakDowns == 1 && #RBNameSrc #Size \ |
164 | 111k | " Src is incorrectly initialized"); \ |
165 | 111k | \ |
166 | 111k | } while (false) |
167 | 13.9k | |
168 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 32); |
169 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 32); |
170 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 64); |
171 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 64); |
172 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 32); |
173 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 32); |
174 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64); |
175 | 13.9k | CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64); |
176 | 13.9k | |
177 | 13.9k | assert(verify(TRI) && "Invalid register bank information"); |
178 | 13.9k | } |
179 | | |
180 | | unsigned AArch64RegisterBankInfo::copyCost(const RegisterBank &A, |
181 | | const RegisterBank &B, |
182 | 348 | unsigned Size) const { |
183 | 348 | // What do we do with different size? |
184 | 348 | // copy are same size. |
185 | 348 | // Will introduce other hooks for different size: |
186 | 348 | // * extract cost. |
187 | 348 | // * build_sequence cost. |
188 | 348 | |
189 | 348 | // Copy from (resp. to) GPR to (resp. from) FPR involves FMOV. |
190 | 348 | // FIXME: This should be deduced from the scheduling model. |
191 | 348 | if (&A == &AArch64::GPRRegBank && 348 &B == &AArch64::FPRRegBank318 ) |
192 | 348 | // FMOVXDr or FMOVWSr. |
193 | 314 | return 5; |
194 | 34 | if (34 &A == &AArch64::FPRRegBank && 34 &B == &AArch64::GPRRegBank30 ) |
195 | 34 | // FMOVDXr or FMOVSWr. |
196 | 26 | return 4; |
197 | 8 | |
198 | 8 | return RegisterBankInfo::copyCost(A, B, Size); |
199 | 8 | } |
200 | | |
201 | | const RegisterBank &AArch64RegisterBankInfo::getRegBankFromRegClass( |
202 | 6.99M | const TargetRegisterClass &RC) const { |
203 | 6.99M | switch (RC.getID()) { |
204 | 145k | case AArch64::FPR8RegClassID: |
205 | 145k | case AArch64::FPR16RegClassID: |
206 | 145k | case AArch64::FPR32RegClassID: |
207 | 145k | case AArch64::FPR64RegClassID: |
208 | 145k | case AArch64::FPR128RegClassID: |
209 | 145k | case AArch64::FPR128_loRegClassID: |
210 | 145k | case AArch64::DDRegClassID: |
211 | 145k | case AArch64::DDDRegClassID: |
212 | 145k | case AArch64::DDDDRegClassID: |
213 | 145k | case AArch64::QQRegClassID: |
214 | 145k | case AArch64::QQQRegClassID: |
215 | 145k | case AArch64::QQQQRegClassID: |
216 | 145k | return getRegBank(AArch64::FPRRegBankID); |
217 | 6.85M | case AArch64::GPR32commonRegClassID: |
218 | 6.85M | case AArch64::GPR32RegClassID: |
219 | 6.85M | case AArch64::GPR32spRegClassID: |
220 | 6.85M | case AArch64::GPR32sponlyRegClassID: |
221 | 6.85M | case AArch64::GPR32allRegClassID: |
222 | 6.85M | case AArch64::GPR64commonRegClassID: |
223 | 6.85M | case AArch64::GPR64RegClassID: |
224 | 6.85M | case AArch64::GPR64spRegClassID: |
225 | 6.85M | case AArch64::GPR64sponlyRegClassID: |
226 | 6.85M | case AArch64::GPR64allRegClassID: |
227 | 6.85M | case AArch64::tcGPR64RegClassID: |
228 | 6.85M | case AArch64::WSeqPairsClassRegClassID: |
229 | 6.85M | case AArch64::XSeqPairsClassRegClassID: |
230 | 6.85M | return getRegBank(AArch64::GPRRegBankID); |
231 | 0 | case AArch64::CCRRegClassID: |
232 | 0 | return getRegBank(AArch64::CCRRegBankID); |
233 | 0 | default: |
234 | 0 | llvm_unreachable("Register class not supported"); |
235 | 0 | } |
236 | 0 | } |
237 | | |
238 | | RegisterBankInfo::InstructionMappings |
239 | | AArch64RegisterBankInfo::getInstrAlternativeMappings( |
240 | 63 | const MachineInstr &MI) const { |
241 | 63 | const MachineFunction &MF = *MI.getParent()->getParent(); |
242 | 63 | const TargetSubtargetInfo &STI = MF.getSubtarget(); |
243 | 63 | const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); |
244 | 63 | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
245 | 63 | |
246 | 63 | switch (MI.getOpcode()) { |
247 | 3 | case TargetOpcode::G_OR: { |
248 | 3 | // 32 and 64-bit or can be mapped on either FPR or |
249 | 3 | // GPR for the same cost. |
250 | 3 | unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); |
251 | 3 | if (Size != 32 && 3 Size != 643 ) |
252 | 0 | break; |
253 | 3 | |
254 | 3 | // If the instruction has any implicit-defs or uses, |
255 | 3 | // do not mess with it. |
256 | 3 | if (3 MI.getNumOperands() != 33 ) |
257 | 0 | break; |
258 | 3 | InstructionMappings AltMappings; |
259 | 3 | const InstructionMapping &GPRMapping = getInstructionMapping( |
260 | 3 | /*ID*/ 1, /*Cost*/ 1, getValueMapping(PMI_FirstGPR, Size), |
261 | 3 | /*NumOperands*/ 3); |
262 | 3 | const InstructionMapping &FPRMapping = getInstructionMapping( |
263 | 3 | /*ID*/ 2, /*Cost*/ 1, getValueMapping(PMI_FirstFPR, Size), |
264 | 3 | /*NumOperands*/ 3); |
265 | 3 | |
266 | 3 | AltMappings.push_back(&GPRMapping); |
267 | 3 | AltMappings.push_back(&FPRMapping); |
268 | 3 | return AltMappings; |
269 | 3 | } |
270 | 10 | case TargetOpcode::G_BITCAST: { |
271 | 10 | unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); |
272 | 10 | if (Size != 32 && 10 Size != 646 ) |
273 | 0 | break; |
274 | 10 | |
275 | 10 | // If the instruction has any implicit-defs or uses, |
276 | 10 | // do not mess with it. |
277 | 10 | if (10 MI.getNumOperands() != 210 ) |
278 | 0 | break; |
279 | 10 | |
280 | 10 | InstructionMappings AltMappings; |
281 | 10 | const InstructionMapping &GPRMapping = getInstructionMapping( |
282 | 10 | /*ID*/ 1, /*Cost*/ 1, |
283 | 10 | getCopyMapping(AArch64::GPRRegBankID, AArch64::GPRRegBankID, Size), |
284 | 10 | /*NumOperands*/ 2); |
285 | 10 | const InstructionMapping &FPRMapping = getInstructionMapping( |
286 | 10 | /*ID*/ 2, /*Cost*/ 1, |
287 | 10 | getCopyMapping(AArch64::FPRRegBankID, AArch64::FPRRegBankID, Size), |
288 | 10 | /*NumOperands*/ 2); |
289 | 10 | const InstructionMapping &GPRToFPRMapping = getInstructionMapping( |
290 | 10 | /*ID*/ 3, |
291 | 10 | /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size), |
292 | 10 | getCopyMapping(AArch64::FPRRegBankID, AArch64::GPRRegBankID, Size), |
293 | 10 | /*NumOperands*/ 2); |
294 | 10 | const InstructionMapping &FPRToGPRMapping = getInstructionMapping( |
295 | 10 | /*ID*/ 3, |
296 | 10 | /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size), |
297 | 10 | getCopyMapping(AArch64::GPRRegBankID, AArch64::FPRRegBankID, Size), |
298 | 10 | /*NumOperands*/ 2); |
299 | 10 | |
300 | 10 | AltMappings.push_back(&GPRMapping); |
301 | 10 | AltMappings.push_back(&FPRMapping); |
302 | 10 | AltMappings.push_back(&GPRToFPRMapping); |
303 | 10 | AltMappings.push_back(&FPRToGPRMapping); |
304 | 10 | return AltMappings; |
305 | 10 | } |
306 | 2 | case TargetOpcode::G_LOAD: { |
307 | 2 | unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); |
308 | 2 | if (Size != 64) |
309 | 0 | break; |
310 | 2 | |
311 | 2 | // If the instruction has any implicit-defs or uses, |
312 | 2 | // do not mess with it. |
313 | 2 | if (2 MI.getNumOperands() != 22 ) |
314 | 0 | break; |
315 | 2 | |
316 | 2 | InstructionMappings AltMappings; |
317 | 2 | const InstructionMapping &GPRMapping = getInstructionMapping( |
318 | 2 | /*ID*/ 1, /*Cost*/ 1, |
319 | 2 | getOperandsMapping({getValueMapping(PMI_FirstGPR, Size), |
320 | 2 | // Addresses are GPR 64-bit. |
321 | 2 | getValueMapping(PMI_FirstGPR, 64)}), |
322 | 2 | /*NumOperands*/ 2); |
323 | 2 | const InstructionMapping &FPRMapping = getInstructionMapping( |
324 | 2 | /*ID*/ 2, /*Cost*/ 1, |
325 | 2 | getOperandsMapping({getValueMapping(PMI_FirstFPR, Size), |
326 | 2 | // Addresses are GPR 64-bit. |
327 | 2 | getValueMapping(PMI_FirstGPR, 64)}), |
328 | 2 | /*NumOperands*/ 2); |
329 | 2 | |
330 | 2 | AltMappings.push_back(&GPRMapping); |
331 | 2 | AltMappings.push_back(&FPRMapping); |
332 | 2 | return AltMappings; |
333 | 2 | } |
334 | 48 | default: |
335 | 48 | break; |
336 | 48 | } |
337 | 48 | return RegisterBankInfo::getInstrAlternativeMappings(MI); |
338 | 48 | } |
339 | | |
340 | | void AArch64RegisterBankInfo::applyMappingImpl( |
341 | 10 | const OperandsMapper &OpdMapper) const { |
342 | 10 | switch (OpdMapper.getMI().getOpcode()) { |
343 | 10 | case TargetOpcode::G_OR: |
344 | 10 | case TargetOpcode::G_BITCAST: |
345 | 10 | case TargetOpcode::G_LOAD: |
346 | 10 | // Those ID must match getInstrAlternativeMappings. |
347 | 10 | assert((OpdMapper.getInstrMapping().getID() >= 1 && |
348 | 10 | OpdMapper.getInstrMapping().getID() <= 4) && |
349 | 10 | "Don't know how to handle that ID"); |
350 | 10 | return applyDefaultMapping(OpdMapper); |
351 | 0 | default: |
352 | 0 | llvm_unreachable("Don't know how to handle that operation"); |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | | /// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode, |
357 | | /// having only floating-point operands. |
358 | 7.07M | static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) { |
359 | 7.07M | switch (Opc) { |
360 | 22.0k | case TargetOpcode::G_FADD: |
361 | 22.0k | case TargetOpcode::G_FSUB: |
362 | 22.0k | case TargetOpcode::G_FMUL: |
363 | 22.0k | case TargetOpcode::G_FDIV: |
364 | 22.0k | case TargetOpcode::G_FCONSTANT: |
365 | 22.0k | case TargetOpcode::G_FPEXT: |
366 | 22.0k | case TargetOpcode::G_FPTRUNC: |
367 | 22.0k | return true; |
368 | 7.05M | } |
369 | 7.05M | return false; |
370 | 7.05M | } |
371 | | |
372 | | const RegisterBankInfo::InstructionMapping & |
373 | | AArch64RegisterBankInfo::getSameKindOfOperandsMapping( |
374 | 826k | const MachineInstr &MI) const { |
375 | 826k | const unsigned Opc = MI.getOpcode(); |
376 | 826k | const MachineFunction &MF = *MI.getParent()->getParent(); |
377 | 826k | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
378 | 826k | |
379 | 826k | unsigned NumOperands = MI.getNumOperands(); |
380 | 826k | assert(NumOperands <= 3 && |
381 | 826k | "This code is for instructions with 3 or less operands"); |
382 | 826k | |
383 | 826k | LLT Ty = MRI.getType(MI.getOperand(0).getReg()); |
384 | 826k | unsigned Size = Ty.getSizeInBits(); |
385 | 826k | bool IsFPR = Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc); |
386 | 826k | |
387 | 826k | PartialMappingIdx RBIdx = IsFPR ? PMI_FirstFPR9.80k : PMI_FirstGPR816k ; |
388 | 826k | |
389 | | #ifndef NDEBUG |
390 | | // Make sure all the operands are using similar size and type. |
391 | | // Should probably be checked by the machine verifier. |
392 | | // This code won't catch cases where the number of lanes is |
393 | | // different between the operands. |
394 | | // If we want to go to that level of details, it is probably |
395 | | // best to check that the types are the same, period. |
396 | | // Currently, we just check that the register banks are the same |
397 | | // for each types. |
398 | | for (unsigned Idx = 1; Idx != NumOperands; ++Idx) { |
399 | | LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg()); |
400 | | assert( |
401 | | AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset( |
402 | | RBIdx, OpTy.getSizeInBits()) == |
403 | | AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset(RBIdx, Size) && |
404 | | "Operand has incompatible size"); |
405 | | bool OpIsFPR = OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc); |
406 | | (void)OpIsFPR; |
407 | | assert(IsFPR == OpIsFPR && "Operand has incompatible type"); |
408 | | } |
409 | | #endif // End NDEBUG. |
410 | | |
411 | 826k | return getInstructionMapping(DefaultMappingID, 1, |
412 | 826k | getValueMapping(RBIdx, Size), NumOperands); |
413 | 826k | } |
414 | | |
415 | | const RegisterBankInfo::InstructionMapping & |
416 | 7.21M | AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { |
417 | 7.21M | const unsigned Opc = MI.getOpcode(); |
418 | 7.21M | const MachineFunction &MF = *MI.getParent()->getParent(); |
419 | 7.21M | const MachineRegisterInfo &MRI = MF.getRegInfo(); |
420 | 7.21M | |
421 | 7.21M | // Try the default logic for non-generic instructions that are either copies |
422 | 7.21M | // or already have some operands assigned to banks. |
423 | 7.21M | if (!isPreISelGenericOpcode(Opc) || |
424 | 7.21M | Opc == TargetOpcode::G_PHI4.39M ) { |
425 | 2.91M | const RegisterBankInfo::InstructionMapping &Mapping = |
426 | 2.91M | getInstrMappingImpl(MI); |
427 | 2.91M | if (Mapping.isValid()) |
428 | 2.91M | return Mapping; |
429 | 4.30M | } |
430 | 4.30M | |
431 | 4.30M | switch (Opc) { |
432 | 4.30M | // G_{F|S|U}REM are not listed because they are not legal. |
433 | 4.30M | // Arithmetic ops. |
434 | 826k | case TargetOpcode::G_ADD: |
435 | 826k | case TargetOpcode::G_SUB: |
436 | 826k | case TargetOpcode::G_GEP: |
437 | 826k | case TargetOpcode::G_MUL: |
438 | 826k | case TargetOpcode::G_SDIV: |
439 | 826k | case TargetOpcode::G_UDIV: |
440 | 826k | // Bitwise ops. |
441 | 826k | case TargetOpcode::G_AND: |
442 | 826k | case TargetOpcode::G_OR: |
443 | 826k | case TargetOpcode::G_XOR: |
444 | 826k | // Shifts. |
445 | 826k | case TargetOpcode::G_SHL: |
446 | 826k | case TargetOpcode::G_LSHR: |
447 | 826k | case TargetOpcode::G_ASHR: |
448 | 826k | // Floating point ops. |
449 | 826k | case TargetOpcode::G_FADD: |
450 | 826k | case TargetOpcode::G_FSUB: |
451 | 826k | case TargetOpcode::G_FMUL: |
452 | 826k | case TargetOpcode::G_FDIV: |
453 | 826k | return getSameKindOfOperandsMapping(MI); |
454 | 302 | case TargetOpcode::G_BITCAST: { |
455 | 302 | LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); |
456 | 302 | LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); |
457 | 302 | unsigned Size = DstTy.getSizeInBits(); |
458 | 302 | bool DstIsGPR = !DstTy.isVector(); |
459 | 302 | bool SrcIsGPR = !SrcTy.isVector(); |
460 | 302 | const RegisterBank &DstRB = |
461 | 302 | DstIsGPR ? AArch64::GPRRegBank292 : AArch64::FPRRegBank10 ; |
462 | 302 | const RegisterBank &SrcRB = |
463 | 302 | SrcIsGPR ? AArch64::GPRRegBank10 : AArch64::FPRRegBank292 ; |
464 | 302 | return getInstructionMapping( |
465 | 302 | DefaultMappingID, copyCost(DstRB, SrcRB, Size), |
466 | 302 | getCopyMapping(DstRB.getID(), SrcRB.getID(), Size), |
467 | 302 | /*NumOperands*/ 2); |
468 | 826k | } |
469 | 3.48M | default: |
470 | 3.48M | break; |
471 | 3.48M | } |
472 | 3.48M | |
473 | 3.48M | unsigned NumOperands = MI.getNumOperands(); |
474 | 3.48M | |
475 | 3.48M | // Track the size and bank of each register. We don't do partial mappings. |
476 | 3.48M | SmallVector<unsigned, 4> OpSize(NumOperands); |
477 | 3.48M | SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands); |
478 | 11.0M | for (unsigned Idx = 0; Idx < NumOperands11.0M ; ++Idx7.57M ) { |
479 | 7.57M | auto &MO = MI.getOperand(Idx); |
480 | 7.57M | if (!MO.isReg() || 7.57M !MO.getReg()5.46M ) |
481 | 2.10M | continue; |
482 | 5.46M | |
483 | 5.46M | LLT Ty = MRI.getType(MO.getReg()); |
484 | 5.46M | OpSize[Idx] = Ty.getSizeInBits(); |
485 | 5.46M | |
486 | 5.46M | // As a top-level guess, vectors go in FPRs, scalars and pointers in GPRs. |
487 | 5.46M | // For floating-point instructions, scalars go in FPRs. |
488 | 5.46M | if (Ty.isVector() || 5.46M isPreISelGenericFloatingPointOpcode(Opc)5.45M || |
489 | 5.44M | Ty.getSizeInBits() > 64) |
490 | 25.2k | OpRegBankIdx[Idx] = PMI_FirstFPR; |
491 | 5.46M | else |
492 | 5.44M | OpRegBankIdx[Idx] = PMI_FirstGPR; |
493 | 7.57M | } |
494 | 3.48M | |
495 | 3.48M | unsigned Cost = 1; |
496 | 3.48M | // Some of the floating-point instructions have mixed GPR and FPR operands: |
497 | 3.48M | // fine-tune the computed mapping. |
498 | 3.48M | switch (Opc) { |
499 | 1.43k | case TargetOpcode::G_SITOFP: |
500 | 1.43k | case TargetOpcode::G_UITOFP: |
501 | 1.43k | OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR}; |
502 | 1.43k | break; |
503 | 630 | case TargetOpcode::G_FPTOSI: |
504 | 630 | case TargetOpcode::G_FPTOUI: |
505 | 630 | OpRegBankIdx = {PMI_FirstGPR, PMI_FirstFPR}; |
506 | 630 | break; |
507 | 1.53k | case TargetOpcode::G_FCMP: |
508 | 1.53k | OpRegBankIdx = {PMI_FirstGPR, |
509 | 1.53k | /* Predicate */ PMI_None, PMI_FirstFPR, PMI_FirstFPR}; |
510 | 1.53k | break; |
511 | 0 | case TargetOpcode::G_BITCAST: |
512 | 0 | // This is going to be a cross register bank copy and this is expensive. |
513 | 0 | if (OpRegBankIdx[0] != OpRegBankIdx[1]) |
514 | 0 | Cost = copyCost( |
515 | 0 | *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[0]].RegBank, |
516 | 0 | *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[1]].RegBank, |
517 | 0 | OpSize[0]); |
518 | 0 | break; |
519 | 363k | case TargetOpcode::G_LOAD: |
520 | 363k | // Loading in vector unit is slightly more expensive. |
521 | 363k | // This is actually only true for the LD1R and co instructions, |
522 | 363k | // but anyway for the fast mode this number does not matter and |
523 | 363k | // for the greedy mode the cost of the cross bank copy will |
524 | 363k | // offset this number. |
525 | 363k | // FIXME: Should be derived from the scheduling model. |
526 | 363k | if (OpRegBankIdx[0] != PMI_FirstGPR) |
527 | 32 | Cost = 2; |
528 | 363k | else |
529 | 363k | // Check if that load feeds fp instructions. |
530 | 363k | // In that case, we want the default mapping to be on FPR |
531 | 363k | // instead of blind map every scalar to GPR. |
532 | 363k | for (const MachineInstr &UseMI : |
533 | 363k | MRI.use_instructions(MI.getOperand(0).getReg())) |
534 | 363k | // If we have at least one direct use in a FP instruction, |
535 | 363k | // assume this was a floating point load in the IR. |
536 | 363k | // If it was not, we would have had a bitcast before |
537 | 363k | // reaching that instruction. |
538 | 485k | if (485k isPreISelGenericFloatingPointOpcode(UseMI.getOpcode())485k ) { |
539 | 2.82k | OpRegBankIdx[0] = PMI_FirstFPR; |
540 | 2.82k | break; |
541 | 2.82k | } |
542 | 363k | break; |
543 | 323k | case TargetOpcode::G_STORE: |
544 | 323k | // Check if that store is fed by fp instructions. |
545 | 323k | if (OpRegBankIdx[0] == PMI_FirstGPR323k ) { |
546 | 315k | unsigned VReg = MI.getOperand(0).getReg(); |
547 | 315k | if (!VReg) |
548 | 0 | break; |
549 | 315k | MachineInstr *DefMI = MRI.getVRegDef(VReg); |
550 | 315k | if (isPreISelGenericFloatingPointOpcode(DefMI->getOpcode())) |
551 | 2.31k | OpRegBankIdx[0] = PMI_FirstFPR; |
552 | 1.43k | break; |
553 | 1.43k | } |
554 | 3.48M | } |
555 | 3.48M | |
556 | 3.48M | // Finally construct the computed mapping. |
557 | 3.48M | SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); |
558 | 11.0M | for (unsigned Idx = 0; Idx < NumOperands11.0M ; ++Idx7.57M ) { |
559 | 7.57M | if (MI.getOperand(Idx).isReg() && 7.57M MI.getOperand(Idx).getReg()5.46M ) { |
560 | 5.46M | auto Mapping = getValueMapping(OpRegBankIdx[Idx], OpSize[Idx]); |
561 | 5.46M | if (!Mapping->isValid()) |
562 | 0 | return getInvalidInstructionMapping(); |
563 | 5.46M | |
564 | 5.46M | OpdsMapping[Idx] = Mapping; |
565 | 5.46M | } |
566 | 7.57M | } |
567 | 3.48M | |
568 | 3.48M | return getInstructionMapping(DefaultMappingID, Cost, |
569 | 3.48M | getOperandsMapping(OpdsMapping), NumOperands); |
570 | 7.21M | } |