Author: Erich Keane Date: 2026-02-25T06:04:58-08:00 New Revision: 6a28a663fb3a473ed256ff119dad9d76ff5dad47
URL: https://github.com/llvm/llvm-project/commit/6a28a663fb3a473ed256ff119dad9d76ff5dad47 DIFF: https://github.com/llvm/llvm-project/commit/6a28a663fb3a473ed256ff119dad9d76ff5dad47.diff LOG: [CIR] Implement compare exchange with dynamic failure ordering (#183110) In #156253, we implemented the rest of this feature, with compile time constant failure ordering. This patch follows the incubators direction (with a little cleanup based on other cleanup that we do) to replace this situation with a 'switch'. Added: Modified: clang/lib/CIR/CodeGen/CIRGenAtomic.cpp clang/test/CIR/CodeGen/atomic.c Removed: ################################################################################ diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp index a9893f83be222..c2d1a031a7e53 100644 --- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp @@ -394,9 +394,53 @@ static void emitAtomicCmpXchgFailureSet(CIRGenFunction &cgf, AtomicExpr *e, return; } - assert(!cir::MissingFeatures::atomicExpr()); - cgf.cgm.errorNYI(e->getSourceRange(), - "emitAtomicCmpXchgFailureSet: non-constant failure order"); + // The failure memory order is not a compile time constant. The CIR atomic ops + // require a constant value, so that memory order is known at compile time. In + // this case, we can switch based on the memory order and call each variant + // individually. + mlir::Value failureOrderVal = cgf.emitScalarExpr(failureOrderExpr); + mlir::Location atomicLoc = cgf.getLoc(e->getSourceRange()); + cir::SwitchOp::create( + cgf.getBuilder(), atomicLoc, failureOrderVal, + [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) { + mlir::Block *switchBlock = cgf.getBuilder().getBlock(); + + // case cir::MemOrder::Relaxed: + // // 31.7.2.18: "The failure argument shall not be + // memory_order_release + // // nor memory_order_acq_rel". Fallback to monotonic. + // case cir::MemOrder::Release: + // case cir::MemOrder::AcquireRelease: + // Note: Since there are 3 options, this makes sense to just emit as a + // 'default', which prevents user code from 'falling off' of this, + // which seems reasonable. Also, 'relaxed' being the default behavior + // is also probably the least harmful. + emitMemOrderDefaultCaseLabel(cgf.getBuilder(), atomicLoc); + emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size, + successOrder, cir::MemOrder::Relaxed, scope); + cgf.getBuilder().createBreak(atomicLoc); + cgf.getBuilder().setInsertionPointToEnd(switchBlock); + + // case cir::MemOrder::Consume: + // case cir::MemOrder::Acquire: + emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(), + {cir::MemOrder::Consume, cir::MemOrder::Acquire}); + emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size, + successOrder, cir::MemOrder::Acquire, scope); + cgf.getBuilder().createBreak(atomicLoc); + cgf.getBuilder().setInsertionPointToEnd(switchBlock); + + // case cir::MemOrder::SequentiallyConsistent: + emitMemOrderCaseLabel(cgf.getBuilder(), loc, failureOrderVal.getType(), + {cir::MemOrder::SequentiallyConsistent}); + emitAtomicCmpXchg(cgf, e, isWeak, dest, ptr, val1, val2, size, + successOrder, cir::MemOrder::SequentiallyConsistent, + scope); + cgf.getBuilder().createBreak(atomicLoc); + cgf.getBuilder().setInsertionPointToEnd(switchBlock); + + cgf.getBuilder().createYield(atomicLoc); + }); } static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c index 6f042b06e3b53..ce3f62eaa871c 100644 --- a/clang/test/CIR/CodeGen/atomic.c +++ b/clang/test/CIR/CodeGen/atomic.c @@ -257,10 +257,11 @@ void c11_store(_Atomic(int) *ptr, int x) { // OGCG: store atomic i32 %{{.+}}, ptr %{{.+}} seq_cst, align 4 // OGCG: } -void c11_atomic_cmpxchg_strong(_Atomic(int) *ptr, int *expected, int desired) { +void c11_atomic_cmpxchg_strong(_Atomic(int) *ptr, int *expected, int desired, int failure) { // CIR-LABEL: @c11_atomic_cmpxchg_strong // LLVM-LABEL: @c11_atomic_cmpxchg_strong // OGCG-LABEL: @c11_atomic_cmpxchg_strong + // CIR: %[[FAILURE:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["failure", init] __c11_atomic_compare_exchange_strong(ptr, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE); @@ -293,12 +294,56 @@ void c11_atomic_cmpxchg_strong(_Atomic(int) *ptr, int *expected, int desired) { // OGCG: [[LABEL_CONT]]: // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8 // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1 + + __c11_atomic_compare_exchange_strong(ptr, expected, desired, + __ATOMIC_SEQ_CST, failure); + // CIR: %[[FAIL_LOAD:.*]] = cir.load{{.*}}%[[FAILURE]] + // CIR: cir.switch(%[[FAIL_LOAD]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(relaxed) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(seq_cst) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + + // LLVM: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // LLVM-NEXT: i32 1, label %[[ACQ:.*]] + // LLVM-NEXT: i32 2, label %[[ACQ]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST:.*]] + // LLVM-NEXT: ] + // LLVM: [[DEF]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // LLVM: [[ACQ]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // LLVM: [[SEQ_CST]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + + // OGCG: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // OGCG-NEXT: i32 1, label %[[ACQ:.*]] + // OGCG-NEXT: i32 2, label %[[ACQ]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST:.*]] + // OGCG-NEXT: ] + // OGCG: [[DEF]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // OGCG: [[ACQ]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // OGCG: [[SEQ_CST]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst } -void c11_atomic_cmpxchg_weak(_Atomic(int) *ptr, int *expected, int desired) { +void c11_atomic_cmpxchg_weak(_Atomic(int) *ptr, int *expected, int desired, int failure) { // CIR-LABEL: @c11_atomic_cmpxchg_weak // LLVM-LABEL: @c11_atomic_cmpxchg_weak // OGCG-LABEL: @c11_atomic_cmpxchg_weak + // CIR: %[[FAILURE:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["failure", init] __c11_atomic_compare_exchange_weak(ptr, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE); @@ -331,12 +376,56 @@ void c11_atomic_cmpxchg_weak(_Atomic(int) *ptr, int *expected, int desired) { // OGCG: [[LABEL_CONT]]: // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8 // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1 + + __c11_atomic_compare_exchange_weak(ptr, expected, desired, + __ATOMIC_SEQ_CST, failure); + // CIR: %[[FAIL_LOAD:.*]] = cir.load{{.*}}%[[FAILURE]] + // CIR: cir.switch(%[[FAIL_LOAD]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(relaxed) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(seq_cst) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + + // LLVM: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // LLVM-NEXT: i32 1, label %[[ACQ:.*]] + // LLVM-NEXT: i32 2, label %[[ACQ]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST:.*]] + // LLVM-NEXT: ] + // LLVM: [[DEF]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // LLVM: [[ACQ]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // LLVM: [[SEQ_CST]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + + // OGCG: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // OGCG-NEXT: i32 1, label %[[ACQ:.*]] + // OGCG-NEXT: i32 2, label %[[ACQ]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST:.*]] + // OGCG-NEXT: ] + // OGCG: [[DEF]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // OGCG: [[ACQ]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // OGCG: [[SEQ_CST]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst } -void atomic_cmpxchg(int *ptr, int *expected, int *desired) { +void atomic_cmpxchg(int *ptr, int *expected, int *desired, int failure) { // CIR-LABEL: @atomic_cmpxchg // LLVM-LABEL: @atomic_cmpxchg // OGCG-LABEL: @atomic_cmpxchg + // CIR: %[[FAILURE:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["failure", init] __atomic_compare_exchange(ptr, expected, desired, /*weak=*/0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE); // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) @@ -399,12 +488,96 @@ void atomic_cmpxchg(int *ptr, int *expected, int *desired) { // OGCG: [[LABEL_CONT]]: // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8 // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1 + + __atomic_compare_exchange(ptr, expected, desired, /*weak=*/0, __ATOMIC_SEQ_CST, failure); + // CIR: %[[FAIL_LOAD:.*]] = cir.load{{.*}}%[[FAILURE]] + // CIR: cir.switch(%[[FAIL_LOAD]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(relaxed) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(seq_cst) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + + // LLVM: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // LLVM-NEXT: i32 1, label %[[ACQ:.*]] + // LLVM-NEXT: i32 2, label %[[ACQ]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST:.*]] + // LLVM-NEXT: ] + // LLVM: [[DEF]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // LLVM: [[ACQ]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // LLVM: [[SEQ_CST]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + + // OGCG: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // OGCG-NEXT: i32 1, label %[[ACQ:.*]] + // OGCG-NEXT: i32 2, label %[[ACQ]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST:.*]] + // OGCG-NEXT: ] + // OGCG: [[DEF]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // OGCG: [[ACQ]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // OGCG: [[SEQ_CST]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + __atomic_compare_exchange(ptr, expected, desired, /*weak=*/1, __ATOMIC_SEQ_CST, failure); + // CIR: %[[FAIL_LOAD:.*]] = cir.load{{.*}}%[[FAILURE]] + // CIR: cir.switch(%[[FAIL_LOAD]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(relaxed) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(seq_cst) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + + // LLVM: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // LLVM-NEXT: i32 1, label %[[ACQ:.*]] + // LLVM-NEXT: i32 2, label %[[ACQ]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST:.*]] + // LLVM-NEXT: ] + // LLVM: [[DEF]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // LLVM: [[ACQ]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // LLVM: [[SEQ_CST]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + + // OGCG: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // OGCG-NEXT: i32 1, label %[[ACQ:.*]] + // OGCG-NEXT: i32 2, label %[[ACQ]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST:.*]] + // OGCG-NEXT: ] + // OGCG: [[DEF]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // OGCG: [[ACQ]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // OGCG: [[SEQ_CST]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst } -void atomic_cmpxchg_n(int *ptr, int *expected, int desired) { +void atomic_cmpxchg_n(int *ptr, int *expected, int desired, int failure) { // CIR-LABEL: @atomic_cmpxchg_n // LLVM-LABEL: @atomic_cmpxchg_n // OGCG-LABEL: @atomic_cmpxchg_n + // CIR: %[[FAILURE:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["failure", init] __atomic_compare_exchange_n(ptr, expected, desired, /*weak=*/0, __ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE); // CIR: %[[OLD:.+]], %[[SUCCESS:.+]] = cir.atomic.cmpxchg success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) @@ -467,6 +640,89 @@ void atomic_cmpxchg_n(int *ptr, int *expected, int desired) { // OGCG: [[LABEL_CONT]]: // OGCG-NEXT: %[[SUCCESS_2:.+]] = zext i1 %[[SUCCESS]] to i8 // OGCG-NEXT: store i8 %[[SUCCESS_2]], ptr %{{.+}}, align 1 + + __atomic_compare_exchange_n(ptr, expected, desired, /*weak=*/0, __ATOMIC_SEQ_CST, failure); + // CIR: %[[FAIL_LOAD:.*]] = cir.load{{.*}}%[[FAILURE]] + // CIR: cir.switch(%[[FAIL_LOAD]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(relaxed) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.cmpxchg success(seq_cst) failure(seq_cst) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + + // LLVM: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // LLVM-NEXT: i32 1, label %[[ACQ:.*]] + // LLVM-NEXT: i32 2, label %[[ACQ]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST:.*]] + // LLVM-NEXT: ] + // LLVM: [[DEF]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // LLVM: [[ACQ]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // LLVM: [[SEQ_CST]]: + // LLVM: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + + // OGCG: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // OGCG-NEXT: i32 1, label %[[ACQ:.*]] + // OGCG-NEXT: i32 2, label %[[ACQ]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST:.*]] + // OGCG-NEXT: ] + // OGCG: [[DEF]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // OGCG: [[ACQ]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // OGCG: [[SEQ_CST]]: + // OGCG: cmpxchg ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + __atomic_compare_exchange_n(ptr, expected, desired, /*weak=*/1, __ATOMIC_SEQ_CST, failure); + // CIR: %[[FAIL_LOAD:.*]] = cir.load{{.*}}%[[FAILURE]] + // CIR: cir.switch(%[[FAIL_LOAD]] : !s32i) { + // CIR-NEXT: cir.case(default, []) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(relaxed) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR: } + // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.cmpxchg weak success(seq_cst) failure(seq_cst) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} align(4) : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool) + // CIR: cir.break + // CIR-NEXT: } + // CIR-NEXT: cir.yield + // CIR-NEXT: } + + // LLVM: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // LLVM-NEXT: i32 1, label %[[ACQ:.*]] + // LLVM-NEXT: i32 2, label %[[ACQ]] + // LLVM-NEXT: i32 5, label %[[SEQ_CST:.*]] + // LLVM-NEXT: ] + // LLVM: [[DEF]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // LLVM: [[ACQ]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // LLVM: [[SEQ_CST]]: + // LLVM: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst + + // OGCG: switch i32 %{{.*}}, label %[[DEF:.*]] [ + // OGCG-NEXT: i32 1, label %[[ACQ:.*]] + // OGCG-NEXT: i32 2, label %[[ACQ]] + // OGCG-NEXT: i32 5, label %[[SEQ_CST:.*]] + // OGCG-NEXT: ] + // OGCG: [[DEF]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst monotonic + // OGCG: [[ACQ]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst acquire + // OGCG: [[SEQ_CST]]: + // OGCG: cmpxchg weak ptr %{{.+}}, i32 %{{.+}}, i32 %{{.+}} seq_cst seq_cst } void c11_atomic_exchange(_Atomic(int) *ptr, int value) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
