gigatron/rom/Contrib/at67/optimiser.cpp
2025-01-28 19:17:01 +03:00

1113 lines
63 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string>
#include <vector>
#include <algorithm>
#include "memory.h"
#include "cpu.h"
#include "assembler.h"
#include "compiler.h"
#include "optimiser.h"
namespace Optimiser
{
enum OptimiseTypes {StwLdwPair=0, StwLdPair, StwStHigh, ExtraLdw, ExtraLd, LdwPair, StwLdiAddw, StwLdwAddw, StwLdwAddwVar, StwLdiAndw, StwLdwAndw, StwLdwAndwVar, StwLdiXorw,
StwLdwXorw, StwLdwXorwVar, StwLdiOrw, StwLdwOrw, StwLdwOrwVar, LdwBeqStwTmp, LdwBeqStwVar, LdBeqStTmp, LdBeqStVar, PokeVar, DokeVar, StwPair, StwPairReg,
ExtraStw, PeekArrayB, PeekArray, DeekArray, PokeArray, DokeArray, PokeVarArrayB, PokeVarArray, DokeVarArray, PokeTmpArrayB, PokeTmpArray, DokeTmpArray,
StwPokeArray, StwDokeArray, LdSubLoHi, LdiSubLoHi, LdwSubLoHi, AddiPair, AddiZero, SubiZero, NumOptimiseTypes};
struct MatchSequence
{
int _firstIndex;
int _secondIndex;
std::vector<std::string> _sequence;
};
std::vector<MatchSequence> matchSequences =
{
// StwLdwPair
{0, 1, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x" }},
// StwLdPair
{0, 1, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "0x" }},
// StwStHigh
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"ST" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_" }},
// ExtraLdw
{0, 1, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_" }},
// ExtraLd
{0, 1, {"ST" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_",
"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_" }},
// LdwPair
{0, 1, {"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x" }},
// StwLdiAddw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDI" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdwAddw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdwAddwVar
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdiAndw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDI" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"ANDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdwAndw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"ANDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdwAndwVar
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"ANDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdiXorw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDI" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"XORW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdwXorw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"XORW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdwXorwVar
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"XORW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x"}},
// StwLdiOrw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDI" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"ORW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x"}},
// StwLdwOrw
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"ORW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x"}},
// StwLdwOrwVar
{0, 2, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"ORW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x"}},
// LdwBeqStwTmp
{0, 2, {"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"BEQ" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x"}},
// LdwBeqStwVar
{0, 2, {"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"BEQ" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_"}},
// LdBeqStTmp
{0, 2, {"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "0x",
"BEQ" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"ST" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "0x"}},
// LdBeqStVar
{0, 2, {"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_",
"BEQ" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"ST" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_"}},
// PokeVar
{0, 2, {"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"POKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + ""}},
// DokeVar
{0, 2, {"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"DOKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + ""}},
// StwPair
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x" }},
// StwPairReg
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem"}},
// ExtraStw
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_" }},
// PeekArrayB
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"PEEK" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + ""}},
// PeekArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"PEEK" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + ""}},
// DeekArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"DEEK" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + ""}},
// PokeArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"POKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// DokeArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"DOKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// PokeVarArrayB
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"POKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// PokeVarArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"POKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// DokeVarArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "_",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"DOKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// PokeTmpArrayB
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"POKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// PokeTmpArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"POKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// DokeTmpArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDWI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "0x",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"ADDW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "mem",
"DOKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// StwPokeArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"POKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// StwDokeArray
{0, 0, {"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "0x",
"DOKE" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "mem"}},
// LdSubLoHi
{0, 0, {"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"SUBW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "reg"}},
// LdiSubLoHi
{0, 0, {"LDI" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"SUBW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "reg"}},
// LdwSubLoHi
{0, 0, {"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"LD" + std::string(OPCODE_TRUNC_SIZE - 2, ' ') + "_",
"STW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"LDW" + std::string(OPCODE_TRUNC_SIZE - 3, ' ') + "reg",
"SUBW" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "reg"}},
// AddiPair
{0, 0, {"ADDI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + "",
"ADDI" + std::string(OPCODE_TRUNC_SIZE - 4, ' ') + ""}},
// AddiZero
{0, 0, {"ADDI" + std::string(OPCODE_TRUNC_SIZE - 4, ' '), ""}},
// SubiZero
{0, 0, {"SUBI" + std::string(OPCODE_TRUNC_SIZE - 4, ' '), ""}},
};
bool initialise(void)
{
return true;
}
// Migrate internal label for an instruction that has been deleted, (use this function before the instruction is deleted)
bool migrateInternalLabel(int index, int oldLine, int newLine)
{
// If a label exists, move it to next available vasm line
if(Compiler::getCodeLines()[index]._vasm[oldLine]._internalLabel.size())
{
// Next available vasm line is part of a new BASIC line, so can't optimise
if(int(Compiler::getCodeLines()[index]._vasm.size()) <= newLine) return false;
Compiler::getCodeLines()[index]._vasm[newLine]._internalLabel = Compiler::getCodeLines()[index]._vasm[oldLine]._internalLabel;
}
return true;
}
// Adjust label addresses for any labels with addresses higher than optimised vasm instruction address
void adjustLabelAddresses(int codeLineIndex, int vasmLineIndex, int offset)
{
// Loop through commented out code
do
{
if(vasmLineIndex >= int(Compiler::getCodeLines()[codeLineIndex]._vasm.size()))
{
if(++codeLineIndex >= int(Compiler::getCodeLines().size())) return;
vasmLineIndex = 0;
}
}
while(Compiler::getCodeLines()[codeLineIndex]._vasm.size() == 0);
uint16_t optimisedAddress = Compiler::getCodeLines()[codeLineIndex]._vasm[vasmLineIndex]._address;
for(int i=0; i<int(Compiler::getLabels().size()); i++)
{
if(Compiler::getLabels()[i]._address >= optimisedAddress)
{
Compiler::getLabels()[i]._address += int16_t(offset);
}
}
}
// Adjust vasm code addresses
void adjustVasmAddresses(int codeLineIndex, int vasmLineIndex, int offset)
{
// Loop through commented out code
do
{
if(vasmLineIndex >= int(Compiler::getCodeLines()[codeLineIndex]._vasm.size()))
{
if(++codeLineIndex >= int(Compiler::getCodeLines().size())) return;
vasmLineIndex = 0;
}
}
while(Compiler::getCodeLines()[codeLineIndex]._vasm.size() == 0);
for(int i=codeLineIndex; i<int(Compiler::getCodeLines().size()); i++)
{
int start = (i == codeLineIndex) ? vasmLineIndex : 0;
for(int j=start; j<int(Compiler::getCodeLines()[i]._vasm.size()); j++)
{
Compiler::getCodeLines()[i]._vasm[j]._address += int16_t(offset);
}
}
}
void updateVasm(int codeLineIndex, int vasmLineIndex, const std::string& opcode, const std::string& operand)
{
Compiler::getCodeLines()[codeLineIndex]._vasm[vasmLineIndex]._opcode = opcode;
Compiler::getCodeLines()[codeLineIndex]._vasm[vasmLineIndex]._operand = operand;
Compiler::getCodeLines()[codeLineIndex]._vasm[vasmLineIndex]._code = opcode + std::string(OPCODE_TRUNC_SIZE - opcode.size(), ' ') + operand;
Compiler::getCodeLines()[codeLineIndex]._vasm[vasmLineIndex]._vasmSize = Assembler::getAsmOpcodeSize(opcode);
}
void updateVasm(std::vector<Compiler::VasmLine>::iterator& it, int offset, const std::string& opcode, const std::string& operand)
{
(it + offset)->_opcode = opcode;
(it + offset)->_operand = operand;
(it + offset)->_code = opcode + std::string(OPCODE_TRUNC_SIZE - opcode.size(), ' ') + operand;
(it + offset)->_vasmSize = Assembler::getAsmOpcodeSize(opcode);
}
bool optimiseCode(void)
{
RESTART_OPTIMISE:
for(int i=0; i<int(Compiler::getCodeLines().size()); i++)
{
for(int j=0; j<int(matchSequences.size()); j++)
{
for(auto itVasm=Compiler::getCodeLines()[i]._vasm.begin(); itVasm!=Compiler::getCodeLines()[i]._vasm.end();)
{
bool linesDeleted = false;
int vasmIndex = int(itVasm - Compiler::getCodeLines()[i]._vasm.begin());
// Can only optimise within a BASIC code line, (use multi-statements to optimise across lines)
int vasmIndexMax = vasmIndex + int(matchSequences[j]._sequence.size()) - 1;
if(vasmIndexMax >= int(Compiler::getCodeLines()[i]._vasm.size()))
{
++itVasm;
continue;
}
// Find opcode match
bool foundOpcodeMatch = true;
for(int k=vasmIndex; k<=vasmIndexMax; k++)
{
if(Compiler::getCodeLines()[i]._vasm[k]._code.find(matchSequences[j]._sequence[k - vasmIndex]) == std::string::npos)
{
foundOpcodeMatch = false;
break;
}
}
if(foundOpcodeMatch)
{
// First operand
int firstIndex = matchSequences[j]._firstIndex;
int firstLine = vasmIndex + firstIndex;
std::string firstOperand = Compiler::getCodeLines()[i]._vasm[firstLine]._operand;
// Second operand
int secondIndex = matchSequences[j]._secondIndex;
int secondLine = vasmIndex + secondIndex;
std::string secondOperand = Compiler::getCodeLines()[i]._vasm[secondLine]._operand;
/*************************************************************************************************************************************************************/
/* Opcode matches required, operand matches required */
/*************************************************************************************************************************************************************/
// Find operand match, (temporary variables are a minimum of 4 chars, i.e. '0xd0')
//if(firstOperand.substr(0, 4) == secondOperand.substr(0, 4))
if(firstOperand == secondOperand)
{
switch(j)
{
// Match STW LDW, delete STW LDW
//case StwLdPair:
case StwLdwPair:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW ST, delete STW
case StwStHigh:
{
// Assume neither of these instructions can have a label
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -2);
adjustVasmAddresses(i, firstLine, -2);
}
break;
// Match STW/ST LDW/LD, delete LDW/LD
case ExtraLdw:
case ExtraLd:
{
// If the LDW has an internal label, then it probably can't be optimised away
if(!Compiler::getCodeLines()[i]._vasm[firstLine + 1]._internalLabel.size())
{
// Migrate internal label to next available instruction
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Delete LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
adjustLabelAddresses(i, firstLine + 1, -2);
adjustVasmAddresses(i, firstLine + 1, -2);
}
}
break;
// Match LDW LDW, delete first LDW
case LdwPair:
{
// Migrate internal label from first LDW to second LDW
if(!migrateInternalLabel(i, firstLine, firstLine + 1)) break;
// Delete first LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine + 1, -2);
adjustVasmAddresses(i, firstLine + 1, -2);
}
break;
// Match STW LDI ADDW, copy LDI operand to ADDW operand, change ADDW to ADDI, delete STW LDW
case StwLdiAddw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ADDW with ADDI and replace ADDW's operand with LDI's operand
std::string ldiOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ADDI", ldiOperand);
// Delete STW and LDI
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW ADDW, copy LDW operand to ADDW operand and delete STW LDW
case StwLdwAddw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ADDW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ADDW", ldwOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW ADDW, copy LDW operand to ADDW operand and delete STW LDW, (LDW is a var)
case StwLdwAddwVar:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ADDW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ADDW", ldwOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDI ANDW, copy LDI operand to ANDW operand, change ANDW to ANDI, delete STW LDW
case StwLdiAndw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ANDW with ANDI and replace ANDW's operand with LDI's operand
std::string ldiOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ANDI", ldiOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW ANDW, copy LDW operand to ANDW operand and delete STW LDW
case StwLdwAndw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ANDW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ANDW", ldwOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW ANDW, copy LDW operand to ANDW operand and delete STW LDW, (LDW is a var)
case StwLdwAndwVar:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ANDW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ANDW", ldwOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDI XORW, copy LDI operand to XORW operand, change XORW to XORI, delete STW LDW
case StwLdiXorw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace XORW with XORI and replace XORW's operand with LDI's operand
std::string ldiOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "XORI", ldiOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW XORW, copy LDW operand to XORW operand and delete STW LDW
case StwLdwXorw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace XORW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "XORW", ldwOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW XORW, copy LDW operand to XORW operand and delete STW LDW, (LDW is a var)
case StwLdwXorwVar:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace XORW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "XORW", ldwOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDI ORW, copy LDI operand to ORW operand, change ORW to ORI, delete STW LDW
case StwLdiOrw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ORW with ORI and replace ORW's operand with LDI's operand
std::string ldiOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ORI", ldiOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW ORW, copy LDW operand to ORW operand and delete STW LDW
case StwLdwOrw:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ORW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ORW", ldwOperand);
// Delete STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW ORW, copy LDW operand to ORW operand and delete STW LDW, (LDW is a var)
case StwLdwOrwVar:
{
// Only one of these can have an internal label
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Replace ORW's operand with LDW's operand
std::string ldwOperand = Compiler::getCodeLines()[i]._vasm[firstLine + 1]._operand;
updateVasm(i, firstLine + 2, "ORW", ldwOperand);
// Delete STW LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match LDW/LD BEQ STW/ST, delete STW/ST
case LdwBeqStwTmp:
case LdwBeqStwVar:
case LdBeqStTmp:
case LdBeqStVar:
{
// STW/ST can have an internal label
if(!migrateInternalLabel(i, firstLine + 2, firstLine + 3)) break;
// Delete STW/ST
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 2);
adjustLabelAddresses(i, firstLine + 2, -2);
adjustVasmAddresses(i, firstLine + 2, -2);
}
break;
// Match LDW POKE/DOKE LDW, delete second LDW if it matches with first LDW
case PokeVar:
case DokeVar:
{
// Migrate second LDW's label, (if it has one)
if(!migrateInternalLabel(i, firstLine + 2, firstLine + 3)) break;
// Delete second LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 2);
adjustLabelAddresses(i, firstLine + 2, -2);
adjustVasmAddresses(i, firstLine + 2, -2);
}
break;
default: break;
}
}
/*************************************************************************************************************************************************************/
/* Opcode matches required, operand matches NOT required */
/*************************************************************************************************************************************************************/
switch(j)
{
// Extra STW, (doesn't require an operand match)
case StwPair:
case StwPairReg:
case ExtraStw:
{
// Migrate internal label to next available instruction
if(!migrateInternalLabel(i, firstLine, firstLine + 1)) break;
// Delete first STW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -2);
adjustVasmAddresses(i, firstLine, -2);
}
break;
// Match LDW STW LDWI ADDW PEEK end up with LDWI ADDW PEEK
case PeekArrayB:
{
// Save previous line LDW, if opcode is not LDW then can't optimise
if(firstLine - 1 < 0) break;
Compiler::VasmLine savedLDW = Compiler::getCodeLines()[i]._vasm[firstLine - 1];
if(savedLDW._opcode != "LDW") break;
// Migrate it's label if it has one
if(!migrateInternalLabel(i, firstLine - 1, firstLine + 1)) break;
// Delete previous line LDW and first STW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine - 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
// Replace operand of ADDW with LDW's operand
updateVasm(itVasm, 1, "ADDW", savedLDW._operand);
adjustLabelAddresses(i, firstLine - 1, -4);
adjustVasmAddresses(i, firstLine - 1, -4);
}
break;
// Match LDW STW LDWI ADDW ADDW PEEK/DEEK end up with LDWI ADDW ADDW PEEK/DEEK
case PeekArray:
case DeekArray:
{
// Save previous line LDW, if opcode is not LDW then can't optimise
if(firstLine - 1 < 0) break;
Compiler::VasmLine savedLDW = Compiler::getCodeLines()[i]._vasm[firstLine - 1];
if(savedLDW._opcode != "LDW") break;
// Migrate it's label if it has one
if(!migrateInternalLabel(i, firstLine - 1, firstLine + 1)) break;
// Delete previous line LDW and first STW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine - 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
// Replace operand of both ADDW's with LDW's operand
updateVasm(itVasm, 1, "ADDW", savedLDW._operand);
updateVasm(itVasm, 2, "ADDW", savedLDW._operand);
adjustLabelAddresses(i, firstLine - 1, -4);
adjustVasmAddresses(i, firstLine - 1, -4);
}
break;
// Match LD<X> STW LDWI STW LDW POKE/DOKE end up with LDWI STW LD<X> POKE/DOKE
case PokeArray:
case DokeArray:
{
uint16_t offset = 9;
// Save previous line LD<X>, if opcode is not some sort of LD then can't optimise
if(firstLine - 1 < 0) break;
Compiler::VasmLine savedLD = Compiler::getCodeLines()[i]._vasm[firstLine - 1];
if(savedLD._opcode.find("LD") == std::string::npos) break;
if(savedLD._opcode.find("LDWI") != std::string::npos) offset += 1;
// Discard it's label, (it's no longer needed), and adjust it's address
if(!migrateInternalLabel(i, firstLine - 1, firstLine + 1)) break;
savedLD._internalLabel = "";
savedLD._address += offset; // LD<X> is moved 9bytes, LDWI is moved 10 bytes
// Delete previous line LD<X>, first STW and LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine - 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm + 2);
// Replace LDW with saved LD<X> and operand
if(offset == 9)
{
itVasm = Compiler::getCodeLines()[i]._vasm.insert(itVasm, savedLD);
adjustLabelAddresses(i, firstLine - 1, -4);
adjustVasmAddresses(i, firstLine - 1, -4);
}
// LDW is replaced with LDWI so push everything forward starting at the POKE/DOKE by 1 more byte
else
{
itVasm = Compiler::getCodeLines()[i]._vasm.insert(itVasm, savedLD);
adjustLabelAddresses(i, firstLine - 1, -5);
adjustVasmAddresses(i, firstLine - 1, -5);
adjustLabelAddresses(i, firstLine + 2, 1);
adjustVasmAddresses(i, firstLine + 2, 1);
}
}
break;
// Match LD<X> STW LDW STW LDWI ADDW STW LDW POKE
case PokeVarArrayB:
case PokeTmpArrayB:
{
uint16_t offset = 15; // LD<X> is moved 15 bytes
// Save previous line LD<X>, if opcode is not some sort of LD then can't optimise first phase
if(firstLine - 1 < 0) break;
Compiler::VasmLine savedLD = Compiler::getCodeLines()[i]._vasm[firstLine - 1];
if(savedLD._opcode == "LDWI") offset += 1;
if(savedLD._opcode.find("LD") != std::string::npos)
{
// Discard it's label, (it's no longer needed), and adjust it's address
if(!migrateInternalLabel(i, firstLine - 1, firstLine + 3)) break;
savedLD._internalLabel = "";
savedLD._address += offset;
// Delete previous line LD<X>, first STW and last LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine - 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm + 5); //points to last LDW
// Replace LDW with saved LD<X> and operand
itVasm = Compiler::getCodeLines()[i]._vasm.insert(itVasm, savedLD);
adjustLabelAddresses(i, firstLine - 1, -4);
adjustVasmAddresses(i, firstLine - 1, -4);
firstLine = firstLine - 1; // points to new first LDW
if(offset != 15)
{
// adjust for LDWI
adjustLabelAddresses(i, firstLine + 6, 1);
adjustVasmAddresses(i, firstLine + 6, 1);
}
}
else
{
firstLine = firstLine + 1; // points to first LDW
}
// Now optimise the first LDW and second STW for second phase
Compiler::VasmLine savedLDW = Compiler::getCodeLines()[i]._vasm[firstLine];
// Delete first LDW and second STW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
// Replace operand of ADDW with LDW's operand
updateVasm(itVasm, 1, "ADDW", savedLDW._operand);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match STW LDW STW LDWI ADDW ADDW STW LDW POKE/DOKE
case PokeVarArray:
case PokeTmpArray:
case DokeVarArray:
case DokeTmpArray:
{
uint16_t offset = 17; // LD<X> is moved 17 bytes
// Save previous line LD<X>, if opcode is not some sort of LD then can't optimise first phase
if(firstLine - 1 < 0) break;
Compiler::VasmLine savedLD = Compiler::getCodeLines()[i]._vasm[firstLine - 1];
if(savedLD._opcode == "LDWI") offset += 1;
if(savedLD._opcode.find("LD") != std::string::npos)
{
// Migrate LD<X>'s label to LDWI
if(!migrateInternalLabel(i, firstLine - 1, firstLine + 3)) break;
savedLD._internalLabel = "";
savedLD._address += offset;
// Delete previous line LD<X>, first STW and last LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine - 1);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm + 6); //points to last LDW, after LD<X> and STW were deleted
// Replace LDW with saved LD<X> and operand
itVasm = Compiler::getCodeLines()[i]._vasm.insert(itVasm, savedLD);
adjustLabelAddresses(i, firstLine - 1, -4);
adjustVasmAddresses(i, firstLine - 1, -4);
firstLine = firstLine - 1; // points to new first LDW
if(offset != 17)
{
// adjust for LDWI
adjustLabelAddresses(i, firstLine + 7, 1);
adjustVasmAddresses(i, firstLine + 7, 1);
}
}
else
{
firstLine = firstLine + 1; // points to first LDW
}
// Now optimise the first LDW and second STW for second phase
Compiler::VasmLine savedLDW = Compiler::getCodeLines()[i]._vasm[firstLine];
// Delete first LDW and second STW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
// Replace operand of both ADDW's
updateVasm(itVasm, 1, "ADDW", savedLDW._operand);
updateVasm(itVasm, 2, "ADDW", savedLDW._operand);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
case StwPokeArray:
case StwDokeArray:
{
// Migrate internal label to next available instruction
if(!migrateInternalLabel(i, firstLine, firstLine + 1)) break;
// Delete first STW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
adjustLabelAddresses(i, firstLine, -2);
adjustVasmAddresses(i, firstLine, -2);
}
break;
// Match LD/LDW STW LD STW LDW SUBW
case LdSubLoHi:
case LdiSubLoHi:
case LdwSubLoHi:
{
// Save LD<X>
Compiler::VasmLine savedLD = Compiler::getCodeLines()[i]._vasm[firstLine];
// Migrate LD<X>'s label to LD
if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break;
savedLD._internalLabel = "";
savedLD._address += 8; // LD<X> is moved 8 bytes
// Delete LD<X>, first STW and last LDW
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm);
itVasm = Compiler::getCodeLines()[i]._vasm.erase(itVasm + 2); //points to last LDW, after LD<X> and STW were deleted
// Replace LDW with saved LD<X> and operand
itVasm = Compiler::getCodeLines()[i]._vasm.insert(itVasm, savedLD);
adjustLabelAddresses(i, firstLine, -4);
adjustVasmAddresses(i, firstLine, -4);
}
break;
// Match ADDI ADDI
case AddiPair:
{
uint8_t addi0, addi1;
// Migrate second ADDI's label to next instruction
if(!migrateInternalLabel(i, firstLine + 1, firstLine + 2)) break;
// Add operands together, replace first operand, delete 2nd opcode and operand
Compiler::VasmLine vasm = Compiler::getCodeLines()[i]._vasm[firstLine];
std::string operand = vasm._operand;
Expression::stringToU8(operand, addi0);
vasm = Compiler::getCodeLines()[i]._vasm[firstLine + 1];
operand = vasm._operand;
Expression::stringToU8(operand, addi1);
// Result can't fit in an ADDI operand so exit, (ADDI can't be -ve so result can't be -ve)
uint16_t result = addi0 + addi1;
if(result > 255) break;
// Delete second ADDI
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + firstLine + 1);
// Replace first ADDI's operand with sum of previous two ADDI's
updateVasm(itVasm, -1, "ADDI", std::to_string(uint8_t(result)));
adjustLabelAddresses(i, firstLine + 1, -2);
adjustVasmAddresses(i, firstLine + 1, -2);
}
break;
default: break;
}
}
// Arithmetic with zero, (does it's own opcode match)
if(j == AddiZero || j == SubiZero)
{
std::string operand;
size_t pos = itVasm->_code.find(matchSequences[j]._sequence[0]);
if(pos != std::string::npos)
{
operand = itVasm->_code.substr(pos + matchSequences[j]._sequence[0].size());
if(operand == "0" || operand == "0x00")
{
// Migrate internal label to next available instruction
if(!migrateInternalLabel(i, vasmIndex, vasmIndex + 1)) break;
// Delete ADD/SUB
linesDeleted = true;
itVasm = Compiler::getCodeLines()[i]._vasm.erase(Compiler::getCodeLines()[i]._vasm.begin() + vasmIndex);
adjustLabelAddresses(i, vasmIndex, -2);
adjustVasmAddresses(i, vasmIndex, -2);
}
}
}
if(!linesDeleted)
{
// Only increment iterator if it has not been invalidated
++itVasm;
}
else
{
// Optimising can cause new optimising opportunities to present, so restart
goto RESTART_OPTIMISE;
}
}
}
}
return true;
}
}