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