diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-12-22 15:53:26 -0500 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-12-22 15:53:26 -0500 |
| commit | 3dd7854076c5f49032ad520dc56769faa1c35d08 (patch) | |
| tree | 9edc71f9f37b0a667ab0ac5586d34c0089744f21 /types.c | |
| parent | cdda494fe53374dc513b04ada2dc0fad6a8b83bc (diff) | |
Add optimized metamethods for enums and structs that hold packed data
Diffstat (limited to 'types.c')
| -rw-r--r-- | types.c | 36 |
1 files changed, 35 insertions, 1 deletions
@@ -444,21 +444,55 @@ PUREFUNC bool is_numeric_type(type_t *t) return t->tag == IntType || t->tag == BigIntType || t->tag == NumType || t->tag == ByteType; } +PUREFUNC bool is_packed_data(type_t *t) +{ + if (t->tag == IntType || t->tag == NumType || t->tag == ByteType || t->tag == PointerType || t->tag == BoolType || t->tag == FunctionType) { + return true; + } else if (t->tag == StructType) { + for (arg_t *field = Match(t, StructType)->fields; field; field = field->next) { + if (!is_packed_data(field->type)) + return false; + } + return true; + } else if (t->tag == EnumType) { + for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) { + if (!is_packed_data(tag->type)) + return false; + } + return true; + } else { + return false; + } +} + PUREFUNC size_t unpadded_struct_size(type_t *t) { arg_t *fields = Match(t, StructType)->fields; size_t size = 0; + size_t bit_offset = 0; for (arg_t *field = fields; field; field = field->next) { type_t *field_type = field->type; if (field_type->tag == BoolType) { - size += 1; // Bit packing + bit_offset += 1; + if (bit_offset >= 8) { + size += 1; + bit_offset = 0; + } } else { + if (bit_offset > 0) { + size += 1; + bit_offset = 0; + } size_t align = type_align(field_type); if (align > 1 && size % align > 0) size += align - (size % align); // Padding size += type_size(field_type); } } + if (bit_offset > 0) { + size += 1; + bit_offset = 0; + } return size; } |
