@@ -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+
44604533def CIR_AtomicXchgOp : CIR_Op<"atomic.xchg", [
44614534 AllTypesMatch<["result", "val"]>,
44624535 TypesMatchWith<"type of 'val' must match the pointee type of 'ptr'",
@@ -4557,4 +4630,66 @@ def CIR_AtomicCmpXchgOp : CIR_Op<"atomic.cmpxchg", [
45574630 }];
45584631}
45594632
4633+ def CIR_AtomicTestAndSetOp : CIR_Op<"atomic.test_and_set"> {
4634+ let summary = "Atomic test and set";
4635+ let description = [{
4636+ C/C++ atomic test and set operation. Implements the builtin function
4637+ `__atomic_test_and_set`.
4638+
4639+ The operation takes as its only operand a pointer to an 8-bit signed
4640+ integer. The operation atomically set the integer to an implementation-
4641+ defined non-zero "set" value. The result of the operation is a boolean value
4642+ indicating whether the previous value of the integer was the "set" value.
4643+
4644+ Example:
4645+ ```mlir
4646+ %res = cir.atomic.test_and_set seq_cst %ptr : !cir.ptr<!s8i> -> !cir.bool
4647+ ```
4648+ }];
4649+
4650+ let arguments = (ins
4651+ Arg<CIR_PtrToType<CIR_SInt8>, "", [MemRead, MemWrite]>:$ptr,
4652+ Arg<CIR_MemOrder, "memory order">:$mem_order,
4653+ OptionalAttr<I64Attr>:$alignment,
4654+ UnitAttr:$is_volatile
4655+ );
4656+
4657+ let results = (outs CIR_BoolType:$result);
4658+
4659+ let assemblyFormat = [{
4660+ $mem_order $ptr
4661+ (`volatile` $is_volatile^)?
4662+ `:` qualified(type($ptr)) `->` qualified(type($result)) attr-dict
4663+ }];
4664+ }
4665+
4666+ def CIR_AtomicClearOp : CIR_Op<"atomic.clear"> {
4667+ let summary = "Atomic clear";
4668+ let description = [{
4669+ C/C++ atomic clear operation. Implements the builtin function
4670+ `__atomic_clear`.
4671+
4672+ The operation takes as its only operand a pointer to an 8-bit signed
4673+ integer. The operation atomically sets the integer to zero.
4674+
4675+ Example:
4676+ ```mlir
4677+ cir.atomic.clear seq_cst %ptr : !cir.ptr<!s8i>
4678+ ```
4679+ }];
4680+
4681+ let arguments = (ins
4682+ Arg<CIR_PtrToType<CIR_SInt8>, "", [MemRead, MemWrite]>:$ptr,
4683+ Arg<CIR_MemOrder, "memory order">:$mem_order,
4684+ OptionalAttr<I64Attr>:$alignment,
4685+ UnitAttr:$is_volatile
4686+ );
4687+
4688+ let assemblyFormat = [{
4689+ $mem_order $ptr
4690+ (`volatile` $is_volatile^)?
4691+ `:` qualified(type($ptr)) attr-dict
4692+ }];
4693+ }
4694+
45604695#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD
0 commit comments