[clang] [CIR][CIRGen] Add support for __sync_* binary atomic builtins (PR #186026)

Ayokunle Amodu via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 12 18:06:07 PDT 2026


https://github.com/ayokunle321 updated https://github.com/llvm/llvm-project/pull/186026

>From 9295f50ff60f8160d00bd25d51053a7f1bc01199 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 11 Mar 2026 20:39:35 -0600
Subject: [PATCH 1/5] add support for binary atomic ops

---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp |  17 +-
 clang/test/CIR/CodeGen/atomic.c         | 524 +++++++++++++++++++++++-
 2 files changed, 538 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 244979aac917e..d407ebc87aefc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -116,7 +116,7 @@ static Address checkAtomicAlignment(CIRGenFunction &cgf, const CallExpr *e) {
 /// and the expression node.
 static mlir::Value makeBinaryAtomicValue(
     CIRGenFunction &cgf, cir::AtomicFetchKind kind, const CallExpr *expr,
-    mlir::Type *originalArgType, mlir::Value *emittedArgValue = nullptr,
+    mlir::Type *originalArgType = nullptr, mlir::Value *emittedArgValue = nullptr,
     cir::MemOrder ordering = cir::MemOrder::SequentiallyConsistent) {
 
   QualType type = expr->getType();
@@ -169,6 +169,11 @@ static mlir::Value makeBinaryAtomicValue(
   return rmwi->getResult(0);
 }
 
+static RValue emitBinaryAtomic(CIRGenFunction &cgf, cir::AtomicFetchKind atomicOpkind,
+                               const CallExpr *e) {
+  return RValue::get(makeBinaryAtomicValue(cgf, atomicOpkind, e));
+}
+
 template <typename BinOp>
 static RValue emitBinaryAtomicPost(CIRGenFunction &cgf,
                                    cir::AtomicFetchKind atomicOpkind,
@@ -1710,42 +1715,50 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   case Builtin::BI__sync_lock_test_and_set:
   case Builtin::BI__sync_lock_release:
   case Builtin::BI__sync_swap:
+    return errorBuiltinNYI(*this, e, builtinID);
   case Builtin::BI__sync_fetch_and_add_1:
   case Builtin::BI__sync_fetch_and_add_2:
   case Builtin::BI__sync_fetch_and_add_4:
   case Builtin::BI__sync_fetch_and_add_8:
   case Builtin::BI__sync_fetch_and_add_16:
+    return emitBinaryAtomic(*this, cir::AtomicFetchKind::Add, e);
   case Builtin::BI__sync_fetch_and_sub_1:
   case Builtin::BI__sync_fetch_and_sub_2:
   case Builtin::BI__sync_fetch_and_sub_4:
   case Builtin::BI__sync_fetch_and_sub_8:
   case Builtin::BI__sync_fetch_and_sub_16:
+    return emitBinaryAtomic(*this, cir::AtomicFetchKind::Sub, e);
   case Builtin::BI__sync_fetch_and_or_1:
   case Builtin::BI__sync_fetch_and_or_2:
   case Builtin::BI__sync_fetch_and_or_4:
   case Builtin::BI__sync_fetch_and_or_8:
   case Builtin::BI__sync_fetch_and_or_16:
+    return emitBinaryAtomic(*this, cir::AtomicFetchKind::Or, e);
   case Builtin::BI__sync_fetch_and_and_1:
   case Builtin::BI__sync_fetch_and_and_2:
   case Builtin::BI__sync_fetch_and_and_4:
   case Builtin::BI__sync_fetch_and_and_8:
   case Builtin::BI__sync_fetch_and_and_16:
+    return emitBinaryAtomic(*this, cir::AtomicFetchKind::And, e);
   case Builtin::BI__sync_fetch_and_xor_1:
   case Builtin::BI__sync_fetch_and_xor_2:
   case Builtin::BI__sync_fetch_and_xor_4:
   case Builtin::BI__sync_fetch_and_xor_8:
   case Builtin::BI__sync_fetch_and_xor_16:
+    return emitBinaryAtomic(*this, cir::AtomicFetchKind::Xor, e);
   case Builtin::BI__sync_fetch_and_nand_1:
   case Builtin::BI__sync_fetch_and_nand_2:
   case Builtin::BI__sync_fetch_and_nand_4:
   case Builtin::BI__sync_fetch_and_nand_8:
   case Builtin::BI__sync_fetch_and_nand_16:
+    return emitBinaryAtomic(*this, cir::AtomicFetchKind::Nand, e);
+  
   case Builtin::BI__sync_fetch_and_min:
   case Builtin::BI__sync_fetch_and_max:
   case Builtin::BI__sync_fetch_and_umin:
   case Builtin::BI__sync_fetch_and_umax:
     return errorBuiltinNYI(*this, e, builtinID);
-    return getUndefRValue(e->getType());
+
   case Builtin::BI__sync_add_and_fetch_1:
   case Builtin::BI__sync_add_and_fetch_2:
   case Builtin::BI__sync_add_and_fetch_4:
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index 9bce73f253a11..200ebc549ef2b 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -1416,8 +1416,528 @@ int c11_atomic_fetch_nand(_Atomic(int) *ptr, int value) {
   // OGCG:      %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4
   // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4
 }
+void inc_int(int* a, int b) {
+  // CIR-LABEL: @inc_int
+  // CIR: %[[PTR:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: %[[VAL:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>, !s32i
+  // CIR: %[[RES:.*]] = cir.atomic.fetch add seq_cst syncscope(system) fetch_first %[[PTR]], %[[VAL]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+  // CIR: cir.store {{.*}} %[[RES]], {{.*}} : !s32i, !cir.ptr<!s32i>
+
+  // LLVM-LABEL: @inc_int
+  // LLVM: atomicrmw add ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @inc_int
+  // OGCG: atomicrmw add ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  int c = __sync_fetch_and_add(a, b);
+}
+
+void inc_long(long* a, long b) {
+  // CIR-LABEL: @inc_long
+  // CIR: cir.atomic.fetch add seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s64i>, !s64i) -> !s64i
+
+  // LLVM-LABEL: @inc_long
+  // LLVM: atomicrmw add ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @inc_long
+  // OGCG: atomicrmw add ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  long c = __sync_fetch_and_add(a, 2);
+}
+
+void inc_short(short* a, short b) {
+  // CIR-LABEL: @inc_short
+  // CIR: cir.atomic.fetch add seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s16i>, !s16i) -> !s16i
+
+  // LLVM-LABEL: @inc_short
+  // LLVM: atomicrmw add ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+
+  // OGCG-LABEL: @inc_short
+  // OGCG: atomicrmw add ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+  short c = __sync_fetch_and_add(a, 2);
+}
+
+void inc_byte(char* a, char b) {
+  // CIR-LABEL: @inc_byte
+  // CIR: cir.atomic.fetch add seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s8i>, !s8i) -> !s8i
+
+  // LLVM-LABEL: @inc_byte
+  // LLVM: atomicrmw add ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @inc_byte
+  // OGCG: atomicrmw add ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  char c = __sync_fetch_and_add(a, b);
+}
+
+void inc_uint(unsigned int* a, int b) {
+  // CIR-LABEL: @inc_uint
+  // CIR: cir.atomic.fetch add seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u32i>, !u32i) -> !u32i
+
+  // LLVM-LABEL: @inc_uint
+  // LLVM: atomicrmw add ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @inc_uint
+  // OGCG: atomicrmw add ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  unsigned int c = __sync_fetch_and_add(a, b);
+}
+
+void inc_ulong(unsigned long* a, long b) {
+  // CIR-LABEL: @inc_ulong
+  // CIR: cir.atomic.fetch add seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u64i>, !u64i) -> !u64i
+
+  // LLVM-LABEL: @inc_ulong
+  // LLVM: atomicrmw add ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @inc_ulong
+  // OGCG: atomicrmw add ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  unsigned long c = __sync_fetch_and_add(a, b);
+}
+
+void inc_uchar(unsigned char* a, char b) {
+  // CIR-LABEL: @inc_uchar
+  // CIR: cir.atomic.fetch add seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u8i>, !u8i) -> !u8i
+
+  // LLVM-LABEL: @inc_uchar
+  // LLVM: atomicrmw add ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @inc_uchar
+  // OGCG: atomicrmw add ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  unsigned char c = __sync_fetch_and_add(a, b);
+}
+
+void sub_int(int* a, int b) {
+  // CIR-LABEL: @sub_int
+  // CIR: %[[PTR:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: %[[VAL:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>, !s32i
+  // CIR: %[[RES:.*]] = cir.atomic.fetch sub seq_cst syncscope(system) fetch_first %[[PTR]], %[[VAL]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+  // CIR: cir.store {{.*}} %[[RES]], {{.*}} : !s32i, !cir.ptr<!s32i>
+
+  // LLVM-LABEL: @sub_int
+  // LLVM: atomicrmw sub ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @sub_int
+  // OGCG: atomicrmw sub ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  int c = __sync_fetch_and_sub(a, b);
+}
+
+void sub_long(long* a, long b) {
+  // CIR-LABEL: @sub_long
+  // CIR: cir.atomic.fetch sub seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s64i>, !s64i) -> !s64i
+
+  // LLVM-LABEL: @sub_long
+  // LLVM: atomicrmw sub ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @sub_long
+  // OGCG: atomicrmw sub ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  long c = __sync_fetch_and_sub(a, 2);
+}
+
+void sub_short(short* a, short b) {
+  // CIR-LABEL: @sub_short
+  // CIR: cir.atomic.fetch sub seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s16i>, !s16i) -> !s16i
+
+  // LLVM-LABEL: @sub_short
+  // LLVM: atomicrmw sub ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+
+  // OGCG-LABEL: @sub_short
+  // OGCG: atomicrmw sub ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+  short c = __sync_fetch_and_sub(a, 2);
+}
+
+void sub_byte(char* a, char b) {
+  // CIR-LABEL: @sub_byte
+  // CIR: cir.atomic.fetch sub seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s8i>, !s8i) -> !s8i
+
+  // LLVM-LABEL: @sub_byte
+  // LLVM: atomicrmw sub ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @sub_byte
+  // OGCG: atomicrmw sub ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  char c = __sync_fetch_and_sub(a, b);
+}
+
+void sub_uint(unsigned int* a, int b) {
+  // CIR-LABEL: @sub_uint
+  // CIR: cir.atomic.fetch sub seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u32i>, !u32i) -> !u32i
+
+  // LLVM-LABEL: @sub_uint
+  // LLVM: atomicrmw sub ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @sub_uint
+  // OGCG: atomicrmw sub ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  unsigned int c = __sync_fetch_and_sub(a, b);
+}
+
+void sub_ulong(unsigned long* a, long b) {
+  // CIR-LABEL: @sub_ulong
+  // CIR: cir.atomic.fetch sub seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u64i>, !u64i) -> !u64i
+
+  // LLVM-LABEL: @sub_ulong
+  // LLVM: atomicrmw sub ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @sub_ulong
+  // OGCG: atomicrmw sub ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  unsigned long c = __sync_fetch_and_sub(a, b);
+}
+
+void sub_uchar(unsigned char* a, char b) {
+  // CIR-LABEL: @sub_uchar
+  // CIR: cir.atomic.fetch sub seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u8i>, !u8i) -> !u8i
+
+  // LLVM-LABEL: @sub_uchar
+  // LLVM: atomicrmw sub ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @sub_uchar
+  // OGCG: atomicrmw sub ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  unsigned char c = __sync_fetch_and_sub(a, b);
+}
+
+void or_int(int* a, int b) {
+  // CIR-LABEL: or_int
+  // CIR: %[[PTR:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: %[[VAL:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>, !s32i
+  // CIR: %[[RES:.*]] = cir.atomic.fetch or seq_cst syncscope(system) fetch_first %[[PTR]], %[[VAL]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+  // CIR: cir.store {{.*}} %[[RES]], {{.*}} : !s32i, !cir.ptr<!s32i>
+
+  // LLVM-LABEL: or_int
+  // LLVM: atomicrmw or ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: or_int
+  // OGCG: atomicrmw or ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  int c = __sync_fetch_and_or(a, b);
+}
+
+void or_long(long* a, long b) {
+  // CIR-LABEL: @or_long
+  // CIR: cir.atomic.fetch or seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s64i>, !s64i) -> !s64i
+
+  // LLVM-LABEL: @or_long
+  // LLVM: atomicrmw or ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @or_long
+  // OGCG: atomicrmw or ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  long c = __sync_fetch_and_or(a, 2);
+}
+
+void or_short(short* a, short b) {
+  // CIR-LABEL: @or_short
+  // CIR: cir.atomic.fetch or seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s16i>, !s16i) -> !s16i
+
+  // LLVM-LABEL: @or_short
+  // LLVM: atomicrmw or ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+
+  // OGCG-LABEL: @or_short
+  // OGCG: atomicrmw or ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+  short c = __sync_fetch_and_or(a, 2);
+}
+
+void or_byte(char* a, char b) {
+  // CIR-LABEL: @or_byte
+  // CIR: cir.atomic.fetch or seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s8i>, !s8i) -> !s8i
+
+  // LLVM-LABEL: @or_byte
+  // LLVM: atomicrmw or ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @or_byte
+  // OGCG: atomicrmw or ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  char c = __sync_fetch_and_or(a, b);
+}
+
+void or_uint(unsigned int* a, int b) {
+  // CIR-LABEL: @or_uint
+  // CIR: cir.atomic.fetch or seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u32i>, !u32i) -> !u32i
+
+  // LLVM-LABEL: @or_uint
+  // LLVM: atomicrmw or ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @or_uint
+  // OGCG: atomicrmw or ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  unsigned int c = __sync_fetch_and_or(a, b);
+}
+
+void or_ulong(unsigned long* a, long b) {
+  // CIR-LABEL: @or_ulong
+  // CIR: cir.atomic.fetch or seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u64i>, !u64i) -> !u64i
+
+  // LLVM-LABEL: @or_ulong
+  // LLVM: atomicrmw or ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @or_ulong
+  // OGCG: atomicrmw or ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  unsigned long c = __sync_fetch_and_or(a, b);
+}
+
+void or_uchar(unsigned char* a, char b) {
+  // CIR-LABEL: @or_uchar
+  // CIR: cir.atomic.fetch or seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u8i>, !u8i) -> !u8i
+
+  // LLVM-LABEL: @or_uchar
+  // LLVM: atomicrmw or ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @or_uchar
+  // OGCG: atomicrmw or ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  unsigned char c = __sync_fetch_and_or(a, b);
+}
+
+void xor_int(int* a, int b) {
+  // CIR-LABEL: xor_int
+  // CIR: %[[PTR:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: %[[VAL:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>, !s32i
+  // CIR: %[[RES:.*]] = cir.atomic.fetch xor seq_cst syncscope(system) fetch_first %[[PTR]], %[[VAL]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+  // CIR: cir.store {{.*}} %[[RES]], {{.*}} : !s32i, !cir.ptr<!s32i>
 
-// CHECK-LABEL: @test_op_and_fetch
+  // LLVM-LABEL: xor_int
+  // LLVM: atomicrmw xor ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: xor_int
+  // OGCG: atomicrmw xor ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  int c = __sync_fetch_and_xor(a, b);
+}
+
+void xor_long(long* a, long b) {
+  // CIR-LABEL: @xor_long
+  // CIR: cir.atomic.fetch xor seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s64i>, !s64i) -> !s64i
+
+  // LLVM-LABEL: @xor_long
+  // LLVM: atomicrmw xor ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @xor_long
+  // OGCG: atomicrmw xor ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  long c = __sync_fetch_and_xor(a, 2);
+}
+
+void xor_short(short* a, short b) {
+  // CIR-LABEL: @xor_short
+  // CIR: cir.atomic.fetch xor seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s16i>, !s16i) -> !s16i
+
+  // LLVM-LABEL: @xor_short
+  // LLVM: atomicrmw xor ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+
+  // OGCG-LABEL: @xor_short
+  // OGCG: atomicrmw xor ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+  short c = __sync_fetch_and_xor(a, 2);
+}
+
+void xor_byte(char* a, char b) {
+  // CIR-LABEL: @xor_byte
+  // CIR: cir.atomic.fetch xor seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s8i>, !s8i) -> !s8i
+
+  // LLVM-LABEL: @xor_byte
+  // LLVM: atomicrmw xor ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @xor_byte
+  // OGCG: atomicrmw xor ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  char c = __sync_fetch_and_xor(a, b);
+}
+
+void xor_uint(unsigned int* a, int b) {
+  // CIR-LABEL: @xor_uint
+  // CIR: cir.atomic.fetch xor seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u32i>, !u32i) -> !u32i
+
+  // LLVM-LABEL: @xor_uint
+  // LLVM: atomicrmw xor ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @xor_uint
+  // OGCG: atomicrmw xor ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  unsigned int c = __sync_fetch_and_xor(a, b);
+}
+
+void xor_ulong(unsigned long* a, long b) {
+  // CIR-LABEL: @xor_ulong
+  // CIR: cir.atomic.fetch xor seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u64i>, !u64i) -> !u64i
+
+  // LLVM-LABEL: @xor_ulong
+  // LLVM: atomicrmw xor ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @xor_ulong
+  // OGCG: atomicrmw xor ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  unsigned long c = __sync_fetch_and_xor(a, b);
+}
+
+void xor_uchar(unsigned char* a, char b) {
+  // CIR-LABEL: @xor_uchar
+  // CIR: cir.atomic.fetch xor seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u8i>, !u8i) -> !u8i
+
+  // LLVM-LABEL: @xor_uchar
+  // LLVM: atomicrmw xor ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @xor_uchar
+  // OGCG: atomicrmw xor ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  unsigned char c = __sync_fetch_and_xor(a, b);
+}
+void and_int(int* a, int b) {
+  // CIR-LABEL: and_int
+  // CIR: %[[PTR:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: %[[VAL:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>, !s32i
+  // CIR: %[[RES:.*]] = cir.atomic.fetch and seq_cst syncscope(system) fetch_first %[[PTR]], %[[VAL]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+  // CIR: cir.store {{.*}} %[[RES]], {{.*}} : !s32i, !cir.ptr<!s32i>
+
+  // LLVM-LABEL: and_int
+  // LLVM: atomicrmw and ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: and_int
+  // OGCG: atomicrmw and ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  int c = __sync_fetch_and_and(a, b);
+}
+
+void and_long(long* a, long b) {
+  // CIR-LABEL: @and_long
+  // CIR: cir.atomic.fetch and seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s64i>, !s64i) -> !s64i
+
+  // LLVM-LABEL: @and_long
+  // LLVM: atomicrmw and ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @and_long
+  // OGCG: atomicrmw and ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  long c = __sync_fetch_and_and(a, 2);
+}
+
+void and_short(short* a, short b) {
+  // CIR-LABEL: @and_short
+  // CIR: cir.atomic.fetch and seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s16i>, !s16i) -> !s16i
+
+  // LLVM-LABEL: @and_short
+  // LLVM: atomicrmw and ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+
+  // OGCG-LABEL: @and_short
+  // OGCG: atomicrmw and ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+  short c = __sync_fetch_and_and(a, 2);
+}
+
+void and_byte(char* a, char b) {
+  // CIR-LABEL: @and_byte
+  // CIR: cir.atomic.fetch and seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s8i>, !s8i) -> !s8i
+
+  // LLVM-LABEL: @and_byte
+  // LLVM: atomicrmw and ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @and_byte
+  // OGCG: atomicrmw and ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  char c = __sync_fetch_and_and(a, b);
+}
+
+void and_uint(unsigned int* a, int b) {
+  // CIR-LABEL: @and_uint
+  // CIR: cir.atomic.fetch and seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u32i>, !u32i) -> !u32i
+
+  // LLVM-LABEL: @and_uint
+  // LLVM: atomicrmw and ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @and_uint
+  // OGCG: atomicrmw and ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  unsigned int c = __sync_fetch_and_and(a, b);
+}
+
+void and_ulong(unsigned long* a, long b) {
+  // CIR-LABEL: @and_ulong
+  // CIR: cir.atomic.fetch and seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u64i>, !u64i) -> !u64i
+
+  // LLVM-LABEL: @and_ulong
+  // LLVM: atomicrmw and ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @and_ulong
+  // OGCG: atomicrmw and ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  unsigned long c = __sync_fetch_and_and(a, b);
+}
+
+void and_uchar(unsigned char* a, char b) {
+  // CIR-LABEL: @and_uchar
+  // CIR: cir.atomic.fetch and seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u8i>, !u8i) -> !u8i
+
+  // LLVM-LABEL: @and_uchar
+  // LLVM: atomicrmw and ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @and_uchar
+  // OGCG: atomicrmw and ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  unsigned char c = __sync_fetch_and_and(a, b);
+}
+
+void nand_int(int* a, int b) {
+  // CIR-LABEL: nand_int
+  // CIR: %[[PTR:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+  // CIR: %[[VAL:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr<!s32i>, !s32i
+  // CIR: %[[RES:.*]] = cir.atomic.fetch nand seq_cst syncscope(system) fetch_first %[[PTR]], %[[VAL]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+  // CIR: cir.store {{.*}} %[[RES]], {{.*}} : !s32i, !cir.ptr<!s32i>
+
+  // LLVM-LABEL: nand_int
+  // LLVM: atomicrmw nand ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: nand_int
+  // OGCG: atomicrmw nand ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  int c = __sync_fetch_and_nand(a, b);
+}
+
+void nand_long(long* a, long b) {
+  // CIR-LABEL: @nand_long
+  // CIR: cir.atomic.fetch nand seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s64i>, !s64i) -> !s64i
+
+  // LLVM-LABEL: @nand_long
+  // LLVM: atomicrmw nand ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @nand_long
+  // OGCG: atomicrmw nand ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  long c = __sync_fetch_and_nand(a, 2);
+}
+
+void nand_short(short* a, short b) {
+  // CIR-LABEL: @nand_short
+  // CIR: cir.atomic.fetch nand seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s16i>, !s16i) -> !s16i
+
+  // LLVM-LABEL: @nand_short
+  // LLVM: atomicrmw nand ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+
+  // OGCG-LABEL: @nand_short
+  // OGCG: atomicrmw nand ptr {{.*}}, i16 {{.*}} seq_cst, align 2
+  short c = __sync_fetch_and_nand(a, 2);
+}
+
+void nand_byte(char* a, char b) {
+  // CIR-LABEL: @nand_byte
+  // CIR: cir.atomic.fetch nand seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!s8i>, !s8i) -> !s8i
+
+  // LLVM-LABEL: @nand_byte
+  // LLVM: atomicrmw nand ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @nand_byte
+  // OGCG: atomicrmw nand ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  char c = __sync_fetch_and_nand(a, b);
+}
+
+void nand_uint(unsigned int* a, int b) {
+  // CIR-LABEL: @nand_uint
+  // CIR: cir.atomic.fetch nand seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u32i>, !u32i) -> !u32i
+
+  // LLVM-LABEL: @nand_uint
+  // LLVM: atomicrmw nand ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+
+  // OGCG-LABEL: @nand_uint
+  // OGCG: atomicrmw nand ptr {{.*}}, i32 {{.*}} seq_cst, align 4
+  unsigned int c = __sync_fetch_and_nand(a, b);
+}
+
+void nand_ulong(unsigned long* a, long b) {
+  // CIR-LABEL: @nand_ulong
+  // CIR: cir.atomic.fetch nand seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u64i>, !u64i) -> !u64i
+
+  // LLVM-LABEL: @nand_ulong
+  // LLVM: atomicrmw nand ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+
+  // OGCG-LABEL: @nand_ulong
+  // OGCG: atomicrmw nand ptr {{.*}}, i64 {{.*}} seq_cst, align 8
+  unsigned long c = __sync_fetch_and_nand(a, b);
+}
+
+void nand_uchar(unsigned char* a, char b) {
+  // CIR-LABEL: @nand_uchar
+  // CIR: cir.atomic.fetch nand seq_cst syncscope(system) fetch_first {{.*}}, {{.*}} : (!cir.ptr<!u8i>, !u8i) -> !u8i
+
+  // LLVM-LABEL: @nand_uchar
+  // LLVM: atomicrmw nand ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+
+  // OGCG-LABEL: @nand_uchar
+  // OGCG: atomicrmw nand ptr {{.*}}, i8 {{.*}} seq_cst, align 1
+  unsigned char c = __sync_fetch_and_nand(a, b);
+}
+
+// CIR-LABEL: @test_op_and_fetch
 // LLVM-LABEL: @test_op_and_fetch
 void test_op_and_fetch() {
   int *ptr;
@@ -2164,6 +2684,8 @@ void test_op_and_fetch() {
   ull = __sync_nand_and_fetch(&ull, uc);
 }
 
+
+
 int atomic_load_dynamic_order(int *ptr, int order) {
   // CIR-LABEL: atomic_load_dynamic_order
   // LLVM-LABEL: atomic_load_dynamic_order

>From 08492c6f7b33571cd5af1fe7ada64644b2cf140e Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 11 Mar 2026 20:44:27 -0600
Subject: [PATCH 2/5] fix style

---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index d407ebc87aefc..6c660552844e8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -116,7 +116,8 @@ static Address checkAtomicAlignment(CIRGenFunction &cgf, const CallExpr *e) {
 /// and the expression node.
 static mlir::Value makeBinaryAtomicValue(
     CIRGenFunction &cgf, cir::AtomicFetchKind kind, const CallExpr *expr,
-    mlir::Type *originalArgType = nullptr, mlir::Value *emittedArgValue = nullptr,
+    mlir::Type *originalArgType = nullptr,
+    mlir::Value *emittedArgValue = nullptr,
     cir::MemOrder ordering = cir::MemOrder::SequentiallyConsistent) {
 
   QualType type = expr->getType();
@@ -169,7 +170,8 @@ static mlir::Value makeBinaryAtomicValue(
   return rmwi->getResult(0);
 }
 
-static RValue emitBinaryAtomic(CIRGenFunction &cgf, cir::AtomicFetchKind atomicOpkind,
+static RValue emitBinaryAtomic(CIRGenFunction &cgf,
+                               cir::AtomicFetchKind atomicOpkind,
                                const CallExpr *e) {
   return RValue::get(makeBinaryAtomicValue(cgf, atomicOpkind, e));
 }
@@ -1752,7 +1754,7 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   case Builtin::BI__sync_fetch_and_nand_8:
   case Builtin::BI__sync_fetch_and_nand_16:
     return emitBinaryAtomic(*this, cir::AtomicFetchKind::Nand, e);
-  
+
   case Builtin::BI__sync_fetch_and_min:
   case Builtin::BI__sync_fetch_and_max:
   case Builtin::BI__sync_fetch_and_umin:

>From 267af53414a9135afedf24099bb240c056390dd3 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Wed, 11 Mar 2026 20:49:21 -0600
Subject: [PATCH 3/5] add rvalue return back

---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 6c660552844e8..652f59c739e0f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1754,13 +1754,12 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
   case Builtin::BI__sync_fetch_and_nand_8:
   case Builtin::BI__sync_fetch_and_nand_16:
     return emitBinaryAtomic(*this, cir::AtomicFetchKind::Nand, e);
-
   case Builtin::BI__sync_fetch_and_min:
   case Builtin::BI__sync_fetch_and_max:
   case Builtin::BI__sync_fetch_and_umin:
   case Builtin::BI__sync_fetch_and_umax:
     return errorBuiltinNYI(*this, e, builtinID);
-
+    return getUndefRValue(e->getType());
   case Builtin::BI__sync_add_and_fetch_1:
   case Builtin::BI__sync_add_and_fetch_2:
   case Builtin::BI__sync_add_and_fetch_4:

>From 7ae0b05ee5718791d50f3f889dd123aeb4283f93 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Thu, 12 Mar 2026 19:04:36 -0600
Subject: [PATCH 4/5] add non-null assert for originalArgType

---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 652f59c739e0f..621b1bbe20d10 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -160,7 +160,9 @@ static mlir::Value makeBinaryAtomicValue(
   // memory location and returns the old value.
   if (emittedArgValue) {
     *emittedArgValue = val;
-    *originalArgType = valueType;
+    assert(originalArgType != nullptr &&
+           "originalArgType must be provided when emittedArgValue is set")
+        *originalArgType = valueType;
   }
 
   auto rmwi = cir::AtomicFetchOp::create(

>From 5d852d8cb100ceb503bc29cfbcee876a2fa51566 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Thu, 12 Mar 2026 19:05:51 -0600
Subject: [PATCH 5/5] add semi colon

---
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 621b1bbe20d10..1a33c3cd446a7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -161,8 +161,8 @@ static mlir::Value makeBinaryAtomicValue(
   if (emittedArgValue) {
     *emittedArgValue = val;
     assert(originalArgType != nullptr &&
-           "originalArgType must be provided when emittedArgValue is set")
-        *originalArgType = valueType;
+           "originalArgType must be provided when emittedArgValue is set");
+    *originalArgType = valueType;
   }
 
   auto rmwi = cir::AtomicFetchOp::create(



More information about the cfe-commits mailing list