]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/config/sparc/sparc.c
*** empty log message ***
[gcc.git] / gcc / config / sparc / sparc.c
index 3f72b3464a825e60f725059b19e37445527bb158..a875dba5e3c2a828dcc81d3597802af22d4b6be7 100644 (file)
@@ -491,8 +491,9 @@ eligible_for_epilogue_delay (trial, slot)
   if (get_attr_length (trial) != 1)
     return 0;
 
-  /* In the case of a true leaf function, anything can
-     go into the delay slot.  */
+  /* In the case of a true leaf function, anything can go into the delay slot.
+     A delay slot only exists however if the frame size is zero, otherwise
+     we will put an insn to adjust the stack after the return.  */
   if (leaf_function)
     {
       if (leaf_return_peephole_ok ())
@@ -505,13 +506,10 @@ eligible_for_epilogue_delay (trial, slot)
   pat = PATTERN (trial);
   if (GET_CODE (SET_DEST (pat)) != REG
       || REGNO (SET_DEST (pat)) == 0
-      || (leaf_function
-         && REGNO (SET_DEST (pat)) < 32
-         && REGNO (SET_DEST (pat)) >= 16)
-      || (! leaf_function
-         && (REGNO (SET_DEST (pat)) >= 32
-             || REGNO (SET_DEST (pat)) < 24)))
+      || REGNO (SET_DEST (pat)) >= 32
+      || REGNO (SET_DEST (pat)) < 24)
     return 0;
+
   src = SET_SRC (pat);
   if (arith_operand (src, GET_MODE (src)))
     return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
@@ -946,9 +944,9 @@ singlemove_string (operands)
     {
       int i = INTVAL (operands[1]);
 
-      /* If all low order 12 bits are clear, then we only need a single
+      /* If all low order 10 bits are clear, then we only need a single
         sethi insn to load the constant.  */
-      if (i & 0x00000FFF)
+      if ((i & 0x000003FF) != 0)
        return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
       else
        return "sethi %%hi(%a1),%0";
@@ -957,35 +955,137 @@ singlemove_string (operands)
   return "mov %1,%0";
 }
 \f
+/* Return non-zero if it is OK to assume that the given memory operand is
+   aligned at least to a 8-byte boundary.  This should only be called
+   for memory accesses whose size is 8 bytes or larger.  */
+
+static int
+mem_aligned_8 (mem)
+     register rtx mem;
+{
+  register rtx addr;
+  register rtx base;
+  register rtx offset;
+
+  if (GET_CODE (mem) != MEM)
+    abort ();  /* It's gotta be a MEM! */
+
+  addr = XEXP (mem, 0);
+
+#if 1
+  /* Now that all misaligned double parms are copied on function entry,
+     we can assume any 64-bit object is 64-bit aligned.  */
+
+  /* See what register we use in the address.  */
+  base = 0;
+  if (GET_CODE (addr) == PLUS)
+    {
+      if (GET_CODE (XEXP (addr, 0)) == REG
+         && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+       {
+         base = XEXP (addr, 0);
+         offset = XEXP (addr, 1);
+       }
+    }
+  else if (GET_CODE (addr) == REG)
+    {
+      base = addr;
+      offset = const0_rtx;
+    }
+
+  /* If it's the stack or frame pointer, check offset alignment.
+     We can have improper aligment in the function entry code.  */
+  if (base
+      && (REGNO (base) == FRAME_POINTER_REGNUM
+         || REGNO (base) == STACK_POINTER_REGNUM))
+    {
+      if ((INTVAL (offset) & 0x7) == 0)
+       return 1;
+    }
+  else
+    /* Anything else, we know is properly aligned.  */
+    return 1;
+#else
+  /* If the operand is known to have been allocated in static storage, then
+     it must be aligned.  */
+
+  if (CONSTANT_P (addr) || GET_CODE (addr) == LO_SUM)
+    return 1;
+
+  base = 0;
+  if (GET_CODE (addr) == PLUS)
+    {
+      if (GET_CODE (XEXP (addr, 0)) == REG
+          && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+        {
+          base = XEXP (addr, 0);
+          offset = XEXP (addr, 1);
+        }
+    }
+  else if (GET_CODE (addr) == REG)
+    {
+      base = addr;
+      offset = const0_rtx;
+    }
+
+  /* Trust round enough offsets from the stack or frame pointer.
+     If TARGET_HOPE_ALIGN, trust round enough offset from any register.
+     If it is obviously unaligned, don't ever return true.  */
+  if (base
+      && (REGNO (base) == FRAME_POINTER_REGNUM
+          || REGNO (base) == STACK_POINTER_REGNUM
+         || TARGET_HOPE_ALIGN))
+    {
+      if ((INTVAL (offset) & 0x7) == 0)
+       return 1;
+    }
+  /* Otherwise, we can assume that an access is aligned if it is to an
+     aggregate.  Also, if TARGET_HOPE_ALIGN, then assume everything that isn't
+     obviously unaligned is aligned.  */
+  else if (MEM_IN_STRUCT_P (mem) || TARGET_HOPE_ALIGN)
+    return 1;
+#endif
+
+  /* An obviously unaligned address.  */
+  return 0;
+}
+
+enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP };
+
 /* Output assembler code to perform a doubleword move insn
-   with operands OPERANDS.  */
+   with operands OPERANDS.  This is very similar to the following
+   output_move_quad function.  */
 
 char *
 output_move_double (operands)
      rtx *operands;
 {
-  enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
+  register rtx op0 = operands[0];
+  register rtx op1 = operands[1];
+  register enum optype optype0;
+  register enum optype optype1;
   rtx latehalf[2];
-  rtx addreg0 = 0, addreg1 = 0;
+  rtx addreg0 = 0;
+  rtx addreg1 = 0;
 
   /* First classify both operands.  */
 
-  if (REG_P (operands[0]))
+  if (REG_P (op0))
     optype0 = REGOP;
-  else if (offsettable_memref_p (operands[0]))
+  else if (offsettable_memref_p (op0))
     optype0 = OFFSOP;
-  else if (GET_CODE (operands[0]) == MEM)
+  else if (GET_CODE (op0) == MEM)
     optype0 = MEMOP;
   else
     optype0 = RNDOP;
 
-  if (REG_P (operands[1]))
+  if (REG_P (op1))
     optype1 = REGOP;
-  else if (CONSTANT_P (operands[1]))
+  else if (CONSTANT_P (op1))
     optype1 = CNSTOP;
-  else if (offsettable_memref_p (operands[1]))
+  else if (offsettable_memref_p (op1))
     optype1 = OFFSOP;
-  else if (GET_CODE (operands[1]) == MEM)
+  else if (GET_CODE (op1) == MEM)
     optype1 = MEMOP;
   else
     optype1 = RNDOP;
@@ -994,145 +1094,76 @@ output_move_double (operands)
      supposed to allow to happen.  Abort if we get one,
      because generating code for these cases is painful.  */
 
-  if (optype0 == RNDOP || optype1 == RNDOP)
+  if (optype0 == RNDOP || optype1 == RNDOP
+      || (optype0 == MEM && optype1 == MEM))
     abort ();
 
   /* If an operand is an unoffsettable memory ref, find a register
      we can increment temporarily to make it refer to the second word.  */
 
   if (optype0 == MEMOP)
-    addreg0 = find_addr_reg (XEXP (operands[0], 0));
+    addreg0 = find_addr_reg (XEXP (op0, 0));
 
   if (optype1 == MEMOP)
-    addreg1 = find_addr_reg (XEXP (operands[1], 0));
+    addreg1 = find_addr_reg (XEXP (op1, 0));
 
   /* Ok, we can do one word at a time.
-     Normally we do the low-numbered word first,
-     but if either operand is autodecrementing then we
-     do the high-numbered word first.
-
-     In either case, set up in LATEHALF the operands to use for the
+     Set up in LATEHALF the operands to use for the
      high-numbered (least significant) word and in some cases alter the
      operands in OPERANDS to be suitable for the low-numbered word.  */
 
   if (optype0 == REGOP)
-    latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+    latehalf[0] = gen_rtx (REG, SImode, REGNO (op0) + 1);
   else if (optype0 == OFFSOP)
-    latehalf[0] = adj_offsettable_operand (operands[0], 4);
+    latehalf[0] = adj_offsettable_operand (op0, 4);
   else
-    latehalf[0] = operands[0];
+    latehalf[0] = op0;
 
   if (optype1 == REGOP)
-    latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
+    latehalf[1] = gen_rtx (REG, SImode, REGNO (op1) + 1);
   else if (optype1 == OFFSOP)
-    latehalf[1] = adj_offsettable_operand (operands[1], 4);
+    latehalf[1] = adj_offsettable_operand (op1, 4);
   else if (optype1 == CNSTOP)
-    split_double (operands[1], &operands[1], &latehalf[1]);
+    split_double (op1, &operands[1], &latehalf[1]);
   else
-    latehalf[1] = operands[1];
+    latehalf[1] = op1;
 
-  /* If the first move would clobber the source of the second one,
-     do them in the other order.
-
-     RMS says "This happens only for registers;
-     such overlap can't happen in memory unless the user explicitly
-     sets it up, and that is an undefined circumstance."
-
-     but it happens on the sparc when loading parameter registers,
-     so I am going to define that circumstance, and make it work
-     as expected.  */
-
-  /* Easy case: try moving both words at once.  */
-  /* First check for moving between an even/odd register pair
-     and a memory location.  */
+  /* Easy case: try moving both words at once.  Check for moving between
+     an even/odd register pair and a memory location.  */
   if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP
-       && (REGNO (operands[0]) & 1) == 0)
+       && (REGNO (op0) & 1) == 0)
       || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP
