Thumb1 register to register MOV instruction is predicable.

Fix a FIXME and allow predication (in Thumb2) for the T1 register to
register MOV instructions. This allows some better codegen with
if-conversion (as seen in the test updates), plus it lays the groundwork
for pseudo-izing the tMOVCC instructions.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134197 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jim Grosbach
2011-06-30 22:10:46 +00:00
parent 2541c41f3e
commit 63b46faeb8
10 changed files with 67 additions and 59 deletions

View File

@@ -1223,6 +1223,9 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
TmpInst.setOpcode(ARM::tMOVr); TmpInst.setOpcode(ARM::tMOVr);
TmpInst.addOperand(MCOperand::CreateReg(ARM::LR)); TmpInst.addOperand(MCOperand::CreateReg(ARM::LR));
TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); TmpInst.addOperand(MCOperand::CreateReg(ARM::PC));
// Add predicate operands.
TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
TmpInst.addOperand(MCOperand::CreateReg(0));
OutStreamer.EmitInstruction(TmpInst); OutStreamer.EmitInstruction(TmpInst);
} }
{ {
@@ -1610,8 +1613,9 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
TmpInst.setOpcode(ARM::tMOVgpr2tgpr); TmpInst.setOpcode(ARM::tMOVgpr2tgpr);
TmpInst.addOperand(MCOperand::CreateReg(ValReg)); TmpInst.addOperand(MCOperand::CreateReg(ValReg));
TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); TmpInst.addOperand(MCOperand::CreateReg(ARM::PC));
// 's' bit operand // Predicate.
TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
TmpInst.addOperand(MCOperand::CreateReg(0));
OutStreamer.AddComment("eh_setjmp begin"); OutStreamer.AddComment("eh_setjmp begin");
OutStreamer.EmitInstruction(TmpInst); OutStreamer.EmitInstruction(TmpInst);
} }

View File

@@ -268,14 +268,14 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
// bic r4, r4, MaxAlign // bic r4, r4, MaxAlign
// mov sp, r4 // mov sp, r4
// FIXME: It will be better just to find spare register here. // FIXME: It will be better just to find spare register here.
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2tgpr), ARM::R4) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2tgpr), ARM::R4)
.addReg(ARM::SP, RegState::Kill); .addReg(ARM::SP, RegState::Kill));
AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl,
TII.get(ARM::t2BICri), ARM::R4) TII.get(ARM::t2BICri), ARM::R4)
.addReg(ARM::R4, RegState::Kill) .addReg(ARM::R4, RegState::Kill)
.addImm(MaxAlign-1))); .addImm(MaxAlign-1)));
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP)
.addReg(ARM::R4, RegState::Kill); .addReg(ARM::R4, RegState::Kill));
} }
AFI->setShouldRestoreSPFromFP(true); AFI->setShouldRestoreSPFromFP(true);
@@ -293,9 +293,9 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
.addReg(ARM::SP) .addReg(ARM::SP)
.addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); .addImm((unsigned)ARMCC::AL).addReg(0).addReg(0);
else else
BuildMI(MBB, MBBI, dl, AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),
TII.get(ARM::tMOVgpr2gpr), RegInfo->getBaseRegister()) RegInfo->getBaseRegister())
.addReg(ARM::SP); .addReg(ARM::SP));
} }
// If the frame has variable sized objects then the epilogue must restore // If the frame has variable sized objects then the epilogue must restore
@@ -364,8 +364,9 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
"No scratch register to restore SP from FP!"); "No scratch register to restore SP from FP!");
emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes, emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
ARMCC::AL, 0, TII); ARMCC::AL, 0, TII);
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),
.addReg(ARM::R4); ARM::SP)
.addReg(ARM::R4));
} }
} else { } else {
// Thumb2 or ARM. // Thumb2 or ARM.
@@ -373,8 +374,9 @@ void ARMFrameLowering::emitEpilogue(MachineFunction &MF,
BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP) BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP)
.addReg(FramePtr).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); .addReg(FramePtr).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0);
else else
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),
.addReg(FramePtr); ARM::SP)
.addReg(FramePtr));
} }
} else if (NumBytes) } else if (NumBytes)
emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes);

View File

