llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Haocong Lu (Luhaocong)

<details>
<summary>Changes</summary>

- 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.

---

Patch is 21.71 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/172455.diff


2 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+82-20) 
- (modified) clang/test/CIR/CodeGen/atomic-thread-fence.c (+424) 


``````````diff
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:     i...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/172455
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to