kit

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

commit 201c8f0da021884364993e891a9bb09ec10c05ad
parent 3021470e7878a91d1960a1d19527d941d7803b8c
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Thu, 14 May 2026 10:49:27 -0700

Expose frontend support API for C

Diffstat:
Dinclude/abi/abi.h | 126-------------------------------------------------------------------------------
Ainclude/cfree/frontend.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/cfree/hashmap.h | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dinclude/core/arena.h | 31-------------------------------
Dinclude/core/core.h | 160-------------------------------------------------------------------------------
Dinclude/core/diag.h | 19-------------------
Dinclude/core/hashmap.h | 202-------------------------------------------------------------------------------
Dinclude/core/heap.h | 16----------------
Dinclude/core/pool.h | 40----------------------------------------
Mlang/c/abi/c_abi.c | 99++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mlang/c/abi/c_abi.h | 46+++++++++++++++++++++++++++++++++++++++++++---
Mlang/c/c.c | 82++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Alang/c/c_support.h | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlang/c/decl/decl.c | 13+++++--------
Mlang/c/decl/decl.h | 4++--
Mlang/c/decl/decl_attrs.c | 4+---
Mlang/c/decl/decl_attrs.h | 1-
Mlang/c/lex/lex.c | 32+++++++++++++++++++++++---------
Mlang/c/lex/lex.h | 2+-
Mlang/c/parse/attr.h | 2+-
Mlang/c/parse/cg_adapter.c | 181++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mlang/c/parse/cg_public_compat.h | 38+++++++++++++++++++-------------------
Mlang/c/parse/parse.c | 226++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mlang/c/parse/parse.h | 2+-
Mlang/c/parse/parse_expr.c | 425++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mlang/c/parse/parse_init.c | 76++++++++++++++++++++++++++++++++++++++++------------------------------------
Mlang/c/parse/parse_priv.h | 77++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mlang/c/parse/parse_stmt.c | 46++++++++++++++++++++++++++--------------------
Mlang/c/parse/parse_type.c | 328++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mlang/c/pp/pp.c | 45++++++++++++++++++++++++++++-----------------
Mlang/c/pp/pp.h | 4++--
Mlang/c/pp/pp_directive.c | 72++++++++++++++++++++++++++++++++++++------------------------------------
Mlang/c/pp/pp_expand.c | 52+++++++++++++++++++++++++++-------------------------
Mlang/c/pp/pp_priv.h | 45+++++++++++++++++++++------------------------
Mlang/c/type/type.c | 64++++++++++++++++++++++++++++++++++++----------------------------
Mlang/c/type/type.h | 8++++----
Asrc/api/frontend.c | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/core/hashmap.h | 202+++----------------------------------------------------------------------------
38 files changed, 1709 insertions(+), 1533 deletions(-)

