This patch converts LEGITIMATE_CONSTANT_P into a target hook and passes along the mode of the constant. This can then be used by 5/5.
The patch is a version of:
http://gcc.gnu.org/ml/gcc-patches/2011-04/msg00195.html
which is still pending review after two pings. It seems pretty simple though, so I think it's worth backporting now rather than waiting for upstream approval.
The backport is very much a cut-down version. Rather than convert all targets to the new hook, I've kept LEGITIMATE_CONSTANT_P around and made it the default implementation of the new hook. Only ARM defines the hook directly.
Note that the ARM definition is supposed to be identical to the old LEGITIMATE_CONSTANT_P version. Only 5/5 is meant to change it.
Richard
gcc/ * doc/tm.texi (LEGITIMATE_CONSTANT_P): Replace with... (TARGET_LEGITIMATE_CONSTANT_P): ...this. * target.h (gcc_target): Add legitimate_constant_p. * target-def.h (TARGET_LEGITIMATE_CONSTANT_P): Define. (TARGET_INITIALIZER): Include it. * calls.c (precompute_register_parameters): Replace uses of LEGITIMATE_CONSTANT_P with targetm.legitimate_constant_p. (emit_library_call_value_1): Likewise. * expr.c (move_block_to_reg, can_store_by_pieces, emit_move_insn) (compress_float_constant, emit_push_insn, expand_expr_real_1): Likewise. * recog.c (general_operand, immediate_operand): Likewise. * reload.c (find_reloads_toplev, find_reloads_address_part): Likewise. * reload1.c (init_eliminable_invariants): Likewise. * targhooks.h (default_legitimate_constant_p); Declare. * targhooks.c (default_legitimate_constant_p): New function.
* config/arm/arm-protos.h (arm_cannot_force_const_mem): Delete. * config/arm/arm.h (ARM_LEGITIMATE_CONSTANT_P): Likewise. (THUMB_LEGITIMATE_CONSTANT_P, LEGITIMATE_CONSTANT_P): Likewise. * config/arm/arm.c (TARGET_LEGITIMATE_CONSTANT_P): Define. (arm_legitimate_constant_p_1, thumb_legitimate_constant_p) (arm_legitimate_constant_p): New functions. (arm_cannot_force_const_mem): Make static.
Index: gcc/doc/tm.texi =================================================================== --- gcc/doc/tm.texi 2011-04-19 16:38:08.000000000 +0000 +++ gcc/doc/tm.texi 2011-04-19 16:38:15.000000000 +0000 @@ -2642,8 +2642,8 @@ instruction for loading an immediate val register, so @code{PREFERRED_RELOAD_CLASS} returns @code{NO_REGS} when @var{x} is a floating-point constant. If the constant can't be loaded into any kind of register, code generation will be better if -@code{LEGITIMATE_CONSTANT_P} makes the constant illegitimate instead -of using @code{PREFERRED_RELOAD_CLASS}. +@code{TARGET_LEGITIMATE_CONSTANT_P} makes the constant illegitimate instead +of using @code{TARGET_PREFERRED_RELOAD_CLASS}.
If an insn has pseudos in it after register allocation, reload will go through the alternatives and call repeatedly @code{PREFERRED_RELOAD_CLASS} @@ -5628,13 +5628,13 @@ addresses. Many RISC machines have no m You may assume that @var{addr} is a valid address for the machine. @end defmac
-@defmac LEGITIMATE_CONSTANT_P (@var{x}) -A C expression that is nonzero if @var{x} is a legitimate constant for -an immediate operand on the target machine. You can assume that -@var{x} satisfies @code{CONSTANT_P}, so you need not check this. In fact, -@samp{1} is a suitable definition for this macro on machines where -anything @code{CONSTANT_P} is valid. -@end defmac +@deftypefn {Target Hook} bool TARGET_LEGITIMATE_CONSTANT_P (enum machine_mode @var{mode}, rtx @var{x}) +This hook returns true if @var{x} is a legitimate constant for a +@var{mode}-mode immediate operand on the target machine. You can assume that +@var{x} satisfies @code{CONSTANT_P}, so you need not check this. + +The default definition returns true. +@end deftypefn
@deftypefn {Target Hook} rtx TARGET_DELEGITIMIZE_ADDRESS (rtx @var{x}) This hook is used to undo the possibly obfuscating effects of the Index: gcc/target.h =================================================================== --- gcc/target.h 2011-04-19 16:38:08.000000000 +0000 +++ gcc/target.h 2011-04-19 16:38:16.000000000 +0000 @@ -645,7 +645,10 @@ struct gcc_target /* Return true if the target supports conditional execution. */ bool (* have_conditional_execution) (void);
- /* True if the constant X cannot be placed in the constant pool. */ + /* See tm.texi. */ + bool (* legitimate_constant_p) (enum machine_mode, rtx); + + /* True if the constant X cannot be placed in the constant pool. */ bool (* cannot_force_const_mem) (rtx);
/* True if the insn X cannot be duplicated. */ Index: gcc/target-def.h =================================================================== --- gcc/target-def.h 2011-04-19 16:38:08.000000000 +0000 +++ gcc/target-def.h 2011-04-19 16:38:16.000000000 +0000 @@ -563,6 +563,7 @@ #define TARGET_BRANCH_TARGET_REGISTER_CL default_branch_target_register_class #define TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED hook_bool_bool_false #define TARGET_HAVE_CONDITIONAL_EXECUTION default_have_conditional_execution +#define TARGET_LEGITIMATE_CONSTANT_P default_legitimate_constant_p #define TARGET_CANNOT_FORCE_CONST_MEM hook_bool_rtx_false #define TARGET_CANNOT_COPY_INSN_P NULL #define TARGET_COMMUTATIVE_P hook_bool_const_rtx_commutative_p @@ -965,6 +966,7 @@ #define TARGET_INITIALIZER \ TARGET_BRANCH_TARGET_REGISTER_CLASS, \ TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED, \ TARGET_HAVE_CONDITIONAL_EXECUTION, \ + TARGET_LEGITIMATE_CONSTANT_P, \ TARGET_CANNOT_FORCE_CONST_MEM, \ TARGET_CANNOT_COPY_INSN_P, \ TARGET_COMMUTATIVE_P, \ Index: gcc/calls.c =================================================================== --- gcc/calls.c 2011-04-19 16:38:08.000000000 +0000 +++ gcc/calls.c 2011-04-19 16:38:15.000000000 +0000 @@ -674,7 +674,7 @@ precompute_register_parameters (int num_ /* If the value is a non-legitimate constant, force it into a pseudo now. TLS symbols sometimes need a call to resolve. */ if (CONSTANT_P (args[i].value) - && !LEGITIMATE_CONSTANT_P (args[i].value)) + && !targetm.legitimate_constant_p (args[i].mode, args[i].value)) args[i].value = force_reg (args[i].mode, args[i].value);
/* If we are to promote the function arg to a wider mode, @@ -3413,7 +3413,8 @@ emit_library_call_value_1 (int retval, r
/* Make sure it is a reasonable operand for a move or push insn. */ if (!REG_P (addr) && !MEM_P (addr) - && ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr))) + && !(CONSTANT_P (addr) + && targetm.legitimate_constant_p (Pmode, addr))) addr = force_operand (addr, NULL_RTX);
argvec[count].value = addr; @@ -3453,7 +3454,7 @@ emit_library_call_value_1 (int retval, r
/* Make sure it is a reasonable operand for a move or push insn. */ if (!REG_P (val) && !MEM_P (val) - && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val))) + && !(CONSTANT_P (val) && targetm.legitimate_constant_p (mode, val))) val = force_operand (val, NULL_RTX);
if (pass_by_reference (&args_so_far, mode, NULL_TREE, 1)) Index: gcc/expr.c =================================================================== --- gcc/expr.c 2011-04-19 16:38:08.000000000 +0000 +++ gcc/expr.c 2011-04-19 16:38:16.000000000 +0000 @@ -1537,7 +1537,7 @@ move_block_to_reg (int regno, rtx x, int if (nregs == 0) return;
- if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x)) + if (CONSTANT_P (x) && !targetm.legitimate_constant_p (mode, x)) x = validize_mem (force_const_mem (mode, x));
/* See if the machine can do this with a load multiple insn. */ @@ -2366,7 +2366,7 @@ can_store_by_pieces (unsigned HOST_WIDE_ offset -= size;
cst = (*constfun) (constfundata, offset, mode); - if (!LEGITIMATE_CONSTANT_P (cst)) + if (!targetm.legitimate_constant_p (mode, cst)) return 0;
if (!reverse) @@ -3440,7 +3440,7 @@ emit_move_insn (rtx x, rtx y)
y_cst = y;
- if (!LEGITIMATE_CONSTANT_P (y)) + if (!targetm.legitimate_constant_p (mode, y)) { y = force_const_mem (mode, y);
@@ -3496,7 +3496,7 @@ compress_float_constant (rtx x, rtx y)
REAL_VALUE_FROM_CONST_DOUBLE (r, y);
- if (LEGITIMATE_CONSTANT_P (y)) + if (targetm.legitimate_constant_p (dstmode, y)) oldcost = rtx_cost (y, SET, speed); else oldcost = rtx_cost (force_const_mem (dstmode, y), SET, speed); @@ -3519,7 +3519,7 @@ compress_float_constant (rtx x, rtx y)
trunc_y = CONST_DOUBLE_FROM_REAL_VALUE (r, srcmode);
- if (LEGITIMATE_CONSTANT_P (trunc_y)) + if (targetm.legitimate_constant_p (srcmode, trunc_y)) { /* Skip if the target needs extra instructions to perform the extension. */ @@ -3932,7 +3932,7 @@ emit_push_insn (rtx x, enum machine_mode by setting SKIP to 0. */ skip = (reg_parm_stack_space == 0) ? 0 : not_stack;
- if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x)) + if (CONSTANT_P (x) && !targetm.legitimate_constant_p (mode, x)) x = validize_mem (force_const_mem (mode, x));
/* If X is a hard register in a non-integer mode, copy it into a pseudo; @@ -8951,7 +8951,7 @@ expand_expr_real_1 (tree exp, rtx target constant and we don't need a memory reference. */ if (CONSTANT_P (op0) && mode2 != BLKmode - && LEGITIMATE_CONSTANT_P (op0) + && targetm.legitimate_constant_p (mode2, op0) && !must_force_mem) op0 = force_reg (mode2, op0);
Index: gcc/recog.c =================================================================== --- gcc/recog.c 2011-04-19 16:38:08.000000000 +0000 +++ gcc/recog.c 2011-04-19 16:38:16.000000000 +0000 @@ -932,7 +932,9 @@ general_operand (rtx op, enum machine_mo return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode || mode == VOIDmode) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) - && LEGITIMATE_CONSTANT_P (op)); + && targetm.legitimate_constant_p (mode == VOIDmode + ? GET_MODE (op) + : mode, op));
/* Except for certain constants with VOIDmode, already checked for, OP's mode must match MODE if MODE specifies a mode. */ @@ -1109,7 +1111,9 @@ immediate_operand (rtx op, enum machine_ && (GET_MODE (op) == mode || mode == VOIDmode || GET_MODE (op) == VOIDmode) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) - && LEGITIMATE_CONSTANT_P (op)); + && targetm.legitimate_constant_p (mode == VOIDmode + ? GET_MODE (op) + : mode, op)); }
/* Returns 1 if OP is an operand that is a CONST_INT. */ @@ -1175,7 +1179,9 @@ nonmemory_operand (rtx op, enum machine_ return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode || mode == VOIDmode) && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op)) - && LEGITIMATE_CONSTANT_P (op)); + && targetm.legitimate_constant_p (mode == VOIDmode + ? GET_MODE (op) + : mode, op)); }
if (GET_MODE (op) != mode && mode != VOIDmode) Index: gcc/reload.c =================================================================== --- gcc/reload.c 2011-04-19 16:38:08.000000000 +0000 +++ gcc/reload.c 2011-04-19 16:38:16.000000000 +0000 @@ -4739,7 +4739,8 @@ find_reloads_toplev (rtx x, int opnum, e simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno], GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x)); gcc_assert (tem); - if (CONSTANT_P (tem) && !LEGITIMATE_CONSTANT_P (tem)) + if (CONSTANT_P (tem) + && !targetm.legitimate_constant_p (GET_MODE (x), tem)) { tem = force_const_mem (GET_MODE (x), tem); i = find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), @@ -6061,7 +6062,7 @@ find_reloads_address_part (rtx x, rtx *l enum reload_type type, int ind_levels) { if (CONSTANT_P (x) - && (! LEGITIMATE_CONSTANT_P (x) + && (!targetm.legitimate_constant_p (mode, x) || PREFERRED_RELOAD_CLASS (x, rclass) == NO_REGS)) { x = force_const_mem (mode, x); @@ -6071,7 +6072,7 @@ find_reloads_address_part (rtx x, rtx *l
else if (GET_CODE (x) == PLUS && CONSTANT_P (XEXP (x, 1)) - && (! LEGITIMATE_CONSTANT_P (XEXP (x, 1)) + && (!targetm.legitimate_constant_p (GET_MODE (x), XEXP (x, 1)) || PREFERRED_RELOAD_CLASS (XEXP (x, 1), rclass) == NO_REGS)) { rtx tem; Index: gcc/reload1.c =================================================================== --- gcc/reload1.c 2011-04-19 16:38:08.000000000 +0000 +++ gcc/reload1.c 2011-04-19 16:38:16.000000000 +0000 @@ -4164,6 +4164,9 @@ init_eliminable_invariants (rtx first, b } else if (function_invariant_p (x)) { + enum machine_mode mode; + + mode = GET_MODE (SET_DEST (set)); if (GET_CODE (x) == PLUS) { /* This is PLUS of frame pointer and a constant, @@ -4176,12 +4179,11 @@ init_eliminable_invariants (rtx first, b reg_equiv_invariant[i] = x; num_eliminable_invariants++; } - else if (LEGITIMATE_CONSTANT_P (x)) + else if (targetm.legitimate_constant_p (mode, x)) reg_equiv_constant[i] = x; else { - reg_equiv_memory_loc[i] - = force_const_mem (GET_MODE (SET_DEST (set)), x); + reg_equiv_memory_loc[i] = force_const_mem (mode, x); if (! reg_equiv_memory_loc[i]) reg_equiv_init[i] = NULL_RTX; } Index: gcc/targhooks.h =================================================================== --- gcc/targhooks.h 2011-04-19 16:38:08.000000000 +0000 +++ gcc/targhooks.h 2011-04-19 16:38:16.000000000 +0000 @@ -132,3 +132,4 @@ extern bool default_addr_space_subset_p extern rtx default_addr_space_convert (rtx, tree, tree); extern unsigned int default_case_values_threshold (void); extern bool default_have_conditional_execution (void); +extern bool default_legitimate_constant_p (enum machine_mode, rtx); Index: gcc/targhooks.c =================================================================== --- gcc/targhooks.c 2011-04-19 16:38:08.000000000 +0000 +++ gcc/targhooks.c 2011-04-20 07:50:38.000000000 +0000 @@ -1008,4 +1008,15 @@ default_have_conditional_execution (void #endif }
+bool +default_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, + rtx x ATTRIBUTE_UNUSED) +{ +#ifdef LEGITIMATE_CONSTANT_P + return LEGITIMATE_CONSTANT_P (x); +#else + return true; +#endif +} + #include "gt-targhooks.h" Index: gcc/config/arm/arm-protos.h =================================================================== --- gcc/config/arm/arm-protos.h 2011-04-19 16:38:08.000000000 +0000 +++ gcc/config/arm/arm-protos.h 2011-04-19 16:38:16.000000000 +0000 @@ -81,7 +81,6 @@ extern void neon_disambiguate_copy (rtx extern enum reg_class coproc_secondary_reload_class (enum machine_mode, rtx, bool); extern bool arm_tls_referenced_p (rtx); -extern bool arm_cannot_force_const_mem (rtx);
extern int cirrus_memory_offset (rtx); extern int arm_coproc_mem_operand (rtx, bool); Index: gcc/config/arm/arm.h =================================================================== --- gcc/config/arm/arm.h 2011-04-19 16:38:08.000000000 +0000 +++ gcc/config/arm/arm.h 2011-04-19 16:38:16.000000000 +0000 @@ -1996,27 +1996,6 @@ #define ARM_OFFSETS_MUST_BE_WITHIN_SECTI #define TARGET_DEFAULT_WORD_RELOCATIONS 0 #endif
-/* Nonzero if the constant value X is a legitimate general operand. - It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. - - On the ARM, allow any integer (invalid ones are removed later by insn - patterns), nice doubles and symbol_refs which refer to the function's - constant pool XXX. - - When generating pic allow anything. */ -#define ARM_LEGITIMATE_CONSTANT_P(X) (flag_pic || ! label_mentioned_p (X)) - -#define THUMB_LEGITIMATE_CONSTANT_P(X) \ - ( GET_CODE (X) == CONST_INT \ - || GET_CODE (X) == CONST_DOUBLE \ - || CONSTANT_ADDRESS_P (X) \ - || flag_pic) - -#define LEGITIMATE_CONSTANT_P(X) \ - (!arm_cannot_force_const_mem (X) \ - && (TARGET_32BIT ? ARM_LEGITIMATE_CONSTANT_P (X) \ - : THUMB_LEGITIMATE_CONSTANT_P (X))) - #ifndef SUBTARGET_NAME_ENCODING_LENGTHS #define SUBTARGET_NAME_ENCODING_LENGTHS #endif Index: gcc/config/arm/arm.c =================================================================== --- gcc/config/arm/arm.c 2011-04-19 16:38:08.000000000 +0000 +++ gcc/config/arm/arm.c 2011-04-20 07:58:46.000000000 +0000 @@ -140,6 +140,8 @@ static void arm_internal_label (FILE *, static void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static bool arm_have_conditional_execution (void); +static bool arm_cannot_force_const_mem (enum machine_mode, rtx); +static bool arm_legitimate_constant_p (enum machine_mode, rtx); static bool arm_rtx_costs_1 (rtx, enum rtx_code, int*, bool); static bool arm_size_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *); static bool thumb2_size_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *); @@ -471,6 +473,9 @@ #define TARGET_HAVE_TLS true #undef TARGET_HAVE_CONDITIONAL_EXECUTION #define TARGET_HAVE_CONDITIONAL_EXECUTION arm_have_conditional_execution
+#undef TARGET_LEGITIMATE_CONSTANT_P +#define TARGET_LEGITIMATE_CONSTANT_P arm_legitimate_constant_p + #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM arm_cannot_force_const_mem
@@ -6451,9 +6456,41 @@ arm_tls_referenced_p (rtx x) return for_each_rtx (&x, arm_tls_operand_p_1, NULL); }
+/* Implement TARGET_LEGITIMATE_CONSTANT_P. + + On the ARM, allow any integer (invalid ones are removed later by insn + patterns), nice doubles and symbol_refs which refer to the function's + constant pool XXX. + + When generating pic allow anything. */ + +static bool +arm_legitimate_constant_p_1 (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + return flag_pic || !label_mentioned_p (x); +} + +static bool +thumb_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x) +{ + return (GET_CODE (x) == CONST_INT + || GET_CODE (x) == CONST_DOUBLE + || CONSTANT_ADDRESS_P (x) + || flag_pic); +} + +static bool +arm_legitimate_constant_p (enum machine_mode mode, rtx x) +{ + return (!arm_cannot_force_const_mem (x) + && (TARGET_32BIT + ? arm_legitimate_constant_p_1 (mode, x) + : thumb_legitimate_constant_p (mode, x))); +} + /* Implement TARGET_CANNOT_FORCE_CONST_MEM. */
-bool +static bool arm_cannot_force_const_mem (rtx x) { rtx base, offset;