OSDN Git Service

* calls.c (expand_call): When copying unaligned values into a register,
[pf3gnuchains/gcc-fork.git] / gcc / expmed.c
index a593942..65fb007 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
 
@@ -409,13 +409,13 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
       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;
@@ -557,6 +557,9 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align)
   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.
@@ -1470,7 +1473,7 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
 #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
@@ -2474,7 +2477,7 @@ invert_mod2n (x, n)
      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.
@@ -3658,11 +3661,18 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
            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,
@@ -3909,7 +3919,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
 
   /* 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)
     {
@@ -3948,7 +3958,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
       && 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;
@@ -4142,7 +4152,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
        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
@@ -4260,8 +4270,45 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
 
   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;