Hi,

the attached patch fixes volatile mem loads on SH so that they won't
result in redundant sign extensions and also utilize the available
addressing modes.

Tested on rev 200116 with
make -k check RUNTESTFLAGS="--target_board=sh-sim
\{-m2/-ml,-m2/-mb,-m2a/-mb,-m4/-ml,-m4/-mb,-m4a/-ml,-m4a/-mb}"

and no new failures.

OK?

Cheers,
Oleg

gcc/ChangeLog:

        PR target/52483
        * config/sh/predicates.md (general_extend_operand): Invoke 
        general_movsrc_operand for memory operands.
        (general_movsrc_operand): Allow reg+reg addressing, do not 
        invoke use general_operand for memory operands.

testsuite/ChangeLog:

        PR target/52483
        * gcc.target/sh/pr52483-1.c: New.
        * gcc.target/sh/pr52483-2.c: New.
        * gcc.target/sh/pr52483-3.c: New.
        * gcc.target/sh/pr52483-4.c: New.
        * gcc.target/sh/pr52483-5.c: New.


Index: gcc/testsuite/gcc.target/sh/pr52483-2.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr52483-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr52483-2.c	(revision 0)
@@ -0,0 +1,59 @@
+/* Check that loads from volatile mems utilize displacement addressing
+   modes and do not result in redundant sign extensions. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+/* { dg-final { scan-assembler-times "@\\(5," 2 } } */
+/* { dg-final { scan-assembler-times "@\\(10," 2 } } */
+/* { dg-final { scan-assembler-times "@\\(20," 2 } } */
+/* { dg-final { scan-assembler-times "@\\(40," 2 } } */
+/* { dg-final { scan-assembler-times "@\\(44," 2 } } */
+/* { dg-final { scan-assembler-not "exts" } } */
+
+int
+test_00 (volatile char* x)
+{
+  return x[5];
+}
+
+int
+test_01 (volatile short* x)
+{
+  return x[5];
+}
+
+int
+test_02 (volatile int* x)
+{
+  return x[5];
+}
+
+long long
+test_03 (volatile long long* x)
+{
+  return x[5];
+}
+
+unsigned int
+test_04 (volatile unsigned char* x)
+{
+  return x[5];
+}
+
+unsigned int
+test_05 (volatile unsigned short* x)
+{
+  return x[5];
+}
+ 
+unsigned int
+test_06 (volatile unsigned int* x)
+{
+  return x[5];
+}
+
+unsigned long long
+test_07 (volatile unsigned long long* x)
+{
+  return x[5];
+}
Index: gcc/testsuite/gcc.target/sh/pr52483-3.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr52483-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr52483-3.c	(revision 0)
@@ -0,0 +1,25 @@
+/* Check that loads from volatile mems utilize indexed addressing
+   modes and do not result in redundant sign extensions. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+/* { dg-final { scan-assembler-times "@\\(r0," 3 } } */
+/* { dg-final { scan-assembler-not "exts" } } */
+
+int
+test_00 (volatile char* x, unsigned int y)
+{
+  return x[y];
+}
+
+int
+test_01 (volatile short* x, unsigned int y)
+{
+  return x[y];
+}
+
+int
+test_02 (volatile int* x, unsigned int y)
+{
+  return x[y];
+}
Index: gcc/testsuite/gcc.target/sh/pr52483-4.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr52483-4.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr52483-4.c	(revision 0)
@@ -0,0 +1,12 @@
+/* Check that loads from volatile floating point mems utilize indexed
+   addressing modes. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m1" "-m2" "-m3" "-m4al" "*nofpu" "-m4-340*" "-m4-400*" "-m4-500*" "-m5*" } { "" } }  */
+/* { dg-final { scan-assembler-times "@\\(r0," 1 } } */
+
+float
+test_00 (volatile float* x, unsigned int y)
+{
+  return x[y];
+}
Index: gcc/testsuite/gcc.target/sh/pr52483-1.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr52483-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr52483-1.c	(revision 0)
@@ -0,0 +1,30 @@
+/* Check that loads from volatile mems don't result in redundant sign
+   extensions.  */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+/* { dg-final { scan-assembler-not "exts" } } */
+
+int
+test_00 (volatile char* x)
+{
+  return *x;
+}
+
+int
+test_01 (volatile short* x)
+{
+  return *x;
+}
+
+int
+test_02 (volatile unsigned char* x)
+{
+  return *x == 0x80;
+}
+
+int
+test_03 (volatile unsigned short* x)
+{
+  return *x == 0xFF80;
+}
Index: gcc/testsuite/gcc.target/sh/pr52483-5.c
===================================================================
--- gcc/testsuite/gcc.target/sh/pr52483-5.c	(revision 0)
+++ gcc/testsuite/gcc.target/sh/pr52483-5.c	(revision 0)
@@ -0,0 +1,28 @@
+/* Check that loads from volatile mems utilize post-increment addressing
+   modes and do not result in redundant sign extensions. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } }  */
+/* { dg-final { scan-assembler-times "@r\[0-9\]\+\\+," 3 } } */
+/* { dg-final { scan-assembler-not "exts" } } */
+
+volatile char*
+test_00 (volatile char* x)
+{
+  int xx = *x++;
+  return x;
+}
+
+volatile short*
+test_01 (volatile short* x)
+{
+  int xx = *x++;
+  return x;
+}
+
+volatile int*
+test_02 (volatile int* x)
+{
+  int xx = *x++;
+  return x;
+}
Index: gcc/config/sh/predicates.md
===================================================================
--- gcc/config/sh/predicates.md	(revision 200116)
+++ gcc/config/sh/predicates.md	(working copy)
@@ -398,9 +398,13 @@
 (define_predicate "general_extend_operand"
   (match_code "subreg,reg,mem,truncate")
 {
-  return (GET_CODE (op) == TRUNCATE
-	  ? arith_operand
-	  : nonimmediate_operand) (op, mode);
+  if (GET_CODE (op) == TRUNCATE)
+    return arith_operand (op, mode);
+
+  if (MEM_P (op) || (GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op))))
+    return general_movsrc_operand (op, mode);
+
+  return nonimmediate_operand (op, mode);
 })
 
 ;; Returns 1 if OP is a simple register address.
