Skip to content

[CIR][CodeGen] Bitfield operations #279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
Original file line number Diff line number Diff line change
Expand Up @@ -521,4 +521,31 @@ def GlobalCtorAttr : CIR_Attr<"GlobalCtor", "globalCtor"> {
];
let skipDefaultBuilders = 1;
}

def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> {
let summary = "Represents a bit field info";
let description = [{
Holds the next information about bitfields: name, storage type, a bitfield size
and position in the storage, if the bitfield is signed or not.
}];
let parameters = (ins "StringAttr":$name,
"Type":$storage_type,
"uint64_t":$size,
"uint64_t":$offset,
"bool":$is_signed);

let assemblyFormat = "`<` struct($name, $storage_type, $size, $offset, $is_signed) `>`";

let builders = [
AttrBuilder<(ins "StringRef":$name,
"Type":$storage_type,
"uint64_t":$size,
"uint64_t":$offset,
"bool":$is_signed
), [{
return $_get($_ctxt, StringAttr::get($_ctxt, name), storage_type, size, offset, is_signed);
}]>
];
}

#endif // MLIR_CIR_DIALECT_CIR_ATTRS
148 changes: 148 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,154 @@ def VTableAddrPointOp : CIR_Op<"vtable.address_point",
let hasVerifier = 1;
}

//===----------------------------------------------------------------------===//
// SetBitfieldOp
//===----------------------------------------------------------------------===//

def SetBitfieldOp : CIR_Op<"set_bitfield"> {
let summary = "Set a bitfield";
let description = [{
The `cir.set_bitfield` operation provides a store-like access to
a bit field of a record.

It expects an address of a storage where to store, a type of the storage,
a value being stored, a name of a bit field, a pointer to the storage in the
base record, a size of the storage, a size the bit field, an offset
of the bit field and a sign. Returns a value being stored.

Example.
Suppose we have a struct with multiple bitfields stored in
different storages. The `cir.set_bitfield` operation sets the value
of the bitfield.
```C++
typedef struct {
int a : 4;
int b : 27;
int c : 17;
int d : 2;
int e : 15;
} S;

void store_bitfield(S& s) {
s.d = 3;
}
```

```mlir
// 'd' is in the storage with the index 1
!struct_type = !cir.struct<struct "S" {!cir.int<u, 32>, !cir.int<u, 32>, !cir.int<u, 16>} #cir.record.decl.ast>
#bfi_d = #cir.bitfield_info<name = "d", storage_type = !u32i, size = 2, offset = 17, is_signed = true>

%1 = cir.const(#cir.int<3> : !s32i) : !s32i
%2 = cir.load %0 : cir.ptr <!cir.ptr<!struct_type>>, !cir.ptr<!struct_type>
%3 = cir.get_member %2[1] {name = "d"} : !cir.ptr<!struct_type> -> !cir.ptr<!u32i>
%4 = cir.set_bitfield(#bfi_d, %3 : !cir.ptr<!u32i>, %1 : !s32i) -> !s32i
```
}];

let arguments = (ins
AnyType:$dst,
AnyType:$src,
BitfieldInfoAttr:$bitfield_info
);

let results = (outs CIR_IntType:$result);

let assemblyFormat = [{ `(`$bitfield_info`,` $dst`:`type($dst)`,`
$src`:`type($src) `)` attr-dict `->` type($result) }];

let builders = [
OpBuilder<(ins "Type":$type,
"Value":$dst,
"Type":$storage_type,
"Value":$src,
"StringRef":$name,
"unsigned":$size,
"unsigned":$offset,
"bool":$is_signed
),
[{
BitfieldInfoAttr info =
BitfieldInfoAttr::get($_builder.getContext(),
name, storage_type,
size, offset, is_signed);
build($_builder, $_state, type, dst, src, info);
}]>
];
}

//===----------------------------------------------------------------------===//
// GetBitfieldOp
//===----------------------------------------------------------------------===//

def GetBitfieldOp : CIR_Op<"get_bitfield"> {
let summary = "Get a bitfield";
let description = [{
The `cir.get_bitfield` operation provides a load-like access to
a bit field of a record.

It expects a name if a bit field, a pointer to a storage in the
base record, a type of the storage, a name of the bitfield,
a size the bit field, an offset of the bit field and a sign.

Example:
Suppose we have a struct with multiple bitfields stored in
different storages. The `cir.get_bitfield` operation gets the value
of the bitfield
```C++
typedef struct {
int a : 4;
int b : 27;
int c : 17;
int d : 2;
int e : 15;
} S;

int load_bitfield(S& s) {
return s.d;
}
```

```mlir
// 'd' is in the storage with the index 1
!struct_type = !cir.struct<struct "S" {!cir.int<u, 32>, !cir.int<u, 32>, !cir.int<u, 16>} #cir.record.decl.ast>
#bfi_d = #cir.bitfield_info<name = "d", storage_type = !u32i, size = 2, offset = 17, is_signed = true>

%2 = cir.load %0 : cir.ptr <!cir.ptr<!struct_type>>, !cir.ptr<!struct_type>
%3 = cir.get_member %2[1] {name = "d"} : !cir.ptr<!struct_type> -> !cir.ptr<!u32i>
%4 = cir.get_bitfield(#bfi_d, %3 : !cir.ptr<!u32i>) -> !s32i
```
}];

let arguments = (ins
AnyType:$addr,
BitfieldInfoAttr:$bitfield_info
);

let results = (outs CIR_IntType:$result);

let assemblyFormat = [{ `(`$bitfield_info `,` $addr attr-dict `:`
type($addr) `)` `->` type($result) }];

let builders = [
OpBuilder<(ins "Type":$type,
"Value":$addr,
"Type":$storage_type,
"StringRef":$name,
"unsigned":$size,
"unsigned":$offset,
"bool":$is_signed
),
[{
BitfieldInfoAttr info =
BitfieldInfoAttr::get($_builder.getContext(),
name, storage_type,
size, offset, is_signed);
build($_builder, $_state, type, addr, info);
}]>
];
}

//===----------------------------------------------------------------------===//
// GetMemberOp
//===----------------------------------------------------------------------===//
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLVM_CLANG_LIB_CIR_CIRGENBUILDER_H

#include "Address.h"
#include "CIRGenRecordLayout.h"
#include "CIRDataLayout.h"
#include "CIRGenTypeCache.h"
#include "UnimplementedFeatureGuarding.h"
Expand Down Expand Up @@ -661,6 +662,26 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy {
global.getLoc(), getPointerTo(global.getSymType()), global.getName());
}

mlir::Value createGetBitfield(mlir::Location loc, mlir::Type resultType,
mlir::Value addr, mlir::Type storageType,
const CIRGenBitFieldInfo &info,
bool useVolatile) {
auto offset = useVolatile ? info.VolatileOffset : info.Offset;
return create<mlir::cir::GetBitfieldOp>(loc, resultType, addr, storageType,
info.Name, info.Size,
offset, info.IsSigned);
}

mlir::Value createSetBitfield(mlir::Location loc, mlir::Type resultType,
mlir::Value dstAddr, mlir::Type storageType,
mlir::Value src, const CIRGenBitFieldInfo &info,
bool useVolatile) {
auto offset = useVolatile ? info.VolatileOffset : info.Offset;
return create<mlir::cir::SetBitfieldOp>(
loc, resultType, dstAddr, storageType, src, info.Name,
info.Size, offset, info.IsSigned);
}

/// Create a pointer to a record member.
mlir::Value createGetMember(mlir::Location loc, mlir::Type result,
mlir::Value base, llvm::StringRef name,
Expand Down
Loading