Respin DI support to be combine friendly; Allow push of SF without temp reg; Fix...
authorMichael Meissner <meissner@gcc.gnu.org>
Tue, 20 Sep 1994 18:36:51 +0000 (18:36 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Tue, 20 Sep 1994 18:36:51 +0000 (18:36 +0000)
From-SVN: r8098

gcc/config/i386/i386.c
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/objc/sendmsg.c

index 0e9d4b3..5a9e882 100644 (file)
@@ -378,6 +378,7 @@ find_addr_reg (addr)
   abort ();
 }
 
+\f
 /* Output an insn to add the constant N to the register X.  */
 
 static void
@@ -404,6 +405,7 @@ asm_add (n, x)
     }
 }
 
+\f
 /* Output assembler code to perform a doubleword move insn
    with operands OPERANDS.  */
 
@@ -735,6 +737,199 @@ compadr:
 
   return "";
 }
+
+\f
+#define MAX_TMPS 2             /* max temporary registers used */
+
+/* Output the appropriate code to move push memory on the stack */
+
+char *
+output_move_pushmem (operands, insn, length, tmp_start, n_operands)
+     rtx operands[];
+     rtx insn;
+     int length;
+     int tmp_start;
+     int n_operands;
+{
+
+  struct {
+    char *load;
+    char *push;
+    rtx   xops[2];
+  } tmp_info[MAX_TMPS];
+
+  rtx src = operands[1];
+  int max_tmps = 0;
+  int offset = 0;
+  int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);
+  int stack_offset = 0;
+  int i, num_tmps;
+  rtx xops[1];
+
+  if (!offsettable_memref_p (src))
+    fatal_insn ("Source is not offsettable", insn);
+
+  if ((length & 3) != 0)
+    fatal_insn ("Pushing non-word aligned size", insn);
+
+  /* Figure out which temporary registers we have available */
+  for (i = tmp_start; i < n_operands; i++)
+    {
+      if (GET_CODE (operands[i]) == REG)
+       {
+         if (reg_overlap_mentioned_p (operands[i], src))
+           continue;
+
+         tmp_info[ max_tmps++ ].xops[1] = operands[i];
+         if (max_tmps == MAX_TMPS)
+           break;
+       }
+    }
+
+  if (max_tmps == 0)
+    for (offset = length - 4; offset >= 0; offset -= 4)
+      {
+       xops[0] = adj_offsettable_operand (src, offset + stack_offset);
+       output_asm_insn (AS1(push%L0,%0), xops);
+       if (stack_p)
+         stack_offset += 4;
+      }
+
+  else
+    for (offset = length - 4; offset >= 0; )
+      {
+       for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)
+         {
+           tmp_info[num_tmps].load    = AS2(mov%L0,%0,%1);
+           tmp_info[num_tmps].push    = AS1(push%L0,%1);
+           tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset);
+           offset -= 4;
+         }
+
+       for (i = 0; i < num_tmps; i++)
+         output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
+
+       for (i = 0; i < num_tmps; i++)
+         output_asm_insn (tmp_info[i].push, tmp_info[i].xops);
+
+       if (stack_p)
+         stack_offset += 4*num_tmps;
+      }
+
+  return "";
+}
+
+\f
+
+/* Output the appropriate code to move data between two memory locations */
+
+char *
+output_move_memory (operands, insn, length, tmp_start, n_operands)
+     rtx operands[];
+     rtx insn;
+     int length;
+     int tmp_start;
+     int n_operands;
+{
+  struct {
+    char *load;
+    char *store;
+    rtx   xops[3];
+  } tmp_info[MAX_TMPS];
+
+  rtx dest = operands[0];
+  rtx src  = operands[1];
+  rtx qi_tmp = NULL_RTX;
+  int max_tmps = 0;
+  int offset = 0;
+  int i, num_tmps;
+  rtx xops[3];
+
+  if (GET_CODE (dest) == MEM
+      && GET_CODE (XEXP (dest, 0)) == PRE_INC
+      && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
+    return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
+
+  if (!offsettable_memref_p (src))
+    fatal_insn ("Source is not offsettable", insn);
+
+  if (!offsettable_memref_p (dest))
+    fatal_insn ("Destination is not offsettable", insn);
+
+  /* Figure out which temporary registers we have available */
+  for (i = tmp_start; i < n_operands; i++)
+    {
+      if (GET_CODE (operands[i]) == REG)
+       {
+         if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i]))
+           qi_tmp = operands[i];
+
+         if (reg_overlap_mentioned_p (operands[i], dest))
+           fatal_insn ("Temporary register overlaps the destination", insn);
+
+         if (reg_overlap_mentioned_p (operands[i], src))
+           fatal_insn ("Temporary register overlaps the source", insn);
+
+         tmp_info[ max_tmps++ ].xops[2] = operands[i];
+         if (max_tmps == MAX_TMPS)
+           break;
+       }
+    }
+
+  if (max_tmps == 0)
+    fatal_insn ("No scratch registers were found to do memory->memory moves", insn);
+
+  if ((length & 1) != 0)
+    {
+      if (!qi_tmp)
+       fatal_insn ("No byte register found when moving odd # of bytes.", insn);
+    }
+
+  while (length > 1)
+    {
+      for (num_tmps = 0; num_tmps < max_tmps; num_tmps++)
+       {
+         if (length >= 4)
+           {
+             tmp_info[num_tmps].load    = AS2(mov%L0,%1,%2);
+             tmp_info[num_tmps].store   = AS2(mov%L0,%2,%0);
+             tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
+             tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+             offset += 4;
+             length -= 4;
+           }
+         else if (length >= 2)
+           {
+             tmp_info[num_tmps].load    = AS2(mov%W0,%1,%2);
+             tmp_info[num_tmps].store   = AS2(mov%W0,%2,%0);
+             tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
+             tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+             offset += 2;
+             length -= 2;
+           }
+         else
+           break;
+       }
+
+      for (i = 0; i < num_tmps; i++)
+       output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
+
+      for (i = 0; i < num_tmps; i++)
+       output_asm_insn (tmp_info[i].store, tmp_info[i].xops);
+    }
+
+  if (length == 1)
+    {
+      xops[0] = adj_offsettable_operand (dest, offset);
+      xops[1] = adj_offsettable_operand (src, offset);
+      xops[2] = qi_tmp;
+      output_asm_insn (AS2(mov%B0,%1,%2), xops);
+      output_asm_insn (AS2(mov%B0,%2,%0), xops);
+    }
+
+  return "";
+}
+
 \f
 int
 standard_80387_constant_p (x)
