https://github.com/Lancern created 
https://github.com/llvm/llvm-project/pull/206073

This patch adds support for atomic exchange and compare-and-exchange operations 
via libcall.

Assisted-by: Codex / gpt-5.5 xhigh

>From 84763db0dfb0cad7b3bcbe179d9687a4754df959 Mon Sep 17 00:00:00 2001
From: Sirui Mu <[email protected]>
Date: Fri, 26 Jun 2026 22:04:57 +0800
Subject: [PATCH] [CIR] Atomic exchange and compare-and-exchange via libcall

This patch adds support for atomic exchange and compare-and-exchange operations
via libcall.

Assisted-by: Codex / gpt-5.5 xhigh
---
 clang/lib/CIR/CodeGen/CIRGenAtomic.cpp  |  51 ++++++--
 clang/test/CIR/CodeGen/atomic-libcall.c | 162 +++++++++++++++++++++++-
 2 files changed, 194 insertions(+), 19 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp 
b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 4d774761b975a..a986b001f2cfc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -1131,7 +1131,8 @@ static RValue emitAtomicLibCall(CIRGenFunction &cgf, 
llvm::StringRef funcName,
 
 static RValue emitLibCallForAtomicExpr(CIRGenFunction &cgf, AtomicExpr *e,
                                        Address atomicPtr, Address dest,
-                                       Address val1, uint64_t atomicTySize,
+                                       Address val1, Address val2,
+                                       uint64_t atomicTySize,
                                        QualType resultTy) {
   mlir::Location loc = cgf.getLoc(e->getSourceRange());
 
@@ -1156,6 +1157,8 @@ static RValue emitLibCallForAtomicExpr(CIRGenFunction 
&cgf, AtomicExpr *e,
                                               e->getPtr()->getType())),
            cgf.getContext().VoidPtrTy);
 
+  mlir::Value order = cgf.emitScalarExpr(e->getOrder());
+
   // The next 1-3 parameters are op-dependent.
   llvm::StringRef calleeName;
   QualType retTy;
