From 33f3393ab5cc809f2636cc3ce86b3032177c91b8 Mon Sep 17 00:00:00 2001 From: Andreas Krebbel Date: Tue, 20 Nov 2018 16:19:54 +0000 Subject: [PATCH] S/390: Fix flogr RTX. The flogr instruction uses a 64 bit register pair target operand. In the RTX we model this as a write to a TImode register. Unfortunately the RTX's being assigned to the two parts of the target operand were swapped. This is no problem if in the end the flogr instruction will be emitted since the instruction still does what the clzdi expander expects. However, a problem arises when the RTX is used to optimize CLZ for a constant input operand. Even then it matters only if the expression couldn't be folded on tree level already. In the testcase this happened thanks to loop unrolling on RTL level. The iteration variable is used as an argument to the clz builtin. Due to the loop unrolling it becomes a constant and after folding the broken RTX leads to a wrong assumption. gcc/ChangeLog: 2018-11-20 Andreas Krebbel * config/s390/s390.md ("clztidi2"): Swap the RTX's written to the DImode parts of the target operand. gcc/testsuite/ChangeLog: 2018-11-20 Andreas Krebbel * gcc.target/s390/flogr-1.c: New test. From-SVN: r266321 --- gcc/ChangeLog | 5 +++ gcc/config/s390/s390.md | 16 ++++----- gcc/testsuite/ChangeLog | 4 +++ gcc/testsuite/gcc.target/s390/flogr-1.c | 47 +++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.target/s390/flogr-1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d9af1e50781..779ed594878 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2018-11-20 Andreas Krebbel + + * config/s390/s390.md ("clztidi2"): Swap the RTX's written to the + DImode parts of the target operand. + 2018-11-20 Nathan Sidwell PR 87926 diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 721222d221f..30d113fd9cc 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -8759,17 +8759,17 @@ DONE; }) +; CLZ result is in hard reg op0 - this is the high part of the target operand +; The source with the left-most one bit cleared is in hard reg op0 + 1 - the low part (define_insn "clztidi2" [(set (match_operand:TI 0 "register_operand" "=d") (ior:TI - (ashift:TI - (zero_extend:TI - (xor:DI (match_operand:DI 1 "register_operand" "d") - (lshiftrt (match_operand:DI 2 "const_int_operand" "") - (subreg:SI (clz:DI (match_dup 1)) 4)))) - - (const_int 64)) - (zero_extend:TI (clz:DI (match_dup 1))))) + (ashift:TI (zero_extend:TI (clz:DI (match_operand:DI 1 "register_operand" "d"))) + (const_int 64)) + (zero_extend:TI + (xor:DI (match_dup 1) + (lshiftrt (match_operand:DI 2 "const_int_operand" "") + (subreg:SI (clz:DI (match_dup 1)) 4)))))) (clobber (reg:CC CC_REGNUM))] "UINTVAL (operands[2]) == HOST_WIDE_INT_1U << 63 && TARGET_EXTIMM && TARGET_ZARCH" diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4ec625f1768..d522b2cebdc 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2018-11-20 Andreas Krebbel + + * gcc.target/s390/flogr-1.c: New test. + 2018-11-20 Jan Hubicka PR ipa/87706 diff --git a/gcc/testsuite/gcc.target/s390/flogr-1.c b/gcc/testsuite/gcc.target/s390/flogr-1.c new file mode 100644 index 00000000000..a3869000d62 --- /dev/null +++ b/gcc/testsuite/gcc.target/s390/flogr-1.c @@ -0,0 +1,47 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -funroll-loops -march=z9-109" } */ +/* { dg-require-effective-target stdint_types } */ + +/* Folding of the FLOGR caused a wrong value to be returned by + __builtin_clz becuase of a problem in the RTX we emit for FLOGR. + The problematic folding can only be triggered with constants inputs + introduced on RTL level. In this case it happens with loop + unrolling. */ + +#include +#include + +static inline uint32_t pow2_ceil_u32(uint32_t x) { + if (x <= 1) { + return x; + } + int msb_on_index; + msb_on_index = (31 ^ __builtin_clz(x - 1)); + assert(msb_on_index < 31); + return 1U << (msb_on_index + 1); +} + +void __attribute__((noinline,noclone)) +die (int a) +{ + if (a) + __builtin_abort (); +} + +void test_pow2_ceil_u32(void) { + unsigned i; + + for (i = 0; i < 18; i++) { + uint32_t a_ = (pow2_ceil_u32(((uint32_t)1) << i)); + if (!(a_ == (((uint32_t)1) << i))) { + die(1); + } + } +} + +int +main(void) { + test_pow2_ceil_u32(); + + return 0; +} -- 2.30.2