diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 627ed8ecd52..235d652c0cc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2002-05-12 Richard Henderson + + * expr.c (compress_float_constant): New. + (emit_move_insn): Use it. + (float_extend_from_mem): New. + (init_expr_once): Initialize it. + * real.c (exact_real_truncate): New. + + * config/i386/i386.h (CONST_COSTS): Assume CONST_DOUBLE gets + dropped into memory; penalize for size. + (RTX_COSTS): FLOAT_EXTEND is free. + * config/i386/i386.md (extendsfdf2, extendsfxf2, extendsftf2, + extenddfxf2, extenddftf2): Accept constants and drop them to memory. + 2002-05-12 Richard Henderson * profile.h (profile_info): Add missing extern to declaration. diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 5bfa582e9a5..680605b9955 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -2595,16 +2595,21 @@ do { \ return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0; \ \ case CONST_DOUBLE: \ - { \ - int code; \ - if (GET_MODE (RTX) == VOIDmode) \ - return 0; \ - \ - code = standard_80387_constant_p (RTX); \ - return code == 1 ? 1 : \ - code == 2 ? 2 : \ - 3; \ - } + if (GET_MODE (RTX) == VOIDmode) \ + return 0; \ + switch (standard_80387_constant_p (RTX)) \ + { \ + case 1: /* 0.0 */ \ + return 1; \ + case 2: /* 1.0 */ \ + return 2; \ + default: \ + /* Start with (MEM (SYMBOL_REF)), since that's where \ + it'll probably end up. Add a penalty for size. */ \ + return (COSTS_N_INSNS (1) + (flag_pic != 0) \ + + (GET_MODE (RTX) == SFmode ? 0 \ + : GET_MODE (RTX) == DFmode ? 1 : 2)); \ + } /* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */ #define TOPLEVEL_COSTS_N_INSNS(N) \ @@ -2766,6 +2771,9 @@ do { \ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2); \ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add); \ \ + case FLOAT_EXTEND: \ + TOPLEVEL_COSTS_N_INSNS (0); \ + \ egress_rtx_costs: \ break; diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 54e1305e8ec..11ab6f42177 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -3367,9 +3367,13 @@ (define_expand "extendsfdf2" [(set (match_operand:DF 0 "nonimmediate_operand" "") - (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))] + (float_extend:DF (match_operand:SF 1 "general_operand" "")))] "TARGET_80387 || TARGET_SSE2" { + /* ??? Needed for compress_float_constant since all fp constants + are LEGITIMATE_CONSTANT_P. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (SFmode, operands[1]); }) @@ -3418,9 +3422,13 @@ (define_expand "extendsfxf2" [(set (match_operand:XF 0 "nonimmediate_operand" "") - (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "")))] + (float_extend:XF (match_operand:SF 1 "general_operand" "")))] "!TARGET_64BIT && TARGET_80387" { + /* ??? Needed for compress_float_constant since all fp constants + are LEGITIMATE_CONSTANT_P. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (SFmode, operands[1]); }) @@ -3459,9 +3467,13 @@ (define_expand "extendsftf2" [(set (match_operand:TF 0 "nonimmediate_operand" "") - (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "")))] + (float_extend:TF (match_operand:SF 1 "general_operand" "")))] "TARGET_80387" { + /* ??? Needed for compress_float_constant since all fp constants + are LEGITIMATE_CONSTANT_P. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (SFmode, operands[1]); }) @@ -3500,9 +3512,13 @@ (define_expand "extenddfxf2" [(set (match_operand:XF 0 "nonimmediate_operand" "") - (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))] + (float_extend:XF (match_operand:DF 1 "general_operand" "")))] "!TARGET_64BIT && TARGET_80387" { + /* ??? Needed for compress_float_constant since all fp constants + are LEGITIMATE_CONSTANT_P. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (DFmode, operands[1]); }) @@ -3541,9 +3557,13 @@ (define_expand "extenddftf2" [(set (match_operand:TF 0 "nonimmediate_operand" "") - (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "")))] + (float_extend:TF (match_operand:DF 1 "general_operand" "")))] "TARGET_80387" { + /* ??? Needed for compress_float_constant since all fp constants + are LEGITIMATE_CONSTANT_P. */ + if (GET_CODE (operands[1]) == CONST_DOUBLE) + operands[1] = validize_mem (force_const_mem (SFmode, operands[1])); if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM) operands[1] = force_reg (DFmode, operands[1]); }) diff --git a/gcc/expr.c b/gcc/expr.c index 84443e014e6..1a8d0518323 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -134,6 +134,7 @@ static void store_by_pieces_1 PARAMS ((struct store_by_pieces *, static void store_by_pieces_2 PARAMS ((rtx (*) (rtx, ...), enum machine_mode, struct store_by_pieces *)); +static rtx compress_float_constant PARAMS ((rtx, rtx)); static rtx get_subtarget PARAMS ((rtx)); static int is_zeros_p PARAMS ((tree)); static int mostly_zeros_p PARAMS ((tree)); @@ -167,6 +168,10 @@ static void do_tablejump PARAMS ((rtx, enum machine_mode, rtx, rtx, rtx)); static char direct_load[NUM_MACHINE_MODES]; static char direct_store[NUM_MACHINE_MODES]; +/* Record for each mode whether we can float-extend from memory. */ + +static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES]; + /* If a memory-to-memory move would take MOVE_RATIO or more simple move-instruction sequences, we will do a movstr or libcall instead. */ @@ -265,6 +270,28 @@ init_expr_once () } } + mem = gen_rtx_MEM (VOIDmode, gen_rtx_raw_REG (Pmode, 10000)); + + for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode; + mode = GET_MODE_WIDER_MODE (mode)) + { + enum machine_mode srcmode; + for (srcmode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); srcmode != mode; + srcmode = GET_MODE_WIDER_MODE (srcmode)) + { + enum insn_code ic; + + ic = can_extend_p (mode, srcmode, 0); + if (ic == CODE_FOR_nothing) + continue; + + PUT_MODE (mem, srcmode); + + if ((*insn_data[ic].operand[1].predicate) (mem, srcmode)) + float_extend_from_mem[mode][srcmode] = true; + } + } + end_sequence (); } @@ -2771,10 +2798,18 @@ emit_move_insn (x, y) /* Never force constant_p_rtx to memory. */ if (GET_CODE (y) == CONSTANT_P_RTX) ; - else if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y)) + else if (CONSTANT_P (y)) { - y_cst = y; - y = force_const_mem (mode, y); + if (optimize + && FLOAT_MODE_P (GET_MODE (x)) + && (last_insn = compress_float_constant (x, y))) + return last_insn; + + if (!LEGITIMATE_CONSTANT_P (y)) + { + y_cst = y; + y = force_const_mem (mode, y); + } } /* If X or Y are memory references, verify that their addresses are valid @@ -3100,6 +3135,64 @@ emit_move_insn_1 (x, y) else abort (); } + +/* If Y is representable exactly in a narrower mode, and the target can + perform the extension directly from constant or memory, then emit the + move as an extension. */ + +static rtx +compress_float_constant (x, y) + rtx x, y; +{ + enum machine_mode dstmode = GET_MODE (x); + enum machine_mode orig_srcmode = GET_MODE (y); + enum machine_mode srcmode; + REAL_VALUE_TYPE r; + + REAL_VALUE_FROM_CONST_DOUBLE (r, y); + + for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode)); + srcmode != orig_srcmode; + srcmode = GET_MODE_WIDER_MODE (srcmode)) + { + enum insn_code ic; + rtx trunc_y, last_insn; + + /* Skip if the target can't extend this way. */ + ic = can_extend_p (dstmode, srcmode, 0); + if (ic == CODE_FOR_nothing) + continue; + + /* Skip if the narrowed value isn't exact. */ + if (! exact_real_truncate (srcmode, &r)) + continue; + + trunc_y = CONST_DOUBLE_FROM_REAL_VALUE (r, srcmode); + + if (LEGITIMATE_CONSTANT_P (trunc_y)) + { + /* Skip if the target needs extra instructions to perform + the extension. */ + if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode)) + continue; + } + else if (float_extend_from_mem[dstmode][srcmode]) + trunc_y = validize_mem (force_const_mem (srcmode, trunc_y)); + else + continue; + + emit_unop_insn (ic, x, trunc_y, UNKNOWN); + last_insn = get_last_insn (); + + if (GET_CODE (x) == REG) + REG_NOTES (last_insn) + = gen_rtx_EXPR_LIST (REG_EQUAL, y, REG_NOTES (last_insn)); + + return last_insn; + } + + return NULL_RTX; +} /* Pushing data onto the stack. */ diff --git a/gcc/real.c b/gcc/real.c index 91298626076..a4196981a1b 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -1066,6 +1066,22 @@ real_value_truncate (mode, arg) return (r); } +/* Return true if ARG can be represented exactly in MODE. */ + +bool +exact_real_truncate (mode, arg) + enum machine_mode mode; + REAL_VALUE_TYPE *arg; +{ + REAL_VALUE_TYPE trunc; + + if (target_isnan (*arg)) + return false; + + trunc = real_value_truncate (mode, *arg); + return ereal_cmp (*arg, trunc) == 0; +} + /* Try to change R into its exact multiplicative inverse in machine mode MODE. Return nonzero function value if successful. */