Reduce padding needed for optional types and clean up some redundant

type padding
This commit is contained in:
Bruce Hill 2024-10-08 21:10:36 -04:00
parent 5103fde1c5
commit 839c1983a0
8 changed files with 68 additions and 48 deletions

View File

@ -46,7 +46,7 @@ CORD promote_to_optional(type_t *t, CORD code)
} else if (t->tag == ByteType) {
return CORD_all("((OptionalByte_t){", code, "})");
} else if (t->tag == StructType) {
return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){", code, "})");
return CORD_all("({ ", compile_type(Type(OptionalType, .type=t)), " nonnull = {.value=", code, "}; nonnull.is_null = false; nonnull; })");
} else {
return code;
}
@ -302,11 +302,11 @@ static CORD compile_lvalue(env_t *env, ast_t *ast)
if (index->unchecked) {
return CORD_all("Array_lvalue_unchecked(", compile_type(item_type), ", ", target_code, ", ",
compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)),
", ", CORD_asprintf("%ld", padded_type_size(item_type)), ")");
", ", CORD_asprintf("%ld", type_size(item_type)), ")");
} else {
return CORD_all("Array_lvalue(", compile_type(item_type), ", ", target_code, ", ",
compile_int_to_type(env, index->index, Type(IntType, .bits=TYPE_IBITS64)),
", ", CORD_asprintf("%ld", padded_type_size(item_type)),
", ", CORD_asprintf("%ld", type_size(item_type)),
", ", heap_strf("%ld", ast->start - ast->file->text),
", ", heap_strf("%ld", ast->end - ast->file->text), ")");
}
@ -720,7 +720,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (lhs_t->tag == TextType) {
return CORD_all(lhs, " = Texts(", lhs, ", ", rhs, ");");
} else if (lhs_t->tag == ArrayType) {
CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(Match(lhs_t, ArrayType)->item_type));
CORD padded_item_size = CORD_asprintf("%ld", type_size(Match(lhs_t, ArrayType)->item_type));
if (promote(env, &rhs, rhs_t, Match(lhs_t, ArrayType)->item_type)) {
// arr ++= item
if (update->lhs->tag == Var)
@ -1814,7 +1814,7 @@ CORD compile_null(type_t *t)
case PointerType: return CORD_all("((", compile_type(t), ")NULL)");
case ClosureType: return "NULL_CLOSURE";
case NumType: return "nan(\"null\")";
case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_null=true})");
case StructType: return CORD_all("((", compile_type(Type(OptionalType, .type=t)), "){.is_null=yes})");
case EnumType: {
env_t *enum_env = Match(t, EnumType)->env;
return CORD_all("((", compile_type(t), "){", namespace_prefix(enum_env, enum_env->namespace), "null})");
@ -2157,7 +2157,7 @@ CORD compile(env_t *env, ast_t *ast)
return CORD_all("Text$concat(", lhs, ", ", rhs, ")");
}
case ArrayType: {
CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(Match(operand_t, ArrayType)->item_type));
CORD padded_item_size = CORD_asprintf("%ld", type_size(Match(operand_t, ArrayType)->item_type));
return CORD_all("Array$concat(", lhs, ", ", rhs, ", ", padded_item_size, ")");
}
default:
@ -2296,9 +2296,9 @@ CORD compile(env_t *env, ast_t *ast)
case Array: {
type_t *array_type = get_type(env, ast);
type_t *item_type = Match(array_type, ArrayType)->item_type;
if (padded_type_size(Match(array_type, ArrayType)->item_type) > ARRAY_MAX_STRIDE)
if (type_size(Match(array_type, ArrayType)->item_type) > ARRAY_MAX_STRIDE)
code_err(ast, "This array holds items that take up %ld bytes, but the maximum supported size is %ld bytes. Consider using an array of pointers instead.",
padded_type_size(item_type), ARRAY_MAX_STRIDE);
type_size(item_type), ARRAY_MAX_STRIDE);
auto array = Match(ast, Array);
if (!array->items)
@ -2581,7 +2581,7 @@ CORD compile(env_t *env, ast_t *ast)
switch (self_value_t->tag) {
case ArrayType: {
type_t *item_t = Match(self_value_t, ArrayType)->item_type;
CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(item_t));
CORD padded_item_size = CORD_asprintf("%ld", type_size(item_t));
if (streq(call->name, "insert")) {
CORD self = compile_to_pointer_depth(env, call->self, 1, false);
arg_t *arg_spec = new(arg_t, .name="item", .type=item_t,
@ -2803,7 +2803,7 @@ CORD compile(env_t *env, ast_t *ast)
}
case ChannelType: {
type_t *item_t = Match(self_value_t, ChannelType)->item_type;
CORD padded_item_size = CORD_asprintf("%ld", padded_type_size(item_t));
CORD padded_item_size = CORD_asprintf("%ld", type_size(item_t));
arg_t *front_default_end = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, false));
arg_t *front_default_start = new(arg_t, .name="front", .type=Type(BoolType), .default_val=FakeAST(Bool, true));
if (streq(call->name, "give")) {

2
repl.c
View File

@ -510,7 +510,7 @@ void eval(env_t *env, ast_t *ast, void *dest)
char item_buf[item_size] = {};
for (ast_list_t *item = Match(ast, Array)->items; item; item = item->next) {
eval(env, item->ast, item_buf);
Array$insert(&arr, item_buf, I(0), (int64_t)padded_type_size(Match(t, ArrayType)->item_type));
Array$insert(&arr, item_buf, I(0), (int64_t)type_size(Match(t, ArrayType)->item_type));
}
memcpy(dest, &arr, sizeof(Array_t));
break;

View File

@ -20,7 +20,7 @@ PUREFUNC static inline int64_t get_padded_item_size(const TypeInfo_t *info)
{
int64_t size = info->ArrayInfo.item->size;
if (info->ArrayInfo.item->align > 1 && size % info->ArrayInfo.item->align)
size += info->ArrayInfo.item->align - (size % info->ArrayInfo.item->align); // padding
errx(1, "Item size is not padded!");
return size;
}
@ -524,7 +524,7 @@ public int32_t Array$compare(const Array_t *x, const Array_t *y, const TypeInfo_
if (item->tag == PointerInfo || (item->tag == CustomInfo && item->CustomInfo.compare == NULL)) { // data comparison
int64_t item_padded_size = type->ArrayInfo.item->size;
if (type->ArrayInfo.item->align > 1 && item_padded_size % type->ArrayInfo.item->align)
item_padded_size += type->ArrayInfo.item->align - (item_padded_size % type->ArrayInfo.item->align); // padding
errx(1, "Item size is not padded!");
if ((int64_t)x->stride == item_padded_size && (int64_t)y->stride == item_padded_size && item->size == item_padded_size) {
int32_t cmp = (int32_t)memcmp(x->data, y->data, (size_t)(MIN(x->length, y->length)*item_padded_size));

View File

@ -43,9 +43,13 @@ public PUREFUNC bool is_null(const void *obj, const TypeInfo_t *non_optional_typ
case TableInfo: return ((Table_t*)obj)->entries.length < 0;
case FunctionInfo: return *(void**)obj == NULL;
case StructInfo: {
int64_t offset = non_optional_type->size;
if (offset % non_optional_type->align)
offset += non_optional_type->align - (offset % non_optional_type->align);
int64_t offset = 0;
for (int i = 0; i < non_optional_type->StructInfo.num_fields; i++) {
NamedType_t field = non_optional_type->StructInfo.fields[i];
if (offset > 0 && (offset % field.type->align) > 0)
offset += field.type->align - (offset % field.type->align);
offset += field.type->size;
}
return *(bool*)(obj + offset);
}
case EnumInfo: return (*(int*)obj) == 0; // NULL tag

View File

@ -55,14 +55,20 @@ CORD compile_struct_header(env_t *env, ast_t *ast)
}
CORD struct_code = CORD_all("struct ", full_name, "_s {\n");
struct_code = CORD_all(struct_code, "};\n");
type_t *t = Table$str_get(*env->types, def->name);
return CORD_all(
"typedef struct ", full_name, "_s ", full_name, "_t;\n",
"struct ", full_name, "_s {\n",
fields,
"};\n",
"typedef struct {\n",
"union {\n",
full_name, "_t value;\n"
"Bool_t is_null:1;\n"
"struct {\n"
"char _padding[", heap_strf("%zu", unpadded_struct_size(t)), "];\n",
"Bool_t is_null;\n"
"};\n"
"};\n"
"} ", namespace_prefix(env, env->namespace), "$Optional", def->name, "_t;\n"
"extern const TypeInfo_t ", full_name, ";\n",
compile_namespace_header(env, def->name, def->namespace));

View File

@ -54,9 +54,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
if (!item_t) code_err(item_type, "I can't figure out what this type is.");
if (has_stack_memory(item_t))
code_err(item_type, "Arrays can't have stack references because the array may outlive the stack frame.");
if (padded_type_size(item_t) > ARRAY_MAX_STRIDE)
if (type_size(item_t) > ARRAY_MAX_STRIDE)
code_err(ast, "This array holds items that take up %ld bytes, but the maximum supported size is %ld bytes. Consider using an array of pointers instead.",
padded_type_size(item_t), ARRAY_MAX_STRIDE);
type_size(item_t), ARRAY_MAX_STRIDE);
return Type(ArrayType, .item_type=item_t);
}
case SetTypeAST: {
@ -65,9 +65,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
if (!item_t) code_err(item_type, "I can't figure out what this type is.");
if (has_stack_memory(item_t))
code_err(item_type, "Sets can't have stack references because the array may outlive the stack frame.");
if (padded_type_size(item_t) > ARRAY_MAX_STRIDE)
if (type_size(item_t) > ARRAY_MAX_STRIDE)
code_err(ast, "This set holds items that take up %ld bytes, but the maximum supported size is %ld bytes. Consider using an set of pointers instead.",
padded_type_size(item_t), ARRAY_MAX_STRIDE);
type_size(item_t), ARRAY_MAX_STRIDE);
return Type(SetType, .item_type=item_t);
}
case ChannelTypeAST: {
@ -76,9 +76,9 @@ type_t *parse_type_ast(env_t *env, type_ast_t *ast)
if (!item_t) code_err(item_type, "I can't figure out what this type is.");
if (!can_send_over_channel(item_t))
code_err(ast, "This item type can't be sent over a channel because it contains reference to memory that may not be thread-safe.");
if (padded_type_size(item_t) > ARRAY_MAX_STRIDE)
if (type_size(item_t) > ARRAY_MAX_STRIDE)
code_err(ast, "This channel holds items that take up %ld bytes, but the maximum supported size is %ld bytes.",
padded_type_size(item_t), ARRAY_MAX_STRIDE);
type_size(item_t), ARRAY_MAX_STRIDE);
return Type(ChannelType, .item_type=item_t);
}
case TableTypeAST: {

58
types.c
View File

@ -398,6 +398,24 @@ PUREFUNC bool is_numeric_type(type_t *t)
return t->tag == IntType || t->tag == BigIntType || t->tag == NumType;
}
PUREFUNC size_t unpadded_struct_size(type_t *t)
{
arg_t *fields = Match(t, StructType)->fields;
size_t size = 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
} else {
size_t align = type_align(field_type);
if (align > 1 && size % align > 0)
size += align - (size % align); // Padding
size += type_size(field_type);
}
}
return size;
}
PUREFUNC size_t type_size(type_t *t)
{
#pragma GCC diagnostic ignored "-Wswitch-default"
@ -438,24 +456,22 @@ PUREFUNC size_t type_size(type_t *t)
case TYPE_IBITS8: return sizeof(OptionalInt8_t);
default: errx(1, "Invalid integer bit size");
}
case StructType: return padded_type_size(nonnull) + 1;
case StructType: {
size_t size = unpadded_struct_size(nonnull);
size += sizeof(bool); // is_null flag
size_t align = type_align(nonnull);
if (align > 0 && (size % align) > 0)
size = (size + align) - (size % align);
return size;
}
default: return type_size(nonnull);
}
}
case StructType: {
arg_t *fields = Match(t, StructType)->fields;
size_t size = t->tag == StructType ? 0 : sizeof(void*);
for (arg_t *field = fields; field; field = field->next) {
type_t *field_type = field->type;
if (field_type->tag == BoolType) {
size += 1; // Bit packing
} else {
size_t align = type_align(field_type);
if (align > 1 && size % align > 0)
size += align - (size % align); // Padding
size += type_size(field_type);
}
}
size_t size = unpadded_struct_size(t);
size_t align = type_align(t);
if (size > 0 && align > 0 && (size % align) > 0)
size = (size + align) - (size % align);
return size;
}
case EnumType: {
@ -468,9 +484,12 @@ PUREFUNC size_t type_size(type_t *t)
if (size > max_size) max_size = size;
}
size_t size = sizeof(UnknownType); // generic enum
if (max_align > 1 && size % max_align > 0)
if (max_align > 1 && size % max_align > 0) // Padding before first union field
size += max_align - (size % max_align);
size += max_size;
size_t align = MAX(__alignof__(UnknownType), max_align);
if (size % align > 0) // Padding after union
size += align - (size % align);
return size;
}
case TypeInfoType: return sizeof(TypeInfo_t);
@ -545,15 +564,6 @@ PUREFUNC size_t type_align(type_t *t)
errx(1, "This should not be reachable");
}
PUREFUNC size_t padded_type_size(type_t *t)
{
size_t size = type_size(t);
size_t align = type_align(t);
if (align > 1 && size % align > 0)
size += align - (size % align); // Padding
return size;
}
type_t *get_field_type(type_t *t, const char *field_name)
{
t = value_type(t);

View File

@ -151,7 +151,7 @@ PUREFUNC bool is_int_type(type_t *t);
PUREFUNC bool is_numeric_type(type_t *t);
PUREFUNC size_t type_size(type_t *t);
PUREFUNC size_t type_align(type_t *t);
PUREFUNC size_t padded_type_size(type_t *t);
PUREFUNC size_t unpadded_struct_size(type_t *t);
type_t *get_field_type(type_t *t, const char *field_name);
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0