This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] gas: Emit A2 encoding for ARM PUSH/POP with single register


On 29/03/12 22:02, Meador Inge wrote:
> Hi,
> 
> This patch changes GAS to emit the A2 encoding for PUSH/POP instructions
> with a single register.  This case is specified by the ARMARM: A8.8.132,
> A8.8.133 [1].  The A2 encoding is allowed on the following architecture
> versions: ARMv4*, ARMv5T*, ARMv6*, and ARMv7.
> 
> Tested with arm-none-eabi configuration.  No regressions.
> 
> OK?
> 
> P.S. If this is OK, then can someone commit for me?  I don't have write
> access.
> 

Sorry, this isn't quite right.

In ARM state, stmfd sp!, {<single-reg>} is not 'push' and should
continue to assemble to an stmfd instruction (otherwise there's no way
to generate that bit pattern).  Similarly for ldmfd.   Only push and pop
should be folded in this way.

Secondly, your use of r0 in the tests is insufficient.  r0 is all-bits
zero in the register specifier, so you fail to test that the register
bits are inserted correctly into bit pattern.  I suggest you _add_ tests
using r9 in the register list.

R.


> [1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c/index.html
> 
> gas/
> 2012-03-29  Jie Zhang  <jie@codesourcery.com>
>             Meador Inge  <meadori@codesourcery.com>
> 
> 	* config/tc-arm.c (only_one_reg_in_list): New function.
> 	(do_ldmstm): Use a different encoding when pushing or poping
> 	a single register.
> 
> gas/testsuite/
> 2012-03-29  Jie Zhang  <jie@codesourcery.com>
>             Meador Inge  <meadori@codesourcery.com>
> 
> 	* gas/arm/push-pop.d: New testcase.
> 	* gas/arm/push-pop.s: New testcase.
> 
> diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
> index 585f78e..826cf62 100644
> --- a/gas/config/tc-arm.c
> +++ b/gas/config/tc-arm.c
> @@ -7795,11 +7795,30 @@ do_it (void)
>      }
>  }
>  
> +/* If there is only one register in the register list, return the register
> +   number of that register.  Otherwise return -1.  */
> +static int
> +only_one_reg_in_list (int range)
> +{
> +  int i;
> +
> +  if (range <= 0 || range > 0xffff
> +      || (range & (range - 1)) != 0)
> +    return -1;
> +
> +  for (i = 0; i <= 15; i++)
> +    if (range & (1 << i))
> +      break;
> +
> +  return i;
> +}
> +
>  static void
>  do_ldmstm (void)
>  {
>    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 +7851,26 @@ do_ldmstm (void)
>  	    as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
>  	}
>      }
> +
> +  /* When POP or PUSH only one register, we have to use different encodings.  */
> +  one_reg = only_one_reg_in_list (range);
> +  if (one_reg >= 0)
> +    {
> +      if ((inst.instruction & 0xfff0000) == 0x8bd0000)
> +	{
> +	  inst.instruction &= 0xf0000000;
> +	  inst.instruction |= 0x49d0004;
> +	}
> +      else if ((inst.instruction & 0xfff0000) == 0x92d0000)
> +	{
> +	  inst.instruction &= 0xf0000000;
> +	  inst.instruction |= 0x52d0004;
> +	}
> +      else
> +	return;
> +
> +      inst.instruction |= one_reg << 12;
> +    }
>  }
>  
>  /* ARMv5TE load-consecutive (argument parse)
> diff --git a/gas/testsuite/gas/arm/push-pop.d b/gas/testsuite/gas/arm/push-pop.d
> new file mode 100644
> index 0000000..e33e985
> --- /dev/null
> +++ b/gas/testsuite/gas/arm/push-pop.d
> @@ -0,0 +1,12 @@
> +#objdump: -dr --prefix-addresses --show-raw-insn
> +#name: PUSH and POP
> +
> +# Test the `PUSH' and `POP' instructions
> +
> +.*: +file format .*arm.*
> +
> +Disassembly of section .text:
> +0+000 <.*> e52d0004 	push	{r0}		; \(str r0, \[sp, #-4\]!\)
> +0+004 <.*> e52d0004 	push	{r0}		; \(str r0, \[sp, #-4\]!\)
> +0+008 <.*> e49d0004 	pop	{r0}		; \(ldr r0, \[sp\], #4\)
> +0+00c <.*> e49d0004 	pop	{r0}		; \(ldr r0, \[sp\], #4\)
> diff --git a/gas/testsuite/gas/arm/push-pop.s b/gas/testsuite/gas/arm/push-pop.s
> new file mode 100644
> index 0000000..2251905
> --- /dev/null
> +++ b/gas/testsuite/gas/arm/push-pop.s
> @@ -0,0 +1,6 @@
> +	.text
> +	.syntax unified
> +	stmfd	sp!, {r0}
> +	push {r0}
> +	pop {r0}
> +	ldmia sp!, {r0}
> 
> 



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]