This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] gas: Emit A2 encoding for ARM PUSH/POP with single register
- From: Meador Inge <meadori at codesourcery dot com>
- To: <binutils at sourceware dot org>
- Date: Thu, 29 Mar 2012 16:02:14 -0500
- Subject: [PATCH] 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
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}