+static void check_fptr_args(int i, int opcnt, struct parsed_proto *pp)
+{
+ struct parsed_opr s_opr = OPR_INIT(OPT_REG, OPLM_DWORD, 0);
+ const struct parsed_proto *pp_arg, *pp_cmp;
+ const struct parsed_op *po_a;
+ const char *s_reg;
+ int pp_cmp_i;
+ int arg, reg;
+ int bad = 0;
+ int j;
+
+ for (arg = 0; arg < pp->argc; arg++) {
+ pp_cmp = NULL;
+ pp_cmp_i = -1;
+
+ pp_arg = pp->arg[arg].pp;
+ if (pp_arg == NULL || !pp_arg->is_func)
+ continue;
+
+ s_reg = pp->arg[arg].reg;
+ if (s_reg != NULL) {
+ reg = char_array_i(regs_r32, ARRAY_SIZE(regs_r32), s_reg);
+ ferr_assert(&ops[i], reg >= 0);
+ s_opr.reg = reg;
+ scan_for_call_type(i, &s_opr, i + arg + opcnt * 28, 0,
+ &pp_cmp, &pp_cmp_i, NULL);
+ if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
+ bad = 1;
+ if (pp_cmp_i >= 0)
+ fnote(&ops[pp_cmp_i], "(referenced here)\n");
+ }
+ }
+ else {
+ for (j = 0; j < pp->arg[arg].push_ref_cnt; j++) {
+ po_a = pp->arg[arg].push_refs[j];
+ if (po_a == NULL || po_a->op != OP_PUSH)
+ continue;
+ pp_cmp = resolve_func_ptr(po_a - ops, opcnt, 0,
+ &po_a->operand[0], &pp_cmp_i, NULL);
+ if (pp_cmp != NULL && !pp_compatible_func(pp_arg, pp_cmp)) {
+ bad = 1;
+ if (pp_cmp_i < 0)
+ pp_cmp_i = po_a - ops;
+ if (pp_cmp_i >= 0)
+ fnote(&ops[pp_cmp_i], "(referenced here)\n");
+ }
+ }
+ }
+
+ if (bad)
+ ferr(&ops[i], "incompatible fptr arg %d\n", arg + 1);
+ }
+}
+
+static void pp_insert_reg_arg(struct parsed_proto *pp, const char *reg)
+{
+ int i;
+
+ for (i = 0; i < pp->argc; i++)
+ if (pp->arg[i].reg == NULL)
+ break;
+
+ if (pp->argc_stack)
+ memmove(&pp->arg[i + 1], &pp->arg[i],
+ sizeof(pp->arg[0]) * pp->argc_stack);
+ memset(&pp->arg[i], 0, sizeof(pp->arg[i]));
+ pp->arg[i].reg = strdup(reg);
+ pp->arg[i].type.name = strdup("int");
+ pp->argc++;
+ pp->argc_reg++;
+}
+
+static void pp_insert_stack_args(struct parsed_proto *pp, int count)
+{
+ int a;
+
+ pp->argc += count;
+ pp->argc_stack += count;
+
+ for (a = 0; a < pp->argc; a++)
+ if (pp->arg[a].type.name == NULL)
+ pp->arg[a].type.name = strdup("int");
+}
+
+static void pp_add_push_ref(struct parsed_proto *pp,
+ int arg, struct parsed_op *po)
+{
+ pp->arg[arg].push_refs = realloc(pp->arg[arg].push_refs,
+ (pp->arg[arg].push_ref_cnt + 1)
+ * sizeof(pp->arg[arg].push_refs[0]));
+ ferr_assert(po, pp->arg[arg].push_refs != NULL);
+ pp->arg[arg].push_refs[pp->arg[arg].push_ref_cnt++] = po;
+}
+
+static void mark_float_arg(struct parsed_op *po,
+ struct parsed_proto *pp, int arg, int *regmask_ffca)
+{
+ ferr_assert(po, pp->arg[arg].push_ref_cnt == 0);
+ pp_add_push_ref(pp, arg, po);
+
+ po->p_argnum = arg + 1;
+ po->flags |= OPF_DONE | OPF_FARGNR | OPF_FARG;
+ if (regmask_ffca != NULL)
+ *regmask_ffca |= 1 << arg;
+}
+
+static int check_for_stp(int i, int i_to)
+{
+ struct parsed_op *po;
+
+ for (; i < i_to; i++) {
+ po = &ops[i];
+ if (po->op == OP_FST)
+ return i;
+ if (g_labels[i] != NULL || (po->flags & OPF_JMP))
+ return -1;
+ if (po->op == OP_CALL || po->op == OP_PUSH || po->op == OP_POP)
+ return -1;
+ if (po->op == OP_ADD && po->operand[0].reg == xSP)
+ return -1;
+ }
+
+ return -1;
+}
+