/* Medium-level subroutines: convert bit-field store and extract
and shifts, multiplies and divides to rtl instructions.
- Copyright (C) 1987, 88, 89, 92-5, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-6, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
int save_volatile_ok = volatile_ok;
volatile_ok = 1;
- /* If this machine's insv can only insert into a register, or if we
- are to force MEMs into a register, copy OP0 into a register and
- save it back later. */
+ /* If this machine's insv can only insert into a register, copy OP0
+ into a register and save it back later. */
+ /* This used to check flag_force_mem, but that was a serious
+ de-optimization now that flag_force_mem is enabled by -O2. */
if (GET_CODE (op0) == MEM
- && (flag_force_mem
- || ! ((*insn_operand_predicate[(int) CODE_FOR_insv][0])
- (op0, VOIDmode))))
+ && ! ((*insn_operand_predicate[(int) CODE_FOR_insv][0])
+ (op0, VOIDmode)))
{
rtx tempreg;
enum machine_mode bestmode;
int all_zero = 0;
int all_one = 0;
+ if (! SLOW_UNALIGNED_ACCESS)
+ struct_align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+
/* There is a case not handled here:
a structure with a known alignment of just a halfword
and a field split across two aligned halfwords within the structure.
#ifdef SLOW_ZERO_EXTEND
/* Always generate an `and' if
we just zero-extended op0 and SLOW_ZERO_EXTEND, since it
- will combine fruitfully with the zero-extend. */
+ will combine fruitfully with the zero-extend. */
|| tmode != mode
#endif
#endif
unsigned HOST_WIDE_INT x;
int n;
{
- /* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */
+ /* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */
/* The algorithm notes that the choice y = x satisfies
x*y == 1 mod 2^3, since x is assumed odd.
return gen_lowpart (mode, remainder);
}
- /* Produce the quotient. */
- /* Try a quotient insn, but not a library call. */
- quotient = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
- op0, op1, rem_flag ? NULL_RTX : target,
- unsignedp, OPTAB_WIDEN);
+ /* Produce the quotient. Try a quotient insn, but not a library call.
+ If we have a divmod in this mode, use it in preference to widening
+ the div (for this test we assume it will not fail). Note that optab2
+ is set to the one of the two optabs that the call below will use. */
+ quotient
+ = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
+ op0, op1, rem_flag ? NULL_RTX : target,
+ unsignedp,
+ ((optab2->handlers[(int) compute_mode].insn_code
+ != CODE_FOR_nothing)
+ ? OPTAB_DIRECT : OPTAB_WIDEN));
+
if (quotient == 0)
{
/* No luck there. Try a quotient-and-remainder insn,
/* For some comparisons with 1 and -1, we can convert this to
comparisons with zero. This will often produce more opportunities for
- store-flag insns. */
+ store-flag insns. */
switch (code)
{
&& GET_MODE_CLASS (mode) == MODE_INT
&& (normalizep || STORE_FLAG_VALUE == 1
|| (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))))
{
subtarget = target;
normalizep = STORE_FLAG_VALUE;
else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))
;
else
return tem;
}
- emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
+
+/* Like emit_store_flag, but always succeeds. */
+
+rtx
+emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
+ rtx target;
+ enum rtx_code code;
+ rtx op0, op1;
+ enum machine_mode mode;
+ int unsignedp;
+ int normalizep;
+{
+ rtx tem, label;
+
+ /* First see if emit_store_flag can do the job. */
+ tem = emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep);
+ if (tem != 0)
+ return tem;
+
+ if (normalizep == 0)
+ normalizep = 1;
+
+ /* If this failed, we have to do this with set/compare/jump/set code. */
+
+ if (GET_CODE (target) != REG
+ || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
+ target = gen_reg_rtx (GET_MODE (target));
+
emit_move_insn (target, const1_rtx);
+ tem = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX, 0);
+ if (GET_CODE (tem) == CONST_INT)
+ return tem;
+
+ label = gen_label_rtx ();
+ if (bcc_gen_fctn[(int) code] == 0)
+ abort ();
+
+ emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
+ emit_move_insn (target, const0_rtx);
emit_label (label);
return target;