123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- //===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "ARMHazardRecognizer.h"
- #include "ARMBaseInstrInfo.h"
- #include "ARMBaseRegisterInfo.h"
- #include "ARMSubtarget.h"
- #include "llvm/Analysis/ValueTracking.h"
- #include "llvm/CodeGen/MachineInstr.h"
- #include "llvm/CodeGen/ScheduleDAG.h"
- #include "llvm/CodeGen/TargetRegisterInfo.h"
- #include "llvm/Support/CommandLine.h"
- using namespace llvm;
- static cl::opt<int> DataBankMask("arm-data-bank-mask", cl::init(-1),
- cl::Hidden);
- static cl::opt<bool> AssumeITCMConflict("arm-assume-itcm-bankconflict",
- cl::init(false), cl::Hidden);
- static bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI,
- const TargetRegisterInfo &TRI) {
- // FIXME: Detect integer instructions properly.
- const MCInstrDesc &MCID = MI->getDesc();
- unsigned Domain = MCID.TSFlags & ARMII::DomainMask;
- if (MI->mayStore())
- return false;
- unsigned Opcode = MCID.getOpcode();
- if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD)
- return false;
- if ((Domain & ARMII::DomainVFP) || (Domain & ARMII::DomainNEON))
- return MI->readsRegister(DefMI->getOperand(0).getReg(), &TRI);
- return false;
- }
- ScheduleHazardRecognizer::HazardType
- ARMHazardRecognizerFPMLx::getHazardType(SUnit *SU, int Stalls) {
- assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead");
- MachineInstr *MI = SU->getInstr();
- if (!MI->isDebugInstr()) {
- // Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following
- // a VMLA / VMLS will cause 4 cycle stall.
- const MCInstrDesc &MCID = MI->getDesc();
- if (LastMI && (MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) {
- MachineInstr *DefMI = LastMI;
- const MCInstrDesc &LastMCID = LastMI->getDesc();
- const MachineFunction *MF = MI->getParent()->getParent();
- const ARMBaseInstrInfo &TII = *static_cast<const ARMBaseInstrInfo *>(
- MF->getSubtarget().getInstrInfo());
- // Skip over one non-VFP / NEON instruction.
- if (!LastMI->isBarrier() &&
- !(TII.getSubtarget().hasMuxedUnits() && LastMI->mayLoadOrStore()) &&
- (LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) {
- MachineBasicBlock::iterator I = LastMI;
- if (I != LastMI->getParent()->begin()) {
- I = std::prev(I);
- DefMI = &*I;
- }
- }
- if (TII.isFpMLxInstruction(DefMI->getOpcode()) &&
- (TII.canCauseFpMLxStall(MI->getOpcode()) ||
- hasRAWHazard(DefMI, MI, TII.getRegisterInfo()))) {
- // Try to schedule another instruction for the next 4 cycles.
- if (FpMLxStalls == 0)
- FpMLxStalls = 4;
- return Hazard;
- }
- }
- }
- return NoHazard;
- }
- void ARMHazardRecognizerFPMLx::Reset() {
- LastMI = nullptr;
- FpMLxStalls = 0;
- }
- void ARMHazardRecognizerFPMLx::EmitInstruction(SUnit *SU) {
- MachineInstr *MI = SU->getInstr();
- if (!MI->isDebugInstr()) {
- LastMI = MI;
- FpMLxStalls = 0;
- }
- }
- void ARMHazardRecognizerFPMLx::AdvanceCycle() {
- if (FpMLxStalls && --FpMLxStalls == 0)
- // Stalled for 4 cycles but still can't schedule any other instructions.
- LastMI = nullptr;
- }
- void ARMHazardRecognizerFPMLx::RecedeCycle() {
- llvm_unreachable("reverse ARM hazard checking unsupported");
- }
- ///////// Bank conflicts handled as hazards //////////////
- static bool getBaseOffset(const MachineInstr &MI, const MachineOperand *&BaseOp,
- int64_t &Offset) {
- uint64_t TSFlags = MI.getDesc().TSFlags;
- unsigned AddrMode = (TSFlags & ARMII::AddrModeMask);
- unsigned IndexMode =
- (TSFlags & ARMII::IndexModeMask) >> ARMII::IndexModeShift;
- // Address mode tells us what we want to know about operands for T2
- // instructions (but not size). It tells us size (but not about operands)
- // for T1 instructions.
- switch (AddrMode) {
- default:
- return false;
- case ARMII::AddrModeT2_i8:
- // t2LDRBT, t2LDRB_POST, t2LDRB_PRE, t2LDRBi8,
- // t2LDRHT, t2LDRH_POST, t2LDRH_PRE, t2LDRHi8,
- // t2LDRSBT, t2LDRSB_POST, t2LDRSB_PRE, t2LDRSBi8,
- // t2LDRSHT, t2LDRSH_POST, t2LDRSH_PRE, t2LDRSHi8,
- // t2LDRT, t2LDR_POST, t2LDR_PRE, t2LDRi8
- BaseOp = &MI.getOperand(1);
- Offset = (IndexMode == ARMII::IndexModePost)
- ? 0
- : (IndexMode == ARMII::IndexModePre ||
- IndexMode == ARMII::IndexModeUpd)
- ? MI.getOperand(3).getImm()
- : MI.getOperand(2).getImm();
- return true;
- case ARMII::AddrModeT2_i12:
- // t2LDRBi12, t2LDRHi12
- // t2LDRSBi12, t2LDRSHi12
- // t2LDRi12
- BaseOp = &MI.getOperand(1);
- Offset = MI.getOperand(2).getImm();
- return true;
- case ARMII::AddrModeT2_i8s4:
- // t2LDRD_POST, t2LDRD_PRE, t2LDRDi8
- BaseOp = &MI.getOperand(2);
- Offset = (IndexMode == ARMII::IndexModePost)
- ? 0
- : (IndexMode == ARMII::IndexModePre ||
- IndexMode == ARMII::IndexModeUpd)
- ? MI.getOperand(4).getImm()
- : MI.getOperand(3).getImm();
- return true;
- case ARMII::AddrModeT1_1:
- // tLDRBi, tLDRBr (watch out!), TLDRSB
- case ARMII::AddrModeT1_2:
- // tLDRHi, tLDRHr (watch out!), TLDRSH
- case ARMII::AddrModeT1_4:
- // tLDRi, tLDRr (watch out!)
- BaseOp = &MI.getOperand(1);
- Offset = MI.getOperand(2).isImm() ? MI.getOperand(2).getImm() : 0;
- return MI.getOperand(2).isImm();
- }
- return false;
- }
- ARMBankConflictHazardRecognizer::ARMBankConflictHazardRecognizer(
- const ScheduleDAG *DAG, int64_t CPUBankMask, bool CPUAssumeITCMConflict)
- : MF(DAG->MF), DL(DAG->MF.getDataLayout()),
- DataMask(DataBankMask.getNumOccurrences() ? int64_t(DataBankMask)
- : CPUBankMask),
- AssumeITCMBankConflict(AssumeITCMConflict.getNumOccurrences()
- ? AssumeITCMConflict
- : CPUAssumeITCMConflict) {
- MaxLookAhead = 1;
- }
- ScheduleHazardRecognizer::HazardType
- ARMBankConflictHazardRecognizer::CheckOffsets(unsigned O0, unsigned O1) {
- return (((O0 ^ O1) & DataMask) != 0) ? NoHazard : Hazard;
- }
- ScheduleHazardRecognizer::HazardType
- ARMBankConflictHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
- MachineInstr &L0 = *SU->getInstr();
- if (!L0.mayLoad() || L0.mayStore() || L0.getNumMemOperands() != 1)
- return NoHazard;
- auto MO0 = *L0.memoperands().begin();
- auto BaseVal0 = MO0->getValue();
- auto BasePseudoVal0 = MO0->getPseudoValue();
- int64_t Offset0 = 0;
- if (MO0->getSize() > 4)
- return NoHazard;
- bool SPvalid = false;
- const MachineOperand *SP = nullptr;
- int64_t SPOffset0 = 0;
- for (auto L1 : Accesses) {
- auto MO1 = *L1->memoperands().begin();
- auto BaseVal1 = MO1->getValue();
- auto BasePseudoVal1 = MO1->getPseudoValue();
- int64_t Offset1 = 0;
- // Pointers to the same object
- if (BaseVal0 && BaseVal1) {
- const Value *Ptr0, *Ptr1;
- Ptr0 = GetPointerBaseWithConstantOffset(BaseVal0, Offset0, DL, true);
- Ptr1 = GetPointerBaseWithConstantOffset(BaseVal1, Offset1, DL, true);
- if (Ptr0 == Ptr1 && Ptr0)
- return CheckOffsets(Offset0, Offset1);
- }
- if (BasePseudoVal0 && BasePseudoVal1 &&
- BasePseudoVal0->kind() == BasePseudoVal1->kind() &&
- BasePseudoVal0->kind() == PseudoSourceValue::FixedStack) {
- // Spills/fills
- auto FS0 = cast<FixedStackPseudoSourceValue>(BasePseudoVal0);
- auto FS1 = cast<FixedStackPseudoSourceValue>(BasePseudoVal1);
- Offset0 = MF.getFrameInfo().getObjectOffset(FS0->getFrameIndex());
- Offset1 = MF.getFrameInfo().getObjectOffset(FS1->getFrameIndex());
- return CheckOffsets(Offset0, Offset1);
- }
- // Constant pools (likely in ITCM)
- if (BasePseudoVal0 && BasePseudoVal1 &&
- BasePseudoVal0->kind() == BasePseudoVal1->kind() &&
- BasePseudoVal0->isConstantPool() && AssumeITCMBankConflict)
- return Hazard;
- // Is this a stack pointer-relative access? We could in general try to
- // use "is this the same register and is it unchanged?", but the
- // memory operand tracking is highly likely to have already found that.
- // What we're after here is bank conflicts between different objects in
- // the stack frame.
- if (!SPvalid) { // set up SP
- if (!getBaseOffset(L0, SP, SPOffset0) || SP->getReg().id() != ARM::SP)
- SP = nullptr;
- SPvalid = true;
- }
- if (SP) {
- int64_t SPOffset1;
- const MachineOperand *SP1;
- if (getBaseOffset(*L1, SP1, SPOffset1) && SP1->getReg().id() == ARM::SP)
- return CheckOffsets(SPOffset0, SPOffset1);
- }
- }
- return NoHazard;
- }
- void ARMBankConflictHazardRecognizer::Reset() { Accesses.clear(); }
- void ARMBankConflictHazardRecognizer::EmitInstruction(SUnit *SU) {
- MachineInstr &MI = *SU->getInstr();
- if (!MI.mayLoad() || MI.mayStore() || MI.getNumMemOperands() != 1)
- return;
- auto MO = *MI.memoperands().begin();
- uint64_t Size1 = MO->getSize();
- if (Size1 > 4)
- return;
- Accesses.push_back(&MI);
- }
- void ARMBankConflictHazardRecognizer::AdvanceCycle() { Accesses.clear(); }
- void ARMBankConflictHazardRecognizer::RecedeCycle() { Accesses.clear(); }
|