internal-fn.c: Include stringpool.h and tree-ssanames.h.
* internal-fn.c: Include stringpool.h and tree-ssanames.h. (ubsan_expand_si_overflow_addsub_check): In the generic expansion, try to improve generated code if one of the arguments is constant or get_range_info says that one of the argument is always negative or always non-negative. * tree-vrp.c (simplify_internal_call_using_ranges): New function. (simplify_stmt_using_ranges): Call it. From-SVN: r206025
This commit is contained in:
parent
91c5ee5b4a
commit
9728643162
|
@ -1,3 +1,13 @@
|
||||||
|
2013-12-16 Jakub Jelinek <jakub@redhat.com>
|
||||||
|
|
||||||
|
* internal-fn.c: Include stringpool.h and tree-ssanames.h.
|
||||||
|
(ubsan_expand_si_overflow_addsub_check): In the generic expansion,
|
||||||
|
try to improve generated code if one of the arguments is constant
|
||||||
|
or get_range_info says that one of the argument is always
|
||||||
|
negative or always non-negative.
|
||||||
|
* tree-vrp.c (simplify_internal_call_using_ranges): New function.
|
||||||
|
(simplify_stmt_using_ranges): Call it.
|
||||||
|
|
||||||
2013-12-16 Vladimir Makarov <vmakarov@redhat.com>
|
2013-12-16 Vladimir Makarov <vmakarov@redhat.com>
|
||||||
|
|
||||||
PR rtl-optimization/59466
|
PR rtl-optimization/59466
|
||||||
|
|
|
@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "ubsan.h"
|
#include "ubsan.h"
|
||||||
#include "target.h"
|
#include "target.h"
|
||||||
#include "predict.h"
|
#include "predict.h"
|
||||||
|
#include "stringpool.h"
|
||||||
|
#include "tree-ssanames.h"
|
||||||
|
|
||||||
/* The names of each internal function, indexed by function number. */
|
/* The names of each internal function, indexed by function number. */
|
||||||
const char *const internal_fn_name_array[] = {
|
const char *const internal_fn_name_array[] = {
|
||||||
|
@ -211,25 +213,78 @@ ubsan_expand_si_overflow_addsub_check (tree_code code, gimple stmt)
|
||||||
if (icode == CODE_FOR_nothing)
|
if (icode == CODE_FOR_nothing)
|
||||||
{
|
{
|
||||||
rtx sub_check = gen_label_rtx ();
|
rtx sub_check = gen_label_rtx ();
|
||||||
|
int pos_neg = 3;
|
||||||
|
|
||||||
/* Compute the operation. On RTL level, the addition is always
|
/* Compute the operation. On RTL level, the addition is always
|
||||||
unsigned. */
|
unsigned. */
|
||||||
res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
|
res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab,
|
||||||
op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
|
op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN);
|
||||||
|
|
||||||
|
/* If we can prove one of the arguments is always non-negative
|
||||||
|
or always negative, we can do just one comparison and
|
||||||
|
conditional jump instead of 2 at runtime, 3 present in the
|
||||||
|
emitted code. If one of the arguments is CONST_INT, all we
|
||||||
|
need is to make sure it is op1, then the first
|
||||||
|
emit_cmp_and_jump_insns will be just folded. Otherwise try
|
||||||
|
to use range info if available. */
|
||||||
|
if (CONST_INT_P (op0))
|
||||||
|
{
|
||||||
|
rtx tem = op0;
|
||||||
|
op0 = op1;
|
||||||
|
op1 = tem;
|
||||||
|
}
|
||||||
|
else if (CONST_INT_P (op1))
|
||||||
|
;
|
||||||
|
else if (TREE_CODE (arg0) == SSA_NAME)
|
||||||
|
{
|
||||||
|
double_int arg0_min, arg0_max;
|
||||||
|
if (get_range_info (arg0, &arg0_min, &arg0_max) == VR_RANGE)
|
||||||
|
{
|
||||||
|
if (!arg0_min.is_negative ())
|
||||||
|
pos_neg = 1;
|
||||||
|
else if (arg0_max.is_negative ())
|
||||||
|
pos_neg = 2;
|
||||||
|
}
|
||||||
|
if (pos_neg != 3)
|
||||||
|
{
|
||||||
|
rtx tem = op0;
|
||||||
|
op0 = op1;
|
||||||
|
op1 = tem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos_neg == 3 && !CONST_INT_P (op1) && TREE_CODE (arg1) == SSA_NAME)
|
||||||
|
{
|
||||||
|
double_int arg1_min, arg1_max;
|
||||||
|
if (get_range_info (arg1, &arg1_min, &arg1_max) == VR_RANGE)
|
||||||
|
{
|
||||||
|
if (!arg1_min.is_negative ())
|
||||||
|
pos_neg = 1;
|
||||||
|
else if (arg1_max.is_negative ())
|
||||||
|
pos_neg = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If the op1 is negative, we have to use a different check. */
|
/* If the op1 is negative, we have to use a different check. */
|
||||||
|
if (pos_neg == 3)
|
||||||
emit_cmp_and_jump_insns (op1, const0_rtx, LT, NULL_RTX, mode,
|
emit_cmp_and_jump_insns (op1, const0_rtx, LT, NULL_RTX, mode,
|
||||||
false, sub_check, PROB_EVEN);
|
false, sub_check, PROB_EVEN);
|
||||||
|
|
||||||
/* Compare the result of the operation with one of the operands. */
|
/* Compare the result of the operation with one of the operands. */
|
||||||
|
if (pos_neg & 1)
|
||||||
emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? GE : LE,
|
emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? GE : LE,
|
||||||
NULL_RTX, mode, false, done_label,
|
NULL_RTX, mode, false, done_label,
|
||||||
PROB_VERY_LIKELY);
|
PROB_VERY_LIKELY);
|
||||||
|
|
||||||
/* If we get here, we have to print the error. */
|
/* If we get here, we have to print the error. */
|
||||||
|
if (pos_neg == 3)
|
||||||
|
{
|
||||||
emit_jump (do_error);
|
emit_jump (do_error);
|
||||||
|
|
||||||
emit_label (sub_check);
|
emit_label (sub_check);
|
||||||
|
}
|
||||||
|
|
||||||
/* We have k = a + b for b < 0 here. k <= a must hold. */
|
/* We have k = a + b for b < 0 here. k <= a must hold. */
|
||||||
|
if (pos_neg & 2)
|
||||||
emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? LE : GE,
|
emit_cmp_and_jump_insns (res, op0, code == PLUS_EXPR ? LE : GE,
|
||||||
NULL_RTX, mode, false, done_label,
|
NULL_RTX, mode, false, done_label,
|
||||||
PROB_VERY_LIKELY);
|
PROB_VERY_LIKELY);
|
||||||
|
|
|
@ -9299,6 +9299,68 @@ simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Simplify an internal fn call using ranges if possible. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
|
||||||
|
{
|
||||||
|
enum tree_code subcode;
|
||||||
|
switch (gimple_call_internal_fn (stmt))
|
||||||
|
{
|
||||||
|
case IFN_UBSAN_CHECK_ADD:
|
||||||
|
subcode = PLUS_EXPR;
|
||||||
|
break;
|
||||||
|
case IFN_UBSAN_CHECK_SUB:
|
||||||
|
subcode = MINUS_EXPR;
|
||||||
|
break;
|
||||||
|
case IFN_UBSAN_CHECK_MUL:
|
||||||
|
subcode = MULT_EXPR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_range_t vr0 = VR_INITIALIZER;
|
||||||
|
value_range_t vr1 = VR_INITIALIZER;
|
||||||
|
tree op0 = gimple_call_arg (stmt, 0);
|
||||||
|
tree op1 = gimple_call_arg (stmt, 1);
|
||||||
|
|
||||||
|
if (TREE_CODE (op0) == SSA_NAME)
|
||||||
|
vr0 = *get_value_range (op0);
|
||||||
|
else if (TREE_CODE (op0) == INTEGER_CST)
|
||||||
|
set_value_range_to_value (&vr0, op0, NULL);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TREE_CODE (op1) == SSA_NAME)
|
||||||
|
vr1 = *get_value_range (op1);
|
||||||
|
else if (TREE_CODE (op1) == INTEGER_CST)
|
||||||
|
set_value_range_to_value (&vr1, op1, NULL);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!range_int_cst_p (&vr0) || !range_int_cst_p (&vr1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
tree r1 = int_const_binop (subcode, vr0.min, vr1.min);
|
||||||
|
tree r2 = int_const_binop (subcode, vr0.max, vr1.max);
|
||||||
|
if (r1 == NULL_TREE || TREE_OVERFLOW (r1)
|
||||||
|
|| r2 == NULL_TREE || TREE_OVERFLOW (r2))
|
||||||
|
return false;
|
||||||
|
if (subcode == MULT_EXPR)
|
||||||
|
{
|
||||||
|
tree r3 = int_const_binop (subcode, vr0.min, vr1.max);
|
||||||
|
tree r4 = int_const_binop (subcode, vr0.max, vr1.min);
|
||||||
|
if (r3 == NULL_TREE || TREE_OVERFLOW (r3)
|
||||||
|
|| r4 == NULL_TREE || TREE_OVERFLOW (r4))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
gimple g = gimple_build_assign_with_ops (subcode, gimple_call_lhs (stmt),
|
||||||
|
op0, op1);
|
||||||
|
gsi_replace (gsi, g, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Simplify STMT using ranges if possible. */
|
/* Simplify STMT using ranges if possible. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -9367,6 +9429,9 @@ simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
|
||||||
return simplify_cond_using_ranges (stmt);
|
return simplify_cond_using_ranges (stmt);
|
||||||
else if (gimple_code (stmt) == GIMPLE_SWITCH)
|
else if (gimple_code (stmt) == GIMPLE_SWITCH)
|
||||||
return simplify_switch_using_ranges (stmt);
|
return simplify_switch_using_ranges (stmt);
|
||||||
|
else if (is_gimple_call (stmt)
|
||||||
|
&& gimple_call_internal_p (stmt))
|
||||||
|
return simplify_internal_call_using_ranges (gsi, stmt);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue