From 056df56eef67cda24b91c915f0e602e001e5a25d Mon Sep 17 00:00:00 2001 From: drmortalwombat <90205530+drmortalwombat@users.noreply.github.com> Date: Tue, 7 Sep 2021 22:35:11 +0200 Subject: [PATCH] First shot native code generator Implements basic load, store compare and add/sub/shift for native compiled functions --- oscar64/ByteCodeGenerator.cpp | 151 ++-- oscar64/ByteCodeGenerator.h | 35 +- oscar64/Compiler.cpp | 36 +- oscar64/Declaration.h | 1 + oscar64/InterCode.cpp | 140 +++- oscar64/InterCode.h | 8 +- oscar64/InterCodeGenerator.cpp | 8 +- oscar64/NativeCodeGenerator.cpp | 1349 +++++++++++++++++++++++++++++-- oscar64/NativeCodeGenerator.h | 31 +- oscar64/Parser.cpp | 15 + 10 files changed, 1589 insertions(+), 185 deletions(-) diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index b4ab708..9caf047 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -405,7 +405,7 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl ByteCodeRelocation rl; rl.mAddr = block->mCode.Size(); - rl.mFunction = false; + rl.mFunction = mFunction; rl.mLower = true; rl.mUpper = true; rl.mIndex = mVIndex; @@ -1481,6 +1481,7 @@ void ByteCodeBasicBlock::CallAssembler(InterCodeProcedure* proc, const InterInst ByteCodeInstruction bins(BC_JSR); bins.mRelocate = true; bins.mVIndex = ins.mVarIndex; + bins.mFunction = ins.mMemory == IM_PROCEDURE; mIns.Push(bins); } } @@ -3394,78 +3395,88 @@ void ByteCodeGenerator::WriteAsmFile(FILE* file) { for (int i = 0; i < mGlobalAddr.Size(); i++) { - if (mGlobalAddr[i].mAssembler) + WriteAsmFile(file, mGlobalAddr[i]); + } + for (int i = 0; i < mProcedureAddr.Size(); i++) + { + WriteAsmFile(file, mProcedureAddr[i]); + } +} + +void ByteCodeGenerator::WriteAsmFile(FILE * file, Address & addr) +{ + + if (addr.mAssembler) + { + fprintf(file, "--------------------------------------------------------------------\n"); + if (addr.mIdent) + fprintf(file, "%s:\n", addr.mIdent->mString); + + int ip = addr.mAddress; + while (ip < addr.mAddress + addr.mSize) { - fprintf(file, "--------------------------------------------------------------------\n"); - if (mGlobalAddr[i].mIdent) - fprintf(file, "%s:\n", mGlobalAddr[i].mIdent->mString); + int iip = ip; + uint8 opcode = mMemory[ip++]; + AsmInsData d = DecInsData[opcode]; + int addr = 0; - int ip = mGlobalAddr[i].mAddress; - while (ip < mGlobalAddr[i].mAddress + mGlobalAddr[i].mSize) + switch (d.mMode) { - int iip = ip; - uint8 opcode = mMemory[ip++]; - AsmInsData d = DecInsData[opcode]; - int addr = 0; - - switch (d.mMode) - { - case ASMIM_IMPLIED: - fprintf(file, "%04x : %04x %02x __ __ %s\n", iip, ip, mMemory[ip], AsmInstructionNames[d.mType]); - break; - case ASMIM_IMMEDIATE: - addr = mMemory[ip++]; - fprintf(file, "%04x : %04x %02x %02x __ %s #$%02x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); - break; - case ASMIM_ZERO_PAGE: - addr = mMemory[ip++]; - fprintf(file, "%04x : %04x %02x %02x __ %s $%02x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); - break; - case ASMIM_ZERO_PAGE_X: - addr = mMemory[ip++]; - fprintf(file, "%04x : %04x %02x %02x __ %s $%02x,x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); - break; - case ASMIM_ZERO_PAGE_Y: - addr = mMemory[ip++]; - fprintf(file, "%04x : %04x %02x %02x __ %s $%02x,y\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); - break; - case ASMIM_ABSOLUTE: - addr = mMemory[ip] + 256 * mMemory[ip + 1]; - fprintf(file, "%04x : %04x %02x %02x %02x %s $%04x\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); - ip += 2; - break; - case ASMIM_ABSOLUTE_X: - addr = mMemory[ip] + 256 * mMemory[ip + 1]; - fprintf(file, "%04x : %04x %02x %02x %02x %s $%04x,x\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); - ip += 2; - break; - case ASMIM_ABSOLUTE_Y: - addr = mMemory[ip] + 256 * mMemory[ip + 1]; - fprintf(file, "%04x : %04x %02x %02x %02x %s $%04x,y\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); - ip += 2; - break; - case ASMIM_INDIRECT: - addr = mMemory[ip] + 256 * mMemory[ip + 1]; - ip += 2; - fprintf(file, "%04x : %04x %02x %02x %02x %s ($%04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); - break; - case ASMIM_INDIRECT_X: - addr = mMemory[ip++]; - fprintf(file, "%04x : %04x %02x %02x __ %s ($%02x,x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); - break; - case ASMIM_INDIRECT_Y: - addr = mMemory[ip++]; - fprintf(file, "%04x : %04x %02x %02x __ %s ($%02x),y\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); - break; - case ASMIM_RELATIVE: - addr = mMemory[ip++]; - if (addr & 0x80) - addr = addr + ip - 256; - else - addr = addr + ip; - fprintf(file, "%04x : %04x %02x %02x __ %s $%02x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); - break; - } + case ASMIM_IMPLIED: + fprintf(file, "%04x : %02x __ __ %s\n", iip, mMemory[ip], AsmInstructionNames[d.mType]); + break; + case ASMIM_IMMEDIATE: + addr = mMemory[ip++]; + fprintf(file, "%04x : %02x %02x __ %s #$%02x\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); + break; + case ASMIM_ZERO_PAGE: + addr = mMemory[ip++]; + fprintf(file, "%04x : %02x %02x __ %s $%02x\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); + break; + case ASMIM_ZERO_PAGE_X: + addr = mMemory[ip++]; + fprintf(file, "%04x : %02x %02x __ %s $%02x,x\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); + break; + case ASMIM_ZERO_PAGE_Y: + addr = mMemory[ip++]; + fprintf(file, "%04x : %02x %02x __ %s $%02x,y\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); + break; + case ASMIM_ABSOLUTE: + addr = mMemory[ip] + 256 * mMemory[ip + 1]; + fprintf(file, "%04x : %02x %02x %02x %s $%04x\n", iip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); + ip += 2; + break; + case ASMIM_ABSOLUTE_X: + addr = mMemory[ip] + 256 * mMemory[ip + 1]; + fprintf(file, "%04x : %02x %02x %02x %s $%04x,x\n", iip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); + ip += 2; + break; + case ASMIM_ABSOLUTE_Y: + addr = mMemory[ip] + 256 * mMemory[ip + 1]; + fprintf(file, "%04x : %02x %02x %02x %s $%04x,y\n", iip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); + ip += 2; + break; + case ASMIM_INDIRECT: + addr = mMemory[ip] + 256 * mMemory[ip + 1]; + ip += 2; + fprintf(file, "%04x : %02x %02x %02x %s ($%04x)\n", iip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr); + break; + case ASMIM_INDIRECT_X: + addr = mMemory[ip++]; + fprintf(file, "%04x : %02x %02x __ %s ($%02x,x)\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); + break; + case ASMIM_INDIRECT_Y: + addr = mMemory[ip++]; + fprintf(file, "%04x : %02x %02x __ %s ($%02x),y\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); + break; + case ASMIM_RELATIVE: + addr = mMemory[ip++]; + if (addr & 0x80) + addr = addr + ip - 256; + else + addr = addr + ip; + fprintf(file, "%04x : %02x %02x __ %s $%02x\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr); + break; } } } diff --git a/oscar64/ByteCodeGenerator.h b/oscar64/ByteCodeGenerator.h index b0821cf..165db05 100644 --- a/oscar64/ByteCodeGenerator.h +++ b/oscar64/ByteCodeGenerator.h @@ -253,26 +253,11 @@ public: ByteCodeGenerator(void); ~ByteCodeGenerator(void); - void WriteBasicHeader(void); - void WriteByteCodeHeader(void); - void SetBasicEntry(int index); - - bool WritePRGFile(const char* filename); - bool WriteMapFile(const char* filename); - - void WriteAsmFile(FILE * file); - - void ResolveRelocations(void); - - int AddGlobal(int index, const Ident* ident, int size, const uint8* data, bool assembler); - - void AddAddress(int index, bool function, int address, int size, const Ident * ident, bool assembler); - struct Address { int mIndex, mAddress, mSize; bool mFunction, mAssembler; - const Ident * mIdent; + const Ident* mIdent; }; GrowingArray
mProcedureAddr, mGlobalAddr; @@ -282,4 +267,22 @@ public: uint8 mMemory[0x10000]; int mProgEnd, mProgStart, mProgEntry; + + void WriteBasicHeader(void); + void WriteByteCodeHeader(void); + void SetBasicEntry(int index); + + bool WritePRGFile(const char* filename); + bool WriteMapFile(const char* filename); + + void WriteAsmFile(FILE * file); + + void WriteAsmFile(FILE* file, Address & addr); + + void ResolveRelocations(void); + + int AddGlobal(int index, const Ident* ident, int size, const uint8* data, bool assembler); + + void AddAddress(int index, bool function, int address, int size, const Ident * ident, bool assembler); + }; diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 16fc48f..6f31fbc 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -4,6 +4,7 @@ #include "InterCodeGenerator.h" #include "InterCode.h" #include "ByteCodeGenerator.h" +#include "NativeCodeGenerator.h" #include "Emulator.h" #include @@ -85,27 +86,38 @@ bool Compiler::GenerateCode(void) for (int i = 0; i < mInterCodeModule->mProcedures.Size(); i++) { - ByteCodeProcedure* bgproc = new ByteCodeProcedure(); + InterCodeProcedure* proc = mInterCodeModule->mProcedures[i]; - mInterCodeModule->mProcedures[i]->ReduceTemporaries(); + proc->ReduceTemporaries(); #if _DEBUG - mInterCodeModule->mProcedures[i]->Disassemble("final"); + proc->Disassemble("final"); #endif - bgproc->Compile(mByteCodeGenerator, mInterCodeModule->mProcedures[i]); - mByteCodeFunctions.Push(bgproc); -#if _DEBUG - FILE* file; - fopen_s(&file, "r:\\cldiss.txt", "a"); - - if (file) + if (proc->mNativeProcedure) { - bgproc->Disassemble(file, mByteCodeGenerator, mInterCodeModule->mProcedures[i]); - fclose(file); + NativeCodeProcedure* ncproc = new NativeCodeProcedure(); + ncproc->Compile(mByteCodeGenerator, proc); } + else + { + ByteCodeProcedure* bgproc = new ByteCodeProcedure(); + + bgproc->Compile(mByteCodeGenerator, proc); + mByteCodeFunctions.Push(bgproc); + +#if _DEBUG + FILE* file; + fopen_s(&file, "r:\\cldiss.txt", "a"); + + if (file) + { + bgproc->Disassemble(file, mByteCodeGenerator, mInterCodeModule->mProcedures[i]); + fclose(file); + } #endif + } } for (int i = 0; i < 128; i++) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index 35f5f7c..4f8ee09 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -52,6 +52,7 @@ static const uint32 DTF_STATIC = 0x00000020; static const uint32 DTF_CONST = 0x00000040; static const uint32 DTF_VOLATILE = 0x00000080; static const uint32 DTF_EXTERN = 0x00000100; +static const uint32 DTF_NATIVE = 0x00000200; class Declaration; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 2846595..34ce1a2 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -2554,9 +2554,12 @@ void InterCodeBasicBlock::MapVariables(GrowingVariableArray& globalVars, Growing switch (mInstructions[i].mCode) { + case IC_CONSTANT: + if (mInstructions[i].mTType != IT_POINTER) + break; + case IC_STORE: case IC_LOAD: - case IC_CONSTANT: case IC_JSR: if (mInstructions[i].mMemory == IM_GLOBAL) { @@ -2619,7 +2622,7 @@ bool InterCodeBasicBlock::IsLeafProcedure(void) mVisited = true; for (i = 0; i < mInstructions.Size(); i++) - if (mInstructions[i].mCode == IC_CALL) + if (mInstructions[i].mCode == IC_CALL || mInstructions[i].mCode == IC_JSR) return false; if (mTrueJump && !mTrueJump->IsLeafProcedure()) @@ -2631,6 +2634,91 @@ bool InterCodeBasicBlock::IsLeafProcedure(void) return true; } +void InterCodeBasicBlock::PeepholeOptimization(void) +{ + int i; + + if (!mVisited) + { + mVisited = true; + + bool changed; + do + { + int j = 0; + for (i = 0; i < mInstructions.Size(); i++) + { + if (mInstructions[i].mCode != IC_NONE) + { + mInstructions[j++] = mInstructions[i]; + } + } + mInstructions.SetSize(j); + + changed = false; + + for (i = 0; i < mInstructions.Size(); i++) + { + if (i + 2 < mInstructions.Size()) + { + if (mInstructions[i + 0].mTTemp >= 0 && + mInstructions[i + 1].mCode == IC_LOAD_TEMPORARY && mInstructions[i + 1].mSTemp[0] == mInstructions[i].mTTemp && + (mInstructions[i + 2].mCode == IC_RELATIONAL_OPERATOR || mInstructions[i + 2].mCode == IC_BINARY_OPERATOR) && mInstructions[i + 2].mSTemp[0] == mInstructions[i].mTTemp && mInstructions[i + 2].mSFinal[0]) + { + mInstructions[i + 0].mTTemp = mInstructions[i + 1].mTTemp; + mInstructions[i + 1].mCode = IC_NONE; + mInstructions[i + 2].mSTemp[0] = mInstructions[i + 1].mTTemp; + mInstructions[i + 2].mSFinal[0] = false; + changed = true; + } + else if (mInstructions[i + 0].mTTemp >= 0 && + mInstructions[i + 1].mCode == IC_LOAD_TEMPORARY && mInstructions[i + 1].mSTemp[0] == mInstructions[i].mTTemp && + (mInstructions[i + 2].mCode == IC_RELATIONAL_OPERATOR || mInstructions[i + 2].mCode == IC_BINARY_OPERATOR) && mInstructions[i + 2].mSTemp[1] == mInstructions[i].mTTemp && mInstructions[i + 2].mSFinal[1]) + { + mInstructions[i + 0].mTTemp = mInstructions[i + 1].mTTemp; + mInstructions[i + 1].mCode = IC_NONE; + mInstructions[i + 2].mSTemp[1] = mInstructions[i + 1].mTTemp; + mInstructions[i + 2].mSFinal[1] = false; + changed = true; + } + + // Postincrement artifact + if (mInstructions[i + 0].mCode == IC_LOAD_TEMPORARY && mInstructions[i + 1].mCode == IC_BINARY_OPERATOR && + mInstructions[i + 1].mSTemp[0] < 0 && + mInstructions[i + 0].mSTemp[0] == mInstructions[i + 1].mSTemp[1] && + mInstructions[i + 0].mSTemp[0] == mInstructions[i + 1].mTTemp) + { + InterInstruction ins = mInstructions[i + 1]; + int ttemp = mInstructions[i + 1].mTTemp; + int k = i + 1; + while (k + 2 < mInstructions.Size() && + mInstructions[k + 1].mSTemp[0] != ttemp && + mInstructions[k + 1].mSTemp[1] != ttemp && + mInstructions[k + 1].mSTemp[2] != ttemp && + mInstructions[k + 1].mTTemp != ttemp) + { + mInstructions[k] = mInstructions[k + 1]; + k++; + } + if (k > i + 1) + { + mInstructions[k] = ins; + changed = true; + } + } + } + + + } + + } while (changed); + + if (mTrueJump) mTrueJump->PeepholeOptimization(); + if (mFalseJump) mFalseJump->PeepholeOptimization(); + } +} + + void InterCodeBasicBlock::CollectVariables(GrowingVariableArray& globalVars, GrowingVariableArray& localVars) { int i; @@ -2783,7 +2871,7 @@ InterCodeProcedure::InterCodeProcedure(InterCodeModule * mod, const Location & l : mTemporaries(IT_NONE), mBlocks(nullptr), mLocation(location), mTempOffset(-1), mRenameTable(-1), mRenameUnionTable(-1), mGlobalRenameTable(-1), mValueForwardingTable(NULL), mLocalVars(InterVariable()), mModule(mod), - mIdent(ident) + mIdent(ident), mNativeProcedure(false), mLeafProcedure(false) { mID = mModule->mProcedures.Size(); mModule->mProcedures.Push(this); @@ -2964,6 +3052,27 @@ void InterCodeProcedure::TempForwarding(void) DisassembleDebug("temp forwarding"); } +void InterCodeProcedure::RemoveUnusedInstructions(void) +{ + int numTemps = mTemporaries.Size(); + + do { + ResetVisited(); + mBlocks[0]->BuildLocalTempSets(numTemps, numFixedTemporaries); + + ResetVisited(); + mBlocks[0]->BuildGlobalProvidedTempSet(NumberSet(numTemps)); + + NumberSet totalRequired2(numTemps); + + do { + ResetVisited(); + } while (mBlocks[0]->BuildGlobalRequiredTempSet(totalRequired2)); + + ResetVisited(); + } while (mBlocks[0]->RemoveUnusedResultInstructions(numFixedTemporaries)); +} + void InterCodeProcedure::Close(void) { int i, j, k, start; @@ -3139,25 +3248,18 @@ void InterCodeProcedure::Close(void) // Now remove unused instructions // - do { - ResetVisited(); - mBlocks[0]->BuildLocalTempSets(numTemps, numFixedTemporaries); - - ResetVisited(); - mBlocks[0]->BuildGlobalProvidedTempSet(NumberSet(numTemps)); - - NumberSet totalRequired2(numTemps); - - do { - ResetVisited(); - } while (mBlocks[0]->BuildGlobalRequiredTempSet(totalRequired2)); - - ResetVisited(); - } while (mBlocks[0]->RemoveUnusedResultInstructions(numFixedTemporaries)); + RemoveUnusedInstructions(); DisassembleDebug("removed unused instructions 2"); + ResetVisited(); + mBlocks[0]->PeepholeOptimization(); + + TempForwarding(); + RemoveUnusedInstructions(); + + DisassembleDebug("Peephole optimized"); FastNumberSet activeSet(numTemps); @@ -3173,6 +3275,8 @@ void InterCodeProcedure::Close(void) mTemporaries.SetSize(activeSet.Num()); + + ResetVisited(); mBlocks[0]->ShrinkActiveTemporaries(activeSet, mTemporaries); diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 4a3fabf..0292294 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -253,6 +253,9 @@ public: } }; + +typedef GrowingArray GrowingInterVariableReferenceArray; + class InterInstruction { public: @@ -415,6 +418,8 @@ public: void CollectOuterFrame(int level, int& size); bool IsLeafProcedure(void); + + void PeepholeOptimization(void); }; class InterCodeModule; @@ -434,7 +439,7 @@ public: GrowingTypeArray mTemporaries; GrowingIntArray mTempOffset; int mTempSize, mCommonFrameSize; - bool mLeafProcedure; + bool mLeafProcedure, mNativeProcedure; InterCodeModule * mModule; int mID; @@ -463,6 +468,7 @@ protected: void BuildDataFlowSets(void); void RenameTemporaries(void); void TempForwarding(void); + void RemoveUnusedInstructions(void); void DisassembleDebug(const char* name); }; diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index befedee..ba9b904 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -1397,7 +1397,10 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* mErrors->Error(exp->mLocation, "Not enough arguments for function call"); InterInstruction cins; - cins.mCode = IC_CALL; + if (exp->mLeft->mDecValue->mFlags & DTF_NATIVE) + cins.mCode = IC_JSR; + else + cins.mCode = IC_CALL; cins.mSType[0] = IT_POINTER; cins.mSTemp[0] = vl.mTemp; if (ftype->mBase->mType != DT_TYPE_VOID) @@ -2210,6 +2213,9 @@ InterCodeProcedure* InterCodeGenerator::TranslateProcedure(InterCodeModule * mod InterCodeProcedure* proc = new InterCodeProcedure(mod, dec->mLocation, dec->mIdent); dec->mVarIndex = proc->mID; + if (dec->mFlags & DTF_NATIVE) + proc->mNativeProcedure = true; + InterCodeBasicBlock* entryBlock = new InterCodeBasicBlock(); proc->Append(entryBlock); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index a8f77bf..15b5c92 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -1,52 +1,66 @@ #include "NativeCodeGenerator.h" -NativeCodeInstruction::NativeCodeInstruction(AsmInsType type, AsmInsMode mode) - : mType(type), mMode(mode), mGlobal(false), mAddress(0), mVarIndex(-1) +NativeCodeInstruction::NativeCodeInstruction(AsmInsType type, AsmInsMode mode, int address, int varIndex, bool lower, bool upper) + : mType(type), mMode(mode), mAddress(address), mVarIndex(varIndex), mLower(lower), mUpper(upper) {} -void NativeCodeInstruction::Assemble(ByteCodeGenerator* generator, NativeCodeBasicBlock* block) +void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block) { + block->PutByte(AsmInsOpcodes[mType][mMode]); + switch (mMode) { - block->PutByte(AsmInsOpcodes[mType][mMode]); - - switch (mMode) + case ASMIM_IMPLIED: + break; + case ASMIM_ZERO_PAGE: + case ASMIM_ZERO_PAGE_X: + case ASMIM_INDIRECT_X: + case ASMIM_INDIRECT_Y: + block->PutByte(uint8(mAddress)); + break; + case ASMIM_IMMEDIATE: + if (mVarIndex != -1) { - case ASMIM_IMPLIED: - break; - case ASMIM_IMMEDIATE: - case ASMIM_ZERO_PAGE: - case ASMIM_ZERO_PAGE_X: - case ASMIM_INDIRECT_X: - case ASMIM_INDIRECT_Y: - block->PutByte(uint8(mAddress)); - break; - case ASMIM_ABSOLUTE: - case ASMIM_INDIRECT: - case ASMIM_ABSOLUTE_X: - case ASMIM_ABSOLUTE_Y: - if (mGlobal) - { - ByteCodeRelocation rl; - rl.mAddr = block->mCode.Size(); - rl.mFunction = false; - rl.mLower = true; - rl.mUpper = true; - rl.mIndex = mVarIndex; - rl.mOffset = mAddress; - block->mRelocations.Push(rl); - block->PutWord(0); - } - else - { - block->PutWord(uint16(mAddress)); - } - break; - case ASMIM_RELATIVE: - block->PutByte(uint8(mAddress - block->mCode.Size() - 1)); - break; + ByteCodeRelocation rl; + rl.mAddr = block->mCode.Size(); + rl.mFunction = false; + rl.mLower = mLower; + rl.mUpper = mUpper; + rl.mIndex = mVarIndex; + rl.mOffset = mAddress; + block->mRelocations.Push(rl); + block->PutByte(0); } + else + { + block->PutByte(uint16(mAddress)); + } + break; + case ASMIM_ABSOLUTE: + case ASMIM_INDIRECT: + case ASMIM_ABSOLUTE_X: + case ASMIM_ABSOLUTE_Y: + if (mVarIndex != - 1) + { + ByteCodeRelocation rl; + rl.mAddr = block->mCode.Size(); + rl.mFunction = false; + rl.mLower = true; + rl.mUpper = true; + rl.mIndex = mVarIndex; + rl.mOffset = mAddress; + block->mRelocations.Push(rl); + block->PutWord(0); + } + else + { + block->PutWord(uint16(mAddress)); + } + break; + case ASMIM_RELATIVE: + block->PutByte(uint8(mAddress)); + break; } } @@ -61,17 +75,17 @@ void NativeCodeBasicBlock::PutWord(uint16 code) this->mCode.Insert((uint8)(code & 0xff)); this->mCode.Insert((uint8)(code >> 8)); } -#if 0 + static AsmInsType InvertBranchCondition(AsmInsType code) { switch (code) { - case BC_BRANCHS_EQ: return BC_BRANCHS_NE; - case BC_BRANCHS_NE: return BC_BRANCHS_EQ; - case BC_BRANCHS_GT: return BC_BRANCHS_LE; - case BC_BRANCHS_GE: return BC_BRANCHS_LT; - case BC_BRANCHS_LT: return BC_BRANCHS_GE; - case BC_BRANCHS_LE: return BC_BRANCHS_GT; + case ASMIT_BEQ: return ASMIT_BNE; + case ASMIT_BNE: return ASMIT_BEQ; + case ASMIT_BPL: return ASMIT_BMI; + case ASMIT_BMI: return ASMIT_BPL; + case ASMIT_BCS: return ASMIT_BCC; + case ASMIT_BCC: return ASMIT_BCS; default: return code; } @@ -81,19 +95,36 @@ static AsmInsType TransposeBranchCondition(AsmInsType code) { switch (code) { - case BC_BRANCHS_EQ: return BC_BRANCHS_EQ; - case BC_BRANCHS_NE: return BC_BRANCHS_NE; - case BC_BRANCHS_GT: return BC_BRANCHS_LT; - case BC_BRANCHS_GE: return BC_BRANCHS_LE; - case BC_BRANCHS_LT: return BC_BRANCHS_GT; - case BC_BRANCHS_LE: return BC_BRANCHS_GE; + case ASMIT_BEQ: return ASMIT_BEQ; + case ASMIT_BNE: return ASMIT_BNE; + case ASMIT_BPL: return ASMIT_BMI; + case ASMIT_BMI: return ASMIT_BPL; + case ASMIT_BCS: return ASMIT_BCC; + case ASMIT_BCC: return ASMIT_BCS; default: return code; } } -int NativeCodeBasicBlock::PutBranch(ByteCodeGenerator* generator, AsmInsType code, int offset) +int NativeCodeBasicBlock::PutJump(NativeCodeProcedure* proc, int offset) +{ + PutByte(0x4c); + + ByteCodeRelocation rl; + rl.mAddr = mCode.Size(); + rl.mFunction = true; + rl.mLower = true; + rl.mUpper = true; + rl.mIndex = proc->mIndex; + rl.mOffset = mOffset + mCode.Size() + offset - 1; + mRelocations.Push(rl); + + PutWord(0); + return 3; +} + +int NativeCodeBasicBlock::PutBranch(NativeCodeProcedure* proc, AsmInsType code, int offset) { if (offset >= -126 && offset <= 129) { @@ -103,11 +134,1213 @@ int NativeCodeBasicBlock::PutBranch(ByteCodeGenerator* generator, AsmInsType cod } else { - PutByte(AsmInsOpcodes[code][ASMIM_RELATIVE]); + PutByte(AsmInsOpcodes[InvertBranchCondition(code)][ASMIM_RELATIVE]); + PutByte(3); + PutByte(0x4c); - PutCode(generator, ByteCode(code + (BC_JUMPF - BC_JUMPS))); - PutWord(offset - 3); - return 3; + ByteCodeRelocation rl; + rl.mAddr = mCode.Size(); + rl.mFunction = true; + rl.mLower = true; + rl.mUpper = true; + rl.mIndex = proc->mIndex; + rl.mOffset = mOffset + mCode.Size() + offset - 3; + mRelocations.Push(rl); + + PutWord(0); + return 5; } } -#endif + +void NativeCodeBasicBlock::LoadConstant(InterCodeProcedure* proc, const InterInstruction& ins) +{ + if (ins.mTType == IT_FLOAT) + { + } + else if (ins.mTType == IT_POINTER) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mIntValue, ins.mVarIndex, true, false)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mIntValue, ins.mVarIndex, false, true)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mIntValue & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mIntValue >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mIntValue; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, index & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, (mNoFrame ? BC_REG_STACK : BC_REG_LOCALS) + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (index >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mMemory == IM_PROCEDURE) + { + } + } + else + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mIntValue & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mIntValue >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + +} + +void NativeCodeBasicBlock::StoreValue(InterCodeProcedure* proc, const InterInstruction& ins) +{ + if (ins.mSType[0] == IT_FLOAT) + { + } + else if (ins.mSType[0] == IT_POINTER) + { + if (ins.mSTemp[1] < 0) + { + if (ins.mSTemp[0] < 0) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1], ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1, ins.mVarIndex)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1)); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[1]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + else if (ins.mMemory == IM_FRAME) + { + } + } + else + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1], ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1, ins.mVarIndex)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1)); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[1]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + else if (ins.mMemory == IM_FRAME) + { + } + } + } + else + { + if (ins.mSTemp[0] < 0) + { + if (ins.mMemory == IM_INDIRECT) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + } + } + else + { + if (ins.mMemory == IM_INDIRECT) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + } + } + } + } + else + { + if (ins.mSTemp[1] < 0) + { + if (ins.mSTemp[0] < 0) + { + if (ins.mOperandSize == 1) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1], ins.mVarIndex)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1])); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[1]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + else if (ins.mMemory == IM_FRAME) + { + } + } + else if (ins.mOperandSize == 2) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1], ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1, ins.mVarIndex)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1)); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[1]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + else if (ins.mMemory == IM_FRAME) + { + } + } + } + else + { + if (ins.mOperandSize == 1) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1], ins.mVarIndex)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1])); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[1]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + else if (ins.mMemory == IM_FRAME) + { + } + } + else if (ins.mOperandSize == 2) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1], ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1, ins.mVarIndex)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, ins.mSIntConst[1] + 1)); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[1]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + else if (ins.mMemory == IM_FRAME) + { + } + } + } + } + else + { + if (ins.mSTemp[0] < 0) + { + if (ins.mMemory == IM_INDIRECT) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + + if (ins.mOperandSize == 2) + { + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + } + } + } + else + { + if (ins.mMemory == IM_INDIRECT) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + + if (ins.mOperandSize == 2) + { + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + } + } + } + } + } + +} + +void NativeCodeBasicBlock::LoadStoreValue(InterCodeProcedure* proc, const InterInstruction& rins, const InterInstruction& wins) +{ + if (rins.mTType == IT_FLOAT) + { + + } + else if (rins.mTType == IT_POINTER) + { + + } + else + { + if (wins.mOperandSize == 1) + { + if (rins.mSTemp[0] < 0) + { + if (rins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, rins.mSIntConst[0], rins.mVarIndex)); + } + else if (rins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, rins.mSIntConst[0])); + } + else if (rins.mMemory == IM_LOCAL || rins.mMemory == IM_PARAM) + { + int index = rins.mSIntConst[0]; + if (rins.mMemory == IM_LOCAL) + index += proc->mLocalVars[rins.mVarIndex].mOffset; + else + index += rins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + } + else + { + if (rins.mMemory == IM_INDIRECT) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins.mSTemp[0]])); + } + } + + if (wins.mSTemp[1] < 0) + { + if (wins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, wins.mSIntConst[1], wins.mVarIndex)); + } + else if (wins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ABSOLUTE, wins.mSIntConst[1])); + } + else if (wins.mMemory == IM_LOCAL || wins.mMemory == IM_PARAM) + { + int index = wins.mSIntConst[1]; + if (wins.mMemory == IM_LOCAL) + index += proc->mLocalVars[wins.mVarIndex].mOffset; + else + index += wins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + else if (wins.mMemory == IM_FRAME) + { + } + } + else + { + if (wins.mMemory == IM_INDIRECT) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[wins.mSTemp[1]])); + } + } + } + } +} + +void NativeCodeBasicBlock::LoadValue(InterCodeProcedure* proc, const InterInstruction& ins) +{ + if (ins.mTType == IT_FLOAT) + { + } + else if (ins.mTType == IT_POINTER) + { + if (ins.mSTemp[0] < 0) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0], ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0] + 1, ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[0]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + } + else + { + if (ins.mMemory == IM_INDIRECT) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + } + } + else + { + if (ins.mSTemp[0] < 0) + { + if (ins.mOperandSize == 1) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0], ins.mVarIndex)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0])); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[0]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + } + + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + if (ins.mTType == IT_SIGNED) + { + mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); + } + else + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + } + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mOperandSize == 2) + { + if (ins.mMemory == IM_GLOBAL) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0], ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0] + 1, ins.mVarIndex)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mMemory == IM_ABSOLUTE) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ABSOLUTE, ins.mSIntConst[0] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mMemory == IM_LOCAL || ins.mMemory == IM_PARAM) + { + int index = ins.mSIntConst[0]; + if (ins.mMemory == IM_LOCAL) + index += proc->mLocalVars[ins.mVarIndex].mOffset; + else + index += ins.mVarIndex + proc->mLocalSize + 2; + + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, index)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, mNoFrame ? BC_REG_STACK : BC_REG_LOCALS)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + } + } + else + { + if (ins.mMemory == IM_INDIRECT) + { + if (ins.mOperandSize == 1) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + if (ins.mTType == IT_SIGNED) + { + mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, 0x80)); + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_EOR, ASMIM_IMMEDIATE, 0xff)); + } + else + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, 0)); + } + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else if (ins.mOperandSize == 2) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDY, ASMIM_IMMEDIATE, 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_INY, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_INDIRECT_Y, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + } + } + } +} + +void NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* proc, const InterInstruction& ins) +{ + switch (ins.mOperator) + { + case IA_ADD: + { + if (ins.mSTemp[0] < 0 && ins.mSIntConst[0] == 1 && ins.mSTemp[1] == ins.mTTemp || + ins.mSTemp[1] < 0 && ins.mSIntConst[1] == 1 && ins.mSTemp[0] == ins.mTTemp) + { + mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_BNE, ASMIM_RELATIVE, 2)); + mIns.Push(NativeCodeInstruction(ASMIT_INC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else + { + mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[1] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[1] >> 8) & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]] + 1)); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + } break; + case IA_SUB: + { + mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[1] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[1] >> 8) & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]] + 1)); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } break; + case IA_SHL: + { + if (ins.mSTemp[0] < 0) + { + if (ins.mSIntConst[0] == 1) + { + if (ins.mSTemp[1] == ins.mTTemp) + { + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + else + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); + } + } + } + } break; + } +} + +void NativeCodeBasicBlock::UnaryOperator(InterCodeProcedure* proc, const InterInstruction& ins) +{ + +} + +void NativeCodeBasicBlock::RelationalOperator(InterCodeProcedure* proc, const InterInstruction& ins, NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump) +{ + switch (ins.mOperator) + { + case IA_CMPEQ: + { + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[1] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + + NativeCodeBasicBlock* tblock = new NativeCodeBasicBlock(); + tblock->mNoFrame = mNoFrame; + tblock->mIndex = 1000; + + this->Close(falseJump, tblock, ASMIT_BNE); + + if (ins.mSTemp[1] < 0) + tblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[1] >> 8) & 0xff)); + else + tblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]] + 1)); + if (ins.mSTemp[0] < 0) + tblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + else + tblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + + tblock->Close(falseJump, trueJump, ASMIT_BNE); + } break; + case IA_CMPNE: + { + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[1] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + + NativeCodeBasicBlock* tblock = new NativeCodeBasicBlock(); + tblock->mNoFrame = mNoFrame; + tblock->mIndex = 1000; + + this->Close(trueJump, tblock, ASMIT_BNE); + + if (ins.mSTemp[1] < 0) + tblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[1] >> 8) & 0xff)); + else + tblock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]] + 1)); + if (ins.mSTemp[0] < 0) + tblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + else + tblock->mIns.Push(NativeCodeInstruction(ASMIT_CMP, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + + tblock->Close(trueJump, falseJump, ASMIT_BNE); + } break; + } +} + +void NativeCodeBasicBlock::LoadEffectiveAddress(InterCodeProcedure* proc, const InterInstruction& ins) +{ + mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, ins.mSIntConst[1] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]])); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, ins.mSIntConst[0] & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp])); + if (ins.mSTemp[1] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, (ins.mSIntConst[1] >> 8) & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[1]] + 1)); + if (ins.mSTemp[0] < 0) + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (ins.mSIntConst[0] >> 8) & 0xff)); + else + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins.mTTemp] + 1)); +} + +void NativeCodeBasicBlock::Compile(InterCodeProcedure* iproc, NativeCodeProcedure* proc, InterCodeBasicBlock* sblock) +{ + mIndex = sblock->mIndex; + + int i = 0; + while (i < sblock->mInstructions.Size()) + { + const InterInstruction& ins = sblock->mInstructions[i]; + + switch (ins.mCode) + { + case IC_STORE: + StoreValue(iproc, ins); + break; + case IC_LOAD: + if (i + 1 < sblock->mInstructions.Size() && + sblock->mInstructions[i + 1].mCode == IC_STORE && + sblock->mInstructions[i + 1].mSTemp[0] == ins.mTTemp && + sblock->mInstructions[i + 1].mSFinal[0] && + sblock->mInstructions[i + 1].mOperandSize == 1) + { + LoadStoreValue(iproc, ins, sblock->mInstructions[i + 1]); + i++; + } + else + LoadValue(iproc, ins); + break; + case IC_COPY: +// CopyValue(iproc, ins); + break; + case IC_LOAD_TEMPORARY: + { + if (ins.mSTemp[0] != ins.mTTemp) + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mTTemp])); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mTTemp] + 1)); + } + } break; + case IC_BINARY_OPERATOR: + BinaryOperator(iproc, ins); + break; + case IC_UNARY_OPERATOR: + UnaryOperator(iproc, ins); + break; + case IC_CONVERSION_OPERATOR: +// NumericConversion(iproc, ins); + break; + case IC_LEA: + LoadEffectiveAddress(iproc, ins); + break; + case IC_CONSTANT: + LoadConstant(iproc, ins); + break; + case IC_CALL: +// CallFunction(iproc, ins); + break; + case IC_JSR: +// CallAssembler(iproc, ins); + break; + case IC_PUSH_FRAME: + { + } break; + case IC_POP_FRAME: + { + } break; + + case IC_RELATIONAL_OPERATOR: + if (sblock->mInstructions[i + 1].mCode == IC_BRANCH) + { + RelationalOperator(iproc, ins, proc->CompileBlock(iproc, sblock->mTrueJump), proc->CompileBlock(iproc, sblock->mFalseJump)); + return; + } + break; + + case IC_RETURN_VALUE: + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mSTemp[0]] + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + + this->Close(proc->exitBlock, nullptr, ASMIT_JMP); + return; + } + + case IC_RETURN: + this->Close(proc->exitBlock, nullptr, ASMIT_JMP); + return; + + case IC_TYPECAST: + break; + + case IC_BRANCH: + if (ins.mSTemp[0] < 0) + { + if (ins.mSIntConst[0] == 0) + this->Close(proc->CompileBlock(iproc, sblock->mFalseJump), nullptr, ASMIT_JMP); + else + this->Close(proc->CompileBlock(iproc, sblock->mTrueJump), nullptr, ASMIT_JMP); + } + else + { + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mSTemp[0]])); + mIns.Push(NativeCodeInstruction(ASMIT_ORA, ASMIM_ZERO_PAGE, BC_REG_TMP + iproc->mTempOffset[ins.mSTemp[0]] + 1)); + + this->Close(proc->CompileBlock(iproc, sblock->mTrueJump), proc->CompileBlock(iproc, sblock->mFalseJump), ASMIT_BNE); + } + return; + + } + + i++; + } + + this->Close(proc->CompileBlock(iproc, sblock->mTrueJump), nullptr, ASMIT_JMP); +} + +void NativeCodeBasicBlock::Assemble(void) +{ + if (!mAssembled) + { + mAssembled = true; + + //PeepHoleOptimizer(); + + for (int i = 0; i < mIns.Size(); i++) + mIns[i].Assemble(this); + + if (this->mTrueJump) + this->mTrueJump->Assemble(); + if (this->mFalseJump) + this->mFalseJump->Assemble(); + } +} + +void NativeCodeBasicBlock::Close(NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump, AsmInsType branch) +{ + this->mTrueJump = trueJump; + this->mFalseJump = falseJump; + this->mBranch = branch; +} + + +static int BranchByteSize(int from, int to) +{ + if (to - from >= -126 && to - from <= 129) + return 2; + else + return 5; +} + +static int JumpByteSize(int from, int to) +{ + return 3; +} + +NativeCodeBasicBlock* NativeCodeBasicBlock::BypassEmptyBlocks(void) +{ + if (mBypassed) + return this; + else if (!mFalseJump && mCode.Size() == 0) + return mTrueJump->BypassEmptyBlocks(); + else + { + mBypassed = true; + + if (mFalseJump) + mFalseJump = mFalseJump->BypassEmptyBlocks(); + if (mTrueJump) + mTrueJump = mTrueJump->BypassEmptyBlocks(); + + return this; + } +} + +void NativeCodeBasicBlock::CopyCode(NativeCodeProcedure * proc, uint8* target) +{ + int i; + int next; + int pos, at; + uint8 b; + + if (!mCopied) + { + mCopied = true; + + + next = mOffset + mCode.Size(); + + if (mFalseJump) + { + if (mFalseJump->mOffset <= mOffset) + { + if (mTrueJump->mOffset <= mOffset) + { + next += PutBranch(proc, mBranch, mTrueJump->mOffset - next); + next += PutJump(proc, mFalseJump->mOffset - next); + + } + else + { + next += PutBranch(proc, InvertBranchCondition(mBranch), mFalseJump->mOffset - next); + } + } + else + { + next += PutBranch(proc, mBranch, mTrueJump->mOffset - next); + } + } + else if (mTrueJump) + { + if (mTrueJump->mOffset != next) + { + next += PutJump(proc, mTrueJump->mOffset - next); + } + } + + assert(next - mOffset == mSize); + + for (i = 0; i < mCode.Size(); i++) + { + mCode.Lookup(i, target[i + mOffset]); + } + + for (int i = 0; i < mRelocations.Size(); i++) + { + ByteCodeRelocation& rl(mRelocations[i]); + rl.mAddr += mOffset; + proc->mRelocations.Push(rl); + } + + if (mTrueJump) mTrueJump->CopyCode(proc, target); + if (mFalseJump) mFalseJump->CopyCode(proc, target); + } +} + +void NativeCodeBasicBlock::CalculateOffset(int& total) +{ + int next; + + if (mOffset > total) + { + mOffset = total; + next = total + mCode.Size(); + + if (mFalseJump) + { + if (mFalseJump->mOffset <= total) + { + // falseJump has been placed + + if (mTrueJump->mOffset <= total) + { + // trueJump and falseJump have been placed, not much to do + + next = next + BranchByteSize(next, mTrueJump->mOffset); + total = next + JumpByteSize(next, mFalseJump->mOffset); + mSize = total - mOffset; + } + else + { + // trueJump has not been placed, but falseJump has + + total = next + BranchByteSize(next, mFalseJump->mOffset); + mSize = total - mOffset; + mTrueJump->CalculateOffset(total); + } + } + else if (mTrueJump->mOffset <= total) + { + // falseJump has not been placed, but trueJump has + + total = next + BranchByteSize(next, mTrueJump->mOffset); + mSize = total - mOffset; + mFalseJump->CalculateOffset(total); + } + else if (mKnownShortBranch) + { + // neither falseJump nor trueJump have been placed, + // but we know from previous iteration that we can do + // a short branch + + total = next + 2; + mSize = total - mOffset; + + mFalseJump->CalculateOffset(total); + if (mTrueJump->mOffset > total) + { + // trueJump was not placed in the process, so lets place it now + mTrueJump->CalculateOffset(total); + } + } + else + { + // neither falseJump nor trueJump have been placed + // this may lead to some undo operation... + // first assume a full size branch: + + total = next + 5; + mSize = total - mOffset; + + mFalseJump->CalculateOffset(total); + if (mTrueJump->mOffset > total) + { + // trueJump was not placed in the process, so lets place it now + + mTrueJump->CalculateOffset(total); + } + + if (BranchByteSize(next, mTrueJump->mOffset) < 3) + { + // oh, we can replace by a short branch + + mKnownShortBranch = true; + + total = next + 2; + mSize = total - mOffset; + + mFalseJump->CalculateOffset(total); + if (mTrueJump->mOffset > total) + { + // trueJump was not placed in the process, so lets place it now + + mTrueJump->CalculateOffset(total); + } + } + } + } + else if (mTrueJump) + { + if (mTrueJump->mOffset <= total) + { + // trueJump has been placed, so append the branch size + + total = next + JumpByteSize(next, mTrueJump->mOffset); + mSize = total - mOffset; + } + else + { + // we have to place trueJump, so just put it right behind us + + total = next; + mSize = total - mOffset; + + mTrueJump->CalculateOffset(total); + } + } + else + { + // no exit from block + + total += mCode.Size(); + mSize = total - mOffset; + } + } +} + +NativeCodeBasicBlock::NativeCodeBasicBlock(void) + : mIns(NativeCodeInstruction(ASMIT_INV, ASMIM_IMPLIED)), mRelocations({ 0 }) +{ + mTrueJump = mFalseJump = NULL; + mOffset = 0x7fffffff; + mCopied = false; + mKnownShortBranch = false; + mBypassed = false; +} + +NativeCodeBasicBlock::~NativeCodeBasicBlock(void) +{ + +} + +NativeCodeProcedure::NativeCodeProcedure(void) + : mRelocations({ 0 }) +{ + +} + +NativeCodeProcedure::~NativeCodeProcedure(void) +{ + +} + +void NativeCodeProcedure::Compile(ByteCodeGenerator* generator, InterCodeProcedure* proc) +{ + tblocks = new NativeCodeBasicBlock * [proc->mBlocks.Size()]; + for (int i = 0; i < proc->mBlocks.Size(); i++) + tblocks[i] = nullptr; + + mIndex = proc->mID; + mNoFrame = true; + + entryBlock = new NativeCodeBasicBlock(); + entryBlock->mNoFrame = mNoFrame; + + tblocks[0] = entryBlock; + + exitBlock = new NativeCodeBasicBlock(); + exitBlock->mNoFrame = mNoFrame; + + exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_RTS, ASMIM_IMPLIED)); + + entryBlock->Compile(proc, this, proc->mBlocks[0]); + entryBlock->Assemble(); + + int total, base; + + NativeCodeBasicBlock* lentryBlock = entryBlock->BypassEmptyBlocks(); + + total = 0; + base = generator->mProgEnd; + + lentryBlock->CalculateOffset(total); + + generator->AddAddress(proc->mID, true, base, total, proc->mIdent, true); + + lentryBlock->CopyCode(this, generator->mMemory + base); + + generator->mProgEnd += total; + + for (int i = 0; i < mRelocations.Size(); i++) + { + ByteCodeRelocation& rl(mRelocations[i]); + rl.mAddr += base; + generator->mRelocations.Push(rl); + } +} + +NativeCodeBasicBlock* NativeCodeProcedure::CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* sblock) +{ + if (tblocks[sblock->mIndex]) + return tblocks[sblock->mIndex]; + + NativeCodeBasicBlock* block = new NativeCodeBasicBlock(); + block->mNoFrame = mNoFrame; + + tblocks[sblock->mIndex] = block; + block->Compile(iproc, this, sblock); + + return block; +} diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index 04b6be7..a27bbe9 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -9,15 +9,15 @@ class NativeCodeBasicBlock; class NativeCodeInstruction { public: - NativeCodeInstruction(AsmInsType type, AsmInsMode mode); + NativeCodeInstruction(AsmInsType type = ASMIT_INV, AsmInsMode mode = ASMIM_IMPLIED, int address = 0, int varIndex = -1, bool lower = true, bool upper = true); AsmInsType mType; AsmInsMode mMode; int mAddress, mVarIndex; - bool mGlobal; + bool mLower, mUpper; - void Assemble(ByteCodeGenerator* generator, NativeCodeBasicBlock* block); + void Assemble(NativeCodeBasicBlock* block); }; class NativeCodeBasicBlock @@ -36,21 +36,30 @@ public: GrowingArray mRelocations; int mOffset, mSize; - bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled; + bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame; - int PutBranch(ByteCodeGenerator* generator, AsmInsType code, int offset); + int PutBranch(NativeCodeProcedure* proc, AsmInsType code, int offset); + int PutJump(NativeCodeProcedure* proc, int offset); NativeCodeBasicBlock* BypassEmptyBlocks(void); void CalculateOffset(int& total); - void CopyCode(ByteCodeGenerator* generator, uint8* target); - void Assemble(ByteCodeGenerator* generator); + void CopyCode(NativeCodeProcedure* proc, uint8* target); + void Assemble(void); void Compile(InterCodeProcedure* iproc, NativeCodeProcedure* proc, InterCodeBasicBlock* block); void Close(NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump, AsmInsType branch); void PutByte(uint8 code); void PutWord(uint16 code); + void LoadConstant(InterCodeProcedure* proc, const InterInstruction& ins); + void StoreValue(InterCodeProcedure* proc, const InterInstruction& ins); + void LoadValue(InterCodeProcedure* proc, const InterInstruction& ins); + void LoadStoreValue(InterCodeProcedure* proc, const InterInstruction& rins, const InterInstruction& wins); + void BinaryOperator(InterCodeProcedure* proc, const InterInstruction& ins); + void UnaryOperator(InterCodeProcedure* proc, const InterInstruction& ins); + void RelationalOperator(InterCodeProcedure* proc, const InterInstruction& ins, NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock * falseJump); + void LoadEffectiveAddress(InterCodeProcedure* proc, const InterInstruction& ins); }; class NativeCodeProcedure @@ -62,10 +71,14 @@ class NativeCodeProcedure NativeCodeBasicBlock* entryBlock, * exitBlock; NativeCodeBasicBlock** tblocks; - int mProgStart, mProgSize; + int mProgStart, mProgSize, mIndex; + bool mNoFrame; - void Compile(ByteCodeGenerator* generator, InterCodeProcedure* proc); + GrowingArray mRelocations; + + void Compile( ByteCodeGenerator * generator, InterCodeProcedure* proc); NativeCodeBasicBlock* CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* block); + NativeCodeBasicBlock* TransientBlock(void); }; diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index d4c002b..8a2a577 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -2106,6 +2106,21 @@ void Parser::ParsePragma(void) } ConsumeToken(TK_CLOSE_PARENTHESIS); } + else if (!strcmp(mScanner->mTokenIdent->mString, "native")) + { + mScanner->NextToken(); + ConsumeToken(TK_OPEN_PARENTHESIS); + if (mScanner->mToken == TK_IDENT) + { + Declaration* dec = mGlobals->Lookup(mScanner->mTokenIdent); + if (dec && dec->mType == DT_CONST_FUNCTION) + dec->mFlags |= DTF_NATIVE; + else + mErrors->Error(mScanner->mLocation, "Native function not found"); + mScanner->NextToken(); + } + ConsumeToken(TK_CLOSE_PARENTHESIS); + } else if (!strcmp(mScanner->mTokenIdent->mString, "startup")) { if (mCompilationUnits->mStartup)