-         && (REGNO (operands[1]) & 1) == 0))
+         && (REGNO (op1) & 1) == 0))
     {
-      rtx op1, op2;
-      rtx base = 0, offset = const0_rtx;
+      register rtx mem;
 
-      /* OP1 gets the register pair, and OP2 gets the memory address.  */
       if (optype0 == REGOP)
-       op1 = operands[0], op2 = operands[1];
+       mem = op1;
       else
-       op1 = operands[1], op2 = operands[0];
-
-      /* Now see if we can trust the address to be 8-byte aligned.  */
-      /* Trust double-precision floats in global variables.  */
-
-      if (GET_CODE (XEXP (op2, 0)) == LO_SUM && GET_MODE (op2) == DFmode)
-       {
-         if (final_sequence)
-           abort ();
-         return (op1 == operands[0] ? "ldd %1,%0" : "std %1,%0");
-       }
-
-      if (GET_CODE (XEXP (op2, 0)) == PLUS)
-       {
-         rtx temp = XEXP (op2, 0);
-         if (GET_CODE (XEXP (temp, 0)) == REG)
-           base = XEXP (temp, 0), offset = XEXP (temp, 1);
-         else if (GET_CODE (XEXP (temp, 1)) == REG)
-           base = XEXP (temp, 1), offset = XEXP (temp, 0);
-       }
+       mem = op0;
 
-      /* Trust round enough offsets from the stack or frame pointer.  */
-      if (base
-         && (REGNO (base) == FRAME_POINTER_REGNUM
-             || REGNO (base) == STACK_POINTER_REGNUM))
-       {
-         if (GET_CODE (offset) == CONST_INT
-             && (INTVAL (offset) & 0x7) == 0)
-           {
-             if (op1 == operands[0])
-               return "ldd %1,%0";
-             else
-               return "std %1,%0";
-           }
-       }
-      /* We know structs not on the stack are properly aligned.  Since a
-        double asks for 8-byte alignment, we know it must have got that
-        if it is in a struct.  But a DImode need not be 8-byte aligned,
-        because it could be a struct containing two ints or pointers.  */
-      else if (GET_CODE (operands[1]) == MEM
-              && GET_MODE (operands[1]) == DFmode
-              && (CONSTANT_P (XEXP (operands[1], 0))
-                  /* Let user ask for it anyway.  */
-                  || TARGET_HOPE_ALIGN))
-       return "ldd %1,%0";
-      else if (GET_CODE (operands[0]) == MEM
-              && GET_MODE (operands[0]) == DFmode
-              && (CONSTANT_P (XEXP (operands[0], 0))
-                  || TARGET_HOPE_ALIGN))
-       return "std %1,%0";
+      if (mem_aligned_8 (mem))
+       return (mem == op1 ? "ldd %1,%0" : "std %1,%0");
     }
 
