2010-12-06 06:04:16 +08:00
|
|
|
//===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2010-12-06 06:04:16 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ARMHazardRecognizer.h"
|
|
|
|
#include "ARMBaseInstrInfo.h"
|
2011-01-12 05:46:47 +08:00
|
|
|
#include "ARMBaseRegisterInfo.h"
|
2010-12-06 06:04:16 +08:00
|
|
|
#include "ARMSubtarget.h"
|
2020-12-23 22:00:59 +08:00
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
2010-12-06 06:04:16 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
|
|
#include "llvm/CodeGen/ScheduleDAG.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
2020-12-23 22:00:59 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
|
2010-12-06 06:04:16 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
2020-12-23 22:00:59 +08:00
|
|
|
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);
|
|
|
|
|
2010-12-06 06:04:16 +08:00
|
|
|
static bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI,
|
|
|
|
const TargetRegisterInfo &TRI) {
|
|
|
|
// FIXME: Detect integer instructions properly.
|
2011-06-29 03:10:37 +08:00
|
|
|
const MCInstrDesc &MCID = MI->getDesc();
|
|
|
|
unsigned Domain = MCID.TSFlags & ARMII::DomainMask;
|
2011-12-07 15:15:52 +08:00
|
|
|
if (MI->mayStore())
|
2010-12-06 06:04:16 +08:00
|
|
|
return false;
|
2011-06-29 03:10:37 +08:00
|
|
|
unsigned Opcode = MCID.getOpcode();
|
2011-02-23 03:53:14 +08:00
|
|
|
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;
|
2010-12-06 06:04:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ScheduleHazardRecognizer::HazardType
|
2020-10-26 16:06:17 +08:00
|
|
|
ARMHazardRecognizerFPMLx::getHazardType(SUnit *SU, int Stalls) {
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 13:03:26 +08:00
|
|
|
assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead");
|
|
|
|
|
2010-12-06 06:04:16 +08:00
|
|
|
MachineInstr *MI = SU->getInstr();
|
|
|
|
|
2018-05-09 10:42:00 +08:00
|
|
|
if (!MI->isDebugInstr()) {
|
2010-12-06 06:04:16 +08:00
|
|
|
// Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following
|
|
|
|
// a VMLA / VMLS will cause 4 cycle stall.
|
2011-06-29 03:10:37 +08:00
|
|
|
const MCInstrDesc &MCID = MI->getDesc();
|
|
|
|
if (LastMI && (MCID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) {
|
2010-12-06 06:04:16 +08:00
|
|
|
MachineInstr *DefMI = LastMI;
|
2011-06-29 03:10:37 +08:00
|
|
|
const MCInstrDesc &LastMCID = LastMI->getDesc();
|
2015-01-29 08:19:33 +08:00
|
|
|
const MachineFunction *MF = MI->getParent()->getParent();
|
2014-08-05 05:25:23 +08:00
|
|
|
const ARMBaseInstrInfo &TII = *static_cast<const ARMBaseInstrInfo *>(
|
2015-01-29 08:19:33 +08:00
|
|
|
MF->getSubtarget().getInstrInfo());
|
2013-06-07 13:54:19 +08:00
|
|
|
|
2010-12-06 06:04:16 +08:00
|
|
|
// Skip over one non-VFP / NEON instruction.
|
2011-12-07 15:15:52 +08:00
|
|
|
if (!LastMI->isBarrier() &&
|
2016-07-06 17:22:23 +08:00
|
|
|
!(TII.getSubtarget().hasMuxedUnits() && LastMI->mayLoadOrStore()) &&
|
2011-06-29 03:10:37 +08:00
|
|
|
(LastMCID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) {
|
2010-12-06 06:04:16 +08:00
|
|
|
MachineBasicBlock::iterator I = LastMI;
|
|
|
|
if (I != LastMI->getParent()->begin()) {
|
2014-03-02 20:27:27 +08:00
|
|
|
I = std::prev(I);
|
2010-12-06 06:04:16 +08:00
|
|
|
DefMI = &*I;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TII.isFpMLxInstruction(DefMI->getOpcode()) &&
|
|
|
|
(TII.canCauseFpMLxStall(MI->getOpcode()) ||
|
2013-06-07 13:54:19 +08:00
|
|
|
hasRAWHazard(DefMI, MI, TII.getRegisterInfo()))) {
|
2010-12-06 06:04:16 +08:00
|
|
|
// Try to schedule another instruction for the next 4 cycles.
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 13:03:26 +08:00
|
|
|
if (FpMLxStalls == 0)
|
|
|
|
FpMLxStalls = 4;
|
2010-12-06 06:04:16 +08:00
|
|
|
return Hazard;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-10-26 16:06:17 +08:00
|
|
|
return NoHazard;
|
2010-12-06 06:04:16 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 16:06:17 +08:00
|
|
|
void ARMHazardRecognizerFPMLx::Reset() {
|
2014-04-25 13:30:21 +08:00
|
|
|
LastMI = nullptr;
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 13:03:26 +08:00
|
|
|
FpMLxStalls = 0;
|
2010-12-06 06:04:16 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 16:06:17 +08:00
|
|
|
void ARMHazardRecognizerFPMLx::EmitInstruction(SUnit *SU) {
|
2010-12-06 06:04:16 +08:00
|
|
|
MachineInstr *MI = SU->getInstr();
|
2018-05-09 10:42:00 +08:00
|
|
|
if (!MI->isDebugInstr()) {
|
2010-12-06 06:04:16 +08:00
|
|
|
LastMI = MI;
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 13:03:26 +08:00
|
|
|
FpMLxStalls = 0;
|
2010-12-06 06:04:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-26 16:06:17 +08:00
|
|
|
void ARMHazardRecognizerFPMLx::AdvanceCycle() {
|
Various bits of framework needed for precise machine-level selection
DAG scheduling during isel. Most new functionality is currently
guarded by -enable-sched-cycles and -enable-sched-hazard.
Added InstrItineraryData::IssueWidth field, currently derived from
ARM itineraries, but could be initialized differently on other targets.
Added ScheduleHazardRecognizer::MaxLookAhead to indicate whether it is
active, and if so how many cycles of state it holds.
Added SchedulingPriorityQueue::HasReadyFilter to allowing gating entry
into the scheduler's available queue.
ScoreboardHazardRecognizer now accesses the ScheduleDAG in order to
get information about it's SUnits, provides RecedeCycle for bottom-up
scheduling, correctly computes scoreboard depth, tracks IssueCount, and
considers potential stall cycles when checking for hazards.
ScheduleDAGRRList now models machine cycles and hazards (under
flags). It tracks MinAvailableCycle, drives the hazard recognizer and
priority queue's ready filter, manages a new PendingQueue, properly
accounts for stall cycles, etc.
llvm-svn: 122541
2010-12-24 13:03:26 +08:00
|
|
|
if (FpMLxStalls && --FpMLxStalls == 0)
|
2010-12-06 06:04:16 +08:00
|
|
|
// Stalled for 4 cycles but still can't schedule any other instructions.
|
2014-04-25 13:30:21 +08:00
|
|
|
LastMI = nullptr;
|
2010-12-09 04:04:29 +08:00
|
|
|
}
|
|
|
|
|
2020-10-26 16:06:17 +08:00
|
|
|
void ARMHazardRecognizerFPMLx::RecedeCycle() {
|
2010-12-09 04:04:29 +08:00
|
|
|
llvm_unreachable("reverse ARM hazard checking unsupported");
|
2010-12-06 06:04:16 +08:00
|
|
|
}
|
2020-12-23 22:00:59 +08:00
|
|
|
|
|
|
|
///////// 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)
|
|
|
|
: ScheduleHazardRecognizer(), 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(); }
|