@@ -409,7 +409,7 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1,
hasExtraDefRegAllocReq = 1 in hasExtraDefRegAllocReq = 1 in
def tPOP_RET : tPseudoInst<(outs), (ins pred:$p, reglist:$regs, variable_ops), def tPOP_RET : tPseudoInst<(outs), (ins pred:$p, reglist:$regs, variable_ops),
Size4Bytes, IIC_iPop_Br, []>; Size2Bytes, IIC_iPop_Br, []>;
// All calls clobber the non-callee saved registers. SP is marked as a use to // All calls clobber the non-callee saved registers. SP is marked as a use to
// prevent stack-pointer assignments that appear immediately before calls from // prevent stack-pointer assignments that appear immediately before calls from
@@ -1054,9 +1054,9 @@ def tMOVi8 : T1sI<(outs tGPR:$Rd), (ins imm0_255:$imm8), IIC_iMOVi,
// TODO: A7-73: MOV(2) - mov setting flag. // TODO: A7-73: MOV(2) - mov setting flag.
let neverHasSideEffects = 1 in { let neverHasSideEffects = 1 in {
// FIXME: Make this predicable. def tMOVr : Thumb1pI<(outs tGPR:$Rd), (ins tGPR:$Rm), AddrModeNone,
def tMOVr : T1I<(outs tGPR:$Rd), (ins tGPR:$Rm), IIC_iMOVr, Size2Bytes, IIC_iMOVr,
"mov\t$Rd, $Rm", []>, "mov", "\t$Rd, $Rm", "", []>,
T1Special<0b1000> { T1Special<0b1000> {
// A8.6.97 // A8.6.97
bits<4> Rd; bits<4> Rd;
@@ -1076,9 +1076,10 @@ def tMOVSr : T1I<(outs tGPR:$Rd), (ins tGPR:$Rm), IIC_iMOVr,
let Inst{2-0} = Rd; let Inst{2-0} = Rd;
} }
// FIXME: Make these predicable. // FIXME: Do we really need separate instructions for GPR<-->tGPR like this?
def tMOVgpr2tgpr : T1I<(outs tGPR:$Rd), (ins GPR:$Rm), IIC_iMOVr, // They all map to the same instruction (MOV encoding T1).
"mov\t$Rd, $Rm", []>, def tMOVgpr2tgpr : Thumb1pI<(outs tGPR:$Rd), (ins GPR:$Rm), AddrModeNone,
Size2Bytes, IIC_iMOVr, "mov", "\t$Rd, $Rm", "", []>,
T1Special<{1,0,0,?}> { T1Special<{1,0,0,?}> {
// A8.6.97 // A8.6.97
bits<4> Rd; bits<4> Rd;
@@ -1087,8 +1088,8 @@ def tMOVgpr2tgpr : T1I<(outs tGPR:$Rd), (ins GPR:$Rm), IIC_iMOVr,
let Inst{6-3} = Rm; let Inst{6-3} = Rm;
let Inst{2-0} = Rd{2-0}; let Inst{2-0} = Rd{2-0};
} }
def tMOVtgpr2gpr : T1I<(outs GPR:$Rd), (ins tGPR:$Rm), IIC_iMOVr, def tMOVtgpr2gpr : Thumb1pI<(outs GPR:$Rd), (ins tGPR:$Rm), AddrModeNone,
"mov\t$Rd, $Rm", []>, Size2Bytes, IIC_iMOVr, "mov", "\t$Rd, $Rm", "", []>,
T1Special<{1,0,?,0}> { T1Special<{1,0,?,0}> {
// A8.6.97 // A8.6.97
bits<4> Rd; bits<4> Rd;
@@ -1098,8 +1099,8 @@ def tMOVtgpr2gpr : T1I<(outs GPR:$Rd), (ins tGPR:$Rm), IIC_iMOVr,
let Inst{5-3} = Rm{2-0}; let Inst{5-3} = Rm{2-0};
let Inst{2-0} = Rd{2-0}; let Inst{2-0} = Rd{2-0};
} }
def tMOVgpr2gpr : T1I<(outs GPR:$Rd), (ins GPR:$Rm), IIC_iMOVr, def tMOVgpr2gpr : Thumb1pI<(outs GPR:$Rd), (ins GPR:$Rm), AddrModeNone,
"mov\t$Rd, $Rm", []>, Size2Bytes, IIC_iMOVr, "mov", "\t$Rd, $Rm", "", []>,
T1Special<{1,0,?,?}> { T1Special<{1,0,?,?}> {
// A8.6.97 // A8.6.97
bits<4> Rd; bits<4> Rd;

View File

@@ -1882,8 +1882,7 @@ GetMnemonicAcceptInfo(StringRef Mnemonic, bool &CanAcceptCarrySet,
if (isThumb) if (isThumb)
if (Mnemonic == "bkpt" || Mnemonic == "mcr" || Mnemonic == "mcrr" || if (Mnemonic == "bkpt" || Mnemonic == "mcr" || Mnemonic == "mcrr" ||
Mnemonic == "mrc" || Mnemonic == "mrrc" || Mnemonic == "cdp" || Mnemonic == "mrc" || Mnemonic == "mrrc" || Mnemonic == "cdp")
(Mnemonic == "mov" && isThumbOne))
CanAcceptPredicationCode = false; CanAcceptPredicationCode = false;
} }

View File

@@ -160,7 +160,8 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF) const {
// will be allocated after this, so we can still use the base pointer // will be allocated after this, so we can still use the base pointer
// to reference locals. // to reference locals.
if (RegInfo->hasBasePointer(MF)) if (RegInfo->hasBasePointer(MF))
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), BasePtr).addReg(ARM::SP); AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), BasePtr)
.addReg(ARM::SP));
// If the frame has variable sized objects then the epilogue must restore // If the frame has variable sized objects then the epilogue must restore
// the sp from fp. We can assume there's an FP here since hasFP already // the sp from fp. We can assume there's an FP here since hasFP already
@@ -239,11 +240,13 @@ void Thumb1FrameLowering::emitEpilogue(MachineFunction &MF,
"No scratch register to restore SP from FP!"); "No scratch register to restore SP from FP!");
emitThumbRegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes, emitThumbRegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes,
TII, *RegInfo); TII, *RegInfo);
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr),
.addReg(ARM::R4); ARM::SP)
.addReg(ARM::R4));
} else } else
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr),
.addReg(FramePtr); ARM::SP)
.addReg(FramePtr));
} else { } else {
if (MBBI->getOpcode() == ARM::tBX_RET && if (MBBI->getOpcode() == ARM::tBX_RET &&
&MBB.front() != MBBI && &MBB.front() != MBBI &&

View File

@@ -46,8 +46,8 @@ void Thumb1InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
else if (tDest) else if (tDest)
Opc = ARM::tMOVgpr2tgpr; Opc = ARM::tMOVgpr2tgpr;
BuildMI(MBB, I, DL, get(Opc), DestReg) AddDefaultPred(BuildMI(MBB, I, DL, get(Opc), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc)); .addReg(SrcReg, getKillRegState(KillSrc)));
assert(ARM::GPRRegClass.contains(DestReg, SrcReg) && assert(ARM::GPRRegClass.contains(DestReg, SrcReg) &&
"Thumb1 can only copy GPR registers"); "Thumb1 can only copy GPR registers");
} }

