Convert pdp11 back end to CCmode.

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

From-SVN: r262198
This commit is contained in:
Paul Koning 2018-06-27 17:58:24 -04:00 committed by Paul Koning
parent 356d53635f
commit b4324a144b
12 changed files with 1524 additions and 884 deletions

View file

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

View file

@ -39,9 +39,27 @@ pdp11_handle_option (struct gcc_options *opts,
switch (code)
{
case OPT_m10:
opts->x_target_flags &= ~(MASK_40 | MASK_45);
opts->x_target_flags &= ~(MASK_40 | MASK_45 | MASK_FPU | MASK_AC0 | MASK_SPLIT);
return true;
case OPT_m40:
opts->x_target_flags &= ~(MASK_45 | MASK_FPU | MASK_AC0 | MASK_SPLIT);
return true;
case OPT_mfpu:
opts->x_target_flags &= ~MASK_40;
opts->x_target_flags |= MASK_45;
return true;
case OPT_msoft_float:
opts->x_target_flags &= ~MASK_AC0;
return true;
case OPT_msplit:
opts->x_target_flags &= ~MASK_40;
opts->x_target_flags |= MASK_45;
return true;
default:
return true;
}

View file

@ -18,11 +18,14 @@
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
(define_register_constraint "a" "LOAD_FPU_REGS"
"FPU register that can be directly loaded from memory")
(define_register_constraint "f" "FPU_REGS"
"Any FPU register")
(define_register_constraint "a" "LOAD_FPU_REGS"
"FPU register that can be directly loaded from memory")
(define_register_constraint "h" "NO_LOAD_FPU_REGS"
"FPU register that cannot be directly loaded from memory")
(define_register_constraint "d" "MUL_REGS"
"General register that can be used for 16-bit multiply (odd numbered)")
@ -60,7 +63,7 @@
(define_constraint "O"
"Integer constant for which several individual shifts are better than one big one"
(and (match_code "const_int")
(match_test "abs (ival) > 1 && abs (ival) <= 4")))
(match_test "pdp11_small_shift (ival)")))
(define_constraint "G"
"Defines a real zero constant."
@ -79,3 +82,9 @@
(match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
&& simple_memory_operand (op, GET_MODE (op))")))
(define_constraint "D"
"Memory reference that is encoded within the opcode, and not push or pop"
(and (match_code "mem")
(match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
&& no_side_effect_operand (op, GET_MODE (op))")))

View file

@ -19,8 +19,26 @@ along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* Add any extra modes needed to represent the condition code.
CCFPmode is used for FPU, but should we use a separate reg? */
CC_MODE (CCFP);
The default CCmode is the CPU condition codes, as set by compare;
all conditional branches are valid with this.
CCNZmode is the CPU condition code as a side effect of arithmetic
or logic operations where N and Z reflect sign and zero status of
the result, but the V bit is not meaningful. Unsigned conditional
branches don't apply then (no such thing when comparing with zero)
and signed branches that use V need to clear V first if they are to
be used. CCNZ mode appears in side effects (implicit compare with
zero) if V is not forced to 0 by the instruction. In such cases, V
often reflects signed overflow of the operation, which means a
signed branch will get the sign backwards. This applies both to
some float and integer operations.
These modes are used both in the FPU and the CPU, since they have
the same meaning, and also because the FPU condition codes are
copied to the CPU before being used in conditional branches. */
CC_MODE (CCNZ);
RESET_FLOAT_FORMAT (SF, pdp11_f_format);
RESET_FLOAT_FORMAT (DF, pdp11_d_format);

View file

@ -21,21 +21,27 @@ along with GCC; see the file COPYING3. If not see
/* declarations */
#ifdef RTX_CODE
extern int simple_memory_operand (rtx, machine_mode);
extern int no_side_effect_operand (rtx, machine_mode);
extern int legitimate_const_double_p (rtx);
extern void notice_update_cc_on_set (rtx, rtx);
extern void output_addr_const_pdp11 (FILE *, rtx);
extern const char *output_move_multiple (rtx *);
extern const char *output_block_move (rtx *);
extern const char *output_jump (enum rtx_code, int, int);
extern const char *output_jump (rtx *, int, int);
extern void print_operand_address (FILE *, rtx);
typedef enum { no_action, dec_before, inc_after } pdp11_action;
typedef enum { little, either, big } pdp11_partorder;
extern bool pdp11_expand_operands (rtx *, rtx [][2], int,
extern bool pdp11_expand_operands (rtx *, rtx [][2], int,
pdp11_action *, pdp11_partorder);
extern int pdp11_sp_frame_offset (void);
extern int pdp11_initial_elimination_offset (int, int);
extern enum reg_class pdp11_regno_reg_class (int);
extern bool pdp11_fixed_cc_regs (unsigned int *, unsigned int *);
extern machine_mode pdp11_cc_mode (enum rtx_code, rtx, rtx);
extern bool pdp11_expand_shift (rtx *, rtx (*) (rtx, rtx, rtx),
rtx (*) (rtx, rtx, rtx));
extern const char * pdp11_assemble_shift (rtx *, machine_mode, int);
extern bool pdp11_small_shift (int);
#endif /* RTX_CODE */
@ -43,5 +49,4 @@ extern void output_ascii (FILE *, const char *, int);
extern void pdp11_asm_output_var (FILE *, const char *, int, int, bool);
extern void pdp11_expand_prologue (void);
extern void pdp11_expand_epilogue (void);
extern int pdp11_branch_cost (void);
extern poly_int64 pdp11_push_rounding (poly_int64);

View file

@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "expr.h"
#include "builtins.h"
#include "dbxout.h"
#include "expmed.h"
/* This file should be included last. */
#include "target-def.h"
@ -146,9 +147,6 @@ decode_pdp11_d (const struct real_format *fmt ATTRIBUTE_UNUSED,
(*vax_d_format.decode) (fmt, r, tbuf);
}
/* This is where the condition code register lives. */
/* rtx cc0_reg_rtx; - no longer needed? */
static const char *singlemove_string (rtx *);
static bool pdp11_assemble_integer (rtx, unsigned int, int);
static bool pdp11_rtx_costs (rtx, machine_mode, int, int, int *, bool);
@ -384,7 +382,7 @@ pdp11_expand_epilogue (void)
emit_move_insn (reg, x);
else
{
emit_move_insn (via_ac, x);
emit_move_insn (via_ac, x);
emit_move_insn (reg, via_ac);
}
}
@ -872,48 +870,40 @@ pdp11_assemble_integer (rtx x, unsigned int size, int aligned_p)
case 1:
fprintf (asm_out_file, "\t.byte\t");
output_addr_const_pdp11 (asm_out_file, GEN_INT (INTVAL (x) & 0xff));
;
fprintf (asm_out_file, " /* char */\n");
fputs ("\n", asm_out_file);
return true;
case 2:
fprintf (asm_out_file, TARGET_UNIX_ASM ? "\t" : "\t.word\t");
output_addr_const_pdp11 (asm_out_file, x);
fprintf (asm_out_file, " /* short */\n");
fputs ("\n", asm_out_file);
return true;
}
return default_assemble_integer (x, size, aligned_p);
}
/* register move costs, indexed by regs */
static const int move_costs[N_REG_CLASSES][N_REG_CLASSES] =
{
/* NO MUL GEN LFPU NLFPU FPU ALL */
/* NO */ { 0, 0, 0, 0, 0, 0, 0},
/* MUL */ { 0, 2, 2, 22, 22, 22, 22},
/* GEN */ { 0, 2, 2, 22, 22, 22, 22},
/* LFPU */ { 0, 22, 22, 2, 2, 2, 22},
/* NLFPU */ { 0, 22, 22, 2, 10, 10, 22},
/* FPU */ { 0, 22, 22, 2, 10, 10, 22},
/* ALL */ { 0, 22, 22, 22, 22, 22, 22}
} ;
/* -- note that some moves are tremendously expensive,
because they require lots of tricks! do we have to
charge the costs incurred by secondary reload class
-- as we do here with 10 -- or not ? */
/* Register to register moves are cheap if both are general registers.
The same is true for FPU, but there we return cost of 3 rather than
2 to make reload look at the constraints. The raeson is that
load/store double require extra care since load touches condition
codes and store doesn't, which is (partly anyway) described by
constraints. */
static int
pdp11_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
reg_class_t c1, reg_class_t c2)
{
return move_costs[(int)c1][(int)c2];
if (((c1 == MUL_REGS || c1 == GENERAL_REGS) &&
(c2 == MUL_REGS || c2 == GENERAL_REGS)))
return 2;
else if ((c1 >= LOAD_FPU_REGS && c1 <= FPU_REGS && c2 == LOAD_FPU_REGS) ||
(c2 >= LOAD_FPU_REGS && c2 <= FPU_REGS && c1 == LOAD_FPU_REGS))
return 3;
else
return 22;
}
static bool
pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
int opno ATTRIBUTE_UNUSED, int *total,
@ -988,7 +978,6 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
return false;
case ASHIFT:
case LSHIFTRT:
case ASHIFTRT:
if (optimize_size)
*total = COSTS_N_INSNS (1);
@ -1020,114 +1009,134 @@ pdp11_rtx_costs (rtx x, machine_mode mode, int outer_code ATTRIBUTE_UNUSED,
}
return false;
case LSHIFTRT:
if (optimize_size)
*total = COSTS_N_INSNS (2);
else if (mode == QImode)
{
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
*total = COSTS_N_INSNS (12); /* worst case */
else
*total = COSTS_N_INSNS (1 + INTVAL (XEXP (x, 1)));
}
else if (mode == HImode)
{
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
if (abs (INTVAL (XEXP (x, 1))) == 1)
*total = COSTS_N_INSNS (2);
else
*total = COSTS_N_INSNS (3.5 + 0.5 * INTVAL (XEXP (x, 1)));
}
else
*total = COSTS_N_INSNS (12); /* worst case */
}
else if (mode == SImode)
{
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
*total = COSTS_N_INSNS (3.5 + 0.5 * INTVAL (XEXP (x, 1)));
else /* worst case */
*total = COSTS_N_INSNS (20);
}
return false;
default:
return false;
}
}
const char *
output_jump (enum rtx_code code, int inv, int length)
output_jump (rtx *operands, int ccnz, int length)
{
static int x = 0;
static char buf[1000];
const char *pos, *neg;
rtx tmpop[1];
static char buf[100];
const char *pos, *neg;
enum rtx_code code = GET_CODE (operands[0]);
if (cc_prev_status.flags & CC_NO_OVERFLOW)
{
switch (code)
{
case GTU: code = GT; break;
case LTU: code = LT; break;
case GEU: code = GE; break;
case LEU: code = LE; break;
default: ;
}
}
switch (code)
{
case EQ: pos = "beq", neg = "bne"; break;
case NE: pos = "bne", neg = "beq"; break;
case GT: pos = "bgt", neg = "ble"; break;
case GTU: pos = "bhi", neg = "blos"; break;
case LT: pos = "blt", neg = "bge"; break;
case LTU: pos = "blo", neg = "bhis"; break;
case GE: pos = "bge", neg = "blt"; break;
case GEU: pos = "bhis", neg = "blo"; break;
case LE: pos = "ble", neg = "bgt"; break;
case LEU: pos = "blos", neg = "bhi"; break;
default: gcc_unreachable ();
}
#if 0
/* currently we don't need this, because the tstdf and cmpdf
copy the condition code immediately, and other float operations are not
yet recognized as changing the FCC - if so, then the length-cost of all
jump insns increases by one, because we have to potentially copy the
FCC! */
if (cc_status.flags & CC_IN_FPU)
output_asm_insn("cfcc", NULL);
#endif
switch (length)
if (ccnz)
{
case 2:
sprintf(buf, "%s %%l1", inv ? neg : pos);
return buf;
case 6:
sprintf(buf, "%s JMP_%d\n\tjmp %%l1\nJMP_%d:", inv ? pos : neg, x, x);
x++;
return buf;
default:
gcc_unreachable ();
/* These are the branches valid for CCNZmode, i.e., a comparison
with zero where the V bit is not set to zero. These cases
occur when CC or FCC are set as a side effect of some data
manipulation, such as the ADD instruction. */
switch (code)
{
case EQ: pos = "beq", neg = "bne"; break;
case NE: pos = "bne", neg = "beq"; break;
case LT: pos = "bmi", neg = "bpl"; break;
case GE: pos = "bpl", neg = "bmi"; break;
default: gcc_unreachable ();
}
}
else
{
switch (code)
{
case EQ: pos = "beq", neg = "bne"; break;
case NE: pos = "bne", neg = "beq"; break;
case GT: pos = "bgt", neg = "ble"; break;
case GTU: pos = "bhi", neg = "blos"; break;
case LT: pos = "blt", neg = "bge"; break;
case LTU: pos = "blo", neg = "bhis"; break;
case GE: pos = "bge", neg = "blt"; break;
case GEU: pos = "bhis", neg = "blo"; break;
case LE: pos = "ble", neg = "bgt"; break;
case LEU: pos = "blos", neg = "bhi"; break;
default: gcc_unreachable ();
}
}
switch (length)
{
case 2:
sprintf (buf, "%s %%l1", pos);
return buf;
case 6:
tmpop[0] = gen_label_rtx ();
sprintf (buf, "%s %%l0", neg);
output_asm_insn (buf, tmpop);
output_asm_insn ("jmp %l1", operands);
output_asm_label (tmpop[0]);
fputs (":\n", asm_out_file);
return "";
default:
gcc_unreachable ();
}
}
void
notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
/* Select the CC mode to be used for the side effect compare with
zero, given the compare operation code in op and the compare
operands in x in and y. */
machine_mode
pdp11_cc_mode (enum rtx_code op, rtx x, rtx y)
{
if (GET_CODE (SET_DEST (exp)) == CC0)
{
cc_status.flags = 0;
cc_status.value1 = SET_DEST (exp);
cc_status.value2 = SET_SRC (exp);
}
else if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
if (FLOAT_MODE_P (GET_MODE (x)))
{
switch (GET_CODE (x))
{
case ABS:
case NEG:
case REG:
case MEM:
return CCmode;
default:
return CCNZmode;
}
}
else if (SET_DEST(exp) == pc_rtx)
{
/* jump */
}
else if (GET_MODE (SET_DEST(exp)) == HImode
|| GET_MODE (SET_DEST(exp)) == QImode)
{
cc_status.flags = GET_CODE (SET_SRC(exp)) == MINUS ? 0 : CC_NO_OVERFLOW;
cc_status.value1 = SET_SRC (exp);
cc_status.value2 = SET_DEST (exp);
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
&& cc_status.value2
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
cc_status.value2 = 0;
if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM
&& cc_status.value2
&& GET_CODE (cc_status.value2) == MEM)
cc_status.value2 = 0;
}
else
{
CC_STATUS_INIT;
else
{
switch (GET_CODE (x))
{
case XOR:
case AND:
case IOR:
case MULT:
case NOT:
case REG:
case MEM:
return CCmode;
default:
return CCNZmode;
}
}
}
@ -1135,62 +1144,115 @@ notice_update_cc_on_set(rtx exp, rtx insn ATTRIBUTE_UNUSED)
int
simple_memory_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
{
rtx addr;
rtx addr;
/* Eliminate non-memory operations */
if (GET_CODE (op) != MEM)
return FALSE;
/* Eliminate non-memory operations */
if (GET_CODE (op) != MEM)
return FALSE;
#if 0
/* dword operations really put out 2 instructions, so eliminate them. */
if (GET_MODE_SIZE (GET_MODE (op)) > (HAVE_64BIT_P () ? 8 : 4))
return FALSE;
#endif
/* Decode the address now. */
/* Decode the address now. */
indirection:
indirection:
addr = XEXP (op, 0);
addr = XEXP (op, 0);
switch (GET_CODE (addr))
switch (GET_CODE (addr))
{
case REG:
/* (R0) - no extra cost */
return 1;
case REG:
/* (R0) - no extra cost */
return 1;
case PRE_DEC:
case POST_INC:
/* -(R0), (R0)+ - cheap! */
case PRE_DEC:
case POST_INC:
case PRE_MODIFY:
case POST_MODIFY:
/* -(R0), (R0)+ - cheap! */
return 1;
case MEM:
/* cheap - is encoded in addressing mode info!
-- except for @(R0), which has to be @0(R0) !!! */
if (GET_CODE (XEXP (addr, 0)) == REG)
return 0;
case MEM:
/* cheap - is encoded in addressing mode info!
-- except for @(R0), which has to be @0(R0) !!! */
if (GET_CODE (XEXP (addr, 0)) == REG)
return 0;
op=addr;
goto indirection;
op=addr;
goto indirection;
case CONST_INT:
case LABEL_REF:
case CONST:
case SYMBOL_REF:
/* @#address - extra cost */
return 0;
case CONST_INT:
case LABEL_REF:
case CONST:
case SYMBOL_REF:
/* @#address - extra cost */
return 0;
case PLUS:
/* X(R0) - extra cost */
return 0;
case PLUS:
/* X(R0) - extra cost */
return 0;
default:
break;
default:
break;
}
return FALSE;
}
/* Similar to simple_memory_operand but doesn't match push/pop. */
int
no_side_effect_operand(rtx op, machine_mode mode ATTRIBUTE_UNUSED)
{
rtx addr;
/* Eliminate non-memory operations */
if (GET_CODE (op) != MEM)
return FALSE;
/* Decode the address now. */
indirection:
addr = XEXP (op, 0);
switch (GET_CODE (addr))
{
case REG:
/* (R0) - no extra cost */
return 1;
case PRE_DEC:
case POST_INC:
case PRE_MODIFY:
case POST_MODIFY:
return 0;
case MEM:
/* cheap - is encoded in addressing mode info!
-- except for @(R0), which has to be @0(R0) !!! */
if (GET_CODE (XEXP (addr, 0)) == REG)
return 0;
op=addr;
goto indirection;
case CONST_INT:
case LABEL_REF:
case CONST:
case SYMBOL_REF:
/* @#address - extra cost */
return 0;
case PLUS:
/* X(R0) - extra cost */
return 0;
default:
break;
}
return FALSE;
}
@ -1446,7 +1508,7 @@ pdp11_preferred_output_reload_class (rtx x, reg_class_t rclass)
FPU registers AC4 and AC5 (class NO_LOAD_FPU_REGS) require an
intermediate register (AC0-AC3: LOAD_FPU_REGS). Everything else
can be loade/stored directly. */
can be loaded/stored directly. */
static reg_class_t
pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
rtx x,
@ -1463,9 +1525,8 @@ pdp11_secondary_reload (bool in_p ATTRIBUTE_UNUSED,
/* Implement TARGET_SECONDARY_MEMORY_NEEDED.
The answer is yes if we're going between general register and FPU
registers. The mode doesn't matter in making this check.
*/
The answer is yes if we're going between general register and FPU
registers. The mode doesn't matter in making this check. */
static bool
pdp11_secondary_memory_needed (machine_mode, reg_class_t c1, reg_class_t c2)
{
@ -1594,6 +1655,8 @@ pdp11_regno_reg_class (int regno)
{
if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM)
return GENERAL_REGS;
else if (regno == CC_REGNUM || regno == FCC_REGNUM)
return CC_REGS;
else if (regno > AC3_REGNUM)
return NO_LOAD_FPU_REGS;
else if (regno >= AC0_REGNUM)
@ -1604,6 +1667,14 @@ pdp11_regno_reg_class (int regno)
return GENERAL_REGS;
}
/* Return the regnums of the CC registers. */
bool
pdp11_fixed_cc_regs (unsigned int *p1, unsigned int *p2)
{
*p1 = CC_REGNUM;
*p2 = FCC_REGNUM;
return true;
}
int
pdp11_sp_frame_offset (void)
@ -1804,6 +1875,151 @@ pdp11_function_value_regno_p (const unsigned int regno)
return (regno == RETVAL_REGNUM) || (TARGET_AC0 && (regno == AC0_REGNUM));
}
/* Used for O constraint, matches if shift count is "small". */
bool
pdp11_small_shift (int n)
{
return (unsigned) n < 4;
}
/* Expand a shift insn. Returns true if the expansion was done,
false if it needs to be handled by the caller. */
bool
pdp11_expand_shift (rtx *operands, rtx (*shift_sc) (rtx, rtx, rtx),
rtx (*shift_base) (rtx, rtx, rtx))
{
rtx dest, n, r, test;
rtx_code_label *lb, *lb2;
if (CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2])))
emit_insn ((*shift_sc) (operands[0], operands[1], operands[2]));
else if (TARGET_40_PLUS)
return false;
else
{
lb = gen_label_rtx ();
r = gen_reg_rtx (HImode);
emit_move_insn (operands[0], operands[1]);
emit_move_insn (r, operands[2]);
if (!CONSTANT_P (operands[2]))
{
test = gen_rtx_LE (HImode, r, const0_rtx);
emit_jump_insn (gen_cbranchhi4 (test, r, const0_rtx, lb));
}
/* It would be nice to expand the loop here, but that's not
possible because shifts may be generated by the loop unroll
optimizer and it doesn't appreciate flow changes happening
while it's doing things. */
emit_insn ((*shift_base) (operands[0], operands[1], r));
if (!CONSTANT_P (operands[2]))
{
emit_label (lb);
/* Allow REG_NOTES to be set on last insn (labels don't have enough
fields, and can't be used for REG_NOTES anyway). */
emit_use (stack_pointer_rtx);
}
}
return true;
}
/* Emit the instructions needed to produce a shift by a small constant
amount (unrolled), or a shift made from a loop for the base machine
case. */
const char *
pdp11_assemble_shift (rtx *operands, machine_mode m, int code)
{
int i, n;
rtx exops[4][2];
rtx lb[1];
pdp11_action action[2];
const bool small = CONSTANT_P (operands[2]) && pdp11_small_shift (INTVAL (operands[2]));
gcc_assert (small || !TARGET_40_PLUS);
if (m == E_SImode)
pdp11_expand_operands (operands, exops, 1, action, either);
if (!small)
{
/* Loop case, generate the top of loop label. */
lb[0] = gen_label_rtx ();
output_asm_label (lb[0]);
fputs (":\n", asm_out_file);
n = 1;
}
else
n = INTVAL (operands[2]);
if (code == LSHIFTRT)
{
output_asm_insn ("clc", NULL);
switch (m)
{
case E_QImode:
output_asm_insn ("rorb %0", operands);
break;
case E_HImode:
output_asm_insn ("ror %0", operands);
break;
case E_SImode:
output_asm_insn ("ror %0", exops[0]);
output_asm_insn ("ror %0", exops[1]);
break;
default:
gcc_unreachable ();
}
n--;
}
for (i = 0; i < n; i++)
{
switch (code)
{
case LSHIFTRT:
case ASHIFTRT:
switch (m)
{
case E_QImode:
output_asm_insn ("asrb %0", operands);
break;
case E_HImode:
output_asm_insn ("asr %0", operands);
break;
case E_SImode:
output_asm_insn ("asr %0", exops[0]);
output_asm_insn ("ror %0", exops[1]);
break;
default:
gcc_unreachable ();
}
break;
case ASHIFT:
switch (m)
{
case E_QImode:
output_asm_insn ("aslb %0", operands);
break;
case E_HImode:
output_asm_insn ("asl %0", operands);
break;
case E_SImode:
output_asm_insn ("asl %0", exops[1]);
output_asm_insn ("rol %0", exops[0]);
break;
default:
gcc_unreachable ();
}
break;
}
}
if (!small)
{
/* Loop case, emit the count-down and branch if not done. */
output_asm_insn ("dec %2", operands);
output_asm_insn ("bne %l0", lb);
}
return "";
}
/* Worker function for TARGET_TRAMPOLINE_INIT.
trampoline - how should i do it in separate i+d ?
@ -1814,7 +2030,6 @@ pdp11_function_value_regno_p (const unsigned int regno)
MOV #STATIC, $4 01270Y 0x0000 <- STATIC; Y = STATIC_CHAIN_REGNUM
JMP @#FUNCTION 000137 0x0000 <- FUNCTION
*/
static void
pdp11_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
{
@ -1934,12 +2149,6 @@ pdp11_scalar_mode_supported_p (scalar_mode mode)
return default_scalar_mode_supported_p (mode);
}
int
pdp11_branch_cost ()
{
return (TARGET_BRANCH_CHEAP ? 0 : 1);
}
/* Implement TARGET_HARD_REGNO_NREGS. */
static unsigned int
@ -1972,9 +2181,9 @@ pdp11_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
/* Implement TARGET_MODES_TIEABLE_P. */
static bool
pdp11_modes_tieable_p (machine_mode, machine_mode)
pdp11_modes_tieable_p (machine_mode mode1, machine_mode mode2)
{
return false;
return mode1 == HImode && mode2 == QImode;
}
/* Implement PUSH_ROUNDING. On the pdp11, the stack is on an even

View file

@ -65,11 +65,11 @@ along with GCC; see the file COPYING3. If not see
#define LONG_DOUBLE_TYPE_SIZE 64
/* machine types from ansi */
#define SIZE_TYPE "unsigned int" /* definition of size_t */
#define WCHAR_TYPE "int" /* or long int???? */
#define SIZE_TYPE "short unsigned int" /* definition of size_t */
#define WCHAR_TYPE "short int" /* or long int???? */
#define WCHAR_TYPE_SIZE 16
#define PTRDIFF_TYPE "int"
#define PTRDIFF_TYPE "short int"
/* target machine storage layout */
@ -99,8 +99,7 @@ along with GCC; see the file COPYING3. If not see
extern const struct real_format pdp11_f_format;
extern const struct real_format pdp11_d_format;
/* Maximum sized of reasonable data type
DImode or Dfmode ...*/
/* Maximum sized of reasonable data type -- DImode ...*/
#define MAX_FIXED_MODE_SIZE 64
/* Allocation boundary (in *bits*) for storing pointers in memory. */
@ -124,6 +123,22 @@ extern const struct real_format pdp11_d_format;
/* Define this if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 1
/* Adjust the length of shifts by small constant amounts. The base
value (in "length" on input) is the length of a shift by one, not
including the CLC in logical shifts. */
#define ADJUST_INSN_LENGTH(insn, length) \
if ((GET_CODE (insn) == ASHIFT || \
GET_CODE (insn) == ASHIFTRT || \
GET_CODE (insn) == LSHIFTRT) && \
GET_CODE (XEXP (insn, 2)) == CONST_INT && \
pdp11_small_shift (XINT (insn, 2))) \
{ \
if (GET_CODE (insn) == LSHIFTRT) \
length = (length * XINT (insn, 2)) + 2; \
else \
length *= XINT (insn, 2); \
}
/* Standard register usage. */
@ -147,7 +162,8 @@ extern const struct real_format pdp11_d_format;
#define FIXED_REGISTERS \
{0, 0, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1 }
0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 }
@ -161,7 +177,8 @@ extern const struct real_format pdp11_d_format;
/* don't know about fp */
#define CALL_USED_REGISTERS \
{1, 1, 0, 0, 0, 0, 1, 1, \
0, 0, 0, 0, 0, 0, 1, 1 }
0, 0, 0, 0, 0, 0, 1, 1, \
1, 1 }
/* Specify the registers used for certain standard purposes.
@ -203,27 +220,47 @@ NO_LOAD_FPU_REGS is ac4 and ac5, currently - difficult to load them
FPU_REGS is all fpu regs
*/
enum reg_class { NO_REGS, MUL_REGS, GENERAL_REGS, LOAD_FPU_REGS, NO_LOAD_FPU_REGS, FPU_REGS, ALL_REGS, LIM_REG_CLASSES };
enum reg_class
{ NO_REGS,
MUL_REGS,
GENERAL_REGS,
LOAD_FPU_REGS,
NO_LOAD_FPU_REGS,
FPU_REGS,
CC_REGS,
ALL_REGS,
LIM_REG_CLASSES };
#define N_REG_CLASSES (int) LIM_REG_CLASSES
#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
/* have to allow this till cmpsi/tstsi are fixed in a better way !! */
#define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
/* Since GENERAL_REGS is the same class as ALL_REGS,
don't give it a different class number; just make it an alias. */
/* #define GENERAL_REGS ALL_REGS */
/* Give names of register classes as strings for dump file. */
#define REG_CLASS_NAMES {"NO_REGS", "MUL_REGS", "GENERAL_REGS", "LOAD_FPU_REGS", "NO_LOAD_FPU_REGS", "FPU_REGS", "ALL_REGS" }
#define REG_CLASS_NAMES \
{ "NO_REGS", \
"MUL_REGS", \
"GENERAL_REGS", \
"LOAD_FPU_REGS", \
"NO_LOAD_FPU_REGS", \
"FPU_REGS", \
"CC_REGS", \
"ALL_REGS" }
/* Define which registers fit in which classes.
This is an initializer for a vector of HARD_REG_SET
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS {{0}, {0x00aa}, {0xc0ff}, {0x0f00}, {0x3000}, {0x3f00}, {0xffff}}
#define REG_CLASS_CONTENTS \
{ {0x00000}, /* NO_REGS */ \
{0x000aa}, /* MUL_REGS */ \
{0x0c0ff}, /* GENERAL_REGS */ \
{0x00f00}, /* LOAD_FPU_REGS */ \
{0x03000}, /* NO_LOAD_FPU_REGS */ \
{0x03f00}, /* FPU_REGS */ \
{0x30000}, /* CC_REGS */ \
{0x3ffff}} /* ALL_REGS */
/* The same information, inverted:
Return the class number of the smallest class containing
@ -331,7 +368,7 @@ extern int may_call_alloca;
{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} \
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
((OFFSET) = pdp11_initial_elimination_offset ((FROM), (TO)))
@ -424,11 +461,18 @@ extern int may_call_alloca;
#define DBX_CONTIN_LENGTH 0
/* Give a comparison code (EQ, NE etc) and the first operand of a COMPARE,
return the mode to be used for the comparison. For floating-point, CCFPmode
should be used. */
return the mode to be used for the comparison. */
#define SELECT_CC_MODE(OP,X,Y) \
(GET_MODE_CLASS(GET_MODE(X)) == MODE_FLOAT? CCFPmode : CCmode)
#define SELECT_CC_MODE(OP,X,Y) pdp11_cc_mode (OP, X, Y)
/* Enable compare elimination pass.
FIXME: how can this be enabled for two registers? */
#undef TARGET_FLAGS_REGNUM
#define TARGET_FLAGS_REGNUM CC_REGNUM
/* Specify the CC registers. TODO: is this for "type 1" CC handling only? */
#undef TARGET_FIXED_CONDITION_CODE_REGS
#define TARGET_FIXED_CONDITION_CODE_REGS pdp11_fixed_cc_regs
/* Specify the machine mode that pointers have.
After generation of rtl, the compiler makes no further distinction
@ -446,54 +490,6 @@ extern int may_call_alloca;
but a CALL with constant address is cheap. */
/* #define NO_FUNCTION_CSE */
/* Tell emit-rtl.c how to initialize special values on a per-function base. */
extern rtx cc0_reg_rtx;
#define CC_STATUS_MDEP rtx
#define CC_STATUS_MDEP_INIT (cc_status.mdep = 0)
/* Tell final.c how to eliminate redundant test instructions. */
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
#define CC_IN_FPU 04000
/* Do UPDATE_CC if EXP is a set, used in
NOTICE_UPDATE_CC
floats only do compare correctly, else nullify ...
get cc0 out soon ...
*/
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
Do not alter them if the instruction would not alter the cc's. */
#define NOTICE_UPDATE_CC(EXP, INSN) \
{ if (GET_CODE (EXP) == SET) \
{ \
notice_update_cc_on_set(EXP, INSN); \
} \
else if (GET_CODE (EXP) == PARALLEL \
&& GET_CODE (XVECEXP (EXP, 0, 0)) == SET) \
{ \
notice_update_cc_on_set(XVECEXP (EXP, 0, 0), INSN); \
} \
else if (GET_CODE (EXP) == CALL) \
{ /* all bets are off */ CC_STATUS_INIT; } \
if (cc_status.value1 && GET_CODE (cc_status.value1) == REG \
&& cc_status.value2 \
&& reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) \
{ \
printf ("here!\n"); \
cc_status.value2 = 0; \
} \
}
/* Control the assembler format that we output. */
@ -520,7 +516,8 @@ extern rtx cc0_reg_rtx;
#define REGISTER_NAMES \
{"r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", \
"ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap" }
"ac0", "ac1", "ac2", "ac3", "ac4", "ac5", "fp", "ap", \
"cc", "fcc" }
/* Globalizing directive for a label. */
#define GLOBAL_ASM_OP "\t.globl "
@ -603,10 +600,7 @@ extern rtx cc0_reg_rtx;
#define TRAMPOLINE_SIZE 8
#define TRAMPOLINE_ALIGNMENT 16
/* there is no point in avoiding branches on a pdp,
since branches are really cheap - I just want to find out
how much difference the BRANCH_COST macro makes in code */
#define BRANCH_COST(speed_p, predictable_p) pdp11_branch_cost ()
#define BRANCH_COST(speed_p, predictable_p) 1
#define COMPARE_FLAG_MODE HImode

