First shot native code generator

Implements basic load, store compare and add/sub/shift for native compiled functions
This commit is contained in:
drmortalwombat 2021-09-07 22:35:11 +02:00
parent 69a44e90e3
commit 056df56eef
10 changed files with 1589 additions and 185 deletions

View File

@ -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,14 +3395,25 @@ 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 (mGlobalAddr[i].mIdent)
fprintf(file, "%s:\n", mGlobalAddr[i].mIdent->mString);
if (addr.mIdent)
fprintf(file, "%s:\n", addr.mIdent->mString);
int ip = mGlobalAddr[i].mAddress;
while (ip < mGlobalAddr[i].mAddress + mGlobalAddr[i].mSize)
int ip = addr.mAddress;
while (ip < addr.mAddress + addr.mSize)
{
int iip = ip;
uint8 opcode = mMemory[ip++];
@ -3411,51 +3423,51 @@ void ByteCodeGenerator::WriteAsmFile(FILE* file)
switch (d.mMode)
{
case ASMIM_IMPLIED:
fprintf(file, "%04x : %04x %02x __ __ %s\n", iip, ip, mMemory[ip], AsmInstructionNames[d.mType]);
fprintf(file, "%04x : %02x __ __ %s\n", iip, 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);
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 : %04x %02x %02x __ %s $%02x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x __ %s $%02x,x\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x __ %s $%02x,y\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x %02x %s $%04x\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x %02x %s $%04x,x\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x %02x %s $%04x,y\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x %02x %s ($%04x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], mMemory[ip + 2], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x __ %s ($%02x,x)\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
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 : %04x %02x %02x __ %s ($%02x),y\n", iip, ip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
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++];
@ -3463,12 +3475,11 @@ void ByteCodeGenerator::WriteAsmFile(FILE* file)
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);
fprintf(file, "%04x : %02x %02x __ %s $%02x\n", iip, mMemory[ip], mMemory[ip + 1], AsmInstructionNames[d.mType], addr);
break;
}
}
}
}
}
bool ByteCodeGenerator::WriteMapFile(const char* filename)

View File

@ -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<Address> 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);
};

View File

@ -4,6 +4,7 @@
#include "InterCodeGenerator.h"
#include "InterCode.h"
#include "ByteCodeGenerator.h"
#include "NativeCodeGenerator.h"
#include "Emulator.h"
#include <stdio.h>
@ -85,15 +86,25 @@ 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]);
if (proc->mNativeProcedure)
{
NativeCodeProcedure* ncproc = new NativeCodeProcedure();
ncproc->Compile(mByteCodeGenerator, proc);
}
else
{
ByteCodeProcedure* bgproc = new ByteCodeProcedure();
bgproc->Compile(mByteCodeGenerator, proc);
mByteCodeFunctions.Push(bgproc);
#if _DEBUG
@ -107,6 +118,7 @@ bool Compiler::GenerateCode(void)
}
#endif
}
}
for (int i = 0; i < 128; i++)
{

View File

@ -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;

View File

@ -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);

View File

@ -253,6 +253,9 @@ public:
}
};
typedef GrowingArray<InterVariable::Reference> 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);
};

View File

@ -1397,6 +1397,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration*
mErrors->Error(exp->mLocation, "Not enough arguments for function call");
InterInstruction cins;
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;
@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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<ByteCodeRelocation> 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<ByteCodeRelocation> mRelocations;
void Compile( ByteCodeGenerator * generator, InterCodeProcedure* proc);
NativeCodeBasicBlock* CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* block);
NativeCodeBasicBlock* TransientBlock(void);
};

View File

@ -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)