gcc_unreachable ();
};
+ if (sparc_memory_model == SMM_DEFAULT)
+ {
+ /* Choose the memory model for the operating system. */
+ enum sparc_memory_model_type os_default = SUBTARGET_DEFAULT_MEMORY_MODEL;
+ if (os_default != SMM_DEFAULT)
+ sparc_memory_model = os_default;
+ /* Choose the most relaxed model for the processor. */
+ else if (TARGET_V9)
+ sparc_memory_model = SMM_RMO;
+ else if (TARGET_V8)
+ sparc_memory_model = SMM_PSO;
+ else
+ sparc_memory_model = SMM_SC;
+ }
+
#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
target_flags |= MASK_LONG_DOUBLE_128;
else if (size <= 8192)
{
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
- /* %sp is still the CFA register. */
RTX_FRAME_RELATED_P (insn) = 1;
+
+ /* %sp is still the CFA register. */
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
}
else
else if (size <= 8192)
{
emit_window_save (GEN_INT (-4096));
+
/* %sp is not the CFA register anymore. */
emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
+
+ /* Make sure no %fp-based store is issued until after the frame is
+ established. The offset between the frame pointer and the stack
+ pointer is calculated relative to the value of the stack pointer
+ at the end of the function prologue, and moving instructions that
+ access the stack via the frame pointer between the instructions
+ that decrement the stack pointer could result in accessing the
+ register window save area, which is volatile. */
+ emit_insn (gen_frame_blockage ());
}
else
{
const int LoadStore = 4;
const int StoreStore = 8;
- int mm = 0;
+ int mm = 0, implied = 0;
+
+ switch (sparc_memory_model)
+ {
+ case SMM_SC:
+ /* Sequential Consistency. All memory transactions are immediately
+ visible in sequential execution order. No barriers needed. */
+ implied = LoadLoad | StoreLoad | LoadStore | StoreStore;
+ break;
+
+ case SMM_TSO:
+ /* Total Store Ordering: all memory transactions with store semantics
+ are followed by an implied StoreStore. */
+ implied |= StoreStore;
+ /* FALLTHRU */
+
+ case SMM_PSO:
+ /* Partial Store Ordering: all memory transactions with load semantics
+ are followed by an implied LoadLoad | LoadStore. */
+ implied |= LoadLoad | LoadStore;
+
+ /* If we're not looking for a raw barrer (before+after), then atomic
+ operations get the benefit of being both load and store. */
+ if (load_store == 3 && before_after == 2)
+ implied |= StoreLoad | StoreStore;
+ /* FALLTHRU */
+
+ case SMM_RMO:
+ /* Relaxed Memory Ordering: no implicit bits. */
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
if (before_after & 1)
{
}
}
+ /* Remove the bits implied by the system memory model. */
+ mm &= ~implied;
+
/* For raw barriers (before+after), always emit a barrier.
This will become a compile-time barrier if needed. */
if (mm || before_after == 3)
/* 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);
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,
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);
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));
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)
{