File diff suppressed because it is too large Load diff

View file

@ -34,22 +34,6 @@ mac0
Target Report Mask(AC0)
Return floating-point results in ac0 (fr0 in Unix assembler syntax).
mbcopy
Target RejectNegative Report Mask(BCOPY)
Do not use inline patterns for copying memory.
mbcopy-builtin
Target RejectNegative Report InverseMask(BCOPY, BCOPY_BUILTIN)
Use inline patterns for copying memory.
mbranch-cheap
Target RejectNegative Report InverseMask(BRANCH_EXPENSIVE, BRANCH_CHEAP)
Do not pretend that branches are expensive.
mbranch-expensive
Target RejectNegative Report Mask(BRANCH_EXPENSIVE)
Pretend that branches are expensive.
mdec-asm
Target RejectNegative Report InverseMask(UNIX_ASM)
Use the DEC assembler syntax.

View file

@ -23,17 +23,12 @@
(ior (match_operand 0 "register_operand")
(match_test "op == CONST0_RTX (GET_MODE (op))")))
;; Accept integer arguments in the range -4..-2 and 2..4, which are the
;; Accept integer arguments in the range 1..3, which are the
;; shift counts for which we unroll a shift. This matches the rule for
;; the "O" constraint.
(define_predicate "expand_shift_operand"
(match_code "const_int")
{
int sh;
sh = INTVAL (op);
return (abs (sh) > 1 && abs (sh) <= 4);
})
(and (match_code "const_int")
(match_test "(unsigned) INTVAL (op) < 4")))
;; Accept anything general_operand accepts, except that registers must
;; be FPU registers.
@ -52,3 +47,7 @@
(match_test "REGNO_REG_CLASS (REGNO (op)) == LOAD_FPU_REGS")
(match_test "REGNO_REG_CLASS (REGNO (op)) == NO_LOAD_FPU_REGS"))
(match_operand 0 "nonimmediate_operand")))
;; Accept any comparison valid for CCNZmode
(define_predicate "ccnz_operator"
(match_code "eq,ne,ge,lt"))

