gcc-papermario/config/pdp11/pdp11.md
2020-09-20 21:06:00 -04:00

49 KiB
Raw Blame History

;;- Machine description for the pdp11 for GNU C compiler ;; Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc. ;; Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).

;; This file is part of GNU CC.

;; GNU CC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 1, or (at your option) ;; any later version.

;; GNU CC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License ;; along with GNU CC; see the file COPYING. If not, write to ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.

;; HI is 16 bit ;; QI is 8 bit

;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.

;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code ;;- updates for most instructions.

;;- Operand classes for the register allocator: ;; Compare instructions.

;; currently we only support df floats, which saves us quite some ;; hassle switching the FP mode! ;; we assume that CPU is always in long float mode, and ;; 16 bit integer mode - currently, the prologue for main does this, ;; but maybe we should just set up a NEW crt0 properly, ;; -- and what about signal handling code? ;; (we don't even let sf floats in the register file, so ;; we only should have to worry about truncating and widening ;; when going to memory)

;; abort() call by g++ - must define libfunc for cmp_optab ;; 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 (define_attr "type" "unknown,arith,fp" (const_string "arith"))

;; length default is 1 word each (define_attr "length" "" (const_int 1))

;; a user's asm statement (define_asm_attributes [(set_attr "type" "unknown") ; all bets are off how long it is - make it 256, forces long jumps ; whenever jumping around it !!! (set_attr "length" "256")])

;; define function units

;; arithmetic - values here immediately when next insn issued ;; or does it mean the number of cycles after this insn was issued? ;; how do I say that fpu insns use cpu also? (pre-interaction phase)

;(define_function_unit "cpu" 1 1 (eq_attr "type" "arith") 0 0) ;(define_function_unit "fpu" 1 1 (eq_attr "type" "fp") 0 0)

;; compare (define_insn "cmpdf" [(set (cc0) (compare (match_operand:DF 0 "general_operand" "fR,Q,F") (match_operand:DF 1 "register_operand" "a,a,a")))] "TARGET_FPU" "* { cc_status.flags = CC_IN_FPU; return "cmpd %0, %1;cfcc"; }" [(set_attr "length" "2,3,6")])

;; a bit of brain damage, maybe inline later - ;; problem is - gcc seems to NEED SImode because ;; of the cmp weirdness - maybe change gcc to handle this?

(define_expand "cmpsi" [(set (reg:SI 0) (match_operand:SI 0 "general_operand" "g")) (set (reg:SI 2) (match_operand:SI 1 "general_operand" "g")) (parallel [(set (cc0) (compare (reg:SI 0) (reg:SI 2))) (clobber (reg:SI 0))])] "0" ;; disable for test "")

;; check for next insn for branch code - does this still ;; work in gcc 2.* ?

(define_insn "" [(set (cc0) (compare (reg:SI 0) (reg:SI 2))) (clobber (reg:SI 0))] "" "* { rtx br_insn = NEXT_INSN (insn); RTX_CODE br_code;

if (GET_CODE (br_insn) != JUMP_INSN) abort(); br_code = GET_CODE (XEXP (XEXP (PATTERN (br_insn), 1), 0));

switch(br_code) { case GEU: case LTU: case GTU: case LEU:

  return \"jsr pc, ___ucmpsi\;cmp $1,r0\";

case GE:
case LT:
case GT:
case LE:
case EQ:
case NE:

  return \"jsr pc, ___cmpsi\;tst r0\";

default:

  abort();

} }" [(set_attr "length" "4")])

(define_insn "cmphi" [(set (cc0) (compare (match_operand:HI 0 "general_operand" "rR,rR,Qi,Qi") (match_operand:HI 1 "general_operand" "rR,Qi,rR,Qi")))] "" "cmp %0,%1" [(set_attr "length" "1,2,2,3")])

(define_insn "cmpqi" [(set (cc0) (compare (match_operand:QI 0 "general_operand" "rR,rR,Qi,Qi") (match_operand:QI 1 "general_operand" "rR,Qi,rR,Qi")))] "" "cmpb %0,%1" [(set_attr "length" "1,2,2,3")])

;; We have to have this because cse can optimize the previous pattern ;; into this one.

(define_insn "tstdf" [(set (cc0) (match_operand:DF 0 "general_operand" "fR,Q"))] "TARGET_FPU" "* { cc_status.flags = CC_IN_FPU; return "tstd %0;cfcc"; }" [(set_attr "length" "2,3")])

(define_expand "tstsi" [(set (reg:SI 0) (match_operand:SI 0 "general_operand" "g")) (parallel [(set (cc0) (reg:SI 0)) (clobber (reg:SI 0))])] "0" ;; disable for test "")

(define_insn "" [(set (cc0) (reg:SI 0)) (clobber (reg:SI 0))] "" "jsr pc, ___tstsi;tst r0" [(set_attr "length" "3")])

(define_insn "tsthi" [(set (cc0) (match_operand:HI 0 "general_operand" "rR,Q"))] "" "tst %0" [(set_attr "length" "1,2")])

(define_insn "tstqi" [(set (cc0) (match_operand:QI 0 "general_operand" "rR,Q"))] "" "tstb %0" [(set_attr "length" "1,2")])

;; sob instruction - we need an assembler which can make this instruction ;; valid under all circumstances!

(define_insn "" [(set (pc) (if_then_else (ne (plus:HI (match_operand:HI 0 "register_operand" "r") (const_int -1)) (const_int 0)) (label_ref (match_operand 1 "" "")) (pc))) (set (match_dup 0) (plus:HI (match_dup 0) (const_int -1)))] "TARGET_40_PLUS" "* { static int labelcount = 0; static char buf[1000];

if (get_attr_length (insn) == 1) return "sob %0, %l1";

/* emulate sob */ output_asm_insn ("dec %0", operands);

sprintf (buf, "bge LONG_SOB%d", labelcount); output_asm_insn (buf, NULL);

output_asm_insn ("jmp %l1", operands);

sprintf (buf, "LONG_SOB%d:", labelcount++); output_asm_insn (buf, NULL);

return ""; }" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -256)) (ge (minus (match_dup 0) (pc)) (const_int 0))) (const_int 4) (const_int 1)))])

;; These control RTL generation for conditional jump insns ;; and match them for register allocation.

;; 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

(define_insn "beq" [(set (pc) (if_then_else (eq (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("beq", "bne", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "bne" [(set (pc) (if_then_else (ne (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("bne", "beq", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "bgt" [(set (pc) (if_then_else (gt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("bgt", "ble", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "bgtu" [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("bhi", "blos", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "blt" [(set (pc) (if_then_else (lt (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("blt", "bge", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "bltu" [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("blo", "bhis", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "bge" [(set (pc) (if_then_else (ge (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("bge", "blt", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "bgeu" [(set (pc) (if_then_else (geu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("bhis", "blo", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "ble" [(set (pc) (if_then_else (le (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("ble", "bgt", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "bleu" [(set (pc) (if_then_else (leu (cc0) (const_int 0)) (label_ref (match_operand 0 "" "")) (pc)))] "" "* return output_jump("blos", "bhi", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

;; These match inverted jump insns for register allocation.

(define_insn "" [(set (pc) (if_then_else (eq (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("bne", "beq", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (ne (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("beq", "bne", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (gt (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("ble", "bgt", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("blos", "bhi", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (lt (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("bge", "blt", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("bhis", "blo", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (ge (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] ""
"* return output_jump("blt", "bge", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (geu (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("blo", "bhis", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (le (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("bgt", "ble", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))])

(define_insn "" [(set (pc) (if_then_else (leu (cc0) (const_int 0)) (pc) (label_ref (match_operand 0 "" ""))))] "" "* return output_jump("bhi", "blos", get_attr_length(insn));" [(set (attr "length") (if_then_else (ior (le (minus (match_dup 0) (pc)) (const_int -128)) (ge (minus (match_dup 0) (pc)) (const_int 128))) (const_int 3) (const_int 1)))]) ;; Move instructions

(define_insn "movdi" [(set (match_operand:DI 0 "general_operand" "=g") (match_operand:DI 1 "general_operand" "g"))] "" "* return output_move_quad (operands);" ;; what's the mose expensive code - say twice movsi = 16 [(set_attr "length" "16")])

(define_insn "movsi" [(set (match_operand:SI 0 "general_operand" "=r,r,r,rm,m") (match_operand:SI 1 "general_operand" "rN,IJ,K,m,r"))] "" "* return output_move_double (operands);" ;; what's the most expensive code ? - I think 8! ;; we could split it up and make several sub-cases... [(set_attr "length" "2,3,4,8,8")])

(define_insn "movhi" [(set (match_operand:HI 0 "general_operand" "=rR,rR,Q,Q") (match_operand:HI 1 "general_operand" "rRN,Qi,rRN,Qi"))] "" "* { if (operands[1] == const0_rtx) return "clr %0";

return "mov %1, %0"; }" [(set_attr "length" "1,2,2,3")])

(define_insn "movqi" [(set (match_operand:QI 0 "general_operand" "=rR,rR,Q,Q") (match_operand:QI 1 "general_operand" "rRN,Qi,rRN,Qi"))] "" "* { if (operands[1] == const0_rtx) return "clrb %0";

return "movb %1, %0"; }" [(set_attr "length" "1,2,2,3")])

;; do we have to supply all these moves? e.g. to ;; NO_LOAD_FPU_REGs ? (define_insn "movdf" [(set (match_operand:DF 0 "general_operand" "=f,R,f,Q,f,m") (match_operand:DF 1 "general_operand" "fR,f,Q,f,F,m"))] "" "* return output_move_quad (operands);" ;; just a guess.. [(set_attr "length" "1,1,2,2,5,16")])

(define_insn "movsf" [(set (match_operand:SF 0 "general_operand" "=g,r,g") (match_operand:SF 1 "general_operand" "r,rmF,g"))] "TARGET_FPU" "* return output_move_double (operands);" [(set_attr "length" "8,8,8")])

;; maybe fiddle a bit with move_ratio, then ;; let constraints only accept a register ...

(define_expand "movstrhi" [(parallel [(set (match_operand:BLK 0 "general_operand" "=g,g") (match_operand:BLK 1 "general_operand" "g,g")) (use (match_operand:HI 2 "arith_operand" "n,&mr")) (use (match_operand:HI 3 "immediate_operand" "i,i")) (clobber (match_scratch:HI 4 "=&r,X")) (clobber (match_dup 5)) (clobber (match_dup 6)) (clobber (match_dup 2))])] "(TARGET_BCOPY_BUILTIN)" " { operands[0] = change_address (operands[0], VOIDmode, copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); operands[1] = change_address (operands[1], VOIDmode, copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));

operands[5] = XEXP (operands[0], 0); operands[6] = XEXP (operands[1], 0); }")

(define_insn "" ; "movstrhi" [(set (mem:BLK (match_operand:HI 0 "general_operand" "=r,r")) (mem:BLK (match_operand:HI 1 "general_operand" "r,r"))) (use (match_operand:HI 2 "arith_operand" "n,&r")) (use (match_operand:HI 3 "immediate_operand" "i,i")) (clobber (match_scratch:HI 4 "=&r,X")) (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" "40")])

;;- truncation instructions

(define_insn "truncdfsf2" [(set (match_operand:SF 0 "general_operand" "=r,R,Q") (float_truncate:SF (match_operand:DF 1 "register_operand" "a,a,a")))] "TARGET_FPU" "* if (which_alternative ==0) { output_asm_insn("stcdf %1, -(sp)", operands); output_asm_insn("mov (sp)+, %0", operands); operands[0] = gen_rtx(REG, HImode, REGNO (operands[0])+1); output_asm_insn("mov (sp)+, %0", operands); return ""; } else if (which_alternative == 1) return "stcdf %1, %0"; else return "stcdf %1, %0"; " [(set_attr "length" "3,1,2")])

(define_expand "truncsihi2" [(set (match_operand:HI 0 "general_operand" "=g") (subreg:HI (match_operand:SI 1 "general_operand" "or") 0))] "" "")

;;- zero extension instructions

(define_insn "zero_extendqihi2" [(set (match_operand:HI 0 "general_operand" "=r") (zero_extend:HI (match_operand:QI 1 "general_operand" "0")))] "" "bic $(256*255), %0" [(set_attr "length" "2")])

(define_expand "zero_extendhisi2" [(set (subreg:HI (match_dup 0) 1) (match_operand:HI 1 "register_operand" "r")) (set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0) (const_int 0))] "" "/* operands[1] = make_safe_from (operands[1], operands[0]); */")

;;- sign extension instructions

(define_insn "extendsfdf2" [(set (match_operand:DF 0 "register_operand" "=a,a,a") (float_extend:SF (match_operand:SF 1 "general_operand" "r,R,Q")))] "TARGET_FPU" "@ mov %1, -(sp);ldcfd (sp)+,%0 ldcfd %1, %0 ldcfd %1, %0" [(set_attr "length" "2,1,2")])

;; does movb sign extend in register-to-register move? (define_insn "extendqihi2" [(set (match_operand:HI 0 "register_operand" "=r,r") (sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))] "" "movb %1, %0" [(set_attr "length" "1,2")])

(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" "2,3")])

;; 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 "general_operand" "=g") (sign_extend:SI (match_operand:HI 1 "general_operand" "g")))] "" "")

(define_insn "" ; "extendhisi2" [(set (match_operand:SI 0 "general_operand" "=o,<,r") (sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))] "TARGET_40_PLUS" "* { rtx latehalf[2];

/* we don't want to mess with auto increment */

switch(which_alternative) { case 0:

  latehalf[0] = operands[0];
  operands[0] = adj_offsettable_operand(operands[0], 2);

  output_asm_insn(\"mov %1, %0\", operands);
  output_asm_insn(\"sxt %0\", latehalf);

  return \"\";

case 1:

  /* - auto-decrement - right direction ;-) */
  output_asm_insn(\"mov %1, %0\", operands);
  output_asm_insn(\"sxt %0\", operands);

  return \"\";

case 2:

  /* make register pair available */
  latehalf[0] = operands[0];
  operands[0] = gen_rtx(REG, HImode, REGNO (operands[0])+1);

  output_asm_insn(\"mov %1, %0\", operands);
  output_asm_insn(\"sxt %0\", latehalf);

  return \"\";

default:

  abort();

} }" [(set_attr "length" "5,3,3")])

(define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (sign_extend:SI (match_operand:HI 1 "general_operand" "0")))] "(! TARGET_40_PLUS)" "* { static 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" "6")])

;; 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" [(set (match_operand:DF 0 "register_operand" "=a,a,a") (float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))] "TARGET_FPU" "* if (which_alternative ==0) { rtx latehalf[2];

   latehalf[0] = NULL; 
   latehalf[1] = gen_rtx(REG, HImode, REGNO (operands[0])+1);
   output_asm_insn(\"mov %1, -(sp)\", latehalf);
   output_asm_insn(\"mov %1, -(sp)\", operands);
   
   output_asm_insn(\"setl\", operands);
   output_asm_insn(\"ldcld (sp)+, %0\", operands);
   output_asm_insn(\"seti\", operands);
   return \"\";
 }
 else if (which_alternative == 1)
   return \"setl\;ldcld %1, %0\;seti\";
 else 
   return \"setl\;ldcld %1, %0\;seti\";

" [(set_attr "length" "5,3,4")])

(define_insn "floathidf2" [(set (match_operand:DF 0 "register_operand" "=a,a") (float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))] "TARGET_FPU" "ldcid %1, %0" [(set_attr "length" "1,2")])

;; cut float to int (define_insn "fix_truncdfsi2" [(set (match_operand:SI 0 "general_operand" "=r,R,Q") (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))] "TARGET_FPU" "* if (which_alternative ==0) { output_asm_insn("setl", operands); output_asm_insn("stcdl %1, -(sp)", operands); output_asm_insn("seti", operands); output_asm_insn("mov (sp)+, %0", operands); operands[0] = gen_rtx(REG, HImode, REGNO (operands[0])+1); output_asm_insn("mov (sp)+, %0", operands); return ""; } else if (which_alternative == 1) return "setl;stcdl %1, %0;seti"; else return "setl;stcdl %1, %0;seti"; " [(set_attr "length" "5,3,4")])

(define_insn "fix_truncdfhi2" [(set (match_operand:HI 0 "general_operand" "=rR,Q") (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))] "TARGET_FPU" "stcdi %1, %0" [(set_attr "length" "1,2")])

;;- arithmetic instructions ;;- add instructions

(define_insn "adddf3" [(set (match_operand:DF 0 "register_operand" "=a,a,a") (plus:DF (match_operand:DF 1 "register_operand" "%0,0,0") (match_operand:DF 2 "general_operand" "fR,Q,F")))] "TARGET_FPU" "addd %2, %0" [(set_attr "length" "1,2,5")])

(define_insn "addsi3" [(set (match_operand:SI 0 "general_operand" "=r,r,o,o,r,r,r,o,o,o") (plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0,0,0,0,0,0,0") (match_operand:SI 2 "general_operand" "r,o,r,o,I,J,K,I,J,K")))] "" "* { /* Here we trust that operands don't overlap

 or is lateoperands the low word?? - looks like it! */

unsigned int i; rtx lateoperands[3];

lateoperands[0] = operands[0];

if (REG_P (operands[0])) operands[0] = gen_rtx(REG, HImode, REGNO(operands[0]) + 1); else operands[0] = adj_offsettable_operand (operands[0], 2);

if (! CONSTANT_P(operands[2])) { lateoperands[2] = operands[2];

if (REG_P (operands[2]))
  operands[2] = gen_rtx(REG, HImode, REGNO(operands[2]) + 1);
else
  operands[2] = adj_offsettable_operand(operands[2], 2);

output_asm_insn (\"add %2, %0\", operands);
output_asm_insn (\"adc %0\", lateoperands);
output_asm_insn (\"add %2, %0\", lateoperands);
return \"\";

}

lateoperands[2] = gen_rtx(CONST_INT, VOIDmode, (INTVAL(operands[2]) >> 16) & 0xffff); operands[2] = gen_rtx(CONST_INT, VOIDmode, INTVAL(operands[2]) & 0xffff);

if (INTVAL(operands[2])) { output_asm_insn ("add %2, %0", operands); output_asm_insn ("adc %0", lateoperands); }

if (INTVAL(lateoperands[2])) output_asm_insn ("add %2, %0", lateoperands);

return ""; }" [(set_attr "length" "3,5,6,8,3,1,5,5,3,8")])

(define_insn "addhi3" [(set (match_operand:HI 0 "general_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")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT) if (INTVAL(operands[2]) == 1) return "inc %0"; else if (INTVAL(operands[2]) == -1) return "dec %0";

return "add %2, %0"; }" [(set_attr "length" "1,2,2,3")])

(define_insn "addqi3" [(set (match_operand:QI 0 "general_operand" "=rR,rR,Q,Q") (plus:QI (match_operand:QI 1 "general_operand" "%0,0,0,0") (match_operand:QI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT) if (INTVAL(operands[2]) == 1) return "incb %0"; else if (INTVAL(operands[2]) == -1) return "decb %0";

return "addb %2, %0"; }" [(set_attr "length" "1,2,2,3")])

;;- subtract instructions ;; we don't have to care for constant second ;; args, since they are canonical plus:xx now! ;; also for minus:DF ??

(define_insn "subdf3" [(set (match_operand:DF 0 "register_operand" "=a,a") (minus:DF (match_operand:DF 1 "register_operand" "0,0") (match_operand:DF 2 "general_operand" "fR,Q")))] "TARGET_FPU" "subd %2, %0" [(set_attr "length" "1,2")])

(define_insn "subsi3" [(set (match_operand:SI 0 "general_operand" "=r,r,o,o") (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") (match_operand:SI 2 "general_operand" "r,o,r,o")))] "" "* { /* Here we trust that operands don't overlap

 or is lateoperands the low word?? - looks like it! */

unsigned int i; rtx lateoperands[3];

lateoperands[0] = operands[0];

if (REG_P (operands[0])) operands[0] = gen_rtx(REG, HImode, REGNO(operands[0]) + 1); else operands[0] = adj_offsettable_operand (operands[0], 2);

lateoperands[2] = operands[2];

if (REG_P (operands[2])) operands[2] = gen_rtx(REG, HImode, REGNO(operands[2]) + 1); else operands[2] = adj_offsettable_operand(operands[2], 2);

output_asm_insn ("sub %2, %0", operands); output_asm_insn ("sbc %0", lateoperands); output_asm_insn ("sub %2, %0", lateoperands); return ""; }" ;; offsettable memory addresses always are expensive!!! [(set_attr "length" "3,5,6,8")])

(define_insn "subhi3" [(set (match_operand:HI 0 "general_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")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT) abort();

return "sub %2, %0"; }" [(set_attr "length" "1,2,2,3")])

(define_insn "subqi3" [(set (match_operand:QI 0 "general_operand" "=rR,rR,Q,Q") (minus:QI (match_operand:QI 1 "general_operand" "0,0,0,0") (match_operand:QI 2 "general_operand" "rR,Qi,rR,Qi")))] "" "* { if (GET_CODE (operands[2]) == CONST_INT) abort();

return "subb %2, %0"; }" [(set_attr "length" "1,2,2,3")])

;;;;- and instructions ;; Bit-and on the pdp (like on the vax) is done with a clear-bits insn. (define_expand "andsi3" [(set (match_operand:SI 0 "general_operand" "=g") (and:SI (match_operand:SI 1 "general_operand" "0") (not:SI (match_operand:SI 2 "general_operand" "g"))))] "" " { extern rtx expand_unop (); if (GET_CODE (operands[2]) == CONST_INT) operands[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); else operands[2] = expand_unop (SImode, one_cmpl_optab, operands[2], 0, 1); }")

(define_expand "andhi3" [(set (match_operand:HI 0 "general_operand" "=g") (and:HI (match_operand:HI 1 "general_operand" "0") (not:HI (match_operand:HI 2 "general_operand" "g"))))] "" " { extern rtx expand_unop (); if (GET_CODE (operands[2]) == CONST_INT) operands[2] = gen_rtx (CONST_INT, VOIDmode, ~INTVAL (operands[2])); else operands[2] = expand_unop (HImode, one_cmpl_optab, operands[2], 0, 1); }")

(define_expand "andqi3" [(set (match_operand:QI 0 "general_operand" "=g") (and:QI (match_operand:QI 1 "general_operand" "0") (not:QI (match_operand:QI 2 "general_operand" "g"))))] "" " { extern rtx expand_unop (); rtx op = operands[2]; if (GET_CODE (op) == CONST_INT) operands[2] = gen_rtx (CONST_INT, VOIDmode, ((1 << 8) - 1) & ~INTVAL (op)); else operands[2] = expand_unop (QImode, one_cmpl_optab, op, 0, 1); }")

(define_insn "andcbsi3" [(set (match_operand:SI 0 "general_operand" "=r,r,o,o,r,r,r,o,o,o") (and:SI (match_operand:SI 1 "general_operand" "%0,0,0,0,0,0,0,0,0,0") (not:SI (match_operand:SI 2 "general_operand" "r,o,r,o,I,J,K,I,J,K"))))] "" "* { /* Here we trust that operands don't overlap

 or is lateoperands the low word?? - looks like it! */

unsigned int i; rtx lateoperands[3];

lateoperands[0] = operands[0];

if (REG_P (operands[0])) operands[0] = gen_rtx(REG, HImode, REGNO(operands[0]) + 1); else operands[0] = adj_offsettable_operand (operands[0], 2);

if (! CONSTANT_P(operands[2])) { lateoperands[2] = operands[2];

if (REG_P (operands[2]))
  operands[2] = gen_rtx(REG, HImode, REGNO(operands[2]) + 1);
else
  operands[2] = adj_offsettable_operand(operands[2], 2);

output_asm_insn (\"bic %2, %0\", operands);
output_asm_insn (\"bic %2, %0\", lateoperands);
return \"\";

}

lateoperands[2] = gen_rtx(CONST_INT, VOIDmode, (INTVAL(operands[2]) >> 16) & 0xffff); operands[2] = gen_rtx(CONST_INT, VOIDmode, INTVAL(operands[2]) & 0xffff);

/* these have different lengths, so we should have different constraints! */ if (INTVAL(operands[2])) output_asm_insn ("bic %2, %0", operands);

if (INTVAL(lateoperands[2])) output_asm_insn ("bic %2, %0", lateoperands);

return ""; }" [(set_attr "length" "2,4,4,6,2,2,4,3,3,6")])

(define_insn "andcbhi3" [(set (match_operand:HI 0 "general_operand" "=rR,rR,Q,Q") (and:HI (match_operand:HI 1 "general_operand" "0,0,0,0") (not:HI (match_operand:HI 2 "general_operand" "rR,Qi,rR,Qi"))))] "" "bic %2, %0" [(set_attr "length" "1,2,2,3")])

(define_insn "andcbqi3" [(set (match_operand:QI 0 "general_operand" "=rR,rR,Q,Q") (and:QI (match_operand:QI 1 "general_operand" "0,0,0,0") (not:QI (match_operand:QI 2 "general_operand" "rR,Qi,rR,Qi"))))] "" "bicb %2, %0" [(set_attr "length" "1,2,2,3")])

;;- Bit set (inclusive or) instructions (define_insn "iorsi3" [(set (match_operand:SI 0 "general_operand" "=r,r,o,o,r,r,r,o,o,o") (ior:SI (match_operand:SI 1 "general_operand" "%0,0,0,0,0,0,0,0,0,0") (match_operand:SI 2 "general_operand" "r,o,r,o,I,J,K,I,J,K")))] "" "* { /* Here we trust that operands don't overlap

 or is lateoperands the low word?? - looks like it! */

unsigned int i; rtx lateoperands[3];

lateoperands[0] = operands[0];

if (REG_P (operands[0])) operands[0] = gen_rtx(REG, HImode, REGNO(operands[0]) + 1); else operands[0] = adj_offsettable_operand (operands[0], 2);

if (! CONSTANT_P(operands[2])) { lateoperands[2] = operands[2];

if (REG_P (operands[2]))
  operands[2] = gen_rtx(REG, HImode, REGNO(operands[2]) + 1);
else
  operands[2] = adj_offsettable_operand(operands[2], 2);

output_asm_insn (\"bis %2, %0\", operands);
output_asm_insn (\"bis %2, %0\", lateoperands);
return \"\";

}

lateoperands[2] = gen_rtx(CONST_INT, VOIDmode, (INTVAL(operands[2]) >> 16) & 0xffff); operands[2] = gen_rtx(CONST_INT, VOIDmode, INTVAL(operands[2]) & 0xffff);

/* these have different lengths, so we should have different constraints! */ if (INTVAL(operands[2])) output_asm_insn ("bis %2, %0", operands);

if (INTVAL(lateoperands[2])) output_asm_insn ("bis %2, %0", lateoperands);

return ""; }" [(set_attr "length" "2,4,4,6,2,2,4,3,3,6")])

(define_insn "iorhi3" [(set (match_operand:HI 0 "general_operand" "=rR,rR,Q,Q") (ior:HI (match_operand:HI 1 "general_operand" "%0,0,0,0") (match_operand:HI 2 "general_operand" "rR,Qi,rR,Qi")))] "" "bis %2, %0" [(set_attr "length" "1,2,2,3")])

(define_insn "iorqi3" [(set (match_operand:QI 0 "general_operand" "=rR,rR,Q,Q") (ior:QI (match_operand:QI 1 "general_operand" "%0,0,0,0") (match_operand:QI 2 "general_operand" "rR,Qi,rR,Qi")))] "" "bisb %2, %0")

;;- xor instructions (define_insn "xorsi3" [(set (match_operand:SI 0 "register_operand" "=r,r,r,r") (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0") (match_operand:SI 2 "arith_operand" "r,I,J,K")))] "TARGET_40_PLUS" "* { /* Here we trust that operands don't overlap */

unsigned int i; rtx lateoperands[3];

lateoperands[0] = operands[0]; operands[0] = gen_rtx(REG, HImode, REGNO(operands[0]) + 1);

if (REG_P(operands[2])) { lateoperands[2] = operands[2]; operands[2] = gen_rtx(REG, HImode, REGNO(operands[2]) + 1);

output_asm_insn (\"xor %2, %0\", operands);
output_asm_insn (\"xor %2, %0\", lateoperands);

return \"\";

}

lateoperands[2] = gen_rtx(CONST_INT, VOIDmode, (INTVAL(operands[2]) >> 16) & 0xffff); operands[2] = gen_rtx(CONST_INT, VOIDmode, INTVAL(operands[2]) & 0xffff);

if (INTVAL(operands[2])) output_asm_insn ("xor %2, %0", operands);

if (INTVAL(lateoperands[2])) output_asm_insn ("xor %2, %0", lateoperands);

return ""; }" [(set_attr "length" "2,1,1,2")])

(define_insn "xorhi3" [(set (match_operand:HI 0 "general_operand" "=rR,Q") (xor:HI (match_operand:HI 1 "general_operand" "%0,0") (match_operand:HI 2 "register_operand" "r,r")))] "TARGET_40_PLUS" "xor %2, %0" [(set_attr "length" "1,2")])

;;- one complement instructions

(define_insn "one_cmplhi2" [(set (match_operand:HI 0 "general_operand" "=rR,Q") (not:HI (match_operand:HI 1 "general_operand" "0,0")))] "" "com %0" [(set_attr "length" "1,2")])

(define_insn "one_cmplqi2" [(set (match_operand:QI 0 "general_operand" "=rR,Q") (not:QI (match_operand:QI 1 "general_operand" "0,0")))] "" "comb %0" [(set_attr "length" "1,2")])

;;- 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_45" "ashc %2,%0" [(set_attr "length" "1,2")])

;; 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")))] "" " { operands[2] = negate_rtx (HImode, operands[2]); }")

;; define asl aslb asr asrb - ashc missing!

;; asl (define_insn "" [(set (match_operand:HI 0 "general_operand" "=rR,Q") (ashift:HI (match_operand:HI 1 "general_operand" "0,0") (const_int 1)))] "" "asl %0" [(set_attr "length" "1,2")])

;; 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 "general_operand" "=rR,Q") (ashift:HI (match_operand:HI 1 "general_operand" "0,0") (const_int -1)))] "" "asr %0" [(set_attr "length" "1,2")])

;; 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 "general_operand" "=r") (ashift:HI (match_operand:HI 1 "general_operand" "0") (match_operand:HI 2 "expand_shift_operand" "O")))] "TARGET_TIME" "* { 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 4))])

;; aslb (define_insn "" [(set (match_operand:QI 0 "general_operand" "=r,o") (ashift:QI (match_operand:QI 1 "general_operand" "0,0") (match_operand:HI 2 "const_immediate_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 7) (const_int 14)])])

;;; asr ;(define_insn "" ; [(set (match_operand:HI 0 "general_operand" "=rR,Q") ; (ashiftrt:HI (match_operand:HI 1 "general_operand" "0,0") ; (const_int 1)))] ; "" ; "asr %0" ; [(set_attr "length" "1,2")])

;; asrb (define_insn "" [(set (match_operand:QI 0 "general_operand" "=r,o") (ashiftrt:QI (match_operand:QI 1 "general_operand" "0,0") (match_operand:HI 2 "const_immediate_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("asrb %0", operands);

return ""; }" [(set_attr_alternative "length" [(const_int 7) (const_int 14)])])

;; the following is invalid - too complex!!! - just say 14 !!! ; [(set (attr "length") (plus (and (match_dup 2) ; (const_int 7)) ; (and (match_dup 2) ; (const_int 7))))])

;; 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")))] "" "* { if (GET_CODE(operands[2]) == CONST_INT) if (INTVAL(operands[2]) == 1) return "asl %0"; else if (INTVAL(operands[2]) == -1) return "asr %0";

return "ash %2,%0"; }" [(set_attr "length" "1,2")])

;; 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]); }")

;;;;- logical shift instructions ;;(define_insn "lshrsi3" ;; [(set (match_operand:HI 0 "register_operand" "=r") ;; (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") ;; (match_operand:HI 2 "arith_operand" "rI")))] ;; "" ;; "srl %0,%2")

;; absolute

(define_insn "absdf2" [(set (match_operand:DF 0 "general_operand" "=fR,Q") (abs:DF (match_operand:DF 1 "general_operand" "0,0")))] "TARGET_FPU" "absd %0" [(set_attr "length" "1,2")])

(define_insn "abshi2" [(set (match_operand:HI 0 "general_operand" "=r,o") (abs:HI (match_operand:HI 1 "general_operand" "0,0")))] "TARGET_ABSHI_BUILTIN" "* { static count = 0; char buf[200];

output_asm_insn("tst %0", operands); sprintf(buf, "bge abshi%d", count); output_asm_insn(buf, NULL); output_asm_insn("neg %0", operands); sprintf(buf, "\nabshi%d:", count++); output_asm_insn(buf, NULL);

return ""; }" [(set_attr "length" "3,5")])

;; define expand abshi - is much better !!! - but ;; will it be optimized into an abshi2 ? ;; it will leave better code, because the tsthi might be ;; optimized away!! ; -- just a thought - don't have time to check ; ;(define_expand "abshi2" ; [(match_operand:HI 0 "general_operand" "") ; (match_operand:HI 1 "general_operand" "")] ; "" ; " ;{ ; rtx label = gen_label_rtx (); ; ; /* do I need this? / ; do_pending_stack_adjust (); ; ; emit_move_insn (operands[0], operands[1]); ; ; emit_insn (gen_tsthi (operands[0])); ; emit_insn (gen_bge (label1)); ; ; emit_insn (gen_neghi(operands[0], operands[0]) ;
; emit_barrier (); ; ; emit_label (label); ; ; /
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_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx)); ; DONE; ;}")

;; negate insns

(define_insn "negdf2" [(set (match_operand:DF 0 "general_operand" "=fR,Q") (neg:DF (match_operand:DF 1 "register_operand" "0,0")))] "TARGET_FPU" "negd %0" [(set_attr "length" "1,2")])

(define_insn "neghi2" [(set (match_operand:HI 0 "general_operand" "=rR,Q") (neg:HI (match_operand:HI 1 "general_operand" "0,0")))] "" "neg %0" [(set_attr "length" "1,2")])

(define_insn "negqi2" [(set (match_operand:QI 0 "general_operand" "=rR,Q") (neg:QI (match_operand:QI 1 "general_operand" "0,0")))] "" "negb %0" [(set_attr "length" "1,2")])

;; Unconditional and other jump instructions (define_insn "jump" [(set (pc) (label_ref (match_operand 0 "" "")))] "" "jmp %l0" [(set_attr "length" "2")])

(define_insn "" [(set (pc) (label_ref (match_operand 0 "" ""))) (clobber (const_int 1))] "" "jmp %l0" [(set_attr "length" "2")])

(define_insn "tablejump" [(set (pc) (match_operand:HI 0 "general_operand" "rR,Q")) (use (label_ref (match_operand 1 "" "")))] "" "jmp %0" [(set_attr "length" "1,2")])

;; indirect jump - let's be conservative! ;; allow only register_operand, even though we could also ;; allow labels etc.

(define_insn "indirect_jump" [(set (pc) (match_operand:HI 0 "register_operand" "r"))] "" "jmp (%0)")

;;- jump to subroutine

(define_insn "call" [(call (match_operand:HI 0 "general_operand" "R,Q") (match_operand:HI 1 "general_operand" "g,g")) ;; (use (reg:HI 0)) what was that ??? ] ;;- Don't use operand 1 for most machines. "" "jsr pc, %0" [(set_attr "length" "1,2")])

;;- jump to subroutine (define_insn "call_value" [(set (match_operand 0 "" "") (call (match_operand:HI 1 "general_operand" "R,Q") (match_operand:HI 2 "general_operand" "g,g"))) ;; (use (reg:HI 0)) - what was that ???? ] ;;- Don't use operand 2 for most machines. "" "jsr pc, %1" [(set_attr "length" "1,2")])

;;- nop instruction (define_insn "nop" [(const_int 0)] "" "nop")

;;- multiply

(define_insn "muldf3" [(set (match_operand:DF 0 "register_operand" "=a,a,a") (mult:DF (match_operand:DF 1 "register_operand" "%0,0,0") (match_operand:DF 2 "general_operand" "fR,Q,F")))] "TARGET_FPU" "muld %2, %0" [(set_attr "length" "1,2,5")])

;; 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 ....

(define_insn "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 "general_operand" "rR,Qi")))] "TARGET_45" "mul %2, %0" [(set_attr "length" "1,2")])

;; 32 bit result (define_expand "mulhisi3" [(set (match_dup 3) (match_operand:HI 1 "general_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")))] "TARGET_45" "operands[3] = gen_lowpart(HImode, operands[1]);")

(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_45" "mul %2, %0" [(set_attr "length" "1,2")])

;(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_45" ; "mul %2, %0" ; [(set_attr "length" "1,2")])

;;- divide (define_insn "divdf3" [(set (match_operand:DF 0 "register_operand" "=a,a,a") (div:DF (match_operand:DF 1 "register_operand" "0,0,0") (match_operand:DF 2 "general_operand" "fR,Q,F")))] "TARGET_FPU" "divd %2, %0" [(set_attr "length" "1,2,5")])

(define_expand "divhi3" [(set (subreg:HI (match_dup 1) 0) (div:HI (match_operand:SI 1 "general_operand" "0") (match_operand:HI 2 "general_operand" "g"))) (set (match_operand:HI 0 "general_operand" "=r") (subreg:HI (match_dup 1) 0))] "TARGET_45" "")

(define_insn "" [(set (subreg:HI (match_operand:SI 0 "general_operand" "=r") 0) (div:HI (match_operand:SI 1 "general_operand" "0") (match_operand:HI 2 "general_operand" "g")))] "TARGET_45" "div %2,%0" [(set_attr "length" "2")])

(define_expand "modhi3" [(set (subreg:HI (match_dup 1) 1) (mod:HI (match_operand:SI 1 "general_operand" "0") (match_operand:HI 2 "general_operand" "g"))) (set (match_operand:HI 0 "general_operand" "=r") (subreg:HI (match_dup 1) 1))] "TARGET_45" "")

(define_insn "" [(set (subreg:HI (match_operand:SI 0 "general_operand" "=r") 1) (mod:HI (match_operand:SI 1 "general_operand" "0") (match_operand:HI 2 "general_operand" "g")))] "TARGET_45" "div %2,%0" [(set_attr "length" "2")])

;(define_expand "divmodhi4" ; [(parallel [(set (subreg:HI (match_dup 1) 0) ; (div:HI (match_operand:SI 1 "general_operand" "0") ; (match_operand:HI 2 "general_operand" "g"))) ; (set (subreg:HI (match_dup 1) 1) ; (mod:HI (match_dup 1) ; (match_dup 2)))]) ; (set (match_operand:HI 3 "general_operand" "=r") ; (subreg:HI (match_dup 1) 1)) ; (set (match_operand:HI 0 "general_operand" "=r") ; (subreg:HI (match_dup 1) 0))] ; "TARGET_45" ; "") ; ;(define_insn "" ; [(set (subreg:HI (match_operand:SI 0 "general_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) 1) ; (mod:HI (match_dup 1) ; (match_dup 2)))] ; "TARGET_45" ; "div %2, %0") ;

;; is rotate doing the right thing to be included here ????