diff mbox series

IBM Z: Handle hard registers in s390_md_asm_adjust()

Message ID 20210427014904.80951-1-iii@linux.ibm.com
State New
Headers show
Series IBM Z: Handle hard registers in s390_md_asm_adjust() | expand

Commit Message

Ilya Leoshkevich April 27, 2021, 1:49 a.m. UTC
Bootstrapped and regtested on s390x-redhat-linux.  Tested with valgrind
on top of 52a5515ed (see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100278).  Ok for master?



gen_fprx2_to_tf() and gen_tf_to_fprx2() cannot handle hard registers,
since the subregs they create do not pass validation.  Change
s390_md_asm_adjust() to manually copy between hard VRs and FPRs instead
of using these two functions.

gcc/ChangeLog:

	PR target/100217
	* config/s390/s390.c (s390_hard_fp_reg_p): New function.
	(s390_md_asm_adjust): Handle hard registers.
	* config/s390/vector.md (*df_to_tf_1): New pattern.

gcc/testsuite/ChangeLog:

	PR target/100217
	* gcc.target/s390/vector/long-double-asm-in-out-hard-fp-reg.c: New test.
	* gcc.target/s390/vector/long-double-asm-inout-hard-fp-reg.c: New test.
---
 gcc/config/s390/s390.c                        | 50 +++++++++++++++++--
 gcc/config/s390/vector.md                     |  8 +++
 .../long-double-asm-in-out-hard-fp-reg.c      | 28 +++++++++++
 .../long-double-asm-inout-hard-fp-reg.c       | 27 ++++++++++
 4 files changed, 109 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out-hard-fp-reg.c
 create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout-hard-fp-reg.c
diff mbox series

Patch

diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index a9c945c5ee9..ed6cea9b1f7 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -16754,6 +16754,23 @@  f_constraint_p (const char *constraint)
   return seen_f_p && !seen_v_p;
 }
 
+/* Return TRUE iff X is a hard floating-point (and not a vector) register.  */
+
+static bool
+s390_hard_fp_reg_p (rtx x)
+{
+  if (!(REG_P (x) && HARD_REGISTER_P (x) && REG_ATTRS (x)))
+    return false;
+
+  tree decl = REG_EXPR (x);
+  if (!(HAS_DECL_ASSEMBLER_NAME_P (decl) && DECL_ASSEMBLER_NAME_SET_P (decl)))
+    return false;
+
+  const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+
+  return name[0] == '*' && name[1] == 'f';
+}
+
 /* Implement TARGET_MD_ASM_ADJUST hook in order to fix up "f"
    constraints when long doubles are stored in vector registers.  */
 
@@ -16787,9 +16804,23 @@  s390_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
       gcc_assert (allows_reg);
       gcc_assert (!is_inout);
       /* Copy output value from a FPR pair into a vector register.  */
-      rtx fprx2 = gen_reg_rtx (FPRX2mode);
+      rtx fprx2;
       push_to_sequence2 (after_md_seq, after_md_end);
-      emit_insn (gen_fprx2_to_tf (outputs[i], fprx2));
+      if (s390_hard_fp_reg_p (outputs[i]))
+	{
+	  fprx2 = gen_rtx_REG (FPRX2mode, REGNO (outputs[i]));
+	  /* The first half is already at the correct location, copy only the
+	   * second one.  Use gen_rtx_raw_SUBREG() in order to skip subreg
+	   * validation - we need to build (subreg:DF (reg:TF %fN) 8), which
+	   * will otherwise be rejected by s390_can_change_mode_class().  */
+	  emit_move_insn (gen_rtx_raw_SUBREG (DFmode, outputs[i], 8),
+			  simplify_gen_subreg (DFmode, fprx2, FPRX2mode, 8));
+	}
+      else
+	{
+	  fprx2 = gen_reg_rtx (FPRX2mode);
+	  emit_insn (gen_fprx2_to_tf (outputs[i], fprx2));
+	}
       after_md_seq = get_insns ();
       after_md_end = get_last_insn ();
       end_sequence ();