+  /* If the first move would clobber the source of the second one,
+     do them in the other order.  */
+
+  /* Overlapping registers.  */
   if (optype0 == REGOP && optype1 == REGOP
-      && REGNO (operands[0]) == REGNO (latehalf[1]))
+      && REGNO (op0) == REGNO (latehalf[1]))
     {
-      /* Make any unoffsettable addresses point at high-numbered word.  */
-      if (addreg0)
-       output_asm_insn ("add %0,0x4,%0", &addreg0);
-      if (addreg1)
-       output_asm_insn ("add %0,0x4,%0", &addreg1);
-
       /* Do that word.  */
       output_asm_insn (singlemove_string (latehalf), latehalf);
-
-      /* Undo the adds we just did.  */
-      if (addreg0)
-       output_asm_insn ("add %0,-0x4,%0", &addreg0);
-      if (addreg1)
-       output_asm_insn ("add %0,-0x4,%0", &addreg1);
-
       /* Do low-numbered word.  */
       return singlemove_string (operands);
     }
+  /* Loading into a register which overlaps a register used in the address.  */
   else if (optype0 == REGOP && optype1 != REGOP
-          && reg_overlap_mentioned_p (operands[0], operands[1]))
+          && reg_overlap_mentioned_p (op0, op1))
     {
+      /* ??? This fails if the address is a double register address, each
+        of which is clobbered by operand 0.  */
       /* Do the late half first.  */
       output_asm_insn (singlemove_string (latehalf), latehalf);
       /* Then clobber.  */
@@ -1160,7 +1191,219 @@ output_move_double (operands)
 
   return "";
 }
+
+/* Output assembler code to perform a quadword move insn
+   with operands OPERANDS.  This is very similar to the preceeding
+   output_move_double function.  */
+
+char *
+output_move_quad (operands)
+     rtx *operands;
+{
+  register rtx op0 = operands[0];
+  register rtx op1 = operands[1];
+  register enum optype optype0;
+  register enum optype optype1;
+  rtx wordpart[4][2];
+  rtx addreg0 = 0;
+  rtx addreg1 = 0;
+
+  /* First classify both operands.  */
+
+  if (REG_P (op0))
+    optype0 = REGOP;
+  else if (offsettable_memref_p (op0))
+    optype0 = OFFSOP;
+  else if (GET_CODE (op0) == MEM)
+    optype0 = MEMOP;
+  else
+    optype0 = RNDOP;
+
+  if (REG_P (op1))
+    optype1 = REGOP;
+  else if (CONSTANT_P (op1))
+    optype1 = CNSTOP;
+  else if (offsettable_memref_p (op1))
+    optype1 = OFFSOP;
+  else if (GET_CODE (op1) == MEM)
+    optype1 = MEMOP;
+  else
+    optype1 = RNDOP;
+
+  /* Check for the cases that the operand constraints are not
+     supposed to allow to happen.  Abort if we get one,
+     because generating code for these cases is painful.  */
+
+  if (optype0 == RNDOP || optype1 == RNDOP
+      || (optype0 == MEM && optype1 == MEM))
+    abort ();
+
+  /* If an operand is an unoffsettable memory ref, find a register
+     we can increment temporarily to make it refer to the later words.  */
+
+  if (optype0 == MEMOP)
+    addreg0 = find_addr_reg (XEXP (op0, 0));
+
+  if (optype1 == MEMOP)
+    addreg1 = find_addr_reg (XEXP (op1, 0));
+
+  /* Ok, we can do one word at a time.
+     Set up in wordpart the operands to use for each word of the arguments.  */
+
+  if (optype0 == REGOP)
+    {
+      wordpart[0][0] = gen_rtx (REG, SImode, REGNO (op0) + 0);
+      wordpart[1][0] = gen_rtx (REG, SImode, REGNO (op0) + 1);
+      wordpart[2][0] = gen_rtx (REG, SImode, REGNO (op0) + 2);
+      wordpart[3][0] = gen_rtx (REG, SImode, REGNO (op0) + 3);
+    }
+  else if (optype0 == OFFSOP)
+    {
+      wordpart[0][0] = adj_offsettable_operand (op0, 0);
+      wordpart[1][0] = adj_offsettable_operand (op0, 4);
+      wordpart[2][0] = adj_offsettable_operand (op0, 8);
+      wordpart[3][0] = adj_offsettable_operand (op0, 12);
+    }
+  else
+    {
+      wordpart[0][0] = op0;
+      wordpart[1][0] = op0;
+      wordpart[2][0] = op0;
+      wordpart[3][0] = op0;
+    }
+
+  if (optype1 == REGOP)
+    {
+      wordpart[0][1] = gen_rtx (REG, SImode, REGNO (op1) + 0);
+      wordpart[1][1] = gen_rtx (REG, SImode, REGNO (op1) + 1);
+      wordpart[2][1] = gen_rtx (REG, SImode, REGNO (op1) + 2);
+      wordpart[3][1] = gen_rtx (REG, SImode, REGNO (op1) + 3);
+    }
+  else if (optype1 == OFFSOP)
+    {
+      wordpart[0][1] = adj_offsettable_operand (op1, 0);
+      wordpart[1][1] = adj_offsettable_operand (op1, 4);
+      wordpart[2][1] = adj_offsettable_operand (op1, 8);
+      wordpart[3][1] = adj_offsettable_operand (op1, 12);
+    }
+  else if (optype1 == CNSTOP)
+    {
+      /* This case isn't implemented yet, because there is no internal
+        representation for quad-word constants, and there is no split_quad
+        function.  */
+#if 0
+      split_quad (op1, &wordpart[0][1], &wordpart[1][1],
+                 &wordpart[2][1], &wordpart[3][1]);
+#else
+      abort ();
+#endif
+    }
+  else
+    {
+      wordpart[0][1] = op1;
+      wordpart[1][1] = op1;
+      wordpart[2][1] = op1;
+      wordpart[3][1] = op1;
+    }
+
+  /* Easy case: try moving the quad as two pairs.  Check for moving between
+     an even/odd register pair and a memory location.  */
+  /* ??? Should also handle the case of non-offsettable addresses here.
+     We can at least do the first pair as a ldd/std, and then do the third
+     and fourth words individually.  */
+  if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0)
+      || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0))
+    {
+      rtx mem;
+
+      if (optype0 == REGOP)
+       mem = op1;
+      else
+       mem = op0;
+
+      if (mem_aligned_8 (mem))
+       {
+         operands[2] = adj_offsettable_operand (mem, 8);
+         if (mem == op1)
+           return "ldd %1,%0;ldd %2,%S0";
+         else
+           return "std %1,%0;std %S1,%2";
+       }
+    }
+
+  /* If the first move would clobber the source of the second one,
+     do them in the other order.  */
+
+  /* Overlapping registers.  */
+  if (optype0 == REGOP && optype1 == REGOP
+      && (REGNO (op0) == REGNO (wordpart[1][3])
+         || REGNO (op0) == REGNO (wordpart[1][2])
+         || REGNO (op0) == REGNO (wordpart[1][1])))
+    {
+      /* Do fourth word.  */
+      output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
+      /* Do the third word.  */
+      output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
+      /* Do the second word.  */
+      output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
+      /* Do lowest-numbered word.  */
+      return singlemove_string (wordpart[0]);
+    }
+  /* Loading into a register which overlaps a register used in the address.  */
+  if (optype0 == REGOP && optype1 != REGOP
+      && reg_overlap_mentioned_p (op0, op1))
+    {
+      /* ??? Not implemented yet.  This is a bit complicated, because we
+        must load which ever part overlaps the address last.  If the address
+        is a double-reg address, then there are two parts which need to
+        be done last, which is impossible.  We would need a scratch register
+        in that case.  */
+      abort ();
+    }
+
+  /* Normal case: move the four words in lowest to higest address order.  */
+
+  output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
+
+  /* Make any unoffsettable addresses point at the second word.  */
+  if (addreg0)
+    output_asm_insn ("add %0,0x4,%0", &addreg0);
+  if (addreg1)
+    output_asm_insn ("add %0,0x4,%0", &addreg1);
+
+  /* Do the second word.  */
+  output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
+
+  /* Make any unoffsettable addresses point at the third word.  */
+  if (addreg0)
+    output_asm_insn ("add %0,0x4,%0", &addreg0);
+  if (addreg1)
+    output_asm_insn ("add %0,0x4,%0", &addreg1);
+
+  /* Do the third word.  */
+  output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
+
+  /* Make any unoffsettable addresses point at the fourth word.  */
+  if (addreg0)
+    output_asm_insn ("add %0,0x4,%0", &addreg0);
+  if (addreg1)
+    output_asm_insn ("add %0,0x4,%0", &addreg1);
+
+  /* Do the fourth word.  */
+  output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
+
+  /* Undo the adds we just did.  */
+  if (addreg0)
+    output_asm_insn ("add %0,-0xc,%0", &addreg0);
+  if (addreg1)
+    output_asm_insn ("add %0,-0xc,%0", &addreg1);
+
+  return "";
+}
 \f
