re PR c/87795 (Excessive alignment permitted for functions and labels)
authorPaul Koning <ni1d@arrl.net>
Thu, 8 Nov 2018 18:56:58 +0000 (13:56 -0500)
committerPaul Koning <pkoning@gcc.gnu.org>
Thu, 8 Nov 2018 18:56:58 +0000 (13:56 -0500)
* config/pdp11/constraints.md: Add "Z" series constraints for use
with pre-dec and post-inc addressing.
* config/pdp11/pdp11-protos.m (expand_block_move): Delete.
(pdp11_expand_operands): Add int argument (word count).
(pdp11_sp_frame_offset): Delete.
(pdp11_cmp_length): New function.
(pushpop_regeq): New function.
* config/pdp11/pdp11.c (TARGET_STACK_PROTECT_RUNTIME_ENABLED_P):
Add hook.
(pdp11_expand_prologue, pdp11_expand_epilogue): Rewrite for new
frame layout.
(pdp11_initial_elimination_offset): Ditto.
(pdp11_expand_operands): Add word count argument.  Bugfixes.
(output_move_multiple): Change how pointer adjustment is done.
(pdp11_gen_int_label): Correct format.
(output_ascii): Ditto.
(pdp11_asm_output_var): Add code for DEC assembler case.
(pdp11_asm_print_operand): Bugfix for CONST_DOUBLE holding integer
value.
(legitimate_const_double_p): Ditto.
(pdp11_register_move_cost): Adjust for new register classes.
(pdp11_regno_reg_class): Ditto.
(expand_block_move): Delete.
(pushpop_regeq): New function.
(pdp11_legitimate_address_p): Bugfix in check for constant
offset.
(pdp11_sp_frame_offset): Delete.
(pdp11_reg_save_size): New helper function for new frame layout.
(output_addr_const_pdp11): Remove CONST_DOUBLE case.
(pdp11_expand_shift): Bugfix in check for constant shift count.
(pdp11_shift_length): Ditto.
(pdp11_assemble_shift): Copy input to pdp11_expand_operands.
(pdp11_cmp_length): New function.
* config/pdp11/pdp11.h (TARGET_CPU_CPP_BUILTINS): Add macros for
some compile options.
(FIXED_REGISTERS): Remove HARD_FRAME_POINTER_REGNUM.
(CALL_USED_REGISTERS): Ditto.
(ELIMINABLE_REGS): Ditto.
(REGISTER_NAMES): Ditto.
(reg_class): Add classes NOTR0_REG through NOTSP_REG for use by Z
constraints.
(REG_CLASS_NAMES): Ditto.
(REG_CLASS_CONTENTS): Ditto.  Also remove
HARD_FRAME_POINTER_REGNUM.
(CPU_REG_CLASS): New macro.
(CLASS_MAX_NREGS): Adjust for new register classes.
(FUNCTION_PROFILER): Make no-op.
(may_call_alloca): Remove unused declaration.
(ASM_OUTPUT_ALIGN): Add workaround for PR87795.
(ASM_OUTPUT_SKIP): Fix format.
* config/pdp11/pdp11.md (unspecv): Add UNSPECV_MOVMEM.
(HARD_FRAME_POINTER_REGNUM): Remove.
(return): Delete.
(*rts): Rename.  Remove epilogue related checks.
(cmpsi, cmpdi): New insn.
(cbranch<mode>4): Change to apply to SI and DI modes as well.
(mov<mode>): Change constraints to enforce that push/pop
destination cannot use the same register as source.
(*mov<mode><cc_cc>): Ditto.
(movmemhi, movmemhi1, movmemhi_nocc): Change to expand block move
at assembly output rather than as RTL expander.
(zero_extendqihi2): Bugfix in check for same registers.
(adddi3_nocc): Bugfix in check for constant operand.
(addsi3_nocc): Ditto.
(subdi3_nocc): Ditto.
(subsi3_nocc): Ditto.
(negdi2_nocc): Copy input to pdp11_expand_operands.
(negsi2_nocc): Ditto.
(bswap2_nocc): Ditto.
* config/pdp11/pdp11.opt (mlra): Fix documentation.
* config/pdp11/t-pdp11: Use -Os.

From-SVN: r265932

gcc/ChangeLog
gcc/config/pdp11/constraints.md
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/t-pdp11

index 9728c82..e131f62 100644 (file)
@@ -1,3 +1,77 @@
+2018-11-08  Paul Koning  <ni1d@arrl.net>
+
+       * config/pdp11/constraints.md: Add "Z" series constraints for use
+       with pre-dec and post-inc addressing.
+       * config/pdp11/pdp11-protos.m (expand_block_move): Delete.
+       (pdp11_expand_operands): Add int argument (word count).
+       (pdp11_sp_frame_offset): Delete.
+       (pdp11_cmp_length): New function.
+       (pushpop_regeq): New function.
+       * config/pdp11/pdp11.c (TARGET_STACK_PROTECT_RUNTIME_ENABLED_P):
+       Add hook.
+       (pdp11_expand_prologue, pdp11_expand_epilogue): Rewrite for new
+       frame layout.
+       (pdp11_initial_elimination_offset): Ditto.
+       (pdp11_expand_operands): Add word count argument.  Bugfixes.
+       (output_move_multiple): Change how pointer adjustment is done.
+       (pdp11_gen_int_label): Correct format.
+       (output_ascii): Ditto.
+       (pdp11_asm_output_var): Add code for DEC assembler case.
+       (pdp11_asm_print_operand): Bugfix for CONST_DOUBLE holding integer
+       value.
+       (legitimate_const_double_p): Ditto.
+       (pdp11_register_move_cost): Adjust for new register classes.
+       (pdp11_regno_reg_class): Ditto.
+       (expand_block_move): Delete.
+       (pushpop_regeq): New function.
+       (pdp11_legitimate_address_p): Bugfix in check for constant
+       offset.
+       (pdp11_sp_frame_offset): Delete.
+       (pdp11_reg_save_size): New helper function for new frame layout.
+       (output_addr_const_pdp11): Remove CONST_DOUBLE case.
+       (pdp11_expand_shift): Bugfix in check for constant shift count.
+       (pdp11_shift_length): Ditto.
+       (pdp11_assemble_shift): Copy input to pdp11_expand_operands.
+       (pdp11_cmp_length): New function.
+       * config/pdp11/pdp11.h (TARGET_CPU_CPP_BUILTINS): Add macros for
+       some compile options.
+       (FIXED_REGISTERS): Remove HARD_FRAME_POINTER_REGNUM.
+       (CALL_USED_REGISTERS): Ditto.
+       (ELIMINABLE_REGS): Ditto.
+       (REGISTER_NAMES): Ditto.
+       (reg_class): Add classes NOTR0_REG through NOTSP_REG for use by Z
+       constraints.
+       (REG_CLASS_NAMES): Ditto.
+       (REG_CLASS_CONTENTS): Ditto.  Also remove
+       HARD_FRAME_POINTER_REGNUM.
+       (CPU_REG_CLASS): New macro.
+       (CLASS_MAX_NREGS): Adjust for new register classes.
+       (FUNCTION_PROFILER): Make no-op.
+       (may_call_alloca): Remove unused declaration.
+       (ASM_OUTPUT_ALIGN): Add workaround for PR87795.
+       (ASM_OUTPUT_SKIP): Fix format.
+       * config/pdp11/pdp11.md (unspecv): Add UNSPECV_MOVMEM.
+       (HARD_FRAME_POINTER_REGNUM): Remove.
+       (return): Delete.
+       (*rts): Rename.  Remove epilogue related checks.
+       (cmpsi, cmpdi): New insn.
+       (cbranch<mode>4): Change to apply to SI and DI modes as well.
+       (mov<mode>): Change constraints to enforce that push/pop
+       destination cannot use the same register as source.
+       (*mov<mode><cc_cc>): Ditto.
+       (movmemhi, movmemhi1, movmemhi_nocc): Change to expand block move
+       at assembly output rather than as RTL expander.
+       (zero_extendqihi2): Bugfix in check for same registers.
+       (adddi3_nocc): Bugfix in check for constant operand.
+       (addsi3_nocc): Ditto.
+       (subdi3_nocc): Ditto.
+       (subsi3_nocc): Ditto.
+       (negdi2_nocc): Copy input to pdp11_expand_operands.
+       (negsi2_nocc): Ditto.
+       (bswap2_nocc): Ditto.
+       * config/pdp11/pdp11.opt (mlra): Fix documentation.
+       * config/pdp11/t-pdp11: Use -Os.
+
 2018-11-08  Richard Earnshaw  <rearnsha@arm.com>
 
        * config/arm/parsecpu.awk (/alias/): New parsing rule.
