mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 21:32:10 +00:00
Sparc: Combine add/or/sethi instruction with restore if possible.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@183088 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0a972fa1ef
commit
65ca7aa57d
@ -82,6 +82,9 @@ namespace {
|
||||
|
||||
bool needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize);
|
||||
|
||||
bool tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI);
|
||||
|
||||
};
|
||||
char Filler::ID = 0;
|
||||
} // end of anonymous namespace
|
||||
@ -100,29 +103,44 @@ FunctionPass *llvm::createSparcDelaySlotFillerPass(TargetMachine &tm) {
|
||||
bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
||||
bool Changed = false;
|
||||
|
||||
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I)
|
||||
if (I->hasDelaySlot()) {
|
||||
MachineBasicBlock::iterator D = MBB.end();
|
||||
MachineBasicBlock::iterator J = I;
|
||||
for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
|
||||
MachineBasicBlock::iterator MI = I;
|
||||
++I;
|
||||
|
||||
if (!DisableDelaySlotFiller)
|
||||
D = findDelayInstr(MBB, I);
|
||||
|
||||
++FilledSlots;
|
||||
Changed = true;
|
||||
|
||||
if (D == MBB.end())
|
||||
BuildMI(MBB, ++J, I->getDebugLoc(), TII->get(SP::NOP));
|
||||
else
|
||||
MBB.splice(++J, &MBB, D);
|
||||
unsigned structSize = 0;
|
||||
if (needsUnimp(I, structSize)) {
|
||||
MachineBasicBlock::iterator J = I;
|
||||
++J; //skip the delay filler.
|
||||
BuildMI(MBB, ++J, I->getDebugLoc(),
|
||||
TII->get(SP::UNIMP)).addImm(structSize);
|
||||
}
|
||||
//If MI is restore, try combining it with previous inst.
|
||||
if (!DisableDelaySlotFiller &&
|
||||
(MI->getOpcode() == SP::RESTORErr
|
||||
|| MI->getOpcode() == SP::RESTOREri)) {
|
||||
Changed |= tryCombineRestoreWithPrevInst(MBB, MI);
|
||||
continue;
|
||||
}
|
||||
|
||||
//If MI has no delay slot, skip
|
||||
if (!MI->hasDelaySlot())
|
||||
continue;
|
||||
|
||||
MachineBasicBlock::iterator D = MBB.end();
|
||||
|
||||
if (!DisableDelaySlotFiller)
|
||||
D = findDelayInstr(MBB, MI);
|
||||
|
||||
++FilledSlots;
|
||||
Changed = true;
|
||||
|
||||
if (D == MBB.end())
|
||||
BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
|
||||
else
|
||||
MBB.splice(I, &MBB, D);
|
||||
|
||||
unsigned structSize = 0;
|
||||
if (needsUnimp(MI, structSize)) {
|
||||
MachineBasicBlock::iterator J = MI;
|
||||
++J; //skip the delay filler.
|
||||
assert (J != MBB.end() && "MI needs a delay instruction.");
|
||||
BuildMI(MBB, ++J, I->getDebugLoc(),
|
||||
TII->get(SP::UNIMP)).addImm(structSize);
|
||||
}
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
@ -332,3 +350,140 @@ bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
|
||||
StructSize = MO.getImm();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
|
||||
MachineBasicBlock::iterator AddMI,
|
||||
const TargetInstrInfo *TII)
|
||||
{
|
||||
//Before: add <op0>, <op1>, %i[0-7]
|
||||
// restore %g0, %g0, %i[0-7]
|
||||
//
|
||||
//After : restore <op0>, <op1>, %o[0-7]
|
||||
|
||||
unsigned reg = AddMI->getOperand(0).getReg();
|
||||
if (reg < SP::I0 || reg > SP::I7)
|
||||
return false;
|
||||
|
||||
//Erase RESTORE
|
||||
RestoreMI->eraseFromParent();
|
||||
|
||||
//Change ADD to RESTORE
|
||||
AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr)
|
||||
? SP::RESTORErr
|
||||
: SP::RESTOREri));
|
||||
|
||||
//map the destination register
|
||||
AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI,
|
||||
MachineBasicBlock::iterator OrMI,
|
||||
const TargetInstrInfo *TII)
|
||||
{
|
||||
//Before: or <op0>, <op1>, %i[0-7]
|
||||
// restore %g0, %g0, %i[0-7]
|
||||
// and <op0> or <op1> is zero,
|
||||
//
|
||||
//After : restore <op0>, <op1>, %o[0-7]
|
||||
|
||||
unsigned reg = OrMI->getOperand(0).getReg();
|
||||
if (reg < SP::I0 || reg > SP::I7)
|
||||
return false;
|
||||
|
||||
//check whether it is a copy
|
||||
if (OrMI->getOpcode() == SP::ORrr
|
||||
&& OrMI->getOperand(1).getReg() != SP::G0
|
||||
&& OrMI->getOperand(2).getReg() != SP::G0)
|
||||
return false;
|
||||
|
||||
if (OrMI->getOpcode() == SP::ORri
|
||||
&& OrMI->getOperand(1).getReg() != SP::G0
|
||||
&& (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0))
|
||||
return false;
|
||||
|
||||
//Erase RESTORE
|
||||
RestoreMI->eraseFromParent();
|
||||
|
||||
//Change OR to RESTORE
|
||||
OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr)
|
||||
? SP::RESTORErr
|
||||
: SP::RESTOREri));
|
||||
|
||||
//map the destination register
|
||||
OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI,
|
||||
MachineBasicBlock::iterator SetHiMI,
|
||||
const TargetInstrInfo *TII)
|
||||
{
|
||||
//Before: sethi imm3, %i[0-7]
|
||||
// restore %g0, %g0, %g0
|
||||
//
|
||||
//After : restore %g0, (imm3<<10), %o[0-7]
|
||||
|
||||
unsigned reg = SetHiMI->getOperand(0).getReg();
|
||||
if (reg < SP::I0 || reg > SP::I7)
|
||||
return false;
|
||||
|
||||
if (!SetHiMI->getOperand(1).isImm())
|
||||
return false;
|
||||
|
||||
int64_t imm = SetHiMI->getOperand(1).getImm();
|
||||
|
||||
//is it a 3 bit immediate?
|
||||
if (!isInt<3>(imm))
|
||||
return false;
|
||||
|
||||
//make it a 13 bit immediate
|
||||
imm = (imm << 10) & 0x1FFF;
|
||||
|
||||
assert(RestoreMI->getOpcode() == SP::RESTORErr);
|
||||
|
||||
RestoreMI->setDesc(TII->get(SP::RESTOREri));
|
||||
|
||||
RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
|
||||
RestoreMI->getOperand(1).setReg(SP::G0);
|
||||
RestoreMI->getOperand(2).ChangeToImmediate(imm);
|
||||
|
||||
|
||||
//Erase the original SETHI
|
||||
SetHiMI->eraseFromParent();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI)
|
||||
{
|
||||
//No previous instruction
|
||||
if (MBBI == MBB.begin())
|
||||
return false;
|
||||
|
||||
//asssert that MBBI is "restore %g0, %g0, %g0"
|
||||
assert(MBBI->getOpcode() == SP::RESTORErr
|
||||
&& MBBI->getOperand(0).getReg() == SP::G0
|
||||
&& MBBI->getOperand(1).getReg() == SP::G0
|
||||
&& MBBI->getOperand(2).getReg() == SP::G0);
|
||||
|
||||
MachineBasicBlock::iterator PrevInst = MBBI; --PrevInst;
|
||||
|
||||
//Cannot combine with a delay filler
|
||||
if (isDelayFiller(MBB, PrevInst))
|
||||
return false;
|
||||
|
||||
switch (PrevInst->getOpcode()) {
|
||||
default: break;
|
||||
case SP::ADDrr:
|
||||
case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break;
|
||||
case SP::ORrr:
|
||||
case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break;
|
||||
case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break;
|
||||
}
|
||||
//Cannot combine with the previous instruction
|
||||
return false;
|
||||
}
|
||||
|
@ -7,10 +7,14 @@
|
||||
define i8* @frameaddr() nounwind readnone {
|
||||
entry:
|
||||
;V8: frameaddr
|
||||
;V8: or %g0, %fp, {{.+}}
|
||||
;V8: save %sp, -96, %sp
|
||||
;V8: jmp %i7+8
|
||||
;V8: restore %g0, %fp, %o0
|
||||
|
||||
;V9: frameaddr
|
||||
;V9: or %g0, %fp, {{.+}}
|
||||
;V9: save %sp, -96, %sp
|
||||
;V9: jmp %i7+8
|
||||
;V9: restore %g0, %fp, %o0
|
||||
%0 = tail call i8* @llvm.frameaddress(i32 0)
|
||||
ret i8* %0
|
||||
}
|
||||
|
@ -105,3 +105,79 @@ entry:
|
||||
|
||||
|
||||
declare i32 @func(i32*)
|
||||
|
||||
|
||||
define i32 @restore_add(i32 %a, i32 %b) {
|
||||
entry:
|
||||
;CHECK: restore_add:
|
||||
;CHECK: jmp %i7+8
|
||||
;CHECK: restore %o0, %i1, %o0
|
||||
%0 = tail call i32 @bar(i32 %a) nounwind
|
||||
%1 = add nsw i32 %0, %b
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @restore_add_imm(i32 %a) {
|
||||
entry:
|
||||
;CHECK: restore_add_imm:
|
||||
;CHECK: jmp %i7+8
|
||||
;CHECK: restore %o0, 20, %o0
|
||||
%0 = tail call i32 @bar(i32 %a) nounwind
|
||||
%1 = add nsw i32 %0, 20
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
define i32 @restore_or(i32 %a) {
|
||||
entry:
|
||||
;CHECK: restore_or:
|
||||
;CHECK: jmp %i7+8
|
||||
;CHECK: restore %g0, %o0, %o0
|
||||
%0 = tail call i32 @bar(i32 %a) nounwind
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
define i32 @restore_or_imm(i32 %a) {
|
||||
entry:
|
||||
;CHECK: restore_or_imm:
|
||||
;CHECK: or %o0, 20, %i0
|
||||
;CHECK: jmp %i7+8
|
||||
;CHECK: restore %g0, %g0, %g0
|
||||
%0 = tail call i32 @bar(i32 %a) nounwind
|
||||
%1 = or i32 %0, 20
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
|
||||
define i32 @restore_sethi(i32 %a) {
|
||||
entry:
|
||||
;CHECK: restore_sethi
|
||||
;CHECK-NOT: sethi 3
|
||||
;CHECK: restore %g0, 3072, %o0
|
||||
%0 = tail call i32 @bar(i32 %a) nounwind
|
||||
%1 = icmp ne i32 %0, 0
|
||||
%2 = select i1 %1, i32 3072, i32 0
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
define i32 @restore_sethi_3bit(i32 %a) {
|
||||
entry:
|
||||
;CHECK: restore_sethi
|
||||
;CHECK: sethi 6
|
||||
;CHECK-NOT: restore %g0, 6144, %o0
|
||||
%0 = tail call i32 @bar(i32 %a) nounwind
|
||||
%1 = icmp ne i32 %0, 0
|
||||
%2 = select i1 %1, i32 6144, i32 0
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
define i32 @restore_sethi_large(i32 %a) {
|
||||
entry:
|
||||
;CHECK: restore_sethi
|
||||
;CHECK: sethi 4000, %i0
|
||||
;CHECK: restore %g0, %g0, %g0
|
||||
%0 = tail call i32 @bar(i32 %a) nounwind
|
||||
%1 = icmp ne i32 %0, 0
|
||||
%2 = select i1 %1, i32 4096000, i32 0
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,22 @@
|
||||
; RUN: llc < %s -march=sparcv9 -disable-sparc-leaf-proc | FileCheck %s
|
||||
; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s
|
||||
; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=OPT
|
||||
|
||||
; CHECK: ret2:
|
||||
; CHECK: or %g0, %i1, %i0
|
||||
|
||||
; OPT: ret2:
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: or %g0, %o1, %o0
|
||||
define i64 @ret2(i64 %a, i64 %b) {
|
||||
ret i64 %b
|
||||
}
|
||||
|
||||
; CHECK: shl_imm
|
||||
; CHECK: sllx %i0, 7, %i0
|
||||
|
||||
; OPT: shl_imm:
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: sllx %o0, 7, %o0
|
||||
define i64 @shl_imm(i64 %a) {
|
||||
%x = shl i64 %a, 7
|
||||
ret i64 %x
|
||||
@ -15,6 +24,10 @@ define i64 @shl_imm(i64 %a) {
|
||||
|
||||
; CHECK: sra_reg
|
||||
; CHECK: srax %i0, %i1, %i0
|
||||
|
||||
; OPT: sra_reg:
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: srax %o0, %o1, %o0
|
||||
define i64 @sra_reg(i64 %a, i64 %b) {
|
||||
%x = ashr i64 %a, %b
|
||||
ret i64 %x
|
||||
@ -27,12 +40,20 @@ define i64 @sra_reg(i64 %a, i64 %b) {
|
||||
;
|
||||
; CHECK: ret_imm0
|
||||
; CHECK: or %g0, 0, %i0
|
||||
|
||||
; OPT: ret_imm0
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: or %g0, 0, %o0
|
||||
define i64 @ret_imm0() {
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
; CHECK: ret_simm13
|
||||
; CHECK: or %g0, -4096, %i0
|
||||
|
||||
; OPT: ret_simm13
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: or %g0, -4096, %o0
|
||||
define i64 @ret_simm13() {
|
||||
ret i64 -4096
|
||||
}
|
||||
@ -41,13 +62,23 @@ define i64 @ret_simm13() {
|
||||
; CHECK: sethi 4, %i0
|
||||
; CHECK-NOT: or
|
||||
; CHECK: restore
|
||||
|
||||
; OPT: ret_sethi
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: sethi 4, %o0
|
||||
define i64 @ret_sethi() {
|
||||
ret i64 4096
|
||||
}
|
||||
|
||||
; CHECK: ret_sethi
|
||||
; CHECK: ret_sethi_or
|
||||
; CHECK: sethi 4, [[R:%[goli][0-7]]]
|
||||
; CHECK: or [[R]], 1, %i0
|
||||
|
||||
; OPT: ret_sethi_or
|
||||
; OPT: sethi 4, [[R:%[go][0-7]]]
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: or [[R]], 1, %o0
|
||||
|
||||
define i64 @ret_sethi_or() {
|
||||
ret i64 4097
|
||||
}
|
||||
@ -55,6 +86,12 @@ define i64 @ret_sethi_or() {
|
||||
; CHECK: ret_nimm33
|
||||
; CHECK: sethi 4, [[R:%[goli][0-7]]]
|
||||
; CHECK: xor [[R]], -4, %i0
|
||||
|
||||
; OPT: ret_nimm33
|
||||
; OPT: sethi 4, [[R:%[go][0-7]]]
|
||||
; OPT: jmp %o7+8
|
||||
; OPT: xor [[R]], -4, %o0
|
||||
|
||||
define i64 @ret_nimm33() {
|
||||
ret i64 -4100
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ if.end:
|
||||
; CHECK: selecti32_xcc
|
||||
; CHECK: subcc %i0, %i1
|
||||
; CHECK: movg %xcc, %i2, %i3
|
||||
; CHECK: or %g0, %i3, %i0
|
||||
; CHECK: restore %g0, %i3, %o0
|
||||
define i32 @selecti32_xcc(i64 %x, i64 %y, i32 %a, i32 %b) {
|
||||
entry:
|
||||
%tobool = icmp sgt i64 %x, %y
|
||||
@ -47,7 +47,7 @@ entry:
|
||||
; CHECK: selecti64_xcc
|
||||
; CHECK: subcc %i0, %i1
|
||||
; CHECK: movg %xcc, %i2, %i3
|
||||
; CHECK: or %g0, %i3, %i0
|
||||
; CHECK: restore %g0, %i3, %o0
|
||||
define i64 @selecti64_xcc(i64 %x, i64 %y, i64 %a, i64 %b) {
|
||||
entry:
|
||||
%tobool = icmp sgt i64 %x, %y
|
||||
@ -58,7 +58,7 @@ entry:
|
||||
; CHECK: selecti64_icc
|
||||
; CHECK: subcc %i0, %i1
|
||||
; CHECK: movg %icc, %i2, %i3
|
||||
; CHECK: or %g0, %i3, %i0
|
||||
; CHECK: restore %g0, %i3, %o0
|
||||
define i64 @selecti64_icc(i32 %x, i32 %y, i64 %a, i64 %b) {
|
||||
entry:
|
||||
%tobool = icmp sgt i32 %x, %y
|
||||
@ -69,7 +69,7 @@ entry:
|
||||
; CHECK: selecti64_fcc
|
||||
; CHECK: fcmps %f1, %f3
|
||||
; CHECK: movul %fcc0, %i2, %i3
|
||||
; CHECK: or %g0, %i3, %i0
|
||||
; CHECK: restore %g0, %i3, %o0
|
||||
define i64 @selecti64_fcc(float %x, float %y, i64 %a, i64 %b) {
|
||||
entry:
|
||||
%tobool = fcmp ult float %x, %y
|
||||
|
Loading…
Reference in New Issue
Block a user