+/* Output assembler code to perform a doubleword move insn with operands
+   OPERANDS, one of which must be a floating point register.  */
+
 char *
 output_fp_move_double (operands)
      rtx *operands;
@@ -1171,35 +1414,15 @@ output_fp_move_double (operands)
     {
       if (FP_REG_P (operands[1]))
        return "fmovs %1,%0\n\tfmovs %R1,%R0";
-      if (GET_CODE (operands[1]) == REG)
+      else if (GET_CODE (operands[1]) == REG)
        {
          if ((REGNO (operands[1]) & 1) == 0)
            return "std %1,[%@-8]\n\tldd [%@-8],%0";
          else
            return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0";
        }
-      addr = XEXP (operands[1], 0);
-
-      /* Use ldd if known to be aligned.  */
-      if (TARGET_HOPE_ALIGN
-         || (GET_CODE (addr) == PLUS
-             && (((XEXP (addr, 0) == frame_pointer_rtx
-                   || XEXP (addr, 0) == stack_pointer_rtx)
-                  && GET_CODE (XEXP (addr, 1)) == CONST_INT
-                  && (INTVAL (XEXP (addr, 1)) & 0x7) == 0)
-                 /* Arrays are known to be aligned,
-                    and reg+reg addresses are used (on this machine)
-                    only for array accesses.  */
-                 || (REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1)))))
-         || (GET_MODE (operands[0]) == DFmode
-             && (GET_CODE (addr) == LO_SUM || CONSTANT_P (addr))))
-       return "ldd %1,%0";
-
-      /* Otherwise use two ld insns.  */
-      operands[2]
-       = gen_rtx (MEM, GET_MODE (operands[1]),
-                  plus_constant_for_output (addr, 4));
-       return "ld %1,%0\n\tld %2,%R0";
+      else
+       return output_move_double (operands);
     }
   else if (FP_REG_P (operands[1]))
     {
@@ -1210,31 +1433,52 @@ output_fp_move_double (operands)
          else
            return "std %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0";
        }
-      addr = XEXP (operands[0], 0);
-
-      /* Use std if we can be sure it is well-aligned.  */
-      if (TARGET_HOPE_ALIGN
-         || (GET_CODE (addr) == PLUS
-             && (((XEXP (addr, 0) == frame_pointer_rtx
-                   || XEXP (addr, 0) == stack_pointer_rtx)
-                  && GET_CODE (XEXP (addr, 1)) == CONST_INT
-                  && (INTVAL (XEXP (addr, 1)) & 0x7) == 0)
-                 /* Arrays are known to be aligned,
-                    and reg+reg addresses are used (on this machine)
-                    only for array accesses.  */
-                 || (REG_P (XEXP (addr, 0)) && REG_P (XEXP (addr, 1)))))
-         || (GET_MODE (operands[1]) == DFmode
-             && (GET_CODE (addr) == LO_SUM || CONSTANT_P (addr))))
-       return "std %1,%0";
-
-      /* Otherwise use two st insns.  */
-      operands[2]
-       = gen_rtx (MEM, GET_MODE (operands[0]),
-                  plus_constant_for_output (addr, 4));
-      return "st %r1,%0\n\tst %R1,%2";
+      else
+       return output_move_double (operands);
     }
   else abort ();
 }
