1 // Copyright (c) 2013- 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 
19 #pragma once
20 
21 #include "Common/Common.h"
22 #include "Common/Log.h"
23 #include "Core/MIPS/MIPS.h"
24 
25 struct JitBlock;
26 class JitBlockCache;
27 
28 namespace MIPSComp {
29 
30 	enum CompileDelaySlotFlags
31 	{
32 		// Easy, nothing extra.
33 		DELAYSLOT_NICE = 0,
34 		// Flush registers after delay slot.
35 		DELAYSLOT_FLUSH = 1,
36 		// Preserve flags.
37 		DELAYSLOT_SAFE = 2,
38 		// Flush registers after and preserve flags.
39 		DELAYSLOT_SAFE_FLUSH = DELAYSLOT_FLUSH | DELAYSLOT_SAFE,
40 	};
41 
42 	struct JitState
43 	{
44 		enum PrefixState
45 		{
46 			PREFIX_UNKNOWN = 0x00,
47 			PREFIX_KNOWN = 0x01,
48 			PREFIX_DIRTY = 0x10,
49 			PREFIX_KNOWN_DIRTY = 0x11,
50 		};
51 
52 		enum AfterOp
53 		{
54 			AFTER_NONE = 0x00,
55 			AFTER_CORE_STATE = 0x01,
56 			AFTER_REWIND_PC_BAD_STATE = 0x02,
57 			AFTER_MEMCHECK_CLEANUP = 0x04,
58 		};
59 
60 		u32 compilerPC;
61 		u32 blockStart;
62 		u32 lastContinuedPC;
63 		u32 initialBlockSize;
64 		int nextExit;
65 		bool cancel;
66 		bool inDelaySlot;
67 		// See JitState::AfterOp for values.
68 		int afterOp;
69 		int downcountAmount;
70 		int numInstructions;
71 		bool compiling;	// TODO: get rid of this in favor of using analysis results to determine end of block
72 		bool hadBreakpoints;
73 		bool preloading = false;
74 		JitBlock *curBlock;
75 
76 		u8 hasSetRounding = 0;
77 		u8 lastSetRounding = 0;
78 		const u8 *currentRoundingFunc = nullptr;
79 
80 		// VFPU prefix magic
81 		bool startDefaultPrefix = true;
82 		u32 prefixS;
83 		u32 prefixT;
84 		u32 prefixD;
85 		PrefixState prefixSFlag = PREFIX_UNKNOWN;
86 		PrefixState prefixTFlag = PREFIX_UNKNOWN;
87 		PrefixState prefixDFlag = PREFIX_UNKNOWN;
88 
PrefixStartJitState89 		void PrefixStart() {
90 			if (startDefaultPrefix) {
91 				EatPrefix();
92 			} else {
93 				PrefixUnknown();
94 			}
95 		}
96 
PrefixUnknownJitState97 		void PrefixUnknown() {
98 			prefixSFlag = PREFIX_UNKNOWN;
99 			prefixTFlag = PREFIX_UNKNOWN;
100 			prefixDFlag = PREFIX_UNKNOWN;
101 		}
102 
HasSPrefixJitState103 		bool HasSPrefix() const {
104 			return (prefixSFlag & PREFIX_KNOWN) == 0 || prefixS != 0xE4;
105 		}
106 
HasTPrefixJitState107 		bool HasTPrefix() const {
108 			return (prefixTFlag & PREFIX_KNOWN) == 0 || prefixT != 0xE4;
109 		}
110 
HasDPrefixJitState111 		bool HasDPrefix() const {
112 			return (prefixDFlag & PREFIX_KNOWN) == 0 || prefixD != 0x0;
113 		}
114 
MayHavePrefixJitState115 		bool MayHavePrefix() const {
116 			if (HasUnknownPrefix()) {
117 				return true;
118 			} else if (prefixS != 0xE4 || prefixT != 0xE4 || prefixD != 0) {
119 				return true;
120 			}
121 			return false;
122 		}
123 
HasUnknownPrefixJitState124 		bool HasUnknownPrefix() const {
125 			if (!(prefixSFlag & PREFIX_KNOWN) || !(prefixTFlag & PREFIX_KNOWN) || !(prefixDFlag & PREFIX_KNOWN)) {
126 				return true;
127 			}
128 			return false;
129 		}
130 
HasNoPrefixJitState131 		bool HasNoPrefix() const {
132 			return !HasSPrefix() && !HasTPrefix() && !HasDPrefix();
133 		}
134 
EatPrefixJitState135 		void EatPrefix() {
136 			if (HasSPrefix())
137 				prefixSFlag = PREFIX_KNOWN_DIRTY;
138 			prefixS = 0xE4;
139 			if (HasTPrefix())
140 				prefixTFlag = PREFIX_KNOWN_DIRTY;
141 			prefixT = 0xE4;
142 			if (HasDPrefix())
143 				prefixDFlag = PREFIX_KNOWN_DIRTY;
144 			prefixD = 0x0;
145 		}
146 
VfpuWriteMaskJitState147 		u8 VfpuWriteMask() const {
148 			_assert_(prefixDFlag & JitState::PREFIX_KNOWN);
149 			return (prefixD >> 8) & 0xF;
150 		}
151 
VfpuWriteMaskJitState152 		bool VfpuWriteMask(int i) const {
153 			_assert_(prefixDFlag & JitState::PREFIX_KNOWN);
154 			return (prefixD >> (8 + i)) & 1;
155 		}
156 
LogPrefixJitState157 		void LogPrefix() {
158 			LogSTPrefix("S", prefixS, prefixSFlag);
159 			LogSTPrefix("T", prefixT, prefixTFlag);
160 			LogDPrefix();
161 		}
162 
163 	private:
LogSTPrefixJitState164 		void LogSTPrefix(const char *name, int p, int pflag) {
165 			if ((prefixSFlag & PREFIX_KNOWN) == 0) {
166 				ERROR_LOG(JIT, "%s: unknown  (%08x %i)", name, p, pflag);
167 			} else if (prefixS != 0xE4) {
168 				ERROR_LOG(JIT, "%s: %08x flag: %i", name, p, pflag);
169 			} else {
170 				WARN_LOG(JIT, "%s: %08x flag: %i", name, p, pflag);
171 			}
172 		}
LogDPrefixJitState173 		void LogDPrefix() {
174 			if ((prefixDFlag & PREFIX_KNOWN) == 0) {
175 				ERROR_LOG(JIT, "D: unknown (%08x %i)", prefixD, prefixDFlag);
176 			} else if (prefixD != 0) {
177 				ERROR_LOG(JIT, "D: (%08x %i)", prefixD, prefixDFlag);
178 			} else {
179 				WARN_LOG(JIT, "D: %08x flag: %i", prefixD, prefixDFlag);
180 			}
181 		}
182 	};
183 
184 	enum class JitDisable {
185 		ALU = 0x0001,
186 		ALU_IMM = 0x0002,
187 		ALU_BIT = 0x0004,
188 		MULDIV = 0x0008,
189 
190 		FPU = 0x0010,
191 		FPU_COMP = 0x0040,
192 		FPU_XFER = 0x0080,
193 
194 		VFPU_VEC = 0x0100,
195 		VFPU_MTX_VTFM = 0x0200,
196 		VFPU_COMP = 0x0400,
197 		VFPU_XFER = 0x0800,
198 
199 		LSU = 0x1000,
200 		LSU_UNALIGNED = 0x2000,
201 		LSU_FPU = 0x4000,
202 		LSU_VFPU = 0x8000,
203 
204 		SIMD = 0x00100000,
205 		BLOCKLINK = 0x00200000,
206 		POINTERIFY = 0x00400000,
207 		STATIC_ALLOC = 0x00800000,
208 		CACHE_POINTERS = 0x01000000,
209 		REGALLOC_GPR = 0x02000000,  // Doesn't really disable regalloc, but flushes after every instr.
210 		REGALLOC_FPR = 0x04000000,
211 		VFPU_MTX_VMMOV = 0x08000000,
212 		VFPU_MTX_VMMUL = 0x10000000,
213 		VFPU_MTX_VMSCL = 0x20000000,
214 
215 		ALL_FLAGS = 0x3FFFFFFF,
216 	};
217 
218 	struct JitOptions {
219 		JitOptions();
220 
221 		bool Disabled(JitDisable bit);
222 
223 		uint32_t disableFlags;
224 
225 		// x86
226 		bool enableVFPUSIMD;
227 		bool reserveR15ForAsm;
228 
229 		// ARM/ARM64
230 		bool useBackJump;
231 		bool useForwardJump;
232 		bool cachePointers;
233 		// ARM only
234 		bool useNEONVFPU;
235 		bool downcountInRegister;
236 		// ARM64 only
237 		bool useASIMDVFPU;
238 		bool useStaticAlloc;
239 		bool enablePointerify;
240 
241 		// Common
242 		bool enableBlocklink;
243 		bool immBranches;
244 		bool continueBranches;
245 		bool continueJumps;
246 		int continueMaxInstructions;
247 	};
248 
249 }
250 
251