]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
(arm_condition_code): Move to start of file.
authorRichard Earnshaw <erich@gnu.org>
Thu, 2 Jun 1994 18:41:52 +0000 (18:41 +0000)
committerRichard Earnshaw <erich@gnu.org>
Thu, 2 Jun 1994 18:41:52 +0000 (18:41 +0000)
(const_pool_offset): Correct typo.
(fp_const_from_val): New function.
(all instruction generators): mark position where conditionalization
should be with '%?'.
(output_move_double): Use new '%m' output type to simplify load/store
multiple generation.
(shift_instr): Delete.
(shift_op): New function.
(output_arithmetic): Delete.
(output_arithmetic_with_shift): Delete.
(output_arithmetic_with_immediate_multiply): Delete.
(output_shifted_move): Delete.
(output_shift_compare): Delete.
(arm_print_operand): New function.

From-SVN: r7423

gcc/config/arm/arm.c

index 0e8d7d7b6bb24049cd24829d355c960288f1a3ac..e4a2a15e10428c8579259fa4645fbdde3fd145ea 100644 (file)
@@ -96,6 +96,15 @@ int arm_ccfsm_state;
 int arm_current_cc;
 rtx arm_target_insn;
 int arm_target_label;
+
+/* The condition codes of the ARM, and the inverse function.  */
+char *arm_condition_codes[] =
+{
+  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
+  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
+};
+
+#define ARM_INVERSE_CONDITION_CODE(X)  ((X) ^ 1)
 \f
 /* Return 1 if it is possible to return using a single instruction */
 
@@ -680,7 +689,7 @@ store_multiple_operation (op, mode)
 
 int
 const_pool_offset (symbol)
-     rtx (symbol);
+     rtx symbol;
 {
   return get_pool_offset (symbol) - get_pool_size () - get_prologue_size ();
 }
@@ -852,6 +861,22 @@ fp_immediate_constant (x)
   abort ();
 }
 
+/* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
+static char *
+fp_const_from_val (r)
+     REAL_VALUE_TYPE *r;
+{
+  int i;
+
+  if (! fpa_consts_inited)
+    init_fpa_table ();
+
+  for (i = 0; i < 8; i++)
+    if (REAL_VALUES_EQUAL (*r, values_fpa[i]))
+      return strings_fpa[i];
+
+  abort ();
+}
 
 /* Output the operands of a LDM/STM instruction to STREAM.
    MASK is the ARM register set mask of which only bits 0-15 are important.
@@ -891,10 +916,10 @@ output_call (operands)
   if (REGNO (operands[0]) == 14)
     {
       operands[0] = gen_rtx (REG, SImode, 12);
-      output_asm_insn ("mov\t%0, lr", operands);
+      output_asm_insn ("mov%?\t%0, lr", operands);
     }
-  output_asm_insn ("mov\tlr, pc", operands);
-  output_asm_insn ("mov\tpc, %0", operands);
+  output_asm_insn ("mov%?\tlr, pc", operands);
+  output_asm_insn ("mov%?\tpc, %0", operands);
   return "";
 }
 
@@ -940,10 +965,10 @@ output_call_mem (operands)
   /* Handle calls using lr by using ip (which may be clobbered in subr anyway).
    */
   if (eliminate_lr2ip (&operands[0]))
-    output_asm_insn ("mov\tip, lr", operands);
+    output_asm_insn ("mov%?\tip, lr", operands);
 
-  output_asm_insn ("mov\tlr, pc", operands);
-  output_asm_insn ("ldr\tpc, %0", operands);
+  output_asm_insn ("mov%?\tlr, pc", operands);
+  output_asm_insn ("ldr%?\tpc, %0", operands);
   return "";
 }
 
@@ -966,8 +991,8 @@ output_mov_long_double_fpu_from_arm (operands)
   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
   ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
   
-  output_asm_insn ("stmfd\tsp!, {%0, %1, %2}", ops);
-  output_asm_insn ("ldfe\t%0, [sp], #12", operands);
+  output_asm_insn ("stm%?fd\tsp!, {%0, %1, %2}", ops);
+  output_asm_insn ("ldf%?e\t%0, [sp], #12", operands);
   return "";
 }
 
