Add experimental native code outliner
This commit is contained in:
parent
9f834c4232
commit
95732265f6
|
@ -293,7 +293,7 @@ const char* AsmInstructionNames[NUM_ASM_INS_TYPES] = {
|
|||
"INV", "BYT"
|
||||
};
|
||||
|
||||
int AsmInsModeSize[NUM_ASM_INS_MODES] = {
|
||||
int AsmInsModeSize[NUM_ASM_INS_MODES_X] = {
|
||||
1,
|
||||
2,
|
||||
2,
|
||||
|
@ -306,6 +306,8 @@ int AsmInsModeSize[NUM_ASM_INS_MODES] = {
|
|||
2,
|
||||
2,
|
||||
2,
|
||||
0,
|
||||
2
|
||||
};
|
||||
|
||||
void InitAssembler(void)
|
||||
|
|
|
@ -31,7 +31,9 @@ enum AsmInsMode
|
|||
|
||||
NUM_ASM_INS_MODES,
|
||||
|
||||
ASMIM_IMMEDIATE_ADDRESS
|
||||
ASMIM_IMMEDIATE_ADDRESS,
|
||||
|
||||
NUM_ASM_INS_MODES_X,
|
||||
};
|
||||
|
||||
struct AsmInsData
|
||||
|
@ -45,6 +47,8 @@ extern AsmInsData DecInsData[256];
|
|||
|
||||
extern short AsmInsOpcodes[NUM_ASM_INS_TYPES][NUM_ASM_INS_MODES];
|
||||
|
||||
extern int AsmInsModeSize[NUM_ASM_INS_MODES_X];
|
||||
|
||||
extern const char* AsmInstructionNames[NUM_ASM_INS_TYPES];
|
||||
|
||||
AsmInsType FindAsmInstruction(const char * ins);
|
||||
|
|
|
@ -466,7 +466,7 @@ void Compiler::CompileProcedure(InterCodeProcedure* proc)
|
|||
printf("Generate native code <%s>\n", proc->mIdent->mString);
|
||||
|
||||
ncproc->Compile(proc);
|
||||
mNativeProcedures.Push(ncproc);
|
||||
mNativeCodeGenerator->mProcedures.Push(ncproc);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1036,13 +1036,15 @@ bool Compiler::GenerateCode(void)
|
|||
mCompilationUnits->mSectionStack->mSections.Push(proc->mLinkerObject->mStackSection);
|
||||
}
|
||||
|
||||
mNativeCodeGenerator->OutlineFunctions();
|
||||
|
||||
mNativeCodeGenerator->BuildFunctionProxies();
|
||||
|
||||
for (int i = 0; i < mNativeProcedures.Size(); i++)
|
||||
for (int i = 0; i < mNativeCodeGenerator->mProcedures.Size(); i++)
|
||||
{
|
||||
if (mCompilerOptions & COPT_VERBOSE2)
|
||||
printf("Assemble native code <%s>\n", mNativeProcedures[i]->mInterProc->mIdent->mString);
|
||||
mNativeProcedures[i]->Assemble();
|
||||
printf("Assemble native code <%s>\n", mNativeCodeGenerator->mProcedures[i]->mInterProc->mIdent->mString);
|
||||
mNativeCodeGenerator->mProcedures[i]->Assemble();
|
||||
}
|
||||
|
||||
LinkerObject* byteCodeObject = nullptr;
|
||||
|
|
|
@ -29,7 +29,6 @@ public:
|
|||
GlobalOptimizer* mGlobalOptimizer;
|
||||
|
||||
GrowingArray<ByteCodeProcedure*> mByteCodeFunctions;
|
||||
ExpandingArray<NativeCodeProcedure*> mNativeProcedures;
|
||||
|
||||
TargetMachine mTargetMachine;
|
||||
uint64 mCompilerOptions;
|
||||
|
|
|
@ -14,6 +14,7 @@ static const uint64 COPT_OPTIMIZE_AUTO_ZEROPAGE = 1ULL << 8;
|
|||
static const uint64 COPT_OPTIMIZE_CONST_PARAMS = 1ULL << 9;
|
||||
static const uint64 COPT_OPTIMIZE_MERGE_CALLS = 1ULL << 10;
|
||||
static const uint64 COPT_OPTIMIZE_GLOBAL = 1ULL << 11;
|
||||
static const uint64 COPT_OPTIMIZE_OUTLINE = 1ULL << 12;
|
||||
|
||||
static const uint64 COPT_OPTIMIZE_CODE_SIZE = 1ULL << 16;
|
||||
static const uint64 COPT_NATIVE = 1ULL << 17;
|
||||
|
@ -50,7 +51,7 @@ static const uint64 COPT_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE |
|
|||
|
||||
static const uint64 COPT_OPTIMIZE_DEFAULT = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS;
|
||||
|
||||
static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
|
||||
static const uint64 COPT_OPTIMIZE_SIZE = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_CODE_SIZE | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;// | COPT_OPTIMIZE_OUTLINE;
|
||||
|
||||
static const uint64 COPT_OPTIMIZE_SPEED = COPT_OPTIMIZE_BASIC | COPT_OPTIMIZE_INLINE | COPT_OPTIMIZE_AUTO_INLINE | COPT_OPTIMIZE_AUTO_UNROLL | COPT_OPTIMIZE_CONST_EXPRESSIONS | COPT_OPTIMIZE_ASSEMBLER | COPT_OPTIMIZE_CONST_PARAMS | COPT_OPTIMIZE_MERGE_CALLS | COPT_OPTIMIZE_GLOBAL;
|
||||
|
||||
|
|
|
@ -9533,7 +9533,12 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray
|
|||
else
|
||||
mTrueValueRange[s1].LimitMinWeak(0);
|
||||
|
||||
if (mFalseValueRange[s1].mMinState == IntegerValueRange::S_BOUND && mFalseValueRange[s1].mMinValue >= 0)
|
||||
if (mInstructions[sz - 2]->mSrc[1].mType == IT_INT8)
|
||||
{
|
||||
mFalseValueRange[s1].LimitMin(mInstructions[sz - 2]->mSrc[0].mIntConst);
|
||||
mFalseValueRange[s1].LimitMax(255);
|
||||
}
|
||||
else if (mFalseValueRange[s1].mMinState == IntegerValueRange::S_BOUND && mFalseValueRange[s1].mMinValue >= 0)
|
||||
{
|
||||
mFalseValueRange[s1].LimitMin(mInstructions[sz - 2]->mSrc[0].mIntConst);
|
||||
}
|
||||
|
@ -19507,7 +19512,7 @@ void InterCodeBasicBlock::CheckFinalLocal(void)
|
|||
{
|
||||
if (ins->mSrc[j].mTemp >= 0 && !provided[ins->mSrc[j].mTemp])
|
||||
{
|
||||
printf("Use of potentially undefined temp %d\n", ins->mSrc[j].mTemp);
|
||||
// printf("Use of potentially undefined temp %d\n", ins->mSrc[j].mTemp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23211,7 +23216,7 @@ void InterCodeProcedure::Close(void)
|
|||
{
|
||||
GrowingTypeArray tstack(IT_NONE);
|
||||
|
||||
CheckFunc = !strcmp(mIdent->mString, "enemies_iterate");
|
||||
CheckFunc = !strcmp(mIdent->mString, "main");
|
||||
CheckCase = false;
|
||||
|
||||
mEntryBlock = mBlocks[0];
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "NativeCodeGenerator.h"
|
||||
#include "CompilerTypes.h"
|
||||
#include "NativeCodeOutliner.h"
|
||||
|
||||
#define JUMP_TO_BRANCH 1
|
||||
#define CHECK_NULLPTR 0
|
||||
|
@ -539,6 +540,67 @@ NativeCodeInstruction::NativeCodeInstruction(const InterInstruction* ins, AsmIns
|
|||
}
|
||||
}
|
||||
|
||||
const char* NativeCodeInstruction::AddrName(char* buffer) const
|
||||
{
|
||||
if (mLinkerObject)
|
||||
{
|
||||
if (mLinkerObject->mIdent)
|
||||
sprintf_s(buffer, 160, "%s + %d", mLinkerObject->mIdent->mString, mAddress);
|
||||
else
|
||||
sprintf_s(buffer, 160, "_lobj%d + %d", mLinkerObject->mID, mAddress);
|
||||
}
|
||||
else if (mAddress < 256)
|
||||
sprintf_s(buffer, 160, "%02x", mAddress);
|
||||
else
|
||||
sprintf_s(buffer, 160, "%04x", mAddress);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void NativeCodeInstruction::Disassemble(FILE* file) const
|
||||
{
|
||||
char buffer[160];
|
||||
|
||||
switch (mMode)
|
||||
{
|
||||
case ASMIM_IMPLIED:
|
||||
fprintf(file, "%s", AsmInstructionNames[mType]);
|
||||
break;
|
||||
case ASMIM_IMMEDIATE:
|
||||
fprintf(file, "%s #$%02x", AsmInstructionNames[mType], mAddress);
|
||||
break;
|
||||
case ASMIM_ZERO_PAGE:
|
||||
fprintf(file, "%s %s", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_ZERO_PAGE_X:
|
||||
fprintf(file, "%s %s, x", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_ZERO_PAGE_Y:
|
||||
fprintf(file, "%s %s, y", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_ABSOLUTE:
|
||||
fprintf(file, "%s %s", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_ABSOLUTE_X:
|
||||
fprintf(file, "%s %s, x", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_ABSOLUTE_Y:
|
||||
fprintf(file, "%s %s, y", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_INDIRECT:
|
||||
fprintf(file, "%s (%s)", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_INDIRECT_X:
|
||||
fprintf(file, "%s (%s, x)", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_INDIRECT_Y:
|
||||
fprintf(file, "%s (%s), y", AsmInstructionNames[mType], AddrName(buffer));
|
||||
break;
|
||||
case ASMIM_RELATIVE:
|
||||
fprintf(file, "%s %d", AsmInstructionNames[mType], mAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeCodeInstruction::IsUsedResultInstructions(NumberSet& requiredTemps)
|
||||
{
|
||||
|
@ -4951,6 +5013,28 @@ void NativeCodeInstruction::FilterRegUsage(NumberSet& requiredTemps, NumberSet&
|
|||
}
|
||||
}
|
||||
|
||||
uint32 NativeCodeInstruction::CodeHash(void) const
|
||||
{
|
||||
uint32 hash = mType + 0x20 * mMode + 0x100 * mAddress;
|
||||
if (mLinkerObject)
|
||||
hash += mLinkerObject->mID * 0x1000;
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool NativeCodeInstruction::CodeSame(const NativeCodeInstruction& ins)
|
||||
{
|
||||
if (mType != ins.mType || mMode != ins.mMode)
|
||||
return false;
|
||||
if (mMode != ASMIM_IMPLIED && (mAddress != ins.mAddress || mLinkerObject != ins.mLinkerObject))
|
||||
return false;
|
||||
if (mMode == ASMIM_IMMEDIATE_ADDRESS && (mFlags & (NCIF_LOWER | NCIF_UPPER)) != (ins.mFlags & (NCIF_LOWER | NCIF_UPPER)))
|
||||
return false;
|
||||
if ((mFlags & NCIF_USE_ZP_32_X) && mParam != ins.mParam)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NativeCodeInstruction::CopyMode(const NativeCodeInstruction& ins)
|
||||
{
|
||||
mMode = ins.mMode;
|
||||
|
@ -5019,7 +5103,7 @@ void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (mType == ASMIT_JSR && (mFlags & NCIF_USE_ZP_32_X))
|
||||
if ((mType == ASMIT_JSR || mType == ASMIT_JMP) && (mFlags & NCIF_USE_ZP_32_X))
|
||||
{
|
||||
block->PutOpcode(AsmInsOpcodes[ASMIT_LDX][ASMIM_IMMEDIATE]);
|
||||
block->PutByte(mParam);
|
||||
|
@ -7818,9 +7902,9 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc,
|
|||
|
||||
if (sstride > 1 || dstride > 1)
|
||||
msize = 32;
|
||||
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
|
||||
else if (nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
|
||||
msize = 8;
|
||||
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
|
||||
else if (nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
|
||||
msize = 2;
|
||||
#if 1
|
||||
if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mTemp < 0)
|
||||
|
@ -8314,9 +8398,9 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::FillValue(InterCodeProcedure* proc,
|
|||
|
||||
if (dstride > 1)
|
||||
msize = 32;
|
||||
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
|
||||
else if (nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
|
||||
msize = 8;
|
||||
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
|
||||
else if (nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
|
||||
msize = 2;
|
||||
#if 1
|
||||
if (ins->mSrc[1].mTemp < 0)
|
||||
|
@ -10604,8 +10688,8 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
|
|||
int lcost = 8 + 2 * (nbytes - 1);
|
||||
int ucost = shift * (1 + 2 * nbytes);
|
||||
|
||||
if ((nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) && lcost < ucost ||
|
||||
!(nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) && 2 * lcost < ucost)
|
||||
if ((nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) && lcost < ucost ||
|
||||
!(nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) && 2 * lcost < ucost)
|
||||
{
|
||||
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
|
||||
this->Close(ins, lblock, nullptr, ASMIT_JMP);
|
||||
|
@ -14015,6 +14099,35 @@ void NativeCodeBasicBlock::CallFunction(InterCodeProcedure* proc, NativeCodeProc
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void NativeCodeBasicBlock::Disassemble(FILE* file)
|
||||
{
|
||||
if (!mVisited)
|
||||
{
|
||||
mVisited = true;
|
||||
|
||||
fprintf(file, "L%d:\n", mIndex);
|
||||
for (int i = 0; i < mIns.Size(); i++)
|
||||
{
|
||||
fprintf(file, "%03d ", i);
|
||||
mIns[i].Disassemble(file);
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
fprintf(file, "%03d %s", mIns.Size(), AsmInstructionNames[mBranch]);
|
||||
if (mTrueJump)
|
||||
{
|
||||
fprintf(file, " L%d", mTrueJump->mIndex);
|
||||
if (mFalseJump)
|
||||
fprintf(file, ", L%d", mFalseJump->mIndex);
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
|
||||
if (mTrueJump) mTrueJump->Disassemble(file);
|
||||
if (mFalseJump) mFalseJump->Disassemble(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NativeCodeInstruction NativeCodeBasicBlock::DecodeNative(const InterInstruction* ins, LinkerObject* lobj, int& offset) const
|
||||
{
|
||||
uint8 op = lobj->mData[offset++];
|
||||
|
@ -41554,7 +41667,7 @@ static bool CheckBlockCopySequence(const ExpandingArray<NativeCodeInstruction>&
|
|||
|
||||
bool NativeCodeBasicBlock::BlockSizeCopyReduction(NativeCodeProcedure* proc, int& si, int& di)
|
||||
{
|
||||
if ((proc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
|
||||
if ((proc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
|
||||
{
|
||||
if (si + 1 < mIns.Size() &&
|
||||
mIns[si + 0].mType == ASMIT_LDA && (mIns[si + 0].mMode == ASMIM_ZERO_PAGE || mIns[si + 0].mMode == ASMIM_ABSOLUTE) &&
|
||||
|
@ -51378,6 +51491,32 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass)
|
|||
return false;
|
||||
}
|
||||
|
||||
void NativeCodeBasicBlock::AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree * tree)
|
||||
{
|
||||
if (!mVisited)
|
||||
{
|
||||
mVisited = true;
|
||||
|
||||
if (!mSuffixString)
|
||||
mSuffixString = new int[mIns.Size() + 100];
|
||||
|
||||
bool rel = false;
|
||||
for (int i = 0; i < mIns.Size(); i++)
|
||||
{
|
||||
if (mIns[i].mMode == ASMIM_RELATIVE)
|
||||
rel = true;
|
||||
mSuffixString[i] = mapper.MapInstruction(mIns[i], mProc->mLinkerObject->mSection);
|
||||
}
|
||||
mSuffixString[mIns.Size()] = mapper.MapBasicBlock(this);
|
||||
|
||||
if (!rel)
|
||||
tree->AddString(mSuffixString);
|
||||
|
||||
if (mTrueJump) mTrueJump->AddToSuffixTree(mapper, tree);
|
||||
if (mFalseJump) mFalseJump->AddToSuffixTree(mapper, tree);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeCodeBasicBlock::CheckVisited(void)
|
||||
{
|
||||
#if _DEBUG
|
||||
|
@ -52063,6 +52202,7 @@ NativeCodeBasicBlock::NativeCodeBasicBlock(NativeCodeProcedure* proc)
|
|||
mDominator = nullptr;
|
||||
mLoopHeadBlock = nullptr;
|
||||
mLoopTailBlock = nullptr;
|
||||
mSuffixString = nullptr;
|
||||
mEntryRegA = false;
|
||||
mEntryRegX = false;
|
||||
mEntryRegY = false;
|
||||
|
@ -52089,6 +52229,22 @@ NativeCodeProcedure::~NativeCodeProcedure(void)
|
|||
|
||||
}
|
||||
|
||||
|
||||
void NativeCodeProcedure::Disassemble(FILE* file)
|
||||
{
|
||||
fprintf(file, "--------------------------------------------------------------------\n");
|
||||
fprintf(file, "%s: %s:%d\n", mIdent->mString, mLocation.mFileName, mLocation.mLine);
|
||||
|
||||
ResetVisited();
|
||||
mEntryBlock->Disassemble(file);
|
||||
}
|
||||
|
||||
void NativeCodeProcedure::AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree* tree)
|
||||
{
|
||||
ResetVisited();
|
||||
mEntryBlock->AddToSuffixTree(mapper, tree);
|
||||
}
|
||||
|
||||
void NativeCodeProcedure::CompressTemporaries(bool singles)
|
||||
{
|
||||
if (mInterProc->mTempSize > 0)
|
||||
|
@ -52286,9 +52442,14 @@ void NativeCodeProcedure::LoadTempsFromStack(int tempSave)
|
|||
void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
|
||||
{
|
||||
mInterProc = proc;
|
||||
mLinkerObject = proc->mLinkerObject;
|
||||
mIdent = proc->mIdent;
|
||||
mLocation = proc->mLocation;
|
||||
mCompilerOptions = proc->mCompilerOptions;
|
||||
|
||||
mInterProc->mLinkerObject->mNativeProc = this;
|
||||
|
||||
CheckFunc = !strcmp(mInterProc->mIdent->mString, "rirq_sort");
|
||||
CheckFunc = !strcmp(mIdent->mString, "rirq_sort");
|
||||
|
||||
int nblocks = proc->mBlocks.Size();
|
||||
tblocks = new NativeCodeBasicBlock * [nblocks];
|
||||
|
@ -52417,14 +52578,14 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
|
|||
if (mInterProc->mInterrupt)
|
||||
{
|
||||
if (!mNoFrame || mStackExpand > 0 || commonFrameSize > 0)
|
||||
mGenerator->mErrors->Error(mInterProc->mLocation, ERRR_INTERRUPT_TO_COMPLEX, "Function to complex for interrupt");
|
||||
mGenerator->mErrors->Error(mLocation, ERRR_INTERRUPT_TO_COMPLEX, "Function to complex for interrupt");
|
||||
|
||||
ZeroPageSet zpLocal, zpGlobal;
|
||||
ResetVisited();
|
||||
if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, true))
|
||||
zpLocal |= zpGlobal;
|
||||
else
|
||||
mGenerator->mErrors->Error(mInterProc->mLocation, ERRR_INTERRUPT_TO_COMPLEX, "No recursive functions in interrupt");
|
||||
mGenerator->mErrors->Error(mLocation, ERRR_INTERRUPT_TO_COMPLEX, "No recursive functions in interrupt");
|
||||
|
||||
if (proc->mHardwareInterrupt)
|
||||
{
|
||||
|
@ -52830,7 +52991,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
|
|||
}
|
||||
}
|
||||
|
||||
if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
|
||||
if (mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
|
||||
{
|
||||
ResetVisited();
|
||||
mEntryBlock->RegisterFunctionCalls();
|
||||
|
@ -52839,9 +53000,9 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
|
|||
|
||||
void NativeCodeProcedure::Assemble(void)
|
||||
{
|
||||
CheckFunc = !strcmp(mInterProc->mIdent->mString, "fighter_ai");
|
||||
CheckFunc = !strcmp(mIdent->mString, "fighter_ai");
|
||||
|
||||
if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
|
||||
if (mCompilerOptions & COPT_OPTIMIZE_MERGE_CALLS)
|
||||
{
|
||||
ResetVisited();
|
||||
mEntryBlock->MergeFunctionCalls();
|
||||
|
@ -52891,7 +53052,7 @@ void NativeCodeProcedure::Assemble(void)
|
|||
for (int i = 0; i < placement.Size(); i++)
|
||||
placement[i]->mAsmFromJump = -1;
|
||||
|
||||
uint8* data = mInterProc->mLinkerObject->AddSpace(total);
|
||||
uint8* data = mLinkerObject->AddSpace(total);
|
||||
|
||||
for (int i = 0; i < placement.Size(); i++)
|
||||
{
|
||||
|
@ -52905,7 +53066,7 @@ void NativeCodeProcedure::Assemble(void)
|
|||
range.mIdent = Ident::Unique(buffer);
|
||||
range.mOffset = placement[i]->mOffset;
|
||||
range.mSize = placement[i]->mSize;
|
||||
mInterProc->mLinkerObject->mRanges.Push(range);
|
||||
mLinkerObject->mRanges.Push(range);
|
||||
placement[i]->CopyCode(this, data);
|
||||
}
|
||||
|
||||
|
@ -52913,10 +53074,10 @@ void NativeCodeProcedure::Assemble(void)
|
|||
for (int i = 0; i < mRelocations.Size(); i++)
|
||||
{
|
||||
LinkerReference& rl(mRelocations[i]);
|
||||
rl.mObject = mInterProc->mLinkerObject;
|
||||
rl.mObject = mLinkerObject;
|
||||
if (!rl.mRefObject)
|
||||
rl.mRefObject = mInterProc->mLinkerObject;
|
||||
mInterProc->mLinkerObject->AddReference(rl);
|
||||
rl.mRefObject = mLinkerObject;
|
||||
mLinkerObject->AddReference(rl);
|
||||
}
|
||||
|
||||
if (mGenerator->mCompilerOptions & (COPT_DEBUGINFO | COPT_PROFILEINFO))
|
||||
|
@ -52937,7 +53098,7 @@ void NativeCodeProcedure::Assemble(void)
|
|||
}
|
||||
mCodeLocations.SetSize(j + 1);
|
||||
|
||||
mInterProc->mLinkerObject->AddLocations(mCodeLocations);
|
||||
mLinkerObject->AddLocations(mCodeLocations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53947,7 +54108,7 @@ void NativeCodeProcedure::Optimize(void)
|
|||
#endif
|
||||
|
||||
#if 1
|
||||
if (step == 10 && (mInterProc->mCompilerOptions & COPT_OPTIMIZE_BASIC))
|
||||
if (step == 10 && (mCompilerOptions & COPT_OPTIMIZE_BASIC))
|
||||
{
|
||||
ResetVisited();
|
||||
mEntryBlock->MarkLocalUsedLinkerObjects();
|
||||
|
@ -54051,7 +54212,7 @@ void NativeCodeProcedure::Optimize(void)
|
|||
|
||||
if (step == 16)
|
||||
{
|
||||
if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_INLINE)
|
||||
if (mCompilerOptions & COPT_OPTIMIZE_INLINE)
|
||||
{
|
||||
ResetVisited();
|
||||
if (mEntryBlock->SimpleInlineCalls())
|
||||
|
@ -54061,7 +54222,7 @@ void NativeCodeProcedure::Optimize(void)
|
|||
|
||||
if (step == 17)
|
||||
{
|
||||
if (!(mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
|
||||
if (!(mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
|
||||
{
|
||||
ResetVisited();
|
||||
if (mEntryBlock->Expand16BitLoopBranch())
|
||||
|
@ -54100,7 +54261,7 @@ void NativeCodeProcedure::Optimize(void)
|
|||
if (cnt > 200)
|
||||
{
|
||||
changed = false;
|
||||
mGenerator->mErrors->Error(mInterProc->mLocation, EWARN_OPTIMIZER_LOCKED, "Optimizer locked in infinite loop", mInterProc->mIdent);
|
||||
mGenerator->mErrors->Error(mLocation, EWARN_OPTIMIZER_LOCKED, "Optimizer locked in infinite loop", mIdent);
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
@ -55316,6 +55477,144 @@ bool NativeCodeGenerator::MergeFunctionCall(NativeCodeBasicBlock* block, int at)
|
|||
return false;
|
||||
}
|
||||
|
||||
void NativeCodeGenerator::OutlineFunctions(void)
|
||||
{
|
||||
NativeCodeMapper mapper;
|
||||
|
||||
bool progress;
|
||||
|
||||
int k = 0;
|
||||
|
||||
int numOutlines = 0;
|
||||
do {
|
||||
progress = false;
|
||||
|
||||
SuffixTree* tree = new SuffixTree(nullptr, 0, nullptr);
|
||||
|
||||
for (int i = 0; i < mProcedures.Size(); i++)
|
||||
{
|
||||
if (mProcedures[i]->mCompilerOptions & COPT_OPTIMIZE_OUTLINE)
|
||||
mProcedures[i]->AddToSuffixTree(mapper, tree);
|
||||
}
|
||||
tree->AddParents(nullptr);
|
||||
|
||||
#if 0
|
||||
FILE* f;
|
||||
|
||||
if (!fopen_s(&f, "r:\\suffix.txt", "w"))
|
||||
{
|
||||
tree->Print(f, mapper, 0);
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
SuffixTree* ltree = nullptr;
|
||||
int lsize = 6;
|
||||
|
||||
tree->LongestMatch(mapper, 0, 0, lsize, ltree);
|
||||
if (lsize > 6)
|
||||
{
|
||||
SuffixTree* leaf = ltree;
|
||||
while (leaf->mFirst)
|
||||
leaf = leaf->mFirst;
|
||||
NativeCodeBasicBlock* block = mapper.mBlocks[-(1 + leaf->mSeg[leaf->mSize - 1])];
|
||||
|
||||
NativeCodeProcedure* nproc = new NativeCodeProcedure(this);
|
||||
|
||||
NativeCodeBasicBlock* nblock = nproc->AllocateBlock();
|
||||
|
||||
// printf("Suffix %s,%d:%s\n", block->mProc->mIdent->mString, block->mIndex, block->mProc->mLinkerObject->mSection->mIdent->mString);
|
||||
|
||||
nproc->mLocation = block->mIns[0].mIns ? block->mIns[0].mIns->mLocation : block->mProc->mLocation;
|
||||
nproc->mCompilerOptions = block->mProc->mCompilerOptions;
|
||||
nproc->mIdent = Ident::Unique("$outline", numOutlines);
|
||||
nproc->mLinkerObject = mLinker->AddObject(nproc->mLocation, nproc->mIdent, block->mProc->mLinkerObject->mSection, LOT_NATIVE_CODE);
|
||||
nproc->mEntryBlock = nblock;
|
||||
|
||||
bool dojmp = false;
|
||||
|
||||
ltree->ParentCollect(mapper, nblock);
|
||||
if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JSR)
|
||||
nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JMP;
|
||||
else if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_RTS || nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JMP)
|
||||
dojmp = true;
|
||||
else
|
||||
nblock->mIns.Push(NativeCodeInstruction(nblock->mIns[nblock->mIns.Size() - 1].mIns, ASMIT_RTS));
|
||||
|
||||
ExpandingArray<SuffixSegment> segs;
|
||||
ltree->ReplaceCalls(mapper, segs);
|
||||
|
||||
segs.Sort([](const SuffixSegment& l, const SuffixSegment& r)->bool {
|
||||
return l.mBlock == r.mBlock ? l.mStart > r.mStart : ptrdiff_t(l.mBlock) < ptrdiff_t(r.mBlock);
|
||||
});
|
||||
|
||||
// Check for complete loop block replacement
|
||||
int k = 0;
|
||||
while (k < segs.Size() && segs[k].mStart == 0 && segs[k].mEnd == segs[k].mBlock->mIns.Size() && segs[k].mBlock->mTrueJump == segs[k].mBlock && segs[k].mBlock->mBranch == segs[0].mBlock->mBranch)
|
||||
k++;
|
||||
|
||||
if (k == segs.Size())
|
||||
{
|
||||
NativeCodeBasicBlock* eblock = nproc->AllocateBlock();
|
||||
|
||||
nblock->mTrueJump = nblock;
|
||||
nblock->mFalseJump = eblock;
|
||||
nblock->mBranch = segs[0].mBlock->mBranch;
|
||||
|
||||
for (int i = 0; i < segs.Size(); i++)
|
||||
{
|
||||
SuffixSegment& s(segs[i]);
|
||||
segs[i].mBlock->mTrueJump = segs[i].mBlock->mFalseJump;
|
||||
segs[i].mBlock->mFalseJump = nullptr;
|
||||
segs[i].mBlock->mBranch = ASMIT_JMP;
|
||||
segs[i].mBlock->mNumEntries = 1;
|
||||
}
|
||||
|
||||
eblock->mIns.Push(NativeCodeInstruction(nblock->mIns[nblock->mIns.Size() - 1].mIns, ASMIT_RTS));
|
||||
if (nblock->mIns[nblock->mIns.Size() - 1].mType == ASMIT_JMP)
|
||||
nblock->mIns[nblock->mIns.Size() - 1].mType = ASMIT_JSR;
|
||||
else
|
||||
nblock->mIns.Remove(nblock->mIns.Size() - 1);
|
||||
}
|
||||
|
||||
NativeCodeBasicBlock* pblock = nullptr;
|
||||
int pstart;
|
||||
for (int i = 0; i < segs.Size(); i++)
|
||||
{
|
||||
SuffixSegment& s(segs[i]);
|
||||
// printf("Seg %s,%d\n", segs[i].mBlock->mProc->mIdent->mString, segs[i].mBlock->mIndex);
|
||||
if (s.mBlock != pblock || s.mEnd <= pstart)
|
||||
{
|
||||
s.mBlock->mIns.Remove(s.mStart + 1, s.mEnd - s.mStart - 1);
|
||||
s.mBlock->mIns[s.mStart] = NativeCodeInstruction(s.mBlock->mIns[s.mStart].mIns, dojmp ? ASMIT_JMP : ASMIT_JSR, ASMIM_ABSOLUTE, 0, nproc->mLinkerObject);
|
||||
pblock = s.mBlock;
|
||||
pstart = s.mStart;
|
||||
}
|
||||
}
|
||||
|
||||
mProcedures.Push(nproc);
|
||||
|
||||
numOutlines++;
|
||||
progress = true;
|
||||
}
|
||||
#if 0
|
||||
if (!fopen_s(&f, "r:\\lsuffix.txt", "w"))
|
||||
{
|
||||
ltree->ParentPrint(f, mapper);
|
||||
fclose(f);
|
||||
}
|
||||
#endif
|
||||
delete tree;
|
||||
mapper.Reset();
|
||||
|
||||
#if 0
|
||||
k++;
|
||||
if (k == 2)
|
||||
break;
|
||||
#endif
|
||||
} while (progress);
|
||||
}
|
||||
|
||||
void NativeCodeGenerator::BuildFunctionProxies(void)
|
||||
{
|
||||
FunctionCall* cp = mFunctionCalls;
|
||||
|
|
|
@ -9,6 +9,9 @@ class NativeCodeBasicBlock;
|
|||
class NativeCodeGenerator;
|
||||
class NativeCodeInstruction;
|
||||
|
||||
class NativeCodeMapper;
|
||||
class SuffixTree;
|
||||
|
||||
enum NativeRegisterDataMode
|
||||
{
|
||||
NRDM_UNKNOWN,
|
||||
|
@ -154,6 +157,9 @@ public:
|
|||
LinkerObject * mLinkerObject;
|
||||
const InterInstruction * mIns;
|
||||
|
||||
void Disassemble(FILE* file) const;
|
||||
void DisassembleAddress(FILE* file) const;
|
||||
|
||||
void CopyMode(const NativeCodeInstruction& ins);
|
||||
|
||||
void Assemble(NativeCodeBasicBlock* block);
|
||||
|
@ -216,6 +222,12 @@ public:
|
|||
void BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets);
|
||||
|
||||
uint32 NeedsLive(void) const;
|
||||
|
||||
uint32 CodeHash(void) const;
|
||||
bool CodeSame(const NativeCodeInstruction& ins);
|
||||
|
||||
protected:
|
||||
const char* AddrName(char* buffer) const;
|
||||
};
|
||||
|
||||
struct NativeCodeLoadStorePair
|
||||
|
@ -264,6 +276,8 @@ public:
|
|||
|
||||
NativeCodeInstruction mALSIns, mXLSIns, mYLSIns;
|
||||
|
||||
void Disassemble(FILE* file);
|
||||
|
||||
NativeCodeInstruction DecodeNative(const InterInstruction* ins, LinkerObject * lobj, int& offset) const;
|
||||
|
||||
int PutBranch(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, AsmInsType code, int from, int to);
|
||||
|
@ -817,6 +831,9 @@ public:
|
|||
void CheckBlocks(bool sequence = false);
|
||||
void CheckAsmCode(void);
|
||||
void CheckVisited(void);
|
||||
|
||||
int* mSuffixString;
|
||||
void AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree * tree);
|
||||
};
|
||||
|
||||
class NativeCodeProcedure
|
||||
|
@ -831,6 +848,10 @@ class NativeCodeProcedure
|
|||
NativeCodeGenerator* mGenerator;
|
||||
|
||||
InterCodeProcedure* mInterProc;
|
||||
LinkerObject* mLinkerObject;
|
||||
const Ident* mIdent;
|
||||
Location mLocation;
|
||||
uint64 mCompilerOptions;
|
||||
|
||||
int mProgStart, mProgSize, mIndex, mFrameOffset, mStackExpand;
|
||||
int mFastCallBase;
|
||||
|
@ -842,10 +863,14 @@ class NativeCodeProcedure
|
|||
ExpandingArray<CodeLocation> mCodeLocations;
|
||||
|
||||
|
||||
void Disassemble(FILE* file);
|
||||
|
||||
void Compile(InterCodeProcedure* proc);
|
||||
void Optimize(void);
|
||||
void Assemble(void);
|
||||
|
||||
void AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree* tree);
|
||||
|
||||
NativeCodeBasicBlock* CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* block);
|
||||
NativeCodeBasicBlock* AllocateBlock(void);
|
||||
|
||||
|
@ -911,6 +936,8 @@ public:
|
|||
Linker* mLinker;
|
||||
LinkerSection* mRuntimeSection;
|
||||
|
||||
ExpandingArray<NativeCodeProcedure*> mProcedures;
|
||||
|
||||
ExpandingArray<Runtime> mRuntime;
|
||||
ExpandingArray<MulTable> mMulTables;
|
||||
ExpandingArray<FloatTable> mFloatTables;
|
||||
|
@ -929,6 +956,8 @@ public:
|
|||
|
||||
FunctionCall* mFunctionCalls;
|
||||
|
||||
void OutlineFunctions(void);
|
||||
|
||||
void RegisterFunctionCall(NativeCodeBasicBlock* block, int at);
|
||||
void BuildFunctionProxies(void);
|
||||
bool MergeFunctionCall(NativeCodeBasicBlock* block, int at);
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
#include "NativeCodeOutliner.h"
|
||||
|
||||
|
||||
NativeCodeMapper::NativeCodeMapper(void)
|
||||
{
|
||||
for (int i = 0; i < HashSize; i++)
|
||||
mHash[i] = nullptr;
|
||||
}
|
||||
|
||||
NativeCodeMapper::~NativeCodeMapper(void)
|
||||
{
|
||||
for (int i = 0; i < HashSize; i++)
|
||||
{
|
||||
InsNode* n = mHash[i];
|
||||
while (n)
|
||||
{
|
||||
InsNode* m = n;
|
||||
n = n->mNext;
|
||||
delete m;
|
||||
}
|
||||
mHash[i] = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NativeCodeMapper::Reset(void)
|
||||
{
|
||||
mBlocks.SetSize(0);
|
||||
}
|
||||
|
||||
int NativeCodeMapper::MapBasicBlock(NativeCodeBasicBlock* block)
|
||||
{
|
||||
mBlocks.Push(block);
|
||||
return -mBlocks.Size();
|
||||
}
|
||||
|
||||
int NativeCodeMapper::MapInstruction(const NativeCodeInstruction& ins, LinkerSection* ls)
|
||||
{
|
||||
int hash = ins.CodeHash() % HashSize;
|
||||
InsNode* n = mHash[hash];
|
||||
while (n)
|
||||
{
|
||||
if (mIns[n->mIndex].CodeSame(ins) && n->mSection == ls)
|
||||
return n->mIndex;
|
||||
n = n->mNext;
|
||||
}
|
||||
n = new InsNode();
|
||||
n->mIndex = mIns.Size();
|
||||
n->mSection = ls;
|
||||
mIns.Push(ins);
|
||||
n->mNext = mHash[hash];
|
||||
mHash[hash] = n;
|
||||
return n->mIndex;
|
||||
}
|
||||
|
||||
SuffixTree::SuffixTree(const int* str, int s, SuffixTree* n)
|
||||
{
|
||||
mSeg = str;
|
||||
mSize = s;
|
||||
mNext = n;
|
||||
mParent = nullptr;
|
||||
mFirst = nullptr;
|
||||
}
|
||||
|
||||
void SuffixTree::AddParents(SuffixTree* parent)
|
||||
{
|
||||
mParent = parent;
|
||||
SuffixTree* n = mFirst;
|
||||
while (n)
|
||||
{
|
||||
n->AddParents(this);
|
||||
n = n->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
void SuffixTree::AddSuffix(const int* str, int s)
|
||||
{
|
||||
SuffixTree* c = mFirst;
|
||||
while (c && c->mSeg[0] != str[0])
|
||||
c = c->mNext;
|
||||
|
||||
if (c)
|
||||
{
|
||||
int k = 1;
|
||||
while (k < c->mSize && str[k] == c->mSeg[k])
|
||||
k++;
|
||||
if (k == c->mSize)
|
||||
c->AddSuffix(str + k, s - k);
|
||||
else
|
||||
{
|
||||
SuffixTree* t = c->mFirst;
|
||||
c->mFirst = new SuffixTree(c->mSeg + k, c->mSize - k, nullptr);
|
||||
c->mFirst->mFirst = t;
|
||||
c->mFirst = new SuffixTree(str + k, s - k, c->mFirst);
|
||||
c->mSize = k;
|
||||
}
|
||||
}
|
||||
else
|
||||
mFirst = new SuffixTree(str, s, mFirst);
|
||||
}
|
||||
|
||||
void SuffixTree::AddString(const int* str)
|
||||
{
|
||||
int s = 0;
|
||||
while(str[s] >= 0)
|
||||
s++;
|
||||
s++;
|
||||
|
||||
int i = 0;
|
||||
while (str[i] >= 0)
|
||||
{
|
||||
AddSuffix(str + i, s - i);
|
||||
i++;
|
||||
}
|
||||
AddSuffix(str + i, 1);
|
||||
}
|
||||
|
||||
void SuffixTree::CollectSuffix(NativeCodeMapper& map, int offset, ExpandingArray<SuffixSegment>& segs)
|
||||
{
|
||||
offset += mSize;
|
||||
if (mFirst)
|
||||
{
|
||||
SuffixTree* t = mFirst;
|
||||
while (t)
|
||||
{
|
||||
t->CollectSuffix(map, offset, segs);
|
||||
t = t->mNext;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeCodeBasicBlock* block = map.mBlocks[-(mSeg[mSize - 1] + 1)];
|
||||
|
||||
SuffixSegment seg;
|
||||
seg.mBlock = block;
|
||||
seg.mStart = offset;
|
||||
seg.mEnd = block->mIns.Size() + 1;
|
||||
segs.Push(seg);
|
||||
}
|
||||
}
|
||||
|
||||
int SuffixTree::LongestMatch(NativeCodeMapper& map, int size, int isize, int& msize, SuffixTree*& mtree)
|
||||
{
|
||||
if (mFirst)
|
||||
{
|
||||
isize += mSize;
|
||||
|
||||
for (int i = 0; i < mSize; i++)
|
||||
{
|
||||
if (mSeg[i] >= 0)
|
||||
size += AsmInsModeSize[map.mIns[mSeg[i]].mMode];
|
||||
}
|
||||
|
||||
assert(size < 10000);
|
||||
|
||||
int cnt = 0;
|
||||
SuffixTree* t = mFirst;
|
||||
while (t)
|
||||
{
|
||||
cnt += t->LongestMatch(map, size, isize, msize, mtree);
|
||||
t = t->mNext;
|
||||
}
|
||||
|
||||
if (size >= 6 && (size - 3) * (cnt - 1) > msize)
|
||||
{
|
||||
// Second run to cross check for overlaps
|
||||
ExpandingArray<SuffixSegment> segs;
|
||||
SuffixTree* t = mFirst;
|
||||
while (t)
|
||||
{
|
||||
t->CollectSuffix(map, 0, segs);
|
||||
t = t->mNext;
|
||||
}
|
||||
segs.Sort([](const SuffixSegment& l, const SuffixSegment& r)->bool {
|
||||
return l.mBlock == r.mBlock ? l.mStart < r.mStart : ptrdiff_t(l.mBlock) < ptrdiff_t(r.mBlock);
|
||||
});
|
||||
|
||||
for (int i = 0; i + 1 < segs.Size(); i++)
|
||||
{
|
||||
if (segs[i].mBlock == segs[i + 1].mBlock && segs[i].mStart + isize > segs[i + 1].mStart)
|
||||
cnt--;
|
||||
}
|
||||
|
||||
if (cnt > 1 && (size - 3) * (cnt - 1) > msize)
|
||||
{
|
||||
msize = (size - 3) * (cnt - 1);
|
||||
mtree = this;
|
||||
}
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SuffixTree::Print(FILE * file, NativeCodeMapper& map, int depth)
|
||||
{
|
||||
for (int i = 0; i < depth; i++)
|
||||
fprintf(file, ".");
|
||||
|
||||
for (int i = 0; i < mSize; i++)
|
||||
{
|
||||
fprintf(file, "[");
|
||||
|
||||
if (mSeg[i] >= 0)
|
||||
map.mIns[mSeg[i]].Disassemble(file);
|
||||
else
|
||||
{
|
||||
NativeCodeBasicBlock* block = map.mBlocks[- (mSeg[i] + 1)];
|
||||
fprintf(file, "%s,%d", block->mProc->mInterProc->mIdent->mString, block->mIndex);
|
||||
}
|
||||
fprintf(file, "]");
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
|
||||
SuffixTree* n = mFirst;
|
||||
while (n)
|
||||
{
|
||||
n->Print(file, map, depth + 1);
|
||||
n = n->mNext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SuffixTree::ParentPrint(FILE* file, NativeCodeMapper& map)
|
||||
{
|
||||
if (mParent)
|
||||
mParent->ParentPrint(file, map);
|
||||
for (int i = 0; i < mSize; i++)
|
||||
{
|
||||
if (mSeg[i] >= 0)
|
||||
map.mIns[mSeg[i]].Disassemble(file);
|
||||
else
|
||||
{
|
||||
NativeCodeBasicBlock* block = map.mBlocks[-(mSeg[i] + 1)];
|
||||
fprintf(file, "%s,%d", block->mProc->mInterProc->mIdent->mString, block->mIndex);
|
||||
}
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
int SuffixTree::ParentCodeSize(NativeCodeMapper& map) const
|
||||
{
|
||||
int size = 0;
|
||||
for (int i = 0; i < mSize; i++)
|
||||
{
|
||||
if (mSeg[i] >= 0)
|
||||
size += AsmInsModeSize[map.mIns[mSeg[i]].mMode];
|
||||
}
|
||||
|
||||
if (mParent)
|
||||
size += mParent->ParentCodeSize(map);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void SuffixTree::ParentCollect(NativeCodeMapper& map, NativeCodeBasicBlock* block)
|
||||
{
|
||||
if (mParent)
|
||||
mParent->ParentCollect(map, block);
|
||||
for (int i = 0; i < mSize; i++)
|
||||
block->mIns.Push(map.mIns[mSeg[i]]);
|
||||
}
|
||||
|
||||
void SuffixTree::ReplaceCalls(NativeCodeMapper& map, ExpandingArray<SuffixSegment>& segs)
|
||||
{
|
||||
SuffixTree* n = mFirst;
|
||||
while (n)
|
||||
{
|
||||
n->ChildReplaceCalls(map, this, 0, segs);
|
||||
n = n->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
void SuffixTree::ChildReplaceCalls(NativeCodeMapper& map, SuffixTree* tree, int offset, ExpandingArray<SuffixSegment>& segs)
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
{
|
||||
if (mSeg[i] >= 0)
|
||||
offset ++;
|
||||
}
|
||||
|
||||
if (mFirst)
|
||||
{
|
||||
SuffixTree* n = mFirst;
|
||||
while (n)
|
||||
{
|
||||
n->ChildReplaceCalls(map, tree, offset, segs);
|
||||
n = n->mNext;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NativeCodeBasicBlock* block = map.mBlocks[-(mSeg[mSize - 1] + 1)];
|
||||
tree->ParentReplaceCalls(map, block, offset, 0, segs);
|
||||
}
|
||||
}
|
||||
|
||||
void SuffixTree::ParentReplaceCalls(NativeCodeMapper& map, NativeCodeBasicBlock* block, int offset, int size, ExpandingArray<SuffixSegment>& segs)
|
||||
{
|
||||
for (int i = 0; i < mSize; i++)
|
||||
{
|
||||
if (mSeg[i] >= 0)
|
||||
size ++;
|
||||
}
|
||||
if (mParent)
|
||||
mParent->ParentReplaceCalls(map, block, offset, size, segs);
|
||||
else
|
||||
{
|
||||
int at = block->mIns.Size() - offset - size;
|
||||
|
||||
SuffixSegment seg;
|
||||
seg.mBlock = block;
|
||||
seg.mStart = at;
|
||||
seg.mEnd = at + size;
|
||||
segs.Push(seg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include "NativeCodeGenerator.h"
|
||||
#include "Array.h"
|
||||
|
||||
class NativeCodeMapper
|
||||
{
|
||||
public:
|
||||
NativeCodeMapper(void);
|
||||
~NativeCodeMapper(void);
|
||||
|
||||
void Reset(void);
|
||||
|
||||
int MapInstruction(const NativeCodeInstruction& ins, LinkerSection * ls);
|
||||
int MapBasicBlock(NativeCodeBasicBlock* block);
|
||||
|
||||
ExpandingArray<NativeCodeInstruction> mIns;
|
||||
ExpandingArray<NativeCodeBasicBlock*> mBlocks;
|
||||
protected:
|
||||
static const int HashSize = 256;
|
||||
|
||||
struct InsNode
|
||||
{
|
||||
int mIndex;
|
||||
LinkerSection * mSection;
|
||||
InsNode* mNext;
|
||||
};
|
||||
|
||||
InsNode * mHash[HashSize];
|
||||
};
|
||||
|
||||
struct SuffixSegment
|
||||
{
|
||||
NativeCodeBasicBlock * mBlock;
|
||||
int mStart, mEnd;
|
||||
};
|
||||
|
||||
class SuffixTree
|
||||
{
|
||||
public:
|
||||
const int * mSeg;
|
||||
int mSize;
|
||||
|
||||
SuffixTree* mNext, * mParent, * mFirst;
|
||||
|
||||
SuffixTree(const int* str, int s, SuffixTree* n);
|
||||
void AddParents(SuffixTree* parent);
|
||||
|
||||
void AddSuffix(const int* str, int s);
|
||||
void AddString(const int* str);
|
||||
|
||||
void Print(FILE* file, NativeCodeMapper & map, int depth);
|
||||
void ParentPrint(FILE* file, NativeCodeMapper& map);
|
||||
int LongestMatch(NativeCodeMapper& map, int size, int isize, int & msize, SuffixTree *& mtree);
|
||||
void CollectSuffix(NativeCodeMapper& map, int offset, ExpandingArray<SuffixSegment>& segs);
|
||||
int ParentCodeSize(NativeCodeMapper& map) const;
|
||||
void ParentCollect(NativeCodeMapper& map, NativeCodeBasicBlock * block);
|
||||
void ReplaceCalls(NativeCodeMapper& map, ExpandingArray<SuffixSegment> & segs);
|
||||
void ChildReplaceCalls(NativeCodeMapper& map, SuffixTree * tree, int offset, ExpandingArray<SuffixSegment>& segs);
|
||||
void ParentReplaceCalls(NativeCodeMapper& map, NativeCodeBasicBlock* block, int offset, int size, ExpandingArray<SuffixSegment>& segs);
|
||||
|
||||
};
|
|
@ -13478,6 +13478,10 @@ void Parser::ParsePragma(void)
|
|||
mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS;
|
||||
else if (ConsumeIdentIf("noconstparams"))
|
||||
mCompilerOptions &= ~COPT_OPTIMIZE_CONST_PARAMS;
|
||||
else if (ConsumeIdentIf("outline"))
|
||||
mCompilerOptions |= COPT_OPTIMIZE_OUTLINE;
|
||||
else if (ConsumeIdentIf("nooutline"))
|
||||
mCompilerOptions &= ~COPT_OPTIMIZE_OUTLINE;
|
||||
else
|
||||
mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid option");
|
||||
|
||||
|
|
|
@ -261,6 +261,8 @@ int main2(int argc, const char** argv)
|
|||
compiler->mCompilerOptions |= COPT_OPTIMIZE_GLOBAL;
|
||||
else if (arg[2] == 'm' && !arg[3])
|
||||
compiler->mCompilerOptions |= COPT_OPTIMIZE_MERGE_CALLS;
|
||||
else if (arg[2] == 'o' && !arg[3])
|
||||
compiler->mCompilerOptions |= COPT_OPTIMIZE_OUTLINE;
|
||||
else
|
||||
compiler->mErrors->Error(loc, EERR_COMMAND_LINE, "Invalid command line argument", arg);
|
||||
}
|
||||
|
|
|
@ -189,6 +189,7 @@
|
|||
<ClCompile Include="Linker.cpp" />
|
||||
<ClCompile Include="MachineTypes.cpp" />
|
||||
<ClCompile Include="NativeCodeGenerator.cpp" />
|
||||
<ClCompile Include="NativeCodeOutliner.cpp" />
|
||||
<ClCompile Include="NumberSet.cpp" />
|
||||
<ClCompile Include="oscar64.cpp" />
|
||||
<ClCompile Include="Parser.cpp" />
|
||||
|
@ -218,6 +219,7 @@
|
|||
<ClInclude Include="Linker.h" />
|
||||
<ClInclude Include="MachineTypes.h" />
|
||||
<ClInclude Include="NativeCodeGenerator.h" />
|
||||
<ClInclude Include="NativeCodeOutliner.h" />
|
||||
<ClInclude Include="NumberSet.h" />
|
||||
<ClInclude Include="Parser.h" />
|
||||
<ClInclude Include="Preprocessor.h" />
|
||||
|
|
|
@ -87,6 +87,9 @@
|
|||
<ClCompile Include="Compression.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NativeCodeOutliner.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Array.h">
|
||||
|
@ -170,6 +173,9 @@
|
|||
<ClInclude Include="Compression.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NativeCodeOutliner.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="oscar64.rc">
|
||||
|
|
Loading…
Reference in New Issue