View file

@ -969,11 +969,9 @@ Objective-C and Objective-C++ Dialects}.
@emph{PDP-11 Options}
@gccoptlist{-mfpu -msoft-float -mac0 -mno-ac0 -m40 -m45 -m10 @gol
-mbcopy -mbcopy-builtin -mint32 -mno-int16 @gol
-mint16 -mno-int32 -mfloat32 -mno-float64 @gol
-mfloat64 -mno-float32 -mabshi -mno-abshi @gol
-mbranch-expensive -mbranch-cheap @gol
-munix-asm -mdec-asm}
-mint32 -mno-int16 -mint16 -mno-int32 @gol
-mfloat32 -mno-float64 -mfloat64 -mno-float32 @gol
-msplit -munix-asm -mdec-asm}
@emph{picoChip Options}
@gccoptlist{-mae=@var{ae_type} -mvliw-lookahead=@var{N} @gol
@ -22018,7 +22016,7 @@ These options are defined for the PDP-11:
@item -mfpu
@opindex mfpu
Use hardware FPP floating point. This is the default. (FIS floating
point on the PDP-11/40 is not supported.)
point on the PDP-11/40 is not supported.) Implies -m45.
@item -msoft-float
@opindex msoft-float
@ -22034,7 +22032,7 @@ Return floating-point results in memory. This is the default.
@item -m40
@opindex m40
Generate code for a PDP-11/40.
Generate code for a PDP-11/40. Implies -msoft-float -mno-split.
@item -m45
@opindex m45
@ -22042,16 +22040,7 @@ Generate code for a PDP-11/45. This is the default.
@item -m10
@opindex m10
Generate code for a PDP-11/10.
@item -mbcopy-builtin
@opindex mbcopy-builtin
Use inline @code{movmemhi} patterns for copying memory. This is the
default.
@item -mbcopy
@opindex mbcopy
Do not use inline @code{movmemhi} patterns for copying memory.
Generate code for a PDP-11/10. Implies -msoft-float -mno-split.
@item -mint16
@itemx -mno-int32
@ -22077,32 +22066,17 @@ Use 64-bit @code{float}. This is the default.
@opindex mno-float64
Use 32-bit @code{float}.
@item -mabshi
@opindex mabshi
Use @code{abshi2} pattern. This is the default.
@item -mno-abshi
@opindex mno-abshi
Do not use @code{abshi2} pattern.
@item -mbranch-expensive
@opindex mbranch-expensive
Pretend that branches are expensive. This is for experimenting with
code generation only.
@item -mbranch-cheap
@opindex mbranch-cheap
Do not pretend that branches are expensive. This is the default.
@item -msplit
@opindex msplit
Target has split instruction and data space. Implies -m45.
@item -munix-asm
@opindex munix-asm
Use Unix assembler syntax. This is the default when configured for
@samp{pdp11-*-bsd}.
Use Unix assembler syntax.
@item -mdec-asm
@opindex mdec-asm
Use DEC assembler syntax. This is the default when configured for any
PDP-11 target other than @samp{pdp11-*-bsd}.
Use DEC assembler syntax. This is the default.
@end table
@node picoChip Options

View file

@ -2966,12 +2966,20 @@ memory with a single instruction.
Odd numbered general registers (R1, R3, R5). These are used for
16-bit multiply operations.
@item D
A memory reference that is encoded within the opcode, but not
auto-increment or auto-decrement.
@item f
Any of the floating point registers (AC0 through AC5).
@item G
Floating point constant 0.
@item h
Floating point registers AC4 and AC5. These cannot be loaded from/to
memory with a single instruction.
@item I
An integer constant that fits in 16 bits.
@ -2992,7 +3000,7 @@ The integer constant @minus{}1.
The integer constant 0.
@item O
Integer constants @minus{}4 through @minus{}1 and 1 through 4; shifts by these
Integer constants 0 through 3; shifts by these
amounts are handled as multiple single-bit shifts rather than a single
variable-length shift.