@@ -1174,14 +1177,28 @@ static RValue emitLibCallForAtomicExpr(CIRGenFunction 
&cgf, AtomicExpr *e,
   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__scoped_atomic_compare_exchange:
+  case AtomicExpr::AO__scoped_atomic_compare_exchange_n: {
+    calleeName = "__atomic_compare_exchange";
+    retTy = cgf.getContext().BoolTy;
+    hasRetTy = true;
+    order = cgf.emitScalarExpr(e->getOrderFail());
+    args.add(RValue::get(castToGenericAddrSpace(val1.emitRawPointer(),
+                                                e->getVal1()->getType())),
+             cgf.getContext().VoidPtrTy);
+    args.add(RValue::get(castToGenericAddrSpace(val2.emitRawPointer(),
+                                                e->getVal2()->getType())),
+             cgf.getContext().VoidPtrTy);
+    break;
+  }
+
   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:
+  case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
+  case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
     cgf.cgm.errorNYI(
-        loc, "emitLibCallForAtomicExpr: atomic compare-and-exchange NYI");
+        loc,
+        "emitLibCallForAtomicExpr: atomic compare-and-exchange for 
OpenCL/HIP");
     return RValue::get(nullptr);
 
   // void __atomic_exchange(size_t size, void *mem, void *val, void *return,
@@ -1189,11 +1206,19 @@ static RValue emitLibCallForAtomicExpr(CIRGenFunction 
&cgf, AtomicExpr *e,
   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");
+  case AtomicExpr::AO__scoped_atomic_exchange_n: {
+    calleeName = "__atomic_exchange";
+    args.add(RValue::get(castToGenericAddrSpace(val1.emitRawPointer(),
+                                                e->getVal1()->getType())),
+             cgf.getContext().VoidPtrTy);
+    break;
+  }
+
+  case AtomicExpr::AO__opencl_atomic_exchange:
+  case AtomicExpr::AO__hip_atomic_exchange:
+    cgf.cgm.errorNYI(
+        loc, "emitLibCallForAtomicExpr: atomic exchange for OpenCL/HIP");
     return RValue::get(nullptr);
 
   // void __atomic_store(size_t size, void *mem, void *val, int order)
@@ -1311,8 +1336,7 @@ static RValue emitLibCallForAtomicExpr(CIRGenFunction 
&cgf, AtomicExpr *e,
   }
 
   // Order is always the last parameter.
-  args.add(RValue::get(cgf.emitScalarExpr(e->getOrder())),
-           cgf.getContext().IntTy);
+  args.add(RValue::get(order), cgf.getContext().IntTy);
   if (e->isOpenCL()) {
     assert(!cir::MissingFeatures::openCL());
     cgf.cgm.errorNYI(loc, "emitLibCallForAtomicExpr: openCL");
@@ -1544,7 +1568,8 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
   //
   // See: https://llvm.org/docs/Atomics.html#libcalls-atomic
   if (useLibCall)
-    return emitLibCallForAtomicExpr(*this, e, ptr, dest, val1, size, resultTy);
+    return emitLibCallForAtomicExpr(*this, e, ptr, dest, val1, val2, size,
+                                    resultTy);
 
   bool isStore = e->getOp() == AtomicExpr::AO__c11_atomic_store ||
                  e->getOp() == AtomicExpr::AO__opencl_atomic_store ||
diff --git a/clang/test/CIR/CodeGen/atomic-libcall.c 
b/clang/test/CIR/CodeGen/atomic-libcall.c
index 53685dd1b543d..135995431d6fe 100644
--- a/clang/test/CIR/CodeGen/atomic-libcall.c
+++ b/clang/test/CIR/CodeGen/atomic-libcall.c
@@ -21,8 +21,8 @@ void load(struct Big *ptr) {
   // 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: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
   // 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
@@ -42,8 +42,8 @@ void scoped_load(struct Big *ptr) {
   // 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: %[[DEST_VOIDPTR:.+]] = cir.cast bitcast %[[DEST_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
   // 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
@@ -63,8 +63,8 @@ void c11_load(_Atomic(struct Big) *ptr) {
   // 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: %[[TEMP_VOIDPTR:.+]] = cir.cast bitcast %[[TEMP_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
   // 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>
@@ -87,8 +87,8 @@ void store(struct Big *dest, struct Big *val) {
   // 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: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
   // 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
@@ -107,8 +107,8 @@ void scoped_store(struct Big *dest, struct Big *val) {
   // 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: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
   // 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
@@ -128,8 +128,8 @@ void c11_store(_Atomic(struct Big) *dest, struct Big *val) {
   // 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: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
   // 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
@@ -137,3 +137,153 @@ void c11_store(_Atomic(struct Big) *dest, struct Big 
*val) {
   // 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)
 }
+
+void cmpxchg(struct Big *ptr, struct Big *expected, struct Big *desired) {
+  // CIR-LABEL: @cmpxchg
+  // LLVM-LABEL: @cmpxchg
+
+  __atomic_compare_exchange(ptr, expected, desired, /*weak=*/0, 
__ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[EXPECTED:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[DESIRED:.+]] = 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: %[[EXPECTED_INTPTR:.+]] = cir.cast bitcast %[[EXPECTED]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[DESIRED_INTPTR:.+]] = cir.cast bitcast %[[DESIRED]] : 
!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: %[[ORDER:.+]] = cir.const #cir.int<2> : !s32i
+  // CIR-NEXT: %[[EXPECTED_VOIDPTR:.+]] = cir.cast bitcast 
%[[EXPECTED_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[DESIRED_VOIDPTR:.+]] = cir.cast bitcast %[[DESIRED_INTPTR]] 
: !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[CALL:.+]] = cir.call @__atomic_compare_exchange(%[[SIZE]], 
%[[PTR_VOIDPTR]], %[[EXPECTED_VOIDPTR]], %[[DESIRED_VOIDPTR]], %[[ORDER]]) : 
(!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> 
!cir.bool
+
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[EXPECTED:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[DESIRED:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[CALL:.+]] = call {{.*}}i1 @__atomic_compare_exchange(i64 
noundef 24, ptr noundef %[[PTR]], ptr noundef %[[EXPECTED]], ptr noundef 
%[[DESIRED]], {{.*}}i32 noundef 2)
+}
+
+void c11_cmpxchg(_Atomic(struct Big) *ptr, struct Big *expected, struct Big 
*desired) {
+  // CIR-LABEL: @c11_cmpxchg
+  // LLVM-LABEL: @c11_cmpxchg
+
+  __c11_atomic_compare_exchange_weak(ptr, expected, *desired, 
__ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE);
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[EXPECTED:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[DESIRED:.+]] = cir.load deref align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: cir.copy %[[DESIRED]] to %[[TEMP_SLOT:.+]] : !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[EXPECTED_INTPTR:.+]] = cir.cast bitcast %[[EXPECTED]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[DESIRED_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: %[[ORDER:.+]] = cir.const #cir.int<2> : !s32i
+  // CIR-NEXT: %[[EXPECTED_VOIDPTR:.+]] = cir.cast bitcast 
%[[EXPECTED_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[DESIRED_VOIDPTR:.+]] = cir.cast bitcast %[[DESIRED_INTPTR]] 
: !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[CALL:.+]] = cir.call @__atomic_compare_exchange(%[[SIZE]], 
%[[PTR_VOIDPTR]], %[[EXPECTED_VOIDPTR]], %[[DESIRED_VOIDPTR]], %[[ORDER]]) : 
(!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> 
!cir.bool
+
+  // LLVM:      %[[TEMP_SLOT:.+]] = alloca %struct.Big
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[EXPECTED:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[DESIRED:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}%[[TEMP_SLOT]], ptr 
{{.*}}%[[DESIRED]], i64 24, i1 false)
+  // LLVM-NEXT: %[[CALL:.+]] = call {{.*}}i1 @__atomic_compare_exchange(i64 
noundef 24, ptr noundef %[[PTR]], ptr noundef %[[EXPECTED]], ptr noundef 
%[[TEMP_SLOT]], {{.*}}i32 noundef 2)
+}
+
+void scoped_cmpxchg(struct Big *ptr, struct Big *expected, struct Big 
*desired) {
+  // CIR-LABEL: @scoped_cmpxchg
+  // LLVM-LABEL: @scoped_cmpxchg
+
+  __scoped_atomic_compare_exchange(ptr, expected, desired, /*weak=*/0, 
__ATOMIC_SEQ_CST, __ATOMIC_ACQUIRE, __MEMORY_SCOPE_SYSTEM);
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[EXPECTED:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[DESIRED:.+]] = 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: %[[EXPECTED_INTPTR:.+]] = cir.cast bitcast %[[EXPECTED]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[DESIRED_INTPTR:.+]] = cir.cast bitcast %[[DESIRED]] : 
!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: %[[ORDER:.+]] = cir.const #cir.int<2> : !s32i
+  // CIR-NEXT: %[[EXPECTED_VOIDPTR:.+]] = cir.cast bitcast 
%[[EXPECTED_INTPTR]] : !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[DESIRED_VOIDPTR:.+]] = cir.cast bitcast %[[DESIRED_INTPTR]] 
: !cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[CALL:.+]] = cir.call @__atomic_compare_exchange(%[[SIZE]], 
%[[PTR_VOIDPTR]], %[[EXPECTED_VOIDPTR]], %[[DESIRED_VOIDPTR]], %[[ORDER]]) : 
(!u64i {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !s32i {llvm.noundef}) -> 
!cir.bool
+
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[EXPECTED:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[DESIRED:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[CALL:.+]] = call {{.*}}i1 @__atomic_compare_exchange(i64 
noundef 24, ptr noundef %[[PTR]], ptr noundef %[[EXPECTED]], ptr noundef 
%[[DESIRED]], {{.*}}i32 noundef 2)
+}
+
+void exchange(struct Big *ptr, struct Big *value, struct Big *old) {
+  // CIR-LABEL: @exchange
+  // LLVM-LABEL: @exchange
+
+  __atomic_exchange(ptr, value, old, __ATOMIC_RELAXED);
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[VALUE:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[OLD:.+]] = 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: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[VALUE]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[OLD_INTPTR:.+]] = cir.cast bitcast %[[OLD]] : 
!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: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[OLD_VOIDPTR:.+]] = cir.cast bitcast %[[OLD_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: cir.call @__atomic_exchange(%[[SIZE]], %[[PTR_VOIDPTR]], 
%[[VALUE_VOIDPTR]], %[[OLD_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, 
!cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[OLD:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @__atomic_exchange(i64 noundef 24, ptr noundef 
%[[PTR]], ptr noundef %[[VALUE]], ptr noundef %[[OLD]], i32 noundef 0)
+}
+
+void c11_exchange(_Atomic(struct Big) *ptr, struct Big *value) {
+  // CIR-LABEL: @c11_exchange
+  // LLVM-LABEL: @c11_exchange
+
+  __c11_atomic_exchange(ptr, *value, __ATOMIC_RELAXED);
+  // CIR:      %[[OLD_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: %[[VALUE:.+]] = cir.load deref align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: cir.copy %[[VALUE]] to %[[VALUE_SLOT:.+]] : !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[PTR_INTPTR:.+]] = cir.cast bitcast %[[PTR]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[VALUE_SLOT]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[OLD_INTPTR:.+]] = cir.cast bitcast %[[OLD_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: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[OLD_VOIDPTR:.+]] = cir.cast bitcast %[[OLD_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: cir.call @__atomic_exchange(%[[SIZE]], %[[PTR_VOIDPTR]], 
%[[VALUE_VOIDPTR]], %[[OLD_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, 
!cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[VALUE_SLOT:.+]] = alloca %struct.Big
+  // LLVM-NEXT: %[[OLD_SLOT:.+]] = alloca %struct.Big
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}%[[VALUE_SLOT]], 
ptr {{.*}}%[[VALUE]], i64 24, i1 false)
+  // LLVM-NEXT: call void @__atomic_exchange(i64 noundef 24, ptr noundef 
%[[PTR]], ptr noundef %[[VALUE_SLOT]], ptr noundef %[[OLD_SLOT]], i32 noundef 0)
+}
+
+void scoped_exchange(struct Big *ptr, struct Big *value, struct Big *old) {
+  // CIR-LABEL: @scoped_exchange
+  // LLVM-LABEL: @scoped_exchange
+
+  __scoped_atomic_exchange(ptr, value, old, __ATOMIC_RELAXED, 
__MEMORY_SCOPE_SYSTEM);
+  // CIR:      %[[PTR:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[VALUE:.+]] = cir.load align(8) %{{.+}} : 
!cir.ptr<!cir.ptr<!rec_Big>>, !cir.ptr<!rec_Big>
+  // CIR-NEXT: %[[OLD:.+]] = 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: %[[VALUE_INTPTR:.+]] = cir.cast bitcast %[[VALUE]] : 
!cir.ptr<!rec_Big> -> !cir.ptr<!cir.int<u, 192>>
+  // CIR-NEXT: %[[OLD_INTPTR:.+]] = cir.cast bitcast %[[OLD]] : 
!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: %[[ORDER:.+]] = cir.const #cir.int<0> : !s32i
+  // CIR-NEXT: %[[VALUE_VOIDPTR:.+]] = cir.cast bitcast %[[VALUE_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: %[[OLD_VOIDPTR:.+]] = cir.cast bitcast %[[OLD_INTPTR]] : 
!cir.ptr<!cir.int<u, 192>> -> !cir.ptr<!void>
+  // CIR-NEXT: cir.call @__atomic_exchange(%[[SIZE]], %[[PTR_VOIDPTR]], 
%[[VALUE_VOIDPTR]], %[[OLD_VOIDPTR]], %[[ORDER]]) : (!u64i {llvm.noundef}, 
!cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> {llvm.noundef}, !cir.ptr<!void> 
{llvm.noundef}, !s32i {llvm.noundef}) -> ()
+
+  // LLVM:      %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[VALUE:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: %[[OLD:.+]] = load ptr, ptr %{{.+}}, align 8
+  // LLVM-NEXT: call void @__atomic_exchange(i64 noundef 24, ptr noundef 
%[[PTR]], ptr noundef %[[VALUE]], ptr noundef %[[OLD]], i32 noundef 0)
+}

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

Reply via email to