Convert pdp11 back end to CCmode.
authorPaul Koning <ni1d@arrl.net>
Wed, 27 Jun 2018 21:58:24 +0000 (17:58 -0400)
committerPaul Koning <pkoning@gcc.gnu.org>
Wed, 27 Jun 2018 21:58:24 +0000 (17:58 -0400)
* common/config/pdp11/pdp11-common.c (pdp11_handle_option): Handle
mutually exclusive options.
* config/pdp11/constraints.md (h): New constraint.
(O): Update definition to match shift code generation.
(D): New constraint.
* config/pdp11/pdp11-modes.def (CCNZ): Define mode.
(CCFP): Remove.
* config/pdp11/pdp11-protos.h (int_no_side_effect_operand): New
function.
(output_jump): Change arguments.
(pdp11_fixed_cc_regs): New function.
(pdp11_cc_mode): Ditto.
(pdp11_expand_shift): Ditto.
(pdp11_assemble_shift): Ditto.
(pdp11_small_shift): Ditto.
(pdp11_branch_cost): Remove.
* config/pdp11/pdp11.c (pdp11_assemble_integer): Remove comments
from output.
(pdp11_register_move_cost): Update for CC registers.
(pdp11_rtx_costs): Add case for LSHIFTRT.
(pdp11_output_jump): Add CCNZ mode conditional branches.
(notice_update_cc_on_set): Remove.
(pdp11_cc_mode): New function.
(simple_memory_operand): Correct pre/post decrement case.
(no_side_effect_operand): New function.
(pdp11_regno_reg_class): Add CC_REGS class.
(pdp11_fixed_cc_regs): New function.
(pdp11_small_shift): New function.
(pdp11_expand_shift): New function to expand shift insns.
(pdp11_assemble_shift): New function to output shifts.
(pdp11_branch_cost): Remove.
(pdp11_modes_tieable_p): Make QI/HI modes tieable.
* config/pdp11/pdp11.h (SIZE_TYPE): Ensure 16-bit type.
(WCHAR_TYPE): Ditto.
(PTRDIFF_TYPE): Ditto.
(ADJUST_INSN_LENGTH): New macro.
(FIXED_REGISTERS): Add CC registers.
(CALL_USED_REGISTERS): Ditto.
(reg_class): Ditto.
(REG_CLASS_NAMES): Ditto.
(REG_CLASS_CONTENTS): Ditto.
(SELECT_CC_MODE): Use new function.
(TARGET_FLAGS_REGNUM): New macro.
(TARGET_FIXED_CONDITION_CODE_REGS): Ditto.
(cc0_reg_rtx): Remove.
(CC_STATUS_MDEP): Remove.
(CC_STATUS_MDEFP_INIT): Remove.
(CC_IN_FPU): Remove.
(NOTICE_UPDATE_CC): Remove.
(REGISTER_NAMES): Add CC registers.
(BRANCH_COST): Change to constant 1.
* config/pdp11/pdp11.md: Rewrite for CCmode condition code
handling.
* config/pdp11/pdp11.opt (mbcopy): Remove.
(mbcopy-builtin): Remove.
(mbranch-cheap): Remove.
(mbranch-expensive): Remove.
* config/pdp11/predicates.md (expand_shift_operand): Update to
match shift code generation.
(ccnz_operator): New predicate.
* doc/invoke.texi (PDP-11 Options): Remove deleted options
-mbcopy, -mbcopy-builtin, -mbranch-cheap, -mbranch-expensive.
Remove non-existent option -mabshi, -mno-abshi.  Document mutually
exclusive options.
* doc/md.texi (PDP-11): Document new D and h constraints.  Update
description of O constraint.

From-SVN: r262198

12 files changed:
gcc/ChangeLog
gcc/common/config/pdp11/pdp11-common.c
gcc/config/pdp11/constraints.md
gcc/config/pdp11/pdp11-modes.def
gcc/config/pdp11/pdp11-protos.h
gcc/config/pdp11/pdp11.c
gcc/config/pdp11/pdp11.h
gcc/config/pdp11/pdp11.md
gcc/config/pdp11/pdp11.opt
gcc/config/pdp11/predicates.md
gcc/doc/invoke.texi
gcc/doc/md.texi

index c435a3b29a7ddfdc80a91a98c372d1abd1cc567c..fc0550460b879aded8c6d9440c490deca03e0091 100644 (file)
@@ -1,3 +1,72 @@
+2018-06-27  Paul Koning  <ni1d@arrl.net>
+
+       * common/config/pdp11/pdp11-common.c (pdp11_handle_option): Handle
+       mutually exclusive options.
+       * config/pdp11/constraints.md (h): New constraint.
+       (O): Update definition to match shift code generation.
+       (D): New constraint.
+       * config/pdp11/pdp11-modes.def (CCNZ): Define mode.
+       (CCFP): Remove.
+       * config/pdp11/pdp11-protos.h (int_no_side_effect_operand): New
+       function.
+       (output_jump): Change arguments.
+       (pdp11_fixed_cc_regs): New function.
+       (pdp11_cc_mode): Ditto.
+       (pdp11_expand_shift): Ditto.
+       (pdp11_assemble_shift): Ditto.
+       (pdp11_small_shift): Ditto.
+       (pdp11_branch_cost): Remove.
+       * config/pdp11/pdp11.c (pdp11_assemble_integer): Remove comments
+       from output.
+       (pdp11_register_move_cost): Update for CC registers.
+       (pdp11_rtx_costs): Add case for LSHIFTRT.
+       (pdp11_output_jump): Add CCNZ mode conditional branches.
+       (notice_update_cc_on_set): Remove.
+       (pdp11_cc_mode): New function.
+       (simple_memory_operand): Correct pre/post decrement case.
+       (no_side_effect_operand): New function.
+       (pdp11_regno_reg_class): Add CC_REGS class.
+       (pdp11_fixed_cc_regs): New function.
+       (pdp11_small_shift): New function.
+       (pdp11_expand_shift): New function to expand shift insns.
+       (pdp11_assemble_shift): New function to output shifts.
+       (pdp11_branch_cost): Remove.
+       (pdp11_modes_tieable_p): Make QI/HI modes tieable.
+       * config/pdp11/pdp11.h (SIZE_TYPE): Ensure 16-bit type.
+       (WCHAR_TYPE): Ditto.
+       (PTRDIFF_TYPE): Ditto.
+       (ADJUST_INSN_LENGTH): New macro.
+       (FIXED_REGISTERS): Add CC registers.
+       (CALL_USED_REGISTERS): Ditto.
+       (reg_class): Ditto.
+       (REG_CLASS_NAMES): Ditto.
+       (REG_CLASS_CONTENTS): Ditto.
+       (SELECT_CC_MODE): Use new function.
+       (TARGET_FLAGS_REGNUM): New macro.
+       (TARGET_FIXED_CONDITION_CODE_REGS): Ditto.
+       (cc0_reg_rtx): Remove.
+       (CC_STATUS_MDEP): Remove.
+       (CC_STATUS_MDEFP_INIT): Remove.
+       (CC_IN_FPU): Remove.
+       (NOTICE_UPDATE_CC): Remove.
+       (REGISTER_NAMES): Add CC registers.
+       (BRANCH_COST): Change to constant 1.
+       * config/pdp11/pdp11.md: Rewrite for CCmode condition code
+       handling.
+       * config/pdp11/pdp11.opt (mbcopy): Remove.
+       (mbcopy-builtin): Remove.
+       (mbranch-cheap): Remove.
+       (mbranch-expensive): Remove.
+       * config/pdp11/predicates.md (expand_shift_operand): Update to
+       match shift code generation.
+       (ccnz_operator): New predicate.
+       * doc/invoke.texi (PDP-11 Options): Remove deleted options
+       -mbcopy, -mbcopy-builtin, -mbranch-cheap, -mbranch-expensive.
+       Remove non-existent option -mabshi, -mno-abshi.  Document mutually
+       exclusive options.
+       * doc/md.texi (PDP-11): Document new D and h constraints.  Update
+       description of O constraint.
+
 2018-06-27  Jeff Law  <law@redhat.com>
            Austin Law  <austinklaw@gmail.com>
 
index aa809a9d457dd67d49d2770794ad2cc946360035..9feb4fd4ea1541f138aa9a3281c9768e8962c240 100644 (file)
@@ -39,9 +39,27 @@ pdp11_handle_option (struct gcc_options *opts,
   switch (code)
     {
     case OPT_m10:
-      opts->x_target_flags &= ~(MASK_40 | MASK_45);
+      opts->x_target_flags &= ~(MASK_40 | MASK_45 | MASK_FPU | MASK_AC0 | MASK_SPLIT);
       return true;
 
+    case OPT_m40:
+      opts->x_target_flags &= ~(MASK_45 | MASK_FPU | MASK_AC0 | MASK_SPLIT);
+      return true;
+
+    case OPT_mfpu:
+      opts->x_target_flags &= ~MASK_40;
+      opts->x_target_flags |= MASK_45;
+      return true;
+      
+    case OPT_msoft_float:
+      opts->x_target_flags &= ~MASK_AC0;
+      return true;
+
+    case OPT_msplit:
+      opts->x_target_flags &= ~MASK_40;
+      opts->x_target_flags |= MASK_45;
+      return true;
+      
     default:
       return true;
     }
index 0d78dd86835ca0c89e272880c871f904c0b7e20b..10bf1204716350a6c1ef9cfb42a21b30df245ab1 100644 (file)
 ;; along with GCC; see the file COPYING3.  If not see
 ;; <http://www.gnu.org/licenses/>.
 
+(define_register_constraint "a" "LOAD_FPU_REGS"
+  "FPU register that can be directly loaded from memory")
+
 (define_register_constraint "f" "FPU_REGS"
   "Any FPU register")
 
-(define_register_constraint "a" "LOAD_FPU_REGS"
-  "FPU register that can be directly loaded from memory")
+(define_register_constraint "h" "NO_LOAD_FPU_REGS"
+  "FPU register that cannot be directly loaded from memory")
 
 (define_register_constraint "d" "MUL_REGS"
   "General register that can be used for 16-bit multiply (odd numbered)")
@@ -60,7 +63,7 @@
 (define_constraint "O"
   "Integer constant for which several individual shifts are better than one big one"
   (and (match_code "const_int")
-       (match_test "abs (ival) > 1 && abs (ival) <= 4")))
+       (match_test "pdp11_small_shift (ival)")))
 
 (define_constraint "G"
   "Defines a real zero constant."
@@ -79,3 +82,9 @@
        (match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
                     && simple_memory_operand (op, GET_MODE (op))")))
 
+(define_constraint "D"
+  "Memory reference that is encoded within the opcode, and not push or pop"
+  (and (match_code "mem")
+       (match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
+                    && no_side_effect_operand (op, GET_MODE (op))")))
+
index a49994acf0990b900259f33bb8ad25f10461ed80..164889eae873c0a3bbcea53183be14de775c31c8 100644 (file)
@@ -19,8 +19,26 @@ along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
 /* Add any extra modes needed to represent the condition code.
-   CCFPmode is used for FPU, but should we use a separate reg? */
 
-CC_MODE (CCFP);
+   The default CCmode is the CPU condition codes, as set by compare;
+   all conditional branches are valid with this.
+
+   CCNZmode is the CPU condition code as a side effect of arithmetic
+   or logic operations where N and Z reflect sign and zero status of
+   the result, but the V bit is not meaningful.  Unsigned conditional
+   branches don't apply then (no such thing when comparing with zero)
+   and signed branches that use V need to clear V first if they are to
+   be used.  CCNZ mode appears in side effects (implicit compare with
+   zero) if V is not forced to 0 by the instruction.  In such cases, V
+   often reflects signed overflow of the operation, which means a
+   signed branch will get the sign backwards.  This applies both to
+   some float and integer operations.
+
+   These modes are used both in the FPU and the CPU, since they have
+   the same meaning, and also because the FPU condition codes are
+   copied to the CPU before being used in conditional branches.  */
+
+CC_MODE (CCNZ);
+
 RESET_FLOAT_FORMAT (SF, pdp11_f_format);
 RESET_FLOAT_FORMAT (DF, pdp11_d_format);
index c5096b0d79332fab618ee2155ad4c0cee1022bc5..453632314d7fd699983b49f4c46fedee0acd2170 100644 (file)
@@ -21,21 +21,27 @@ along with GCC; see the file COPYING3.  If not see
 /* declarations */
 #ifdef RTX_CODE
 extern int simple_memory_operand (rtx, machine_mode);
-
+extern int no_side_effect_operand (rtx, machine_mode);
 extern int legitimate_const_double_p (rtx);
 extern void notice_update_cc_on_set (rtx, rtx);
 extern void output_addr_const_pdp11 (FILE *, rtx);
 extern const char *output_move_multiple (rtx *);
 extern const char *output_block_move (rtx *);
-extern const char *output_jump (enum rtx_code, int, int);
+extern const char *output_jump (rtx *, int, int);
 extern void print_operand_address (FILE *, rtx);
 typedef enum { no_action, dec_before, inc_after } pdp11_action;
 typedef enum { little, either, big } pdp11_partorder;
-extern bool pdp11_expand_operands (rtx *, rtx [][2], int, 
+extern bool pdp11_expand_operands (rtx *, rtx [][2], int,
                                   pdp11_action *, pdp11_partorder);
 extern int pdp11_sp_frame_offset (void);
 extern int pdp11_initial_elimination_offset (int, int);
 extern enum reg_class pdp11_regno_reg_class (int);
+extern bool pdp11_fixed_cc_regs (unsigned int *, unsigned int *);
+extern machine_mode pdp11_cc_mode (enum rtx_code, rtx, rtx);
+extern bool pdp11_expand_shift (rtx *, rtx (*) (rtx, rtx, rtx),
+                               rtx (*) (rtx, rtx, rtx));
+extern const char * pdp11_assemble_shift (rtx *, machine_mode, int);
+extern bool pdp11_small_shift (int);
 
 #endif /* RTX_CODE */
 
@@ -43,5 +49,4 @@ extern void output_ascii (FILE *, const char *, int);
 extern void pdp11_asm_output_var (FILE *, const char *, int, int, bool);
 extern void pdp11_expand_prologue (void);
 extern void pdp11_expand_epilogue (void);
-extern int pdp11_branch_cost (void);
 extern poly_int64 pdp11_push_rounding (poly_int64);
index 38c55fbb3df97a9c956ae1ac58b184a5b83accb3..ab73693d1da4236172b8607d8d24e31e48599a7b 100644 (file)
@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "expr.h"
 #include "builtins.h"
 #include "dbxout.h"
+#include "expmed.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -146,9 +147,6 @@ decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
   (*vax_d_format.decode) (fmt, r, tbuf);
 }
 
-/* This is where the condition code register lives.  */
-/* rtx cc0_reg_rtx; - no longer needed? */
-
 static const char *singlemove_string (rtx *);
 static bool pdp11_assemble_integer (rtx, unsigned int, int);
 static bool pdp11_rtx_costs (rtx, machine_mode, int, int, int *, bool);
@@ -384,7 +382,7 @@ pdp11_expand_epilogue (void)
              emit_move_insn (reg, x);
            else
              {
-               emit_move_insn (via_ac, x);
+               emit_move_insn (via_ac, x);
                emit_move_insn (reg, via_ac);
              }
          }
@@ -872,48 +870,40 @@ pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
       case 1:
        fprintf (asm_out_file, "\t.byte\t");
        output_addr_const_pdp11 (asm_out_file, GEN_INT (INTVAL (x) & 0xff));
-;
-       fprintf (asm_out_file, " /* char */\n");
+       fputs ("\n", asm_out_file);
        return true;
 
       case 2:
        fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
        output_addr_const_pdp11 (asm_out_file, x);
-       fprintf (asm_out_file, " /* short */\n");
+       fputs ("\n", asm_out_file);
        return true;
       }
   return default_assemble_integer (x, size, aligned_p);
 }
 
 
-/* register move costs, indexed by regs */
-
-static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] = 
-{
-             /* NO  MUL  GEN  LFPU  NLFPU FPU ALL */
-
-/* NO */     {  0,   0,   0,    0,    0,    0,   0},
-/* MUL */    {  0,   2,   2,   22,   22,   22,  22},
-/* GEN */    {  0,   2,   2,   22,   22,   22,  22},
-/* LFPU */   {  0,  22,  22,    2,    2,    2,  22},
-/* NLFPU */  {  0,  22,  22,    2,   10,   10,  22},
-/* FPU */    {  0,  22,  22,    2,   10,   10,  22},
-/* ALL */    {  0,  22,  22,   22,   22,   22,  22}
-}  ;
-
-
-/* -- note that some moves are tremendously expensive, 
-   because they require lots of tricks! do we have to 
-   charge the costs incurred by secondary reload class 
-   -- as we do here with 10 -- or not ? */
-
+/* Register to register moves are cheap if both are general registers.
+   The same is true for FPU, but there we return cost of 3 rather than
+   2 to make reload look at the constraints.  The raeson is that
+   load/store double require extra care since load touches condition
+   codes and store doesn't, which is (partly anyway) described by
+   constraints.  */
 static int 
 pdp11_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
                          reg_class_t c1, reg_class_t c2)
 {
-    return move_costs[(int)c1][(int)c2];
+  if (((c1 == MUL_REGS || c1 == GENERAL_REGS) &&
+       (c2 == MUL_REGS || c2 == GENERAL_REGS)))
+    return 2;
+  else if ((c1 >= LOAD_FPU_REGS && c1 <= FPU_REGS && c2 == LOAD_FPU_REGS) ||
+          (c2 >= LOAD_FPU_REGS && c2 <= FPU_REGS && c1 == LOAD_FPU_REGS))
+    return 3;
+  else
+    return 22;
 }
 
