Skip to content
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

[CIR][CodeGen][Bugfix] bitfields: use the storage type ifor the getMeberOp #261

Closed
wants to merge 1 commit into from
Closed
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
12 changes: 7 additions & 5 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,16 @@ static bool isAAPCS(const TargetInfo &TargetInfo) {
return TargetInfo.getABI().startswith("aapcs");
}

Address CIRGenFunction::getAddrOfField(LValue base, const FieldDecl *field,
unsigned index) {
Address CIRGenFunction::getAddrOfBitFieldStorage(LValue base,
const FieldDecl *field,
unsigned index,
unsigned size) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you changing the function signature? Why wasn't it getAddrOfBitFieldStorage in the first place?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function was introduced by me and in previous version it was not intended to work with bitfields only. After the last changes it will serve only them though. That's why I renamed it and added one more argument

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good.

if (index == 0)
return base.getAddress();

auto loc = getLoc(field->getLocation());
auto fieldType = convertType(field->getType());
auto fieldType = builder.getUIntNTy(size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain why it shouldn't use convertType here.

Copy link
Collaborator Author

@gitoleg gitoleg Sep 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convertType for the integer field is always 32, type mismatch guaranteed, see a longer comment below

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So please add assert(convertType(field->getType()) == ...)


auto fieldPtr =
mlir::cir::PointerType::get(getBuilder().getContext(), fieldType);
auto sea = getBuilder().createGetMember(
Expand Down Expand Up @@ -257,9 +260,8 @@ LValue CIRGenFunction::buildLValueForBitField(LValue base,
llvm_unreachable("NYI");
}

Address Addr = getAddrOfField(base, field, Idx);

const unsigned SS = useVolatile ? info.VolatileStorageSize : info.StorageSize;
Address Addr = getAddrOfBitFieldStorage(base, field, Idx, SS);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's LLVM codegen doing here? Does it call getAddrOfBitFieldStorage or getAddrOfField?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no LLVM codegen here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, we follow the principle of using the same skeleton as clang/lib/CodeGen, at least to the extend of what's possible.

I don't see anything similar to getAddrOfBitFieldStorage or getAddrOfField in clang/lib/CodeGen/*, and I want to understand what's the rationale there. Are those names introduced for specific functionality you refactor into helpers or are they complete new names for something that already existed in clang/lib/CodeGen? If so, I'm trying to understand why can't you just s/Emit/build and call it a day?


// Get the access type.
mlir::Type FieldIntTy = builder.getUIntNTy(SS);
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1553,8 +1553,9 @@ class CIRGenFunction : public CIRGenTypeCache {
"Invalid argument to GetAddrOfLocalVar(), no decl!");
return it->second;
}

Address getAddrOfField(LValue base, const clang::FieldDecl *field, unsigned index);

Address getAddrOfBitFieldStorage(LValue base, const clang::FieldDecl *field,
unsigned index, unsigned size);

/// Given an opaque value expression, return its LValue mapping if it exists,
/// otherwise create one.
Expand Down
51 changes: 25 additions & 26 deletions clang/test/CIR/CodeGen/bitfields.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,36 @@ void store_field() {
// CHECK: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr <!ty_22S22>,
// CHECK: [[TMP1:%.*]] = cir.const(#cir.int<1> : !s32i) : !s32i
// CHECK: [[TMP2:%.*]] = cir.unary(minus, [[TMP1]]) : !s32i, !s32i
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP0]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!s32i>
// CHECK: [[TMP4:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<!s32i>), !cir.ptr<!u32i>
// CHECK: [[TMP5:%.*]] = cir.cast(integral, [[TMP2]] : !s32i), !u32i
// CHECK: [[TMP6:%.*]] = cir.load [[TMP4]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP7:%.*]] = cir.const(#cir.int<3> : !u32i) : !u32i
// CHECK: [[TMP8:%.*]] = cir.binop(and, [[TMP5]], [[TMP7]]) : !u32i
// CHECK: [[TMP9:%.*]] = cir.const(#cir.int<17> : !u32i) : !u32i
// CHECK: [[TMP10:%.*]] = cir.shift(left, [[TMP8]] : !u32i, [[TMP9]] : !u32i) -> !u32i
// CHECK: [[TMP11:%.*]] = cir.const(#cir.int<4294574079> : !u32i) : !u32i
// CHECK: [[TMP12:%.*]] = cir.binop(and, [[TMP6]], [[TMP11]]) : !u32i
// CHECK: [[TMP13:%.*]] = cir.binop(or, [[TMP12]], [[TMP10]]) : !u32i
// CHECK: cir.store [[TMP13]], [[TMP4]] : !u32i, cir.ptr <!u32i>
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP0]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!u32i>
// CHECK: [[TMP4:%.*]] = cir.cast(integral, [[TMP2]] : !s32i), !u32i
// CHECK: [[TMP5:%.*]] = cir.load [[TMP3]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP6:%.*]] = cir.const(#cir.int<3> : !u32i) : !u32i
// CHECK: [[TMP7:%.*]] = cir.binop(and, [[TMP4]], [[TMP6]]) : !u32i
// CHECK: [[TMP8:%.*]] = cir.const(#cir.int<17> : !u32i) : !u32i
// CHECK: [[TMP9:%.*]] = cir.shift(left, [[TMP7]] : !u32i, [[TMP8]] : !u32i) -> !u32i
// CHECK: [[TMP10:%.*]] = cir.const(#cir.int<4294574079> : !u32i) : !u32i
// CHECK: [[TMP11:%.*]] = cir.binop(and, [[TMP5]], [[TMP10]]) : !u32i
// CHECK: [[TMP12:%.*]] = cir.binop(or, [[TMP11]], [[TMP9]]) : !u32i
// CHECK: cir.store [[TMP12]], [[TMP3]] : !u32i, cir.ptr <!u32i>
void store_neg_field() {
S s;
s.d = -1;
}

// CHECK: cir.func {{.*@load_field}}
// CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr<!ty_22S22>, cir.ptr <!cir.ptr<!ty_22S22>>
// CHECK: [[TMP2:%.*]] = cir.load [[TMP0]] : cir.ptr <!cir.ptr<!ty_22S22>>, !cir.ptr<!ty_22S22>
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP2]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!s32i>
// CHECK: [[TMP4:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<!s32i>), !cir.ptr<!u32i>
// CHECK: [[TMP5:%.*]] = cir.load [[TMP4]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP6:%.*]] = cir.cast(integral, [[TMP5]] : !u32i), !s32i
// CHECK: [[TMP7:%.*]] = cir.const(#cir.int<13> : !s32i) : !s32i
// CHECK: [[TMP8:%.*]] = cir.shift(left, [[TMP6]] : !s32i, [[TMP7]] : !s32i) -> !s32i
// CHECK: [[TMP9:%.*]] = cir.const(#cir.int<30> : !s32i) : !s32i
// CHECK: [[TMP10:%.*]] = cir.shift( right, [[TMP8]] : !s32i, [[TMP9]] : !s32i) -> !s32i
// CHECK: [[TMP11:%.*]] = cir.cast(integral, [[TMP10]] : !s32i), !s32i
// CHECK: cir.store [[TMP11]], [[TMP1]] : !s32i, cir.ptr <!s32i>
// CHECK: [[TMP12:%.*]] = cir.load [[TMP1]] : cir.ptr <!s32i>, !s32i
// CHECK: cir.func {{.*@load_field}}
// CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr<!ty_22S22>, cir.ptr <!cir.ptr<!ty_22S22>>
// CHECK: [[TMP1:%.*]] = cir.alloca !s32i, cir.ptr <!s32i>, ["__retval"]
// CHECK: [[TMP2:%.*]] = cir.load [[TMP0]] : cir.ptr <!cir.ptr<!ty_22S22>>, !cir.ptr<!ty_22S22>
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP2]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!u32i>
// CHECK: [[TMP4:%.*]] = cir.load [[TMP3]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP5:%.*]] = cir.cast(integral, [[TMP4]] : !u32i), !s32i
// CHECK: [[TMP6:%.*]] = cir.const(#cir.int<13> : !s32i) : !s32i
// CHECK: [[TMP7:%.*]] = cir.shift(left, [[TMP5]] : !s32i, [[TMP6]] : !s32i) -> !s32i
// CHECK: [[TMP8:%.*]] = cir.const(#cir.int<30> : !s32i) : !s32i
// CHECK: [[TMP9:%.*]] = cir.shift( right, [[TMP7]] : !s32i, [[TMP8]] : !s32i) -> !s32i
// CHECK: [[TMP10:%.*]] = cir.cast(integral, [[TMP9]] : !s32i), !s32i
// CHECK: cir.store [[TMP10]], [[TMP1]] : !s32i, cir.ptr <!s32i>
// CHECK: [[TMP11:%.*]] = cir.load [[TMP1]] : cir.ptr <!s32i>, !s32i
int load_field(S* s) {
return s->d;
}
45 changes: 22 additions & 23 deletions clang/test/CIR/CodeGen/bitfields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,37 +46,36 @@ void store_field() {
// CHECK: [[TMP0:%.*]] = cir.alloca !ty_22S22, cir.ptr <!ty_22S22>
// CHECK: [[TMP1:%.*]] = cir.const(#cir.int<1> : !s32i) : !s32i
// CHECK: [[TMP2:%.*]] = cir.unary(minus, [[TMP1]]) : !s32i, !s32i
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP0]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!s32i>
// CHECK: [[TMP4:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<!s32i>), !cir.ptr<!u32i>
// CHECK: [[TMP5:%.*]] = cir.cast(integral, [[TMP2]] : !s32i), !u32i
// CHECK: [[TMP6:%.*]] = cir.load [[TMP4]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP7:%.*]] = cir.const(#cir.int<3> : !u32i) : !u32i
// CHECK: [[TMP8:%.*]] = cir.binop(and, [[TMP5]], [[TMP7]]) : !u32i
// CHECK: [[TMP9:%.*]] = cir.const(#cir.int<17> : !u32i) : !u32i
// CHECK: [[TMP10:%.*]] = cir.shift(left, [[TMP8]] : !u32i, [[TMP9]] : !u32i) -> !u32i
// CHECK: [[TMP11:%.*]] = cir.const(#cir.int<4294574079> : !u32i) : !u32i
// CHECK: [[TMP12:%.*]] = cir.binop(and, [[TMP6]], [[TMP11]]) : !u32i
// CHECK: [[TMP13:%.*]] = cir.binop(or, [[TMP12]], [[TMP10]]) : !u32i
// CHECK: cir.store [[TMP13]], [[TMP4]] : !u32i, cir.ptr <!u32i>
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP0]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!u32i>
// CHECK: [[TMP4:%.*]] = cir.cast(integral, [[TMP2]] : !s32i), !u32i
// CHECK: [[TMP5:%.*]] = cir.load [[TMP3]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP6:%.*]] = cir.const(#cir.int<3> : !u32i) : !u32i
// CHECK: [[TMP7:%.*]] = cir.binop(and, [[TMP4]], [[TMP6]]) : !u32i
// CHECK: [[TMP8:%.*]] = cir.const(#cir.int<17> : !u32i) : !u32i
// CHECK: [[TMP9:%.*]] = cir.shift(left, [[TMP7]] : !u32i, [[TMP8]] : !u32i) -> !u32i
// CHECK: [[TMP10:%.*]] = cir.const(#cir.int<4294574079> : !u32i) : !u32i
// CHECK: [[TMP11:%.*]] = cir.binop(and, [[TMP5]], [[TMP10]]) : !u32i
// CHECK: [[TMP12:%.*]] = cir.binop(or, [[TMP11]], [[TMP9]]) : !u32i
// CHECK: cir.store [[TMP12]], [[TMP3]] : !u32i, cir.ptr <!u32i>
void store_neg_field() {
S s;
s.d = -1;
}

