kit

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

commit f12acfbd50f35de7c87bfefce0ca26709fb0b8a2
parent 4ae07c0721915d9b00d24e96bc6469e9eb3a38b3
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed, 13 May 2026 12:15:27 -0700

Update impl + toy to new CG api

Diffstat:
Minclude/cfree/cg.h | 9+++++++++
Mlang/toy/toy.c | 382+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/api/cg.c | 1255++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/api/lifecycle.c | 24++++++++++++++++++++++++
4 files changed, 1096 insertions(+), 574 deletions(-)

diff --git a/include/cfree/cg.h b/include/cfree/cg.h @@ -164,6 +164,7 @@ CfreeCgCallConv cfree_cg_type_func_call_conv(CfreeCompiler*, CfreeCgTypeId); int cfree_cg_type_func_is_variadic(CfreeCompiler*, CfreeCgTypeId); uint32_t cfree_cg_type_record_nfields(CfreeCompiler*, CfreeCgTypeId); +/* Returns 0 on success and fills any non-NULL out parameters. */ int cfree_cg_type_record_field(CfreeCompiler*, CfreeCgTypeId, uint32_t index, CfreeCgField* out, uint64_t* offset_out); @@ -335,6 +336,14 @@ CfreeCgSym cfree_cg_decl(CfreeCg*, CfreeCgDecl decl); /* Defines alias.linkage_name as another symbol for alias.target. */ CfreeCgSym cfree_cg_alias(CfreeCg*, CfreeCgAlias alias); +/* Converts a source-level C ABI symbol spelling to the exact object/linker + * spelling for the selected target. This is object-format decoration only + * (for example Mach-O's leading underscore); language-specific mangling + * remains the frontend's responsibility. Use this when filling + * CfreeCgDecl.linkage_name for symbols that should interoperate with C entry + * names, libc symbols, and linker entry lookup. */ +CfreeSym cfree_cg_c_linkage_name(CfreeCompiler*, CfreeSym source_name); + /* ============================================================ * Lifecycle and Source Locations * ============================================================ */ diff --git a/lang/toy/toy.c b/lang/toy/toy.c @@ -6,60 +6,9 @@ #include <stdint.h> #include <string.h> -/* ============================================================ - * CG API coverage checklist — APIs NOT yet exercised by toy: - * - * Types (query): - * cfree_cg_type_is_ptr / ptr_pointee - * cfree_cg_type_is_func / func_ret / func_nparams / func_param - * cfree_cg_type_is_record / record_nfields / record_field - * cfree_cg_type_size / type_align - * - * Types (constructors): - * cfree_cg_type_array - * cfree_cg_type_qualified - * cfree_cg_type_alias - * cfree_cg_type_record - * cfree_cg_type_enum - * - * Functions & data: - * 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_addr / cfree_cg_push_symbol_lvalue - * - * Stack: - * cfree_cg_swap - * cfree_cg_rot3 - * cfree_cg_addr (only used for &var, not for general lvalues) - * - * Arithmetic: - * cfree_cg_binop (only ADD, SUB, MUL, SDIV, SREM used) - * cfree_cg_unop (NEG, NOT used; BNOT unused) - * cfree_cg_cmp (only EQ, NE, LT_S, GT_S, LE_S, GE_S used) - * cfree_cg_convert (only i1→int used) - * - * Scopes & control flow: - * cfree_cg_break_true (only with result_type != NONE) - * cfree_cg_continue_true / continue_false - * cfree_cg_label_new / label_place / jump / branch_true / branch_false - * - * Calls: - * cfree_cg_tail_call - * - * Intrinsics: - * cfree_cg_intrinsic (all) - * - * Atomics: - * cfree_cg_atomic_load / atomic_store / atomic_rmw - * cfree_cg_atomic_cmpxchg / atomic_fence - * - * Memory: - * cfree_cg_memcpy / memset / index / field - * ============================================================ */ +/* Public CG API coverage goals for this frontend are tracked in + * doc/toy-todo.md. Keep this file aligned with include/cfree/cg.h rather than + * private CG implementation details. */ /* ============================================================ * Lexer / token iterator @@ -436,8 +385,8 @@ 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 = toy_builtin_type(p, CFREE_CG_BUILTIN_ISIZE); - p->int_ptr_type = cfree_cg_type_ptr(c, p->int_type); + p->int_type = toy_builtin_type(p, CFREE_CG_BUILTIN_I64); + p->int_ptr_type = cfree_cg_type_ptr(c, p->int_type, 0); p->va_list_type = toy_builtin_type(p, CFREE_CG_BUILTIN_VARARG_STATE); p->target = cfree_compiler_target(c); { @@ -449,7 +398,7 @@ static void toy_parser_init(ToyParser* p, CfreeCompiler* c, CfreeCg* cg, fields[1].type = p->int_type; p->pair_type = cfree_cg_type_record(c, cfree_sym_intern(c, "Pair"), fields, 2); - p->pair_ptr_type = cfree_cg_type_ptr(c, p->pair_type); + p->pair_ptr_type = cfree_cg_type_ptr(c, p->pair_type, 0); } p->nvars = 0; p->nfns = 0; @@ -561,7 +510,7 @@ static CfreeCgTypeId toy_parse_type(ToyParser* p) { toy_error(p, p->cur.loc, "expected type after '*'"); return CFREE_CG_TYPE_NONE; } - return cfree_cg_type_ptr(p->c, pointee); + return cfree_cg_type_ptr(p->c, pointee, 0); } toy_error(p, p->cur.loc, "expected type"); return CFREE_CG_TYPE_NONE; @@ -584,6 +533,59 @@ static void toy_emit_int_bytes(ToyParser* p, uint64_t v, uint8_t* buf, for (i = 0; i < n; ++i) buf[i] = (uint8_t)(v >> (i * 8u)); } +static CfreeCgMemAccess toy_mem_access(ToyParser* p, CfreeCgTypeId type) { + CfreeCgMemAccess access; + (void)p; + memset(&access, 0, sizeof access); + access.type = type; + return access; +} + +static CfreeCgSlotAttrs toy_slot_attrs(CfreeSym name) { + CfreeCgSlotAttrs attrs; + memset(&attrs, 0, sizeof attrs); + attrs.name = name; + return attrs; +} + +static CfreeSym toy_c_linkage_name(ToyParser* p, CfreeSym source_name) { + CfreeSym linkage_name = cfree_cg_c_linkage_name(p->c, source_name); + if (!linkage_name) { + toy_error(p, p->cur.loc, "failed to create linkage name"); + } + return linkage_name; +} + +static void toy_inline_asm(ToyParser* p, CfreeSym tmpl, + const CfreeCgAsmOperand* outputs, + uint32_t noutputs, + const CfreeCgAsmOperand* inputs, uint32_t ninputs, + const CfreeSym* clobbers, uint32_t nclobbers, + uint32_t flags) { + CfreeCgInlineAsm asm_block; + memset(&asm_block, 0, sizeof asm_block); + asm_block.tmpl = tmpl; + asm_block.outputs = outputs; + asm_block.noutputs = noutputs; + asm_block.inputs = inputs; + asm_block.ninputs = ninputs; + asm_block.clobbers = clobbers; + asm_block.nclobbers = nclobbers; + asm_block.flags = flags; + cfree_cg_inline_asm(p->cg, asm_block); +} + +static int toy_emit_truthy(ToyParser* p, CfreeCgTypeId type) { + if (type == toy_builtin_type(p, CFREE_CG_BUILTIN_BOOL)) return 1; + if (type == p->int_type) { + cfree_cg_push_int(p->cg, 0, p->int_type); + cfree_cg_int_cmp(p->cg, CFREE_CG_INT_NE); + return 1; + } + toy_error(p, p->cur.loc, "condition must be int or bool"); + return 0; +} + static int toy_expect_comma(ToyParser* p) { if (!toy_parser_expect(p, TOK_COMMA)) { toy_error(p, p->cur.loc, "expected ','"); @@ -755,7 +757,7 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, toy_emit_int_bytes(p, 42, buf, n); cfree_cg_push_bytes(p->cg, buf, n, p->int_type); cfree_cg_indirect(p->cg); - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); return p->int_type; } @@ -815,7 +817,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, !toy_parse_number_arg(p, &val) || !toy_expect_comma(p) || !toy_parse_number_arg(p, &size)) return CFREE_CG_TYPE_NONE; if (!toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_memset(p->cg, (uint8_t)val, (uint32_t)size, 1); + cfree_cg_memset(p->cg, (uint8_t)val, (uint64_t)size, + toy_mem_access(p, p->int_type)); cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; } @@ -830,7 +833,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (src == CFREE_CG_TYPE_NONE || !toy_expect_comma(p) || !toy_parse_number_arg(p, &size)) return CFREE_CG_TYPE_NONE; if (!toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_memcpy(p->cg, (uint32_t)size, 1); + cfree_cg_memcpy(p->cg, (uint64_t)size, toy_mem_access(p, p->int_type), + toy_mem_access(p, p->int_type)); cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; } @@ -841,7 +845,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, 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_atomic_load(p->cg, CFREE_CG_MO_SEQ_CST); + cfree_cg_atomic_load(p->cg, toy_mem_access(p, p->int_type), + CFREE_CG_MO_SEQ_CST); return p->int_type; } @@ -860,10 +865,12 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, if (val_ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; if (!toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; if (is_store) { - cfree_cg_atomic_store(p->cg, CFREE_CG_MO_SEQ_CST); + cfree_cg_atomic_store(p->cg, toy_mem_access(p, p->int_type), + CFREE_CG_MO_SEQ_CST); cfree_cg_push_int(p->cg, 0, p->int_type); } else { - cfree_cg_atomic_rmw(p->cg, op, CFREE_CG_MO_SEQ_CST); + cfree_cg_atomic_rmw(p->cg, toy_mem_access(p, p->int_type), op, + CFREE_CG_MO_SEQ_CST); } return p->int_type; } @@ -878,7 +885,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, t2 = toy_parse_expr(p); if (t2 == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; if (!toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_atomic_cmpxchg(p->cg, CFREE_CG_MO_SEQ_CST, CFREE_CG_MO_RELAXED); + cfree_cg_atomic_cmpxchg(p->cg, toy_mem_access(p, p->int_type), + CFREE_CG_MO_SEQ_CST, CFREE_CG_MO_RELAXED, 0); cfree_cg_swap(p->cg); cfree_cg_drop(p->cg); return p->int_type; @@ -951,17 +959,17 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, 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); + slot = cfree_cg_local_slot(p->cg, p->pair_type, toy_slot_attrs(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); cfree_cg_push_int(p->cg, 42, p->int_type); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_indirect(p->cg); cfree_cg_field(p->cg, 1); - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); return p->int_type; } @@ -969,8 +977,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, CfreeSym tmpl = cfree_sym_intern(p->c, "nop"); if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; - cfree_cg_inline_asm(p->cg, tmpl, NULL, 0, NULL, 0, NULL, 0, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, NULL, 0, NULL, 0, NULL, 0, + CFREE_CG_ASM_VOLATILE); cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; } @@ -982,8 +990,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, !toy_parse_arch_string(p, &tmpl, &tmpl_len) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; if (tmpl_len) { - cfree_cg_inline_asm(p->cg, tmpl, NULL, 0, NULL, 0, NULL, 0, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, NULL, 0, NULL, 0, NULL, 0, + CFREE_CG_ASM_VOLATILE); } cfree_cg_push_int(p->cg, 0, p->int_type); return p->int_type; @@ -1017,8 +1025,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, inputs[0].type = p->int_type; inputs[0].dir = CFREE_CG_ASM_IN; inputs[1] = inputs[0]; - cfree_cg_inline_asm(p->cg, tmpl, outputs, 1, inputs, 2, NULL, 0, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, outputs, 1, inputs, 2, NULL, 0, + CFREE_CG_ASM_VOLATILE); } else { cfree_cg_drop(p->cg); cfree_cg_drop(p->cg); @@ -1047,8 +1055,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, inputs[0].type = p->int_type; inputs[0].dir = CFREE_CG_ASM_IN; cfree_cg_push_int(p->cg, (uint64_t)imm, p->int_type); - cfree_cg_inline_asm(p->cg, tmpl, outputs, 1, inputs, 1, NULL, 0, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, outputs, 1, inputs, 1, NULL, 0, + CFREE_CG_ASM_VOLATILE); } else { cfree_cg_push_int(p->cg, 0, p->int_type); } @@ -1086,10 +1094,10 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, inputs[0].constraint = cfree_sym_intern(p->c, "m"); inputs[0].type = p->int_type; inputs[0].dir = CFREE_CG_ASM_IN; - cfree_cg_inline_asm(p->cg, tmpl, outputs, 1, inputs, 1, NULL, 0, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, outputs, 1, inputs, 1, NULL, 0, + CFREE_CG_ASM_VOLATILE); } else { - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, var_ty)); } return p->int_type; } @@ -1114,8 +1122,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, outputs[0].constraint = cfree_sym_intern(p->c, "+r"); outputs[0].type = p->int_type; outputs[0].dir = CFREE_CG_ASM_INOUT; - cfree_cg_inline_asm(p->cg, tmpl, outputs, 1, NULL, 0, NULL, 0, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, outputs, 1, NULL, 0, NULL, 0, + CFREE_CG_ASM_VOLATILE); } return p->int_type; } @@ -1148,10 +1156,10 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, inputs[0].type = p->int_type; inputs[0].dir = CFREE_CG_ASM_IN; inputs[1] = inputs[0]; - cfree_cg_inline_asm(p->cg, tmpl, outputs, 1, inputs, 2, NULL, 0, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, outputs, 1, inputs, 2, NULL, 0, + CFREE_CG_ASM_VOLATILE); } else { - cfree_cg_binop(p->cg, CFREE_CG_ADD); + cfree_cg_int_binop(p->cg, CFREE_CG_INT_ADD, 0); } return p->int_type; } @@ -1173,8 +1181,8 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, } if (tmpl_len) { clobber = cfree_sym_intern(p->c, "memory"); - cfree_cg_inline_asm(p->cg, tmpl, NULL, 0, NULL, 0, &clobber, 1, - CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, NULL, 0, NULL, 0, &clobber, 1, + CFREE_CG_ASM_VOLATILE); } return p->int_type; } @@ -1190,39 +1198,53 @@ static CfreeCgTypeId toy_parse_builtin_call(ToyParser* p, CfreeSym name, !toy_parse_arch_string(p, &clobber, &clobber_len) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; if (tmpl_len) { - cfree_cg_inline_asm(p->cg, tmpl, NULL, 0, NULL, 0, - clobber_len ? &clobber : NULL, - clobber_len ? 1u : 0u, CFREE_CG_ASM_VOLATILE); + toy_inline_asm(p, tmpl, NULL, 0, NULL, 0, + clobber_len ? &clobber : NULL, clobber_len ? 1u : 0u, + CFREE_CG_ASM_VOLATILE); } cfree_cg_push_int(p->cg, 11, p->int_type); return p->int_type; } if (toy_sym_is(p, name, "typecheck")) { - CfreeCgTypeId arr, qual, alias, enm, fnty; + CfreeCgTypeId arr, alias, enm, fnty; CfreeCgEnumValue ev; + CfreeCgParam fn_params[1]; + CfreeCgFuncSig sig; + CfreeCgField field; + CfreeCgParam first_param; int ok = 1; if (!toy_parser_expect(p, TOK_LPAREN) || !toy_parser_expect(p, TOK_RPAREN)) return CFREE_CG_TYPE_NONE; arr = cfree_cg_type_array(p->c, p->int_type, 4); - qual = cfree_cg_type_qualified(p->c, p->int_type, CFREE_CG_TQ_CONST); alias = cfree_cg_type_alias(p->c, cfree_sym_intern(p->c, "Word"), p->int_type); ev.name = cfree_sym_intern(p->c, "E"); ev.value = 7; enm = cfree_cg_type_enum(p->c, cfree_sym_intern(p->c, "Enum"), p->int_type, &ev, 1); - fnty = cfree_cg_type_func(p->c, p->int_type, &p->int_type, 1, 0); - ok = ok && arr && qual && alias && enm && fnty; - ok = ok && cfree_cg_type_is_ptr(p->c, p->int_ptr_type); + memset(fn_params, 0, sizeof fn_params); + memset(&sig, 0, sizeof sig); + fn_params[0].type = p->int_type; + sig.ret = p->int_type; + sig.params = fn_params; + sig.nparams = 1; + sig.call_conv = CFREE_CG_CC_TARGET_C; + fnty = cfree_cg_type_func(p->c, sig); + first_param = cfree_cg_type_func_param(p->c, fnty, 0); + ok = ok && arr && alias && enm && fnty; + ok = ok && cfree_cg_type_kind(p->c, p->int_ptr_type) == CFREE_CG_TYPE_PTR; ok = ok && cfree_cg_type_ptr_pointee(p->c, p->int_ptr_type) == p->int_type; - ok = ok && cfree_cg_type_is_record(p->c, p->pair_type); + ok = ok && cfree_cg_type_kind(p->c, p->pair_type) == CFREE_CG_TYPE_RECORD; ok = ok && cfree_cg_type_record_nfields(p->c, p->pair_type) == 2; - ok = ok && cfree_cg_type_is_func(p->c, fnty); + ok = ok && + cfree_cg_type_record_field(p->c, p->pair_type, 1, &field, NULL) == 0; + ok = ok && field.type == p->int_type; + ok = ok && cfree_cg_type_kind(p->c, fnty) == CFREE_CG_TYPE_FUNC; ok = ok && cfree_cg_type_func_ret(p->c, fnty) == p->int_type; ok = ok && cfree_cg_type_func_nparams(p->c, fnty) == 1; - ok = ok && cfree_cg_type_func_param(p->c, fnty, 0) == p->int_type; + ok = ok && first_param.type == p->int_type; ok = ok && cfree_cg_type_size(p->c, arr) >= 4; - ok = ok && cfree_cg_type_align(p->c, qual) >= 1; + ok = ok && cfree_cg_type_align(p->c, p->int_type) >= 1; cfree_cg_push_int(p->cg, ok ? 1 : 0, p->int_type); return p->int_type; } @@ -1296,7 +1318,7 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { } } - cfree_cg_call_symbol(p->cg, fn->sym, (uint32_t)nargs); + cfree_cg_call_symbol_default(p->cg, fn->sym, (uint32_t)nargs); return fn->ret; } @@ -1304,13 +1326,13 @@ static CfreeCgTypeId toy_parse_expr_primary(ToyParser* p) { ToyVar* v = toy_find_var(p, name); if (v) { cfree_cg_push_local(p->cg, v->slot); - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, v->type)); return v->type; } ToyGlobal* g = toy_find_global(p, name); if (g) { cfree_cg_push_symbol_lvalue(p->cg, g->sym, 0); - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, g->type)); return g->type; } toy_error(p, ident_tok.loc, "undefined variable '%s'", @@ -1342,7 +1364,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { toy_error(p, p->cur.loc, "invalid operand for unary '-'"); return CFREE_CG_TYPE_NONE; } - cfree_cg_unop(p->cg, CFREE_CG_NEG); + cfree_cg_int_unop(p->cg, CFREE_CG_INT_NEG, 0); return p->int_type; } @@ -1353,7 +1375,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { toy_error(p, p->cur.loc, "invalid operand for '!'"); return CFREE_CG_TYPE_NONE; } - cfree_cg_unop(p->cg, CFREE_CG_NOT); + cfree_cg_int_unop(p->cg, CFREE_CG_INT_NOT, 0); return p->int_type; } @@ -1364,7 +1386,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { toy_error(p, p->cur.loc, "invalid operand for '~'"); return CFREE_CG_TYPE_NONE; } - cfree_cg_unop(p->cg, CFREE_CG_BNOT); + cfree_cg_int_unop(p->cg, CFREE_CG_INT_BNOT, 0); return p->int_type; } @@ -1379,7 +1401,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { if (v) { cfree_cg_push_local(p->cg, v->slot); cfree_cg_addr(p->cg); - return cfree_cg_type_ptr(p->c, v->type); + return cfree_cg_type_ptr(p->c, v->type, 0); } else { ToyGlobal* g = toy_find_global(p, name); if (!g) { @@ -1387,7 +1409,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { return CFREE_CG_TYPE_NONE; } cfree_cg_push_symbol_addr(p->cg, g->sym, 0); - return cfree_cg_type_ptr(p->c, g->type); + return cfree_cg_type_ptr(p->c, g->type, 0); } } @@ -1399,7 +1421,7 @@ static CfreeCgTypeId toy_parse_expr_unary(ToyParser* p) { return CFREE_CG_TYPE_NONE; } cfree_cg_indirect(p->cg); - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); return p->int_type; } @@ -1412,7 +1434,7 @@ static CfreeCgTypeId toy_parse_expr_mul(ToyParser* p) { while (p->cur.kind == TOK_STAR || p->cur.kind == TOK_SLASH || p->cur.kind == TOK_PERCENT) { ToyTokenKind op = p->cur.kind; - CfreeCgBinOp binop; + CfreeCgIntBinOp binop; toy_parser_advance(p); CfreeCgTypeId ty2 = toy_parse_expr_unary(p); if (ty2 == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; @@ -1422,18 +1444,18 @@ static CfreeCgTypeId toy_parse_expr_mul(ToyParser* p) { } switch (op) { case TOK_STAR: - binop = CFREE_CG_MUL; + binop = CFREE_CG_INT_MUL; break; case TOK_SLASH: - binop = CFREE_CG_SDIV; + binop = CFREE_CG_INT_SDIV; break; case TOK_PERCENT: - binop = CFREE_CG_SREM; + binop = CFREE_CG_INT_SREM; break; default: return CFREE_CG_TYPE_NONE; } - cfree_cg_binop(p->cg, binop); + cfree_cg_int_binop(p->cg, binop, 0); } return ty; } @@ -1443,7 +1465,8 @@ static CfreeCgTypeId toy_parse_expr_add(ToyParser* p) { if (ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; while (p->cur.kind == TOK_PLUS || p->cur.kind == TOK_MINUS) { ToyTokenKind op = p->cur.kind; - CfreeCgBinOp binop = (op == TOK_PLUS) ? CFREE_CG_ADD : CFREE_CG_SUB; + CfreeCgIntBinOp binop = + (op == TOK_PLUS) ? CFREE_CG_INT_ADD : CFREE_CG_INT_SUB; toy_parser_advance(p); CfreeCgTypeId ty2 = toy_parse_expr_mul(p); if (ty2 == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; @@ -1451,7 +1474,7 @@ static CfreeCgTypeId toy_parse_expr_add(ToyParser* p) { toy_error(p, p->cur.loc, "arithmetic operands must be int"); return CFREE_CG_TYPE_NONE; } - cfree_cg_binop(p->cg, binop); + cfree_cg_int_binop(p->cg, binop, 0); } return ty; } @@ -1463,7 +1486,7 @@ static CfreeCgTypeId toy_parse_expr_cmp(ToyParser* p) { p->cur.kind == TOK_LT || p->cur.kind == TOK_GT || p->cur.kind == TOK_LE || p->cur.kind == TOK_GE) { ToyTokenKind op = p->cur.kind; - CfreeCgCmpOp cmp; + CfreeCgIntCmpOp cmp; toy_parser_advance(p); CfreeCgTypeId ty2 = toy_parse_expr_add(p); if (ty2 == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; @@ -1473,28 +1496,28 @@ static CfreeCgTypeId toy_parse_expr_cmp(ToyParser* p) { } switch (op) { case TOK_EQEQ: - cmp = CFREE_CG_EQ; + cmp = CFREE_CG_INT_EQ; break; case TOK_NE: - cmp = CFREE_CG_NE; + cmp = CFREE_CG_INT_NE; break; case TOK_LT: - cmp = CFREE_CG_LT_S; + cmp = CFREE_CG_INT_LT_S; break; case TOK_GT: - cmp = CFREE_CG_GT_S; + cmp = CFREE_CG_INT_GT_S; break; case TOK_LE: - cmp = CFREE_CG_LE_S; + cmp = CFREE_CG_INT_LE_S; break; case TOK_GE: - cmp = CFREE_CG_GE_S; + cmp = CFREE_CG_INT_GE_S; break; default: return CFREE_CG_TYPE_NONE; } - cfree_cg_cmp(p->cg, cmp); - cfree_cg_convert(p->cg, p->int_type); + cfree_cg_int_cmp(p->cg, cmp); + cfree_cg_zext(p->cg, p->int_type); ty = p->int_type; } return ty; @@ -1505,7 +1528,8 @@ static CfreeCgTypeId toy_parse_expr_shift(ToyParser* p) { if (ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; while (p->cur.kind == TOK_SHL || p->cur.kind == TOK_SHR) { ToyTokenKind op = p->cur.kind; - CfreeCgBinOp binop = (op == TOK_SHL) ? CFREE_CG_SHL : CFREE_CG_SHR_S; + CfreeCgIntBinOp binop = + (op == TOK_SHL) ? CFREE_CG_INT_SHL : CFREE_CG_INT_ASHR; toy_parser_advance(p); CfreeCgTypeId ty2 = toy_parse_expr_cmp(p); if (ty2 == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; @@ -1513,7 +1537,7 @@ static CfreeCgTypeId toy_parse_expr_shift(ToyParser* p) { toy_error(p, p->cur.loc, "shift operands must be int"); return CFREE_CG_TYPE_NONE; } - cfree_cg_binop(p->cg, binop); + cfree_cg_int_binop(p->cg, binop, 0); } return ty; } @@ -1529,7 +1553,7 @@ static CfreeCgTypeId toy_parse_expr_band(ToyParser* p) { toy_error(p, p->cur.loc, "bitwise operands must be int"); return CFREE_CG_TYPE_NONE; } - cfree_cg_binop(p->cg, CFREE_CG_AND); + cfree_cg_int_binop(p->cg, CFREE_CG_INT_AND, 0); } return ty; } @@ -1545,7 +1569,7 @@ static CfreeCgTypeId toy_parse_expr_bxor(ToyParser* p) { toy_error(p, p->cur.loc, "bitwise operands must be int"); return CFREE_CG_TYPE_NONE; } - cfree_cg_binop(p->cg, CFREE_CG_XOR); + cfree_cg_int_binop(p->cg, CFREE_CG_INT_XOR, 0); } return ty; } @@ -1561,7 +1585,7 @@ static CfreeCgTypeId toy_parse_expr_bor(ToyParser* p) { toy_error(p, p->cur.loc, "bitwise operands must be int"); return CFREE_CG_TYPE_NONE; } - cfree_cg_binop(p->cg, CFREE_CG_OR); + cfree_cg_int_binop(p->cg, CFREE_CG_INT_OR, 0); } return ty; } @@ -1576,22 +1600,24 @@ static CfreeCgTypeId toy_parse_expr_and(ToyParser* p) { toy_parser_advance(p); false_label = cfree_cg_label_new(p->cg); end_label = cfree_cg_label_new(p->cg); - result_slot = cfree_cg_local_slot(p->cg, p->int_type, 0); + result_slot = cfree_cg_local_slot(p->cg, p->int_type, toy_slot_attrs(0)); + if (!toy_emit_truthy(p, ty)) return CFREE_CG_TYPE_NONE; cfree_cg_branch_false(p->cg, false_label); ty = toy_parse_expr_bor(p); if (ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; + if (!toy_emit_truthy(p, ty)) return CFREE_CG_TYPE_NONE; cfree_cg_branch_false(p->cg, false_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 1, p->int_type); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_jump(p->cg, end_label); cfree_cg_label_place(p->cg, false_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 0, p->int_type); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_label_place(p->cg, end_label); cfree_cg_push_local(p->cg, result_slot); - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); ty = p->int_type; } return ty; @@ -1607,22 +1633,24 @@ static CfreeCgTypeId toy_parse_expr_or(ToyParser* p) { toy_parser_advance(p); true_label = cfree_cg_label_new(p->cg); end_label = cfree_cg_label_new(p->cg); - result_slot = cfree_cg_local_slot(p->cg, p->int_type, 0); + result_slot = cfree_cg_local_slot(p->cg, p->int_type, toy_slot_attrs(0)); + if (!toy_emit_truthy(p, ty)) return CFREE_CG_TYPE_NONE; cfree_cg_branch_true(p->cg, true_label); ty = toy_parse_expr_and(p); if (ty == CFREE_CG_TYPE_NONE) return CFREE_CG_TYPE_NONE; + if (!toy_emit_truthy(p, ty)) return CFREE_CG_TYPE_NONE; cfree_cg_branch_true(p->cg, true_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 0, p->int_type); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_jump(p->cg, end_label); cfree_cg_label_place(p->cg, true_label); cfree_cg_push_local(p->cg, result_slot); cfree_cg_push_int(p->cg, 1, p->int_type); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, p->int_type)); cfree_cg_label_place(p->cg, end_label); cfree_cg_push_local(p->cg, result_slot); - cfree_cg_load(p->cg); + cfree_cg_load(p->cg, toy_mem_access(p, p->int_type)); ty = p->int_type; } return ty; @@ -1670,7 +1698,7 @@ static int toy_parse_let_stmt(ToyParser* p) { } ty = toy_parse_type(p); if (ty == CFREE_CG_TYPE_NONE) return 0; - slot = cfree_cg_local_slot(p->cg, ty, name); + slot = cfree_cg_local_slot(p->cg, ty, toy_slot_attrs(name)); if (p->nvars >= TOY_MAX_VARS) { toy_error(p, p->cur.loc, "too many locals"); return 0; @@ -1690,7 +1718,7 @@ static int toy_parse_let_stmt(ToyParser* p) { } cfree_cg_push_local(p->cg, slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, ty)); } if (!toy_parser_expect(p, TOK_SEMI)) { toy_error(p, p->cur.loc, "expected ';' after let"); @@ -1705,10 +1733,7 @@ static int toy_parse_if_stmt(ToyParser* p) { toy_parser_advance(p); /* if */ cond_ty = toy_parse_expr(p); if (cond_ty == CFREE_CG_TYPE_NONE) return 0; - if (cond_ty != p->int_type) { - toy_error(p, p->cur.loc, "if condition must be int"); - return 0; - } + if (!toy_emit_truthy(p, cond_ty)) return 0; it = cfree_cg_if_begin(p->cg); @@ -1748,14 +1773,10 @@ static int toy_parse_while_stmt(ToyParser* p) { p->nscopes--; return 0; } - if (cond_ty != p->int_type) { - toy_error(p, p->cur.loc, "while condition must be int"); + if (!toy_emit_truthy(p, cond_ty)) { p->nscopes--; return 0; } - - cfree_cg_push_int(p->cg, 0, p->int_type); - cfree_cg_cmp(p->cg, CFREE_CG_NE); cfree_cg_break_false(p->cg, scope); if (!toy_parse_block(p)) { @@ -1902,7 +1923,7 @@ static int toy_parse_stmt(ToyParser* p) { } cfree_cg_push_local(p->cg, v->slot); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, v->type)); } else { ToyGlobal* g = toy_find_global(p, name); if (!g) { @@ -1919,7 +1940,7 @@ static int toy_parse_stmt(ToyParser* p) { } cfree_cg_push_symbol_lvalue(p->cg, g->sym, 0); cfree_cg_swap(p->cg); - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, g->type)); } } if (!toy_parser_expect(p, TOK_SEMI)) { @@ -1935,7 +1956,7 @@ static int toy_parse_stmt(ToyParser* p) { toy_parser_advance(p); /* * */ ptr_ty = toy_parse_expr_unary(p); if (ptr_ty == CFREE_CG_TYPE_NONE) return 0; - if (!cfree_cg_type_is_ptr(p->c, ptr_ty)) { + if (cfree_cg_type_kind(p->c, ptr_ty) != CFREE_CG_TYPE_PTR) { toy_error(p, p->cur.loc, "cannot assign through non-pointer"); return 0; } @@ -1950,7 +1971,7 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "type mismatch in pointer assignment"); return 0; } - cfree_cg_store(p->cg); + cfree_cg_store(p->cg, toy_mem_access(p, expr_ty)); if (!toy_parser_expect(p, TOK_SEMI)) { toy_error(p, p->cur.loc, "expected ';' after assignment"); return 0; @@ -1969,10 +1990,12 @@ static int toy_parse_fn(ToyParser* p) { CfreeSym name; CfreeCgTypeId ret_type; CfreeCgTypeId param_types[TOY_MAX_PARAMS]; + CfreeCgParam sig_params[TOY_MAX_PARAMS]; CfreeSym param_names[TOY_MAX_PARAMS]; size_t nparams = 0; int variadic = 0; - CfreeCgDeclAttrs attrs; + CfreeCgDecl decl; + CfreeCgFuncSig sig; CfreeCgTypeId fn_ty; ToyFn* fn_entry; size_t i; @@ -2039,18 +2062,29 @@ static int toy_parse_fn(ToyParser* p) { ret_type = toy_builtin_type(p, CFREE_CG_BUILTIN_VOID); } - /* Build function type */ - fn_ty = cfree_cg_type_func(p->c, ret_type, param_types, (uint32_t)nparams, - variadic); + memset(sig_params, 0, sizeof sig_params); + for (i = 0; i < nparams; i++) sig_params[i].type = param_types[i]; + memset(&sig, 0, sizeof sig); + sig.ret = ret_type; + sig.params = sig_params; + sig.nparams = (uint32_t)nparams; + sig.call_conv = CFREE_CG_CC_TARGET_C; + sig.abi_variadic = variadic; + + fn_ty = cfree_cg_type_func(p->c, sig); if (fn_ty == CFREE_CG_TYPE_NONE) { toy_error(p, p->cur.loc, "failed to create function type"); return -1; } - memset(&attrs, 0, sizeof(attrs)); - attrs.kind = CFREE_CG_DECL_FUNC; - attrs.sym.bind = CFREE_SB_GLOBAL; - attrs.sym.visibility = CFREE_CG_VIS_DEFAULT; + memset(&decl, 0, sizeof(decl)); + decl.kind = CFREE_CG_DECL_FUNC; + decl.linkage_name = toy_c_linkage_name(p, name); + if (!decl.linkage_name) return -1; + decl.display_name = name; + decl.type = fn_ty; + decl.sym.bind = CFREE_SB_GLOBAL; + decl.sym.visibility = CFREE_CG_VIS_DEFAULT; /* Register function for recursion and later calls. */ if (p->nfns >= TOY_MAX_FNS) { @@ -2059,7 +2093,7 @@ static int toy_parse_fn(ToyParser* p) { } fn_entry = &p->fns[p->nfns]; fn_entry->name = name; - fn_entry->sym = cfree_cg_decl(p->cg, name, fn_ty, attrs); + fn_entry->sym = cfree_cg_decl(p->cg, decl); if (fn_entry->sym == CFREE_CG_SYM_NONE) { toy_error(p, p->cur.loc, "failed to declare function"); return -1; @@ -2077,8 +2111,8 @@ static int toy_parse_fn(ToyParser* p) { p->nvars = 0; p->cur_fn_ret = ret_type; for (i = 0; i < nparams; i++) { - CfreeCgSlot slot = - cfree_cg_param_slot(p->cg, (uint32_t)i, param_types[i], param_names[i]); + CfreeCgSlot slot = cfree_cg_param_slot( + p->cg, (uint32_t)i, param_types[i], toy_slot_attrs(param_names[i])); if (p->nvars >= TOY_MAX_VARS) { toy_error(p, p->cur.loc, "too many vars"); return -1; @@ -2110,7 +2144,7 @@ static int toy_parse_fn(ToyParser* p) { static int toy_parse_global_var(ToyParser* p) { CfreeSym name; CfreeCgTypeId ty; - CfreeCgDeclAttrs attrs; + CfreeCgDecl decl; CfreeCgDataDefAttrs data_attrs; CfreeCgSym sym; int mutable; @@ -2136,14 +2170,18 @@ 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); + memset(&decl, 0, sizeof(decl)); + decl.kind = CFREE_CG_DECL_OBJECT; + decl.linkage_name = toy_c_linkage_name(p, name); + if (!decl.linkage_name) return 0; + decl.display_name = name; + decl.type = ty; + decl.sym.bind = CFREE_SB_GLOBAL; + decl.sym.visibility = CFREE_CG_VIS_DEFAULT; + decl.as.object.tls_model = CFREE_CG_TLS_AUTO; + if (!mutable) decl.as.object.flags |= CFREE_CG_OBJ_READONLY; + + sym = cfree_cg_decl(p->cg, decl); if (sym == CFREE_CG_SYM_NONE) { toy_error(p, p->cur.loc, "failed to declare global"); return 0; @@ -2191,7 +2229,7 @@ static int toy_parse_global_var(ToyParser* p) { return 0; } cfree_cg_data_begin(p->cg, sym, data_attrs); - cfree_cg_data_addr(p->cg, target_sym, 0, nbytes); + cfree_cg_data_addr(p->cg, target_sym, 0, nbytes, 0); cfree_cg_data_end(p->cg); } else { toy_error(p, p->cur.loc, "expected constant global initializer"); diff --git a/src/api/cg.c b/src/api/cg.c @@ -4,8 +4,8 @@ #include <stdio.h> #include <string.h> -#include "api/cg_api.h" #include "abi/abi.h" +#include "api/cg_api.h" #include "arch/arch.h" #include "core/arena.h" #include "core/heap.h" @@ -16,7 +16,6 @@ typedef enum CgApiTypeKind { CG_API_TYPE_PTR, CG_API_TYPE_ARRAY, - CG_API_TYPE_QUALIFIED, CG_API_TYPE_ALIAS, CG_API_TYPE_RECORD, CG_API_TYPE_ENUM, @@ -29,11 +28,16 @@ typedef struct CgApiType { CfreeSym name; u32 count; u32 flags; + u32 address_space; + u64 array_count; const CfreeCgField* fields; const CfreeCgEnumValue* values; - const CfreeCgTypeId* params; + const CfreeCgParam* params; + CfreeCgAbiAttrs ret_attrs; + CfreeCgCallConv call_conv; u8 kind; - u8 pad[3]; + u8 abi_variadic; + u8 pad[2]; } CgApiType; SEGVEC_DEFINE(CgApiTypes, CgApiType, CG_API_TYPE_SEG_SHIFT); @@ -83,26 +87,14 @@ static const Type* builtin_type(Compiler* c, CfreeCgBuiltinType t) { return type_prim(c->global, TY_BOOL); case CFREE_CG_BUILTIN_I8: return type_prim(c->global, TY_SCHAR); - case CFREE_CG_BUILTIN_U8: - return type_prim(c->global, TY_UCHAR); case CFREE_CG_BUILTIN_I16: return type_prim(c->global, TY_SHORT); - case CFREE_CG_BUILTIN_U16: - return type_prim(c->global, TY_USHORT); case CFREE_CG_BUILTIN_I32: return type_prim(c->global, TY_INT); - case CFREE_CG_BUILTIN_U32: - return type_prim(c->global, TY_UINT); case CFREE_CG_BUILTIN_I64: return type_prim(c->global, TY_LLONG); - case CFREE_CG_BUILTIN_U64: - return type_prim(c->global, TY_ULLONG); - case CFREE_CG_BUILTIN_ISIZE: - return c->target.ptr_size == 8 ? type_prim(c->global, TY_LLONG) - : type_prim(c->global, TY_INT); - case CFREE_CG_BUILTIN_USIZE: - return c->target.ptr_size == 8 ? type_prim(c->global, TY_ULLONG) - : type_prim(c->global, TY_UINT); + case CFREE_CG_BUILTIN_I128: + return type_prim(c->global, TY_INT128); case CFREE_CG_BUILTIN_F32: return type_prim(c->global, TY_FLOAT); case CFREE_CG_BUILTIN_F64: @@ -143,7 +135,8 @@ static CgApiType* type_alloc(Compiler* c, CfreeCgTypeId* id_out) { return e; } -static CfreeCgTypeId find_ptr_type_id(Compiler* c, CfreeCgTypeId pointee) { +static CfreeCgTypeId find_ptr_type_id(Compiler* c, CfreeCgTypeId pointee, + u32 address_space) { CgApiState* s; u32 n; if (!c || !c->cg_api) return CFREE_CG_TYPE_NONE; @@ -151,14 +144,15 @@ static CfreeCgTypeId find_ptr_type_id(Compiler* c, CfreeCgTypeId pointee) { n = CgApiTypes_count(&s->types); for (u32 i = 0; i < n; ++i) { CgApiType* e = CgApiTypes_at(&s->types, i); - if (e && e->kind == CG_API_TYPE_PTR && e->base == pointee) + if (e && e->kind == CG_API_TYPE_PTR && e->base == pointee && + e->address_space == address_space) return type_id_for_user_index(i); } return CFREE_CG_TYPE_NONE; } static CfreeCgTypeId find_array_type_id(Compiler* c, CfreeCgTypeId elem, - u32 count) { + u64 count) { CgApiState* s; u32 n; if (!c || !c->cg_api) return CFREE_CG_TYPE_NONE; @@ -167,38 +161,22 @@ static CfreeCgTypeId find_array_type_id(Compiler* c, CfreeCgTypeId elem, for (u32 i = 0; i < n; ++i) { CgApiType* e = CgApiTypes_at(&s->types, i); if (e && e->kind == CG_API_TYPE_ARRAY && e->base == elem && - e->count == count) - return type_id_for_user_index(i); - } - return CFREE_CG_TYPE_NONE; -} - -static CfreeCgTypeId find_qualified_type_id(Compiler* c, CfreeCgTypeId base, - u32 quals) { - CgApiState* s; - u32 n; - if (!c || !c->cg_api) return CFREE_CG_TYPE_NONE; - s = (CgApiState*)c->cg_api; - n = CgApiTypes_count(&s->types); - for (u32 i = 0; i < n; ++i) { - CgApiType* e = CgApiTypes_at(&s->types, i); - if (e && e->kind == CG_API_TYPE_QUALIFIED && e->base == base && - e->flags == quals) + e->array_count == count) return type_id_for_user_index(i); } return CFREE_CG_TYPE_NONE; } -static int type_id_arrays_eq(const CfreeCgTypeId* a, const CfreeCgTypeId* b, - u32 n) { +static int cg_params_eq(const CfreeCgParam* a, const CfreeCgParam* b, u32 n) { for (u32 i = 0; i < n; ++i) - if (a[i] != b[i]) return 0; + if (a[i].type != b[i].type || + memcmp(&a[i].attrs, &b[i].attrs, sizeof(a[i].attrs)) != 0) { + return 0; + } return 1; } -static CfreeCgTypeId find_func_type_id(Compiler* c, CfreeCgTypeId ret, - const CfreeCgTypeId* params, - u32 nparams, int variadic) { +static CfreeCgTypeId find_func_type_id(Compiler* c, CfreeCgFuncSig sig) { CgApiState* s; u32 n; if (!c || !c->cg_api) return CFREE_CG_TYPE_NONE; @@ -207,9 +185,15 @@ static CfreeCgTypeId find_func_type_id(Compiler* c, CfreeCgTypeId ret, for (u32 i = 0; i < n; ++i) { CgApiType* e = CgApiTypes_at(&s->types, i); if (!e || e->kind != CG_API_TYPE_FUNC) continue; - if (e->base != ret || e->count != nparams) continue; - if ((e->flags != 0) != (variadic != 0)) continue; - if (nparams && !type_id_arrays_eq(e->params, params, nparams)) continue; + if (e->base != sig.ret || e->count != sig.nparams) continue; + if (e->abi_variadic != (sig.abi_variadic != 0)) continue; + if (e->call_conv != sig.call_conv) continue; + if (memcmp(&e->ret_attrs, &sig.ret_attrs, sizeof(e->ret_attrs)) != 0) { + continue; + } + if (sig.nparams && !cg_params_eq(e->params, sig.params, sig.nparams)) { + continue; + } return type_id_for_user_index(i); } return CFREE_CG_TYPE_NONE; @@ -248,20 +232,12 @@ static CgApiType* api_type_from_id(Compiler* c, CfreeCgTypeId id) { return e; } -static u16 quals_to_internal(u32 quals) { - u16 q = 0; - if (quals & CFREE_CG_TQ_CONST) q |= Q_CONST; - if (quals & CFREE_CG_TQ_VOLATILE) q |= Q_VOLATILE; - if (quals & CFREE_CG_TQ_RESTRICT) q |= Q_RESTRICT; - return q; -} - -static CfreeCgTypeId* copy_type_ids(Compiler* c, const CfreeCgTypeId* src, +static CfreeCgParam* copy_cg_params(Compiler* c, const CfreeCgParam* src, u32 n) { - CfreeCgTypeId* dst; + CfreeCgParam* dst; if (!n) return NULL; if (!src) return NULL; - dst = arena_array(&c->global->arena, CfreeCgTypeId, n); + dst = arena_array(&c->global->arena, CfreeCgParam, n); if (!dst) return NULL; memcpy(dst, src, sizeof(*dst) * n); return dst; @@ -277,58 +253,40 @@ CfreeCgBuiltinTypes cfree_cg_builtin_types(CfreeCompiler* c) { return out; } -CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee) { +CfreeCgTypeId cfree_cg_type_ptr(CfreeCompiler* c, CfreeCgTypeId pointee, + uint32_t address_space) { const Type* pty = resolve_type(c, pointee); CfreeCgTypeId id; CgApiType* e; if (!pty) return CFREE_CG_TYPE_NONE; - id = find_ptr_type_id(c, pointee); + id = find_ptr_type_id(c, pointee, address_space); if (id != CFREE_CG_TYPE_NONE) return id; e = type_alloc(c, &id); if (!e) return CFREE_CG_TYPE_NONE; e->type = type_ptr(c->global, pty); e->base = pointee; + e->address_space = address_space; e->kind = CG_API_TYPE_PTR; return e->type ? id : CFREE_CG_TYPE_NONE; } CfreeCgTypeId cfree_cg_type_array(CfreeCompiler* c, CfreeCgTypeId elem, - uint32_t count) { + uint64_t count) { const Type* ety = resolve_type(c, elem); CfreeCgTypeId id; CgApiType* e; - if (!ety) return CFREE_CG_TYPE_NONE; + if (!ety || count > UINT32_MAX) return CFREE_CG_TYPE_NONE; id = find_array_type_id(c, elem, count); if (id != CFREE_CG_TYPE_NONE) return id; e = type_alloc(c, &id); if (!e) return CFREE_CG_TYPE_NONE; - e->type = type_array(c->global, ety, count, 0); + e->type = type_array(c->global, ety, (u32)count, 0); e->base = elem; - e->count = count; + e->array_count = count; e->kind = CG_API_TYPE_ARRAY; return e->type ? id : CFREE_CG_TYPE_NONE; } -CfreeCgTypeId cfree_cg_type_qualified(CfreeCompiler* c, CfreeCgTypeId base, - uint32_t quals) { - const u32 known = - CFREE_CG_TQ_CONST | CFREE_CG_TQ_VOLATILE | CFREE_CG_TQ_RESTRICT; - const Type* bty = resolve_type(c, base); - CfreeCgTypeId id; - CgApiType* e; - if (!bty || (quals & ~known)) return CFREE_CG_TYPE_NONE; - if (quals == 0) return base; - id = find_qualified_type_id(c, base, quals); - if (id != CFREE_CG_TYPE_NONE) return id; - e = type_alloc(c, &id); - if (!e) return CFREE_CG_TYPE_NONE; - e->type = type_qualified(c->global, bty, quals_to_internal(quals)); - e->base = base; - e->flags = quals; - e->kind = CG_API_TYPE_QUALIFIED; - return e->type ? id : CFREE_CG_TYPE_NONE; -} - CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name, CfreeCgTypeId base) { const Type* bty = resolve_type(c, base); @@ -345,8 +303,8 @@ CfreeCgTypeId cfree_cg_type_alias(CfreeCompiler* c, CfreeSym name, } CfreeCgTypeId cfree_cg_type_record(CfreeCompiler* c, CfreeSym tag, - const CfreeCgField* fields, - uint32_t nfields) { + const CfreeCgField* fields, + uint32_t nfields) { CfreeCgTypeId id; CgApiType* e; TypeRecordBuilder* b; @@ -420,49 +378,50 @@ CfreeCgTypeId cfree_cg_type_enum(CfreeCompiler* c, CfreeSym tag, return e->type ? id : CFREE_CG_TYPE_NONE; } -CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgTypeId ret, - const CfreeCgTypeId* params, uint32_t nparams, - int variadic) { +CfreeCgTypeId cfree_cg_type_func(CfreeCompiler* c, CfreeCgFuncSig sig) { Heap* h; - const Type* rty = resolve_type(c, ret); + const Type* rty = resolve_type(c, sig.ret); const Type** ptypes = NULL; - CfreeCgTypeId* copied = NULL; + CfreeCgParam* copied = NULL; CfreeCgTypeId id; CgApiType* e; - if (!c || !rty || (nparams && !params) || nparams > UINT16_MAX) { + if (!c || !rty || (sig.nparams && !sig.params) || sig.nparams > UINT16_MAX) { return CFREE_CG_TYPE_NONE; } - id = find_func_type_id(c, ret, params, nparams, variadic); + id = find_func_type_id(c, sig); if (id != CFREE_CG_TYPE_NONE) return id; h = (Heap*)c->env->heap; - if (nparams) { - ptypes = (const Type**)h->alloc(h, sizeof(*ptypes) * nparams, + if (sig.nparams) { + ptypes = (const Type**)h->alloc(h, sizeof(*ptypes) * sig.nparams, _Alignof(const Type*)); if (!ptypes) return CFREE_CG_TYPE_NONE; - copied = copy_type_ids(c, params, nparams); + copied = copy_cg_params(c, sig.params, sig.nparams); if (!copied) { - h->free(h, ptypes, sizeof(*ptypes) * nparams); + h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); return CFREE_CG_TYPE_NONE; } - for (u32 i = 0; i < nparams; ++i) { - ptypes[i] = resolve_type(c, params[i]); + for (u32 i = 0; i < sig.nparams; ++i) { + ptypes[i] = resolve_type(c, sig.params[i].type); if (!ptypes[i]) { - h->free(h, ptypes, sizeof(*ptypes) * nparams); + h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); return CFREE_CG_TYPE_NONE; } } } e = type_alloc(c, &id); if (!e) { - if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * nparams); + if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); return CFREE_CG_TYPE_NONE; } - e->type = type_func(c->global, rty, ptypes, (u16)nparams, variadic); - if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * nparams); - e->base = ret; - e->count = nparams; + e->type = + type_func(c->global, rty, ptypes, (u16)sig.nparams, sig.abi_variadic); + if (ptypes) h->free(h, ptypes, sizeof(*ptypes) * sig.nparams); + e->base = sig.ret; + e->count = sig.nparams; e->params = copied; - e->flags = variadic ? 1u : 0u; + e->ret_attrs = sig.ret_attrs; + e->call_conv = sig.call_conv; + e->abi_variadic = sig.abi_variadic != 0; e->kind = CG_API_TYPE_FUNC; return e->type ? id : CFREE_CG_TYPE_NONE; } @@ -481,9 +440,61 @@ uint32_t cfree_cg_type_align(CfreeCompiler* c, CfreeCgTypeId id) { return ty ? (uint32_t)abi_alignof(c->abi, ty) : 0; } -int cfree_cg_type_is_ptr(CfreeCompiler* c, CfreeCgTypeId id) { +static CfreeCgTypeKind api_type_kind_from_type(const Type* ty) { + if (!ty) return CFREE_CG_TYPE_VOID; + switch (ty->kind) { + case TY_VOID: + return CFREE_CG_TYPE_VOID; + case TY_BOOL: + return CFREE_CG_TYPE_BOOL; + case TY_FLOAT: + case TY_DOUBLE: + case TY_LDOUBLE: + return CFREE_CG_TYPE_FLOAT; + case TY_PTR: + return CFREE_CG_TYPE_PTR; + case TY_ARRAY: + return CFREE_CG_TYPE_ARRAY; + case TY_FUNC: + return CFREE_CG_TYPE_FUNC; + case TY_STRUCT: + case TY_UNION: + return CFREE_CG_TYPE_RECORD; + case TY_ENUM: + return CFREE_CG_TYPE_ENUM; + default: + return type_is_int(ty) ? CFREE_CG_TYPE_INT : CFREE_CG_TYPE_VOID; + } +} + +CfreeCgTypeKind cfree_cg_type_kind(CfreeCompiler* c, CfreeCgTypeId id) { CgApiType* e = api_type_from_id(c, id); - return e && e->kind == CG_API_TYPE_PTR; + if (e) { + if (e->kind == CG_API_TYPE_ALIAS) return CFREE_CG_TYPE_ALIAS; + if (e->kind == CG_API_TYPE_PTR) return CFREE_CG_TYPE_PTR; + if (e->kind == CG_API_TYPE_ARRAY) return CFREE_CG_TYPE_ARRAY; + if (e->kind == CG_API_TYPE_FUNC) return CFREE_CG_TYPE_FUNC; + if (e->kind == CG_API_TYPE_RECORD) return CFREE_CG_TYPE_RECORD; + if (e->kind == CG_API_TYPE_ENUM) return CFREE_CG_TYPE_ENUM; + } + if (id == builtin_id(CFREE_CG_BUILTIN_VARARG_STATE)) { + return CFREE_CG_TYPE_VARARG_STATE; + } + return api_type_kind_from_type(resolve_type(c, id)); +} + +uint32_t cfree_cg_type_int_width(CfreeCompiler* c, CfreeCgTypeId id) { + const Type* ty = resolve_type(c, id); + return (ty && type_is_int(ty)) ? (uint32_t)abi_sizeof(c->abi, ty) * 8u : 0u; +} + +uint32_t cfree_cg_type_float_width(CfreeCompiler* c, CfreeCgTypeId id) { + const Type* ty = resolve_type(c, id); + if (!ty) return 0; + if (ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE || ty->kind == TY_LDOUBLE) { + return (uint32_t)abi_sizeof(c->abi, ty) * 8u; + } + return 0; } CfreeCgTypeId cfree_cg_type_ptr_pointee(CfreeCompiler* c, CfreeCgTypeId id) { @@ -491,9 +502,19 @@ CfreeCgTypeId cfree_cg_type_ptr_pointee(CfreeCompiler* c, CfreeCgTypeId id) { return (e && e->kind == CG_API_TYPE_PTR) ? e->base : CFREE_CG_TYPE_NONE; } -int cfree_cg_type_is_func(CfreeCompiler* c, CfreeCgTypeId id) { +CfreeCgTypeId cfree_cg_type_array_elem(CfreeCompiler* c, CfreeCgTypeId id) { + CgApiType* e = api_type_from_id(c, id); + return (e && e->kind == CG_API_TYPE_ARRAY) ? e->base : CFREE_CG_TYPE_NONE; +} + +uint32_t cfree_cg_type_ptr_address_space(CfreeCompiler* c, CfreeCgTypeId id) { + CgApiType* e = api_type_from_id(c, id); + return (e && e->kind == CG_API_TYPE_PTR) ? e->address_space : 0u; +} + +uint64_t cfree_cg_type_array_count(CfreeCompiler* c, CfreeCgTypeId id) { CgApiType* e = api_type_from_id(c, id); - return e && e->kind == CG_API_TYPE_FUNC; + return (e && e->kind == CG_API_TYPE_ARRAY) ? e->array_count : 0u; } CfreeCgTypeId cfree_cg_type_func_ret(CfreeCompiler* c, CfreeCgTypeId id) { @@ -506,17 +527,33 @@ uint32_t cfree_cg_type_func_nparams(CfreeCompiler* c, CfreeCgTypeId id) { return (e && e->kind == CG_API_TYPE_FUNC) ? e->count : 0; } -CfreeCgTypeId cfree_cg_type_func_param(CfreeCompiler* c, CfreeCgTypeId id, - uint32_t index) { +CfreeCgAbiAttrs cfree_cg_type_func_ret_attrs(CfreeCompiler* c, + CfreeCgTypeId id) { CgApiType* e = api_type_from_id(c, id); - if (!e || e->kind != CG_API_TYPE_FUNC || index >= e->count) - return CFREE_CG_TYPE_NONE; + CfreeCgAbiAttrs empty; + memset(&empty, 0, sizeof(empty)); + return (e && e->kind == CG_API_TYPE_FUNC) ? e->ret_attrs : empty; +} + +CfreeCgParam cfree_cg_type_func_param(CfreeCompiler* c, CfreeCgTypeId id, + uint32_t index) { + CgApiType* e = api_type_from_id(c, id); + CfreeCgParam empty; + memset(&empty, 0, sizeof(empty)); + if (!e || e->kind != CG_API_TYPE_FUNC || index >= e->count) return empty; return e->params[index]; } -int cfree_cg_type_is_record(CfreeCompiler* c, CfreeCgTypeId id) { +CfreeCgCallConv cfree_cg_type_func_call_conv(CfreeCompiler* c, + CfreeCgTypeId id) { + CgApiType* e = api_type_from_id(c, id); + return (e && e->kind == CG_API_TYPE_FUNC) ? e->call_conv + : CFREE_CG_CC_TARGET_C; +} + +int cfree_cg_type_func_is_variadic(CfreeCompiler* c, CfreeCgTypeId id) { CgApiType* e = api_type_from_id(c, id); - return e && e->kind == CG_API_TYPE_RECORD; + return e && e->kind == CG_API_TYPE_FUNC && e->abi_variadic; } uint32_t cfree_cg_type_record_nfields(CfreeCompiler* c, CfreeCgTypeId id) { @@ -525,13 +562,80 @@ uint32_t cfree_cg_type_record_nfields(CfreeCompiler* c, CfreeCgTypeId id) { } int cfree_cg_type_record_field(CfreeCompiler* c, CfreeCgTypeId id, - uint32_t index, CfreeCgField* out) { + uint32_t index, CfreeCgField* out, + uint64_t* offset_out) { CgApiType* e = api_type_from_id(c, id); - if (!e || e->kind != CG_API_TYPE_RECORD || !out || index >= e->count) return 1; - *out = e->fields[index]; + const ABIRecordLayout* layout; + if (!e || e->kind != CG_API_TYPE_RECORD || index >= e->count) return 1; + if (out) *out = e->fields[index]; + if (offset_out) { + layout = abi_record_layout(c->abi, e->type); + *offset_out = (layout && index < layout->nfields) + ? (uint64_t)layout->fields[index].offset + : 0u; + } + return 0; +} + +int cfree_cg_target_supports_call_conv(CfreeCompiler* c, CfreeCgCallConv cc) { + if (!c) return 0; + switch (cc) { + case CFREE_CG_CC_TARGET_C: + return 1; + case CFREE_CG_CC_SYSV: + return c->target.arch == CFREE_ARCH_X86_64 && + c->target.os != CFREE_OS_WINDOWS; + case CFREE_CG_CC_WIN64: + return c->target.arch == CFREE_ARCH_X86_64 && + c->target.os == CFREE_OS_WINDOWS; + case CFREE_CG_CC_AAPCS: + return c->target.arch == CFREE_ARCH_ARM_32 || + c->target.arch == CFREE_ARCH_ARM_64; + case CFREE_CG_CC_WASM: + return c->target.arch == CFREE_ARCH_WASM; + case CFREE_CG_CC_INTERRUPT: + return 0; + } + return 0; +} + +int cfree_cg_target_supports_symbol_feature(CfreeCompiler* c, + CfreeCgSymbolFeature feat) { + if (!c) return 0; + switch (feat) { + case CFREE_CG_SYMFEAT_WEAK: + case CFREE_CG_SYMFEAT_PROTECTED_VISIBILITY: + case CFREE_CG_SYMFEAT_COMDAT: + case CFREE_CG_SYMFEAT_COMMON: + return 1; + case CFREE_CG_SYMFEAT_TLS_LOCAL_EXEC: + case CFREE_CG_SYMFEAT_TLS_INITIAL_EXEC: + case CFREE_CG_SYMFEAT_TLS_LOCAL_DYNAMIC: + case CFREE_CG_SYMFEAT_TLS_GENERAL_DYNAMIC: + return c->target.obj == CFREE_OBJ_ELF || c->target.obj == CFREE_OBJ_MACHO; + case CFREE_CG_SYMFEAT_DLLIMPORT: + case CFREE_CG_SYMFEAT_DLLEXPORT: + case CFREE_CG_SYMFEAT_MERGE_SECTIONS: + case CFREE_CG_SYMFEAT_CONSTRUCTOR_PRIORITY: + return 0; + } return 0; } +uint64_t cfree_cg_target_backend_features(CfreeCompiler* c) { + uint64_t out = 0; + if (!c) return 0; + if (c->target.arch == CFREE_ARCH_X86_64 || + c->target.arch == CFREE_ARCH_X86_32) { + out |= CFREE_CG_BACKEND_UNALIGNED_MEMORY; + out |= CFREE_CG_BACKEND_RED_ZONE; + out |= CFREE_CG_BACKEND_SIMD; + } else { + out |= CFREE_CG_BACKEND_STRICT_ALIGNMENT; + } + return out; +} + void cg_api_fini(Compiler* c) { CgApiState* s; if (!c || !c->cg_api) return; @@ -610,7 +714,7 @@ struct CfreeCg { CGParamDesc fn_params[64]; const Type** sym_types; - CfreeCgDeclAttrs* sym_attrs; + CfreeCgDecl* sym_attrs; u32 sym_cap; ApiCgScope scopes[API_CG_MAX_SCOPES]; @@ -791,8 +895,10 @@ static Reg api_reg_of_sv(const ApiSValue* sv) { } static void api_set_owned_reg(ApiSValue* sv, Reg r) { - if (sv->op.kind == OPK_REG) sv->op.v.reg = r; - else if (sv->op.kind == OPK_INDIRECT) sv->op.v.ind.base = r; + if (sv->op.kind == OPK_REG) + sv->op.v.reg = r; + else if (sv->op.kind == OPK_INDIRECT) + sv->op.v.ind.base = r; } static const Type* api_owned_reg_type(CfreeCg* g, const ApiSValue* sv) { @@ -831,10 +937,13 @@ static void api_return_spill_slot(CfreeCg* g, FrameSlot s, u8 cls) { h = g->c->env->heap; if (g->slot_pools[cls].n >= g->slot_pools[cls].cap) { u32 new_cap = g->slot_pools[cls].cap ? g->slot_pools[cls].cap * 2 : 8; - FrameSlot* nb = (FrameSlot*)h->alloc(h, sizeof(FrameSlot) * new_cap, _Alignof(FrameSlot)); + FrameSlot* nb = (FrameSlot*)h->alloc(h, sizeof(FrameSlot) * new_cap, + _Alignof(FrameSlot)); if (g->slot_pools[cls].free) { - memcpy(nb, g->slot_pools[cls].free, sizeof(FrameSlot) * g->slot_pools[cls].n); - h->free(h, g->slot_pools[cls].free, sizeof(FrameSlot) * g->slot_pools[cls].cap); + memcpy(nb, g->slot_pools[cls].free, + sizeof(FrameSlot) * g->slot_pools[cls].n); + h->free(h, g->slot_pools[cls].free, + sizeof(FrameSlot) * g->slot_pools[cls].cap); } g->slot_pools[cls].free = nb; g->slot_pools[cls].cap = new_cap; @@ -874,7 +983,8 @@ static int api_spill_avs_victim(CfreeCg* g, u8 cls) { return 0; } -static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, const Type* ty) { +static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, + const Type* ty) { MemAccess m; memset(&m, 0, sizeof m); m.type = ty; @@ -893,6 +1003,19 @@ static MemAccess api_mem_for_lvalue(CfreeCg* g, const Operand* lv, const Type* t return m; } +static MemAccess api_mem_from_access(CfreeCg* g, const Operand* lv, + CfreeCgMemAccess access) { + const Type* ty = resolve_type(g->c, access.type); + MemAccess m = api_mem_for_lvalue(g, lv, ty); + if (access.align) m.align = access.align; + m.addr_space = (u16)access.address_space; + if (access.flags & CFREE_CG_MEM_VOLATILE) m.flags |= MF_VOLATILE; + if (!access.align || (ty && access.align < abi_alignof(g->c->abi, ty))) { + m.flags |= MF_UNALIGNED; + } + return m; +} + static MemAccess api_mem_for_spill(CfreeCg* g, const ApiSValue* sv) { const Type* ty = api_owned_reg_type(g, sv); MemAccess m; @@ -938,7 +1061,8 @@ static void api_ensure_reg(CfreeCg* g, ApiSValue* sv) { CGTarget* T = g->target; u8 cls = api_class_of_sv(sv); const Type* ty = api_owned_reg_type(g, sv); - Reg r = api_alloc_reg_or_spill(g, cls, ty ? ty : type_prim(g->c->global, TY_INT)); + Reg r = + api_alloc_reg_or_spill(g, cls, ty ? ty : type_prim(g->c->global, TY_INT)); T->reload_reg(T, api_op_reg(r, ty), sv->spill_slot, api_mem_for_spill(g, sv)); api_return_spill_slot(g, sv->spill_slot, cls); sv->spill_slot = FRAME_SLOT_NONE; @@ -966,14 +1090,16 @@ static Operand api_force_reg(CfreeCg* g, ApiSValue* v, const Type* ty) { } else if (v->op.kind == OPK_GLOBAL) { T->addr_of(T, dst, v->op); } else { - compiler_panic(g->c, g->cur_loc, "CfreeCg: cannot force operand to register"); + compiler_panic(g->c, g->cur_loc, + "CfreeCg: cannot force operand to register"); } v->op = dst; v->res = RES_REG; return dst; } -static Operand api_force_reg_unless_imm(CfreeCg* g, ApiSValue* v, const Type* ty) { +static Operand api_force_reg_unless_imm(CfreeCg* g, ApiSValue* v, + const Type* ty) { if (v->op.kind == OPK_IMM) return v->op; return api_force_reg(g, v, ty); } @@ -1002,138 +1128,218 @@ static void api_release_arg_storage(CfreeCg* g, Operand* storage) { /* ---- BinOp / UnOp / CmpOp mapping ---- */ -static BinOp api_map_binop(CfreeCgBinOp op) { +static BinOp api_map_int_binop(CfreeCgIntBinOp op) { switch (op) { - case CFREE_CG_ADD: return BO_IADD; - case CFREE_CG_SUB: return BO_ISUB; - case CFREE_CG_MUL: return BO_IMUL; - case CFREE_CG_SDIV: return BO_SDIV; - case CFREE_CG_UDIV: return BO_UDIV; - case CFREE_CG_SREM: return BO_SREM; - case CFREE_CG_UREM: return BO_UREM; - case CFREE_CG_AND: return BO_AND; - case CFREE_CG_OR: return BO_OR; - case CFREE_CG_XOR: return BO_XOR; - case CFREE_CG_SHL: return BO_SHL; - case CFREE_CG_SHR_S: return BO_SHR_S; - case CFREE_CG_SHR_U: return BO_SHR_U; + case CFREE_CG_INT_ADD: + return BO_IADD; + case CFREE_CG_INT_SUB: + return BO_ISUB; + case CFREE_CG_INT_MUL: + return BO_IMUL; + case CFREE_CG_INT_SDIV: + return BO_SDIV; + case CFREE_CG_INT_UDIV: + return BO_UDIV; + case CFREE_CG_INT_SREM: + return BO_SREM; + case CFREE_CG_INT_UREM: + return BO_UREM; + case CFREE_CG_INT_AND: + return BO_AND; + case CFREE_CG_INT_OR: + return BO_OR; + case CFREE_CG_INT_XOR: + return BO_XOR; + case CFREE_CG_INT_SHL: + return BO_SHL; + case CFREE_CG_INT_LSHR: + return BO_SHR_U; + case CFREE_CG_INT_ASHR: + return BO_SHR_S; } return BO_IADD; } -static UnOp api_map_unop(CfreeCgUnOp op) { +static BinOp api_map_fp_binop(CfreeCgFpBinOp op) { switch (op) { - case CFREE_CG_NEG: return UO_NEG; - case CFREE_CG_NOT: return UO_NOT; - case CFREE_CG_BNOT: return UO_BNOT; + case CFREE_CG_FP_ADD: + return BO_FADD; + case CFREE_CG_FP_SUB: + return BO_FSUB; + case CFREE_CG_FP_MUL: + return BO_FMUL; + case CFREE_CG_FP_DIV: + return BO_FDIV; + case CFREE_CG_FP_REM: + return BO_FDIV; + } + return BO_FADD; +} + +static UnOp api_map_int_unop(CfreeCgIntUnOp op) { + switch (op) { + case CFREE_CG_INT_NEG: + return UO_NEG; + case CFREE_CG_INT_NOT: + return UO_NOT; + case CFREE_CG_INT_BNOT: + return UO_BNOT; } return UO_NEG; } -static CmpOp api_map_cmp(CfreeCgCmpOp op) { +static CmpOp api_map_int_cmp(CfreeCgIntCmpOp op) { switch (op) { - case CFREE_CG_EQ: return CMP_EQ; - case CFREE_CG_NE: return CMP_NE; - case CFREE_CG_LT_S: return CMP_LT_S; - case CFREE_CG_LE_S: return CMP_LE_S; - case CFREE_CG_GT_S: return CMP_GT_S; - case CFREE_CG_GE_S: return CMP_GE_S; - case CFREE_CG_LT_U: return CMP_LT_U; - case CFREE_CG_LE_U: return CMP_LE_U; - case CFREE_CG_GT_U: return CMP_GT_U; - case CFREE_CG_GE_U: return CMP_GE_U; + case CFREE_CG_INT_EQ: + return CMP_EQ; + case CFREE_CG_INT_NE: + return CMP_NE; + case CFREE_CG_INT_LT_S: + return CMP_LT_S; + case CFREE_CG_INT_LE_S: + return CMP_LE_S; + case CFREE_CG_INT_GT_S: + return CMP_GT_S; + case CFREE_CG_INT_GE_S: + return CMP_GE_S; + case CFREE_CG_INT_LT_U: + return CMP_LT_U; + case CFREE_CG_INT_LE_U: + return CMP_LE_U; + case CFREE_CG_INT_GT_U: + return CMP_GT_U; + case CFREE_CG_INT_GE_U: + return CMP_GE_U; + } + return CMP_EQ; +} + +static CmpOp api_map_fp_cmp(CfreeCgFpCmpOp op) { + switch (op) { + case CFREE_CG_FP_OEQ: + case CFREE_CG_FP_UEQ: + return CMP_EQ; + case CFREE_CG_FP_ONE: + case CFREE_CG_FP_UNE: + return CMP_NE; + case CFREE_CG_FP_OLT: + case CFREE_CG_FP_ULT: + return CMP_LT_F; + case CFREE_CG_FP_OLE: + case CFREE_CG_FP_ULE: + return CMP_LE_F; + case CFREE_CG_FP_OGT: + case CFREE_CG_FP_UGT: + return CMP_GT_F; + case CFREE_CG_FP_OGE: + case CFREE_CG_FP_UGE: + return CMP_GE_F; } return CMP_EQ; } static AtomicOp api_map_atomic_op(CfreeCgAtomicOp op) { switch (op) { - case CFREE_CG_ATOMIC_XCHG: return AO_XCHG; - case CFREE_CG_ATOMIC_ADD: return AO_ADD; - case CFREE_CG_ATOMIC_SUB: return AO_SUB; - case CFREE_CG_ATOMIC_AND: return AO_AND; - case CFREE_CG_ATOMIC_OR: return AO_OR; - case CFREE_CG_ATOMIC_XOR: return AO_XOR; - case CFREE_CG_ATOMIC_NAND: return AO_NAND; + case CFREE_CG_ATOMIC_XCHG: + return AO_XCHG; + case CFREE_CG_ATOMIC_ADD: + return AO_ADD; + case CFREE_CG_ATOMIC_SUB: + return AO_SUB; + case CFREE_CG_ATOMIC_AND: + return AO_AND; + case CFREE_CG_ATOMIC_OR: + return AO_OR; + case CFREE_CG_ATOMIC_XOR: + return AO_XOR; + case CFREE_CG_ATOMIC_NAND: + return AO_NAND; } return AO_XCHG; } static MemOrder api_map_mem_order(CfreeCgMemOrder order) { switch (order) { - case CFREE_CG_MO_RELAXED: return MO_RELAXED; - case CFREE_CG_MO_CONSUME: return MO_CONSUME; - case CFREE_CG_MO_ACQUIRE: return MO_ACQUIRE; - case CFREE_CG_MO_RELEASE: return MO_RELEASE; - case CFREE_CG_MO_ACQ_REL: return MO_ACQ_REL; - case CFREE_CG_MO_SEQ_CST: return MO_SEQ_CST; + case CFREE_CG_MO_RELAXED: + return MO_RELAXED; + case CFREE_CG_MO_CONSUME: + return MO_CONSUME; + case CFREE_CG_MO_ACQUIRE: + return MO_ACQUIRE; + case CFREE_CG_MO_RELEASE: + return MO_RELEASE; + case CFREE_CG_MO_ACQ_REL: + return MO_ACQ_REL; + case CFREE_CG_MO_SEQ_CST: + return MO_SEQ_CST; } return MO_RELAXED; } static AsmDir api_map_asm_dir(uint8_t dir) { switch ((CfreeCgAsmDir)dir) { - case CFREE_CG_ASM_IN: return ASM_IN; - case CFREE_CG_ASM_OUT: return ASM_OUT; - case CFREE_CG_ASM_INOUT: return ASM_INOUT; + case CFREE_CG_ASM_IN: + return ASM_IN; + case CFREE_CG_ASM_OUT: + return ASM_OUT; + case CFREE_CG_ASM_INOUT: + return ASM_INOUT; } return ASM_IN; } /* ---- C-symbol mangling ---- */ -static Sym api_c_mangle(Compiler* c, CfreeSym name) { - size_t len; - const char* str = pool_str(c->global, (Sym)name, &len); - if (!str) return 0; - return obj_format_c_mangle(c, str); -} - static SymBind api_map_bind(CfreeSymBind b) { switch (b) { - case CFREE_SB_LOCAL: return SB_LOCAL; - case CFREE_SB_GLOBAL: return SB_GLOBAL; - case CFREE_SB_WEAK: return SB_WEAK; + case CFREE_SB_LOCAL: + return SB_LOCAL; + case CFREE_SB_GLOBAL: + return SB_GLOBAL; + case CFREE_SB_WEAK: + return SB_WEAK; } return SB_LOCAL; } static SymVis api_map_vis(CfreeCgVisibility v) { switch (v) { - case CFREE_CG_VIS_DEFAULT: return SV_DEFAULT; - case CFREE_CG_VIS_HIDDEN: return SV_HIDDEN; - case CFREE_CG_VIS_PROTECTED: return SV_PROTECTED; + case CFREE_CG_VIS_DEFAULT: + return SV_DEFAULT; + case CFREE_CG_VIS_HIDDEN: + return SV_HIDDEN; + case CFREE_CG_VIS_PROTECTED: + return SV_PROTECTED; } return SV_DEFAULT; } -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; +static SymKind api_decl_sym_kind(CfreeCgDecl decl) { + if (decl.kind == CFREE_CG_DECL_FUNC) { + if (decl.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; + if (decl.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) { + CfreeCgDecl decl) { Heap* h; const Type** nts; - CfreeCgDeclAttrs* nas; + CfreeCgDecl* 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; + g->sym_attrs[sym] = decl; 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)); + nas = (CfreeCgDecl*)h->alloc(h, sizeof(*nas) * cap, _Alignof(CfreeCgDecl)); if (!nts || !nas) { if (nts) h->free(h, nts, sizeof(*nts) * cap); if (nas) h->free(h, nas, sizeof(*nas) * cap); @@ -1153,7 +1359,7 @@ static void api_remember_sym(CfreeCg* g, ObjSymId sym, const Type* ty, g->sym_attrs = nas; g->sym_cap = cap; g->sym_types[sym] = ty; - g->sym_attrs[sym] = attrs; + g->sym_attrs[sym] = decl; } static const Type* api_sym_type(CfreeCg* g, CfreeCgSym sym) { @@ -1161,20 +1367,20 @@ static const Type* api_sym_type(CfreeCg* g, CfreeCgSym sym) { 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; +static CfreeCgDecl api_sym_attrs(CfreeCg* g, CfreeCgSym sym) { + CfreeCgDecl decl; + memset(&decl, 0, sizeof(decl)); + decl.kind = CFREE_CG_DECL_OBJECT; + decl.sym.bind = CFREE_SB_GLOBAL; + decl.sym.visibility = CFREE_CG_VIS_DEFAULT; + if (!g || sym == CFREE_CG_SYM_NONE || sym >= g->sym_cap) return decl; 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); + CfreeCgDecl decl = api_sym_attrs(g, sym); + return decl.kind == CFREE_CG_DECL_OBJECT && + (decl.as.object.flags & CFREE_CG_OBJ_TLS); } static RelocKind api_data_reloc_kind(int pcrel, uint32_t width) { @@ -1239,7 +1445,8 @@ void cfree_cg_free(CfreeCg* g) { } 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); + h->free(h, g->slot_pools[c].free, + sizeof(FrameSlot) * g->slot_pools[c].cap); } } h->free(h, g, sizeof *g); @@ -1259,59 +1466,53 @@ void cfree_cg_set_loc(CfreeCg* g, CfreeSrcLoc loc) { * Function lifecycle * ============================================================ */ -CfreeCgSym cfree_cg_decl(CfreeCg* g, CfreeSym name, CfreeCgTypeId type, - CfreeCgDeclAttrs attrs) { +CfreeCgSym cfree_cg_decl(CfreeCg* g, CfreeCgDecl decl) { Compiler* c; ObjBuilder* ob; - Sym mangled; ObjSymId sym; const Type* ty; - if (!g || !name) return CFREE_CG_SYM_NONE; + if (!g || !decl.linkage_name) return CFREE_CG_SYM_NONE; c = g->c; ob = g->obj; - ty = resolve_type(c, type); + ty = resolve_type(c, decl.type); if (!ty) return CFREE_CG_SYM_NONE; - mangled = api_c_mangle(c, name); - sym = obj_symbol_find(ob, mangled); + sym = obj_symbol_find(ob, (Sym)decl.linkage_name); if (sym == OBJ_SYM_NONE) { - 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); + sym = obj_symbol_ex(ob, (Sym)decl.linkage_name, api_map_bind(decl.sym.bind), + api_map_vis(decl.sym.visibility), + api_decl_sym_kind(decl), OBJ_SEC_NONE, 0, 0, 0); } - if (attrs.sym.flags) { - obj_symbol_set_flags(ob, sym, (u16)attrs.sym.flags); + if (decl.sym.flags) { + obj_symbol_set_flags(ob, sym, (u16)decl.sym.flags); } - api_remember_sym(g, sym, ty, attrs); + api_remember_sym(g, sym, ty, decl); return (CfreeCgSym)sym; } -CfreeCgSym cfree_cg_alias(CfreeCg* g, CfreeSym alias_name, CfreeCgSym target, - CfreeCgSymbolAttrs attrs) { +CfreeCgSym cfree_cg_alias(CfreeCg* g, CfreeCgAlias alias) { ObjBuilder* ob; - Sym mangled; ObjSymId sym; const ObjSym* ts; - CfreeCgDeclAttrs decl_attrs; - if (!g || !alias_name || target == CFREE_CG_SYM_NONE) { + CfreeCgDecl decl_attrs; + if (!g || !alias.linkage_name || alias.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); + sym = obj_symbol_find(ob, (Sym)alias.linkage_name); + ts = obj_symbol_get(ob, (ObjSymId)alias.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); + sym = + obj_symbol_ex(ob, (Sym)alias.linkage_name, api_map_bind(alias.sym.bind), + api_map_vis(alias.sym.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); + if (alias.sym.flags) obj_symbol_set_flags(ob, sym, (u16)alias.sym.flags); + decl_attrs = api_sym_attrs(g, alias.target); + decl_attrs.sym = alias.sym; + api_remember_sym(g, sym, api_sym_type(g, alias.target), decl_attrs); return (CfreeCgSym)sym; } @@ -1323,7 +1524,7 @@ void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { ObjSecId text_sec; const Type* fty; const ABIFuncInfo* abi; - CfreeCgDeclAttrs attrs; + CfreeCgDecl attrs; if (!g) return; c = g->c; ob = g->obj; @@ -1334,8 +1535,8 @@ void cfree_cg_func_begin(CfreeCg* g, CfreeCgSym cg_sym) { abi = abi_func_info(c->abi, fty); attrs = api_sym_attrs(g, cg_sym); - text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), - SEC_TEXT, SF_EXEC | SF_ALLOC, 4); + text_sec = obj_section(ob, pool_intern_cstr(c->global, ".text"), SEC_TEXT, + SF_EXEC | SF_ALLOC, 4); if (sym != OBJ_SYM_NONE) { obj_symbol_define(ob, sym, text_sec, 0, 0); @@ -1375,7 +1576,8 @@ void cfree_cg_func_end(CfreeCg* g) { * Local / param slots * ============================================================ */ -CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, CfreeSym name) { +CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, + CfreeCgSlotAttrs attrs) { const Type* ty; FrameSlotDesc fsd; FrameSlot slot; @@ -1384,18 +1586,19 @@ CfreeCgSlot cfree_cg_local_slot(CfreeCg* g, CfreeCgTypeId type, CfreeSym name) { if (!ty) return 0; memset(&fsd, 0, sizeof fsd); fsd.type = ty; - fsd.name = (Sym)name; + fsd.name = (Sym)attrs.name; fsd.loc = g->cur_loc; fsd.size = abi_sizeof(g->c->abi, ty); - fsd.align = abi_alignof(g->c->abi, ty); + fsd.align = attrs.align ? attrs.align : abi_alignof(g->c->abi, ty); fsd.kind = FS_LOCAL; + if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) fsd.flags |= FSF_ADDR_TAKEN; slot = g->target->frame_slot(g->target, &fsd); api_remember_slot_type(g, slot, ty); return (CfreeCgSlot)slot; } CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, - CfreeSym name) { + CfreeCgSlotAttrs attrs) { const Type* ty; FrameSlot slot; CGParamDesc pd; @@ -1406,17 +1609,18 @@ CfreeCgSlot cfree_cg_param_slot(CfreeCg* g, uint32_t index, CfreeCgTypeId type, memset(&fsd, 0, sizeof fsd); fsd.type = ty; - fsd.name = (Sym)name; + fsd.name = (Sym)attrs.name; fsd.loc = g->cur_loc; fsd.size = abi_sizeof(g->c->abi, ty); - fsd.align = abi_alignof(g->c->abi, ty); + fsd.align = attrs.align ? attrs.align : abi_alignof(g->c->abi, ty); fsd.kind = FS_PARAM; + if (attrs.flags & CFREE_CG_SLOT_ADDRESS_TAKEN) fsd.flags |= FSF_ADDR_TAKEN; slot = g->target->frame_slot(g->target, &fsd); api_remember_slot_type(g, slot, ty); memset(&pd, 0, sizeof pd); pd.index = index; - pd.name = (Sym)name; + pd.name = (Sym)attrs.name; pd.type = ty; pd.slot = slot; if (g->fn_abi && index < g->fn_abi->nparams) { @@ -1444,7 +1648,11 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { const Type* ty; CGTarget* T; ConstBytes cb; - union { double d; float f; uint8_t b[8]; } u; + union { + double d; + float f; + uint8_t b[8]; + } u; Reg r; Operand dst; if (!g) return; @@ -1454,8 +1662,10 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { cb.type = ty; cb.size = (u32)abi_sizeof(g->c->abi, ty); cb.align = (u32)abi_alignof(g->c->abi, ty); - if (ty->kind == TY_FLOAT) u.f = (float)value; - else u.d = value; + if (ty->kind == TY_FLOAT) + u.f = (float)value; + else + u.d = value; cb.bytes = u.b; r = api_alloc_reg_or_spill(g, api_type_class(ty), ty); dst = api_op_reg(r, ty); @@ -1463,6 +1673,14 @@ void cfree_cg_push_float(CfreeCg* g, double value, CfreeCgTypeId type) { api_push(g, api_make_sv(dst, ty)); } +void cfree_cg_push_null(CfreeCg* g, CfreeCgTypeId ptr_type) { + const Type* ty; + if (!g) return; + ty = resolve_type(g->c, ptr_type); + if (!ty) return; + api_push(g, api_make_sv(api_op_imm(0, ty), ty)); +} + CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, uint32_t align, CfreeCgTypeId pointee_type) { Compiler* c; @@ -1474,7 +1692,7 @@ CfreeCgSym cfree_cg_const_data(CfreeCg* g, const uint8_t* data, size_t len, char name_buf[32]; Sym anon_name; ObjSymId sym; - CfreeCgDeclAttrs attrs; + CfreeCgDecl attrs; if (!g) return CFREE_CG_SYM_NONE; c = g->c; ob = g->obj; @@ -1517,8 +1735,8 @@ void cfree_cg_push_symbol_addr(CfreeCg* g, CfreeCgSym sym, int64_t addend) { 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)); + api_push(g, + api_make_sv(api_op_global((ObjSymId)sym, addend, ptr_ty), ptr_ty)); } } @@ -1538,11 +1756,57 @@ void cfree_cg_push_symbol_lvalue(CfreeCg* g, CfreeCgSym sym, int64_t addend) { } } +void cfree_cg_addr_offset(CfreeCg* g, int64_t byte_offset, + CfreeCgTypeId result_type) { + ApiSValue v; + const Type* rty; + const Type* ptr_ty; + Operand base; + Operand result; + Reg rr; + if (!g) return; + rty = resolve_type(g->c, result_type); + if (!rty) return; + v = api_pop(g); + api_ensure_reg(g, &v); + if (v.op.kind == OPK_GLOBAL) { + result = api_op_global(v.op.v.global.sym, + v.op.v.global.addend + byte_offset, rty); + api_push(g, type_is_ptr(rty) ? api_make_sv(result, rty) + : api_make_lv(result, rty)); + return; + } + if (v.op.kind == OPK_INDIRECT) { + i64 ofs = (i64)v.op.v.ind.ofs + byte_offset; + if (ofs >= INT32_MIN && ofs <= INT32_MAX) { + result = api_op_indirect(v.op.v.ind.base, (i32)ofs, rty); + api_push(g, type_is_ptr(rty) ? api_make_sv(result, rty) + : api_make_lv(result, rty)); + return; + } + } + ptr_ty = type_is_ptr(api_sv_type(&v)) ? api_sv_type(&v) + : type_ptr(g->c->global, rty); + base = api_is_lvalue_sv(&v) ? api_force_reg(g, &v, ptr_ty) + : api_force_reg(g, &v, ptr_ty); + rr = api_alloc_reg_or_spill(g, RC_INT, ptr_ty); + result = api_op_reg(rr, ptr_ty); + g->target->binop(g->target, BO_IADD, result, base, + api_op_imm(byte_offset, ptr_ty)); + api_release(g, &v); + if (type_is_ptr(rty)) { + result.type = rty; + api_push(g, api_make_sv(result, rty)); + } else { + api_push(g, api_make_lv(api_op_indirect(result.v.reg, 0, rty), rty)); + } +} + /* ============================================================ * Load / addr / store * ============================================================ */ -void cfree_cg_load(CfreeCg* g) { +void cfree_cg_load(CfreeCg* g, CfreeCgMemAccess access) { ApiSValue v; const Type* ty; Operand dst; @@ -1553,8 +1817,10 @@ void cfree_cg_load(CfreeCg* g) { api_push(g, v); return; } - ty = api_sv_type(&v); + ty = resolve_type(g->c, access.type); + if (!ty) ty = api_sv_type(&v); dst = api_force_reg(g, &v, ty); + dst.type = ty; api_push(g, api_make_sv(dst, ty)); } @@ -1574,8 +1840,7 @@ void cfree_cg_indirect(CfreeCg* g) { } pointee = pty->ptr.pointee; ptr_op = api_force_reg(g, &ptr, pty); - api_push(g, api_make_lv(api_op_indirect(ptr_op.v.reg, 0, pointee), - pointee)); + api_push(g, api_make_lv(api_op_indirect(ptr_op.v.reg, 0, pointee), pointee)); } void cfree_cg_addr(CfreeCg* g) { @@ -1600,7 +1865,7 @@ void cfree_cg_addr(CfreeCg* g) { api_push(g, api_make_sv(dst, pty)); } -void cfree_cg_store(CfreeCg* g) { +void cfree_cg_store(CfreeCg* g, CfreeCgMemAccess access) { ApiSValue lv, rv; CGTarget* T; const Type* ty; @@ -1612,16 +1877,18 @@ void cfree_cg_store(CfreeCg* g) { api_ensure_reg(g, &lv); api_ensure_reg(g, &rv); if (!api_is_lvalue_sv(&lv)) { - compiler_panic(g->c, g->cur_loc, "CfreeCg: store destination is not an lvalue"); + compiler_panic(g->c, g->cur_loc, + "CfreeCg: store destination is not an lvalue"); return; } - ty = api_sv_type(&lv); + ty = resolve_type(g->c, access.type); + if (!ty) ty = api_sv_type(&lv); if (rv.op.kind == OPK_IMM || rv.op.kind == OPK_REG) { src = rv.op; } else { src = api_force_reg(g, &rv, api_sv_type(&rv)); } - T->store(T, lv.op, src, api_mem_for_lvalue(g, &lv.op, ty)); + T->store(T, lv.op, src, api_mem_from_access(g, &lv.op, access)); api_release(g, &lv); api_release(g, &rv); } @@ -1648,8 +1915,7 @@ void cfree_cg_dup(CfreeCg* g) { ty = api_owned_reg_type(g, &v); r = api_alloc_reg_or_spill(g, api_class_of_sv(&v), ty); dst = api_op_reg(r, ty); - g->target->copy(g->target, dst, - api_op_reg((Reg)api_reg_of_sv(&v), ty)); + g->target->copy(g->target, dst, api_op_reg((Reg)api_reg_of_sv(&v), ty)); g->stack[g->sp - 1].pinned = 0; dup = v; api_set_owned_reg(&dup, r); @@ -1689,11 +1955,10 @@ void cfree_cg_rot3(CfreeCg* g) { * Arithmetic / compare / convert * ============================================================ */ -void cfree_cg_binop(CfreeCg* g, CfreeCgBinOp op) { +static void api_cg_binop(CfreeCg* g, BinOp iop) { ApiSValue b, a; CGTarget* T; const Type* ty; - BinOp iop; Operand ra, rb; Reg rr; Operand dst; @@ -1702,7 +1967,6 @@ void cfree_cg_binop(CfreeCg* g, CfreeCgBinOp op) { b = api_pop(g); a = api_pop(g); ty = a.type ? a.type : b.type; - iop = api_map_binop(op); ra = api_force_reg_unless_imm(g, &a, ty); rb = api_force_reg_unless_imm(g, &b, ty); @@ -1714,11 +1978,10 @@ void cfree_cg_binop(CfreeCg* g, CfreeCgBinOp op) { api_push(g, api_make_sv(dst, ty)); } -void cfree_cg_unop(CfreeCg* g, CfreeCgUnOp op) { +static void api_cg_unop(CfreeCg* g, UnOp iop) { ApiSValue a; CGTarget* T; const Type* ty; - UnOp iop; Operand ra; Reg rr; Operand dst; @@ -1726,7 +1989,6 @@ void cfree_cg_unop(CfreeCg* g, CfreeCgUnOp op) { T = g->target; a = api_pop(g); ty = a.type ? a.type : a.op.type; - iop = api_map_unop(op); ra = api_force_reg_unless_imm(g, &a, ty); rr = api_alloc_reg_or_spill(g, api_type_class(ty), ty); @@ -1736,12 +1998,11 @@ void cfree_cg_unop(CfreeCg* g, CfreeCgUnOp op) { api_push(g, api_make_sv(dst, ty)); } -void cfree_cg_cmp(CfreeCg* g, CfreeCgCmpOp op) { +static void api_cg_cmp(CfreeCg* g, CmpOp cop) { ApiSValue b, a; CGTarget* T; const Type* opty; const Type* i32; - CmpOp cop; Operand ra, rb; Reg rr; Operand dst; @@ -1751,7 +2012,6 @@ void cfree_cg_cmp(CfreeCg* g, CfreeCgCmpOp op) { a = api_pop(g); opty = a.type ? a.type : b.type; i32 = type_prim(g->c->global, TY_INT); - cop = api_map_cmp(op); ra = api_force_reg_unless_imm(g, &a, opty); rb = api_force_reg_unless_imm(g, &b, opty); @@ -1763,18 +2023,15 @@ void cfree_cg_cmp(CfreeCg* g, CfreeCgCmpOp op) { api_push(g, api_make_sv(dst, i32)); } -void cfree_cg_convert(CfreeCg* g, CfreeCgTypeId dst_type) { +static void api_cg_convert_kind(CfreeCg* g, CfreeCgTypeId dst_type, + ConvKind ck) { ApiSValue v; CGTarget* T; const Type* sty; const Type* dty; - ConvKind ck; Operand src; Reg rr; Operand dst; - int s_int, d_int, s_flt, d_flt, s_ptr, d_ptr; - u32 s_sz, d_sz; - int s_signed; if (!g) return; T = g->target; dty = resolve_type(g->c, dst_type); @@ -1786,42 +2043,6 @@ void cfree_cg_convert(CfreeCg* g, CfreeCgTypeId dst_type) { return; } - s_int = type_is_int(sty); - d_int = type_is_int(dty); - s_flt = sty && (sty->kind == TY_FLOAT || sty->kind == TY_DOUBLE); - d_flt = dty && (dty->kind == TY_FLOAT || dty->kind == TY_DOUBLE); - s_sz = sty ? abi_sizeof(g->c->abi, sty) : 0; - d_sz = dty ? abi_sizeof(g->c->abi, dty) : 0; - s_signed = sty ? abi_type_info(g->c->abi, sty).signed_ : 0; - s_ptr = type_is_ptr(sty); - d_ptr = type_is_ptr(dty); - - { - int s_int_or_ptr = s_int || s_ptr; - int d_int_or_ptr = d_int || d_ptr; - if (s_int_or_ptr && d_int_or_ptr) { - if (d_sz < s_sz) { - ck = CV_TRUNC; - } else if (d_sz > s_sz) { - ck = (s_int && s_signed) ? CV_SEXT : CV_ZEXT; - } else { - v.type = dty; - v.op.type = dty; - api_push(g, v); - return; - } - } else if (s_int && d_flt) { - ck = s_signed ? CV_ITOF_S : CV_ITOF_U; - } else if (s_flt && d_int) { - int d_signed = abi_type_info(g->c->abi, dty).signed_; - ck = d_signed ? CV_FTOI_S : CV_FTOI_U; - } else if (s_flt && d_flt) { - ck = (d_sz > s_sz) ? CV_FEXT : CV_FTRUNC; - } else { - ck = CV_BITCAST; - } - } - src = api_force_reg(g, &v, sty); rr = api_alloc_reg_or_spill(g, api_type_class(dty), dty); dst = api_op_reg(rr, dty); @@ -1830,6 +2051,95 @@ void cfree_cg_convert(CfreeCg* g, CfreeCgTypeId dst_type) { api_push(g, api_make_sv(dst, dty)); } +void cfree_cg_int_binop(CfreeCg* g, CfreeCgIntBinOp op, uint32_t flags) { + (void)flags; + api_cg_binop(g, api_map_int_binop(op)); +} + +void cfree_cg_int_unop(CfreeCg* g, CfreeCgIntUnOp op, uint32_t flags) { + (void)flags; + api_cg_unop(g, api_map_int_unop(op)); +} + +void cfree_cg_int_cmp(CfreeCg* g, CfreeCgIntCmpOp op) { + api_cg_cmp(g, api_map_int_cmp(op)); +} + +void cfree_cg_fp_binop(CfreeCg* g, CfreeCgFpBinOp op, uint32_t flags) { + (void)flags; + if (op == CFREE_CG_FP_REM) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: FP remainder is unsupported"); + return; + } + api_cg_binop(g, api_map_fp_binop(op)); +} + +void cfree_cg_fp_unop(CfreeCg* g, CfreeCgFpUnOp op, uint32_t flags) { + (void)flags; + (void)op; + api_cg_unop(g, UO_NEG); +} + +void cfree_cg_fp_cmp(CfreeCg* g, CfreeCgFpCmpOp op) { + api_cg_cmp(g, api_map_fp_cmp(op)); +} + +void cfree_cg_sext(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_SEXT); +} + +void cfree_cg_zext(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_ZEXT); +} + +void cfree_cg_trunc(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_TRUNC); +} + +void cfree_cg_ptr_to_int(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_BITCAST); +} + +void cfree_cg_int_to_ptr(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_BITCAST); +} + +void cfree_cg_bitcast(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_BITCAST); +} + +void cfree_cg_fpext(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_FEXT); +} + +void cfree_cg_fptrunc(CfreeCg* g, CfreeCgTypeId dst) { + api_cg_convert_kind(g, dst, CV_FTRUNC); +} + +void cfree_cg_sint_to_float(CfreeCg* g, CfreeCgTypeId dst, + CfreeCgRounding rounding) { + (void)rounding; + api_cg_convert_kind(g, dst, CV_ITOF_S); +} + +void cfree_cg_uint_to_float(CfreeCg* g, CfreeCgTypeId dst, + CfreeCgRounding rounding) { + (void)rounding; + api_cg_convert_kind(g, dst, CV_ITOF_U); +} + +void cfree_cg_float_to_sint(CfreeCg* g, CfreeCgTypeId dst, + CfreeCgRounding rounding) { + (void)rounding; + api_cg_convert_kind(g, dst, CV_FTOI_S); +} + +void cfree_cg_float_to_uint(CfreeCg* g, CfreeCgTypeId dst, + CfreeCgRounding rounding) { + (void)rounding; + api_cg_convert_kind(g, dst, CV_FTOI_U); +} + /* ============================================================ * Intrinsics (stub) * ============================================================ */ @@ -1838,42 +2148,73 @@ static IntrinKind api_map_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, const Type* result_type) { u32 size = result_type ? abi_sizeof(g->c->abi, result_type) : 0; switch (intrin) { - case CFREE_CG_INTRIN_TRAP: return INTRIN_TRAP; - case CFREE_CG_INTRIN_UNREACHABLE: return INTRIN_UNREACHABLE; - case CFREE_CG_INTRIN_CLZ: return INTRIN_CLZ; - case CFREE_CG_INTRIN_CTZ: return INTRIN_CTZ; - case CFREE_CG_INTRIN_POPCOUNT: return INTRIN_POPCOUNT; + case CFREE_CG_INTRIN_TRAP: + return INTRIN_TRAP; + case CFREE_CG_INTRIN_CLZ: + return INTRIN_CLZ; + case CFREE_CG_INTRIN_CTZ: + return INTRIN_CTZ; + case CFREE_CG_INTRIN_POPCOUNT: + return INTRIN_POPCOUNT; case CFREE_CG_INTRIN_BSWAP: if (size <= 2) return INTRIN_BSWAP16; if (size <= 4) return INTRIN_BSWAP32; return INTRIN_BSWAP64; - case CFREE_CG_INTRIN_SETJMP: return INTRIN_SETJMP; - case CFREE_CG_INTRIN_LONGJMP: return INTRIN_LONGJMP; - case CFREE_CG_INTRIN_ADD_OVERFLOW: return INTRIN_ADD_OVERFLOW; - case CFREE_CG_INTRIN_SUB_OVERFLOW: return INTRIN_SUB_OVERFLOW; - case CFREE_CG_INTRIN_MUL_OVERFLOW: return INTRIN_MUL_OVERFLOW; - 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; + case CFREE_CG_INTRIN_SETJMP: + return INTRIN_SETJMP; + case CFREE_CG_INTRIN_LONGJMP: + return INTRIN_LONGJMP; + case CFREE_CG_INTRIN_SADD_OVERFLOW: + case CFREE_CG_INTRIN_UADD_OVERFLOW: + return INTRIN_ADD_OVERFLOW; + case CFREE_CG_INTRIN_SSUB_OVERFLOW: + case CFREE_CG_INTRIN_USUB_OVERFLOW: + return INTRIN_SUB_OVERFLOW; + case CFREE_CG_INTRIN_SMUL_OVERFLOW: + case CFREE_CG_INTRIN_UMUL_OVERFLOW: + return INTRIN_MUL_OVERFLOW; + 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_FMA: + case CFREE_CG_INTRIN_SYSCALL: + case CFREE_CG_INTRIN_IRQ_SAVE: + case CFREE_CG_INTRIN_IRQ_RESTORE: + case CFREE_CG_INTRIN_IRQ_DISABLE: + case CFREE_CG_INTRIN_IRQ_ENABLE: + case CFREE_CG_INTRIN_DMB: + case CFREE_CG_INTRIN_DSB: + case CFREE_CG_INTRIN_ISB: + case CFREE_CG_INTRIN_DCACHE_CLEAN: + case CFREE_CG_INTRIN_DCACHE_INVALIDATE: + case CFREE_CG_INTRIN_DCACHE_CLEAN_INVALIDATE: + case CFREE_CG_INTRIN_ICACHE_INVALIDATE: + case CFREE_CG_INTRIN_CPU_NOP: + case CFREE_CG_INTRIN_CPU_YIELD: + case CFREE_CG_INTRIN_WFI: + case CFREE_CG_INTRIN_WFE: + case CFREE_CG_INTRIN_SEV: + case CFREE_CG_INTRIN_CORO_SWITCH: + return INTRIN_NONE; } return INTRIN_NONE; } static int api_intrinsic_is_void(CfreeCgIntrinsic intrin) { - return intrin == CFREE_CG_INTRIN_TRAP || - intrin == CFREE_CG_INTRIN_UNREACHABLE || - intrin == CFREE_CG_INTRIN_LONGJMP || + return intrin == CFREE_CG_INTRIN_TRAP || intrin == CFREE_CG_INTRIN_LONGJMP || intrin == CFREE_CG_INTRIN_PREFETCH; } static int api_intrinsic_is_overflow(CfreeCgIntrinsic intrin) { - return intrin == CFREE_CG_INTRIN_ADD_OVERFLOW || - intrin == CFREE_CG_INTRIN_SUB_OVERFLOW || - intrin == CFREE_CG_INTRIN_MUL_OVERFLOW; + return intrin == CFREE_CG_INTRIN_SADD_OVERFLOW || + intrin == CFREE_CG_INTRIN_UADD_OVERFLOW || + intrin == CFREE_CG_INTRIN_SSUB_OVERFLOW || + intrin == CFREE_CG_INTRIN_USUB_OVERFLOW || + intrin == CFREE_CG_INTRIN_SMUL_OVERFLOW || + intrin == CFREE_CG_INTRIN_UMUL_OVERFLOW; } void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, @@ -1927,8 +2268,7 @@ void cfree_cg_intrinsic(CfreeCg* g, CfreeCgIntrinsic intrin, uint32_t nargs, dsts[0] = api_op_reg(rr, vty); dsts[1] = api_op_reg(ok, int_ty); ndst = 2; - } else if (!api_intrinsic_is_void(intrin) && rty && - rty->kind != TY_VOID) { + } else if (!api_intrinsic_is_void(intrin) && rty && rty->kind != TY_VOID) { Reg rr = api_alloc_reg_or_spill(g, api_type_class(rty), rty); dsts[0] = api_op_reg(rr, rty); ndst = 1; @@ -1972,7 +2312,22 @@ static MemAccess api_mem_for_atomic(CfreeCg* g, const Type* val_ty) { return ma; } -void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemOrder order) { +int cfree_cg_atomic_is_legal(CfreeCompiler* c, CfreeCgMemAccess access, + CfreeCgMemOrder order) { + const Type* ty = resolve_type(c, access.type); + (void)order; + if (!ty) return 0; + return abi_sizeof(c->abi, ty) <= 8; +} + +int cfree_cg_atomic_is_lock_free(CfreeCompiler* c, CfreeCgMemAccess access) { + const Type* ty = resolve_type(c, access.type); + if (!ty) return 0; + return abi_sizeof(c->abi, ty) <= (u32)c->target.ptr_size; +} + +void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemAccess access, + CfreeCgMemOrder order) { ApiSValue ptr; const Type *pty, *val_ty; Operand addr, dst; @@ -1980,7 +2335,8 @@ void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemOrder order) { if (!g) return; ptr = api_pop(g); pty = api_sv_type(&ptr); - val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_load"); + val_ty = resolve_type(g->c, access.type); + if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_load"); addr = api_force_reg(g, &ptr, pty); rr = api_alloc_reg_or_spill(g, api_type_class(val_ty), val_ty); dst = api_op_reg(rr, val_ty); @@ -1990,7 +2346,8 @@ void cfree_cg_atomic_load(CfreeCg* g, CfreeCgMemOrder order) { api_push(g, api_make_sv(dst, val_ty)); } -void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemOrder order) { +void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemAccess access, + CfreeCgMemOrder order) { ApiSValue val, ptr; const Type *pty, *val_ty; Operand addr, src; @@ -1998,7 +2355,8 @@ void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemOrder order) { val = api_pop(g); ptr = api_pop(g); pty = api_sv_type(&ptr); - val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_store"); + val_ty = resolve_type(g->c, access.type); + if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_store"); addr = api_force_reg(g, &ptr, pty); src = (val.op.kind == OPK_IMM || val.op.kind == OPK_REG) ? val.op @@ -2009,7 +2367,8 @@ void cfree_cg_atomic_store(CfreeCg* g, CfreeCgMemOrder order) { api_release(g, &ptr); } -void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgAtomicOp op, CfreeCgMemOrder order) { +void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgMemAccess access, + CfreeCgAtomicOp op, CfreeCgMemOrder order) { ApiSValue val, ptr; const Type *pty, *val_ty; Operand addr, vop, dst; @@ -2018,7 +2377,8 @@ void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgAtomicOp op, CfreeCgMemOrder order) val = api_pop(g); ptr = api_pop(g); pty = api_sv_type(&ptr); - val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_rmw"); + val_ty = resolve_type(g->c, access.type); + if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_rmw"); addr = api_force_reg(g, &ptr, pty); vop = (val.op.kind == OPK_IMM || val.op.kind == OPK_REG) ? val.op @@ -2033,18 +2393,21 @@ void cfree_cg_atomic_rmw(CfreeCg* g, CfreeCgAtomicOp op, CfreeCgMemOrder order) api_push(g, api_make_sv(dst, val_ty)); } -void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemOrder success, - CfreeCgMemOrder failure) { +void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemAccess access, + CfreeCgMemOrder success, CfreeCgMemOrder failure, + int weak) { ApiSValue desired, expected, ptr; const Type *pty, *val_ty, *int_ty; Operand addr, exp_op, des_op, prior, ok; Reg pr, kr; if (!g) return; + (void)weak; desired = api_pop(g); expected = api_pop(g); ptr = api_pop(g); pty = api_sv_type(&ptr); - val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_cmpxchg"); + val_ty = resolve_type(g->c, access.type); + if (!val_ty) val_ty = api_atomic_pointee(g, pty, "CfreeCg: atomic_cmpxchg"); int_ty = type_prim(g->c->global, TY_INT); addr = api_force_reg(g, &ptr, pty); exp_op = (expected.op.kind == OPK_IMM || expected.op.kind == OPK_REG) @@ -2059,8 +2422,7 @@ void cfree_cg_atomic_cmpxchg(CfreeCg* g, CfreeCgMemOrder success, ok = api_op_reg(kr, int_ty); g->target->atomic_cas(g->target, prior, ok, addr, exp_op, des_op, api_mem_for_atomic(g, val_ty), - api_map_mem_order(success), - api_map_mem_order(failure)); + api_map_mem_order(success), api_map_mem_order(failure)); api_release(g, &desired); api_release(g, &expected); api_release(g, &ptr); @@ -2119,13 +2481,9 @@ static void api_asm_spill_sv(CfreeCg* g, ApiSValue* sv, Reg phys, api_set_owned_reg(sv, (Reg)REG_NONE); } -void cfree_cg_inline_asm(CfreeCg* g, CfreeSym tmpl, - const CfreeCgAsmOperand* outputs, uint32_t noutputs, - const CfreeCgAsmOperand* inputs, uint32_t ninputs, - const CfreeSym* clobbers, uint32_t nclobbers, - uint32_t flags) { - static const char* const match_strs[10] = { - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; +void cfree_cg_inline_asm(CfreeCg* g, CfreeCgInlineAsm asm_block) { + static const char* const match_strs[10] = {"0", "1", "2", "3", "4", + "5", "6", "7", "8", "9"}; CGTarget* T; Heap* h; const Type* fallback_ty; @@ -2141,7 +2499,15 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeSym tmpl, int has_memory_clobber; uint32_t ninout; uint32_t total_inputs; - (void)flags; + CfreeSym tmpl = asm_block.tmpl; + const CfreeCgAsmOperand* outputs = asm_block.outputs; + uint32_t noutputs = asm_block.noutputs; + const CfreeCgAsmOperand* inputs = asm_block.inputs; + uint32_t ninputs = asm_block.ninputs; + const CfreeSym* clobbers = asm_block.clobbers; + uint32_t nclobbers = asm_block.nclobbers; + (void)asm_block.flags; + (void)asm_block.clobber_abi_sets; if (!g) return; T = g->target; h = g->c->env->heap; @@ -2176,8 +2542,8 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeSym tmpl, ninout++; } } - out_ops = (Operand*)h->alloc(h, sizeof(*out_ops) * noutputs, - _Alignof(Operand)); + out_ops = + (Operand*)h->alloc(h, sizeof(*out_ops) * noutputs, _Alignof(Operand)); memset(out_ops, 0, sizeof(*out_ops) * noutputs); out_reg_owned = (u8*)h->alloc(h, noutputs, 1); memset(out_reg_owned, 0, noutputs); @@ -2272,7 +2638,8 @@ void cfree_cg_inline_asm(CfreeCg* g, CfreeSym tmpl, if (in_svs[i].op.kind == OPK_INDIRECT) { in_ops[i] = in_svs[i].op; } else if (api_is_lvalue_sv(&in_svs[i])) { - const Type* pty = type_ptr(g->c->global, ity ? ity : type_void(g->c->global)); + const Type* pty = + type_ptr(g->c->global, ity ? ity : type_void(g->c->global)); Reg r = api_alloc_reg_or_spill(g, RC_INT, pty); Operand dst = api_op_reg(r, pty); T->addr_of(T, dst, in_svs[i].op); @@ -2438,6 +2805,53 @@ void cfree_cg_branch_false(CfreeCg* g, CfreeCgLabel label) { } } +void cfree_cg_switch(CfreeCg* g, CfreeCgSwitch sw) { + ApiSValue selector; + const Type* ty; + Operand sel; + if (!g) return; + if (g->sp == 0) return; + selector = api_pop(g); + ty = resolve_type(g->c, sw.selector_type); + if (!ty) ty = api_sv_type(&selector); + sel = api_force_reg_unless_imm(g, &selector, ty); + for (u32 i = 0; i < sw.ncases; ++i) { + Operand imm = api_op_imm((i64)sw.cases[i].value, ty); + g->target->cmp_branch(g->target, CMP_EQ, sel, imm, + (Label)sw.cases[i].label); + } + if (sw.default_label != CFREE_CG_LABEL_NONE) { + g->target->jump(g->target, (Label)sw.default_label); + } + api_release(g, &selector); +} + +void cfree_cg_push_label_addr(CfreeCg* g, CfreeCgLabel label, + CfreeCgTypeId ptr_type) { + (void)label; + if (!g) return; + compiler_panic(g->c, g->cur_loc, + "CfreeCg: label addresses are unsupported by CGTarget"); + cfree_cg_push_null(g, ptr_type); +} + +void cfree_cg_computed_goto(CfreeCg* g, const CfreeCgLabel* valid_targets, + uint32_t ntargets) { + ApiSValue target; + (void)valid_targets; + (void)ntargets; + if (!g) return; + target = api_pop(g); + api_release(g, &target); + compiler_panic(g->c, g->cur_loc, + "CfreeCg: computed goto is unsupported by CGTarget"); +} + +void cfree_cg_unreachable(CfreeCg* g) { + if (!g) return; + g->target->intrinsic(g->target, INTRIN_UNREACHABLE, NULL, 0, NULL, 0); +} + /* ============================================================ * Scopes / structured control flow * ============================================================ */ @@ -2447,8 +2861,7 @@ static CfreeCgScope api_scope_handle(u32 idx, u32 generation) { } static ApiCgScope* api_scope_from_handle(CfreeCg* g, CfreeCgScope scope, - int require_top, - const char* who) { + int require_top, const char* who) { u32 slot; u32 generation; ApiCgScope* s; @@ -2721,7 +3134,8 @@ void cfree_cg_continue_false(CfreeCg* g, CfreeCgScope scope) { * Dynamic stack allocation / variadics (stubs) * ============================================================ */ -void cfree_cg_alloca(CfreeCg* g, CfreeCgTypeId result_ptr_type, uint32_t align) { +void cfree_cg_alloca(CfreeCg* g, CfreeCgTypeId result_ptr_type, + uint32_t align) { ApiSValue sz; CGTarget* T; const Type* pty; @@ -2733,7 +3147,8 @@ void cfree_cg_alloca(CfreeCg* g, CfreeCgTypeId result_ptr_type, uint32_t align) sz = api_pop(g); pty = resolve_type(g->c, result_ptr_type); if (!pty) pty = type_ptr(g->c->global, type_void(g->c->global)); - sz_op = (sz.op.kind == OPK_IMM) ? sz.op : api_force_reg(g, &sz, api_sv_type(&sz)); + sz_op = + (sz.op.kind == OPK_IMM) ? sz.op : api_force_reg(g, &sz, api_sv_type(&sz)); rr = api_alloc_reg_or_spill(g, RC_INT, pty); dst = api_op_reg(rr, pty); T->alloca_(T, dst, sz_op, align ? align : 16); @@ -2804,30 +3219,42 @@ void cfree_cg_vararg_copy(CfreeCg* g) { * Memory operations (stubs) * ============================================================ */ -void cfree_cg_memcpy(CfreeCg* g, uint32_t size, uint32_t align) { +void cfree_cg_memcpy(CfreeCg* g, uint64_t size, CfreeCgMemAccess dst_access, + CfreeCgMemAccess src_access) { ApiSValue src, dst; CGTarget* T; AggregateAccess agg; Operand dst_op, src_op; if (!g) return; + (void)src_access; + if (size > UINT32_MAX) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: memcpy size exceeds CGTarget"); + return; + } T = g->target; src = api_pop(g); dst = api_pop(g); dst_op = api_force_reg(g, &dst, api_sv_type(&dst)); src_op = api_force_reg(g, &src, api_sv_type(&src)); memset(&agg, 0, sizeof agg); - agg.size = size; - agg.align = align ? align : size; + agg.size = (u32)size; + agg.align = dst_access.align ? dst_access.align : (u32)size; T->copy_bytes(T, dst_op, src_op, agg); api_release(g, &dst); api_release(g, &src); } -void cfree_cg_memmove(CfreeCg* g, uint32_t size, uint32_t align) { +void cfree_cg_memmove(CfreeCg* g, uint64_t size, CfreeCgMemAccess dst_access, + CfreeCgMemAccess src_access) { ApiSValue src, dst; Operand args[3]; if (!g) return; - (void)align; + (void)dst_access; + (void)src_access; + if (size > INT64_MAX) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: memmove size exceeds CGTarget"); + return; + } src = api_pop(g); dst = api_pop(g); args[0] = api_force_reg(g, &dst, api_sv_type(&dst)); @@ -2838,24 +3265,29 @@ void cfree_cg_memmove(CfreeCg* g, uint32_t size, uint32_t align) { api_release(g, &src); } -void cfree_cg_memset(CfreeCg* g, uint8_t val, uint32_t size, uint32_t align) { +void cfree_cg_memset(CfreeCg* g, uint8_t val, uint64_t size, + CfreeCgMemAccess dst_access) { ApiSValue dst; CGTarget* T; AggregateAccess agg; Operand dst_op, byte_val; if (!g) return; + if (size > UINT32_MAX) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: memset size exceeds CGTarget"); + return; + } T = g->target; dst = api_pop(g); dst_op = api_force_reg(g, &dst, api_sv_type(&dst)); byte_val = api_op_imm((i64)val, NULL); memset(&agg, 0, sizeof agg); - agg.size = size; - agg.align = align ? align : size; + agg.size = (u32)size; + agg.align = dst_access.align ? dst_access.align : (u32)size; T->set_bytes(T, dst_op, byte_val, agg); api_release(g, &dst); } -void cfree_cg_index(CfreeCg* g, uint32_t offset) { +void cfree_cg_index(CfreeCg* g, uint64_t offset) { ApiSValue idx, base; CGTarget* T; const Type *base_ty, *base_ptr_ty, *elem_ty, *idx_ty; @@ -2864,6 +3296,10 @@ void cfree_cg_index(CfreeCg* g, uint32_t offset) { Operand base_op, idx_op, result; Reg rr; if (!g) return; + if (offset > INT64_MAX) { + compiler_panic(g->c, g->cur_loc, "CfreeCg: index offset too large"); + return; + } T = g->target; idx = api_pop(g); base = api_pop(g); @@ -2897,7 +3333,8 @@ void cfree_cg_index(CfreeCg* g, uint32_t offset) { result = api_op_reg(rr, base_ptr_ty); if (idx_op.kind == OPK_IMM) { i64 total_offset = idx_op.v.imm * (i64)elemsz + (i64)offset; - T->binop(T, BO_IADD, result, base_op, api_op_imm(total_offset, base_ptr_ty)); + T->binop(T, BO_IADD, result, base_op, + api_op_imm(total_offset, base_ptr_ty)); } else { Reg sr = api_alloc_reg_or_spill(g, RC_INT, idx_ty); Operand scaled = api_op_reg(sr, idx_ty); @@ -2930,8 +3367,7 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { api_ensure_reg(g, &base); rec_ty = api_sv_type(&base); if (!api_is_lvalue_sv(&base)) { - compiler_panic(g->c, g->cur_loc, - "CfreeCg: field base is not an lvalue"); + compiler_panic(g->c, g->cur_loc, "CfreeCg: field base is not an lvalue"); return; } layout = abi_record_layout(g->c->abi, rec_ty); @@ -2948,12 +3384,11 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { rec_ptr_ty = type_ptr(g->c->global, rec_ty); field_offset = layout->fields[field_index].offset; if (base.op.kind == OPK_GLOBAL) { - result = api_op_global(base.op.v.global.sym, - base.op.v.global.addend + (i64)field_offset, - field_ty); + result = + api_op_global(base.op.v.global.sym, + base.op.v.global.addend + (i64)field_offset, field_ty); api_push(g, api_make_lv(result, field_ty)); - } else if (base.op.kind == OPK_INDIRECT && - field_offset <= (u32)INT32_MAX && + } else if (base.op.kind == OPK_INDIRECT && field_offset <= (u32)INT32_MAX && base.op.v.ind.ofs <= INT32_MAX - (i32)field_offset) { result = api_op_indirect(base.op.v.ind.base, base.op.v.ind.ofs + (i32)field_offset, field_ty); @@ -2973,21 +3408,17 @@ void cfree_cg_field(CfreeCg* g, uint32_t field_index) { api_op_imm((i64)field_offset, rec_ptr_ty)); T->free_reg(T, base_addr.v.reg, RC_INT); } - api_push(g, api_make_lv(api_op_indirect(result.v.reg, 0, field_ty), - field_ty)); + api_push(g, + api_make_lv(api_op_indirect(result.v.reg, 0, field_ty), field_ty)); } } -void cfree_cg_field_addr(CfreeCg* g, uint32_t field_index) { - cfree_cg_field(g, field_index); - cfree_cg_addr(g); -} - /* ============================================================ * Calls / return * ============================================================ */ -void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { +void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type, + CfreeCgCallAttrs attrs) { CGTarget* T; const Type* fty; const ABIFuncInfo* abi; @@ -2996,13 +3427,16 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { CGABIValue* avs; CGCallDesc desc; ApiSValue callee; + int tail; if (!g) return; + tail = + attrs.tail == CFREE_CG_TAIL_ALLOWED || attrs.tail == CFREE_CG_TAIL_MUST; T = g->target; fty = resolve_type(g->c, fn_type); if (!fty) return; abi = abi_func_info(g->c->abi, fty); ret_ty = fty->fn.ret; - has_result = ret_ty && ret_ty->kind != TY_VOID; + has_result = !tail && ret_ty && ret_ty->kind != TY_VOID; if (g->sp < (u32)nargs + 1u) { compiler_panic(g->c, g->cur_loc, "CfreeCg: call stack underflow"); @@ -3055,7 +3489,7 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { desc.callee = callee_op; desc.args = avs; desc.nargs = nargs; - desc.flags = CG_CALL_NONE; + desc.flags = tail ? CG_CALL_TAIL : CG_CALL_NONE; desc.ret.type = ret_ty; desc.ret.abi = &abi->ret; @@ -3101,7 +3535,10 @@ void cfree_cg_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { } } -void cfree_cg_tail_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) { +static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, CfreeCgTypeId fn_type) + __attribute__((unused)); +static void api_cg_tail_call(CfreeCg* g, uint32_t nargs, + CfreeCgTypeId fn_type) { CGTarget* T; const Type* fty; const ABIFuncInfo* abi; @@ -3153,7 +3590,7 @@ 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) { + CfreeCgCallAttrs attrs) { CGTarget* T; const Type* fty; const ABIFuncInfo* abi; @@ -3163,6 +3600,8 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, CGCallDesc desc; Operand callee_op; if (!g) return; + int tail = + attrs.tail == CFREE_CG_TAIL_ALLOWED || attrs.tail == CFREE_CG_TAIL_MUST; T = g->target; fty = api_sym_type(g, sym); if (!fty) return; @@ -3246,12 +3685,9 @@ static void api_call_symbol_common(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, } } -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_call_symbol(CfreeCg* g, CfreeCgSym sym, uint32_t nargs, + CfreeCgCallAttrs attrs) { + api_call_symbol_common(g, sym, nargs, attrs); } void cfree_cg_ret(CfreeCg* g) { @@ -3305,7 +3741,7 @@ void cfree_cg_data_begin(CfreeCg* g, CfreeCgSym cg_sym, u16 sec_flags; Sym sec_name_sym; ObjSecId sec; - CfreeCgDeclAttrs decl_attrs; + CfreeCgDecl decl_attrs; if (!g) return; c = g->c; ob = g->obj; @@ -3349,7 +3785,7 @@ void cfree_cg_data_common(CfreeCg* g, CfreeCgSym cg_sym, uint64_t size, uint32_t align) { ObjSym* osym; ObjSymId sym; - CfreeCgDeclAttrs decl_attrs; + CfreeCgDecl decl_attrs; if (!g || cg_sym == CFREE_CG_SYM_NONE) return; sym = (ObjSymId)cg_sym; osym = (ObjSym*)obj_symbol_get(g->obj, sym); @@ -3472,10 +3908,25 @@ static void api_cg_data_reloc(CfreeCg* g, CfreeCgSym target, int64_t addend, } void cfree_cg_data_addr(CfreeCg* g, CfreeCgSym target, int64_t addend, - uint32_t width) { + uint32_t width, uint32_t address_space) { + (void)address_space; api_cg_data_reloc(g, target, addend, width, 0); } +void cfree_cg_data_label_addr(CfreeCg* g, CfreeCgLabel target, int64_t addend, + uint32_t width, uint32_t address_space) { + u8 pad[8]; + (void)target; + (void)addend; + (void)address_space; + if (!g || !width || width > sizeof(pad)) return; + compiler_panic(g->c, g->cur_loc, + "CfreeCg: data label addresses are unsupported by ObjBuilder"); + memset(pad, 0, sizeof(pad)); + obj_write(g->obj, g->data_sec, pad, width); + g->data_size += width; +} + void cfree_cg_data_pcrel(CfreeCg* g, CfreeCgSym target, int64_t addend, uint32_t width) { api_cg_data_reloc(g, target, addend, width, 1); diff --git a/src/api/lifecycle.c b/src/api/lifecycle.c @@ -3,6 +3,7 @@ * don't drag in the full compile/link pipeline through the linker. */ #include <cfree.h> +#include <cfree/cg.h> #include <string.h> #include "core/core.h" @@ -49,6 +50,29 @@ CfreeSym cfree_sym_intern(CfreeCompiler* c, const char* str) { return pool_intern_cstr(c->global, str); } +CfreeSym cfree_cg_c_linkage_name(CfreeCompiler* c, CfreeSym source_name) { + const char* name; + size_t len; + char* buf; + CfreeSym out; + Heap* h; + + if (!c || !source_name) return 0; + name = pool_str(c->global, (Sym)source_name, &len); + if (!name) return 0; + if (c->target.obj != CFREE_OBJ_MACHO) return source_name; + + h = (Heap*)c->env->heap; + buf = (char*)h->alloc(h, len + 2u, 1); + if (!buf) return 0; + buf[0] = '_'; + if (len) memcpy(buf + 1, name, len); + buf[len + 1u] = '\0'; + out = pool_intern(c->global, buf, (u32)(len + 1u)); + h->free(h, buf, len + 2u); + return out; +} + int cfree_register_frontend(CfreeCompiler* c, CfreeLanguage lang, CfreeCompileFn fn) { if (!c || lang >= CFREE_LANG_COUNT) return 1;