View File

@@ -244,8 +244,8 @@ void llvm::emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
AddDefaultT1CC(BuildMI(MBB, MBBI, dl, MCID, DestReg).setMIFlags(MIFlags)); AddDefaultT1CC(BuildMI(MBB, MBBI, dl, MCID, DestReg).setMIFlags(MIFlags));
AddDefaultPred(MIB.addReg(BaseReg, RegState::Kill).addImm(ThisVal)); AddDefaultPred(MIB.addReg(BaseReg, RegState::Kill).addImm(ThisVal));
} else { } else {
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), DestReg) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr), DestReg)
.addReg(BaseReg, RegState::Kill) .addReg(BaseReg, RegState::Kill))
.setMIFlags(MIFlags); .setMIFlags(MIFlags);
} }
BaseReg = DestReg; BaseReg = DestReg;
@@ -419,11 +419,10 @@ rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx,
// Turn it into a move. // Turn it into a move.
MI.setDesc(TII.get(ARM::tMOVgpr2tgpr)); MI.setDesc(TII.get(ARM::tMOVgpr2tgpr));
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false); MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
// Remove offset and remaining explicit predicate operands. // Remove offset and add predicate operands.
do MI.RemoveOperand(FrameRegIdx+1); MI.RemoveOperand(FrameRegIdx+1);
while (MI.getNumOperands() > FrameRegIdx+1 && MachineInstrBuilder MIB(&MI);
(!MI.getOperand(FrameRegIdx+1).isReg() || AddDefaultPred(MIB);
!MI.getOperand(FrameRegIdx+1).isImm()));
return true; return true;
} }
@@ -565,8 +564,9 @@ Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB,
// the function, the offset will be negative. Use R12 instead since that's // the function, the offset will be negative. Use R12 instead since that's
// a call clobbered register that we know won't be used in Thumb1 mode. // a call clobbered register that we know won't be used in Thumb1 mode.
DebugLoc DL; DebugLoc DL;
BuildMI(MBB, I, DL, TII.get(ARM::tMOVtgpr2gpr)). AddDefaultPred(BuildMI(MBB, I, DL, TII.get(ARM::tMOVtgpr2gpr))
addReg(ARM::R12, RegState::Define).addReg(Reg, RegState::Kill); .addReg(ARM::R12, RegState::Define)
.addReg(Reg, RegState::Kill));
// The UseMI is where we would like to restore the register. If there's // The UseMI is where we would like to restore the register. If there's
// interference with R12 before then, however, we'll need to restore it // interference with R12 before then, however, we'll need to restore it
@@ -589,8 +589,8 @@ Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB,
} }
} }
// Restore the register from R12 // Restore the register from R12
BuildMI(MBB, UseMI, DL, TII.get(ARM::tMOVgpr2tgpr)). AddDefaultPred(BuildMI(MBB, UseMI, DL, TII.get(ARM::tMOVgpr2tgpr)).
addReg(Reg, RegState::Define).addReg(ARM::R12, RegState::Kill); addReg(Reg, RegState::Define).addReg(ARM::R12, RegState::Kill));
return true; return true;
} }

