Add branch hinting for SPU.

The implemented algorithm is overly simplistic (just speculate all branches are
taken)- this is work in progress.

llvm-svn: 126651
This commit is contained in:
Kalle Raiskila 2011-02-28 14:08:24 +00:00
parent feb9926a59
commit 612b85e58c
4 changed files with 94 additions and 5 deletions

View File

@ -182,6 +182,10 @@ namespace {
printOp(MI->getOperand(OpNo), O);
}
void printHBROperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
printOp(MI->getOperand(OpNo), O);
}
void printPCRelativeOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
// Used to generate a ".-<target>", but it turns out that the assembler
// really wants the target.
@ -279,6 +283,9 @@ void SPUAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
}
O << *Mang->getSymbol(MO.getGlobal());
return;
case MachineOperand::MO_MCSymbol:
O << *(MO.getMCSymbol());
return;
default:
O << "<unknown operand type: " << MO.getType() << ">";
return;

View File

@ -296,3 +296,25 @@ class Pseudo<dag OOL, dag IOL, string asmstr, list<dag> pattern>
let Pattern = pattern;
let Inst{31-0} = 0;
}
//===----------------------------------------------------------------------===//
// Branch hint formats
//===----------------------------------------------------------------------===//
// For hbrr and hbra
class HBI16Form<bits<7> opcode, dag IOL, string asmstr>
: Instruction {
field bits<32> Inst;
bits<16>i16;
bits<9>RO;
let Namespace = "SPU";
let InOperandList = IOL;
let OutOperandList = (outs); //no output
let AsmString = asmstr;
let Itinerary = BranchHints;
let Inst{0-6} = opcode;
let Inst{7-8} = RO{8-7};
let Inst{9-24} = i16;
let Inst{25-31} = RO{6-0};
}

View File

@ -21,6 +21,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/MC/MCContext.h"
using namespace llvm;
@ -281,9 +282,20 @@ SPUInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
return true;
}
// 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);
}
}
}
unsigned
SPUInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator I = MBB.end();
removeHBR(MBB);
if (I == MBB.begin())
return 0;
--I;
@ -314,6 +326,23 @@ SPUInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
return 2;
}
/** 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;
}
unsigned
SPUInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
@ -324,32 +353,61 @@ SPUInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
assert((Cond.size() == 2 || Cond.size() == 0) &&
"SPU branch conditions have two components!");
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);
// One-way branch.
if (FBB == 0) {
if (Cond.empty()) {
// Unconditional branch
MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(SPU::BR));
MIB = BuildMI(&MBB, DL, get(SPU::BR));
MIB.addMBB(TBB);
DEBUG(errs() << "Inserted one-way uncond branch: ");
DEBUG((*MIB).dump());
// 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);
}
} else {
// Conditional branch
MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
MIB.addReg(Cond[1].getReg()).addMBB(TBB);
if (haveHBR) {
MIB = BuildMI(MBB, findHBRPosition(MBB), DL, get(SPU::HBRA));
MIB.addSym(branchLabel);
MIB.addMBB(TBB);
}
DEBUG(errs() << "Inserted one-way cond branch: ");
DEBUG((*MIB).dump());
}
return 1;
} else {
MachineInstrBuilder MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
MIB = BuildMI(&MBB, DL, get(Cond[0].getImm()));
MachineInstrBuilder MIB2 = BuildMI(&MBB, DL, get(SPU::BR));
// Two-way Conditional Branch.
MIB.addReg(Cond[1].getReg()).addMBB(TBB);
MIB2.addMBB(FBB);
if (haveHBR) {
MIB = BuildMI( MBB, findHBRPosition(MBB), DL, get(SPU::HBRA));
MIB.addSym(branchLabel);
MIB.addMBB(FBB);
}
DEBUG(errs() << "Inserted conditional branch: ");
DEBUG((*MIB).dump());
DEBUG(errs() << "part 2: ");

View File

@ -28,6 +28,8 @@ let hasCtrlDep = 1, Defs = [R1], Uses = [R1] in {
def ADJCALLSTACKUP : Pseudo<(outs), (ins u16imm_i32:$amt),
"${:comment} ADJCALLSTACKUP",
[(callseq_end timm:$amt)]>;
def HBR_LABEL : Pseudo<(outs), (ins hbrtarget:$targ),
"$targ:\t${:comment}branch hint target",[ ]>;
}
//===----------------------------------------------------------------------===//
@ -4208,8 +4210,8 @@ def : Pat<(fabs (v4f32 VECREG:$rA)),
//===----------------------------------------------------------------------===//
// Hint for branch instructions:
//===----------------------------------------------------------------------===//
/* def HBR : SPUInstr<(outs), (ins), "hbr\t" */
def HBRA :
HBI16Form<0b0001001,(ins hbrtarget:$brinst, brtarget:$btarg), "hbra\t$brinst, $btarg">;
//===----------------------------------------------------------------------===//
// Execution, Load NOP (execute NOPs belong in even pipeline, load NOPs belong