https://github.com/Lancern updated 
https://github.com/llvm/llvm-project/pull/202671

>From 413e79be89ecbd53ef9e03661c10aa972d073741 Mon Sep 17 00:00:00 2001
From: Sirui Mu <[email protected]>
Date: Tue, 9 Jun 2026 22:17:50 +0800
Subject: [PATCH] [CIR] Atomic load and store via library call

This call adds support for atomic load/store operations that go through calls
to the `__atomic_load` and `__atomic_store` library functions. This could happen
when the size of the atomic type is too large or is not a power of 2.

Assisted-by: Codex / gpt-5.5 xhigh
---
 clang/lib/CIR/CodeGen/CIRGenAtomic.cpp  | 225 +++++++++++++++++++++++-
 clang/lib/CIR/CodeGen/CIRGenCall.cpp    |  12 ++
 clang/lib/CIR/CodeGen/CIRGenTypes.h     |   5 +
 clang/test/CIR/CodeGen/atomic-libcall.c | 172 ++++++++++++++++++
 4 files changed, 409 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/atomic-libcall.c

diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp 
b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 6ba6bc1c0405a..4498326376694 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -1114,6 +1114,224 @@ void CIRGenFunction::emitAtomicExprWithMemOrder(
                                     emitAtomicOpFn);
 }
 