+
 static bool
 pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
                 int opno ATTRIBUTE_UNUSED, int *total,
@@ -988,7 +978,6 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
       return false;
 
     case ASHIFT:
-    case LSHIFTRT:
     case ASHIFTRT:
       if (optimize_size)
         *total = COSTS_N_INSNS (1);
@@ -1020,114 +1009,134 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
         }
       return false;
 
+    case LSHIFTRT:
+      if (optimize_size)
+        *total = COSTS_N_INSNS (2);
+      else if (mode ==  QImode)
+        {
+          if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+           *total = COSTS_N_INSNS (12); /* worst case */
+          else
+           *total = COSTS_N_INSNS (1 + INTVAL (XEXP (x, 1)));
+        }
+      else if (mode == HImode)
+        {
+          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+            {
+             if (abs (INTVAL (XEXP (x, 1))) == 1)
+                *total = COSTS_N_INSNS (2);
+              else
+               *total = COSTS_N_INSNS (3.5 + 0.5 * INTVAL (XEXP (x, 1)));
+            }
+          else
+            *total = COSTS_N_INSNS (12); /* worst case */
+        }
+      else if (mode == SImode)
+        {
+          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+           *total = COSTS_N_INSNS (3.5 + 0.5 * INTVAL (XEXP (x, 1)));
+          else /* worst case */
+            *total = COSTS_N_INSNS (20);
+        }
+      return false;
+
     default:
       return false;
     }
 }
 
 const char *
-output_jump (enum rtx_code code, int inv, int length)
+output_jump (rtx *operands, int ccnz, int length)
 {
-    static int x = 0;
-    
-    static char buf[1000];
-    const char *pos, *neg;
+  rtx tmpop[1];
+  static char buf[100];
+  const char *pos, *neg;
+  enum rtx_code code = GET_CODE (operands[0]);
 
-    if (cc_prev_status.flags & CC_NO_OVERFLOW)
-      {
-       switch (code)
-         {
-         case GTU: code = GT; break;
-         case LTU: code = LT; break;
-         case GEU: code = GE; break;
-         case LEU: code = LE; break;
-         default: ;
-         }
-      }
-    switch (code)
-      {
-      case EQ: pos = "beq", neg = "bne"; break;
-      case NE: pos = "bne", neg = "beq"; break;
-      case GT: pos = "bgt", neg = "ble"; break;
-      case GTU: pos = "bhi", neg = "blos"; break;
-      case LT: pos = "blt", neg = "bge"; break;
-      case LTU: pos = "blo", neg = "bhis"; break;
-      case GE: pos = "bge", neg = "blt"; break;
-      case GEU: pos = "bhis", neg = "blo"; break;
-      case LE: pos = "ble", neg = "bgt"; break;
-      case LEU: pos = "blos", neg = "bhi"; break;
-      default: gcc_unreachable ();
-      }
-
-#if 0
-/* currently we don't need this, because the tstdf and cmpdf 
-   copy the condition code immediately, and other float operations are not 
-   yet recognized as changing the FCC - if so, then the length-cost of all
-   jump insns increases by one, because we have to potentially copy the 
-   FCC! */
-    if (cc_status.flags & CC_IN_FPU)
-       output_asm_insn("cfcc", NULL);
-#endif
-       
-    switch (length)
+  if (ccnz)
     {
-      case 2:
-       
-       sprintf(buf, "%s %%l1", inv ? neg : pos);
-       
-       return buf;
-       
-      case 6:
-       
-       sprintf(buf, "%s JMP_%d\n\tjmp %%l1\nJMP_%d:", inv ? pos : neg, x, x);
-       
-       x++;
-       
-       return buf;
-       
-      default:
-       
-       gcc_unreachable ();
+      /* These are the branches valid for CCNZmode, i.e., a comparison
+        with zero where the V bit is not set to zero.  These cases
+        occur when CC or FCC are set as a side effect of some data
+        manipulation, such as the ADD instruction.  */
+      switch (code)
+       {
+       case EQ: pos = "beq", neg = "bne"; break;
+       case NE: pos = "bne", neg = "beq"; break;
+       case LT: pos = "bmi", neg = "bpl"; break;
+       case GE: pos = "bpl", neg = "bmi"; break;
+       default: gcc_unreachable ();
+       }
+    }
+  else
+    {
+      switch (code)
+       {
+       case EQ: pos = "beq", neg = "bne"; break;
+       case NE: pos = "bne", neg = "beq"; break;
+       case GT: pos = "bgt", neg = "ble"; break;
+       case GTU: pos = "bhi", neg = "blos"; break;
+       case LT: pos = "blt", neg = "bge"; break;
+       case LTU: pos = "blo", neg = "bhis"; break;
+       case GE: pos = "bge", neg = "blt"; break;
+       case GEU: pos = "bhis", neg = "blo"; break;
+       case LE: pos = "ble", neg = "bgt"; break;
+       case LEU: pos = "blos", neg = "bhi"; break;
+       default: gcc_unreachable ();
+       }
+    }
+  switch (length)
+    {
+    case 2:
+      sprintf (buf, "%s %%l1", pos);
+      return buf;
+    case 6:
+      tmpop[0] = gen_label_rtx ();
+      sprintf (buf, "%s %%l0", neg);
+      output_asm_insn (buf, tmpop);
+      output_asm_insn ("jmp %l1", operands);
+      output_asm_label (tmpop[0]);
+      fputs (":\n", asm_out_file);
+      return "";
+    default:
+      gcc_unreachable ();
     }
-    
 }
 
