From 6a2fa325c1763a0fb27eceaa78b3a9bf683416bf Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 27 Sep 2009 23:52:58 +0000 Subject: [PATCH] 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 --- lib/Target/ARM/ARMISelDAGToDAG.cpp | 22 ++++++------ lib/Target/ARM/ARMInstrInfo.cpp | 3 ++ lib/Target/ARM/ARMInstrInfo.td | 56 +++++++++++++++++++++++++++--- lib/Target/ARM/ARMInstrThumb2.td | 27 ++------------ test/CodeGen/ARM/t2-imm.ll | 9 +++++ 5 files changed, 77 insertions(+), 40 deletions(-) create mode 100644 test/CodeGen/ARM/t2-imm.ll diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index a37c7c5a026..d165a09997e 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -934,19 +934,21 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { case ISD::Constant: { unsigned Val = cast(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( diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp index 4c92891c82b..15c3c393c32 100644 --- a/lib/Target/ARM/ARMInstrInfo.cpp +++ b/lib/Target/ARM/ARMInstrInfo.cpp @@ -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); } diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 329a7a53cc6..0e9e67709dd 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -190,6 +190,27 @@ def bf_inv_mask_imm : Operand, let PrintMethod = "printBitfieldInvMaskImmOperand"; } +/// Split a 32-bit immediate into two 16 bit parts. +def lo16 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() & 0xffff, + MVT::i32); +}]>; + +def hi16 : SDNodeXFormgetTargetConstant((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 : PatFrag<(ops node:$LHS, node:$RHS), res>; class UnOpFrag : 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? diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index 3d8e1a709db..d0fe4329634 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -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 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() & 0xffff, - MVT::i32); -}]>; - -def t2_hi16 : SDNodeXFormgetTargetConstant((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))>; diff --git a/test/CodeGen/ARM/t2-imm.ll b/test/CodeGen/ARM/t2-imm.ll new file mode 100644 index 00000000000..8b619bfef3e --- /dev/null +++ b/test/CodeGen/ARM/t2-imm.ll @@ -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 +}