;; GCC machine description for ARC atomic instructions. ;; Copyright (C) 2015-2021 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 ;; http://www.gnu.org/licenses/.

(define_mode_iterator QHSI [QI HI SI]) (define_code_iterator atomicop [plus minus ior xor and]) (define_code_attr atomic_optab [(ior “or”) (xor “xor”) (and “and”) (plus “add”) (minus “sub”)])

(define_expand “memory_barrier” [(set (match_dup 0) (unspec:BLK [(match_dup 0)] UNSPEC_ARC_MEMBAR))] "" { operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); MEM_VOLATILE_P (operands[0]) = 1; })

;; A compiler-only memory barrier for ARC700. Generic code, when ;; checking for the existence of various named patterns, uses ;; asm("":::“memory”) when we don't need an actual instruction. For ;; ARCHS, we use a hardware data memory barrier that waits for ;; completion of current data memory operations before initiating ;; similar data memory operations. (define_insn “*memory_barrier” [(set (match_operand:BLK 0 "" "") (unspec:BLK [(match_dup 0)] UNSPEC_ARC_MEMBAR))] "" { if (TARGET_HS) { return “dmb\t3”; } else { return ""; } } [(set_attr “type” “multi”) (set_attr “length” “4”)])

(define_expand “atomic_compare_and_swap” [(match_operand:SI 0 “register_operand” "") ;; bool out (match_operand:QHSI 1 “register_operand” "") ;; val out (match_operand:QHSI 2 “mem_noofs_operand” "");; memory (match_operand:QHSI 3 “register_operand” "") ;; expected (match_operand:QHSI 4 “register_operand” "") ;; desired (match_operand:SI 5 “const_int_operand”) ;; is_weak (match_operand:SI 6 “const_int_operand”) ;; mod_s (match_operand:SI 7 “const_int_operand”)] ;; mod_f “TARGET_ATOMIC” { arc_expand_compare_and_swap (operands); DONE; })

