cpu_recompiler_code_generator.h (14780B)
1 // SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "cpu_code_cache_private.h" 7 #include "cpu_recompiler_register_cache.h" 8 #include "cpu_recompiler_thunks.h" 9 #include "cpu_recompiler_types.h" 10 #include "cpu_types.h" 11 12 #include <array> 13 #include <utility> 14 15 namespace CPU::Recompiler { 16 17 enum class Condition : u8 18 { 19 Always, 20 NotEqual, 21 Equal, 22 Overflow, 23 Greater, 24 GreaterEqual, 25 LessEqual, 26 Less, 27 Negative, 28 PositiveOrZero, 29 Above, // unsigned variant of Greater 30 AboveEqual, // unsigned variant of GreaterEqual 31 Below, // unsigned variant of Less 32 BelowEqual, // unsigned variant of LessEqual 33 34 NotZero, 35 Zero 36 }; 37 38 class CodeGenerator 39 { 40 public: 41 using SpeculativeValue = std::optional<u32>; 42 43 struct CodeBlockInstruction 44 { 45 const Instruction* instruction; 46 const CodeCache::InstructionInfo* info; 47 }; 48 49 CodeGenerator(); 50 ~CodeGenerator(); 51 52 static const char* GetHostRegName(HostReg reg, RegSize size = HostPointerSize); 53 54 static void BackpatchLoadStore(void* host_pc, const CodeCache::LoadstoreBackpatchInfo& lbi); 55 56 const void* CompileBlock(CodeCache::Block* block, u32* out_host_code_size, u32* out_host_far_code_size); 57 58 ////////////////////////////////////////////////////////////////////////// 59 // Code Generation 60 ////////////////////////////////////////////////////////////////////////// 61 void EmitBeginBlock(bool allocate_registers = true); 62 void EmitEndBlock(bool free_registers, const void* jump_to); 63 void EmitExceptionExit(); 64 void EmitExceptionExitOnBool(const Value& value); 65 const void* FinalizeBlock(u32* out_host_code_size, u32* out_host_far_code_size); 66 67 void EmitSignExtend(HostReg to_reg, RegSize to_size, HostReg from_reg, RegSize from_size); 68 void EmitZeroExtend(HostReg to_reg, RegSize to_size, HostReg from_reg, RegSize from_size); 69 void EmitCopyValue(HostReg to_reg, const Value& value); 70 void EmitAdd(HostReg to_reg, HostReg from_reg, const Value& value, bool set_flags); 71 void EmitSub(HostReg to_reg, HostReg from_reg, const Value& value, bool set_flags); 72 void EmitCmp(HostReg to_reg, const Value& value); 73 void EmitMul(HostReg to_reg_hi, HostReg to_reg_lo, const Value& lhs, const Value& rhs, bool signed_multiply); 74 void EmitDiv(HostReg to_reg_quotient, HostReg to_reg_remainder, HostReg num, HostReg denom, RegSize size, 75 bool signed_divide); 76 void EmitInc(HostReg to_reg, RegSize size); 77 void EmitDec(HostReg to_reg, RegSize size); 78 void EmitShl(HostReg to_reg, HostReg from_reg, RegSize size, const Value& amount_value, 79 bool assume_amount_masked = true); 80 void EmitShr(HostReg to_reg, HostReg from_reg, RegSize size, const Value& amount_value, 81 bool assume_amount_masked = true); 82 void EmitSar(HostReg to_reg, HostReg from_reg, RegSize size, const Value& amount_value, 83 bool assume_amount_masked = true); 84 void EmitAnd(HostReg to_reg, HostReg from_reg, const Value& value); 85 void EmitOr(HostReg to_reg, HostReg from_reg, const Value& value); 86 void EmitXor(HostReg to_reg, HostReg from_reg, const Value& value); 87 void EmitTest(HostReg to_reg, const Value& value); 88 void EmitNot(HostReg to_reg, RegSize size); 89 void EmitSetConditionResult(HostReg to_reg, RegSize to_size, Condition condition); 90 91 void EmitLoadGuestRegister(HostReg host_reg, Reg guest_reg); 92 void EmitStoreGuestRegister(Reg guest_reg, const Value& value); 93 void EmitStoreInterpreterLoadDelay(Reg reg, const Value& value); 94 void EmitFlushInterpreterLoadDelay(); 95 void EmitMoveNextInterpreterLoadDelay(); 96 void EmitCancelInterpreterLoadDelayForReg(Reg reg); 97 void EmitICacheCheckAndUpdate(); 98 void EmitBlockProtectCheck(const u8* ram_ptr, const u8* shadow_ptr, u32 size); 99 void EmitStallUntilGTEComplete(); 100 void EmitLoadCPUStructField(HostReg host_reg, RegSize size, u32 offset); 101 void EmitStoreCPUStructField(u32 offset, const Value& value); 102 void EmitAddCPUStructField(u32 offset, const Value& value); 103 void EmitLoadGlobal(HostReg host_reg, RegSize size, const void* ptr); 104 void EmitStoreGlobal(void* ptr, const Value& value); 105 void EmitLoadGlobalAddress(HostReg host_reg, const void* ptr); 106 107 // Automatically generates an exception handler. 108 Value EmitLoadGuestMemory(Instruction instruction, const CodeCache::InstructionInfo& info, const Value& address, 109 const SpeculativeValue& address_spec, RegSize size); 110 void EmitLoadGuestRAMFastmem(const Value& address, RegSize size, Value& result); 111 void EmitLoadGuestMemoryFastmem(Instruction instruction, const CodeCache::InstructionInfo& info, const Value& address, 112 RegSize size, Value& result); 113 void EmitLoadGuestMemorySlowmem(Instruction instruction, const CodeCache::InstructionInfo& info, const Value& address, 114 RegSize size, Value& result, bool in_far_code); 115 void EmitStoreGuestMemory(Instruction instruction, const CodeCache::InstructionInfo& info, const Value& address, 116 const SpeculativeValue& address_spec, RegSize size, const Value& value); 117 void EmitStoreGuestMemoryFastmem(Instruction instruction, const CodeCache::InstructionInfo& info, 118 const Value& address, RegSize size, const Value& value); 119 void EmitStoreGuestMemorySlowmem(Instruction instruction, const CodeCache::InstructionInfo& info, 120 const Value& address, RegSize size, const Value& value, bool in_far_code); 121 void EnsureMembaseLoaded(); 122 void EmitUpdateFastmemBase(); 123 124 // Unconditional branch to pointer. May allocate a scratch register. 125 void EmitBranch(const void* address, bool allow_scratch = true); 126 void EmitBranch(LabelType* label); 127 128 // Branching, generates two paths. 129 void EmitConditionalBranch(Condition condition, bool invert, HostReg value, RegSize size, LabelType* label); 130 void EmitConditionalBranch(Condition condition, bool invert, HostReg lhs, const Value& rhs, LabelType* label); 131 void EmitConditionalBranch(Condition condition, bool invert, LabelType* label); 132 void EmitBranchIfBitClear(HostReg reg, RegSize size, u8 bit, LabelType* label); 133 void EmitBranchIfBitSet(HostReg reg, RegSize size, u8 bit, LabelType* label); 134 void EmitBindLabel(LabelType* label); 135 136 u32 PrepareStackForCall(); 137 void RestoreStackAfterCall(u32 adjust_size); 138 139 void EmitCall(const void* ptr); 140 void EmitFunctionCallPtr(Value* return_value, const void* ptr); 141 void EmitFunctionCallPtr(Value* return_value, const void* ptr, const Value& arg1); 142 void EmitFunctionCallPtr(Value* return_value, const void* ptr, const Value& arg1, const Value& arg2); 143 void EmitFunctionCallPtr(Value* return_value, const void* ptr, const Value& arg1, const Value& arg2, 144 const Value& arg3); 145 void EmitFunctionCallPtr(Value* return_value, const void* ptr, const Value& arg1, const Value& arg2, 146 const Value& arg3, const Value& arg4); 147 148 template<typename FunctionType> 149 void EmitFunctionCall(Value* return_value, const FunctionType ptr) 150 { 151 EmitFunctionCallPtr(return_value, reinterpret_cast<const void**>(ptr)); 152 } 153 154 template<typename FunctionType> 155 void EmitFunctionCall(Value* return_value, const FunctionType ptr, const Value& arg1) 156 { 157 EmitFunctionCallPtr(return_value, reinterpret_cast<const void**>(ptr), arg1); 158 } 159 160 template<typename FunctionType> 161 void EmitFunctionCall(Value* return_value, const FunctionType ptr, const Value& arg1, const Value& arg2) 162 { 163 EmitFunctionCallPtr(return_value, reinterpret_cast<const void**>(ptr), arg1, arg2); 164 } 165 166 template<typename FunctionType> 167 void EmitFunctionCall(Value* return_value, const FunctionType ptr, const Value& arg1, const Value& arg2, 168 const Value& arg3) 169 { 170 EmitFunctionCallPtr(return_value, reinterpret_cast<const void**>(ptr), arg1, arg2, arg3); 171 } 172 173 template<typename FunctionType> 174 void EmitFunctionCall(Value* return_value, const FunctionType ptr, const Value& arg1, const Value& arg2, 175 const Value& arg3, const Value& arg4) 176 { 177 EmitFunctionCallPtr(return_value, reinterpret_cast<const void**>(ptr), arg1, arg2, arg3, arg4); 178 } 179 180 // Host register saving. 181 void EmitPushHostReg(HostReg reg, u32 position); 182 void EmitPushHostRegPair(HostReg reg, HostReg reg2, u32 position); 183 void EmitPopHostReg(HostReg reg, u32 position); 184 void EmitPopHostRegPair(HostReg reg, HostReg reg2, u32 position); 185 186 // Value ops 187 Value AddValues(const Value& lhs, const Value& rhs, bool set_flags); 188 Value SubValues(const Value& lhs, const Value& rhs, bool set_flags); 189 std::pair<Value, Value> MulValues(const Value& lhs, const Value& rhs, bool signed_multiply); 190 Value ShlValues(const Value& lhs, const Value& rhs, bool assume_amount_masked = true); 191 Value ShrValues(const Value& lhs, const Value& rhs, bool assume_amount_masked = true); 192 Value SarValues(const Value& lhs, const Value& rhs, bool assume_amount_masked = true); 193 Value OrValues(const Value& lhs, const Value& rhs); 194 void OrValueInPlace(Value& lhs, const Value& rhs); 195 Value AndValues(const Value& lhs, const Value& rhs); 196 void AndValueInPlace(Value& lhs, const Value& rhs); 197 Value XorValues(const Value& lhs, const Value& rhs); 198 Value NotValue(const Value& val); 199 200 const TickCount* GetFetchMemoryAccessTimePtr() const; 201 202 // Raising exception if condition is true. 203 void GenerateExceptionExit(Instruction instruction, const CodeCache::InstructionInfo& info, Exception excode, 204 Condition condition = Condition::Always); 205 206 private: 207 // Host register setup 208 void InitHostRegs(); 209 210 Value ConvertValueSize(const Value& value, RegSize size, bool sign_extend); 211 void ConvertValueSizeInPlace(Value* value, RegSize size, bool sign_extend); 212 213 Value GetValueInHostRegister(const Value& value, bool allow_zero_register = true); 214 Value GetValueInHostOrScratchRegister(const Value& value, bool allow_zero_register = true); 215 216 void SwitchToFarCode(); 217 void SwitchToNearCode(); 218 void* GetStartNearCodePointer() const; 219 void* GetCurrentCodePointer() const; 220 void* GetCurrentNearCodePointer() const; 221 void* GetCurrentFarCodePointer() const; 222 223 ////////////////////////////////////////////////////////////////////////// 224 // Code Generation Helpers 225 ////////////////////////////////////////////////////////////////////////// 226 // branch target, memory address, etc 227 void BlockPrologue(); 228 void BlockEpilogue(); 229 void InstructionPrologue(Instruction instruction, const CodeCache::InstructionInfo& info, TickCount cycles, 230 bool force_sync = false); 231 void InstructionEpilogue(Instruction instruction, const CodeCache::InstructionInfo& info); 232 void TruncateBlockAtCurrentInstruction(); 233 void AddPendingCycles(bool commit); 234 void AddGTETicks(TickCount ticks); 235 void StallUntilGTEComplete(); 236 237 Value CalculatePC(u32 offset = 0); 238 Value GetCurrentInstructionPC(u32 offset = 0); 239 void WriteNewPC(const Value& value, bool commit); 240 241 Value DoGTERegisterRead(u32 index); 242 void DoGTERegisterWrite(u32 index, const Value& value); 243 244 ////////////////////////////////////////////////////////////////////////// 245 // Instruction Code Generators 246 ////////////////////////////////////////////////////////////////////////// 247 bool CompileInstruction(Instruction instruction, const CodeCache::InstructionInfo& info); 248 bool Compile_Fallback(Instruction instruction, const CodeCache::InstructionInfo& info); 249 bool Compile_Nop(Instruction instruction, const CodeCache::InstructionInfo& info); 250 bool Compile_Bitwise(Instruction instruction, const CodeCache::InstructionInfo& info); 251 bool Compile_Shift(Instruction instruction, const CodeCache::InstructionInfo& info); 252 bool Compile_Load(Instruction instruction, const CodeCache::InstructionInfo& info); 253 bool Compile_Store(Instruction instruction, const CodeCache::InstructionInfo& info); 254 bool Compile_LoadLeftRight(Instruction instruction, const CodeCache::InstructionInfo& info); 255 bool Compile_StoreLeftRight(Instruction instruction, const CodeCache::InstructionInfo& info); 256 bool Compile_MoveHiLo(Instruction instruction, const CodeCache::InstructionInfo& info); 257 bool Compile_Add(Instruction instruction, const CodeCache::InstructionInfo& info); 258 bool Compile_Subtract(Instruction instruction, const CodeCache::InstructionInfo& info); 259 bool Compile_Multiply(Instruction instruction, const CodeCache::InstructionInfo& info); 260 bool Compile_Divide(Instruction instruction, const CodeCache::InstructionInfo& info); 261 bool Compile_SignedDivide(Instruction instruction, const CodeCache::InstructionInfo& info); 262 bool Compile_SetLess(Instruction instruction, const CodeCache::InstructionInfo& info); 263 bool Compile_Branch(Instruction instruction, const CodeCache::InstructionInfo& info); 264 bool Compile_lui(Instruction instruction, const CodeCache::InstructionInfo& info); 265 bool Compile_cop0(Instruction instruction, const CodeCache::InstructionInfo& info); 266 bool Compile_cop2(Instruction instruction, const CodeCache::InstructionInfo& info); 267 268 CodeCache::Block* m_block = nullptr; 269 CodeBlockInstruction m_block_start = {}; 270 CodeBlockInstruction m_block_end = {}; 271 CodeBlockInstruction m_current_instruction = {}; 272 RegisterCache m_register_cache; 273 CodeEmitter m_near_emitter; 274 CodeEmitter m_far_emitter; 275 CodeEmitter* m_emit; 276 277 TickCount m_delayed_cycles_add = 0; 278 TickCount m_gte_done_cycle = 0; 279 280 u32 m_pc = 0; 281 bool m_pc_valid = false; 282 bool m_block_linked = false; 283 284 // whether various flags need to be reset. 285 bool m_current_instruction_in_branch_delay_slot_dirty = false; 286 bool m_branch_was_taken_dirty = false; 287 bool m_current_instruction_was_branch_taken_dirty = false; 288 bool m_load_delay_dirty = false; 289 bool m_next_load_delay_dirty = false; 290 bool m_gte_busy_cycles_dirty = false; 291 bool m_membase_loaded = false; 292 293 ////////////////////////////////////////////////////////////////////////// 294 // Speculative Constants 295 ////////////////////////////////////////////////////////////////////////// 296 struct SpeculativeConstants 297 { 298 std::array<SpeculativeValue, static_cast<u8>(Reg::count)> regs; 299 std::unordered_map<PhysicalMemoryAddress, SpeculativeValue> memory; 300 SpeculativeValue cop0_sr; 301 }; 302 303 void InitSpeculativeRegs(); 304 void InvalidateSpeculativeValues(); 305 SpeculativeValue SpeculativeReadReg(Reg reg); 306 void SpeculativeWriteReg(Reg reg, SpeculativeValue value); 307 SpeculativeValue SpeculativeReadMemory(u32 address); 308 void SpeculativeWriteMemory(VirtualMemoryAddress address, SpeculativeValue value); 309 bool SpeculativeIsCacheIsolated(); 310 311 SpeculativeConstants m_speculative_constants; 312 }; 313 314 } // namespace CPU::Recompiler