;; Machine description for eBPF. ;; Copyright (C) 2023-2024 Free Software Foundation, Inc. ;; This file is part of GCC. ;; GCC is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. ;; GCC is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GCC; see the file COPYING3. If not see ;; . (define_mode_iterator AMO [SI DI]) ;;; Plain atomic modify operations. ;; Non-fetching atomic add predates all other BPF atomic insns. ;; Use xadd{w,dw} for compatibility with older GAS without support ;; for v3 atomics. Newer GAS supports "aadd[32]" in line with the ;; other atomic operations. (define_insn "atomic_add" [(set (match_operand:AMO 0 "memory_operand" "+m") (unspec_volatile:AMO [(plus:AMO (match_dup 0) (match_operand:AMO 1 "register_operand" "r")) (match_operand:SI 2 "const_int_operand")] ;; Memory model. UNSPEC_AADD))] "" "{xadd\t%0,%1|lock *( *)(%w0) += %w1}" [(set_attr "type" "atomic")]) (define_insn "atomic_and" [(set (match_operand:AMO 0 "memory_operand" "+m") (unspec_volatile:AMO [(and:AMO (match_dup 0) (match_operand:AMO 1 "register_operand" "r")) (match_operand:SI 2 "const_int_operand")] ;; Memory model. UNSPEC_AAND))] "bpf_has_v3_atomics" "{aand\t%0,%1|lock *( *)(%w0) &= %w1}") (define_insn "atomic_or" [(set (match_operand:AMO 0 "memory_operand" "+m") (unspec_volatile:AMO [(ior:AMO (match_dup 0) (match_operand:AMO 1 "register_operand" "r")) (match_operand:SI 2 "const_int_operand")] ;; Memory model. UNSPEC_AOR))] "bpf_has_v3_atomics" "{aor\t%0,%1|lock *( *)(%w0) %|= %w1}") (define_insn "atomic_xor" [(set (match_operand:AMO 0 "memory_operand" "+m") (unspec_volatile:AMO [(xor:AMO (match_dup 0) (match_operand:AMO 1 "register_operand" "r")) (match_operand:SI 2 "const_int_operand")] ;; Memory model. UNSPEC_AXOR))] "bpf_has_v3_atomics" "{axor\t%0,%1|lock *( *)(%w0) ^= %w1}") ;;; Feching (read-modify-store) versions of atomic operations. (define_insn "atomic_fetch_add" [(set (match_operand:AMO 0 "register_operand" "=r") ; output (match_operand:AMO 1 "memory_operand" "+m")) (set (match_dup 1) (unspec_volatile:AMO [(plus:AMO (match_dup 1) (match_operand:AMO 2 "nonmemory_operand" "0")) ; second operand to op (match_operand:AMO 3 "const_int_operand")] ;; Memory model UNSPEC_AFADD))] "bpf_has_v3_atomics" "{afadd\t%1,%0|%w0 = atomic_fetch_add(( *)(%1), %w0)}") (define_insn "atomic_fetch_and" [(set (match_operand:AMO 0 "register_operand" "=r") (match_operand:AMO 1 "memory_operand" "+m")) (set (match_dup 1) (unspec_volatile:AMO [(and:AMO (match_dup 1) (match_operand:AMO 2 "nonmemory_operand" "0")) (match_operand:AMO 3 "const_int_operand")] UNSPEC_AFAND))] "bpf_has_v3_atomics" "{afand\t%1,%0|%w0 = atomic_fetch_and(( *)(%1), %w0)}") (define_insn "atomic_fetch_or" [(set (match_operand:AMO 0 "register_operand" "=r") (match_operand:AMO 1 "memory_operand" "+m")) (set (match_dup 1) (unspec_volatile:AMO [(ior:AMO (match_dup 1) (match_operand:AMO 2 "nonmemory_operand" "0")) (match_operand:AMO 3 "const_int_operand")] UNSPEC_AFOR))] "bpf_has_v3_atomics" "{afor\t%1,%0|%w0 = atomic_fetch_or(( *)(%1), %w0)}") (define_insn "atomic_fetch_xor" [(set (match_operand:AMO 0 "register_operand" "=r") (match_operand:AMO 1 "memory_operand" "+m")) (set (match_dup 1) (unspec_volatile:AMO [(xor:AMO (match_dup 1) (match_operand:AMO 2 "nonmemory_operand" "0")) (match_operand:AMO 3 "const_int_operand")] UNSPEC_AFXOR))] "bpf_has_v3_atomics" "{afxor\t%1,%0|%w0 = atomic_fetch_xor(( *)(%1), %w0)}") ;; Weird suffixes used in pseudo-c atomic compare-exchange insns. (define_mode_attr pcaxsuffix [(SI "32_32") (DI "_64")]) (define_insn "atomic_exchange" [(set (match_operand:AMO 0 "register_operand" "=r") (unspec_volatile:AMO [(match_operand:AMO 1 "memory_operand" "+m") (match_operand:AMO 3 "const_int_operand")] UNSPEC_AXCHG)) (set (match_dup 1) (match_operand:AMO 2 "nonmemory_operand" "0"))] "bpf_has_v3_atomics" "{axchg\t%1,%0|%w0 = xchg(%1, %w0)}") ;; The eBPF atomic-compare-and-exchange instruction has the form ;; acmp [%dst+offset], %src ;; The instruction atomically compares the value addressed by %dst+offset ;; with register R0. If they match, the value at %dst+offset is overwritten ;; with the value of %src. Otherwise, no write occurs. In either case, the ;; original value of %dst+offset is zero-extended and loaded back into R0. (define_expand "atomic_compare_and_swap" [(match_operand:SI 0 "register_operand" "=r") ;; bool success (match_operand:AMO 1 "register_operand" "=r") ;; old value (match_operand:AMO 2 "memory_operand" "+m") ;; memory (match_operand:AMO 3 "register_operand") ;; expected (match_operand:AMO 4 "register_operand") ;; desired (match_operand:SI 5 "const_int_operand") ;; is_weak (unused) (match_operand:SI 6 "const_int_operand") ;; success model (unused) (match_operand:SI 7 "const_int_operand")] ;; failure model (unused) "bpf_has_v3_atomics" { /* Load the expected value (into R0 by constraint of below). */ emit_move_insn (operands[1], operands[3]); /* Emit the acmp. */ emit_insn (gen_atomic_compare_and_swap_1 (operands[1], operands[2], operands[3], operands[4])); /* Assume that the operation was successful. */ emit_move_insn (operands[0], const1_rtx); rtx_code_label *success_label = gen_label_rtx (); /* Compare value that was in memory (now in R0/op[1]) to expected value. If they are equal, then the write occurred. Otherwise, indicate fail in output. */ emit_cmp_and_jump_insns (operands[1], operands[3], EQ, 0, GET_MODE (operands[1]), 1, success_label); emit_move_insn (operands[0], const0_rtx); if (success_label) { emit_label (success_label); LABEL_NUSES (success_label) = 1; } DONE; }) (define_insn "atomic_compare_and_swap_1" [(set (match_operand:AMO 0 "register_operand" "+t") ;; R0 is both input (expected value) (unspec_volatile:AMO ;; and output (original value) [(match_dup 0) ;; result depends on R0 (match_operand:AMO 1 "memory_operand") ;; memory (match_operand:AMO 2 "register_operand") ;; expected (match_operand:AMO 3 "register_operand")] ;; desired UNSPEC_ACMP))] "bpf_has_v3_atomics" "{acmp\t%1,%3|%w0 = cmpxchg(%1, %w0, %w3)}")