From b4324a144b4499725143baf1f69722f92814572e Mon Sep 17 00:00:00 2001 From: Paul Koning Date: Wed, 27 Jun 2018 17:58:24 -0400 Subject: [PATCH] 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 --- gcc/ChangeLog | 69 ++ gcc/common/config/pdp11/pdp11-common.c | 20 +- gcc/config/pdp11/constraints.md | 15 +- gcc/config/pdp11/pdp11-modes.def | 22 +- gcc/config/pdp11/pdp11-protos.h | 13 +- gcc/config/pdp11/pdp11.c | 559 ++++++--- gcc/config/pdp11/pdp11.h | 142 ++- gcc/config/pdp11/pdp11.md | 1439 +++++++++++++++--------- gcc/config/pdp11/pdp11.opt | 16 - gcc/config/pdp11/predicates.md | 15 +- gcc/doc/invoke.texi | 48 +- gcc/doc/md.texi | 10 +- 12 files changed, 1504 insertions(+), 864 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c435a3b29a7..fc0550460b8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,72 @@ +2018-06-27 Paul Koning + + * 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 Austin Law diff --git a/gcc/common/config/pdp11/pdp11-common.c b/gcc/common/config/pdp11/pdp11-common.c index aa809a9d457..9feb4fd4ea1 100644 --- a/gcc/common/config/pdp11/pdp11-common.c +++ b/gcc/common/config/pdp11/pdp11-common.c @@ -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; } diff --git a/gcc/config/pdp11/constraints.md b/gcc/config/pdp11/constraints.md index 0d78dd86835..10bf1204716 100644 --- a/gcc/config/pdp11/constraints.md +++ b/gcc/config/pdp11/constraints.md @@ -18,11 +18,14 @@ ;; along with GCC; see the file COPYING3. If not see ;; . +(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))"))) + diff --git a/gcc/config/pdp11/pdp11-modes.def b/gcc/config/pdp11/pdp11-modes.def index a49994acf09..164889eae87 100644 --- a/gcc/config/pdp11/pdp11-modes.def +++ b/gcc/config/pdp11/pdp11-modes.def @@ -19,8 +19,26 @@ along with GCC; see the file COPYING3. If not see . */ /* 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); diff --git a/gcc/config/pdp11/pdp11-protos.h b/gcc/config/pdp11/pdp11-protos.h index c5096b0d793..453632314d7 100644 --- a/gcc/config/pdp11/pdp11-protos.h +++ b/gcc/config/pdp11/pdp11-protos.h @@ -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); diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c index 38c55fbb3df..ab73693d1da 100644 --- a/gcc/config/pdp11/pdp11.c +++ b/gcc/config/pdp11/pdp11.c @@ -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; - - /* Eliminate non-memory operations */ - if (GET_CODE (op) != MEM) - return FALSE; + rtx addr; -#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 + /* Eliminate non-memory operations */ + if (GET_CODE (op) != MEM) + return FALSE; - /* 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! + 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; +} + +/* 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; - -- except for @(R0), which has to be @0(R0) !!! */ + /* Eliminate non-memory operations */ + if (GET_CODE (op) != MEM) + return FALSE; + + /* Decode the address now. */ + + indirection: + + addr = XEXP (op, 0); - if (GET_CODE (XEXP (addr, 0)) == REG) - return 0; + switch (GET_CODE (addr)) + { + case REG: + /* (R0) - no extra cost */ + return 1; - op=addr; - goto indirection; + case PRE_DEC: + case POST_INC: + case PRE_MODIFY: + case POST_MODIFY: + return 0; - case CONST_INT: - case LABEL_REF: - case CONST: - case SYMBOL_REF: - /* @#address - extra cost */ - return 0; + case MEM: + /* cheap - is encoded in addressing mode info! - case PLUS: - /* X(R0) - extra cost */ + -- 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; - default: - break; + case PLUS: + /* X(R0) - extra cost */ + return 0; + + default: + break; } - return FALSE; + 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 diff --git a/gcc/config/pdp11/pdp11.h b/gcc/config/pdp11/pdp11.h index af92a79bf30..f995bc8672b 100644 --- a/gcc/config/pdp11/pdp11.h +++ b/gcc/config/pdp11/pdp11.h @@ -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) pdp11_cc_mode (OP, X, Y) -#define SELECT_CC_MODE(OP,X,Y) \ -(GET_MODE_CLASS(GET_MODE(X)) == MODE_FLOAT? CCFPmode : CCmode) +/* 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 diff --git a/gcc/config/pdp11/pdp11.md b/gcc/config/pdp11/pdp11.md index 4f4a5d20a91..1dd069ff101 100644 --- a/gcc/config/pdp11/pdp11.md +++ b/gcc/config/pdp11/pdp11.md @@ -44,28 +44,80 @@ ;; arguments. (FRAME_POINTER_REGNUM 14) (ARG_POINTER_REGNUM 15) - (FIRST_PSEUDO_REGISTER 16) + ;; Condition code registers + (CC_REGNUM 16) + (FCC_REGNUM 17) + ;; End of hard registers + (FIRST_PSEUDO_REGISTER 18) + ;; Branch offset limits, as byte offsets from instruction address (MIN_BRANCH -254) (MAX_BRANCH 256) (MIN_SOB -126) (MAX_SOB 0)]) +;; DF is 64 bit +;; SF is 32 bit +;; SI is 32 bit ;; HI is 16 bit ;; QI is 8 bit ;; Integer modes supported on the PDP11, with a mapping from machine mode -;; to mnemonic suffix. SImode and DImode always are special cases. +;; to mnemonic suffix. SImode and DImode are usually special cases. (define_mode_iterator PDPint [QI HI]) (define_mode_attr isfx [(QI "b") (HI "")]) +(define_mode_attr mname [(QI "QImode") (HI "HImode") (SI "SImode") (DI "DImode")]) +(define_mode_attr e_mname [(QI "E_QImode") (HI "E_HImode") (SI "E_SImode") (DI "E_DImode")]) +(define_mode_attr hmode [(QI "hi") (HI "hi") (SI "si") (DI "di")]) + +;; These are analogous for use in splitters and expanders. +(define_mode_iterator HSint [HI SI]) +(define_mode_iterator QHSint [QI HI SI]) +(define_mode_iterator QHSDint [QI HI SI DI]) + +(define_code_iterator SHF [ashift ashiftrt lshiftrt]) + +;; Substitution to turn a CC clobber into a CC setter. We have four of +;; these: for CCmode vs. CCNZmode, and for CC_REGNUM vs. FCC_REGNUM. +(define_subst "cc_cc" + [(set (match_operand 0 "") (match_operand 1 "")) + (clobber (reg CC_REGNUM))] + "" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_dup 1) (const_int 0))) + (set (match_dup 0) (match_dup 1))]) -;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. +(define_subst "cc_ccnz" + [(set (match_operand 0 "") (match_operand 1 "")) + (clobber (reg CC_REGNUM))] + "" + [(set (reg:CCNZ CC_REGNUM) + (compare:CCNZ (match_dup 1) (const_int 0))) + (set (match_dup 0) (match_dup 1))]) -;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code -;;- updates for most instructions. +(define_subst "fcc_cc" + [(set (match_operand 0 "") (match_operand 1 "")) + (clobber (reg FCC_REGNUM))] + "" + [(set (reg:CC FCC_REGNUM) + (compare:CC (match_dup 1) (const_int 0))) + (set (match_dup 0) (match_dup 1))]) + +(define_subst "fcc_ccnz" + [(set (match_operand 0 "") (match_operand 1 "")) + (clobber (reg FCC_REGNUM))] + "" + [(set (reg:CCNZ FCC_REGNUM) + (compare:CCNZ (match_dup 1) (const_int 0))) + (set (match_dup 0) (match_dup 1))]) + +(define_subst_attr "cc_cc" "cc_cc" "_nocc" "_cc") +(define_subst_attr "fcc_cc" "fcc_cc" "_nocc" "_cc") +(define_subst_attr "cc_ccnz" "cc_ccnz" "_nocc" "_cc") +(define_subst_attr "fcc_ccnz" "fcc_ccnz" "_nocc" "_cc") + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. -;;- Operand classes for the register allocator: - ;; Compare instructions. ;; currently we only support df floats, which saves us quite some @@ -82,16 +134,6 @@ ;; and ucmp_optab for mode SImode, because we don't have that!!! ;; - yet since no libfunc is there, we abort () -;; The only thing that remains to be done then is output -;; the floats in a way the assembler can handle it (and -;; if you're really into it, use a PDP11 float emulation -;; library to do floating point constant folding - but -;; I guess you'll get reasonable results even when not -;; doing this) -;; the last thing to do is fix the UPDATE_CC macro to check -;; for floating point condition codes, and set cc_status -;; properly, also setting the CC_IN_FCCR flag. - ;; define attributes ;; currently type is only fpu or arith or unknown, maybe branch later ? ;; default is arith @@ -163,24 +205,31 @@ ;; compare (define_insn "*cmpdf" - [(set (cc0) - (compare (match_operand:DF 0 "general_operand" "fR,fR,Q,QF") - (match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))] - "TARGET_FPU" + [(set (reg:CC FCC_REGNUM) + (compare:CC (match_operand:DF 0 "general_operand" "fR,fR,Q,QF") + (match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))] + "TARGET_FPU && reload_completed" "* { - cc_status.flags = CC_IN_FPU; if (which_alternative == 0 || which_alternative == 2) - return \"{tstd|tstf} %0\;cfcc\"; + return \"{tstd|tstf} %0\"; else - return \"{cmpd|cmpf} %0, %1\;cfcc\"; + return \"{cmpd|cmpf} %0, %1\"; }" - [(set_attr "length" "4,4,6,6")]) - -(define_insn "*cmp" - [(set (cc0) - (compare (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi") - (match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))] + [(set_attr "length" "2,2,4,4") + (set_attr "type" "fp")]) + +;; Copy floating point processor condition code register to main CPU +;; condition code register. +(define_insn "*cfcc" + [(set (reg CC_REGNUM) (reg FCC_REGNUM))] + "TARGET_FPU && reload_completed" + "cfcc") + +(define_insn "cmp" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi") + (match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))] "" "@ tst %0 @@ -191,8 +240,7 @@ cmp %0,%1" [(set_attr "length" "2,2,4,4,4,6")]) -;; sob instruction - we need an assembler which can make this instruction -;; valid under _all_ circumstances! +;; sob instruction - FIXME: this doesn't do anything, need to use doloop_end. (define_insn "" [(set (pc) @@ -208,22 +256,17 @@ "TARGET_40_PLUS" "* { - static int labelcount = 0; - static char buf[1000]; - if (get_attr_length (insn) == 2) return \"sob %0, %l1\"; /* emulate sob */ + operands[2] = gen_label_rtx (); output_asm_insn (\"dec %0\", operands); - - sprintf (buf, \"bge LONG_SOB%d\", labelcount); - output_asm_insn (buf, NULL); - + output_asm_insn (\"beq %l2\", operands); output_asm_insn (\"jmp %l1\", operands); - sprintf (buf, \"LONG_SOB%d:\", labelcount++); - output_asm_insn (buf, NULL); + output_asm_label (operands[2]); + fputs (\":\\n\", asm_out_file); return \"\"; }" @@ -238,46 +281,73 @@ ;; These control RTL generation for conditional jump insns ;; and match them for register allocation. - -(define_expand "cbranchdf4" - [(set (cc0) - (compare (match_operand:DF 1 "general_operand") - (match_operand:DF 2 "register_or_const0_operand"))) - (set (pc) +;; Post reload these get expanded into insns that actually +;; manipulate the condition code registers. We can't do that before +;; because instructions generated by reload clobber condition codes (new +;; CC design, type #2). +(define_insn_and_split "cbranchdf4" + [(set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) + [(match_operand:DF 1 "general_operand" "fg") + (match_operand:DF 2 "general_operand" "a")]) (label_ref (match_operand 3 "" "")) (pc)))] "TARGET_FPU" + "#" + "&& reload_completed" + [(set (reg:CC FCC_REGNUM) + (compare:CC (match_dup 1) (match_dup 2))) + (set (pc) + (if_then_else (match_op_dup 0 + [(reg:CC FCC_REGNUM) (const_int 0)]) + (label_ref (match_dup 3)) + (pc)))] "") -(define_expand "cbranch4" - [(set (cc0) - (compare (match_operand:PDPint 1 "general_operand") - (match_operand:PDPint 2 "general_operand"))) - (set (pc) +(define_insn_and_split "cbranch4" + [(set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) + [(match_operand:PDPint 1 "general_operand" "g") + (match_operand:PDPint 2 "general_operand" "g")]) (label_ref (match_operand 3 "" "")) (pc)))] "" + "#" + "reload_completed" + [(set (reg:CC CC_REGNUM) + (compare:CC (match_dup 1) (match_dup 2))) + (set (pc) + (if_then_else (match_op_dup 0 + [(reg:CC CC_REGNUM) (const_int 0)]) + (label_ref (match_dup 3)) + (pc)))] "") -;; problem with too short jump distance! we need an assembler which can -;; make this valid for all jump distances! -;; e.g. gas! - -;; these must be changed to check for CC_IN_FCCR if float is to be -;; enabled +;; This splitter turns a branch on float condition into a branch on +;; CPU condition, by adding a CFCC. +(define_split + [(set (pc) + (if_then_else (match_operator 0 "ordered_comparison_operator" + [(reg:CC FCC_REGNUM) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "TARGET_FPU && reload_completed" + [(set (reg:CC CC_REGNUM) (reg:CC FCC_REGNUM)) + (set (pc) + (if_then_else (match_op_dup 0 + [(reg:CC CC_REGNUM) (const_int 0)]) + (label_ref (match_dup 1)) + (pc)))] + "") -(define_insn "*branch" +(define_insn "cond_branch" [(set (pc) (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) + [(reg:CC CC_REGNUM) (const_int 0)]) (label_ref (match_operand 1 "" "")) (pc)))] - "" - "* return output_jump(GET_CODE (operands[0]), 0, get_attr_length(insn));" + "reload_completed" + "* return output_jump (operands, 0, get_attr_length (insn));" [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1) (pc)) (const_int MIN_BRANCH)) @@ -287,17 +357,14 @@ (const_int 6) (const_int 2)))]) - -;; These match inverted jump insns for register allocation. - -(define_insn "*branch_inverted" +(define_insn "*branch" [(set (pc) - (if_then_else (match_operator 0 "ordered_comparison_operator" - [(cc0) (const_int 0)]) - (pc) - (label_ref (match_operand 1 "" ""))))] - "" - "* return output_jump(GET_CODE (operands[0]), 1, get_attr_length(insn));" + (if_then_else (match_operator 0 "ccnz_operator" + [(reg:CCNZ CC_REGNUM) (const_int 0)]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "reload_completed" + "* return output_jump (operands, 1, get_attr_length (insn));" [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1) (pc)) (const_int MIN_BRANCH)) @@ -306,6 +373,7 @@ (const_int MAX_BRANCH))) (const_int 6) (const_int 2)))]) + ;; Move instructions @@ -313,6 +381,14 @@ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g") (match_operand:DI 1 "general_operand" "rN,g"))] "" + "") + + +(define_insn "*movdi_nocc" + [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g") + (match_operand:DI 1 "general_operand" "rN,g")) + (clobber (reg:CC CC_REGNUM))] + "" "* return output_move_multiple (operands);" [(set_attr "length" "16,32")]) @@ -320,6 +396,13 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g") (match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))] "" + "") + +(define_insn "*movsi_nocc" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g") + (match_operand:SI 1 "general_operand" "rN,IJ,IJ,g")) + (clobber (reg:CC CC_REGNUM))] + "" "* return output_move_multiple (operands);" [(set_attr "length" "4,6,8,16")]) @@ -327,6 +410,25 @@ [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") (match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))] "" + "") + +;; This splits all the integer moves: DI and SI modes as well as +;; the simple machine operations. +(define_split + [(set (match_operand:QHSDint 0 "nonimmediate_operand" "") + (match_operand:QHSDint 1 "general_operand" ""))] + "reload_completed" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (clobber (reg:CC CC_REGNUM))])] + "") + +;; MOV clears V +(define_insn "*mov_" + [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") + (match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi")) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "* { if (operands[1] == const0_rtx) @@ -336,31 +438,87 @@ }" [(set_attr "length" "2,4,4,6")]) -(define_insn "movdf" - [(set (match_operand:DF 0 "float_nonimm_operand" "=a,fR,a,Q,g") - (match_operand:DF 1 "float_operand" "fR,a,FQ,a,g"))] +;; movdf has unusually complicated condition code handling, because +;; load (into float register) updates the FCC, while store (from +;; float register) leaves it untouched. +;; +;; 1. Loads are: ac4, ac5, or non-register into load-register +;; 2. Stores are: load-register to non-register, ac4, or ac5 +;; 3. Moves from ac0-ac3 to another ac0-ac3 can be handled +;; either as loads or as stores. + +(define_expand "movdf" + [(set (match_operand:DF 0 "float_nonimm_operand" "") + (match_operand:DF 1 "float_operand" ""))] "TARGET_FPU" - "* if (which_alternative ==0 || which_alternative == 2) - return \"ldd %1, %0\"; - else if (which_alternative == 1 || which_alternative == 3) - return \"std %1, %0\"; - else - return output_move_multiple (operands); " -;; last one is worst-case - [(set_attr "length" "2,2,4,4,24")]) + "") -(define_insn "movsf" - [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,g") - (match_operand:SF 1 "float_operand" "fR,a,FQ,a,g"))] +;; Splitter for all these cases. Store is the first two +;; alternatives, which are not split. Note that case 3 +;; is treated as a store, i.e., not split. +(define_insn_and_split "movdf_split" + [(set (match_operand:DF 0 "float_nonimm_operand" "=fR,FQ,a,a,a") + (match_operand:DF 1 "float_operand" "a,a,hR,FQ,G"))] "TARGET_FPU" - "* if (which_alternative ==0 || which_alternative == 2) - return \"{ldcfd|movof} %1, %0\"; - else if (which_alternative == 1 || which_alternative == 3) - return \"{stcdf|movfo} %1, %0\"; - else - return output_move_multiple (operands); " -;; last one is worst-case - [(set_attr "length" "2,2,4,4,12")]) + "* + gcc_assert (which_alternative < 2); + return \"std %1, %0\"; + " + "&& reload_completed" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (clobber (reg:CC FCC_REGNUM))])] + "{ + if (GET_CODE (operands[1]) == REG && + REGNO_REG_CLASS (REGNO (operands[1])) == LOAD_FPU_REGS) + FAIL; + }" + [(set_attr "length" "2,4,0,0,0")]) + +;; Loads (case 1). +(define_insn "*ldd" + [(set (match_operand:DF 0 "float_nonimm_operand" "=a,a,a") + (match_operand:DF 1 "float_operand" "hR,FQ,G")) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" + "@ + ldd %1, %0 + ldd %1, %0 + clrd %0" + [(set_attr "length" "2,4,2")]) + +;; SFmode is easier because that uses convert load/store, which +;; always change condition codes. +;; Note that these insns are cheating a bit. We actually have +;; DFmode operands in the FPU registers, which is why the +;; ldcfd and stcdf instructions appear. But GCC likes to think +;; of these as SFmode loads and does the conversion once in the +;; register, at least in many cases. So we pretend to do this, +;; but then extend and truncate register-to-register are NOP and +;; generate no code. +(define_insn_and_split "movsf" + [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q") + (match_operand:SF 1 "float_operand" "fRG,a,FQ,a"))] + "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) + (match_dup 1)) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "*movsf" + [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,a") + (match_operand:SF 1 "float_operand" "fR,a,FQ,a,G")) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" + "@ + {ldcfd|movof} %1, %0 + {stcdf|movfo} %1, %0 + {ldcfd|movof} %1, %0 + {stcdf|movfo} %1, %0 + clrf %0" + [(set_attr "length" "2,2,4,4,2")]) ;; maybe fiddle a bit with move_ratio, then ;; let constraints only accept a register ... @@ -374,7 +532,7 @@ (clobber (match_dup 4)) (clobber (match_dup 5)) (clobber (match_dup 2))])] - "(TARGET_BCOPY_BUILTIN)" + "" " { operands[0] @@ -389,7 +547,7 @@ }") -(define_insn "movmemhi1" +(define_insn "*movmemhi1" [(set (mem:BLK (match_operand:HI 0 "register_operand" "r,r")) (mem:BLK (match_operand:HI 1 "register_operand" "r,r"))) (use (match_operand:HI 2 "general_operand" "n,r")) @@ -398,7 +556,7 @@ (clobber (match_dup 0)) (clobber (match_dup 1)) (clobber (match_dup 2))] - "(TARGET_BCOPY_BUILTIN)" + "" "* return output_block_move (operands);" ;;; just a guess [(set_attr "length" "80")]) @@ -407,29 +565,56 @@ ;;- truncation instructions -(define_insn "truncdfsf2" +;; We sometimes end up doing a register to register truncate, +;; which isn't right because we actually load registers always +;; with a DFmode value. But even with PROMOTE the compiler +;; doesn't always get that (so we don't use it). That means +;; a register to register truncate is a NOP. +(define_insn_and_split "truncdfsf2" [(set (match_operand:SF 0 "float_nonimm_operand" "=f,R,Q") - (float_truncate:SF (match_operand:DF 1 "register_operand" "f,a,a")))] + (float_truncate:SF (match_operand:DF 1 "register_operand" "0,a,a")))] "TARGET_FPU" - "* if (which_alternative ==0) - { - return \"\"; - } - else if (which_alternative == 1) - return \"{stcdf|movfo} %1, %0\"; - else - return \"{stcdf|movfo} %1, %0\"; - " - [(set_attr "length" "0,2,4")]) - + { + gcc_assert (which_alternative == 0); + return ""; + } + "&& reload_completed" + [(parallel [(set (match_dup 0) (float_truncate:SF (match_dup 1))) + (clobber (reg:CC FCC_REGNUM))])] + "{ + if (GET_CODE (operands[0]) == REG && + GET_CODE (operands[1]) == REG && + REGNO (operands[0]) == REGNO (operands[1])) + FAIL; + }" + [(set_attr "length" "0,0,0")]) + +(define_insn "*truncdfsf2_" + [(set (match_operand:SF 0 "float_nonimm_operand" "=R,Q") + (float_truncate:SF (match_operand:DF 1 "register_operand" "a,a"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" + "{stcdf|movfo} %1, %0" + [(set_attr "length" "2,4")]) ;;- zero extension instructions -(define_insn "zero_extendqihi2" +(define_insn_and_split "zero_extendqihi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") (zero_extend:HI (match_operand:QI 1 "general_operand" "0,0")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (zero_extend:HI (match_dup 1))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*zero_extendqihi2" + [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") + (zero_extend:HI (match_operand:QI 1 "general_operand" "0,0"))) + (clobber (reg:CC CC_REGNUM))])] + "reload_completed" "bic $0177400, %0" [(set_attr "length" "4,6")]) @@ -448,56 +633,73 @@ ;;- sign extension instructions -(define_insn "extendsfdf2" +;; We sometimes end up doing a register to register extend, +;; which isn't right because we actually load registers always +;; with a DFmode value. But even with PROMOTE the compiler +;; doesn't always get that (so we don't use it). That means +;; a register to register truncate is a NOP. +(define_insn_and_split "extendsfdf2" [(set (match_operand:DF 0 "register_operand" "=f,a,a") - (float_extend:DF (match_operand:SF 1 "float_operand" "f,R,Q")))] + (float_extend:DF (match_operand:SF 1 "float_operand" "0,R,Q")))] "TARGET_FPU" - "@ - /* nothing */ - {ldcfd|movof} %1, %0 - {ldcfd|movof} %1, %0" - [(set_attr "length" "0,2,4")]) + { + gcc_assert (which_alternative == 0); + return ""; + } + "&& reload_completed" + [(parallel [(set (match_dup 0) (float_extend:DF (match_dup 1))) + (clobber (reg:CC FCC_REGNUM))])] + "{ + if (GET_CODE (operands[0]) == REG && + GET_CODE (operands[1]) == REG && + REGNO (operands[0]) == REGNO (operands[1])) + FAIL; + }" + [(set_attr "length" "0,0,0")]) + +(define_insn "*extendsfdf2_" + [(set (match_operand:DF 0 "register_operand" "=a,a") + (float_extend:DF (match_operand:SF 1 "float_operand" "R,Q"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" + "{ldcfd|movof} %1, %0" + [(set_attr "length" "2,4")]) -;; does movb sign extend in register-to-register move? -(define_insn "extendqihi2" +;; movb sign extends if destination is a register +(define_insn_and_split "extendqihi2" [(set (match_operand:HI 0 "register_operand" "=r,r") (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (sign_extend:HI (match_dup 1))) + (clobber (reg:CC CC_REGNUM))])] + "") + +;; MOVB clears V +(define_insn "*extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "movb %1, %0" [(set_attr "length" "2,4")]) -(define_insn "extendqisi2" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (sign_extend:SI (match_operand:QI 1 "general_operand" "rR,Q")))] - "TARGET_40_PLUS" - "* -{ - rtx latehalf[2]; - - /* make register pair available */ - latehalf[0] = operands[0]; - operands[0] = gen_rtx_REG (HImode, REGNO (operands[0])+ 1); - - output_asm_insn(\"movb %1, %0\", operands); - output_asm_insn(\"sxt %0\", latehalf); - - return \"\"; -}" - [(set_attr "length" "4,6")]) - -;; maybe we have to use define_expand to say that we have the instruction, -;; unconditionally, and then match dependent on CPU type: - -(define_expand "extendhisi2" - [(set (match_operand:SI 0 "nonimmediate_operand" "=g") - (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))] - "" - "") - -(define_insn "" ; "extendhisi2" +(define_insn_and_split "extendhisi2" [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r") (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))] "TARGET_40_PLUS" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (sign_extend:SI (match_dup 1))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*extendhisi2_nocc" + [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r") + (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g"))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_40_PLUS && reload_completed" "* { rtx latehalf[2]; @@ -542,52 +744,33 @@ }" [(set_attr "length" "10,6,6")]) - -(define_insn "" - [(set (match_operand:SI 0 "register_operand" "=r") - (sign_extend:SI (match_operand:HI 1 "general_operand" "0")))] - "(! TARGET_40_PLUS)" - "* -{ - static int count = 0; - char buf[100]; - rtx lateoperands[2]; - - lateoperands[0] = operands[0]; - operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1); - - output_asm_insn(\"tst %0\", operands); - sprintf(buf, \"bge extendhisi%d\", count); - output_asm_insn(buf, NULL); - output_asm_insn(\"mov -1, %0\", lateoperands); - sprintf(buf, \"bne extendhisi%d\", count+1); - output_asm_insn(buf, NULL); - sprintf(buf, \"\\nextendhisi%d:\", count); - output_asm_insn(buf, NULL); - output_asm_insn(\"clr %0\", lateoperands); - sprintf(buf, \"\\nextendhisi%d:\", count+1); - output_asm_insn(buf, NULL); - - count += 2; - - return \"\"; -}" - [(set_attr "length" "12")]) - ;; make float to int and vice versa -;; using the cc_status.flag field we could probably cut down -;; on seti and setl ;; assume that we are normally in double and integer mode - ;; what do pdp library routines do to fpu mode ? -(define_insn "floatsidf2" +;; Note: the hardware treats register source as +;; a 16-bit (high order only) source, which isn't +;; what we want. But we do need to support register +;; dest because gcc asks for it. +(define_insn_and_split "floatsidf2" [(set (match_operand:DF 0 "register_operand" "=a,a,a") (float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (float:DF (match_dup 1))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "*floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=a,a,a") + (float:DF (match_operand:SI 1 "general_operand" "r,R,Q"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "* if (which_alternative ==0) { rtx latehalf[2]; - + latehalf[0] = NULL; latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1); output_asm_insn(\"mov %1, -(sp)\", latehalf); @@ -598,25 +781,53 @@ output_asm_insn(\"seti\", operands); return \"\"; } - else if (which_alternative == 1) - return \"setl\;{ldcld|movif} %1, %0\;seti\"; else return \"setl\;{ldcld|movif} %1, %0\;seti\"; " [(set_attr "length" "10,6,8")]) -(define_insn "floathidf2" +(define_insn_and_split "floathidf2" [(set (match_operand:DF 0 "register_operand" "=a,a") (float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (float:DF (match_dup 1))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "*floathidf2" + [(set (match_operand:DF 0 "register_operand" "=a,a") + (float:DF (match_operand:HI 1 "general_operand" "rR,Qi"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{ldcid|movif} %1, %0" [(set_attr "length" "2,4")]) ;; cut float to int -(define_insn "fix_truncdfsi2" + +;; Note: the hardware treats register destination as +;; a 16-bit (high order only) destination, which isn't +;; what we want. But we do need to support register +;; dest because gcc asks for it. +(define_insn_and_split "fix_truncdfsi2" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q") (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (fix:SI (fix:DF (match_dup 1)))) + (clobber (reg:CC CC_REGNUM)) + (clobber (reg:CC FCC_REGNUM))])] + "") + +;; Note: this clobbers both sets of condition codes! +(define_insn "*fix_truncdfsi2_nocc" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q") + (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a")))) + (clobber (reg:CC CC_REGNUM)) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "* if (which_alternative ==0) { output_asm_insn(\"setl\", operands); @@ -627,17 +838,29 @@ output_asm_insn(\"mov (sp)+, %0\", operands); return \"\"; } - else if (which_alternative == 1) - return \"setl\;{stcdl|movfi} %1, %0\;seti\"; else return \"setl\;{stcdl|movfi} %1, %0\;seti\"; " [(set_attr "length" "10,6,8")]) -(define_insn "fix_truncdfhi2" +(define_insn_and_split "fix_truncdfhi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (fix:HI (fix:DF (match_dup 1)))) + (clobber (reg:CC CC_REGNUM)) + (clobber (reg:CC FCC_REGNUM))])] + "") + +;; Note: this clobbers both sets of condition codes! +(define_insn "*fix_truncdfhi2_nocc" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") + (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a")))) + (clobber (reg:CC CC_REGNUM)) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{stcdi|movfi} %1, %0" [(set_attr "length" "2,4")]) @@ -645,19 +868,45 @@ ;;- arithmetic instructions ;;- add instructions -(define_insn "adddf3" +(define_insn_and_split "adddf3" [(set (match_operand:DF 0 "register_operand" "=a,a") (plus:DF (match_operand:DF 1 "register_operand" "%0,0") (match_operand:DF 2 "general_operand" "fR,QF")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) + (plus:DF (match_dup 1) (match_dup 2))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +;; Float add sets V if overflow from add +(define_insn "*adddf3" + [(set (match_operand:DF 0 "register_operand" "=a,a") + (plus:DF (match_operand:DF 1 "register_operand" "%0,0") + (match_operand:DF 2 "general_operand" "fR,QF"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{addd|addf} %2, %0" [(set_attr "length" "2,4")]) -(define_insn "adddi3" +(define_insn_and_split "adddi3" [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0") (match_operand:DI 2 "general_operand" "r,on,r,on")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*adddi3_nocc" + [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") + (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0") + (match_operand:DI 2 "general_operand" "r,on,r,on"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "* { rtx inops[2]; @@ -701,11 +950,23 @@ ;; high word is added at the end, so the adding of the high parts ;; will always used the original high part and not a high part ;; modified by carry (which would amount to double carry). -(define_insn "addsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o") +(define_insn_and_split "addsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0") (match_operand:SI 2 "general_operand" "r,on,r,on")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*addsi3_nocc" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") + (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0") + (match_operand:SI 2 "general_operand" "r,on,r,on"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "* { rtx inops[2]; @@ -727,11 +988,25 @@ }" [(set_attr "length" "6,10,12,16")]) -(define_insn "addhi3" +(define_insn_and_split "addhi3" [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0") (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (plus:HI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +;; Add sets V if overflow from the add +(define_insn "*addhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") + (plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0") + (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "* { if (GET_CODE (operands[2]) == CONST_INT) @@ -752,19 +1027,44 @@ ;; args, since they are canonical plus:xx now! ;; also for minus:DF ?? -(define_insn "subdf3" +(define_insn_and_split "subdf3" [(set (match_operand:DF 0 "register_operand" "=a,a") (minus:DF (match_operand:DF 1 "register_operand" "0,0") (match_operand:DF 2 "general_operand" "fR,Q")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) + (minus:DF (match_dup 1) (match_dup 2))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "*subdf3" + [(set (match_operand:DF 0 "register_operand" "=a,a") + (minus:DF (match_operand:DF 1 "register_operand" "0,0") + (match_operand:DF 2 "general_operand" "fR,QF"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{subd|subf} %2, %0" [(set_attr "length" "2,4")]) -(define_insn "subdi3" +(define_insn_and_split "subdi3" [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0") (match_operand:DI 2 "general_operand" "r,on,r,on")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*subdi3_nocc" + [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o") + (minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0") + (match_operand:DI 2 "general_operand" "r,on,r,on"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "* { rtx inops[2]; @@ -799,11 +1099,23 @@ }" [(set_attr "length" "20,28,40,48")]) -(define_insn "subsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o") +(define_insn_and_split "subsi3" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") (match_operand:SI 2 "general_operand" "r,on,r,on")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*subsi3_nocc" + [(set (match_operand:SI 0 "nonimmediate_operand" "=&r,r,o,o") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") + (match_operand:SI 2 "general_operand" "r,on,r,on"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "* { rtx inops[2]; @@ -825,14 +1137,37 @@ }" [(set_attr "length" "6,10,12,16")]) -(define_insn "subhi3" +(define_insn_and_split "subhi3" [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") - (match_operand:HI 2 "general_operand" "rR,Qi,rR,Qi")))] + (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (minus:HI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +;; Note: the manual says that (minus m (const_int n)) is converted +;; to (plus m (const_int -n)) but that does not appear to be +;; the case when it's wrapped in a PARALLEL. So instead we handle +;; that case here, which is easy enough. +(define_insn "*subhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q") + (minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0") + (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "* { - gcc_assert (GET_CODE (operands[2]) != CONST_INT); + if (GET_CODE (operands[2]) == CONST_INT) + { + if (INTVAL(operands[2]) == 1) + return \"dec %0\"; + else if (INTVAL(operands[2]) == -1) + return \"inc %0\"; + } return \"sub %2, %0\"; }" @@ -867,317 +1202,288 @@ operands[1] = expand_unop (mode, one_cmpl_optab, op1, 0, 1); }") -(define_insn "*bic" +(define_insn_and_split "*bic" [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") (and:PDPint (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi")) (match_operand:PDPint 2 "general_operand" "0,0,0,0")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (and:PDPint (not:PDPint (match_dup 1)) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*bic" + [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") + (and:PDPint + (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi")) + (match_operand:PDPint 2 "general_operand" "0,0,0,0"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "bic %1, %0" [(set_attr "length" "2,4,4,6")]) ;;- Bit set (inclusive or) instructions -(define_insn "ior3" +(define_insn_and_split "ior3" [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") (ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0") - (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))] + (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (ior:PDPint (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "ior3" + [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q") + (ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0") + (match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "bis %2, %0" [(set_attr "length" "2,4,4,6")]) ;;- xor instructions -(define_insn "xorhi3" +(define_insn_and_split "xorhi3" [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") (xor:HI (match_operand:HI 1 "general_operand" "%0,0") (match_operand:HI 2 "register_operand" "r,r")))] "TARGET_40_PLUS" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) + (xor:HI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*xorhi3" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") + (xor:HI (match_operand:HI 1 "general_operand" "%0,0") + (match_operand:HI 2 "register_operand" "r,r"))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_40_PLUS && reload_completed" "xor %2, %0" [(set_attr "length" "2,4")]) ;;- one complement instructions -(define_insn "one_cmpl2" +(define_insn_and_split "one_cmpl2" [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) + (not:PDPint (match_dup 1))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "*one_cmpl2" + [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") + (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" "com %0" [(set_attr "length" "2,4")]) ;;- arithmetic shift instructions -(define_insn "ashlsi3" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (ashift:SI (match_operand:SI 1 "register_operand" "0,0") - (match_operand:HI 2 "general_operand" "rR,Qi")))] - "TARGET_40_PLUS" - "ashc %2,%0" - [(set_attr "length" "2,4")]) - -;; Arithmetic right shift on the pdp works by negating the shift count. -(define_expand "ashrsi3" - [(set (match_operand:SI 0 "register_operand" "=r") - (ashift:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:HI 2 "general_operand" "g")))] +;; +;; There is a fair amount of complexity here because with -m10 +;; (pdp-11/10, /20) we only have shift by one bit. Iterators are +;; used to reduce the amount of very similar code. +;; +;; First the insns used for small constant shifts. +; +;; The "length" attribute values are modified by the ADJUST_INSN_LENGTH +;; macro for the small constant shift case (first two alternatives). +;; For those, the value coded in the length attribute is the cost of just +;; the shift for a single shift. +(define_insn "_sc" + [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q") + (SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0") + (match_operand:HI 2 "expand_shift_operand" "O,O")))] "" - " -{ - operands[2] = negate_rtx (HImode, operands[2]); -}") - -;; define asl aslb asr asrb - ashc missing! + "* return pdp11_assemble_shift (operands, , );" + [(set_attr "length" "2,4")]) -;; asl -(define_insn "" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") - (ashift:HI (match_operand:HI 1 "general_operand" "0,0") - (const_int 1)))] +;; Next, shifts that are done as a loop on base (11/10 class) machines. +;; This applies to shift counts too large to unroll, or variable shift +;; counts. The check for count <= 0 is done before we get here. +(define_insn "_base" + [(set (match_operand:QHSint 0 "nonimmediate_operand" "=rD,Q") + (SHF:QHSint (match_operand:QHSint 1 "general_operand" "0,0") + (match_operand:HI 2 "register_operand" "r,r"))) + (clobber (match_dup 2))] "" - "asl %0" + "* return pdp11_assemble_shift (operands, , );" [(set_attr "length" "2,4")]) -;; and another possibility for asr is << -1 -;; might cause problems since -1 can also be encoded as 65535! -;; not in gcc2 ??? - -;; asr -(define_insn "" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") +;; Next the insns that use the extended instructions ash and ashc. +;; Note that these are just left shifts, and HI/SI only. (Right shifts +;; are done by shifting by a negative amount.) +(define_insn "aslhi_op" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r") (ashift:HI (match_operand:HI 1 "general_operand" "0,0") - (const_int -1)))] - "" - "asr %0" + (match_operand:HI 2 "general_operand" "rR,Q")))] + "TARGET_40_PLUS" + "ash %2, %0" [(set_attr "length" "2,4")]) -;; lsr -(define_insn "lsrhi1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") - (lshiftrt:HI (match_operand:HI 1 "general_operand" "0,0") - (const_int 1)))] - "" - "clc\;ror %0" +(define_insn "aslsi_op" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r") + (ashift:SI (match_operand:SI 1 "general_operand" "0,0") + (match_operand:HI 2 "general_operand" "rR,Q")))] + "TARGET_40_PLUS" + "ashc %2, %0" [(set_attr "length" "2,4")]) -(define_insn "lsrsi1" - [(set (match_operand:SI 0 "register_operand" "=r") - (lshiftrt:SI (match_operand:SI 1 "general_operand" "0") - (const_int 1)))] - "" -{ - - rtx lateoperands[2]; - - lateoperands[0] = operands[0]; - operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1); - - lateoperands[1] = operands[1]; - operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1); - - output_asm_insn (\"clc\", operands); - output_asm_insn (\"ror %0\", lateoperands); - output_asm_insn (\"ror %0\", operands); - - return \"\"; -} - [(set_attr "length" "10")]) - -(define_expand "lshrsi3" - [(match_operand:SI 0 "register_operand" "") - (match_operand:SI 1 "register_operand" "0") +;; Now the expanders that produce the insns defined above. +(define_expand "ashl3" + [(match_operand:QHSint 0 "nonimmediate_operand" "") + (match_operand:QHSint 1 "general_operand" "") (match_operand:HI 2 "general_operand" "")] "" " { rtx r; - if (!TARGET_40_PLUS && - (GET_CODE (operands[2]) != CONST_INT || - (unsigned) INTVAL (operands[2]) > 3)) - FAIL; - emit_insn (gen_lsrsi1 (operands[0], operands[1])); - if (GET_CODE (operands[2]) != CONST_INT) + if (!pdp11_expand_shift (operands, gen_ashift_sc, gen_ashift_base)) { - r = gen_reg_rtx (HImode); - emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1))); - emit_insn (gen_ashrsi3 (operands[0], operands[0], r)); - } - else if ((unsigned) INTVAL (operands[2]) != 1) - { - emit_insn (gen_ashlsi3 (operands[0], operands[0], - GEN_INT (1 - INTVAL (operands[2])))); + if ( == E_QImode) + { + r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1])); + emit_insn (gen_aslhi_op (r, r, operands[2])); + emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0))); + } + else + { + emit_insn (gen_asl_op (operands[0], operands[1], operands[2])); + } } DONE; -} -" -) - -;; shift is by arbitrary count is expensive, -;; shift by one cheap - so let's do that, if -;; space doesn't matter -(define_insn "" - [(set (match_operand:HI 0 "nonimmediate_operand" "=r") - (ashift:HI (match_operand:HI 1 "general_operand" "0") - (match_operand:HI 2 "expand_shift_operand" "O")))] - "! optimize_size" - "* -{ - register int i; - - for (i = 1; i <= abs(INTVAL(operands[2])); i++) - if (INTVAL(operands[2]) < 0) - output_asm_insn(\"asr %0\", operands); - else - output_asm_insn(\"asl %0\", operands); - - return \"\"; -}" -;; longest is 4 - [(set (attr "length") (const_int 8))]) - -;; aslb -(define_insn "" - [(set (match_operand:QI 0 "nonimmediate_operand" "=r,o") - (ashift:QI (match_operand:QI 1 "general_operand" "0,0") - (match_operand:HI 2 "const_int_operand" "n,n")))] - "" - "* -{ /* allowing predec or post_inc is possible, but hairy! */ - int i, cnt; - - cnt = INTVAL(operands[2]) & 0x0007; - - for (i=0 ; i < cnt ; i++) - output_asm_insn(\"aslb %0\", operands); +}") - return \"\"; -}" -;; set attribute length ( match_dup 2 & 7 ) *(1 or 2) !!! - [(set_attr_alternative "length" - [(const_int 14) - (const_int 28)])]) - -;;; asr -;(define_insn "" -; [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q") -; (ashiftrt:HI (match_operand:HI 1 "general_operand" "0,0") -; (const_int 1)))] -; "" -; "asr %0" -; [(set_attr "length" "2,4")]) - -;; asrb -(define_insn "" - [(set (match_operand:QI 0 "nonimmediate_operand" "=r,o") - (ashiftrt:QI (match_operand:QI 1 "general_operand" "0,0") - (match_operand:HI 2 "const_int_operand" "n,n")))] +(define_expand "ashr3" + [(match_operand:QHSint 0 "nonimmediate_operand" "") + (match_operand:QHSint 1 "general_operand" "") + (match_operand:HI 2 "general_operand" "")] "" - "* -{ /* allowing predec or post_inc is possible, but hairy! */ - int i, cnt; - - cnt = INTVAL(operands[2]) & 0x0007; - - for (i=0 ; i < cnt ; i++) - output_asm_insn(\"asrb %0\", operands); - - return \"\"; -}" - [(set_attr_alternative "length" - [(const_int 14) - (const_int 28)])]) - -;; the following is invalid - too complex!!! - just say 14 !!! -; [(set (attr "length") (plus (and (match_dup 2) -; (const_int 14)) -; (and (match_dup 2) -; (const_int 14))))]) - - - -;; can we get +-1 in the next pattern? should -;; have been caught by previous patterns! - -(define_insn "ashlhi3" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (ashift:HI (match_operand:HI 1 "register_operand" "0,0") - (match_operand:HI 2 "general_operand" "rR,Qi")))] - "TARGET_40_PLUS" - "* + " { - if (GET_CODE(operands[2]) == CONST_INT) + rtx r; + + if (!pdp11_expand_shift (operands, gen_ashiftrt_sc, gen_ashiftrt_base)) { - if (INTVAL(operands[2]) == 1) - return \"asl %0\"; - else if (INTVAL(operands[2]) == -1) - return \"asr %0\"; + operands[2] = negate_rtx (HImode, operands[2]); + if ( == E_QImode) + { + r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1])); + emit_insn (gen_aslhi_op (r, r, operands[2])); + emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0))); + } + else + { + emit_insn (gen_asl_op (operands[0], operands[1], operands[2])); + } } - - return \"ash %2,%0\"; -}" - [(set_attr "length" "2,4")]) - -;; Arithmetic right shift on the pdp works by negating the shift count. -(define_expand "ashrhi3" - [(set (match_operand:HI 0 "register_operand" "=r") - (ashift:HI (match_operand:HI 1 "register_operand" "0") - (match_operand:HI 2 "general_operand" "g")))] - "" - " -{ - operands[2] = negate_rtx (HImode, operands[2]); + DONE; }") -(define_expand "lshrhi3" - [(match_operand:HI 0 "register_operand" "") - (match_operand:HI 1 "register_operand" "") +(define_expand "lshr3" + [(match_operand:QHSint 0 "nonimmediate_operand" "") + (match_operand:QHSint 1 "general_operand" "") (match_operand:HI 2 "general_operand" "")] "" " { - rtx r; + rtx r, n; - if (!TARGET_40_PLUS && - (GET_CODE (operands[2]) != CONST_INT || - (unsigned) INTVAL (operands[2]) > 3)) - FAIL; - emit_insn (gen_lsrhi1 (operands[0], operands[1])); - if (GET_CODE (operands[2]) != CONST_INT) - { - r = gen_reg_rtx (HImode); - emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1))); - emit_insn (gen_ashrhi3 (operands[0], operands[0], r)); - } - else if ((unsigned) INTVAL (operands[2]) != 1) + if (!pdp11_expand_shift (operands, gen_lshiftrt_sc, gen_lshiftrt_base)) { - emit_insn (gen_ashlhi3 (operands[0], operands[0], - GEN_INT (1 - INTVAL (operands[2])))); + if ( == E_QImode) + { + r = copy_to_mode_reg (HImode, gen_rtx_ZERO_EXTEND (HImode, operands[1])); + emit_insn (gen_aslhi_op (r, r, operands[2])); + emit_insn (gen_movqi (operands[0], gen_rtx_SUBREG (QImode, r, 0))); + } + else + { + r = gen_reg_rtx (); + emit_insn (gen_lshiftrt_sc (r, operands[1], const1_rtx)); + if (GET_CODE (operands[2]) != CONST_INT) + { + n = gen_reg_rtx (HImode); + emit_insn (gen_addhi3 (n, operands [2], GEN_INT (-1))); + emit_insn (gen_ashr3 (operands[0], r, n)); + } + else + emit_insn (gen_asl_op (operands[0], r, + GEN_INT (1 - INTVAL (operands[2])))); + } } DONE; -} -" -) +}") ;; absolute -(define_insn "absdf2" +(define_insn_and_split "absdf2" [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") (abs:DF (match_operand:DF 1 "general_operand" "0,0")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (abs:DF (match_dup 1))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "absdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") + (abs:DF (match_operand:DF 1 "general_operand" "0,0"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{absd|absf} %0" [(set_attr "length" "2,4")]) - ;; negate insns -(define_insn "negdf2" - [(set (match_operand:DF 0 "float_nonimm_operand" "=fR,Q") - (neg:DF (match_operand:DF 1 "register_operand" "0,0")))] +(define_insn_and_split "negdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") + (neg:DF (match_operand:DF 1 "general_operand" "0,0")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (neg:DF (match_dup 1))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "negdf2" + [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q") + (neg:DF (match_operand:DF 1 "general_operand" "0,0"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{negd|negf} %0" [(set_attr "length" "2,4")]) -(define_insn "negdi2" +(define_insn_and_split "negdi2" [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") (neg:DI (match_operand:DI 1 "general_operand" "0,0")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (neg:DI (match_dup 1))) + (clobber (reg:CC CC_REGNUM))])] + "") + +;; TODO: this can be neg/adc/neg/adc... I believe. Check. Saves one word. +(define_insn "negdi2_nocc" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") + (neg:DI (match_operand:DI 1 "general_operand" "0,0"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" { rtx exops[4][2]; @@ -1196,10 +1502,22 @@ } [(set_attr "length" "18,34")]) -(define_insn "negsi2" +(define_insn_and_split "negsi2" [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o") (neg:SI (match_operand:SI 1 "general_operand" "0,0")))] "" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (neg:SI (match_dup 1))) + (clobber (reg:CC CC_REGNUM))])] + "") + +;; TODO: this can be neg/adc/neg/adc... I believe. Check. Saves one word. +(define_insn "negsi2_nocc" + [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o") + (neg:SI (match_operand:SI 1 "general_operand" "0,0"))) + (clobber (reg:CC CC_REGNUM))] + "reload_completed" { rtx exops[2][2]; @@ -1212,13 +1530,24 @@ return \"\"; } -[(set_attr "length" "12,20")]) +[(set_attr "length" "10,18")]) -(define_insn "neg2" +(define_insn_and_split "neg2" [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") (neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))] "" - "neg %0" + "#" + "reload_completed" + [(parallel [(set (match_dup 0) (neg:PDPint (match_dup 1))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "neg2" + [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q") + (neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0"))) + (clobber (reg:CC CC_REGNUM))] + "" + "neg %0" [(set_attr "length" "2,4")]) @@ -1229,9 +1558,9 @@ "" "* { - if (get_attr_length (insn) == 2) + if (get_attr_length (insn) == 2) return \"br %l0\"; - return \"jmp %l0\"; + return \"jmp %l0\"; }" [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 0) (pc)) @@ -1242,14 +1571,6 @@ (const_int 4) (const_int 2)))]) -(define_insn "" - [(set (pc) - (label_ref (match_operand 0 "" ""))) - (clobber (const_int 1))] - "" - "jmp %l0" - [(set_attr "length" "4")]) - (define_insn "tablejump" [(set (pc) (match_operand:HI 0 "general_operand" "r,R,Q")) (use (label_ref (match_operand 1 "" "")))] @@ -1260,22 +1581,20 @@ jmp %@%0" [(set_attr "length" "2,2,4")]) -;; indirect jump - let's be conservative! -;; allow only register_operand, even though we could also -;; allow labels etc. - +;; indirect jump. TODO: this needs a constraint that allows memory +;; references but not indirection, since we add a level of indirection +;; in the generated code. (define_insn "indirect_jump" - [(set (pc) (match_operand:HI 0 "register_operand" "r"))] + [(set (pc) (match_operand:HI 0 "general_operand" "r"))] "" - "jmp (%0)") + "jmp @%0" + [(set_attr "length" "2")]) ;;- jump to subroutine (define_insn "call" [(call (match_operand:HI 0 "general_operand" "rR,Q") - (match_operand:HI 1 "general_operand" "g,g")) -;; (use (reg:HI 0)) what was that ??? - ] + (match_operand:HI 1 "general_operand" "g,g"))] ;;- Don't use operand 1 for most machines. "" "jsr pc, %0" @@ -1285,14 +1604,38 @@ (define_insn "call_value" [(set (match_operand 0 "" "") (call (match_operand:HI 1 "general_operand" "rR,Q") - (match_operand:HI 2 "general_operand" "g,g"))) -;; (use (reg:HI 0)) - what was that ???? - ] + (match_operand:HI 2 "general_operand" "g,g")))] ;;- Don't use operand 2 for most machines. "" "jsr pc, %1" [(set_attr "length" "2,4")]) +(define_expand "untyped_call" + [(parallel [(call (match_operand 0 "" "") + (const_int 0)) + (match_operand 1 "" "") + (match_operand 2 "" "")])] + "" +{ + int i; + + emit_call_insn (gen_call (operands[0], const0_rtx)); + + for (i = 0; i < XVECLEN (operands[2], 0); i++) + { + rtx set = XVECEXP (operands[2], 0, i); + emit_move_insn (SET_DEST (set), SET_SRC (set)); + } + + /* The optimizer does not know that the call sets the function value + registers we stored in the result block. We avoid problems by + claiming that all hard registers are used and clobbered at this + point. */ + emit_insn (gen_blockage ()); + + DONE; +}) + ;;- nop instruction (define_insn "nop" [(const_int 0)] @@ -1302,124 +1645,134 @@ ;;- multiply -(define_insn "muldf3" +(define_insn_and_split "muldf3" [(set (match_operand:DF 0 "register_operand" "=a,a") (mult:DF (match_operand:DF 1 "register_operand" "%0,0") (match_operand:DF 2 "float_operand" "fR,QF")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (mult:DF (match_dup 1) (match_dup 2))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=a,a") + (mult:DF (match_operand:DF 1 "register_operand" "%0,0") + (match_operand:DF 2 "float_operand" "fR,QF"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{muld|mulf} %2, %0" [(set_attr "length" "2,4")]) -;; 16 bit result multiply: -;; currently we multiply only into odd registers, so we don't use two -;; registers - but this is a bit inefficient at times. If we define -;; a register class for each register, then we can specify properly -;; which register need which scratch register .... +;; 16 bit result multiply. This uses odd numbered registers. -(define_insn "mulhi3" +(define_insn_and_split "mulhi3" [(set (match_operand:HI 0 "register_operand" "=d,d") ; multiply regs (mult:HI (match_operand:HI 1 "register_operand" "%0,0") - (match_operand:HI 2 "float_operand" "rR,Qi")))] + (match_operand:HI 2 "general_operand" "rR,Qi")))] "TARGET_40_PLUS" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (mult:HI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] + "") + +(define_insn "mulhi3" + [(set (match_operand:HI 0 "register_operand" "=d,d") + (mult:HI (match_operand:HI 1 "register_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rR,Qi"))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_40_PLUS && reload_completed" "mul %2, %0" [(set_attr "length" "2,4")]) -;; 32 bit result -(define_expand "mulhisi3" - [(set (match_dup 3) - (match_operand:HI 1 "nonimmediate_operand" "g,g")) - (set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered! - (mult:SI (truncate:HI - (match_dup 0)) - (match_operand:HI 2 "general_operand" "rR,Qi")))] +;; 32 bit result from 16 bit operands +(define_insn_and_split "mulhisi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0")) + (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi"))))] "TARGET_40_PLUS" - "operands[3] = gen_lowpart(HImode, operands[1]);") + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) + (mult:SI (sign_extend:SI (match_dup 1)) + (sign_extend:SI (match_dup 2)))) + (clobber (reg:CC CC_REGNUM))])] + "") -(define_insn "" - [(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered! - (mult:SI (truncate:HI - (match_operand:SI 1 "register_operand" "%0,0")) - (match_operand:HI 2 "general_operand" "rR,Qi")))] - "TARGET_40_PLUS" +(define_insn "mulhisi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0,0")) + (sign_extend:SI (match_operand:HI 2 "general_operand" "rR,Qi")))) + (clobber (reg:CC CC_REGNUM))] + "TARGET_40_PLUS && reload_completed" "mul %2, %0" [(set_attr "length" "2,4")]) -;(define_insn "mulhisi3" -; [(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered! -; (mult:SI (truncate:HI -; (match_operand:SI 1 "register_operand" "%0,0")) -; (match_operand:HI 2 "general_operand" "rR,Qi")))] -; "TARGET_40_PLUS" -; "mul %2, %0" -; [(set_attr "length" "2,4")]) - ;;- divide -(define_insn "divdf3" +(define_insn_and_split "divdf3" [(set (match_operand:DF 0 "register_operand" "=a,a") (div:DF (match_operand:DF 1 "register_operand" "0,0") (match_operand:DF 2 "general_operand" "fR,QF")))] "TARGET_FPU" + "#" + "&& reload_completed" + [(parallel [(set (match_dup 0) (div:DF (match_dup 1) (match_dup 2))) + (clobber (reg:CC FCC_REGNUM))])] + "") + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=a,a") + (div:DF (match_operand:DF 1 "register_operand" "0,0") + (match_operand:DF 2 "general_operand" "fR,QF"))) + (clobber (reg:CC FCC_REGNUM))] + "TARGET_FPU && reload_completed" "{divd|divf} %2, %0" [(set_attr "length" "2,4")]) - -(define_expand "divhi3" - [(set (subreg:HI (match_dup 1) 0) +(define_expand "divmodhi4" + [(parallel + [(set (subreg:HI (match_dup 1) 0) (div:HI (match_operand:SI 1 "register_operand" "0") (match_operand:HI 2 "general_operand" "g"))) + (set (subreg:HI (match_dup 1) 2) + (mod:HI (match_dup 1) (match_dup 2)))]) (set (match_operand:HI 0 "register_operand" "=r") - (subreg:HI (match_dup 1) 0))] + (subreg:HI (match_dup 1) 0)) + (set (match_operand:HI 3 "register_operand" "=r") + (subreg:HI (match_dup 1) 2))] "TARGET_40_PLUS" "") -(define_insn "" - [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0) - (div:HI (match_operand:SI 1 "general_operand" "0") - (match_operand:HI 2 "general_operand" "g")))] - "TARGET_40_PLUS" - "div %2,%0" - [(set_attr "length" "4")]) - -(define_expand "modhi3" - [(set (subreg:HI (match_dup 1) 2) - (mod:HI (match_operand:SI 1 "register_operand" "0") - (match_operand:HI 2 "general_operand" "g"))) - (set (match_operand:HI 0 "register_operand" "=r") - (subreg:HI (match_dup 1) 2))] +(define_insn_and_split "*divmodhi4" + [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0) + (div:HI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:HI 2 "general_operand" "rR,Qi"))) + (set (subreg:HI (match_dup 1) 2) + (mod:HI (match_dup 1) (match_dup 2)))] "TARGET_40_PLUS" + "#" + "&& reload_completed" + [(parallel [(set (subreg:HI (match_dup 0) 0) + (div:HI (match_dup 1) (match_dup 2))) + (set (subreg:HI (match_dup 1) 2) + (mod:HI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))])] "") -(define_insn "" - [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 2) - (mod:HI (match_operand:SI 1 "general_operand" "0") - (match_operand:HI 2 "general_operand" "g")))] +;; Note that there is no corresponding CC setter pattern. +;; The reason is that it won't be generated, because +;; compare-elim.c only does the transformation on input +;; insns that have a two-element PARALLEL, as opposed to +;; the three-element one we have here. +(define_insn "divmodhi4_nocc" + [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r,r") 0) + (div:HI (match_operand:SI 1 "register_operand" "0,0") + (match_operand:HI 2 "general_operand" "rR,Qi"))) + (set (subreg:HI (match_dup 1) 2) + (mod:HI (match_dup 1) (match_dup 2))) + (clobber (reg:CC CC_REGNUM))] "TARGET_40_PLUS" - "div %2,%0" - [(set_attr "length" "4")]) - -;(define_expand "divmodhi4" -; [(parallel [(set (subreg:HI (match_dup 1) 0) -; (div:HI (match_operand:SI 1 "register_operand" "0") -; (match_operand:HI 2 "general_operand" "g"))) -; (set (subreg:HI (match_dup 1) 2) -; (mod:HI (match_dup 1) -; (match_dup 2)))]) -; (set (match_operand:HI 3 "register_operand" "=r") -; (subreg:HI (match_dup 1) 2)) -; (set (match_operand:HI 0 "register_operand" "=r") -; (subreg:HI (match_dup 1) 0))] -; "TARGET_40_PLUS" -; "") -; -;(define_insn "" -; [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0) -; (div:HI (match_operand:SI 1 "general_operand" "0") -; (match_operand:HI 2 "general_operand" "g"))) -; (set (subreg:HI (match_dup 0) 2) -; (mod:HI (match_dup 1) -; (match_dup 2)))] -; "TARGET_40_PLUS" -; "div %2, %0") -; - -;; is rotate doing the right thing to be included here ???? + "div %2,%0" + [(set_attr "length" "2,4")]) diff --git a/gcc/config/pdp11/pdp11.opt b/gcc/config/pdp11/pdp11.opt index 0a1eb223416..feebcc674fa 100644 --- a/gcc/config/pdp11/pdp11.opt +++ b/gcc/config/pdp11/pdp11.opt @@ -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. diff --git a/gcc/config/pdp11/predicates.md b/gcc/config/pdp11/predicates.md index d489a043396..eed711f7281 100644 --- a/gcc/config/pdp11/predicates.md +++ b/gcc/config/pdp11/predicates.md @@ -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")) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 1014022d6bc..df4c55fdefb 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index a3ecb711eca..22919e4310c 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -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. -- 2.30.2