Message ID | 20181125122027.GP21617@bubble.grove.modra.org |
---|---|
State | New |
Headers | show |
Series | [RS6000] PowerPC64 soft-float | expand |
Hi! On Sun, Nov 25, 2018 at 10:50:27PM +1030, Alan Modra wrote: > This patch aims to prevent long sequences loading soft-float > constants. For 32-bit, it makes sense to load values inline to a gpr > with lis, addi, but not so much for 64-bit where a 5 insn sequence > might be needed for each gpr. For TFmode in particular, a 10 insn > sequence is reduced to 2 loads from memory plus 1 or 2 address setup > insns. > > Bootstrapped etc. powerpc64le-linux and powerpc64-linux. OK for > next stage1? It's okay now, even. > * config/rs6000/predicates.md (easy_fp_constant): Avoid long > dependent insn sequences. > * config/rs6000/rs6000.c (num_insns_constant): Support long > double constants. > * config/rs6000/rs6000.md (mov<mode>_softfloat128) Adjust length > attribute. > - /* Consider all constants with -msoft-float to be easy. */ > - if (TARGET_SOFT_FLOAT) > + /* Consider all constants with -msoft-float to be easy when regs are > + 32-bit and thus can be loaded with a maximum of 2 insns. For > + 64-bit avoid long dependent insn sequences. */ > + if (TARGET_SOFT_FLOAT > + && (!TARGET_POWERPC64 > + || mode == SFmode || mode == SDmode > + || ((mode == DFmode || mode == DDmode) > + && (num_insns_constant (op, mode) > + <= (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2))) > + || ((mode == TFmode || mode == TDmode > + || mode == KFmode || mode == IFmode) > + && (num_insns_constant (op, mode) > + <= (TARGET_CMODEL != CMODEL_SMALL ? 4 : 3))))) > return 1; Maybe this can be written simpler with MODE_SIZE (mode) >= 16 or such. if (TARGET_SOFT_FLOAT) { if (!TARGET_POWERPC64) return 1; int size = MODE_SIZE (mode); if (size == 4) return 1; int max_insns = 3; if (TARGET_CMODEL == CMODEL_SMALL) max_insns--; if (size >= 16) max_insns++; if (num_insns_constant (op, mode) <= max_insns) return 1; } Something like that, perhaps. It's not really shorter :-/ > + else if (mode == TFmode || mode == TDmode > + || mode == KFmode || mode == IFmode) > + { > + long l[4]; > + int ins; > + > + if (mode == TDmode) > + REAL_VALUE_TO_TARGET_DECIMAL128 (*rv, l); > + else > + REAL_VALUE_TO_TARGET_LONG_DOUBLE (*rv, l); > + > + val = l[WORDS_BIG_ENDIAN ? 0 : 3] << 32; > + val |= l[WORDS_BIG_ENDIAN ? 1 : 2] & 0xffffffffUL; You can't shift a "long" left by 32 bits. Cast to HOST_WIDE_INT? Maybe there is some helper already? > --- a/gcc/config/rs6000/rs6000.md > +++ b/gcc/config/rs6000/rs6000.md > @@ -7729,7 +7729,7 @@ (define_insn_and_split "*mov<mode>_softfloat128" > (const_string "8") > (const_string "16")) > (if_then_else (match_test "TARGET_POWERPC64") > - (const_string "40") > + (const_string "16") > (const_string "32")) > (if_then_else (match_test "TARGET_POWERPC64") > (const_string "8") I really would love to see this in stage3 still; it's arguably a bugfix. Segher
On Thu, Nov 29, 2018 at 12:15:06PM -0600, Segher Boessenkool wrote: > On Sun, Nov 25, 2018 at 10:50:27PM +1030, Alan Modra wrote: > > This patch aims to prevent long sequences loading soft-float > > constants. For 32-bit, it makes sense to load values inline to a gpr > > with lis, addi, but not so much for 64-bit where a 5 insn sequence > > might be needed for each gpr. For TFmode in particular, a 10 insn > > sequence is reduced to 2 loads from memory plus 1 or 2 address setup > > insns. > > > > Bootstrapped etc. powerpc64le-linux and powerpc64-linux. OK for > > next stage1? > > It's okay now, even. Thanks! Revised patch as per your other comments bootstrapped and regression tested powerpc64le-linux. * config/rs6000/predicates.md (easy_fp_constant): Avoid long dependent insn sequences. * config/rs6000/rs6000.c (num_insns_constant): Support long double constants. * config/rs6000/rs6000.md (mov<mode>_softfloat128) Adjust length attribute. diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index cf07d5c6372..94feae28c02 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -564,9 +564,26 @@ (define_predicate "easy_fp_constant" { gcc_assert (GET_MODE (op) == mode && SCALAR_FLOAT_MODE_P (mode)); - /* Consider all constants with -msoft-float to be easy. */ + /* Consider all constants with -msoft-float to be easy when regs are + 32-bit and thus can be loaded with a maximum of 2 insns. For + 64-bit avoid long dependent insn sequences. */ if (TARGET_SOFT_FLOAT) - return 1; + { + if (!TARGET_POWERPC64) + return 1; + + int size = GET_MODE_SIZE (mode); + if (size < 8) + return 1; + + int load_from_mem_insns = 2; + if (size > 8) + load_from_mem_insns++; + if (TARGET_CMODEL != CMODEL_SMALL) + load_from_mem_insns++; + if (num_insns_constant (op, mode) <= load_from_mem_insns) + return 1; + } /* 0.0D is not all zero bits. */ if (DECIMAL_FLOAT_MODE_P (mode)) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c438fdc64fe..60c319de467 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -5940,6 +5940,25 @@ num_insns_constant (rtx op, machine_mode mode) val |= l[WORDS_BIG_ENDIAN ? 1 : 0] & 0xffffffffUL; mode = DImode; } + else if (mode == TFmode || mode == TDmode + || mode == KFmode || mode == IFmode) + { + long l[4]; + int insns; + + if (mode == TDmode) + REAL_VALUE_TO_TARGET_DECIMAL128 (*rv, l); + else + REAL_VALUE_TO_TARGET_LONG_DOUBLE (*rv, l); + + val = (unsigned HOST_WIDE_INT) l[WORDS_BIG_ENDIAN ? 0 : 3] << 32; + val |= l[WORDS_BIG_ENDIAN ? 1 : 2] & 0xffffffffUL; + insns = num_insns_constant_multi (val, DImode); + val = (unsigned HOST_WIDE_INT) l[WORDS_BIG_ENDIAN ? 2 : 1] << 32; + val |= l[WORDS_BIG_ENDIAN ? 3 : 0] & 0xffffffffUL; + insns += num_insns_constant_multi (val, DImode); + return insns; + } else gcc_unreachable (); } diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index d2f6f11b3e5..797d5c32e64 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -7729,7 +7729,7 @@ (define_insn_and_split "*mov<mode>_softfloat" (const_string "8") (const_string "16")) (if_then_else (match_test "TARGET_POWERPC64") - (const_string "40") + (const_string "16") (const_string "32")) (if_then_else (match_test "TARGET_POWERPC64") (const_string "8")
On Fri, Nov 30, 2018 at 06:28:28PM +1030, Alan Modra wrote: > On Thu, Nov 29, 2018 at 12:15:06PM -0600, Segher Boessenkool wrote: > > On Sun, Nov 25, 2018 at 10:50:27PM +1030, Alan Modra wrote: > > > This patch aims to prevent long sequences loading soft-float > > > constants. For 32-bit, it makes sense to load values inline to a gpr > > > with lis, addi, but not so much for 64-bit where a 5 insn sequence > > > might be needed for each gpr. For TFmode in particular, a 10 insn > > > sequence is reduced to 2 loads from memory plus 1 or 2 address setup > > > insns. > > > > > > Bootstrapped etc. powerpc64le-linux and powerpc64-linux. OK for > > > next stage1? > > > > It's okay now, even. > > Thanks! Revised patch as per your other comments bootstrapped and > regression tested powerpc64le-linux. That looks great. Okay for trunk. Thanks! > * config/rs6000/predicates.md (easy_fp_constant): Avoid long > dependent insn sequences. > * config/rs6000/rs6000.c (num_insns_constant): Support long > double constants. > * config/rs6000/rs6000.md (mov<mode>_softfloat128) Adjust length > attribute. Missing colon on that last line. Segher
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 9fbeb928fe6..349f38c44f2 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -565,8 +565,19 @@ (define_predicate "easy_fp_constant" gcc_assert (GET_MODE (op) == mode && SCALAR_FLOAT_MODE_P (mode)); - /* Consider all constants with -msoft-float to be easy. */ - if (TARGET_SOFT_FLOAT) + /* Consider all constants with -msoft-float to be easy when regs are + 32-bit and thus can be loaded with a maximum of 2 insns. For + 64-bit avoid long dependent insn sequences. */ + if (TARGET_SOFT_FLOAT + && (!TARGET_POWERPC64 + || mode == SFmode || mode == SDmode + || ((mode == DFmode || mode == DDmode) + && (num_insns_constant (op, mode) + <= (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2))) + || ((mode == TFmode || mode == TDmode + || mode == KFmode || mode == IFmode) + && (num_insns_constant (op, mode) + <= (TARGET_CMODEL != CMODEL_SMALL ? 4 : 3))))) return 1; /* 0.0D is not all zero bits. */ diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 3364068d976..212e9facb3a 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -5934,6 +5934,25 @@ num_insns_constant (rtx op, machine_mode mode) val |= l[WORDS_BIG_ENDIAN ? 1 : 0] & 0xffffffffUL; mode = DImode; } + else if (mode == TFmode || mode == TDmode + || mode == KFmode || mode == IFmode) + { + long l[4]; + int ins; + + if (mode == TDmode) + REAL_VALUE_TO_TARGET_DECIMAL128 (*rv, l); + else + REAL_VALUE_TO_TARGET_LONG_DOUBLE (*rv, l); + + val = l[WORDS_BIG_ENDIAN ? 0 : 3] << 32; + val |= l[WORDS_BIG_ENDIAN ? 1 : 2] & 0xffffffffUL; + ins = num_insns_constant_multi (val, DImode); + val = l[WORDS_BIG_ENDIAN ? 2 : 1] << 32; + val |= l[WORDS_BIG_ENDIAN ? 3 : 0] & 0xffffffffUL; + ins += num_insns_constant_multi (val, DImode); + return ins; + } else gcc_unreachable (); } diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 11097717268..e75f35dac60 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -7729,7 +7729,7 @@ (define_insn_and_split "*mov<mode>_softfloat128" (const_string "8") (const_string "16")) (if_then_else (match_test "TARGET_POWERPC64") - (const_string "40") + (const_string "16") (const_string "32")) (if_then_else (match_test "TARGET_POWERPC64") (const_string "8")