;; GCC machine description for ARC atomic instructions.
;; Copyright (C) 2015-2020 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<mode>"
[(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 (<CODE>, 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 (<CODE>, 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 (<CODE>, 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;
})