-void
-notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
+/* Select the CC mode to be used for the side effect compare with
+   zero, given the compare operation code in op and the compare
+   operands in x in and y.  */
+machine_mode
+pdp11_cc_mode (enum rtx_code op, rtx x, rtx y)
 {
-    if (GET_CODE (SET_DEST (exp)) == CC0)
-    { 
-      cc_status.flags = 0;                                     
-      cc_status.value1 = SET_DEST (exp);                       
-      cc_status.value2 = SET_SRC (exp);                        
-    }                                                  
-    else if (GET_CODE (SET_SRC (exp)) == CALL)         
-    { 
-      CC_STATUS_INIT; 
+  if (FLOAT_MODE_P (GET_MODE (x)))
+    {
+      switch (GET_CODE (x))
+       {
+       case ABS:
+       case NEG:
+       case REG:
+       case MEM:
+         return CCmode;
+       default:
+         return CCNZmode;
+       }
     }
-    else if (SET_DEST(exp) == pc_rtx)
-    { 
-      /* jump */
-    }  
-    else if (GET_MODE (SET_DEST(exp)) == HImode                
-            || GET_MODE (SET_DEST(exp)) == QImode)
-    { 
-      cc_status.flags = GET_CODE (SET_SRC(exp)) == MINUS ? 0 : CC_NO_OVERFLOW;
-      cc_status.value1 = SET_SRC (exp);                        
-      cc_status.value2 = SET_DEST (exp);                       
-       
-      if (cc_status.value1 && GET_CODE (cc_status.value1) == REG       
-         && cc_status.value2                                   
-         && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
-       cc_status.value2 = 0;                                   
-      if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM       
-         && cc_status.value2                                   
-         && GET_CODE (cc_status.value2) == MEM)                        
-       cc_status.value2 = 0;                                   
-    }                  
-    else
-    { 
-      CC_STATUS_INIT; 
+  else
+    {
+      switch (GET_CODE (x))
+       {
+       case XOR:
+       case AND:
+       case IOR:
+       case MULT:
+       case NOT:
+       case REG:
+       case MEM:
+         return CCmode;
+       default:
+         return CCNZmode;
+       }
     }
 }
 
@@ -1135,62 +1144,115 @@ notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
 int
 simple_memory_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
 {
-    rtx addr;
-
-    /* Eliminate non-memory operations */
-    if (GET_CODE (op) != MEM)
-       return FALSE;
+  rtx addr;
 
-#if 0
-    /* dword operations really put out 2 instructions, so eliminate them.  */
-    if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
-       return FALSE;
-#endif
+  /* Eliminate non-memory operations */
+  if (GET_CODE (op) != MEM)
+    return FALSE;
 
-    /* Decode the address now.  */
+  /* Decode the address now.  */
 
 indirection:
+ indirection:
     
-    addr = XEXP (op, 0);
+  addr = XEXP (op, 0);
 
-    switch (GET_CODE (addr))
+  switch (GET_CODE (addr))
     {
-      case REG:
-       /* (R0) - no extra cost */
-       return 1;
+    case REG:
+      /* (R0) - no extra cost */
+      return 1;
        
-      case PRE_DEC:
-      case POST_INC:
-       /* -(R0), (R0)+ - cheap! */
+    case PRE_DEC:
+    case POST_INC:
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      /* -(R0), (R0)+ - cheap! */
+      return 1;
+       
+    case MEM:
+      /* cheap - is encoded in addressing mode info! 
+
+        -- except for @(R0), which has to be @0(R0) !!! */
+
+      if (GET_CODE (XEXP (addr, 0)) == REG)
        return 0;
        
-      case MEM:
-       /* cheap - is encoded in addressing mode info! 
+      op=addr;
+      goto indirection;
+       
+    case CONST_INT:
+    case LABEL_REF:           
+    case CONST:
+    case SYMBOL_REF:
+      /* @#address - extra cost */
+      return 0;
+
+    case PLUS:
+      /* X(R0) - extra cost */
+      return 0;
+
+    default:
+      break;
+    }
+    
+  return FALSE;
+}
+
+/* Similar to simple_memory_operand but doesn't match push/pop.  */
+int
+no_side_effect_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
+{
+  rtx addr;
 
-          -- except for @(R0), which has to be @0(R0) !!! */
+  /* Eliminate non-memory operations */
+  if (GET_CODE (op) != MEM)
+    return FALSE;
+
+  /* Decode the address now.  */
+
+ indirection:
+    
+  addr = XEXP (op, 0);
 
-       if (GET_CODE (XEXP (addr, 0)) == REG)
-           return 0;
+  switch (GET_CODE (addr))
+    {
+    case REG:
+      /* (R0) - no extra cost */
+      return 1;
        
-       op=addr;
-       goto indirection;
+    case PRE_DEC:
+    case POST_INC:
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      return 0;
        
-      case CONST_INT:
-      case LABEL_REF:         
-      case CONST:
-      case SYMBOL_REF:
-       /* @#address - extra cost */
-       return 0;
+    case MEM:
+      /* cheap - is encoded in addressing mode info! 
 
-      case PLUS:
-       /* X(R0) - extra cost */
+        -- except for @(R0), which has to be @0(R0) !!! */
+
+      if (GET_CODE (XEXP (addr, 0)) == REG)
        return 0;
+       
+      op=addr;
+      goto indirection;
+       
+    case CONST_INT:
+    case LABEL_REF:           
+    case CONST:
+    case SYMBOL_REF:
+      /* @#address - extra cost */
+      return 0;
 
-      default:
-       break;
+    case PLUS:
+      /* X(R0) - extra cost */
+      return 0;
+
+    default:
+      break;
     }
     
-    return FALSE;
+  return FALSE;
 }
 
 
@@ -1446,7 +1508,7 @@ pdp11_preferred_output_reload_class (rtx x, reg_class_t rclass)
 
    FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an 
    intermediate register (AC0-AC3: LOAD_FPU_REGS).  Everything else
-   can be loade/stored directly.  */
+   can be loaded/stored directly.  */
 static reg_class_t 
 pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
                        rtx x,
@@ -1463,9 +1525,8 @@ pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
 
 /* Implement TARGET_SECONDARY_MEMORY_NEEDED.
 
-   The answer is yes if we're going between general register and FPU 
-   registers.  The mode doesn't matter in making this check.
-*/
+   The answer is yes if we're going between general register and FPU
+   registers.  The mode doesn't matter in making this check.  */
 static bool
 pdp11_secondary_memory_needed (machine_mode, reg_class_t c1, reg_class_t c2)
 {
@@ -1594,6 +1655,8 @@ pdp11_regno_reg_class (int regno)
 { 
   if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM)
     return GENERAL_REGS;
+  else if (regno == CC_REGNUM || regno == FCC_REGNUM)
+    return CC_REGS;
   else if (regno > AC3_REGNUM)
     return NO_LOAD_FPU_REGS;
   else if (regno >= AC0_REGNUM)
@@ -1604,6 +1667,14 @@ pdp11_regno_reg_class (int regno)
     return GENERAL_REGS;
 }
 
+/* Return the regnums of the CC registers.  */
+bool
+pdp11_fixed_cc_regs (unsigned int *p1, unsigned int *p2)
+{
+  *p1 = CC_REGNUM;
+  *p2 = FCC_REGNUM;
+  return true;
+}
 
 int
 pdp11_sp_frame_offset (void)
@@ -1804,6 +1875,151 @@ pdp11_function_value_regno_p (const unsigned int regno)
   return (regno == RETVAL_REGNUM) || (TARGET_AC0 && (regno == AC0_REGNUM));
 }
 
+/* Used for O constraint, matches if shift count is "small".  */
+bool
+pdp11_small_shift (int n)
+{
+  return (unsigned) n < 4;
+}
+
+/* Expand a shift insn.  Returns true if the expansion was done,
+   false if it needs to be handled by the caller.  */
+bool
+pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
+                   rtx (*shift_base) (rtx, rtx, rtx))
+{
+  rtx dest, n, r, test;
+  rtx_code_label *lb, *lb2;
+  
+  if (CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2])))
+    emit_insn ((*shift_sc) (operands[0], operands[1], operands[2]));
+  else if (TARGET_40_PLUS)
+    return false;
+  else
+    {
+      lb = gen_label_rtx ();
+      r = gen_reg_rtx (HImode);
+      emit_move_insn (operands[0], operands[1]);
+      emit_move_insn (r, operands[2]);
+      if (!CONSTANT_P (operands[2]))
+       {
+         test = gen_rtx_LE (HImode, r, const0_rtx);
+         emit_jump_insn (gen_cbranchhi4 (test, r, const0_rtx, lb));
+       }
+      /* It would be nice to expand the loop here, but that's not
+        possible because shifts may be generated by the loop unroll
+        optimizer and it doesn't appreciate flow changes happening
+        while it's doing things.  */
+      emit_insn ((*shift_base) (operands[0], operands[1], r));
+      if (!CONSTANT_P (operands[2]))
+       {
+         emit_label (lb);
+
+         /* Allow REG_NOTES to be set on last insn (labels don't have enough
+            fields, and can't be used for REG_NOTES anyway).  */
+         emit_use (stack_pointer_rtx);
+       }
+    }
+  return true;
+}
+
+/* Emit the instructions needed to produce a shift by a small constant
+   amount (unrolled), or a shift made from a loop for the base machine
+   case.  */
+const char *
+pdp11_assemble_shift (rtx *operands, machine_mode m, int code)
+{
+  int i, n;
+  rtx exops[4][2];
+  rtx lb[1];
+  pdp11_action action[2];
+  const bool small = CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2]));
+
+  gcc_assert (small || !TARGET_40_PLUS);
+
+  if (m == E_SImode)
+      pdp11_expand_operands (operands, exops, 1, action, either);
+
+  if (!small)
+    {
+      /* Loop case, generate the top of loop label.  */
+      lb[0] = gen_label_rtx ();
+      output_asm_label (lb[0]);
+      fputs (":\n", asm_out_file);
+      n = 1;
+    }
+  else
+    n = INTVAL (operands[2]);
+  if (code == LSHIFTRT)
+    {
+      output_asm_insn ("clc", NULL);
+      switch (m)
+       {
+       case E_QImode:
+         output_asm_insn ("rorb %0", operands);
+         break;
+       case E_HImode:
+         output_asm_insn ("ror %0", operands);
+         break;
+       case E_SImode:
+         output_asm_insn ("ror %0", exops[0]);
+         output_asm_insn ("ror %0", exops[1]);
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      n--;
+    }
+  for (i = 0; i < n; i++)
+    {
+      switch (code)
+       {
+       case LSHIFTRT:
+       case ASHIFTRT:
+         switch (m)
+           {
+           case E_QImode:
+             output_asm_insn ("asrb %0", operands);
+             break;
+           case E_HImode:
+             output_asm_insn ("asr %0", operands);
+             break;
+           case E_SImode:
+             output_asm_insn ("asr %0", exops[0]);
+             output_asm_insn ("ror %0", exops[1]);
+             break;
+           default:
+             gcc_unreachable ();
+           }
+         break;
+       case ASHIFT:
+         switch (m)
+           {
+           case E_QImode:
+             output_asm_insn ("aslb %0", operands);
+             break;
+           case E_HImode:
+             output_asm_insn ("asl %0", operands);
+             break;
+           case E_SImode:
+             output_asm_insn ("asl %0", exops[1]);
+             output_asm_insn ("rol %0", exops[0]);
+             break;
+           default:
+             gcc_unreachable ();
+           }
+         break;
+       }
+    }
+  if (!small)
+    {
+      /* Loop case, emit the count-down and branch if not done.  */
+      output_asm_insn ("dec %2", operands);
+      output_asm_insn ("bne %l0", lb);
+    }
+  return "";
+}
+
 /* Worker function for TARGET_TRAMPOLINE_INIT.
 
    trampoline - how should i do it in separate i+d ? 
@@ -1814,7 +2030,6 @@ pdp11_function_value_regno_p (const unsigned int regno)
    MOV #STATIC, $4     01270Y  0x0000 <- STATIC; Y = STATIC_CHAIN_REGNUM
    JMP @#FUNCTION      000137  0x0000 <- FUNCTION
 */
-
 static void
 pdp11_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
 {
@@ -1934,12 +2149,6 @@ pdp11_scalar_mode_supported_p (scalar_mode mode)
   return default_scalar_mode_supported_p (mode);
 }
 
-int
-pdp11_branch_cost ()
-{
-  return (TARGET_BRANCH_CHEAP ? 0 : 1);
-}
-
 /* Implement TARGET_HARD_REGNO_NREGS.  */
 
 static unsigned int
@@ -1972,9 +2181,9 @@ pdp11_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
 /* Implement TARGET_MODES_TIEABLE_P.  */
 
 static bool
-pdp11_modes_tieable_p (machine_mode, machine_mode)
+pdp11_modes_tieable_p (machine_mode mode1, machine_mode mode2)
 {
-  return false;
+  return mode1 == HImode && mode2 == QImode;
 }
 
 /* Implement PUSH_ROUNDING.  On the pdp11, the stack is on an even
index af92a79bf30bce8dc902214e87a353e62561c862..f995bc8672b37d979935726ebc93da861142014d 100644 (file)
@@ -65,11 +65,11 @@ along with GCC; see the file COPYING3.  If not see
 #define LONG_DOUBLE_TYPE_SIZE  64
 
 /* machine types from ansi */
-#define SIZE_TYPE "unsigned int"       /* definition of size_t */
-#define WCHAR_TYPE "int"               /* or long int???? */
+#define SIZE_TYPE "short unsigned int"         /* definition of size_t */
+#define WCHAR_TYPE "short int"                 /* or long int???? */
 #define WCHAR_TYPE_SIZE 16
 
-#define PTRDIFF_TYPE "int"
+#define PTRDIFF_TYPE "short int"
 
 /* target machine storage layout */
 
@@ -99,8 +99,7 @@ along with GCC; see the file COPYING3.  If not see
 extern const struct real_format pdp11_f_format;
 extern const struct real_format pdp11_d_format;
 
-/* Maximum sized of reasonable data type 
-   DImode or Dfmode ...*/
+/* Maximum sized of reasonable data type -- DImode ...*/
 #define MAX_FIXED_MODE_SIZE 64 
 
 /* Allocation boundary (in *bits*) for storing pointers in memory.  */
@@ -124,6 +123,22 @@ extern const struct real_format pdp11_d_format;
 /* Define this if move instructions will actually fail to work
    when given unaligned data.  */
 #define STRICT_ALIGNMENT 1
+
+/* Adjust the length of shifts by small constant amounts.  The base
+   value (in "length" on input) is the length of a shift by one, not
+   including the CLC in logical shifts.  */
+#define ADJUST_INSN_LENGTH(insn, length) \
+  if ((GET_CODE (insn) == ASHIFT ||     \
+       GET_CODE (insn) == ASHIFTRT || \
+       GET_CODE (insn) == LSHIFTRT) && \
+      GET_CODE (XEXP (insn, 2)) == CONST_INT && \
+      pdp11_small_shift (XINT (insn, 2))) \
+    {                                    \
+      if (GET_CODE (insn) == LSHIFTRT)   \
+       length = (length * XINT (insn, 2)) + 2; \
+      else \
+       length *= XINT (insn, 2); \
+    }
 \f
 /* Standard register usage.  */
 
@@ -147,7 +162,8 @@ extern const struct real_format pdp11_d_format;
 
 #define FIXED_REGISTERS  \
 {0, 0, 0, 0, 0, 0, 1, 1, \
- 0, 0, 0, 0, 0, 0, 1, 1 }
+ 0, 0, 0, 0, 0, 0, 1, 1, \
+ 1, 1 }
 
 
 
@@ -161,7 +177,8 @@ extern const struct real_format pdp11_d_format;
 /* don't know about fp */
 #define CALL_USED_REGISTERS  \
 {1, 1, 0, 0, 0, 0, 1, 1, \
- 0, 0, 0, 0, 0, 0, 1, 1 }
+ 0, 0, 0, 0, 0, 0, 1, 1, \
+ 1, 1 }
 
 
 /* Specify the registers used for certain standard purposes.
@@ -203,27 +220,47 @@ NO_LOAD_FPU_REGS is ac4 and ac5, currently - difficult to load them
 FPU_REGS is all fpu regs 
 */
 
-enum reg_class { NO_REGS, MUL_REGS, GENERAL_REGS, LOAD_FPU_REGS, NO_LOAD_FPU_REGS, FPU_REGS, ALL_REGS, LIM_REG_CLASSES };
+enum reg_class
+  { NO_REGS,
+    MUL_REGS,
+    GENERAL_REGS,
+    LOAD_FPU_REGS,
+    NO_LOAD_FPU_REGS,
+    FPU_REGS,
+    CC_REGS,
+    ALL_REGS,
+    LIM_REG_CLASSES };
 
-#define N_REG_CLASSES (int) LIM_REG_CLASSES
+#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
 
 /* have to allow this till cmpsi/tstsi are fixed in a better way !! */
 #define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
 
-/* Since GENERAL_REGS is the same class as ALL_REGS,
-   don't give it a different class number; just make it an alias.  */
-
-/* #define GENERAL_REGS ALL_REGS */
-
 /* Give names of register classes as strings for dump file.  */
 
-#define REG_CLASS_NAMES {"NO_REGS", "MUL_REGS", "GENERAL_REGS", "LOAD_FPU_REGS", "NO_LOAD_FPU_REGS", "FPU_REGS", "ALL_REGS" }
+#define REG_CLASS_NAMES  \
+  { "NO_REGS",          \
+    "MUL_REGS",         \
+    "GENERAL_REGS",     \
+    "LOAD_FPU_REGS",    \
+    "NO_LOAD_FPU_REGS",         \
+    "FPU_REGS",                 \
+    "CC_REGS",          \
+    "ALL_REGS" }
 
 /* Define which registers fit in which classes.
    This is an initializer for a vector of HARD_REG_SET
    of length N_REG_CLASSES.  */
 
-#define REG_CLASS_CONTENTS {{0}, {0x00aa}, {0xc0ff}, {0x0f00}, {0x3000}, {0x3f00}, {0xffff}}
+#define REG_CLASS_CONTENTS \
+  { {0x00000}, /* NO_REGS */           \
+    {0x000aa}, /* MUL_REGS */          \
+    {0x0c0ff}, /* GENERAL_REGS */      \
+    {0x00f00}, /* LOAD_FPU_REGS */     \
+    {0x03000}, /* NO_LOAD_FPU_REGS */  \
+    {0x03f00}, /* FPU_REGS */          \
+    {0x30000}, /* CC_REGS */           \
+    {0x3ffff}} /* ALL_REGS */
 
 /* The same information, inverted:
    Return the class number of the smallest class containing
@@ -331,7 +368,7 @@ extern int may_call_alloca;
 {{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM},          \
  { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM},     \
  { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM},                \
- { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}   \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
 
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
   ((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO)))
@@ -424,11 +461,18 @@ extern int may_call_alloca;
 #define DBX_CONTIN_LENGTH 0
 
 /* Give a comparison code (EQ, NE etc) and the first operand of a COMPARE,
-   return the mode to be used for the comparison.  For floating-point, CCFPmode
-   should be used.  */
+   return the mode to be used for the comparison.  */
+
+#define SELECT_CC_MODE(OP,X,Y) pdp11_cc_mode (OP, X, Y)
 
