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