From: sandra Date: Thu, 9 Aug 2007 14:08:54 +0000 (+0000) Subject: 2007-08-09 Sandra Loosemore X-Git-Tag: upstream/4.9.2~47046 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e533b20e5dabbb15601e49736e9e9ca917dcb44e;p=platform%2Fupstream%2Flinaro-gcc.git 2007-08-09 Sandra Loosemore Nigel Stephens gcc/ * doc/tm.texi (CLZ_DEFINED_VALUE_AT_ZERO, CTZ_DEFINED_VALUE_AT_ZERO): Document change in interpretation of value from boolean to tri-state integer. * optabs.c (expand_ffs, expand_ctz): New functions to compute ffs and ctz using clz. (expand_unop): Call them. * config/rs6000/rs6000.h (CLZ_DEFINED_VALUE_AT_ZERO): Fix its result value. (CTZ_DEFINED_VALUE_AT_ZERO): Likewise. * config/mips/mips.h (CLZ_DEFINED_VALUE_AT_ZERO): Likewise, to enable the new ffs expansion on this target. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127318 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d5170d8..826aa53 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2007-08-09 Sandra Loosemore + Nigel Stephens + + * doc/tm.texi (CLZ_DEFINED_VALUE_AT_ZERO, CTZ_DEFINED_VALUE_AT_ZERO): + Document change in interpretation of value from boolean to + tri-state integer. + * optabs.c (expand_ffs, expand_ctz): New functions to compute + ffs and ctz using clz. + (expand_unop): Call them. + * config/rs6000/rs6000.h (CLZ_DEFINED_VALUE_AT_ZERO): Fix its + result value. + (CTZ_DEFINED_VALUE_AT_ZERO): Likewise. + * config/mips/mips.h (CLZ_DEFINED_VALUE_AT_ZERO): Likewise, to + enable the new ffs expansion on this target. + 2007-08-09 Jan Hubicka * optabs.c (expand_widen_pattern_expr): Use optabs accestors. diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 9a55f02..9e90478 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -1295,7 +1295,7 @@ extern enum mips_code_readable_setting mips_code_readable; /* The [d]clz instructions have the natural values at 0. */ #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \ - ((VALUE) = GET_MODE_BITSIZE (MODE), true) + ((VALUE) = GET_MODE_BITSIZE (MODE), 2) /* Standard register usage. */ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index fae5ea2..5f34c80 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1856,10 +1856,10 @@ do { \ /* The cntlzw and cntlzd instructions return 32 and 64 for input of zero. */ #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \ - ((VALUE) = ((MODE) == SImode ? 32 : 64)) + ((VALUE) = ((MODE) == SImode ? 32 : 64), 1) /* The CTZ patterns return -1 for input of zero. */ -#define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = -1) +#define CTZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) ((VALUE) = -1, 1) /* Specify the machine mode that pointers have. After generation of rtl, the compiler makes no further distinction diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index bf6859d..1b690a1 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -9638,14 +9638,23 @@ given mode. @defmac CLZ_DEFINED_VALUE_AT_ZERO (@var{mode}, @var{value}) @defmacx CTZ_DEFINED_VALUE_AT_ZERO (@var{mode}, @var{value}) -A C expression that evaluates to true if the architecture defines a value -for @code{clz} or @code{ctz} with a zero operand. If so, @var{value} -should be set to this value. If this macro is not defined, the value of -@code{clz} or @code{ctz} is assumed to be undefined. +A C expression that indicates whether the architecture defines a value +for @code{clz} or @code{ctz} with a zero operand. +A result of @code{0} indicates the value is undefined. +If the value is defined for only the RTL expression, the macro should +evaluate to @code{1}; if the value applies also to the corresponding optab +entry (which is normally the case if it expands directly into +the corresponding RTL), then the macro should evaluate to @code{2}. +In the cases where the value is defined, @var{value} should be set to +this value. + +If this macro is not defined, the value of @code{clz} or +@code{ctz} at zero is assumed to be undefined. This macro must be defined if the target's expansion for @code{ffs} relies on a particular value to get correct results. Otherwise it -is not necessary, though it may be used to optimize some corner cases. +is not necessary, though it may be used to optimize some corner cases, and +to provide a default expansion for the @code{ffs} optab. Note that regardless of this macro the ``definedness'' of @code{clz} and @code{ctz} at zero do @emph{not} extend to the builtin functions diff --git a/gcc/optabs.c b/gcc/optabs.c index 5afd935..bf15d4f 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -122,6 +122,8 @@ static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *, enum machine_mode *, int *); static rtx widen_clz (enum machine_mode, rtx, rtx); static rtx expand_parity (enum machine_mode, rtx, rtx); +static rtx expand_ffs (enum machine_mode, rtx, rtx); +static rtx expand_ctz (enum machine_mode, rtx, rtx); static enum rtx_code get_rtx_code (enum tree_code, bool); static rtx vector_compare_rtx (tree, bool, enum insn_code); @@ -2561,6 +2563,68 @@ expand_parity (enum machine_mode mode, rtx op0, rtx target) return 0; } +/* Try calculating ffs(x) using clz(x). Since the ffs builtin promises + to return zero for a zero value and clz may have an undefined value + in that case, only do this if we know clz returns the right thing so + that we don't have to generate a test and branch. */ +static rtx +expand_ffs (enum machine_mode mode, rtx op0, rtx target) +{ + HOST_WIDE_INT val; + if (clz_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing + && CLZ_DEFINED_VALUE_AT_ZERO (mode, val) == 2 + && val == GET_MODE_BITSIZE (mode)) + { + rtx last = get_last_insn (); + rtx temp; + + temp = expand_unop (mode, neg_optab, op0, NULL_RTX, true); + if (temp) + temp = expand_binop (mode, and_optab, op0, temp, NULL_RTX, + true, OPTAB_DIRECT); + if (temp) + temp = expand_unop (mode, clz_optab, temp, NULL_RTX, true); + if (temp) + temp = expand_binop (mode, sub_optab, + GEN_INT (GET_MODE_BITSIZE (mode)), + temp, + target, true, OPTAB_DIRECT); + if (temp == 0) + delete_insns_since (last); + return temp; + } + return 0; +} + +/* We can compute ctz(x) using clz(x) with a similar recipe. Here the ctz + builtin has an undefined result on zero, just like clz, so we don't have + to do that check. */ +static rtx +expand_ctz (enum machine_mode mode, rtx op0, rtx target) +{ + if (clz_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + { + rtx last = get_last_insn (); + rtx temp; + + temp = expand_unop (mode, neg_optab, op0, NULL_RTX, true); + if (temp) + temp = expand_binop (mode, and_optab, op0, temp, NULL_RTX, + true, OPTAB_DIRECT); + if (temp) + temp = expand_unop (mode, clz_optab, temp, NULL_RTX, true); + if (temp) + temp = expand_binop (mode, xor_optab, temp, + GEN_INT (GET_MODE_BITSIZE (mode) - 1), + target, + true, OPTAB_DIRECT); + if (temp == 0) + delete_insns_since (last); + return temp; + } + return 0; +} + /* Extract the OMODE lowpart from VAL, which has IMODE. Under certain conditions, VAL may already be a SUBREG against which we cannot generate a further SUBREG. In this case, we expect forcing the value into a @@ -2886,6 +2950,22 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target, return temp; } + /* Try implementing ffs (x) in terms of clz (x). */ + if (unoptab == ffs_optab) + { + temp = expand_ffs (mode, op0, target); + if (temp) + return temp; + } + + /* Try implementing ctz (x) in terms of clz (x). */ + if (unoptab == ctz_optab) + { + temp = expand_ctz (mode, op0, target); + if (temp) + return temp; + } + try_libcall: /* Now try a library call in this mode. */ if (optab_handler (unoptab, mode)->libfunc)