]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/bpf/bpf.md
Update copyright years.
[thirdparty/gcc.git] / gcc / config / bpf / bpf.md
CommitLineData
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")])