CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/FakeEmitter.h
Views: 1401
1
// Copyright (C) 2003 Dolphin 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.
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 SVN repository and contact information can be found at
16
// http://code.google.com/p/dolphin-emu/
17
18
// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!!
19
20
#ifndef _DOLPHIN_FAKE_CODEGEN_
21
#define _DOLPHIN_FAKE_CODEGEN_
22
23
#include <stdint.h>
24
25
#include "Common/CommonTypes.h"
26
#include "Common/CodeBlock.h"
27
28
// VCVT flags
29
#define TO_FLOAT 0
30
#define TO_INT 1 << 0
31
#define IS_SIGNED 1 << 1
32
#define ROUND_TO_ZERO 1 << 2
33
34
namespace FakeGen
35
{
36
enum FakeReg
37
{
38
// GPRs
39
R0 = 0, R1, R2, R3, R4, R5,
40
R6, R7, R8, R9, R10, R11,
41
42
// SPRs
43
// R13 - R15 are SP, LR, and PC.
44
// Almost always referred to by name instead of register number
45
R12 = 12, R13 = 13, R14 = 14, R15 = 15,
46
R_IP = 12, R_SP = 13, R_LR = 14, R_PC = 15,
47
48
49
// VFP single precision registers
50
S0, S1, S2, S3, S4, S5, S6,
51
S7, S8, S9, S10, S11, S12, S13,
52
S14, S15, S16, S17, S18, S19, S20,
53
S21, S22, S23, S24, S25, S26, S27,
54
S28, S29, S30, S31,
55
56
// VFP Double Precision registers
57
D0, D1, D2, D3, D4, D5, D6, D7,
58
D8, D9, D10, D11, D12, D13, D14, D15,
59
D16, D17, D18, D19, D20, D21, D22, D23,
60
D24, D25, D26, D27, D28, D29, D30, D31,
61
62
// ASIMD Quad-Word registers
63
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
64
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
65
66
// for NEON VLD/VST instructions
67
REG_UPDATE = R13,
68
INVALID_REG = 0xFFFFFFFF
69
};
70
71
enum CCFlags
72
{
73
CC_EQ = 0, // Equal
74
CC_NEQ, // Not equal
75
CC_CS, // Carry Set
76
CC_CC, // Carry Clear
77
CC_MI, // Minus (Negative)
78
CC_PL, // Plus
79
CC_VS, // Overflow
80
CC_VC, // No Overflow
81
CC_HI, // Unsigned higher
82
CC_LS, // Unsigned lower or same
83
CC_GE, // Signed greater than or equal
84
CC_LT, // Signed less than
85
CC_GT, // Signed greater than
86
CC_LE, // Signed less than or equal
87
CC_AL, // Always (unconditional) 14
88
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
89
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
90
};
91
const u32 NO_COND = 0xE0000000;
92
93
enum ShiftType
94
{
95
ST_LSL = 0,
96
ST_ASL = 0,
97
ST_LSR = 1,
98
ST_ASR = 2,
99
ST_ROR = 3,
100
ST_RRX = 4
101
};
102
enum IntegerSize
103
{
104
I_I8 = 0,
105
I_I16,
106
I_I32,
107
I_I64
108
};
109
110
enum
111
{
112
NUMGPRs = 13,
113
};
114
115
class FakeXEmitter;
116
117
enum OpType
118
{
119
TYPE_IMM = 0,
120
TYPE_REG,
121
TYPE_IMMSREG,
122
TYPE_RSR,
123
TYPE_MEM
124
};
125
126
// This is no longer a proper operand2 class. Need to split up.
127
class Operand2
128
{
129
friend class FakeXEmitter;
130
protected:
131
u32 Value;
132
133
private:
134
OpType Type;
135
136
// IMM types
137
u8 Rotation; // Only for u8 values
138
139
// Register types
140
u8 IndexOrShift;
141
ShiftType Shift;
142
public:
143
OpType GetType()
144
{
145
return Type;
146
}
147
Operand2() {}
148
Operand2(u32 imm, OpType type = TYPE_IMM) : IndexOrShift(), Shift()
149
{
150
Type = type;
151
Value = imm;
152
Rotation = 0;
153
}
154
155
Operand2(FakeReg Reg) : IndexOrShift(), Shift()
156
{
157
Type = TYPE_REG;
158
Value = Reg;
159
Rotation = 0;
160
}
161
Operand2(u8 imm, u8 rotation) : IndexOrShift(), Shift()
162
{
163
Type = TYPE_IMM;
164
Value = imm;
165
Rotation = rotation;
166
}
167
Operand2(FakeReg base, ShiftType type, FakeReg shift) : Rotation(0) // RSR
168
{
169
Type = TYPE_RSR;
170
_assert_msg_(type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");
171
IndexOrShift = shift;
172
Shift = type;
173
Value = base;
174
}
175
176
Operand2(FakeReg base, ShiftType type, u8 shift) : Rotation(0) // For IMM shifted register
177
{
178
if(shift == 32) shift = 0;
179
switch (type)
180
{
181
case ST_LSL:
182
_assert_msg_(shift < 32, "Invalid Operand2: LSL %u", shift);
183
break;
184
case ST_LSR:
185
_assert_msg_(shift <= 32, "Invalid Operand2: LSR %u", shift);
186
if (!shift)
187
type = ST_LSL;
188
if (shift == 32)
189
shift = 0;
190
break;
191
case ST_ASR:
192
_assert_msg_(shift < 32, "Invalid Operand2: ASR %u", shift);
193
if (!shift)
194
type = ST_LSL;
195
if (shift == 32)
196
shift = 0;
197
break;
198
case ST_ROR:
199
_assert_msg_(shift < 32, "Invalid Operand2: ROR %u", shift);
200
if (!shift)
201
type = ST_LSL;
202
break;
203
case ST_RRX:
204
_assert_msg_(shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");
205
type = ST_ROR;
206
break;
207
}
208
IndexOrShift = shift;
209
Shift = type;
210
Value = base;
211
Type = TYPE_IMMSREG;
212
}
213
u32 GetData()
214
{
215
switch(Type)
216
{
217
case TYPE_IMM:
218
return Imm12Mod(); // This'll need to be changed later
219
case TYPE_REG:
220
return Rm();
221
case TYPE_IMMSREG:
222
return IMMSR();
223
case TYPE_RSR:
224
return RSR();
225
default:
226
_assert_msg_(false, "GetData with Invalid Type");
227
return 0;
228
}
229
}
230
u32 IMMSR() // IMM shifted register
231
{
232
_assert_msg_(Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");
233
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
234
}
235
u32 RSR() // Register shifted register
236
{
237
_assert_msg_(Type == TYPE_RSR, "RSR must be RSR Of Course");
238
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
239
}
240
u32 Rm()
241
{
242
_assert_msg_(Type == TYPE_REG, "Rm must be with Reg");
243
return Value;
244
}
245
246
u32 Imm5()
247
{
248
_assert_msg_(Type == TYPE_IMM, "Imm5 not IMM value");
249
return ((Value & 0x0000001F) << 7);
250
}
251
u32 Imm8()
252
{
253
_assert_msg_(Type == TYPE_IMM, "Imm8Rot not IMM value");
254
return Value & 0xFF;
255
}
256
u32 Imm8Rot() // IMM8 with Rotation
257
{
258
_assert_msg_(Type == TYPE_IMM, "Imm8Rot not IMM value");
259
_assert_msg_((Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
260
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
261
}
262
u32 Imm12()
263
{
264
_assert_msg_(Type == TYPE_IMM, "Imm12 not IMM");
265
return (Value & 0x00000FFF);
266
}
267
268
u32 Imm12Mod()
269
{
270
// This is an IMM12 with the top four bits being rotation and the
271
// bottom eight being an IMM. This is for instructions that need to
272
// expand a 8bit IMM to a 32bit value and gives you some rotation as
273
// well.
274
// Each rotation rotates to the right by 2 bits
275
_assert_msg_(Type == TYPE_IMM, "Imm12Mod not IMM");
276
return ((Rotation & 0xF) << 8) | (Value & 0xFF);
277
}
278
u32 Imm16()
279
{
280
_assert_msg_(Type == TYPE_IMM, "Imm16 not IMM");
281
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
282
}
283
u32 Imm16Low()
284
{
285
return Imm16();
286
}
287
u32 Imm16High() // Returns high 16bits
288
{
289
_assert_msg_(Type == TYPE_IMM, "Imm16 not IMM");
290
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
291
}
292
u32 Imm24()
293
{
294
_assert_msg_(Type == TYPE_IMM, "Imm16 not IMM");
295
return (Value & 0x0FFFFFFF);
296
}
297
};
298
299
// Use these when you don't know if an imm can be represented as an operand2.
300
// This lets you generate both an optimal and a fallback solution by checking
301
// the return value, which will be false if these fail to find a Operand2 that
302
// represents your 32-bit imm value.
303
bool TryMakeOperand2(u32 imm, Operand2 &op2);
304
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
305
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
306
307
// Use this only when you know imm can be made into an Operand2.
308
Operand2 AssumeMakeOperand2(u32 imm);
309
310
inline Operand2 R(FakeReg Reg) { return Operand2(Reg, TYPE_REG); }
311
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
312
inline Operand2 Mem(void *ptr) { return Operand2((u32)(uintptr_t)ptr, TYPE_IMM); }
313
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
314
#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))
315
316
317
struct FixupBranch
318
{
319
u8 *ptr;
320
u32 condition; // Remembers our codition at the time
321
int type; //0 = B 1 = BL
322
};
323
324
typedef const u8* JumpTarget;
325
326
// XXX: Stop polluting the global namespace
327
const u32 I_8 = (1 << 0);
328
const u32 I_16 = (1 << 1);
329
const u32 I_32 = (1 << 2);
330
const u32 I_64 = (1 << 3);
331
const u32 I_SIGNED = (1 << 4);
332
const u32 I_UNSIGNED = (1 << 5);
333
const u32 F_32 = (1 << 6);
334
const u32 I_POLYNOMIAL = (1 << 7); // Only used in VMUL/VMULL
335
336
u32 EncodeVd(FakeReg Vd);
337
u32 EncodeVn(FakeReg Vn);
338
u32 EncodeVm(FakeReg Vm);
339
340
u32 encodedSize(u32 value);
341
342
// Subtracts the base from the register to give us the real one
343
FakeReg SubBase(FakeReg Reg);
344
345
// See A.7.1 in the Fakev7-A
346
// VMUL F32 scalars can only be up to D15[0], D15[1] - higher scalars cannot be individually addressed
347
FakeReg DScalar(FakeReg dreg, int subScalar);
348
FakeReg QScalar(FakeReg qreg, int subScalar);
349
350
enum NEONAlignment {
351
ALIGN_NONE = 0,
352
ALIGN_64 = 1,
353
ALIGN_128 = 2,
354
ALIGN_256 = 3
355
};
356
357
358
class NEONXEmitter;
359
360
class FakeXEmitter
361
{
362
friend struct OpArg; // for Write8 etc
363
private:
364
u8 *code, *startcode;
365
u8 *lastCacheFlushEnd;
366
u32 condition;
367
368
protected:
369
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
370
371
public:
372
FakeXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {
373
condition = CC_AL << 28;
374
}
375
FakeXEmitter(u8 *code_ptr) {
376
code = code_ptr;
377
lastCacheFlushEnd = code_ptr;
378
startcode = code_ptr;
379
condition = CC_AL << 28;
380
}
381
virtual ~FakeXEmitter() {}
382
383
void SetCodePointer(u8 *ptr, u8 *writePtr) {}
384
const u8 *GetCodePointer() const { return nullptr; }
385
386
void SetCodePtr(u8 *ptr) {}
387
void ReserveCodeSpace(u32 bytes) {}
388
const u8 *AlignCode16() { return nullptr; }
389
const u8 *AlignCodePage() { return nullptr; }
390
const u8 *GetCodePtr() const { return nullptr; }
391
void FlushIcache() {}
392
void FlushIcacheSection(u8 *start, u8 *end) {}
393
u8 *GetWritableCodePtr() { return nullptr; }
394
395
CCFlags GetCC() { return CCFlags(condition >> 28); }
396
void SetCC(CCFlags cond = CC_AL) {}
397
398
// Special purpose instructions
399
400
// Do nothing
401
void NOP(int count = 1) {} //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
402
403
#ifdef CALL
404
#undef CALL
405
#endif
406
407
void QuickCallFunction(FakeReg scratchreg, const void *func);
408
template <typename T> void QuickCallFunction(FakeReg scratchreg, T func) {
409
QuickCallFunction(scratchreg, (const void *)func);
410
}
411
}; // class FakeXEmitter
412
413
414
// Everything that needs to generate machine code should inherit from this.
415
// You get memory management for free, plus, you can use all the MOV etc functions without
416
// having to prefix them with gen-> or something similar.
417
class FakeXCodeBlock : public CodeBlock<FakeXEmitter> {
418
public:
419
void PoisonMemory(int offset) override {
420
}
421
};
422
423
} // namespace
424
425
#endif // _DOLPHIN_FAKE_CODEGEN_
426
427