(define_insn_and_split “atomic_compare_and_swapsi_1” [(set (reg:CC_Z CC_REG) ;; bool out (unspec_volatile:CC_Z [(const_int 0)] VUNSPEC_ARC_CAS)) (set (match_operand:SI 0 “register_operand” “=&r”) ;; val out (match_operand:SI 1 “mem_noofs_operand” “+ATO”)) ;; memory (set (match_dup 1) (unspec_volatile:SI [(match_operand:SI 2 “register_operand” “r”) ;; expect (match_operand:SI 3 “register_operand” “r”) ;; desired (match_operand:SI 4 “const_int_operand”) ;; is_weak (match_operand:SI 5 “const_int_operand”) ;; mod_s (match_operand:SI 6 “const_int_operand”)] ;; mod_f VUNSPEC_ARC_CAS))] “TARGET_ATOMIC” “#” “&& reload_completed” [(const_int 0)] { arc_split_compare_and_swap (operands); DONE; })

(define_insn “arc_load_exclusivesi” [(set (match_operand:SI 0 “register_operand” “=r”) (unspec_volatile:SI [(match_operand:SI 1 “mem_noofs_operand” “ATO”)] VUNSPEC_ARC_LL))] “TARGET_ATOMIC” “llock %0,%1” [(set_attr “type” “load”) (set_attr “iscompact” “false”) (set_attr “predicable” “no”) (set_attr “length” “*”)])

(define_insn “arc_store_exclusivesi” [(set (match_operand:SI 0 “mem_noofs_operand” “=ATO”) (unspec_volatile:SI[(match_operand:SI 1 “register_operand” “r”)] VUNSPEC_ARC_SC)) (clobber (reg:CC_Z CC_REG))] “TARGET_ATOMIC” “scond %1,%0” [(set_attr “type” “store”) (set_attr “iscompact” “false”) (set_attr “predicable” “no”) (set_attr “length” “*”)])

(define_expand “atomic_exchangesi” [(match_operand:SI 0 “register_operand” "") (match_operand:SI 1 “mem_noofs_operand” "") (match_operand:SI 2 “register_operand” "") (match_operand:SI 3 “const_int_operand” "")] “TARGET_ARC700 || TARGET_V2” { enum memmodel model = (enum memmodel) INTVAL (operands[3]);

if (model == MEMMODEL_SEQ_CST) emit_insn (gen_sync (const1_rtx)); emit_insn (gen_exchangesi (operands[0], operands[1], operands[2])); DONE; })

(define_insn “exchangesi” [(set (match_operand:SI 0 “register_operand” “=r”) (unspec_volatile:SI [(match_operand:SI 1 “mem_noofs_operand” “+ATO”)] VUNSPEC_ARC_EX)) (set (match_dup 1) (match_operand:SI 2 “register_operand” “0”))] "" “ex %0,%1” [(set_attr “type” “load”) (set_attr “iscompact” “false”) (set_attr “predicable” “no”) (set_attr “length” “*”)])

(define_expand “atomic_<atomic_optab>si” [(match_operand:SI 0 “mem_noofs_operand” "") ;; memory (atomicop:SI (match_dup 0) (match_operand:SI 1 “register_operand” "")) ;; operand (match_operand:SI 2 “const_int_operand” "")] ;; model “TARGET_ATOMIC” { arc_expand_atomic_op (, operands[0], operands[1], NULL_RTX, NULL_RTX, operands[2]); DONE; })

(define_expand “atomic_nandsi” [(match_operand:SI 0 “mem_noofs_operand” "") ;; memory (match_operand:SI 1 “register_operand” "") ;; operand (match_operand:SI 2 “const_int_operand” "")] ;; model “TARGET_ATOMIC” { arc_expand_atomic_op (NOT, operands[0], operands[1], NULL_RTX, NULL_RTX, operands[2]); DONE; })

(define_expand “atomic_fetch_<atomic_optab>si” [(match_operand:SI 0 “register_operand” "") ;; output (match_operand:SI 1 “mem_noofs_operand” "") ;; memory (atomicop:SI (match_dup 1) (match_operand:SI 2 “register_operand” "")) ;; operand (match_operand:SI 3 “const_int_operand” "")] ;; model “TARGET_ATOMIC” { arc_expand_atomic_op (, operands[1], operands[2], operands[0], NULL_RTX, operands[3]); DONE; })

(define_expand “atomic_fetch_nandsi” [(match_operand:SI 0 “register_operand” "") ;; output (match_operand:SI 1 “mem_noofs_operand” "") ;; memory (match_operand:SI 2 “register_operand” "") ;; operand (match_operand:SI 3 “const_int_operand” "")] ;; model “TARGET_ATOMIC” { arc_expand_atomic_op (NOT, operands[1], operands[2], operands[0], NULL_RTX, operands[3]); DONE; })

(define_expand “atomic_<atomic_optab>_fetchsi” [(match_operand:SI 0 “register_operand” "") ;; output (match_operand:SI 1 “mem_noofs_operand” "") ;; memory (atomicop:SI (match_dup 1) (match_operand:SI 2 “register_operand” "")) ;; operand (match_operand:SI 3 “const_int_operand” "")] ;; model “TARGET_ATOMIC” { arc_expand_atomic_op (, operands[1], operands[2], NULL_RTX, operands[0], operands[3]); DONE; })

(define_expand “atomic_nand_fetchsi” [(match_operand:SI 0 “register_operand” "") ;; output (match_operand:SI 1 “mem_noofs_operand” "") ;; memory (match_operand:SI 2 “register_operand” "") ;; operand (match_operand:SI 3 “const_int_operand” "")] ;; model “TARGET_ATOMIC” { arc_expand_atomic_op (NOT, operands[1], operands[2], NULL_RTX, operands[0], operands[3]); DONE; })