#include "stdafx.h"

#include <Compiler.h>

#include "../BasicCompiler_Common/common.h"
#include "Opcode.h"

BOOL Calc_Xor(int *type,LONG_PTR *index_stack,int *pStackPointer){
	//value[sp-2] xor= value[sp-1]
	//xor演算

	int sp;
	sp=*pStackPointer;

	if(IsRealNumberType(type[sp-2])||IsRealNumberType(type[sp-1])){
		//いずれかの項が実数のとき
		compiler.errorMessenger.Output(45,"xor",cp);
		return 0;
	}

	if(type[sp-2]==DEF_INT64||type[sp-2]==DEF_QWORD||
		type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
		////////////////////
		// 64ビット整数演算
		////////////////////

		//第2項を64ビットに対応させる
		if(type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
			//第2項が64ビット整数値のとき

			//pop ebx
			compiler.codeGenerator.op_pop(REG_EBX);

			//pop ecx
			compiler.codeGenerator.op_pop(REG_ECX);
		}
		else{
			//第2項がその他整数値のとき

			//pop eax
			compiler.codeGenerator.op_pop(REG_EAX);

			if(IsSignedType(type[sp-1])){
				//符号拡張
				//edx:eax ← eax
				
				//cdq
				compiler.codeGenerator.op_cdq();
			}
			else{
				//ビット拡張
				//edx:eax ← eax

				//xor edx,edx
				compiler.codeGenerator.op_zero_reg(REG_EDX);
			}

			//mov ebx,eax
			compiler.codeGenerator.op_mov_RR( REG_EBX, REG_EAX );

			//mov ecx,edx
			compiler.codeGenerator.op_mov_RR( REG_ECX, REG_EDX );
		}

		if(type[sp-2]==DEF_INT64||type[sp-2]==DEF_QWORD){
			//第1項が64ビット整数値のとき

			//xor dword ptr[esp],ebx
			compiler.codeGenerator.PutOld(
				(char)0x31,
				(char)0x1C,
				(char)0x24
			);

			//xor dword ptr[esp+sizeof(long)],ecx
			compiler.codeGenerator.PutOld(
				(char)0x31,
				(char)0x4C,
				(char)0x24,
				(char)0x04
			);
		}
		else{
			//第1項がその他整数値のとき
			if(IsSignedType(type[sp-2])){
				//pop eax
				compiler.codeGenerator.op_pop(REG_EAX);

				//符号拡張
				//edx:eax ← eax

				//cdq
				compiler.codeGenerator.op_cdq();
			}
			else{
				//pop eax
				compiler.codeGenerator.op_pop(REG_EAX);

				//ビット拡張
				//edx:eax ← eax

				//xor edx,edx
				compiler.codeGenerator.op_zero_reg(REG_EDX);
			}

			//xor ebx,eax
			compiler.codeGenerator.op_xor_RR( REG_EBX, REG_EAX );

			//xor ecx,edx
			compiler.codeGenerator.op_xor_RR( REG_ECX, REG_EDX );

			//push ecx
			compiler.codeGenerator.op_push(REG_ECX);

			//push ebx
			compiler.codeGenerator.op_push(REG_EBX);
		}

		sp--;
		if(type[sp-1]==DEF_QWORD&&type[sp]==DEF_QWORD) type[sp-1]=DEF_QWORD;
		else type[sp-1]=DEF_INT64;
	}
	else{
		////////////////////
		// 整数演算
		////////////////////

		//pop ebx
		compiler.codeGenerator.op_pop(REG_EBX);

		//pop eax
		compiler.codeGenerator.op_pop(REG_EAX);

		//sub esp,4
		compiler.codeGenerator.op_sub_esp(4);

		//xor eax,ebx
		compiler.codeGenerator.op_xor_RR( REG_EAX, REG_EBX );

		//mov dword ptr[esp],eax
		compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_ESP, 0, MOD_BASE );

		sp--;
		type[sp-1]=NeutralizationType(type[sp-1],index_stack[sp-1],type[sp],index_stack[sp]);
	}

	*pStackPointer=sp;
	return 1;
}

