2007-12-29 20:36:04 +00:00
|
|
|
//===- SPUInstrInfo.cpp - Cell SPU Instruction Information ----------------===//
|
2007-12-04 22:35:58 +00:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 20:36:04 +00:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-12-04 22:35:58 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file contains the Cell SPU implementation of the TargetInstrInfo class.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "SPUInstrInfo.h"
|
2008-01-01 21:11:32 +00:00
|
|
|
#include "SPUInstrBuilder.h"
|
2007-12-04 22:35:58 +00:00
|
|
|
#include "SPUTargetMachine.h"
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122541 91177308-0d34-0410-b5e6-96231b3b80d8
2010-12-24 05:03:26 +00:00
|
|
|
#include "SPUHazardRecognizers.h"
|
2007-12-04 22:35:58 +00:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2011-07-11 03:57:24 +00:00
|
|
|
#include "llvm/MC/MCContext.h"
|
2009-01-02 20:52:08 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
2009-07-08 20:53:28 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2011-08-24 18:08:43 +00:00
|
|
|
#include "llvm/Support/TargetRegistry.h"
|
2009-08-23 11:52:17 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2007-12-04 22:35:58 +00:00
|
|
|
|
2011-07-01 17:57:27 +00:00
|
|
|
#define GET_INSTRINFO_CTOR
|
2011-06-28 20:07:07 +00:00
|
|
|
#include "SPUGenInstrInfo.inc"
|
|
|
|
|
2007-12-04 22:35:58 +00:00
|
|
|
using namespace llvm;
|
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
namespace {
|
|
|
|
//! Predicate for an unconditional branch instruction
|
|
|
|
inline bool isUncondBranch(const MachineInstr *I) {
|
|
|
|
unsigned opc = I->getOpcode();
|
|
|
|
|
|
|
|
return (opc == SPU::BR
|
2009-01-26 03:37:41 +00:00
|
|
|
|| opc == SPU::BRA
|
|
|
|
|| opc == SPU::BI);
|
2008-12-10 00:15:19 +00:00
|
|
|
}
|
|
|
|
|
2009-01-03 00:27:53 +00:00
|
|
|
//! Predicate for a conditional branch instruction
|
2008-12-10 00:15:19 +00:00
|
|
|
inline bool isCondBranch(const MachineInstr *I) {
|
|
|
|
unsigned opc = I->getOpcode();
|
|
|
|
|
2008-12-27 04:51:36 +00:00
|
|
|
return (opc == SPU::BRNZr32
|
|
|
|
|| opc == SPU::BRNZv4i32
|
2009-01-26 03:37:41 +00:00
|
|
|
|| opc == SPU::BRZr32
|
|
|
|
|| opc == SPU::BRZv4i32
|
|
|
|
|| opc == SPU::BRHNZr16
|
|
|
|
|| opc == SPU::BRHNZv8i16
|
|
|
|
|| opc == SPU::BRHZr16
|
|
|
|
|| opc == SPU::BRHZv8i16);
|
2008-12-10 00:15:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-04 22:35:58 +00:00
|
|
|
SPUInstrInfo::SPUInstrInfo(SPUTargetMachine &tm)
|
2011-07-01 17:57:27 +00:00
|
|
|
: SPUGenInstrInfo(SPU::ADJCALLSTACKDOWN, SPU::ADJCALLSTACKUP),
|
2007-12-04 22:35:58 +00:00
|
|
|
TM(tm),
|
|
|
|
RI(*TM.getSubtargetImpl(), *this)
|
2009-01-03 00:27:53 +00:00
|
|
|
{ /* NOP */ }
|
2007-12-04 22:35:58 +00:00
|
|
|
|
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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122541 91177308-0d34-0410-b5e6-96231b3b80d8
2010-12-24 05:03:26 +00:00
|
|
|
/// CreateTargetHazardRecognizer - Return the hazard recognizer to use for
|
|
|
|
/// this target when scheduling the DAG.
|
|
|
|
ScheduleHazardRecognizer *SPUInstrInfo::CreateTargetHazardRecognizer(
|
|
|
|
const TargetMachine *TM,
|
|
|
|
const ScheduleDAG *DAG) const {
|
|
|
|
const TargetInstrInfo *TII = TM->getInstrInfo();
|
|
|
|
assert(TII && "No InstrInfo?");
|
|
|
|
return new SPUHazardRecognizer(*TII);
|
|
|
|
}
|
|
|
|
|
2007-12-04 22:35:58 +00:00
|
|
|
unsigned
|
2008-11-18 19:49:32 +00:00
|
|
|
SPUInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
|
|
|
|
int &FrameIndex) const {
|
2007-12-04 22:35:58 +00:00
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
case SPU::LQDv16i8:
|
|
|
|
case SPU::LQDv8i16:
|
|
|
|
case SPU::LQDv4i32:
|
|
|
|
case SPU::LQDv4f32:
|
|
|
|
case SPU::LQDv2f64:
|
|
|
|
case SPU::LQDr128:
|
|
|
|
case SPU::LQDr64:
|
|
|
|
case SPU::LQDr32:
|
2008-12-10 00:15:19 +00:00
|
|
|
case SPU::LQDr16: {
|
|
|
|
const MachineOperand MOp1 = MI->getOperand(1);
|
|
|
|
const MachineOperand MOp2 = MI->getOperand(2);
|
2009-01-03 00:27:53 +00:00
|
|
|
if (MOp1.isImm() && MOp2.isFI()) {
|
|
|
|
FrameIndex = MOp2.getIndex();
|
2008-12-10 00:15:19 +00:00
|
|
|
return MI->getOperand(0).getReg();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2007-12-04 22:35:58 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
2008-11-18 19:49:32 +00:00
|
|
|
SPUInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
|
|
|
|
int &FrameIndex) const {
|
2007-12-04 22:35:58 +00:00
|
|
|
switch (MI->getOpcode()) {
|
|
|
|
default: break;
|
|
|
|
case SPU::STQDv16i8:
|
|
|
|
case SPU::STQDv8i16:
|
|
|
|
case SPU::STQDv4i32:
|
|
|
|
case SPU::STQDv4f32:
|
|
|
|
case SPU::STQDv2f64:
|
|
|
|
case SPU::STQDr128:
|
|
|
|
case SPU::STQDr64:
|
|
|
|
case SPU::STQDr32:
|
|
|
|
case SPU::STQDr16:
|
2008-12-10 00:15:19 +00:00
|
|
|
case SPU::STQDr8: {
|
|
|
|
const MachineOperand MOp1 = MI->getOperand(1);
|
|
|
|
const MachineOperand MOp2 = MI->getOperand(2);
|
2008-12-27 04:51:36 +00:00
|
|
|
if (MOp1.isImm() && MOp2.isFI()) {
|
|
|
|
FrameIndex = MOp2.getIndex();
|
2008-12-10 00:15:19 +00:00
|
|
|
return MI->getOperand(0).getReg();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2007-12-04 22:35:58 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2007-12-31 06:32:00 +00:00
|
|
|
|
2010-07-11 07:31:03 +00:00
|
|
|
void SPUInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
|
|
|
MachineBasicBlock::iterator I, DebugLoc DL,
|
|
|
|
unsigned DestReg, unsigned SrcReg,
|
|
|
|
bool KillSrc) const
|
2007-12-31 06:32:00 +00:00
|
|
|
{
|
2008-03-09 20:31:11 +00:00
|
|
|
// We support cross register class moves for our aliases, such as R3 in any
|
|
|
|
// reg class to any other reg class containing R3. This is required because
|
|
|
|
// we instruction select bitconvert i64 -> f64 as a noop for example, so our
|
|
|
|
// types have no specific meaning.
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2010-07-11 07:31:03 +00:00
|
|
|
BuildMI(MBB, I, DL, get(SPU::LRr128), DestReg)
|
|
|
|
.addReg(SrcReg, getKillRegState(KillSrc));
|
2007-12-31 06:32:00 +00:00
|
|
|
}
|
2008-01-01 21:11:32 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
SPUInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
|
2010-05-06 19:06:44 +00:00
|
|
|
MachineBasicBlock::iterator MI,
|
|
|
|
unsigned SrcReg, bool isKill, int FrameIdx,
|
|
|
|
const TargetRegisterClass *RC,
|
|
|
|
const TargetRegisterInfo *TRI) const
|
2008-01-01 21:11:32 +00:00
|
|
|
{
|
2008-01-07 02:48:55 +00:00
|
|
|
unsigned opc;
|
2011-01-10 12:39:04 +00:00
|
|
|
bool isValidFrameIdx = (FrameIdx < SPUFrameLowering::maxFrameOffset());
|
2008-01-01 21:11:32 +00:00
|
|
|
if (RC == SPU::GPRCRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::STQDr128 : SPU::STQXr128);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R64CRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::STQDr64 : SPU::STQXr64);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R64FPRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::STQDr64 : SPU::STQXr64);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R32CRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::STQDr32 : SPU::STQXr32);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R32FPRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::STQDr32 : SPU::STQXr32);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R16CRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::STQDr16 : SPU::STQXr16);
|
|
|
|
} else if (RC == SPU::R8CRegisterClass) {
|
|
|
|
opc = (isValidFrameIdx ? SPU::STQDr8 : SPU::STQXr8);
|
2008-12-27 04:51:36 +00:00
|
|
|
} else if (RC == SPU::VECREGRegisterClass) {
|
|
|
|
opc = (isValidFrameIdx) ? SPU::STQDv16i8 : SPU::STQXv16i8;
|
2008-01-01 21:11:32 +00:00
|
|
|
} else {
|
2009-07-14 16:55:14 +00:00
|
|
|
llvm_unreachable("Unknown regclass!");
|
2008-01-01 21:11:32 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 20:16:16 +00:00
|
|
|
DebugLoc DL;
|
2009-02-12 00:02:55 +00:00
|
|
|
if (MI != MBB.end()) DL = MI->getDebugLoc();
|
|
|
|
addFrameReference(BuildMI(MBB, MI, DL, get(opc))
|
2009-05-13 21:33:08 +00:00
|
|
|
.addReg(SrcReg, getKillRegState(isKill)), FrameIdx);
|
2008-01-01 21:11:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SPUInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
|
2010-05-06 19:06:44 +00:00
|
|
|
MachineBasicBlock::iterator MI,
|
|
|
|
unsigned DestReg, int FrameIdx,
|
|
|
|
const TargetRegisterClass *RC,
|
|
|
|
const TargetRegisterInfo *TRI) const
|
2008-01-01 21:11:32 +00:00
|
|
|
{
|
2008-01-07 02:48:55 +00:00
|
|
|
unsigned opc;
|
2011-01-10 12:39:04 +00:00
|
|
|
bool isValidFrameIdx = (FrameIdx < SPUFrameLowering::maxFrameOffset());
|
2008-01-01 21:11:32 +00:00
|
|
|
if (RC == SPU::GPRCRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::LQDr128 : SPU::LQXr128);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R64CRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::LQDr64 : SPU::LQXr64);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R64FPRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::LQDr64 : SPU::LQXr64);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R32CRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::LQDr32 : SPU::LQXr32);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R32FPRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::LQDr32 : SPU::LQXr32);
|
2008-01-01 21:11:32 +00:00
|
|
|
} else if (RC == SPU::R16CRegisterClass) {
|
2008-12-10 00:15:19 +00:00
|
|
|
opc = (isValidFrameIdx ? SPU::LQDr16 : SPU::LQXr16);
|
|
|
|
} else if (RC == SPU::R8CRegisterClass) {
|
|
|
|
opc = (isValidFrameIdx ? SPU::LQDr8 : SPU::LQXr8);
|
2008-12-27 04:51:36 +00:00
|
|
|
} else if (RC == SPU::VECREGRegisterClass) {
|
|
|
|
opc = (isValidFrameIdx) ? SPU::LQDv16i8 : SPU::LQXv16i8;
|
2008-01-01 21:11:32 +00:00
|
|
|
} else {
|
2009-07-14 16:55:14 +00:00
|
|
|
llvm_unreachable("Unknown regclass in loadRegFromStackSlot!");
|
2008-01-01 21:11:32 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 20:16:16 +00:00
|
|
|
DebugLoc DL;
|
2009-02-12 00:02:55 +00:00
|
|
|
if (MI != MBB.end()) DL = MI->getDebugLoc();
|
2009-05-16 07:25:44 +00:00
|
|
|
addFrameReference(BuildMI(MBB, MI, DL, get(opc), DestReg), FrameIdx);
|
2008-01-01 21:11:32 +00:00
|
|
|
}
|
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
//! Branch analysis
|
2009-01-02 20:52:08 +00:00
|
|
|
/*!
|
2008-12-10 00:15:19 +00:00
|
|
|
\note This code was kiped from PPC. There may be more branch analysis for
|
|
|
|
CellSPU than what's currently done here.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
SPUInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
|
2009-01-26 03:37:41 +00:00
|
|
|
MachineBasicBlock *&FBB,
|
2009-02-09 07:14:22 +00:00
|
|
|
SmallVectorImpl<MachineOperand> &Cond,
|
|
|
|
bool AllowModify) const {
|
2008-12-10 00:15:19 +00:00
|
|
|
// If the block has no terminators, it just falls into the block after it.
|
|
|
|
MachineBasicBlock::iterator I = MBB.end();
|
2010-04-02 01:38:09 +00:00
|
|
|
if (I == MBB.begin())
|
|
|
|
return false;
|
|
|
|
--I;
|
|
|
|
while (I->isDebugValue()) {
|
|
|
|
if (I == MBB.begin())
|
|
|
|
return false;
|
|
|
|
--I;
|
|
|
|
}
|
|
|
|
if (!isUnpredicatedTerminator(I))
|
2008-12-10 00:15:19 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Get the last instruction in the block.
|
|
|
|
MachineInstr *LastInst = I;
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
// If there is only one terminator instruction, process it.
|
|
|
|
if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) {
|
|
|
|
if (isUncondBranch(LastInst)) {
|
2010-05-11 11:00:02 +00:00
|
|
|
// Check for jump tables
|
|
|
|
if (!LastInst->getOperand(0).isMBB())
|
|
|
|
return true;
|
2008-12-10 00:15:19 +00:00
|
|
|
TBB = LastInst->getOperand(0).getMBB();
|
|
|
|
return false;
|
|
|
|
} else if (isCondBranch(LastInst)) {
|
|
|
|
// Block ends with fall-through condbranch.
|
|
|
|
TBB = LastInst->getOperand(1).getMBB();
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "Pushing LastInst: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG(LastInst->dump());
|
|
|
|
Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode()));
|
2008-12-10 00:15:19 +00:00
|
|
|
Cond.push_back(LastInst->getOperand(0));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Otherwise, don't know what this is.
|
|
|
|
return true;
|
|
|
|
}
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
// Get the instruction before it if it's a terminator.
|
|
|
|
MachineInstr *SecondLastInst = I;
|
|
|
|
|
|
|
|
// If there are three terminators, we don't know what sort of block this is.
|
|
|
|
if (SecondLastInst && I != MBB.begin() &&
|
|
|
|
isUnpredicatedTerminator(--I))
|
|
|
|
return true;
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
// If the block ends with a conditional and unconditional branch, handle it.
|
|
|
|
if (isCondBranch(SecondLastInst) && isUncondBranch(LastInst)) {
|
|
|
|
TBB = SecondLastInst->getOperand(1).getMBB();
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "Pushing SecondLastInst: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG(SecondLastInst->dump());
|
|
|
|
Cond.push_back(MachineOperand::CreateImm(SecondLastInst->getOpcode()));
|
2008-12-10 00:15:19 +00:00
|
|
|
Cond.push_back(SecondLastInst->getOperand(0));
|
|
|
|
FBB = LastInst->getOperand(0).getMBB();
|
|
|
|
return false;
|
|
|
|
}
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
// If the block ends with two unconditional branches, handle it. The second
|
|
|
|
// one is not executed, so remove it.
|
|
|
|
if (isUncondBranch(SecondLastInst) && isUncondBranch(LastInst)) {
|
|
|
|
TBB = SecondLastInst->getOperand(0).getMBB();
|
|
|
|
I = LastInst;
|
2009-02-09 07:14:22 +00:00
|
|
|
if (AllowModify)
|
|
|
|
I->eraseFromParent();
|
2008-12-10 00:15:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, can't handle this.
|
|
|
|
return true;
|
|
|
|
}
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2011-02-28 14:08:24 +00:00
|
|
|
// search MBB for branch hint labels and branch hit ops
|
|
|
|
static void removeHBR( MachineBasicBlock &MBB) {
|
|
|
|
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I){
|
|
|
|
if (I->getOpcode() == SPU::HBRA ||
|
|
|
|
I->getOpcode() == SPU::HBR_LABEL){
|
|
|
|
I=MBB.erase(I);
|
2011-10-11 12:55:18 +00:00
|
|
|
if (I == MBB.end())
|
|
|
|
break;
|
2011-02-28 14:08:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
unsigned
|
|
|
|
SPUInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
|
|
|
|
MachineBasicBlock::iterator I = MBB.end();
|
2011-02-28 14:08:24 +00:00
|
|
|
removeHBR(MBB);
|
2008-12-10 00:15:19 +00:00
|
|
|
if (I == MBB.begin())
|
|
|
|
return 0;
|
|
|
|
--I;
|
2010-04-02 01:38:09 +00:00
|
|
|
while (I->isDebugValue()) {
|
|
|
|
if (I == MBB.begin())
|
|
|
|
return 0;
|
|
|
|
--I;
|
|
|
|
}
|
2008-12-10 00:15:19 +00:00
|
|
|
if (!isCondBranch(I) && !isUncondBranch(I))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Remove the first branch.
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "Removing branch: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG(I->dump());
|
2008-12-10 00:15:19 +00:00
|
|
|
I->eraseFromParent();
|
|
|
|
I = MBB.end();
|
|
|
|
if (I == MBB.begin())
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
--I;
|
2009-01-02 20:52:08 +00:00
|
|
|
if (!(isCondBranch(I) || isUncondBranch(I)))
|
2008-12-10 00:15:19 +00:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
// Remove the second branch.
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "Removing second branch: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG(I->dump());
|
2008-12-10 00:15:19 +00:00
|
|
|
I->eraseFromParent();
|
|
|
|
return 2;
|
|
|
|
}
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2011-02-28 14:08:24 +00:00
|
|
|
/** Find the optimal position for a hint branch instruction in a basic block.
|
|
|
|
* This should take into account:
|
|
|
|
* -the branch hint delays
|
|
|
|
* -congestion of the memory bus
|
|
|
|
* -dual-issue scheduling (i.e. avoid insertion of nops)
|
|
|
|
* Current implementation is rather simplistic.
|
|
|
|
*/
|
|
|
|
static MachineBasicBlock::iterator findHBRPosition(MachineBasicBlock &MBB)
|
|
|
|
{
|
|
|
|
MachineBasicBlock::iterator J = MBB.end();
|
|
|
|
for( int i=0; i<8; i++) {
|
|
|
|
if( J == MBB.begin() ) return J;
|
|
|
|
J--;
|
|
|
|
}
|
|
|
|
return J;
|
|
|
|
}
|
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
unsigned
|
|
|
|
SPUInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
|
2009-01-26 03:37:41 +00:00
|
|
|
MachineBasicBlock *FBB,
|
2010-06-17 22:43:56 +00:00
|
|
|
const SmallVectorImpl<MachineOperand> &Cond,
|
|
|
|
DebugLoc DL) const {
|
2008-12-10 00:15:19 +00:00
|
|
|
// Shouldn't be a fall through.
|
|
|
|
assert(TBB && "InsertBranch must not be told to insert a fallthrough");
|
2008-12-30 23:28:25 +00:00
|
|
|
assert((Cond.size() == 2 || Cond.size() == 0) &&
|
2008-12-10 00:15:19 +00:00
|
|
|
"SPU branch conditions have two components!");
|
2008-12-30 23:28:25 +00:00
|
|
|
|
2011-02-28 14:08:24 +00:00
|
|
|
MachineInstrBuilder MIB;
|
|
|
|
//TODO: make a more accurate algorithm.
|
|
|
|
bool haveHBR = MBB.size()>8;
|
|
|
|
|
|
|
|
removeHBR(MBB);
|
|
|
|
MCSymbol *branchLabel = MBB.getParent()->getContext().CreateTempSymbol();
|
|
|
|
// Add a label just before the branch
|
|
|
|
if (haveHBR)
|
|
|
|
MIB = BuildMI(&MBB, DL, get(SPU::HBR_LABEL)).addSym(branchLabel);
|
|
|
|
|
2008-12-10 00:15:19 +00:00
|
|
|
// One-way branch.
|
|
|
|
if (FBB == 0) {
|
2009-01-02 20:52:08 +00:00
|
|
|
if (Cond.empty()) {
|
|
|
|
// Unconditional branch
|
2011-02-28 14:08:24 +00:00
|
|
|
MIB = BuildMI(&MBB, DL, get(SPU::BR));
|
2009-01-02 20:52:08 +00:00
|
|
|
MIB.addMBB(TBB);
|
|
|
|
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "Inserted one-way uncond branch: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG((*MIB).dump());
|
2011-02-28 14:08:24 +00:00
|
|
|
|
|
|
|
// basic blocks have just one branch so it is safe to add the hint a its
|
|
|
|
if (haveHBR) {
|
|
|
|
MIB = BuildMI( MBB, findHBRPosition(MBB), DL, get(SPU::HBRA));
|
|
|
|
MIB.addSym(branchLabel);
|
|
|
|
MIB.addMBB(TBB);
|
|
|
|
}
|
2009-01-02 20:52:08 +00:00
|
|
|
} else {
|
|
|
|
// Conditional branch
|
2011-02-28 14:08:24 +00:00
|
|
|
MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
|
2009-01-02 20:52:08 +00:00
|
|
|
MIB.addReg(Cond[1].getReg()).addMBB(TBB);
|
|
|
|
|
2011-02-28 14:08:24 +00:00
|
|
|
if (haveHBR) {
|
|
|
|
MIB = BuildMI(MBB, findHBRPosition(MBB), DL, get(SPU::HBRA));
|
|
|
|
MIB.addSym(branchLabel);
|
|
|
|
MIB.addMBB(TBB);
|
|
|
|
}
|
|
|
|
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "Inserted one-way cond branch: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG((*MIB).dump());
|
2008-12-10 00:15:19 +00:00
|
|
|
}
|
|
|
|
return 1;
|
2009-01-02 20:52:08 +00:00
|
|
|
} else {
|
2011-02-28 14:08:24 +00:00
|
|
|
MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
|
2010-06-17 22:43:56 +00:00
|
|
|
MachineInstrBuilder MIB2 = BuildMI(&MBB, DL, get(SPU::BR));
|
2009-01-02 20:52:08 +00:00
|
|
|
|
|
|
|
// Two-way Conditional Branch.
|
|
|
|
MIB.addReg(Cond[1].getReg()).addMBB(TBB);
|
|
|
|
MIB2.addMBB(FBB);
|
|
|
|
|
2011-02-28 14:08:24 +00:00
|
|
|
if (haveHBR) {
|
|
|
|
MIB = BuildMI( MBB, findHBRPosition(MBB), DL, get(SPU::HBRA));
|
|
|
|
MIB.addSym(branchLabel);
|
|
|
|
MIB.addMBB(FBB);
|
|
|
|
}
|
|
|
|
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "Inserted conditional branch: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG((*MIB).dump());
|
2009-08-23 11:52:17 +00:00
|
|
|
DEBUG(errs() << "part 2: ");
|
2009-01-02 20:52:08 +00:00
|
|
|
DEBUG((*MIB2).dump());
|
|
|
|
return 2;
|
2008-12-10 00:15:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-03 00:27:53 +00:00
|
|
|
//! Reverses a branch's condition, returning false on success.
|
|
|
|
bool
|
|
|
|
SPUInstrInfo::ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond)
|
|
|
|
const {
|
|
|
|
// Pretty brainless way of inverting the condition, but it works, considering
|
|
|
|
// there are only two conditions...
|
|
|
|
static struct {
|
|
|
|
unsigned Opc; //! The incoming opcode
|
|
|
|
unsigned RevCondOpc; //! The reversed condition opcode
|
|
|
|
} revconds[] = {
|
|
|
|
{ SPU::BRNZr32, SPU::BRZr32 },
|
|
|
|
{ SPU::BRNZv4i32, SPU::BRZv4i32 },
|
|
|
|
{ SPU::BRZr32, SPU::BRNZr32 },
|
|
|
|
{ SPU::BRZv4i32, SPU::BRNZv4i32 },
|
|
|
|
{ SPU::BRHNZr16, SPU::BRHZr16 },
|
|
|
|
{ SPU::BRHNZv8i16, SPU::BRHZv8i16 },
|
|
|
|
{ SPU::BRHZr16, SPU::BRHNZr16 },
|
|
|
|
{ SPU::BRHZv8i16, SPU::BRHNZv8i16 }
|
|
|
|
};
|
|
|
|
|
|
|
|
unsigned Opc = unsigned(Cond[0].getImm());
|
|
|
|
// Pretty dull mapping between the two conditions that SPU can generate:
|
2009-01-07 23:07:29 +00:00
|
|
|
for (int i = sizeof(revconds)/sizeof(revconds[0]) - 1; i >= 0; --i) {
|
2009-01-03 00:27:53 +00:00
|
|
|
if (revconds[i].Opc == Opc) {
|
|
|
|
Cond[0].setImm(revconds[i].RevCondOpc);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2008-12-10 00:15:19 +00:00
|
|
|
|
2009-01-03 00:27:53 +00:00
|
|
|
return true;
|
|
|
|
}
|