@@ -989,8 +1014,8 @@ output_mov_long_double_arm_from_fpu (operands)
   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
   ops[2] = gen_rtx (REG, SImode, 2 + arm_reg0);
 
-  output_asm_insn ("stfe\t%1, [sp, #-12]!", operands);
-  output_asm_insn ("ldmfd\tsp!, {%0, %1, %2}", ops);
+  output_asm_insn ("stf%?e\t%1, [sp, #-12]!", operands);
+  output_asm_insn ("ldm%?fd\tsp!, {%0, %1, %2}", ops);
   return "";
 }
 
@@ -1013,7 +1038,7 @@ output_mov_long_double_arm_from_arm (operands)
        {
          ops[0] = gen_rtx (REG, SImode, dest_start + i);
          ops[1] = gen_rtx (REG, SImode, src_start + i);
-         output_asm_insn ("mov\t%0, %1", ops);
+         output_asm_insn ("mov%?\t%0, %1", ops);
        }
     }
   else
@@ -1022,7 +1047,7 @@ output_mov_long_double_arm_from_arm (operands)
        {
          ops[0] = gen_rtx (REG, SImode, dest_start + i);
          ops[1] = gen_rtx (REG, SImode, src_start + i);
-         output_asm_insn ("mov\t%0, %1", ops);
+         output_asm_insn ("mov%?\t%0, %1", ops);
        }
     }
 
@@ -1045,8 +1070,8 @@ output_mov_double_fpu_from_arm (operands)
     abort();
   ops[0] = gen_rtx (REG, SImode, arm_reg0);
   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
-  output_asm_insn ("stmfd\tsp!, {%0, %1}", ops);
-  output_asm_insn ("ldfd\t%0, [sp], #8", operands);
+  output_asm_insn ("stm%?fd\tsp!, {%0, %1}", ops);
+  output_asm_insn ("ldf%?d\t%0, [sp], #8", operands);
   return "";
 }
 
@@ -1066,8 +1091,8 @@ output_mov_double_arm_from_fpu (operands)
 
   ops[0] = gen_rtx (REG, SImode, arm_reg0);
   ops[1] = gen_rtx (REG, SImode, 1 + arm_reg0);
-  output_asm_insn ("stfd\t%1, [sp, #-8]!", operands);
-  output_asm_insn ("ldmfd\tsp!, {%0, %1}", ops);
+  output_asm_insn ("stf%?d\t%1, [sp, #-8]!", operands);
+  output_asm_insn ("ldm%?fd\tsp!, {%0, %1}", ops);
   return "";
 }
 
@@ -1099,13 +1124,13 @@ output_move_double (operands)
          /* Ensure the second source is not overwritten */
          if (reg0 == 1 + reg1)
            {
-             output_asm_insn("mov\t%0, %1", otherops);
-             output_asm_insn("mov\t%0, %1", operands);
+             output_asm_insn("mov%?\t%0, %1", otherops);
+             output_asm_insn("mov%?\t%0, %1", operands);
            }
          else
            {
-             output_asm_insn("mov\t%0, %1", operands);
-             output_asm_insn("mov\t%0, %1", otherops);
+             output_asm_insn("mov%?\t%0, %1", operands);
+             output_asm_insn("mov%?\t%0, %1", otherops);
            }
        }
       else if (code1 == CONST_DOUBLE)
@@ -1124,9 +1149,9 @@ output_move_double (operands)
          /* Note: output_mov_immediate may clobber operands[1], so we
             put this out first */
          if (INTVAL (operands[1]) < 0)
-           output_asm_insn ("mvn\t%0, %1", otherops);
+           output_asm_insn ("mvn%?\t%0, %1", otherops);
          else
-           output_asm_insn ("mov\t%0, %1", otherops);
+           output_asm_insn ("mov%?\t%0, %1", otherops);
          output_mov_immediate (operands, FALSE, "");
        }
       else if (code1 == MEM)
@@ -1136,40 +1161,35 @@ output_move_double (operands)
            case REG:
              /* Handle the simple case where address is [r, #0] more
                 efficient.  */
-             operands[1] = XEXP (operands[1], 0);
-             output_asm_insn ("ldmia\t%1, %M0", operands);
+             output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
              break;
            case PRE_INC:
