#include #include #include #include #include #include #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 _sequence; }; std::vector 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= 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::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()[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 STW LDWI STW LDW POKE/DOKE end up with LDWI STW LD POKE/DOKE case PokeArray: case DokeArray: { uint16_t offset = 9; // Save previous line LD, 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 is moved 9bytes, LDWI is moved 10 bytes // Delete previous line LD, 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 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 STW LDW STW LDWI ADDW STW LDW POKE case PokeVarArrayB: case PokeTmpArrayB: { uint16_t offset = 15; // LD is moved 15 bytes // Save previous line LD, 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, 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 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 is moved 17 bytes // Save previous line LD, 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's label to LDWI if(!migrateInternalLabel(i, firstLine - 1, firstLine + 3)) break; savedLD._internalLabel = ""; savedLD._address += offset; // Delete previous line LD, 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 and STW were deleted // Replace LDW with saved LD 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 Compiler::VasmLine savedLD = Compiler::getCodeLines()[i]._vasm[firstLine]; // Migrate LD's label to LD if(!migrateInternalLabel(i, firstLine, firstLine + 2)) break; savedLD._internalLabel = ""; savedLD._address += 8; // LD is moved 8 bytes // Delete LD, 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 and STW were deleted // Replace LDW with saved LD 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; } }