Optimize outliner compile time performance

This commit is contained in:
drmortalwombat 2025-01-19 18:10:02 +01:00
parent 95732265f6
commit c8abb42c3c
4 changed files with 112 additions and 45 deletions

View File

@ -128,6 +128,7 @@ The compiler is command line driven, and creates an executable .prg file.
* -Oa : optimize inline assembler (part of O2/O3) * -Oa : optimize inline assembler (part of O2/O3)
* -Oz : enable auto placement of global variables in zero page (part of O3) * -Oz : enable auto placement of global variables in zero page (part of O3)
* -Op : optimize constant parameters * -Op : optimize constant parameters
* -Oo : optimize size using "outliner" (extract repeated code sequences into functions)
* -g : create source level debug info and add source line numbers to asm listing * -g : create source level debug info and add source line numbers to asm listing
* -gp : create source level debug info and add source line numbers to asm listing and static profile data * -gp : create source level debug info and add source line numbers to asm listing and static profile data
* -tf : target format, may be prg, crt or bin * -tf : target format, may be prg, crt or bin
@ -483,6 +484,8 @@ Set optimizer options that are active for the functions after it
* maxinline : inline any function suitable * maxinline : inline any function suitable
* constparams : enable constant parameter folding into called functions * constparams : enable constant parameter folding into called functions
* noconstparams : disable constant parameter folding into called functions * noconstparams : disable constant parameter folding into called functions
* outline : enable outliner
* nooutline : disable outliner
* 0 : no optimization * 0 : no optimization
* 1 : default optimizations * 1 : default optimizations
* 2 : aggressive optimizations * 2 : aggressive optimizations

View File

@ -5015,9 +5015,12 @@ void NativeCodeInstruction::FilterRegUsage(NumberSet& requiredTemps, NumberSet&
uint32 NativeCodeInstruction::CodeHash(void) const uint32 NativeCodeInstruction::CodeHash(void) const
{ {
uint32 hash = mType + 0x20 * mMode + 0x100 * mAddress; uint32 hash = mType + 137 * mMode + 4111 * mAddress;
if (mLinkerObject) if (mLinkerObject)
hash += mLinkerObject->mID * 0x1000; hash += mLinkerObject->mID * 135123;
hash ^= hash >> 13;
hash ^= hash << 11;
hash ^= hash >> 23;
return hash; return hash;
} }
@ -55514,10 +55517,10 @@ void NativeCodeGenerator::OutlineFunctions(void)
tree->LongestMatch(mapper, 0, 0, lsize, ltree); tree->LongestMatch(mapper, 0, 0, lsize, ltree);
if (lsize > 6) if (lsize > 6)
{ {
SuffixTree* leaf = ltree; ExpandingArray<SuffixSegment> segs;
while (leaf->mFirst) ltree->ReplaceCalls(mapper, segs);
leaf = leaf->mFirst;
NativeCodeBasicBlock* block = mapper.mBlocks[-(1 + leaf->mSeg[leaf->mSize - 1])]; NativeCodeBasicBlock* block = segs[0].mBlock;
NativeCodeProcedure* nproc = new NativeCodeProcedure(this); NativeCodeProcedure* nproc = new NativeCodeProcedure(this);
@ -55541,9 +55544,6 @@ void NativeCodeGenerator::OutlineFunctions(void)
else else
nblock->mIns.Push(NativeCodeInstruction(nblock->mIns[nblock->mIns.Size() - 1].mIns, ASMIT_RTS)); 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 { 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); return l.mBlock == r.mBlock ? l.mStart > r.mStart : ptrdiff_t(l.mBlock) < ptrdiff_t(r.mBlock);
}); });

View File

