* [PATCH v3] IBM Z: Fix usage of "f" constraint with long doubles
@ 2021-03-04 14:08 Ilya Leoshkevich
2021-03-08 7:25 ` Andreas Krebbel
0 siblings, 1 reply; 2+ messages in thread
From: Ilya Leoshkevich @ 2021-03-04 14:08 UTC (permalink / raw)
To: Andreas Krebbel; +Cc: gcc-patches, Ilya Leoshkevich
v1: https://gcc.gnu.org/pipermail/gcc-patches/2021-January/563799.html
v1 -> v2:
- Handle constraint modifiers, use AR constraint instead of R, add
testcases for & and %.
v2: https://gcc.gnu.org/pipermail/gcc-patches/2021-January/564380.html
v2 -> v3:
- The main prereq is now committed:
https://gcc.gnu.org/pipermail/gcc-patches/2021-March/566237.html
- Dropped long-double-asm-abi.c test, because its prereq is not
approved (yet):
https://gcc.gnu.org/pipermail/gcc-patches/2021-March/566218.html
- Removed superfluous constraint pointer increment.
After switching the s390 backend to store long doubles in vector
registers, "f" constraint broke when used with the former: long doubles
correspond to TFmode, which in combination with "f" corresponds to
hard regs %v0-%v15, however, asm users expect a %f0-%f15 pair.
Fix by using TARGET_MD_ASM_ADJUST hook to convert TFmode values to
FPRX2mode and back.
gcc/ChangeLog:
2020-12-14 Ilya Leoshkevich <iii@linux.ibm.com>
* config/s390/s390.c (f_constraint_p): New function.
(s390_md_asm_adjust): Implement TARGET_MD_ASM_ADJUST.
(TARGET_MD_ASM_ADJUST): Likewise.
* config/s390/vector.md (fprx2_to_tf): Rename from *fprx2_to_tf,
add memory alternative.
(tf_to_fprx2): New pattern.
gcc/testsuite/ChangeLog:
2020-12-14 Ilya Leoshkevich <iii@linux.ibm.com>
* gcc.target/s390/vector/long-double-asm-commutative.c: New
test.
* gcc.target/s390/vector/long-double-asm-earlyclobber.c: New
test.
* gcc.target/s390/vector/long-double-asm-in-out.c: New test.
* gcc.target/s390/vector/long-double-asm-inout.c: New test.
* gcc.target/s390/vector/long-double-asm-matching.c: New test.
* gcc.target/s390/vector/long-double-asm-regmem.c: New test.
* gcc.target/s390/vector/long-double-volatile-from-i64.c: New
test.
---
gcc/config/s390/s390.c | 86 +++++++++++++++++++
.../s390/vector/long-double-asm-commutative.c | 16 ++++
.../vector/long-double-asm-earlyclobber.c | 17 ++++
.../s390/vector/long-double-asm-in-out.c | 14 +++
.../s390/vector/long-double-asm-inout.c | 14 +++
.../s390/vector/long-double-asm-matching.c | 13 +++
.../s390/vector/long-double-asm-regmem.c | 8 ++
.../vector/long-double-volatile-from-i64.c | 22 +++++
8 files changed, 190 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-commutative.c
create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-earlyclobber.c
create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out.c
create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout.c
create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-matching.c
create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-asm-regmem.c
create mode 100644 gcc/testsuite/gcc.target/s390/vector/long-double-volatile-from-i64.c
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index f3d0d1ba596..68dc3c58c1b 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -16698,6 +16698,89 @@ s390_shift_truncation_mask (machine_mode mode)
return mode == DImode || mode == SImode ? 63 : 0;
}
+/* Return TRUE iff CONSTRAINT is an "f" constraint, possibly with additional
+ modifiers. */
+
+static bool
+f_constraint_p (const char *constraint)
+{
+ 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;
+ }
+ return false;
+}
+
+/* Implement TARGET_MD_ASM_ADJUST hook in order to fix up "f"
+ constraints when long doubles are stored in vector registers. */
+
+static rtx_insn *
+s390_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
+ vec<machine_mode> &input_modes,
+ vec<const char *> &constraints, vec<rtx> & /*clobbers*/,
+ HARD_REG_SET & /*clobbered_regs*/)
+{
+ if (!TARGET_VXE)
+ /* Long doubles are stored in FPR pairs - nothing to do. */
+ return NULL;
+
+ rtx_insn *after_md_seq = NULL, *after_md_end = NULL;
+
+ unsigned ninputs = inputs.length ();
+ unsigned noutputs = outputs.length ();
+ for (unsigned i = 0; i < noutputs; i++)
+ {
+ if (GET_MODE (outputs[i]) != TFmode)
+ /* Not a long double - nothing to do. */
+ continue;
+ const char *constraint = constraints[i];
+ bool allows_mem, allows_reg, is_inout;
+ bool ok = parse_output_constraint (&constraint, i, ninputs, noutputs,
+ &allows_mem, &allows_reg, &is_inout);
+ gcc_assert (ok);
+ if (!f_constraint_p (constraint))
+ /* Long double with a constraint other than "=f" - nothing to do. */
+ continue;
+ 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);
+ push_to_sequence2 (after_md_seq, after_md_end);
+ emit_insn (gen_fprx2_to_tf (outputs[i], fprx2));
+ after_md_seq = get_insns ();
+ after_md_end = get_last_insn ();
+ end_sequence ();
+ outputs[i] = fprx2;
+ }
+
+ for (unsigned i = 0; i < ninputs; i++)
+ {
+ if (GET_MODE (inputs[i]) != TFmode)
+ /* Not a long double - nothing to do. */
+ continue;
+ const char *constraint = constraints[noutputs + i];
+ bool allows_mem, allows_reg;
+ bool ok = parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+ constraints.address (), &allows_mem,
+ &allows_reg);
+ gcc_assert (ok);
+ if (!f_constraint_p (constraint))
+ /* Long double with a constraint other than "f" (or "=f" for inout
+ operands) - nothing to do. */
+ 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]));
+ inputs[i] = fprx2;
+ input_modes[i] = FPRX2mode;
+ }
+
+ return after_md_seq;
+}
+
/* Initialize GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
@@ -17005,6 +17088,9 @@ s390_shift_truncation_mask (machine_mode mode)
#undef TARGET_MAX_ANCHOR_OFFSET
#define TARGET_MAX_ANCHOR_OFFSET 0xfff
+#undef TARGET_MD_ASM_ADJUST
+#define TARGET_MD_ASM_ADJUST s390_md_asm_adjust
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-s390.h"
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-commutative.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-commutative.c
new file mode 100644
index 00000000000..59d807c54b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-commutative.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch" } */
+/* { dg-do run { target { s390_z14_hw } } } */
+#include <assert.h>
+#include <stdint.h>
+
+int
+main (void)
+{
+ long double res, x = 40., y = 2.;
+ asm("lxr\t%0,%1\n"
+ "\taxbr\t%0,%2"
+ : "=&f"(res)
+ : "%f"(x), "f"(y));
+ assert (res == 42.);
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-earlyclobber.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-earlyclobber.c
new file mode 100644
index 00000000000..5dd027596de
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-earlyclobber.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch" } */
+/* { dg-do run { target { s390_z14_hw } } } */
+#include <assert.h>
+#include <stdint.h>
+
+int
+main (void)
+{
+ long double res, x = 0x1.0000000000001p+0L,
+ exp = 1.00000000000000011102230246251564788e+0L;
+ asm("lzxr\t%0\n"
+ "\tsqxbr\t%0,%1"
+ : "=&f"(res)
+ : "f"(x));
+ assert (res == exp);
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out.c
new file mode 100644
index 00000000000..27d447f6898
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-in-out.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch" } */
+/* { dg-do run { target { s390_z14_hw } } } */
+#include <assert.h>
+#include <stdint.h>
+
+int
+main (void)
+{
+ long double res, x = 0x1.0000000000001p+0L,
+ exp = 1.00000000000000011102230246251564788e+0L;
+ asm("sqxbr\t%0,%1" : "=f"(res) : "f"(x));
+ assert (res == exp);
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout.c
new file mode 100644
index 00000000000..e0b6ac518aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-inout.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch" } */
+/* { dg-do run { target { s390_z14_hw } } } */
+#include <assert.h>
+#include <stdint.h>
+
+int
+main (void)
+{
+ long double res = 0x1.0000000000001p+0L,
+ exp = 1.00000000000000011102230246251564788e+0L;
+ asm("sqxbr\t%0,%0" : "+f"(res));
+ assert (res == exp);
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-matching.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-matching.c
new file mode 100644
index 00000000000..c8b8c3d1c6e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-matching.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch" } */
+/* { dg-do run { target { s390_z14_hw } } } */
+#include <assert.h>
+#include <stdint.h>
+
+int
+main (void)
+{
+ long double res, x = 40., y = 2.;
+ asm("axbr\t%0,%2" : "=f"(res) : "0"(x), "f"(y));
+ assert (res == 42.);
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-asm-regmem.c b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-regmem.c
new file mode 100644
index 00000000000..314f658b025
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-asm-regmem.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=z14 -mzarch" } */
+
+void
+foo (long double x)
+{
+ asm("# %0" : "+fm"(x));
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/long-double-volatile-from-i64.c b/gcc/testsuite/gcc.target/s390/vector/long-double-volatile-from-i64.c
new file mode 100644
index 00000000000..f4489841c28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/vector/long-double-volatile-from-i64.c
@@ -0,0 +1,22 @@
+/* { 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
+long_double_volatile_from_i64 (int64_t x)
+{
+ static volatile long double y;
+ y = x;
+ return y;
+}
+
+/* { dg-final { scan-assembler-times {\n\tcxgbr\t} 1 } } */
+
+int
+main (void)
+{
+ assert (long_double_volatile_from_i64 (42) == 42.L);
+ assert (long_double_volatile_from_i64 (-42) == -42.L);
+}
--
2.29.2
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH v3] IBM Z: Fix usage of "f" constraint with long doubles
2021-03-04 14:08 [PATCH v3] IBM Z: Fix usage of "f" constraint with long doubles Ilya Leoshkevich
@ 2021-03-08 7:25 ` Andreas Krebbel
0 siblings, 0 replies; 2+ messages in thread
From: Andreas Krebbel @ 2021-03-08 7:25 UTC (permalink / raw)
To: Ilya Leoshkevich; +Cc: gcc-patches
On 3/4/21 3:08 PM, Ilya Leoshkevich wrote:
> v1: https://gcc.gnu.org/pipermail/gcc-patches/2021-January/563799.html
> v1 -> v2:
> - Handle constraint modifiers, use AR constraint instead of R, add
> testcases for & and %.
>
> v2: https://gcc.gnu.org/pipermail/gcc-patches/2021-January/564380.html
> v2 -> v3:
> - The main prereq is now committed:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/566237.html
> - Dropped long-double-asm-abi.c test, because its prereq is not
> approved (yet):
> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/566218.html
> - Removed superfluous constraint pointer increment.
>
>
>
> After switching the s390 backend to store long doubles in vector
> registers, "f" constraint broke when used with the former: long doubles
> correspond to TFmode, which in combination with "f" corresponds to
> hard regs %v0-%v15, however, asm users expect a %f0-%f15 pair.
>
> Fix by using TARGET_MD_ASM_ADJUST hook to convert TFmode values to
> FPRX2mode and back.
>
> gcc/ChangeLog:
>
> 2020-12-14 Ilya Leoshkevich <iii@linux.ibm.com>
>
> * config/s390/s390.c (f_constraint_p): New function.
> (s390_md_asm_adjust): Implement TARGET_MD_ASM_ADJUST.
> (TARGET_MD_ASM_ADJUST): Likewise.
> * config/s390/vector.md (fprx2_to_tf): Rename from *fprx2_to_tf,
> add memory alternative.
> (tf_to_fprx2): New pattern.
>
> gcc/testsuite/ChangeLog:
>
> 2020-12-14 Ilya Leoshkevich <iii@linux.ibm.com>
>
> * gcc.target/s390/vector/long-double-asm-commutative.c: New
> test.
> * gcc.target/s390/vector/long-double-asm-earlyclobber.c: New
> test.
> * gcc.target/s390/vector/long-double-asm-in-out.c: New test.
> * gcc.target/s390/vector/long-double-asm-inout.c: New test.
> * gcc.target/s390/vector/long-double-asm-matching.c: New test.
> * gcc.target/s390/vector/long-double-asm-regmem.c: New test.
> * gcc.target/s390/vector/long-double-volatile-from-i64.c: New
> test.
Ok. Thanks!
Andreas
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-03-08 7:25 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-04 14:08 [PATCH v3] IBM Z: Fix usage of "f" constraint with long doubles Ilya Leoshkevich
2021-03-08 7:25 ` Andreas Krebbel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).