Skip to content

Commit 3161e16

Browse files
authored
[CIR] Atomic fetch operation (#161631)
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`.
1 parent 6d5dea6 commit 3161e16

File tree

6 files changed

+878
-24
lines changed

6 files changed

+878
-24
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4457,6 +4457,79 @@ def CIR_TryOp : CIR_Op<"try",[
44574457
// Atomic operations
44584458
//===----------------------------------------------------------------------===//
44594459

4460+
def CIR_AtomicFetchKind : CIR_I32EnumAttr<
4461+
"AtomicFetchKind", "Binary opcode for atomic fetch-and-update operations", [
4462+
I32EnumAttrCase<"Add", 0, "add">,
4463+
I32EnumAttrCase<"Sub", 1, "sub">,
4464+
I32EnumAttrCase<"And", 2, "and">,
4465+
I32EnumAttrCase<"Xor", 3, "xor">,
4466+
I32EnumAttrCase<"Or", 4, "or">,
4467+
I32EnumAttrCase<"Nand", 5, "nand">,
4468+
I32EnumAttrCase<"Max", 6, "max">,
4469+
I32EnumAttrCase<"Min", 7, "min">
4470+
]>;
4471+
4472+
def CIR_AtomicFetchOp : CIR_Op<"atomic.fetch", [
4473+
AllTypesMatch<["result", "val"]>,
4474+
TypesMatchWith<"type of 'val' must match the pointee type of 'ptr'",
4475+
"ptr", "val", "mlir::cast<cir::PointerType>($_self).getPointee()">
4476+
]> {
4477+
let summary = "Atomic fetch-and-update operation";
4478+
let description = [{
4479+
C/C++ atomic fetch-and-update operation. This operation implements the C/C++
4480+
builtin functions `__atomic_<binop>_fetch`, `__atomic_fetch_<binop>`, and
4481+
`__c11_atomic_fetch_<binop>`, where `<binop>` is one of the following binary
4482+
opcodes: `add`, `sub`, `and`, `xor`, `or`, `nand`, `max`, and `min`.
4483+
4484+
This operation takes 2 arguments: a pointer `ptr` and a value `val`. The
4485+
type of `val` must match the pointee type of `ptr`. If the binary operation
4486+
is `add`, `sub`, `max`, or `min`, the type of `val` may either be an integer
4487+
type or a floating-point type. Otherwise, `val` must be an integer.
4488+
4489+
This operation atomically loads the value from `ptr`, performs the binary
4490+
operation as indicated by `binop` on the loaded value and `val`, and stores
4491+
the result back to `ptr`. If the `fetch_first` flag is present, the result
4492+
of this operation is the old value loaded from `ptr` before the binary
4493+
operation. Otherwise, the result of this operation is the result of the
4494+
binary operation.
4495+
4496+
Example:
4497+
%res = cir.atomic.fetch add seq_cst %ptr, %val
4498+
: (!cir.ptr<!s32i>, !s32i) -> !s32i
4499+
}];
4500+
let results = (outs CIR_AnyIntOrFloatType:$result);
4501+
let arguments = (ins
4502+
Arg<CIR_PtrToIntOrFloatType, "", [MemRead, MemWrite]>:$ptr,
4503+
CIR_AnyIntOrFloatType:$val,
4504+
CIR_AtomicFetchKind:$binop,
4505+
Arg<CIR_MemOrder, "memory order">:$mem_order,
4506+
UnitAttr:$is_volatile,
4507+
UnitAttr:$fetch_first
4508+
);
4509+
4510+
let assemblyFormat = [{
4511+
$binop $mem_order
4512+
(`fetch_first` $fetch_first^)?
4513+
$ptr `,` $val
4514+
(`volatile` $is_volatile^)?
4515+
`:` `(` qualified(type($ptr)) `,` qualified(type($val)) `)`
4516+
`->` type($result) attr-dict
4517+
}];
4518+
4519+
let hasVerifier = 1;
4520+
4521+
let extraLLVMLoweringPatternDecl = [{
4522+
mlir::Value buildPostOp(cir::AtomicFetchOp op, OpAdaptor adaptor,
4523+
mlir::ConversionPatternRewriter &rewriter,
4524+
mlir::Value rmwVal, bool isInt) const;
4525+
4526+
mlir::Value buildMinMaxPostOp(cir::AtomicFetchOp op, OpAdaptor adaptor,
4527+
mlir::ConversionPatternRewriter &rewriter,
4528+
mlir::Value rmwVal, bool isInt,
4529+
bool isSigned) const;
4530+
}];
4531+
}
4532+
44604533
def CIR_AtomicXchgOp : CIR_Op<"atomic.xchg", [
44614534
AllTypesMatch<["result", "val"]>,
44624535
TypesMatchWith<"type of 'val' must match the pointee type of 'ptr'",

clang/lib/CIR/CodeGen/CIRGenAtomic.cpp

Lines changed: 119 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
346346
CIRGenBuilderTy &builder = cgf.getBuilder();
347347
mlir::Location loc = cgf.getLoc(expr->getSourceRange());
348348
auto orderAttr = cir::MemOrderAttr::get(builder.getContext(), order);
349+
cir::AtomicFetchKindAttr fetchAttr;
350+
bool fetchFirst = true;
349351

350352
switch (expr->getOp()) {
351353
case AtomicExpr::AO__c11_atomic_init:
@@ -407,6 +409,86 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
407409
opName = cir::AtomicXchgOp::getOperationName();
408410
break;
409411

412+
case AtomicExpr::AO__atomic_add_fetch:
413+
fetchFirst = false;
414+
[[fallthrough]];
415+
case AtomicExpr::AO__c11_atomic_fetch_add:
416+
case AtomicExpr::AO__atomic_fetch_add:
417+
opName = cir::AtomicFetchOp::getOperationName();
418+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
419+
cir::AtomicFetchKind::Add);
420+
break;
421+
422+
case AtomicExpr::AO__atomic_sub_fetch:
423+
fetchFirst = false;
424+
[[fallthrough]];
425+
case AtomicExpr::AO__c11_atomic_fetch_sub:
426+
case AtomicExpr::AO__atomic_fetch_sub:
427+
opName = cir::AtomicFetchOp::getOperationName();
428+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
429+
cir::AtomicFetchKind::Sub);
430+
break;
431+
432+
case AtomicExpr::AO__atomic_min_fetch:
433+
fetchFirst = false;
434+
[[fallthrough]];
435+
case AtomicExpr::AO__c11_atomic_fetch_min:
436+
case AtomicExpr::AO__atomic_fetch_min:
437+
opName = cir::AtomicFetchOp::getOperationName();
438+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
439+
cir::AtomicFetchKind::Min);
440+
break;
441+
442+
case AtomicExpr::AO__atomic_max_fetch:
443+
fetchFirst = false;
444+
[[fallthrough]];
445+
case AtomicExpr::AO__c11_atomic_fetch_max:
446+
case AtomicExpr::AO__atomic_fetch_max:
447+
opName = cir::AtomicFetchOp::getOperationName();
448+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
449+
cir::AtomicFetchKind::Max);
450+
break;
451+
452+
case AtomicExpr::AO__atomic_and_fetch:
453+
fetchFirst = false;
454+
[[fallthrough]];
455+
case AtomicExpr::AO__c11_atomic_fetch_and:
456+
case AtomicExpr::AO__atomic_fetch_and:
457+
opName = cir::AtomicFetchOp::getOperationName();
458+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
459+
cir::AtomicFetchKind::And);
460+
break;
461+
462+
case AtomicExpr::AO__atomic_or_fetch:
463+
fetchFirst = false;
464+
[[fallthrough]];
465+
case AtomicExpr::AO__c11_atomic_fetch_or:
466+
case AtomicExpr::AO__atomic_fetch_or:
467+
opName = cir::AtomicFetchOp::getOperationName();
468+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
469+
cir::AtomicFetchKind::Or);
470+
break;
471+
472+
case AtomicExpr::AO__atomic_xor_fetch:
473+
fetchFirst = false;
474+
[[fallthrough]];
475+
case AtomicExpr::AO__c11_atomic_fetch_xor:
476+
case AtomicExpr::AO__atomic_fetch_xor:
477+
opName = cir::AtomicFetchOp::getOperationName();
478+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
479+
cir::AtomicFetchKind::Xor);
480+
break;
481+
482+
case AtomicExpr::AO__atomic_nand_fetch:
483+
fetchFirst = false;
484+
[[fallthrough]];
485+
case AtomicExpr::AO__c11_atomic_fetch_nand:
486+
case AtomicExpr::AO__atomic_fetch_nand:
487+
opName = cir::AtomicFetchOp::getOperationName();
488+
fetchAttr = cir::AtomicFetchKindAttr::get(builder.getContext(),
489+
cir::AtomicFetchKind::Nand);
490+
break;
491+
410492
case AtomicExpr::AO__atomic_test_and_set: {
411493
auto op = cir::AtomicTestAndSetOp::create(
412494
builder, loc, ptr.getPointer(), order,
@@ -450,74 +532,50 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
450532
case AtomicExpr::AO__scoped_atomic_exchange_n:
451533
case AtomicExpr::AO__scoped_atomic_exchange:
452534

453-
case AtomicExpr::AO__atomic_add_fetch:
454535
case AtomicExpr::AO__scoped_atomic_add_fetch:
455536

456-
case AtomicExpr::AO__c11_atomic_fetch_add:
457537
case AtomicExpr::AO__hip_atomic_fetch_add:
458538
case AtomicExpr::AO__opencl_atomic_fetch_add:
459-
case AtomicExpr::AO__atomic_fetch_add:
460539
case AtomicExpr::AO__scoped_atomic_fetch_add:
461540

462-
case AtomicExpr::AO__atomic_sub_fetch:
463541
case AtomicExpr::AO__scoped_atomic_sub_fetch:
464542

465-
case AtomicExpr::AO__c11_atomic_fetch_sub:
466543
case AtomicExpr::AO__hip_atomic_fetch_sub:
467544
case AtomicExpr::AO__opencl_atomic_fetch_sub:
468-
case AtomicExpr::AO__atomic_fetch_sub:
469545
case AtomicExpr::AO__scoped_atomic_fetch_sub:
470546

471-
case AtomicExpr::AO__atomic_min_fetch:
472547
case AtomicExpr::AO__scoped_atomic_min_fetch:
473548

474-
case AtomicExpr::AO__c11_atomic_fetch_min:
475549
case AtomicExpr::AO__hip_atomic_fetch_min:
476550
case AtomicExpr::AO__opencl_atomic_fetch_min:
477-
case AtomicExpr::AO__atomic_fetch_min:
478551
case AtomicExpr::AO__scoped_atomic_fetch_min:
479552

480-
case AtomicExpr::AO__atomic_max_fetch:
481553
case AtomicExpr::AO__scoped_atomic_max_fetch:
482554

483-
case AtomicExpr::AO__c11_atomic_fetch_max:
484555
case AtomicExpr::AO__hip_atomic_fetch_max:
485556
case AtomicExpr::AO__opencl_atomic_fetch_max:
486-
case AtomicExpr::AO__atomic_fetch_max:
487557
case AtomicExpr::AO__scoped_atomic_fetch_max:
488558

489-
case AtomicExpr::AO__atomic_and_fetch:
490559
case AtomicExpr::AO__scoped_atomic_and_fetch:
491560

492-
case AtomicExpr::AO__c11_atomic_fetch_and:
493561
case AtomicExpr::AO__hip_atomic_fetch_and:
494562
case AtomicExpr::AO__opencl_atomic_fetch_and:
495-
case AtomicExpr::AO__atomic_fetch_and:
496563
case AtomicExpr::AO__scoped_atomic_fetch_and:
497564

498-
case AtomicExpr::AO__atomic_or_fetch:
499565
case AtomicExpr::AO__scoped_atomic_or_fetch:
500566

501-
case AtomicExpr::AO__c11_atomic_fetch_or:
502567
case AtomicExpr::AO__hip_atomic_fetch_or:
503568
case AtomicExpr::AO__opencl_atomic_fetch_or:
504-
case AtomicExpr::AO__atomic_fetch_or:
505569
case AtomicExpr::AO__scoped_atomic_fetch_or:
506570

507-
case AtomicExpr::AO__atomic_xor_fetch:
508571
case AtomicExpr::AO__scoped_atomic_xor_fetch:
509572

510-
case AtomicExpr::AO__c11_atomic_fetch_xor:
511573
case AtomicExpr::AO__hip_atomic_fetch_xor:
512574
case AtomicExpr::AO__opencl_atomic_fetch_xor:
513-
case AtomicExpr::AO__atomic_fetch_xor:
514575
case AtomicExpr::AO__scoped_atomic_fetch_xor:
515576

516-
case AtomicExpr::AO__atomic_nand_fetch:
517577
case AtomicExpr::AO__scoped_atomic_nand_fetch:
518578

519-
case AtomicExpr::AO__c11_atomic_fetch_nand:
520-
case AtomicExpr::AO__atomic_fetch_nand:
521579
case AtomicExpr::AO__scoped_atomic_fetch_nand:
522580
cgf.cgm.errorNYI(expr->getSourceRange(), "emitAtomicOp: expr op NYI");
523581
return;
@@ -531,9 +589,13 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
531589
mlir::Operation *rmwOp = builder.create(loc, builder.getStringAttr(opName),
532590
atomicOperands, atomicResTys);
533591

592+
if (fetchAttr)
593+
rmwOp->setAttr("binop", fetchAttr);
534594
rmwOp->setAttr("mem_order", orderAttr);
535595
if (expr->isVolatile())
536596
rmwOp->setAttr("is_volatile", builder.getUnitAttr());
597+
if (fetchFirst && opName == cir::AtomicFetchOp::getOperationName())
598+
rmwOp->setAttr("fetch_first", builder.getUnitAttr());
537599

538600
mlir::Value result = rmwOp->getResult(0);
539601
builder.createStore(loc, result, dest);
@@ -629,8 +691,41 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
629691
isWeakExpr = e->getWeak();
630692
break;
631693

694+
case AtomicExpr::AO__c11_atomic_fetch_add:
695+
case AtomicExpr::AO__c11_atomic_fetch_sub:
696+
if (memTy->isPointerType()) {
697+
cgm.errorNYI(e->getSourceRange(),
698+
"atomic fetch-and-add and fetch-and-sub for pointers");
699+
return RValue::get(nullptr);
700+
}
701+
[[fallthrough]];
702+
case AtomicExpr::AO__atomic_fetch_add:
703+
case AtomicExpr::AO__atomic_fetch_max:
704+
case AtomicExpr::AO__atomic_fetch_min:
705+
case AtomicExpr::AO__atomic_fetch_sub:
706+
case AtomicExpr::AO__atomic_add_fetch:
707+
case AtomicExpr::AO__atomic_max_fetch:
708+
case AtomicExpr::AO__atomic_min_fetch:
709+
case AtomicExpr::AO__atomic_sub_fetch:
710+
case AtomicExpr::AO__c11_atomic_fetch_max:
711+
case AtomicExpr::AO__c11_atomic_fetch_min:
712+
shouldCastToIntPtrTy = !memTy->isFloatingType();
713+
[[fallthrough]];
714+
715+
case AtomicExpr::AO__atomic_fetch_and:
716+
case AtomicExpr::AO__atomic_fetch_nand:
717+
case AtomicExpr::AO__atomic_fetch_or:
718+
case AtomicExpr::AO__atomic_fetch_xor:
719+
case AtomicExpr::AO__atomic_and_fetch:
720+
case AtomicExpr::AO__atomic_nand_fetch:
721+
case AtomicExpr::AO__atomic_or_fetch:
722+
case AtomicExpr::AO__atomic_xor_fetch:
632723
case AtomicExpr::AO__atomic_exchange_n:
633724
case AtomicExpr::AO__atomic_store_n:
725+
case AtomicExpr::AO__c11_atomic_fetch_and:
726+
case AtomicExpr::AO__c11_atomic_fetch_nand:
727+
case AtomicExpr::AO__c11_atomic_fetch_or:
728+
case AtomicExpr::AO__c11_atomic_fetch_xor:
634729
case AtomicExpr::AO__c11_atomic_exchange:
635730
case AtomicExpr::AO__c11_atomic_store:
636731
val1 = emitValToTemp(*this, e->getVal1());

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,6 +2940,21 @@ mlir::LogicalResult cir::ThrowOp::verify() {
29402940
return failure();
29412941
}
29422942

2943+
//===----------------------------------------------------------------------===//
2944+
// AtomicFetchOp
2945+
//===----------------------------------------------------------------------===//
2946+
2947+
LogicalResult cir::AtomicFetchOp::verify() {
2948+
if (getBinop() != cir::AtomicFetchKind::Add &&
2949+
getBinop() != cir::AtomicFetchKind::Sub &&
2950+
getBinop() != cir::AtomicFetchKind::Max &&
2951+
getBinop() != cir::AtomicFetchKind::Min &&
2952+
!mlir::isa<cir::IntType>(getVal().getType()))
2953+
return emitError("only atomic add, sub, max, and min operation could "
2954+
"operate on floating-point values");
2955+
return success();
2956+
}
2957+
29432958
//===----------------------------------------------------------------------===//
29442959
// TypeInfoAttr
29452960
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)