// Generate function call. The function address is pushed first, then // all the parameters in call order. This function pops all the // parameters and the function address. void gfunc_call(int nb_args) { int size, align, r, args_size, i, func_call, v; Sym *func_sym; args_size = 0; for (i = 0; i < nb_args; i++) { if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { size = type_size(&vtop->type, &align); // Align to stack align size size = (size + 3) & ~3; // Allocate the necessary size on stack oad(0xec81, size); // sub $xxx, %esp // Generate structure store r = get_reg(RC_INT); o(0x89); // mov %esp, r o(0xe0 + r); vset(&vtop->type, r | VT_LVAL, 0); vswap(); vstore(); args_size += size; } else if (is_float(vtop->type.t)) { gv(RC_FLOAT); // Only one float register if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { size = 4; } else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) { size = 8; } else { size = 12; } oad(0xec81, size); // sub $xxx, %esp if (size == 12) { o(0x7cdb); } else { o(0x5cd9 + size - 4); // fstp[s|l] 0(%esp) } g(0x24); g(0x00); args_size += size; } else { // Simple type (currently always same size) // TODO: implicit cast? v = vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM); if (v == VT_CONST || v == (VT_CONST | VT_SYM)) { // Push constant if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { size = 8; if (vtop->c.word[1] == (char) vtop->c.word[1]) { g(0x6a); // push imm8 g(vtop->c.word[1]); } else { g(0x68); // push imm32 gen_le32(vtop->c.word[1]); } } else { size = 4; } if ((v & VT_SYM) == 0 && vtop->c.i == (char) vtop->c.i) { g(0x6a); // push imm8 g(vtop->c.i); } else { g(0x68); // push imm32 gen_addr32(v, vtop->sym, vtop->c.i); } } else { r = gv(RC_INT); if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { size = 8; o(0x50 + vtop->r2); // push r2 } else { size = 4; } o(0x50 + r); // push r } args_size += size; } vtop--; } save_regs(0); // Save used temporary registers func_sym = vtop->type.ref; func_call = FUNC_CALL(func_sym->r); // fast call case if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || func_call == FUNC_FASTCALLW) { int fastcall_nb_regs; uint8_t *fastcall_regs_ptr; if (func_call == FUNC_FASTCALLW) { fastcall_regs_ptr = fastcallw_regs; fastcall_nb_regs = 2; } else { fastcall_regs_ptr = fastcall_regs; fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; } for (i = 0; i < fastcall_nb_regs; i++) { if (args_size <= 0) break; o(0x58 + fastcall_regs_ptr[i]); // pop r // TODO: incorrect for struct/floats args_size -= 4; } } gcall_or_jmp(0); if (args_size && func_call != FUNC_STDCALL) gadd_sp(args_size); vtop--; }
/* Generate function call. The function address is pushed first, then all the parameters in call order. This functions pops all the parameters and the function address. */ void gfunc_call(int nb_args) { int size, align, r, args_size, i, func_call; Sym *func_sym; args_size = 0; for(i = 0;i < nb_args; i++) { if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { size = type_size(&vtop->type, &align); /* align to stack align size */ size = (size + 3) & ~3; /* allocate the necessary size on stack */ oad(0xec81, size); /* sub $xxx, %esp */ /* generate structure store */ r = get_reg(RC_INT); o(0x89); /* mov %esp, r */ o(0xe0 + r); vset(&vtop->type, r | VT_LVAL, 0); vswap(); vstore(); args_size += size; } else if (is_float(vtop->type.t)) { gv(RC_FLOAT); /* only one float register */ if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) size = 4; else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) size = 8; else size = 12; oad(0xec81, size); /* sub $xxx, %esp */ if (size == 12) o(0x7cdb); else o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */ g(0x24); g(0x00); args_size += size; } else { /* simple type (currently always same size) */ /* XXX: implicit cast ? */ r = gv(RC_INT); if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { size = 8; o(0x50 + vtop->r2); /* push r */ } else { size = 4; } o(0x50 + r); /* push r */ args_size += size; } vtop--; } save_regs(0); /* save used temporary registers */ func_sym = vtop->type.ref; func_call = FUNC_CALL(func_sym->r); /* fast call case */ if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) || func_call == FUNC_FASTCALLW) { int fastcall_nb_regs; uint8_t *fastcall_regs_ptr; if (func_call == FUNC_FASTCALLW) { fastcall_regs_ptr = fastcallw_regs; fastcall_nb_regs = 2; } else { fastcall_regs_ptr = fastcall_regs; fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1; } for(i = 0;i < fastcall_nb_regs; i++) { if (args_size <= 0) break; o(0x58 + fastcall_regs_ptr[i]); /* pop r */ /* XXX: incorrect for struct/floats */ args_size -= 4; } } gcall_or_jmp(0); if (args_size && func_call != FUNC_STDCALL) gadd_sp(args_size); vtop--; }