-             operands[1] = XEXP (XEXP (operands[1], 0), 0);
-             output_asm_insn ("add\t%1, %1, #8", operands);
-             output_asm_insn ("ldmia\t%1, %M0", operands);
+             output_asm_insn ("add%?\t%m1, %m1, #8", operands);
+             output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
              break;
            case PRE_DEC:
-             operands[1] = XEXP (XEXP (operands[1], 0), 0);
-             output_asm_insn ("sub\t%1, %1, #8", operands);
-             output_asm_insn ("ldmia\t%1, %M0", operands);
+             output_asm_insn ("sub%?\t%m1, %m1, #8", operands);
+             output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
              break;
            case POST_INC:
-             operands[1] = XEXP (XEXP (operands[1], 0), 0);
-             output_asm_insn ("ldmia\t%1!, %M0", operands);
+             output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
              break;
            case POST_DEC:
-             operands[1] = XEXP (XEXP (operands[1], 0), 0);
-             output_asm_insn ("ldmia\t%1, %M0", operands);
-             output_asm_insn ("sub\t%1, %1, #8", operands);
+             output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
+             output_asm_insn ("sub%?\t%m1, %m1, #8", operands);
              break;
            default:
              otherops[1] = adj_offsettable_operand (operands[1], 4);
              /* Take care of overlapping base/data reg.  */
              if (reg_mentioned_p (operands[0], operands[1]))
                {
-                 output_asm_insn ("ldr\t%0, %1", otherops);
-                 output_asm_insn ("ldr\t%0, %1", operands);
+                 output_asm_insn ("ldr%?\t%0, %1", otherops);
+                 output_asm_insn ("ldr%?\t%0, %1", operands);
                }
              else
                {
-                 output_asm_insn ("ldr\t%0, %1", operands);
-                 output_asm_insn ("ldr\t%0, %1", otherops);
+                 output_asm_insn ("ldr%?\t%0, %1", operands);
+                 output_asm_insn ("ldr%?\t%0, %1", otherops);
                }
            }
        }
@@ -1182,39 +1202,34 @@ output_move_double (operands)
       switch (GET_CODE (XEXP (operands[0], 0)))
         {
        case REG:
-         operands[0] = XEXP (operands[0], 0);
-         output_asm_insn ("stmia\t%0, %M1", operands);
+         output_asm_insn ("stm%?ia\t%m0, %M1", operands);
          break;
         case PRE_INC:
-         operands[0] = XEXP (XEXP (operands[0], 0), 0);
-         output_asm_insn ("add\t%0, %0, #8", operands);
-         output_asm_insn ("stmia\t%0, %M1", operands);
+         output_asm_insn ("add%?\t%m0, %m0, #8", operands);
+         output_asm_insn ("stm%?ia\t%m0, %M1", operands);
          break;
         case PRE_DEC:
-         operands[0] = XEXP (XEXP (operands[0], 0), 0);
-         output_asm_insn ("sub\t%0, %0, #8", operands);
-         output_asm_insn ("stmia\t%0, %M1", operands);
+         output_asm_insn ("sub%?\t%m0, %m0, #8", operands);
+         output_asm_insn ("stm%?ia\t%m0, %M1", operands);
          break;
         case POST_INC:
-         operands[0] = XEXP (XEXP (operands[0], 0), 0);
-         output_asm_insn ("stmia\t%0!, %M1", operands);
+         output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
          break;
         case POST_DEC:
-         operands[0] = XEXP (XEXP (operands[0], 0), 0);
-         output_asm_insn ("stmia\t%0, %M1", operands);
-         output_asm_insn ("sub\t%0, %0, #8", operands);
+         output_asm_insn ("stm%?ia\t%m0, %M1", operands);
+         output_asm_insn ("sub%?\t%m0, %m0, #8", operands);
          break;
         default:
          otherops[0] = adj_offsettable_operand (operands[0], 4);
          otherops[1] = gen_rtx (REG, SImode, 1 + REGNO (operands[1]));
-         output_asm_insn ("str\t%1, %0", operands);
-         output_asm_insn ("str\t%1, %0", otherops);
+         output_asm_insn ("str%?\t%1, %0", operands);
+         output_asm_insn ("str%?\t%1, %0", otherops);
        }
     }
   else abort();  /* Constraints should prevent this */
 
