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