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.
This commit is contained in:
parent
203890574d
commit
3c707909b2
5 changed files with 160 additions and 64 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
27
gas/testsuite/gas/arm/thumb2_ldmstm.d
Normal file
27
gas/testsuite/gas/arm/thumb2_ldmstm.d
Normal file
|
@ -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\]!
|
24
gas/testsuite/gas/arm/thumb2_ldmstm.s
Normal file
24
gas/testsuite/gas/arm/thumb2_ldmstm.s
Normal file
|
@ -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}
|
||||
|
Loading…
Add table
Reference in a new issue