From 4e74d8ec4b55e5a28738f5d3a2cb99335c0098f4 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Mon, 11 Mar 1996 18:57:23 +0000 Subject: [PATCH] Make long longs use normal CONST_DOUBLE in movdi, do not split too early From-SVN: r11513 --- gcc/config/rs6000/rs6000.c | 112 ++++++++++++++++++++-- gcc/config/rs6000/rs6000.h | 11 ++- gcc/config/rs6000/rs6000.md | 181 +++++++++++++++++++++++++++--------- 3 files changed, 246 insertions(+), 58 deletions(-) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 6d89bea6ff8..34fdab7b239 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -524,6 +524,90 @@ reg_or_cint_operand (op, mode) return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode); } +/* Return the number of instructions it takes to form a constant in an + integer register. */ + +static int +num_insns_constant_wide (value) + HOST_WIDE_INT value; +{ + /* signed constant loadable with {cal|addi} */ + if (((unsigned HOST_WIDE_INT)value + 0x8000) < 0x10000) + return 1; + +#if HOST_BITS_PER_WIDE_INT == 32 + /* constant loadable with {cau|addis} */ + else if ((value & 0xffff) == 0) + return 1; + +#else + /* constant loadable with {cau|addis} */ + else if ((value & 0xffff) == 0 && (value & ~0xffffffff) == 0) + return 1; + + else if (TARGET_64BIT) + { + HOST_WIDE_INT low = value & 0xffffffff; + HOST_WIDE_INT high = value >> 32; + + if (high == 0 && (low & 0x80000000) == 0) + return 2; + + else if (high == 0xffffffff && (low & 0x80000000) != 0) + return 2; + + else if (!low) + return num_insns_constant_wide (high) + 1; + + else + return (num_insns_constant_wide (high) + + num_insns_constant_low (low) + 1); + } +#endif + + else + return 2; +} + +int +num_insns_constant (op, mode) + rtx op; + enum machine_mode mode; +{ + if (mode != SImode && mode != DImode) + abort (); + + if (GET_CODE (op) == CONST_INT) + return num_insns_constant_wide (INTVAL (op)); + + else if (GET_CODE (op) == CONST_DOUBLE && TARGET_32BIT) + return (num_insns_constant_wide (CONST_DOUBLE_LOW (op)) + + num_insns_constant_wide (CONST_DOUBLE_HIGH (op))); + + else if (GET_CODE (op) == CONST_DOUBLE && TARGET_64BIT) + { + HOST_WIDE_INT low = CONST_DOUBLE_LOW (op); + HOST_WIDE_INT high = CONST_DOUBLE_HIGH (op); + + if (high == 0 && (low & 0x80000000) == 0) + return num_insns_constant_wide (low); + + else if (((high & 0xffffffff) == 0xffffffff) + && ((low & 0x80000000) != 0)) + return num_insns_constant_wide (low); + + else if (low == 0) + return num_insns_constant_wide (high) + 1; + + else + return (num_insns_constant_wide (high) + + num_insns_constant_wide (low) + 1); + } + + else + abort (); +} + /* Return 1 if the operand is a CONST_DOUBLE and it can be put into a register with one instruction per word. We only do this if we can safely read CONST_DOUBLE_{LOW,HIGH}. */ @@ -535,11 +619,11 @@ easy_fp_constant (op, mode) { if (GET_CODE (op) != CONST_DOUBLE || GET_MODE (op) != mode - || GET_MODE_CLASS (mode) != MODE_FLOAT) + || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode)) return 0; /* Consider all constants with -msoft-float to be easy */ - if (TARGET_SOFT_FLOAT) + if (TARGET_SOFT_FLOAT && mode != DImode) return 1; if (mode == DFmode) @@ -550,10 +634,11 @@ easy_fp_constant (op, mode) REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_DOUBLE (rv, k); - return (((unsigned) (k[0] + 0x8000) < 0x10000 || (k[0] & 0xffff) == 0) - && ((unsigned) (k[1] + 0x8000) < 0x10000 || (k[1] & 0xffff) == 0)); + return (num_insns_constant_wide ((HOST_WIDE_INT)k[0]) == 1 + && num_insns_constant_wide ((HOST_WIDE_INT)k[1]) == 1); } - else + + else if (mode == SFmode) { long l; REAL_VALUE_TYPE rv; @@ -561,8 +646,14 @@ easy_fp_constant (op, mode) REAL_VALUE_FROM_CONST_DOUBLE (rv, op); REAL_VALUE_TO_TARGET_SINGLE (rv, l); - return ((unsigned) (l + 0x8000) < 0x10000 || (l & 0xffff) == 0); + return num_insns_constant_wide (l) == 1; } + + else if (mode == DImode && TARGET_32BIT) + return num_insns_constant (op, DImode) == 2; + + else + abort (); } /* Return 1 if the operand is in volatile memory. Note that during the @@ -821,6 +912,11 @@ input_operand (op, mode) && easy_fp_constant (op, mode)) return 1; + /* Allow any integer constant. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)) + return 1; + /* For floating-point or multi-word mode, the only remaining valid type is a register. */ if (GET_MODE_CLASS (mode) == MODE_FLOAT @@ -833,10 +929,6 @@ input_operand (op, mode) if (register_operand (op, mode)) return 1; - /* For integer modes, any constant is ok. */ - if (GET_CODE (op) == CONST_INT) - return 1; - /* A SYMBOL_REF referring to the TOC is valid. */ if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (op)) return 1; diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index f49c687b36b..aa1e5f0af53 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -995,10 +995,14 @@ enum reg_class Here VALUE is the CONST_DOUBLE rtx itself. We flag for special constants when we can copy the constant into - a general register in two insns for DF and one insn for SF. */ + a general register in two insns for DF/DI and one insn for SF. -#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'G' ? easy_fp_constant (VALUE, GET_MODE (VALUE)) : 0) + 'H' is used for DI constants that take 3 insns. */ + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'G' ? easy_fp_constant (VALUE, GET_MODE (VALUE)) : \ + (C) == 'H' ? (num_insns_constant (VALUE, DImode) == 3) : \ + 0) /* Optional extra constraints for this machine. @@ -2819,6 +2823,7 @@ extern int reg_or_short_operand (); extern int reg_or_neg_short_operand (); extern int reg_or_u_short_operand (); extern int reg_or_cint_operand (); +extern int num_insns_constant (); extern int easy_fp_constant (); extern int volatile_mem_operand (); extern int offsettable_addr_operand (); diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index aa1b0fe6146..5c47d6a3648 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -5429,8 +5429,9 @@ if (GET_CODE (operands[0]) != REG) operands[1] = force_reg (DImode, operands[1]); - if (GET_CODE (operands[1]) == CONST_DOUBLE - || GET_CODE (operands[1]) == CONST_INT) + if (TARGET_64BIT + && (GET_CODE (operands[1]) == CONST_DOUBLE + || GET_CODE (operands[1]) == CONST_INT)) { HOST_WIDE_INT low; HOST_WIDE_INT high; @@ -5453,39 +5454,23 @@ } #endif - if (! TARGET_POWERPC64) - { - emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], - WORDS_BIG_ENDIAN), GEN_INT (low)); - - emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], - ! WORDS_BIG_ENDIAN), GEN_INT (high)); - DONE; - } - else - { - if (high + 0x8000 >= 0x10000) - { - emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], 1), - GEN_INT (high)); - emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32))); - if (low) - { - HOST_WIDE_INT low_low = low & 0xffff; - HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff); - if (low_high) - emit_insn (gen_iordi3 (operands[0], operands[0], - GEN_INT (low_high))); - if (low_low) - emit_insn (gen_iordi3 (operands[0], operands[0], - GEN_INT (low_low))); - } - } - else if (low) - emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], 1), - GEN_INT (low)); - DONE; - } + if (high) + { + emit_move_insn (operands[0], GEN_INT (high)); + emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32))); + if (low) + { + HOST_WIDE_INT low_low = low & 0xffff; + HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff); + if (low_high) + emit_insn (gen_iordi3 (operands[0], operands[0], + GEN_INT (low_high))); + if (low_low) + emit_insn (gen_iordi3 (operands[0], operands[0], + GEN_INT (low_low))); + } + DONE; + } } /* Stores between FPR and any non-FPR registers must go through a @@ -5506,10 +5491,11 @@ }") (define_insn "" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m") - (match_operand:DI 1 "input_operand" "r,m,r,f,m,f"))] - "! TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode) - || gpc_reg_operand (operands[1], DImode))" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m,r,r,r,r,r") + (match_operand:DI 1 "input_operand" "r,m,r,f,m,f,IJK,n,G,H,F"))] + "TARGET_32BIT + && (gpc_reg_operand (operands[0], DImode) + || gpc_reg_operand (operands[1], DImode))" "* { switch (which_alternative) @@ -5540,16 +5526,121 @@ return \"lfd%U1%X1 %0,%1\"; case 5: return \"stfd%U0%X0 %1,%0\"; + case 6: + case 7: + case 8: + case 9: + case 10: + return \"#\"; } }" - [(set_attr "type" "*,load,store,fp,fpload,fpstore") - (set_attr "length" "8,8,8,*,*,*")]) + [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*") + (set_attr "length" "8,8,8,*,*,*,8,12,8,12,16")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 1" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 1))] + " +{ + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx; +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 2" + [(set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 6)))] + " +{ + HOST_WIDE_INT value = INTVAL (operands[1]); + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx; + operands[5] = GEN_INT (value & 0xffff0000); + operands[6] = GEN_INT (value & 0x0000ffff); +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 2" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + operands[5] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) == 3" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6)))] + " +{ + HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]); + HOST_WIDE_INT low = CONST_DOUBLE_LOW (operands[1]); + rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + rtx low_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + + if (((unsigned HOST_WIDE_INT) (low + 0x8000) < 0x10000) + || (low & 0xffff) == 0) + { + operands[2] = high_reg; + operands[3] = low_reg; + operands[4] = GEN_INT (high & 0xffff0000); + operands[5] = GEN_INT (low); + operands[6] = GEN_INT (high & 0x0000ffff); + } + else + { + operands[2] = low_reg; + operands[3] = high_reg; + operands[4] = GEN_INT (low & 0xffff0000); + operands[5] = GEN_INT (high); + operands[6] = GEN_INT (low & 0x0000ffff); + } +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 4" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6))) + (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 7)))] + " +{ + HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]); + HOST_WIDE_INT low = CONST_DOUBLE_LOW (operands[1]); + + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = GEN_INT (high & 0xffff0000); + operands[5] = GEN_INT (low & 0xffff0000); + operands[6] = GEN_INT (high & 0x0000ffff); + operands[7] = GEN_INT (low & 0x0000ffff); +}") (define_insn "" [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,f,f,m,r,*h,*h") - (match_operand:DI 1 "input_operand" "r,m,r,I,J,n,R,f,m,f,*h,r,0"))] - "TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode) - || gpc_reg_operand (operands[1], DImode))" + (match_operand:DI 1 "input_operand" "r,m,r,I,J,nF,R,f,m,f,*h,r,0"))] + "TARGET_64BIT + && (gpc_reg_operand (operands[0], DImode) + || gpc_reg_operand (operands[1], DImode))" "@ mr %0,%1 ld%U1%X1 %0,%1 @@ -5574,7 +5665,7 @@ (define_split [(set (match_operand:DI 0 "gpc_reg_operand" "") (match_operand:DI 1 "const_double_operand" ""))] - "TARGET_POWERPC64" + "TARGET_64BIT && num_insns_constant (operands[1], DImode) > 1" [(set (match_dup 0) (match_dup 2)) (set (match_dup 0) -- 2.30.2