Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARM/ARMHazardRecognizer.cpp
35266 views
//===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===//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//===----------------------------------------------------------------------===//78#include "ARMHazardRecognizer.h"9#include "ARMBaseInstrInfo.h"10#include "ARMBaseRegisterInfo.h"11#include "ARMSubtarget.h"12#include "llvm/Analysis/ValueTracking.h"13#include "llvm/CodeGen/MachineFrameInfo.h"14#include "llvm/CodeGen/MachineFunctionPass.h"15#include "llvm/CodeGen/MachineInstr.h"16#include "llvm/CodeGen/ScheduleDAG.h"17#include "llvm/CodeGen/TargetRegisterInfo.h"18#include "llvm/Support/CommandLine.h"1920using namespace llvm;2122static cl::opt<int> DataBankMask("arm-data-bank-mask", cl::init(-1),23cl::Hidden);24static cl::opt<bool> AssumeITCMConflict("arm-assume-itcm-bankconflict",25cl::init(false), cl::Hidden);2627static bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI,28const TargetRegisterInfo &TRI) {29// FIXME: Detect integer instructions properly.30const MCInstrDesc &MCID = MI->getDesc();31unsigned Domain = MCID.TSFlags & ARMII::DomainMask;32if (MI->mayStore())33return false;34unsigned Opcode = MCID.getOpcode();35if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD)36return false;37if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON))38return MI->readsRegister(DefMI->getOperand(0).getReg(), &TRI);39return false;40}4142ScheduleHazardRecognizer::HazardType43ARMHazardRecognizerFPMLx::getHazardType(SUnit *SU, int Stalls) {44assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead");4546MachineInstr *MI = SU->getInstr();4748if (!MI->isDebugInstr()) {49// Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following50// a VMLA / VMLS will cause 4 cycle stall.51const MCInstrDesc &MCID = MI->getDesc();52if (LastMI && (MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) {53MachineInstr *DefMI = LastMI;54const MCInstrDesc &LastMCID = LastMI->getDesc();55const MachineFunction *MF = MI->getParent()->getParent();56const ARMBaseInstrInfo &TII = *static_cast<const ARMBaseInstrInfo *>(57MF->getSubtarget().getInstrInfo());5859// Skip over one non-VFP / NEON instruction.60if (!LastMI->isBarrier() &&61!(TII.getSubtarget().hasMuxedUnits() && LastMI->mayLoadOrStore()) &&62(LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) {63MachineBasicBlock::iterator I = LastMI;64if (I != LastMI->getParent()->begin()) {65I = std::prev(I);66DefMI = &*I;67}68}6970if (TII.isFpMLxInstruction(DefMI->getOpcode()) &&71(TII.canCauseFpMLxStall(MI->getOpcode()) ||72hasRAWHazard(DefMI, MI, TII.getRegisterInfo()))) {73// Try to schedule another instruction for the next 4 cycles.74if (FpMLxStalls == 0)75FpMLxStalls = 4;76return Hazard;77}78}79}80return NoHazard;81}8283void ARMHazardRecognizerFPMLx::Reset() {84LastMI = nullptr;85FpMLxStalls = 0;86}8788void ARMHazardRecognizerFPMLx::EmitInstruction(SUnit *SU) {89MachineInstr *MI = SU->getInstr();90if (!MI->isDebugInstr()) {91LastMI = MI;92FpMLxStalls = 0;93}94}9596void ARMHazardRecognizerFPMLx::AdvanceCycle() {97if (FpMLxStalls && --FpMLxStalls == 0)98// Stalled for 4 cycles but still can't schedule any other instructions.99LastMI = nullptr;100}101102void ARMHazardRecognizerFPMLx::RecedeCycle() {103llvm_unreachable("reverse ARM hazard checking unsupported");104}105106///////// Bank conflicts handled as hazards //////////////107108static bool getBaseOffset(const MachineInstr &MI, const MachineOperand *&BaseOp,109int64_t &Offset) {110111uint64_t TSFlags = MI.getDesc().TSFlags;112unsigned AddrMode = (TSFlags & ARMII::AddrModeMask);113unsigned IndexMode =114(TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;115116// Address mode tells us what we want to know about operands for T2117// instructions (but not size). It tells us size (but not about operands)118// for T1 instructions.119switch (AddrMode) {120default:121return false;122case ARMII::AddrModeT2_i8:123// t2LDRBT, t2LDRB_POST, t2LDRB_PRE, t2LDRBi8,124// t2LDRHT, t2LDRH_POST, t2LDRH_PRE, t2LDRHi8,125// t2LDRSBT, t2LDRSB_POST, t2LDRSB_PRE, t2LDRSBi8,126// t2LDRSHT, t2LDRSH_POST, t2LDRSH_PRE, t2LDRSHi8,127// t2LDRT, t2LDR_POST, t2LDR_PRE, t2LDRi8128BaseOp = &MI.getOperand(1);129Offset = (IndexMode == ARMII::IndexModePost)130? 0131: (IndexMode == ARMII::IndexModePre ||132IndexMode == ARMII::IndexModeUpd)133? MI.getOperand(3).getImm()134: MI.getOperand(2).getImm();135return true;136case ARMII::AddrModeT2_i12:137// t2LDRBi12, t2LDRHi12138// t2LDRSBi12, t2LDRSHi12139// t2LDRi12140BaseOp = &MI.getOperand(1);141Offset = MI.getOperand(2).getImm();142return true;143case ARMII::AddrModeT2_i8s4:144// t2LDRD_POST, t2LDRD_PRE, t2LDRDi8145BaseOp = &MI.getOperand(2);146Offset = (IndexMode == ARMII::IndexModePost)147? 0148: (IndexMode == ARMII::IndexModePre ||149IndexMode == ARMII::IndexModeUpd)150? MI.getOperand(4).getImm()151: MI.getOperand(3).getImm();152return true;153case ARMII::AddrModeT1_1:154// tLDRBi, tLDRBr (watch out!), TLDRSB155case ARMII::AddrModeT1_2:156// tLDRHi, tLDRHr (watch out!), TLDRSH157case ARMII::AddrModeT1_4:158// tLDRi, tLDRr (watch out!)159BaseOp = &MI.getOperand(1);160Offset = MI.getOperand(2).isImm() ? MI.getOperand(2).getImm() : 0;161return MI.getOperand(2).isImm();162}163return false;164}165166ARMBankConflictHazardRecognizer::ARMBankConflictHazardRecognizer(167const ScheduleDAG *DAG, int64_t CPUBankMask, bool CPUAssumeITCMConflict)168: MF(DAG->MF), DL(DAG->MF.getDataLayout()),169DataMask(DataBankMask.getNumOccurrences() ? int64_t(DataBankMask)170: CPUBankMask),171AssumeITCMBankConflict(AssumeITCMConflict.getNumOccurrences()172? AssumeITCMConflict173: CPUAssumeITCMConflict) {174MaxLookAhead = 1;175}176177ScheduleHazardRecognizer::HazardType178ARMBankConflictHazardRecognizer::CheckOffsets(unsigned O0, unsigned O1) {179return (((O0 ^ O1) & DataMask) != 0) ? NoHazard : Hazard;180}181182ScheduleHazardRecognizer::HazardType183ARMBankConflictHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {184MachineInstr &L0 = *SU->getInstr();185if (!L0.mayLoad() || L0.mayStore() || L0.getNumMemOperands() != 1)186return NoHazard;187188auto MO0 = *L0.memoperands().begin();189auto BaseVal0 = MO0->getValue();190auto BasePseudoVal0 = MO0->getPseudoValue();191int64_t Offset0 = 0;192193if (!MO0->getSize().hasValue() || MO0->getSize().getValue() > 4)194return NoHazard;195196bool SPvalid = false;197const MachineOperand *SP = nullptr;198int64_t SPOffset0 = 0;199200for (auto L1 : Accesses) {201auto MO1 = *L1->memoperands().begin();202auto BaseVal1 = MO1->getValue();203auto BasePseudoVal1 = MO1->getPseudoValue();204int64_t Offset1 = 0;205206// Pointers to the same object207if (BaseVal0 && BaseVal1) {208const Value *Ptr0, *Ptr1;209Ptr0 = GetPointerBaseWithConstantOffset(BaseVal0, Offset0, DL, true);210Ptr1 = GetPointerBaseWithConstantOffset(BaseVal1, Offset1, DL, true);211if (Ptr0 == Ptr1 && Ptr0)212return CheckOffsets(Offset0, Offset1);213}214215if (BasePseudoVal0 && BasePseudoVal1 &&216BasePseudoVal0->kind() == BasePseudoVal1->kind() &&217BasePseudoVal0->kind() == PseudoSourceValue::FixedStack) {218// Spills/fills219auto FS0 = cast<FixedStackPseudoSourceValue>(BasePseudoVal0);220auto FS1 = cast<FixedStackPseudoSourceValue>(BasePseudoVal1);221Offset0 = MF.getFrameInfo().getObjectOffset(FS0->getFrameIndex());222Offset1 = MF.getFrameInfo().getObjectOffset(FS1->getFrameIndex());223return CheckOffsets(Offset0, Offset1);224}225226// Constant pools (likely in ITCM)227if (BasePseudoVal0 && BasePseudoVal1 &&228BasePseudoVal0->kind() == BasePseudoVal1->kind() &&229BasePseudoVal0->isConstantPool() && AssumeITCMBankConflict)230return Hazard;231232// Is this a stack pointer-relative access? We could in general try to233// use "is this the same register and is it unchanged?", but the234// memory operand tracking is highly likely to have already found that.235// What we're after here is bank conflicts between different objects in236// the stack frame.237if (!SPvalid) { // set up SP238if (!getBaseOffset(L0, SP, SPOffset0) || SP->getReg().id() != ARM::SP)239SP = nullptr;240SPvalid = true;241}242if (SP) {243int64_t SPOffset1;244const MachineOperand *SP1;245if (getBaseOffset(*L1, SP1, SPOffset1) && SP1->getReg().id() == ARM::SP)246return CheckOffsets(SPOffset0, SPOffset1);247}248}249250return NoHazard;251}252253void ARMBankConflictHazardRecognizer::Reset() { Accesses.clear(); }254255void ARMBankConflictHazardRecognizer::EmitInstruction(SUnit *SU) {256MachineInstr &MI = *SU->getInstr();257if (!MI.mayLoad() || MI.mayStore() || MI.getNumMemOperands() != 1)258return;259260auto MO = *MI.memoperands().begin();261LocationSize Size1 = MO->getSize();262if (Size1.hasValue() && Size1.getValue() > 4)263return;264Accesses.push_back(&MI);265}266267void ARMBankConflictHazardRecognizer::AdvanceCycle() { Accesses.clear(); }268269void ARMBankConflictHazardRecognizer::RecedeCycle() { Accesses.clear(); }270271272