29 static int integer_fits_longlong(
const mpz_t value)
33 mpz_init_set_si(max, 2);
34 mpz_pow_ui(max, max,
sizeof(
long long) * CHAR_BIT - 1);
35 mpz_sub_ui(max, max, 1);
38 mpz_init_set_si(min, 2);
39 mpz_pow_ui(min, min,
sizeof(
long long) * CHAR_BIT - 1);
43 return mpz_cmp(value, max) <= 0 && mpz_cmp(value, min) >= 0;
46 static int integer_is_unsigned(
const mpz_t value)
48 return mpz_sgn(value) >= 0;
64 io_t *io =
fs_open(emit->
fs, it, eOsAccessWrite | eOsAccessTruncate);
75 io_t *io =
fs_open(emit->
fs, it, eOsAccessWrite | eOsAccessTruncate);
83 if (emit->
layout == eFileLayoutPair)
94 if (emit->
layout == eFileLayoutPair)
117 static const char *format_path(
const char *base,
const char *name,
arena_t *arena)
120 return str_format(arena,
"%s/%s", base, name);
126 for (
size_t i = 0; i < len; i++)
133 static void cplusplus_prelude(
io_t *io)
136 "#ifdef __cplusplus\n"
142 static void cplusplus_epilogue(
io_t *io)
145 "#ifdef __cplusplus\n"
157 io_t *src =
fs_open(emit->
fs,
"module.c", eOsAccessWrite | eOsAccessTruncate);
158 io_t *hdr =
fs_open(emit->
fs,
"module.h", eOsAccessWrite | eOsAccessTruncate);
165 io_printf(src,
"#include \"module.h\"\n");
168 io_printf(hdr,
"#include <stdbool.h>\n");
172 cplusplus_prelude(hdr);
185 cplusplus_epilogue(hdr->
io);
194 collect_deps(emit, mod, mod->
globals);
200 const char *src_file = format_path(path, mod->
name, emit->
arena);
201 const char *hdr_file = format_path(path, mod->
name, emit->
arena);
213 cplusplus_prelude(hdr->
io);
215 io_printf(src->
io,
"#include \"%s.h\"\n", hdr_file);
224 case eLinkImport:
return "extern ";
225 case eLinkModule:
return "static ";
232 default:
CT_NEVER(
"unknown linkage %d", linkage);
239 for (
size_t i = 0; i < len; i++)
243 if (deps == NULL) {
continue; }
266 get_required_headers(emit, requires, mod, mod->
globals);
267 get_required_headers(emit, requires, mod, mod->
functions);
283 case eLinkEntryCli:
return "main";
284 case eLinkEntryGui:
return "WinMain";
290 if (symbol->
name == NULL)
301 return link == eLinkEntryCli || link == eLinkEntryGui;
311 if (mpz_fits_sint_p(value))
312 return mpz_get_str(NULL, 10, value);
314 if (integer_fits_longlong(value))
315 return str_format(arena,
"%sll", mpz_get_str(NULL, 10, value));
318 if (integer_is_unsigned(value))
319 return str_format(arena,
"%sull", mpz_get_str(NULL, 10, value));
321 CT_NEVER(
"integer literal %s is too large, this should be caught earlier", mpz_get_str(NULL, 10, value));
341 io_printf(io,
"enum %s_cases_t { /* %zu cases */\n", type->
name, len);
346 else for (
size_t i = 0; i < len; i++)
356 static void c89_proto_aggregate(
io_t *io,
const char *ty,
const char *name)
366 c89_proto_aggregate(io,
"struct", type->
name);
369 c89_proto_aggregate(io,
"union", type->
name);
373 define_enum(io, type, emit);
385 const char *link = format_c89_link(global->
linkage);
397 write_global(emit, io, global);
403 write_global(emit, io, global);
411 if (is_entry_point(symbol->
linkage)) {
return; }
417 CTASSERTF(type->
kind == eTypeClosure,
"expected closure type on %s, got %d", symbol->
name, type->
kind);
421 const char *result = format_symbol(emit, closure.
result, mangle_symbol_name(emit, symbol));
423 const char *link = format_c89_link(symbol->
linkage);
426 io_printf(dst,
"%s%s(%s);\n", link, result, params);
432 for (
size_t i = 0; i < len; i++)
435 fn(emit, mod, symbol);
442 for (
size_t i = 0; i < len; i++)
453 for (
size_t i = 0; i <
vector_len(modules); i++)
456 proto_module_types(emit, header->
io, mod->
types);
463 for (
size_t i = 0; i < len; i++)
473 for (
size_t i = 0; i < len; i++)
482 emit_required_headers(emit, mod);
485 proto_module_types(emit, hdr, mod->
types);
495 switch (operand.
kind)
501 case eOperandLocal: {
505 case eOperandParam: {
509 case eOperandGlobal: {
513 case eOperandFunction: {
524 default:
CT_NEVER(
"unknown operand kind %d", operand.
kind);
538 return format_symbol(emit, type,
id);
543 const ssa_type_t *type = get_operand_type(emit, operand);
544 return c89_name_vreg(emit, step, type);
562 const ssa_type_t *type = get_operand_type(emit, operand);
563 return c89_name_vreg(emit, step, get_reg_type(type));
568 const ssa_type_t *type = get_operand_type(emit, operand);
576 if (value->
value == eValueRelative)
586 for (
size_t i = 0; i < len; i++)
589 const char *it = c89_format_value(emit, element);
593 char *joined =
str_join(
", ", result, arena);
599 if (value->
value == eValueLiteral)
605 if (value->
value == eValueRelative)
622 return format_integer_value(emit->
arena, value);
623 case eTypePointer:
return c89_format_pointer(emit, value);
624 case eTypeOpaque:
return c89_format_opaque(emit, value);
631 if (local->
name != NULL)
637 static const char *c89_format_local(
c89_emit_t *emit,
size_t local)
643 return get_local_name(emit, it);
646 static const char *c89_format_param(
c89_emit_t *emit,
size_t param)
657 switch (operand.
kind)
659 case eOperandEmpty:
return "/* empty */";
661 return c89_format_value(emit, operand.
value);
670 return mangle_symbol_name(emit, operand.
global);
672 case eOperandFunction:
673 return mangle_symbol_name(emit, operand.
function);
676 return c89_format_local(emit, operand.
local);
679 return c89_format_param(emit, operand.
param);
681 default:
CT_NEVER(
"unknown operand kind %d", operand.
kind);
687 return operand.
kind == eOperandEmpty;
692 if (operand.
kind == eOperandImm)
696 return type->
kind == eTypeUnit || type->
kind == eTypeEmpty;
699 return operand.
kind == eOperandEmpty;
706 const ssa_type_t *type = get_operand_type(emit, symbol);
709 const char *step_name = c89_name_vreg(emit, step, ptr);
711 io_printf(io,
"\t%s = &(%s); /* %s */\n",
713 c89_format_operand(emit, addr.
symbol),
721 io_printf(io,
"\t%s = &%s[%s]; /* (array = %s, offset = %s) */\n",
722 c89_name_vreg_by_operand(emit, step, offset.
array),
723 c89_format_operand(emit, offset.
array),
724 c89_format_operand(emit, offset.
offset),
725 operand_type_string(emit, offset.
array),
726 operand_type_string(emit, offset.
offset)
754 c89_format_operand(emit, member.
object),
763 for (
size_t i = 0; i < len; i++)
773 const char *name = c89_name_vreg(emit, step, value->
type);
774 io_printf(io,
"\t%s = %s;\n", name, c89_format_value(emit, value));
780 c89_format_operand(emit, store.
dst),
781 c89_format_operand(emit, store.
src)
788 c89_name_vreg(emit, step, cast.
type),
789 format_symbol(emit, cast.
type, NULL),
790 c89_format_operand(emit, cast.
operand)
797 c89_name_load_vreg_by_operand(emit, step, load.
src),
798 c89_format_operand(emit, load.
src)
804 c89_write_address(emit, io, step);
807 c89_write_offset(emit, io, step);
810 c89_write_member(emit, io, step);
816 c89_name_vreg_by_operand(emit, step, unary.
operand),
818 c89_format_operand(emit, unary.
operand)
825 c89_name_vreg_by_operand(emit, step, bin.
lhs),
826 c89_format_operand(emit, bin.
lhs),
828 c89_format_operand(emit, bin.
rhs)
835 c89_name_vreg(emit, step,
ssa_type_bool(
"bool", eQualConst)),
836 c89_format_operand(emit, cmp.
lhs),
838 c89_format_operand(emit, cmp.
rhs)
852 for (
size_t arg_idx = 0; arg_idx < args_len; arg_idx++)
855 vector_set(args, arg_idx, (
char*)c89_format_operand(emit, *operand));
860 if (result->
kind != eTypeEmpty && result->
kind != eTypeUnit)
862 io_printf(io,
"%s = ", c89_name_vreg(emit, step, result));
866 c89_format_operand(emit, call.
function),
879 io_printf(io,
"\tif (%s) { goto %s; }", c89_format_operand(emit, br.
cond), c89_format_operand(emit, br.
then));
880 if (!operand_is_empty(br.
other))
882 io_printf(io,
" else { goto %s; }", c89_format_operand(emit, br.
other));
889 if (!operand_cant_return(ret.
value))
891 io_printf(io,
"\treturn %s;\n", c89_format_operand(emit, ret.
value));
902 c89_name_vreg(emit, step,
ssa_type_digit(
"size_t", eQualConst, eSignUnsigned, eDigitSize)),
909 c89_name_vreg(emit, step,
ssa_type_digit(
"size_t", eQualConst, eSignUnsigned, eDigitSize)),
917 io_printf(io,
"\t%s = offsetof(%s, %s);\n",
918 c89_name_vreg(emit, step,
ssa_type_digit(
"size_t", eQualConst, eSignUnsigned, eDigitSize)),
938 for (
size_t i = 0; i < len; i++)
951 define_record(emit,
"struct", io, type);
954 define_record(emit,
"union", io, type);
965 const char *init = c89_format_value(emit, value);
967 if (type->
kind == eTypePointer)
981 if (symbol->
linkage != eLinkImport)
984 write_global(emit, src, symbol);
987 write_init(emit, src, value);
994 static bool is_type_pointer(
const ssa_type_t *type)
996 return type->
kind == eTypePointer || type->
kind == eTypeOpaque || type->
kind == eTypeClosure;
1002 for (
size_t i = 0; i < len; i++)
1005 const char *name = get_local_name(emit, local);
1011 if (!is_type_pointer(storage.
type))
1025 CTASSERTF(type->
kind == eTypeClosure,
"expected closure type on %s, got %d", symbol->
name, type->
kind);
1031 const char *result = format_symbol(emit, closure.
result, mangle_symbol_name(emit, symbol));
1033 const char *link = format_c89_link(symbol->
linkage);
1035 if (symbol->
linkage != eLinkImport)
1037 io_printf(src,
"%s%s(%s) {\n", link, result, params);
1038 write_locals(emit, src, symbol->
locals);
1041 for (
size_t i = 0; i < len; i++)
1044 c89_write_block(emit, src, bb);
1053 static void define_symbols(
1061 for (
size_t i = 0; i < len; i++)
1065 fn(emit, mod, symbol);
1075 if (type->
kind == eTypeStruct || type->
kind == eTypeUnion)
1080 for (
size_t i = 0; i < len; i++)
1083 define_type_ordererd(emit, io, field->
type);
1093 for (
size_t i = 0; i < len; i++)
1096 define_type_ordererd(emit, io, type);
1103 c89_define_types(emit, hdr, mod->
types);
1107 cplusplus_epilogue(hdr);
1113 for (
size_t i = 0; i < len; i++)
1123 for (
size_t i = 0; i < len; i++)
1133 for (
size_t i = 0; i < len; i++)
1151 .reports = runtime->
logger,
1169 if (emit->
layout == eFileLayoutPair)
1171 c89_begin_all(&ctx);
1173 c89_proto_all_types(&ctx, modules);
1174 c89_proto_all_globals(&ctx, modules);
1175 c89_proto_all_functions(&ctx, modules);
1177 c89_define_all_types(&ctx, modules);
1178 c89_define_all_globals(&ctx, modules);
1179 c89_define_all_functions(&ctx, modules);
1185 for (
size_t i = 0; i < len; i++)
1188 c89_begin_module(&ctx, mod);
1191 for (
size_t i = 0; i < len; i++)
1194 c89_proto_module(&ctx, mod);
1197 for (
size_t i = 0; i < len; i++)
1200 c89_define_module(&ctx, mod);
const char * c89_format_type(c89_emit_t *emit, const ssa_type_t *type, const char *name, type_format_t flags)
const char * c89_format_storage(c89_emit_t *emit, ssa_storage_t storage, const char *name, type_format_t flags)
const char * c89_format_params(c89_emit_t *emit, typevec_t *params, bool variadic)
CT_NODISCARD STA_RET_STRING CT_OS_API char * os_error_string(os_error_t error, arena_t *arena)
convert an os error code to a string
io_t * c89_get_source_io(c89_emit_t *emit, const ssa_module_t *mod)
c89_source_t * c89_get_source(c89_emit_t *emit, const ssa_module_t *mod)
emit_result_t cfamily_ssa(target_runtime_t *runtime, const ssa_result_t *ssa, target_emit_t *emit)
c89_source_t * c89_get_header(c89_emit_t *emit, const ssa_module_t *mod)
io_t * c89_get_header_io(c89_emit_t *emit, const ssa_module_t *mod)
void c89_define_type(c89_emit_t *emit, io_t *io, const ssa_type_t *type)
void c89_proto_global(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *global)
void c89_proto_type(c89_emit_t *emit, io_t *io, const ssa_type_t *type)
void c89_proto_function(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
void c89_define_function(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
void c89_define_global(c89_emit_t *emit, const ssa_module_t *mod, const ssa_symbol_t *symbol)
char * c89_format_integer_literal(arena_t *arena, const mpz_t value)
CT_NODISCARD CT_PUREFN CT_BASE_API size_t ctu_strlen(const char *str)
get the length of a string not including the null terminator equivalent to strlen but with safety che...
CT_NODISCARD CT_FS_API io_t * fs_open(fs_t *fs, const char *path, os_access_t flags)
open a file at a given location in the filesystem
CT_FS_API void fs_file_create(fs_t *fs, const char *path)
create a file
CT_NODISCARD CT_STD_API map_t * map_optimal(size_t size, hash_info_t info, arena_t *arena)
create a new map with an optimal size
CT_STD_API void map_reset(map_t *map)
clear all key-value pairs from a map
CT_STD_API void map_set(map_t *map, const void *key, void *value)
set a key-value pair in a map
CT_NODISCARD CT_PUREFN CT_STD_API void * map_get(const map_t *map, const void *key)
get a value from a map
CT_NODISCARD CT_STD_API set_t * set_new(size_t size, hash_info_t info, arena_t *arena)
create a new set
CT_STD_API const void * set_add(set_t *set, const void *key)
add a key to a set
CT_NODISCARD CT_PUREFN CT_STD_API set_iter_t set_iter(set_t *set)
acquire a set iterator for a set
CT_NODISCARD CT_STD_API const void * set_next(set_iter_t *iter)
get the next item from a set iterator
CT_NODISCARD CT_PUREFN CT_STD_API bool set_contains(const set_t *set, const void *key)
check if a set contains a key
CT_NODISCARD CT_PUREFN CT_STD_API bool set_has_next(set_iter_t *iter)
check if a set iterator has more items
CT_NODISCARD CT_IO_API os_error_t io_error(const io_t *io)
get the last error from the io object
CT_IO_API os_error_t io_close(INOUT_NOTNULL io_t *io)
destroy an IO object
CT_IO_API size_t io_printf(io_t *io, STA_FORMAT_STRING const char *fmt,...)
printf to an io object
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
#define CT_NEVER(...)
assert that a code path is never reached
#define CTASSERT(expr)
assert a condition, prints the condition as a message
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
CT_CONSTFN CT_NODISCARD CT_SSA_API const char * ssa_type_name(STA_IN_RANGE(0, eTypeCount - 1) ssa_kind_t kind)
CT_CONSTFN CT_NODISCARD CT_SSA_API const char * ssa_opcode_name(STA_IN_RANGE(0, eOpCount - 1) ssa_opcode_t opcode)
CT_SSA_API bool ssa_value_get_bool(const ssa_value_t *value)
CT_SSA_API ssa_type_t * ssa_type_bool(const char *name, tree_quals_t quals)
CT_SSA_API ssa_type_t * ssa_type_pointer(const char *name, tree_quals_t quals, ssa_type_t *pointer, size_t length)
CT_SSA_API void ssa_value_get_digit(const ssa_value_t *value, OUT_NOTNULL mpz_t result)
CT_SSA_API ssa_type_t * ssa_type_digit(const char *name, tree_quals_t quals, sign_t sign, digit_t digit)
CT_SSA_API ssa_literal_value_t ssa_value_get_literal(const ssa_value_t *value)
CT_NODISCARD CT_STD_API char * str_join(const char *sep, const vector_t *parts, arena_t *arena)
join strings
CT_TREE_API const char * binary_symbol(binary_t op)
get the C symbol of a binary operator
CT_TREE_API const char * unary_symbol(unary_t op)
get the C symbol of a unary operator
CT_TREE_API const char * compare_symbol(compare_t op)
get the C symbol of a comparison operator
tree_linkage_t
the linkage of a declaration
CT_STD_API const hash_info_t kTypeInfoPtr
type information for a generic pointer this operates on the pointer itself and not the data it points...
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
CT_NODISCARD CT_STD_API vector_t * vector_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
CT_NODISCARD CT_STD_API vector_t * vector_of(size_t len, arena_t *arena)
create a new vector with a specified length
CT_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
CT_STD_API void vector_set(vector_t *vector, size_t index, void *value)
set a value in a vector
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
const ssa_symbol_t * current
vector_t * types
vector<ssa_type_t> all types used by this module
vector_t * functions
vector<ssa_symbol_t> all functions declared/imported/exported by this module
vector_t * globals
vector<ssa_symbol_t> all globals declared/imported/exported by this module
const ssa_value_t * value
const ssa_block_t * vreg_context
const ssa_symbol_t * function
const ssa_symbol_t * global
const ssa_value_t * value
ssa underlying storage type
tree_quals_t quals
the qualifiers of the storage
const ssa_type_t * type
the internal storage type
ssa_block_t * entry
entry block
const ssa_type_t * type
the public facing type of this symbol
vector_t * blocks
vector_t<ssa_block_t *>
ssa_storage_t storage
the backing storage for this symbol
tree_visibility_t visibility
typevec_t * params
typevec_t<ssa_type_t>
const char * linkage_string
external name
const ssa_value_t * value
the value of this symbol, must always be set for globals
typevec_t * locals
typevec_t<ssa_type_t>
const char * name
internal name
const ssa_type_t * result
const ssa_type_t * pointer
ssa_type_closure_t closure
ssa_type_pointer_t pointer
ssa_literal_value_t literal
bool init
whether this value has been initialized
ssa_relative_value_t relative
A vector with a fixed type size.
a generic vector of pointers
char * get_anon_symbol_name(emit_t *emit, const ssa_symbol_t *symbol, const char *prefix)
void counter_reset(emit_t *emit)
names_t names_new(size_t size, arena_t *arena)
char * begin_module(emit_t *emit, fs_t *fs, const ssa_module_t *mod)
char * get_step_name(emit_t *emit, const ssa_step_t *step)
char * get_anon_local_name(emit_t *emit, const ssa_local_t *local, const char *prefix)
char * get_block_name(emit_t *emit, const ssa_block_t *block)
char * get_step_from_block(emit_t *emit, const ssa_block_t *block, size_t index)
const char * type_to_string(const ssa_type_t *type, arena_t *arena)
const ssa_symbol_t * symbol