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