#define T_OPCODE_BRANCH 0xe000
+#define T_OPCODE_STMFD 0xe9000000
+
#define THUMB_SIZE 2 /* Size of thumb instruction. */
#define THUMB_PP_PC_LR 0x0100
#define THUMB_LOAD_BIT 0x0800
inst.instruction |= base << 16;
}
+static void do_t_push_pop (void);
+
static void
do_t_ldmstm (void)
{
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[1].imm & ~0xff))
+ /* Try to convert ldm/stm to a 16-bit instruction. */
+ /* First, handle SP as the base. */
+ if (inst.operands[0].reg == REG_SP)
+ {
+ /* Try converting to push/pop. */
+ if (inst.operands[0].writeback
+ && (inst.instruction == T_OPCODE_STMFD /* Push. */
+ || inst.instruction == T_MNEM_ldmia)) /* Pop. */
+ {
+ inst.instruction = (inst.instruction == T_MNEM_ldmia
+ ? T_MNEM_pop
+ : T_MNEM_push);
+ inst.operands[0] = inst.operands[1];
+ do_t_push_pop ();
+ return;
+ }
+ /* For single registers try a simple ldr/str. */
+ if (!inst.operands[0].writeback
+ && (inst.instruction == T_MNEM_stmia
+ || inst.instruction == T_MNEM_ldmia)
+ && (inst.operands[1].imm & (inst.operands[1].imm - 1)) == 0)
+ {
+ unsigned long opcode = T_MNEM_str_sp;
+ if (inst.instruction == T_MNEM_ldmia)
+ opcode = T_MNEM_ldr_sp;
+ inst.instruction = THUMB_OP16 (opcode);
+ inst.instruction |= ((ffs (inst.operands[1].imm) - 1) << 8);
+ narrow = true;
+ }
+ }
+ /* For ldmia/stmia with all low registers we can try 16-bit
+ encodings. */
+ else if (inst.size_req != 4
+ && (inst.instruction == T_MNEM_ldmia
+ || inst.instruction == T_MNEM_stmia)
+ && inst.operands[0].reg <= 7
+ && !(inst.operands[1].imm & ~0xff))
{
- mask = 1 << inst.operands[0].reg;
+ /* For single registers try a simple ldr/str. */
+ if (!inst.operands[0].writeback
+ && (inst.operands[1].imm & (inst.operands[1].imm - 1)) == 0)
+ {
+ unsigned long opcode = T_MNEM_ldr;
+ if (inst.instruction == T_MNEM_stmia)
+ opcode = T_MNEM_str;
- if (inst.operands[0].reg <= 7)
+ inst.instruction = THUMB_OP16 (opcode);
+ inst.instruction |= inst.operands[0].reg << 3;
+ inst.instruction |= (ffs (inst.operands[1].imm) - 1);
+ narrow = true;
+ }
+ /* Finally, try a 16-bit ldm/stm. */
+ else
{
+ mask = 1 << inst.operands[0].reg;
+
+ /* STMIA must have writeback; LDMIA must have writeback
+ if and only if the base register is not in the
+ transfer list. */
if (inst.instruction == T_MNEM_stmia
? inst.operands[0].writeback
: (inst.operands[0].writeback
== !(inst.operands[1].imm & mask)))
{
+ /* For STMIA, if the base register is in the
+ transfer list, the value stored is UNKOWN if it
+ is not the first register in the list. */
if (inst.instruction == T_MNEM_stmia
&& (inst.operands[1].imm & mask)
&& (inst.operands[1].imm & (mask - 1)))
inst.instruction |= inst.operands[1].imm;
narrow = true;
}
- else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
- {
- /* This means 1 register in reg list one of 3 situations:
- 1. Instruction is stmia, but without writeback.
- 2. lmdia without writeback, but with Rn not in
- reglist.
- 3. ldmia with writeback, but with Rn in reglist.
- Case 3 is UNPREDICTABLE behaviour, so we handle
- case 1 and 2 which can be converted into a 16-bit
- str or ldr. The SP cases are handled below. */
- unsigned long opcode;
- /* First, record an error for Case 3. */
- if (inst.operands[1].imm & mask
- && inst.operands[0].writeback)
- inst.error =
- _("having the base register in the register list when "
- "using write back is UNPREDICTABLE");
-
- opcode = (inst.instruction == T_MNEM_stmia ? T_MNEM_str
- : T_MNEM_ldr);
- inst.instruction = THUMB_OP16 (opcode);
- inst.instruction |= inst.operands[0].reg << 3;
- inst.instruction |= (ffs (inst.operands[1].imm)-1);
- narrow = true;
- }
- }
- else if (inst.operands[0] .reg == REG_SP)
- {
- if (inst.operands[0].writeback)
- {
- inst.instruction =
- THUMB_OP16 (inst.instruction == T_MNEM_stmia
- ? T_MNEM_push : T_MNEM_pop);
- inst.instruction |= inst.operands[1].imm;
- narrow = true;
- }
- else if ((inst.operands[1].imm & (inst.operands[1].imm-1)) == 0)
- {
- inst.instruction =
- THUMB_OP16 (inst.instruction == T_MNEM_stmia
- ? T_MNEM_str_sp : T_MNEM_ldr_sp);
- inst.instruction |= ((ffs (inst.operands[1].imm)-1) << 8);
- narrow = true;
- }
}
}
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 3b04 str.w r3, \[sp\], #4
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]+ <[^>]+> b408 push {r3}
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\]!
+0[0-9a-f]+ <[^>]+> 6800 ldr r0, \[r0, #0\]
0[0-9a-f]+ <[^>]+> c80e ldmia r0!, {r1, r2, r3}
0[0-9a-f]+ <[^>]+> c80f ldmia r0, {r0, r1, r2, r3}
0[0-9a-f]+ <[^>]+> c802 ldmia r0!, {r1}