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:
parent
356d53635f
commit
b4324a144b
12 changed files with 1524 additions and 884 deletions
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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))")))
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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.
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue