aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPaul Koning <ni1d@arrl.net>2018-11-08 13:56:58 -0500
committerPaul Koning <pkoning@gcc.gnu.org>2018-11-08 13:56:58 -0500
commit442fcea74d0c7797fc083fa7e5543268c0ff54a6 (patch)
tree8d6dabf3fc85a028b233437a17c5fb3e6c20e9a3 /gcc
parentd4f680c672261642b47ecd72b6201825703bfa40 (diff)
downloadgcc-442fcea74d0c7797fc083fa7e5543268c0ff54a6.zip
gcc-442fcea74d0c7797fc083fa7e5543268c0ff54a6.tar.gz
gcc-442fcea74d0c7797fc083fa7e5543268c0ff54a6.tar.bz2
re PR c/87795 (Excessive alignment permitted for functions and labels)
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog74
-rw-r--r--gcc/config/pdp11/constraints.md29
-rw-r--r--gcc/config/pdp11/pdp11-protos.h6
-rw-r--r--gcc/config/pdp11/pdp11.c484
-rw-r--r--gcc/config/pdp11/pdp11.h106
-rw-r--r--gcc/config/pdp11/pdp11.md268
-rw-r--r--gcc/config/pdp11/pdp11.opt2
-rw-r--r--gcc/config/pdp11/t-pdp114
8 files changed, 605 insertions, 368 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9728c82..e131f62 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/pdp11/constraints.md b/gcc/config/pdp11/constraints.md
index 33882ed..d821af3 100644
--- a/gcc/config/pdp11/constraints.md
+++ b/gcc/config/pdp11/constraints.md
@@ -88,3 +88,32 @@
(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)"))
+
diff --git a/gcc/config/pdp11/pdp11-protos.h b/gcc/config/pdp11/pdp11-protos.h
index 0ed61ea..135d437 100644
--- a/gcc/config/pdp11/pdp11-protos.h
+++ b/gcc/config/pdp11/pdp11-protos.h
@@ -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 */
diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c
index 06129f1..0019efe 100644
--- a/gcc/config/pdp11/pdp11.c
+++ b/gcc/config/pdp11/pdp11.c
@@ -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
/* 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)
/* 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
diff --git a/gcc/config/pdp11/pdp11.h b/gcc/config/pdp11/pdp11.h
index d65d8f5..92c237b 100644
--- a/gcc/config/pdp11/pdp11.h
+++ b/gcc/config/pdp11/pdp11.h
@@ -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): \
- 1 \
-)
+ (CPU_REG_CLASS (CLASS) ? \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD): \
+ 1 \
+ )
/* 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. */
diff --git a/gcc/config/pdp11/pdp11.md b/gcc/config/pdp11/pdp11.md
index 773715d..fc5efc7 100644
--- a/gcc/config/pdp11/pdp11.md
+++ b/gcc/config/pdp11/pdp11.md
@@ -26,6 +26,7 @@
UNSPECV_BLOCKAGE
UNSPECV_SETD
UNSPECV_SETI
+ UNSPECV_MOVMEM
])
(define_constants
@@ -33,22 +34,21 @@
;; 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
@@ -178,12 +178,7 @@
DONE;
})
-(define_expand "return"
- [(return)]
- "reload_completed && !frame_pointer_needed && pdp11_sp_frame_offset () == 0"
- "")
-
-(define_insn "*rts"
+(define_insn "rtspc"
[(return)]
""
"rts\tpc")
@@ -249,6 +244,78 @@
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
@@ -368,8 +435,8 @@
(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)))]
""
@@ -473,12 +540,19 @@
"* 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.
@@ -493,8 +567,8 @@
;; 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"
"*
@@ -504,7 +578,7 @@
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
@@ -591,18 +665,98 @@
;; 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)))])
;;- truncation instructions
@@ -659,7 +813,8 @@
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);
@@ -975,22 +1130,22 @@
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]);
@@ -1037,11 +1192,11 @@
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]);
@@ -1169,22 +1324,22 @@
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]);
@@ -1222,11 +1377,11 @@
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]);
@@ -1702,9 +1857,11 @@
(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]);
@@ -1738,9 +1895,11 @@
(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]);
@@ -2046,10 +2205,13 @@
(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];
diff --git a/gcc/config/pdp11/pdp11.opt b/gcc/config/pdp11/pdp11.opt
index 5da3b39..79fca28 100644
--- a/gcc/config/pdp11/pdp11.opt
+++ b/gcc/config/pdp11/pdp11.opt
@@ -68,4 +68,4 @@ Use UNIX assembler syntax.
mlra
Target Report Mask(LRA)
-Use LRA register allocator
+Use LRA register allocator.
diff --git a/gcc/config/pdp11/t-pdp11 b/gcc/config/pdp11/t-pdp11
index ab01bff..467d228 100644
--- a/gcc/config/pdp11/t-pdp11
+++ b/gcc/config/pdp11/t-pdp11
@@ -18,6 +18,10 @@
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