LLVM 23.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"
18
19using namespace llvm;
20
21/// CMN, CMP, TST followed by Bcc
22static bool isArithmeticBccPair(const MachineInstr *FirstMI,
23 const MachineInstr &SecondMI, bool CmpOnly) {
24 if (SecondMI.getOpcode() != AArch64::Bcc)
25 return false;
26
27 // Assume the 1st instr to be a wildcard if it is unspecified.
28 if (FirstMI == nullptr)
29 return true;
30
31 // If we're in CmpOnly mode, we only fuse arithmetic instructions that
32 // discard their result.
33 if (CmpOnly && FirstMI->getOperand(0).isReg() &&
34 !(FirstMI->getOperand(0).getReg() == AArch64::XZR ||
35 FirstMI->getOperand(0).getReg() == AArch64::WZR)) {
36 return false;
37 }
38
39 switch (FirstMI->getOpcode()) {
40 case AArch64::ADDSWri:
41 case AArch64::ADDSWrr:
42 case AArch64::ADDSXri:
43 case AArch64::ADDSXrr:
44 case AArch64::ANDSWri:
45 case AArch64::ANDSWrr:
46 case AArch64::ANDSXri:
47 case AArch64::ANDSXrr:
48 case AArch64::SUBSWri:
49 case AArch64::SUBSWrr:
50 case AArch64::SUBSXri:
51 case AArch64::SUBSXrr:
52 case AArch64::BICSWrr:
53 case AArch64::BICSXrr:
54 return true;
55 case AArch64::ADDSWrs:
56 case AArch64::ADDSXrs:
57 case AArch64::ANDSWrs:
58 case AArch64::ANDSXrs:
59 case AArch64::SUBSWrs:
60 case AArch64::SUBSXrs:
61 case AArch64::BICSWrs:
62 case AArch64::BICSXrs:
63 // Shift value can be 0 making these behave like the "rr" variant...
64 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
65 }
66
67 return false;
68}
69
70/// ALU operations followed by CBZ/CBNZ.
71static bool isArithmeticCbzPair(const MachineInstr *FirstMI,
72 const MachineInstr &SecondMI) {
73 if (SecondMI.getOpcode() != AArch64::CBZW &&
74 SecondMI.getOpcode() != AArch64::CBZX &&
75 SecondMI.getOpcode() != AArch64::CBNZW &&
76 SecondMI.getOpcode() != AArch64::CBNZX)
77 return false;
78
79 // Assume the 1st instr to be a wildcard if it is unspecified.
80 if (FirstMI == nullptr)
81 return true;
82
83 switch (FirstMI->getOpcode()) {
84 case AArch64::ADDWri:
85 case AArch64::ADDWrr:
86 case AArch64::ADDXri:
87 case AArch64::ADDXrr:
88 case AArch64::ANDWri:
89 case AArch64::ANDWrr:
90 case AArch64::ANDXri:
91 case AArch64::ANDXrr:
92 case AArch64::EORWri:
93 case AArch64::EORWrr:
94 case AArch64::EORXri:
95 case AArch64::EORXrr:
96 case AArch64::ORRWri:
97 case AArch64::ORRWrr:
98 case AArch64::ORRXri:
99 case AArch64::ORRXrr:
100 case AArch64::SUBWri:
101 case AArch64::SUBWrr:
102 case AArch64::SUBXri:
103 case AArch64::SUBXrr:
104 return true;
105 case AArch64::ADDWrs:
106 case AArch64::ADDXrs:
107 case AArch64::ANDWrs:
108 case AArch64::ANDXrs:
109 case AArch64::SUBWrs:
110 case AArch64::SUBXrs:
111 case AArch64::BICWrs:
112 case AArch64::BICXrs:
113 // Shift value can be 0 making these behave like the "rr" variant...
114 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
115 }
116
117 return false;
118}
119
120// True unless the pair provably writes different physical registers. Pre-RA
121// the dests are still virtual, and post-RA it requires a genuine WAW (same dest
122// reg).
123static bool mayHaveWAWDependency(const MachineInstr &FirstMI,
124 const MachineInstr &SecondMI) {
125 Register DestFirst = FirstMI.getOperand(0).getReg();
126 Register DestSecond = SecondMI.getOperand(0).getReg();
127 if (!DestFirst.isPhysical() || !DestSecond.isPhysical())
128 return true;
129 return DestFirst == DestSecond;
130}
131
132/// AES crypto encoding or decoding.
133static bool isAESPair(const MachineInstr *FirstMI,
134 const MachineInstr &SecondMI) {
135 // Assume the 1st instr to be a wildcard if it is unspecified.
136 unsigned SecondOpcode = SecondMI.getOpcode();
137 switch (SecondOpcode) {
138 // AES encode.
139 case AArch64::AESMCrr:
140 case AArch64::AESMCrrTied:
141 if (FirstMI == nullptr)
142 return true;
143 if (FirstMI->getOpcode() != AArch64::AESErr)
144 return false;
145 return SecondOpcode == AArch64::AESMCrrTied ||
146 mayHaveWAWDependency(*FirstMI, SecondMI);
147 // AES decode.
148 case AArch64::AESIMCrr:
149 case AArch64::AESIMCrrTied:
150 if (FirstMI == nullptr)
151 return true;
152 if (FirstMI->getOpcode() != AArch64::AESDrr)
153 return false;
154 return SecondOpcode == AArch64::AESIMCrrTied ||
155 mayHaveWAWDependency(*FirstMI, SecondMI);
156 }
157
158 return false;
159}
160
161/// AESE/AESD/PMULL + EOR.
162static bool isCryptoEORPair(const MachineInstr *FirstMI,
163 const MachineInstr &SecondMI) {
164 if (SecondMI.getOpcode() != AArch64::EORv16i8)
165 return false;
166
167 // Assume the 1st instr to be a wildcard if it is unspecified.
168 if (FirstMI == nullptr)
169 return true;
170
171 switch (FirstMI->getOpcode()) {
172 case AArch64::AESErr:
173 case AArch64::AESDrr:
174 case AArch64::PMULLv16i8:
175 case AArch64::PMULLv8i8:
176 case AArch64::PMULLv1i64:
177 case AArch64::PMULLv2i64:
178 return true;
179 }
180
181 return false;
182}
183
184static bool isAdrpAddPair(const MachineInstr *FirstMI,
185 const MachineInstr &SecondMI) {
186 // Assume the 1st instr to be a wildcard if it is unspecified.
187 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::ADRP) &&
188 SecondMI.getOpcode() == AArch64::ADDXri)
189 return true;
190 return false;
191}
192
193/// Literal generation.
194static bool isLiteralsPair(const MachineInstr *FirstMI,
195 const MachineInstr &SecondMI) {
196 // Assume the 1st instr to be a wildcard if it is unspecified.
197 // 32 bit immediate.
198 if ((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZWi) &&
199 (SecondMI.getOpcode() == AArch64::MOVKWi &&
200 SecondMI.getOperand(3).getImm() == 16))
201 return true;
202
203 // Lower half of 64 bit immediate.
204 if((FirstMI == nullptr || FirstMI->getOpcode() == AArch64::MOVZXi) &&
205 (SecondMI.getOpcode() == AArch64::MOVKXi &&
206 SecondMI.getOperand(3).getImm() == 16))
207 return true;
208
209 // Upper half of 64 bit immediate.
210 if ((FirstMI == nullptr ||
211 (FirstMI->getOpcode() == AArch64::MOVKXi &&
212 FirstMI->getOperand(3).getImm() == 32)) &&
213 (SecondMI.getOpcode() == AArch64::MOVKXi &&
214 SecondMI.getOperand(3).getImm() == 48))
215 return true;
216
217 return false;
218}
219
220/// Fuse address generation and loads or stores.
221static bool isAddressLdStPair(const MachineInstr *FirstMI,
222 const MachineInstr &SecondMI) {
223 switch (SecondMI.getOpcode()) {
224 case AArch64::STRBBui:
225 case AArch64::STRBui:
226 case AArch64::STRDui:
227 case AArch64::STRHHui:
228 case AArch64::STRHui:
229 case AArch64::STRQui:
230 case AArch64::STRSui:
231 case AArch64::STRWui:
232 case AArch64::STRXui:
233 case AArch64::LDRBBui:
234 case AArch64::LDRBui:
235 case AArch64::LDRDui:
236 case AArch64::LDRHHui:
237 case AArch64::LDRHui:
238 case AArch64::LDRQui:
239 case AArch64::LDRSui:
240 case AArch64::LDRWui:
241 case AArch64::LDRXui:
242 case AArch64::LDRSBWui:
243 case AArch64::LDRSBXui:
244 case AArch64::LDRSHWui:
245 case AArch64::LDRSHXui:
246 case AArch64::LDRSWui:
247 // Assume the 1st instr to be a wildcard if it is unspecified.
248 if (FirstMI == nullptr)
249 return true;
250
251 switch (FirstMI->getOpcode()) {
252 case AArch64::ADR:
253 return SecondMI.getOperand(2).getImm() == 0;
254 case AArch64::ADRP:
255 return true;
256 }
257 }
258
259 return false;
260}
261
262/// Compare and conditional select.
263static bool isCmpCSelPair(const MachineInstr *FirstMI,
264 const MachineInstr &SecondMI) {
265 // 32 bits
266 if (SecondMI.getOpcode() == AArch64::CSELWr) {
267 // Assume the 1st instr to be a wildcard if it is unspecified.
268 if (FirstMI == nullptr)
269 return true;
270
271 if (FirstMI->definesRegister(AArch64::WZR, /*TRI=*/nullptr))
272 switch (FirstMI->getOpcode()) {
273 case AArch64::SUBSWrs:
274 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
275 case AArch64::SUBSWrx:
276 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
277 case AArch64::SUBSWrr:
278 case AArch64::SUBSWri:
279 return true;
280 }
281 }
282
283 // 64 bits
284 if (SecondMI.getOpcode() == AArch64::CSELXr) {
285 // Assume the 1st instr to be a wildcard if it is unspecified.
286 if (FirstMI == nullptr)
287 return true;
288
289 if (FirstMI->definesRegister(AArch64::XZR, /*TRI=*/nullptr))
290 switch (FirstMI->getOpcode()) {
291 case AArch64::SUBSXrs:
292 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
293 case AArch64::SUBSXrx:
294 case AArch64::SUBSXrx64:
295 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
296 case AArch64::SUBSXrr:
297 case AArch64::SUBSXri:
298 return true;
299 }
300 }
301
302 return false;
303}
304
305/// Floating-point compare and floating-point conditional select.
306static bool isFCmpFCSelPair(const MachineInstr *FirstMI,
307 const MachineInstr &SecondMI) {
308 switch (SecondMI.getOpcode()) {
309 case AArch64::FCSELSrrr:
310 case AArch64::FCSELDrrr:
311 case AArch64::FCSELHrrr:
312 break;
313 default:
314 return false;
315 }
316
317 // Assume the 1st instr to be a wildcard if it is unspecified.
318 if (FirstMI == nullptr)
319 return true;
320
321 switch (FirstMI->getOpcode()) {
322 case AArch64::FCMPSrr:
323 case AArch64::FCMPDrr:
324 case AArch64::FCMPESrr:
325 case AArch64::FCMPEDrr:
326 case AArch64::FCMPHrr:
327 case AArch64::FCMPEHrr:
328 return true;
329 default:
330 return false;
331 }
332}
333
334/// Compare and cset.
335static bool isCmpCSetPair(const MachineInstr *FirstMI,
336 const MachineInstr &SecondMI) {
337 if ((SecondMI.getOpcode() == AArch64::CSINCWr &&
338 SecondMI.getOperand(1).getReg() == AArch64::WZR &&
339 SecondMI.getOperand(2).getReg() == AArch64::WZR) ||
340 (SecondMI.getOpcode() == AArch64::CSINCXr &&
341 SecondMI.getOperand(1).getReg() == AArch64::XZR &&
342 SecondMI.getOperand(2).getReg() == AArch64::XZR)) {
343 // Assume the 1st instr to be a wildcard if it is unspecified.
344 if (FirstMI == nullptr)
345 return true;
346
347 if (FirstMI->definesRegister(AArch64::WZR, /*TRI=*/nullptr) ||
348 FirstMI->definesRegister(AArch64::XZR, /*TRI=*/nullptr))
349 switch (FirstMI->getOpcode()) {
350 case AArch64::SUBSWrs:
351 case AArch64::SUBSXrs:
352 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
353 case AArch64::SUBSWrx:
354 case AArch64::SUBSXrx:
355 case AArch64::SUBSXrx64:
356 return !AArch64InstrInfo::hasExtendedReg(*FirstMI);
357 case AArch64::SUBSWri:
358 case AArch64::SUBSWrr:
359 case AArch64::SUBSXri:
360 case AArch64::SUBSXrr:
361 return true;
362 }
363 }
364
365 return false;
366}
367
368// Arithmetic and logic.
369static bool isArithmeticLogicPair(const MachineInstr *FirstMI,
370 const MachineInstr &SecondMI) {
371 if (AArch64InstrInfo::hasShiftedReg(SecondMI))
372 return false;
373
374 switch (SecondMI.getOpcode()) {
375 // Arithmetic
376 case AArch64::ADDWrr:
377 case AArch64::ADDXrr:
378 case AArch64::SUBWrr:
379 case AArch64::SUBXrr:
380 case AArch64::ADDWrs:
381 case AArch64::ADDXrs:
382 case AArch64::SUBWrs:
383 case AArch64::SUBXrs:
384 // Logic
385 case AArch64::ANDWrr:
386 case AArch64::ANDXrr:
387 case AArch64::BICWrr:
388 case AArch64::BICXrr:
389 case AArch64::EONWrr:
390 case AArch64::EONXrr:
391 case AArch64::EORWrr:
392 case AArch64::EORXrr:
393 case AArch64::ORNWrr:
394 case AArch64::ORNXrr:
395 case AArch64::ORRWrr:
396 case AArch64::ORRXrr:
397 case AArch64::ANDWrs:
398 case AArch64::ANDXrs:
399 case AArch64::BICWrs:
400 case AArch64::BICXrs:
401 case AArch64::EONWrs:
402 case AArch64::EONXrs:
403 case AArch64::EORWrs:
404 case AArch64::EORXrs:
405 case AArch64::ORNWrs:
406 case AArch64::ORNXrs:
407 case AArch64::ORRWrs:
408 case AArch64::ORRXrs:
409 // Assume the 1st instr to be a wildcard if it is unspecified.
410 if (FirstMI == nullptr)
411 return true;
412
413 // Arithmetic
414 switch (FirstMI->getOpcode()) {
415 case AArch64::ADDWrr:
416 case AArch64::ADDXrr:
417 case AArch64::ADDSWrr:
418 case AArch64::ADDSXrr:
419 case AArch64::SUBWrr:
420 case AArch64::SUBXrr:
421 case AArch64::SUBSWrr:
422 case AArch64::SUBSXrr:
423 return true;
424 case AArch64::ADDWrs:
425 case AArch64::ADDXrs:
426 case AArch64::ADDSWrs:
427 case AArch64::ADDSXrs:
428 case AArch64::SUBWrs:
429 case AArch64::SUBXrs:
430 case AArch64::SUBSWrs:
431 case AArch64::SUBSXrs:
432 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
433 }
434 break;
435
436 // Arithmetic, setting flags.
437 case AArch64::ADDSWrr:
438 case AArch64::ADDSXrr:
439 case AArch64::SUBSWrr:
440 case AArch64::SUBSXrr:
441 case AArch64::ADDSWrs:
442 case AArch64::ADDSXrs:
443 case AArch64::SUBSWrs:
444 case AArch64::SUBSXrs:
445 // Assume the 1st instr to be a wildcard if it is unspecified.
446 if (FirstMI == nullptr)
447 return true;
448
449 // Arithmetic, not setting flags.
450 switch (FirstMI->getOpcode()) {
451 case AArch64::ADDWrr:
452 case AArch64::ADDXrr:
453 case AArch64::SUBWrr:
454 case AArch64::SUBXrr:
455 return true;
456 case AArch64::ADDWrs:
457 case AArch64::ADDXrs:
458 case AArch64::SUBWrs:
459 case AArch64::SUBXrs:
460 return !AArch64InstrInfo::hasShiftedReg(*FirstMI);
461 }
462 break;
463 }
464
465 return false;
466}
467
468// "(A + B) + 1" or "(A - B) - 1"
469static bool isAddSub2RegAndConstOnePair(const MachineInstr *FirstMI,
470 const MachineInstr &SecondMI) {
471 bool NeedsSubtract = false;
472
473 // The 2nd instr must be an add-immediate or subtract-immediate.
474 switch (SecondMI.getOpcode()) {
475 case AArch64::SUBWri:
476 case AArch64::SUBXri:
477 NeedsSubtract = true;
478 [[fallthrough]];
479 case AArch64::ADDWri:
480 case AArch64::ADDXri:
481 break;
482
483 default:
484 return false;
485 }
486
487 // The immediate in the 2nd instr must be "1".
488 if (!SecondMI.getOperand(2).isImm() || SecondMI.getOperand(2).getImm() != 1) {
489 return false;
490 }
491
492 // Assume the 1st instr to be a wildcard if it is unspecified.
493 if (FirstMI == nullptr) {
494 return true;
495 }
496
497 switch (FirstMI->getOpcode()) {
498 case AArch64::SUBWrs:
499 case AArch64::SUBXrs:
500 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
501 return false;
502 [[fallthrough]];
503 case AArch64::SUBWrr:
504 case AArch64::SUBXrr:
505 if (NeedsSubtract) {
506 return true;
507 }
508 break;
509
510 case AArch64::ADDWrs:
511 case AArch64::ADDXrs:
512 if (AArch64InstrInfo::hasShiftedReg(*FirstMI))
513 return false;
514 [[fallthrough]];
515 case AArch64::ADDWrr:
516 case AArch64::ADDXrr:
517 if (!NeedsSubtract) {
518 return true;
519 }
520 break;
521 }
522
523 return false;
524}
525
526/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
527/// together. Given SecondMI, when FirstMI is unspecified, then check if
528/// SecondMI may be part of a fused pair at all.
530 const TargetSubtargetInfo &TSI,
531 const MachineInstr *FirstMI,
532 const MachineInstr &SecondMI) {
533 const AArch64Subtarget &ST = static_cast<const AArch64Subtarget&>(TSI);
534
535 // All checking functions assume that the 1st instr is a wildcard if it is
536 // unspecified.
537 if (ST.hasCmpBccFusion() || ST.hasArithmeticBccFusion()) {
538 bool CmpOnly = !ST.hasArithmeticBccFusion();
539 if (isArithmeticBccPair(FirstMI, SecondMI, CmpOnly))
540 return true;
541 }
542 if (ST.hasArithmeticCbzFusion() && isArithmeticCbzPair(FirstMI, SecondMI))
543 return true;
544 if (ST.hasFuseAES() && isAESPair(FirstMI, SecondMI))
545 return true;
546 if (ST.hasFuseCryptoEOR() && isCryptoEORPair(FirstMI, SecondMI))
547 return true;
548 if (ST.hasFuseAdrpAdd() && isAdrpAddPair(FirstMI, SecondMI))
549 return true;
550 if (ST.hasFuseLiterals() && isLiteralsPair(FirstMI, SecondMI))
551 return true;
552 if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI))
553 return true;
554 if (ST.hasFuseCmpCSel() && isCmpCSelPair(FirstMI, SecondMI))
555 return true;
556 if (ST.hasFuseFCmpFCSel() && isFCmpFCSelPair(FirstMI, SecondMI))
557 return true;
558 if (ST.hasFuseCmpCSet() && isCmpCSetPair(FirstMI, SecondMI))
559 return true;
560 if (ST.hasFuseArithmeticLogic() && isArithmeticLogicPair(FirstMI, SecondMI))
561 return true;
562 if (ST.hasFuseAddSub2RegAndConstOne() &&
563 isAddSub2RegAndConstOnePair(FirstMI, SecondMI))
564 return true;
565
566 return false;
567}
568
569std::unique_ptr<ScheduleDAGMutation>
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 isArithmeticCbzPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
ALU operations followed by CBZ/CBNZ.
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Check if the instr pair, FirstMI and SecondMI, should be fused together.
static bool isAESPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
AES crypto encoding or decoding.
static bool isCmpCSetPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Compare and cset.
static bool isAdrpAddPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool mayHaveWAWDependency(const MachineInstr &FirstMI, const MachineInstr &SecondMI)
static bool isArithmeticLogicPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
static bool isCryptoEORPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
AESE/AESD/PMULL + EOR.
static bool isLiteralsPair(const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Literal generation.
const HexagonInstrInfo * TII
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
TargetInstrInfo - Interface to description of machine instruction set.
TargetSubtargetInfo - Generic base class for all target subtargets.
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...
std::unique_ptr< ScheduleDAGMutation > createAArch64MacroFusionDAGMutation()
Note that you have to add: DAG.addMutation(createAArch64MacroFusionDAGMutation()); to AArch64TargetMa...
static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, const MachineInstr &SecondMI)
Check if the instr pair, FirstMI and SecondMI, should be fused together.