+ MODE is the mode of operation and result.
+
+ UNSIGNEDP nonzero means unsigned multiply.
+
+ MAX_COST is the total allowed cost for the expanded RTL. */
+
+static rtx
+expand_mult_highpart (enum machine_mode mode, rtx op0, rtx op1,
+ rtx target, int unsignedp, int max_cost)
+{
+ enum machine_mode wider_mode = GET_MODE_WIDER_MODE (mode);
+ unsigned HOST_WIDE_INT cnst1;
+ int extra_cost;
+ bool sign_adjust = false;
+ enum mult_variant variant;
+ struct algorithm alg;
+ rtx tem;
+ bool speed = optimize_insn_for_speed_p ();
+
+ gcc_assert (!SCALAR_FLOAT_MODE_P (mode));
+ /* We can't support modes wider than HOST_BITS_PER_INT. */
+ gcc_assert (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT);
+
+ cnst1 = INTVAL (op1) & GET_MODE_MASK (mode);
+
+ /* We can't optimize modes wider than BITS_PER_WORD.
+ ??? We might be able to perform double-word arithmetic if
+ mode == word_mode, however all the cost calculations in
+ synth_mult etc. assume single-word operations. */
+ if (GET_MODE_BITSIZE (wider_mode) > BITS_PER_WORD)
+ return expand_mult_highpart_optab (mode, op0, op1, target,
+ unsignedp, max_cost);
+
+ extra_cost = shift_cost[speed][mode][GET_MODE_BITSIZE (mode) - 1];
+
+ /* Check whether we try to multiply by a negative constant. */
+ if (!unsignedp && ((cnst1 >> (GET_MODE_BITSIZE (mode) - 1)) & 1))
+ {
+ sign_adjust = true;
+ extra_cost += add_cost[speed][mode];
+ }
+
+ /* See whether shift/add multiplication is cheap enough. */
+ if (choose_mult_variant (wider_mode, cnst1, &alg, &variant,
+ max_cost - extra_cost))
+ {
+ /* See whether the specialized multiplication optabs are
+ cheaper than the shift/add version. */
+ tem = expand_mult_highpart_optab (mode, op0, op1, target, unsignedp,
+ alg.cost.cost + extra_cost);
+ if (tem)
+ return tem;
+
+ tem = convert_to_mode (wider_mode, op0, unsignedp);
+ tem = expand_mult_const (wider_mode, tem, cnst1, 0, &alg, variant);
+ tem = extract_high_half (mode, tem);
+
+ /* Adjust result for signedness. */
+ if (sign_adjust)
+ tem = force_operand (gen_rtx_MINUS (mode, tem, op0), tem);
+
+ return tem;
+ }
+ return expand_mult_highpart_optab (mode, op0, op1, target,
+ unsignedp, max_cost);
+}
+
+
+/* Expand signed modulus of OP0 by a power of two D in mode MODE. */
+
+static rtx
+expand_smod_pow2 (enum machine_mode mode, rtx op0, HOST_WIDE_INT d)
+{
+ unsigned HOST_WIDE_INT masklow, maskhigh;
+ rtx result, temp, shift, label;
+ int logd;
+
+ logd = floor_log2 (d);
+ result = gen_reg_rtx (mode);
+
+ /* Avoid conditional branches when they're expensive. */
+ if (BRANCH_COST (optimize_insn_for_speed_p (), false) >= 2
+ && optimize_insn_for_speed_p ())
+ {
+ rtx signmask = emit_store_flag (result, LT, op0, const0_rtx,
+ mode, 0, -1);
+ if (signmask)
+ {
+ signmask = force_reg (mode, signmask);
+ masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
+ shift = GEN_INT (GET_MODE_BITSIZE (mode) - logd);
+
+ /* Use the rtx_cost of a LSHIFTRT instruction to determine
+ which instruction sequence to use. If logical right shifts
+ are expensive the use 2 XORs, 2 SUBs and an AND, otherwise
+ use a LSHIFTRT, 1 ADD, 1 SUB and an AND. */
+
+ temp = gen_rtx_LSHIFTRT (mode, result, shift);
+ if (optab_handler (lshr_optab, mode)->insn_code == CODE_FOR_nothing
+ || rtx_cost (temp, SET, optimize_insn_for_speed_p ()) > COSTS_N_INSNS (2))
+ {
+ temp = expand_binop (mode, xor_optab, op0, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, sub_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, xor_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, sub_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ }
+ else
+ {
+ signmask = expand_binop (mode, lshr_optab, signmask, shift,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ signmask = force_reg (mode, signmask);
+
+ temp = expand_binop (mode, add_optab, op0, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, and_optab, temp, GEN_INT (masklow),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ temp = expand_binop (mode, sub_optab, temp, signmask,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ }
+ return temp;
+ }
+ }
+
+ /* Mask contains the mode's signbit and the significant bits of the
+ modulus. By including the signbit in the operation, many targets
+ can avoid an explicit compare operation in the following comparison
+ against zero. */
+
+ masklow = ((HOST_WIDE_INT) 1 << logd) - 1;
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)