1;;- Machine description for the pdp11 for GNU C compiler
2;; Copyright (C) 1994-2018 Free Software Foundation, Inc.
3;; Contributed by Michael K. Gschwind (mike@vlsivie.tuwien.ac.at).
4
5;; This file is part of GCC.
6
7;; GCC is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 3, or (at your option)
10;; any later version.
11
12;; GCC is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GCC; see the file COPYING3.  If not see
19;; <http://www.gnu.org/licenses/>.
20
21(include "predicates.md")
22(include "constraints.md")
23
24(define_c_enum "unspecv"
25  [
26    UNSPECV_BLOCKAGE
27    UNSPECV_SETD
28    UNSPECV_SETI
29  ])
30
31(define_constants
32  [
33   ;; Register numbers
34   (R0_REGNUM     	  0)
35   (RETVAL_REGNUM     	  0)
36   (HARD_FRAME_POINTER_REGNUM  5)
37   (STACK_POINTER_REGNUM  6)
38   (PC_REGNUM             7)
39   (AC0_REGNUM            8)
40   (AC3_REGNUM            11)
41   (AC4_REGNUM            12)
42   (AC5_REGNUM            13)
43   ;; The next two are not physical registers but are used for addressing
44   ;; arguments.
45   (FRAME_POINTER_REGNUM  14)
46   (ARG_POINTER_REGNUM    15)
47   (FIRST_PSEUDO_REGISTER 16)
48   ;; Branch offset limits, as byte offsets from instruction address
49   (MIN_BRANCH            -254)
50   (MAX_BRANCH            256)
51   (MIN_SOB               -126)
52   (MAX_SOB               0)])
53
54;; HI is 16 bit
55;; QI is 8 bit
56
57;; Integer modes supported on the PDP11, with a mapping from machine mode
58;; to mnemonic suffix.  SImode and DImode always are special cases.
59(define_mode_iterator PDPint [QI HI])
60(define_mode_attr  isfx [(QI "b") (HI "")])
61
62;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
63
64;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code
65;;- updates for most instructions.
66
67;;- Operand classes for the register allocator:
68
69;; Compare instructions.
70
71;; currently we only support df floats, which saves us quite some
72;; hassle switching the FP mode!
73;; we assume that CPU is always in long float mode, and
74;; 16 bit integer mode - currently, the prologue for main does this,
75;; but maybe we should just set up a NEW crt0 properly,
76;; -- and what about signal handling code?
77;; (we don't even let sf floats in the register file, so
78;; we only should have to worry about truncating and widening
79;; when going to memory)
80
81;; abort() call by g++ - must define libfunc for cmp_optab
82;; and ucmp_optab for mode SImode, because we don't have that!!!
83;; - yet since no libfunc is there, we abort ()
84
85;; The only thing that remains to be done then is output
86;; the floats in a way the assembler can handle it (and
87;; if you're really into it, use a PDP11 float emulation
88;; library to do floating point constant folding - but
89;; I guess you'll get reasonable results even when not
90;; doing this)
91;; the last thing to do is fix the UPDATE_CC macro to check
92;; for floating point condition codes, and set cc_status
93;; properly, also setting the CC_IN_FCCR flag.
94
95;; define attributes
96;; currently type is only fpu or arith or unknown, maybe branch later ?
97;; default is arith
98(define_attr "type" "unknown,arith,fp" (const_string "arith"))
99
100;; length default is 2 bytes each
101(define_attr "length" "" (const_int 2))
102
103;; a user's asm statement
104(define_asm_attributes
105  [(set_attr "type" "unknown")
106; length for asm is the max length per statement.  That would be
107; 3 words, for a two-operand instruction with extra word addressing
108; modes for both operands.
109   (set_attr "length" "6")])
110
111;; define function units
112
113;; Prologue and epilogue support.
114
115(define_expand "prologue"
116  [(const_int 0)]
117  ""
118{
119  pdp11_expand_prologue ();
120  DONE;
121})
122
123(define_expand "epilogue"
124  [(const_int 0)]
125  ""
126{
127  pdp11_expand_epilogue ();
128  DONE;
129})
130
131(define_expand "return"
132  [(return)]
133  "reload_completed && !frame_pointer_needed && pdp11_sp_frame_offset () == 0"
134  "")
135
136(define_insn "*rts"
137  [(return)]
138  ""
139  "rts pc")
140
141(define_insn "blockage"
142  [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
143  ""
144  ""
145  [(set_attr "length" "0")])
146
147(define_insn "setd"
148  [(unspec_volatile [(const_int 0)] UNSPECV_SETD)]
149  ""
150  "setd")
151
152(define_insn "seti"
153  [(unspec_volatile [(const_int 0)] UNSPECV_SETI)]
154  ""
155  "seti")
156
157;; arithmetic - values here immediately when next insn issued
158;; or does it mean the number of cycles after this insn was issued?
159;; how do I say that fpu insns use cpu also? (pre-interaction phase)
160
161;(define_function_unit "cpu" 1 1 (eq_attr "type" "arith") 0 0)
162;(define_function_unit "fpu" 1 1 (eq_attr "type" "fp") 0 0)
163
164;; compare
165(define_insn "*cmpdf"
166  [(set (cc0)
167	(compare (match_operand:DF 0 "general_operand" "fR,fR,Q,QF")
168		 (match_operand:DF 1 "register_or_const0_operand" "G,a,G,a")))]
169  "TARGET_FPU"
170  "*
171{
172  cc_status.flags = CC_IN_FPU;
173  if (which_alternative == 0 || which_alternative == 2)
174    return \"{tstd|tstf} %0\;cfcc\";
175  else
176    return \"{cmpd|cmpf} %0, %1\;cfcc\";
177}"
178  [(set_attr "length" "4,4,6,6")])
179
180(define_insn "*cmp<mode>"
181  [(set (cc0)
182	(compare (match_operand:PDPint 0 "general_operand" "rR,rR,rR,Q,Qi,Qi")
183		 (match_operand:PDPint 1 "general_operand" "N,rR,Qi,N,rR,Qi")))]
184  ""
185  "@
186   tst<PDPint:isfx> %0
187   cmp<PDPint:isfx> %0,%1
188   cmp<PDPint:isfx> %0,%1
189   tst<PDPint:isfx> %0
190   cmp<PDPint:isfx> %0,%1
191   cmp<PDPint:isfx> %0,%1"
192  [(set_attr "length" "2,2,4,4,4,6")])
193
194;; sob instruction - we need an assembler which can make this instruction
195;; valid under _all_ circumstances!
196
197(define_insn ""
198  [(set (pc)
199	(if_then_else
200	 (ne (plus:HI (match_operand:HI 0 "register_operand" "+r")
201		      (const_int -1))
202	     (const_int 0))
203	 (label_ref (match_operand 1 "" ""))
204	 (pc)))
205   (set (match_dup 0)
206	(plus:HI (match_dup 0)
207		 (const_int -1)))]
208  "TARGET_40_PLUS"
209  "*
210{
211 static int labelcount = 0;
212 static char buf[1000];
213
214 if (get_attr_length (insn) == 2)
215    return \"sob %0, %l1\";
216
217 /* emulate sob */
218 output_asm_insn (\"dec %0\", operands);
219
220 sprintf (buf, \"bge LONG_SOB%d\", labelcount);
221 output_asm_insn (buf, NULL);
222
223 output_asm_insn (\"jmp %l1\", operands);
224
225 sprintf (buf, \"LONG_SOB%d:\", labelcount++);
226 output_asm_insn (buf, NULL);
227
228 return \"\";
229}"
230  [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 0)
231						       (pc))
232						(const_int MIN_SOB))
233					   (gt (minus (match_dup 0)
234						       (pc))
235						(const_int MAX_SOB)))
236				      (const_int 8)
237				      (const_int 2)))])
238
239;; These control RTL generation for conditional jump insns
240;; and match them for register allocation.
241
242(define_expand "cbranchdf4"
243  [(set (cc0)
244        (compare (match_operand:DF 1 "general_operand")
245		 (match_operand:DF 2 "register_or_const0_operand")))
246   (set (pc)
247	(if_then_else (match_operator 0 "ordered_comparison_operator"
248		       [(cc0) (const_int 0)])
249		      (label_ref (match_operand 3 "" ""))
250		      (pc)))]
251  "TARGET_FPU"
252  "")
253
254(define_expand "cbranch<mode>4"
255  [(set (cc0)
256        (compare (match_operand:PDPint 1 "general_operand")
257		 (match_operand:PDPint 2 "general_operand")))
258   (set (pc)
259	(if_then_else (match_operator 0 "ordered_comparison_operator"
260		       [(cc0) (const_int 0)])
261		      (label_ref (match_operand 3 "" ""))
262		      (pc)))]
263  ""
264  "")
265
266;; problem with too short jump distance! we need an assembler which can
267;; make this valid for all jump distances!
268;; e.g. gas!
269
270;; these must be changed to check for CC_IN_FCCR if float is to be
271;; enabled
272
273(define_insn "*branch"
274  [(set (pc)
275	(if_then_else (match_operator 0 "ordered_comparison_operator"
276		       [(cc0) (const_int 0)])
277		      (label_ref (match_operand 1 "" ""))
278		      (pc)))]
279  ""
280  "* return output_jump(GET_CODE (operands[0]), 0, get_attr_length(insn));"
281  [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1)
282						      (pc))
283					       (const_int MIN_BRANCH))
284					   (gt (minus (match_dup 1)
285						      (pc))
286					       (const_int MAX_BRANCH)))
287				      (const_int 6)
288				      (const_int 2)))])
289
290
291;; These match inverted jump insns for register allocation.
292
293(define_insn "*branch_inverted"
294  [(set (pc)
295	(if_then_else (match_operator 0 "ordered_comparison_operator"
296		       [(cc0) (const_int 0)])
297		      (pc)
298		      (label_ref (match_operand 1 "" ""))))]
299  ""
300  "* return output_jump(GET_CODE (operands[0]), 1, get_attr_length(insn));"
301  [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 1)
302						      (pc))
303					       (const_int MIN_BRANCH))
304					   (gt (minus (match_dup 1)
305						      (pc))
306					       (const_int MAX_BRANCH)))
307				      (const_int 6)
308				      (const_int 2)))])
309
310;; Move instructions
311
312(define_insn "movdi"
313  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,g")
314	(match_operand:DI 1 "general_operand" "rN,g"))]
315  ""
316  "* return output_move_multiple (operands);"
317;; what's the mose expensive code - say twice movsi = 16
318  [(set_attr "length" "16,32")])
319
320(define_insn "movsi"
321  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,g,g")
322	(match_operand:SI 1 "general_operand" "rN,IJ,IJ,g"))]
323  ""
324  "* return output_move_multiple (operands);"
325;; what's the most expensive code ? - I think 8!
326;; we could split it up and make several sub-cases...
327  [(set_attr "length" "4,6,8,16")])
328
329(define_insn "mov<mode>"
330  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
331	(match_operand:PDPint 1 "general_operand" "rRN,Qi,rRN,Qi"))]
332  ""
333  "*
334{
335  if (operands[1] == const0_rtx)
336    return \"clr<PDPint:isfx> %0\";
337
338  return \"mov<PDPint:isfx> %1, %0\";
339}"
340  [(set_attr "length" "2,4,4,6")])
341
342(define_insn "movdf"
343  [(set (match_operand:DF 0 "float_nonimm_operand" "=a,fR,a,Q,g")
344        (match_operand:DF 1 "float_operand" "fR,a,FQ,a,g"))]
345  "TARGET_FPU"
346  "* if (which_alternative ==0 || which_alternative == 2)
347       return \"ldd %1, %0\";
348     else if (which_alternative == 1 || which_alternative == 3)
349       return \"std %1, %0\";
350     else
351       return output_move_multiple (operands); "
352;; last one is worst-case
353  [(set_attr "length" "2,2,4,4,24")])
354
355(define_insn "movsf"
356  [(set (match_operand:SF 0 "float_nonimm_operand" "=a,fR,a,Q,g")
357        (match_operand:SF 1 "float_operand" "fR,a,FQ,a,g"))]
358  "TARGET_FPU"
359  "* if (which_alternative ==0 || which_alternative == 2)
360       return \"{ldcfd|movof} %1, %0\";
361     else if (which_alternative == 1 || which_alternative == 3)
362       return \"{stcdf|movfo} %1, %0\";
363     else
364       return output_move_multiple (operands); "
365;; last one is worst-case
366  [(set_attr "length" "2,2,4,4,12")])
367
368;; maybe fiddle a bit with move_ratio, then
369;; let constraints only accept a register ...
370
371(define_expand "movmemhi"
372  [(parallel [(set (match_operand:BLK 0 "general_operand" "=g,g")
373		   (match_operand:BLK 1 "general_operand" "g,g"))
374	      (use (match_operand:HI 2 "general_operand" "n,mr"))
375	      (use (match_operand:HI 3 "immediate_operand" "i,i"))
376	      (clobber (match_scratch:HI 6 "=&r,X"))
377	      (clobber (match_dup 4))
378	      (clobber (match_dup 5))
379	      (clobber (match_dup 2))])]
380  "(TARGET_BCOPY_BUILTIN)"
381  "
382{
383  operands[0]
384    = replace_equiv_address (operands[0],
385			     copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
386  operands[1]
387    = replace_equiv_address (operands[1],
388			     copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
389
390  operands[4] = XEXP (operands[0], 0);
391  operands[5] = XEXP (operands[1], 0);
392}")
393
394
395(define_insn "movmemhi1"
396  [(set (mem:BLK (match_operand:HI 0 "register_operand" "r,r"))
397	(mem:BLK (match_operand:HI 1 "register_operand" "r,r")))
398   (use (match_operand:HI 2 "general_operand" "n,r"))
399   (use (match_operand:HI 3 "immediate_operand" "i,i"))
400   (clobber (match_scratch:HI 4 "=&r,X"))
401   (clobber (match_dup 0))
402   (clobber (match_dup 1))
403   (clobber (match_dup 2))]
404  "(TARGET_BCOPY_BUILTIN)"
405  "* return output_block_move (operands);"
406;;; just a guess
407  [(set_attr "length" "80")])
408
409
410
411;;- truncation instructions
412
413(define_insn  "truncdfsf2"
414  [(set (match_operand:SF 0 "float_nonimm_operand" "=f,R,Q")
415	(float_truncate:SF (match_operand:DF 1 "register_operand" "f,a,a")))]
416  "TARGET_FPU"
417  "* if (which_alternative ==0)
418     {
419       return \"\";
420     }
421     else if (which_alternative == 1)
422       return \"{stcdf|movfo} %1, %0\";
423     else
424       return \"{stcdf|movfo} %1, %0\";
425  "
426  [(set_attr "length" "0,2,4")])
427
428
429(define_expand "truncsihi2"
430  [(set (match_operand:HI 0 "nonimmediate_operand" "=g")
431	(subreg:HI
432	  (match_operand:SI 1 "general_operand" "or")
433          0))]
434  ""
435  "")
436
437
438;;- zero extension instructions
439
440(define_insn "zero_extendqihi2"
441  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
442	(zero_extend:HI (match_operand:QI 1 "general_operand" "0,0")))]
443  ""
444  "bic $0177400, %0"
445  [(set_attr "length" "4,6")])
446
447(define_expand "zero_extendhisi2"
448  [(set (subreg:HI
449          (match_dup 0)
450          2)
451        (match_operand:HI 1 "register_operand" "r"))
452   (set (subreg:HI
453          (match_operand:SI 0 "register_operand" "=r")
454          0)
455        (const_int 0))]
456  ""
457  "/* operands[1] = make_safe_from (operands[1], operands[0]); */")
458
459
460;;- sign extension instructions
461
462(define_insn "extendsfdf2"
463  [(set (match_operand:DF 0 "register_operand" "=f,a,a")
464	(float_extend:DF (match_operand:SF 1 "float_operand" "f,R,Q")))]
465  "TARGET_FPU"
466  "@
467   /* nothing */
468   {ldcfd|movof} %1, %0
469   {ldcfd|movof} %1, %0"
470  [(set_attr "length" "0,2,4")])
471
472;; does movb sign extend in register-to-register move?
473(define_insn "extendqihi2"
474  [(set (match_operand:HI 0 "register_operand" "=r,r")
475	(sign_extend:HI (match_operand:QI 1 "general_operand" "rR,Q")))]
476  ""
477  "movb %1, %0"
478  [(set_attr "length" "2,4")])
479
480(define_insn "extendqisi2"
481  [(set (match_operand:SI 0 "register_operand" "=r,r")
482	(sign_extend:SI (match_operand:QI 1 "general_operand" "rR,Q")))]
483  "TARGET_40_PLUS"
484  "*
485{
486  rtx latehalf[2];
487
488  /* make register pair available */
489  latehalf[0] = operands[0];
490  operands[0] = gen_rtx_REG (HImode, REGNO (operands[0])+ 1);
491
492  output_asm_insn(\"movb %1, %0\", operands);
493  output_asm_insn(\"sxt %0\", latehalf);
494
495  return \"\";
496}"
497  [(set_attr "length" "4,6")])
498
499;; maybe we have to use define_expand to say that we have the instruction,
500;; unconditionally, and then match dependent on CPU type:
501
502(define_expand "extendhisi2"
503  [(set (match_operand:SI 0 "nonimmediate_operand" "=g")
504	(sign_extend:SI (match_operand:HI 1 "general_operand" "g")))]
505  ""
506  "")
507
508(define_insn "" ; "extendhisi2"
509  [(set (match_operand:SI 0 "nonimmediate_operand" "=o,<,r")
510	(sign_extend:SI (match_operand:HI 1 "general_operand" "g,g,g")))]
511  "TARGET_40_PLUS"
512  "*
513{
514  rtx latehalf[2];
515
516  /* we don't want to mess with auto increment */
517
518  switch (which_alternative)
519  {
520    case 0:
521
522      latehalf[0] = operands[0];
523      operands[0] = adjust_address(operands[0], HImode, 2);
524
525      output_asm_insn(\"mov %1, %0\", operands);
526      output_asm_insn(\"sxt %0\", latehalf);
527
528      return \"\";
529
530    case 1:
531
532      /* - auto-decrement - right direction ;-) */
533      output_asm_insn(\"mov %1, %0\", operands);
534      output_asm_insn(\"sxt %0\", operands);
535
536      return \"\";
537
538    case 2:
539
540      /* make register pair available */
541      latehalf[0] = operands[0];
542      operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
543
544      output_asm_insn(\"mov %1, %0\", operands);
545      output_asm_insn(\"sxt %0\", latehalf);
546
547      return \"\";
548
549    default:
550
551      gcc_unreachable ();
552  }
553}"
554  [(set_attr "length" "10,6,6")])
555
556
557(define_insn ""
558  [(set (match_operand:SI 0 "register_operand" "=r")
559	(sign_extend:SI (match_operand:HI 1 "general_operand" "0")))]
560  "(! TARGET_40_PLUS)"
561  "*
562{
563  static int count = 0;
564  char buf[100];
565  rtx lateoperands[2];
566
567  lateoperands[0] = operands[0];
568  operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
569
570  output_asm_insn(\"tst %0\", operands);
571  sprintf(buf, \"bge extendhisi%d\", count);
572  output_asm_insn(buf, NULL);
573  output_asm_insn(\"mov -1, %0\", lateoperands);
574  sprintf(buf, \"bne extendhisi%d\", count+1);
575  output_asm_insn(buf, NULL);
576  sprintf(buf, \"\\nextendhisi%d:\", count);
577  output_asm_insn(buf, NULL);
578  output_asm_insn(\"clr %0\", lateoperands);
579  sprintf(buf, \"\\nextendhisi%d:\", count+1);
580  output_asm_insn(buf, NULL);
581
582  count += 2;
583
584  return \"\";
585}"
586  [(set_attr "length" "12")])
587
588;; make float to int and vice versa
589;; using the cc_status.flag field we could probably cut down
590;; on seti and setl
591;; assume that we are normally in double and integer mode -
592;; what do pdp library routines do to fpu mode ?
593
594(define_insn "floatsidf2"
595  [(set (match_operand:DF 0 "register_operand" "=a,a,a")
596	(float:DF (match_operand:SI 1 "general_operand" "r,R,Q")))]
597  "TARGET_FPU"
598  "* if (which_alternative ==0)
599     {
600       rtx latehalf[2];
601
602       latehalf[0] = NULL;
603       latehalf[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
604       output_asm_insn(\"mov %1, -(sp)\", latehalf);
605       output_asm_insn(\"mov %1, -(sp)\", operands);
606
607       output_asm_insn(\"setl\", operands);
608       output_asm_insn(\"{ldcld|movif} (sp)+, %0\", operands);
609       output_asm_insn(\"seti\", operands);
610       return \"\";
611     }
612     else if (which_alternative == 1)
613       return \"setl\;{ldcld|movif} %1, %0\;seti\";
614     else
615       return \"setl\;{ldcld|movif} %1, %0\;seti\";
616  "
617  [(set_attr "length" "10,6,8")])
618
619(define_insn "floathidf2"
620  [(set (match_operand:DF 0 "register_operand" "=a,a")
621	(float:DF (match_operand:HI 1 "general_operand" "rR,Qi")))]
622  "TARGET_FPU"
623  "{ldcid|movif} %1, %0"
624  [(set_attr "length" "2,4")])
625
626;; cut float to int
627(define_insn "fix_truncdfsi2"
628  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,R,Q")
629	(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "a,a,a"))))]
630  "TARGET_FPU"
631  "* if (which_alternative ==0)
632     {
633       output_asm_insn(\"setl\", operands);
634       output_asm_insn(\"{stcdl|movfi} %1, -(sp)\", operands);
635       output_asm_insn(\"seti\", operands);
636       output_asm_insn(\"mov (sp)+, %0\", operands);
637       operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
638       output_asm_insn(\"mov (sp)+, %0\", operands);
639       return \"\";
640     }
641     else if (which_alternative == 1)
642       return \"setl\;{stcdl|movfi} %1, %0\;seti\";
643     else
644       return \"setl\;{stcdl|movfi} %1, %0\;seti\";
645  "
646  [(set_attr "length" "10,6,8")])
647
648(define_insn "fix_truncdfhi2"
649  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
650	(fix:HI (fix:DF (match_operand:DF 1 "register_operand" "a,a"))))]
651  "TARGET_FPU"
652  "{stcdi|movfi} %1, %0"
653  [(set_attr "length" "2,4")])
654
655
656;;- arithmetic instructions
657;;- add instructions
658
659(define_insn "adddf3"
660  [(set (match_operand:DF 0 "register_operand" "=a,a")
661	(plus:DF (match_operand:DF 1 "register_operand" "%0,0")
662		 (match_operand:DF 2 "general_operand" "fR,QF")))]
663  "TARGET_FPU"
664  "{addd|addf} %2, %0"
665  [(set_attr "length" "2,4")])
666
667(define_insn "adddi3"
668  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
669	(plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0")
670		 (match_operand:DI 2 "general_operand" "r,on,r,on")))]
671  ""
672  "*
673{
674  rtx inops[2];
675  rtx exops[4][2];
676
677  inops[0] = operands[0];
678  inops[1] = operands[2];
679  pdp11_expand_operands (inops, exops, 2, NULL, either);
680
681  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
682    output_asm_insn (\"add %1, %0\", exops[0]);
683  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
684  {
685    output_asm_insn (\"add %1, %0\", exops[1]);
686    output_asm_insn (\"adc %0\", exops[0]);
687  }
688  if (!CONSTANT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
689  {
690    output_asm_insn (\"add %1, %0\", exops[2]);
691    output_asm_insn (\"adc %0\", exops[1]);
692    output_asm_insn (\"adc %0\", exops[0]);
693  }
694  if (!CONSTANT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
695  {
696    output_asm_insn (\"add %1, %0\", exops[3]);
697    output_asm_insn (\"adc %0\", exops[2]);
698    output_asm_insn (\"adc %0\", exops[1]);
699    output_asm_insn (\"adc %0\", exops[0]);
700  }
701
702  return \"\";
703}"
704  [(set_attr "length" "20,28,40,48")])
705
706;; Note that the register operand is not marked earlyclobber.
707;; The reason is that SI values go in register pairs, so they
708;; can't partially overlap.  They can be either disjoint, or
709;; source and destination can be equal.  The latter case is
710;; handled properly because of the ordering of the individual
711;; instructions used.  Specifically, carry from the low to the
712;; high word is added at the end, so the adding of the high parts
713;; will always used the original high part and not a high part
714;; modified by carry (which would amount to double carry).
715(define_insn "addsi3"
716  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o")
717	(plus:SI (match_operand:SI 1 "general_operand" "%0,0,0,0")
718		 (match_operand:SI 2 "general_operand" "r,on,r,on")))]
719  ""
720  "*
721{
722  rtx inops[2];
723  rtx exops[2][2];
724
725  inops[0] = operands[0];
726  inops[1] = operands[2];
727  pdp11_expand_operands (inops, exops, 2, NULL, either);
728
729  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
730    output_asm_insn (\"add %1, %0\", exops[0]);
731  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
732  {
733    output_asm_insn (\"add %1, %0\", exops[1]);
734    output_asm_insn (\"adc %0\", exops[0]);
735  }
736
737  return \"\";
738}"
739  [(set_attr "length" "6,10,12,16")])
740
741(define_insn "addhi3"
742  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
743	(plus:HI (match_operand:HI 1 "general_operand" "%0,0,0,0")
744		 (match_operand:HI 2 "general_operand" "rRLM,Qi,rRLM,Qi")))]
745  ""
746  "*
747{
748  if (GET_CODE (operands[2]) == CONST_INT)
749    {
750      if (INTVAL(operands[2]) == 1)
751	return \"inc %0\";
752      else if (INTVAL(operands[2]) == -1)
753        return \"dec %0\";
754    }
755
756  return \"add %2, %0\";
757}"
758  [(set_attr "length" "2,4,4,6")])
759
760
761;;- subtract instructions
762;; we don't have to care for constant second
763;; args, since they are canonical plus:xx now!
764;; also for minus:DF ??
765
766(define_insn "subdf3"
767  [(set (match_operand:DF 0 "register_operand" "=a,a")
768	(minus:DF (match_operand:DF 1 "register_operand" "0,0")
769		  (match_operand:DF 2 "general_operand" "fR,Q")))]
770  "TARGET_FPU"
771  "{subd|subf} %2, %0"
772  [(set_attr "length" "2,4")])
773
774(define_insn "subdi3"
775  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,o")
776	(minus:DI (match_operand:DI 1 "general_operand" "0,0,0,0")
777		 (match_operand:DI 2 "general_operand" "r,on,r,on")))]
778  ""
779  "*
780{
781  rtx inops[2];
782  rtx exops[4][2];
783
784  inops[0] = operands[0];
785  inops[1] = operands[2];
786  pdp11_expand_operands (inops, exops, 2, NULL, either);
787
788  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
789    output_asm_insn (\"sub %1, %0\", exops[0]);
790  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
791  {
792    output_asm_insn (\"sub %1, %0\", exops[1]);
793    output_asm_insn (\"sbc %0\", exops[0]);
794  }
795  if (!CONSTANT_P (exops[2][1]) || INTVAL (exops[2][1]) != 0)
796  {
797    output_asm_insn (\"sub %1, %0\", exops[2]);
798    output_asm_insn (\"sbc %0\", exops[1]);
799    output_asm_insn (\"sbc %0\", exops[0]);
800  }
801  if (!CONSTANT_P (exops[3][1]) || INTVAL (exops[3][1]) != 0)
802  {
803    output_asm_insn (\"sub %1, %0\", exops[3]);
804    output_asm_insn (\"sbc %0\", exops[2]);
805    output_asm_insn (\"sbc %0\", exops[1]);
806    output_asm_insn (\"sbc %0\", exops[0]);
807  }
808
809  return \"\";
810}"
811  [(set_attr "length" "20,28,40,48")])
812
813(define_insn "subsi3"
814  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,o,o")
815	(minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0")
816		 (match_operand:SI 2 "general_operand" "r,on,r,on")))]
817  ""
818  "*
819{
820  rtx inops[2];
821  rtx exops[2][2];
822
823  inops[0] = operands[0];
824  inops[1] = operands[2];
825  pdp11_expand_operands (inops, exops, 2, NULL, either);
826
827  if (!CONSTANT_P (exops[0][1]) || INTVAL (exops[0][1]) != 0)
828    output_asm_insn (\"sub %1, %0\", exops[0]);
829  if (!CONSTANT_P (exops[1][1]) || INTVAL (exops[1][1]) != 0)
830  {
831    output_asm_insn (\"sub %1, %0\", exops[1]);
832    output_asm_insn (\"sbc %0\", exops[0]);
833  }
834
835  return \"\";
836}"
837  [(set_attr "length" "6,10,12,16")])
838
839(define_insn "subhi3"
840  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,rR,Q,Q")
841	(minus:HI (match_operand:HI 1 "general_operand" "0,0,0,0")
842		  (match_operand:HI 2 "general_operand" "rR,Qi,rR,Qi")))]
843  ""
844  "*
845{
846  gcc_assert (GET_CODE (operands[2]) != CONST_INT);
847
848  return \"sub %2, %0\";
849}"
850  [(set_attr "length" "2,4,4,6")])
851
852;;;;- and instructions
853;; Bit-and on the pdp (like on the VAX) is done with a clear-bits insn.
854
855(define_expand "and<mode>3"
856  [(set (match_operand:PDPint 0 "nonimmediate_operand" "")
857	(and:PDPint (not:PDPint (match_operand:PDPint 1 "general_operand" ""))
858		   (match_operand:PDPint 2 "general_operand" "")))]
859  ""
860  "
861{
862  rtx op1 = operands[1];
863
864  /* If there is a constant argument, complement that one.
865     Similarly, if one of the inputs is the same as the output,
866     complement the other input.  */
867  if ((CONST_INT_P (operands[2]) && ! CONST_INT_P (op1)) ||
868      rtx_equal_p (operands[0], operands[1]))
869    {
870      operands[1] = operands[2];
871      operands[2] = op1;
872      op1 = operands[1];
873    }
874
875  if (CONST_INT_P (op1))
876    operands[1] = GEN_INT (~INTVAL (op1));
877  else
878    operands[1] = expand_unop (<MODE>mode, one_cmpl_optab, op1, 0, 1);
879}")
880
881(define_insn "*bic<mode>"
882  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
883	(and:PDPint
884	     (not: PDPint (match_operand:PDPint 1 "general_operand" "rR,Qi,rR,Qi"))
885	     (match_operand:PDPint 2 "general_operand" "0,0,0,0")))]
886  ""
887  "bic<PDPint:isfx> %1, %0"
888  [(set_attr "length" "2,4,4,6")])
889
890;;- Bit set (inclusive or) instructions
891(define_insn "ior<mode>3"
892  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,rR,Q,Q")
893	(ior:PDPint (match_operand:PDPint 1 "general_operand" "%0,0,0,0")
894		(match_operand:PDPint 2 "general_operand" "rR,Qi,rR,Qi")))]
895  ""
896  "bis<PDPint:isfx> %2, %0"
897  [(set_attr "length" "2,4,4,6")])
898
899;;- xor instructions
900(define_insn "xorhi3"
901  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
902	(xor:HI (match_operand:HI 1 "general_operand" "%0,0")
903		(match_operand:HI 2 "register_operand" "r,r")))]
904  "TARGET_40_PLUS"
905  "xor %2, %0"
906  [(set_attr "length" "2,4")])
907
908;;- one complement instructions
909
910(define_insn "one_cmpl<mode>2"
911  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
912        (not:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
913  ""
914  "com<PDPint:isfx> %0"
915  [(set_attr "length" "2,4")])
916
917;;- arithmetic shift instructions
918(define_insn "ashlsi3"
919  [(set (match_operand:SI 0 "register_operand" "=r,r")
920	(ashift:SI (match_operand:SI 1 "register_operand" "0,0")
921		   (match_operand:HI 2 "general_operand" "rR,Qi")))]
922  "TARGET_40_PLUS"
923  "ashc %2,%0"
924  [(set_attr "length" "2,4")])
925
926;; Arithmetic right shift on the pdp works by negating the shift count.
927(define_expand "ashrsi3"
928  [(set (match_operand:SI 0 "register_operand" "=r")
929	(ashift:SI (match_operand:SI 1 "register_operand" "0")
930		   (match_operand:HI 2 "general_operand" "g")))]
931  ""
932  "
933{
934  operands[2] = negate_rtx (HImode, operands[2]);
935}")
936
937;; define asl aslb asr asrb - ashc missing!
938
939;; asl
940(define_insn ""
941  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
942	(ashift:HI (match_operand:HI 1 "general_operand" "0,0")
943		   (const_int 1)))]
944  ""
945  "asl %0"
946  [(set_attr "length" "2,4")])
947
948;; and another possibility for asr is << -1
949;; might cause problems since -1 can also be encoded as 65535!
950;; not in gcc2 ???
951
952;; asr
953(define_insn ""
954  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
955	(ashift:HI (match_operand:HI 1 "general_operand" "0,0")
956		   (const_int -1)))]
957  ""
958  "asr %0"
959  [(set_attr "length" "2,4")])
960
961;; lsr
962(define_insn "lsrhi1"
963  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
964	(lshiftrt:HI (match_operand:HI 1 "general_operand" "0,0")
965		   (const_int 1)))]
966  ""
967  "clc\;ror %0"
968  [(set_attr "length" "2,4")])
969
970(define_insn "lsrsi1"
971  [(set (match_operand:SI 0 "register_operand" "=r")
972	(lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
973                   (const_int 1)))]
974  ""
975{
976
977  rtx lateoperands[2];
978
979  lateoperands[0] = operands[0];
980  operands[0] = gen_rtx_REG (HImode, REGNO (operands[0]) + 1);
981
982  lateoperands[1] = operands[1];
983  operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]) + 1);
984
985  output_asm_insn (\"clc\", operands);
986  output_asm_insn (\"ror %0\", lateoperands);
987  output_asm_insn (\"ror %0\", operands);
988
989  return \"\";
990}
991  [(set_attr "length" "10")])
992
993(define_expand "lshrsi3"
994  [(match_operand:SI 0 "register_operand" "")
995   (match_operand:SI 1 "register_operand" "0")
996   (match_operand:HI 2 "general_operand" "")]
997  ""
998  "
999{
1000  rtx r;
1001
1002  if (!TARGET_40_PLUS &&
1003      (GET_CODE (operands[2]) != CONST_INT ||
1004       (unsigned) INTVAL (operands[2]) > 3))
1005    FAIL;
1006  emit_insn (gen_lsrsi1 (operands[0], operands[1]));
1007  if (GET_CODE (operands[2]) != CONST_INT)
1008    {
1009      r = gen_reg_rtx (HImode);
1010      emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1)));
1011      emit_insn (gen_ashrsi3 (operands[0], operands[0], r));
1012    }
1013  else if ((unsigned) INTVAL (operands[2]) != 1)
1014    {
1015      emit_insn (gen_ashlsi3 (operands[0], operands[0],
1016                              GEN_INT (1 - INTVAL (operands[2]))));
1017    }
1018  DONE;
1019}
1020"
1021)
1022
1023;; shift is by arbitrary count is expensive,
1024;; shift by one cheap - so let's do that, if
1025;; space doesn't matter
1026(define_insn ""
1027  [(set (match_operand:HI 0 "nonimmediate_operand" "=r")
1028	(ashift:HI (match_operand:HI 1 "general_operand" "0")
1029		   (match_operand:HI 2 "expand_shift_operand" "O")))]
1030  "! optimize_size"
1031  "*
1032{
1033  register int i;
1034
1035  for (i = 1; i <= abs(INTVAL(operands[2])); i++)
1036    if (INTVAL(operands[2]) < 0)
1037      output_asm_insn(\"asr %0\", operands);
1038    else
1039      output_asm_insn(\"asl %0\", operands);
1040
1041  return \"\";
1042}"
1043;; longest is 4
1044  [(set (attr "length") (const_int 8))])
1045
1046;; aslb
1047(define_insn ""
1048  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,o")
1049	(ashift:QI (match_operand:QI 1 "general_operand" "0,0")
1050		   (match_operand:HI 2 "const_int_operand" "n,n")))]
1051  ""
1052  "*
1053{ /* allowing predec or post_inc is possible, but hairy! */
1054  int i, cnt;
1055
1056  cnt = INTVAL(operands[2]) & 0x0007;
1057
1058  for (i=0 ; i < cnt ; i++)
1059       output_asm_insn(\"aslb %0\", operands);
1060
1061  return \"\";
1062}"
1063;; set attribute length ( match_dup 2 & 7 ) *(1 or 2) !!!
1064  [(set_attr_alternative "length"
1065                         [(const_int 14)
1066                          (const_int 28)])])
1067
1068;;; asr
1069;(define_insn ""
1070;  [(set (match_operand:HI 0 "nonimmediate_operand" "=rR,Q")
1071;	(ashiftrt:HI (match_operand:HI 1 "general_operand" "0,0")
1072;		     (const_int 1)))]
1073;  ""
1074;  "asr %0"
1075;  [(set_attr "length" "2,4")])
1076
1077;; asrb
1078(define_insn ""
1079  [(set (match_operand:QI 0 "nonimmediate_operand" "=r,o")
1080	(ashiftrt:QI (match_operand:QI 1 "general_operand" "0,0")
1081		     (match_operand:HI 2 "const_int_operand" "n,n")))]
1082  ""
1083  "*
1084{ /* allowing predec or post_inc is possible, but hairy! */
1085  int i, cnt;
1086
1087  cnt = INTVAL(operands[2]) & 0x0007;
1088
1089  for (i=0 ; i < cnt ; i++)
1090       output_asm_insn(\"asrb %0\", operands);
1091
1092  return \"\";
1093}"
1094  [(set_attr_alternative "length"
1095                         [(const_int 14)
1096                          (const_int 28)])])
1097
1098;; the following is invalid - too complex!!! - just say 14 !!!
1099;  [(set (attr "length") (plus (and (match_dup 2)
1100;                                   (const_int 14))
1101;                              (and (match_dup 2)
1102;                                   (const_int 14))))])
1103
1104
1105
1106;; can we get +-1 in the next pattern? should
1107;; have been caught by previous patterns!
1108
1109(define_insn "ashlhi3"
1110  [(set (match_operand:HI 0 "register_operand" "=r,r")
1111	(ashift:HI (match_operand:HI 1 "register_operand" "0,0")
1112		   (match_operand:HI 2 "general_operand" "rR,Qi")))]
1113  "TARGET_40_PLUS"
1114  "*
1115{
1116  if (GET_CODE(operands[2]) == CONST_INT)
1117    {
1118      if (INTVAL(operands[2]) == 1)
1119	return \"asl %0\";
1120      else if (INTVAL(operands[2]) == -1)
1121	return \"asr %0\";
1122    }
1123
1124  return \"ash %2,%0\";
1125}"
1126  [(set_attr "length" "2,4")])
1127
1128;; Arithmetic right shift on the pdp works by negating the shift count.
1129(define_expand "ashrhi3"
1130  [(set (match_operand:HI 0 "register_operand" "=r")
1131	(ashift:HI (match_operand:HI 1 "register_operand" "0")
1132		   (match_operand:HI 2 "general_operand" "g")))]
1133  ""
1134  "
1135{
1136  operands[2] = negate_rtx (HImode, operands[2]);
1137}")
1138
1139(define_expand "lshrhi3"
1140  [(match_operand:HI 0 "register_operand" "")
1141   (match_operand:HI 1 "register_operand" "")
1142   (match_operand:HI 2 "general_operand" "")]
1143  ""
1144  "
1145{
1146  rtx r;
1147
1148  if (!TARGET_40_PLUS &&
1149      (GET_CODE (operands[2]) != CONST_INT ||
1150       (unsigned) INTVAL (operands[2]) > 3))
1151    FAIL;
1152  emit_insn (gen_lsrhi1 (operands[0], operands[1]));
1153  if (GET_CODE (operands[2]) != CONST_INT)
1154    {
1155      r = gen_reg_rtx (HImode);
1156      emit_insn (gen_addhi3 (r, operands [2], GEN_INT (-1)));
1157      emit_insn (gen_ashrhi3 (operands[0], operands[0], r));
1158    }
1159  else if ((unsigned) INTVAL (operands[2]) != 1)
1160    {
1161      emit_insn (gen_ashlhi3 (operands[0], operands[0],
1162                              GEN_INT (1 - INTVAL (operands[2]))));
1163    }
1164  DONE;
1165}
1166"
1167)
1168
1169;; absolute
1170
1171(define_insn "absdf2"
1172  [(set (match_operand:DF 0 "nonimmediate_operand" "=fR,Q")
1173	(abs:DF (match_operand:DF 1 "general_operand" "0,0")))]
1174  "TARGET_FPU"
1175  "{absd|absf} %0"
1176  [(set_attr "length" "2,4")])
1177
1178
1179;; negate insns
1180
1181(define_insn "negdf2"
1182  [(set (match_operand:DF 0 "float_nonimm_operand" "=fR,Q")
1183	(neg:DF (match_operand:DF 1 "register_operand" "0,0")))]
1184  "TARGET_FPU"
1185  "{negd|negf} %0"
1186  [(set_attr "length" "2,4")])
1187
1188(define_insn "negdi2"
1189  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
1190	(neg:DI (match_operand:DI 1 "general_operand" "0,0")))]
1191  ""
1192{
1193  rtx exops[4][2];
1194
1195  pdp11_expand_operands (operands, exops, 1, NULL, either);
1196
1197  output_asm_insn (\"com %0\", exops[3]);
1198  output_asm_insn (\"com %0\", exops[2]);
1199  output_asm_insn (\"com %0\", exops[1]);
1200  output_asm_insn (\"com %0\", exops[0]);
1201  output_asm_insn (\"add $1, %0\", exops[3]);
1202  output_asm_insn (\"adc %0\", exops[2]);
1203  output_asm_insn (\"adc %0\", exops[1]);
1204  output_asm_insn (\"adc %0\", exops[0]);
1205
1206  return \"\";
1207}
1208[(set_attr "length" "18,34")])
1209
1210(define_insn "negsi2"
1211  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,o")
1212	(neg:SI (match_operand:SI 1 "general_operand" "0,0")))]
1213  ""
1214{
1215  rtx exops[2][2];
1216
1217  pdp11_expand_operands (operands, exops, 1, NULL, either);
1218
1219  output_asm_insn (\"com %0\", exops[1]);
1220  output_asm_insn (\"com %0\", exops[0]);
1221  output_asm_insn (\"add $1, %0\", exops[1]);
1222  output_asm_insn (\"adc %0\", exops[0]);
1223
1224  return \"\";
1225}
1226[(set_attr "length" "12,20")])
1227
1228(define_insn "neg<mode>2"
1229  [(set (match_operand:PDPint 0 "nonimmediate_operand" "=rR,Q")
1230	(neg:PDPint (match_operand:PDPint 1 "general_operand" "0,0")))]
1231  ""
1232  "neg<isfx> %0"
1233  [(set_attr "length" "2,4")])
1234
1235
1236;; Unconditional and other jump instructions
1237(define_insn "jump"
1238  [(set (pc)
1239	(label_ref (match_operand 0 "" "")))]
1240  ""
1241  "*
1242{
1243 if (get_attr_length (insn) == 2)
1244    return \"br %l0\";
1245 return \"jmp %l0\";
1246}"
1247  [(set (attr "length") (if_then_else (ior (lt (minus (match_dup 0)
1248						      (pc))
1249					       (const_int MIN_BRANCH))
1250					   (gt (minus (match_dup 0)
1251						      (pc))
1252					       (const_int MAX_BRANCH)))
1253				      (const_int 4)
1254				      (const_int 2)))])
1255
1256(define_insn ""
1257  [(set (pc)
1258    (label_ref (match_operand 0 "" "")))
1259   (clobber (const_int 1))]
1260  ""
1261  "jmp %l0"
1262  [(set_attr "length" "4")])
1263
1264(define_insn "tablejump"
1265  [(set (pc) (match_operand:HI 0 "general_operand" "r,R,Q"))
1266   (use (label_ref (match_operand 1 "" "")))]
1267  ""
1268  "@
1269  jmp (%0)
1270  jmp %@%0
1271  jmp %@%0"
1272  [(set_attr "length" "2,2,4")])
1273
1274;; indirect jump - let's be conservative!
1275;; allow only register_operand, even though we could also
1276;; allow labels etc.
1277
1278(define_insn "indirect_jump"
1279  [(set (pc) (match_operand:HI 0 "register_operand" "r"))]
1280  ""
1281  "jmp (%0)")
1282
1283;;- jump to subroutine
1284
1285(define_insn "call"
1286  [(call (match_operand:HI 0 "general_operand" "rR,Q")
1287	 (match_operand:HI 1 "general_operand" "g,g"))
1288;;   (use (reg:HI 0)) what was that ???
1289  ]
1290  ;;- Don't use operand 1 for most machines.
1291  ""
1292  "jsr pc, %0"
1293  [(set_attr "length" "2,4")])
1294
1295;;- jump to subroutine
1296(define_insn "call_value"
1297  [(set (match_operand 0 "" "")
1298	(call (match_operand:HI 1 "general_operand" "rR,Q")
1299	      (match_operand:HI 2 "general_operand" "g,g")))
1300;;   (use (reg:HI 0)) - what was that ????
1301  ]
1302  ;;- Don't use operand 2 for most machines.
1303  ""
1304  "jsr pc, %1"
1305  [(set_attr "length" "2,4")])
1306
1307;;- nop instruction
1308(define_insn "nop"
1309  [(const_int 0)]
1310  ""
1311  "nop")
1312
1313
1314;;- multiply
1315
1316(define_insn "muldf3"
1317  [(set (match_operand:DF 0 "register_operand" "=a,a")
1318	(mult:DF (match_operand:DF 1 "register_operand" "%0,0")
1319		 (match_operand:DF 2 "float_operand" "fR,QF")))]
1320  "TARGET_FPU"
1321  "{muld|mulf} %2, %0"
1322  [(set_attr "length" "2,4")])
1323
1324;; 16 bit result multiply:
1325;; currently we multiply only into odd registers, so we don't use two
1326;; registers - but this is a bit inefficient at times. If we define
1327;; a register class for each register, then we can specify properly
1328;; which register need which scratch register ....
1329
1330(define_insn "mulhi3"
1331  [(set (match_operand:HI 0 "register_operand" "=d,d") ; multiply regs
1332	(mult:HI (match_operand:HI 1 "register_operand" "%0,0")
1333		 (match_operand:HI 2 "float_operand" "rR,Qi")))]
1334  "TARGET_40_PLUS"
1335  "mul %2, %0"
1336  [(set_attr "length" "2,4")])
1337
1338;; 32 bit result
1339(define_expand "mulhisi3"
1340  [(set (match_dup 3)
1341	(match_operand:HI 1 "nonimmediate_operand" "g,g"))
1342   (set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered!
1343	(mult:SI (truncate:HI
1344                  (match_dup 0))
1345		 (match_operand:HI 2 "general_operand" "rR,Qi")))]
1346  "TARGET_40_PLUS"
1347  "operands[3] = gen_lowpart(HImode, operands[1]);")
1348
1349(define_insn ""
1350  [(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered!
1351	(mult:SI (truncate:HI
1352                  (match_operand:SI 1 "register_operand" "%0,0"))
1353		 (match_operand:HI 2 "general_operand" "rR,Qi")))]
1354  "TARGET_40_PLUS"
1355  "mul %2, %0"
1356  [(set_attr "length" "2,4")])
1357
1358;(define_insn "mulhisi3"
1359;  [(set (match_operand:SI 0 "register_operand" "=r,r") ; even numbered!
1360;	(mult:SI (truncate:HI
1361;                  (match_operand:SI 1 "register_operand" "%0,0"))
1362;		 (match_operand:HI 2 "general_operand" "rR,Qi")))]
1363;  "TARGET_40_PLUS"
1364;  "mul %2, %0"
1365;  [(set_attr "length" "2,4")])
1366
1367;;- divide
1368(define_insn "divdf3"
1369  [(set (match_operand:DF 0 "register_operand" "=a,a")
1370	(div:DF (match_operand:DF 1 "register_operand" "0,0")
1371		(match_operand:DF 2 "general_operand" "fR,QF")))]
1372  "TARGET_FPU"
1373  "{divd|divf} %2, %0"
1374  [(set_attr "length" "2,4")])
1375
1376
1377(define_expand "divhi3"
1378  [(set (subreg:HI (match_dup 1) 0)
1379	(div:HI (match_operand:SI 1 "register_operand" "0")
1380		(match_operand:HI 2 "general_operand" "g")))
1381   (set (match_operand:HI 0 "register_operand" "=r")
1382        (subreg:HI (match_dup 1) 0))]
1383  "TARGET_40_PLUS"
1384  "")
1385
1386(define_insn ""
1387  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0)
1388	(div:HI (match_operand:SI 1 "general_operand" "0")
1389		(match_operand:HI 2 "general_operand" "g")))]
1390  "TARGET_40_PLUS"
1391  "div %2,%0"
1392  [(set_attr "length" "4")])
1393
1394(define_expand "modhi3"
1395  [(set (subreg:HI (match_dup 1) 2)
1396	(mod:HI (match_operand:SI 1 "register_operand" "0")
1397		(match_operand:HI 2 "general_operand" "g")))
1398   (set (match_operand:HI 0 "register_operand" "=r")
1399        (subreg:HI (match_dup 1) 2))]
1400  "TARGET_40_PLUS"
1401  "")
1402
1403(define_insn ""
1404  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 2)
1405	(mod:HI (match_operand:SI 1 "general_operand" "0")
1406		(match_operand:HI 2 "general_operand" "g")))]
1407  "TARGET_40_PLUS"
1408  "div %2,%0"
1409  [(set_attr "length" "4")])
1410
1411;(define_expand "divmodhi4"
1412;  [(parallel [(set (subreg:HI (match_dup 1) 0)
1413;	           (div:HI (match_operand:SI 1 "register_operand" "0")
1414;		           (match_operand:HI 2 "general_operand" "g")))
1415;              (set (subreg:HI (match_dup 1) 2)
1416;	           (mod:HI (match_dup 1)
1417;		           (match_dup 2)))])
1418;   (set (match_operand:HI 3 "register_operand" "=r")
1419;        (subreg:HI (match_dup 1) 2))
1420;   (set (match_operand:HI 0 "register_operand" "=r")
1421;        (subreg:HI (match_dup 1) 0))]
1422;  "TARGET_40_PLUS"
1423;  "")
1424;
1425;(define_insn ""
1426;  [(set (subreg:HI (match_operand:SI 0 "register_operand" "=r") 0)
1427;	           (div:HI (match_operand:SI 1 "general_operand" "0")
1428;		           (match_operand:HI 2 "general_operand" "g")))
1429;   (set (subreg:HI (match_dup 0) 2)
1430;	           (mod:HI (match_dup 1)
1431;		           (match_dup 2)))]
1432;  "TARGET_40_PLUS"
1433;  "div %2, %0")
1434;
1435
1436;; is rotate doing the right thing to be included here ????
1437