Hi Michael,
Thanks for the review. I will update the patch and post a v4 with some of the necessary changes you mentioned. However for some of points I have some doubts/arguments below. On Tue, 2026-06-02 at 02:39 -0400, Michael Meissner wrote: > On Wed, May 27, 2026 at 10:43:29AM +0530, Avinash Jayakar wrote: > > Hi, > > > > Incorporated the changes requested in > > https://gcc.gnu.org/pipermail/gcc-patches/2026-May/717045.html > > > > Bootstrappend and regtested on powerpc64le and powerpc64 (32 and 64 > > bit) > > variants with no regressions. Kindly review. > > > > Changes from v3: > > * Remove case 5 in altivec_build_resolved_builtin > > > > Changes from v2: > > * Updated commit message with hint explaination. > > * Expanded test case macros. > > I have some questions, but it looks like we are converging to a > solution. Thanks for your work in doing this. > > > Thanks and regards, > > Avinash Jayakar > > > > This patch adds a new powerpc specific atomic builtin which is > > similar > > to the generic __atomic_compare_exchange builtin. > > > > bool __builtin_ppc_atomic_cas_local (type *ptr, type *expected, > > type *desired, bool weak, > > int success_memorder, > > int failure_memorder) > > > > It behaves like __atomic_compare_exchange(), but it uses an EH > > value of > > 1 in the larx (load-and-reserve) instruction, which provides a hint > > whether the program will perform a subsequent store to the > > specified > > location. The new builtin helps optimize lock contention on PowerPC > > by > > keeping the lock cacheline in the local processor longer, reducing > > performance penalties from cache coherence protocol traffic. > > > > 2026-05-27 Avinash Jayakar <[email protected]> > > Surya Kumari Jangala <[email protected]> > > > > gcc/ChangeLog: > > * config/rs6000/rs6000-builtin.cc (rs6000_expand_builtin): > > Add logic to > > handle __builtin_ppc_atomic_cas_local. > > * config/rs6000/rs6000-builtins.def: New builtins for > > __builtin_ppc_atomic_cas_local with types. > > * config/rs6000/rs6000-c.cc > > (altivec_build_resolved_builtin): Handle > > builtins with up to 6 arguments. > > * config/rs6000/rs6000-overload.def: Overload builtin for > > signed/unsiged > > char, short, int, long, __int128. > > * config/rs6000/rs6000-protos.h > > (rs6000_expand_atomic_compare_and_swap): Add > > additional parameter 'local' to the prototype. > > * config/rs6000/rs6000.cc (emit_load_locked): Add new > > parameter. Pass new > > parameter to generate load-locked instruction. > > (rs6000_expand_atomic_compare_and_swap): Add new > > parameter. Call > > emit_load_locked() with additional parameter value of EH > > bit. > > (rs6000_expand_atomic_exchange): Pass EH value 0 to > > emit_load_locked(). > > (rs6000_expand_atomic_op): Likewise. > > * config/rs6000/sync.md (load_locked<mode>): Add new > > operand in RTL template. > > Specify EH bit in the larx instruction. > > (load_locked<QHI:mode>_si): Likewise. > > (load_lockedpti): Likewise. > > (load_lockedti): Add new operand in RTL template. Pass EH > > bit to > > gen_load_lockedpti(). > > (atomic_compare_and_swap<mode>): Pass new parameter > > 'false' to > > rs6000_expand_atomic_compare_and_swap. > > (atomic_compare_and_swap_local<mode>): New define_expand. > > You also need to add documentation to doc/extend.texi to describe > these > functions. Noted, will update. > > > gcc/testsuite/ChangeLog: > > * gcc.target/powerpc/acmp-tst-32bit.c: New test. > > * gcc.target/powerpc/acmp-tst.c: New test. > > See below. > > > --- > > gcc/config/rs6000/rs6000-builtin.cc | 102 ++++++++++ > > gcc/config/rs6000/rs6000-builtins.def | 11 ++ > > gcc/config/rs6000/rs6000-c.cc | 119 +++++++++++- > > gcc/config/rs6000/rs6000-overload.def | 7 + > > gcc/config/rs6000/rs6000-protos.h | 2 +- > > gcc/config/rs6000/rs6000.cc | 17 +- > > gcc/config/rs6000/sync.md | 37 +++- > > .../gcc.target/powerpc/acmp-tst-32bit.c | 62 +++++++ > > gcc/testsuite/gcc.target/powerpc/acmp-tst.c | 174 > > ++++++++++++++++++ > > 9 files changed, 511 insertions(+), 20 deletions(-) > > create mode 100644 gcc/testsuite/gcc.target/powerpc/acmp-tst- > > 32bit.c > > create mode 100644 gcc/testsuite/gcc.target/powerpc/acmp-tst.c > > > > diff --git a/gcc/config/rs6000/rs6000-builtin.cc > > b/gcc/config/rs6000/rs6000-builtin.cc > > index 4d0e541351f..7661147d05c 100644 > > --- a/gcc/config/rs6000/rs6000-builtin.cc > > +++ b/gcc/config/rs6000/rs6000-builtin.cc > > @@ -3289,6 +3289,108 @@ rs6000_expand_builtin (tree exp, rtx > > target, rtx /* subtarget */, > > 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) > > { > > In the above you use force_reg. I recall in the past that force_reg > tended to set flags that may prevent using indexed arithmetic > (i.e. reg1+reg2 addressing). > > Could you try the following case? > > bool > word_exchange_hi_n (short *ptr, short *expected, short *desired, > size_t n) > { > return __builtin_ppc_atomic_cas_local (ptr+n, expected+n, > desired+n, 1, > __ATOMIC_SEQ_CST, > __ATOMIC_ACQUIRE); > } > > And see if something similar to the code is generated: > > sldi 6,6,2 > lwz 9,0(4) > lwzx 10,5,6 > .L2: > lwarx 2,3,6,1 > cmpw 0,2,9 > bne 0,.L3 > stwcx. 10,3,6 > bne 0,.L2 You are right, forcing it to register loads the addr into a separate reg instead of using indexed form. Generated code for the above with O2 is .LFB0: .cfi_startproc sldi 6,6,1 add 8,3,6 lhzx 10,4,6 lhzx 7,5,6 sync lharx 9,3,6,1 cmpw 0,9,10 bne 0,.L2 sthcx. 7,0,8 .L2: isync mfcr 3,128 rlwinm 3,3,3,1 beq 0,.L3 sthx 9,4,6 only for sthcx. it forced the addr into a register. I think for lhzx and lharx, the rtl optimizations might have helped use the indexed form of loads. > > I.e. the lwzx, lwarx, and stwcx. instructions use reg,reg addressing > instead of 0,reg. I think using force_reg will tend to tell the > optimizer to generate 0,reg address. > > The solution would be to switch to using copy_to_mode_reg instead of > force_reg. I.e. I tried using this, but it did not solve the issue mentioned above. I looked at how generic builtin expands and they use expand_expr instead of expand_normal. Replacing that seemed to solve the issue, hope this change is OK. // For arg 0 (ptr to data) rtx ptr = expand_expr (CALL_EXPR_ARG (exp, 0), NULL_RTX, Pmode, EXPAND_SUM); ptr = convert_memory_address (Pmode, ptr); rtx mem = gen_rtx_MEM (mode, ptr); // For arg 1 (expected ptr) rtx exp_ptr = expand_expr (CALL_EXPR_ARG (exp, 1), NULL_RTX, Pmode, EXPAND_SUM); exp_ptr = convert_memory_address (Pmode, exp_ptr); rtx expected_val = gen_reg_rtx (mode); emit_move_insn (expected_val, gen_rtx_MEM (mode, exp_ptr)); // For arg 2 (desired ptr) rtx desired_ptr = expand_expr (CALL_EXPR_ARG (exp, 2), NULL_RTX, Pmode, EXPAND_SUM); desired_ptr = convert_memory_address (Pmode, desired_ptr); rtx desired_val = gen_reg_rtx (mode); emit_move_insn (desired_val, gen_rtx_MEM (mode, desired_ptr)); > > diff --git a/gcc/config/rs6000/rs6000-builtin.cc > b/gcc/config/rs6000/rs6000-builtin.cc > index 4d0e541351f..7661147d05c 100644 > --- a/gcc/config/rs6000/rs6000-builtin.cc > +++ b/gcc/config/rs6000/rs6000-builtin.cc > @@ -3289,6 +3289,108 @@ rs6000_expand_builtin (tree exp, rtx target, > rtx /* subtarget */, > 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, copy_to_mode_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, > + copy_to_mode_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, copy_to_mode_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, copy_to_mode_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) > { > > > > diff --git a/gcc/config/rs6000/rs6000-builtins.def > > b/gcc/config/rs6000/rs6000-builtins.def > > index 0d1529b71d4..ef1a641e99e 100644 > > --- a/gcc/config/rs6000/rs6000-builtins.def > > +++ b/gcc/config/rs6000/rs6000-builtins.def > > @@ -246,6 +246,17 @@ > > 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 long > > *, long long *, const int, const int, const int); > > + PPC_ATOMIC_CAS_DI nothing {} > > + bool __builtin_ppc_atomic_cas_local_ti (__int128 *, __int128 *, > > __int128 *, const int, const int, const int); > > + PPC_ATOMIC_CAS_TI nothing {} > > > > ; Builtins that have been around just about forever, but not > > quite. > > [power5] > > I'm wondering aloud, do we need unsigned versions of the overloaded > built-ins (and signed char) I.e. something like: > > +; 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_uqi (unsigned char *, unsigned > char *, unsigned char *, const int, const int, const int); > + PPC_ATOMIC_CAS_UQI nothing {} > + bool __builtin_ppc_atomic_cas_local_sqi (signed char *, signed > char *, signed char *, const int, const int, const int); > + PPC_ATOMIC_CAS_SQI 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_uhi (unsigned short *, > unsigned short *, unsigned short *, const int, const int, const int); > + PPC_ATOMIC_CAS_UHI 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_si (unsigned int *, unsigned > int *, unsigned int *, const int, const int, const int); > + PPC_ATOMIC_CAS_USI nothing {} > + bool __builtin_ppc_atomic_cas_local_di (long long *, long long *, > long long *, const int, const int, const int); > + PPC_ATOMIC_CAS_DI nothing {} > + bool __builtin_ppc_atomic_cas_local_udi (unsigned long long *, > unsigned long long *, unsigned long long *, const int, const int, > const int); > + PPC_ATOMIC_CAS_DI nothing {} > + bool __builtin_ppc_atomic_cas_local_ti (__int128 *, __int128 *, > __int128 *, const int, const int, const int); > + PPC_ATOMIC_CAS_TI nothing {} > + bool __builtin_ppc_atomic_cas_local_uti (unsigned __int128 *, > unsigned __int128 *, unsigned __int128 *, const int, const int, const > int); > + PPC_ATOMIC_CAS_TI nothing {} > > Could you check whether all of the variants of signed/unsigned work > in > C and C++ without warnings? If we have to add all of the other > types, > you will obviously need to add them in other parts of the code. > Actually, it compiles fine without warning in all cases signed/unsigned. We only look at the type size, and a fake builtin for this is provided in the overload file, which takes void* as arguments hence no parsing warnings. Only constraint on the types is - 1st three argument type size must be same and known at compile time (the types itself can be different) - They must be a complete pointer type. > Also, you will need to break the long lines. Sure will do, using '\' for line break should do right? I was facing parsing errors building when I break them in new lines for the .def files. > > > diff --git a/gcc/config/rs6000/rs6000-c.cc > > b/gcc/config/rs6000/rs6000-c.cc > > index 3fa7c04a7ce..91380137f35 100644 > > --- a/gcc/config/rs6000/rs6000-c.cc > > +++ b/gcc/config/rs6000/rs6000-c.cc > > @@ -929,7 +929,7 @@ altivec_build_resolved_builtin (tree *args, int > > n, tree fntype, tree ret_type, > > > > /* If the number of arguments to an overloaded function > > increases, > > we must expand this switch. */ > > - gcc_assert (MAX_OVLD_ARGS <= 4); > > + gcc_assert (MAX_OVLD_ARGS <= 6); > > > > tree call; > > switch (n) > > @@ -949,6 +949,10 @@ altivec_build_resolved_builtin (tree *args, > > int n, tree fntype, tree ret_type, > > case 4: > > call = build_call_expr (fndecl, 4, args[0], args[1], > > args[2], args[3]); > > 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 (); > > } > > @@ -1710,11 +1714,122 @@ find_instance (bool *unsupported_builtin, > > int *instance, > > > > tree > > altivec_resolve_overloaded_builtin (location_t loc, tree fndecl, > > - void *passed_arglist, bool) > > + void *passed_arglist, bool > > complain) > > { > > rs6000_gen_builtins fcode > > = (rs6000_gen_builtins) DECL_MD_FUNCTION_CODE (fndecl); > > > > + /* Handle __builtin_ppc_atomic_cas_local before standard > > overload > > + processing. */ > > + if (fcode == RS6000_OVLD_PPC_ATOMIC_CAS) > > + { > > + vec<tree, va_gc> *arglist > > + = static_cast<vec<tree, va_gc> *> (passed_arglist); > > + > > + /* Expected: (void *ptr, void *expected, void *desired, > > + bool weak, int success_order, int failure_order). */ > > + if (vec_safe_length (arglist) != 6) > > + { > > + if (complain) > > + error_at (loc, "%qE requires 6 arguments", fndecl); > > + return error_mark_node; > > + } > > + > > + /* Get the first argument to determine the actual type. */ > > + tree arg0 = (*arglist)[0]; > > + tree type0 = TREE_TYPE (arg0); > > + > > + /* Must be a pointer. */ > > + if (!POINTER_TYPE_P (type0)) > > + { > > + if (complain) > > + error_at (loc, "first argument to %qE must be a > > pointer", fndecl); > > + return error_mark_node; > > + } > > + > > + /* Get the pointee type. */ > > + tree pointee_type = TREE_TYPE (type0); > > + > > + /* Must be a complete type. */ > > + if (!COMPLETE_TYPE_P (pointee_type)) > > + { > > + if (complain) > > + error_at (loc, "first argument to %qE must point to a > > complete type", > > + fndecl); > > + return error_mark_node; > > + } > > + > > + /* Get size in bytes. */ > > + tree size_tree = TYPE_SIZE_UNIT (pointee_type); > > + if (!tree_fits_uhwi_p (size_tree)) > > + { > > + if (complain) > > + error_at (loc, "type size must be constant"); > > + return error_mark_node; > > + } > > + > > + unsigned HOST_WIDE_INT size = tree_to_uhwi (size_tree); > > + > > + /* Determine which size-specific builtin to use. */ > > + rs6000_gen_builtins target_fcode; > > + tree int_type; > > + > > + switch (size) > > + { > > + case 1: > > + target_fcode = RS6000_BIF_PPC_ATOMIC_CAS_QI; > > + int_type = unsigned_char_type_node; > > + break; > > + case 2: > > + target_fcode = RS6000_BIF_PPC_ATOMIC_CAS_HI; > > + int_type = short_unsigned_type_node; > > + break; > > + case 4: > > + target_fcode = RS6000_BIF_PPC_ATOMIC_CAS_SI; > > + int_type = unsigned_intSI_type_node; > > + break; > > + case 8: > > + target_fcode = RS6000_BIF_PPC_ATOMIC_CAS_DI; > > + int_type = long_long_unsigned_type_node; > > + break; > > + case 16: > > + target_fcode = RS6000_BIF_PPC_ATOMIC_CAS_TI; > > + int_type = unsigned_intTI_type_node; > > + break; > > + default: > > + if (complain) > > + error_at (loc, "size %wu not supported for %qE " > > + "(must be 1, 2, 4, 8, or 16 bytes)", size, > > fndecl); > > + return error_mark_node; > > + } > > + > > + /* Create pointer type to the appropriate integer type. */ > > + tree int_ptr_type = build_pointer_type (int_type); > > + > > + /* Cast the three pointer arguments to the appropriate > > integer > > + pointer type. */ > > + tree new_arg0 = build1 (VIEW_CONVERT_EXPR, int_ptr_type, > > (*arglist)[0]); > > + tree new_arg1 = build1 (VIEW_CONVERT_EXPR, int_ptr_type, > > (*arglist)[1]); > > + tree new_arg2 = build1 (VIEW_CONVERT_EXPR, int_ptr_type, > > (*arglist)[2]); > > + > > + /* Build new argument list with casted pointers. */ > > + vec<tree, va_gc> *new_arglist; > > + vec_alloc (new_arglist, 6); > > + new_arglist->quick_push (new_arg0); > > + new_arglist->quick_push (new_arg1); > > + new_arglist->quick_push (new_arg2); > > + new_arglist->quick_push ((*arglist)[3]); /* weak (bool). > > */ > > + new_arglist->quick_push ((*arglist)[4]); /* > > success_memorder. */ > > + new_arglist->quick_push ((*arglist)[5]); /* > > failure_memorder. */ > > + > > + /* Get the target builtin function. */ > > + tree new_fndecl = rs6000_builtin_decls[target_fcode]; > > + > > + /* Build and return the function call. */ > > + return build_function_call_vec (loc, vNULL, new_fndecl, > > new_arglist, > > + NULL, fndecl); > > + } > > + > > /* Return immediately if this isn't an overload. */ > > if (fcode <= RS6000_OVLD_NONE) > > return NULL_TREE; > > diff --git a/gcc/config/rs6000/rs6000-overload.def > > b/gcc/config/rs6000/rs6000-overload.def > > index ef7b59ed112..808b7133d19 100644 > > --- a/gcc/config/rs6000/rs6000-overload.def > > +++ b/gcc/config/rs6000/rs6000-overload.def > > @@ -79,6 +79,13 @@ > > ; a semicolon are also treated as blank lines. > > > > > > +; The following function is not overloaded, but is internally > > substituted by > > +; __builtin_ppc_atomic_cas_local_{qi,hi,si,di,ti} based on the > > first 3 > > +; arguments. > > +[PPC_ATOMIC_CAS, SKIP, __builtin_ppc_atomic_cas_local] > > + bool __builtin_ppc_atomic_cas_local (void *, void *, void *, > > const int, const int, const int); > > + PPC_ATOMIC_CAS_QI PPC_ATOMIC_CAS_FAKERY > > + > > [BCDADD, __builtin_bcdadd, __builtin_vec_bcdadd] > > vsq __builtin_vec_bcdadd (vsq, vsq, const int); > > BCDADD_V1TI > > diff --git a/gcc/config/rs6000/rs6000-protos.h > > b/gcc/config/rs6000/rs6000-protos.h > > index 09424ebaf97..5efca2d5834 100644 > > --- a/gcc/config/rs6000/rs6000-protos.h > > +++ b/gcc/config/rs6000/rs6000-protos.h > > @@ -127,7 +127,7 @@ extern bool rs6000_emit_set_const (rtx, rtx); > > 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[]); > > +extern void rs6000_expand_atomic_compare_and_swap (rtx op[], bool > > local); > > extern rtx swap_endian_selector_for_mode (machine_mode mode); > > > > extern void rs6000_expand_atomic_exchange (rtx op[]); > > diff --git a/gcc/config/rs6000/rs6000.cc > > b/gcc/config/rs6000/rs6000.cc > > index fba481b2b5d..cb8b8ce437b 100644 > > --- a/gcc/config/rs6000/rs6000.cc > > +++ b/gcc/config/rs6000/rs6000.cc > > @@ -16748,12 +16748,13 @@ emit_unlikely_jump (rtx cond, rtx label) > > > > /* 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. */ > > + the zero_extend operation. LOCAL indicates the EH bit value > > for the > > + load-locked instruction. */ > > > > static void > > -emit_load_locked (machine_mode mode, rtx reg, rtx mem) > > +emit_load_locked (machine_mode mode, rtx reg, rtx mem, rtx local) > > { > > - rtx (*fn) (rtx, rtx) = NULL; > > + rtx (*fn) (rtx, rtx, rtx) = NULL; > > > > switch (mode) > > { > > @@ -16780,7 +16781,7 @@ emit_load_locked (machine_mode mode, rtx > > reg, rtx mem) > > default: > > gcc_unreachable (); > > } > > - emit_insn (fn (reg, mem)); > > + emit_insn (fn (reg, mem, local)); > > } > > > > /* A subroutine of the atomic operation splitters. Emit a store- > > conditional > > @@ -16950,7 +16951,7 @@ rs6000_finish_atomic_subword (rtx narrow, > > rtx wide, rtx shift) > > /* Expand an atomic compare and swap operation. */ > > > > void > > -rs6000_expand_atomic_compare_and_swap (rtx operands[]) > > +rs6000_expand_atomic_compare_and_swap (rtx operands[], bool local) > > { > > rtx boolval, retval, mem, oldval, newval, cond; > > rtx label1, label2, x, mask, shift; > > @@ -17013,7 +17014,7 @@ rs6000_expand_atomic_compare_and_swap (rtx > > operands[]) > > } > > label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ()); > > > > - emit_load_locked (mode, retval, mem); > > + emit_load_locked (mode, retval, mem, local ? const1_rtx : > > const0_rtx); > > > > x = retval; > > if (mask) > > @@ -17111,7 +17112,7 @@ rs6000_expand_atomic_exchange (rtx > > operands[]) > > label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ()); > > emit_label (XEXP (label, 0)); > > > > - emit_load_locked (mode, retval, mem); > > + emit_load_locked (mode, retval, mem, const0_rtx); > > > > x = val; > > if (mask) > > @@ -17216,7 +17217,7 @@ rs6000_expand_atomic_op (enum rtx_code > > code, rtx mem, rtx val, > > if (before == NULL_RTX) > > before = gen_reg_rtx (mode); > > > > - emit_load_locked (mode, before, mem); > > + emit_load_locked (mode, before, mem, const0_rtx); > > > > if (code == NOT) > > { > > diff --git a/gcc/config/rs6000/sync.md b/gcc/config/rs6000/sync.md > > index a4e8344ef11..7087daf7e4c 100644 > > --- a/gcc/config/rs6000/sync.md > > +++ b/gcc/config/rs6000/sync.md > > @@ -278,17 +278,19 @@ (define_mode_iterator ATOMIC [(QI > > "TARGET_SYNC_HI_QI") > > (define_insn "load_locked<mode>" > > [(set (match_operand:ATOMIC 0 "int_reg_operand" "=r") > > (unspec_volatile:ATOMIC > > - [(match_operand:ATOMIC 1 "memory_operand" "Z")] > > UNSPECV_LL))] > > + [(match_operand:ATOMIC 1 "memory_operand" "Z") > > + (match_operand:QI 2 "u1bit_cint_operand" "n")] > > UNSPECV_LL))] > > "" > > - "<larx> %0,%y1" > > + "<larx> %0,%y1,%2" > > [(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")] > > UNSPECV_LL))] > > + [(match_operand:QHI 1 "memory_operand" "Z") > > + (match_operand:QI 2 "u1bit_cint_operand" "n")] > > UNSPECV_LL))] > > "TARGET_SYNC_HI_QI" > > - "<QHI:larx> %0,%y1" > > + "<QHI:larx> %0,%y1,%2" > > [(set_attr "type" "load_l")]) > > > > ;; Use PTImode to get even/odd register pairs. > > @@ -302,7 +304,8 @@ (define_insn "load_locked<QHI:mode>_si" > > > > (define_expand "load_lockedti" > > [(use (match_operand:TI 0 "quad_int_reg_operand")) > > - (use (match_operand:TI 1 "memory_operand"))] > > + (use (match_operand:TI 1 "memory_operand")) > > + (use (match_operand:QI 2 "u1bit_cint_operand"))] > > "TARGET_SYNC_TI" > > { > > rtx op0 = operands[0]; > > @@ -316,7 +319,7 @@ (define_expand "load_lockedti" > > operands[1] = op1 = change_address (op1, TImode, new_addr); > > } > > > > - emit_insn (gen_load_lockedpti (pti, op1)); > > + emit_insn (gen_load_lockedpti (pti, op1, operands[2])); > > if (WORDS_BIG_ENDIAN) > > emit_move_insn (op0, gen_lowpart (TImode, pti)); > > else > > @@ -330,11 +333,12 @@ (define_expand "load_lockedti" > > (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")] > > UNSPECV_LL))] > > + [(match_operand:TI 1 "indexed_or_indirect_operand" "Z") > > + (match_operand:QI 2 "u1bit_cint_operand" "n")] > > UNSPECV_LL))] > > "TARGET_SYNC_TI > > && !reg_mentioned_p (operands[0], operands[1]) > > && quad_int_reg_operand (operands[0], PTImode)" > > - "lqarx %0,%y1" > > + "lqarx %0,%y1,%2" > > [(set_attr "type" "load_l") > > (set_attr "size" "128")]) > > > > @@ -411,7 +415,22 @@ (define_expand "atomic_compare_and_swap<mode>" > > (match_operand:SI 7 "const_int_operand")] ;; model > > fail > > "" > > { > > - rs6000_expand_atomic_compare_and_swap (operands); > > + 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); > > DONE; > > }) > > > > diff --git a/gcc/testsuite/gcc.target/powerpc/acmp-tst-32bit.c > > b/gcc/testsuite/gcc.target/powerpc/acmp-tst-32bit.c > > For both of the tests, could you add some tests where the EH field is > 1 > and not 0? And then check explicitly whether the expected 0 or 1 for > EH is generated. Actually I'm a bit confused here. Are you referring to the 4th argument? Actually that is for "bool weak" parameter same as __atomic_compare_exchange. It has no influence on this particular builtin as of now, and just added to keep the signatures of the new builtin same as the generic __atomic_compare_exchange. Thanks and regards, Avinash Jayakar > > > new file mode 100644 > > index 00000000000..d73951955a3 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/powerpc/acmp-tst-32bit.c > > @@ -0,0 +1,62 @@ > > +/* { dg-do compile } */ > > +/* { dg-require-effective-target ilp32 } */ > > +/* { dg-options "-O2" } */ > > + > > +bool > > +word_exchange_qi (signed char *ptr, signed char *expected, signed > > char *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_uqi (unsigned char *ptr, unsigned char *expected, > > + unsigned char *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_hi (short *ptr, short *expected, short *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_shi (signed short *ptr, signed short *expected, > > + signed short *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_uhi (unsigned short *ptr, unsigned short *expected, > > + unsigned short *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_si (int *ptr, int *expected, int *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_ssi (signed int *ptr, signed int *expected, signed > > int *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_usi (unsigned int *ptr, unsigned int *expected, > > + unsigned int *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > + > > +/* { 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 } } */ > > diff --git a/gcc/testsuite/gcc.target/powerpc/acmp-tst.c > > b/gcc/testsuite/gcc.target/powerpc/acmp-tst.c > > new file mode 100644 > > index 00000000000..e68681d5795 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.target/powerpc/acmp-tst.c > > @@ -0,0 +1,174 @@ > > +/* { dg-do compile } */ > > +/* { dg-require-effective-target lp64 } */ > > +/* { dg-options "-O2" } */ > > + > > +typedef struct udt_1 > > +{ > > + char *a; > > +} udt_1t; > > +typedef struct udt_2 > > +{ > > + char a; > > + char b; > > +} udt_2t; > > +typedef struct udt_4 > > +{ > > + short a; > > + short b; > > +} udt_4t; > > +typedef struct udt_8 > > +{ > > + int a; > > + int b; > > +} udt_8t; > > +typedef struct udt_16 > > +{ > > + long long a; > > + long long b; > > +} udt_16t; > > +bool > > +word_exchange_nqi (char *ptr, char *expected, char *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_qi (signed char *ptr, signed char *expected, signed > > char *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_uqi (unsigned char *ptr, unsigned char *expected, > > + unsigned char *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_hi (short *ptr, short *expected, short *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_shi (signed short *ptr, signed short *expected, > > + signed short *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_uhi (unsigned short *ptr, unsigned short *expected, > > + unsigned short *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_si (int *ptr, int *expected, int *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_ssi (signed int *ptr, signed int *expected, signed > > int *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_usi (unsigned int *ptr, unsigned int *expected, > > + unsigned int *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_di (long long *ptr, long long *expected, long long > > *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_sdi (signed long long *ptr, signed long long > > *expected, > > + signed long long *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_udi (unsigned long long *ptr, unsigned long long > > *expected, > > + unsigned long long *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_sti (signed __int128 *ptr, signed __int128 > > *expected, > > + signed __int128 *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_uti (unsigned __int128 *ptr, unsigned __int128 > > *expected, > > + unsigned __int128 *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_f32 (float *ptr, float *expected, float *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_f64 (double *ptr, double *expected, double *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_f128 (__ieee128 *ptr, __ieee128 *expected, __ieee128 > > *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_udt_1 (udt_1t *ptr, udt_1t *expected, udt_1t > > *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_udt_2 (udt_2t *ptr, udt_2t *expected, udt_2t > > *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_udt_4 (udt_4t *ptr, udt_4t *expected, udt_4t > > *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_udt_8 (udt_8t *ptr, udt_8t *expected, udt_8t > > *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > +bool > > +word_exchange_udt_16 (udt_16t *ptr, udt_16t *expected, udt_16t > > *desired) > > +{ > > + return __builtin_ppc_atomic_cas_local (ptr, expected, desired, > > 0, > > + __ATOMIC_SEQ_CST, > > __ATOMIC_ACQUIRE); > > +} > > + > > +/* { dg-final { scan-assembler-times {\mlbarx +[0-9]+,[0-9]+,[0- > > 9]+,1} 3 } } */ > > +/* { dg-final { scan-assembler-times {\mlharx +[0-9]+,[0-9]+,[0- > > 9]+,1} 4 } } */ > > +/* { dg-final { scan-assembler-times {\mlwarx +[0-9]+,[0-9]+,[0- > > 9]+,1} 5 } } */ > > +/* { dg-final { scan-assembler-times {\mldarx +[0-9]+,[0-9]+,[0- > > 9]+,1} 6 } } */ > > +/* { dg-final { scan-assembler-times {\mlqarx +[0-9]+,[0-9]+,[0- > > 9]+,1} 4 } } */ > > -- > > 2.52.0 > >
