OSDN Git Service

* i386.md (ashlsi patterns): Call output_ashl instead of output_ashlsi3.
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index e6f807b..50acbb1 100644 (file)
@@ -4179,6 +4179,66 @@ output_fix_trunc (insn, operands)
   return AS1 (fldc%W2,%2);
 }
 \f
+/* Output code for INSN to extend a float.  OPERANDS are the insn
+   operands.  The output may be DFmode or XFmode and the input operand
+   may be SFmode or DFmode.  Operands 2 and 3 are scratch memory and
+   are only necessary if operands 0 or 1 are non-stack registers.  */
+
+void
+output_float_extend (insn, operands)
+     rtx insn;
+     rtx *operands;
+{
+  int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
+  rtx xops[2];
+
+  if (! STACK_TOP_P (operands[0]) && ! STACK_TOP_P (operands[1]))
+    abort ();
+
+  if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]) && stack_top_dies)
+    return;
+
+  if (STACK_TOP_P (operands[0]) )
+    {
+      if (NON_STACK_REG_P (operands[1]))
+       {
+         if (GET_MODE (operands[1]) == SFmode)
+           output_asm_insn (AS2 (mov%L0,%1,%2), operands);
+         else
+           {
+             xops[0] = operands[2];
+             xops[1] = operands[1];
+             output_asm_insn (output_move_double (xops), xops);
+           }
+       }
+
+      xops[0] = NON_STACK_REG_P (operands[1]) ? operands[2] : operands[1];
+
+      output_asm_insn (AS1 (fld%z0,%y0), xops);
+    }
+  else
+    {
+      xops[0] = NON_STACK_REG_P (operands[0]) ? operands[3] : operands[0];
+
+      if (stack_top_dies
+         || (GET_CODE (xops[0]) == MEM && GET_MODE (xops[0]) == XFmode))
+       {
+         output_asm_insn (AS1 (fstp%z0,%y0), xops);
+         if (! stack_top_dies)
+           output_asm_insn (AS1 (fld%z0,%y0), xops);
+       }
+      else
+       output_asm_insn (AS1 (fst%z0,%y0), xops);
+
+      if (NON_STACK_REG_P (operands[0]))
+       {
+         xops[0] = operands[0];
+         xops[1] = operands[3];
+         output_asm_insn (output_move_double (xops), xops);
+       }
+    }
+}
+\f
 /* Output code for INSN to compare OPERANDS.  The two operands might
    not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
    expression.  If the compare is in mode CCFPEQmode, use an opcode that
@@ -5424,7 +5484,7 @@ x86_adjust_cost (insn, link, dep_insn, cost)
        return 0;
 
       if (agi_dependent (insn, dep_insn))
-       return 3;
+       return cost ? cost + 1 : 2;
 
       if (GET_CODE (insn) == INSN
          && GET_CODE (PATTERN (insn)) == SET
@@ -5435,6 +5495,10 @@ x86_adjust_cost (insn, link, dep_insn, cost)
        return 0;
       break;
 
+      /* Stores stalls one cycle longer than other insns.  */
+      if (is_fp_insn (insn) && cost && is_fp_store (dep_insn))
+       cost++;
+
     case PROCESSOR_K6:
     default:
       if (!is_fp_dest (dep_insn))
@@ -5479,34 +5543,50 @@ x86_adjust_cost (insn, link, dep_insn, cost)
      TARGET_DOUBLE_WITH_ADD.  */
 
 char *
