diff --git a/autotest/autotest.bat b/autotest/autotest.bat index 0dbf0f6..c18d90d 100644 --- a/autotest/autotest.bat +++ b/autotest/autotest.bat @@ -1,5 +1,8 @@ rem @echo off +@call :test opp_string.cpp +@if %errorlevel% neq 0 goto :error + @call :test operatoroverload.cpp @if %errorlevel% neq 0 goto :error diff --git a/autotest/opp_string.cpp b/autotest/opp_string.cpp new file mode 100644 index 0000000..8df38de --- /dev/null +++ b/autotest/opp_string.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +static const char HelloWorld[] = "Hello World"; +static const char AndBeyond[] = "And Beyond"; +static const char And[] = "And"; +static const char HelloWorldAndBeyond[] = "Hello World And Beyond"; + +void test_create(void) +{ + string s1(); + string s2(HelloWorld); + string s3(s2); + string s4('a'); + + assert(!strcmp(s2.tocstr(), HelloWorld)); + assert(!strcmp(s3.tocstr(), HelloWorld)); + assert(s4.size() == 1 && s4[0] == 'a'); +} + +void test_concat(void) +{ + string s1(); + string s2(HelloWorld); + string s3(AndBeyond); + + string s4 = s1 + s2; + string s5 = s2 + " " + s3; + string s6 = s2 + " " + AndBeyond; + + assert(!strcmp(s4.tocstr(), HelloWorld)); + assert(!strcmp(s5.tocstr(), HelloWorldAndBeyond)); + assert(!strcmp(s6.tocstr(), HelloWorldAndBeyond)); +} + +__noinline void test_find(void) +{ + string s1(HelloWorldAndBeyond); + string s2(And); + + assert(s1.find(HelloWorld) == 0); + assert(s1.find(AndBeyond) == 12); + assert(s1.find(And) == 12); + assert(s1.find(s2) == 12); + + assert(s1.find(' ') == 5); + assert(s1.find(' ', 6) == 11); +} + +void test_assign(void) +{ + string s1(HelloWorld); + string s2(AndBeyond); + string s3; + s3 = s1; + s3 = s2; + s3 = s1; + s3 += " "; + s3 += s2; + + assert(!strcmp(s3.tocstr(), HelloWorldAndBeyond)); + + s3 <<= 12; + + assert(!strcmp(s3.tocstr(), AndBeyond)); + + s3 = HelloWorldAndBeyond; + + assert(!strcmp(s3.tocstr(), HelloWorldAndBeyond)); + + s3 >>= 11; + + assert(!strcmp(s3.tocstr(), HelloWorld)); +} + +int main(void) +{ + char * p = new char; + unsigned avail = heapfree(); + + test_create(); + assert(avail == heapfree()); + + test_concat(); + assert(avail == heapfree()); + + test_find(); + assert(avail == heapfree()); + + test_assign(); + assert(avail == heapfree()); + + return 0; +} diff --git a/include/opp/string.cpp b/include/opp/string.cpp index b64136f..f5468d6 100644 --- a/include/opp/string.cpp +++ b/include/opp/string.cpp @@ -2,26 +2,53 @@ #include #include +static inline void smemcpy(char * dp, const char * sp, char s) +{ + for(char i=0; i 0 && cstr) + { + if (n >= cstr[0]) + { + free(cstr); + cstr = nullptr; + } + else + { + char i = 1; + n++; + while (cstr[n]) + cstr[i++] = cstr[n++]; + cstr[i] = 0; + cstr[0] = i - 1; + } + } + return *this; +} + +string & string::operator>>=(char n) +{ + if (n > 0 && cstr) + { + if (n >= cstr[0]) + { + free(cstr); + cstr = nullptr; + } + else + { + cstr[0] -= n; + cstr[n + 1] = 0; + } + } + return *this; +} + +string string::operator<<(char n) const +{ + if (n > 0 && cstr) + { + if (n >= cstr[0]) + return string(); + else + { + + } + } + else + return *this; +} + +string string::operator>>(char n) const +{ + +} + +static int scmp(const char * s1, const char * s2) +{ + char n = 0; + while (s1[n]) + { + if (s1[n] != s2[n]) + return s1[n] - s2[n]; + n++; + } + return 0; +} inline bool string::operator==(const string & s) const { - return strcmp(cstr, s.cstr) == 0; + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) == 0; + else + return !cstr && !s.cstr; } inline bool string::operator==(const char * s) const { - return strcmp(cstr, s) == 0; + if (cstr) + return scmp(cstr + 1, s) == 0; + else + return s[0] == 0; } inline bool string::operator!=(const string & s) const { - return strcmp(cstr, s.cstr) != 0; + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) != 0; + else + return cstr || s.cstr; } inline bool string::operator!=(const char * s) const { - return strcmp(cstr, s) == 0; + if (cstr) + return scmp(cstr + 1, s) == 0; + else + return s[0] != 0; } inline bool string::operator<(const string & s) const { - return strcmp(cstr, s.cstr) < 0; + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) < 0; + else + return s.cstr; } inline bool string::operator<(const char * s) const { - return strcmp(cstr, s) < 0; + if (cstr) + return scmp(cstr + 1, s) < 0; + else + return s[0] != 0; } inline bool string::operator<=(const string & s) const { - return strcmp(cstr, s.cstr) <= 0; + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) <= 0; + else + return !cstr || s.cstr; } inline bool string::operator<=(const char * s) const { - return strcmp(cstr, s) <= 0; + if (cstr) + return scmp(cstr + 1, s) <= 0; + else + return true; } inline bool string::operator>(const string & s) const { - return strcmp(cstr, s.cstr) > 0; + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) > 0; + else + return cstr; } inline bool string::operator>(const char * s) const { - return strcmp(cstr, s) > 0; + if (cstr) + return scmp(cstr + 1, s) > 0; + else + return false; } inline bool string::operator>=(const string & s) const { - return strcmp(cstr, s.cstr) >= 0; + if (cstr && s.cstr) + return scmp(cstr + 1, s.cstr + 1) >= 0; + else + return cstr || !s.cstr; } inline bool string::operator>=(const char * s) const { - return strcmp(cstr, s) >= 0; + if (cstr) + return scmp(cstr + 1, s) >= 0; + else + return s[0] == 0; } -inline char & string::operator[](unsigned t) +inline char & string::operator[](char t) { - return cstr[t]; + return cstr[t + 1]; } -inline char string::operator[](unsigned t) const +inline char string::operator[](char t) const { - return cstr[t]; + return cstr[t + 1]; +} + +string string::substr(char pos, char len) const +{ + if (!cstr || len == 0 || pos >= cstr[0]) + return string; + else + { + char l = cstr[0]; + if (pos + len > l) + len = l - pos; + + char * p = malloc(len + 2); + memcpy(p + 1, cstr + 1 + pos, len); + return string(len, p); + } +} + +inline int string::find(const string & s) const +{ + return find(s, 0); +} + +inline int string::find(const char * s) const +{ + return find(s, 0); +} + +inline int string::find(char c) const +{ + return find(c, 0); +} + +int string::find(const string & s, char pos) const +{ + if (!s.cstr) + return pos; + if (cstr) + { + char l = cstr[0]; + char sl = s.cstr[0]; + if (sl <= l) + { + l -= sl; + + while (pos <= l) + { + char i = 1; + while (s.cstr[i] && s.cstr[i] == cstr[pos + i]) + i++; + if (!s.cstr[i]) + return pos; + pos++; + } + } + } + + return -1; +} + +int string::find(const char * s, char pos) const +{ + if (cstr) + { + char l = cstr[0]; + char sl = strlen(s); + if (sl <= l) + { + l -= sl; + + while (pos <= l) + { + char i = 0; + while (s[i] && s[i] == cstr[pos + i + 1]) + i++; + if (!s[i]) + return pos; + pos++; + } + } + } + + return -1; +} + +int string::find(char c, char pos) const +{ + if (cstr) + { + char l = cstr[0]; + while (pos < l) + { + if (cstr[pos + 1] == c) + return pos; + pos++; + } + } + + return -1; } diff --git a/include/opp/string.h b/include/opp/string.h index bde2f0a..ac4f784 100644 --- a/include/opp/string.h +++ b/include/opp/string.h @@ -9,20 +9,28 @@ private: public: string(void); string(const string & s); - string(const char * s); - string(const char * s1, const char * s2); + __noinline string(const char * s); + string(char c); ~string(void); unsigned size(void) const; - + string & operator=(const string & s); string & operator=(const char * s); string & operator+=(const string & s); string & operator+=(const char * s); + string & operator+=(char c); - string operator+(const string & s); - string operator+(const char * s); + string operator+(const string & s) const; + string operator+(const char * s) const; + string operator+(char c) const; + + string & operator<<=(char n); + string & operator>>=(char n); + + string operator<<(char n) const; + string operator>>(char n) const; bool operator==(const string & s) const; bool operator==(const char * s) const; @@ -39,10 +47,22 @@ public: bool operator>=(const string & s) const; bool operator>=(const char * s) const; - char & operator[](unsigned t); - char operator[](unsigned t) const; + char & operator[](char t); + char operator[](char t) const; const char * tocstr(void) const; + + string substr(char pos, char len) const; + + int find(const string & s) const; + int find(const char * s) const; + int find(char c) const; + + int find(const string & s, char pos) const; + int find(const char * s, char pos) const; + int find(char c, char pos) const; +protected: + string(char l, char * b); }; #pragma compile("string.cpp") diff --git a/include/stdlib.c b/include/stdlib.c index a181c0a..7b5709e 100644 --- a/include/stdlib.c +++ b/include/stdlib.c @@ -524,6 +524,22 @@ void exit(int status) } } +extern struct Heap { + Heap * next, * end; +} HeapNode; + +unsigned heapfree(void) +{ + unsigned avail = 0; + Heap * h = HeapNode.next; + while (h) + { + avail += (h->end - h) * sizeof(Heap); + h = h->next; + } + return avail; +} + #if 0 struct Heap { unsigned int size; diff --git a/include/stdlib.h b/include/stdlib.h index 7384454..4d4eac5 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -43,6 +43,8 @@ void free(void * ptr); void * calloc(int num, int size); +unsigned heapfree(void); + unsigned int rand(void); void srand(unsigned int seed); diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index ff056cf..91b1108 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -4428,6 +4428,9 @@ void InterCodeBasicBlock::Append(InterInstruction * code) assert(code->mSrc[1].mType != IT_POINTER); } + for (int i = 0; i < code->mNumOperands; i++) + assert(code->mSrc[i].mType != IT_NONE); + assert(!(code->mInUse)); code->mInUse = true; this->mInstructions.Push(code); @@ -16126,7 +16129,7 @@ void InterCodeProcedure::Close(void) { GrowingTypeArray tstack(IT_NONE); - CheckFunc = !strcmp(mIdent->mString, "setspr"); + CheckFunc = !strcmp(mIdent->mString, "test_find"); mEntryBlock = mBlocks[0]; diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index bd1a538..8908ed9 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -1007,8 +1007,9 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateInline(Declaration* pro InterInstruction* wins = new InterInstruction(texp->mLocation, IC_STORE); wins->mSrc[1].mMemory = IM_INDIRECT; - wins->mSrc[0].mType = InterTypeOf(vr.mType);; + wins->mSrc[0].mType = vr.mReference > 0 ? IT_POINTER : InterTypeOf(vr.mType); wins->mSrc[0].mTemp = vr.mTemp; + assert(wins->mSrc[0].mType != IT_NONE); wins->mSrc[1].mType = IT_POINTER; wins->mSrc[1].mTemp = ains->mDst.mTemp; if (pdec) @@ -3195,6 +3196,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* block->Append(defins[i]); InterInstruction * cins = new InterInstruction(exp->mLocation, IC_CALL); + cins->mNumOperands = 1; if (funcexp->mDecValue && (funcexp->mDecValue->mFlags & DTF_NATIVE)) cins->mCode = IC_CALL_NATIVE; else diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index b0a1fe5..95f6dcc 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -28951,7 +28951,7 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc i++; while (i < mIns.Size() && !mIns[i].ReferencesZeroPage(mIns[si].mAddress)) i++; - if (i < mIns.Size() && (mIns[i].mType == ASMIT_DEC || mIns[i].mType == ASMIT_INC)) + if (i < mIns.Size() && (mIns[i].mType == ASMIT_DEC || mIns[i].mType == ASMIT_INC) && (!(mIns[ei].mLive & LIVE_CPU_REG_Z) || mIns[ei].ChangesAccuAndFlag())) { int j = i + 1; while (j < mIns.Size() && !mIns[j].ReferencesZeroPage(mIns[si].mAddress)) @@ -28961,6 +28961,9 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc // So we have an LDX from ZP, and exactly one INC/DECof this ZP and X never changes in the loop if (!prevBlock) return OptimizeSimpleLoopInvariant(proc, full); + + bool needRecheck = mIns[ei].mLive & LIVE_CPU_REG_Z; + prevBlock->mIns.Push(mIns[si]); exitBlock->mIns.Insert(0, NativeCodeInstruction(mIns[si].mIns, ASMIT_STX, mIns[si])); mIns[si].mType = ASMIT_NOP; @@ -28975,6 +28978,12 @@ bool NativeCodeBasicBlock::OptimizeSimpleLoopInvariant(NativeCodeProcedure* proc mIns[i].mType = ASMIT_NOP; mIns[i].mMode = ASMIM_IMPLIED; + if (needRecheck) + { + mIns[ei].mLive |= LIVE_CPU_REG_A; + mIns.Insert(ei + 1, NativeCodeInstruction(mIns[ei].mIns, ASMIT_ORA, ASMIM_IMMEDIATE, 0)); + } + mIns.Insert(ei + 1, NativeCodeInstruction(mIns[i].mIns, t)); for (int i = 0; i < mIns.Size(); i++) @@ -31171,6 +31180,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) NativeCodeBasicBlock* block = lblocks[i]; int yoffset = 0, xoffset = 0, aoffset = 0; + int yskew = 0, xskew = 0; for (int j = 0; j < block->mIns.Size(); j++) { @@ -31189,6 +31199,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) zareg[ins.mAddress] = -1; } yoffset = 0; + yskew = 0; zareg[CPU_REG_Y] = -1; break; case ASMIT_LDX: @@ -31202,6 +31213,7 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) zareg[ins.mAddress] = -1; } xoffset = 0; + xskew = 0; zareg[CPU_REG_X] = -1; break; case ASMIT_STY: @@ -31235,13 +31247,35 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) zareg[CPU_REG_X] = -1; break; case ASMIT_INC: + if (ins.mMode == ASMIM_ZERO_PAGE) + { + if (zxreg[ins.mAddress] >= 0) + { + zxreg[ins.mAddress] += 3; + xskew++; + } + if (zyreg[ins.mAddress] >= 0) + { + zyreg[ins.mAddress] += 3; + yskew++; + } + + zareg[ins.mAddress] = -1; + } + break; case ASMIT_DEC: if (ins.mMode == ASMIM_ZERO_PAGE) { if (zxreg[ins.mAddress] >= 0) + { zxreg[ins.mAddress] += 3; + xskew--; + } if (zyreg[ins.mAddress] >= 0) + { zyreg[ins.mAddress] += 3; + yskew--; + } zareg[ins.mAddress] = -1; } @@ -31335,6 +31369,11 @@ bool NativeCodeBasicBlock::OptimizeGenericLoop(NativeCodeProcedure* proc) areg = -2; } + if (xreg >= 0 && ins.mMode == ASMIM_ABSOLUTE_X && xskew != xoffset) + zxreg[xreg] = -1; + if (yreg >= 0 && (ins.mMode == ASMIM_ABSOLUTE_Y || ins.mMode == ASMIM_INDIRECT_Y) && yskew != yoffset) + zyreg[yreg] = -1; + if (!(ins.mLive & LIVE_CPU_REG_Y)) yoffset = 0; if (!(ins.mLive & LIVE_CPU_REG_X)) @@ -40154,7 +40193,7 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) { mInterProc = proc; - CheckFunc = !strcmp(mInterProc->mIdent->mString, "heapcheck"); + CheckFunc = !strcmp(mInterProc->mIdent->mString, "test_find"); int nblocks = proc->mBlocks.Size(); tblocks = new NativeCodeBasicBlock * [nblocks];