llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Sirui Mu (Lancern) <details> <summary>Changes</summary> This patch adds CIR support for atomic fetch-and-update operations, including the intrinsic functions `__atomic_fetch_<binop>`, `__atomic_<binop>_fetch`, and `__c11_atomic_fetch_<binop>`, where `<binop>` could be `add`, `sub`, `max`, `min`, `and`, `or`, `xor`, and `nand`. --- Patch is 38.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/161631.diff 6 Files Affected: - (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+72) - (modified) clang/lib/CIR/CodeGen/CIRGenAtomic.cpp (+119-24) - (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+13) - (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+133) - (modified) clang/test/CIR/CodeGen/atomic.c (+429) - (added) clang/test/CIR/IR/invalid-atomic.cir (+7) ``````````diff diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index f857cf82a5192..80958344d7556 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4151,6 +4151,78 @@ def CIR_ThrowOp : CIR_Op<"throw"> { // Atomic operations //===----------------------------------------------------------------------===// +def CIR_AtomicFetchKind : CIR_I32EnumAttr< + "AtomicFetchKind", "Binary opcode for atomic fetch-and-update operations", [ + I32EnumAttrCase<"Add", 0, "add">, + I32EnumAttrCase<"Sub", 1, "sub">, + I32EnumAttrCase<"And", 2, "and">, + I32EnumAttrCase<"Xor", 3, "xor">, + I32EnumAttrCase<"Or", 4, "or">, + I32EnumAttrCase<"Nand", 5, "nand">, + I32EnumAttrCase<"Max", 6, "max">, + I32EnumAttrCase<"Min", 7, "min"> +]>; + +def CIR_AtomicFetchOp : CIR_Op<"atomic.fetch", [ + AllTypesMatch<["result", "val"]>, + TypesMatchWith<"type of 'val' must match the pointee type of 'ptr'", + "ptr", "val", "mlir::cast<cir::PointerType>($_self).getPointee()"> +]> { + let summary = "Atomic fetch-and-update operation"; + let description = [{ + 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`. + + This operation takes 2 arguments: a pointer `ptr` and a value `val`. The + type of `val` must match the pointee type of `ptr`. And the type of `val` + must either be an integer or a floating-point type. If the binary operation + is neither `add` nor `sub`, then `val` must be an integer. + + This operation atomically loads the value from `ptr`, performs the binary + operation as indicated by `binop` on the loaded value and `val`, and stores + the result back to `ptr`. If the `fetch_first` flag is present, the result + of this operation is the old value loaded from `ptr` before the binary + operation. Otherwise, the result of this operation is the result of the + binary operation. + + Example: + %res = cir.atomic.fetch add seq_cst %ptr, %val + : (!cir.ptr<!s32i>, !s32i) -> !s32i + }]; + let results = (outs CIR_AnyIntOrFloatType:$result); + let arguments = (ins + Arg<CIR_PtrToIntOrFloatType, "", [MemRead, MemWrite]>:$ptr, + CIR_AnyIntOrFloatType:$val, + CIR_AtomicFetchKind:$binop, + Arg<CIR_MemOrder, "memory order">:$mem_order, + UnitAttr:$is_volatile, + UnitAttr:$fetch_first + ); + + let assemblyFormat = [{ + $binop $mem_order + (`fetch_first` $fetch_first^)? + $ptr `,` $val + (`volatile` $is_volatile^)? + `:` `(` qualified(type($ptr)) `,` qualified(type($val)) `)` + `->` type($result) attr-dict + }]; + + let hasVerifier = 1; + + let extraLLVMLoweringPatternDecl = [{ + mlir::Value buildPostOp(cir::AtomicFetchOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter, + mlir::Value rmwVal, bool isInt) const; + + mlir::Value buildMinMaxPostOp(cir::AtomicFetchOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter, + mlir::Value rmwVal, bool isSigned) const; + }]; +} + def CIR_AtomicXchg : CIR_Op<"atomic.xchg", [ AllTypesMatch<["result", "val"]>, TypesMatchWith<"type of 'val' must match the pointee type of 'ptr'", diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp index e943b0252bf4e..d7749f8acbee2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp @@ -346,6 +346,8 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, CIRGenBuilderTy &builder = cgf.getBuilder(); mlir::Location loc = cgf.getLoc(expr->getSourceRange()); auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order); + cir::AtomicFetchKindAttr fetchAttr; + bool fetchFirst = true; switch (expr->getOp()) { case AtomicExpr::AO__c11_atomic_init: @@ -407,6 +409,86 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, opName = cir::AtomicXchg::getOperationName(); break; + case AtomicExpr::AO__atomic_add_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__atomic_fetch_add: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::Add); + break; + + case AtomicExpr::AO__atomic_sub_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__atomic_fetch_sub: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::Sub); + break; + + case AtomicExpr::AO__atomic_min_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_min: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::Min); + break; + + case AtomicExpr::AO__atomic_max_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_max: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::Max); + break; + + case AtomicExpr::AO__atomic_and_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__atomic_fetch_and: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::And); + break; + + case AtomicExpr::AO__atomic_or_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__atomic_fetch_or: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::Or); + break; + + case AtomicExpr::AO__atomic_xor_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__atomic_fetch_xor: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::Xor); + break; + + case AtomicExpr::AO__atomic_nand_fetch: + fetchFirst = false; + [[fallthrough]]; + case AtomicExpr::AO__c11_atomic_fetch_nand: + case AtomicExpr::AO__atomic_fetch_nand: + opName = cir::AtomicFetchOp::getOperationName(); + fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(), + cir::AtomicFetchKind::Nand); + break; + case AtomicExpr::AO__opencl_atomic_init: case AtomicExpr::AO__hip_atomic_compare_exchange_strong: @@ -433,74 +515,50 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, case AtomicExpr::AO__scoped_atomic_exchange_n: case AtomicExpr::AO__scoped_atomic_exchange: - case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__scoped_atomic_add_fetch: - case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__hip_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_add: - case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__scoped_atomic_fetch_add: - case AtomicExpr::AO__atomic_sub_fetch: case AtomicExpr::AO__scoped_atomic_sub_fetch: - case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__hip_atomic_fetch_sub: case AtomicExpr::AO__opencl_atomic_fetch_sub: - case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__scoped_atomic_fetch_sub: - case AtomicExpr::AO__atomic_min_fetch: case AtomicExpr::AO__scoped_atomic_min_fetch: - case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__hip_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_min: - case AtomicExpr::AO__atomic_fetch_min: case AtomicExpr::AO__scoped_atomic_fetch_min: - case AtomicExpr::AO__atomic_max_fetch: case AtomicExpr::AO__scoped_atomic_max_fetch: - case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__hip_atomic_fetch_max: case AtomicExpr::AO__opencl_atomic_fetch_max: - case AtomicExpr::AO__atomic_fetch_max: case AtomicExpr::AO__scoped_atomic_fetch_max: - case AtomicExpr::AO__atomic_and_fetch: case AtomicExpr::AO__scoped_atomic_and_fetch: - case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__hip_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_and: - case AtomicExpr::AO__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__c11_atomic_fetch_or: case AtomicExpr::AO__hip_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_or: - case AtomicExpr::AO__atomic_fetch_or: case AtomicExpr::AO__scoped_atomic_fetch_or: - case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__scoped_atomic_xor_fetch: - case AtomicExpr::AO__c11_atomic_fetch_xor: case AtomicExpr::AO__hip_atomic_fetch_xor: case AtomicExpr::AO__opencl_atomic_fetch_xor: - case AtomicExpr::AO__atomic_fetch_xor: case AtomicExpr::AO__scoped_atomic_fetch_xor: - case AtomicExpr::AO__atomic_nand_fetch: case AtomicExpr::AO__scoped_atomic_nand_fetch: - case AtomicExpr::AO__c11_atomic_fetch_nand: - case AtomicExpr::AO__atomic_fetch_nand: case AtomicExpr::AO__scoped_atomic_fetch_nand: case AtomicExpr::AO__atomic_test_and_set: @@ -518,9 +576,13 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest, mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName), atomicOperands, atomicResTys); + if (fetchAttr) + rmwOp->setAttr("binop", fetchAttr); rmwOp->setAttr("mem_order", orderAttr); if (expr->isVolatile()) rmwOp->setAttr("is_volatile", builder.getUnitAttr()); + if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName()) + rmwOp->setAttr("fetch_first", builder.getUnitAttr()); mlir::Value result = rmwOp->getResult(0); builder.createStore(loc, result, dest); @@ -614,8 +676,41 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) { isWeakExpr = e->getWeak(); break; + case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__c11_atomic_fetch_sub: + if (memTy->isPointerType()) { + cgm.errorNYI(e->getSourceRange(), + "atomic fetch-and-add and fetch-and-sub for pointers"); + return RValue::get(nullptr); + } + [[fallthrough]]; + case AtomicExpr::AO__atomic_fetch_add: + case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_fetch_sub: + case AtomicExpr::AO__atomic_add_fetch: + case AtomicExpr::AO__atomic_max_fetch: + case AtomicExpr::AO__atomic_min_fetch: + case AtomicExpr::AO__atomic_sub_fetch: + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__c11_atomic_fetch_min: + shouldCastToIntPtrTy = !memTy->isFloatingType(); + [[fallthrough]]; + + case AtomicExpr::AO__atomic_fetch_and: + case AtomicExpr::AO__atomic_fetch_nand: + case AtomicExpr::AO__atomic_fetch_or: + case AtomicExpr::AO__atomic_fetch_xor: + case AtomicExpr::AO__atomic_and_fetch: + case AtomicExpr::AO__atomic_nand_fetch: + case AtomicExpr::AO__atomic_or_fetch: + case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__atomic_store_n: + case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__c11_atomic_fetch_nand: + case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__c11_atomic_fetch_xor: case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__c11_atomic_store: val1 = emitValToTemp(*this, e->getVal1()); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index fb87036fdfe21..2444620a57dae 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2831,6 +2831,19 @@ LogicalResult cir::AtomicCmpXchg::verify() { return success(); } +//===----------------------------------------------------------------------===// +// AtomicFetchOp +//===----------------------------------------------------------------------===// + +LogicalResult cir::AtomicFetchOp::verify() { + if (getBinop() != cir::AtomicFetchKind::Add && + getBinop() != cir::AtomicFetchKind::Sub && + !mlir::isa<cir::IntType>(getVal().getType())) + return emitError("only atomic add and atomic sub operation could operate " + "on floating-point values"); + return success(); +} + //===----------------------------------------------------------------------===// // TypeInfoAttr //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 22f069d9cead0..ae5360633317e 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -729,6 +729,139 @@ mlir::LogicalResult CIRToLLVMAtomicXchgLowering::matchAndRewrite( return mlir::success(); } +static mlir::LLVM::AtomicBinOp +getLLVMAtomicBinOp(cir::AtomicFetchKind k, bool isInt, bool isSignedInt) { + switch (k) { + case cir::AtomicFetchKind::Add: + return isInt ? mlir::LLVM::AtomicBinOp::add : mlir::LLVM::AtomicBinOp::fadd; + case cir::AtomicFetchKind::Sub: + return isInt ? mlir::LLVM::AtomicBinOp::sub : mlir::LLVM::AtomicBinOp::fsub; + case cir::AtomicFetchKind::And: + return mlir::LLVM::AtomicBinOp::_and; + case cir::AtomicFetchKind::Xor: + return mlir::LLVM::AtomicBinOp::_xor; + case cir::AtomicFetchKind::Or: + return mlir::LLVM::AtomicBinOp::_or; + case cir::AtomicFetchKind::Nand: + return mlir::LLVM::AtomicBinOp::nand; + case cir::AtomicFetchKind::Max: { + if (!isInt) + return mlir::LLVM::AtomicBinOp::fmax; + return isSignedInt ? mlir::LLVM::AtomicBinOp::max + : mlir::LLVM::AtomicBinOp::umax; + } + case cir::AtomicFetchKind::Min: { + if (!isInt) + return mlir::LLVM::AtomicBinOp::fmin; + return isSignedInt ? mlir::LLVM::AtomicBinOp::min + : mlir::LLVM::AtomicBinOp::umin; + } + } + llvm_unreachable("Unknown atomic fetch opcode"); +} + +static llvm::StringLiteral getLLVMBinop(cir::AtomicFetchKind k, bool isInt) { + switch (k) { + case cir::AtomicFetchKind::Add: + return isInt ? mlir::LLVM::AddOp::getOperationName() + : mlir::LLVM::FAddOp::getOperationName(); + case cir::AtomicFetchKind::Sub: + return isInt ? mlir::LLVM::SubOp::getOperationName() + : mlir::LLVM::FSubOp::getOperationName(); + case cir::AtomicFetchKind::And: + return mlir::LLVM::AndOp::getOperationName(); + case cir::AtomicFetchKind::Xor: + return mlir::LLVM::XOrOp::getOperationName(); + case cir::AtomicFetchKind::Or: + return mlir::LLVM::OrOp::getOperationName(); + case cir::AtomicFetchKind::Nand: + // There's no nand binop in LLVM, this is later fixed with a not. + return mlir::LLVM::AndOp::getOperationName(); + case cir::AtomicFetchKind::Max: + case cir::AtomicFetchKind::Min: + llvm_unreachable("handled in buildMinMaxPostOp"); + } + llvm_unreachable("Unknown atomic fetch opcode"); +} + +mlir::Value CIRToLLVMAtomicFetchOpLowering::buildPostOp( + cir::AtomicFetchOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter, mlir::Value rmwVal, + bool isInt) const { + SmallVector<mlir::Value> atomicOperands = {rmwVal, adaptor.getVal()}; + SmallVector<mlir::Type> atomicResTys = {rmwVal.getType()}; + return rewriter + .create(op.getLoc(), + rewriter.getStringAttr(getLLVMBinop(op.getBinop(), isInt)), + atomicOperands, atomicResTys, {}) + ->getResult(0); +} + +mlir::Value CIRToLLVMAtomicFetchOpLowering::buildMinMaxPostOp( + cir::AtomicFetchOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter, mlir::Value rmwVal, + bool isSigned) const { + mlir::Location loc = op.getLoc(); + mlir::LLVM::ICmpPredicate pred; + if (op.getBinop() == cir::AtomicFetchKind::Max) { + pred = isSigned ? mlir::LLVM::ICmpPredicate::sgt + : mlir::LLVM::ICmpPredicate::ugt; + } else { // Min + pred = isSigned ? mlir::LLVM::ICmpPredicate::slt + : mlir::LLVM::ICmpPredicate::ult; + } + + auto cmp = mlir::LLVM::ICmpOp::create( + rewriter, loc, + mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(), pred), rmwVal, + adaptor.getVal()); + return mlir::LLVM::SelectOp::create(rewriter, loc, cmp, rmwVal, + adaptor.getVal()); +} + +mlir::LogicalResult CIRToLLVMAtomicFetchOpLowering::matchAndRewrite( + cir::AtomicFetchOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + bool isInt = false; + bool isSignedInt = false; + if (auto intTy = mlir::dyn_cast<cir::IntType>(op.getVal().getType())) { + isInt = true; + isSignedInt = intTy.isSigned(); + } else if (mlir::isa<cir::SingleType, cir::DoubleType>( + op.getVal().getType())) { + isInt = false; + } else { + return op.emitError() << "Unsupported type: " << op.getVal().getType(); + } + + mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(op.getMemOrder()); + mlir::LLVM::AtomicBinOp llvmBinOp = + getLLVMAtomicBinOp(op.getBinop(), isInt, isSignedInt); + auto rmwVal = mlir::LLVM::AtomicRMWOp::create(rewriter, op.getLoc(), + llvmBinOp, adaptor.getPtr(), + adaptor.getVal(), llvmOrder); + + mlir::Value result = rmwVal.getResult(); + if (!op.getFetchFirst()) { + if (op.getBinop() == cir::AtomicFetchKind::Max || + op.getBinop() == cir::AtomicFetchKind::Min) + result = buildMinMaxPostOp(op, adaptor, rewriter, rmwVal.getRes(), + isSignedInt); + else + result = buildPostOp(op, adaptor, rewriter, rmwVal.getRes(), isInt); + + // Compensate lack of nand binop in LLVM IR. + if (op.getBinop() == cir::AtomicFetchKind::Nand) { + auto negOne = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), + result.getType(), -1); + result = mlir::LLVM::XOrOp::create(rewriter, op.getLoc(), result, negOne); + } + } + + rewriter.replaceOp(op, result); + return mlir::success(); +} + mlir::LogicalResult CIRToLLVMBitClrsbOpLowering::matchAndRewrite( cir::BitClrsbOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c index 76289c597a2b5..701795a877ed4 100644 --- a/clang/test/CIR/CodeGen/atomic.c +++ b/clang/test/CIR/CodeGen/atomic.c @@ -514,3 +514,432 @@ void atomic_exchange_n(int *ptr, int value) { // OGCG: %{{.+}} = atomicrmw xchg ptr %{{.+}}, i32 %{{.+}} acq_rel, align 4 // OGCG: %{{.+}} = atomicrmw xchg ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4 } + +int atomic_fetch_add(int *ptr, int value) { + // CIR-LABEL: @atomic_fetch_add + // LLVM-LABEL: @atomic_fetch_add + // OGCG-LABEL: @atomic_fetch_add + + return __atomic_fetch_add(ptr, value, __ATOMIC_SEQ_CST); + // CIR: %{{.+}} = cir.atomic.fetch add seq_cst fetch_first %{{.+}}, %{{.+}} : (!cir.ptr<!s32i>, !s32i) -> !s32i + + // LLVM: %[[RES:.+]] = atomicrmw... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/161631 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
