From: Nick Clifton Date: Thu, 12 Apr 2012 07:46:54 +0000 (+0000) Subject: * config/tc-arm.c (only_one_reg_in_list): New function. X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=6530b175a1051db81806d031b8ab2937744ff57b;hp=202e23565d36f4696d5e836ec06d4c685c30fb16;p=deliverable%2Fbinutils-gdb.git * config/tc-arm.c (only_one_reg_in_list): New function. (encode_ldmstm): Ditto. (do_ldmstm): Use a different encoding when pushing or poping a single register. (A_COND_MASK): New macro. (A_PUSH_POP_OP_MASK): Ditto. (A1_OPCODE_PUSH): Ditto. (A2_OPCODE_PUSH): Ditto. (A2_OPCODE_POP): Ditto. * gas/arm/push-pop.d: New testcase. * gas/arm/push-pop.s: Ditto. * gas/arm/stm-ldm.d: Ditto. * gas/arm/stm-ldm.s: Ditto. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index 6243dfe802..b1d863af0f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,16 @@ +2012-04-12 Jie Zhang + Meador Inge + + * config/tc-arm.c (only_one_reg_in_list): New function. + (encode_ldmstm): Ditto. + (do_ldmstm): Use a different encoding when pushing or poping + a single register. + (A_COND_MASK): New macro. + (A_PUSH_POP_OP_MASK): Ditto. + (A1_OPCODE_PUSH): Ditto. + (A2_OPCODE_PUSH): Ditto. + (A2_OPCODE_POP): Ditto. + 2012-04-06 Maciej W. Rozycki * doc/c-mips.texi (MIPS Opts): Correct -no-mfix-24k to diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 585f78e0a2..545b7ec7a3 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -622,6 +622,14 @@ struct asm_opcode #define T2_OPCODE_MASK 0xfe1fffff #define T2_DATA_OP_SHIFT 21 +#define A_COND_MASK 0xf0000000 +#define A_PUSH_POP_OP_MASK 0x0fff0000 + +/* Opcodes for pushing/poping registers to/from the stack. */ +#define A1_OPCODE_PUSH 0x092d0000 +#define A2_OPCODE_PUSH 0x052d0004 +#define A2_OPCODE_POP 0x049d0004 + /* Codes to distinguish the arithmetic instructions. */ #define OPCODE_AND 0 #define OPCODE_EOR 1 @@ -7795,11 +7803,21 @@ do_it (void) } } +/* If there is only one register in the register list, + then return its register number. Otherwise return -1. */ +static int +only_one_reg_in_list (int range) +{ + int i = ffs (range) - 1; + return (i > 15 || range != (1 << i)) ? -1 : i; +} + static void -do_ldmstm (void) +encode_ldmstm(int from_push_pop_mnem) { int base_reg = inst.operands[0].reg; int range = inst.operands[1].imm; + int one_reg; inst.instruction |= base_reg << 16; inst.instruction |= range; @@ -7832,6 +7850,23 @@ do_ldmstm (void) as_warn (_("if writeback register is in list, it must be the lowest reg in the list")); } } + + /* If PUSH/POP has only one register, then use the A2 encoding. */ + one_reg = only_one_reg_in_list (range); + if (from_push_pop_mnem && one_reg >= 0) + { + int is_push = (inst.instruction & A_PUSH_POP_OP_MASK) == A1_OPCODE_PUSH; + + inst.instruction &= A_COND_MASK; + inst.instruction |= is_push ? A2_OPCODE_PUSH : A2_OPCODE_POP; + inst.instruction |= one_reg << 12; + } +} + +static void +do_ldmstm (void) +{ + encode_ldmstm (/*from_push_pop_mnem=*/FALSE); } /* ARMv5TE load-consecutive (argument parse) @@ -8333,7 +8368,7 @@ do_push_pop (void) inst.operands[0].isreg = 1; inst.operands[0].writeback = 1; inst.operands[0].reg = REG_SP; - do_ldmstm (); + encode_ldmstm (/*from_push_pop_mnem=*/TRUE); } /* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index d509b7d6c2..b9e884f903 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2012-04-12 Jie Zhang + Meador Inge + + * gas/arm/push-pop.d: New testcase. + * gas/arm/push-pop.s: Ditto. + * gas/arm/stm-ldm.d: Ditto. + * gas/arm/stm-ldm.s: Ditto. + 2012-04-07 David S. Miller * gas/all/gas.exp: Sparc can handle BFD_RELOC_8 for constants.