OSDN Git Service

Emit MMIX function prologue and epilogue as rtl.
[pf3gnuchains/gcc-fork.git] / gcc / config / mmix / mmix.md
1 ;; GCC machine description for MMIX
2 ;; Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
3 ;; Contributed by Hans-Peter Nilsson (hp@bitrange.com)
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 2, 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 COPYING.  If not, write to
19 ;; the Free Software Foundation, 59 Temple Place - Suite 330,
20 ;; Boston, MA 02111-1307, USA.
21
22 ;; The original PO technology requires these to be ordered by speed,
23 ;; so that assigner will pick the fastest.
24
25 ;; See file "rtl.def" for documentation on define_insn, match_*, et al.
26
27 ;; Uses of UNSPEC in this file:
28 ;; UNSPEC_VOLATILE:
29 ;;
30 ;;      0       sync_icache (sync icache before trampoline jump)
31 ;;      1       nonlocal_goto_receiver
32 ;;
33
34 ;; The order of insns is as in Node: Standard Names, with smaller modes
35 ;; before bigger modes.
36
37 (define_constants
38   [(MMIX_rJ_REGNUM 259)
39    (MMIX_fp_rO_OFFSET -24)]
40 )
41
42 ;; FIXME: Can we remove the reg-to-reg for smaller modes?  Shouldn't they
43 ;; be synthesized ok?
44 (define_insn "movqi"
45   [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r ,r,x ,r,r,m,??r")
46         (match_operand:QI 1 "general_operand"       "r,LS,K,rI,x,m,r,n"))]
47   ""
48   "@
49    SET %0,%1
50    %s1 %0,%v1
51    NEGU %0,0,%n1
52    PUT %0,%1
53    GET %0,%1
54    LDB%U0 %0,%1
55    STBU %1,%0
56    %r0%I1")
57
58 (define_insn "movhi"
59   [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r ,r ,x,r,r,m,??r")
60         (match_operand:HI 1 "general_operand"       "r,LS,K,r,x,m,r,n"))]
61   ""
62   "@
63    SET %0,%1
64    %s1 %0,%v1
65    NEGU %0,0,%n1
66    PUT %0,%1
67    GET %0,%1
68    LDW%U0 %0,%1
69    STWU %1,%0
70    %r0%I1")
71
72 ;; gcc.c-torture/compile/920428-2.c fails if there's no "n".
73 (define_insn "movsi"
74   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r ,r,x,r,r,m,??r")
75         (match_operand:SI 1 "general_operand"       "r,LS,K,r,x,m,r,n"))]
76   ""
77   "@
78    SET %0,%1
79    %s1 %0,%v1
80    NEGU %0,0,%n1
81    PUT %0,%1
82    GET %0,%1
83    LDT%U0 %0,%1
84    STTU %1,%0
85    %r0%I1")
86
87 ;; We assume all "s" are addresses.  Does that hold?
88 (define_insn "movdi"
89   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r ,r,x,r,m,r,m,r,r,??r")
90         (match_operand:DI 1 "general_operand"       "r,LS,K,r,x,I,m,r,R,s,n"))]
91   ""
92   "@
93    SET %0,%1
94    %s1 %0,%v1
95    NEGU %0,0,%n1
96    PUT %0,%1
97    GET %0,%1
98    STCO %1,%0
99    LDO %0,%1
100    STOU %1,%0
101    GETA %0,%1
102    LDA %0,%1
103    %r0%I1")
104
105 ;; Note that we move around the float as a collection of bits; no
106 ;; conversion to double.
107 (define_insn "movsf"
108  [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r")
109        (match_operand:SF 1 "general_operand"       "r,G,r,x,m,r,F"))]
110   ""
111   "@
112    SET %0,%1
113    SETL %0,0
114    PUT %0,%1
115    GET %0,%1
116    LDT %0,%1
117    STTU %1,%0
118    %r0%I1")
119
120 (define_insn "movdf"
121   [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,x,r,r,m,??r")
122         (match_operand:DF 1 "general_operand"       "r,G,r,x,m,r,F"))]
123   ""
124   "@
125    SET %0,%1
126    SETL %0,0
127    PUT %0,%1
128    GET %0,%1
129    LDO %0,%1
130    STOU %1,%0
131    %r0%I1")
132 \f
133 (define_insn "adddi3"
134   [(set (match_operand:DI 0 "register_operand"  "=r,r,r")
135         (plus:DI
136          (match_operand:DI 1 "register_operand" "%r,r,0")
137          (match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,K,LS")))]
138   ""
139   "@
140    ADDU %0,%1,%2
141    SUBU %0,%1,%n2
142    %i2 %0,%v2")
143
144 (define_insn "adddf3"
145   [(set (match_operand:DF 0 "register_operand" "=r")
146         (plus:DF (match_operand:DF 1 "register_operand" "%r")
147                  (match_operand:DF 2 "register_operand" "r")))]
148   ""
149   "FADD %0,%1,%2")
150
151 ;; Insn canonicalization *should* have removed the need for an integer
152 ;; in operand 2.
153 (define_insn "subdi3"
154   [(set (match_operand:DI 0 "register_operand" "=r,r")
155         (minus:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "r,I")
156                   (match_operand:DI 2 "register_operand" "r,r")))]
157   ""
158   "@
159    SUBU %0,%1,%2
160    NEGU %0,%1,%2")
161
162 (define_insn "subdf3"
163   [(set (match_operand:DF 0 "register_operand" "=r")
164         (minus:DF (match_operand:DF 1 "register_operand" "r")
165                   (match_operand:DF 2 "register_operand" "r")))]
166   ""
167   "FSUB %0,%1,%2")
168
169 ;; FIXME: Should we define_expand and match 2, 4, 8 (etc) with shift (or
170 ;; %{something}2ADDU %0,%1,0)?  Hopefully GCC should still handle it, so
171 ;; we don't have to taint the machine description.  If results are bad
172 ;; enough, we may have to do it anyway.
173 (define_insn "muldi3"
174   [(set (match_operand:DI 0 "register_operand" "=r,r")
175         (mult:DI (match_operand:DI 1 "register_operand" "%r,r")
176                  (match_operand:DI 2 "mmix_reg_or_8bit_operand" "O,rI")))
177    (clobber (match_scratch:DI 3 "=X,z"))]
178   ""
179   "@
180    %m2ADDU %0,%1,%1
181    MULU %0,%1,%2")
182
183 (define_insn "muldf3"
184   [(set (match_operand:DF 0 "register_operand" "=r")
185         (mult:DF (match_operand:DF 1 "register_operand" "r")
186                  (match_operand:DF 2 "register_operand" "r")))]
187   ""
188   "FMUL %0,%1,%2")
189
190 (define_insn "divdf3"
191   [(set (match_operand:DF 0 "register_operand" "=r")
192         (div:DF (match_operand:DF 1 "register_operand" "r")
193                 (match_operand:DF 2 "register_operand" "r")))]
194   ""
195   "FDIV %0,%1,%2")
196
197 ;; FIXME: Is "frem" doing the right operation for moddf3?
198 (define_insn "moddf3"
199   [(set (match_operand:DF 0 "register_operand" "=r")
200         (mod:DF (match_operand:DF 1 "register_operand" "r")
201                 (match_operand:DF 2 "register_operand" "r")))]
202   ""
203   "FREM %0,%1,%2")
204
205 ;; FIXME: Should we define_expand for smin, smax, umin, umax using a
206 ;; nifty conditional sequence?
207
208 ;; FIXME: The cuter andn combinations don't get here, presumably because
209 ;; they ended up in the constant pool.  Check: still?
210 (define_insn "anddi3"
211   [(set (match_operand:DI 0 "register_operand" "=r,r")
212         (and:DI
213          (match_operand:DI 1 "register_operand" "%r,0")
214          (match_operand:DI 2 "mmix_reg_or_constant_operand" "rI,NT")))]
215   ""
216   "@
217    AND %0,%1,%2
218    %A2 %0,%V2")
219
220 (define_insn "iordi3"
221   [(set (match_operand:DI 0 "register_operand" "=r,r")
222         (ior:DI (match_operand:DI 1 "register_operand" "%r,0")
223                 (match_operand:DI 2 "mmix_reg_or_constant_operand" "rH,LS")))]
224   ""
225   "@
226    OR %0,%1,%2
227    %o2 %0,%v2")
228
229 (define_insn "xordi3"
230   [(set (match_operand:DI 0 "register_operand" "=r")
231         (xor:DI (match_operand:DI 1 "register_operand" "%r")
232                 (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
233   ""
234   "XOR %0,%1,%2")
235 \f
236 ;; FIXME:  When TImode works for other reasons (like cross-compiling from
237 ;; a 32-bit host), add back umulditi3 and umuldi3_highpart here.
238
239 ;; FIXME: Check what's really reasonable for the mod part.
240
241 ;; One day we might persuade GCC to expand divisions with constants the
242 ;; way MMIX does; giving the remainder the sign of the divisor.  But even
243 ;; then, it might be good to have an option to divide the way "everybody
244 ;; else" does.  Perhaps then, this option can be on by default.  However,
245 ;; it's not likely to happen because major (C, C++, Fortran) language
246 ;; standards in effect at 2002-04-29 reportedly demand that the sign of
247 ;; the remainder must follow the sign of the dividend.
248
249 (define_insn "divmoddi4"
250   [(set (match_operand:DI 0 "register_operand" "=r")
251         (div:DI (match_operand:DI 1 "register_operand" "r")
252                 (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))
253    (set (match_operand:DI 3 "register_operand" "=y")
254         (mod:DI (match_dup 1) (match_dup 2)))]
255   ;; Do the library stuff later.
256   "TARGET_KNUTH_DIVISION"
257   "DIV %0,%1,%2")
258
259 (define_insn "udivmoddi4"
260   [(set (match_operand:DI 0 "register_operand" "=r")
261         (udiv:DI (match_operand:DI 1 "register_operand" "r")
262                  (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))
263    (set (match_operand:DI 3 "register_operand" "=y")
264         (umod:DI (match_dup 1) (match_dup 2)))]
265   ""
266   "DIVU %0,%1,%2")
267
268 (define_expand "divdi3"
269   [(parallel
270     [(set (match_operand:DI 0 "register_operand" "=&r")
271           (div:DI (match_operand:DI 1 "register_operand" "r")
272                   (match_operand:DI 2 "register_operand" "r")))
273      (clobber (scratch:DI))
274      (clobber (scratch:DI))])]
275   "! TARGET_KNUTH_DIVISION"
276   "")
277
278 ;; The %2-is-%1-case is there just to make sure things don't fail.  Could
279 ;; presumably happen with optimizations off; no evidence.
280 (define_insn "*divdi3_nonknuth"
281   [(set (match_operand:DI 0 "register_operand" "=&r,r")
282         (div:DI (match_operand:DI 1 "register_operand" "r,r")
283                 (match_operand:DI 2 "register_operand" "1,r")))
284    (clobber (match_scratch:DI 3 "=1,1"))
285    (clobber (match_scratch:DI 4 "=2,2"))]
286   "! TARGET_KNUTH_DIVISION"
287   "@
288    SETL %0,1
289    XOR $255,%1,%2\;NEGU %0,0,%2\;CSN %2,%2,%0\;NEGU %0,0,%1\;CSN %1,%1,%0\;\
290 DIVU %0,%1,%2\;NEGU %1,0,%0\;CSN %0,$255,%1")
291
292 (define_expand "moddi3"
293   [(parallel
294     [(set (match_operand:DI 0 "register_operand" "=&r")
295           (mod:DI (match_operand:DI 1 "register_operand" "r")
296                   (match_operand:DI 2 "register_operand" "r")))
297      (clobber (scratch:DI))
298      (clobber (scratch:DI))])]
299   "! TARGET_KNUTH_DIVISION"
300   "")
301
302 ;; The %2-is-%1-case is there just to make sure things don't fail.  Could
303 ;; presumably happen with optimizations off; no evidence.
304 (define_insn "*moddi3_nonknuth"
305   [(set (match_operand:DI 0 "register_operand" "=&r,r")
306         (mod:DI (match_operand:DI 1 "register_operand" "r,r")
307                 (match_operand:DI 2 "register_operand" "1,r")))
308    (clobber (match_scratch:DI 3 "=1,1"))
309    (clobber (match_scratch:DI 4 "=2,2"))]
310   "! TARGET_KNUTH_DIVISION"
311   "@
312    SETL %0,0
313    NEGU %0,0,%2\;CSN %2,%2,%0\;NEGU $255,0,%1\;CSN %1,%1,$255\;\
314 DIVU %1,%1,%2\;GET %0,:rR\;NEGU %2,0,%0\;CSNN %0,$255,%2")
315 \f
316 (define_insn "ashldi3"
317   [(set (match_operand:DI 0 "register_operand" "=r")
318         (ashift:DI
319          (match_operand:DI 1 "register_operand" "r")
320          (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
321   ""
322   "SLU %0,%1,%2")
323
324 (define_insn "ashrdi3"
325   [(set (match_operand:DI 0 "register_operand" "=r")
326         (ashiftrt:DI
327          (match_operand:DI 1 "register_operand" "r")
328          (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
329   ""
330   "SR %0,%1,%2")
331
332 (define_insn "lshrdi3"
333   [(set (match_operand:DI 0 "register_operand" "=r")
334         (lshiftrt:DI
335          (match_operand:DI 1 "register_operand" "r")
336          (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
337   ""
338   "SRU %0,%1,%2")
339
340 (define_insn "negdi2"
341   [(set (match_operand:DI 0 "register_operand" "=r")
342         (neg:DI (match_operand:DI 1 "register_operand" "r")))]
343   ""
344   "NEGU %0,0,%1")
345
346 ;; FIXME: GCC should be able to synthesize this by itself as "0.0 - x".
347 (define_expand "negdf2"
348   [(set (match_operand:DF 0 "register_operand" "=r")
349         (minus:DF (match_dup 2)
350                 (match_operand:DF 1 "register_operand" "r")))]
351   ""
352   "operands[2] = force_reg (DFmode, CONST0_RTX (DFmode));")
353
354 ;; FIXME: define_expand for absdi2?
355
356 (define_insn "absdf2"
357   [(set (match_operand:DF 0 "register_operand" "=r")
358         (abs:DF (match_operand:DF 1 "register_operand" "0")))]
359   ""
360   "ANDNH %0,#8000")
361
362 (define_insn "sqrtdf2"
363   [(set (match_operand:DF 0 "register_operand" "=r")
364         (sqrt:DF (match_operand:DF 1 "register_operand" "r")))]
365   ""
366   "FSQRT %0,%1")
367
368 ;; FIXME: define_expand for ffssi2? (not ffsdi2 since int is SImode).
369
370 (define_insn "one_cmpldi2"
371   [(set (match_operand:DI 0 "register_operand" "=r")
372         (not:DI (match_operand:DI 1 "register_operand" "r")))]
373   ""
374   "NOR %0,%1,0")
375 \f
376 ;; Since we don't have cc0, we do what is recommended in the manual;
377 ;; store away the operands for use in the branch, scc or movcc insn.
378 (define_expand "cmpdi"
379   [(match_operand:DI 0 "register_operand" "")
380    (match_operand:DI 1 "mmix_reg_or_8bit_operand" "")]
381   ""
382   "
383 {
384   mmix_compare_op0 = operands[0];
385   mmix_compare_op1 = operands[1];
386   DONE;
387 }")
388
389 (define_expand "cmpdf"
390   [(match_operand:DF 0 "register_operand" "")
391    (match_operand:DF 1 "register_operand" "")]
392   ""
393   "
394 {
395   mmix_compare_op0 = operands[0];
396   mmix_compare_op1 = operands[1];
397   DONE;
398 }")
399
400 ;; When the user-patterns expand, the resulting insns will match the
401 ;; patterns below.
402
403 ;; We can fold the signed-compare where the register value is
404 ;; already equal to (compare:CCTYPE (reg) (const_int 0)).
405 ;;  We can't do that at all for floating-point, due to NaN, +0.0
406 ;; and -0.0, and we can only do it for the non/zero test of
407 ;; unsigned, so that has to be done another way.
408 ;;  FIXME: Perhaps a peep2 changing CCcode to a new code, that
409 ;; gets folded here.
410 (define_insn "*cmpcc_folded"
411   [(set (match_operand:CC 0 "register_operand" "=r")
412         (compare:CC
413          (match_operand:DI 1 "register_operand" "r")
414          (const_int 0)))]
415   ;; FIXME: Can we test equivalence any other way?
416   ;; FIXME: Can we fold any other way?
417   "REGNO (operands[1]) == REGNO (operands[0])"
418   "%% folded: cmp %0,%1,0")
419
420 (define_insn "*cmpcc"
421   [(set (match_operand:CC 0 "register_operand" "=r")
422         (compare:CC
423          (match_operand:DI 1 "register_operand" "r")
424          (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
425   ""
426   "CMP %0,%1,%2")
427
428 (define_insn "*cmpu"
429   [(set (match_operand:CC_UNS 0 "register_operand" "=r")
430         (compare:CC_UNS
431          (match_operand:DI 1 "register_operand" "r")
432          (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI")))]
433   ""
434   "CMPU %0,%1,%2")
435
436 (define_insn "*fcmp"
437   [(set (match_operand:CC_FP 0 "register_operand" "=r")
438         (compare:CC_FP
439          (match_operand:DF 1 "register_operand" "r")
440          (match_operand:DF 2 "register_operand" "r")))]
441   ""
442   "FCMP%e0 %0,%1,%2")
443
444 ;; FIXME: for -mieee, add fsub %0,%1,%1\;fsub %0,%2,%2 before to
445 ;; make signalling compliant.
446 (define_insn "*feql"
447   [(set (match_operand:CC_FPEQ 0 "register_operand" "=r")
448         (compare:CC_FPEQ
449          (match_operand:DF 1 "register_operand" "r")
450          (match_operand:DF 2 "register_operand" "r")))]
451   ""
452   "FEQL%e0 %0,%1,%2")
453
454 (define_insn "*fun"
455   [(set (match_operand:CC_FUN 0 "register_operand" "=r")
456         (compare:CC_FUN
457          (match_operand:DF 1 "register_operand" "r")
458          (match_operand:DF 2 "register_operand" "r")))]
459   ""
460   "FUN%e0 %0,%1,%2")
461 \f
462 ;; In order to get correct rounding, we have to use SFLOT and SFLOTU for
463 ;; conversion.  They do not convert to SFmode; they convert to DFmode,
464 ;; with rounding as of SFmode.  They are not usable as is, but we pretend
465 ;; we have a single instruction but emit two.
466
467 ;; Note that this will (somewhat unexpectedly) create an inexact
468 ;; exception if rounding is necessary - has to be masked off in crt0?
469 (define_expand "floatdisf2"
470   [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm")
471                    (float:SF
472                     (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
473               ;; Let's use a DI scratch, since SF don't generally get into
474               ;; registers.  Dunno what's best; it's really a DF, but that
475               ;; doesn't logically follow from operands in the pattern.
476               (clobber (match_scratch:DI 2 "=&r"))])]
477   ""
478   "
479 {
480   if (GET_CODE (operands[0]) != MEM)
481     {
482       rtx stack_slot;
483
484       /* FIXME: This stack-slot remains even at -O3.  There must be a
485          better way.  */
486       stack_slot
487         = validize_mem (assign_stack_temp (SFmode,
488                                            GET_MODE_SIZE (SFmode), 0));
489       emit_insn (gen_floatdisf2 (stack_slot, operands[1]));
490       emit_move_insn (operands[0], stack_slot);
491       DONE;
492     }
493 }")
494
495 (define_insn "*floatdisf2_real"
496   [(set (match_operand:SF 0 "memory_operand" "=m")
497         (float:SF
498          (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
499    (clobber (match_scratch:DI 2 "=&r"))]
500   ""
501   "SFLOT %2,%1\;STSF %2,%0")
502
503 (define_expand "floatunsdisf2"
504   [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "=rm")
505                    (unsigned_float:SF
506                     (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
507               ;; Let's use a DI scratch, since SF don't generally get into
508               ;; registers.  Dunno what's best; it's really a DF, but that
509               ;; doesn't logically follow from operands in the pattern.
510               (clobber (scratch:DI))])]
511   ""
512   "
513 {
514   if (GET_CODE (operands[0]) != MEM)
515     {
516       rtx stack_slot;
517
518       /* FIXME: This stack-slot remains even at -O3.  Must be a better
519          way.  */
520       stack_slot
521         = validize_mem (assign_stack_temp (SFmode,
522                                            GET_MODE_SIZE (SFmode), 0));
523       emit_insn (gen_floatunsdisf2 (stack_slot, operands[1]));
524       emit_move_insn (operands[0], stack_slot);
525       DONE;
526     }
527 }")
528
529 (define_insn "*floatunsdisf2_real"
530   [(set (match_operand:SF 0 "memory_operand" "=m")
531         (unsigned_float:SF
532          (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))
533    (clobber (match_scratch:DI 2 "=&r"))]
534   ""
535   "SFLOTU %2,%1\;STSF %2,%0")
536
537 ;; Note that this will (somewhat unexpectedly) create an inexact
538 ;; exception if rounding is necessary - has to be masked off in crt0?
539 (define_insn "floatdidf2"
540   [(set (match_operand:DF 0 "register_operand" "=r")
541         (float:DF
542          (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))]
543   ""
544   "FLOT %0,%1")
545
546 (define_insn "floatunsdidf2"
547   [(set (match_operand:DF 0 "register_operand" "=r")
548         (unsigned_float:DF
549          (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI")))]
550   ""
551   "FLOTU %0,%1")
552
553 (define_insn "ftruncdf2"
554   [(set (match_operand:DF 0 "register_operand" "=r")
555         (fix:DF (match_operand:DF 1 "register_operand" "r")))]
556   ""
557   ;; ROUND_OFF
558   "FINT %0,1,%1")
559
560 ;; Note that this will (somewhat unexpectedly) create an inexact
561 ;; exception if rounding is necessary - has to be masked off in crt0?
562 (define_insn "fix_truncdfdi2"
563   [(set (match_operand:DI 0 "register_operand" "=r")
564         (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "r"))))]
565   ""
566   ;; ROUND_OFF
567   "FIX %0,1,%1")
568
569 (define_insn "fixuns_truncdfdi2"
570   [(set (match_operand:DI 0 "register_operand" "=r")
571         (unsigned_fix:DI
572          (unsigned_fix:DF (match_operand:DF 1 "register_operand" "r"))))]
573   ""
574   ;; ROUND_OFF
575   "FIXU %0,1,%1")
576
577 ;; It doesn't seem like it's possible to have memory_operand as a
578 ;; predicate here (testcase: libgcc2 floathisf).  FIXME:  Shouldn't it be
579 ;; possible to do that?  Bug in GCC?  Anyway, this used to be a simple
580 ;; pattern with a memory_operand predicate, but was split up with a
581 ;; define_expand with the old pattern as "anonymous".
582 ;; FIXME: Perhaps with SECONDARY_MEMORY_NEEDED?
583 (define_expand "truncdfsf2"
584   [(set (match_operand:SF 0 "memory_operand" "")
585         (float_truncate:SF (match_operand:DF 1 "register_operand" "")))]
586   ""
587   "
588 {
589   if (GET_CODE (operands[0]) != MEM)
590     {
591       /* FIXME: There should be a way to say: 'put this in operands[0]
592          but *after* the expanded insn'.  */
593       rtx stack_slot;
594
595       /* There is no sane destination but a register here, if it wasn't
596          already MEM.  (It's too hard to get fatal_insn to work here.)  */
597       if (! REG_P (operands[0]))
598         internal_error (\"MMIX Internal: Bad truncdfsf2 expansion\");
599
600       /* FIXME: This stack-slot remains even at -O3.  Must be a better
601          way.  */
602       stack_slot
603         = validize_mem (assign_stack_temp (SFmode,
604                                            GET_MODE_SIZE (SFmode), 0));
605       emit_insn (gen_truncdfsf2 (stack_slot, operands[1]));
606       emit_move_insn (operands[0], stack_slot);
607       DONE;
608     }
609 }")
610
611 (define_insn "*truncdfsf2_real"
612   [(set (match_operand:SF 0 "memory_operand" "=m")
613         (float_truncate:SF (match_operand:DF 1 "register_operand" "r")))]
614   ""
615   "STSF %1,%0")
616
617 ;; Same comment as for truncdfsf2.
618 (define_expand "extendsfdf2"
619   [(set (match_operand:DF 0 "register_operand" "=r")
620         (float_extend:DF (match_operand:SF 1 "memory_operand" "m")))]
621   ""
622   "
623 {
624   if (GET_CODE (operands[1]) != MEM)
625     {
626       rtx stack_slot;
627
628       /* There is no sane destination but a register here, if it wasn't
629          already MEM.  (It's too hard to get fatal_insn to work here.)  */
630       if (! REG_P (operands[0]))
631         internal_error (\"MMIX Internal: Bad extendsfdf2 expansion\");
632
633       /* FIXME: This stack-slot remains even at -O3.  There must be a
634          better way.  */
635       stack_slot
636         = validize_mem (assign_stack_temp (SFmode,
637                                            GET_MODE_SIZE (SFmode), 0));
638       emit_move_insn (stack_slot, operands[1]);
639       emit_insn (gen_extendsfdf2 (operands[0], stack_slot));
640       DONE;
641     }
642 }")
643
644 (define_insn "*extendsfdf2_real"
645   [(set (match_operand:DF 0 "register_operand" "=r")
646         (float_extend:DF (match_operand:SF 1 "memory_operand" "m")))]
647   ""
648   "LDSF %0,%1")
649 \f
650 ;; Neither sign-extend nor zero-extend are necessary; gcc knows how to
651 ;; synthesize using shifts or and, except with a memory source and not
652 ;; completely optimal.  FIXME: Actually, other bugs surface when those
653 ;; patterns are defined; fix later.
654
655 ;; There are no sane values with the bit-patterns of (int) 0..255 except
656 ;; 0 to use in movdfcc.
657
658 (define_expand "movdfcc"
659   [(set (match_operand:DF 0 "register_operand" "")
660         (if_then_else:DF
661          (match_operand 1 "comparison_operator" "")
662          (match_operand:DF 2 "mmix_reg_or_0_operand" "")
663          (match_operand:DF 3 "mmix_reg_or_0_operand" "")))]
664   ""
665   "
666 {
667   enum rtx_code code = GET_CODE (operands[1]);
668   rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0,
669                                      mmix_compare_op1);
670   if (cc_reg == NULL_RTX)
671     FAIL;
672   operands[1] = gen_rtx (code, VOIDmode, cc_reg, const0_rtx);
673 }")
674
675 (define_expand "movdicc"
676   [(set (match_operand:DI 0 "register_operand" "")
677         (if_then_else:DI
678          (match_operand 1 "comparison_operator" "")
679          (match_operand:DI 2 "mmix_reg_or_8bit_operand" "")
680          (match_operand:DI 3 "mmix_reg_or_8bit_operand" "")))]
681   ""
682   "
683 {
684   enum rtx_code code = GET_CODE (operands[1]);
685   rtx cc_reg = mmix_gen_compare_reg (code, mmix_compare_op0,
686                                      mmix_compare_op1);
687   if (cc_reg == NULL_RTX)
688     FAIL;
689   operands[1] = gen_rtx (code, VOIDmode, cc_reg, const0_rtx);
690 }")
691
692 ;; FIXME: Is this the right way to do "folding" of CCmode -> DImode?
693 (define_insn "*movdicc_real_foldable"
694   [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
695         (if_then_else:DI
696          (match_operator 2 "mmix_foldable_comparison_operator"
697                          [(match_operand 3 "register_operand" "r,r,r,r")
698                           (const_int 0)])
699          (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM")
700          (match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))]
701   ""
702   "@
703    CS%d2 %0,%3,%1
704    CS%D2 %0,%3,%4
705    ZS%d2 %0,%3,%1
706    ZS%D2 %0,%3,%4")
707
708 (define_insn "*movdicc_real"
709   [(set
710     (match_operand:DI 0 "register_operand"         "=r ,r ,r ,r")
711     (if_then_else:DI
712      (match_operator
713       2 "mmix_comparison_operator"
714       [(match_operand 3 "mmix_reg_cc_operand"       "r ,r ,r ,r")
715       (const_int 0)])
716      (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI,0 ,rI,GM")
717      (match_operand:DI 4 "mmix_reg_or_8bit_operand" "0 ,rI,GM,rI")))]
718   ""
719   "@
720    CS%d2 %0,%3,%1
721    CS%D2 %0,%3,%4
722    ZS%d2 %0,%3,%1
723    ZS%D2 %0,%3,%4")
724
725 (define_insn "*movdfcc_real_foldable"
726   [(set
727     (match_operand:DF 0 "register_operand"      "=r  ,r  ,r  ,r")
728     (if_then_else:DF
729      (match_operator
730       2 "mmix_foldable_comparison_operator"
731       [(match_operand 3 "register_operand"       "r  ,r  ,r  ,r")
732       (const_int 0)])
733      (match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0  ,rGM,GM")
734      (match_operand:DF 4 "mmix_reg_or_0_operand" "0  ,rGM,GM ,rGM")))]
735   ""
736   "@
737    CS%d2 %0,%3,%1
738    CS%D2 %0,%3,%4
739    ZS%d2 %0,%3,%1
740    ZS%D2 %0,%3,%4")
741
742 (define_insn "*movdfcc_real"
743   [(set
744     (match_operand:DF 0 "register_operand"      "=r  ,r  ,r  ,r")
745     (if_then_else:DF
746      (match_operator
747       2 "mmix_comparison_operator"
748       [(match_operand 3 "mmix_reg_cc_operand"    "r  ,r  ,r  ,r")
749       (const_int 0)])
750      (match_operand:DF 1 "mmix_reg_or_0_operand" "rGM,0  ,rGM,GM")
751      (match_operand:DF 4 "mmix_reg_or_0_operand" "0  ,rGM,GM ,rGM")))]
752   ""
753   "@
754    CS%d2 %0,%3,%1
755    CS%D2 %0,%3,%4
756    ZS%d2 %0,%3,%1
757    ZS%D2 %0,%3,%4")
758
759 ;; FIXME: scc patterns will probably help, I just skip them
760 ;; right now.  Revisit.
761 \f
762 (define_expand "beq"
763   [(set (pc)
764         (if_then_else (eq (match_dup 1) (const_int 0))
765                       (label_ref (match_operand 0 "" ""))
766                       (pc)))]
767   ""
768   "
769 {
770   operands[1]
771     = mmix_gen_compare_reg (EQ, mmix_compare_op0, mmix_compare_op1);
772 }")
773
774 (define_expand "bne"
775   [(set (pc)
776         (if_then_else (ne (match_dup 1) (const_int 0))
777                       (label_ref (match_operand 0 "" ""))
778                       (pc)))]
779   ""
780   "
781 {
782   operands[1]
783     = mmix_gen_compare_reg (NE, mmix_compare_op0, mmix_compare_op1);
784 }")
785
786 (define_expand "bgt"
787   [(set (pc)
788         (if_then_else (gt (match_dup 1) (const_int 0))
789                       (label_ref (match_operand 0 "" ""))
790                       (pc)))]
791   ""
792   "
793 {
794   operands[1]
795     = mmix_gen_compare_reg (GT, mmix_compare_op0, mmix_compare_op1);
796 }")
797
798 (define_expand "ble"
799   [(set (pc)
800         (if_then_else (le (match_dup 1) (const_int 0))
801                       (label_ref (match_operand 0 "" ""))
802                       (pc)))]
803   ""
804   "
805 {
806   operands[1]
807     = mmix_gen_compare_reg (LE, mmix_compare_op0, mmix_compare_op1);
808
809   /* The head comment of optabs.c:can_compare_p says we're required to
810      implement this, so we have to clean up the mess here. */
811   if (operands[1] == NULL_RTX)
812     {
813       /* FIXME: Watch out for sharing/unsharing of rtx:es.  */
814       emit_jump_insn ((*bcc_gen_fctn[(int) LT]) (operands[0]));
815       emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (operands[0]));
816       DONE;
817     }
818 }")
819
820 (define_expand "bge"
821   [(set (pc)
822         (if_then_else (ge (match_dup 1) (const_int 0))
823                       (label_ref (match_operand 0 "" ""))
824                       (pc)))]
825   ""
826   "
827 {
828   operands[1]
829     = mmix_gen_compare_reg (GE, mmix_compare_op0, mmix_compare_op1);
830
831   /* The head comment of optabs.c:can_compare_p says we're required to
832      implement this, so we have to clean up the mess here. */
833   if (operands[1] == NULL_RTX)
834     {
835       /* FIXME: Watch out for sharing/unsharing of rtx:es.  */
836       emit_jump_insn ((*bcc_gen_fctn[(int) GT]) (operands[0]));
837       emit_jump_insn ((*bcc_gen_fctn[(int) EQ]) (operands[0]));
838       DONE;
839     }
840 }")
841
842 (define_expand "blt"
843   [(set (pc)
844         (if_then_else (lt (match_dup 1) (const_int 0))
845                       (label_ref (match_operand 0 "" ""))
846                       (pc)))]
847   ""
848   "
849 {
850   operands[1]
851     = mmix_gen_compare_reg (LT, mmix_compare_op0, mmix_compare_op1);
852 }")
853
854 (define_expand "bgtu"
855   [(set (pc)
856         (if_then_else (gtu (match_dup 1) (const_int 0))
857                       (label_ref (match_operand 0 "" ""))
858                       (pc)))]
859   ""
860   "
861 {
862   operands[1]
863     = mmix_gen_compare_reg (GTU, mmix_compare_op0, mmix_compare_op1);
864 }")
865
866 (define_expand "bleu"
867   [(set (pc)
868         (if_then_else (leu (match_dup 1) (const_int 0))
869                       (label_ref (match_operand 0 "" ""))
870                       (pc)))]
871   ""
872   "
873 {
874   operands[1]
875     = mmix_gen_compare_reg (LEU, mmix_compare_op0, mmix_compare_op1);
876 }")
877
878 (define_expand "bgeu"
879   [(set (pc)
880         (if_then_else (geu (match_dup 1) (const_int 0))
881                       (label_ref (match_operand 0 "" ""))
882                       (pc)))]
883   ""
884   "
885 {
886   operands[1]
887     = mmix_gen_compare_reg (GEU, mmix_compare_op0, mmix_compare_op1);
888 }")
889
890 (define_expand "bltu"
891   [(set (pc)
892         (if_then_else (ltu (match_dup 1) (const_int 0))
893                       (label_ref (match_operand 0 "" ""))
894                       (pc)))]
895   ""
896   "
897 {
898   operands[1]
899     = mmix_gen_compare_reg (LTU, mmix_compare_op0, mmix_compare_op1);
900 }")
901
902 (define_expand "bunordered"
903   [(set (pc)
904         (if_then_else (unordered (match_dup 1) (const_int 0))
905                       (label_ref (match_operand 0 "" ""))
906                       (pc)))]
907   ""
908   "
909 {
910   operands[1]
911     = mmix_gen_compare_reg (UNORDERED, mmix_compare_op0, mmix_compare_op1);
912
913   if (operands[1] == NULL_RTX)
914     FAIL;
915 }")
916
917 (define_expand "bordered"
918   [(set (pc)
919         (if_then_else (ordered (match_dup 1) (const_int 0))
920                       (label_ref (match_operand 0 "" ""))
921                       (pc)))]
922   ""
923   "
924 {
925   operands[1]
926     = mmix_gen_compare_reg (ORDERED, mmix_compare_op0, mmix_compare_op1);
927 }")
928
929 ;; FIXME: we can emit an unordered-or-*not*-equal compare in one insn, but
930 ;; there's no RTL code for it.  Maybe revisit in future.
931
932 ;; FIXME: Odd/Even matchers?
933 (define_insn "*bCC_foldable"
934   [(set (pc)
935         (if_then_else
936          (match_operator 1 "mmix_foldable_comparison_operator"
937                          [(match_operand 2 "register_operand" "r")
938                           (const_int 0)])
939          (label_ref (match_operand 0 "" ""))
940          (pc)))]
941   ""
942   "%+B%d1 %2,%0")
943
944 (define_insn "*bCC"
945   [(set (pc)
946         (if_then_else
947          (match_operator 1 "mmix_comparison_operator"
948                          [(match_operand 2 "mmix_reg_cc_operand" "r")
949                           (const_int 0)])
950          (label_ref (match_operand 0 "" ""))
951          (pc)))]
952   ""
953   "%+B%d1 %2,%0")
954
955 (define_insn "*bCC_inverted_foldable"
956   [(set (pc)
957         (if_then_else
958          (match_operator 1 "mmix_foldable_comparison_operator"
959                          [(match_operand 2 "register_operand" "r")
960                           (const_int 0)])
961                       (pc)
962                       (label_ref (match_operand 0 "" ""))))]
963 ;; REVERSIBLE_CC_MODE is checked by mmix_foldable_comparison_operator.
964   ""
965   "%+B%D1 %2,%0")
966
967 (define_insn "*bCC_inverted"
968   [(set (pc)
969         (if_then_else
970          (match_operator 1 "mmix_comparison_operator"
971                          [(match_operand 2 "mmix_reg_cc_operand" "r")
972                           (const_int 0)])
973          (pc)
974          (label_ref (match_operand 0 "" ""))))]
975   "REVERSIBLE_CC_MODE (GET_MODE (operands[2]))"
976   "%+B%D1 %2,%0")
977 \f
978 (define_expand "call"
979   [(parallel [(call (match_operand:QI 0 "memory_operand" "")
980                     (match_operand 1 "general_operand" ""))
981               (use (match_operand 2 "general_operand" ""))
982               (clobber (match_dup 4))])
983    (set (match_dup 4) (match_dup 3))]
984   ""
985   "
986 {
987   /* Since the epilogue 'uses' the return address, and it is clobbered
988      in the call, and we set it back after every call (all but one setting
989      will be optimized away), integrity is maintained.  */
990   operands[3]
991     = mmix_get_hard_reg_initial_val (Pmode,
992                                      MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
993
994   /* FIXME: There's a bug in gcc which causes NULL to be passed as
995      operand[2] when we get out of registers, which later confuses gcc.
996      Work around it by replacing it with const_int 0.  Possibly documentation
997      error too.  */
998   if (operands[2] == NULL_RTX)
999     operands[2] = const0_rtx;
1000
1001   operands[4] = gen_rtx_REG (DImode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
1002 }")
1003
1004 (define_expand "call_value"
1005   [(parallel [(set (match_operand 0 "" "")
1006                    (call (match_operand:QI 1 "memory_operand" "")
1007                          (match_operand 2 "general_operand" "")))
1008               (use (match_operand 3 "general_operand" ""))
1009               (clobber (match_dup 5))])
1010    (set (match_dup 5) (match_dup 4))]
1011   ""
1012   "
1013 {
1014   /* Since the epilogue 'uses' the return address, and it is clobbered
1015      in the call, and we set it back after every call (all but one setting
1016      will be optimized away), integrity is maintained.  */
1017   operands[4]
1018     = mmix_get_hard_reg_initial_val (Pmode,
1019                                      MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
1020
1021   /* FIXME: See 'call'.  */
1022   if (operands[3] == NULL_RTX)
1023     operands[3] = const0_rtx;
1024
1025   /* FIXME: Documentation bug: operands[3] (operands[2] for 'call') is the
1026      *next* argument register, not the number of arguments in registers.
1027      (There used to be code here where that mattered.)  */
1028
1029   operands[5] = gen_rtx_REG (DImode, MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
1030 }")
1031
1032 ;; Don't use 'p' here.  A 'p' must stand first in constraints, or reload
1033 ;; messes up, not registering the address for reload.  Several C++
1034 ;; test-cases, including g++.brendan/crash40.C.  FIXME: This is arguably a
1035 ;; bug in gcc.  Note line ~2612 in reload.c, that does things on the
1036 ;; condition <<else if (constraints[i][0] == 'p')>> and the comment on
1037 ;; ~3017 that says:
1038 ;; <<   case 'p':
1039 ;;           /* All necessary reloads for an address_operand
1040 ;;              were handled in find_reloads_address.  */>>
1041 ;; Sorry, I have not dug deeper.  If symbolic addresses are used
1042 ;; rarely compared to addresses in registers, disparaging the
1043 ;; first ("p") alternative by adding ? in the first operand
1044 ;; might do the trick.  We define 'U' as a synonym to 'p', but without the
1045 ;; caveats (and very small advantages) of 'p'.
1046 (define_insn "*call_real"
1047   [(call (mem:QI
1048           (match_operand:DI 0 "mmix_symbolic_or_address_operand" "s,rU"))
1049          (match_operand 1 "" ""))
1050    (use (match_operand 2 "" ""))
1051    (clobber (reg:DI MMIX_rJ_REGNUM))]
1052   ""
1053   "@
1054    PUSHJ $%p2,%0
1055    PUSHGO $%p2,%a0")
1056
1057 (define_insn "*call_value_real"
1058   [(set (match_operand 0 "register_operand" "=r,r")
1059         (call (mem:QI
1060                (match_operand:DI 1 "mmix_symbolic_or_address_operand" "s,rU"))
1061               (match_operand 2 "" "")))
1062   (use (match_operand 3 "" ""))
1063   (clobber (reg:DI MMIX_rJ_REGNUM))]
1064   ""
1065   "@
1066    PUSHJ $%p3,%1
1067    PUSHGO $%p3,%a1")
1068
1069 ;; I hope untyped_call and untyped_return are not needed for MMIX.
1070 ;; Users of Objective C will notice.
1071
1072 ; Generated by GCC.
1073 (define_expand "return"
1074   [(return)]
1075   "mmix_use_simple_return ()"
1076   "")
1077
1078 ; Generated by the epilogue expander.
1079 (define_insn "*expanded_return"
1080   [(return)]
1081   ""
1082   "POP %.,0")
1083
1084 (define_expand "prologue"
1085   [(const_int 0)]
1086   ""
1087   "mmix_expand_prologue (); DONE;")
1088
1089 ; Note that the (return) from the expander itself is always the last insn
1090 ; in the epilogue.
1091 (define_expand "epilogue"
1092   [(return)]
1093   ""
1094   "mmix_expand_epilogue ();")
1095
1096 (define_insn "nop"
1097   [(const_int 0)]
1098   ""
1099   "SWYM 0,0,0")
1100
1101 (define_insn "jump"
1102   [(set (pc) (label_ref (match_operand 0 "" "")))]
1103   ""
1104   "JMP %0")
1105
1106 (define_insn "indirect_jump"
1107   [(set (pc) (match_operand 0 "address_operand" "p"))]
1108   ""
1109   "GO $255,%a0")
1110
1111 ;; FIXME: This is just a jump, and should be expanded to one.
1112 (define_insn "tablejump"
1113   [(set (pc) (match_operand:DI 0 "address_operand" "p"))
1114    (use (label_ref (match_operand 1 "" "")))]
1115   ""
1116   "GO $255,%a0")
1117
1118 ;; The only peculiar thing is that the register stack has to be unwound at
1119 ;; nonlocal_goto_receiver.  At each function that has a nonlocal label, we
1120 ;; save at function entry the location of the "alpha" register stack
1121 ;; pointer, rO, in a stack slot known to that function (right below where
1122 ;; the frame-pointer would be located).
1123 ;; In the nonlocal goto receiver, we unwind the register stack by a series
1124 ;; of "pop 0,0" until rO equals the saved value.  (If it goes lower, we
1125 ;; should call abort.)
1126 (define_expand "nonlocal_goto_receiver"
1127   [(parallel [(unspec_volatile [(const_int 0)] 1)
1128               (clobber (scratch:DI))
1129               (clobber (reg:DI MMIX_rJ_REGNUM))])
1130    (set (reg:DI MMIX_rJ_REGNUM) (match_dup 0))]
1131   ""
1132   "
1133 {
1134   operands[0]
1135     = mmix_get_hard_reg_initial_val (Pmode,
1136                                      MMIX_INCOMING_RETURN_ADDRESS_REGNUM);
1137
1138   /* Mark this function as containing a landing-pad.  */
1139   cfun->machine->has_landing_pad = 1;
1140 }")
1141
1142 ;; GCC can insist on using saved registers to keep the slot address in
1143 ;; "across" the exception, or (perhaps) to use saved registers in the
1144 ;; address and re-use them after the register stack unwind, so it's best
1145 ;; to form the address ourselves.
1146 (define_insn "*nonlocal_goto_receiver_expanded"
1147   [(unspec_volatile [(const_int 0)] 1)
1148    (clobber (match_scratch:DI 0 "=&r"))
1149    (clobber (reg:DI MMIX_rJ_REGNUM))]
1150   ""
1151 {
1152   rtx temp_reg = operands[0];
1153   rtx my_operands[2];
1154   HOST_WIDEST_INT offs;
1155   const char *my_template
1156     = "GETA $255,0f\;PUT rJ,$255\;LDOU $255,%a0\n\
1157 0:\;GET %1,rO\;CMPU %1,%1,$255\;BNP %1,1f\;POP 0,0\n1:";
1158
1159   my_operands[1] = temp_reg;
1160
1161   /* If we have a frame-pointer (hence unknown stack-pointer offset),
1162      just use the frame-pointer and the known offset.  */
1163   if (frame_pointer_needed)
1164     {
1165       my_operands[0] = GEN_INT (-MMIX_fp_rO_OFFSET);
1166
1167       output_asm_insn ("NEGU %1,0,%0", my_operands);
1168       my_operands[0] = gen_rtx_PLUS (Pmode, frame_pointer_rtx, temp_reg);
1169     }
1170   else
1171     {
1172       /* We know the fp-based offset, so "eliminate" it to be sp-based.  */
1173       offs
1174         = (mmix_initial_elimination_offset (MMIX_FRAME_POINTER_REGNUM,
1175                                             MMIX_STACK_POINTER_REGNUM)
1176            + MMIX_fp_rO_OFFSET);
1177
1178       if (offs >= 0 && offs <= 255)
1179         my_operands[0]
1180           = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offs));
1181       else
1182         {
1183           mmix_output_register_setting (asm_out_file, REGNO (temp_reg),
1184                                         offs, 1);
1185           my_operands[0] = gen_rtx_PLUS (Pmode, stack_pointer_rtx, temp_reg);
1186         }
1187     }
1188
1189   output_asm_insn (my_template, my_operands);
1190   return "";
1191 })
1192 \f
1193 (define_insn "*Naddu"
1194   [(set (match_operand:DI 0 "register_operand" "=r")
1195         (plus:DI (mult:DI (match_operand:DI 1 "register_operand" "r")
1196                           (match_operand:DI 2 "const_int_operand" "n"))
1197                  (match_operand:DI 3 "mmix_reg_or_8bit_operand" "rI")))]
1198   "GET_CODE (operands[2]) == CONST_INT
1199    && (INTVAL (operands[2]) == 2
1200        || INTVAL (operands[2]) == 4
1201        || INTVAL (operands[2]) == 8
1202        || INTVAL (operands[2]) == 16)"
1203   "%2ADDU %0,%1,%3")
1204
1205 (define_insn "*andn"
1206   [(set (match_operand:DI 0 "register_operand" "=r")
1207         (and:DI
1208          (not:DI (match_operand:DI 1 "mmix_reg_or_8bit_operand" "rI"))
1209          (match_operand:DI 2 "register_operand" "r")))]
1210   ""
1211   "ANDN %0,%2,%1")
1212
1213 (define_insn "*nand"
1214   [(set (match_operand:DI 0 "register_operand" "=r")
1215         (ior:DI
1216          (not:DI (match_operand:DI 1 "register_operand" "%r"))
1217          (not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
1218   ""
1219   "NAND %0,%1,%2")
1220
1221 (define_insn "*nor"
1222   [(set (match_operand:DI 0 "register_operand" "=r")
1223         (and:DI
1224          (not:DI (match_operand:DI 1 "register_operand" "%r"))
1225          (not:DI (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
1226   ""
1227   "NOR %0,%1,%2")
1228
1229 (define_insn "*nxor"
1230   [(set (match_operand:DI 0 "register_operand" "=r")
1231         (not:DI
1232          (xor:DI (match_operand:DI 1 "register_operand" "%r")
1233                  (match_operand:DI 2 "mmix_reg_or_8bit_operand" "rI"))))]
1234   ""
1235   "NXOR %0,%1,%2")
1236
1237 (define_insn "sync_icache"
1238   [(unspec_volatile [(match_operand:DI 0 "memory_operand" "m")
1239                      (match_operand:DI 1 "const_int_operand" "I")] 0)]
1240   ""
1241   "SYNCID %1,%0")
1242
1243 ;; Local Variables:
1244 ;; mode: lisp
1245 ;; indent-tabs-mode: t
1246 ;; End: