aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/pdp11
diff options
context:
space:
mode:
authorPaul Koning <ni1d@arrl.net>2018-06-27 17:58:24 -0400
committerPaul Koning <pkoning@gcc.gnu.org>2018-06-27 17:58:24 -0400
commitb4324a144b4499725143baf1f69722f92814572e (patch)
treeed5e61eed2d97171a207721de22310cec011d782 /gcc/config/pdp11
parent356d53635faecee4b8abfc6b21208432c72eebff (diff)
downloadgcc-b4324a144b4499725143baf1f69722f92814572e.zip
gcc-b4324a144b4499725143baf1f69722f92814572e.tar.gz
gcc-b4324a144b4499725143baf1f69722f92814572e.tar.bz2
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
Diffstat (limited to 'gcc/config/pdp11')
-rw-r--r--gcc/config/pdp11/constraints.md15
-rw-r--r--gcc/config/pdp11/pdp11-modes.def22
-rw-r--r--gcc/config/pdp11/pdp11-protos.h13
-rw-r--r--gcc/config/pdp11/pdp11.c559
-rw-r--r--gcc/config/pdp11/pdp11.h142
-rw-r--r--gcc/config/pdp11/pdp11.md1439
-rw-r--r--gcc/config/pdp11/pdp11.opt16
-rw-r--r--gcc/config/pdp11/predicates.md15
8 files changed, 1396 insertions, 825 deletions
diff --git a/gcc/config/pdp11/constraints.md b/gcc/config/pdp11/constraints.md
index 0d78dd8..10bf120 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
;; <http://www.gnu.org/licenses/>.
+(define_register_constraint "a" "LOAD_FPU_REGS"
+ "FPU register that can be directly loaded from memory")
+
(define_register_constraint "f" "FPU_REGS"
"Any FPU register")
-(define_register_constraint "a" "LOAD_FPU_REGS"
- "FPU register that can be directly loaded from memory")
+(define_register_constraint "h" "NO_LOAD_FPU_REGS"
+ "FPU register that cannot be directly loaded from memory")
(define_register_constraint "d" "MUL_REGS"
"General register that can be used for 16-bit multiply (odd numbered)")
@@ -60,7 +63,7 @@
(define_constraint "O"
"Integer constant for which several individual shifts are better than one big one"
(and (match_code "const_int")
- (match_test "abs (ival) > 1 && abs (ival) <= 4")))
+ (match_test "pdp11_small_shift (ival)")))
(define_constraint "G"
"Defines a real zero constant."
@@ -79,3 +82,9 @@
(match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
&& simple_memory_operand (op, GET_MODE (op))")))
+(define_constraint "D"
+ "Memory reference that is encoded within the opcode, and not push or pop"
+ (and (match_code "mem")
+ (match_test "memory_address_p (GET_MODE (op), XEXP (op, 0))
+ && no_side_effect_operand (op, GET_MODE (op))")))
+
diff --git a/gcc/config/pdp11/pdp11-modes.def b/gcc/config/pdp11/pdp11-modes.def
index a49994a..164889e 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
<http://www.gnu.org/licenses/>. */
/* Add any extra modes needed to represent the condition code.
- CCFPmode is used for FPU, but should we use a separate reg? */
-CC_MODE (CCFP);
+ The default CCmode is the CPU condition codes, as set by compare;
+ all conditional branches are valid with this.
+
+ CCNZmode is the CPU condition code as a side effect of arithmetic
+ or logic operations where N and Z reflect sign and zero status of
+ the result, but the V bit is not meaningful. Unsigned conditional
+ branches don't apply then (no such thing when comparing with zero)
+ and signed branches that use V need to clear V first if they are to
+ be used. CCNZ mode appears in side effects (implicit compare with
+ zero) if V is not forced to 0 by the instruction. In such cases, V
+ often reflects signed overflow of the operation, which means a
+ signed branch will get the sign backwards. This applies both to
+ some float and integer operations.
+
+ These modes are used both in the FPU and the CPU, since they have
+ the same meaning, and also because the FPU condition codes are
+ copied to the CPU before being used in conditional branches. */
+
+CC_MODE (CCNZ);
+
RESET_FLOAT_FORMAT (SF, pdp11_f_format);
RESET_FLOAT_FORMAT (DF, pdp11_d_format);
diff --git a/gcc/config/pdp11/pdp11-protos.h b/gcc/config/pdp11/pdp11-protos.h
index c5096b0..4536323 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 38c55fb..ab73693 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 af92a79..f995bc8 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
@@ -447,54 +491,6 @@ extern int may_call_alloca;
/* #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. */
/* Output to assembler file text saying following lines
@@ -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 4f4a5d2..1dd069f 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<mode>"
- [(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<mode>"
+ [(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<PDPint:isfx> %0
@@ -191,8 +240,7 @@
cmp<PDPint:isfx> %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 "cbranch<mode>4"
- [(set (cc0)
- (compare (match_operand:PDPint 1 "general_operand")
- (match_operand:PDPint 2 "general_operand")))
- (set (pc)
+(define_insn_and_split "cbranch<mode>4"
+ [(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<mode>_<cc_cc>"
+ [(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<fcc_cc>"
+ [(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<fcc_ccnz>"
+ [(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_<fcc_cc>"
+ [(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<cc_cc>"
+ [(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_<fcc_cc>"
+ [(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<cc_cc>"
+ [(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<fcc_cc>"
+ [(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<fcc_cc>"
+ [(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<fcc_ccnz>"
+ [(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<cc_ccnz>"
+ [(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<fcc_ccnz>"
+ [(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<cc_ccnz>"
+ [(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>mode, one_cmpl_optab, op1, 0, 1);
}")
-(define_insn "*bic<mode>"
+(define_insn_and_split "*bic<mode>"
[(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<mode><cc_cc>"
+ [(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<PDPint:isfx> %1, %0"
[(set_attr "length" "2,4,4,6")])
;;- Bit set (inclusive or) instructions
-(define_insn "ior<mode>3"
+(define_insn_and_split "ior<mode>3"
[(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 "ior<mode>3<cc_cc>"
+ [(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<PDPint:isfx> %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<cc_cc>"
+ [(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_cmpl<mode>2"
+(define_insn_and_split "one_cmpl<mode>2"
[(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_cmpl<mode>2<cc_cc>"
+ [(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<PDPint:isfx> %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 "<code><mode>_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, <QHSint:mname>, <CODE>);"
+ [(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 "<code><mode>_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, <QHSint:mname>, <CODE>);"
[(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 "ashl<mode>3"
+ [(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<mode>_sc, gen_ashift<mode>_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 (<QHSint:e_mname> == 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<QHSint:hmode>_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 "ashr<mode>3"
+ [(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<mode>_sc, gen_ashiftrt<mode>_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 (<QHSint:e_mname> == 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<QHSint:hmode>_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 "lshr<mode>3"
+ [(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<mode>_sc, gen_lshiftrt<mode>_base))
{
- emit_insn (gen_ashlhi3 (operands[0], operands[0],
- GEN_INT (1 - INTVAL (operands[2]))));
+ if (<QHSint:e_mname> == 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 (<QHSint:mname>);
+ emit_insn (gen_lshiftrt<mode>_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_ashr<mode>3 (operands[0], r, n));
+ }
+ else
+ emit_insn (gen_asl<QHSint:hmode>_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<fcc_cc>"
+ [(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<fcc_cc>"
+ [(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 "neg<mode>2"
+(define_insn_and_split "neg<mode>2"
[(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
(neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
""
- "neg<isfx> %0"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 0) (neg:PDPint (match_dup 1)))
+ (clobber (reg:CC CC_REGNUM))])]
+ "")
+
+(define_insn "neg<mode>2<cc_ccnz>"
+ [(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<PDPint:isfx> %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<fcc_ccnz>"
+ [(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<cc_cc>"
+ [(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<cc_cc>"
+ [(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<fcc_ccnz>"
+ [(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 0a1eb22..feebcc6 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 d489a04..eed711f 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"))