diff --git a/autotest/autotest.bat b/autotest/autotest.bat index dc0ddf5..920d91f 100644 --- a/autotest/autotest.bat +++ b/autotest/autotest.bat @@ -18,6 +18,13 @@ if %errorlevel% neq 0 goto :error ..\release\oscar64 -e -n testint32.c if %errorlevel% neq 0 goto :error +..\release\oscar64 -e testint16mul.c +if %errorlevel% neq 0 goto :error + +..\release\oscar64 -e -n testint16mul.c +if %errorlevel% neq 0 goto :error + + ..\release\oscar64 -e recursiontest.c if %errorlevel% neq 0 goto :error diff --git a/autotest/testint16mul.c b/autotest/testint16mul.c new file mode 100644 index 0000000..bc799e4 --- /dev/null +++ b/autotest/testint16mul.c @@ -0,0 +1,23 @@ +#include + +int mul[32][32]; + +int main(void) +{ + for(int i=0; i<32; i++) + for(int j=0; j<32; j++) + mul[i][j] = i * j; +#assign xi 0 +#repeat + + for(int j=0; j<32; j++) + { + assert(mul[xi][j] == xi * j); + assert(mul[j][xi] == j * xi); + } + +#assign xi xi + 1 +#until xi == 32 + + return 0; +} diff --git a/include/c64/joystick.c b/include/c64/joystick.c new file mode 100644 index 0000000..cea89aa --- /dev/null +++ b/include/c64/joystick.c @@ -0,0 +1,25 @@ +#include "joystick.h" + +signed char joyx[2], joyy[2]; +bool joyb[2]; + +void joy_poll(char n) +{ + char b = ((char *)0xdc00)[n]; + + if (!(b & 1)) + joyy[n] = -1; + else if (!(b & 2)) + joyy[n] = 1; + else + joyy[n] = 0; + + if (!(b & 4)) + joyx[n] = -1; + else if (!(b & 8)) + joyx[n] = 1; + else + joyx[n] = 0; + + joyb[n] = (b & 0x10) == 0; +} diff --git a/include/c64/joystick.h b/include/c64/joystick.h new file mode 100644 index 0000000..7f303fa --- /dev/null +++ b/include/c64/joystick.h @@ -0,0 +1,11 @@ +#ifndef C64_JOYSTICK_H +#define C64_JOYSTICK_H + +extern signed char joyx[2], joyy[2]; +extern bool joyb[2]; + +void joy_poll(char n); + +#pragma compile("joystick.c") + +#endif diff --git a/include/crt.c b/include/crt.c index b16172a..5f30c0b 100644 --- a/include/crt.c +++ b/include/crt.c @@ -6,6 +6,8 @@ void StackStart, StackEnd, BSSStart, BSSEnd; #pragma section(stack, 0x0000, StackStart, StackEnd) #pragma section(bss, 0x0000, BSSStart, BSSEnd) +char spentry; + int main(void); __asm startup @@ -25,6 +27,9 @@ __asm startup // Clear BSS Segment + tsx + stx spentry + lda #BSSStart @@ -202,13 +207,18 @@ __asm divmod // byte / byte BB: lda #0 - ldx #8 + ldx #4 asl accu LBB1: rol cmp tmp bcc WBB1 sbc tmp WBB1: rol accu + rol + cmp tmp + bcc WBB2 + sbc tmp +WBB2: rol accu dex bne LBB1 sta tmp + 2 @@ -330,26 +340,55 @@ W1: dey __asm mul16 { - lda #0 - sta tmp + 2 - sta tmp + 3 + ldy #0 + sty tmp + 3 - ldx #16 -L1: lsr tmp + 1 - ror tmp - bcc W1 + lda tmp + ldx tmp + 1 + beq W1 + + sec + ror + bcc L2 +L1: + tax clc - lda tmp + 2 + tya adc accu - sta tmp + 2 + tay lda tmp + 3 adc accu + 1 sta tmp + 3 -W1: asl accu + txa +L2: + asl accu + 0 rol accu + 1 - dex + lsr + bcc L2 bne L1 - rts + + lda tmp + 1 +W1: + lsr + bcc L4 +L3: + tax + clc + tya + adc accu + tay + lda tmp + 3 + adc accu + 1 + sta tmp + 3 + txa +L4: + asl accu + 0 + rol accu + 1 + lsr + bcs L3 + bne L4 + + sty tmp + 2 } __asm mul32 @@ -1010,6 +1049,25 @@ __asm inp_lea_abs #pragma bytecode(BC_LEA_ABS, inp_lea_abs) +__asm inp_lea_abs_index +{ + lda (ip), y + tax + iny + clc + lda $00, x + adc (ip), y + sta addr + iny + lda $01, x + adc (ip), y + sta addr + 1 + iny + jmp startup.exec +} + +#pragma bytecode(BC_LEA_ABS_INDEX, inp_lea_abs_index) + __asm inp_load_local_16 { lda (ip), y diff --git a/include/crt.h b/include/crt.h index 48e0b4e..5b0d34a 100644 --- a/include/crt.h +++ b/include/crt.h @@ -13,6 +13,7 @@ #define sregs 0x43 #define regs 0x53 +extern char spentry; enum ByteCode { @@ -42,6 +43,7 @@ enum ByteCode BC_STORE_ABS_32, BC_LEA_ABS, + BC_LEA_ABS_INDEX, BC_LOAD_LOCAL_8, BC_LOAD_LOCAL_16, diff --git a/include/stdio.c b/include/stdio.c index f7fa2ab..80c5a7b 100644 --- a/include/stdio.c +++ b/include/stdio.c @@ -92,7 +92,7 @@ struct sinfo bool sign, left, prefix; }; -int nformi(const sinfo * si, char * str, int v, bool s) +inline int nformi(const sinfo * si, char * str, int v, bool s) { char * sp = str; diff --git a/include/stdlib.c b/include/stdlib.c index c903cd9..313a7bb 100644 --- a/include/stdlib.c +++ b/include/stdlib.c @@ -2,6 +2,7 @@ #include "string.h" #include "stdio.h" #include "math.h" +#include "crt.h" void itoa(int n, char * s, unsigned radix) { @@ -312,8 +313,12 @@ void exit(int status) sta accu + 0 lda status + 1 sta accu + 1 - pla - pla + ldx spentry + txs + lda #$4c + sta $54 + lda #0 + sta $13 } } diff --git a/include/string.c b/include/string.c index b11d4c3..de74d56 100644 --- a/include/string.c +++ b/include/string.c @@ -13,6 +13,10 @@ char * strcpy(char * dst, const char * src) ldy #0 L1: lda (src), y + sta (dst), y + beq W1 + iny + lda (src), y sta (dst), y beq W1 iny @@ -21,7 +25,6 @@ char * strcpy(char * dst, const char * src) inc dst + 1 bne L1 W1: - rts } } @@ -57,17 +60,18 @@ int strcmp(const char * ptr1, const char * ptr2) W2: bcs gt lda #$ff sta accu - sta accu + 1 - rts + bmi E + gt: lda #$01 sta accu lda #$00 - sta accu + 1 - rts + beq E + W1: cmp (ptr2), y bne W2 lda #$00 sta accu + E: sta accu + 1 } } diff --git a/include/string.h b/include/string.h index 71de7d5..5aa4102 100644 --- a/include/string.h +++ b/include/string.h @@ -1,9 +1,9 @@ #ifndef STRING_H #define STRING_H -__fastcall char * strcpy(char * dst, const char * src); +char * strcpy(char * dst, const char * src); -__fastcall int strcmp(const char * ptr1, const char * ptr2); +int strcmp(const char * ptr1, const char * ptr2); int strlen(const char * str); diff --git a/oscar64/Array.h b/oscar64/Array.h index 16a50a5..1c91de7 100644 --- a/oscar64/Array.h +++ b/oscar64/Array.h @@ -267,4 +267,12 @@ public: { Grow(size, true); } + + int IndexOf(const T& t) + { + for (int i = 0; i < size; i++) + if (array[i] == t) + return i; + return -1; + } }; diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index 35f202a..c53edad 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -206,6 +206,8 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const return true; if (mCode == BC_JSR || mCode == BC_CALL) return true; + if (mCode == BC_LEA_ABS_INDEX) + return true; } return false; @@ -293,6 +295,7 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl break; case BC_LEA_ABS: + case BC_LEA_ABS_INDEX: block->PutCode(generator, mCode); block->PutByte(mRegister); if (mRelocate) { @@ -3261,6 +3264,23 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) for (int i = 0; i < mIns.Size(); i++) { + if (i + 3 < mIns.Size()) + { + if ( + mIns[i + 0].mCode == BC_LEA_ABS && mIns[i + 0].mRegister == BC_REG_ACCU && + mIns[i + 1].mCode == BC_BINOP_ADDR_16 && + mIns[i + 2].mCode == BC_ADDR_REG && mIns[i + 2].mRegister == BC_REG_ACCU && + mIns[i + 3].ChangesAccu()) + { + mIns[i + 0].mCode = BC_LEA_ABS_INDEX; + mIns[i + 0].mRegister = mIns[i + 1].mRegister; + mIns[i + 0].mRegisterFinal = mIns[i + 1].mRegisterFinal; + mIns[i + 1].mCode = BC_NOP; + mIns[i + 2].mCode = BC_NOP; + progress = true; + } + } + if (i + 2 < mIns.Size()) { if (mIns[i].mCode == BC_LOAD_LOCAL_16 && @@ -3403,6 +3423,15 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) mIns[i + 1].mRegister = mIns[i + 0].mRegister; progress = true; } + else if ( + mIns[i + 0].mCode == BC_LOAD_REG_8 && + mIns[i + 1].mCode == BC_STORE_REG_8 && + mIns[i + 2].mCode == BC_LOAD_REG_8 && mIns[i + 1].mRegister == mIns[i + 2].mRegister && mIns[i + 2].mRegisterFinal) + { + mIns[i + 1].mCode = BC_NOP; + mIns[i + 2].mCode = BC_NOP; + progress = true; + } } if (i + 1 < mIns.Size()) diff --git a/oscar64/ByteCodeGenerator.h b/oscar64/ByteCodeGenerator.h index fca1861..9b5aabc 100644 --- a/oscar64/ByteCodeGenerator.h +++ b/oscar64/ByteCodeGenerator.h @@ -32,6 +32,7 @@ enum ByteCode BC_STORE_ABS_32, BC_LEA_ABS, + BC_LEA_ABS_INDEX, BC_LOAD_LOCAL_8, BC_LOAD_LOCAL_16, diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 28def4f..edf7226 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -19,6 +19,7 @@ Compiler::Compiler(void) mInterCodeGenerator = new InterCodeGenerator(mErrors, mLinker); mNativeCodeGenerator = new NativeCodeGenerator(mErrors, mLinker); mInterCodeModule = new InterCodeModule(); + mGlobalAnalyzer = new GlobalAnalyzer(mErrors, mLinker); mCompilationUnits->mLinker = mLinker; @@ -156,6 +157,11 @@ bool Compiler::GenerateCode(void) dcrtstart->mSection = sectionStartup; + mGlobalAnalyzer->AnalyzeAssembler(dcrtstart->mValue, nullptr); + mGlobalAnalyzer->DumpCallGraph(); + mGlobalAnalyzer->AutoInline(); + mGlobalAnalyzer->DumpCallGraph(); + mInterCodeGenerator->mForceNativeCode = mNativeCode; mInterCodeGenerator->TranslateAssembler(mInterCodeModule, dcrtstart->mValue, nullptr); diff --git a/oscar64/Compiler.h b/oscar64/Compiler.h index eab9d5e..38fc89b 100644 --- a/oscar64/Compiler.h +++ b/oscar64/Compiler.h @@ -6,6 +6,7 @@ #include "ByteCodeGenerator.h" #include "NativeCodeGenerator.h" #include "InterCodeGenerator.h" +#include "GlobalAnalyzer.h" #include "Linker.h" class Compiler @@ -22,6 +23,7 @@ public: NativeCodeGenerator* mNativeCodeGenerator; InterCodeGenerator* mInterCodeGenerator; InterCodeModule* mInterCodeModule; + GlobalAnalyzer* mGlobalAnalyzer; GrowingArray mByteCodeFunctions; diff --git a/oscar64/Declaration.cpp b/oscar64/Declaration.cpp index 311250f..00ab164 100644 --- a/oscar64/Declaration.cpp +++ b/oscar64/Declaration.cpp @@ -337,7 +337,7 @@ Expression* Expression::ConstantFold(void) } Declaration::Declaration(const Location& loc, DecType type) - : mLocation(loc), mType(type), mScope(nullptr), mData(nullptr), mIdent(nullptr), mSize(0), mOffset(0), mFlags(0), mBase(nullptr), mParams(nullptr), mValue(nullptr), mNext(nullptr), mVarIndex(-1), mLinkerObject(nullptr) + : mLocation(loc), mType(type), mScope(nullptr), mData(nullptr), mIdent(nullptr), mSize(0), mOffset(0), mFlags(0), mComplexity(0), mBase(nullptr), mParams(nullptr), mValue(nullptr), mNext(nullptr), mVarIndex(-1), mLinkerObject(nullptr), mCallers(nullptr), mCalled(nullptr) {} Declaration::~Declaration(void) diff --git a/oscar64/Declaration.h b/oscar64/Declaration.h index ed1c898..2acef33 100644 --- a/oscar64/Declaration.h +++ b/oscar64/Declaration.h @@ -4,6 +4,7 @@ #include "Scanner.h" #include "MachineTypes.h" #include "Assembler.h" +#include "Array.h" class LinkerObject; class LinkerSection; @@ -63,6 +64,14 @@ static const uint32 DTF_SECTION_START = 0x00001000; static const uint32 DTF_SECTION_END = 0x00002000; static const uint32 DTF_FASTCALL = 0x00004000; static const uint32 DTF_INLINE = 0x00008000; +static const uint32 DTF_ANALYZED = 0x00010000; +static const uint32 DTF_REQUEST_INLINE = 0x00020000; + +static const uint32 DTF_FUNC_VARIABLE = 0x00040000; +static const uint32 DTF_FUNC_ASSEMBLER = 0x00080000; +static const uint32 DTF_FUNC_RECURSIVE = 0x00100000; +static const uint32 DTF_FUNC_ANALYZING = 0x00200000; + class Declaration; @@ -156,7 +165,7 @@ public: Declaration* mBase, *mParams, * mNext; Expression* mValue; DeclarationScope* mScope; - int mOffset, mSize, mVarIndex, mNumVars; + int mOffset, mSize, mVarIndex, mNumVars, mComplexity; int64 mInteger; double mNumber; uint32 mFlags; @@ -165,6 +174,8 @@ public: const uint8 * mData; LinkerObject * mLinkerObject; + GrowingArray mCallers, mCalled; + bool CanAssign(const Declaration* fromType) const; bool IsSame(const Declaration* dec) const; bool IsSubType(const Declaration* dec) const; diff --git a/oscar64/Disassembler.cpp b/oscar64/Disassembler.cpp index 0148f84..34dfe8b 100644 --- a/oscar64/Disassembler.cpp +++ b/oscar64/Disassembler.cpp @@ -20,6 +20,11 @@ const char* ByteCodeDisassembler::TempName(uint8 tmp, char* buffer, InterCodePro return "ADDR"; else if (tmp == BC_REG_ACCU) return "ACCU"; + else if (tmp >= BC_REG_FPARAMS && tmp <= BC_REG_FPARAMS + 7) + { + sprintf_s(buffer, 10, "P%d", tmp - BC_REG_FPARAMS); + return buffer; + } else if (proc && tmp >= BC_REG_TMP && tmp < BC_REG_TMP + proc->mTempSize) { int i = 0; @@ -152,6 +157,11 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int star i += 3; break; + case BC_LEA_ABS_INDEX: + fprintf(file, "LEAX\tADDR, %s + %s", AddrName(uint16(memory[start + i + 1] + 256 * memory[start + i + 2]), abuffer, linker), TempName(memory[start + i + 0], tbuffer, proc)); + i += 3; + break; + case BC_STORE_ABS_8: fprintf(file, "MOVB\t%s, %s", AddrName(uint16(memory[start + i + 0] + 256 * memory[start + i + 1]), abuffer, linker), TempName(memory[start + i + 2], tbuffer, proc)); i += 3; @@ -639,7 +649,7 @@ const char* NativeCodeDisassembler::AddrName(int addr, char* buffer, Linker* lin LinkerObject* obj = linker->FindObjectByAddr(addr); if (obj && obj->mIdent) { - sprintf_s(buffer, 40, "%s + %d", obj->mIdent->mString, addr - obj->mAddress); + sprintf_s(buffer, 40, "$%04x ; (%s + %d)", addr, obj->mIdent->mString, addr - obj->mAddress); return buffer; } } @@ -671,6 +681,11 @@ const char* NativeCodeDisassembler::TempName(uint8 tmp, char* buffer, InterCodeP sprintf_s(buffer, 10, "IP + %d", tmp - BC_REG_IP); return buffer; } + else if (tmp >= BC_REG_FPARAMS && tmp <= BC_REG_FPARAMS + 7) + { + sprintf_s(buffer, 10, "P%d", tmp - BC_REG_FPARAMS); + return buffer; + } else if (tmp >= BC_REG_LOCALS && tmp <= BC_REG_LOCALS + 3) { sprintf_s(buffer, 10, "FP + %d", tmp - BC_REG_LOCALS); diff --git a/oscar64/Emulator.cpp b/oscar64/Emulator.cpp index 928cbdc..d5996dd 100644 --- a/oscar64/Emulator.cpp +++ b/oscar64/Emulator.cpp @@ -633,7 +633,7 @@ int Emulator::Emulate(int startIP) break; } - if ((trace & 1) && ip == 0x081f) + if ((trace & 1) && ip == 0x0850) { int accu = mMemory[BC_REG_ACCU] + 256 * mMemory[BC_REG_ACCU + 1]; int ptr = mMemory[BC_REG_ADDR] + 256 * mMemory[BC_REG_ADDR + 1]; diff --git a/oscar64/GlobalAnalyzer.cpp b/oscar64/GlobalAnalyzer.cpp new file mode 100644 index 0000000..3623720 --- /dev/null +++ b/oscar64/GlobalAnalyzer.cpp @@ -0,0 +1,400 @@ +#include "GlobalAnalyzer.h" + +GlobalAnalyzer::GlobalAnalyzer(Errors* errors, Linker* linker) + : mErrors(errors), mLinker(linker), mCalledFunctions(nullptr), mCallingFunctions(nullptr), mVariableFunctions(nullptr), mFunctions(nullptr) +{ + +} + +GlobalAnalyzer::~GlobalAnalyzer(void) +{ + +} + +void GlobalAnalyzer::DumpCallGraph(void) +{ + printf("------------------------------\n"); + + for (int i = 0; i < mFunctions.Size(); i++) + { + GrowingArray decs(nullptr); + GrowingArray calls(0); + + Declaration* from = mFunctions[i]; + for (int j = 0; j < from->mCalled.Size(); j++) + { + Declaration* to = from->mCalled[j]; + + int k = decs.IndexOf(to); + if (k == -1) + { + decs.Push(to); + calls.Push(1); + } + else + calls[k]++; + } + + if (decs.Size() > 0) + { + for (int j = 0; j < decs.Size(); j++) + { + printf("CALL %s[%d] -> %d -> %s[%d]\n", from->mIdent->mString, from->mComplexity, calls[j], decs[j]->mIdent->mString, decs[j]->mComplexity); + } + } + else + { + printf("LEAF %d -> %s[%d]\n", from->mCallers.Size(), from->mIdent->mString, from->mComplexity ); + } + } +} + +void GlobalAnalyzer::AutoInline(void) +{ + bool changed = false; + do + { + changed = false; + + for (int i = 0; i < mFunctions.Size(); i++) + { + Declaration* f = mFunctions[i]; + if (!(f->mFlags & DTF_INLINE) && !(f->mBase->mFlags & DTF_VARIADIC) && !(f->mFlags & DTF_FUNC_VARIABLE) && !(f->mFlags & DTF_FUNC_ASSEMBLER) && !(f->mFlags & DTF_INTRINSIC) && !(f->mFlags & DTF_FUNC_RECURSIVE)) + { + int nparams = 0; + Declaration* dec = f->mParams; + while (dec) + { + nparams++; + dec = dec->mNext; + } + + int cost = (f->mComplexity - 20 * nparams); + if (cost * (f->mCallers.Size() - 1) <= 0 || (f->mFlags & DTF_REQUEST_INLINE)) + //if (cost * (f->mCallers.Size() - 1) <= 1000 || (f->mFlags & DTF_REQUEST_INLINE)) + { + printf("INLINING %s %d * (%d - 1)\n", f->mIdent->mString, cost, f->mCallers.Size()); + f->mFlags |= DTF_INLINE; + for (int j = 0; j < f->mCallers.Size(); j++) + { + Declaration* cf = f->mCallers[j]; + + int sk = 0, dk = 0; + while (sk < cf->mCalled.Size()) + { + if (cf->mCalled[sk] == f) + { + cf->mComplexity += cost; + for (int m = 0; m < f->mCalled.Size(); m++) + { + cf->mCalled.Push(f->mCalled[m]); + f->mCalled[m]->mCallers.Push(cf); + } + } + else + cf->mCalled[dk++] = cf->mCalled[sk]; + sk++; + } + cf->mCalled.SetSize(dk); + } + + changed = true; + } + } + } + + } while (changed); + + + for (int i = 0; i < mFunctions.Size(); i++) + { + Declaration* f = mFunctions[i]; + if (!(f->mFlags & DTF_INLINE) && !(f->mBase->mFlags & DTF_VARIADIC) && !(f->mFlags & DTF_FUNC_VARIABLE) && !(f->mFlags & DTF_INTRINSIC) && f->mCalled.Size() == 0) + { + int nparams = 0; + Declaration* dec = f->mParams; + while (dec) + { + nparams += dec->mSize; + dec = dec->mNext; + } + + if (nparams <= 8) + { + f->mBase->mFlags |= DTF_FASTCALL; + printf("FASTCALL %s\n", f->mIdent->mString); + } + + } + } +} + +void GlobalAnalyzer::AnalyzeProcedure(Expression* exp, Declaration* dec) +{ + if (dec->mFlags & DTF_FUNC_ANALYZING) + dec->mFlags |= DTF_FUNC_RECURSIVE; + + if (!(dec->mFlags & DTF_ANALYZED)) + { + dec->mFlags |= DTF_FUNC_ANALYZING; + + mFunctions.Push(dec); + + dec->mFlags |= DTF_ANALYZED; + if (dec->mFlags & DTF_INTRINSIC) + ; + else if (dec->mFlags & DTF_DEFINED) + Analyze(exp, dec); + else + mErrors->Error(dec->mLocation, EERR_UNDEFINED_OBJECT, "Calling undefined function", dec->mIdent->mString); + + dec->mFlags &= ~DTF_FUNC_ANALYZING; + } +} + + +void GlobalAnalyzer::AnalyzeAssembler(Expression* exp, Declaration* procDec) +{ + while (exp) + { + if (procDec) + procDec->mComplexity += 2; + + if (exp->mLeft) + { + Declaration* adec = exp->mLeft->mDecValue; + if (adec->mType == DT_LABEL_REF) + { + + } + else if (adec->mType == DT_VARIABLE_REF) + { + if (adec->mBase->mFlags & DTF_GLOBAL) + AnalyzeGlobalVariable(adec->mBase); + } + else if (adec->mType == DT_LABEL) + { + + } + else if (adec->mType == DT_VARIABLE) + { + if (adec->mFlags & DTF_GLOBAL) + AnalyzeGlobalVariable(adec); + } + else if (adec->mType == DT_FUNCTION_REF) + { + AnalyzeProcedure(adec->mBase->mValue, adec->mBase); + RegisterProc(adec->mBase); + } + else if (adec->mType == DT_CONST_FUNCTION) + { + AnalyzeProcedure(adec->mValue, adec); + RegisterCall(adec, procDec); + } + } + + exp = exp->mRight; + } +} + +void GlobalAnalyzer::AnalyzeGlobalVariable(Declaration* dec) +{ + if (!(dec->mFlags & DTF_ANALYZED)) + { + dec->mFlags |= DTF_ANALYZED; + + if (dec->mValue) + { + Analyze(dec->mValue, dec); + } + } +} + +Declaration * GlobalAnalyzer::Analyze(Expression* exp, Declaration* procDec) +{ + Declaration* ldec, * rdec; + + procDec->mComplexity += 10; + + switch (exp->mType) + { + case EX_ERROR: + case EX_VOID: + break; + case EX_CONSTANT: + if (exp->mDecValue->mType == DT_CONST_FUNCTION) + AnalyzeProcedure(exp->mDecValue->mValue, exp->mDecValue); + else if (exp->mDecValue->mType == DT_CONST_STRUCT) + { + Declaration* mdec = exp->mDecValue->mParams; + while (mdec) + { + if (mdec->mValue) + RegisterProc(Analyze(mdec->mValue, mdec)); + mdec = mdec->mNext; + } + } + else if (exp->mDecValue->mType == DT_CONST_POINTER) + { + RegisterProc(Analyze(exp->mDecValue->mValue, procDec)); + } + else if (exp->mDecValue->mType == DT_CONST_ASSEMBLER) + { + AnalyzeAssembler(exp->mDecValue->mValue, procDec); + } + + return exp->mDecValue; + case EX_VARIABLE: + return exp->mDecValue; + case EX_ASSIGNMENT: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + RegisterProc(rdec); + break; + case EX_BINARY: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + break; + case EX_RELATIONAL: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + return TheBoolTypeDeclaration; + case EX_PREINCDEC: + return Analyze(exp->mLeft, procDec); + case EX_PREFIX: + break; + case EX_POSTFIX: + break; + case EX_POSTINCDEC: + return Analyze(exp->mLeft, procDec); + case EX_INDEX: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + return ldec->mBase; + case EX_QUALIFY: + Analyze(exp->mLeft, procDec); + return exp->mDecValue->mBase; + case EX_CALL: + ldec = Analyze(exp->mLeft, procDec); + RegisterCall(procDec, ldec); + if (exp->mRight) + RegisterProc(Analyze(exp->mRight, procDec)); + break; + case EX_LIST: + RegisterProc(Analyze(exp->mLeft, procDec)); + return Analyze(exp->mRight, procDec); + case EX_RETURN: + if (exp->mLeft) + RegisterProc(Analyze(exp->mLeft, procDec)); + break; + case EX_SEQUENCE: + do + { + ldec = Analyze(exp->mLeft, procDec); + exp = exp->mRight; + } while (exp); + break; + case EX_WHILE: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + break; + case EX_IF: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight->mLeft, procDec); + if (exp->mRight->mRight) + rdec = Analyze(exp->mRight->mRight, procDec); + break; + case EX_ELSE: + break; + case EX_FOR: + if (exp->mLeft->mRight) + ldec = Analyze(exp->mLeft->mRight, procDec); + if (exp->mLeft->mLeft->mLeft) + ldec = Analyze(exp->mLeft->mLeft->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + if (exp->mLeft->mLeft->mRight) + ldec = Analyze(exp->mLeft->mLeft->mRight, procDec); + break; + case EX_DO: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + break; + case EX_BREAK: + case EX_CONTINUE: + break; + case EX_TYPE: + break; + case EX_TYPECAST: + rdec = Analyze(exp->mRight, procDec); + break; + case EX_LOGICAL_AND: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + break; + case EX_LOGICAL_OR: + ldec = Analyze(exp->mLeft, procDec); + rdec = Analyze(exp->mRight, procDec); + break; + case EX_LOGICAL_NOT: + ldec = Analyze(exp->mLeft, procDec); + break; + case EX_ASSEMBLER: + procDec->mFlags |= DTF_FUNC_ASSEMBLER; + AnalyzeAssembler(exp, procDec); + break; + case EX_UNDEFINED: + break; + case EX_SWITCH: + ldec = Analyze(exp->mLeft, procDec); + exp = exp->mRight; + while (exp) + { + if (exp->mLeft->mRight) + rdec = Analyze(exp->mLeft->mRight, procDec); + exp = exp->mRight; + } + break; + case EX_CASE: + break; + case EX_DEFAULT: + break; + case EX_CONDITIONAL: + ldec = Analyze(exp->mLeft, procDec); + RegisterProc(Analyze(exp->mRight->mLeft, procDec)); + RegisterProc(Analyze(exp->mRight->mRight, procDec)); + break; + } + + return TheVoidTypeDeclaration; +} + +void GlobalAnalyzer::RegisterCall(Declaration* from, Declaration* to) +{ + if (from) + { + if (to->mType == DT_CONST_FUNCTION) + { + if (to->mCallers.Size() == 0) + mCalledFunctions.Push(to); + to->mCallers.Push(from); + if (from->mCalled.Size() == 0) + mCallingFunctions.Push(from); + from->mCalled.Push(to); + } + else if (to->mType == DT_TYPE_FUNCTION) + { + if (from->mCalled.Size() == 0) + mCallingFunctions.Push(from); + from->mCalled.Push(to); + } + } +} + +void GlobalAnalyzer::RegisterProc(Declaration* to) +{ + if (to->mType == DT_CONST_FUNCTION) + { + to->mFlags |= DTF_FUNC_VARIABLE; + mVariableFunctions.Push(to); + } +} diff --git a/oscar64/GlobalAnalyzer.h b/oscar64/GlobalAnalyzer.h new file mode 100644 index 0000000..8b533ff --- /dev/null +++ b/oscar64/GlobalAnalyzer.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Declaration.h" +#include "Linker.h" + +class GlobalAnalyzer +{ +public: + GlobalAnalyzer(Errors* errors, Linker* linker); + ~GlobalAnalyzer(void); + + void DumpCallGraph(void); + void AutoInline(void); + + void AnalyzeProcedure(Expression* exp, Declaration* procDec); + void AnalyzeAssembler(Expression* exp, Declaration* procDec); + void AnalyzeGlobalVariable(Declaration* dec); + +protected: + Errors* mErrors; + Linker* mLinker; + + GrowingArray mCalledFunctions, mCallingFunctions, mVariableFunctions, mFunctions; + + Declaration* Analyze(Expression* exp, Declaration* procDec); + + void RegisterCall(Declaration* from, Declaration* to); + void RegisterProc(Declaration* to); +}; + diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index 9e65f26..973cbed 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -673,6 +673,8 @@ void ValueSet::UpdateValue(InterInstruction * ins, const GrowingInstructionPtrAr case IT_POINTER: break; default: + assert(ins->mSrc[1].mType == IT_INT8 || ins->mSrc[1].mType == IT_INT16 || ins->mSrc[1].mType == IT_INT32); + if (ins->mSrc[1].mTemp >= 0 && tvalue[ins->mSrc[1].mTemp] && tvalue[ins->mSrc[1].mTemp]->mCode == IC_CONSTANT && ins->mSrc[0].mTemp >= 0 && tvalue[ins->mSrc[0].mTemp] && tvalue[ins->mSrc[0].mTemp]->mCode == IC_CONSTANT) { @@ -1199,10 +1201,12 @@ bool InterInstruction::PropagateConstTemps(const GrowingInstructionPtrArray& cte switch (mCode) { case IC_LOAD: + case IC_CALL: + case IC_CALL_NATIVE: if (mSrc[0].mTemp >= 0 && ctemps[mSrc[0].mTemp]) { InterInstruction* ains = ctemps[mSrc[0].mTemp]; - mSrc[0].mIntConst = ains->mConst.mIntConst; + mSrc[0].mIntConst += ains->mConst.mIntConst; mSrc[0].mLinkerObject = ains->mConst.mLinkerObject; mSrc[0].mVarIndex = ains->mConst.mVarIndex; mSrc[0].mMemory = ains->mConst.mMemory; @@ -1214,7 +1218,7 @@ bool InterInstruction::PropagateConstTemps(const GrowingInstructionPtrArray& cte if (mSrc[1].mTemp >= 0 && ctemps[mSrc[1].mTemp]) { InterInstruction* ains = ctemps[mSrc[1].mTemp]; - mSrc[1].mIntConst = ains->mConst.mIntConst; + mSrc[1].mIntConst += ains->mConst.mIntConst; mSrc[1].mLinkerObject = ains->mConst.mLinkerObject; mSrc[1].mVarIndex = ains->mConst.mVarIndex; mSrc[1].mMemory = ains->mConst.mMemory; @@ -1732,6 +1736,11 @@ InterCodeBasicBlock::~InterCodeBasicBlock(void) void InterCodeBasicBlock::Append(InterInstruction * code) { + if (code->mCode == IC_BINARY_OPERATOR) + { + assert(code->mSrc[1].mType != IT_POINTER); + } + assert(!(code->mInUse)); code->mInUse = true; this->mInstructions.Push(code); @@ -1843,7 +1852,7 @@ static void OptimizeAddress(InterInstruction * ins, const GrowingInstructionPtrA if (ains->mCode == IC_CONSTANT) { - ins->mSrc[offset].mIntConst = ains->mConst.mIntConst; + ins->mSrc[offset].mIntConst += ains->mConst.mIntConst; ins->mSrc[offset].mLinkerObject = ains->mConst.mLinkerObject; ins->mSrc[offset].mVarIndex = ains->mConst.mVarIndex; ins->mSrc[offset].mMemory = ains->mConst.mMemory; @@ -1851,16 +1860,18 @@ static void OptimizeAddress(InterInstruction * ins, const GrowingInstructionPtrA } else if (ains->mCode == IC_LEA && ains->mSrc[0].mTemp < 0 && ains->mSrc[1].mTemp >= 0 && tvalue[ains->mSrc[1].mTemp]) { - ins->mSrc[offset].mIntConst = ains->mSrc[0].mIntConst; + ins->mSrc[offset].mIntConst += ains->mSrc[0].mIntConst; ins->mSrc[offset].mTemp = ains->mSrc[1].mTemp; } else if (ains->mCode == IC_BINARY_OPERATOR && ains->mOperator == IA_ADD && ains->mSrc[0].mTemp < 0 && ains->mSrc[1].mTemp >= 0 && tvalue[ains->mSrc[1].mTemp] && ains->mSrc[0].mIntConst >= 0) { + assert(false); ins->mSrc[offset].mIntConst = ains->mSrc[0].mIntConst; ins->mSrc[offset].mTemp = ains->mSrc[1].mTemp; } else if (ains->mCode == IC_BINARY_OPERATOR && ains->mOperator == IA_ADD && ains->mSrc[1].mTemp < 0 && ains->mSrc[0].mTemp >= 0 && tvalue[ains->mSrc[0].mTemp] && ains->mSrc[1].mIntConst >= 0) { + assert(false); ins->mSrc[offset].mIntConst = ains->mSrc[1].mIntConst; ins->mSrc[offset].mTemp = ains->mSrc[0].mTemp; } @@ -3263,7 +3274,7 @@ void InterCodeBasicBlock::MapVariables(GrowingVariableArray& globalVars, Growing } } -void InterCodeBasicBlock::CollectOuterFrame(int level, int& size, bool &inner, bool &inlineAssembler) +void InterCodeBasicBlock::CollectOuterFrame(int level, int& size, bool &inner, bool &inlineAssembler, bool &byteCodeCall) { int i; @@ -3295,10 +3306,12 @@ void InterCodeBasicBlock::CollectOuterFrame(int level, int& size, bool &inner, b } else if (mInstructions[i]->mCode == IC_ASSEMBLER) inlineAssembler = true; + else if (mInstructions[i]->mCode == IC_CALL) + byteCodeCall = true; } - if (mTrueJump) mTrueJump->CollectOuterFrame(level, size, inner, inlineAssembler); - if (mFalseJump) mFalseJump->CollectOuterFrame(level, size, inner, inlineAssembler); + if (mTrueJump) mTrueJump->CollectOuterFrame(level, size, inner, inlineAssembler, byteCodeCall); + if (mFalseJump) mFalseJump->CollectOuterFrame(level, size, inner, inlineAssembler, byteCodeCall); } } @@ -3450,6 +3463,14 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa if (mLoopHead && mNumEntries == 2 && (mTrueJump == this || mFalseJump == this)) { + bool hasCall = false; + for (int i = 0; i < mInstructions.Size(); i++) + { + InterInstruction* ins = mInstructions[i]; + if (ins->mCode == IC_CALL || ins->mCode == IC_CALL_NATIVE) + hasCall = true; + } + for (int i = 0; i < mInstructions.Size(); i++) { InterInstruction* ins = mInstructions[i]; @@ -3463,6 +3484,10 @@ void InterCodeBasicBlock::SingleBlockLoopOptimisation(const NumberSet& aliasedPa { ins->mInvariant = false; } + else if (ins->mSrc[0].mMemory == IM_GLOBAL && hasCall) + { + ins->mInvariant = false; + } else { for (int j = 0; j < mInstructions.Size(); j++) @@ -4159,12 +4184,13 @@ void InterCodeProcedure::Close(void) mHasDynamicStack = false; mHasInlineAssembler = false; + mCallsByteCode = false; if (!mLeafProcedure) { int size = 0; ResetVisited(); - mEntryBlock->CollectOuterFrame(0, size, mHasDynamicStack, mHasInlineAssembler); + mEntryBlock->CollectOuterFrame(0, size, mHasDynamicStack, mHasInlineAssembler, mCallsByteCode); mCommonFrameSize = size; } else @@ -4458,6 +4484,20 @@ bool InterCodeProcedure::GlobalConstantPropagation(void) ResetVisited(); mEntryBlock->CollectConstTemps(ctemps, assignedTemps); + FILE* file; + fopen_s(&file, "r:\\cldiss.txt", "a"); + + for (int i = 0; i < assignedTemps.Size(); i++) + { + if (assignedTemps[i]) + { + if (ctemps[i]) + fprintf(file, "%d, ", i); + } + } + fprintf(file, "\n"); + fclose(file); + ResetVisited(); return mEntryBlock->PropagateConstTemps(ctemps); } diff --git a/oscar64/InterCode.h b/oscar64/InterCode.h index 3b295e4..f4c9620 100644 --- a/oscar64/InterCode.h +++ b/oscar64/InterCode.h @@ -483,7 +483,7 @@ public: void CollectVariables(GrowingVariableArray & globalVars, GrowingVariableArray & localVars); void MapVariables(GrowingVariableArray& globalVars, GrowingVariableArray& localVars); - void CollectOuterFrame(int level, int& size, bool& inner, bool& inlineAssembler); + void CollectOuterFrame(int level, int& size, bool& inner, bool& inlineAssembler, bool& byteCodeCall); bool IsLeafProcedure(void); @@ -511,7 +511,7 @@ public: GrowingTypeArray mTemporaries; GrowingIntArray mTempOffset, mTempSizes; int mTempSize, mCommonFrameSize, mCallerSavedTemps; - bool mLeafProcedure, mNativeProcedure, mCallsFunctionPointer, mHasDynamicStack, mHasInlineAssembler; + bool mLeafProcedure, mNativeProcedure, mCallsFunctionPointer, mHasDynamicStack, mHasInlineAssembler, mCallsByteCode; GrowingInterCodeProcedurePtrArray mCalledFunctions; InterCodeModule * mModule; diff --git a/oscar64/InterCodeGenerator.cpp b/oscar64/InterCodeGenerator.cpp index b431f29..8394029 100644 --- a/oscar64/InterCodeGenerator.cpp +++ b/oscar64/InterCodeGenerator.cpp @@ -756,7 +756,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* if (inlineMapper) { ins->mConst.mMemory = IM_LOCAL; - ins->mConst.mVarIndex = inlineMapper->mParams[dec->mOffset]; + ins->mConst.mVarIndex = inlineMapper->mParams[dec->mVarIndex]; } else if (procType->mFlags & DTF_FASTCALL) ins->mConst.mMemory = IM_FPARAM; @@ -1298,13 +1298,21 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* block->Append(cins); - ains->mCode = IC_BINARY_OPERATOR; - ains->mOperator = IA_ADD; + InterType ttype = InterTypeOf(vdl.mType); + if (ttype == IT_POINTER) + { + ains->mCode = IC_LEA; + } + else + { + ains->mCode = IC_BINARY_OPERATOR; + ains->mOperator = IA_ADD; + } ains->mSrc[0].mType = cins->mDst.mType; ains->mSrc[0].mTemp = cins->mDst.mTemp; - ains->mSrc[1].mType = InterTypeOf(vdl.mType); + ains->mSrc[1].mType = ttype; ains->mSrc[1].mTemp = vdl.mTemp; - ains->mDst.mType = ains->mSrc[1].mType; + ains->mDst.mType = ttype; ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); block->Append(ains); @@ -1349,14 +1357,22 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* mErrors->Error(exp->mLocation, EERR_INCOMPATIBLE_OPERATOR, "Not a numeric value or pointer"); block->Append(cins); - ains->mCode = IC_BINARY_OPERATOR; - ains->mOperator = IA_ADD; + InterType ttype = InterTypeOf(vdl.mType); + if (ttype == IT_POINTER) + { + ains->mCode = IC_LEA; + } + else + { + ains->mCode = IC_BINARY_OPERATOR; + ains->mOperator = IA_ADD; + } ains->mSrc[0].mType = cins->mDst.mType; ains->mSrc[0].mTemp = cins->mDst.mTemp; - ains->mSrc[1].mType = InterTypeOf(vdl.mType); + ains->mSrc[1].mType = ttype; ains->mSrc[1].mTemp = vdl.mTemp; - ains->mDst.mType = ains->mSrc[1].mType; - ains->mDst.mTemp = proc->AddTemporary(ains->mDst.mType); + ains->mDst.mType = ttype; + ains->mDst.mTemp = proc->AddTemporary(ttype); block->Append(ains); sins->mCode = IC_STORE; @@ -1588,7 +1604,7 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* return ExValue(TheVoidTypeDeclaration); } - else if (exp->mLeft->mType == EX_CONSTANT && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION && (exp->mLeft->mDecValue->mFlags & DTF_INLINE) && !(inlineMapper && inlineMapper->mDepth > 3)) + else if (exp->mLeft->mType == EX_CONSTANT && exp->mLeft->mDecValue->mType == DT_CONST_FUNCTION && (exp->mLeft->mDecValue->mFlags & DTF_INLINE) && !(inlineMapper && inlineMapper->mDepth > 10)) { Declaration* fdec = exp->mLeft->mDecValue; Expression* fexp = fdec->mValue; @@ -1965,13 +1981,18 @@ InterCodeGenerator::ExValue InterCodeGenerator::TranslateExpression(Declaration* Declaration* vdec = refvars[i]; if (vdec->mType == DT_ARGUMENT) { - if (procType->mFlags & DTF_FASTCALL) + vins->mConst.mVarIndex = vdec->mVarIndex; + if (inlineMapper) + { + vins->mConst.mMemory = IM_LOCAL; + vins->mConst.mVarIndex = inlineMapper->mParams[vdec->mVarIndex]; + } + else if (procType->mFlags & DTF_FASTCALL) vins->mConst.mMemory = IM_FPARAM; else vins->mConst.mMemory = IM_PARAM; vins->mConst.mOperandSize = vdec->mSize; vins->mConst.mIntConst = vdec->mOffset; - vins->mConst.mVarIndex = vdec->mVarIndex; } block->Append(vins); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index aa5db74..7176fbb 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -15,9 +15,10 @@ static const uint32 LIVE_CPU_REG_C = 0x00000008; static const uint32 LIVE_CPU_REG_Z = 0x00000010; static const uint32 LIVE_MEM = 0x00000020; +static int GlobalValueNumber = 0; NativeRegisterData::NativeRegisterData(void) - : mMode(NRDM_UNKNOWN) + : mMode(NRDM_UNKNOWN), mValue(GlobalValueNumber++) { } @@ -25,6 +26,7 @@ NativeRegisterData::NativeRegisterData(void) void NativeRegisterData::Reset(void) { mMode = NRDM_UNKNOWN; + mValue = GlobalValueNumber++; } void NativeRegisterDataSet::Reset(void) @@ -39,10 +41,57 @@ void NativeRegisterDataSet::ResetZeroPage(int addr) for (int i = 0; i < NUM_REGS; i++) { if (mRegs[i].mMode == NRDM_ZERO_PAGE && mRegs[i].mValue == addr) - mRegs[i].mMode = NRDM_UNKNOWN; + mRegs[i].Reset(); } } +void NativeRegisterDataSet::Intersect(const NativeRegisterDataSet& set) +{ + + for (int i = 0; i < NUM_REGS; i++) + { + if (mRegs[i].mMode == NRDM_UNKNOWN) + { + if (set.mRegs[i].mMode != NRDM_UNKNOWN || mRegs[i].mValue != set.mRegs[i].mValue) + mRegs[i].Reset(); + } + else if (mRegs[i].mMode == NRDM_IMMEDIATE) + { + if (set.mRegs[i].mMode != NRDM_IMMEDIATE || mRegs[i].mValue != set.mRegs[i].mValue) + mRegs[i].Reset(); + } + else if (mRegs[i].mMode == NRDM_IMMEDIATE_ADDRESS) + { + if (set.mRegs[i].mMode != NRDM_IMMEDIATE_ADDRESS || mRegs[i].mValue != set.mRegs[i].mValue || mRegs[i].mLinkerObject != set.mRegs[i].mLinkerObject || mRegs[i].mFlags != set.mRegs[i].mFlags) + mRegs[i].Reset(); + } + } + + bool changed; + do + { + changed = false; + + for (int i = 0; i < NUM_REGS; i++) + { + if (mRegs[i].mMode == NRDM_ZERO_PAGE) + { + if (set.mRegs[i].mMode != NRDM_ZERO_PAGE || mRegs[i].mValue != set.mRegs[i].mValue) + { + mRegs[i].Reset(); + changed = true; + } + else if (mRegs[mRegs[i].mValue].mValue != set.mRegs[set.mRegs[i].mValue].mValue) + { + mRegs[i].Reset(); + changed = true; + } + } + } + + } while (changed); +} + NativeCodeInstruction::NativeCodeInstruction(AsmInsType type, AsmInsMode mode, int address, LinkerObject* linkerObject, uint32 flags) : mType(type), mMode(mode), mAddress(address), mLinkerObject(linkerObject), mFlags(flags) {} @@ -448,7 +497,7 @@ bool NativeCodeInstruction::ChangesAccuAndFlag(void) const return mType == ASMIT_LDA || mType == ASMIT_TXA || mType == ASMIT_TYA || mType == ASMIT_ORA || mType == ASMIT_AND || mType == ASMIT_EOR || - mType == ASMIT_SBC || mType == ASMIT_ADC; + mType == ASMIT_SBC || mType == ASMIT_ADC || mType == ASMIT_JSR; } bool NativeCodeInstruction::RequiresYReg(void) const @@ -463,9 +512,26 @@ bool NativeCodeInstruction::RequiresYReg(void) const bool NativeCodeInstruction::ChangesYReg(void) const { - return mType == ASMIT_TAY || mType == ASMIT_LDY || mType == ASMIT_INY || mType == ASMIT_DEY; + return mType == ASMIT_TAY || mType == ASMIT_LDY || mType == ASMIT_INY || mType == ASMIT_DEY || mType == ASMIT_JSR; } +bool NativeCodeInstruction::ChangesZeroPage(int address) const +{ + if (mMode == ASMIM_ZERO_PAGE && mAddress == address) + return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY; + else + return false; +} + +bool NativeCodeInstruction::ChangesGlobalMemory(void) const +{ + if (mMode == ASMIM_INDIRECT_Y || mMode == ASMIM_ABSOLUTE || mMode == ASMIM_ABSOLUTE_X || mMode == ASMIM_ABSOLUTE_Y) + return mType == ASMIT_INC || mType == ASMIT_DEC || mType == ASMIT_ASL || mType == ASMIT_LSR || mType == ASMIT_ROL || mType == ASMIT_ROR || mType == ASMIT_STA || mType == ASMIT_STX || mType == ASMIT_STY || mType == ASMIT_JSR; + else + return false; +} + + bool NativeCodeInstruction::RequiresAccu(void) const { if (mMode == ASMIM_IMPLIED) @@ -578,6 +644,11 @@ bool NativeCodeInstruction::ApplySimulation(const NativeRegisterDataSet& data) case ASMIT_CMP: case ASMIT_CPX: case ASMIT_CPY: + case ASMIT_ADC: + case ASMIT_SBC: + case ASMIT_AND: + case ASMIT_ORA: + case ASMIT_EOR: if (mMode == ASMIM_ZERO_PAGE && data.mRegs[mAddress].mMode == NRDM_IMMEDIATE) { mMode = ASMIM_IMMEDIATE; @@ -1314,6 +1385,25 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data) break; case ASMIT_ADC: + if (data.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_C].mValue == 0) + { + if (mMode == ASMIM_IMMEDIATE && mAddress == 0) + { + mType = ASMIT_ORA; + changed = true; + } + else if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0) + { + mType = ASMIT_LDA; + changed = true; + } + } + + data.mRegs[CPU_REG_A].Reset(); + data.mRegs[CPU_REG_C].Reset(); + data.mRegs[CPU_REG_Z].Reset(); + break; + case ASMIT_SBC: data.mRegs[CPU_REG_A].Reset(); data.mRegs[CPU_REG_C].Reset(); @@ -1377,6 +1467,7 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data) data.mRegs[CPU_REG_A].mValue = mAddress; data.mRegs[CPU_REG_Z].mMode = NRDM_IMMEDIATE; data.mRegs[CPU_REG_Z].mValue = mAddress; + changed = true; } else if (data.mRegs[CPU_REG_A].mMode == NRDM_IMMEDIATE && data.mRegs[CPU_REG_A].mValue == 0) { @@ -1391,6 +1482,7 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data) mMode = ASMIM_IMMEDIATE; mAddress = 0; } + changed = true; } else { @@ -1715,6 +1807,13 @@ bool NativeCodeInstruction::ValueForwarding(NativeRegisterDataSet& data) break; } } + else if (mMode == ASMIM_INDIRECT_Y) + { + if (data.mRegs[mAddress].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress + 1].mMode == NRDM_ZERO_PAGE && data.mRegs[mAddress].mValue + 1 == data.mRegs[mAddress + 1].mValue) + { + mAddress = data.mRegs[mAddress].mValue; + } + } return changed; } @@ -1968,7 +2067,7 @@ void NativeCodeInstruction::Assemble(NativeCodeBasicBlock* block) { if (mType == ASMIT_BYTE) block->PutByte(mAddress); - else if (mType == ASMIT_JSR && (mLinkerObject->mFlags & LOBJF_INLINE)) + else if (mType == ASMIT_JSR && mLinkerObject && (mLinkerObject->mFlags & LOBJF_INLINE)) { int pos = block->mCode.Size(); for (int i = 0; i < mLinkerObject->mSize - 1; i++) @@ -3769,6 +3868,7 @@ int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProc switch (lmul) { +#if 1 case 1: ShiftRegisterLeft(proc, BC_REG_ACCU, lshift); return BC_REG_ACCU; @@ -3806,7 +3906,47 @@ int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProc mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); ShiftRegisterLeft(proc, BC_REG_ACCU, lshift); return BC_REG_ACCU; -#if 0 + case 7: + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + ShiftRegisterLeft(proc, BC_REG_ACCU, lshift); + return BC_REG_ACCU; + case 9: + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_TAX, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_TXA, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_ROL, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_WORK + 0)); + mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); + ShiftRegisterLeft(proc, BC_REG_ACCU, lshift); + return BC_REG_ACCU; +#if 1 case 25: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 0)); mIns.Push(NativeCodeInstruction(ASMIT_ASL, ASMIM_IMPLIED)); @@ -3836,6 +3976,7 @@ int NativeCodeBasicBlock::ShortMultiply(InterCodeProcedure* proc, NativeCodeProc mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_ACCU + 1)); ShiftRegisterLeft(proc, BC_REG_ACCU, lshift); return BC_REG_ACCU; +#endif #endif default: mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE, mul)); @@ -6320,6 +6461,9 @@ bool NativeCodeBasicBlock::RemoveUnusedResultInstructions(void) void NativeCodeBasicBlock::CountEntries(NativeCodeBasicBlock * fromJump) { + if (mVisiting) + mLoopHead = true; + if (mNumEntries == 0) mFromJump = fromJump; else @@ -6329,11 +6473,14 @@ void NativeCodeBasicBlock::CountEntries(NativeCodeBasicBlock * fromJump) if (!mVisited) { mVisited = true; + mVisiting = true; if (mTrueJump) mTrueJump->CountEntries(this); if (mFalseJump) mFalseJump->CountEntries(this); + + mVisiting = false; } } @@ -6408,15 +6555,15 @@ void NativeCodeBasicBlock::BuildEntryDataSet(const NativeRegisterDataSet& set) { mVisited = true; - NativeRegisterDataSet nset = mEntryRegisterDataSet; + mNDataSet = mEntryRegisterDataSet; for (int i = 0; i < mIns.Size(); i++) - mIns[i].Simulate(nset); + mIns[i].Simulate(mNDataSet); if (mTrueJump) - mTrueJump->BuildEntryDataSet(nset); + mTrueJump->BuildEntryDataSet(mNDataSet); if (mFalseJump) - mFalseJump->BuildEntryDataSet(nset); + mFalseJump->BuildEntryDataSet(mNDataSet); } } @@ -6428,13 +6575,13 @@ bool NativeCodeBasicBlock::ApplyEntryDataSet(void) { mVisited = true; - NativeRegisterDataSet nset = mEntryRegisterDataSet; + mNDataSet = mEntryRegisterDataSet; for (int i = 0; i < mIns.Size(); i++) { - if (mIns[i].ApplySimulation(nset)) + if (mIns[i].ApplySimulation(mNDataSet)) changed = true; - mIns[i].Simulate(nset); + mIns[i].Simulate(mNDataSet); } if (mTrueJump && mTrueJump->ApplyEntryDataSet()) @@ -6627,6 +6774,35 @@ bool NativeCodeBasicBlock::FindAddressSumY(int at, int reg, int & apos, int& bre return false; } +bool NativeCodeBasicBlock::MoveIndirectLoadStoreUp(int at) +{ + int j = at - 1; + while (j > 0) + { + if (mIns[j].mType == ASMIT_STA && mIns[j].mMode == ASMIM_ZERO_PAGE && mIns[j].mAddress == mIns[at].mAddress) + { + mIns.Insert(j + 1, mIns[at + 1]); + mIns.Insert(j + 2, mIns[at + 3]); + mIns[at + 4].mType = ASMIT_NOP; + mIns[at + 4].mMode = ASMIM_IMPLIED; + return true; + } + + if (mIns[j].ChangesYReg()) + return false; + if (mIns[j].ChangesZeroPage(mIns[at].mAddress)) + return false; + if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress)) + return false; + if (mIns[j].ChangesZeroPage(mIns[at + 2].mAddress + 1)) + return false; + + j--; + } + + return false; +} + bool NativeCodeBasicBlock::MoveLoadStoreUp(int at) { int j = at; @@ -6664,16 +6840,37 @@ bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data) if (!mVisited) { - mVisited = true; + mNDataSet = data; - NativeRegisterDataSet ndata(data); - - if (mNumEntries != 1) + if (mLoopHead) + { + mNDataSet.Reset(); + } +#if 0 + else if (mNumEntries != 1) + { ndata.Reset(); + } +#endif + else if (mNumEntries > 0) + { + if (mNumEntered > 0) + mNDataSet.Intersect(mDataSet); + + mNumEntered++; + + if (mNumEntered < mNumEntries) + { + mDataSet = mNDataSet; + return false; + } + } + + mVisited = true; for (int i = 0; i < mIns.Size(); i++) { - if (mIns[i].ValueForwarding(ndata)) + if (mIns[i].ValueForwarding(mNDataSet)) changed = true; } @@ -6682,60 +6879,60 @@ bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data) switch (mBranch) { case ASMIT_BCS: - if (ndata.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) + if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) { mBranch = ASMIT_JMP; - if (!ndata.mRegs[CPU_REG_C].mValue) + if (!mNDataSet.mRegs[CPU_REG_C].mValue) mTrueJump = mFalseJump; mFalseJump = nullptr; changed = true; } break; case ASMIT_BCC: - if (ndata.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) + if (mNDataSet.mRegs[CPU_REG_C].mMode == NRDM_IMMEDIATE) { mBranch = ASMIT_JMP; - if (ndata.mRegs[CPU_REG_C].mValue) + if (mNDataSet.mRegs[CPU_REG_C].mValue) mTrueJump = mFalseJump; mFalseJump = nullptr; changed = true; } break; case ASMIT_BNE: - if (ndata.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) + if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) { mBranch = ASMIT_JMP; - if (!ndata.mRegs[CPU_REG_Z].mValue) + if (!mNDataSet.mRegs[CPU_REG_Z].mValue) mTrueJump = mFalseJump; mFalseJump = nullptr; changed = true; } break; case ASMIT_BEQ: - if (ndata.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) + if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) { mBranch = ASMIT_JMP; - if (ndata.mRegs[CPU_REG_Z].mValue) + if (mNDataSet.mRegs[CPU_REG_Z].mValue) mTrueJump = mFalseJump; mFalseJump = nullptr; changed = true; } break; case ASMIT_BPL: - if (ndata.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) + if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) { mBranch = ASMIT_JMP; - if ((ndata.mRegs[CPU_REG_Z].mValue & 0x80)) + if ((mNDataSet.mRegs[CPU_REG_Z].mValue & 0x80)) mTrueJump = mFalseJump; mFalseJump = nullptr; changed = true; } break; case ASMIT_BMI: - if (ndata.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) + if (mNDataSet.mRegs[CPU_REG_Z].mMode == NRDM_IMMEDIATE) { mBranch = ASMIT_JMP; - if (!(ndata.mRegs[CPU_REG_Z].mValue & 0x80)) + if (!(mNDataSet.mRegs[CPU_REG_Z].mValue & 0x80)) mTrueJump = mFalseJump; mFalseJump = nullptr; changed = true; @@ -6744,9 +6941,9 @@ bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data) } } - if (this->mTrueJump && this->mTrueJump->ValueForwarding(ndata)) + if (this->mTrueJump && this->mTrueJump->ValueForwarding(mNDataSet)) changed = true; - if (this->mFalseJump && this->mFalseJump->ValueForwarding(ndata)) + if (this->mFalseJump && this->mFalseJump->ValueForwarding(mNDataSet)) changed = true; } @@ -7074,6 +7271,22 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) } } #endif + +#if 1 + // move load - store (),y up to initial store + // + + for (int i = 2; i + 2 < mIns.Size(); i++) + { + if (mIns[i].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mType == ASMIT_STA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y) + { + if (MoveIndirectLoadStoreUp(i)) + changed = true; + } + } +#endif + + // // shorten x/y register livetime #if 1 @@ -7267,6 +7480,18 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) mIns[i + 1].mMode = ASMIM_IMPLIED; progress = true; } + else if (mIns[i + 1].mType == ASMIT_ORA && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i].ChangesAccuAndFlag()) + { + mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z); + mIns[i + 1].mType = ASMIT_NOP; + progress = true; + } + else if (mIns[i + 1].mType == ASMIT_CMP && mIns[i + 1].mMode == ASMIM_IMMEDIATE && mIns[i + 1].mAddress == 0 && mIns[i].ChangesAccuAndFlag() && !(mIns[i + 1].mLive & LIVE_CPU_REG_C)) + { + mIns[i + 0].mLive |= (mIns[i + 1].mLive & LIVE_CPU_REG_Z); + mIns[i + 1].mType = ASMIT_NOP; + progress = true; + } else if ( mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress && (mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ASL || mIns[i + 1].mType == ASMIT_ROL || mIns[i + 1].mType == ASMIT_ROR)) @@ -7376,6 +7601,16 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z); progress = true; } + else if ( + mIns[i + 0].ChangesAccuAndFlag() && + mIns[i + 1].mType == ASMIT_STA && + mIns[i + 2].mType == ASMIT_CMP && mIns[i + 2].mMode == ASMIM_IMMEDIATE && mIns[i + 2].mAddress == 0 && !(mIns[i + 2].mLive & LIVE_CPU_REG_C)) + { + mIns[i + 2].mType = ASMIT_NOP; mIns[i + 2].mMode = ASMIM_IMPLIED; + mIns[i + 0].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z); + mIns[i + 1].mLive |= mIns[i + 2].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z); + progress = true; + } else if ( mIns[i + 0].mType == ASMIT_LDA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && (mIns[i + 1].mType == ASMIT_ASL || mIns[i + 1].mType == ASMIT_LSR || mIns[i + 1].mType == ASMIT_ROL || mIns[i + 1].mType == ASMIT_ROR) && @@ -7879,6 +8114,10 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) int tempSave = proc->mTempSize > 16 ? proc->mTempSize - 16 : 0; int stackExpand = tempSave + proc->mLocalSize; + int commonFrameSize = proc->mCommonFrameSize; + + if (proc->mCallsByteCode || commonFrameSize > 0) + commonFrameSize += 2; mFrameOffset = 0; mNoFrame = (stackExpand + proc->mCommonFrameSize) < 64 && !proc->mHasDynamicStack && !(proc->mHasInlineAssembler && !proc->mLeafProcedure); @@ -7966,16 +8205,19 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) if (!proc->mLeafProcedure) { - entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); - entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); - entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (proc->mCommonFrameSize + 2) & 0xff)); - entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); - entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); - entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, ((proc->mCommonFrameSize + 2) >> 8) & 0xff)); - entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); + if (commonFrameSize > 0) + { + entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SEC, ASMIM_IMPLIED)); + entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); + entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, commonFrameSize & 0xff)); + entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); + entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); + entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_SBC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff)); + entryBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); + } if (mNoFrame) - mFrameOffset = proc->mCommonFrameSize + tempSave + 2; + mFrameOffset = commonFrameSize + tempSave; } entryBlock->mFrameOffset = mFrameOffset; @@ -7985,14 +8227,14 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) exitBlock = AllocateBlock(); mBlocks.Push(exitBlock); - if (!proc->mLeafProcedure) + if (!proc->mLeafProcedure && commonFrameSize > 0) { exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_CLC, ASMIM_IMPLIED)); exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK)); - exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (proc->mCommonFrameSize + 2) & 0xff)); + exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, commonFrameSize & 0xff)); exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK)); exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); - exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, ((proc->mCommonFrameSize + 2) >> 8) & 0xff)); + exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, (commonFrameSize >> 8) & 0xff)); exitBlock->mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_STACK + 1)); } @@ -8060,6 +8302,8 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) CompileInterBlock(proc, proc->mBlocks[0], entryBlock); #if 1 + int step = 0; + bool changed; do { @@ -8067,6 +8311,8 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) for (int i = 0; i < mBlocks.Size(); i++) { mBlocks[i]->mNumEntries = 0; + mBlocks[i]->mVisiting = false; + mBlocks[i]->mLoopHead = false; mBlocks[i]->mFromJump = nullptr; } entryBlock->CountEntries(nullptr); @@ -8101,9 +8347,12 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) mBlocks[i]->mEntryBlocks.SetSize(0); entryBlock->CollectEntryBlocks(nullptr); - ResetVisited(); - if (entryBlock->JoinTailCodeSequences()) - changed = true; + if (step > 2) + { + ResetVisited(); + if (entryBlock->JoinTailCodeSequences()) + changed = true; + } ResetVisited(); NativeRegisterDataSet data; @@ -8113,6 +8362,11 @@ void NativeCodeProcedure::Compile(InterCodeProcedure* proc) if (entryBlock->ApplyEntryDataSet()) changed = true; + if (!changed && step < 4) + { + step++; + changed = true; + } } while (changed); #endif @@ -8198,7 +8452,10 @@ void NativeCodeProcedure::ResetVisited(void) int i; for (i = 0; i < mBlocks.Size(); i++) + { mBlocks[i]->mVisited = false; + mBlocks[i]->mNumEntered = 0; + } } @@ -8517,6 +8774,9 @@ NativeCodeGenerator::Runtime& NativeCodeGenerator::ResolveRuntime(const Ident* i int i = 0; while (i < mRuntime.Size() && mRuntime[i].mIdent != ident) i++; + Location loc; + if (i == mRuntime.Size() || !mRuntime[i].mLinkerObject) + mErrors->Error(loc, EERR_RUNTIME_CODE, "Undefied runtime function", ident->mString); return mRuntime[i]; } diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index c816e0e..c6a8b99 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -34,6 +34,7 @@ struct NativeRegisterDataSet void Reset(void); void ResetZeroPage(int addr); + void Intersect(const NativeRegisterDataSet& set); }; @@ -70,6 +71,8 @@ public: bool RequiresAccu(void) const; bool RequiresYReg(void) const; bool ChangesYReg(void) const; + bool ChangesZeroPage(int address) const; + bool ChangesGlobalMemory(void) const; bool SameEffectiveAddress(const NativeCodeInstruction& ins) const; bool IsSame(const NativeCodeInstruction& ins) const; bool IsCommutative(void) const; @@ -92,8 +95,10 @@ public: GrowingArray mEntryBlocks; - int mOffset, mSize, mNumEntries, mFrameOffset; - bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame, mVisited; + int mOffset, mSize, mNumEntries, mNumEntered, mFrameOffset; + bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mNoFrame, mVisited, mLoopHead, mVisiting; + + NativeRegisterDataSet mDataSet, mNDataSet; int PutBranch(NativeCodeProcedure* proc, AsmInsType code, int offset); int PutJump(NativeCodeProcedure* proc, int offset); @@ -147,8 +152,10 @@ public: void CountEntries(NativeCodeBasicBlock* fromJump); bool MergeBasicBlocks(void); + void MarkLoopHead(void); bool MoveLoadStoreUp(int at); + bool MoveIndirectLoadStoreUp(int at); bool FindAddressSumY(int at, int reg, int & apos, int& breg, int& ireg); bool FindGlobalAddress(int at, int reg, int& apos); bool FindGlobalAddressSumY(int at, int reg, const NativeCodeInstruction * & ains, int& ireg); diff --git a/oscar64/Parser.cpp b/oscar64/Parser.cpp index d7f4d96..b2ec04b 100644 --- a/oscar64/Parser.cpp +++ b/oscar64/Parser.cpp @@ -704,13 +704,7 @@ Declaration* Parser::ParseDeclaration(bool variable) if (mScanner->mToken == TK_INLINE) { - storageFlags |= DTF_INLINE; - mScanner->NextToken(); - } - - if (mScanner->mToken == TK_FASTCALL) - { - typeFlags |= DTF_FASTCALL; + storageFlags |= DTF_REQUEST_INLINE; mScanner->NextToken(); } } @@ -785,6 +779,18 @@ Declaration* Parser::ParseDeclaration(bool variable) ndec = pdec; } + else if ((ndec->mFlags & DTF_EXTERN) || (pdec->mFlags & DTF_EXTERN)) + { + if (!ndec->mBase->IsSame(pdec->mBase)) + { + mErrors->Error(ndec->mLocation, EERR_DECLARATION_DIFFERS, "Variable declaration differs"); + } + + if (!(ndec->mFlags & DTF_EXTERN)) + pdec->mFlags &= ~DTF_EXTERN; + + ndec = pdec; + } else mErrors->Error(ndec->mLocation, EERR_DUPLICATE_DEFINITION, "Duplicate variable declaration", ndec->mIdent->mString); } diff --git a/oscar64/Scanner.cpp b/oscar64/Scanner.cpp index d5a2ca9..718bc1c 100644 --- a/oscar64/Scanner.cpp +++ b/oscar64/Scanner.cpp @@ -46,7 +46,6 @@ const char* TokenNames[] = { "'static'", "'extern'", "'inline'", - "'__fastcall'", "__asm", @@ -1152,8 +1151,6 @@ void Scanner::NextRawToken(void) mToken = TK_EXTERN; else if (!strcmp(tkident, "inline")) mToken = TK_INLINE; - else if (!strcmp(tkident, "__fastcall")) - mToken = TK_FASTCALL; else if (!strcmp(tkident, "__asm")) mToken = TK_ASM; else diff --git a/oscar64/Scanner.h b/oscar64/Scanner.h index c33cecd..32bcf88 100644 --- a/oscar64/Scanner.h +++ b/oscar64/Scanner.h @@ -45,7 +45,6 @@ enum Token TK_STATIC, TK_EXTERN, TK_INLINE, - TK_FASTCALL, TK_ASM, diff --git a/oscar64/oscar64.vcxproj b/oscar64/oscar64.vcxproj index 0a1c27c..57b2040 100644 --- a/oscar64/oscar64.vcxproj +++ b/oscar64/oscar64.vcxproj @@ -149,6 +149,7 @@ + @@ -171,6 +172,7 @@ + diff --git a/oscar64/oscar64.vcxproj.filters b/oscar64/oscar64.vcxproj.filters index b37d7f7..35735e8 100644 --- a/oscar64/oscar64.vcxproj.filters +++ b/oscar64/oscar64.vcxproj.filters @@ -69,6 +69,9 @@ Source Files + + Source Files + @@ -137,6 +140,9 @@ Header Files + + Header Files +