IBM Z: Fix "+fvm" constraint with long doubles
authorIlya Leoshkevich <iii@linux.ibm.com>
Thu, 10 Dec 2020 14:43:59 +0000 (15:43 +0100)
committerIlya Leoshkevich <iii@linux.ibm.com>
Tue, 16 Mar 2021 12:57:34 +0000 (13:57 +0100)
When a long double is passed to an asm statement with a "+fvm"
constraint, a LRA loop occurs.  This happens, because LRA chooses the
widest register class in this case (VEC_REGS), but the code generated
by s390_md_asm_adjust() always wants FP_REGS.  Mismatching register
classes cause infinite reloading.

Fix by treating "fv" constraints as "v" in s390_md_asm_adjust().

gcc/ChangeLog:

* config/s390/s390.c (f_constraint_p): Treat "fv" constraints
as "v".

gcc/testsuite/ChangeLog:

* gcc.target/s390/vector/long-double-asm-fprvrmem.c: New test.

gcc/config/s390/s390.c
gcc/testsuite/gcc.target/s390/vector/long-double-asm-fprvrmem.c [new file with mode: 0644]

index 151136b..f7b1c03 100644 (file)
@@ -16714,13 +16714,21 @@ s390_shift_truncation_mask (machine_mode mode)
 static bool
 f_constraint_p (const char *constraint)
 {
+  bool seen_f_p = false;
+  bool seen_v_p = false;
+
   for (size_t i = 0, c_len = strlen (constraint); i < c_len;
        i += CONSTRAINT_LEN (constraint[i], constraint + i))
     {
       if (constraint[i] == 'f')
-       return true;
+       seen_f_p = true;
+      if (constraint[i] == 'v')
+       seen_v_p = true;
     }
-  return false;
+
+  /* Treat "fv" constraints as "v", because LRA will choose the widest register
+   * class.  */
+  return seen_f_p && !seen_v_p;
 }
 
 /* Implement TARGET_MD_ASM_ADJUST hook in order to fix up "f"
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-fprvrmem.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-fprvrmem.c
new file mode 100644 (file)
index 0000000..f95656c
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch" } */
+
+long double
+foo (long double x)
+{
+  x = x * x;
+  asm("# %0" : "+fvm"(x));
+  x = x + x;
+  return x;
+}