blob: e431f510372c53afae398a2724079dcf1fb39a5d [file] [log] [blame] [view]
;; Machine description for Xilinx MicroBlaze synchronization instructions.
;; Copyright (C) 2011-2025 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_insn "atomic_compare_and_swapsi"
[(set (match_operand:SI 0 "register_operand" "=&d") ;; bool output
(unspec_volatile:SI
[(match_operand:SI 2 "nonimmediate_operand" "+Q") ;; memory
(match_operand:SI 3 "register_operand" "d") ;; expected value
(match_operand:SI 4 "register_operand" "d")] ;; desired value
UNSPECV_CAS_BOOL))
(set (match_operand:SI 1 "register_operand" "=&d") ;; val output
(unspec_volatile:SI [(const_int 0)] UNSPECV_CAS_VAL))
(set (match_dup 2)
(unspec_volatile:SI [(const_int 0)] UNSPECV_CAS_MEM))
(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
(clobber (match_scratch:SI 8 "=&d"))]
""
{
return "add \t%0,r0,r0\n\t"
"lwx \t%1,%y2,r0\n\t"
"addic\t%8,r0,0\n\t"
"bnei \t%8,.-8\n\t"
"cmp \t%8,%1,%3\n\t"
"bnei \t%8,.+20\n\t"
"swx \t%4,%y2,r0\n\t"
"addic\t%8,r0,0\n\t"
"bnei \t%8,.-28\n\t"
"addi \t%0,r0,1";
}
[(set_attr "type" "atomic")
(set_attr "mode" "SI")
(set_attr "length" "40")]
)
;;
;;
;;
;;
(define_insn "atomic_fetch_<atomic_optab>si"
[(set (match_operand:SI 0 "register_operand" "=&d")
(match_operand:SI 1 "memory_operand" "+Q"))
(set (match_dup 1)
(unspec_volatile:SI
[(any_atomic:SI (match_dup 1)
(match_operand:SI 2 "register_operand" "d"))
(match_operand:SI 3 "const_int_operand")] ;; model
UNSPECV_ATOMIC_FETCH_OP))
(clobber (match_scratch:SI 4 "=&d"))] ;; tmp_1
""
{
return
"lwx \t%0,%y1,r0\n\t"
"addic\t%4,r0,0\n\t"
"bnei \t%4,.-8\n\t"
"<atomic_optab>\t%4,%0,%2\n\t"
"swx \t%4,%y1,r0\n\t"
"addic\t%4,r0,0\n\t"
"bnei \t%4,.-24";
}
[(set_attr "type" "atomic")
(set_attr "mode" "SI")
(set_attr "length" "28")])
;;
;; MicroBlaze only supports lx/sx instructions for word mode only
;;
;; Use shift|mask magic to implement atomic_test_and_set using lwx/swx
;;
(define_expand "atomic_test_and_set"
[(match_operand:QI 0 "register_operand" "") ;; bool output
(match_operand:QI 1 "memory_operand" "m") ;; memory
(match_operand:SI 2 "const_int_operand" "")] ;; model
""
{
rtx old = gen_reg_rtx (SImode);
rtx mem = operands[1];
rtx model = operands[2];
rtx set = gen_reg_rtx (SImode);
rtx aligned_mem = gen_reg_rtx (SImode);
rtx shift = gen_reg_rtx (SImode);
microblaze_subword_address (mem, &aligned_mem, &shift);
emit_move_insn (set, GEN_INT (1));
rtx shifted_set = gen_reg_rtx (SImode);
emit_move_insn (shifted_set, gen_rtx_ASHIFT (SImode, set, shift));
emit_insn (gen_atomic_fetch_orsi (old, aligned_mem, shifted_set, model));
emit_move_insn (old, gen_rtx_ASHIFTRT (SImode, old, shift));
emit_move_insn (operands[0], gen_lowpart (QImode, old));
DONE;
})