Hello, The attached patch fixes volatile mem stores on SH so that they won't result in redundant sign/zero extensions and will utilize available addressing modes. This is similar to what has been done to fix memory loads in http://gcc.gnu.org/ml/gcc-patches/2013-06/msg01315.html
Tested on rev 203909 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. However, the test result summary showed a bunch of "WARNING: program timed out." Kaz, could you please add it to your test queue and let me know if it's OK for trunk? Cheers, Oleg gcc/ChangeLog: PR target/52483 * config/sh/predicates.md (general_movdst_operand): Allow reg+reg addressing, do not use general_operand for memory operands. testsuite/ChangeLog: PR target/52483 * gcc.target/sh/pr52483-1.c: Add tests for memory stores. * gcc.target/sh/pr52483-2.c: Likewise. * gcc.target/sh/pr52483-3.c: Likewise. * gcc.target/sh/pr52483-4.c: Likewise.
Index: gcc/config/sh/predicates.md =================================================================== --- gcc/config/sh/predicates.md (revision 203857) +++ gcc/config/sh/predicates.md (working copy) @@ -550,17 +550,36 @@ && ! (reload_in_progress || reload_completed)) 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 + stores. 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; } return general_operand (op, mode); Index: gcc/testsuite/gcc.target/sh/pr52483-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr52483-1.c (revision 203857) +++ gcc/testsuite/gcc.target/sh/pr52483-1.c (working copy) @@ -1,9 +1,9 @@ -/* Check that loads from volatile mems don't result in redundant sign - extensions. */ +/* Check that loads/stores from/to volatile mems don't result in redundant + sign/zero extensions. */ /* { dg-do compile { target "sh*-*-*" } } */ -/* { dg-options "-O1" } */ +/* { dg-options "-O2" } */ /* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ -/* { dg-final { scan-assembler-not "exts" } } */ +/* { dg-final { scan-assembler-not "exts|extu" } } */ int test_00 (volatile char* x) @@ -11,20 +11,44 @@ return *x; } +void +test_100 (volatile char* x, char y) +{ + *x = y; +} + int test_01 (volatile short* x) { return *x; } +void +test_101 (volatile unsigned char* x, unsigned char y) +{ + *x = y; +} + int test_02 (volatile unsigned char* x) { return *x == 0x80; } +void +test_102 (volatile short* x, short y) +{ + *x = y; +} + int test_03 (volatile unsigned short* x) { return *x == 0xFF80; } + +void +test_103 (volatile unsigned short* x, unsigned short y) +{ + *x = y; +} Index: gcc/testsuite/gcc.target/sh/pr52483-2.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr52483-2.c (revision 203857) +++ gcc/testsuite/gcc.target/sh/pr52483-2.c (working copy) @@ -1,14 +1,15 @@ -/* Check that loads from volatile mems utilize displacement addressing - modes and do not result in redundant sign extensions. */ +/* Check that loads/stores from/to volatile mems utilize displacement + addressing modes and do not result in redundant sign/zero 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-times "@\\(5," 4 } } */ +/* { dg-final { scan-assembler-times "@\\(10," 4 } } */ +/* { dg-final { scan-assembler-times "@\\(20," 4 } } */ +/* { dg-final { scan-assembler-times "@\\(40," 4 } } */ +/* { dg-final { scan-assembler-times "@\\(44," 4 } } */ /* { dg-final { scan-assembler-not "exts" } } */ +/* { dg-final { scan-assembler-times "extu|movu" 2 } } */ int test_00 (volatile char* x) @@ -16,35 +17,73 @@ return x[5]; } +void +test_100 (volatile char* x, char y) +{ + x[5] = y; +} + int test_01 (volatile short* x) { return x[5]; } +void +test_101 (volatile short* x, short y) +{ + x[5] = y; +} + int test_02 (volatile int* x) { return x[5]; } +void +test_102 (volatile int* x, int y) +{ + x[5] = y; +} + long long test_03 (volatile long long* x) { return x[5]; } +void +test_103 (volatile long long* x, long long y) +{ + x[5] = y; +} + unsigned int test_04 (volatile unsigned char* x) { + // expected 1x extu.b or movu.b return x[5]; } +void +test_104 (volatile unsigned char* x, unsigned char y) +{ + x[5] = y; +} + unsigned int test_05 (volatile unsigned short* x) { + // expected 1x extu.w or movu.w return x[5]; } + +void +test_105 (volatile unsigned short* x, unsigned short y) +{ + x[5] = y; +} unsigned int test_06 (volatile unsigned int* x) @@ -52,8 +91,20 @@ return x[5]; } +void +test_106 (volatile unsigned int* x, unsigned int y) +{ + x[5] = y; +} + unsigned long long test_07 (volatile unsigned long long* x) { return x[5]; } + +void +test_107 (volatile unsigned long long* x, unsigned long long y) +{ + x[5] = y; +} Index: gcc/testsuite/gcc.target/sh/pr52483-3.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr52483-3.c (revision 203857) +++ gcc/testsuite/gcc.target/sh/pr52483-3.c (working copy) @@ -1,10 +1,10 @@ -/* Check that loads from volatile mems utilize indexed addressing - modes and do not result in redundant sign extensions. */ +/* Check that loads/stores from/to volatile mems utilize indexed addressing + modes and do not result in redundant sign/zero 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" } } */ +/* { dg-final { scan-assembler-times "@\\(r0," 6 } } */ +/* { dg-final { scan-assembler-not "exts|extu" } } */ int test_00 (volatile char* x, unsigned int y) @@ -12,14 +12,32 @@ return x[y]; } +void +test_100 (volatile char* x, unsigned int y, char z) +{ + x[y] = z; +} + int test_01 (volatile short* x, unsigned int y) { return x[y]; } +void +test_101 (volatile short* x, unsigned int y, short z) +{ + x[y] = z; +} + int test_02 (volatile int* x, unsigned int y) { return x[y]; } + +int +test_102 (volatile int* x, unsigned int y, int z) +{ + x[y] = z; +} Index: gcc/testsuite/gcc.target/sh/pr52483-4.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr52483-4.c (revision 203857) +++ gcc/testsuite/gcc.target/sh/pr52483-4.c (working copy) @@ -1,12 +1,18 @@ -/* Check that loads from volatile floating point mems utilize indexed - addressing modes. */ +/* Check that loads/stores from/to 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 } } */ +/* { dg-final { scan-assembler-times "@\\(r0," 2 } } */ float test_00 (volatile float* x, unsigned int y) { return x[y]; } + +void +test_100 (volatile float* x, unsigned int y, float z) +{ + x[y] = z; +}