index 33882ed..d821af3 100644 (file)
        (match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
                     && no_side_effect_operand (op, GET_MODE (op))")))
 
+;; What follows is a set of constraints used to prevent the generation
+;; of insns that have a register as source, and an auto-increment or
+;; auto-decrement memory reference as the destination where the register
+;; is the same as the source.  On the PDP11, such instructions are not
+;; implemented consistently across the models and often do something
+;; different from what the RTL intends.
+(define_register_constraint "Z0" "NOTR0_REG" "Register other than 0")
+(define_register_constraint "Z1" "NOTR1_REG" "Register other than 1")
+(define_register_constraint "Z2" "NOTR2_REG" "Register other than 2")
+(define_register_constraint "Z3" "NOTR3_REG" "Register other than 3")
+(define_register_constraint "Z4" "NOTR4_REG" "Register other than 4")
+(define_register_constraint "Z5" "NOTR5_REG" "Register other than 5")
+(define_register_constraint "Z6" "NOTSP_REG"
+  "Register other than stack pointer (register 6)")
+(define_memory_constraint "Za" "R0 push/pop"
+  (match_test "pushpop_regeq (op, 0)"))
+(define_memory_constraint "Zb" "R1 push/pop"
+  (match_test "pushpop_regeq (op, 1)"))
+(define_memory_constraint "Zc" "R2 push/pop"
+  (match_test "pushpop_regeq (op, 2)"))
+(define_memory_constraint "Zd" "R3 push/pop"
+  (match_test "pushpop_regeq (op, 3)"))
+(define_memory_constraint "Ze" "R4 push/pop"
+  (match_test "pushpop_regeq (op, 4)"))
+(define_memory_constraint "Zf" "R5 push/pop"
+  (match_test "pushpop_regeq (op, 5)"))
+(define_memory_constraint "Zg" "SP push/pop"
+  (match_test "pushpop_regeq (op, 6)"))
+  
index 0ed61ea..135d437 100644 (file)
@@ -26,14 +26,12 @@ 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 void expand_block_move (rtx *);
 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, 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 *);
@@ -42,6 +40,8 @@ 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 int pdp11_shift_length (rtx *, machine_mode, int, bool);
+extern int pdp11_cmp_length (rtx *, int);
+extern bool pushpop_regeq (rtx, int);
 extern bool pdp11_small_shift (int);
 
 #endif /* RTX_CODE */
index 06129f1..0019efe 100644 (file)
@@ -304,6 +304,9 @@ static bool pdp11_scalar_mode_supported_p (scalar_mode);
 
 #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
 #define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed
+
+#undef  TARGET_STACK_PROTECT_RUNTIME_ENABLED_P
+#define TARGET_STACK_PROTECT_RUNTIME_ENABLED_P hook_bool_void_false
 \f
 /* A helper function to determine if REGNO should be saved in the
    current function's stack frame.  */
@@ -316,6 +319,13 @@ pdp11_saved_regno (unsigned regno)
 
 /* Expand the function prologue.  */
 
+/* Frame layout, from high to low memory (stack push order):
+   return address (from jsr instruction)
+   saved CPU registers, lowest number first
+   saved FPU registers, lowest number first, always 64 bit mode
+   *** frame pointer points here ***
+   local variables
+   alloca storage if any.  */
 void
 pdp11_expand_prologue (void)
 {                                                             
@@ -331,31 +341,9 @@ pdp11_expand_prologue (void)
       emit_insn (gen_seti ());
     }
     
-  if (frame_pointer_needed)                                    
-    {                                                          
-      x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
-      x = gen_frame_mem (Pmode, x);
-      emit_move_insn (x, hard_frame_pointer_rtx);
-
-      emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
-    }                                                          
-
-  /* Make frame.  */
-  if (fsize)
-    {
-      emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx,
-                            GEN_INT (-fsize)));
-
-      /* Prevent frame references via the frame pointer from being
-        scheduled before the frame is allocated.  */
-      if (frame_pointer_needed)
-       emit_insn (gen_blockage ());
-    }
-
   /* Save CPU registers.  */
   for (regno = R0_REGNUM; regno <= PC_REGNUM; regno++)
-    if (pdp11_saved_regno (regno)
-       && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
+    if (pdp11_saved_regno (regno))
       {
        x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
        x = gen_frame_mem (Pmode, x);
@@ -383,25 +371,21 @@ pdp11_expand_prologue (void)
        x = gen_frame_mem (DFmode, x);
        emit_move_insn (x, via_ac);
       }
-}
-
-/* The function epilogue should not depend on the current stack pointer!
-   It should use the frame pointer only.  This is mandatory because
-   of alloca; we also take advantage of it to omit stack adjustments
-   before returning.  */
-
-/* Maybe we can make leaf functions faster by switching to the
-   second register file - this way we don't have to save regs!
-   leaf functions are ~ 50% of all functions (dynamically!) 
 
-   set/clear bit 11 (dec. 2048) of status word for switching register files - 
-   but how can we do this? the pdp11/45 manual says bit may only 
-   be set (p.24), but not cleared!
+  if (frame_pointer_needed)
+    emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
 
-   switching to kernel is probably more expensive, so we'll leave it 
-   like this and not use the second set of registers... 
+  /* Make local variable space.  */
+  if (fsize)
+    emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx,
+                          GEN_INT (-fsize)));
+}
 
-   maybe as option if you want to generate code for kernel mode? */
+/* Generate epilogue.  This uses the frame pointer to pop the local
+   variables and any alloca data off the stack.  If there is no alloca
+   and frame pointer elimination hasn't been disabled, there is no
+   frame pointer and the local variables are popped by adjusting the
+   stack pointer instead.  */
 
 void
 pdp11_expand_epilogue (void)
@@ -410,6 +394,20 @@ pdp11_expand_epilogue (void)
   unsigned regno;
   rtx x, reg, via_ac = NULL;
 
+  /* Deallocate the local variables.  */
+  if (fsize)
+    {
+      if (frame_pointer_needed)
+       {
+         /* We can deallocate the frame with a single move.  */
+         emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+       }
+      else
+       emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx,
+                              GEN_INT (fsize)));
+    }
+
+  /* Restore the FPU registers.  */
   if (pdp11_saved_regno (AC4_REGNUM) || pdp11_saved_regno (AC5_REGNUM))
     {
       /* Find a temporary with which to restore AC4/5.  */
@@ -421,109 +419,33 @@ pdp11_expand_epilogue (void)
          }
     }
 
