@@ -19,7 +19,7 @@
;;; Unused letters:
;;; AB
-;;; a jkl q tuvwxyz
+;;; a jkl q tuv xyz
;; Register constraints
@@ -44,6 +44,9 @@
(define_register_constraint "h" "(TARGET_V9 && TARGET_V8PLUS ? I64_REGS : NO_REGS)"
"64-bit global or out register in V8+ mode")
+(define_memory_constraint "w"
+ "A memory with only a base register"
+ (match_operand 0 "mem_noofs_operand"))
;; Floating-point constant constraints
@@ -467,6 +467,10 @@
(match_test "call_address_operand (XEXP (op, 0), mode)")))
+(define_predicate "mem_noofs_operand"
+ (and (match_code "mem")
+ (match_code "reg" "0")))
+
;; Predicates for operators.
;; Return true if OP is a comparison operator. This allows the use of
@@ -104,7 +104,7 @@ extern int v9_regcmp_p (enum rtx_code);
32 bits of REG are 0 before INSN. */
extern int sparc_check_64 (rtx, rtx);
extern rtx gen_df_reg (rtx, int);
-extern void sparc_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx);
+extern void sparc_expand_compare_and_swap (rtx op[]);
extern void sparc_expand_vector_init (rtx, rtx);
extern void sparc_expand_vec_perm_bmask(enum machine_mode, rtx);
extern bool sparc_expand_conditional_move (enum machine_mode, rtx *);
@@ -10897,8 +10897,9 @@ sparc_emit_membar_for_model (enum memmodel model,
/* 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. */
-void
-sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+static void
+sparc_expand_compare_and_swap_12 (rtx bool_result, rtx result, rtx mem,
+ rtx oldval, rtx newval)
{
rtx addr1 = force_reg (Pmode, XEXP (mem, 0));
rtx addr = gen_reg_rtx (Pmode);
@@ -10923,7 +10924,7 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
- val = force_reg (SImode, memsi);
+ val = copy_to_reg (memsi);
emit_insn (gen_rtx_SET (VOIDmode, off,
gen_rtx_XOR (SImode, off,
@@ -10969,7 +10970,9 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
emit_insn (gen_rtx_SET (VOIDmode, newvalue,
gen_rtx_IOR (SImode, newv, val)));
- emit_insn (gen_sync_compare_and_swapsi (res, memsi, oldvalue, newvalue));
+ emit_move_insn (bool_result, const1_rtx);
+
+ emit_insn (gen_atomic_compare_and_swapsi_1 (res, memsi, oldvalue, newvalue));
emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label);
@@ -10977,6 +10980,8 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
res)));
+ emit_move_insn (bool_result, const0_rtx);
+
cc = gen_compare_reg_1 (NE, resv, val);
emit_insn (gen_rtx_SET (VOIDmode, val, resv));
@@ -10995,6 +11000,49 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
}
+/* Expand code to perform a compare-and-swap. */
+
+void
+sparc_expand_compare_and_swap (rtx operands[])
+{
+ rtx bval, retval, mem, oldval, newval;
+ enum machine_mode mode;
+ enum memmodel model;
+
+ bval = operands[0];
+ retval = operands[1];
+ mem = operands[2];
+ oldval = operands[3];
+ newval = operands[4];
+ model = (enum memmodel) INTVAL (operands[6]);
+ mode = GET_MODE (mem);
+
+ sparc_emit_membar_for_model (model, 3, 1);
+
+ if (reg_overlap_mentioned_p (retval, oldval))
+ oldval = copy_to_reg (oldval);
+
+ if (mode == QImode || mode == HImode)
+ sparc_expand_compare_and_swap_12 (bval, retval, mem, oldval, newval);
+ else
+ {
+ rtx (*gen) (rtx, rtx, rtx, rtx);
+ rtx x;
+
+ if (mode == SImode)
+ gen = gen_atomic_compare_and_swapsi_1;
+ else
+ gen = gen_atomic_compare_and_swapdi_1;
+ emit_insn (gen (retval, mem, oldval, newval));
+
+ x = emit_store_flag (bval, EQ, retval, oldval, mode, 1, 1);
+ if (x != bval)
+ convert_move (bval, x, 1);
+ }
+
+ sparc_emit_membar_for_model (model, 3, 2);
+}
+
void
sparc_expand_vec_perm_bmask (enum machine_mode vmode, rtx sel)
{
@@ -147,55 +147,37 @@
[(set_attr "type" "store,store,fpstore")
(set_attr "cpu_feature" "v9,*,*")])
-;;;;;;;;
-
-(define_expand "sync_compare_and_swap<mode>"
- [(match_operand:I12MODE 0 "register_operand" "")
- (match_operand:I12MODE 1 "memory_operand" "")
- (match_operand:I12MODE 2 "register_operand" "")
- (match_operand:I12MODE 3 "register_operand" "")]
+(define_expand "atomic_compare_and_swap<mode>"
+ [(match_operand:SI 0 "register_operand" "") ;; bool output
+ (match_operand:I 1 "register_operand" "") ;; val output
+ (match_operand:I 2 "mem_noofs_operand" "") ;; memory
+ (match_operand:I 3 "register_operand" "") ;; expected
+ (match_operand:I 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_V9"
{
- sparc_expand_compare_and_swap_12 (operands[0], operands[1],
- operands[2], operands[3]);
+ sparc_expand_compare_and_swap (operands);
DONE;
})
-(define_expand "sync_compare_and_swap<mode>"
- [(parallel
- [(set (match_operand:I48MODE 0 "register_operand" "")
- (match_operand:I48MODE 1 "memory_operand" ""))
- (set (match_dup 1)
- (unspec_volatile:I48MODE
- [(match_operand:I48MODE 2 "register_operand" "")
- (match_operand:I48MODE 3 "register_operand" "")]
- UNSPECV_CAS))])]
- "TARGET_V9"
-{
- if (!REG_P (XEXP (operands[1], 0)))
- {
- rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
- operands[1] = replace_equiv_address (operands[1], addr);
- }
- emit_insn (gen_memory_barrier ());
-})
-
-(define_insn "*sync_compare_and_swap<mode>"
+(define_insn "atomic_compare_and_swap<mode>_1"
[(set (match_operand:I48MODE 0 "register_operand" "=r")
- (mem:I48MODE (match_operand 1 "register_operand" "r")))
- (set (mem:I48MODE (match_dup 1))
+ (match_operand:I48MODE 1 "mem_noofs_operand" "+w"))
+ (set (match_dup 1)
(unspec_volatile:I48MODE
[(match_operand:I48MODE 2 "register_operand" "r")
(match_operand:I48MODE 3 "register_operand" "0")]
UNSPECV_CAS))]
"TARGET_V9 && (<MODE>mode == SImode || TARGET_ARCH64)"
- "cas<modesuffix>\t[%1], %2, %0"
+ "cas<modesuffix>\t%1, %2, %0"
[(set_attr "type" "multi")])
-(define_insn "*sync_compare_and_swapdi_v8plus"
+(define_insn "*atomic_compare_and_swapdi_v8plus"
[(set (match_operand:DI 0 "register_operand" "=h")
- (mem:DI (match_operand 1 "register_operand" "r")))
- (set (mem:DI (match_dup 1))
+ (match_operand:DI 1 "mem_noofs_operand" "+w"))
+ (set (match_dup 1)
(unspec_volatile:DI
[(match_operand:DI 2 "register_operand" "h")
(match_operand:DI 3 "register_operand" "0")]
@@ -210,12 +192,14 @@
output_asm_insn ("srl\t%L2, 0, %L2", operands);
output_asm_insn ("sllx\t%H2, 32, %H3", operands);
output_asm_insn ("or\t%L2, %H3, %H3", operands);
- output_asm_insn ("casx\t[%1], %H3, %L3", operands);
+ output_asm_insn ("casx\t%1, %H3, %L3", operands);
return "srlx\t%L3, 32, %H3";
}
[(set_attr "type" "multi")
(set_attr "length" "8")])
+;;;;;;;;
+
(define_expand "sync_lock_test_and_set<mode>"
[(match_operand:I12MODE 0 "register_operand" "")
(match_operand:I12MODE 1 "memory_operand" "")