The aarch64 ISA specification allows a left shift amount to be applied
after extension in the range of 0 to 4 (encoded in the imm3 field).

This is true for at least the following instructions:

 * ADD (extend register)
 * ADDS (extended register)
 * SUB (extended register)

The result of this patch can be seen, when compiling the following code:

uint64_t myadd(uint64_t a, uint64_t b)
{
  return a+(((uint8_t)b)<<4);
}

Without the patch the following sequence will be generated:

0000000000000000 <myadd>:
   0:   d37c1c21        ubfiz   x1, x1, #4, #8
   4:   8b000020        add     x0, x1, x0
   8:   d65f03c0        ret

With the patch the ubfiz will be merged into the add instruction:

0000000000000000 <myadd>:
   0:   8b211000        add     x0, x0, w1, uxtb #4
   4:   d65f03c0        ret

Tested with "make check" and no regressions found.

*** gcc/ChangeLog ***

2018-xx-xx  Christoph Muellner  <christoph.muell...@theobroma-systems.com>
            Philipp Tomsich  <philipp.toms...@theobroma-systems.com>

        * config/aarch64/aarch64.c (aarch64_uxt_size): Correct the maximum
        shift amount for shifted operands.

*** gcc/testsuite/ChangeLog ***

2018-xx-xx  Christoph Muellner  <christoph.muell...@theobroma-systems.com>
            Philipp Tomsich  <philipp.toms...@theobroma-systems.com>

        * gcc.target/aarch64/extend.c: Adjust the testcases to cover
        the changed shift amount.

Signed-off-by: Christoph Muellner <christoph.muell...@theobroma-systems.com>
---
 gcc/config/aarch64/aarch64.c              |  2 +-
 gcc/testsuite/gcc.target/aarch64/extend.c | 28 ++++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 90bbc57..27b53f4 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -8226,7 +8226,7 @@ aarch64_output_casesi (rtx *operands)
 int
 aarch64_uxt_size (int shift, HOST_WIDE_INT mask)
 {
-  if (shift >= 0 && shift <= 3)
+  if (shift >= 0 && shift <= 4)
     {
       int size;
       for (size = 8; size <= 32; size *= 2)
diff --git a/gcc/testsuite/gcc.target/aarch64/extend.c 
b/gcc/testsuite/gcc.target/aarch64/extend.c
index f399e55..19b120d 100644
--- a/gcc/testsuite/gcc.target/aarch64/extend.c
+++ b/gcc/testsuite/gcc.target/aarch64/extend.c
@@ -37,6 +37,13 @@ adddi_uxtw (unsigned long long a, unsigned int i)
 }
 
 unsigned long long
+adddi_uxtw4 (unsigned long long a, unsigned int i)
+{
+  /* { dg-final { scan-assembler "add\tx\[0-9\]+,.*uxtw #?4" } } */
+  return a + ((unsigned long long)i << 4);
+}
+
+unsigned long long
 adddi_uxtw0 (unsigned long long a, unsigned int i)
 {
   /* { dg-final { scan-assembler "add\tx\[0-9\]+,.*uxtw\n" } } */
@@ -51,6 +58,13 @@ adddi_sxtw (long long a, int i)
 }
 
 long long
+adddi_sxtw4 (long long a, int i)
+{
+  /* { dg-final { scan-assembler "add\tx\[0-9\]+,.*sxtw #?4" } } */
+  return a + ((long long)i << 4);
+}
+
+long long
 adddi_sxtw0 (long long a, int i)
 {
   /* { dg-final { scan-assembler "add\tx\[0-9\]+,.*sxtw\n" } } */
@@ -65,6 +79,13 @@ subdi_uxtw (unsigned long long a, unsigned int i)
 }
 
 unsigned long long
+subdi_uxtw4 (unsigned long long a, unsigned int i)
+{
+  /* { dg-final { scan-assembler "sub\tx\[0-9\]+,.*uxtw #?4" } } */
+  return a - ((unsigned long long)i << 4);
+}
+
+unsigned long long
 subdi_uxtw0 (unsigned long long a, unsigned int i)
 {
   /* { dg-final { scan-assembler "sub\tx\[0-9\]+,.*uxtw\n" } } */
@@ -79,6 +100,13 @@ subdi_sxtw (long long a, int i)
 }
 
 long long
+subdi_sxtw4 (long long a, int i)
+{
+  /* { dg-final { scan-assembler "sub\tx\[0-9\]+,.*sxtw #?4" } } */
+  return a - ((long long)i << 4);
+}
+
+long long
 subdi_sxtw0 (long long a, int i)
 {
   /* { dg-final { scan-assembler "sub\tx\[0-9\]+,.*sxtw\n" } } */
-- 
2.9.5

Reply via email to