-  /* If possible, restore registers via pops.  */
-  if (!frame_pointer_needed || crtl->sp_is_unchanging)
-    {
-      /* Restore registers via pops.  */
-
-      for (regno = AC5_REGNUM; regno >= AC0_REGNUM; regno--)
-       if (pdp11_saved_regno (regno))
-         {
-           x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
-           x = gen_frame_mem (DFmode, x);
-           reg = gen_rtx_REG (DFmode, regno);
-
-           if (LOAD_FPU_REG_P (regno))
-             emit_move_insn (reg, x);
-           else
-             {
-               emit_move_insn (via_ac, x);
-               emit_move_insn (reg, via_ac);
-             }
-         }
+  /* Restore registers via pops.  */
 
-      for (regno = PC_REGNUM; regno >= R0_REGNUM + 2; regno--)
-       if (pdp11_saved_regno (regno)
-           && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
-         {
-           x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
-           x = gen_frame_mem (Pmode, x);
-           emit_move_insn (gen_rtx_REG (Pmode, regno), x);
-         }
-    }
-  else
-    {
-      /* Restore registers via moves.  */
-      /* ??? If more than a few registers need to be restored, it's smaller
-        to generate a pointer through which we can emit pops.  Consider
-        that moves cost 2*NREG words and pops cost NREG+3 words.  This
-        means that the crossover is NREG=3.
-
-        Possible registers to use are:
-         (1) The first call-saved general register.  This register will
-               be restored with the last pop.
-         (2) R1, if it's not used as a return register.
-         (3) FP itself.  This option may result in +4 words, since we
-               may need two add imm,rn instructions instead of just one.
-               This also has the downside that we're not representing
-               the unwind info in any way, so during the epilogue the
-               debugger may get lost.  */
-
-      HOST_WIDE_INT ofs = -pdp11_sp_frame_offset ();
-
-      for (regno = AC5_REGNUM; regno >= AC0_REGNUM; regno--)
-       if (pdp11_saved_regno (regno))
-         {
-           x = plus_constant (Pmode, hard_frame_pointer_rtx, ofs);
-           x = gen_frame_mem (DFmode, x);
-           reg = gen_rtx_REG (DFmode, regno);
-
-           if (LOAD_FPU_REG_P (regno))
-             emit_move_insn (reg, x);
-           else
-             {
-               emit_move_insn (via_ac, x);
-               emit_move_insn (reg, via_ac);
-             }
-           ofs += 8;
-         }
+  for (regno = AC5_REGNUM; regno >= AC0_REGNUM; regno--)
+    if (pdp11_saved_regno (regno))
+      {
+       x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
+       x = gen_frame_mem (DFmode, x);
+       reg = gen_rtx_REG (DFmode, regno);
 
-      for (regno = PC_REGNUM; regno >= R0_REGNUM + 2; regno--)
-       if (pdp11_saved_regno (regno)
-           && (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
+       if (LOAD_FPU_REG_P (regno))
+         emit_move_insn (reg, x);
+       else
          {
-           x = plus_constant (Pmode, hard_frame_pointer_rtx, ofs);
-           x = gen_frame_mem (Pmode, x);
-           emit_move_insn (gen_rtx_REG (Pmode, regno), x);
-           ofs += 2;
+           emit_move_insn (via_ac, x);
+           emit_move_insn (reg, via_ac);
          }
-    }
-
-  /* Deallocate the stack frame.  */
-  if (fsize)
-    {
-      /* Prevent frame references via any pointer from being
-        scheduled after the frame is deallocated.  */
-      emit_insn (gen_blockage ());
-
-      if (frame_pointer_needed)
-       {
-         /* We can deallocate the frame with a single move.  */
-         emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
-       }
-      else
-       emit_insn (gen_addhi3 (stack_pointer_rtx, stack_pointer_rtx,
-                              GEN_INT (fsize)));
-    }
+      }
 
-  if (frame_pointer_needed)
-    {
-      x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
-      x = gen_frame_mem (Pmode, x);
-      emit_move_insn (hard_frame_pointer_rtx, x);
-    }
+  for (regno = PC_REGNUM; regno >= R0_REGNUM + 2; regno--)
+    if (pdp11_saved_regno (regno))
+      {
+       x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
+       x = gen_frame_mem (Pmode, x);
+       emit_move_insn (gen_rtx_REG (Pmode, regno), x);
+      }
 
-  emit_jump_insn (gen_return ());
+  emit_jump_insn (gen_rtspc ());
 }
 
 /* Return the best assembler insn template
@@ -539,21 +461,23 @@ singlemove_string (rtx *operands)
 
 \f
 /* Expand multi-word operands (SImode or DImode) into the 2 or 4
-   corresponding HImode operands.  The number of operands is given
-   as the third argument, and the required order of the parts as
-   the fourth argument.  */
+   corresponding HImode operands.  The number of operands is given as
+   the third argument, the word count for the mode as the fourth
+   argument, and the required order of parts as the sixth argument.
+   The word count is explicit because sometimes we're asked to compare
+   two constants, both of which have mode VOIDmode, so we can't always
+   rely on the input operand mode to imply the operand size.  */
 bool
-pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount, 
+pdp11_expand_operands (rtx *operands, rtx exops[][2],
+                      int opcount, int words,
                       pdp11_action *action, pdp11_partorder order)
 {
-  int words, op, w, i, sh;
+  int op, w, i, sh;
   pdp11_partorder useorder;
   bool sameoff = false;
   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype;
   long sval[2];
   
-  words = GET_MODE_BITSIZE (GET_MODE (operands[0])) / 16;
-  
   /* If either piece order is accepted and one is pre-decrement
      while the other is post-increment, set order to be high order
      word first.  That will force the pre-decrement to be turned
@@ -566,19 +490,16 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
   useorder = either;
   if (opcount == 2)
     {
-      if (!REG_P (operands[0]) && !REG_P (operands[1]) &&
-         !(CONSTANT_P (operands[1]) || 
-           GET_CODE (operands[1]) == CONST_DOUBLE) &&
+      if (GET_CODE (operands[0]) == MEM &&
+         GET_CODE (operands[1]) == MEM &&
          ((GET_CODE (XEXP (operands[0], 0)) == POST_INC &&
            GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ||
           (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC &&
            GET_CODE (XEXP (operands[1], 0)) == POST_INC)))
            useorder = big;
-      else if ((!REG_P (operands[0]) &&
+      else if ((GET_CODE (operands[0]) == MEM &&
                GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ||
-              (!REG_P (operands[1]) &&
-               !(CONSTANT_P (operands[1]) || 
-                 GET_CODE (operands[1]) == CONST_DOUBLE) &&
+              (GET_CODE (operands[1]) == MEM &&
                GET_CODE (XEXP (operands[1], 0)) == PRE_DEC))
        useorder = little;
       else if (REG_P (operands[0]) && REG_P (operands[1]) &&
@@ -615,7 +536,7 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
       /* First classify the operand.  */
       if (REG_P (operands[op]))
        optype = REGOP;
-      else if (CONSTANT_P (operands[op])
+      else if (CONST_INT_P (operands[op])
               || GET_CODE (operands[op]) == CONST_DOUBLE)
        optype = CNSTOP;
       else if (GET_CODE (XEXP (operands[op], 0)) == POST_INC)
@@ -663,8 +584,11 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
        }
 
       if (GET_CODE (operands[op]) == CONST_DOUBLE)
-       REAL_VALUE_TO_TARGET_DOUBLE
-         (*CONST_DOUBLE_REAL_VALUE (operands[op]), sval);
+       {
+         gcc_assert (GET_MODE (operands[op]) != VOIDmode);
+         REAL_VALUE_TO_TARGET_DOUBLE
+           (*CONST_DOUBLE_REAL_VALUE (operands[op]), sval);
+       }
       
       for (i = 0; i < words; i++)
        {
@@ -707,24 +631,31 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
 const char *
 output_move_multiple (rtx *operands)
 {
+  rtx inops[2];
   rtx exops[4][2];
+  rtx adjops[2];
+  
   pdp11_action action[2];
   int i, words;
   
   words = GET_MODE_BITSIZE (GET_MODE (operands[0])) / 16;
+  adjops[1] = gen_rtx_CONST_INT (HImode, words * 2);
 
-  pdp11_expand_operands (operands, exops, 2, action, either);
+  inops[0] = operands[0];
+  inops[1] = operands[1];
+  
+  pdp11_expand_operands (inops, exops, 2, words, action, either);
   
   /* Check for explicit decrement before.  */
   if (action[0] == dec_before)
     {
-      operands[0] = XEXP (operands[0], 0);
-      output_asm_insn ("sub\t%#4,%0", operands);
+      adjops[0] = XEXP (XEXP (operands[0], 0), 0);
+      output_asm_insn ("sub\t%1,%0", adjops);
     }
   if (action[1] == dec_before)
     {
-      operands[1] = XEXP (operands[1], 0);
-      output_asm_insn ("sub\t%#4,%1", operands);
+      adjops[0] = XEXP (XEXP (operands[1], 0), 0);
+      output_asm_insn ("sub\t%1,%0", adjops);
     }
 
   /* Do the words.  */
@@ -734,13 +665,13 @@ output_move_multiple (rtx *operands)
   /* Check for increment after.  */
   if (action[0] == inc_after)
     {
-      operands[0] = XEXP (operands[0], 0);
-      output_asm_insn ("add\t%#4,%0", operands);
+      adjops[0] = XEXP (XEXP (operands[0], 0), 0);
+      output_asm_insn ("add\t%1,%0", adjops);
     }
   if (action[1] == inc_after)
     {
-      operands[1] = XEXP (operands[1], 0);
-      output_asm_insn ("add\t%#4,%1", operands);
+      adjops[0] = XEXP (XEXP (operands[1], 0), 0);
+      output_asm_insn ("add\t%1,%0", adjops);
     }
 
   return "";
@@ -752,9 +683,9 @@ pdp11_gen_int_label (char *label, const char *prefix, int num)
 {
   if (TARGET_DEC_ASM)
     /* +1 because GCC numbers labels starting at zero.  */
-    sprintf (label, "*%lu$", num + 1);
+    sprintf (label, "*%u$", num + 1);
   else
-    sprintf (label, "*%s_%lu", prefix, num);
+    sprintf (label, "*%s_%u", prefix, num);
 }
   
 /* Output an ascii string.  */
@@ -780,7 +711,7 @@ output_ascii (FILE *file, const char *p, int size)
            {
              if (delim)
                putc ('"', file);
-             fprintf (file, "<%o%>", c);
+             fprintf (file, "<%o>", c);
              delim = false;
            }
          else
@@ -815,15 +746,30 @@ pdp11_asm_output_var (FILE *file, const char *name, int size,
 {
   if (align > 8)
     fprintf (file, "\t.even\n");
-  if (global)
+  if (TARGET_DEC_ASM)
     {
-      fprintf (file, ".globl ");
       assemble_name (file, name);
+      if (global)
+       fputs ("::", file);
+      else
+       fputs (":", file);
+      if (align > 8)
+       fprintf (file, "\t.blkw\t%o\n", (size & 0xffff) / 2);
+      else
+       fprintf (file, "\t.blkb\t%o\n", size & 0xffff);
     }
-  fprintf (file, "\n");
-  assemble_name (file, name);
-  fputs (":", file);
-  ASM_OUTPUT_SKIP (file, size);
+  else
+    {
+      if (global)
+       {
+         fprintf (file, ".globl ");
+         assemble_name (file, name);
+       }
+      fprintf (file, "\n");
+      assemble_name (file, name);
+      fputs (":", file);
+      ASM_OUTPUT_SKIP (file, size);
+    }  
 }
 
 /* Special format operators handled here:
@@ -855,7 +801,7 @@ pdp11_asm_print_operand (FILE *file, rtx x, int code)
     fprintf (file, "%s", reg_names[REGNO (x)]);
   else if (GET_CODE (x) == MEM)
     output_address (GET_MODE (x), XEXP (x, 0));
-  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != SImode)
+  else if (GET_CODE (x) == CONST_DOUBLE && FLOAT_MODE_P (GET_MODE (x)))
     {
       REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (x), sval);
       if (TARGET_DEC_ASM)
@@ -1013,8 +959,7 @@ static int
 pdp11_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
                          reg_class_t c1, reg_class_t c2)
 {
-  if (((c1 == MUL_REGS || c1 == GENERAL_REGS) &&
-       (c2 == MUL_REGS || c2 == GENERAL_REGS)))
+  if (CPU_REG_CLASS (c1) && CPU_REG_CLASS (c2))
     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))
@@ -1512,50 +1457,32 @@ no_side_effect_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
   return FALSE;
 }
 
-
-/*
- * expand a block move:
- *
- * operands[0] ... to
- * operands[1]  ... from
- * operands[2]  ... length
- * operands[3]  ... alignment
- */
-
-void
-expand_block_move(rtx *operands)
+/* Return TRUE if op is a push or pop using the register "regno".  */
+bool
+pushpop_regeq (rtx op, int regno)
 {
-    rtx lb, test;
-    rtx fromop, toop, counter;
-    int count;
-
-    /* Transform BLKmode MEM reference into a (reg)+ operand.  */
-    toop = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
-    toop = gen_rtx_POST_INC (Pmode, toop);
-    fromop = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
-    fromop = gen_rtx_POST_INC (Pmode, fromop);
-
-    count = INTVAL (operands[2]);
-    if (INTVAL (operands [3]) >= 2 && (count & 1) == 0)
-      {
-       count >>= 1;
-       toop = gen_rtx_MEM (HImode, toop);
-       fromop = gen_rtx_MEM (HImode, fromop);
-      }
-    else
-      {
-       toop = gen_rtx_MEM (QImode, toop);
-       fromop = gen_rtx_MEM (QImode, fromop);
-      }
-    counter = copy_to_mode_reg (HImode, gen_rtx_CONST_INT (HImode, count));
+  rtx addr;
+  
+  /* False if not memory reference.  */
+  if (GET_CODE (op) != MEM)
+    return FALSE;
+  
+  /* Get the address of the memory reference.  */
+  addr = XEXP (op, 0);
 
-    /* Label at top of loop */
-    lb = gen_label_rtx ();
-    emit_label (lb);
-    emit_move_insn (toop, fromop);
-    emit_insn (gen_subhi3 (counter, counter, const1_rtx));
-    test = gen_rtx_NE (HImode, counter, const0_rtx);
-    emit_jump_insn (gen_cbranchhi4 (test, counter, const0_rtx, lb));
+  if (GET_CODE (addr) == MEM)
+    addr = XEXP (addr, 0);
+    
+  switch (GET_CODE (addr))
+    {
+    case PRE_DEC:
+    case POST_INC:
+    case PRE_MODIFY:
+    case POST_MODIFY:
+      return REGNO (XEXP (addr, 0)) == regno;
+    default:
+      return FALSE;
+    }
 }
 
 /* This function checks whether a real value can be encoded as
@@ -1565,7 +1492,12 @@ int
 legitimate_const_double_p (rtx address)
 {
   long sval[2];
+
+  /* If it's too big for HOST_WIDE_INT, it's definitely to big here.  */
+  if (GET_MODE (address) == VOIDmode)
+    return 0;
   REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (address), sval);
+
   if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
     return 1;
   return 0;
@@ -1723,7 +1655,7 @@ pdp11_legitimate_address_p (machine_mode mode,
          && GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS
          && GET_CODE (XEXP (xfoob, 0)) == REG
          && REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM
-         && CONSTANT_P (XEXP (xfoob, 1))
+         && CONST_INT_P (XEXP (xfoob, 1))
          && INTVAL (XEXP (xfoob,1)) == -2;
 
       case POST_MODIFY:
@@ -1733,7 +1665,7 @@ pdp11_legitimate_address_p (machine_mode mode,
          && GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS
          && GET_CODE (XEXP (xfoob, 0)) == REG
          && REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM
-         && CONSTANT_P (XEXP (xfoob, 1))
+         && CONST_INT_P (XEXP (xfoob, 1))
          && INTVAL (XEXP (xfoob,1)) == 2;
 
       case MEM:
@@ -1792,16 +1724,18 @@ pdp11_legitimate_address_p (machine_mode mode,
 enum reg_class
 pdp11_regno_reg_class (int regno)
 { 
-  if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM)
-    return GENERAL_REGS;
+  if (regno == ARG_POINTER_REGNUM)
+    return NOTSP_REG;
   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)
     return LOAD_FPU_REGS;
-  else if (regno & 1)
-    return MUL_REGS;
+  else if (regno == 6)
+    return NOTR0_REG;
+  else if (regno < 6)
+    return NOTSP_REG;
   else
     return GENERAL_REGS;
 }
@@ -1815,11 +1749,11 @@ pdp11_fixed_cc_regs (unsigned int *p1, unsigned int *p2)
   return true;
 }
 
-int
-pdp11_sp_frame_offset (void)
+static int
+pdp11_reg_save_size (void)
 {
   int offset = 0, regno;
-  offset = get_frame_size();
+
   for (regno = 0; regno <= PC_REGNUM; regno++)
     if (pdp11_saved_regno (regno))
       offset += 2;
@@ -1836,32 +1770,18 @@ pdp11_sp_frame_offset (void)
 int
 pdp11_initial_elimination_offset (int from, int to)
 {
+  /* Get the size of the register save area.  */
   int spoff;
   
-  if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
-    return 4;
-  else if (from == FRAME_POINTER_REGNUM
-          && to == HARD_FRAME_POINTER_REGNUM)
-    return 0;
+  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    return get_frame_size ();
+  else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+    return pdp11_reg_save_size () + 2;
+  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    return pdp11_reg_save_size () + 2 + get_frame_size ();
   else
-    {
-      gcc_assert (to == STACK_POINTER_REGNUM);
-
-      /* Get the size of the register save area.  */
-      spoff = pdp11_sp_frame_offset ();
-      if (from == FRAME_POINTER_REGNUM)
-       return spoff;
-
-      gcc_assert (from == ARG_POINTER_REGNUM);
-
-      /* If there is a frame pointer, that is saved too.  */
-      if (frame_pointer_needed)
-       spoff += 2;
-      
-      /* Account for the saved PC in the function call.  */
-      return spoff + 2;
-    }
-}    
+    gcc_assert (0);
+}
 
 /* A copy of output_addr_const modified for pdp11 expression syntax.
    output_addr_const also gets called for %cDIGIT and %nDIGIT, which we don't
@@ -1913,21 +1833,6 @@ output_addr_const_pdp11 (FILE *file, rtx x)
       output_addr_const_pdp11 (file, XEXP (x, 0));
       break;
 
-    case CONST_DOUBLE:
-      if (GET_MODE (x) == VOIDmode)
-       {
-         /* We can use %o if the number is one word and positive.  */
-         if (TARGET_DEC_ASM)
-           fprintf (file, "%o", (int) CONST_DOUBLE_LOW (x) & 0xffff);
-         else
-           fprintf (file, "%#o", (int) CONST_DOUBLE_LOW (x) & 0xffff);
-       }
-      else
-       /* We can't handle floating point constants;
-          PRINT_OPERAND must handle them.  */
-       output_operand_lossage ("floating constant misused");
-      break;
-
     case PLUS:
       /* Some assemblers need integer constants to appear last (e.g. masm).  */
       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
@@ -2033,7 +1938,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
   rtx r, test;
   rtx_code_label *lb;
   
-  if (CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2])))
+  if (CONST_INT_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;
@@ -2043,7 +1948,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
       r = gen_reg_rtx (HImode);
       emit_move_insn (operands[0], operands[1]);
       emit_move_insn (r, operands[2]);
-      if (!CONSTANT_P (operands[2]))
+      if (!CONST_INT_P (operands[2]))
        {
          test = gen_rtx_LE (HImode, r, const0_rtx);
          emit_jump_insn (gen_cbranchhi4 (test, r, const0_rtx, lb));
@@ -2053,7 +1958,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
         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]))
