https://github.com/Luhaocong created https://github.com/llvm/llvm-project/pull/172455
- Support CIR codegen for follow atomic fence builtin when the memory order is non constant: `__atomic_thread_fence` `__atomic_signal_fence` `__c11_atomic_thread_fence` `__c11_atomic_signal_fence` - Refactor current implementation when the memory order is constant, the argument expression at AST is evaluated as a constant directly. - Add test cases that cover all kinds of memory order. >From 7e4702431800316320edf41733dd11fe8a22ab7b Mon Sep 17 00:00:00 2001 From: Haocong Lu <[email protected]> Date: Tue, 16 Dec 2025 16:15:50 +0800 Subject: [PATCH] [CIR] Support codegen for atomic fence builtin with non-const memory order - Support CIR codegen for follow atomic fence builtin when the memory order is non constant: `__atomic_thread_fence` `__atomic_signal_fence` `__c11_atomic_thread_fence` `__c11_atomic_signal_fence` - Refactor current implementation when the memory order is constant, the argument expression at AST is evaluated as a constant directly. - Add test cases that cover all kinds of memory order. --- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 102 ++++- clang/test/CIR/CodeGen/atomic-thread-fence.c | 424 +++++++++++++++++++ 2 files changed, 506 insertions(+), 20 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index b4f02c97f539a..4f732bbb4750c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -63,25 +63,87 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e, static void emitAtomicFenceOp(CIRGenFunction &cgf, const CallExpr *expr, cir::SyncScopeKind syncScope) { CIRGenBuilderTy &builder = cgf.getBuilder(); - mlir::Value orderingVal = cgf.emitScalarExpr(expr->getArg(0)); - - auto constOrdering = orderingVal.getDefiningOp<cir::ConstantOp>(); - - if (!constOrdering) { - // TODO(cir): Emit code to switch on `orderingVal`, - // and creating the fence op for valid values. - cgf.cgm.errorNYI("Variable atomic fence ordering"); + mlir::Location loc = cgf.getLoc(expr->getSourceRange()); + + // Convert the memory order specified by user to effective one: + // Relaxed -> std::nullopt + // Consume/Acquire -> Acquire + // Release -> Release + // AcquireRelease -> AcquireRelease + // SequentiallyConsistent -> SequentiallyConsistent + auto getEffectiveMemOrder = + [](cir::MemOrder oriOrder) -> std::optional<cir::MemOrder> { + if (oriOrder == cir::MemOrder::Relaxed) + return std::nullopt; + else if (oriOrder == cir::MemOrder::Consume || + oriOrder == cir::MemOrder::Acquire) + return cir::MemOrder::Acquire; + else + return oriOrder; + }; + + // Handle constant memory ordering. + Expr::EvalResult eval; + if (expr->getArg(0)->EvaluateAsInt(eval, cgf.getContext())) { + uint64_t constOrder = eval.Val.getInt().getZExtValue(); + // Not emit anything if it's an invalid constant. + if (!cir::isValidCIRAtomicOrderingCABI(constOrder)) + return; + cir::MemOrder caseOrder = static_cast<cir::MemOrder>(constOrder); + if (std::optional<cir::MemOrder> order = getEffectiveMemOrder(caseOrder)) + cir::AtomicFenceOp::create( + builder, loc, order.value(), + cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope)); return; } - auto constOrderingAttr = constOrdering.getValueAttr<cir::IntAttr>(); - assert(constOrderingAttr && "Expected integer constant for ordering"); - - auto ordering = static_cast<cir::MemOrder>(constOrderingAttr.getUInt()); - - cir::AtomicFenceOp::create( - builder, cgf.getLoc(expr->getSourceRange()), ordering, - cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope)); + // Otherwise, handle variable memory ordering. Emit `SwitchOp` to convert + // dynamic value to static value. + mlir::Value varOrder = cgf.emitScalarExpr(expr->getArg(0)); + cir::SwitchOp::create( + builder, loc, varOrder, + [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) { + mlir::Block *switchBlock = builder.getBlock(); + + auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) { + if (caseOrders.empty()) { + // Creating default case operation + mlir::OpBuilder::InsertPoint insertPoint; + cir::CaseOp::create(builder, loc, builder.getArrayAttr({}), + cir::CaseOpKind::Default, insertPoint); + builder.restoreInsertionPoint(insertPoint); + } else if (auto actualOrder = getEffectiveMemOrder(caseOrders[0])) { + // Creating case operation for effective memory order + mlir::OpBuilder::InsertPoint insertPoint; + llvm::SmallVector<mlir::Attribute, 2> orderAttrs; + for (cir::MemOrder caseOrder : caseOrders) + orderAttrs.push_back(cir::IntAttr::get( + varOrder.getType(), static_cast<int>(caseOrder))); + cir::CaseOp::create(builder, loc, builder.getArrayAttr(orderAttrs), + cir::CaseOpKind::Anyof, insertPoint); + // Creating atomic fence operation + builder.restoreInsertionPoint(insertPoint); + cir::AtomicFenceOp::create( + builder, loc, actualOrder.value(), + cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope)); + } else { + // Do nothing if unneccssary (!caseOrders.empty() && !actualOrder) + return; + } + builder.createBreak(loc); + builder.setInsertionPointToEnd(switchBlock); + return; + }; + + emitMemOrderCase(/*default:*/ {}); + emitMemOrderCase({cir::MemOrder::Relaxed}); // Not effective + emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire}); + emitMemOrderCase({cir::MemOrder::Release}); + emitMemOrderCase({cir::MemOrder::AcquireRelease}); + emitMemOrderCase({cir::MemOrder::SequentiallyConsistent}); + + builder.createYield(loc); + }); } namespace { @@ -1007,16 +1069,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, case Builtin::BI__atomic_test_and_set: case Builtin::BI__atomic_clear: return errorBuiltinNYI(*this, e, builtinID); - case Builtin::BI__atomic_thread_fence: { + case Builtin::BI__atomic_thread_fence: + case Builtin::BI__c11_atomic_thread_fence: { emitAtomicFenceOp(*this, e, cir::SyncScopeKind::System); return RValue::get(nullptr); } - case Builtin::BI__atomic_signal_fence: { + case Builtin::BI__atomic_signal_fence: + case Builtin::BI__c11_atomic_signal_fence: { emitAtomicFenceOp(*this, e, cir::SyncScopeKind::SingleThread); return RValue::get(nullptr); } - case Builtin::BI__c11_atomic_thread_fence: - case Builtin::BI__c11_atomic_signal_fence: case Builtin::BI__scoped_atomic_thread_fence: case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: diff --git a/clang/test/CIR/CodeGen/atomic-thread-fence.c b/clang/test/CIR/CodeGen/atomic-thread-fence.c index f28bc6808cbfa..69298fb9cd7b0 100644 --- a/clang/test/CIR/CodeGen/atomic-thread-fence.c +++ b/clang/test/CIR/CodeGen/atomic-thread-fence.c @@ -179,3 +179,427 @@ void loadWithSignalFence(DataPtr d) { // OGCG: %[[DATA_TEMP_LOAD]] = load ptr, ptr %[[DATA_TEMP]], align 8 // OGCG: ret void } + +void const_atomic_thread_fence() { + __atomic_thread_fence(__ATOMIC_RELAXED); + __atomic_thread_fence(__ATOMIC_CONSUME); + __atomic_thread_fence(__ATOMIC_ACQUIRE); + __atomic_thread_fence(__ATOMIC_RELEASE); + __atomic_thread_fence(__ATOMIC_ACQ_REL); + __atomic_thread_fence(__ATOMIC_SEQ_CST); + // CIR-LABEL: const_atomic_thread_fence + // CIR: cir.atomic.fence syncscope(system) acquire + // CIR: cir.atomic.fence syncscope(system) acquire + // CIR: cir.atomic.fence syncscope(system) release + // CIR: cir.atomic.fence syncscope(system) acq_rel + // CIR: cir.atomic.fence syncscope(system) seq_cst + + // LLVM-LABEL: const_atomic_thread_fence + // LLVM: fence acquire + // LLVM: fence acquire + // LLVM: fence release + // LLVM: fence acq_rel + // LLVM: fence seq_cst + + // OGCG-LABEL: const_atomic_thread_fence + // OGCG: fence acquire + // OGCG: fence acquire + // OGCG: fence release + // OGCG: fence acq_rel + // OGCG: fence seq_cst +} + +void const_c11_atomic_thread_fence() { + __c11_atomic_thread_fence(__ATOMIC_RELAXED); + __c11_atomic_thread_fence(__ATOMIC_CONSUME); + __c11_atomic_thread_fence(__ATOMIC_ACQUIRE); + __c11_atomic_thread_fence(__ATOMIC_RELEASE); + __c11_atomic_thread_fence(__ATOMIC_ACQ_REL); + __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); + // CIR-LABEL: const_c11_atomic_thread_fence + // CIR: cir.atomic.fence syncscope(system) acquire + // CIR: cir.atomic.fence syncscope(system) acquire + // CIR: cir.atomic.fence syncscope(system) release + // CIR: cir.atomic.fence syncscope(system) acq_rel + // CIR: cir.atomic.fence syncscope(system) seq_cst + + // LLVM-LABEL: const_c11_atomic_thread_fence + // LLVM: fence acquire + // LLVM: fence acquire + // LLVM: fence release + // LLVM: fence acq_rel + // LLVM: fence seq_cst + + // OGCG-LABEL: const_c11_atomic_thread_fence + // OGCG: fence acquire + // OGCG: fence acquire + // OGCG: fence release + // OGCG: fence acq_rel + // OGCG: fence seq_cst +} + +void const_atomic_signal_fence() { + __atomic_signal_fence(__ATOMIC_RELAXED); + __atomic_signal_fence(__ATOMIC_CONSUME); + __atomic_signal_fence(__ATOMIC_ACQUIRE); + __atomic_signal_fence(__ATOMIC_RELEASE); + __atomic_signal_fence(__ATOMIC_ACQ_REL); + __atomic_signal_fence(__ATOMIC_SEQ_CST); + // CIR-LABEL: const_atomic_signal_fence + // CIR: cir.atomic.fence syncscope(single_thread) acquire + // CIR: cir.atomic.fence syncscope(single_thread) acquire + // CIR: cir.atomic.fence syncscope(single_thread) release + // CIR: cir.atomic.fence syncscope(single_thread) acq_rel + // CIR: cir.atomic.fence syncscope(single_thread) seq_cst + + // LLVM-LABEL: const_atomic_signal_fence + // LLVM: fence syncscope("singlethread") acquire + // LLVM: fence syncscope("singlethread") acquire + // LLVM: fence syncscope("singlethread") release + // LLVM: fence syncscope("singlethread") acq_rel + // LLVM: fence syncscope("singlethread") seq_cst + + // OGCG--LABEL: const_atomic_signal_fence + // OGCG: fence syncscope("singlethread") acquire + // OGCG: fence syncscope("singlethread") acquire + // OGCG: fence syncscope("singlethread") release + // OGCG: fence syncscope("singlethread") acq_rel + // OGCG: fence syncscope("singlethread") seq_cst +} + +void const_c11_atomic_signal_fence() { + __c11_atomic_signal_fence(__ATOMIC_RELAXED); + __c11_atomic_signal_fence(__ATOMIC_CONSUME); + __c11_atomic_signal_fence(__ATOMIC_ACQUIRE); + __c11_atomic_signal_fence(__ATOMIC_RELEASE); + __c11_atomic_signal_fence(__ATOMIC_ACQ_REL); + __c11_atomic_signal_fence(__ATOMIC_SEQ_CST); + // CIR-LABEL: const_c11_atomic_signal_fence + // CIR: cir.atomic.fence syncscope(single_thread) acquire + // CIR: cir.atomic.fence syncscope(single_thread) acquire + // CIR: cir.atomic.fence syncscope(single_thread) release + // CIR: cir.atomic.fence syncscope(single_thread) acq_rel + // CIR: cir.atomic.fence syncscope(single_thread) seq_cst + + // LLVM-LABEL: const_c11_atomic_signal_fence + // LLVM: fence syncscope("singlethread") acquire + // LLVM: fence syncscope("singlethread") acquire + // LLVM: fence syncscope("singlethread") release + // LLVM: fence syncscope("singlethread") acq_rel + // LLVM: fence syncscope("singlethread") seq_cst + + // OGCG-LABEL: const_c11_atomic_signal_fence + // OGCG: fence syncscope("singlethread") acquire + // OGCG: fence syncscope("singlethread") acquire + // OGCG: fence syncscope("singlethread") release + // OGCG: fence syncscope("singlethread") acq_rel + // OGCG: fence syncscope("singlethread") seq_cst +} + +void variable_atomic_thread_fences(int memorder) { + __atomic_thread_fence(memorder); + // CIR-LABEL: variable_atomic_thread_fences + // CIR: cir.switch + // CIR: cir.case(default, []) { + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) acquire + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) release + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) acq_rel + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) + // CIR: cir.break + // CIR: } + // CIR: cir.yield + // CIR: } + + // LLVM-LABEL: variable_atomic_thread_fences + // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // LLVM: br label %[[SWITCH_BLK:.+]] + // LLVM: [[SWITCH_BLK]]: + // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // LLVM: i32 1, label %[[ACQUIRE_BLK:.+]] + // LLVM: i32 2, label %[[ACQUIRE_BLK]] + // LLVM: i32 3, label %[[RELEASE_BLK:.+]] + // LLVM: i32 4, label %[[ACQ_REL_BLK:.+]] + // LLVM: i32 5, label %[[SEQ_CST_BLK:.+]] + // LLVM: ] + // LLVM: [[DEFAULT_BLK]]: + // LLVM: br label %{{.+}} + // LLVM: [[ACQUIRE_BLK]]: + // LLVM: fence acquire + // LLVM: br label %{{.+}} + // LLVM: [[RELEASE_BLK]]: + // LLVM: fence release + // LLVM: br label %{{.+}} + // LLVM: [[ACQ_REL_BLK]]: + // LLVM: fence acq_rel + // LLVM: br label %{{.+}} + // LLVM: [[SEQ_CST_BLK]]: + // LLVM: fence seq_cst + // LLVM: br label %{{.+}} + + // OGCG-LABEL: variable_atomic_thread_fences + // OGCG: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // OGCG: i32 1, label %[[ACQUIRE_BLK:.+]] + // OGCG: i32 2, label %[[ACQUIRE_BLK]] + // OGCG: i32 3, label %[[RELEASE_BLK:.+]] + // OGCG: i32 4, label %[[ACQ_REL_BLK:.+]] + // OGCG: i32 5, label %[[SEQ_CST_BLK:.+]] + // OGCG: ] + // OGCG: [[ACQUIRE_BLK]]: + // OGCG: fence acquire + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[RELEASE_BLK]]: + // OGCG: fence release + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[ACQ_REL_BLK]]: + // OGCG: fence acq_rel + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[SEQ_CST_BLK]]: + // OGCG: fence seq_cst + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[DEFAULT_BLK]]: + // OGCG: ret void +} + +void variable_c11_atomic_thread_fences(int memorder) { + __c11_atomic_thread_fence(memorder); + // CIR-LABEL: variable_c11_atomic_thread_fences + // CIR: cir.switch + // CIR: cir.case(default, []) { + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) acquire + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) release + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) acq_rel + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.fence syncscope(system) + // CIR: cir.break + // CIR: } + // CIR: cir.yield + // CIR: } + + // LLVM-LABEL: variable_c11_atomic_thread_fences + // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // LLVM: br label %[[SWITCH_BLK:.+]] + // LLVM: [[SWITCH_BLK]]: + // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // LLVM: i32 1, label %[[ACQUIRE_BLK:.+]] + // LLVM: i32 2, label %[[ACQUIRE_BLK]] + // LLVM: i32 3, label %[[RELEASE_BLK:.+]] + // LLVM: i32 4, label %[[ACQ_REL_BLK:.+]] + // LLVM: i32 5, label %[[SEQ_CST_BLK:.+]] + // LLVM: ] + // LLVM: [[DEFAULT_BLK]]: + // LLVM: br label %{{.+}} + // LLVM: [[ACQUIRE_BLK]]: + // LLVM: fence acquire + // LLVM: br label %{{.+}} + // LLVM: [[RELEASE_BLK]]: + // LLVM: fence release + // LLVM: br label %{{.+}} + // LLVM: [[ACQ_REL_BLK]]: + // LLVM: fence acq_rel + // LLVM: br label %{{.+}} + // LLVM: [[SEQ_CST_BLK]]: + // LLVM: fence seq_cst + // LLVM: br label %{{.+}} + + // OGCG-LABEL: variable_c11_atomic_thread_fences + // OGCG: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // OGCG: i32 1, label %[[ACQUIRE_BLK:.+]] + // OGCG: i32 2, label %[[ACQUIRE_BLK]] + // OGCG: i32 3, label %[[RELEASE_BLK:.+]] + // OGCG: i32 4, label %[[ACQ_REL_BLK:.+]] + // OGCG: i32 5, label %[[SEQ_CST_BLK:.+]] + // OGCG: ] + // OGCG: [[ACQUIRE_BLK]]: + // OGCG: fence acquire + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[RELEASE_BLK]]: + // OGCG: fence release + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[ACQ_REL_BLK]]: + // OGCG: fence acq_rel + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[SEQ_CST_BLK]]: + // OGCG: fence seq_cst + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[DEFAULT_BLK]]: + // OGCG: ret void +} + +void variable_atomic_signal_fences(int memorder) { + __atomic_signal_fence(memorder); + // CIR-LABEL: variable_atomic_signal_fences + // CIR: cir.switch + // CIR: cir.case(default, []) { + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) acquire + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) release + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) acq_rel + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) + // CIR: cir.break + // CIR: } + // CIR: cir.yield + // CIR: } + + // LLVM-LABEL: variable_atomic_signal_fences + // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // LLVM: br label %[[SWITCH_BLK:.+]] + // LLVM: [[SWITCH_BLK]]: + // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // LLVM: i32 1, label %[[ACQUIRE_BLK:.+]] + // LLVM: i32 2, label %[[ACQUIRE_BLK]] + // LLVM: i32 3, label %[[RELEASE_BLK:.+]] + // LLVM: i32 4, label %[[ACQ_REL_BLK:.+]] + // LLVM: i32 5, label %[[SEQ_CST_BLK:.+]] + // LLVM: ] + // LLVM: [[DEFAULT_BLK]]: + // LLVM: br label %{{.+}} + // LLVM: [[ACQUIRE_BLK]]: + // LLVM: fence syncscope("singlethread") acquire + // LLVM: br label %{{.+}} + // LLVM: [[RELEASE_BLK]]: + // LLVM: fence syncscope("singlethread") release + // LLVM: br label %{{.+}} + // LLVM: [[ACQ_REL_BLK]]: + // LLVM: fence syncscope("singlethread") acq_rel + // LLVM: br label %{{.+}} + // LLVM: [[SEQ_CST_BLK]]: + // LLVM: fence syncscope("singlethread") seq_cst + // LLVM: br label %{{.+}} + + // OGCG-LABEL: variable_atomic_signal_fences + // OGCG: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // OGCG: i32 1, label %[[ACQUIRE_BLK:.+]] + // OGCG: i32 2, label %[[ACQUIRE_BLK]] + // OGCG: i32 3, label %[[RELEASE_BLK:.+]] + // OGCG: i32 4, label %[[ACQ_REL_BLK:.+]] + // OGCG: i32 5, label %[[SEQ_CST_BLK:.+]] + // OGCG: ] + // OGCG: [[ACQUIRE_BLK]]: + // OGCG: fence syncscope("singlethread") acquire + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[RELEASE_BLK]]: + // OGCG: fence syncscope("singlethread") release + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[ACQ_REL_BLK]]: + // OGCG: fence syncscope("singlethread") acq_rel + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[SEQ_CST_BLK]]: + // OGCG: fence syncscope("singlethread") seq_cst + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[DEFAULT_BLK]]: + // OGCG: ret void +} + +void variable_c11_atomic_signal_fences(int memorder) { + __c11_atomic_signal_fence(memorder); + // CIR-LABEL: variable_c11_atomic_signal_fences + // CIR: cir.switch + // CIR: cir.case(default, []) { + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) acquire + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) release + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) acq_rel + // CIR: cir.break + // CIR: } + // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) { + // CIR: cir.atomic.fence syncscope(single_thread) + // CIR: cir.break + // CIR: } + // CIR: cir.yield + // CIR: } + + // LLVM-LABEL: variable_c11_atomic_signal_fences + // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // LLVM: br label %[[SWITCH_BLK:.+]] + // LLVM: [[SWITCH_BLK]]: + // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // LLVM: i32 1, label %[[ACQUIRE_BLK:.+]] + // LLVM: i32 2, label %[[ACQUIRE_BLK]] + // LLVM: i32 3, label %[[RELEASE_BLK:.+]] + // LLVM: i32 4, label %[[ACQ_REL_BLK:.+]] + // LLVM: i32 5, label %[[SEQ_CST_BLK:.+]] + // LLVM: ] + // LLVM: [[DEFAULT_BLK]]: + // LLVM: br label %{{.+}} + // LLVM: [[ACQUIRE_BLK]]: + // LLVM: fence syncscope("singlethread") acquire + // LLVM: br label %{{.+}} + // LLVM: [[RELEASE_BLK]]: + // LLVM: fence syncscope("singlethread") release + // LLVM: br label %{{.+}} + // LLVM: [[ACQ_REL_BLK]]: + // LLVM: fence syncscope("singlethread") acq_rel + // LLVM: br label %{{.+}} + // LLVM: [[SEQ_CST_BLK]]: + // LLVM: fence syncscope("singlethread") seq_cst + // LLVM: br label %{{.+}} + + // OGCG-LABEL: variable_c11_atomic_signal_fences + // OGCG: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4 + // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [ + // OGCG: i32 1, label %[[ACQUIRE_BLK:.+]] + // OGCG: i32 2, label %[[ACQUIRE_BLK]] + // OGCG: i32 3, label %[[RELEASE_BLK:.+]] + // OGCG: i32 4, label %[[ACQ_REL_BLK:.+]] + // OGCG: i32 5, label %[[SEQ_CST_BLK:.+]] + // OGCG: ] + // OGCG: [[ACQUIRE_BLK]]: + // OGCG: fence syncscope("singlethread") acquire + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[RELEASE_BLK]]: + // OGCG: fence syncscope("singlethread") release + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[ACQ_REL_BLK]]: + // OGCG: fence syncscope("singlethread") acq_rel + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[SEQ_CST_BLK]]: + // OGCG: fence syncscope("singlethread") seq_cst + // OGCG: br label %[[DEFAULT_BLK]] + // OGCG: [[DEFAULT_BLK]]: + // OGCG: ret void +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
