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:
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;