]>
Commit | Line | Data |
---|---|---|
c6243b4c | 1 | ;; XSTORMY16 Machine description template |
e03f5d43 | 2 | ;; Copyright (C) 1997, 1998, 1999, 2001, 2002 Free Software Foundation, Inc. |
4b58290f GK |
3 | ;; Contributed by Red Hat, Inc. |
4 | ||
5 | ;; This file is part of GNU CC. | |
6 | ||
7 | ;; GNU CC is free software; you can redistribute it and/or modify | |
8 | ;; it under the terms of the GNU General Public License as published by | |
9 | ;; the Free Software Foundation; either version 2, or (at your option) | |
10 | ;; any later version. | |
11 | ||
12 | ;; GNU CC 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 GNU CC; see the file COPYING. If not, write to | |
19 | ;; the Free Software Foundation, 59 Temple Place - Suite 330, | |
20 | ;; Boston, MA 02111-1307, USA. | |
21 | ||
22 | ;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. | |
23 | ||
24 | \f | |
25 | ;; :::::::::::::::::::: | |
26 | ;; :: | |
27 | ;; :: Attributes | |
28 | ;; :: | |
29 | ;; :::::::::::::::::::: | |
30 | ||
31 | ; Categorize branches for the conditional in the length attribute. | |
32 | (define_attr "branch_class" "notdirectbranch,br12,bcc12,bcc8p2,bcc8p4" | |
33 | (const_string "notdirectbranch")) | |
34 | ||
35 | ; The length of an instruction, used for branch shortening. | |
36 | (define_attr "length" "" | |
37 | (cond | |
38 | [(eq_attr "branch_class" "br12") | |
39 | (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2046)) | |
40 | (lt (minus (match_dup 0) (pc)) (const_int 2048))) | |
41 | (const_int 2) | |
42 | (const_int 4)) | |
43 | (eq_attr "branch_class" "bcc12") | |
44 | (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -2044)) | |
45 | (lt (minus (match_dup 0) (pc)) (const_int 2048))) | |
46 | (const_int 4) | |
47 | (const_int 8)) | |
48 | (eq_attr "branch_class" "bcc8p2") | |
49 | (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -124)) | |
50 | (lt (minus (match_dup 0) (pc)) (const_int 128))) | |
51 | (const_int 4) | |
52 | (const_int 8)) | |
53 | (eq_attr "branch_class" "bcc8p4") | |
54 | (if_then_else (and (ge (minus (match_dup 0) (pc)) (const_int -122)) | |
55 | (lt (minus (match_dup 0) (pc)) (const_int 128))) | |
56 | (const_int 6) | |
57 | (const_int 10))] | |
58 | (const_int 2))) | |
59 | ||
60 | ; The operand which determines the setting of Rpsw. | |
61 | ; The numbers indicate the operand number, | |
62 | ; 'clobber' indicates it is changed in some unspecified way | |
63 | ; 'nop' means it is not changed. | |
64 | (define_attr "psw_operand" "clobber,nop,0,1,2,3,4" (const_string "0")) | |
65 | ||
66 | (define_asm_attributes [(set_attr "length" "4") | |
67 | (set_attr "psw_operand" "clobber")]) | |
68 | ||
69 | \f | |
70 | ;; :::::::::::::::::::: | |
71 | ;; :: | |
72 | ;; :: Moves | |
73 | ;; :: | |
74 | ;; :::::::::::::::::::: | |
75 | ||
76 | (define_expand "movqi" | |
77 | [(set (match_operand:QI 0 "nonimmediate_operand" "") | |
78 | (match_operand:QI 1 "general_operand" ""))] | |
79 | "" | |
c6243b4c | 80 | "{ xstormy16_expand_move (QImode, operands[0], operands[1]); DONE; }") |
4b58290f GK |
81 | |
82 | (define_insn "*movqi_internal" | |
83 | [(set (match_operand:QI 0 "nonimmediate_operand" "=r,Q,r,m,e,e,T,r,S") | |
84 | (match_operand:QI 1 "general_operand" "r,r,R,e,m,i,i,i,i"))] | |
85 | "" | |
86 | "@ | |
87 | mov %0,%1 | |
88 | push %1 | |
89 | pop %0 | |
90 | mov.b %0,%1 | |
91 | mov.b %0,%1 | |
92 | mov %0,%1 | |
93 | mov Rx,%1 | |
94 | mov %0,%1 | |
95 | mov.b %0,%1" | |
96 | [(set_attr_alternative "length" | |
97 | [(const_int 2) | |
98 | (const_int 2) | |
99 | (const_int 2) | |
100 | (if_then_else (match_operand:QI 0 "short_memory_operand" "") | |
101 | (const_int 2) | |
102 | (const_int 4)) | |
103 | (if_then_else (match_operand:QI 1 "short_memory_operand" "") | |
104 | (const_int 2) | |
105 | (const_int 4)) | |
106 | (const_int 2) | |
107 | (const_int 2) | |
108 | (const_int 4) | |
109 | (const_int 4)]) | |
110 | (set_attr "psw_operand" "0,nop,nop,0,0,0,nop,0,nop")]) | |
111 | ||
112 | (define_expand "movhi" | |
113 | [(set (match_operand:HI 0 "nonimmediate_operand" "") | |
114 | (match_operand:HI 1 "general_operand" ""))] | |
115 | "" | |
c6243b4c | 116 | "{ xstormy16_expand_move (HImode, operands[0], operands[1]); DONE; }") |
4b58290f GK |
117 | |
118 | (define_insn "*movhi_internal" | |
119 | [(set (match_operand:HI 0 "nonimmediate_operand" "=r,Q,r,m,e,e,T,r,S") | |
120 | (match_operand:HI 1 "general_operand" "r,r,R,e,m,L,L,i,i"))] | |
121 | "" | |
122 | "@ | |
123 | mov %0,%1 | |
124 | push %1 | |
125 | pop %0 | |
126 | mov.w %0,%1 | |
127 | mov.w %0,%1 | |
128 | mov.w %0,%1 | |
129 | mov.w Rx,%1 | |
130 | mov.w %0,%1 | |
131 | mov.w %0,%1" | |
132 | [(set_attr_alternative "length" | |
133 | [(const_int 2) | |
134 | (const_int 2) | |
135 | (const_int 2) | |
136 | (if_then_else (match_operand:QI 0 "short_memory_operand" "") | |
137 | (const_int 2) | |
138 | (const_int 4)) | |
139 | (if_then_else (match_operand:QI 1 "short_memory_operand" "") | |
140 | (const_int 2) | |
141 | (const_int 4)) | |
142 | (const_int 2) | |
143 | (const_int 2) | |
144 | (const_int 4) | |
145 | (const_int 4)]) | |
146 | (set_attr "psw_operand" "0,nop,nop,0,0,0,nop,0,nop")]) | |
147 | ||
148 | (define_expand "movsi" | |
149 | [(set (match_operand:SI 0 "nonimmediate_operand" "") | |
150 | (match_operand:SI 1 "general_operand" ""))] | |
151 | "" | |
c6243b4c | 152 | "{ xstormy16_expand_move (SImode, operands[0], operands[1]); DONE; }") |
4b58290f GK |
153 | |
154 | (define_insn_and_split "*movsi_internal" | |
155 | [(set (match_operand:SI 0 "nonimmediate_operand" "=r,Q,r,m,e,&e,e,r,S") | |
156 | (match_operand:SI 1 "general_operand" "r,r,R,e,o, V,L,i,i"))] | |
157 | "" | |
158 | "#" | |
159 | "reload_completed" | |
160 | [(pc)] | |
c6243b4c | 161 | "{ xstormy16_split_move (SImode, operands[0], operands[1]); DONE; }" |
4b58290f GK |
162 | [(set_attr_alternative "length" |
163 | [(const_int 4) | |
164 | (const_int 4) | |
165 | (const_int 4) | |
166 | (if_then_else (match_operand:QI 0 "short_memory_operand" "") | |
167 | (const_int 6) | |
168 | (const_int 8)) | |
169 | (if_then_else (match_operand:QI 1 "short_memory_operand" "") | |
170 | (const_int 6) | |
171 | (const_int 8)) | |
172 | (if_then_else (match_operand:QI 1 "short_memory_operand" "") | |
173 | (const_int 6) | |
174 | (const_int 8)) | |
175 | (const_int 4) | |
176 | (const_int 8) | |
177 | (const_int 8)])]) | |
178 | ||
179 | \f | |
180 | ;; :::::::::::::::::::: | |
181 | ;; :: | |
182 | ;; :: Conversions | |
183 | ;; :: | |
184 | ;; :::::::::::::::::::: | |
185 | ||
186 | (define_insn "extendqihi2" | |
187 | [(set (match_operand:HI 0 "register_operand" "=r") | |
188 | (sign_extend:HI (match_operand:QI 1 "register_operand" "0")))] | |
189 | "" | |
190 | "cbw %0") | |
191 | ||
192 | \f | |
193 | ;; :::::::::::::::::::: | |
194 | ;; :: | |
195 | ;; :: Bit field extraction | |
196 | ;; :: | |
197 | ;; :::::::::::::::::::: | |
198 | ||
199 | ;; Extract an unsigned bit field | |
200 | ;(define_insn "extzv" | |
201 | ; [(set (match_operand:SI 0 "register_operand" "=r") | |
202 | ; (zero_extract:SI (match_operand:SI 1 "register_operand" "r") | |
203 | ; (match_operand:SI 2 "const_int_operand" "n") | |
204 | ; (match_operand:SI 3 "const_int_operand" "n")))] | |
205 | ; "" | |
206 | ; "extzv %0,%1,%2,%3" | |
207 | ; [(set_attr "length" "4")]) | |
208 | ||
209 | ;; Insert a bit field | |
210 | ;(define_insn "insv" | |
211 | ; [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+r") | |
212 | ; (match_operand:SI 1 "const_int_operand" "n") | |
213 | ; (match_operand:SI 2 "const_int_operand" "n")) | |
214 | ; (match_operand:SI 3 "nonmemory_operand" "ri"))] | |
215 | ; "" | |
216 | ; "insv %0,%1,%2,%3" | |
217 | ; [(set_attr "length" "4")]) | |
218 | ||
219 | \f | |
220 | ;; :::::::::::::::::::: | |
221 | ;; :: | |
222 | ;; :: 16 bit Integer arithmetic | |
223 | ;; :: | |
224 | ;; :::::::::::::::::::: | |
225 | ||
226 | ;; Addition | |
227 | ; Operand 3 is marked earlyclobber because that helps reload | |
228 | ; to generate better code---this pattern will never need the | |
229 | ; carry register as an input, and some output reloads or input | |
230 | ; reloads might need to use it. In fact, without the '&' reload | |
231 | ; will fail in some cases. | |
232 | (define_insn "addhi3" | |
233 | [(set (match_operand:HI 0 "register_operand" "=r,r,T,T,r,r,r") | |
234 | (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0,0,0") | |
235 | (match_operand:HI 2 "nonmemory_operand" "O,P,L,M,Ir,N,i"))) | |
236 | (clobber (match_scratch:BI 3 "=X,X,&y,&y,&y,&y,&y"))] | |
237 | "" | |
238 | "@ | |
239 | inc %0,%o2 | |
240 | dec %0,%O2 | |
241 | add Rx,%2 | |
242 | sub Rx,#%n2 | |
243 | add %0,%2 | |
244 | sub %0,#%n2 | |
245 | add %0,%2" | |
246 | [(set_attr "length" "2,2,2,2,2,2,4")]) | |
247 | ||
248 | ; Reload can generate addition operations. The SECONDARY_RELOAD_CLASS | |
249 | ; macro causes it to allocate the carry register; this pattern | |
250 | ; shows it how to place the register in RTL to make the addition work. | |
251 | (define_expand "reload_inhi" | |
252 | [(parallel [(set (match_operand:HI 0 "register_operand" "=r") | |
c6243b4c | 253 | (match_operand:HI 1 "xstormy16_carry_plus_operand" "")) |
4b58290f GK |
254 | (clobber (match_operand:BI 2 "" "=&y"))])] |
255 | "" | |
256 | "if (! rtx_equal_p (operands[0], XEXP (operands[1], 0))) | |
257 | { | |
258 | emit_insn (gen_rtx_SET (VOIDmode, operands[0], XEXP (operands[1], 0))); | |
259 | operands[1] = gen_rtx_PLUS (GET_MODE (operands[1]), operands[0], | |
260 | XEXP (operands[1], 1)); | |
261 | } | |
262 | ") | |
263 | ||
264 | (define_insn "addchi4" | |
265 | [(set (match_operand:HI 0 "register_operand" "=T,r,r") | |
266 | (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0") | |
267 | (match_operand:HI 2 "nonmemory_operand" "L,Ir,i"))) | |
268 | (set (match_operand:BI 3 "register_operand" "=y,y,y") | |
269 | (truncate:BI (lshiftrt:SI (plus:SI (zero_extend:SI (match_dup 1)) | |
270 | (zero_extend:SI (match_dup 2))) | |
271 | (const_int 16))))] | |
272 | "" | |
273 | "@ | |
274 | add Rx,%2 | |
275 | add %0,%2 | |
276 | add %0,%2" | |
277 | [(set_attr "length" "2,2,4")]) | |
278 | ||
279 | (define_insn "addchi5" | |
280 | [(set (match_operand:HI 0 "register_operand" "=T,r,r") | |
281 | (plus:HI (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0") | |
282 | (zero_extend:HI (match_operand:BI 3 | |
283 | "register_operand" | |
284 | "y,y,y"))) | |
285 | (match_operand:HI 2 "nonmemory_operand" "L,Ir,i"))) | |
286 | (set (match_operand:BI 4 "register_operand" "=y,y,y") | |
287 | (truncate:BI (lshiftrt:SI (plus:SI (plus:SI | |
288 | (zero_extend:SI (match_dup 1)) | |
289 | (zero_extend:SI (match_dup 3))) | |
290 | (zero_extend:SI (match_dup 2))) | |
291 | (const_int 16))))] | |
292 | "" | |
293 | "@ | |
294 | adc Rx,%2 | |
295 | adc %0,%2 | |
296 | adc %0,%2" | |
297 | [(set_attr "length" "2,2,4")]) | |
298 | ||
299 | ;; Subtraction | |
300 | ; Operand 3 is marked earlyclobber because that helps reload | |
301 | ; to generate better code---this pattern will never need the | |
302 | ; carry register as an input, and some output reloads or input | |
303 | ; reloads might need to use it. In fact, without the '&' reload | |
304 | ; will fail in some cases. | |
305 | (define_insn "subhi3" | |
306 | [(set (match_operand:HI 0 "register_operand" "=r,r,T,T,r,r,r") | |
307 | (minus:HI (match_operand:HI 1 "register_operand" "0,0,0,0,0,0,0") | |
308 | (match_operand:HI 2 "nonmemory_operand" "O,P,L,M,rI,M,i"))) | |
309 | (clobber (match_scratch:BI 3 "=X,X,&y,&y,&y,&y,&y"))] | |
310 | "" | |
311 | "@ | |
312 | dec %0,%o2 | |
313 | inc %0,%O2 | |
314 | sub Rx,%2 | |
315 | add Rx,#%n2 | |
316 | sub %0,%2 | |
317 | add %0,#%n2 | |
318 | sub %0,%2" | |
319 | [(set_attr "length" "2,2,2,2,2,2,4")]) | |
320 | ||
321 | (define_insn "subchi4" | |
322 | [(set (match_operand:HI 0 "register_operand" "=T,r,r") | |
323 | (minus:HI (match_operand:HI 1 "register_operand" "0,0,0") | |
324 | (match_operand:HI 2 "nonmemory_operand" "L,Ir,i"))) | |
325 | (set (match_operand:BI 3 "register_operand" "=y,y,y") | |
326 | (truncate:BI (lshiftrt:SI (minus:SI (zero_extend:SI (match_dup 1)) | |
327 | (zero_extend:SI (match_dup 2))) | |
328 | (const_int 16))))] | |
329 | "" | |
330 | "@ | |
331 | sub Rx,%2 | |
332 | sub %0,%2 | |
333 | sub %0,%2" | |
334 | [(set_attr "length" "2,2,4")]) | |
335 | ||
336 | (define_insn "subchi5" | |
337 | [(set (match_operand:HI 0 "register_operand" "=T,r,r") | |
338 | (minus:HI (minus:HI (match_operand:HI 1 "register_operand" "0,0,0") | |
339 | (zero_extend:HI (match_operand:BI 3 | |
340 | "register_operand" | |
341 | "y,y,y"))) | |
342 | (match_operand:HI 2 "nonmemory_operand" "L,Ir,i"))) | |
343 | (set (match_operand:BI 4 "register_operand" "=y,y,y") | |
344 | (truncate:BI (lshiftrt:SI (minus:SI (minus:SI | |
345 | (zero_extend:SI (match_dup 1)) | |
346 | (zero_extend:SI (match_dup 3))) | |
347 | (zero_extend:SI (match_dup 2))) | |
348 | (const_int 16))))] | |
349 | "" | |
350 | "@ | |
351 | sbc Rx,%2 | |
352 | sbc %0,%2 | |
353 | sbc %0,%2" | |
354 | [(set_attr "length" "2,2,4")]) | |
355 | ||
356 | ; Basic multiplication | |
357 | (define_insn "mulhi3" | |
358 | [(set (match_operand:HI 0 "register_operand" "=a") | |
359 | (mult:HI (match_operand:HI 1 "register_operand" "%a") | |
360 | (match_operand:HI 2 "register_operand" "c"))) | |
361 | (clobber (match_scratch:HI 3 "=b")) | |
362 | ] | |
363 | "" | |
364 | "mul" | |
365 | [(set_attr "psw_operand" "nop")]) | |
366 | ||
367 | ;; Unsigned multiplication producing 64 bit results from 32 bit inputs | |
368 | ; The constraint on operand 0 is 't' because it is actually two regs | |
369 | ; long, and both regs must match the constraint. | |
370 | (define_insn "umulhisi3" | |
371 | [(set (match_operand:SI 0 "register_operand" "=t") | |
372 | (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%a")) | |
373 | (zero_extend:SI (match_operand:HI 2 "register_operand" "c")))) | |
374 | ] | |
375 | "" | |
376 | "mul" | |
377 | [(set_attr "psw_operand" "nop")]) | |
378 | ||
379 | ;; Unsigned division giving both quotient and remainder | |
380 | (define_insn "udivmodhi4" | |
381 | [(set (match_operand:HI 0 "register_operand" "=a") | |
ed09481d GK |
382 | (udiv:HI (match_operand:HI 1 "register_operand" "a") |
383 | (match_operand:HI 2 "register_operand" "c"))) | |
4b58290f | 384 | (set (match_operand:HI 3 "register_operand" "=b") |
ed09481d GK |
385 | (umod:HI (match_dup 1) |
386 | (match_dup 2)))] | |
4b58290f GK |
387 | "" |
388 | "div" | |
389 | [(set_attr "psw_operand" "nop")]) | |
390 | ||
391 | ;; Negation | |
392 | ||
393 | (define_expand "neghi2" | |
394 | [(set (match_operand:HI 0 "register_operand" "") | |
395 | (not:HI (match_operand:HI 1 "register_operand" ""))) | |
396 | (parallel [(set (match_dup 0) (plus:HI (match_dup 0) (const_int 1))) | |
397 | (clobber (match_scratch:BI 3 ""))])] | |
398 | "" | |
399 | "") | |
400 | ||
401 | \f | |
402 | ;; :::::::::::::::::::: | |
403 | ;; :: | |
404 | ;; :: 16 bit Integer Shifts and Rotates | |
405 | ;; :: | |
406 | ;; :::::::::::::::::::: | |
407 | ||
408 | ;; Arithmetic Shift Left | |
409 | (define_insn "ashlhi3" | |
410 | [(set (match_operand:HI 0 "register_operand" "=r") | |
411 | (ashift:HI (match_operand:HI 1 "register_operand" "0") | |
412 | (match_operand:HI 2 "nonmemory_operand" "ri"))) | |
413 | (clobber (match_scratch:BI 3 "=y"))] | |
414 | "" | |
415 | "shl %0,%2") | |
416 | ||
417 | ;; Arithmetic Shift Right | |
418 | (define_insn "ashrhi3" | |
419 | [(set (match_operand:HI 0 "register_operand" "=r") | |
420 | (ashiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
421 | (match_operand:HI 2 "nonmemory_operand" "ri"))) | |
422 | (clobber (match_scratch:BI 3 "=y"))] | |
423 | "" | |
424 | "asr %0,%2") | |
425 | ||
426 | ;; Logical Shift Right | |
427 | (define_insn "lshrhi3" | |
428 | [(set (match_operand:HI 0 "register_operand" "=r") | |
429 | (lshiftrt:HI (match_operand:HI 1 "register_operand" "0") | |
430 | (match_operand:HI 2 "nonmemory_operand" "ri"))) | |
431 | (clobber (match_scratch:BI 3 "=y"))] | |
432 | "" | |
433 | "shr %0,%2") | |
434 | ||
435 | \f | |
436 | ;; :::::::::::::::::::: | |
437 | ;; :: | |
438 | ;; :: 16 Bit Integer Logical operations | |
439 | ;; :: | |
440 | ;; :::::::::::::::::::: | |
441 | ||
442 | ;; Logical AND, 16 bit integers | |
443 | (define_insn "andhi3" | |
444 | [(set (match_operand:HI 0 "register_operand" "=T,r,r,r") | |
445 | (and:HI (match_operand:HI 1 "register_operand" "%0,0,0,0") | |
446 | (match_operand:HI 2 "nonmemory_operand" "L,r,K,i")))] | |
447 | "" | |
448 | "@ | |
449 | and Rx,%2 | |
450 | and %0,%2 | |
451 | clr1 %0,%B2 | |
452 | and %0,%2" | |
453 | [(set_attr "length" "2,2,2,4")]) | |
454 | ||
455 | ;; Inclusive OR, 16 bit integers | |
456 | (define_insn "iorhi3" | |
457 | [(set (match_operand:HI 0 "register_operand" "=T,r,r,r") | |
458 | (ior:HI (match_operand:HI 1 "register_operand" "%0,0,0,0") | |
459 | (match_operand:HI 2 "nonmemory_operand" "L,r,J,i")))] | |
460 | "" | |
461 | "@ | |
462 | or Rx,%2 | |
463 | or %0,%2 | |
464 | set1 %0,%B2 | |
465 | or %0,%2" | |
466 | [(set_attr "length" "2,2,2,4")]) | |
467 | ||
468 | ;; Exclusive OR, 16 bit integers | |
469 | (define_insn "xorhi3" | |
470 | [(set (match_operand:HI 0 "register_operand" "=T,r,r") | |
471 | (xor:HI (match_operand:HI 1 "register_operand" "%0,0,0") | |
472 | (match_operand:HI 2 "nonmemory_operand" "L,r,i")))] | |
473 | "" | |
474 | "@ | |
475 | xor Rx,%2 | |
476 | xor %0,%2 | |
477 | xor %0,%2" | |
478 | [(set_attr "length" "2,2,4")]) | |
479 | ||
480 | ;; One's complement, 16 bit integers | |
481 | (define_insn "one_cmplhi2" | |
482 | [(set (match_operand:HI 0 "register_operand" "=r") | |
483 | (not:HI (match_operand:HI 1 "register_operand" "0")))] | |
484 | "" | |
485 | "not %0") | |
486 | ||
487 | \f | |
488 | ;; :::::::::::::::::::: | |
489 | ;; :: | |
490 | ;; :: 32 bit Integer arithmetic | |
491 | ;; :: | |
492 | ;; :::::::::::::::::::: | |
493 | ||
494 | ;; Addition | |
495 | (define_insn_and_split "addsi3" | |
496 | [(set (match_operand:SI 0 "register_operand" "=r") | |
497 | (plus:SI (match_operand:SI 1 "register_operand" "%0") | |
498 | (match_operand:SI 2 "nonmemory_operand" "ri"))) | |
499 | (clobber (match_scratch:BI 3 "=y"))] | |
500 | "" | |
501 | "#" | |
502 | "reload_completed" | |
503 | [(pc)] | |
c6243b4c | 504 | "{ xstormy16_expand_arith (SImode, PLUS, operands[0], operands[1], |
4b58290f GK |
505 | operands[2], operands[3]); DONE; } " |
506 | [(set_attr "length" "4")]) | |
507 | ||
508 | ;; Subtraction | |
509 | (define_insn_and_split "subsi3" | |
510 | [(set (match_operand:SI 0 "register_operand" "=r") | |
511 | (minus:SI (match_operand:SI 1 "register_operand" "0") | |
512 | (match_operand:SI 2 "nonmemory_operand" "ri"))) | |
513 | (clobber (match_scratch:BI 3 "=y"))] | |
514 | "" | |
515 | "#" | |
516 | "reload_completed" | |
517 | [(pc)] | |
c6243b4c | 518 | "{ xstormy16_expand_arith (SImode, MINUS, operands[0], operands[1], |
4b58290f GK |
519 | operands[2], operands[3]); DONE; } " |
520 | [(set_attr "length" "4")]) | |
521 | ||
522 | (define_expand "negsi2" | |
523 | [(set (match_operand:SI 0 "register_operand" "") | |
524 | (neg:SI (match_operand:SI 1 "register_operand" "")))] | |
525 | "" | |
c6243b4c | 526 | "{ xstormy16_expand_arith (SImode, NEG, operands[0], const0_rtx, |
4b58290f GK |
527 | operands[1], gen_reg_rtx (BImode)); DONE; }") |
528 | ||
529 | ;; :::::::::::::::::::: | |
530 | ;; :: | |
531 | ;; :: 32 bit Integer Shifts and Rotates | |
532 | ;; :: | |
533 | ;; :::::::::::::::::::: | |
534 | ||
535 | ;; Arithmetic Shift Left | |
536 | (define_expand "ashlsi3" | |
537 | [(parallel [(set (match_operand:SI 0 "register_operand" "") | |
538 | (ashift:SI (match_operand:SI 1 "register_operand" "") | |
539 | (match_operand:SI 2 "const_int_operand" ""))) | |
540 | (clobber (match_dup 3)) | |
541 | (clobber (match_dup 4))])] | |
542 | "" | |
543 | " if (! const_int_operand (operands[2], SImode)) FAIL; | |
544 | operands[3] = gen_reg_rtx (BImode); operands[4] = gen_reg_rtx (HImode); ") | |
545 | ||
546 | ;; Arithmetic Shift Right | |
547 | (define_expand "ashrsi3" | |
548 | [(parallel [(set (match_operand:SI 0 "register_operand" "") | |
549 | (ashiftrt:SI (match_operand:SI 1 "register_operand" "") | |
550 | (match_operand:SI 2 "const_int_operand" ""))) | |
551 | (clobber (match_dup 3)) | |
552 | (clobber (match_dup 4))])] | |
553 | "" | |
554 | " if (! const_int_operand (operands[2], SImode)) FAIL; | |
555 | operands[3] = gen_reg_rtx (BImode); operands[4] = gen_reg_rtx (HImode); ") | |
556 | ||
557 | ;; Logical Shift Right | |
558 | (define_expand "lshrsi3" | |
559 | [(parallel [(set (match_operand:SI 0 "register_operand" "") | |
560 | (lshiftrt:SI (match_operand:SI 1 "register_operand" "") | |
561 | (match_operand:SI 2 "const_int_operand" ""))) | |
562 | (clobber (match_dup 3)) | |
563 | (clobber (match_dup 4))])] | |
564 | "" | |
565 | " if (! const_int_operand (operands[2], SImode)) FAIL; | |
566 | operands[3] = gen_reg_rtx (BImode); operands[4] = gen_reg_rtx (HImode); ") | |
567 | ||
568 | (define_insn "*shiftsi" | |
569 | [(set (match_operand:SI 0 "register_operand" "=r,r") | |
570 | (match_operator:SI 5 "shift_operator" | |
571 | [(match_operand:SI 1 "register_operand" "0,0") | |
572 | (match_operand:SI 2 "const_int_operand" "U,n")])) | |
573 | (clobber (match_operand:BI 3 "register_operand" "=y,y")) | |
574 | (clobber (match_operand:HI 4 "" "=X,r"))] | |
575 | "" | |
c6243b4c | 576 | "* return xstormy16_output_shift (SImode, GET_CODE (operands[5]), |
4b58290f GK |
577 | operands[0], operands[2], operands[4]);" |
578 | [(set_attr "length" "6,10") | |
579 | (set_attr "psw_operand" "clobber,clobber")]) | |
580 | ||
581 | \f | |
582 | ;; :::::::::::::::::::: | |
583 | ;; :: | |
584 | ;; :: Comparisons | |
585 | ;; :: | |
586 | ;; :::::::::::::::::::: | |
587 | ||
588 | ;; Note, we store the operands in the comparison insns, and use them later | |
589 | ;; when generating the branch or scc operation. | |
590 | ||
591 | ;; First the routines called by the machine independent part of the compiler | |
592 | (define_expand "cmphi" | |
593 | [(set (cc0) | |
594 | (compare (match_operand:HI 0 "register_operand" "") | |
595 | (match_operand:HI 1 "nonmemory_operand" "")))] | |
596 | "" | |
597 | " | |
598 | { | |
c6243b4c GK |
599 | xstormy16_compare_op0 = operands[0]; |
600 | xstormy16_compare_op1 = operands[1]; | |
4b58290f GK |
601 | DONE; |
602 | }") | |
603 | ||
604 | ; There are no real SImode comparisons, but some can be emulated | |
605 | ; by performing a SImode subtract and looking at the condition flags. | |
606 | (define_expand "cmpsi" | |
607 | [(set (cc0) | |
608 | (compare (match_operand:SI 0 "register_operand" "") | |
609 | (match_operand:SI 1 "nonmemory_operand" "")))] | |
610 | "" | |
611 | " | |
612 | { | |
c6243b4c GK |
613 | xstormy16_compare_op0 = operands[0]; |
614 | xstormy16_compare_op1 = operands[1]; | |
4b58290f GK |
615 | DONE; |
616 | }") | |
617 | ||
618 | \f | |
619 | ;; :::::::::::::::::::: | |
620 | ;; :: | |
621 | ;; :: Branches | |
622 | ;; :: | |
623 | ;; :::::::::::::::::::: | |
624 | ||
625 | (define_expand "beq" | |
626 | [(use (match_operand 0 "" ""))] | |
627 | "" | |
c6243b4c | 628 | "{ xstormy16_emit_cbranch (EQ, operands[0]); DONE; }") |
4b58290f GK |
629 | |
630 | (define_expand "bne" | |
631 | [(use (match_operand 0 "" ""))] | |
632 | "" | |
c6243b4c | 633 | "{ xstormy16_emit_cbranch (NE, operands[0]); DONE; }") |
4b58290f GK |
634 | |
635 | (define_expand "bge" | |
636 | [(use (match_operand 0 "" ""))] | |
637 | "" | |
c6243b4c | 638 | "{ xstormy16_emit_cbranch (GE, operands[0]); DONE; }") |
4b58290f GK |
639 | |
640 | (define_expand "bgt" | |
641 | [(use (match_operand 0 "" ""))] | |
642 | "" | |
c6243b4c | 643 | "{ xstormy16_emit_cbranch (GT, operands[0]); DONE; }") |
4b58290f GK |
644 | |
645 | (define_expand "ble" | |
646 | [(use (match_operand 0 "" ""))] | |
647 | "" | |
c6243b4c | 648 | "{ xstormy16_emit_cbranch (LE, operands[0]); DONE; }") |
4b58290f GK |
649 | |
650 | (define_expand "blt" | |
651 | [(use (match_operand 0 "" ""))] | |
652 | "" | |
c6243b4c | 653 | "{ xstormy16_emit_cbranch (LT, operands[0]); DONE; }") |
4b58290f GK |
654 | |
655 | (define_expand "bgeu" | |
656 | [(use (match_operand 0 "" ""))] | |
657 | "" | |
c6243b4c | 658 | "{ xstormy16_emit_cbranch (GEU, operands[0]); DONE; }") |
4b58290f GK |
659 | |
660 | (define_expand "bgtu" | |
661 | [(use (match_operand 0 "" ""))] | |
662 | "" | |
c6243b4c | 663 | "{ xstormy16_emit_cbranch (GTU, operands[0]); DONE; }") |
4b58290f GK |
664 | |
665 | (define_expand "bleu" | |
666 | [(use (match_operand 0 "" ""))] | |
667 | "" | |
c6243b4c | 668 | "{ xstormy16_emit_cbranch (LEU, operands[0]); DONE; }") |
4b58290f GK |
669 | |
670 | (define_expand "bltu" | |
671 | [(use (match_operand 0 "" ""))] | |
672 | "" | |
c6243b4c | 673 | "{ xstormy16_emit_cbranch (LTU, operands[0]); DONE; }") |
4b58290f GK |
674 | |
675 | ||
676 | (define_insn "*cbranchhi" | |
677 | [(set (pc) | |
678 | (if_then_else (match_operator:HI 1 "comparison_operator" | |
679 | [(match_operand:HI 2 "nonmemory_operand" | |
680 | "r,e,L") | |
681 | (match_operand:HI 3 "nonmemory_operand" | |
682 | "r,L,e")]) | |
683 | (label_ref (match_operand 0 "" "")) | |
684 | (pc))) | |
685 | (clobber (match_operand:BI 4 "" "=&y,&y,&y"))] | |
686 | "" | |
687 | "* | |
688 | { | |
c6243b4c | 689 | return xstormy16_output_cbranch_hi (operands[1], \"%l0\", 0, insn); |
4b58290f GK |
690 | }" |
691 | [(set_attr "branch_class" "bcc12") | |
692 | (set_attr "psw_operand" "0,0,1")]) | |
693 | ||
694 | (define_insn "*cbranchhi_neg" | |
695 | [(set (pc) | |
696 | (if_then_else (match_operator:HI 1 "comparison_operator" | |
697 | [(match_operand:HI 2 "nonmemory_operand" | |
698 | "r,e,L") | |
699 | (match_operand:HI 3 "nonmemory_operand" | |
700 | "r,L,e")]) | |
701 | (pc) | |
702 | (label_ref (match_operand 0 "" "")))) | |
703 | (clobber (match_operand:BI 4 "" "=&y,&y,&y"))] | |
704 | "" | |
705 | "* | |
706 | { | |
c6243b4c | 707 | return xstormy16_output_cbranch_hi (operands[1], \"%l0\", 1, insn); |
4b58290f GK |
708 | }" |
709 | [(set_attr "branch_class" "bcc12") | |
710 | (set_attr "psw_operand" "0,0,1")]) | |
711 | ||
712 | (define_insn "*eqbranchsi" | |
713 | [(set (pc) | |
714 | (if_then_else (match_operator:SI 1 "equality_operator" | |
715 | [(match_operand:SI 2 "register_operand" | |
716 | "+r") | |
717 | (const_int 0)]) | |
718 | (label_ref (match_operand 0 "" "")) | |
719 | (pc))) | |
720 | ;; Although I would greatly like the 'match_dup' in the following line | |
721 | ;; to actually be a register constraint, there is (at the time of writing) no | |
722 | ;; way for reload to insert an output reload on the edges out of a branch. | |
723 | ;; If reload is fixed to use insert_insn_on_edge, this can be changed. | |
724 | (clobber (match_dup 2))] | |
725 | "" | |
726 | "* | |
727 | { | |
c6243b4c | 728 | return xstormy16_output_cbranch_si (operands[1], \"%l0\", 0, insn); |
4b58290f GK |
729 | }" |
730 | [(set_attr "branch_class" "bcc8p2") | |
731 | (set_attr "psw_operand" "clobber")]) | |
732 | ||
733 | (define_insn_and_split "*ineqbranchsi" | |
734 | [(set (pc) | |
c6243b4c | 735 | (if_then_else (match_operator:SI 1 "xstormy16_ineqsi_operator" |
4b58290f GK |
736 | [(match_operand:SI 2 "register_operand" |
737 | "+r") | |
738 | (match_operand:SI 3 "nonmemory_operand" | |
739 | "ri")]) | |
740 | (label_ref (match_operand 0 "" "")) | |
741 | (pc))) | |
742 | ;; Although I would greatly like the 'match_dup' in the following line | |
743 | ;; to actually be a register constraint, there is (at the time of writing) no | |
744 | ;; way for reload to insert an output reload on the edges out of a branch. | |
745 | ;; If reload is fixed to use insert_insn_on_edge, this can be changed, | |
746 | ;; preferably to a 'minus' operand that explains the actual operation, like: | |
747 | ; (set (match_operand 5 "register_operand" "=2") | |
748 | ; (minus:SI (match_operand 6 "register_operand" "2") | |
749 | ; (match_operand 7 "register_operand" "3"))) | |
750 | (clobber (match_dup 2)) | |
751 | (clobber (match_operand:BI 4 "" "=&y"))] | |
752 | "" | |
753 | "#" | |
754 | "reload_completed" | |
755 | [(pc)] | |
c6243b4c | 756 | "{ xstormy16_split_cbranch (SImode, operands[0], operands[1], operands[2], |
4b58290f GK |
757 | operands[4]); DONE; }" |
758 | [(set_attr "length" "8")]) | |
759 | ||
760 | (define_insn "*ineqbranch_1" | |
761 | [(set (pc) | |
c6243b4c | 762 | (if_then_else (match_operator:HI 5 "xstormy16_ineqsi_operator" |
4b58290f GK |
763 | [(minus:HI (match_operand:HI 1 "register_operand" |
764 | "T,r,r") | |
765 | (zero_extend:HI (match_operand:BI 4 | |
766 | "register_operand" | |
767 | "y,y,y"))) | |
768 | (match_operand:HI 3 "nonmemory_operand" "L,Ir,i")]) | |
769 | (label_ref (match_operand 0 "" "")) | |
770 | (pc))) | |
771 | (set (match_operand:HI 2 "register_operand" "=2,2,2") | |
772 | (minus:HI (minus:HI (match_dup 1) (zero_extend:HI (match_dup 4))) | |
773 | (match_dup 3))) | |
774 | (clobber (match_operand:BI 6 "" "=y,y,y"))] | |
775 | "" | |
776 | "* | |
777 | { | |
c6243b4c | 778 | return xstormy16_output_cbranch_si (operands[5], \"%l0\", 0, insn); |
4b58290f GK |
779 | }" |
780 | [(set_attr "branch_class" "bcc8p2,bcc8p2,bcc8p4") | |
781 | (set_attr "psw_operand" "2,2,2")]) | |
782 | ||
783 | \f | |
784 | ;; :::::::::::::::::::: | |
785 | ;; :: | |
786 | ;; :: Call and branch instructions | |
787 | ;; :: | |
788 | ;; :::::::::::::::::::: | |
789 | ||
790 | ;; Subroutine call instruction returning no value. Operand 0 is the function | |
791 | ;; to call; operand 1 is the number of bytes of arguments pushed (in mode | |
792 | ;; `SImode', except it is normally a `const_int'); operand 2 is the number of | |
793 | ;; registers used as operands. | |
794 | ||
795 | ;; On most machines, operand 2 is not actually stored into the RTL pattern. It | |
796 | ;; is supplied for the sake of some RISC machines which need to put this | |
797 | ;; information into the assembler code; they can put it in the RTL instead of | |
798 | ;; operand 1. | |
799 | ||
800 | (define_expand "call" | |
801 | [(call (match_operand:HI 0 "memory_operand" "m") | |
802 | (match_operand 1 "" "")) | |
803 | (use (match_operand 2 "immediate_operand" ""))] | |
804 | "" | |
c6243b4c | 805 | "xstormy16_expand_call (NULL_RTX, operands[0], operands[1]); DONE;") |
4b58290f GK |
806 | |
807 | ;; Subroutine call instruction returning a value. Operand 0 is the hard | |
808 | ;; register in which the value is returned. There are three more operands, the | |
809 | ;; same as the three operands of the `call' instruction (but with numbers | |
810 | ;; increased by one). | |
811 | ||
812 | ;; Subroutines that return `BLKmode' objects use the `call' insn. | |
813 | ||
814 | (define_expand "call_value" | |
815 | [(set (match_operand 0 "register_operand" "=r") | |
816 | (call (match_operand:HI 1 "memory_operand" "m") | |
817 | (match_operand:SI 2 "" ""))) | |
818 | (use (match_operand 3 "immediate_operand" ""))] | |
819 | "" | |
c6243b4c | 820 | "xstormy16_expand_call (operands[0], operands[1], operands[2]); DONE;") |
4b58290f GK |
821 | |
822 | (define_insn "*call_internal" | |
823 | [(call (mem:HI (match_operand:HI 0 "nonmemory_operand" "i,r")) | |
824 | (match_operand 1 "" "")) | |
da6e254e | 825 | (use (match_operand:HI 2 "nonmemory_operand" "X,z"))] |
4b58290f GK |
826 | "" |
827 | "@ | |
828 | callf %C0 | |
829 | call %2,%0" | |
830 | [(set_attr "length" "4,2") | |
831 | (set_attr "psw_operand" "clobber")]) | |
832 | ||
833 | (define_insn "*call_value_internal" | |
834 | [(set (match_operand 3 "register_operand" "=r,r") | |
835 | (call (mem:HI (match_operand:HI 0 "nonmemory_operand" "i,r")) | |
836 | (match_operand 1 "" ""))) | |
da6e254e | 837 | (use (match_operand:HI 2 "nonmemory_operand" "X,z"))] |
4b58290f GK |
838 | "" |
839 | "@ | |
840 | callf %C0 | |
841 | call %2,%0" | |
842 | [(set_attr "length" "4,2") | |
843 | (set_attr "psw_operand" "clobber")]) | |
844 | ||
845 | ;; Subroutine return | |
846 | (define_expand "return" | |
847 | [(return)] | |
848 | "direct_return()" | |
849 | "") | |
850 | ||
851 | (define_insn "return_internal" | |
852 | [(return)] | |
853 | "" | |
854 | "ret" | |
855 | [(set_attr "psw_operand" "nop")]) | |
856 | ||
857 | (define_insn "return_internal_interrupt" | |
858 | [(return) | |
859 | (unspec_volatile [(const_int 0)] 1)] | |
860 | "" | |
861 | "iret" | |
862 | [(set_attr "psw_operand" "clobber")]) | |
863 | ||
864 | ;; Normal unconditional jump | |
865 | (define_insn "jump" | |
866 | [(set (pc) (label_ref (match_operand 0 "" "")))] | |
867 | "" | |
868 | "* | |
869 | { | |
c6243b4c | 870 | return xstormy16_output_cbranch_hi (NULL_RTX, \"%l0\", 0, insn); |
4b58290f GK |
871 | }" |
872 | [(set_attr "branch_class" "br12") | |
873 | (set_attr "psw_operand" "nop")]) | |
874 | ||
875 | ;; Indirect jump through a register | |
876 | (define_expand "indirect_jump" | |
877 | [(set (match_dup 1) (const_int 0)) | |
878 | (parallel [(set (pc) (match_operand:HI 0 "register_operand" "r")) | |
879 | (use (match_dup 1))])] | |
880 | "" | |
881 | "operands[1] = gen_reg_rtx (HImode);") | |
882 | ||
883 | (define_insn "" | |
884 | [(set (pc) (match_operand:HI 0 "register_operand" "r")) | |
da6e254e | 885 | (use (match_operand:HI 1 "register_operand" "z"))] |
4b58290f GK |
886 | "" |
887 | "jmp %1,%0" | |
888 | [(set_attr "length" "4") | |
889 | (set_attr "psw_operand" "nop")]) | |
890 | ||
891 | ;; Table-based switch statements. | |
892 | (define_expand "casesi" | |
893 | [(use (match_operand:SI 0 "register_operand" "")) | |
894 | (use (match_operand:SI 1 "immediate_operand" "")) | |
895 | (use (match_operand:SI 2 "immediate_operand" "")) | |
896 | (use (label_ref (match_operand 3 "" ""))) | |
897 | (use (label_ref (match_operand 4 "" "")))] | |
898 | "" | |
899 | " | |
900 | { | |
c6243b4c | 901 | xstormy16_expand_casesi (operands[0], operands[1], operands[2], |
4b58290f GK |
902 | operands[3], operands[4]); |
903 | DONE; | |
904 | }") | |
905 | ||
906 | (define_insn "tablejump_pcrel" | |
907 | [(set (pc) (plus:HI (pc) (match_operand:HI 0 "register_operand" "r"))) | |
908 | (use (label_ref:SI (match_operand 1 "" "")))] | |
909 | "" | |
910 | "br %0" | |
911 | [(set_attr "psw_operand" "nop")]) | |
912 | ||
913 | \f | |
914 | ;; :::::::::::::::::::: | |
915 | ;; :: | |
916 | ;; :: Prologue and Epilogue instructions | |
917 | ;; :: | |
918 | ;; :::::::::::::::::::: | |
919 | ||
41441dc7 NB |
920 | ;; Called after register allocation to add any instructions needed for |
921 | ;; the prologue. Using a prologue insn is favored compared to putting | |
922 | ;; all of the instructions in the TARGET_ASM_FUNCTION_PROLOGUE macro, | |
923 | ;; since it allows the scheduler to intermix instructions with the | |
924 | ;; saves of the caller saved registers. In some cases, it might be | |
925 | ;; necessary to emit a barrier instruction as the last insn to prevent | |
926 | ;; such scheduling. | |
4b58290f GK |
927 | (define_expand "prologue" |
928 | [(const_int 1)] | |
929 | "" | |
930 | " | |
931 | { | |
c6243b4c | 932 | xstormy16_expand_prologue (); |
4b58290f GK |
933 | DONE; |
934 | }") | |
935 | ||
41441dc7 | 936 | ;; Called after register allocation to add any instructions needed for |
e03f5d43 | 937 | ;; the epilogue. Using an epilogue insn is favored compared to putting |
41441dc7 NB |
938 | ;; all of the instructions in the TARGET_ASM_FUNCTION_EPILOGUE macro, |
939 | ;; since it allows the scheduler to intermix instructions with the | |
940 | ;; restires of the caller saved registers. In some cases, it might be | |
941 | ;; necessary to emit a barrier instruction as the first insn to | |
942 | ;; prevent such scheduling. | |
4b58290f GK |
943 | (define_expand "epilogue" |
944 | [(const_int 2)] | |
945 | "" | |
946 | " | |
947 | { | |
c6243b4c | 948 | xstormy16_expand_epilogue (); |
4b58290f GK |
949 | DONE; |
950 | }") | |
951 | ||
952 | \f | |
953 | ;; :::::::::::::::::::: | |
954 | ;; :: | |
955 | ;; :: Miscellaneous instructions | |
956 | ;; :: | |
957 | ;; :::::::::::::::::::: | |
958 | ||
959 | ;; No operation, needed in case the user uses -g but not -O. | |
960 | (define_insn "nop" | |
961 | [(const_int 0)] | |
962 | "" | |
963 | "nop" | |
964 | [(set_attr "psw_operand" "nop")]) | |
965 | ||
966 | ;; Pseudo instruction that prevents the scheduler from moving code above this | |
967 | ;; point. | |
968 | (define_insn "blockage" | |
969 | [(unspec_volatile [(const_int 0)] 0)] | |
970 | "" | |
971 | "" | |
972 | [(set_attr "length" "0") | |
973 | (set_attr "psw_operand" "nop")]) |