+
+/* Output assembler code to perform a quadword move insn with operands
+   OPERANDS, one of which must be a floating point register.  */
+
+char *
+output_fp_move_quad (operands)
+     rtx *operands;
+{
+  register rtx op0 = operands[0];
+  register rtx op1 = operands[1];
+  register rtx addr;
+
+  if (FP_REG_P (op0))
+    {
+      if (FP_REG_P (op1))
+       return "fmovs %1,%0\n\tfmovs %R1,%R0\n\tfmovs %S1,%S0\n\tfmovs %T1,%T0";
+      if (GET_CODE (op1) == REG)
+       {
+         if ((REGNO (op1) & 1) == 0)
+           return "std %1,[%@-8]\n\tldd [%@-8],%0\n\tstd %S1,[%@-8]\n\tldd [%@-8],%S0";
+         else
+           return "st %R1,[%@-4]\n\tst %1,[%@-8]\n\tldd [%@-8],%0\n\tst %T1,[%@-4]\n\tst %S1,[%@-8]\n\tldd [%@-8],%S0";
+       }
+      else
+       return output_move_quad (operands);
+    }
+  else if (FP_REG_P (op1))
+    {
+      if (GET_CODE (op0) == REG)
+       {
+         if ((REGNO (op0) & 1) == 0)
+           return "std %1,[%@-8]\n\tldd [%@-8],%0\n\tstd %S1,[%@-8]\n\tldd [%@-8],%S0";
+         else
+           return "std %S1,[%@-8]\n\tld [%@-4],%T0\n\tld [%@-8],%S0\n\tstd %1,[%@-8]\n\tld [%@-4],%R0\n\tld [%@-8],%0";
+       }
+      else
+       return output_move_quad (operands);
+    }
+  else
+    abort ();
+}
 \f
 /* Return a REG that occurs in ADDR with coefficient 1.
    ADDR can be effectively incremented by incrementing REG.  */
@@ -1827,62 +2071,63 @@ compute_frame_size (size, leaf_function)
   return actual_fsize;
 }
 
-/* If this were a leaf function, how far would we have to reach
-   from the stack pointer to the last arg on the stack?
-
-   If we don't know, return 4096 (i.e., "too far".)  */
-
-int
-compute_last_arg_offset ()
-{
-  if (GET_CODE (current_function_arg_offset_rtx) == CONST_INT)
-    return (compute_frame_size (get_frame_size (), 1)
-           + INTVAL (current_function_arg_offset_rtx));
-  return 4096;
-}
+/* Output code for the function prologue.  */
 
 void
 output_function_prologue (file, size, leaf_function)
      FILE *file;
      int size;
+     int leaf_function;
 {
   if (leaf_function)
     frame_base_name = "%sp+80";
   else
     frame_base_name = "%fp";
 
+  /* Need to use actual_fsize, since we are also allocating
+     space for our callee (and our own register save area).  */
   actual_fsize = compute_frame_size (size, leaf_function);
 
   fprintf (file, "\t!#PROLOGUE# 0\n");
-  if (actual_fsize == 0) /* do nothing.  */ ;
-  else if (actual_fsize < 4096)
+  if (actual_fsize == 0)
+    /* do nothing.  */ ;
+  else if (actual_fsize <= 4096)
     {
       if (! leaf_function)
        fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize);
       else
        fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize);
     }
-  else if (! leaf_function)
+  else if (actual_fsize <= 8192)
     {
-      /* Need to use actual_fsize, since we are also allocating space for
-        our callee (and our own register save area).  */
-      fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n",
-              -actual_fsize, -actual_fsize);
-      fprintf (file, "\tsave %%sp,%%g1,%%sp\n");
+      /* For frames in the range 4097..8192, we can use just two insns.  */
+      if (! leaf_function)
+       {
+         fprintf (file, "\tsave %%sp,-4096,%%sp\n");
+         fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
+       }
+      else
+       {
+         fprintf (file, "\tadd %%sp,-4096,%%sp\n");
+         fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
+       }
     }
   else
     {
-      /* The rest of the support for this case hasn't been implemented,
-        but FRAME_POINTER_REQUIRED is supposed to prevent it from arising,
-        by checking the frame size.  */
-      abort ();
-
-      /* Put pointer to parameters into %g4, and allocate
-        frame space using result computed into %g1.  actual_fsize
-        used instead of apparent_fsize for reasons stated above.  */
-      fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n",
-              -actual_fsize, -actual_fsize);
-      fprintf (file, "\tadd %%sp,64,%%g4\n\tadd %%sp,%%g1,%%sp\n");
+      if (! leaf_function)
+       {
+         fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize);
+         if ((actual_fsize & 0x3ff) != 0)
+           fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize);
+         fprintf (file, "\tsave %%sp,%%g1,%%sp\n");
+       }
+      else
+       {
+         fprintf (file, "\tsethi %%hi(-%d),%%g1\n", actual_fsize);
+         if ((actual_fsize & 0x3ff) != 0)
+           fprintf (file, "\tor %%g1,%%lo(-%d),%%g1\n", actual_fsize);
+         fprintf (file, "\tadd %%sp,%%g1,%%sp\n");
+       }
     }
 
   /* If doing anything with PIC, do it now.  */
@@ -1922,18 +2167,19 @@ output_function_prologue (file, size, leaf_function)
     }
 }
 
+/* Output code for the function epilogue.  */
+
 void
-output_function_epilogue (file, size, leaf_function, true_epilogue)
+output_function_epilogue (file, size, leaf_function)
      FILE *file;
      int size;
