This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
use narrow fp constants
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 12 May 2002 10:16:30 -0700
- Subject: use narrow fp constants
Quite a few targets represent FP values in registers in a canonical
format, so that the "load single precision" instruction does an
implicit extend to double precision.
This patch takes advantage of that to reduce the memory required
for constants that can be represented exactly in a narrower mode.
Tested on i686 and alphaev6 linux.
I expect there may be other targets that can take advantage of
this that also require adjustments to their cost macros to avoid
CSE undoing the narrowing of the constants. There shouldn't be
many, since it is rare that LEGITIMATE_CONSTANT_P accepts all
FP constants.
r~
* 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.
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.452
diff -c -p -d -r1.452 expr.c
*** expr.c 7 May 2002 05:44:26 -0000 1.452
--- expr.c 12 May 2002 17:04:29 -0000
*************** static void store_by_pieces_1 PARAMS ((s
*** 134,139 ****
--- 134,140 ----
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));
*************** static void do_tablejump PARAMS ((rtx, e
*** 167,172 ****
--- 168,177 ----
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. */
*************** init_expr_once ()
*** 265,270 ****
--- 270,297 ----
}
}
+ 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 ();
}
*************** emit_move_insn (x, y)
*** 2771,2780 ****
/* Never force constant_p_rtx to memory. */
if (GET_CODE (y) == CONSTANT_P_RTX)
;
! else if (CONSTANT_P (y) && ! 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
--- 2798,2815 ----
/* Never force constant_p_rtx to memory. */
if (GET_CODE (y) == CONSTANT_P_RTX)
;
! else if (CONSTANT_P (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
*************** emit_move_insn_1 (x, y)
*** 3099,3104 ****
--- 3134,3197 ----
}
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. */
Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.70
diff -c -p -d -r1.70 real.c
*** real.c 9 May 2002 01:42:25 -0000 1.70
--- real.c 12 May 2002 17:04:30 -0000
*************** real_value_truncate (mode, arg)
*** 1066,1071 ****
--- 1066,1087 ----
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. */
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.258
diff -c -p -d -r1.258 i386.h
*** config/i386/i386.h 8 May 2002 23:05:40 -0000 1.258
--- config/i386/i386.h 12 May 2002 17:04:30 -0000
*************** do { \
*** 2595,2610 ****
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; \
! }
/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
#define TOPLEVEL_COSTS_N_INSNS(N) \
--- 2595,2615 ----
return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0; \
\
case CONST_DOUBLE: \
! 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) \
*************** do { \
*** 2765,2770 ****
--- 2770,2778 ----
if (!TARGET_64BIT && GET_MODE (X) == DImode) \
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;
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.357
diff -c -p -d -r1.357 i386.md
*** config/i386/i386.md 11 May 2002 17:16:28 -0000 1.357
--- config/i386/i386.md 12 May 2002 17:04:30 -0000
***************
*** 3367,3375 ****
(define_expand "extendsfdf2"
[(set (match_operand:DF 0 "nonimmediate_operand" "")
! (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))]
"TARGET_80387 || TARGET_SSE2"
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (SFmode, operands[1]);
})
--- 3367,3379 ----
(define_expand "extendsfdf2"
[(set (match_operand:DF 0 "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,3426 ****
(define_expand "extendsfxf2"
[(set (match_operand:XF 0 "nonimmediate_operand" "")
! (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "")))]
"!TARGET_64BIT && TARGET_80387"
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (SFmode, operands[1]);
})
--- 3422,3434 ----
(define_expand "extendsfxf2"
[(set (match_operand:XF 0 "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,3467 ****
(define_expand "extendsftf2"
[(set (match_operand:TF 0 "nonimmediate_operand" "")
! (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "")))]
"TARGET_80387"
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (SFmode, operands[1]);
})
--- 3467,3479 ----
(define_expand "extendsftf2"
[(set (match_operand:TF 0 "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,3508 ****
(define_expand "extenddfxf2"
[(set (match_operand:XF 0 "nonimmediate_operand" "")
! (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))]
"!TARGET_64BIT && TARGET_80387"
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (DFmode, operands[1]);
})
--- 3512,3524 ----
(define_expand "extenddfxf2"
[(set (match_operand:XF 0 "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,3549 ****
(define_expand "extenddftf2"
[(set (match_operand:TF 0 "nonimmediate_operand" "")
! (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "")))]
"TARGET_80387"
{
if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (DFmode, operands[1]);
})
--- 3557,3569 ----
(define_expand "extenddftf2"
[(set (match_operand:TF 0 "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]);
})