Mercurial > hg > CbC > CbC_gcc
comparison gcc/config/or1k/or1k.md @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 ;; Machine description for OpenRISC | |
2 ;; Copyright (C) 2018-2020 Free Software Foundation, Inc. | |
3 ;; Contributed by Stafford Horne | |
4 | |
5 ;; This file is part of GCC. | |
6 | |
7 ;; GCC is free software; you can redistribute it and/or modify it | |
8 ;; under the terms of the GNU General Public License as published | |
9 ;; by the Free Software Foundation; either version 3, or (at your | |
10 ;; option) any later version. | |
11 | |
12 ;; GCC is distributed in the hope that it will be useful, but WITHOUT | |
13 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
15 ;; 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 ;; ------------------------------------------------------------------------- | |
22 ;; OpenRISC specific constraints, predicates and attributes | |
23 ;; ------------------------------------------------------------------------- | |
24 | |
25 (include "constraints.md") | |
26 (include "predicates.md") | |
27 | |
28 ;; Register numbers | |
29 (define_constants | |
30 [(SP_REGNUM 1) | |
31 (HFP_REGNUM 2) | |
32 (LR_REGNUM 9) | |
33 (TLS_REGNUM 10) | |
34 (RV_REGNUM 11) | |
35 (PE_TMP_REGNUM 13) | |
36 (AP_REGNUM 32) | |
37 (SFP_REGNUM 33) | |
38 (SR_F_REGNUM 34)] | |
39 ) | |
40 | |
41 (define_c_enum "unspec" [ | |
42 UNSPEC_SET_GOT | |
43 UNSPEC_GOT | |
44 UNSPEC_GOTOFF | |
45 UNSPEC_TPOFF | |
46 UNSPEC_GOTTPOFF | |
47 UNSPEC_TLSGD | |
48 UNSPEC_MSYNC | |
49 ]) | |
50 | |
51 (define_c_enum "unspecv" [ | |
52 UNSPECV_SET_GOT | |
53 UNSPECV_LL | |
54 UNSPECV_SC | |
55 ]) | |
56 | |
57 ;; Instruction scheduler | |
58 | |
59 ; Most instructions are 4 bytes long. | |
60 (define_attr "length" "" (const_int 4)) | |
61 | |
62 (define_attr "type" | |
63 "alu,st,ld,control,multi,fpu" | |
64 (const_string "alu")) | |
65 | |
66 (define_attr "insn_support" "class1,sext,sfimm,shftimm,ror,rori" (const_string "class1")) | |
67 | |
68 (define_attr "enabled" "" | |
69 (cond [(eq_attr "insn_support" "class1") (const_int 1) | |
70 (and (eq_attr "insn_support" "sext") | |
71 (ne (symbol_ref "TARGET_SEXT") (const_int 0))) (const_int 1) | |
72 (and (eq_attr "insn_support" "sfimm") | |
73 (ne (symbol_ref "TARGET_SFIMM") (const_int 0))) (const_int 1) | |
74 (and (eq_attr "insn_support" "shftimm") | |
75 (ne (symbol_ref "TARGET_SHFTIMM") (const_int 0))) (const_int 1) | |
76 (and (eq_attr "insn_support" "ror") | |
77 (ne (symbol_ref "TARGET_ROR") (const_int 0))) (const_int 1) | |
78 (and (eq_attr "insn_support" "rori") | |
79 (ne (symbol_ref "TARGET_RORI") (const_int 0))) (const_int 1)] | |
80 (const_int 0))) | |
81 | |
82 ;; Describe a user's asm statement. | |
83 (define_asm_attributes | |
84 [(set_attr "type" "multi")]) | |
85 | |
86 (define_automaton "or1k") | |
87 (define_cpu_unit "cpu" "or1k") | |
88 (define_insn_reservation "alu" 1 | |
89 (eq_attr "type" "alu") | |
90 "cpu") | |
91 (define_insn_reservation "st" 1 | |
92 (eq_attr "type" "st") | |
93 "cpu") | |
94 (define_insn_reservation "ld" 3 | |
95 (eq_attr "type" "st") | |
96 "cpu") | |
97 (define_insn_reservation "control" 1 | |
98 (eq_attr "type" "control") | |
99 "cpu") | |
100 (define_insn_reservation "fpu" 2 | |
101 (eq_attr "type" "fpu") | |
102 "cpu") | |
103 | |
104 | |
105 ; Define delay slots for any branch | |
106 (define_delay (eq_attr "type" "control") | |
107 [(eq_attr "type" "alu,st,ld") (nil) (nil)]) | |
108 | |
109 ;; ------------------------------------------------------------------------- | |
110 ;; nop instruction | |
111 ;; ------------------------------------------------------------------------- | |
112 | |
113 (define_insn "nop" | |
114 [(const_int 0)] | |
115 "" | |
116 "l.nop") | |
117 | |
118 ;; ------------------------------------------------------------------------- | |
119 ;; Arithmetic instructions | |
120 ;; ------------------------------------------------------------------------- | |
121 | |
122 (define_insn "addsi3" | |
123 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
124 (plus:SI | |
125 (match_operand:SI 1 "register_operand" "%r,r") | |
126 (match_operand:SI 2 "reg_or_s16_operand" " r,I")))] | |
127 "" | |
128 "@ | |
129 l.add\t%0, %1, %2 | |
130 l.addi\t%0, %1, %2") | |
131 | |
132 (define_insn "mulsi3" | |
133 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
134 (mult:SI | |
135 (match_operand:SI 1 "register_operand" "%r,r") | |
136 (match_operand:SI 2 "reg_or_s16_operand" " r,I")))] | |
137 "!TARGET_SOFT_MUL" | |
138 "@ | |
139 l.mul\t%0, %1, %2 | |
140 l.muli\t%0, %1, %2") | |
141 | |
142 (define_insn "divsi3" | |
143 [(set (match_operand:SI 0 "register_operand" "=r") | |
144 (div:SI | |
145 (match_operand:SI 1 "register_operand" "r") | |
146 (match_operand:SI 2 "register_operand" "r")))] | |
147 "!TARGET_SOFT_DIV" | |
148 "l.div\t%0, %1, %2") | |
149 | |
150 (define_insn "udivsi3" | |
151 [(set (match_operand:SI 0 "register_operand" "=r") | |
152 (udiv:SI | |
153 (match_operand:SI 1 "register_operand" "r") | |
154 (match_operand:SI 2 "register_operand" "r")))] | |
155 "!TARGET_SOFT_DIV" | |
156 "l.divu\t%0, %1, %2") | |
157 | |
158 (define_insn "subsi3" | |
159 [(set (match_operand:SI 0 "register_operand" "=r") | |
160 (minus:SI | |
161 (match_operand:SI 1 "reg_or_0_operand" "rO") | |
162 (match_operand:SI 2 "register_operand" "r")))] | |
163 "" | |
164 "l.sub\t%0, %r1, %2") | |
165 | |
166 ;; ------------------------------------------------------------------------- | |
167 ;; Floating Point Arithmetic instructions | |
168 ;; ------------------------------------------------------------------------- | |
169 | |
170 ;; Mode iterator for single/double float | |
171 (define_mode_iterator F [(SF "TARGET_HARD_FLOAT") | |
172 (DF "TARGET_DOUBLE_FLOAT")]) | |
173 (define_mode_attr f [(SF "s") (DF "d")]) | |
174 (define_mode_attr fr [(SF "r") (DF "d")]) | |
175 (define_mode_attr fi [(SF "si") (DF "di")]) | |
176 (define_mode_attr FI [(SF "SI") (DF "DI")]) | |
177 | |
178 ;; Basic arithmetic instructions | |
179 (define_code_iterator FOP [plus minus mult div]) | |
180 (define_code_attr fop [(plus "add") (minus "sub") (mult "mul") (div "div")]) | |
181 | |
182 (define_insn "<fop><F:mode>3" | |
183 [(set (match_operand:F 0 "register_operand" "=<fr>") | |
184 (FOP:F (match_operand:F 1 "register_operand" "<fr>") | |
185 (match_operand:F 2 "register_operand" "<fr>")))] | |
186 "TARGET_HARD_FLOAT" | |
187 "lf.<fop>.<f>\t%d0, %d1, %d2" | |
188 [(set_attr "type" "fpu")]) | |
189 | |
190 ;; Basic float<->int conversion | |
191 (define_insn "float<fi><F:mode>2" | |
192 [(set (match_operand:F 0 "register_operand" "=<fr>") | |
193 (float:F | |
194 (match_operand:<FI> 1 "register_operand" "<fr>")))] | |
195 "TARGET_HARD_FLOAT" | |
196 "lf.itof.<f>\t%d0, %d1" | |
197 [(set_attr "type" "fpu")]) | |
198 | |
199 (define_insn "fix_trunc<F:mode><fi>2" | |
200 [(set (match_operand:<FI> 0 "register_operand" "=<fr>") | |
201 (fix:<FI> | |
202 (match_operand:F 1 "register_operand" "<fr>")))] | |
203 "TARGET_HARD_FLOAT" | |
204 "lf.ftoi.<f>\t%d0, %d1" | |
205 [(set_attr "type" "fpu")]) | |
206 | |
207 ;; ------------------------------------------------------------------------- | |
208 ;; Logical operators | |
209 ;; ------------------------------------------------------------------------- | |
210 | |
211 (define_code_iterator SHIFT [ashift ashiftrt lshiftrt]) | |
212 (define_code_attr shift_op [(ashift "ashl") (ashiftrt "ashr") | |
213 (lshiftrt "lshr")]) | |
214 (define_code_attr shift_asm [(ashift "sll") (ashiftrt "sra") | |
215 (lshiftrt "srl")]) | |
216 | |
217 (define_insn "<shift_op>si3" | |
218 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
219 (SHIFT:SI (match_operand:SI 1 "register_operand" "r,r") | |
220 (match_operand:SI 2 "reg_or_u6_operand" "r,n")))] | |
221 "" | |
222 "@ | |
223 l.<shift_asm>\t%0, %1, %2 | |
224 l.<shift_asm>i\t%0, %1, %2" | |
225 [(set_attr "insn_support" "*,shftimm")]) | |
226 | |
227 (define_insn "rotrsi3" | |
228 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
229 (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") | |
230 (match_operand:SI 2 "ror_reg_or_u6_operand" "r,n")))] | |
231 "TARGET_ROR || TARGET_RORI" | |
232 "@ | |
233 l.ror\t%0, %1, %2 | |
234 l.rori\t%0, %1, %2" | |
235 [(set_attr "insn_support" "ror,rori")]) | |
236 | |
237 (define_insn "andsi3" | |
238 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
239 (and:SI | |
240 (match_operand:SI 1 "register_operand" "%r,r") | |
241 (match_operand:SI 2 "reg_or_u16_operand" " r,K")))] | |
242 "" | |
243 "@ | |
244 l.and\t%0, %1, %2 | |
245 l.andi\t%0, %1, %2") | |
246 | |
247 (define_insn "xorsi3" | |
248 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
249 (xor:SI | |
250 (match_operand:SI 1 "register_operand" "%r,r") | |
251 (match_operand:SI 2 "reg_or_s16_operand" " r,I")))] | |
252 "" | |
253 "@ | |
254 l.xor\t%0, %1, %2 | |
255 l.xori\t%0, %1, %2") | |
256 | |
257 (define_insn "iorsi3" | |
258 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
259 (ior:SI | |
260 (match_operand:SI 1 "register_operand" "%r,r") | |
261 (match_operand:SI 2 "reg_or_u16_operand" " r,K")))] | |
262 "" | |
263 "@ | |
264 l.or\t%0, %1, %2 | |
265 l.ori\t%0, %1, %2") | |
266 | |
267 (define_expand "one_cmplsi2" | |
268 [(set (match_operand:SI 0 "register_operand" "") | |
269 (xor:SI (match_operand:SI 1 "register_operand" "") (const_int -1)))] | |
270 "" | |
271 "") | |
272 | |
273 ;; ------------------------------------------------------------------------- | |
274 ;; Move instructions | |
275 ;; ------------------------------------------------------------------------- | |
276 | |
277 (define_mode_iterator I [QI HI SI]) | |
278 (define_mode_iterator I12 [QI HI]) | |
279 | |
280 (define_mode_attr ldst [(QI "b") (HI "h") (SI "w")]) | |
281 (define_mode_attr zext_andi [(QI "0xff") (HI "0xffff")]) | |
282 | |
283 (define_expand "mov<I:mode>" | |
284 [(set (match_operand:I 0 "nonimmediate_operand" "") | |
285 (match_operand:I 1 "general_operand" ""))] | |
286 "" | |
287 { | |
288 or1k_expand_move (<MODE>mode, operands[0], operands[1]); | |
289 DONE; | |
290 }) | |
291 | |
292 ;; 8-bit, 16-bit and 32-bit moves | |
293 | |
294 (define_insn "*mov<I:mode>_internal" | |
295 [(set (match_operand:I 0 "nonimmediate_operand" "=r,r,r,r, m,r") | |
296 (match_operand:I 1 "input_operand" " r,M,K,I,rO,m"))] | |
297 "register_operand (operands[0], <I:MODE>mode) | |
298 || reg_or_0_operand (operands[1], <I:MODE>mode)" | |
299 "@ | |
300 l.or\t%0, %1, %1 | |
301 l.movhi\t%0, hi(%1) | |
302 l.ori\t%0, r0, %1 | |
303 l.xori\t%0, r0, %1 | |
304 l.s<I:ldst>\t%0, %r1 | |
305 l.l<I:ldst>z\t%0, %1" | |
306 [(set_attr "type" "alu,alu,alu,alu,st,ld")]) | |
307 | |
308 ;; Hi/Low moves for constant and symbol loading | |
309 | |
310 (define_insn "movsi_high" | |
311 [(set (match_operand:SI 0 "register_operand" "=r") | |
312 (high:SI (match_operand:SI 1 "high_operand" "")))] | |
313 "" | |
314 "l.movhi\t%0, %h1" | |
315 [(set_attr "type" "alu")]) | |
316 | |
317 (define_insn "*movsi_lo_sum_iori" | |
318 [(set (match_operand:SI 0 "register_operand" "=r") | |
319 (lo_sum:SI (match_operand:SI 1 "register_operand" "r") | |
320 (match_operand:SI 2 "losum_ior_operand" "")))] | |
321 "" | |
322 "l.ori\t%0, %1, %L2" | |
323 [(set_attr "type" "alu")]) | |
324 | |
325 (define_insn "*movsi_lo_sum_addi" | |
326 [(set (match_operand:SI 0 "register_operand" "=r") | |
327 (lo_sum:SI (match_operand:SI 1 "register_operand" "r") | |
328 (match_operand:SI 2 "losum_add_operand" "")))] | |
329 "" | |
330 "l.addi\t%0, %1, %L2" | |
331 [(set_attr "type" "alu")]) | |
332 | |
333 ;; 64-bit moves | |
334 ;; ??? The clobber that emit_move_multi_word emits is arguably incorrect. | |
335 ;; Consider gcc.c-torture/execute/20030222-1.c, where a reg-reg DImode | |
336 ;; move gets register allocated to a no-op move. At which point the | |
337 ;; we actively clobber the input. | |
338 | |
339 (define_expand "movdi" | |
340 [(set (match_operand:DI 0 "nonimmediate_operand" "") | |
341 (match_operand:DI 1 "general_operand" ""))] | |
342 "" | |
343 { | |
344 if (MEM_P (operands[0]) && !const0_operand(operands[1], DImode)) | |
345 operands[1] = force_reg (DImode, operands[1]); | |
346 }) | |
347 | |
348 (define_insn_and_split "*movdi" | |
349 [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,o,r") | |
350 (match_operand:DI 1 "general_operand" " r,o,rO,n"))] | |
351 "register_operand (operands[0], DImode) | |
352 || reg_or_0_operand (operands[1], DImode)" | |
353 "#" | |
354 "" | |
355 [(const_int 0)] | |
356 { | |
357 rtx l0 = operand_subword (operands[0], 0, 0, DImode); | |
358 rtx l1 = operand_subword (operands[1], 0, 0, DImode); | |
359 rtx h0 = operand_subword (operands[0], 1, 0, DImode); | |
360 rtx h1 = operand_subword (operands[1], 1, 0, DImode); | |
361 | |
362 if (reload_completed && reg_overlap_mentioned_p (l0, h1)) | |
363 { | |
364 gcc_assert (!reg_overlap_mentioned_p (h0, l1)); | |
365 emit_move_insn (h0, h1); | |
366 emit_move_insn (l0, l1); | |
367 } | |
368 else | |
369 { | |
370 emit_move_insn (l0, l1); | |
371 emit_move_insn (h0, h1); | |
372 } | |
373 DONE; | |
374 }) | |
375 | |
376 ;; ------------------------------------------------------------------------- | |
377 ;; Sign Extending | |
378 ;; ------------------------------------------------------------------------- | |
379 | |
380 ;; Zero extension can always be done with AND or an extending load. | |
381 | |
382 (define_insn "zero_extend<mode>si2" | |
383 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
384 (zero_extend:SI (match_operand:I12 1 "reg_or_mem_operand" "r,m")))] | |
385 "" | |
386 "@ | |
387 l.andi\t%0, %1, <zext_andi> | |
388 l.l<ldst>z\t%0, %1") | |
389 | |
390 ;; Sign extension in registers is an optional extension, but the | |
391 ;; extending load is always available. If SEXT is not available, | |
392 ;; force the middle-end to do the expansion to shifts. | |
393 | |
394 (define_insn "extend<mode>si2" | |
395 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
396 (sign_extend:SI (match_operand:I12 1 "reg_or_mem_operand" "r,m")))] | |
397 "TARGET_SEXT" | |
398 "@ | |
399 l.ext<ldst>s\t%0, %1 | |
400 l.l<ldst>s\t%0, %1") | |
401 | |
402 (define_insn "*extend<mode>si2_mem" | |
403 [(set (match_operand:SI 0 "register_operand" "=r") | |
404 (sign_extend:SI (match_operand:I12 1 "memory_operand" "m")))] | |
405 "" | |
406 "l.l<ldst>s\t%0, %1") | |
407 | |
408 ;; ------------------------------------------------------------------------- | |
409 ;; Compare instructions | |
410 ;; ------------------------------------------------------------------------- | |
411 | |
412 ;; OpenRISC supports these integer comparisons: | |
413 ;; | |
414 ;; l.sfeq[i] - equality, r r or r i | |
415 ;; l.sfne[i] - not equal, r r or r i | |
416 ;; l.sflt{s,u}[i] - less than, signed or unsigned, r r or r i | |
417 ;; l.sfle{s,u}[i] - less than or equal, signed or unsigned, r r or r i | |
418 ;; l.sfgt{s,u}[i] - greater than, signed or unsigned, r r or r i | |
419 ;; l.sfge{s,u}[i] - greater than or equal, signed or unsigned, r r or r i | |
420 ;; | |
421 ;; EQ,NE,LT,LTU,LE,LEU,GT,GTU,GE,GEU | |
422 ;; We iterate through all of these | |
423 ;; | |
424 | |
425 (define_code_iterator intcmpcc [ne eq lt ltu gt gtu ge le geu leu]) | |
426 (define_code_attr insn [(ne "ne") (eq "eq") (lt "lts") (ltu "ltu") | |
427 (gt "gts") (gtu "gtu") (ge "ges") (le "les") | |
428 (geu "geu") (leu "leu")]) | |
429 | |
430 (define_insn "*sf_insn" | |
431 [(set (reg:BI SR_F_REGNUM) | |
432 (intcmpcc:BI (match_operand:SI 0 "reg_or_0_operand" "rO,rO") | |
433 (match_operand:SI 1 "reg_or_s16_operand" "r,I")))] | |
434 "" | |
435 "@ | |
436 l.sf<insn>\t%r0, %1 | |
437 l.sf<insn>i\t%r0, %1" | |
438 [(set_attr "insn_support" "*,sfimm")]) | |
439 | |
440 ;; Support FP comparisons too | |
441 | |
442 ;; The OpenRISC FPU supports these comparisons: | |
443 ;; | |
444 ;; lf.sfeq.{d,s} - equality, r r, double or single precision | |
445 ;; lf.sfge.{d,s} - greater than or equal, r r, double or single precision | |
446 ;; lf.sfgt.{d,s} - greater than, r r, double or single precision | |
447 ;; lf.sfle.{d,s} - less than or equal, r r, double or single precision | |
448 ;; lf.sflt.{d,s} - less than, r r, double or single precision | |
449 ;; lf.sfne.{d,s} - not equal, r r, double or single precision | |
450 ;; | |
451 ;; Double precision is only supported on some hardware. Only register/register | |
452 ;; comparisons are supported. All comparisons are signed. | |
453 | |
454 (define_code_iterator fpcmpcc [ne eq lt gt ge le uneq unle unlt ungt unge | |
455 unordered]) | |
456 (define_code_attr fpcmpinsn [(ne "ne") (eq "eq") (lt "lt") (gt "gt") (ge "ge") | |
457 (le "le") (uneq "ueq") (unle "ule") (unlt "ult") | |
458 (ungt "ugt") (unge "uge") (unordered "un")]) | |
459 | |
460 | |
461 (define_insn "*sf_fp_insn" | |
462 [(set (reg:BI SR_F_REGNUM) | |
463 (fpcmpcc:BI (match_operand:F 0 "register_operand" "<fr>") | |
464 (match_operand:F 1 "register_operand" "<fr>")))] | |
465 "TARGET_HARD_FLOAT" | |
466 "lf.sf<fpcmpinsn>.<f>\t%d0, %d1" | |
467 [(set_attr "type" "fpu")]) | |
468 | |
469 | |
470 ;; ------------------------------------------------------------------------- | |
471 ;; Conditional Store instructions | |
472 ;; ------------------------------------------------------------------------- | |
473 | |
474 (define_expand "cstoresi4" | |
475 [(set (match_operand:SI 0 "register_operand" "") | |
476 (if_then_else:SI | |
477 (match_operator 1 "comparison_operator" | |
478 [(match_operand:SI 2 "reg_or_0_operand" "") | |
479 (match_operand:SI 3 "reg_or_s16_operand" "")]) | |
480 (match_dup 0) | |
481 (const_int 0)))] | |
482 "" | |
483 { | |
484 or1k_expand_compare (operands + 1); | |
485 PUT_MODE (operands[1], SImode); | |
486 emit_insn (gen_rtx_SET (operands[0], operands[1])); | |
487 DONE; | |
488 }) | |
489 | |
490 ;; Support FP cstores too | |
491 (define_expand "cstore<F:mode>4" | |
492 [(set (match_operand:SI 0 "register_operand" "") | |
493 (if_then_else:F | |
494 (match_operator 1 "fp_comparison_operator" | |
495 [(match_operand:F 2 "register_operand" "") | |
496 (match_operand:F 3 "register_operand" "")]) | |
497 (match_dup 0) | |
498 (const_int 0)))] | |
499 "TARGET_HARD_FLOAT" | |
500 { | |
501 or1k_expand_compare (operands + 1); | |
502 PUT_MODE (operands[1], SImode); | |
503 emit_insn (gen_rtx_SET (operands[0], operands[1])); | |
504 DONE; | |
505 }) | |
506 | |
507 ;; Being able to "copy" SR_F to a general register is helpful for | |
508 ;; the atomic insns, wherein the usual usage is to test the success | |
509 ;; of the compare-and-swap. Representing the operation in this way, | |
510 ;; rather than exposing the cmov immediately, allows the optimizers | |
511 ;; to propagate the use of SR_F directly into a branch. | |
512 | |
513 (define_expand "sne_sr_f" | |
514 [(set (match_operand:SI 0 "register_operand" "=r") | |
515 (ne:SI (reg:BI SR_F_REGNUM) (const_int 0)))] | |
516 "") | |
517 | |
518 (define_insn_and_split "*scc" | |
519 [(set (match_operand:SI 0 "register_operand" "=r") | |
520 (match_operator:SI 1 "equality_comparison_operator" | |
521 [(reg:BI SR_F_REGNUM) (const_int 0)]))] | |
522 "" | |
523 "#" | |
524 "reload_completed" | |
525 [(set (match_dup 0) (const_int 1)) | |
526 (set (match_dup 0) | |
527 (if_then_else:SI (match_dup 1) | |
528 (match_dup 0) | |
529 (const_int 0)))] | |
530 "") | |
531 | |
532 (define_expand "mov<I:mode>cc" | |
533 [(set (match_operand:I 0 "register_operand" "") | |
534 (if_then_else:I (match_operand 1 "comparison_operator" "") | |
535 (match_operand:I 2 "reg_or_0_operand" "") | |
536 (match_operand:I 3 "reg_or_0_operand" "")))] | |
537 "" | |
538 { | |
539 rtx xops[3] = { operands[1], XEXP (operands[1], 0), XEXP (operands[1], 1) }; | |
540 or1k_expand_compare (xops); | |
541 operands[1] = xops[0]; | |
542 }) | |
543 | |
544 (define_insn_and_split "*cmov<I:mode>" | |
545 [(set (match_operand:I 0 "register_operand" "=r") | |
546 (if_then_else:I | |
547 (match_operator 3 "equality_comparison_operator" | |
548 [(reg:BI SR_F_REGNUM) (const_int 0)]) | |
549 (match_operand:I 1 "reg_or_0_operand" "rO") | |
550 (match_operand:I 2 "reg_or_0_operand" "rO")))] | |
551 "" | |
552 { | |
553 return (GET_CODE (operands[3]) == NE | |
554 ? "l.cmov\t%0, %r1, %r2" | |
555 : "l.cmov\t%0, %r2, %r1"); | |
556 } | |
557 "!TARGET_CMOV" | |
558 [(const_int 0)] | |
559 { | |
560 rtx x; | |
561 rtx label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ()); | |
562 | |
563 /* Generated a *cbranch pattern. */ | |
564 if (rtx_equal_p (operands[0], operands[2])) | |
565 { | |
566 PUT_CODE (operands[3], (GET_CODE (operands[3]) == NE) ? EQ : NE); | |
567 x = gen_rtx_IF_THEN_ELSE (VOIDmode, operands[3], label, pc_rtx); | |
568 emit_jump_insn (gen_rtx_SET (pc_rtx, x)); | |
569 emit_move_insn (operands[0], operands[1]); | |
570 } | |
571 else | |
572 { | |
573 x = gen_rtx_IF_THEN_ELSE (VOIDmode, operands[3], label, pc_rtx); | |
574 emit_move_insn (operands[0], operands[1]); | |
575 emit_jump_insn (gen_rtx_SET (pc_rtx, x)); | |
576 emit_move_insn (operands[0], operands[2]); | |
577 } | |
578 | |
579 emit_label (XEXP (label, 0)); | |
580 DONE; | |
581 }) | |
582 | |
583 ;; ------------------------------------------------------------------------- | |
584 ;; Branch instructions | |
585 ;; ------------------------------------------------------------------------- | |
586 | |
587 (define_expand "cbranchsi4" | |
588 [(set (pc) | |
589 (if_then_else | |
590 (match_operator 0 "comparison_operator" | |
591 [(match_operand:SI 1 "reg_or_0_operand" "") | |
592 (match_operand:SI 2 "reg_or_s16_operand" "")]) | |
593 (label_ref (match_operand 3 "" "")) | |
594 (pc)))] | |
595 "" | |
596 { | |
597 or1k_expand_compare (operands); | |
598 }) | |
599 | |
600 ;; Support FP branching | |
601 | |
602 (define_expand "cbranch<F:mode>4" | |
603 [(set (pc) | |
604 (if_then_else | |
605 (match_operator 0 "fp_comparison_operator" | |
606 [(match_operand:F 1 "register_operand" "") | |
607 (match_operand:F 2 "register_operand" "")]) | |
608 (label_ref (match_operand 3 "" "")) | |
609 (pc)))] | |
610 "TARGET_HARD_FLOAT" | |
611 { | |
612 or1k_expand_compare (operands); | |
613 }) | |
614 | |
615 (define_insn "*cbranch" | |
616 [(set (pc) | |
617 (if_then_else | |
618 (match_operator 1 "equality_comparison_operator" | |
619 [(reg:BI SR_F_REGNUM) (const_int 0)]) | |
620 (label_ref (match_operand 0 "" "")) | |
621 (pc)))] | |
622 "" | |
623 { | |
624 return (GET_CODE (operands[1]) == NE | |
625 ? "l.bf\t%0%#" | |
626 : "l.bnf\t%0%#"); | |
627 } | |
628 [(set_attr "type" "control")]) | |
629 | |
630 ;; ------------------------------------------------------------------------- | |
631 ;; Jump instructions | |
632 ;; ------------------------------------------------------------------------- | |
633 | |
634 (define_insn "jump" | |
635 [(set (pc) (label_ref (match_operand 0 "" "")))] | |
636 "" | |
637 "l.j\t%0%#" | |
638 [(set_attr "type" "control")]) | |
639 | |
640 (define_insn "indirect_jump" | |
641 [(set (pc) (match_operand:SI 0 "register_operand" "r"))] | |
642 "" | |
643 "l.jr\t%0%#" | |
644 [(set_attr "type" "control")]) | |
645 | |
646 ;; ------------------------------------------------------------------------- | |
647 ;; Prologue & Epilogue | |
648 ;; ------------------------------------------------------------------------- | |
649 | |
650 (define_expand "prologue" | |
651 [(const_int 1)] | |
652 "" | |
653 { | |
654 or1k_expand_prologue (); | |
655 DONE; | |
656 }) | |
657 | |
658 ;; Expand epilogue as RTL | |
659 (define_expand "epilogue" | |
660 [(return)] | |
661 "" | |
662 { | |
663 or1k_expand_epilogue (); | |
664 emit_jump_insn (gen_simple_return ()); | |
665 DONE; | |
666 }) | |
667 | |
668 (define_expand "sibcall_epilogue" | |
669 [(return)] | |
670 "" | |
671 { | |
672 or1k_expand_epilogue (); | |
673 /* Placing a USE of LR here, rather than as a REG_USE on the | |
674 sibcall itself, means that LR is not unnecessarily live | |
675 within the function itself, which would force creation of | |
676 a stack frame. */ | |
677 emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, LR_REGNUM))); | |
678 DONE; | |
679 }) | |
680 | |
681 (define_expand "simple_return" | |
682 [(parallel [(simple_return) (use (match_dup 0))])] | |
683 "" | |
684 { | |
685 operands[0] = gen_rtx_REG (Pmode, LR_REGNUM); | |
686 }) | |
687 | |
688 (define_insn "*simple_return" | |
689 [(simple_return) | |
690 (use (match_operand:SI 0 "register_operand" "r"))] | |
691 "" | |
692 "l.jr\t%0%#" | |
693 [(set_attr "type" "control")]) | |
694 | |
695 (define_expand "eh_return" | |
696 [(use (match_operand 0 "general_operand"))] | |
697 "" | |
698 { | |
699 or1k_expand_eh_return (operands[0]); | |
700 DONE; | |
701 }) | |
702 | |
703 ;; This is a placeholder, during RA, in order to create the PIC regiter. | |
704 ;; We do this so that we don't unconditionally mark the LR register as | |
705 ;; clobbered. It is replaced during prologue generation with the proper | |
706 ;; set_got pattern below. This works because the set_got_tmp insn is the | |
707 ;; first insn in the stream and that it isn't moved during RA. | |
708 (define_insn "set_got_tmp" | |
709 [(set (match_operand:SI 0 "register_operand" "=t") | |
710 (unspec_volatile:SI [(const_int 0)] UNSPECV_SET_GOT))] | |
711 "" | |
712 { | |
713 gcc_unreachable (); | |
714 }) | |
715 | |
716 ;; The insn to initialize the GOT. | |
717 (define_insn "set_got" | |
718 [(set (match_operand:SI 0 "register_operand" "=t") | |
719 (unspec:SI [(const_int 0)] UNSPEC_SET_GOT)) | |
720 (clobber (reg:SI LR_REGNUM))] | |
721 "" | |
722 { | |
723 return ("l.jal\t8\;" | |
724 " l.movhi\t%0, gotpchi(_GLOBAL_OFFSET_TABLE_-4)\;" | |
725 "l.ori\t%0, %0, gotpclo(_GLOBAL_OFFSET_TABLE_+0)\;" | |
726 "l.add\t%0, %0, r9"); | |
727 } | |
728 [(set_attr "length" "16") | |
729 (set_attr "type" "multi")]) | |
730 | |
731 ;; Block memory operations from being scheduled across frame (de)allocation. | |
732 (define_insn "frame_addsi3" | |
733 [(set (match_operand:SI 0 "register_operand" "=r,r") | |
734 (plus:SI | |
735 (match_operand:SI 1 "register_operand" "%r,r") | |
736 (match_operand:SI 2 "reg_or_s16_operand" " r,I"))) | |
737 (clobber (mem:BLK (scratch)))] | |
738 "reload_completed" | |
739 "@ | |
740 l.add\t%0, %1, %2 | |
741 l.addi\t%0, %1, %2") | |
742 | |
743 ;; ------------------------------------------------------------------------- | |
744 ;; Atomic Operations | |
745 ;; ------------------------------------------------------------------------- | |
746 | |
747 ;; Note that MULT stands in for the non-existant NAND rtx_code. | |
748 (define_code_iterator FETCHOP [plus minus ior xor and mult]) | |
749 | |
750 (define_code_attr fetchop_name | |
751 [(plus "add") | |
752 (minus "sub") | |
753 (ior "or") | |
754 (xor "xor") | |
755 (and "and") | |
756 (mult "nand")]) | |
757 | |
758 (define_code_attr fetchop_pred | |
759 [(plus "reg_or_s16_operand") | |
760 (minus "register_operand") | |
761 (ior "reg_or_u16_operand") | |
762 (xor "reg_or_s16_operand") | |
763 (and "reg_or_u16_operand") | |
764 (mult "reg_or_u16_operand")]) | |
765 | |
766 (define_expand "mem_thread_fence" | |
767 [(match_operand:SI 0 "const_int_operand" "")] ;; model | |
768 "" | |
769 { | |
770 memmodel model = memmodel_base (INTVAL (operands[0])); | |
771 if (model != MEMMODEL_RELAXED) | |
772 emit_insn (gen_msync ()); | |
773 DONE; | |
774 }) | |
775 | |
776 (define_expand "msync" | |
777 [(set (match_dup 0) (unspec:BLK [(match_dup 0)] UNSPEC_MSYNC))] | |
778 "" | |
779 { | |
780 operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); | |
781 MEM_VOLATILE_P (operands[0]) = 1; | |
782 }) | |
783 | |
784 (define_insn "*msync" | |
785 [(set (match_operand:BLK 0 "" "") | |
786 (unspec:BLK [(match_dup 0)] UNSPEC_MSYNC))] | |
787 "" | |
788 "l.msync") | |
789 | |
790 (define_insn "load_locked_si" | |
791 [(set (match_operand:SI 0 "register_operand" "=r") | |
792 (unspec_volatile:SI | |
793 [(match_operand:SI 1 "memory_operand" "m")] UNSPECV_LL))] | |
794 "" | |
795 "l.lwa\t%0,%1" | |
796 [(set_attr "type" "ld")]) | |
797 | |
798 (define_insn "store_conditional_si" | |
799 [(set (reg:BI SR_F_REGNUM) | |
800 (unspec_volatile:BI [(const_int 0)] UNSPECV_SC)) | |
801 (set (match_operand:SI 0 "memory_operand" "=m") | |
802 (match_operand:SI 1 "reg_or_0_operand" "rO"))] | |
803 "" | |
804 "l.swa\t%0,%r1" | |
805 [(set_attr "type" "st")]) | |
806 | |
807 (define_expand "atomic_compare_and_swapsi" | |
808 [(match_operand:SI 0 "register_operand") ;; bool output | |
809 (match_operand:SI 1 "register_operand") ;; val output | |
810 (match_operand:SI 2 "memory_operand") ;; memory | |
811 (match_operand:SI 3 "reg_or_s16_operand") ;; expected | |
812 (match_operand:SI 4 "reg_or_0_operand") ;; desired | |
813 (match_operand:SI 5 "const_int_operand") ;; is_weak | |
814 (match_operand:SI 6 "const_int_operand") ;; mod_s | |
815 (match_operand:SI 7 "const_int_operand")] ;; mod_f | |
816 "" | |
817 { | |
818 or1k_expand_atomic_compare_and_swap (operands); | |
819 DONE; | |
820 }) | |
821 | |
822 (define_expand "atomic_compare_and_swap<mode>" | |
823 [(match_operand:SI 0 "register_operand") ;; bool output | |
824 (match_operand:I12 1 "register_operand") ;; val output | |
825 (match_operand:I12 2 "memory_operand") ;; memory | |
826 (match_operand:I12 3 "register_operand") ;; expected | |
827 (match_operand:I12 4 "reg_or_0_operand") ;; desired | |
828 (match_operand:SI 5 "const_int_operand") ;; is_weak | |
829 (match_operand:SI 6 "const_int_operand") ;; mod_s | |
830 (match_operand:SI 7 "const_int_operand")] ;; mod_f | |
831 "" | |
832 { | |
833 or1k_expand_atomic_compare_and_swap_qihi (operands); | |
834 DONE; | |
835 }) | |
836 | |
837 (define_expand "atomic_exchangesi" | |
838 [(match_operand:SI 0 "register_operand") ;; output | |
839 (match_operand:SI 1 "memory_operand") ;; memory | |
840 (match_operand:SI 2 "reg_or_0_operand") ;; input | |
841 (match_operand:SI 3 "const_int_operand")] ;; model | |
842 "" | |
843 { | |
844 or1k_expand_atomic_exchange (operands); | |
845 DONE; | |
846 }) | |
847 | |
848 (define_expand "atomic_exchange<mode>" | |
849 [(match_operand:I12 0 "register_operand") ;; output | |
850 (match_operand:I12 1 "memory_operand") ;; memory | |
851 (match_operand:I12 2 "reg_or_0_operand") ;; input | |
852 (match_operand:SI 3 "const_int_operand")] ;; model | |
853 "" | |
854 { | |
855 or1k_expand_atomic_exchange_qihi (operands); | |
856 DONE; | |
857 }) | |
858 | |
859 (define_expand "atomic_<fetchop_name>si" | |
860 [(match_operand:SI 0 "memory_operand") ;; memory | |
861 (FETCHOP:SI (match_dup 0) | |
862 (match_operand:SI 1 "<fetchop_pred>")) ;; operand | |
863 (match_operand:SI 2 "const_int_operand")] ;; model | |
864 "" | |
865 { | |
866 or1k_expand_atomic_op (<CODE>, operands[0], operands[1], NULL, NULL); | |
867 DONE; | |
868 }) | |
869 | |
870 (define_expand "atomic_<fetchop_name><mode>" | |
871 [(match_operand:I12 0 "memory_operand") ;; memory | |
872 (FETCHOP:I12 (match_dup 0) | |
873 (match_operand:I12 1 "register_operand")) ;; operand | |
874 (match_operand:SI 2 "const_int_operand")] ;; model | |
875 "" | |
876 { | |
877 or1k_expand_atomic_op_qihi (<CODE>, operands[0], operands[1], NULL, NULL); | |
878 DONE; | |
879 }) | |
880 | |
881 (define_expand "atomic_fetch_<fetchop_name>si" | |
882 [(match_operand:SI 0 "register_operand" "") ;; output | |
883 (match_operand:SI 1 "memory_operand" "") ;; memory | |
884 (FETCHOP:SI (match_dup 1) | |
885 (match_operand:SI 2 "<fetchop_pred>" "")) ;; operand | |
886 (match_operand:SI 3 "const_int_operand" "")] ;; model | |
887 "" | |
888 { | |
889 or1k_expand_atomic_op (<CODE>, operands[1], operands[2], operands[0], NULL); | |
890 DONE; | |
891 }) | |
892 | |
893 (define_expand "atomic_fetch_<fetchop_name><mode>" | |
894 [(match_operand:I12 0 "register_operand" "") ;; output | |
895 (match_operand:I12 1 "memory_operand" "") ;; memory | |
896 (FETCHOP:I12 (match_dup 1) | |
897 (match_operand:I12 2 "<fetchop_pred>" "")) ;; operand | |
898 (match_operand:SI 3 "const_int_operand" "")] ;; model | |
899 "" | |
900 { | |
901 or1k_expand_atomic_op_qihi (<CODE>, operands[1], operands[2], | |
902 operands[0], NULL); | |
903 DONE; | |
904 }) | |
905 | |
906 (define_expand "atomic_<fetchop_name>_fetchsi" | |
907 [(match_operand:SI 0 "register_operand" "") ;; output | |
908 (match_operand:SI 1 "memory_operand" "") ;; memory | |
909 (FETCHOP:SI (match_dup 1) | |
910 (match_operand:SI 2 "<fetchop_pred>" "")) ;; operand | |
911 (match_operand:SI 3 "const_int_operand" "")] ;; model | |
912 "" | |
913 { | |
914 or1k_expand_atomic_op (<CODE>, operands[1], operands[2], NULL, operands[0]); | |
915 DONE; | |
916 }) | |
917 | |
918 (define_expand "atomic_<fetchop_name>_fetch<mode>" | |
919 [(match_operand:I12 0 "register_operand" "") ;; output | |
920 (match_operand:I12 1 "memory_operand" "") ;; memory | |
921 (FETCHOP:I12 (match_dup 1) | |
922 (match_operand:I12 2 "<fetchop_pred>" "")) ;; operand | |
923 (match_operand:SI 3 "const_int_operand" "")] ;; model | |
924 "" | |
925 { | |
926 or1k_expand_atomic_op_qihi (<CODE>, operands[1], operands[2], | |
927 NULL, operands[0]); | |
928 DONE; | |
929 }) | |
930 | |
931 ;; ------------------------------------------------------------------------- | |
932 ;; Call Instructions | |
933 ;; ------------------------------------------------------------------------- | |
934 | |
935 ;; Leave these to last, as the modeless operand for call_value | |
936 ;; interferes with normal patterns. | |
937 | |
938 (define_expand "call" | |
939 [(call (match_operand 0) (match_operand 1))] | |
940 "" | |
941 { | |
942 or1k_expand_call (NULL, operands[0], operands[1], false); | |
943 DONE; | |
944 }) | |
945 | |
946 (define_expand "sibcall" | |
947 [(call (match_operand 0) (match_operand 1))] | |
948 "" | |
949 { | |
950 or1k_expand_call (NULL, operands[0], operands[1], true); | |
951 DONE; | |
952 }) | |
953 | |
954 (define_expand "call_value" | |
955 [(set (match_operand 0) (call (match_operand 1) (match_operand 2)))] | |
956 "" | |
957 { | |
958 or1k_expand_call (operands[0], operands[1], operands[2], false); | |
959 DONE; | |
960 }) | |
961 | |
962 (define_expand "sibcall_value" | |
963 [(set (match_operand 0) (call (match_operand 1) (match_operand 2)))] | |
964 "" | |
965 { | |
966 or1k_expand_call (operands[0], operands[1], operands[2], true); | |
967 DONE; | |
968 }) | |
969 | |
970 (define_insn "*call" | |
971 [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "r,s")) | |
972 (match_operand 1)) | |
973 (clobber (reg:SI LR_REGNUM))] | |
974 "!SIBLING_CALL_P (insn)" | |
975 "@ | |
976 l.jalr\t%0%# | |
977 l.jal\t%P0%#" | |
978 [(set_attr "type" "control")]) | |
979 | |
980 (define_insn "*sibcall" | |
981 [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "c,s")) | |
982 (match_operand 1))] | |
983 "SIBLING_CALL_P (insn)" | |
984 "@ | |
985 l.jr\t%0%# | |
986 l.j\t%P0%#" | |
987 [(set_attr "type" "control")]) | |
988 | |
989 (define_insn "*call_value" | |
990 [(set (match_operand 0) | |
991 (call (mem:SI (match_operand:SI 1 "call_insn_operand" "r,s")) | |
992 (match_operand 2))) | |
993 (clobber (reg:SI LR_REGNUM))] | |
994 "!SIBLING_CALL_P (insn)" | |
995 "@ | |
996 l.jalr\t%1%# | |
997 l.jal\t%P1%#" | |
998 [(set_attr "type" "control")]) | |
999 | |
1000 (define_insn "*sibcall_value" | |
1001 [(set (match_operand 0) | |
1002 (call (mem:SI (match_operand:SI 1 "call_insn_operand" "c,s")) | |
1003 (match_operand 2)))] | |
1004 "SIBLING_CALL_P (insn)" | |
1005 "@ | |
1006 l.jr\t%1%# | |
1007 l.j\t%P1%#" | |
1008 [(set_attr "type" "control")]) |