diff --git a/.gitignore b/.gitignore index bd9263c..bfdba7c 100644 --- a/.gitignore +++ b/.gitignore @@ -341,3 +341,4 @@ ASALocalRun/ *.lbl make/oscar64 *.int +*.bcs diff --git a/include/crt.c b/include/crt.c index 0033a41..49e3ff4 100644 --- a/include/crt.c +++ b/include/crt.c @@ -920,6 +920,39 @@ inp_load_addr_8: #pragma bytecode(BC_LOAD_ABS_8, inp_load_abs_8) #pragma bytecode(BC_LOAD_ADDR_8, inp_load_abs_8.inp_load_addr_8) + +__asm inp_load_abs_u8 +{ + lda (ip), y + sta addr + iny + lda (ip), y + sta addr + 1 + iny + lda (ip), y + tax + sty tmpy + ldy #0 +L0: + lda (addr), y + sta $00, x + lda #0 + sta $01, x + ldy tmpy + iny + jmp startup.exec +inp_load_addr_u8: + lda (ip), y + tax + iny + lda (ip), y + sty tmpy + tay + jmp L0 +} + +#pragma bytecode(BC_LOAD_ABS_U8, inp_load_abs_u8) +#pragma bytecode(BC_LOAD_ADDR_U8, inp_load_abs_u8.inp_load_addr_u8) __asm inp_load_abs_16 { @@ -1142,6 +1175,25 @@ __asm inp_lea_abs_index #pragma bytecode(BC_LEA_ABS_INDEX, inp_lea_abs_index) +__asm inp_lea_abs_index_u8 +{ + lda (ip), y + tax + iny + clc + lda $00, x + adc (ip), y + sta addr + iny + lda #$00 + adc (ip), y + sta addr + 1 + iny + jmp startup.exec +} + +#pragma bytecode(BC_LEA_ABS_INDEX_U8, inp_lea_abs_index_u8) + __asm inp_load_local_16 { lda (ip), y diff --git a/include/crt.h b/include/crt.h index caea93b..8b03994 100644 --- a/include/crt.h +++ b/include/crt.h @@ -23,6 +23,7 @@ enum ByteCode BC_STORE_REG_32, BC_LOAD_ABS_8, + BC_LOAD_ABS_U8, BC_LOAD_ABS_16, BC_LOAD_ABS_32, @@ -32,6 +33,7 @@ enum ByteCode BC_LEA_ABS, BC_LEA_ABS_INDEX, + BC_LEA_ABS_INDEX_U8, BC_LOAD_LOCAL_8, BC_LOAD_LOCAL_16, @@ -50,6 +52,7 @@ enum ByteCode BC_LEA_FRAME, BC_LOAD_ADDR_8, + BC_LOAD_ADDR_U8, BC_LOAD_ADDR_16, BC_LOAD_ADDR_32, diff --git a/oscar64/Array.h b/oscar64/Array.h index 9132ac8..c2279ef 100644 --- a/oscar64/Array.h +++ b/oscar64/Array.h @@ -277,6 +277,25 @@ public: Grow(size, clear); } + void Reserve(int to) + { + if (to > range) + { + range = to; + + T* a2 = new T[range]; + if (to > size) + for (int i = 0; i < size; i++) a2[i] = array[i]; + else + for (int i = 0; i < to; i++) a2[i] = array[i]; + + delete[] array; + array = a2; + + for (int i = size; i < range; i++) array[i] = empty; + } + } + void Clear(void) { Grow(size, true); diff --git a/oscar64/ByteCodeGenerator.cpp b/oscar64/ByteCodeGenerator.cpp index 1c2c5a6..58140f4 100644 --- a/oscar64/ByteCodeGenerator.cpp +++ b/oscar64/ByteCodeGenerator.cpp @@ -1,6 +1,171 @@ #include "ByteCodeGenerator.h" #include "Assembler.h" +static const char* ByteCodeNames[] = { + "NOP", + "EXIT", + + "CONST_8", + "CONST_P8", + "CONST_N8", + "CONST_16", + "CONST_32", + + "LOAD_REG_8", + "STORE_REG_8", + "LOAD_REG_16", + "STORE_REG_16", + "ADDR_REG", + "LOAD_REG_32", + "STORE_REG_32", + + "LOAD_ABS_8", + "LOAD_ABS_U8", + "LOAD_ABS_16", + "LOAD_ABS_32", + + "STORE_ABS_8", + "STORE_ABS_16", + "STORE_ABS_32", + + "LEA_ABS", + "LEA_ABS_INDEX", + "LEA_ABS_INDEX_U8", + + "LOAD_LOCAL_8", + "LOAD_LOCAL_16", + "LOAD_LOCAL_32", + + "STORE_LOCAL_8", + "STORE_LOCAL_16", + "STORE_LOCAL_32", + + "LEA_LOCAL", + + "STORE_FRAME_8", + "STORE_FRAME_16", + "STORE_FRAME_32", + + "LEA_FRAME", + + "LOAD_ADDR_8", + "LOAD_ADDR_U8", + "LOAD_ADDR_16", + "LOAD_ADDR_32", + + "STORE_ADDR_8", + "STORE_ADDR_16", + "STORE_ADDR_32", + + "BINOP_ADDR_16", + "BINOP_SUBR_16", + "BINOP_ANDR_16", + "BINOP_ORR_16", + "BINOP_XORR_16", + "BINOP_MULR_16", + "BINOP_DIVR_U16", + "BINOP_MODR_U16", + "BINOP_DIVR_I16", + "BINOP_MODR_I16", + "BINOP_SHLR_16", + "BINOP_SHRR_U16", + "BINOP_SHRR_I16", + + "BINOP_ADDI_16", + "BINOP_SUBI_16", + "BINOP_ANDI_16", + "BINOP_ORI_16", + "BINOP_MULI8_16", + + "BINOP_ADDI_8", + "BINOP_ANDI_8", + "BINOP_ORI_8", + + "BINOP_SHLI_16", + "BINOP_SHRI_U16", + "BINOP_SHRI_I16", + + "BINOP_CMPUR_16", + "BINOP_CMPSR_16", + + "BINOP_CMPUI_16", + "BINOP_CMPSI_16", + + "BINOP_CMPUR_8", + "BINOP_CMPSR_8", + + "BINOP_CMPUI_8", + "BINOP_CMPSI_8", + + "OP_NEGATE_16", + "OP_INVERT_16", + + "BINOP_ADD_F32", + "BINOP_SUB_F32", + "BINOP_MUL_F32", + "BINOP_DIV_F32", + "BINOP_CMP_F32", + "OP_NEGATE_F32", + "OP_ABS_F32", + "OP_FLOOR_F32", + "OP_CEIL_F32", + + "CONV_U16_F32", + "CONV_I16_F32", + "CONV_F32_U16", + "CONV_F32_I16", + + "CONV_I8_I16", + + "JUMPS", + "BRANCHS_EQ", + "BRANCHS_NE", + "BRANCHS_GT", + "BRANCHS_GE", + "BRANCHS_LT", + "BRANCHS_LE", + + "JUMPF", + "BRANCHF_EQ", + "BRANCHF_NE", + "BRANCHF_GT", + "BRANCHF_GE", + "BRANCHF_LT", + "BRANCHF_LE", + + "SET_EQ", + "SET_NE", + "SET_GT", + "SET_GE", + "SET_LT", + "SET_LE", + + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + + "NATIVE", + + "ENTER", + "RETURN", + "CALL", + "PUSH_FRAME", + "POP_FRAME", + + "JSR", + + "COPY", + "COPY_LONG", + "STRCPY", + + "EXTRT" +}; + + static ByteCode StoreTypedTmpCodes[] = { BC_NOP, BC_STORE_REG_8, @@ -70,6 +235,11 @@ bool ByteCodeInstruction::ChangesAccu(void) const return ChangesRegister(BC_REG_ACCU); } +bool ByteCodeInstruction::UsesAccu(void) const +{ + return UsesRegister(BC_REG_ACCU); +} + bool ByteCodeInstruction::ChangesAddr(void) const { return ChangesRegister(BC_REG_ADDR); @@ -166,6 +336,76 @@ bool ByteCodeInstruction::StoresRegister(uint32 reg) const } +bool ByteCodeInstruction::UsesRegister(uint32 reg) const +{ + if (StoresRegister(reg)) + return true; + + if (mRegister == reg) + { + if (mCode == BC_LOAD_REG_8 || mCode == BC_LOAD_REG_16 || mCode == BC_LOAD_REG_32 || mCode == BC_ADDR_REG || mCode == BC_LEA_ABS_INDEX || mCode == BC_LEA_ABS_INDEX_U8) + return true; + + if (mCode >= BC_BINOP_ADDI_16 && mCode <= BC_BINOP_ORI_8) + return true; + + if (mCode >= BC_BINOP_ADDR_16 && mCode <= BC_BINOP_SHRR_I16) + return true; + + if (mCode == BC_BINOP_CMPUR_16 || mCode == BC_BINOP_CMPSR_16) + return true; + + if (mCode == BC_BINOP_CMPUR_8 || mCode == BC_BINOP_CMPSR_8) + return true; + + if (mCode >= BC_BINOP_ADD_F32 && mCode <= BC_BINOP_CMP_F32) + return true; + + if (mCode >= BC_BINOP_ADD_L32 && mCode <= BC_BINOP_CMP_S32) + return true; + } + + if (reg == BC_REG_ACCU) + { + if (mCode == BC_STORE_REG_8 || mCode == BC_STORE_REG_16 || mCode == BC_STORE_REG_32) + return true; + + if (mCode >= BC_BINOP_ADDR_16 && mCode <= BC_BINOP_SHRR_I16) + return true; + if (mCode >= BC_BINOP_CMPUR_16 && mCode <= BC_BINOP_CMPSI_16) + return true; + if (mCode >= BC_BINOP_CMPUR_8 && mCode <= BC_BINOP_CMPSI_8) + return true; + if (mCode >= BC_OP_NEGATE_16 && mCode <= BC_OP_INVERT_16) + return true; + if (mCode >= BC_BINOP_ADD_F32 && mCode <= BC_OP_CEIL_F32) + return true; + if (mCode >= BC_CONV_U16_F32 && mCode <= BC_CONV_F32_I16) + return true; + if (mCode >= BC_BINOP_SHLI_16 && mCode <= BC_BINOP_SHRI_I16) + return true; + if (mCode >= BC_SET_EQ && mCode <= BC_SET_LE) + return true; + if (mCode >= BC_CONV_I16_I32 && mCode <= BC_BINOP_CMP_S32) + return true; + } + + if (reg == BC_REG_ADDR) + { + if (mCode >= BC_LOAD_ADDR_8 && mCode <= BC_LOAD_ADDR_32) + return true; + + if (mCode >= BC_LOAD_ADDR_8 && mCode <= BC_STORE_ADDR_32) + return true; + + if (mCode == BC_JSR || mCode == BC_CALL) + return true; + } + + return false; +} + + bool ByteCodeInstruction::ChangesRegister(uint32 reg) const { if (mRegister == reg) @@ -222,7 +462,7 @@ bool ByteCodeInstruction::ChangesRegister(uint32 reg) const return true; if (mCode == BC_JSR || mCode == BC_CALL) return true; - if (mCode == BC_LEA_ABS_INDEX) + if (mCode == BC_LEA_ABS_INDEX || mCode == BC_LEA_ABS_INDEX_U8) return true; } @@ -288,6 +528,7 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl break; case BC_LOAD_ABS_8: + case BC_LOAD_ABS_U8: case BC_LOAD_ABS_16: case BC_LOAD_ABS_32: case BC_STORE_ABS_8: @@ -312,6 +553,7 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl case BC_LEA_ABS: case BC_LEA_ABS_INDEX: + case BC_LEA_ABS_INDEX_U8: block->PutCode(generator, mCode); block->PutByte(mRegister); if (mRelocate) { @@ -497,6 +739,7 @@ void ByteCodeInstruction::Assemble(ByteCodeGenerator* generator, ByteCodeBasicBl } break; case BC_LOAD_ADDR_8: + case BC_LOAD_ADDR_U8: case BC_LOAD_ADDR_16: case BC_LOAD_ADDR_32: case BC_STORE_ADDR_8: @@ -594,7 +837,7 @@ void ByteCodeBasicBlock::PutBytes(const uint8* code, int num) void ByteCodeBasicBlock::PutCode(ByteCodeGenerator* generator, ByteCode code) { PutByte(uint8(code) * 2); - generator->mByteCodeUsed[code] = true; + generator->mByteCodeUsed[code]++; } int ByteCodeBasicBlock::PutBranch(ByteCodeGenerator* generator, ByteCode code, int offset) @@ -623,6 +866,7 @@ ByteCodeBasicBlock::ByteCodeBasicBlock(void) mAssembled = false; mKnownShortBranch = false; mBypassed = false; + mExitLive = 0; } void ByteCodeBasicBlock::IntConstToAccu(int64 val) @@ -3482,6 +3726,8 @@ bool ByteCodeBasicBlock::SameTail(ByteCodeInstruction& ins) return false; } +static const uint32 LIVE_ACCU = 0x00000001; + bool ByteCodeBasicBlock::JoinTailCodeSequences(void) { bool changed = false; @@ -3512,6 +3758,7 @@ bool ByteCodeBasicBlock::JoinTailCodeSequences(void) { ByteCodeBasicBlock* b = mEntryBlocks[i]; b->mIns.SetSize(b->mIns.Size() - 1); + b->mExitLive = LIVE_ACCU; } changed = true; } @@ -3530,7 +3777,6 @@ bool ByteCodeBasicBlock::JoinTailCodeSequences(void) return changed; } - bool ByteCodeBasicBlock::PeepHoleOptimizer(void) { bool changed = false; @@ -3561,7 +3807,26 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) } mIns.SetSize(j); - int accuTemp = -1, addrTemp = -1; + // mark accu live + + uint32 live = mExitLive; + if (mBranch != BC_JUMPS && mBranch != BC_NOP) + live |= LIVE_ACCU; + + for (int i = mIns.Size() - 1; i >= 0; i--) + { + mIns[i].mLive = live; + + if (mIns[i].ChangesAccu()) + live &= ~LIVE_ACCU; + if (mIns[i].UsesAccu()) + live |= LIVE_ACCU; + } + +// assert(!(live & LIVE_ACCU)); + + int accuTemp = -1, addrTemp = -1, accuVal = 0; + bool accuConst = false; for (int i = 0; i < mIns.Size(); i++) { @@ -3569,19 +3834,6 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) 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; - } - else if ( mIns[i + 0].mCode == BC_LOAD_REG_8 && mIns[i + 1].mCode == BC_STORE_REG_16 && mIns[i + 2].IsIntegerConst() && mIns[i + 2].mRegister == BC_REG_ACCU && @@ -3592,6 +3844,22 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) mIns[i + 3].mRegister = mIns[i + 0].mRegister; progress = true; } + else if ( + mIns[i + 0].mCode == BC_LOAD_REG_8 && + mIns[i + 1].mCode == BC_LEA_ABS && mIns[i + 1].mRegister != BC_REG_ACCU && + mIns[i + 2].mCode == BC_BINOP_ADDR_16 && mIns[i + 2].mRegister == mIns[i + 1].mRegister && mIns[i + 2].mRegisterFinal && + mIns[i + 3].mCode == BC_ADDR_REG && mIns[i + 3].mRegister == BC_REG_ACCU && !(mIns[i + 3].mLive & LIVE_ACCU)) + { + mIns[i + 1].mCode = BC_LEA_ABS_INDEX_U8; + mIns[i + 1].mRegister = mIns[i + 0].mRegister; + mIns[i + 1].mRegisterFinal = mIns[i + 0].mRegisterFinal; + mIns[i + 1].mLive &= ~LIVE_ACCU; + + mIns[i + 0].mCode = BC_NOP; + mIns[i + 2].mCode = BC_NOP; + mIns[i + 3].mCode = BC_NOP; + progress = true; + } } #endif #if 1 @@ -3764,6 +4032,16 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) mIns[i + 1].mCode = BC_NOP; progress = true; } + else if ( + mIns[i + 0].mCode == BC_STORE_REG_16 && + mIns[i + 1].mCode == BC_LOAD_REG_8 && mIns[i + 0].mRegister == mIns[i + 1].mRegister && + mIns[i + 2].mCode == BC_STORE_REG_8) + { + if (mIns[i + 1].mRegisterFinal) + mIns[i + 0].mCode = BC_NOP; + mIns[i + 1].mCode = BC_NOP; + progress = true; + } #if 1 else if ( mIns[i + 0].mCode == BC_STORE_REG_16 && @@ -3775,6 +4053,32 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) progress = true; } #endif + else 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 + 2].mLive & LIVE_ACCU)) + { + 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 + 0].mLive &= ~LIVE_ACCU; + mIns[i + 1].mCode = BC_NOP; + mIns[i + 2].mCode = BC_NOP; + progress = true; + } + + else if ( + mIns[i + 0].mCode == BC_LOAD_REG_8 && + mIns[i + 1].mCode == BC_STORE_REG_16 && + mIns[i + 2].mCode == BC_LEA_ABS_INDEX && mIns[i + 2].mRegister == mIns[i + 1].mRegister && !(mIns[i + 2].mLive & LIVE_ACCU) && mIns[i + 2].mRegisterFinal) + { + mIns[i + 2].mCode = BC_LEA_ABS_INDEX_U8; + mIns[i + 2].mRegister = mIns[i + 0].mRegister; + mIns[i + 2].mRegisterFinal = mIns[i + 0].mRegisterFinal; + mIns[i + 0].mCode = BC_NOP; + mIns[i + 1].mCode = BC_NOP; + progress = true; + } } #endif #if 1 @@ -3888,6 +4192,22 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) progress = true; } #endif +#if 1 + else if (mIns[i + 1].mCode == BC_LOAD_REG_8 && mIns[i + 0].mCode == BC_LOAD_ADDR_8 && mIns[i + 1].mRegisterFinal && mIns[i + 0].mRegister == mIns[i + 1].mRegister) + { + mIns[i + 0].mCode = BC_LOAD_ADDR_U8; + mIns[i + 0].mRegister = BC_REG_ACCU; + mIns[i + 1].mCode = BC_NOP; + progress = true; + } + else if (mIns[i + 1].mCode == BC_LOAD_REG_8 && mIns[i + 0].mCode == BC_LOAD_ABS_8 && mIns[i + 1].mRegisterFinal && mIns[i + 0].mRegister == mIns[i + 1].mRegister) + { + mIns[i + 0].mCode = BC_LOAD_ABS_U8; + mIns[i + 0].mRegister = BC_REG_ACCU; + mIns[i + 1].mCode = BC_NOP; + progress = true; + } +#endif #if 0 else if ((mIns[i].mCode == BC_LOAD_LOCAL_16 || mIns[i].mCode == BC_LOAD_ABS_16) && mIns[i + 1].mCode == BC_ADDR_REG && mIns[i].mRegister == mIns[i + 1].mRegister && mIns[i + 1].mRegisterFinal) { @@ -3911,8 +4231,39 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) progress = true; } + if (accuConst && !mIns[i].mRelocate && mIns[i].mRegister == BC_REG_ACCU) + { + switch (mIns[i].mCode) + { + case BC_CONST_16: + if ((mIns[i].mValue & 0xffff) == (accuVal & 0xffff)) + { + mIns[i].mCode = BC_NOP; + progress = true; + } + break; + case BC_CONST_32: + if (mIns[i].mValue == accuVal) + { + mIns[i].mCode = BC_NOP; + progress = true; + } + break; + case BC_CONST_8: + if ((mIns[i].mValue & 0xff) == (accuVal & 0xffff)) + { + mIns[i].mCode = BC_NOP; + progress = true; + } + break; + } + } + if (mIns[i].ChangesAccu()) + { accuTemp = -1; + accuConst = false; + } if (mIns[i].ChangesAddr()) addrTemp = -1; if (accuTemp != -1 && mIns[i].ChangesRegister(accuTemp)) @@ -3924,6 +4275,25 @@ bool ByteCodeBasicBlock::PeepHoleOptimizer(void) accuTemp = mIns[i].mRegister; if (mIns[i].mCode == BC_ADDR_REG && mIns[i].mRegister != BC_REG_ACCU) addrTemp = mIns[i].mRegister; + + if (mIns[i].mRegister == BC_REG_ACCU && !mIns[i].mRelocate) + { + switch (mIns[i].mCode) + { + case BC_CONST_16: + accuVal = mIns[i].mValue & 0xffff; + accuConst = true; + break; + case BC_CONST_32: + accuVal = mIns[i].mValue; + accuConst = true; + break; + case BC_CONST_8: + accuVal = mIns[i].mValue & 0xff; + accuConst = true; + break; + } + } } if (progress) @@ -4294,16 +4664,37 @@ ByteCodeGenerator::ByteCodeGenerator(Errors* errors, Linker* linker) { for (int i = 0; i < 128; i++) { - mByteCodeUsed[i] = false; + mByteCodeUsed[i] = 0; mExtByteCodes[i] = nullptr; } - mByteCodeUsed[BC_LEA_ABS] = true; - mByteCodeUsed[BC_CALL] = true; - mByteCodeUsed[BC_EXIT] = true; - mByteCodeUsed[BC_NATIVE] = true; + mByteCodeUsed[BC_LEA_ABS] = 1; + mByteCodeUsed[BC_CALL] = 1; + mByteCodeUsed[BC_EXIT] = 1; + mByteCodeUsed[BC_NATIVE] = 1; + + assert(sizeof(ByteCodeNames) == 128 * sizeof(char*)); } ByteCodeGenerator::~ByteCodeGenerator(void) { } + +bool ByteCodeGenerator::WriteByteCodeStats(const char* filename) +{ + FILE* file; + fopen_s(&file, filename, "w"); + if (file) + { + for (int i = 0; i < 128; i++) + { + if (mByteCodeUsed[i] > 0) + fprintf(file, "BC %s : %d\n", ByteCodeNames[i], mByteCodeUsed[i]); + } + fclose(file); + + return true; + } + + return false; +} diff --git a/oscar64/ByteCodeGenerator.h b/oscar64/ByteCodeGenerator.h index 7cae193..5fe40c5 100644 --- a/oscar64/ByteCodeGenerator.h +++ b/oscar64/ByteCodeGenerator.h @@ -24,6 +24,7 @@ enum ByteCode BC_STORE_REG_32, BC_LOAD_ABS_8, + BC_LOAD_ABS_U8, BC_LOAD_ABS_16, BC_LOAD_ABS_32, @@ -33,6 +34,7 @@ enum ByteCode BC_LEA_ABS, BC_LEA_ABS_INDEX, + BC_LEA_ABS_INDEX_U8, BC_LOAD_LOCAL_8, BC_LOAD_LOCAL_16, @@ -51,6 +53,7 @@ enum ByteCode BC_LEA_FRAME, BC_LOAD_ADDR_8, + BC_LOAD_ADDR_U8, BC_LOAD_ADDR_16, BC_LOAD_ADDR_32, @@ -198,11 +201,16 @@ public: bool mRelocate, mRegisterFinal; LinkerObject* mLinkerObject; const char* mRuntime; + uint32 mLive; bool IsStore(void) const; bool ChangesAccu(void) const; bool ChangesAddr(void) const; bool ChangesRegister(uint32 reg) const; + + bool UsesAccu(void) const; + bool UsesRegister(uint32 reg) const; + bool LoadsRegister(uint32 reg) const; bool StoresRegister(uint32 reg) const; bool IsLocalStore(void) const; @@ -233,6 +241,7 @@ public: int mOffset, mSize; bool mPlaced, mCopied, mKnownShortBranch, mBypassed, mAssembled, mVisited; + uint32 mExitLive; ByteCodeBasicBlock(void); @@ -316,10 +325,8 @@ public: Errors* mErrors; Linker* mLinker; - bool mByteCodeUsed[128]; + uint32 mByteCodeUsed[128]; LinkerObject* mExtByteCodes[128]; - void WriteBasicHeader(void); - void WriteByteCodeHeader(void); - void SetBasicEntry(int index); + bool WriteByteCodeStats(const char* filename); }; diff --git a/oscar64/Compiler.cpp b/oscar64/Compiler.cpp index 5ffd606..cc29cbb 100644 --- a/oscar64/Compiler.cpp +++ b/oscar64/Compiler.cpp @@ -282,7 +282,7 @@ bool Compiler::GenerateCode(void) for (int i = 0; i < 128; i++) { - if (mByteCodeGenerator->mByteCodeUsed[i]) + if (mByteCodeGenerator->mByteCodeUsed[i] > 0) { Declaration* bcdec = mCompilationUnits->mByteCodes[i]; if (bcdec) @@ -338,7 +338,7 @@ bool Compiler::GenerateCode(void) bool Compiler::WriteOutputFile(const char* targetPath) { - char prgPath[200], mapPath[200], asmPath[200], lblPath[200], crtPath[200], intPath[200]; + char prgPath[200], mapPath[200], asmPath[200], lblPath[200], crtPath[200], intPath[200], bcsPath[200]; strcpy_s(prgPath, targetPath); int i = strlen(prgPath); @@ -351,6 +351,7 @@ bool Compiler::WriteOutputFile(const char* targetPath) strcpy_s(lblPath, prgPath); strcpy_s(crtPath, prgPath); strcpy_s(intPath, prgPath); + strcpy_s(bcsPath, prgPath); strcat_s(prgPath, "prg"); strcat_s(mapPath, "map"); @@ -358,6 +359,7 @@ bool Compiler::WriteOutputFile(const char* targetPath) strcat_s(lblPath, "lbl"); strcat_s(crtPath, "crt"); strcat_s(intPath, "int"); + strcat_s(bcsPath, "bcs"); if (mCompilerOptions & COPT_TARGET_PRG) { @@ -383,6 +385,12 @@ bool Compiler::WriteOutputFile(const char* targetPath) printf("Writing <%s>\n", intPath); mInterCodeModule->Disassemble(intPath); + if (!(mCompilerOptions & COPT_NATIVE)) + { + printf("Writing <%s>\n", bcsPath); + mByteCodeGenerator->WriteByteCodeStats(bcsPath); + } + return true; } diff --git a/oscar64/Disassembler.cpp b/oscar64/Disassembler.cpp index fdce4de..505b926 100644 --- a/oscar64/Disassembler.cpp +++ b/oscar64/Disassembler.cpp @@ -143,6 +143,10 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int star fprintf(file, "MOVB\t%s, %s", TempName(memory[start + i + 2], tbuffer, proc), AddrName(uint16(memory[start + i + 0] + 256 * memory[start + i + 1]), abuffer, linker)); i += 3; break; + case BC_LOAD_ABS_U8: + fprintf(file, "MOVUB\t%s, %s", TempName(memory[start + i + 2], tbuffer, proc), AddrName(uint16(memory[start + i + 0] + 256 * memory[start + i + 1]), abuffer, linker)); + i += 3; + break; case BC_LOAD_ABS_16: fprintf(file, "MOV\t%s, %s", TempName(memory[start + i + 2], tbuffer, proc), AddrName(uint16(memory[start + i + 0] + 256 * memory[start + i + 1]), abuffer, linker)); i += 3; @@ -162,6 +166,11 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int star i += 3; break; + case BC_LEA_ABS_INDEX_U8: + fprintf(file, "LEAXB\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; @@ -540,6 +549,10 @@ void ByteCodeDisassembler::Disassemble(FILE* file, const uint8* memory, int star fprintf(file, "MOVB\t%s, %d(ADDR)", TempName(memory[start + i + 0], tbuffer, proc), memory[start + i + 1]); i += 2; break; + case BC_LOAD_ADDR_U8: + fprintf(file, "MOVUB\t%s, %d(ADDR)", TempName(memory[start + i + 0], tbuffer, proc), memory[start + i + 1]); + i += 2; + break; case BC_LOAD_ADDR_16: fprintf(file, "MOV\t%s, %d(ADDR)", TempName(memory[start + i + 0], tbuffer, proc), memory[start + i + 1]); i += 2; diff --git a/oscar64/InterCode.cpp b/oscar64/InterCode.cpp index bf5425c..81a80e3 100644 --- a/oscar64/InterCode.cpp +++ b/oscar64/InterCode.cpp @@ -1569,9 +1569,12 @@ void InterInstruction::MarkAliasedLocalTemps(const GrowingIntArray& localTable, void InterInstruction::FilterTempUsage(NumberSet& requiredTemps, NumberSet& providedTemps) { - for(int i=0; imSrc[1].mLinkerObject->mFlags & LOBJF_RELEVANT) && (ins->mSrc[1].mLinkerObject->mType == LOT_BSS || ins->mSrc[1].mLinkerObject->mType == LOT_DATA)) { + ins->mSrc[0].mTemp = -1; ins->mCode = IC_NONE; } } @@ -5378,50 +5388,53 @@ void InterCodeProcedure::Close(void) } - // - // Promote local variables to temporaries - // - - FastNumberSet simpleLocals(nlocals), complexLocals(nlocals); - GrowingTypeArray localTypes(IT_NONE); - - FastNumberSet simpleParams(nparams), complexParams(nparams); - GrowingTypeArray paramTypes(IT_NONE); - - ResetVisited(); - mEntryBlock->CollectSimpleLocals(complexLocals, simpleLocals, localTypes, complexParams, simpleParams, paramTypes); - - for (int i = 0; i < simpleLocals.Num(); i++) + for (int j = 0; j < 2; j++) { - int vi = simpleLocals.Element(i); - if (!complexLocals[vi]) + // + // Promote local variables to temporaries + // + + FastNumberSet simpleLocals(nlocals), complexLocals(nlocals); + GrowingTypeArray localTypes(IT_NONE); + + FastNumberSet simpleParams(nparams), complexParams(nparams); + GrowingTypeArray paramTypes(IT_NONE); + + ResetVisited(); + mEntryBlock->CollectSimpleLocals(complexLocals, simpleLocals, localTypes, complexParams, simpleParams, paramTypes); + + for (int i = 0; i < simpleLocals.Num(); i++) { - ResetVisited(); - mEntryBlock->SimpleLocalToTemp(vi, AddTemporary(localTypes[vi])); + int vi = simpleLocals.Element(i); + if (!complexLocals[vi]) + { + ResetVisited(); + mEntryBlock->SimpleLocalToTemp(vi, AddTemporary(localTypes[vi])); + } } - } - DisassembleDebug("local variables to temps"); + DisassembleDebug("local variables to temps"); - BuildTraces(false); + BuildTraces(false); - BuildDataFlowSets(); + BuildDataFlowSets(); - RenameTemporaries(); + RenameTemporaries(); + + do { + TempForwarding(); + } while (GlobalConstantPropagation()); + + // + // Now remove unused instructions + // + + RemoveUnusedInstructions(); + + DisassembleDebug("removed unused instructions 2"); - do { TempForwarding(); - } while (GlobalConstantPropagation()); - - // - // Now remove unused instructions - // - - RemoveUnusedInstructions(); - - DisassembleDebug("removed unused instructions 2"); - - TempForwarding(); + } BuildDominators(); DisassembleDebug("added dominators"); diff --git a/oscar64/NativeCodeGenerator.cpp b/oscar64/NativeCodeGenerator.cpp index a508a27..85c6777 100644 --- a/oscar64/NativeCodeGenerator.cpp +++ b/oscar64/NativeCodeGenerator.cpp @@ -6830,9 +6830,11 @@ void NativeCodeBasicBlock::LoadEffectiveAddress(InterCodeProcedure* proc, const mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp])); // if the global variable is smaller than 256 bytes, we can safely ignore the upper byte? mIns.Push(NativeCodeInstruction(ASMIT_LDA, ASMIM_IMMEDIATE_ADDRESS, ins->mSrc[1].mIntConst, ins->mSrc[1].mLinkerObject, NCIF_UPPER)); +#if 1 if (ins->mSrc[1].mLinkerObject->mSize < 256) mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_IMMEDIATE, 0)); else +#endif mIns.Push(NativeCodeInstruction(ASMIT_ADC, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mSrc[0].mTemp] + 1)); mIns.Push(NativeCodeInstruction(ASMIT_STA, ASMIM_ZERO_PAGE, BC_REG_TMP + proc->mTempOffset[ins->mDst.mTemp] + 1)); } @@ -8065,6 +8067,37 @@ bool NativeCodeBasicBlock::MoveStoreHighByteDown(int at) return false; } +bool NativeCodeBasicBlock::MoveAddHighByteDown(int at) +{ + int i = at + 4; + while (i + 1 < mIns.Size()) + { + if (mIns[i].mLive & LIVE_CPU_REG_C) + return false; + if (mIns[i].ChangesZeroPage(mIns[at + 1].mAddress) || mIns[i].ChangesZeroPage(mIns[at + 3].mAddress)) + return false; + if (mIns[i].UsesZeroPage(mIns[at + 3].mAddress)) + return false; + + if (!(mIns[i].mLive & (LIVE_CPU_REG_A | LIVE_CPU_REG_Z))) + { + mIns.Insert(i + 1, mIns[at + 3]); + mIns.Insert(i + 1, mIns[at + 2]); + mIns.Insert(i + 1, mIns[at + 1]); + + mIns[at + 1].mType = ASMIT_NOP; mIns[at + 1].mMode = ASMIM_IMPLIED; // LDA U + mIns[at + 2].mType = ASMIT_NOP; mIns[at + 2].mMode = ASMIM_IMPLIED; // ADC # + mIns[at + 3].mType = ASMIT_NOP; mIns[at + 3].mMode = ASMIM_IMPLIED; // STA T + + return true; + } + + i++; + } + + return false; +} + bool NativeCodeBasicBlock::MoveLoadStoreUp(int at) { int j = at; @@ -8169,14 +8202,15 @@ bool NativeCodeBasicBlock::ValueForwarding(const NativeRegisterDataSet& data) AsmInsType carryop; // Check load and commutative with current accu value - +#if 1 if (i + 1 < mIns.Size() && mIns[i].mType == ASMIT_LDA && mIns[i + 1].IsCommutative() && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mMode == NRDM_ZERO_PAGE && mNDataSet.mRegs[CPU_REG_A].mValue == mIns[i + 1].mAddress) { mIns[i].mType = mIns[i + 1].mType; mIns[i + 1].mType = ASMIT_NOP; mIns[i + 1].mMode = ASMIM_IMPLIED; + changed = true; } - +#endif if (mIns[i].ValueForwarding(mNDataSet, carryop)) changed = true; if (carryop != ASMIT_NOP) @@ -9001,11 +9035,37 @@ void NativeCodeBasicBlock::BlockSizeReduction(void) } -bool NativeCodeBasicBlock::PeepHoleOptimizer(void) +bool NativeCodeBasicBlock::RemoveNops(void) +{ + bool changed = false; + + int i = 0; + int j = 0; + while (i < mIns.Size()) + { + if (mIns[i].mType == ASMIT_NOP) + ; + else + { + if (i != j) + mIns[j] = mIns[i]; + j++; + } + i++; + } + if (j != i) + changed = true; + mIns.SetSize(j); + mIns.Reserve(2 * j); + + return changed; +} + +bool NativeCodeBasicBlock::PeepHoleOptimizer(int pass) { if (!mVisited) { - bool changed = false; + bool changed = RemoveNops(); mVisited = true; @@ -9084,6 +9144,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) NativeCodeInstruction ins = mIns[i]; mIns[i] = mIns[i + 1]; mIns[i + 1] = ins; + mIns[i + 1].mLive |= mIns[i].mLive; } } } @@ -9101,49 +9162,50 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) } } #endif - // move high byte load down, if low byte is immediatedly needed afterwards - for (int i = 0; i + 4 < mIns.Size(); i++) +#if 1 + if (pass > 1) { - if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && - mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && - mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && mIns[i + 2].mAddress != mIns[i + 3].mAddress && mIns[i + 2].mAddress + 1 != mIns[i + 3].mAddress && - mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress && - mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_Z)) + // move high byte load down, if low byte is immediatedly needed afterwards + + for (int i = 0; i + 4 < mIns.Size(); i++) { - if (MoveStoreHighByteDown(i)) - changed = true; + if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDY && mIns[i + 1].mMode == ASMIM_IMMEDIATE && + mIns[i + 2].mType == ASMIT_LDA && mIns[i + 2].mMode == ASMIM_INDIRECT_Y && mIns[i + 2].mAddress != mIns[i + 3].mAddress && mIns[i + 2].mAddress + 1 != mIns[i + 3].mAddress && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress && + mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_Z)) + { + if (MoveStoreHighByteDown(i)) + changed = true; + } } + for (int i = 0; i + 4 < mIns.Size(); i++) + { + if (mIns[i + 0].mType == ASMIT_STA && mIns[i + 0].mMode == ASMIM_ZERO_PAGE && + mIns[i + 1].mType == ASMIT_LDA && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mAddress != mIns[i + 0].mAddress && + mIns[i + 2].mType == ASMIT_ADC && mIns[i + 2].mMode == ASMIM_IMMEDIATE && + mIns[i + 3].mType == ASMIT_STA && mIns[i + 3].mMode == ASMIM_ZERO_PAGE && mIns[i + 3].mAddress != mIns[i + 0].mAddress && + mIns[i + 4].mType == ASMIT_LDA && mIns[i + 4].mMode == ASMIM_ZERO_PAGE && mIns[i + 4].mAddress == mIns[i + 0].mAddress && !(mIns[i + 4].mLive & LIVE_CPU_REG_Z)) + { + if (MoveAddHighByteDown(i)) + changed = true; + } + } } - +#endif bool progress = false; do { progress = false; - int i = 0; - int j = 0; - while (i < mIns.Size()) - { - if (mIns[i].mType == ASMIT_NOP) - ; - else - { - if (i != j) - mIns[j] = mIns[i]; - j++; - } - i++; - } - if (j != i) - changed = true; - mIns.SetSize(j); + changed = RemoveNops(); // Replace (a & 0x80) != 0 with bpl/bmi int sz = mIns.Size(); if (sz > 1 && mIns[sz - 2].ChangesAccuAndFlag() && - mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[i].mLive & LIVE_CPU_REG_A)) + mIns[sz - 1].mType == ASMIT_AND && mIns[sz - 1].mMode == ASMIM_IMMEDIATE && mIns[sz - 1].mAddress == 0x80 && !(mIns[sz - 1].mLive & LIVE_CPU_REG_A)) { if (mBranch == ASMIT_BEQ) { @@ -9282,6 +9344,7 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) } else if (mIns[i].mType == ASMIT_STA && mIns[i + 1].mType == ASMIT_LDA && mIns[i].mMode == ASMIM_ZERO_PAGE && mIns[i + 1].mMode == ASMIM_ZERO_PAGE && mIns[i].mAddress == mIns[i + 1].mAddress && (mIns[i + 1].mLive & LIVE_CPU_REG_Z) == 0) { + mIns[i + 1].mLive |= LIVE_CPU_REG_A; mIns[i + 1].mType = ASMIT_NOP; progress = true; } @@ -9999,9 +10062,9 @@ bool NativeCodeBasicBlock::PeepHoleOptimizer(void) } while (progress); - if (this->mTrueJump && this->mTrueJump->PeepHoleOptimizer()) + if (this->mTrueJump && this->mTrueJump->PeepHoleOptimizer(pass)) changed = true; - if (this->mFalseJump && this->mFalseJump->PeepHoleOptimizer()) + if (this->mFalseJump && this->mFalseJump->PeepHoleOptimizer(pass)) changed = true; return changed; @@ -10623,7 +10686,7 @@ void NativeCodeProcedure::Optimize(void) } while (changed); #endif ResetVisited(); - if (mEntryBlock->PeepHoleOptimizer()) + if (mEntryBlock->PeepHoleOptimizer(step)) changed = true; ResetVisited(); diff --git a/oscar64/NativeCodeGenerator.h b/oscar64/NativeCodeGenerator.h index e3f5985..c88a5c0 100644 --- a/oscar64/NativeCodeGenerator.h +++ b/oscar64/NativeCodeGenerator.h @@ -120,7 +120,8 @@ public: void Assemble(void); void Close(NativeCodeBasicBlock* trueJump, NativeCodeBasicBlock* falseJump, AsmInsType branch); - bool PeepHoleOptimizer(void); + bool RemoveNops(void); + bool PeepHoleOptimizer(int pass); void BlockSizeReduction(void); bool OptimizeSimpleLoop(NativeCodeProcedure* proc); bool OptimizeInnerLoop(NativeCodeProcedure* proc, NativeCodeBasicBlock* head, NativeCodeBasicBlock* tail, GrowingArray& blocks); @@ -179,6 +180,7 @@ public: bool FindGlobalAddressSumY(int at, int reg, bool direct, int& apos, const NativeCodeInstruction * & ains, const NativeCodeInstruction*& iins, uint32 & flags); bool MoveStoreXUp(int at); bool MoveStoreHighByteDown(int at); + bool MoveAddHighByteDown(int at); bool ValueForwarding(const NativeRegisterDataSet& data);