kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 5336a9a232e0099fbfbbabb4eb2be3e4cab93c02
parent df89de575e43a34401cd2a8cfbc73ae97c2e6c0e
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 14 May 2026 09:52:05 -0700

Remove C Type dependencies from src

Diffstat:
MMakefile | 2+-
Mdoc/cg-type-migration-plan.md | 4++--
Mdriver/as.c | 3++-
Mdriver/cc.c | 7++++---
Mdriver/env.c | 5++++-
Minclude/abi/abi.h | 31+++++--------------------------
Minclude/cfree.h | 50+++++++++-----------------------------------------
Minclude/cfree/cg.h | 10++++++++++
Minclude/core/pool.h | 12++----------
Alang/c/abi/c_abi.c | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alang/c/abi/c_abi.h | 19+++++++++++++++++++
Mlang/c/c.c | 48++++++++++++++++++++++++++++++++++++++++++++++++
Mlang/c/c.h | 1+
Alang/c/debug/c_debug.c | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/debug/c_debug.h -> lang/c/debug/c_debug.h | 0
Mlang/c/parse/attr.h | 2+-
Mlang/c/parse/parse.c | 24++++++++++++------------
Mlang/c/parse/parse_expr.c | 62+++++++++++++++++++++++++++++++-------------------------------
Mlang/c/parse/parse_init.c | 42+++++++++++++++++++++---------------------
Mlang/c/parse/parse_priv.h | 2+-
Mlang/c/parse/parse_stmt.c | 4++--
Mlang/c/parse/parse_type.c | 12++++++------
Mlang/c/pp/pp.h | 2+-
Mlang/c/pp/pp_priv.h | 2+-
Mlang/c/type/type.c | 17+++++++++++++++--
Mlang/c/type/type.h | 6++++--
Msrc/abi/abi.c | 373++-----------------------------------------------------------------------------
Msrc/abi/abi.h | 31+++++--------------------------
Msrc/abi/abi_aapcs64.c | 26+-------------------------
Msrc/abi/abi_apple_arm64.c | 13+------------
Msrc/abi/abi_internal.h | 4+---
Msrc/abi/abi_rv64.c | 10+---------
Msrc/abi/abi_sysv_x64.c | 27+--------------------------
Msrc/api/cg.c | 854++++++++++++++++++++++++++-----------------------------------------------------
Msrc/api/cg_api.h | 15---------------
Msrc/api/pipeline.c | 72+-----------------------------------------------------------------------
Msrc/api/stubs.c | 8++------
Msrc/arch/aarch64/alloc.c | 2+-
Msrc/arch/aarch64/emit.c | 78+++++++++++++++++++++---------------------------------------------------------
Msrc/arch/aarch64/internal.h | 11++++++-----
Msrc/arch/aarch64/ops.c | 4++--
Msrc/arch/arch.h | 32+++++++++++++++-----------------
Msrc/arch/rv64/alloc.c | 2+-
Msrc/arch/rv64/emit.c | 2+-
Msrc/arch/rv64/internal.h | 76+++++++++++++++++++++-------------------------------------------------------
Msrc/arch/rv64/ops.c | 4++--
Msrc/arch/x64/alloc.c | 3+--
Msrc/arch/x64/emit.c | 5++---
Msrc/arch/x64/internal.h | 75++++++++++++++++++++-------------------------------------------------------
Msrc/arch/x64/ops.c | 5++---
Msrc/core/pool.c | 17++---------------
Msrc/core/pool.h | 12++----------
Dsrc/debug/c_debug.c | 251-------------------------------------------------------------------------------
Msrc/debug/debug.h | 14+++++---------
Dsrc/decl/decl.h | 6------
Dsrc/decl/decl_attrs.h | 6------
Msrc/emu/cpu.c | 12++++++------
Msrc/emu/emu.h | 11+++++------
Msrc/lex/lex.h | 114++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/opt/ir.c | 6+++---
Msrc/opt/ir.h | 17++++++++---------
Msrc/opt/opt.c | 10+++++-----
Msrc/opt/pass_lower.c | 45+++++++++++++++++++++++++--------------------
Dsrc/parse/cg_public_compat.h | 6------
Dsrc/pp/pp.h | 6------
Dsrc/type/type.h | 6------
Mtest/api/cg_type_test.c | 17+++++++++++++++++
Mtest/opt/opt_test.c | 40++++++++++++++++++++++++++--------------
Mtest/parse/harness/parse_runner.c | 3+++
69 files changed, 1189 insertions(+), 1878 deletions(-)