-  return("");
-} /* output_move_double */
+  return "";
+}
 
 
 /* Output an arbitrary MOV reg, #n.
@@ -1231,7 +1246,7 @@ output_mov_immediate (operands)
   /* Try to use one MOV */
   if (const_ok_for_arm (n))
     {
-      output_asm_insn ("mov\t%0, %1", operands);
+      output_asm_insn ("mov%?\t%0, %1", operands);
       return "";
     }
 
@@ -1239,7 +1254,7 @@ output_mov_immediate (operands)
   if (const_ok_for_arm (~n))
     {
       operands[1] = GEN_INT (~n);
-      output_asm_insn ("mvn\t%0, %1", operands);
+      output_asm_insn ("mvn%?\t%0, %1", operands);
       return "";
     }
 
@@ -1250,9 +1265,11 @@ output_mov_immediate (operands)
       n_ones++;
 
   if (n_ones > 16)  /* Shorter to use MVN with BIC in this case. */
-    output_multi_immediate(operands, "mvn\t%0, %1", "bic\t%0, %0, %1", 1, ~n);
+    output_multi_immediate(operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1,
+                          ~n);
   else
-    output_multi_immediate(operands, "mov\t%0, %1", "orr\t%0, %0, %1", 1, n);
+    output_multi_immediate(operands, "mov%?\t%0, %1", "orr%?\t%0, %0, %1", 1,
+                          n);
 
   return "";
 }
@@ -1271,16 +1288,17 @@ output_add_immediate (operands)
     {
       if (n < 0)
        output_multi_immediate (operands,
-                               "sub\t%0, %1, %2", "sub\t%0, %0, %2", 2, -n);
+                               "sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
+                               -n);
       else
        output_multi_immediate (operands,
-                               "add\t%0, %1, %2", "add\t%0, %0, %2", 2, n);
+                               "add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
+                               n);
     }
 
   return "";
 }
 
-
 /* Output a multiple immediate operation.
    OPERANDS is the vector of operands referred to in the output patterns.
    INSTR1 is the output pattern to use for the first constant.
@@ -1322,7 +1340,7 @@ output_multi_immediate (operands, instr1, instr2, immed_op, n)
        }
     }
   return "";
-} /* output_multi_immediate */
+}
 
 
 /* Return the appropriate ARM instruction for the operation code.
@@ -1335,7 +1353,7 @@ arithmetic_instr (op, shift_first_arg)
      rtx op;
      int shift_first_arg;
 {
-  switch (GET_CODE(op))
+  switch (GET_CODE (op))
     {
     case PLUS:
       return "add";
@@ -1361,18 +1379,26 @@ arithmetic_instr (op, shift_first_arg)
 /* Ensure valid constant shifts and return the appropriate shift mnemonic
    for the operation code.  The returned result should not be overwritten.
    OP is the rtx code of the shift.
-   SHIFT_PTR points to the shift size operand.  */
+   On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
+   shift. */
 
-char *
-shift_instr (op, shift_ptr)
-     enum rtx_code op;
-     rtx *shift_ptr;
+static char *
+shift_op (op, amountp)
+     rtx op;
+     HOST_WIDE_INT *amountp;
 {
   int min_shift = 0;
   int max_shift = 31;
   char *mnem;
 
-  switch (op)
+  if (GET_CODE (XEXP (op, 1)) == REG || GET_CODE (XEXP (op, 1)) == SUBREG)
+    *amountp = -1;
+  else if (GET_CODE (XEXP (op, 1)) == CONST_INT)
+    *amountp = INTVAL (XEXP (op, 1));
+  else
+    abort ();
+
+  switch (GET_CODE (op))
     {
     case ASHIFT:
       mnem = "asl";
@@ -1388,25 +1414,27 @@ shift_instr (op, shift_ptr)
       max_shift = 32;
       break;
 
+    case ROTATERT:
+      mnem = "ror";
+      max_shift = 31;
+      break;
+
     case MULT:
-      *shift_ptr = GEN_INT (int_log2 (INTVAL (*shift_ptr)));
+      if (*amountp != -1)
+       *amountp = int_log2 (*amountp);
+      else
+       abort ();
       return "asl";
 
     default:
       abort ();
     }
 
-  if (GET_CODE (*shift_ptr) == CONST_INT)
-    {
-      int shift = INTVAL (*shift_ptr);
-
-      if (shift < min_shift)
-       *shift_ptr = gen_rtx (CONST_INT, VOIDmode, 0);
-      else if (shift > max_shift)
-       *shift_ptr = gen_rtx (CONST_INT, VOIDmode, max_shift);
-    }
-  return (mnem);
-} /* shift_instr */
+  if (*amountp != -1
+      && (*amountp < min_shift || *amountp > max_shift))
+    abort ();
+  return mnem;
+}
 
 
 /* Obtain the shift from the POWER of two. */
