Use movt/movw pair to materialize 32 bit constants on ARMv6T2+.

This should be better than single load from constpool.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@82948 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Anton Korobeynikov 2009-09-27 23:52:58 +00:00
parent 1edaef62a4
commit 6a2fa325c1
5 changed files with 77 additions and 40 deletions

View File

@ -934,19 +934,21 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) {
case ISD::Constant: {
unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
bool UseCP = true;
if (Subtarget->isThumb()) {
if (Subtarget->hasThumb2())
// Thumb2 has the MOVT instruction, so all immediates can
// be done with MOV + MOVT, at worst.
UseCP = 0;
else
if (Subtarget->hasThumb2())
// Thumb2-aware targets have the MOVT instruction, so all immediates can
// be done with MOV + MOVT, at worst.
UseCP = 0;
else {
if (Subtarget->isThumb()) {
UseCP = (Val > 255 && // MOV
~Val > 255 && // MOV + MVN
!ARM_AM::isThumbImmShiftedVal(Val)); // MOV + LSL
} else
UseCP = (ARM_AM::getSOImmVal(Val) == -1 && // MOV
ARM_AM::getSOImmVal(~Val) == -1 && // MVN
!ARM_AM::isSOImmTwoPartVal(Val)); // two instrs.
} else
UseCP = (ARM_AM::getSOImmVal(Val) == -1 && // MOV
ARM_AM::getSOImmVal(~Val) == -1 && // MVN
!ARM_AM::isSOImmTwoPartVal(Val)); // two instrs.
}
if (UseCP) {
SDValue CPIdx =
CurDAG->getTargetConstantPool(ConstantInt::get(

View File

@ -96,6 +96,9 @@ reMaterialize(MachineBasicBlock &MBB,
MachineInstr *MI = MBB.getParent()->CloneMachineInstr(Orig);
MI->getOperand(0).setReg(DestReg);
if (Orig->getOpcode() == ARM::MOVTi16)
MI->getOperand(1).setReg(DestReg);
MBB.insert(I, MI);
}

View File

@ -190,6 +190,27 @@ def bf_inv_mask_imm : Operand<i32>,
let PrintMethod = "printBitfieldInvMaskImmOperand";
}
/// Split a 32-bit immediate into two 16 bit parts.
def lo16 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() & 0xffff,
MVT::i32);
}]>;
def hi16 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32);
}]>;
def lo16AllZero : PatLeaf<(i32 imm), [{
// Returns true if all low 16-bits are 0.
return (((uint32_t)N->getZExtValue()) & 0xFFFFUL) == 0;
}], hi16>;
/// imm0_65535 predicate - True if the 32-bit immediate is in the range
/// [0.65535].
def imm0_65535 : PatLeaf<(i32 imm), [{
return (uint32_t)N->getZExtValue() < 65536;
}]>;
class BinOpFrag<dag res> : PatFrag<(ops node:$LHS, node:$RHS), res>;
class UnOpFrag <dag res> : PatFrag<(ops node:$Src), res>;
@ -897,15 +918,36 @@ def STM : AXI4st<(outs),
let neverHasSideEffects = 1 in
def MOVr : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr,
"mov", " $dst, $src", []>, UnaryDP;
"mov", " $dst, $src", []>, UnaryDP;
def MOVs : AsI1<0b1101, (outs GPR:$dst), (ins so_reg:$src),
DPSoRegFrm, IIC_iMOVsr,
"mov", " $dst, $src", [(set GPR:$dst, so_reg:$src)]>, UnaryDP;
DPSoRegFrm, IIC_iMOVsr,
"mov", " $dst, $src", [(set GPR:$dst, so_reg:$src)]>, UnaryDP;
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def MOVi : AsI1<0b1101, (outs GPR:$dst), (ins so_imm:$src), DPFrm, IIC_iMOVi,
"mov", " $dst, $src", [(set GPR:$dst, so_imm:$src)]>, UnaryDP {
let Inst{25} = 1;
"mov", " $dst, $src", [(set GPR:$dst, so_imm:$src)]>, UnaryDP {
let Inst{25} = 1;
}
let isReMaterializable = 1, isAsCheapAsAMove = 1 in
def MOVi16 : AI1<0b1000, (outs GPR:$dst), (ins i32imm:$src),
DPFrm, IIC_iMOVi,
"movw", " $dst, $src",
[(set GPR:$dst, imm0_65535:$src)]>,
Requires<[IsARM, HasV6T2]> {
let Inst{25} = 1;
}
let isReMaterializable = 1, isAsCheapAsAMove = 1,
Constraints = "$src = $dst" in
def MOVTi16 : AI1<0b1010, (outs GPR:$dst), (ins GPR:$src, i32imm:$imm),
DPFrm, IIC_iMOVi,
"movt", " $dst, $imm",
[(set GPR:$dst,
(or (and GPR:$src, 0xffff),
lo16AllZero:$imm))]>, UnaryDP,
Requires<[IsARM, HasV6T2]> {
let Inst{25} = 1;
}
let Uses = [CPSR] in
@ -1478,6 +1520,10 @@ def : ARMPat<(xor GPR:$LHS, so_imm2part:$RHS),
(EORri (EORri GPR:$LHS, (so_imm2part_1 imm:$RHS)),
(so_imm2part_2 imm:$RHS))>;
def : ARMPat<(i32 imm:$src),
(MOVTi16 (MOVi16 (lo16 imm:$src)), (hi16 imm:$src))>,
Requires<[IsARM, HasV6T2]>;
// TODO: add,sub,and, 3-instr forms?

View File

@ -88,28 +88,6 @@ def imm0_255_neg : PatLeaf<(i32 imm), [{
return (uint32_t)(-N->getZExtValue()) < 255;
}], imm_neg_XFORM>;
/// imm0_65535 predicate - True if the 32-bit immediate is in the range
/// [0.65535].
def imm0_65535 : PatLeaf<(i32 imm), [{
return (uint32_t)N->getZExtValue() < 65536;
}]>;
/// Split a 32-bit immediate into two 16 bit parts.
def t2_lo16 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() & 0xffff,
MVT::i32);
}]>;
def t2_hi16 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32);
}]>;
def t2_lo16AllZero : PatLeaf<(i32 imm), [{
// Returns true if all low 16-bits are 0.
return (((uint32_t)N->getZExtValue()) & 0xFFFFUL) == 0;
}], t2_hi16>;
// Define Thumb2 specific addressing modes.
// t2addrmode_imm12 := reg + imm12
@ -681,12 +659,11 @@ def t2MOVi16 : T2I<(outs GPR:$dst), (ins i32imm:$src), IIC_iMOVi,
"movw", " $dst, $src",
[(set GPR:$dst, imm0_65535:$src)]>;
// FIXME: Also available in ARM mode.
let Constraints = "$src = $dst" in
def t2MOVTi16 : T2sI<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), IIC_iMOVi,
"movt", " $dst, $imm",
[(set GPR:$dst,
(or (and GPR:$src, 0xffff), t2_lo16AllZero:$imm))]>;
(or (and GPR:$src, 0xffff), lo16AllZero:$imm))]>;
//===----------------------------------------------------------------------===//
// Extend Instructions.
@ -1153,4 +1130,4 @@ def : T2Pat<(ARMWrapperJT tjumptable:$dst, imm:$id),
// Large immediate handling.
def : T2Pat<(i32 imm:$src),
(t2MOVTi16 (t2MOVi16 (t2_lo16 imm:$src)), (t2_hi16 imm:$src))>;
(t2MOVTi16 (t2MOVi16 (lo16 imm:$src)), (hi16 imm:$src))>;

View File

@ -0,0 +1,9 @@
; RUN: llc < %s -march=arm -mattr=+thumb2 | FileCheck %s
define i32 @f6(i32 %a) {
; CHECK:f6
; CHECK: movw r0, #1123
; CHECK: movt r0, #1000
%tmp = add i32 0, 65537123
ret i32 %tmp
}