#include "stdafx.h"

#include <Compiler.h>

#include "../BasicCompiler_Common/common.h"
#include "Opcode.h"

BOOL IsUse_r11(RELATIVE_VAR *pRelativeVar){
	if(pRelativeVar->bOffsetOffset||pRelativeVar->dwKind==VAR_DIRECTMEM) return 1;
	return 0;
}

void SetStructVariableFromRax( const Type &varType, const Type &calcType, RELATIVE_VAR *pRelativeVar,BOOL bUseHeap){
	int RightTermReg;
	pobj_reg=new CRegister(REG_RCX);

	//VarRegにオブジェクトポインタをコピー
	int VarReg;
	VarReg=pobj_reg->LockReg();
	SetVarPtrToReg(VarReg,pRelativeVar);

	//右辺
	if( calcType.IsReal() ){
		RightTermReg=pobj_reg->LockXmmReg();

		if( calcType.IsDouble() ){
			//movlsd RightTermReg,xmm0
			compiler.codeGenerator.op_movsd_RR(RightTermReg,REG_XMM0);
		}
		else if( calcType.IsSingle() ){
			//movlss RightTermReg,xmm0
			compiler.codeGenerator.op_movss_RR(RightTermReg,REG_XMM0);
		}
	}
	else{
		RightTermReg=pobj_reg->LockReg();

		//mov RightTermReg,rax
		compiler.codeGenerator.op_mov_RR(RightTermReg,REG_RAX);
	}

	//右辺用レジスタを解除
	if( calcType.IsReal() ) pobj_reg->UnlockXmmReg();
	else pobj_reg->UnlockReg();

	//左辺用レジスタを解除
	pobj_reg->UnlockReg();

	//レジスタ管理オブジェクトを破棄
	delete pobj_reg;
	pobj_reg=0;


	if( calcType.IsStruct() ){
		if( varType.GetClass().IsEquals( &calcType.GetClass() ) ){			//等しい

				//双方のオブジェクト型が一致、または派生・継承関係にあるとき
				//※コピーを行う

				//mov rsi,RightTermReg
				compiler.codeGenerator.op_mov_RR(REG_RSI,RightTermReg);

				//mov rdi,VarReg
				compiler.codeGenerator.op_mov_RR(REG_RDI,VarReg);

				int object_size = varType.GetClass().GetSize();

				//mov rcx,object_size
				compiler.codeGenerator.op_mov_RV(sizeof(_int64),REG_RCX,object_size);

				if(bUseHeap){
					//mov rax,rsi
					compiler.codeGenerator.op_mov_RR(REG_RAX,REG_RSI);
				}

				//rep movs byte ptr[rdi],byte ptr[rsi]
				compiler.codeGenerator.op_rep_movs(sizeof(BYTE));

				if(bUseHeap){
					//mov rcx,rax
					compiler.codeGenerator.op_mov_RR(REG_RCX,REG_RAX);

					//call free
					extern const UserProc *pSub_free;
					compiler.codeGenerator.op_call(pSub_free);
				}

				return;
		}
	}

	compiler.errorMessenger.Output(1,NULL,cp);
}


