Ping. This patch is stalling for two weeks. Thanks, Claudiu
On Mon, Nov 16, 2015 at 11:18 AM, Claudiu Zissulescu <claudiu.zissule...@synopsys.com> wrote: > This patch adds support for atomic memory built-in for ARCHS and ARC700. > Tested with dg.exp. > > OK to apply? > > Thanks, > Claudiu > > ChangeLogs: > gcc/ > > 2015-11-12 Claudiu Zissulescu <claz...@synopsys.com> > > * config/arc/arc-protos.h (arc_expand_atomic_op): Prototype. > (arc_split_compare_and_swap): Likewise. > (arc_expand_compare_and_swap): Likewise. > * config/arc/arc.c (arc_init): Check usage atomic option. > (arc_pre_atomic_barrier): New function. > (arc_post_atomic_barrier): Likewise. > (emit_unlikely_jump): Likewise. > (arc_expand_compare_and_swap_qh): Likewise. > (arc_expand_compare_and_swap): Likewise. > (arc_split_compare_and_swap): Likewise. > (arc_expand_atomic_op): Likewise. > * config/arc/arc.h (TARGET_CPU_CPP_BUILTINS): New C macro. > (ASM_SPEC): Enable mlock option when matomic is used. > * config/arc/arc.md (UNSPEC_ARC_MEMBAR): Define. > (VUNSPEC_ARC_CAS): Likewise. > (VUNSPEC_ARC_LL): Likewise. > (VUNSPEC_ARC_SC): Likewise. > (VUNSPEC_ARC_EX): Likewise. > * config/arc/arc.opt (matomic): New option. > * config/arc/constraints.md (ATO): New constraint. > * config/arc/predicates.md (mem_noofs_operand): New predicate. > * doc/invoke.texi: Document -matomic. > * config/arc/atomic.md: New file. > > gcc/testsuite > > 2015-11-12 Claudiu Zissulescu <claz...@synopsys.com> > > * lib/target-supports.exp (check_effective_target_arc_atomic): New > function. > (check_effective_target_sync_int_long): Add checks for ARC atomic > feature. > (check_effective_target_sync_char_short): Likewise. > --- > gcc/config/arc/arc-protos.h | 4 + > gcc/config/arc/arc.c | 391 > ++++++++++++++++++++++++++++++++++ > gcc/config/arc/arc.h | 6 +- > gcc/config/arc/arc.md | 9 + > gcc/config/arc/arc.opt | 3 + > gcc/config/arc/atomic.md | 235 ++++++++++++++++++++ > gcc/config/arc/constraints.md | 6 + > gcc/config/arc/predicates.md | 4 + > gcc/doc/invoke.texi | 8 +- > gcc/testsuite/lib/target-supports.exp | 11 + > 10 files changed, 675 insertions(+), 2 deletions(-) > create mode 100644 gcc/config/arc/atomic.md > > diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h > index 6e04351..3581bb0 100644 > --- a/gcc/config/arc/arc-protos.h > +++ b/gcc/config/arc/arc-protos.h > @@ -41,6 +41,10 @@ extern int arc_output_commutative_cond_exec (rtx > *operands, bool); > extern bool arc_expand_movmem (rtx *operands); > extern bool prepare_move_operands (rtx *operands, machine_mode mode); > extern void emit_shift (enum rtx_code, rtx, rtx, rtx); > +extern void arc_expand_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx); > +extern void arc_split_compare_and_swap (rtx *); > +extern void arc_expand_compare_and_swap (rtx *); > + > #endif /* RTX_CODE */ > > #ifdef TREE_CODE > diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c > index 8bb0969..d47bbe4 100644 > --- a/gcc/config/arc/arc.c > +++ b/gcc/config/arc/arc.c > @@ -61,6 +61,7 @@ along with GCC; see the file COPYING3. If not see > #include "context.h" > #include "builtins.h" > #include "rtl-iter.h" > +#include "alias.h" > > /* Which cpu we're compiling for (ARC600, ARC601, ARC700). */ > static const char *arc_cpu_string = ""; > @@ -884,6 +885,9 @@ arc_init (void) > flag_pic = 0; > } > > + if (TARGET_ATOMIC && !(TARGET_ARC700 || TARGET_HS)) > + error ("-matomic is only supported for ARC700 or ARC HS cores"); > + > arc_init_reg_tables (); > > /* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */ > @@ -9650,6 +9654,393 @@ arc_use_by_pieces_infrastructure_p (unsigned > HOST_WIDE_INT size, > return default_use_by_pieces_infrastructure_p (size, align, op, speed_p); > } > > +/* Emit a (pre) memory barrier around an atomic sequence according to > + MODEL. */ > + > +static void > +arc_pre_atomic_barrier (enum memmodel model) > +{ > + switch (model & MEMMODEL_MASK) > + { > + case MEMMODEL_RELAXED: > + case MEMMODEL_CONSUME: > + case MEMMODEL_ACQUIRE: > + case MEMMODEL_SYNC_ACQUIRE: > + break; > + case MEMMODEL_RELEASE: > + case MEMMODEL_ACQ_REL: > + case MEMMODEL_SYNC_RELEASE: > + emit_insn (gen_membar (const0_rtx)); > + break; > + case MEMMODEL_SEQ_CST: > + case MEMMODEL_SYNC_SEQ_CST: > + emit_insn (gen_sync (const1_rtx)); > + break; > + default: > + gcc_unreachable (); > + } > +} > + > +/* Emit a (post) memory barrier around an atomic sequence according to > + MODEL. */ > + > +static void > +arc_post_atomic_barrier (enum memmodel model) > +{ > + switch (model & MEMMODEL_MASK) > + { > + case MEMMODEL_RELAXED: > + case MEMMODEL_CONSUME: > + case MEMMODEL_RELEASE: > + case MEMMODEL_SYNC_RELEASE: > + break; > + case MEMMODEL_ACQUIRE: > + case MEMMODEL_ACQ_REL: > + case MEMMODEL_SYNC_ACQUIRE: > + emit_insn (gen_membar (const0_rtx)); > + break; > + case MEMMODEL_SEQ_CST: > + case MEMMODEL_SYNC_SEQ_CST: > + emit_insn (gen_sync (const1_rtx)); > + break; > + default: > + gcc_unreachable (); > + } > +} > + > +/* Expand a compare and swap pattern. */ > + > +static void > +emit_unlikely_jump (rtx insn) > +{ > + int very_unlikely = REG_BR_PROB_BASE / 100 - 1; > + > + insn = emit_jump_insn (insn); > + add_int_reg_note (insn, REG_BR_PROB, very_unlikely); > +} > + > +/* Expand code to perform a 8 or 16-bit compare and swap by doing > + 32-bit compare and swap on the word containing the byte or > + half-word. The difference between a weak and a strong CAS is that > + the weak version may simply fail. The strong version relays on two > + loops, one checks if the SCOND op is succsfully or not, the other > + checks if the 32 bit accessed location which contains the 8 or 16 > + bit datum is not changed by other thread. The first loop is > + implemented by the atomic_compare_and_swapsi_1 pattern. The second > + loops is implemented by this routine. */ > + > +static void > +arc_expand_compare_and_swap_qh (rtx bool_result, rtx result, rtx mem, > + rtx oldval, rtx newval, rtx weak, > + rtx mod_s, rtx mod_f) > +{ > + rtx addr1 = force_reg (Pmode, XEXP (mem, 0)); > + rtx addr = gen_reg_rtx (Pmode); > + rtx off = gen_reg_rtx (SImode); > + rtx oldv = gen_reg_rtx (SImode); > + rtx newv = gen_reg_rtx (SImode); > + rtx oldvalue = gen_reg_rtx (SImode); > + rtx newvalue = gen_reg_rtx (SImode); > + rtx res = gen_reg_rtx (SImode); > + rtx resv = gen_reg_rtx (SImode); > + rtx memsi, val, mask, end_label, loop_label, cc, x; > + machine_mode mode; > + bool is_weak = (weak != const0_rtx); > + > + /* Truncate the address. */ > + emit_insn (gen_rtx_SET (addr, > + gen_rtx_AND (Pmode, addr1, GEN_INT (-4)))); > + > + /* Compute the datum offset. */ > + emit_insn (gen_rtx_SET (off, > + gen_rtx_AND (SImode, addr1, GEN_INT (3)))); > + if (TARGET_BIG_ENDIAN) > + emit_insn (gen_rtx_SET (off, > + gen_rtx_MINUS (SImode, > + (GET_MODE (mem) == QImode) ? > + GEN_INT (3) : GEN_INT (2), off))); > + > + /* Normal read from truncated address. */ > + memsi = gen_rtx_MEM (SImode, addr); > + set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER); > + MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem); > + > + val = copy_to_reg (memsi); > + > + /* Convert the offset in bits. */ > + emit_insn (gen_rtx_SET (off, > + gen_rtx_ASHIFT (SImode, off, GEN_INT (3)))); > + > + /* Get the proper mask. */ > + if (GET_MODE (mem) == QImode) > + mask = force_reg (SImode, GEN_INT (0xff)); > + else > + mask = force_reg (SImode, GEN_INT (0xffff)); > + > + emit_insn (gen_rtx_SET (mask, > + gen_rtx_ASHIFT (SImode, mask, off))); > + > + /* Prepare the old and new values. */ > + emit_insn (gen_rtx_SET (val, > + gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask), > + val))); > + > + oldval = gen_lowpart (SImode, oldval); > + emit_insn (gen_rtx_SET (oldv, > + gen_rtx_ASHIFT (SImode, oldval, off))); > + > + newval = gen_lowpart_common (SImode, newval); > + emit_insn (gen_rtx_SET (newv, > + gen_rtx_ASHIFT (SImode, newval, off))); > + > + emit_insn (gen_rtx_SET (oldv, > + gen_rtx_AND (SImode, oldv, mask))); > + > + emit_insn (gen_rtx_SET (newv, > + gen_rtx_AND (SImode, newv, mask))); > + > + if (!is_weak) > + { > + end_label = gen_label_rtx (); > + loop_label = gen_label_rtx (); > + emit_label (loop_label); > + } > + > + /* Make the old and new values. */ > + emit_insn (gen_rtx_SET (oldvalue, > + gen_rtx_IOR (SImode, oldv, val))); > + > + emit_insn (gen_rtx_SET (newvalue, > + gen_rtx_IOR (SImode, newv, val))); > + > + /* Try an 32bit atomic compare and swap. It clobbers the CC > + register. */ > + emit_insn (gen_atomic_compare_and_swapsi_1 (res, memsi, oldvalue, newvalue, > + weak, mod_s, mod_f)); > + > + /* Regardless of the weakness of the operation, a proper boolean > + result needs to be provided. */ > + x = gen_rtx_REG (CC_Zmode, CC_REG); > + x = gen_rtx_EQ (SImode, x, const0_rtx); > + emit_insn (gen_rtx_SET (bool_result, x)); > + > + if (!is_weak) > + { > + /* Check the results: if the atomic op is successfully the goto > + to end label. */ > + x = gen_rtx_REG (CC_Zmode, CC_REG); > + x = gen_rtx_EQ (VOIDmode, x, const0_rtx); > + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, > + gen_rtx_LABEL_REF (Pmode, end_label), pc_rtx); > + emit_jump_insn (gen_rtx_SET (pc_rtx, x)); > + > + /* Wait for the right moment when the accessed 32-bit location > + is stable. */ > + emit_insn (gen_rtx_SET (resv, > + gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask), > + res))); > + mode = SELECT_CC_MODE (NE, resv, val); > + cc = gen_rtx_REG (mode, CC_REG); > + emit_insn (gen_rtx_SET (cc, gen_rtx_COMPARE (mode, resv, val))); > + > + /* Set the new value of the 32 bit location, proper masked. */ > + emit_insn (gen_rtx_SET (val, resv)); > + > + /* Try again if location is unstable. Fall through if only > + scond op failed. */ > + x = gen_rtx_NE (VOIDmode, cc, const0_rtx); > + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, > + gen_rtx_LABEL_REF (Pmode, loop_label), > pc_rtx); > + emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); > + > + emit_label (end_label); > + } > + > + /* End: proper return the result for the given mode. */ > + emit_insn (gen_rtx_SET (res, > + gen_rtx_AND (SImode, res, mask))); > + > + emit_insn (gen_rtx_SET (res, > + gen_rtx_LSHIFTRT (SImode, res, off))); > + > + emit_move_insn (result, gen_lowpart (GET_MODE (result), res)); > +} > + > +/* Helper function used by "atomic_compare_and_swap" expand > + pattern. */ > + > +void > +arc_expand_compare_and_swap (rtx operands[]) > +{ > + rtx bval, rval, mem, oldval, newval, is_weak, mod_s, mod_f, x; > + machine_mode mode; > + > + bval = operands[0]; > + rval = operands[1]; > + mem = operands[2]; > + oldval = operands[3]; > + newval = operands[4]; > + is_weak = operands[5]; > + mod_s = operands[6]; > + mod_f = operands[7]; > + mode = GET_MODE (mem); > + > + if (reg_overlap_mentioned_p (rval, oldval)) > + oldval = copy_to_reg (oldval); > + > + if (mode == SImode) > + { > + emit_insn (gen_atomic_compare_and_swapsi_1 (rval, mem, oldval, newval, > + is_weak, mod_s, mod_f)); > + x = gen_rtx_REG (CC_Zmode, CC_REG); > + x = gen_rtx_EQ (SImode, x, const0_rtx); > + emit_insn (gen_rtx_SET (bval, x)); > + } > + else > + { > + arc_expand_compare_and_swap_qh (bval, rval, mem, oldval, newval, > + is_weak, mod_s, mod_f); > + } > +} > + > +/* Helper function used by the "atomic_compare_and_swapsi_1" > + pattern. */ > + > +void > +arc_split_compare_and_swap (rtx operands[]) > +{ > + rtx rval, mem, oldval, newval; > + machine_mode mode; > + enum memmodel mod_s, mod_f; > + bool is_weak; > + rtx label1, label2, x, cond; > + > + rval = operands[0]; > + mem = operands[1]; > + oldval = operands[2]; > + newval = operands[3]; > + is_weak = (operands[4] != const0_rtx); > + mod_s = (enum memmodel) INTVAL (operands[5]); > + mod_f = (enum memmodel) INTVAL (operands[6]); > + mode = GET_MODE (mem); > + > + /* ARC atomic ops work only with 32-bit aligned memories. */ > + gcc_assert (mode == SImode); > + > + arc_pre_atomic_barrier (mod_s); > + > + label1 = NULL_RTX; > + if (!is_weak) > + { > + label1 = gen_label_rtx (); > + emit_label (label1); > + } > + label2 = gen_label_rtx (); > + > + /* Load exclusive. */ > + emit_insn (gen_arc_load_exclusivesi (rval, mem)); > + > + /* Check if it is oldval. */ > + mode = SELECT_CC_MODE (NE, rval, oldval); > + cond = gen_rtx_REG (mode, CC_REG); > + emit_insn (gen_rtx_SET (cond, gen_rtx_COMPARE (mode, rval, oldval))); > + > + x = gen_rtx_NE (VOIDmode, cond, const0_rtx); > + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, > + gen_rtx_LABEL_REF (Pmode, label2), pc_rtx); > + emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); > + > + /* Exclusively store new item. Store clobbers CC reg. */ > + emit_insn (gen_arc_store_exclusivesi (mem, newval)); > + > + if (!is_weak) > + { > + /* Check the result of the store. */ > + cond = gen_rtx_REG (CC_Zmode, CC_REG); > + x = gen_rtx_NE (VOIDmode, cond, const0_rtx); > + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, > + gen_rtx_LABEL_REF (Pmode, label1), pc_rtx); > + emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); > + } > + > + if (mod_f != MEMMODEL_RELAXED) > + emit_label (label2); > + > + arc_post_atomic_barrier (mod_s); > + > + if (mod_f == MEMMODEL_RELAXED) > + emit_label (label2); > +} > + > +/* Expand an atomic fetch-and-operate pattern. CODE is the binary operation > + to perform. MEM is the memory on which to operate. VAL is the second > + operand of the binary operator. BEFORE and AFTER are optional locations > to > + return the value of MEM either before of after the operation. MODEL_RTX > + is a CONST_INT containing the memory model to use. */ > + > +void > +arc_expand_atomic_op (enum rtx_code code, rtx mem, rtx val, > + rtx orig_before, rtx orig_after, rtx model_rtx) > +{ > + enum memmodel model = (enum memmodel) INTVAL (model_rtx); > + machine_mode mode = GET_MODE (mem); > + rtx label, x, cond; > + rtx before = orig_before, after = orig_after; > + > + /* ARC atomic ops work only with 32-bit aligned memories. */ > + gcc_assert (mode == SImode); > + > + arc_pre_atomic_barrier (model); > + > + label = gen_label_rtx (); > + emit_label (label); > + label = gen_rtx_LABEL_REF (VOIDmode, label); > + > + if (before == NULL_RTX) > + before = gen_reg_rtx (mode); > + > + if (after == NULL_RTX) > + after = gen_reg_rtx (mode); > + > + /* Load exclusive. */ > + emit_insn (gen_arc_load_exclusivesi (before, mem)); > + > + switch (code) > + { > + case NOT: > + x = gen_rtx_AND (mode, before, val); > + emit_insn (gen_rtx_SET (after, x)); > + x = gen_rtx_NOT (mode, after); > + emit_insn (gen_rtx_SET (after, x)); > + break; > + > + case MINUS: > + if (CONST_INT_P (val)) > + { > + val = GEN_INT (-INTVAL (val)); > + code = PLUS; > + } > + > + /* FALLTHRU. */ > + default: > + x = gen_rtx_fmt_ee (code, mode, before, val); > + emit_insn (gen_rtx_SET (after, x)); > + break; > + } > + > + /* Exclusively store new item. Store clobbers CC reg. */ > + emit_insn (gen_arc_store_exclusivesi (mem, after)); > + > + /* Check the result of the store. */ > + cond = gen_rtx_REG (CC_Zmode, CC_REG); > + x = gen_rtx_NE (VOIDmode, cond, const0_rtx); > + x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, > + label, pc_rtx); > + emit_unlikely_jump (gen_rtx_SET (pc_rtx, x)); > + > + arc_post_atomic_barrier (model); > +} > + > struct gcc_target targetm = TARGET_INITIALIZER; > > #include "gt-arc.h" > diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h > index d312f9f..c895725 100644 > --- a/gcc/config/arc/arc.h > +++ b/gcc/config/arc/arc.h > @@ -88,6 +88,10 @@ along with GCC; see the file COPYING3. If not see > { \ > builtin_define ("__HS__"); \ > } \ > + if (TARGET_ATOMIC) \ > + { \ > + builtin_define ("__ARC_ATOMIC__"); \ > + } \ > if (TARGET_NORM) \ > { \ > builtin_define ("__ARC_NORM__");\ > @@ -153,7 +157,7 @@ along with GCC; see the file COPYING3. If not see > %{mcpu=ARC700|!mcpu=*:%{mrtsc}} \ > %{mcpu=ARCHS:-mHS} \ > %{mcpu=ARCEM:-mEM} \ > -" > +%{matomic:-mlock}" > > #if DEFAULT_LIBC == LIBC_UCLIBC > /* Note that the default is to link against dynamic libraries, if they are > diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md > index 1d070a3..ac181a9 100644 > --- a/gcc/config/arc/arc.md > +++ b/gcc/config/arc/arc.md > @@ -128,6 +128,12 @@ > (VUNSPEC_UNIMP_S 28) ; blockage insn for unimp_s generation > (VUNSPEC_NOP 29) ; volatile NOP > > + (UNSPEC_ARC_MEMBAR 30) > + (VUNSPEC_ARC_CAS 31) > + (VUNSPEC_ARC_LL 32) > + (VUNSPEC_ARC_SC 33) > + (VUNSPEC_ARC_EX 34) > + > (R0_REG 0) > (R1_REG 1) > (R2_REG 2) > @@ -5531,3 +5537,6 @@ > (include "fpx.md") > > (include "simdext.md") > + > +;; include atomic extensions > +(include "atomic.md") > diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt > index 0c10c67..c4d7306 100644 > --- a/gcc/config/arc/arc.opt > +++ b/gcc/config/arc/arc.opt > @@ -414,3 +414,6 @@ Target Joined > mmac_ > Target Joined > > +matomic > +Target Report Mask(ATOMIC) > +Enable atomic instructions. > diff --git a/gcc/config/arc/atomic.md b/gcc/config/arc/atomic.md > new file mode 100644 > index 0000000..13bcb76 > --- /dev/null > +++ b/gcc/config/arc/atomic.md > @@ -0,0 +1,235 @@ > +;; GCC machine description for ARC atomic instructions. > +;; Copyright (C) 2015 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 "mem_thread_fence" > + [(match_operand:SI 0 "const_int_operand")] > + "" > +{ > + enum memmodel model = (enum memmodel) INTVAL (operands[0]); > + switch (model) > + { > + case MEMMODEL_RELAXED: > + break; > + case MEMMODEL_CONSUME: > + case MEMMODEL_ACQUIRE: > + case MEMMODEL_RELEASE: > + case MEMMODEL_ACQ_REL: > + case MEMMODEL_SYNC_ACQUIRE: > + case MEMMODEL_SYNC_RELEASE: > + emit_insn (gen_membar (const0_rtx)); > + break; > + case MEMMODEL_SEQ_CST: > + case MEMMODEL_SYNC_SEQ_CST: > + emit_insn (gen_sync (const1_rtx)); > + break; > + default: > + gcc_unreachable (); > + } > + DONE; > +}) > + > +(define_expand "membar" > + [(set (match_dup 1) > + (unspec:BLK [(match_dup 1) (match_operand:SI 0 "const_int_operand")] > + UNSPEC_ARC_MEMBAR))] > + "" > +{ > + operands[1] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (Pmode)); > + MEM_VOLATILE_P (operands[1]) = 1; > +}) > + > +;; A compiler-only memory barrier. Generic code, when checking for the > +;; existence of various named patterns, uses asm("":::"memory") when we > +;; don't need an actual instruction. > +(define_insn "*membar_empty" > + [(set (match_operand:BLK 0 "" "") > + (unspec:BLK [(match_dup 0) (const_int 0)] > + UNSPEC_ARC_MEMBAR))] > + "" > + "" > + [(set_attr "type" "multi") > + (set_attr "length" "0")]) > + > +(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_ATOMIC" > +{ > + 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; > +}) > + > diff --git a/gcc/config/arc/constraints.md b/gcc/config/arc/constraints.md > index 65ea44a..18309cc 100644 > --- a/gcc/config/arc/constraints.md > +++ b/gcc/config/arc/constraints.md > @@ -421,3 +421,9 @@ > An unsigned 6-bit integer constant, up to 62." > (and (match_code "const_int") > (match_test "UNSIGNED_INT6 (ival - 1)"))) > + > +;; Memory constraint used for atomic ops. > +(define_memory_constraint "ATO" > + "A memory with only a base register" > + (match_operand 0 "mem_noofs_operand")) > + > diff --git a/gcc/config/arc/predicates.md b/gcc/config/arc/predicates.md > index 43f9474..de0735a 100644 > --- a/gcc/config/arc/predicates.md > +++ b/gcc/config/arc/predicates.md > @@ -813,3 +813,7 @@ > (define_predicate "short_const_int_operand" > (and (match_operand 0 "const_int_operand") > (match_test "satisfies_constraint_C16 (op)"))) > + > +(define_predicate "mem_noofs_operand" > + (and (match_code "mem") > + (match_code "reg" "0"))) > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > index fb908b3..c0a99d7 100644 > --- a/gcc/doc/invoke.texi > +++ b/gcc/doc/invoke.texi > @@ -538,7 +538,7 @@ Objective-C and Objective-C++ Dialects}. > @gccoptlist{-mbarrel-shifter @gol > -mcpu=@var{cpu} -mA6 -mARC600 -mA7 -mARC700 @gol > -mdpfp -mdpfp-compact -mdpfp-fast -mno-dpfp-lrsr @gol > --mea -mno-mpy -mmul32x16 -mmul64 @gol > +-mea -mno-mpy -mmul32x16 -mmul64 -matomic @gol > -mnorm -mspfp -mspfp-compact -mspfp-fast -msimd -msoft-float -mswap @gol > -mcrc -mdsp-packa -mdvbf -mlock -mmac-d16 -mmac-24 -mrtsc -mswape @gol > -mtelephony -mxy -misize -mannotate-align -marclinux -marclinux_prof @gol > @@ -12948,6 +12948,12 @@ can overridden by FPX options; @samp{mspfp}, > @samp{mspfp-compact}, or > @opindex mswap > Generate swap instructions. > > +@item -matomic > +@opindex matomic > +This enables Locked Load/Store Conditional extension to implement > +atomic memopry built-in functions. Not available for ARC 6xx or ARC > +EM cores. > + > @item -mdiv-rem > @opindex mdiv-rem > Enable DIV/REM instructions for ARCv2 cores. > diff --git a/gcc/testsuite/lib/target-supports.exp > b/gcc/testsuite/lib/target-supports.exp > index 75d5068..cc847ee 100644 > --- a/gcc/testsuite/lib/target-supports.exp > +++ b/gcc/testsuite/lib/target-supports.exp > @@ -2602,6 +2602,15 @@ proc check_effective_target_aarch64_little_endian { } { > }] > } > > +# Return 1 if this is a compiler supporting ARC atomic operations > +proc check_effective_target_arc_atomic { } { > + return [check_no_compiler_messages arc_atomic assembly { > + #if !defined(__ARC_ATOMIC__) > + #error FOO > + #endif > + }] > +} > + > # Return 1 if this is an arm target using 32-bit instructions > proc check_effective_target_arm32 { } { > if { ![istarget arm*-*-*] } { > @@ -5513,6 +5522,7 @@ proc check_effective_target_sync_int_long { } { > || [istarget crisv32-*-*] || [istarget cris-*-*] > || ([istarget sparc*-*-*] && [check_effective_target_sparc_v9]) > || [istarget spu-*-*] > + || ([istarget arc*-*-*] && [check_effective_target_arc_atomic]) > || [check_effective_target_mips_llsc] } { > set et_sync_int_long_saved 1 > } > @@ -5544,6 +5554,7 @@ proc check_effective_target_sync_char_short { } { > || [istarget crisv32-*-*] || [istarget cris-*-*] > || ([istarget sparc*-*-*] && [check_effective_target_sparc_v9]) > || [istarget spu-*-*] > + || ([istarget arc*-*-*] && [check_effective_target_arc_atomic]) > || [check_effective_target_mips_llsc] } { > set et_sync_char_short_saved 1 > } > -- > 1.9.1 >