-output_ashlsi3 (operands)
-     rtx *operands;
+output_ashl (insn, operands)
+     rtx insn, *operands;
 {
   /* Handle case where srcreg != dstreg.  */
   if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
     {
       if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1)
-       {
-         output_asm_insn (AS2 (mov%L0,%1,%0), operands);
-         return AS2 (add%L0,%1,%0);
-       }
+       switch (GET_MODE (operands[0]))
+         {
+         case SImode:
+           output_asm_insn (AS2 (mov%L0,%1,%0), operands);
+           return AS2 (add%L0,%1,%0);
+         case HImode:
+           output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
+           if (i386_cc_probably_useless_p (insn))
+             {
+               CC_STATUS_INIT;
+               return AS2 (add%L0,%k1,%k0);
+             }
+           return AS2 (add%W0,%k1,%k0);
+         case QImode:
+           output_asm_insn (AS2 (mov%B0,%1,%0), operands);
+           return AS2 (add%B0,%1,%0);
+         default:
+           abort ();
+         }
       else
-        {
-          CC_STATUS_INIT;
+       {
+         CC_STATUS_INIT;
 
          /* This should be extremely rare (impossible?).  We can not encode a
             shift of the stack pointer using an lea instruction.  So copy the
             stack pointer into the destination register and use an lea.  */
          if (operands[1] == stack_pointer_rtx)
            {
-             output_asm_insn (AS2 (mov%L0,%1,%0), operands);
+             output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
              operands[1] = operands[0];
            }
 
          /* For shifts up to and including 3 bits, use lea.  */
-          operands[1] = gen_rtx_MULT (SImode, operands[1],
+         operands[1] = gen_rtx_MULT (SImode,
+                                     gen_rtx_REG (SImode, REGNO (operands[1])),
                                      GEN_INT (1 << INTVAL (operands[2])));
-         return AS2 (lea%L0,%a1,%0);
+         return AS2 (lea%L0,%a1,%k0);
        }
     }
 
@@ -5514,17 +5594,47 @@ output_ashlsi3 (operands)
 
   /* Handle variable shift.  */
   if (REG_P (operands[2]))
-    return AS2 (sal%L0,%b2,%0);
+    switch (GET_MODE (operands[0]))
+      {
+      case SImode:
+       return AS2 (sal%L0,%b2,%0);
+      case HImode:
+       if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+         {
+           CC_STATUS_INIT;
+           return AS2 (sal%L0,%b2,%k0);
+         }
+       else
+         return AS2 (sal%W0,%b2,%0);
+      case QImode:
+       return AS2 (sal%B0,%b2,%0);
+      default:
+       abort ();
+      }
 
   /* Always perform shift by 1 using an add instruction.  */
   if (REG_P (operands[0]) && operands[2] == const1_rtx)
-    return AS2 (add%L0,%0,%0);
+    switch (GET_MODE (operands[0]))
+      {
+      case SImode:
+       return AS2 (add%L0,%0,%0);
+      case HImode:
+       if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+         {
+           CC_STATUS_INIT;
+           return AS2 (add%L0,%k0,%k0);
+         }
+       else
+         return AS2 (add%W0,%0,%0);
+      case QImode:
+         return AS2 (add%B0,%0,%0);
+      default:
+         abort ();
+      }
 
 #if 0
-  /* ??? Currently disabled.  reg-stack currently stomps on the mode of
-     each insn.  Thus, we can not easily detect when we should use lea to
-     improve issue characteristics.  Until reg-stack is fixed, fall back to
-     sal instruction for Pentiums to avoid AGI stall.  */
+  /* ??? Currently disabled.  Because our model of Pentium is far from being
+     exact, this change will need some benchmarking.  */
   /* Shift reg by 2 or 3 use an lea instruction for Pentium if this is
      insn is expected to issue into the V pipe (the insn's mode will be
      TImode for a U pipe, and !TImode for a V pipe instruction).  */
@@ -5536,12 +5646,155 @@ output_ashlsi3 (operands)
       && GET_MODE (insn) != TImode)
     {
       CC_STATUS_INIT;
-      operands[1] = gen_rtx_MULT (SImode, operands[1],
+      operands[1] = gen_rtx_MULT (SImode, gen_rtx_REG (SImode, REGNO (operands[1])),
                                  GEN_INT (1 << INTVAL (operands[2])));
       return AS2 (lea%L0,%a1,%0);
     }
 #endif
 
   /* Otherwise use a shift instruction.  */
-  return AS2 (sal%L0,%2,%0);
+  switch (GET_MODE (operands[0]))
+    {
+    case SImode:
+      return AS2 (sal%L0,%2,%0);
+    case HImode:
+      if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+       {
+         CC_STATUS_INIT;
+         return AS2 (sal%L0,%2,%k0);
+       }
+      else
+       return AS2 (sal%W0,%2,%0);
+    case QImode:
+      return AS2 (sal%B0,%2,%0);
+    default:
+      abort ();
+    }
+}
+
+/* Given the memory address ADDR, calculate the length of the address or
+   the length of just the displacement (controlled by DISP_LENGTH).
+  
+   The length returned does not include the one-byte modrm, opcode,
+   or prefix.  */
+
+int
+memory_address_info (addr, disp_length)
+     rtx addr;
+     int disp_length;
+{
+  rtx base, index, disp, scale;
+  rtx op0, op1;
+  int len;
+
+  if (GET_CODE (addr) == PRE_DEC
+      || GET_CODE (addr) == POST_INC)
+    return 0;
+
+  /* Register Indirect.  */
+  if (register_operand (addr, Pmode))
+    {
+      /* Special cases: ebp and esp need the two-byte modrm form. 
+
+        We change [ESI] to [ESI+0] on the K6 when not optimizing
+        for size.  */
+      if (addr == stack_pointer_rtx
+         || addr == arg_pointer_rtx
+         || addr == frame_pointer_rtx
+         || (REGNO_REG_CLASS (REGNO (addr)) == SIREG
+             && ix86_cpu == PROCESSOR_K6 && !optimize_size))
+       return 1;
+      else
+       return 0;
+    }
+
+  /* Direct Addressing.  */
+  if (CONSTANT_P (addr))
+    return 4;
+
+  index = base = disp = scale = NULL_RTX;
+  op0 = XEXP (addr, 0);
+  op1 = XEXP (addr, 1);
+
+  if (GET_CODE (addr) == PLUS)
+    {
+      if (register_operand (op0, Pmode))
+       {
+         if (register_operand (op1, Pmode))
+           index = op0, base = op1;
+         else
+           base = op0, disp = op1;
+       }
+      else if (GET_CODE (op0) == MULT)
+       {
+         index = XEXP (op0, 0);
+         scale = XEXP (op0, 1);
+         if (register_operand (op1, Pmode))
+           base = op1;
+         else
+           disp = op1;
+       }
+      else if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
+       {
+         index = XEXP (XEXP (op0, 0), 0);
+         scale = XEXP (XEXP (op0, 0), 1);
+         base = XEXP (op0, 1);
+         disp = op1;
+       }
+      else if (GET_CODE (op0) == PLUS)
+       {
+         index = XEXP (op0, 0);
+         base = XEXP (op0, 1);
+         disp = op1;
+       }
+      else
+       abort ();
+    }
+  else if (GET_CODE (addr) == MULT
+          /* We're called for lea too, which implements ashift on occasion.  */
+          || GET_CODE (addr) == ASHIFT)
+    {
+      index = XEXP (addr, 0);
+      scale = XEXP (addr, 1);
+    }
+  else
+    abort ();
+      
+  /* Allow arg pointer and stack pointer as index if there is not scaling */
+  if (base && index && !scale
+      && (index == stack_pointer_rtx
+         || index == arg_pointer_rtx
+         || index == frame_pointer_rtx))
+    {
+      rtx tmp = base;
+      base = index;
+      index = tmp;
+    }
+
+  /* Special case: ebp cannot be encoded as a base without a displacement.  */
+  if (base == frame_pointer_rtx && !disp)
+    disp = const0_rtx;
+
+  /* Scaling can not be encoded without base or displacement.  
+     Except for scale == 1 where we can encode reg + reg instead of reg * 2.  */
+  if (!base && index && scale != 1)
+    disp = const0_rtx;
+
+  /* Find the length of the displacement constant.  */
+  len = 0;
+  if (disp)
+    {
+      if (GET_CODE (disp) == CONST_INT
+         && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K'))
+       len = 1;
+      else
+       len = 4;
+    }
+
+  /* An index requires the two-byte modrm form.  Not important
+     if we are computing just length of the displacement.  */
+  if (index && ! disp_length)
+    len += 1;
+
+  return len;
 }