diff options
-rw-r--r-- | gcc/config/s390/s390.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/s390/pr97497.c | 36 |
2 files changed, 43 insertions, 0 deletions
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index f9b27f9..3c3feb2 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -10376,9 +10376,16 @@ static bool s390_hard_regno_call_part_clobbered (unsigned int, unsigned int regno, machine_mode mode) { + /* For r12 we know that the only bits we actually care about are + preserved across function calls. Since r12 is a fixed reg all + accesses to r12 are generated by the backend. + + This workaround is necessary until gcse implements proper + tracking of partially clobbered registers. */ if (!TARGET_64BIT && TARGET_ZARCH && GET_MODE_SIZE (mode) > 4 + && (!flag_pic || regno != PIC_OFFSET_TABLE_REGNUM) && ((regno >= 6 && regno <= 15) || regno == 32)) return true; diff --git a/gcc/testsuite/gcc.target/s390/pr97497.c b/gcc/testsuite/gcc.target/s390/pr97497.c new file mode 100644 index 0000000..460c850 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/pr97497.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -march=z900 -mzarch -fpic" } */ + +char *t; + +void __attribute__((noinline,noclone)) +bar(int a, char* b) +{ + if (a != 1) + __builtin_abort(); +} + +void __attribute__((noinline,noclone)) +baz(char* a, int b) +{ + if (b != 1) + __builtin_abort(); +} + +int __attribute__((noinline,noclone)) +foo (int a) +{ + bar (1, t); + if (a) + baz (t, 1); + + bar (1, t); +} + +int +main () +{ + foo (1); + + return 0; +} |