aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-arm.c
diff options
context:
space:
mode:
authorMatthew Gretton-Dann <matthew.gretton-dann@arm.com>2010-09-17 15:19:14 +0000
committerMatthew Gretton-Dann <matthew.gretton-dann@arm.com>2010-09-17 15:19:14 +0000
commiteab4f823f7793e025759fb47748b4b71bb88dac9 (patch)
treea83ab731ad550e9f1a4ed67a8faaefdb1edb13be /gas/config/tc-arm.c
parent59b42a0df4c14288bd6bc922c187a9e218323d3d (diff)
downloadgdb-eab4f823f7793e025759fb47748b4b71bb88dac9.zip
gdb-eab4f823f7793e025759fb47748b4b71bb88dac9.tar.gz
gdb-eab4f823f7793e025759fb47748b4b71bb88dac9.tar.bz2
2010-09-17 Tejas Belagod <tejas.belagod@arm.com>
* config/tc-arm.c (do_t_ldmstm): Add logic to handle single-register list for ldm/stm. 2010-09-17 Tejas Belagod <tejas.belagod@arm.com> * gas/arm/thumb2_ldmstm.d: Change single-register stmia to use 16-bit str encoding instead of str.w. Likewise for ldmia. * gas/arm/thumb2_ldmstm.s: Change stmia comment. Add tests for T1 ldmia-to-ldr.
Diffstat (limited to 'gas/config/tc-arm.c')
-rw-r--r--gas/config/tc-arm.c76
1 files changed, 57 insertions, 19 deletions
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 9bba5e4..deb78ce 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -9943,30 +9943,68 @@ do_t_ldmstm (void)
{
mask = 1 << inst.operands[0].reg;
- 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[0].reg <= 7)
{
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 UNKNOWN"),
- inst.operands[0].reg);
+ ? inst.operands[0].writeback
+ : (inst.operands[0].writeback
+ == !(inst.operands[1].imm & mask)))
+ {
+ 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 UNKNOWN"),
+ 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;
+ inst.instruction = THUMB_OP16 (inst.instruction);
+ inst.instruction |= inst.operands[0].reg << 8;
+ 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
- && inst.operands[0].writeback)
+ else if (inst.operands[0] .reg == REG_SP)
{
- inst.instruction = THUMB_OP16 (inst.instruction == T_MNEM_stmia
- ? T_MNEM_push : T_MNEM_pop);
- inst.instruction |= inst.operands[1].imm;
- narrow = TRUE;
+ 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;
+ }
}
}