Skip to content

Commit 0161dcc

Browse files
authored
Merge pull request #127 from kornilova-l/fix-fields-offsets
Represent structs with bit fields as arrays
2 parents 535b724 + c25a757 commit 0161dcc

File tree

7 files changed

+55
-28
lines changed

7 files changed

+55
-28
lines changed

bindgen/ir/IR.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ void IR::addEnum(std::string name, const std::string &type,
3434

3535
void IR::addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
3636
uint64_t typeSize, std::shared_ptr<Location> location,
37-
bool isPacked) {
38-
std::shared_ptr<Struct> s = std::make_shared<Struct>(
39-
name, std::move(fields), typeSize, std::move(location), isPacked);
37+
bool isPacked, bool isBitField) {
38+
std::shared_ptr<Struct> s =
39+
std::make_shared<Struct>(name, std::move(fields), typeSize,
40+
std::move(location), isPacked, isBitField);
4041
structs.push_back(s);
4142
std::shared_ptr<TypeDef> typeDef = getTypeDefWithName("struct_" + name);
4243
if (typeDef) {

bindgen/ir/IR.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class IR {
3636

3737
void addStruct(std::string name, std::vector<std::shared_ptr<Field>> fields,
3838
uint64_t typeSize, std::shared_ptr<Location> location,
39-
bool isPacked);
39+
bool isPacked, bool isBitField);
4040

4141
void addUnion(std::string name, std::vector<std::shared_ptr<Field>> fields,
4242
uint64_t maxSize, std::shared_ptr<Location> location);

bindgen/ir/Struct.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
Field::Field(std::string name, std::shared_ptr<Type> type)
99
: TypeAndName(std::move(name), std::move(type)) {}
1010

11-
Field::Field(std::string name, std::shared_ptr<Type> type, uint64_t offset)
12-
: TypeAndName(std::move(name), std::move(type)), offset(offset) {}
11+
Field::Field(std::string name, std::shared_ptr<Type> type,
12+
uint64_t offsetInBits)
13+
: TypeAndName(std::move(name), std::move(type)),
14+
offsetInBits(offsetInBits) {}
1315

14-
uint64_t Field::getOffset() const { return offset; }
16+
uint64_t Field::getOffsetInBits() const { return offsetInBits; }
1517

1618
StructOrUnion::StructOrUnion(std::string name,
1719
std::vector<std::shared_ptr<Field>> fields,
@@ -29,12 +31,12 @@ bool StructOrUnion::hasHelperMethods() const { return !fields.empty(); }
2931

3032
Struct::Struct(std::string name, std::vector<std::shared_ptr<Field>> fields,
3133
uint64_t typeSize, std::shared_ptr<Location> location,
32-
bool isPacked)
34+
bool isPacked, bool isBitField)
3335
: StructOrUnion(std::move(name), std::move(fields), std::move(location)),
34-
typeSize(typeSize), isPacked(isPacked) {}
36+
typeSize(typeSize), isPacked(isPacked), isBitField(isBitField) {}
3537

3638
std::shared_ptr<TypeDef> Struct::generateTypeDef() {
37-
if (fields.size() < SCALA_NATIVE_MAX_STRUCT_FIELDS) {
39+
if (isRepresentedAsStruct()) {
3840
return std::make_shared<TypeDef>(getTypeAlias(), shared_from_this(),
3941
nullptr);
4042
} else {
@@ -56,7 +58,7 @@ std::string Struct::generateHelperClass() const {
5658
s << " implicit class " << type << "_ops(val p: native.Ptr[" << type
5759
<< "])"
5860
<< " extends AnyVal {\n";
59-
if (fields.size() <= SCALA_NATIVE_MAX_STRUCT_FIELDS) {
61+
if (isRepresentedAsStruct()) {
6062
s << generateHelperClassMethodsForStructRepresentation();
6163
} else {
6264
s << generateHelperClassMethodsForArrayRepresentation();
@@ -72,6 +74,9 @@ std::string Struct::generateHelperClass() const {
7274
}
7375

7476
bool Struct::hasHelperMethods() const {
77+
if (isBitField) {
78+
return false;
79+
}
7580
if (!isRepresentedAsStruct()) {
7681
return !fields.empty();
7782
}
@@ -176,7 +181,7 @@ Struct::generateGetterForStructRepresentation(unsigned fieldIndex) const {
176181
}
177182

178183
bool Struct::isRepresentedAsStruct() const {
179-
return fields.size() <= SCALA_NATIVE_MAX_STRUCT_FIELDS;
184+
return fields.size() <= SCALA_NATIVE_MAX_STRUCT_FIELDS && !isBitField;
180185
}
181186

182187
std::string
@@ -188,9 +193,10 @@ Struct::generateSetterForArrayRepresentation(unsigned int fieldIndex) const {
188193
std::string castedField = "p._1";
189194

190195
PointerType pointerToFieldType = PointerType(field->getType());
191-
if (field->getOffset() > 0) {
192-
castedField = "(" + castedField + " + " +
193-
std::to_string(field->getOffset()) + ")";
196+
uint64_t offsetInBytes = field->getOffsetInBits() / 8;
197+
if (offsetInBytes > 0) {
198+
castedField =
199+
"(" + castedField + " + " + std::to_string(offsetInBytes) + ")";
194200
}
195201
castedField = "!" + castedField + ".cast[" + pointerToFieldType.str() + "]";
196202
if (isAliasForType<ArrayType>(field->getType().get()) ||
@@ -215,8 +221,9 @@ Struct::generateGetterForArrayRepresentation(unsigned fieldIndex) const {
215221
std::string methodBody;
216222

217223
PointerType pointerToFieldType = PointerType(field->getType());
218-
if (field->getOffset() > 0) {
219-
methodBody = "(p._1 + " + std::to_string(field->getOffset()) + ")";
224+
uint64_t offsetInBytes = field->getOffsetInBits() / 8;
225+
if (offsetInBytes > 0) {
226+
methodBody = "(p._1 + " + std::to_string(offsetInBytes) + ")";
220227
} else {
221228
methodBody = "p._1";
222229
}
@@ -233,7 +240,6 @@ Struct::generateGetterForArrayRepresentation(unsigned fieldIndex) const {
233240
s << " def " << getter << ": " << returnType << " = " << methodBody
234241
<< "\n";
235242
return s.str();
236-
return "";
237243
}
238244

239245
Union::Union(std::string name, std::vector<std::shared_ptr<Field>> fields,

bindgen/ir/Struct.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ class Field : public TypeAndName {
1313
public:
1414
Field(std::string name, std::shared_ptr<Type> type);
1515

16-
Field(std::string name, std::shared_ptr<Type> type, uint64_t offset);
16+
Field(std::string name, std::shared_ptr<Type> type, uint64_t offsetInBits);
1717

18-
uint64_t getOffset() const;
18+
uint64_t getOffsetInBits() const;
1919

2020
protected:
2121
/**
2222
* Offset in bytes from address of struct/union.
2323
*/
24-
uint64_t offset = 0;
24+
uint64_t offsetInBits = 0;
2525
};
2626

2727
class StructOrUnion {
@@ -52,8 +52,8 @@ class Struct : public StructOrUnion,
5252
public std::enable_shared_from_this<Struct> {
5353
public:
5454
Struct(std::string name, std::vector<std::shared_ptr<Field>> fields,
55-
uint64_t typeSize, std::shared_ptr<Location> location,
56-
bool isPacked);
55+
uint64_t typeSize, std::shared_ptr<Location> location, bool isPacked,
56+
bool isBitField);
5757

5858
std::shared_ptr<TypeDef> generateTypeDef() override;
5959

@@ -74,9 +74,11 @@ class Struct : public StructOrUnion,
7474
bool operator==(const Type &other) const override;
7575

7676
private:
77-
/* type size is needed if number of fields is bigger than 22 */
77+
/** type size is needed if number of fields is bigger than 22 */
7878
uint64_t typeSize;
7979
bool isPacked;
80+
/** true if at least one field is bit field */
81+
bool isBitField;
8082

8183
bool isRepresentedAsStruct() const;
8284

bindgen/visitor/TreeVisitor.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,17 @@ void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) {
130130
const clang::ASTRecordLayout &recordLayout =
131131
astContext->getASTRecordLayout(record);
132132

133+
bool isBitFieldStruct = false;
133134
for (const clang::FieldDecl *field : record->fields()) {
135+
if (field->isBitField()) {
136+
isBitFieldStruct = true;
137+
}
134138
std::shared_ptr<Type> ftype =
135139
typeTranslator.translate(field->getType(), &name);
136140
uint64_t recordOffsetInBits =
137141
recordLayout.getFieldOffset(field->getFieldIndex());
138-
assert(recordOffsetInBits % 8 == 0);
139-
fields.push_back(std::make_shared<Field>(
140-
field->getNameAsString(), ftype, recordOffsetInBits / 8));
142+
fields.push_back(std::make_shared<Field>(field->getNameAsString(),
143+
ftype, recordOffsetInBits));
141144

142145
cycleDetection.AddDependency(newName, field->getType());
143146
}
@@ -156,7 +159,7 @@ void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) {
156159
assert(sizeInBits % 8 == 0);
157160

158161
ir.addStruct(name, std::move(fields), sizeInBits / 8, getLocation(record),
159-
record->hasAttr<clang::PackedAttr>());
162+
record->hasAttr<clang::PackedAttr>(), isBitFieldStruct);
160163
}
161164

162165
bool TreeVisitor::VisitVarDecl(clang::VarDecl *varDecl) {

tests/samples/Struct.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ struct __attribute__((__packed__)) packedStruct { // no helper methods
6060
char a;
6161
};
6262

63+
struct bitFieldStruct { // no helper methods
64+
unsigned char b1 : 3;
65+
unsigned char : 0; // start a new byte
66+
unsigned char b2 : 6;
67+
unsigned char b3 : 2;
68+
};
69+
70+
struct bitFieldOffsetDivByEight { // no helper methods
71+
unsigned b1 : 8;
72+
unsigned b2 : 8;
73+
unsigned char b3 : 8;
74+
};
75+
6376
char getCharFromAnonymousStruct(struct structWithAnonymousStruct *s);
6477

6578
char getIntFromAnonymousStruct(struct structWithAnonymousStruct *s);

tests/samples/Struct.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ object Struct {
1414
type struct_bigStruct = native.CArray[Byte, native.Nat.Digit[native.Nat._1, native.Nat.Digit[native.Nat._1, native.Nat._2]]]
1515
type struct_structWithAnonymousStruct = native.CStruct2[native.CInt, native.CArray[Byte, native.Nat._8]]
1616
type struct_packedStruct = native.CStruct1[native.CChar]
17+
type struct_bitFieldStruct = native.CArray[Byte, native.Nat._2]
18+
type struct_bitFieldOffsetDivByEight = native.CArray[Byte, native.Nat._4]
1719
type enum_struct_op = native.CUnsignedInt
1820
def setPoints(points: native.Ptr[struct_points], x1: native.CInt, y1: native.CInt, x2: native.CInt, y2: native.CInt): Unit = native.extern
1921
def getPoint(points: native.Ptr[struct_points], pointIndex: enum_pointIndex): native.CInt = native.extern

0 commit comments

Comments
 (0)