// CHECK: cir.func @_Z10load_field
// CHECK: [[TMP0:%.*]] = cir.alloca !cir.ptr<!ty_22S22>, cir.ptr <!cir.ptr<!ty_22S22>>
// CHECK: [[TMP1:%.*]] = cir.alloca !s32i, cir.ptr <!s32i>, ["__retval"]
// CHECK: [[TMP2:%.*]] = cir.load [[TMP0]] : cir.ptr <!cir.ptr<!ty_22S22>>, !cir.ptr<!ty_22S22>
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP2]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!s32i>
// CHECK: [[TMP4:%.*]] = cir.cast(bitcast, [[TMP3]] : !cir.ptr<!s32i>), !cir.ptr<!u32i>
// CHECK: [[TMP5:%.*]] = cir.load [[TMP4]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP6:%.*]] = cir.cast(integral, [[TMP5]] : !u32i), !s32i
// CHECK: [[TMP7:%.*]] = cir.const(#cir.int<13> : !s32i) : !s32i
// CHECK: [[TMP8:%.*]] = cir.shift(left, [[TMP6]] : !s32i, [[TMP7]] : !s32i) -> !s32i
// CHECK: [[TMP9:%.*]] = cir.const(#cir.int<30> : !s32i) : !s32i
// CHECK: [[TMP10:%.*]] = cir.shift( right, [[TMP8]] : !s32i, [[TMP9]] : !s32i) -> !s32i
// CHECK: [[TMP11:%.*]] = cir.cast(integral, [[TMP10]] : !s32i), !s32i
// CHECK: cir.store [[TMP11]], [[TMP1]] : !s32i, cir.ptr <!s32i>
// CHECK: [[TMP12:%.*]] = cir.load [[TMP1]] : cir.ptr <!s32i>, !s32i
// CHECK: [[TMP3:%.*]] = cir.get_member [[TMP2]][1] {name = "d"} : !cir.ptr<!ty_22S22> -> !cir.ptr<!u32i>
// CHECK: [[TMP4:%.*]] = cir.load [[TMP3]] : cir.ptr <!u32i>, !u32i
// CHECK: [[TMP5:%.*]] = cir.cast(integral, [[TMP4]] : !u32i), !s32i
// CHECK: [[TMP6:%.*]] = cir.const(#cir.int<13> : !s32i) : !s32i
// CHECK: [[TMP7:%.*]] = cir.shift(left, [[TMP5]] : !s32i, [[TMP6]] : !s32i) -> !s32i
// CHECK: [[TMP8:%.*]] = cir.const(#cir.int<30> : !s32i) : !s32i
// CHECK: [[TMP9:%.*]] = cir.shift( right, [[TMP7]] : !s32i, [[TMP8]] : !s32i) -> !s32i
// CHECK: [[TMP10:%.*]] = cir.cast(integral, [[TMP9]] : !s32i), !s32i
// CHECK: cir.store [[TMP10]], [[TMP1]] : !s32i, cir.ptr <!s32i>
// CHECK: [[TMP11:%.*]] = cir.load [[TMP1]] : cir.ptr <!s32i>, !s32i
int load_field(S& s) {
return s.d;
}