diff options
Diffstat (limited to 'gcc/optabs.c')
-rw-r--r-- | gcc/optabs.c | 167 |
1 files changed, 114 insertions, 53 deletions
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'); |