tm.texi (CLZ_DEFINED_VALUE_AT_ZERO, [...]): Document change in interpretation of value from boolean to tri-state integer.

2007-08-09  Sandra Loosemore  <sandra@codesourcery.com>
	    Nigel Stephens  <nigel@mips.com>

	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.

Co-Authored-By: Nigel Stephens <nigel@mips.com>

From-SVN: r127318
This commit is contained in:
Sandra Loosemore 2007-08-09 10:08:54 -04:00 committed by Sandra Loosemore
parent 166cdb08f2
commit 14670a74f8
5 changed files with 112 additions and 8 deletions

View File

@ -1,3 +1,18 @@
2007-08-09 Sandra Loosemore <sandra@codesourcery.com>
Nigel Stephens <nigel@mips.com>
* 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 <jh@suse.cz> 2007-08-09 Jan Hubicka <jh@suse.cz>
* optabs.c (expand_widen_pattern_expr): Use optabs accestors. * optabs.c (expand_widen_pattern_expr): Use optabs accestors.

View File

@ -1295,7 +1295,7 @@ extern enum mips_code_readable_setting mips_code_readable;
/* The [d]clz instructions have the natural values at 0. */ /* The [d]clz instructions have the natural values at 0. */
#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \ #define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \
((VALUE) = GET_MODE_BITSIZE (MODE), true) ((VALUE) = GET_MODE_BITSIZE (MODE), 2)
/* Standard register usage. */ /* Standard register usage. */

View File

@ -1856,10 +1856,10 @@ do { \
/* The cntlzw and cntlzd instructions return 32 and 64 for input of zero. */ /* The cntlzw and cntlzd instructions return 32 and 64 for input of zero. */
#define CLZ_DEFINED_VALUE_AT_ZERO(MODE, VALUE) \ #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. */ /* 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. /* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction After generation of rtl, the compiler makes no further distinction

View File

@ -9638,14 +9638,23 @@ given mode.
@defmac CLZ_DEFINED_VALUE_AT_ZERO (@var{mode}, @var{value}) @defmac CLZ_DEFINED_VALUE_AT_ZERO (@var{mode}, @var{value})
@defmacx CTZ_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 A C expression that indicates whether the architecture defines a value
for @code{clz} or @code{ctz} with a zero operand. If so, @var{value} for @code{clz} or @code{ctz} with a zero operand.
should be set to this value. If this macro is not defined, the value of A result of @code{0} indicates the value is undefined.
@code{clz} or @code{ctz} is assumed to be 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} This macro must be defined if the target's expansion for @code{ffs}
relies on a particular value to get correct results. Otherwise it 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} Note that regardless of this macro the ``definedness'' of @code{clz}
and @code{ctz} at zero do @emph{not} extend to the builtin functions and @code{ctz} at zero do @emph{not} extend to the builtin functions

View File

@ -122,6 +122,8 @@ static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
enum machine_mode *, int *); enum machine_mode *, int *);
static rtx widen_clz (enum machine_mode, rtx, rtx); static rtx widen_clz (enum machine_mode, rtx, rtx);
static rtx expand_parity (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 enum rtx_code get_rtx_code (enum tree_code, bool);
static rtx vector_compare_rtx (tree, bool, enum insn_code); 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; 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 /* Extract the OMODE lowpart from VAL, which has IMODE. Under certain
conditions, VAL may already be a SUBREG against which we cannot generate 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 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; 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: try_libcall:
/* Now try a library call in this mode. */ /* Now try a library call in this mode. */
if (optab_handler (unoptab, mode)->libfunc) if (optab_handler (unoptab, mode)->libfunc)