kit

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

commit 1bf64d6836d6e075edcf407dc848c199f777f2ad
parent 005f891059421c2be387dc3f64435f9e797eff2a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 13 May 2026 10:21:15 -0700

Update cg impl + toy to the new cg api

Diffstat:
Mlang/toy/toy.c | 143++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/api/cg.c | 598++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mtest/api/cg_type_test.c | 44+++++++++++++++++++++++++++-----------------
Dtest/toy/cases/16_cg_api_alloca_memory_index.toy | 10----------
Rtest/toy/cases/16_cg_api_alloca_memory_index.expected -> test/toy/cases/16_cg_api_memory_index.expected | 0
Atest/toy/cases/16_cg_api_memory_index.toy | 11+++++++++++
Mtest/toy/demo.toy | 15++++++++-------
7 files changed, 600 insertions(+), 221 deletions(-)

diff --git a/lang/toy/toy.c b/lang/toy/toy.c @@ -23,14 +23,13 @@ * cfree_cg_type_enum * * Functions & data: - * cfree_cg_func_decl - * cfree_cg_data_decl / data_begin / data_bytes / data_zero - * cfree_cg_data_symbol / data_end + * cfree_cg_decl + * cfree_cg_data_begin / data_bytes / data_zero / data_addr / data_end * * Values: * cfree_cg_push_float * cfree_cg_push_bytes - * cfree_cg_push_symbol (non-ADDR kinds: PCREL, GOT, PLT, TLS_*) + * cfree_cg_push_symbol_addr / cfree_cg_push_symbol_lvalue * * Stack: * cfree_cg_swap @@ -377,6 +376,7 @@ typedef struct ToyVar { typedef struct ToyFn { CfreeSym name; + CfreeCgSym sym; CfreeCgTypeId type; CfreeCgTypeId ret; CfreeCgTypeId params[TOY_MAX_PARAMS]; @@ -386,6 +386,7 @@ typedef struct ToyFn { typedef struct ToyGlobal { CfreeSym name; + CfreeCgSym sym; CfreeCgTypeId type; int mutable; } ToyGlobal; @@ -424,6 +425,10 @@ typedef struct ToyParser { int has_error; } ToyParser; +static CfreeCgTypeId toy_builtin_type(ToyParser* p, CfreeCgBuiltinType ty) { + return p->types.id[ty]; +} + static void toy_parser_init(ToyParser* p, CfreeCompiler* c, CfreeCg* cg, const uint8_t* data, size_t len) { toy_lexer_init(&p->lex, data, len); @@ -431,9 +436,9 @@ static void toy_parser_init(ToyParser* p, CfreeCompiler* c, CfreeCg* cg, p->c = c; p->cg = cg; p->types = cfree_cg_builtin_types(c); - p->int_type = p->types.isize; + p->int_type = toy_builtin_type(p, CFREE_CG_BUILTIN_ISIZE); p->int_ptr_type = cfree_cg_type_ptr(c, p->int_type); - p->va_list_type = p->types.va_list; + p->va_list_type = toy_builtin_type(p, CFREE_CG_BUILTIN_VARARG_STATE); p->target = cfree_compiler_target(c); { CfreeCgField fields[2]; @@ -450,7 +455,7 @@ static void toy_parser_init(ToyParser* p, CfreeCompiler* c, CfreeCg* cg, p->nfns = 0; p->nglobals = 0; p->nscopes = 0; - p->cur_fn_ret = p->types.void_; + p->cur_fn_ret = toy_builtin_type(p, CFREE_CG_BUILTIN_VOID); p->diag = cfree_compiler_diag_sink(c); p->has_error = 0; } @@ -527,6 +532,16 @@ static ToyGlobal* toy_find_global(ToyParser* p, CfreeSym name) { return NULL; } +static CfreeCgSym toy_find_decl_sym(ToyParser* p, CfreeSym name) { + ToyGlobal* g = toy_find_global(p, name); + if (g) return g->sym; + { + ToyFn* fn = toy_find_fn(p, name); + if (fn) return fn->sym; + } + return CFREE_CG_SYM_NONE; +} + /* ============================================================ * Type parsing * ============================================================ */ @@ -684,7 +699,7 @@ static int toy_emit_var_addr(ToyParser* p, CfreeSym name) { { ToyGlobal* g = toy_find_global(p, name); if (g) { - cfree_cg_push_symbol(p->cg, name, g->type, CFREE_CG_SYMREF_ADDR, 0); + cfree_cg_push_symbol_addr(p->cg, g->sym, 0); return 1; } } @@ -700,8 +715,7 @@ static CfreeCgTypeId toy_emit_var_lvalue(ToyParser* p, CfreeSym name) { { ToyGlobal* g = toy_find_global(p, name); if (g) { - cfree_cg_push_symbol(p->cg, name, g->type, CFREE_CG_SYMREF_ADDR, 0); - cfree_cg_indirect(p->cg); + cfree_cg_push_symbol_lvalue(p->cg, g->sym, 0); return g->type; } } @@ -775,16 +789,6 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, return p->int_type; } - if (toy_sym_is(p, name, "alloca")) { - CfreeCgTypeId ty; - toy_parser_advance(p); - ty = toy_parse_expr(p); - if (ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; - if (!toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_alloca(p->cg, p->int_ptr_type, 8); - return p->int_ptr_type; - } - if (toy_sym_is(p, name, "index")) { CfreeCgTypeId base, idx; toy_parser_advance(p); @@ -905,7 +909,7 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (toy_sym_is(p, name, "va_start")) { if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_va_start(p->cg); + cfree_cg_vararg_start(p->cg); cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; } @@ -913,7 +917,7 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (toy_sym_is(p, name, "va_end")) { if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_va_end(p->cg); + cfree_cg_vararg_end(p->cg); cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; } @@ -922,7 +926,7 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parse_va_list_addr_arg(p) || !toy_expect_comma(p) || !toy_parse_va_list_addr_arg(p) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_va_copy(p->cg); + cfree_cg_vararg_copy(p->cg); cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; } @@ -934,16 +938,22 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, ty = toy_parse_type(p); if (ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; if (!toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_va_arg(p->cg, ty); + cfree_cg_vararg_next(p->cg, ty); return ty; } if (toy_sym_is(p, name, "fieldtest")) { uint64_t sz = cfree_cg_type_size(p->c, p->pair_type); + CfreeCgSlot slot; if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_push_int(p->cg, sz, p->int_type); - cfree_cg_alloca(p->cg, p->pair_ptr_type, cfree_cg_type_align(p->c, p->pair_type)); + if (sz == 0) { + toy_error(p, p->cur.loc, "invalid Pair layout"); + return CFREE_CG_TYPE_NONE; + } + slot = cfree_cg_local_slot(p->cg, p->pair_type, 0); + cfree_cg_push_local(p->cg, slot); + cfree_cg_addr(p->cg); cfree_cg_dup(p->cg); cfree_cg_indirect(p->cg); cfree_cg_field(p->cg, 1); @@ -1248,8 +1258,6 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { } toy_parser_advance(p); /* ( */ - cfree_cg_push_symbol(p->cg, name, fn->type, CFREE_CG_SYMREF_ADDR, 0); - CfreeCgTypeId arg_types[TOY_MAX_PARAMS]; size_t nargs = 0; if (p->cur.kind != TOK_RPAREN) { @@ -1288,7 +1296,7 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { } } - cfree_cg_call(p->cg, (uint32_t)nargs, fn->type); + cfree_cg_call_symbol(p->cg, fn->sym, (uint32_t)nargs); return fn->ret; } @@ -1301,8 +1309,7 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { } ToyGlobal* g = toy_find_global(p, name); if (g) { - cfree_cg_push_symbol(p->cg, name, g->type, CFREE_CG_SYMREF_ADDR, 0); - cfree_cg_indirect(p->cg); + cfree_cg_push_symbol_lvalue(p->cg, g->sym, 0); cfree_cg_load(p->cg); return g->type; } @@ -1379,7 +1386,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { toy_error(p, p->cur.loc, "undefined variable"); return CFREE_CG_TYPE_NONE; } - cfree_cg_push_symbol(p->cg, name, g->type, CFREE_CG_SYMREF_ADDR, 0); + cfree_cg_push_symbol_addr(p->cg, g->sym, 0); return cfree_cg_type_ptr(p->c, g->type); } } @@ -1813,7 +1820,6 @@ static int toy_parse_return_stmt(ToyParser* p) { } toy_parser_advance(p); if (!toy_parser_expect(p, TOK_LPAREN)) return 0; - cfree_cg_push_symbol(p->cg, name, fn->type, CFREE_CG_SYMREF_ADDR, 0); if (p->cur.kind != TOK_RPAREN) { for (;;) { CfreeCgTypeId arg_ty = toy_parse_expr(p); @@ -1831,13 +1837,13 @@ static int toy_parse_return_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "tail call signature mismatch"); return 0; } - cfree_cg_tail_call(p->cg, (uint32_t)nargs, fn->type); + cfree_cg_tail_call_symbol(p->cg, fn->sym, (uint32_t)nargs); if (!toy_parser_expect(p, TOK_SEMI)) return 0; return 1; } if (p->cur.kind == TOK_SEMI) { toy_parser_advance(p); - if (p->cur_fn_ret != p->types.void_) { + if (p->cur_fn_ret != toy_builtin_type(p, CFREE_CG_BUILTIN_VOID)) { toy_error(p, p->cur.loc, "return without value in non-void function"); return 0; } @@ -1911,8 +1917,7 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "type mismatch in assignment"); return 0; } - cfree_cg_push_symbol(p->cg, name, g->type, CFREE_CG_SYMREF_ADDR, 0); - cfree_cg_indirect(p->cg); + cfree_cg_push_symbol_lvalue(p->cg, g->sym, 0); cfree_cg_swap(p->cg); cfree_cg_store(p->cg); } @@ -2031,7 +2036,7 @@ static int toy_parse_fn(ToyParser* p) { ret_type = toy_parse_type(p); if (ret_type == CFREE_CG_TYPE_NONE) return -1; } else { - ret_type = p->types.void_; + ret_type = toy_builtin_type(p, CFREE_CG_BUILTIN_VOID); } /* Build function type */ @@ -2042,13 +2047,23 @@ static int toy_parse_fn(ToyParser* p) { return -1; } - /* Register function for recursion and later calls */ + memset(&attrs, 0, sizeof(attrs)); + attrs.kind = CFREE_CG_DECL_FUNC; + attrs.sym.bind = CFREE_SB_GLOBAL; + attrs.sym.visibility = CFREE_CG_VIS_DEFAULT; + + /* Register function for recursion and later calls. */ if (p->nfns >= TOY_MAX_FNS) { toy_error(p, p->cur.loc, "too many functions"); return -1; } fn_entry = &p->fns[p->nfns]; fn_entry->name = name; + fn_entry->sym = cfree_cg_decl(p->cg, name, fn_ty, attrs); + if (fn_entry->sym == CFREE_CG_SYM_NONE) { + toy_error(p, p->cur.loc, "failed to declare function"); + return -1; + } fn_entry->type = fn_ty; fn_entry->ret = ret_type; fn_entry->nparams = nparams; @@ -2056,14 +2071,7 @@ static int toy_parse_fn(ToyParser* p) { for (i = 0; i < nparams; i++) fn_entry->params[i] = param_types[i]; p->nfns++; - /* Emit function */ - memset(&attrs, 0, sizeof(attrs)); - attrs.bind = CFREE_SB_GLOBAL; - attrs.visibility = CFREE_CG_VIS_DEFAULT; - attrs.tls_model = CFREE_CG_TLS_DEFAULT; - attrs.flags = CFREE_CG_DECL_DEFINED; - cfree_cg_func_decl(p->cg, name, fn_ty, attrs); - cfree_cg_func_begin(p->cg, name, fn_ty, attrs); + cfree_cg_func_begin(p->cg, fn_entry->sym); /* Setup parameter slots */ p->nvars = 0; @@ -2085,13 +2093,13 @@ static int toy_parse_fn(ToyParser* p) { if (!toy_parse_block(p)) return -1; /* Implicit return for void functions */ - if (ret_type == p->types.void_) { + if (ret_type == toy_builtin_type(p, CFREE_CG_BUILTIN_VOID)) { cfree_cg_ret_void(p->cg); } cfree_cg_func_end(p->cg); p->nvars = 0; - p->cur_fn_ret = p->types.void_; + p->cur_fn_ret = toy_builtin_type(p, CFREE_CG_BUILTIN_VOID); return 1; } @@ -2103,6 +2111,8 @@ static int toy_parse_global_var(ToyParser* p) { CfreeSym name; CfreeCgTypeId ty; CfreeCgDeclAttrs attrs; + CfreeCgDataDefAttrs data_attrs; + CfreeCgSym sym; int mutable; if (p->cur.kind == TOK_VAR) { @@ -2126,21 +2136,30 @@ static int toy_parse_global_var(ToyParser* p) { ty = toy_parse_type(p); if (ty == CFREE_CG_TYPE_NONE) return 0; + memset(&attrs, 0, sizeof(attrs)); + attrs.kind = CFREE_CG_DECL_OBJECT; + attrs.sym.bind = CFREE_SB_GLOBAL; + attrs.sym.visibility = CFREE_CG_VIS_DEFAULT; + attrs.as.object.tls_model = CFREE_CG_TLS_AUTO; + if (!mutable) attrs.as.object.flags |= CFREE_CG_OBJ_READONLY; + + sym = cfree_cg_decl(p->cg, name, ty, attrs); + if (sym == CFREE_CG_SYM_NONE) { + toy_error(p, p->cur.loc, "failed to declare global"); + return 0; + } + if (p->nglobals >= TOY_MAX_GLOBALS) { toy_error(p, p->cur.loc, "too many globals"); return 0; } p->globals[p->nglobals].name = name; + p->globals[p->nglobals].sym = sym; p->globals[p->nglobals].type = ty; p->globals[p->nglobals].mutable = mutable; p->nglobals++; - memset(&attrs, 0, sizeof(attrs)); - attrs.bind = CFREE_SB_GLOBAL; - attrs.visibility = CFREE_CG_VIS_DEFAULT; - attrs.tls_model = CFREE_CG_TLS_DEFAULT; - attrs.flags = CFREE_CG_DECL_DEFINED; - if (!mutable) attrs.flags |= CFREE_CG_DECL_READONLY; + memset(&data_attrs, 0, sizeof(data_attrs)); if (toy_parser_match(p, TOK_EQ)) { if (p->cur.kind == TOK_NUMBER) { @@ -2152,11 +2171,12 @@ static int toy_parse_global_var(ToyParser* p) { } toy_emit_int_bytes(p, (uint64_t)p->cur.int_value, buf, n); toy_parser_advance(p); - cfree_cg_data_begin(p->cg, name, ty, attrs); + cfree_cg_data_begin(p->cg, sym, data_attrs); cfree_cg_data_bytes(p->cg, buf, n); cfree_cg_data_end(p->cg); } else if (p->cur.kind == TOK_AMPERSAND) { CfreeSym target; + CfreeCgSym target_sym; uint32_t nbytes = (uint32_t)cfree_cg_type_size(p->c, ty); toy_parser_advance(p); if (p->cur.kind != TOK_IDENT) { @@ -2165,8 +2185,13 @@ static int toy_parse_global_var(ToyParser* p) { } target = toy_tok_sym(p, p->cur); toy_parser_advance(p); - cfree_cg_data_begin(p->cg, name, ty, attrs); - cfree_cg_data_symbol(p->cg, CFREE_CG_SYMREF_ADDR, target, 0, nbytes); + target_sym = toy_find_decl_sym(p, target); + if (target_sym == CFREE_CG_SYM_NONE) { + toy_error(p, p->cur.loc, "undefined symbol in initializer"); + return 0; + } + cfree_cg_data_begin(p->cg, sym, data_attrs); + cfree_cg_data_addr(p->cg, target_sym, 0, nbytes); cfree_cg_data_end(p->cg); } else { toy_error(p, p->cur.loc, "expected constant global initializer"); @@ -2174,7 +2199,7 @@ static int toy_parse_global_var(ToyParser* p) { } } else { /* Zero-initialized */ - cfree_cg_data_begin(p->cg, name, ty, attrs); + cfree_cg_data_begin(p->cg, sym, data_attrs); cfree_cg_data_zero(p->cg, cfree_cg_type_size(p->c, ty)); cfree_cg_data_end(p->cg); } diff --git a/src/api/cg.c b/src/api/cg.c @@ -107,7 +107,7 @@ static const Type* builtin_type(Compiler* c, CfreeCgBuiltinType t) { return type_prim(c->global, TY_FLOAT); case CFREE_CG_BUILTIN_F64: return type_prim(c->global, TY_DOUBLE); - case CFREE_CG_BUILTIN_VA_LIST: + case CFREE_CG_BUILTIN_VARARG_STATE: return abi_va_list_type(c->abi, c->global); case CFREE_CG_BUILTIN_COUNT: return NULL; @@ -270,21 +270,10 @@ static CfreeCgTypeId* copy_type_ids(Compiler* c, const CfreeCgTypeId* src, CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler* c) { CfreeCgBuiltinTypes out; (void)c; - out.void_ = builtin_id(CFREE_CG_BUILTIN_VOID); - out.bool_ = builtin_id(CFREE_CG_BUILTIN_BOOL); - out.i8 = builtin_id(CFREE_CG_BUILTIN_I8); - out.u8 = builtin_id(CFREE_CG_BUILTIN_U8); - out.i16 = builtin_id(CFREE_CG_BUILTIN_I16); - out.u16 = builtin_id(CFREE_CG_BUILTIN_U16); - out.i32 = builtin_id(CFREE_CG_BUILTIN_I32); - out.u32 = builtin_id(CFREE_CG_BUILTIN_U32); - out.i64 = builtin_id(CFREE_CG_BUILTIN_I64); - out.u64 = builtin_id(CFREE_CG_BUILTIN_U64); - out.isize = builtin_id(CFREE_CG_BUILTIN_ISIZE); - out.usize = builtin_id(CFREE_CG_BUILTIN_USIZE); - out.f32 = builtin_id(CFREE_CG_BUILTIN_F32); - out.f64 = builtin_id(CFREE_CG_BUILTIN_F64); - out.va_list = builtin_id(CFREE_CG_BUILTIN_VA_LIST); + memset(&out, 0, sizeof(out)); + for (u32 i = 0; i < CFREE_CG_BUILTIN_COUNT; ++i) { + out.id[i] = builtin_id((CfreeCgBuiltinType)i); + } return out; } @@ -620,6 +609,10 @@ struct CfreeCg { CGFuncDesc fn_desc; CGParamDesc fn_params[64]; + const Type** sym_types; + CfreeCgDeclAttrs* sym_attrs; + u32 sym_cap; + ApiCgScope scopes[API_CG_MAX_SCOPES]; u32 nscopes; u32 scope_generation; @@ -627,6 +620,7 @@ struct CfreeCg { u32 rodata_counter; ObjSecId data_sec; + ObjSymId data_sym; u32 data_base; u64 data_size; }; @@ -1113,11 +1107,87 @@ static SymVis api_map_vis(CfreeCgVisibility v) { return SV_DEFAULT; } -static SymKind api_data_sym_kind(CfreeCgDeclAttrs attrs) { - if (attrs.flags & CFREE_CG_DECL_TLS) return SK_TLS; +static SymKind api_decl_sym_kind(CfreeCgDeclAttrs attrs) { + if (attrs.kind == CFREE_CG_DECL_FUNC) { + if (attrs.as.func.flags & CFREE_CG_FUNC_IFUNC) return SK_IFUNC; + return SK_FUNC; + } + if (attrs.as.object.flags & CFREE_CG_OBJ_TLS) return SK_TLS; return SK_OBJ; } +static void api_remember_sym(CfreeCg* g, ObjSymId sym, const Type* ty, + CfreeCgDeclAttrs attrs) { + Heap* h; + const Type** nts; + CfreeCgDeclAttrs* nas; + u32 cap; + if (!g || sym == OBJ_SYM_NONE) return; + if (sym < g->sym_cap) { + g->sym_types[sym] = ty; + g->sym_attrs[sym] = attrs; + return; + } + h = g->c->env->heap; + cap = g->sym_cap ? g->sym_cap : 16u; + while (cap <= sym) cap *= 2u; + nts = (const Type**)h->alloc(h, sizeof(*nts) * cap, _Alignof(const Type*)); + nas = (CfreeCgDeclAttrs*)h->alloc(h, sizeof(*nas) * cap, + _Alignof(CfreeCgDeclAttrs)); + if (!nts || !nas) { + if (nts) h->free(h, nts, sizeof(*nts) * cap); + if (nas) h->free(h, nas, sizeof(*nas) * cap); + return; + } + memset(nts, 0, sizeof(*nts) * cap); + memset(nas, 0, sizeof(*nas) * cap); + if (g->sym_types) { + memcpy(nts, g->sym_types, sizeof(*nts) * g->sym_cap); + h->free(h, g->sym_types, sizeof(*g->sym_types) * g->sym_cap); + } + if (g->sym_attrs) { + memcpy(nas, g->sym_attrs, sizeof(*nas) * g->sym_cap); + h->free(h, g->sym_attrs, sizeof(*g->sym_attrs) * g->sym_cap); + } + g->sym_types = nts; + g->sym_attrs = nas; + g->sym_cap = cap; + g->sym_types[sym] = ty; + g->sym_attrs[sym] = attrs; +} + +static const Type* api_sym_type(CfreeCg* g, CfreeCgSym sym) { + if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) return NULL; + return g->sym_types[sym]; +} + +static CfreeCgDeclAttrs api_sym_attrs(CfreeCg* g, CfreeCgSym sym) { + CfreeCgDeclAttrs attrs; + memset(&attrs, 0, sizeof(attrs)); + attrs.kind = CFREE_CG_DECL_OBJECT; + attrs.sym.bind = CFREE_SB_GLOBAL; + attrs.sym.visibility = CFREE_CG_VIS_DEFAULT; + if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) return attrs; + return g->sym_attrs[sym]; +} + +static int api_sym_is_tls(CfreeCg* g, CfreeCgSym sym) { + CfreeCgDeclAttrs attrs = api_sym_attrs(g, sym); + return attrs.kind == CFREE_CG_DECL_OBJECT && + (attrs.as.object.flags & CFREE_CG_OBJ_TLS); +} + +static RelocKind api_data_reloc_kind(int pcrel, uint32_t width) { + if (pcrel) { + if (width == 4) return R_PC32; + if (width == 8) return R_PC64; + } else { + if (width == 4) return R_ABS32; + if (width == 8) return R_ABS64; + } + return R_NONE; +} + /* ============================================================ * Public API: CfreeCg lifecycle * ============================================================ */ @@ -1161,6 +1231,12 @@ void cfree_cg_free(CfreeCg* g) { if (g->slot_types) { h->free(h, g->slot_types, sizeof(*g->slot_types) * g->slot_types_cap); } + if (g->sym_types) { + h->free(h, g->sym_types, sizeof(*g->sym_types) * g->sym_cap); + } + if (g->sym_attrs) { + h->free(h, g->sym_attrs, sizeof(*g->sym_attrs) * g->sym_cap); + } for (u32 c = 0; c < 3; ++c) { if (g->slot_pools[c].free) { h->free(h, g->slot_pools[c].free, sizeof(FrameSlot) * g->slot_pools[c].cap); @@ -1183,59 +1259,85 @@ void cfree_cg_set_loc(CfreeCg* g, CfreeSrcLoc loc) { * Function lifecycle * ============================================================ */ -void cfree_cg_func_decl(CfreeCg* g, CfreeSym name, CfreeCgTypeId fn_type, - CfreeCgDeclAttrs attrs) { +CfreeCgSym cfree_cg_decl(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, + CfreeCgDeclAttrs attrs) { Compiler* c; ObjBuilder* ob; Sym mangled; ObjSymId sym; - const Type* fty; - if (!g) return; + const Type* ty; + if (!g || !name) return CFREE_CG_SYM_NONE; c = g->c; ob = g->obj; - fty = resolve_type(c, fn_type); - if (!fty) return; + ty = resolve_type(c, type); + if (!ty) return CFREE_CG_SYM_NONE; mangled = api_c_mangle(c, name); sym = obj_symbol_find(ob, mangled); if (sym == OBJ_SYM_NONE) { - sym = obj_symbol(ob, mangled, api_map_bind(attrs.bind), SK_FUNC, - OBJ_SEC_NONE, 0, 0); + sym = obj_symbol_ex(ob, mangled, api_map_bind(attrs.sym.bind), + api_map_vis(attrs.sym.visibility), + api_decl_sym_kind(attrs), OBJ_SEC_NONE, 0, 0, 0); } - if (attrs.flags & CFREE_CG_DECL_DEFINED) { - ObjSecId text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), - SEC_TEXT, SF_EXEC | SF_ALLOC, 4); - obj_symbol_define(ob, sym, text_sec, 0, 0); + if (attrs.sym.flags) { + obj_symbol_set_flags(ob, sym, (u16)attrs.sym.flags); } - (void)fn_type; + api_remember_sym(g, sym, ty, attrs); + return (CfreeCgSym)sym; } -void cfree_cg_func_begin(CfreeCg* g, CfreeSym name, CfreeCgTypeId fn_type, - CfreeCgDeclAttrs attrs) { +CfreeCgSym cfree_cg_alias(CfreeCg* g, CfreeSym alias_name, CfreeCgSym target, + CfreeCgSymbolAttrs attrs) { + ObjBuilder* ob; + Sym mangled; + ObjSymId sym; + const ObjSym* ts; + CfreeCgDeclAttrs decl_attrs; + if (!g || !alias_name || target == CFREE_CG_SYM_NONE) { + return CFREE_CG_SYM_NONE; + } + ob = g->obj; + mangled = api_c_mangle(g->c, alias_name); + sym = obj_symbol_find(ob, mangled); + ts = obj_symbol_get(ob, (ObjSymId)target); + if (!ts) return CFREE_CG_SYM_NONE; + if (sym == OBJ_SYM_NONE) { + sym = obj_symbol_ex(ob, mangled, api_map_bind(attrs.bind), + api_map_vis(attrs.visibility), (SymKind)ts->kind, + ts->section_id, ts->value, ts->size, + ts->common_align); + } else if (ts->section_id != OBJ_SEC_NONE) { + obj_symbol_define(ob, sym, ts->section_id, ts->value, ts->size); + } + if (attrs.flags) obj_symbol_set_flags(ob, sym, (u16)attrs.flags); + decl_attrs = api_sym_attrs(g, target); + decl_attrs.sym = attrs; + api_remember_sym(g, sym, api_sym_type(g, target), decl_attrs); + return (CfreeCgSym)sym; +} + +void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { Compiler* c; ObjBuilder* ob; CGTarget* T; - Sym mangled; ObjSymId sym; ObjSecId text_sec; const Type* fty; const ABIFuncInfo* abi; + CfreeCgDeclAttrs attrs; if (!g) return; c = g->c; ob = g->obj; T = g->target; - fty = resolve_type(c, fn_type); + sym = (ObjSymId)cg_sym; + fty = api_sym_type(g, cg_sym); if (!fty) return; abi = abi_func_info(c->abi, fty); + attrs = api_sym_attrs(g, cg_sym); - mangled = api_c_mangle(c, name); - sym = obj_symbol_find(ob, mangled); text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), SEC_TEXT, SF_EXEC | SF_ALLOC, 4); - if (sym == OBJ_SYM_NONE) { - sym = obj_symbol(ob, mangled, api_map_bind(attrs.bind), SK_FUNC, - text_sec, 0, 0); - } else { + if (sym != OBJ_SYM_NONE) { obj_symbol_define(ob, sym, text_sec, 0, 0); } @@ -1246,7 +1348,9 @@ void cfree_cg_func_begin(CfreeCg* g, CfreeSym name, CfreeCgTypeId fn_type, g->fn_desc.fn_type = fty; g->fn_desc.abi = abi; g->fn_desc.loc = g->cur_loc; - if (attrs.flags & CFREE_CG_DECL_NORETURN) g->fn_desc.flags |= CGFD_NORETURN; + if (attrs.as.func.flags & CFREE_CG_FUNC_NORETURN) { + g->fn_desc.flags |= CGFD_NORETURN; + } g->fn_ret_type = fty->fn.ret; g->fn_abi = abi; @@ -1359,32 +1463,38 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { api_push(g, api_make_sv(dst, ty)); } -void cfree_cg_push_bytes(CfreeCg* g, const uint8_t* str, size_t len, - CfreeCgTypeId pointee_type) { +CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, + uint32_t align, CfreeCgTypeId pointee_type) { Compiler* c; ObjBuilder* ob; const Type* pty; - const Type* ptr_ty; Sym sec_name; ObjSecId sec; u32 base; char name_buf[32]; Sym anon_name; ObjSymId sym; - if (!g) return; + CfreeCgDeclAttrs attrs; + if (!g) return CFREE_CG_SYM_NONE; c = g->c; ob = g->obj; pty = resolve_type(c, pointee_type); - if (!pty) return; - ptr_ty = type_ptr(c->global, pty); + if (!pty) return CFREE_CG_SYM_NONE; sec_name = pool_intern_cstr(c->global, ".rodata"); - sec = obj_section(ob, sec_name, SEC_RODATA, SF_ALLOC, 1); - base = obj_align_to(ob, sec, (u32)abi_alignof(c->abi, pty)); - obj_write(ob, sec, str, len); + sec = obj_section(ob, sec_name, SEC_RODATA, SF_ALLOC, + align ? align : (u32)abi_alignof(c->abi, pty)); + base = obj_align_to(ob, sec, align ? align : (u32)abi_alignof(c->abi, pty)); + obj_write(ob, sec, data, len); snprintf(name_buf, sizeof(name_buf), ".Lcfree_ro.%u", g->rodata_counter++); anon_name = pool_intern_cstr(c->global, name_buf); sym = obj_symbol(ob, anon_name, SB_LOCAL, SK_OBJ, sec, base, (u64)len); - api_push(g, api_make_sv(api_op_global(sym, 0, ptr_ty), ptr_ty)); + memset(&attrs, 0, sizeof(attrs)); + attrs.kind = CFREE_CG_DECL_OBJECT; + attrs.sym.bind = CFREE_SB_LOCAL; + attrs.sym.visibility = CFREE_CG_VIS_DEFAULT; + attrs.as.object.flags = CFREE_CG_OBJ_READONLY; + api_remember_sym(g, sym, pty, attrs); + return (CfreeCgSym)sym; } void cfree_cg_push_local(CfreeCg* g, CfreeCgSlot slot) { @@ -1394,24 +1504,38 @@ void cfree_cg_push_local(CfreeCg* g, CfreeCgSlot slot) { api_push(g, api_make_lv(api_op_local((FrameSlot)slot, ty), ty)); } -void cfree_cg_push_symbol(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, - CfreeCgSymbolRefKind kind, int64_t addend) { - Sym mangled; - ObjSymId sym; +void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend) { const Type* ty; const Type* ptr_ty; if (!g) return; - ty = resolve_type(g->c, type); - if (!ty) return; + ty = api_sym_type(g, sym); + if (!ty) ty = type_void(g->c->global); ptr_ty = type_ptr(g->c->global, ty); - mangled = api_c_mangle(g->c, name); - sym = obj_symbol_find(g->obj, mangled); - if (sym == OBJ_SYM_NONE) { - sym = obj_symbol(g->obj, mangled, SB_GLOBAL, SK_FUNC, - OBJ_SEC_NONE, 0, 0); + if (api_sym_is_tls(g, sym)) { + Reg r = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); + Operand dst = api_op_reg(r, ptr_ty); + g->target->tls_addr_of(g->target, dst, (ObjSymId)sym, addend); + api_push(g, api_make_sv(dst, ptr_ty)); + } else { + api_push(g, api_make_sv(api_op_global((ObjSymId)sym, addend, ptr_ty), + ptr_ty)); + } +} + +void cfree_cg_push_symbol_lvalue(CfreeCg* g, CfreeCgSym sym, int64_t addend) { + const Type* ty; + if (!g) return; + ty = api_sym_type(g, sym); + if (!ty) return; + if (api_sym_is_tls(g, sym)) { + const Type* ptr_ty = type_ptr(g->c->global, ty); + Reg r = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); + Operand dst = api_op_reg(r, ptr_ty); + g->target->tls_addr_of(g->target, dst, (ObjSymId)sym, addend); + api_push(g, api_make_lv(api_op_indirect(r, 0, ty), ty)); + } else { + api_push(g, api_make_lv(api_op_global((ObjSymId)sym, addend, ty), ty)); } - (void)kind; - api_push(g, api_make_sv(api_op_global(sym, addend, ptr_ty), ptr_ty)); } /* ============================================================ @@ -1731,6 +1855,10 @@ static IntrinKind api_map_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, case CFREE_CG_INTRIN_PREFETCH: return INTRIN_PREFETCH; case CFREE_CG_INTRIN_EXPECT: return INTRIN_EXPECT; case CFREE_CG_INTRIN_ASSUME_ALIGNED: return INTRIN_ASSUME_ALIGNED; + case CFREE_CG_INTRIN_MEMCPY: return INTRIN_MEMCPY; + case CFREE_CG_INTRIN_MEMMOVE: return INTRIN_MEMMOVE; + case CFREE_CG_INTRIN_MEMSET: return INTRIN_MEMSET; + case CFREE_CG_INTRIN_MEMCMP: return INTRIN_NONE; } return INTRIN_NONE; } @@ -2613,7 +2741,7 @@ void cfree_cg_alloca(CfreeCg* g, CfreeCgTypeId result_ptr_type, uint32_t align) api_push(g, api_make_sv(dst, pty)); } -void cfree_cg_va_start(CfreeCg* g) { +void cfree_cg_vararg_start(CfreeCg* g) { ApiSValue ap; CGTarget* T; Operand ap_op; @@ -2625,7 +2753,7 @@ void cfree_cg_va_start(CfreeCg* g) { api_release(g, &ap); } -void cfree_cg_va_arg(CfreeCg* g, CfreeCgTypeId type) { +void cfree_cg_vararg_next(CfreeCg* g, CfreeCgTypeId type) { ApiSValue ap; CGTarget* T; const Type* ty; @@ -2645,7 +2773,7 @@ void cfree_cg_va_arg(CfreeCg* g, CfreeCgTypeId type) { api_push(g, api_make_sv(dst, ty)); } -void cfree_cg_va_end(CfreeCg* g) { +void cfree_cg_vararg_end(CfreeCg* g) { ApiSValue ap; CGTarget* T; Operand ap_op; @@ -2657,7 +2785,7 @@ void cfree_cg_va_end(CfreeCg* g) { api_release(g, &ap); } -void cfree_cg_va_copy(CfreeCg* g) { +void cfree_cg_vararg_copy(CfreeCg* g) { ApiSValue src, dst; CGTarget* T; Operand src_op, dst_op; @@ -2695,6 +2823,21 @@ void cfree_cg_memcpy(CfreeCg* g, uint32_t size, uint32_t align) { api_release(g, &src); } +void cfree_cg_memmove(CfreeCg* g, uint32_t size, uint32_t align) { + ApiSValue src, dst; + Operand args[3]; + if (!g) return; + (void)align; + src = api_pop(g); + dst = api_pop(g); + args[0] = api_force_reg(g, &dst, api_sv_type(&dst)); + args[1] = api_force_reg(g, &src, api_sv_type(&src)); + args[2] = api_op_imm((i64)size, type_prim(g->c->global, TY_ULLONG)); + g->target->intrinsic(g->target, INTRIN_MEMMOVE, NULL, 0, args, 3); + api_release(g, &dst); + api_release(g, &src); +} + void cfree_cg_memset(CfreeCg* g, uint8_t val, uint32_t size, uint32_t align) { ApiSValue dst; CGTarget* T; @@ -3009,6 +3152,108 @@ void cfree_cg_tail_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { } } +static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, + int tail) { + CGTarget* T; + const Type* fty; + const ABIFuncInfo* abi; + const Type* ret_ty; + int has_result; + CGABIValue* avs; + CGCallDesc desc; + Operand callee_op; + if (!g) return; + T = g->target; + fty = api_sym_type(g, sym); + if (!fty) return; + abi = abi_func_info(g->c->abi, fty); + ret_ty = fty->fn.ret; + has_result = !tail && ret_ty && ret_ty->kind != TY_VOID; + if (g->sp < nargs) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: call stack underflow"); + return; + } + avs = NULL; + if (nargs) { + avs = arena_array(g->c->tu, CGABIValue, nargs); + memset(avs, 0, sizeof(CGABIValue) * nargs); + } + g->avs_in_flight = avs; + g->avs_in_flight_n = nargs; + for (u32 i = 0; i < nargs; ++i) { + u32 idx = nargs - 1u - i; + ApiSValue arg = api_pop(g); + int is_vararg = (idx >= abi->nparams); + const Type* aty; + api_ensure_reg(g, &arg); + aty = is_vararg ? (arg.type ? arg.type : api_sv_type(&arg)) + : (fty->fn.params ? fty->fn.params[idx] : arg.type); + avs[idx].type = aty; + avs[idx].abi = is_vararg ? NULL : &abi->params[idx]; + if (aty && (aty->kind == TY_STRUCT || aty->kind == TY_UNION)) { + Operand st = arg.op; + st.type = aty; + avs[idx].storage = st; + avs[idx].size = abi_sizeof(g->c->abi, aty); + } else { + avs[idx].storage = + api_is_lvalue_sv(&arg) ? api_force_reg(g, &arg, aty) : arg.op; + } + } + callee_op = api_op_global((ObjSymId)sym, 0, type_ptr(g->c->global, fty)); + memset(&desc, 0, sizeof desc); + desc.fn_type = fty; + desc.abi = abi; + desc.callee = callee_op; + desc.args = avs; + desc.nargs = nargs; + desc.flags = tail ? CG_CALL_TAIL : CG_CALL_NONE; + desc.ret.type = ret_ty; + desc.ret.abi = &abi->ret; + if (has_result) { + if (ret_ty->kind == TY_STRUCT || ret_ty->kind == TY_UNION) { + FrameSlotDesc fsd; + FrameSlot ret_slot; + memset(&fsd, 0, sizeof fsd); + fsd.type = ret_ty; + fsd.size = abi_sizeof(g->c->abi, ret_ty); + fsd.align = abi_alignof(g->c->abi, ret_ty); + fsd.kind = FS_LOCAL; + fsd.flags = FSF_ADDR_TAKEN; + ret_slot = T->frame_slot(T, &fsd); + desc.ret.storage = api_op_local(ret_slot, ret_ty); + } else { + Reg r = api_alloc_reg_or_spill(g, api_type_class(ret_ty), ret_ty); + desc.ret.storage = api_op_reg(r, ret_ty); + } + } else { + desc.ret.storage = api_op_imm(0, type_void(g->c->global)); + } + T->call(T, &desc); + for (u32 i = 0; i < nargs; ++i) { + api_release_arg_storage(g, &avs[i].storage); + } + g->avs_in_flight = NULL; + g->avs_in_flight_n = 0; + if (has_result) { + if (desc.ret.storage.kind == OPK_LOCAL || + desc.ret.storage.kind == OPK_GLOBAL || + desc.ret.storage.kind == OPK_INDIRECT) { + api_push(g, api_make_lv(desc.ret.storage, ret_ty)); + } else { + api_push(g, api_make_sv(desc.ret.storage, ret_ty)); + } + } +} + +void cfree_cg_call_symbol(CfreeCg* g, CfreeCgSym sym, uint32_t nargs) { + api_call_symbol_common(g, sym, nargs, 0); +} + +void cfree_cg_tail_call_symbol(CfreeCg* g, CfreeCgSym sym, uint32_t nargs) { + api_call_symbol_common(g, sym, nargs, 1); +} + void cfree_cg_ret(CfreeCg* g) { ApiSValue v; CGTarget* T; @@ -3049,30 +3294,10 @@ void cfree_cg_ret_void(CfreeCg* g) { * Data definitions (stubs) * ============================================================ */ -void cfree_cg_data_decl(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, - CfreeCgDeclAttrs attrs) { - Compiler* c; - ObjBuilder* ob; - Sym mangled; - ObjSymId sym; - if (!g) return; - c = g->c; - ob = g->obj; - mangled = api_c_mangle(c, name); - sym = obj_symbol_find(ob, mangled); - if (sym == OBJ_SYM_NONE) { - sym = obj_symbol_ex(ob, mangled, api_map_bind(attrs.bind), - api_map_vis(attrs.visibility), - api_data_sym_kind(attrs), OBJ_SEC_NONE, 0, 0, 0); - } - (void)type; -} - -void cfree_cg_data_begin(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, - CfreeCgDeclAttrs attrs) { +void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, + CfreeCgDataDefAttrs attrs) { Compiler* c; ObjBuilder* ob; - Sym mangled; ObjSymId sym; const Type* ty; u32 align; @@ -3080,50 +3305,135 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, u16 sec_flags; Sym sec_name_sym; ObjSecId sec; + CfreeCgDeclAttrs decl_attrs; if (!g) return; c = g->c; ob = g->obj; - ty = resolve_type(c, type); + sym = (ObjSymId)cg_sym; + ty = api_sym_type(g, cg_sym); if (!ty) return; - mangled = api_c_mangle(c, name); - sym = obj_symbol_find(ob, mangled); + decl_attrs = api_sym_attrs(g, cg_sym); align = attrs.align ? attrs.align : (u32)abi_alignof(c->abi, ty); if (attrs.section) { sec_name_sym = (Sym)attrs.section; sec_kind = SEC_OTHER; sec_flags = SF_ALLOC | SF_WRITE; - } else if (attrs.flags & CFREE_CG_DECL_READONLY) { + } else if (decl_attrs.as.object.flags & CFREE_CG_OBJ_READONLY) { sec_kind = SEC_RODATA; sec_flags = SF_ALLOC; sec_name_sym = pool_intern_cstr(c->global, ".rodata"); - } else if (attrs.flags & CFREE_CG_DECL_TLS) { + } else if (decl_attrs.as.object.flags & CFREE_CG_OBJ_TLS) { sec_kind = SEC_DATA; sec_flags = SF_ALLOC | SF_WRITE | SF_TLS; sec_name_sym = pool_intern_cstr(c->global, ".tdata"); - } else if (attrs.flags & CFREE_CG_DECL_COMMON) { - sec_kind = SEC_BSS; - sec_flags = SF_ALLOC | SF_WRITE; - sec_name_sym = pool_intern_cstr(c->global, ".bss"); } else { sec_kind = SEC_DATA; sec_flags = SF_ALLOC | SF_WRITE; sec_name_sym = pool_intern_cstr(c->global, ".data"); } + if (attrs.flags & CFREE_CG_DATADEF_RETAIN) sec_flags |= SF_RETAIN; + if (attrs.flags & CFREE_CG_DATADEF_MERGE) sec_flags |= SF_MERGE; + if (attrs.flags & CFREE_CG_DATADEF_STRINGS) sec_flags |= SF_STRINGS; sec = obj_section(ob, sec_name_sym, sec_kind, sec_flags, align); g->data_sec = sec; + g->data_sym = sym; g->data_base = obj_align_to(ob, sec, align); g->data_size = 0; - if (sym == OBJ_SYM_NONE) { - sym = obj_symbol_ex(ob, mangled, api_map_bind(attrs.bind), - api_map_vis(attrs.visibility), - api_data_sym_kind(attrs), sec, - (u64)g->data_base, (u64)abi_sizeof(c->abi, ty), 0); - } else { + if (sym != OBJ_SYM_NONE) { obj_symbol_define(ob, sym, sec, (u64)g->data_base, (u64)abi_sizeof(c->abi, ty)); } } +void cfree_cg_data_common(CfreeCg* g, CfreeCgSym cg_sym, uint64_t size, + uint32_t align) { + ObjSym* osym; + ObjSymId sym; + CfreeCgDeclAttrs decl_attrs; + if (!g || cg_sym == CFREE_CG_SYM_NONE) return; + sym = (ObjSymId)cg_sym; + osym = (ObjSym*)obj_symbol_get(g->obj, sym); + if (!osym) return; + decl_attrs = api_sym_attrs(g, cg_sym); + osym->bind = api_map_bind(decl_attrs.sym.bind); + osym->vis = api_map_vis(decl_attrs.sym.visibility); + osym->kind = SK_COMMON; + osym->section_id = OBJ_SEC_NONE; + osym->value = 0; + osym->size = size; + osym->common_align = align; +} + +void cfree_cg_data_align(CfreeCg* g, uint32_t align) { + if (!g || g->data_sec == OBJ_SEC_NONE || !align) return; + g->data_size = obj_align_to(g->obj, g->data_sec, align) - g->data_base; +} + +void cfree_cg_data_pad(CfreeCg* g, uint64_t size, uint8_t value) { + u8 pad[64]; + if (!g || !size) return; + memset(pad, value, sizeof(pad)); + while (size >= sizeof(pad)) { + obj_write(g->obj, g->data_sec, pad, sizeof(pad)); + size -= sizeof(pad); + g->data_size += sizeof(pad); + } + if (size) { + obj_write(g->obj, g->data_sec, pad, (size_t)size); + g->data_size += size; + } +} + +void cfree_cg_data_int(CfreeCg* g, uint64_t value, CfreeCgTypeId type) { + const Type* ty; + u32 size; + u8 bytes[8]; + if (!g) return; + ty = resolve_type(g->c, type); + if (!ty) return; + size = (u32)abi_sizeof(g->c->abi, ty); + if (size > sizeof(bytes)) return; + for (u32 i = 0; i < size; ++i) { + u32 shift = g->c->target.big_endian ? (size - 1u - i) * 8u : i * 8u; + bytes[i] = (u8)(value >> shift); + } + cfree_cg_data_bytes(g, bytes, size); +} + +void cfree_cg_data_float(CfreeCg* g, double value, CfreeCgTypeId type) { + const Type* ty; + union { + float f; + double d; + u8 b[8]; + } u; + if (!g) return; + ty = resolve_type(g->c, type); + if (!ty) return; + if (ty->kind == TY_FLOAT) { + u.f = (float)value; + if (g->c->target.big_endian) { + u8 t = u.b[0]; + u.b[0] = u.b[3]; + u.b[3] = t; + t = u.b[1]; + u.b[1] = u.b[2]; + u.b[2] = t; + } + cfree_cg_data_bytes(g, u.b, 4); + } else if (ty->kind == TY_DOUBLE) { + u.d = value; + if (g->c->target.big_endian) { + for (u32 i = 0; i < 4; ++i) { + u8 t = u.b[i]; + u.b[i] = u.b[7u - i]; + u.b[7u - i] = t; + } + } + cfree_cg_data_bytes(g, u.b, 8); + } +} + void cfree_cg_data_bytes(CfreeCg* g, const uint8_t* data, size_t len) { if (!g || !len) return; obj_write(g->obj, g->data_sec, data, len); @@ -3145,43 +3455,75 @@ void cfree_cg_data_zero(CfreeCg* g, uint64_t size) { g->data_size += size; } -void cfree_cg_data_symbol(CfreeCg* g, CfreeCgSymbolRefKind kind, - CfreeSym target, int64_t addend, uint32_t nbytes) { - Compiler* c; +static void api_cg_data_reloc(CfreeCg* g, CfreeCgSym target, int64_t addend, + uint32_t width, int pcrel) { ObjBuilder* ob; - Sym mangled; - ObjSymId sym; RelocKind rk; u8 pad[8]; - if (!g) return; - c = g->c; + if (!g || !width || width > sizeof(pad)) return; ob = g->obj; - mangled = api_c_mangle(c, target); - sym = obj_symbol_find(ob, mangled); - if (sym == OBJ_SYM_NONE) { - sym = obj_symbol(ob, mangled, SB_GLOBAL, SK_OBJ, OBJ_SEC_NONE, 0, 0); - } - switch (nbytes) { + rk = api_data_reloc_kind(pcrel, width); + if (rk == R_NONE) return; + memset(pad, 0, sizeof pad); + obj_write(ob, g->data_sec, pad, width); + obj_reloc(ob, g->data_sec, g->data_base + (u32)g->data_size, rk, + (ObjSymId)target, addend); + g->data_size += width; +} + +void cfree_cg_data_addr(CfreeCg* g, CfreeCgSym target, int64_t addend, + uint32_t width) { + api_cg_data_reloc(g, target, addend, width, 0); +} + +void cfree_cg_data_pcrel(CfreeCg* g, CfreeCgSym target, int64_t addend, + uint32_t width) { + api_cg_data_reloc(g, target, addend, width, 1); +} + +void cfree_cg_data_symdiff(CfreeCg* g, CfreeCgSym lhs, CfreeCgSym rhs, + int64_t addend, uint32_t width) { + u8 pad[8]; + RelocKind add_kind; + RelocKind sub_kind; + if (!g || width > sizeof(pad)) return; + switch (width) { + case 1: + add_kind = R_RV_ADD8; + sub_kind = R_RV_SUB8; + break; + case 2: + add_kind = R_RV_ADD16; + sub_kind = R_RV_SUB16; + break; case 4: - rk = (kind == CFREE_CG_SYMREF_PCREL) ? R_PC32 : R_ABS32; + add_kind = R_RV_ADD32; + sub_kind = R_RV_SUB32; break; case 8: - rk = (kind == CFREE_CG_SYMREF_PCREL) ? R_PC64 : R_ABS64; + add_kind = R_RV_ADD64; + sub_kind = R_RV_SUB64; break; default: - rk = R_ABS64; - break; + return; } - memset(pad, 0, sizeof pad); - obj_write(ob, g->data_sec, pad, nbytes); - obj_reloc(ob, g->data_sec, g->data_base + (u32)g->data_size, rk, sym, - addend); - g->data_size += nbytes; + memset(pad, 0, sizeof(pad)); + obj_write(g->obj, g->data_sec, pad, width); + obj_reloc(g->obj, g->data_sec, g->data_base + (u32)g->data_size, add_kind, + (ObjSymId)lhs, addend); + obj_reloc(g->obj, g->data_sec, g->data_base + (u32)g->data_size, sub_kind, + (ObjSymId)rhs, 0); + g->data_size += width; } void cfree_cg_data_end(CfreeCg* g) { if (!g) return; + if (g->data_sym != OBJ_SYM_NONE) { + obj_symbol_define(g->obj, g->data_sym, g->data_sec, g->data_base, + g->data_size); + } g->data_sec = OBJ_SEC_NONE; + g->data_sym = OBJ_SYM_NONE; g->data_base = 0; g->data_size = 0; } diff --git a/test/api/cg_type_test.c b/test/api/cg_type_test.c @@ -54,6 +54,11 @@ int main(void) { CfreeEnv env; CfreeCompiler* c; CfreeCgBuiltinTypes bi; + CfreeCgTypeId void_ty; + CfreeCgTypeId i32_ty; + CfreeCgTypeId i64_ty; + CfreeCgTypeId f64_ty; + CfreeCgTypeId va_list_ty; CfreeCgTypeId ptr_i32; CfreeCgTypeId array_i32; CfreeCgTypeId params[2]; @@ -87,26 +92,31 @@ int main(void) { } bi = cfree_cg_builtin_types(c); - EXPECT(bi.void_ != CFREE_CG_TYPE_NONE, "void builtin id is none"); - EXPECT(bi.i32 != CFREE_CG_TYPE_NONE, "i32 builtin id is none"); - EXPECT(bi.f64 != CFREE_CG_TYPE_NONE, "f64 builtin id is none"); - EXPECT(bi.va_list != CFREE_CG_TYPE_NONE, "va_list builtin id is none"); - EXPECT(bi.void_ != bi.i32 && bi.i32 != bi.f64, "builtin ids collide"); - - ptr_i32 = cfree_cg_type_ptr(c, bi.i32); - array_i32 = cfree_cg_type_array(c, bi.i32, 4); + void_ty = bi.id[CFREE_CG_BUILTIN_VOID]; + i32_ty = bi.id[CFREE_CG_BUILTIN_I32]; + i64_ty = bi.id[CFREE_CG_BUILTIN_I64]; + f64_ty = bi.id[CFREE_CG_BUILTIN_F64]; + va_list_ty = bi.id[CFREE_CG_BUILTIN_VARARG_STATE]; + EXPECT(void_ty != CFREE_CG_TYPE_NONE, "void builtin id is none"); + EXPECT(i32_ty != CFREE_CG_TYPE_NONE, "i32 builtin id is none"); + EXPECT(f64_ty != CFREE_CG_TYPE_NONE, "f64 builtin id is none"); + EXPECT(va_list_ty != CFREE_CG_TYPE_NONE, "va_list builtin id is none"); + EXPECT(void_ty != i32_ty && i32_ty != f64_ty, "builtin ids collide"); + + ptr_i32 = cfree_cg_type_ptr(c, i32_ty); + array_i32 = cfree_cg_type_array(c, i32_ty, 4); EXPECT(ptr_i32 != CFREE_CG_TYPE_NONE, "ptr type failed"); EXPECT(array_i32 != CFREE_CG_TYPE_NONE, "array type failed"); - EXPECT(cfree_cg_type_ptr(c, bi.i32) == ptr_i32, + EXPECT(cfree_cg_type_ptr(c, i32_ty) == ptr_i32, "ptr type id should be interned"); - EXPECT(cfree_cg_type_array(c, bi.i32, 4) == array_i32, + EXPECT(cfree_cg_type_array(c, i32_ty, 4) == array_i32, "array type id should be interned"); EXPECT(cfree_cg_type_ptr(c, CFREE_CG_TYPE_NONE) == CFREE_CG_TYPE_NONE, "invalid pointer pointee should fail"); - alias = cfree_cg_type_alias(c, cfree_sym_intern(c, "I"), bi.i32); + alias = cfree_cg_type_alias(c, cfree_sym_intern(c, "I"), i32_ty); qual = cfree_cg_type_qualified(c, alias, CFREE_CG_TQ_CONST); - EXPECT(alias != CFREE_CG_TYPE_NONE && alias != bi.i32, + EXPECT(alias != CFREE_CG_TYPE_NONE && alias != i32_ty, "alias id should be fresh"); EXPECT(qual != CFREE_CG_TYPE_NONE && qual != alias, "qualified type failed"); @@ -118,7 +128,7 @@ int main(void) { "unknown qualifier bit should fail"); fields[0].name = cfree_sym_intern(c, "a"); - fields[0].type = bi.i32; + fields[0].type = i32_ty; fields[0].align_override = 0; fields[1].name = cfree_sym_intern(c, "b"); fields[1].type = ptr_i32; @@ -137,13 +147,13 @@ int main(void) { vals, 2); EXPECT(enm != CFREE_CG_TYPE_NONE, "enum type failed"); - params[0] = bi.i32; + params[0] = i32_ty; params[1] = ptr_i32; - fn = cfree_cg_type_func(c, bi.i64, params, 2, 1); + fn = cfree_cg_type_func(c, i64_ty, params, 2, 1); EXPECT(fn != CFREE_CG_TYPE_NONE, "function type failed"); - EXPECT(cfree_cg_type_func(c, bi.i64, params, 2, 1) == fn, + EXPECT(cfree_cg_type_func(c, i64_ty, params, 2, 1) == fn, "function type id should be interned"); - EXPECT(cfree_cg_type_func(c, bi.i64, params, 70000, 0) == CFREE_CG_TYPE_NONE, + EXPECT(cfree_cg_type_func(c, i64_ty, params, 70000, 0) == CFREE_CG_TYPE_NONE, "oversized function param list should fail"); cfree_compiler_free(c); diff --git a/test/toy/cases/16_cg_api_alloca_memory_index.toy b/test/toy/cases/16_cg_api_alloca_memory_index.toy @@ -1,10 +0,0 @@ -fn main(): int { - let p: *int = alloca(16); - *p = 10; - *index(p, 1) = 32; - - let q: *int = alloca(16); - memset(q, 0, 16); - memcpy(q, p, 16); - return *q + *index(q, 1); -} diff --git a/test/toy/cases/16_cg_api_alloca_memory_index.expected b/test/toy/cases/16_cg_api_memory_index.expected diff --git a/test/toy/cases/16_cg_api_memory_index.toy b/test/toy/cases/16_cg_api_memory_index.toy @@ -0,0 +1,11 @@ +fn main(): int { + let a: int = 0; + let b: int = 0; + let p: *int = &a; + let q: *int = &b; + + *index(p, 0) = 42; + memset(q, 0, 8); + memcpy(q, p, 8); + return *index(q, 0); +} diff --git a/test/toy/demo.toy b/test/toy/demo.toy @@ -34,14 +34,15 @@ fn sum_to(n: int): int { } fn memory_demo(): int { - let p: *int = alloca(16); - *p = 10; - *index(p, 1) = 32; + let a: int = 0; + let b: int = 0; + let p: *int = &a; + let q: *int = &b; - let q: *int = alloca(16); - memset(q, 0, 16); - memcpy(q, p, 16); - return *q + *index(q, 1); + *index(p, 0) = 42; + memset(q, 0, 8); + memcpy(q, p, 8); + return *index(q, 0); } fn atomic_demo(): int {