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(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")])
498