diff options
author | Paul Brook <paul@codesourcery.com> | 2007-03-30 14:51:25 +0000 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2007-03-30 14:51:25 +0000 |
commit | 3c707909b23a5458d20df1af10120ddc2c0da00d (patch) | |
tree | 7d95f5f28a5cded1c001d284b1f96b2530dc9305 | |
parent | 203890574da95d16f8c453491026d349be4b2721 (diff) | |
download | gdb-3c707909b23a5458d20df1af10120ddc2c0da00d.zip gdb-3c707909b23a5458d20df1af10120ddc2c0da00d.tar.gz gdb-3c707909b23a5458d20df1af10120ddc2c0da00d.tar.bz2 |
2007-03-30 Paul Brook <paul@codesourcery.com>
gas/
* config/tc-arm.c (encode_thumb2_ldmstm): New function.
(do_t_ldmstm): Generate 16-bit push/pop. Use encode_thumb2_ldmstm.
(do_t_push_pop): Use encode_thumb2_ldmstm.
gas/testsuite/
* gas/arm/thumb2_ldmstm.d: New test.
* gas/arm/thumb2_ldmstm.s: New test.
-rw-r--r-- | gas/ChangeLog | 6 | ||||
-rw-r--r-- | gas/config/tc-arm.c | 162 | ||||
-rw-r--r-- | gas/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gas/testsuite/gas/arm/thumb2_ldmstm.d | 27 | ||||
-rw-r--r-- | gas/testsuite/gas/arm/thumb2_ldmstm.s | 24 |
5 files changed, 160 insertions, 64 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index d629396..7f46533 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2007-03-30 Paul Brook <paul@codesourcery.com> + + * config/tc-arm.c (encode_thumb2_ldmstm): New function. + (do_t_ldmstm): Generate 16-bit push/pop. Use encode_thumb2_ldmstm. + (do_t_push_pop): Use encode_thumb2_ldmstm. + 2007-03-29 DJ Delorie <dj@redhat.com> * config/tc-m32c.c (rl_for, relaxable): Protect argument. diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index e1cd5fc..6b915ba 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -9086,6 +9086,68 @@ do_t_it (void) inst.instruction |= cond << 4; } +/* Helper function used for both push/pop and ldm/stm. */ +static void +encode_thumb2_ldmstm (int base, unsigned mask, bfd_boolean writeback) +{ + bfd_boolean load; + + load = (inst.instruction & (1 << 20)) != 0; + + if (mask & (1 << 13)) + inst.error = _("SP not allowed in register list"); + if (load) + { + if (mask & (1 << 14) + && mask & (1 << 15)) + inst.error = _("LR and PC should not both be in register list"); + + if ((mask & (1 << base)) != 0 + && writeback) + as_warn (_("base register should not be in register list " + "when written back")); + } + else + { + if (mask & (1 << 15)) + inst.error = _("PC not allowed in register list"); + + if (mask & (1 << base)) + as_warn (_("value stored for r%d is UNPREDICTABLE"), base); + } + + if ((mask & (mask - 1)) == 0) + { + /* Single register transfers implemented as str/ldr. */ + if (writeback) + { + if (inst.instruction & (1 << 23)) + inst.instruction = 0x00000b04; /* ia! -> [base], #4 */ + else + inst.instruction = 0x00000d04; /* db! -> [base, #-4]! */ + } + else + { + if (inst.instruction & (1 << 23)) + inst.instruction = 0x00800000; /* ia -> [base] */ + else + inst.instruction = 0x00000c04; /* db -> [base, #-4] */ + } + + inst.instruction |= 0xf8400000; + if (load) + inst.instruction |= 0x00100000; + + mask = ffs(mask) - 1; + mask <<= 12; + } + else if (writeback) + inst.instruction |= WRITE_BACK; + + inst.instruction |= mask; + inst.instruction |= base << 16; +} + static void do_t_ldmstm (void) { @@ -9097,54 +9159,51 @@ do_t_ldmstm (void) if (unified_syntax) { + bfd_boolean narrow; + unsigned mask; + + narrow = FALSE; /* See if we can use a 16-bit instruction. */ if (inst.instruction < 0xffff /* not ldmdb/stmdb */ && inst.size_req != 4 - && inst.operands[0].reg <= 7 - && !(inst.operands[1].imm & ~0xff) - && (inst.instruction == T_MNEM_stmia - ? inst.operands[0].writeback - : (inst.operands[0].writeback - == !(inst.operands[1].imm & (1 << inst.operands[0].reg))))) + && !(inst.operands[1].imm & ~0xff)) { - if (inst.instruction == T_MNEM_stmia - && (inst.operands[1].imm & (1 << inst.operands[0].reg)) - && (inst.operands[1].imm & ((1 << inst.operands[0].reg) - 1))) - as_warn (_("value stored for r%d is UNPREDICTABLE"), - inst.operands[0].reg); + mask = 1 << inst.operands[0].reg; - inst.instruction = THUMB_OP16 (inst.instruction); - inst.instruction |= inst.operands[0].reg << 8; - inst.instruction |= inst.operands[1].imm; - } - else - { - if (inst.operands[1].imm & (1 << 13)) - as_warn (_("SP should not be in register list")); - if (inst.instruction == T_MNEM_stmia) + if (inst.operands[0].reg <= 7 + && (inst.instruction == T_MNEM_stmia + ? inst.operands[0].writeback + : (inst.operands[0].writeback + == !(inst.operands[1].imm & mask)))) { - if (inst.operands[1].imm & (1 << 15)) - as_warn (_("PC should not be in register list")); - if (inst.operands[1].imm & (1 << inst.operands[0].reg)) + if (inst.instruction == T_MNEM_stmia + && (inst.operands[1].imm & mask) + && (inst.operands[1].imm & (mask - 1))) as_warn (_("value stored for r%d is UNPREDICTABLE"), inst.operands[0].reg); + + inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction |= inst.operands[0].reg << 8; + inst.instruction |= inst.operands[1].imm; + narrow = TRUE; } - else + else if (inst.operands[0] .reg == REG_SP + && inst.operands[0].writeback) { - if (inst.operands[1].imm & (1 << 14) - && inst.operands[1].imm & (1 << 15)) - as_warn (_("LR and PC should not both be in register list")); - if ((inst.operands[1].imm & (1 << inst.operands[0].reg)) - && inst.operands[0].writeback) - as_warn (_("base register should not be in register list " - "when written back")); + inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia + ? T_MNEM_push : T_MNEM_pop); + inst.instruction |= inst.operands[1].imm; + narrow = TRUE; } + } + + if (!narrow) + { if (inst.instruction < 0xffff) inst.instruction = THUMB_OP32 (inst.instruction); - inst.instruction |= inst.operands[0].reg << 16; - inst.instruction |= inst.operands[1].imm; - if (inst.operands[0].writeback) - inst.instruction |= WRITE_BACK; + + encode_thumb2_ldmstm(inst.operands[0].reg, inst.operands[1].imm, + inst.operands[0].writeback); } } else @@ -9833,7 +9892,7 @@ do_t_push_pop (void) mask = inst.operands[0].imm; if ((mask & ~0xff) == 0) - inst.instruction = THUMB_OP16 (inst.instruction); + inst.instruction = THUMB_OP16 (inst.instruction) | mask; else if ((inst.instruction == T_MNEM_push && (mask & ~0xff) == 1 << REG_LR) || (inst.instruction == T_MNEM_pop @@ -9841,43 +9900,18 @@ do_t_push_pop (void) { inst.instruction = THUMB_OP16 (inst.instruction); inst.instruction |= THUMB_PP_PC_LR; - mask &= 0xff; + inst.instruction |= mask & 0xff; } else if (unified_syntax) { - if (mask & (1 << 13)) - inst.error = _("SP not allowed in register list"); - if (inst.instruction == T_MNEM_push) - { - if (mask & (1 << 15)) - inst.error = _("PC not allowed in register list"); - } - else - { - if (mask & (1 << 14) - && mask & (1 << 15)) - inst.error = _("LR and PC should not both be in register list"); - } - if ((mask & (mask - 1)) == 0) - { - /* Single register push/pop implemented as str/ldr. */ - if (inst.instruction == T_MNEM_push) - inst.instruction = 0xf84d0d04; /* str reg, [sp, #-4]! */ - else - inst.instruction = 0xf85d0b04; /* ldr reg, [sp], #4 */ - mask = ffs(mask) - 1; - mask <<= 12; - } - else - inst.instruction = THUMB_OP32 (inst.instruction); + inst.instruction = THUMB_OP32 (inst.instruction); + encode_thumb2_ldmstm(13, mask, TRUE); } else { inst.error = _("invalid register list to push/pop instruction"); return; } - - inst.instruction |= mask; } static void diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 7397508..bb7be0a 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-03-30 Paul Brook <paul@codesourcery.com> + + * gas/arm/thumb2_ldmstm.d: New test. + * gas/arm/thumb2_ldmstm.s: New test. + 2007-03-27 Alan Modra <amodra@bigpond.net.au> * gas/ppc/reloc.s: New. diff --git a/gas/testsuite/gas/arm/thumb2_ldmstm.d b/gas/testsuite/gas/arm/thumb2_ldmstm.d new file mode 100644 index 0000000..2f50486 --- /dev/null +++ b/gas/testsuite/gas/arm/thumb2_ldmstm.d @@ -0,0 +1,27 @@ +# name: Thumb-2 LDM/STM single reg +# as: -march=armv6t2 +# objdump: -dr --prefix-addresses --show-raw-insn + +.*: +file format .*arm.* + +Disassembly of section .text: +0[0-9a-f]+ <[^>]+> bc01 pop {r0} +0[0-9a-f]+ <[^>]+> f85d 8b04 ldr.w r8, \[sp\], #4 +0[0-9a-f]+ <[^>]+> f8d1 9000 ldr.w r9, \[r1\] +0[0-9a-f]+ <[^>]+> f852 cb04 ldr.w ip, \[r2\], #4 +0[0-9a-f]+ <[^>]+> f85d 2d04 ldr.w r2, \[sp, #-4\]! +0[0-9a-f]+ <[^>]+> f85d 8d04 ldr.w r8, \[sp, #-4\]! +0[0-9a-f]+ <[^>]+> f856 4c04 ldr.w r4, \[r6, #-4\] +0[0-9a-f]+ <[^>]+> f856 8c04 ldr.w r8, \[r6, #-4\] +0[0-9a-f]+ <[^>]+> f852 4d04 ldr.w r4, \[r2, #-4\]! +0[0-9a-f]+ <[^>]+> f852 cd04 ldr.w ip, \[r2, #-4\]! +0[0-9a-f]+ <[^>]+> b408 push {r3} +0[0-9a-f]+ <[^>]+> f84d 9b04 str.w r9, \[sp\], #4 +0[0-9a-f]+ <[^>]+> f8c3 c000 str.w ip, \[r3\] +0[0-9a-f]+ <[^>]+> f844 cb04 str.w ip, \[r4\], #4 +0[0-9a-f]+ <[^>]+> f84d 3d04 str.w r3, \[sp, #-4\]! +0[0-9a-f]+ <[^>]+> f84d 9d04 str.w r9, \[sp, #-4\]! +0[0-9a-f]+ <[^>]+> f847 5c04 str.w r5, \[r7, #-4\] +0[0-9a-f]+ <[^>]+> f846 cc04 str.w ip, \[r6, #-4\] +0[0-9a-f]+ <[^>]+> f846 bd04 str.w fp, \[r6, #-4\]! +0[0-9a-f]+ <[^>]+> f845 8d04 str.w r8, \[r5, #-4\]! diff --git a/gas/testsuite/gas/arm/thumb2_ldmstm.s b/gas/testsuite/gas/arm/thumb2_ldmstm.s new file mode 100644 index 0000000..fd4410a --- /dev/null +++ b/gas/testsuite/gas/arm/thumb2_ldmstm.s @@ -0,0 +1,24 @@ +.syntax unified +.thumb +ldmstm: + ldmia sp!, {r0} + ldmia sp!, {r8} + ldmia r1, {r9} + ldmia r2!, {ip} + ldmdb sp!, {r2} + ldmdb sp!, {r8} + ldmdb r6, {r4} + ldmdb r6, {r8} + ldmdb r2!, {r4} + ldmdb r2!, {ip} + stmia sp!, {r3} + stmia sp!, {r9} + stmia r3, {ip} + stmia r4!, {ip} + stmdb sp!, {r3} + stmdb sp!, {r9} + stmdb r7, {r5} + stmdb r6, {ip} + stmdb r6!, {fp} + stmdb r5!, {r8} + |