xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/config/bpf/bpf.md (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1;; Machine description for eBPF.
2;; Copyright (C) 2019-2020 Free Software Foundation, Inc.
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;; 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
90(define_insn "nop"
91  [(const_int 0)]
92  ""
93  "ja\t0"
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
103;; instructions.
104
105(define_mode_iterator AM [SI DI])
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
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
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
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
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"
244  [(set (match_operand:DI 0 "register_operand" "=r,r")
245	(zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
246  ""
247  "@
248   and\t%0,0xffff
249   ldxh\t%0,%1"
250  [(set_attr "type" "alu,ldx")])
251
252(define_insn "zero_extendqidi2"
253  [(set (match_operand:DI 0 "register_operand" "=r,r")
254	(zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
255  ""
256  "@
257   and\t%0,0xff
258   ldxb\t%0,%1"
259  [(set_attr "type" "alu,ldx")])
260
261(define_insn "zero_extendsidi2"
262  [(set (match_operand:DI 0 "register_operand" "=r,r")
263	(zero_extend:DI
264	  (match_operand:SI 1 "nonimmediate_operand" "r,m")))]
265  ""
266  "@
267   mov32\t%0,%1
268   ldxw\t%0,%1"
269  [(set_attr "type" "alu,ldx")])
270
271;;; Sign-extension
272
273;; Sign-extending a 32-bit value into a 64-bit value is achieved using
274;; shifting, with instructions generated by the expand below.
275
276(define_expand "extendsidi2"
277  [(set (match_operand:DI 0 "register_operand")
278	(sign_extend:DI (match_operand:SI 1 "register_operand")))]
279  ""
280{
281  operands[1] = gen_lowpart (DImode, operands[1]);
282  emit_insn (gen_ashldi3 (operands[0], operands[1], GEN_INT (32)));
283  emit_insn (gen_ashrdi3 (operands[0], operands[0], GEN_INT (32)));
284  DONE;
285})
286
287;;;; Data movement
288
289(define_mode_iterator MM [QI HI SI DI SF DF])
290
291(define_expand "mov<MM:mode>"
292  [(set (match_operand:MM 0 "general_operand")
293        (match_operand:MM 1 "general_operand"))]
294        ""
295        "
296{
297  if (!register_operand(operands[0], <MM:MODE>mode)
298      && !register_operand(operands[1], <MM:MODE>mode))
299    operands[1] = force_reg (<MM:MODE>mode, operands[1]);
300}")
301
302(define_insn "*mov<MM:mode>"
303  [(set (match_operand:MM 0 "nonimmediate_operand" "=r, r,r,m,m")
304        (match_operand:MM 1 "mov_src_operand"      " m,rI,B,r,I"))]
305  ""
306  "@
307   ldx<mop>\t%0,%1
308   mov\t%0,%1
309   lddw\t%0,%1
310   stx<mop>\t%0,%1
311   st<mop>\t%0,%1"
312[(set_attr "type" "ldx,alu,alu,stx,st")])
313
314;;;; Shifts
315
316(define_mode_iterator SIM [SI DI])
317
318(define_insn "ashr<SIM:mode>3"
319  [(set (match_operand:SIM 0 "register_operand"                 "=r,r")
320        (ashiftrt:SIM (match_operand:SIM 1 "register_operand"   " 0,0")
321                      (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
322  ""
323  "arsh<msuffix>\t%0,%2"
324  [(set_attr "type" "<mtype>")])
325
326(define_insn "ashl<SIM:mode>3"
327  [(set (match_operand:SIM 0 "register_operand"               "=r,r")
328        (ashift:SIM (match_operand:SIM 1 "register_operand"   " 0,0")
329                    (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
330  ""
331  "lsh<msuffix>\t%0,%2"
332  [(set_attr "type" "<mtype>")])
333
334(define_insn "lshr<SIM:mode>3"
335  [(set (match_operand:SIM 0 "register_operand"                 "=r,r")
336        (lshiftrt:SIM (match_operand:SIM 1 "register_operand"   " 0,0")
337                      (match_operand:SIM 2 "reg_or_imm_operand" " r,I")))]
338  ""
339  "rsh<msuffix>\t%0,%2"
340  [(set_attr "type" "<mtype>")])
341
342;;;; Conditional branches
343
344;; The eBPF jump instructions use 64-bit arithmetic when evaluating
345;; the jump conditions.  Therefore we use DI modes below.
346
347(define_expand "cbranchdi4"
348  [(set (pc)
349	(if_then_else (match_operator 0 "comparison_operator"
350			[(match_operand:DI 1 "register_operand")
351			 (match_operand:DI 2 "reg_or_imm_operand")])
352		      (label_ref (match_operand 3 "" ""))
353		      (pc)))]
354  ""
355{
356  if (!ordered_comparison_operator (operands[0], VOIDmode))
357    FAIL;
358})
359
360(define_insn "*branch_on_di"
361  [(set (pc)
362	(if_then_else (match_operator 3 "ordered_comparison_operator"
363			 [(match_operand:DI 0 "register_operand" "r")
364			  (match_operand:DI 1 "reg_or_imm_operand" "rI")])
365		      (label_ref (match_operand 2 "" ""))
366		      (pc)))]
367  ""
368{
369  int code = GET_CODE (operands[3]);
370
371  switch (code)
372  {
373  case EQ: return "jeq\t%0,%1,%2"; break;
374  case NE: return "jne\t%0,%1,%2"; break;
375  case LT: return "jslt\t%0,%1,%2"; break;
376  case LE: return "jsle\t%0,%1,%2"; break;
377  case GT: return "jsgt\t%0,%1,%2"; break;
378  case GE: return "jsge\t%0,%1,%2"; break;
379  case LTU: return "jlt\t%0,%1,%2"; break;
380  case LEU: return "jle\t%0,%1,%2"; break;
381  case GTU: return "jgt\t%0,%1,%2"; break;
382  case GEU: return "jge\t%0,%1,%2"; break;
383  default:
384    gcc_unreachable ();
385    return "";
386  }
387}
388  [(set_attr "type" "jmp")])
389
390;;;; Unconditional branches
391
392(define_insn "jump"
393  [(set (pc)
394        (label_ref (match_operand 0 "" "")))]
395  ""
396  "ja\t%0"
397[(set_attr "type" "jmp")])
398
399;;;; Function prologue/epilogue
400
401(define_insn "exit"
402  [(simple_return)]
403  ""
404  "exit"
405  [(set_attr "type" "jmp")])
406
407(define_expand "prologue"
408  [(const_int 0)]
409  ""
410{
411  bpf_expand_prologue ();
412  DONE;
413})
414
415(define_expand "epilogue"
416  [(const_int 0)]
417  ""
418{
419  bpf_expand_epilogue ();
420  DONE;
421})
422
423;;;; Function calls
424
425(define_expand "call"
426  [(parallel [(call (match_operand 0 "")
427		    (match_operand 1 ""))
428	      (use (match_operand 2 ""))	;; next_arg_reg
429	      (use (match_operand 3 ""))])]	;; struct_value_size_rtx
430  ""
431{
432  rtx target = XEXP (operands[0], 0);
433  emit_call_insn (gen_call_internal (target, operands[1]));
434  DONE;
435})
436
437(define_insn "call_internal"
438  [(call (mem:DI (match_operand:DI 0 "call_operand" "Sr"))
439         (match_operand:SI 1 "general_operand" ""))]
440  ;; operands[2] is next_arg_register
441  ;; operands[3] is struct_value_size_rtx.
442  ""
443  { return bpf_output_call (operands[0]); }
444  [(set_attr "type" "jmp")])
445
446(define_expand "call_value"
447  [(parallel [(set (match_operand 0 "")
448		   (call (match_operand 1 "")
449			 (match_operand 2 "")))
450	      (use (match_operand 3 ""))])]		;; next_arg_reg
451  ""
452{
453  rtx target = XEXP (operands[1], 0);
454  emit_call_insn (gen_call_value_internal (operands[0], target,
455                                           operands[2]));
456  DONE;
457})
458
459(define_insn "call_value_internal"
460  [(set (match_operand 0 "register_operand" "")
461	(call (mem:DI (match_operand:DI 1 "call_operand" "Sr"))
462	      (match_operand:SI 2 "general_operand" "")))]
463  ;; operands[3] is next_arg_register
464  ;; operands[4] is struct_value_size_rtx.
465  ""
466  { return bpf_output_call (operands[1]); }
467  [(set_attr "type" "jmp")])
468
469(define_insn "sibcall"
470  [(call (label_ref (match_operand 0 "" ""))
471	 (match_operand:SI 1 "general_operand" ""))]
472  ;; operands[2] is next_arg_register
473  ;; operands[3] is struct_value_size_rtx.
474  ""
475  "ja\t%0"
476  [(set_attr "type" "jmp")])
477
478;;;; Non-generic load instructions
479
480(define_mode_iterator LDM [QI HI SI DI])
481(define_mode_attr ldop [(QI "b") (HI "h") (SI "w") (DI "dw")])
482
483(define_insn "ldind<ldop>"
484  [(set (reg:LDM R0_REGNUM)
485        (unspec:LDM [(match_operand:DI 0 "register_operand" "r")
486                    (match_operand:SI 1 "imm32_operand" "I")]
487                    UNSPEC_LDINDABS))
488   (clobber (reg:DI R1_REGNUM))
489   (clobber (reg:DI R2_REGNUM))
490   (clobber (reg:DI R3_REGNUM))
491   (clobber (reg:DI R4_REGNUM))]
492  ""
493  "ldind<ldop>\t%0,%1"
494  [(set_attr "type" "ld")])
495
496(define_insn "ldabs<ldop>"
497  [(set (reg:LDM R0_REGNUM)
498        (unspec:LDM [(match_operand:SI 0 "imm32_operand" "I")
499                    (match_operand:SI 1 "imm32_operand" "I")]
500                    UNSPEC_LDINDABS))
501   (clobber (reg:DI R1_REGNUM))
502   (clobber (reg:DI R2_REGNUM))
503   (clobber (reg:DI R3_REGNUM))
504   (clobber (reg:DI R4_REGNUM))]
505  ""
506  "ldabs<ldop>\t%0"
507  [(set_attr "type" "ld")])
508
509;;;; Atomic increments
510
511(define_mode_iterator AMO [SI DI])
512
513(define_insn "atomic_add<AMO:mode>"
514  [(set (match_operand:AMO 0 "memory_operand" "+m")
515        (unspec_volatile:AMO
516         [(plus:AMO (match_dup 0)
517                    (match_operand:AMO 1 "register_operand" "r"))
518          (match_operand:SI 2 "const_int_operand")] ;; Memory model.
519         UNSPEC_XADD))]
520  ""
521  "xadd<mop>\t%0,%1"
522  [(set_attr "type" "xadd")])
523