BOOL Calc_Or(int *type,LONG_PTR *index_stack,int *pStackPointer){
	//value[sp-2] or= value[sp-1]
	//or演算

	int sp;
	sp=*pStackPointer;

	if(IsRealNumberType(type[sp-2])||IsRealNumberType(type[sp-1])){
		//いずれかの項が実数のとき
		compiler.errorMessenger.Output(45,"or",cp);
		return 0;
	}

	if(type[sp-2]==DEF_INT64||type[sp-2]==DEF_QWORD||
		type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
		////////////////////
		// 64ビット整数演算
		////////////////////

		//第2項を64ビットに対応させる
		if(type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
			//第2項が64ビット整数値のとき

			//pop ebx
			compiler.codeGenerator.op_pop(REG_EBX);

			//pop ecx
			compiler.codeGenerator.op_pop(REG_ECX);
		}
		else{
			//第2項が32ビット整数値のとき

			//pop eax
			compiler.codeGenerator.op_pop(REG_EAX);

			if(IsSignedType(type[sp-1])){
				//符号拡張
				//edx:eax ← eax
				
				//cdq
				compiler.codeGenerator.op_cdq();
			}
			else{
				//ビット拡張
				//edx:eax ← eax

				//xor edx,edx
				compiler.codeGenerator.op_zero_reg(REG_EDX);
			}

			//mov ebx,eax
			compiler.codeGenerator.op_mov_RR( REG_EBX, REG_EAX );

			//mov ecx,edx
			compiler.codeGenerator.op_mov_RR( REG_ECX, REG_EDX );
		}

		if(type[sp-2]==DEF_INT64||type[sp-2]==DEF_QWORD){
			//第1項が64ビット整数値のとき

			//or dword ptr[esp],ebx
			compiler.codeGenerator.PutOld(
				(char)0x09,
				(char)0x1C,
				(char)0x24
			);

			//or dword ptr[esp+sizeof(long)],ecx
			compiler.codeGenerator.PutOld(
				(char)0x09,
				(char)0x4C,
				(char)0x24,
				(char)0x04
			);
		}
		else{
			//第1項が32ビット整数値のとき
			if(IsSignedType(type[sp-2])){
				//pop eax
				compiler.codeGenerator.op_pop(REG_EAX);

				//符号拡張
				//edx:eax ← eax

				//cdq
				compiler.codeGenerator.op_cdq();
			}
			else{
				//pop eax
				compiler.codeGenerator.op_pop(REG_EAX);

				//ビット拡張
				//edx:eax ← eax

				//xor edx,edx
				compiler.codeGenerator.op_zero_reg(REG_EDX);
			}

			//or ebx,eax
			compiler.codeGenerator.op_or_RR( sizeof(long), REG_EBX, REG_EAX );

			//or ecx,edx
			compiler.codeGenerator.op_or_RR( sizeof(long), REG_ECX, REG_EDX );

			//push ecx
			compiler.codeGenerator.op_push(REG_ECX);

			//push ebx
			compiler.codeGenerator.op_push(REG_EBX);
		}

		sp--;
		if(type[sp-1]==DEF_QWORD&&type[sp]==DEF_QWORD) type[sp-1]=DEF_QWORD;
		else type[sp-1]=DEF_INT64;
	}
	else{
		////////////////////
		// 32ビット整数演算
		////////////////////

		//pop ebx
		compiler.codeGenerator.op_pop(REG_EBX);

		//pop eax
		compiler.codeGenerator.op_pop(REG_EAX);

		//sub esp,4
		compiler.codeGenerator.op_sub_esp(4);

		//or eax,ebx
		compiler.codeGenerator.op_or_RR( sizeof(long), REG_EAX, REG_EBX );

		//mov dword ptr[esp],eax
		compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_ESP, 0, MOD_BASE );

		sp--;
		type[sp-1]=NeutralizationType(type[sp-1],index_stack[sp-1],type[sp],index_stack[sp]);
	}

	*pStackPointer=sp;
	return 1;
}