index c68b32d..562f0bd 100644 (file)
@@ -1704,6 +1704,8 @@ extern void output_op_from_reg ();
 extern void output_to_reg ();
 extern char *singlemove_string ();
 extern char *output_move_double ();
+extern char *output_move_memory ();
+extern char *output_move_pushmem ();
 extern int standard_80387_constant_p ();
 extern char *output_move_const_single ();
 extern int symbolic_operand ();
index 330002b..0c1c31c 100644 (file)
     /* Fastest way to change a 0 to a 1.  */
     return AS1 (inc%L0,%0);
 
+  if (flag_pic
+      && GET_CODE (operands[1]) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (operands[1]))
+    return AS2 (lea%L0,%a1,%0);
+
   return AS2 (mov%L0,%1,%0);
 }")
 
 }")
 
 (define_insn "movsf_push"
-  [(set (match_operand:SF 0 "push_operand" "=<,<,<")
-       (match_operand:SF 1 "general_operand" "rF,f,m"))
-   (clobber (match_scratch:SI 2 "=X,X,r"))]
+  [(set (match_operand:SF 0 "push_operand" "=<,<,<,<")
+       (match_operand:SF 1 "general_operand" "rF,f,m,m"))
+   (clobber (match_scratch:SI 2 "=X,X,r,X"))]
   ""
   "*
 {
       RET;
     }
 
-  else if (GET_CODE (operands[1]) != MEM)
+  else if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != REG)
     return AS1 (push%L1,%1);
 
   else
       RET;
     }
 
