1 ;; Machine description for eBPF.
2 ;; Copyright (C) 2019-2023 Free Software Foundation, Inc.
4 ;; This file is part of GCC.
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)
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.
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/>.
20 (include "predicates.md")
21 (include "constraints.md")
23 ;;;; Instruction Scheduler FSM
25 ;; This is just to get INSN_SCHEDULING defined, so that combine does
26 ;; not make paradoxical subregs of memory. These subregs seems to
27 ;; confuse LRA that ends generating wrong instructions.
29 (define_automaton "frob")
30 (define_cpu_unit "frob_unit" "frob")
31 (define_insn_reservation "frobnicator" 814
32 (const_int 0) "frob_unit")
36 (define_c_enum "unspec" [
70 ;; Instruction classes.
71 ;; alu 64-bit arithmetic.
72 ;; alu32 32-bit arithmetic.
73 ;; end endianness conversion or byte swap instructions.
74 ;; ld load instructions.
75 ;; lddx load 64-bit immediate instruction.
76 ;; ldx generic load instructions.
77 ;; st generic store instructions for immediates.
78 ;; stx generic store instructions.
79 ;; jmp jump instructions.
80 ;; multi multiword sequence (or user asm statements).
83 "unknown,alu,alu32,end,ld,lddw,ldx,st,stx,jmp,multi,atomic"
84 (const_string "unknown"))
86 ;; Length of instruction in bytes.
87 (define_attr "length" ""
89 (eq_attr "type" "lddw") (const_int 16)
92 ;; Describe a user's asm statement.
93 (define_asm_attributes
94 [(set_attr "type" "multi")])
96 ;;;; Mode attributes and iterators
98 (define_mode_attr mop [(QI "b") (HI "h") (SI "w") (DI "dw")
100 (define_mode_attr smop [(QI "u8") (HI "u16") (SI "u32") (DI "u64")
101 (SF "u32") (DF "u64")])
102 (define_mode_attr mtype [(SI "alu32") (DI "alu")])
103 (define_mode_attr msuffix [(SI "32") (DI "")])
107 ;; The Linux kernel verifier performs some optimizations that rely on
108 ;; nop instructions to be encoded as `ja 0', i.e. a jump to offset 0,
109 ;; which actually means to jump to the next instruction, since in BPF
110 ;; offsets are expressed in 64-bit words _minus one_.
116 [(set_attr "type" "alu")])
120 (define_expand "allocate_stack"
121 [(match_operand:DI 0 "general_operand" "")
122 (match_operand:DI 1 "general_operand" "")]
126 error (\"BPF does not support dynamic stack allocation\");
127 emit_insn (gen_nop ());
131 ;;;; Arithmetic/Logical
133 ;; The arithmetic and logic operations below are defined for SI and DI
134 ;; modes. The mode iterator AM is used in order to expand to two
135 ;; insns, with the proper modes.
137 ;; 32-bit arithmetic (for SI modes) is implemented using the alu32
138 ;; instructions, if available.
140 (define_mode_iterator AM [(SI "bpf_has_alu32") DI])
143 (define_insn "add<AM:mode>3"
144 [(set (match_operand:AM 0 "register_operand" "=r,r")
145 (plus:AM (match_operand:AM 1 "register_operand" " 0,0")
146 (match_operand:AM 2 "reg_or_imm_operand" " r,I")))]
148 "{add<msuffix>\t%0,%2|%w0 += %w2}"
149 [(set_attr "type" "<mtype>")])
153 ;; Note that subtractions of constants become additions, so there is
154 ;; no need to handle immediate operands in the subMODE3 insns.
156 (define_insn "sub<AM:mode>3"
157 [(set (match_operand:AM 0 "register_operand" "=r")
158 (minus:AM (match_operand:AM 1 "register_operand" " 0")
159 (match_operand:AM 2 "register_operand" " r")))]
161 "{sub<msuffix>\t%0,%2|%w0 -= %w2}"
162 [(set_attr "type" "<mtype>")])
165 (define_insn "neg<AM:mode>2"
166 [(set (match_operand:AM 0 "register_operand" "=r")
167 (neg:AM (match_operand:AM 1 "register_operand" " 0")))]
169 "{neg<msuffix>\t%0|%w0 = -%w1}"
170 [(set_attr "type" "<mtype>")])
173 (define_insn "mul<AM:mode>3"
174 [(set (match_operand:AM 0 "register_operand" "=r,r")
175 (mult:AM (match_operand:AM 1 "register_operand" " 0,0")
176 (match_operand:AM 2 "reg_or_imm_operand" " r,I")))]
178 "{mul<msuffix>\t%0,%2|%w0 *= %w2}"
179 [(set_attr "type" "<mtype>")])
181 (define_insn "*mulsidi3_zeroextend"
182 [(set (match_operand:DI 0 "register_operand" "=r,r")
184 (mult:SI (match_operand:SI 1 "register_operand" "0,0")
185 (match_operand:SI 2 "reg_or_imm_operand" "r,I"))))]
187 "{mul32\t%0,%2|%W0 *= %W2}"
188 [(set_attr "type" "alu32")])
192 ;; Note that eBPF <= V3 doesn't provide instructions for signed
195 (define_insn "udiv<AM:mode>3"
196 [(set (match_operand:AM 0 "register_operand" "=r,r")
197 (udiv:AM (match_operand:AM 1 "register_operand" " 0,0")
198 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
200 "{div<msuffix>\t%0,%2|%w0 /= %w2}"
201 [(set_attr "type" "<mtype>")])
203 ;; However, BPF V4 does provide a signed division operator, sdiv.
205 (define_insn "div<AM:mode>3"
206 [(set (match_operand:AM 0 "register_operand" "=r,r")
207 (div:AM (match_operand:AM 1 "register_operand" " 0,0")
208 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
210 "{sdiv<msuffix>\t%0,%2|%w0 s/= %w2}"
211 [(set_attr "type" "<mtype>")])
215 ;; Note that eBPF <= V3 doesn't provide instructions for signed
216 ;; integer remainder.
218 (define_insn "umod<AM:mode>3"
219 [(set (match_operand:AM 0 "register_operand" "=r,r")
220 (umod:AM (match_operand:AM 1 "register_operand" " 0,0")
221 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
223 "{mod<msuffix>\t%0,%2|%w0 %%= %w2}"
224 [(set_attr "type" "<mtype>")])
226 ;; However, BPF V4 does provide a signed modulus operator, smod.
228 (define_insn "mod<AM:mode>3"
229 [(set (match_operand:AM 0 "register_operand" "=r,r")
230 (mod:AM (match_operand:AM 1 "register_operand" " 0,0")
231 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
233 "{smod<msuffix>\t%0,%2|%w0 s%%= %w2}"
234 [(set_attr "type" "<mtype>")])
237 (define_insn "and<AM:mode>3"
238 [(set (match_operand:AM 0 "register_operand" "=r,r")
239 (and:AM (match_operand:AM 1 "register_operand" " 0,0")
240 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
242 "{and<msuffix>\t%0,%2|%w0 &= %w2}"
243 [(set_attr "type" "<mtype>")])
245 ;;; Logical inclusive-OR
246 (define_insn "ior<AM:mode>3"
247 [(set (match_operand:AM 0 "register_operand" "=r,r")
248 (ior:AM (match_operand:AM 1 "register_operand" " 0,0")
249 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
251 "{or<msuffix>\t%0,%2|%w0 %|= %w2}"
252 [(set_attr "type" "<mtype>")])
254 ;;; Logical exclusive-OR
255 (define_insn "xor<AM:mode>3"
256 [(set (match_operand:AM 0 "register_operand" "=r,r")
257 (xor:AM (match_operand:AM 1 "register_operand" " 0,0")
258 (match_operand:AM 2 "reg_or_imm_operand" "r,I")))]
260 "{xor<msuffix>\t%0,%2|%w0 ^= %w2}"
261 [(set_attr "type" "<mtype>")])
267 ;; For register operands smaller than 32-bit zero-extending is
268 ;; achieved ANDing the value in the source register to a suitable
271 ;; For register operands bigger or equal than 32-bit, we generate a
272 ;; mov32 instruction to zero the high 32-bits of the destination
275 ;; For memory operands, of any width, zero-extending is achieved using
276 ;; the ldx{bhwdw} instructions to load the values in registers.
278 (define_insn "zero_extendhidi2"
279 [(set (match_operand:DI 0 "register_operand" "=r,r,r")
280 (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "0,r,q")))]
283 {and\t%0,0xffff|%0 &= 0xffff}
284 {mov\t%0,%1\;and\t%0,0xffff|%0 = %1;%0 &= 0xffff}
285 {ldxh\t%0,%1|%0 = *(u16 *) (%1)}"
286 [(set_attr "type" "alu,alu,ldx")])
288 (define_insn "zero_extendqidi2"
289 [(set (match_operand:DI 0 "register_operand" "=r,r,r")
290 (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "0,r,q")))]
293 {and\t%0,0xff|%0 &= 0xff}
294 {mov\t%0,%1\;and\t%0,0xff|%0 = %1;%0 &= 0xff}
295 {ldxh\t%0,%1|%0 = *(u8 *) (%1)}"
296 [(set_attr "type" "alu,alu,ldx")])
298 (define_insn "zero_extendsidi2"
299 [(set (match_operand:DI 0 "register_operand" "=r,r")
301 (match_operand:SI 1 "nonimmediate_operand" "r,q")))]
304 * return bpf_has_alu32 ? \"{mov32\t%0,%1|%0 = %1}\" : \"{mov\t%0,%1\;and\t%0,0xffffffff|%0 = %1;%0 &= 0xffffffff}\";
305 {ldxw\t%0,%1|%0 = *(u32 *) (%1)}"
306 [(set_attr "type" "alu,ldx")])
310 ;; Sign-extending a 32-bit value into a 64-bit value is achieved using
311 ;; shifting, with instructions generated by the expand below.
313 (define_expand "extendsidi2"
314 [(set (match_operand:DI 0 "register_operand")
315 (sign_extend:DI (match_operand:SI 1 "register_operand")))]
318 operands[1] = gen_lowpart (DImode, operands[1]);
319 emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (32)));
320 emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (32)));
324 ;; ISA V4 introduces sign-extending move and load operations.
326 (define_insn "*extendsidi2"
327 [(set (match_operand:DI 0 "register_operand" "=r,r")
328 (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,q")))]
331 {movs\t%0,%1,32|%0 = (s32) %1}
332 {ldxsw\t%0,%1|%0 = *(s32 *) (%1)}"
333 [(set_attr "type" "alu,ldx")])
335 (define_insn "extendhidi2"
336 [(set (match_operand:DI 0 "register_operand" "=r,r")
337 (sign_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,q")))]
340 {movs\t%0,%1,16|%0 = (s16) %1}
341 {ldxsh\t%0,%1|%0 = *(s16 *) (%1)}"
342 [(set_attr "type" "alu,ldx")])
344 (define_insn "extendqidi2"
345 [(set (match_operand:DI 0 "register_operand" "=r,r")
346 (sign_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,q")))]
349 {movs\t%0,%1,8|%0 = (s8) %1}
350 {ldxsb\t%0,%1|%0 = *(s8 *) (%1)}"
351 [(set_attr "type" "alu,ldx")])
353 (define_insn "extendhisi2"
354 [(set (match_operand:SI 0 "register_operand" "=r")
355 (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
357 "{movs32\t%0,%1,16|%w0 = (s16) %w1}"
358 [(set_attr "type" "alu")])
360 (define_insn "extendqisi2"
361 [(set (match_operand:SI 0 "register_operand" "=r")
362 (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
364 "{movs32\t%0,%1,8|%w0 = (s8) %w1}"
365 [(set_attr "type" "alu")])
369 (define_mode_iterator MM [QI HI SI DI SF DF])
371 (define_expand "mov<MM:mode>"
372 [(set (match_operand:MM 0 "general_operand")
373 (match_operand:MM 1 "general_operand"))]
377 if (!register_operand(operands[0], <MM:MODE>mode)
378 && !register_operand(operands[1], <MM:MODE>mode))
379 operands[1] = force_reg (<MM:MODE>mode, operands[1]);
382 (define_insn "*mov<MM:mode>"
383 [(set (match_operand:MM 0 "nonimmediate_operand" "=r, r,r,q,q")
384 (match_operand:MM 1 "mov_src_operand" " q,rI,B,r,I"))]
387 {ldx<mop>\t%0,%1|%0 = *(<smop> *) (%1)}
389 {lddw\t%0,%1|%0 = %1 ll}
390 {stx<mop>\t%0,%1|*(<smop> *) (%0) = %1}
391 {st<mop>\t%0,%1|*(<smop> *) (%0) = %1}"
392 [(set_attr "type" "ldx,alu,alu,stx,st")])
394 (define_insn "*mov_reloc_core<MM:mode>"
395 [(set (match_operand:MM 0 "nonimmediate_operand" "=r,q,r")
397 (match_operand:MM 1 "immediate_operand" " I,I,B")
398 (match_operand:SI 2 "immediate_operand" " I,I,I")
403 *return bpf_add_core_reloc (operands, \"{mov\t%0,%1|%0 = %1}\");
404 *return bpf_add_core_reloc (operands, \"{st<mop>\t%0,%1|*(<smop> *) (%0) = %1}\");
405 *return bpf_add_core_reloc (operands, \"{lddw\t%0,%1|%0 = %1 ll}\");"
406 [(set_attr "type" "alu,st,alu")])
410 (define_mode_iterator SIM [(SI "bpf_has_alu32") DI])
412 (define_insn "ashr<SIM:mode>3"
413 [(set (match_operand:SIM 0 "register_operand" "=r,r")
414 (ashiftrt:SIM (match_operand:SIM 1 "register_operand" " 0,0")
415 (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
417 "{arsh<msuffix>\t%0,%2|%w0 s>>= %w2}"
418 [(set_attr "type" "<mtype>")])
420 (define_insn "ashl<SIM:mode>3"
421 [(set (match_operand:SIM 0 "register_operand" "=r,r")
422 (ashift:SIM (match_operand:SIM 1 "register_operand" " 0,0")
423 (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
425 "{lsh<msuffix>\t%0,%2|%w0 <<= %w2}"
426 [(set_attr "type" "<mtype>")])
428 (define_insn "lshr<SIM:mode>3"
429 [(set (match_operand:SIM 0 "register_operand" "=r,r")
430 (lshiftrt:SIM (match_operand:SIM 1 "register_operand" " 0,0")
431 (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
433 "{rsh<msuffix>\t%0,%2|%w0 >>= %w2}"
434 [(set_attr "type" "<mtype>")])
438 (define_mode_iterator BSM [HI SI DI])
439 (define_mode_attr endmode [(HI "16") (SI "32") (DI "64")])
441 (define_insn "bswap<BSM:mode>2"
442 [(set (match_operand:BSM 0 "register_operand" "=r")
443 (bswap:BSM (match_operand:BSM 1 "register_operand" " 0")))]
447 return "{bswap\t%0, <endmode>|%0 = bswap<endmode> %1}";
450 if (TARGET_BIG_ENDIAN)
451 return "{endle\t%0, <endmode>|%0 = le<endmode> %1}";
453 return "{endbe\t%0, <endmode>|%0 = be<endmode> %1}";
456 [(set_attr "type" "end")])
458 ;;;; Conditional branches
460 ;; The eBPF jump instructions use 64-bit arithmetic when evaluating
461 ;; the jump conditions. Therefore we use DI modes below.
463 (define_mode_iterator JM [(SI "bpf_has_jmp32") DI])
465 (define_expand "cbranch<JM:mode>4"
467 (if_then_else (match_operator 0 "comparison_operator"
468 [(match_operand:JM 1 "register_operand")
469 (match_operand:JM 2 "reg_or_imm_operand")])
470 (label_ref (match_operand 3 "" ""))
474 if (!ordered_comparison_operator (operands[0], VOIDmode))
477 bpf_expand_cbranch (<JM:MODE>mode, operands);
480 (define_insn "*branch_on_<JM:mode>"
482 (if_then_else (match_operator 3 "ordered_comparison_operator"
483 [(match_operand:JM 0 "register_operand" "r")
484 (match_operand:JM 1 "reg_or_imm_operand" "rI")])
485 (label_ref (match_operand 2 "" ""))
489 int code = GET_CODE (operands[3]);
493 case EQ: return "{jeq<msuffix>\t%0,%1,%2|if %w0 == %w1 goto %2}"; break;
494 case NE: return "{jne<msuffix>\t%0,%1,%2|if %w0 != %w1 goto %2}"; break;
495 case LT: return "{jslt<msuffix>\t%0,%1,%2|if %w0 s< %w1 goto %2}"; break;
496 case LE: return "{jsle<msuffix>\t%0,%1,%2|if %w0 s<= %w1 goto %2}"; break;
497 case GT: return "{jsgt<msuffix>\t%0,%1,%2|if %w0 s> %w1 goto %2}"; break;
498 case GE: return "{jsge<msuffix>\t%0,%1,%2|if %w0 s>= %w1 goto %2}"; break;
499 case LTU: return "{jlt<msuffix>\t%0,%1,%2|if %w0 < %w1 goto %2}"; break;
500 case LEU: return "{jle<msuffix>\t%0,%1,%2|if %w0 <= %w1 goto %2}"; break;
501 case GTU: return "{jgt<msuffix>\t%0,%1,%2|if %w0 > %w1 goto %2}"; break;
502 case GEU: return "{jge<msuffix>\t%0,%1,%2|if %w0 >= %w1 goto %2}"; break;
508 [(set_attr "type" "jmp")])
510 ;;;; Unconditional branches
514 (label_ref (match_operand 0 "" "")))]
517 [(set_attr "type" "jmp")])
519 ;;;; Function prologue/epilogue
525 [(set_attr "type" "jmp")])
527 (define_expand "prologue"
531 bpf_expand_prologue ();
535 (define_expand "epilogue"
539 bpf_expand_epilogue ();
545 (define_expand "call"
546 [(parallel [(call (match_operand 0 "")
547 (match_operand 1 ""))
548 (use (match_operand 2 "")) ;; next_arg_reg
549 (use (match_operand 3 ""))])] ;; struct_value_size_rtx
552 rtx target = XEXP (operands[0], 0);
553 emit_call_insn (gen_call_internal (target, operands[1]));
557 (define_insn "call_internal"
558 [(call (mem:DI (match_operand:DI 0 "call_operand" "Sr"))
559 (match_operand:SI 1 "general_operand" ""))]
560 ;; operands[2] is next_arg_register
561 ;; operands[3] is struct_value_size_rtx.
563 { return bpf_output_call (operands[0]); }
564 [(set_attr "type" "jmp")])
566 (define_expand "call_value"
567 [(parallel [(set (match_operand 0 "")
568 (call (match_operand 1 "")
569 (match_operand 2 "")))
570 (use (match_operand 3 ""))])] ;; next_arg_reg
573 rtx target = XEXP (operands[1], 0);
574 emit_call_insn (gen_call_value_internal (operands[0], target,
579 (define_insn "call_value_internal"
580 [(set (match_operand 0 "register_operand" "")
581 (call (mem:DI (match_operand:DI 1 "call_operand" "Sr"))
582 (match_operand:SI 2 "general_operand" "")))]
583 ;; operands[3] is next_arg_register
584 ;; operands[4] is struct_value_size_rtx.
586 { return bpf_output_call (operands[1]); }
587 [(set_attr "type" "jmp")])
589 (define_insn "sibcall"
590 [(call (label_ref (match_operand 0 "" ""))
591 (match_operand:SI 1 "general_operand" ""))]
592 ;; operands[2] is next_arg_register
593 ;; operands[3] is struct_value_size_rtx.
596 [(set_attr "type" "jmp")])
598 ;;;; Non-generic load instructions
600 (define_mode_iterator LDM [QI HI SI DI])
601 (define_mode_attr ldop [(QI "b") (HI "h") (SI "w") (DI "dw")])
602 (define_mode_attr pldop [(QI "u8") (HI "u16") (SI "u32") (DI "u64")])
604 (define_insn "ldind<ldop>"
605 [(set (reg:LDM R0_REGNUM)
606 (unspec:LDM [(match_operand:DI 0 "register_operand" "r")
607 (match_operand:SI 1 "imm32_operand" "I")]
609 (clobber (reg:DI R1_REGNUM))
610 (clobber (reg:DI R2_REGNUM))
611 (clobber (reg:DI R3_REGNUM))
612 (clobber (reg:DI R4_REGNUM))]
614 "{ldind<ldop>\t%0,%1|r0 = *(<pldop> *) skb[%0 + %1]}"
615 [(set_attr "type" "ld")])
617 (define_insn "ldabs<ldop>"
618 [(set (reg:LDM R0_REGNUM)
619 (unspec:LDM [(match_operand:SI 0 "imm32_operand" "I")
620 (match_operand:SI 1 "imm32_operand" "I")]
622 (clobber (reg:DI R1_REGNUM))
623 (clobber (reg:DI R2_REGNUM))
624 (clobber (reg:DI R3_REGNUM))
625 (clobber (reg:DI R4_REGNUM))]
627 "{ldabs<ldop>\t%0|r0 = *(<pldop> *) skb[%0]}"
628 [(set_attr "type" "ld")])
630 (include "atomic.md")