LLVM 24.0.0git
AArch64MacroFusion.cpp
Go to the documentation of this file.
1//===- AArch64MacroFusion.cpp - AArch64 Macro Fusion ----------------------===//
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//
9/// \file This file contains the AArch64 implementation of the DAG scheduling
10/// mutation to pair instructions back to back.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AArch64MacroFusion.h"
15#include "AArch64Subtarget.h"
16#include "llvm/ADT/Statistic.h"
19
20#define DEBUG_TYPE "aarch64-macro-fusion"
21
22using namespace llvm;
23
24STATISTIC(NumFusedArithmeticBcc, "Number of arithmetic-Bcc fusions");
25STATISTIC(NumFusedArithmeticCbz, "Number of arithmetic-Cbz fusions");
26STATISTIC(NumFusedAES, "Number of AES fusions");
27STATISTIC(NumFusedCryptoEOR, "Number of crypto-EOR fusions");
28STATISTIC(NumFusedAdrpAdd, "Number of ADRP-ADD fusions");
29STATISTIC(NumFusedLiterals, "Number of literal-generation fusions");
30STATISTIC(NumFusedAddress, "Number of address-generation load/store fusions");
31STATISTIC(NumFusedCmpCSel, "Number of compare-CSEL fusions");
32STATISTIC(NumFusedFCmpFCSel, "Number of FP-compare-FCSEL fusions");
33STATISTIC(NumFusedCmpCSet, "Number of compare-CSET fusions");
34STATISTIC(NumFusedArithmeticLogic, "Number of arithmetic-logic fusions");
35STATISTIC(NumFusedAddSub2RegAndConstOne,
36 "Number of add/sub-two-register-and-constant-one fusions");
37STATISTIC(NumFusedAppleSMECompute, "Number of Apple SME compute fusions");
38STATISTIC(NumFusedFMinFMax, "Number of FMIN-FMAX fusions");
39
40/// CMN, CMP, TST followed by Bcc
41static bool isArithmeticBccPair(const MachineInstr *FirstMI,
42 const MachineInstr &SecondMI, bool CmpOnly) {
43 if (SecondMI.getOpcode() != AArch64::Bcc)
44 return false;
45
46 // Assume the 1st instr to be a wildcard if it is unspecified.
47 if (FirstMI == nullptr)
48 return true;
49
50 // If we're in CmpOnly mode, we only fuse arithmetic instructions that
51 // discard their result.
52 if (CmpOnly && FirstMI->getOperand(0).isReg() &&
53 !(FirstMI->getOperand(0).getReg() == AArch64::XZR ||
54 FirstMI->getOperand(0).getReg() == AArch64::WZR)) {
55 return false;
56 }
57
58 switch (FirstMI->getOpcode()) {
59 case AArch64::ADDSWri:
60 case AArch64::ADDSWrr:
61 case AArch64::ADDSXri:
62 case AArch64::ADDSXrr:
63 case AArch64::ANDSWri:
64 case AArch64::ANDSWrr:
65 case AArch64::ANDSXri:
66 case AArch64::ANDSXrr:
67 case AArch64::SUBSWri:
68 case AArch64::SUBSWrr:
69 case AArch64::SUBSXri:
70 case AArch64::SUBSXrr:
71 case AArch64::BICSWrr:
72 case AArch64::BICSXrr:
73 return true;
74 case AArch64::ADDSWrs:
75 case AArch64::ADDSXrs:
76 case AArch64::ANDSWrs:
77 case AArch64::ANDSXrs:
78 case AArch64::SUBSWrs:
79 case AArch64::SUBSXrs:
80 case AArch64::BICSWrs:
81 case AArch64::BICSXrs:
82 // Shift value can be 0 making these behave like the "rr" variant...
83 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
84 }
85
86 return false;
87}
88
89/// ALU operations followed by CBZ/CBNZ.
90static bool isArithmeticCbzPair(const MachineInstr *FirstMI,
91 const MachineInstr &SecondMI) {
92 if (SecondMI.getOpcode() != AArch64::CBZW &&
93 SecondMI.getOpcode() != AArch64::CBZX &&
94 SecondMI.getOpcode() != AArch64::CBNZW &&
95 SecondMI.getOpcode() != AArch64::CBNZX &&
96 SecondMI.getOpcode() != AArch64::TBZW &&
97 SecondMI.getOpcode() != AArch64::TBZX &&
98 SecondMI.getOpcode() != AArch64::TBNZW &&
99 SecondMI.getOpcode() != AArch64::TBNZX)
100 return false;
101
102 // Assume the 1st instr to be a wildcard if it is unspecified.
103 if (FirstMI == nullptr)
104 return true;
105
106 switch (FirstMI->getOpcode()) {
107 case AArch64::ADDWri:
108 case AArch64::ADDWrr:
109 case AArch64::ADDXri:
110 case AArch64::ADDXrr:
111 case AArch64::ANDWri:
112 case AArch64::ANDWrr:
113 case AArch64::ANDXri:
114 case AArch64::ANDXrr:
115 case AArch64::EORWri:
116 case AArch64::EORWrr:
117 case AArch64::EORXri:
118 case AArch64::EORXrr:
119 case AArch64::ORRWri:
120 case AArch64::ORRWrr:
121 case AArch64::ORRXri:
122 case AArch64::ORRXrr:
123 case AArch64::ORNWrr:
124 case AArch64::ORNXrr:
125 case AArch64::SUBWri:
126 case AArch64::SUBWrr:
127 case AArch64::SUBXri:
128 case AArch64::SUBXrr:
129 case AArch64::BICWrr:
130 case AArch64::BICXrr:
131 return true;
132 case AArch64::ADDWrs:
133 case AArch64::ADDXrs:
134 case AArch64::ANDWrs:
135 case AArch64::ANDXrs:
136 case AArch64::EORWrs:
137 case AArch64::EORXrs:
138 case AArch64::ORNWrs:
139 case AArch64::ORNXrs:
140 case AArch64::ORRWrs:
141 case AArch64::ORRXrs:
142 case AArch64::SUBWrs:
143 case AArch64::SUBXrs:
144 case AArch64::BICWrs:
145 case AArch64::BICXrs:
146 // Shift value can be 0 making these behave like the "rr" variant...
147 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
148 }
149
150 return false;
151}
152
153// True unless the pair provably writes non overlapping physical registers.
154// Pre-RA the dests are still virtual, and post-RA it requires a genuine WAW,
155// that is overlapping dest regs. Overlapping includes sub and super register
156// relations, e.g. W0 and X0, which matches the register unit based dependency
157// model of the scheduling DAG.
158static bool mayHaveWAWDependency(const MachineInstr &FirstMI,
159 const MachineInstr &SecondMI,
160 const TargetRegisterInfo *TRI) {
161 Register DestFirst = FirstMI.getOperand(0).getReg();
162 Register DestSecond = SecondMI.getOperand(0).getReg();
163 if (!DestFirst.isPhysical() || !DestSecond.isPhysical())
164 return true;
165 return TRI->regsOverlap(DestFirst, DestSecond);
166}
167
168/// AES crypto encoding or decoding.
169static bool isAESPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI,
170 const TargetRegisterInfo *TRI) {
171 // Assume the 1st instr to be a wildcard if it is unspecified.
172 unsigned SecondOpcode = SecondMI.getOpcode();
173 switch (SecondOpcode) {
174 // AES encode.
175 case AArch64::AESMCrr:
176 case AArch64::AESMCrrTied:
177 if (FirstMI == nullptr)
178 return true;
179 if (FirstMI->getOpcode() != AArch64::AESErr)
180 return false;
181 return SecondOpcode == AArch64::AESMCrrTied ||
182 mayHaveWAWDependency(*FirstMI, SecondMI, TRI);
183 // AES decode.
184 case AArch64::AESIMCrr:
185 case AArch64::AESIMCrrTied:
186 if (FirstMI == nullptr)
187 return true;
188 if (FirstMI->getOpcode() != AArch64::AESDrr)
189 return false;
190 return SecondOpcode == AArch64::AESIMCrrTied ||
191 mayHaveWAWDependency(*FirstMI, SecondMI, TRI);
192 }
193
194 return false;
195}
196
197/// AESE/AESD/PMULL + EOR.
198static bool isCryptoEORPair(const MachineInstr *FirstMI,
199 const MachineInstr &SecondMI) {
200 if (SecondMI.getOpcode() != AArch64::EORv16i8)
201 return false;
202
203 // Assume the 1st instr to be a wildcard if it is unspecified.
204 if (FirstMI == nullptr)
205 return true;
206
207 switch (FirstMI->getOpcode()) {
208 case AArch64::AESErr:
209 case AArch64::AESDrr:
210 case AArch64::PMULLv16i8:
211 case AArch64::PMULLv8i8:
212 case AArch64::PMULLv1i64:
213 case AArch64::PMULLv2i64:
214 return true;
215 }
216
217 return false;
218}
219
220static bool isAdrpAddPair(const MachineInstr *FirstMI,
221 const MachineInstr &SecondMI) {
222 // Assume the 1st instr to be a wildcard if it is unspecified.
223 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::ADRP) &&
224 SecondMI.getOpcode() == AArch64::ADDXri)
225 return true;
226 return false;
227}
228
229/// Literal generation.
230static bool isLiteralsPair(const MachineInstr *FirstMI,
231 const MachineInstr &SecondMI) {
232 // Assume the 1st instr to be a wildcard if it is unspecified.
233 // 32 bit immediate.
234 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZWi) &&
235 (SecondMI.getOpcode() == AArch64::MOVKWi &&
236 SecondMI.getOperand(3).getImm() == 16))
237 return true;
238
239 // Lower half of 64 bit immediate.
240 if((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZXi) &&
241 (SecondMI.getOpcode() == AArch64::MOVKXi &&
242 SecondMI.getOperand(3).getImm() == 16))
243 return true;
244
245 // Upper half of 64 bit immediate.
246 if ((FirstMI == nullptr ||
247 (FirstMI->getOpcode() == AArch64::MOVKXi &&
248 FirstMI->getOperand(3).getImm() == 32)) &&
249 (SecondMI.getOpcode() == AArch64::MOVKXi &&
250 SecondMI.getOperand(3).getImm() == 48))
251 return true;
252
253 return false;
254}
255
256/// Fuse address generation and loads or stores.
257static bool isAddressLdStPair(const MachineInstr *FirstMI,
258 const MachineInstr &SecondMI) {
259 switch (SecondMI.getOpcode()) {
260 case AArch64::STRBBui:
261 case AArch64::STRBui:
262 case AArch64::STRDui:
263 case AArch64::STRHHui:
264 case AArch64::STRHui:
265 case AArch64::STRQui:
266 case AArch64::STRSui:
267 case AArch64::STRWui:
268 case AArch64::STRXui:
269 case AArch64::LDRBBui:
270 case AArch64::LDRBui:
271 case AArch64::LDRDui:
272 case AArch64::LDRHHui:
273 case AArch64::LDRHui:
274 case AArch64::LDRQui:
275 case AArch64::LDRSui:
276 case AArch64::LDRWui:
277 case AArch64::LDRXui:
278 case AArch64::LDRSBWui:
279 case AArch64::LDRSBXui:
280 case AArch64::LDRSHWui:
281 case AArch64::LDRSHXui:
282 case AArch64::LDRSWui:
283 // Assume the 1st instr to be a wildcard if it is unspecified.
284 if (FirstMI == nullptr)
285 return true;
286
287 switch (FirstMI->getOpcode()) {
288 case AArch64::ADR:
289 return SecondMI.getOperand(2).getImm() == 0;
290 case AArch64::ADRP:
291 return true;
292 }
293 }
294
295 return false;
296}
297
298/// Compare and conditional select.
299static bool isCmpCSelPair(const MachineInstr *FirstMI,
300 const MachineInstr &SecondMI) {
301 // 32 bits
302 if (SecondMI.getOpcode() == AArch64::CSELWr) {
303 // Assume the 1st instr to be a wildcard if it is unspecified.
304 if (FirstMI == nullptr)
305 return true;
306
307 if (FirstMI->definesRegister(AArch64::WZR, /*TRI=*/nullptr))
308 switch (FirstMI->getOpcode()) {
309 case AArch64::SUBSWrs:
310 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
311 case AArch64::SUBSWrx:
312 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
313 case AArch64::SUBSWrr:
314 case AArch64::SUBSWri:
315 return true;
316 }
317 }
318
319 // 64 bits
320 if (SecondMI.getOpcode() == AArch64::CSELXr) {
321 // Assume the 1st instr to be a wildcard if it is unspecified.
322 if (FirstMI == nullptr)
323 return true;
324
325 if (FirstMI->definesRegister(AArch64::XZR, /*TRI=*/nullptr))
326 switch (FirstMI->getOpcode()) {
327 case AArch64::SUBSXrs:
328 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
329 case AArch64::SUBSXrx:
330 case AArch64::SUBSXrx64:
331 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
332 case AArch64::SUBSXrr:
333 case AArch64::SUBSXri:
334 return true;
335 }
336 }
337
338 return false;
339}
340
341/// Floating-point compare and floating-point conditional select.
342static bool isFCmpFCSelPair(const MachineInstr *FirstMI,
343 const MachineInstr &SecondMI) {
344 switch (SecondMI.getOpcode()) {
345 case AArch64::FCSELSrrr:
346 case AArch64::FCSELDrrr:
347 case AArch64::FCSELHrrr:
348 break;
349 default:
350 return false;
351 }
352
353 // Assume the 1st instr to be a wildcard if it is unspecified.
354 if (FirstMI == nullptr)
355 return true;
356
357 switch (FirstMI->getOpcode()) {
358 case AArch64::FCMPSrr:
359 case AArch64::FCMPDrr:
360 case AArch64::FCMPESrr:
361 case AArch64::FCMPEDrr:
362 case AArch64::FCMPHrr:
363 case AArch64::FCMPEHrr:
364 return true;
365 default:
366 return false;
367 }
368}
369
370/// Compare and cset.
371static bool isCmpCSetPair(const MachineInstr *FirstMI,
372 const MachineInstr &SecondMI) {
373 if ((SecondMI.getOpcode() == AArch64::CSINCWr &&
374 SecondMI.getOperand(1).getReg() == AArch64::WZR &&
375 SecondMI.getOperand(2).getReg() == AArch64::WZR) ||
376 (SecondMI.getOpcode() == AArch64::CSINCXr &&
377 SecondMI.getOperand(1).getReg() == AArch64::XZR &&
378 SecondMI.getOperand(2).getReg() == AArch64::XZR)) {
379 // Assume the 1st instr to be a wildcard if it is unspecified.
380 if (FirstMI == nullptr)
381 return true;
382
383 if (FirstMI->definesRegister(AArch64::WZR, /*TRI=*/nullptr) ||
384 FirstMI->definesRegister(AArch64::XZR, /*TRI=*/nullptr))
385 switch (FirstMI->getOpcode()) {
386 case AArch64::SUBSWrs:
387 case AArch64::SUBSXrs:
388 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
389 case AArch64::SUBSWrx:
390 case AArch64::SUBSXrx:
391 case AArch64::SUBSXrx64:
392 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
393 case AArch64::SUBSWri:
394 case AArch64::SUBSWrr:
395 case AArch64::SUBSXri:
396 case AArch64::SUBSXrr:
397 return true;
398 }
399 }
400
401 return false;
402}
403
404// Arithmetic and logic.
405static bool isArithmeticLogicPair(const MachineInstr *FirstMI,
406 const MachineInstr &SecondMI) {
407 if (AArch64InstrInfo::hasShiftedReg(SecondMI))
408 return false;
409
410 switch (SecondMI.getOpcode()) {
411 // Arithmetic
412 case AArch64::ADDWrr:
413 case AArch64::ADDXrr:
414 case AArch64::SUBWrr:
415 case AArch64::SUBXrr:
416 case AArch64::ADDWrs:
417 case AArch64::ADDXrs:
418 case AArch64::SUBWrs:
419 case AArch64::SUBXrs:
420 // Logic
421 case AArch64::ANDWrr:
422 case AArch64::ANDXrr:
423 case AArch64::BICWrr:
424 case AArch64::BICXrr:
425 case AArch64::EONWrr:
426 case AArch64::EONXrr:
427 case AArch64::EORWrr:
428 case AArch64::EORXrr:
429 case AArch64::ORNWrr:
430 case AArch64::ORNXrr:
431 case AArch64::ORRWrr:
432 case AArch64::ORRXrr:
433 case AArch64::ANDWrs:
434 case AArch64::ANDXrs:
435 case AArch64::BICWrs:
436 case AArch64::BICXrs:
437 case AArch64::EONWrs:
438 case AArch64::EONXrs:
439 case AArch64::EORWrs:
440 case AArch64::EORXrs:
441 case AArch64::ORNWrs:
442 case AArch64::ORNXrs:
443 case AArch64::ORRWrs:
444 case AArch64::ORRXrs:
445 // Assume the 1st instr to be a wildcard if it is unspecified.
446 if (FirstMI == nullptr)
447 return true;
448
449 // Arithmetic
450 switch (FirstMI->getOpcode()) {
451 case AArch64::ADDWrr:
452 case AArch64::ADDXrr:
453 case AArch64::ADDSWrr:
454 case AArch64::ADDSXrr:
455 case AArch64::SUBWrr:
456 case AArch64::SUBXrr:
457 case AArch64::SUBSWrr:
458 case AArch64::SUBSXrr:
459 return true;
460 case AArch64::ADDWrs:
461 case AArch64::ADDXrs:
462 case AArch64::ADDSWrs:
463 case AArch64::ADDSXrs:
464 case AArch64::SUBWrs:
465 case AArch64::SUBXrs:
466 case AArch64::SUBSWrs:
467 case AArch64::SUBSXrs:
468 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
469 }
470 break;
471
472 // Arithmetic, setting flags.
473 case AArch64::ADDSWrr:
474 case AArch64::ADDSXrr:
475 case AArch64::SUBSWrr:
476 case AArch64::SUBSXrr:
477 case AArch64::ADDSWrs:
478 case AArch64::ADDSXrs:
479 case AArch64::SUBSWrs:
480 case AArch64::SUBSXrs:
481 // Assume the 1st instr to be a wildcard if it is unspecified.
482 if (FirstMI == nullptr)
483 return true;
484
485 // Arithmetic, not setting flags.
486 switch (FirstMI->getOpcode()) {
487 case AArch64::ADDWrr:
488 case AArch64::ADDXrr:
489 case AArch64::SUBWrr:
490 case AArch64::SUBXrr:
491 return true;
492 case AArch64::ADDWrs:
493 case AArch64::ADDXrs:
494 case AArch64::SUBWrs:
495 case AArch64::SUBXrs:
496 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
497 }
498 break;
499 }
500
501 return false;
502}
503
504// "(A + B) + 1" or "(A - B) - 1"
505static bool isAddSub2RegAndConstOnePair(const MachineInstr *FirstMI,
506 const MachineInstr &SecondMI) {
507 bool NeedsSubtract = false;
508
509 // The 2nd instr must be an add-immediate or subtract-immediate.
510 switch (SecondMI.getOpcode()) {
511 case AArch64::SUBWri:
512 case AArch64::SUBXri:
513 NeedsSubtract = true;
514 [[fallthrough]];
515 case AArch64::ADDWri:
516 case AArch64::ADDXri:
517 break;
518
519 default:
520 return false;
521 }
522
523 // The immediate in the 2nd instr must be "1".
524 if (!SecondMI.getOperand(2).isImm() || SecondMI.getOperand(2).getImm() != 1) {
525 return false;
526 }
527
528 // Assume the 1st instr to be a wildcard if it is unspecified.
529 if (FirstMI == nullptr) {
530 return true;
531 }
532
533 switch (FirstMI->getOpcode()) {
534 case AArch64::SUBWrs:
535 case AArch64::SUBXrs:
536 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
537 return false;
538 [[fallthrough]];
539 case AArch64::SUBWrr:
540 case AArch64::SUBXrr:
541 if (NeedsSubtract) {
542 return true;
543 }
544 break;
545
546 case AArch64::ADDWrs:
547 case AArch64::ADDXrs:
548 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
549 return false;
550 [[fallthrough]];
551 case AArch64::ADDWrr:
552 case AArch64::ADDXrr:
553 if (!NeedsSubtract) {
554 return true;
555 }
556 break;
557 }
558
559 return false;
560}
561
563 const TargetRegisterInfo *TRI,
564 const TargetRegisterClass &Class) {
565 return llvm::any_of(Class, [&MI, TRI](MCPhysReg Reg) {
566 return MI.definesRegister(Reg, TRI);
567 });
568}
569
570static bool readsRegInClass(const MachineInstr &MI,
571 const TargetRegisterInfo *TRI,
572 const TargetRegisterClass &Class) {
573 return llvm::any_of(
574 Class, [&MI, TRI](MCPhysReg Reg) { return MI.readsRegister(Reg, TRI); });
575}
576
578 const TargetInstrInfo &TII,
579 const TargetRegisterInfo *TRI) {
580 const bool ReadOrWriteZA = MI.readsRegister(AArch64::ZA, TRI) ||
581 MI.definesRegister(AArch64::ZA, TRI);
582
583 // (read/write ZA or read/write Z)
584 if (!ReadOrWriteZA && !definesRegInClass(MI, TRI, AArch64::ZPRRegClass))
585 return false;
586
587 // (NOT load/store)
588 if (MI.mayLoad() || MI.mayStore())
589 return false;
590
591 // (NOT write P)
592 if (definesRegInClass(MI, TRI, AArch64::PPRRegClass))
593 return false;
594
595 // (NOT write GPR)
596 const bool WriteGPR = definesRegInClass(MI, TRI, AArch64::GPR32RegClass) ||
597 definesRegInClass(MI, TRI, AArch64::GPR64RegClass);
598 if (WriteGPR)
599 return false;
600
601 // (NOT read/write NZCV)
602 if (MI.readsRegister(AArch64::NZCV, TRI) ||
603 MI.definesRegister(AArch64::NZCV, TRI))
604 return false;
605
606 const bool ReadGPR = readsRegInClass(MI, TRI, AArch64::GPR32RegClass) &&
607 readsRegInClass(MI, TRI, AArch64::GPR64RegClass);
608
609 // ( (NOT read GPR) or read/write ZA )
610 if (ReadGPR && !ReadOrWriteZA)
611 return false;
612
613 return true;
614}
615
616static bool isAppleSMEComputePair(const MachineInstr *FirstMI,
617 const MachineInstr &SecondMI,
618 const TargetInstrInfo &TII,
619 const TargetRegisterInfo *TRI) {
620 if (!isFusableAppleSMEComputeOp(SecondMI, TII, TRI))
621 return false;
622 // Assume the 1st instr to be a wildcard if it is unspecified.
623 if (FirstMI == nullptr)
624 return true;
625 if (isFusableAppleSMEComputeOp(*FirstMI, TII, TRI))
626 return true;
627 return false;
628}
629
630// Floating-point minimum or maximum, scalar (H/S/D) or vector (Vd).
631static bool isFMinFMax(unsigned Opcode) {
632 switch (Opcode) {
633 // Scalar.
634 case AArch64::FMAXHrr:
635 case AArch64::FMAXSrr:
636 case AArch64::FMAXDrr:
637 case AArch64::FMINHrr:
638 case AArch64::FMINSrr:
639 case AArch64::FMINDrr:
640 // Vector.
641 case AArch64::FMAXv4f16:
642 case AArch64::FMAXv8f16:
643 case AArch64::FMAXv2f32:
644 case AArch64::FMAXv4f32:
645 case AArch64::FMAXv2f64:
646 case AArch64::FMINv4f16:
647 case AArch64::FMINv8f16:
648 case AArch64::FMINv2f32:
649 case AArch64::FMINv4f32:
650 case AArch64::FMINv2f64:
651 return true;
652 }
653 return false;
654}
655
656// FMIN + FMAX.
657static bool isFMinFMaxPair(const MachineInstr *FirstMI,
658 const MachineInstr &SecondMI,
659 const TargetRegisterInfo *TRI) {
660 if (!isFMinFMax(SecondMI.getOpcode()))
661 return false;
662
663 // Assume the 1st instr to be a wildcard if it is unspecified.
664 if (FirstMI == nullptr)
665 return true;
666
667 if (!isFMinFMax(FirstMI->getOpcode()))
668 return false;
669
670 return mayHaveWAWDependency(*FirstMI, SecondMI, TRI);
671}
672
673/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
674/// together. Given SecondMI, when FirstMI is unspecified, then check if
675/// SecondMI may be part of a fused pair at all.
677 const TargetSubtargetInfo &TSI,
678 const MachineInstr *FirstMI,
679 const MachineInstr &SecondMI,
680 const SDep *Dep) {
681 const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);
683
684 // All checking functions assume that the 1st instr is a wildcard if it is
685 // unspecified.
686
687 // FuseAppleSMECompute does not require a specific dependency kind
688 if (ST.hasFuseAppleSMECompute() &&
689 isAppleSMEComputePair(FirstMI, SecondMI, TII, TRI)) {
690 ++NumFusedAppleSMECompute;
691 return true;
692 }
693
694 // All the other fusions require RAW dependency
695 if (isNonDataDep(Dep))
696 return false;
697
698 if (ST.hasCmpBccFusion() || ST.hasArithmeticBccFusion()) {
699 bool CmpOnly = !ST.hasArithmeticBccFusion();
700 if (isArithmeticBccPair(FirstMI, SecondMI, CmpOnly)) {
701 ++NumFusedArithmeticBcc;
702 return true;
703 }
704 }
705 if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI)) {
706 ++NumFusedArithmeticCbz;
707 return true;
708 }
709 if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI, TRI)) {
710 ++NumFusedAES;
711 return true;
712 }
713 if (ST.hasFuseCryptoEOR() && isCryptoEORPair(FirstMI, SecondMI)) {
714 ++NumFusedCryptoEOR;
715 return true;
716 }
717 if (ST.hasFuseAdrpAdd() && isAdrpAddPair(FirstMI, SecondMI)) {
718 ++NumFusedAdrpAdd;
719 return true;
720 }
721 if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI)) {
722 ++NumFusedLiterals;
723 return true;
724 }
725 if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI)) {
726 ++NumFusedAddress;
727 return true;
728 }
729 if (ST.hasFuseCmpCSel() && isCmpCSelPair(FirstMI, SecondMI)) {
730 ++NumFusedCmpCSel;
731 return true;
732 }
733 if (ST.hasFuseFCmpFCSel() && isFCmpFCSelPair(FirstMI, SecondMI)) {
734 ++NumFusedFCmpFCSel;
735 return true;
736 }
737 if (ST.hasFuseCmpCSet() && isCmpCSetPair(FirstMI, SecondMI)) {
738 ++NumFusedCmpCSet;
739 return true;
740 }
741 if (ST.hasFuseArithmeticLogic() && isArithmeticLogicPair(FirstMI, SecondMI)) {
742 ++NumFusedArithmeticLogic;
743 return true;
744 }
745 if (ST.hasFuseAddSub2RegAndConstOne() &&
746 isAddSub2RegAndConstOnePair(FirstMI, SecondMI)) {
747 ++NumFusedAddSub2RegAndConstOne;
748 return true;
749 }
750 if (ST.hasFuseFMinFMax() && isFMinFMaxPair(FirstMI, SecondMI, TRI)) {
751 ++NumFusedFMinFMax;
752 return true;
753 }
754
755 return false;
756}
757
758std::unique_ptr<ScheduleDAGMutation>
static bool isFusableAppleSMEComputeOp(const MachineInstr &MI, const TargetInstrInfo &TII, const TargetRegisterInfo *TRI)
static bool isFCmpFCSelPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Floating-point compare and floating-point conditional select.
static bool isAddSub2RegAndConstOnePair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isCmpCSelPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Compare and conditional select.
static bool isArithmeticBccPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI, bool CmpOnly)
CMN, CMP, TST followed by Bcc.
static bool isAddressLdStPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Fuse address generation and loads or stores.
static bool isFMinFMaxPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI, const TargetRegisterInfo *TRI)
static bool isArithmeticCbzPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
ALU operations followed by CBZ/CBNZ.
static bool isCmpCSetPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Compare and cset.
static bool isAdrpAddPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isAESPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI, const TargetRegisterInfo *TRI)
AES crypto encoding or decoding.
static bool readsRegInClass(const MachineInstr &MI, const TargetRegisterInfo *TRI, const TargetRegisterClass &Class)
static bool definesRegInClass(const MachineInstr &MI, const TargetRegisterInfo *TRI, const TargetRegisterClass &Class)
static bool isArithmeticLogicPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isFMinFMax(unsigned Opcode)
static bool mayHaveWAWDependency(const MachineInstr &FirstMI, const MachineInstr &SecondMI, const TargetRegisterInfo *TRI)
static bool isCryptoEORPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
AESE/AESD/PMULL + EOR.
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI, const SDep *Dep)
Check if the instr pair, FirstMI and SecondMI, should be fused together.
static bool isAppleSMEComputePair(const MachineInstr *FirstMI, const MachineInstr &SecondMI, const TargetInstrInfo &TII, const TargetRegisterInfo *TRI)
static bool isLiteralsPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Literal generation.
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Register Reg
Register const TargetRegisterInfo * TRI
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
bool definesRegister(Register Reg, const TargetRegisterInfo *TRI) const
Return true if the MachineInstr fully defines the specified register.
const MachineOperand & getOperand(unsigned i) const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
Scheduling dependency.
Definition ScheduleDAG.h:52
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::unique_ptr< ScheduleDAGMutation > createMacroFusionDAGMutation(ArrayRef< MacroFusionPredTy > Predicates, bool BranchOnly=false)
Create a DAG scheduling mutation to pair instructions back to back for instructions that benefit acco...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
std::unique_ptr< ScheduleDAGMutation > createAArch64MacroFusionDAGMutation()
Note that you have to add: DAG.addMutation(createAArch64MacroFusionDAGMutation()); to AArch64TargetMa...
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI, const SDep *Dep)
Check if the instr pair, FirstMI and SecondMI, should be fused together.
LLVM_ABI bool isNonDataDep(const SDep *Dep)
Returns true if Dep is a non-null non-data dependency.
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58