@@ -16813,8 +16844,19 @@  s390_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
 	continue;
       gcc_assert (allows_reg);
       /* Copy input value from a vector register into a FPR pair.  */
-      rtx fprx2 = gen_reg_rtx (FPRX2mode);
-      emit_insn (gen_tf_to_fprx2 (fprx2, inputs[i]));
+      rtx fprx2;
+      if (s390_hard_fp_reg_p (inputs[i]))
+	{
+	  fprx2 = gen_rtx_REG (FPRX2mode, REGNO (inputs[i]));
+	  /* Copy only the second half.  */
+	  emit_move_insn (gen_rtx_raw_SUBREG (DFmode, fprx2, 8),
+			  gen_rtx_raw_SUBREG (DFmode, inputs[i], 8));
+	}
+      else
+	{
+	  fprx2 = gen_reg_rtx (FPRX2mode);
+	  emit_insn (gen_tf_to_fprx2 (fprx2, inputs[i]));
+	}
       inputs[i] = fprx2;
       input_modes[i] = FPRX2mode;
     }
diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md
index c80d582a300..648e00625e1 100644
--- a/gcc/config/s390/vector.md
+++ b/gcc/config/s390/vector.md
@@ -634,6 +634,14 @@ 
 }
   [(set_attr "op_type" "VRR,*")])
 
+(define_insn "*df_to_tf_1"
+  [(set (subreg:DF (match_operand:TF 0 "nonimmediate_operand" "+v") 8)
+	(match_operand:DF            1 "general_operand"       "f"))]
+  "TARGET_VXE"
+  ; M4 == 0 corresponds to %v0[0] = %v0[0]; %v0[1] = %v1[0];
+  "vpdi\t%v0,%v0,%v1,0"
+  [(set_attr "op_type" "VRR")])
+
 (define_insn "*vec_ti_to_v1ti"
   [(set (match_operand:V1TI                   0 "nonimmediate_operand" "=v,v,R,  v,  v,v")
 	(vec_duplicate:V1TI (match_operand:TI 1 "general_operand"       "v,R,v,j00,jm1,d")))]
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out-hard-fp-reg.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out-hard-fp-reg.c
new file mode 100644
index 00000000000..b9b23bb9188
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out-hard-fp-reg.c
@@ -0,0 +1,28 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch --save-temps" } */
+/* { dg-do run { target { s390_z14_hw } } } */
+#include <assert.h>
+#include <stdint.h>
+
+__attribute__ ((noipa)) static long double
+sqxbr (long double x)
+{
+  register long double in asm("f0") = x;
+  register long double out asm("f1");
+
+  asm("sqxbr\t%0,%1" : "=f"(out) : "f"(in));
+  asm("# %0" : "+f"(out));
+
+  return out;
+}
+
+/* { dg-final { scan-assembler-times {\n\tvpdi\t%v2,%v0,%v2,5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\n\tvpdi\t%v1,%v1,%v3,0\n} 2 } } */
+
+int
+main (void)
+{
+  long double x = 0x1.0000000000001p+0L,
+	      exp = 1.00000000000000011102230246251564788e+0L;
+  assert (sqxbr (x) == exp);
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout-hard-fp-reg.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout-hard-fp-reg.c
new file mode 100644
index 00000000000..130324b0846
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout-hard-fp-reg.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch --save-temps" } */
+/* { dg-do run { target { s390_z14_hw } } } */
+#include <assert.h>
+#include <stdint.h>
+
+__attribute__ ((noipa)) static long double
+sqxbr (long double x)
+{
+  register long double inout asm("f4") = x;
+
+  asm("sqxbr\t%0,%0" : "+f"(inout));
+  asm("# %0" : "+f"(inout));
+
+  return inout;
+}
+
+/* { dg-final { scan-assembler-times {\n\tvpdi\t%v6,%v4,%v6,5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\n\tvpdi\t%v4,%v4,%v6,0\n} 2 } } */
+
+int
+main (void)
+{
+  long double x = 0x1.0000000000001p+0L,
+	      exp = 1.00000000000000011102230246251564788e+0L;
+  assert (sqxbr (x) == exp);
+}