Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -257,9 +257,15 @@ bool hasThumb() const { return getSTI().getFeatureBits()[ARM::HasV4TOps]; } + bool hasThumb2() const { + return getSTI().getFeatureBits()[ARM::FeatureThumb2]; + } bool hasV6Ops() const { return getSTI().getFeatureBits()[ARM::HasV6Ops]; } + bool hasV6T2Ops() const { + return getSTI().getFeatureBits()[ARM::HasV6T2Ops]; + } bool hasV6MOps() const { return getSTI().getFeatureBits()[ARM::HasV6MOps]; } @@ -5247,7 +5253,6 @@ S = Parser.getTok().getLoc(); if (Mnemonic != "ldr") // only parse for ldr pseudo (e.g. ldr r0, =val) return Error(S, "unexpected token in operand"); - Parser.Lex(); // Eat '=' const MCExpr *SubExprVal; if (getParser().parseExpression(SubExprVal)) @@ -6870,10 +6875,10 @@ return true; case ARM::LDRConstPool: case ARM::tLDRConstPool: - case ARM::t2LDRConstPool: { - // Handle the pseudo instruction for ldr rn,= - // For now we always create the constant pool entry and load from it - // FIXME: Use a MOV or MVN when the immediate will fit + case ARM::t2LDRConstPool: { + // Pseudo instruction ldr rt, =immediate is converted to a + // MOV rt, immediate if immediate is known and representable + // otherwise we create a constant pool entry that we load from. MCInst TmpInst; if (Inst.getOpcode() == ARM::LDRConstPool) TmpInst.setOpcode(ARM::LDRi12); @@ -6884,6 +6889,62 @@ const ARMOperand &PoolOperand = static_cast(*Operands[3]); const MCExpr *SubExprVal = PoolOperand.getConstantPoolImm(); + // If SubExprVal is a constant we may be able to use a MOV + if (isa(SubExprVal) && + Inst.getOperand(0).getReg() != ARM::PC && + Inst.getOperand(0).getReg() != ARM::SP) { + int64_t Value = + (int64_t) (cast(SubExprVal))->getValue(); + bool UseMov = true; + bool MovHasS = true; + if (Inst.getOpcode() == ARM::LDRConstPool) { + // ARM Constant + if (ARM_AM::getSOImmVal(Value) != -1) { + Value = ARM_AM::getSOImmVal(Value); + TmpInst.setOpcode(ARM::MOVi); + } + else if (ARM_AM::getSOImmVal(~Value) != -1) { + Value = ARM_AM::getSOImmVal(~Value); + TmpInst.setOpcode(ARM::MVNi); + } + else if (hasV6T2Ops() && + Value >=0 && Value < 65536) { + TmpInst.setOpcode(ARM::MOVi16); + MovHasS = false; + } + else + UseMov = false; + } + else { + // Thumb/Thumb2 Constant + if (hasThumb2() && + ARM_AM::getT2SOImmVal(Value) != -1) + TmpInst.setOpcode(ARM::t2MOVi); + else if (hasThumb2() && + ARM_AM::getT2SOImmVal(~Value) != -1) { + TmpInst.setOpcode(ARM::t2MVNi); + Value = ~Value; + } + else if (hasV8MBaseline() && + Value >=0 && Value < 65536) { + TmpInst.setOpcode(ARM::t2MOVi16); + MovHasS = false; + } + else + UseMov = false; + } + if (UseMov) { + TmpInst.addOperand(Inst.getOperand(0)); // Rt + TmpInst.addOperand(MCOperand::createImm(Value)); // Immediate + TmpInst.addOperand(Inst.getOperand(2)); // CondCode + TmpInst.addOperand(Inst.getOperand(3)); // CondCode + if (MovHasS) + TmpInst.addOperand(MCOperand::createReg(0)); // S + Inst = TmpInst; + return true; + } + } + // No opportunity to use MOV/MVN create constant pool const MCExpr *CPLoc = getTargetStreamer().addConstantPoolEntry(SubExprVal, PoolOperand.getStartLoc()); Index: test/MC/ARM/ldr-pseudo-cond-darwin.s =================================================================== --- /dev/null +++ test/MC/ARM/ldr-pseudo-cond-darwin.s @@ -0,0 +1,55 @@ +@RUN: llvm-mc -triple armv7-base-apple-darwin %s | FileCheck --check-prefix=CHECK-ARM --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv7-base-apple-darwin %s | FileCheck --check-prefix=CHECK-THUMB2 --check-prefix=CHECK %s + +@ +@ Check that ldr to constant pool correctly transfers the condition codes +@ +@ simple test +.section __TEXT,a,regular,pure_instructions +@ CHECK-LABEL: f0: +f0: + it eq + ldreq r0, =0x10002 +@ CHECK: ldreq r0, Ltmp0 + +@ loading multiple constants +.section __TEXT,b,regular,pure_instructions +@ CHECK-LABEL: f1: +f1: + ite eq + ldreq r0, =0x10003 +@ CHECK: ldreq r0, Ltmp1 + ldrne r0, =0x10004 +@ CHECK: ldrne r0, Ltmp2 + +@ transformation to mov +.section __TEXT,d,regular,pure_instructions +@ CHECK-LABEL: f2: +f2: +@ Can use the narrow Thumb mov as it does not set flags in an IT block + it eq + ldreq r1, =0x1 +@ CHECK: moveq r1, #1 + +@ Must use the wide Thumb mov if the constant can't be represented + ite eq + ldreq r2, = 0x1f000000 +@ CHECK-ARM moveq r2, #520093696 +@ CHECK-THUMB2 moveq.w r2, #520093696 + ldrne r3, = 0x00001234 +@ CHECK movwne r2, #4660 + +@ +@ Constant Pools +@ +@ CHECK: .section __TEXT,a,regular,pure_instructions +@ CHECK: .p2align 2 +@ CHECK: Ltmp0: +@ CHECK: .long 65538 + +@ CHECK: .section __TEXT,b,regular,pure_instructions +@ CHECK: .p2align 2 +@ CHECK: Ltmp1: +@ CHECK: .long 65539 +@ CHECK: Ltmp2: +@ CHECK: .long 65540 Index: test/MC/ARM/ldr-pseudo-cond.s =================================================================== --- /dev/null +++ test/MC/ARM/ldr-pseudo-cond.s @@ -0,0 +1,55 @@ +@RUN: llvm-mc -triple armv7-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-ARM --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv7-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-THUMB2 --check-prefix=CHECK %s + +@ +@ Check that ldr to constant pool correctly transfers the condition codes +@ +@ simple test +.section a,"ax",%progbits +@ CHECK-LABEL: f0: +f0: + it eq + ldreq r0, =0x10002 +@ CHECK: ldreq r0, .Ltmp[[TMP0:[0-9]+]] + +@ loading multiple constants +.section b,"ax",%progbits +@ CHECK-LABEL: f1: +f1: + ite eq + ldreq r0, =0x10003 +@ CHECK: ldreq r0, .Ltmp[[TMP1:[0-9]+]] + ldrne r0, =0x10004 +@ CHECK: ldrne r0, .Ltmp[[TMP2:[0-9]+]] + +@ transformation to mov +.section c, "ax", %progbits +@ CHECK-LABEL: f2: +f2: +@ Can use the narrow Thumb mov as it does not set flags in an IT block + it eq + ldreq r1, =0x1 +@ CHECK: moveq r1, #1 + +@ Must use the wide Thumb mov if the constant can't be represented + ite eq + ldreq r2, = 0x1f000000 +@ CHECK-ARM moveq r2, #520093696 +@ CHECK-THUMB2 moveq.w r2, #520093696 + ldrne r3, = 0x00001234 +@ CHECK movwne r2, #4660 + +@ +@ Constant Pools +@ +@ CHECK: .section a,"ax",%progbits +@ CHECK: .p2align 2 +@ CHECK: .Ltmp[[TMP0]] +@ CHECK: .long 65538 + +@ CHECK: .section b,"ax",%progbits +@ CHECK: .p2align 2 +@ CHECK: .Ltmp[[TMP1]] +@ CHECK: .long 65539 +@ CHECK: .Ltmp[[TMP2]] +@ CHECK: .long 65540 Index: test/MC/ARM/ldr-pseudo-darwin.s =================================================================== --- test/MC/ARM/ldr-pseudo-darwin.s +++ test/MC/ARM/ldr-pseudo-darwin.s @@ -4,10 +4,11 @@ @ between darwin and linux. Any tests added here should have a matching @ test added there. -@RUN: llvm-mc -triple armv7-apple-darwin %s | FileCheck %s -@RUN: llvm-mc -triple thumbv5-apple-darwin %s | FileCheck %s -@RUN: llvm-mc -triple thumbv7-apple-darwin %s | FileCheck %s - +@RUN: llvm-mc -triple armv7-base-apple-darwin %s | FileCheck --check-prefix=CHECK-ARM --check-prefix=CHECK %s +@RUN: llvm-mc -triple armv5-base-apple-darwin %s | FileCheck --check-prefix=CHECK-ARMV5 --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv5-base-apple-darwin %s | FileCheck --check-prefix=CHECK-THUMB --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv7-base-apple-darwin %s | FileCheck --check-prefix=CHECK-THUMB2 --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv8m.base-base-apple-darwin %s | FileCheck --check-prefix=CHECK-BASELINE --check-prefix=CHECK %s @ @ Check that large constants are converted to ldr from constant pool @ @@ -152,6 +153,98 @@ @ CHECK: ldr r0, Ltmp15 adds r0, r0, #1 +@ transformation to mov +.section __TEXT,m,regular,pure_instructions +@ CHECK-LABEL: f16: +f16: + +@ Representable in ARM, and Thumb with support mov.w or movw + ldr r1, =0x1 +@ CHECK-ARM: mov r1, #1 +@ CHECK-ARMV5: mov r1, #1 +@ CHECK-THUMB: ldr r1, Ltmp16 +@ CHECK-THUMB2: mov.w r1, #1 +@ CHECK-BASELINE: movw r1, #1 + +@ Immediate is representable in A1 and T2 modified immediate only not movw + ldr r2, =0x120000 +@ CHECK-ARM: mov r2, #1179648 +@ CHECK-ARMV5: mov r2, #1179648 +@ CHECK-THUMB: ldr r2, Ltmp17 +@ CHECK-THUMB2: mov.w r2, #1179648 +@ CHECK-BASELINE: ldr r2, Ltmp16 + +@ Immediate can be represented only with movw instruction + ldr r3, =0x1234 +@ CHECK-ARM: movw r3, #4660 +@ CHECK-ARMV5: ldr r3, Ltmp16 +@ CHECK-THUMB: ldr r3, Ltmp18 +@ CHECK-THUMB2: movw r3, #4660 +@ CHECK-BASELINE: movw r3, #4660 + +@ Immediate can be represented only with T2 modified immediate + ldr r4, =0xabababab +@ CHECK-ARM: ldr r4, Ltmp16 +@ CHECK-ARMV5: ldr r4, Ltmp17 +@ CHECK-THUMB: ldr r4, Ltmp19 +@ CHECK-THUMB2: mov.w r4, #2880154539 +@ CHECK-BASELINE: ldr r4, Ltmp17 + +@ Immediate can be represented only with A1 modified immediate + ldr r5, =0x1000000b +@ CHECK-ARM: mov r5, #268435467 +@ CHECK-ARMV5: mov r5, #268435467 +@ CHECK-THUMB: ldr r5, Ltmp20 +@ CHECK-THUMB2: ldr r5, Ltmp16 +@ CHECK-BASELINE: ldr r5, Ltmp18 + +@ Negative numbers can be used with MVN or in Thumb2 with modified immediate + ldr r6, =-1 +@ CHECK-ARM: mvn r6, #0 +@ CHECK-ARMV5: mvn r6, #0 +@ CHECK-THUMB: ldr r6, Ltmp21 +@ CHECK-THUMB2: mov.w r6, #-1 +@ CHECK-BASELINE: ldr r6, Ltmp19 + ldr r7, =-0x100 +@ CHECK-ARM: mvn r7, #255 +@ CHECK-ARMV5: mvn r7, #255 +@ CHECK-THUMB: ldr r7, Ltmp22 +@ CHECK-THUMB2: mvn r7, #255 +@ CHECK-BASELINE: ldr r7, Ltmp20 + +@ Constant expressions can be used + .equ expr, 0x10 + 0x10 + ldr r0, = expr +@ CHECK-ARM: mov r0, #32 +@ CHECK-ARMV5: mov r0, #32 +@ CHECK-THUMB: ldr r0, Ltmp23 +@ CHECK-THUMB2: mov.w r0, #32 +@ CHECK-BASELINE: movw r0, #32 + ldr r1, = expr - 0x10 +@ CHECK-ARM: mov r1, #16 +@ CHECK-ARMV5: mov r1, #16 +@ CHECK-THUMB: ldr r1, Ltmp24 +@ CHECK-THUMB2: mov.w r1, #16 +@ CHECK-BASELINE: movw r1, #16 + +@ usage of translation in macro +.macro usemov_in_a_macro + ldr r2, =0x3 + ldr r3, =expr +.endm +@ CHECK-LABEL: f17: +f17: + usemov_in_a_macro +@ CHECK-ARM: mov r2, #3 +@ CHECK-ARM: mov r3, #32 +@ CHECK-ARMV5: mov r2, #3 +@ CHECK-ARMV5: mov r3, #32 +@ CHECK-THUMB: ldr r2, Ltmp25 +@ CHECK-THUMB: ldr r3, Ltmp26 +@ CHECK-THUMB2: mov.w r2, #3 +@ CHECK-THUMB2: mov.w r3, #32 +@ CHECK-BASELINE: movw r2, #3 +@ CHECK-BASELINE: movw r3, #32 @ @ Constant Pools @ Index: test/MC/ARM/ldr-pseudo-unpredictable.s =================================================================== --- /dev/null +++ test/MC/ARM/ldr-pseudo-unpredictable.s @@ -0,0 +1,21 @@ +@RUN: llvm-mc -triple armv5-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-ARM %s +@RUN: not llvm-mc -triple thumbv7-unknown-linux-gnueabi %s 2>&1 | FileCheck --check-prefix=CHECK-SP %s +@RUN: not llvm-mc -triple thumbv5-unknown-linux-gnueabi %s 2>&1 | FileCheck --check-prefix=CHECK-NONE %s +@RUN: llvm-mc -triple armv5-base-apple-darwin %s | FileCheck --check-prefix=CHECK-DARWIN-ARM %s +@RUN: not llvm-mc -triple thumbv7-base-apple-darwin %s 2>&1 | FileCheck --check-prefix=CHECK-DARWIN-SP %s +@RUN: not llvm-mc -triple thumbv5-base.apple.darwin %s 2>&1 | FileCheck --check-prefix=CHECK-NONE %s + +@ We dont't do the transformation for rt = sp or pc +@ as it is unpredictable for many of the MOV encondings + ldr pc, = 0x4 +@ CHECK-ARM: ldr pc, .Ltmp[[TMP0:[0-9]+]] +@ CHECK-DARWIN-ARM: ldr pc, Ltmp0 +@ CHECK-SP: error: instruction requires: arm-mode +@ CHECK-DARWIN-SP: error: instruction requires: arm-mode +@ CHECK-NONE: error: instruction requires: arm-mode + ldr sp, = 0x8 +@ CHECK-ARM: ldr sp, .Ltmp[[TMP1:[0-9]+]] +@ CHECK-DARWIN-ARM: ldr sp, Ltmp1 +@ CHECK-SP: ldr.w sp, .Ltmp[[TMP0:[0-9]+]] +@ CHECK-DARWIN-SP: ldr.w sp, Ltmp0 +@ CHECK-NONE: error: instruction requires: arm-mode Index: test/MC/ARM/ldr-pseudo.s =================================================================== --- test/MC/ARM/ldr-pseudo.s +++ test/MC/ARM/ldr-pseudo.s @@ -4,10 +4,11 @@ @ between darwin and linux. Any tests added here should have a matching @ test added there. -@RUN: llvm-mc -triple armv7-unknown-linux-gnueabi %s | FileCheck %s -@RUN: llvm-mc -triple thumbv5-unknown-linux-gnueabi %s | FileCheck %s -@RUN: llvm-mc -triple thumbv7-unknown-linux-gnueabi %s | FileCheck %s - +@RUN: llvm-mc -triple armv7-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-ARM --check-prefix=CHECK %s +@RUN: llvm-mc -triple armv5-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-ARMV5 --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv5-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-THUMB --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv7-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-THUMB2 --check-prefix=CHECK %s +@RUN: llvm-mc -triple thumbv8m.base-unknown-linux-gnueabi %s | FileCheck --check-prefix=CHECK-BASELINE --check-prefix=CHECK %s @ @ Check that large constants are converted to ldr from constant pool @ @@ -152,6 +153,98 @@ @ CHECK: ldr r0, .Ltmp[[TMP15:[0-9]+]] adds r0, r0, #1 +@ transformation to mov +.section m, "ax", %progbits +@ CHECK-LABEL: f16: +f16: + +@ Representable in ARM, and Thumb with support mov.w or movw + ldr r1, =0x1 +@ CHECK-ARM: mov r1, #1 +@ CHECK-ARMV5: mov r1, #1 +@ CHECK-THUMB: ldr r1, .Ltmp[[TMP16:[0-9]+]] +@ CHECK-THUMB2: mov.w r1, #1 +@ CHECK-BASELINE: movw r1, #1 + +@ Immediate is representable in A1 and T2 modified immediate only not movw + ldr r2, =0x120000 +@ CHECK-ARM: mov r2, #1179648 +@ CHECK-ARMV5: mov r2, #1179648 +@ CHECK-THUMB: ldr r2, .Ltmp[[TMP17:[0-9]+]] +@ CHECK-THUMB2: mov.w r2, #1179648 +@ CHECK-BASELINE: ldr r2, .Ltmp[[TMP16:[0-9]+]] + +@ Immediate can be represented only with movw instruction + ldr r3, =0x1234 +@ CHECK-ARM: movw r3, #4660 +@ CHECK-ARMV5: ldr r3, .Ltmp[[TMP16:[0-9]+]] +@ CHECK-THUMB: ldr r3, .Ltmp[[TMP18:[0-9]+]] +@ CHECK-THUMB2: movw r3, #4660 +@ CHECK-BASELINE: movw r3, #4660 + +@ Immediate can be represented only with T2 modified immediate + ldr r4, =0xabababab +@ CHECK-ARM: ldr r4, .Ltmp[[TMP16:[0-9]+]] +@ CHECK-ARMV5: ldr r4, .Ltmp[[TMP17:[0-9]+]] +@ CHECK-THUMB: ldr r4, .Ltmp[[TMP19:[0-9]+]] +@ CHECK-THUMB2: mov.w r4, #2880154539 +@ CHECK-BASELINE: ldr r4, .Ltmp[[TMP17:[0-9]+]] + +@ Immediate can be represented only with A1 modified immediate + ldr r5, =0x1000000b +@ CHECK-ARM: mov r5, #268435467 +@ CHECK-ARMV5: mov r5, #268435467 +@ CHECK-THUMB: ldr r5, .Ltmp[[TMP20:[0-9]+]] +@ CHECK-THUMB2: ldr r5, .Ltmp[[TMP16:[0-9]+]] +@ CHECK-BASELINE: ldr r5, .Ltmp[[TMP18:[0-9]+]] + +@ Negative numbers can be used with MVN or in Thumb2 with modified immediate + ldr r6, =-1 +@ CHECK-ARM: mvn r6, #0 +@ CHECK-ARMV5: mvn r6, #0 +@ CHECK-THUMB: ldr r6, .Ltmp[[TMP21:[0-9]+]] +@ CHECK-THUMB2: mov.w r6, #-1 +@ CHECK-BASELINE: ldr r6, .Ltmp[[TMP19:[0-9]+]] + ldr r7, =-0x100 +@ CHECK-ARM: mvn r7, #255 +@ CHECK-ARMV5: mvn r7, #255 +@ CHECK-THUMB: ldr r7, .Ltmp[[TMP22:[0-9]+]] +@ CHECK-THUMB2: mvn r7, #255 +@ CHECK-BASELINE: ldr r7, .Ltmp[[TMP20:[0-9]+]] + +@ Constant expressions can be used + .equ expr, 0x10 + 0x10 + ldr r0, = expr +@ CHECK-ARM: mov r0, #32 +@ CHECK-ARMV5: mov r0, #32 +@ CHECK-THUMB: ldr r0, .Ltmp[[TMP23:[0-9]+]] +@ CHECK-THUMB2: mov.w r0, #32 +@ CHECK-BASELINE: movw r0, #32 + ldr r1, = expr - 0x10 +@ CHECK-ARM: mov r1, #16 +@ CHECK-ARMV5: mov r1, #16 +@ CHECK-THUMB: ldr r1, .Ltmp[[TMP24:[0-9]+]] +@ CHECK-THUMB2: mov.w r1, #16 +@ CHECK-BASELINE: movw r1, #16 + +@ usage of translation in macro +.macro usemov_in_a_macro + ldr r2, =0x3 + ldr r3, =expr +.endm +@ CHECK-LABEL: f17: +f17: + usemov_in_a_macro +@ CHECK-ARM: mov r2, #3 +@ CHECK-ARM: mov r3, #32 +@ CHECK-ARMV5: mov r2, #3 +@ CHECK-ARMV5: mov r3, #32 +@ CHECK-THUMB: ldr r2, .Ltmp[[TMP25:[0-9]+]] +@ CHECK-THUMB: ldr r3, .Ltmp[[TMP26:[0-9]+]] +@ CHECK-THUMB2: mov.w r2, #3 +@ CHECK-THUMB2: mov.w r3, #32 +@ CHECK-BASELINE: movw r2, #3 +@ CHECK-BASELINE: movw r3, #32 @ @ Constant Pools @