-#define SELECT_CC_MODE(OP,X,Y) \
-(GET_MODE_CLASS(GET_MODE(X)) == MODE_FLOAT? CCFPmode : CCmode)
+/* Enable compare elimination pass.
+   FIXME: how can this be enabled for two registers?  */
+#undef TARGET_FLAGS_REGNUM
+#define TARGET_FLAGS_REGNUM CC_REGNUM
+
+/* Specify the CC registers.  TODO: is this for "type 1" CC handling only?  */
+#undef TARGET_FIXED_CONDITION_CODE_REGS
+#define TARGET_FIXED_CONDITION_CODE_REGS pdp11_fixed_cc_regs
 
 /* Specify the machine mode that pointers have.
    After generation of rtl, the compiler makes no further distinction
@@ -446,54 +490,6 @@ extern int may_call_alloca;
    but a CALL with constant address is cheap.  */
 /* #define NO_FUNCTION_CSE */
 
-\f
-/* Tell emit-rtl.c how to initialize special values on a per-function base.  */
-extern rtx cc0_reg_rtx;
-
-#define CC_STATUS_MDEP rtx
-
-#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0)
-\f
-/* Tell final.c how to eliminate redundant test instructions.  */
-
-/* Here we define machine-dependent flags and fields in cc_status
-   (see `conditions.h').  */
-
-#define CC_IN_FPU 04000 
-
-/* Do UPDATE_CC if EXP is a set, used in
-   NOTICE_UPDATE_CC 
-
-   floats only do compare correctly, else nullify ...
-
-   get cc0 out soon ...
-*/
-
-/* Store in cc_status the expressions
-   that the condition codes will describe
-   after execution of an instruction whose pattern is EXP.
-   Do not alter them if the instruction would not alter the cc's.  */
-
-#define NOTICE_UPDATE_CC(EXP, INSN) \
-{ if (GET_CODE (EXP) == SET)                                   \
-    {                                                          \
-      notice_update_cc_on_set(EXP, INSN);                      \
-    }                                                          \
-  else if (GET_CODE (EXP) == PARALLEL                          \
-          && GET_CODE (XVECEXP (EXP, 0, 0)) == SET)            \
-    {                                                          \
-      notice_update_cc_on_set(XVECEXP (EXP, 0, 0), INSN);      \
-    }                                                          \
-  else if (GET_CODE (EXP) == CALL)                             \
-    { /* all bets are off */ CC_STATUS_INIT; }                 \
-  if (cc_status.value1 && GET_CODE (cc_status.value1) == REG   \
-      && cc_status.value2                                      \
-      && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \
-    {                                                          \
-      printf ("here!\n");                                      \
-      cc_status.value2 = 0;                                    \
-    }                                                          \
-}
 \f
 /* Control the assembler format that we output.  */
 
@@ -520,7 +516,8 @@ extern rtx cc0_reg_rtx;
 
 #define REGISTER_NAMES \
 {"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc",     \
- "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap" }
+ "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap", \
+ "cc", "fcc" }
 
 /* Globalizing directive for a label.  */
 #define GLOBAL_ASM_OP "\t.globl "
@@ -603,10 +600,7 @@ extern rtx cc0_reg_rtx;
 #define TRAMPOLINE_SIZE 8
 #define TRAMPOLINE_ALIGNMENT 16
 
-/* there is no point in avoiding branches on a pdp, 
-   since branches are really cheap - I just want to find out
-   how much difference the BRANCH_COST macro makes in code */
-#define BRANCH_COST(speed_p, predictable_p) pdp11_branch_cost ()
+#define BRANCH_COST(speed_p, predictable_p) 1
 
 #define COMPARE_FLAG_MODE HImode
 
index 4f4a5d20a91ec51fa4f1481c0714d4f03d14eea9..1dd069ff101b7cec1faaadf2fb12b85e80590229 100644 (file)
    ;; arguments.
    (FRAME_POINTER_REGNUM  14)
    (ARG_POINTER_REGNUM    15)
-   (FIRST_PSEUDO_REGISTER 16)
+   ;; Condition code registers
+   (CC_REGNUM             16)
+   (FCC_REGNUM            17)
+   ;; End of hard registers
+   (FIRST_PSEUDO_REGISTER 18)
+   
    ;; Branch offset limits, as byte offsets from instruction address
    (MIN_BRANCH            -254)
    (MAX_BRANCH            256)
    (MIN_SOB               -126)
    (MAX_SOB               0)])
 
+;; DF is 64 bit
+;; SF is 32 bit
+;; SI is 32 bit
 ;; HI is 16 bit
 ;; QI is 8 bit 
 
 ;; Integer modes supported on the PDP11, with a mapping from machine mode
-;; to mnemonic suffix.  SImode and DImode always are special cases.
+;; to mnemonic suffix.  SImode and DImode are usually special cases.
 (define_mode_iterator PDPint [QI HI])
 (define_mode_attr  isfx [(QI "b") (HI "")])
