
//included on x86_emitter.cpp

/*
enum x86_op_params
{
	param_none,
	param_reg,
	param_mem,
	param_imm,

	param_reg_reg,
	param_reg_mem,
	param_reg_imm,

	param_mem_reg,
	param_mem_imm,
};
*/

encoded_type pg_none = {pg_NONE};

encoded_type __fastcall param_type(x86_Label* lbl)
{
	encoded_type rv;
	//Return pg_MEM_Rel32/pg_MEM_Rel16/pg_MEM_Rel8
	//we do need some more info on this :P
	if (lbl->patch_sz==8)
		rv.type=pg_MEM_Rel8;
	else
		rv.type=pg_MEM_Rel32;
	rv.ptr=lbl;
	rv.ptr_type=1;
	return rv;
}
encoded_type __fastcall param_type(x86_ptr_imm ptr)
{
	encoded_type rv;
	//Return pg_MEM_Rel32.Due to relocation we cant optimise to 16/8 in one pass ...
	//we do need some more info on this :P
	rv.type=pg_MEM_Rel32;
	rv.ptr=ptr.ptr;
	rv.ptr_type=0;
	return rv;
}
encoded_type __fastcall param_type(x86_mrm_t& modrm)
{
	encoded_type rv;
	rv.modrm=modrm;
	//Return reg , mem cmplx , mem direct
	rv.type=pg_ModRM;
	return rv;
}
encoded_type __fastcall param_type(x86_reg reg)
{
	encoded_type rv;
	rv.reg=REG_ID(reg);
	//later : detect R0 :)
	if (reg==EAX ||reg==AX ||reg==AL)
		rv.type=pg_R0;
	else if (reg==CL || reg==ECX)
		rv.type=pg_CL;
	else
		rv.type=pg_REG;
	return rv;
}

encoded_type __fastcall param_type(u32 imm)
{
	encoded_type rv;
	rv.imm=imm;
	//later : detect u8/s8/s16/s32 encodings :)
	
	if (IsS8(imm))
		rv.type=pg_IMM_S8;
	else if ((imm & (~0xFF))==0)
		rv.type=pg_IMM_U8;
	else if ((imm & (~0xFFFF))==0)
		rv.type=pg_IMM_U16;
	else
		rv.type=pg_IMM_U32;

	return rv;
}
void __fastcall Match_opcode(x86_block* block,const x86_opcode* ops,encoded_type pg1,encoded_type pg2,encoded_type pg3)
{
	block->opcode_count++;
	const x86_opcode* match=0;
	for (u32 i=0;ops[i].encode!=0;i++)
	{
			if (ENC_PARAM_CONTAINS(ops[i].pg_1,pg1.type) &&
				ENC_PARAM_CONTAINS(ops[i].pg_2,pg2.type) &&
				ENC_PARAM_CONTAINS(ops[i].pg_3,pg3.type)
				)
			{
				match= &ops[i];
				break;
			}
	}
	if (match==0)
	{
		char temp[512];
		sprintf(temp,"Unable to match opcode %s",DissasmClass(ops->opcode));
		die(temp);
		return;
	}
//	printf("Matched opcode %s to %s\n",DissasmClass(ops->opcode),DissasmClass(match->opcode));
	match->encode(block,match,&pg1,&pg2,pg3.imm);
}

#define ME_op_0(opcl)					Match_opcode(this,x86_opcode_list[opcl], pg_none, pg_none, pg_none)

#define ME_op_1_nrm(opcl, pg1)				Match_opcode(this,x86_opcode_list[opcl], param_type(pg1), pg_none, pg_none)
#define ME_op_1_imm(opcl, pg1)				Match_opcode(this,x86_opcode_list[opcl], pg_none, pg_none, param_type(pg1))

#define ME_op_2_nrm(opcl, pg1, pg2)			Match_opcode(this,x86_opcode_list[opcl], param_type(pg1), param_type(pg2), pg_none)
#define ME_op_2_imm(opcl, pg1, pg2)			Match_opcode(this,x86_opcode_list[opcl], param_type(pg1), pg_none,param_type(pg2))

#define ME_op_3_nrm(opcl, pg1, pg2, pg3)	Match_opcode(this,x86_opcode_list[opcl], param_type(pg1), param_type(pg2), param_type(pg3))
#define ME_op_3_imm(opcl, pg1, pg2, pg3)	Match_opcode(this,x86_opcode_list[opcl], param_type(pg1), param_type(pg2), param_type(pg3))