1 //===- AArch64MachineScheduler.cpp - MI Scheduler for AArch64 -------------===//
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 #include "AArch64MachineScheduler.h"
10 #include "AArch64InstrInfo.h"
11 #include "AArch64Subtarget.h"
12 #include "MCTargetDesc/AArch64MCTargetDesc.h"
13 
14 using namespace llvm;
15 
16 static bool needReorderStoreMI(const MachineInstr *MI) {
17   if (!MI)
18     return false;
19 
20   switch (MI->getOpcode()) {
21   default:
22     return false;
23   case AArch64::STURQi:
24   case AArch64::STRQui:
25     if (!MI->getMF()->getSubtarget<AArch64Subtarget>().isStoreAddressAscend())
26       return false;
27     [[fallthrough]];
28   case AArch64::STPQi:
29     return AArch64InstrInfo::getLdStOffsetOp(*MI).isImm();
30   }
31 
32   return false;
33 }
34 
35 // Return true if two stores with same base address may overlap writes
36 static bool mayOverlapWrite(const MachineInstr &MI0, const MachineInstr &MI1,
37                             int64_t &Off0, int64_t &Off1) {
38   const MachineOperand &Base0 = AArch64InstrInfo::getLdStBaseOp(MI0);
39   const MachineOperand &Base1 = AArch64InstrInfo::getLdStBaseOp(MI1);
40 
41   // May overlapping writes if two store instructions without same base
42   if (!Base0.isIdenticalTo(Base1))
43     return true;
44 
45   int StoreSize0 = AArch64InstrInfo::getMemScale(MI0);
46   int StoreSize1 = AArch64InstrInfo::getMemScale(MI1);
47   Off0 = AArch64InstrInfo::hasUnscaledLdStOffset(MI0.getOpcode())
48              ? AArch64InstrInfo::getLdStOffsetOp(MI0).getImm()
49              : AArch64InstrInfo::getLdStOffsetOp(MI0).getImm() * StoreSize0;
50   Off1 = AArch64InstrInfo::hasUnscaledLdStOffset(MI1.getOpcode())
51              ? AArch64InstrInfo::getLdStOffsetOp(MI1).getImm()
52              : AArch64InstrInfo::getLdStOffsetOp(MI1).getImm() * StoreSize1;
53 
54   const MachineInstr &MI = (Off0 < Off1) ? MI0 : MI1;
55   int Multiples = AArch64InstrInfo::isPairedLdSt(MI) ? 2 : 1;
56   int StoreSize = AArch64InstrInfo::getMemScale(MI) * Multiples;
57 
58   return llabs(Off0 - Off1) < StoreSize;
59 }
60 
61 bool AArch64PostRASchedStrategy::tryCandidate(SchedCandidate &Cand,
62                                               SchedCandidate &TryCand) {
63   bool OriginalResult = PostGenericScheduler::tryCandidate(Cand, TryCand);
64 
65   if (Cand.isValid()) {
66     MachineInstr *Instr0 = TryCand.SU->getInstr();
67     MachineInstr *Instr1 = Cand.SU->getInstr();
68 
69     if (!needReorderStoreMI(Instr0) || !needReorderStoreMI(Instr1))
70       return OriginalResult;
71 
72     int64_t Off0, Off1;
73     // With the same base address and non-overlapping writes.
74     if (!mayOverlapWrite(*Instr0, *Instr1, Off0, Off1)) {
75       TryCand.Reason = NodeOrder;
76       // Order them by ascending offsets.
77       return Off0 < Off1;
78     }
79   }
80 
81   return OriginalResult;
82 }
83