-  else if (GET_CODE (operands[1]) != MEM
-          || GET_CODE (operands[2]) != REG)
+  else if (GET_CODE (operands[1]) != MEM)
     return output_move_double (operands);
 
   else
-    {
-      rtx low[1], high[1], xop[4];
-
-      split_di (&operands[1], 1, low, high);
-      xop[0] = operands[2];
-      xop[1] = operands[3];
-      xop[2] = high[0];
-      xop[3] = low[0];
-
-      if (GET_CODE (operands[3]) == REG)
-       {                       /* 2 scratch registers available */
-         output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-         output_asm_insn (AS2 (mov%L0,%3,%1), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-         output_asm_insn (AS1 (push%L0,%1), xop);
-       }
-      else
-       {                       /* 1 scratch register */
-         output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-
-                               /* account for push above */
-         if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[3], 0)))
-           xop[3] = adj_offsettable_operand (xop[3], 4);
-
-         output_asm_insn (AS2 (mov%L0,%3,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-       }
-
-      RET;
-    }
+    return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);
 }")
 
 (define_insn "movdf_mem"
    (clobber (match_scratch:SI 2 "=&r,&r"))
    (clobber (match_scratch:SI 3 "=&r,X"))]
   ""
-  "*
-{
-  rtx low[2], high[2], xop[6];
-
-  split_di (operands, 2, low, high);
-  xop[0] = operands[2];
-  xop[1] = operands[3];
-  xop[2] = high[0];
-  xop[3] = high[1];
-  xop[4] = low[0];
-  xop[5] = low[1];
-  if (GET_CODE (operands[3]) == REG)
-    {                          /* 2 scratch registers available */
-      output_asm_insn (AS2 (mov%L0,%5,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%3,%1), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%4), xop);
-      output_asm_insn (AS2 (mov%L0,%1,%2), xop);
-    }
-  else
-    {                          /* 1 scratch register */
-      output_asm_insn (AS2 (mov%L0,%5,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%4), xop);
-      output_asm_insn (AS2 (mov%L0,%3,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%2), xop);
-    }
-
-  RET;
-}")
+  "* return output_move_memory (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);")
 
 ;; For the purposes of regclass, prefer FLOAT_REGS.
 (define_insn "movdf_normal"
     return output_move_double (operands);
 
   else
-    {
-      rtx xop[5];
-
-      xop[0] = operands[2];
-      xop[1] = operands[3];
-      xop[2] = adj_offsettable_operand (operands[1], 8);
-      xop[3] = adj_offsettable_operand (operands[1], 4);
-      xop[4] = operands[1];
-
-      if (GET_CODE (operands[3]) == REG)
-       {                       /* 2 scratch registers available */
-         output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-         output_asm_insn (AS2 (mov%L0,%3,%1), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-         output_asm_insn (AS1 (push%L0,%1), xop);
-
-                               /* account for 2 pushes above */
-         if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[4], 0)))
-           xop[4] = adj_offsettable_operand (xop[4], 8);
-
-         output_asm_insn (AS2 (mov%L0,%4,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-       }
-      else
-       {                       /* 1 scratch register */
-         output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-
-                               /* account for 1 push above */
-         if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[3], 0)))
-           xop[3] = adj_offsettable_operand (xop[3], 4);
-
-         output_asm_insn (AS2 (mov%L0,%3,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-
-                               /* account for 2 pushes above */
-         if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[4], 0)))
-           xop[4] = adj_offsettable_operand (xop[4], 8);
-
-         output_asm_insn (AS2 (mov%L0,%4,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-       }
-
-      RET;
-    }
+    return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);
 }")
 
 (define_insn "movxf_mem"
    (clobber (match_scratch:SI 2 "=&r,&r"))
    (clobber (match_scratch:SI 3 "=&r,X"))]
   ""
