#include <ctype.h>
#include <limits.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "reswords.h"
#include "expreval.h"
#include "lqueue.h"
#include "equate.h"
#include "assume.h"
#include "segment.h"
#include "listing.h"
#include "myassert.h"
#include "label.h"
#include "hll.h"
#include "segment.h"
#if DLLIMPORT
#include "mangle.h"
#include "extern.h"
#endif
#include "proc.h"
#if defined(WINDOWSDDK)
#if defined(_WIN32)
typedef _W64 int INT_PTR, *PINT_PTR;
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
typedef _W64 long LONG_PTR, *PLONG_PTR;
typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
#define __int3264 __int32
#else
typedef __int64 INT_PTR, *PINT_PTR;
typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
typedef __int64 LONG_PTR, *PLONG_PTR;
typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
#define __int3264 __int64
#endif
#else
#include <inttypes.h>
#if defined(_WIN32)
typedef _W64 int INT_PTR, *PINT_PTR;
typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
typedef _W64 long LONG_PTR, *PLONG_PTR;
typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
#define __int3264 __int32
#else
typedef int64_t INT_PTR, *PINT_PTR;
typedef uint64_t UINT_PTR, *PUINT_PTR;
typedef int64_t LONG_PTR, *PLONG_PTR;
typedef uint64_t ULONG_PTR, *PULONG_PTR;
#define __int3264 int64_t
#endif
#endif
extern bool write_to_file;
extern int_64 maxintvalues[];
extern int_64 minintvalues[];
extern enum special_token stackreg[];
extern struct dsym *CurrStruct;
extern UINT_PTR UTF8toWideChar(const unsigned char *pSource, UINT_PTR nSourceLen, UINT_PTR *nSourceDone, unsigned short *szTarget, UINT_PTR nTargetMax);
#ifdef __I86__
#define NUMQUAL (long)
#else
#define NUMQUAL
#endif
enum reg_used_flags {
R0_USED = 0x01,
R0_H_CLEARED = 0x02,
R0_X_CLEARED = 0x04,
R2_USED = 0x08,
#if AMD64_SUPPORT
RCX_USED = 0x08,
RDX_USED = 0x10,
R8_USED = 0x20,
R9_USED = 0x40,
#define RPAR_START 3
#endif
#if SYSV_SUPPORT
SV_RDI_USED = 0x02,
SV_RSI_USED = 0x04,
SV_RDX_USED = 0x08,
SV_RCX_USED = 0x10,
SV_R8_USED = 0x20,
SV_R9_USED = 0x40,
#define SYSVR_START 1
#endif
#if OWFC_SUPPORT
ROW_AX_USED = 0x08,
ROW_DX_USED = 0x10,
ROW_BX_USED = 0x20,
ROW_CX_USED = 0x40,
#define ROW_START 3
#endif
};
extern void myatoi128( const char *, uint_64[], int, int );
static int size_vararg;
static int fcscratch = 0;
static int vcallpass = 0;
struct fastcall_conv {
int (* invokestart)( struct dsym const *, int, int, struct asm_tok[], int * );
void (* invokeend) ( struct dsym const *, int, int );
int (* handleparam)( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 * );
};
struct vectorcall_conv {
int (* invokestart)( struct dsym const *, int, int, struct asm_tok[], int * );
void (* invokeend) ( struct dsym const *, int, int );
int (* handleparam)( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 * );
};
struct sysvcall_conv {
int (* invokestart)( struct dsym const *, int, int, struct asm_tok[], int *);
void (* invokeend) ( struct dsym const *, int, int);
int (* handleparam)( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 *);
};
struct delphicall_conv {
int (* invokestart)( struct dsym const *, int, int, struct asm_tok[], int *);
void (* invokeend) ( struct dsym const *, int, int);
int (* handleparam)( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 *);
};
static int ms32_fcstart( struct dsym const *, int, int, struct asm_tok[], int * );
static void ms32_fcend ( struct dsym const *, int, int );
static int ms32_param ( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 * );
#if OWFC_SUPPORT
static int watc_fcstart( struct dsym const *, int, int, struct asm_tok[], int * );
static void watc_fcend ( struct dsym const *, int, int );
static int watc_param ( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 * );
#endif
#if AMD64_SUPPORT
static int ms64_fcstart( struct dsym const *, int, int, struct asm_tok[], int * );
static void ms64_fcend ( struct dsym const *, int, int );
static int ms64_param ( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 * );
#define REGPAR_WIN64 0x0306
#endif
#if SYSV_SUPPORT
static int sysv_reg ( unsigned int );
static int sysv_fcstart ( struct dsym const *, int, int, struct asm_tok[], int * );
static void sysv_fcend ( struct dsym const *, int, int );
static int sysv_param ( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 * );
static int sysv_vararg_param ( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 *);
#define REGPAR_SYSV 0x03C6
#endif
#if DELPHI_SUPPORT
static int delphi32_fcstart( struct dsym const *, int, int, struct asm_tok[], int * );
static void delphi32_fcend ( struct dsym const *, int, int );
static int delphi32_param ( struct dsym const *, int, struct dsym *, bool, struct expr *, char *, uint_8 * );
#define REGPAR_DELPHI 0x03
#endif
static const struct fastcall_conv fastcall_tab[] = {
{ ms32_fcstart, ms32_fcend , ms32_param },
#if OWFC_SUPPORT
{ watc_fcstart, watc_fcend , watc_param },
#endif
#if AMD64_SUPPORT
{ ms64_fcstart, ms64_fcend , ms64_param }
#endif
};
static const struct vectorcall_conv vectorcall_tab[] = {
{ ms32_fcstart, ms32_fcend , ms32_param },
#if OWFC_SUPPORT
{ watc_fcstart, watc_fcend , watc_param },
#endif
#if AMD64_SUPPORT
{ ms64_fcstart, ms64_fcend , ms64_param }
#endif
};
static const struct sysvcall_conv sysvcall_tab[] = {
{ ms32_fcstart, ms32_fcend , ms32_param },
#if OWFC_SUPPORT
{ watc_fcstart, watc_fcend , watc_param },
#endif
#if AMD64_SUPPORT
{ sysv_fcstart, sysv_fcend , sysv_param }
#endif
};
static const struct delphicall_conv delphicall_tab[] = {
{ delphi32_fcstart, delphi32_fcend , delphi32_param },
#if OWFC_SUPPORT
{ watc_fcstart, watc_fcend , watc_param },
#endif
#if AMD64_SUPPORT
{ ms64_fcstart, ms64_fcend , ms64_param }
#endif
};
static const enum special_token regax[] = { T_AX, T_EAX,
#if AMD64_SUPPORT
T_RAX
#endif
};
static const enum special_token ms16_regs[] = {
T_AX, T_DX, T_BX
};
static const enum special_token ms32_regs[] = {
T_ECX, T_EDX
};
static const enum special_token delphi32_regs[] = {
T_EAX, T_EDX, T_ECX
};
#if AMD64_SUPPORT
static const enum special_token ms64_regs[] = {
T_CL, T_DL, T_R8B, T_R9B,
T_CX, T_DX, T_R8W, T_R9W,
T_ECX, T_EDX, T_R8D, T_R9D,
T_RCX, T_RDX, T_R8, T_R9
};
#endif
#if SYSV_SUPPORT
static const enum special_token sysV64_regs[] = {
T_DIL, T_SIL, T_DL, T_CL, T_R8B, T_R9B,
T_DI, T_SI, T_DX, T_CX, T_R8W, T_R9W,
T_EDI, T_ESI, T_EDX, T_ECX, T_R8D, T_R9D,
T_RDI, T_RSI, T_RDX, T_RCX, T_R8, T_R9
};
static const enum special_token sysV64_regsXMM[] = {
T_XMM0, T_XMM1, T_XMM2, T_XMM3, T_XMM4, T_XMM5, T_XMM6, T_XMM7
};
static const enum special_token sysV64_regsYMM[] = {
T_YMM0, T_YMM1, T_YMM2, T_YMM3, T_YMM4, T_YMM5, T_YMM6, T_YMM7
};
static const enum special_token sysV64_regsZMM[] = {
T_ZMM0, T_ZMM1, T_ZMM2, T_ZMM3, T_ZMM4, T_ZMM5, T_ZMM6, T_ZMM7
};
#endif
static int ms32_fcstart( struct dsym const *proc, int numparams, int start, struct asm_tok tokenarray[], int *value )
{
struct dsym *param;
DebugMsg1(("ms32_fcstart(proc=%s, ofs=%u)\n", proc->sym.name, GetSymOfssize( &proc->sym ) ));
if ( GetSymOfssize( &proc->sym ) == USE16 )
return( 0 );
for ( param = proc->e.procinfo->paralist ; param ; param = param->nextparam )
if ( param->sym.state == SYM_TMACRO )
fcscratch++;
return( 1 );
}
static void ms32_fcend( struct dsym const *proc, int numparams, int value )
{
return;
}
static int ms32_param( struct dsym const *proc, int index, struct dsym *param, bool addr, struct expr *opnd, char *paramvalue, uint_8 *r0used )
{
enum special_token const *pst;
DebugMsg1(("ms32_param(proc=%s, ofs=%u, index=%u, param=%s) fcscratch=%u\n", proc->sym.name, proc->sym.Ofssize, index, param->sym.name, fcscratch ));
if ( param->sym.state != SYM_TMACRO || param->sym.mem_type == MT_REAL4 || param->sym.mem_type == MT_REAL8 )
return( 0 );
if ( GetSymOfssize( &proc->sym ) == USE16 ) {
pst = ms16_regs + fcscratch;
fcscratch++;
} else {
fcscratch--;
pst = ms32_regs + fcscratch;
}
if ( addr )
AddLineQueueX( " lea %r, %s", *pst, paramvalue );
else {
enum special_token reg = *pst;
int size;
if ( ( opnd->kind != EXPR_CONST ) &&
( size = SizeFromMemtype( param->sym.mem_type, USE_EMPTY, param->sym.type ) ) < SizeFromRegister( *pst ) ) {
if (( ModuleInfo.curr_cpu & P_CPU_MASK ) >= P_386 ) {
AddLineQueueX( " %s %r, %s", ( param->sym.mem_type & MT_SIGNED ) ? "movsx" : "movzx", reg, paramvalue );
} else {
AddLineQueueX( " mov %r, %s", T_AL + GetRegNo( reg ), paramvalue );
AddLineQueueX( " mov %r, 0", T_AH + GetRegNo( reg ) );
}
} else {
if ( opnd->kind == EXPR_REG && opnd->indirect == 0 && opnd->base_reg ) {
if ( opnd->base_reg->tokval == reg )
return( 1 );
}
AddLineQueueX( " mov %r, %s", reg, paramvalue );
}
}
if ( *pst == T_AX )
*r0used |= R0_USED;
return( 1 );
}
static int delphi32_fcstart( struct dsym const *proc, int numparams, int start, struct asm_tok tokenarray[], int *value )
{
return( 0 );
}
static void delphi32_fcend( struct dsym const *proc, int numparams, int value )
{
return;
}
static int delphi32_param( struct dsym const *proc, int index, struct dsym *param, bool addr, struct expr *opnd, char *paramvalue, uint_8 *r0used )
{
enum special_token const *pst;
struct proc_info *info;
enum special_token reg;
info = proc->e.procinfo;
DebugMsg1(("delphi_param(proc=%s, ofs=%u, index=%u, param=%s) fcscratch=%u\n", proc->sym.name, proc->sym.Ofssize, index, param->sym.name, fcscratch ));
if (param->sym.state != SYM_TMACRO && ((param->sym.state == SYM_STACK && !addr) || fcscratch > 2))
{
return(0);
}
pst = delphi32_regs + fcscratch;
reg = *pst;
info->delregsused[fcscratch] = reg;
if ((_stricmp(paramvalue, "EAX") == 0) && fcscratch == 0){
fcscratch++;
return (1);
}
else if ((_stricmp(paramvalue, "EDX") == 0) && fcscratch == 1){
fcscratch++;
return (1);
}
else if ((_stricmp(paramvalue, "ECX") == 0) && fcscratch == 2){
fcscratch++;
return (1);
}
if ( opnd->kind == EXPR_REG && opnd->indirect == 0 && opnd->base_reg ) {
if (opnd->base_reg->tokval == reg){
fcscratch++;
return(1);
}
}
if (Parse_Pass)
{
switch (fcscratch)
{
case 0:
if ((_stricmp(paramvalue, "EDX") == 0) && info->delregsused[1] ||
(_stricmp(paramvalue, "ECX") == 0) && info->delregsused[2])
EmitWarn(2, REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
break;
case 1:
if ((_stricmp(paramvalue, "EAX") == 0) && info->delregsused[0] ||
(_stricmp(paramvalue, "ECX") == 0) && info->delregsused[2])
EmitWarn(2, REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
break;
case 2:
if ((_stricmp(paramvalue, "EAX") == 0) && info->delregsused[0] ||
(_stricmp(paramvalue, "EDX") == 0) && info->delregsused[1])
EmitWarn(2, REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
}
}
if (param->sym.state == SYM_TMACRO && !addr)
AddLineQueueX(" mov %r, %s", reg, paramvalue);
else if (addr)
AddLineQueueX(" lea %r, %s", reg, paramvalue);
fcscratch++;
return( 1 );
}
#if AMD64_SUPPORT
static int ms64_fcstart(struct dsym const *proc, int numparams, int start, struct asm_tok tokenarray[], int *value)
{
int j;
if (proc->e.procinfo->has_vararg)
{
for (numparams = 0; tokenarray[start].token != T_FINAL; start++)
if (tokenarray[start].token == T_COMMA) {
numparams++;
}
}
DebugMsg1(("ms64_fcstart(%s, numparams=%u) vararg=%u\n", proc->sym.name, numparams, proc->e.procinfo->has_vararg));
j = 4;
if (numparams < j)
numparams = j;
else if (numparams & 1)
numparams++;
*value = numparams;
if (ModuleInfo.win64_flags & W64F_AUTOSTACKSP)
{
if ((numparams * sizeof(uint_64)) > sym_ReservedStack->value)
sym_ReservedStack->value = numparams * sizeof(uint_64);
}
else
AddLineQueueX("sub %r, %d", T_RSP, numparams * sizeof(uint_64));
return(0);
}
static void ms64_fcend(struct dsym const *proc, int numparams, int value)
{
if (!(ModuleInfo.win64_flags & W64F_AUTOSTACKSP))
AddLineQueueX(" add %r, %d", T_RSP, value * 8);
return;
}
#define GetParmIndex( x ) ( ( (x) >= 8 ) ? (x) - 6 : (x) - 1 )
static int ms64_param(struct dsym const *proc, int index, struct dsym *param, bool addr, struct expr *opnd, char *paramvalue, uint_8 *regs_used)
{
uint_32 size;
uint_32 psize;
int reg;
int reg2;
int i;
int j = 0;
int tCount = 0;
int freevecregs = 0;
int vecidx = -1;
int membersize = 0;
int memberCount = 0;
int base;
struct proc_info *info = proc->e.procinfo;
struct dsym *t = NULL;
bool destroyed = FALSE;
struct asym *sym = NULL;
DebugMsg1(("ms64_param(%s, index=%u, param.memtype=%Xh, addr=%u) enter\n", proc->sym.name, index, param->sym.mem_type, addr));
if (param->sym.is_vararg)
{
psize = 0;
if (opnd->kind == EXPR_CONST && (opnd->llvalue > INT_MAX || opnd->llvalue < INT_MIN))
psize = 8;
else if (addr || opnd->instr == T_OFFSET)
psize = 8;
else if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
psize = SizeFromRegister(opnd->base_reg->tokval);
else if (opnd->mem_type != MT_EMPTY)
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (psize < 4)
psize = 4;
}
else
psize = SizeFromMemtype(param->sym.mem_type, USE64, param->sym.type);
if (psize == 3 || psize == 5 || psize == 6 || psize == 7)
{
if (param->sym.mem_type == MT_TYPE)
{
EmitErr(INVALID_REG_STRUCT_SIZE);
}
}
if (vcallpass == 1)
goto vcall;
if (opnd->base_reg != NULL)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_R) {
i = GetRegNo(reg);
if (REGPAR_WIN64 & (1 << i)) {
base = GetParmIndex(i);
if (*regs_used & (1 << (base + RPAR_START)))
destroyed = TRUE;
}
else if ((*regs_used & R0_USED) && ((GetValueSp(reg) & OP_A) || reg == T_AH)) {
destroyed = TRUE;
}
}
}
if (opnd->idx_reg != NULL)
{
reg2 = opnd->idx_reg->tokval;
if (GetValueSp(reg2) & OP_R) {
i = GetRegNo(reg2);
if (REGPAR_WIN64 & (1 << i)) {
base = GetParmIndex(i);
if (*regs_used & (1 << (base + RPAR_START)))
destroyed = TRUE;
}
else if ((*regs_used & R0_USED) && ((GetValueSp(reg2) & OP_A) || reg2 == T_AH)) {
destroyed = TRUE;
}
}
}
if (destroyed)
{
EmitErr(REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
*regs_used = 0;
}
if ( ( (proc->sym.langtype == LANG_VECTORCALL) && (index >= 6) ) ||
( (proc->sym.langtype == LANG_FASTCALL) && (index >= 4) ) ) {
if (addr)
{
if (psize == 4)
i = T_EAX;
else {
i = T_RAX;
if (psize < 8)
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
}
*regs_used |= R0_USED;
AddLineQueueX(" lea %r, %s", i, paramvalue);
AddLineQueueX(" mov [%r+%u], %r", T_RSP, NUMQUAL index * 8, i);
DebugMsg(("ms64_param(%s, param=%u): ADDR flags=%X\n", proc->sym.name, index, *regs_used));
return(1);
}
if (opnd->kind == EXPR_CONST ||
(opnd->kind == EXPR_ADDR && opnd->indirect == FALSE && opnd->mem_type == MT_EMPTY && opnd->instr != T_OFFSET)) {
if (psize == 8 &&
(opnd->value64 > H_LONG_MAX || opnd->value64 < H_LONG_MIN)) {
AddLineQueueX(" mov %r ptr [%r+%u], %r ( %s )", T_DWORD, T_RSP, NUMQUAL index * 8, T_LOW32, paramvalue);
AddLineQueueX(" mov %r ptr [%r+%u], %r ( %s )", T_DWORD, T_RSP, NUMQUAL index * 8 + 4, T_HIGH32, paramvalue);
return(1);
}
else {
if (param->sym.mem_type == MT_PTR && opnd->kind == EXPR_ADDR && opnd->sym->state != SYM_UNDEFINED) {
DebugMsg(("ms64_param(%s, param=%u): MT_PTR, type error, psize=%u\n", proc->sym.name, index, psize));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
}
switch (psize) {
case 1: i = T_BYTE; break;
case 2: i = T_WORD; break;
case 4: i = T_DWORD; break;
default: i = T_QWORD; break;
}
AddLineQueueX(" mov %r ptr [%r+%u], %s", i, T_RSP, NUMQUAL index * 8, paramvalue);
return(1);
}
DebugMsg(("ms64_param(%s, param=%u): MT_EMPTY size.p=%u flags=%X\n", proc->sym.name, index, psize, *regs_used));
}
else if (opnd->kind == EXPR_FLOAT)
{
if (param->sym.mem_type == MT_REAL8) {
AddLineQueueX(" mov %r ptr [%r+%u+0], %r (%s)", T_DWORD, T_RSP, NUMQUAL index * 8, T_LOW32, paramvalue);
AddLineQueueX(" mov %r ptr [%r+%u+4], %r (%s)", T_DWORD, T_RSP, NUMQUAL index * 8, T_HIGH32, paramvalue);
return(1);
}
else {
AddLineQueueX(" mov %r ptr [%r+%u], %s", T_DWORD, T_RSP, NUMQUAL index * 8, paramvalue);
return(1);
}
}
else {
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
size = SizeFromRegister(reg);
if (size == 0x10 && param->sym.mem_type == MT_REAL4)
{
AddLineQueueX(" %s %r ptr [%r+%u], %s", MOVE_SINGLE(), T_DWORD, T_RSP, NUMQUAL index*8, paramvalue);
return(1);
}
if (size == 0x10 && param->sym.mem_type == MT_REAL8)
{
AddLineQueueX(" %s %r ptr [%r+%u], %s", MOVE_DOUBLE(), T_QWORD, T_RSP, NUMQUAL index * 8, paramvalue);
return(1);
}
if (size == psize)
i = reg;
else {
if (size > psize || (size < psize && param->sym.mem_type == MT_PTR)) {
DebugMsg(("ms64_param(%s, param=%u): type error size.p/a=%u/%u flags=%X\n", proc->sym.name, index, psize, size, *regs_used));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
psize = size;
}
switch (psize) {
case 1: i = T_AL; break;
case 2: i = T_AX; break;
case 4: i = T_EAX; break;
default: i = T_RAX; break;
}
*regs_used |= R0_USED;
}
DebugMsg(("ms64_param(%s, param=%u): REG size.p/a=%u/%u flags=%X\n", proc->sym.name, index, psize, size, *regs_used));
}
else {
if (opnd->mem_type == MT_EMPTY)
size = (opnd->instr == T_OFFSET ? 8 : 4);
else
size = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
DebugMsg(("ms64_param(%s, param=%u): MEM size.p/a=%u/%u flags=%X\n", proc->sym.name, index, psize, size, *regs_used));
switch (psize) {
case 1: i = T_AL; break;
case 2: i = T_AX; break;
case 4: i = T_EAX; break;
default: i = T_RAX; break;
}
if (proc->sym.langtype == LANG_VECTORCALL) return(1);
*regs_used |= R0_USED;
}
if (size > psize || (size < psize && param->sym.mem_type == MT_PTR))
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
}
if (size != psize)
{
if (size == 4) {
if (IS_SIGNED(opnd->mem_type))
AddLineQueueX(" movsxd %r, %s", i, paramvalue);
else
AddLineQueueX(" mov %r, %s", i, paramvalue);
}
else
AddLineQueueX(" mov%sx %r, %s", IS_SIGNED(opnd->mem_type) ? "s" : "z", i, paramvalue);
}
else if (opnd->kind != EXPR_REG || opnd->indirect == TRUE)
AddLineQueueX(" mov %r, %s", i, paramvalue);
AddLineQueueX(" mov [%r+%u], %r", T_RSP, NUMQUAL index * 8, i);
return(1);
}
}
else if (param->sym.mem_type == MT_REAL4 || param->sym.mem_type == MT_REAL8)
{
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE) {
if (GetValueSp(reg) & OP_XMM) {
if (proc->sym.langtype == LANG_VECTORCALL)
info->vregs[index] = 1;
if (reg == T_XMM0 + index)
DebugMsg(("ms64_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
{
if (param->sym.mem_type == MT_REAL4)
AddLineQueueX(" %s %r, %s", MOVE_ALIGNED_FLOAT(), T_XMM0 + index, paramvalue);
else
AddLineQueueX(" %s %r, %s", MOVE_ALIGNED_FLOAT(), T_XMM0 + index, paramvalue);
}
return(1);
}
}
else if (opnd->kind == EXPR_REG && opnd->indirect == TRUE) {
if (reg == T_XMM0 + index)
DebugMsg(("ms64_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
{
if (param->sym.mem_type == MT_REAL4)
AddLineQueueX(" %s %r, %s", MOVE_SIMD_DWORD(), T_XMM0 + index, paramvalue);
else
AddLineQueueX(" %s %r, %s", MOVE_SIMD_QWORD(), T_XMM0 + index, paramvalue);
}
return(1);
}
if (opnd->kind == EXPR_FLOAT) {
if (proc->sym.langtype == LANG_VECTORCALL)
{
info->vregs[index] = 1;
info->xyzused[index] = 1;
}
*regs_used |= R0_USED;
if (param->sym.mem_type == MT_REAL4) {
AddLineQueueX("mov %r, %s", T_EAX, paramvalue);
AddLineQueueX("%s %r, %r", MOVE_SIMD_DWORD(), T_XMM0 + index, T_EAX);
return(1);
}
else {
AddLineQueueX("mov %r, %r ptr %s", T_RAX, T_REAL8, paramvalue);
AddLineQueueX("%s %r, %r", MOVE_SIMD_QWORD(), T_XMM0 + index, T_RAX);
return(1);
}
}
if (opnd->kind == EXPR_ADDR) {
if (proc->sym.langtype == LANG_VECTORCALL)
{
*regs_used |= R0_USED;
info->vregs[index] = 1;
info->xyzused[index] = 1;
if (opnd->sym->mem_type == MT_REAL8)
{
AddLineQueueX("%s %r,qword ptr %s", MOVE_DOUBLE(), T_XMM0 + index, paramvalue);
}
else
{
AddLineQueueX("%s %r,dword ptr %s", MOVE_SINGLE(), T_XMM0 + index, paramvalue);
}
}
else
{
if (param->sym.mem_type == MT_REAL8)
AddLineQueueX("%s %r,qword ptr %s", MOVE_SIMD_QWORD(), T_XMM0 + index, paramvalue);
else if (param->sym.mem_type == MT_REAL4)
AddLineQueueX("%s %r,dword ptr %s", MOVE_SIMD_DWORD(), T_XMM0 + index, paramvalue);
}
return(1);
}
}
if (vcallpass == 1)
goto vcalldone;
vcall:
if ((proc->sym.langtype == LANG_VECTORCALL) && (psize == 8) && (param->sym.ttype != 0) && (param->sym.ttype->e.structinfo->isHFA) && (param->sym.mem_type == MT_TYPE)) {
t = param->sym.ttype;
if (t != 0 && t->e.structinfo->isHFA && (vcallpass == 1))
{
freevecregs = 0;
vecidx = -1;
for (i = 0; i < 6; i++)
{
if (info->vregs[i] == 0)
{
if (vecidx == -1) vecidx = i;
freevecregs++;
}
}
memberCount = t->e.structinfo->memberCount;
if (memberCount > freevecregs) goto uselea;
membersize = psize / memberCount; j = 0;
tCount = memberCount;
while (tCount > 0)
{
if (info->vregs[vecidx] == 0)
{
info->vregs[vecidx] = 1;
info->vecregs[index] = memberCount; info->vsize += membersize; info->vecregsize[vecidx] = membersize; info->xyzused[vecidx] = 1; AddLineQueueX("%s %r,dword ptr [%s+%d]", MOVE_SINGLE(), T_XMM0 + vecidx, paramvalue, j* membersize);
tCount--;
j++;
}
vecidx++;
}
}
}
else if ((proc->sym.langtype == LANG_VECTORCALL) && (psize == 16) && (param->sym.ttype != 0) && (param->sym.ttype->e.structinfo->isHFA) && (param->sym.mem_type == MT_TYPE)) {
t = param->sym.ttype;
if (t != 0 && t->e.structinfo->isHFA && (vcallpass == 1))
{
freevecregs = 0;
vecidx = -1;
for (i = 0; i < 6; i++)
{
if (info->vregs[i] == 0)
{
if (vecidx == -1) vecidx = i;
freevecregs++;
}
}
memberCount = t->e.structinfo->memberCount;
if (memberCount > freevecregs) goto uselea;
membersize = psize / memberCount; j = 0;
tCount = memberCount;
if (membersize == 8)
{
while (tCount > 0)
{
if (info->vregs[vecidx] == 0)
{
info->vregs[vecidx] = 1;
info->vecregs[index] = memberCount; info->vsize += membersize; info->vecregsize[vecidx] = membersize; info->xyzused[vecidx] = 1; AddLineQueueX("%s %r,qword ptr [%s+%d]", MOVE_DOUBLE(), T_XMM0 + vecidx, paramvalue, j * membersize);
tCount--;
j++;
}
vecidx++;
}
}
else if (membersize == 4)
{
while (tCount > 0)
{
if (info->vregs[vecidx] == 0)
{
info->vregs[vecidx] = 1;
info->vecregs[index] = memberCount; info->vsize += membersize; info->vecregsize[vecidx] = membersize; info->xyzused[vecidx] = 1; AddLineQueueX("%s %r,dword ptr [%s+%d]", MOVE_SINGLE(), T_XMM0 + vecidx, paramvalue, j * membersize);
tCount--;
j++;
}
vecidx++;
}
}
}
}
else if ((proc->sym.langtype == LANG_VECTORCALL) && (psize == 12) && (param->sym.ttype != 0) && (param->sym.ttype->e.structinfo->isHFA) && (param->sym.mem_type == MT_TYPE)) {
t = param->sym.ttype;
if (t != 0 && t->e.structinfo->isHFA && (vcallpass == 1))
{
freevecregs = 0;
vecidx = -1;
for (i = 0; i < 6; i++)
{
if (info->vregs[i] == 0)
{
if (vecidx == -1) vecidx = i;
freevecregs++;
}
}
memberCount = t->e.structinfo->memberCount;
if (memberCount > freevecregs) goto uselea;
membersize = psize / memberCount; j = 0;
tCount = memberCount;
while (tCount > 0)
{
if (info->vregs[vecidx] == 0)
{
info->vregs[vecidx] = 1;
info->vecregs[index] = memberCount; info->vsize += membersize; info->vecregsize[vecidx] = membersize; info->xyzused[vecidx] = 1; AddLineQueueX("%s %r,dword ptr [%s+%d]", MOVE_SINGLE(), T_XMM0 + vecidx, paramvalue, j * membersize);
tCount--;
j++;
}
vecidx++;
}
}
}
else if ((proc->sym.langtype == LANG_VECTORCALL) && (psize == 24) && (param->sym.ttype != 0) && (param->sym.ttype->e.structinfo->isHFA) && (param->sym.mem_type == MT_TYPE)) {
t = param->sym.ttype;
if (t != 0 && t->e.structinfo->isHFA && (vcallpass == 1))
{
freevecregs = 0;
vecidx = -1;
for (i = 0; i < 6; i++)
{
if (info->vregs[i] == 0)
{
if (vecidx == -1) vecidx = i;
freevecregs++;
}
}
memberCount = t->e.structinfo->memberCount;
if (memberCount > freevecregs) goto uselea;
membersize = psize / memberCount; j = 0;
tCount = memberCount;
while (tCount > 0)
{
if (info->vregs[vecidx] == 0)
{
info->vregs[vecidx] = 1;
info->vecregs[index] = memberCount; info->vsize += membersize; info->vecregsize[vecidx] = membersize; info->xyzused[vecidx] = 1; AddLineQueueX("%s %r,qword ptr [%s+%d]", MOVE_DOUBLE(), T_XMM0 + vecidx, paramvalue, j * membersize);
tCount--;
j++;
}
vecidx++;
}
}
}
else if ((proc->sym.langtype == LANG_VECTORCALL) && (psize == 32) && (param->sym.ttype != 0) && (param->sym.ttype->e.structinfo->isHFA) && (param->sym.mem_type == MT_TYPE)) {
t = param->sym.ttype;
if (t != 0 && t->e.structinfo->isHFA && (vcallpass == 1))
{
freevecregs = 0;
vecidx = -1;
for (i = 0; i < 6; i++)
{
if (info->vregs[i] == 0)
{
if (vecidx == -1) vecidx = i;
freevecregs++;
}
}
memberCount = t->e.structinfo->memberCount;
if (memberCount > freevecregs) goto uselea;
membersize = psize / memberCount; j = 0;
tCount = memberCount;
while (tCount > 0)
{
if (info->vregs[vecidx] == 0)
{
info->vregs[vecidx] = 1;
info->vecregs[index] = memberCount; info->vsize += membersize; info->vecregsize[vecidx] = membersize; info->xyzused[vecidx] = 1; AddLineQueueX("%s %r,qword ptr [%s+%d]", MOVE_DOUBLE(), T_XMM0 + vecidx, paramvalue, j * 8);
tCount--;
j++;
}
vecidx++;
}
}
}
else {
if (addr || psize > 8) {
if (psize >= 4) {
if (proc->sym.langtype == LANG_VECTORCALL) {
if ((param->sym.mem_type == MT_TYPE)) {
t = param->sym.ttype;
if (vcallpass == 0 && opnd->kind == EXPR_REG && opnd->indirect == FALSE && reg < T_XMM6 && index < 6 && info->xyzused[(reg - T_XMM0)] != 0 && (index != reg - T_XMM0))
{
EmitErr(REGISTER_VALUE_OVERWRITTEN_BY_INVOKE, index);
return(1);
}
if (t->e.structinfo->stype == MM128 && vcallpass == 0) {
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE) {
if ((GetValueSp(reg) & OP_XMM) || t->e.structinfo->isHFA) {
t->e.structinfo->memberCount = 1;
info->vregs[index] = 1;
info->vecregs[index] = 1;
info->xyzused[index] = 1;
info->vsize += 16;
info->vecregsize[index] = 16;
if (reg == T_XMM0 + index)
DebugMsg(("ms64_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %r,oword ptr %s", MOVE_ALIGNED_FLOAT(), T_XMM0 + index, paramvalue);
return(1);
}
}
}
else if (t->e.structinfo->stype == MM256 && vcallpass == 0) {
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE) {
if (GetValueSp(reg) & OP_YMM) {
t->e.structinfo->memberCount = 1;
info->vregs[index] = 1;
info->xyzused[index] = 1;
info->vsize += 32;
info->vecregsize[index] = 32;
if (reg == T_YMM0 + index)
DebugMsg(("ms64_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("vmovaps %r,ymmword ptr %s", T_YMM0 + index, paramvalue);
return(1);
}
}
}
else if (t->e.structinfo->stype == MM512 && vcallpass == 0) {
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE) {
if (GetValueSp(reg) & OP_YMM) {
t->e.structinfo->memberCount = 1;
info->vregs[index] = 1;
info->xyzused[index] = 1;
info->vsize += 64;
info->vecregsize[index] = 64;
if (reg == T_YMM0 + index)
DebugMsg(("ms64_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("vmovaps %r,ymmword ptr %s", T_YMM0 + index, paramvalue);
return(1);
}
}
}
if (t->e.structinfo->stype == MM128)
membersize = 16;
else if (t->e.structinfo->stype == MM256)
membersize = 32;
else if (t->e.structinfo->stype == MM512)
membersize = 64;
memberCount = t->e.structinfo->memberCount;
if (t->e.structinfo->isHVA) {
if (memberCount)
membersize = psize / memberCount;
}
else if ((t->e.structinfo->isHFA) || (proc->e.procinfo->paralist->sym.type && proc->e.procinfo->paralist->sym.type->max_mbr_size == 4)) {
membersize = psize;
memberCount = 1;
}
else if (vcallpass == 0 && t->e.structinfo->stype != MM128 && t->e.structinfo->stype != MM256) {
goto uselea;
}
if (t->e.structinfo->isHFA) memberCount = 1;
info->vecregs[index] = memberCount;
info->vsize += psize;
info->vecregsize[index] = membersize;
if (((vcallpass == 1) && t->e.structinfo->isHVA) || t->e.structinfo->stype == MM128 || t->e.structinfo->stype == MM256) {
for (i = 0, j = 0; i < 6; i++) {
j += info->vregs[i];
if (info->vregs[i]) {
info->xyzused[i] = 1;
}
else if ((info->vregs[i] >= 1) && (info->xyzused[i] != 1))
info->xyzused[i] = 0;
}
if (j > 6)goto uselea;
for (i = 0, j = 0; i < 6; i++) {
if (info->xyzused[i] == 0)
j++;
}
if (vcallpass == 1 && memberCount > j && (t->e.structinfo->isHFA || t->e.structinfo->isHVA)) goto uselea;
switch (membersize) {
case 4:
for (i = 0, j = 0; i < membersize; i++) {
while (info->xyzused[j] != 0) j++;
if (i == 0) AddLineQueueX("%s %r,dword ptr %s", MOVE_SINGLE(), T_XMM0 + j, paramvalue);
else AddLineQueueX("%s %r,dword ptr [%s+%d]", MOVE_SINGLE(), T_XMM0 + j, paramvalue, i * 4);
info->xyzused[j] = 1;
}
break;
case 8:
for (i = 0, j = 0; i < memberCount; i++) {
while (info->xyzused[j] != 0) j++;
if (i == 0) AddLineQueueX("%s %r,oword ptr %s", MOVE_DOUBLE(), T_XMM0 + j, paramvalue);
else AddLineQueueX("%s %r,oword ptr [%s+%d]", MOVE_DOUBLE(), T_XMM0 + j, paramvalue, i * 8);
info->xyzused[j] = 1;
}
break;
case 16:
if ((vcallpass == 0) && t->e.structinfo->stype == MM128)
{
AddLineQueueX("%s %r,oword ptr %s", MOVE_ALIGNED_FLOAT(), T_XMM0 + index, paramvalue);
info->xyzused[index] = 1;
}
else if ((vcallpass == 1) && (t->e.structinfo->isHFA || t->e.structinfo->isHVA))
{
for (i = 0, j = 0; i < memberCount; i++) {
while (info->xyzused[j] != 0) j++;
if (i == 0) AddLineQueueX("%s %r,oword ptr %s", MOVE_ALIGNED_FLOAT(), T_XMM0 + j, paramvalue);
else AddLineQueueX("%s %r,oword ptr [%s+%d]", MOVE_ALIGNED_FLOAT(), T_XMM0 + j, paramvalue, i * 16);
info->xyzused[j] = 1;
}
}
break;
case 32:
if ((vcallpass == 0) && t->e.structinfo->stype == MM256)
{
AddLineQueueX("vmovups %r,oword ptr %s", T_YMM0 + index, paramvalue);
info->xyzused[index] = 1;
}
else if ((vcallpass == 1) && (t->e.structinfo->isHFA || t->e.structinfo->isHVA))
{
for (i = 0, j = 0; i < memberCount; i++) {
while (info->xyzused[j] != 0) j++;
if (i == 0) AddLineQueueX("vmovups %r,ymmword ptr %s", T_YMM0 + j, paramvalue);
else AddLineQueueX("vmovups %r,ymmword ptr [%s+%d]", T_YMM0 + j, paramvalue, i * 32);
info->xyzused[j] = 1;
}
}
break;
case 64:
if ((vcallpass == 1) && (t->e.structinfo->isHFA || t->e.structinfo->isHVA))
{
for (i = 0, j = 0; i < memberCount; i++) {
while (info->xyzused[j] != 0) j++;
if (i == 0) AddLineQueueX("vmovups %r,zmmword ptr %s", T_ZMM0 + j, paramvalue);
else AddLineQueueX("vmovups %r,zmmword ptr [%s+%d]", T_ZMM0 + j, paramvalue, i * 64);
info->xyzused[j] = 1;
}
}
break;
}
}
}
else if (vcallpass == 0) {
switch (psize) {
case 4:
if (opnd->kind == EXPR_FLOAT) {
AddLineQueueX("%s %r,dword ptr %s", MOVE_SINGLE(), T_XMM0 + index, paramvalue);
info->vregs[index] = 1;
}
else
AddLineQueueX("mov %r, qword ptr %s", ms64_regs[index + 2 * 4], paramvalue);
break;
case 8:
if (opnd->kind == EXPR_FLOAT) {
AddLineQueueX("%s %r,qword ptr %s", MOVE_DOUBLE(), T_XMM0 + index, paramvalue);
info->vregs[index] = 1;
}
else
AddLineQueueX("mov %r, qword ptr %s", ms64_regs[index + 2 * 4], paramvalue);
break;
case 16:
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE) {
if (GetValueSp(reg) & OP_XMM) {
if (reg == T_XMM0 + index)
DebugMsg(("ms64_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %r,oword ptr %s", MOVE_ALIGNED_FLOAT(), T_XMM0 + index, paramvalue);
}
}
else
AddLineQueueX("%s %r,oword ptr %s", MOVE_ALIGNED_FLOAT(), T_XMM0 + index, paramvalue);
info->vregs[index] = 1;
break;
case 32:
info->vregs[index] = 1;
AddLineQueueX("vmovups %r,oword ptr %s", T_YMM0 + index, paramvalue);
break;
case 64:
info->vregs[index] = 1;
AddLineQueueX("vmovups %r,zmmword ptr %s", T_ZMM0 + index, paramvalue);
break;
}
}
}
else
{
uselea:
if ((proc->sym.langtype == LANG_VECTORCALL))
{
if (index < 4)
{
*regs_used |= (1 << (index + RPAR_START));
info->vecregs[index] = 0;
AddLineQueueX(" lea %r, %s", ms64_regs[index + 2 * 4 + (psize > 4 ? 4 : 0)], paramvalue);
}
else
{
*regs_used |= R0_USED;
AddLineQueueX(" lea %r, %s", T_RAX, paramvalue);
AddLineQueueX(" mov qword ptr [%r+%u], %r", T_RSP, NUMQUAL index * 8, T_RAX);
return(1);
}
}
else
{
*regs_used |= (1 << (index + RPAR_START));
AddLineQueueX(" lea %r, %s", ms64_regs[index + 2 * 4 + (psize > 4 ? 4 : 0)], paramvalue);
}
}
}
else
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
if (vcallpass == 0)
{
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE) {
reg = opnd->base_reg->tokval;
size = SizeFromRegister(reg);
}
else if (opnd->kind == EXPR_CONST || opnd->kind == EXPR_FLOAT) {
size = psize;
}
else if (opnd->mem_type != MT_EMPTY) {
size = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
}
else if (opnd->kind == EXPR_ADDR && opnd->sym != NULL && opnd->sym->state == SYM_UNDEFINED) {
DebugMsg1(("ms64_param(%s, param=%u): forward ref=%s, assumed size=%u\n", proc->sym.name, index, opnd->sym->name, psize));
size = psize;
}
else if (opnd->kind == EXPR_ADDR && opnd->sym == NULL) {
size = psize;
}
else if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
size = psize;
}
else
size = (opnd->instr == T_OFFSET ? 8 : 4);
if (size > psize || (size < psize && param->sym.mem_type == MT_PTR)) {
DebugMsg(("ms64_param(%s, param=%u): type error size.p/a=%u/%u flags=%X\n", proc->sym.name, index, psize, size, *regs_used));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
}
j = 4;
switch (psize)
{
case 1: base = 0 * j; break;
case 2: base = 1 * j; break;
case 4: base = 2 * j; break;
default:base = 3 * j; break;
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
if (GetValueSp(reg) & OP_R) {
if (ms64_regs[index + base] == reg) {
DebugMsg(("ms64_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
return(1);
}
i = GetRegNo(reg);
if (REGPAR_WIN64 & (1 << i)) {
i = GetParmIndex(i);
if (*regs_used & (1 << (i + RPAR_START)))
EmitErr(REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
}
}
}
if (size < psize)
{
if (size == 4)
{
if (IS_SIGNED(opnd->mem_type))
AddLineQueueX(" movsxd %r, %s", ms64_regs[index + base], paramvalue);
else
AddLineQueueX(" mov %r, %s", ms64_regs[index + 2 * 4], paramvalue);
}
else
AddLineQueueX(" mov%sx %r, %s", IS_SIGNED(opnd->mem_type) ? "s" : "z", ms64_regs[index + base], paramvalue);
*regs_used |= (1 << (index + RPAR_START));
}
else
{
*regs_used |= (1 << (index + RPAR_START));
DebugMsg1(("ms64_param(%s, param=%u): size=%u flags=%X\n", proc->sym.name, index, size, *regs_used));
sym = SymLookup(paramvalue);
if ( (sym && sym->isequate && sym->value == 0) || (!strcasecmp(paramvalue, "0") || (!strcasecmp(paramvalue, "NULL")) || (!strcasecmp(paramvalue, "FALSE") ) ) )
{
if (ms64_regs[index + base] > T_R9D)
index -= 4;
AddLineQueueX(" xor %r, %r", ms64_regs[index + base], ms64_regs[index + base]);
return(1);
}
else
{
if (index > 3)
{
switch (psize) {
case 1: i = T_BYTE; break;
case 2: i = T_WORD; break;
case 4: i = T_DWORD; break;
default: i = T_QWORD; break;
}
AddLineQueueX(" mov %r ptr [%r+%u], %s", i, T_RSP, NUMQUAL index * 8, paramvalue);
}
else
AddLineQueueX(" mov %r, %s", ms64_regs[index + base], paramvalue);
}
}
}
}
vcalldone:
return(1);
}
#endif
#if SYSV_SUPPORT
static int sysv_fcstart(struct dsym const *proc, int numparams, int start, struct asm_tok tokenarray[], int *value)
{
if (proc->e.procinfo->has_vararg)
{
for (numparams = 0; tokenarray[start].token != T_FINAL; start++)
if (tokenarray[start].token == T_COMMA)
numparams++;
}
if (CurrProc)
CurrProc->e.procinfo->stackAdj = 0;
return(0); }
static void sysv_fcend(struct dsym const *proc, int numparams, int value)
{
if (proc->e.procinfo->stackAdj != 0)
AddLineQueueX("add %r, %d", T_RSP, NUMQUAL 8);
proc->e.procinfo->stackAdj = 0;
return;
}
static int sysv_reg( unsigned int reg )
{
int i;
int base = -1;
if (GetValueSp(reg) & OP_XMM || GetValueSp(reg) & OP_YMM || GetValueSp(reg) & OP_ZMM)
{
i = GetRegNo(reg);
base = i;
}
else
{
i = GetRegNo(reg);
switch (i)
{
case 7:
base = 0;
break;
case 6:
base = 1;
break;
case 2:
base = 2;
break;
case 1:
base = 3;
break;
case 8:
base = 4;
break;
case 9:
base = 5;
break;
case 0:
base = 6;
break;
}
}
return(base);
}
static int sysv_regTo64(unsigned int reg)
{
unsigned int resultReg = T_RAX;
if (GetValueSp(reg) & OP_XMM || GetValueSp(reg) & OP_YMM || GetValueSp(reg) & OP_ZMM)
{
return(reg);
}
else
{
switch (reg)
{
case T_AL:
case T_AH:
case T_AX:
case T_EAX:
case T_RAX:
resultReg = T_RAX;
break;
case T_BL:
case T_BH:
case T_BX:
case T_EBX:
case T_RBX:
resultReg = T_RBX;
break;
case T_CL:
case T_CH:
case T_CX:
case T_ECX:
case T_RCX:
resultReg = T_RCX;
break;
case T_DL:
case T_DH:
case T_DX:
case T_EDX:
case T_RDX:
resultReg = T_RDX;
break;
case T_SIL:
case T_SI:
case T_ESI:
case T_RSI:
resultReg = T_RSI;
break;
case T_DIL:
case T_DI:
case T_EDI:
case T_RDI:
resultReg = T_RDI;
break;
case T_BPL:
case T_BP:
case T_EBP:
case T_RBP:
resultReg = T_RBP;
break;
case T_SPL:
case T_SP:
case T_ESP:
case T_RSP:
resultReg = T_RSP;
break;
case T_R8B:
case T_R8D:
case T_R8:
resultReg = T_R8;
break;
case T_R9B:
case T_R9D:
case T_R9:
resultReg = T_R9;
break;
case T_R10B:
case T_R10D:
case T_R10:
resultReg = T_R10;
break;
case T_R11B:
case T_R11D:
case T_R11:
resultReg = T_R11;
break;
case T_R12B:
case T_R12D:
case T_R12:
resultReg = T_R12;
break;
case T_R13B:
case T_R13D:
case T_R13:
resultReg = T_R13;
break;
case T_R14B:
case T_R14D:
case T_R14:
resultReg = T_R14;
break;
case T_R15B:
case T_R15D:
case T_R15:
resultReg = T_R15;
break;
}
return(resultReg);
}
}
static int sysv_GetNextGPR(struct proc_info *info, int size)
{
int base = 0;
switch (size)
{
case 1:
base = 0;
break;
case 2:
base = 1;
break;
case 4:
base = 2;
break;
case 8:
base = 3;
break;
default:
base = 3;
break;
}
if (info->firstGPR >= 6)
return(-1);
return(sysV64_regs[(base*6)+info->firstGPR++]);
}
static int sysv_GetNextVEC(struct proc_info *info, int size)
{
if (info->firstVEC >= 8)
return(-1);
if(size == 16)
return(sysV64_regsXMM[info->firstVEC++]);
if (size == 32)
return(sysV64_regsYMM[info->firstVEC++]);
if (size == 64)
return(sysV64_regsZMM[info->firstVEC++]);
}
static int sysv_vararg_param(struct dsym const *proc, int index, struct dsym *param, bool addr, struct expr *opnd, char *paramvalue, uint_8 *regs_used)
{
uint_32 psize;
int reg;
int regsize;
struct proc_info *info = proc->e.procinfo;
DebugMsg1(("sysv_vararg_param(%s, index=%u, param.memtype=%Xh, addr=%u) enter\n", proc->sym.name, index, param->sym.mem_type, addr));
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (opnd->kind == EXPR_CONST && !addr)
{
if (psize == 0) psize = 8;
reg = sysv_GetNextGPR( info, psize );
if (reg != -1)
{
if ((!strcasecmp(paramvalue, "0") || (!strcasecmp(paramvalue, "NULL")) || (!strcasecmp(paramvalue, "FALSE"))))
AddLineQueueX("xor %r, %r", reg, reg);
else
AddLineQueueX("mov %r, %s", reg, paramvalue);
reg = sysv_reg(reg);
*regs_used |= (1 << reg);
}
else
{
if ( (opnd->value64 > H_LONG_MAX || opnd->value64 < H_LONG_MIN) )
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov %r ptr [%r+4], %r ( %s )", T_DWORD, T_RSP, T_HIGH32, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov %r ptr [%r], %r ( %s )", T_DWORD, T_RSP, T_LOW32, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub rsp,8");
}
else
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8;
}
return(1);
}
if (opnd->kind == EXPR_FLOAT)
{
if (psize == 0) psize = 4; reg = sysv_GetNextVEC(info, 16); if (reg != -1)
{
if ( (!strcasecmp(paramvalue, "0.0")) || (!strcasecmp(paramvalue, "0")) )
{
if(ModuleInfo.arch == ARCH_AVX)
AddLineQueueX("vxorps %r, %r, %r", reg, reg, reg);
else
AddLineQueueX("xorps %r, %r", reg, reg);
}
else
{
if (psize == 4)
{
AddLineQueueX("mov %r, %s", T_EAX, paramvalue);
AddLineQueueX("%s %r, %r", MOVE_SIMD_DWORD(), reg, T_EAX);
}
else if (psize == 8)
{
AddLineQueueX("mov %r, %r ptr %s", T_RAX, T_REAL8, opnd->float_tok->string_ptr);
AddLineQueueX("%s %r, %r", MOVE_SIMD_QWORD(), reg, T_RAX);
}
}
*regs_used |= (1 << 6);
info->vecused |= (1 << sysv_reg(reg));
info->vararg_vecs++;
}
else
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
regsize = SizeFromRegister(reg);
if (GetValueSp(reg) & OP_R)
reg = sysv_GetNextGPR(info, regsize);
else if (GetValueSp(reg) & OP_XMM)
reg = sysv_GetNextVEC(info, 16);
else if (GetValueSp(reg) & OP_YMM)
reg = sysv_GetNextVEC(info, 32);
else if (GetValueSp(reg) & OP_ZMM)
reg = sysv_GetNextVEC(info, 64);
if (reg != -1)
{
if (GetValueSp(opnd->base_reg->tokval) & OP_R)
{
AddLineQueueX("mov %r, %s", reg, paramvalue);
*regs_used |= (1 << sysv_reg(reg));
}
else
{
AddLineQueueX("%s %r, %s", MOVE_ALIGNED_INT(), reg, paramvalue);
info->vecused |= (1 << sysv_reg(reg));
info->vararg_vecs++;
}
}
else
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_R)
{
if (regsize == 8)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
}
else if (regsize == 4)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsxd %r, %s", sysv_regTo64(reg), paramvalue);
}
else if (regsize == 2)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx %r, %s", sysv_regTo64(reg), paramvalue);
}
else if (regsize == 1)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx %r, %s", sysv_regTo64(reg), paramvalue);
}
info->stackOfs += 8;
info->stackAdj += 8; }
else if (GetValueSp(reg) & OP_XMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r], %s", MOVE_ALIGNED_INT(), T_RSP, paramvalue);
if (info->stackOfs % 16 != 0)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 24", T_RSP);
info->stackOfs += 24;
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 16", T_RSP);
info->stackOfs += 16;
}
}
else if (GetValueSp(reg) & OP_YMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymmword ptr [%r], %s", MOVE_UNALIGNED_INT(), T_RSP, paramvalue);
if (info->stackOfs % 16 != 0)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 40", T_RSP);
info->stackOfs += 40;
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 32", T_RSP);
info->stackOfs += 32;
}
}
else if (GetValueSp(reg) & OP_ZMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmmword ptr [%r], %s", MOVE_UNALIGNED_INT(), T_RSP, paramvalue);
if (info->stackOfs % 16 != 0)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 72", T_RSP);
info->stackOfs += 72;
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 64", T_RSP);
info->stackOfs += 64;
}
}
}
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
if (psize == 0) psize = 8; reg = sysv_GetNextGPR(info, psize);
if (reg != -1)
{
AddLineQueueX("mov %r, %s", reg, paramvalue);
*regs_used |= (1 << sysv_reg(reg));
}
else
{
if (psize == 8)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 4)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsxd rax, eax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov eax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 2)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, ax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov ax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 1)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, al");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov al, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
}
return(1);
}
if (opnd->kind == EXPR_ADDR && !addr && ((opnd->sym && ((opnd->sym->type &&
_stricmp(opnd->sym->type->name, "__m128") != 0 &&
_stricmp(opnd->sym->type->name, "__m256") != 0 &&
_stricmp(opnd->sym->type->name, "__m512") != 0) || !opnd->sym->type)) || !opnd->sym) )
{
if (psize == 0) psize = 8; reg = sysv_GetNextGPR(info, psize);
if (reg != -1)
{
AddLineQueueX("mov %r, %s", reg, paramvalue);
*regs_used |= (1 << sysv_reg(reg));
}
else
{
if (psize == 8)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 4)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsxd rax, eax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov eax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 2)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, ax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov ax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 1)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, al");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov al, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
}
return(1);
}
if ( opnd->sym && (opnd->sym->mem_type == MT_TYPE || opnd->kind == EXPR_ADDR) && opnd->sym->type && _stricmp(opnd->sym->type->name, "__m128") == 0 )
{
reg = sysv_GetNextVEC(info, 16);
if (reg != -1)
{
AddLineQueueX("%s %r, xmmword ptr %s", MOVE_ALIGNED_INT(), reg, paramvalue);
info->vecused |= (1 << sysv_reg(reg));
info->vararg_vecs++;
}
else
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r+%u], xmm8", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r], xmm8", MOVE_ALIGNED_INT(), T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 16", T_RSP);
info->stackOfs += 16;
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmm8, xmmword ptr %s", MOVE_ALIGNED_INT(), paramvalue);
}
return(1);
}
if ( opnd->sym && (opnd->sym->mem_type == MT_TYPE || opnd->kind == EXPR_ADDR) && opnd->sym->type && _stricmp(opnd->sym->type->name, "__m256") == 0)
{
reg = sysv_GetNextVEC(info, 32);
if (reg != -1)
{
AddLineQueueX("%s %r, ymmword ptr %s", MOVE_ALIGNED_INT(), reg, paramvalue);
info->vecused |= (1 << sysv_reg(reg));
info->vararg_vecs++;
}
else
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymmword ptr [%r+%u], ymm8", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymmword ptr [%r], ymm8", MOVE_UNALIGNED_INT(), T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 32", T_RSP);
info->stackOfs += 32;
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymm8, ymmword ptr %s", MOVE_UNALIGNED_INT(), paramvalue);
}
return(1);
}
if ( opnd->sym && (opnd->sym->mem_type == MT_TYPE || opnd->kind == EXPR_ADDR) && opnd->sym->type && _stricmp(opnd->sym->type->name, "__m512") == 0)
{
reg = sysv_GetNextVEC(info, 64);
if (reg != -1)
{
AddLineQueueX("%s %r, zmmword ptr %s", MOVE_ALIGNED_INT(), reg, paramvalue);
info->vecused |= (1 << sysv_reg(reg));
info->vararg_vecs++;
}
else
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmmword ptr [%r+%u], zmm8", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmmword ptr [%r], zmm8", MOVE_UNALIGNED_INT(), T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 64", T_RSP);
info->stackOfs += 64;
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmm8, zmmword ptr %s", MOVE_UNALIGNED_INT(), paramvalue);
}
return(1);
}
if (addr || psize > 8)
{
if (psize < 8)
psize = 8;
reg = sysv_GetNextGPR(info, 8); if (reg != -1)
{
if (psize >= 4)
AddLineQueueX("lea %r, %s", reg, paramvalue);
else
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
*regs_used |= (1 << reg);
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "lea rax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
return(1);
}
return(1);
}
static int sysv_param(struct dsym const *proc, int index, struct dsym *param, bool addr, struct expr *opnd, char *paramvalue, uint_8 *regs_used)
{
uint_32 psize;
int reg;
int reg2;
int i;
int base;
int regsize;
struct proc_info *info = proc->e.procinfo;
bool destroyed = FALSE;
DebugMsg1(("sysv_param(%s, index=%u, param.memtype=%Xh, addr=%u) enter\n", proc->sym.name, index, param->sym.mem_type, addr));
if (opnd->base_reg != NULL)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_XMM || GetValueSp(reg) & OP_YMM || GetValueSp(reg) & OP_ZMM)
{
i = sysv_reg(reg);
if (i <= 7 && info->vecused & (1 << i))
destroyed = TRUE;
}
}
if (opnd->base_reg != NULL) {
reg = sysv_regTo64(opnd->base_reg->tokval); if (GetValueSp(reg) & OP_R)
{
base = sysv_reg(reg);
if (base <= 6 && *regs_used & (1 << base))
destroyed = TRUE;
}
}
if (opnd->idx_reg != NULL) {
reg2 = sysv_regTo64(opnd->idx_reg->tokval);
if (GetValueSp(reg2) & OP_R)
{
base = sysv_reg(reg);
if (base <= 6 && *regs_used & (1 << base))
destroyed = TRUE;
}
}
if (destroyed)
{
EmitErr(REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
*regs_used = 0;
return(ERROR);
}
if (param->sym.is_vararg)
{
return(sysv_vararg_param(proc, index, param, addr, opnd, paramvalue, regs_used));
}
if ( param->sym.string_ptr )
{
if (param->sym.mem_type == MT_REAL4)
{
reg = param->sym.tokval;
info->vecused |= (1 << sysv_reg(reg));
if (opnd->kind == EXPR_FLOAT)
{
*regs_used |= (1 << 6);
AddLineQueueX("mov %r, %s", T_EAX, paramvalue);
AddLineQueueX("%s %s, %r", MOVE_SIMD_DWORD(), param->sym.string_ptr, T_EAX);
return(1);
}
if (opnd->kind == EXPR_CONST)
{
*regs_used |= (1 << 6);
AddLineQueueX("mov %r, %s.0", T_EAX, paramvalue);
AddLineQueueX("%s %s, %r", MOVE_SIMD_DWORD(), param->sym.string_ptr, T_EAX);
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_XMM)
{
if ( _stricmp(param->sym.string_ptr, paramvalue) == 0 )
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %s, %s", MOVE_ALIGNED_FLOAT(), param->sym.string_ptr, paramvalue);
return(1);
}
else
{
EmitErr( INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1 );
return(1);
}
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
if (_stricmp(param->sym.string_ptr, paramvalue) == 0)
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %s, %s", MOVE_SIMD_DWORD(), param->sym.string_ptr, paramvalue);
return(1);
}
if (opnd->kind == EXPR_ADDR)
{
AddLineQueueX("%s %s,dword ptr %s", MOVE_SIMD_DWORD(), param->sym.string_ptr, paramvalue);
return(1);
}
}
if (param->sym.mem_type == MT_REAL8)
{
reg = param->sym.tokval;
info->vecused |= (1 << sysv_reg(reg));
if (opnd->kind == EXPR_FLOAT)
{
*regs_used |= (1<<6);
AddLineQueueX("mov %r, %r ptr %s", T_RAX, T_REAL8, paramvalue);
AddLineQueueX("%s %s, %r", MOVE_SIMD_QWORD(), param->sym.string_ptr, T_RAX);
return(1);
}
if (opnd->kind == EXPR_CONST)
{
*regs_used |= (1 << 6);
AddLineQueueX("mov %r, %r ptr %s.0", T_RAX, T_REAL8, paramvalue);
AddLineQueueX("%s %s, %r", MOVE_SIMD_QWORD(), param->sym.string_ptr, T_RAX);
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_XMM)
{
if (_stricmp(param->sym.string_ptr, paramvalue) == 0)
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %s, %s", MOVE_ALIGNED_FLOAT(), param->sym.string_ptr, paramvalue);
return(1);
}
else
{
EmitErr( INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
if (_stricmp(param->sym.string_ptr, paramvalue) == 0)
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %s, %s", MOVE_SIMD_QWORD(), param->sym.string_ptr, paramvalue);
return(1);
}
if (opnd->kind == EXPR_ADDR)
{
AddLineQueueX("%s %s,dword ptr %s", MOVE_SIMD_QWORD(), param->sym.string_ptr, paramvalue);
return(1);
}
}
if ( param->sym.mem_type == MT_OWORD || (param->sym.mem_type == MT_TYPE && _stricmp(param->sym.type->name, "__m128") == 0) )
{
reg = param->sym.tokval;
info->vecused |= (1 << sysv_reg(reg));
psize = 0;
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
psize = SizeFromRegister(opnd->base_reg->tokval);
else if (opnd->mem_type != MT_EMPTY)
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_XMM)
{
if (_stricmp(param->sym.string_ptr, paramvalue) == 0)
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %s, %s", MOVE_ALIGNED_INT(), param->sym.string_ptr, paramvalue);
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
AddLineQueueX("%s %s, xmmword ptr %s", MOVE_ALIGNED_INT(), param->sym.string_ptr, paramvalue);
return(1);
}
if (opnd->kind == EXPR_ADDR && !addr)
{
if (psize == param->sym.total_size || opnd->mem_type == MT_EMPTY)
AddLineQueueX("%s %s, xmmword ptr %s", MOVE_ALIGNED_INT(), param->sym.string_ptr, paramvalue);
else
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
if ( param->sym.mem_type == MT_YMMWORD || (param->sym.mem_type == MT_TYPE && _stricmp(param->sym.type->name, "__m256") == 0) )
{
reg = param->sym.tokval;
info->vecused |= (1 << sysv_reg(reg));
psize = 0;
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
psize = SizeFromRegister(opnd->base_reg->tokval);
else if (opnd->mem_type != MT_EMPTY)
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_YMM)
{
if (_stricmp(param->sym.string_ptr, paramvalue) == 0)
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("vmovdqa %s, %s", param->sym.string_ptr, paramvalue);
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
AddLineQueueX("vmovdqu %s, ymmword ptr %s", param->sym.string_ptr, paramvalue);
return(1);
}
if (opnd->kind == EXPR_ADDR && !addr)
{
if (psize == param->sym.total_size || opnd->mem_type == MT_EMPTY)
AddLineQueueX("vmovdqu %s, ymmword ptr %s", param->sym.string_ptr, paramvalue);
else
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
if ( param->sym.mem_type == MT_ZMMWORD || (param->sym.mem_type == MT_TYPE && _stricmp(param->sym.type->name, "__m512") == 0) )
{
reg = param->sym.tokval;
info->vecused |= (1 << sysv_reg(reg));
psize = 0;
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
psize = SizeFromRegister(opnd->base_reg->tokval);
else if (opnd->mem_type != MT_EMPTY)
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_ZMM)
{
if (_stricmp(param->sym.string_ptr, paramvalue) == 0)
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("%s %s, %s", MOVE_ALIGNED_INT(), param->sym.string_ptr, paramvalue);
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
AddLineQueueX("%s %s, zmmword ptr %s", MOVE_UNALIGNED_INT(), param->sym.string_ptr, paramvalue);
return(1);
}
if (opnd->kind == EXPR_ADDR && !addr)
{
if (psize == param->sym.total_size || opnd->mem_type == MT_EMPTY)
AddLineQueueX("%s %s, zmmword ptr %s", MOVE_UNALIGNED_INT(), param->sym.string_ptr, paramvalue);
else
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
if (param->sym.mem_type == MT_BYTE || param->sym.mem_type == MT_WORD || param->sym.mem_type == MT_DWORD || param->sym.mem_type == MT_QWORD ||
param->sym.mem_type == MT_SBYTE || param->sym.mem_type == MT_SWORD || param->sym.mem_type == MT_SDWORD || param->sym.mem_type == MT_SQWORD || param->sym.mem_type == MT_PTR)
{
psize = 0;
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
psize = SizeFromRegister(opnd->base_reg->tokval);
else if (opnd->mem_type != MT_EMPTY)
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (addr || opnd->instr == T_OFFSET)
psize = 8;
if (param->sym.mem_type == MT_PTR && psize != 8)
{
EmitErr( INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
if (opnd->kind == EXPR_CONST && !addr) {
if ((!strcasecmp(paramvalue, "0") || (!strcasecmp(paramvalue, "NULL")) || (!strcasecmp(paramvalue, "FALSE"))))
AddLineQueueX("xor %s, %s", param->sym.string_ptr, param->sym.string_ptr);
else
AddLineQueueX("mov %s, %s", param->sym.string_ptr, paramvalue);
reg = sysv_reg(param->sym.tokval);
*regs_used |= (1 << reg);
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_R)
{
if (_stricmp(param->sym.string_ptr, paramvalue) == 0)
DebugMsg(("sysv_param(%s, param=%u): argument optimized\n", proc->sym.name, index));
else
AddLineQueueX("mov %s, %s", param->sym.string_ptr, paramvalue);
reg = sysv_reg(param->sym.tokval);
*regs_used |= (1 << reg);
return(1);
}
else
{
EmitErr( INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
AddLineQueueX("mov %s, %s", param->sym.string_ptr, paramvalue);
reg = sysv_reg(param->sym.tokval);
*regs_used |= (1 << reg);
return(1);
}
if (opnd->kind == EXPR_ADDR && !addr)
{
if (psize == param->sym.total_size || opnd->mem_type == MT_EMPTY)
AddLineQueueX("mov %s, %s", param->sym.string_ptr, paramvalue);
else
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
reg = sysv_reg(param->sym.tokval);
*regs_used |= (1 << reg);
return(1);
}
if (addr || psize > 8)
{
if (psize >= 4)
AddLineQueueX("lea %s, %s", param->sym.string_ptr, paramvalue);
else
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
reg = sysv_reg(param->sym.tokval);
if(reg != -1)
*regs_used |= (1 << reg);
return(1);
}
}
EmitErr(INVOKE_ARGUMENT_NOT_SUPPORTED, index+1);
}
else
{
if (param->sym.mem_type == MT_REAL4)
{
psize = 0;
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (psize == 0) psize = 4;
if (opnd->kind == EXPR_FLOAT)
{
*regs_used |= (1 << 6);
BuildCodeLine(info->stackOps[info->stackOpCount++], "push %r", T_RAX);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov %r, %s", T_EAX, paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
if (opnd->kind == EXPR_CONST)
{
*regs_used |= (1 << 6);
AddLineQueueX("mov %r, %s.0", T_EAX, paramvalue);
AddLineQueueX("%s %s, %r", MOVE_SIMD_DWORD(), param->sym.string_ptr, T_EAX);
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_XMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s [%r], %s", MOVE_SINGLE(), T_RSP, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 8", T_RSP);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
*regs_used |= (1 << 6);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov [%r], eax", T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov eax, dword ptr %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 8", T_RSP);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
if (opnd->kind == EXPR_ADDR)
{
if (psize == 4)
{
*regs_used |= (1 << 6);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov [%r], eax", T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov eax, dword ptr %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 8", T_RSP);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
}
return(1);
}
if (param->sym.mem_type == MT_REAL8)
{
psize = 0;
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (psize == 0) psize = 8;
if (opnd->kind == EXPR_FLOAT)
{
*regs_used |= (1 << 6);
BuildCodeLine(info->stackOps[info->stackOpCount++], "push %r", T_RAX);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov %r, %r ptr %s", T_RAX, T_REAL8, paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
if (opnd->kind == EXPR_CONST)
{
*regs_used |= (1 << 6);
BuildCodeLine(info->stackOps[info->stackOpCount++], "push %r", T_RAX);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov %r, %r ptr %s.0", T_RAX, T_REAL8, paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_XMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s [%r], %s", MOVE_DOUBLE(), T_RSP, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 8", T_RSP);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
*regs_used |= (1 << 6);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov [%r], rax", T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov rax, qword ptr %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 8", T_RSP);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
if (opnd->kind == EXPR_ADDR)
{
if (psize == 8)
{
*regs_used |= (1 << 6);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov [%r], rax", T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov rax, qword ptr %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 8", T_RSP);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
}
return(1);
}
if (param->sym.mem_type == MT_OWORD || (param->sym.mem_type == MT_TYPE && _stricmp(param->sym.type->name, "__m128") == 0))
{
if (opnd->kind == EXPR_REG)
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r+%u], %s", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj, paramvalue);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r], %s", MOVE_ALIGNED_INT(), T_RSP, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 16", T_RSP);
info->stackOfs += 16;
}
else
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r+%u], xmm8", MOVE_ALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r], xmm8", MOVE_ALIGNED_INT(), T_RSP);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 16", T_RSP);
info->stackOfs += 16;
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmm8, xmmword ptr %s", MOVE_ALIGNED_INT(), paramvalue);
}
return(1);
}
if (param->sym.mem_type == MT_YMMWORD || (param->sym.mem_type == MT_TYPE && _stricmp(param->sym.type->name, "__m256") == 0))
{
if (opnd->kind == EXPR_REG)
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymmword ptr [%r+%u], %s", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj, paramvalue);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymmword ptr [%r], %s", MOVE_UNALIGNED_INT(), T_RSP, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 32", T_RSP);
info->stackOfs += 32;
}
else
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymmword ptr [%r+%u], ymm8", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 32", T_RSP);
info->stackOfs += 32;
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymm8, ymmword ptr %s", MOVE_UNALIGNED_INT(), paramvalue);
}
return(1);
}
if (param->sym.mem_type == MT_OWORD || (param->sym.mem_type == MT_TYPE && _stricmp(param->sym.type->name, "__m512") == 0))
{
if (opnd->kind == EXPR_REG)
{
if (info->stackOfs % 16 != 0)
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmmword ptr [%r+%u], %s", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj, paramvalue);
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmmword ptr [%r], %s", MOVE_UNALIGNED_INT(), T_RSP, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 64", T_RSP);
info->stackOfs += 64;
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmmword ptr [%r+%u], zmm8", MOVE_UNALIGNED_INT(), T_RSP, NUMQUAL info->stackAdj);
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 64", T_RSP);
info->stackOfs += 64;
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmm8, zmmword ptr %s", MOVE_UNALIGNED_INT(), paramvalue);
}
return(1);
}
if (param->sym.mem_type == MT_BYTE || param->sym.mem_type == MT_WORD || param->sym.mem_type == MT_DWORD || param->sym.mem_type == MT_QWORD ||
param->sym.mem_type == MT_SBYTE || param->sym.mem_type == MT_SWORD || param->sym.mem_type == MT_SDWORD || param->sym.mem_type == MT_SQWORD || param->sym.mem_type == MT_PTR)
{
psize = 0;
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
psize = SizeFromRegister(opnd->base_reg->tokval);
else if (opnd->mem_type != MT_EMPTY)
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (addr || opnd->instr == T_OFFSET)
psize = 8;
if (param->sym.mem_type == MT_PTR && psize != 8)
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
if (opnd->kind == EXPR_CONST && !addr) {
if ((opnd->value64 > H_LONG_MAX || opnd->value64 < H_LONG_MIN))
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov %r ptr [%r+4], %r ( %s )", T_DWORD, T_RSP, T_HIGH32, paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov %r ptr [%r], %r ( %s )", T_DWORD, T_RSP, T_LOW32, paramvalue);
}
else
BuildCodeLine(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == FALSE)
{
reg = opnd->base_reg->tokval;
regsize = SizeFromRegister(reg);
if (GetValueSp(reg) & OP_R)
reg = sysv_GetNextGPR(info, regsize);
else if (GetValueSp(reg) & OP_XMM)
reg = sysv_GetNextVEC(info, 16);
else if (GetValueSp(reg) & OP_YMM)
reg = sysv_GetNextVEC(info, 32);
else if (GetValueSp(reg) & OP_ZMM)
reg = sysv_GetNextVEC(info, 64);
reg = opnd->base_reg->tokval;
if (GetValueSp(reg) & OP_R)
{
if (regsize == 8)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
}
else if (regsize == 4)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsxd %r, %s", sysv_regTo64(reg), paramvalue);
}
else if (regsize == 2)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx %r, %s", sysv_regTo64(reg), paramvalue);
}
else if (regsize == 1)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx %r, %s", sysv_regTo64(reg), paramvalue);
}
info->stackOfs += 8;
info->stackAdj += 8; }
else if (GetValueSp(reg) & OP_XMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s xmmword ptr [%r], %s", MOVE_ALIGNED_INT(), T_RSP, paramvalue);
if (info->stackOfs % 16 != 0)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 24", T_RSP);
info->stackOfs += 24;
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 16", T_RSP);
info->stackOfs += 16;
}
}
else if (GetValueSp(reg) & OP_YMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s ymmword ptr [%r], %s", MOVE_UNALIGNED_INT(), T_RSP, paramvalue);
if (info->stackOfs % 16 != 0)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 40", T_RSP);
info->stackOfs += 40;
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 32", T_RSP);
info->stackOfs += 32;
}
}
else if (GetValueSp(reg) & OP_ZMM)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "%s zmmword ptr [%r], %s", MOVE_UNALIGNED_INT(), T_RSP, paramvalue);
if (info->stackOfs % 16 != 0)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 72", T_RSP);
info->stackOfs += 72;
}
else
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "sub %r, 64", T_RSP);
info->stackOfs += 64;
}
}
else
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
return(1);
}
if (opnd->kind == EXPR_REG && opnd->indirect == TRUE)
{
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (psize == 0) psize = SizeFromMemtype(param->sym.mem_type, USE64, opnd->type);
if (psize != SizeFromMemtype(param->sym.mem_type, USE64, opnd->type))
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, index + 1);
return(1);
}
if (psize == 8)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 4)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsxd rax, eax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov eax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 2)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, ax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov ax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 1)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, al");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov al, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
return(1);
}
if (opnd->kind == EXPR_ADDR && !addr && ((opnd->sym->type &&
_stricmp(opnd->sym->type->name, "__m128") != 0 &&
_stricmp(opnd->sym->type->name, "__m256") != 0 &&
_stricmp(opnd->sym->type->name, "__m512") != 0) || !opnd->sym->type))
{
psize = SizeFromMemtype(opnd->mem_type, USE64, opnd->type);
if (psize == 0) psize = 8; if (psize == 8)
{
sprintf(info->stackOps[info->stackOpCount++], "push %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 4)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsxd rax, eax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov eax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 2)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, ax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov ax, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
else if (psize == 1)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push rax");
BuildCodeLine(info->stackOps[info->stackOpCount++], "movsx rax, al");
BuildCodeLine(info->stackOps[info->stackOpCount++], "mov al, %s", paramvalue);
info->stackOfs += 8;
info->stackAdj += 8; }
return(1);
}
if (addr || psize > 8)
{
BuildCodeLine(info->stackOps[info->stackOpCount++], "push %r", T_RAX);
BuildCodeLine(info->stackOps[info->stackOpCount++], "lea %r, %s", T_RAX, paramvalue);
info->stackOfs += 8;
info->stackAdj += 8;
*regs_used |= (1 << 6);
return(1);
}
}
}
return(1);
}
#endif
static short GetSegmentPart(struct expr *opnd, char *buffer, const char *fullparam)
{
short reg = T_NULL;
DebugMsg1(("GetSegmentPart(%s) enter [override=%s sym=%s segment=%s]\n",
fullparam, opnd->override ? opnd->override->string_ptr : "NULL",
opnd->sym ? opnd->sym->name : "NULL",
opnd->sym ? opnd->sym->segment ? opnd->sym->segment->name : "NULL" : "NULL"));
if (opnd->override != NULL) {
if (opnd->override->token == T_REG)
reg = opnd->override->tokval;
else
strcpy(buffer, opnd->override->string_ptr);
}
else if (opnd->sym != NULL && opnd->sym->segment != NULL) {
struct dsym *dir = GetSegm(opnd->sym);
enum assume_segreg as;
if (dir->e.seginfo->segtype == SEGTYPE_DATA ||
dir->e.seginfo->segtype == SEGTYPE_BSS)
as = search_assume((struct asym *)dir, ASSUME_DS, TRUE);
else
as = search_assume((struct asym *)dir, ASSUME_CS, TRUE);
if (as != ASSUME_NOTHING) {
reg = T_ES + as;
}
else {
struct asym *seg;
seg = GetGroup(opnd->sym);
if (seg == NULL)
seg = &dir->sym;
if (seg)
strcpy(buffer, seg->name);
else {
strcpy(buffer, "seg ");
strcat(buffer, fullparam);
}
}
}
else if (opnd->sym && opnd->sym->state == SYM_STACK) {
reg = T_SS;
}
else {
strcpy(buffer, "seg ");
strcat(buffer, fullparam);
}
DebugMsg1(("GetSegmentPart: reg%u, buffer=%s\n", reg, reg ? "" : buffer));
return(reg);
}
#if OWFC_SUPPORT
static int watc_fcstart(struct dsym const *proc, int numparams, int start, struct asm_tok tokenarray[], int *value)
{
DebugMsg1(("watc_fcstart(%s, %u, %u)\n", proc->sym.name, numparams, start));
return(1);
}
static void watc_fcend(struct dsym const *proc, int numparams, int value)
{
DebugMsg1(("watc_fcend(%s, %u, %u)\n", proc->sym.name, numparams, value));
if (proc->e.procinfo->has_vararg) {
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL proc->e.procinfo->parasize + size_vararg);
}
else if (fcscratch < proc->e.procinfo->parasize) {
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL(proc->e.procinfo->parasize - fcscratch));
}
return;
}
static int watc_param(struct dsym const *proc, int index, struct dsym *param, bool addr, struct expr *opnd, char *paramvalue, uint_8 *r0used)
{
int opc;
int qual;
int i;
char regs[64];
char *reg[4];
char *p;
int psize = SizeFromMemtype(param->sym.mem_type, USE_EMPTY, param->sym.type);
DebugMsg1(("watc_param(%s, param=%u [name=%s, state=%u]),addr=%u: psize=%u\n", proc->sym.name, index, param->sym.name, param->sym.state, addr, psize));
if (param->sym.state != SYM_TMACRO)
return(0);
DebugMsg1(("watc_param(%s): register param=%s\n", proc->sym.name, param->sym.string_ptr));
fcscratch += CurrWordSize;
reg[0] = param->sym.string_ptr;
reg[1] = NULL;
reg[2] = NULL;
reg[3] = NULL;
if (strchr(reg[0], ':')) {
strcpy(regs, reg[0]);
fcscratch += CurrWordSize;
for (p = regs, i = 0; i < 4; i++) {
reg[i] = p;
p = strchr(p, ':');
if (p == NULL)
break;
*p++ = NULLC;
p++;
}
}
if (addr) {
if (opnd->kind == T_REG || opnd->sym->state == SYM_STACK) {
opc = T_LEA;
qual = T_NULL;
}
else {
opc = T_MOV;
qual = T_OFFSET;
}
i = 0;
if (reg[1] != NULL) {
char buffer[128];
short sreg;
if (sreg = GetSegmentPart(opnd, buffer, paramvalue))
AddLineQueueX("%r %s, %r", T_MOV, reg[0], sreg);
else
AddLineQueueX("%r %s, %s", T_MOV, reg[0], buffer);
i++;
}
AddLineQueueX("%r %s, %r %s", opc, reg[i], qual, paramvalue);
return(1);
}
for (i = 3; i >= 0; i--) {
if (reg[i]) {
if (opnd->kind == EXPR_CONST) {
if (i > 0)
qual = T_LOWWORD;
else if (i == 0 && reg[1] != NULL)
qual = T_HIGHWORD;
else
qual = T_NULL;
if (qual != T_NULL)
AddLineQueueX("mov %s, %r (%s)", reg[i], qual, paramvalue);
else
AddLineQueueX("mov %s, %s", reg[i], paramvalue);
}
else if (opnd->kind == EXPR_REG) {
AddLineQueueX("mov %s, %s", reg[i], paramvalue);
}
else {
if (i == 0 && reg[1] == NULL)
AddLineQueueX("mov %s, %s", reg[i], paramvalue);
else {
if (ModuleInfo.Ofssize)
qual = T_DWORD;
else
qual = T_WORD;
AddLineQueueX("mov %s, %r %r %s[%u]", reg[i], qual, T_PTR, paramvalue, psize - ((i + 1) * (2 << ModuleInfo.Ofssize)));
}
}
}
}
return(1);
}
#endif
static void SkipTypecast(char *fullparam, int i, struct asm_tok tokenarray[])
{
int j;
fullparam[0] = NULLC;
for (j = i; ; j++) {
if ((tokenarray[j].token == T_COMMA) || (tokenarray[j].token == T_FINAL))
break;
if ((tokenarray[j + 1].token == T_BINARY_OPERATOR) && (tokenarray[j + 1].tokval == T_PTR))
j = j + 1;
else {
if (fullparam[0] != NULLC)
strcat(fullparam, " ");
strcat(fullparam, tokenarray[j].string_ptr);
}
}
}
static int ParamIsString(char *pStr, int param, struct dsym* proc) {
char c;
char *pS = pStr;
int i = 0;
struct dsym* p = proc->e.procinfo->paralist;
struct asym* type = NULL;
enum memtype mtype = MT_EMPTY;
if (!Options.literal_strings)
return(FALSE);
for (i = 0; i < param; i++)
{
if (p->nextparam == NULL)
break;
p = p->nextparam;
}
if (p)
{
if (p->sym.mem_type == MT_PTR)
{
mtype = MT_PTR;
}
else
{
if (p->sym.target_type)
{
type = p->sym.target_type;
while (type->target_type && (int)type->target_type > 0x2000)
{
type = type->target_type;
if (type->mem_type == MT_PTR)
{
mtype = MT_PTR;
break;
}
}
mtype = MT_EMPTY;
}
else
mtype = p->sym.mem_type;
}
}
if (!p)
return(FALSE);
c = *pS;
if (c != '"') return(FALSE);
pS++;
while (TRUE)
{
c = *pS;
if (c == 0)
{
c = *(pS - 1);
if (c != '"') return(FALSE);
break;
}
pS++;
}
if (p && mtype != MT_PTR && !p->sym.is_vararg)
{
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, param);
return(FALSE);
}
return(TRUE);
}
static unsigned int hashpjw(const char *s)
{
uint_64 fnv_basis = 14695981039346656037;
uint_64 register fnv_prime = 1099511628211;
uint_64 h;
for (h = fnv_basis; *s; ++s) {
h ^= (*s | ' ');
h *= fnv_prime;
}
return((((h >> 16) ^ h) & 0xffff));
}
static int PushInvokeParam(int i, struct asm_tok tokenarray[], struct dsym *proc, struct dsym *curr, int reqParam, uint_8 *r0flags)
{
int currParm;
int psize;
int asize;
int pushsize;
int j;
int previ;
int fptrsize;
char Ofssize;
bool addr = FALSE;
struct expr opnd;
char fullparam[MAX_LINE_LEN];
char buffer[MAX_LINE_LEN];
char stringparam[256][32];
bool isString[256];
int reg = 0;
struct asym *lbl = NULL;
struct dsym *curseg;
struct dsym *prev;
struct dsym *currs;
size_t slen;
char *pSrc;
char *pDest;
char *labelstr = "__ls";
char buf[32];
char c1;
char c2;
size_t finallen;
uint_16 buff[256];
uint_8 buff2[256];
DebugMsg1(("PushInvokeParam(%s, param=%s:%u, i=%u ) enter\n", proc->sym.name, curr ? curr->sym.name : "NULL", reqParam, i));
previ = i;
i++;
for (currParm = 0; currParm <= reqParam; )
{
if (tokenarray[i].token == T_FINAL) {
break;
}
if (tokenarray[i].token == T_COMMA) {
currParm++;
}
if (currParm == reqParam && curr)
{
if (ParamIsString(tokenarray[i].string_ptr, currParm, proc))
{
curseg = ModuleInfo.currseg;
prev = NULL;
currs = NULL;
for (currs = SymTables[TAB_SEG].head; currs && currs->next; prev = currs, currs = currs->next)
{
if (strcmp(currs->sym.name, "_DATA") == 0)
break;
}
CurrSeg = currs;
slen = strlen(tokenarray[i].string_ptr) - 2;
pSrc = (tokenarray[i].string_ptr) + 1;
sprintf(buf, "%s%d", labelstr, hashpjw(tokenarray[i].string_ptr));
lbl = SymLookup(buf);
SetSymSegOfs(lbl);
memset(&buff, 0, 256);
pDest = buff;
finallen = slen;
while (*pSrc != '"')
{
c1 = *pSrc++;
c2 = *(pSrc);
if (c1 == '\\' && c2 == 'n')
{
*pDest++ = 10;
finallen--;
pSrc++;
}
else if (c1 == '\\' && c2 == 'r')
{
*pDest++ = 13;
finallen--;
pSrc++;
}
else if (c1 == '\\' && c2 == 't')
{
*pDest++ = 9;
finallen--;
pSrc++;
}
else
*pDest++ = c1;
}
*pDest++ = 0;
OutputBytes((unsigned char *)&buff, finallen + 1, NULL);
lbl->isdefined = TRUE;
lbl->isarray = TRUE;
lbl->mem_type = MT_BYTE;
lbl->state = SYM_INTERNAL;
lbl->first_size = finallen;
lbl->first_length = slen;
lbl->total_length = finallen;
lbl->total_size = finallen;
lbl->debuginfo = FALSE;
lbl->ispublic = 0;
BackPatch(lbl);
sprintf(stringparam[currParm], "%s", buf);
isString[currParm] = TRUE;
CurrSeg = curseg;
}
else if (strcmp(tokenarray[i].string_ptr, "L") == 0 && ParamIsString(tokenarray[i + 1].string_ptr, currParm, proc))
{
curseg = ModuleInfo.currseg;
prev = NULL;
currs = NULL;
for (currs = SymTables[TAB_SEG].head; currs && currs->next; prev = currs, currs = currs->next)
{
if (strcmp(currs->sym.name, "_DATA") == 0)
break;
}
CurrSeg = currs;
slen = strlen(tokenarray[i + 1].string_ptr) - 2;
pSrc = (tokenarray[i + 1].string_ptr) + 1;
sprintf(buf, "%s%d", labelstr, hashpjw(pSrc));
lbl = SymLookup(buf);
memset(&buff, 0, 256);
pDest = buff2;
finallen = slen;
while (*pSrc != '"')
{
c1 = *pSrc++;
c2 = *(pSrc);
if (c1 == '\\' && c2 == 'n')
{
*pDest++ = 10;
finallen--;
pSrc++;
}
else if (c1 == '\\' && c2 == 'r')
{
*pDest++ = 13;
finallen--;
pSrc++;
}
else if (c1 == '\\' && c2 == 't')
{
*pDest++ = 9;
finallen--;
pSrc++;
}
else
*pDest++ = c1;
}
*pDest++ = 0;
j = UTF8toWideChar(&buff2, slen, NULL, (unsigned short *)&buff, slen);
SetSymSegOfs(lbl);
OutputBytes((unsigned char *)&buff, (j * 2) + 2, NULL);
lbl->isdefined = TRUE;
lbl->isarray = TRUE;
lbl->mem_type = MT_BYTE;
lbl->state = SYM_INTERNAL;
lbl->first_size = finallen;
lbl->first_length = slen;
lbl->total_length = j;
lbl->total_size = j;
lbl->debuginfo = FALSE;
lbl->ispublic = 0;
BackPatch(lbl);
sprintf(stringparam[currParm], "%s", buf);
isString[currParm] = TRUE;
CurrSeg = curseg;
i++;
}
else
{
isString[currParm] = FALSE;
}
}
i++;
}
i = previ;
for (currParm = 0; currParm <= reqParam; )
{
if (tokenarray[i].token == T_FINAL ) {
DebugMsg1(("PushInvokeParam(%s): T_FINAL token, i=%u\n", proc->sym.name, i));
return(ERROR);
}
if (tokenarray[i].token == T_COMMA) {
currParm++;
}
i++;
}
if (!curr) return(NOT_ERROR);
psize = curr->sym.total_size;
if (_stricmp(tokenarray[i].string_ptr, "L") == 0 && (*(tokenarray[i+1].string_ptr) == '"') )
{
i++;
}
if (tokenarray[i].token == T_RES_ID && tokenarray[i].tokval == T_ADDR) {
addr = TRUE;
i++;
}
for (j = i; tokenarray[j].token != T_COMMA && tokenarray[j].token != T_FINAL; j++);
if (isString[reqParam])
{
memcpy(fullparam, stringparam[reqParam], strlen(stringparam[reqParam]) + 1);
addr = TRUE;
psize = 2 << curr->sym.Ofssize;
if (curr->sym.isfar)
psize += 2;
}
else
{
memcpy(fullparam, tokenarray[i].tokpos, tokenarray[j].tokpos - tokenarray[i].tokpos);
fullparam[tokenarray[j].tokpos - tokenarray[i].tokpos] = NULLC;
}
j = i;
Ofssize = (proc->sym.state == SYM_TYPE ? proc->sym.seg_ofssize : GetSymOfssize(&proc->sym));
fptrsize = 2 + (2 << Ofssize);
if (proc->sym.langtype == LANG_DELPHICALL)
{
if ( delphicall_tab[ModuleInfo.fctype].handleparam(proc, reqParam, curr, addr, &opnd, fullparam, r0flags) )
return(NOT_ERROR);
}
if ( addr ) {
if (EvalOperand(&j, tokenarray, Token_Count, &opnd, ModuleInfo.invoke_exprparm) == ERROR)
return(ERROR);
if (psize > fptrsize && fptrsize > 4) {
DebugMsg1(("PushInvokeParm(%u): error, psize=%u, fptrsize=%u\n", reqParam, psize, fptrsize));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
return(NOT_ERROR);
}
if (proc->sym.langtype == LANG_FASTCALL) {
if (fastcall_tab[ModuleInfo.fctype].handleparam(proc, reqParam, curr, addr, &opnd, fullparam, r0flags))
return(NOT_ERROR);
}
else if (proc->sym.langtype == LANG_VECTORCALL) {
if (vectorcall_tab[ModuleInfo.fctype].handleparam(proc, reqParam, curr, addr, &opnd, fullparam, r0flags))
return(NOT_ERROR);
}
else if (proc->sym.langtype == LANG_SYSVCALL) {
if (sysvcall_tab[ModuleInfo.fctype].handleparam(proc, reqParam, curr, addr, &opnd, fullparam, r0flags))
return(NOT_ERROR);
}
if (opnd.kind == EXPR_REG || opnd.indirect) {
if (curr->sym.isfar || psize == fptrsize) {
DebugMsg1(("PushInvokeParam: far ptr, %s isfar=%u, psize=%u, fptrsize=%u\n", curr->sym.name, curr->sym.isfar, psize, fptrsize));
if (opnd.sym && opnd.sym->state == SYM_STACK)
GetResWName(T_SS, buffer);
else if (opnd.override != NULL)
strcpy(buffer, opnd.override->string_ptr);
else
GetResWName(T_DS, buffer);
AddLineQueueX(" push %s", buffer);
}
if (proc->sym.langtype == LANG_DELPHICALL)
{
AddLineQueueX("push %r", T_EAX);
AddLineQueueX("lea %r, %s", regax[ModuleInfo.Ofssize], fullparam);
AddLineQueueX("xchg eax,[esp]");
}
else
{
AddLineQueueX(" lea %r, %s", regax[ModuleInfo.Ofssize], fullparam);
*r0flags |= R0_USED;
AddLineQueueX(" push %r", regax[ModuleInfo.Ofssize]);
}
}
else {
push_address:
if (curr->sym.isfar || psize > (2 << curr->sym.Ofssize)) {
short sreg;
sreg = GetSegmentPart(&opnd, buffer, fullparam);
if (sreg) {
if (Ofssize != ModuleInfo.Ofssize || (curr->sym.Ofssize == USE16 && CurrWordSize > 2))
AddLineQueue(" db 66h");
AddLineQueueX(" push %r", sreg);
}
else
AddLineQueueX(" push %s", buffer);
}
if ((ModuleInfo.curr_cpu & P_CPU_MASK) < P_186) {
AddLineQueueX(" mov %r, offset %s", T_AX, fullparam);
AddLineQueueX(" push %r", T_AX);
*r0flags |= R0_USED;
}
else {
if (curr->sym.is_vararg && opnd.Ofssize == USE_EMPTY && opnd.sym)
opnd.Ofssize = GetSymOfssize(opnd.sym);
if ((opnd.Ofssize == USE16 && CurrWordSize > 2) ||
(curr->sym.Ofssize == USE32 && CurrWordSize == 2)) {
AddLineQueueX(" pushd %r %s", T_OFFSET, fullparam);
}
else if (CurrWordSize > 2 && curr->sym.Ofssize == USE16 &&
(curr->sym.isfar || Ofssize == USE16)) {
AddLineQueueX(" pushw %r %s", T_OFFSET, fullparam);
}
else {
AddLineQueueX(" push %r %s", T_OFFSET, fullparam);
if (curr->sym.is_vararg && CurrWordSize == 2 && opnd.Ofssize > USE16) {
size_vararg += CurrWordSize;
}
}
}
}
if (curr->sym.is_vararg) {
size_vararg += CurrWordSize + (curr->sym.isfar ? CurrWordSize : 0);
DebugMsg1(("PushInvokeParm(%u): new value of size_vararg=%u [CurrWordSize=%u]\n", reqParam, size_vararg, CurrWordSize));
}
}
else {
if (tokenarray[j].token == T_REG &&
tokenarray[j + 1].token == T_DBL_COLON &&
tokenarray[j + 2].token == T_REG) {
int asize2;
if (GetValueSp(tokenarray[j].tokval) & OP_SR) {
asize2 = 2;
if (Ofssize != ModuleInfo.Ofssize || (curr->sym.Ofssize == USE16 && CurrWordSize > 2))
AddLineQueue(" db 66h");
}
else
asize2 = SizeFromRegister(tokenarray[j].tokval);
asize = SizeFromRegister(tokenarray[j + 2].tokval);
AddLineQueueX(" push %r", tokenarray[j].tokval);
if ((curr->sym.is_vararg) && (asize + asize2) != CurrWordSize)
size_vararg += asize2;
else
asize += asize2;
strcpy(fullparam, tokenarray[j + 2].string_ptr);
opnd.kind = EXPR_REG;
opnd.indirect = FALSE;
opnd.sym = NULL;
opnd.base_reg = &tokenarray[j + 2];
}
else {
if (EvalOperand(&j, tokenarray, Token_Count, &opnd, ModuleInfo.invoke_exprparm) == ERROR) {
return(ERROR);
}
if (opnd.kind == EXPR_REG && opnd.indirect == FALSE) {
asize = SizeFromRegister(opnd.base_reg->tokval);
}
else if (opnd.kind == EXPR_CONST || opnd.mem_type == MT_EMPTY) {
asize = psize;
if (psize == 0) {
if (curr->sym.is_vararg == FALSE) {
DebugMsg1(("PushInvokeParm(%u): error, psize=0\n"));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
}
if (opnd.mbr && opnd.mbr->mem_type == MT_TYPE)
asize = SizeFromMemtype(opnd.mbr->mem_type, opnd.Ofssize, opnd.mbr->type);
}
DebugMsg1(("PushInvokeParm(%u): memtype EMPTY, asize=%u psize=%u\n", reqParam, asize, psize));
}
else if (opnd.mem_type != MT_TYPE) {
if (opnd.kind == EXPR_ADDR &&
opnd.indirect == FALSE &&
opnd.sym &&
opnd.instr == EMPTY &&
(opnd.mem_type == MT_NEAR || opnd.mem_type == MT_FAR))
goto push_address;
if (opnd.Ofssize == USE_EMPTY)
opnd.Ofssize = ModuleInfo.Ofssize;
asize = SizeFromMemtype(opnd.mem_type, opnd.Ofssize, opnd.type);
}
else {
if (opnd.sym != NULL)
asize = opnd.sym->type->total_size;
else
asize = opnd.mbr->type->total_size;
}
}
if (curr->sym.is_vararg == TRUE)
psize = asize;
#ifdef DEBUG_OUT
if (opnd.sym)
DebugMsg1(("PushInvokeParam(%s, %u): arg name=%s, asize=%u, amtype=%xh psize=%u\n", proc->sym.name, reqParam, opnd.sym->name, asize, opnd.mem_type, psize));
else
DebugMsg1(("PushInvokeParam(%s, %u): arg no name, asize=%u, amtype=%xh psize=%u\n", proc->sym.name, reqParam, asize, opnd.mem_type, psize));
#endif
pushsize = CurrWordSize;
if (proc->sym.langtype == LANG_FASTCALL) {
if (fastcall_tab[ModuleInfo.fctype].handleparam(proc, reqParam, curr, addr, &opnd, fullparam, r0flags))
return(NOT_ERROR);
}
if (proc->sym.langtype == LANG_SYSVCALL) {
if (sysvcall_tab[ModuleInfo.fctype].handleparam(proc, reqParam, curr, addr, &opnd, fullparam, r0flags))
return(NOT_ERROR);
}
else if (proc->sym.langtype == LANG_VECTORCALL) {
if (opnd.kind == EXPR_REG && reqParam > 5) {
if ((GetValueSp(reg) & OP_XMM) || (GetValueSp(reg) & OP_YMM) || (GetValueSp(reg) & OP_ZMM))
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam);
}
else if (vectorcall_tab[ModuleInfo.fctype].handleparam(proc, reqParam, curr, addr, &opnd, fullparam, r0flags))
return(NOT_ERROR);
}
if ((asize > psize) || (asize < psize && curr->sym.mem_type == MT_PTR)) {
DebugMsg(("PushInvokeParm(%u): argsize error, arg size=%d, parm size=%d\n", reqParam, asize, psize));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
return(NOT_ERROR);
}
if ((opnd.kind == EXPR_ADDR && opnd.instr != T_OFFSET) ||
(opnd.kind == EXPR_REG && opnd.indirect == TRUE)) {
if (*r0flags &&
((opnd.base_reg != NULL &&
(opnd.base_reg->tokval == T_EAX
#if AMD64_SUPPORT
|| opnd.base_reg->tokval == T_RAX
#endif
)) ||
(opnd.idx_reg != NULL &&
(opnd.idx_reg->tokval == T_EAX
#if AMD64_SUPPORT
|| opnd.idx_reg->tokval == T_RAX
#endif
)))) {
*r0flags = 0;
}
if (curr->sym.is_vararg) {
size_vararg += (asize > pushsize ? asize : pushsize);
DebugMsg1(("PushInvokeParm(%u): asize=%u added to size_vararg, now=%u\n",
reqParam, asize > pushsize ? asize : pushsize, size_vararg));
}
if (asize > pushsize) {
short dw = T_WORD;
if ((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386) {
pushsize = 4;
dw = T_DWORD;
}
if (opnd.explicit) {
SkipTypecast(fullparam, i, tokenarray);
opnd.explicit = FALSE;
}
if (ModuleInfo.Ofssize != USE32)
goto only64;
if (asize == 5) {
if (pushsize == 4) {
AddLineQueueX(" sub %r, 2", T_ESP);
AddLineQueueX(" mov al, byte ptr %s[7]", fullparam);
AddLineQueueX(" push ax");
AddLineQueueX(" push dword ptr %s", fullparam);
}
}
else if (asize == 6 && curr->sym.mem_type != MT_FWORD) {
if (pushsize == 4) {
AddLineQueueX(" sub %r, 2", T_ESP);
AddLineQueueX(" push word ptr %s[6]", fullparam);
AddLineQueueX(" push dword ptr %s", fullparam);
}
}
else if (asize == 7) {
if (pushsize == 4) {
AddLineQueueX(" mov al, byte ptr %s[6]", fullparam);
AddLineQueue(" push ax");
AddLineQueueX(" push word ptr %s[10]", fullparam);
AddLineQueueX(" push dword ptr %s[6]", fullparam);
}
}
else {
only64:
while (asize > 0) {
if (asize & 2) {
if (ModuleInfo.Ofssize > USE16) {
if (pushsize == 4)
size_vararg += 2;
#if AMD64_SUPPORT
AddLineQueueX(" sub %r, 2", stackreg[ModuleInfo.Ofssize]);
#else
AddLineQueueX(" sub %r, 2", T_ESP);
#endif
}
AddLineQueueX(" push word ptr %s+%u", fullparam, NUMQUAL asize - 2);
asize -= 2;
}
else {
if (CurrProc && ModuleInfo.basereg[ModuleInfo.Ofssize] == T_ESP)
AddLineQueueX(" push %r ptr %s+%u", dw, fullparam, NUMQUAL pushsize);
else
AddLineQueueX(" push %r ptr %s+%u", dw, fullparam, NUMQUAL asize - pushsize);
asize -= pushsize;
}
}
}
}
else if (asize < pushsize) {
if (psize > 4) {
DebugMsg1(("PushInvokeParm(%u): error, ADDR, psize=%u, is > 4\n",
reqParam, psize));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
}
if (asize < 4 && psize > 2 && IS_SIGNED(opnd.mem_type) && (ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386) {
AddLineQueueX(" movsx %r, %s", T_EAX, fullparam);
AddLineQueueX(" push %r", T_EAX);
*r0flags = R0_USED;
}
else {
switch (opnd.mem_type) {
case MT_BYTE:
case MT_SBYTE:
if (psize == 1 && curr->sym.is_vararg == FALSE) {
AddLineQueueX(" mov %r, %s", T_AL, fullparam);
AddLineQueueX(" push %r", regax[ModuleInfo.Ofssize]);
}
else if (pushsize == 2) {
if (opnd.mem_type == MT_BYTE) {
if (psize == 4)
if ((ModuleInfo.curr_cpu & P_CPU_MASK) < P_186) {
if (!(*r0flags & R0_X_CLEARED))
AddLineQueueX(" xor %r, %r", T_AX, T_AX);
*r0flags |= (R0_X_CLEARED | R0_H_CLEARED);
AddLineQueueX(" push %r", T_AX);
}
else
AddLineQueue(" push 0");
AddLineQueueX(" mov %r, %s", T_AL, fullparam);
if (!(*r0flags & R0_H_CLEARED)) {
AddLineQueueX(" mov %r, 0", T_AH);
*r0flags |= R0_H_CLEARED;
}
}
else {
AddLineQueueX(" mov %r, %s", T_AL, fullparam);
*r0flags = 0;
AddLineQueue(" cbw");
if (psize == 4) {
AddLineQueue(" cwd");
AddLineQueueX(" push %r", T_DX);
*r0flags |= R2_USED;
}
}
AddLineQueueX(" push %r", T_AX);
}
else {
AddLineQueueX(" mov%sx %r, %s", opnd.mem_type == MT_BYTE ? "z" : "s", T_EAX, fullparam);
AddLineQueueX(" push %r", T_EAX);
}
*r0flags |= R0_USED;
break;
case MT_WORD:
case MT_SWORD:
if (opnd.mem_type == MT_WORD && (Options.masm_compat_gencode || psize == 2)) {
if (curr->sym.is_vararg || psize != 2)
AddLineQueueX(" pushw 0");
else {
#if AMD64_SUPPORT
AddLineQueueX(" sub %r, 2", stackreg[ModuleInfo.Ofssize]);
#else
AddLineQueueX(" sub %r, 2", T_ESP);
#endif
}
AddLineQueueX(" push %s", fullparam);
}
else {
AddLineQueueX(" mov%sx %r, %s", opnd.mem_type == MT_WORD ? "z" : "s", T_EAX, fullparam);
AddLineQueueX(" push %r", T_EAX);
*r0flags = R0_USED;
}
break;
default:
if (asize == 3)
{
if (pushsize == 4)
{
AddLineQueueX(" mov al, byte ptr %s[2]", fullparam);
AddLineQueue(" push ax");
AddLineQueueX(" push word ptr %s[2]", fullparam);
}
else
{
AddLineQueueX(" push word ptr %s[2]", fullparam);
AddLineQueueX(" push word ptr %s", fullparam);
}
}
else
AddLineQueueX(" push %s", fullparam);
}
}
}
else {
if (IS_SIGNED(opnd.mem_type) && psize > asize) {
if (psize > 2 && ((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386)) {
AddLineQueueX(" movsx %r, %s", T_EAX, fullparam);
AddLineQueueX(" push %r", T_EAX);
*r0flags = R0_USED;
}
else if (pushsize == 2 && psize > 2) {
AddLineQueueX(" mov %r, %s", T_AX, fullparam);
AddLineQueueX(" cwd");
AddLineQueueX(" push %r", T_DX);
AddLineQueueX(" push %r", T_AX);
*r0flags = R0_USED | R2_USED;
}
else
AddLineQueueX(" push %s", fullparam);
}
else {
if (pushsize == 2 && psize > 2) {
if ((ModuleInfo.curr_cpu & P_CPU_MASK) < P_186) {
if (!(*r0flags & R0_X_CLEARED))
AddLineQueueX(" xor %r, %r", T_AX, T_AX);
AddLineQueueX(" push %r", T_AX);
*r0flags |= (R0_USED | R0_X_CLEARED | R0_H_CLEARED);
}
else
AddLineQueueX(" pushw 0");
}
AddLineQueueX(" push %s", fullparam);
}
}
}
else {
if (opnd.kind == EXPR_REG) {
int reg = opnd.base_reg->tokval;
unsigned optype = GetValueSp(reg);
if (curr->sym.is_vararg == TRUE && psize < pushsize)
psize = pushsize;
if (optype & (OP_STI | OP_MMX | OP_YMM | OP_RSPEC)) {
return(EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1));
}
if ((*r0flags & R0_USED) && (reg == T_AH || (optype & OP_A))) {
EmitErr(REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
*r0flags &= ~R0_USED;
}
else if ((*r0flags & R2_USED) && (reg == T_DH || GetRegNo(reg) == 2)) {
EmitErr(REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
*r0flags &= ~R2_USED;
}
if (asize != psize || asize < (2 << Ofssize)) {
if (psize > 4) {
DebugMsg1(("PushInvokeParm(%u): error, REG, asize=%u, psize=%u, pushsize=%u\n",
reqParam, asize, psize, pushsize));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
}
if (asize <= 2 && (psize == 4 || pushsize == 4)) {
if ((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386 && asize == psize) {
if (asize == 2)
reg = reg - T_AX + T_EAX;
else {
if (reg < T_AH)
reg = reg - T_AL + T_EAX;
else {
AddLineQueueX(" mov %r, %s", T_AL, fullparam);
*r0flags |= R0_USED;
reg = T_EAX;
}
asize = 2;
}
}
else if (IS_SIGNED(opnd.mem_type) && pushsize < 4) {
if ((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386) {
AddLineQueueX(" movsx %r, %s", T_EAX, fullparam);
*r0flags = R0_USED;
reg = T_EAX;
}
else {
*r0flags = R0_USED | R2_USED;
if (asize == 1) {
if (reg != T_AL)
AddLineQueueX(" mov %r, %s", T_AL, fullparam);
AddLineQueue(" cbw");
}
else if (reg != T_AX)
AddLineQueueX(" mov %r, %s", T_AX, fullparam);
AddLineQueue(" cwd");
AddLineQueueX(" push %r", T_DX);
reg = T_AX;
}
asize = 2;
}
else if ((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_186) {
if (pushsize == 4) {
if (asize == 1) {
}
else if (psize <= 2) {
#if AMD64_SUPPORT
AddLineQueueX(" sub %r, 2", stackreg[ModuleInfo.Ofssize]);
#else
AddLineQueueX(" sub %r, 2", T_ESP);
#endif
}
else if (IS_SIGNED(opnd.mem_type)) {
AddLineQueueX(" movsx %r, %s", T_EAX, fullparam);
*r0flags = R0_USED;
reg = T_EAX;
}
else {
AddLineQueue(" pushw 0");
}
}
else
AddLineQueue(" pushw 0");
}
else {
if (!(*r0flags & R0_X_CLEARED)) {
if (reg == T_AH || (optype & OP_A))
EmitErr(REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
AddLineQueueX(" xor %r, %r", T_AX, T_AX);
}
AddLineQueueX(" push %r", T_AX);
*r0flags = R0_USED | R0_H_CLEARED | R0_X_CLEARED;
}
}
if (asize == 1) {
if ((reg >= T_AH && reg <= T_BH) || psize != 1) {
if (psize != 1 && (ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386) {
AddLineQueueX(" mov%sx %r, %s", IS_SIGNED(opnd.mem_type) ? "s" : "z",
regax[ModuleInfo.Ofssize], fullparam);
*r0flags = (IS_SIGNED(opnd.mem_type) ? R0_USED : R0_USED | R0_H_CLEARED);
}
else {
if (reg != T_AL) {
AddLineQueueX(" mov %r, %s", T_AL, fullparam);
*r0flags |= R0_USED;
*r0flags &= ~R0_X_CLEARED;
}
if (psize != 1)
if (IS_SIGNED(opnd.mem_type)) {
AddLineQueue(" cbw");
*r0flags &= ~(R0_H_CLEARED | R0_X_CLEARED);
}
else if (!(*r0flags & R0_H_CLEARED)) {
AddLineQueueX(" mov %r, 0", T_AH);
*r0flags |= R0_H_CLEARED;
}
}
reg = regax[ModuleInfo.Ofssize];
}
else {
if (((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386) &&
(psize == 4 || pushsize == 4)) {
reg = reg - T_AL + T_EAX;
}
else
reg = reg - T_AL + T_AX;
}
}
#if 0#endif
}
if (optype & OP_XMM)
{
AddLineQueueX(" movd eax,%r", reg); AddLineQueueX(" push eax");
}
else
{
AddLineQueueX(" push %r", reg);
}
if (psize < pushsize)
psize = pushsize;
}
else {
if (psize) {
if (opnd.kind == EXPR_FLOAT)
asize = 4;
else if (opnd.value64 <= 255 && opnd.value64 >= -255)
asize = 1;
else if (opnd.value64 <= 65535 && opnd.value64 >= -65535)
asize = 2;
else if (opnd.value64 <= maxintvalues[0] && opnd.value64 >= minintvalues[0])
asize = 4;
else
asize = 8;
if (psize < asize)
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
}
asize = 2 << Ofssize;
if (psize < asize)
if (psize == 0 && curr->sym.is_vararg) {
if (asize == 2 &&
(opnd.value > 0xFFFFL || opnd.value < -65535L))
psize = 4;
else
psize = asize;
}
else
psize = asize;
if ((ModuleInfo.curr_cpu & P_CPU_MASK) < P_186) {
*r0flags |= R0_USED;
switch (psize) {
case 2:
if (opnd.value != 0 || opnd.kind == EXPR_ADDR) {
AddLineQueueX(" mov %r, %s", T_AX, fullparam);
}
else {
if (!(*r0flags & R0_X_CLEARED)) {
AddLineQueueX(" xor %r, %r", T_AX, T_AX);
}
*r0flags |= R0_H_CLEARED | R0_X_CLEARED;
}
break;
case 4:
if (opnd.uvalue <= 0xFFFF)
AddLineQueueX(" xor %r, %r", T_AX, T_AX);
else
AddLineQueueX(" mov %r, %r (%s)", T_AX, T_HIGHWORD, fullparam);
AddLineQueueX(" push %r", T_AX);
if (opnd.uvalue != 0 || opnd.kind == EXPR_ADDR) {
AddLineQueueX(" mov %r, %r (%s)", T_AX, T_LOWWORD, fullparam);
}
else {
*r0flags |= R0_H_CLEARED | R0_X_CLEARED;
}
break;
default:
DebugMsg1(("PushInvokeParm(%u): error, CONST, asize=%u, psize=%u, pushsize=%u\n",
reqParam, asize, psize, pushsize));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
}
AddLineQueueX(" push %r", T_AX);
}
else {
char *instr = "";
char *suffix;
int qual = EMPTY;
if (psize != pushsize) {
switch (psize) {
case 2:
instr = "w";
break;
case 6:
if (Ofssize == USE16)
suffix = "w";
else if (Ofssize == USE32 && CurrWordSize == 2)
suffix = "d";
else
suffix = "";
AddLineQueueX(" push%s (%s) shr 32t", suffix, fullparam);
case 4:
if ((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_386)
instr = "d";
else {
AddLineQueueX(" pushw %r (%s)", T_HIGHWORD, fullparam);
instr = "w";
qual = T_LOWWORD;
}
break;
case 8:
#if AMD64_SUPPORT
if ((ModuleInfo.curr_cpu & P_CPU_MASK) >= P_64)
break;
#endif
if (opnd.kind == EXPR_CONST || opnd.kind == EXPR_FLOAT) {
AddLineQueueX(" pushd %r (%s)", T_HIGH32, fullparam);
qual = T_LOW32;
instr = "d";
break;
}
default:
DebugMsg1(("PushInvokeParm(%u): error, CONST, asize=%u, psize=%u, pushsize=%u\n",
reqParam, asize, psize, pushsize));
EmitErr(INVOKE_ARGUMENT_TYPE_MISMATCH, reqParam + 1);
}
}
if (qual != EMPTY)
AddLineQueueX(" push%s %r (%s)", instr, qual, fullparam);
else
AddLineQueueX(" push%s %s", instr, fullparam);
}
}
if (curr->sym.is_vararg) {
size_vararg += psize;
DebugMsg1(("PushInvokeParm(%u): psize=%u added to size_vararg, now=%u\n", reqParam, psize, size_vararg));
}
}
}
return(NOT_ERROR);
}
ret_code InvokeDirective(int i, struct asm_tok tokenarray[])
{
struct asym *sym;
struct dsym *proc;
char *p;
int numParam;
int value;
int size;
int parmpos;
int namepos;
int porder;
int j;
uint_8 r0flags = 0;
struct proc_info *info;
struct dsym *curr;
struct expr opnd;
struct asym *lastret;
bool wasEquateProc = FALSE;
i++;
namepos = i;
if (tokenarray[i].token != T_ID || (tokenarray[i + 1].token != T_COMMA && tokenarray[i + 1].token != T_FINAL && tokenarray[i + 1].token != T_OP_BRACKET))
{
if (ERROR == EvalOperand(&i, tokenarray, Token_Count, &opnd, 0))
return(ERROR);
if (opnd.type != NULL && opnd.type->state == SYM_TYPE)
{
sym = opnd.type;
proc = (struct dsym *)sym;
if (sym->mem_type == MT_PROC)
goto isfnproto;
if (sym->mem_type == MT_PTR)
goto isfnptr;
}
if (opnd.kind == EXPR_REG)
{
if (GetValueSp(opnd.base_reg->tokval) & OP_RGT8)
sym = GetStdAssume(GetRegNo(opnd.base_reg->tokval));
else
sym = NULL;
}
else
sym = (opnd.mbr ? opnd.mbr : opnd.sym);
}
else
{
opnd.base_reg = NULL;
sym = SymSearch(tokenarray[i].string_ptr);
if (sym && sym->variable && sym->procptr) {
sym = sym->procptr;
wasEquateProc = TRUE;
}
i++;
}
if (sym == NULL)
return(EmitErr(INVOKE_REQUIRES_PROTOTYPE));
if (sym->isproc)
;
else if (sym->mem_type == MT_PTR && sym->target_type && sym->target_type->isproc)
sym = sym->target_type;
else if (sym->mem_type == MT_PTR && sym->target_type && sym->target_type->mem_type == MT_PROC)
{
proc = (struct dsym *)sym->target_type;
goto isfnproto;
}
else if ((sym->mem_type == MT_TYPE) && (sym->type->mem_type == MT_PTR || sym->type->mem_type == MT_PROC))
{
proc = (struct dsym *)sym->type;
if (proc->sym.mem_type != MT_PROC)
goto isfnptr;
isfnproto:
if (proc->sym.mem_type != MT_PROC)
{
return(EmitErr(INVOKE_REQUIRES_PROTOTYPE));
}
isfnptr:
sym = proc->sym.target_type;
if (sym == NULL)
return(EmitErr(INVOKE_REQUIRES_PROTOTYPE));
}
else
{
return(EmitErr(INVOKE_REQUIRES_PROTOTYPE));
}
proc = (struct dsym *)sym;
info = proc->e.procinfo;
if(CurrProc)
CurrProc->e.procinfo->isleaf = FALSE;
lastret = SymFind("@LastReturnType");
lastret->value = info->ret_type;
if (proc->sym.langtype == LANG_SYSVCALL)
{
info->vecused = 0;
for (j = 0; j < 64; j++)
*(info->stackOps[j]) = NULLC;
info->stackOpCount = 0;
info->stackOfs = 0;
}
memset(info->vregs, 0, 6);
memset(info->xyzused, 0, 6);
memset(info->vecregsize, 0, 6);
if (Parse_Pass == PASS_1)
memset(info->delregsused, 0, 3);
info->vsize = 0;
for (curr = info->paralist, numParam = 0; curr; curr = curr->nextparam, numParam++)
{
}
fcscratch = 0;
if (proc->sym.langtype == LANG_FASTCALL)
porder = fastcall_tab[ModuleInfo.fctype].invokestart(proc, numParam, i, tokenarray, &value);
else if (proc->sym.langtype == LANG_VECTORCALL)
porder = vectorcall_tab[ModuleInfo.fctype].invokestart(proc, numParam, i, tokenarray, &value);
else if (proc->sym.langtype == LANG_SYSVCALL)
porder = sysvcall_tab[ModuleInfo.fctype].invokestart(proc, numParam, i, tokenarray, &value);
else if (proc->sym.langtype == LANG_DELPHICALL)
porder = delphicall_tab[ModuleInfo.fctype].invokestart(proc, numParam, i, tokenarray, &value);
curr = info->paralist;
parmpos = i;
if (!(info->has_vararg)) {
if (PushInvokeParam(i, tokenarray, proc, NULL, numParam, &r0flags) != ERROR) {
DebugMsg(("InvokeDir: superfluous argument, i=%u\n", i));
return(EmitErr(TOO_MANY_ARGUMENTS_TO_INVOKE));
}
}
else {
if (proc->sym.langtype != LANG_SYSVCALL)
{
int j = (Token_Count - i) / 2;
numParam--;
size_vararg = 0;
while (curr && curr->sym.is_vararg == FALSE) curr = curr->nextparam;
DebugMsg1(("InvokeDir: VARARG proc, numparams=%u, actual (max) params=%u, parasize=%u\n", numParam, j, info->parasize));
for (; j >= numParam; j--)
PushInvokeParam(i, tokenarray, proc, curr, j, &r0flags);
for (curr = info->paralist; curr && curr->sym.is_vararg == TRUE; curr = curr->nextparam);
}
else if (proc->sym.langtype == LANG_SYSVCALL && info->has_vararg)
{
numParam = 0;
for (curr = info->paralist, numParam = 0; curr && (curr->sym.is_vararg == FALSE); curr = curr->nextparam, numParam++)
{
}
if (PushInvokeParam(i, tokenarray, proc, NULL, numParam, &r0flags) != ERROR) {
}
curr = info->paralist;
}
}
if ( sym->langtype == LANG_STDCALL ||
sym->langtype == LANG_C ||
sym->langtype == LANG_SYSCALL ||
(sym->langtype == LANG_FASTCALL && porder) ||
(sym->langtype == LANG_VECTORCALL && porder) ||
(sym->langtype == LANG_SYSVCALL && porder) ||
(sym->langtype == LANG_DELPHICALL && porder) )
{
int total = 0;
int offset;
struct dsym *p;
for (; curr; curr = curr->nextparam)
{
numParam--;
if (PushInvokeParam(i, tokenarray, proc, curr, numParam, &r0flags) == ERROR)
{
DebugMsg(("InvokeDir: PushInvokeParam(curr=%u, i=%u, numParam=%u) failed\n", curr, i, numParam));
EmitErr(TOO_FEW_ARGUMENTS_TO_INVOKE, sym->name);
}
if (CurrProc && ModuleInfo.basereg[ModuleInfo.Ofssize] == T_ESP)
{
RunLineQueue();
offset = curr->sym.total_size;
if (offset < 4)
offset = 4;
if (offset > 4)
offset = 8;
total += offset;
for (p = CurrProc->e.procinfo->paralist; p; p = p->nextparam)
if (p->sym.state != SYM_TMACRO)
p->sym.offset += offset;
}
}
if (total)
{
for (p = CurrProc->e.procinfo->paralist; p; p = p->nextparam)
{
if (p->sym.state != SYM_TMACRO)
p->sym.offset -= total;
}
}
}
else
{
unsigned char sGPR = proc->e.procinfo->firstGPR;
unsigned char sVEC = proc->e.procinfo->firstVEC;
proc->e.procinfo->vararg_vecs = 0;
for (numParam = 0; curr && (curr->sym.is_vararg == FALSE); curr = curr->nextparam, numParam++)
{
if (PushInvokeParam(i, tokenarray, proc, curr, numParam, &r0flags) == ERROR)
{
DebugMsg(("InvokeDir: PushInvokeParam(curr=%u, i=%u, numParam=%u) failed\n", curr, i, numParam));
EmitErr(TOO_FEW_ARGUMENTS_TO_INVOKE, sym->name);
}
}
if (proc->sym.langtype == LANG_SYSVCALL && proc->e.procinfo->has_vararg)
{
int j = numParam;
for (; j < ((Token_Count - i) / 2); j++)
PushInvokeParam(i, tokenarray, proc, curr, j, &r0flags);
}
if (proc->e.procinfo->stackAdj % 16 != 0) {
BuildCodeLine(proc->e.procinfo->stackOps[proc->e.procinfo->stackOpCount++], "sub %r, 8", T_RSP);
}
if (proc->sym.langtype == LANG_SYSVCALL)
{
for (j = proc->e.procinfo->stackOpCount; j >= 0; j--)
{
AddLineQueueX(proc->e.procinfo->stackOps[j]);
}
if (proc->e.procinfo->has_vararg)
{
if (proc->e.procinfo->vararg_vecs > 0)
AddLineQueueX("mov eax,%u", proc->e.procinfo->vararg_vecs);
else
AddLineQueueX("xor eax,eax");
}
}
proc->e.procinfo->firstGPR = sGPR;
proc->e.procinfo->firstVEC = sVEC;
}
if (sym->langtype == LANG_VECTORCALL)
{
vcallpass = 1;
info->vsize = 0;
curr = info->paralist;
parmpos = i;
if (!(info->has_vararg)) {
if (PushInvokeParam(i, tokenarray, proc, NULL, numParam, &r0flags) != ERROR) {
DebugMsg(("InvokeDir: superfluous argument, i=%u\n", i));
return(EmitErr(TOO_MANY_ARGUMENTS_TO_INVOKE));
}
}
else {
int j = (Token_Count - i) / 2;
numParam--;
size_vararg = 0;
while (curr && curr->sym.is_vararg == FALSE) curr = curr->nextparam;
DebugMsg1(("InvokeDir: VARARG proc, numparams=%u, actual (max) params=%u, parasize=%u\n", numParam, j, info->parasize));
for (; j >= numParam; j--)
PushInvokeParam(i, tokenarray, proc, curr, j, &r0flags);
for (curr = info->paralist; curr && curr->sym.is_vararg == TRUE; curr = curr->nextparam);
}
if (sym->langtype == LANG_STDCALL ||
sym->langtype == LANG_C ||
(sym->langtype == LANG_FASTCALL && porder) ||
(sym->langtype == LANG_VECTORCALL && porder) ||
sym->langtype == LANG_SYSCALL) {
for (; curr; curr = curr->nextparam) {
numParam--;
if (PushInvokeParam(i, tokenarray, proc, curr, numParam, &r0flags) == ERROR) {
DebugMsg(("InvokeDir: PushInvokeParam(curr=%u, i=%u, numParam=%u) failed\n", curr, i, numParam));
EmitErr(TOO_FEW_ARGUMENTS_TO_INVOKE, sym->name);
}
}
}
else {
for (numParam = 0; curr && curr->sym.is_vararg == FALSE; curr = curr->nextparam, numParam++) {
if (PushInvokeParam(i, tokenarray, proc, curr, numParam, &r0flags) == ERROR) {
DebugMsg(("InvokeDir: PushInvokeParam(curr=%u, i=%u, numParam=%u) failed\n", curr, i, numParam));
EmitErr(TOO_FEW_ARGUMENTS_TO_INVOKE, sym->name);
}
}
}
}
vcallpass = 0;
if (opnd.base_reg != NULL && Parse_Pass == PASS_1 && (r0flags & R0_USED) && opnd.base_reg->bytval == 0)
EmitWarn(2, REGISTER_VALUE_OVERWRITTEN_BY_INVOKE);
p = StringBufferEnd;
if (Options.bnd)
{
strcpy(p, " bnd call ");
p += 10;
}
else
{
strcpy(p, " call ");
p += 6;
}
#if DLLIMPORT
if (sym->state == SYM_EXTERNAL && sym->dll) {
char *iatname = p;
strcpy(p, ModuleInfo.g.imp_prefix);
p += strlen(p);
p += Mangle(sym, p);
namepos++;
if (sym->iat_used == FALSE) {
sym->iat_used = TRUE;
sym->dll->cnt++;
if (sym->langtype != LANG_NONE && sym->langtype != ModuleInfo.langtype)
AddLineQueueX(" externdef %r %s: %r %r", sym->langtype + T_C - 1, iatname, T_PTR, T_PROC);
else
AddLineQueueX(" externdef %s: %r %r", iatname, T_PTR, T_PROC);
}
}
#endif
if (wasEquateProc) {
size = strlen(sym->name);
memcpy(p, sym->name, size);
*(p + size) = NULLC;
}
else
{
size = tokenarray[parmpos].tokpos - tokenarray[namepos].tokpos;
memcpy(p, tokenarray[namepos].tokpos, size);
*(p + size) = NULLC;
}
AddLineQueue(StringBufferEnd);
if ((sym->langtype == LANG_C || sym->langtype == LANG_SYSCALL) &&
(info->parasize || (info->has_vararg && size_vararg))) {
if (info->has_vararg) {
DebugMsg1(("InvokeDir: size of fix args=%u, var args=%u\n", info->parasize, size_vararg));
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL info->parasize + size_vararg);
}
else
AddLineQueueX(" add %r, %u", stackreg[ModuleInfo.Ofssize], NUMQUAL info->parasize);
}
else if (sym->langtype == LANG_FASTCALL) {
fastcall_tab[ModuleInfo.fctype].invokeend(proc, numParam, value);
}
else if (sym->langtype == LANG_VECTORCALL) {
vectorcall_tab[ModuleInfo.fctype].invokeend(proc, numParam, value);
}
else if (sym->langtype == LANG_SYSVCALL) {
sysvcall_tab[ModuleInfo.fctype].invokeend(proc, numParam, value);
}
else if (sym->langtype == LANG_DELPHICALL) {
delphicall_tab[ModuleInfo.fctype].invokeend(proc, numParam, value);
}
LstWrite(LSTTYPE_DIRECTIVE, GetCurrOffset(), NULL);
RunLineQueue();
return(NOT_ERROR);
}