OSDN Git Service

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