+ /* Not bailing out just now. If this happens a lot you don't want to have
+ * to rerun gmqcc for each such function.
+ */
+
+ /* return false; */
+ }
+ }
+ /* this was a function pointer, don't generate code for those */
+ return true;
+ }
+
+ if (irfun->builtin)
+ return true;
+
+ /*
+ * If there is no definition and the thing is eraseable, we can ignore
+ * outputting the function to begin with.
+ */
+ if (global->flags & IR_FLAG_ERASABLE && irfun->code_function_def < 0) {
+ return true;
+ }
+
+ if (irfun->code_function_def < 0) {
+ irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
+ return false;
+ }
+ fundef = &ir->code->functions[irfun->code_function_def];
+
+ fundef->entry = vec_size(ir->code->statements);
+ if (!gen_function_locals(ir, global)) {
+ irerror(irfun->context, "Failed to generate locals for function %s", irfun->name);
+ return false;
+ }
+ if (!gen_function_extparam_copy(ir->code, irfun)) {
+ irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
+ return false;
+ }
+ if (irfun->max_varargs && !gen_function_varargs_copy(ir->code, irfun)) {
+ irerror(irfun->context, "Failed to generate vararg-copy code for function %s", irfun->name);
+ return false;
+ }
+ if (!gen_function_code(ir->code, irfun)) {
+ irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
+ return false;
+ }
+ return true;
+}
+
+static void gen_vector_defs(code_t *code, prog_section_def_t def, const char *name)
+{
+ char *component;
+ size_t len, i;
+
+ if (!name || name[0] == '#' || OPTS_FLAG(SINGLE_VECTOR_DEFS))
+ return;
+
+ def.type = TYPE_FLOAT;
+
+ len = strlen(name);
+
+ component = (char*)mem_a(len+3);
+ memcpy(component, name, len);
+ len += 2;
+ component[len-0] = 0;
+ component[len-2] = '_';
+
+ component[len-1] = 'x';
+
+ for (i = 0; i < 3; ++i) {
+ def.name = code_genstring(code, component);
+ vec_push(code->defs, def);
+ def.offset++;
+ component[len-1]++;
+ }
+
+ mem_d(component);
+}
+
+static void gen_vector_fields(code_t *code, prog_section_field_t fld, const char *name)
+{
+ char *component;
+ size_t len, i;
+
+ if (!name || OPTS_FLAG(SINGLE_VECTOR_DEFS))
+ return;
+
+ fld.type = TYPE_FLOAT;
+
+ len = strlen(name);
+
+ component = (char*)mem_a(len+3);
+ memcpy(component, name, len);
+ len += 2;
+ component[len-0] = 0;
+ component[len-2] = '_';
+
+ component[len-1] = 'x';
+
+ for (i = 0; i < 3; ++i) {
+ fld.name = code_genstring(code, component);
+ vec_push(code->fields, fld);
+ fld.offset++;
+ component[len-1]++;
+ }
+
+ mem_d(component);
+}
+
+static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
+{
+ size_t i;
+ int32_t *iptr;
+ prog_section_def_t def;
+ bool pushdef = opts.optimizeoff;
+
+ /* we don't generate split-vectors */
+ if (global->vtype == TYPE_VECTOR && (global->flags & IR_FLAG_SPLIT_VECTOR))
+ return true;
+
+ def.type = global->vtype;
+ def.offset = vec_size(self->code->globals);
+ def.name = 0;
+ if (OPTS_OPTION_BOOL(OPTION_G) || !islocal)
+ {
+ pushdef = true;
+
+ /*
+ * if we're eraseable and the function isn't referenced ignore outputting
+ * the function.
+ */
+ if (global->flags & IR_FLAG_ERASABLE && vec_size(global->reads) == 0) {
+ return true;
+ }
+
+ if (OPTS_OPTIMIZATION(OPTIM_STRIP_CONSTANT_NAMES) &&
+ !(global->flags & IR_FLAG_INCLUDE_DEF) &&
+ (global->name[0] == '#' || global->cvq == CV_CONST))
+ {
+ pushdef = false;
+ }
+
+ if (pushdef) {
+ if (global->name[0] == '#') {
+ if (!self->str_immediate)
+ self->str_immediate = code_genstring(self->code, "IMMEDIATE");
+ def.name = global->code.name = self->str_immediate;
+ }
+ else
+ def.name = global->code.name = code_genstring(self->code, global->name);
+ }
+ else
+ def.name = 0;
+ if (islocal) {
+ def.offset = ir_value_code_addr(global);
+ vec_push(self->code->defs, def);
+ if (global->vtype == TYPE_VECTOR)
+ gen_vector_defs(self->code, def, global->name);
+ else if (global->vtype == TYPE_FIELD && global->fieldtype == TYPE_VECTOR)
+ gen_vector_defs(self->code, def, global->name);
+ return true;
+ }
+ }
+ if (islocal)
+ return true;
+
+ switch (global->vtype)
+ {
+ case TYPE_VOID:
+ if (!strcmp(global->name, "end_sys_globals")) {
+ /* TODO: remember this point... all the defs before this one
+ * should be checksummed and added to progdefs.h when we generate it.
+ */
+ }
+ else if (!strcmp(global->name, "end_sys_fields")) {
+ /* TODO: same as above but for entity-fields rather than globsl
+ */
+ }
+ else if(irwarning(global->context, WARN_VOID_VARIABLES, "unrecognized variable of type void `%s`",
+ global->name))
+ {
+ /* Not bailing out */
+ /* return false; */
+ }
+ /* I'd argue setting it to 0 is sufficient, but maybe some depend on knowing how far
+ * the system fields actually go? Though the engine knows this anyway...
+ * Maybe this could be an -foption
+ * fteqcc creates data for end_sys_* - of size 1, so let's do the same
+ */
+ ir_value_code_setaddr(global, vec_size(self->code->globals));
+ vec_push(self->code->globals, 0);
+ /* Add the def */
+ if (pushdef) vec_push(self->code->defs, def);
+ return true;
+ case TYPE_POINTER:
+ if (pushdef) vec_push(self->code->defs, def);
+ return gen_global_pointer(self->code, global);
+ case TYPE_FIELD:
+ if (pushdef) {
+ vec_push(self->code->defs, def);
+ if (global->fieldtype == TYPE_VECTOR)
+ gen_vector_defs(self->code, def, global->name);
+ }
+ return gen_global_field(self->code, global);
+ case TYPE_ENTITY:
+ /* fall through */
+ case TYPE_FLOAT:
+ {
+ ir_value_code_setaddr(global, vec_size(self->code->globals));
+ if (global->hasvalue) {
+ if (global->cvq == CV_CONST && !vec_size(global->reads))
+ return true;
+ iptr = (int32_t*)&global->constval.ivec[0];
+ vec_push(self->code->globals, *iptr);
+ } else {
+ vec_push(self->code->globals, 0);
+ }
+ if (!islocal && global->cvq != CV_CONST)
+ def.type |= DEF_SAVEGLOBAL;
+ if (pushdef) vec_push(self->code->defs, def);
+
+ return global->code.globaladdr >= 0;
+ }
+ case TYPE_STRING:
+ {
+ ir_value_code_setaddr(global, vec_size(self->code->globals));
+ if (global->hasvalue) {
+ uint32_t load;
+ if (global->cvq == CV_CONST && !vec_size(global->reads))
+ return true;
+ load = code_genstring(self->code, global->constval.vstring);
+ vec_push(self->code->globals, load);
+ } else {
+ vec_push(self->code->globals, 0);
+ }
+ if (!islocal && global->cvq != CV_CONST)
+ def.type |= DEF_SAVEGLOBAL;
+ if (pushdef) vec_push(self->code->defs, def);
+ return global->code.globaladdr >= 0;
+ }
+ case TYPE_VECTOR:
+ {
+ size_t d;
+ ir_value_code_setaddr(global, vec_size(self->code->globals));
+ if (global->hasvalue) {
+ iptr = (int32_t*)&global->constval.ivec[0];
+ vec_push(self->code->globals, iptr[0]);
+ if (global->code.globaladdr < 0)
+ return false;
+ for (d = 1; d < type_sizeof_[global->vtype]; ++d) {
+ vec_push(self->code->globals, iptr[d]);