145
|
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")])
|