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
14using namespace llvm;
15
16static 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: *MI).isImm();
30 }
31
32 return false;
33}
34
35// Return true if two stores with same base address may overlap writes
36static bool mayOverlapWrite(const MachineInstr &MI0, const MachineInstr &MI1,
37 int64_t &Off0, int64_t &Off1) {
38 const MachineOperand &Base0 = AArch64InstrInfo::getLdStBaseOp(MI: MI0);
39 const MachineOperand &Base1 = AArch64InstrInfo::getLdStBaseOp(MI: MI1);
40
41 // May overlapping writes if two store instructions without same base
42 if (!Base0.isIdenticalTo(Other: Base1))
43 return true;
44
45 int StoreSize0 = AArch64InstrInfo::getMemScale(MI: MI0);
46 int StoreSize1 = AArch64InstrInfo::getMemScale(MI: MI1);
47 Off0 = AArch64InstrInfo::hasUnscaledLdStOffset(Opc: MI0.getOpcode())
48 ? AArch64InstrInfo::getLdStOffsetOp(MI: MI0).getImm()
49 : AArch64InstrInfo::getLdStOffsetOp(MI: MI0).getImm() * StoreSize0;
50 Off1 = AArch64InstrInfo::hasUnscaledLdStOffset(Opc: MI1.getOpcode())
51 ? AArch64InstrInfo::getLdStOffsetOp(MI: MI1).getImm()
52 : AArch64InstrInfo::getLdStOffsetOp(MI: 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(x: Off0 - Off1) < StoreSize;
59}
60
61bool 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(MI: Instr0) || !needReorderStoreMI(MI: Instr1))
70 return OriginalResult;
71
72 int64_t Off0, Off1;
73 // With the same base address and non-overlapping writes.
74 if (!mayOverlapWrite(MI0: *Instr0, MI1: *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