+     int leaf_function;
 {
   int n_fregs, i;
   char *ret;
 
   if (leaf_label)
     {
-      if (leaf_function < 0)
-       abort ();
       emit_label_after (leaf_label, get_last_insn ());
       final_scan_insn (get_last_insn (), file, 0, 0, 1);
     }
@@ -1962,66 +2208,52 @@ output_function_epilogue (file, size, leaf_function, true_epilogue)
   else
     ret = (current_function_returns_struct ? "jmp %i7+12" : "ret");
 
-  /* Tail calls have to do this work themselves.  */
-  if (leaf_function >= 0)
+  if (TARGET_EPILOGUE || leaf_label)
     {
-      if (TARGET_EPILOGUE || leaf_label)
-       {
-         int old_target_epilogue = TARGET_EPILOGUE;
-         target_flags &= ~old_target_epilogue;
+      int old_target_epilogue = TARGET_EPILOGUE;
+      target_flags &= ~old_target_epilogue;
 
-         if (! leaf_function)
-           {
-             /* If we wound up with things in our delay slot,
-                flush them here.  */
-             if (current_function_epilogue_delay_list)
-               {
-                 rtx insn = emit_jump_insn_after (gen_rtx (RETURN, VOIDmode),
-                                                  get_last_insn ());
-                 PATTERN (insn) = gen_rtx (PARALLEL, VOIDmode,
-                                           gen_rtvec (2,
-                                                      PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
-                                                      PATTERN (insn)));
-                 final_scan_insn (insn, file, 1, 0, 1);
-               }
-             else
-               fprintf (file, "\t%s\n\trestore\n", ret);
-           }
-         else if (actual_fsize < 4096)
+      if (! leaf_function)
+       {
+         /* If we wound up with things in our delay slot, flush them here.  */
+         if (current_function_epilogue_delay_list)
            {
-             if (current_function_epilogue_delay_list)
-               {
-                 fprintf (file, "\t%s\n", ret);
-                 final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
-                                  file, 1, 0, 1);
-               }
-             else
-               fprintf (file, "\t%s\n\tadd %%sp,%d,%%sp\n",
-                        ret, actual_fsize);
+             rtx insn = emit_jump_insn_after (gen_rtx (RETURN, VOIDmode),
+                                              get_last_insn ());
+             PATTERN (insn) = gen_rtx (PARALLEL, VOIDmode,
+                                       gen_rtvec (2,
+                                                  PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
+                                                  PATTERN (insn)));
+             final_scan_insn (insn, file, 1, 0, 1);
            }
          else
-           {
-             if (current_function_epilogue_delay_list)
-               abort ();
-             fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
-                      actual_fsize, actual_fsize, ret);
-           }
-         target_flags |= old_target_epilogue;
+           fprintf (file, "\t%s\n\trestore\n", ret);
        }
-    }
-  else if (true_epilogue)
-    {
-      /* We may still need a return insn!  Somebody could jump around
-        the tail-calls that this function makes.  */
-      if (TARGET_EPILOGUE)
+      /* All of the following cases are for leaf functions.  */
+      else if (current_function_epilogue_delay_list)
        {
-         rtx last = get_last_insn ();
-
-         last = prev_nonnote_insn (last);
-         if (last == 0
-             || (GET_CODE (last) != JUMP_INSN && GET_CODE (last) != BARRIER))
-           fprintf (file, "\t%s\n\tnop\n", ret);
+         /* eligible_for_epilogue_delay_slot ensures that if this is a
+            leaf function, then we will only have insn in the delay slot
+            if the frame size is zero, thus no adjust for the stack is
+            needed here.  */
+         if (actual_fsize != 0)
+           abort ();
+         fprintf (file, "\t%s\n", ret);
+         final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
+                          file, 1, 0, 1);
        }
+      else if (actual_fsize <= 4096)
+       fprintf (file, "\t%s\n\tsub %%sp,-%d,%%sp\n", ret, actual_fsize);
+      else if (actual_fsize <= 8192)
+       fprintf (file, "\tsub %%sp,-4096,%%sp\n\t%s\n\tsub %%sp,-%d,%%sp\n",
+                ret, actual_fsize - 4096);
+      else if ((actual_fsize & 0x3ff) == 0)
+       fprintf (file, "\tsethi %%hi(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
+                actual_fsize, ret);
+      else              
+       fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
+                actual_fsize, actual_fsize, ret);
+      target_flags |= old_target_epilogue;
     }
 }
 \f
@@ -2156,6 +2388,8 @@ output_cbranch (op, label, reversed, annul, noop)
   return string;
 }
 
+/* Output assembler code to return from a function.  */
+
 char *
 output_return (operands)
      rtx *operands;
@@ -2167,20 +2401,43 @@ output_return (operands)
     }
   else if (leaf_function)
     {
+      /* If we didn't allocate a frame pointer for the current function,
+        the stack pointer might have been adjusted.  Output code to
+        restore it now.  */
+
       operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize);
-      if (actual_fsize < 4096)
+
+      /* Use sub of negated value in first two cases instead of add to
+        allow actual_fsize == 4096.  */
+
+      if (actual_fsize <= 4096)
        {
          if (current_function_returns_struct)
-           return "jmp %%o7+12\n\tadd %%sp,%0,%%sp";
+           return "jmp %%o7+12\n\tsub %%sp,-%0,%%sp";
          else
-           return "retl\n\tadd %%sp,%0,%%sp";
+           return "retl\n\tsub %%sp,-%0,%%sp";
        }
-      else
+      else if (actual_fsize <= 8192)
        {
+         operands[0] = gen_rtx (CONST_INT, VOIDmode, actual_fsize - 4096);
          if (current_function_returns_struct)
+           return "sub %%sp,-4096,%%sp\n\tjmp %%o7+12\n\tsub %%sp,-%0,%%sp";
+         else
+           return "sub %%sp,-4096,%%sp\n\tretl\n\tsub %%sp,-%0,%%sp";
+       }
+      else if (current_function_returns_struct)
+       {
+         if ((actual_fsize & 0x3ff) != 0)
            return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
          else
+           return "sethi %%hi(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
+       }
+      else
+       {
+         if ((actual_fsize & 0x3ff) != 0)
            return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+         else
+           return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
        }
     }
   else