+(define_mode_attr  mname [(QI "QImode") (HI "HImode") (SI "SImode") (DI "DImode")])
+(define_mode_attr  e_mname [(QI "E_QImode") (HI "E_HImode") (SI "E_SImode") (DI "E_DImode")])
+(define_mode_attr  hmode [(QI "hi") (HI "hi") (SI "si") (DI "di")])
+
+;; These are analogous for use in splitters and expanders.
+(define_mode_iterator HSint [HI SI])
+(define_mode_iterator QHSint [QI HI SI])
+(define_mode_iterator QHSDint [QI HI SI DI])
+
+(define_code_iterator SHF [ashift ashiftrt lshiftrt])
+
+;; Substitution to turn a CC clobber into a CC setter.  We have four of
+;; these: for CCmode vs. CCNZmode, and for CC_REGNUM vs. FCC_REGNUM.
+(define_subst "cc_cc"
+  [(set (match_operand 0 "") (match_operand 1 ""))
+   (clobber (reg CC_REGNUM))]
+  ""
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
 
-;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+(define_subst "cc_ccnz"
+  [(set (match_operand 0 "") (match_operand 1 ""))
+   (clobber (reg CC_REGNUM))]
+  ""
+  [(set (reg:CCNZ CC_REGNUM)
+       (compare:CCNZ (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
 
-;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
-;;- updates for most instructions.
+(define_subst "fcc_cc"
+  [(set (match_operand 0 "") (match_operand 1 ""))
+   (clobber (reg FCC_REGNUM))]
+  ""
+  [(set (reg:CC FCC_REGNUM)
+       (compare:CC (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
+
+(define_subst "fcc_ccnz"
+  [(set (match_operand 0 "") (match_operand 1 ""))
+   (clobber (reg FCC_REGNUM))]
+  ""
+  [(set (reg:CCNZ FCC_REGNUM)
+       (compare:CCNZ (match_dup 1) (const_int 0)))
+   (set (match_dup 0) (match_dup 1))])
+
+(define_subst_attr "cc_cc" "cc_cc" "_nocc" "_cc")
+(define_subst_attr "fcc_cc" "fcc_cc" "_nocc" "_cc")
+(define_subst_attr "cc_ccnz" "cc_ccnz" "_nocc" "_cc")
+(define_subst_attr "fcc_ccnz" "fcc_ccnz" "_nocc" "_cc")
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
 
-;;- Operand classes for the register allocator:
-\f
 ;; Compare instructions.
 
 ;; currently we only support df floats, which saves us quite some
 ;; and ucmp_optab for mode SImode, because we don't have that!!!
 ;; - yet since no libfunc is there, we abort ()
 
-;; The only thing that remains to be done then is output 
-;; the floats in a way the assembler can handle it (and 
-;; if you're really into it, use a PDP11 float emulation
-;; library to do floating point constant folding - but 
-;; I guess you'll get reasonable results even when not
-;; doing this)
-;; the last thing to do is fix the UPDATE_CC macro to check
-;; for floating point condition codes, and set cc_status
-;; properly, also setting the CC_IN_FCCR flag. 
-
 ;; define attributes
 ;; currently type is only fpu or arith or unknown, maybe branch later ?
 ;; default is arith
 
 ;; compare
 (define_insn "*cmpdf"
-  [(set (cc0)
-       (compare (match_operand:DF 0 "general_operand" "fR,fR,Q,QF")
-                (match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))]
-  "TARGET_FPU"
+  [(set (reg:CC FCC_REGNUM)
+       (compare:CC (match_operand:DF 0 "general_operand" "fR,fR,Q,QF")
+                   (match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))]
+  "TARGET_FPU && reload_completed"
   "*
 {
-  cc_status.flags = CC_IN_FPU;
   if (which_alternative == 0 || which_alternative == 2)
-    return \"{tstd|tstf} %0\;cfcc\";
+    return \"{tstd|tstf} %0\";
   else
-    return \"{cmpd|cmpf} %0, %1\;cfcc\";
+    return \"{cmpd|cmpf} %0, %1\";
 }"
-  [(set_attr "length" "4,4,6,6")]) 
-
-(define_insn "*cmp<mode>"
-  [(set (cc0)
-       (compare (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi")
-                (match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))]
+  [(set_attr "length" "2,2,4,4")
+   (set_attr "type" "fp")]) 
+
+;; Copy floating point processor condition code register to main CPU
+;; condition code register.
+(define_insn "*cfcc"
+  [(set (reg CC_REGNUM) (reg FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
+  "cfcc")
+
+(define_insn "cmp<mode>"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi")
+                   (match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))]
   ""
   "@
    tst<PDPint:isfx> %0
    cmp<PDPint:isfx> %0,%1"
   [(set_attr "length" "2,2,4,4,4,6")])
 
-;; sob instruction - we need an assembler which can make this instruction
-;; valid under _all_ circumstances!
+;; sob instruction - FIXME: this doesn't do anything, need to use doloop_end.
 
 (define_insn ""
   [(set (pc)
   "TARGET_40_PLUS"
   "*
 {
- static int labelcount = 0;
- static char buf[1000];
-
  if (get_attr_length (insn) == 2)
     return \"sob %0, %l1\";
 
  /* emulate sob */
+ operands[2] = gen_label_rtx ();
  output_asm_insn (\"dec %0\", operands);
- sprintf (buf, \"bge LONG_SOB%d\", labelcount);
- output_asm_insn (buf, NULL);
-
+ output_asm_insn (\"beq %l2\", operands);
  output_asm_insn (\"jmp %l1\", operands);
  
sprintf (buf, \"LONG_SOB%d:\", labelcount++);
output_asm_insn (buf, NULL);
output_asm_label (operands[2]);
fputs (\":\\n\", asm_out_file);
 
  return \"\";
 }"
 
 ;; These control RTL generation for conditional jump insns
 ;; and match them for register allocation.
-
-(define_expand "cbranchdf4"
-  [(set (cc0)
-        (compare (match_operand:DF 1 "general_operand")
-                (match_operand:DF 2 "register_or_const0_operand")))
-   (set (pc)
+;; Post reload these get expanded into insns that actually
+;; manipulate the condition code registers.  We can't do that before
+;; because instructions generated by reload clobber condition codes (new
+;; CC design, type #2).
+(define_insn_and_split "cbranchdf4"
+  [(set (pc)
        (if_then_else (match_operator 0 "ordered_comparison_operator"
-                      [(cc0) (const_int 0)])
+                      [(match_operand:DF 1 "general_operand" "fg")
+                       (match_operand:DF 2 "general_operand" "a")])
                      (label_ref (match_operand 3 "" ""))
                      (pc)))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(set (reg:CC FCC_REGNUM)
+       (compare:CC (match_dup 1) (match_dup 2)))
+   (set (pc)
+       (if_then_else (match_op_dup 0
+                      [(reg:CC FCC_REGNUM) (const_int 0)])
+                     (label_ref (match_dup 3))
+                     (pc)))]
   "")
 
-(define_expand "cbranch<mode>4"
-  [(set (cc0)
-        (compare (match_operand:PDPint 1 "general_operand")
-                (match_operand:PDPint 2 "general_operand")))
-   (set (pc)
+(define_insn_and_split "cbranch<mode>4"
+  [(set (pc)
        (if_then_else (match_operator 0 "ordered_comparison_operator"
-                      [(cc0) (const_int 0)])
+                      [(match_operand:PDPint 1 "general_operand" "g")
+                       (match_operand:PDPint 2 "general_operand" "g")])
                      (label_ref (match_operand 3 "" ""))
                      (pc)))]
   ""
+  "#"
+  "reload_completed"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_dup 1) (match_dup 2)))
+   (set (pc)
+       (if_then_else (match_op_dup 0
+                      [(reg:CC CC_REGNUM) (const_int 0)])
+                     (label_ref (match_dup 3))
+                     (pc)))]
   "")
 
-;; problem with too short jump distance! we need an assembler which can 
-;; make this valid for all jump distances!
-;; e.g. gas!
-
-;; these must be changed to check for CC_IN_FCCR if float is to be 
-;; enabled
+;; This splitter turns a branch on float condition into a branch on
+;; CPU condition, by adding a CFCC.
+(define_split
+  [(set (pc)
+       (if_then_else (match_operator 0 "ordered_comparison_operator"
+                      [(reg:CC FCC_REGNUM) (const_int 0)])
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))]
+  "TARGET_FPU && reload_completed"
+  [(set (reg:CC CC_REGNUM) (reg:CC FCC_REGNUM))
+   (set (pc)
+       (if_then_else (match_op_dup 0
+                      [(reg:CC CC_REGNUM) (const_int 0)])
+                     (label_ref (match_dup 1))
+                     (pc)))]
+  "")
 
-(define_insn "*branch"
+(define_insn "cond_branch"
   [(set (pc)
        (if_then_else (match_operator 0 "ordered_comparison_operator"
-                      [(cc0) (const_int 0)])
+                      [(reg:CC CC_REGNUM) (const_int 0)])
                      (label_ref (match_operand 1 "" ""))
                      (pc)))]
-  ""
-  "* return output_jump(GET_CODE (operands[0]), 0, get_attr_length(insn));"
+  "reload_completed"
+  "* return output_jump (operands, 0, get_attr_length (insn));"
   [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1)
                                                      (pc))
                                               (const_int MIN_BRANCH))
                                      (const_int 6)
                                      (const_int 2)))])
 
-
-;; These match inverted jump insns for register allocation.
-
-(define_insn "*branch_inverted"
+(define_insn "*branch"
   [(set (pc)
-       (if_then_else (match_operator 0 "ordered_comparison_operator"
-                      [(cc0) (const_int 0)])
-                     (pc)
-                     (label_ref (match_operand 1 "" ""))))]
-  ""
-  "* return output_jump(GET_CODE (operands[0]), 1, get_attr_length(insn));"
+       (if_then_else (match_operator 0 "ccnz_operator"
+                      [(reg:CCNZ CC_REGNUM) (const_int 0)])
+                     (label_ref (match_operand 1 "" ""))
+                     (pc)))]
+  "reload_completed"
+  "* return output_jump (operands, 1, get_attr_length (insn));"
   [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1)
                                                      (pc))
                                               (const_int MIN_BRANCH))
                                               (const_int MAX_BRANCH)))
                                      (const_int 6)
                                      (const_int 2)))])
+
 \f
 ;; Move instructions
 
   [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g")
        (match_operand:DI 1 "general_operand" "rN,g"))]
   ""
+  "")
+
+
+(define_insn "*movdi_nocc"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g")
+       (match_operand:DI 1 "general_operand" "rN,g"))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
   "* return output_move_multiple (operands);"
   [(set_attr "length" "16,32")])
 
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g")
        (match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))]
   ""
+  "")
+
+(define_insn "*movsi_nocc"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g")
+       (match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
   "* return output_move_multiple (operands);"
   [(set_attr "length" "4,6,8,16")])
 
   [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
        (match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))]
   ""
+  "")
+
+;; This splits all the integer moves: DI and SI modes as well as
+;; the simple machine operations.
+(define_split 
+  [(set (match_operand:QHSDint 0 "nonimmediate_operand" "")
+       (match_operand:QHSDint 1 "general_operand" ""))]
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (match_dup 1))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+  
+;; MOV clears V
+(define_insn "*mov<mode>_<cc_cc>"
+  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
+       (match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "*
 {
   if (operands[1] == const0_rtx)
 }"
   [(set_attr "length" "2,4,4,6")])
 
-(define_insn "movdf"
-  [(set (match_operand:DF 0 "float_nonimm_operand" "=a,fR,a,Q,g")
-        (match_operand:DF 1 "float_operand" "fR,a,FQ,a,g"))]
+;; movdf has unusually complicated condition code handling, because
+;; load (into float register) updates the FCC, while store (from
+;; float register) leaves it untouched.
+;;
+;; 1. Loads are:  ac4, ac5, or non-register into load-register
+;; 2. Stores are: load-register to non-register, ac4, or ac5
+;; 3. Moves from ac0-ac3 to another ac0-ac3 can be handled
+;;    either as loads or as stores.
+
+(define_expand "movdf"
+  [(set (match_operand:DF 0 "float_nonimm_operand" "")
+        (match_operand:DF 1 "float_operand" ""))]
   "TARGET_FPU"
-  "* if (which_alternative ==0 || which_alternative == 2)
-       return \"ldd %1, %0\";
-     else if (which_alternative == 1 || which_alternative == 3)
-       return \"std %1, %0\";
-     else 
-       return output_move_multiple (operands); "
-;; last one is worst-case
-  [(set_attr "length" "2,2,4,4,24")])
+  "")
 
-(define_insn "movsf"
-  [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,g")
-        (match_operand:SF 1 "float_operand" "fR,a,FQ,a,g"))]
+;; Splitter for all these cases.  Store is the first two
+;; alternatives, which are not split.  Note that case 3
+;; is treated as a store, i.e., not split.
+(define_insn_and_split "movdf_split"
+  [(set (match_operand:DF 0 "float_nonimm_operand" "=fR,FQ,a,a,a")
+        (match_operand:DF 1 "float_operand" "a,a,hR,FQ,G"))]
   "TARGET_FPU"
-  "* if (which_alternative ==0 || which_alternative == 2)
-       return \"{ldcfd|movof} %1, %0\";
-     else if (which_alternative == 1 || which_alternative == 3)
-       return \"{stcdf|movfo} %1, %0\";
-     else 
-       return output_move_multiple (operands); "
-;; last one is worst-case
-  [(set_attr "length" "2,2,4,4,12")])
+  "*
+  gcc_assert (which_alternative < 2);
+  return \"std %1, %0\";
+  "
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (match_dup 1))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "{
+  if (GET_CODE (operands[1]) == REG && 
+      REGNO_REG_CLASS (REGNO (operands[1])) == LOAD_FPU_REGS)
+    FAIL;
+  }"
+  [(set_attr "length" "2,4,0,0,0")])
+
+;; Loads (case 1).  
+(define_insn "*ldd<fcc_cc>"
+  [(set (match_operand:DF 0 "float_nonimm_operand" "=a,a,a")
+        (match_operand:DF 1 "float_operand" "hR,FQ,G"))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
+  "@
+  ldd %1, %0
+  ldd %1, %0
+  clrd %0"
+  [(set_attr "length" "2,4,2")])
+
+;; SFmode is easier because that uses convert load/store, which
+;; always change condition codes.
+;; Note that these insns are cheating a bit.  We actually have
+;; DFmode operands in the FPU registers, which is why the
+;; ldcfd and stcdf instructions appear.  But GCC likes to think
+;; of these as SFmode loads and does the conversion once in the
+;; register, at least in many cases.  So we pretend to do this,
+;; but then extend and truncate register-to-register are NOP and
+;; generate no code.
+(define_insn_and_split "movsf"
+  [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q")
+        (match_operand:SF 1 "float_operand" "fRG,a,FQ,a"))]
+  "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (match_dup 1))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+  
+(define_insn "*movsf<fcc_ccnz>"
+  [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,a")
+        (match_operand:SF 1 "float_operand" "fR,a,FQ,a,G"))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
+  "@
+  {ldcfd|movof} %1, %0
+  {stcdf|movfo} %1, %0
+  {ldcfd|movof} %1, %0
+  {stcdf|movfo} %1, %0
+  clrf %0"
+  [(set_attr "length" "2,2,4,4,2")])
 
 ;; maybe fiddle a bit with move_ratio, then 
 ;; let constraints only accept a register ...
              (clobber (match_dup 4))
              (clobber (match_dup 5))
              (clobber (match_dup 2))])]
-  "(TARGET_BCOPY_BUILTIN)"
+  ""
   "
 {
   operands[0]
 }")
 
 
-(define_insn "movmemhi1"
+(define_insn "*movmemhi1"
   [(set (mem:BLK (match_operand:HI 0 "register_operand" "r,r"))
        (mem:BLK (match_operand:HI 1 "register_operand" "r,r")))
    (use (match_operand:HI 2 "general_operand" "n,r"))
    (clobber (match_dup 0))
    (clobber (match_dup 1))
    (clobber (match_dup 2))]
-  "(TARGET_BCOPY_BUILTIN)"
+  ""
   "* return output_block_move (operands);"
 ;;; just a guess
   [(set_attr "length" "80")])
 \f
 ;;- truncation instructions
 
-(define_insn  "truncdfsf2"
+;; We sometimes end up doing a register to register truncate,
+;; which isn't right because we actually load registers always
+;; with a DFmode value.  But even with PROMOTE the compiler
+;; doesn't always get that (so we don't use it).  That means
+;; a register to register truncate is a NOP.
+(define_insn_and_split  "truncdfsf2"
   [(set (match_operand:SF 0 "float_nonimm_operand" "=f,R,Q")
-       (float_truncate:SF (match_operand:DF 1 "register_operand" "f,a,a")))]
+       (float_truncate:SF (match_operand:DF 1 "register_operand" "0,a,a")))]
   "TARGET_FPU"
-  "* if (which_alternative ==0)
-     {
-       return \"\";
-     }
-     else if (which_alternative == 1)
-       return \"{stcdf|movfo} %1, %0\";
-     else 
-       return \"{stcdf|movfo} %1, %0\";
-  "
-  [(set_attr "length" "0,2,4")])
-
+  {
+    gcc_assert (which_alternative == 0);
+    return "";
+  }          
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (float_truncate:SF (match_dup 1)))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "{
+  if (GET_CODE (operands[0]) == REG && 
+      GET_CODE (operands[1]) == REG && 
+      REGNO (operands[0]) == REGNO (operands[1]))
+    FAIL;
+  }"
+  [(set_attr "length" "0,0,0")])
+
+(define_insn "*truncdfsf2_<fcc_cc>"
+  [(set (match_operand:SF 0 "float_nonimm_operand" "=R,Q")
+       (float_truncate:SF (match_operand:DF 1 "register_operand" "a,a")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
+   "{stcdf|movfo} %1, %0"
+  [(set_attr "length" "2,4")])
 
 \f
 ;;- zero extension instructions
 
-(define_insn "zero_extendqihi2"
+(define_insn_and_split "zero_extendqihi2"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
        (zero_extend:HI (match_operand:QI 1 "general_operand" "0,0")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (zero_extend:HI (match_dup 1)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*zero_extendqihi2<cc_cc>"
+  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
+                  (zero_extend:HI (match_operand:QI 1 "general_operand" "0,0")))
+             (clobber (reg:CC CC_REGNUM))])]
+  "reload_completed"
   "bic $0177400, %0"
   [(set_attr "length" "4,6")])
                         
 \f
 ;;- sign extension instructions
 
-(define_insn "extendsfdf2"
+;; We sometimes end up doing a register to register extend,
+;; which isn't right because we actually load registers always
+;; with a DFmode value.  But even with PROMOTE the compiler
+;; doesn't always get that (so we don't use it).  That means
+;; a register to register truncate is a NOP.
+(define_insn_and_split "extendsfdf2"
   [(set (match_operand:DF 0 "register_operand" "=f,a,a")
-       (float_extend:DF (match_operand:SF 1 "float_operand" "f,R,Q")))]
+       (float_extend:DF (match_operand:SF 1 "float_operand" "0,R,Q")))]
   "TARGET_FPU"
-  "@
-   /* nothing */
-   {ldcfd|movof} %1, %0
-   {ldcfd|movof} %1, %0"
-  [(set_attr "length" "0,2,4")])
+  {
+    gcc_assert (which_alternative == 0);
+    return "";
+  }          
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (float_extend:DF (match_dup 1)))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "{
+  if (GET_CODE (operands[0]) == REG && 
+      GET_CODE (operands[1]) == REG && 
+      REGNO (operands[0]) == REGNO (operands[1]))
+    FAIL;
+  }"
+  [(set_attr "length" "0,0,0")])
+
+(define_insn "*extendsfdf2_<fcc_cc>"
+  [(set (match_operand:DF 0 "register_operand" "=a,a")
+       (float_extend:DF (match_operand:SF 1 "float_operand" "R,Q")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
+  "{ldcfd|movof} %1, %0"
+  [(set_attr "length" "2,4")])
 
-;; does movb sign extend in register-to-register move?
-(define_insn "extendqihi2"
+;; movb sign extends if destination is a register
+(define_insn_and_split "extendqihi2"
   [(set (match_operand:HI 0 "register_operand" "=r,r")
        (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (sign_extend:HI (match_dup 1)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+;; MOVB clears V
+(define_insn "*extendqihi2<cc_cc>"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "movb %1, %0"
   [(set_attr "length" "2,4")])
 
-(define_insn "extendqisi2"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (sign_extend:SI (match_operand:QI 1 "general_operand" "rR,Q")))]
-  "TARGET_40_PLUS"
-  "*
-{
-  rtx latehalf[2];
-
-  /* make register pair available */
-  latehalf[0] = operands[0];
-  operands[0] = gen_rtx_REG (HImode, REGNO (operands[0])+ 1);
-
-  output_asm_insn(\"movb %1, %0\", operands);
-  output_asm_insn(\"sxt %0\", latehalf);
-    
-  return \"\";
-}"
-  [(set_attr "length" "4,6")])
-
-;; maybe we have to use define_expand to say that we have the instruction,
-;; unconditionally, and then match dependent on CPU type:
-
-(define_expand "extendhisi2"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
-       (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))]
-  ""
-  "")
-  
-(define_insn "" ; "extendhisi2"
+(define_insn_and_split "extendhisi2"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r")
        (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))]
   "TARGET_40_PLUS"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (sign_extend:SI (match_dup 1)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*extendhisi2_nocc"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r")
+       (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_40_PLUS && reload_completed"
   "*
 {
   rtx latehalf[2];
 }"
   [(set_attr "length" "10,6,6")])
 
-
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (sign_extend:SI (match_operand:HI 1 "general_operand" "0")))]
-  "(! TARGET_40_PLUS)"
-  "*
-{
-  static int count = 0;
-  char buf[100];
-  rtx lateoperands[2];
-
-  lateoperands[0] = operands[0];
-  operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
-
-  output_asm_insn(\"tst %0\", operands);
-  sprintf(buf, \"bge extendhisi%d\", count);
-  output_asm_insn(buf, NULL);
-  output_asm_insn(\"mov -1, %0\", lateoperands);
-  sprintf(buf, \"bne extendhisi%d\", count+1);
-  output_asm_insn(buf, NULL);
-  sprintf(buf, \"\\nextendhisi%d:\", count);
-  output_asm_insn(buf, NULL);
-  output_asm_insn(\"clr %0\", lateoperands);
-  sprintf(buf, \"\\nextendhisi%d:\", count+1);
-  output_asm_insn(buf, NULL);
-
-  count += 2;
-
-  return \"\";
-}"
-  [(set_attr "length" "12")])
-
 ;; make float to int and vice versa 
-;; using the cc_status.flag field we could probably cut down
-;; on seti and setl
 ;; assume that we are normally in double and integer mode -
 ;; what do pdp library routines do to fpu mode ?
 
-(define_insn "floatsidf2"
+;; Note: the hardware treats register source as
+;; a 16-bit (high order only) source, which isn't
+;; what we want.  But we do need to support register
+;; dest because gcc asks for it.
+(define_insn_and_split "floatsidf2"
   [(set (match_operand:DF 0 "register_operand" "=a,a,a")
        (float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (float:DF (match_dup 1)))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+
+(define_insn "*floatsidf2<fcc_cc>"
+  [(set (match_operand:DF 0 "register_operand" "=a,a,a")
+       (float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "* if (which_alternative ==0)
      {
        rtx latehalf[2];
-
        latehalf[0] = NULL; 
        latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
        output_asm_insn(\"mov %1, -(sp)\", latehalf);
        output_asm_insn(\"seti\", operands);
        return \"\";
      }
-     else if (which_alternative == 1)
-       return \"setl\;{ldcld|movif} %1, %0\;seti\";
      else 
        return \"setl\;{ldcld|movif} %1, %0\;seti\";
   "
   [(set_attr "length" "10,6,8")])
 
-(define_insn "floathidf2"
+(define_insn_and_split "floathidf2"
   [(set (match_operand:DF 0 "register_operand" "=a,a")
        (float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (float:DF (match_dup 1)))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+
+(define_insn "*floathidf2<fcc_cc>"
+  [(set (match_operand:DF 0 "register_operand" "=a,a")
+       (float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{ldcid|movif} %1, %0"
   [(set_attr "length" "2,4")])
        
 ;; cut float to int
-(define_insn "fix_truncdfsi2"
+
+;; Note: the hardware treats register destination as
+;; a 16-bit (high order only) destination, which isn't
+;; what we want.  But we do need to support register
+;; dest because gcc asks for it.
+(define_insn_and_split "fix_truncdfsi2"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q")
        (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (fix:SI (fix:DF (match_dup 1))))
+             (clobber (reg:CC CC_REGNUM))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+
+;; Note: this clobbers both sets of condition codes!
+(define_insn "*fix_truncdfsi2_nocc"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q")
+       (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))
+   (clobber (reg:CC CC_REGNUM))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "* if (which_alternative ==0)
      {
        output_asm_insn(\"setl\", operands);
        output_asm_insn(\"mov (sp)+, %0\", operands);
        return \"\";
      }
-     else if (which_alternative == 1)
-       return \"setl\;{stcdl|movfi} %1, %0\;seti\";
      else 
        return \"setl\;{stcdl|movfi} %1, %0\;seti\";
   "
   [(set_attr "length" "10,6,8")])
 
-(define_insn "fix_truncdfhi2"
+(define_insn_and_split "fix_truncdfhi2"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
        (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (fix:HI (fix:DF (match_dup 1))))
+             (clobber (reg:CC CC_REGNUM))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+
+;; Note: this clobbers both sets of condition codes!
+(define_insn "*fix_truncdfhi2_nocc"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
+       (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))
+   (clobber (reg:CC CC_REGNUM))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{stcdi|movfi} %1, %0"
   [(set_attr "length" "2,4")])
 
 ;;- arithmetic instructions
 ;;- add instructions
 
-(define_insn "adddf3"
+(define_insn_and_split "adddf3"
   [(set (match_operand:DF 0 "register_operand" "=a,a")
        (plus:DF (match_operand:DF 1 "register_operand" "%0,0")
                 (match_operand:DF 2 "general_operand" "fR,QF")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (plus:DF (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+
+;; Float add sets V if overflow from add
+(define_insn "*adddf3<fcc_ccnz>"
+  [(set (match_operand:DF 0 "register_operand" "=a,a")
+       (plus:DF (match_operand:DF 1 "register_operand" "%0,0")
+             (match_operand:DF 2 "general_operand" "fR,QF")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{addd|addf} %2, %0"
   [(set_attr "length" "2,4")])
 
-(define_insn "adddi3"
+(define_insn_and_split "adddi3"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
        (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0")
                 (match_operand:DI 2 "general_operand" "r,on,r,on")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*adddi3_nocc"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
+       (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0")
+             (match_operand:DI 2 "general_operand" "r,on,r,on")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"  
   "*
 {
   rtx inops[2];
 ;; high word is added at the end, so the adding of the high parts
 ;; will always used the original high part and not a high part
 ;; modified by carry (which would amount to double carry).
-(define_insn "addsi3"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o")
+(define_insn_and_split "addsi3"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
        (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0")
                 (match_operand:SI 2 "general_operand" "r,on,r,on")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*addsi3_nocc"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
+       (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0")
+             (match_operand:SI 2 "general_operand" "r,on,r,on")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "*
 {
   rtx inops[2];
 }"
   [(set_attr "length" "6,10,12,16")])
 
-(define_insn "addhi3"
+(define_insn_and_split "addhi3"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
        (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0")
                 (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (plus:HI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+;; Add sets V if overflow from the add
+(define_insn "*addhi3<cc_ccnz>"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
+       (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0")
+                (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "*
 {
   if (GET_CODE (operands[2]) == CONST_INT)
 ;; args, since they are canonical plus:xx now!
 ;; also for minus:DF ??
 
-(define_insn "subdf3"
+(define_insn_and_split "subdf3"
   [(set (match_operand:DF 0 "register_operand" "=a,a")
        (minus:DF (match_operand:DF 1 "register_operand" "0,0")
                  (match_operand:DF 2 "general_operand" "fR,Q")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (minus:DF (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+
+(define_insn "*subdf3<fcc_ccnz>"
+  [(set (match_operand:DF 0 "register_operand" "=a,a")
+       (minus:DF (match_operand:DF 1 "register_operand" "0,0")
+                 (match_operand:DF 2 "general_operand" "fR,QF")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{subd|subf} %2, %0"
   [(set_attr "length" "2,4")])
 
-(define_insn "subdi3"
+(define_insn_and_split "subdi3"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
        (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0")
                 (match_operand:DI 2 "general_operand" "r,on,r,on")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*subdi3_nocc"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
+       (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0")
+             (match_operand:DI 2 "general_operand" "r,on,r,on")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "*
 {
   rtx inops[2];
 }"
   [(set_attr "length" "20,28,40,48")])
 
-(define_insn "subsi3"
-  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o")
+(define_insn_and_split "subsi3"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
        (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
                 (match_operand:SI 2 "general_operand" "r,on,r,on")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*subsi3_nocc"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o")
+       (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
+             (match_operand:SI 2 "general_operand" "r,on,r,on")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "*
 {
   rtx inops[2];
 }"
   [(set_attr "length" "6,10,12,16")])
 
-(define_insn "subhi3"
+(define_insn_and_split "subhi3"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
        (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
-                 (match_operand:HI 2 "general_operand" "rR,Qi,rR,Qi")))]
+                 (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (minus:HI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+;; Note: the manual says that (minus m (const_int n)) is converted
+;; to (plus m (const_int -n)) but that does not appear to be
+;; the case when it's wrapped in a PARALLEL.  So instead we handle
+;; that case here, which is easy enough.
+(define_insn "*subhi3<cc_ccnz>"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
+       (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
+                 (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "*
 {
-  gcc_assert (GET_CODE (operands[2]) != CONST_INT);
+  if (GET_CODE (operands[2]) == CONST_INT)
+    {
+      if (INTVAL(operands[2]) == 1)
+       return \"dec %0\";
+      else if (INTVAL(operands[2]) == -1)
+        return \"inc %0\";
+    }
 
   return \"sub %2, %0\";
 }"
     operands[1] = expand_unop (<MODE>mode, one_cmpl_optab, op1, 0, 1);
 }")
 
-(define_insn "*bic<mode>"
+(define_insn_and_split "*bic<mode>"
   [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
        (and:PDPint
             (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi"))
             (match_operand:PDPint 2 "general_operand" "0,0,0,0")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (and:PDPint (not:PDPint (match_dup 1)) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*bic<mode><cc_cc>"
+  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
+       (and:PDPint
+            (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi"))
+                         (match_operand:PDPint 2 "general_operand" "0,0,0,0")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "bic<PDPint:isfx> %1, %0"
   [(set_attr "length" "2,4,4,6")])
 
 ;;- Bit set (inclusive or) instructions
-(define_insn "ior<mode>3"
+(define_insn_and_split "ior<mode>3"
   [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
        (ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0")
-               (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))]
+                   (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (ior:PDPint (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "ior<mode>3<cc_cc>"
+  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
+       (ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0")
+            (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "bis<PDPint:isfx> %2, %0"
   [(set_attr "length" "2,4,4,6")])
 
 ;;- xor instructions
-(define_insn "xorhi3"
+(define_insn_and_split "xorhi3"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
        (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
                (match_operand:HI 2 "register_operand" "r,r")))]
   "TARGET_40_PLUS"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (xor:HI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*xorhi3<cc_cc>"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
+       (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
+            (match_operand:HI 2 "register_operand" "r,r")))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_40_PLUS && reload_completed"
   "xor %2, %0"
   [(set_attr "length" "2,4")])
 
 ;;- one complement instructions
 
-(define_insn "one_cmpl<mode>2"
+(define_insn_and_split "one_cmpl<mode>2"
   [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
         (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (not:PDPint (match_dup 1)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "*one_cmpl<mode>2<cc_cc>"
+  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
+       (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
   "com<PDPint:isfx> %0"
   [(set_attr "length" "2,4")])
 
 ;;- arithmetic shift instructions
-(define_insn "ashlsi3"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (ashift:SI (match_operand:SI 1 "register_operand" "0,0")
-                  (match_operand:HI 2 "general_operand" "rR,Qi")))]
-  "TARGET_40_PLUS"
-  "ashc %2,%0"
-  [(set_attr "length" "2,4")])
-
-;; Arithmetic right shift on the pdp works by negating the shift count.
-(define_expand "ashrsi3"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (ashift:SI (match_operand:SI 1 "register_operand" "0")
-                  (match_operand:HI 2 "general_operand" "g")))]
+;;
+;; There is a fair amount of complexity here because with -m10
+;; (pdp-11/10, /20) we only have shift by one bit.  Iterators are
+;; used to reduce the amount of very similar code.
+;;
+;; First the insns used for small constant shifts.
+;
+;; The "length" attribute values are modified by the ADJUST_INSN_LENGTH
+;; macro for the small constant shift case (first two alternatives).
+;; For those, the value coded in the length attribute is the cost of just
+;; the shift for a single shift.
+(define_insn "<code><mode>_sc"
+  [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q")
+       (SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0")
+                   (match_operand:HI 2 "expand_shift_operand" "O,O")))]
   ""
-  "
-{
-  operands[2] = negate_rtx (HImode, operands[2]);
-}")
-
-;; define asl aslb asr asrb - ashc missing!
+  "* return pdp11_assemble_shift (operands, <QHSint:mname>, <CODE>);"
+  [(set_attr "length" "2,4")])
 
-;; asl 
-(define_insn "" 
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
-       (ashift:HI (match_operand:HI 1 "general_operand" "0,0")
-                  (const_int 1)))]
+;; Next, shifts that are done as a loop on base (11/10 class) machines.
+;; This applies to shift counts too large to unroll, or variable shift
+;; counts.  The check for count <= 0 is done before we get here.
+(define_insn "<code><mode>_base"
+  [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q")
+       (SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0")
+            (match_operand:HI 2 "register_operand" "r,r")))
+   (clobber (match_dup 2))]
   ""
-  "asl %0"
+  "* return pdp11_assemble_shift (operands, <QHSint:mname>, <CODE>);"
   [(set_attr "length" "2,4")])
 
-;; and another possibility for asr is << -1
-;; might cause problems since -1 can also be encoded as 65535!
-;; not in gcc2 ??? 
-
-;; asr
-(define_insn "" 
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
+;; Next the insns that use the extended instructions ash and ashc.
+;; Note that these are just left shifts, and HI/SI only.  (Right shifts
+;; are done by shifting by a negative amount.)
+(define_insn "aslhi_op"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r")
        (ashift:HI (match_operand:HI 1 "general_operand" "0,0")
-                  (const_int -1)))]
-  ""
-  "asr %0"
+                      (match_operand:HI 2 "general_operand" "rR,Q")))]
+  "TARGET_40_PLUS"
+  "ash %2, %0"
   [(set_attr "length" "2,4")])
 
-;; lsr
-(define_insn "lsrhi1" 
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
-       (lshiftrt:HI (match_operand:HI 1 "general_operand" "0,0")
-                  (const_int 1)))]
-  ""
-  "clc\;ror %0"
+(define_insn "aslsi_op"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r")
+       (ashift:SI (match_operand:SI 1 "general_operand" "0,0")
+                  (match_operand:HI 2 "general_operand" "rR,Q")))]
+  "TARGET_40_PLUS"
+  "ashc %2, %0"
   [(set_attr "length" "2,4")])
 
-(define_insn "lsrsi1"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
-                   (const_int 1)))]
-  ""
-{
-
-  rtx lateoperands[2];
-
-  lateoperands[0] = operands[0];
-  operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
-
-  lateoperands[1] = operands[1];
-  operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
-
-  output_asm_insn (\"clc\", operands);
-  output_asm_insn (\"ror %0\", lateoperands);
-  output_asm_insn (\"ror %0\", operands);
-
-  return \"\";
-}
-  [(set_attr "length" "10")])
-
-(define_expand "lshrsi3"
-  [(match_operand:SI 0 "register_operand" "")
-   (match_operand:SI 1 "register_operand" "0")
+;; Now the expanders that produce the insns defined above. 
+(define_expand "ashl<mode>3"
+  [(match_operand:QHSint 0 "nonimmediate_operand" "")
+   (match_operand:QHSint 1 "general_operand" "")
    (match_operand:HI 2 "general_operand" "")]
   ""
   "
 {
   rtx r;
 
-  if (!TARGET_40_PLUS &&
-      (GET_CODE (operands[2]) != CONST_INT ||
-       (unsigned) INTVAL (operands[2]) > 3))
-    FAIL;
-  emit_insn (gen_lsrsi1 (operands[0], operands[1]));
-  if (GET_CODE (operands[2]) != CONST_INT)
+  if (!pdp11_expand_shift (operands, gen_ashift<mode>_sc, gen_ashift<mode>_base))
     {
-      r = gen_reg_rtx (HImode);
-      emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1)));
-      emit_insn (gen_ashrsi3 (operands[0], operands[0], r));
-    }
-  else if ((unsigned) INTVAL (operands[2]) != 1)
-    {
-      emit_insn (gen_ashlsi3 (operands[0], operands[0],
-                              GEN_INT (1 - INTVAL (operands[2]))));
+      if (<QHSint:e_mname> == E_QImode)
+        {
+          r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1]));
+          emit_insn (gen_aslhi_op (r, r, operands[2]));
+          emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0)));
+        }
+      else
+        {
+          emit_insn (gen_asl<QHSint:hmode>_op (operands[0], operands[1], operands[2]));
+        }
     }
   DONE;
-}
-"
-)
-
-;; shift is by arbitrary count is expensive, 
-;; shift by one cheap - so let's do that, if
-;; space doesn't matter
-(define_insn "" 
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=r")
-       (ashift:HI (match_operand:HI 1 "general_operand" "0")
-                  (match_operand:HI 2 "expand_shift_operand" "O")))]
-  "! optimize_size"
-  "*
-{
-  register int i;
-
-  for (i = 1; i <= abs(INTVAL(operands[2])); i++)
-    if (INTVAL(operands[2]) < 0)
-      output_asm_insn(\"asr %0\", operands);
-    else
-      output_asm_insn(\"asl %0\", operands);
-      
-  return \"\";
-}"
-;; longest is 4
-  [(set (attr "length") (const_int 8))])
-
-;; aslb
-(define_insn "" 
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,o")
-       (ashift:QI (match_operand:QI 1 "general_operand" "0,0")
-                  (match_operand:HI 2 "const_int_operand" "n,n")))]
-  ""
-  "*
-{ /* allowing predec or post_inc is possible, but hairy! */
-  int i, cnt;
-
-  cnt = INTVAL(operands[2]) & 0x0007;
-
-  for (i=0 ; i < cnt ; i++)
-       output_asm_insn(\"aslb %0\", operands);
+}")
 
-  return \"\";
-}"
-;; set attribute length ( match_dup 2 & 7 ) *(1 or 2) !!!
-  [(set_attr_alternative "length" 
-                         [(const_int 14)
-                          (const_int 28)])])
-
-;;; asr 
-;(define_insn "" 
-;  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
-;      (ashiftrt:HI (match_operand:HI 1 "general_operand" "0,0")
-;                   (const_int 1)))]
-;  ""
-;  "asr %0"
-;  [(set_attr "length" "2,4")])
-
-;; asrb
-(define_insn "" 
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,o")
-       (ashiftrt:QI (match_operand:QI 1 "general_operand" "0,0")
-                    (match_operand:HI 2 "const_int_operand" "n,n")))]
+(define_expand "ashr<mode>3"
+  [(match_operand:QHSint 0 "nonimmediate_operand" "")
+   (match_operand:QHSint 1 "general_operand" "")
+   (match_operand:HI 2 "general_operand" "")]
   ""
-  "*
-{ /* allowing predec or post_inc is possible, but hairy! */
-  int i, cnt;
-
-  cnt = INTVAL(operands[2]) & 0x0007;
-
-  for (i=0 ; i < cnt ; i++)
-       output_asm_insn(\"asrb %0\", operands);
-
-  return \"\";
-}"
-  [(set_attr_alternative "length" 
-                         [(const_int 14)
-                          (const_int 28)])])
-
-;; the following is invalid - too complex!!! - just say 14 !!!
-;  [(set (attr "length") (plus (and (match_dup 2)
-;                                   (const_int 14))
-;                              (and (match_dup 2)
-;                                   (const_int 14))))])
-
-
-
-;; can we get +-1 in the next pattern? should 
-;; have been caught by previous patterns!
-
-(define_insn "ashlhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (ashift:HI (match_operand:HI 1 "register_operand" "0,0")
-                  (match_operand:HI 2 "general_operand" "rR,Qi")))]
-  "TARGET_40_PLUS"
-  "*
+  "
 {
-  if (GET_CODE(operands[2]) == CONST_INT)
+  rtx r;
+
+  if (!pdp11_expand_shift (operands, gen_ashiftrt<mode>_sc, gen_ashiftrt<mode>_base))
     {
-      if (INTVAL(operands[2]) == 1)
-       return \"asl %0\";
-      else if (INTVAL(operands[2]) == -1)
-       return \"asr %0\";
+      operands[2] = negate_rtx (HImode, operands[2]);
+      if (<QHSint:e_mname> == E_QImode)
+        {
+          r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1]));
+          emit_insn (gen_aslhi_op (r, r, operands[2]));
+          emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0)));
+        }
+      else
+        {
+          emit_insn (gen_asl<QHSint:hmode>_op (operands[0], operands[1], operands[2]));
+        }
     }
-
-  return \"ash %2,%0\";
-}"
-  [(set_attr "length" "2,4")])
-
-;; Arithmetic right shift on the pdp works by negating the shift count.
-(define_expand "ashrhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (ashift:HI (match_operand:HI 1 "register_operand" "0")
-                  (match_operand:HI 2 "general_operand" "g")))]
-  ""
-  "
-{
-  operands[2] = negate_rtx (HImode, operands[2]);
+  DONE;
 }")
 
-(define_expand "lshrhi3"
-  [(match_operand:HI 0 "register_operand" "")
-   (match_operand:HI 1 "register_operand" "")
+(define_expand "lshr<mode>3"
+  [(match_operand:QHSint 0 "nonimmediate_operand" "")
+   (match_operand:QHSint 1 "general_operand" "")
    (match_operand:HI 2 "general_operand" "")]
   ""
   "
 {
-  rtx r;
+  rtx r, n;
 
-  if (!TARGET_40_PLUS &&
-      (GET_CODE (operands[2]) != CONST_INT ||
-       (unsigned) INTVAL (operands[2]) > 3))
-    FAIL;
-  emit_insn (gen_lsrhi1 (operands[0], operands[1]));
-  if (GET_CODE (operands[2]) != CONST_INT)
-    {
-      r = gen_reg_rtx (HImode);
-      emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1)));
-      emit_insn (gen_ashrhi3 (operands[0], operands[0], r));
-    }
-  else if ((unsigned) INTVAL (operands[2]) != 1)
+  if (!pdp11_expand_shift (operands, gen_lshiftrt<mode>_sc, gen_lshiftrt<mode>_base))
     {
-      emit_insn (gen_ashlhi3 (operands[0], operands[0],
-                              GEN_INT (1 - INTVAL (operands[2]))));
+      if (<QHSint:e_mname> == E_QImode)
+        {
+          r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1]));
+          emit_insn (gen_aslhi_op (r, r, operands[2]));
+          emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0)));
+        }
+      else
+        {
+          r = gen_reg_rtx (<QHSint:mname>);
+          emit_insn (gen_lshiftrt<mode>_sc (r, operands[1], const1_rtx));
+          if (GET_CODE (operands[2]) != CONST_INT)
+            {
+              n = gen_reg_rtx (HImode);
+              emit_insn (gen_addhi3 (n, operands [2], GEN_INT (-1)));
+              emit_insn (gen_ashr<mode>3 (operands[0], r, n));
+            }
+          else
+            emit_insn (gen_asl<QHSint:hmode>_op (operands[0], r,
+                                 GEN_INT (1 - INTVAL (operands[2]))));
+        }
     }
   DONE;
-}
-"
-)
+}")
 
 ;; absolute 
 
-(define_insn "absdf2"
+(define_insn_and_split "absdf2"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
        (abs:DF (match_operand:DF 1 "general_operand" "0,0")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (abs:DF (match_dup 1)))
+             (clobber (reg:CC FCC_REGNUM))])]
+   "")
+
+(define_insn "absdf2<fcc_cc>"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
+       (abs:DF (match_operand:DF 1 "general_operand" "0,0")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{absd|absf} %0"
   [(set_attr "length" "2,4")])
 
-
 ;; negate insns
 
-(define_insn "negdf2"
-  [(set (match_operand:DF 0 "float_nonimm_operand" "=fR,Q")
-       (neg:DF (match_operand:DF 1 "register_operand" "0,0")))]
+(define_insn_and_split "negdf2"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
+       (neg:DF (match_operand:DF 1 "general_operand" "0,0")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (neg:DF (match_dup 1)))
+             (clobber (reg:CC FCC_REGNUM))])]
+   "")
+
+(define_insn "negdf2<fcc_cc>"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
+       (neg:DF (match_operand:DF 1 "general_operand" "0,0")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{negd|negf} %0"
   [(set_attr "length" "2,4")])
 
-(define_insn "negdi2"
+(define_insn_and_split "negdi2"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
        (neg:DI (match_operand:DI 1 "general_operand" "0,0")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (neg:DI (match_dup 1)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+  
+;; TODO: this can be neg/adc/neg/adc... I believe.  Check.  Saves one word.
+(define_insn "negdi2_nocc"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
+       (neg:DI (match_operand:DI 1 "general_operand" "0,0")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
 {
   rtx exops[4][2];
   
 }
 [(set_attr "length" "18,34")])
 
-(define_insn "negsi2"
+(define_insn_and_split "negsi2"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o")
        (neg:SI (match_operand:SI 1 "general_operand" "0,0")))]
   ""
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (neg:SI (match_dup 1)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+  
+;; TODO: this can be neg/adc/neg/adc... I believe.  Check.  Saves one word.
+(define_insn "negsi2_nocc"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o")
+       (neg:SI (match_operand:SI 1 "general_operand" "0,0")))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
 {
   rtx exops[2][2];
   
 
   return \"\";
 }
-[(set_attr "length" "12,20")])
+[(set_attr "length" "10,18")])
 
-(define_insn "neg<mode>2"
+(define_insn_and_split "neg<mode>2"
   [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
        (neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
   ""
-  "neg<isfx> %0"
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 0) (neg:PDPint (match_dup 1)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+  
+(define_insn "neg<mode>2<cc_ccnz>"
+  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
+       (neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "neg<PDPint:isfx> %0"
   [(set_attr "length" "2,4")])
 
 
   ""
   "*
 {
- if (get_attr_length (insn) == 2)
 if (get_attr_length (insn) == 2)
     return \"br %l0\";
- return \"jmp %l0\";
 return \"jmp %l0\";
 }"
   [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 0)
                                                      (pc))
                                      (const_int 4)
                                      (const_int 2)))])
 
-(define_insn ""
-  [(set (pc)
-    (label_ref (match_operand 0 "" "")))
-   (clobber (const_int 1))]
-  ""
-  "jmp %l0"
-  [(set_attr "length" "4")])
-
 (define_insn "tablejump"
   [(set (pc) (match_operand:HI 0 "general_operand" "r,R,Q"))
    (use (label_ref (match_operand 1 "" "")))]
   jmp %@%0"
   [(set_attr "length" "2,2,4")])
 
-;; indirect jump - let's be conservative!
-;; allow only register_operand, even though we could also 
-;; allow labels etc.
-
+;; indirect jump.  TODO: this needs a constraint that allows memory
+;; references but not indirection, since we add a level of indirection
+;; in the generated code.
 (define_insn "indirect_jump"
-  [(set (pc) (match_operand:HI 0 "register_operand" "r"))]
+  [(set (pc) (match_operand:HI 0 "general_operand" "r"))]
   ""
-  "jmp (%0)")
+  "jmp @%0"
+  [(set_attr "length" "2")])
 
 ;;- jump to subroutine
 
 (define_insn "call"
   [(call (match_operand:HI 0 "general_operand" "rR,Q")
-        (match_operand:HI 1 "general_operand" "g,g"))
-;;   (use (reg:HI 0)) what was that ???
-  ]
+        (match_operand:HI 1 "general_operand" "g,g"))]
   ;;- Don't use operand 1 for most machines.
   ""
   "jsr pc, %0"
 (define_insn "call_value"
   [(set (match_operand 0 "" "")
        (call (match_operand:HI 1 "general_operand" "rR,Q")
-             (match_operand:HI 2 "general_operand" "g,g")))
-;;   (use (reg:HI 0)) - what was that ????
-  ]
+             (match_operand:HI 2 "general_operand" "g,g")))]
   ;;- Don't use operand 2 for most machines.
   ""
   "jsr pc, %1"
   [(set_attr "length" "2,4")])
 
+(define_expand "untyped_call"
+  [(parallel [(call (match_operand 0 "" "")
+                   (const_int 0))
+             (match_operand 1 "" "")
+             (match_operand 2 "" "")])]
+  ""
+{
+  int i;
+
+  emit_call_insn (gen_call (operands[0], const0_rtx));
+
+  for (i = 0; i < XVECLEN (operands[2], 0); i++)
+    {
+      rtx set = XVECEXP (operands[2], 0, i);
+      emit_move_insn (SET_DEST (set), SET_SRC (set));
+    }
+
+  /* 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;
+})
+
 ;;- nop instruction
 (define_insn "nop"
   [(const_int 0)]
 
 ;;- multiply 
 
-(define_insn "muldf3"
+(define_insn_and_split "muldf3"
   [(set (match_operand:DF 0 "register_operand" "=a,a")
        (mult:DF (match_operand:DF 1 "register_operand" "%0,0")
                 (match_operand:DF 2 "float_operand" "fR,QF")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (mult:DF (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC FCC_REGNUM))])]
+  "")
+
+(define_insn "muldf3<fcc_ccnz>"
+  [(set (match_operand:DF 0 "register_operand" "=a,a")
+       (mult:DF (match_operand:DF 1 "register_operand" "%0,0")
+             (match_operand:DF 2 "float_operand" "fR,QF")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{muld|mulf} %2, %0"
   [(set_attr "length" "2,4")])
 
-;; 16 bit result multiply:
-;; currently we multiply only into odd registers, so we don't use two 
-;; registers - but this is a bit inefficient at times. If we define 
-;; a register class for each register, then we can specify properly 
-;; which register need which scratch register ....
+;; 16 bit result multiply.  This uses odd numbered registers.
 
-(define_insn "mulhi3"
+(define_insn_and_split "mulhi3"
   [(set (match_operand:HI 0 "register_operand" "=d,d") ; multiply regs
        (mult:HI (match_operand:HI 1 "register_operand" "%0,0")
-                (match_operand:HI 2 "float_operand" "rR,Qi")))]
+                (match_operand:HI 2 "general_operand" "rR,Qi")))]
   "TARGET_40_PLUS"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (mult:HI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "mulhi3<cc_cc>"
+  [(set (match_operand:HI 0 "register_operand" "=d,d")
+       (mult:HI (match_operand:HI 1 "register_operand" "%0,0")
+             (match_operand:HI 2 "general_operand" "rR,Qi")))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_40_PLUS && reload_completed"
   "mul %2, %0"
   [(set_attr "length" "2,4")])
 
-;; 32 bit result
-(define_expand "mulhisi3"
-  [(set (match_dup 3)
-       (match_operand:HI 1 "nonimmediate_operand" "g,g"))
-   (set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered!
-       (mult:SI (truncate:HI 
-                  (match_dup 0))
-                (match_operand:HI 2 "general_operand" "rR,Qi")))]
+;; 32 bit result from 16 bit operands
+(define_insn_and_split "mulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0"))
+                (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi"))))]
   "TARGET_40_PLUS"
-  "operands[3] = gen_lowpart(HImode, operands[1]);")
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0)
+                  (mult:SI (sign_extend:SI (match_dup 1))
+                        (sign_extend:SI (match_dup 2))))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
 
-(define_insn ""
-  [(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered!
-       (mult:SI (truncate:HI 
-                  (match_operand:SI 1 "register_operand" "%0,0"))
-                (match_operand:HI 2 "general_operand" "rR,Qi")))]
-  "TARGET_40_PLUS"
+(define_insn "mulhisi3<cc_cc>"
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0"))
+             (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi"))))
+   (clobber (reg:CC CC_REGNUM))]
+  "TARGET_40_PLUS && reload_completed"
   "mul %2, %0"
   [(set_attr "length" "2,4")])
 
-;(define_insn "mulhisi3"
-;  [(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered!
-;      (mult:SI (truncate:HI 
-;                  (match_operand:SI 1 "register_operand" "%0,0"))
-;               (match_operand:HI 2 "general_operand" "rR,Qi")))]
-;  "TARGET_40_PLUS"
-;  "mul %2, %0"
-;  [(set_attr "length" "2,4")])
-
 ;;- divide
-(define_insn "divdf3"
+(define_insn_and_split "divdf3"
   [(set (match_operand:DF 0 "register_operand" "=a,a")
        (div:DF (match_operand:DF 1 "register_operand" "0,0")
                (match_operand:DF 2 "general_operand" "fR,QF")))]
   "TARGET_FPU"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (match_dup 0) (div:DF (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC FCC_REGNUM))])]
+   "")
+  
+(define_insn "divdf3<fcc_ccnz>"
+  [(set (match_operand:DF 0 "register_operand" "=a,a")
+       (div:DF (match_operand:DF 1 "register_operand" "0,0")
+            (match_operand:DF 2 "general_operand" "fR,QF")))
+   (clobber (reg:CC FCC_REGNUM))]
+  "TARGET_FPU && reload_completed"
   "{divd|divf} %2, %0"
   [(set_attr "length" "2,4")])
 
-        
-(define_expand "divhi3"
-  [(set (subreg:HI (match_dup 1) 0)
+(define_expand "divmodhi4"
+  [(parallel
+    [(set (subreg:HI (match_dup 1) 0)
        (div:HI (match_operand:SI 1 "register_operand" "0")
                (match_operand:HI 2 "general_operand" "g")))
+     (set (subreg:HI (match_dup 1) 2)
+       (mod:HI (match_dup 1) (match_dup 2)))])
    (set (match_operand:HI 0 "register_operand" "=r")
-        (subreg:HI (match_dup 1) 0))]
+        (subreg:HI (match_dup 1) 0))
+   (set (match_operand:HI 3 "register_operand" "=r")
+        (subreg:HI (match_dup 1) 2))]
   "TARGET_40_PLUS"
   "")
 
-(define_insn ""
-  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0)
-       (div:HI (match_operand:SI 1 "general_operand" "0")
-               (match_operand:HI 2 "general_operand" "g")))]
-  "TARGET_40_PLUS"
-  "div %2,%0"
-  [(set_attr "length" "4")])
-
-(define_expand "modhi3"
-  [(set (subreg:HI (match_dup 1) 2)
-       (mod:HI (match_operand:SI 1 "register_operand" "0")
-               (match_operand:HI 2 "general_operand" "g")))
-   (set (match_operand:HI 0 "register_operand" "=r")
-        (subreg:HI (match_dup 1) 2))]
+(define_insn_and_split "*divmodhi4"
+  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0)
+       (div:HI (match_operand:SI 1 "register_operand" "0,0")
+            (match_operand:HI 2 "general_operand" "rR,Qi")))
+   (set (subreg:HI (match_dup 1) 2)
+       (mod:HI (match_dup 1) (match_dup 2)))]
   "TARGET_40_PLUS"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (subreg:HI (match_dup 0) 0)
+                  (div:HI (match_dup 1) (match_dup 2)))
+             (set (subreg:HI (match_dup 1) 2)
+                  (mod:HI (match_dup 1) (match_dup 2)))
+             (clobber (reg:CC CC_REGNUM))])]
   "")
 
-(define_insn ""
-  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 2)
-       (mod:HI (match_operand:SI 1 "general_operand" "0")
-               (match_operand:HI 2 "general_operand" "g")))]
+;; Note that there is no corresponding CC setter pattern.
+;; The reason is that it won't be generated, because
+;; compare-elim.c only does the transformation on input
+;; insns that have a two-element PARALLEL, as opposed to
+;; the three-element one we have here.     
+(define_insn "divmodhi4_nocc"
+  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0)
+       (div:HI (match_operand:SI 1 "register_operand" "0,0")
+               (match_operand:HI 2 "general_operand" "rR,Qi")))
+   (set (subreg:HI (match_dup 1) 2)
+       (mod:HI (match_dup 1) (match_dup 2)))
+   (clobber (reg:CC CC_REGNUM))]
   "TARGET_40_PLUS"
-  "div %2,%0"
-  [(set_attr "length" "4")])
-
-;(define_expand "divmodhi4"
-;  [(parallel [(set (subreg:HI (match_dup 1) 0)
-;                 (div:HI (match_operand:SI 1 "register_operand" "0")
-;                         (match_operand:HI 2 "general_operand" "g")))
-;              (set (subreg:HI (match_dup 1) 2)
-;                 (mod:HI (match_dup 1)
-;                         (match_dup 2)))])
-;   (set (match_operand:HI 3 "register_operand" "=r")
-;        (subreg:HI (match_dup 1) 2))
-;   (set (match_operand:HI 0 "register_operand" "=r")
-;        (subreg:HI (match_dup 1) 0))]
-;  "TARGET_40_PLUS"
-;  "")
-;
-;(define_insn ""
-;  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0)
-;                 (div:HI (match_operand:SI 1 "general_operand" "0")
-;                         (match_operand:HI 2 "general_operand" "g")))
-;   (set (subreg:HI (match_dup 0) 2)
-;                 (mod:HI (match_dup 1)
-;                         (match_dup 2)))]
-;  "TARGET_40_PLUS"
-;  "div %2, %0")
-;
-   
-;; is rotate doing the right thing to be included here ????
+   "div %2,%0"
+  [(set_attr "length" "2,4")])
index 0a1eb223416e806fbae6b944e58053ceba6e8cfd..feebcc674fa4760a4da0270d497ac61b944ae659 100644 (file)
@@ -34,22 +34,6 @@ mac0
 Target Report Mask(AC0)
 Return floating-point results in ac0 (fr0 in Unix assembler syntax).
 
-mbcopy
-Target RejectNegative Report Mask(BCOPY)
-Do not use inline patterns for copying memory.
-
-mbcopy-builtin
-Target RejectNegative Report InverseMask(BCOPY, BCOPY_BUILTIN)
-Use inline patterns for copying memory.
-
-mbranch-cheap
-Target RejectNegative Report InverseMask(BRANCH_EXPENSIVE, BRANCH_CHEAP)
-Do not pretend that branches are expensive.
-
-mbranch-expensive
-Target RejectNegative Report Mask(BRANCH_EXPENSIVE)
-Pretend that branches are expensive.
-
 mdec-asm
 Target RejectNegative Report InverseMask(UNIX_ASM)
 Use the DEC assembler syntax.
index d489a043396b5b41baa2440183ba337a0a34d56c..eed711f7281b76af47256787f3bcad816ec19af6 100644 (file)
   (ior (match_operand 0 "register_operand")
        (match_test "op == CONST0_RTX (GET_MODE (op))")))
 
-;; Accept integer arguments in the range -4..-2 and 2..4, which are the
+;; Accept integer arguments in the range 1..3, which are the
 ;; shift counts for which we unroll a shift.  This matches the rule for
 ;; the "O" constraint.
 (define_predicate "expand_shift_operand"
-  (match_code "const_int")
-{
-  int sh;
-
-  sh = INTVAL (op);
-  return (abs (sh) > 1 && abs (sh) <= 4);
-})
+  (and (match_code "const_int")
+       (match_test "(unsigned) INTVAL (op) < 4")))
 
 ;; Accept anything general_operand accepts, except that registers must
 ;; be FPU registers.
@@ -52,3 +47,7 @@
                 (match_test "REGNO_REG_CLASS (REGNO (op)) == LOAD_FPU_REGS")
                 (match_test "REGNO_REG_CLASS (REGNO (op)) == NO_LOAD_FPU_REGS"))
                (match_operand 0 "nonimmediate_operand")))
+
+;; Accept any comparison valid for CCNZmode
+(define_predicate "ccnz_operator"
+  (match_code "eq,ne,ge,lt"))
index 1014022d6bc72b4bf9c54f4385b6a7771b7f7e9d..df4c55fdefbb2759a022025cd2f5410b45fba08f 100644 (file)
@@ -969,11 +969,9 @@ Objective-C and Objective-C++ Dialects}.
 
 @emph{PDP-11 Options}
 @gccoptlist{-mfpu  -msoft-float  -mac0  -mno-ac0  -m40  -m45  -m10 @gol
--mbcopy  -mbcopy-builtin  -mint32  -mno-int16 @gol
--mint16  -mno-int32  -mfloat32  -mno-float64 @gol
--mfloat64  -mno-float32  -mabshi  -mno-abshi @gol
--mbranch-expensive  -mbranch-cheap @gol
--munix-asm  -mdec-asm}
+-mint32  -mno-int16 -mint16  -mno-int32 @gol
+-mfloat32  -mno-float64 -mfloat64  -mno-float32 @gol
+-msplit -munix-asm  -mdec-asm}
 
 @emph{picoChip Options}
 @gccoptlist{-mae=@var{ae_type}  -mvliw-lookahead=@var{N} @gol
@@ -22018,7 +22016,7 @@ These options are defined for the PDP-11:
 @item -mfpu
 @opindex mfpu
 Use hardware FPP floating point.  This is the default.  (FIS floating
-point on the PDP-11/40 is not supported.)
+point on the PDP-11/40 is not supported.)  Implies -m45.
 
 @item -msoft-float
 @opindex msoft-float
@@ -22034,7 +22032,7 @@ Return floating-point results in memory.  This is the default.
 
 @item -m40
 @opindex m40
-Generate code for a PDP-11/40.
+Generate code for a PDP-11/40.  Implies -msoft-float -mno-split.
 
 @item -m45
 @opindex m45
@@ -22042,16 +22040,7 @@ Generate code for a PDP-11/45.  This is the default.
 
 @item -m10
 @opindex m10
-Generate code for a PDP-11/10.
-
-@item -mbcopy-builtin
-@opindex mbcopy-builtin
-Use inline @code{movmemhi} patterns for copying memory.  This is the
-default.
-
-@item -mbcopy
-@opindex mbcopy
-Do not use inline @code{movmemhi} patterns for copying memory.
+Generate code for a PDP-11/10.  Implies -msoft-float -mno-split.
 
 @item -mint16
 @itemx -mno-int32
@@ -22077,32 +22066,17 @@ Use 64-bit @code{float}.  This is the default.
 @opindex mno-float64
 Use 32-bit @code{float}.
 
-@item -mabshi
-@opindex mabshi
-Use @code{abshi2} pattern.  This is the default.
-
-@item -mno-abshi
-@opindex mno-abshi
-Do not use @code{abshi2} pattern.
-
-@item -mbranch-expensive
-@opindex mbranch-expensive
-Pretend that branches are expensive.  This is for experimenting with
-code generation only.
-
-@item -mbranch-cheap
-@opindex mbranch-cheap
-Do not pretend that branches are expensive.  This is the default.
+@item -msplit
+@opindex msplit
+Target has split instruction and data space.  Implies -m45.
 
 @item -munix-asm
 @opindex munix-asm
-Use Unix assembler syntax.  This is the default when configured for
-@samp{pdp11-*-bsd}.
+Use Unix assembler syntax.
 
 @item -mdec-asm
 @opindex mdec-asm
-Use DEC assembler syntax.  This is the default when configured for any
-PDP-11 target other than @samp{pdp11-*-bsd}.
+Use DEC assembler syntax.  This is the default.
 @end table
 
 @node picoChip Options
index a3ecb711ecaa69e2c4a2ba194581e726fa857149..22919e4310c90763e5daa71778d68803c331f6dc 100644 (file)
@@ -2966,12 +2966,20 @@ memory with a single instruction.
 Odd numbered general registers (R1, R3, R5).  These are used for
 16-bit multiply operations.
 
+@item D
+A memory reference that is encoded within the opcode, but not
+auto-increment or auto-decrement.
+
 @item f
 Any of the floating point registers (AC0 through AC5).
 
 @item G
 Floating point constant 0.
 
+@item h
+Floating point registers AC4 and AC5.  These cannot be loaded from/to
+memory with a single instruction.
+
 @item I
 An integer constant that fits in 16 bits.
 
@@ -2992,7 +3000,7 @@ The integer constant @minus{}1.
 The integer constant 0.
 
 @item O
-Integer constants @minus{}4 through @minus{}1 and 1 through 4; shifts by these
+Integer constants 0 through 3; shifts by these
 amounts are handled as multiple single-bit shifts rather than a single
 variable-length shift.