diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-09-28 21:26:31 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-09-28 21:26:31 +0000 |
commit | 94e08e50cec67a1026ae11c82b3a441871da3817 (patch) | |
tree | 2b4602f59f93e1c9ebfa00346b0b70ecdd95b378 /gcc/optabs.c | |
parent | a2a58dc4ab39e0b69ec3834a3b8bdc9e018981f7 (diff) | |
download | gcc-94e08e50cec67a1026ae11c82b3a441871da3817.tar.gz |
./:
* ifcvt.c (noce_try_abs): Recognize pattern and call
expand_one_cmpl_abs_nojump.
* optabs.c (expand_one_cmpl_abs_nojump): New function.
* optabs.h (expand_one_cmpl_abs_nojump): Declare.
testsuite/:
* gcc.target/i386/ifcvt-onecmpl-abs-1.c: New file.
* gcc.c-torture/execute/ifcvt-onecmpl-abs-1.c: New file.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152253 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/gcc/optabs.c b/gcc/optabs.c index a1adc581dc1..1c136236060 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -3488,6 +3488,60 @@ expand_abs (enum machine_mode mode, rtx op0, rtx target, return target; } +/* Emit code to compute the one's complement absolute value of OP0 + (if (OP0 < 0) OP0 = ~OP0), with result to TARGET if convenient. + (TARGET may be NULL_RTX.) The return value says where the result + actually is to be found. + + MODE is the mode of the operand; the mode of the result is + different but can be deduced from MODE. */ + +rtx +expand_one_cmpl_abs_nojump (enum machine_mode mode, rtx op0, rtx target) +{ + rtx temp; + + /* Not applicable for floating point modes. */ + if (FLOAT_MODE_P (mode)) + return NULL_RTX; + + /* If we have a MAX insn, we can do this as MAX (x, ~x). */ + if (optab_handler (smax_optab, mode)->insn_code != CODE_FOR_nothing) + { + rtx last = get_last_insn (); + + temp = expand_unop (mode, one_cmpl_optab, op0, NULL_RTX, 0); + if (temp != 0) + temp = expand_binop (mode, smax_optab, op0, temp, target, 0, + OPTAB_WIDEN); + + if (temp != 0) + return temp; + + delete_insns_since (last); + } + + /* If this machine has expensive jumps, we can do one's complement + absolute value of X as (((signed) x >> (W-1)) ^ x). */ + + if (GET_MODE_CLASS (mode) == MODE_INT + && BRANCH_COST (optimize_insn_for_speed_p (), + false) >= 2) + { + rtx extended = expand_shift (RSHIFT_EXPR, mode, op0, + size_int (GET_MODE_BITSIZE (mode) - 1), + NULL_RTX, 0); + + temp = expand_binop (mode, xor_optab, extended, op0, target, 0, + OPTAB_LIB_WIDEN); + + if (temp != 0) + return temp; + } + + return NULL_RTX; +} + /* A subroutine of expand_copysign, perform the copysign operation using the abs and neg primitives advertised to exist on the target. The assumption is that we have a split register file, and leaving op0 in fp registers, |