diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-05-21 13:42:33 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-05-21 13:42:33 -0400 |
| commit | 760f46e71c2a430c5824e79539af4b3537f307f0 (patch) | |
| tree | d42cf5bc5cad9f7035ae30fe15fef22fa8bb66d1 | |
| parent | c5c3be9e5d74cda08df2c36412e0a652f1433d4f (diff) | |
Reduce codegen output for enums without data attached to any tags
| -rw-r--r-- | builtins/functions.c | 4 | ||||
| -rw-r--r-- | builtins/types.h | 5 | ||||
| -rw-r--r-- | enums.c | 60 | ||||
| -rw-r--r-- | structs.c | 63 |
4 files changed, 92 insertions, 40 deletions
diff --git a/builtins/functions.c b/builtins/functions.c index b2808c5a..bed3dbfd 100644 --- a/builtins/functions.c +++ b/builtins/functions.c @@ -81,6 +81,7 @@ public uint32_t generic_hash(const void *obj, const TypeInfo *type) case TextInfo: return Text$hash(obj); case ArrayInfo: return Array$hash(obj, type); case TableInfo: return Table$hash(obj, type); + case EmptyStruct: return 0; case CustomInfo: if (!type->CustomInfo.hash) goto hash_data; @@ -101,6 +102,7 @@ public int32_t generic_compare(const void *x, const void *y, const TypeInfo *typ case TextInfo: return Text$compare(x, y); case ArrayInfo: return Array$compare(x, y, type); case TableInfo: return Table$compare(x, y, type); + case EmptyStruct: return 0; case CustomInfo: if (!type->CustomInfo.compare) goto compare_data; @@ -118,6 +120,7 @@ public bool generic_equal(const void *x, const void *y, const TypeInfo *type) case TextInfo: return Text$equal(x, y); case ArrayInfo: return Array$equal(x, y, type); case TableInfo: return Table$equal(x, y, type); + case EmptyStruct: return true; case CustomInfo: if (!type->CustomInfo.equal) goto use_generic_compare; @@ -137,6 +140,7 @@ public CORD generic_as_text(const void *obj, bool colorize, const TypeInfo *type case ArrayInfo: return Array$as_text(obj, colorize, type); case TableInfo: return Table$as_text(obj, colorize, type); case TypeInfoInfo: return Type$as_text(obj, colorize, type); + case EmptyStruct: return colorize ? CORD_all("\x1b[0;1m", type->EmptyStruct.name, "\x1b[m()") : CORD_all(type->EmptyStruct.name, "()"); case CustomInfo: if (!type->CustomInfo.as_text) fail("No cord function provided for type!\n"); diff --git a/builtins/types.h b/builtins/types.h index 3b517fd3..ac2166f0 100644 --- a/builtins/types.h +++ b/builtins/types.h @@ -18,7 +18,7 @@ typedef CORD (*str_fn_t)(const void*, bool, const struct TypeInfo*); typedef struct TypeInfo { int64_t size, align; struct { // Anonymous tagged union for convenience - enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, } tag; + enum { CustomInfo, PointerInfo, TextInfo, ArrayInfo, TableInfo, FunctionInfo, TypeInfoInfo, OpaqueInfo, EmptyStruct } tag; union { struct { equal_fn_t equal; @@ -47,6 +47,9 @@ typedef struct TypeInfo { const char *type_str; } TypeInfoInfo; struct {} OpaqueInfo; + struct { + const char *name; + } EmptyStruct; }; }; } TypeInfo; @@ -12,6 +12,14 @@ #include "typecheck.h" #include "builtins/util.h" +static bool has_extra_data(tag_ast_t *tags) +{ + for (tag_ast_t *tag = tags; tag; tag = tag->next) { + if (tag->fields) return true; + } + return false; +} + static CORD compile_str_method(env_t *env, ast_t *ast) { auto def = Match(ast, EnumDef); @@ -50,6 +58,14 @@ static CORD compile_compare_method(env_t *env, ast_t *ast) { auto def = Match(ast, EnumDef); CORD full_name = CORD_cat(env->file_prefix, def->name); + if (!has_extra_data(def->tags)) { + // Comparisons are simpler if there is only a tag, no tagged data: + return CORD_all("static int ", full_name, "$compare(const ", full_name, "_t *x, const ", full_name, + "_t *y, const TypeInfo *info) {\n" + "(void)info;\n" + "return (x->$tag - y->$tag);\n" + "}\n"); + } CORD cmp_func = CORD_all("static int ", full_name, "$compare(const ", full_name, "_t *x, const ", full_name, "_t *y, const TypeInfo *info) {\n" "(void)info;\n" @@ -73,6 +89,14 @@ static CORD compile_equals_method(env_t *env, ast_t *ast) { auto def = Match(ast, EnumDef); CORD full_name = CORD_cat(env->file_prefix, def->name); + if (!has_extra_data(def->tags)) { + // Equality is simpler if there is only a tag, no tagged data: + return CORD_all("static bool ", full_name, "$equal(const ", full_name, "_t *x, const ", full_name, + "_t *y, const TypeInfo *info) {\n" + "(void)info;\n" + "return (x->$tag == y->$tag);\n" + "}\n"); + } CORD eq_func = CORD_all("static bool ", full_name, "$equal(const ", full_name, "_t *x, const ", full_name, "_t *y, const TypeInfo *info) {\n" "(void)info;\n" @@ -95,6 +119,15 @@ static CORD compile_hash_method(env_t *env, ast_t *ast) { auto def = Match(ast, EnumDef); CORD full_name = CORD_cat(env->file_prefix, def->name); + if (!has_extra_data(def->tags)) { + // Hashing is simpler if there is only a tag, no tagged data: + return CORD_all("static uint32_t ", full_name, "$hash(const ", full_name, "_t *obj, const TypeInfo *info) {\n" + "(void)info;\n" + "uint32_t hash;\n" + "halfsiphash(&obj->$tag, sizeof(obj->$tag), TOMO_HASH_VECTOR, (uint8_t*)&hash, sizeof(hash));\n" + "return hash;" + "\n}\n"); + } CORD hash_func = CORD_all("static uint32_t ", full_name, "$hash(const ", full_name, "_t *obj, const TypeInfo *info) {\n" "(void)info;\n" "uint32_t hashes[2] = {(uint32_t)obj->$tag, 0};\n" @@ -167,17 +200,22 @@ void compile_enum_def(env_t *env, ast_t *ast) CORD typeinfo = CORD_asprintf("public const TypeInfo %s = {%zu, %zu, {.tag=CustomInfo, .CustomInfo={", full_name, type_size(t), type_align(t)); - env->code->funcs = CORD_all( - env->code->funcs, - compile_str_method(env, ast), - compile_equals_method(env, ast), compile_compare_method(env, ast), - compile_hash_method(env, ast)); - typeinfo = CORD_all( - typeinfo, - ".as_text=(void*)", full_name, "$as_text, " - ".equal=(void*)", full_name, "$equal, " - ".hash=(void*)", full_name, "$hash, " - ".compare=(void*)", full_name, "$compare"); + env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast)); + if (has_extra_data(def->tags)) { + env->code->funcs = CORD_all( + env->code->funcs, + compile_equals_method(env, ast), compile_compare_method(env, ast), + compile_hash_method(env, ast)); + typeinfo = CORD_all( + typeinfo, + ".as_text=(void*)", full_name, "$as_text, " + ".equal=(void*)", full_name, "$equal, " + ".hash=(void*)", full_name, "$hash, " + ".compare=(void*)", full_name, "$compare"); + } else { + // No need for custom methods if there is no tagged data + typeinfo = CORD_all(typeinfo, ".as_text=(void*)", full_name, "$as_text"); + } typeinfo = CORD_cat(typeinfo, "}}};\n"); env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo); @@ -133,38 +133,45 @@ void compile_struct_def(env_t *env, ast_t *ast) type_t *t = Table$str_get(*env->types, def->name); assert(t && t->tag == StructType); auto struct_ = Match(t, StructType); - CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=CustomInfo, .CustomInfo={", - full_name, type_size(t), type_align(t)); + if (def->fields) { + CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=CustomInfo, .CustomInfo={", + full_name, type_size(t), type_align(t)); - typeinfo = CORD_all(typeinfo, ".as_text=(void*)", full_name, "$as_text, "); - env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast)); + typeinfo = CORD_all(typeinfo, ".as_text=(void*)", full_name, "$as_text, "); + env->code->funcs = CORD_all(env->code->funcs, compile_str_method(env, ast)); - if (struct_->fields && !struct_->fields->next) { // Single member, can just use its methods - type_t *member_t = struct_->fields->type; - switch (member_t->tag) { - case TextType: - typeinfo = CORD_all(typeinfo, ".hash=(void*)", type_to_cord(member_t), "$hash", ", "); - // fallthrough - case IntType: case NumType: - typeinfo = CORD_all(typeinfo, ".compare=(void*)", type_to_cord(member_t), "$compare, " - ".equal=(void*)", type_to_cord(member_t), "$equal, "); - // fallthrough - case BoolType: goto got_methods; - default: break; + if (struct_->fields && !struct_->fields->next) { // Single member, can just use its methods + type_t *member_t = struct_->fields->type; + switch (member_t->tag) { + case TextType: + typeinfo = CORD_all(typeinfo, ".hash=(void*)", type_to_cord(member_t), "$hash", ", "); + // fallthrough + case IntType: case NumType: + typeinfo = CORD_all(typeinfo, ".compare=(void*)", type_to_cord(member_t), "$compare, " + ".equal=(void*)", type_to_cord(member_t), "$equal, "); + // fallthrough + case BoolType: goto got_methods; + default: break; + } } + if (struct_->fields) { + env->code->funcs = CORD_all(env->code->funcs, compile_compare_method(env, ast), + compile_equals_method(env, ast), compile_hash_method(env, ast)); + typeinfo = CORD_all( + typeinfo, + ".compare=(void*)", full_name, "$compare, " + ".equal=(void*)", full_name, "$equal, " + ".hash=(void*)", full_name, "$hash"); + } + got_methods:; + typeinfo = CORD_cat(typeinfo, "}}};\n"); + env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo); + } else { + // If there are no fields, we can use an EmptyStruct typeinfo, which generates less code: + CORD typeinfo = CORD_asprintf("public const TypeInfo %r = {%zu, %zu, {.tag=EmptyStruct, .EmptyStruct.name=%r}};\n", + full_name, type_size(t), type_align(t), Text$quoted(def->name, false)); + env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo); } - if (struct_->fields) { - env->code->funcs = CORD_all(env->code->funcs, compile_compare_method(env, ast), - compile_equals_method(env, ast), compile_hash_method(env, ast)); - typeinfo = CORD_all( - typeinfo, - ".compare=(void*)", full_name, "$compare, " - ".equal=(void*)", full_name, "$equal, " - ".hash=(void*)", full_name, "$hash"); - } - got_methods:; - typeinfo = CORD_cat(typeinfo, "}}};\n"); - env->code->typeinfos = CORD_all(env->code->typeinfos, typeinfo); compile_namespace(env, def->name, def->namespace); } |