@@ -1427,119 +1455,6 @@ int_log2 (power)
   return shift;
 }
 
-
-/* Output an arithmetic instruction which may set the condition code.
-   OPERANDS[0] is the destination register.
-   OPERANDS[1] is the arithmetic operator expression.
-   OPERANDS[2] is the left hand argument.
-   OPERANDS[3] is the right hand argument.
-   CONST_FIRST_ARG is TRUE if the first argument of the operator was constant.
-   SET_COND is TRUE when the condition code should be set.  */
-
-char *
-output_arithmetic (operands, const_first_arg, set_cond)
-     rtx *operands;
-     int const_first_arg;
-     int set_cond;
-{
-  char mnemonic[80];
-  char *instr = arithmetic_instr (operands[1], const_first_arg);
-
-  sprintf (mnemonic, "%s%s\t%%0, %%2, %%3", instr, set_cond ? "s" : "");
-  output_asm_insn (mnemonic, operands);
-  return "";
-}
-
-
-/* Output an arithmetic instruction with a shift.
-   OPERANDS[0] is the destination register.
-   OPERANDS[1] is the arithmetic operator expression.
-   OPERANDS[2] is the unshifted register.
-   OPERANDS[3] is the shift operator expression.
-   OPERANDS[4] is the shifted register.
-   OPERANDS[5] is the shift constant or register.
-   SHIFT_FIRST_ARG is TRUE if the first argument of the operator was shifted.
-   SET_COND is TRUE when the condition code should be set.  */
-
-char *
-output_arithmetic_with_shift (operands, shift_first_arg, set_cond)
-     rtx *operands;
-     int shift_first_arg;
-     int set_cond;
-{
-  char mnemonic[80];
-  char *instr = arithmetic_instr (operands[1], shift_first_arg);
-  char *condbit = set_cond ? "s" : "";
-  char *shift = shift_instr (GET_CODE (operands[3]), &operands[5]);
-
-  sprintf (mnemonic, "%s%s\t%%0, %%2, %%4, %s %%5", instr, condbit, shift);
-  output_asm_insn (mnemonic, operands);
-  return "";
-}
-
-/* Output an arithmetic instruction with a power of two multiplication.
-   OPERANDS[0] is the destination register.
-   OPERANDS[1] is the arithmetic operator expression.
-   OPERANDS[2] is the unmultiplied register.
-   OPERANDS[3] is the multiplied register.
-   OPERANDS[4] is the constant multiple (power of two).
-   SHIFT_FIRST_ARG is TRUE if the first arg of the operator was multiplied.  */
-
-char *
-output_arithmetic_with_immediate_multiply (operands, shift_first_arg)
-     rtx *operands;
-     int shift_first_arg;
-{
-  char mnemonic[80];
-  char *instr = arithmetic_instr (operands[1], shift_first_arg);
-  HOST_WIDE_INT shift = int_log2 (INTVAL (operands[4]));
-
-  sprintf (mnemonic, "%s\t%%0, %%2, %%3, asl#%d", instr, (int) shift);
-  output_asm_insn (mnemonic, operands);
-  return "";
-}
-
-
-/* Output a move with a shift.
-   OP is the shift rtx code.
-   OPERANDS[0] = destination register.
-   OPERANDS[1] = source register.
-   OPERANDS[2] = shift constant or register.  */
-
-char *
-output_shifted_move (op, operands)
-     enum rtx_code op;
-     rtx *operands;
-{
-  char mnemonic[80];
-
-  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)
-    sprintf (mnemonic, "mov\t%%0, %%1");
-  else
-    sprintf (mnemonic, "mov\t%%0, %%1, %s %%2",
-            shift_instr (op, &operands[2]));
-
-  output_asm_insn (mnemonic, operands);
-  return "";
-}
-
-char *
-output_shift_compare (operands, neg)
-     rtx *operands;
-     int neg;
-{
-  char buf[80];
-
-  if (neg)
-    sprintf (buf, "cmn\t%%1, %%3, %s %%4", shift_instr (GET_CODE (operands[2]),
-                                                       &operands[4]));
-  else
-    sprintf (buf, "cmp\t%%1, %%3, %s %%4", shift_instr (GET_CODE (operands[2]),
-                                                       &operands[4]));
-  output_asm_insn (buf, operands);
-  return "";
-}
-
 /* Output a .ascii pseudo-op, keeping track of lengths.  This is because
    /bin/as is horribly restrictive.  */
 
