#include "stdafx.h"

#include <Compiler.h>

#include "../BasicCompiler_Common/common.h"
#include "Opcode.h"

BOOL CalcTwoTerm_Arithmetic(int idCalc,int *type,LONG_PTR *index_stack,int *pStackPointer){
	/*	value[sp-2] = value[sp-2] + value[sp-1]
		value[sp-2] = value[sp-2] - value[sp-1]
		value[sp-2] = value[sp-2] * value[sp-1]		*/

	int reg1,reg2;

	int sp;
	sp=*pStackPointer;

	int AnswerType;
	AnswerType=NeutralizationType(type[sp-2],index_stack[sp-2],type[sp-1],index_stack[sp-1]);

	if(type[sp-2]==DEF_DOUBLE||type[sp-2]==DEF_SINGLE||
		type[sp-1]==DEF_DOUBLE||type[sp-1]==DEF_SINGLE){
		/////////////
		// 実数演算
		/////////////

		int xmm_reg1,xmm_reg2;

		//2つの項を適切なレジスタにセット
		SetTowTermToReg_RealCalc(AnswerType,type,sp,&xmm_reg1,&xmm_reg2);

		if(AnswerType==DEF_DOUBLE){
			///////////////////////
			// Double演算
			///////////////////////

			if(idCalc==CALC_ADDITION){
				//addsd xmm_reg1,xmm_reg2
				compiler.codeGenerator.PutOld(
					(char)0xF2,
					(char)0x0F,
					(char)0x58,
					(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
				);
			}
			else if(idCalc==CALC_SUBTRACTION){
				//subsd xmm_reg1,xmm_reg2
				compiler.codeGenerator.PutOld(
					(char)0xF2,
					(char)0x0F,
					(char)0x5C,
					(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
				);
			}
			else if(idCalc==CALC_PRODUCT){
				//mulsd xmm_reg1,xmm_reg2
				compiler.codeGenerator.PutOld(
					(char)0xF2,
					(char)0x0F,
					(char)0x59,
					(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
				);
			}

			if(xmm_reg1==REG_XMM4){
				//movsd qword ptr[rsp+offset],xmm4		※スタックフレームを利用
				pobj_sf->push(REG_XMM4,sizeof(double));
			}
		}
		if(AnswerType==DEF_SINGLE){
			///////////////////////
			// Single演算
			///////////////////////

			if(idCalc==CALC_ADDITION){
				//addss xmm_reg1,xmm_reg2
				compiler.codeGenerator.PutOld(
					(char)0xF3,
					(char)0x0F,
					(char)0x58,
					(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
				);
			}
			else if(idCalc==CALC_SUBTRACTION){
				//subss xmm_reg1,xmm_reg2
				compiler.codeGenerator.PutOld(
					(char)0xF3,
					(char)0x0F,
					(char)0x5C,
					(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
				);
			}
			else if(idCalc==CALC_PRODUCT){
				//mulss xmm_reg1,xmm_reg2
				compiler.codeGenerator.PutOld(
					(char)0xF3,
					(char)0x0F,
					(char)0x59,
					(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
				);
			}

			if(xmm_reg1==REG_XMM4){
				//movss dword ptr[rsp+offset],xmm4		※スタックフレームを利用
				pobj_sf->push(REG_XMM4,sizeof(float));
			}
		}
	}
	else if(Is64Type(type[sp-2])||Is64Type(type[sp-1])){
		//////////////////////
		// 64ビット整数演算
		//////////////////////

		SetTowTermToReg_Whole64Calc(type,sp,&reg1,&reg2);

		if(idCalc==CALC_ADDITION){
			//add reg1,reg2
			compiler.codeGenerator.op_add_RR(reg1,reg2);
		}
		else if(idCalc==CALC_SUBTRACTION){
			//sub reg1,reg2
			compiler.codeGenerator.op_sub64_reg(reg1,reg2);
		}
		else if(idCalc==CALC_PRODUCT){
			//mul reg1,reg2
			compiler.codeGenerator.op_imul_RR(sizeof(_int64),reg1,reg2);
		}

		if(reg1==REG_R14){
			//mov qword ptr[rsp+offset],r14     ※スタックフレームを利用
			pobj_sf->push(REG_R14);
		}
	}
	else{
		//32ビット以下の整数演算

		SetTowTermToReg_Whole32Calc(type,sp,&reg1,&reg2);

		if(idCalc==CALC_ADDITION){
			//add reg1,reg2
			compiler.codeGenerator.op_add32_reg(reg1,reg2);
		}
		else if(idCalc==CALC_SUBTRACTION){
			//sub reg1,reg2
			compiler.codeGenerator.op_sub32_reg(reg1,reg2);
		}
		else if(idCalc==CALC_PRODUCT){
			//mul reg1,reg2
			compiler.codeGenerator.op_imul_RR(sizeof(long),reg1,reg2);
		}

		if(reg1==REG_R14){
			//mov qword ptr[rsp+offset],r14     ※スタックフレームを利用
			pobj_sf->push(REG_R14);
		}
	}

	sp--;
	type[sp-1]=AnswerType;

	*pStackPointer=sp;

	return 1;
}



BOOL Calc_Mod(int *type,LONG_PTR *index_stack,int *pStackPointer){
	//value[sp-2]%=value[sp-1]
	//剰余演算

	int reg1,reg2;
	int AnswerType;

	int sp;
	sp=*pStackPointer;

	if(IsRealNumberType(type[sp-2])||IsRealNumberType(type[sp-1])){
		//実数演算は行えないため、エラー扱い
		compiler.errorMessenger.Output(45,"mod",cp);
		return 0;
	}

	/////////////////////////
	// 64ビット整数演算のみ
	/////////////////////////

	AnswerType=NeutralizationType(type[sp-2],index_stack[sp-2],type[sp-1],index_stack[sp-1]);

	//2つの項を適切なレジスタにセット
	SetTowTermToReg_Whole64Calc(type,sp,&reg1,&reg2);

	if(reg2==REG_RAX||reg2==REG_RDX){
		//mov r15,reg2
		compiler.codeGenerator.op_mov_RR(REG_R15,reg2);

		reg2=REG_R15;
	}

	//raxまたはrdxが使用中かどうかを調べる( true/使用中, false/未使用 )
	bool isUsingRax = pobj_reg->IsUsing( REG_RAX );
	bool isUsingRdx = pobj_reg->IsUsing( REG_RDX );

	if(reg1!=REG_RDX && isUsingRdx){
		//結果レジスタがrdxでない場合（使用されている可能性があるとき）

		//mov qword ptr[rsp+offset],rdx     ※スタックフレームを利用
		pobj_sf->push(REG_RDX);
	}

	if(reg1!=REG_RAX && isUsingRax){
		//結果レジスタがraxでない場合（使用されている可能性があるとき）

		//mov qword ptr[rsp+offset],rax     ※スタックフレームを利用
		pobj_sf->push(REG_RAX);
	}

	{

		//mov rax,reg1
		compiler.codeGenerator.op_mov_RR(REG_RAX,reg1);

		if(IsSignedType(type[sp-2])){
			//符号拡張
			//rdx:rax ← rax

			//cqo
			compiler.codeGenerator.op_cqo();
		}
		else{
			//ビット拡張
			//rdx:rax ← rax

			//xor rdx,rdx
			compiler.codeGenerator.op_zero_reg(REG_RDX);
		}

		if(IsSignedType(AnswerType)){
			//idiv reg2
			compiler.codeGenerator.op_idiv64_reg(reg2);
		}
		else{
			//div reg2
			compiler.codeGenerator.op_div64_reg(reg2);
		}

		//mov reg1,rdx
		compiler.codeGenerator.op_mov_RR(reg1,REG_RDX);

	}

	if(reg1!=REG_RAX && isUsingRax){
		//結果レジスタがraxでない場合（使用されている可能性があるとき）

		//mov rax,qword ptr[rsp+offset]     ※スタックフレームを利用
		pobj_sf->pop(REG_RAX);
	}

	if(reg1!=REG_RDX && isUsingRdx){
		//結果レジスタがrdxでない場合（使用されている可能性があるとき）

		//mov rdx,qword ptr[rsp+offset]     ※スタックフレームを利用
		pobj_sf->pop(REG_RDX);
	}


	if(reg1==REG_R14){
		//mov qword ptr[rsp+offset],r14     ※スタックフレームを利用
		pobj_sf->push(REG_R14);
	}

	sp--;
	type[sp-1]=AnswerType;


	*pStackPointer=sp;

	return 1;
}

BOOL Calc_Divide(int *type,int *pStackPointer,int BaseType){
	//value[sp-2]/=value[sp-1];
	//除算

	int sp;
	sp=*pStackPointer;

	///////////////////////
	// 実数演算のみ
	///////////////////////

	int AnswerType;
	if(type[sp-2]==DEF_SINGLE&&type[sp-1]==DEF_SINGLE&&BaseType==DEF_SINGLE) AnswerType=DEF_SINGLE;
	else AnswerType=DEF_DOUBLE;

	int xmm_reg1,xmm_reg2;

	//2つの項を適切なレジスタにセット
	SetTowTermToReg_RealCalc(AnswerType,type,sp,&xmm_reg1,&xmm_reg2);

	if(AnswerType==DEF_DOUBLE){
		///////////////////////
		// Double演算
		///////////////////////

		//divsd xmm_reg1,xmm_reg2
		compiler.codeGenerator.PutOld(
			(char)0xF2,
			(char)0x0F,
			(char)0x5E,
			(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
		);

		if(xmm_reg1==REG_XMM4){
			//movsd qword ptr[rsp+offset],xmm4		※スタックフレームを利用
			pobj_sf->push(REG_XMM4,sizeof(double));
		}
	}
	if(AnswerType==DEF_SINGLE){
		///////////////////////
		// Single演算
		///////////////////////

		//divss xmm_reg1,xmm_reg2
		compiler.codeGenerator.PutOld(
			(char)0xF3,
			(char)0x0F,
			(char)0x5E,
			(char)(0xC0 | REGISTER_OPERAND(xmm_reg1)<<3 | REGISTER_OPERAND(xmm_reg2))
		);

		if(xmm_reg1==REG_XMM4){
			//movss dword ptr[rsp+offset],xmm4		※スタックフレームを利用
			pobj_sf->push(REG_XMM4,sizeof(float));
		}
	}

	sp--;
	type[sp-1]=AnswerType;


	*pStackPointer=sp;

	return 1;
}

BOOL Calc_IntDivide(int *type,LONG_PTR *index_stack,int *pStackPointer){
	//value[sp-2]/=value[sp-1]
	//除算（整数）

	int reg1,reg2;
	int AnswerType;

	int sp;
	sp=*pStackPointer;

	if(IsRealNumberType(type[sp-2])||IsRealNumberType(type[sp-1])){
		//実数演算は行えないため、エラー扱い
		compiler.errorMessenger.Output(45,"mod",cp);
		return 0;
	}

	/////////////////////////
	// 64ビット整数演算のみ
	/////////////////////////

	AnswerType=NeutralizationType(type[sp-2],index_stack[sp-2],type[sp-1],index_stack[sp-1]);

	//2つの項を適切なレジスタにセット
	SetTowTermToReg_Whole64Calc(type,sp,&reg1,&reg2);

	if(reg2==REG_RAX||reg2==REG_RDX){
		//mov r15,reg2
		compiler.codeGenerator.op_mov_RR(REG_R15,reg2);

		reg2=REG_R15;
	}

	//raxまたはrdxが使用中かどうかを調べる( true/使用中, false/未使用 )
	bool isUsingRax = pobj_reg->IsUsing( REG_RAX );
	bool isUsingRdx = pobj_reg->IsUsing( REG_RDX );

	if(reg1!=REG_RDX && isUsingRdx){
		//結果レジスタがrdxでない場合（使用されている可能性があるとき）

		//mov qword ptr[rsp+offset],rdx     ※スタックフレームを利用
		pobj_sf->push(REG_RDX);
	}

	if(reg1!=REG_RAX && isUsingRax){
		//結果レジスタがraxでない場合（使用されている可能性があるとき）

		//mov qword ptr[rsp+offset],rax     ※スタックフレームを利用
		pobj_sf->push(REG_RAX);
	}

	{

		//mov rax,reg1
		compiler.codeGenerator.op_mov_RR(REG_RAX,reg1);

		if(IsSignedType(type[sp-2])){
			//符号拡張
			//rdx:rax ← rax

			//cqo
			compiler.codeGenerator.op_cqo();
		}
		else{
			//ビット拡張
			//rdx:rax ← rax

			//xor rdx,rdx
			compiler.codeGenerator.op_zero_reg(REG_RDX);
		}

		if(IsSignedType(AnswerType)){
			//idiv reg2
			compiler.codeGenerator.op_idiv64_reg(reg2);
		}
		else{
			//div reg2
			compiler.codeGenerator.op_div64_reg(reg2);
		}

		//mov reg1,rax
		compiler.codeGenerator.op_mov_RR(reg1,REG_RAX);

	}

	if(reg1!=REG_RAX && isUsingRax){
		//結果レジスタがraxでない場合（使用されている可能性があるとき）

		//mov rax,qword ptr[rsp+offset]     ※スタックフレームを利用
		pobj_sf->pop(REG_RAX);
	}

	if(reg1!=REG_RDX && isUsingRdx){
		//結果レジスタがrdxでない場合（使用されている可能性があるとき）

		//mov rdx,qword ptr[rsp+offset]     ※スタックフレームを利用
		pobj_sf->pop(REG_RDX);
	}


	if(reg1==REG_R14){
		//mov qword ptr[rsp+offset],r14     ※スタックフレームを利用
		pobj_sf->push(REG_R14);
	}

	sp--;
	type[sp-1]=AnswerType;

	*pStackPointer=sp;

	return 1;
}

BOOL Calc_MinusMark(int *type,int sp){
	//value[sp-1]=-value[sp-1]
	//符号反転

	int xmm_reg;
	int reg;
	int i32data;

	if(type[sp-1]==DEF_DOUBLE){
		SetOneTermToReg_RealCalc(type[sp-1],&xmm_reg);

		double dbl;
		dbl=-1;
		i32data = compiler.GetObjectModule().dataTable.Add( dbl );

		//mulsd xmm_reg,qword ptr[data table offset]   ※data = -1
		compiler.codeGenerator.PutOld(
			(char)0xF2,
			(char)0x0F,
			(char)0x59,
			(char)(0x04 | REGISTER_OPERAND(xmm_reg)<<3),
			(char)0x25
		);
		compiler.codeGenerator.PutOld(
			(long)i32data,
			Schedule::DataTable
		);

		if(xmm_reg==REG_XMM4){
			//movsd qword ptr[rsp+offset],xmm4		※スタックフレームを利用
			pobj_sf->push(REG_XMM4,sizeof(double));
		}
	}
	else if(type[sp-1]==DEF_SINGLE){
		SetOneTermToReg_RealCalc(type[sp-1],&xmm_reg);

		float flt;
		flt=-1;
		i32data = compiler.GetObjectModule().dataTable.Add( flt );

		//mulss xmm_reg,dword ptr[data table offset]   ※data = -1
		compiler.codeGenerator.PutOld(
			(char)0xF3,
			(char)0x0F,
			(char)0x59,
			(char)(0x04 | REGISTER_OPERAND(xmm_reg)<<3),
			(char)0x25
		);
		compiler.codeGenerator.PutOld(
			(long)i32data,
			Schedule::DataTable
		);

		if(xmm_reg==REG_XMM4){
			//movss dword ptr[rsp+offset],xmm4		※スタックフレームを利用
			pobj_sf->push(REG_XMM4,sizeof(float));
		}
	}
	else if(type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
		SetOneTermToReg_Whole64Calc(type[sp-1],&reg);

		//imul reg,-1
		compiler.codeGenerator.op_imul_RV(sizeof(_int64),reg,-1);

		if(reg==REG_R14){
			//mov qword ptr[rsp+offset],r14     ※スタックフレームを利用
			pobj_sf->push(REG_R14);
		}

		type[sp-1]=DEF_INT64;	//QWordはInt64へ
	}
	else if(IsWholeNumberType(type[sp-1])){
		SetOneTermToReg_Whole32Calc(type[sp-1],&reg);

		//imul reg,-1
		compiler.codeGenerator.op_imul_RV(sizeof(long),reg,-1);

		if(reg==REG_R14){
			//mov qword ptr[rsp+offset],r14     ※スタックフレームを利用
			pobj_sf->push(REG_R14);
		}

		type[sp-1]=GetSignedType(type[sp-1]);
	}

	return 1;
}

BOOL Calc_Power(int *type,int *pStackPointer){
	//べき乗（実数演算のみ）

	int sp;
	sp=*pStackPointer;


	//2つの項を適切なレジスタにセット
	int xmm_reg1,xmm_reg2;
	SetTowTermToReg_RealCalc(DEF_DOUBLE,type,sp,&xmm_reg1,&xmm_reg2);


	//////////////////////////////////////////////////////
	/////    レジスタ資源のバックアップ
	{	BACKUP_REGISTER_RESOURCE
	//////////////////////////////////////////////////////


		////////////////
		// 呼び出し
		////////////////

		if(xmm_reg1==REG_XMM1){
			//movsd xmm0,xmm_reg1
			compiler.codeGenerator.op_movsd_RR(REG_XMM0,xmm_reg1);

			//movsd xmm1,xmm_reg2
			compiler.codeGenerator.op_movsd_RR(REG_XMM1,xmm_reg2);
		}
		else{
			//movsd xmm1,xmm_reg2
			compiler.codeGenerator.op_movsd_RR(REG_XMM1,xmm_reg2);

			//movsd xmm0,xmm_reg1
			compiler.codeGenerator.op_movsd_RR(REG_XMM0,xmm_reg1);
		}

		//call pow
		extern const UserProc *pSub_pow;
		compiler.codeGenerator.op_call(pSub_pow);

		//movsd xmm4,xmm0
		compiler.codeGenerator.op_movsd_RR(REG_XMM4,REG_XMM0);


	/////////////////////////////////////////////
	//////   レジスタ資源を復元
		RESTORE_REGISTER_RESOURCE
	}////////////////////////////////////////////


	//////////////////////////////////
	// 戻り値を所定のレジスタへ格納
	//////////////////////////////////

	if(xmm_reg1==REG_XMM4){
		//movsd qword ptr[rsp+offset],xmm4		※スタックフレームを利用
		pobj_sf->push(REG_XMM0,sizeof(double));
	}
	else{
		//movsd xmm_reg1,xmm4
		compiler.codeGenerator.op_movsd_RR(xmm_reg1,REG_XMM4);
	}


	sp--;
	type[sp-1]=DEF_DOUBLE;

	*pStackPointer=sp;
	return 1;
}

BOOL Calc_Shift(int idCalc,int *type,int *pStackPointer){
	//ビットシフト

	int sp;
	sp=*pStackPointer;

	if(IsRealNumberType(type[sp-2])||IsRealNumberType(type[sp-1])){
		//いずれかの項が実数のとき
		compiler.errorMessenger.Output(45,"<<",cp);
		return 0;
	}


	/////////////////////////
	// 64ビット整数演算のみ
	/////////////////////////
	int reg1,reg2;

	//2つの項を適切なレジスタにセット
	SetTowTermToReg_Whole64Calc(type,sp,&reg1,&reg2);

	int sw=0;
	if(reg1==REG_RCX){
		//mov r15,rcx
		compiler.codeGenerator.op_mov_RR(REG_R15,REG_RCX);

		reg1=REG_R15;
	}
	else if(reg2!=REG_RCX){
		sw=1;

		//mov qword ptr[rsp+offset],rcx     ※スタックフレームを利用
		pobj_sf->push(REG_RCX);
	}

	//mov rcx,reg2
	compiler.codeGenerator.op_mov_RR(REG_RCX,reg2);

	if(idCalc==CALC_SHL){
		//左シフトは符号あり、なしは同様の動きをする

		//32ビット型にする
		if(!Is64Type(type[sp-2])){
			ExtendTypeTo32(type[sp-2],reg1);

			if(IsSignedType(type[sp-2])) type[sp-2]=DEF_LONG;
			else type[sp-2]=DEF_DWORD;
		}

		//shl reg1,cl
		compiler.codeGenerator.op_shl_reg(Type(type[sp-2]).GetSize(),reg1);
	}
	else if(idCalc==CALC_SHR){
		if(IsSignedType(type[sp-2])){
			//符号あり

			//sar
			compiler.codeGenerator.op_sar_reg(Type(type[sp-2]).GetSize(),reg1);
		}
		else{
			//符号なし

			//shr
			compiler.codeGenerator.op_shr_reg(Type(type[sp-2]).GetSize(),reg1);
		}
	}

	if(sw==0){
		//mov rcx,r15
		compiler.codeGenerator.op_mov_RR(REG_RCX,REG_R15);
	}
	else{
		//mov rcx,qword ptr[rsp+offset]     ※スタックフレームを利用
		pobj_sf->pop(REG_RCX);
	}

	if(reg1==REG_R14){
		//mov qword ptr[rsp+offset],r14     ※スタックフレームを利用
		pobj_sf->push(REG_R14);
	}

	sp--;

	*pStackPointer=sp;
	return 1;
}
