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 +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