@@ -2192,6 +2449,8 @@ output_return (operands)
     }
 }
 
+/* Output assembler code for a SImode to SFmode conversion.  */
+
 char *
 output_floatsisf2 (operands)
      rtx *operands;
@@ -2203,6 +2462,8 @@ output_floatsisf2 (operands)
   return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitos %0,%0";
 }
 
+/* Output assembler code for a SImode to DFmode conversion.  */
+
 char *
 output_floatsidf2 (operands)
      rtx *operands;
@@ -2214,23 +2475,17 @@ output_floatsidf2 (operands)
   return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitod %0,%0";
 }
 
-int
-tail_call_valid_p ()
-{
-  static int checked = 0;
-  static int valid_p = 0;
+/* Output assembler code for a SImode to TFmode conversion.  */
 
-  if (! checked)
-    {
-      register int i;
-
-      checked = 1;
-      for (i = 32; i < FIRST_PSEUDO_REGISTER; i++)
-       if (! fixed_regs[i] && ! call_used_regs[i])
-         return 0;
-      valid_p = 1;
-    }
-  return valid_p;
+char *
+output_floatsitf2 (operands)
+     rtx *operands;
+{
+  if (GET_CODE (operands[1]) == MEM)
+    return "ld %1,%0\n\tfitoq %0,%0";
+  else if (FP_REG_P (operands[1]))
+    return "fitoq %1,%0";
+  return "st %r1,[%%fp-4]\n\tld [%%fp-4],%0\n\tfitoq %0,%0";
 }
 \f
 /* Leaf functions and non-leaf functions have different needs.  */
@@ -2307,93 +2562,107 @@ output_arc_profiler (arcno, insert_after)
   emit_insn_after (gen_rtx (SET, VOIDmode, mem_ref, profiler_reg),
                   insert_after);
 }
-\f
-/* All the remaining routines in this file have been turned off.  */
-#if 0
-char *
-output_tail_call (operands, insn)
-     rtx *operands;
-     rtx insn;
+
+/* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
+   This makes them candidates for using ldd and std insns. 
+
+   Note reg1 and reg2 *must* be hard registers.  To be sure we will
+   abort if we are passed pseudo registers.  */
+
+int
+registers_ok_for_ldd (reg1, reg2)
+     rtx reg1, reg2;
 {
-  int this_fsize = actual_fsize;
-  rtx next;
-  int need_nop_at_end = 0;
 
-  next = next_real_insn (insn);
-  while (next && GET_CODE (next) == CODE_LABEL)
-    next = next_real_insn (insn);
+  /* We might have been passed a SUBREG.  */
+  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) 
+    return 0;
 
-  if (final_sequence && this_fsize > 0)
-    {
-      rtx xoperands[1];
+  /* Should never happen.  */
+  if (REGNO (reg1) > FIRST_PSEUDO_REGISTER 
+      || REGNO (reg2) > FIRST_PSEUDO_REGISTER)
+    abort ();
 
-      /* If we have to restore any registers, don't take any chances
-        restoring a register before we discharge it into
-        its home.  If the frame size is only 88, we are guaranteed
-        that the epilogue will fit in the delay slot.  */
-      rtx delay_insn = XVECEXP (final_sequence, 0, 1);
-      if (GET_CODE (PATTERN (delay_insn)) == SET)
-       {
-         rtx dest = SET_DEST (PATTERN (delay_insn));
-         if (GET_CODE (dest) == REG
-             && reg_mentioned_p (dest, insn))
-           abort ();
-       }
-      else if (GET_CODE (PATTERN (delay_insn)) == PARALLEL)
-       abort ();
-      xoperands[0] = operands[0];
-      final_scan_insn (delay_insn, asm_out_file, 0, 0, 1);
-      operands[0] = xoperands[0];
-      final_sequence = 0;
-    }
+  if (REGNO (reg1) % 2 != 0)
+    return 0;
+
+  return (REGNO (reg1) == REGNO (reg2) - 1);
+  
+}
 
-  /* Make sure we are clear to return.  */
-  output_function_epilogue (asm_out_file, get_frame_size (), -1, 0);
+/* Return 1 if addr1 and addr2 are suitable for use in an ldd or 
+   std insn.
 
-  /* Strip the MEM.  */
-  operands[0] = XEXP (operands[0], 0);
+   This can only happen when addr1 and addr2 are consecutive memory
+   locations (addr1 + 4 == addr2).  addr1 must also be aligned on a 
+   64 bit boundary (addr1 % 8 == 0).  
 
-  if (final_sequence == 0
-      && (next == 0
-         || GET_CODE (next) == CALL_INSN
-         || GET_CODE (next) == JUMP_INSN))
-    need_nop_at_end = 1;
+   We know %sp and %fp are kept aligned on a 64 bit boundary.  Other
+   registers are assumed to *never* be properly aligned and are 
+   rejected.
 
-  if (flag_pic)
-    return output_pic_sequence_2 (2, 3, 0, "jmpl %%g1+%3", operands, need_nop_at_end);
+   Knowing %sp and %fp are kept aligned on a 64 bit boundary, we 
+   need only check that the offset for addr1 % 8 == 0.  */
 
