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