@@ -1760,9 +1675,9 @@ output_return_instruction (operand, really_return)
         live_regs++;
 
       if (frame_pointer_needed)
-        strcpy (instr, "ldm%d0ea\tfp, {");
+        strcpy (instr, "ldm%?%d0ea\tfp, {");
       else
-        strcpy (instr, "ldm%d0fd\tsp!, {");
+        strcpy (instr, "ldm%?%d0fd\tsp!, {");
 
       for (reg = 0; reg <= 10; reg++)
         if (regs_ever_live[reg] && ! call_used_regs[reg])
@@ -1787,7 +1702,7 @@ output_return_instruction (operand, really_return)
     }
   else if (really_return)
     {
-      strcpy (instr, TARGET_6 ? "mov%d0\tpc, lr" : "mov%d0s\tpc, lr");
+      strcpy (instr, TARGET_6 ? "mov%?%d0\tpc, lr" : "mov%?%d0s\tpc, lr");
       output_asm_insn (instr, &operand);
     }
 
@@ -2052,6 +1967,153 @@ output_func_epilogue (f, frame_size)
   current_function_anonymous_args = 0;
 }
 \f
+/* If CODE is 'd', then the X is a condition operand and the instruction
+   should only be executed if the condition is true.
+   if CODE is 'D', then the X is a condition operand and the instruciton
+   should only be executed if the condition is false: however, if the mode
+   of the comparison is CCFPEmode, then always execute the instruction -- we
+   do this because in these circumstances !GE does not necessarily imply LT;
+   in these cases the instruction pattern will take care to make sure that
+   an instruction containing %d will follow, thereby undoing the effects of
+   doing this instrucion unconditionally.
+   If CODE is 'N' then X is a floating point operand that must be negated
+   before output.
+   If CODE is 'B' then output a bitwise inverted value of X (a const int).
+   If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
+
+void
+arm_print_operand (stream, x, code)
+     FILE *stream;
+     rtx x;
+     int code;
+{
+  switch (code)
+    {
+    case '@':
+      fputc (ARM_COMMENT_CHAR, stream);
+      return;
+
+    case '|':
+      fputs (ARM_REG_PREFIX, stream);
+      return;
+
+    case '?':
+      if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
+       fputs (arm_condition_codes[arm_current_cc], stream);
+      return;
+
+    case 'N':
+      {
+       REAL_VALUE_TYPE r;
+       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+       r = REAL_VALUE_NEGATE (r);
+       fprintf (stream, "%s", fp_const_from_val (&r));
+      }
+      return;
+
+    case 'B':
+      if (GET_CODE (x) == CONST_INT)
+       fprintf (stream,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+                "%d",
+#else
+                "%ld",
+#endif
+                ARM_SIGN_EXTEND (~ INTVAL (x)));
+      else
+       {
+         putc ('~', stream);
+         output_addr_const (stream, x);
+       }
+      return;
+
+    case 'i':
+      fprintf (stream, "%s", arithmetic_instr (x, 1));
+      return;
+
+    case 'I':
+      fprintf (stream, "%s", arithmetic_instr (x, 0));
+      return;
+
+    case 'S':
+      {
+       HOST_WIDE_INT val;
+
+       fprintf (stream, "%s ", shift_op (x, &val));
+       if (val == -1)
+         arm_print_operand (stream, XEXP (x, 1), 0);
+       else
+         fprintf (stream,
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+                  "#%d",
+#else
+                  "#%ld",
+#endif
+                  val);
+      }
+      return;
+
+    case 'R':
+      if (REGNO (x) > 15)
+       abort ();
+      fputs (reg_names[REGNO (x) + 1], stream);
+      return;
+
+    case 'm':
+      if (GET_CODE (XEXP (x, 0)) == REG)
+       fputs (reg_names[REGNO (XEXP (x, 0))], stream);
+      else
+       fputs (reg_names[REGNO (XEXP (XEXP (x, 0), 0))], stream);
+      return;
+
+    case 'M':
+      fprintf (stream, "{%s-%s}", reg_names[REGNO (x)],
+              reg_names[REGNO (x) - 1
+                        + ((GET_MODE_SIZE (GET_MODE (x))
+                            + GET_MODE_SIZE (SImode) - 1)
+                           / GET_MODE_SIZE (SImode))]);
+      return;
+
+    case 'd':
+      if (x)
+        fputs (arm_condition_codes[get_arm_condition_code (x)],
+              stream);
+      return;
+
+    case 'D':
+      if (x && (flag_fast_math
+               || GET_CODE (x) == EQ || GET_CODE (x) == NE
+               || (GET_MODE (XEXP (x, 0)) != CCFPEmode
+                   && (GET_MODE_CLASS (GET_MODE (XEXP (x, 0)))
+                       != MODE_FLOAT))))
+        fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
+                                  (get_arm_condition_code (x))],
+              stream);
+      return;
+
+    default:
+      if (x == 0)
+       abort ();
+
+      if (GET_CODE (x) == REG)
+       fputs (reg_names[REGNO (x)], stream);
+      else if (GET_CODE (x) == MEM)
+       {
+         output_memory_reference_mode = GET_MODE (x);
+         output_address (XEXP (x, 0));
+       }
+      else if (GET_CODE (x) == CONST_DOUBLE)
+       fprintf (stream, "#%s", fp_immediate_constant (x));
+      else if (GET_CODE (x) == NEG)
+       abort (); /* This should never happen now. */
+      else
+       {
+         fputc ('#', stream);
+         output_addr_const (stream, x);
+       }
+    }
+}
+
 /* Increase the `arm_text_location' by AMOUNT if we're in the text
    segment.  */
 