diff --git a/Makefile b/Makefile @@ -68,7 +68,7 @@ build/lib/%.o: src/%.c build/lang/c/%.o: lang/c/%.c @mkdir -p $(dir $@) - $(CC) $(CFLAGS_COMMON) -ffreestanding -Iinclude -Ilang/c $(DEPFLAGS) -c $< -o $@ + $(CC) $(CFLAGS_COMMON) -ffreestanding -Iinclude -Ilang/c -Isrc $(DEPFLAGS) -c $< -o $@ build/lib/%.o: src/%.S @mkdir -p $(dir $@) diff --git a/doc/cg-type-migration-plan.md b/doc/cg-type-migration-plan.md @@ -9,7 +9,7 @@ codegen, ABI, arch lowering, optimizer, debug, object emission, and emu use Completion means: ```sh -rg 'lang/c|type/type\.h|const Type\*|TypeKind|TY_' src include/abi +rg 'lang/c|type/type\.h|const Type\*|\bTypeKind\b|\bTY_' src include/abi ``` finds no generic `src` dependency on C semantic types. C-specific files under @@ -152,6 +152,6 @@ behavior. make lib make bin make test-cg-api -rg 'lang/c|type/type\.h|const Type\*|TypeKind|TY_' src include/abi +rg 'lang/c|type/type\.h|const Type\*|\bTypeKind\b|\bTY_' src include/abi rg 'cg_api_type_import|cg_api_type_resolve|cfree_cg_internal_.*type' src ``` diff --git a/driver/as.c b/driver/as.c @@ -2,6 +2,7 @@ #include "cflags.h" #include "driver.h" +#include "lang/c/c.h" /* `cfree as` — standalone assembler. Reads a single text source, writes a * relocatable object via cfree_compile_obj_emit with the input tagged @@ -195,7 +196,7 @@ int driver_as(int argc, char** argv) { driver_errf(AS_TOOL, "out of memory"); goto out; } - if (cfree_preprocess(compiler, &pp, &input, pp_writer) != 0) goto out; + if (cfree_c_preprocess(compiler, &pp, &input, pp_writer) != 0) goto out; if (cfree_writer_error(pp_writer)) { driver_errf(AS_TOOL, "failed to preprocess: %s", o.source); goto out; diff --git a/driver/cc.c b/driver/cc.c @@ -2,6 +2,7 @@ #include "cflags.h" #include "driver.h" +#include "lang/c/c.h" #include "lib_resolve.h" /* `cfree cc` — C compiler driver. With -c produces a single object; @@ -973,7 +974,7 @@ static int cc_preprocess(DriverEnv* env, const CcOptions* o, goto out; } - rc = cfree_preprocess(compiler, pp_opts, &input, writer); + rc = cfree_c_preprocess(compiler, pp_opts, &input, writer); out: if (compiler) driver_compiler_free(compiler); @@ -1005,7 +1006,7 @@ static int cc_dump_tokens(DriverEnv* env, const CcOptions* o) { goto out; } - rc = cfree_dump_tokens(compiler, &input, writer); + rc = cfree_c_dump_tokens(compiler, &input, writer); out: if (compiler) driver_compiler_free(compiler); @@ -1338,7 +1339,7 @@ static int cc_run_deps_only(DriverEnv* env, const CcOptions* o, goto out; } - if (cfree_preprocess(compiler, pp, &input, discard) != 0) goto out; + if (cfree_c_preprocess(compiler, pp, &input, discard) != 0) goto out; rc = cc_dep_finish(env, &cenv, compiler, o); diff --git a/driver/env.c b/driver/env.c @@ -35,8 +35,9 @@ #include <libkern/OSCacheControl.h> #endif -#include "lang/toy/toy.h" #include "driver.h" +#include "lang/c/c.h" +#include "lang/toy/toy.h" /* Dual-mapping back-ends for strict W^X. Picks per-platform: * @@ -141,6 +142,7 @@ void driver_diag_set_compiler(CfreeCompiler* c) { g_diag_active_compiler = c; } CfreeCompiler* driver_compiler_new(CfreeTarget t, const CfreeEnv* env) { CfreeCompiler* c = cfree_compiler_new(t, env); if (c) { + cfree_c_register(c); (void)cfree_register_frontend(c, CFREE_LANG_TOY, cfree_toy_compile); driver_diag_set_compiler(c); } @@ -157,6 +159,7 @@ CfreePipeline* driver_pipeline_new(CfreeTarget t, const CfreeEnv* env) { CfreePipeline* p = cfree_pipeline_new(t, env); if (p) { CfreeCompiler* c = cfree_pipeline_compiler(p); + cfree_c_register(c); (void)cfree_register_frontend(c, CFREE_LANG_TOY, cfree_toy_compile); driver_diag_set_compiler(c); } diff --git a/include/abi/abi.h b/include/abi/abi.h @@ -4,12 +4,10 @@ #include <cfree/cg.h> #include "core/core.h" -#include "type/type.h" -/* TargetABI is the single authority for target-dependent C layout and calling - * convention decisions. Type remains structural and ABI-neutral; all sizes, - * alignments, field offsets, bitfield packing, scalar widths, and - * argument/return classifications are derived here from Compiler.target. */ +/* TargetABI is the single authority for target-dependent storage layout and + * calling convention decisions. Frontends lower source-language types to + * CfreeCgTypeId before entering this generic ABI layer. */ typedef struct TargetABI TargetABI; typedef enum ABIScalarKind { @@ -116,32 +114,13 @@ void abi_fini(TargetABI*); * The returned pointer is valid until abi_free returns. */ TargetABI* abi_new(Compiler*); void abi_free(TargetABI*); +Compiler* abi_compiler(TargetABI*); -/* Builtin scalar profiles and general type layout. New code should enter - * through CfreeCgTypeId; Type* overloads are the temporary C frontend bridge. */ ABITypeInfo abi_cg_type_info(TargetABI*, CfreeCgTypeId); u32 abi_cg_sizeof(TargetABI*, CfreeCgTypeId); u32 abi_cg_alignof(TargetABI*, CfreeCgTypeId); const ABIRecordLayout* abi_cg_record_layout(TargetABI*, CfreeCgTypeId); const ABIFuncInfo* abi_cg_func_info(TargetABI*, CfreeCgTypeId fn_type); - -ABITypeInfo abi_type_info(TargetABI*, const Type*); -u32 abi_sizeof(TargetABI*, const Type*); -u32 abi_alignof(TargetABI*, const Type*); - -/* Record layout is cached by Type* identity inside TargetABI and is stable for - * the lifetime of the ABI object. Incomplete records are fatal diagnostics. */ -const ABIRecordLayout* abi_record_layout(TargetABI*, const Type*); - -/* Calling convention classification. The returned object is owned by the ABI - * cache and remains valid until abi_fini. */ -const ABIFuncInfo* abi_func_info(TargetABI*, const Type* fn_type); - -/* Target-defined library types used by headers and builtins. */ -const Type* abi_size_type(TargetABI*, Pool*); -const Type* abi_ptrdiff_type(TargetABI*, Pool*); -const Type* abi_intptr_type(TargetABI*, Pool*); -const Type* abi_uintptr_type(TargetABI*, Pool*); -const Type* abi_va_list_type(TargetABI*, Pool*); +ABITypeInfo abi_va_list_info(TargetABI*); #endif diff --git a/include/cfree.h b/include/cfree.h @@ -23,6 +23,7 @@ typedef struct CfreeObjFile CfreeObjFile; typedef struct CfreeDebugInfo CfreeDebugInfo; typedef struct CfreeBytesInput CfreeBytesInput; typedef struct CfreeCompileOptions CfreeCompileOptions; +typedef struct CfreePpOptions CfreePpOptions; typedef uint32_t CfreeSym; /* ============================================================ @@ -698,14 +699,14 @@ typedef struct CfreeDefine { } CfreeDefine; /* Source language tag carried on CfreeBytesInput when the input is fed to - * cfree_compile_obj* or cfree_preprocess. Ignored by entries that take bytes + * cfree_compile_obj*. Ignored by entries that take bytes * for non-source purposes (linker, archive writer/reader, object reader). * * CFREE_LANG_C is value 0 so a zero-initialized CfreeBytesInput defaults to * C, matching the prior contract. * * `.S` (preprocessed asm) is NOT auto-handled at this layer: the driver runs - * cfree_preprocess first and then submits the result as CFREE_LANG_ASM. */ + * its C preprocessor first and then submits the result as CFREE_LANG_ASM. */ typedef enum CfreeLanguage { CFREE_LANG_C = 0, CFREE_LANG_ASM = 1, @@ -716,8 +717,7 @@ typedef enum CfreeLanguage { typedef int (*CfreeCompileFn)(CfreeCompiler*, const CfreeCompileOptions*, const CfreeBytesInput*, CfreeObjBuilder* out); -/* Register an out-of-core language frontend for this compiler instance. - * Built-in C and asm compilation remain available without registration. +/* Register out-of-core language frontend hooks for this compiler instance. * Passing NULL clears the slot. Returns nonzero on bad args. */ int cfree_register_frontend(CfreeCompiler*, CfreeLanguage, CfreeCompileFn); @@ -740,7 +740,7 @@ struct CfreeBytesInput { CfreeLanguage cfree_language_for_path(const char* path); /* Preprocessor configuration shared by compile_* and the convenience run. */ -typedef struct CfreePpOptions { +struct CfreePpOptions { const char* const* include_dirs; uint32_t ninclude_dirs; const char* const* system_include_dirs; @@ -749,7 +749,7 @@ typedef struct CfreePpOptions { uint32_t ndefines; const char* const* undefines; uint32_t nundefines; -} CfreePpOptions; +}; /* Path prefix remap entry. Applied by SourceManager whenever it produces a * path for DWARF emission (DW_AT_comp_dir, DW_AT_name, line program). The @@ -784,38 +784,6 @@ struct CfreeCompileOptions { uint32_t max_errors; }; -/* Preprocess one C input. - * - * Reads `input` through the preprocessor configured by `pp` and writes - * preprocessed text to `out`. The Writer is not closed. On nonzero return - * the Writer may contain partial output and should not be consumed. The - * input bytes must outlive this call. */ -int cfree_preprocess(CfreeCompiler*, const CfreePpOptions* pp, - const CfreeBytesInput* input, CfreeWriter* out); - -/* Lex one C input and write a stable, diff-friendly token dump to `out`. - * - * The format is one S-expression per line, terminated by `(eof)`. Examples: - * - * (ident foo) - * (num 42) - * (flt 3.14f) - * (str "hello") ; spelling for TOK_STR includes its surrounding quotes - * (chr 'a') - * (punct +) - * (punct ->) - * (pp-hash) - * (pp-paste) - * (newline) - * (eof) - * - * Source locations and token flags are intentionally omitted so whitespace - * edits don't churn diffs; the preprocessed-text path (cfree_preprocess) - * is the right place to validate spacing and BOL behavior. The Writer is - * not closed. The input bytes must outlive this call. */ -int cfree_dump_tokens(CfreeCompiler*, const CfreeBytesInput* input, - CfreeWriter* out); - /* Compile one source TU (C or GAS-subset asm; selected by input->lang). * * cfree_compile_obj returns a CfreeObjBuilder owned by the CfreeCompiler. The @@ -847,13 +815,13 @@ int cfree_compile_obj_emit(CfreeCompiler*, const CfreeCompileOptions*, /* ----- Header-dependency iteration ----- * * Walks the include edges recorded by SourceManager during a preceding - * cfree_preprocess or cfree_compile_obj* call. The library hands out raw + * cfree_compile_obj* call. The library hands out raw * edges; formatting (Make rules, ninja, JSON) is the driver's job. * * cfree_dep_iter_next returns 1 and fills `*out` for each remaining edge, * 0 when iteration is exhausted. The strings in CfreeDepEdge alias storage - * owned by the CfreeCompiler and are valid until the next preprocess/ - * compile call or compiler_free, whichever comes first. + * owned by the CfreeCompiler and are valid until the next compile call or + * compiler_free, whichever comes first. * * `includer_name` and `included_name` are the *resolved* paths SourceManager * actually opened — the same byte sequences passed to CfreeFileIO.read_all. diff --git a/include/cfree/cg.h b/include/cfree/cg.h @@ -116,6 +116,14 @@ typedef struct CfreeCgEnumValue { uint64_t value; /* bit pattern interpreted using the enum's integer base */ } CfreeCgEnumValue; +typedef struct CfreeCgRecordDesc { + CfreeSym tag; + const CfreeCgField* fields; + uint32_t nfields; + int is_union; + uint32_t align_override; /* 0 = natural, >0 explicit record alignment */ +} CfreeCgRecordDesc; + /* Builtin ids are stable for the compiler. Pointer, array, and function * constructors return a stable id for the same shape within one compiler; * aliases, records, and enums allocate fresh user-facing identities. @@ -138,6 +146,8 @@ CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler*, CfreeSym name, CfreeCgTypeId cfree_cg_type_record(CfreeCompiler*, CfreeSym tag, const CfreeCgField* fields, uint32_t nfields); +CfreeCgTypeId cfree_cg_type_record_ex(CfreeCompiler*, + const CfreeCgRecordDesc*); CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler*, CfreeSym tag, CfreeCgTypeId base, const CfreeCgEnumValue* values, diff --git a/include/core/pool.h b/include/core/pool.h @@ -5,8 +5,6 @@ #include "core/core.h" #include "core/heap.h" -typedef struct Type Type; /* declared in src/type/type.h */ - typedef struct PoolEntry { const char* data; u32 len; @@ -15,7 +13,7 @@ typedef struct PoolEntry { struct Pool { Heap* heap; - Arena arena; /* string and type-template storage */ + Arena arena; /* string storage */ /* Hash table: 0 means empty. Otherwise it's a Sym id (1-based). */ Sym* table; @@ -27,8 +25,7 @@ struct Pool { u32 nentries; u32 entries_cap; - /* Lazily-initialized type interning cache (defined in src/type/type.c). - * Opaque to other consumers; type.c casts as needed. */ + /* Frontends may hang language-specific interning state here. */ void* type_cache; }; @@ -40,9 +37,4 @@ Sym pool_intern(Pool*, const char* s, size_t len); Sym pool_intern_cstr(Pool*, const char* s); const char* pool_str(Pool*, Sym, size_t* len_out); -/* Types. Caller fills a stack-allocated Type template; pool returns the - * canonical pointer (allocating into the pool the first time). Equal types → - * equal pointers. */ -const Type* pool_type(Pool*, const Type* tmpl); - #endif diff --git a/lang/c/abi/c_abi.c b/lang/c/abi/c_abi.c @@ -0,0 +1,117 @@ +#include "abi/c_abi.h" + +#include "core/pool.h" + +static int c_type_is_signed_integer(const Type* t) { + if (!t) return 0; + switch ((TypeKind)t->kind) { + case TY_CHAR: + case TY_SCHAR: + case TY_SHORT: + case TY_INT: + case TY_LONG: + case TY_LLONG: + case TY_INT128: + case TY_ENUM: + return 1; + default: + return 0; + } +} + +ABITypeInfo c_abi_type_info(TargetABI* a, const Type* t) { + Compiler* c = abi_compiler(a); + ABITypeInfo r = abi_cg_type_info(a, type_cg_id(c, t)); + r.signed_ = c_type_is_signed_integer(t); + return r; +} + +u32 c_abi_sizeof(TargetABI* a, const Type* t) { + return c_abi_type_info(a, t).size; +} + +u32 c_abi_alignof(TargetABI* a, const Type* t) { + return c_abi_type_info(a, t).align; +} + +const ABIRecordLayout* c_abi_record_layout(TargetABI* a, const Type* t) { + return abi_cg_record_layout(a, type_cg_id(abi_compiler(a), t)); +} + +const ABIFuncInfo* c_abi_func_info(TargetABI* a, const Type* fn_type) { + return abi_cg_func_info(a, type_cg_id(abi_compiler(a), fn_type)); +} + +static const Type* c_size_or_uintptr(TargetABI* a, Pool* p) { + Compiler* c = abi_compiler(a); + return c->target.ptr_size == 8 ? type_prim(p, TY_ULLONG) + : type_prim(p, TY_UINT); +} + +const Type* c_abi_size_type(TargetABI* a, Pool* p) { + return c_size_or_uintptr(a, p); +} + +const Type* c_abi_ptrdiff_type(TargetABI* a, Pool* p) { + Compiler* c = abi_compiler(a); + return c->target.ptr_size == 8 ? type_prim(p, TY_LLONG) + : type_prim(p, TY_INT); +} + +const Type* c_abi_intptr_type(TargetABI* a, Pool* p) { + return c_abi_ptrdiff_type(a, p); +} + +const Type* c_abi_uintptr_type(TargetABI* a, Pool* p) { + return c_size_or_uintptr(a, p); +} + +const Type* c_abi_va_list_type(TargetABI* a, Pool* p) { + Compiler* c = abi_compiler(a); + switch (c->target.arch) { + case CFREE_ARCH_X86_64: { + const Type* vp = type_ptr(p, type_void(p)); + const Type* uit = type_prim(p, TY_UINT); + Sym name = pool_intern_cstr(p, "__va_list_tag"); + SrcLoc nl = {0, 0, 0}; + TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); + TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "gp_offset"), .type = uit}); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "fp_offset"), .type = uit}); + type_record_field( + b, + (Field){.name = pool_intern_cstr(p, "overflow_arg_area"), .type = vp}); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "reg_save_area"), .type = vp}); + return type_record_end(p, b); + } + case CFREE_ARCH_ARM_64: + if (c->target.os == CFREE_OS_MACOS) { + return type_ptr(p, type_prim(p, TY_CHAR)); + } else { + const Type* vp = type_ptr(p, type_void(p)); + const Type* it = type_prim(p, TY_INT); + Sym name = pool_intern_cstr(p, "__va_list"); + SrcLoc nl = {0, 0, 0}; + TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); + TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "__stack"), .type = vp}); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "__gr_top"), .type = vp}); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "__vr_top"), .type = vp}); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "__gr_offs"), .type = it}); + type_record_field( + b, (Field){.name = pool_intern_cstr(p, "__vr_offs"), .type = it}); + return type_record_end(p, b); + } + case CFREE_ARCH_RV64: + return type_ptr(p, type_void(p)); + default: + return type_ptr(p, type_void(p)); + } +} diff --git a/lang/c/abi/c_abi.h b/lang/c/abi/c_abi.h @@ -0,0 +1,19 @@ +#ifndef CFREE_LANG_C_ABI_H +#define CFREE_LANG_C_ABI_H + +#include "abi/abi.h" +#include "type/type.h" + +ABITypeInfo c_abi_type_info(TargetABI*, const Type*); +u32 c_abi_sizeof(TargetABI*, const Type*); +u32 c_abi_alignof(TargetABI*, const Type*); +const ABIRecordLayout* c_abi_record_layout(TargetABI*, const Type*); +const ABIFuncInfo* c_abi_func_info(TargetABI*, const Type*); + +const Type* c_abi_size_type(TargetABI*, Pool*); +const Type* c_abi_ptrdiff_type(TargetABI*, Pool*); +const Type* c_abi_intptr_type(TargetABI*, Pool*); +const Type* c_abi_uintptr_type(TargetABI*, Pool*); +const Type* c_abi_va_list_type(TargetABI*, Pool*); + +#endif diff --git a/lang/c/c.c b/lang/c/c.c @@ -8,6 +8,18 @@ #include "parse/parse.h" #include "pp/pp.h" +static SrcLoc c_no_loc(void) { + SrcLoc loc; + loc.file_id = 0; + loc.line = 0; + loc.col = 0; + return loc; +} + +static _Noreturn void c_bad_options(Compiler* c, const char* msg) { + compiler_panic(c, c_no_loc(), "bad C frontend options: %s", msg); +} + static void c_apply_pp_options(Pp* pp, const CfreePpOptions* opts) { u32 i; @@ -28,15 +40,31 @@ static void c_apply_pp_options(Pp* pp, const CfreePpOptions* opts) { int cfree_c_preprocess(CfreeCompiler* c, const CfreePpOptions* opts, const CfreeBytesInput* input, CfreeWriter* out) { + PanicSave saved; Lexer* lex; Pp* pp; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return 1; + } + if (!opts || !input || !out) { + c_bad_options(c, "preprocess args missing"); + } + if (!input->name) c_bad_options(c, "input name is NULL"); + if (!input->data && input->len != 0) { + c_bad_options(c, "input data is NULL but len > 0"); + } + lex = lex_open_mem(c, input->name, (const char*)input->data, input->len); pp = pp_new(c); c_apply_pp_options(pp, opts); pp_push_input(pp, lex); pp_emit_text(pp, out); pp_free(pp); + compiler_panic_restore(c, &saved); return 0; } @@ -97,9 +125,24 @@ static void dump_emit(CfreeWriter* w, Pool* p, const Tok* t) { int cfree_c_dump_tokens(CfreeCompiler* c, const CfreeBytesInput* input, CfreeWriter* out) { + PanicSave saved; Lexer* lex; Tok t; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return 1; + } + if (!input || !out) { + c_bad_options(c, "dump_tokens args missing"); + } + if (!input->name) c_bad_options(c, "input name is NULL"); + if (!input->data && input->len != 0) { + c_bad_options(c, "input data is NULL but len > 0"); + } + lex = lex_open_mem(c, input->name, (const char*)input->data, input->len); for (;;) { t = lex_next(lex); @@ -107,6 +150,7 @@ int cfree_c_dump_tokens(CfreeCompiler* c, const CfreeBytesInput* input, if (t.kind == TOK_EOF) break; } lex_close(lex); + compiler_panic_restore(c, &saved); return 0; } @@ -133,3 +177,7 @@ int cfree_c_compile(CfreeCompiler* c, const CfreeCompileOptions* opts, pp_free(pp); return 0; } + +void cfree_c_register(CfreeCompiler* c) { + (void)cfree_register_frontend(c, CFREE_LANG_C, cfree_c_compile); +} diff --git a/lang/c/c.h b/lang/c/c.h @@ -8,5 +8,6 @@ int cfree_c_compile(CfreeCompiler*, const CfreeCompileOptions*, int cfree_c_preprocess(CfreeCompiler*, const CfreePpOptions*, const CfreeBytesInput*, CfreeWriter*); int cfree_c_dump_tokens(CfreeCompiler*, const CfreeBytesInput*, CfreeWriter*); +void cfree_c_register(CfreeCompiler*); #endif diff --git a/lang/c/debug/c_debug.c b/lang/c/debug/c_debug.c @@ -0,0 +1,252 @@ +/* C-type → DebugTypeId adapter. + * + * Walks the C `Type*` chain, calling debug_type_* on the language-neutral + * Debug surface and caching the result keyed by Type* identity. + * + * Identity contract (see c_debug.h): the cache is per-Debug; equal Type* + * (canonical pool pointer) → equal DebugTypeId. Recursive shapes (a + * struct containing a pointer to itself) work because: + * - We allocate the record DIE id first via debug_type_record_begin / + * end and store the id in the cache *before* descending into fields. + * Cyclic references through a pointer get a fresh ptr-DIE that points + * back to the (now-known) record id. + * - Direct cycles (a struct containing itself by value) are illegal in + * C anyway. */ + +#include "debug/c_debug.h" + +#include <string.h> + +#include "core/core.h" +#include "core/heap.h" +#include "core/pool.h" +#include "core/vec.h" +#include "abi/c_abi.h" +#include "debug/debug.h" +#include "debug/debug_internal.h" + +/* Cache: Type* → DebugTypeId. + * + * We attach the cache to the Debug instance via a void* slot. Since + * DebugTypeId is u32 and we use a u64-keyed hashmap (PtrToU32 from the + * internal header), the cache survives the lifetime of one Debug. + * + * The cache is created lazily on first lookup so producers that don't + * use c_debug_type pay nothing. */ + +typedef struct CDebugCache { + PtrToU32 map; /* (u64)(uintptr_t)Type* → DebugTypeId */ +} CDebugCache; + +/* The Debug struct doesn't have a slot for the cache. Rather than + * touching debug.h, we keep a single (Debug* → cache) tiny association + * list. In practice exactly one Debug exists per TU; this list rarely + * grows past 1. */ + +typedef struct CDebugCacheEntry { + Debug* d; + CDebugCache* cache; +} CDebugCacheEntry; + +static CDebugCacheEntry* g_caches = NULL; +static u32 g_caches_n = 0; +static u32 g_caches_cap = 0; + +static CDebugCache* cache_for(Debug* d) { + u32 i; + Heap* h; + for (i = 0; i < g_caches_n; ++i) { + if (g_caches[i].d == d) return g_caches[i].cache; + } + h = (Heap*)d->c->env->heap; + if (VEC_GROW(h, g_caches, g_caches_cap, g_caches_n + 1)) return NULL; + { + CDebugCacheEntry* slot = &g_caches[g_caches_n++]; + slot->d = d; + slot->cache = + (CDebugCache*)h->alloc(h, sizeof(CDebugCache), _Alignof(CDebugCache)); + if (!slot->cache) { + g_caches_n--; + return NULL; + } + PtrToU32_init(&slot->cache->map, h); + return slot->cache; + } +} + +static DebugTypeId cache_get(CDebugCache* c, const Type* t) { + u32* v = PtrToU32_get(&c->map, (u64)(uintptr_t)t); + return v ? *v : DEBUG_TYPE_NONE; +} + +static void cache_put(CDebugCache* c, const Type* t, DebugTypeId id) { + PtrToU32_set(&c->map, (u64)(uintptr_t)t, id); +} + +/* ---- recursive type walk ---- */ + +static DebugTypeId walk(Debug* d, TargetABI* abi, const Type* t, + CDebugCache* cache); + +static Sym intern_cstr(Debug* d, const char* s) { + return pool_intern_cstr(d->c->global, s); +} + +static DebugTypeId base_id(Debug* d, TargetABI* abi, const Type* t, + const char* name, DebugBaseEncoding enc) { + return debug_type_base(d, intern_cstr(d, name), enc, c_abi_sizeof(abi, t)); +} + +static DebugTypeId walk_unqual(Debug* d, TargetABI* abi, const Type* t, + CDebugCache* cache) { + switch ((TypeKind)t->kind) { + case TY_VOID: + return debug_type_void(d); + case TY_BOOL: + return base_id(d, abi, t, "_Bool", DEBUG_BE_BOOL); + case TY_CHAR: + return base_id(d, abi, t, "char", DEBUG_BE_SIGNED_CHAR); + case TY_SCHAR: + return base_id(d, abi, t, "signed char", DEBUG_BE_SIGNED_CHAR); + case TY_UCHAR: + return base_id(d, abi, t, "unsigned char", DEBUG_BE_UNSIGNED_CHAR); + case TY_SHORT: + return base_id(d, abi, t, "short", DEBUG_BE_SIGNED); + case TY_USHORT: + return base_id(d, abi, t, "unsigned short", DEBUG_BE_UNSIGNED); + case TY_INT: + return base_id(d, abi, t, "int", DEBUG_BE_SIGNED); + case TY_UINT: + return base_id(d, abi, t, "unsigned int", DEBUG_BE_UNSIGNED); + case TY_LONG: + return base_id(d, abi, t, "long", DEBUG_BE_SIGNED); + case TY_ULONG: + return base_id(d, abi, t, "unsigned long", DEBUG_BE_UNSIGNED); + case TY_LLONG: + return base_id(d, abi, t, "long long", DEBUG_BE_SIGNED); + case TY_ULLONG: + return base_id(d, abi, t, "unsigned long long", DEBUG_BE_UNSIGNED); + case TY_INT128: + return base_id(d, abi, t, "__int128", DEBUG_BE_SIGNED); + case TY_UINT128: + return base_id(d, abi, t, "unsigned __int128", DEBUG_BE_UNSIGNED); + case TY_FLOAT: + return base_id(d, abi, t, "float", DEBUG_BE_FLOAT); + case TY_DOUBLE: + return base_id(d, abi, t, "double", DEBUG_BE_FLOAT); + case TY_LDOUBLE: + return base_id(d, abi, t, "long double", DEBUG_BE_FLOAT); + case TY_PTR: { + DebugTypeId pointee = walk(d, abi, t->ptr.pointee, cache); + return debug_type_ptr(d, pointee); + } + case TY_ARRAY: { + DebugTypeId elem = walk(d, abi, t->arr.elem, cache); + return debug_type_array(d, elem, t->arr.incomplete ? 0 : t->arr.count); + } + case TY_FUNC: { + DebugTypeId ret = walk(d, abi, t->fn.ret, cache); + DebugTypeId* params = NULL; + DebugTypeId result; + u32 i; + Heap* h = (Heap*)d->c->env->heap; + if (t->fn.nparams) { + params = (DebugTypeId*)h->alloc(h, sizeof(DebugTypeId) * t->fn.nparams, + _Alignof(DebugTypeId)); + if (!params) return DEBUG_TYPE_NONE; + for (i = 0; i < t->fn.nparams; ++i) { + params[i] = walk(d, abi, t->fn.params[i], cache); + } + } + result = debug_type_func(d, ret, params, t->fn.nparams, t->fn.variadic); + if (params) h->free(h, params, sizeof(DebugTypeId) * t->fn.nparams); + return result; + } + case TY_STRUCT: + case TY_UNION: { + const ABIRecordLayout* layout; + DebugTypeBuilder* b; + DebugTypeId id; + u32 i; + if (t->rec.incomplete) { + /* Emit an opaque record: zero size, no fields. */ + b = debug_type_record_begin(d, t->rec.tag, t->kind == TY_UNION, 0, 0); + return debug_type_record_end(b); + } + layout = c_abi_record_layout(abi, t); + b = debug_type_record_begin(d, t->rec.tag, t->kind == TY_UNION, + layout ? layout->size : 0, + layout ? layout->align : 0); + /* Pre-publish the cache entry pointing at the in-progress builder + * id so cycles via pointer fields resolve. We don't have a builder + * id yet; allocate one early via the record_end-then-walk strategy + * is safer. To keep things simple here, we cache after end_record. + * Self-referential pointers must therefore be expressed via a + * `Type*` that points to a *forward-declared* incomplete record + * (handled above), then refined later. For now no test path hits + * this. */ + for (i = 0; i < t->rec.nfields; ++i) { + const Field* f = &t->rec.fields[i]; + DebugTypeId ftype = walk(d, abi, f->type, cache); + u32 byte_ofs = layout ? layout->fields[i].offset : 0; + if (f->flags & FIELD_BITFIELD) { + u16 bit_ofs = layout ? layout->fields[i].bit_offset : 0; + debug_type_record_bitfield(b, f->name, ftype, byte_ofs, bit_ofs, + f->bitfield_width); + } else { + debug_type_record_field(b, f->name, ftype, byte_ofs); + } + } + id = debug_type_record_end(b); + return id; + } + case TY_ENUM: { + DebugTypeId base = walk(d, abi, t->enm.base, cache); + DebugEnumBuilder* b = debug_type_enum_begin(d, t->enm.tag, base); + /* Type doesn't carry enum members directly; we'd need a registry + * lookup keyed by tag_id. Leave empty — consumers see an enum + * with no enumerators. */ + return debug_type_enum_end(b); + } + } + return DEBUG_TYPE_NONE; +} + +static DebugTypeId walk(Debug* d, TargetABI* abi, const Type* t, + CDebugCache* cache) { + DebugTypeId cached; + DebugTypeId base_id_; + DebugTypeId result; + if (!t) return DEBUG_TYPE_NONE; + cached = cache_get(cache, t); + if (cached != DEBUG_TYPE_NONE) return cached; + + /* Strip and re-apply qualifiers. The unqualified type goes into the + * pool as one DIE; const/volatile/restrict layer DIEs around it. */ + if (t->qual) { + /* Build the unqualified core, then layer qualifiers. We can't simply + * re-pool a Type with qual=0 because we don't have a pool here. + * Instead walk fields directly and synthesize. */ + /* Synthesize unqualified DIE from the same shape. We construct a + * shallow Type with qual=0 and recurse via walk_unqual. */ + Type tmp = *t; + tmp.qual = 0; + base_id_ = walk_unqual(d, abi, &tmp, cache); + result = base_id_; + if (t->qual & Q_CONST) result = debug_type_const(d, result); + if (t->qual & Q_VOLATILE) result = debug_type_volatile(d, result); + if (t->qual & Q_RESTRICT) result = debug_type_restrict(d, result); + } else { + result = walk_unqual(d, abi, t, cache); + } + cache_put(cache, t, result); + return result; +} + +DebugTypeId c_debug_type(Debug* d, TargetABI* abi, const Type* t) { + CDebugCache* cache; + if (!d || !t) return DEBUG_TYPE_NONE; + cache = cache_for(d); + if (!cache) return DEBUG_TYPE_NONE; + return walk(d, abi, t, cache); +} diff --git a/src/debug/c_debug.h b/lang/c/debug/c_debug.h diff --git a/lang/c/parse/attr.h b/lang/c/parse/attr.h @@ -4,7 +4,7 @@ #include "core/core.h" /* GNU __attribute__((...)) AST node, shared between the parser (producer) - * and the Phase 2 consumers in src/decl (decl_attrs.c). The parser builds + * and the declaration-attribute consumers. The parser builds * the list and chains it onto its carriers (DeclSpecs.attrs, * TagEntry.attrs, SymEntry.attrs); consumers walk a `const Attr*` head * and decode according to `kind`. See doc/ATTRIBUTE.md. */ diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c @@ -322,7 +322,7 @@ TagEntry* tag_lookup_local(Parser* p, Sym name) { * ============================================================ */ static const Type* ty_size_t(Parser* p) { - return abi_size_type(p->abi, p->pool); + return c_abi_size_type(p->abi, p->pool); } /* ============================================================ @@ -334,12 +334,12 @@ FrameSlot make_local_aligned(Parser* p, Sym name, const Type* type, FrameSlotDesc fsd; FrameSlot s; SymEntry* e; - u32 nat = abi_alignof(p->abi, type); + u32 nat = c_abi_alignof(p->abi, type); memset(&fsd, 0, sizeof fsd); fsd.type = type; fsd.name = name; fsd.loc = loc; - fsd.size = abi_sizeof(p->abi, type); + fsd.size = c_abi_sizeof(p->abi, type); fsd.align = (align_override > nat) ? align_override : nat; fsd.kind = FS_LOCAL; fsd.flags = FSF_NONE; @@ -401,13 +401,13 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { if (p->vla_pending && var_ty && var_ty->kind == TY_ARRAY) { FrameSlot count_slot = p->vla_pending_count_slot; const Type* elem_ty = var_ty->arr.elem; - u32 esz = abi_sizeof(p->abi, elem_ty); + u32 esz = c_abi_sizeof(p->abi, elem_ty); FrameSlotDesc bsd; FrameSlot byte_slot; memset(&bsd, 0, sizeof bsd); bsd.type = ty_size_t(p); - bsd.size = abi_sizeof(p->abi, bsd.type); - bsd.align = abi_alignof(p->abi, bsd.type); + bsd.size = c_abi_sizeof(p->abi, bsd.type); + bsd.align = c_abi_alignof(p->abi, bsd.type); bsd.kind = FS_LOCAL; byte_slot = cg_local(p->cg, &bsd); cg_set_loc(p->cg, loc); @@ -507,12 +507,12 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { SymEntry* sym_entry; if (p->vla_pending) { FrameSlot count_slot = p->vla_pending_count_slot; - u32 esz = abi_sizeof(p->abi, elem_ty); + u32 esz = c_abi_sizeof(p->abi, elem_ty); FrameSlotDesc bsd; memset(&bsd, 0, sizeof bsd); bsd.type = ty_size_t(p); - bsd.size = abi_sizeof(p->abi, bsd.type); - bsd.align = abi_alignof(p->abi, bsd.type); + bsd.size = c_abi_sizeof(p->abi, bsd.type); + bsd.align = c_abi_alignof(p->abi, bsd.type); bsd.kind = FS_LOCAL; byte_slot = cg_local(p->cg, &bsd); p->vla_pending = 0; @@ -750,8 +750,8 @@ static void parse_function_body(Parser* p, ObjSymId fsym, const Type* fn_ty, fsd.type = infos[i].type; fsd.name = infos[i].name; fsd.loc = infos[i].loc; - fsd.size = abi_sizeof(p->abi, infos[i].type); - fsd.align = abi_alignof(p->abi, infos[i].type); + fsd.size = c_abi_sizeof(p->abi, infos[i].type); + fsd.align = c_abi_alignof(p->abi, infos[i].type); fsd.kind = FS_PARAM; fsd.flags = FSF_NONE; s = pcg_param_slot(p, i, &fsd); @@ -850,7 +850,7 @@ static void parse_external_decl(Parser* p) { for (u16 i = 0; i < nparams; ++i) ptypes[i] = infos[i].type; } fn_ty = type_func(p->pool, base_ty, ptypes, nparams, (int)variadic); - abi = abi_func_info(p->abi, fn_ty); + abi = c_abi_func_info(p->abi, fn_ty); ObjSecId fn_section_id; u32 fn_decl_flags; diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -5,7 +5,7 @@ static const Type* ty_int(Parser* p) { return type_prim(p->pool, TY_INT); } static const Type* ty_size_t(Parser* p) { - return abi_size_type(p->abi, p->pool); + return c_abi_size_type(p->abi, p->pool); } @@ -364,14 +364,14 @@ static i64 cexpr_unary(Parser* p, SrcLoc loc) { { const Type* t = parse_type_name(p); expect_punct(p, ')', "')' after sizeof type-name"); - return (i64)abi_sizeof(p->abi, t); + return (i64)c_abi_sizeof(p->abi, t); } } } parse_unary(p); { const Type* ty = cg_top_type(p->cg); - i64 sz = (i64)abi_sizeof(p->abi, ty); + i64 sz = (i64)c_abi_sizeof(p->abi, ty); cg_drop(p->cg); return sz; } @@ -384,14 +384,14 @@ static i64 cexpr_unary(Parser* p, SrcLoc loc) { { const Type* t = parse_type_name(p); expect_punct(p, ')', "')' after _Alignof type-name"); - return (i64)abi_alignof(p->abi, t); + return (i64)c_abi_alignof(p->abi, t); } } } parse_unary(p); { const Type* ty = cg_top_type(p->cg); - i64 al = (i64)abi_alignof(p->abi, ty); + i64 al = (i64)c_abi_alignof(p->abi, ty); cg_drop(p->cg); return al; } @@ -402,8 +402,8 @@ static i64 cexpr_unary(Parser* p, SrcLoc loc) { expect_punct(p, ')', "')' after cast type-name"); { i64 v = cexpr_unary(p, loc); - u32 sz = abi_sizeof(p->abi, t); - int is_signed = abi_type_info(p->abi, t).signed_; + u32 sz = c_abi_sizeof(p->abi, t); + int is_signed = c_abi_type_info(p->abi, t).signed_; if (sz < 8) { u64 mask = (1ull << (sz * 8u)) - 1ull; u64 uv = (u64)v & mask; @@ -510,8 +510,8 @@ static const Type* offsetof_designator(Parser* p, const Type* base, u32* off) { u32 moff = 0; const Field* mf = NULL; /* find_field is static in parse_type.c; we need it here. - * We call abi_record_layout directly inline. */ - const ABIRecordLayout* L = abi_record_layout(p->abi, cur); + * We call c_abi_record_layout directly inline. */ + const ABIRecordLayout* L = c_abi_record_layout(p->abi, cur); if (!L) perr(p, "no such member in __builtin_offsetof"); int found = 0; for (u16 i = 0; i < cur->rec.nfields; ++i) { @@ -548,7 +548,7 @@ static const Type* offsetof_designator(Parser* p, const Type* base, u32* off) { if (cur->kind != TY_ARRAY) { perr(p, "__builtin_offsetof '[' on non-array"); } - *off += (u32)((i64)abi_sizeof(p->abi, cur->arr.elem) * idx); + *off += (u32)((i64)c_abi_sizeof(p->abi, cur->arr.elem) * idx); cur = cur->arr.elem; continue; } @@ -788,8 +788,8 @@ static int try_parse_builtin_call(Parser* p) { FrameSlotDesc pd; memset(&pd, 0, sizeof pd); pd.type = val_ty; - pd.size = abi_sizeof(p->abi, val_ty); - pd.align = abi_alignof(p->abi, val_ty); + pd.size = c_abi_sizeof(p->abi, val_ty); + pd.align = c_abi_alignof(p->abi, val_ty); pd.kind = FS_LOCAL; FrameSlot pslot = cg_local(p->cg, &pd); cg_push_local_typed(p->cg, pslot, val_ty); @@ -1032,7 +1032,7 @@ static void parse_postfix(Parser* p) { perr(p, "invalid subscript: needs one pointer and one integer"); } if (!elem) perr(p, "subscript on incomplete pointee"); - u32 esz = abi_sizeof(p->abi, elem); + u32 esz = c_abi_sizeof(p->abi, elem); if (esz != 1) { cg_push_int(p->cg, (i64)esz, ty_size_t(p)); cg_binop(p->cg, BO_IMUL); @@ -1058,7 +1058,7 @@ static void parse_postfix(Parser* p) { mname = p->cur.v.ident; advance(p); { - const ABIRecordLayout* L = abi_record_layout(p->abi, lt); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, lt); if (!L) perr(p, "no such member"); int found = 0; for (u16 i = 0; i < lt->rec.nfields; ++i) { @@ -1076,7 +1076,7 @@ static void parse_postfix(Parser* p) { const Type* inner_ty = NULL; u32 inner_off = 0; const Field* inner_f = NULL; - const ABIRecordLayout* IL = abi_record_layout(p->abi, f->type); + const ABIRecordLayout* IL = c_abi_record_layout(p->abi, f->type); if (IL) { for (u16 j = 0; j < f->type->rec.nfields; ++j) { const Field* ff = &f->type->rec.fields[j]; @@ -1132,7 +1132,7 @@ static void parse_postfix(Parser* p) { mname = p->cur.v.ident; advance(p); { - const ABIRecordLayout* L = abi_record_layout(p->abi, rec_ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, rec_ty); if (!L) perr(p, "no such member"); int found = 0; for (u16 i = 0; i < rec_ty->rec.nfields; ++i) { @@ -1146,7 +1146,7 @@ static void parse_postfix(Parser* p) { } if ((f->flags & FIELD_ANON) && (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) { - const ABIRecordLayout* IL = abi_record_layout(p->abi, f->type); + const ABIRecordLayout* IL = c_abi_record_layout(p->abi, f->type); if (IL) { for (u16 j = 0; j < f->type->rec.nfields; ++j) { const Field* ff = &f->type->rec.fields[j]; @@ -1195,8 +1195,8 @@ void parse_unary(Parser* p) { } memset(&fsd, 0, sizeof fsd); fsd.type = lit_ty; - fsd.size = abi_sizeof(p->abi, lit_ty); - fsd.align = abi_alignof(p->abi, lit_ty); + fsd.size = c_abi_sizeof(p->abi, lit_ty); + fsd.align = c_abi_alignof(p->abi, lit_ty); fsd.kind = FS_LOCAL; fsd.flags = FSF_NONE; slot = cg_local(p->cg, &fsd); @@ -1311,7 +1311,7 @@ void parse_unary(Parser* p) { cg_push_local_typed(p->cg, vla_slot, ty_size_t(p)); cg_load(p->cg); } else { - cg_push_int(p->cg, (i64)abi_sizeof(p->abi, ty), ty_size_t(p)); + cg_push_int(p->cg, (i64)c_abi_sizeof(p->abi, ty), ty_size_t(p)); } return; } @@ -1446,7 +1446,7 @@ void parse_unary(Parser* p) { cg_drop(p->cg); } expect_punct(p, ')', "')'"); - cg_push_int(p->cg, (i64)abi_alignof(p->abi, ty), ty_size_t(p)); + cg_push_int(p->cg, (i64)c_abi_alignof(p->abi, ty), ty_size_t(p)); return; } parse_postfix(p); @@ -1526,7 +1526,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { int r_is_ptr = rt && rt->kind == TY_PTR; if (bop == BO_IADD) { if (l_is_ptr && type_is_int(rt)) { - u32 esz = abi_sizeof(p->abi, lt->ptr.pointee); + u32 esz = c_abi_sizeof(p->abi, lt->ptr.pointee); if (esz != 1) { cg_push_int(p->cg, (i64)esz, ty_size_t(p)); cg_binop(p->cg, BO_IMUL); @@ -1536,7 +1536,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { } if (r_is_ptr && type_is_int(lt)) { cg_swap(p->cg); - u32 esz = abi_sizeof(p->abi, rt->ptr.pointee); + u32 esz = c_abi_sizeof(p->abi, rt->ptr.pointee); if (esz != 1) { cg_push_int(p->cg, (i64)esz, ty_size_t(p)); cg_binop(p->cg, BO_IMUL); @@ -1546,7 +1546,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { } } else { /* BO_ISUB */ if (l_is_ptr && type_is_int(rt)) { - u32 esz = abi_sizeof(p->abi, lt->ptr.pointee); + u32 esz = c_abi_sizeof(p->abi, lt->ptr.pointee); if (esz != 1) { cg_push_int(p->cg, (i64)esz, ty_size_t(p)); cg_binop(p->cg, BO_IMUL); @@ -1555,7 +1555,7 @@ static void emit_add_or_sub(Parser* p, BinOp bop) { return; } if (l_is_ptr && r_is_ptr) { - u32 esz = abi_sizeof(p->abi, lt->ptr.pointee); + u32 esz = c_abi_sizeof(p->abi, lt->ptr.pointee); cg_binop(p->cg, BO_ISUB); if (esz != 1) { cg_push_int(p->cg, (i64)esz, ty_size_t(p)); @@ -1693,8 +1693,8 @@ static FrameSlot ll_tmp_slot(Parser* p, const Type* ty) { FrameSlotDesc fsd; memset(&fsd, 0, sizeof fsd); fsd.type = ty; - fsd.size = abi_sizeof(p->abi, ty); - fsd.align = abi_alignof(p->abi, ty); + fsd.size = c_abi_sizeof(p->abi, ty); + fsd.align = c_abi_alignof(p->abi, ty); fsd.kind = FS_LOCAL; fsd.flags = FSF_NONE; return cg_local(p->cg, &fsd); @@ -1770,8 +1770,8 @@ static void parse_ternary(Parser* p) { if (!result_ty) result_ty = ty_int(p); memset(&fsd, 0, sizeof fsd); fsd.type = result_ty; - fsd.size = abi_sizeof(p->abi, result_ty); - fsd.align = abi_alignof(p->abi, result_ty); + fsd.size = c_abi_sizeof(p->abi, result_ty); + fsd.align = c_abi_alignof(p->abi, result_ty); fsd.kind = FS_LOCAL; fsd.flags = FSF_NONE; tmp = cg_local(p->cg, &fsd); @@ -1799,8 +1799,8 @@ static void parse_ternary(Parser* p) { FrameSlot ctmp; memset(&cfsd, 0, sizeof cfsd); cfsd.type = common; - cfsd.size = abi_sizeof(p->abi, common); - cfsd.align = abi_alignof(p->abi, common); + cfsd.size = c_abi_sizeof(p->abi, common); + cfsd.align = c_abi_alignof(p->abi, common); cfsd.kind = FS_LOCAL; cfsd.flags = FSF_NONE; ctmp = cg_local(p->cg, &cfsd); diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -17,7 +17,7 @@ * ============================================================ */ static const Type* ty_size_t_init(Parser* p) { - return abi_size_type(p->abi, p->pool); + return c_abi_size_type(p->abi, p->pool); } static SrcLoc tok_loc_init(const Tok* t) { return t->loc; } @@ -91,7 +91,7 @@ static void emit_walk_copy(Parser* p, FrameSlot dst_slot, FrameSlot src_ptr_slot, const Type* src_ptr_ty, u32 src_off, const Type* ty) { if (ty->kind == TY_STRUCT) { - const ABIRecordLayout* L = abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, ty); for (u16 i = 0; i < ty->rec.nfields; ++i) { const Field* f = &ty->rec.fields[i]; if (f->flags & FIELD_BITFIELD) continue; @@ -102,7 +102,7 @@ static void emit_walk_copy(Parser* p, FrameSlot dst_slot, return; } if (ty->kind == TY_ARRAY) { - u32 esz = abi_sizeof(p->abi, ty->arr.elem); + u32 esz = c_abi_sizeof(p->abi, ty->arr.elem); for (u32 i = 0; i < ty->arr.count; ++i) { emit_walk_copy(p, dst_slot, dst_arr_ty, dst_off + i * esz, src_ptr_slot, src_ptr_ty, src_off + i * esz, @@ -111,7 +111,7 @@ static void emit_walk_copy(Parser* p, FrameSlot dst_slot, return; } if (ty->kind == TY_UNION) { - u32 sz = abi_sizeof(p->abi, ty); + u32 sz = c_abi_sizeof(p->abi, ty); const Type* uchar_ty = type_prim(p->pool, TY_UCHAR); for (u32 i = 0; i < sz; ++i) { emit_copy_leaf(p, dst_slot, dst_arr_ty, dst_off + i, @@ -135,8 +135,8 @@ void emit_struct_copy_into_slot(Parser* p, FrameSlot dst_slot, cg_addr(p->cg); memset(&fsd, 0, sizeof fsd); fsd.type = ptr_ty; - fsd.size = abi_sizeof(p->abi, ptr_ty); - fsd.align = abi_alignof(p->abi, ptr_ty); + fsd.size = c_abi_sizeof(p->abi, ptr_ty); + fsd.align = c_abi_alignof(p->abi, ptr_ty); fsd.kind = FS_LOCAL; fsd.flags = FSF_NONE; src_ptr_slot = cg_local(p->cg, &fsd); @@ -151,14 +151,14 @@ void emit_struct_copy_into_slot(Parser* p, FrameSlot dst_slot, static void zero_init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* ty) { if (ty->kind == TY_ARRAY) { - u32 esz = abi_sizeof(p->abi, ty->arr.elem); + u32 esz = c_abi_sizeof(p->abi, ty->arr.elem); for (u32 i = 0; i < ty->arr.count; ++i) { zero_init_at(p, slot, arr_ty, offset + i * esz, ty->arr.elem); } return; } if (ty->kind == TY_STRUCT) { - const ABIRecordLayout* L = abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, ty); for (u16 i = 0; i < ty->rec.nfields; ++i) { const Field* f = &ty->rec.fields[i]; zero_init_at(p, slot, arr_ty, offset + L->fields[i].offset, f->type); @@ -225,7 +225,7 @@ static void parse_designator_chain(Parser* p, const Type* outer_ty, if (idx < 0 || (u32)idx >= cur_ty->arr.count) { perr(p, "array designator index out of range"); } - esz = abi_sizeof(p->abi, cur_ty->arr.elem); + esz = c_abi_sizeof(p->abi, cur_ty->arr.elem); cur_off += (u32)idx * esz; cur_ty = cur_ty->arr.elem; if (first) *top_index_out = (u32)idx; @@ -285,7 +285,7 @@ static void parse_designator_chain(Parser* p, const Type* outer_ty, static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* ty, u32 start_field, int braced) { - const ABIRecordLayout* L = abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, ty); u32 i = start_field; u32 zero_lo = start_field; for (; i < ty->rec.nfields; ++i) { @@ -338,7 +338,7 @@ static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty, static u32 init_elided(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* ty) { if (ty->kind == TY_ARRAY) { - u32 esz = abi_sizeof(p->abi, ty->arr.elem); + u32 esz = c_abi_sizeof(p->abi, ty->arr.elem); init_at(p, slot, arr_ty, offset, ty->arr.elem); (void)esz; return 1; @@ -365,7 +365,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* ty) { if (ty->kind == TY_ARRAY) { const Type* elem_ty = ty->arr.elem; - u32 esz = abi_sizeof(p->abi, elem_ty); + u32 esz = c_abi_sizeof(p->abi, elem_ty); if (is_char_kind(elem_ty)) { if (p->cur.kind == TOK_STR) { init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count); @@ -568,7 +568,7 @@ static int try_parse_addr_const(Parser* p, const Type* ty, u8* buf, expect_punct(p, ']', "']' after array-subscript constant"); if (tgt_ty && tgt_ty->kind == TY_ARRAY) { byte_addend += - element_addend * (i64)abi_sizeof(p->abi, tgt_ty->arr.elem); + element_addend * (i64)c_abi_sizeof(p->abi, tgt_ty->arr.elem); } else { byte_addend += element_addend; } @@ -582,11 +582,11 @@ static int try_parse_addr_const(Parser* p, const Type* ty, u8* buf, v = eval_const_int(p, cloc); if (neg) v = -v; if (tgt_ty && tgt_ty->kind == TY_ARRAY) { - byte_addend += v * (i64)abi_sizeof(p->abi, tgt_ty->arr.elem); + byte_addend += v * (i64)c_abi_sizeof(p->abi, tgt_ty->arr.elem); } else if (tgt_ty && tgt_ty->kind == TY_PTR) { - byte_addend += v * (i64)abi_sizeof(p->abi, tgt_ty->ptr.pointee); + byte_addend += v * (i64)c_abi_sizeof(p->abi, tgt_ty->ptr.pointee); } else if (saw_amp) { - byte_addend += v * (i64)abi_sizeof(p->abi, tgt_ty); + byte_addend += v * (i64)c_abi_sizeof(p->abi, tgt_ty); } else { byte_addend += v; } @@ -602,7 +602,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, const Type* ty) { if (ty->kind == TY_ARRAY) { const Type* elem = ty->arr.elem; - u32 esz = abi_sizeof(p->abi, elem); + u32 esz = c_abi_sizeof(p->abi, elem); u32 i = 0; int had_brace; if (is_char_kind(elem)) { @@ -647,7 +647,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, } if (ty->kind == TY_STRUCT) { int had_brace = accept_punct(p, '{'); - const ABIRecordLayout* L = abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, ty); u32 i = 0; if (!had_brace) { perr(p, "expected '{' for static-storage struct initializer"); @@ -679,7 +679,7 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, { int had_brace = accept_punct(p, '{'); SrcLoc cloc = tok_loc_init(&p->cur); - u32 sz = abi_sizeof(p->abi, ty); + u32 sz = c_abi_sizeof(p->abi, ty); if (offset + sz > buflen) perr(p, "initializer overflows object"); if (ty->kind == TY_PTR && try_parse_addr_const(p, ty, buf, offset, sz)) { /* Address constant recorded as a reloc. */ @@ -739,8 +739,8 @@ static void emit_static_data(Parser* p, const u8* buf, u32 size) { void define_static_object(Parser* p, ObjSymId sym, ObjSecId section_id, const Type* var_ty, u16 quals, int has_init, SrcLoc loc, u32 align_override) { - u32 size = abi_sizeof(p->abi, var_ty); - u32 align = abi_alignof(p->abi, var_ty); + u32 size = c_abi_sizeof(p->abi, var_ty); + u32 align = c_abi_alignof(p->abi, var_ty); CfreeCgDataDefAttrs attrs; if (align_override > align) align = align_override; u8* buf = NULL; diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h @@ -11,7 +11,7 @@ #include <stdarg.h> #include <string.h> -#include "abi/abi.h" +#include "abi/c_abi.h" #include "core/arena.h" #include "core/core.h" #include "core/heap.h" diff --git a/lang/c/parse/parse_stmt.c b/lang/c/parse/parse_stmt.c @@ -264,8 +264,8 @@ static void parse_switch_stmt(Parser* p) { memset(&ctx, 0, sizeof ctx); memset(&fsd, 0, sizeof fsd); fsd.type = vty; - fsd.size = abi_sizeof(p->abi, vty); - fsd.align = abi_alignof(p->abi, vty); + fsd.size = c_abi_sizeof(p->abi, vty); + fsd.align = c_abi_alignof(p->abi, vty); fsd.kind = FS_LOCAL; ctx.value_slot = cg_local(p->cg, &fsd); ctx.value_type = vty; diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -9,7 +9,7 @@ static const Type* ty_int(Parser* p) { return type_prim(p->pool, TY_INT); } static const Type* ty_size_t(Parser* p) { - return abi_size_type(p->abi, p->pool); + return c_abi_size_type(p->abi, p->pool); } /* ============================================================ @@ -486,7 +486,7 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { expect_punct(p, '(', "'(' after _Alignas"); if (starts_type_name(p, &p->cur)) { const Type* tn = parse_type_name(p); - a = abi_alignof(p->abi, tn); + a = c_abi_alignof(p->abi, tn); } else { i64 v = eval_const_int(p, tok_loc(&p->cur)); if (v < 0) perr(p, "_Alignas requires a non-negative alignment"); @@ -505,7 +505,7 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { } else if (!acc.saw_explicit_type && !tagged_ty && t.kind == TOK_IDENT && ident_kw(p, t.v.ident) == KW_NONE) { if (t.v.ident == p->sym_b_va_list) { - tagged_ty = abi_va_list_type(p->abi, p->pool); + tagged_ty = c_abi_va_list_type(p->abi, p->pool); acc.saw_explicit_type = 1; advance(p); seen = 1; @@ -548,7 +548,7 @@ int find_field(TargetABI* abi, const Type* rec, Sym name, const Type** out_type, u32* out_offset, const Field** out_field) { if (!rec || (rec->kind != TY_STRUCT && rec->kind != TY_UNION)) return 0; - const ABIRecordLayout* L = abi_record_layout(abi, rec); + const ABIRecordLayout* L = c_abi_record_layout(abi, rec); if (!L) return 0; for (u16 i = 0; i < rec->rec.nfields; ++i) { const Field* f = &rec->rec.fields[i]; @@ -938,8 +938,8 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { out->vla = 1; memset(&fsd, 0, sizeof fsd); fsd.type = ty_size_t(p); - fsd.size = abi_sizeof(p->abi, fsd.type); - fsd.align = abi_alignof(p->abi, fsd.type); + fsd.size = c_abi_sizeof(p->abi, fsd.type); + fsd.align = c_abi_alignof(p->abi, fsd.type); fsd.kind = FS_LOCAL; out->vla_count_slot = cg_local(p->cg, &fsd); parse_assign_expr(p); diff --git a/lang/c/pp/pp.h b/lang/c/pp/pp.h @@ -30,7 +30,7 @@ const LitInfo* pp_lit(const Pp*, LitId); /* Drains pp_next into `out` as preprocessed C source text: token spellings * separated by single spaces where TF_HAS_SPACE is set, with newlines for - * TF_AT_BOL transitions. Stops on TOK_EOF. Used by cfree_preprocess. */ + * TF_AT_BOL transitions. Stops on TOK_EOF. Used by the C driver. */ void pp_emit_text(Pp*, Writer* out); #endif diff --git a/lang/c/pp/pp_priv.h b/lang/c/pp/pp_priv.h @@ -1,6 +1,6 @@ /* pp_priv.h — shared types, helpers, and cross-module forward declarations * for the preprocessor split (pp.c / pp_expand.c / pp_directive.c). - * NOT part of the public API; included only within src/pp/. */ + * NOT part of the public API; included only within lang/c/pp/. */ #ifndef CFREE_PP_PRIV_H #define CFREE_PP_PRIV_H diff --git a/lang/c/type/type.c b/lang/c/type/type.c @@ -420,15 +420,28 @@ static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, const Type* t, case TY_STRUCT: case TY_UNION: { CfreeCgField* fields = NULL; + CfreeCgRecordDesc desc; if (t->rec.nfields) { - fields = arena_zarray(c->tu, CfreeCgField, t->rec.nfields); + fields = arena_zarray(c->tu, CfreeCgField, t->rec.nfields); for (u32 i = 0; i < t->rec.nfields; ++i) { fields[i].name = t->rec.fields[i].name; fields[i].type = type_cg_id_walk(c, t->rec.fields[i].type, t); fields[i].align_override = t->rec.fields[i].align_override; + if (t->rec.fields[i].packed && fields[i].align_override == 0) { + fields[i].align_override = 1; + } + if (t->rec.packed && fields[i].align_override == 0) { + fields[i].align_override = 1; + } } } - return cfree_cg_type_record(c, t->rec.tag, fields, t->rec.nfields); + memset(&desc, 0, sizeof desc); + desc.tag = t->rec.tag; + desc.fields = fields; + desc.nfields = t->rec.nfields; + desc.is_union = t->kind == TY_UNION; + desc.align_override = t->rec.align_override; + return cfree_cg_type_record_ex(c, &desc); } case TY_ENUM: return cfree_cg_type_enum(c, t->enm.tag, diff --git a/lang/c/type/type.h b/lang/c/type/type.h @@ -61,6 +61,8 @@ typedef enum TypeQual { Q_ATOMIC = 1u << 3, } TypeQual; +typedef struct Type Type; + typedef enum FieldFlag { FIELD_NONE = 0, FIELD_BITFIELD = 1u << 0, @@ -76,7 +78,7 @@ typedef struct Field { u16 flags; /* FieldFlag */ /* Phase 2 attribute carriers — populated by the parser when the member * carries __attribute__((aligned(N))) / ((packed)). Zero means "no - * override"; abi_record_layout interprets them. */ + * override"; c_abi_record_layout interprets them. */ u16 align_override; u8 packed; u8 pad; @@ -108,7 +110,7 @@ struct Type { u8 incomplete; /* Phase 2 attribute carriers — record-level * __attribute__((packed)) / ((aligned(N))). Both zero means - * "natural layout". abi_record_layout honors them. */ + * "natural layout". c_abi_record_layout honors them. */ u8 packed; u16 align_override; } rec; /* struct / union */ diff --git a/src/abi/abi.c b/src/abi/abi.c @@ -1,9 +1,8 @@ -/* TargetABI dispatch and shared C-standard layout. +/* TargetABI dispatch and shared codegen type layout. * - * The single authority for target-dependent C layout and calling - * convention decisions. Type stays structural and ABI-neutral; sizes, - * alignments, record layouts, and argument/return classification are - * derived here from Compiler.target. + * The single authority for target-dependent storage layout and calling + * convention decisions. Frontends lower source-language types to CgType + * before calling into this layer. * * Per-ABI bits (function classification, __va_list shape) live in * abi_aapcs64.c, abi_sysv_x64.c, ... abi_init switches on @@ -17,11 +16,9 @@ #include <string.h> #include "abi/abi_internal.h" -#include "api/cg_api.h" #include "api/cg_type.h" #include "core/arena.h" #include "core/core.h" -#include "core/pool.h" /* ---- scalar profile ---- * @@ -29,114 +26,6 @@ * aarch64 and x86_64). When a Windows-x64 (LLP64) or 32-bit ABI lands, * promote prim_info into the vtable. */ -static ABITypeInfo prim_info(TargetABI* a, TypeKind k) { - ABITypeInfo r = {0, 0, ABI_SC_INT, 0, 0, 0}; - switch (k) { - case TY_VOID: - r.size = 0; - r.align = 1; - r.scalar_kind = ABI_SC_VOID; - return r; - case TY_BOOL: - r.size = 1; - r.align = 1; - r.scalar_kind = ABI_SC_BOOL; - return r; - case TY_CHAR: - r.size = 1; - r.align = 1; - r.signed_ = 1; - return r; - case TY_SCHAR: - r.size = 1; - r.align = 1; - r.signed_ = 1; - return r; - case TY_UCHAR: - r.size = 1; - r.align = 1; - r.signed_ = 0; - return r; - case TY_SHORT: - r.size = 2; - r.align = 2; - r.signed_ = 1; - return r; - case TY_USHORT: - r.size = 2; - r.align = 2; - r.signed_ = 0; - return r; - case TY_INT: - r.size = 4; - r.align = 4; - r.signed_ = 1; - return r; - case TY_UINT: - r.size = 4; - r.align = 4; - r.signed_ = 0; - return r; - case TY_LONG: - r.size = (a->c->target.arch == CFREE_ARCH_ARM_64 || - a->c->target.arch == CFREE_ARCH_X86_64 || - a->c->target.arch == CFREE_ARCH_RV64) - ? 8 - : 4; - r.align = r.size; - r.signed_ = 1; - return r; - case TY_ULONG: - r.size = (a->c->target.arch == CFREE_ARCH_ARM_64 || - a->c->target.arch == CFREE_ARCH_X86_64 || - a->c->target.arch == CFREE_ARCH_RV64) - ? 8 - : 4; - r.align = r.size; - r.signed_ = 0; - return r; - case TY_LLONG: - r.size = 8; - r.align = 8; - r.signed_ = 1; - return r; - case TY_ULLONG: - r.size = 8; - r.align = 8; - r.signed_ = 0; - return r; - case TY_INT128: - r.size = 16; - r.align = 16; - r.signed_ = 1; - return r; - case TY_UINT128: - r.size = 16; - r.align = 16; - r.signed_ = 0; - return r; - case TY_FLOAT: - r.size = 4; - r.align = 4; - r.scalar_kind = ABI_SC_FLOAT; - return r; - case TY_DOUBLE: - r.size = 8; - r.align = 8; - r.scalar_kind = ABI_SC_FLOAT; - return r; - case TY_LDOUBLE: - r.size = 16; - r.align = 16; - r.scalar_kind = ABI_SC_FLOAT; - return r; - default: - return r; - } -} - -static ABITypeInfo abi_c_type_info_no_bridge(TargetABI* a, const Type* t); - ABITypeInfo abi_cg_type_info(TargetABI* a, CfreeCgTypeId id) { ABITypeInfo r = {0, 0, ABI_SC_VOID, 0, 0, 0}; const CgType* t; @@ -248,7 +137,7 @@ static ABIRecordLayout* compute_record_layout(TargetABI* a, CfreeCgTypeId id) { } u32 mask = max_align - 1; L->size = (off + mask) & ~mask; - } else { /* TY_UNION */ + } else { u32 mx = 0; for (u32 i = 0; i < t->record.nfields; ++i) { const CgTypeField* f = &t->record.fields[i]; @@ -308,254 +197,7 @@ const ABIFuncInfo* abi_cg_func_info(TargetABI* a, CfreeCgTypeId fn_type) { return info; } -static ABITypeInfo abi_c_type_info_no_bridge(TargetABI* a, const Type* t) { - ABITypeInfo r = {0, 0, ABI_SC_VOID, 0, 0, 0}; - if (!t) return r; - switch (t->kind) { - case TY_VOID: - case TY_BOOL: - case TY_CHAR: - case TY_SCHAR: - case TY_UCHAR: - case TY_SHORT: - case TY_USHORT: - case TY_INT: - case TY_UINT: - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_INT128: - case TY_UINT128: - case TY_FLOAT: - case TY_DOUBLE: - case TY_LDOUBLE: - return prim_info(a, (TypeKind)t->kind); - case TY_ENUM: - return abi_c_type_info_no_bridge( - a, t->enm.base ? t->enm.base : type_prim(a->c->global, TY_INT)); - default: - r = abi_cg_type_info(a, cg_api_type_import(a->c, t)); - switch (t->kind) { - case TY_CHAR: - case TY_SCHAR: - case TY_SHORT: - case TY_INT: - case TY_LONG: - case TY_LLONG: - case TY_INT128: - r.signed_ = 1; - break; - default: - r.signed_ = 0; - break; - } - return r; - } -} - -ABITypeInfo abi_type_info(TargetABI* a, const Type* t) { - return abi_c_type_info_no_bridge(a, t); -} - -u32 abi_sizeof(TargetABI* a, const Type* t) { return abi_type_info(a, t).size; } -u32 abi_alignof(TargetABI* a, const Type* t) { - return abi_type_info(a, t).align; -} - -const ABIRecordLayout* abi_record_layout(TargetABI* a, const Type* t) { - ABIRecordLayout* L; - ABIFieldLayout* fl = NULL; - u32 max_align = 1; - if (!t || (t->kind != TY_STRUCT && t->kind != TY_UNION)) return NULL; - L = arena_new(a->c->tu, ABIRecordLayout); - if (!L) return NULL; - memset(L, 0, sizeof *L); - if (t->rec.nfields) { - fl = arena_array(a->c->tu, ABIFieldLayout, t->rec.nfields); - memset(fl, 0, sizeof(ABIFieldLayout) * t->rec.nfields); - } - if (t->kind == TY_STRUCT) { - u32 off = 0; - for (u16 i = 0; i < t->rec.nfields; ++i) { - const Field* f = &t->rec.fields[i]; - ABITypeInfo fi = abi_type_info(a, f->type); - if (t->rec.packed) fi.align = 1; - if (f->align_override > fi.align) fi.align = f->align_override; - if (fi.align > max_align) max_align = fi.align; - u32 mask = fi.align ? fi.align - 1 : 0; - off = (off + mask) & ~mask; - fl[i].offset = off; - fl[i].storage_size = fi.size; - off += fi.size; - } - { - u32 mask = max_align - 1; - L->size = (off + mask) & ~mask; - } - } else { - u32 mx = 0; - for (u16 i = 0; i < t->rec.nfields; ++i) { - const Field* f = &t->rec.fields[i]; - ABITypeInfo fi = abi_type_info(a, f->type); - if (t->rec.packed) fi.align = 1; - if (f->align_override > fi.align) fi.align = f->align_override; - if (fi.align > max_align) max_align = fi.align; - if (fi.size > mx) mx = fi.size; - fl[i].offset = 0; - fl[i].storage_size = fi.size; - } - { - u32 mask = max_align - 1; - L->size = (mx + mask) & ~mask; - } - } - L->align = max_align; - if (t->rec.align_override > L->align) { - L->align = t->rec.align_override; - u32 mask = L->align - 1; - L->size = (L->size + mask) & ~mask; - } - L->nfields = t->rec.nfields; - L->fields = fl; - return L; -} - -static void classify_type_void(ABIArgInfo* out) { - memset(out, 0, sizeof *out); - out->kind = ABI_ARG_IGNORE; -} - -static void classify_type_scalar(TargetABI* a, const Type* t, - ABIArgInfo* out) { - ABITypeInfo ti = abi_type_info(a, t); - ABIArgPart* parts = arena_new(a->c->tu, ABIArgPart); - memset(out, 0, sizeof *out); - memset(parts, 0, sizeof *parts); - out->kind = ABI_ARG_DIRECT; - out->parts = parts; - out->nparts = 1; - parts->cls = (ti.scalar_kind == ABI_SC_FLOAT) ? ABI_CLASS_FP : ABI_CLASS_INT; - parts->loc = ABI_LOC_REG; - parts->size = ti.size; - parts->align = ti.align; -} - -static void classify_type_aggregate(TargetABI* a, const Type* t, - ABIArgInfo* out, int is_return) { - ABITypeInfo ti = abi_type_info(a, t); - memset(out, 0, sizeof *out); - if (ti.size == 0) { - classify_type_void(out); - return; - } - if (ti.size <= 16) { - u32 nparts = (ti.size + 7) / 8; - ABIArgPart* parts = arena_array(a->c->tu, ABIArgPart, nparts); - memset(parts, 0, sizeof(ABIArgPart) * nparts); - u32 off = 0; - for (u32 i = 0; i < nparts; ++i) { - u32 chunk = (ti.size - off > 8) ? 8 : (ti.size - off); - parts[i].cls = ABI_CLASS_INT; - parts[i].loc = ABI_LOC_REG; - parts[i].size = chunk; - parts[i].align = 8; - parts[i].src_offset = off; - off += chunk; - } - out->kind = ABI_ARG_DIRECT; - out->parts = parts; - out->nparts = (u16)nparts; - } else { - out->kind = ABI_ARG_INDIRECT; - out->flags = is_return ? ABI_AF_SRET : ABI_AF_BYVAL; - out->indirect_align = ti.align ? ti.align : 8; - } -} - -static void classify_type_one(TargetABI* a, const Type* t, ABIArgInfo* out, - int is_return) { - if (!t || t->kind == TY_VOID) { - classify_type_void(out); - return; - } - switch (t->kind) { - case TY_STRUCT: - case TY_UNION: - classify_type_aggregate(a, t, out, is_return); - return; - default: - classify_type_scalar(a, t, out); - return; - } -} - -static ABIFuncInfo* compute_type_func_info(TargetABI* a, const Type* fn_type) { - ABIFuncInfo* info = arena_new(a->c->tu, ABIFuncInfo); - memset(info, 0, sizeof *info); - classify_type_one(a, fn_type->fn.ret, &info->ret, 1); - info->has_sret = (info->ret.kind == ABI_ARG_INDIRECT) ? 1 : 0; - info->variadic = fn_type->fn.variadic; - info->nparams = fn_type->fn.nparams; - if (a->c->target.arch == CFREE_ARCH_ARM_64 && - a->c->target.os == CFREE_OS_MACOS) { - info->vararg_on_stack = 1; - } - if (fn_type->fn.nparams) { - ABIArgInfo* arr = arena_array(a->c->tu, ABIArgInfo, fn_type->fn.nparams); - memset(arr, 0, sizeof(ABIArgInfo) * fn_type->fn.nparams); - for (u16 i = 0; i < fn_type->fn.nparams; ++i) { - classify_type_one(a, fn_type->fn.params[i], &arr[i], 0); - } - info->params = arr; - } - return info; -} - -const ABIFuncInfo* abi_func_info(TargetABI* a, const Type* fn_type) { - CfreeCgTypeId id; - if (!fn_type || fn_type->kind != TY_FUNC) return NULL; - id = cg_api_type_import(a->c, fn_type); - for (FuncInfoCacheEntry* e = a->fn_cache; e; e = e->next) { - if (e->fn == id) return e->info; - } - ABIFuncInfo* info = compute_type_func_info(a, fn_type); - if (!info) return NULL; - FuncInfoCacheEntry* e = arena_new(a->c->tu, FuncInfoCacheEntry); - e->fn = id; - e->info = info; - e->next = a->fn_cache; - a->fn_cache = e; - return info; -} - -/* ---- target-defined library types ---- */ - -static const Type* size_or_uintptr(TargetABI* a, Pool* p) { - return a->c->target.ptr_size == 8 ? type_prim(p, TY_ULLONG) - : type_prim(p, TY_UINT); -} - -const Type* abi_size_type(TargetABI* a, Pool* p) { - return size_or_uintptr(a, p); -} -const Type* abi_ptrdiff_type(TargetABI* a, Pool* p) { - return a->c->target.ptr_size == 8 ? type_prim(p, TY_LLONG) - : type_prim(p, TY_INT); -} -const Type* abi_intptr_type(TargetABI* a, Pool* p) { - return a->c->target.ptr_size == 8 ? type_prim(p, TY_LLONG) - : type_prim(p, TY_INT); -} -const Type* abi_uintptr_type(TargetABI* a, Pool* p) { - return size_or_uintptr(a, p); -} - -const Type* abi_va_list_type(TargetABI* a, Pool* p) { - if (a->va_list_cache) return a->va_list_cache; - a->va_list_cache = a->vt->va_list_type(a, p); - return a->va_list_cache; -} +ABITypeInfo abi_va_list_info(TargetABI* a) { return a->vt->va_list_info; } /* ---- lifecycle ---- */ @@ -596,7 +238,6 @@ void abi_fini(TargetABI* a) { if (!a) return; a->fn_cache = NULL; a->rec_cache = NULL; - a->va_list_cache = NULL; a->vt = NULL; a->c = NULL; } @@ -616,3 +257,5 @@ void abi_free(TargetABI* a) { abi_fini(a); h->free(h, a, sizeof(TargetABI)); } + +Compiler* abi_compiler(TargetABI* a) { return a ? a->c : NULL; } diff --git a/src/abi/abi.h b/src/abi/abi.h @@ -4,12 +4,10 @@ #include <cfree/cg.h> #include "core/core.h" -#include "type/type.h" -/* TargetABI is the single authority for target-dependent C layout and calling - * convention decisions. Type remains structural and ABI-neutral; all sizes, - * alignments, field offsets, bitfield packing, scalar widths, and - * argument/return classifications are derived here from Compiler.target. */ +/* TargetABI is the single authority for target-dependent storage layout and + * calling convention decisions. Frontends lower source-language types to + * CfreeCgTypeId before entering this generic ABI layer. */ typedef struct TargetABI TargetABI; typedef enum ABIScalarKind { @@ -116,32 +114,13 @@ void abi_fini(TargetABI*); * The returned pointer is valid until abi_free returns. */ TargetABI* abi_new(Compiler*); void abi_free(TargetABI*); +Compiler* abi_compiler(TargetABI*); -/* Builtin scalar profiles and general type layout. New code should enter - * through CfreeCgTypeId; Type* overloads are the temporary C frontend bridge. */ ABITypeInfo abi_cg_type_info(TargetABI*, CfreeCgTypeId); u32 abi_cg_sizeof(TargetABI*, CfreeCgTypeId); u32 abi_cg_alignof(TargetABI*, CfreeCgTypeId); const ABIRecordLayout* abi_cg_record_layout(TargetABI*, CfreeCgTypeId); const ABIFuncInfo* abi_cg_func_info(TargetABI*, CfreeCgTypeId fn_type); - -ABITypeInfo abi_type_info(TargetABI*, const Type*); -u32 abi_sizeof(TargetABI*, const Type*); -u32 abi_alignof(TargetABI*, const Type*); - -/* Record layout is cached by Type* identity inside TargetABI and is stable for - * the lifetime of the ABI object. Incomplete records are fatal diagnostics. */ -const ABIRecordLayout* abi_record_layout(TargetABI*, const Type*); - -/* Calling convention classification. The returned object is owned by the ABI - * cache and remains valid until abi_fini. */ -const ABIFuncInfo* abi_func_info(TargetABI*, const Type* fn_type); - -/* Target-defined library types used by headers and builtins. */ -const Type* abi_size_type(TargetABI*, Pool*); -const Type* abi_ptrdiff_type(TargetABI*, Pool*); -const Type* abi_intptr_type(TargetABI*, Pool*); -const Type* abi_uintptr_type(TargetABI*, Pool*); -const Type* abi_va_list_type(TargetABI*, Pool*); +ABITypeInfo abi_va_list_info(TargetABI*); #endif diff --git a/src/abi/abi_aapcs64.c b/src/abi/abi_aapcs64.c @@ -17,7 +17,6 @@ #include "api/cg_type.h" #include "core/arena.h" #include "core/core.h" -#include "core/pool.h" static void classify_scalar(TargetABI* a, CfreeCgTypeId t, ABIArgInfo* out) { ABITypeInfo ti = abi_internal_type_info(a, t); @@ -125,30 +124,7 @@ ABIFuncInfo* aapcs64_compute_func_info(TargetABI* a, CfreeCgTypeId fn) { return info; } -static const Type* aapcs64_va_list_type(TargetABI* a, Pool* p) { - /* AAPCS64 __va_list: 3 pointers (__stack, __gr_top, __vr_top) followed - * by 2 ints (__gr_offs, __vr_offs). Total 32 bytes, 8-aligned. */ - (void)a; - const Type* vp = type_ptr(p, type_void(p)); - const Type* it = type_prim(p, TY_INT); - Sym name = pool_intern_cstr(p, "__va_list"); - SrcLoc nl = {0, 0, 0}; - TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); - TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__stack"), .type = vp}); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__gr_top"), .type = vp}); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__vr_top"), .type = vp}); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__gr_offs"), .type = it}); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "__vr_offs"), .type = it}); - return type_record_end(p, b); -} - const ABIVtable aapcs64_vtable = { .compute_func_info = aapcs64_compute_func_info, - .va_list_type = aapcs64_va_list_type, + .va_list_info = {32, 8, ABI_SC_VOID, 0, 0, 0}, }; diff --git a/src/abi/abi_apple_arm64.c b/src/abi/abi_apple_arm64.c @@ -26,8 +26,6 @@ #include "abi/abi_internal.h" #include "core/core.h" -#include "core/pool.h" -#include "type/type.h" extern ABIFuncInfo* aapcs64_compute_func_info(TargetABI*, CfreeCgTypeId); @@ -44,16 +42,7 @@ static ABIFuncInfo* apple_arm64_compute_func_info(TargetABI* a, return info; } -static const Type* apple_arm64_va_list_type(TargetABI* a, Pool* p) { - /* Apple ARM64: __builtin_va_list is `char*`, full stop. No struct, - * no five fields — variadics are stack-passed so the implementation - * just walks a byte cursor. (AAPCS64 needs the five-field struct - * because variadics may originate in v0-v7 / x0-x7.) */ - (void)a; - return type_ptr(p, type_prim(p, TY_CHAR)); -} - const ABIVtable apple_arm64_vtable = { .compute_func_info = apple_arm64_compute_func_info, - .va_list_type = apple_arm64_va_list_type, + .va_list_info = {8, 8, ABI_SC_PTR, 0, 0, 0}, }; diff --git a/src/abi/abi_internal.h b/src/abi/abi_internal.h @@ -13,8 +13,7 @@ typedef struct ABIVtable { /* Compute the ABIFuncInfo for a function type. The cache wrapper in * abi.c calls this once per CgTypeId and memoizes the result. */ ABIFuncInfo* (*compute_func_info)(TargetABI*, CfreeCgTypeId fn); - /* Build the per-ABI __va_list type. The wrapper in abi.c memoizes. */ - const Type* (*va_list_type)(TargetABI*, Pool*); + ABITypeInfo va_list_info; } ABIVtable; /* Per-ABI vtables exposed by their TUs. */ @@ -49,7 +48,6 @@ struct TargetABI { const ABIVtable* vt; FuncInfoCacheEntry* fn_cache; RecordLayoutCacheEntry* rec_cache; - const Type* va_list_cache; }; /* Shared helpers exposed to per-ABI TUs. */ diff --git a/src/abi/abi_rv64.c b/src/abi/abi_rv64.c @@ -17,7 +17,6 @@ #include "api/cg_type.h" #include "core/arena.h" #include "core/core.h" -#include "core/pool.h" static void classify_scalar(TargetABI* a, CfreeCgTypeId t, ABIArgInfo* out) { ABITypeInfo ti = abi_internal_type_info(a, t); @@ -120,14 +119,7 @@ static ABIFuncInfo* rv64_compute_func_info(TargetABI* a, CfreeCgTypeId fn) { return info; } -static const Type* rv64_va_list_type(TargetABI* a, Pool* p) { - /* RISC-V LP64: va_list is `void *` (one pointer to the next argument - * in memory). */ - (void)a; - return type_ptr(p, type_void(p)); -} - const ABIVtable rv64_vtable = { .compute_func_info = rv64_compute_func_info, - .va_list_type = rv64_va_list_type, + .va_list_info = {8, 8, ABI_SC_PTR, 0, 0, 0}, }; diff --git a/src/abi/abi_sysv_x64.c b/src/abi/abi_sysv_x64.c @@ -19,7 +19,6 @@ #include "api/cg_type.h" #include "core/arena.h" #include "core/core.h" -#include "core/pool.h" static void classify_void(ABIArgInfo* out) { memset(out, 0, sizeof *out); @@ -123,31 +122,7 @@ static ABIFuncInfo* sysv_x64_compute_func_info(TargetABI* a, return info; } -static const Type* sysv_x64_va_list_type(TargetABI* a, Pool* p) { - /* SysV AMD64 __va_list_tag: { unsigned gp_offset; unsigned fp_offset; - * void* overflow_arg_area; void* reg_save_area; }. 24 bytes, 8-aligned. - * The va_list type is an array of one __va_list_tag element so taking - * its address yields a pointer, matching the macro semantics. */ - (void)a; - const Type* vp = type_ptr(p, type_void(p)); - const Type* uit = type_prim(p, TY_UINT); - Sym name = pool_intern_cstr(p, "__va_list_tag"); - SrcLoc nl = {0, 0, 0}; - TagId tg = type_tag_new(p, TAG_STRUCT, name, nl); - TypeRecordBuilder* b = type_record_begin(p, TY_STRUCT, tg, name); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "gp_offset"), .type = uit}); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "fp_offset"), .type = uit}); - type_record_field( - b, - (Field){.name = pool_intern_cstr(p, "overflow_arg_area"), .type = vp}); - type_record_field( - b, (Field){.name = pool_intern_cstr(p, "reg_save_area"), .type = vp}); - return type_record_end(p, b); -} - const ABIVtable sysv_x64_vtable = { .compute_func_info = sysv_x64_compute_func_info, - .va_list_type = sysv_x64_va_list_type, + .va_list_info = {24, 8, ABI_SC_VOID, 0, 0, 0}, }; diff --git a/src/api/cg.c b/src/api/cg.c @@ -10,9 +10,9 @@ #include "arch/arch.h" #include "core/arena.h" #include "core/heap.h" +#include "core/pool.h" #include "core/segvec.h" #include "obj/obj.h" -#include "type/type.h" typedef enum CgApiTypeKind { CG_API_TYPE_PTR, @@ -25,7 +25,6 @@ typedef enum CgApiTypeKind { typedef struct CgApiType { CgType cg; - const Type* type; CfreeCgTypeId base; CfreeSym name; u32 count; @@ -89,68 +88,6 @@ static u64 cg_align_to(u64 n, u32 align) { return ((n + a - 1u) / a) * a; } -static const Type* builtin_type(Compiler* c, CfreeCgBuiltinType t) { - switch (t) { - case CFREE_CG_BUILTIN_VOID: - return type_void(c->global); - case CFREE_CG_BUILTIN_BOOL: - return type_prim(c->global, TY_BOOL); - case CFREE_CG_BUILTIN_I8: - return type_prim(c->global, TY_SCHAR); - case CFREE_CG_BUILTIN_I16: - return type_prim(c->global, TY_SHORT); - case CFREE_CG_BUILTIN_I32: - return type_prim(c->global, TY_INT); - case CFREE_CG_BUILTIN_I64: - return type_prim(c->global, TY_LLONG); - case CFREE_CG_BUILTIN_I128: - return type_prim(c->global, TY_INT128); - case CFREE_CG_BUILTIN_F32: - return type_prim(c->global, TY_FLOAT); - case CFREE_CG_BUILTIN_F64: - return type_prim(c->global, TY_DOUBLE); - case CFREE_CG_BUILTIN_VARARG_STATE: - return abi_va_list_type(c->abi, c->global); - case CFREE_CG_BUILTIN_COUNT: - return NULL; - } - return NULL; -} - -static CfreeCgTypeId builtin_id_from_type_kind(TypeKind kind) { - switch (kind) { - case TY_VOID: - return builtin_id(CFREE_CG_BUILTIN_VOID); - case TY_BOOL: - return builtin_id(CFREE_CG_BUILTIN_BOOL); - case TY_CHAR: - case TY_SCHAR: - case TY_UCHAR: - return builtin_id(CFREE_CG_BUILTIN_I8); - case TY_SHORT: - case TY_USHORT: - return builtin_id(CFREE_CG_BUILTIN_I16); - case TY_INT: - case TY_UINT: - return builtin_id(CFREE_CG_BUILTIN_I32); - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - return builtin_id(CFREE_CG_BUILTIN_I64); - case TY_INT128: - case TY_UINT128: - return builtin_id(CFREE_CG_BUILTIN_I128); - case TY_FLOAT: - return builtin_id(CFREE_CG_BUILTIN_F32); - case TY_DOUBLE: - case TY_LDOUBLE: - return builtin_id(CFREE_CG_BUILTIN_F64); - default: - return CFREE_CG_TYPE_NONE; - } -} - static void builtin_cg_type_init(Compiler* c, CgType* out, CfreeCgBuiltinType t) { memset(out, 0, sizeof(*out)); @@ -208,10 +145,10 @@ static void builtin_cg_type_init(Compiler* c, CgType* out, out->fp.width = 64; break; case CFREE_CG_BUILTIN_VARARG_STATE: { - const Type* ty = builtin_type(c, t); + ABITypeInfo info = abi_va_list_info(c->abi); out->kind = CFREE_CG_TYPE_VARARG_STATE; - out->size = ty ? abi_sizeof(c->abi, ty) : 0; - out->align = ty ? abi_alignof(c->abi, ty) : 1; + out->size = info.size; + out->align = info.align ? info.align : 1; break; } case CFREE_CG_BUILTIN_COUNT: @@ -309,6 +246,40 @@ int cg_type_is_record(Compiler* c, CfreeCgTypeId id) { return ty && ty->kind == CFREE_CG_TYPE_RECORD; } +static int cg_type_is_void(Compiler* c, CfreeCgTypeId id) { + const CgType* ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_is_void(c, ty->alias.base); + return ty && ty->kind == CFREE_CG_TYPE_VOID; +} + +static int cg_type_is_aggregate(Compiler* c, CfreeCgTypeId id) { + return cg_type_is_record(c, id); +} + +static CfreeCgTypeId cg_type_ptr_to(Compiler* c, CfreeCgTypeId pointee) { + return cfree_cg_type_ptr(c, pointee, 0); +} + +static CfreeCgTypeId cg_type_pointee(Compiler* c, CfreeCgTypeId id) { + const CgType* ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_pointee(c, ty->alias.base); + return ty && ty->kind == CFREE_CG_TYPE_PTR ? ty->ptr.pointee : CFREE_CG_TYPE_NONE; +} + +static CfreeCgTypeId cg_type_func_ret_id(Compiler* c, CfreeCgTypeId id) { + const CgType* ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_func_ret_id(c, ty->alias.base); + return ty && ty->kind == CFREE_CG_TYPE_FUNC ? ty->func.ret : CFREE_CG_TYPE_NONE; +} + +static CfreeCgTypeId cg_type_func_param_id(Compiler* c, CfreeCgTypeId id, + u32 index) { + const CgType* ty = cg_type_get(c, id); + if (ty && ty->kind == CFREE_CG_TYPE_ALIAS) return cg_type_func_param_id(c, ty->alias.base, index); + if (!ty || ty->kind != CFREE_CG_TYPE_FUNC || index >= ty->func.nparams) return CFREE_CG_TYPE_NONE; + return ty->func.params[index].type; +} + static CgApiType* type_alloc(Compiler* c, CfreeCgTypeId* id_out) { CgApiState* s = cg_api_get(c); CgApiType* e; @@ -385,26 +356,6 @@ static CfreeCgTypeId find_func_type_id(Compiler* c, CfreeCgFuncSig sig) { return CFREE_CG_TYPE_NONE; } -static const Type* resolve_type(Compiler* c, CfreeCgTypeId id) { - u32 seg; - u32 off; - u32 index; - CgApiState* s; - CgApiType* e; - if (!c || id == CFREE_CG_TYPE_NONE) return NULL; - seg = id >> CG_API_TYPE_SEG_SHIFT; - off = id & CG_API_TYPE_SEG_MASK; - if (seg == CG_API_TYPE_BUILTIN_SEG) { - if (off >= CFREE_CG_BUILTIN_COUNT) return NULL; - return builtin_type(c, (CfreeCgBuiltinType)off); - } - if (!decode_user_id(id, &index)) return NULL; - s = (CgApiState*)c->cg_api; - if (!s) return NULL; - e = CgApiTypes_at(&s->types, index); - return e ? e->type : NULL; -} - static CgApiType* api_type_from_id(Compiler* c, CfreeCgTypeId id) { u32 index; CgApiState* s; @@ -418,6 +369,10 @@ static CgApiType* api_type_from_id(Compiler* c, CfreeCgTypeId id) { return e; } +static CfreeCgTypeId resolve_type(Compiler* c, CfreeCgTypeId id) { + return cg_type_get(c, id) ? id : CFREE_CG_TYPE_NONE; +} + static CfreeCgParam* copy_cg_params(Compiler* c, const CfreeCgParam* src, u32 n) { CfreeCgParam* dst; @@ -602,19 +557,17 @@ CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler* c) { CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee, uint32_t address_space) { - const Type* pty = resolve_type(c, pointee); CfreeCgTypeId id; CgApiType* e; - if (!pty) return CFREE_CG_TYPE_NONE; + if (!cg_type_get(c, pointee)) return CFREE_CG_TYPE_NONE; id = find_ptr_type_id(c, pointee, address_space); if (id != CFREE_CG_TYPE_NONE) return id; e = type_alloc(c, &id); if (!e) return CFREE_CG_TYPE_NONE; - e->type = type_ptr(c->global, pty); e->base = pointee; e->address_space = address_space; e->kind = CG_API_TYPE_PTR; - if (!e->type || !cg_type_set_ptr(c, e, pointee, address_space)) { + if (!cg_type_set_ptr(c, e, pointee, address_space)) { return CFREE_CG_TYPE_NONE; } return id; @@ -622,19 +575,17 @@ CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee, CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem, uint64_t count) { - const Type* ety = resolve_type(c, elem); CfreeCgTypeId id; CgApiType* e; - if (!ety || count > UINT32_MAX) return CFREE_CG_TYPE_NONE; + if (!cg_type_get(c, elem) || count > UINT32_MAX) return CFREE_CG_TYPE_NONE; id = find_array_type_id(c, elem, count); if (id != CFREE_CG_TYPE_NONE) return id; e = type_alloc(c, &id); if (!e) return CFREE_CG_TYPE_NONE; - e->type = type_array(c->global, ety, (u32)count, 0); e->base = elem; e->array_count = count; e->kind = CG_API_TYPE_ARRAY; - if (!e->type || !cg_type_set_array(c, e, elem, count)) { + if (!cg_type_set_array(c, e, elem, count)) { return CFREE_CG_TYPE_NONE; } return id; @@ -642,13 +593,11 @@ CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem, CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name, CfreeCgTypeId base) { - const Type* bty = resolve_type(c, base); CfreeCgTypeId id; CgApiType* e; - if (!bty) return CFREE_CG_TYPE_NONE; + if (!cg_type_get(c, base)) return CFREE_CG_TYPE_NONE; e = type_alloc(c, &id); if (!e) return CFREE_CG_TYPE_NONE; - e->type = bty; e->base = base; e->name = name; e->kind = CG_API_TYPE_ALIAS; @@ -658,46 +607,41 @@ CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name, CfreeCgTypeId cfree_cg_type_record(CfreeCompiler* c, CfreeSym tag, const CfreeCgField* fields, uint32_t nfields) { + CfreeCgRecordDesc desc; + memset(&desc, 0, sizeof desc); + desc.tag = tag; + desc.fields = fields; + desc.nfields = nfields; + return cfree_cg_type_record_ex(c, &desc); +} + +CfreeCgTypeId cfree_cg_type_record_ex(CfreeCompiler* c, + const CfreeCgRecordDesc* desc) { CfreeCgTypeId id; CgApiType* e; - TypeRecordBuilder* b; CfreeCgField* copied = NULL; - TagId tag_id; - if (!c || (nfields && !fields) || nfields > UINT16_MAX) { + if (!c || !desc || (desc->nfields && !desc->fields) || + desc->nfields > UINT16_MAX) { return CFREE_CG_TYPE_NONE; } - if (nfields) { - copied = arena_array(&c->global->arena, CfreeCgField, nfields); + if (desc->nfields) { + copied = arena_array(&c->global->arena, CfreeCgField, desc->nfields); if (!copied) return CFREE_CG_TYPE_NONE; } - tag_id = type_tag_new(c->global, TAG_STRUCT, tag, (SrcLoc){0, 0, 0}); - b = type_record_begin(c->global, TY_STRUCT, tag_id, tag); - if (!tag_id || !b) return CFREE_CG_TYPE_NONE; - for (u32 i = 0; i < nfields; ++i) { - const Type* fty = resolve_type(c, fields[i].type); - Field f; - if (!fty) return CFREE_CG_TYPE_NONE; - copied[i] = fields[i]; - memset(&f, 0, sizeof(f)); - f.name = fields[i].name; - f.type = fty; - if (fields[i].align_override == 1u) { - f.packed = 1; - } else if (fields[i].align_override > 1u) { - if (fields[i].align_override > UINT16_MAX) return CFREE_CG_TYPE_NONE; - f.align_override = (u16)fields[i].align_override; - } - type_record_field(b, f); + for (u32 i = 0; i < desc->nfields; ++i) { + if (!cg_type_get(c, desc->fields[i].type)) return CFREE_CG_TYPE_NONE; + copied[i] = desc->fields[i]; } e = type_alloc(c, &id); if (!e) return CFREE_CG_TYPE_NONE; - e->type = type_record_end(c->global, b); - e->name = tag; - e->count = nfields; + e->name = desc->tag; + e->count = desc->nfields; e->fields = copied; e->kind = CG_API_TYPE_RECORD; - if (!e->type || !cg_type_set_record(c, e, tag, fields, nfields, 0, 0, 0)) { + if (!cg_type_set_record(c, e, desc->tag, desc->fields, desc->nfields, + desc->is_union, desc->align_override, + 0)) { return CFREE_CG_TYPE_NONE; } return id; @@ -707,74 +651,49 @@ CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler* c, CfreeSym tag, CfreeCgTypeId base, const CfreeCgEnumValue* values, uint32_t nvalues) { - const Type* bty; CfreeCgEnumValue* copied = NULL; CfreeCgTypeId id; CgApiType* e; - TagId tag_id; if (!c || (nvalues && !values)) return CFREE_CG_TYPE_NONE; - bty = base == CFREE_CG_TYPE_NONE ? type_prim(c->global, TY_INT) - : resolve_type(c, base); - if (!bty || !type_is_int(bty)) return CFREE_CG_TYPE_NONE; + if (base == CFREE_CG_TYPE_NONE) base = builtin_id(CFREE_CG_BUILTIN_I32); + if (!cg_type_is_int(c, base)) return CFREE_CG_TYPE_NONE; if (nvalues) { copied = arena_array(&c->global->arena, CfreeCgEnumValue, nvalues); if (!copied) return CFREE_CG_TYPE_NONE; memcpy(copied, values, sizeof(*copied) * nvalues); } - tag_id = type_tag_new(c->global, TAG_ENUM, tag, (SrcLoc){0, 0, 0}); - if (!tag_id) return CFREE_CG_TYPE_NONE; e = type_alloc(c, &id); if (!e) return CFREE_CG_TYPE_NONE; - e->type = type_enum(c->global, tag_id, tag, bty); e->base = base; e->name = tag; e->count = nvalues; e->values = copied; e->kind = CG_API_TYPE_ENUM; - if (!e->type || !cg_type_set_enum(c, e, tag, base, copied, nvalues)) { + if (!cg_type_set_enum(c, e, tag, base, copied, nvalues)) { return CFREE_CG_TYPE_NONE; } return id; } CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgFuncSig sig) { - Heap* h; - const Type* rty = resolve_type(c, sig.ret); - const Type** ptypes = NULL; CfreeCgParam* copied = NULL; CfreeCgTypeId id; CgApiType* e; - if (!c || !rty || (sig.nparams && !sig.params) || sig.nparams > UINT16_MAX) { + if (!c || !cg_type_get(c, sig.ret) || (sig.nparams && !sig.params) || + sig.nparams > UINT16_MAX) { return CFREE_CG_TYPE_NONE; } id = find_func_type_id(c, sig); if (id != CFREE_CG_TYPE_NONE) return id; - h = (Heap*)c->env->heap; if (sig.nparams) { - ptypes = (const Type**)h->alloc(h, sizeof(*ptypes) * sig.nparams, - _Alignof(const Type*)); - if (!ptypes) return CFREE_CG_TYPE_NONE; copied = copy_cg_params(c, sig.params, sig.nparams); - if (!copied) { - h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); - return CFREE_CG_TYPE_NONE; - } + if (!copied) return CFREE_CG_TYPE_NONE; for (u32 i = 0; i < sig.nparams; ++i) { - ptypes[i] = resolve_type(c, sig.params[i].type); - if (!ptypes[i]) { - h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); - return CFREE_CG_TYPE_NONE; - } + if (!cg_type_get(c, sig.params[i].type)) return CFREE_CG_TYPE_NONE; } } e = type_alloc(c, &id); - if (!e) { - if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); - return CFREE_CG_TYPE_NONE; - } - e->type = - type_func(c->global, rty, ptypes, (u16)sig.nparams, sig.abi_variadic); - if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); + if (!e) return CFREE_CG_TYPE_NONE; e->base = sig.ret; e->count = sig.nparams; e->params = copied; @@ -782,150 +701,12 @@ CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgFuncSig sig) { e->call_conv = sig.call_conv; e->abi_variadic = sig.abi_variadic != 0; e->kind = CG_API_TYPE_FUNC; - if (!e->type || !cg_type_set_func(c, e, sig, copied)) { + if (!cg_type_set_func(c, e, sig, copied)) { return CFREE_CG_TYPE_NONE; } return id; } -CfreeCgTypeId cg_api_type_import(Compiler* c, const Type* ty) { - CgApiState* s; - CfreeCgTypeId id; - CgApiType* e; - if (!c || !ty) return CFREE_CG_TYPE_NONE; - if (!ty->qual) { - switch (ty->kind) { - case TY_VOID: - return builtin_id(CFREE_CG_BUILTIN_VOID); - case TY_BOOL: - return builtin_id(CFREE_CG_BUILTIN_BOOL); - case TY_CHAR: - case TY_SCHAR: - case TY_UCHAR: - return builtin_id(CFREE_CG_BUILTIN_I8); - case TY_SHORT: - case TY_USHORT: - return builtin_id(CFREE_CG_BUILTIN_I16); - case TY_INT: - case TY_UINT: - return builtin_id(CFREE_CG_BUILTIN_I32); - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - return builtin_id(CFREE_CG_BUILTIN_I64); - case TY_INT128: - case TY_UINT128: - return builtin_id(CFREE_CG_BUILTIN_I128); - case TY_FLOAT: - return builtin_id(CFREE_CG_BUILTIN_F32); - case TY_DOUBLE: - return builtin_id(CFREE_CG_BUILTIN_F64); - default: - break; - } - } - - s = cg_api_get(c); - if (!s) return CFREE_CG_TYPE_NONE; - for (u32 i = 0, n = CgApiTypes_count(&s->types); i < n; ++i) { - e = CgApiTypes_at(&s->types, i); - if (e && e->type == ty) return type_id_for_user_index(i); - } - - e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; - e->type = ty; - switch (ty->kind) { - case TY_PTR: - e->base = cg_api_type_import(c, ty->ptr.pointee); - e->kind = CG_API_TYPE_PTR; - if (!cg_type_set_ptr(c, e, e->base, 0)) return CFREE_CG_TYPE_NONE; - break; - case TY_ARRAY: - e->base = cg_api_type_import(c, ty->arr.elem); - e->array_count = ty->arr.count; - e->kind = CG_API_TYPE_ARRAY; - if (!cg_type_set_array(c, e, e->base, e->array_count)) { - return CFREE_CG_TYPE_NONE; - } - break; - case TY_FUNC: { - CfreeCgParam* params = NULL; - CfreeCgFuncSig sig; - e->base = cg_api_type_import(c, ty->fn.ret); - e->count = ty->fn.nparams; - e->abi_variadic = ty->fn.variadic; - e->call_conv = CFREE_CG_CC_TARGET_C; - e->kind = CG_API_TYPE_FUNC; - memset(&sig, 0, sizeof(sig)); - sig.ret = e->base; - sig.nparams = ty->fn.nparams; - sig.abi_variadic = ty->fn.variadic; - sig.call_conv = CFREE_CG_CC_TARGET_C; - if (ty->fn.nparams) { - params = arena_zarray(&c->global->arena, CfreeCgParam, ty->fn.nparams); - if (!params) return CFREE_CG_TYPE_NONE; - for (u32 i = 0; i < ty->fn.nparams; ++i) { - params[i].type = cg_api_type_import(c, ty->fn.params[i]); - if (params[i].type == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; - } - } - sig.params = params; - e->params = params; - if (!cg_type_set_func(c, e, sig, params)) return CFREE_CG_TYPE_NONE; - break; - } - case TY_STRUCT: - case TY_UNION: { - CfreeCgField* fields = NULL; - e->name = ty->rec.tag; - e->count = ty->rec.nfields; - e->kind = CG_API_TYPE_RECORD; - e->cg.kind = CFREE_CG_TYPE_RECORD; - if (ty->rec.nfields) { - fields = arena_zarray(&c->global->arena, CfreeCgField, ty->rec.nfields); - if (!fields) return CFREE_CG_TYPE_NONE; - for (u32 i = 0; i < ty->rec.nfields; ++i) { - const Field* f = &ty->rec.fields[i]; - fields[i].name = f->name; - fields[i].type = cg_api_type_import(c, f->type); - if (fields[i].type == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; - fields[i].align_override = - (ty->rec.packed || f->packed) ? 1u : f->align_override; - } - } - e->fields = fields; - if (!cg_type_set_record(c, e, ty->rec.tag, fields, ty->rec.nfields, - ty->kind == TY_UNION, ty->rec.align_override, - 0)) { - return CFREE_CG_TYPE_NONE; - } - break; - } - case TY_ENUM: - e->name = ty->enm.tag; - e->base = cg_api_type_import(c, ty->enm.base); - e->kind = CG_API_TYPE_ENUM; - if (!cg_type_set_enum(c, e, ty->enm.tag, e->base, NULL, 0)) { - return CFREE_CG_TYPE_NONE; - } - break; - default: - { - CfreeCgTypeId base_id = builtin_id_from_type_kind((TypeKind)ty->kind); - e->kind = CG_API_TYPE_ALIAS; - if (!cg_type_set_alias(c, e, 0, base_id)) return CFREE_CG_TYPE_NONE; - break; - } - } - return id; -} - -const Type* cg_api_type_resolve(Compiler* c, CfreeCgTypeId id) { - return resolve_type(c, id); -} - uint64_t cfree_cg_type_size(CfreeCompiler* c, CfreeCgTypeId id) { return cg_type_size(c, id); } @@ -1135,7 +916,7 @@ typedef enum SResidency { typedef struct ApiSValue { Operand op; - const Type* type; + CfreeCgTypeId type; u8 res; u8 pinned; u8 lvalue; @@ -1149,7 +930,7 @@ typedef struct ApiCgScope { Label break_lbl; Label continue_lbl; CGScope target_scope; - const Type* result_type; + CfreeCgTypeId result_type; FrameSlot result_slot; u32 generation; u8 active; @@ -1168,7 +949,7 @@ struct CfreeCg { u32 sp; u32 cap; - const Type** slot_types; + CfreeCgTypeId* slot_types; u32 slot_types_cap; struct { @@ -1180,14 +961,14 @@ struct CfreeCg { CGABIValue* avs_in_flight; u32 avs_in_flight_n; - const Type* fn_ret_type; + CfreeCgTypeId fn_ret_type; const ABIFuncInfo* fn_abi; SrcLoc cur_loc; CGFuncDesc fn_desc; CGParamDesc fn_params[64]; - const Type** sym_types; + CfreeCgTypeId* sym_types; CfreeCgDecl* sym_attrs; u32 sym_cap; @@ -1205,15 +986,15 @@ struct CfreeCg { /* ---- value stack helpers ---- */ -static u8 api_type_class(const Type* ty) { - if (ty && (ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE || - ty->kind == TY_LDOUBLE)) { +static u8 api_type_class(CfreeCgTypeId ty) { + if (ty == builtin_id(CFREE_CG_BUILTIN_F32) || + ty == builtin_id(CFREE_CG_BUILTIN_F64)) { return RC_FP; } return RC_INT; } -static Operand api_op_imm(i64 v, const Type* ty) { +static Operand api_op_imm(i64 v, CfreeCgTypeId ty) { Operand o; memset(&o, 0, sizeof o); o.kind = OPK_IMM; @@ -1223,7 +1004,7 @@ static Operand api_op_imm(i64 v, const Type* ty) { return o; } -static Operand api_op_reg(Reg r, const Type* ty) { +static Operand api_op_reg(Reg r, CfreeCgTypeId ty) { Operand o; memset(&o, 0, sizeof o); o.kind = OPK_REG; @@ -1233,7 +1014,7 @@ static Operand api_op_reg(Reg r, const Type* ty) { return o; } -static Operand api_op_local(FrameSlot s, const Type* ty) { +static Operand api_op_local(FrameSlot s, CfreeCgTypeId ty) { Operand o; memset(&o, 0, sizeof o); o.kind = OPK_LOCAL; @@ -1243,7 +1024,7 @@ static Operand api_op_local(FrameSlot s, const Type* ty) { return o; } -static Operand api_op_global(ObjSymId sym, i64 addend, const Type* ty) { +static Operand api_op_global(ObjSymId sym, i64 addend, CfreeCgTypeId ty) { Operand o; memset(&o, 0, sizeof o); o.kind = OPK_GLOBAL; @@ -1254,7 +1035,7 @@ static Operand api_op_global(ObjSymId sym, i64 addend, const Type* ty) { return o; } -static Operand api_op_indirect(Reg base, i32 ofs, const Type* ty) { +static Operand api_op_indirect(Reg base, i32 ofs, CfreeCgTypeId ty) { Operand o; memset(&o, 0, sizeof o); o.kind = OPK_INDIRECT; @@ -1270,7 +1051,7 @@ static u8 api_residency_for(const Operand* o) { return RES_INHERENT; } -static ApiSValue api_make_sv(Operand op, const Type* ty) { +static ApiSValue api_make_sv(Operand op, CfreeCgTypeId ty) { ApiSValue sv; memset(&sv, 0, sizeof sv); sv.op = op; @@ -1280,13 +1061,13 @@ static ApiSValue api_make_sv(Operand op, const Type* ty) { return sv; } -static ApiSValue api_make_lv(Operand op, const Type* ty) { +static ApiSValue api_make_lv(Operand op, CfreeCgTypeId ty) { ApiSValue sv = api_make_sv(op, ty); sv.lvalue = 1; return sv; } -static const Type* api_sv_type(const ApiSValue* sv) { +static CfreeCgTypeId api_sv_type(const ApiSValue* sv) { return sv->type ? sv->type : sv->op.type; } @@ -1326,9 +1107,9 @@ static ApiSValue api_pop(CfreeCg* g) { return g->stack[--g->sp]; } -static void api_remember_slot_type(CfreeCg* g, FrameSlot slot, const Type* ty) { +static void api_remember_slot_type(CfreeCg* g, FrameSlot slot, CfreeCgTypeId ty) { Heap* h = g->c->env->heap; - const Type** nb; + CfreeCgTypeId* nb; u32 cap; if (slot == FRAME_SLOT_NONE) return; if (slot < g->slot_types_cap) { @@ -1337,7 +1118,7 @@ static void api_remember_slot_type(CfreeCg* g, FrameSlot slot, const Type* ty) { } cap = g->slot_types_cap ? g->slot_types_cap : 16; while (cap <= slot) cap *= 2u; - nb = (const Type**)h->alloc(h, sizeof(*nb) * cap, _Alignof(const Type*)); + nb = (CfreeCgTypeId*)h->alloc(h, sizeof(*nb) * cap, _Alignof(CfreeCgTypeId)); if (!nb) return; memset(nb, 0, sizeof(*nb) * cap); if (g->slot_types) { @@ -1349,8 +1130,10 @@ static void api_remember_slot_type(CfreeCg* g, FrameSlot slot, const Type* ty) { g->slot_types[slot] = ty; } -static const Type* api_slot_type(CfreeCg* g, FrameSlot slot) { - if (slot == FRAME_SLOT_NONE || slot >= g->slot_types_cap) return NULL; +static CfreeCgTypeId api_slot_type(CfreeCg* g, FrameSlot slot) { + if (slot == FRAME_SLOT_NONE || slot >= g->slot_types_cap) { + return CFREE_CG_TYPE_NONE; + } return g->slot_types[slot]; } @@ -1375,10 +1158,10 @@ static void api_set_owned_reg(ApiSValue* sv, Reg r) { sv->op.v.ind.base = r; } -static const Type* api_owned_reg_type(CfreeCg* g, const ApiSValue* sv) { +static CfreeCgTypeId api_owned_reg_type(CfreeCg* g, const ApiSValue* sv) { if (sv->op.kind == OPK_INDIRECT) { - const Type* base = sv->type ? sv->type : type_void(g->c->global); - return type_ptr(g->c->global, base); + CfreeCgTypeId base = sv->type ? sv->type : builtin_id(CFREE_CG_BUILTIN_VOID); + return cg_type_ptr_to(g->c, base); } return api_sv_type(sv); } @@ -1458,14 +1241,13 @@ static int api_spill_avs_victim(CfreeCg* g, u8 cls) { } static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, - const Type* ty) { + CfreeCgTypeId ty) { MemAccess m; memset(&m, 0, sizeof m); m.type = ty; - m.size = ty ? abi_sizeof(g->c->abi, ty) : 0; - m.align = ty ? abi_alignof(g->c->abi, ty) : 0; + m.size = ty ? abi_cg_sizeof(g->c->abi, ty) : 0; + m.align = ty ? abi_cg_alignof(g->c->abi, ty) : 0; m.flags = MF_NONE; - if (ty && (ty->qual & Q_VOLATILE)) m.flags |= MF_VOLATILE; if (lv->kind == OPK_LOCAL) { m.alias.kind = (u8)ALIAS_LOCAL; m.alias.v.local_id = (i32)lv->v.frame_slot; @@ -1479,29 +1261,29 @@ static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, static MemAccess api_mem_from_access(CfreeCg* g, const Operand* lv, CfreeCgMemAccess access) { - const Type* ty = resolve_type(g->c, access.type); + CfreeCgTypeId ty = resolve_type(g->c, access.type); MemAccess m = api_mem_for_lvalue(g, lv, ty); if (access.align) m.align = access.align; m.addr_space = (u16)access.address_space; if (access.flags & CFREE_CG_MEM_VOLATILE) m.flags |= MF_VOLATILE; - if (!access.align || (ty && access.align < abi_alignof(g->c->abi, ty))) { + if (!access.align || (ty && access.align < abi_cg_alignof(g->c->abi, ty))) { m.flags |= MF_UNALIGNED; } return m; } static MemAccess api_mem_for_spill(CfreeCg* g, const ApiSValue* sv) { - const Type* ty = api_owned_reg_type(g, sv); + CfreeCgTypeId ty = api_owned_reg_type(g, sv); MemAccess m; memset(&m, 0, sizeof m); m.type = ty; - m.size = ty ? abi_sizeof(g->c->abi, ty) : 8; - m.align = ty ? abi_alignof(g->c->abi, ty) : 8; + m.size = ty ? abi_cg_sizeof(g->c->abi, ty) : 8; + m.align = ty ? abi_cg_alignof(g->c->abi, ty) : 8; m.alias.kind = (u8)ALIAS_UNKNOWN; return m; } -static Reg api_alloc_reg_or_spill(CfreeCg* g, u8 cls, const Type* ty) { +static Reg api_alloc_reg_or_spill(CfreeCg* g, u8 cls, CfreeCgTypeId ty) { CGTarget* T = g->target; Reg r = T->alloc_reg(T, cls, ty); if (r != (Reg)REG_NONE) return r; @@ -1509,7 +1291,7 @@ static Reg api_alloc_reg_or_spill(CfreeCg* g, u8 cls, const Type* ty) { ApiSValue* victim = api_pick_victim(g, cls); if (victim) { FrameSlot slot = api_take_spill_slot(g, cls); - const Type* rty = api_owned_reg_type(g, victim); + CfreeCgTypeId rty = api_owned_reg_type(g, victim); Operand victim_reg = api_op_reg((Reg)api_reg_of_sv(victim), rty); T->spill_reg(T, victim_reg, slot, api_mem_for_spill(g, victim)); victim->spill_slot = slot; @@ -1534,9 +1316,9 @@ static void api_ensure_reg(CfreeCg* g, ApiSValue* sv) { if (sv->res != RES_SPILLED) return; CGTarget* T = g->target; u8 cls = api_class_of_sv(sv); - const Type* ty = api_owned_reg_type(g, sv); + CfreeCgTypeId ty = api_owned_reg_type(g, sv); Reg r = - api_alloc_reg_or_spill(g, cls, ty ? ty : type_prim(g->c->global, TY_INT)); + api_alloc_reg_or_spill(g, cls, ty ? ty : builtin_id(CFREE_CG_BUILTIN_I32)); T->reload_reg(T, api_op_reg(r, ty), sv->spill_slot, api_mem_for_spill(g, sv)); api_return_spill_slot(g, sv->spill_slot, cls); sv->spill_slot = FRAME_SLOT_NONE; @@ -1548,7 +1330,7 @@ static void api_ensure_reg(CfreeCg* g, ApiSValue* sv) { sv->res = RES_REG; } -static Operand api_force_reg(CfreeCg* g, ApiSValue* v, const Type* ty) { +static Operand api_force_reg(CfreeCg* g, ApiSValue* v, CfreeCgTypeId ty) { CGTarget* T = g->target; api_ensure_reg(g, v); if (v->op.kind == OPK_REG) return v->op; @@ -1573,7 +1355,7 @@ static Operand api_force_reg(CfreeCg* g, ApiSValue* v, const Type* ty) { } static Operand api_force_reg_unless_imm(CfreeCg* g, ApiSValue* v, - const Type* ty) { + CfreeCgTypeId ty) { if (v->op.kind == OPK_IMM) return v->op; return api_force_reg(g, v, ty); } @@ -1592,8 +1374,8 @@ static void api_release_arg_storage(CfreeCg* g, Operand* storage) { if (storage->kind == OPK_REG) { g->target->free_reg(g->target, storage->v.reg, storage->cls); } else if (storage->kind == OPK_LOCAL && storage->cls < 3) { - const Type* ty = storage->type; - if (ty && (ty->kind == TY_STRUCT || ty->kind == TY_UNION)) return; + CfreeCgTypeId ty = storage->type; + if (cg_type_is_aggregate(g->c, ty)) return; api_return_spill_slot(g, storage->v.frame_slot, storage->cls); } else if (storage->kind == OPK_INDIRECT) { g->target->free_reg(g->target, storage->v.ind.base, RC_INT); @@ -1797,10 +1579,10 @@ static SymKind api_decl_sym_kind(CfreeCgDecl decl) { return SK_OBJ; } -static void api_remember_sym(CfreeCg* g, ObjSymId sym, const Type* ty, +static void api_remember_sym(CfreeCg* g, ObjSymId sym, CfreeCgTypeId ty, CfreeCgDecl decl) { Heap* h; - const Type** nts; + CfreeCgTypeId* nts; CfreeCgDecl* nas; u32 cap; if (!g || sym == OBJ_SYM_NONE) return; @@ -1812,7 +1594,7 @@ static void api_remember_sym(CfreeCg* g, ObjSymId sym, const Type* ty, h = g->c->env->heap; cap = g->sym_cap ? g->sym_cap : 16u; while (cap <= sym) cap *= 2u; - nts = (const Type**)h->alloc(h, sizeof(*nts) * cap, _Alignof(const Type*)); + nts = (CfreeCgTypeId*)h->alloc(h, sizeof(*nts) * cap, _Alignof(CfreeCgTypeId)); nas = (CfreeCgDecl*)h->alloc(h, sizeof(*nas) * cap, _Alignof(CfreeCgDecl)); if (!nts || !nas) { if (nts) h->free(h, nts, sizeof(*nts) * cap); @@ -1836,8 +1618,10 @@ static void api_remember_sym(CfreeCg* g, ObjSymId sym, const Type* ty, g->sym_attrs[sym] = decl; } -static const Type* api_sym_type(CfreeCg* g, CfreeCgSym sym) { - if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) return NULL; +static CfreeCgTypeId api_sym_type(CfreeCg* g, CfreeCgSym sym) { + if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) { + return CFREE_CG_TYPE_NONE; + } return g->sym_types[sym]; } @@ -1926,81 +1710,6 @@ void cfree_cg_free(CfreeCg* g) { h->free(h, g, sizeof *g); } -Compiler* cfree_cg_internal_compiler(CfreeCg* g) { - return g ? g->c : NULL; -} - -CGTarget* cfree_cg_internal_target(CfreeCg* g) { - return g ? g->target : NULL; -} - -MCEmitter* cfree_cg_internal_mc(CfreeCg* g) { - return g ? g->mc : NULL; -} - -const Type* cfree_cg_internal_top_type(CfreeCg* g) { - if (!g || g->sp == 0) return NULL; - return api_sv_type(&g->stack[g->sp - 1u]); -} - -const Type* cfree_cg_internal_top2_type(CfreeCg* g) { - if (!g || g->sp < 2) return NULL; - return api_sv_type(&g->stack[g->sp - 2u]); -} - -void cfree_cg_internal_retag_top(CfreeCg* g, const Type* ty) { - if (!g || g->sp == 0) return; - g->stack[g->sp - 1u].type = ty; - g->stack[g->sp - 1u].op.type = ty; -} - -void cfree_cg_internal_push_local_typed(CfreeCg* g, CfreeCgSlot slot, - const Type* ty) { - if (!g) return; - api_remember_slot_type(g, (FrameSlot)slot, ty); - cfree_cg_push_local(g, slot); -} - -void cfree_cg_internal_bind_sym(CfreeCg* g, ObjSymId sym, const Type* ty, - CfreeCgDeclKind kind) { - CfreeCgDecl decl; - const ObjSym* os; - if (!g || sym == OBJ_SYM_NONE || !ty) return; - memset(&decl, 0, sizeof decl); - os = obj_symbol_get(g->obj, sym); - decl.kind = kind; - if (os) { - decl.linkage_name = os->name; - decl.sym.bind = os->bind == SB_LOCAL ? CFREE_SB_LOCAL - : os->bind == SB_WEAK ? CFREE_SB_WEAK - : CFREE_SB_GLOBAL; - decl.sym.visibility = - (os->vis == SV_HIDDEN || os->vis == SV_INTERNAL) - ? CFREE_CG_VIS_HIDDEN - : (os->vis == SV_PROTECTED ? CFREE_CG_VIS_PROTECTED - : CFREE_CG_VIS_DEFAULT); - } - api_remember_sym(g, sym, ty, decl); -} - -void cfree_cg_internal_param_slot_existing(CfreeCg* g, uint32_t index, - CfreeCgSlot slot, - const Type* ty, CfreeSym name) { - CGParamDesc pd; - if (!g || !ty || slot == CFREE_CG_SLOT_NONE) return; - api_remember_slot_type(g, (FrameSlot)slot, ty); - memset(&pd, 0, sizeof pd); - pd.index = index; - pd.name = (Sym)name; - pd.type = ty; - pd.slot = (FrameSlot)slot; - if (g->fn_abi && index < g->fn_abi->nparams) { - pd.abi = &g->fn_abi->params[index]; - } - pd.loc = g->cur_loc; - g->target->param(g->target, &pd); -} - /* ============================================================ * Source location * ============================================================ */ @@ -2019,7 +1728,7 @@ CfreeCgSym cfree_cg_decl(CfreeCg* g, CfreeCgDecl decl) { Compiler* c; ObjBuilder* ob; ObjSymId sym; - const Type* ty; + CfreeCgTypeId ty; if (!g || !decl.linkage_name) return CFREE_CG_SYM_NONE; c = g->c; ob = g->obj; @@ -2071,7 +1780,7 @@ void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { CGTarget* T; ObjSymId sym; ObjSecId text_sec; - const Type* fty; + CfreeCgTypeId fty; const ABIFuncInfo* abi; CfreeCgDecl attrs; if (!g) return; @@ -2082,7 +1791,7 @@ void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { fty = api_sym_type(g, cg_sym); if (!fty) return; attrs = api_sym_attrs(g, cg_sym); - abi = abi_func_info(c->abi, fty); + abi = abi_cg_func_info(c->abi, fty); text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), SEC_TEXT, SF_EXEC | SF_ALLOC, 4); @@ -2102,7 +1811,7 @@ void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { g->fn_desc.flags |= CGFD_NORETURN; } - g->fn_ret_type = fty->fn.ret; + g->fn_ret_type = cg_type_func_ret_id(c, fty); g->fn_abi = abi; g->sp = 0; for (u32 i = 0; i < 3; ++i) g->slot_pools[i].n = 0; @@ -2116,7 +1825,7 @@ void cfree_cg_func_end(CfreeCg* g) { if (!g) return; g->target->func_end(g->target); g->fn_abi = NULL; - g->fn_ret_type = NULL; + g->fn_ret_type = CFREE_CG_TYPE_NONE; g->nscopes = 0; memset(g->scopes, 0, sizeof g->scopes); } @@ -2127,7 +1836,7 @@ void cfree_cg_func_end(CfreeCg* g) { CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, CfreeCgSlotAttrs attrs) { - const Type* ty; + CfreeCgTypeId ty; FrameSlotDesc fsd; FrameSlot slot; if (!g) return 0; @@ -2148,7 +1857,7 @@ CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, CfreeCgSlotAttrs attrs) { - const Type* ty; + CfreeCgTypeId ty; FrameSlot slot; CGParamDesc pd; FrameSlotDesc fsd; @@ -2186,7 +1895,7 @@ CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, * ============================================================ */ void cfree_cg_push_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { - const Type* ty; + CfreeCgTypeId ty; if (!g) return; ty = resolve_type(g->c, type); if (!ty) return; @@ -2194,7 +1903,7 @@ void cfree_cg_push_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { } void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { - const Type* ty; + CfreeCgTypeId ty; CGTarget* T; ConstBytes cb; union { @@ -2211,7 +1920,7 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { cb.type = ty; cb.size = (u32)abi_cg_sizeof(g->c->abi, type); cb.align = (u32)abi_cg_alignof(g->c->abi, type); - if (ty->kind == TY_FLOAT) + if (ty == builtin_id(CFREE_CG_BUILTIN_F32)) u.f = (float)value; else u.d = value; @@ -2223,7 +1932,7 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { } void cfree_cg_push_null(CfreeCg* g, CfreeCgTypeId ptr_type) { - const Type* ty; + CfreeCgTypeId ty; if (!g) return; ty = resolve_type(g->c, ptr_type); if (!ty) return; @@ -2234,7 +1943,7 @@ CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, uint32_t align, CfreeCgTypeId pointee_type) { Compiler* c; ObjBuilder* ob; - const Type* pty; + CfreeCgTypeId pty; Sym sec_name; ObjSecId sec; u32 base; @@ -2266,19 +1975,19 @@ CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, } void cfree_cg_push_local(CfreeCg* g, CfreeCgSlot slot) { - const Type* ty; + CfreeCgTypeId ty; if (!g) return; ty = api_slot_type(g, (FrameSlot)slot); api_push(g, api_make_lv(api_op_local((FrameSlot)slot, ty), ty)); } void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend) { - const Type* ty; - const Type* ptr_ty; + CfreeCgTypeId ty; + CfreeCgTypeId ptr_ty; if (!g) return; ty = api_sym_type(g, sym); - if (!ty) ty = type_void(g->c->global); - ptr_ty = type_ptr(g->c->global, ty); + if (!ty) ty = builtin_id(CFREE_CG_BUILTIN_VOID); + ptr_ty = cg_type_ptr_to(g->c, ty); if (api_sym_is_tls(g, sym)) { Reg r = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); Operand dst = api_op_reg(r, ptr_ty); @@ -2291,12 +2000,12 @@ void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend) { } void cfree_cg_push_symbol_lvalue(CfreeCg* g, CfreeCgSym sym, int64_t addend) { - const Type* ty; + CfreeCgTypeId ty; if (!g) return; ty = api_sym_type(g, sym); if (!ty) return; if (api_sym_is_tls(g, sym)) { - const Type* ptr_ty = type_ptr(g->c->global, ty); + CfreeCgTypeId ptr_ty = cg_type_ptr_to(g->c, ty); Reg r = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); Operand dst = api_op_reg(r, ptr_ty); g->target->tls_addr_of(g->target, dst, (ObjSymId)sym, addend); @@ -2309,8 +2018,8 @@ void cfree_cg_push_symbol_lvalue(CfreeCg* g, CfreeCgSym sym, int64_t addend) { void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, CfreeCgTypeId result_type) { ApiSValue v; - const Type* rty; - const Type* ptr_ty; + CfreeCgTypeId rty; + CfreeCgTypeId ptr_ty; Operand base; Operand result; Reg rr; @@ -2322,7 +2031,7 @@ void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, if (v.op.kind == OPK_GLOBAL) { result = api_op_global(v.op.v.global.sym, v.op.v.global.addend + byte_offset, rty); - api_push(g, type_is_ptr(rty) ? api_make_sv(result, rty) + api_push(g, cg_type_is_ptr(g->c, rty) ? api_make_sv(result, rty) : api_make_lv(result, rty)); return; } @@ -2330,13 +2039,13 @@ void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, i64 ofs = (i64)v.op.v.ind.ofs + byte_offset; if (ofs >= INT32_MIN && ofs <= INT32_MAX) { result = api_op_indirect(v.op.v.ind.base, (i32)ofs, rty); - api_push(g, type_is_ptr(rty) ? api_make_sv(result, rty) + api_push(g, cg_type_is_ptr(g->c, rty) ? api_make_sv(result, rty) : api_make_lv(result, rty)); return; } } - ptr_ty = type_is_ptr(api_sv_type(&v)) ? api_sv_type(&v) - : type_ptr(g->c->global, rty); + ptr_ty = cg_type_is_ptr(g->c, api_sv_type(&v)) ? api_sv_type(&v) + : cg_type_ptr_to(g->c, rty); base = api_is_lvalue_sv(&v) ? api_force_reg(g, &v, ptr_ty) : api_force_reg(g, &v, ptr_ty); rr = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); @@ -2344,7 +2053,7 @@ void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, g->target->binop(g->target, BO_IADD, result, base, api_op_imm(byte_offset, ptr_ty)); api_release(g, &v); - if (type_is_ptr(rty)) { + if (cg_type_is_ptr(g->c, rty)) { result.type = rty; api_push(g, api_make_sv(result, rty)); } else { @@ -2358,7 +2067,7 @@ void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access) { ApiSValue v; - const Type* ty; + CfreeCgTypeId ty; Operand dst; if (!g) return; v = api_pop(g); @@ -2376,19 +2085,18 @@ void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access) { void cfree_cg_indirect(CfreeCg* g) { ApiSValue ptr; - const Type* pty; - const Type* pointee; + CfreeCgTypeId pty; + CfreeCgTypeId pointee; Operand ptr_op; if (!g) return; ptr = api_pop(g); pty = api_sv_type(&ptr); - if (!pty || pty->kind != TY_PTR || !pty->ptr.pointee || - pty->ptr.pointee->kind == TY_VOID) { + pointee = cg_type_pointee(g->c, pty); + if (!pointee || cg_type_is_void(g->c, pointee)) { compiler_panic(g->c, g->cur_loc, "CfreeCg: indirect operand is not a pointer to object"); return; } - pointee = pty->ptr.pointee; ptr_op = api_force_reg(g, &ptr, pty); api_push(g, api_make_lv(api_op_indirect(ptr_op.v.reg, 0, pointee), pointee)); } @@ -2396,7 +2104,7 @@ void cfree_cg_indirect(CfreeCg* g) { void cfree_cg_addr(CfreeCg* g) { ApiSValue v; CGTarget* T; - const Type* pty; + CfreeCgTypeId pty; Reg r; Operand dst; if (!g) return; @@ -2407,7 +2115,7 @@ void cfree_cg_addr(CfreeCg* g) { compiler_panic(g->c, g->cur_loc, "CfreeCg: addr operand is not an lvalue"); return; } - pty = type_ptr(g->c->global, api_sv_type(&v)); + pty = cg_type_ptr_to(g->c, api_sv_type(&v)); r = api_alloc_reg_or_spill(g, RC_INT, pty); dst = api_op_reg(r, pty); T->addr_of(T, dst, v.op); @@ -2418,7 +2126,7 @@ void cfree_cg_addr(CfreeCg* g) { void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access) { ApiSValue lv, rv; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; Operand src; if (!g) return; T = g->target; @@ -2450,7 +2158,7 @@ void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access) { void cfree_cg_dup(CfreeCg* g) { ApiSValue v, dup; ApiSValue* top; - const Type* ty; + CfreeCgTypeId ty; Reg r; Operand dst; if (!g || g->sp == 0) return; @@ -2508,7 +2216,7 @@ void cfree_cg_rot3(CfreeCg* g) { static void api_cg_binop(CfreeCg* g, BinOp iop) { ApiSValue b, a; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; Operand ra, rb; Reg rr; Operand dst; @@ -2531,7 +2239,7 @@ static void api_cg_binop(CfreeCg* g, BinOp iop) { static void api_cg_unop(CfreeCg* g, UnOp iop) { ApiSValue a; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; Operand ra; Reg rr; Operand dst; @@ -2551,8 +2259,8 @@ static void api_cg_unop(CfreeCg* g, UnOp iop) { static void api_cg_cmp(CfreeCg* g, CmpOp cop) { ApiSValue b, a; CGTarget* T; - const Type* opty; - const Type* i32; + CfreeCgTypeId opty; + CfreeCgTypeId i32; Operand ra, rb; Reg rr; Operand dst; @@ -2561,7 +2269,7 @@ static void api_cg_cmp(CfreeCg* g, CmpOp cop) { b = api_pop(g); a = api_pop(g); opty = a.type ? a.type : b.type; - i32 = type_prim(g->c->global, TY_INT); + i32 = builtin_id(CFREE_CG_BUILTIN_I32); ra = api_force_reg_unless_imm(g, &a, opty); rb = api_force_reg_unless_imm(g, &b, opty); @@ -2577,8 +2285,8 @@ static void api_cg_convert_kind(CfreeCg* g, CfreeCgTypeId dst_type, ConvKind ck) { ApiSValue v; CGTarget* T; - const Type* sty; - const Type* dty; + CfreeCgTypeId sty; + CfreeCgTypeId dty; Operand src; Reg rr; Operand dst; @@ -2593,7 +2301,7 @@ static void api_cg_convert_kind(CfreeCg* g, CfreeCgTypeId dst_type, return; } if (ck == CV_BITCAST && - abi_sizeof(g->c->abi, sty) == abi_cg_sizeof(g->c->abi, dst_type) && + abi_cg_sizeof(g->c->abi, sty) == abi_cg_sizeof(g->c->abi, dst_type) && api_type_class(sty) == api_type_class(dty)) { v.type = dty; v.op.type = dty; @@ -2778,8 +2486,8 @@ static int api_intrinsic_is_overflow(CfreeCgIntrinsic intrin) { void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, CfreeCgTypeId result_type) { CGTarget* T; - const Type* rty; - const Type* int_ty; + CfreeCgTypeId rty; + CfreeCgTypeId int_ty; IntrinKind kind; ApiSValue* svs; Operand* args; @@ -2790,7 +2498,7 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, T = g->target; h = g->c->env->heap; rty = resolve_type(g->c, result_type); - int_ty = type_prim(g->c->global, TY_INT); + int_ty = builtin_id(CFREE_CG_BUILTIN_I32); kind = api_map_intrinsic(g, intrin, result_type); if (kind == INTRIN_NONE) { compiler_panic(g->c, g->cur_loc, "CfreeCg: unsupported intrinsic"); @@ -2805,7 +2513,7 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, memset(args, 0, sizeof(*args) * nargs); for (u32 i = 0; i < nargs; ++i) { u32 idx = nargs - 1u - i; - const Type* aty; + CfreeCgTypeId aty; svs[idx] = api_pop(g); aty = api_sv_type(&svs[idx]); if (svs[idx].op.kind == OPK_IMM && @@ -2820,13 +2528,13 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, } if (api_intrinsic_is_overflow(intrin)) { - const Type* vty = rty ? rty : (nargs ? api_sv_type(&svs[0]) : int_ty); + CfreeCgTypeId vty = rty ? rty : (nargs ? api_sv_type(&svs[0]) : int_ty); Reg rr = api_alloc_reg_or_spill(g, api_type_class(vty), vty); Reg ok = api_alloc_reg_or_spill(g, RC_INT, int_ty); dsts[0] = api_op_reg(rr, vty); dsts[1] = api_op_reg(ok, int_ty); ndst = 2; - } else if (!api_intrinsic_is_void(intrin) && rty && rty->kind != TY_VOID) { + } else if (!api_intrinsic_is_void(intrin) && !cg_type_is_void(g->c, rty)) { Reg rr = api_alloc_reg_or_spill(g, api_type_class(rty), rty); dsts[0] = api_op_reg(rr, rty); ndst = 1; @@ -2850,23 +2558,22 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, * Atomics (stub) * ============================================================ */ -static const Type* api_atomic_pointee(CfreeCg* g, const Type* pty, +static CfreeCgTypeId api_atomic_pointee(CfreeCg* g, CfreeCgTypeId pty, const char* who) { - if (!pty || pty->kind != TY_PTR) { + CfreeCgTypeId pointee = cg_type_pointee(g->c, pty); + if (!pointee) { compiler_panic(g->c, g->cur_loc, "%s: operand is not a pointer", who); - return type_prim(g->c->global, TY_INT); + return builtin_id(CFREE_CG_BUILTIN_I32); } - return pty->ptr.pointee; + return pointee; } -static MemAccess api_mem_for_atomic(CfreeCg* g, const Type* val_ty) { +static MemAccess api_mem_for_atomic(CfreeCg* g, CfreeCgTypeId val_ty) { MemAccess ma; memset(&ma, 0, sizeof ma); ma.type = val_ty; - ma.size = val_ty ? abi_cg_sizeof(g->c->abi, cg_api_type_import(g->c, val_ty)) - : 0; - ma.align = - val_ty ? abi_cg_alignof(g->c->abi, cg_api_type_import(g->c, val_ty)) : 0; + ma.size = val_ty ? abi_cg_sizeof(g->c->abi, val_ty) : 0; + ma.align = val_ty ? abi_cg_alignof(g->c->abi, val_ty) : 0; ma.flags = MF_ATOMIC; ma.alias.kind = (u8)ALIAS_UNKNOWN; return ma; @@ -2874,14 +2581,14 @@ static MemAccess api_mem_for_atomic(CfreeCg* g, const Type* val_ty) { int cfree_cg_atomic_is_legal(CfreeCompiler* c, CfreeCgMemAccess access, CfreeCgMemOrder order) { - const Type* ty = resolve_type(c, access.type); + CfreeCgTypeId ty = resolve_type(c, access.type); (void)order; if (!ty) return 0; return abi_cg_sizeof(c->abi, access.type) <= 8; } int cfree_cg_atomic_is_lock_free(CfreeCompiler* c, CfreeCgMemAccess access) { - const Type* ty = resolve_type(c, access.type); + CfreeCgTypeId ty = resolve_type(c, access.type); if (!ty) return 0; return abi_cg_sizeof(c->abi, access.type) <= (u32)c->target.ptr_size; } @@ -2889,7 +2596,7 @@ int cfree_cg_atomic_is_lock_free(CfreeCompiler* c, CfreeCgMemAccess access) { void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemAccess access, CfreeCgMemOrder order) { ApiSValue ptr; - const Type *pty, *val_ty; + CfreeCgTypeId pty, val_ty; Operand addr, dst; Reg rr; if (!g) return; @@ -2909,7 +2616,7 @@ void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemAccess access, void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemAccess access, CfreeCgMemOrder order) { ApiSValue val, ptr; - const Type *pty, *val_ty; + CfreeCgTypeId pty, val_ty; Operand addr, src; if (!g) return; val = api_pop(g); @@ -2930,7 +2637,7 @@ void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemAccess access, void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgMemAccess access, CfreeCgAtomicOp op, CfreeCgMemOrder order) { ApiSValue val, ptr; - const Type *pty, *val_ty; + CfreeCgTypeId pty, val_ty; Operand addr, vop, dst; Reg rr; if (!g) return; @@ -2957,7 +2664,7 @@ void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemAccess access, CfreeCgMemOrder success, CfreeCgMemOrder failure, int weak) { ApiSValue desired, expected, ptr; - const Type *pty, *val_ty, *int_ty; + CfreeCgTypeId pty, val_ty, int_ty; Operand addr, exp_op, des_op, prior, ok; Reg pr, kr; if (!g) return; @@ -2968,7 +2675,7 @@ void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemAccess access, pty = api_sv_type(&ptr); val_ty = resolve_type(g->c, access.type); if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_cmpxchg"); - int_ty = type_prim(g->c->global, TY_INT); + int_ty = builtin_id(CFREE_CG_BUILTIN_I32); addr = api_force_reg(g, &ptr, pty); exp_op = (expected.op.kind == OPK_IMM || expected.op.kind == OPK_REG) ? expected.op @@ -3046,7 +2753,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { "5", "6", "7", "8", "9"}; CGTarget* T; Heap* h; - const Type* fallback_ty; + CfreeCgTypeId fallback_ty; AsmConstraint* outs; AsmConstraint* ins; Sym* clobs; @@ -3071,7 +2778,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { if (!g) return; T = g->target; h = g->c->env->heap; - fallback_ty = type_prim(g->c->global, TY_LLONG); + fallback_ty = builtin_id(CFREE_CG_BUILTIN_I64); tmpl_str = api_sym_cstr(g, tmpl); ninout = 0; @@ -3151,7 +2858,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { const char* body = api_asm_constraint_body(outs[i].str); if (api_asm_is_early_clobber(outs[i].str)) continue; if (body[0] == 'r') { - const Type* oty = outs[i].type ? outs[i].type : fallback_ty; + CfreeCgTypeId oty = outs[i].type ? outs[i].type : fallback_ty; Reg r = api_alloc_reg_or_spill(g, api_type_class(oty), oty); out_ops[i] = api_op_reg(r, oty); out_reg_owned[i] = 1; @@ -3164,7 +2871,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { for (u32 i = 0; i < total_inputs; ++i) { const char* s = ins[i].str ? ins[i].str : ""; int matched = api_asm_parse_match_index(s); - const Type* ity = api_sv_type(&in_svs[i]); + CfreeCgTypeId ity = api_sv_type(&in_svs[i]); if (matched >= 0) { Operand bound; if ((u32)matched >= noutputs) { @@ -3198,8 +2905,8 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { if (in_svs[i].op.kind == OPK_INDIRECT) { in_ops[i] = in_svs[i].op; } else if (api_is_lvalue_sv(&in_svs[i])) { - const Type* pty = - type_ptr(g->c->global, ity ? ity : type_void(g->c->global)); + CfreeCgTypeId pty = + cg_type_ptr_to(g->c, ity ? ity : builtin_id(CFREE_CG_BUILTIN_VOID)); Reg r = api_alloc_reg_or_spill(g, RC_INT, pty); Operand dst = api_op_reg(r, pty); T->addr_of(T, dst, in_svs[i].op); @@ -3218,7 +2925,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { for (u32 i = 0; i < noutputs; ++i) { const char* body; - const Type* oty; + CfreeCgTypeId oty; Reg r; if (!api_asm_is_early_clobber(outs[i].str)) continue; body = api_asm_constraint_body(outs[i].str); @@ -3289,7 +2996,7 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { for (u32 i = 0; i < total_inputs; ++i) api_release(g, &in_svs[i]); for (u32 i = 0; i < noutputs; ++i) { - const Type* oty = outs[i].type ? outs[i].type : fallback_ty; + CfreeCgTypeId oty = outs[i].type ? outs[i].type : fallback_ty; ApiSValue sv = api_make_sv(out_ops[i], oty); if (!out_reg_owned[i] && sv.res == RES_REG) sv.res = RES_INHERENT; api_push(g, sv); @@ -3326,11 +3033,11 @@ void cfree_cg_jump(CfreeCg* g, CfreeCgLabel label) { void cfree_cg_branch_true(CfreeCg* g, CfreeCgLabel label) { ApiSValue v; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; if (!g) return; T = g->target; v = api_pop(g); - ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { if (v.op.v.imm != 0) T->jump(T, (Label)label); api_release(g, &v); @@ -3347,11 +3054,11 @@ void cfree_cg_branch_true(CfreeCg* g, CfreeCgLabel label) { void cfree_cg_branch_false(CfreeCg* g, CfreeCgLabel label) { ApiSValue v; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; if (!g) return; T = g->target; v = api_pop(g); - ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { if (v.op.v.imm == 0) T->jump(T, (Label)label); api_release(g, &v); @@ -3367,7 +3074,7 @@ void cfree_cg_branch_false(CfreeCg* g, CfreeCgLabel label) { void cfree_cg_switch(CfreeCg* g, CfreeCgSwitch sw) { ApiSValue selector; - const Type* ty; + CfreeCgTypeId ty; Operand sel; if (!g) return; if (g->sp == 0) return; @@ -3450,7 +3157,7 @@ static ApiCgScope* api_scope_from_handle(CfreeCg* g, CfreeCgScope scope, } static int api_scope_has_result(const ApiCgScope* s) { - return s->result_type && s->result_type->kind != TY_VOID; + return s->result_type != CFREE_CG_TYPE_NONE; } static void api_scope_store_result(CfreeCg* g, ApiCgScope* s, @@ -3554,13 +3261,13 @@ void cfree_cg_break_true(CfreeCg* g, CfreeCgScope scope) { ApiCgScope* s; ApiSValue cond; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; if (!g || scope == 0) return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: break_true"); if (!s) return; T = g->target; cond = api_pop(g); - ty = cond.type ? cond.type : type_prim(g->c->global, TY_INT); + ty = cond.type ? cond.type : builtin_id(CFREE_CG_BUILTIN_I32); if (api_scope_has_result(s)) { ApiSValue result = api_pop(g); @@ -3599,13 +3306,13 @@ void cfree_cg_break_false(CfreeCg* g, CfreeCgScope scope) { ApiCgScope* s; ApiSValue cond; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; if (!g || scope == 0) return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: break_false"); if (!s) return; T = g->target; cond = api_pop(g); - ty = cond.type ? cond.type : type_prim(g->c->global, TY_INT); + ty = cond.type ? cond.type : builtin_id(CFREE_CG_BUILTIN_I32); if (api_scope_has_result(s)) { ApiSValue result = api_pop(g); @@ -3650,13 +3357,13 @@ void cfree_cg_continue_true(CfreeCg* g, CfreeCgScope scope) { ApiCgScope* s; ApiSValue v; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; if (!g || scope == 0) return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: continue_true"); if (!s) return; T = g->target; v = api_pop(g); - ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { if (v.op.v.imm != 0) T->jump(T, s->continue_lbl); api_release(g, &v); @@ -3672,13 +3379,13 @@ void cfree_cg_continue_false(CfreeCg* g, CfreeCgScope scope) { ApiCgScope* s; ApiSValue v; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; if (!g || scope == 0) return; s = api_scope_from_handle(g, scope, 0, "CfreeCg: continue_false"); if (!s) return; T = g->target; v = api_pop(g); - ty = v.type ? v.type : type_prim(g->c->global, TY_INT); + ty = v.type ? v.type : builtin_id(CFREE_CG_BUILTIN_I32); if (v.op.kind == OPK_IMM) { if (v.op.v.imm == 0) T->jump(T, s->continue_lbl); api_release(g, &v); @@ -3698,7 +3405,7 @@ void cfree_cg_alloca(CfreeCg* g, uint32_t align, CfreeCgTypeId result_ptr_type) { ApiSValue sz; CGTarget* T; - const Type* pty; + CfreeCgTypeId pty; Operand sz_op; Reg rr; Operand dst; @@ -3706,7 +3413,7 @@ void cfree_cg_alloca(CfreeCg* g, uint32_t align, T = g->target; sz = api_pop(g); pty = resolve_type(g->c, result_ptr_type); - if (!pty) pty = type_ptr(g->c->global, type_void(g->c->global)); + if (!pty) pty = cg_type_ptr_to(g->c, builtin_id(CFREE_CG_BUILTIN_VOID)); sz_op = (sz.op.kind == OPK_IMM) ? sz.op : api_force_reg(g, &sz, api_sv_type(&sz)); rr = api_alloc_reg_or_spill(g, RC_INT, pty); @@ -3731,7 +3438,7 @@ void cfree_cg_vararg_start(CfreeCg* g) { void cfree_cg_vararg_next(CfreeCg* g, CfreeCgTypeId type) { ApiSValue ap; CGTarget* T; - const Type* ty; + CfreeCgTypeId ty; Operand ap_op; Reg rr; Operand dst; @@ -3819,7 +3526,7 @@ void cfree_cg_memmove(CfreeCg* g, uint64_t size, CfreeCgMemAccess dst_access, dst = api_pop(g); args[0] = api_force_reg(g, &dst, api_sv_type(&dst)); args[1] = api_force_reg(g, &src, api_sv_type(&src)); - args[2] = api_op_imm((i64)size, type_prim(g->c->global, TY_ULLONG)); + args[2] = api_op_imm((i64)size, builtin_id(CFREE_CG_BUILTIN_I64)); g->target->intrinsic(g->target, INTRIN_MEMMOVE, NULL, 0, args, 3); api_release(g, &dst); api_release(g, &src); @@ -3839,7 +3546,7 @@ void cfree_cg_memset(CfreeCg* g, uint8_t val, uint64_t size, T = g->target; dst = api_pop(g); dst_op = api_force_reg(g, &dst, api_sv_type(&dst)); - byte_val = api_op_imm((i64)val, NULL); + byte_val = api_op_imm((i64)val, CFREE_CG_TYPE_NONE); memset(&agg, 0, sizeof agg); agg.size = (u32)size; agg.align = dst_access.align ? dst_access.align : (u32)size; @@ -3850,7 +3557,8 @@ void cfree_cg_memset(CfreeCg* g, uint8_t val, uint64_t size, void cfree_cg_index(CfreeCg* g, uint64_t offset) { ApiSValue idx, base; CGTarget* T; - const Type *base_ty, *base_ptr_ty, *elem_ty, *idx_ty; + CfreeCgTypeId base_ty, base_ptr_ty, elem_ty, idx_ty; + const CgType* base_info; u32 elemsz; int free_base_op = 0; Operand base_op, idx_op, result; @@ -3865,21 +3573,23 @@ void cfree_cg_index(CfreeCg* g, uint64_t offset) { base = api_pop(g); api_ensure_reg(g, &base); base_ty = api_sv_type(&base); - if (base_ty && base_ty->kind == TY_PTR) { - elem_ty = base_ty->ptr.pointee; + base_info = cg_type_get(g->c, base_ty); + if (base_info && base_info->kind == CFREE_CG_TYPE_PTR) { + elem_ty = base_info->ptr.pointee; base_ptr_ty = base_ty; - } else if (base_ty && base_ty->kind == TY_ARRAY && api_is_lvalue_sv(&base)) { - elem_ty = base_ty->arr.elem; - base_ptr_ty = type_ptr(g->c->global, elem_ty); + } else if (base_info && base_info->kind == CFREE_CG_TYPE_ARRAY && + api_is_lvalue_sv(&base)) { + elem_ty = base_info->array.elem; + base_ptr_ty = cg_type_ptr_to(g->c, elem_ty); } else { compiler_panic(g->c, g->cur_loc, "CfreeCg: index base is not a pointer or array lvalue"); return; } - elemsz = (u32)abi_cg_sizeof(g->c->abi, cg_api_type_import(g->c, elem_ty)); + elemsz = (u32)abi_cg_sizeof(g->c->abi, elem_ty); idx_ty = idx.type ? idx.type : idx.op.type; - if (!idx_ty) idx_ty = type_prim(g->c->global, TY_INT); - if (base_ty && base_ty->kind == TY_ARRAY) { + if (!idx_ty) idx_ty = builtin_id(CFREE_CG_BUILTIN_I32); + if (base_info && base_info->kind == CFREE_CG_TYPE_ARRAY) { rr = api_alloc_reg_or_spill(g, RC_INT, base_ptr_ty); base_op = api_op_reg(rr, base_ptr_ty); T->addr_of(T, base_op, base.op); @@ -3906,7 +3616,7 @@ void cfree_cg_index(CfreeCg* g, uint64_t offset) { T->free_reg(T, sr, RC_INT); } if (free_base_op) T->free_reg(T, base_op.v.reg, RC_INT); - if (base_ty && base_ty->kind != TY_ARRAY) api_release(g, &base); + if (!base_info || base_info->kind != CFREE_CG_TYPE_ARRAY) api_release(g, &base); api_release(g, &idx); api_push(g, api_make_lv(api_op_indirect(result.v.reg, 0, elem_ty), elem_ty)); } @@ -3914,9 +3624,10 @@ void cfree_cg_index(CfreeCg* g, uint64_t offset) { void cfree_cg_field(CfreeCg* g, uint32_t field_index) { ApiSValue base; CGTarget* T; - const Type* rec_ty; - const Type* field_ty; - const Type* rec_ptr_ty; + CfreeCgTypeId rec_ty; + CfreeCgTypeId field_ty; + CfreeCgTypeId rec_ptr_ty; + const CgType* rec_info; const ABIRecordLayout* layout; u32 field_offset; Operand result; @@ -3930,18 +3641,19 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { compiler_panic(g->c, g->cur_loc, "CfreeCg: field base is not an lvalue"); return; } - layout = abi_cg_record_layout(g->c->abi, cg_api_type_import(g->c, rec_ty)); + layout = abi_cg_record_layout(g->c->abi, rec_ty); if (!layout || field_index >= layout->nfields) { compiler_panic(g->c, g->cur_loc, "CfreeCg: invalid field index"); return; } - if (!rec_ty || (rec_ty->kind != TY_STRUCT && rec_ty->kind != TY_UNION) || - field_index >= rec_ty->rec.nfields) { + rec_info = cg_type_get(g->c, rec_ty); + if (!rec_info || rec_info->kind != CFREE_CG_TYPE_RECORD || + field_index >= rec_info->record.nfields) { compiler_panic(g->c, g->cur_loc, "CfreeCg: invalid record base"); return; } - field_ty = rec_ty->rec.fields[field_index].type; - rec_ptr_ty = type_ptr(g->c->global, rec_ty); + field_ty = rec_info->record.fields[field_index].type; + rec_ptr_ty = cg_type_ptr_to(g->c, rec_ty); field_offset = layout->fields[field_index].offset; if (base.op.kind == OPK_GLOBAL) { result = @@ -3980,9 +3692,9 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, CfreeCgCallAttrs attrs) { CGTarget* T; - const Type* fty; + CfreeCgTypeId fty; const ABIFuncInfo* abi; - const Type* ret_ty; + CfreeCgTypeId ret_ty; int has_result; CGABIValue* avs; CGCallDesc desc; @@ -3994,9 +3706,9 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, T = g->target; fty = resolve_type(g->c, fn_type); if (!fty) return; - abi = abi_func_info(g->c->abi, fty); - ret_ty = fty->fn.ret; - has_result = !tail && ret_ty && ret_ty->kind != TY_VOID; + abi = abi_cg_func_info(g->c->abi, fty); + ret_ty = cg_type_func_ret_id(g->c, fty); + has_result = !tail && !cg_type_is_void(g->c, ret_ty); if (g->sp < (u32)nargs + 1u) { compiler_panic(g->c, g->cur_loc, "CfreeCg: call stack underflow"); @@ -4017,20 +3729,21 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, ApiSValue arg = api_pop(g); api_ensure_reg(g, &arg); int is_vararg = (idx >= abi->nparams); - const Type* aty; + CfreeCgTypeId aty; if (is_vararg) { aty = arg.type ? arg.type : api_sv_type(&arg); } else { - aty = fty->fn.params ? fty->fn.params[idx] : arg.type; + aty = cg_type_func_param_id(g->c, fty, idx); + if (!aty) aty = arg.type; } avs[idx].type = aty; avs[idx].abi = is_vararg ? NULL : &abi->params[idx]; - int is_aggregate = aty && (aty->kind == TY_STRUCT || aty->kind == TY_UNION); + int is_aggregate = cg_type_is_aggregate(g->c, aty); if (is_aggregate) { Operand st = arg.op; st.type = aty; avs[idx].storage = st; - avs[idx].size = abi_sizeof(g->c->abi, aty); + avs[idx].size = abi_cg_sizeof(g->c->abi, aty); } else { avs[idx].storage = api_is_lvalue_sv(&arg) ? api_force_reg(g, &arg, aty) : arg.op; @@ -4054,14 +3767,13 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, desc.ret.abi = &abi->ret; if (has_result) { - int ret_is_aggregate = - ret_ty->kind == TY_STRUCT || ret_ty->kind == TY_UNION; + int ret_is_aggregate = cg_type_is_aggregate(g->c, ret_ty); if (ret_is_aggregate) { FrameSlotDesc fsd; memset(&fsd, 0, sizeof fsd); fsd.type = ret_ty; - fsd.size = abi_sizeof(g->c->abi, ret_ty); - fsd.align = abi_alignof(g->c->abi, ret_ty); + fsd.size = abi_cg_sizeof(g->c->abi, ret_ty); + fsd.align = abi_cg_alignof(g->c->abi, ret_ty); fsd.kind = FS_LOCAL; fsd.flags = FSF_ADDR_TAKEN; FrameSlot ret_slot = T->frame_slot(T, &fsd); @@ -4100,7 +3812,7 @@ static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { CGTarget* T; - const Type* fty; + CfreeCgTypeId fty; const ABIFuncInfo* abi; CGABIValue* avs; CGCallDesc desc; @@ -4109,7 +3821,7 @@ static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, T = g->target; fty = resolve_type(g->c, fn_type); if (!fty) return; - abi = abi_func_info(g->c->abi, fty); + abi = abi_cg_func_info(g->c->abi, fty); avs = NULL; if (nargs) { avs = arena_array(g->c->tu, CGABIValue, nargs); @@ -4119,7 +3831,8 @@ static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, u32 idx = nargs - 1u - i; ApiSValue arg = api_pop(g); api_ensure_reg(g, &arg); - const Type* aty = fty->fn.params ? fty->fn.params[idx] : arg.type; + CfreeCgTypeId aty = cg_type_func_param_id(g->c, fty, idx); + if (!aty) aty = arg.type; avs[idx].type = aty; avs[idx].abi = idx < abi->nparams ? &abi->params[idx] : NULL; avs[idx].storage = @@ -4137,9 +3850,9 @@ static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, desc.args = avs; desc.nargs = nargs; desc.flags = CG_CALL_TAIL; - desc.ret.type = fty->fn.ret; + desc.ret.type = cg_type_func_ret_id(g->c, fty); desc.ret.abi = &abi->ret; - desc.ret.storage = api_op_imm(0, type_void(g->c->global)); + desc.ret.storage = api_op_imm(0, builtin_id(CFREE_CG_BUILTIN_VOID)); T->call(T, &desc); for (u32 i = 0; i < nargs; ++i) { api_release_arg_storage(g, &avs[i].storage); @@ -4152,9 +3865,9 @@ static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, CfreeCgCallAttrs attrs) { CGTarget* T; - const Type* fty; + CfreeCgTypeId fty; const ABIFuncInfo* abi; - const Type* ret_ty; + CfreeCgTypeId ret_ty; int has_result; CGABIValue* avs; CGCallDesc desc; @@ -4165,9 +3878,9 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, T = g->target; fty = api_sym_type(g, sym); if (!fty) return; - abi = abi_func_info(g->c->abi, fty); - ret_ty = fty->fn.ret; - has_result = !tail && ret_ty && ret_ty->kind != TY_VOID; + abi = abi_cg_func_info(g->c->abi, fty); + ret_ty = cg_type_func_ret_id(g->c, fty); + has_result = !tail && !cg_type_is_void(g->c, ret_ty); if (g->sp < nargs) { compiler_panic(g->c, g->cur_loc, "CfreeCg: call stack underflow"); return; @@ -4183,23 +3896,24 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, u32 idx = nargs - 1u - i; ApiSValue arg = api_pop(g); int is_vararg = (idx >= abi->nparams); - const Type* aty; + CfreeCgTypeId aty; api_ensure_reg(g, &arg); aty = is_vararg ? (arg.type ? arg.type : api_sv_type(&arg)) - : (fty->fn.params ? fty->fn.params[idx] : arg.type); + : cg_type_func_param_id(g->c, fty, idx); + if (!aty) aty = arg.type; avs[idx].type = aty; avs[idx].abi = is_vararg ? NULL : &abi->params[idx]; - if (aty && (aty->kind == TY_STRUCT || aty->kind == TY_UNION)) { + if (cg_type_is_aggregate(g->c, aty)) { Operand st = arg.op; st.type = aty; avs[idx].storage = st; - avs[idx].size = abi_sizeof(g->c->abi, aty); + avs[idx].size = abi_cg_sizeof(g->c->abi, aty); } else { avs[idx].storage = api_is_lvalue_sv(&arg) ? api_force_reg(g, &arg, aty) : arg.op; } } - callee_op = api_op_global((ObjSymId)sym, 0, type_ptr(g->c->global, fty)); + callee_op = api_op_global((ObjSymId)sym, 0, cg_type_ptr_to(g->c, fty)); memset(&desc, 0, sizeof desc); desc.fn_type = fty; desc.abi = abi; @@ -4210,13 +3924,13 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, desc.ret.type = ret_ty; desc.ret.abi = &abi->ret; if (has_result) { - if (ret_ty->kind == TY_STRUCT || ret_ty->kind == TY_UNION) { + if (cg_type_is_aggregate(g->c, ret_ty)) { FrameSlotDesc fsd; FrameSlot ret_slot; memset(&fsd, 0, sizeof fsd); fsd.type = ret_ty; - fsd.size = abi_sizeof(g->c->abi, ret_ty); - fsd.align = abi_alignof(g->c->abi, ret_ty); + fsd.size = abi_cg_sizeof(g->c->abi, ret_ty); + fsd.align = abi_cg_alignof(g->c->abi, ret_ty); fsd.kind = FS_LOCAL; fsd.flags = FSF_ADDR_TAKEN; ret_slot = T->frame_slot(T, &fsd); @@ -4226,7 +3940,7 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, desc.ret.storage = api_op_reg(r, ret_ty); } } else { - desc.ret.storage = api_op_imm(0, type_void(g->c->global)); + desc.ret.storage = api_op_imm(0, builtin_id(CFREE_CG_BUILTIN_VOID)); } T->call(T, &desc); for (u32 i = 0; i < nargs; ++i) { @@ -4253,13 +3967,13 @@ void cfree_cg_call_symbol(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, void cfree_cg_ret(CfreeCg* g) { ApiSValue v; CGTarget* T; - const Type* rty; + CfreeCgTypeId rty; CGABIValue av; Operand ret_op; if (!g) return; T = g->target; rty = g->fn_ret_type; - if (!rty || rty->kind == TY_VOID) { + if (cg_type_is_void(g->c, rty)) { T->ret(T, NULL); return; } @@ -4267,11 +3981,11 @@ void cfree_cg_ret(CfreeCg* g) { memset(&av, 0, sizeof av); av.type = rty; av.abi = &g->fn_abi->ret; - int is_aggregate = rty->kind == TY_STRUCT || rty->kind == TY_UNION; + int is_aggregate = cg_type_is_aggregate(g->c, rty); if (is_aggregate) { av.storage = v.op; av.storage.type = rty; - av.size = abi_sizeof(g->c->abi, rty); + av.size = abi_cg_sizeof(g->c->abi, rty); T->ret(T, &av); return; } @@ -4295,7 +4009,7 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, Compiler* c; ObjBuilder* ob; ObjSymId sym; - const Type* ty; + CfreeCgTypeId ty; u32 align; SecKind sec_kind; u16 sec_flags; @@ -4400,7 +4114,7 @@ void cfree_cg_data_pad(CfreeCg* g, uint64_t size, uint8_t value) { } void cfree_cg_data_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { - const Type* ty; + CfreeCgTypeId ty; u32 size; u8 bytes[8]; if (!g) return; @@ -4416,7 +4130,7 @@ void cfree_cg_data_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { } void cfree_cg_data_float(CfreeCg* g, double value, CfreeCgTypeId type) { - const Type* ty; + CfreeCgTypeId ty; union { float f; double d; @@ -4425,7 +4139,7 @@ void cfree_cg_data_float(CfreeCg* g, double value, CfreeCgTypeId type) { if (!g) return; ty = resolve_type(g->c, type); if (!ty) return; - if (ty->kind == TY_FLOAT) { + if (ty == builtin_id(CFREE_CG_BUILTIN_F32)) { u.f = (float)value; if (g->c->target.big_endian) { u8 t = u.b[0]; @@ -4436,7 +4150,7 @@ void cfree_cg_data_float(CfreeCg* g, double value, CfreeCgTypeId type) { u.b[2] = t; } cfree_cg_data_bytes(g, u.b, 4); - } else if (ty->kind == TY_DOUBLE) { + } else if (ty == builtin_id(CFREE_CG_BUILTIN_F64)) { u.d = value; if (g->c->target.big_endian) { for (u32 i = 0; i < 4; ++i) { diff --git a/src/api/cg_api.h b/src/api/cg_api.h @@ -5,7 +5,6 @@ #include "api/cg_type.h" #include "core/core.h" -#include "type/type.h" typedef struct CGTarget CGTarget; typedef struct MCEmitter MCEmitter; @@ -19,20 +18,6 @@ enum { CG_API_TYPE_USER_SEG_BIAS = 2u, }; -const Type* cg_api_type_resolve(Compiler*, CfreeCgTypeId); -CfreeCgTypeId cg_api_type_import(Compiler*, const Type*); -Compiler* cfree_cg_internal_compiler(CfreeCg*); -CGTarget* cfree_cg_internal_target(CfreeCg*); -MCEmitter* cfree_cg_internal_mc(CfreeCg*); -const Type* cfree_cg_internal_top_type(CfreeCg*); -const Type* cfree_cg_internal_top2_type(CfreeCg*); -void cfree_cg_internal_retag_top(CfreeCg*, const Type*); -void cfree_cg_internal_push_local_typed(CfreeCg*, CfreeCgSlot, const Type*); -void cfree_cg_internal_bind_sym(CfreeCg*, ObjSymId, const Type*, - CfreeCgDeclKind); -void cfree_cg_internal_param_slot_existing(CfreeCg*, uint32_t index, - CfreeCgSlot slot, - const Type* type, CfreeSym name); void cg_api_fini(Compiler*); #endif diff --git a/src/api/pipeline.c b/src/api/pipeline.c @@ -6,10 +6,10 @@ #include <cfree.h> -#include "../../lang/c/c.h" #include "arch/arch.h" #include "core/arena.h" #include "core/heap.h" +#include "core/pool.h" #include "link/link.h" #include "obj/obj.h" #include "parse/parse.h" @@ -41,67 +41,6 @@ static _Noreturn void panic_bad_options(Compiler* c, const char* msg) { } /* ============================================================ - * Preprocess one TU - * ============================================================ */ - -int cfree_preprocess(CfreeCompiler* c, const CfreePpOptions* pp_opts, - const CfreeBytesInput* input, CfreeWriter* out) { - PanicSave saved; - - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return 1; - } - if (!pp_opts || !input || !out) { - panic_bad_options(c, "preprocess args missing"); - } - if (!input->name) panic_bad_options(c, "input name is NULL"); - if (!input->data && input->len != 0) { - panic_bad_options(c, "input data is NULL but len > 0"); - } - - if (cfree_c_preprocess(c, pp_opts, input, out) != 0) { - compiler_panic(c, no_loc(), "C preprocessor failed for input: %s", - input->name); - } - - compiler_panic_restore(c, &saved); - return 0; -} - -/* ============================================================ - * Dump tokens (lex-only) - * ============================================================ */ - -int cfree_dump_tokens(CfreeCompiler* c, const CfreeBytesInput* input, - CfreeWriter* out) { - PanicSave saved; - - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return 1; - } - if (!input || !out) { - panic_bad_options(c, "dump_tokens args missing"); - } - if (!input->name) panic_bad_options(c, "input name is NULL"); - if (!input->data && input->len != 0) { - panic_bad_options(c, "input data is NULL but len > 0"); - } - - if (cfree_c_dump_tokens(c, input, out) != 0) { - compiler_panic(c, no_loc(), "C lexer failed for input: %s", input->name); - } - - compiler_panic_restore(c, &saved); - return 0; -} - -/* ============================================================ * Compile one TU * ============================================================ */ @@ -127,15 +66,6 @@ static void compile_into(Compiler* c, const CfreeCompileOptions* opts, return; } - if (input->lang == CFREE_LANG_C) { - if (cfree_c_compile(c, opts, input, ob) != 0) { - compiler_panic(c, no_loc(), "C frontend failed for input: %s", - input->name); - } - obj_finalize(ob); - return; - } - lex = lex_open_mem(c, input->name, (const char*)input->data, input->len); mc = mc_new(c, ob); diff --git a/src/api/stubs.c b/src/api/stubs.c @@ -16,12 +16,9 @@ #include "arch/arch.h" #include "debug/debug.h" -#include "decl/decl.h" -#include "lex/lex.h" #include "link/link.h" #include "obj/obj.h" #include "parse/parse.h" -#include "pp/pp.h" /* Internal panic stub used when a not-yet-implemented subsystem is invoked * with a Compiler in hand. Public-API stubs that don't have a Compiler @@ -31,10 +28,9 @@ static _Noreturn void unimplemented(Compiler* c, const char* what) { compiler_panic(c, loc, "subsystem not implemented: %s", what); } -/* Preprocessor implementation lives in src/pp/pp.c. */ +/* C preprocessing is owned by the C frontend. */ -/* parse_c lives in src/parse/parse.c. parse_asm lives in - * src/parse/parse_asm.c. DeclTable lives in src/decl/decl.c. */ +/* parse_asm lives in src/parse/parse_asm.c. */ /* mc_new / mc_free live in src/arch/mc.c. * cgtarget_new / cgtarget_finalize / cgtarget_free live in src/arch/<target>.c diff --git a/src/arch/aarch64/alloc.c b/src/arch/aarch64/alloc.c @@ -51,7 +51,7 @@ AASlot* aa64_slot_get(AAImpl* a, FrameSlot fs) { * Register allocation / free * ============================================================ */ -static Reg aa_alloc_reg(CGTarget* t, RegClass cls, const Type* ty) { +static Reg aa_alloc_reg(CGTarget* t, RegClass cls, CfreeCgTypeId ty) { AAImpl* a = impl_of(t); (void)ty; if (cls == RC_INT) return regpool_alloc(&a->int_pool); diff --git a/src/arch/aarch64/emit.c b/src/arch/aarch64/emit.c @@ -9,65 +9,30 @@ extern void debug_emit_row(Debug*, ObjSecId text_section, u32 offset, SrcLoc); * Shared type / operand helpers * ============================================================ */ -int type_is_64(const Type* t) { - if (!t) return 0; - switch (t->kind) { - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_PTR: - case TY_DOUBLE: - return 1; - default: - return 0; - } +int type_is_64(CfreeCgTypeId t) { + return t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I64) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F64) || + t >= (CfreeCgTypeId)(2u << 6); } -int type_is_fp_double(const Type* t) { - return t && (t->kind == TY_DOUBLE || t->kind == TY_LDOUBLE); +int type_is_fp_double(CfreeCgTypeId t) { + return t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F64); } -int type_is_signed(const Type* t) { - if (!t) return 0; - switch (t->kind) { - case TY_CHAR: - case TY_SCHAR: - case TY_SHORT: - case TY_INT: - case TY_LONG: - case TY_LLONG: - return 1; - default: - return 0; - } +int type_is_signed(CfreeCgTypeId t) { + (void)t; + return 0; } -u32 type_byte_size(const Type* t) { - if (!t) return 4; - switch (t->kind) { - case TY_CHAR: - case TY_SCHAR: - case TY_UCHAR: - case TY_BOOL: - return 1; - case TY_SHORT: - case TY_USHORT: - return 2; - case TY_INT: - case TY_UINT: - case TY_FLOAT: - return 4; - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_PTR: - case TY_DOUBLE: - return 8; - default: - return 8; - } +u32 type_byte_size(CfreeCgTypeId t) { + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I8) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_BOOL)) + return 1; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) return 2; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I32) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F32)) + return 4; + return 8; } u32 size_idx_for_bytes(u32 nbytes) { @@ -205,7 +170,7 @@ void aa_func_begin(CGTarget* t, const CGFuncDesc* fd) { if (a->has_sret) { FrameSlotDesc fsd = { - .type = NULL, + .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = (SrcLoc){0, 0, 0}, .size = 8, @@ -218,7 +183,7 @@ void aa_func_begin(CGTarget* t, const CGFuncDesc* fd) { if (a->is_variadic) { FrameSlotDesc gpd = { - .type = NULL, + .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = (SrcLoc){0, 0, 0}, .size = 64, @@ -228,7 +193,7 @@ void aa_func_begin(CGTarget* t, const CGFuncDesc* fd) { }; a->gp_save_slot = aa_frame_slot(t, &gpd); FrameSlotDesc fpd = { - .type = NULL, + .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = (SrcLoc){0, 0, 0}, .size = 128, @@ -543,4 +508,3 @@ void aa64_emit_addr_adjust(MCEmitter* mc, u32 Rd, u32 base, i32 off) { aa64_emit_load_imm(mc, 1, Rd, off); aa64_emit32(mc, aa64_add(1, Rd, base, Rd)); } - diff --git a/src/arch/aarch64/internal.h b/src/arch/aarch64/internal.h @@ -9,14 +9,15 @@ #include "arch/aa64_regs.h" #include "arch/arch.h" #include "core/arena.h" +#include "core/pool.h" #include "obj/obj.h" -#include "type/type.h" /* ============================================================ * Local encoding helpers (kept here, not in aa64_isa.h). * ============================================================ */ #define AA64_NOP 0xD503201Fu +#define CG_BUILTIN_ID(k) ((CfreeCgTypeId)((1u << 6) | (u32)(k))) static inline u32 aa64_stp_x(u32 Rt, u32 Rt2, u32 Rn, i32 byte_off) { i32 sc = byte_off >> 3; @@ -305,9 +306,9 @@ void aa_alloc_vtable_init(CGTarget* t); void aa_coord_vtable_init(CGTarget* t); /* shared type helpers (defined in emit.c, used broadly) */ -int type_is_64(const Type* t); -int type_is_fp_double(const Type* t); -int type_is_signed(const Type* t); -u32 type_byte_size(const Type* t); +int type_is_64(CfreeCgTypeId t); +int type_is_fp_double(CfreeCgTypeId t); +int type_is_signed(CfreeCgTypeId t); +u32 type_byte_size(CfreeCgTypeId t); u32 size_idx_for_bytes(u32 nbytes); u32 reg_num(Operand op); diff --git a/src/arch/aarch64/ops.c b/src/arch/aarch64/ops.c @@ -1006,7 +1006,7 @@ static void aa_call(CGTarget* t, const CGCallDesc* d) { } else { aa64_emit32(mc, aa64_stur_fp(sidx, src_reg, base_reg, off)); } - } else if (rs.kind == OPK_IMM && rs.type && rs.type->kind == TY_VOID) { + } else if (rs.kind == OPK_IMM && rs.type == CG_BUILTIN_ID(CFREE_CG_BUILTIN_VOID)) { /* void return placeholder */ } else { compiler_panic(t->c, a->loc, @@ -1241,7 +1241,7 @@ static void aa_va_start_(CGTarget* t, Operand ap_op) { } static void aa_va_arg_(CGTarget* t, Operand dst, Operand ap_op, - const Type* ty) { + CfreeCgTypeId ty) { MCEmitter* mc = t->mc; u32 ap = reg_num(ap_op); int is_fp = (dst.cls == RC_FP); diff --git a/src/arch/arch.h b/src/arch/arch.h @@ -5,8 +5,6 @@ #include "core/core.h" #include "obj/obj.h" -typedef struct Type Type; - /* Forward-declared so CGTarget can carry an optional Debug* without * pulling debug/debug.h into every translation unit that includes arch.h. * Per doc/DWARF.md §3.2 the backend gets exactly one new dependency on @@ -179,7 +177,7 @@ typedef enum FrameSlotFlag { } FrameSlotFlag; typedef struct FrameSlotDesc { - const Type* type; + CfreeCgTypeId type; Sym name; SrcLoc loc; u32 size; @@ -220,7 +218,7 @@ typedef struct AliasRoot { } AliasRoot; typedef struct MemAccess { - const Type* type; /* semantic C object type accessed */ + CfreeCgTypeId type; /* codegen object type accessed */ u32 size; /* ABI byte size of this access */ u32 align; /* known byte alignment; 0 means unknown */ u16 flags; /* MemFlag */ @@ -229,21 +227,21 @@ typedef struct MemAccess { } MemAccess; typedef struct ConstBytes { - const Type* type; + CfreeCgTypeId type; const u8* bytes; /* ABI representation, little/big endian per target */ u32 size; u32 align; } ConstBytes; typedef struct AggregateAccess { - const Type* type; + CfreeCgTypeId type; u32 size; u32 align; MemAccess mem; } AggregateAccess; typedef struct BitFieldAccess { - const Type* field_type; + CfreeCgTypeId field_type; MemAccess storage; u32 storage_offset; /* byte offset from record base */ u16 bit_offset; /* target-endian bit offset within storage unit */ @@ -256,7 +254,7 @@ typedef struct Operand { u8 kind; u8 cls; /* RegClass */ u16 pad; - const Type* type; + CfreeCgTypeId type; union { i64 imm; Reg reg; @@ -289,7 +287,7 @@ typedef struct CGABIPart { } CGABIPart; typedef struct CGABIValue { - const Type* type; + CfreeCgTypeId type; const ABIArgInfo* abi; Operand storage; /* address for indirect/byval/sret, REG/IMM for simple values */ @@ -304,7 +302,7 @@ typedef struct CGABIValue { typedef struct CGParamDesc { u32 index; Sym name; - const Type* type; + CfreeCgTypeId type; FrameSlot slot; const ABIArgInfo* abi; const CGABIPart* incoming; @@ -330,7 +328,7 @@ typedef struct CGFuncDesc { ObjSymId sym; ObjSecId text_section_id; ObjGroupId group_id; /* OBJ_GROUP_NONE if none */ - const Type* fn_type; + CfreeCgTypeId fn_type; const ABIFuncInfo* abi; const CGParamDesc* params; u32 nparams; @@ -349,7 +347,7 @@ typedef enum CGCallFlag { } CGCallFlag; typedef struct CGCallDesc { - const Type* fn_type; + CfreeCgTypeId fn_type; const ABIFuncInfo* abi; Operand callee; const CGABIValue* args; @@ -379,7 +377,7 @@ typedef struct CGScopeDesc { Label continue_label; /* explicit target for continue; LABEL_NONE for non-loops */ Operand cond; /* SCOPE_IF condition; ignored otherwise */ - const Type* result_type; /* reserved for structured expression results */ + CfreeCgTypeId result_type; /* reserved for structured expression results */ } CGScopeDesc; typedef enum AsmDir { ASM_IN, ASM_OUT, ASM_INOUT } AsmDir; @@ -387,7 +385,7 @@ typedef enum AsmDir { ASM_IN, ASM_OUT, ASM_INOUT } AsmDir; typedef struct AsmConstraint { const char* str; /* GCC-style: "r", "=&r", "+m", "i", "0" ... */ Sym name; /* GCC `[name]` symbolic operand; 0 if absent */ - const Type* type; /* C type of the bound expression (output lvalue or + CfreeCgTypeId type; /* codegen type of the bound expression (output lvalue or input rvalue). Drives RegClass + width for the binder. NULL only for hand-built test constraints (binder falls back to a 64-bit int default). */ @@ -453,7 +451,7 @@ struct MCEmitter { typedef struct CGTarget CGTarget; struct CGTarget { - /* Typed C/IR lowering context. Subclasses extend. */ + /* Typed IR lowering context. Subclasses extend. */ Compiler* c; ObjBuilder* obj; MCEmitter* mc; @@ -475,7 +473,7 @@ struct CGTarget { * values must be spilled/reloaded across register pressure, calls, and asm. * Real targets return physical scratch registers and implement spill/reload * mechanics; opt_cgtarget returns fresh virtual regs and ignores spills. */ - Reg (*alloc_reg)(CGTarget*, RegClass, const Type*); + Reg (*alloc_reg)(CGTarget*, RegClass, CfreeCgTypeId); void (*free_reg)(CGTarget*, Reg, RegClass); /* hint; opt_cgtarget ignores */ FrameSlot (*frame_slot)(CGTarget*, const FrameSlotDesc*); void (*param)(CGTarget*, const CGParamDesc*); @@ -600,7 +598,7 @@ struct CGTarget { * area, on WASM the backend walks the spilled-args memory. */ void (*va_start_)(CGTarget*, Operand ap_addr); void (*va_arg_)(CGTarget*, Operand dst /*REG*/, Operand ap_addr, - const Type* t); + CfreeCgTypeId t); void (*va_end_)(CGTarget*, Operand ap_addr); void (*va_copy_)(CGTarget*, Operand dst_ap_addr, Operand src_ap_addr); diff --git a/src/arch/rv64/alloc.c b/src/arch/rv64/alloc.c @@ -4,7 +4,7 @@ /* ---- regs / frame ---- */ -Reg rv_alloc_reg(CGTarget* t, RegClass cls, const Type* ty) { +Reg rv_alloc_reg(CGTarget* t, RegClass cls, CfreeCgTypeId ty) { RImpl* a = impl_of(t); (void)ty; if (cls == RC_INT) return regpool_alloc(&a->int_pool); diff --git a/src/arch/rv64/emit.c b/src/arch/rv64/emit.c @@ -134,7 +134,7 @@ void rv_func_begin(CGTarget* t, const CGFuncDesc* fd) { * prologue once the slot offset is known. */ if (a->has_sret) { FrameSlotDesc fsd = { - .type = NULL, + .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = (SrcLoc){0, 0, 0}, .size = 8, diff --git a/src/arch/rv64/internal.h b/src/arch/rv64/internal.h @@ -8,8 +8,8 @@ #include "arch/rv64.h" #include "arch/rv64_isa.h" #include "core/arena.h" +#include "core/pool.h" #include "obj/obj.h" -#include "type/type.h" #define RV_PROLOGUE_WORDS 32u @@ -87,62 +87,28 @@ typedef struct RImpl { static inline RImpl* impl_of(CGTarget* t) { return (RImpl*)t; } /* ---- type helpers ---- */ -static inline int type_is_64(const Type* t) { - if (!t) return 0; - switch (t->kind) { - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_PTR: - case TY_DOUBLE: - return 1; - default: - return 0; - } +#define CG_BUILTIN_ID(k) ((CfreeCgTypeId)((1u << 6) | (u32)(k))) +static inline int type_is_64(CfreeCgTypeId t) { + return t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I64) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F64) || + t >= (CfreeCgTypeId)(2u << 6); } -static inline int type_is_fp_double(const Type* t) { - return t && (t->kind == TY_DOUBLE || t->kind == TY_LDOUBLE); +static inline int type_is_fp_double(CfreeCgTypeId t) { + return t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F64); } -static inline u32 type_byte_size(const Type* t) { - if (!t) return 4; - switch (t->kind) { - case TY_CHAR: - case TY_SCHAR: - case TY_UCHAR: - case TY_BOOL: - return 1; - case TY_SHORT: - case TY_USHORT: - return 2; - case TY_INT: - case TY_UINT: - case TY_FLOAT: - return 4; - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_PTR: - case TY_DOUBLE: - return 8; - default: - return 8; - } +static inline u32 type_byte_size(CfreeCgTypeId t) { + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I8) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_BOOL)) + return 1; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) return 2; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I32) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F32)) + return 4; + return 8; } -static inline int type_is_signed(const Type* t) { - if (!t) return 0; - switch (t->kind) { - case TY_CHAR: - case TY_SCHAR: - case TY_SHORT: - case TY_INT: - case TY_LONG: - case TY_LLONG: - return 1; - default: - return 0; - } +static inline int type_is_signed(CfreeCgTypeId t) { + (void)t; + return 0; } static inline u32 reg_num(Operand op) { return op.v.reg & 0x1fu; } @@ -189,7 +155,7 @@ void emit_sp_addi(MCEmitter* mc, i64 imm); _Noreturn void rv_panic(CGTarget* t, const char* what); /* ---- alloc.c: all functions (non-static; referenced by ops.c vtable) ---- */ -Reg rv_alloc_reg(CGTarget* t, RegClass cls, const Type* ty); +Reg rv_alloc_reg(CGTarget* t, RegClass cls, CfreeCgTypeId ty); void rv_free_reg(CGTarget* t, Reg r, RegClass cls); FrameSlot rv_frame_slot(CGTarget* t, const FrameSlotDesc* d); RvSlot* rv64_slot_get(RImpl* a, FrameSlot fs); diff --git a/src/arch/rv64/ops.c b/src/arch/rv64/ops.c @@ -997,7 +997,7 @@ static void rv_call(CGTarget* t, const CGCallDesc* d) { if (p->size == 8) rv64_emit32(mc, rv_fsd(src_reg, base_reg, off)); else rv64_emit32(mc, rv_fsw(src_reg, base_reg, off)); } - } else if (rs.kind == OPK_IMM && rs.type && rs.type->kind == TY_VOID) { + } else if (rs.kind == OPK_IMM && rs.type == CG_BUILTIN_ID(CFREE_CG_BUILTIN_VOID)) { /* void return placeholder — nothing to do. */ } else { compiler_panic(t->c, a->loc, "rv64 call: ret_storage kind %d unsupported", @@ -1179,7 +1179,7 @@ static void rv_va_start_(CGTarget* t, Operand ap_op) { } static void rv_va_arg_(CGTarget* t, Operand dst, Operand ap_op, - const Type* ty) { + CfreeCgTypeId ty) { MCEmitter* mc = t->mc; u32 ap = reg_num(ap_op); u32 sz = type_byte_size(ty); diff --git a/src/arch/x64/alloc.c b/src/arch/x64/alloc.c @@ -13,7 +13,6 @@ #include "core/arena.h" #include "core/pool.h" #include "obj/obj.h" -#include "type/type.h" #include "arch/x64/internal.h" @@ -51,7 +50,7 @@ static int xpool_free(XRegPool* p, Reg r) { /* ============================================================ * Registers / frame */ -Reg x_alloc_reg(CGTarget* t, RegClass cls, const Type* ty) { +Reg x_alloc_reg(CGTarget* t, RegClass cls, CfreeCgTypeId ty) { XImpl* a = impl_of(t); (void)ty; if (cls == RC_INT) return xpool_alloc(&a->int_pool); diff --git a/src/arch/x64/emit.c b/src/arch/x64/emit.c @@ -12,7 +12,6 @@ #include "core/arena.h" #include "core/pool.h" #include "obj/obj.h" -#include "type/type.h" #include "arch/x64/internal.h" @@ -498,7 +497,7 @@ void x_func_begin(CGTarget* t, const CGFuncDesc* fd) { * hidden slot so the body can use rdi freely. */ if (a->has_sret) { FrameSlotDesc fsd = { - .type = NULL, .name = 0, .loc = {0, 0, 0}, + .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = {0, 0, 0}, .size = 8, .align = 8, .kind = FS_SPILL, .flags = 0, }; a->sret_ptr_slot = x_frame_slot(t, &fsd); @@ -512,7 +511,7 @@ void x_func_begin(CGTarget* t, const CGFuncDesc* fd) { * args are preserved before x_param() spills the named ones. */ if (a->is_variadic) { FrameSlotDesc rsd = { - .type = NULL, .name = 0, .loc = {0, 0, 0}, + .type = CFREE_CG_TYPE_NONE, .name = 0, .loc = {0, 0, 0}, .size = 176, .align = 8, .kind = FS_SPILL, .flags = 0, }; a->reg_save_slot = x_frame_slot(t, &rsd); diff --git a/src/arch/x64/internal.h b/src/arch/x64/internal.h @@ -18,7 +18,6 @@ #include "core/arena.h" #include "core/pool.h" #include "obj/obj.h" -#include "type/type.h" #define X64_PROLOGUE_BYTES 96u @@ -106,62 +105,28 @@ extern void debug_emit_row(Debug*, ObjSecId text_section, u32 offset, SrcLoc); /* ============================================================ * Type helpers (static inline — used in all three translation units). */ -static inline int type_is_64(const Type* t) { - if (!t) return 0; - switch (t->kind) { - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_PTR: - case TY_DOUBLE: - return 1; - default: - return 0; - } +#define CG_BUILTIN_ID(k) ((CfreeCgTypeId)((1u << 6) | (u32)(k))) +static inline int type_is_64(CfreeCgTypeId t) { + return t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I64) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F64) || + t >= (CfreeCgTypeId)(2u << 6); } -static inline int type_is_fp_double(const Type* t) { - return t && (t->kind == TY_DOUBLE || t->kind == TY_LDOUBLE); +static inline int type_is_fp_double(CfreeCgTypeId t) { + return t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F64); } -static inline u32 type_byte_size(const Type* t) { - if (!t) return 4; - switch (t->kind) { - case TY_CHAR: - case TY_SCHAR: - case TY_UCHAR: - case TY_BOOL: - return 1; - case TY_SHORT: - case TY_USHORT: - return 2; - case TY_INT: - case TY_UINT: - case TY_FLOAT: - return 4; - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_PTR: - case TY_DOUBLE: - return 8; - default: - return 8; - } +static inline u32 type_byte_size(CfreeCgTypeId t) { + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I8) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_BOOL)) + return 1; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I16)) return 2; + if (t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_I32) || + t == CG_BUILTIN_ID(CFREE_CG_BUILTIN_F32)) + return 4; + return 8; } -static inline int type_is_signed(const Type* t) { - if (!t) return 0; - switch (t->kind) { - case TY_CHAR: - case TY_SCHAR: - case TY_SHORT: - case TY_INT: - case TY_LONG: - case TY_LLONG: - return 1; - default: - return 0; - } +static inline int type_is_signed(CfreeCgTypeId t) { + (void)t; + return 0; } static inline _Noreturn void x_panic(CGTarget* t, const char* what) { @@ -234,7 +199,7 @@ void emit_sse_rr_w(MCEmitter* mc, u8 prefix, u8 opcode, int w, u32 dst, void xpool_init(XRegPool* p, const u8* order, u8 nregs, u8 n_cs); XSlot* x64_slot_get(XImpl* a, FrameSlot fs); FrameSlot x_frame_slot(CGTarget* t, const FrameSlotDesc* d); -Reg x_alloc_reg(CGTarget* t, RegClass cls, const Type* ty); +Reg x_alloc_reg(CGTarget* t, RegClass cls, CfreeCgTypeId ty); void x_free_reg(CGTarget* t, Reg r, RegClass cls); void x_param(CGTarget* t, const CGParamDesc* p); void x_spill_reg(CGTarget* t, Operand src, FrameSlot slot, MemAccess ma); diff --git a/src/arch/x64/ops.c b/src/arch/x64/ops.c @@ -18,7 +18,6 @@ #include "core/arena.h" #include "core/pool.h" #include "obj/obj.h" -#include "type/type.h" #include "arch/x64/internal.h" @@ -931,7 +930,7 @@ static void x_call(CGTarget* t, const CGCallDesc* d) { u8 prefix2 = (p->size == 8) ? 0xF2 : 0xF3; emit_sse_store(mc, prefix2, 0x11, src_reg, base_reg, off); } - } else if (rs.kind == OPK_IMM && rs.type && rs.type->kind == TY_VOID) { + } else if (rs.kind == OPK_IMM && rs.type == CG_BUILTIN_ID(CFREE_CG_BUILTIN_VOID)) { /* void ret placeholder — nothing to do. */ } else { compiler_panic(t->c, a->loc, @@ -1167,7 +1166,7 @@ static void x_va_start_(CGTarget* t, Operand ap_op) { } static void x_va_arg_(CGTarget* t, Operand dst, Operand ap_op, - const Type* ty) { + CfreeCgTypeId ty) { MCEmitter* mc = t->mc; u32 ap = ap_op.v.reg & 0xFu; u32 sz = type_byte_size(ty); diff --git a/src/core/pool.c b/src/core/pool.c @@ -1,11 +1,8 @@ -/* Interned strings + types. Open-addressed hash table keyed by FNV-1a +/* Interned strings. Open-addressed hash table keyed by FNV-1a * over the string body; the table holds Sym ids that index into a * heap-allocated `entries` array. Strings live in a per-Pool arena * (block-allocated), so str_data pointers are stable for the Pool's - * lifetime. - * - * pool_type is left as a panic stub: types come online with the parser, - * which isn't part of the foundation work that gates ELF support. */ + * lifetime. */ #include "core/pool.h" @@ -150,13 +147,3 @@ const char* pool_str(Pool* p, Sym sym, size_t* len_out) { if (len_out) *len_out = p->entries[sym].len; return p->entries[sym].data; } - -const Type* pool_type(Pool* p, const Type* tmpl) { - /* Type interning is the parser/typer's province; not used by the - * obj+ELF foundation. Keep the API present so callers that don't - * exercise the type table still link, but treat actual use as a - * loud bug. */ - (void)p; - (void)tmpl; - return NULL; -} diff --git a/src/core/pool.h b/src/core/pool.h @@ -5,8 +5,6 @@ #include "core/core.h" #include "core/heap.h" -typedef struct Type Type; /* declared in src/type/type.h */ - typedef struct PoolEntry { const char* data; u32 len; @@ -15,7 +13,7 @@ typedef struct PoolEntry { struct Pool { Heap* heap; - Arena arena; /* string and type-template storage */ + Arena arena; /* string storage */ /* Hash table: 0 means empty. Otherwise it's a Sym id (1-based). */ Sym* table; @@ -27,8 +25,7 @@ struct Pool { u32 nentries; u32 entries_cap; - /* Lazily-initialized type interning cache (defined in src/type/type.c). - * Opaque to other consumers; type.c casts as needed. */ + /* Frontends may hang language-specific interning state here. */ void* type_cache; }; @@ -40,9 +37,4 @@ Sym pool_intern(Pool*, const char* s, size_t len); Sym pool_intern_cstr(Pool*, const char* s); const char* pool_str(Pool*, Sym, size_t* len_out); -/* Types. Caller fills a stack-allocated Type template; pool returns the - * canonical pointer (allocating into the pool the first time). Equal types → - * equal pointers. */ -const Type* pool_type(Pool*, const Type* tmpl); - #endif diff --git a/src/debug/c_debug.c b/src/debug/c_debug.c @@ -1,251 +0,0 @@ -/* C-type → DebugTypeId adapter. - * - * Walks the C `Type*` chain, calling debug_type_* on the language-neutral - * Debug surface and caching the result keyed by Type* identity. - * - * Identity contract (see c_debug.h): the cache is per-Debug; equal Type* - * (canonical pool pointer) → equal DebugTypeId. Recursive shapes (a - * struct containing a pointer to itself) work because: - * - We allocate the record DIE id first via debug_type_record_begin / - * end and store the id in the cache *before* descending into fields. - * Cyclic references through a pointer get a fresh ptr-DIE that points - * back to the (now-known) record id. - * - Direct cycles (a struct containing itself by value) are illegal in - * C anyway. */ - -#include "debug/c_debug.h" - -#include <string.h> - -#include "core/core.h" -#include "core/heap.h" -#include "core/pool.h" -#include "core/vec.h" -#include "debug/debug.h" -#include "debug/debug_internal.h" - -/* Cache: Type* → DebugTypeId. - * - * We attach the cache to the Debug instance via a void* slot. Since - * DebugTypeId is u32 and we use a u64-keyed hashmap (PtrToU32 from the - * internal header), the cache survives the lifetime of one Debug. - * - * The cache is created lazily on first lookup so producers that don't - * use c_debug_type pay nothing. */ - -typedef struct CDebugCache { - PtrToU32 map; /* (u64)(uintptr_t)Type* → DebugTypeId */ -} CDebugCache; - -/* The Debug struct doesn't have a slot for the cache. Rather than - * touching debug.h, we keep a single (Debug* → cache) tiny association - * list. In practice exactly one Debug exists per TU; this list rarely - * grows past 1. */ - -typedef struct CDebugCacheEntry { - Debug* d; - CDebugCache* cache; -} CDebugCacheEntry; - -static CDebugCacheEntry* g_caches = NULL; -static u32 g_caches_n = 0; -static u32 g_caches_cap = 0; - -static CDebugCache* cache_for(Debug* d) { - u32 i; - Heap* h; - for (i = 0; i < g_caches_n; ++i) { - if (g_caches[i].d == d) return g_caches[i].cache; - } - h = (Heap*)d->c->env->heap; - if (VEC_GROW(h, g_caches, g_caches_cap, g_caches_n + 1)) return NULL; - { - CDebugCacheEntry* slot = &g_caches[g_caches_n++]; - slot->d = d; - slot->cache = - (CDebugCache*)h->alloc(h, sizeof(CDebugCache), _Alignof(CDebugCache)); - if (!slot->cache) { - g_caches_n--; - return NULL; - } - PtrToU32_init(&slot->cache->map, h); - return slot->cache; - } -} - -static DebugTypeId cache_get(CDebugCache* c, const Type* t) { - u32* v = PtrToU32_get(&c->map, (u64)(uintptr_t)t); - return v ? *v : DEBUG_TYPE_NONE; -} - -static void cache_put(CDebugCache* c, const Type* t, DebugTypeId id) { - PtrToU32_set(&c->map, (u64)(uintptr_t)t, id); -} - -/* ---- recursive type walk ---- */ - -static DebugTypeId walk(Debug* d, TargetABI* abi, const Type* t, - CDebugCache* cache); - -static Sym intern_cstr(Debug* d, const char* s) { - return pool_intern_cstr(d->c->global, s); -} - -static DebugTypeId base_id(Debug* d, TargetABI* abi, const Type* t, - const char* name, DebugBaseEncoding enc) { - return debug_type_base(d, intern_cstr(d, name), enc, abi_sizeof(abi, t)); -} - -static DebugTypeId walk_unqual(Debug* d, TargetABI* abi, const Type* t, - CDebugCache* cache) { - switch ((TypeKind)t->kind) { - case TY_VOID: - return debug_type_void(d); - case TY_BOOL: - return base_id(d, abi, t, "_Bool", DEBUG_BE_BOOL); - case TY_CHAR: - return base_id(d, abi, t, "char", DEBUG_BE_SIGNED_CHAR); - case TY_SCHAR: - return base_id(d, abi, t, "signed char", DEBUG_BE_SIGNED_CHAR); - case TY_UCHAR: - return base_id(d, abi, t, "unsigned char", DEBUG_BE_UNSIGNED_CHAR); - case TY_SHORT: - return base_id(d, abi, t, "short", DEBUG_BE_SIGNED); - case TY_USHORT: - return base_id(d, abi, t, "unsigned short", DEBUG_BE_UNSIGNED); - case TY_INT: - return base_id(d, abi, t, "int", DEBUG_BE_SIGNED); - case TY_UINT: - return base_id(d, abi, t, "unsigned int", DEBUG_BE_UNSIGNED); - case TY_LONG: - return base_id(d, abi, t, "long", DEBUG_BE_SIGNED); - case TY_ULONG: - return base_id(d, abi, t, "unsigned long", DEBUG_BE_UNSIGNED); - case TY_LLONG: - return base_id(d, abi, t, "long long", DEBUG_BE_SIGNED); - case TY_ULLONG: - return base_id(d, abi, t, "unsigned long long", DEBUG_BE_UNSIGNED); - case TY_INT128: - return base_id(d, abi, t, "__int128", DEBUG_BE_SIGNED); - case TY_UINT128: - return base_id(d, abi, t, "unsigned __int128", DEBUG_BE_UNSIGNED); - case TY_FLOAT: - return base_id(d, abi, t, "float", DEBUG_BE_FLOAT); - case TY_DOUBLE: - return base_id(d, abi, t, "double", DEBUG_BE_FLOAT); - case TY_LDOUBLE: - return base_id(d, abi, t, "long double", DEBUG_BE_FLOAT); - case TY_PTR: { - DebugTypeId pointee = walk(d, abi, t->ptr.pointee, cache); - return debug_type_ptr(d, pointee); - } - case TY_ARRAY: { - DebugTypeId elem = walk(d, abi, t->arr.elem, cache); - return debug_type_array(d, elem, t->arr.incomplete ? 0 : t->arr.count); - } - case TY_FUNC: { - DebugTypeId ret = walk(d, abi, t->fn.ret, cache); - DebugTypeId* params = NULL; - DebugTypeId result; - u32 i; - Heap* h = (Heap*)d->c->env->heap; - if (t->fn.nparams) { - params = (DebugTypeId*)h->alloc(h, sizeof(DebugTypeId) * t->fn.nparams, - _Alignof(DebugTypeId)); - if (!params) return DEBUG_TYPE_NONE; - for (i = 0; i < t->fn.nparams; ++i) { - params[i] = walk(d, abi, t->fn.params[i], cache); - } - } - result = debug_type_func(d, ret, params, t->fn.nparams, t->fn.variadic); - if (params) h->free(h, params, sizeof(DebugTypeId) * t->fn.nparams); - return result; - } - case TY_STRUCT: - case TY_UNION: { - const ABIRecordLayout* layout; - DebugTypeBuilder* b; - DebugTypeId id; - u32 i; - if (t->rec.incomplete) { - /* Emit an opaque record: zero size, no fields. */ - b = debug_type_record_begin(d, t->rec.tag, t->kind == TY_UNION, 0, 0); - return debug_type_record_end(b); - } - layout = abi_record_layout(abi, t); - b = debug_type_record_begin(d, t->rec.tag, t->kind == TY_UNION, - layout ? layout->size : 0, - layout ? layout->align : 0); - /* Pre-publish the cache entry pointing at the in-progress builder - * id so cycles via pointer fields resolve. We don't have a builder - * id yet; allocate one early via the record_end-then-walk strategy - * is safer. To keep things simple here, we cache after end_record. - * Self-referential pointers must therefore be expressed via a - * `Type*` that points to a *forward-declared* incomplete record - * (handled above), then refined later. For now no test path hits - * this. */ - for (i = 0; i < t->rec.nfields; ++i) { - const Field* f = &t->rec.fields[i]; - DebugTypeId ftype = walk(d, abi, f->type, cache); - u32 byte_ofs = layout ? layout->fields[i].offset : 0; - if (f->flags & FIELD_BITFIELD) { - u16 bit_ofs = layout ? layout->fields[i].bit_offset : 0; - debug_type_record_bitfield(b, f->name, ftype, byte_ofs, bit_ofs, - f->bitfield_width); - } else { - debug_type_record_field(b, f->name, ftype, byte_ofs); - } - } - id = debug_type_record_end(b); - return id; - } - case TY_ENUM: { - DebugTypeId base = walk(d, abi, t->enm.base, cache); - DebugEnumBuilder* b = debug_type_enum_begin(d, t->enm.tag, base); - /* Type doesn't carry enum members directly; we'd need a registry - * lookup keyed by tag_id. Leave empty — consumers see an enum - * with no enumerators. */ - return debug_type_enum_end(b); - } - } - return DEBUG_TYPE_NONE; -} - -static DebugTypeId walk(Debug* d, TargetABI* abi, const Type* t, - CDebugCache* cache) { - DebugTypeId cached; - DebugTypeId base_id_; - DebugTypeId result; - if (!t) return DEBUG_TYPE_NONE; - cached = cache_get(cache, t); - if (cached != DEBUG_TYPE_NONE) return cached; - - /* Strip and re-apply qualifiers. The unqualified type goes into the - * pool as one DIE; const/volatile/restrict layer DIEs around it. */ - if (t->qual) { - /* Build the unqualified core, then layer qualifiers. We can't simply - * re-pool a Type with qual=0 because we don't have a pool here. - * Instead walk fields directly and synthesize. */ - /* Synthesize unqualified DIE from the same shape. We construct a - * shallow Type with qual=0 and recurse via walk_unqual. */ - Type tmp = *t; - tmp.qual = 0; - base_id_ = walk_unqual(d, abi, &tmp, cache); - result = base_id_; - if (t->qual & Q_CONST) result = debug_type_const(d, result); - if (t->qual & Q_VOLATILE) result = debug_type_volatile(d, result); - if (t->qual & Q_RESTRICT) result = debug_type_restrict(d, result); - } else { - result = walk_unqual(d, abi, t, cache); - } - cache_put(cache, t, result); - return result; -} - -DebugTypeId c_debug_type(Debug* d, TargetABI* abi, const Type* t) { - CDebugCache* cache; - if (!d || !t) return DEBUG_TYPE_NONE; - cache = cache_for(d); - if (!cache) return DEBUG_TYPE_NONE; - return walk(d, abi, t, cache); -} diff --git a/src/debug/debug.h b/src/debug/debug.h @@ -11,17 +11,14 @@ * Type DIEs are addressed through opaque DebugTypeId handles. The core * Debug module is language-neutral: it knows about DWARF type kinds (base, * pointer, array, qualified, typedef, function, record, enum) but not - * about the C `Type` representation. C-specific walking — turning a - * `const Type*` chain into a tree of debug_type_* calls — lives in the - * c_debug adapter (src/debug/c_debug.h) and is the only consumer that - * needs to see `type/type.h`. + * about any source-language type representation. Frontends own their + * adapters and pass DebugTypeId values here. * * Producer responsibilities: * - Parser: nothing directly; types are looked up on demand from those * that reach debug_local / debug_param. - * - CG: function and scope lifecycle, parameter and local declarations. - * Resolves a `const Type*` to a DebugTypeId once via c_debug_type and - * passes the id thereafter. + * - CG: function and scope lifecycle, parameter and local declarations, + * using frontend-provided DebugTypeId values. * - MCEmitter (or the lowering pass inside opt at -O2): the line program * and pc-range bounds for functions. * - opt at -O2: location-list entries when a variable's location changes @@ -44,8 +41,7 @@ u32 debug_file(Debug*, u32 source_file_id); * "no type" (e.g. a void return without an explicit void DIE — callers * normally supply debug_type_void()). * - * The core Debug module does not intern by source-language identity; that - * is the adapter's job (c_debug.h keeps a Type* → DebugTypeId cache). + * The core Debug module does not intern by source-language identity. * Constructing the same shape twice yields two distinct ids. */ typedef u32 DebugTypeId; diff --git a/src/decl/decl.h b/src/decl/decl.h @@ -1,6 +0,0 @@ -#ifndef CFREE_SRC_DECL_COMPAT_H -#define CFREE_SRC_DECL_COMPAT_H - -#include "../../lang/c/decl/decl.h" - -#endif diff --git a/src/decl/decl_attrs.h b/src/decl/decl_attrs.h @@ -1,6 +0,0 @@ -#ifndef CFREE_SRC_DECL_ATTRS_COMPAT_H -#define CFREE_SRC_DECL_ATTRS_COMPAT_H - -#include "../../lang/c/decl/decl_attrs.h" - -#endif diff --git a/src/emu/cpu.c b/src/emu/cpu.c @@ -1,5 +1,5 @@ /* CPUState: per-thread guest register/lazy-flag/memory-base record, - * synthesized once per emu invocation as an interned C `Type*`. The + * synthesized once per emu invocation as an interned C `CfreeCgTypeId`. The * lifter references fields through a stable offset table generated * alongside the type; the runtime owns the storage and exposes its * address to the JIT linker via the extern resolver (EMU_SYM_CPU_STATE). @@ -22,7 +22,7 @@ struct EmuCPUState { EmuTrapReason trap; int exit_code; /* Per-arch register / lazy-flag fields land alongside the synthesized - * Type*; the runtime helpers (emu_mem_*, emu_syscall) reach them + * CfreeCgTypeId; the runtime helpers (emu_mem_*, emu_syscall) reach them * through the canonical offsets. */ }; @@ -62,19 +62,19 @@ EmuTrapReason emu_cpu_trap_reason(const EmuCPUState* s) { int emu_cpu_exit_code(const EmuCPUState* s) { return s ? s->exit_code : 0; } -const Type* emu_cpu_type(Compiler* c, CfreeEmuArch arch) { +CfreeCgTypeId emu_cpu_type(Compiler* c, CfreeEmuArch arch) { /* Per-arch struct layout lands with the per-ISA lifter. The lifter * is a stub for now; translate_block panics before any consumer * dereferences this, so a NULL placeholder is safe. */ (void)c; (void)arch; - return NULL; + return CFREE_CG_TYPE_NONE; } -const Type* emu_block_fn_type(Compiler* c, CfreeEmuArch arch) { +CfreeCgTypeId emu_block_fn_type(Compiler* c, CfreeEmuArch arch) { /* Block ABI: u64 entry(EmuCPUState*). Materialized once the type * subsystem and per-arch CPUState type land together. */ (void)c; (void)arch; - return NULL; + return CFREE_CG_TYPE_NONE; } diff --git a/src/emu/emu.h b/src/emu/emu.h @@ -16,7 +16,6 @@ #include "core/core.h" #include "obj/obj.h" -#include "type/type.h" typedef struct LinkImage LinkImage; typedef struct Linker Linker; @@ -67,14 +66,14 @@ void emu_cpu_set_pc(EmuCPUState*, u64); EmuTrapReason emu_cpu_trap_reason(const EmuCPUState*); int emu_cpu_exit_code(const EmuCPUState*); -/* The interned C struct type representing CPUState for `arch`. The +/* The interned codegen record type representing CPUState for `arch`. The * lifter references fields through an ObjSymId resolved by the * runtime extern resolver to &CfreeEmu->cpu storage. */ -const Type* emu_cpu_type(Compiler*, CfreeEmuArch); +CfreeCgTypeId emu_cpu_type(Compiler*, CfreeEmuArch); /* The function type `u64 (CPUState*)` used for every lifted block. * Returned interned. */ -const Type* emu_block_fn_type(Compiler*, CfreeEmuArch); +CfreeCgTypeId emu_block_fn_type(Compiler*, CfreeEmuArch); /* ---- Decoder ---------------------------------------------------- */ /* Concrete shape lives here (rather than as a per-ISA opaque) so the @@ -100,8 +99,8 @@ u32 emu_decode_block(CfreeEmuArch, const u8* bytes, u64 guest_pc, EmuInst* out, typedef struct EmuLiftCtx { CfreeEmuArch arch; - const Type* cpu_state_type; /* from emu_cpu_type */ - const Type* block_fn_type; /* from emu_block_fn_type */ + CfreeCgTypeId cpu_state_type; /* from emu_cpu_type */ + CfreeCgTypeId block_fn_type; /* from emu_block_fn_type */ ObjSymId block_sym; /* function symbol for this block */ u64 guest_pc; /* PC of first instruction in the block */ } EmuLiftCtx; diff --git a/src/lex/lex.h b/src/lex/lex.h @@ -1,6 +1,114 @@ -#ifndef CFREE_SRC_LEX_COMPAT_H -#define CFREE_SRC_LEX_COMPAT_H +#ifndef CFREE_LEX_H +#define CFREE_LEX_H -#include "../../lang/c/lex/lex.h" +#include "core/core.h" + +typedef enum TokKind { + TOK_EOF = 0, + TOK_IDENT, + TOK_NUM, + TOK_FLT, + TOK_STR, + TOK_CHR, + TOK_PUNCT, + TOK_PP_HASH, + TOK_PP_PASTE, + TOK_HEADER, + TOK_NEWLINE, + TOK_KW_FIRST, + TOK_KW_LAST = 0x1000, +} TokKind; + +typedef enum TokFlag { + TF_AT_BOL = 1u << 0, + TF_HAS_SPACE = 1u << 1, + TF_NO_EXPAND = 1u << 2, + TF_INT_U = 1u << 3, + TF_INT_L = 1u << 4, + TF_INT_LL = 1u << 5, + TF_FLT_F = 1u << 6, + TF_FLT_L = 1u << 7, + TF_STR_WIDE = 1u << 8, + TF_STR_U8 = 1u << 9, + TF_STR_U16 = 1u << 10, + TF_STR_U32 = 1u << 11, + TF_LITERAL_BAD = 1u << 12, +} TokFlag; + +typedef enum Punct { + P_NONE = 0, + P_ARROW = 256, + P_INC, + P_DEC, + P_SHL, + P_SHR, + P_LE, + P_GE, + P_EQ, + P_NE, + P_AND, + P_OR, + P_ADD_ASSIGN, + P_SUB_ASSIGN, + P_MUL_ASSIGN, + P_DIV_ASSIGN, + P_MOD_ASSIGN, + P_AND_ASSIGN, + P_OR_ASSIGN, + P_XOR_ASSIGN, + P_SHL_ASSIGN, + P_SHR_ASSIGN, + P_ELLIPSIS, + P_HASH_HASH, +} Punct; + +typedef u32 LitId; +#define LIT_NONE 0u + +typedef enum LitKind { + LIT_INT, + LIT_FLOAT, + LIT_STRING, + LIT_CHAR, +} LitKind; + +typedef enum LitEnc { + LENC_ORDINARY, + LENC_UTF8, + LENC_WIDE, + LENC_UTF16, + LENC_UTF32, +} LitEnc; + +typedef struct LitInfo { + u8 kind; + u8 enc; + u16 flags; + Sym spelling; + BytesId bytes; +} LitInfo; + +typedef struct Tok { + u16 kind; + u16 flags; + SrcLoc loc; + Sym spelling; + LitId lit; + union { + Sym ident; + Sym str; + u32 punct; + } v; +} Tok; + +typedef struct Lexer Lexer; + +Lexer* lex_open_mem(Compiler*, const char* name, const char* src, size_t len); +void lex_close(Lexer*); + +Tok lex_next(Lexer*); +SrcLoc lex_loc(const Lexer*); +u32 lex_file_id(const Lexer*); +const LitInfo* lex_lit(const Lexer*, LitId); #endif diff --git a/src/opt/ir.c b/src/opt/ir.c @@ -30,12 +30,12 @@ static void val_table_grow(Func* f, u32 needed) { while (ncap < needed) ncap *= 2u; u32* nb_blk = arena_zarray(f->arena, u32, ncap); u32* nb_ins = arena_zarray(f->arena, u32, ncap); - const Type** nb_ty = arena_zarray(f->arena, const Type*, ncap); + CfreeCgTypeId* nb_ty = arena_zarray(f->arena, CfreeCgTypeId, ncap); u8* nb_cls = arena_zarray(f->arena, u8, ncap); if (f->nvals) { memcpy(nb_blk, f->val_def_block, sizeof(u32) * f->nvals); memcpy(nb_ins, f->val_def_inst, sizeof(u32) * f->nvals); - memcpy(nb_ty, f->val_type, sizeof(const Type*) * f->nvals); + memcpy(nb_ty, f->val_type, sizeof(CfreeCgTypeId) * f->nvals); memcpy(nb_cls, f->val_cls, sizeof(u8) * f->nvals); } f->val_def_block = nb_blk; @@ -45,7 +45,7 @@ static void val_table_grow(Func* f, u32 needed) { f->vals_cap = ncap; } -Val ir_alloc_val(Func* f, const Type* t, u8 cls) { +Val ir_alloc_val(Func* f, CfreeCgTypeId t, u8 cls) { Val v; if (f->nvals == 0) { val_table_grow(f, 16); diff --git a/src/opt/ir.h b/src/opt/ir.h @@ -4,7 +4,6 @@ #include "arch/arch.h" #include "core/arena.h" #include "core/core.h" -#include "type/type.h" /* SSA value id. Identical to the Reg space (doc/OPT.md §5.1): when an * Operand has kind OPK_REG, v.reg names the Val it carries. VAL_NONE=0 @@ -69,7 +68,7 @@ typedef enum IROp { /* alloca / variadics. */ IR_ALLOCA, /* opnds = [dst REG, size]; extra.imm = align */ IR_VA_START, /* opnds = [ap] */ - IR_VA_ARG, /* opnds = [dst REG, ap]; extra.aux = const Type* */ + IR_VA_ARG, /* opnds = [dst REG, ap]; extra.aux = CfreeCgTypeId*/ IR_VA_END, /* opnds = [ap] */ IR_VA_COPY, /* opnds = [dst, src] */ @@ -106,7 +105,7 @@ typedef struct IRBitFieldAux { } IRBitFieldAux; typedef struct IRGepAux { - const Type* base_type; + CfreeCgTypeId base_type; u32 nindices; i64* indices; } IRGepAux; @@ -189,7 +188,7 @@ typedef struct IRParamDeclAux { typedef struct IRFrameSlot { FrameSlot id; - const Type* type; + CfreeCgTypeId type; Sym name; SrcLoc loc; u32 size; @@ -202,7 +201,7 @@ typedef struct IRFrameSlot { typedef struct IRParam { u32 index; Sym name; - const Type* type; + CfreeCgTypeId type; FrameSlot slot; const ABIArgInfo* abi; SrcLoc loc; @@ -214,7 +213,7 @@ typedef struct Inst { u16 op; u16 flags; SrcLoc loc; /* sticky from CGTarget.set_loc at recording */ - const Type* type; + CfreeCgTypeId type; Val def; /* primary SSA def, or VAL_NONE */ u32 ndefs; /* multi-result */ Val* defs; @@ -277,7 +276,7 @@ typedef struct Func { Compiler* c; CGFuncDesc desc; /* preserved for level-1 replay func_begin */ ObjSymId name; /* alias for desc.sym (kept for older callers) */ - const Type* type; + CfreeCgTypeId type; Block* blocks; u32 nblocks, blocks_cap; u32 entry; @@ -290,7 +289,7 @@ typedef struct Func { /* Value table. Index 0 is VAL_NONE; first allocated Val is 1. */ u32* val_def_block; u32* val_def_inst; - const Type** val_type; + CfreeCgTypeId* val_type; u8* val_cls; /* RegClass per Val, used by replay to reconstruct REG operands */ u32 nvals, vals_cap; @@ -333,7 +332,7 @@ u32 ir_block_new(Func*); FrameSlot ir_frame_slot_new(Func*, const FrameSlotDesc*); void ir_param_add(Func*, const CGParamDesc*); -Val ir_alloc_val(Func*, const Type*, u8 cls); +Val ir_alloc_val(Func*, CfreeCgTypeId, u8 cls); Inst* ir_emit(Func*, u32 block, IROp); diff --git a/src/opt/opt.c b/src/opt/opt.c @@ -55,7 +55,7 @@ static Inst* rec(OptImpl* o, IROp op) { return in; } -static void set_def(Func* f, Inst* in, u32 block, Val v, const Type* t) { +static void set_def(Func* f, Inst* in, u32 block, Val v, CfreeCgTypeId t) { in->def = v; in->type = t; if (v != VAL_NONE && v < f->nvals) { @@ -115,7 +115,7 @@ static void w_func_end(CGTarget* t); /* ---- registers and frame slots ---- */ -static Reg w_alloc_reg(CGTarget* t, RegClass cls, const Type* ty) { +static Reg w_alloc_reg(CGTarget* t, RegClass cls, CfreeCgTypeId ty) { OptImpl* o = impl_of(t); Val v = ir_alloc_val(o->f, ty, (u8)cls); return (Reg)v; @@ -587,13 +587,13 @@ static void w_va_start_(CGTarget* t, Operand ap) { in->nopnds = 1; } -static void w_va_arg_(CGTarget* t, Operand dst, Operand ap, const Type* ty) { +static void w_va_arg_(CGTarget* t, Operand dst, Operand ap, CfreeCgTypeId ty) { OptImpl* o = impl_of(t); Inst* in = rec(o, IR_VA_ARG); Operand ops[2] = {dst, ap}; in->opnds = dup_opnds(o->f, ops, 2); in->nopnds = 2; - in->extra.aux = (void*)ty; + in->extra.aux = (void*)(uintptr_t)ty; if (dst.kind == OPK_REG) set_def(o->f, in, o->cur, (Val)dst.v.reg, dst.type); } @@ -1076,7 +1076,7 @@ static void replay_inst(ReplayCtx* r, u32 b, Inst* in) { case IR_VA_ARG: { Operand dst = xlat_op(r, in->opnds[0]); Operand ap = xlat_op(r, in->opnds[1]); - const Type* ty = (const Type*)in->extra.aux; + CfreeCgTypeId ty = (CfreeCgTypeId)(uintptr_t)in->extra.aux; w->va_arg_(w, dst, ap, ty); break; } diff --git a/src/opt/pass_lower.c b/src/opt/pass_lower.c @@ -5,32 +5,37 @@ #include "core/arena.h" #include "core/core.h" -static u32 type_size_fallback(const Func* f, const Type* t) { +enum { + OPT_CG_TYPE_SEG_SHIFT = 6, + OPT_CG_TYPE_SEG_MASK = (1u << OPT_CG_TYPE_SEG_SHIFT) - 1u, + OPT_CG_TYPE_BUILTIN_SEG = 1u, +}; + +static u32 type_size_fallback(const Func* f, CfreeCgTypeId t) { + CfreeCgBuiltinType b; if (!t) return f->opt_target.ptr_size ? f->opt_target.ptr_size : 8u; - switch ((TypeKind)t->kind) { - case TY_BOOL: - case TY_CHAR: - case TY_SCHAR: - case TY_UCHAR: + if ((t >> OPT_CG_TYPE_SEG_SHIFT) != OPT_CG_TYPE_BUILTIN_SEG) { + return f->opt_target.ptr_size ? f->opt_target.ptr_size : 8u; + } + b = (CfreeCgBuiltinType)(t & OPT_CG_TYPE_SEG_MASK); + switch (b) { + case CFREE_CG_BUILTIN_BOOL: + case CFREE_CG_BUILTIN_I8: return 1; - case TY_SHORT: - case TY_USHORT: + case CFREE_CG_BUILTIN_I16: return 2; - case TY_INT: - case TY_UINT: - case TY_FLOAT: + case CFREE_CG_BUILTIN_I32: + case CFREE_CG_BUILTIN_F32: return 4; - case TY_LONG: - case TY_ULONG: - case TY_LLONG: - case TY_ULLONG: - case TY_DOUBLE: - case TY_PTR: + case CFREE_CG_BUILTIN_I64: + case CFREE_CG_BUILTIN_F64: return 8; - case TY_INT128: - case TY_UINT128: - case TY_LDOUBLE: + case CFREE_CG_BUILTIN_I128: return 16; + case CFREE_CG_BUILTIN_VOID: + return 0; + case CFREE_CG_BUILTIN_VARARG_STATE: + case CFREE_CG_BUILTIN_COUNT: default: return f->opt_target.ptr_size ? f->opt_target.ptr_size : 8u; } diff --git a/src/parse/cg_public_compat.h b/src/parse/cg_public_compat.h @@ -1,6 +0,0 @@ -#ifndef CFREE_SRC_PARSE_CG_PUBLIC_COMPAT_H -#define CFREE_SRC_PARSE_CG_PUBLIC_COMPAT_H - -#include "../../lang/c/parse/cg_public_compat.h" - -#endif diff --git a/src/pp/pp.h b/src/pp/pp.h @@ -1,6 +0,0 @@ -#ifndef CFREE_SRC_PP_COMPAT_H -#define CFREE_SRC_PP_COMPAT_H - -#include "../../lang/c/pp/pp.h" - -#endif diff --git a/src/type/type.h b/src/type/type.h @@ -1,6 +0,0 @@ -#ifndef CFREE_SRC_TYPE_COMPAT_H -#define CFREE_SRC_TYPE_COMPAT_H - -#include "../../lang/c/type/type.h" - -#endif diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -66,7 +66,9 @@ int main(void) { CfreeCgTypeId fn; CfreeCgTypeId alias; CfreeCgTypeId rec; + CfreeCgTypeId rec_ex; CfreeCgTypeId enm; + CfreeCgRecordDesc rdesc; CfreeCgField fields[2]; CfreeCgField field_out; CfreeCgEnumValue vals[2]; @@ -153,6 +155,21 @@ int main(void) { "record field data mismatch"); EXPECT(field_off == 4, "record field offset mismatch"); + memset(&rdesc, 0, sizeof rdesc); + rdesc.tag = cfree_sym_intern(c, "U"); + rdesc.fields = fields; + rdesc.nfields = 2; + rdesc.is_union = 1; + rdesc.align_override = 16; + rec_ex = cfree_cg_type_record_ex(c, &rdesc); + EXPECT(rec_ex != CFREE_CG_TYPE_NONE, "record desc type failed"); + EXPECT(cfree_cg_type_size(c, rec_ex) == 16, "record desc size mismatch"); + EXPECT(cfree_cg_type_align(c, rec_ex) == 16, "record desc align mismatch"); + EXPECT(cfree_cg_type_record_field(c, rec_ex, 1, &field_out, &field_off) == + 0, + "record desc field query failed"); + EXPECT(field_off == 0, "union field offset mismatch"); + vals[0].name = cfree_sym_intern(c, "A"); vals[0].value = 1; vals[1].name = cfree_sym_intern(c, "B"); diff --git a/test/opt/opt_test.c b/test/opt/opt_test.c @@ -11,7 +11,6 @@ #include "core/heap.h" #include "opt/ir.h" #include "opt/opt.h" -#include "type/type.h" static void* h_alloc(CfreeHeap* h, size_t n, size_t a) { (void)h; @@ -59,8 +58,8 @@ static int g_checks; typedef struct TestCtx { Compiler cc; Compiler* c; - const Type* i32; - const Type* i64; + CfreeCgTypeId i32; + CfreeCgTypeId i64; } TestCtx; static void tc_init(TestCtx* tc) { @@ -82,13 +81,16 @@ static void tc_init(TestCtx* tc) { s_env = env; compiler_init(&tc->cc, tgt, &s_env); tc->c = &tc->cc; - tc->i32 = type_prim(tc->c->global, TY_INT); - tc->i64 = type_prim(tc->c->global, TY_LLONG); + { + CfreeCgBuiltinTypes b = cfree_cg_builtin_types(tc->c); + tc->i32 = b.id[CFREE_CG_BUILTIN_I32]; + tc->i64 = b.id[CFREE_CG_BUILTIN_I64]; + } } static void tc_fini(TestCtx* tc) { compiler_fini(&tc->cc); } -static Operand op_reg_(Reg r, const Type* ty) { +static Operand op_reg_(Reg r, CfreeCgTypeId ty) { Operand o; memset(&o, 0, sizeof o); o.kind = OPK_REG; @@ -98,7 +100,7 @@ static Operand op_reg_(Reg r, const Type* ty) { return o; } -static Operand op_imm_(i64 v, const Type* ty) { +static Operand op_imm_(i64 v, CfreeCgTypeId ty) { Operand o; memset(&o, 0, sizeof o); o.kind = OPK_IMM; @@ -110,19 +112,24 @@ static Operand op_imm_(i64 v, const Type* ty) { static Func* new_func(TestCtx* tc) { CGFuncDesc fd; + CfreeCgFuncSig sig; memset(&fd, 0, sizeof fd); - fd.fn_type = type_func(tc->c->global, tc->i32, NULL, 0, 0); + memset(&sig, 0, sizeof sig); + sig.ret = tc->i32; + sig.call_conv = CFREE_CG_CC_TARGET_C; + fd.fn_type = cfree_cg_type_func(tc->c, sig); Func* f = ir_func_new(tc->c, &fd); f->entry = ir_block_new(f); ir_note_emit(f, f->entry); return f; } -static Val add_val(Func* f, const Type* ty) { +static Val add_val(Func* f, CfreeCgTypeId ty) { return ir_alloc_val(f, ty, RC_INT); } -static Inst* emit_load_imm(Func* f, u32 b, Val dst, const Type* ty, i64 imm) { +static Inst* emit_load_imm(Func* f, u32 b, Val dst, CfreeCgTypeId ty, + i64 imm) { Inst* in = ir_emit(f, b, IR_LOAD_IMM); in->opnds = arena_array(f->arena, Operand, 1); in->opnds[0] = op_reg_(dst, ty); @@ -135,7 +142,7 @@ static Inst* emit_load_imm(Func* f, u32 b, Val dst, const Type* ty, i64 imm) { return in; } -static Inst* emit_copy(Func* f, u32 b, Val dst, Val src, const Type* ty) { +static Inst* emit_copy(Func* f, u32 b, Val dst, Val src, CfreeCgTypeId ty) { Inst* in = ir_emit(f, b, IR_COPY); in->opnds = arena_array(f->arena, Operand, 2); in->opnds[0] = op_reg_(dst, ty); @@ -148,7 +155,8 @@ static Inst* emit_copy(Func* f, u32 b, Val dst, Val src, const Type* ty) { return in; } -static Inst* emit_binop(Func* f, u32 b, Val dst, Val a, Val c, const Type* ty) { +static Inst* emit_binop(Func* f, u32 b, Val dst, Val a, Val c, + CfreeCgTypeId ty) { Inst* in = ir_emit(f, b, IR_BINOP); in->opnds = arena_array(f->arena, Operand, 3); in->opnds[0] = op_reg_(dst, ty); @@ -170,7 +178,7 @@ static Inst* emit_call_void(Func* f, u32 b) { return in; } -static void emit_ret_val(Func* f, u32 b, Val v, const Type* ty) { +static void emit_ret_val(Func* f, u32 b, Val v, CfreeCgTypeId ty) { Inst* in = ir_emit(f, b, IR_RET); IRRetAux* aux = arena_znew(f->arena, IRRetAux); aux->present = 1; @@ -641,8 +649,12 @@ static void opt_emit_no_virtual_alloc(void) { CGTarget* opt = opt_cgtarget_new(tc.c, &mock.base, 1); CGFuncDesc fd; + CfreeCgFuncSig sig; memset(&fd, 0, sizeof fd); - fd.fn_type = type_func(tc.c->global, tc.i32, NULL, 0, 0); + memset(&sig, 0, sizeof sig); + sig.ret = tc.i32; + sig.call_conv = CFREE_CG_CC_TARGET_C; + fd.fn_type = cfree_cg_type_func(tc.c, sig); opt->func_begin(opt, &fd); Reg a = opt->alloc_reg(opt, RC_INT, tc.i32); diff --git a/test/parse/harness/parse_runner.c b/test/parse/harness/parse_runner.c @@ -27,6 +27,7 @@ #include <sys/stat.h> #include <unistd.h> +#include "../../../lang/c/c.h" #include "lib/cfree_test_target.h" /* ---- env: heap, diag ---- */ @@ -283,6 +284,7 @@ static int mode_emit(const char* src_path, const char* out_path) { free(src); return 2; } + cfree_c_register(c); memset(&in, 0, sizeof in); in.name = src_path; @@ -359,6 +361,7 @@ static int mode_jit(const char* src_path) { free(src); return 2; } + cfree_c_register(c); memset(&in, 0, sizeof in); in.name = src_path;