<commit_before>#include "stdafx.h"
#include "MipsMacros.h"
#include "CMipsInstruction.h"
#include "Core/Common.h"
#include "Mips.h"
#include "MipsOpcodes.h"
#include "Parser/Parser.h"
#include "MipsParser.h"

MipsMacroCommand::MipsMacroCommand(CAssemblerCommand* content, int macroFlags)
{
	this->content = content;
	this->macroFlags = macroFlags;
	IgnoreLoadDelay = Mips.GetIgnoreDelay();
}

MipsMacroCommand::~MipsMacroCommand()
{
	delete content;
}

bool MipsMacroCommand::Validate()
{
	u64 memoryPos = g_fileManager->getVirtualAddress();
	content->applyFileInfo();
	bool result = content->Validate();
	u64 newMemoryPos = g_fileManager->getVirtualAddress();

	applyFileInfo();

	if (IgnoreLoadDelay == false && Mips.GetDelaySlot() == true && (newMemoryPos-memoryPos) > 4
		&& (macroFlags & MIPSM_DONTWARNDELAYSLOT) == 0)
	{
		Logger::queueError(Logger::Warning,L"Macro with multiple opcodes used inside a delay slot");
	}

	if (newMemoryPos == memoryPos)
		Logger::queueError(Logger::Warning,L"Empty macro content");

	return result;
}

void MipsMacroCommand::Encode() const
{
	content->Encode();
}

void MipsMacroCommand::writeTempData(TempData& tempData) const
{
	content->applyFileInfo();
	content->writeTempData(tempData);
}

std::wstring preprocessMacro(const wchar_t* text, MipsImmediateData& immediates)
{
	// A macro is turned into a sequence of opcodes that are parsed seperately.
	// Any expressions used in the macro may be evaluated at a different memory
	// position, so the '.' operator needs to be replaced by a label at the start
	// of the macro
	std::wstring labelName = Global.symbolTable.getUniqueLabelName(true);
	immediates.primary.expression.replaceMemoryPos(labelName);
	immediates.secondary.expression.replaceMemoryPos(labelName);

	return formatString(L"%s: %s",labelName,text);
}

CAssemblerCommand* createMacro(Parser& parser, const std::wstring& text, int flags, std::initializer_list<AssemblyTemplateArgument> variables)
{
	CAssemblerCommand* content = parser.parseTemplate(text,variables);
	return new MipsMacroCommand(content,flags);
}

CAssemblerCommand* generateMipsMacroAbs(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
{
	const wchar_t* templateAbs = LR"(
		%sraop% 	r1,%rs%,31
		xor 		%rd%,%rs%,r1
		%subop% 	%rd%,%rd%,r1
	)";

	std::wstring sraop, subop;

	switch (flags & MIPSM_ACCESSMASK)
	{
	case MIPSM_W:	sraop = L"sra"; subop = L"subu"; break;
	case MIPSM_DW:	sraop = L"dsra32"; subop = L"dsub"; break;
	default: return nullptr;
	}

	std::wstring macroText = preprocessMacro(templateAbs,immediates);
	return createMacro(parser,macroText,flags, {
			{ L"%rd%",		registers.grd.name },
			{ L"%rs%",		registers.grs.name },
			{ L"%sraop%",	sraop },
			{ L"%subop%",	subop },
	});
}

