]>
Commit | Line | Data |
---|---|---|
91dfef96 | 1 | ;; Machine description for eBPF. |
7adcbafe | 2 | ;; Copyright (C) 2019-2022 Free Software Foundation, Inc. |
91dfef96 JM |
3 | |
4 | ;; This file is part of GCC. | |
5 | ||
6 | ;; GCC is free software; you can redistribute it and/or modify | |
7 | ;; it under the terms of the GNU General Public License as published by | |
8 | ;; the Free Software Foundation; either version 3, or (at your option) | |
9 | ;; any later version. | |
10 | ||
11 | ;; GCC is distributed in the hope that it will be useful, | |
12 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ;; GNU General Public License for more details. | |
15 | ||
16 | ;; You should have received a copy of the GNU General Public License | |
17 | ;; along with GCC; see the file COPYING3. If not see | |
18 | ;; <http://www.gnu.org/licenses/>. | |
19 | ||
20 | (include "predicates.md") | |
21 | (include "constraints.md") | |
22 | ||
23 | ;;;; Unspecs | |
24 | ||
25 | (define_c_enum "unspec" [ | |
26 | UNSPEC_LDINDABS | |
27 | UNSPEC_XADD | |
28 | ]) | |
29 | ||
30 | ;;;; Constants | |
31 | ||
32 | (define_constants | |
33 | [(R0_REGNUM 0) | |
34 | (R1_REGNUM 1) | |
35 | (R2_REGNUM 2) | |
36 | (R3_REGNUM 3) | |
37 | (R4_REGNUM 4) | |
38 | (R5_REGNUM 5) | |
39 | (R6_REGNUM 6) | |
40 | (R7_REGNUM 7) | |
41 | (R8_REGNUM 8) | |
42 | (R9_REGNUM 9) | |
43 | (R10_REGNUM 10) | |
44 | (R11_REGNUM 11) | |
45 | ]) | |
46 | ||
47 | ;;;; Attributes | |
48 | ||
49 | ;; Instruction classes. | |
50 | ;; alu 64-bit arithmetic. | |
51 | ;; alu32 32-bit arithmetic. | |
52 | ;; end endianness conversion instructions. | |
53 | ;; ld load instructions. | |
54 | ;; lddx load 64-bit immediate instruction. | |
55 | ;; ldx generic load instructions. | |
56 | ;; st generic store instructions for immediates. | |
57 | ;; stx generic store instructions. | |
58 | ;; jmp jump instructions. | |
59 | ;; xadd atomic exchange-and-add instructions. | |
60 | ;; multi multiword sequence (or user asm statements). | |
61 | ||
62 | (define_attr "type" | |
63 | "unknown,alu,alu32,end,ld,lddw,ldx,st,stx,jmp,xadd,multi" | |
64 | (const_string "unknown")) | |
65 | ||
66 | ;; Length of instruction in bytes. | |
67 | (define_attr "length" "" | |
68 | (cond [ | |
69 | (eq_attr "type" "lddw") (const_int 16) | |
70 | ] (const_int 8))) | |
71 | ||
72 | ;; Describe a user's asm statement. | |
73 | (define_asm_attributes | |
74 | [(set_attr "type" "multi")]) | |
75 | ||
76 | ;;;; Mode attributes and iterators | |
77 | ||
78 | (define_mode_attr mop [(QI "b") (HI "h") (SI "w") (DI "dw") | |
79 | (SF "w") (DF "dw")]) | |
80 | (define_mode_attr mtype [(SI "alu32") (DI "alu")]) | |
81 | (define_mode_attr msuffix [(SI "32") (DI "")]) | |
82 | ||
83 | ;;;; NOPs | |
84 | ||
5bcc0fa0 JM |
85 | ;; The Linux kernel verifier performs some optimizations that rely on |
86 | ;; nop instructions to be encoded as `ja 0', i.e. a jump to offset 0, | |
87 | ;; which actually means to jump to the next instruction, since in BPF | |
88 | ;; offsets are expressed in 64-bit words _minus one_. | |
89 | ||
91dfef96 JM |
90 | (define_insn "nop" |
91 | [(const_int 0)] | |
92 | "" | |
5bcc0fa0 | 93 | "ja\t0" |
91dfef96 JM |
94 | [(set_attr "type" "alu")]) |
95 | ||
96 | ;;;; Arithmetic/Logical | |
97 | ||
98 | ;; The arithmetic and logic operations below are defined for SI and DI | |
99 | ;; modes. The mode iterator AM is used in order to expand to two | |
100 | ;; insns, with the proper modes. | |
101 | ;; | |
102 | ;; 32-bit arithmetic (for SI modes) is implemented using the alu32 | |
5b2ab1d3 | 103 | ;; instructions, if available. |
91dfef96 | 104 | |
5b2ab1d3 | 105 | (define_mode_iterator AM [(SI "bpf_has_alu32") DI]) |
91dfef96 JM |
106 | |
107 | ;;; Addition | |
108 | (define_insn "add<AM:mode>3" | |
109 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
110 | (plus:AM (match_operand:AM 1 "register_operand" " 0,0") | |
111 | (match_operand:AM 2 "reg_or_imm_operand" " r,I")))] | |
112 | "1" | |
113 | "add<msuffix>\t%0,%2" | |
114 | [(set_attr "type" "<mtype>")]) | |
115 | ||
116 | ;;; Subtraction | |
117 | ||
118 | ;; Note that subtractions of constants become additions, so there is | |
119 | ;; no need to handle immediate operands in the subMODE3 insns. | |
120 | ||
121 | (define_insn "sub<AM:mode>3" | |
122 | [(set (match_operand:AM 0 "register_operand" "=r") | |
123 | (minus:AM (match_operand:AM 1 "register_operand" " 0") | |
124 | (match_operand:AM 2 "register_operand" " r")))] | |
125 | "" | |
126 | "sub<msuffix>\t%0,%2" | |
127 | [(set_attr "type" "<mtype>")]) | |
128 | ||
129 | ;;; Negation | |
130 | (define_insn "neg<AM:mode>2" | |
131 | [(set (match_operand:AM 0 "register_operand" "=r") | |
132 | (neg:AM (match_operand:AM 1 "register_operand" " 0")))] | |
133 | "" | |
134 | "neg<msuffix>\t%0" | |
135 | [(set_attr "type" "<mtype>")]) | |
136 | ||
137 | ;;; Multiplication | |
138 | (define_insn "mul<AM:mode>3" | |
139 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
140 | (mult:AM (match_operand:AM 1 "register_operand" " 0,0") | |
141 | (match_operand:AM 2 "reg_or_imm_operand" " r,I")))] | |
142 | "" | |
143 | "mul<msuffix>\t%0,%2" | |
144 | [(set_attr "type" "<mtype>")]) | |
145 | ||
146 | (define_insn "*mulsidi3_zeroextend" | |
147 | [(set (match_operand:DI 0 "register_operand" "=r,r") | |
148 | (zero_extend:DI | |
149 | (mult:SI (match_operand:SI 1 "register_operand" "0,0") | |
150 | (match_operand:SI 2 "reg_or_imm_operand" "r,I"))))] | |
151 | "" | |
152 | "mul32\t%0,%2" | |
153 | [(set_attr "type" "alu32")]) | |
154 | ||
155 | ;;; Division | |
156 | ||
157 | ;; Note that eBPF doesn't provide instructions for signed integer | |
158 | ;; division. | |
159 | ||
160 | (define_insn "udiv<AM:mode>3" | |
161 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
162 | (udiv:AM (match_operand:AM 1 "register_operand" " 0,0") | |
163 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
164 | "" | |
165 | "div<msuffix>\t%0,%2" | |
166 | [(set_attr "type" "<mtype>")]) | |
167 | ||
7c8ba5da DF |
168 | ;; However, xBPF does provide a signed division operator, sdiv. |
169 | ||
170 | (define_insn "div<AM:mode>3" | |
171 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
172 | (div:AM (match_operand:AM 1 "register_operand" " 0,0") | |
173 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
174 | "TARGET_XBPF" | |
175 | "sdiv<msuffix>\t%0,%2" | |
176 | [(set_attr "type" "<mtype>")]) | |
177 | ||
91dfef96 JM |
178 | ;;; Modulus |
179 | ||
180 | ;; Note that eBPF doesn't provide instructions for signed integer | |
181 | ;; remainder. | |
182 | ||
183 | (define_insn "umod<AM:mode>3" | |
184 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
185 | (umod:AM (match_operand:AM 1 "register_operand" " 0,0") | |
186 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
187 | "" | |
188 | "mod<msuffix>\t%0,%2" | |
189 | [(set_attr "type" "<mtype>")]) | |
190 | ||
7c8ba5da DF |
191 | ;; Again, xBPF provides a signed version, smod. |
192 | ||
193 | (define_insn "mod<AM:mode>3" | |
194 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
195 | (mod:AM (match_operand:AM 1 "register_operand" " 0,0") | |
196 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
197 | "TARGET_XBPF" | |
198 | "smod<msuffix>\t%0,%2" | |
199 | [(set_attr "type" "<mtype>")]) | |
200 | ||
91dfef96 JM |
201 | ;;; Logical AND |
202 | (define_insn "and<AM:mode>3" | |
203 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
204 | (and:AM (match_operand:AM 1 "register_operand" " 0,0") | |
205 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
206 | "" | |
207 | "and<msuffix>\t%0,%2" | |
208 | [(set_attr "type" "<mtype>")]) | |
209 | ||
210 | ;;; Logical inclusive-OR | |
211 | (define_insn "ior<AM:mode>3" | |
212 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
213 | (ior:AM (match_operand:AM 1 "register_operand" " 0,0") | |
214 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
215 | "" | |
216 | "or<msuffix>\t%0,%2" | |
217 | [(set_attr "type" "<mtype>")]) | |
218 | ||
219 | ;;; Logical exclusive-OR | |
220 | (define_insn "xor<AM:mode>3" | |
221 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
222 | (xor:AM (match_operand:AM 1 "register_operand" " 0,0") | |
223 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
224 | "" | |
225 | "xor<msuffix>\t%0,%2" | |
226 | [(set_attr "type" "<mtype>")]) | |
227 | ||
228 | ;;;; Conversions | |
229 | ||
230 | ;;; Zero-extensions | |
231 | ||
232 | ;; For register operands smaller than 32-bit zero-extending is | |
233 | ;; achieved ANDing the value in the source register to a suitable | |
234 | ;; mask. | |
235 | ;; | |
236 | ;; For register operands bigger or equal than 32-bit, we generate a | |
237 | ;; mov32 instruction to zero the high 32-bits of the destination | |
238 | ;; register. | |
239 | ;; | |
240 | ;; For memory operands, of any width, zero-extending is achieved using | |
241 | ;; the ldx{bhwdw} instructions to load the values in registers. | |
242 | ||
243 | (define_insn "zero_extendhidi2" | |
4f0f696f DF |
244 | [(set (match_operand:DI 0 "register_operand" "=r,r,r") |
245 | (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "0,r,m")))] | |
91dfef96 JM |
246 | "" |
247 | "@ | |
248 | and\t%0,0xffff | |
4f0f696f | 249 | mov\t%0,%1\;and\t%0,0xffff |
91dfef96 | 250 | ldxh\t%0,%1" |
4f0f696f | 251 | [(set_attr "type" "alu,alu,ldx")]) |
91dfef96 JM |
252 | |
253 | (define_insn "zero_extendqidi2" | |
4f0f696f DF |
254 | [(set (match_operand:DI 0 "register_operand" "=r,r,r") |
255 | (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "0,r,m")))] | |
91dfef96 JM |
256 | "" |
257 | "@ | |
258 | and\t%0,0xff | |
4f0f696f | 259 | mov\t%0,%1\;and\t%0,0xff |
91dfef96 | 260 | ldxb\t%0,%1" |
4f0f696f | 261 | [(set_attr "type" "alu,alu,ldx")]) |
91dfef96 JM |
262 | |
263 | (define_insn "zero_extendsidi2" | |
264 | [(set (match_operand:DI 0 "register_operand" "=r,r") | |
265 | (zero_extend:DI | |
266 | (match_operand:SI 1 "nonimmediate_operand" "r,m")))] | |
267 | "" | |
268 | "@ | |
5b2ab1d3 | 269 | * return bpf_has_alu32 ? \"mov32\t%0,%1\" : \"mov\t%0,%1\;and\t%0,0xffffffff\"; |
91dfef96 JM |
270 | ldxw\t%0,%1" |
271 | [(set_attr "type" "alu,ldx")]) | |
272 | ||
273 | ;;; Sign-extension | |
274 | ||
275 | ;; Sign-extending a 32-bit value into a 64-bit value is achieved using | |
276 | ;; shifting, with instructions generated by the expand below. | |
277 | ||
278 | (define_expand "extendsidi2" | |
279 | [(set (match_operand:DI 0 "register_operand") | |
280 | (sign_extend:DI (match_operand:SI 1 "register_operand")))] | |
281 | "" | |
282 | { | |
283 | operands[1] = gen_lowpart (DImode, operands[1]); | |
284 | emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (32))); | |
285 | emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (32))); | |
286 | DONE; | |
287 | }) | |
288 | ||
289 | ;;;; Data movement | |
290 | ||
291 | (define_mode_iterator MM [QI HI SI DI SF DF]) | |
292 | ||
293 | (define_expand "mov<MM:mode>" | |
294 | [(set (match_operand:MM 0 "general_operand") | |
295 | (match_operand:MM 1 "general_operand"))] | |
296 | "" | |
297 | " | |
298 | { | |
299 | if (!register_operand(operands[0], <MM:MODE>mode) | |
300 | && !register_operand(operands[1], <MM:MODE>mode)) | |
e87c540f | 301 | operands[1] = force_reg (<MM:MODE>mode, operands[1]); |
91dfef96 JM |
302 | }") |
303 | ||
304 | (define_insn "*mov<MM:mode>" | |
305 | [(set (match_operand:MM 0 "nonimmediate_operand" "=r, r,r,m,m") | |
306 | (match_operand:MM 1 "mov_src_operand" " m,rI,B,r,I"))] | |
307 | "" | |
308 | "@ | |
309 | ldx<mop>\t%0,%1 | |
310 | mov\t%0,%1 | |
311 | lddw\t%0,%1 | |
312 | stx<mop>\t%0,%1 | |
313 | st<mop>\t%0,%1" | |
314 | [(set_attr "type" "ldx,alu,alu,stx,st")]) | |
315 | ||
316 | ;;;; Shifts | |
317 | ||
5b2ab1d3 | 318 | (define_mode_iterator SIM [(SI "bpf_has_alu32") DI]) |
91dfef96 JM |
319 | |
320 | (define_insn "ashr<SIM:mode>3" | |
321 | [(set (match_operand:SIM 0 "register_operand" "=r,r") | |
322 | (ashiftrt:SIM (match_operand:SIM 1 "register_operand" " 0,0") | |
323 | (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))] | |
324 | "" | |
325 | "arsh<msuffix>\t%0,%2" | |
326 | [(set_attr "type" "<mtype>")]) | |
327 | ||
328 | (define_insn "ashl<SIM:mode>3" | |
329 | [(set (match_operand:SIM 0 "register_operand" "=r,r") | |
330 | (ashift:SIM (match_operand:SIM 1 "register_operand" " 0,0") | |
331 | (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))] | |
332 | "" | |
333 | "lsh<msuffix>\t%0,%2" | |
334 | [(set_attr "type" "<mtype>")]) | |
335 | ||
336 | (define_insn "lshr<SIM:mode>3" | |
337 | [(set (match_operand:SIM 0 "register_operand" "=r,r") | |
338 | (lshiftrt:SIM (match_operand:SIM 1 "register_operand" " 0,0") | |
339 | (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))] | |
340 | "" | |
341 | "rsh<msuffix>\t%0,%2" | |
342 | [(set_attr "type" "<mtype>")]) | |
343 | ||
344 | ;;;; Conditional branches | |
345 | ||
346 | ;; The eBPF jump instructions use 64-bit arithmetic when evaluating | |
347 | ;; the jump conditions. Therefore we use DI modes below. | |
348 | ||
5b2ab1d3 DF |
349 | (define_mode_iterator JM [(SI "bpf_has_jmp32") DI]) |
350 | ||
351 | (define_expand "cbranch<JM:mode>4" | |
91dfef96 JM |
352 | [(set (pc) |
353 | (if_then_else (match_operator 0 "comparison_operator" | |
5b2ab1d3 DF |
354 | [(match_operand:JM 1 "register_operand") |
355 | (match_operand:JM 2 "reg_or_imm_operand")]) | |
91dfef96 JM |
356 | (label_ref (match_operand 3 "" "")) |
357 | (pc)))] | |
358 | "" | |
359 | { | |
360 | if (!ordered_comparison_operator (operands[0], VOIDmode)) | |
361 | FAIL; | |
5b2ab1d3 DF |
362 | |
363 | bpf_expand_cbranch (<JM:MODE>mode, operands); | |
91dfef96 JM |
364 | }) |
365 | ||
5b2ab1d3 | 366 | (define_insn "*branch_on_<JM:mode>" |
91dfef96 JM |
367 | [(set (pc) |
368 | (if_then_else (match_operator 3 "ordered_comparison_operator" | |
5b2ab1d3 DF |
369 | [(match_operand:JM 0 "register_operand" "r") |
370 | (match_operand:JM 1 "reg_or_imm_operand" "rI")]) | |
91dfef96 JM |
371 | (label_ref (match_operand 2 "" "")) |
372 | (pc)))] | |
373 | "" | |
374 | { | |
375 | int code = GET_CODE (operands[3]); | |
376 | ||
377 | switch (code) | |
378 | { | |
5b2ab1d3 DF |
379 | case EQ: return "jeq<msuffix>\t%0,%1,%2"; break; |
380 | case NE: return "jne<msuffix>\t%0,%1,%2"; break; | |
381 | case LT: return "jslt<msuffix>\t%0,%1,%2"; break; | |
382 | case LE: return "jsle<msuffix>\t%0,%1,%2"; break; | |
383 | case GT: return "jsgt<msuffix>\t%0,%1,%2"; break; | |
384 | case GE: return "jsge<msuffix>\t%0,%1,%2"; break; | |
385 | case LTU: return "jlt<msuffix>\t%0,%1,%2"; break; | |
386 | case LEU: return "jle<msuffix>\t%0,%1,%2"; break; | |
387 | case GTU: return "jgt<msuffix>\t%0,%1,%2"; break; | |
388 | case GEU: return "jge<msuffix>\t%0,%1,%2"; break; | |
91dfef96 JM |
389 | default: |
390 | gcc_unreachable (); | |
391 | return ""; | |
392 | } | |
393 | } | |
394 | [(set_attr "type" "jmp")]) | |
395 | ||
396 | ;;;; Unconditional branches | |
397 | ||
398 | (define_insn "jump" | |
399 | [(set (pc) | |
400 | (label_ref (match_operand 0 "" "")))] | |
401 | "" | |
402 | "ja\t%0" | |
403 | [(set_attr "type" "jmp")]) | |
404 | ||
405 | ;;;; Function prologue/epilogue | |
406 | ||
407 | (define_insn "exit" | |
408 | [(simple_return)] | |
409 | "" | |
410 | "exit" | |
411 | [(set_attr "type" "jmp")]) | |
412 | ||
413 | (define_expand "prologue" | |
414 | [(const_int 0)] | |
415 | "" | |
416 | { | |
417 | bpf_expand_prologue (); | |
418 | DONE; | |
419 | }) | |
420 | ||
421 | (define_expand "epilogue" | |
422 | [(const_int 0)] | |
423 | "" | |
424 | { | |
425 | bpf_expand_epilogue (); | |
426 | DONE; | |
427 | }) | |
428 | ||
429 | ;;;; Function calls | |
430 | ||
431 | (define_expand "call" | |
432 | [(parallel [(call (match_operand 0 "") | |
433 | (match_operand 1 "")) | |
434 | (use (match_operand 2 "")) ;; next_arg_reg | |
435 | (use (match_operand 3 ""))])] ;; struct_value_size_rtx | |
436 | "" | |
437 | { | |
438 | rtx target = XEXP (operands[0], 0); | |
439 | emit_call_insn (gen_call_internal (target, operands[1])); | |
440 | DONE; | |
441 | }) | |
442 | ||
443 | (define_insn "call_internal" | |
444 | [(call (mem:DI (match_operand:DI 0 "call_operand" "Sr")) | |
445 | (match_operand:SI 1 "general_operand" ""))] | |
446 | ;; operands[2] is next_arg_register | |
447 | ;; operands[3] is struct_value_size_rtx. | |
448 | "" | |
449 | { return bpf_output_call (operands[0]); } | |
450 | [(set_attr "type" "jmp")]) | |
451 | ||
452 | (define_expand "call_value" | |
453 | [(parallel [(set (match_operand 0 "") | |
454 | (call (match_operand 1 "") | |
455 | (match_operand 2 ""))) | |
456 | (use (match_operand 3 ""))])] ;; next_arg_reg | |
457 | "" | |
458 | { | |
459 | rtx target = XEXP (operands[1], 0); | |
460 | emit_call_insn (gen_call_value_internal (operands[0], target, | |
461 | operands[2])); | |
462 | DONE; | |
463 | }) | |
464 | ||
465 | (define_insn "call_value_internal" | |
466 | [(set (match_operand 0 "register_operand" "") | |
467 | (call (mem:DI (match_operand:DI 1 "call_operand" "Sr")) | |
468 | (match_operand:SI 2 "general_operand" "")))] | |
469 | ;; operands[3] is next_arg_register | |
470 | ;; operands[4] is struct_value_size_rtx. | |
471 | "" | |
472 | { return bpf_output_call (operands[1]); } | |
473 | [(set_attr "type" "jmp")]) | |
474 | ||
475 | (define_insn "sibcall" | |
476 | [(call (label_ref (match_operand 0 "" "")) | |
477 | (match_operand:SI 1 "general_operand" ""))] | |
478 | ;; operands[2] is next_arg_register | |
479 | ;; operands[3] is struct_value_size_rtx. | |
480 | "" | |
481 | "ja\t%0" | |
482 | [(set_attr "type" "jmp")]) | |
483 | ||
484 | ;;;; Non-generic load instructions | |
485 | ||
486 | (define_mode_iterator LDM [QI HI SI DI]) | |
487 | (define_mode_attr ldop [(QI "b") (HI "h") (SI "w") (DI "dw")]) | |
488 | ||
489 | (define_insn "ldind<ldop>" | |
490 | [(set (reg:LDM R0_REGNUM) | |
491 | (unspec:LDM [(match_operand:DI 0 "register_operand" "r") | |
492 | (match_operand:SI 1 "imm32_operand" "I")] | |
493 | UNSPEC_LDINDABS)) | |
494 | (clobber (reg:DI R1_REGNUM)) | |
495 | (clobber (reg:DI R2_REGNUM)) | |
496 | (clobber (reg:DI R3_REGNUM)) | |
497 | (clobber (reg:DI R4_REGNUM))] | |
498 | "" | |
499 | "ldind<ldop>\t%0,%1" | |
500 | [(set_attr "type" "ld")]) | |
501 | ||
502 | (define_insn "ldabs<ldop>" | |
503 | [(set (reg:LDM R0_REGNUM) | |
504 | (unspec:LDM [(match_operand:SI 0 "imm32_operand" "I") | |
505 | (match_operand:SI 1 "imm32_operand" "I")] | |
506 | UNSPEC_LDINDABS)) | |
507 | (clobber (reg:DI R1_REGNUM)) | |
508 | (clobber (reg:DI R2_REGNUM)) | |
509 | (clobber (reg:DI R3_REGNUM)) | |
510 | (clobber (reg:DI R4_REGNUM))] | |
511 | "" | |
512 | "ldabs<ldop>\t%0" | |
513 | [(set_attr "type" "ld")]) | |
514 | ||
515 | ;;;; Atomic increments | |
516 | ||
517 | (define_mode_iterator AMO [SI DI]) | |
518 | ||
519 | (define_insn "atomic_add<AMO:mode>" | |
520 | [(set (match_operand:AMO 0 "memory_operand" "+m") | |
521 | (unspec_volatile:AMO | |
522 | [(plus:AMO (match_dup 0) | |
523 | (match_operand:AMO 1 "register_operand" "r")) | |
524 | (match_operand:SI 2 "const_int_operand")] ;; Memory model. | |
525 | UNSPEC_XADD))] | |
526 | "" | |
527 | "xadd<mop>\t%0,%1" | |
528 | [(set_attr "type" "xadd")]) |