xref: /aosp_15_r20/external/llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- AArch64A53Fix835769.cpp -------------------------------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker // This pass changes code to work around Cortex-A53 erratum 835769.
10*9880d681SAndroid Build Coastguard Worker // It works around it by inserting a nop instruction in code sequences that
11*9880d681SAndroid Build Coastguard Worker // in some circumstances may trigger the erratum.
12*9880d681SAndroid Build Coastguard Worker // It inserts a nop instruction between a sequence of the following 2 classes
13*9880d681SAndroid Build Coastguard Worker // of instructions:
14*9880d681SAndroid Build Coastguard Worker // instr 1: mem-instr (including loads, stores and prefetches).
15*9880d681SAndroid Build Coastguard Worker // instr 2: non-SIMD integer multiply-accumulate writing 64-bit X registers.
16*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
17*9880d681SAndroid Build Coastguard Worker 
18*9880d681SAndroid Build Coastguard Worker #include "AArch64.h"
19*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/Statistic.h"
20*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineFunction.h"
21*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineFunctionPass.h"
22*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineInstr.h"
23*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineInstrBuilder.h"
24*9880d681SAndroid Build Coastguard Worker #include "llvm/CodeGen/MachineRegisterInfo.h"
25*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Debug.h"
26*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h"
27*9880d681SAndroid Build Coastguard Worker #include "llvm/Target/TargetInstrInfo.h"
28*9880d681SAndroid Build Coastguard Worker 
29*9880d681SAndroid Build Coastguard Worker using namespace llvm;
30*9880d681SAndroid Build Coastguard Worker 
31*9880d681SAndroid Build Coastguard Worker #define DEBUG_TYPE "aarch64-fix-cortex-a53-835769"
32*9880d681SAndroid Build Coastguard Worker 
33*9880d681SAndroid Build Coastguard Worker STATISTIC(NumNopsAdded, "Number of Nops added to work around erratum 835769");
34*9880d681SAndroid Build Coastguard Worker 
35*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
36*9880d681SAndroid Build Coastguard Worker // Helper functions
37*9880d681SAndroid Build Coastguard Worker 
38*9880d681SAndroid Build Coastguard Worker // Is the instruction a match for the instruction that comes first in the
39*9880d681SAndroid Build Coastguard Worker // sequence of instructions that can trigger the erratum?
isFirstInstructionInSequence(MachineInstr * MI)40*9880d681SAndroid Build Coastguard Worker static bool isFirstInstructionInSequence(MachineInstr *MI) {
41*9880d681SAndroid Build Coastguard Worker   // Must return true if this instruction is a load, a store or a prefetch.
42*9880d681SAndroid Build Coastguard Worker   switch (MI->getOpcode()) {
43*9880d681SAndroid Build Coastguard Worker   case AArch64::PRFMl:
44*9880d681SAndroid Build Coastguard Worker   case AArch64::PRFMroW:
45*9880d681SAndroid Build Coastguard Worker   case AArch64::PRFMroX:
46*9880d681SAndroid Build Coastguard Worker   case AArch64::PRFMui:
47*9880d681SAndroid Build Coastguard Worker   case AArch64::PRFUMi:
48*9880d681SAndroid Build Coastguard Worker     return true;
49*9880d681SAndroid Build Coastguard Worker   default:
50*9880d681SAndroid Build Coastguard Worker     return MI->mayLoadOrStore();
51*9880d681SAndroid Build Coastguard Worker   }
52*9880d681SAndroid Build Coastguard Worker }
53*9880d681SAndroid Build Coastguard Worker 
54*9880d681SAndroid Build Coastguard Worker // Is the instruction a match for the instruction that comes second in the
55*9880d681SAndroid Build Coastguard Worker // sequence that can trigger the erratum?
isSecondInstructionInSequence(MachineInstr * MI)56*9880d681SAndroid Build Coastguard Worker static bool isSecondInstructionInSequence(MachineInstr *MI) {
57*9880d681SAndroid Build Coastguard Worker   // Must return true for non-SIMD integer multiply-accumulates, writing
58*9880d681SAndroid Build Coastguard Worker   // to a 64-bit register.
59*9880d681SAndroid Build Coastguard Worker   switch (MI->getOpcode()) {
60*9880d681SAndroid Build Coastguard Worker   // Erratum cannot be triggered when the destination register is 32 bits,
61*9880d681SAndroid Build Coastguard Worker   // therefore only include the following.
62*9880d681SAndroid Build Coastguard Worker   case AArch64::MSUBXrrr:
63*9880d681SAndroid Build Coastguard Worker   case AArch64::MADDXrrr:
64*9880d681SAndroid Build Coastguard Worker   case AArch64::SMADDLrrr:
65*9880d681SAndroid Build Coastguard Worker   case AArch64::SMSUBLrrr:
66*9880d681SAndroid Build Coastguard Worker   case AArch64::UMADDLrrr:
67*9880d681SAndroid Build Coastguard Worker   case AArch64::UMSUBLrrr:
68*9880d681SAndroid Build Coastguard Worker     // Erratum can only be triggered by multiply-adds, not by regular
69*9880d681SAndroid Build Coastguard Worker     // non-accumulating multiplies, i.e. when Ra=XZR='11111'
70*9880d681SAndroid Build Coastguard Worker     return MI->getOperand(3).getReg() != AArch64::XZR;
71*9880d681SAndroid Build Coastguard Worker   default:
72*9880d681SAndroid Build Coastguard Worker     return false;
73*9880d681SAndroid Build Coastguard Worker   }
74*9880d681SAndroid Build Coastguard Worker }
75*9880d681SAndroid Build Coastguard Worker 
76*9880d681SAndroid Build Coastguard Worker 
77*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
78*9880d681SAndroid Build Coastguard Worker 
79*9880d681SAndroid Build Coastguard Worker namespace {
80*9880d681SAndroid Build Coastguard Worker class AArch64A53Fix835769 : public MachineFunctionPass {
81*9880d681SAndroid Build Coastguard Worker   const TargetInstrInfo *TII;
82*9880d681SAndroid Build Coastguard Worker 
83*9880d681SAndroid Build Coastguard Worker public:
84*9880d681SAndroid Build Coastguard Worker   static char ID;
AArch64A53Fix835769()85*9880d681SAndroid Build Coastguard Worker   explicit AArch64A53Fix835769() : MachineFunctionPass(ID) {}
86*9880d681SAndroid Build Coastguard Worker 
87*9880d681SAndroid Build Coastguard Worker   bool runOnMachineFunction(MachineFunction &F) override;
88*9880d681SAndroid Build Coastguard Worker 
getRequiredProperties() const89*9880d681SAndroid Build Coastguard Worker   MachineFunctionProperties getRequiredProperties() const override {
90*9880d681SAndroid Build Coastguard Worker     return MachineFunctionProperties().set(
91*9880d681SAndroid Build Coastguard Worker         MachineFunctionProperties::Property::AllVRegsAllocated);
92*9880d681SAndroid Build Coastguard Worker   }
93*9880d681SAndroid Build Coastguard Worker 
getPassName() const94*9880d681SAndroid Build Coastguard Worker   const char *getPassName() const override {
95*9880d681SAndroid Build Coastguard Worker     return "Workaround A53 erratum 835769 pass";
96*9880d681SAndroid Build Coastguard Worker   }
97*9880d681SAndroid Build Coastguard Worker 
getAnalysisUsage(AnalysisUsage & AU) const98*9880d681SAndroid Build Coastguard Worker   void getAnalysisUsage(AnalysisUsage &AU) const override {
99*9880d681SAndroid Build Coastguard Worker     AU.setPreservesCFG();
100*9880d681SAndroid Build Coastguard Worker     MachineFunctionPass::getAnalysisUsage(AU);
101*9880d681SAndroid Build Coastguard Worker   }
102*9880d681SAndroid Build Coastguard Worker 
103*9880d681SAndroid Build Coastguard Worker private:
104*9880d681SAndroid Build Coastguard Worker   bool runOnBasicBlock(MachineBasicBlock &MBB);
105*9880d681SAndroid Build Coastguard Worker };
106*9880d681SAndroid Build Coastguard Worker char AArch64A53Fix835769::ID = 0;
107*9880d681SAndroid Build Coastguard Worker 
108*9880d681SAndroid Build Coastguard Worker } // end anonymous namespace
109*9880d681SAndroid Build Coastguard Worker 
110*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
111*9880d681SAndroid Build Coastguard Worker 
112*9880d681SAndroid Build Coastguard Worker bool
runOnMachineFunction(MachineFunction & F)113*9880d681SAndroid Build Coastguard Worker AArch64A53Fix835769::runOnMachineFunction(MachineFunction &F) {
114*9880d681SAndroid Build Coastguard Worker   DEBUG(dbgs() << "***** AArch64A53Fix835769 *****\n");
115*9880d681SAndroid Build Coastguard Worker   bool Changed = false;
116*9880d681SAndroid Build Coastguard Worker   TII = F.getSubtarget().getInstrInfo();
117*9880d681SAndroid Build Coastguard Worker 
118*9880d681SAndroid Build Coastguard Worker   for (auto &MBB : F) {
119*9880d681SAndroid Build Coastguard Worker     Changed |= runOnBasicBlock(MBB);
120*9880d681SAndroid Build Coastguard Worker   }
121*9880d681SAndroid Build Coastguard Worker   return Changed;
122*9880d681SAndroid Build Coastguard Worker }
123*9880d681SAndroid Build Coastguard Worker 
124*9880d681SAndroid Build Coastguard Worker // Return the block that was fallen through to get to MBB, if any,
125*9880d681SAndroid Build Coastguard Worker // otherwise nullptr.
getBBFallenThrough(MachineBasicBlock * MBB,const TargetInstrInfo * TII)126*9880d681SAndroid Build Coastguard Worker static MachineBasicBlock *getBBFallenThrough(MachineBasicBlock *MBB,
127*9880d681SAndroid Build Coastguard Worker                                              const TargetInstrInfo *TII) {
128*9880d681SAndroid Build Coastguard Worker   // Get the previous machine basic block in the function.
129*9880d681SAndroid Build Coastguard Worker   MachineFunction::iterator MBBI(MBB);
130*9880d681SAndroid Build Coastguard Worker 
131*9880d681SAndroid Build Coastguard Worker   // Can't go off top of function.
132*9880d681SAndroid Build Coastguard Worker   if (MBBI == MBB->getParent()->begin())
133*9880d681SAndroid Build Coastguard Worker     return nullptr;
134*9880d681SAndroid Build Coastguard Worker 
135*9880d681SAndroid Build Coastguard Worker   MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
136*9880d681SAndroid Build Coastguard Worker   SmallVector<MachineOperand, 2> Cond;
137*9880d681SAndroid Build Coastguard Worker 
138*9880d681SAndroid Build Coastguard Worker   MachineBasicBlock *PrevBB = &*std::prev(MBBI);
139*9880d681SAndroid Build Coastguard Worker   for (MachineBasicBlock *S : MBB->predecessors())
140*9880d681SAndroid Build Coastguard Worker     if (S == PrevBB && !TII->analyzeBranch(*PrevBB, TBB, FBB, Cond) && !TBB &&
141*9880d681SAndroid Build Coastguard Worker         !FBB)
142*9880d681SAndroid Build Coastguard Worker       return S;
143*9880d681SAndroid Build Coastguard Worker 
144*9880d681SAndroid Build Coastguard Worker   return nullptr;
145*9880d681SAndroid Build Coastguard Worker }
146*9880d681SAndroid Build Coastguard Worker 
147*9880d681SAndroid Build Coastguard Worker // Iterate through fallen through blocks trying to find a previous non-pseudo if
148*9880d681SAndroid Build Coastguard Worker // there is one, otherwise return nullptr. Only look for instructions in
149*9880d681SAndroid Build Coastguard Worker // previous blocks, not the current block, since we only use this to look at
150*9880d681SAndroid Build Coastguard Worker // previous blocks.
getLastNonPseudo(MachineBasicBlock & MBB,const TargetInstrInfo * TII)151*9880d681SAndroid Build Coastguard Worker static MachineInstr *getLastNonPseudo(MachineBasicBlock &MBB,
152*9880d681SAndroid Build Coastguard Worker                                       const TargetInstrInfo *TII) {
153*9880d681SAndroid Build Coastguard Worker   MachineBasicBlock *FMBB = &MBB;
154*9880d681SAndroid Build Coastguard Worker 
155*9880d681SAndroid Build Coastguard Worker   // If there is no non-pseudo in the current block, loop back around and try
156*9880d681SAndroid Build Coastguard Worker   // the previous block (if there is one).
157*9880d681SAndroid Build Coastguard Worker   while ((FMBB = getBBFallenThrough(FMBB, TII))) {
158*9880d681SAndroid Build Coastguard Worker     for (MachineInstr &I : make_range(FMBB->rbegin(), FMBB->rend()))
159*9880d681SAndroid Build Coastguard Worker       if (!I.isPseudo())
160*9880d681SAndroid Build Coastguard Worker         return &I;
161*9880d681SAndroid Build Coastguard Worker   }
162*9880d681SAndroid Build Coastguard Worker 
163*9880d681SAndroid Build Coastguard Worker   // There was no previous non-pseudo in the fallen through blocks
164*9880d681SAndroid Build Coastguard Worker   return nullptr;
165*9880d681SAndroid Build Coastguard Worker }
166*9880d681SAndroid Build Coastguard Worker 
insertNopBeforeInstruction(MachineBasicBlock & MBB,MachineInstr * MI,const TargetInstrInfo * TII)167*9880d681SAndroid Build Coastguard Worker static void insertNopBeforeInstruction(MachineBasicBlock &MBB, MachineInstr* MI,
168*9880d681SAndroid Build Coastguard Worker                                        const TargetInstrInfo *TII) {
169*9880d681SAndroid Build Coastguard Worker   // If we are the first instruction of the block, put the NOP at the end of
170*9880d681SAndroid Build Coastguard Worker   // the previous fallthrough block
171*9880d681SAndroid Build Coastguard Worker   if (MI == &MBB.front()) {
172*9880d681SAndroid Build Coastguard Worker     MachineInstr *I = getLastNonPseudo(MBB, TII);
173*9880d681SAndroid Build Coastguard Worker     assert(I && "Expected instruction");
174*9880d681SAndroid Build Coastguard Worker     DebugLoc DL = I->getDebugLoc();
175*9880d681SAndroid Build Coastguard Worker     BuildMI(I->getParent(), DL, TII->get(AArch64::HINT)).addImm(0);
176*9880d681SAndroid Build Coastguard Worker   }
177*9880d681SAndroid Build Coastguard Worker   else {
178*9880d681SAndroid Build Coastguard Worker     DebugLoc DL = MI->getDebugLoc();
179*9880d681SAndroid Build Coastguard Worker     BuildMI(MBB, MI, DL, TII->get(AArch64::HINT)).addImm(0);
180*9880d681SAndroid Build Coastguard Worker   }
181*9880d681SAndroid Build Coastguard Worker 
182*9880d681SAndroid Build Coastguard Worker   ++NumNopsAdded;
183*9880d681SAndroid Build Coastguard Worker }
184*9880d681SAndroid Build Coastguard Worker 
185*9880d681SAndroid Build Coastguard Worker bool
runOnBasicBlock(MachineBasicBlock & MBB)186*9880d681SAndroid Build Coastguard Worker AArch64A53Fix835769::runOnBasicBlock(MachineBasicBlock &MBB) {
187*9880d681SAndroid Build Coastguard Worker   bool Changed = false;
188*9880d681SAndroid Build Coastguard Worker   DEBUG(dbgs() << "Running on MBB: " << MBB << " - scanning instructions...\n");
189*9880d681SAndroid Build Coastguard Worker 
190*9880d681SAndroid Build Coastguard Worker   // First, scan the basic block, looking for a sequence of 2 instructions
191*9880d681SAndroid Build Coastguard Worker   // that match the conditions under which the erratum may trigger.
192*9880d681SAndroid Build Coastguard Worker 
193*9880d681SAndroid Build Coastguard Worker   // List of terminating instructions in matching sequences
194*9880d681SAndroid Build Coastguard Worker   std::vector<MachineInstr*> Sequences;
195*9880d681SAndroid Build Coastguard Worker   unsigned Idx = 0;
196*9880d681SAndroid Build Coastguard Worker   MachineInstr *PrevInstr = nullptr;
197*9880d681SAndroid Build Coastguard Worker 
198*9880d681SAndroid Build Coastguard Worker   // Try and find the last non-pseudo instruction in any fallen through blocks,
199*9880d681SAndroid Build Coastguard Worker   // if there isn't one, then we use nullptr to represent that.
200*9880d681SAndroid Build Coastguard Worker   PrevInstr = getLastNonPseudo(MBB, TII);
201*9880d681SAndroid Build Coastguard Worker 
202*9880d681SAndroid Build Coastguard Worker   for (auto &MI : MBB) {
203*9880d681SAndroid Build Coastguard Worker     MachineInstr *CurrInstr = &MI;
204*9880d681SAndroid Build Coastguard Worker     DEBUG(dbgs() << "  Examining: " << MI);
205*9880d681SAndroid Build Coastguard Worker     if (PrevInstr) {
206*9880d681SAndroid Build Coastguard Worker       DEBUG(dbgs() << "    PrevInstr: " << *PrevInstr
207*9880d681SAndroid Build Coastguard Worker                    << "    CurrInstr: " << *CurrInstr
208*9880d681SAndroid Build Coastguard Worker                    << "    isFirstInstructionInSequence(PrevInstr): "
209*9880d681SAndroid Build Coastguard Worker                    << isFirstInstructionInSequence(PrevInstr) << "\n"
210*9880d681SAndroid Build Coastguard Worker                    << "    isSecondInstructionInSequence(CurrInstr): "
211*9880d681SAndroid Build Coastguard Worker                    << isSecondInstructionInSequence(CurrInstr) << "\n");
212*9880d681SAndroid Build Coastguard Worker       if (isFirstInstructionInSequence(PrevInstr) &&
213*9880d681SAndroid Build Coastguard Worker           isSecondInstructionInSequence(CurrInstr)) {
214*9880d681SAndroid Build Coastguard Worker         DEBUG(dbgs() << "   ** pattern found at Idx " << Idx << "!\n");
215*9880d681SAndroid Build Coastguard Worker         Sequences.push_back(CurrInstr);
216*9880d681SAndroid Build Coastguard Worker       }
217*9880d681SAndroid Build Coastguard Worker     }
218*9880d681SAndroid Build Coastguard Worker     if (!CurrInstr->isPseudo())
219*9880d681SAndroid Build Coastguard Worker       PrevInstr = CurrInstr;
220*9880d681SAndroid Build Coastguard Worker     ++Idx;
221*9880d681SAndroid Build Coastguard Worker   }
222*9880d681SAndroid Build Coastguard Worker 
223*9880d681SAndroid Build Coastguard Worker   DEBUG(dbgs() << "Scan complete, " << Sequences.size()
224*9880d681SAndroid Build Coastguard Worker                << " occurrences of pattern found.\n");
225*9880d681SAndroid Build Coastguard Worker 
226*9880d681SAndroid Build Coastguard Worker   // Then update the basic block, inserting nops between the detected sequences.
227*9880d681SAndroid Build Coastguard Worker   for (auto &MI : Sequences) {
228*9880d681SAndroid Build Coastguard Worker     Changed = true;
229*9880d681SAndroid Build Coastguard Worker     insertNopBeforeInstruction(MBB, MI, TII);
230*9880d681SAndroid Build Coastguard Worker   }
231*9880d681SAndroid Build Coastguard Worker 
232*9880d681SAndroid Build Coastguard Worker   return Changed;
233*9880d681SAndroid Build Coastguard Worker }
234*9880d681SAndroid Build Coastguard Worker 
235*9880d681SAndroid Build Coastguard Worker // Factory function used by AArch64TargetMachine to add the pass to
236*9880d681SAndroid Build Coastguard Worker // the passmanager.
createAArch64A53Fix835769()237*9880d681SAndroid Build Coastguard Worker FunctionPass *llvm::createAArch64A53Fix835769() {
238*9880d681SAndroid Build Coastguard Worker   return new AArch64A53Fix835769();
239*9880d681SAndroid Build Coastguard Worker }
240