~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Common/FakeEmitter.h

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <vector>
 
24
#include <stdint.h>
 
25
 
 
26
#include "Common.h"
 
27
#include "MsgHandler.h"
 
28
 
 
29
// TODO: Check if Pandora still needs signal.h/kill here. Symbian doesn't.
 
30
 
 
31
// VCVT flags
 
32
#define TO_FLOAT      0
 
33
#define TO_INT        1 << 0
 
34
#define IS_SIGNED     1 << 1
 
35
#define ROUND_TO_ZERO 1 << 2
 
36
 
 
37
namespace FakeGen
 
38
{
 
39
enum FakeReg
 
40
{
 
41
        // GPRs
 
42
        R0 = 0, R1, R2, R3, R4, R5,
 
43
        R6, R7, R8, R9, R10, R11,
 
44
 
 
45
        // SPRs
 
46
        // R13 - R15 are SP, LR, and PC.
 
47
        // Almost always referred to by name instead of register number
 
48
        R12 = 12, R13 = 13, R14 = 14, R15 = 15,
 
49
        R_IP = 12, R_SP = 13, R_LR = 14, R_PC = 15,
 
50
 
 
51
 
 
52
        // VFP single precision registers
 
53
        S0, S1, S2, S3, S4, S5, S6,
 
54
        S7, S8, S9, S10, S11, S12, S13,
 
55
        S14, S15, S16, S17, S18, S19, S20,
 
56
        S21, S22, S23, S24, S25, S26, S27,
 
57
        S28, S29, S30, S31,
 
58
 
 
59
        // VFP Double Precision registers
 
60
        D0, D1, D2, D3, D4, D5, D6, D7,
 
61
        D8, D9, D10, D11, D12, D13, D14, D15,
 
62
        D16, D17, D18, D19, D20, D21, D22, D23,
 
63
        D24, D25, D26, D27, D28, D29, D30, D31,
 
64
        
 
65
        // ASIMD Quad-Word registers
 
66
        Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
 
67
        Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
 
68
 
 
69
        // for NEON VLD/VST instructions
 
70
        REG_UPDATE = R13,
 
71
        INVALID_REG = 0xFFFFFFFF
 
72
};
 
73
 
 
74
enum CCFlags
 
75
{
 
76
        CC_EQ = 0, // Equal
 
77
        CC_NEQ, // Not equal
 
78
        CC_CS, // Carry Set
 
79
        CC_CC, // Carry Clear
 
80
        CC_MI, // Minus (Negative)
 
81
        CC_PL, // Plus
 
82
        CC_VS, // Overflow
 
83
        CC_VC, // No Overflow
 
84
        CC_HI, // Unsigned higher
 
85
        CC_LS, // Unsigned lower or same
 
86
        CC_GE, // Signed greater than or equal
 
87
        CC_LT, // Signed less than
 
88
        CC_GT, // Signed greater than
 
89
        CC_LE, // Signed less than or equal
 
90
        CC_AL, // Always (unconditional) 14
 
91
        CC_HS = CC_CS, // Alias of CC_CS  Unsigned higher or same
 
92
        CC_LO = CC_CC, // Alias of CC_CC  Unsigned lower
 
93
};
 
94
const u32 NO_COND = 0xE0000000;
 
95
 
 
96
enum ShiftType
 
97
{
 
98
        ST_LSL = 0,
 
99
        ST_ASL = 0,
 
100
        ST_LSR = 1,
 
101
        ST_ASR = 2,
 
102
        ST_ROR = 3,
 
103
        ST_RRX = 4
 
104
};
 
105
enum IntegerSize
 
106
{
 
107
        I_I8 = 0, 
 
108
        I_I16,
 
109
        I_I32,
 
110
        I_I64
 
111
};
 
112
 
 
113
enum
 
114
{
 
115
        NUMGPRs = 13,
 
116
};
 
117
 
 
118
class FakeXEmitter;
 
119
 
 
120
enum OpType
 
121
{
 
122
        TYPE_IMM = 0,
 
123
        TYPE_REG,
 
124
        TYPE_IMMSREG,
 
125
        TYPE_RSR,
 
126
        TYPE_MEM
 
127
};
 
128
 
 
129
// This is no longer a proper operand2 class. Need to split up.
 
130
class Operand2
 
131
{
 
132
        friend class FakeXEmitter;
 
133
protected:
 
134
        u32 Value;
 
135
 
 
136
private:
 
137
        OpType Type;
 
138
 
 
139
        // IMM types
 
140
        u8      Rotation; // Only for u8 values
 
141
 
 
142
        // Register types
 
143
        u8 IndexOrShift;
 
144
        ShiftType Shift;
 
145
public:
 
146
        OpType GetType()
 
147
        {
 
148
                return Type;
 
149
        }
 
150
        Operand2() {} 
 
151
        Operand2(u32 imm, OpType type = TYPE_IMM)
 
152
        { 
 
153
                Type = type; 
 
154
                Value = imm; 
 
155
                Rotation = 0;
 
156
        }
 
157
 
 
158
        Operand2(FakeReg Reg)
 
159
        {
 
160
                Type = TYPE_REG;
 
161
                Value = Reg;
 
162
                Rotation = 0;
 
163
        }
 
164
        Operand2(u8 imm, u8 rotation)
 
165
        {
 
166
                Type = TYPE_IMM;
 
167
                Value = imm;
 
168
                Rotation = rotation;
 
169
        }
 
170
        Operand2(FakeReg base, ShiftType type, FakeReg shift) // RSR
 
171
        {
 
172
                Type = TYPE_RSR;
 
173
                _assert_msg_(JIT, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");
 
174
                IndexOrShift = shift;
 
175
                Shift = type;
 
176
                Value = base;
 
177
        }
 
178
 
 
179
        Operand2(FakeReg base, ShiftType type, u8 shift)// For IMM shifted register
 
180
        {
 
181
                if(shift == 32) shift = 0;
 
182
                switch (type)
 
183
                {
 
184
                case ST_LSL:
 
185
                        _assert_msg_(JIT, shift < 32, "Invalid Operand2: LSL %u", shift);
 
186
                        break;
 
187
                case ST_LSR:
 
188
                        _assert_msg_(JIT, shift <= 32, "Invalid Operand2: LSR %u", shift);
 
189
                        if (!shift)
 
190
                                type = ST_LSL;
 
191
                        if (shift == 32)
 
192
                                shift = 0;
 
193
                        break;
 
194
                case ST_ASR:
 
195
                        _assert_msg_(JIT, shift < 32, "Invalid Operand2: ASR %u", shift);
 
196
                        if (!shift)
 
197
                                type = ST_LSL;
 
198
                        if (shift == 32)
 
199
                                shift = 0;
 
200
                        break;
 
201
                case ST_ROR:
 
202
                        _assert_msg_(JIT, shift < 32, "Invalid Operand2: ROR %u", shift);
 
203
                        if (!shift)
 
204
                                type = ST_LSL;
 
205
                        break;
 
206
                case ST_RRX:
 
207
                        _assert_msg_(JIT, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");
 
208
                        type = ST_ROR;
 
209
                        break;
 
210
                }
 
211
                IndexOrShift = shift;
 
212
                Shift = type;
 
213
                Value = base;
 
214
                Type = TYPE_IMMSREG;
 
215
        }
 
216
        u32 GetData()
 
217
        {
 
218
                switch(Type)
 
219
                {
 
220
                case TYPE_IMM:
 
221
                        return Imm12Mod(); // This'll need to be changed later
 
222
                case TYPE_REG:
 
223
                        return Rm();
 
224
                case TYPE_IMMSREG:
 
225
                        return IMMSR();
 
226
                case TYPE_RSR:
 
227
                        return RSR();
 
228
                default:
 
229
                        _assert_msg_(JIT, false, "GetData with Invalid Type");
 
230
                        return 0;
 
231
                }
 
232
        }
 
233
        u32 IMMSR() // IMM shifted register
 
234
        {
 
235
                _assert_msg_(JIT, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");
 
236
                return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
 
237
        }
 
238
        u32 RSR() // Register shifted register
 
239
        {
 
240
                _assert_msg_(JIT, Type == TYPE_RSR, "RSR must be RSR Of Course");
 
241
                return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
 
242
        }
 
243
        u32 Rm()
 
244
        {
 
245
                _assert_msg_(JIT, Type == TYPE_REG, "Rm must be with Reg");
 
246
                return Value;
 
247
        }
 
248
 
 
249
        u32 Imm5()
 
250
        {
 
251
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm5 not IMM value");
 
252
                return ((Value & 0x0000001F) << 7);
 
253
        }
 
254
        u32 Imm8()
 
255
        {
 
256
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value");
 
257
                return Value & 0xFF;
 
258
        }
 
259
        u32 Imm8Rot() // IMM8 with Rotation
 
260
        {
 
261
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm8Rot not IMM value");
 
262
                _assert_msg_(JIT, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
 
263
                return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
 
264
        }
 
265
        u32 Imm12()
 
266
        {
 
267
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm12 not IMM");
 
268
                return (Value & 0x00000FFF);
 
269
        }
 
270
 
 
271
        u32 Imm12Mod()
 
272
        {
 
273
                // This is an IMM12 with the top four bits being rotation and the
 
274
                // bottom eight being an IMM. This is for instructions that need to
 
275
                // expand a 8bit IMM to a 32bit value and gives you some rotation as
 
276
                // well.
 
277
                // Each rotation rotates to the right by 2 bits
 
278
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm12Mod not IMM");
 
279
                return ((Rotation & 0xF) << 8) | (Value & 0xFF);
 
280
        }
 
281
        u32 Imm16()
 
282
        {
 
283
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
 
284
                return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
 
285
        }
 
286
        u32 Imm16Low()
 
287
        {
 
288
                return Imm16();
 
289
        }
 
290
        u32 Imm16High() // Returns high 16bits
 
291
        {
 
292
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
 
293
                return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
 
294
        }
 
295
        u32 Imm24()
 
296
        {
 
297
                _assert_msg_(JIT, (Type == TYPE_IMM), "Imm16 not IMM");
 
298
                return (Value & 0x0FFFFFFF);
 
299
        }
 
300
};
 
301
 
 
302
// Use these when you don't know if an imm can be represented as an operand2.
 
303
// This lets you generate both an optimal and a fallback solution by checking
 
304
// the return value, which will be false if these fail to find a Operand2 that
 
305
// represents your 32-bit imm value.
 
306
bool TryMakeOperand2(u32 imm, Operand2 &op2);
 
307
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
 
308
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
 
309
 
 
310
// Use this only when you know imm can be made into an Operand2.
 
311
Operand2 AssumeMakeOperand2(u32 imm);
 
312
 
 
313
inline Operand2 R(FakeReg Reg)  { return Operand2(Reg, TYPE_REG); }
 
314
inline Operand2 IMM(u32 Imm)    { return Operand2(Imm, TYPE_IMM); }
 
315
inline Operand2 Mem(void *ptr)  { return Operand2((u32)(uintptr_t)ptr, TYPE_IMM); }
 
316
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
 
317
#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))
 
318
 
 
319
 
 
320
struct FixupBranch
 
321
{
 
322
        u8 *ptr;
 
323
        u32 condition; // Remembers our codition at the time
 
324
        int type; //0 = B 1 = BL
 
325
};
 
326
 
 
327
typedef const u8* JumpTarget;
 
328
 
 
329
// XXX: Stop polluting the global namespace
 
330
const u32 I_8 = (1 << 0);
 
331
const u32 I_16 = (1 << 1);
 
332
const u32 I_32 = (1 << 2);
 
333
const u32 I_64 = (1 << 3);
 
334
const u32 I_SIGNED = (1 << 4);
 
335
const u32 I_UNSIGNED = (1 << 5);
 
336
const u32 F_32 = (1 << 6);
 
337
const u32 I_POLYNOMIAL = (1 << 7); // Only used in VMUL/VMULL
 
338
 
 
339
u32 EncodeVd(FakeReg Vd);
 
340
u32 EncodeVn(FakeReg Vn);
 
341
u32 EncodeVm(FakeReg Vm);
 
342
 
 
343
u32 encodedSize(u32 value);
 
344
 
 
345
// Subtracts the base from the register to give us the real one
 
346
FakeReg SubBase(FakeReg Reg);
 
347
 
 
348
// See A.7.1 in the Fakev7-A
 
349
// VMUL F32 scalars can only be up to D15[0], D15[1] - higher scalars cannot be individually addressed
 
350
FakeReg DScalar(FakeReg dreg, int subScalar);
 
351
FakeReg QScalar(FakeReg qreg, int subScalar);
 
352
 
 
353
enum NEONAlignment {
 
354
        ALIGN_NONE = 0,
 
355
        ALIGN_64 = 1,
 
356
        ALIGN_128 = 2,
 
357
        ALIGN_256 = 3
 
358
};
 
359
 
 
360
 
 
361
class NEONXEmitter;
 
362
 
 
363
class FakeXEmitter
 
364
{
 
365
        friend struct OpArg;  // for Write8 etc
 
366
private:
 
367
        u8 *code, *startcode;
 
368
        u8 *lastCacheFlushEnd;
 
369
        u32 condition;
 
370
 
 
371
protected:
 
372
        inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
 
373
 
 
374
public:
 
375
        FakeXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {
 
376
                condition = CC_AL << 28;
 
377
        }
 
378
        FakeXEmitter(u8 *code_ptr) {
 
379
                code = code_ptr;
 
380
                lastCacheFlushEnd = code_ptr;
 
381
                startcode = code_ptr;
 
382
                condition = CC_AL << 28;
 
383
        }
 
384
        virtual ~FakeXEmitter() {}
 
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 FakeXEmitter
 
418
{
 
419
protected:
 
420
        u8 *region;
 
421
        size_t region_size;
 
422
 
 
423
public:
 
424
        FakeXCodeBlock() : region(NULL), region_size(0) {}
 
425
        virtual ~FakeXCodeBlock() { if (region) FreeCodeSpace(); }
 
426
 
 
427
        // Call this before you generate any code.
 
428
        void AllocCodeSpace(int size) { }
 
429
 
 
430
        // Always clear code space with breakpoints, so that if someone accidentally executes
 
431
        // uninitialized, it just breaks into the debugger.
 
432
        void ClearCodeSpace() { }
 
433
 
 
434
        // Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
 
435
        void FreeCodeSpace() { }
 
436
 
 
437
        bool IsInSpace(const u8 *ptr) const
 
438
        {
 
439
                return ptr >= region && ptr < region + region_size;
 
440
        }
 
441
 
 
442
        // Cannot currently be undone. Will write protect the entire code region.
 
443
        // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
 
444
        void WriteProtect() { }
 
445
        void UnWriteProtect() { }
 
446
 
 
447
        void ResetCodePtr()
 
448
        {
 
449
                SetCodePtr(region);
 
450
        }
 
451
 
 
452
        size_t GetSpaceLeft() const
 
453
        {
 
454
                return region_size - (GetCodePtr() - region);
 
455
        }
 
456
 
 
457
        u8 *GetBasePtr() {
 
458
                return region;
 
459
        }
 
460
 
 
461
        size_t GetOffset(const u8 *ptr) const {
 
462
                return ptr - region;
 
463
        }
 
464
};
 
465
 
 
466
}  // namespace
 
467
 
 
468
#endif // _DOLPHIN_FAKE_CODEGEN_