Commit 442fcea7 by Paul Koning Committed by Paul Koning

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
parent d4f680c6
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> 2018-11-08 Richard Earnshaw <rearnsha@arm.com>
* config/arm/parsecpu.awk (/alias/): New parsing rule. * config/arm/parsecpu.awk (/alias/): New parsing rule.
...@@ -88,3 +88,32 @@ ...@@ -88,3 +88,32 @@
(match_test "memory_address_p (GET_MODE (op), XEXP (op, 0)) (match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
&& no_side_effect_operand (op, GET_MODE (op))"))) && 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)"))
...@@ -26,14 +26,12 @@ extern int legitimate_const_double_p (rtx); ...@@ -26,14 +26,12 @@ extern int legitimate_const_double_p (rtx);
extern void notice_update_cc_on_set (rtx, rtx); extern void notice_update_cc_on_set (rtx, rtx);
extern void output_addr_const_pdp11 (FILE *, rtx); extern void output_addr_const_pdp11 (FILE *, rtx);
extern const char *output_move_multiple (rtx *); extern const char *output_move_multiple (rtx *);
extern void expand_block_move (rtx *);
extern const char *output_jump (rtx *, int, int); extern const char *output_jump (rtx *, int, int);
extern void print_operand_address (FILE *, rtx); extern void print_operand_address (FILE *, rtx);
typedef enum { no_action, dec_before, inc_after } pdp11_action; typedef enum { no_action, dec_before, inc_after } pdp11_action;
typedef enum { little, either, big } pdp11_partorder; 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); pdp11_action *, pdp11_partorder);
extern int pdp11_sp_frame_offset (void);
extern int pdp11_initial_elimination_offset (int, int); extern int pdp11_initial_elimination_offset (int, int);
extern enum reg_class pdp11_regno_reg_class (int); extern enum reg_class pdp11_regno_reg_class (int);
extern bool pdp11_fixed_cc_regs (unsigned int *, unsigned 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), ...@@ -42,6 +40,8 @@ extern bool pdp11_expand_shift (rtx *, rtx (*) (rtx, rtx, rtx),
rtx (*) (rtx, rtx, rtx)); rtx (*) (rtx, rtx, rtx));
extern const char * pdp11_assemble_shift (rtx *, machine_mode, int); extern const char * pdp11_assemble_shift (rtx *, machine_mode, int);
extern int pdp11_shift_length (rtx *, machine_mode, int, bool); 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); extern bool pdp11_small_shift (int);
#endif /* RTX_CODE */ #endif /* RTX_CODE */
......
...@@ -304,6 +304,9 @@ static bool pdp11_scalar_mode_supported_p (scalar_mode); ...@@ -304,6 +304,9 @@ static bool pdp11_scalar_mode_supported_p (scalar_mode);
#undef TARGET_HAVE_SPECULATION_SAFE_VALUE #undef TARGET_HAVE_SPECULATION_SAFE_VALUE
#define TARGET_HAVE_SPECULATION_SAFE_VALUE speculation_safe_value_not_needed #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 /* A helper function to determine if REGNO should be saved in the
current function's stack frame. */ current function's stack frame. */
...@@ -316,6 +319,13 @@ pdp11_saved_regno (unsigned regno) ...@@ -316,6 +319,13 @@ pdp11_saved_regno (unsigned regno)
/* Expand the function prologue. */ /* 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 void
pdp11_expand_prologue (void) pdp11_expand_prologue (void)
{ {
...@@ -331,31 +341,9 @@ pdp11_expand_prologue (void) ...@@ -331,31 +341,9 @@ pdp11_expand_prologue (void)
emit_insn (gen_seti ()); 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. */ /* Save CPU registers. */
for (regno = R0_REGNUM; regno <= PC_REGNUM; regno++) for (regno = R0_REGNUM; regno <= PC_REGNUM; regno++)
if (pdp11_saved_regno (regno) if (pdp11_saved_regno (regno))
&& (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed))
{ {
x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx); x = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx);
x = gen_frame_mem (Pmode, x); x = gen_frame_mem (Pmode, x);
...@@ -383,25 +371,21 @@ pdp11_expand_prologue (void) ...@@ -383,25 +371,21 @@ pdp11_expand_prologue (void)
x = gen_frame_mem (DFmode, x); x = gen_frame_mem (DFmode, x);
emit_move_insn (x, via_ac); 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 - if (frame_pointer_needed)
but how can we do this? the pdp11/45 manual says bit may only emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
be set (p.24), but not cleared!
switching to kernel is probably more expensive, so we'll leave it /* Make local variable space. */
like this and not use the second set of registers... 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 void
pdp11_expand_epilogue (void) pdp11_expand_epilogue (void)
...@@ -410,6 +394,20 @@ pdp11_expand_epilogue (void) ...@@ -410,6 +394,20 @@ pdp11_expand_epilogue (void)
unsigned regno; unsigned regno;
rtx x, reg, via_ac = NULL; 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)) if (pdp11_saved_regno (AC4_REGNUM) || pdp11_saved_regno (AC5_REGNUM))
{ {
/* Find a temporary with which to restore AC4/5. */ /* Find a temporary with which to restore AC4/5. */
...@@ -421,109 +419,33 @@ pdp11_expand_epilogue (void) ...@@ -421,109 +419,33 @@ pdp11_expand_epilogue (void)
} }
} }
/* If possible, restore registers via pops. */ /* 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);
}
}
for (regno = PC_REGNUM; regno >= R0_REGNUM + 2; regno--) for (regno = AC5_REGNUM; regno >= AC0_REGNUM; regno--)
if (pdp11_saved_regno (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_rtx_POST_INC (Pmode, stack_pointer_rtx); x = gen_frame_mem (DFmode, x);
x = gen_frame_mem (Pmode, x); reg = gen_rtx_REG (DFmode, regno);
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 = PC_REGNUM; regno >= R0_REGNUM + 2; regno--) if (LOAD_FPU_REG_P (regno))
if (pdp11_saved_regno (regno) emit_move_insn (reg, x);
&& (regno != HARD_FRAME_POINTER_REGNUM || !frame_pointer_needed)) else
{ {
x = plus_constant (Pmode, hard_frame_pointer_rtx, ofs); emit_move_insn (via_ac, x);
x = gen_frame_mem (Pmode, x); emit_move_insn (reg, via_ac);
emit_move_insn (gen_rtx_REG (Pmode, regno), x);
ofs += 2;
} }
} }
/* 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) 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); x = gen_rtx_POST_INC (Pmode, stack_pointer_rtx);
emit_move_insn (hard_frame_pointer_rtx, x); 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 /* Return the best assembler insn template
...@@ -539,21 +461,23 @@ singlemove_string (rtx *operands) ...@@ -539,21 +461,23 @@ singlemove_string (rtx *operands)
/* Expand multi-word operands (SImode or DImode) into the 2 or 4 /* Expand multi-word operands (SImode or DImode) into the 2 or 4
corresponding HImode operands. The number of operands is given corresponding HImode operands. The number of operands is given as
as the third argument, and the required order of the parts as the third argument, the word count for the mode as the fourth
the fourth argument. */ 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 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) pdp11_action *action, pdp11_partorder order)
{ {
int words, op, w, i, sh; int op, w, i, sh;
pdp11_partorder useorder; pdp11_partorder useorder;
bool sameoff = false; bool sameoff = false;
enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype; enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype;
long sval[2]; long sval[2];
words = GET_MODE_BITSIZE (GET_MODE (operands[0])) / 16;
/* If either piece order is accepted and one is pre-decrement /* If either piece order is accepted and one is pre-decrement
while the other is post-increment, set order to be high order while the other is post-increment, set order to be high order
word first. That will force the pre-decrement to be turned 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, ...@@ -566,19 +490,16 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
useorder = either; useorder = either;
if (opcount == 2) if (opcount == 2)
{ {
if (!REG_P (operands[0]) && !REG_P (operands[1]) && if (GET_CODE (operands[0]) == MEM &&
!(CONSTANT_P (operands[1]) || GET_CODE (operands[1]) == MEM &&
GET_CODE (operands[1]) == CONST_DOUBLE) &&
((GET_CODE (XEXP (operands[0], 0)) == POST_INC && ((GET_CODE (XEXP (operands[0], 0)) == POST_INC &&
GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) || GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) ||
(GET_CODE (XEXP (operands[0], 0)) == PRE_DEC && (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC &&
GET_CODE (XEXP (operands[1], 0)) == POST_INC))) GET_CODE (XEXP (operands[1], 0)) == POST_INC)))
useorder = big; useorder = big;
else if ((!REG_P (operands[0]) && else if ((GET_CODE (operands[0]) == MEM &&
GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) || GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) ||
(!REG_P (operands[1]) && (GET_CODE (operands[1]) == MEM &&
!(CONSTANT_P (operands[1]) ||
GET_CODE (operands[1]) == CONST_DOUBLE) &&
GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)) GET_CODE (XEXP (operands[1], 0)) == PRE_DEC))
useorder = little; useorder = little;
else if (REG_P (operands[0]) && REG_P (operands[1]) && else if (REG_P (operands[0]) && REG_P (operands[1]) &&
...@@ -615,7 +536,7 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount, ...@@ -615,7 +536,7 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
/* First classify the operand. */ /* First classify the operand. */
if (REG_P (operands[op])) if (REG_P (operands[op]))
optype = REGOP; optype = REGOP;
else if (CONSTANT_P (operands[op]) else if (CONST_INT_P (operands[op])
|| GET_CODE (operands[op]) == CONST_DOUBLE) || GET_CODE (operands[op]) == CONST_DOUBLE)
optype = CNSTOP; optype = CNSTOP;
else if (GET_CODE (XEXP (operands[op], 0)) == POST_INC) else if (GET_CODE (XEXP (operands[op], 0)) == POST_INC)
...@@ -663,8 +584,11 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount, ...@@ -663,8 +584,11 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
} }
if (GET_CODE (operands[op]) == CONST_DOUBLE) 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++) for (i = 0; i < words; i++)
{ {
...@@ -707,24 +631,31 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount, ...@@ -707,24 +631,31 @@ pdp11_expand_operands (rtx *operands, rtx exops[][2], int opcount,
const char * const char *
output_move_multiple (rtx *operands) output_move_multiple (rtx *operands)
{ {
rtx inops[2];
rtx exops[4][2]; rtx exops[4][2];
rtx adjops[2];
pdp11_action action[2]; pdp11_action action[2];
int i, words; int i, words;
words = GET_MODE_BITSIZE (GET_MODE (operands[0])) / 16; 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. */ /* Check for explicit decrement before. */
if (action[0] == dec_before) if (action[0] == dec_before)
{ {
operands[0] = XEXP (operands[0], 0); adjops[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("sub\t%#4,%0", operands); output_asm_insn ("sub\t%1,%0", adjops);
} }
if (action[1] == dec_before) if (action[1] == dec_before)
{ {
operands[1] = XEXP (operands[1], 0); adjops[0] = XEXP (XEXP (operands[1], 0), 0);
output_asm_insn ("sub\t%#4,%1", operands); output_asm_insn ("sub\t%1,%0", adjops);
} }
/* Do the words. */ /* Do the words. */
...@@ -734,13 +665,13 @@ output_move_multiple (rtx *operands) ...@@ -734,13 +665,13 @@ output_move_multiple (rtx *operands)
/* Check for increment after. */ /* Check for increment after. */
if (action[0] == inc_after) if (action[0] == inc_after)
{ {
operands[0] = XEXP (operands[0], 0); adjops[0] = XEXP (XEXP (operands[0], 0), 0);
output_asm_insn ("add\t%#4,%0", operands); output_asm_insn ("add\t%1,%0", adjops);
} }
if (action[1] == inc_after) if (action[1] == inc_after)
{ {
operands[1] = XEXP (operands[1], 0); adjops[0] = XEXP (XEXP (operands[1], 0), 0);
output_asm_insn ("add\t%#4,%1", operands); output_asm_insn ("add\t%1,%0", adjops);
} }
return ""; return "";
...@@ -752,9 +683,9 @@ pdp11_gen_int_label (char *label, const char *prefix, int num) ...@@ -752,9 +683,9 @@ pdp11_gen_int_label (char *label, const char *prefix, int num)
{ {
if (TARGET_DEC_ASM) if (TARGET_DEC_ASM)
/* +1 because GCC numbers labels starting at zero. */ /* +1 because GCC numbers labels starting at zero. */
sprintf (label, "*%lu$", num + 1); sprintf (label, "*%u$", num + 1);
else else
sprintf (label, "*%s_%lu", prefix, num); sprintf (label, "*%s_%u", prefix, num);
} }
/* Output an ascii string. */ /* Output an ascii string. */
...@@ -780,7 +711,7 @@ output_ascii (FILE *file, const char *p, int size) ...@@ -780,7 +711,7 @@ output_ascii (FILE *file, const char *p, int size)
{ {
if (delim) if (delim)
putc ('"', file); putc ('"', file);
fprintf (file, "<%o%>", c); fprintf (file, "<%o>", c);
delim = false; delim = false;
} }
else else
...@@ -815,15 +746,30 @@ pdp11_asm_output_var (FILE *file, const char *name, int size, ...@@ -815,15 +746,30 @@ pdp11_asm_output_var (FILE *file, const char *name, int size,
{ {
if (align > 8) if (align > 8)
fprintf (file, "\t.even\n"); fprintf (file, "\t.even\n");
if (global) if (TARGET_DEC_ASM)
{ {
fprintf (file, ".globl ");
assemble_name (file, name); 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"); else
assemble_name (file, name); {
fputs (":", file); if (global)
ASM_OUTPUT_SKIP (file, size); {
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: /* Special format operators handled here:
...@@ -855,7 +801,7 @@ pdp11_asm_print_operand (FILE *file, rtx x, int code) ...@@ -855,7 +801,7 @@ pdp11_asm_print_operand (FILE *file, rtx x, int code)
fprintf (file, "%s", reg_names[REGNO (x)]); fprintf (file, "%s", reg_names[REGNO (x)]);
else if (GET_CODE (x) == MEM) else if (GET_CODE (x) == MEM)
output_address (GET_MODE (x), XEXP (x, 0)); 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); REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (x), sval);
if (TARGET_DEC_ASM) if (TARGET_DEC_ASM)
...@@ -1013,8 +959,7 @@ static int ...@@ -1013,8 +959,7 @@ static int
pdp11_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED, pdp11_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
reg_class_t c1, reg_class_t c2) reg_class_t c1, reg_class_t c2)
{ {
if (((c1 == MUL_REGS || c1 == GENERAL_REGS) && if (CPU_REG_CLASS (c1) && CPU_REG_CLASS (c2))
(c2 == MUL_REGS || c2 == GENERAL_REGS)))
return 2; return 2;
else if ((c1 >= LOAD_FPU_REGS && c1 <= FPU_REGS && c2 == LOAD_FPU_REGS) || else if ((c1 >= LOAD_FPU_REGS && c1 <= FPU_REGS && c2 == LOAD_FPU_REGS) ||
(c2 >= LOAD_FPU_REGS && c2 <= FPU_REGS && c1 == 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) ...@@ -1512,50 +1457,32 @@ no_side_effect_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
return FALSE; return FALSE;
} }
/* Return TRUE if op is a push or pop using the register "regno". */
/* bool
* expand a block move: pushpop_regeq (rtx op, int regno)
*
* operands[0] ... to
* operands[1] ... from
* operands[2] ... length
* operands[3] ... alignment
*/
void
expand_block_move(rtx *operands)
{ {
rtx lb, test; rtx addr;
rtx fromop, toop, counter;
int count; /* False if not memory reference. */
if (GET_CODE (op) != MEM)
/* Transform BLKmode MEM reference into a (reg)+ operand. */ return FALSE;
toop = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
toop = gen_rtx_POST_INC (Pmode, toop); /* Get the address of the memory reference. */
fromop = copy_to_mode_reg (Pmode, XEXP (operands[1], 0)); addr = XEXP (op, 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));
/* Label at top of loop */ if (GET_CODE (addr) == MEM)
lb = gen_label_rtx (); addr = XEXP (addr, 0);
emit_label (lb);
emit_move_insn (toop, fromop); switch (GET_CODE (addr))
emit_insn (gen_subhi3 (counter, counter, const1_rtx)); {
test = gen_rtx_NE (HImode, counter, const0_rtx); case PRE_DEC:
emit_jump_insn (gen_cbranchhi4 (test, counter, const0_rtx, lb)); 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 /* This function checks whether a real value can be encoded as
...@@ -1565,7 +1492,12 @@ int ...@@ -1565,7 +1492,12 @@ int
legitimate_const_double_p (rtx address) legitimate_const_double_p (rtx address)
{ {
long sval[2]; 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); REAL_VALUE_TO_TARGET_DOUBLE (*CONST_DOUBLE_REAL_VALUE (address), sval);
if ((sval[0] & 0xffff) == 0 && sval[1] == 0) if ((sval[0] & 0xffff) == 0 && sval[1] == 0)
return 1; return 1;
return 0; return 0;
...@@ -1723,7 +1655,7 @@ pdp11_legitimate_address_p (machine_mode mode, ...@@ -1723,7 +1655,7 @@ pdp11_legitimate_address_p (machine_mode mode,
&& GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS && GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS
&& GET_CODE (XEXP (xfoob, 0)) == REG && GET_CODE (XEXP (xfoob, 0)) == REG
&& REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM && REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM
&& CONSTANT_P (XEXP (xfoob, 1)) && CONST_INT_P (XEXP (xfoob, 1))
&& INTVAL (XEXP (xfoob,1)) == -2; && INTVAL (XEXP (xfoob,1)) == -2;
case POST_MODIFY: case POST_MODIFY:
...@@ -1733,7 +1665,7 @@ pdp11_legitimate_address_p (machine_mode mode, ...@@ -1733,7 +1665,7 @@ pdp11_legitimate_address_p (machine_mode mode,
&& GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS && GET_CODE ((xfoob = XEXP (operand, 1))) == PLUS
&& GET_CODE (XEXP (xfoob, 0)) == REG && GET_CODE (XEXP (xfoob, 0)) == REG
&& REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM && REGNO (XEXP (xfoob, 0)) == STACK_POINTER_REGNUM
&& CONSTANT_P (XEXP (xfoob, 1)) && CONST_INT_P (XEXP (xfoob, 1))
&& INTVAL (XEXP (xfoob,1)) == 2; && INTVAL (XEXP (xfoob,1)) == 2;
case MEM: case MEM:
...@@ -1792,16 +1724,18 @@ pdp11_legitimate_address_p (machine_mode mode, ...@@ -1792,16 +1724,18 @@ pdp11_legitimate_address_p (machine_mode mode,
enum reg_class enum reg_class
pdp11_regno_reg_class (int regno) pdp11_regno_reg_class (int regno)
{ {
if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM) if (regno == ARG_POINTER_REGNUM)
return GENERAL_REGS; return NOTSP_REG;
else if (regno == CC_REGNUM || regno == FCC_REGNUM) else if (regno == CC_REGNUM || regno == FCC_REGNUM)
return CC_REGS; return CC_REGS;
else if (regno > AC3_REGNUM) else if (regno > AC3_REGNUM)
return NO_LOAD_FPU_REGS; return NO_LOAD_FPU_REGS;
else if (regno >= AC0_REGNUM) else if (regno >= AC0_REGNUM)
return LOAD_FPU_REGS; return LOAD_FPU_REGS;
else if (regno & 1) else if (regno == 6)
return MUL_REGS; return NOTR0_REG;
else if (regno < 6)
return NOTSP_REG;
else else
return GENERAL_REGS; return GENERAL_REGS;
} }
...@@ -1815,11 +1749,11 @@ pdp11_fixed_cc_regs (unsigned int *p1, unsigned int *p2) ...@@ -1815,11 +1749,11 @@ pdp11_fixed_cc_regs (unsigned int *p1, unsigned int *p2)
return true; return true;
} }
int static int
pdp11_sp_frame_offset (void) pdp11_reg_save_size (void)
{ {
int offset = 0, regno; int offset = 0, regno;
offset = get_frame_size();
for (regno = 0; regno <= PC_REGNUM; regno++) for (regno = 0; regno <= PC_REGNUM; regno++)
if (pdp11_saved_regno (regno)) if (pdp11_saved_regno (regno))
offset += 2; offset += 2;
...@@ -1836,32 +1770,18 @@ pdp11_sp_frame_offset (void) ...@@ -1836,32 +1770,18 @@ pdp11_sp_frame_offset (void)
int int
pdp11_initial_elimination_offset (int from, int to) pdp11_initial_elimination_offset (int from, int to)
{ {
/* Get the size of the register save area. */
int spoff; int spoff;
if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM) if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return 4; return get_frame_size ();
else if (from == FRAME_POINTER_REGNUM else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
&& to == HARD_FRAME_POINTER_REGNUM) return pdp11_reg_save_size () + 2;
return 0; else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
return pdp11_reg_save_size () + 2 + get_frame_size ();
else else
{ gcc_assert (0);
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;
}
}
/* A copy of output_addr_const modified for pdp11 expression syntax. /* 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 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) ...@@ -1913,21 +1833,6 @@ output_addr_const_pdp11 (FILE *file, rtx x)
output_addr_const_pdp11 (file, XEXP (x, 0)); output_addr_const_pdp11 (file, XEXP (x, 0));
break; 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: case PLUS:
/* Some assemblers need integer constants to appear last (e.g. masm). */ /* Some assemblers need integer constants to appear last (e.g. masm). */
if (GET_CODE (XEXP (x, 0)) == CONST_INT) if (GET_CODE (XEXP (x, 0)) == CONST_INT)
...@@ -2033,7 +1938,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx), ...@@ -2033,7 +1938,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
rtx r, test; rtx r, test;
rtx_code_label *lb; 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])); emit_insn ((*shift_sc) (operands[0], operands[1], operands[2]));
else if (TARGET_40_PLUS) else if (TARGET_40_PLUS)
return false; return false;
...@@ -2043,7 +1948,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx), ...@@ -2043,7 +1948,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
r = gen_reg_rtx (HImode); r = gen_reg_rtx (HImode);
emit_move_insn (operands[0], operands[1]); emit_move_insn (operands[0], operands[1]);
emit_move_insn (r, operands[2]); 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); test = gen_rtx_LE (HImode, r, const0_rtx);
emit_jump_insn (gen_cbranchhi4 (test, r, const0_rtx, lb)); 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), ...@@ -2053,7 +1958,7 @@ pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
optimizer and it doesn't appreciate flow changes happening optimizer and it doesn't appreciate flow changes happening
while it's doing things. */ while it's doing things. */
emit_insn ((*shift_base) (operands[0], operands[1], r)); emit_insn ((*shift_base) (operands[0], operands[1], r));
if (!CONSTANT_P (operands[2])) if (!CONST_INT_P (operands[2]))
{ {
emit_label (lb); emit_label (lb);
...@@ -2072,16 +1977,20 @@ const char * ...@@ -2072,16 +1977,20 @@ const char *
pdp11_assemble_shift (rtx *operands, machine_mode m, int code) pdp11_assemble_shift (rtx *operands, machine_mode m, int code)
{ {
int i, n; int i, n;
rtx exops[4][2]; rtx inops[2];
rtx exops[2][2];
rtx lb[1]; rtx lb[1];
pdp11_action action[2]; 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); gcc_assert (small || !TARGET_40_PLUS);
if (m == E_SImode) 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) if (!small)
{ {
/* Loop case, generate the top of loop label. */ /* 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 ...@@ -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 /* If shifting by a small constant, the loop is unrolled by the
shift count. Otherwise, account for the size of the decrement shift count. Otherwise, account for the size of the decrement
and branch. */ 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]); shift_size *= INTVAL (operands[2]);
else else
shift_size += 4; shift_size += 4;
...@@ -2191,6 +2100,39 @@ pdp11_shift_length (rtx *operands, machine_mode m, int code, bool simple_operand ...@@ -2191,6 +2100,39 @@ pdp11_shift_length (rtx *operands, machine_mode m, int code, bool simple_operand
return shift_size; 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 /* Prepend to CLOBBERS hard registers that are automatically clobbered
for an asm We do this for CC_REGNUM and FCC_REGNUM (on FPU target) for an asm We do this for CC_REGNUM and FCC_REGNUM (on FPU target)
to maintain source compatibility with the original cc0-based to maintain source compatibility with the original cc0-based
......
...@@ -32,6 +32,20 @@ along with GCC; see the file COPYING3. If not see ...@@ -32,6 +32,20 @@ along with GCC; see the file COPYING3. If not see
do \ do \
{ \ { \
builtin_define_std ("pdp11"); \ 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) while (0)
...@@ -153,7 +167,7 @@ extern const struct real_format pdp11_d_format; ...@@ -153,7 +167,7 @@ extern const struct real_format pdp11_d_format;
#define FIXED_REGISTERS \ #define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 1, 1, \ {0, 0, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1, \ 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 } 1 }
...@@ -168,7 +182,7 @@ extern const struct real_format pdp11_d_format; ...@@ -168,7 +182,7 @@ extern const struct real_format pdp11_d_format;
#define CALL_USED_REGISTERS \ #define CALL_USED_REGISTERS \
{1, 1, 0, 0, 0, 0, 1, 1, \ {1, 1, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1, \ 0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 } 1 }
/* Specify the registers used for certain standard purposes. /* Specify the registers used for certain standard purposes.
...@@ -211,6 +225,13 @@ CC_REGS is the condition codes (CPU and FPU) ...@@ -211,6 +225,13 @@ CC_REGS is the condition codes (CPU and FPU)
enum reg_class enum reg_class
{ NO_REGS, { NO_REGS,
NOTR0_REG,
NOTR1_REG,
NOTR2_REG,
NOTR3_REG,
NOTR4_REG,
NOTR5_REG,
NOTSP_REG,
MUL_REGS, MUL_REGS,
GENERAL_REGS, GENERAL_REGS,
LOAD_FPU_REGS, LOAD_FPU_REGS,
...@@ -229,6 +250,13 @@ enum reg_class ...@@ -229,6 +250,13 @@ enum reg_class
#define REG_CLASS_NAMES \ #define REG_CLASS_NAMES \
{ "NO_REGS", \ { "NO_REGS", \
"NOTR0_REG", \
"NOTR1_REG", \
"NOTR2_REG", \
"NOTR3_REG", \
"NOTR4_REG", \
"NOTR5_REG", \
"SP_REG", \
"MUL_REGS", \ "MUL_REGS", \
"GENERAL_REGS", \ "GENERAL_REGS", \
"LOAD_FPU_REGS", \ "LOAD_FPU_REGS", \
...@@ -243,13 +271,20 @@ enum reg_class ...@@ -243,13 +271,20 @@ enum reg_class
#define REG_CLASS_CONTENTS \ #define REG_CLASS_CONTENTS \
{ {0x00000}, /* NO_REGS */ \ { {0x00000}, /* NO_REGS */ \
{0x000aa}, /* MUL_REGS */ \ {0x000fe}, /* NOTR0_REG */ \
{0x0c0ff}, /* GENERAL_REGS */ \ {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 */ \ {0x00f00}, /* LOAD_FPU_REGS */ \
{0x03000}, /* NO_LOAD_FPU_REGS */ \ {0x03000}, /* NO_LOAD_FPU_REGS */ \
{0x03f00}, /* FPU_REGS */ \ {0x03f00}, /* FPU_REGS */ \
{0x30000}, /* CC_REGS */ \ {0x18000}, /* CC_REGS */ \
{0x3ffff}} /* ALL_REGS */ {0x1ffff}} /* ALL_REGS */
/* The same information, inverted: /* The same information, inverted:
Return the class number of the smallest class containing Return the class number of the smallest class containing
...@@ -262,13 +297,17 @@ enum reg_class ...@@ -262,13 +297,17 @@ enum reg_class
#define INDEX_REG_CLASS GENERAL_REGS #define INDEX_REG_CLASS GENERAL_REGS
#define BASE_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 /* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS. */ needed to represent mode MODE in a register of class CLASS. */
#define CLASS_MAX_NREGS(CLASS, MODE) \ #define CLASS_MAX_NREGS(CLASS, MODE) \
((CLASS == GENERAL_REGS || CLASS == MUL_REGS)? \ (CPU_REG_CLASS (CLASS) ? \
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD): \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD): \
1 \ 1 \
) )
/* Stack layout; function entry, exit and calling. */ /* Stack layout; function entry, exit and calling. */
...@@ -328,16 +367,13 @@ extern int current_first_parm_offset; ...@@ -328,16 +367,13 @@ extern int current_first_parm_offset;
/* Output assembler code to FILE to increment profiler label # LABELNO /* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. */ for profiling a function entry. */
#define FUNCTION_PROFILER(FILE, LABELNO) \ #define FUNCTION_PROFILER(FILE, LABELNO)
gcc_unreachable ();
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in the stack pointer does not matter. The value is tested only in
functions that have frame pointers. functions that have frame pointers.
No definition is equivalent to always zero. */ No definition is equivalent to always zero. */
extern int may_call_alloca;
#define EXIT_IGNORE_STACK 1 #define EXIT_IGNORE_STACK 1
/* Definitions for register eliminations. /* Definitions for register eliminations.
...@@ -347,17 +383,14 @@ extern int may_call_alloca; ...@@ -347,17 +383,14 @@ extern int may_call_alloca;
followed by "to". Eliminations of the same "from" register are listed followed by "to". Eliminations of the same "from" register are listed
in order of preference. in order of preference.
There are two registers that can always be eliminated on the pdp11. There are two registers that can be eliminated on the pdp11. The
The frame pointer and the arg pointer can be replaced by either the arg pointer can be replaced by the frame pointer; the frame pointer
hard frame pointer or to the stack pointer, depending upon the can often be replaced by the stack pointer. */
circumstances. The hard frame pointer is not used before reload and
so it is not eligible for elimination. */
#define ELIMINABLE_REGS \ #define ELIMINABLE_REGS \
{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ {{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO))) ((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO)))
...@@ -514,8 +547,8 @@ extern int may_call_alloca; ...@@ -514,8 +547,8 @@ extern int may_call_alloca;
#define REGISTER_NAMES \ #define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \ {"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \
"ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap", \ "ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "ap", "cc", \
"cc", "fcc" } "fcc" }
/* Globalizing directive for a label. */ /* Globalizing directive for a label. */
#define GLOBAL_ASM_OP "\t.globl\t" #define GLOBAL_ASM_OP "\t.globl\t"
...@@ -568,28 +601,22 @@ extern int may_call_alloca; ...@@ -568,28 +601,22 @@ extern int may_call_alloca;
#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ #define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
pdp11_output_addr_vec_elt (FILE, VALUE) pdp11_output_addr_vec_elt (FILE, VALUE)
/* This is how to output an assembler line /* This is how to output an assembler line that says to advance the
that says to advance the location counter location counter to a multiple of 2**LOG bytes. Only values 0 and
to a multiple of 2**LOG bytes. 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) \ #define ASM_OUTPUT_ALIGN(FILE,LOG) \
switch (LOG) \ if (LOG != 0) \
{ \ fprintf (FILE, "\t.even\n")
case 0: \
break; \
case 1: \
fprintf (FILE, "\t.even\n"); \
break; \
default: \
gcc_unreachable (); \
}
#define ASM_OUTPUT_SKIP(FILE,SIZE) \ #define ASM_OUTPUT_SKIP(FILE,SIZE) \
if (TARGET_DEC_ASM) \ if (TARGET_DEC_ASM) \
fprintf (FILE, "\t.blkb\t%ho\n", (SIZE) & 0xffff); \ fprintf (FILE, "\t.blkb\t%o\n", (SIZE) & 0xffff); \
else \ else \
fprintf (FILE, "\t.=.+ %#ho\n", (SIZE) & 0xffff); fprintf (FILE, "\t.=.+ %#o\n", (SIZE) & 0xffff);
/* This says how to output an assembler line /* This says how to output an assembler line
to define a global common symbol. */ to define a global common symbol. */
...@@ -597,7 +624,6 @@ extern int may_call_alloca; ...@@ -597,7 +624,6 @@ extern int may_call_alloca;
#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ #define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
pdp11_asm_output_var (FILE, NAME, SIZE, ALIGN, true) pdp11_asm_output_var (FILE, NAME, SIZE, ALIGN, true)
/* This says how to output an assembler line /* This says how to output an assembler line
to define a local common symbol. */ to define a local common symbol. */
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
UNSPECV_BLOCKAGE UNSPECV_BLOCKAGE
UNSPECV_SETD UNSPECV_SETD
UNSPECV_SETI UNSPECV_SETI
UNSPECV_MOVMEM
]) ])
(define_constants (define_constants
...@@ -33,22 +34,21 @@ ...@@ -33,22 +34,21 @@
;; Register numbers ;; Register numbers
(R0_REGNUM 0) (R0_REGNUM 0)
(RETVAL_REGNUM 0) (RETVAL_REGNUM 0)
(HARD_FRAME_POINTER_REGNUM 5) (FRAME_POINTER_REGNUM 5)
(STACK_POINTER_REGNUM 6) (STACK_POINTER_REGNUM 6)
(PC_REGNUM 7) (PC_REGNUM 7)
(AC0_REGNUM 8) (AC0_REGNUM 8)
(AC3_REGNUM 11) (AC3_REGNUM 11)
(AC4_REGNUM 12) (AC4_REGNUM 12)
(AC5_REGNUM 13) (AC5_REGNUM 13)
;; The next two are not physical registers but are used for addressing ;; The next one is not a physical register but is used for
;; arguments. ;; addressing arguments.
(FRAME_POINTER_REGNUM 14) (ARG_POINTER_REGNUM 14)
(ARG_POINTER_REGNUM 15)
;; Condition code registers ;; Condition code registers
(CC_REGNUM 16) (CC_REGNUM 15)
(FCC_REGNUM 17) (FCC_REGNUM 16)
;; End of hard registers ;; End of hard registers
(FIRST_PSEUDO_REGISTER 18) (FIRST_PSEUDO_REGISTER 17)
;; Branch offset limits, as byte offsets from (pc). That is NOT ;; Branch offset limits, as byte offsets from (pc). That is NOT
;; the same thing as "instruction address" -- it is for backward ;; the same thing as "instruction address" -- it is for backward
...@@ -178,12 +178,7 @@ ...@@ -178,12 +178,7 @@
DONE; DONE;
}) })
(define_expand "return" (define_insn "rtspc"
[(return)]
"reload_completed && !frame_pointer_needed && pdp11_sp_frame_offset () == 0"
"")
(define_insn "*rts"
[(return)] [(return)]
"" ""
"rts\tpc") "rts\tpc")
...@@ -249,6 +244,78 @@ ...@@ -249,6 +244,78 @@
cmp<PDPint:isfx>\t%0,%1" cmp<PDPint:isfx>\t%0,%1"
[(set_attr "length" "2,2,4,4,4,6")]) [(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 ;; sob instruction
;; ;;
;; This expander has to check for mode match because the doloop pass ;; This expander has to check for mode match because the doloop pass
...@@ -368,8 +435,8 @@ ...@@ -368,8 +435,8 @@
(define_insn_and_split "cbranch<mode>4" (define_insn_and_split "cbranch<mode>4"
[(set (pc) [(set (pc)
(if_then_else (match_operator 0 "ordered_comparison_operator" (if_then_else (match_operator 0 "ordered_comparison_operator"
[(match_operand:PDPint 1 "general_operand" "g") [(match_operand:QHSDint 1 "general_operand" "g")
(match_operand:PDPint 2 "general_operand" "g")]) (match_operand:QHSDint 2 "general_operand" "g")])
(label_ref (match_operand 3 "" "")) (label_ref (match_operand 3 "" ""))
(pc)))] (pc)))]
"" ""
...@@ -473,12 +540,19 @@ ...@@ -473,12 +540,19 @@
"* return output_move_multiple (operands);" "* return output_move_multiple (operands);"
[(set_attr "length" "4,6,8,16")]) [(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>" (define_insn "mov<mode>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") [(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" "rRN,Qi,rRN,Qi"))] (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 ;; This splits all the integer moves: DI and SI modes as well as
;; the simple machine operations. ;; the simple machine operations.
...@@ -493,8 +567,8 @@ ...@@ -493,8 +567,8 @@
;; MOV clears V ;; MOV clears V
(define_insn "*mov<mode>_<cc_cc>" (define_insn "*mov<mode>_<cc_cc>"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") [(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" "rRN,Qi,rRN,Qi")) (match_operand:PDPint 1 "general_operand" "RN,Z0,Z1,Z2,Z3,Z4,Z5,Z6,r,Qi,rRN,Qi"))
(clobber (reg:CC CC_REGNUM))] (clobber (reg:CC CC_REGNUM))]
"reload_completed" "reload_completed"
"* "*
...@@ -504,7 +578,7 @@ ...@@ -504,7 +578,7 @@
return \"mov<PDPint:isfx>\t%1,%0\"; 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 ;; movdf has unusually complicated condition code handling, because
;; load (into float register) updates the FCC, while store (from ;; load (into float register) updates the FCC, while store (from
...@@ -591,18 +665,98 @@ ...@@ -591,18 +665,98 @@
;; Expand a block move. We turn this into a move loop. ;; Expand a block move. We turn this into a move loop.
(define_expand "movmemhi" (define_expand "movmemhi"
[(match_operand:BLK 0 "general_operand" "=g") [(parallel [(unspec_volatile [(const_int 0)] UNSPECV_MOVMEM)
(match_operand:BLK 1 "general_operand" "g") (match_operand:BLK 0 "general_operand" "=g")
(match_operand:HI 2 "immediate_operand" "i") (match_operand:BLK 1 "general_operand" "g")
(match_operand:HI 3 "immediate_operand" "i")] (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) int count;
expand_block_move (operands); count = INTVAL (operands[2]);
DONE; 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 ;;- truncation instructions
...@@ -659,7 +813,8 @@ ...@@ -659,7 +813,8 @@
emit_move_insn (r, const0_rtx); emit_move_insn (r, const0_rtx);
DONE; 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 */ /* Alternatives 2 and 3 */
emit_move_insn (operands[0], const0_rtx); emit_move_insn (operands[0], const0_rtx);
...@@ -975,22 +1130,22 @@ ...@@ -975,22 +1130,22 @@
inops[0] = operands[0]; inops[0] = operands[0];
inops[1] = operands[2]; 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]); 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 (\"add\t%1,%0\", exops[1]);
output_asm_insn (\"adc\t%0\", exops[0]); 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 (\"add\t%1,%0\", exops[2]);
output_asm_insn (\"adc\t%0\", exops[1]); output_asm_insn (\"adc\t%0\", exops[1]);
output_asm_insn (\"adc\t%0\", exops[0]); 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 (\"add\t%1,%0\", exops[3]);
output_asm_insn (\"adc\t%0\", exops[2]); output_asm_insn (\"adc\t%0\", exops[2]);
...@@ -1037,11 +1192,11 @@ ...@@ -1037,11 +1192,11 @@
inops[0] = operands[0]; inops[0] = operands[0];
inops[1] = operands[2]; 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]); 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 (\"add\t%1,%0\", exops[1]);
output_asm_insn (\"adc\t%0\", exops[0]); output_asm_insn (\"adc\t%0\", exops[0]);
...@@ -1169,22 +1324,22 @@ ...@@ -1169,22 +1324,22 @@
inops[0] = operands[0]; inops[0] = operands[0];
inops[1] = operands[2]; 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]); 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 (\"sub\t%1,%0\", exops[1]);
output_asm_insn (\"sbc\t%0\", exops[0]); 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 (\"sub\t%1,%0\", exops[2]);
output_asm_insn (\"sbc\t%0\", exops[1]); output_asm_insn (\"sbc\t%0\", exops[1]);
output_asm_insn (\"sbc\t%0\", exops[0]); 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 (\"sub\t%1,%0\", exops[3]);
output_asm_insn (\"sbc\t%0\", exops[2]); output_asm_insn (\"sbc\t%0\", exops[2]);
...@@ -1222,11 +1377,11 @@ ...@@ -1222,11 +1377,11 @@
inops[0] = operands[0]; inops[0] = operands[0];
inops[1] = operands[2]; 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]); 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 (\"sub\t%1,%0\", exops[1]);
output_asm_insn (\"sbc\t%0\", exops[0]); output_asm_insn (\"sbc\t%0\", exops[0]);
...@@ -1702,9 +1857,11 @@ ...@@ -1702,9 +1857,11 @@
(clobber (reg:CC CC_REGNUM))] (clobber (reg:CC CC_REGNUM))]
"reload_completed" "reload_completed"
{ {
rtx inops[2];
rtx exops[4][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[3]);
output_asm_insn (\"com\t%0\", exops[2]); output_asm_insn (\"com\t%0\", exops[2]);
...@@ -1738,9 +1895,11 @@ ...@@ -1738,9 +1895,11 @@
(clobber (reg:CC CC_REGNUM))] (clobber (reg:CC CC_REGNUM))]
"reload_completed" "reload_completed"
{ {
rtx exops[2][2]; 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, 2, NULL, big);
output_asm_insn (\"com\t%0\", exops[1]); output_asm_insn (\"com\t%0\", exops[1]);
output_asm_insn (\"com\t%0\", exops[0]); output_asm_insn (\"com\t%0\", exops[0]);
...@@ -2046,10 +2205,13 @@ ...@@ -2046,10 +2205,13 @@
(clobber (reg:CC CC_REGNUM))] (clobber (reg:CC CC_REGNUM))]
"" ""
{ {
rtx inops[2];
rtx exops[2][2]; rtx exops[2][2];
rtx t; 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]; t = exops[0][0];
exops[0][0] = exops[1][0]; exops[0][0] = exops[1][0];
......
...@@ -68,4 +68,4 @@ Use UNIX assembler syntax. ...@@ -68,4 +68,4 @@ Use UNIX assembler syntax.
mlra mlra
Target Report Mask(LRA) Target Report Mask(LRA)
Use LRA register allocator Use LRA register allocator.
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
MULTILIB_OPTIONS = msoft-float 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, # 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 # 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 # (i < (unsigned) DWARF_ARANGES_PAD_SIZE) elicits a warning that the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment