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]

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


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.

[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c/index.html

Changes since v1 (Improvements suggested by Matthew Gretton-Dann):

   * Use 'ffs' instead of manual loop to see if a bit is set.
   * Use macros instead of magic number bit patterns.

gas/
2012-03-30  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.
	(A_COND_MASK): New macro.
	(A_LDMSTM_OP_MASK): Ditto.
	(A1_OPCODE_LDM_SP_W): Ditto.
	(A1_OPCODE_STM_SP_W): Ditto.
	(A2_OPCODE_PUSH): Ditto.
	(A2_OPCODE_POP): Ditto.

gas/testsuite/
2012-03-30  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..a3bc4d8 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -622,6 +622,15 @@ struct asm_opcode
 #define T2_OPCODE_MASK	0xfe1fffff
 #define T2_DATA_OP_SHIFT 21
 
+#define A_COND_MASK       0xf0000000
+#define A_LDMSTM_OP_MASK  0x0fff0000
+
+/* Opcodes for pushing/poping registers to/from the stack.  */
+#define A1_OPCODE_LDM_SP_W  0x08bd0000
+#define A1_OPCODE_STM_SP_W  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 +7804,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)
 {
   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,30 @@ do_ldmstm (void)
 	    as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
 	}
     }
+
+  /* If POP/PUSH has only one register, then we use the A2 encoding.  */
+  one_reg = only_one_reg_in_list (range);
+  if (one_reg >= 0)
+    {
+      int opcode = inst.instruction & A_LDMSTM_OP_MASK;
+
+      /* LDMIA SP!, {reg} -> POP {reg}  */
+      if (opcode == A1_OPCODE_LDM_SP_W)
+	{
+	  inst.instruction &= A_COND_MASK;
+	  inst.instruction |= A2_OPCODE_POP;
+	}
+      /* STMFD SP!, {reg} -> PUSH {reg}  */
+      else if (opcode == A1_OPCODE_STM_SP_W)
+	{
+	  inst.instruction &= A_COND_MASK;
+	  inst.instruction |= A2_OPCODE_PUSH;
+	}
+      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]