void SetDoubleVariable(int type,RELATIVE_VAR *pRelative){
	//////////////////////////
	// Double型変数に書き込む
	//////////////////////////

	//xmm0に型変換
	ChangeTypeToXmm_Double(type,REG_XMM0,REG_RAX);

	if(pRelative->dwKind==VAR_GLOBAL){
		if(pRelative->bOffsetOffset){
			//movsd qword ptr[r11+offset],xmm0
			compiler.codeGenerator.op_movsd_MR( REG_XMM0, REG_R11, (long)pRelative->offset, MOD_BASE_DISP32, Schedule::GlobalVar );
		}
		else{
			//movsd qword ptr[offset],xmm0
			compiler.codeGenerator.op_movsd_MR( REG_XMM0, 0, (long)pRelative->offset, MOD_DISP32, Schedule::GlobalVar );
		}
	}
	else if(pRelative->dwKind==VAR_REFGLOBAL){
		compiler.errorMessenger.Output(300,NULL,cp);
	}
	else if(pRelative->dwKind==VAR_LOCAL){
		if(pRelative->bOffsetOffset){
			//movsd qword ptr[rsp+r11+offset],xmm0
			compiler.codeGenerator.PutOld(
				(char)0xF2,
				(char)0x42,
				(char)0x0F,
				(char)0x11,
				(char)0x84,
				(char)0x1C
			);
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.PutOld( (long)pRelative->offset, true )
			);
		}
		else{
			//movsd qword ptr[rsp+offset],xmm0
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_movsd_MR( REG_XMM0, REG_RSP, (long)pRelative->offset, MOD_BASE_DISP32, Schedule::None, true )
			);
		}
	}
	else if( pRelative->dwKind == VAR_REFLOCAL ){
		if(pRelative->bOffsetOffset){
			//add r11,qword ptr[rsp+offset]
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_add_RM(sizeof(_int64),REG_R11,REG_RSP,(int)pRelative->offset,MOD_BASE_DISP32, Schedule::None, true )
			);
		}
		else{
			//mov r11,qword ptr[rsp+offset]
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_mov_RM(sizeof(_int64),REG_R11,REG_RSP,(int)pRelative->offset,MOD_BASE_DISP32, Schedule::None, true )
			);
		}

		goto directmem;
	}
	else if(pRelative->dwKind==VAR_DIRECTMEM){
directmem:
		//movsd qword ptr[r11],xmm0
		compiler.codeGenerator.op_movsd_MR( REG_XMM0, REG_R11, 0, MOD_BASE );
	}
}
void SetSingleVariable(int type,RELATIVE_VAR *pRelative){
	//////////////////////////
	// Single型変数に書き込む
	//////////////////////////

	//xmm0に型変換
	ChangeTypeToXmm_Single(type,REG_XMM0,REG_RAX);

	if(pRelative->dwKind==VAR_GLOBAL){
		if(pRelative->bOffsetOffset){
			//movss dword ptr[r11+offset],xmm0
			compiler.codeGenerator.op_movss_MR( REG_XMM0, REG_R11, (long)pRelative->offset, MOD_BASE_DISP32, Schedule::GlobalVar );
		}
		else{
			//movss dword ptr[offset],xmm0
			compiler.codeGenerator.op_movss_MR( REG_XMM0, 0, (long)pRelative->offset, MOD_DISP32, Schedule::GlobalVar );
		}
	}
	else if(pRelative->dwKind==VAR_REFGLOBAL){
		compiler.errorMessenger.Output(300,NULL,cp);
	}
	else if(pRelative->dwKind==VAR_LOCAL){
		if(pRelative->bOffsetOffset){
			//movss dword ptr[rsp+r11+offset],xmm0
			compiler.codeGenerator.PutOld(
				(char)0xF3,
				(char)0x42,
				(char)0x0F,
				(char)0x11,
				(char)0x84,
				(char)0x1C
			);
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.PutOld( (long)pRelative->offset, true )
			);
		}
		else{
			//movss dword ptr[rsp+offset],xmm0
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_movss_MR( REG_XMM0, REG_RSP, (long)pRelative->offset, MOD_BASE_DISP32, Schedule::None, true )
			);
		}
	}
	else if( pRelative->dwKind == VAR_REFLOCAL ){
		if(pRelative->bOffsetOffset){
			//add r11,qword ptr[rsp+offset]
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_add_RM(sizeof(_int64),REG_R11,REG_RSP,(int)pRelative->offset,MOD_BASE_DISP32, Schedule::None, true )
			);
		}
		else{
			//mov r11,qword ptr[rsp+offset]
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_mov_RM(sizeof(_int64),REG_R11,REG_RSP,(int)pRelative->offset,MOD_BASE_DISP32, Schedule::None, true )
			);
		}

		goto directmem;
	}
	else if(pRelative->dwKind==VAR_DIRECTMEM){
directmem:
		//movss dword ptr[r11],xmm0
		compiler.codeGenerator.op_movss_MR( REG_XMM0, REG_R11, 0, MOD_BASE );
	}
}
void SetRealVariable(int VarType, int CalcType, RELATIVE_VAR *pRelativeVar){
	if(VarType==DEF_DOUBLE){
		//Double型変数へスタックの内容を格納する
		SetDoubleVariable(CalcType,pRelativeVar);
	}
	else if(VarType==DEF_SINGLE){
		//Single型変数へスタックの内容を格納する
		SetSingleVariable(CalcType,pRelativeVar);
	}
}
void SetBooleanVariable(int type,RELATIVE_VAR *pRelative){
	if(type==DEF_DOUBLE){
		//Double型

		//cvttsd2si rax,xmm0
		compiler.codeGenerator.op_cvttsd2si_xmm(sizeof(_int64),REG_RAX,REG_XMM0);
	}
	else if(type==DEF_SINGLE){
		//Single型

		//cvttss2si rax,xmm0
		compiler.codeGenerator.op_cvttss2si_xmm(sizeof(_int64),REG_RAX,REG_XMM0);
	}

	//cmp rax,0
	compiler.codeGenerator.op_cmp_value(Type(type).GetSize(),REG_RAX,0);

	//setne al
	compiler.codeGenerator.op_setne( REG_RAX );

	SetWholeVariable( sizeof(char), DEF_BYTE, pRelative);
}
void SetWholeVariable(int varSize,int type,RELATIVE_VAR *pRelative){
	if(type==DEF_DOUBLE){
		//Double型

		//cvttsd2si rax,xmm0
		compiler.codeGenerator.op_cvttsd2si_xmm(sizeof(_int64),REG_RAX,REG_XMM0);
	}
	else if(type==DEF_SINGLE){
		//Single型

		//cvttss2si rax,xmm0
		compiler.codeGenerator.op_cvttss2si_xmm(sizeof(_int64),REG_RAX,REG_XMM0);
	}
	else{
		//その他の整数

		if(varSize==sizeof(_int64)){
			//レジスタの値を64ビット（rax）に拡張する
			ExtendTypeTo64(type,REG_RAX);
		}
		else if(varSize==sizeof(long)){
			//レジスタの値を32ビット（eax）に拡張する
			ExtendTypeTo32(type,REG_RAX);
		}
		else if(varSize==sizeof(short)){
			//レジスタの値を16ビット（ax）に拡張する
			ExtendTypeTo16(type,REG_RAX);
		}
		//8ビットは拡張なし
	}

	if(pRelative->dwKind==VAR_GLOBAL){
		if(pRelative->bOffsetOffset){
			//mov ptr[r11+offset],rax/eax/ax/al
			compiler.codeGenerator.op_mov_MR(varSize,REG_RAX,REG_R11,(int)pRelative->offset,MOD_BASE_DISP32, Schedule::GlobalVar );
		}
		else{
			//mov ptr[offset],rax/eax/ax/al
			compiler.codeGenerator.op_mov_MR(varSize,REG_RAX,0,(int)pRelative->offset,MOD_DISP32, Schedule::GlobalVar );
		}
	}
	else if( pRelative->dwKind == VAR_REFGLOBAL ){
		if(pRelative->bOffsetOffset){
			//add r11,qword ptr[offset]
			compiler.codeGenerator.op_add_RM( sizeof(_int64), REG_R11, REG_NON, (int)pRelative->offset, MOD_DISP32, Schedule::GlobalVar );
		}
		else{
			//mov r11,qword ptr[offset]
			compiler.codeGenerator.op_mov_RM(sizeof(_int64),REG_R11,REG_NON,(int)pRelative->offset,MOD_DISP32, Schedule::GlobalVar );
		}

		goto directmem;
	}
	else if(pRelative->dwKind==VAR_LOCAL){
		if(pRelative->bOffsetOffset){
			//mov ptr[rsp+r11+offset],rax/eax/ax/al
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_mov_MR_ex(varSize,REG_RAX,REG_RSP,REG_R11,(int)pRelative->offset,USE_OFFSET, Schedule::None, true )
			);
		}
		else{
			//mov ptr[rsp+offset],rax/eax/ax/al
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_mov_MR(varSize,REG_RAX,REG_RSP,(int)pRelative->offset,MOD_BASE_DISP32, Schedule::None, true )
			);
		}
	}
	else if( pRelative->dwKind == VAR_REFLOCAL ){
		if(pRelative->bOffsetOffset){
			//add r11,qword ptr[rsp+offset]
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_add_RM( sizeof(_int64), REG_R11, REG_RSP, (int)pRelative->offset, MOD_BASE_DISP32, Schedule::None, true )
			);
		}
		else{
			//mov r11,qword ptr[rsp+offset]
			compiler.codeGenerator.localVarPertialSchedules.push_back(
				compiler.codeGenerator.op_mov_RM(sizeof(_int64),REG_R11,REG_RSP,(int)pRelative->offset,MOD_BASE_DISP32, Schedule::None, true )
			);
		}

		goto directmem;
	}
	else if(pRelative->dwKind==VAR_DIRECTMEM){
directmem:

		//mov ptr[r11],rax/eax/ax/al
		compiler.codeGenerator.op_mov_MR(varSize,REG_RAX,REG_R11,0,MOD_BASE);
	}
}