-  if (GET_CODE (operands[0]) == REG)
-    output_asm_insn ("jmpl %a0,%%g0", operands);
-  else if (TARGET_TAIL_CALL)
+int
+memory_ok_for_ldd (addr1, addr2)
+      rtx addr1, addr2;
+{
+  int reg1, offset1;
+
+  /* Extract a register number and offset (if used) from the first addr.  */
+  if (GET_CODE (addr1) == PLUS)
     {
-      /* We assume all labels will be within 16 MB of our call.  */
-      if (need_nop_at_end || final_sequence)
-       output_asm_insn ("b %a0", operands);
+      /* If not a REG, return zero.  */
+      if (GET_CODE (XEXP (addr1, 0)) != REG)
+       return 0;
       else
-       output_asm_insn ("b,a %a0", operands);
-    }
-  else if (! final_sequence)
-    {
-      output_asm_insn ("sethi %%hi(%a0),%%g1\n\tjmpl %%g1+%%lo(%a0),%%g1",
-                      operands);
+       {
+          reg1 = REGNO (XEXP (addr1, 0));
+         /* The offset must be constant!  */
+         if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
+            return 0;
+          offset1 = INTVAL (XEXP (addr1, 1));
+       }
     }
+  else if (GET_CODE (addr1) != REG)
+    return 0;
   else
     {
-      int i;
-      rtx x = PATTERN (XVECEXP (final_sequence, 0, 1));
-      for (i = 1; i < 32; i++)
-       if ((i == 1 || ! fixed_regs[i])
-           && call_used_regs[i]
-           && ! refers_to_regno_p (i, i+1, x, 0))
-         break;
-      if (i == 32)
-       abort ();
-      operands[1] = gen_rtx (REG, SImode, i);
-      output_asm_insn ("sethi %%hi(%a0),%1\n\tjmpl %1+%%lo(%a0),%1", operands);
+      reg1 = REGNO (addr1);
+      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
+      offset1 = 0;
     }
-  return (need_nop_at_end ? "nop" : "");
+
+  /* Make sure the second address is a (mem (plus (reg) (const_int).  */
+  if (GET_CODE (addr2) != PLUS)
+    return 0;
+
+  if (GET_CODE (XEXP (addr2, 0)) != REG
+      || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
+    return 0;
+
+  /* Only %fp and %sp are allowed.  Additionally both addresses must
+     use the same register.  */
+  if (reg1 != FRAME_POINTER_REGNUM && reg1 != STACK_POINTER_REGNUM)
+    return 0;
+
+  if (reg1 != REGNO (XEXP (addr2, 0)))
+    return 0;
+
+  /* The first offset must be evenly divisable by 8 to ensure the 
+     address is 64 bit aligned.  */
+  if (offset1 % 8 != 0)
+    return 0;
+
+  /* The offset for the second addr must be 4 more than the first addr.  */
+  if (INTVAL (XEXP (addr2, 1)) != offset1 + 4)
+    return 0;
+
+  /* All the tests passed.  addr1 and addr2 are valid for ldd and std
+     instructions.  */
+  return 1;
 }
-#endif
 \f
 /* Print operand X (an rtx) in assembler syntax to file FILE.
    CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
@@ -2434,10 +2703,20 @@ print_operand (file, x, code)
       fputs (frame_base_name, file);
       return;
     case 'R':
-      /* Print out the second register name of a register pair.
+      /* Print out the second register name of a register pair or quad.
         I.e., R (%o0) => %o1.  */
       fputs (reg_names[REGNO (x)+1], file);
       return;
+    case 'S':
+      /* Print out the third register name of a register quad.
+        I.e., S (%o0) => %o2.  */
+      fputs (reg_names[REGNO (x)+2], file);
+      return;
+    case 'T':
+      /* Print out the fourth register name of a register quad.
+        I.e., T (%o0) => %o3.  */
+      fputs (reg_names[REGNO (x)+3], file);
+      return;
     case 'm':
       /* Print the operand's address only.  */
       output_address (XEXP (x, 0));
@@ -2642,3 +2921,112 @@ sparc_type_code (type)
         }
     }
 }
+\f
+#ifdef HANDLE_PRAGMA
+
+/* Handle a pragma directive.  HANDLE_PRAGMA conspires to parse the
+   input following #pragma into tokens based on yylex.  TOKEN is the
+   current token, and STRING is its printable form.  */
+
+void
+handle_pragma_token (string, token)
+     char *string;
+     tree token;
+{
+  static enum pragma_state
+    {
+      ps_start,
+      ps_done,
+      ps_bad,
+      ps_weak,
+      ps_name,
+      ps_equals,
+      ps_value,
+      } state = ps_start, type;
+  static char *name;
+  static char *value;
+  static int align;
+
+  if (string == 0)
+    {
+#ifdef WEAK_ASM_OP
+      if (type == ps_weak)
+       {
+         if (state == ps_name || state == ps_value)
+           {
+             fprintf (asm_out_file, "\t%s\t", WEAK_ASM_OP);
+             ASM_OUTPUT_LABELREF (asm_out_file, name);
+             fputc ('\n', asm_out_file);
+             if (state == ps_value)
+               {
+                 fputc ('\t', asm_out_file);
+                 ASM_OUTPUT_LABELREF (asm_out_file, name);
+                 fputs (" = ", asm_out_file);
+                 ASM_OUTPUT_LABELREF (asm_out_file, value);
+                 fputc ('\n', asm_out_file);
+               }
+           }
+         else if (! (state == ps_done || state == ps_start))
+           warning ("ignoring malformed #pragma weak symbol [=value]");
+       }
+#endif /* WEAK_ASM_OP */
+
+      type = state = ps_start;
+      return;
+    }
+
+  switch (state)
+    {
+    case ps_start:
+      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
+       {
+#ifdef WEAK_ASM_OP
+         if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
+           type = state = ps_weak;
+         else
+#endif
+           type = state = ps_done;
+       }
+      else
+       type = state = ps_done;
+      break;
+
+#ifdef WEAK_ASM_OP
+    case ps_weak:
+      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
+       {
+         name = IDENTIFIER_POINTER (token);
+         state = ps_name;
+       }
+      else
+       state = ps_bad;
+      break;
+
+    case ps_name:
+      state = (strcmp (string, "=") ? ps_bad : ps_equals);
+      break;
+
+    case ps_equals:
+      if (token && TREE_CODE (token) == IDENTIFIER_NODE)
+       {
+         value = IDENTIFIER_POINTER (token);
+         state = ps_value;
+       }
+      else
+       state = ps_bad;
+      break;
+
+    case ps_value:
+      state = ps_bad;
+      break;
+#endif /* WEAK_ASM_OP */
+
+    case ps_bad:
+    case ps_done:
+      break;
+
+    default:
+      abort ();
+    }
+}
+#endif /* HANDLE_PRAGMA */
This page took 0.058518 seconds and 5 git commands to generate.