-  "*
-{
-  rtx xop[8];
-
-  xop[0] = operands[2];
-  xop[1] = operands[3];
-  xop[2] = adj_offsettable_operand (operands[1], 8);
-  xop[3] = adj_offsettable_operand (operands[1], 4);
-  xop[4] = operands[1];
-  xop[5] = adj_offsettable_operand (operands[0], 8);
-  xop[6] = adj_offsettable_operand (operands[0], 4);
-  xop[7] = operands[0];
-
-  if (GET_CODE (operands[3]) == REG)
-    {                          /* 2 scratch registers available */
-      output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%3,%1), xop);
-      output_asm_insn (AS2 (mov%L5,%0,%5), xop);
-      output_asm_insn (AS2 (mov%L6,%1,%6), xop);
-      output_asm_insn (AS2 (mov%L0,%4,%0), xop);
-      output_asm_insn (AS2 (mov%L7,%0,%7), xop);
-    }
-  else
-    {                          /* 1 scratch register */
-      output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%5), xop);
-      output_asm_insn (AS2 (mov%L0,%3,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%6), xop);
-      output_asm_insn (AS2 (mov%L0,%4,%0), xop);
-      output_asm_insn (AS2 (mov%L7,%0,%7), xop);
-    }
-
-  RET;
-}")
+  "* return output_move_memory (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);")
 
 (define_insn "movxf_normal"
   [(set (match_operand:XF 0 "general_operand" "=f,fm,!*rf,!*rm")
     return AS1 (fxch,%0);
 }")
 
-(define_expand "movdi"
-  [(set (match_operand:DI 0 "general_operand" "")
-       (match_operand:DI 1 "general_operand" ""))]
-  ""
-  "
-{
-  /* Special case memory->memory moves and pushes */
-  if (TARGET_MOVE
-      && (reload_in_progress | reload_completed) == 0
-      && GET_CODE (operands[0]) == MEM
-      && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], DImode)))
-    {
-      rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], DImode))
-                                               ? gen_movdi_push
-                                               : gen_movdi_mem;
-
-      emit_insn ((*genfunc) (operands[0], operands[1]));
-      DONE;
-    }
-}")
-
-(define_insn "movdi_push_nomove"
-  [(set (match_operand:DI 0 "push_operand" "=<")
-       (match_operand:DI 1 "general_operand" "roiF"))]
-  "!TARGET_MOVE"
-  "* return output_move_double (operands);")
-
-(define_insn "movdi_push"
+(define_insn ""
   [(set (match_operand:DI 0 "push_operand" "=<,<,<,<")
        (match_operand:DI 1 "general_operand" "riF,o,o,o"))
    (clobber (match_scratch:SI 2 "=X,&r,&r,X"))
   ""
   "*
 {
-  if (GET_CODE (operands[1]) != MEM
-      || GET_CODE (operands[2]) != REG)
+  if (GET_CODE (operands[1]) != MEM)
     return output_move_double (operands);
 
   else
-    {
-      rtx low[1], high[1], xop[4];
-
-      split_di (&operands[1], 1, low, high);
-      xop[0] = operands[2];
-      xop[1] = operands[3];
-      xop[2] = high[0];
-      xop[3] = low[0];
-
-      if (GET_CODE (operands[3]) == REG)
-       {                       /* 2 scratch registers available */
-         output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-         output_asm_insn (AS2 (mov%L0,%3,%1), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-         output_asm_insn (AS1 (push%L0,%1), xop);
-       }
-      else
-       {                       /* 1 scratch register */
-         output_asm_insn (AS2 (mov%L0,%2,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-
-                               /* account for push above */
-         if (reg_mentioned_p (stack_pointer_rtx, XEXP (xop[3], 0)))
-           xop[3] = adj_offsettable_operand (xop[3], 4);
-
-         output_asm_insn (AS2 (mov%L0,%3,%0), xop);
-         output_asm_insn (AS1 (push%L0,%0), xop);
-       }
-
-      RET;
-    }
+    return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
 }")
 
-(define_insn "movdi_mem"
-  [(set (match_operand:DI 0 "memory_operand" "=o,o")
-       (match_operand:DI 1 "memory_operand" "o,o"))
-   (clobber (match_scratch:SI 2 "=&r,&r"))
-   (clobber (match_scratch:SI 3 "=&r,X"))]
+(define_insn "movdi"
+  [(set (match_operand:DI 0 "general_operand" "=o,o,r,rm")
+       (match_operand:DI 1 "general_operand" "o,o,m,riF"))
+   (clobber (match_scratch:SI 2 "=&r,&r,X,X"))
+   (clobber (match_scratch:SI 3 "=&r,X,X,X"))]
   ""
   "*
 {
   rtx low[2], high[2], xop[6];
 
-  split_di (operands, 2, low, high);
-  xop[0] = operands[2];
-  xop[1] = operands[3];
-  xop[2] = high[0];
-  xop[3] = high[1];
-  xop[4] = low[0];
-  xop[5] = low[1];
-  if (GET_CODE (operands[3]) == REG)
-    {                          /* 2 scratch registers available */
-      output_asm_insn (AS2 (mov%L0,%5,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%3,%1), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%4), xop);
-      output_asm_insn (AS2 (mov%L0,%1,%2), xop);
-    }
+  if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+    return output_move_double (operands);
   else
-    {                          /* 1 scratch register */
-      output_asm_insn (AS2 (mov%L0,%5,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%4), xop);
-      output_asm_insn (AS2 (mov%L0,%3,%0), xop);
-      output_asm_insn (AS2 (mov%L0,%0,%2), xop);
-    }
-
-  RET;
+    return output_move_memory (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
 }")
 
-(define_insn "movdi_normal"
-  [(set (match_operand:DI 0 "general_operand" "=r,rm")
-       (match_operand:DI 1 "general_operand" "m,riF"))]
-  "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
-  "* return output_move_double (operands);")
-
 \f
 ;;- conversion instructions
 ;;- NONE
   "!HALF_PIC_P ()"
   "call %P1")
 
+;; Call subroutine returning any type.
+
 (define_expand "untyped_call"
-  [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
+  [(parallel [(call (match_operand 0 "" "")
                    (const_int 0))
-             (match_operand:BLK 1 "memory_operand" "")
+             (match_operand 1 "" "")
              (match_operand 2 "" "")])]
   ""
   "
 {
-  rtx addr;
+  int i;
 
-  if (flag_pic)
-    current_function_uses_pic_offset_table = 1;
-
-  /* With half-pic, force the address into a register.  */
-  addr = XEXP (operands[0], 0);
-  if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
-    XEXP (operands[0], 0) = force_reg (Pmode, addr);
-
-  operands[1] = change_address (operands[1], DImode, XEXP (operands[1], 0));
-  if (! expander_call_insn_operand (operands[1], QImode))
-    operands[1]
-      = change_address (operands[1], VOIDmode,
-                       copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
-}")
+  emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
 
-(define_insn ""
-  [(call (match_operand:QI 0 "call_insn_operand" "m")
-        (const_int 0))
-   (match_operand:DI 1 "memory_operand" "o")
-   (match_operand 2 "" "")]
-  ""
-  "*
-{
-  rtx addr = operands[1];
-
-  if (GET_CODE (operands[0]) == MEM
-      && ! CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
+  for (i = 0; i < XVECLEN (operands[2], 0); i++)
     {
-      operands[0] = XEXP (operands[0], 0);
-      output_asm_insn (AS1 (call,%*%0), operands);
+      rtx set = XVECEXP (operands[2], 0, i);
+      emit_move_insn (SET_DEST (set), SET_SRC (set));
     }
-  else
-    output_asm_insn (AS1 (call,%P0), operands);
-
-  operands[2] = gen_rtx (REG, SImode, 0);
-  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
-  operands[2] = gen_rtx (REG, SImode, 1);
-  operands[1] = adj_offsettable_operand (addr, 4);
-  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
-  operands[1] = adj_offsettable_operand (addr, 8);
-  return AS1 (fnsave,%1);
-}")
-
-(define_insn ""
-  [(call (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
-        (const_int 0))
-   (match_operand:DI 1 "memory_operand" "o")
-   (match_operand 2 "" "")]
-  "!HALF_PIC_P ()"
-  "*
-{
-  rtx addr = operands[1];
-
-  output_asm_insn (AS1 (call,%P0), operands);
-
-  operands[2] = gen_rtx (REG, SImode, 0);
-  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
-  operands[2] = gen_rtx (REG, SImode, 1);
-  operands[1] = adj_offsettable_operand (addr, 4);
-  output_asm_insn (AS2 (mov%L2,%2,%1), operands);
-
-  operands[1] = adj_offsettable_operand (addr, 8);
-  return AS1 (fnsave,%1);
-}")
-
-;; We use fnsave and frstor to save and restore the floating point result.
-;; These are expensive instructions and require a large space to save the
-;; FPU state.  An more complicated alternative is to use fnstenv to store
-;; the FPU environment and test whether the stack top is valid.  Store the
-;; result of the test, and if it is valid, pop and save the value.  The
-;; untyped_return would check the test and optionally push the saved value.
-
-(define_expand "untyped_return"
-  [(match_operand:BLK 0 "memory_operand" "")
-   (match_operand 1 "" "")]
-  ""
-  "
-{
-  rtx valreg1 = gen_rtx (REG, SImode, 0);
-  rtx valreg2 = gen_rtx (REG, SImode, 1);
-  rtx result = operands[0];
-
-  /* Restore the FPU state.  */
-  emit_insn (gen_update_return (change_address (result, SImode,
-                                               plus_constant (XEXP (result, 0),
-                                                              8))));
 
-  /* Reload the function value registers.  */
-  emit_move_insn (valreg1, change_address (result, SImode, XEXP (result, 0)));
-  emit_move_insn (valreg2,
-                 change_address (result, SImode,
-                                 plus_constant (XEXP (result, 0), 4)));
-
-  /* Put USE insns before the return.  */
-  emit_insn (gen_rtx (USE, VOIDmode, valreg1));
-  emit_insn (gen_rtx (USE, VOIDmode, valreg2));
-
-  /* Construct the return.  */
-  expand_null_return ();
+  /* The optimizer does not know that the call sets the function value
+     registers we stored in the result block.  We avoid problems by
+     claiming that all hard registers are used and clobbered at this
+     point.  */
+  emit_insn (gen_blockage ());
 
   DONE;
 }")
 
-(define_insn "update_return"
-  [(unspec:SI [(match_operand:SI 0 "memory_operand" "m")] 0)]
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory.  This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+  [(unspec_volatile [(const_int 0)] 0)]
   ""
-  "frstor %0")
+  "")
 
 ;; Insn emitted into the body of a function to return from a function.
 ;; This is only done if the function's epilogue is known to be simple.
index 3e4f504..8185485 100644 (file)
@@ -68,9 +68,7 @@ nil_method(id receiver, SEL op, ...)
 }
 
 /* Given a class and selector, return the selector's implementation.  */
-#ifndef i386
-__inline__ /* this is broken on i386... */
-#endif
+__inline__
 IMP
 get_imp (Class* class, SEL sel)
 {