View File

@@ -122,8 +122,8 @@ void Thumb2InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
else if (tDest) else if (tDest)
Opc = ARM::tMOVgpr2tgpr; Opc = ARM::tMOVgpr2tgpr;
BuildMI(MBB, I, DL, get(Opc), DestReg) AddDefaultPred(BuildMI(MBB, I, DL, get(Opc), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc)); .addReg(SrcReg, getKillRegState(KillSrc)));
} }
void Thumb2InstrInfo:: void Thumb2InstrInfo::
@@ -231,8 +231,8 @@ void llvm::emitT2RegPlusImmediate(MachineBasicBlock &MBB,
unsigned Opc = 0; unsigned Opc = 0;
if (DestReg == ARM::SP && BaseReg != ARM::SP) { if (DestReg == ARM::SP && BaseReg != ARM::SP) {
// mov sp, rn. Note t2MOVr cannot be used. // mov sp, rn. Note t2MOVr cannot be used.
BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),DestReg) AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),DestReg)
.addReg(BaseReg).setMIFlags(MIFlags); .addReg(BaseReg).setMIFlags(MIFlags));
BaseReg = ARM::SP; BaseReg = ARM::SP;
continue; continue;
} }
@@ -413,9 +413,9 @@ bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false); MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
// Remove offset and remaining explicit predicate operands. // Remove offset and remaining explicit predicate operands.
do MI.RemoveOperand(FrameRegIdx+1); do MI.RemoveOperand(FrameRegIdx+1);
while (MI.getNumOperands() > FrameRegIdx+1 && while (MI.getNumOperands() > FrameRegIdx+1);
(!MI.getOperand(FrameRegIdx+1).isReg() || MachineInstrBuilder MIB(&MI);
!MI.getOperand(FrameRegIdx+1).isImm())); AddDefaultPred(MIB);
return true; return true;
} }

View File

@@ -1,13 +1,11 @@
; RUN: llc < %s | FileCheck %s ; RUN: llc -mtriple=thumbv7-apple-darwin10 < %s | FileCheck %s
target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
target triple = "thumbv7-apple-darwin10"
%struct.op = type { %struct.op*, %struct.op*, %struct.op* ()*, i32, i16, i16, i8, i8 } %struct.op = type { %struct.op*, %struct.op*, %struct.op* ()*, i32, i16, i16, i8, i8 }
; CHECK: Perl_ck_sort ; CHECK: Perl_ck_sort
; CHECK: ldr ; CHECK: ldreq
; CHECK: mov [[REGISTER:(r[0-9]+)|(lr)]] ; CHECK: moveq [[REGISTER:(r[0-9]+)|(lr)]]
; CHECK: str {{(r[0-9])|(lr)}}, {{\[}}[[REGISTER]]{{\]}}, #24 ; CHECK: streq {{(r[0-9])|(lr)}}, {{\[}}[[REGISTER]]{{\]}}, #24
define void @Perl_ck_sort() nounwind optsize { define void @Perl_ck_sort() nounwind optsize {
entry: entry:

View File

@@ -70,8 +70,9 @@ entry:
define void @t3(i32 %a, i32 %b) nounwind { define void @t3(i32 %a, i32 %b) nounwind {
entry: entry:
; CHECK: t3: ; CHECK: t3:
; CHECK: it lt ; CHECK: itt ge
; CHECK: poplt {r7, pc} ; CHECK: movge r0, r1
; CHECK: blge _foo
%tmp1 = icmp sgt i32 %a, 10 ; <i1> [#uses=1] %tmp1 = icmp sgt i32 %a, 10 ; <i1> [#uses=1]
br i1 %tmp1, label %cond_true, label %UnifiedReturnBlock br i1 %tmp1, label %cond_true, label %UnifiedReturnBlock