diff options
author | Matthew Gretton-Dann <matthew.gretton-dann@arm.com> | 2010-09-17 15:19:14 +0000 |
---|---|---|
committer | Matthew Gretton-Dann <matthew.gretton-dann@arm.com> | 2010-09-17 15:19:14 +0000 |
commit | eab4f823f7793e025759fb47748b4b71bb88dac9 (patch) | |
tree | a83ab731ad550e9f1a4ed67a8faaefdb1edb13be /gas/config/tc-arm.c | |
parent | 59b42a0df4c14288bd6bc922c187a9e218323d3d (diff) | |
download | gdb-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.c | 76 |
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; + } } } |