sync.md 7.5 KB

;; GCC machine description for Tilera TILE-Gx synchronization ;; instructions. ;; Copyright (C) 2011-2015 Free Software Foundation, Inc. ;; Contributed by Walter Lee (walt@tilera.com) ;; ;; 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_code_iterator fetchop [plus ior and]) (define_code_attr fetchop_name [(plus "add") (ior "or") (and "and")])

(define_insn "mtspr_cmpexch" [(set (reg:I48MODE TILEGX_CMPEXCH_REG)

    (unspec_volatile:I48MODE
     [(match_operand:I48MODE 0 "reg_or_0_operand" "rO")]
     UNSPEC_SPR_MOVE))]

"" "mtspr\tCMPEXCH_VALUE, %r0" [(set_attr "type" "X1")])

(define_expand "atomic_compare_and_swap" [(match_operand:DI 0 "register_operand" "") ;; bool output (match_operand:I48MODE 1 "register_operand" "") ;; val output (match_operand:I48MODE 2 "nonautoincmem_operand" "") ;; memory (match_operand:I48MODE 3 "reg_or_0_operand" "") ;; expected value (match_operand:I48MODE 4 "reg_or_0_operand" "") ;; desired value (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 "" { enum memmodel mod_s = (enum memmodel) INTVAL (operands[6]);

if (operands[3] != const0_rtx)

operands[3] = force_reg (<MODE>mode, operands[3]);

if (operands[4] != const0_rtx)

operands[4] = force_reg (<MODE>mode, operands[4]);

tilegx_pre_atomic_barrier (mod_s); emit_insn (gen_mtspr_cmpexch (operands[3])); emit_insn (gen_atomic_compare_and_swap_bare (operands[1], operands[2],

                                               operands[4]));

tilegx_post_atomic_barrier (mod_s); emit_insn (gen_insncmpeqdi (operands[0], operands[1], operands[3])); DONE; })

(define_insn "atomic_compare_and_swap_bare" [(set (match_operand:I48MODE 0 "register_operand" "=r")

    (match_operand:I48MODE 1 "nonautoincmem_operand" "+U"))

(set (match_dup 1)

    (unspec_volatile:I48MODE
     [(match_dup 1)
     (reg:I48MODE TILEGX_CMPEXCH_REG)
     (match_operand:I48MODE 2 "reg_or_0_operand" "rO")]
     UNSPEC_CMPXCHG))]

"" "cmpexch\t%0, %1, %r2" [(set_attr "type" "X1_remote")])

(define_expand "atomic_exchange" [(match_operand:I48MODE 0 "register_operand" "") ;; result (match_operand:I48MODE 1 "nonautoincmem_operand" "") ;; memory (match_operand:I48MODE 2 "reg_or_0_operand" "") ;; input (match_operand:SI 3 "const_int_operand" "")] ;; model "" { enum memmodel model = (enum memmodel) INTVAL (operands[3]);

tilegx_pre_atomic_barrier (model); emit_insn (gen_atomic_exchange_bare (operands[0], operands[1],

                                         operands[2]));

tilegx_post_atomic_barrier (model); DONE; })

(define_insn "atomic_exchange_bare" [(set (match_operand:I48MODE 0 "register_operand" "=r")

(match_operand:I48MODE 1 "nonautoincmem_operand" "+U"))

(set (match_dup 1)

(unspec_volatile:I48MODE
 [(match_operand:I48MODE 2 "reg_or_0_operand" "rO")]
 UNSPEC_XCHG))]

"" "exch\t%0, %1, %r2" [(set_attr "type" "X1_remote")])

(define_expand "atomicfetch" [(match_operand:I48MODE 0 "register_operand" "") ;; result (match_operand:I48MODE 1 "nonautoincmem_operand" "") ;; memory (unspec_volatile:I48MODE

[(fetchop:I48MODE
  (match_dup 1)
  (match_operand:I48MODE 2 "reg_or_0_operand" ""))] ;; value
UNSPEC_ATOMIC)

(match_operand:SI 3 "const_int_operand" "")] ;; model "" { enum memmodel model = (enum memmodel) INTVAL (operands[3]);

tilegx_pre_atomic_barrier (model); emit_insn (gen_atomicfetch_bare (operands[0],

                                                     operands[1],
                                                     operands[2]));

tilegx_post_atomic_barrier (model); DONE; })

(define_insn "atomicfetch_bare" [(set (match_operand:I48MODE 0 "register_operand" "=r")

(match_operand:I48MODE 1 "nonautoincmem_operand" "+U"))

(set (match_dup 1)

(unspec_volatile:I48MODE
 [(fetchop:I48MODE
   (match_dup 1)
   (match_operand:I48MODE 2 "reg_or_0_operand" "rO"))]
   UNSPEC_ATOMIC))]

"" "fetch\t%0, %1, %r2" [(set_attr "type" "X1_remote")])

(define_expand "atomic_fetch_sub" [(match_operand:I48MODE 0 "register_operand" "") ;; result (match_operand:I48MODE 1 "nonautoincmem_operand" "") ;; memory (unspec_volatile:I48MODE

[(minus:I48MODE
  (match_dup 1)
  (match_operand:I48MODE 2 "reg_or_0_operand" ""))] ;; value
UNSPEC_ATOMIC)

(match_operand:SI 3 "const_int_operand" "")] ;; model "" { rtx addend; enum memmodel model = (enum memmodel) INTVAL (operands[3]);

if (operands[2] != const0_rtx)

{
   addend = gen_reg_rtx (<MODE>mode);
   emit_move_insn (addend,
                   gen_rtx_MINUS (<MODE>mode, const0_rtx, operands[2]));
}

else

addend = operands[2];

tilegx_pre_atomic_barrier (model); emit_insn (gen_atomic_fetch_add_bare (operands[0],

                                          operands[1],
                                          addend));

tilegx_post_atomic_barrier (model); DONE; })

(define_expand "atomic_test_and_set" [(match_operand:QI 0 "register_operand" "") ;; bool output (match_operand:QI 1 "nonautoincmem_operand" "+U") ;; memory (match_operand:SI 2 "const_int_operand" "")] ;; model "" { rtx addr, aligned_addr, aligned_mem, offset, word, shmt, tmp; rtx result = operands[0]; rtx mem = operands[1]; enum memmodel model = (enum memmodel) INTVAL (operands[2]);

addr = force_reg (Pmode, XEXP (mem, 0));

aligned_addr = gen_reg_rtx (Pmode); emit_move_insn (aligned_addr, gen_rtx_AND (Pmode, addr, GEN_INT (-8)));

aligned_mem = change_address (mem, DImode, aligned_addr); set_mem_alias_set (aligned_mem, 0);

tmp = gen_reg_rtx (Pmode); if (BYTES_BIG_ENDIAN)

{
  emit_move_insn (gen_lowpart (DImode, tmp),
                  gen_rtx_NOT (DImode, gen_lowpart (DImode, addr)));
}

else

{
  tmp = addr;
}

offset = gen_reg_rtx (DImode); emit_move_insn (offset, gen_rtx_AND (DImode, gen_lowpart (DImode, tmp),

                                   GEN_INT (7)));

tmp = gen_reg_rtx (DImode); emit_move_insn (tmp, GEN_INT (1));

shmt = gen_reg_rtx (DImode); emit_move_insn (shmt, gen_rtx_ASHIFT (DImode, offset, GEN_INT (3)));

word = gen_reg_rtx (DImode); emit_move_insn (word, gen_rtx_ASHIFT (DImode, tmp,

                                    gen_lowpart (SImode, shmt)));

tmp = gen_reg_rtx (DImode); tilegx_pre_atomic_barrier (model); emit_insn (gen_atomic_fetch_or_baredi (tmp, aligned_mem, word)); tilegx_post_atomic_barrier (model);

emit_move_insn (gen_lowpart (DImode, result),

              gen_rtx_LSHIFTRT (DImode, tmp,
                                gen_lowpart (SImode, shmt)));

DONE; })