The signbit-3.c test explicitly tests for the value coming from memory, a vector register, or a GPR. Unfortunately, the code did not handle splitting up the registers when the value was in a GPR.
These patches add teh GPR support. While I was editing the code, I also did some cleanup. I removed the Fsignbit mode attribute, since the only two modes used both use the same attribute. This is a relic of the original code generation that also provided optimized signbit support for DFmode/SFmode. Since the DFmode/SFmode got dropped (GCC 6 was in stage 3, and we needed to get signbit working for __float128 -- it already worked for DFmode/SFmode, but the code generation could be improved). I also noticed that use of signbit tended to generate sign or zero extension. Since the function only returns 0/1, I added combiner insns to eliminate the extra zero/sign extend. I have tested this on both big endian and little endian power8 systems. The bootstrap and make check had no regressions. Is this ok to put into the trunk? The same error appears on GCC 6 as well. Assuming the patch applys cleanly and fixes the problem, can I install it on the GCC 6 branch as well after a burn in period? 2016-12-30 Michael Meissner <meiss...@linux.vnet.ibm.com> PR target/78900 * config/rs6000/rs6000.c (rs6000_split_signbit): Change some assertions. Add support for doing the signbit if the IEEE 128-bit floating point value is in a GPR. * config/rs6000/rs6000.md (Fsignbit): Delete. (signbit<mode>2_dm): Delete using <Fsignbit> and just use "wa". Update the length attribute if the value is in a GPR. (signbit<mode>2_dm_<su>ext): Add combiner pattern to eliminate the sign or zero extension instruction, since the value is always 0/1. (signbit<mode>2_dm2): Delete using <Fsignbit>. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.c =================================================================== --- gcc/config/rs6000/rs6000.c (revision 243966) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -25170,9 +25170,7 @@ rs6000_split_signbit (rtx dest, rtx src) rtx dest_di = (d_mode == DImode) ? dest : gen_lowpart (DImode, dest); rtx shift_reg = dest_di; - gcc_assert (REG_P (dest)); - gcc_assert (REG_P (src) || MEM_P (src)); - gcc_assert (s_mode == KFmode || s_mode == TFmode); + gcc_assert (FLOAT128_IEEE_P (s_mode) && TARGET_POWERPC64); if (MEM_P (src)) { @@ -25184,17 +25182,20 @@ rs6000_split_signbit (rtx dest, rtx src) else { - unsigned int r = REGNO (src); + unsigned int r = reg_or_subregno (src); - /* If this is a VSX register, generate the special mfvsrd instruction - to get it in a GPR. Until we support SF and DF modes, that will - always be true. */ - gcc_assert (VSX_REGNO_P (r)); + if (INT_REGNO_P (r)) + shift_reg = gen_rtx_REG (DImode, r + (BYTES_BIG_ENDIAN == 0)); - if (s_mode == KFmode) - emit_insn (gen_signbitkf2_dm2 (dest_di, src)); else - emit_insn (gen_signbittf2_dm2 (dest_di, src)); + { + /* Generate the special mfvsrd instruction to get it in a GPR. */ + gcc_assert (VSX_REGNO_P (r)); + if (s_mode == KFmode) + emit_insn (gen_signbitkf2_dm2 (dest_di, src)); + else + emit_insn (gen_signbittf2_dm2 (dest_di, src)); + } } emit_insn (gen_lshrdi3 (dest_di, shift_reg, GEN_INT (63))); Index: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (revision 243966) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -518,9 +518,6 @@ (define_mode_iterator FLOAT128 [(KF "TAR (define_mode_iterator SIGNBIT [(KF "FLOAT128_VECTOR_P (KFmode)") (TF "FLOAT128_VECTOR_P (TFmode)")]) -(define_mode_attr Fsignbit [(KF "wa") - (TF "wa")]) - ; Iterator for ISA 3.0 supported floating point types (define_mode_iterator FP_ISA3 [SF DF @@ -4744,7 +4741,7 @@ (define_expand "copysign<mode>3" (define_insn_and_split "signbit<mode>2_dm" [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r") (unspec:SI - [(match_operand:SIGNBIT 1 "input_operand" "<Fsignbit>,m,r")] + [(match_operand:SIGNBIT 1 "input_operand" "wa,m,r")] UNSPEC_SIGNBIT))] "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" "#" @@ -4754,7 +4751,24 @@ (define_insn_and_split "signbit<mode>2_d rs6000_split_signbit (operands[0], operands[1]); DONE; } - [(set_attr "length" "8,8,12") + [(set_attr "length" "8,8,4") + (set_attr "type" "mftgpr,load,integer")]) + +(define_insn_and_split "*signbit<mode>2_dm_<su>ext" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r") + (any_extend:DI + (unspec:SI + [(match_operand:SIGNBIT 1 "input_operand" "wa,m,r")] + UNSPEC_SIGNBIT)))] + "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rs6000_split_signbit (operands[0], operands[1]); + DONE; +} + [(set_attr "length" "8,8,4") (set_attr "type" "mftgpr,load,integer")]) ;; MODES_TIEABLE_P doesn't allow DImode to be tied with the various floating @@ -4762,7 +4776,7 @@ (define_insn_and_split "signbit<mode>2_d ;; special pattern to avoid using a normal movdi. (define_insn "signbit<mode>2_dm2" [(set (match_operand:DI 0 "gpc_reg_operand" "=r") - (unspec:DI [(match_operand:SIGNBIT 1 "gpc_reg_operand" "<Fsignbit>") + (unspec:DI [(match_operand:SIGNBIT 1 "gpc_reg_operand" "wa") (const_int 0)] UNSPEC_SIGNBIT))] "TARGET_POWERPC64 && TARGET_DIRECT_MOVE"