@@ -2143,7 +2205,7 @@ output_load_symbol (insn, operands)
     abort ();
 
   /* When generating the instructions, we never mask out the bits that we
-     think will be always zero, then if a mistake has occureed somewhere, the
+     think will be always zero, then if a mistake has occured somewhere, the
      assembler will spot it and generate an error.  */
 
   /* If the symbol is word aligned then we might be able to reduce the
@@ -2166,12 +2228,12 @@ output_load_symbol (insn, operands)
     {
       if (inst == 8)
        {
-         strcpy (buffer, "sub\t%0, pc, #(8 + . -%a1)");
+         strcpy (buffer, "sub%?\t%0, pc, #(8 + . -%a1)");
          if ((never_mask | mask) != 0xffffffff)
            sprintf (buffer + strlen (buffer), " & 0x%x", mask | never_mask);
        }
       else
-       sprintf (buffer, "sub\t%%0, %%0, #(%d + . -%%a1) & 0x%x",
+       sprintf (buffer, "sub%%?\t%%0, %%0, #(%d + . -%%a1) & 0x%x",
                 inst, mask | never_mask);
 
       output_asm_insn (buffer, operands);
@@ -2235,15 +2297,6 @@ output_lcomm_directive (stream, name, size, rounded)
    time.  But then, I want to reduce the code size to somewhere near what
    /bin/cc produces.  */
 
-/* The condition codes of the ARM, and the inverse function.  */
-char *arm_condition_codes[] =
-{
-  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
-  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
-};
-
-#define ARM_INVERSE_CONDITION_CODE(X)  ((X) ^ 1)
-
 /* Returns the index of the ARM condition code string in
    `arm_condition_codes'.  COMPARISON should be an rtx like
    `(eq (...) (...))'.  */