@@ -1669,6 +1669,94 @@ def GetGlobalOp : CIR_Op<"get_global",
16691669 }];
16701670}
16711671
1672+ //===----------------------------------------------------------------------===//
1673+ // SetBitfieldOp
1674+ //===----------------------------------------------------------------------===//
1675+
1676+ def SetBitfieldOp : CIR_Op<"set_bitfield"> {
1677+ let summary = "Set the value of a bitfield member";
1678+ let description = [{
1679+ The `cir.set_bitfield` operation provides a store-like access to
1680+ a bit field of a record.
1681+
1682+ A bitfield info attribute must be provided to describe the location of
1683+ the bitfield within the memory referenced by the $addr argument.
1684+ The $src argument is inserted at the appropriate place in the memory and
1685+ the value that was stored. Returns the value being stored.
1686+
1687+ A unit attribute `volatile` can be used to indicate a volatile store of the
1688+ bitfield.
1689+ ```mlir
1690+ cir.set_bitfield(#bfi, %0 : !cir.ptr<!u32i>, %1 : !s32i) {is_volatile}
1691+ -> !s32i
1692+ ```
1693+
1694+ Example.
1695+ Suppose we have a struct with multiple bitfields stored in
1696+ different storages. The `cir.set_bitfield` operation sets the value
1697+ of the bitfield.
1698+ ```C++
1699+ typedef struct {
1700+ int a : 4;
1701+ int b : 27;
1702+ int c : 17;
1703+ int d : 2;
1704+ int e : 15;
1705+ } S;
1706+
1707+ void store_bitfield(S& s) {
1708+ s.e = 3;
1709+ }
1710+ ```
1711+
1712+ ```mlir
1713+ // 'e' is in the storage with the index 1
1714+ !record_type = !cir.record<struct "S" packed padded {!u64i, !u16i,
1715+ !cir.array<!u8i x 2>} #cir.record.decl.ast>
1716+ #bfi_e = #cir.bitfield_info<name = "e", storage_type = !u16i, size = 15,
1717+ offset = 0, is_signed = true>
1718+
1719+ %1 = cir.const #cir.int<3> : !s32i
1720+ %2 = cir.load %0 : !cir.ptr<!cir.ptr<!record_type>>, !cir.ptr<!record_type>
1721+ %3 = cir.get_member %2[1] {name = "e"} : !cir.ptr<!record_type>
1722+ -> !cir.ptr<!u16i>
1723+ %4 = cir.set_bitfield(#bfi_e, %3 : !cir.ptr<!u16i>, %1 : !s32i) -> !s32i
1724+ ```
1725+ }];
1726+
1727+ let arguments = (ins
1728+ Arg<CIR_PointerType, "the address to store the value", [MemWrite]>:$addr,
1729+ CIR_AnyType:$src,
1730+ BitfieldInfoAttr:$bitfield_info,
1731+ UnitAttr:$is_volatile
1732+ );
1733+
1734+ let results = (outs CIR_IntType:$result);
1735+
1736+ let assemblyFormat = [{ `(`$bitfield_info`,` $addr`:`qualified(type($addr))`,`
1737+ $src`:`type($src) `)` attr-dict `->` type($result) }];
1738+
1739+ let builders = [
1740+ OpBuilder<(ins "mlir::Type":$type,
1741+ "mlir::Value":$addr,
1742+ "mlir::Type":$storage_type,
1743+ "mlir::Value":$src,
1744+ "llvm::StringRef":$name,
1745+ "unsigned":$size,
1746+ "unsigned":$offset,
1747+ "bool":$is_signed,
1748+ "bool":$is_volatile
1749+ ),
1750+ [{
1751+ BitfieldInfoAttr info =
1752+ BitfieldInfoAttr::get($_builder.getContext(),
1753+ name, storage_type,
1754+ size, offset, is_signed);
1755+ build($_builder, $_state, type, addr, src, info, is_volatile);
1756+ }]>
1757+ ];
1758+ }
1759+
16721760//===----------------------------------------------------------------------===//
16731761// GetBitfieldOp
16741762//===----------------------------------------------------------------------===//
@@ -1685,6 +1773,9 @@ def GetBitfieldOp : CIR_Op<"get_bitfield"> {
16851773
16861774 A unit attribute `volatile` can be used to indicate a volatile load of the
16871775 bitfield.
1776+ ```mlir
1777+ cir.get_bitfield(#bfi, %0 {is_volatile} : !cir.ptr<!u64i>) -> !s32i
1778+ ```
16881779
16891780 Example:
16901781 Suppose we have a struct with multiple bitfields stored in
0 commit comments