- /* Add/subtract previous carry to main result. */
- newx = expand_binop (word_mode,
- normalizep == 1 ? binoptab : otheroptab,
- x, carry_in,
- NULL_RTX, 1, next_methods);
-
- if (i + 1 < nwords)
- {
- /* Get out carry from adding/subtracting carry in. */
- rtx carry_tmp = gen_reg_rtx (word_mode);
- carry_tmp = emit_store_flag_force (carry_tmp,
- (binoptab == add_optab
- ? LT : GT),
- newx, x,
- word_mode, 1, normalizep);
-
- /* Logical-ior the two poss. carry together. */
- carry_out = expand_binop (word_mode, ior_optab,
- carry_out, carry_tmp,
- carry_out, 0, next_methods);
- if (carry_out == 0)
- break;
- }
- emit_move_insn (target_piece, newx);
- }
-
- carry_in = carry_out;
- }
-
- if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
- {
- if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
- || ! rtx_equal_p (target, xtarget))
- {
- rtx temp = emit_move_insn (target, xtarget);
-
- set_unique_reg_note (temp,
- REG_EQUAL,
- gen_rtx_fmt_ee (binoptab->code, mode,
- copy_rtx (xop0),
- copy_rtx (xop1)));
- }
- else
- target = xtarget;
-
- return target;
- }
-
- else
- delete_insns_since (last);
- }
-
- /* If we want to multiply two two-word values and have normal and widening
- multiplies of single-word values, we can do this with three smaller
- multiplications. Note that we do not make a REG_NO_CONFLICT block here
- because we are not operating on one word at a time.
-
- The multiplication proceeds as follows:
- _______________________
- [__op0_high_|__op0_low__]
- _______________________
- * [__op1_high_|__op1_low__]
- _______________________________________________
- _______________________
- (1) [__op0_low__*__op1_low__]
- _______________________
- (2a) [__op0_low__*__op1_high_]
- _______________________
- (2b) [__op0_high_*__op1_low__]
- _______________________
- (3) [__op0_high_*__op1_high_]
-
-
- This gives a 4-word result. Since we are only interested in the
- lower 2 words, partial result (3) and the upper words of (2a) and
- (2b) don't need to be calculated. Hence (2a) and (2b) can be
- calculated using non-widening multiplication.
-
- (1), however, needs to be calculated with an unsigned widening
- multiplication. If this operation is not directly supported we
- try using a signed widening multiplication and adjust the result.
- This adjustment works as follows:
-
- If both operands are positive then no adjustment is needed.
-
- If the operands have different signs, for example op0_low < 0 and
- op1_low >= 0, the instruction treats the most significant bit of
- op0_low as a sign bit instead of a bit with significance
- 2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low
- with 2**BITS_PER_WORD - op0_low, and two's complements the
- result. Conclusion: We need to add op1_low * 2**BITS_PER_WORD to
- the result.
-
- Similarly, if both operands are negative, we need to add
- (op0_low + op1_low) * 2**BITS_PER_WORD.
-
- We use a trick to adjust quickly. We logically shift op0_low right
- (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to
- op0_high (op1_high) before it is used to calculate 2b (2a). If no
- logical shift exists, we do an arithmetic right shift and subtract
- the 0 or -1. */
-
- if (binoptab == smul_optab
- && class == MODE_INT
- && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
- && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
- && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
- && ((umul_widen_optab->handlers[(int) mode].insn_code
- != CODE_FOR_nothing)
- || (smul_widen_optab->handlers[(int) mode].insn_code
- != CODE_FOR_nothing)))
- {
- int low = (WORDS_BIG_ENDIAN ? 1 : 0);
- int high = (WORDS_BIG_ENDIAN ? 0 : 1);
- rtx op0_high = operand_subword_force (op0, high, mode);
- rtx op0_low = operand_subword_force (op0, low, mode);
- rtx op1_high = operand_subword_force (op1, high, mode);
- rtx op1_low = operand_subword_force (op1, low, mode);
- rtx product = 0;
- rtx op0_xhigh = NULL_RTX;
- rtx op1_xhigh = NULL_RTX;
-
- /* If the target is the same as one of the inputs, don't use it. This
- prevents problems with the REG_EQUAL note. */
- if (target == op0 || target == op1
- || (target != 0 && !REG_P (target)))
- target = 0;
-
- /* Multiply the two lower words to get a double-word product.
- If unsigned widening multiplication is available, use that;
- otherwise use the signed form and compensate. */
-
- if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
- {
- product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
- target, 1, OPTAB_DIRECT);
-
- /* If we didn't succeed, delete everything we did so far. */
- if (product == 0)
- delete_insns_since (last);
- else
- op0_xhigh = op0_high, op1_xhigh = op1_high;
- }
-
- if (product == 0
- && smul_widen_optab->handlers[(int) mode].insn_code
- != CODE_FOR_nothing)
- {
- rtx wordm1 = GEN_INT (BITS_PER_WORD - 1);
- product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
- target, 1, OPTAB_DIRECT);
- op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
- NULL_RTX, 1, next_methods);
- if (op0_xhigh)
- op0_xhigh = expand_binop (word_mode, add_optab, op0_high,
- op0_xhigh, op0_xhigh, 0, next_methods);
- else
- {
- op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
- NULL_RTX, 0, next_methods);
- if (op0_xhigh)
- op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,
- op0_xhigh, op0_xhigh, 0,
- next_methods);
- }
-
- op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
- NULL_RTX, 1, next_methods);
- if (op1_xhigh)
- op1_xhigh = expand_binop (word_mode, add_optab, op1_high,
- op1_xhigh, op1_xhigh, 0, next_methods);
- else
- {
- op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
- NULL_RTX, 0, next_methods);
- if (op1_xhigh)
- op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,
- op1_xhigh, op1_xhigh, 0,
- next_methods);
- }
- }
-
- /* If we have been able to directly compute the product of the
- low-order words of the operands and perform any required adjustments
- of the operands, we proceed by trying two more multiplications
- and then computing the appropriate sum.
-
- We have checked above that the required addition is provided.
- Full-word addition will normally always succeed, especially if
- it is provided at all, so we don't worry about its failure. The
- multiplication may well fail, however, so we do handle that. */
-
- if (product && op0_xhigh && op1_xhigh)
- {
- rtx product_high = operand_subword (product, high, 1, mode);
- rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
- NULL_RTX, 0, OPTAB_DIRECT);
-
- if (!REG_P (product_high))
- product_high = force_reg (word_mode, product_high);
-
- if (temp != 0)
- temp = expand_binop (word_mode, add_optab, temp, product_high,
- product_high, 0, next_methods);
-
- if (temp != 0 && temp != product_high)
- emit_move_insn (product_high, temp);
-
- if (temp != 0)
- temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
- NULL_RTX, 0, OPTAB_DIRECT);
-
- if (temp != 0)
- temp = expand_binop (word_mode, add_optab, temp,
- product_high, product_high,
- 0, next_methods);
-
- if (temp != 0 && temp != product_high)
- emit_move_insn (product_high, temp);
-
- emit_move_insn (operand_subword (product, high, 1, mode), product_high);
-
- if (temp != 0)
- {
- if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
- {
- temp = emit_move_insn (product, product);
- set_unique_reg_note (temp,
- REG_EQUAL,
- gen_rtx_fmt_ee (MULT, mode,
- copy_rtx (op0),
- copy_rtx (op1)));
- }
-
- return product;
- }
- }
-
- /* If we get here, we couldn't do it for some reason even though we
- originally thought we could. Delete anything we've emitted in
- trying to do it. */
-
- delete_insns_since (last);
- }
-
- /* Open-code the vector operations if we have no hardware support
- for them. */
- if (class == MODE_VECTOR_INT || class == MODE_VECTOR_FLOAT)
- return expand_vector_binop (mode, binoptab, op0, op1, target,
- unsignedp, methods);
-
- /* We need to open-code the complex type operations: '+, -, * and /' */
-
- /* At this point we allow operations between two similar complex
- numbers, and also if one of the operands is not a complex number
- but rather of MODE_FLOAT or MODE_INT. However, the caller
- must make sure that the MODE of the non-complex operand matches
- the SUBMODE of the complex operand. */
-
- if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
- {
- rtx real0 = 0, imag0 = 0;
- rtx real1 = 0, imag1 = 0;
- rtx realr, imagr, res;
- rtx seq, result;
- int ok = 0;
-
- /* Find the correct mode for the real and imaginary parts. */
- enum machine_mode submode = GET_MODE_INNER (mode);
-
- if (submode == BLKmode)
- abort ();
-
- start_sequence ();
-
- if (GET_MODE (op0) == mode)
- {
- real0 = gen_realpart (submode, op0);
- imag0 = gen_imagpart (submode, op0);
- }
- else
- real0 = op0;
-
- if (GET_MODE (op1) == mode)
- {
- real1 = gen_realpart (submode, op1);
- imag1 = gen_imagpart (submode, op1);
- }
- else
- real1 = op1;
-
- if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0))
- abort ();
-
- result = gen_reg_rtx (mode);
- realr = gen_realpart (submode, result);
- imagr = gen_imagpart (submode, result);
-
- switch (binoptab->code)
- {
- case PLUS:
- /* (a+ib) + (c+id) = (a+c) + i(b+d) */
- case MINUS:
- /* (a+ib) - (c+id) = (a-c) + i(b-d) */
- res = expand_binop (submode, binoptab, real0, real1,
- realr, unsignedp, methods);
-
- if (res == 0)
- break;
- else if (res != realr)
- emit_move_insn (realr, res);
-
- if (imag0 != 0 && imag1 != 0)
- res = expand_binop (submode, binoptab, imag0, imag1,
- imagr, unsignedp, methods);
- else if (imag0 != 0)
- res = imag0;
- else if (binoptab->code == MINUS)
- res = expand_unop (submode,
- binoptab == subv_optab ? negv_optab : neg_optab,
- imag1, imagr, unsignedp);
- else
- res = imag1;
-
- if (res == 0)
- break;
- else if (res != imagr)
- emit_move_insn (imagr, res);
-
- ok = 1;
- break;
-
- case MULT:
- /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
-
- if (imag0 != 0 && imag1 != 0)
- {
- rtx temp1, temp2;
-
- /* Don't fetch these from memory more than once. */
- real0 = force_reg (submode, real0);
- real1 = force_reg (submode, real1);
- imag0 = force_reg (submode, imag0);
- imag1 = force_reg (submode, imag1);
-
- temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX,
- unsignedp, methods);
-
- temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX,
- unsignedp, methods);
-
- if (temp1 == 0 || temp2 == 0)
- break;
-
- res = (expand_binop
- (submode,
- binoptab == smulv_optab ? subv_optab : sub_optab,
- temp1, temp2, realr, unsignedp, methods));
-
- if (res == 0)
- break;
- else if (res != realr)
- emit_move_insn (realr, res);
-
- temp1 = expand_binop (submode, binoptab, real0, imag1,
- NULL_RTX, unsignedp, methods);
-
- /* Avoid expanding redundant multiplication for the common
- case of squaring a complex number. */
- if (rtx_equal_p (real0, real1) && rtx_equal_p (imag0, imag1))
- temp2 = temp1;
- else
- temp2 = expand_binop (submode, binoptab, real1, imag0,
- NULL_RTX, unsignedp, methods);
-
- if (temp1 == 0 || temp2 == 0)
- break;
-
- res = (expand_binop
- (submode,
- binoptab == smulv_optab ? addv_optab : add_optab,
- temp1, temp2, imagr, unsignedp, methods));