diff --git a/include/abi/abi.h b/include/abi/abi.h @@ -1,126 +0,0 @@ -#ifndef CFREE_ABI_H -#define CFREE_ABI_H - -#include <cfree/cg.h> - -#include "core/core.h" - -/* 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 { - ABI_SC_VOID, - ABI_SC_BOOL, - ABI_SC_INT, - ABI_SC_FLOAT, - ABI_SC_PTR, -} ABIScalarKind; - -typedef struct ABITypeInfo { - u32 size; - u32 align; - u8 scalar_kind; /* ABIScalarKind; ABI_SC_VOID for aggregates/void */ - u8 signed_; - u8 atomic; - u8 pad; -} ABITypeInfo; - -typedef struct ABIFieldLayout { - u32 offset; /* byte offset from record base */ - u16 bit_offset; /* bit offset within storage unit for bitfields */ - u16 bit_width; /* 0 for non-bitfield */ - u32 storage_size; /* bytes in the bitfield storage unit; 0 otherwise */ -} ABIFieldLayout; - -typedef struct ABIRecordLayout { - u32 size; - u32 align; - u32 nfields; - const ABIFieldLayout* fields; -} ABIRecordLayout; - -typedef enum ABIArgKind { - ABI_ARG_IGNORE, - ABI_ARG_DIRECT, /* one or more inspectable parts */ - ABI_ARG_INDIRECT, /* caller passes address */ - ABI_ARG_EXPAND, /* aggregate split into parts below */ -} ABIArgKind; - -typedef enum ABIArgClass { - ABI_CLASS_NONE, - ABI_CLASS_INT, - ABI_CLASS_FP, - ABI_CLASS_VEC, - ABI_CLASS_MEM, -} ABIArgClass; - -typedef enum ABIArgLoc { - ABI_LOC_NONE, - ABI_LOC_REG, - ABI_LOC_STACK, - ABI_LOC_EITHER, -} ABIArgLoc; - -typedef enum ABIArgFlag { - ABI_AF_NONE = 0, - ABI_AF_SRET = 1u << 0, /* hidden structure-return pointer */ - ABI_AF_BYVAL = 1u << 1, /* caller passes an address to a copy */ - ABI_AF_SIGN_EXT = 1u << 2, - ABI_AF_ZERO_EXT = 1u << 3, - ABI_AF_VARARG = 1u << 4, /* placement affected by variadic rules */ - ABI_AF_SPLIT = 1u << 5, /* source value is split across parts */ -} ABIArgFlag; - -typedef struct ABIArgPart { - u8 cls; /* ABIArgClass */ - u8 loc; /* ABIArgLoc preference */ - u16 flags; /* ABIArgFlag */ - u32 src_offset; /* byte offset within source object */ - u32 size; /* bytes carried by this part */ - u32 align; /* part alignment */ - u32 stack_align; /* required stack alignment if stack-passed */ -} ABIArgPart; - -typedef struct ABIArgInfo { - u8 kind; /* ABIArgKind */ - u8 flags; /* ABIArgFlag applying to the whole argument */ - u16 nparts; - u32 indirect_align; /* required alignment for ABI_ARG_INDIRECT/byval copy */ - const ABIArgPart* parts; -} ABIArgInfo; - -typedef struct ABIFuncInfo { - ABIArgInfo ret; - const ABIArgInfo* params; - u16 nparams; - u8 variadic; - u8 has_sret; - /* True when the trailing `...` portion of a variadic call must be - * routed to the stack exclusively, bypassing the GPR/FPR arg pools. - * Apple ARM64 sets this; AAPCS64 / SysV-x64 leave it 0 (variadics - * use the same register routing as fixed args). */ - u8 vararg_on_stack; - u32 vararg_gp_offset; - u32 vararg_fp_offset; - u32 vararg_overflow_offset; -} ABIFuncInfo; - -void abi_init(TargetABI*, Compiler*); -void abi_fini(TargetABI*); - -/* Heap-allocating wrappers around abi_init/abi_fini, used by compiler_init. - * The returned pointer is valid until abi_free returns. */ -TargetABI* abi_new(Compiler*); -void abi_free(TargetABI*); -Compiler* abi_compiler(TargetABI*); - -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_va_list_info(TargetABI*); - -#endif diff --git a/include/cfree/frontend.h b/include/cfree/frontend.h @@ -0,0 +1,72 @@ +#ifndef CFREE_FRONTEND_H +#define CFREE_FRONTEND_H + +#include <cfree.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> + +typedef struct CfreeArena CfreeArena; + +/* Arena storage for frontends. The arena is opaque; allocation is bump-style + * and released wholesale by reset/free. */ +CfreeArena* cfree_arena_new(CfreeHeap*, size_t block_size); +void cfree_arena_free(CfreeArena*); +void cfree_arena_reset(CfreeArena*); +void* cfree_arena_alloc(CfreeArena*, size_t size, size_t align); +void* cfree_arena_zalloc(CfreeArena*, size_t size, size_t align); +char* cfree_arena_strdup(CfreeArena*, const char* s, size_t len); + +#define cfree_arena_new_obj(a, T) \ + ((T*)cfree_arena_alloc((a), sizeof(T), _Alignof(T))) +#define cfree_arena_znew_obj(a, T) \ + ((T*)cfree_arena_zalloc((a), sizeof(T), _Alignof(T))) +#define cfree_arena_array(a, T, n) \ + ((T*)cfree_arena_alloc((a), sizeof(T) * (size_t)(n), _Alignof(T))) +#define cfree_arena_zarray(a, T, n) \ + ((T*)cfree_arena_zalloc((a), sizeof(T) * (size_t)(n), _Alignof(T))) + +/* Compiler-attached host services. These expose the vtables already present + * in CfreeEnv without exposing CfreeCompiler's internal layout. */ +CfreeHeap* cfree_compiler_heap(CfreeCompiler*); +const CfreeFileIO* cfree_compiler_file_io(CfreeCompiler*); +int64_t cfree_compiler_now(CfreeCompiler*); + +/* Symbol pool helpers. cfree_sym_intern is the c-string convenience in + * <cfree.h>; the length-taking form is needed by lexers and preprocessors. */ +CfreeSym cfree_sym_intern_len(CfreeCompiler*, const char* str, size_t len); +const char* cfree_sym_str(CfreeCompiler*, CfreeSym, size_t* len_out); + +/* Source-file registration and include-edge recording. */ +uint32_t cfree_source_add_file(CfreeCompiler*, const char* path, + int system_header); +uint32_t cfree_source_add_memory(CfreeCompiler*, const char* name); +uint32_t cfree_source_add_builtin(CfreeCompiler*, const char* name); +void cfree_source_add_include(CfreeCompiler*, uint32_t includer_file_id, + uint32_t included_file_id, CfreeSrcLoc loc, + int system); + +typedef struct CfreeSourceFile { + uint32_t id; + CfreeSym name; + CfreeSym path; + uint8_t kind; + uint8_t system_header; + uint16_t pad; +} CfreeSourceFile; + +int cfree_source_file(CfreeCompiler*, uint32_t file_id, CfreeSourceFile* out); + +/* Frontend panic boundary. Frontend entry points called by cfree_compile_obj* + * already run under libcfree's top-level boundary; standalone frontend helpers + * such as preprocess/token-dump can use cfree_frontend_run to get the same + * behavior without seeing jmp_buf or CfreeCompiler internals. */ +typedef int (*CfreeFrontendRunFn)(CfreeCompiler*, void* user); +int cfree_frontend_run(CfreeCompiler*, CfreeFrontendRunFn, void* user); + +_Noreturn void cfree_frontend_fatal(CfreeCompiler*, CfreeSrcLoc, + const char* fmt, ...); +_Noreturn void cfree_frontend_vfatal(CfreeCompiler*, CfreeSrcLoc, + const char* fmt, va_list); + +#endif diff --git a/include/cfree/hashmap.h b/include/cfree/hashmap.h @@ -0,0 +1,170 @@ +#ifndef CFREE_HASHMAP_H +#define CFREE_HASHMAP_H + +#include <cfree.h> +#include <stdint.h> +#include <string.h> + +static inline uint32_t cfree_hash_u32(uint32_t x) { + x += 0x9e3779b9u; + x ^= x >> 16; + x *= 0x7feb352du; + x ^= x >> 15; + x *= 0x846ca68bu; + x ^= x >> 16; + return x; +} + +static inline uint32_t cfree_hash_u64(uint64_t x) { + x ^= x >> 33; + x *= 0xff51afd7ed558ccdULL; + x ^= x >> 33; + x *= 0xc4ceb9fe1a85ec53ULL; + x ^= x >> 33; + return (uint32_t)x; +} + +#define CFREE_HASHMAP_LOAD_NUM 3u +#define CFREE_HASHMAP_LOAD_DEN 4u +#define CFREE_HASHMAP_INIT_CAP 16u + +#define CFREE_HASHMAP_DEFINE(NAME, KT, VT, HASH_FN) \ + typedef struct NAME##Slot { \ + KT k; \ + VT v; \ + } NAME##Slot; \ + typedef struct NAME { \ + CfreeHeap* heap; \ + NAME##Slot* slots; \ + uint32_t cap; \ + uint32_t used; \ + } NAME; \ + \ + __attribute__((unused)) static void NAME##_resize(NAME* m, \ + uint32_t new_cap) { \ + NAME##Slot* fresh; \ + uint32_t i, mask; \ + fresh = (NAME##Slot*)m->heap->alloc(m->heap, sizeof(*fresh) * new_cap, \ + _Alignof(NAME##Slot)); \ + if (!fresh) return; \ + memset(fresh, 0, sizeof(*fresh) * new_cap); \ + mask = new_cap - 1u; \ + for (i = 0; i < m->cap; ++i) { \ + KT k = m->slots[i].k; \ + uint32_t j; \ + if (!(k)) continue; \ + j = HASH_FN(k) & mask; \ + while (fresh[j].k) j = (j + 1u) & mask; \ + fresh[j] = m->slots[i]; \ + } \ + if (m->slots) \ + m->heap->free(m->heap, m->slots, sizeof(*m->slots) * m->cap); \ + m->slots = fresh; \ + m->cap = new_cap; \ + } \ + \ + __attribute__((unused)) static inline void NAME##_init_cap( \ + NAME* m, CfreeHeap* h, uint32_t cap) { \ + m->heap = h; \ + m->slots = NULL; \ + m->cap = 0; \ + m->used = 0; \ + if (cap) NAME##_resize(m, cap); \ + } \ + \ + __attribute__((unused)) static inline void NAME##_init(NAME* m, \ + CfreeHeap* h) { \ + NAME##_init_cap(m, h, CFREE_HASHMAP_INIT_CAP); \ + } \ + \ + __attribute__((unused)) static inline void NAME##_fini(NAME* m) { \ + if (m->slots) \ + m->heap->free(m->heap, m->slots, sizeof(*m->slots) * m->cap); \ + m->slots = NULL; \ + m->cap = m->used = 0; \ + } \ + \ + __attribute__((unused)) static inline VT* NAME##_get(const NAME* m, KT k) { \ + uint32_t mask, j; \ + if (m->cap == 0 || !(k)) return NULL; \ + mask = m->cap - 1u; \ + j = HASH_FN(k) & mask; \ + while (m->slots[j].k) { \ + if (m->slots[j].k == (k)) return &m->slots[j].v; \ + j = (j + 1u) & mask; \ + } \ + return NULL; \ + } \ + \ + __attribute__((unused)) static inline int NAME##_set(NAME* m, KT k, VT v) { \ + uint32_t mask, j; \ + if (m->cap == 0 || \ + m->used * CFREE_HASHMAP_LOAD_DEN >= m->cap * CFREE_HASHMAP_LOAD_NUM) \ + NAME##_resize(m, m->cap ? m->cap * 2u : CFREE_HASHMAP_INIT_CAP); \ + mask = m->cap - 1u; \ + j = HASH_FN(k) & mask; \ + while (m->slots[j].k) { \ + if (m->slots[j].k == (k)) { \ + m->slots[j].v = (v); \ + return 0; \ + } \ + j = (j + 1u) & mask; \ + } \ + m->slots[j].k = (k); \ + m->slots[j].v = (v); \ + m->used++; \ + return 1; \ + } \ + \ + __attribute__((unused)) static inline int NAME##_try_insert( \ + NAME* m, KT k, VT v, VT* existing_out) { \ + uint32_t mask, j; \ + if (m->cap == 0 || \ + m->used * CFREE_HASHMAP_LOAD_DEN >= m->cap * CFREE_HASHMAP_LOAD_NUM) \ + NAME##_resize(m, m->cap ? m->cap * 2u : CFREE_HASHMAP_INIT_CAP); \ + mask = m->cap - 1u; \ + j = HASH_FN(k) & mask; \ + while (m->slots[j].k) { \ + if (m->slots[j].k == (k)) { \ + if (existing_out) *existing_out = m->slots[j].v; \ + return 0; \ + } \ + j = (j + 1u) & mask; \ + } \ + m->slots[j].k = (k); \ + m->slots[j].v = (v); \ + m->used++; \ + return 1; \ + } \ + \ + __attribute__((unused)) static inline void NAME##_del(NAME* m, KT k) { \ + uint32_t mask, j; \ + if (m->cap == 0 || !(k)) return; \ + mask = m->cap - 1u; \ + j = HASH_FN(k) & mask; \ + while (m->slots[j].k) { \ + if (m->slots[j].k == (k)) { \ + uint32_t i = (j + 1u) & mask; \ + m->slots[j].k = 0; \ + m->used--; \ + while (m->slots[i].k) { \ + KT rk = m->slots[i].k; \ + VT rv = m->slots[i].v; \ + uint32_t nh; \ + m->slots[i].k = 0; \ + m->used--; \ + nh = HASH_FN(rk) & mask; \ + while (m->slots[nh].k) nh = (nh + 1u) & mask; \ + m->slots[nh].k = rk; \ + m->slots[nh].v = rv; \ + m->used++; \ + i = (i + 1u) & mask; \ + } \ + return; \ + } \ + j = (j + 1u) & mask; \ + } \ + } \ + struct NAME + +#endif diff --git a/include/core/arena.h b/include/core/arena.h @@ -1,31 +0,0 @@ -#ifndef CFREE_ARENA_H -#define CFREE_ARENA_H - -#include "core/core.h" -#include "core/heap.h" - -typedef struct ArenaBlock ArenaBlock; - -struct Arena { - Heap* heap; - ArenaBlock* head; - u8* cur; /* points into head's buffer */ - u8* end; /* end of head's buffer */ - size_t block_size; -}; - -void arena_init(Arena*, Heap*, size_t block_size); -void arena_fini(Arena*); -void arena_reset(Arena*); -void* arena_alloc(Arena*, size_t size, size_t align); -void* arena_zalloc(Arena*, size_t size, size_t align); /* zeroed; NULL on OOM */ -char* arena_strdup(Arena*, const char* s, size_t len); - -#define arena_new(a, T) ((T*)arena_alloc((a), sizeof(T), _Alignof(T))) -#define arena_znew(a, T) ((T*)arena_zalloc((a), sizeof(T), _Alignof(T))) -#define arena_array(a, T, n) \ - ((T*)arena_alloc((a), sizeof(T) * (size_t)(n), _Alignof(T))) -#define arena_zarray(a, T, n) \ - ((T*)arena_zalloc((a), sizeof(T) * (size_t)(n), _Alignof(T))) - -#endif diff --git a/include/core/core.h b/include/core/core.h @@ -1,160 +0,0 @@ -#ifndef CFREE_INTERNAL_CORE_H -#define CFREE_INTERNAL_CORE_H - -#include <cfree.h> -#include <setjmp.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdint.h> - -/* Short integer aliases used throughout libcfree's internal headers. */ -typedef int8_t i8; -typedef int16_t i16; -typedef int32_t i32; -typedef int64_t i64; -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -/* Internal aliases for types that also have a public Cfree-prefixed name. - * <cfree.h> is the single source of truth for those types' identities; - * src/ keeps its terser, plain names so the internal call sites don't - * change. Both names refer to the same struct. */ -typedef CfreeCompiler Compiler; -typedef CfreeHeap Heap; -typedef CfreeDiagSink DiagSink; -typedef CfreeWriter Writer; -typedef CfreeTarget Target; -typedef CfreeObjBuilder ObjBuilder; -typedef enum CfreeArchKind ArchKind; -typedef enum CfreeOSKind OSKind; -typedef enum CfreeObjFmt ObjFmt; - -/* Internal-only forward declarations. */ -typedef struct Arena Arena; -typedef struct Pool Pool; -typedef struct TargetABI TargetABI; -typedef struct SourceManager SourceManager; - -/* Interned string ids. 0 reserved as "none". Object and linker symbols are - * intentionally not intern-pool concepts; see obj/obj.h and link/link.h. */ -typedef u32 Sym; - -/* Binary-blob handle into the same Pool. Shares the numeric value space with - * Sym but is a distinct typedef so callers don't accidentally mix interned - * strings with decoded literal bytes. */ -typedef u32 BytesId; -#define BYTES_NONE 0u - -/* SrcLoc is the public CfreeSrcLoc; the alias keeps internal call sites - * terse. */ -typedef CfreeSrcLoc SrcLoc; - -typedef struct SrcRange { - SrcLoc begin; - SrcLoc end; -} SrcRange; - -typedef enum SourceFileKind { - SRC_FILE_REAL, - SRC_FILE_MEMORY, - SRC_FILE_BUILTIN, - SRC_FILE_MACRO, -} SourceFileKind; - -typedef struct SourceFile { - u32 id; - Sym name; /* spelling used in diagnostics */ - Sym path; /* normalized path, 0 for memory/builtin-only input */ - u8 kind; /* SourceFileKind */ - u8 system_header; - u16 pad; -} SourceFile; - -typedef struct SourceInclude { - u32 includer_file_id; - u32 included_file_id; - SrcLoc include_loc; - u8 system; - u8 pad[3]; -} SourceInclude; - -typedef struct SourceExpansion { - SrcLoc spelling_loc; /* where the token text came from */ - SrcLoc expansion_loc; /* where the macro expansion was requested */ - Sym macro_name; -} SourceExpansion; - -typedef struct SourceDepIter SourceDepIter; - -SourceManager* source_new(Compiler*); -void source_free(SourceManager*); - -u32 source_add_file(SourceManager*, const char* path, int system_header); -u32 source_add_memory(SourceManager*, const char* name); -u32 source_add_builtin(SourceManager*, const char* name); -void source_add_include(SourceManager*, u32 includer_file_id, - u32 included_file_id, SrcLoc include_loc, int system); -u32 source_add_macro_expansion(SourceManager*, Sym macro_name, - SrcLoc spelling_loc, SrcLoc expansion_loc); - -const SourceFile* source_file(SourceManager*, u32 file_id); -const SourceExpansion* source_expansion(SourceManager*, u32 expansion_file_id); -SrcLoc source_spelling_loc(SourceManager*, SrcLoc); -SrcLoc source_expansion_loc(SourceManager*, SrcLoc); - -SourceDepIter* source_depiter_new(SourceManager*); -const SourceInclude* source_depiter_next(SourceDepIter*); -void source_depiter_free(SourceDepIter*); - -/* compiler_defer registers a cleanup that runs LIFO from cfree_run's panic - * boundary (or any caller that establishes its own setjmp). Each subsystem - * _new registers its matching _free; the matched _free calls compiler_undefer - * with the returned handle. The cleanup stack lives in scratch arena and is - * bounded by pipeline depth (~10 entries). */ -typedef struct CompilerCleanup CompilerCleanup; - -struct CfreeCompiler { - jmp_buf panic; - const CfreeEnv* env; - Pool* global; - Arena* tu; - Arena* scratch; - SourceManager* sources; - TargetABI* abi; - Target target; - CompilerCleanup* cleanup; /* top of LIFO cleanup stack */ - CfreeCompileFn frontends[CFREE_LANG_COUNT]; - void* cg_api; /* public cfree/cg.h adapter state */ - void (*cg_api_free)(Compiler*); -}; - -void compiler_init(Compiler*, Target, const CfreeEnv*); -void compiler_fini(Compiler*); - -/* Cleanup stack. compiler_defer returns an opaque handle; compiler_undefer - * removes the entry without running it (use after a successful _free). - * compiler_run_cleanups runs everything LIFO, used by the panic handler. */ -CompilerCleanup* compiler_defer(Compiler*, void (*fn)(void*), void* arg); -void compiler_undefer(Compiler*, CompilerCleanup*); -void compiler_run_cleanups(Compiler*); - -/* Emits a diagnostic and longjmps c->panic. Used by parse/cg/arch fatal paths. - */ -_Noreturn void compiler_panic(Compiler*, SrcLoc, const char* fmt, ...); -_Noreturn void compiler_panicv(Compiler*, SrcLoc, const char* fmt, va_list); - -/* Save/restore the panic jmp_buf so layered APIs can nest. Each top-level - * driver function (cfree_compile_obj, cfree_link_*, ...) saves c->panic, - * installs its own setjmp, and restores on every exit path — both the - * panic-return path (after compiler_run_cleanups) and the success path. - * Without this, an inner setjmp clobbers an outer setjmp's jmp_buf, and a - * subsequent compiler_panic by the outer caller longjmps to a dead frame. */ -typedef struct PanicSave { - jmp_buf buf; -} PanicSave; -void compiler_panic_save(Compiler*, PanicSave* out); -void compiler_panic_restore(Compiler*, const PanicSave* saved); - -#endif diff --git a/include/core/diag.h b/include/core/diag.h @@ -1,19 +0,0 @@ -#ifndef CFREE_DIAG_H -#define CFREE_DIAG_H - -#include "core/core.h" - -/* DiagKind / DiagSink struct are public (see <cfree.h>). The internal - * aliases below keep terse names; the unprefixed enum constants below - * are the names libcfree's source uses internally. */ -typedef CfreeDiagKind DiagKind; -#define DIAG_NOTE CFREE_DIAG_NOTE -#define DIAG_WARN CFREE_DIAG_WARN -#define DIAG_ERROR CFREE_DIAG_ERROR -#define DIAG_FATAL CFREE_DIAG_FATAL - -/* Convenience varargs wrappers around `sink->emit`. Internal use only. */ -void diag_emit(DiagSink*, DiagKind, SrcLoc, const char* fmt, ...); -void diag_emitv(DiagSink*, DiagKind, SrcLoc, const char* fmt, va_list); - -#endif diff --git a/include/core/hashmap.h b/include/core/hashmap.h @@ -1,202 +0,0 @@ -#ifndef CFREE_HASHMAP_H -#define CFREE_HASHMAP_H - -/* Generic open-addressed hashmap as a typed-macro template. - * - * Linear probing; doubling rehash at 75% load. Tombstoneless deletion - * via cluster rehash. Empty-key sentinel is 0 — slots are zero-initialized - * by allocation, and callers must never insert a key whose value compares - * equal to 0. (Sym=0 already means "none" per core.h:42; OBJ_SEC_NONE=0; - * pointer keys avoid 0 by construction.) - * - * HASHMAP_DEFINE(NAME, KT, VT, HASH_FN) - * NAME — struct typedef name for this instance. - * KT — key type (must support `== 0` and `==` against another KT). - * VT — value type (any assignable type). - * HASH_FN — function-like expression mapping KT -> u32. - * - * Emits typedef NAME, NAME##Slot, and these static functions: - * void NAME##_init (NAME*, Heap*) — default initial cap - * void NAME##_init_cap(NAME*, Heap*, u32 cap) — caller picks initial - * cap void NAME##_fini (NAME*) VT* NAME##_get (const NAME*, KT) — - * NULL if absent int NAME##_set (NAME*, KT, VT) — 1 - * inserted, 0 updated void NAME##_del (NAME*, KT) — no-op - * if absent - * - * Equality is `==` on KT. That covers all keys we use (Sym which is u32, - * u64 guest_pc). A string-keyed instance would need a small extension. - * - * Built-in mixers below cover u32 (hash_u32) and u64 (hash_u64) keys. */ - -#include <string.h> - -#include "core/core.h" -#include "core/heap.h" - -/* xorshift mixer suitable for dense u32 keys (interned Sym ids etc.). */ -static inline u32 hash_u32(u32 x) { - x += 0x9e3779b9u; - x ^= x >> 16; - x *= 0x7feb352du; - x ^= x >> 15; - x *= 0x846ca68bu; - x ^= x >> 16; - return x; -} - -/* SplitMix-style mixer for u64 keys (e.g. guest PC). */ -static inline u32 hash_u64(u64 x) { - x ^= x >> 33; - x *= 0xff51afd7ed558ccdULL; - x ^= x >> 33; - x *= 0xc4ceb9fe1a85ec53ULL; - x ^= x >> 33; - return (u32)x; -} - -#define HASHMAP_LOAD_NUM 3u -#define HASHMAP_LOAD_DEN 4u -#define HASHMAP_INIT_CAP 16u - -#define HASHMAP_DEFINE(NAME, KT, VT, HASH_FN) \ - typedef struct NAME##Slot { \ - KT k; \ - VT v; \ - } NAME##Slot; \ - typedef struct NAME { \ - Heap* heap; \ - NAME##Slot* slots; \ - u32 cap; \ - u32 used; \ - } NAME; \ - \ - __attribute__((unused)) static void NAME##_resize(NAME* m, u32 new_cap) { \ - NAME##Slot* fresh; \ - u32 i, mask; \ - fresh = (NAME##Slot*)m->heap->alloc(m->heap, sizeof(*fresh) * new_cap, \ - _Alignof(NAME##Slot)); \ - if (!fresh) return; \ - memset(fresh, 0, sizeof(*fresh) * new_cap); \ - mask = new_cap - 1u; \ - for (i = 0; i < m->cap; ++i) { \ - KT k = m->slots[i].k; \ - u32 j; \ - if (!(k)) continue; \ - j = HASH_FN(k) & mask; \ - while (fresh[j].k) j = (j + 1u) & mask; \ - fresh[j] = m->slots[i]; \ - } \ - if (m->slots) \ - m->heap->free(m->heap, m->slots, sizeof(*m->slots) * m->cap); \ - m->slots = fresh; \ - m->cap = new_cap; \ - } \ - \ - __attribute__((unused)) static inline void NAME##_init_cap(NAME* m, Heap* h, \ - u32 cap) { \ - m->heap = h; \ - m->slots = NULL; \ - m->cap = 0; \ - m->used = 0; \ - if (cap) NAME##_resize(m, cap); \ - } \ - \ - __attribute__((unused)) static inline void NAME##_init(NAME* m, Heap* h) { \ - NAME##_init_cap(m, h, HASHMAP_INIT_CAP); \ - } \ - \ - __attribute__((unused)) static inline void NAME##_fini(NAME* m) { \ - if (m->slots) \ - m->heap->free(m->heap, m->slots, sizeof(*m->slots) * m->cap); \ - m->slots = NULL; \ - m->cap = m->used = 0; \ - } \ - \ - __attribute__((unused)) static inline VT* NAME##_get(const NAME* m, KT k) { \ - u32 mask, j; \ - if (m->cap == 0 || !(k)) return NULL; \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) return &m->slots[j].v; \ - j = (j + 1u) & mask; \ - } \ - return NULL; \ - } \ - \ - __attribute__((unused)) static inline int NAME##_set(NAME* m, KT k, VT v) { \ - u32 mask, j; \ - if (m->cap == 0 || \ - m->used * HASHMAP_LOAD_DEN >= m->cap * HASHMAP_LOAD_NUM) \ - NAME##_resize(m, m->cap ? m->cap * 2u : HASHMAP_INIT_CAP); \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) { \ - m->slots[j].v = (v); \ - return 0; \ - } \ - j = (j + 1u) & mask; \ - } \ - m->slots[j].k = (k); \ - m->slots[j].v = (v); \ - m->used++; \ - return 1; \ - } \ - \ - /* Insert if absent. Returns 1 if newly inserted; 0 if k was present \ - * (in that case writes the existing value to *existing_out when \ - * existing_out is non-NULL). */ \ - __attribute__((unused)) static inline int NAME##_try_insert( \ - NAME* m, KT k, VT v, VT* existing_out) { \ - u32 mask, j; \ - if (m->cap == 0 || \ - m->used * HASHMAP_LOAD_DEN >= m->cap * HASHMAP_LOAD_NUM) \ - NAME##_resize(m, m->cap ? m->cap * 2u : HASHMAP_INIT_CAP); \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) { \ - if (existing_out) *existing_out = m->slots[j].v; \ - return 0; \ - } \ - j = (j + 1u) & mask; \ - } \ - m->slots[j].k = (k); \ - m->slots[j].v = (v); \ - m->used++; \ - return 1; \ - } \ - \ - __attribute__((unused)) static inline void NAME##_del(NAME* m, KT k) { \ - u32 mask, j; \ - if (m->cap == 0 || !(k)) return; \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) { \ - u32 i = (j + 1u) & mask; \ - m->slots[j].k = 0; \ - m->used--; \ - while (m->slots[i].k) { \ - KT rk = m->slots[i].k; \ - VT rv = m->slots[i].v; \ - u32 nh; \ - m->slots[i].k = 0; \ - m->used--; \ - nh = HASH_FN(rk) & mask; \ - while (m->slots[nh].k) nh = (nh + 1u) & mask; \ - m->slots[nh].k = rk; \ - m->slots[nh].v = rv; \ - m->used++; \ - i = (i + 1u) & mask; \ - } \ - return; \ - } \ - j = (j + 1u) & mask; \ - } \ - } \ - /* trailing struct decl swallows the macro-call's semicolon */ \ - struct NAME - -#endif diff --git a/include/core/heap.h b/include/core/heap.h @@ -1,16 +0,0 @@ -#ifndef CFREE_HEAP_H -#define CFREE_HEAP_H - -#include "core/core.h" - -/* CfreeHeap struct definition is in <cfree.h> (public). The host - * implements `alloc`/`realloc`/`free` and passes the heap in via - * CfreeEnv.heap. - * - * heap_mmap_exec is a libcfree-internal helper used only by the JIT path - * (mapped pages with PROT_EXEC available on flip). It is the one place - * inside libcfree that genuinely depends on host memory mapping; for now - * it stays internal until the JIT is wired up. */ -Heap* heap_mmap_exec(void); - -#endif diff --git a/include/core/pool.h b/include/core/pool.h @@ -1,40 +0,0 @@ -#ifndef CFREE_POOL_H -#define CFREE_POOL_H - -#include "core/arena.h" -#include "core/core.h" -#include "core/heap.h" - -typedef struct PoolEntry { - const char* data; - u32 len; - u32 hash; -} PoolEntry; - -struct Pool { - Heap* heap; - Arena arena; /* string storage */ - - /* Hash table: 0 means empty. Otherwise it's a Sym id (1-based). */ - Sym* table; - u32 cap; /* always a power of two */ - u32 used; - - /* Sym → string mapping. Index 0 reserved as Sym = 0 ("none"). */ - PoolEntry* entries; - u32 nentries; - u32 entries_cap; - - /* Frontends may hang language-specific interning state here. */ - void* type_cache; -}; - -void pool_init(Pool*, Heap*); -void pool_fini(Pool*); - -/* Strings. Returns canonical id; equal strings → equal ids. */ -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); - -#endif diff --git a/lang/c/abi/c_abi.c b/lang/c/abi/c_abi.c @@ -1,6 +1,6 @@ #include "abi/c_abi.h" -#include "core/pool.h" +#include <string.h> static int c_type_is_signed_integer(const Type* t) { if (!t) return 0; @@ -20,8 +20,33 @@ static int c_type_is_signed_integer(const Type* t) { } 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)); + CfreeCgTypeId id = type_cg_id(a, t); + CfreeCgTypeKind kind = cfree_cg_type_kind(a, id); + ABITypeInfo r; + memset(&r, 0, sizeof(r)); + r.size = (u32)cfree_cg_type_size(a, id); + r.align = cfree_cg_type_align(a, id); + switch (kind) { + case CFREE_CG_TYPE_VOID: + r.scalar_kind = ABI_SC_VOID; + break; + case CFREE_CG_TYPE_BOOL: + r.scalar_kind = ABI_SC_BOOL; + break; + case CFREE_CG_TYPE_INT: + case CFREE_CG_TYPE_ENUM: + r.scalar_kind = ABI_SC_INT; + break; + case CFREE_CG_TYPE_FLOAT: + r.scalar_kind = ABI_SC_FLOAT; + break; + case CFREE_CG_TYPE_PTR: + r.scalar_kind = ABI_SC_PTR; + break; + default: + r.scalar_kind = ABI_SC_VOID; + break; + } r.signed_ = c_type_is_signed_integer(t); return r; } @@ -34,18 +59,57 @@ 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 ABIRecordLayout* c_abi_record_layout(TargetABI* a, Pool* p, + const Type* t) { + CfreeCgTypeId id = type_cg_id_in_pool(a, p, t); + ABIRecordLayout* L; + ABIFieldLayout* fl = NULL; + u32 nfields; + if (cfree_cg_type_kind(a, id) != CFREE_CG_TYPE_RECORD) return NULL; + nfields = cfree_cg_type_record_nfields(a, id); + L = arena_znew(p->arena, ABIRecordLayout); + if (!L) return NULL; + if (nfields) { + fl = arena_zarray(p->arena, ABIFieldLayout, nfields); + if (!fl) return NULL; + for (u32 i = 0; i < nfields; ++i) { + CfreeCgField f; + uint64_t off = 0; + memset(&f, 0, sizeof(f)); + if (cfree_cg_type_record_field(a, id, i, &f, &off) != 0) return NULL; + fl[i].offset = (u32)off; + fl[i].storage_size = (u32)cfree_cg_type_size(a, f.type); + if (t->rec.fields[i].flags & FIELD_BITFIELD) { + fl[i].bit_width = t->rec.fields[i].bitfield_width; + } + } + } + L->size = (u32)cfree_cg_type_size(a, id); + L->align = cfree_cg_type_align(a, id); + L->nfields = nfields; + L->fields = fl; + return L; } -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)); +const ABIFuncInfo* c_abi_func_info(TargetABI* a, Pool* p, const Type* fn_type) { + CfreeCgTypeId id = type_cg_id_in_pool(a, p, fn_type); + ABIFuncInfo* info; + uint32_t nparams; + if (cfree_cg_type_kind(a, id) != CFREE_CG_TYPE_FUNC) return NULL; + nparams = cfree_cg_type_func_nparams(a, id); + info = arena_znew(p->arena, ABIFuncInfo); + if (!info) return NULL; + info->nparams = (u16)nparams; + if (nparams) { + info->params = arena_zarray(p->arena, ABIArgInfo, nparams); + if (!info->params) return NULL; + } + return info; } 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); + CfreeTarget target = cfree_compiler_target(a); + return target.ptr_size == 8 ? type_prim(p, TY_ULLONG) : type_prim(p, TY_UINT); } const Type* c_abi_size_type(TargetABI* a, Pool* p) { @@ -53,9 +117,8 @@ const Type* c_abi_size_type(TargetABI* a, Pool* 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); + CfreeTarget target = cfree_compiler_target(a); + return target.ptr_size == 8 ? type_prim(p, TY_LLONG) : type_prim(p, TY_INT); } const Type* c_abi_intptr_type(TargetABI* a, Pool* p) { @@ -67,8 +130,8 @@ const Type* c_abi_uintptr_type(TargetABI* a, Pool* p) { } const Type* c_abi_va_list_type(TargetABI* a, Pool* p) { - Compiler* c = abi_compiler(a); - switch (c->target.arch) { + CfreeTarget target = cfree_compiler_target(a); + switch (target.arch) { case CFREE_ARCH_X86_64: { const Type* vp = type_ptr(p, type_void(p)); const Type* uit = type_prim(p, TY_UINT); @@ -81,14 +144,14 @@ const Type* c_abi_va_list_type(TargetABI* a, Pool* p) { 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}); + 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) { + if (target.os == CFREE_OS_MACOS) { return type_ptr(p, type_prim(p, TY_CHAR)); } else { const Type* vp = type_ptr(p, type_void(p)); diff --git a/lang/c/abi/c_abi.h b/lang/c/abi/c_abi.h @@ -1,14 +1,54 @@ #ifndef CFREE_LANG_C_ABI_H #define CFREE_LANG_C_ABI_H -#include "abi/abi.h" +#include "c_support.h" #include "type/type.h" +typedef enum ABIScalarKind { + ABI_SC_VOID, + ABI_SC_BOOL, + ABI_SC_INT, + ABI_SC_FLOAT, + ABI_SC_PTR, +} ABIScalarKind; + +typedef struct ABITypeInfo { + u32 size; + u32 align; + u8 scalar_kind; + u8 signed_; + u8 atomic; + u8 pad; +} ABITypeInfo; + +typedef struct ABIFieldLayout { + u32 offset; + u16 bit_offset; + u16 bit_width; + u32 storage_size; +} ABIFieldLayout; + +typedef struct ABIRecordLayout { + u32 size; + u32 align; + u32 nfields; + const ABIFieldLayout* fields; +} ABIRecordLayout; + +typedef struct ABIArgInfo { + u8 dummy; +} ABIArgInfo; + +typedef struct ABIFuncInfo { + ABIArgInfo* params; + u16 nparams; +} ABIFuncInfo; + 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 ABIRecordLayout* c_abi_record_layout(TargetABI*, Pool*, const Type*); +const ABIFuncInfo* c_abi_func_info(TargetABI*, Pool*, const Type*); const Type* c_abi_size_type(TargetABI*, Pool*); const Type* c_abi_ptrdiff_type(TargetABI*, Pool*); diff --git a/lang/c/c.c b/lang/c/c.c @@ -2,7 +2,6 @@ #include <cfree/cg.h> -#include "core/pool.h" #include "decl/decl.h" #include "lex/lex.h" #include "parse/parse.h" @@ -38,18 +37,21 @@ 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; +typedef struct CPreprocessRun { + const CfreePpOptions* opts; + const CfreeBytesInput* input; + CfreeWriter* out; +} CPreprocessRun; + +static int c_preprocess_body(CfreeCompiler* c, void* user) { + CPreprocessRun* r = (CPreprocessRun*)user; Lexer* lex; Pp* pp; - compiler_panic_save(c, &saved); - if (setjmp(c->panic)) { - compiler_run_cleanups(c); - compiler_panic_restore(c, &saved); - return 1; - } + const CfreePpOptions* opts = r->opts; + const CfreeBytesInput* input = r->input; + CfreeWriter* out = r->out; + if (!opts || !input || !out) { c_bad_options(c, "preprocess args missing"); } @@ -60,27 +62,37 @@ int cfree_c_preprocess(CfreeCompiler* c, const CfreePpOptions* opts, lex = lex_open_mem(c, input->name, (const char*)input->data, input->len); pp = pp_new(c); + if (!lex || !pp) + compiler_panic(c, c_no_loc(), "C preprocessor out of memory"); 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; } +int cfree_c_preprocess(CfreeCompiler* c, const CfreePpOptions* opts, + const CfreeBytesInput* input, CfreeWriter* out) { + CPreprocessRun r; + r.opts = opts; + r.input = input; + r.out = out; + return cfree_frontend_run(c, c_preprocess_body, &r); +} + static void dump_write_str(CfreeWriter* w, const char* s) { size_t n = 0; while (s[n]) ++n; w->write(w, s, n); } -static void dump_write_sym(CfreeWriter* w, Pool* p, Sym sym) { +static void dump_write_sym(CfreeWriter* w, Compiler* c, Sym sym) { size_t len = 0; - const char* s = sym ? pool_str(p, sym, &len) : NULL; + const char* s = sym ? compiler_sym_str(c, sym, &len) : NULL; if (s && len) w->write(w, s, len); } -static void dump_emit(CfreeWriter* w, Pool* p, const Tok* t) { +static void dump_emit(CfreeWriter* w, Compiler* c, const Tok* t) { switch (t->kind) { case TOK_EOF: dump_write_str(w, "(eof)\n"); @@ -119,22 +131,22 @@ static void dump_emit(CfreeWriter* w, Pool* p, const Tok* t) { dump_write_str(w, "(unknown "); break; } - dump_write_sym(w, p, t->spelling); + dump_write_sym(w, c, t->spelling); dump_write_str(w, ")\n"); } -int cfree_c_dump_tokens(CfreeCompiler* c, const CfreeBytesInput* input, - CfreeWriter* out) { - PanicSave saved; +typedef struct CDumpTokensRun { + const CfreeBytesInput* input; + CfreeWriter* out; +} CDumpTokensRun; + +static int c_dump_tokens_body(CfreeCompiler* c, void* user) { + CDumpTokensRun* r = (CDumpTokensRun*)user; + const CfreeBytesInput* input = r->input; + CfreeWriter* out = r->out; 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"); } @@ -144,37 +156,51 @@ int cfree_c_dump_tokens(CfreeCompiler* c, const CfreeBytesInput* input, } lex = lex_open_mem(c, input->name, (const char*)input->data, input->len); + if (!lex) compiler_panic(c, c_no_loc(), "C lexer out of memory"); for (;;) { t = lex_next(lex); - dump_emit(out, c->global, &t); + dump_emit(out, c, &t); if (t.kind == TOK_EOF) break; } lex_close(lex); - compiler_panic_restore(c, &saved); return 0; } +int cfree_c_dump_tokens(CfreeCompiler* c, const CfreeBytesInput* input, + CfreeWriter* out) { + CDumpTokensRun r; + r.input = input; + r.out = out; + return cfree_frontend_run(c, c_dump_tokens_body, &r); +} + int cfree_c_compile(CfreeCompiler* c, const CfreeCompileOptions* opts, const CfreeBytesInput* input, CfreeObjBuilder* out) { + Pool* pool; Lexer* lex; Pp* pp; DeclTable* decls; CfreeCg* cg; + pool = c_pool_new(c); + if (!pool) compiler_panic(c, c_no_loc(), "C compiler out of memory"); lex = lex_open_mem(c, input->name, (const char*)input->data, input->len); pp = pp_new(c); - cg = cfree_cg_new(c, out); + cg = cfree_cg_new(c, out, opts); + if (!lex || !pp || !cg) + compiler_panic(c, c_no_loc(), "C compiler out of memory"); (void)out; decls = decl_new(c, cg); c_apply_pp_options(pp, &opts->pp); pp_push_input(pp, lex); - parse_c(c, pp, decls, cg); + parse_c(c, pool, pp, decls, cg); cfree_cg_free(cg); decl_free(decls); pp_free(pp); + c_pool_free(pool); return 0; } diff --git a/lang/c/c_support.h b/lang/c/c_support.h @@ -0,0 +1,97 @@ +#ifndef CFREE_LANG_C_SUPPORT_H +#define CFREE_LANG_C_SUPPORT_H + +#include <cfree/frontend.h> +#include <cfree/hashmap.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> + +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef CfreeCompiler Compiler; +typedef CfreeHeap Heap; +typedef CfreeWriter Writer; +typedef CfreeSym Sym; +typedef CfreeSrcLoc SrcLoc; +typedef CfreeCompiler TargetABI; +typedef u32 BytesId; + +typedef struct SrcRange { + SrcLoc begin; + SrcLoc end; +} SrcRange; + +typedef struct Pool { + Compiler* c; + CfreeArena* arena; + void* type_cache; +} Pool; + +static inline Pool* c_pool_new(Compiler* c) { + Heap* h = cfree_compiler_heap(c); + Pool* p = h ? (Pool*)h->alloc(h, sizeof(*p), _Alignof(Pool)) : NULL; + if (!p) return NULL; + p->c = c; + p->arena = cfree_arena_new(h, 0); + p->type_cache = NULL; + if (!p->arena) { + h->free(h, p, sizeof(*p)); + return NULL; + } + return p; +} + +static inline void c_pool_free(Pool* p) { + Heap* h; + if (!p) return; + h = cfree_compiler_heap(p->c); + cfree_arena_free(p->arena); + if (h) h->free(h, p, sizeof(*p)); +} + +static inline Sym pool_intern(Pool* p, const char* s, size_t len) { + return cfree_sym_intern_len(p->c, s, len); +} + +static inline Sym pool_intern_cstr(Pool* p, const char* s) { + return cfree_sym_intern(p->c, s); +} + +static inline const char* pool_str(Pool* p, Sym sym, size_t* len_out) { + return cfree_sym_str(p->c, sym, len_out); +} + +static inline const char* compiler_sym_str(Compiler* c, Sym sym, + size_t* len_out) { + return cfree_sym_str(c, sym, len_out); +} + +#define arena_alloc(a, size, align) cfree_arena_alloc((a), (size), (align)) +#define arena_zalloc(a, size, align) cfree_arena_zalloc((a), (size), (align)) +#define arena_strdup(a, s, len) cfree_arena_strdup((a), (s), (len)) +#define arena_new(a, T) cfree_arena_new_obj((a), T) +#define arena_znew(a, T) cfree_arena_znew_obj((a), T) +#define arena_array(a, T, n) cfree_arena_array((a), T, n) +#define arena_zarray(a, T, n) cfree_arena_zarray((a), T, n) + +_Noreturn static inline void compiler_panic(Compiler* c, SrcLoc loc, + const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + cfree_frontend_vfatal(c, loc, fmt, ap); +} + +_Noreturn static inline void compiler_panicv(Compiler* c, SrcLoc loc, + const char* fmt, va_list ap) { + cfree_frontend_vfatal(c, loc, fmt, ap); +} + +#endif diff --git a/lang/c/decl/decl.c b/lang/c/decl/decl.c @@ -18,10 +18,6 @@ #include <string.h> -#include "core/arena.h" -#include "core/core.h" -#include "core/heap.h" -#include "core/pool.h" #include "parse/cg_public_compat.h" struct DeclTable { @@ -35,7 +31,7 @@ struct DeclTable { #define DECL_INITIAL_CAP 16u static void decls_grow(DeclTable* t, u32 want) { - Heap* h = t->c->env->heap; + Heap* h = cfree_compiler_heap(t->c); u32 cap = t->cap; Decl* nb; if (cap >= want) return; @@ -50,7 +46,7 @@ static void decls_grow(DeclTable* t, u32 want) { } DeclTable* decl_new(Compiler* c, CfreeCg* cg) { - Heap* h = c->env->heap; + Heap* h = cfree_compiler_heap(c); DeclTable* t = (DeclTable*)h->alloc(h, sizeof(DeclTable), _Alignof(DeclTable)); memset(t, 0, sizeof *t); @@ -65,7 +61,7 @@ DeclTable* decl_new(Compiler* c, CfreeCg* cg) { void decl_free(DeclTable* t) { Heap* h; if (!t) return; - h = t->c->env->heap; + h = cfree_compiler_heap(t->c); if (t->slots) h->free(h, t->slots, sizeof(Decl) * t->cap); h->free(h, t, sizeof(*t)); } @@ -106,7 +102,8 @@ DeclId decl_declare(DeclTable* t, const Decl* in) { decl.type = pcg_tid(t->c, slot->type); decl.sym = decl_sym_attrs(slot); if (decl.kind == CFREE_CG_DECL_FUNC) { - if (slot->flags & DF_NORETURN) decl.as.func.flags |= CFREE_CG_FUNC_NORETURN; + if (slot->flags & DF_NORETURN) + decl.as.func.flags |= CFREE_CG_FUNC_NORETURN; decl.as.func.section = slot->section_id; } else { if (slot->flags & DF_THREAD) decl.as.object.flags |= CFREE_CG_OBJ_TLS; diff --git a/lang/c/decl/decl.h b/lang/c/decl/decl.h @@ -3,7 +3,7 @@ #include <cfree/cg.h> -#include "core/core.h" +#include "c_support.h" #include "type/type.h" #ifndef CFREE_OBJ_H @@ -74,7 +74,7 @@ typedef struct Decl { u8 pad; u32 flags; /* DeclFlag */ /* Phase 2 attribute carriers — populated by attr_list_to_decl. */ - u32 align; /* explicit alignment from _Alignas or aligned(N); 0=natural */ + u32 align; /* explicit alignment from _Alignas or aligned(N); 0=natural */ Sym alias_target; /* target name for __attribute__((alias("..."))); 0=none */ } Decl; diff --git a/lang/c/decl/decl_attrs.c b/lang/c/decl/decl_attrs.c @@ -2,8 +2,6 @@ #include <string.h> -#include "core/pool.h" - /* Bare `__attribute__((aligned))` (no argument) means "biggest scalar * alignment". cfree's targets all have `_Alignof(long double) == 16` * (x86_64 SysV, AArch64 AAPCS, RISC-V LP64D), so 16 is a valid v1 @@ -21,7 +19,7 @@ static void apply_visibility(Compiler* c, const Attr* a, Decl* out) { compiler_panic(c, a->loc, "visibility attribute missing argument"); } size_t n = 0; - const char* s = pool_str(c->global, a->v.sym, &n); + const char* s = compiler_sym_str(c, a->v.sym, &n); if (s && strcmp(s, "default") == 0) { out->visibility = SV_DEFAULT; } else if (s && strcmp(s, "hidden") == 0) { diff --git a/lang/c/decl/decl_attrs.h b/lang/c/decl/decl_attrs.h @@ -1,7 +1,6 @@ #ifndef CFREE_DECL_ATTRS_H #define CFREE_DECL_ATTRS_H -#include "core/core.h" #include "decl/decl.h" #include "parse/attr.h" diff --git a/lang/c/lex/lex.c b/lang/c/lex/lex.c @@ -16,9 +16,6 @@ #include <string.h> -#include "core/heap.h" -#include "core/pool.h" - struct Lexer { Compiler* c; Pool* pool; @@ -126,17 +123,21 @@ static SrcLoc lex_here(const Lexer* l) { Lexer* lex_open_mem(Compiler* c, const char* name, const char* src, size_t len) { - Heap* h = (Heap*)c->env->heap; + Heap* h = (Heap*)cfree_compiler_heap(c); Lexer* l = (Lexer*)h->alloc(h, sizeof(*l), _Alignof(Lexer)); if (!l) return NULL; memset(l, 0, sizeof(*l)); l->c = c; - l->pool = c->global; + l->pool = c_pool_new(c); + if (!l->pool) { + h->free(h, l, sizeof(*l)); + return NULL; + } l->heap = h; l->src = src ? src : ""; l->len = src ? len : 0; l->pos = 0; - l->file_id = source_add_memory(c->sources, name); + l->file_id = cfree_source_add_memory(c, name); l->line = 1; l->col = 1; l->at_bol = 1; @@ -146,6 +147,7 @@ Lexer* lex_open_mem(Compiler* c, const char* name, const char* src, void lex_close(Lexer* l) { if (!l) return; + c_pool_free(l->pool); l->heap->free(l->heap, l, sizeof(*l)); } @@ -488,15 +490,27 @@ Tok lex_next(Lexer* l) { size_t j = k; while (j > 0) { char c = pbuf[j - 1]; - if (c == 'f' || c == 'F') { t.flags |= TF_FLT_F; --j; continue; } - if (c == 'l' || c == 'L') { t.flags |= TF_FLT_L; --j; continue; } + if (c == 'f' || c == 'F') { + t.flags |= TF_FLT_F; + --j; + continue; + } + if (c == 'l' || c == 'L') { + t.flags |= TF_FLT_L; + --j; + continue; + } break; } } else { size_t j = k; while (j > 0) { char c = pbuf[j - 1]; - if (c == 'u' || c == 'U') { t.flags |= TF_INT_U; --j; continue; } + if (c == 'u' || c == 'U') { + t.flags |= TF_INT_U; + --j; + continue; + } if (c == 'l' || c == 'L') { if (j >= 2 && (pbuf[j - 2] == 'l' || pbuf[j - 2] == 'L')) { t.flags |= TF_INT_LL; diff --git a/lang/c/lex/lex.h b/lang/c/lex/lex.h @@ -1,7 +1,7 @@ #ifndef CFREE_LEX_H #define CFREE_LEX_H -#include "core/core.h" +#include "c_support.h" typedef enum TokKind { TOK_EOF = 0, diff --git a/lang/c/parse/attr.h b/lang/c/parse/attr.h @@ -1,7 +1,7 @@ #ifndef CFREE_PARSE_ATTR_H #define CFREE_PARSE_ATTR_H -#include "core/core.h" +#include "c_support.h" /* GNU __attribute__((...)) AST node, shared between the parser (producer) * and the declaration-attribute consumers. The parser builds diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -1,7 +1,7 @@ -#include "parse/parse_priv.h" - #include <string.h> +#include "parse/parse_priv.h" + CfreeCgTypeId pcg_tid(Compiler* c, const Type* ty) { return type_cg_id(c, ty); } static u32 pcg_sizeof(Parser* p, const Type* ty) { @@ -27,7 +27,7 @@ static void pcg_stack_grow(Parser* p, u32 want) { if (p->cg_type_cap >= want) return; nc = p->cg_type_cap ? p->cg_type_cap * 2u : 64u; while (nc < want) nc *= 2u; - ns = arena_array(p->c->tu, const Type*, nc); + ns = arena_array(p->pool->arena, const Type*, nc); if (!ns) perr(p, "out of memory in CG type stack"); if (p->cg_type_stack && p->cg_type_sp) { memcpy(ns, p->cg_type_stack, sizeof(*ns) * p->cg_type_sp); @@ -53,8 +53,7 @@ void pcg_dup_type(Parser* p) { void pcg_swap_type(Parser* p) { if (p->cg_type_sp >= 2) { const Type* a = p->cg_type_stack[p->cg_type_sp - 1u]; - p->cg_type_stack[p->cg_type_sp - 1u] = - p->cg_type_stack[p->cg_type_sp - 2u]; + p->cg_type_stack[p->cg_type_sp - 1u] = p->cg_type_stack[p->cg_type_sp - 2u]; p->cg_type_stack[p->cg_type_sp - 2u] = a; } } @@ -62,10 +61,8 @@ void pcg_swap_type(Parser* p) { void pcg_rot3_type(Parser* p) { if (p->cg_type_sp >= 3) { const Type* a = p->cg_type_stack[p->cg_type_sp - 3u]; - p->cg_type_stack[p->cg_type_sp - 3u] = - p->cg_type_stack[p->cg_type_sp - 2u]; - p->cg_type_stack[p->cg_type_sp - 2u] = - p->cg_type_stack[p->cg_type_sp - 1u]; + p->cg_type_stack[p->cg_type_sp - 3u] = p->cg_type_stack[p->cg_type_sp - 2u]; + p->cg_type_stack[p->cg_type_sp - 2u] = p->cg_type_stack[p->cg_type_sp - 1u]; p->cg_type_stack[p->cg_type_sp - 1u] = a; } } @@ -106,70 +103,114 @@ int pcg_type_is_signed(const Type* ty) { CfreeCgIntBinOp pcg_int_binop(BinOp op) { switch (op) { - case BO_IADD: return CFREE_CG_INT_ADD; - case BO_ISUB: return CFREE_CG_INT_SUB; - case BO_IMUL: return CFREE_CG_INT_MUL; - case BO_SDIV: return CFREE_CG_INT_SDIV; - case BO_UDIV: return CFREE_CG_INT_UDIV; - case BO_SREM: return CFREE_CG_INT_SREM; - case BO_UREM: return CFREE_CG_INT_UREM; - case BO_AND: return CFREE_CG_INT_AND; - case BO_OR: return CFREE_CG_INT_OR; - case BO_XOR: return CFREE_CG_INT_XOR; - case BO_SHL: return CFREE_CG_INT_SHL; - case BO_SHR_S: return CFREE_CG_INT_ASHR; - case BO_SHR_U: return CFREE_CG_INT_LSHR; - default: return CFREE_CG_INT_ADD; + case BO_IADD: + return CFREE_CG_INT_ADD; + case BO_ISUB: + return CFREE_CG_INT_SUB; + case BO_IMUL: + return CFREE_CG_INT_MUL; + case BO_SDIV: + return CFREE_CG_INT_SDIV; + case BO_UDIV: + return CFREE_CG_INT_UDIV; + case BO_SREM: + return CFREE_CG_INT_SREM; + case BO_UREM: + return CFREE_CG_INT_UREM; + case BO_AND: + return CFREE_CG_INT_AND; + case BO_OR: + return CFREE_CG_INT_OR; + case BO_XOR: + return CFREE_CG_INT_XOR; + case BO_SHL: + return CFREE_CG_INT_SHL; + case BO_SHR_S: + return CFREE_CG_INT_ASHR; + case BO_SHR_U: + return CFREE_CG_INT_LSHR; + default: + return CFREE_CG_INT_ADD; } } CfreeCgFpBinOp pcg_fp_binop(BinOp op) { switch (op) { - case BO_FADD: return CFREE_CG_FP_ADD; - case BO_FSUB: return CFREE_CG_FP_SUB; - case BO_FMUL: return CFREE_CG_FP_MUL; - case BO_FDIV: return CFREE_CG_FP_DIV; - default: return CFREE_CG_FP_ADD; + case BO_FADD: + return CFREE_CG_FP_ADD; + case BO_FSUB: + return CFREE_CG_FP_SUB; + case BO_FMUL: + return CFREE_CG_FP_MUL; + case BO_FDIV: + return CFREE_CG_FP_DIV; + default: + return CFREE_CG_FP_ADD; } } CfreeCgIntCmpOp pcg_int_cmp(CmpOp op) { switch (op) { - case CMP_EQ: return CFREE_CG_INT_EQ; - case CMP_NE: return CFREE_CG_INT_NE; - case CMP_LT_S: return CFREE_CG_INT_LT_S; - case CMP_LE_S: return CFREE_CG_INT_LE_S; - case CMP_GT_S: return CFREE_CG_INT_GT_S; - case CMP_GE_S: return CFREE_CG_INT_GE_S; - case CMP_LT_U: return CFREE_CG_INT_LT_U; - case CMP_LE_U: return CFREE_CG_INT_LE_U; - case CMP_GT_U: return CFREE_CG_INT_GT_U; - case CMP_GE_U: return CFREE_CG_INT_GE_U; - default: return CFREE_CG_INT_EQ; + case CMP_EQ: + return CFREE_CG_INT_EQ; + case CMP_NE: + return CFREE_CG_INT_NE; + case CMP_LT_S: + return CFREE_CG_INT_LT_S; + case CMP_LE_S: + return CFREE_CG_INT_LE_S; + case CMP_GT_S: + return CFREE_CG_INT_GT_S; + case CMP_GE_S: + return CFREE_CG_INT_GE_S; + case CMP_LT_U: + return CFREE_CG_INT_LT_U; + case CMP_LE_U: + return CFREE_CG_INT_LE_U; + case CMP_GT_U: + return CFREE_CG_INT_GT_U; + case CMP_GE_U: + return CFREE_CG_INT_GE_U; + default: + return CFREE_CG_INT_EQ; } } CfreeCgFpCmpOp pcg_fp_cmp(CmpOp op) { switch (op) { - case CMP_EQ: return CFREE_CG_FP_OEQ; - case CMP_NE: return CFREE_CG_FP_ONE; - case CMP_LT_F: return CFREE_CG_FP_OLT; - case CMP_LE_F: return CFREE_CG_FP_OLE; - case CMP_GT_F: return CFREE_CG_FP_OGT; - case CMP_GE_F: return CFREE_CG_FP_OGE; - default: return CFREE_CG_FP_OEQ; + case CMP_EQ: + return CFREE_CG_FP_OEQ; + case CMP_NE: + return CFREE_CG_FP_ONE; + case CMP_LT_F: + return CFREE_CG_FP_OLT; + case CMP_LE_F: + return CFREE_CG_FP_OLE; + case CMP_GT_F: + return CFREE_CG_FP_OGT; + case CMP_GE_F: + return CFREE_CG_FP_OGE; + default: + return CFREE_CG_FP_OEQ; } } CfreeCgAtomicOp pcg_atomic_op(AtomicOp op) { switch (op) { - case AO_XCHG: return CFREE_CG_ATOMIC_XCHG; - case AO_ADD: return CFREE_CG_ATOMIC_ADD; - case AO_SUB: return CFREE_CG_ATOMIC_SUB; - case AO_AND: return CFREE_CG_ATOMIC_AND; - case AO_OR: return CFREE_CG_ATOMIC_OR; - case AO_XOR: return CFREE_CG_ATOMIC_XOR; - case AO_NAND: return CFREE_CG_ATOMIC_NAND; + case AO_XCHG: + return CFREE_CG_ATOMIC_XCHG; + case AO_ADD: + return CFREE_CG_ATOMIC_ADD; + case AO_SUB: + return CFREE_CG_ATOMIC_SUB; + case AO_AND: + return CFREE_CG_ATOMIC_AND; + case AO_OR: + return CFREE_CG_ATOMIC_OR; + case AO_XOR: + return CFREE_CG_ATOMIC_XOR; + case AO_NAND: + return CFREE_CG_ATOMIC_NAND; } return CFREE_CG_ATOMIC_XCHG; } @@ -301,10 +342,12 @@ void pcg_convert(Parser* p, const Type* dst) { return; } if (si && di) { - if (ds < ss) cfree_cg_trunc(p->cg, id); + if (ds < ss) + cfree_cg_trunc(p->cg, id); else if (ds > ss && type_is_int(src) && pcg_type_is_signed(src)) cfree_cg_sext(p->cg, id); - else if (ds > ss) cfree_cg_zext(p->cg, id); + else if (ds > ss) + cfree_cg_zext(p->cg, id); } else if (type_is_int(src) && df) { if (pcg_type_is_signed(src)) cfree_cg_sint_to_float(p->cg, id, CFREE_CG_ROUND_DEFAULT); @@ -316,8 +359,10 @@ void pcg_convert(Parser* p, const Type* dst) { else cfree_cg_float_to_uint(p->cg, id, CFREE_CG_ROUND_DEFAULT); } else if (sf && df) { - if (ds > ss) cfree_cg_fpext(p->cg, id); - else if (ds < ss) cfree_cg_fptrunc(p->cg, id); + if (ds > ss) + cfree_cg_fpext(p->cg, id); + else if (ds < ss) + cfree_cg_fptrunc(p->cg, id); } else { cfree_cg_bitcast(p->cg, id); } @@ -396,17 +441,19 @@ void pcg_fence(Parser* p, MemOrder ord) { } void pcg_intrinsic_unary_to_int(Parser* p, IntrinKind k) { - CfreeCgIntrinsic ck = k == INTRIN_CLZ ? CFREE_CG_INTRIN_CLZ - : k == INTRIN_CTZ ? CFREE_CG_INTRIN_CTZ - : CFREE_CG_INTRIN_POPCOUNT; + CfreeCgIntrinsic ck = k == INTRIN_CLZ ? CFREE_CG_INTRIN_CLZ + : k == INTRIN_CTZ ? CFREE_CG_INTRIN_CTZ + : CFREE_CG_INTRIN_POPCOUNT; const Type* ity = type_prim(p->pool, TY_INT); cfree_cg_intrinsic(p->cg, ck, 1, pcg_tid(p->c, ity)); pcg_retag_top(p, ity); } void pcg_intrinsic_void(Parser* p, IntrinKind k) { - if (k == INTRIN_UNREACHABLE) cfree_cg_unreachable(p->cg); - else cfree_cg_intrinsic(p->cg, CFREE_CG_INTRIN_TRAP, 0, CFREE_CG_TYPE_NONE); + if (k == INTRIN_UNREACHABLE) + cfree_cg_unreachable(p->cg); + else + cfree_cg_intrinsic(p->cg, CFREE_CG_INTRIN_TRAP, 0, CFREE_CG_TYPE_NONE); } void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, @@ -419,7 +466,7 @@ void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, memset(&a, 0, sizeof a); a.tmpl = cfree_sym_intern(p->c, tmpl ? tmpl : ""); if (nout) { - o = arena_zarray(p->c->tu, CfreeCgAsmOperand, nout); + o = arena_zarray(p->pool->arena, CfreeCgAsmOperand, nout); for (u32 i = 0; i < nout; ++i) { o[i].constraint = cfree_sym_intern(p->c, outs[i].str ? outs[i].str : ""); o[i].name = outs[i].name; @@ -428,17 +475,17 @@ void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, } } if (nin) { - in = arena_zarray(p->c->tu, CfreeCgAsmOperand, nin); + in = arena_zarray(p->pool->arena, CfreeCgAsmOperand, nin); for (u32 i = 0; i < nin; ++i) { in[i].constraint = cfree_sym_intern(p->c, ins[i].str ? ins[i].str : ""); in[i].name = ins[i].name; in[i].type = pcg_tid(p->c, ins[i].type); - in[i].dir = (ins[i].dir == ASM_INOUT) ? CFREE_CG_ASM_INOUT - : CFREE_CG_ASM_IN; + in[i].dir = + (ins[i].dir == ASM_INOUT) ? CFREE_CG_ASM_INOUT : CFREE_CG_ASM_IN; } } if (nclob) { - cl = arena_array(p->c->tu, CfreeSym, nclob); + cl = arena_array(p->pool->arena, CfreeSym, nclob); for (u32 i = 0; i < nclob; ++i) cl[i] = clobbers[i]; } a.outputs = o; diff --git a/lang/c/parse/cg_public_compat.h b/lang/c/parse/cg_public_compat.h @@ -3,7 +3,7 @@ #include <cfree/cg.h> -#include "core/core.h" +#include "c_support.h" #include "type/type.h" typedef CfreeCg CG; @@ -226,20 +226,20 @@ void pcg_inline_asm(Parser*, const char*, const AsmConstraint*, u32, #define cg_push_global(g, sym, ty) pcg_push_global(p, (sym), (ty)) #define cg_load(g) pcg_load(p) #define cg_addr(g) pcg_addr(p) -#define cg_dup(g) \ - do { \ - cfree_cg_dup((g)); \ - pcg_dup_type(p); \ +#define cg_dup(g) \ + do { \ + cfree_cg_dup((g)); \ + pcg_dup_type(p); \ } while (0) -#define cg_swap(g) \ - do { \ - cfree_cg_swap((g)); \ - pcg_swap_type(p); \ +#define cg_swap(g) \ + do { \ + cfree_cg_swap((g)); \ + pcg_swap_type(p); \ } while (0) -#define cg_drop(g) \ - do { \ - cfree_cg_drop((g)); \ - pcg_drop_type(p); \ +#define cg_drop(g) \ + do { \ + cfree_cg_drop((g)); \ + pcg_drop_type(p); \ } while (0) #define cg_store(g) pcg_store(p) #define cg_deref(g, ty) pcg_deref(p, (ty)) @@ -268,15 +268,15 @@ void pcg_inline_asm(Parser*, const char*, const AsmConstraint*, u32, #define cg_label_new(g) cfree_cg_label_new((g)) #define cg_label_place(g, l) cfree_cg_label_place((g), (l)) #define cg_jump(g, l) cfree_cg_jump((g), (l)) -#define cg_branch_true(g, l) \ - do { \ +#define cg_branch_true(g, l) \ + do { \ cfree_cg_branch_true((g), (l)); \ - pcg_drop_type(p); \ + pcg_drop_type(p); \ } while (0) -#define cg_branch_false(g, l) \ - do { \ +#define cg_branch_false(g, l) \ + do { \ cfree_cg_branch_false((g), (l)); \ - pcg_drop_type(p); \ + pcg_drop_type(p); \ } while (0) #define cg_inline_asm(g, tmpl, outs, nout, ins, nin, clob, nclob) \ pcg_inline_asm(p, (tmpl), (outs), (nout), (ins), (nin), (clob), (nclob)) diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c @@ -15,26 +15,63 @@ * All expression, type, initializer, and statement code lives in * parse_expr.c, parse_type.c, parse_init.c, and parse_stmt.c. */ -#include "parse/parse_priv.h" - #include <stdarg.h> #include <string.h> +#include "parse/parse_priv.h" + /* ============================================================ * Keywords * ============================================================ */ static const char* const kw_names[KW_COUNT] = { - NULL, "auto", "break", "case", "char", - "const", "continue", "default", "do", "double", - "else", "enum", "extern", "float", "for", - "goto", "if", "inline", "int", "long", - "register", "restrict", "return", "short", "signed", - "sizeof", "static", "struct", "switch", "typedef", - "union", "unsigned", "void", "volatile", "while", - "_Bool", "_Complex", "_Imaginary","_Alignas", "_Alignof", - "_Atomic", "_Generic", "_Noreturn", "_Static_assert", "_Thread_local", - "asm", "__asm__", + NULL, + "auto", + "break", + "case", + "char", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extern", + "float", + "for", + "goto", + "if", + "inline", + "int", + "long", + "register", + "restrict", + "return", + "short", + "signed", + "sizeof", + "static", + "struct", + "switch", + "typedef", + "union", + "unsigned", + "void", + "volatile", + "while", + "_Bool", + "_Complex", + "_Imaginary", + "_Alignas", + "_Alignof", + "_Atomic", + "_Generic", + "_Noreturn", + "_Static_assert", + "_Thread_local", + "asm", + "__asm__", }; /* ============================================================ @@ -62,8 +99,7 @@ static size_t str_prefix_len(u16 flags) { return 0; } -#define STR_ENC_MASK \ - (TF_STR_WIDE | TF_STR_U8 | TF_STR_U16 | TF_STR_U32) +#define STR_ENC_MASK (TF_STR_WIDE | TF_STR_U8 | TF_STR_U16 | TF_STR_U32) /* Fuse two adjacent TOK_STR tokens into one per C11 §6.4.5 ¶5. */ static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { @@ -77,14 +113,15 @@ static Tok fuse_string_lits(Parser* p, Tok a, Tok b) { size_t a_content_len, b_content_len; size_t out_pfx_len; size_t out_len; - Heap* h = p->c->env->heap; + Heap* h = cfree_compiler_heap(p->c); char* buf; size_t k = 0; Tok out; if (!as || !bs) perr(p, "bad string literal in concatenation"); if (ae != 0 && be != 0 && ae != be) { - perr(p, "concatenating string literals with incompatible " - "encoding prefixes"); + perr(p, + "concatenating string literals with incompatible " + "encoding prefixes"); } fused_enc = ae ? ae : be; apfx = str_prefix_len(a.flags); @@ -193,7 +230,7 @@ void record_braced_block(Parser* p) { for (;;) { if (p->replay_len == p->replay_cap) { u32 new_cap = p->replay_cap ? p->replay_cap * 2 : 32; - Tok* nv = arena_array(p->c->tu, Tok, new_cap); + Tok* nv = arena_array(p->pool->arena, Tok, new_cap); if (!nv) perr(p, "out of memory in record_braced_block"); if (p->replay && p->replay_len) { memcpy(nv, p->replay, p->replay_len * sizeof(Tok)); @@ -233,9 +270,12 @@ u32 count_recorded_top_level_items(const Tok* vec, u32 len) { count = 1; for (i = 1; i < len - 1; ++i) { const Tok* t = &vec[i]; - if (is_punct(t, '{') || is_punct(t, '(') || is_punct(t, '[')) ++depth; - else if (is_punct(t, '}') || is_punct(t, ')') || is_punct(t, ']')) --depth; - else if (depth == 0 && is_punct(t, ',')) ++count; + if (is_punct(t, '{') || is_punct(t, '(') || is_punct(t, '[')) + ++depth; + else if (is_punct(t, '}') || is_punct(t, ')') || is_punct(t, ']')) + --depth; + else if (depth == 0 && is_punct(t, ',')) + ++count; } if (is_punct(&vec[len - 2], ',')) --count; return count; @@ -246,7 +286,7 @@ u32 count_recorded_top_level_items(const Tok* vec, u32 len) { * ============================================================ */ Scope* scope_new(Parser* p, Scope* parent) { - Scope* s = arena_new(p->c->tu, Scope); + Scope* s = arena_new(p->pool->arena, Scope); if (!s) perr(p, "out of memory in scope_new"); s->entries = NULL; s->tags = NULL; @@ -262,7 +302,7 @@ void scope_pop(Parser* p) { SymEntry* scope_define(Parser* p, Sym name, SymEntryKind kind, const Type* type) { - SymEntry* e = arena_new(p->c->tu, SymEntry); + SymEntry* e = arena_new(p->pool->arena, SymEntry); if (!e) perr(p, "out of memory in scope_define"); memset(e, 0, sizeof *e); e->name = name; @@ -286,7 +326,7 @@ SymEntry* scope_lookup(Parser* p, Sym name) { TagEntry* tag_define(Parser* p, Sym name, TagDeclKind kind, Type* type, int complete) { - TagEntry* e = arena_new(p->c->tu, TagEntry); + TagEntry* e = arena_new(p->pool->arena, TagEntry); if (!e) perr(p, "out of memory in tag_define"); memset(e, 0, sizeof *e); e->name = name; @@ -329,8 +369,8 @@ static const Type* ty_size_t(Parser* p) { * Local-variable slot allocation * ============================================================ */ -FrameSlot make_local_aligned(Parser* p, Sym name, const Type* type, - SrcLoc loc, u32 align_override) { +FrameSlot make_local_aligned(Parser* p, Sym name, const Type* type, SrcLoc loc, + u32 align_override) { FrameSlotDesc fsd; FrameSlot s; SymEntry* e; @@ -454,7 +494,8 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { e = scope_define(p, name, SEK_GLOBAL, var_ty); e->v.sym = sym; has_init = accept_punct(p, '='); - if (has_init && var_ty && var_ty->kind == TY_ARRAY && var_ty->arr.incomplete) { + if (has_init && var_ty && var_ty->kind == TY_ARRAY && + var_ty->arr.incomplete) { const Type* completed = complete_incomplete_array(p, var_ty); if (completed != var_ty) { var_ty = completed; @@ -553,7 +594,8 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { { int has_init = is_punct(&p->cur, '='); FrameSlot s; - if (has_init && var_ty && var_ty->kind == TY_ARRAY && var_ty->arr.incomplete) { + if (has_init && var_ty && var_ty->kind == TY_ARRAY && + var_ty->arr.incomplete) { advance(p); /* '=' */ var_ty = complete_incomplete_array(p, var_ty); s = make_local_aligned(p, name, var_ty, loc, specs->align); @@ -569,7 +611,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { parse_assign_expr(p); emit_struct_copy_into_slot(p, s, var_ty, 0, var_ty); } else if (var_ty->kind == TY_ARRAY || var_ty->kind == TY_STRUCT || - var_ty->kind == TY_UNION) { + var_ty->kind == TY_UNION) { init_at(p, s, var_ty, 0, var_ty); } else { cg_push_local_typed(p->cg, s, var_ty); @@ -616,7 +658,7 @@ void parse_param_list(Parser* p, ParamInfo** infos_out, u16* nparams_out, } } - infos = (ParamInfo*)arena_array(p->c->tu, ParamInfo, cap); + infos = (ParamInfo*)arena_array(p->pool->arena, ParamInfo, cap); for (;;) { DeclSpecs specs; Sym pname = 0; @@ -640,7 +682,7 @@ void parse_param_list(Parser* p, ParamInfo** infos_out, u16* nparams_out, } if (n == cap) { cap *= 2; - ParamInfo* nbuf = (ParamInfo*)arena_array(p->c->tu, ParamInfo, cap); + ParamInfo* nbuf = (ParamInfo*)arena_array(p->pool->arena, ParamInfo, cap); memcpy(nbuf, infos, sizeof(ParamInfo) * n); infos = nbuf; } @@ -656,10 +698,8 @@ void parse_param_list(Parser* p, ParamInfo** infos_out, u16* nparams_out, static SymEntry* declare_function(Parser* p, Sym fname, const Type* fn_ty, const DeclSpecs* specs, SrcLoc fname_loc, - const Attr* dattrs, - ObjSecId* out_section_id, - u32* out_decl_flags, - Sym* out_alias_target) { + const Attr* dattrs, ObjSecId* out_section_id, + u32* out_decl_flags, Sym* out_alias_target) { if (out_section_id) *out_section_id = OBJ_SEC_NONE; if (out_decl_flags) *out_decl_flags = 0; if (out_alias_target) *out_alias_target = 0; @@ -684,8 +724,7 @@ static SymEntry* declare_function(Parser* p, Sym fname, const Type* fn_ty, decl_in.type = fn_ty; decl_in.loc = fname_loc; decl_in.storage = (specs->storage == DS_STATIC) ? DS_STATIC : DS_EXTERN; - decl_in.linkage = - (specs->storage == DS_STATIC) ? DL_INTERNAL : DL_EXTERNAL; + decl_in.linkage = (specs->storage == DS_STATIC) ? DL_INTERNAL : DL_EXTERNAL; decl_in.visibility = SV_DEFAULT; attr_list_to_decl(p->c, p->decls, specs->attrs, &decl_in); attr_list_to_decl(p->c, p->decls, dattrs, &decl_in); @@ -719,7 +758,7 @@ static void parse_function_body(Parser* p, ObjSymId fsym, const Type* fn_ty, if (decl_flags & DF_NORETURN) fd.flags |= CGFD_NORETURN; if (nparams) { - pds = (CGParamDesc*)arena_array(p->c->tu, CGParamDesc, nparams); + pds = (CGParamDesc*)arena_array(p->pool->arena, CGParamDesc, nparams); memset(pds, 0, sizeof(CGParamDesc) * nparams); for (u16 i = 0; i < nparams; ++i) { pds[i].index = i; @@ -798,9 +837,9 @@ static void parse_external_decl(Parser* p) { for (;;) { Sym tname = 0; SrcLoc tloc = {0, 0, 0}; - const Type* tty = parse_declarator_full(p, specs.type, - /*allow_abstract=*/0, - &tname, &tloc); + const Type* tty = + parse_declarator_full(p, specs.type, + /*allow_abstract=*/0, &tname, &tloc); if (is_punct(&p->cur, '=')) { perr(p, "typedef declarator cannot have initializer"); } @@ -813,7 +852,8 @@ static void parse_external_decl(Parser* p) { } base_ty = parse_pointer_layer(p, specs.type); - if (p->cur.kind != TOK_IDENT || ident_kw_inline(p, p->cur.v.ident) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, p->cur.v.ident) != KW_NONE) { perr(p, "expected declarator"); } name = p->cur.v.ident; @@ -846,18 +886,17 @@ static void parse_external_decl(Parser* p) { parse_attrs_into(p, &dattrs); if (nparams) { - ptypes = (const Type**)arena_array(p->c->tu, const Type*, nparams); + ptypes = (const Type**)arena_array(p->pool->arena, const Type*, nparams); 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 = c_abi_func_info(p->abi, fn_ty); + abi = c_abi_func_info(p->abi, p->pool, fn_ty); ObjSecId fn_section_id; u32 fn_decl_flags; Sym fn_alias_target; - fent = declare_function(p, name, fn_ty, &specs, loc, dattrs, - &fn_section_id, &fn_decl_flags, - &fn_alias_target); + fent = declare_function(p, name, fn_ty, &specs, loc, dattrs, &fn_section_id, + &fn_decl_flags, &fn_alias_target); attr_list_append(&fent->attrs, dattrs); if (is_punct(&p->cur, '{')) { @@ -874,8 +913,7 @@ static void parse_external_decl(Parser* p) { if (!te) { size_t nl = 0; const char* nm = pool_str(p->pool, fn_alias_target, &nl); - compiler_panic(p->c, loc, - "alias target '%s' is undefined", + compiler_panic(p->c, loc, "alias target '%s' is undefined", nm ? nm : "?"); } CfreeCgAlias alias; @@ -883,14 +921,13 @@ static void parse_external_decl(Parser* p) { alias.display_name = name; alias.linkage_name = cfree_cg_c_linkage_name(p->c, name); alias.target = te->v.sym; - alias.sym.bind = (fn_decl_flags & DF_WEAK) ? CFREE_SB_WEAK - : CFREE_SB_GLOBAL; + alias.sym.bind = + (fn_decl_flags & DF_WEAK) ? CFREE_SB_WEAK : CFREE_SB_GLOBAL; alias.sym.visibility = CFREE_CG_VIS_DEFAULT; if (cfree_cg_alias(p->cg, alias) == CFREE_CG_SYM_NONE) { size_t nl = 0; const char* nm = pool_str(p->pool, fn_alias_target, &nl); - compiler_panic(p->c, loc, - "alias target '%s' is undefined", + compiler_panic(p->c, loc, "alias target '%s' is undefined", nm ? nm : "?"); } } @@ -960,17 +997,16 @@ static void parse_external_decl(Parser* p) { } } define_static_object(p, sym, section_id, base_ty, specs.quals, - /*has_init=*/1, loc, - align_eff); + /*has_init=*/1, loc, align_eff); } else if (!is_pure_extern) { define_static_object(p, sym, section_id, base_ty, specs.quals, - /*has_init=*/0, loc, - align_eff); + /*has_init=*/0, loc, align_eff); } if (!accept_punct(p, ',')) break; base_ty = parse_pointer_layer(p, specs.type); - if (p->cur.kind != TOK_IDENT || ident_kw_inline(p, p->cur.v.ident) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_inline(p, p->cur.v.ident) != KW_NONE) { perr(p, "expected declarator after ','"); } name = p->cur.v.ident; @@ -1033,7 +1069,7 @@ static void parse_translation_unit(Parser* p) { * Entry point * ============================================================ */ -void parse_c(Compiler* c, Pp* pp, DeclTable* decls, CG* cg) { +void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg) { Parser p; CKw i; @@ -1042,51 +1078,51 @@ void parse_c(Compiler* c, Pp* pp, DeclTable* decls, CG* cg) { p.pp = pp; p.decls = decls; p.cg = cg; - p.abi = c->abi; - p.pool = c->global; + p.abi = c; + p.pool = pool; for (i = (CKw)1; i < KW_COUNT; ++i) { p.kw_sym[i] = pool_intern_cstr(p.pool, kw_names[i]); } - p.sym_b_alloca = pool_intern_cstr(p.pool, "__builtin_alloca"); - p.sym_b_ctz = pool_intern_cstr(p.pool, "__builtin_ctz"); - p.sym_b_clz = pool_intern_cstr(p.pool, "__builtin_clz"); - p.sym_b_clzl = pool_intern_cstr(p.pool, "__builtin_clzl"); - p.sym_b_clzll = pool_intern_cstr(p.pool, "__builtin_clzll"); - p.sym_b_trap = pool_intern_cstr(p.pool, "__builtin_trap"); + p.sym_b_alloca = pool_intern_cstr(p.pool, "__builtin_alloca"); + p.sym_b_ctz = pool_intern_cstr(p.pool, "__builtin_ctz"); + p.sym_b_clz = pool_intern_cstr(p.pool, "__builtin_clz"); + p.sym_b_clzl = pool_intern_cstr(p.pool, "__builtin_clzl"); + p.sym_b_clzll = pool_intern_cstr(p.pool, "__builtin_clzll"); + p.sym_b_trap = pool_intern_cstr(p.pool, "__builtin_trap"); p.sym_b_unreachable = pool_intern_cstr(p.pool, "__builtin_unreachable"); - p.sym_b_memcpy = pool_intern_cstr(p.pool, "__builtin_memcpy"); - p.sym_b_memmove = pool_intern_cstr(p.pool, "__builtin_memmove"); - p.sym_b_memcmp = pool_intern_cstr(p.pool, "__builtin_memcmp"); - p.sym_b_memset = pool_intern_cstr(p.pool, "__builtin_memset"); - p.sym_func = pool_intern_cstr(p.pool, "__func__"); - p.sym_func_gcc = pool_intern_cstr(p.pool, "__FUNCTION__"); + p.sym_b_memcpy = pool_intern_cstr(p.pool, "__builtin_memcpy"); + p.sym_b_memmove = pool_intern_cstr(p.pool, "__builtin_memmove"); + p.sym_b_memcmp = pool_intern_cstr(p.pool, "__builtin_memcmp"); + p.sym_b_memset = pool_intern_cstr(p.pool, "__builtin_memset"); + p.sym_func = pool_intern_cstr(p.pool, "__func__"); + p.sym_func_gcc = pool_intern_cstr(p.pool, "__FUNCTION__"); p.sym_pretty_func_gcc = pool_intern_cstr(p.pool, "__PRETTY_FUNCTION__"); - p.sym_b_expect = pool_intern_cstr(p.pool, "__builtin_expect"); - p.sym_b_offsetof = pool_intern_cstr(p.pool, "__builtin_offsetof"); - p.sym_b_va_list = pool_intern_cstr(p.pool, "__builtin_va_list"); - p.sym_b_va_start = pool_intern_cstr(p.pool, "__builtin_va_start"); - p.sym_b_va_arg = pool_intern_cstr(p.pool, "__builtin_va_arg"); - p.sym_b_va_end = pool_intern_cstr(p.pool, "__builtin_va_end"); - p.sym_b_va_copy = pool_intern_cstr(p.pool, "__builtin_va_copy"); - p.sym_attribute = pool_intern_cstr(p.pool, "__attribute__"); + p.sym_b_expect = pool_intern_cstr(p.pool, "__builtin_expect"); + p.sym_b_offsetof = pool_intern_cstr(p.pool, "__builtin_offsetof"); + p.sym_b_va_list = pool_intern_cstr(p.pool, "__builtin_va_list"); + p.sym_b_va_start = pool_intern_cstr(p.pool, "__builtin_va_start"); + p.sym_b_va_arg = pool_intern_cstr(p.pool, "__builtin_va_arg"); + p.sym_b_va_end = pool_intern_cstr(p.pool, "__builtin_va_end"); + p.sym_b_va_copy = pool_intern_cstr(p.pool, "__builtin_va_copy"); + p.sym_attribute = pool_intern_cstr(p.pool, "__attribute__"); p.sym_volatile_alias = pool_intern_cstr(p.pool, "__volatile__"); - p.sym_alignof_alias = pool_intern_cstr(p.pool, "__alignof__"); - p.sym_int128 = pool_intern_cstr(p.pool, "__int128"); - p.sym_int128_t = pool_intern_cstr(p.pool, "__int128_t"); - p.sym_uint128_t = pool_intern_cstr(p.pool, "__uint128_t"); - p.sym_a_load_n = pool_intern_cstr(p.pool, "__atomic_load_n"); - p.sym_a_store_n = pool_intern_cstr(p.pool, "__atomic_store_n"); + p.sym_alignof_alias = pool_intern_cstr(p.pool, "__alignof__"); + p.sym_int128 = pool_intern_cstr(p.pool, "__int128"); + p.sym_int128_t = pool_intern_cstr(p.pool, "__int128_t"); + p.sym_uint128_t = pool_intern_cstr(p.pool, "__uint128_t"); + p.sym_a_load_n = pool_intern_cstr(p.pool, "__atomic_load_n"); + p.sym_a_store_n = pool_intern_cstr(p.pool, "__atomic_store_n"); p.sym_a_exchange_n = pool_intern_cstr(p.pool, "__atomic_exchange_n"); - p.sym_a_fetch_add = pool_intern_cstr(p.pool, "__atomic_fetch_add"); - p.sym_a_fetch_sub = pool_intern_cstr(p.pool, "__atomic_fetch_sub"); - p.sym_a_fetch_and = pool_intern_cstr(p.pool, "__atomic_fetch_and"); - p.sym_a_fetch_or = pool_intern_cstr(p.pool, "__atomic_fetch_or"); - p.sym_a_fetch_xor = pool_intern_cstr(p.pool, "__atomic_fetch_xor"); - p.sym_a_cas_n = pool_intern_cstr(p.pool, "__atomic_compare_exchange_n"); - p.sym_a_thread_fence = pool_intern_cstr(p.pool, "__atomic_thread_fence"); - p.sym_a_signal_fence = pool_intern_cstr(p.pool, "__atomic_signal_fence"); + p.sym_a_fetch_add = pool_intern_cstr(p.pool, "__atomic_fetch_add"); + p.sym_a_fetch_sub = pool_intern_cstr(p.pool, "__atomic_fetch_sub"); + p.sym_a_fetch_and = pool_intern_cstr(p.pool, "__atomic_fetch_and"); + p.sym_a_fetch_or = pool_intern_cstr(p.pool, "__atomic_fetch_or"); + p.sym_a_fetch_xor = pool_intern_cstr(p.pool, "__atomic_fetch_xor"); + p.sym_a_cas_n = pool_intern_cstr(p.pool, "__atomic_compare_exchange_n"); + p.sym_a_thread_fence = pool_intern_cstr(p.pool, "__atomic_thread_fence"); + p.sym_a_signal_fence = pool_intern_cstr(p.pool, "__atomic_signal_fence"); p.scope = scope_new(&p, NULL); diff --git a/lang/c/parse/parse.h b/lang/c/parse/parse.h @@ -7,6 +7,6 @@ /* C11 frontend. Reads preprocessed tokens, records C declarations, and drives * the public CG API for executable code and object data. */ -void parse_c(Compiler*, Pp*, DeclTable*, CG*); +void parse_c(Compiler*, Pool*, Pp*, DeclTable*, CG*); #endif diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -8,7 +8,6 @@ static const Type* ty_size_t(Parser* p) { return c_abi_size_type(p->abi, p->pool); } - static CKw ident_kw(const Parser* p, Sym name) { return ident_kw_inline(p, name); } @@ -65,10 +64,14 @@ static const Type* int_literal_type(Parser* p, const Tok* t) { int l = (t->flags & TF_INT_L) != 0; int ll = (t->flags & TF_INT_LL) != 0; TypeKind k; - if (ll) k = u ? TY_ULLONG : TY_LLONG; - else if (l) k = u ? TY_ULONG : TY_LONG; - else if (u) k = TY_UINT; - else k = TY_INT; + if (ll) + k = u ? TY_ULLONG : TY_LLONG; + else if (l) + k = u ? TY_ULONG : TY_LONG; + else if (u) + k = TY_UINT; + else + k = TY_INT; return type_prim(p->pool, k); } @@ -89,13 +92,17 @@ static double parse_float_literal(Parser* p, const Tok* t) { while (i < len) { int c = (unsigned char)s[i]; int dv; - if (c == '.' || c == 'e' || c == 'E' || c == 'p' || c == 'P' || - c == 'f' || c == 'F' || c == 'l' || c == 'L') + if (c == '.' || c == 'e' || c == 'E' || c == 'p' || c == 'P' || c == 'f' || + c == 'F' || c == 'l' || c == 'L') break; - if (c >= '0' && c <= '9') dv = c - '0'; - else if (is_hex && c >= 'a' && c <= 'f') dv = c - 'a' + 10; - else if (is_hex && c >= 'A' && c <= 'F') dv = c - 'A' + 10; - else perr(p, "bad digit in float literal"); + if (c >= '0' && c <= '9') + dv = c - '0'; + else if (is_hex && c >= 'a' && c <= 'f') + dv = c - 'a' + 10; + else if (is_hex && c >= 'A' && c <= 'F') + dv = c - 'A' + 10; + else + perr(p, "bad digit in float literal"); v = v * (is_hex ? 16.0 : 10.0) + (double)dv; i++; } @@ -104,13 +111,17 @@ static double parse_float_literal(Parser* p, const Tok* t) { while (i < len) { int c = (unsigned char)s[i]; int dv; - if (c == 'e' || c == 'E' || c == 'p' || c == 'P' || - c == 'f' || c == 'F' || c == 'l' || c == 'L') + if (c == 'e' || c == 'E' || c == 'p' || c == 'P' || c == 'f' || + c == 'F' || c == 'l' || c == 'L') break; - if (c >= '0' && c <= '9') dv = c - '0'; - else if (is_hex && c >= 'a' && c <= 'f') dv = c - 'a' + 10; - else if (is_hex && c >= 'A' && c <= 'F') dv = c - 'A' + 10; - else perr(p, "bad digit in float literal"); + if (c >= '0' && c <= '9') + dv = c - '0'; + else if (is_hex && c >= 'a' && c <= 'f') + dv = c - 'a' + 10; + else if (is_hex && c >= 'A' && c <= 'F') + dv = c - 'A' + 10; + else + perr(p, "bad digit in float literal"); v = v * (is_hex ? 16.0 : 10.0) + (double)dv; exp -= 1; frac_seen = 1; @@ -139,14 +150,32 @@ static double parse_float_literal(Parser* p, const Tok* t) { exp = 0; } } - while (exp < 0) { v /= (is_hex ? 16.0 : 10.0); exp++; } - while (exp > 0) { v *= (is_hex ? 16.0 : 10.0); exp--; } + while (exp < 0) { + v /= (is_hex ? 16.0 : 10.0); + exp++; + } + while (exp > 0) { + v *= (is_hex ? 16.0 : 10.0); + exp--; + } if (is_hex) { - while (dec_exp < 0) { v /= 2.0; dec_exp++; } - while (dec_exp > 0) { v *= 2.0; dec_exp--; } + while (dec_exp < 0) { + v /= 2.0; + dec_exp++; + } + while (dec_exp > 0) { + v *= 2.0; + dec_exp--; + } } else { - while (dec_exp < 0) { v /= 10.0; dec_exp++; } - while (dec_exp > 0) { v *= 10.0; dec_exp--; } + while (dec_exp < 0) { + v /= 10.0; + dec_exp++; + } + while (dec_exp > 0) { + v *= 10.0; + dec_exp--; + } } return v; } @@ -172,27 +201,53 @@ static i64 decode_one_char(Parser* p, const char* s, size_t len, size_t* pi, if (i >= len) compiler_panic(p->c, loc, "trailing '\\' in literal"); c = (unsigned char)s[i++]; switch (c) { - case 'n': v = '\n'; break; - case 't': v = '\t'; break; - case 'r': v = '\r'; break; - case 'b': v = '\b'; break; - case 'f': v = '\f'; break; - case 'v': v = '\v'; break; - case 'a': v = '\a'; break; - case '\\': v = '\\'; break; - case '\'': v = '\''; break; - case '"': v = '"'; break; - case '?': v = '?'; break; + case 'n': + v = '\n'; + break; + case 't': + v = '\t'; + break; + case 'r': + v = '\r'; + break; + case 'b': + v = '\b'; + break; + case 'f': + v = '\f'; + break; + case 'v': + v = '\v'; + break; + case 'a': + v = '\a'; + break; + case '\\': + v = '\\'; + break; + case '\'': + v = '\''; + break; + case '"': + v = '"'; + break; + case '?': + v = '?'; + break; case 'x': { i64 hex = 0; int any = 0; while (i < len) { int d = (unsigned char)s[i]; int dv; - if (d >= '0' && d <= '9') dv = d - '0'; - else if (d >= 'a' && d <= 'f') dv = d - 'a' + 10; - else if (d >= 'A' && d <= 'F') dv = d - 'A' + 10; - else break; + if (d >= '0' && d <= '9') + dv = d - '0'; + else if (d >= 'a' && d <= 'f') + dv = d - 'a' + 10; + else if (d >= 'A' && d <= 'F') + dv = d - 'A' + 10; + else + break; hex = hex * 16 + dv; any = 1; i++; @@ -226,8 +281,10 @@ i64 decode_char_literal(Parser* p, const Tok* t) { size_t i = 0; i64 v; if (!s) perr(p, "bad char literal"); - if (t->flags & TF_STR_U8) i = 2; - else if (t->flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32)) i = 1; + if (t->flags & TF_STR_U8) + i = 2; + else if (t->flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32)) + i = 1; if (i >= len || s[i] != '\'') perr(p, "malformed character literal"); i++; if (i >= len || s[i] == '\'') perr(p, "empty character literal"); @@ -242,12 +299,14 @@ u8* decode_string_literal(Parser* p, const Tok* t, size_t* nlen_out) { size_t len = 0; const char* s = pool_str(p->pool, t->spelling, &len); size_t i = 0; - Heap* h = p->c->env->heap; + Heap* h = cfree_compiler_heap(p->c); u8* buf; size_t k = 0; if (!s) perr(p, "bad string literal"); - if (t->flags & TF_STR_U8) i = 2; - else if (t->flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32)) i = 1; + if (t->flags & TF_STR_U8) + i = 2; + else if (t->flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32)) + i = 1; if (i >= len || s[i] != '"') perr(p, "malformed string literal"); i++; buf = (u8*)h->alloc(h, len + 1, 1); @@ -262,7 +321,8 @@ u8* decode_string_literal(Parser* p, const Tok* t, size_t* nlen_out) { } CfreeCgSym emit_string_to_rodata(Parser* p, const u8* bytes, size_t n) { - const Type* arr_ty = type_array(p->pool, type_prim(p->pool, TY_CHAR), (u32)n, 0); + const Type* arr_ty = + type_array(p->pool, type_prim(p->pool, TY_CHAR), (u32)n, 0); return cfree_cg_const_data(p->cg, bytes, n, 1u, pcg_tid(p->c, arr_ty)); } @@ -276,7 +336,8 @@ static const Type* offsetof_designator(Parser* p, const Type* base, u32* off); static i64 cexpr_mul(Parser* p, SrcLoc loc) { i64 v = cexpr_unary(p, loc); for (;;) { - if (accept_punct(p, '*')) v = v * cexpr_unary(p, loc); + if (accept_punct(p, '*')) + v = v * cexpr_unary(p, loc); else if (accept_punct(p, '/')) { i64 r = cexpr_unary(p, loc); if (r == 0) compiler_panic(p->c, loc, "division by zero in constant"); @@ -285,47 +346,62 @@ static i64 cexpr_mul(Parser* p, SrcLoc loc) { i64 r = cexpr_unary(p, loc); if (r == 0) compiler_panic(p->c, loc, "modulo by zero in constant"); v = v % r; - } else break; + } else + break; } return v; } static i64 cexpr_add(Parser* p, SrcLoc loc) { i64 v = cexpr_mul(p, loc); for (;;) { - if (accept_punct(p, '+')) v = v + cexpr_mul(p, loc); - else if (accept_punct(p, '-')) v = v - cexpr_mul(p, loc); - else break; + if (accept_punct(p, '+')) + v = v + cexpr_mul(p, loc); + else if (accept_punct(p, '-')) + v = v - cexpr_mul(p, loc); + else + break; } return v; } static i64 cexpr_shift(Parser* p, SrcLoc loc) { i64 v = cexpr_add(p, loc); for (;;) { - if (accept_punct(p, P_SHL)) v = v << cexpr_add(p, loc); - else if (accept_punct(p, P_SHR)) v = v >> cexpr_add(p, loc); - else break; + if (accept_punct(p, P_SHL)) + v = v << cexpr_add(p, loc); + else if (accept_punct(p, P_SHR)) + v = v >> cexpr_add(p, loc); + else + break; } return v; } static i64 cexpr_rel(Parser* p, SrcLoc loc) { i64 v = cexpr_shift(p, loc); for (;;) { - if (accept_punct(p, P_LE)) v = v <= cexpr_shift(p, loc); - else if (accept_punct(p, P_GE)) v = v >= cexpr_shift(p, loc); + if (accept_punct(p, P_LE)) + v = v <= cexpr_shift(p, loc); + else if (accept_punct(p, P_GE)) + v = v >= cexpr_shift(p, loc); else if (is_punct(&p->cur, '<')) { - advance(p); v = v < cexpr_shift(p, loc); + advance(p); + v = v < cexpr_shift(p, loc); } else if (is_punct(&p->cur, '>')) { - advance(p); v = v > cexpr_shift(p, loc); - } else break; + advance(p); + v = v > cexpr_shift(p, loc); + } else + break; } return v; } static i64 cexpr_eq(Parser* p, SrcLoc loc) { i64 v = cexpr_rel(p, loc); for (;;) { - if (accept_punct(p, P_EQ)) v = (v == cexpr_rel(p, loc)); - else if (accept_punct(p, P_NE)) v = (v != cexpr_rel(p, loc)); - else break; + if (accept_punct(p, P_EQ)) + v = (v == cexpr_rel(p, loc)); + else if (accept_punct(p, P_NE)) + v = (v != cexpr_rel(p, loc)); + else + break; } return v; } @@ -511,7 +587,7 @@ static const Type* offsetof_designator(Parser* p, const Type* base, u32* off) { const Field* mf = NULL; /* find_field is static in parse_type.c; we need it here. * We call c_abi_record_layout directly inline. */ - const ABIRecordLayout* L = c_abi_record_layout(p->abi, cur); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, cur); if (!L) perr(p, "no such member in __builtin_offsetof"); int found = 0; for (u16 i = 0; i < cur->rec.nfields; ++i) { @@ -570,27 +646,26 @@ static int try_parse_builtin_call(Parser* p) { * forgot to declare the underlying libc function. */ if (name == p->sym_b_memcpy || name == p->sym_b_memmove || name == p->sym_b_memcmp || name == p->sym_b_memset) { - const char* libname = (name == p->sym_b_memcpy) ? "memcpy" - : (name == p->sym_b_memmove) ? "memmove" - : (name == p->sym_b_memcmp) ? "memcmp" - : "memset"; + const char* libname = (name == p->sym_b_memcpy) ? "memcpy" + : (name == p->sym_b_memmove) ? "memmove" + : (name == p->sym_b_memcmp) ? "memcmp" + : "memset"; p->cur.v.ident = pool_intern_cstr(p->pool, libname); return 0; } - if (name != p->sym_b_alloca && name != p->sym_b_ctz && - name != p->sym_b_clz && name != p->sym_b_clzl && - name != p->sym_b_clzll && name != p->sym_b_trap && - name != p->sym_b_unreachable && - name != p->sym_b_expect && - name != p->sym_b_offsetof && name != p->sym_b_va_start && - name != p->sym_b_va_arg && name != p->sym_b_va_end && - name != p->sym_b_va_copy && name != p->sym_a_load_n && - name != p->sym_a_store_n && name != p->sym_a_exchange_n && - name != p->sym_a_fetch_add && name != p->sym_a_fetch_sub && - name != p->sym_a_fetch_and && name != p->sym_a_fetch_or && - name != p->sym_a_fetch_xor && name != p->sym_a_cas_n && - name != p->sym_a_thread_fence && name != p->sym_a_signal_fence) { + if (name != p->sym_b_alloca && name != p->sym_b_ctz && name != p->sym_b_clz && + name != p->sym_b_clzl && name != p->sym_b_clzll && + name != p->sym_b_trap && name != p->sym_b_unreachable && + name != p->sym_b_expect && name != p->sym_b_offsetof && + name != p->sym_b_va_start && name != p->sym_b_va_arg && + name != p->sym_b_va_end && name != p->sym_b_va_copy && + name != p->sym_a_load_n && name != p->sym_a_store_n && + name != p->sym_a_exchange_n && name != p->sym_a_fetch_add && + name != p->sym_a_fetch_sub && name != p->sym_a_fetch_and && + name != p->sym_a_fetch_or && name != p->sym_a_fetch_xor && + name != p->sym_a_cas_n && name != p->sym_a_thread_fence && + name != p->sym_a_signal_fence) { return 0; } advance(p); /* IDENT */ @@ -634,8 +709,7 @@ static int try_parse_builtin_call(Parser* p) { return 1; } - if (name == p->sym_b_clz || name == p->sym_b_clzl || - name == p->sym_b_clzll) { + if (name == p->sym_b_clz || name == p->sym_b_clzl || name == p->sym_b_clzll) { parse_assign_expr(p); to_rvalue(p); expect_punct(p, ')', "')' after __builtin_clz"); @@ -743,22 +817,29 @@ static int try_parse_builtin_call(Parser* p) { } if (name == p->sym_a_cas_n) { - parse_assign_expr(p); to_rvalue(p); /* ptr */ + parse_assign_expr(p); + to_rvalue(p); /* ptr */ expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); - parse_assign_expr(p); to_rvalue(p); /* &expected */ + parse_assign_expr(p); + to_rvalue(p); /* &expected */ const Type* eptr_ty = cg_top_type(p->cg); if (!eptr_ty || eptr_ty->kind != TY_PTR) { perr(p, "__atomic_compare_exchange_n: arg 2 must be a pointer"); } const Type* val_ty = eptr_ty->ptr.pointee; - FrameSlotDesc fsd; memset(&fsd, 0, sizeof fsd); - fsd.type = eptr_ty; fsd.size = 8; fsd.align = 8; fsd.kind = FS_LOCAL; + FrameSlotDesc fsd; + memset(&fsd, 0, sizeof fsd); + fsd.type = eptr_ty; + fsd.size = 8; + fsd.align = 8; + fsd.kind = FS_LOCAL; FrameSlot eslot = cg_local(p->cg, &fsd); cg_push_local_typed(p->cg, eslot, eptr_ty); cg_swap(p->cg); - cg_store(p->cg); cg_drop(p->cg); + cg_store(p->cg); + cg_drop(p->cg); cg_push_local_typed(p->cg, eslot, eptr_ty); cg_load(p->cg); @@ -766,10 +847,11 @@ static int try_parse_builtin_call(Parser* p) { cg_load(p->cg); expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); - parse_assign_expr(p); to_rvalue(p); /* desired */ + parse_assign_expr(p); + to_rvalue(p); /* desired */ expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); - (void)eval_const_int(p, p->cur.loc); /* weak */ + (void)eval_const_int(p, p->cur.loc); /* weak */ expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); i64 succ = eval_const_int(p, p->cur.loc); expect_punct(p, ',', "',' in __atomic_compare_exchange_n"); @@ -780,20 +862,29 @@ static int try_parse_builtin_call(Parser* p) { cg_atomic_cas(p->cg, (MemOrder)succ, (MemOrder)fail); const Type* ok_ty = cg_top_type(p->cg); - FrameSlotDesc okd; memset(&okd, 0, sizeof okd); - okd.type = ok_ty; okd.size = 4; okd.align = 4; okd.kind = FS_LOCAL; + FrameSlotDesc okd; + memset(&okd, 0, sizeof okd); + okd.type = ok_ty; + okd.size = 4; + okd.align = 4; + okd.kind = FS_LOCAL; FrameSlot okslot = cg_local(p->cg, &okd); cg_push_local_typed(p->cg, okslot, ok_ty); - cg_swap(p->cg); cg_store(p->cg); cg_drop(p->cg); + cg_swap(p->cg); + cg_store(p->cg); + cg_drop(p->cg); - FrameSlotDesc pd; memset(&pd, 0, sizeof pd); + FrameSlotDesc pd; + memset(&pd, 0, sizeof pd); pd.type = 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); - cg_swap(p->cg); cg_store(p->cg); cg_drop(p->cg); + cg_swap(p->cg); + cg_store(p->cg); + cg_drop(p->cg); cg_push_local_typed(p->cg, okslot, ok_ty); cg_load(p->cg); @@ -804,7 +895,8 @@ static int try_parse_builtin_call(Parser* p) { cg_deref(p->cg, val_ty); cg_push_local_typed(p->cg, pslot, val_ty); cg_load(p->cg); - cg_store(p->cg); cg_drop(p->cg); + cg_store(p->cg); + cg_drop(p->cg); cg_label_place(p->cg, L_done); cg_push_local_typed(p->cg, okslot, ok_ty); @@ -813,13 +905,21 @@ static int try_parse_builtin_call(Parser* p) { } AtomicOp op; - if (name == p->sym_a_exchange_n) op = AO_XCHG; - else if (name == p->sym_a_fetch_add) op = AO_ADD; - else if (name == p->sym_a_fetch_sub) op = AO_SUB; - else if (name == p->sym_a_fetch_and) op = AO_AND; - else if (name == p->sym_a_fetch_or) op = AO_OR; - else if (name == p->sym_a_fetch_xor) op = AO_XOR; - else { perr(p, "internal: unhandled builtin"); } + if (name == p->sym_a_exchange_n) + op = AO_XCHG; + else if (name == p->sym_a_fetch_add) + op = AO_ADD; + else if (name == p->sym_a_fetch_sub) + op = AO_SUB; + else if (name == p->sym_a_fetch_and) + op = AO_AND; + else if (name == p->sym_a_fetch_or) + op = AO_OR; + else if (name == p->sym_a_fetch_xor) + op = AO_XOR; + else { + perr(p, "internal: unhandled builtin"); + } parse_assign_expr(p); to_rvalue(p); @@ -883,13 +983,13 @@ static void parse_primary(Parser* p) { t.v.ident == p->sym_pretty_func_gcc) { if (p->cur_func_name == 0) { compiler_panic(p->c, t.loc, "'%s' used outside a function", - t.v.ident == p->sym_func ? "__func__" + t.v.ident == p->sym_func ? "__func__" : t.v.ident == p->sym_func_gcc ? "__FUNCTION__" - : "__PRETTY_FUNCTION__"); + : "__PRETTY_FUNCTION__"); } size_t nlen = 0; const char* fn_name = pool_str(p->pool, p->cur_func_name, &nlen); - Heap* h = p->c->env->heap; + Heap* h = cfree_compiler_heap(p->c); u8* bytes = (u8*)h->alloc(h, nlen + 1u, 1u); for (size_t i = 0; i < nlen; ++i) bytes[i] = (u8)fn_name[i]; bytes[nlen] = 0; @@ -938,7 +1038,7 @@ static void parse_primary(Parser* p) { size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); ObjSymId sym = emit_string_to_rodata(p, bytes, n); - p->c->env->heap->free(p->c->env->heap, bytes, 0); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); advance(p); { const Type* char_ty = type_prim(p->pool, TY_CHAR); @@ -1050,7 +1150,8 @@ static void parse_postfix(Parser* p) { const Field* mf = NULL; advance(p); /* '.' */ if (!lt || (lt->kind != TY_STRUCT && lt->kind != TY_UNION)) { - perr(p, "request for member in something that is not a struct or union"); + perr(p, + "request for member in something that is not a struct or union"); } if (p->cur.kind != TOK_IDENT || ident_kw(p, p->cur.v.ident) != KW_NONE) { perr(p, "expected member name after '.'"); @@ -1058,7 +1159,7 @@ static void parse_postfix(Parser* p) { mname = p->cur.v.ident; advance(p); { - const ABIRecordLayout* L = c_abi_record_layout(p->abi, lt); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, lt); if (!L) perr(p, "no such member"); int found = 0; for (u16 i = 0; i < lt->rec.nfields; ++i) { @@ -1071,12 +1172,13 @@ static void parse_postfix(Parser* p) { break; } /* anonymous member flattening */ - if ((f->flags & FIELD_ANON) && (f->type->kind == TY_STRUCT || - f->type->kind == TY_UNION)) { + if ((f->flags & FIELD_ANON) && + (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) { const Type* inner_ty = NULL; u32 inner_off = 0; const Field* inner_f = NULL; - const ABIRecordLayout* IL = c_abi_record_layout(p->abi, f->type); + const ABIRecordLayout* IL = + c_abi_record_layout(p->abi, p->pool, f->type); if (IL) { for (u16 j = 0; j < f->type->rec.nfields; ++j) { const Field* ff = &f->type->rec.fields[j]; @@ -1132,7 +1234,7 @@ static void parse_postfix(Parser* p) { mname = p->cur.v.ident; advance(p); { - const ABIRecordLayout* L = c_abi_record_layout(p->abi, rec_ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, rec_ty); if (!L) perr(p, "no such member"); int found = 0; for (u16 i = 0; i < rec_ty->rec.nfields; ++i) { @@ -1144,9 +1246,10 @@ static void parse_postfix(Parser* p) { found = 1; break; } - if ((f->flags & FIELD_ANON) && (f->type->kind == TY_STRUCT || - f->type->kind == TY_UNION)) { - const ABIRecordLayout* IL = c_abi_record_layout(p->abi, f->type); + if ((f->flags & FIELD_ANON) && + (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) { + const ABIRecordLayout* IL = + c_abi_record_layout(p->abi, p->pool, f->type); if (IL) { for (u16 j = 0; j < f->type->rec.nfields; ++j) { const Field* ff = &f->type->rec.fields[j]; @@ -1346,7 +1449,7 @@ void parse_unary(Parser* p) { emitted = 1; } else if (is_default && !default_buf) { u32 cap = 16; - Tok* buf = arena_array(p->c->tu, Tok, cap); + Tok* buf = arena_array(p->pool->arena, Tok, cap); u32 len = 0; int paren_depth = 0, brack_depth = 0, brace_depth = 0; while (p->cur.kind != TOK_EOF) { @@ -1355,24 +1458,30 @@ void parse_unary(Parser* p) { } if (len == cap) { u32 new_cap = cap * 2; - Tok* nv = arena_array(p->c->tu, Tok, new_cap); + Tok* nv = arena_array(p->pool->arena, Tok, new_cap); if (!nv) perr(p, "out of memory recording _Generic default"); memcpy(nv, buf, len * sizeof(Tok)); buf = nv; cap = new_cap; } buf[len++] = p->cur; - if (is_punct(&p->cur, '(')) ++paren_depth; - else if (is_punct(&p->cur, ')')) --paren_depth; - else if (is_punct(&p->cur, '[')) ++brack_depth; - else if (is_punct(&p->cur, ']')) --brack_depth; - else if (is_punct(&p->cur, '{')) ++brace_depth; - else if (is_punct(&p->cur, '}')) --brace_depth; + if (is_punct(&p->cur, '(')) + ++paren_depth; + else if (is_punct(&p->cur, ')')) + --paren_depth; + else if (is_punct(&p->cur, '[')) + ++brack_depth; + else if (is_punct(&p->cur, ']')) + --brack_depth; + else if (is_punct(&p->cur, '{')) + ++brace_depth; + else if (is_punct(&p->cur, '}')) + --brace_depth; advance(p); } if (len == cap) { u32 new_cap = cap + 1; - Tok* nv = arena_array(p->c->tu, Tok, new_cap); + Tok* nv = arena_array(p->pool->arena, Tok, new_cap); if (!nv) perr(p, "out of memory recording _Generic default"); memcpy(nv, buf, len * sizeof(Tok)); buf = nv; @@ -1392,12 +1501,18 @@ void parse_unary(Parser* p) { if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0) { if (is_punct(&p->cur, ',') || is_punct(&p->cur, ')')) break; } - if (is_punct(&p->cur, '(')) ++paren_depth; - else if (is_punct(&p->cur, ')')) --paren_depth; - else if (is_punct(&p->cur, '[')) ++brack_depth; - else if (is_punct(&p->cur, ']')) --brack_depth; - else if (is_punct(&p->cur, '{')) ++brace_depth; - else if (is_punct(&p->cur, '}')) --brace_depth; + if (is_punct(&p->cur, '(')) + ++paren_depth; + else if (is_punct(&p->cur, ')')) + --paren_depth; + else if (is_punct(&p->cur, '[')) + ++brack_depth; + else if (is_punct(&p->cur, ']')) + --brack_depth; + else if (is_punct(&p->cur, '{')) + ++brace_depth; + else if (is_punct(&p->cur, '}')) + --brace_depth; advance(p); } } @@ -1457,8 +1572,8 @@ void parse_unary(Parser* p) { * ============================================================ */ static int type_is_fp(const Type* t) { - return t && (t->kind == TY_FLOAT || t->kind == TY_DOUBLE || - t->kind == TY_LDOUBLE); + return t && + (t->kind == TY_FLOAT || t->kind == TY_DOUBLE || t->kind == TY_LDOUBLE); } static const Type* common_fp_type(Parser* p, const Type* a, const Type* b) { @@ -1479,10 +1594,18 @@ static void emit_fp_binop(Parser* p, BinOp bop, const Type* common) { cg_swap(p->cg); BinOp fop; switch (bop) { - case BO_IADD: fop = BO_FADD; break; - case BO_ISUB: fop = BO_FSUB; break; - case BO_IMUL: fop = BO_FMUL; break; - case BO_SDIV: fop = BO_FDIV; break; + case BO_IADD: + fop = BO_FADD; + break; + case BO_ISUB: + fop = BO_FSUB; + break; + case BO_IMUL: + fop = BO_FMUL; + break; + case BO_SDIV: + fop = BO_FDIV; + break; default: perr(p, "operator does not apply to floating types"); return; @@ -1826,25 +1949,35 @@ void parse_assign_expr(Parser* p) { is_simple_assign = 1; compound = (BinOp)0; } else if (is_punct(&t, P_ADD_ASSIGN)) { - is_simple_assign = 0; compound = BO_IADD; + is_simple_assign = 0; + compound = BO_IADD; } else if (is_punct(&t, P_SUB_ASSIGN)) { - is_simple_assign = 0; compound = BO_ISUB; + is_simple_assign = 0; + compound = BO_ISUB; } else if (is_punct(&t, P_MUL_ASSIGN)) { - is_simple_assign = 0; compound = BO_IMUL; + is_simple_assign = 0; + compound = BO_IMUL; } else if (is_punct(&t, P_DIV_ASSIGN)) { - is_simple_assign = 0; compound = BO_SDIV; + is_simple_assign = 0; + compound = BO_SDIV; } else if (is_punct(&t, P_MOD_ASSIGN)) { - is_simple_assign = 0; compound = BO_SREM; + is_simple_assign = 0; + compound = BO_SREM; } else if (is_punct(&t, P_AND_ASSIGN)) { - is_simple_assign = 0; compound = BO_AND; + is_simple_assign = 0; + compound = BO_AND; } else if (is_punct(&t, P_OR_ASSIGN)) { - is_simple_assign = 0; compound = BO_OR; + is_simple_assign = 0; + compound = BO_OR; } else if (is_punct(&t, P_XOR_ASSIGN)) { - is_simple_assign = 0; compound = BO_XOR; + is_simple_assign = 0; + compound = BO_XOR; } else if (is_punct(&t, P_SHL_ASSIGN)) { - is_simple_assign = 0; compound = BO_SHL; + is_simple_assign = 0; + compound = BO_SHL; } else if (is_punct(&t, P_SHR_ASSIGN)) { - is_simple_assign = 0; compound = BO_SHR_S; + is_simple_assign = 0; + compound = BO_SHR_S; } else { return; } @@ -1878,6 +2011,4 @@ void parse_expr(Parser* p) { } /* parse_cond_expr is the ternary level, provided for completeness */ -void parse_cond_expr(Parser* p) { - parse_ternary(p); -} +void parse_cond_expr(Parser* p) { parse_ternary(p); } diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -47,7 +47,7 @@ static u8* peek_string_bytes(Parser* p, size_t* nlen_out) { /* Forward declaration for mutual recursion. */ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, - const Type* ty); + const Type* ty); static u32 init_elided(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* ty); @@ -66,10 +66,10 @@ void push_subobject_lv(Parser* p, FrameSlot slot, const Type* arr_ty, } /* Emit a load+store for one scalar leaf. */ -static void emit_copy_leaf(Parser* p, FrameSlot dst_slot, const Type* dst_arr_ty, - u32 dst_off, FrameSlot src_ptr_slot, - const Type* src_ptr_ty, u32 src_off, - const Type* leaf_ty) { +static void emit_copy_leaf(Parser* p, FrameSlot dst_slot, + const Type* dst_arr_ty, u32 dst_off, + FrameSlot src_ptr_slot, const Type* src_ptr_ty, + u32 src_off, const Type* leaf_ty) { push_subobject_lv(p, dst_slot, dst_arr_ty, dst_off, leaf_ty); cg_push_local_typed(p->cg, src_ptr_slot, src_ptr_ty); cg_load(p->cg); @@ -91,22 +91,21 @@ 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 = c_abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty); for (u16 i = 0; i < ty->rec.nfields; ++i) { const Field* f = &ty->rec.fields[i]; if (f->flags & FIELD_BITFIELD) continue; u32 foff = L->fields[i].offset; - emit_walk_copy(p, dst_slot, dst_arr_ty, dst_off + foff, - src_ptr_slot, src_ptr_ty, src_off + foff, f->type); + emit_walk_copy(p, dst_slot, dst_arr_ty, dst_off + foff, src_ptr_slot, + src_ptr_ty, src_off + foff, f->type); } return; } if (ty->kind == TY_ARRAY) { 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, - ty->arr.elem); + emit_walk_copy(p, dst_slot, dst_arr_ty, dst_off + i * esz, src_ptr_slot, + src_ptr_ty, src_off + i * esz, ty->arr.elem); } return; } @@ -114,8 +113,8 @@ static void emit_walk_copy(Parser* p, FrameSlot dst_slot, 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, - src_ptr_slot, src_ptr_ty, src_off + i, uchar_ty); + emit_copy_leaf(p, dst_slot, dst_arr_ty, dst_off + i, src_ptr_slot, + src_ptr_ty, src_off + i, uchar_ty); } return; } @@ -158,7 +157,7 @@ static void zero_init_at(Parser* p, FrameSlot slot, const Type* arr_ty, return; } if (ty->kind == TY_STRUCT) { - const ABIRecordLayout* L = c_abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, 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); @@ -180,7 +179,8 @@ static void zero_init_at(Parser* p, FrameSlot slot, const Type* arr_ty, cg_drop(p->cg); } -/* Emit byte stores for a string literal initializing a char-array sub-object. */ +/* Emit byte stores for a string literal initializing a char-array sub-object. + */ static void init_string_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* elem_ty, u32 count) { size_t n = 0; @@ -200,7 +200,7 @@ static void init_string_at(Parser* p, FrameSlot slot, const Type* arr_ty, cg_store(p->cg); cg_drop(p->cg); } - p->c->env->heap->free(p->c->env->heap, bytes, 0); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); advance(p); /* consume TOK_STR */ } @@ -237,16 +237,16 @@ static void parse_designator_chain(Parser* p, const Type* outer_ty, const Field* ff; u16 fi; advance(p); - if (p->cur.kind != TOK_IDENT || ident_kw_init(p, p->cur.v.ident) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_init(p, p->cur.v.ident) != KW_NONE) { perr(p, "expected field name after '.'"); } fname = p->cur.v.ident; advance(p); - if (!cur_ty || - (cur_ty->kind != TY_STRUCT && cur_ty->kind != TY_UNION)) { + if (!cur_ty || (cur_ty->kind != TY_STRUCT && cur_ty->kind != TY_UNION)) { perr(p, "field designator on non-record type"); } - if (!find_field(p->abi, cur_ty, fname, &fty, &foff, &ff)) { + if (!find_field(p->abi, p->pool, cur_ty, fname, &fty, &foff, &ff)) { perr(p, "no such field in designator"); } cur_off += foff; @@ -262,7 +262,7 @@ static void parse_designator_chain(Parser* p, const Type* outer_ty, const Type* tmp_ty; u32 tmp_off; const Field* tmp_f; - if (find_field(p->abi, g->type, fname, &tmp_ty, &tmp_off, + if (find_field(p->abi, p->pool, g->type, fname, &tmp_ty, &tmp_off, &tmp_f)) { *top_index_out = fi; break; @@ -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 = c_abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty); u32 i = start_field; u32 zero_lo = start_field; for (; i < ty->rec.nfields; ++i) { @@ -314,7 +314,7 @@ static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty, ++i; break; } - next_item_struct: + next_item_struct: if (!accept_punct(p, ',')) { ++i; break; @@ -393,8 +393,7 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* sub_ty; u32 sub_off; u32 top_idx = 0; - parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, - &top_idx); + parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, &top_idx); while (zero_lo < top_idx) { zero_init_at(p, slot, arr_ty, offset + zero_lo * esz, elem_ty); ++zero_lo; @@ -489,9 +488,10 @@ static void parse_static_string_at(Parser* p, u8* buf, u32 buflen, u32 offset, u8* bytes = peek_string_bytes(p, &n); size_t copy = n; if (copy > count) copy = count; - if (offset + (u32)copy > buflen) perr(p, "string initializer overflows object"); + if (offset + (u32)copy > buflen) + perr(p, "string initializer overflows object"); memcpy(buf + offset, bytes, copy); - p->c->env->heap->free(p->c->env->heap, bytes, 0); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); advance(p); } @@ -499,8 +499,8 @@ static void parse_static_string_at(Parser* p, u8* buf, u32 buflen, u32 offset, void srl_push(Parser* p, u32 offset, u32 size, ObjSymId target, i64 addend) { if (p->static_relocs_len == p->static_relocs_cap) { u32 nc = p->static_relocs_cap ? p->static_relocs_cap * 2u : 4u; - void* nb = arena_array(p->c->tu, char, - nc * sizeof(*p->static_relocs)); + void* nb = + arena_array(p->pool->arena, char, nc * sizeof(*p->static_relocs)); if (!nb) perr(p, "out of memory recording static relocs"); if (p->static_relocs && p->static_relocs_len) { memcpy(nb, p->static_relocs, @@ -517,8 +517,8 @@ void srl_push(Parser* p, u32 offset, u32 size, ObjSymId target, i64 addend) { } /* Try to parse the current expression as an address constant. */ -static int try_parse_addr_const(Parser* p, const Type* ty, u8* buf, - u32 offset, u32 sz) { +static int try_parse_addr_const(Parser* p, const Type* ty, u8* buf, u32 offset, + u32 sz) { Tok t = p->cur; Sym name = 0; SrcLoc nloc = tok_loc_init(&p->cur); @@ -532,7 +532,7 @@ static int try_parse_addr_const(Parser* p, const Type* ty, u8* buf, size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); ObjSymId str_sym = emit_string_to_rodata(p, bytes, n); - p->c->env->heap->free(p->c->env->heap, bytes, 0); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); advance(p); (void)ty; (void)buf; @@ -542,7 +542,8 @@ static int try_parse_addr_const(Parser* p, const Type* ty, u8* buf, if (is_punct(&t, '&')) { saw_amp = 1; advance(p); - if (p->cur.kind != TOK_IDENT || ident_kw_init(p, p->cur.v.ident) != KW_NONE) { + if (p->cur.kind != TOK_IDENT || + ident_kw_init(p, p->cur.v.ident) != KW_NONE) { perr(p, "expected identifier after '&' in static initializer"); } name = p->cur.v.ident; @@ -647,7 +648,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 = c_abi_record_layout(p->abi, ty); + const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty); u32 i = 0; if (!had_brace) { perr(p, "expected '{' for static-storage struct initializer"); @@ -747,12 +748,15 @@ void define_static_object(Parser* p, ObjSymId sym, ObjSecId section_id, int has_nonzero = 0; if (has_init) { - buf = (u8*)arena_array(p->c->tu, u8, size ? size : 1u); + buf = (u8*)arena_array(p->pool->arena, u8, size ? size : 1u); memset(buf, 0, size); p->static_relocs_len = 0; parse_static_init_at(p, buf, size, 0, var_ty); for (u32 i = 0; i < size; ++i) { - if (buf[i]) { has_nonzero = 1; break; } + if (buf[i]) { + has_nonzero = 1; + break; + } } if (p->static_relocs_len) has_nonzero = 1; } diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h @@ -6,20 +6,15 @@ #pragma once -#include "parse/parse.h" - #include <stdarg.h> #include <string.h> #include "abi/c_abi.h" -#include "core/arena.h" -#include "core/core.h" -#include "core/heap.h" -#include "core/pool.h" #include "decl/decl.h" #include "decl/decl_attrs.h" #include "lex/lex.h" #include "parse/attr.h" +#include "parse/parse.h" #include "pp/pp.h" #include "type/type.h" @@ -62,16 +57,16 @@ typedef enum CKw { KW_VOID, KW_VOLATILE, KW_WHILE, - KW_BOOL, /* _Bool */ - KW_COMPLEX, /* _Complex */ - KW_IMAGINARY, /* _Imaginary */ - KW_ALIGNAS, /* _Alignas */ - KW_ALIGNOF, /* _Alignof */ - KW_ATOMIC, /* _Atomic */ - KW_GENERIC, /* _Generic */ - KW_NORETURN, /* _Noreturn */ + KW_BOOL, /* _Bool */ + KW_COMPLEX, /* _Complex */ + KW_IMAGINARY, /* _Imaginary */ + KW_ALIGNAS, /* _Alignas */ + KW_ALIGNOF, /* _Alignof */ + KW_ATOMIC, /* _Atomic */ + KW_GENERIC, /* _Generic */ + KW_NORETURN, /* _Noreturn */ KW_STATIC_ASSERT, /* _Static_assert */ - KW_THREAD_LOCAL, /* _Thread_local */ + KW_THREAD_LOCAL, /* _Thread_local */ KW_ASM, /* GNU `asm` */ KW_BUILTIN_ASM, /* GNU `__asm__` */ KW_COUNT @@ -189,11 +184,11 @@ typedef struct Parser { Sym sym_b_memmove; Sym sym_b_memcmp; Sym sym_b_memset; - Sym sym_func; /* __func__ */ - Sym sym_func_gcc; /* __FUNCTION__ */ - Sym sym_pretty_func_gcc; /* __PRETTY_FUNCTION__ */ - Sym cur_func_name; /* name of the function whose body we're in, - * 0 at file scope */ + Sym sym_func; /* __func__ */ + Sym sym_func_gcc; /* __FUNCTION__ */ + Sym sym_pretty_func_gcc; /* __PRETTY_FUNCTION__ */ + Sym cur_func_name; /* name of the function whose body we're in, + * 0 at file scope */ Sym sym_b_expect; Sym sym_b_offsetof; Sym sym_b_va_list; @@ -204,9 +199,9 @@ typedef struct Parser { Sym sym_attribute; Sym sym_volatile_alias; Sym sym_alignof_alias; - Sym sym_int128; /* __int128 */ - Sym sym_int128_t; /* __int128_t */ - Sym sym_uint128_t; /* __uint128_t */ + Sym sym_int128; /* __int128 */ + Sym sym_int128_t; /* __int128_t */ + Sym sym_uint128_t; /* __uint128_t */ Sym sym_a_load_n; Sym sym_a_store_n; Sym sym_a_exchange_n; @@ -250,7 +245,7 @@ typedef struct Parser { u32 size; ObjSymId target; i64 addend; - } *static_relocs; + }* static_relocs; u32 static_relocs_len; u32 static_relocs_cap; } Parser; @@ -280,7 +275,7 @@ typedef struct TypeSpecAccum { u8 saw_bool; u8 saw_float; u8 saw_double; - u8 saw_int128; /* __int128 / __int128_t / __uint128_t */ + u8 saw_int128; /* __int128 / __int128_t / __uint128_t */ u8 saw_explicit_type; } TypeSpecAccum; @@ -301,9 +296,11 @@ int accept_punct(Parser* p, u32 punct); Scope* scope_new(Parser* p, Scope* parent); void scope_push(Parser* p); void scope_pop(Parser* p); -SymEntry* scope_define(Parser* p, Sym name, SymEntryKind kind, const Type* type); +SymEntry* scope_define(Parser* p, Sym name, SymEntryKind kind, + const Type* type); SymEntry* scope_lookup(Parser* p, Sym name); -TagEntry* tag_define(Parser* p, Sym name, TagDeclKind kind, Type* type, int complete); +TagEntry* tag_define(Parser* p, Sym name, TagDeclKind kind, Type* type, + int complete); TagEntry* tag_lookup(Parser* p, Sym name); TagEntry* tag_lookup_local(Parser* p, Sym name); @@ -367,22 +364,26 @@ typedef struct DeclSuffix { /* parse_type.c */ int parse_decl_specs(Parser* p, DeclSpecs* out); -const Type* parse_struct_or_union(Parser* p, TypeKind kind, Attr** anon_attrs_out); +const Type* parse_struct_or_union(Parser* p, TypeKind kind, + Attr** anon_attrs_out); const Type* parse_enum(Parser* p, Attr** anon_attrs_out); const Type* resolve_type_specs(Parser* p, const TypeSpecAccum* a, SrcLoc loc); const Type* parse_type_name(Parser* p); const Type* parse_pointer_layer(Parser* p, const Type* base); -const Type* parse_declarator_full(Parser* p, const Type* base, int allow_abstract, - Sym* name_out, SrcLoc* loc_out); -const Type* parse_declarator_full_ex(Parser* p, const Type* base, int allow_abstract, - Sym* name_out, SrcLoc* loc_out, Attr** attrs_out); -const Type* parse_declarator(Parser* p, const Type* base, Sym* name_out, SrcLoc* loc_out); +const Type* parse_declarator_full(Parser* p, const Type* base, + int allow_abstract, Sym* name_out, + SrcLoc* loc_out); +const Type* parse_declarator_full_ex(Parser* p, const Type* base, + int allow_abstract, Sym* name_out, + SrcLoc* loc_out, Attr** attrs_out); +const Type* parse_declarator(Parser* p, const Type* base, Sym* name_out, + SrcLoc* loc_out); const Type* complete_incomplete_array(Parser* p, const Type* ty); int starts_type_name(const Parser* p, const Tok* t); int starts_attr(const Parser* p); Attr* parse_attribute_spec_list(Parser* p); void parse_and_discard_attributes(Parser* p); -int find_field(TargetABI* abi, const Type* rec, Sym name, +int find_field(TargetABI* abi, Pool* pool, const Type* rec, Sym name, const Type** out_type, u32* out_offset, const Field** out_field); u32 attrs_pick_aligned(const Attr* a); void attr_list_append(Attr** head, Attr* add); @@ -404,8 +405,10 @@ void coerce_top_to_lvalue(Parser* p); CfreeCgSym emit_string_to_rodata(Parser* p, const u8* bytes, size_t n); /* parse_init.c */ -void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* ty); -void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, const Type* ty); +void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, + const Type* ty); +void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, + const Type* ty); 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); @@ -429,7 +432,7 @@ void parse_param_list(Parser* p, ParamInfo** infos_out, u16* nparams_out, void parse_local_decl(Parser* p, const DeclSpecs* specs); FrameSlot make_local(Parser* p, Sym name, const Type* type, SrcLoc loc); FrameSlot make_local_aligned(Parser* p, Sym name, const Type* type, SrcLoc loc, - u32 align_override); + u32 align_override); Sym mint_static_local_sym(Parser* p, Sym orig); void record_braced_block(Parser* p); void replay_rewind(Parser* p); diff --git a/lang/c/parse/parse_stmt.c b/lang/c/parse/parse_stmt.c @@ -172,7 +172,7 @@ static GotoLabel* label_get_or_create(Parser* p, Sym name, SrcLoc loc) { for (gl = p->goto_labels; gl; gl = gl->next) { if (gl->name == name) return gl; } - gl = arena_new(p->c->tu, GotoLabel); + gl = arena_new(p->pool->arena, GotoLabel); if (!gl) perr(p, "out of memory in label_get_or_create"); memset(gl, 0, sizeof *gl); gl->name = name; @@ -222,7 +222,7 @@ static void parse_case_stmt(Parser* p) { expect_punct(p, ':', "':' after case constant"); L = cg_label_new(p->cg); cg_label_place(p->cg, L); - ce = arena_new(p->c->tu, CaseEntry); + ce = arena_new(p->pool->arena, CaseEntry); if (!ce) perr(p, "out of memory in parse_case_stmt"); ce->value = v; ce->label = L; @@ -328,8 +328,8 @@ void parse_static_assert(Parser* p) { if (!v) { size_t mlen = 0; const char* mstr = pool_str(p->pool, msg.spelling, &mlen); - compiler_panic(p->c, loc, "static assertion failed: %.*s", - (int)mlen, mstr ? mstr : ""); + compiler_panic(p->c, loc, "static assertion failed: %.*s", (int)mlen, + mstr ? mstr : ""); } } } @@ -368,7 +368,7 @@ static const char* parse_asm_str(Parser* p, const char* what) { bytes = decode_string_literal(p, &t, &nlen); if (nlen > 0) nlen -= 1; s = pool_intern(p->pool, (const char*)bytes, nlen); - p->c->env->heap->free(p->c->env->heap, bytes, 0); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); return pool_str(p->pool, s, NULL); } @@ -399,8 +399,10 @@ static void parse_asm_stmt(Parser* p) { if (accept_punct(p, ':')) { if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { cap_out = 4; - outs = (AsmConstraint*)arena_array(p->c->tu, AsmConstraint, cap_out); - out_lvs = (AsmOutLValue*)arena_array(p->c->tu, AsmOutLValue, cap_out); + outs = + (AsmConstraint*)arena_array(p->pool->arena, AsmConstraint, cap_out); + out_lvs = + (AsmOutLValue*)arena_array(p->pool->arena, AsmOutLValue, cap_out); for (;;) { AsmConstraint c; AsmOutLValue lv; @@ -412,8 +414,10 @@ static void parse_asm_stmt(Parser* p) { memset(&lv, 0, sizeof lv); c.name = parse_asm_operand_name(p); c.str = parse_asm_str(p, "asm output constraint"); - if (c.str && c.str[0] == '+') c.dir = ASM_INOUT; - else c.dir = ASM_OUT; + if (c.str && c.str[0] == '+') + c.dir = ASM_INOUT; + else + c.dir = ASM_OUT; expect_punct(p, '(', "'(' before asm output lvalue"); parse_assign_expr(p); val_ty = cg_top_type(p->cg); @@ -439,9 +443,9 @@ static void parse_asm_stmt(Parser* p) { if (nout == cap_out) { u32 nc = cap_out * 2; AsmConstraint* nb = - (AsmConstraint*)arena_array(p->c->tu, AsmConstraint, nc); + (AsmConstraint*)arena_array(p->pool->arena, AsmConstraint, nc); AsmOutLValue* nlv = - (AsmOutLValue*)arena_array(p->c->tu, AsmOutLValue, nc); + (AsmOutLValue*)arena_array(p->pool->arena, AsmOutLValue, nc); memcpy(nb, outs, sizeof(AsmConstraint) * nout); memcpy(nlv, out_lvs, sizeof(AsmOutLValue) * nout); outs = nb; @@ -458,7 +462,8 @@ static void parse_asm_stmt(Parser* p) { if (accept_punct(p, ':')) { if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { cap_in = 4; - ins = (AsmConstraint*)arena_array(p->c->tu, AsmConstraint, cap_in); + ins = + (AsmConstraint*)arena_array(p->pool->arena, AsmConstraint, cap_in); for (;;) { AsmConstraint c; memset(&c, 0, sizeof c); @@ -473,7 +478,7 @@ static void parse_asm_stmt(Parser* p) { if (nin == cap_in) { u32 nc = cap_in * 2; AsmConstraint* nb = - (AsmConstraint*)arena_array(p->c->tu, AsmConstraint, nc); + (AsmConstraint*)arena_array(p->pool->arena, AsmConstraint, nc); memcpy(nb, ins, sizeof(AsmConstraint) * nin); ins = nb; cap_in = nc; @@ -486,7 +491,7 @@ static void parse_asm_stmt(Parser* p) { if (accept_punct(p, ':')) { if (!is_punct(&p->cur, ':') && !is_punct(&p->cur, ')')) { cap_clob = 4; - clobbers = (Sym*)arena_array(p->c->tu, Sym, cap_clob); + clobbers = (Sym*)arena_array(p->pool->arena, Sym, cap_clob); for (;;) { const char* cstr; Sym cs; @@ -494,7 +499,7 @@ static void parse_asm_stmt(Parser* p) { cs = pool_intern_cstr(p->pool, cstr); if (nclob == cap_clob) { u32 nc = cap_clob * 2; - Sym* nb = (Sym*)arena_array(p->c->tu, Sym, nc); + Sym* nb = (Sym*)arena_array(p->pool->arena, Sym, nc); memcpy(nb, clobbers, sizeof(Sym) * nclob); clobbers = nb; cap_clob = nc; @@ -529,14 +534,14 @@ static void parse_asm_stmt(Parser* p) { if (outs[i].dir == ASM_INOUT) ninout++; } if (ninout > 0) { - static const char* const k_match_strs[10] = { - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; + static const char* const k_match_strs[10] = {"0", "1", "2", "3", "4", + "5", "6", "7", "8", "9"}; u32 need = nin + ninout; if (need > cap_in) { u32 nc = cap_in ? cap_in : 4; while (nc < need) nc *= 2; AsmConstraint* nb = - (AsmConstraint*)arena_array(p->c->tu, AsmConstraint, nc); + (AsmConstraint*)arena_array(p->pool->arena, AsmConstraint, nc); if (nin) memcpy(nb, ins, sizeof(AsmConstraint) * nin); ins = nb; cap_in = nc; @@ -544,8 +549,9 @@ static void parse_asm_stmt(Parser* p) { for (u32 i = 0; i < nout; ++i) { if (outs[i].dir != ASM_INOUT) continue; if (i >= 10) { - perr(p, "asm: '+r' constraint at output index >9 exceeds " - "matching-digit syntax"); + perr(p, + "asm: '+r' constraint at output index >9 exceeds " + "matching-digit syntax"); } AsmOutLValue* lv = &out_lvs[i]; cg_push_local_typed(p->cg, lv->addr_slot, lv->ptr_ty); diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -21,40 +21,40 @@ static const struct { AttrKind kind; AttrArgShape shape; } kAttrTable[] = { - {"packed", ATTR_PACKED, AS_NONE}, - {"aligned", ATTR_ALIGNED, AS_INT_OPT}, - {"section", ATTR_SECTION, AS_STRING}, - {"used", ATTR_USED, AS_NONE}, - {"noreturn", ATTR_NORETURN, AS_NONE}, - {"alias", ATTR_ALIAS, AS_STRING}, - {"weak", ATTR_WEAK, AS_NONE}, - {"visibility", ATTR_VISIBILITY, AS_STRING}, - {"always_inline", ATTR_ALWAYS_INLINE, AS_NONE}, - {"noinline", ATTR_NOINLINE, AS_NONE}, - {"unused", ATTR_UNUSED, AS_NONE}, - {"deprecated", ATTR_DEPRECATED, AS_OPAQUE}, - {"warn_unused_result", ATTR_WARN_UNUSED_RESULT, AS_NONE}, - {"format", ATTR_FORMAT, AS_FORMAT}, - {"nonnull", ATTR_NONNULL, AS_OPAQUE}, - {"returns_nonnull", ATTR_RETURNS_NONNULL, AS_NONE}, - {"pure", ATTR_PURE, AS_NONE}, - {"const", ATTR_CONST, AS_NONE}, - {"malloc", ATTR_MALLOC, AS_OPAQUE}, - {"nothrow", ATTR_NOTHROW, AS_NONE}, - {"leaf", ATTR_LEAF, AS_NONE}, - {"cold", ATTR_COLD, AS_NONE}, - {"hot", ATTR_HOT, AS_NONE}, - {"constructor", ATTR_CONSTRUCTOR, AS_INT_OPT}, - {"destructor", ATTR_DESTRUCTOR, AS_INT_OPT}, - {"cleanup", ATTR_CLEANUP, AS_IDENT}, - {"mode", ATTR_MODE, AS_IDENT}, - {"vector_size", ATTR_VECTOR_SIZE, AS_INT}, - {"transparent_union", ATTR_TRANSPARENT_UNION, AS_NONE}, - {"gnu_inline", ATTR_GNU_INLINE, AS_NONE}, - {"fallthrough", ATTR_FALLTHROUGH, AS_NONE}, - {"sentinel", ATTR_SENTINEL, AS_OPAQUE}, - {"no_instrument_function", ATTR_NO_INSTRUMENT_FUNCTION, AS_NONE}, - {"no_sanitize", ATTR_NO_SANITIZE, AS_OPAQUE}, + {"packed", ATTR_PACKED, AS_NONE}, + {"aligned", ATTR_ALIGNED, AS_INT_OPT}, + {"section", ATTR_SECTION, AS_STRING}, + {"used", ATTR_USED, AS_NONE}, + {"noreturn", ATTR_NORETURN, AS_NONE}, + {"alias", ATTR_ALIAS, AS_STRING}, + {"weak", ATTR_WEAK, AS_NONE}, + {"visibility", ATTR_VISIBILITY, AS_STRING}, + {"always_inline", ATTR_ALWAYS_INLINE, AS_NONE}, + {"noinline", ATTR_NOINLINE, AS_NONE}, + {"unused", ATTR_UNUSED, AS_NONE}, + {"deprecated", ATTR_DEPRECATED, AS_OPAQUE}, + {"warn_unused_result", ATTR_WARN_UNUSED_RESULT, AS_NONE}, + {"format", ATTR_FORMAT, AS_FORMAT}, + {"nonnull", ATTR_NONNULL, AS_OPAQUE}, + {"returns_nonnull", ATTR_RETURNS_NONNULL, AS_NONE}, + {"pure", ATTR_PURE, AS_NONE}, + {"const", ATTR_CONST, AS_NONE}, + {"malloc", ATTR_MALLOC, AS_OPAQUE}, + {"nothrow", ATTR_NOTHROW, AS_NONE}, + {"leaf", ATTR_LEAF, AS_NONE}, + {"cold", ATTR_COLD, AS_NONE}, + {"hot", ATTR_HOT, AS_NONE}, + {"constructor", ATTR_CONSTRUCTOR, AS_INT_OPT}, + {"destructor", ATTR_DESTRUCTOR, AS_INT_OPT}, + {"cleanup", ATTR_CLEANUP, AS_IDENT}, + {"mode", ATTR_MODE, AS_IDENT}, + {"vector_size", ATTR_VECTOR_SIZE, AS_INT}, + {"transparent_union", ATTR_TRANSPARENT_UNION, AS_NONE}, + {"gnu_inline", ATTR_GNU_INLINE, AS_NONE}, + {"fallthrough", ATTR_FALLTHROUGH, AS_NONE}, + {"sentinel", ATTR_SENTINEL, AS_OPAQUE}, + {"no_instrument_function", ATTR_NO_INSTRUMENT_FUNCTION, AS_NONE}, + {"no_sanitize", ATTR_NO_SANITIZE, AS_OPAQUE}, }; static SrcLoc tok_loc(const Tok* t) { return t->loc; } @@ -75,10 +75,10 @@ int starts_attr(const Parser* p) { return p->cur.kind == TOK_IDENT && p->cur.v.ident == p->sym_attribute; } -static void attr_canon_range(const char* s, size_t len, - const char** out_p, size_t* out_len) { - if (len >= 4 && s[0] == '_' && s[1] == '_' && - s[len - 1] == '_' && s[len - 2] == '_') { +static void attr_canon_range(const char* s, size_t len, const char** out_p, + size_t* out_len) { + if (len >= 4 && s[0] == '_' && s[1] == '_' && s[len - 1] == '_' && + s[len - 2] == '_') { *out_p = s + 2; *out_len = len - 4; return; @@ -119,10 +119,14 @@ static void skip_balanced_parens(Parser* p) { if (p->cur.kind == TOK_EOF) { perr(p, "unexpected EOF inside attribute arguments"); } - if (is_punct(&p->cur, '(')) ++depth; + if (is_punct(&p->cur, '(')) + ++depth; else if (is_punct(&p->cur, ')')) { --depth; - if (depth == 0) { advance(p); return; } + if (depth == 0) { + advance(p); + return; + } } advance(p); } @@ -155,8 +159,7 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, advance(p); /* '(' */ if (is_punct(&p->cur, ')')) { if (shape == AS_INT) { - perr(p, "attribute '%s' expects an integer argument", - attr_diag_name); + perr(p, "attribute '%s' expects an integer argument", attr_diag_name); } advance(p); return; @@ -177,8 +180,8 @@ static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape, size_t nlen = 0; u8* bytes = decode_string_literal(p, &t, &nlen); u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0; - a->v.sym = pool_intern(p->c->global, (const char*)bytes, ilen); - p->c->env->heap->free(p->c->env->heap, bytes, 0); + a->v.sym = pool_intern(p->pool, (const char*)bytes, ilen); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); } a->nargs = 1; advance(p); @@ -243,13 +246,14 @@ Attr* parse_attribute_spec_list(Parser* p) { size_t diag_len; const char* canon; size_t canon_len; - while (accept_punct(p, ',')) { /* skip */ } + while (accept_punct(p, ',')) { /* skip */ + } if (is_punct(&p->cur, ')')) break; if (p->cur.kind != TOK_IDENT) { perr(p, "expected attribute name"); } aname = p->cur.v.ident; - a = arena_new(p->c->tu, Attr); + a = arena_new(p->pool->arena, Attr); if (!a) perr(p, "out of memory in parse_attribute_spec_list"); memset(a, 0, sizeof *a); a->loc = tok_loc(&p->cur); @@ -258,9 +262,13 @@ Attr* parse_attribute_spec_list(Parser* p) { advance(p); diag_name = pool_str(p->pool, aname, &diag_len); attr_canon_range(diag_name, diag_len, &canon, &canon_len); - (void)canon; (void)canon_len; + (void)canon; + (void)canon_len; parse_attr_args(p, a, shape, diag_name ? diag_name : "<unknown>"); - if (tail) tail->next = a; else head = a; + if (tail) + tail->next = a; + else + head = a; tail = a; if (!accept_punct(p, ',')) break; } @@ -278,7 +286,10 @@ void parse_and_discard_attributes(Parser* p) { /* Append `add` to the end of `*head` (linked via Attr.next). */ void attr_list_append(Attr** head, Attr* add) { if (!add) return; - if (!*head) { *head = add; return; } + if (!*head) { + *head = add; + return; + } Attr* tail = *head; while (tail->next) tail = tail->next; tail->next = add; @@ -424,43 +435,92 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { continue; } if (is_kw(p, &t, KW_VOID)) { - acc.saw_void = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_void = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_CHAR)) { - acc.saw_char = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_char = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_INT)) { - acc.saw_int = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_int = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_SHORT)) { - acc.saw_short = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_short = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_LONG)) { - acc.long_count++; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.long_count++; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_SIGNED)) { - acc.saw_signed = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_signed = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_UNSIGNED)) { - acc.saw_unsigned = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_unsigned = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_BOOL)) { - acc.saw_bool = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_bool = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_FLOAT)) { - acc.saw_float = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_float = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_DOUBLE)) { - acc.saw_double = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_double = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (t.kind == TOK_IDENT && t.v.ident == p->sym_int128) { - acc.saw_int128 = 1; acc.saw_explicit_type = 1; advance(p); seen = 1; + acc.saw_int128 = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (t.kind == TOK_IDENT && t.v.ident == p->sym_int128_t) { - acc.saw_int128 = 1; acc.saw_signed = 1; acc.saw_explicit_type = 1; - advance(p); seen = 1; + acc.saw_int128 = 1; + acc.saw_signed = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (t.kind == TOK_IDENT && t.v.ident == p->sym_uint128_t) { - acc.saw_int128 = 1; acc.saw_unsigned = 1; acc.saw_explicit_type = 1; - advance(p); seen = 1; + acc.saw_int128 = 1; + acc.saw_unsigned = 1; + acc.saw_explicit_type = 1; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_STATIC)) { - out->storage = DS_STATIC; advance(p); seen = 1; + out->storage = DS_STATIC; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_EXTERN)) { - out->storage = DS_EXTERN; advance(p); seen = 1; + out->storage = DS_EXTERN; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_CONST)) { - out->quals |= Q_CONST; advance(p); seen = 1; + out->quals |= Q_CONST; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_VOLATILE)) { - out->quals |= Q_VOLATILE; advance(p); seen = 1; + out->quals |= Q_VOLATILE; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_RESTRICT)) { - out->quals |= Q_RESTRICT; advance(p); seen = 1; + out->quals |= Q_RESTRICT; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_ATOMIC)) { Tok n = peek1(p); if (is_punct(&n, '(')) { @@ -477,9 +537,13 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { seen = 1; continue; } - out->quals |= Q_ATOMIC; advance(p); seen = 1; + out->quals |= Q_ATOMIC; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_TYPEDEF)) { - out->storage = DS_TYPEDEF; advance(p); seen = 1; + out->storage = DS_TYPEDEF; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_ALIGNAS)) { u32 a = 0; advance(p); /* `_Alignas` */ @@ -496,14 +560,19 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { if (a > out->align) out->align = a; seen = 1; } else if (is_kw(p, &t, KW_INLINE)) { - out->flags |= DF_INLINE; advance(p); seen = 1; + out->flags |= DF_INLINE; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_THREAD_LOCAL)) { - out->flags |= DF_THREAD; advance(p); seen = 1; + out->flags |= DF_THREAD; + advance(p); + seen = 1; } else if (is_kw(p, &t, KW_NORETURN) || is_kw(p, &t, KW_REGISTER) || is_kw(p, &t, KW_AUTO)) { - advance(p); seen = 1; - } else if (!acc.saw_explicit_type && !tagged_ty && - t.kind == TOK_IDENT && ident_kw(p, t.v.ident) == KW_NONE) { + advance(p); + seen = 1; + } 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 = c_abi_va_list_type(p->abi, p->pool); acc.saw_explicit_type = 1; @@ -544,11 +613,11 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { * struct / union / enum * ============================================================ */ -int find_field(TargetABI* abi, const Type* rec, Sym name, +int find_field(TargetABI* abi, Pool* pool, 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 = c_abi_record_layout(abi, rec); + const ABIRecordLayout* L = c_abi_record_layout(abi, pool, rec); if (!L) return 0; for (u16 i = 0; i < rec->rec.nfields; ++i) { const Field* f = &rec->rec.fields[i]; @@ -558,12 +627,13 @@ int find_field(TargetABI* abi, const Type* rec, Sym name, *out_field = f; return 1; } - if ((f->flags & FIELD_ANON) && (f->type->kind == TY_STRUCT || - f->type->kind == TY_UNION)) { + if ((f->flags & FIELD_ANON) && + (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) { const Type* inner_ty = NULL; u32 inner_off = 0; const Field* inner_f = NULL; - if (find_field(abi, f->type, name, &inner_ty, &inner_off, &inner_f)) { + if (find_field(abi, pool, f->type, name, &inner_ty, &inner_off, + &inner_f)) { *out_type = inner_ty; *out_offset = L->fields[i].offset + inner_off; *out_field = inner_f; @@ -581,8 +651,8 @@ static void parse_member_decls(Parser* p, TypeRecordBuilder* b) { perr(p, "expected member declaration"); } if (is_punct(&p->cur, ';')) { - if (specs.type && (specs.type->kind == TY_STRUCT || - specs.type->kind == TY_UNION)) { + if (specs.type && + (specs.type->kind == TY_STRUCT || specs.type->kind == TY_UNION)) { Field f; memset(&f, 0, sizeof f); f.name = 0; @@ -709,8 +779,7 @@ const Type* parse_struct_or_union(Parser* p, TypeKind kind, } { const Type* fresh = type_record_end(p->pool, b); - type_record_install(target, (Field*)fresh->rec.fields, - fresh->rec.nfields); + type_record_install(target, (Field*)fresh->rec.fields, fresh->rec.nfields); } { TypeRecordOpts opts; @@ -837,7 +906,8 @@ int starts_type_name(const Parser* p, const Tok* t) { case KW_NONE: { if (t->v.ident == p->sym_b_va_list) return 1; if (t->v.ident == p->sym_int128 || t->v.ident == p->sym_int128_t || - t->v.ident == p->sym_uint128_t) return 1; + t->v.ident == p->sym_uint128_t) + return 1; SymEntry* e = scope_lookup((Parser*)p, t->v.ident); return e && e->kind == SEK_TYPEDEF; } @@ -851,11 +921,26 @@ const Type* parse_pointer_layer(Parser* p, const Type* base) { u16 q = 0; base = type_ptr(p->pool, base); for (;;) { - if (accept_kw(p, KW_CONST)) { q |= Q_CONST; continue; } - if (accept_kw(p, KW_VOLATILE)) { q |= Q_VOLATILE; continue; } - if (accept_kw(p, KW_RESTRICT)) { q |= Q_RESTRICT; continue; } - if (accept_kw(p, KW_ATOMIC)) { q |= Q_ATOMIC; continue; } - if (starts_attr(p)) { parse_and_discard_attributes(p); continue; } + if (accept_kw(p, KW_CONST)) { + q |= Q_CONST; + continue; + } + if (accept_kw(p, KW_VOLATILE)) { + q |= Q_VOLATILE; + continue; + } + if (accept_kw(p, KW_RESTRICT)) { + q |= Q_RESTRICT; + continue; + } + if (accept_kw(p, KW_ATOMIC)) { + q |= Q_ATOMIC; + continue; + } + if (starts_attr(p)) { + parse_and_discard_attributes(p); + continue; + } break; } if (q) base = type_qualified(p->pool, base, q); @@ -870,8 +955,8 @@ const Type* parse_type_name(Parser* p) { if (!parse_decl_specs(p, &specs)) { perr(p, "expected type-name"); } - return parse_declarator_full(p, specs.type, /*allow_abstract=*/1, - &dummy_name, &dummy_loc); + return parse_declarator_full(p, specs.type, /*allow_abstract=*/1, &dummy_name, + &dummy_loc); } /* ============================================================ @@ -903,7 +988,8 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { if (p->cur.kind == TOK_EOF) { perr(p, "unexpected EOF in parameter array bound"); } - if (is_punct(&p->cur, '[')) ++depth; + if (is_punct(&p->cur, '[')) + ++depth; else if (is_punct(&p->cur, ']')) { --depth; if (depth == 0) break; @@ -968,14 +1054,15 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { } const Type* apply_decl_suffix(Parser* p, const Type* base, - const DeclSuffix* s) { + const DeclSuffix* s) { if (s->kind == DS_ARRAY) { return type_array(p->pool, base, s->count, s->incomplete || s->vla); } { const Type** ptypes = NULL; if (s->nparams) { - ptypes = (const Type**)arena_array(p->c->tu, const Type*, s->nparams); + ptypes = + (const Type**)arena_array(p->pool->arena, const Type*, s->nparams); for (u16 i = 0; i < s->nparams; ++i) ptypes[i] = s->params[i].type; } return type_func(p->pool, base, ptypes, s->nparams, (int)s->variadic); @@ -995,8 +1082,7 @@ const Type* parse_declarator_full(Parser* p, const Type* base, const Type* parse_declarator_full_ex(Parser* p, const Type* base, int allow_abstract, Sym* name_out, - SrcLoc* loc_out, - Attr** attrs_out) { + SrcLoc* loc_out, Attr** attrs_out) { base = parse_pointer_layer(p, base); Sym name = 0; @@ -1023,11 +1109,26 @@ const Type* parse_declarator_full_ex(Parser* p, const Type* base, u16 q = 0; if (nptrs_inner >= 8) perr(p, "too many pointer levels"); for (;;) { - if (accept_kw(p, KW_CONST)) { q |= Q_CONST; continue; } - if (accept_kw(p, KW_VOLATILE)) { q |= Q_VOLATILE; continue; } - if (accept_kw(p, KW_RESTRICT)) { q |= Q_RESTRICT; continue; } - if (accept_kw(p, KW_ATOMIC)) { q |= Q_ATOMIC; continue; } - if (starts_attr(p)) { parse_and_discard_attributes(p); continue; } + if (accept_kw(p, KW_CONST)) { + q |= Q_CONST; + continue; + } + if (accept_kw(p, KW_VOLATILE)) { + q |= Q_VOLATILE; + continue; + } + if (accept_kw(p, KW_RESTRICT)) { + q |= Q_RESTRICT; + continue; + } + if (accept_kw(p, KW_ATOMIC)) { + q |= Q_ATOMIC; + continue; + } + if (starts_attr(p)) { + parse_and_discard_attributes(p); + continue; + } break; } inner_quals[nptrs_inner++] = q; @@ -1060,8 +1161,10 @@ const Type* parse_declarator_full_ex(Parser* p, const Type* base, } if (starts_attr(p)) { - if (attrs_out) parse_attrs_into(p, attrs_out); - else parse_and_discard_attributes(p); + if (attrs_out) + parse_attrs_into(p, attrs_out); + else + parse_and_discard_attributes(p); } DeclSuffix suffs[8]; @@ -1070,8 +1173,10 @@ const Type* parse_declarator_full_ex(Parser* p, const Type* base, if (!parse_decl_suffix(p, &suffs[nsuffs])) break; ++nsuffs; if (starts_attr(p)) { - if (attrs_out) parse_attrs_into(p, attrs_out); - else parse_and_discard_attributes(p); + if (attrs_out) + parse_attrs_into(p, attrs_out); + else + parse_and_discard_attributes(p); } } if (nsuffs == 8 && (is_punct(&p->cur, '[') || is_punct(&p->cur, '('))) { @@ -1098,8 +1203,9 @@ const Type* parse_declarator_full_ex(Parser* p, const Type* base, } const Type* parse_declarator(Parser* p, const Type* base, Sym* name_out, - SrcLoc* loc_out) { - return parse_declarator_full(p, base, /*allow_abstract=*/0, name_out, loc_out); + SrcLoc* loc_out) { + return parse_declarator_full(p, base, /*allow_abstract=*/0, name_out, + loc_out); } /* ============================================================ @@ -1114,7 +1220,7 @@ const Type* complete_incomplete_array(Parser* p, const Type* ty) { Tok t = p->cur; size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); - p->c->env->heap->free(p->c->env->heap, bytes, 0); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); return type_array(p->pool, elem, (u32)n, /*incomplete=*/0); } if (is_punct(&p->cur, '{')) { @@ -1126,7 +1232,7 @@ const Type* complete_incomplete_array(Parser* p, const Type* ty) { Tok t = p->replay[1]; size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); - p->c->env->heap->free(p->c->env->heap, bytes, 0); + cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); cnt = (u32)n; } replay_rewind(p); diff --git a/lang/c/pp/pp.c b/lang/c/pp/pp.c @@ -142,8 +142,8 @@ Tok pp_next(Pp* pp) { } /* Not a pragma — push the peeked token back as a 1-element buffer * so the next pp_next_raw returns it, and surface the hash now. */ - Tok* keep = arena_array(&pp->arena, Tok, 1); - HidesetId* hs = arena_array(&pp->arena, HidesetId, 1); + Tok* keep = arena_array(pp->arena, Tok, 1); + HidesetId* hs = arena_array(pp->arena, HidesetId, 1); keep[0] = t2; hs[0] = HS_EMPTY; push_buf(pp, keep, hs, 1); @@ -180,7 +180,7 @@ void pp_emit_text(Pp* pp, Writer* out) { } if (t.spelling) { size_t slen = 0; - const char* s = pool_str(pp->c->global, t.spelling, &slen); + const char* s = pool_str(pp->pool, t.spelling, &slen); w_str(out, s, slen); } at_bol = 0; @@ -192,7 +192,7 @@ void pp_emit_text(Pp* pp, Writer* out) { * ============================================================ */ static void pp_intern_keywords(Pp* pp) { - Pool* p = pp->c->global; + Pool* p = pp->pool; pp->sym_define = pool_intern_cstr(p, "define"); pp->sym_undef = pool_intern_cstr(p, "undef"); pp->sym_include = pool_intern_cstr(p, "include"); @@ -269,11 +269,11 @@ static void compute_date_time(Pp* pp) { "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; char date[24]; char tm[16]; - int64_t t = pp->c->env->now; + int64_t t = cfree_compiler_now(pp->c); PpYMD ymd; if (t < 0) { - pp->val_date_str = pool_intern_cstr(pp->c->global, "\"??? ?? ????\""); - pp->val_time_str = pool_intern_cstr(pp->c->global, "\"??:??:??\""); + pp->val_date_str = pool_intern_cstr(pp->pool, "\"??? ?? ????\""); + pp->val_time_str = pool_intern_cstr(pp->pool, "\"??:??:??\""); return; } pp_break_time(t, &ymd); @@ -292,7 +292,7 @@ static void compute_date_time(Pp* pp) { date[p++] = (char)('0' + (yyyy / 10) % 10); date[p++] = (char)('0' + (yyyy) % 10); date[p++] = '"'; - pp->val_date_str = pool_intern(pp->c->global, date, (size_t)p); + pp->val_date_str = pool_intern(pp->pool, date, (size_t)p); } { int hh = ymd.h, mm = ymd.m, ss = ymd.s; @@ -307,7 +307,7 @@ static void compute_date_time(Pp* pp) { tm[p++] = (char)('0' + (ss / 10) % 10); tm[p++] = (char)('0' + ss % 10); tm[p++] = '"'; - pp->val_time_str = pool_intern(pp->c->global, tm, (size_t)p); + pp->val_time_str = pool_intern(pp->pool, tm, (size_t)p); } } @@ -333,10 +333,11 @@ static void pp_register_static_predefined(Pp* pp) { * cfree supports), ptr_size == 4 picks ILP32. LLP64 (Windows x86-64) is * not yet a supported target, so `long` always tracks pointer width here. */ static void pp_register_target_predefined(Pp* pp) { - int lp64 = (pp->c->target.ptr_size == 8); + CfreeTarget target = cfree_compiler_target(pp->c); + int lp64 = (target.ptr_size == 8); pp_define(pp, "__USER_LABEL_PREFIX__", - pp->c->target.obj == CFREE_OBJ_MACHO ? "_" : ""); + target.obj == CFREE_OBJ_MACHO ? "_" : ""); /* stddef.h base aliases */ pp_define(pp, "__SIZE_TYPE__", lp64 ? "unsigned long" : "unsigned int"); @@ -447,12 +448,19 @@ static void pp_register_target_predefined(Pp* pp) { } Pp* pp_new(Compiler* c) { - Heap* h = (Heap*)c->env->heap; + Heap* h = (Heap*)cfree_compiler_heap(c); Pp* pp = (Pp*)h->alloc(h, sizeof(*pp), _Alignof(Pp)); if (!pp) return NULL; memset(pp, 0, sizeof(*pp)); pp->c = c; - arena_init(&pp->arena, h, 64 * 1024); + pp->pool = c_pool_new(c); + pp->arena = cfree_arena_new(h, 64 * 1024); + if (!pp->pool || !pp->arena) { + c_pool_free(pp->pool); + cfree_arena_free(pp->arena); + h->free(h, pp, sizeof(*pp)); + return NULL; + } /* Reserve hideset slot 0 for HS_EMPTY. The slot is unused but the * indexing convention costs only a pointer. */ pp->hsets_cap = 8; @@ -469,7 +477,9 @@ Pp* pp_new(Compiler* c) { } void pp_free(Pp* pp) { + Heap* h; if (!pp) return; + h = pp_heap(pp); /* Pop / close any remaining lex sources. */ while (pp->nsources) src_pop(pp); pp_xfree(pp, pp->sources, sizeof(TokSrc) * pp->sources_cap); @@ -477,8 +487,9 @@ void pp_free(Pp* pp) { pp_xfree(pp, pp->hsets, sizeof(Hideset*) * pp->hsets_cap); pp_xfree(pp, pp->ifstk, sizeof(IfFrame) * pp->ifstk_cap); pp_xfree(pp, pp->inc_dirs, sizeof(*pp->inc_dirs) * pp->inc_dirs_cap); - arena_fini(&pp->arena); - pp_heap(pp)->free((Heap*)pp->c->env->heap, pp, sizeof(*pp)); + c_pool_free(pp->pool); + cfree_arena_free(pp->arena); + h->free(h, pp, sizeof(*pp)); } void pp_push_input(Pp* pp, Lexer* lex) { @@ -546,13 +557,13 @@ void pp_define(Pp* pp, const char* name, const char* body) { void pp_undef(Pp* pp, const char* name) { Sym s; if (!name || !*name) return; - s = pool_intern_cstr(pp->c->global, name); + s = pool_intern_cstr(pp->pool, name); mt_del(pp, s); } void pp_add_include_edge(Pp* pp, u32 includer, u32 included, SrcLoc include_loc, int system) { - source_add_include(pp->c->sources, includer, included, include_loc, system); + cfree_source_add_include(pp->c, includer, included, include_loc, system); } const LitInfo* pp_lit(const Pp* pp, LitId id) { diff --git a/lang/c/pp/pp.h b/lang/c/pp/pp.h @@ -5,8 +5,8 @@ typedef struct Pp Pp; -/* PP reads file_io from c->env for include search. If include search is - * configured but c->env->file_io is missing, include resolution panics. */ +/* PP reads the compiler file-IO service for include search. If include search + * is configured but file_io is missing, include resolution panics. */ Pp* pp_new(Compiler*); void pp_free(Pp*); diff --git a/lang/c/pp/pp_directive.c b/lang/c/pp/pp_directive.c @@ -42,7 +42,7 @@ void read_directive_line(Pp* pp, Tok** out_toks, u32* out_n) { if (t.kind == TOK_NEWLINE || t.kind == TOK_EOF) break; if (n == cap) { u32 nc = cap ? cap * 2 : 8; - Tok* nb = (Tok*)arena_alloc(&pp->arena, sizeof(Tok) * nc, _Alignof(Tok)); + Tok* nb = (Tok*)arena_alloc(pp->arena, sizeof(Tok) * nc, _Alignof(Tok)); if (cap) memcpy(nb, buf, sizeof(Tok) * cap); buf = nb; cap = nc; @@ -120,8 +120,7 @@ static void prepass_defined(Pp* pp, const Tok* in, u32 nin, TokVec* out) { t.kind = TOK_NUM; t.flags = in[i].flags & (TF_AT_BOL | TF_HAS_SPACE); t.loc = in[i].loc; - t.spelling = - pool_intern_cstr(pp->c->global, mt_get(pp, ident) ? "1" : "0"); + t.spelling = pool_intern_cstr(pp->pool, mt_get(pp, ident) ? "1" : "0"); tv_push(pp, out, t); } i = j - 1; @@ -137,13 +136,13 @@ static void prepass_defined(Pp* pp, const Tok* in, u32 nin, TokVec* out) { static void expand_for_if(Pp* pp, const Tok* in, u32 nin, TokVec* out) { Tok* slice; if (nin == 0) return; - slice = arena_array(&pp->arena, Tok, nin); + slice = arena_array(pp->arena, Tok, nin); memcpy(slice, in, sizeof(Tok) * nin); expand_arg_to_eof(pp, slice, nin, out); /* Replace remaining identifiers with `0`. */ { u32 i; - Sym zero = pool_intern_cstr(pp->c->global, "0"); + Sym zero = pool_intern_cstr(pp->pool, "0"); for (i = 0; i < out->n; ++i) { if (out->data[i].kind == TOK_IDENT) { out->data[i].kind = TOK_NUM; @@ -182,7 +181,7 @@ static i64 ee_primary(EE* e) { if (!t) compiler_panic(e->pp->c, e->loc, "#if: missing operand"); if (t->kind == TOK_NUM) { size_t slen; - const char* s = pool_str(e->pp->c->global, t->spelling, &slen); + const char* s = pool_str(e->pp->pool, t->spelling, &slen); ++e->pos; return parse_pp_int(s, slen); } @@ -191,7 +190,7 @@ static i64 ee_primary(EE* e) { * not implemented; cover the common case of a single ASCII * char). */ size_t slen; - const char* s = pool_str(e->pp->c->global, t->spelling, &slen); + const char* s = pool_str(e->pp->pool, t->spelling, &slen); ++e->pos; if (slen >= 3 && s[0] == '\'') return (unsigned char)s[1]; return 0; @@ -585,7 +584,7 @@ static int try_open_include(Pp* pp, const char* path, const u8** data_out, u8* buf; memset(&fd, 0, sizeof(fd)); - io = pp->c->env->file_io; + io = cfree_compiler_file_io(pp->c); if (!io || !io->read_all) { compiler_panic(pp->c, (SrcLoc){0, 0, 0}, "#include: env.file_io is not configured"); @@ -593,7 +592,7 @@ static int try_open_include(Pp* pp, const char* path, const u8** data_out, if (!io->read_all(io->user, path, &fd)) return 0; { size_t sz = fd.size; - buf = (u8*)arena_alloc(&pp->arena, sz ? sz : 1, 1); + buf = (u8*)arena_alloc(pp->arena, sz ? sz : 1, 1); if (sz && fd.data) memcpy(buf, fd.data, sz); if (io->release) io->release(io->user, &fd); /* zeros fd */ *data_out = buf; @@ -606,12 +605,15 @@ static int try_open_include(Pp* pp, const char* path, const u8** data_out, * for in-memory/builtin sources (where CWD is the natural fallback, like * gcc treats stdin). `dir_out` must point to a buffer of size >= cap. */ static int includer_dir(Pp* pp, SrcLoc loc, char* dir_out, size_t cap) { - const SourceFile* sf = source_file(pp->c->sources, loc.file_id); + CfreeSourceFile sf; const char* p = NULL; size_t plen = 0; const char* slash; size_t dlen; - if (sf && sf->name) p = pool_str(pp->c->global, sf->name, &plen); + memset(&sf, 0, sizeof(sf)); + if (cfree_source_file(pp->c, loc.file_id, &sf) == 0 && sf.name) { + p = pool_str(pp->pool, sf.name, &plen); + } if (!p || plen == 0 || p[0] == '<') { if (cap < 2) return 0; dir_out[0] = '.'; @@ -706,7 +708,7 @@ static void parse_include_path(Pp* pp, const Tok* line, u32 n, SrcLoc loc, if (line[0].kind == TOK_HEADER) { size_t slen = 0; - const char* s = pool_str(pp->c->global, line[0].spelling, &slen); + const char* s = pool_str(pp->pool, line[0].spelling, &slen); if (slen < 2) compiler_panic(pp->c, loc, "#include: malformed header name"); if (s[0] == '<' && s[slen - 1] == '>') *system_out = 1; @@ -724,7 +726,7 @@ static void parse_include_path(Pp* pp, const Tok* line, u32 n, SrcLoc loc, /* Macro-replaced form. */ { TokVec exp = {0}; - Tok* slice = arena_array(&pp->arena, Tok, n); + Tok* slice = arena_array(pp->arena, Tok, n); memcpy(slice, line, sizeof(Tok) * n); expand_arg_to_eof(pp, slice, n, &exp); @@ -733,7 +735,7 @@ static void parse_include_path(Pp* pp, const Tok* line, u32 n, SrcLoc loc, } if (exp.data[0].kind == TOK_STR) { size_t slen = 0; - const char* s = pool_str(pp->c->global, exp.data[0].spelling, &slen); + const char* s = pool_str(pp->pool, exp.data[0].spelling, &slen); if (slen < 2 || s[0] != '"' || s[slen - 1] != '"') { compiler_panic(pp->c, loc, "#include: malformed string"); } @@ -755,7 +757,7 @@ static void parse_include_path(Pp* pp, const Tok* line, u32 n, SrcLoc loc, break; } if (exp.data[i].spelling) { - s = pool_str(pp->c->global, exp.data[i].spelling, &slen); + s = pool_str(pp->pool, exp.data[i].spelling, &slen); } if (s && pos + slen + 1 <= cap) { memcpy(path_out + pos, s, slen); @@ -807,8 +809,7 @@ static void do_include(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { s.lex = lex; src_push(pp, s); - source_add_include(pp->c->sources, includer_id, included_id, loc, - system_form); + cfree_source_add_include(pp->c, includer_id, included_id, loc, system_form); } /* ============================================================ @@ -835,7 +836,7 @@ static void do_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { Sym target_file = 0; if (n == 0) compiler_panic(pp->c, loc, "#line: missing arguments"); - slice = arena_array(&pp->arena, Tok, n); + slice = arena_array(pp->arena, Tok, n); memcpy(slice, line, sizeof(Tok) * n); expand_arg_to_eof(pp, slice, n, &exp); @@ -844,7 +845,7 @@ static void do_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { } { size_t sl = 0; - const char* s = pool_str(pp->c->global, exp.data[0].spelling, &sl); + const char* s = pool_str(pp->pool, exp.data[0].spelling, &sl); target_line = parse_pp_int(s, sl); } if (exp.n >= 2) { @@ -853,9 +854,9 @@ static void do_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { } { size_t sl = 0; - const char* s = pool_str(pp->c->global, exp.data[1].spelling, &sl); + const char* s = pool_str(pp->pool, exp.data[1].spelling, &sl); if (sl >= 2 && s[0] == '"' && s[sl - 1] == '"') { - target_file = pool_intern(pp->c->global, s + 1, sl - 2); + target_file = pool_intern(pp->pool, s + 1, sl - 2); } } } @@ -889,7 +890,7 @@ void emit_pragma_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { hash.kind = TOK_PP_HASH; hash.flags = TF_AT_BOL; hash.loc = loc; - hash.spelling = pool_intern_cstr(pp->c->global, "#"); + hash.spelling = pool_intern_cstr(pp->pool, "#"); tv_push(pp, &out, hash); memset(&ident, 0, sizeof(ident)); @@ -915,7 +916,7 @@ void emit_pragma_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { nl.loc = loc; tv_push(pp, &out, nl); - hids = arena_array(&pp->arena, HidesetId, out.n ? out.n : 1); + hids = arena_array(pp->arena, HidesetId, out.n ? out.n : 1); for (i = 0; i < out.n; ++i) hids[i] = HS_EMPTY; push_buf(pp, out.data, hids, out.n); } @@ -933,7 +934,7 @@ static void do_pragma(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { static void destringize(Pp* pp, const Tok* str_tok, char* out, size_t cap, size_t* out_len) { size_t slen = 0; - const char* s = pool_str(pp->c->global, str_tok->spelling, &slen); + const char* s = pool_str(pp->pool, str_tok->spelling, &slen); size_t i, w = 0; if (slen < 2 || s[0] != '"' || s[slen - 1] != '"') { compiler_panic(pp->c, str_tok->loc, @@ -997,7 +998,7 @@ int try_expand_pragma_op(Pp* pp, const Tok* invoke) { /* Re-lex into args. Bytes need to live until lex_close; copy into * arena. */ { - char* arena_buf = (char*)arena_alloc(&pp->arena, buf_n + 1, 1); + char* arena_buf = (char*)arena_alloc(pp->arena, buf_n + 1, 1); memcpy(arena_buf, buf, buf_n + 1); lex = lex_open_mem(pp->c, "<_Pragma>", arena_buf, buf_n); } @@ -1022,9 +1023,8 @@ static void do_error(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { u32 i; for (i = 0; i < n; ++i) { size_t sl = 0; - const char* s = line[i].spelling - ? pool_str(pp->c->global, line[i].spelling, &sl) - : NULL; + const char* s = + line[i].spelling ? pool_str(pp->pool, line[i].spelling, &sl) : NULL; if (i > 0) cb_putc(pp, &cb, ' '); if (s && sl) cb_append(pp, &cb, s, (u32)sl); } @@ -1054,7 +1054,7 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { if (line[0].kind == TOK_HEADER) { size_t sl = 0; - const char* s = pool_str(pp->c->global, line[0].spelling, &sl); + const char* s = pool_str(pp->pool, line[0].spelling, &sl); if (sl < 2) compiler_panic(pp->c, loc, "#embed: malformed header name"); if (s[0] == '<' && s[sl - 1] == '>') system_form = 1; @@ -1074,7 +1074,7 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { while (j < n) { if (line[j].kind == TOK_IDENT) { size_t sl = 0; - const char* s = pool_str(pp->c->global, line[j].v.ident, &sl); + const char* s = pool_str(pp->pool, line[j].v.ident, &sl); if (sl == 5 && memcmp(s, "limit", 5) == 0) { if (j + 1 >= n || line[j + 1].kind != TOK_PUNCT || line[j + 1].v.punct != '(') { @@ -1086,7 +1086,7 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { } { size_t sl2 = 0; - const char* s2 = pool_str(pp->c->global, line[j].spelling, &sl2); + const char* s2 = pool_str(pp->pool, line[j].spelling, &sl2); limit_n = parse_pp_int(s2, sl2); } ++j; @@ -1119,7 +1119,7 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { if (j >= n) { compiler_panic(pp->c, loc, "#embed: unterminated if_empty"); } - if_empty_toks = arena_array(&pp->arena, Tok, j - start ? j - start : 1); + if_empty_toks = arena_array(pp->arena, Tok, j - start ? j - start : 1); if_empty_n = j - start; memcpy(if_empty_toks, line + start, sizeof(Tok) * if_empty_n); ++j; /* skip ')' */ @@ -1141,7 +1141,7 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { if (emit_n == 0) { /* Empty: emit if_empty payload (or nothing). */ if (if_empty_toks && if_empty_n) { - HidesetId* hids = arena_array(&pp->arena, HidesetId, if_empty_n); + HidesetId* hids = arena_array(pp->arena, HidesetId, if_empty_n); u32 i; for (i = 0; i < if_empty_n; ++i) hids[i] = HS_EMPTY; push_buf(pp, if_empty_toks, hids, if_empty_n); @@ -1174,7 +1174,7 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { memset(&t, 0, sizeof(t)); t.kind = TOK_NUM; t.loc = loc; - t.spelling = pool_intern(pp->c->global, numbuf, (size_t)nl); + t.spelling = pool_intern(pp->pool, numbuf, (size_t)nl); if (i == 0) t.flags = TF_AT_BOL; /* Bytes after a comma get a leading space to match * clang's `, ` separator format. */ @@ -1188,11 +1188,11 @@ static void do_embed(Pp* pp, const Tok* line, u32 n, SrcLoc loc) { comma.kind = TOK_PUNCT; comma.v.punct = ','; comma.loc = loc; - comma.spelling = pool_intern_cstr(pp->c->global, ","); + comma.spelling = pool_intern_cstr(pp->pool, ","); tv_push(pp, &out, comma); } } - hids = arena_array(&pp->arena, HidesetId, out.n ? out.n : 1); + hids = arena_array(pp->arena, HidesetId, out.n ? out.n : 1); { u32 k; for (k = 0; k < out.n; ++k) hids[k] = HS_EMPTY; diff --git a/lang/c/pp/pp_expand.c b/lang/c/pp/pp_expand.c @@ -41,7 +41,7 @@ static HidesetId hs_register(Pp* pp, const Sym* names, u32 n) { sizeof(Hideset*) * nc, _Alignof(Hideset*)); pp->hsets_cap = nc; } - h = (Hideset*)arena_alloc(&pp->arena, + h = (Hideset*)arena_alloc(pp->arena, sizeof(Hideset) + sizeof(Sym) * (n ? n - 1 : 0), _Alignof(Hideset)); h->n = n; @@ -149,7 +149,7 @@ void do_define(Pp* pp, const Tok* line, u32 n) { def_loc = line[i].loc; ++i; - m = arena_znew(&pp->arena, Macro); + m = arena_znew(pp->arena, Macro); m->name = name; m->def_loc = def_loc; @@ -174,7 +174,7 @@ void do_define(Pp* pp, const Tok* line, u32 n) { * matches the standard identifier directly. */ if (pn == pcap) { u32 nc = pcap ? pcap * 2 : 4; - Sym* nb = arena_array(&pp->arena, Sym, nc); + Sym* nb = arena_array(pp->arena, Sym, nc); if (pcap) memcpy(nb, params, sizeof(Sym) * pcap); params = nb; pcap = nc; @@ -185,7 +185,7 @@ void do_define(Pp* pp, const Tok* line, u32 n) { } else if (line[i].kind == TOK_IDENT) { if (pn == pcap) { u32 nc = pcap ? pcap * 2 : 4; - Sym* nb = arena_array(&pp->arena, Sym, nc); + Sym* nb = arena_array(pp->arena, Sym, nc); if (pcap) memcpy(nb, params, sizeof(Sym) * pcap); params = nb; pcap = nc; @@ -246,7 +246,7 @@ void do_define(Pp* pp, const Tok* line, u32 n) { { u32 body_n = n - i; u32 j; - m->body = body_n ? arena_array(&pp->arena, Tok, body_n) : NULL; + m->body = body_n ? arena_array(pp->arena, Tok, body_n) : NULL; m->body_len = body_n; for (j = 0; j < body_n; ++j) { Tok t = line[i + j]; @@ -361,7 +361,7 @@ static void expand_object_macro(Pp* pp, const Macro* m, const Tok* invoke, } /* Run the body through the paste phase: object-like macros may use * `##`. There are no parameters, so phase 1 reduces to a copy. */ - tmp = arena_array(&pp->arena, Tok, m->body_len); + tmp = arena_array(pp->arena, Tok, m->body_len); for (i = 0; i < m->body_len; ++i) tmp[i] = m->body[i]; subst_phase2(pp, tmp, m->body_len, invoke, &body); @@ -374,7 +374,7 @@ static void expand_object_macro(Pp* pp, const Macro* m, const Tok* invoke, for (i = 0; i < body.n; ++i) body.data[i].loc = invoke->loc; hs = hs_add(pp, invoke_hs, m->name); - hids = arena_array(&pp->arena, HidesetId, body.n); + hids = arena_array(pp->arena, HidesetId, body.n); for (i = 0; i < body.n; ++i) hids[i] = hs; push_buf(pp, body.data, hids, body.n); } @@ -483,7 +483,7 @@ static Tok read_invocation_args(Pp* pp, const Macro* m, SrcLoc invoke_loc, Tok close_tok; memset(out, 0, sizeof(*out)); - starts = arena_array(&pp->arena, u32, 8); + starts = arena_array(pp->arena, u32, 8); starts_cap = 8; starts[0] = 0; @@ -534,7 +534,7 @@ static Tok read_invocation_args(Pp* pp, const Macro* m, SrcLoc invoke_loc, if (want_slot) { if (n_args + 1 >= starts_cap) { u32 nc = starts_cap * 2; - u32* nb = arena_array(&pp->arena, u32, nc); + u32* nb = arena_array(pp->arena, u32, nc); memcpy(nb, starts, sizeof(u32) * starts_cap); starts = nb; starts_cap = nc; @@ -558,7 +558,7 @@ static Tok read_invocation_args(Pp* pp, const Macro* m, SrcLoc invoke_loc, /* Close current arg, start next. */ if (n_args + 1 >= starts_cap) { u32 nc = starts_cap * 2; - u32* nb = arena_array(&pp->arena, u32, nc); + u32* nb = arena_array(pp->arena, u32, nc); memcpy(nb, starts, sizeof(u32) * starts_cap); starts = nb; starts_cap = nc; @@ -594,7 +594,7 @@ done: if (n_args + 1 == expected) { if (n_args + 1 >= starts_cap) { u32 nc = starts_cap * 2; - u32* nb = arena_array(&pp->arena, u32, nc); + u32* nb = arena_array(pp->arena, u32, nc); memcpy(nb, starts, sizeof(u32) * starts_cap); starts = nb; starts_cap = nc; @@ -623,7 +623,7 @@ static void preexpand_args(Pp* pp, ArgList* a) { TokVec exp = {0}; u32* exp_start; u32 i; - exp_start = arena_array(&pp->arena, u32, a->n_args + 1); + exp_start = arena_array(pp->arena, u32, a->n_args + 1); exp_start[0] = 0; for (i = 0; i < a->n_args; ++i) { u32 lo = a->raw_start[i]; @@ -631,7 +631,7 @@ static void preexpand_args(Pp* pp, ArgList* a) { if (hi > lo) { /* Copy the slice into a fresh buffer so expand_arg_to_eof can * own it without aliasing. */ - Tok* slice = arena_array(&pp->arena, Tok, hi - lo); + Tok* slice = arena_array(pp->arena, Tok, hi - lo); memcpy(slice, &a->raw[lo], sizeof(Tok) * (hi - lo)); expand_arg_to_eof(pp, slice, hi - lo, &exp); } @@ -657,7 +657,7 @@ static Tok make_stringize(Pp* pp, const Tok* arg, u32 lo, u32 hi, SrcLoc loc) { const Tok* at = &arg[i]; size_t slen = 0; const char* s = - at->spelling ? pool_str(pp->c->global, at->spelling, &slen) : NULL; + at->spelling ? pool_str(pp->pool, at->spelling, &slen) : NULL; if (i > lo && (at->flags & TF_HAS_SPACE)) cb_putc(pp, &b, ' '); if (s && slen) { int esc = (at->kind == TOK_STR || at->kind == TOK_CHR); @@ -671,7 +671,7 @@ static Tok make_stringize(Pp* pp, const Tok* arg, u32 lo, u32 hi, SrcLoc loc) { } cb_putc(pp, &b, '"'); - sp = pool_intern(pp->c->global, b.data, b.len); + sp = pool_intern(pp->pool, b.data, b.len); memset(&t, 0, sizeof(t)); t.kind = TOK_STR; t.loc = loc; @@ -693,8 +693,8 @@ static Tok paste_tokens(Pp* pp, Tok lhs, Tok rhs, SrcLoc loc) { if (lhs.kind == TOK_PP_PLACEMARKER) return rhs; if (rhs.kind == TOK_PP_PLACEMARKER) return lhs; - a = lhs.spelling ? pool_str(pp->c->global, lhs.spelling, &alen) : ""; - b = rhs.spelling ? pool_str(pp->c->global, rhs.spelling, &blen) : ""; + a = lhs.spelling ? pool_str(pp->pool, lhs.spelling, &alen) : ""; + b = rhs.spelling ? pool_str(pp->pool, rhs.spelling, &blen) : ""; if (alen + blen + 2 > sizeof(buf)) { compiler_panic(pp->c, loc, "token paste: spelling too long"); } @@ -892,7 +892,7 @@ static int try_expand_func_macro(Pp* pp, const Macro* m, const Tok* invoke, { u32 i; - HidesetId* hids = arena_array(&pp->arena, HidesetId, body.n ? body.n : 1); + HidesetId* hids = arena_array(pp->arena, HidesetId, body.n ? body.n : 1); for (i = 0; i < body.n; ++i) { hids[i] = (HidesetId)hsvec.data[i].spelling; } @@ -946,7 +946,7 @@ Tok pp_next_raw(Pp* pp) { while (j > 0) buf[k++] = tmp[--j]; } t.kind = TOK_NUM; - t.spelling = pool_intern(pp->c->global, buf, (size_t)k); + t.spelling = pool_intern(pp->pool, buf, (size_t)k); return t; } if (id == pp->sym_file__) { @@ -958,17 +958,19 @@ Tok pp_next_raw(Pp* pp) { if (ls && ls->file_override) { name = ls->file_override; } else if (ls) { - const SourceFile* sf = - source_file(pp->c->sources, lex_file_id(ls->lex)); - if (sf) name = sf->name; + CfreeSourceFile sf; + memset(&sf, 0, sizeof(sf)); + if (cfree_source_file(pp->c, lex_file_id(ls->lex), &sf) == 0) { + name = sf.name; + } } - if (name) nstr = pool_str(pp->c->global, name, &nlen); - buf = (char*)arena_alloc(&pp->arena, nlen + 2, 1); + if (name) nstr = pool_str(pp->pool, name, &nlen); + buf = (char*)arena_alloc(pp->arena, nlen + 2, 1); buf[0] = '"'; if (nlen) memcpy(buf + 1, nstr, nlen); buf[nlen + 1] = '"'; t.kind = TOK_STR; - t.spelling = pool_intern(pp->c->global, buf, nlen + 2); + t.spelling = pool_intern(pp->pool, buf, nlen + 2); t.v.str = t.spelling; return t; } diff --git a/lang/c/pp/pp_priv.h b/lang/c/pp/pp_priv.h @@ -5,22 +5,18 @@ #ifndef CFREE_PP_PRIV_H #define CFREE_PP_PRIV_H -#include "pp/pp.h" - #include <stdlib.h> #include <string.h> -#include "core/arena.h" -#include "core/diag.h" -#include "core/heap.h" -#include "core/pool.h" +#include "c_support.h" +#include "pp/pp.h" /* ============================================================ * Internal token kinds * ============================================================ */ /* Outside the range used by the lexer (TOK_KW_LAST = 0x1000). */ -#define TOK_PP_PARAM ((u16)0x1100) +#define TOK_PP_PARAM ((u16)0x1100) #define TOK_PP_PLACEMARKER ((u16)0x1101) /* empty-arg substitution marker */ /* ============================================================ @@ -73,9 +69,9 @@ typedef struct TokSrc { } TokSrc; typedef enum IfState { - IF_INCLUDE = 1, /* group active, emit code */ + IF_INCLUDE = 1, /* group active, emit code */ IF_SEEK_TRUE = 2, /* skip, looking for the first true elif/else */ - IF_DONE = 3, /* skip, already had a true branch */ + IF_DONE = 3, /* skip, already had a true branch */ } IfState; typedef struct IfFrame { @@ -87,9 +83,9 @@ typedef struct IfFrame { /* MacroMap = Sym -> Macro*. Generated open-addressed hashmap with * deletion (#undef). See core/hashmap.h. */ -#include "core/hashmap.h" -static inline u32 macro_hash_(Sym s) { return hash_u32((u32)s); } -HASHMAP_DEFINE(MacroMap, Sym, Macro*, macro_hash_); +#include <cfree/hashmap.h> +static inline u32 macro_hash_(Sym s) { return cfree_hash_u32((u32)s); } +CFREE_HASHMAP_DEFINE(MacroMap, Sym, Macro*, macro_hash_); /* ============================================================ * Pp struct (definition shared across all three TUs) @@ -97,6 +93,7 @@ HASHMAP_DEFINE(MacroMap, Sym, Macro*, macro_hash_); struct Pp { Compiler* c; + Pool* pool; /* Source stack — top of stack is sources[nsources-1]. */ TokSrc* sources; @@ -126,7 +123,7 @@ struct Pp { /* Internal arena: macro bodies, hidesets, expansion buffers, file * data for #include. Lives until pp_free. */ - Arena arena; + CfreeArena* arena; /* Cached interned identifiers used for directive recognition. */ Sym sym_define; @@ -165,10 +162,10 @@ struct Pp { * Allocation helpers (defined in pp.c, used everywhere) * ============================================================ */ -static inline Heap* pp_heap(Pp* pp) { return (Heap*)pp->c->env->heap; } +static inline Heap* pp_heap(Pp* pp) { return cfree_compiler_heap(pp->c); } static inline void* pp_xrealloc(Pp* pp, void* p, size_t old_n, size_t new_n, - size_t align) { + size_t align) { Heap* h = pp_heap(pp); void* q = h->realloc(h, p, old_n, new_n, align); if (!q) compiler_panic(pp->c, (SrcLoc){0, 0, 0}, "pp: out of memory"); @@ -195,7 +192,7 @@ static inline void tv_grow(Pp* pp, TokVec* v, u32 want) { nc = v->cap ? v->cap * 2 : 8; while (nc < want) nc *= 2; { - Tok* nb = arena_array(&pp->arena, Tok, nc); + Tok* nb = arena_array(pp->arena, Tok, nc); if (v->n) memcpy(nb, v->data, sizeof(Tok) * v->n); v->data = nb; v->cap = nc; @@ -219,7 +216,7 @@ static inline void cb_append(Pp* pp, CharBuf* b, const char* s, u32 n) { u32 nc = b->cap ? b->cap * 2 : 64; while (nc < b->len + n) nc *= 2; { - char* nb = (char*)arena_alloc(&pp->arena, nc, 1); + char* nb = (char*)arena_alloc(pp->arena, nc, 1); if (b->len) memcpy(nb, b->data, b->len); b->data = nb; b->cap = nc; @@ -250,11 +247,11 @@ Tok pp_next_raw(Pp* pp); /* --- pp_expand.c → pp.c, pp_directive.c --- */ HidesetId hs_add(Pp* pp, HidesetId id, Sym s); -int hs_contains(Pp* pp, HidesetId id, Sym s); -Macro* mt_get(Pp* pp, Sym name); -void mt_put(Pp* pp, Sym name, Macro* m); -void mt_del(Pp* pp, Sym name); -void expand_arg_to_eof(Pp* pp, Tok* in, u32 nin, TokVec* out); +int hs_contains(Pp* pp, HidesetId id, Sym s); +Macro* mt_get(Pp* pp, Sym name); +void mt_put(Pp* pp, Sym name, Macro* m); +void mt_del(Pp* pp, Sym name); +void expand_arg_to_eof(Pp* pp, Tok* in, u32 nin, TokVec* out); /* --- pp_directive.c → pp_expand.c --- */ i64 eval_if_expr(Pp* pp, const Tok* line, u32 n, SrcLoc loc); @@ -262,8 +259,8 @@ void process_directive(Pp* pp, SrcLoc hash_loc); /* --- pp_directive.c internal helpers called from pp_expand.c --- */ void emit_pragma_line(Pp* pp, const Tok* line, u32 n, SrcLoc loc); -int peek_for_invoke_paren(Pp* pp, int* ws_has_space_out); -int try_expand_pragma_op(Pp* pp, const Tok* invoke); +int peek_for_invoke_paren(Pp* pp, int* ws_has_space_out); +int try_expand_pragma_op(Pp* pp, const Tok* invoke); /* --- pp_directive.c: read_directive_line (used by pp.c/pp_define) --- */ void read_directive_line(Pp* pp, Tok** out_toks, u32* out_n); diff --git a/lang/c/type/type.c b/lang/c/type/type.c @@ -21,9 +21,6 @@ #include <stdint.h> #include <string.h> -#include "core/arena.h" -#include "core/pool.h" - #define NUM_PRIM_KINDS ((unsigned)TY_LDOUBLE + 1u) typedef struct TypeListNode TypeListNode; @@ -44,7 +41,7 @@ typedef struct PoolTypeCache { static PoolTypeCache* cache_get(Pool* p) { PoolTypeCache* c = (PoolTypeCache*)p->type_cache; if (c) return c; - c = arena_new(&p->arena, PoolTypeCache); + c = arena_new(p->arena, PoolTypeCache); if (!c) return NULL; memset(c, 0, sizeof *c); c->next_tag = 1; @@ -53,7 +50,7 @@ static PoolTypeCache* cache_get(Pool* p) { } static Type* alloc_type_node(Pool* p, PoolTypeCache* c) { - TypeListNode* n = arena_new(&p->arena, TypeListNode); + TypeListNode* n = arena_new(p->arena, TypeListNode); if (!n) return NULL; memset(n, 0, sizeof *n); n->next = c->derived; @@ -140,7 +137,7 @@ const Type* type_func(Pool* p, const Type* ret, const Type** params, u16 n, t->fn.nparams = n; t->fn.variadic = (u8)(variadic ? 1 : 0); if (n) { - const Type** dst = arena_array(&p->arena, const Type*, n); + const Type** dst = arena_array(p->arena, const Type*, n); if (!dst) return NULL; for (u16 i = 0; i < n; ++i) dst[i] = params[i]; t->fn.params = dst; @@ -207,7 +204,7 @@ TypeRecordBuilder* type_record_begin(Pool* p, TypeKind kind, TagId tag_id, TypeRecordBuilder* type_record_begin_ex(Pool* p, TypeKind kind, TagId tag_id, Sym tag, TypeRecordOpts opts) { - TypeRecordBuilder* b = arena_new(&p->arena, TypeRecordBuilder); + TypeRecordBuilder* b = arena_new(p->arena, TypeRecordBuilder); if (!b) return NULL; memset(b, 0, sizeof *b); b->pool = p; @@ -221,7 +218,7 @@ TypeRecordBuilder* type_record_begin_ex(Pool* p, TypeKind kind, TagId tag_id, void type_record_field(TypeRecordBuilder* b, Field f) { if (b->nfields == b->cap) { u32 nc = b->cap ? b->cap * 2 : 4; - Field* nf = arena_array(&b->pool->arena, Field, nc); + Field* nf = arena_array(b->pool->arena, Field, nc); if (!nf) return; if (b->fields) memcpy(nf, b->fields, sizeof(Field) * b->nfields); b->fields = nf; @@ -350,8 +347,10 @@ int type_is_ptr(const Type* t) { return t && t->kind == TY_PTR; } static CfreeCgTypeId type_cg_builtin(CfreeCompiler* c, TypeKind kind) { CfreeCgBuiltinTypes b = cfree_cg_builtin_types(c); switch (kind) { - case TY_VOID: return b.id[CFREE_CG_BUILTIN_VOID]; - case TY_BOOL: return b.id[CFREE_CG_BUILTIN_BOOL]; + case TY_VOID: + return b.id[CFREE_CG_BUILTIN_VOID]; + case TY_BOOL: + return b.id[CFREE_CG_BUILTIN_BOOL]; case TY_CHAR: case TY_SCHAR: case TY_UCHAR: @@ -370,7 +369,8 @@ static CfreeCgTypeId type_cg_builtin(CfreeCompiler* c, TypeKind kind) { case TY_INT128: case TY_UINT128: return b.id[CFREE_CG_BUILTIN_I128]; - case TY_FLOAT: return b.id[CFREE_CG_BUILTIN_F32]; + case TY_FLOAT: + return b.id[CFREE_CG_BUILTIN_F32]; case TY_DOUBLE: case TY_LDOUBLE: return b.id[CFREE_CG_BUILTIN_F64]; @@ -380,7 +380,7 @@ static CfreeCgTypeId type_cg_builtin(CfreeCompiler* c, TypeKind kind) { return CFREE_CG_TYPE_NONE; } -static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, const Type* t, +static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, Pool* p, const Type* t, const Type* pending_record) { CfreeCgTypeId id; if (!c || !t) return CFREE_CG_TYPE_NONE; @@ -390,28 +390,27 @@ static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, const Type* t, case TY_PTR: { const Type* pointee = t->ptr.pointee; if (pointee == pending_record) { - pointee = type_void(c->global); + pointee = type_void(p); } - return cfree_cg_type_ptr(c, type_cg_id_walk(c, pointee, pending_record), - 0); + return cfree_cg_type_ptr( + c, type_cg_id_walk(c, p, pointee, pending_record), 0); } case TY_ARRAY: - return cfree_cg_type_array(c, type_cg_id_walk(c, t->arr.elem, - pending_record), - t->arr.count); + return cfree_cg_type_array( + c, type_cg_id_walk(c, p, t->arr.elem, pending_record), t->arr.count); case TY_FUNC: { CfreeCgParam* params = NULL; CfreeCgFuncSig sig; memset(&sig, 0, sizeof sig); - sig.ret = type_cg_id_walk(c, t->fn.ret, pending_record); + sig.ret = type_cg_id_walk(c, p, t->fn.ret, pending_record); sig.nparams = t->fn.nparams; sig.abi_variadic = t->fn.variadic; sig.call_conv = CFREE_CG_CC_TARGET_C; if (t->fn.nparams) { - params = arena_zarray(c->tu, CfreeCgParam, t->fn.nparams); + params = arena_zarray(p->arena, CfreeCgParam, t->fn.nparams); for (u32 i = 0; i < t->fn.nparams; ++i) { params[i].type = - type_cg_id_walk(c, t->fn.params[i], pending_record); + type_cg_id_walk(c, p, t->fn.params[i], pending_record); } } sig.params = params; @@ -422,10 +421,10 @@ static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, const Type* t, CfreeCgField* fields = NULL; CfreeCgRecordDesc desc; if (t->rec.nfields) { - fields = arena_zarray(c->tu, CfreeCgField, t->rec.nfields); + fields = arena_zarray(p->arena, 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].type = type_cg_id_walk(c, p, 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; @@ -444,10 +443,9 @@ static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, const Type* t, return cfree_cg_type_record_ex(c, &desc); } case TY_ENUM: - return cfree_cg_type_enum(c, t->enm.tag, - type_cg_id_walk(c, t->enm.base, - pending_record), - NULL, 0); + return cfree_cg_type_enum( + c, t->enm.tag, type_cg_id_walk(c, p, t->enm.base, pending_record), + NULL, 0); default: if (id != CFREE_CG_TYPE_NONE) { return cfree_cg_type_alias(c, 0, id); @@ -456,6 +454,16 @@ static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, const Type* t, } } +CfreeCgTypeId type_cg_id_in_pool(CfreeCompiler* c, Pool* p, const Type* t) { + if (!p) return CFREE_CG_TYPE_NONE; + return type_cg_id_walk(c, p, t, NULL); +} + CfreeCgTypeId type_cg_id(CfreeCompiler* c, const Type* t) { - return type_cg_id_walk(c, t, NULL); + CfreeCgTypeId id; + Pool* p = c_pool_new(c); + if (!p) return CFREE_CG_TYPE_NONE; + id = type_cg_id_in_pool(c, p, t); + c_pool_free(p); + return id; } diff --git a/lang/c/type/type.h b/lang/c/type/type.h @@ -3,8 +3,7 @@ #include <cfree/cg.h> -#include "core/core.h" -#include "core/pool.h" +#include "c_support.h" typedef enum TypeKind { TY_VOID, @@ -151,8 +150,8 @@ typedef struct TypeRecordOpts { * options on the builder; type_record_end copies them to Type.rec. The * plain type_record_begin is equivalent to passing a zeroed * TypeRecordOpts. */ -TypeRecordBuilder* type_record_begin_ex(Pool*, TypeKind kind, TagId, - Sym tag, TypeRecordOpts); +TypeRecordBuilder* type_record_begin_ex(Pool*, TypeKind kind, TagId, Sym tag, + TypeRecordOpts); void type_record_field(TypeRecordBuilder*, Field); const Type* type_record_end(Pool*, TypeRecordBuilder*); /* Forward-declared struct/union: returns a mutable, incomplete Type with the @@ -170,6 +169,7 @@ int type_is_arith(const Type*); int type_is_int(const Type*); int type_is_ptr(const Type*); +CfreeCgTypeId type_cg_id_in_pool(CfreeCompiler*, Pool*, const Type*); CfreeCgTypeId type_cg_id(CfreeCompiler*, const Type*); #endif diff --git a/src/api/frontend.c b/src/api/frontend.c @@ -0,0 +1,133 @@ +#include <cfree/frontend.h> +#include <setjmp.h> +#include <stdarg.h> +#include <string.h> + +#include "core/arena.h" +#include "core/core.h" +#include "core/pool.h" + +struct CfreeArena { + Arena inner; +}; + +CfreeArena* cfree_arena_new(CfreeHeap* h, size_t block_size) { + CfreeArena* a; + if (!h) return NULL; + a = (CfreeArena*)h->alloc(h, sizeof(*a), _Alignof(CfreeArena)); + if (!a) return NULL; + arena_init(&a->inner, (Heap*)h, block_size); + return a; +} + +void cfree_arena_free(CfreeArena* a) { + CfreeHeap* h; + if (!a) return; + h = a->inner.heap; + arena_fini(&a->inner); + h->free(h, a, sizeof(*a)); +} + +void cfree_arena_reset(CfreeArena* a) { + if (a) arena_reset(&a->inner); +} + +void* cfree_arena_alloc(CfreeArena* a, size_t size, size_t align) { + return a ? arena_alloc(&a->inner, size, align) : NULL; +} + +void* cfree_arena_zalloc(CfreeArena* a, size_t size, size_t align) { + return a ? arena_zalloc(&a->inner, size, align) : NULL; +} + +char* cfree_arena_strdup(CfreeArena* a, const char* s, size_t len) { + return a ? arena_strdup(&a->inner, s, len) : NULL; +} + +CfreeHeap* cfree_compiler_heap(CfreeCompiler* c) { + return (c && c->env) ? (CfreeHeap*)c->env->heap : NULL; +} + +const CfreeFileIO* cfree_compiler_file_io(CfreeCompiler* c) { + return (c && c->env) ? c->env->file_io : NULL; +} + +int64_t cfree_compiler_now(CfreeCompiler* c) { + return (c && c->env) ? c->env->now : -1; +} + +CfreeSym cfree_sym_intern_len(CfreeCompiler* c, const char* str, size_t len) { + if (!c || !str || len == 0) return 0; + return pool_intern(c->global, str, len); +} + +const char* cfree_sym_str(CfreeCompiler* c, CfreeSym sym, size_t* len_out) { + if (!c) { + if (len_out) *len_out = 0; + return NULL; + } + return pool_str(c->global, (Sym)sym, len_out); +} + +uint32_t cfree_source_add_file(CfreeCompiler* c, const char* path, + int system_header) { + return c ? source_add_file(c->sources, path, system_header) : 0; +} + +uint32_t cfree_source_add_memory(CfreeCompiler* c, const char* name) { + return c ? source_add_memory(c->sources, name) : 0; +} + +uint32_t cfree_source_add_builtin(CfreeCompiler* c, const char* name) { + return c ? source_add_builtin(c->sources, name) : 0; +} + +void cfree_source_add_include(CfreeCompiler* c, uint32_t includer_file_id, + uint32_t included_file_id, CfreeSrcLoc loc, + int system) { + if (!c) return; + source_add_include(c->sources, includer_file_id, included_file_id, loc, + system); +} + +int cfree_source_file(CfreeCompiler* c, uint32_t file_id, + CfreeSourceFile* out) { + const SourceFile* f; + if (!c || !out) return 1; + f = source_file(c->sources, file_id); + if (!f) return 1; + memset(out, 0, sizeof *out); + out->id = f->id; + out->name = f->name; + out->path = f->path; + out->kind = f->kind; + out->system_header = f->system_header; + return 0; +} + +int cfree_frontend_run(CfreeCompiler* c, CfreeFrontendRunFn fn, void* user) { + PanicSave saved; + int rc; + if (!c || !fn) return 1; + compiler_panic_save(c, &saved); + if (setjmp(c->panic)) { + compiler_run_cleanups(c); + compiler_panic_restore(c, &saved); + return 1; + } + rc = fn(c, user); + compiler_panic_restore(c, &saved); + return rc; +} + +void cfree_frontend_fatal(CfreeCompiler* c, CfreeSrcLoc loc, const char* fmt, + ...) { + va_list ap; + va_start(ap, fmt); + cfree_frontend_vfatal(c, loc, fmt, ap); +} + +void cfree_frontend_vfatal(CfreeCompiler* c, CfreeSrcLoc loc, const char* fmt, + va_list ap) { + compiler_panicv((Compiler*)c, loc, fmt, ap); +} diff --git a/src/core/hashmap.h b/src/core/hashmap.h @@ -1,202 +1,12 @@ -#ifndef CFREE_HASHMAP_H -#define CFREE_HASHMAP_H +#ifndef CFREE_INTERNAL_HASHMAP_H +#define CFREE_INTERNAL_HASHMAP_H -/* Generic open-addressed hashmap as a typed-macro template. - * - * Linear probing; doubling rehash at 75% load. Tombstoneless deletion - * via cluster rehash. Empty-key sentinel is 0 — slots are zero-initialized - * by allocation, and callers must never insert a key whose value compares - * equal to 0. (Sym=0 already means "none" per core.h:42; OBJ_SEC_NONE=0; - * pointer keys avoid 0 by construction.) - * - * HASHMAP_DEFINE(NAME, KT, VT, HASH_FN) - * NAME — struct typedef name for this instance. - * KT — key type (must support `== 0` and `==` against another KT). - * VT — value type (any assignable type). - * HASH_FN — function-like expression mapping KT -> u32. - * - * Emits typedef NAME, NAME##Slot, and these static functions: - * void NAME##_init (NAME*, Heap*) — default initial cap - * void NAME##_init_cap(NAME*, Heap*, u32 cap) — caller picks initial - * cap void NAME##_fini (NAME*) VT* NAME##_get (const NAME*, KT) — - * NULL if absent int NAME##_set (NAME*, KT, VT) — 1 - * inserted, 0 updated void NAME##_del (NAME*, KT) — no-op - * if absent - * - * Equality is `==` on KT. That covers all keys we use (Sym which is u32, - * u64 guest_pc). A string-keyed instance would need a small extension. - * - * Built-in mixers below cover u32 (hash_u32) and u64 (hash_u64) keys. */ - -#include <string.h> +#include <cfree/hashmap.h> #include "core/core.h" -#include "core/heap.h" - -/* xorshift mixer suitable for dense u32 keys (interned Sym ids etc.). */ -static inline u32 hash_u32(u32 x) { - x += 0x9e3779b9u; - x ^= x >> 16; - x *= 0x7feb352du; - x ^= x >> 15; - x *= 0x846ca68bu; - x ^= x >> 16; - return x; -} - -/* SplitMix-style mixer for u64 keys (e.g. guest PC). */ -static inline u32 hash_u64(u64 x) { - x ^= x >> 33; - x *= 0xff51afd7ed558ccdULL; - x ^= x >> 33; - x *= 0xc4ceb9fe1a85ec53ULL; - x ^= x >> 33; - return (u32)x; -} - -#define HASHMAP_LOAD_NUM 3u -#define HASHMAP_LOAD_DEN 4u -#define HASHMAP_INIT_CAP 16u -#define HASHMAP_DEFINE(NAME, KT, VT, HASH_FN) \ - typedef struct NAME##Slot { \ - KT k; \ - VT v; \ - } NAME##Slot; \ - typedef struct NAME { \ - Heap* heap; \ - NAME##Slot* slots; \ - u32 cap; \ - u32 used; \ - } NAME; \ - \ - __attribute__((unused)) static void NAME##_resize(NAME* m, u32 new_cap) { \ - NAME##Slot* fresh; \ - u32 i, mask; \ - fresh = (NAME##Slot*)m->heap->alloc(m->heap, sizeof(*fresh) * new_cap, \ - _Alignof(NAME##Slot)); \ - if (!fresh) return; \ - memset(fresh, 0, sizeof(*fresh) * new_cap); \ - mask = new_cap - 1u; \ - for (i = 0; i < m->cap; ++i) { \ - KT k = m->slots[i].k; \ - u32 j; \ - if (!(k)) continue; \ - j = HASH_FN(k) & mask; \ - while (fresh[j].k) j = (j + 1u) & mask; \ - fresh[j] = m->slots[i]; \ - } \ - if (m->slots) \ - m->heap->free(m->heap, m->slots, sizeof(*m->slots) * m->cap); \ - m->slots = fresh; \ - m->cap = new_cap; \ - } \ - \ - __attribute__((unused)) static inline void NAME##_init_cap(NAME* m, Heap* h, \ - u32 cap) { \ - m->heap = h; \ - m->slots = NULL; \ - m->cap = 0; \ - m->used = 0; \ - if (cap) NAME##_resize(m, cap); \ - } \ - \ - __attribute__((unused)) static inline void NAME##_init(NAME* m, Heap* h) { \ - NAME##_init_cap(m, h, HASHMAP_INIT_CAP); \ - } \ - \ - __attribute__((unused)) static inline void NAME##_fini(NAME* m) { \ - if (m->slots) \ - m->heap->free(m->heap, m->slots, sizeof(*m->slots) * m->cap); \ - m->slots = NULL; \ - m->cap = m->used = 0; \ - } \ - \ - __attribute__((unused)) static inline VT* NAME##_get(const NAME* m, KT k) { \ - u32 mask, j; \ - if (m->cap == 0 || !(k)) return NULL; \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) return &m->slots[j].v; \ - j = (j + 1u) & mask; \ - } \ - return NULL; \ - } \ - \ - __attribute__((unused)) static inline int NAME##_set(NAME* m, KT k, VT v) { \ - u32 mask, j; \ - if (m->cap == 0 || \ - m->used * HASHMAP_LOAD_DEN >= m->cap * HASHMAP_LOAD_NUM) \ - NAME##_resize(m, m->cap ? m->cap * 2u : HASHMAP_INIT_CAP); \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) { \ - m->slots[j].v = (v); \ - return 0; \ - } \ - j = (j + 1u) & mask; \ - } \ - m->slots[j].k = (k); \ - m->slots[j].v = (v); \ - m->used++; \ - return 1; \ - } \ - \ - /* Insert if absent. Returns 1 if newly inserted; 0 if k was present \ - * (in that case writes the existing value to *existing_out when \ - * existing_out is non-NULL). */ \ - __attribute__((unused)) static inline int NAME##_try_insert( \ - NAME* m, KT k, VT v, VT* existing_out) { \ - u32 mask, j; \ - if (m->cap == 0 || \ - m->used * HASHMAP_LOAD_DEN >= m->cap * HASHMAP_LOAD_NUM) \ - NAME##_resize(m, m->cap ? m->cap * 2u : HASHMAP_INIT_CAP); \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) { \ - if (existing_out) *existing_out = m->slots[j].v; \ - return 0; \ - } \ - j = (j + 1u) & mask; \ - } \ - m->slots[j].k = (k); \ - m->slots[j].v = (v); \ - m->used++; \ - return 1; \ - } \ - \ - __attribute__((unused)) static inline void NAME##_del(NAME* m, KT k) { \ - u32 mask, j; \ - if (m->cap == 0 || !(k)) return; \ - mask = m->cap - 1u; \ - j = HASH_FN(k) & mask; \ - while (m->slots[j].k) { \ - if (m->slots[j].k == (k)) { \ - u32 i = (j + 1u) & mask; \ - m->slots[j].k = 0; \ - m->used--; \ - while (m->slots[i].k) { \ - KT rk = m->slots[i].k; \ - VT rv = m->slots[i].v; \ - u32 nh; \ - m->slots[i].k = 0; \ - m->used--; \ - nh = HASH_FN(rk) & mask; \ - while (m->slots[nh].k) nh = (nh + 1u) & mask; \ - m->slots[nh].k = rk; \ - m->slots[nh].v = rv; \ - m->used++; \ - i = (i + 1u) & mask; \ - } \ - return; \ - } \ - j = (j + 1u) & mask; \ - } \ - } \ - /* trailing struct decl swallows the macro-call's semicolon */ \ - struct NAME +#define hash_u32 cfree_hash_u32 +#define hash_u64 cfree_hash_u64 +#define HASHMAP_DEFINE CFREE_HASHMAP_DEFINE #endif