+static RValue emitAtomicLibCall(CIRGenFunction &cgf, llvm::StringRef funcName,
+                                QualType resultType, CallArgList &args) {
+  const CIRGenFunctionInfo &fnInfo =
+      cgf.cgm.getTypes().arrangeBuiltinFunctionCall(resultType, args);
+  cir::FuncType fnTy = cgf.cgm.getTypes().getFunctionType(fnInfo);
+
+  mlir::NamedAttrList fnAttrs;
+  assert(!cir::MissingFeatures::opFuncExtraAttrs());
+
+  cir::FuncOp fn = cgf.cgm.createRuntimeFunction(fnTy, funcName, fnAttrs);
+  auto callee = CIRGenCallee::forDirect(fn);
+  return cgf.emitCall(fnInfo, callee, ReturnValueSlot(), args);
+}
+
+static RValue emitLibCallForAtomicExpr(CIRGenFunction &cgf, AtomicExpr *e,
+                                       Address atomicPtr, Address dest,
+                                       Address val1, uint64_t atomicTySize,
+                                       QualType resultTy) {
+  mlir::Location loc = cgf.getLoc(e->getSourceRange());
+
+  CallArgList args;
+  // For non-optimized library calls, the size is the first parameter.
+  args.add(
+      RValue::get(cgf.getBuilder().getConstInt(loc, cgf.sizeTy, atomicTySize)),
+      cgf.getContext().getSizeType());
+
+  // The atomic address is the second parameter.
+  // The OpenCL atomic library functions only accept pointer arguments to
+  // generic address space.
+  auto castToGenericAddrSpace = [&](mlir::Value v, QualType pt) {
+    if (!e->isOpenCL())
+      return cgf.getBuilder().createPtrBitcast(v, cgf.voidTy);
+
+    assert(!cir::MissingFeatures::openCL());
+    cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL");
+    return cgf.getBuilder().createPtrBitcast(v, cgf.voidTy);
+  };
+  args.add(RValue::get(castToGenericAddrSpace(atomicPtr.emitRawPointer(),
+                                              e->getPtr()->getType())),
+           cgf.getContext().VoidPtrTy);
+
+  // The next 1-3 parameters are op-dependent.
+  llvm::StringRef calleeName;
+  QualType retTy;
+  bool hasRetTy = false;
+  switch (e->getOp()) {
+  case AtomicExpr::AO__c11_atomic_init:
+  case AtomicExpr::AO__opencl_atomic_init:
+    llvm_unreachable("Already handled!");
+
+  // There is only one libcall for compare an exchange, because there is no
+  // optimisation benefit possible from a libcall version of a weak compare
+  // and exchange.
+  // bool __atomic_compare_exchange(size_t size, void *mem, void *expected,
+  //                                void *desired, int success, int failure)
+  case AtomicExpr::AO__atomic_compare_exchange:
+  case AtomicExpr::AO__atomic_compare_exchange_n:
+  case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+  case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+  case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
+  case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
+  case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
+  case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
+  case AtomicExpr::AO__scoped_atomic_compare_exchange:
+  case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
+    cgf.cgm.errorNYI(
+        loc, "emitLibCallForAtomicExpr: atomic compare-and-exchange NYI");
+    return RValue::get(nullptr);
+
+  // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
+  //                        int order)
+  case AtomicExpr::AO__atomic_exchange:
+  case AtomicExpr::AO__atomic_exchange_n:
+  case AtomicExpr::AO__c11_atomic_exchange:
+  case AtomicExpr::AO__hip_atomic_exchange:
+  case AtomicExpr::AO__opencl_atomic_exchange:
+  case AtomicExpr::AO__scoped_atomic_exchange:
+  case AtomicExpr::AO__scoped_atomic_exchange_n:
+    cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: atomic exchange NYI");
+    return RValue::get(nullptr);
+
+  // void __atomic_store(size_t size, void *mem, void *val, int order)
+  case AtomicExpr::AO__atomic_store:
+  case AtomicExpr::AO__atomic_store_n:
+  case AtomicExpr::AO__c11_atomic_store:
+  case AtomicExpr::AO__scoped_atomic_store:
+  case AtomicExpr::AO__scoped_atomic_store_n: {
+    calleeName = "__atomic_store";
+    retTy = cgf.getContext().VoidTy;
+    hasRetTy = true;
+    args.add(RValue::get(castToGenericAddrSpace(val1.emitRawPointer(),
+                                                e->getVal1()->getType())),
+             cgf.getContext().VoidPtrTy);
+    break;
+  }
+
+  case AtomicExpr::AO__hip_atomic_store:
+  case AtomicExpr::AO__opencl_atomic_store:
+    cgf.cgm.errorNYI(loc,
+                     "emitLibCallForAtomicExpr: atomic store for hip/opencl");
+    return RValue::get(nullptr);
+
+  // void __atomic_load(size_t size, void *mem, void *return, int order)
+  case AtomicExpr::AO__atomic_load:
+  case AtomicExpr::AO__atomic_load_n:
+  case AtomicExpr::AO__c11_atomic_load:
+  case AtomicExpr::AO__scoped_atomic_load:
+  case AtomicExpr::AO__scoped_atomic_load_n: {
+    calleeName = "__atomic_load";
+    break;
+  }
+
+  case AtomicExpr::AO__hip_atomic_load:
+  case AtomicExpr::AO__opencl_atomic_load:
+    cgf.cgm.errorNYI(loc,
+                     "emitLibCallForAtomicExpr: atomic load for hip/opencl");
+    return RValue::get(nullptr);
+
+  case AtomicExpr::AO__atomic_add_fetch:
+  case AtomicExpr::AO__scoped_atomic_add_fetch:
+  case AtomicExpr::AO__atomic_fetch_add:
+  case AtomicExpr::AO__c11_atomic_fetch_add:
+  case AtomicExpr::AO__hip_atomic_fetch_add:
+  case AtomicExpr::AO__opencl_atomic_fetch_add:
+  case AtomicExpr::AO__scoped_atomic_fetch_add:
+  case AtomicExpr::AO__atomic_and_fetch:
+  case AtomicExpr::AO__scoped_atomic_and_fetch:
+  case AtomicExpr::AO__atomic_fetch_and:
+  case AtomicExpr::AO__c11_atomic_fetch_and:
+  case AtomicExpr::AO__hip_atomic_fetch_and:
+  case AtomicExpr::AO__opencl_atomic_fetch_and:
+  case AtomicExpr::AO__scoped_atomic_fetch_and:
+  case AtomicExpr::AO__atomic_or_fetch:
+  case AtomicExpr::AO__scoped_atomic_or_fetch:
+  case AtomicExpr::AO__atomic_fetch_or:
+  case AtomicExpr::AO__c11_atomic_fetch_or:
+  case AtomicExpr::AO__hip_atomic_fetch_or:
+  case AtomicExpr::AO__opencl_atomic_fetch_or:
+  case AtomicExpr::AO__scoped_atomic_fetch_or:
+  case AtomicExpr::AO__atomic_sub_fetch:
+  case AtomicExpr::AO__scoped_atomic_sub_fetch:
+  case AtomicExpr::AO__atomic_fetch_sub:
+  case AtomicExpr::AO__c11_atomic_fetch_sub:
+  case AtomicExpr::AO__hip_atomic_fetch_sub:
+  case AtomicExpr::AO__opencl_atomic_fetch_sub:
+  case AtomicExpr::AO__scoped_atomic_fetch_sub:
+  case AtomicExpr::AO__atomic_xor_fetch:
+  case AtomicExpr::AO__scoped_atomic_xor_fetch:
+  case AtomicExpr::AO__atomic_fetch_xor:
+  case AtomicExpr::AO__c11_atomic_fetch_xor:
+  case AtomicExpr::AO__hip_atomic_fetch_xor:
+  case AtomicExpr::AO__opencl_atomic_fetch_xor:
+  case AtomicExpr::AO__scoped_atomic_fetch_xor:
+  case AtomicExpr::AO__atomic_nand_fetch:
+  case AtomicExpr::AO__atomic_fetch_nand:
+  case AtomicExpr::AO__c11_atomic_fetch_nand:
+  case AtomicExpr::AO__scoped_atomic_fetch_nand:
+  case AtomicExpr::AO__scoped_atomic_nand_fetch:
+  case AtomicExpr::AO__atomic_min_fetch:
+  case AtomicExpr::AO__atomic_fetch_min:
+  case AtomicExpr::AO__c11_atomic_fetch_min:
+  case AtomicExpr::AO__hip_atomic_fetch_min:
+  case AtomicExpr::AO__opencl_atomic_fetch_min:
+  case AtomicExpr::AO__scoped_atomic_fetch_min:
+  case AtomicExpr::AO__scoped_atomic_min_fetch:
+  case AtomicExpr::AO__atomic_max_fetch:
+  case AtomicExpr::AO__atomic_fetch_max:
+  case AtomicExpr::AO__c11_atomic_fetch_max:
+  case AtomicExpr::AO__hip_atomic_fetch_max:
+  case AtomicExpr::AO__opencl_atomic_fetch_max:
+  case AtomicExpr::AO__scoped_atomic_fetch_max:
+  case AtomicExpr::AO__scoped_atomic_max_fetch:
+  case AtomicExpr::AO__scoped_atomic_fetch_uinc:
+  case AtomicExpr::AO__scoped_atomic_fetch_udec:
+  case AtomicExpr::AO__atomic_test_and_set:
+  case AtomicExpr::AO__atomic_clear:
+  case AtomicExpr::AO__atomic_fetch_uinc:
+  case AtomicExpr::AO__atomic_fetch_udec:
+    llvm_unreachable("Integral atomic operations always become atomicrmw!");
+  }
+
+  if (e->isOpenCL()) {
+    assert(!cir::MissingFeatures::openCL());
+    cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL");
+    return RValue::get(nullptr);
+  }
+
+  // By default, assume we return a value of the atomic type.
+  if (!hasRetTy) {
+    // Value is returned through parameter before the order.
+    retTy = cgf.getContext().VoidTy;
+    args.add(RValue::get(castToGenericAddrSpace(dest.emitRawPointer(), retTy)),
+             cgf.getContext().VoidPtrTy);
+  }
+
+  // Order is always the last parameter.
+  args.add(RValue::get(cgf.emitScalarExpr(e->getOrder())),
+           cgf.getContext().IntTy);
+  if (e->isOpenCL()) {
+    assert(!cir::MissingFeatures::openCL());
+    cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL");
+    return RValue::get(nullptr);
+  }
+
+  RValue res = emitAtomicLibCall(cgf, calleeName, retTy, args);
+
+  // The value is returned directly from the libcall.
+  if (e->isCmpXChg())
+    return res;
+
+  if (resultTy->isVoidType())
+    return RValue::get(nullptr);
+
+  return cgf.convertTempToRValue(
+      dest.withElementType(cgf.getBuilder(), cgf.convertTypeForMem(resultTy)),
+      resultTy, e->getExprLoc());
+}
+
 RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
   QualType atomicTy = e->getPtr()->getType()->getPointeeType();
   QualType memTy = atomicTy;
