return expand_call (exp, target, ignore);
}
- if (fcode == RS6000_BIF_PPC_ATOMIC_CAS_QI
- || fcode == RS6000_BIF_PPC_ATOMIC_CAS_HI
- || fcode == RS6000_BIF_PPC_ATOMIC_CAS_SI
- || fcode == RS6000_BIF_PPC_ATOMIC_CAS_DI
- || fcode == RS6000_BIF_PPC_ATOMIC_CAS_TI)
- {
- machine_mode mode; // Get mode based on BIF ID (QImode, SImode, etc.)
-
- switch (fcode)
- {
- case RS6000_BIF_PPC_ATOMIC_CAS_QI:
- mode = QImode;
- icode = CODE_FOR_atomic_compare_and_swap_localqi;
- break;
- case RS6000_BIF_PPC_ATOMIC_CAS_HI:
- mode = HImode;
- icode = CODE_FOR_atomic_compare_and_swap_localhi;
- break;
- case RS6000_BIF_PPC_ATOMIC_CAS_SI:
- mode = SImode;
- icode = CODE_FOR_atomic_compare_and_swap_localsi;
- break;
- case RS6000_BIF_PPC_ATOMIC_CAS_DI:
- mode = DImode;
- icode = CODE_FOR_atomic_compare_and_swap_localdi;
- break;
- case RS6000_BIF_PPC_ATOMIC_CAS_TI:
- mode = TImode;
- icode = CODE_FOR_atomic_compare_and_swap_localti;
- break;
- default:
- gcc_unreachable ();
- }
-
- // Arg 0: ptr (pointer to data)
- rtx ptr = expand_normal (CALL_EXPR_ARG (exp, 0));
- rtx mem = gen_rtx_MEM (mode, force_reg (Pmode, ptr));
-
- // Arg 1: expected (pointer to value) -> WE MUST DEREFERENCE THIS
- rtx exp_ptr = expand_normal (CALL_EXPR_ARG (exp, 1));
- rtx expected_val = gen_reg_rtx (mode);
- emit_move_insn (expected_val, gen_rtx_MEM (mode,
- force_reg (Pmode, exp_ptr)));
-
- // Arg 2: desired (value), dereference this as well
- rtx desired_ptr = expand_normal (CALL_EXPR_ARG (exp, 2));
- rtx desired_val = gen_reg_rtx (mode);
- emit_move_insn (desired_val,
- gen_rtx_MEM (mode, force_reg (Pmode, desired_ptr)));
-
- // Args 3, 4, 5: weak, succ, fail (constants)
- rtx weak = expand_normal (CALL_EXPR_ARG (exp, 3));
- rtx succ = expand_normal (CALL_EXPR_ARG (exp, 4));
- rtx fail = expand_normal (CALL_EXPR_ARG (exp, 5));
-
- // 0: Boolean return (Output)
- struct expand_operand ops[8];
- create_output_operand (&ops[0], target, SImode);
-
- // 1: Old value return (Output)
- rtx old_val = gen_reg_rtx (mode);
- create_output_operand (&ops[1], old_val, mode);
-
- // 2: The Memory (Fixed/Input - it's a MEM rtx)
- // We use create_fixed_operand because it's a specific MEM location
- create_fixed_operand (&ops[2], mem);
-
- // 3: Expected Value (Input)
- create_input_operand (&ops[3], expected_val, mode);
-
- // 4: Desired Value (Input)
- create_input_operand (&ops[4], desired_val, mode);
-
- // 5, 6, 7: Weak, Success, Failure (Immediate/Constants)
- create_input_operand (&ops[5], weak, SImode);
- create_input_operand (&ops[6], succ, SImode);
- create_input_operand (&ops[7], fail, SImode);
-
- // Now call expand_insn with the ops array
- if (!maybe_expand_insn (icode, 8, ops))
- error ("invalid arguments to builtin");
-
- // Create a label for the end of the function.
- rtx done_label = gen_label_rtx ();
-
- /* Standard Semantics: Update 'expected' ONLY on failure.
- If target (the boolean result) is NOT 0, the CAS succeeded.
- In the case of success, we jump straight to the end. */
-
- // If target != 0 (Success), skip the store.
- emit_cmp_and_jump_insns (target, const0_rtx, NE, NULL_RTX,
- SImode, 1, done_label);
-
- // FAILURE PATH: This code runs only if target == 0.
- rtx expected_mem = gen_rtx_MEM (mode, force_reg (Pmode, exp_ptr));
- emit_move_insn (expected_mem, old_val);
-
- emit_label (done_label);
-
- return target;
- }
-
if (bif_is_nosoft (*bifaddr)
&& rs6000_isa_flags & OPTION_MASK_SOFT_FLOAT)
{
const double __builtin_unpack_longdouble (long double, const int<1>);
UNPACK_TF unpacktf {ibmld}
-; Builtins for ppc specific atomic compare exchange
- bool __builtin_ppc_atomic_cas_local_qi (char *, char *, char *, const int, const int, const int);
- PPC_ATOMIC_CAS_QI nothing {}
- bool __builtin_ppc_atomic_cas_local_hi (short *, short *, short *, const int, const int, const int);
- PPC_ATOMIC_CAS_HI nothing {}
- bool __builtin_ppc_atomic_cas_local_si (int *, int *, int *, const int, const int, const int);
- PPC_ATOMIC_CAS_SI nothing {}
- bool __builtin_ppc_atomic_cas_local_di (long *, long *, long *, const int, const int, const int);
- PPC_ATOMIC_CAS_DI nothing {}
- bool __builtin_ppc_atomic_cas_local_ti (vsq *, vsq *, vsq *, const int, const int, const int);
- PPC_ATOMIC_CAS_TI nothing {}
; Builtins that have been around just about forever, but not quite.
[power5]
/* If the number of arguments to an overloaded function increases,
we must expand this switch. */
- gcc_assert (MAX_OVLD_ARGS <= 6);
+ gcc_assert (MAX_OVLD_ARGS <= 4);
tree call;
switch (n)
case 4:
call = build_call_expr (fndecl, 4, args[0], args[1], args[2], args[3]);
break;
- case 5:
- call = build_call_expr (fndecl, 5, args[0], args[1], args[2], args[3],
- args[4]);
- break;
- case 6:
- call = build_call_expr (fndecl, 6, args[0], args[1], args[2], args[3],
- args[4], args[5]);
- break;
default:
gcc_unreachable ();
}
; a semicolon are also treated as blank lines.
-[PPC_ATOMIC_CAS, SKIP, __builtin_ppc_atomic_cas_local]
- bool __builtin_ppc_atomic_cas_local (signed char *, signed char *, signed char *, const int, const int, const int);
- PPC_ATOMIC_CAS_QI PPC_ATOMIC_CAS_SQI
- bool __builtin_ppc_atomic_cas_local (unsigned char *, unsigned char *, unsigned char *, const int, const int, const int);
- PPC_ATOMIC_CAS_QI PPC_ATOMIC_CAS_UQI
- bool __builtin_ppc_atomic_cas_local (signed short *, signed short *, signed short *, const int, const int, const int);
- PPC_ATOMIC_CAS_HI PPC_ATOMIC_CAS_SHI
- bool __builtin_ppc_atomic_cas_local (unsigned short *, unsigned short *, unsigned short *, const int, const int, const int);
- PPC_ATOMIC_CAS_HI PPC_ATOMIC_CAS_UHI
- bool __builtin_ppc_atomic_cas_local (signed int *, signed int *, signed int *, const int, const int, const int);
- PPC_ATOMIC_CAS_SI PPC_ATOMIC_CAS_SSI
- bool __builtin_ppc_atomic_cas_local (unsigned int *, unsigned int *, unsigned int *, const int, const int, const int);
- PPC_ATOMIC_CAS_SI PPC_ATOMIC_CAS_USI
- bool __builtin_ppc_atomic_cas_local (signed long *, signed long *, signed long *, const int, const int, const int);
- PPC_ATOMIC_CAS_DI PPC_ATOMIC_CAS_SDI
- bool __builtin_ppc_atomic_cas_local (unsigned long *, unsigned long *, unsigned long *, const int, const int, const int);
- PPC_ATOMIC_CAS_DI PPC_ATOMIC_CAS_UDI
- bool __builtin_ppc_atomic_cas_local (vsq *, vsq *, vsq *, const int, const int, const int);
- PPC_ATOMIC_CAS_TI PPC_ATOMIC_CAS_STI
- bool __builtin_ppc_atomic_cas_local (vuq *, vuq *, vuq *, const int, const int, const int);
- PPC_ATOMIC_CAS_TI PPC_ATOMIC_CAS_UTI
-
[BCDADD, __builtin_bcdadd, __builtin_vec_bcdadd]
vsq __builtin_vec_bcdadd (vsq, vsq, const int);
BCDADD_V1TI
extern bool rs6000_emit_cmove (rtx, rtx, rtx, rtx);
extern bool rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
extern void rs6000_emit_minmax (rtx, enum rtx_code, rtx, rtx);
-extern void rs6000_expand_atomic_compare_and_swap (rtx op[], bool local);
+extern void rs6000_expand_atomic_compare_and_swap (rtx op[]);
extern rtx swap_endian_selector_for_mode (machine_mode mode);
extern void rs6000_expand_atomic_exchange (rtx op[]);
/* A subroutine of the atomic operation splitters. Emit a load-locked
instruction in MODE. For QI/HImode, possibly use a pattern than includes
- the zero_extend operation. LOCAL indicates the EH bit value for the
- load-locked instruction. */
+ the zero_extend operation. */
static void
-emit_load_locked (machine_mode mode, rtx reg, rtx mem, rtx local)
+emit_load_locked (machine_mode mode, rtx reg, rtx mem)
{
- rtx (*fn) (rtx, rtx, rtx) = NULL;
+ rtx (*fn) (rtx, rtx) = NULL;
switch (mode)
{
default:
gcc_unreachable ();
}
- emit_insn (fn (reg, mem, local));
+ emit_insn (fn (reg, mem));
}
/* A subroutine of the atomic operation splitters. Emit a store-conditional
/* Expand an atomic compare and swap operation. */
void
-rs6000_expand_atomic_compare_and_swap (rtx operands[], bool local)
+rs6000_expand_atomic_compare_and_swap (rtx operands[])
{
rtx boolval, retval, mem, oldval, newval, cond;
rtx label1, label2, x, mask, shift;
}
label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
- emit_load_locked (mode, retval, mem, local ? const1_rtx : const0_rtx);
+ emit_load_locked (mode, retval, mem);
x = retval;
if (mask)
label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
emit_label (XEXP (label, 0));
- emit_load_locked (mode, retval, mem, const0_rtx);
+ emit_load_locked (mode, retval, mem);
x = val;
if (mask)
if (before == NULL_RTX)
before = gen_reg_rtx (mode);
- emit_load_locked (mode, before, mem, const0_rtx);
+ emit_load_locked (mode, before, mem);
if (code == NOT)
{
(define_insn "load_locked<mode>"
[(set (match_operand:ATOMIC 0 "int_reg_operand" "=r")
(unspec_volatile:ATOMIC
- [(match_operand:ATOMIC 1 "memory_operand" "Z")
- (match_operand:QI 2 "u1bit_cint_operand" "n")] UNSPECV_LL))]
+ [(match_operand:ATOMIC 1 "memory_operand" "Z")] UNSPECV_LL))]
""
- "<larx> %0,%y1,%2"
+ "<larx> %0,%y1"
[(set_attr "type" "load_l")])
(define_insn "load_locked<QHI:mode>_si"
[(set (match_operand:SI 0 "int_reg_operand" "=r")
(unspec_volatile:SI
- [(match_operand:QHI 1 "memory_operand" "Z")
- (match_operand:QI 2 "u1bit_cint_operand" "n")] UNSPECV_LL))]
+ [(match_operand:QHI 1 "memory_operand" "Z")] UNSPECV_LL))]
"TARGET_SYNC_HI_QI"
- "<QHI:larx> %0,%y1,%2"
+ "<QHI:larx> %0,%y1"
[(set_attr "type" "load_l")])
;; Use PTImode to get even/odd register pairs.
(define_expand "load_lockedti"
[(use (match_operand:TI 0 "quad_int_reg_operand"))
- (use (match_operand:TI 1 "memory_operand"))
- (use (match_operand:QI 2 "u1bit_cint_operand"))]
+ (use (match_operand:TI 1 "memory_operand"))]
"TARGET_SYNC_TI"
{
rtx op0 = operands[0];
operands[1] = op1 = change_address (op1, TImode, new_addr);
}
- emit_insn (gen_load_lockedpti (pti, op1, operands[2]));
+ emit_insn (gen_load_lockedpti (pti, op1));
if (WORDS_BIG_ENDIAN)
emit_move_insn (op0, gen_lowpart (TImode, pti));
else
(define_insn "load_lockedpti"
[(set (match_operand:PTI 0 "quad_int_reg_operand" "=&r")
(unspec_volatile:PTI
- [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")
- (match_operand:QI 2 "u1bit_cint_operand" "n")] UNSPECV_LL))]
+ [(match_operand:TI 1 "indexed_or_indirect_operand" "Z")] UNSPECV_LL))]
"TARGET_SYNC_TI
&& !reg_mentioned_p (operands[0], operands[1])
&& quad_int_reg_operand (operands[0], PTImode)"
- "lqarx %0,%y1,%2"
+ "lqarx %0,%y1"
[(set_attr "type" "load_l")
(set_attr "size" "128")])
(match_operand:SI 7 "const_int_operand")] ;; model fail
""
{
- rs6000_expand_atomic_compare_and_swap (operands, false);
- DONE;
-})
-
-(define_expand "atomic_compare_and_swap_local<mode>"
- [(match_operand:SI 0 "int_reg_operand") ;; bool out
- (match_operand:AINT 1 "int_reg_operand") ;; val out
- (match_operand:AINT 2 "memory_operand") ;; memory
- (match_operand:AINT 3 "reg_or_short_operand") ;; expected
- (match_operand:AINT 4 "int_reg_operand") ;; desired
- (match_operand:SI 5 "const_int_operand") ;; is_weak
- (match_operand:SI 6 "const_int_operand") ;; model succ
- (match_operand:SI 7 "const_int_operand")] ;; model fail
- ""
-{
- rs6000_expand_atomic_compare_and_swap (operands, true);
+ rs6000_expand_atomic_compare_and_swap (operands);
DONE;
})
+++ /dev/null
-/* { dg-do compile } */
-/* { dg-options "-O2" } */
-
-#define TESTS \
- X(signed char, qi) \
- X(unsigned char, uqi) \
- X(short, hi) \
- X(signed short, shi) \
- X(unsigned short, uhi) \
- X(int, si) \
- X(signed int, ssi) \
- X(unsigned int, usi) \
- X(long, di) \
- X(signed long, sdi) \
- X(unsigned long, udi) \
- X(vector signed __int128, sti) \
- X(vector unsigned __int128, uti)
-
-#define X(T, name) \
-bool word_exchange_##name (T *ptr, T *expected, T * desired) \
-{ \
- return __builtin_ppc_atomic_cas_local (ptr, expected, desired, 0, \
- __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE); \
-}
-
-TESTS
-
-/* { dg-final { scan-assembler-times {\mlbarx +[0-9]+,[0-9]+,[0-9]+,1} 2 } } */
-/* { dg-final { scan-assembler-times {\mlharx +[0-9]+,[0-9]+,[0-9]+,1} 3 } } */
-/* { dg-final { scan-assembler-times {\mlwarx +[0-9]+,[0-9]+,[0-9]+,1} 3 } } */
-/* { dg-final { scan-assembler-times {\mldarx +[0-9]+,[0-9]+,[0-9]+,1} 3 } } */
-/* { dg-final { scan-assembler-times {\mlqarx +[0-9]+,[0-9]+,[0-9]+,1} 2 } } */