diff --git a/src/ARMJIT.cpp b/src/ARMJIT.cpp index 5d92e47c..85cadf36 100644 --- a/src/ARMJIT.cpp +++ b/src/ARMJIT.cpp @@ -159,6 +159,7 @@ CompiledBlock CompileBlock(ARM* cpu) u32 r15 = cpu->R[15]; cpu->FillPipeline(); u32 nextInstr[2] = {cpu->NextInstr[0], cpu->NextInstr[1]}; + u32 nextInstrAddr[2] = {blockAddr, r15}; do { r15 += thumb ? 2 : 4; @@ -166,6 +167,10 @@ CompiledBlock CompileBlock(ARM* cpu) instrs[i].SetFlags = 0; instrs[i].Instr = nextInstr[0]; instrs[i].NextInstr[0] = nextInstr[0] = nextInstr[1]; + + instrs[i].Addr = nextInstrAddr[0]; + nextInstrAddr[0] = nextInstrAddr[1]; + nextInstrAddr[1] = r15; if (cpu->Num == 0) { @@ -193,8 +198,19 @@ CompiledBlock CompileBlock(ARM* cpu) instrs[i].NextInstr[1] = nextInstr[1]; instrs[i].Info = ARMInstrInfo::Decode(thumb, cpu->Num, instrs[i].Instr); + if (thumb && instrs[i].Info.Kind == ARMInstrInfo::tk_BL_LONG_2 && i > 0 + && instrs[i - 1].Info.Kind == ARMInstrInfo::tk_BL_LONG_1) + { + instrs[i - 1].Info.Kind = ARMInstrInfo::tk_BL_LONG; + instrs[i - 1].Instr = (instrs[i - 1].Instr & 0xFFFF) | (instrs[i].Instr << 16); + instrs[i - 1].Info.DstRegs = 0xC000; + instrs[i - 1].Info.SrcRegs = 0; + instrs[i - 1].Info.EndBlock = true; + i--; + } i++; + bool canCompile = compiler->CanCompile(thumb, instrs[i - 1].Info.Kind); if (instrs[i - 1].Info.ReadFlags != 0 || !canCompile) floodFillSetFlags(instrs, i - 2, canCompile ? instrs[i - 1].Info.ReadFlags : 0xF); diff --git a/src/ARMJIT.h b/src/ARMJIT.h index 61976953..7e448eff 100644 --- a/src/ARMJIT.h +++ b/src/ARMJIT.h @@ -31,6 +31,7 @@ struct FetchedInstr u8 SetFlags; u32 Instr; u32 NextInstr[2]; + u32 Addr; u8 CodeCycles; diff --git a/src/ARMJIT_RegisterCache.h b/src/ARMJIT_RegisterCache.h index 04c1eda0..fe2f2030 100644 --- a/src/ARMJIT_RegisterCache.h +++ b/src/ARMJIT_RegisterCache.h @@ -38,7 +38,7 @@ public: Mapping[reg] = (Reg)-1; } - void LoadRegister(int reg) + void LoadRegister(int reg, bool loadValue) { assert(Mapping[reg] == -1); for (int i = 0; i < NativeRegsAvailable; i++) @@ -50,7 +50,8 @@ public: NativeRegsUsed |= 1 << (int)nativeReg; LoadedRegs |= 1 << reg; - Compiler->LoadReg(reg, nativeReg); + if (loadValue) + Compiler->LoadReg(reg, nativeReg); return; } @@ -66,7 +67,7 @@ public: UnloadRegister(reg); } - void Prepare(int i) + void Prepare(bool thumb, int i) { u16 futureNeeded = 0; int ranking[16]; @@ -111,8 +112,11 @@ public: loadedSet.m_val = LoadedRegs; } + BitSet16 needValueLoaded(needToBeLoaded); + if (thumb || Instr.Cond() >= 0xE) + needValueLoaded = BitSet16(Instr.Info.SrcRegs); for (int reg : needToBeLoaded) - LoadRegister(reg); + LoadRegister(reg, needValueLoaded[reg]); } DirtyRegs |= Instr.Info.DstRegs & ~(1 << 15); } diff --git a/src/ARMJIT_x64/ARMJIT_Branch.cpp b/src/ARMJIT_x64/ARMJIT_Branch.cpp index c0a8f1f4..cc7a3c4a 100644 --- a/src/ARMJIT_x64/ARMJIT_Branch.cpp +++ b/src/ARMJIT_x64/ARMJIT_Branch.cpp @@ -271,15 +271,17 @@ void Compiler::T_Comp_BL_LONG_2() Comp_JumpTo(RSCRATCH); } -void Compiler::T_Comp_BL_Merged(FetchedInstr part1) +void Compiler::T_Comp_BL_Merged() { - assert(part1.Info.Kind == ARMInstrInfo::tk_BL_LONG_1); Comp_AddCycles_C(); - u32 target = (R15 - 2) + ((s32)((part1.Instr & 0x7FF) << 21) >> 9); - target += (CurInstr.Instr & 0x7FF) << 1; + R15 += 2; - if (Num == 1 || CurInstr.Instr & (1 << 12)) + u32 upperPart = CurInstr.Instr >> 16; + u32 target = (R15 - 2) + ((s32)((CurInstr.Instr & 0x7FF) << 21) >> 9); + target += (upperPart & 0x7FF) << 1; + + if (Num == 1 || upperPart & (1 << 12)) target |= 1; MOV(32, MapReg(14), Imm32((R15 - 2) | 1)); diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.cpp b/src/ARMJIT_x64/ARMJIT_Compiler.cpp index d585f395..d8ce1aa0 100644 --- a/src/ARMJIT_x64/ARMJIT_Compiler.cpp +++ b/src/ARMJIT_x64/ARMJIT_Compiler.cpp @@ -338,7 +338,8 @@ const Compiler::CompileFunc T_Comp[ARMInstrInfo::tk_Count] = { // Branch F(T_Comp_BCOND), F(T_Comp_BranchXchangeReg), F(T_Comp_BranchXchangeReg), F(T_Comp_B), F(T_Comp_BL_LONG_1), F(T_Comp_BL_LONG_2), // Unk, SVC - NULL, NULL + NULL, NULL, + F(T_Comp_BL_Merged) }; #undef F @@ -361,21 +362,18 @@ CompiledBlock Compiler::CompileBlock(ARM* cpu, FetchedInstr instrs[], int instrs ConstantCycles = 0; Thumb = cpu->CPSR & 0x20; Num = cpu->Num; - R15 = cpu->R[15]; CodeRegion = cpu->CodeRegion; CurCPU = cpu; CompiledBlock res = (CompiledBlock)GetWritableCodePtr(); if (!(Num == 0 - ? IsMapped<0>(R15 - (Thumb ? 2 : 4)) - : IsMapped<1>(R15 - (Thumb ? 2 : 4)))) + ? IsMapped<0>(instrs[0].Addr - (Thumb ? 2 : 4)) + : IsMapped<1>(instrs[0].Addr - (Thumb ? 2 : 4)))) { printf("Trying to compile a block in unmapped memory\n"); } - bool mergedThumbBL = false; - ABI_PushRegistersAndAdjustStack(BitSet32(ABI_ALL_CALLEE_SAVED & ABI_ALL_GPRS & ~BitSet32({RSP})), 8); MOV(64, R(RCPU), ImmPtr(cpu)); @@ -387,8 +385,8 @@ CompiledBlock Compiler::CompileBlock(ARM* cpu, FetchedInstr instrs[], int instrs for (int i = 0; i < instrsCount; i++) { - R15 += Thumb ? 2 : 4; CurInstr = instrs[i]; + R15 = CurInstr.Addr + (Thumb ? 4 : 8); CompileFunc comp = Thumb ? T_Comp[CurInstr.Info.Kind] @@ -406,29 +404,21 @@ CompiledBlock Compiler::CompileBlock(ARM* cpu, FetchedInstr instrs[], int instrs } if (comp != NULL) - RegCache.Prepare(i); + RegCache.Prepare(Thumb, i); else RegCache.Flush(); if (Thumb) { - if (i < instrsCount - 1 && CurInstr.Info.Kind == ARMInstrInfo::tk_BL_LONG_1 - && instrs[i + 1].Info.Kind == ARMInstrInfo::tk_BL_LONG_2) - mergedThumbBL = true; - else + u32 icode = (CurInstr.Instr >> 6) & 0x3FF; + if (comp == NULL) { - u32 icode = (CurInstr.Instr >> 6) & 0x3FF; - if (comp == NULL) - { - MOV(64, R(ABI_PARAM1), R(RCPU)); + MOV(64, R(ABI_PARAM1), R(RCPU)); - ABI_CallFunction(ARMInterpreter::THUMBInstrTable[icode]); - } - else if (mergedThumbBL) - T_Comp_BL_Merged(instrs[i - 1]); - else - (this->*comp)(); + ABI_CallFunction(ARMInterpreter::THUMBInstrTable[icode]); } + else + (this->*comp)(); } else { diff --git a/src/ARMJIT_x64/ARMJIT_Compiler.h b/src/ARMJIT_x64/ARMJIT_Compiler.h index a62f0436..fcb23802 100644 --- a/src/ARMJIT_x64/ARMJIT_Compiler.h +++ b/src/ARMJIT_x64/ARMJIT_Compiler.h @@ -90,7 +90,7 @@ public: void T_Comp_BranchXchangeReg(); void T_Comp_BL_LONG_1(); void T_Comp_BL_LONG_2(); - void T_Comp_BL_Merged(FetchedInstr prefix); + void T_Comp_BL_Merged(); void Comp_MemAccess(Gen::OpArg rd, bool signExtend, bool store, int size); s32 Comp_MemAccessBlock(int rn, BitSet16 regs, bool store, bool preinc, bool decrement, bool usermode); diff --git a/src/ARM_InstrInfo.h b/src/ARM_InstrInfo.h index 53368379..d01c600d 100644 --- a/src/ARM_InstrInfo.h +++ b/src/ARM_InstrInfo.h @@ -212,6 +212,9 @@ enum tk_UNK, tk_SVC, + // not a real instruction + tk_BL_LONG, + tk_Count };