BOOL Calc_And(int *type,LONG_PTR *index_stack,int *pStackPointer){
	//value[sp-2] and= value[sp-1]
	//and演算

	int sp;
	sp=*pStackPointer;

	if(IsRealNumberType(type[sp-2])||IsRealNumberType(type[sp-1])){
		//いずれかの項が実数のとき
		compiler.errorMessenger.Output(45,"and",cp);
		return 0;
	}

	if(type[sp-2]==DEF_INT64||type[sp-2]==DEF_QWORD||
		type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
		////////////////////
		// 64ビット整数演算
		////////////////////

		//第2項を64ビットに対応させる
		if(type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
			//第2項が64ビット整数値のとき

			//pop ebx
			compiler.codeGenerator.op_pop(REG_EBX);

			//pop ecx
			compiler.codeGenerator.op_pop(REG_ECX);
		}
		else{
			//第2項が32ビット整数値のとき

			//pop eax
			compiler.codeGenerator.op_pop(REG_EAX);

			if(IsSignedType(type[sp-1])){
				//符号拡張
				//edx:eax ← eax
				
				//cdq
				compiler.codeGenerator.op_cdq();
			}
			else{
				//ビット拡張
				//edx:eax ← eax

				//xor edx,edx
				compiler.codeGenerator.op_zero_reg(REG_EDX);
			}

			//mov ebx,eax
			compiler.codeGenerator.op_mov_RR( REG_EBX, REG_EAX );

			//mov ecx,edx
			compiler.codeGenerator.op_mov_RR( REG_ECX, REG_EDX );
		}

		if(type[sp-2]==DEF_INT64||type[sp-2]==DEF_QWORD){
			//第1項が64ビット整数値のとき

			//and dword ptr[esp],ebx
			compiler.codeGenerator.PutOld(
				(char)0x21,
				(char)0x1C,
				(char)0x24
			);

			//and dword ptr[esp+sizeof(long)],ecx
			compiler.codeGenerator.PutOld(
				(char)0x21,
				(char)0x4C,
				(char)0x24,
				(char)0x04
			);
		}
		else{
			//第1項が32ビット整数値のとき
			if(IsSignedType(type[sp-2])){
				//pop eax
				compiler.codeGenerator.op_pop(REG_EAX);

				//符号拡張
				//edx:eax ← eax

				//cdq
				compiler.codeGenerator.op_cdq();
			}
			else{
				//pop eax
				compiler.codeGenerator.op_pop(REG_EAX);

				//ビット拡張
				//edx:eax ← eax

				//xor edx,edx
				compiler.codeGenerator.op_zero_reg(REG_EDX);
			}

			//and ebx,eax
			compiler.codeGenerator.op_and_RR( REG_EBX, REG_EAX );

			//and ecx,edx
			compiler.codeGenerator.op_and_RR( REG_ECX, REG_EDX );

			//push ecx
			compiler.codeGenerator.op_push(REG_ECX);

			//push ebx
			compiler.codeGenerator.op_push(REG_EBX);
		}

		sp--;
		if(type[sp-1]==DEF_QWORD&&type[sp]==DEF_QWORD) type[sp-1]=DEF_QWORD;
		else type[sp-1]=DEF_INT64;
	}
	else{
		////////////////////
		// 32ビット整数演算
		////////////////////

		//pop ebx
		compiler.codeGenerator.op_pop(REG_EBX);

		//pop eax
		compiler.codeGenerator.op_pop(REG_EAX);

		//sub esp,4
		compiler.codeGenerator.op_sub_esp(4);

		//and eax,ebx
		compiler.codeGenerator.op_and_RR( REG_EAX, REG_EBX );

		//mov dword ptr[esp],eax
		compiler.codeGenerator.op_mov_MR( sizeof(long), REG_EAX, REG_ESP, 0, MOD_BASE );

		sp--;
		type[sp-1]=NeutralizationType(type[sp-1],index_stack[sp-1],type[sp],index_stack[sp]);
	}

	*pStackPointer=sp;
	return 1;
}

BOOL Calc_Not(int *type,int sp){
	//value[sp-1]=Not value[sp-1]
	//NOT演算子

	if(IsRealNumberType(type[sp-1])){
		//実数のとき
		compiler.errorMessenger.Output(45,"Not",cp);
		return 0;
	}

	if( type[sp - 1] == DEF_BOOLEAN ){
		//pop eax
		compiler.codeGenerator.op_pop( REG_EAX );

		//cmp eax,0
		compiler.codeGenerator.op_cmp_value(Type(type[sp-1]).GetSize(),REG_EAX,0);

		//setne al
		compiler.codeGenerator.op_setne( REG_EAX );

		//and eax,000000FFh
		compiler.codeGenerator.op_and_RV(REG_EAX,(int)0xFF);

		//neg
		compiler.codeGenerator.op_neg( REG_EAX );

		//sbb eax, eax
		compiler.codeGenerator.op_sbb_RR( REG_EAX, REG_EAX );

		//add eax, 1
		compiler.codeGenerator.op_add_RV8( REG_EAX, 1 );

		//push eax
		compiler.codeGenerator.op_push( REG_EAX );
	}
	else if(type[sp-1]==DEF_INT64||type[sp-1]==DEF_QWORD){
		////////////////////
		// 64ビット整数演算
		////////////////////

		//not dword ptr[esp]
		compiler.codeGenerator.PutOld(
			(char)0xF7,
			(char)0x14,
			(char)0x24
		);

		//not dword ptr[esp+4]
		compiler.codeGenerator.PutOld(
			(char)0xF7,
			(char)0x54,
			(char)0x24,
			(char)0x04
		);
	}
	else{
		////////////////////
		// 32ビット整数演算
		////////////////////

		//not dword ptr[esp]
		compiler.codeGenerator.PutOld(
			(char)0xF7,
			(char)0x14,
			(char)0x24
		);
	}

	return 1;
}
