| ;; 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; |
| }) |