+      if (!CONST_INT_P (operands[2]))
        {
          emit_label (lb);
 
@@ -2072,16 +1977,20 @@ const char *
 pdp11_assemble_shift (rtx *operands, machine_mode m, int code)
 {
   int i, n;
-  rtx exops[4][2];
+  rtx inops[2];
+  rtx exops[2][2];
   rtx lb[1];
   pdp11_action action[2];
-  const bool small = CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2]));
+  const bool small = CONST_INT_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);
-
+    {
+      inops[0] = operands[0];
+      pdp11_expand_operands (inops, exops, 1, 2, action, either);
+    }
+  
   if (!small)
     {
       /* Loop case, generate the top of loop label.  */
@@ -2179,7 +2088,7 @@ pdp11_shift_length (rtx *operands, machine_mode m, int code, bool simple_operand
   /* If shifting by a small constant, the loop is unrolled by the
      shift count.  Otherwise, account for the size of the decrement
      and branch.  */
-  if (CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2])))
+  if (CONST_INT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2])))
     shift_size *= INTVAL (operands[2]);
   else
     shift_size += 4;
@@ -2191,6 +2100,39 @@ pdp11_shift_length (rtx *operands, machine_mode m, int code, bool simple_operand
   return shift_size;
 }
 
+/* Return the length of 2 or 4 word integer compares.  */
+int
+pdp11_cmp_length (rtx *operands, int words)
+{
+  rtx inops[2];
+  rtx exops[4][2];
+  rtx lb[1];
+  int i, len = 0;
+
+  if (!reload_completed)
+    return 2;
+  
+  inops[0] = operands[0];
+  inops[1] = operands[1];
+  
+  pdp11_expand_operands (inops, exops, 2, words, NULL, big);
+
+  for (i = 0; i < words; i++)
+    {
+      len += 4;    /* cmp instruction word and branch that follows.  */
+      if (!REG_P (exops[i][0]) &&
+         !simple_memory_operand (exops[i][0], HImode))
+       len += 2;  /* first operand extra word.  */
+      if (!REG_P (exops[i][1]) &&
+         !simple_memory_operand (exops[i][1], HImode) &&
+         !(CONST_INT_P (exops[i][1]) && INTVAL (exops[i][1]) == 0))
+       len += 2;  /* second operand extra word.  */
+    }
+
+  /* Deduct one word because there is no branch at the end.  */
+  return len - 2;
+}
+
 /* Prepend to CLOBBERS hard registers that are automatically clobbered
    for an asm We do this for CC_REGNUM and FCC_REGNUM (on FPU target)
    to maintain source compatibility with the original cc0-based
index d65d8f5..92c237b 100644 (file)
@@ -32,6 +32,20 @@ along with GCC; see the file COPYING3.  If not see
   do                                           \
     {                                          \
       builtin_define_std ("pdp11");            \
+      if (TARGET_INT16)                                        \
+       builtin_define_with_int_value ("__pdp11_int", 16);      \
+      else                                                     \
+       builtin_define_with_int_value ("__pdp11_int", 32);      \
+      if (TARGET_40)                                           \
+       builtin_define_with_int_value ("__pdp11_model", 40);    \
+      else if (TARGET_45)                                      \
+       builtin_define_with_int_value ("__pdp11_model", 45);    \
+      else                                                     \
+       builtin_define_with_int_value ("__pdp11_model", 10);    \
+      if (TARGET_FPU)                                          \
+       builtin_define ("__pdp11_fpu");                         \
+      if (TARGET_AC0)                                          \
+       builtin_define ("__pdp11_ac0");                         \
     }                                          \
   while (0)
 
@@ -153,7 +167,7 @@ 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, \
- 1, 1 }
+ 1 }
 
 
 
@@ -168,7 +182,7 @@ extern const struct real_format pdp11_d_format;
 #define CALL_USED_REGISTERS  \
 {1, 1, 0, 0, 0, 0, 1, 1, \
  0, 0, 0, 0, 0, 0, 1, 1, \
- 1, 1 }
+ 1 }
 
 
 /* Specify the registers used for certain standard purposes.
@@ -211,6 +225,13 @@ CC_REGS is the condition codes (CPU and FPU)
 
 enum reg_class
   { NO_REGS,
+    NOTR0_REG,
+    NOTR1_REG,
+    NOTR2_REG,
+    NOTR3_REG,
+    NOTR4_REG,
+    NOTR5_REG,
+    NOTSP_REG,
     MUL_REGS,
     GENERAL_REGS,
     LOAD_FPU_REGS,
@@ -229,6 +250,13 @@ enum reg_class
 
 #define REG_CLASS_NAMES  \
   { "NO_REGS",          \
+    "NOTR0_REG",        \
+    "NOTR1_REG",        \
+    "NOTR2_REG",        \
+    "NOTR3_REG",        \
+    "NOTR4_REG",        \
+    "NOTR5_REG",        \
+    "SP_REG",           \
     "MUL_REGS",         \
     "GENERAL_REGS",     \
     "LOAD_FPU_REGS",    \
@@ -243,13 +271,20 @@ enum reg_class
 
 #define REG_CLASS_CONTENTS \
   { {0x00000}, /* NO_REGS */           \
