#include "expr.h"
#include "builtins.h"
#include "dbxout.h"
+#include "expmed.h"
/* This file should be included last. */
#include "target-def.h"
(*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);
emit_move_insn (reg, x);
else
{
- emit_move_insn (via_ac, x);
+ emit_move_insn (via_ac, x);
emit_move_insn (reg, via_ac);
}
}
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,
return false;
case ASHIFT:
- case LSHIFTRT:
case ASHIFTRT:
if (optimize_size)
*total = COSTS_N_INSNS (1);
}
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;
+ }
}
}
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;
}
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,
/* 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)
{
{
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)
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)
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 ?
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)
{
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
/* 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
;; 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:
-\f
;; Compare instructions.
;; currently we only support df floats, which saves us quite some
;; 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
;; 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
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)
"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 \"\";
}"
;; 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))
(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))
(const_int MAX_BRANCH)))
(const_int 6)
(const_int 2)))])
+
\f
;; Move instructions
[(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")])
[(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")])
[(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)
}"
[(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 ...
(clobber (match_dup 4))
(clobber (match_dup 5))
(clobber (match_dup 2))])]
- "(TARGET_BCOPY_BUILTIN)"
+ ""
"
{
operands[0]
}")
-(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"))
(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")])
\f
;;- 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")])
\f
;;- 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")])
\f
;;- 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];
}"
[(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);
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);
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")])
;;- 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];
;; 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];
}"
[(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)
;; 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];
}"
[(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];
}"
[(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\";
}"
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];
}
[(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];
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")])
""
"*
{
- 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))
(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 "" "")))]
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"
(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)]
;;- 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")])