1 // Copyright 2016 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <unordered_map>
8 
9 #include "Common/BitSet.h"
10 #include "Common/CommonTypes.h"
11 #include "Common/x64Emitter.h"
12 
13 #include "Core/PowerPC/Jit64Common/ConstantPool.h"
14 #include "Core/PowerPC/Jit64Common/FarCodeCache.h"
15 #include "Core/PowerPC/Jit64Common/TrampolineInfo.h"
16 
17 namespace MMIO
18 {
19 class Mapping;
20 }
21 
22 class Jit64;
23 
24 // Like XCodeBlock but has some utilities for memory access.
25 class EmuCodeBlock : public Gen::X64CodeBlock
26 {
27 public:
EmuCodeBlock(Jit64 & jit)28   explicit EmuCodeBlock(Jit64& jit) : m_jit{jit} {}
29   void MemoryExceptionCheck();
30 
31   // Simple functions to switch between near and far code emitting
32   void SwitchToFarCode();
33   void SwitchToNearCode();
34 
35   template <typename T>
GetConstantFromPool(const T & value)36   const void* GetConstantFromPool(const T& value)
37   {
38     return m_const_pool.GetConstant(&value, sizeof(T), 1, 0);
39   }
40 
41   template <typename T>
MConst(const T & value)42   Gen::OpArg MConst(const T& value)
43   {
44     return Gen::M(GetConstantFromPool(value));
45   }
46 
47   template <typename T, size_t N>
48   Gen::OpArg MConst(const T (&value)[N], size_t index = 0)
49   {
50     return Gen::M(m_const_pool.GetConstant(&value, sizeof(T), N, index));
51   }
52 
53   Gen::FixupBranch CheckIfSafeAddress(const Gen::OpArg& reg_value, Gen::X64Reg reg_addr,
54                                       BitSet32 registers_in_use);
55   void UnsafeLoadRegToReg(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize,
56                           s32 offset = 0, bool signExtend = false);
57   void UnsafeLoadRegToRegNoSwap(Gen::X64Reg reg_addr, Gen::X64Reg reg_value, int accessSize,
58                                 s32 offset, bool signExtend = false);
59   // these return the address of the MOV, for backpatching
60   void UnsafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize,
61                            s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr);
62   void UnsafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize,
63                            s32 offset = 0, bool swap = true, Gen::MovInfo* info = nullptr);
64 
65   bool UnsafeLoadToReg(Gen::X64Reg reg_value, Gen::OpArg opAddress, int accessSize, s32 offset,
66                        bool signExtend, Gen::MovInfo* info = nullptr);
67 
68   // Generate a load/write from the MMIO handler for a given address. Only
69   // call for known addresses in MMIO range (MMIO::IsMMIOAddress).
70   void MMIOLoadToReg(MMIO::Mapping* mmio, Gen::X64Reg reg_value, BitSet32 registers_in_use,
71                      u32 address, int access_size, bool sign_extend);
72 
73   enum SafeLoadStoreFlags
74   {
75     SAFE_LOADSTORE_NO_SWAP = 1,
76     SAFE_LOADSTORE_NO_PROLOG = 2,
77     // This indicates that the write being generated cannot be patched (and thus can't use fastmem)
78     SAFE_LOADSTORE_NO_FASTMEM = 4,
79     SAFE_LOADSTORE_CLOBBER_RSCRATCH_INSTEAD_OF_ADDR = 8,
80     // Force slowmem (used when generating fallbacks in trampolines)
81     SAFE_LOADSTORE_FORCE_SLOWMEM = 16,
82     SAFE_LOADSTORE_DR_ON = 32,
83     // Generated from a context that doesn't have the PC of the instruction that caused it
84     SAFE_LOADSTORE_NO_UPDATE_PC = 64,
85   };
86 
87   void SafeLoadToReg(Gen::X64Reg reg_value, const Gen::OpArg& opAddress, int accessSize, s32 offset,
88                      BitSet32 registersInUse, bool signExtend, int flags = 0);
89   void SafeLoadToRegImmediate(Gen::X64Reg reg_value, u32 address, int accessSize,
90                               BitSet32 registersInUse, bool signExtend);
91 
92   // Clobbers RSCRATCH or reg_addr depending on the relevant flag.  Preserves
93   // reg_value if the load fails and js.memcheck is enabled.
94   // Works with immediate inputs and simple registers only.
95   void SafeWriteRegToReg(Gen::OpArg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset,
96                          BitSet32 registersInUse, int flags = 0);
97   void SafeWriteRegToReg(Gen::X64Reg reg_value, Gen::X64Reg reg_addr, int accessSize, s32 offset,
98                          BitSet32 registersInUse, int flags = 0);
99 
100   // applies to safe and unsafe WriteRegToReg
101   bool WriteClobbersRegValue(int accessSize, bool swap);
102 
103   // returns true if an exception could have been caused
104   bool WriteToConstAddress(int accessSize, Gen::OpArg arg, u32 address, BitSet32 registersInUse);
105   void WriteToConstRamAddress(int accessSize, Gen::OpArg arg, u32 address, bool swap = true);
106 
107   void JitGetAndClearCAOV(bool oe);
108   void JitSetCA();
109   void JitSetCAIf(Gen::CCFlags conditionCode);
110   void JitClearCA();
111 
112   void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&),
113               void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&), Gen::X64Reg regOp,
114               const Gen::OpArg& arg1, const Gen::OpArg& arg2, bool packed = true,
115               bool reversible = false);
116   void avx_op(void (Gen::XEmitter::*avxOp)(Gen::X64Reg, Gen::X64Reg, const Gen::OpArg&, u8),
117               void (Gen::XEmitter::*sseOp)(Gen::X64Reg, const Gen::OpArg&, u8), Gen::X64Reg regOp,
118               const Gen::OpArg& arg1, const Gen::OpArg& arg2, u8 imm);
119 
120   void ForceSinglePrecision(Gen::X64Reg output, const Gen::OpArg& input, bool packed = true,
121                             bool duplicate = false);
122   void Force25BitPrecision(Gen::X64Reg output, const Gen::OpArg& input, Gen::X64Reg tmp);
123 
124   // RSCRATCH might get trashed
125   void ConvertSingleToDouble(Gen::X64Reg dst, Gen::X64Reg src, bool src_is_gpr = false);
126   void ConvertDoubleToSingle(Gen::X64Reg dst, Gen::X64Reg src);
127   void SetFPRF(Gen::X64Reg xmm);
128   void Clear();
129 
130 protected:
131   Jit64& m_jit;
132   ConstantPool m_const_pool;
133   FarCodeCache m_far_code;
134 
135   // Backed up when we switch to far code.
136   u8* m_near_code;
137   u8* m_near_code_end;
138   bool m_near_code_write_failed;
139 
140   std::unordered_map<u8*, TrampolineInfo> m_back_patch_info;
141   std::unordered_map<u8*, u8*> m_exception_handler_at_loc;
142 };
143