[optabs][ifcvt][1/3] Define negcc, notcc optabs
* ifcvt.c (noce_try_inverse_constants): New function. (noce_process_if_block): Call it. * optabs.h (emit_conditional_neg_or_complement): Declare prototype. * optabs.def (negcc_optab, notcc_optab): Declare. * optabs.c (emit_conditional_neg_or_complement): New function. * doc/tm.texi (Standard Names): Document negcc, notcc names. From-SVN: r230089
This commit is contained in:
parent
df554b0e49
commit
ce68b5cfb9
@ -1,3 +1,12 @@
|
||||
2015-11-10 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
|
||||
|
||||
* ifcvt.c (noce_try_inverse_constants): New function.
|
||||
(noce_process_if_block): Call it.
|
||||
* optabs.h (emit_conditional_neg_or_complement): Declare prototype.
|
||||
* optabs.def (negcc_optab, notcc_optab): Declare.
|
||||
* optabs.c (emit_conditional_neg_or_complement): New function.
|
||||
* doc/tm.texi (Standard Names): Document negcc, notcc names.
|
||||
|
||||
2015-11-10 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
|
||||
|
||||
PR rtl-optimization/68236
|
||||
|
@ -5805,6 +5805,21 @@ move operand 2 or (operands 2 + operand 3) into operand 0 according to the
|
||||
comparison in operand 1. If the comparison is false, operand 2 is moved into
|
||||
operand 0, otherwise (operand 2 + operand 3) is moved.
|
||||
|
||||
@cindex @code{neg@var{mode}cc} instruction pattern
|
||||
@item @samp{neg@var{mode}cc}
|
||||
Similar to @samp{mov@var{mode}cc} but for conditional negation. Conditionally
|
||||
move the negation of operand 2 or the unchanged operand 3 into operand 0
|
||||
according to the comparison in operand 1. If the comparison is true, the negation
|
||||
of operand 2 is moved into operand 0, otherwise operand 3 is moved.
|
||||
|
||||
@cindex @code{not@var{mode}cc} instruction pattern
|
||||
@item @samp{not@var{mode}cc}
|
||||
Similar to @samp{neg@var{mode}cc} but for conditional complement.
|
||||
Conditionally move the bitwise complement of operand 2 or the unchanged
|
||||
operand 3 into operand 0 according to the comparison in operand 1.
|
||||
If the comparison is true, the complement of operand 2 is moved into
|
||||
operand 0, otherwise operand 3 is moved.
|
||||
|
||||
@cindex @code{cstore@var{mode}4} instruction pattern
|
||||
@item @samp{cstore@var{mode}4}
|
||||
Store zero or nonzero in operand 0 according to whether a comparison
|
||||
|
79
gcc/ifcvt.c
79
gcc/ifcvt.c
@ -1168,6 +1168,83 @@ noce_try_store_flag (struct noce_if_info *if_info)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert "if (test) x = -A; else x = A" into
|
||||
x = A; if (test) x = -x if the machine can do the
|
||||
conditional negate form of this cheaply.
|
||||
Try this before noce_try_cmove that will just load the
|
||||
immediates into two registers and do a conditional select
|
||||
between them. If the target has a conditional negate or
|
||||
conditional invert operation we can save a potentially
|
||||
expensive constant synthesis. */
|
||||
|
||||
static bool
|
||||
noce_try_inverse_constants (struct noce_if_info *if_info)
|
||||
{
|
||||
if (!noce_simple_bbs (if_info))
|
||||
return false;
|
||||
|
||||
if (!CONST_INT_P (if_info->a)
|
||||
|| !CONST_INT_P (if_info->b)
|
||||
|| !REG_P (if_info->x))
|
||||
return false;
|
||||
|
||||
machine_mode mode = GET_MODE (if_info->x);
|
||||
|
||||
HOST_WIDE_INT val_a = INTVAL (if_info->a);
|
||||
HOST_WIDE_INT val_b = INTVAL (if_info->b);
|
||||
|
||||
rtx cond = if_info->cond;
|
||||
|
||||
rtx x = if_info->x;
|
||||
rtx target;
|
||||
|
||||
start_sequence ();
|
||||
|
||||
rtx_code code;
|
||||
if (val_b != HOST_WIDE_INT_MIN && val_a == -val_b)
|
||||
code = NEG;
|
||||
else if (val_a == ~val_b)
|
||||
code = NOT;
|
||||
else
|
||||
{
|
||||
end_sequence ();
|
||||
return false;
|
||||
}
|
||||
|
||||
rtx tmp = gen_reg_rtx (mode);
|
||||
noce_emit_move_insn (tmp, if_info->a);
|
||||
|
||||
target = emit_conditional_neg_or_complement (x, code, mode, cond, tmp, tmp);
|
||||
|
||||
if (target)
|
||||
{
|
||||
rtx_insn *seq = get_insns ();
|
||||
|
||||
if (!seq)
|
||||
{
|
||||
end_sequence ();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target != if_info->x)
|
||||
noce_emit_move_insn (if_info->x, target);
|
||||
|
||||
seq = end_ifcvt_sequence (if_info);
|
||||
|
||||
if (!seq)
|
||||
return false;
|
||||
|
||||
emit_insn_before_setloc (seq, if_info->jump,
|
||||
INSN_LOCATION (if_info->insn_a));
|
||||
return true;
|
||||
}
|
||||
|
||||
end_sequence ();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Convert "if (test) x = a; else x = b", for A and B constant.
|
||||
Also allow A = y + c1, B = y + c2, with a common y between A
|
||||
and B. */
|
||||
@ -3497,6 +3574,8 @@ noce_process_if_block (struct noce_if_info *if_info)
|
||||
goto success;
|
||||
if (noce_try_abs (if_info))
|
||||
goto success;
|
||||
if (noce_try_inverse_constants (if_info))
|
||||
goto success;
|
||||
if (!targetm.have_conditional_execution ()
|
||||
&& noce_try_store_flag_constants (if_info))
|
||||
goto success;
|
||||
|
50
gcc/optabs.c
50
gcc/optabs.c
@ -4210,6 +4210,56 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
|
||||
/* Emit a conditional negate or bitwise complement using the
|
||||
negcc or notcc optabs if available. Return NULL_RTX if such operations
|
||||
are not available. Otherwise return the RTX holding the result.
|
||||
TARGET is the desired destination of the result. COMP is the comparison
|
||||
on which to negate. If COND is true move into TARGET the negation
|
||||
or bitwise complement of OP1. Otherwise move OP2 into TARGET.
|
||||
CODE is either NEG or NOT. MODE is the machine mode in which the
|
||||
operation is performed. */
|
||||
|
||||
rtx
|
||||
emit_conditional_neg_or_complement (rtx target, rtx_code code,
|
||||
machine_mode mode, rtx cond, rtx op1,
|
||||
rtx op2)
|
||||
{
|
||||
optab op = unknown_optab;
|
||||
if (code == NEG)
|
||||
op = negcc_optab;
|
||||
else if (code == NOT)
|
||||
op = notcc_optab;
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
insn_code icode = direct_optab_handler (op, mode);
|
||||
|
||||
if (icode == CODE_FOR_nothing)
|
||||
return NULL_RTX;
|
||||
|
||||
if (!target)
|
||||
target = gen_reg_rtx (mode);
|
||||
|
||||
rtx_insn *last = get_last_insn ();
|
||||
struct expand_operand ops[4];
|
||||
|
||||
create_output_operand (&ops[0], target, mode);
|
||||
create_fixed_operand (&ops[1], cond);
|
||||
create_input_operand (&ops[2], op1, mode);
|
||||
create_input_operand (&ops[3], op2, mode);
|
||||
|
||||
if (maybe_expand_insn (icode, 4, ops))
|
||||
{
|
||||
if (ops[0].value != target)
|
||||
convert_move (target, ops[0].value, false);
|
||||
|
||||
return target;
|
||||
}
|
||||
delete_insns_since (last);
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Emit a conditional addition instruction if the machine supports one for that
|
||||
condition and machine mode.
|
||||
|
||||
|
@ -183,6 +183,8 @@ OPTAB_D (reload_out_optab, "reload_out$a")
|
||||
|
||||
OPTAB_DC(cbranch_optab, "cbranch$a4", COMPARE)
|
||||
OPTAB_D (addcc_optab, "add$acc")
|
||||
OPTAB_D (negcc_optab, "neg$acc")
|
||||
OPTAB_D (notcc_optab, "not$acc")
|
||||
OPTAB_D (movcc_optab, "mov$acc")
|
||||
OPTAB_D (cmov_optab, "cmov$a6")
|
||||
OPTAB_D (cstore_optab, "cstore$a4")
|
||||
|
@ -259,6 +259,10 @@ extern void emit_indirect_jump (rtx);
|
||||
rtx emit_conditional_move (rtx, enum rtx_code, rtx, rtx, machine_mode,
|
||||
rtx, rtx, machine_mode, int);
|
||||
|
||||
/* Emit a conditional negate or bitwise complement operation. */
|
||||
rtx emit_conditional_neg_or_complement (rtx, rtx_code, machine_mode, rtx,
|
||||
rtx, rtx);
|
||||
|
||||
rtx emit_conditional_add (rtx, enum rtx_code, rtx, rtx, machine_mode,
|
||||
rtx, rtx, machine_mode, int);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user