Translating functions into C, and the calling conventions needed for them.
void CFunctionModel::initialise(code_generation_target *cgt) { METHOD_ADD(cgt, BEGIN_FUNCTION_MTID, CFunctionModel::begin_function); METHOD_ADD(cgt, DECLARE_LOCAL_VARIABLE_MTID, CFunctionModel::declare_local_variable); METHOD_ADD(cgt, BEGIN_FUNCTION_CODE_MTID, CFunctionModel::begin_function_code); METHOD_ADD(cgt, PLACE_LABEL_MTID, CFunctionModel::place_label); METHOD_ADD(cgt, END_FUNCTION_MTID, CFunctionModel::end_function); METHOD_ADD(cgt, FUNCTION_CALL_MTID, CFunctionModel::function_call); } typedef struct C_generation_function_model_data { struct text_stream *prototype; int argument_count; struct final_c_function *current_fcf; int compiling_function; } C_generation_function_model_data; void CFunctionModel::initialise_data(code_generation *gen) { C_GEN_DATA(fndata.prototype) = Str::new(); C_GEN_DATA(fndata.argument_count) = 0; C_GEN_DATA(fndata.current_fcf) = NULL; C_GEN_DATA(fndata.compiling_function) = FALSE; } void CFunctionModel::begin(code_generation *gen) { CFunctionModel::initialise_data(gen); generated_segment *saved = CodeGen::select(gen, c_stubs_at_eof_I7CGS); text_stream *OUT = CodeGen::current(gen); WRITE("void i7_initializer(void);\n"); WRITE("void i7_initialise_header(void);\n"); WRITE("void i7_initialise_streams(void (*receiver)(int id, wchar_t c));\n"); WRITE("int begin_execution(void (*receiver)(int id, wchar_t c)) { i7_initializer(); i7_initialise_header(); i7_initialise_streams(receiver); "); WRITE("fn_"); CNamespace::mangle(NULL, OUT, I"Main"); WRITE("(0); return 0; }\n"); CodeGen::deselect(gen, saved); } void CFunctionModel::end(code_generation *gen) { generated_segment *saved = CodeGen::select(gen, c_globals_array_I7CGS); text_stream *OUT = CodeGen::current(gen); WRITE("#ifdef i7_defined_i7_mgl_I7S_Comp\n"); WRITE("#ifndef fn_i7_mgl_I7S_Comp\n"); WRITE("i7val fn_i7_mgl_I7S_Comp(int argc, i7val a1, i7val a2, i7val a3, i7val a4, i7val a5) {\n"); WRITE(" return i7_call_5(i7_mgl_I7S_Comp, a1, a2, a3, a4, a5);\n"); WRITE("}\n"); WRITE("#endif\n"); WRITE("#endif\n"); WRITE("#ifdef i7_defined_i7_mgl_I7S_Swap\n"); WRITE("#ifndef fn_i7_mgl_I7S_Swap\n"); WRITE("i7val fn_i7_mgl_I7S_Swap(int argc, i7val a1, i7val a2, i7val a3) {\n"); WRITE(" return i7_call_3(i7_mgl_I7S_Swap, a1, a2, a3);\n"); WRITE("}\n"); WRITE("#endif\n"); WRITE("#endif\n"); CodeGen::deselect(gen, saved); saved = CodeGen::select(gen, c_fundamental_types_I7CGS); OUT = CodeGen::current(gen); WRITE("i7val i7_gen_call(i7val fn_ref, i7val *args, int argc);\n"); CodeGen::deselect(gen, saved); saved = CodeGen::select(gen, c_stubs_at_eof_I7CGS); OUT = CodeGen::current(gen); WRITE("i7val i7_gen_call(i7val fn_ref, i7val *args, int argc) {\n"); INDENT; WRITE("int ssp = i7_asm_stack_pointer;\n"); WRITE("i7val rv = 0;\n"); WRITE("switch (fn_ref) {\n"); INDENT; WRITE("case 0: rv = 0; break;\n"); final_c_function *fcf; LOOP_OVER(fcf, final_c_function) { WRITE("case "); CNamespace::mangle(NULL, OUT, fcf->identifier_as_constant); WRITE(": "); if (fcf->uses_vararg_model) { WRITE("for (int i=argc-1; i>=0; i--) i7_push(args[i]); "); } WRITE("rv = fn_"); CNamespace::mangle(NULL, OUT, fcf->identifier_as_constant); WRITE("("); if (fcf->uses_vararg_model) { WRITE("2, argc"); for (int i=0; i<fcf->max_arity - 1; i++) WRITE(", 0"); } else { WRITE("argc"); for (int i=0; i<fcf->max_arity; i++) WRITE(", args[%d]", i); } WRITE("); break;\n"); } WRITE("default: printf(\"function %%d not found\\n\", fn_ref); break;\n"); OUTDENT; WRITE("}\n"); WRITE("i7_asm_stack_pointer = ssp;\n"); WRITE("return rv;\n"); OUTDENT; WRITE("}\n"); CodeGen::deselect(gen, saved); } typedef struct final_c_function { struct text_stream *identifier_as_constant; int uses_vararg_model; int max_arity; CLASS_DEFINITION } final_c_function; final_c_function *CFunctionModel::new_fcf(text_stream *unmangled_name) { final_c_function *fcf = CREATE(final_c_function); fcf->max_arity = 0; fcf->uses_vararg_model = FALSE; fcf->identifier_as_constant = Str::duplicate(unmangled_name); return fcf; } void CFunctionModel::declare_fcf(code_generation *gen, final_c_function *fcf) { generated_segment *saved = CodeGen::select(gen, c_predeclarations_I7CGS); text_stream *OUT = CodeGen::current(gen); WRITE("#define "); CNamespace::mangle(NULL, OUT, fcf->identifier_as_constant); WRITE(" (I7VAL_FUNCTIONS_BASE + %d)\n", fcf->allocation_id); CodeGen::deselect(gen, saved); } void CFunctionModel::make_veneer_fcf(code_generation *gen, text_stream *unmangled_name) { final_c_function *fcf = CFunctionModel::new_fcf(unmangled_name); fcf->max_arity = 1; CFunctionModel::declare_fcf(gen, fcf); } void CFunctionModel::begin_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) { text_stream *fn_name = CodeGen::CL::name(fn); C_GEN_DATA(fndata.argument_count) = 0; if (pass == 1) { C_GEN_DATA(fndata.current_fcf) = CFunctionModel::new_fcf(fn_name); fn->translation_data = STORE_POINTER_final_c_function(C_GEN_DATA(fndata.current_fcf)); Str::clear(C_GEN_DATA(fndata.prototype)); WRITE_TO(C_GEN_DATA(fndata.prototype), "i7val fn_"); CNamespace::mangle(cgt, C_GEN_DATA(fndata.prototype), fn_name); WRITE_TO(C_GEN_DATA(fndata.prototype), "(int __argc"); } if (pass == 2) { C_GEN_DATA(fndata.current_fcf) = RETRIEVE_POINTER_final_c_function(fn->translation_data); text_stream *OUT = CodeGen::current(gen); WRITE("i7val fn_"); CNamespace::mangle(cgt, OUT, fn_name); WRITE("(int __argc"); } } void CFunctionModel::begin_function_code(code_generation_target *cgt, code_generation *gen) { text_stream *OUT = CodeGen::current(gen); WRITE(") {\n"); if (C_GEN_DATA(fndata.current_fcf)) { text_stream *fn_name = C_GEN_DATA(fndata.current_fcf)->identifier_as_constant; WRITE("i7_debug_stack(\"%S\");\n", fn_name); if (Str::eq(fn_name, I"DebugAction")) { WRITE("switch (i7_mgl_local_a) {\n"); text_stream *aname; LOOP_OVER_LINKED_LIST(aname, text_stream, C_GEN_DATA(litdata.actions)) { WRITE("case i7_ss_%S", aname); WRITE(": printf(\"%S\"); return 1;\n", aname); } WRITE("}\n"); } } C_GEN_DATA(fndata.compiling_function) = TRUE; } void CFunctionModel::place_label(code_generation_target *cgt, code_generation *gen, text_stream *label_name) { text_stream *OUT = CodeGen::current(gen); LOOP_THROUGH_TEXT(pos, label_name) if (Str::get(pos) != '.') PUT(Str::get(pos)); WRITE(": ;\n", label_name); } void CFunctionModel::end_function(code_generation_target *cgt, int pass, code_generation *gen, inter_symbol *fn) { if (pass == 1) { WRITE_TO(C_GEN_DATA(fndata.prototype), ")"); generated_segment *saved = CodeGen::select(gen, c_predeclarations_I7CGS); text_stream *OUT = CodeGen::current(gen); WRITE("%S;\n", C_GEN_DATA(fndata.prototype)); CodeGen::deselect(gen, saved); final_c_function *fcf = RETRIEVE_POINTER_final_c_function(fn->translation_data); CFunctionModel::declare_fcf(gen, fcf); } if (pass == 2) { text_stream *OUT = CodeGen::current(gen); WRITE("return 1;\n"); WRITE("\n}\n"); C_GEN_DATA(fndata.compiling_function) = FALSE; } } int CFunctionModel::inside_function(code_generation *gen) { if (C_GEN_DATA(fndata.compiling_function)) return TRUE; return FALSE; } void CFunctionModel::function_call(code_generation_target *cgt, code_generation *gen, inter_symbol *fn, inter_tree_node *P, int argc) { inter_tree_node *D = fn->definition; if ((D) && (D->W.data[ID_IFLD] == CONSTANT_IST) && (D->W.data[FORMAT_CONST_IFLD] == CONSTANT_DIRECT)) { inter_ti val1 = D->W.data[DATA_CONST_IFLD]; inter_ti val2 = D->W.data[DATA_CONST_IFLD + 1]; if (Inter::Symbols::is_stored_in_data(val1, val2)) { inter_symbol *aliased = InterSymbolsTables::symbol_from_data_pair_and_table(val1, val2, Inter::Packages::scope_of(D)); if (aliased) fn = aliased; } } final_c_function *fcf = NULL; if (GENERAL_POINTER_IS_NULL(fn->translation_data) == FALSE) fcf = RETRIEVE_POINTER_final_c_function(fn->translation_data); text_stream *fn_name = CodeGen::CL::name(fn); text_stream *OUT = CodeGen::current(gen); inter_tree_node *fargstuff[128]; WRITE("fn_"); CNamespace::mangle(cgt, OUT, fn_name); WRITE("(%d", argc); int c = 0; LOOP_THROUGH_INTER_CHILDREN(F, P) { if (fcf) { if (fcf->uses_vararg_model) fargstuff[c] = F; else { WRITE(", "); CodeGen::FC::frame(gen, F); } } else { WRITE(", "); CodeGen::FC::frame(gen, F); } c++; } if (fcf) { if (fcf->uses_vararg_model) { WRITE(", ("); for (int i=argc-1; i >= 0; i--) { WRITE("i7_push("); CodeGen::FC::frame(gen, fargstuff[i]); WRITE("), "); } WRITE("%d)", argc); argc = 1; } while (argc < fcf->max_arity) { WRITE(", 0"); argc++; } } WRITE(")"); } void CFunctionModel::declare_local_variable(code_generation_target *cgt, int pass, code_generation *gen, inter_tree_node *P, inter_symbol *var_name) { TEMPORARY_TEXT(name) CNamespace::mangle(cgt, name, CodeGen::CL::name(var_name)); C_GEN_DATA(fndata.argument_count)++; if (pass == 1) { if (Str::eq(var_name->symbol_name, I"_vararg_count")) { C_GEN_DATA(fndata.current_fcf)->uses_vararg_model = TRUE; WRITE_TO(C_GEN_DATA(fndata.prototype), ", i7val %S", name); } else { WRITE_TO(C_GEN_DATA(fndata.prototype), ", i7val %S", name); } C_GEN_DATA(fndata.current_fcf)->max_arity++; } if (pass == 2) { text_stream *OUT = CodeGen::current(gen); WRITE(", i7val %S", name); } DISCARD_TEXT(name) }
- The structure C_generation_function_model_data is private to this section.
- The structure final_c_function is private to this section.
i7val i7_mgl_self = 0; i7val i7_call_0(i7val fn_ref) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; return i7_gen_call(fn_ref, args, 0); } i7val i7_mcall_0(i7val to, i7val prop) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; i7val saved = i7_mgl_self; i7_mgl_self = to; i7val fn_ref = i7_read_prop_value(to, prop); i7val rv = i7_gen_call(fn_ref, args, 0); i7_mgl_self = saved; return rv; } i7val i7_call_1(i7val fn_ref, i7val v) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; return i7_gen_call(fn_ref, args, 1); } i7val i7_mcall_1(i7val to, i7val prop, i7val v) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; i7val saved = i7_mgl_self; i7_mgl_self = to; i7val fn_ref = i7_read_prop_value(to, prop); i7val rv = i7_gen_call(fn_ref, args, 1); i7_mgl_self = saved; return rv; } i7val i7_call_2(i7val fn_ref, i7val v, i7val v2) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; args[1] = v2; return i7_gen_call(fn_ref, args, 2); } i7val i7_mcall_2(i7val to, i7val prop, i7val v, i7val v2) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; args[1] = v2; i7val saved = i7_mgl_self; i7_mgl_self = to; i7val fn_ref = i7_read_prop_value(to, prop); i7val rv = i7_gen_call(fn_ref, args, 2); i7_mgl_self = saved; return rv; } i7val i7_call_3(i7val fn_ref, i7val v, i7val v2, i7val v3) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; args[1] = v2; args[2] = v3; return i7_gen_call(fn_ref, args, 3); } i7val i7_mcall_3(i7val to, i7val prop, i7val v, i7val v2, i7val v3) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; args[1] = v2; args[2] = v3; i7val saved = i7_mgl_self; i7_mgl_self = to; i7val fn_ref = i7_read_prop_value(to, prop); i7val rv = i7_gen_call(fn_ref, args, 3); i7_mgl_self = saved; return rv; } i7val i7_call_4(i7val fn_ref, i7val v, i7val v2, i7val v3, i7val v4) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; args[1] = v2; args[2] = v3; args[3] = v4; return i7_gen_call(fn_ref, args, 4); } i7val i7_call_5(i7val fn_ref, i7val v, i7val v2, i7val v3, i7val v4, i7val v5) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; args[0] = v; args[1] = v2; args[2] = v3; args[3] = v4; args[4] = v5; return i7_gen_call(fn_ref, args, 5); } void glulx_call(i7val fn_ref, i7val varargc, i7val *z) { i7val args[10]; for (int i=0; i<10; i++) args[i] = 0; for (int i=0; i<varargc; i++) args[i] = i7_pull(); i7val rv = i7_gen_call(fn_ref, args, varargc); if (z) *z = rv; }
- This is part of the extract file inform7_clib.h.