Hi, the current cost computations in rtlanal.c and maybe other places suffer from the fact that they are hiding parts of the expressions from the back-end, like SET_DESTs of single_set or the anatomy of PARALELLs.
Would it be in order to have a hook like the one attached? I am aware of that, in an ideal world, there wouldn't be more than one hook to get rtx costs. But well... Whilst rtx_costs does in the majority of cases, there are cases where hiding information leads to performance degradation, for example when insn combine cooks up a set zero_extract. combine.c does actually the right thing as it uses insn_rtx_costs, but insn_rtx_cost is already a lie because it only uses SET_SRC and digs into PARALELL without exposing the whole story. The patch just uses a new targetm.insn_cost hook. If the back-end doesn't come up with something useful, the classic functions with rtx_costs for sub-rtxes are called. The purpose is to allow a friendly transition and not no raise any performance degradations which would be very likely if we just called rtx_costs with outer_code = INSN. If a back-end finds it useful to implement this hook and need the whole story, they can do so. Otherwise, or if it is too lazy to analyse a specific rtx, they can switch to the old infrastructure. Returning a magic value for "unknown" is just an implementation detail; it could just as well be some bool* that would be set to true or false depending on whether or not the computation returned something useful or not. The patch only touches seq_cost insn_rtx_cost of rtlanal.c. Would something like this be in order, or is a new hook just a complete no-go?
Index: coretypes.h =================================================================== --- coretypes.h (revision 250090) +++ coretypes.h (working copy) @@ -253,6 +253,10 @@ construct that is easy to avoid even whe WARN_STRICT_OVERFLOW_MAGNITUDE = 5 }; +/* A magic value to be returned by TARGET_INSN_COSTS to indicate that + the costs are not known or too complicated to work out there. */ +#define INSN_COSTS_UNKNOWN (-1234567) + /* The type of an alias set. Code currently assumes that variables of this type can take the values 0 (the alias set which aliases everything) and -1 (sometimes indicating that the alias set is Index: doc/tm.texi =================================================================== --- doc/tm.texi (revision 250123) +++ doc/tm.texi (working copy) @@ -6564,6 +6564,39 @@ optimizers should use optab @code{rintdf The default hook returns true for all inputs. @end deftypefn +@deftypefn {Target Hook} int TARGET_INSN_COSTS (const rtx_insn *@var{insn}, rtx @var{pattern}, bool @var{speed}) +This target hook describes the relative costs of an insn. + +@var{insn} might be NULL or an @code{INSN_P}. +@var{pattern} is the pattern of @var{insn} or an rtx that is supposed +to be used as the pattern of an insn the remainder of the compilation. + +In implementing this hook, you can use the construct +@code{COSTS_N_INSNS (@var{n})} to specify a cost equal to @var{n} +instructions. +When optimizing for execution speed, i.e.@: when @var{speed} is +true, this target hook should be used to estimate the relative +execution cost of the pattern, and the size cost of the pattern if +@var{speed} is false. + +Use this pattern if a @code{SET_DEST} is needed to calculate the correct +costs or when you want to see the whole of a @code{PARALLEL} and not only +parts of it. Notice that for a @code{single_set} you might see a +@code{PARALLEL} @var{pattern} that contains a @code{SET} together with +@code{COBBER}s. + +If the pattern is too complicated to be evaluated in this hook, return +@code{INSN_COSTS_UNKNOWN} which directs the middle-end to use other +approaches to get the respective costs like calling +@code{TARGET_RTX_COSTS} for sub-rtxes of @var{pattern}. + +Don't implement this hook if it would always return +@code{INSN_COSTS_UNKNOWN}. + +Don't use @code{INSN_COSTS_UNKNOWN} except as a return value for this hook. +Do @emph{not use} that value as a return value for @code{TARGET_RTX_COSTS}! +@end deftypefn + @deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, machine_mode @var{mode}, int @var{outer_code}, int @var{opno}, int *@var{total}, bool @var{speed}) This target hook describes the relative costs of RTL expressions. Index: doc/tm.texi.in =================================================================== --- doc/tm.texi.in (revision 250123) +++ doc/tm.texi.in (working copy) @@ -4790,6 +4790,8 @@ @samp{fold_range_test ()} is optimal. T @hook TARGET_OPTAB_SUPPORTED_P +@hook TARGET_INSN_COSTS + @hook TARGET_RTX_COSTS @hook TARGET_ADDRESS_COST Index: rtlanal.c =================================================================== --- rtlanal.c (revision 250090) +++ rtlanal.c (working copy) @@ -5263,6 +5263,10 @@ insn_rtx_cost (rtx pat, bool speed) int i, cost; rtx set; + int icost = targetm.insn_costs (NULL, pat, speed); + if (icost != INSN_COSTS_UNKNOWN) + return icost; + /* Extract the single set rtx from the instruction pattern. We can't use single_set since we only have the pattern. We also consider PARALLELs of a normal set and a single comparison. In @@ -5318,6 +5322,15 @@ seq_cost (const rtx_insn *seq, bool spee for (; seq; seq = NEXT_INSN (seq)) { + if (INSN_P (seq)) + { + int icost = targetm.insn_costs (seq, PATTERN (seq), speed); + if (icost != INSN_COSTS_UNKNOWN) + { + cost += icost; + continue; + } + } set = single_set (seq); if (set) cost += set_rtx_cost (set, speed); Index: target.def =================================================================== --- target.def (revision 250090) +++ target.def (working copy) @@ -3558,6 +3558,41 @@ DEFHOOKPOD appropriately.", unsigned int, INVALID_REGNUM) +DEFHOOK +(insn_costs, +"This target hook describes the relative costs of an insn.\n\ +\n\ +@var{insn} might be NULL or an @code{INSN_P}.\n\ +@var{pattern} is the pattern of @var{insn} or an rtx that is supposed\n\ +to be used as the pattern of an insn the remainder of the compilation.\n\ +\n\ +In implementing this hook, you can use the construct\n\ +@code{COSTS_N_INSNS (@var{n})} to specify a cost equal to @var{n}\n\ +instructions.\n\ +When optimizing for execution speed, i.e.@: when @var{speed} is\n\ +true, this target hook should be used to estimate the relative\n\ +execution cost of the pattern, and the size cost of the pattern if\n\ +@var{speed} is false.\n\ +\n\ +Use this pattern if a @code{SET_DEST} is needed to calculate the correct\n\ +costs or when you want to see the whole of a @code{PARALLEL} and not only\n\ +parts of it. Notice that for a @code{single_set} you might see a\n\ +@code{PARALLEL} @var{pattern} that contains a @code{SET} together with\n\ +@code{COBBER}s.\n\ +\n\ +If the pattern is too complicated to be evaluated in this hook, return\n\ +@code{INSN_COSTS_UNKNOWN} which directs the middle-end to use other\n\ +approaches to get the respective costs like calling\n\ +@code{TARGET_RTX_COSTS} for sub-rtxes of @var{pattern}.\n\ +\n\ +Don't implement this hook if it would always return\n\ +@code{INSN_COSTS_UNKNOWN}.\n\ +\n\ +Don't use @code{INSN_COSTS_UNKNOWN} except as a return value for this hook.\n\ +Do @emph{not use} that value as a return value for @code{TARGET_RTX_COSTS}!", + int, (const rtx_insn *insn, rtx pattern, bool speed), + default_insn_costs) + /* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */ Index: targhooks.c =================================================================== --- targhooks.c (revision 250090) +++ targhooks.c (working copy) @@ -2108,4 +2108,10 @@ default_excess_precision (enum excess_pr return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT; } +int +default_insn_costs (const rtx_insn*, rtx, bool) +{ + return INSN_COSTS_UNKNOWN; +} + #include "gt-targhooks.h" Index: targhooks.h =================================================================== --- targhooks.h (revision 250090) +++ targhooks.h (working copy) @@ -264,4 +264,6 @@ extern unsigned int default_min_arithmet extern enum flt_eval_method default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED); +extern int default_insn_costs (const rtx_insn*, rtx, bool); + #endif /* GCC_TARGHOOKS_H */