]>
Commit | Line | Data |
---|---|---|
91dfef96 | 1 | ;; Machine description for eBPF. |
8d9254fc | 2 | ;; Copyright (C) 2019-2020 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 | ||
85 | (define_insn "nop" | |
86 | [(const_int 0)] | |
87 | "" | |
88 | "mov\t%%r0,%%r0" | |
89 | [(set_attr "type" "alu")]) | |
90 | ||
91 | ;;;; Arithmetic/Logical | |
92 | ||
93 | ;; The arithmetic and logic operations below are defined for SI and DI | |
94 | ;; modes. The mode iterator AM is used in order to expand to two | |
95 | ;; insns, with the proper modes. | |
96 | ;; | |
97 | ;; 32-bit arithmetic (for SI modes) is implemented using the alu32 | |
98 | ;; instructions. | |
99 | ||
100 | (define_mode_iterator AM [SI DI]) | |
101 | ||
102 | ;;; Addition | |
103 | (define_insn "add<AM:mode>3" | |
104 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
105 | (plus:AM (match_operand:AM 1 "register_operand" " 0,0") | |
106 | (match_operand:AM 2 "reg_or_imm_operand" " r,I")))] | |
107 | "1" | |
108 | "add<msuffix>\t%0,%2" | |
109 | [(set_attr "type" "<mtype>")]) | |
110 | ||
111 | ;;; Subtraction | |
112 | ||
113 | ;; Note that subtractions of constants become additions, so there is | |
114 | ;; no need to handle immediate operands in the subMODE3 insns. | |
115 | ||
116 | (define_insn "sub<AM:mode>3" | |
117 | [(set (match_operand:AM 0 "register_operand" "=r") | |
118 | (minus:AM (match_operand:AM 1 "register_operand" " 0") | |
119 | (match_operand:AM 2 "register_operand" " r")))] | |
120 | "" | |
121 | "sub<msuffix>\t%0,%2" | |
122 | [(set_attr "type" "<mtype>")]) | |
123 | ||
124 | ;;; Negation | |
125 | (define_insn "neg<AM:mode>2" | |
126 | [(set (match_operand:AM 0 "register_operand" "=r") | |
127 | (neg:AM (match_operand:AM 1 "register_operand" " 0")))] | |
128 | "" | |
129 | "neg<msuffix>\t%0" | |
130 | [(set_attr "type" "<mtype>")]) | |
131 | ||
132 | ;;; Multiplication | |
133 | (define_insn "mul<AM:mode>3" | |
134 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
135 | (mult:AM (match_operand:AM 1 "register_operand" " 0,0") | |
136 | (match_operand:AM 2 "reg_or_imm_operand" " r,I")))] | |
137 | "" | |
138 | "mul<msuffix>\t%0,%2" | |
139 | [(set_attr "type" "<mtype>")]) | |
140 | ||
141 | (define_insn "*mulsidi3_zeroextend" | |
142 | [(set (match_operand:DI 0 "register_operand" "=r,r") | |
143 | (zero_extend:DI | |
144 | (mult:SI (match_operand:SI 1 "register_operand" "0,0") | |
145 | (match_operand:SI 2 "reg_or_imm_operand" "r,I"))))] | |
146 | "" | |
147 | "mul32\t%0,%2" | |
148 | [(set_attr "type" "alu32")]) | |
149 | ||
150 | ;;; Division | |
151 | ||
152 | ;; Note that eBPF doesn't provide instructions for signed integer | |
153 | ;; division. | |
154 | ||
155 | (define_insn "udiv<AM:mode>3" | |
156 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
157 | (udiv:AM (match_operand:AM 1 "register_operand" " 0,0") | |
158 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
159 | "" | |
160 | "div<msuffix>\t%0,%2" | |
161 | [(set_attr "type" "<mtype>")]) | |
162 | ||
163 | ;;; Modulus | |
164 | ||
165 | ;; Note that eBPF doesn't provide instructions for signed integer | |
166 | ;; remainder. | |
167 | ||
168 | (define_insn "umod<AM:mode>3" | |
169 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
170 | (umod:AM (match_operand:AM 1 "register_operand" " 0,0") | |
171 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
172 | "" | |
173 | "mod<msuffix>\t%0,%2" | |
174 | [(set_attr "type" "<mtype>")]) | |
175 | ||
176 | ;;; Logical AND | |
177 | (define_insn "and<AM:mode>3" | |
178 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
179 | (and:AM (match_operand:AM 1 "register_operand" " 0,0") | |
180 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
181 | "" | |
182 | "and<msuffix>\t%0,%2" | |
183 | [(set_attr "type" "<mtype>")]) | |
184 | ||
185 | ;;; Logical inclusive-OR | |
186 | (define_insn "ior<AM:mode>3" | |
187 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
188 | (ior:AM (match_operand:AM 1 "register_operand" " 0,0") | |
189 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
190 | "" | |
191 | "or<msuffix>\t%0,%2" | |
192 | [(set_attr "type" "<mtype>")]) | |
193 | ||
194 | ;;; Logical exclusive-OR | |
195 | (define_insn "xor<AM:mode>3" | |
196 | [(set (match_operand:AM 0 "register_operand" "=r,r") | |
197 | (xor:AM (match_operand:AM 1 "register_operand" " 0,0") | |
198 | (match_operand:AM 2 "reg_or_imm_operand" "r,I")))] | |
199 | "" | |
200 | "xor<msuffix>\t%0,%2" | |
201 | [(set_attr "type" "<mtype>")]) | |
202 | ||
203 | ;;;; Conversions | |
204 | ||
205 | ;;; Zero-extensions | |
206 | ||
207 | ;; For register operands smaller than 32-bit zero-extending is | |
208 | ;; achieved ANDing the value in the source register to a suitable | |
209 | ;; mask. | |
210 | ;; | |
211 | ;; For register operands bigger or equal than 32-bit, we generate a | |
212 | ;; mov32 instruction to zero the high 32-bits of the destination | |
213 | ;; register. | |
214 | ;; | |
215 | ;; For memory operands, of any width, zero-extending is achieved using | |
216 | ;; the ldx{bhwdw} instructions to load the values in registers. | |
217 | ||
218 | (define_insn "zero_extendhidi2" | |
219 | [(set (match_operand:DI 0 "register_operand" "=r,r") | |
220 | (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] | |
221 | "" | |
222 | "@ | |
223 | and\t%0,0xffff | |
224 | ldxh\t%0,%1" | |
225 | [(set_attr "type" "alu,ldx")]) | |
226 | ||
227 | (define_insn "zero_extendqidi2" | |
228 | [(set (match_operand:DI 0 "register_operand" "=r,r") | |
229 | (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] | |
230 | "" | |
231 | "@ | |
232 | and\t%0,0xff | |
233 | ldxb\t%0,%1" | |
234 | [(set_attr "type" "alu,ldx")]) | |
235 | ||
236 | (define_insn "zero_extendsidi2" | |
237 | [(set (match_operand:DI 0 "register_operand" "=r,r") | |
238 | (zero_extend:DI | |
239 | (match_operand:SI 1 "nonimmediate_operand" "r,m")))] | |
240 | "" | |
241 | "@ | |
242 | mov32\t%0,%1 | |
243 | ldxw\t%0,%1" | |
244 | [(set_attr "type" "alu,ldx")]) | |
245 | ||
246 | ;;; Sign-extension | |
247 | ||
248 | ;; Sign-extending a 32-bit value into a 64-bit value is achieved using | |
249 | ;; shifting, with instructions generated by the expand below. | |
250 | ||
251 | (define_expand "extendsidi2" | |
252 | [(set (match_operand:DI 0 "register_operand") | |
253 | (sign_extend:DI (match_operand:SI 1 "register_operand")))] | |
254 | "" | |
255 | { | |
256 | operands[1] = gen_lowpart (DImode, operands[1]); | |
257 | emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (32))); | |
258 | emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (32))); | |
259 | DONE; | |
260 | }) | |
261 | ||
262 | ;;;; Data movement | |
263 | ||
264 | (define_mode_iterator MM [QI HI SI DI SF DF]) | |
265 | ||
266 | (define_expand "mov<MM:mode>" | |
267 | [(set (match_operand:MM 0 "general_operand") | |
268 | (match_operand:MM 1 "general_operand"))] | |
269 | "" | |
270 | " | |
271 | { | |
272 | if (!register_operand(operands[0], <MM:MODE>mode) | |
273 | && !register_operand(operands[1], <MM:MODE>mode)) | |
274 | operands[1] = force_reg (<MM:MODE>mode, operands[1]); | |
275 | }") | |
276 | ||
277 | (define_insn "*mov<MM:mode>" | |
278 | [(set (match_operand:MM 0 "nonimmediate_operand" "=r, r,r,m,m") | |
279 | (match_operand:MM 1 "mov_src_operand" " m,rI,B,r,I"))] | |
280 | "" | |
281 | "@ | |
282 | ldx<mop>\t%0,%1 | |
283 | mov\t%0,%1 | |
284 | lddw\t%0,%1 | |
285 | stx<mop>\t%0,%1 | |
286 | st<mop>\t%0,%1" | |
287 | [(set_attr "type" "ldx,alu,alu,stx,st")]) | |
288 | ||
289 | ;;;; Shifts | |
290 | ||
291 | (define_mode_iterator SIM [SI DI]) | |
292 | ||
293 | (define_insn "ashr<SIM:mode>3" | |
294 | [(set (match_operand:SIM 0 "register_operand" "=r,r") | |
295 | (ashiftrt:SIM (match_operand:SIM 1 "register_operand" " 0,0") | |
296 | (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))] | |
297 | "" | |
298 | "arsh<msuffix>\t%0,%2" | |
299 | [(set_attr "type" "<mtype>")]) | |
300 | ||
301 | (define_insn "ashl<SIM:mode>3" | |
302 | [(set (match_operand:SIM 0 "register_operand" "=r,r") | |
303 | (ashift:SIM (match_operand:SIM 1 "register_operand" " 0,0") | |
304 | (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))] | |
305 | "" | |
306 | "lsh<msuffix>\t%0,%2" | |
307 | [(set_attr "type" "<mtype>")]) | |
308 | ||
309 | (define_insn "lshr<SIM:mode>3" | |
310 | [(set (match_operand:SIM 0 "register_operand" "=r,r") | |
311 | (lshiftrt:SIM (match_operand:SIM 1 "register_operand" " 0,0") | |
312 | (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))] | |
313 | "" | |
314 | "rsh<msuffix>\t%0,%2" | |
315 | [(set_attr "type" "<mtype>")]) | |
316 | ||
317 | ;;;; Conditional branches | |
318 | ||
319 | ;; The eBPF jump instructions use 64-bit arithmetic when evaluating | |
320 | ;; the jump conditions. Therefore we use DI modes below. | |
321 | ||
322 | (define_expand "cbranchdi4" | |
323 | [(set (pc) | |
324 | (if_then_else (match_operator 0 "comparison_operator" | |
325 | [(match_operand:DI 1 "register_operand") | |
326 | (match_operand:DI 2 "reg_or_imm_operand")]) | |
327 | (label_ref (match_operand 3 "" "")) | |
328 | (pc)))] | |
329 | "" | |
330 | { | |
331 | if (!ordered_comparison_operator (operands[0], VOIDmode)) | |
332 | FAIL; | |
333 | }) | |
334 | ||
335 | (define_insn "*branch_on_di" | |
336 | [(set (pc) | |
337 | (if_then_else (match_operator 3 "ordered_comparison_operator" | |
338 | [(match_operand:DI 0 "register_operand" "r") | |
339 | (match_operand:DI 1 "reg_or_imm_operand" "rI")]) | |
340 | (label_ref (match_operand 2 "" "")) | |
341 | (pc)))] | |
342 | "" | |
343 | { | |
344 | int code = GET_CODE (operands[3]); | |
345 | ||
346 | switch (code) | |
347 | { | |
348 | case EQ: return "jeq\t%0,%1,%2"; break; | |
349 | case NE: return "jne\t%0,%1,%2"; break; | |
350 | case LT: return "jslt\t%0,%1,%2"; break; | |
351 | case LE: return "jsle\t%0,%1,%2"; break; | |
352 | case GT: return "jsgt\t%0,%1,%2"; break; | |
353 | case GE: return "jsge\t%0,%1,%2"; break; | |
354 | case LTU: return "jlt\t%0,%1,%2"; break; | |
355 | case LEU: return "jle\t%0,%1,%2"; break; | |
356 | case GTU: return "jgt\t%0,%1,%2"; break; | |
357 | case GEU: return "jge\t%0,%1,%2"; break; | |
358 | default: | |
359 | gcc_unreachable (); | |
360 | return ""; | |
361 | } | |
362 | } | |
363 | [(set_attr "type" "jmp")]) | |
364 | ||
365 | ;;;; Unconditional branches | |
366 | ||
367 | (define_insn "jump" | |
368 | [(set (pc) | |
369 | (label_ref (match_operand 0 "" "")))] | |
370 | "" | |
371 | "ja\t%0" | |
372 | [(set_attr "type" "jmp")]) | |
373 | ||
374 | ;;;; Function prologue/epilogue | |
375 | ||
376 | (define_insn "exit" | |
377 | [(simple_return)] | |
378 | "" | |
379 | "exit" | |
380 | [(set_attr "type" "jmp")]) | |
381 | ||
382 | (define_expand "prologue" | |
383 | [(const_int 0)] | |
384 | "" | |
385 | { | |
386 | bpf_expand_prologue (); | |
387 | DONE; | |
388 | }) | |
389 | ||
390 | (define_expand "epilogue" | |
391 | [(const_int 0)] | |
392 | "" | |
393 | { | |
394 | bpf_expand_epilogue (); | |
395 | DONE; | |
396 | }) | |
397 | ||
398 | ;;;; Function calls | |
399 | ||
400 | (define_expand "call" | |
401 | [(parallel [(call (match_operand 0 "") | |
402 | (match_operand 1 "")) | |
403 | (use (match_operand 2 "")) ;; next_arg_reg | |
404 | (use (match_operand 3 ""))])] ;; struct_value_size_rtx | |
405 | "" | |
406 | { | |
407 | rtx target = XEXP (operands[0], 0); | |
408 | emit_call_insn (gen_call_internal (target, operands[1])); | |
409 | DONE; | |
410 | }) | |
411 | ||
412 | (define_insn "call_internal" | |
413 | [(call (mem:DI (match_operand:DI 0 "call_operand" "Sr")) | |
414 | (match_operand:SI 1 "general_operand" ""))] | |
415 | ;; operands[2] is next_arg_register | |
416 | ;; operands[3] is struct_value_size_rtx. | |
417 | "" | |
418 | { return bpf_output_call (operands[0]); } | |
419 | [(set_attr "type" "jmp")]) | |
420 | ||
421 | (define_expand "call_value" | |
422 | [(parallel [(set (match_operand 0 "") | |
423 | (call (match_operand 1 "") | |
424 | (match_operand 2 ""))) | |
425 | (use (match_operand 3 ""))])] ;; next_arg_reg | |
426 | "" | |
427 | { | |
428 | rtx target = XEXP (operands[1], 0); | |
429 | emit_call_insn (gen_call_value_internal (operands[0], target, | |
430 | operands[2])); | |
431 | DONE; | |
432 | }) | |
433 | ||
434 | (define_insn "call_value_internal" | |
435 | [(set (match_operand 0 "register_operand" "") | |
436 | (call (mem:DI (match_operand:DI 1 "call_operand" "Sr")) | |
437 | (match_operand:SI 2 "general_operand" "")))] | |
438 | ;; operands[3] is next_arg_register | |
439 | ;; operands[4] is struct_value_size_rtx. | |
440 | "" | |
441 | { return bpf_output_call (operands[1]); } | |
442 | [(set_attr "type" "jmp")]) | |
443 | ||
444 | (define_insn "sibcall" | |
445 | [(call (label_ref (match_operand 0 "" "")) | |
446 | (match_operand:SI 1 "general_operand" ""))] | |
447 | ;; operands[2] is next_arg_register | |
448 | ;; operands[3] is struct_value_size_rtx. | |
449 | "" | |
450 | "ja\t%0" | |
451 | [(set_attr "type" "jmp")]) | |
452 | ||
453 | ;;;; Non-generic load instructions | |
454 | ||
455 | (define_mode_iterator LDM [QI HI SI DI]) | |
456 | (define_mode_attr ldop [(QI "b") (HI "h") (SI "w") (DI "dw")]) | |
457 | ||
458 | (define_insn "ldind<ldop>" | |
459 | [(set (reg:LDM R0_REGNUM) | |
460 | (unspec:LDM [(match_operand:DI 0 "register_operand" "r") | |
461 | (match_operand:SI 1 "imm32_operand" "I")] | |
462 | UNSPEC_LDINDABS)) | |
463 | (clobber (reg:DI R1_REGNUM)) | |
464 | (clobber (reg:DI R2_REGNUM)) | |
465 | (clobber (reg:DI R3_REGNUM)) | |
466 | (clobber (reg:DI R4_REGNUM))] | |
467 | "" | |
468 | "ldind<ldop>\t%0,%1" | |
469 | [(set_attr "type" "ld")]) | |
470 | ||
471 | (define_insn "ldabs<ldop>" | |
472 | [(set (reg:LDM R0_REGNUM) | |
473 | (unspec:LDM [(match_operand:SI 0 "imm32_operand" "I") | |
474 | (match_operand:SI 1 "imm32_operand" "I")] | |
475 | UNSPEC_LDINDABS)) | |
476 | (clobber (reg:DI R1_REGNUM)) | |
477 | (clobber (reg:DI R2_REGNUM)) | |
478 | (clobber (reg:DI R3_REGNUM)) | |
479 | (clobber (reg:DI R4_REGNUM))] | |
480 | "" | |
481 | "ldabs<ldop>\t%0" | |
482 | [(set_attr "type" "ld")]) | |
483 | ||
484 | ;;;; Atomic increments | |
485 | ||
486 | (define_mode_iterator AMO [SI DI]) | |
487 | ||
488 | (define_insn "atomic_add<AMO:mode>" | |
489 | [(set (match_operand:AMO 0 "memory_operand" "+m") | |
490 | (unspec_volatile:AMO | |
491 | [(plus:AMO (match_dup 0) | |
492 | (match_operand:AMO 1 "register_operand" "r")) | |
493 | (match_operand:SI 2 "const_int_operand")] ;; Memory model. | |
494 | UNSPEC_XADD))] | |
495 | "" | |
496 | "xadd<mop>\t%0,%1" | |
497 | [(set_attr "type" "xadd")]) |