-    {0x000aa}, /* MUL_REGS */          \
-    {0x0c0ff}, /* GENERAL_REGS */      \
+    {0x000fe}, /* NOTR0_REG */         \
+    {0x000fd}, /* NOTR1_REG */         \
+    {0x000fb}, /* NOTR2_REG */         \
+    {0x000f7}, /* NOTR3_REG */         \
+    {0x000ef}, /* NOTR4_REG */         \
+    {0x000df}, /* NOTR5_REG */         \
+    {0x000bf}, /* NOTSP_REG */         \
+    {0x0002a}, /* MUL_REGS */          \
+    {0x040ff}, /* GENERAL_REGS */      \
     {0x00f00}, /* LOAD_FPU_REGS */     \
     {0x03000}, /* NO_LOAD_FPU_REGS */  \
     {0x03f00}, /* FPU_REGS */          \
-    {0x30000}, /* CC_REGS */           \
-    {0x3ffff}} /* ALL_REGS */
+    {0x18000}, /* CC_REGS */           \
+    {0x1ffff}} /* ALL_REGS */
 
 /* The same information, inverted:
    Return the class number of the smallest class containing
@@ -262,13 +297,17 @@ enum reg_class
 #define INDEX_REG_CLASS GENERAL_REGS
 #define BASE_REG_CLASS GENERAL_REGS
 
+/* Return TRUE if the class is a CPU register.  */
+#define CPU_REG_CLASS(CLASS) \
+  (CLASS >= NOTR0_REG && CLASS <= GENERAL_REGS)
+  
 /* Return the maximum number of consecutive registers
    needed to represent mode MODE in a register of class CLASS.  */
 #define CLASS_MAX_NREGS(CLASS, MODE)   \