@ -62,20 +62,32 @@ SuffixTree::SuffixTree(const int* str, int s, SuffixTree* n)
mFirst = nullptr; mFirst = nullptr;
} }
SuffixTree::~SuffixTree(void)
{
delete[] mFirst;
}
void SuffixTree::AddParents(SuffixTree* parent) void SuffixTree::AddParents(SuffixTree* parent)
{ {
mParent = parent; mParent = parent;
SuffixTree* n = mFirst; if (mFirst)
while (n)
{ {
n->AddParents(this); for (int i = 0; i < HashSize; i++)
n = n->mNext; {
SuffixTree* n = mFirst[i];
while (n)
{
n->AddParents(this);
n = n->mNext;
}
}
} }
} }
void SuffixTree::AddSuffix(const int* str, int s) void SuffixTree::AddSuffix(const int* str, int s)
{ {
SuffixTree* c = mFirst; int hi = str[0] & (HashSize - 1);
SuffixTree* c = mFirst ? mFirst[hi] : nullptr;
while (c && c->mSeg[0] != str[0]) while (c && c->mSeg[0] != str[0])
c = c->mNext; c = c->mNext;
@ -88,15 +100,39 @@ void SuffixTree::AddSuffix(const int* str, int s)
c->AddSuffix(str + k, s - k); c->AddSuffix(str + k, s - k);
else else
{ {
SuffixTree* t = c->mFirst; SuffixTree * n = new SuffixTree(c->mSeg + k, c->mSize - k, nullptr);
c->mFirst = new SuffixTree(c->mSeg + k, c->mSize - k, nullptr); if (c->mFirst)
c->mFirst->mFirst = t; {
c->mFirst = new SuffixTree(str + k, s - k, c->mFirst); n->mFirst = new SuffixTree * [HashSize];
for (int i = 0; i < HashSize; i++)
{
n->mFirst[i] = c->mFirst[i];
c->mFirst[i] = nullptr;
}
}
else
{
c->mFirst = new SuffixTree * [HashSize];
for (int i = 0; i < HashSize; i++)
c->mFirst[i] = nullptr;
}
c->mFirst[c->mSeg[k] & (HashSize - 1)] = n;
int hk = str[k] & (HashSize - 1);
c->mFirst[hk] = new SuffixTree(str + k, s - k, c->mFirst[hk]);
c->mSize = k; c->mSize = k;
} }
} }
else else
mFirst = new SuffixTree(str, s, mFirst); {
if (!mFirst)
{
mFirst = new SuffixTree * [HashSize];
for (int i = 0; i < HashSize; i++)
mFirst[i] = nullptr;
}
mFirst[hi] = new SuffixTree(str, s, mFirst[hi]);
}
} }
void SuffixTree::AddString(const int* str) void SuffixTree::AddString(const int* str)
@ -120,11 +156,15 @@ void SuffixTree::CollectSuffix(NativeCodeMapper& map, int offset, ExpandingArray
offset += mSize; offset += mSize;
if (mFirst) if (mFirst)
{ {
SuffixTree* t = mFirst; for (int i = 0; i < HashSize; i++)
while (t)
{ {
t->CollectSuffix(map, offset, segs); SuffixTree* t = mFirst[i];
t = t->mNext;
while (t)
{
t->CollectSuffix(map, offset, segs);
t = t->mNext;
}
} }
} }
else else
@ -154,22 +194,28 @@ int SuffixTree::LongestMatch(NativeCodeMapper& map, int size, int isize, int& ms
assert(size < 10000); assert(size < 10000);
int cnt = 0; int cnt = 0;
SuffixTree* t = mFirst; for (int i = 0; i < HashSize; i++)
while (t)
{ {
cnt += t->LongestMatch(map, size, isize, msize, mtree); SuffixTree* t = mFirst[i];
t = t->mNext; while (t)
{
cnt += t->LongestMatch(map, size, isize, msize, mtree);
t = t->mNext;
}
} }
if (size >= 6 && (size - 3) * (cnt - 1) > msize) if (size >= 6 && (size - 3) * (cnt - 1) > msize)
{ {
// Second run to cross check for overlaps // Second run to cross check for overlaps
ExpandingArray<SuffixSegment> segs; ExpandingArray<SuffixSegment> segs;
SuffixTree* t = mFirst; for (int i = 0; i < HashSize; i++)
while (t)
{ {
t->CollectSuffix(map, 0, segs); SuffixTree* t = mFirst[i];
t = t->mNext; while (t)
{
t->CollectSuffix(map, 0, segs);
t = t->mNext;
}
} }
segs.Sort([](const SuffixSegment& l, const SuffixSegment& r)->bool { 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); return l.mBlock == r.mBlock ? l.mStart < r.mStart : ptrdiff_t(l.mBlock) < ptrdiff_t(r.mBlock);
@ -214,13 +260,18 @@ void SuffixTree::Print(FILE * file, NativeCodeMapper& map, int depth)
} }
fprintf(file, "\n"); fprintf(file, "\n");
SuffixTree* n = mFirst; if (mFirst)
while (n)
{ {
n->Print(file, map, depth + 1); for (int i = 0; i < HashSize; i++)
n = n->mNext; {
SuffixTree* n = mFirst[i];
while (n)
{
n->Print(file, map, depth + 1);
n = n->mNext;
}
}
} }
} }
void SuffixTree::ParentPrint(FILE* file, NativeCodeMapper& map) void SuffixTree::ParentPrint(FILE* file, NativeCodeMapper& map)
@ -265,11 +316,17 @@ void SuffixTree::ParentCollect(NativeCodeMapper& map, NativeCodeBasicBlock* bloc
void SuffixTree::ReplaceCalls(NativeCodeMapper& map, ExpandingArray<SuffixSegment>& segs) void SuffixTree::ReplaceCalls(NativeCodeMapper& map, ExpandingArray<SuffixSegment>& segs)
{ {
SuffixTree* n = mFirst; if (mFirst)
while (n)
{ {
n->ChildReplaceCalls(map, this, 0, segs); for (int i = 0; i < HashSize; i++)
n = n->mNext; {
SuffixTree* n = mFirst[i];
while (n)
{
n->ChildReplaceCalls(map, this, 0, segs);
n = n->mNext;
}
}
} }
} }
@ -283,11 +340,14 @@ void SuffixTree::ChildReplaceCalls(NativeCodeMapper& map, SuffixTree* tree, int
if (mFirst) if (mFirst)
{ {
SuffixTree* n = mFirst; for (int i = 0; i < HashSize; i++)
while (n)
{ {
n->ChildReplaceCalls(map, tree, offset, segs); SuffixTree* n = mFirst[i];
n = n->mNext; while (n)
{
n->ChildReplaceCalls(map, tree, offset, segs);
n = n->mNext;
}
} }
} }
else else

View File

@ -41,9 +41,13 @@ public:
const int * mSeg; const int * mSeg;
int mSize; int mSize;
SuffixTree* mNext, * mParent, * mFirst; static const int HashSize = 32;
SuffixTree* mNext, * mParent, ** mFirst;
SuffixTree(const int* str, int s, SuffixTree* n); SuffixTree(const int* str, int s, SuffixTree* n);
~SuffixTree(void);
void AddParents(SuffixTree* parent); void AddParents(SuffixTree* parent);
void AddSuffix(const int* str, int s); void AddSuffix(const int* str, int s);