This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [patch] Lno branch merge part 8 -- canonical induction variable creation
Hello,
> > There is the third alternative -- to abandon the whole system, for that
> > you yourself admit that it probably does not work on many places,
> > and we are not likely to ever be able to get it working.
> >
> > My proposal is: Add for each operation flag(s) telling whether it is
> > 1) Wrapping -- i.e. the compiler cannot assume anything about it.
> > 2) Wrap undefined -- i.e. compiler can assume it does not wrap if it
> > wants to.
> > 3) Trapping -- i.e. the compiler not only assumes it does not wrap,
> > but also adds check for it.
> >
> > This allows for greater flexibility, as frontends/optimization that
> > from some reason know that a particular operation does not wrap can
> > indicate it, regardless of what it the type of operands.
>
> I've absolutely nothing against such an overhaul of GCC's tree and RTL
> codes. The only reason that I suggested flag_wrapv was that I assumed
> that timing was an issue. Such a change may not be suitable even for
> stage2, and we're a very short time away from stage3.
>
>
> Again your points "1)" and "2)" above show the confusion. We really,
> need a way to say
>
> 1) doesn't overflow.
> 2) undefined on overflow.
> 3) overflow wraps around using 2's complement arithmetic.
> 4) trap on overflow.
>
> Of course, if LNO knows that an expression is type "1)" if doesn't
> matter whether the tree code is actually 2), 3) or 4).
here is the patch that implements the proposal. Some remarks:
-- It should be safer than the current system in case of -fno-wrapv,
since all expressions are by default produced with modulo semantics
(i.e. it should not happen that an optimizer would produce an operation
with undefined behavior by mistake).
-- There may be some minor differences in behavior with -ftrapv. Fold
is updated to preserve trap flags, but the new operations produced by
other optimizers are still produced with modulo semantics. This
should not occur too often -- optimizers usually do not produce new
expressions from scratch; and those that do should probably anyway be
reviewed to see whether their handling of trapping overflows is
correct.
-- Of course with -fwrapv the behavior should be completely unchanged.
OB_UNDEFINED and OB_NO_OVERFLOW (which correspond to 2) and 1) in your
list, resp. to 2) in mine) are IMHO equivalent for any practical purpose.
I have included them both since I am not entirely sure that I do not
miss something, since you probably had some reason for listing both.
The overflow behavior flags are set only for the C frontend, the reason
being that I have no idea how the overflow behavior is defined in other
languages.
Bootstrapped & regtested on i686.
Zdenek
* builtins.c (expand_powi_1, builtin_memset_gen_str,
expand_builtin_fabs, expand_builtin_cabs):
Pass overflow behavior flag to expander calls.
* explow.c (round_push, allocate_dynamic_stack_space): Ditto.
* expr.c (force_operand, expand_expr_real_1): Ditto.
* ifcvt.c (noce_try_abs): Ditto.
* c-typeck.c (set_c_overflow_behavior): New function.
(build_unary_op, build_binary_op): Set overflow behavior flags.
* expmed.c (expand_mult, expand_divmod): Add trap_on_overflow
argument and produce operations according to it.
* expr.h (expand_divmod, expand_mult): Declaration added.
* fold-const.c (curr_op_traps_on_overflow, curr_op_does_not_overflow,
ignore_overflow_traps): New static variables.
(fold): Made a wrapper around fold_2, set the overflow behavior
variables.
(fold_2): Split from fold. Handle overflow behavior flags.
(negate_expr_p, negate_expr): Added overflow behavior argument.
(extract_muldiv_1): Handle overflow behavior flags.
(fold_initializer): Set/restore ignore_overflow_traps.
(tree_expr_nonzero_p): Handle overflow behavior flags.
* gimplify.c (gimplify_self_mod_expr): Copy overflow behavior flags.
* loop.c (basic_induction_var): Add a comment.
(product_cheap_p): Pass overflow behavior flag to expander calls.
* optabs.c (expand_cmplxdiv_straight, expand_cmplxdiv_wide,
expand_binop, expand_vector_binop): Pass overflow behavior flag
to expander calls.
(optab_for_tree_code): Added overflow behavior argument, choose
an optab according to it.
(expand_abs_nojump, expand_abs, expand_complex_abs): Added overflow
behavior argument.
* optabs.h (expand_abs_nojump, expand_abs, expand_complex_abs,
optab_for_tree_code): Declaration changed.
* simplify-rtx.c (simplify_const_relational_operation): Add a comment.
* tree-complex.c (expand_vector_operations_1): Take overflow behavior
into account.
* tree-dump.c (dump_options): Add TDF_WRAPS option.
* tree-eh.c (tree_could_trap_p): Take overflow behavior flags into
account.
* tree-pretty-print.c (dump_overflow_behavior): New function.
(dump_generic_node): Use it.
* tree-vectorizer.c (vectorizable_operation): Use overflow behavior
flags.
* tree.c (default_overflow_behavior): New variable.
(build1_stat, build2_stat): Set default overflow behavior.
(affected_by_overflow_behavior_p, traps_on_overflow_p,
does_not_overflow_p, copy_overflow_behavior): New functions.
* tree.h (TYPE_TRAP_SIGNED): Removed.
(enum overflow_behavior): New.
(default_overflow_behavior): Declare.
(GET_TREE_OVERFLOW_BEHAVIOR, SET_TREE_OVERFLOW_BEHAVIOR): New macros.
(affected_by_overflow_behavior_p, traps_on_overflow_p,
does_not_overflow_p, copy_overflow_behavior): Declare.
(TDF_WRAPS): New constant.
Index: builtins.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/builtins.c,v
retrieving revision 1.373
diff -c -3 -p -r1.373 builtins.c
*** builtins.c 25 Aug 2004 09:51:17 -0000 1.373
--- builtins.c 27 Aug 2004 11:47:45 -0000
*************** expand_powi_1 (enum machine_mode mode, u
*** 2250,2256 ****
op1 = op0;
}
! result = expand_mult (mode, op0, op1, target, 0);
if (result != target)
emit_move_insn (target, result);
return target;
--- 2250,2256 ----
op1 = op0;
}
! result = expand_mult (mode, op0, op1, target, 0, 0);
if (result != target)
emit_move_insn (target, result);
return target;
*************** builtin_memset_gen_str (void *data, HOST
*** 3278,3284 ****
coeff = c_readstr (p, mode);
target = convert_to_mode (mode, (rtx) data, 1);
! target = expand_mult (mode, target, coeff, NULL_RTX, 1);
return force_reg (mode, target);
}
--- 3278,3284 ----
coeff = c_readstr (p, mode);
target = convert_to_mode (mode, (rtx) data, 1);
! target = expand_mult (mode, target, coeff, NULL_RTX, 1, 0);
return force_reg (mode, target);
}
*************** expand_builtin_fabs (tree arglist, rtx t
*** 4901,4907 ****
arg = TREE_VALUE (arglist);
mode = TYPE_MODE (TREE_TYPE (arg));
op0 = expand_expr (arg, subtarget, VOIDmode, 0);
! return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
}
/* Expand a call to cabs, cabsf or cabsl with arguments ARGLIST.
--- 4901,4908 ----
arg = TREE_VALUE (arglist);
mode = TYPE_MODE (TREE_TYPE (arg));
op0 = expand_expr (arg, subtarget, VOIDmode, 0);
! return expand_abs (mode, op0, target, 0, 0,
! safe_from_p (target, arg, 1));
}
/* Expand a call to cabs, cabsf or cabsl with arguments ARGLIST.
*************** expand_builtin_cabs (tree arglist, rtx t
*** 4925,4931 ****
mode = TYPE_MODE (TREE_TYPE (arg));
op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
! return expand_complex_abs (mode, op0, target, 0);
}
/* Create a new constant string literal and return a char* pointer to it.
--- 4926,4932 ----
mode = TYPE_MODE (TREE_TYPE (arg));
op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
! return expand_complex_abs (mode, op0, target, 0, flag_trapv);
}
/* Create a new constant string literal and return a char* pointer to it.
Index: c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.363
diff -c -3 -p -r1.363 c-typeck.c
*** c-typeck.c 27 Aug 2004 00:37:48 -0000 1.363
--- c-typeck.c 27 Aug 2004 11:47:45 -0000
*************** static void set_nonincremental_init_from
*** 83,88 ****
--- 83,113 ----
static tree find_init_member (tree);
static int lvalue_or_else (tree, const char *);
+ /* Set overflow behavior flags of EXPR according to flag_wrapv and
+ flag_trapw. */
+
+ static void
+ set_c_overflow_behavior (tree expr)
+ {
+ tree type = TREE_TYPE (expr);
+ enum overflow_behavior behavior = flag_trapv ? OB_TRAP : OB_UNDEFINED;
+
+ /* With flag_wrapv all arithmetics has the modulo semantics. */
+ if (!flag_trapv && flag_wrapv)
+ return;
+
+ /* The wrap behavior only affects some expressions. */
+ if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+ return;
+
+ /* And only signed integer arithmetics (rest defaults to the modulo
+ semantics). */
+ if (!INTEGRAL_TYPE_P (type) || TYPE_UNSIGNED (type))
+ return;
+
+ SET_TREE_OVERFLOW_BEHAVIOR (expr, behavior);
+ }
+
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
*************** build_unary_op (enum tree_code code, tre
*** 2466,2472 ****
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
else
! val = build2 (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
val = convert (result_type, val);
if (TREE_CODE (val) != code)
--- 2491,2500 ----
if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE)
val = boolean_increment (code, arg);
else
! {
! val = build2 (code, TREE_TYPE (arg), arg, inc);
! set_c_overflow_behavior (val);
! }
TREE_SIDE_EFFECTS (val) = 1;
val = convert (result_type, val);
if (TREE_CODE (val) != code)
*************** build_unary_op (enum tree_code code, tre
*** 2560,2565 ****
--- 2588,2595 ----
if (argtype == 0)
argtype = TREE_TYPE (arg);
val = build1 (code, argtype, arg);
+ set_c_overflow_behavior (val);
+
return require_constant_value ? fold_initializer (val) : fold (val);
}
*************** build_binary_op (enum tree_code code, tr
*** 7573,7578 ****
--- 7603,7609 ----
{
tree result = build2 (resultcode, build_type, op0, op1);
+ set_c_overflow_behavior (result);
/* Treat expressions in initializers specially as they can't trap. */
result = require_constant_value ? fold_initializer (result)
Index: explow.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/explow.c,v
retrieving revision 1.138
diff -c -3 -p -r1.138 explow.c
*** explow.c 18 Aug 2004 08:23:42 -0000 1.138
--- explow.c 27 Aug 2004 11:47:45 -0000
*************** round_push (rtx size)
*** 900,907 ****
size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
! NULL_RTX, 1);
! size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);
}
return size;
--- 900,907 ----
size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
! NULL_RTX, 1, 0);
! size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1, 0);
}
return size;
*************** allocate_dynamic_stack_space (rtx size,
*** 1385,1394 ****
NULL_RTX, 1, OPTAB_LIB_WIDEN);
target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! NULL_RTX, 1);
target = expand_mult (Pmode, target,
GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! NULL_RTX, 1);
}
/* Record the new stack level for nonlocal gotos. */
--- 1385,1394 ----
NULL_RTX, 1, OPTAB_LIB_WIDEN);
target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! NULL_RTX, 1, 0);
target = expand_mult (Pmode, target,
GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT),
! NULL_RTX, 1, 0);
}
/* Record the new stack level for nonlocal gotos. */
Index: expmed.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expmed.c,v
retrieving revision 1.193
diff -c -3 -p -r1.193 expmed.c
*** expmed.c 25 Aug 2004 09:51:22 -0000 1.193
--- expmed.c 27 Aug 2004 11:47:46 -0000
*************** expand_mult_const (enum machine_mode mod
*** 2663,2673 ****
We check specially for a constant integer as OP1.
If you want this check for OP0 as well, then before calling
! you should swap the two operands if OP0 would be constant. */
rtx
expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
! int unsignedp)
{
rtx const_op1 = op1;
enum mult_variant variant;
--- 2663,2676 ----
We check specially for a constant integer as OP1.
If you want this check for OP0 as well, then before calling
! you should swap the two operands if OP0 would be constant.
!
! TRAP_ON_OVERFLOW is true if the operation should trap on
! overflow. */
rtx
expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
! int unsignedp, int trap_on_overflow)
{
rtx const_op1 = op1;
enum mult_variant variant;
*************** expand_mult (enum machine_mode mode, rtx
*** 2698,2704 ****
that it seems better to use synth_mult always. */
if (const_op1 && GET_CODE (const_op1) == CONST_INT
! && (unsignedp || !flag_trapv))
{
int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
--- 2701,2707 ----
that it seems better to use synth_mult always. */
if (const_op1 && GET_CODE (const_op1) == CONST_INT
! && !trap_on_overflow)
{
int mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
*************** expand_mult (enum machine_mode mode, rtx
*** 2732,2741 ****
/* This used to use umul_optab if unsigned, but for non-widening multiply
there is no difference between signed and unsigned. */
! op0 = expand_binop (mode,
! ! unsignedp
! && flag_trapv && (GET_MODE_CLASS(mode) == MODE_INT)
! ? smulv_optab : smul_optab,
op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
if (op0 == 0)
abort ();
--- 2735,2741 ----
/* This used to use umul_optab if unsigned, but for non-widening multiply
there is no difference between signed and unsigned. */
! op0 = expand_binop (mode, trap_on_overflow ? smulv_optab : smul_optab,
op0, op1, target, unsignedp, OPTAB_LIB_WIDEN);
if (op0 == 0)
abort ();
*************** expand_sdiv_pow2 (enum machine_mode mode
*** 3299,3305 ****
rtx
expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
! rtx op0, rtx op1, rtx target, int unsignedp)
{
enum machine_mode compute_mode;
rtx tquotient;
--- 3299,3306 ----
rtx
expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
! rtx op0, rtx op1, rtx target, int unsignedp,
! int trap_on_overflow)
{
enum machine_mode compute_mode;
rtx tquotient;
*************** expand_divmod (int rem_flag, enum tree_c
*** 3359,3371 ****
return rem_flag ? const0_rtx : op0;
/* When dividing by -1, we could get an overflow.
! negv_optab can handle overflows. */
if (! unsignedp && op1 == constm1_rtx)
{
if (rem_flag)
return const0_rtx;
! return expand_unop (mode, flag_trapv && GET_MODE_CLASS(mode) == MODE_INT
! ? negv_optab : neg_optab, op0, target, 0);
}
if (target
--- 3360,3372 ----
return rem_flag ? const0_rtx : op0;
/* When dividing by -1, we could get an overflow.
! negv_optab can handle overflows. */
if (! unsignedp && op1 == constm1_rtx)
{
if (rem_flag)
return const0_rtx;
! return expand_unop (mode, trap_on_overflow ? negv_optab : neg_optab,
! op0, target, 0);
}
if (target
*************** expand_divmod (int rem_flag, enum tree_c
*** 3873,3879 ****
t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
NULL_RTX);
t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
! NULL_RTX, 0);
if (t4)
{
rtx t5;
--- 3874,3880 ----
t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
NULL_RTX);
t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
! NULL_RTX, 0, trap_on_overflow);
if (t4)
{
rtx t5;
*************** expand_divmod (int rem_flag, enum tree_c
*** 4207,4213 ****
NULL_RTX, unsignedp);
quotient = expand_mult (compute_mode, t1,
gen_int_mode (ml, compute_mode),
! NULL_RTX, 1);
insn = get_last_insn ();
set_unique_reg_note (insn,
--- 4208,4214 ----
NULL_RTX, unsignedp);
quotient = expand_mult (compute_mode, t1,
gen_int_mode (ml, compute_mode),
! NULL_RTX, 1, 0);
insn = get_last_insn ();
set_unique_reg_note (insn,
*************** expand_divmod (int rem_flag, enum tree_c
*** 4232,4238 ****
rtx tem;
quotient = expand_binop (compute_mode, udiv_optab, op0, op1,
quotient, 1, OPTAB_LIB_WIDEN);
! tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 1);
remainder = expand_binop (compute_mode, sub_optab, op0, tem,
remainder, 1, OPTAB_LIB_WIDEN);
}
--- 4233,4239 ----
rtx tem;
quotient = expand_binop (compute_mode, udiv_optab, op0, op1,
quotient, 1, OPTAB_LIB_WIDEN);
! tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 1, 0);
remainder = expand_binop (compute_mode, sub_optab, op0, tem,
remainder, 1, OPTAB_LIB_WIDEN);
}
*************** expand_divmod (int rem_flag, enum tree_c
*** 4257,4268 ****
rtx tem;
quotient = expand_binop (compute_mode, sdiv_optab, op0, op1,
quotient, 0, OPTAB_LIB_WIDEN);
! tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 0);
remainder = expand_binop (compute_mode, sub_optab, op0, tem,
remainder, 0, OPTAB_LIB_WIDEN);
}
! abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0);
! abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0);
tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
build_int_cst (NULL_TREE, 1),
NULL_RTX, 1);
--- 4258,4270 ----
rtx tem;
quotient = expand_binop (compute_mode, sdiv_optab, op0, op1,
quotient, 0, OPTAB_LIB_WIDEN);
! tem = expand_mult (compute_mode, quotient, op1, NULL_RTX, 0,
! trap_on_overflow);
remainder = expand_binop (compute_mode, sub_optab, op0, tem,
remainder, 0, OPTAB_LIB_WIDEN);
}
! abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 1, 0, 0);
! abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 1, 0, 0);
tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
build_int_cst (NULL_TREE, 1),
NULL_RTX, 1);
*************** expand_divmod (int rem_flag, enum tree_c
*** 4391,4397 ****
{
/* We divided. Now finish doing X - Y * (X / Y). */
remainder = expand_mult (compute_mode, quotient, op1,
! NULL_RTX, unsignedp);
remainder = expand_binop (compute_mode, sub_optab, op0,
remainder, target, unsignedp,
OPTAB_LIB_WIDEN);
--- 4393,4399 ----
{
/* We divided. Now finish doing X - Y * (X / Y). */
remainder = expand_mult (compute_mode, quotient, op1,
! NULL_RTX, unsignedp, trap_on_overflow);
remainder = expand_binop (compute_mode, sub_optab, op0,
remainder, target, unsignedp,
OPTAB_LIB_WIDEN);
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.711
diff -c -3 -p -r1.711 expr.c
*** expr.c 26 Aug 2004 00:24:33 -0000 1.711
--- expr.c 27 Aug 2004 11:47:46 -0000
*************** force_operand (rtx value, rtx target)
*** 5666,5672 ****
switch (code)
{
case MULT:
! return expand_mult (GET_MODE (value), op1, op2, target, 1);
case DIV:
if (!INTEGRAL_MODE_P (GET_MODE (value)))
return expand_simple_binop (GET_MODE (value), code, op1, op2,
--- 5666,5672 ----
switch (code)
{
case MULT:
! return expand_mult (GET_MODE (value), op1, op2, target, 1, 0);
case DIV:
if (!INTEGRAL_MODE_P (GET_MODE (value)))
return expand_simple_binop (GET_MODE (value), code, op1, op2,
*************** force_operand (rtx value, rtx target)
*** 5675,5693 ****
return expand_divmod (0,
FLOAT_MODE_P (GET_MODE (value))
? RDIV_EXPR : TRUNC_DIV_EXPR,
! GET_MODE (value), op1, op2, target, 0);
break;
case MOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! target, 0);
break;
case UDIV:
return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
! target, 1);
break;
case UMOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! target, 1);
break;
case ASHIFTRT:
return expand_simple_binop (GET_MODE (value), code, op1, op2,
--- 5675,5693 ----
return expand_divmod (0,
FLOAT_MODE_P (GET_MODE (value))
? RDIV_EXPR : TRUNC_DIV_EXPR,
! GET_MODE (value), op1, op2, target, 0, 0);
break;
case MOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! target, 0, 0);
break;
case UDIV:
return expand_divmod (0, TRUNC_DIV_EXPR, GET_MODE (value), op1, op2,
! target, 1, 0);
break;
case UMOD:
return expand_divmod (1, TRUNC_MOD_EXPR, GET_MODE (value), op1, op2,
! target, 1, 0);
break;
case ASHIFTRT:
return expand_simple_binop (GET_MODE (value), code, op1, op2,
*************** expand_expr_real_1 (tree exp, rtx target
*** 6202,6207 ****
--- 6202,6208 ----
int ignore;
tree context;
bool reduce_bit_field = false;
+ enum overflow_behavior ob;
#define REDUCE_BIT_FIELD(expr) (reduce_bit_field && !ignore \
? reduce_to_bit_field_precision ((expr), \
target, \
*************** expand_expr_real_1 (tree exp, rtx target
*** 7277,7283 ****
If this is an EXPAND_SUM call, always return the sum. */
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
! || (mode == ptr_mode && (unsignedp || ! flag_trapv)))
{
if (modifier == EXPAND_STACK_PARM)
target = 0;
--- 7278,7284 ----
If this is an EXPAND_SUM call, always return the sum. */
if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER
! || (mode == ptr_mode && !traps_on_overflow_p (exp)))
{
if (modifier == EXPAND_STACK_PARM)
target = 0;
*************** expand_expr_real_1 (tree exp, rtx target
*** 7511,7517 ****
}
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
! return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp));
case TRUNC_DIV_EXPR:
case FLOOR_DIV_EXPR:
--- 7512,7519 ----
}
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
! return REDUCE_BIT_FIELD (expand_mult (mode, op0, op1, target, unsignedp,
! traps_on_overflow_p (exp)));
case TRUNC_DIV_EXPR:
case FLOOR_DIV_EXPR:
*************** expand_expr_real_1 (tree exp, rtx target
*** 7525,7531 ****
where some terms of the dividend have coeffs divisible by it. */
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
! return expand_divmod (0, code, mode, op0, op1, target, unsignedp);
case RDIV_EXPR:
/* Emit a/b as a*(1/b). Later we may manage CSE the reciprocal saving
--- 7527,7534 ----
where some terms of the dividend have coeffs divisible by it. */
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
! return expand_divmod (0, code, mode, op0, op1, target, unsignedp,
! traps_on_overflow_p (exp));
case RDIV_EXPR:
/* Emit a/b as a*(1/b). Later we may manage CSE the reciprocal saving
*************** expand_expr_real_1 (tree exp, rtx target
*** 7550,7556 ****
target = 0;
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
! return expand_divmod (1, code, mode, op0, op1, target, unsignedp);
case FIX_ROUND_EXPR:
case FIX_FLOOR_EXPR:
--- 7553,7559 ----
target = 0;
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
! return expand_divmod (1, code, mode, op0, op1, target, unsignedp, 0);
case FIX_ROUND_EXPR:
case FIX_FLOOR_EXPR:
*************** expand_expr_real_1 (tree exp, rtx target
*** 7578,7588 ****
return target;
case NEGATE_EXPR:
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_unop (mode,
! optab_for_tree_code (NEGATE_EXPR, type),
op0, target, 0);
if (temp == 0)
abort ();
--- 7581,7592 ----
return target;
case NEGATE_EXPR:
+ ob = GET_TREE_OVERFLOW_BEHAVIOR (exp);
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
if (modifier == EXPAND_STACK_PARM)
target = 0;
temp = expand_unop (mode,
! optab_for_tree_code (NEGATE_EXPR, type, ob),
op0, target, 0);
if (temp == 0)
abort ();
*************** expand_expr_real_1 (tree exp, rtx target
*** 7604,7609 ****
--- 7608,7614 ----
return op0;
return expand_abs (mode, op0, target, unsignedp,
+ traps_on_overflow_p (exp),
safe_from_p (target, TREE_OPERAND (exp, 0), 1));
case MAX_EXPR:
*************** expand_expr_real_1 (tree exp, rtx target
*** 7622,7628 ****
/* First try to do it with a special MIN or MAX instruction.
If that does not win, use a conditional jump to select the proper
value. */
! this_optab = optab_for_tree_code (code, type);
temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
OPTAB_WIDEN);
if (temp != 0)
--- 7627,7633 ----
/* First try to do it with a special MIN or MAX instruction.
If that does not win, use a conditional jump to select the proper
value. */
! this_optab = optab_for_tree_code (code, type, OB_NO_OVERFLOW);
temp = expand_binop (mode, this_optab, op0, op1, target, unsignedp,
OPTAB_WIDEN);
if (temp != 0)
*************** expand_expr_real_1 (tree exp, rtx target
*** 8196,8202 ****
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
binop2:
! this_optab = optab_for_tree_code (code, type);
binop3:
if (modifier == EXPAND_STACK_PARM)
target = 0;
--- 8201,8208 ----
expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
subtarget, &op0, &op1, 0);
binop2:
! ob = GET_TREE_OVERFLOW_BEHAVIOR (exp);
! this_optab = optab_for_tree_code (code, type, ob);
binop3:
if (modifier == EXPAND_STACK_PARM)
target = 0;
Index: expr.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.h,v
retrieving revision 1.170
diff -c -3 -p -r1.170 expr.h
*** expr.h 18 Aug 2004 08:23:46 -0000 1.170
--- expr.h 27 Aug 2004 11:47:46 -0000
*************** extern void fixup_tail_calls (void);
*** 573,579 ****
extern rtx expand_shift (enum tree_code, enum machine_mode, rtx, tree, rtx,
int);
extern rtx expand_divmod (int, enum tree_code, enum machine_mode, rtx, rtx,
! rtx, int);
#endif
extern void locate_and_pad_parm (enum machine_mode, tree, int, int, tree,
--- 573,579 ----
extern rtx expand_shift (enum tree_code, enum machine_mode, rtx, tree, rtx,
int);
extern rtx expand_divmod (int, enum tree_code, enum machine_mode, rtx, rtx,
! rtx, int, int);
#endif
extern void locate_and_pad_parm (enum machine_mode, tree, int, int, tree,
*************** extern rtx store_bit_field (rtx, unsigne
*** 741,747 ****
extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int, rtx,
enum machine_mode, enum machine_mode);
! extern rtx expand_mult (enum machine_mode, rtx, rtx, rtx, int);
extern bool const_mult_add_overflow_p (rtx, rtx, rtx, enum machine_mode, int);
extern rtx expand_mult_add (rtx, rtx, rtx, rtx,enum machine_mode, int);
extern rtx expand_mult_highpart_adjust (enum machine_mode, rtx, rtx, rtx, rtx, int);
--- 741,747 ----
extern rtx extract_bit_field (rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int, rtx,
enum machine_mode, enum machine_mode);
! extern rtx expand_mult (enum machine_mode, rtx, rtx, rtx, int, int);
extern bool const_mult_add_overflow_p (rtx, rtx, rtx, enum machine_mode, int);
extern rtx expand_mult_add (rtx, rtx, rtx, rtx,enum machine_mode, int);
extern rtx expand_mult_highpart_adjust (enum machine_mode, rtx, rtx, rtx, rtx, int);
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.444
diff -c -3 -p -r1.444 fold-const.c
*** fold-const.c 25 Aug 2004 09:51:25 -0000 1.444
--- fold-const.c 27 Aug 2004 11:47:46 -0000
*************** enum comparison_code {
*** 81,86 ****
--- 81,99 ----
COMPCODE_TRUE = 15
};
+ /* True if the currently processed operation traps on overflow. */
+
+ static bool curr_op_traps_on_overflow;
+
+ /* True if the currently processed operation may be assumed not to
+ overflow. */
+
+ static bool curr_op_does_not_overflow;
+
+ /* True if the traps due to overflow are to be ignored. */
+
+ static bool ignore_overflow_traps;
+
static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
static bool negate_mathfn_p (enum built_in_function);
*************** static tree fold_relational_const (enum
*** 138,143 ****
--- 151,157 ----
static tree fold_relational_hi_lo (enum tree_code *, const tree,
tree *, tree *);
static bool tree_expr_nonzero_p (tree);
+ static tree fold_2 (tree);
/* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
overflow. Suppose A, B and SUM have the same respective signs as A1, B1,
*************** negate_expr_p (tree t)
*** 914,920 ****
switch (TREE_CODE (t))
{
case INTEGER_CST:
! if (TYPE_UNSIGNED (type) || ! flag_trapv)
return true;
/* Check that -CST will not overflow type. */
--- 928,935 ----
switch (TREE_CODE (t))
{
case INTEGER_CST:
! if (TYPE_UNSIGNED (type)
! || !curr_op_traps_on_overflow)
return true;
/* Check that -CST will not overflow type. */
*************** negate_expr (tree t)
*** 1012,1018 ****
tem = fold_negate_const (t, type);
if (! TREE_OVERFLOW (tem)
|| TYPE_UNSIGNED (type)
! || ! flag_trapv)
return tem;
break;
--- 1027,1033 ----
tem = fold_negate_const (t, type);
if (! TREE_OVERFLOW (tem)
|| TYPE_UNSIGNED (type)
! || ! curr_op_traps_on_overflow)
return tem;
break;
*************** extract_muldiv_1 (tree t, tree c, enum t
*** 5249,5255 ****
fold_convert (ctype, c), 0);
/* We allow the constant to overflow with wrapping semantics. */
if (op1 == 0
! || (TREE_OVERFLOW (op1) && ! flag_wrapv))
break;
}
else
--- 5264,5271 ----
fold_convert (ctype, c), 0);
/* We allow the constant to overflow with wrapping semantics. */
if (op1 == 0
! || (TREE_OVERFLOW (op1)
! && default_overflow_behavior != OB_MODULO))
break;
}
else
*************** extract_muldiv_1 (tree t, tree c, enum t
*** 5325,5331 ****
overflowed. */
if ((! TYPE_UNSIGNED (ctype)
|| (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)))
! && ! flag_wrapv
&& ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
|| (tcode == MULT_EXPR
&& code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
--- 5341,5347 ----
overflowed. */
if ((! TYPE_UNSIGNED (ctype)
|| (TREE_CODE (ctype) == INTEGER_TYPE && TYPE_IS_SIZETYPE (ctype)))
! && does_not_overflow_p (t)
&& ((code == MULT_EXPR && tcode == EXACT_DIV_EXPR)
|| (tcode == MULT_EXPR
&& code != TRUNC_MOD_EXPR && code != CEIL_MOD_EXPR
*************** tree_swap_operands_p (tree arg0, tree ar
*** 6008,6016 ****
--- 6024,6067 ----
static tree fold_1 (tree);
static
#endif
+
+ /* A wrapper to set up flags describing the behavior on overflows
+ and restore them after running the real fold function. */
+
tree
fold (tree expr)
{
+ tree ret;
+ enum overflow_behavior old_overflow_behavior = default_overflow_behavior;
+ bool old_curr_op_traps_on_overflow = curr_op_traps_on_overflow;
+ bool old_curr_op_does_not_overflow = curr_op_does_not_overflow;
+
+ if (traps_on_overflow_p (expr)
+ && !ignore_overflow_traps)
+ {
+ default_overflow_behavior = OB_TRAP;
+ curr_op_traps_on_overflow = true;
+ }
+ else
+ {
+ default_overflow_behavior = OB_MODULO;
+ curr_op_traps_on_overflow = false;
+ }
+
+ curr_op_does_not_overflow = does_not_overflow_p (expr);
+
+ ret = fold_2 (expr);
+
+ default_overflow_behavior = old_overflow_behavior;
+ curr_op_traps_on_overflow = old_curr_op_traps_on_overflow;
+ curr_op_does_not_overflow = old_curr_op_does_not_overflow;
+
+ return ret;
+ }
+
+ static tree
+ fold_2 (tree expr)
+ {
const tree t = expr;
const tree type = TREE_TYPE (expr);
tree t1 = NULL_TREE;
*************** fold (tree expr)
*** 6101,6108 ****
to ARG1 to reduce the number of tests below. */
if (commutative_tree_code (code)
&& tree_swap_operands_p (arg0, arg1, true))
! return fold (build2 (code, type, TREE_OPERAND (t, 1),
! TREE_OPERAND (t, 0)));
/* Now WINS is set as described above,
ARG0 is the first operand of EXPR,
--- 6152,6165 ----
to ARG1 to reduce the number of tests below. */
if (commutative_tree_code (code)
&& tree_swap_operands_p (arg0, arg1, true))
! {
! tem = build2 (code, type, TREE_OPERAND (t, 1),
! TREE_OPERAND (t, 0));
! /* Swapping the operands does not change overflow behavior. */
! copy_overflow_behavior (tem, t);
!
! return fold (tem);
! }
/* Now WINS is set as described above,
ARG0 is the first operand of EXPR,
*************** fold (tree expr)
*** 6915,6921 ****
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
if (TREE_CODE (arg0) == NEGATE_EXPR
&& (FLOAT_TYPE_P (type)
! || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))
&& negate_expr_p (arg1)
&& reorder_operands_p (arg0, arg1))
return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
--- 6972,6980 ----
/* (-A) - B -> (-B) - A where B is easily negated and we can swap. */
if (TREE_CODE (arg0) == NEGATE_EXPR
&& (FLOAT_TYPE_P (type)
! || (INTEGRAL_TYPE_P (type)
! && default_overflow_behavior == OB_MODULO
! && !curr_op_traps_on_overflow))
&& negate_expr_p (arg1)
&& reorder_operands_p (arg0, arg1))
return fold (build2 (MINUS_EXPR, type, negate_expr (arg1),
*************** fold (tree expr)
*** 6990,6996 ****
/* Avoid this transformation if B is a positive REAL_CST. */
&& (TREE_CODE (arg1) != REAL_CST
|| REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
! || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
if (TREE_CODE (arg0) == MULT_EXPR
--- 7049,7057 ----
/* Avoid this transformation if B is a positive REAL_CST. */
&& (TREE_CODE (arg1) != REAL_CST
|| REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1))))
! || (INTEGRAL_TYPE_P (type)
! && default_overflow_behavior == OB_MODULO
! && !curr_op_traps_on_overflow)))
return fold (build2 (PLUS_EXPR, type, arg0, negate_expr (arg1)));
if (TREE_CODE (arg0) == MULT_EXPR
*************** fold (tree expr)
*** 7642,7648 ****
&& !TYPE_UNSIGNED (type)
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_INT_CST_HIGH (arg1) < 0
! && !flag_trapv
/* Avoid this transformation if C is INT_MIN, i.e. C == -C. */
&& !sign_bit_p (arg1, arg1))
return fold (build2 (code, type, fold_convert (type, arg0),
--- 7703,7709 ----
&& !TYPE_UNSIGNED (type)
&& TREE_CODE (arg1) == INTEGER_CST
&& TREE_INT_CST_HIGH (arg1) < 0
! && !curr_op_traps_on_overflow
/* Avoid this transformation if C is INT_MIN, i.e. C == -C. */
&& !sign_bit_p (arg1, arg1))
return fold (build2 (code, type, fold_convert (type, arg0),
*************** fold (tree expr)
*** 7652,7658 ****
if (code == TRUNC_MOD_EXPR
&& !TYPE_UNSIGNED (type)
&& TREE_CODE (arg1) == NEGATE_EXPR
! && !flag_trapv)
return fold (build2 (code, type, fold_convert (type, arg0),
fold_convert (type, TREE_OPERAND (arg1, 0))));
--- 7713,7719 ----
if (code == TRUNC_MOD_EXPR
&& !TYPE_UNSIGNED (type)
&& TREE_CODE (arg1) == NEGATE_EXPR
! && !curr_op_traps_on_overflow)
return fold (build2 (code, type, fold_convert (type, arg0),
fold_convert (type, TREE_OPERAND (arg1, 0))));
*************** fold_initializer (tree expr)
*** 9223,9240 ****
{
int saved_signaling_nans = flag_signaling_nans;
int saved_trapping_math = flag_trapping_math;
! int saved_trapv = flag_trapv;
tree result;
flag_signaling_nans = 0;
flag_trapping_math = 0;
! flag_trapv = 0;
result = fold (expr);
flag_signaling_nans = saved_signaling_nans;
flag_trapping_math = saved_trapping_math;
! flag_trapv = saved_trapv;
return result;
}
--- 9284,9301 ----
{
int saved_signaling_nans = flag_signaling_nans;
int saved_trapping_math = flag_trapping_math;
! int saved_ignore_overflow_traps = ignore_overflow_traps;
tree result;
flag_signaling_nans = 0;
flag_trapping_math = 0;
! ignore_overflow_traps = true;
result = fold (expr);
flag_signaling_nans = saved_signaling_nans;
flag_trapping_math = saved_trapping_math;
! ignore_overflow_traps = saved_ignore_overflow_traps;
return result;
}
*************** tree_expr_nonzero_p (tree t)
*** 9628,9635 ****
switch (TREE_CODE (t))
{
case ABS_EXPR:
! if (!TYPE_UNSIGNED (type) && !flag_wrapv)
return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
case INTEGER_CST:
/* We used to test for !integer_zerop here. This does not work correctly
--- 9689,9697 ----
switch (TREE_CODE (t))
{
case ABS_EXPR:
! if (does_not_overflow_p (t))
return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
+ break;
case INTEGER_CST:
/* We used to test for !integer_zerop here. This does not work correctly
*************** tree_expr_nonzero_p (tree t)
*** 9638,9644 ****
|| TREE_INT_CST_HIGH (t) != 0);
case PLUS_EXPR:
! if (!TYPE_UNSIGNED (type) && !flag_wrapv)
{
/* With the presence of negative values it is hard
to say something. */
--- 9700,9706 ----
|| TREE_INT_CST_HIGH (t) != 0);
case PLUS_EXPR:
! if (does_not_overflow_p (t))
{
/* With the presence of negative values it is hard
to say something. */
*************** tree_expr_nonzero_p (tree t)
*** 9652,9658 ****
break;
case MULT_EXPR:
! if (!TYPE_UNSIGNED (type) && !flag_wrapv)
{
return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
&& tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
--- 9714,9720 ----
break;
case MULT_EXPR:
! if (does_not_overflow_p (t))
{
return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
&& tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.67
diff -c -3 -p -r2.67 gimplify.c
*** gimplify.c 25 Aug 2004 18:11:12 -0000 2.67
--- gimplify.c 27 Aug 2004 11:47:46 -0000
*************** gimplify_self_mod_expr (tree *expr_p, tr
*** 1683,1688 ****
--- 1683,1689 ----
}
t1 = build (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
+ copy_overflow_behavior (t1, *expr_p);
t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
if (postfix)
Index: ifcvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ifcvt.c,v
retrieving revision 1.163
diff -c -3 -p -r1.163 ifcvt.c
*** ifcvt.c 25 Aug 2004 19:52:53 -0000 1.163
--- ifcvt.c 27 Aug 2004 11:47:46 -0000
*************** noce_try_abs (struct noce_if_info *if_in
*** 1696,1702 ****
start_sequence ();
! target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 1);
/* ??? It's a quandary whether cmove would be better here, especially
for integers. Perhaps combine will clean things up. */
--- 1696,1702 ----
start_sequence ();
! target = expand_abs_nojump (GET_MODE (if_info->x), b, if_info->x, 0, 1);
/* ??? It's a quandary whether cmove would be better here, especially
for integers. Perhaps combine will clean things up. */
Index: loop.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/loop.c,v
retrieving revision 1.507
diff -c -3 -p -r1.507 loop.c
*** loop.c 25 Aug 2004 08:20:09 -0000 1.507
--- loop.c 27 Aug 2004 11:47:46 -0000
*************** basic_induction_var (const struct loop *
*** 6278,6283 ****
--- 6278,6287 ----
return 0;
case SIGN_EXTEND:
+ /* FIXME -- this test is bogus. The fact that sign extension
+ is used here does not necessarily imply that (only) signed
+ arithmetics was used during the IV computation. */
+
/* Ignore this BIV if signed arithmetic overflow is defined. */
if (flag_wrapv)
return 0;
*************** product_cheap_p (rtx a, rtx b)
*** 7839,7845 ****
of insns is generated. */
start_sequence ();
! expand_mult (GET_MODE (a), a, b, NULL_RTX, 1);
tmp = get_insns ();
end_sequence ();
--- 7843,7849 ----
of insns is generated. */
start_sequence ();
! expand_mult (GET_MODE (a), a, b, NULL_RTX, 1, 0);
tmp = get_insns ();
end_sequence ();
Index: optabs.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.c,v
retrieving revision 1.235
diff -c -3 -p -r1.235 optabs.c
*** optabs.c 19 Aug 2004 22:24:54 -0000 1.235
--- optabs.c 27 Aug 2004 11:47:46 -0000
*************** expand_cmplxdiv_straight (rtx real0, rtx
*** 345,351 ****
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real_t, divisor, realr, unsignedp);
if (res == 0)
return 0;
--- 346,352 ----
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real_t, divisor, realr, unsignedp, 0);
if (res == 0)
return 0;
*************** expand_cmplxdiv_straight (rtx real0, rtx
*** 358,364 ****
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag_t, divisor, imagr, unsignedp);
if (res == 0)
return 0;
--- 359,365 ----
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag_t, divisor, imagr, unsignedp, 0);
if (res == 0)
return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 412,419 ****
}
else
{
! temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1);
! temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1);
}
if (temp1 == 0 || temp2 == 0)
--- 413,420 ----
}
else
{
! temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 0, 1);
! temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 0, 1);
}
if (temp1 == 0 || temp2 == 0)
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 431,437 ****
NULL_RTX, unsignedp, methods);
else
ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag1, real1, NULL_RTX, unsignedp);
if (ratio == 0)
return 0;
--- 432,438 ----
NULL_RTX, unsignedp, methods);
else
ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag1, real1, NULL_RTX, unsignedp, 0);
if (ratio == 0)
return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 502,508 ****
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real_t, divisor, realr, unsignedp);
if (res == 0)
return 0;
--- 503,509 ----
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real_t, divisor, realr, unsignedp, 0);
if (res == 0)
return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 515,521 ****
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag_t, divisor, imagr, unsignedp);
if (res == 0)
return 0;
--- 516,522 ----
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag_t, divisor, imagr, unsignedp, 0);
if (res == 0)
return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 536,542 ****
NULL_RTX, unsignedp, methods);
else
ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real1, imag1, NULL_RTX, unsignedp);
if (ratio == 0)
return 0;
--- 537,543 ----
NULL_RTX, unsignedp, methods);
else
ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real1, imag1, NULL_RTX, unsignedp, 0);
if (ratio == 0)
return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 602,608 ****
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real_t, divisor, realr, unsignedp);
if (res == 0)
return 0;
--- 603,609 ----
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real_t, divisor, realr, unsignedp, 0);
if (res == 0)
return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 615,621 ****
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag_t, divisor, imagr, unsignedp);
if (res == 0)
return 0;
--- 616,622 ----
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag_t, divisor, imagr, unsignedp, 0);
if (res == 0)
return 0;
*************** expand_cmplxdiv_wide (rtx real0, rtx rea
*** 634,640 ****
or division) but probably ought to be relied on more widely
throughout the expander. */
optab
! optab_for_tree_code (enum tree_code code, tree type)
{
bool trapv;
switch (code)
--- 635,642 ----
or division) but probably ought to be relied on more widely
throughout the expander. */
optab
! optab_for_tree_code (enum tree_code code, tree type,
! enum overflow_behavior ob)
{
bool trapv;
switch (code)
*************** optab_for_tree_code (enum tree_code code
*** 687,693 ****
break;
}
! trapv = flag_trapv && INTEGRAL_TYPE_P (type) && !TYPE_UNSIGNED (type);
switch (code)
{
case PLUS_EXPR:
--- 689,695 ----
break;
}
! trapv = ob == OB_TRAP;
switch (code)
{
case PLUS_EXPR:
*************** expand_binop (enum machine_mode mode, op
*** 1776,1782 ****
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real0, real1, realr, unsignedp);
if (res == 0)
break;
--- 1778,1784 ----
realr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! real0, real1, realr, unsignedp, 0);
if (res == 0)
break;
*************** expand_binop (enum machine_mode mode, op
*** 1788,1794 ****
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag0, real1, imagr, unsignedp);
if (res == 0)
break;
--- 1790,1796 ----
imagr, unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! imag0, real1, imagr, unsignedp, 0);
if (res == 0)
break;
*************** expand_vector_binop (enum machine_mode m
*** 2048,2054 ****
unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! a, b, t, unsignedp);
}
else
res = expand_binop (submode, binoptab, a, b, t,
--- 2050,2056 ----
unsignedp, methods);
else
res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
! a, b, t, unsignedp, 0);
}
else
res = expand_binop (submode, binoptab, a, b, t,
*************** expand_unop (enum machine_mode mode, opt
*** 2963,2973 ****
rtx
expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
! int result_unsignedp)
{
rtx temp;
! if (! flag_trapv)
result_unsignedp = 1;
/* First try to do it with a special abs instruction. */
--- 2965,2975 ----
rtx
expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
! int result_unsignedp, int traps_on_overflow)
{
rtx temp;
! if (!traps_on_overflow)
result_unsignedp = 1;
/* First try to do it with a special abs instruction. */
*************** expand_abs_nojump (enum machine_mode mod
*** 3067,3080 ****
rtx
expand_abs (enum machine_mode mode, rtx op0, rtx target,
! int result_unsignedp, int safe)
{
rtx temp, op1;
! if (! flag_trapv)
result_unsignedp = 1;
! temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
if (temp != 0)
return temp;
--- 3069,3084 ----
rtx
expand_abs (enum machine_mode mode, rtx op0, rtx target,
! int result_unsignedp, int trap_on_overflow,
! int safe)
{
rtx temp, op1;
! if (!trap_on_overflow)
result_unsignedp = 1;
! temp = expand_abs_nojump (mode, op0, target, result_unsignedp,
! trap_on_overflow);
if (temp != 0)
return temp;
*************** expand_abs (enum machine_mode mode, rtx
*** 3127,3133 ****
rtx
expand_complex_abs (enum machine_mode mode, rtx op0, rtx target,
! int unsignedp)
{
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode wider_mode;
--- 3131,3137 ----
rtx
expand_complex_abs (enum machine_mode mode, rtx op0, rtx target,
! int unsignedp, int trap_on_overflow)
{
enum mode_class class = GET_MODE_CLASS (mode);
enum machine_mode wider_mode;
*************** expand_complex_abs (enum machine_mode mo
*** 3148,3155 ****
last = get_last_insn ();
! this_abs_optab = ! unsignedp && flag_trapv
! && (GET_MODE_CLASS(mode) == MODE_INT)
? absv_optab : abs_optab;
if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
--- 3152,3159 ----
last = get_last_insn ();
! this_abs_optab = trap_on_overflow
! && GET_MODE_CLASS(mode) == MODE_INT
? absv_optab : abs_optab;
if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
*************** expand_complex_abs (enum machine_mode mo
*** 3206,3212 ****
rtx xop0 = op0;
xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
! temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
if (temp)
{
--- 3210,3217 ----
rtx xop0 = op0;
xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
! temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp,
! trap_on_overflow);
if (temp)
{
*************** expand_complex_abs (enum machine_mode mo
*** 3228,3234 ****
/* Open-code the complex absolute-value operation
if we can open-code sqrt. Otherwise it's not worth while. */
if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
! && ! flag_trapv)
{
rtx real, imag, total;
--- 3233,3239 ----
/* Open-code the complex absolute-value operation
if we can open-code sqrt. Otherwise it's not worth while. */
if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
! && ! trap_on_overflow)
{
rtx real, imag, total;
*************** expand_complex_abs (enum machine_mode mo
*** 3236,3243 ****
imag = gen_imagpart (submode, op0);
/* Square both parts. */
! real = expand_mult (submode, real, real, NULL_RTX, 0);
! imag = expand_mult (submode, imag, imag, NULL_RTX, 0);
/* Sum the parts. */
total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
--- 3241,3248 ----
imag = gen_imagpart (submode, op0);
/* Square both parts. */
! real = expand_mult (submode, real, real, NULL_RTX, 0, 0);
! imag = expand_mult (submode, imag, imag, NULL_RTX, 0, 0);
/* Sum the parts. */
total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
*************** expand_complex_abs (enum machine_mode mo
*** 3286,3292 ****
xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
! temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
if (temp)
{
--- 3291,3298 ----
xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
! temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp,
! trap_on_overflow);
if (temp)
{
Index: optabs.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/optabs.h,v
retrieving revision 1.33
diff -c -3 -p -r1.33 optabs.h
*** optabs.h 11 Aug 2004 02:50:06 -0000 1.33
--- optabs.h 27 Aug 2004 11:47:46 -0000
*************** extern bool expand_twoval_binop_libfunc
*** 426,436 ****
extern rtx expand_unop (enum machine_mode, optab, rtx, rtx, int);
/* Expand the absolute value operation. */
! extern rtx expand_abs_nojump (enum machine_mode, rtx, rtx, int);
! extern rtx expand_abs (enum machine_mode, rtx, rtx, int, int);
/* Expand the complex absolute value operation. */
! extern rtx expand_complex_abs (enum machine_mode, rtx, rtx, int);
/* Generate an instruction with a given INSN_CODE with an output and
an input. */
--- 426,436 ----
extern rtx expand_unop (enum machine_mode, optab, rtx, rtx, int);
/* Expand the absolute value operation. */
! extern rtx expand_abs_nojump (enum machine_mode, rtx, rtx, int, int);
! extern rtx expand_abs (enum machine_mode, rtx, rtx, int, int, int);
/* Expand the complex absolute value operation. */
! extern rtx expand_complex_abs (enum machine_mode, rtx, rtx, int, int);
/* Generate an instruction with a given INSN_CODE with an output and
an input. */
*************** enum can_compare_purpose
*** 455,461 ****
/* Return the optab used for computing the given operation on the type
given by the second argument. */
! extern optab optab_for_tree_code (enum tree_code, tree);
/* Nonzero if a compare of mode MODE can be done straightforwardly
(without splitting it into pieces). */
--- 455,462 ----
/* Return the optab used for computing the given operation on the type
given by the second argument. */
! extern optab optab_for_tree_code (enum tree_code, tree,
! enum overflow_behavior);
/* Nonzero if a compare of mode MODE can be done straightforwardly
(without splitting it into pieces). */
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.202
diff -c -3 -p -r1.202 simplify-rtx.c
*** simplify-rtx.c 27 Jul 2004 19:09:32 -0000 1.202
--- simplify-rtx.c 27 Aug 2004 11:47:46 -0000
*************** simplify_const_relational_operation (enu
*** 2847,2853 ****
because it gives an incorrect result if the subtraction wraps around zero.
ANSI C defines unsigned operations such that they never overflow, and
thus such cases can not be ignored; but we cannot do it even for
! signed comparisons for languages such as Java, so test flag_wrapv. */
if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
&& ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
--- 2847,2858 ----
because it gives an incorrect result if the subtraction wraps around zero.
ANSI C defines unsigned operations such that they never overflow, and
thus such cases can not be ignored; but we cannot do it even for
! signed comparisons for languages such as Java, so test flag_wrapv.
!
! FIXME -- this is nonsense; we no longer have information on what
! the type of arguments was. We could wery well compute the subtraction
! in unsigned arithmetics, then cast it to signed and compare. The cast
! would not be represented at rtl level, since it is a no-op. */
if (!flag_wrapv && INTEGRAL_MODE_P (mode) && trueop1 != const0_rtx
&& ! ((REG_P (op0) || GET_CODE (trueop0) == CONST_INT)
Index: tree-complex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-complex.c,v
retrieving revision 2.9
diff -c -3 -p -r2.9 tree-complex.c
*** tree-complex.c 25 Aug 2004 09:51:29 -0000 2.9
--- tree-complex.c 27 Aug 2004 11:47:46 -0000
*************** expand_vector_operations_1 (block_stmt_i
*** 753,758 ****
--- 753,759 ----
enum tree_code code;
enum machine_mode compute_mode;
optab op;
+ enum overflow_behavior ob;
switch (TREE_CODE (stmt))
{
*************** expand_vector_operations_1 (block_stmt_i
*** 781,793 ****
&& TREE_CODE_CLASS (code) != '2')
return;
if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
return;
if (code == CONVERT_EXPR)
abort ();
! op = optab_for_tree_code (code, type);
/* Optabs will try converting a negation into a subtraction, so
look for it as well. TODO: negation of floating-point vectors
--- 782,796 ----
&& TREE_CODE_CLASS (code) != '2')
return;
+ ob = GET_TREE_OVERFLOW_BEHAVIOR (rhs);
+
if (code == NOP_EXPR || code == VIEW_CONVERT_EXPR)
return;
if (code == CONVERT_EXPR)
abort ();
! op = optab_for_tree_code (code, type, ob);
/* Optabs will try converting a negation into a subtraction, so
look for it as well. TODO: negation of floating-point vectors
*************** expand_vector_operations_1 (block_stmt_i
*** 795,801 ****
if (op == NULL
&& code == NEGATE_EXPR
&& INTEGRAL_TYPE_P (TREE_TYPE (type)))
! op = optab_for_tree_code (MINUS_EXPR, type);
/* For very wide vectors, try using a smaller vector mode. */
compute_type = type;
--- 798,804 ----
if (op == NULL
&& code == NEGATE_EXPR
&& INTEGRAL_TYPE_P (TREE_TYPE (type)))
! op = optab_for_tree_code (MINUS_EXPR, type, ob);
/* For very wide vectors, try using a smaller vector mode. */
compute_type = type;
*************** expand_vector_operations_1 (block_stmt_i
*** 836,842 ****
{
case PLUS_EXPR:
case MINUS_EXPR:
! if (TYPE_TRAP_SIGNED (type))
break;
*p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
--- 839,845 ----
{
case PLUS_EXPR:
case MINUS_EXPR:
! if (traps_on_overflow_p (rhs))
break;
*p_rhs = expand_vector_addition (bsi, do_binop, do_plus_minus, type,
*************** expand_vector_operations_1 (block_stmt_i
*** 846,852 ****
return;
case NEGATE_EXPR:
! if (TYPE_TRAP_SIGNED (type))
break;
*p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
--- 849,855 ----
return;
case NEGATE_EXPR:
! if (traps_on_overflow_p (rhs))
break;
*p_rhs = expand_vector_addition (bsi, do_unop, do_negate, type,
Index: tree-dump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-dump.c,v
retrieving revision 1.29
diff -c -3 -p -r1.29 tree-dump.c
*** tree-dump.c 26 Jul 2004 08:23:34 -0000 1.29
--- tree-dump.c 27 Aug 2004 11:47:46 -0000
*************** static const struct dump_option_value_in
*** 709,714 ****
--- 709,715 ----
{"vops", TDF_VOPS},
{"lineno", TDF_LINENO},
{"uid", TDF_UID},
+ {"wraps", TDF_WRAPS},
{"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)},
{NULL, 0}
};
Index: tree-eh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-eh.c,v
retrieving revision 2.16
diff -c -3 -p -r2.16 tree-eh.c
*** tree-eh.c 25 Aug 2004 09:51:29 -0000 2.16
--- tree-eh.c 27 Aug 2004 11:47:46 -0000
*************** tree_could_trap_p (tree expr)
*** 1730,1736 ****
honor_nans = flag_trapping_math && !flag_finite_math_only;
honor_snans = flag_signaling_nans != 0;
}
! else if (INTEGRAL_TYPE_P (t) && TYPE_TRAP_SIGNED (t))
honor_trapv = true;
}
--- 1730,1737 ----
honor_nans = flag_trapping_math && !flag_finite_math_only;
honor_snans = flag_signaling_nans != 0;
}
! else if (INTEGRAL_TYPE_P (t)
! && traps_on_overflow_p (expr))
honor_trapv = true;
}
Index: tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.32
diff -c -3 -p -r2.32 tree-pretty-print.c
*** tree-pretty-print.c 25 Aug 2004 21:21:15 -0000 2.32
--- tree-pretty-print.c 27 Aug 2004 11:47:46 -0000
*************** print_generic_expr (FILE *file, tree t,
*** 148,153 ****
--- 148,185 ----
dump_generic_node (&buffer, t, 0, flags, false);
}
+ /* Dumps overflow behavior of operation EXPR to BUFFER. */
+
+ static void
+ dump_overflow_behavior (pretty_printer *buffer, tree expr)
+ {
+ enum overflow_behavior ob = GET_TREE_OVERFLOW_BEHAVIOR (expr);
+
+ if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+ return;
+
+ switch (ob)
+ {
+ case OB_MODULO:
+ break;
+
+ case OB_UNDEFINED:
+ pp_string (buffer, "{u}");
+ break;
+
+ case OB_NO_OVERFLOW:
+ pp_string (buffer, "{n}");
+ break;
+
+ case OB_TRAP:
+ pp_string (buffer, "{t}");
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
/* Dump the name of a _DECL node and its DECL_UID if TDF_UID is set
in FLAGS. */
*************** dump_generic_node (pretty_printer *buffe
*** 982,987 ****
--- 1014,1021 ----
pp_space (buffer);
pp_string (buffer, op);
+ if (flags & TDF_WRAPS)
+ dump_overflow_behavior (buffer, node);
pp_space (buffer);
/* When the operands are expressions with less priority,
*************** dump_generic_node (pretty_printer *buffe
*** 1012,1017 ****
--- 1046,1054 ----
else
pp_string (buffer, op_symbol (node));
+ if (flags & TDF_WRAPS)
+ dump_overflow_behavior (buffer, node);
+
if (op_prio (TREE_OPERAND (node, 0)) < op_prio (node))
{
pp_character (buffer, '(');
*************** dump_generic_node (pretty_printer *buffe
*** 1033,1038 ****
--- 1070,1077 ----
else
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
pp_string (buffer, op_symbol (node));
+ if (flags & TDF_WRAPS)
+ dump_overflow_behavior (buffer, node);
break;
case MIN_EXPR:
*************** dump_generic_node (pretty_printer *buffe
*** 1052,1058 ****
break;
case ABS_EXPR:
! pp_string (buffer, "ABS_EXPR <");
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
pp_character (buffer, '>');
break;
--- 1091,1100 ----
break;
case ABS_EXPR:
! pp_string (buffer, "ABS_EXPR");
! if (flags & TDF_WRAPS)
! dump_overflow_behavior (buffer, node);
! pp_string (buffer, " <");
dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
pp_character (buffer, '>');
break;
Index: tree-vectorizer.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-vectorizer.c,v
retrieving revision 2.5
diff -c -3 -p -r2.5 tree-vectorizer.c
*** tree-vectorizer.c 25 Aug 2004 21:21:19 -0000 2.5
--- tree-vectorizer.c 27 Aug 2004 11:47:47 -0000
*************** vectorizable_operation (tree stmt, block
*** 1112,1117 ****
--- 1112,1118 ----
int op_type;
tree op;
optab optab;
+ enum overflow_behavior ob;
/* Is STMT a vectorizable binary/unary operation? */
if (TREE_CODE (stmt) != MODIFY_EXPR)
*************** vectorizable_operation (tree stmt, block
*** 1121,1128 ****
return false;
operation = TREE_OPERAND (stmt, 1);
code = TREE_CODE (operation);
! optab = optab_for_tree_code (code, vectype);
/* Support only unary or binary operations. */
op_type = TREE_CODE_LENGTH (code);
--- 1122,1130 ----
return false;
operation = TREE_OPERAND (stmt, 1);
+ ob = GET_TREE_OVERFLOW_BEHAVIOR (operation);
code = TREE_CODE (operation);
! optab = optab_for_tree_code (code, vectype, ob);
/* Support only unary or binary operations. */
op_type = TREE_CODE_LENGTH (code);
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.417
diff -c -3 -p -r1.417 tree.c
*** tree.c 27 Aug 2004 00:55:38 -0000 1.417
--- tree.c 27 Aug 2004 11:47:47 -0000
*************** Software Foundation, 59 Temple Place - S
*** 50,55 ****
--- 50,59 ----
#include "tree-flow.h"
#include "params.h"
+ /* Expressions are by default build with this overflow behavior. */
+
+ enum overflow_behavior default_overflow_behavior = OB_MODULO;
+
/* obstack.[ch] explicitly declined to prototype this. */
extern int _obstack_allocated_p (struct obstack *h, void *obj);
*************** build1_stat (enum tree_code code, tree t
*** 2416,2421 ****
--- 2420,2428 ----
break;
}
+ if (affected_by_overflow_behavior_p (code))
+ SET_TREE_OVERFLOW_BEHAVIOR (t, default_overflow_behavior);
+
return t;
}
*************** build2_stat (enum tree_code code, tree t
*** 2474,2479 ****
--- 2481,2489 ----
TREE_THIS_VOLATILE (t)
= TREE_CODE_CLASS (code) == 'r' && arg0 && TREE_THIS_VOLATILE (arg0);
+ if (affected_by_overflow_behavior_p (code))
+ SET_TREE_OVERFLOW_BEHAVIOR (t, default_overflow_behavior);
+
return t;
}
*************** tree_fold_gcd (tree a, tree b)
*** 5837,5840 ****
--- 5847,5913 ----
}
}
+ /* Returns true if the operation OP is affected by overflow behavior flags. */
+
+ bool
+ affected_by_overflow_behavior_p (enum tree_code code)
+ {
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+
+ /* Division may overflow if we divide by -1. */
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /* Returns true if the operation EXPR may trap according to overflow
+ behavior flags. */
+
+ bool
+ traps_on_overflow_p (tree expr)
+ {
+ if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+ return false;
+
+ return GET_TREE_OVERFLOW_BEHAVIOR (expr) == OB_TRAP;
+ }
+
+ /* Returns true if the operation EXPR may be assumed not to overflow
+ according to behavior flags. */
+
+ bool
+ does_not_overflow_p (tree expr)
+ {
+ if (!affected_by_overflow_behavior_p (TREE_CODE (expr)))
+ return false;
+
+ return GET_TREE_OVERFLOW_BEHAVIOR (expr) != OB_MODULO;
+ }
+
+ /* Copies overflow behavior flags from expression FROM to TO. */
+
+ void
+ copy_overflow_behavior (tree to, tree from)
+ {
+ enum overflow_behavior ob = GET_TREE_OVERFLOW_BEHAVIOR (from);
+ SET_TREE_OVERFLOW_BEHAVIOR (to, ob);
+ }
+
#include "gt-tree.h"
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.605
diff -c -3 -p -r1.605 tree.h
*** tree.h 27 Aug 2004 00:27:24 -0000 1.605
--- tree.h 27 Aug 2004 11:47:47 -0000
*************** struct tree_common GTY(())
*** 220,225 ****
--- 220,227 ----
EH_FILTER_MUST_NOT_THROW in EH_FILTER_EXPR
TYPE_REF_CAN_ALIAS_ALL in
POINTER_TYPE, REFERENCE_TYPE
+ TREE_OVERFLOW_BEHAVIOR
+ in arithmetic expressions
public_flag:
*************** struct tree_common GTY(())
*** 232,237 ****
--- 234,241 ----
ASM_EXPR
TYPE_CACHED_VALUES_P in
..._TYPE
+ TREE_OVERFLOW_BEHAVIOR
+ in arithmetic expressions
SAVE_EXPR_RESOLVED_P in
SAVE_EXPR
*************** extern void tree_operand_check_failed (i
*** 852,860 ****
/* In integral and pointer types, means an unsigned type. */
#define TYPE_UNSIGNED(NODE) (TYPE_CHECK (NODE)->common.unsigned_flag)
- #define TYPE_TRAP_SIGNED(NODE) \
- (flag_trapv && ! TYPE_UNSIGNED (NODE))
-
/* Nonzero in a VAR_DECL means assembler code has been written.
Nonzero in a FUNCTION_DECL means that the function has been compiled.
This is interesting in an inline function, since it might not need
--- 856,861 ----
*************** extern void tree_operand_check_failed (i
*** 915,920 ****
--- 916,950 ----
any expression node. */
#define TREE_INVARIANT(NODE) ((NODE)->common.invariant_flag)
+ /* Defines a behavior of an expression on overflow. */
+
+ enum overflow_behavior
+ {
+ OB_MODULO = 0, /* The operation is computed modulo 2^size of type. */
+ OB_UNDEFINED = 1, /* The behavior is undefined, i.e. we may assume
+ any semantics as needed, or assume that the
+ overflow does not occur. */
+ OB_NO_OVERFLOW = 2, /* The operation is guaranteed to be executed with
+ such operands that it does not overflow. */
+ OB_TRAP = 3 /* The operation traps. */
+ };
+
+ extern enum overflow_behavior default_overflow_behavior;
+
+ #define GET_TREE_OVERFLOW_BEHAVIOR(NODE) \
+ (2 * (NODE)->common.static_flag + (NODE)->common.public_flag)
+ #define SET_TREE_OVERFLOW_BEHAVIOR(NODE, VAL) \
+ do \
+ { \
+ (NODE)->common.static_flag = ((VAL) & 2) != 0; \
+ (NODE)->common.public_flag = ((VAL) & 1) != 0; \
+ } while (0)
+
+ bool affected_by_overflow_behavior_p (enum tree_code);
+ bool traps_on_overflow_p (tree);
+ bool does_not_overflow_p (tree);
+ void copy_overflow_behavior (tree, tree);
+
/* These flags are available for each language front end to use internally. */
#define TREE_LANG_FLAG_0(NODE) ((NODE)->common.lang_flag_0)
#define TREE_LANG_FLAG_1(NODE) ((NODE)->common.lang_flag_1)
*************** enum tree_dump_index
*** 3733,3739 ****
#define TDF_VOPS (1 << 6) /* display virtual operands */
#define TDF_LINENO (1 << 7) /* display statement line numbers */
#define TDF_UID (1 << 8) /* display decl UIDs */
!
typedef struct dump_info *dump_info_p;
--- 3763,3770 ----
#define TDF_VOPS (1 << 6) /* display virtual operands */
#define TDF_LINENO (1 << 7) /* display statement line numbers */
#define TDF_UID (1 << 8) /* display decl UIDs */
! #define TDF_WRAPS (1 << 9) /* display overflow behavior of
! operations */
typedef struct dump_info *dump_info_p;