-((CLASS == GENERAL_REGS || CLASS == MUL_REGS)?                         \
-  ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD):      \
-                                                                     \
-)
+  (CPU_REG_CLASS (CLASS) ?     \
+   ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD):     \
+   1                                                                   \
+  )
 \f
 /* Stack layout; function entry, exit and calling.  */
 
@@ -328,16 +367,13 @@ extern int current_first_parm_offset;
 /* Output assembler code to FILE to increment profiler label # LABELNO
    for profiling a function entry.  */
 
-#define FUNCTION_PROFILER(FILE, LABELNO)  \
-   gcc_unreachable ();
+#define FUNCTION_PROFILER(FILE, LABELNO)
 
 /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
    the stack pointer does not matter.  The value is tested only in
    functions that have frame pointers.
    No definition is equivalent to always zero.  */
 
-extern int may_call_alloca;
-
 #define EXIT_IGNORE_STACK      1
 
 /* Definitions for register eliminations.
@@ -347,17 +383,14 @@ extern int may_call_alloca;
    followed by "to".  Eliminations of the same "from" register are listed
    in order of preference.
 
-   There are two registers that can always be eliminated on the pdp11.
-   The frame pointer and the arg pointer can be replaced by either the
-   hard frame pointer or to the stack pointer, depending upon the
-   circumstances.  The hard frame pointer is not used before reload and
-   so it is not eligible for elimination.  */
+   There are two registers that can be eliminated on the pdp11.  The
+   arg pointer can be replaced by the frame pointer; the frame pointer
+   can often be replaced by the stack pointer.  */
 
 #define ELIMINABLE_REGS                                        \
 {{ 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}}
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM},          \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
 
 #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
   ((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO)))
@@ -514,8 +547,8 @@ extern int may_call_alloca;
 
 #define REGISTER_NAMES \
 {"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc",     \
- "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap", \
- "cc", "fcc" }
+ "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "ap", "cc", \
+ "fcc" }
 
 /* Globalizing directive for a label.  */
 #define GLOBAL_ASM_OP "\t.globl\t"
@@ -568,28 +601,22 @@ extern int may_call_alloca;
 #define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)  \
   pdp11_output_addr_vec_elt (FILE, VALUE)
 
-/* This is how to output an assembler line
-   that says to advance the location counter
-   to a multiple of 2**LOG bytes. 
+/* This is how to output an assembler line that says to advance the
+   location counter to a multiple of 2**LOG bytes.  Only values 0 and
+   1 should appear, but due to PR87795 larger values (which are not
+   supported) can also appear.  So we treat all alignment of LOG >= 1
+   as word (2 byte) alignment.
 */
 
 #define ASM_OUTPUT_ALIGN(FILE,LOG)     \
-  switch (LOG)                         \
-    {                                  \
-      case 0:                          \
-       break;                          \
-      case 1:                          \
-       fprintf (FILE, "\t.even\n");    \
-       break;                          \
-      default:                         \
-       gcc_unreachable ();             \
-    }
+  if (LOG != 0)                                \
+    fprintf (FILE, "\t.even\n")
 
 #define ASM_OUTPUT_SKIP(FILE,SIZE)  \
   if (TARGET_DEC_ASM) \
-    fprintf (FILE, "\t.blkb\t%ho\n", (SIZE) & 0xffff); \
+    fprintf (FILE, "\t.blkb\t%o\n", (SIZE) & 0xffff);  \
   else                                                 \
-    fprintf (FILE, "\t.=.+ %#ho\n", (SIZE) & 0xffff);
+    fprintf (FILE, "\t.=.+ %#o\n", (SIZE) & 0xffff);
 
 /* This says how to output an assembler line
    to define a global common symbol.  */
@@ -597,7 +624,6 @@ extern int may_call_alloca;
 #define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN)  \
   pdp11_asm_output_var (FILE, NAME, SIZE, ALIGN, true)
 
-
 /* This says how to output an assembler line
    to define a local common symbol.  */
 
index 773715d..fc5efc7 100644 (file)
@@ -26,6 +26,7 @@
     UNSPECV_BLOCKAGE
     UNSPECV_SETD
     UNSPECV_SETI
+    UNSPECV_MOVMEM
   ])
 
 (define_constants
    ;; Register numbers
    (R0_REGNUM            0)
    (RETVAL_REGNUM        0)
-   (HARD_FRAME_POINTER_REGNUM  5)
+   (FRAME_POINTER_REGNUM  5)
    (STACK_POINTER_REGNUM  6)
    (PC_REGNUM             7)
    (AC0_REGNUM            8)
    (AC3_REGNUM            11)
    (AC4_REGNUM            12)
    (AC5_REGNUM            13)
-   ;; The next two are not physical registers but are used for addressing
-   ;; arguments.
-   (FRAME_POINTER_REGNUM  14)
-   (ARG_POINTER_REGNUM    15)
+   ;; The next one is not a physical register but is used for
+   ;; addressing arguments.
+   (ARG_POINTER_REGNUM    14)
    ;; Condition code registers
-   (CC_REGNUM             16)
-   (FCC_REGNUM            17)
+   (CC_REGNUM             15)
+   (FCC_REGNUM            16)
    ;; End of hard registers
-   (FIRST_PSEUDO_REGISTER 18)
+   (FIRST_PSEUDO_REGISTER 17)
    
    ;; Branch offset limits, as byte offsets from (pc).  That is NOT
    ;; the same thing as "instruction address" -- it is for backward
   DONE;
 })
 
