diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 605ab537b61..61cd3aed827 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,47 @@ +2000-10-18 Chandrakala Chavva + + * expmed.c (expand_mult): Don't do synth_mult optimization for -ftrapv. + Use smulv_optab for -ftrapv. + (expand_mult_highpart): Use unsigned multiply. + (expand_divmod): Special-case division by -1. + For EXACT_DIV_EXPR, do right shift first, then the multiply. + For complex divide, use abs with unsigned result. + * expr.c (force_operand): Use unsigned multiply. + (expand_expr): Use overflow-trapping optabs for signed types if + flag_trapv. + If flag_trapv, don't generate a recursive call with EXPAND_SUM + if the type is signed and the original call wasn't EXPAND_SUM or + EXPAND_INITIALIZER. + * expr.h (addv_optab, subv_optab, smulv_optab, sdivv_optab): Declare. + (negv_optab, absv_optab): Declare. + * flags.h (flag_trapv): Declare. + * genopinit.c (optabs): Add entries for addv_optab, subv_optab, + smulv_optab, sdivv_optab, negv_optab and absv_optab. + (gen_insn): Interpret '$P' as requiring an integer mode, + including partial integer modes. + * loop.c (emit_iv_add_mult): Use unsigned expand_mult_add. + (product_cheap_p): Use unsigned expand_mult. + * optabs.c (addv_optab, subv_optab, smulv_optab, sdivv_optab): Define. + (negv_optab, absv_optab): Define. + (expand_binop): Use overflow-trapping optabs for signed types if + flag_trapv. + Handle negv_optab libe neg_optab. + (expand_abs): Take result_unsignedp argument instead of unsignedp one. + Use overflow-trapping optabs for signed result if flag_trapv. + (expand_complex_abs): Use overflow-trapping optabs for signed types if + flag_trapv. + Don't open-code complex absolute-value operation for flag_trapv. + (init_optabs): Initialize addv_optab, subv_optab, smulv_optab, + sdivv_optab, negv_optab and absv_optab. + * toplev.c (flag_trapv): Define. + (lang_independent_options f_options): Include flag_trapv. + * tree.h (TYPE_TRAP_SIGNED): Define. + * libgcc2.c (__addvsi3, __addvdi3, __subvsi3,__subvsi3, __subvdi3, + __mulvsi3, __negvsi2, __negvdi2, __absvsi2, __absvdi2, __mulvdi3): + New functions. + * Makefile.in: add _absvsi2 _absvdi2 _addvsi3 _addvdi3 _subvsi3 + _subvdi3 _mulvsi3 _mulvdi3 _negvsi2 _negvdi2. + 2000-10-18 Geoffrey Keating David V. Henkel-Wallace diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 7f9fcfe8d6f..595c62ef247 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -754,6 +754,8 @@ LIB2FUNCS = _muldi3 _divdi3 _moddi3 _udivdi3 _umoddi3 _negdi2 \ _fixtfdi _fixunstfdi _floatditf \ __gcc_bcmp _varargs __dummy _eprintf \ _bb _shtab _clear_cache _trampoline __main _exit \ + _absvsi2 _absvdi2 _addvsi3 _addvdi3 _subvsi3 _subvdi3 \ + _mulvsi3 _mulvdi3 _negvsi2 _negvdi2 \ _ctors LIB2FUNCS_EH = _eh diff --git a/gcc/expmed.c b/gcc/expmed.c index 69761b99165..bdd9fa703c4 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -2358,7 +2358,8 @@ expand_mult (mode, op0, op1, target, unsignedp) But this causes such a terrible slowdown sometimes that it seems better to use synth_mult always. */ - if (const_op1 && GET_CODE (const_op1) == CONST_INT) + if (const_op1 && GET_CODE (const_op1) == CONST_INT + && (unsignedp || ! flag_trapv)) { struct algorithm alg; struct algorithm alg2; @@ -2531,7 +2532,10 @@ expand_mult (mode, op0, op1, target, unsignedp) /* 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, smul_optab, + 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 (); @@ -2775,7 +2779,9 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost) multiply. Maybe change expand_binop to handle widening multiply? */ op0 = convert_to_mode (wider_mode, op0, unsignedp); - tem = expand_mult (wider_mode, op0, wide_op1, NULL_RTX, unsignedp); + /* We know that this can't have signed overflow, so pretend this is + an unsigned multiply. */ + tem = expand_mult (wider_mode, op0, wide_op1, NULL_RTX, 0); tem = expand_shift (RSHIFT_EXPR, wider_mode, tem, build_int_2 (size, 0), NULL_RTX, 1); return convert_modes (mode, wider_mode, tem, unsignedp); @@ -2968,6 +2974,16 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) if (op1 == const1_rtx) 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 /* Don't use the function value register as a target since we have to read it as well as write it, @@ -3764,16 +3780,15 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) { HOST_WIDE_INT d = INTVAL (op1); unsigned HOST_WIDE_INT ml; - int post_shift; + int pre_shift; rtx t1; - post_shift = floor_log2 (d & -d); - ml = invert_mod2n (d >> post_shift, size); - t1 = expand_mult (compute_mode, op0, GEN_INT (ml), NULL_RTX, - unsignedp); - quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1, - build_int_2 (post_shift, 0), - NULL_RTX, unsignedp); + pre_shift = floor_log2 (d & -d); + ml = invert_mod2n (d >> pre_shift, size); + t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0, + build_int_2 (pre_shift, 0), NULL_RTX, unsignedp); + quotient = expand_mult (compute_mode, t1, GEN_INT (ml), NULL_RTX, + 0); insn = get_last_insn (); set_unique_reg_note (insn, @@ -3826,8 +3841,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp) remainder = expand_binop (compute_mode, sub_optab, op0, tem, remainder, 0, OPTAB_LIB_WIDEN); } - abs_rem = expand_abs (compute_mode, remainder, NULL_RTX, 0); - abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0); + 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_2 (1, 0), NULL_RTX, 1); do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label); @@ -4477,6 +4492,11 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep) we can use zero-extension to the wider mode (an unsigned conversion) as the operation. */ + /* CYGNUS LOCAL - amylaar/-ftrapv: Note that ABS doesn't yield a + positive number for INT_MIN, but that is compensated by the + subsequent overflow when subtracting one / negating. + END CYGNUS LOCAL */ + if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) tem = expand_unop (mode, abs_optab, op0, subtarget, 1); else if (ffs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) diff --git a/gcc/expr.c b/gcc/expr.c index 01c1fb66b6b..84e574d915b 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -5307,7 +5307,7 @@ force_operand (value, target) tmp = force_operand (XEXP (value, 0), subtarget); return expand_mult (GET_MODE (value), tmp, force_operand (op2, NULL_RTX), - target, 0); + target, 1); } if (binoptab) @@ -7248,7 +7248,9 @@ expand_expr (exp, target, tmode, modifier) /* We come here from MINUS_EXPR when the second operand is a constant. */ plus_expr: - this_optab = add_optab; + this_optab = ! unsignedp && flag_trapv + && (GET_MODE_CLASS(mode) == MODE_INT) + ? addv_optab : add_optab; /* If we are adding a constant, an RTL_EXPR that is sp, fp, or ap, and something else, make sure we add the register to the constant and @@ -7283,7 +7285,7 @@ expand_expr (exp, target, tmode, modifier) If this is an EXPAND_SUM call, always return the sum. */ if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER - || mode == ptr_mode) + || (mode == ptr_mode && (unsignedp || ! flag_trapv))) { if (TREE_CODE (TREE_OPERAND (exp, 0)) == INTEGER_CST && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT @@ -7441,7 +7443,9 @@ expand_expr (exp, target, tmode, modifier) goto plus_expr; } } - this_optab = sub_optab; + this_optab = ! unsignedp && flag_trapv + && (GET_MODE_CLASS(mode) == MODE_INT) + ? subv_optab : sub_optab; goto binop; case MULT_EXPR: @@ -7624,7 +7628,10 @@ expand_expr (exp, target, tmode, modifier) case NEGATE_EXPR: op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0); - temp = expand_unop (mode, neg_optab, op0, target, 0); + temp = expand_unop (mode, + ! unsignedp && flag_trapv + && (GET_MODE_CLASS(mode) == MODE_INT) + ? negv_optab : neg_optab, op0, target, 0); if (temp == 0) abort (); return temp; @@ -7642,7 +7649,7 @@ expand_expr (exp, target, tmode, modifier) if (TREE_UNSIGNED (type)) return op0; - return expand_abs (mode, op0, target, + return expand_abs (mode, op0, target, unsignedp, safe_from_p (target, TREE_OPERAND (exp, 0), 1)); case MAX_EXPR: @@ -7964,10 +7971,14 @@ expand_expr (exp, target, tmode, modifier) && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<') { rtx result; - optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR ? add_optab - : TREE_CODE (binary_op) == MINUS_EXPR ? sub_optab - : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab - : xor_optab); + optab boptab = (TREE_CODE (binary_op) == PLUS_EXPR + ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op)) + ? addv_optab : add_optab) + : TREE_CODE (binary_op) == MINUS_EXPR + ? (TYPE_TRAP_SIGNED (TREE_TYPE (binary_op)) + ? subv_optab : sub_optab) + : TREE_CODE (binary_op) == BIT_IOR_EXPR ? ior_optab + : xor_optab); /* If we had X ? A : A + 1, do this as A + (X == 0). @@ -8491,7 +8502,10 @@ expand_expr (exp, target, tmode, modifier) gen_realpart (partmode, op0)); imag_t = gen_imagpart (partmode, target); - temp = expand_unop (partmode, neg_optab, + temp = expand_unop (partmode, + ! unsignedp && flag_trapv + && (GET_MODE_CLASS(partmode) == MODE_INT) + ? negv_optab : neg_optab, gen_imagpart (partmode, op0), imag_t, 0); if (temp != imag_t) emit_move_insn (imag_t, temp); @@ -9045,6 +9059,9 @@ expand_increment (exp, post, ignore) this_optab = add_optab; } + if (TYPE_TRAP_SIGNED (TREE_TYPE (exp))) + this_optab = this_optab == add_optab ? addv_optab : subv_optab; + /* For a preincrement, see if we can do this with a single instruction. */ if (!post) { diff --git a/gcc/expr.h b/gcc/expr.h index ffa7d86ad95..8cb28361038 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -298,10 +298,13 @@ typedef struct optab enum optab_index { OTI_add, + OTI_addv, OTI_sub, + OTI_subv, /* Signed and fp multiply */ OTI_smul, + OTI_smulv, /* Signed multiply, return high word */ OTI_smul_highpart, OTI_umul_highpart, @@ -311,6 +314,7 @@ enum optab_index /* Signed divide */ OTI_sdiv, + OTI_sdivv, /* Signed divide-and-remainder in one */ OTI_sdivmod, OTI_udiv, @@ -357,8 +361,10 @@ enum optab_index /* Unary operations */ /* Negation */ OTI_neg, + OTI_negv, /* Abs value */ OTI_abs, + OTI_absv, /* Bitwise not */ OTI_one_cmpl, /* Find first bit set */ @@ -393,11 +399,15 @@ extern optab optab_table[OTI_MAX]; #define add_optab (optab_table[OTI_add]) #define sub_optab (optab_table[OTI_sub]) #define smul_optab (optab_table[OTI_smul]) +#define addv_optab (optab_table[OTI_addv]) +#define subv_optab (optab_table[OTI_subv]) #define smul_highpart_optab (optab_table[OTI_smul_highpart]) #define umul_highpart_optab (optab_table[OTI_umul_highpart]) #define smul_widen_optab (optab_table[OTI_smul_widen]) #define umul_widen_optab (optab_table[OTI_umul_widen]) #define sdiv_optab (optab_table[OTI_sdiv]) +#define smulv_optab (optab_table[OTI_smulv]) +#define sdivv_optab (optab_table[OTI_sdivv]) #define sdivmod_optab (optab_table[OTI_sdivmod]) #define udiv_optab (optab_table[OTI_udiv]) #define udivmod_optab (optab_table[OTI_udivmod]) @@ -422,7 +432,9 @@ extern optab optab_table[OTI_MAX]; #define movstrict_optab (optab_table[OTI_movstrict]) #define neg_optab (optab_table[OTI_neg]) +#define negv_optab (optab_table[OTI_negv]) #define abs_optab (optab_table[OTI_abs]) +#define absv_optab (optab_table[OTI_absv]) #define one_cmpl_optab (optab_table[OTI_one_cmpl]) #define ffs_optab (optab_table[OTI_ffs]) #define sqrt_optab (optab_table[OTI_sqrt]) @@ -769,7 +781,7 @@ extern int expand_twoval_binop PARAMS ((optab, rtx, rtx, rtx, rtx, int)); extern rtx expand_unop PARAMS ((enum machine_mode, optab, rtx, rtx, int)); /* Expand the absolute value operation. */ -extern rtx expand_abs PARAMS ((enum machine_mode, rtx, rtx, int)); +extern rtx expand_abs PARAMS ((enum machine_mode, rtx, rtx, int, int)); /* Expand the complex absolute value operation. */ extern rtx expand_complex_abs PARAMS ((enum machine_mode, rtx, rtx, int)); diff --git a/gcc/flags.h b/gcc/flags.h index 7fec383bdd7..dec686dfe38 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -555,6 +555,10 @@ extern int frame_pointer_needed; extern int flag_check_memory_usage; +/* Nonzero if the generated code should trap on signed overflow + for PLUS / SUB / MULT. */ +extern int flag_trapv; + /* Nonzero if GCC must prefix function names (used with flag_check_memory_usage). */ diff --git a/gcc/genopinit.c b/gcc/genopinit.c index 993c347a1b0..9aeaee7baac 100644 --- a/gcc/genopinit.c +++ b/gcc/genopinit.c @@ -46,8 +46,11 @@ Boston, MA 02111-1307, USA. */ If $N is present in the pattern, it means the two modes must be consecutive widths in the same mode class (e.g, QImode and HImode). $I means that - only integer modes should be considered for the next mode, and $F means - that only float modes should be considered. + only full integer modes should be considered for the next mode, and $F + means that only float modes should be considered. + $P means that both full and partial integer modes should be considered. + + $V means to emit 'v' if the first mode is a MODE_FLOAT mode. For some optabs, we store the operation by RTL codes. These are only used for comparisons. In that case, $c and $C are the lower-case and @@ -62,14 +65,24 @@ const char * const optabs[] = "fixtrunctab[$A][$B][1] = CODE_FOR_$(fixuns_trunc$F$a$I$b2$)", "floattab[$B][$A][0] = CODE_FOR_$(float$I$a$F$b2$)", "floattab[$B][$A][1] = CODE_FOR_$(floatuns$I$a$F$b2$)", - "add_optab->handlers[$A].insn_code = CODE_FOR_$(add$a3$)", - "sub_optab->handlers[$A].insn_code = CODE_FOR_$(sub$a3$)", - "smul_optab->handlers[$A].insn_code = CODE_FOR_$(mul$a3$)", + "add_optab->handlers[$A].insn_code = CODE_FOR_$(add$P$a3$)", + "addv_optab->handlers[(int) $A].insn_code =\n\ + add_optab->handlers[(int) $A].insn_code = CODE_FOR_$(add$F$a3$)", + "addv_optab->handlers[(int) $A].insn_code = CODE_FOR_$(addv$I$a3$)", + "sub_optab->handlers[$A].insn_code = CODE_FOR_$(sub$P$a3$)", + "subv_optab->handlers[(int) $A].insn_code =\n\ + sub_optab->handlers[(int) $A].insn_code = CODE_FOR_$(sub$F$a3$)", + "subv_optab->handlers[(int) $A].insn_code = CODE_FOR_$(subv$I$a3$)", + "smul_optab->handlers[$A].insn_code = CODE_FOR_$(mul$P$a3$)", + "smulv_optab->handlers[(int) $A].insn_code =\n\ + smul_optab->handlers[(int) $A].insn_code = CODE_FOR_$(mul$F$a3$)", + "smulv_optab->handlers[(int) $A].insn_code = CODE_FOR_$(mulv$I$a3$)", "umul_highpart_optab->handlers[$A].insn_code = CODE_FOR_$(umul$a3_highpart$)", "smul_highpart_optab->handlers[$A].insn_code = CODE_FOR_$(smul$a3_highpart$)", "smul_widen_optab->handlers[$B].insn_code = CODE_FOR_$(mul$a$b3$)$N", "umul_widen_optab->handlers[$B].insn_code = CODE_FOR_$(umul$a$b3$)$N", "sdiv_optab->handlers[$A].insn_code = CODE_FOR_$(div$I$a3$)", + "sdivv_optab->handlers[(int) $A].insn_code = CODE_FOR_$(div$V$I$a3$)", "udiv_optab->handlers[$A].insn_code = CODE_FOR_$(udiv$I$a3$)", "sdivmod_optab->handlers[$A].insn_code = CODE_FOR_$(divmod$a4$)", "udivmod_optab->handlers[$A].insn_code = CODE_FOR_$(udivmod$a4$)", @@ -91,8 +104,14 @@ const char * const optabs[] = "smax_optab->handlers[$A].insn_code = CODE_FOR_$(max$F$a3$)", "umin_optab->handlers[$A].insn_code = CODE_FOR_$(umin$I$a3$)", "umax_optab->handlers[$A].insn_code = CODE_FOR_$(umax$I$a3$)", - "neg_optab->handlers[$A].insn_code = CODE_FOR_$(neg$a2$)", - "abs_optab->handlers[$A].insn_code = CODE_FOR_$(abs$a2$)", + "neg_optab->handlers[$A].insn_code = CODE_FOR_$(neg$P$a2$)", + "negv_optab->handlers[(int) $A].insn_code =\n\ + neg_optab->handlers[(int) $A].insn_code = CODE_FOR_$(neg$F$a2$)", + "negv_optab->handlers[(int) $A].insn_code = CODE_FOR_$(negv$I$a2$)", + "abs_optab->handlers[$A].insn_code = CODE_FOR_$(abs$P$a2$)", + "absv_optab->handlers[(int) $A].insn_code =\n\ + abs_optab->handlers[(int) $A].insn_code = CODE_FOR_$(abs$F$a2$)", + "absv_optab->handlers[(int) $A].insn_code = CODE_FOR_$(absv$I$a2$)", "sqrt_optab->handlers[$A].insn_code = CODE_FOR_$(sqrt$a2$)", "sin_optab->handlers[$A].insn_code = CODE_FOR_$(sin$a2$)", "cos_optab->handlers[$A].insn_code = CODE_FOR_$(cos$a2$)", @@ -136,7 +155,7 @@ gen_insn (insn) for (pindex = 0; pindex < ARRAY_SIZE (optabs); pindex++) { - int force_float = 0, force_int = 0; + int force_float = 0, force_int = 0, force_partial_int = 0; int force_consec = 0; int matches = 1; @@ -160,9 +179,14 @@ gen_insn (insn) case 'I': force_int = 1; break; + case 'P': + force_partial_int = 1; + break; case 'F': force_float = 1; break; + case 'V': + break; case 'c': for (op = 0; op < NUM_RTX_CODE; op++) { @@ -196,6 +220,9 @@ gen_insn (insn) if (*p == 0 && (! force_int || mode_class[i] == MODE_INT) + && (! force_partial_int + || mode_class[i] == MODE_INT + || mode_class[i] == MODE_PARTIAL_INT) && (! force_float || mode_class[i] == MODE_FLOAT)) break; } @@ -207,7 +234,7 @@ gen_insn (insn) else m2 = i, np += strlen (GET_MODE_NAME(i)); - force_int = force_float = 0; + force_int = force_partial_int = force_float = 0; break; default: @@ -243,6 +270,10 @@ gen_insn (insn) case '(': case ')': case 'I': case 'F': case 'N': break; + case 'V': + if (GET_MODE_CLASS (m1) == MODE_FLOAT) + printf ("v"); + break; case 'a': for (np = GET_MODE_NAME(m1); *np; np++) putchar (TOLOWER (*np)); diff --git a/gcc/invoke.texi b/gcc/invoke.texi index 19ae2a0b28d..73dd1d9c85b 100644 --- a/gcc/invoke.texi +++ b/gcc/invoke.texi @@ -173,7 +173,7 @@ in the following sections. -fdata-sections -ffunction-sections -fgcse -finline-functions -finline-limit=@var{n} -fkeep-inline-functions -fmove-all-movables -fno-default-inline -fno-defer-pop --fno-function-cse -fno-inline -fno-peephole +-fno-function-cse -fno-inline -fno-peephole -ftrapv -fomit-frame-pointer -foptimize-register-moves -foptimize-sibling-calls -fregmove -frerun-cse-after-loop -frerun-loop-opt -freduce-all-givs -fschedule-insns -fschedule-insns2 -fssa -fstrength-reduce @@ -2664,6 +2664,10 @@ Usage, gcc.info, Using and Porting GCC}.@refill @item -foptimize-sibling-calls Optimize sibling and tail recursive calls. +@item -ftrapv +This option generates traps for signed overflow on addition, subtraction, +multiplication operations. + @item -fno-inline Don't pay attention to the @code{inline} keyword. Normally this option is used to keep the compiler from expanding any functions inline. diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index 7e8eaf7b11b..00a50e6b43e 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -50,6 +50,176 @@ Boston, MA 02111-1307, USA. */ #if defined (L_divdi3) || defined (L_moddi3) static inline #endif + +#ifdef L_addvsi3 +SItype +__addvsi3 (SItype a, SItype b) +{ + SItype w, w1; + + w = a + b; + + if (b >= 0 ? w < a : w > a) + abort (); + + return w; +} + +#ifdef L_addvdi3 +DItype +__addvdi3 (DItype a, DItype b) +{ + DItype w; + + w = a + b; + + if (b >= 0 ? w < a : w > a) + abort (); + + return w; +} +#endif + +#ifdef L_subvsi3 +SItype +__subvsi3 (SItype a, SItype b) +{ +#ifdef L_addvsi3 + return __addvsi3 (a, (-b)); +#else + DItype w; + + w = a - b; + + if (b >= 0 ? w > a : w < a) + abort (); + + return w; +#endif +} +#endif + +#ifdef L_subvdi3 +DItype +__subvdi3 (DItype a, DItype b) +{ +#ifdef L_addvdi3 + return (a, (-b)); +#else + DItype w; + + w = a - b; + + if (b >= 0 ? w > a : w < a) + abort (); + + return w; +#endif +} +#endif + +#ifdef L_mulvsi3 +SItype +__mulvsi3 (SItype a, SItype b) +{ + DItype w; + + w = a * b; + + if ((a >= 0 && b >= 0) ? w < 0 + : (a >= 0 || b >= 0) ? w > 0 : w < 0) + abort (); + + return w; +} +#endif + +#ifdef L_negvsi2 +SItype +__negvsi2 (SItype a) +{ + SItype w; + + w = -a; + + if (a >= 0 ? w > 0 : w < 0) + abort (); + + return w; +} +#endif + +#ifdef L_negvdi2 +DItype +__negvdi2 (DItype a) +{ + DItype w; + + w = -a; + + if (a >= 0 ? w > 0 : w < 0) + abort (); + + return w; +} +#endif + +#ifdef L_absvsi2 +SItype +__absvsi2 (SItype a) +{ + SItype w = a; + + if (a < 0) +#ifdef L_negvsi2 + w = __negvsi2 (a); +#else + w = -a; + + if (w < 0) + abort (); +#endif + + return w; +} +#endif + +#ifdef L_absvdi2 +DItype +__absvdi2 (DItype a) +{ + DItype w = a; + + if (a < 0) +#ifdef L_negvsi2 + w = __negvsi2 (a); +#else + w = -a; + + if (w < 0) + abort (); +#endif + + return w; +} +#endif + +#ifdef L_mulvdi3 +DItype +__mulvdi3 (DItype u, DItype v) +{ + DItype w; + + w = u * v; + + if ((u >= 0 && v >= 0) ? w < 0 + : (u >= 0 || v >= 0) ? w > 0 : w < 0) + abort (); + + return w; +} +#endif + DWtype __negdi2 (DWtype u) { diff --git a/gcc/loop.c b/gcc/loop.c index 977bbd26279..23ee292f091 100644 --- a/gcc/loop.c +++ b/gcc/loop.c @@ -6877,7 +6877,7 @@ emit_iv_add_mult (b, m, a, reg, insert_before) update_reg_last_use (m, insert_before); start_sequence (); - result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 0); + result = expand_mult_add (b, reg, m, a, GET_MODE (reg), 1); if (reg != result) emit_move_insn (reg, result); seq = gen_sequence (); @@ -6961,7 +6961,7 @@ product_cheap_p (a, b) of insns is generated. */ start_sequence (); - expand_mult (GET_MODE (a), a, b, NULL_RTX, 0); + expand_mult (GET_MODE (a), a, b, NULL_RTX, 1); tmp = gen_sequence (); end_sequence (); diff --git a/gcc/optabs.c b/gcc/optabs.c index 5dbbcaa9ee9..16433a9a3dc 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -218,7 +218,19 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode, rtx real_t, imag_t; rtx temp1, temp2; rtx res; + optab this_add_optab = add_optab; + optab this_sub_optab = sub_optab; + optab this_neg_optab = neg_optab; + optab this_mul_optab = smul_optab; + if (binoptab == sdivv_optab) + { + this_add_optab = addv_optab; + this_sub_optab = subv_optab; + this_neg_optab = negv_optab; + this_mul_optab = smulv_optab; + } + /* Don't fetch these from memory more than once. */ real0 = force_reg (submode, real0); real1 = force_reg (submode, real1); @@ -229,16 +241,16 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode, imag1 = force_reg (submode, imag1); /* Divisor: c*c + d*d. */ - temp1 = expand_binop (submode, smul_optab, real1, real1, + temp1 = expand_binop (submode, this_mul_optab, real1, real1, NULL_RTX, unsignedp, methods); - temp2 = expand_binop (submode, smul_optab, imag1, imag1, + temp2 = expand_binop (submode, this_mul_optab, imag1, imag1, NULL_RTX, unsignedp, methods); if (temp1 == 0 || temp2 == 0) return 0; - divisor = expand_binop (submode, add_optab, temp1, temp2, + divisor = expand_binop (submode, this_add_optab, temp1, temp2, NULL_RTX, unsignedp, methods); if (divisor == 0) return 0; @@ -249,44 +261,44 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode, /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)). */ /* Calculate the dividend. */ - real_t = expand_binop (submode, smul_optab, real0, real1, + real_t = expand_binop (submode, this_mul_optab, real0, real1, NULL_RTX, unsignedp, methods); - imag_t = expand_binop (submode, smul_optab, real0, imag1, + imag_t = expand_binop (submode, this_mul_optab, real0, imag1, NULL_RTX, unsignedp, methods); if (real_t == 0 || imag_t == 0) return 0; - imag_t = expand_unop (submode, neg_optab, imag_t, + imag_t = expand_unop (submode, this_neg_optab, imag_t, NULL_RTX, unsignedp); } else { /* Mathematically, ((a+ib)(c-id))/divider. */ /* Calculate the dividend. */ - temp1 = expand_binop (submode, smul_optab, real0, real1, + temp1 = expand_binop (submode, this_mul_optab, real0, real1, NULL_RTX, unsignedp, methods); - temp2 = expand_binop (submode, smul_optab, imag0, imag1, + temp2 = expand_binop (submode, this_mul_optab, imag0, imag1, NULL_RTX, unsignedp, methods); if (temp1 == 0 || temp2 == 0) return 0; - real_t = expand_binop (submode, add_optab, temp1, temp2, + real_t = expand_binop (submode, this_add_optab, temp1, temp2, NULL_RTX, unsignedp, methods); - temp1 = expand_binop (submode, smul_optab, imag0, real1, + temp1 = expand_binop (submode, this_mul_optab, imag0, real1, NULL_RTX, unsignedp, methods); - temp2 = expand_binop (submode, smul_optab, real0, imag1, + temp2 = expand_binop (submode, this_mul_optab, real0, imag1, NULL_RTX, unsignedp, methods); if (temp1 == 0 || temp2 == 0) return 0; - imag_t = expand_binop (submode, sub_optab, temp1, temp2, + imag_t = expand_binop (submode, this_sub_optab, temp1, temp2, NULL_RTX, unsignedp, methods); if (real_t == 0 || imag_t == 0) @@ -340,6 +352,18 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, enum machine_mode mode; int align; rtx res; + optab this_add_optab = add_optab; + optab this_sub_optab = sub_optab; + optab this_neg_optab = neg_optab; + optab this_mul_optab = smul_optab; + + if (binoptab == sdivv_optab) + { + this_add_optab = addv_optab; + this_sub_optab = subv_optab; + this_neg_optab = negv_optab; + this_mul_optab = smulv_optab; + } /* Don't fetch these from memory more than once. */ real0 = force_reg (submode, real0); @@ -358,8 +382,8 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, } else { - temp1 = expand_abs (submode, real1, NULL_RTX, 1); - temp2 = expand_abs (submode, imag1, NULL_RTX, 1); + temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1); + temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1); } if (temp1 == 0 || temp2 == 0) @@ -385,13 +409,13 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, /* Calculate divisor. */ - temp1 = expand_binop (submode, smul_optab, imag1, ratio, + temp1 = expand_binop (submode, this_mul_optab, imag1, ratio, NULL_RTX, unsignedp, methods); if (temp1 == 0) return 0; - divisor = expand_binop (submode, add_optab, temp1, real1, + divisor = expand_binop (submode, this_add_optab, temp1, real1, NULL_RTX, unsignedp, methods); if (divisor == 0) @@ -405,13 +429,13 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)). */ - imag_t = expand_binop (submode, smul_optab, real0, ratio, + imag_t = expand_binop (submode, this_mul_optab, real0, ratio, NULL_RTX, unsignedp, methods); if (imag_t == 0) return 0; - imag_t = expand_unop (submode, neg_optab, imag_t, + imag_t = expand_unop (submode, this_neg_optab, imag_t, NULL_RTX, unsignedp); if (real_t == 0 || imag_t == 0) @@ -422,22 +446,22 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, /* Compute (a+ib)/(c+id) as (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)). */ - temp1 = expand_binop (submode, smul_optab, imag0, ratio, + temp1 = expand_binop (submode, this_mul_optab, imag0, ratio, NULL_RTX, unsignedp, methods); if (temp1 == 0) return 0; - real_t = expand_binop (submode, add_optab, temp1, real0, + real_t = expand_binop (submode, this_add_optab, temp1, real0, NULL_RTX, unsignedp, methods); - temp1 = expand_binop (submode, smul_optab, real0, ratio, + temp1 = expand_binop (submode, this_mul_optab, real0, ratio, NULL_RTX, unsignedp, methods); if (temp1 == 0) return 0; - imag_t = expand_binop (submode, sub_optab, imag0, temp1, + imag_t = expand_binop (submode, this_sub_optab, imag0, temp1, NULL_RTX, unsignedp, methods); if (real_t == 0 || imag_t == 0) @@ -490,13 +514,13 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, /* Calculate divisor. */ - temp1 = expand_binop (submode, smul_optab, real1, ratio, + temp1 = expand_binop (submode, this_mul_optab, real1, ratio, NULL_RTX, unsignedp, methods); if (temp1 == 0) return 0; - divisor = expand_binop (submode, add_optab, temp1, imag1, + divisor = expand_binop (submode, this_add_optab, temp1, imag1, NULL_RTX, unsignedp, methods); if (divisor == 0) @@ -508,10 +532,10 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, { /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d). */ - real_t = expand_binop (submode, smul_optab, real0, ratio, + real_t = expand_binop (submode, this_mul_optab, real0, ratio, NULL_RTX, unsignedp, methods); - imag_t = expand_unop (submode, neg_optab, real0, + imag_t = expand_unop (submode, this_neg_optab, real0, NULL_RTX, unsignedp); if (real_t == 0 || imag_t == 0) @@ -522,22 +546,22 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode, /* Compute (a+ib)/(c+id) as (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d). */ - temp1 = expand_binop (submode, smul_optab, real0, ratio, + temp1 = expand_binop (submode, this_mul_optab, real0, ratio, NULL_RTX, unsignedp, methods); if (temp1 == 0) return 0; - real_t = expand_binop (submode, add_optab, temp1, imag0, + real_t = expand_binop (submode, this_add_optab, temp1, imag0, NULL_RTX, unsignedp, methods); - temp1 = expand_binop (submode, smul_optab, imag0, ratio, + temp1 = expand_binop (submode, this_mul_optab, imag0, ratio, NULL_RTX, unsignedp, methods); if (temp1 == 0) return 0; - imag_t = expand_binop (submode, sub_optab, temp1, real0, + imag_t = expand_binop (submode, this_sub_optab, temp1, real0, NULL_RTX, unsignedp, methods); if (real_t == 0 || imag_t == 0) @@ -1491,7 +1515,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) else if (imag0) res = imag0; else if (binoptab->code == MINUS) - res = expand_unop (submode, neg_optab, imag1, imagr, unsignedp); + res = expand_unop (submode, + binoptab == subv_optab ? negv_optab : neg_optab, + imag1, imagr, unsignedp); else res = imag1; @@ -1525,8 +1551,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) if (temp1 == 0 || temp2 == 0) break; - res = expand_binop (submode, sub_optab, temp1, temp2, - realr, unsignedp, methods); + res = (expand_binop + (submode, + binoptab == smulv_optab ? subv_optab : sub_optab, + temp1, temp2, realr, unsignedp, methods)); if (res == 0) break; @@ -1542,8 +1570,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods) if (temp1 == 0 || temp2 == 0) break; - res = expand_binop (submode, add_optab, temp1, temp2, - imagr, unsignedp, methods); + res = (expand_binop + (submode, + binoptab == smulv_optab ? addv_optab : add_optab, + temp1, temp2, imagr, unsignedp, methods)); if (res == 0) break; @@ -2120,7 +2150,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp) } /* Open-code the complex negation operation. */ - else if (unoptab == neg_optab + else if (unoptab->code == NEG && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)) { rtx target_piece; @@ -2231,11 +2261,13 @@ expand_unop (mode, unoptab, op0, target, unsignedp) /* If there is no negate operation, try doing a subtract from zero. The US Software GOFAST library needs this. */ - if (unoptab == neg_optab) + if (unoptab->code == NEG) { rtx temp; - temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0, - target, unsignedp, OPTAB_LIB_WIDEN); + temp = expand_binop (mode, + unoptab == negv_optab ? subv_optab : sub_optab, + CONST0_RTX (mode), op0, + target, unsignedp, OPTAB_LIB_WIDEN); if (temp) return temp; } @@ -2253,16 +2285,21 @@ expand_unop (mode, unoptab, op0, target, unsignedp) */ rtx -expand_abs (mode, op0, target, safe) +expand_abs (mode, op0, target, result_unsignedp, safe) enum machine_mode mode; rtx op0; rtx target; + int result_unsignedp; int safe; { rtx temp, op1; + if (! flag_trapv) + result_unsignedp = 1; + /* First try to do it with a special abs instruction. */ - temp = expand_unop (mode, abs_optab, op0, target, 0); + temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab, + op0, target, 0); if (temp != 0) return temp; @@ -2298,8 +2335,8 @@ expand_abs (mode, op0, target, safe) temp = expand_binop (mode, xor_optab, extended, op0, target, 0, OPTAB_LIB_WIDEN); if (temp != 0) - temp = expand_binop (mode, sub_optab, temp, extended, target, 0, - OPTAB_LIB_WIDEN); + temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab, + temp, extended, target, 0, OPTAB_LIB_WIDEN); if (temp != 0) return temp; @@ -2335,7 +2372,8 @@ expand_abs (mode, op0, target, safe) do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode, NULL_RTX, 0, NULL_RTX, op1); - op0 = expand_unop (mode, neg_optab, target, target, 0); + op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab, + target, target, 0); if (op0 != target) emit_move_insn (target, op0); emit_label (op1); @@ -2365,6 +2403,7 @@ expand_complex_abs (mode, op0, target, unsignedp) rtx entry_last = get_last_insn (); rtx last; rtx pat; + optab this_abs_optab; /* Find the correct mode for the real and imaginary parts. */ enum machine_mode submode @@ -2387,9 +2426,13 @@ expand_complex_abs (mode, op0, target, unsignedp) if (target) target = protect_from_queue (target, 1); - if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) + 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) { - int icode = (int) abs_optab->handlers[(int) mode].insn_code; + int icode = (int) this_abs_optab->handlers[(int) mode].insn_code; enum machine_mode mode0 = insn_data[icode].operand[1].mode; rtx xop0 = op0; @@ -2414,10 +2457,12 @@ expand_complex_abs (mode, op0, target, unsignedp) if (pat) { if (GET_CODE (pat) == SEQUENCE - && ! add_equal_note (pat, temp, abs_optab->code, xop0, NULL_RTX)) + && ! add_equal_note (pat, temp, this_abs_optab->code, xop0, + NULL_RTX)) { delete_insns_since (last); - return expand_unop (mode, abs_optab, op0, NULL_RTX, unsignedp); + return expand_unop (mode, this_abs_optab, op0, NULL_RTX, + unsignedp); } emit_insn (pat); @@ -2433,7 +2478,8 @@ expand_complex_abs (mode, op0, target, unsignedp) for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; wider_mode = GET_MODE_WIDER_MODE (wider_mode)) { - if (abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) + if (this_abs_optab->handlers[(int) wider_mode].insn_code + != CODE_FOR_nothing) { rtx xop0 = op0; @@ -2483,7 +2529,7 @@ expand_complex_abs (mode, op0, target, unsignedp) } /* Now try a library call in this mode. */ - if (abs_optab->handlers[(int) mode].libfunc) + if (this_abs_optab->handlers[(int) mode].libfunc) { rtx insns; rtx value; @@ -2499,7 +2545,7 @@ expand_complex_abs (mode, op0, target, unsignedp) target = gen_reg_rtx (submode); emit_libcall_block (insns, target, value, - gen_rtx_fmt_e (abs_optab->code, mode, op0)); + gen_rtx_fmt_e (this_abs_optab->code, mode, op0)); return target; } @@ -2509,9 +2555,9 @@ expand_complex_abs (mode, op0, target, unsignedp) for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode; wider_mode = GET_MODE_WIDER_MODE (wider_mode)) { - if ((abs_optab->handlers[(int) wider_mode].insn_code + if ((this_abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing) - || abs_optab->handlers[(int) wider_mode].libfunc) + || this_abs_optab->handlers[(int) wider_mode].libfunc) { rtx xop0 = op0; @@ -4528,13 +4574,17 @@ init_optabs () #endif add_optab = init_optab (PLUS); + addv_optab = init_optab (PLUS); sub_optab = init_optab (MINUS); + subv_optab = init_optab (MINUS); smul_optab = init_optab (MULT); + smulv_optab = init_optab (MULT); smul_highpart_optab = init_optab (UNKNOWN); umul_highpart_optab = init_optab (UNKNOWN); smul_widen_optab = init_optab (UNKNOWN); umul_widen_optab = init_optab (UNKNOWN); sdiv_optab = init_optab (DIV); + sdivv_optab = init_optab (DIV); sdivmod_optab = init_optab (UNKNOWN); udiv_optab = init_optab (UDIV); udivmod_optab = init_optab (UNKNOWN); @@ -4560,7 +4610,9 @@ init_optabs () ucmp_optab = init_optab (UNKNOWN); tst_optab = init_optab (UNKNOWN); neg_optab = init_optab (NEG); + negv_optab = init_optab (NEG); abs_optab = init_optab (ABS); + absv_optab = init_optab (ABS); one_cmpl_optab = init_optab (NOT); ffs_optab = init_optab (FFS); sqrt_optab = init_optab (SQRT); @@ -4595,11 +4647,18 @@ init_optabs () /* Initialize the optabs with the names of the library functions. */ init_integral_libfuncs (add_optab, "add", '3'); init_floating_libfuncs (add_optab, "add", '3'); + init_integral_libfuncs (addv_optab, "addv", '3'); + init_floating_libfuncs (addv_optab, "add", '3'); init_integral_libfuncs (sub_optab, "sub", '3'); init_floating_libfuncs (sub_optab, "sub", '3'); + init_integral_libfuncs (subv_optab, "subv", '3'); + init_floating_libfuncs (subv_optab, "sub", '3'); init_integral_libfuncs (smul_optab, "mul", '3'); init_floating_libfuncs (smul_optab, "mul", '3'); + init_integral_libfuncs (smulv_optab, "mulv", '3'); + init_floating_libfuncs (smulv_optab, "mul", '3'); init_integral_libfuncs (sdiv_optab, "div", '3'); + init_integral_libfuncs (sdivv_optab, "divv", '3'); init_integral_libfuncs (udiv_optab, "udiv", '3'); init_integral_libfuncs (sdivmod_optab, "divmod", '4'); init_integral_libfuncs (udivmod_optab, "udivmod", '4'); @@ -4621,6 +4680,8 @@ init_optabs () init_integral_libfuncs (umax_optab, "umax", '3'); init_integral_libfuncs (neg_optab, "neg", '2'); init_floating_libfuncs (neg_optab, "neg", '2'); + init_integral_libfuncs (negv_optab, "negv", '2'); + init_floating_libfuncs (negv_optab, "neg", '2'); init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2'); init_integral_libfuncs (ffs_optab, "ffs", '2'); diff --git a/gcc/toplev.c b/gcc/toplev.c index 66139638309..1dfa7f5cbf7 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -947,6 +947,8 @@ typedef struct } lang_independent_options; +int flag_trapv = 0; + /* Add or remove a leading underscore from user symbols. */ int flag_leading_underscore = -1; @@ -1145,6 +1147,8 @@ lang_independent_options f_options[] = "Report time taken by each compiler pass at end of run"}, {"mem-report", &mem_report, 1, "Report on permanent memory allocation at end of run"}, + { "trapv", &flag_trapv, 1, + "Trap for signed overflow in addition / subtraction / multiplication." }, }; /* Table of language-specific options. */ diff --git a/gcc/tree.h b/gcc/tree.h index 2ec1274b957..68ccbbf8dd3 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -574,6 +574,8 @@ extern void tree_class_check_failed PARAMS ((const tree, int, The same bit is used in functions as DECL_BUILT_IN_NONANSI. */ #define TREE_UNSIGNED(NODE) ((NODE)->common.unsigned_flag) +#define TYPE_TRAP_SIGNED(NODE) (flag_trapv && ! TREE_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