Add experimental native code outliner

This commit is contained in:
drmortalwombat 2025-01-19 17:28:20 +01:00
parent 9f834c4232
commit 95732265f6
14 changed files with 771 additions and 35 deletions

View File

@ -293,7 +293,7 @@ const char* AsmInstructionNames[NUM_ASM_INS_TYPES] = {
"INV", "BYT" "INV", "BYT"
}; };
int AsmInsModeSize[NUM_ASM_INS_MODES] = { int AsmInsModeSize[NUM_ASM_INS_MODES_X] = {
1, 1,
2, 2,
2, 2,
@ -306,6 +306,8 @@ int AsmInsModeSize[NUM_ASM_INS_MODES] = {
2, 2,
2, 2,
2, 2,
0,
2
}; };
void InitAssembler(void) void InitAssembler(void)

View File

@ -31,7 +31,9 @@ enum AsmInsMode
NUM_ASM_INS_MODES, NUM_ASM_INS_MODES,
ASMIM_IMMEDIATE_ADDRESS ASMIM_IMMEDIATE_ADDRESS,
NUM_ASM_INS_MODES_X,
}; };
struct AsmInsData struct AsmInsData
@ -45,6 +47,8 @@ extern AsmInsData DecInsData[256];
extern short AsmInsOpcodes[NUM_ASM_INS_TYPES][NUM_ASM_INS_MODES]; 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]; extern const char* AsmInstructionNames[NUM_ASM_INS_TYPES];
AsmInsType FindAsmInstruction(const char * ins); AsmInsType FindAsmInstruction(const char * ins);

View File

@ -466,7 +466,7 @@ void Compiler::CompileProcedure(InterCodeProcedure* proc)
printf("Generate native code <%s>\n", proc->mIdent->mString); printf("Generate native code <%s>\n", proc->mIdent->mString);
ncproc->Compile(proc); ncproc->Compile(proc);
mNativeProcedures.Push(ncproc); mNativeCodeGenerator->mProcedures.Push(ncproc);
} }
else else
{ {
@ -1036,13 +1036,15 @@ bool Compiler::GenerateCode(void)
mCompilationUnits->mSectionStack->mSections.Push(proc->mLinkerObject->mStackSection); mCompilationUnits->mSectionStack->mSections.Push(proc->mLinkerObject->mStackSection);
} }
mNativeCodeGenerator->OutlineFunctions();
mNativeCodeGenerator->BuildFunctionProxies(); mNativeCodeGenerator->BuildFunctionProxies();
for (int i = 0; i < mNativeProcedures.Size(); i++) for (int i = 0; i < mNativeCodeGenerator->mProcedures.Size(); i++)
{ {
if (mCompilerOptions & COPT_VERBOSE2) if (mCompilerOptions & COPT_VERBOSE2)
printf("Assemble native code <%s>\n", mNativeProcedures[i]->mInterProc->mIdent->mString); printf("Assemble native code <%s>\n", mNativeCodeGenerator->mProcedures[i]->mInterProc->mIdent->mString);
mNativeProcedures[i]->Assemble(); mNativeCodeGenerator->mProcedures[i]->Assemble();
} }
LinkerObject* byteCodeObject = nullptr; LinkerObject* byteCodeObject = nullptr;

View File

@ -29,7 +29,6 @@ public:
GlobalOptimizer* mGlobalOptimizer; GlobalOptimizer* mGlobalOptimizer;
GrowingArray<ByteCodeProcedure*> mByteCodeFunctions; GrowingArray<ByteCodeProcedure*> mByteCodeFunctions;
ExpandingArray<NativeCodeProcedure*> mNativeProcedures;
TargetMachine mTargetMachine; TargetMachine mTargetMachine;
uint64 mCompilerOptions; uint64 mCompilerOptions;

View File

