Path: blob/main/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64A53Fix835769.cpp
35269 views
//===-- AArch64A53Fix835769.cpp -------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7// This pass changes code to work around Cortex-A53 erratum 835769.8// It works around it by inserting a nop instruction in code sequences that9// in some circumstances may trigger the erratum.10// It inserts a nop instruction between a sequence of the following 2 classes11// of instructions:12// instr 1: mem-instr (including loads, stores and prefetches).13// instr 2: non-SIMD integer multiply-accumulate writing 64-bit X registers.14//===----------------------------------------------------------------------===//1516#include "AArch64.h"17#include "AArch64Subtarget.h"18#include "llvm/ADT/Statistic.h"19#include "llvm/CodeGen/MachineFunction.h"20#include "llvm/CodeGen/MachineFunctionPass.h"21#include "llvm/CodeGen/MachineInstr.h"22#include "llvm/CodeGen/MachineInstrBuilder.h"23#include "llvm/CodeGen/MachineRegisterInfo.h"24#include "llvm/CodeGen/TargetInstrInfo.h"25#include "llvm/Support/Debug.h"26#include "llvm/Support/raw_ostream.h"2728using namespace llvm;2930#define DEBUG_TYPE "aarch64-fix-cortex-a53-835769"3132STATISTIC(NumNopsAdded, "Number of Nops added to work around erratum 835769");3334//===----------------------------------------------------------------------===//35// Helper functions3637// Is the instruction a match for the instruction that comes first in the38// sequence of instructions that can trigger the erratum?39static bool isFirstInstructionInSequence(MachineInstr *MI) {40// Must return true if this instruction is a load, a store or a prefetch.41switch (MI->getOpcode()) {42case AArch64::PRFMl:43case AArch64::PRFMroW:44case AArch64::PRFMroX:45case AArch64::PRFMui:46case AArch64::PRFUMi:47return true;48default:49return MI->mayLoadOrStore();50}51}5253// Is the instruction a match for the instruction that comes second in the54// sequence that can trigger the erratum?55static bool isSecondInstructionInSequence(MachineInstr *MI) {56// Must return true for non-SIMD integer multiply-accumulates, writing57// to a 64-bit register.58switch (MI->getOpcode()) {59// Erratum cannot be triggered when the destination register is 32 bits,60// therefore only include the following.61case AArch64::MSUBXrrr:62case AArch64::MADDXrrr:63case AArch64::SMADDLrrr:64case AArch64::SMSUBLrrr:65case AArch64::UMADDLrrr:66case AArch64::UMSUBLrrr:67// Erratum can only be triggered by multiply-adds, not by regular68// non-accumulating multiplies, i.e. when Ra=XZR='11111'69return MI->getOperand(3).getReg() != AArch64::XZR;70default:71return false;72}73}747576//===----------------------------------------------------------------------===//7778namespace {79class AArch64A53Fix835769 : public MachineFunctionPass {80const TargetInstrInfo *TII;8182public:83static char ID;84explicit AArch64A53Fix835769() : MachineFunctionPass(ID) {85initializeAArch64A53Fix835769Pass(*PassRegistry::getPassRegistry());86}8788bool runOnMachineFunction(MachineFunction &F) override;8990MachineFunctionProperties getRequiredProperties() const override {91return MachineFunctionProperties().set(92MachineFunctionProperties::Property::NoVRegs);93}9495StringRef getPassName() const override {96return "Workaround A53 erratum 835769 pass";97}9899void getAnalysisUsage(AnalysisUsage &AU) const override {100AU.setPreservesCFG();101MachineFunctionPass::getAnalysisUsage(AU);102}103104private:105bool runOnBasicBlock(MachineBasicBlock &MBB);106};107char AArch64A53Fix835769::ID = 0;108109} // end anonymous namespace110111INITIALIZE_PASS(AArch64A53Fix835769, "aarch64-fix-cortex-a53-835769-pass",112"AArch64 fix for A53 erratum 835769", false, false)113114//===----------------------------------------------------------------------===//115116bool117AArch64A53Fix835769::runOnMachineFunction(MachineFunction &F) {118LLVM_DEBUG(dbgs() << "***** AArch64A53Fix835769 *****\n");119auto &STI = F.getSubtarget<AArch64Subtarget>();120// Fix not requested, skip pass.121if (!STI.fixCortexA53_835769())122return false;123124bool Changed = false;125TII = STI.getInstrInfo();126127for (auto &MBB : F) {128Changed |= runOnBasicBlock(MBB);129}130return Changed;131}132133// Return the block that was fallen through to get to MBB, if any,134// otherwise nullptr.135static MachineBasicBlock *getBBFallenThrough(MachineBasicBlock *MBB,136const TargetInstrInfo *TII) {137// Get the previous machine basic block in the function.138MachineFunction::iterator MBBI(MBB);139140// Can't go off top of function.141if (MBBI == MBB->getParent()->begin())142return nullptr;143144MachineBasicBlock *TBB = nullptr, *FBB = nullptr;145SmallVector<MachineOperand, 2> Cond;146147MachineBasicBlock *PrevBB = &*std::prev(MBBI);148for (MachineBasicBlock *S : MBB->predecessors())149if (S == PrevBB && !TII->analyzeBranch(*PrevBB, TBB, FBB, Cond) && !TBB &&150!FBB)151return S;152153return nullptr;154}155156// Iterate through fallen through blocks trying to find a previous non-pseudo if157// there is one, otherwise return nullptr. Only look for instructions in158// previous blocks, not the current block, since we only use this to look at159// previous blocks.160static MachineInstr *getLastNonPseudo(MachineBasicBlock &MBB,161const TargetInstrInfo *TII) {162MachineBasicBlock *FMBB = &MBB;163164// If there is no non-pseudo in the current block, loop back around and try165// the previous block (if there is one).166while ((FMBB = getBBFallenThrough(FMBB, TII))) {167for (MachineInstr &I : llvm::reverse(*FMBB))168if (!I.isPseudo())169return &I;170}171172// There was no previous non-pseudo in the fallen through blocks173return nullptr;174}175176static void insertNopBeforeInstruction(MachineBasicBlock &MBB, MachineInstr* MI,177const TargetInstrInfo *TII) {178// If we are the first instruction of the block, put the NOP at the end of179// the previous fallthrough block180if (MI == &MBB.front()) {181MachineInstr *I = getLastNonPseudo(MBB, TII);182assert(I && "Expected instruction");183DebugLoc DL = I->getDebugLoc();184BuildMI(I->getParent(), DL, TII->get(AArch64::HINT)).addImm(0);185}186else {187DebugLoc DL = MI->getDebugLoc();188BuildMI(MBB, MI, DL, TII->get(AArch64::HINT)).addImm(0);189}190191++NumNopsAdded;192}193194bool195AArch64A53Fix835769::runOnBasicBlock(MachineBasicBlock &MBB) {196bool Changed = false;197LLVM_DEBUG(dbgs() << "Running on MBB: " << MBB198<< " - scanning instructions...\n");199200// First, scan the basic block, looking for a sequence of 2 instructions201// that match the conditions under which the erratum may trigger.202203// List of terminating instructions in matching sequences204std::vector<MachineInstr*> Sequences;205unsigned Idx = 0;206MachineInstr *PrevInstr = nullptr;207208// Try and find the last non-pseudo instruction in any fallen through blocks,209// if there isn't one, then we use nullptr to represent that.210PrevInstr = getLastNonPseudo(MBB, TII);211212for (auto &MI : MBB) {213MachineInstr *CurrInstr = &MI;214LLVM_DEBUG(dbgs() << " Examining: " << MI);215if (PrevInstr) {216LLVM_DEBUG(dbgs() << " PrevInstr: " << *PrevInstr217<< " CurrInstr: " << *CurrInstr218<< " isFirstInstructionInSequence(PrevInstr): "219<< isFirstInstructionInSequence(PrevInstr) << "\n"220<< " isSecondInstructionInSequence(CurrInstr): "221<< isSecondInstructionInSequence(CurrInstr) << "\n");222if (isFirstInstructionInSequence(PrevInstr) &&223isSecondInstructionInSequence(CurrInstr)) {224LLVM_DEBUG(dbgs() << " ** pattern found at Idx " << Idx << "!\n");225(void) Idx;226Sequences.push_back(CurrInstr);227}228}229if (!CurrInstr->isPseudo())230PrevInstr = CurrInstr;231++Idx;232}233234LLVM_DEBUG(dbgs() << "Scan complete, " << Sequences.size()235<< " occurrences of pattern found.\n");236237// Then update the basic block, inserting nops between the detected sequences.238for (auto &MI : Sequences) {239Changed = true;240insertNopBeforeInstruction(MBB, MI, TII);241}242243return Changed;244}245246// Factory function used by AArch64TargetMachine to add the pass to247// the passmanager.248FunctionPass *llvm::createAArch64A53Fix835769() {249return new AArch64A53Fix835769();250}251252253