-(define_expand "return"
-  [(return)]
-  "reload_completed && !frame_pointer_needed && pdp11_sp_frame_offset () == 0"
-  "")
-
-(define_insn "*rts"
+(define_insn "rtspc"
   [(return)]
   ""
   "rts\tpc")
    cmp<PDPint:isfx>\t%0,%1"
   [(set_attr "length" "2,2,4,4,4,6")])
 
+;; Two word compare
+(define_insn "cmpsi"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_operand:SI 0 "general_operand" "rDQi")
+                   (match_operand:SI 1 "general_operand" "rDQi")))]
+  ""
+{
+  rtx inops[2];
+  rtx exops[2][2];
+  rtx lb[1];
+  
+  inops[0] = operands[0];
+  inops[1] = operands[1];
+  pdp11_expand_operands (inops, exops, 2, 2, NULL, big);
+  lb[0] = gen_label_rtx ();
+  
+  if (CONST_INT_P (exops[0][1]) && INTVAL (exops[0][1]) == 0)
+   output_asm_insn ("tst\t%0", exops[0]);
+  else
+   output_asm_insn ("cmp\t%0,%1", exops[0]);
+  output_asm_insn ("bne\t%l0", lb);
+  if (CONST_INT_P (exops[1][1]) && INTVAL (exops[1][1]) == 0)
+   output_asm_insn ("tst\t%0", exops[1]);
+  else
+   output_asm_insn ("cmp\t%0,%1", exops[1]);
+  output_asm_label (lb[0]);
+  fputs (":\n", asm_out_file);
+
+  return "";
+}
+  [(set (attr "length")
+       (symbol_ref "pdp11_cmp_length (operands, 2)"))
+   (set_attr "base_cost" "0")])
+
+;; Four word compare
+(define_insn "cmpdi"
+  [(set (reg:CC CC_REGNUM)
+       (compare:CC (match_operand:DI 0 "general_operand" "rDQi")
+                   (match_operand:DI 1 "general_operand" "rDQi")))]
+  ""
+{
+  rtx inops[4];
+  rtx exops[4][2];
+  rtx lb[1];
+  int i;
+  
+  inops[0] = operands[0];
+  inops[1] = operands[1];
+  pdp11_expand_operands (inops, exops, 2, 4, NULL, big);
+  lb[0] = gen_label_rtx ();
+
+  for (i = 0; i < 3; i++)
+    {
+      if (CONST_INT_P (exops[i][1]) && INTVAL (exops[i][1]) == 0)
+        output_asm_insn ("tst\t%0", exops[i]);
+      else
+        output_asm_insn ("cmp\t%0,%1", exops[i]);
+       output_asm_insn ("bne\t%l0", lb);
+     }
+  if (CONST_INT_P (exops[3][1]) && INTVAL (exops[3][1]) == 0)
+   output_asm_insn ("tst\t%0", exops[3]);
+  else
+   output_asm_insn ("cmp\t%0,%1", exops[3]);
+  output_asm_label (lb[0]);
+   fputs (":\n", asm_out_file);
+
+  return "";
+}
+  [(set (attr "length")
+       (symbol_ref "pdp11_cmp_length (operands, 2)"))
+   (set_attr "base_cost" "0")])
+
 ;; sob instruction
 ;;
 ;; This expander has to check for mode match because the doloop pass
 (define_insn_and_split "cbranch<mode>4"
   [(set (pc)
        (if_then_else (match_operator 0 "ordered_comparison_operator"
-                      [(match_operand:PDPint 1 "general_operand" "g")
-                       (match_operand:PDPint 2 "general_operand" "g")])
+                      [(match_operand:QHSDint 1 "general_operand" "g")
+                       (match_operand:QHSDint 2 "general_operand" "g")])
                      (label_ref (match_operand 3 "" ""))
                      (pc)))]
   ""
   "* return output_move_multiple (operands);"
   [(set_attr "length" "4,6,8,16")])
 
+;; That long string of "Z" constraints enforces the restriction that
+;; a register source and auto increment or decrement destination must
+;; not use the same register, because that case is not consistently
+;; implemented across the PDP11 models.
+;; TODO: the same should be applied to insn like add, but this is not
+;; necessary yet because the incdec optimization pass does not apply
+;; that optimization to 3-operand insns at the moment.
 (define_insn "mov<mode>"
-  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
-       (match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))]
+  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Za,Zb,Zc,Zd,Ze,Zf,Zg,rD,rR,Q,Q")
+       (match_operand:PDPint 1 "general_operand" "RN,Z0,Z1,Z2,Z3,Z4,Z5,Z6,r,Qi,rRN,Qi"))]
   ""
   ""
-  [(set_attr "length" "2,4,4,6")])
+  [(set_attr "length" "2,2,2,2,2,2,2,2,2,4,4,6")])
 
 ;; This splits all the integer moves: DI and SI modes as well as
 ;; the simple machine operations.
   
 ;; 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"))
+  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Za,Zb,Zc,Zd,Ze,Zf,Zg,rD,rR,Q,Q")
+       (match_operand:PDPint 1 "general_operand" "RN,Z0,Z1,Z2,Z3,Z4,Z5,Z6,r,Qi,rRN,Qi"))
    (clobber (reg:CC CC_REGNUM))]
   "reload_completed"
   "*
 
   return \"mov<PDPint:isfx>\t%1,%0\";
 }"