@ -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_CONST_PARAMS = 1ULL << 9;
static const uint64 COPT_OPTIMIZE_MERGE_CALLS = 1ULL << 10; static const uint64 COPT_OPTIMIZE_MERGE_CALLS = 1ULL << 10;
static const uint64 COPT_OPTIMIZE_GLOBAL = 1ULL << 11; 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_OPTIMIZE_CODE_SIZE = 1ULL << 16;
static const uint64 COPT_NATIVE = 1ULL << 17; 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_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; 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;

View File

@ -9533,7 +9533,12 @@ void InterCodeBasicBlock::UpdateLocalIntegerRangeSets(const GrowingVariableArray
else else
mTrueValueRange[s1].LimitMinWeak(0); 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); 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]) 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); GrowingTypeArray tstack(IT_NONE);
CheckFunc = !strcmp(mIdent->mString, "enemies_iterate"); CheckFunc = !strcmp(mIdent->mString, "main");
CheckCase = false; CheckCase = false;
mEntryBlock = mBlocks[0]; mEntryBlock = mBlocks[0];

View File

@ -1,5 +1,6 @@
#include "NativeCodeGenerator.h" #include "NativeCodeGenerator.h"
#include "CompilerTypes.h" #include "CompilerTypes.h"
#include "NativeCodeOutliner.h"
#define JUMP_TO_BRANCH 1 #define JUMP_TO_BRANCH 1
#define CHECK_NULLPTR 0 #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) 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) void NativeCodeInstruction::CopyMode(const NativeCodeInstruction& ins)
{ {
mMode = ins.mMode; mMode = ins.mMode;
@ -5019,7 +5103,7 @@ void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block)
} }
else 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->PutOpcode(AsmInsOpcodes[ASMIT_LDX][ASMIM_IMMEDIATE]);
block->PutByte(mParam); block->PutByte(mParam);
@ -7818,9 +7902,9 @@ NativeCodeBasicBlock * NativeCodeBasicBlock::CopyValue(InterCodeProcedure* proc,
if (sstride > 1 || dstride > 1) if (sstride > 1 || dstride > 1)
msize = 32; msize = 32;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) else if (nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
msize = 8; msize = 8;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) else if (nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
msize = 2; msize = 2;
#if 1 #if 1
if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mTemp < 0) if (ins->mSrc[0].mTemp < 0 && ins->mSrc[1].mTemp < 0)
@ -8314,9 +8398,9 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::FillValue(InterCodeProcedure* proc,
if (dstride > 1) if (dstride > 1)
msize = 32; msize = 32;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) else if (nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL)
msize = 8; msize = 8;
else if (nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) else if (nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)
msize = 2; msize = 2;
#if 1 #if 1
if (ins->mSrc[1].mTemp < 0) if (ins->mSrc[1].mTemp < 0)
@ -10604,8 +10688,8 @@ NativeCodeBasicBlock* NativeCodeBasicBlock::BinaryOperator(InterCodeProcedure* p
int lcost = 8 + 2 * (nbytes - 1); int lcost = 8 + 2 * (nbytes - 1);
int ucost = shift * (1 + 2 * nbytes); int ucost = shift * (1 + 2 * nbytes);
if ((nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) && lcost < ucost || if ((nproc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE) && lcost < ucost ||
!(nproc->mInterProc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) && 2 * lcost < ucost) !(nproc->mCompilerOptions & COPT_OPTIMIZE_AUTO_UNROLL) && 2 * lcost < ucost)
{ {
mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift)); mIns.Push(NativeCodeInstruction(ins, ASMIT_LDX, ASMIM_IMMEDIATE, shift));
this->Close(ins, lblock, nullptr, ASMIT_JMP); 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 NativeCodeInstruction NativeCodeBasicBlock::DecodeNative(const InterInstruction* ins, LinkerObject* lobj, int& offset) const
{ {
uint8 op = lobj->mData[offset++]; uint8 op = lobj->mData[offset++];
@ -41554,7 +41667,7 @@ static bool CheckBlockCopySequence(const ExpandingArray<NativeCodeInstruction>&
bool NativeCodeBasicBlock::BlockSizeCopyReduction(NativeCodeProcedure* proc, int& si, int& di) 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() && if (si + 1 < mIns.Size() &&
mIns[si + 0].mType == ASMIT_LDA && (mIns[si + 0].mMode == ASMIM_ZERO_PAGE || mIns[si + 0].mMode == ASMIM_ABSOLUTE) && 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; 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) void NativeCodeBasicBlock::CheckVisited(void)
{ {
#if _DEBUG #if _DEBUG
@ -52063,6 +52202,7 @@ NativeCodeBasicBlock::NativeCodeBasicBlock(NativeCodeProcedure* proc)
mDominator = nullptr; mDominator = nullptr;
mLoopHeadBlock = nullptr; mLoopHeadBlock = nullptr;
mLoopTailBlock = nullptr; mLoopTailBlock = nullptr;
mSuffixString = nullptr;
mEntryRegA = false; mEntryRegA = false;
mEntryRegX = false; mEntryRegX = false;
mEntryRegY = 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) void NativeCodeProcedure::CompressTemporaries(bool singles)
{ {
if (mInterProc->mTempSize > 0) if (mInterProc->mTempSize > 0)
@ -52286,9 +52442,14 @@ void NativeCodeProcedure::LoadTempsFromStack(int tempSave)
void NativeCodeProcedure::Compile(InterCodeProcedure* proc) void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
{ {
mInterProc = proc; mInterProc = proc;
mLinkerObject = proc->mLinkerObject;
mIdent = proc->mIdent;
mLocation = proc->mLocation;
mCompilerOptions = proc->mCompilerOptions;
mInterProc->mLinkerObject->mNativeProc = this; mInterProc->mLinkerObject->mNativeProc = this;
CheckFunc = !strcmp(mInterProc->mIdent->mString, "rirq_sort"); CheckFunc = !strcmp(mIdent->mString, "rirq_sort");
int nblocks = proc->mBlocks.Size(); int nblocks = proc->mBlocks.Size();
tblocks = new NativeCodeBasicBlock * [nblocks]; tblocks = new NativeCodeBasicBlock * [nblocks];
@ -52417,14 +52578,14 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
if (mInterProc->mInterrupt) if (mInterProc->mInterrupt)
{ {
if (!mNoFrame || mStackExpand > 0 || commonFrameSize > 0) 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; ZeroPageSet zpLocal, zpGlobal;
ResetVisited(); ResetVisited();
if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, true)) if (mEntryBlock->CollectZeroPageSet(zpLocal, zpGlobal, true))
zpLocal |= zpGlobal; zpLocal |= zpGlobal;
else 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) 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(); ResetVisited();
mEntryBlock->RegisterFunctionCalls(); mEntryBlock->RegisterFunctionCalls();
@ -52839,9 +53000,9 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc)
void NativeCodeProcedure::Assemble(void) 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(); ResetVisited();
mEntryBlock->MergeFunctionCalls(); mEntryBlock->MergeFunctionCalls();
@ -52891,7 +53052,7 @@ void NativeCodeProcedure::Assemble(void)
for (int i = 0; i < placement.Size(); i++) for (int i = 0; i < placement.Size(); i++)
placement[i]->mAsmFromJump = -1; placement[i]->mAsmFromJump = -1;
uint8* data = mInterProc->mLinkerObject->AddSpace(total); uint8* data = mLinkerObject->AddSpace(total);
for (int i = 0; i < placement.Size(); i++) for (int i = 0; i < placement.Size(); i++)
{ {
@ -52905,7 +53066,7 @@ void NativeCodeProcedure::Assemble(void)
range.mIdent = Ident::Unique(buffer); range.mIdent = Ident::Unique(buffer);
range.mOffset = placement[i]->mOffset; range.mOffset = placement[i]->mOffset;
range.mSize = placement[i]->mSize; range.mSize = placement[i]->mSize;
mInterProc->mLinkerObject->mRanges.Push(range); mLinkerObject->mRanges.Push(range);
placement[i]->CopyCode(this, data); placement[i]->CopyCode(this, data);
} }
@ -52913,10 +53074,10 @@ void NativeCodeProcedure::Assemble(void)
for (int i = 0; i < mRelocations.Size(); i++) for (int i = 0; i < mRelocations.Size(); i++)
{ {
LinkerReference& rl(mRelocations[i]); LinkerReference& rl(mRelocations[i]);
rl.mObject = mInterProc->mLinkerObject; rl.mObject = mLinkerObject;
if (!rl.mRefObject) if (!rl.mRefObject)
rl.mRefObject = mInterProc->mLinkerObject; rl.mRefObject = mLinkerObject;
mInterProc->mLinkerObject->AddReference(rl); mLinkerObject->AddReference(rl);
} }
if (mGenerator->mCompilerOptions & (COPT_DEBUGINFO | COPT_PROFILEINFO)) if (mGenerator->mCompilerOptions & (COPT_DEBUGINFO | COPT_PROFILEINFO))
@ -52937,7 +53098,7 @@ void NativeCodeProcedure::Assemble(void)
} }
mCodeLocations.SetSize(j + 1); mCodeLocations.SetSize(j + 1);
mInterProc->mLinkerObject->AddLocations(mCodeLocations); mLinkerObject->AddLocations(mCodeLocations);
} }
} }
} }
@ -53947,7 +54108,7 @@ void NativeCodeProcedure::Optimize(void)
#endif #endif
#if 1 #if 1
if (step == 10 && (mInterProc->mCompilerOptions & COPT_OPTIMIZE_BASIC)) if (step == 10 && (mCompilerOptions & COPT_OPTIMIZE_BASIC))
{ {
ResetVisited(); ResetVisited();
mEntryBlock->MarkLocalUsedLinkerObjects(); mEntryBlock->MarkLocalUsedLinkerObjects();
@ -54051,7 +54212,7 @@ void NativeCodeProcedure::Optimize(void)
if (step == 16) if (step == 16)
{ {
if (mInterProc->mCompilerOptions & COPT_OPTIMIZE_INLINE) if (mCompilerOptions & COPT_OPTIMIZE_INLINE)
{ {
ResetVisited(); ResetVisited();
if (mEntryBlock->SimpleInlineCalls()) if (mEntryBlock->SimpleInlineCalls())
@ -54061,7 +54222,7 @@ void NativeCodeProcedure::Optimize(void)
if (step == 17) if (step == 17)
{ {
if (!(mInterProc->mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE)) if (!(mCompilerOptions & COPT_OPTIMIZE_CODE_SIZE))
{ {
ResetVisited(); ResetVisited();
if (mEntryBlock->Expand16BitLoopBranch()) if (mEntryBlock->Expand16BitLoopBranch())
@ -54100,7 +54261,7 @@ void NativeCodeProcedure::Optimize(void)
if (cnt > 200) if (cnt > 200)
{ {
changed = false; 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 #if 1
@ -55316,6 +55477,144 @@ bool NativeCodeGenerator::MergeFunctionCall(NativeCodeBasicBlock* block, int at)
return false; 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) void NativeCodeGenerator::BuildFunctionProxies(void)
{ {
FunctionCall* cp = mFunctionCalls; FunctionCall* cp = mFunctionCalls;

View File

@ -9,6 +9,9 @@ class NativeCodeBasicBlock;
class NativeCodeGenerator; class NativeCodeGenerator;
class NativeCodeInstruction; class NativeCodeInstruction;
class NativeCodeMapper;
class SuffixTree;
enum NativeRegisterDataMode enum NativeRegisterDataMode
{ {
NRDM_UNKNOWN, NRDM_UNKNOWN,
@ -154,6 +157,9 @@ public:
LinkerObject * mLinkerObject; LinkerObject * mLinkerObject;
const InterInstruction * mIns; const InterInstruction * mIns;
void Disassemble(FILE* file) const;
void DisassembleAddress(FILE* file) const;
void CopyMode(const NativeCodeInstruction& ins); void CopyMode(const NativeCodeInstruction& ins);
void Assemble(NativeCodeBasicBlock* block); void Assemble(NativeCodeBasicBlock* block);
@ -216,6 +222,12 @@ public:
void BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets); void BuildCollisionTable(NumberSet& liveTemps, NumberSet* collisionSets);
uint32 NeedsLive(void) const; uint32 NeedsLive(void) const;
uint32 CodeHash(void) const;
bool CodeSame(const NativeCodeInstruction& ins);
protected:
const char* AddrName(char* buffer) const;
}; };
struct NativeCodeLoadStorePair struct NativeCodeLoadStorePair
@ -264,6 +276,8 @@ public:
NativeCodeInstruction mALSIns, mXLSIns, mYLSIns; NativeCodeInstruction mALSIns, mXLSIns, mYLSIns;
void Disassemble(FILE* file);
NativeCodeInstruction DecodeNative(const InterInstruction* ins, LinkerObject * lobj, int& offset) const; NativeCodeInstruction DecodeNative(const InterInstruction* ins, LinkerObject * lobj, int& offset) const;
int PutBranch(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, AsmInsType code, int from, int to); int PutBranch(NativeCodeProcedure* proc, NativeCodeBasicBlock* target, AsmInsType code, int from, int to);
@ -817,6 +831,9 @@ public:
void CheckBlocks(bool sequence = false); void CheckBlocks(bool sequence = false);
void CheckAsmCode(void); void CheckAsmCode(void);
void CheckVisited(void); void CheckVisited(void);
int* mSuffixString;
void AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree * tree);
}; };
class NativeCodeProcedure class NativeCodeProcedure
@ -831,6 +848,10 @@ class NativeCodeProcedure
NativeCodeGenerator* mGenerator; NativeCodeGenerator* mGenerator;
InterCodeProcedure* mInterProc; InterCodeProcedure* mInterProc;
LinkerObject* mLinkerObject;
const Ident* mIdent;
Location mLocation;
uint64 mCompilerOptions;
int mProgStart, mProgSize, mIndex, mFrameOffset, mStackExpand; int mProgStart, mProgSize, mIndex, mFrameOffset, mStackExpand;
int mFastCallBase; int mFastCallBase;
@ -842,10 +863,14 @@ class NativeCodeProcedure
ExpandingArray<CodeLocation> mCodeLocations; ExpandingArray<CodeLocation> mCodeLocations;
void Disassemble(FILE* file);
void Compile(InterCodeProcedure* proc); void Compile(InterCodeProcedure* proc);
void Optimize(void); void Optimize(void);
void Assemble(void); void Assemble(void);
void AddToSuffixTree(NativeCodeMapper& mapper, SuffixTree* tree);
NativeCodeBasicBlock* CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* block); NativeCodeBasicBlock* CompileBlock(InterCodeProcedure* iproc, InterCodeBasicBlock* block);
NativeCodeBasicBlock* AllocateBlock(void); NativeCodeBasicBlock* AllocateBlock(void);
@ -911,6 +936,8 @@ public:
Linker* mLinker; Linker* mLinker;
LinkerSection* mRuntimeSection; LinkerSection* mRuntimeSection;
ExpandingArray<NativeCodeProcedure*> mProcedures;
ExpandingArray<Runtime> mRuntime; ExpandingArray<Runtime> mRuntime;
ExpandingArray<MulTable> mMulTables; ExpandingArray<MulTable> mMulTables;
ExpandingArray<FloatTable> mFloatTables; ExpandingArray<FloatTable> mFloatTables;
@ -929,6 +956,8 @@ public:
FunctionCall* mFunctionCalls; FunctionCall* mFunctionCalls;
void OutlineFunctions(void);
void RegisterFunctionCall(NativeCodeBasicBlock* block, int at); void RegisterFunctionCall(NativeCodeBasicBlock* block, int at);
void BuildFunctionProxies(void); void BuildFunctionProxies(void);
bool MergeFunctionCall(NativeCodeBasicBlock* block, int at); bool MergeFunctionCall(NativeCodeBasicBlock* block, int at);

View File

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

View File

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

View File

@ -13478,6 +13478,10 @@ void Parser::ParsePragma(void)
mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS; mCompilerOptions |= COPT_OPTIMIZE_CONST_PARAMS;
else if (ConsumeIdentIf("noconstparams")) else if (ConsumeIdentIf("noconstparams"))
mCompilerOptions &= ~COPT_OPTIMIZE_CONST_PARAMS; mCompilerOptions &= ~COPT_OPTIMIZE_CONST_PARAMS;
else if (ConsumeIdentIf("outline"))
mCompilerOptions |= COPT_OPTIMIZE_OUTLINE;
else if (ConsumeIdentIf("nooutline"))
mCompilerOptions &= ~COPT_OPTIMIZE_OUTLINE;
else else
mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid option"); mErrors->Error(mScanner->mLocation, EERR_INVALID_IDENTIFIER, "Invalid option");

View File

@ -261,6 +261,8 @@ int main2(int argc, const char** argv)
compiler->mCompilerOptions |= COPT_OPTIMIZE_GLOBAL; compiler->mCompilerOptions |= COPT_OPTIMIZE_GLOBAL;
else if (arg[2] == 'm' && !arg[3]) else if (arg[2] == 'm' && !arg[3])
compiler->mCompilerOptions |= COPT_OPTIMIZE_MERGE_CALLS; compiler->mCompilerOptions |= COPT_OPTIMIZE_MERGE_CALLS;
else if (arg[2] == 'o' && !arg[3])
compiler->mCompilerOptions |= COPT_OPTIMIZE_OUTLINE;
else else
compiler->mErrors->Error(loc, EERR_COMMAND_LINE, "Invalid command line argument", arg); compiler->mErrors->Error(loc, EERR_COMMAND_LINE, "Invalid command line argument", arg);
} }

View File

@ -189,6 +189,7 @@
<ClCompile Include="Linker.cpp" /> <ClCompile Include="Linker.cpp" />
<ClCompile Include="MachineTypes.cpp" /> <ClCompile Include="MachineTypes.cpp" />
<ClCompile Include="NativeCodeGenerator.cpp" /> <ClCompile Include="NativeCodeGenerator.cpp" />
<ClCompile Include="NativeCodeOutliner.cpp" />
<ClCompile Include="NumberSet.cpp" /> <ClCompile Include="NumberSet.cpp" />
<ClCompile Include="oscar64.cpp" /> <ClCompile Include="oscar64.cpp" />
<ClCompile Include="Parser.cpp" /> <ClCompile Include="Parser.cpp" />
@ -218,6 +219,7 @@
<ClInclude Include="Linker.h" /> <ClInclude Include="Linker.h" />
<ClInclude Include="MachineTypes.h" /> <ClInclude Include="MachineTypes.h" />
<ClInclude Include="NativeCodeGenerator.h" /> <ClInclude Include="NativeCodeGenerator.h" />
<ClInclude Include="NativeCodeOutliner.h" />
<ClInclude Include="NumberSet.h" /> <ClInclude Include="NumberSet.h" />
<ClInclude Include="Parser.h" /> <ClInclude Include="Parser.h" />
<ClInclude Include="Preprocessor.h" /> <ClInclude Include="Preprocessor.h" />

View File

@ -87,6 +87,9 @@
<ClCompile Include="Compression.cpp"> <ClCompile Include="Compression.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="NativeCodeOutliner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Array.h"> <ClInclude Include="Array.h">
@ -170,6 +173,9 @@
<ClInclude Include="Compression.h"> <ClInclude Include="Compression.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="NativeCodeOutliner.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="oscar64.rc"> <ResourceCompile Include="oscar64.rc">