@@ -468,17 +472,36 @@
 	return 0;
     }
 
-  if ((mode == QImode || mode == HImode)
-      && mode == GET_MODE (op)
-      && (MEM_P (op)
-	  || (GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op)))))
+  if (mode == GET_MODE (op)
+      && (MEM_P (op) || (GET_CODE (op) == SUBREG && MEM_P (SUBREG_REG (op)))))
     {
-      rtx x = XEXP ((MEM_P (op) ? op : SUBREG_REG (op)), 0);
+      rtx mem_rtx = MEM_P (op) ? op : SUBREG_REG (op);
+      rtx x = XEXP (mem_rtx, 0);
 
-      if (GET_CODE (x) == PLUS
+      if ((mode == QImode || mode == HImode)
+	  && GET_CODE (x) == PLUS
 	  && REG_P (XEXP (x, 0))
 	  && CONST_INT_P (XEXP (x, 1)))
 	return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false);
+
+      /* Allow reg+reg addressing here without validating the register
+	 numbers.  Usually one of the regs must be R0 or a pseudo reg.
+	 In some cases it can happen that arguments from hard regs are
+	 propagated directly into address expressions.  In this cases reload
+	 will have to fix it up later.  However, allow this only for native
+	 1, 2 or 4 byte addresses.  */
+      if (can_create_pseudo_p () && GET_CODE (x) == PLUS
+	  && GET_MODE_SIZE (mode) <= 4
+	  && REG_P (XEXP (x, 0)) && REG_P (XEXP (x, 1)))
+	return true;
+
+      /* 'general_operand' does not allow volatile mems during RTL expansion to
+	 avoid matching arithmetic that operates on mems, it seems.
+	 On SH this leads to redundant sign extensions for QImode or HImode
+	 loads.  Thus we mimic the behavior but allow volatile mems.  */
+        if (memory_address_addr_space_p (GET_MODE (mem_rtx), x,
+					 MEM_ADDR_SPACE (mem_rtx)))
+	  return true;
     }
 
   if (TARGET_SHMEDIA
@@ -489,6 +512,7 @@
       && GET_CODE (op) == SUBREG && GET_MODE (op) == mode
       && SUBREG_REG (op) == const0_rtx && subreg_lowpart_p (op))
     /* FIXME */ abort (); /* return 1; */
+
   return general_operand (op, mode);
 })
 

Reply via email to