-  [(set_attr "length" "2,4,4,6")])
+  [(set_attr "length" "2,2,2,2,2,2,2,2,2,4,4,6")])
 
 ;; movdf has unusually complicated condition code handling, because
 ;; load (into float register) updates the FCC, while store (from
 
 ;; Expand a block move.  We turn this into a move loop.
 (define_expand "movmemhi"
-  [(match_operand:BLK 0 "general_operand" "=g")
-   (match_operand:BLK 1 "general_operand" "g")
-   (match_operand:HI 2 "immediate_operand" "i")
-   (match_operand:HI 3 "immediate_operand" "i")]
+  [(parallel [(unspec_volatile [(const_int 0)] UNSPECV_MOVMEM)
+             (match_operand:BLK 0 "general_operand" "=g")
+             (match_operand:BLK 1 "general_operand" "g")
+             (match_operand:HI 2 "immediate_operand" "i")
+             (match_operand:HI 3 "immediate_operand" "i")
+             (clobber (mem:BLK (scratch)))
+             (clobber (match_dup 0))
+             (clobber (match_dup 1))
+             (clobber (match_dup 2))])]
   ""
   "
 {
-  if (INTVAL (operands[2]) != 0)
-    expand_block_move (operands);
-  DONE;
+  int count;
+  count = INTVAL (operands[2]);
+  if (count == 0)
+    DONE;
+  if (INTVAL (operands [3]) >= 2 && (count & 1) == 0)
+    count >>= 1;
+  else
+    operands[3] = const1_rtx;
+  operands[2] = copy_to_mode_reg (HImode,
+                                  gen_rtx_CONST_INT (HImode, count));
+
+  /* Load BLKmode MEM addresses into scratch registers.  */
+  operands[0] = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+  operands[1] = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
 }")
 
+;; Expand a block move.  We turn this into a move loop.
+(define_insn_and_split "movmemhi1"
+  [(unspec_volatile [(const_int 0)] UNSPECV_MOVMEM)
+   (match_operand:HI 0 "register_operand" "+r")
+   (match_operand:HI 1 "register_operand" "+r")
+   (match_operand:HI 2 "register_operand" "+r")
+   (match_operand:HI 3 "immediate_operand" "i")
+   (clobber (mem:BLK (scratch)))
+   (clobber (match_dup 0))
+   (clobber (match_dup 1))
+   (clobber (match_dup 2))]
+  ""
+  "#"
+  "reload_completed"
+  [(parallel [(unspec_volatile [(const_int 0)] UNSPECV_MOVMEM)
+             (match_dup 0)
+             (match_dup 1)
+             (match_dup 2)
+             (match_dup 3)
+             (clobber (mem:BLK (scratch)))
+             (clobber (match_dup 0))
+             (clobber (match_dup 1))
+             (clobber (match_dup 2))
+             (clobber (reg:CC CC_REGNUM))])]
+  "")
+
+(define_insn "movmemhi_nocc"
+  [(unspec_volatile [(const_int 0)] UNSPECV_MOVMEM)
+   (match_operand:HI 0 "register_operand" "+r")
+   (match_operand:HI 1 "register_operand" "+r")
+   (match_operand:HI 2 "register_operand" "+r")
+   (match_operand:HI 3 "immediate_operand" "i")
+   (clobber (mem:BLK (scratch)))
+   (clobber (match_dup 0))
+   (clobber (match_dup 1))
+   (clobber (match_dup 2))
+   (clobber (reg:CC CC_REGNUM))]
+  "reload_completed"
+  "*
+{
+  rtx lb[2];
+  
+  lb[0] = operands[2];
+  lb[1] = gen_label_rtx ();
+  
+  output_asm_label (lb[1]);
+  fputs (\":\n\", asm_out_file);
+  if (INTVAL (operands[3]) > 1)
+    output_asm_insn (\"mov\t(%1)+,(%0)+\", operands);
+  else
+    output_asm_insn (\"movb\t(%1)+,(%0)+\", operands);
+  if (TARGET_40_PLUS)
+    output_asm_insn (\"sob\t%0,%l1\", lb);
+  else
+    {
+      output_asm_insn (\"dec\t%0\", lb);
+      output_asm_insn (\"bne\t%l1\", lb);
+    }
+  return \"\";
+}"
+  [(set (attr "length")
+       (if_then_else (match_test "TARGET_40_PLUS")
+                     (const_int 4)
+                     (const_int 6)))])
 \f
 ;;- truncation instructions
 
         emit_move_insn (r, const0_rtx);
         DONE;
       }
-    else if (!rtx_equal_p (operands[0], operands[1]))
+    else if (!REG_P (operands[1]) ||
+             REGNO (operands[0]) != REGNO (operands[1]))
       {
         /* Alternatives 2 and 3 */
         emit_move_insn (operands[0], const0_rtx);
   
   inops[0] = operands[0];
   inops[1] = operands[2];
-  pdp11_expand_operands (inops, exops, 2, NULL, either);
+  pdp11_expand_operands (inops, exops, 2, 4, NULL, big);
   
-  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
+  if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
     output_asm_insn (\"add\t%1,%0\", exops[0]);
-  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
+  if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
   {
     output_asm_insn (\"add\t%1,%0\", exops[1]);
     output_asm_insn (\"adc\t%0\", exops[0]);
   }
-  if (!CONSTANT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
+  if (!CONST_INT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
   {
     output_asm_insn (\"add\t%1,%0\", exops[2]);
     output_asm_insn (\"adc\t%0\", exops[1]);
     output_asm_insn (\"adc\t%0\", exops[0]);
   }
-  if (!CONSTANT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
+  if (!CONST_INT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
   {
     output_asm_insn (\"add\t%1,%0\", exops[3]);
     output_asm_insn (\"adc\t%0\", exops[2]);
   
   inops[0] = operands[0];
   inops[1] = operands[2];
-  pdp11_expand_operands (inops, exops, 2, NULL, either);
+  pdp11_expand_operands (inops, exops, 2, 2, NULL, big);
   
-  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
+  if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
     output_asm_insn (\"add\t%1,%0\", exops[0]);
-  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
+  if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
   {
     output_asm_insn (\"add\t%1,%0\", exops[1]);
     output_asm_insn (\"adc\t%0\", exops[0]);
   
   inops[0] = operands[0];
   inops[1] = operands[2];
-  pdp11_expand_operands (inops, exops, 2, NULL, either);
+  pdp11_expand_operands (inops, exops, 2, 4, NULL, big);
   
-  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
+  if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
     output_asm_insn (\"sub\t%1,%0\", exops[0]);
-  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
+  if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
   {
     output_asm_insn (\"sub\t%1,%0\", exops[1]);
     output_asm_insn (\"sbc\t%0\", exops[0]);
   }
-  if (!CONSTANT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
+  if (!CONST_INT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
   {
     output_asm_insn (\"sub\t%1,%0\", exops[2]);
     output_asm_insn (\"sbc\t%0\", exops[1]);
     output_asm_insn (\"sbc\t%0\", exops[0]);
   }
-  if (!CONSTANT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
+  if (!CONST_INT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
   {
     output_asm_insn (\"sub\t%1,%0\", exops[3]);
     output_asm_insn (\"sbc\t%0\", exops[2]);
   
   inops[0] = operands[0];
   inops[1] = operands[2];
-  pdp11_expand_operands (inops, exops, 2, NULL, either);
+  pdp11_expand_operands (inops, exops, 2, 2, NULL, big);
   
-  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
+  if (!CONST_INT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
     output_asm_insn (\"sub\t%1,%0\", exops[0]);
-  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
+  if (!CONST_INT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
   {
     output_asm_insn (\"sub\t%1,%0\", exops[1]);
     output_asm_insn (\"sbc\t%0\", exops[0]);
    (clobber (reg:CC CC_REGNUM))]
   "reload_completed"
   {
+    rtx inops[2];
     rtx exops[4][2];
-    
-    pdp11_expand_operands (operands, exops, 1, NULL, either);
+
+    inops[0] = operands[0];
+    pdp11_expand_operands (inops, exops, 1, 4, NULL, big);
   
     output_asm_insn (\"com\t%0\", exops[3]);
     output_asm_insn (\"com\t%0\", exops[2]);
    (clobber (reg:CC CC_REGNUM))]
   "reload_completed"
   {
-    rtx exops[2][2];
-    
-    pdp11_expand_operands (operands, exops, 1, NULL, either);
+    rtx inops[2];
+    rtx exops[4][2];
+
+    inops[0] = operands[0];
+    pdp11_expand_operands (inops, exops, 1, 2, NULL, big);
   
     output_asm_insn (\"com\t%0\", exops[1]);
     output_asm_insn (\"com\t%0\", exops[0]);
    (clobber (reg:CC CC_REGNUM))]
   ""
   {
+    rtx inops[2];
     rtx exops[2][2];
     rtx t;
-  
-    pdp11_expand_operands (operands, exops, 2, NULL, either);
+
+    inops[0] = operands[0];
+    inops[1] = operands[1];
+    pdp11_expand_operands (inops, exops, 2, 2, NULL, either);
 
     t = exops[0][0];
     exops[0][0] = exops[1][0];
index 5da3b39..79fca28 100644 (file)
@@ -68,4 +68,4 @@ Use UNIX assembler syntax.
 
 mlra
 Target Report Mask(LRA)
-Use LRA register allocator
+Use LRA register allocator.
index ab01bff..467d228 100644 (file)
 
 MULTILIB_OPTIONS = msoft-float
 
+# Optimize for space
+LIBGCC2_CFLAGS = -Os
+CRTSTUFF_T_CFLAGS = -Os
+
 # Because the pdp11 POINTER_SIZE is only 16, in dwarf2out.c,
 # DWARF_ARANGES_PAD_SIZE is 0, thus a loop in output_aranges that checks
 # (i < (unsigned) DWARF_ARANGES_PAD_SIZE) elicits a warning that the