1 // Copyright (c) 2012- PPSSPP Project. 2 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, version 2.0 or later versions. 6 7 // This program is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 // GNU General Public License 2.0 for more details. 11 12 // A copy of the GPL 2.0 should have been included with the program. 13 // If not, see http://www.gnu.org/licenses/ 14 15 // Official git repository and contact information can be found at 16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. 17 18 #pragma once 19 20 #include "Common/CPUDetect.h" 21 #include "Common/ArmCommon.h" 22 #include "Common/Arm64Emitter.h" 23 #include "Core/MIPS/JitCommon/JitState.h" 24 #include "Core/MIPS/JitCommon/JitBlockCache.h" 25 #include "Core/MIPS/JitCommon/JitCommon.h" 26 #include "Core/MIPS/ARM64/Arm64RegCache.h" 27 #include "Core/MIPS/ARM64/Arm64RegCacheFPU.h" 28 #include "Core/MIPS/MIPSVFPUUtils.h" 29 30 #ifndef offsetof 31 #include "stddef.h" 32 #endif 33 34 namespace MIPSComp { 35 36 class Arm64Jit : public Arm64Gen::ARM64CodeBlock, public JitInterface, public MIPSFrontendInterface { 37 public: 38 Arm64Jit(MIPSState *mipsState); 39 virtual ~Arm64Jit(); 40 41 void DoState(PointerWrap &p) override; 42 GetJitOptions()43 const JitOptions &GetJitOptions() { return jo; } 44 45 // Compiled ops should ignore delay slots 46 // the compiler will take care of them by itself 47 // OR NOT 48 void Comp_Generic(MIPSOpcode op) override; 49 50 void RunLoopUntil(u64 globalticks) override; 51 52 void Compile(u32 em_address) override; // Compiles a block at current MIPS PC 53 const u8 *DoJit(u32 em_address, JitBlock *b); 54 GetCrashHandler()55 const u8 *GetCrashHandler() const override { return crashHandler; } CodeInRange(const u8 * ptr)56 bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } 57 bool DescribeCodePtr(const u8 *ptr, std::string &name) override; 58 MIPSOpcode GetOriginalOp(MIPSOpcode op) override; 59 60 void Comp_RunBlock(MIPSOpcode op) override; 61 void Comp_ReplacementFunc(MIPSOpcode op) override; 62 63 // Ops 64 void Comp_ITypeMem(MIPSOpcode op) override; 65 void Comp_Cache(MIPSOpcode op) override; 66 67 void Comp_RelBranch(MIPSOpcode op) override; 68 void Comp_RelBranchRI(MIPSOpcode op) override; 69 void Comp_FPUBranch(MIPSOpcode op) override; 70 void Comp_FPULS(MIPSOpcode op) override; 71 void Comp_FPUComp(MIPSOpcode op) override; 72 void Comp_Jump(MIPSOpcode op) override; 73 void Comp_JumpReg(MIPSOpcode op) override; 74 void Comp_Syscall(MIPSOpcode op) override; 75 void Comp_Break(MIPSOpcode op) override; 76 77 void Comp_IType(MIPSOpcode op) override; 78 void Comp_RType2(MIPSOpcode op) override; 79 void Comp_RType3(MIPSOpcode op) override; 80 void Comp_ShiftType(MIPSOpcode op) override; 81 void Comp_Allegrex(MIPSOpcode op) override; 82 void Comp_Allegrex2(MIPSOpcode op) override; 83 void Comp_VBranch(MIPSOpcode op) override; 84 void Comp_MulDivType(MIPSOpcode op) override; 85 void Comp_Special3(MIPSOpcode op) override; 86 87 void Comp_FPU3op(MIPSOpcode op) override; 88 void Comp_FPU2op(MIPSOpcode op) override; 89 void Comp_mxc1(MIPSOpcode op) override; 90 91 void Comp_DoNothing(MIPSOpcode op) override; 92 93 void Comp_SV(MIPSOpcode op) override; 94 void Comp_SVQ(MIPSOpcode op) override; 95 void Comp_VPFX(MIPSOpcode op) override; 96 void Comp_VVectorInit(MIPSOpcode op) override; 97 void Comp_VMatrixInit(MIPSOpcode op) override; 98 void Comp_VDot(MIPSOpcode op) override; 99 void Comp_VecDo3(MIPSOpcode op) override; 100 void Comp_VV2Op(MIPSOpcode op) override; 101 void Comp_Mftv(MIPSOpcode op) override; 102 void Comp_Vmfvc(MIPSOpcode op) override; 103 void Comp_Vmtvc(MIPSOpcode op) override; 104 void Comp_Vmmov(MIPSOpcode op) override; 105 void Comp_VScl(MIPSOpcode op) override; 106 void Comp_Vmmul(MIPSOpcode op) override; 107 void Comp_Vmscl(MIPSOpcode op) override; 108 void Comp_Vtfm(MIPSOpcode op) override; 109 void Comp_VHdp(MIPSOpcode op) override; 110 void Comp_VCrs(MIPSOpcode op) override; 111 void Comp_VDet(MIPSOpcode op) override; 112 void Comp_Vi2x(MIPSOpcode op) override; 113 void Comp_Vx2i(MIPSOpcode op) override; 114 void Comp_Vf2i(MIPSOpcode op) override; 115 void Comp_Vi2f(MIPSOpcode op) override; 116 void Comp_Vh2f(MIPSOpcode op) override; 117 void Comp_Vcst(MIPSOpcode op) override; 118 void Comp_Vhoriz(MIPSOpcode op) override; 119 void Comp_VRot(MIPSOpcode op) override; 120 void Comp_VIdt(MIPSOpcode op) override; 121 void Comp_Vcmp(MIPSOpcode op) override; 122 void Comp_Vcmov(MIPSOpcode op) override; 123 void Comp_Viim(MIPSOpcode op) override; 124 void Comp_Vfim(MIPSOpcode op) override; 125 void Comp_VCrossQuat(MIPSOpcode op) override; 126 void Comp_Vsgn(MIPSOpcode op) override; 127 void Comp_Vocp(MIPSOpcode op) override; 128 void Comp_ColorConv(MIPSOpcode op) override; 129 void Comp_Vbfy(MIPSOpcode op) override; 130 131 // Non-NEON: VPFX 132 133 // NEON implementations of the VFPU ops. 134 void CompNEON_SV(MIPSOpcode op); 135 void CompNEON_SVQ(MIPSOpcode op); 136 void CompNEON_VVectorInit(MIPSOpcode op); 137 void CompNEON_VMatrixInit(MIPSOpcode op); 138 void CompNEON_VDot(MIPSOpcode op); 139 void CompNEON_VecDo3(MIPSOpcode op); 140 void CompNEON_VV2Op(MIPSOpcode op); 141 void CompNEON_Mftv(MIPSOpcode op); 142 void CompNEON_Vmfvc(MIPSOpcode op); 143 void CompNEON_Vmtvc(MIPSOpcode op); 144 void CompNEON_Vmmov(MIPSOpcode op); 145 void CompNEON_VScl(MIPSOpcode op); 146 void CompNEON_Vmmul(MIPSOpcode op); 147 void CompNEON_Vmscl(MIPSOpcode op); 148 void CompNEON_Vtfm(MIPSOpcode op); 149 void CompNEON_VHdp(MIPSOpcode op); 150 void CompNEON_VCrs(MIPSOpcode op); 151 void CompNEON_VDet(MIPSOpcode op); 152 void CompNEON_Vi2x(MIPSOpcode op); 153 void CompNEON_Vx2i(MIPSOpcode op); 154 void CompNEON_Vf2i(MIPSOpcode op); 155 void CompNEON_Vi2f(MIPSOpcode op); 156 void CompNEON_Vh2f(MIPSOpcode op); 157 void CompNEON_Vcst(MIPSOpcode op); 158 void CompNEON_Vhoriz(MIPSOpcode op); 159 void CompNEON_VRot(MIPSOpcode op); 160 void CompNEON_VIdt(MIPSOpcode op); 161 void CompNEON_Vcmp(MIPSOpcode op); 162 void CompNEON_Vcmov(MIPSOpcode op); 163 void CompNEON_Viim(MIPSOpcode op); 164 void CompNEON_Vfim(MIPSOpcode op); 165 void CompNEON_VCrossQuat(MIPSOpcode op); 166 void CompNEON_Vsgn(MIPSOpcode op); 167 void CompNEON_Vocp(MIPSOpcode op); 168 void CompNEON_ColorConv(MIPSOpcode op); 169 void CompNEON_Vbfy(MIPSOpcode op); 170 171 int Replace_fabsf() override; 172 GetBlockCache()173 JitBlockCache *GetBlockCache() override { return &blocks; } GetBlockCacheDebugInterface()174 JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() override { return &blocks; } 175 SaveAndClearEmuHackOps()176 std::vector<u32> SaveAndClearEmuHackOps() override { return blocks.SaveAndClearEmuHackOps(); } RestoreSavedEmuHackOps(std::vector<u32> saved)177 void RestoreSavedEmuHackOps(std::vector<u32> saved) override { blocks.RestoreSavedEmuHackOps(saved); } 178 179 void ClearCache() override; 180 void InvalidateCacheAt(u32 em_address, int length = 4) override; 181 void UpdateFCR31() override; 182 EatPrefix()183 void EatPrefix() override { js.EatPrefix(); } 184 GetDispatcher()185 const u8 *GetDispatcher() const override { 186 return dispatcher; 187 } IsAtDispatchFetch(const u8 * ptr)188 bool IsAtDispatchFetch(const u8 *ptr) const override { 189 return ptr == dispatcherFetch; 190 } 191 192 void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override; 193 void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override; 194 195 private: 196 void GenerateFixedCode(const JitOptions &jo); 197 void FlushAll(); 198 void FlushPrefixV(); 199 200 u32 GetCompilerPC(); 201 void CompileDelaySlot(int flags); 202 void EatInstruction(MIPSOpcode op); 203 void AddContinuedBlock(u32 dest); 204 MIPSOpcode GetOffsetInstruction(int offset); 205 206 void WriteDownCount(int offset = 0, bool updateFlags = true); 207 void WriteDownCountR(Arm64Gen::ARM64Reg reg, bool updateFlags = true); 208 void RestoreRoundingMode(bool force = false); 209 void ApplyRoundingMode(bool force = false); 210 void UpdateRoundingMode(u32 fcr31 = -1); 211 void MovFromPC(Arm64Gen::ARM64Reg r); 212 void MovToPC(Arm64Gen::ARM64Reg r); 213 214 bool ReplaceJalTo(u32 dest); 215 216 void SaveStaticRegisters(); 217 void LoadStaticRegisters(); 218 219 void WriteExit(u32 destination, int exit_num); 220 void WriteExitDestInR(Arm64Gen::ARM64Reg Reg); 221 void WriteSyscallExit(); 222 bool CheckJitBreakpoint(u32 addr, int downcountOffset); 223 bool CheckMemoryBreakpoint(int instructionOffset = 0); 224 225 // Utility compilation functions 226 void BranchFPFlag(MIPSOpcode op, CCFlags cc, bool likely); 227 void BranchVFPUFlag(MIPSOpcode op, CCFlags cc, bool likely); 228 void BranchRSZeroComp(MIPSOpcode op, CCFlags cc, bool andLink, bool likely); 229 void BranchRSRTComp(MIPSOpcode op, CCFlags cc, bool likely); 230 231 // Utilities to reduce duplicated code 232 void CompImmLogic(MIPSGPReg rs, MIPSGPReg rt, u32 uimm, void (ARM64XEmitter::*arith)(Arm64Gen::ARM64Reg dst, Arm64Gen::ARM64Reg src, Arm64Gen::ARM64Reg src2), bool (ARM64XEmitter::*tryArithI2R)(Arm64Gen::ARM64Reg dst, Arm64Gen::ARM64Reg src, u64 val), u32 (*eval)(u32 a, u32 b)); 233 void CompType3(MIPSGPReg rd, MIPSGPReg rs, MIPSGPReg rt, void (ARM64XEmitter::*arithOp2)(Arm64Gen::ARM64Reg dst, Arm64Gen::ARM64Reg rm, Arm64Gen::ARM64Reg rn), bool (ARM64XEmitter::*tryArithI2R)(Arm64Gen::ARM64Reg dst, Arm64Gen::ARM64Reg rm, u64 val), u32 (*eval)(u32 a, u32 b), bool symmetric = false); 234 void CompShiftImm(MIPSOpcode op, Arm64Gen::ShiftType shiftType, int sa); 235 void CompShiftVar(MIPSOpcode op, Arm64Gen::ShiftType shiftType); 236 void CompVrotShuffle(u8 *dregs, int imm, VectorSize sz, bool negSin); 237 238 void ApplyPrefixST(u8 *vregs, u32 prefix, VectorSize sz); 239 void ApplyPrefixD(const u8 *vregs, VectorSize sz); GetVectorRegsPrefixS(u8 * regs,VectorSize sz,int vectorReg)240 void GetVectorRegsPrefixS(u8 *regs, VectorSize sz, int vectorReg) { 241 _assert_(js.prefixSFlag & JitState::PREFIX_KNOWN); 242 GetVectorRegs(regs, sz, vectorReg); 243 ApplyPrefixST(regs, js.prefixS, sz); 244 } GetVectorRegsPrefixT(u8 * regs,VectorSize sz,int vectorReg)245 void GetVectorRegsPrefixT(u8 *regs, VectorSize sz, int vectorReg) { 246 _assert_(js.prefixTFlag & JitState::PREFIX_KNOWN); 247 GetVectorRegs(regs, sz, vectorReg); 248 ApplyPrefixST(regs, js.prefixT, sz); 249 } 250 void GetVectorRegsPrefixD(u8 *regs, VectorSize sz, int vectorReg); 251 252 // Utils 253 void SetScratch1ToEffectiveAddress(MIPSGPReg rs, s16 offset); 254 std::vector<Arm64Gen::FixupBranch> SetScratch1ForSafeAddress(MIPSGPReg rs, s16 offset, Arm64Gen::ARM64Reg tempReg); 255 void Comp_ITypeMemLR(MIPSOpcode op, bool load); 256 257 JitBlockCache blocks; 258 JitOptions jo; 259 JitState js; 260 261 Arm64RegCache gpr; 262 Arm64RegCacheFPU fpr; 263 264 Arm64Gen::ARM64FloatEmitter fp; 265 266 MIPSState *mips_; 267 268 int dontLogBlocks; 269 int logBlocks; 270 271 public: 272 // Code pointers 273 const u8 *enterDispatcher; 274 275 const u8 *outerLoop; 276 const u8 *outerLoopPCInSCRATCH1; 277 const u8 *dispatcherCheckCoreState; 278 const u8 *dispatcherPCInSCRATCH1; 279 const u8 *dispatcher; 280 const u8 *dispatcherNoCheck; 281 const u8 *dispatcherFetch; 282 283 const u8 *saveStaticRegisters; 284 const u8 *loadStaticRegisters; 285 286 const u8 *restoreRoundingMode; 287 const u8 *applyRoundingMode; 288 const u8 *updateRoundingMode; 289 290 const u8 *crashHandler; 291 292 int jitStartOffset; 293 294 // Indexed by FPCR FZ:RN bits for convenience. Uses SCRATCH2. 295 const u8 *convertS0ToSCRATCH1[8]; 296 }; 297 298 } // namespace MIPSComp 299 300