@@ -1324,11 +1542,8 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
   // the size-optimized libcall variants, which are only valid up to 16 bytes.)
   //
   // See: https://llvm.org/docs/Atomics.html#libcalls-atomic
-  if (useLibCall) {
-    assert(!cir::MissingFeatures::atomicUseLibCall());
-    cgm.errorNYI(e->getSourceRange(), "emitAtomicExpr: emit atomic lib call");
-    return RValue::get(nullptr);
-  }
+  if (useLibCall)
+    return emitLibCallForAtomicExpr(*this, e, ptr, dest, val1, size, resultTy);
 
   bool isStore = e->getOp() == AtomicExpr::AO__c11_atomic_store ||
                  e->getOp() == AtomicExpr::AO__opencl_atomic_store ||
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index f648eff375a77..c3065c8917924 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -1016,6 +1016,18 @@ CIRGenTypes::arrangeFreeFunctionCall(const CallArgList 
&args,
   return arrangeFreeFunctionLikeCall(*this, cgm, args, fnType);
 }
 
+const CIRGenFunctionInfo &
+CIRGenTypes::arrangeBuiltinFunctionCall(QualType resultType,
+                                        const CallArgList &args) {
+  llvm::SmallVector<CanQualType, 16> argTypes;
+  for (const CallArg &arg : args)
+    argTypes.push_back(astContext.getCanonicalParamType(arg.ty));
+
+  CanQualType retType = resultType->getCanonicalTypeUnqualified();
+  return arrangeCIRFunctionInfo(retType, /*isInstanceMethod=*/false, argTypes,
+                                FunctionType::ExtInfo(), RequiredArgs::All);
+}
+
 /// Arrange the argument and result information for a declaration or definition
 /// of the given C++ non-static member function. The member function must be an
 /// ordinary function, i.e. not a constructor or destructor.
diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h 
b/clang/lib/CIR/CodeGen/CIRGenTypes.h
index 15955c517f1f3..a7827f76bd5f2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenTypes.h
+++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h
@@ -186,6 +186,11 @@ class CIRGenTypes {
   const CIRGenFunctionInfo &
   arrangeFunctionDeclaration(const clang::FunctionDecl *fd);
 
+  /// A builtin function is a freestanding function using the default
+  /// C conventions.
+  const CIRGenFunctionInfo &arrangeBuiltinFunctionCall(QualType resultType,
+                                                       const CallArgList 
&args);
+
   /// Return whether a type can be zero-initialized (in the C++ sense) with an
   /// LLVM zeroinitializer.
   bool isZeroInitializable(clang::QualType ty);
diff --git a/clang/test/CIR/CodeGen/atomic-libcall.c 
b/clang/test/CIR/CodeGen/atomic-libcall.c
new file mode 100644
index 0000000000000..4518dd5e24dda
--- /dev/null
+++ b/clang/test/CIR/CodeGen/atomic-libcall.c
@@ -0,0 +1,172 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value 
-emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
+
+struct Big {
+  int x[6];
+};
+
+void load(struct Big *ptr) {
+  // CIR-LABEL: @load
+  // LLVM-LABEL: @load
+  // OGCG-LABEL: @load
+
+  struct Big b;
+  __atomic_load(ptr, &b, __ATOMIC_RELAXED);
+  // CIR:      %[[DEST_SLOT:.+]] = cir.alloca "b" align(4) : !cir.ptr<!rec_Big>
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_SLOT]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i
+  // CIR-NEXT: %[[PTR_VOIDPTR:.+]] = cir.cast bitcast %[[PTR_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: cir.call @__atomic_load(%[[SIZE]], %[[PTR_VOIDPTR]], 
%[[DEST_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[DEST:.+]] = alloca %struct.Big, i64 1, align 4
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], 
ptr noundef %[[DEST]], i32 noundef 0)
+
+  // OGCG:      %[[DEST:.+]] = alloca %struct.Big, align 4
+  // OGCG:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], 
ptr noundef %[[DEST]], i32 noundef 0)
+}
+
+void scoped_load(struct Big *ptr) {
+  // CIR-LABEL: @scoped_load
+  // LLVM-LABEL: @scoped_load
+  // OGCG-LABEL: @scoped_load
+
+  struct Big b;
+  __scoped_atomic_load(ptr, &b, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
+  // CIR:      %[[DEST_SLOT:.+]] = cir.alloca "b" align(4) : !cir.ptr<!rec_Big>
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_SLOT]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i
+  // CIR-NEXT: %[[PTR_VOIDPTR:.+]] = cir.cast bitcast %[[PTR_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: cir.call @__atomic_load(%[[SIZE]], %[[PTR_VOIDPTR]], 
%[[DEST_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[DEST:.+]] = alloca %struct.Big, i64 1, align 4
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], 
ptr noundef %[[DEST]], i32 noundef 0)
+
+  // OGCG:      %[[DEST:.+]] = alloca %struct.Big, align 4
+  // OGCG:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], 
ptr noundef %[[DEST]], i32 noundef 0)
+}
+
+void c11_load(_Atomic(struct Big) *ptr) {
+  // CIR-LABEL: @c11_load
+  // LLVM-LABEL: @c11_load
+  // OGCG-LABEL: @c11_load
+
+  struct Big b = __c11_atomic_load(ptr, __ATOMIC_RELAXED);
+  // CIR:      %[[DEST_SLOT:.+]] = cir.alloca "b" align(4) init : 
!cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[TEMP_SLOT:.+]] = cir.alloca "atomic-temp" align(4) : 
!cir.ptr<!rec_Big>
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[TEMP_INTPTR:.+]] = cir.cast bitcast %[[TEMP_SLOT]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i
+  // CIR-NEXT: %[[PTR_VOIDPTR:.+]] = cir.cast bitcast %[[PTR_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[TEMP_VOIDPTR:.+]] = cir.cast bitcast %[[TEMP_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: cir.call @__atomic_load(%[[SIZE]], %[[PTR_VOIDPTR]], 
%[[TEMP_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> ()
+  // CIR-NEXT: %[[TEMP_CAST:.+]] = cir.cast bitcast %[[TEMP_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!rec_Big>
+  // CIR-NEXT: cir.copy %[[TEMP_CAST]] to %[[DEST_SLOT]] : !cir.ptr<!rec_Big>
+
+  // LLVM:      %[[DEST_SLOT:.+]] = alloca %struct.Big, i64 1, align 4
+  // LLVM-NEXT: %[[TEMP_SLOT:.+]] = alloca %struct.Big, i64 1, align 4
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], 
ptr noundef %[[TEMP_SLOT]], i32 noundef 0)
+  // LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %[[DEST_SLOT]], ptr 
%[[TEMP_SLOT]], i64 24, i1 false)
+
+  // OGCG:      %[[DEST_SLOT:.+]] = alloca %struct.Big, align 4
+  // OGCG-NEXT: %[[TEMP_SLOT:.+]] = alloca %struct.Big, align 4
+  // OGCG:      %[[PTR:.+]] = load ptr, ptr %ptr.addr, align 8
+  // OGCG-NEXT: call void @__atomic_load(i64 noundef 24, ptr noundef %[[PTR]], 
ptr noundef %[[TEMP_SLOT]], i32 noundef 0)
+  // OGCG-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[DEST_SLOT]], 
ptr align 4 %[[TEMP_SLOT]], i64 24, i1 false)
+}
+
+void store(struct Big *dest, struct Big *val) {
+  // CIR-LABEL: @store
+  // LLVM-LABEL: @store
+  // OGCG-LABEL: @store
+
+  __atomic_store(dest, val, __ATOMIC_RELAXED);
+  // CIR:      %[[DEST_PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[VALUE_PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[VALUE_PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i
+  // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: cir.call @__atomic_store(%[[SIZE]], %[[DEST_VOIDPTR]], 
%[[VALUE_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef 
%[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0)
+
+  // OGCG:      %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef 
%[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0)
+}
+
+void scoped_store(struct Big *dest, struct Big *val) {
+  // CIR-LABEL: @scoped_store
+  // LLVM-LABEL: @scoped_store
+  // OGCG-LABEL: @scoped_store
+
+  __scoped_atomic_store(dest, val, __ATOMIC_RELAXED, __MEMORY_SCOPE_SYSTEM);
+  // CIR:      %[[DEST_PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[VALUE_PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[VALUE_PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i
+  // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: cir.call @__atomic_store(%[[SIZE]], %[[DEST_VOIDPTR]], 
%[[VALUE_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef 
%[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0)
+
+  // OGCG:      %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef 
%[[DEST]], ptr noundef %[[VALUE]], i32 noundef 0)
+}
+
+void c11_store(_Atomic(struct Big) *dest, struct Big *val) {
+  // CIR-LABEL: @c11_store
+  // LLVM-LABEL: @c11_store
+  // OGCG-LABEL: @c11_store
+
+  __c11_atomic_store(dest, *val, __ATOMIC_RELAXED);
+  // CIR:      %[[DEST_PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[VALUE_PTR:.+]] = cir.load deref align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: cir.copy %[[VALUE_PTR]] to %[[TEMP_SLOT:.+]] : 
!cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[DEST_INTPTR:.+]] = cir.cast bitcast %[[DEST_PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[TEMP_SLOT]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[SIZE:.+]] = cir.const #cir.int<24> : !u64i
+  // CIR-NEXT: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: cir.call @__atomic_store(%[[SIZE]], %[[DEST_VOIDPTR]], 
%[[VALUE_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr %[[TEMP_SLOT:.+]], ptr 
%[[VALUE]], i64 24, i1 false)
+  // LLVM-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef 
%[[DEST]], ptr noundef %[[TEMP_SLOT]], i32 noundef 0)
+
+  // OGCG:      %[[DEST:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // OGCG-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 
%[[TEMP_SLOT:.+]], ptr align 4 %[[VALUE]], i64 24, i1 false)
+  // OGCG-NEXT: call void @__atomic_store(i64 noundef 24, ptr noundef 
%[[DEST]], ptr noundef %[[TEMP_SLOT]], i32 noundef 0)
+}

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

Reply via email to