CAssemblerCommand* generateMipsMacroLi(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
{
	const wchar_t* templateLi = LR"(
		.if %imm% > 0xFFFF
			.if (%imm% & 0xFFFF8000) == 0xFFFF8000
				.if %lower%
					addiu	%rs%,r0,%imm% & 0xFFFF
				.endif
			.elseif (%imm% & 0xFFFF) == 0
				.if %upper%<commit_msg>Use sub in abs macro<commit_after>#include "stdafx.h"
#include "MipsMacros.h"
#include "CMipsInstruction.h"
#include "Core/Common.h"
#include "Mips.h"
#include "MipsOpcodes.h"
#include "Parser/Parser.h"
#include "MipsParser.h"

MipsMacroCommand::MipsMacroCommand(CAssemblerCommand* content, int macroFlags)
{
	this->content = content;
	this->macroFlags = macroFlags;
	IgnoreLoadDelay = Mips.GetIgnoreDelay();
}

MipsMacroCommand::~MipsMacroCommand()
{
	delete content;
}

bool MipsMacroCommand::Validate()
{
	u64 memoryPos = g_fileManager->getVirtualAddress();
	content->applyFileInfo();
	bool result = content->Validate();
	u64 newMemoryPos = g_fileManager->getVirtualAddress();

	applyFileInfo();

	if (IgnoreLoadDelay == false && Mips.GetDelaySlot() == true && (newMemoryPos-memoryPos) > 4
		&& (macroFlags & MIPSM_DONTWARNDELAYSLOT) == 0)
	{
		Logger::queueError(Logger::Warning,L"Macro with multiple opcodes used inside a delay slot");
	}

	if (newMemoryPos == memoryPos)
		Logger::queueError(Logger::Warning,L"Empty macro content");

	return result;
}

void MipsMacroCommand::Encode() const
{
	content->Encode();
}

void MipsMacroCommand::writeTempData(TempData& tempData) const
{
	content->applyFileInfo();
	content->writeTempData(tempData);
}

std::wstring preprocessMacro(const wchar_t* text, MipsImmediateData& immediates)
{
	// A macro is turned into a sequence of opcodes that are parsed seperately.
	// Any expressions used in the macro may be evaluated at a different memory
	// position, so the '.' operator needs to be replaced by a label at the start
	// of the macro
	std::wstring labelName = Global.symbolTable.getUniqueLabelName(true);
	immediates.primary.expression.replaceMemoryPos(labelName);
	immediates.secondary.expression.replaceMemoryPos(labelName);

	return formatString(L"%s: %s",labelName,text);
}

CAssemblerCommand* createMacro(Parser& parser, const std::wstring& text, int flags, std::initializer_list<AssemblyTemplateArgument> variables)
{
	CAssemblerCommand* content = parser.parseTemplate(text,variables);
	return new MipsMacroCommand(content,flags);
}

CAssemblerCommand* generateMipsMacroAbs(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
{
	const wchar_t* templateAbs = LR"(
		%sraop% 	r1,%rs%,31
		xor 		%rd%,%rs%,r1
		%subop% 	%rd%,%rd%,r1
	)";

	std::wstring sraop, subop;

	switch (flags & MIPSM_ACCESSMASK)
	{
	case MIPSM_W:	sraop = L"sra"; subop = L"sub"; break;
	case MIPSM_DW:	sraop = L"dsra32"; subop = L"dsub"; break;
	default: return nullptr;
	}

	std::wstring macroText = preprocessMacro(templateAbs,immediates);
	return createMacro(parser,macroText,flags, {
			{ L"%rd%",		registers.grd.name },
			{ L"%rs%",		registers.grs.name },
			{ L"%sraop%",	sraop },
			{ L"%subop%",	subop },
	});
}

CAssemblerCommand* generateMipsMacroLi(Parser& parser, MipsRegisterData& registers, MipsImmediateData& immediates, int flags)
{
	const wchar_t* templateLi = LR"(
		.if %imm% > 0xFFFF
			.if (%imm% & 0xFFFF8000) == 0xFFFF8000
				.if %lower%
					addiu	%rs%,r0,%imm% & 0xFFFF
				.endif
			.elseif (%imm% & 0xFFFF) == 0
				.if %upper%
{'fraction_non_alphanumeric': 0.13607188703465983, 'fraction_numerical': 0.008985879332477536, 'mean_word_length': 5.609756097560975, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '324455', 'n_tokens_mistral': 2352, 'n_tokens_neox': 2233, 'n_words': 481}