[clang] 1422665 - [CIR] Add support for __atomic_fetch_uinc and __atomic_fetch_udec (#188050)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 26 08:01:05 PDT 2026
Author: Sirui Mu
Date: 2026-03-26T23:01:00+08:00
New Revision: 1422665595d9aa596666cb15f5ef83623fa8d25e
URL: https://github.com/llvm/llvm-project/commit/1422665595d9aa596666cb15f5ef83623fa8d25e
DIFF: https://github.com/llvm/llvm-project/commit/1422665595d9aa596666cb15f5ef83623fa8d25e.diff
LOG: [CIR] Add support for __atomic_fetch_uinc and __atomic_fetch_udec (#188050)
This patch adds CIRGen and LLVM lowering support for the
`__atomic_fetch_uinc` and the `__atomic_fetch_udec` built-in functions.
Assisted-by: Claude Opus 4.6
Added:
Modified:
clang/include/clang/CIR/Dialect/IR/CIROps.td
clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
clang/test/CIR/CodeGen/atomic.c
clang/test/CIR/IR/atomic.cir
Removed:
################################################################################
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index b15dc30ffb87d..329939dc1b2e9 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -7297,7 +7297,9 @@ def CIR_AtomicFetchKind : CIR_I32EnumAttr<
I32EnumAttrCase<"Or", 4, "or">,
I32EnumAttrCase<"Nand", 5, "nand">,
I32EnumAttrCase<"Max", 6, "max">,
- I32EnumAttrCase<"Min", 7, "min">
+ I32EnumAttrCase<"Min", 7, "min">,
+ I32EnumAttrCase<"UIncWrap", 8, "uinc_wrap">,
+ I32EnumAttrCase<"UDecWrap", 9, "udec_wrap">
]>;
def CIR_AtomicFetchOp : CIR_Op<"atomic.fetch", [
@@ -7310,7 +7312,8 @@ def CIR_AtomicFetchOp : CIR_Op<"atomic.fetch", [
C/C++ atomic fetch-and-update operation. This operation implements the C/C++
builtin functions `__atomic_<binop>_fetch`, `__atomic_fetch_<binop>`, and
`__c11_atomic_fetch_<binop>`, where `<binop>` is one of the following binary
- opcodes: `add`, `sub`, `and`, `xor`, `or`, `nand`, `max`, and `min`.
+ opcodes: `add`, `sub`, `and`, `xor`, `or`, `nand`, `max`, `min`,
+ `uinc_wrap`, and `udec_wrap`.
This operation takes 2 arguments: a pointer `ptr` and a value `val`. The
type of `val` must match the pointee type of `ptr`. If the binary operation
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 1b55c317e0e81..6fca3cd0444aa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -637,6 +637,20 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
return;
}
+ case AtomicExpr::AO__atomic_fetch_uinc:
+ case AtomicExpr::AO__scoped_atomic_fetch_uinc:
+ opName = cir::AtomicFetchOp::getOperationName();
+ fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
+ cir::AtomicFetchKind::UIncWrap);
+ break;
+
+ case AtomicExpr::AO__atomic_fetch_udec:
+ case AtomicExpr::AO__scoped_atomic_fetch_udec:
+ opName = cir::AtomicFetchOp::getOperationName();
+ fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
+ cir::AtomicFetchKind::UDecWrap);
+ break;
+
case AtomicExpr::AO__opencl_atomic_init:
case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
@@ -674,11 +688,6 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
case AtomicExpr::AO__hip_atomic_fetch_xor:
case AtomicExpr::AO__opencl_atomic_fetch_xor:
-
- case AtomicExpr::AO__scoped_atomic_fetch_uinc:
- case AtomicExpr::AO__scoped_atomic_fetch_udec:
- case AtomicExpr::AO__atomic_fetch_uinc:
- case AtomicExpr::AO__atomic_fetch_udec:
cgf.cgm.errorNYI(expr->getSourceRange(), "emitAtomicOp: expr op NYI");
return;
}
@@ -1000,6 +1009,8 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
case AtomicExpr::AO__scoped_atomic_xor_fetch:
case AtomicExpr::AO__scoped_atomic_store_n:
case AtomicExpr::AO__scoped_atomic_exchange_n:
+ case AtomicExpr::AO__atomic_fetch_uinc:
+ case AtomicExpr::AO__atomic_fetch_udec:
val1 = emitValToTemp(*this, e->getVal1());
break;
}
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 9fa0e720e1591..ba89fbe3091bc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1094,11 +1094,16 @@ getLLVMAtomicBinOp(cir::AtomicFetchKind k, bool isInt, bool isSignedInt) {
return isSignedInt ? mlir::LLVM::AtomicBinOp::min
: mlir::LLVM::AtomicBinOp::umin;
}
+ case cir::AtomicFetchKind::UIncWrap:
+ return mlir::LLVM::AtomicBinOp::uinc_wrap;
+ case cir::AtomicFetchKind::UDecWrap:
+ return mlir::LLVM::AtomicBinOp::udec_wrap;
}
llvm_unreachable("Unknown atomic fetch opcode");
}
-static llvm::StringLiteral getLLVMBinop(cir::AtomicFetchKind k, bool isInt) {
+static llvm::StringLiteral getLLVMBinopForPostAtomic(cir::AtomicFetchKind k,
+ bool isInt) {
switch (k) {
case cir::AtomicFetchKind::Add:
return isInt ? mlir::LLVM::AddOp::getOperationName()
@@ -1118,6 +1123,9 @@ static llvm::StringLiteral getLLVMBinop(cir::AtomicFetchKind k, bool isInt) {
case cir::AtomicFetchKind::Max:
case cir::AtomicFetchKind::Min:
llvm_unreachable("handled in buildMinMaxPostOp");
+ case cir::AtomicFetchKind::UIncWrap:
+ case cir::AtomicFetchKind::UDecWrap:
+ llvm_unreachable("uinc_wrap and udec_wrap are always fetch_first");
}
llvm_unreachable("Unknown atomic fetch opcode");
}
@@ -1130,7 +1138,8 @@ mlir::Value CIRToLLVMAtomicFetchOpLowering::buildPostOp(
SmallVector<mlir::Type> atomicResTys = {rmwVal.getType()};
return rewriter
.create(op.getLoc(),
- rewriter.getStringAttr(getLLVMBinop(op.getBinop(), isInt)),
+ rewriter.getStringAttr(
+ getLLVMBinopForPostAtomic(op.getBinop(), isInt)),
atomicOperands, atomicResTys, {})
->getResult(0);
}
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index 6476f35009e3e..50ed62cc9d7d1 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -2951,3 +2951,33 @@ int atomic_load_and_store_dynamic_order(int *ptr, int order) {
// OGCG: [[CONTINUE_BLK]]:
// OGCG-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
}
+
+int atomic_fetch_uinc(int *ptr, int value) {
+ // CIR-LABEL: @atomic_fetch_uinc
+ // LLVM-LABEL: @atomic_fetch_uinc
+ // OGCG-LABEL: @atomic_fetch_uinc
+
+ return __atomic_fetch_uinc(ptr, value, __ATOMIC_SEQ_CST);
+ // CIR: %{{.+}} = cir.atomic.fetch uinc_wrap seq_cst syncscope(system) fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i
+
+ // LLVM: %[[RES:.+]] = atomicrmw uinc_wrap ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4
+
+ // OGCG: %[[RES:.+]] = atomicrmw uinc_wrap ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4
+}
+
+int atomic_fetch_udec(int *ptr, int value) {
+ // CIR-LABEL: @atomic_fetch_udec
+ // LLVM-LABEL: @atomic_fetch_udec
+ // OGCG-LABEL: @atomic_fetch_udec
+
+ return __atomic_fetch_udec(ptr, value, __ATOMIC_SEQ_CST);
+ // CIR: %{{.+}} = cir.atomic.fetch udec_wrap seq_cst syncscope(system) fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i
+
+ // LLVM: %[[RES:.+]] = atomicrmw udec_wrap ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4
+
+ // OGCG: %[[RES:.+]] = atomicrmw udec_wrap ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4
+}
diff --git a/clang/test/CIR/IR/atomic.cir b/clang/test/CIR/IR/atomic.cir
index 5d186f3a49cb6..ccb7108a950ef 100644
--- a/clang/test/CIR/IR/atomic.cir
+++ b/clang/test/CIR/IR/atomic.cir
@@ -32,3 +32,17 @@ cir.func @atomic_cmpxchg(%ptr: !cir.ptr<!s32i>, %expected: !s32i, %desired: !s32
// CHECK: cir.atomic.cmpxchg weak success(seq_cst) failure(acquire) syncscope(system) %{{.+}}, %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i, !s32i) -> (!s32i, !cir.bool)
cir.return
}
+
+cir.func @atomic_fetch_uinc_wrap(%ptr: !cir.ptr<!s32i>, %val: !s32i) {
+ // CHECK-LABEL: @atomic_fetch_uinc_wrap
+ %0 = cir.atomic.fetch uinc_wrap seq_cst syncscope(system) fetch_first %ptr, %val : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ // CHECK: cir.atomic.fetch uinc_wrap seq_cst syncscope(system) fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ cir.return
+}
+
+cir.func @atomic_fetch_udec_wrap(%ptr: !cir.ptr<!s32i>, %val: !s32i) {
+ // CHECK-LABEL: @atomic_fetch_udec_wrap
+ %0 = cir.atomic.fetch udec_wrap seq_cst syncscope(system) fetch_first %ptr, %val : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ // CHECK: cir.atomic.fetch udec_wrap seq_cst syncscope(system) fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ cir.return
+}
More information about the cfe-commits
mailing list