~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to Core/MIPS/x86/CompFPU.cpp

  • 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) 2012- 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
#include "Core/Config.h"
 
19
#include "Core/MemMap.h"
 
20
#include "Common/Common.h"
 
21
#include "Core/MIPS/MIPS.h"
 
22
#include "Core/MIPS/MIPSCodeUtils.h"
 
23
#include "Core/MIPS/x86/Jit.h"
 
24
#include "Core/MIPS/x86/RegCache.h"
 
25
 
 
26
#define _RS MIPS_GET_RS(op)
 
27
#define _RT MIPS_GET_RT(op)
 
28
#define _RD MIPS_GET_RD(op)
 
29
#define _FS MIPS_GET_FS(op)
 
30
#define _FT MIPS_GET_FT(op)
 
31
#define _FD MIPS_GET_FD(op)
 
32
#define _SA MIPS_GET_SA(op)
 
33
#define _POS  ((op>> 6) & 0x1F)
 
34
#define _SIZE ((op>>11) & 0x1F)
 
35
#define _IMM16 (signed short)(op & 0xFFFF)
 
36
#define _IMM26 (op & 0x03FFFFFF)
 
37
 
 
38
// All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly.
 
39
// Currently known non working ones should have DISABLE.
 
40
 
 
41
// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; }
 
42
#define CONDITIONAL_DISABLE ;
 
43
#define DISABLE { Comp_Generic(op); return; }
 
44
 
 
45
namespace MIPSComp {
 
46
 
 
47
using namespace Gen;
 
48
using namespace X64JitConstants;
 
49
 
 
50
void Jit::CopyFPReg(X64Reg dst, OpArg src) {
 
51
        if (src.IsSimpleReg()) {
 
52
                MOVAPS(dst, src);
 
53
        } else {
 
54
                MOVSS(dst, src);
 
55
        }
 
56
}
 
57
 
 
58
void Jit::CompFPTriArith(MIPSOpcode op, void (XEmitter::*arith)(X64Reg reg, OpArg), bool orderMatters) {
 
59
        int ft = _FT;
 
60
        int fs = _FS;
 
61
        int fd = _FD;
 
62
        fpr.SpillLock(fd, fs, ft);
 
63
 
 
64
        if (fs == fd) {
 
65
                fpr.MapReg(fd, true, true);
 
66
                (this->*arith)(fpr.RX(fd), fpr.R(ft));
 
67
        } else if (ft == fd && !orderMatters) {
 
68
                fpr.MapReg(fd, true, true);
 
69
                (this->*arith)(fpr.RX(fd), fpr.R(fs));
 
70
        } else if (ft != fd) {
 
71
                // fs can't be fd (handled above.)
 
72
                fpr.MapReg(fd, false, true);
 
73
                CopyFPReg(fpr.RX(fd), fpr.R(fs));
 
74
                (this->*arith)(fpr.RX(fd), fpr.R(ft));
 
75
        } else {
 
76
                // fd must be ft, and order must matter.
 
77
                fpr.MapReg(fd, true, true);
 
78
                CopyFPReg(XMM0, fpr.R(fs));
 
79
                (this->*arith)(XMM0, fpr.R(ft));
 
80
                MOVAPS(fpr.RX(fd), R(XMM0));
 
81
        }
 
82
        fpr.ReleaseSpillLocks();
 
83
}
 
84
 
 
85
void Jit::Comp_FPU3op(MIPSOpcode op) {
 
86
        CONDITIONAL_DISABLE;
 
87
        switch (op & 0x3f) {
 
88
        case 0: CompFPTriArith(op, &XEmitter::ADDSS, false); break; //F(fd) = F(fs) + F(ft); //add
 
89
        case 1: CompFPTriArith(op, &XEmitter::SUBSS, true); break;  //F(fd) = F(fs) - F(ft); //sub
 
90
        case 2: CompFPTriArith(op, &XEmitter::MULSS, false); break; //F(fd) = F(fs) * F(ft); //mul
 
91
        case 3: CompFPTriArith(op, &XEmitter::DIVSS, true); break;  //F(fd) = F(fs) / F(ft); //div
 
92
        default:
 
93
                _dbg_assert_msg_(CPU,0,"Trying to compile FPU3Op instruction that can't be interpreted");
 
94
                break;
 
95
        }
 
96
}
 
97
 
 
98
static u32 MEMORY_ALIGNED16(ssLoadStoreTemp);
 
99
 
 
100
void Jit::Comp_FPULS(MIPSOpcode op) {
 
101
        CONDITIONAL_DISABLE;
 
102
        s32 offset = _IMM16;
 
103
        int ft = _FT;
 
104
        MIPSGPReg rs = _RS;
 
105
 
 
106
        switch (op >> 26) {
 
107
        case 49: //FI(ft) = Memory::Read_U32(addr); break; //lwc1
 
108
                {
 
109
                        gpr.Lock(rs);
 
110
                        fpr.SpillLock(ft);
 
111
                        fpr.MapReg(ft, false, true);
 
112
 
 
113
                        JitSafeMem safe(this, rs, offset);
 
114
                        OpArg src;
 
115
                        if (safe.PrepareRead(src, 4))
 
116
                                MOVSS(fpr.RX(ft), src);
 
117
                        if (safe.PrepareSlowRead(safeMemFuncs.readU32))
 
118
                                MOVD_xmm(fpr.RX(ft), R(EAX));
 
119
                        safe.Finish();
 
120
 
 
121
                        gpr.UnlockAll();
 
122
                        fpr.ReleaseSpillLocks();
 
123
                }
 
124
                break;
 
125
        case 57: //Memory::Write_U32(FI(ft), addr); break; //swc1
 
126
                {
 
127
                        gpr.Lock(rs);
 
128
                        fpr.SpillLock(ft);
 
129
                        fpr.MapReg(ft, true, false);
 
130
 
 
131
                        JitSafeMem safe(this, rs, offset);
 
132
                        OpArg dest;
 
133
                        if (safe.PrepareWrite(dest, 4))
 
134
                                MOVSS(dest, fpr.RX(ft));
 
135
                        if (safe.PrepareSlowWrite())
 
136
                        {
 
137
                                MOVSS(M(&ssLoadStoreTemp), fpr.RX(ft));
 
138
                                safe.DoSlowWrite(safeMemFuncs.writeU32, M(&ssLoadStoreTemp));
 
139
                        }
 
140
                        safe.Finish();
 
141
 
 
142
                        gpr.UnlockAll();
 
143
                        fpr.ReleaseSpillLocks();
 
144
                }
 
145
                break;
 
146
 
 
147
        default:
 
148
                _dbg_assert_msg_(CPU,0,"Trying to interpret FPULS instruction that can't be interpreted");
 
149
                break;
 
150
        }
 
151
}
 
152
 
 
153
static const u64 MEMORY_ALIGNED16(ssOneBits[2]) = {0x0000000100000001ULL, 0x0000000100000001ULL};
 
154
static const u64 MEMORY_ALIGNED16(ssSignBits2[2])       = {0x8000000080000000ULL, 0x8000000080000000ULL};
 
155
static const u64 MEMORY_ALIGNED16(ssNoSignMask[2]) = {0x7FFFFFFF7FFFFFFFULL, 0x7FFFFFFF7FFFFFFFULL};
 
156
 
 
157
void Jit::CompFPComp(int lhs, int rhs, u8 compare, bool allowNaN) {
 
158
        gpr.MapReg(MIPS_REG_FPCOND, false, true);
 
159
 
 
160
        // This means that NaN also means true, e.g. !<> or !>, etc.
 
161
        if (allowNaN) {
 
162
                CopyFPReg(XMM0, fpr.R(lhs));
 
163
                CopyFPReg(XMM1, fpr.R(lhs));
 
164
                CMPSS(XMM0, fpr.R(rhs), compare);
 
165
                CMPUNORDSS(XMM1, fpr.R(rhs));
 
166
 
 
167
                POR(XMM0, R(XMM1));
 
168
        } else {
 
169
                CopyFPReg(XMM0, fpr.R(lhs));
 
170
                CMPSS(XMM0, fpr.R(rhs), compare);
 
171
        }
 
172
 
 
173
        MOVD_xmm(gpr.R(MIPS_REG_FPCOND), XMM0);
 
174
}
 
175
 
 
176
void Jit::Comp_FPUComp(MIPSOpcode op) {
 
177
        CONDITIONAL_DISABLE;
 
178
 
 
179
        int fs = _FS;
 
180
        int ft = _FT;
 
181
 
 
182
        switch (op & 0xf) {
 
183
        case 0: //f
 
184
        case 8: //sf
 
185
                gpr.SetImm(MIPS_REG_FPCOND, 0);
 
186
                break;
 
187
 
 
188
        case 1: //un
 
189
        case 9: //ngle
 
190
                CompFPComp(fs, ft, CMP_UNORD);
 
191
                break;
 
192
 
 
193
        case 2: //eq
 
194
        case 10: //seq
 
195
                CompFPComp(fs, ft, CMP_EQ);
 
196
                break;
 
197
 
 
198
        case 3: //ueq
 
199
        case 11: //ngl
 
200
                CompFPComp(fs, ft, CMP_EQ, true);
 
201
                break;
 
202
 
 
203
        case 4: //olt
 
204
        case 12: //lt
 
205
                CompFPComp(fs, ft, CMP_LT);
 
206
                break;
 
207
 
 
208
        case 5: //ult
 
209
        case 13: //nge
 
210
                CompFPComp(ft, fs, CMP_NLE);
 
211
                break;
 
212
 
 
213
        case 6: //ole
 
214
        case 14: //le
 
215
                CompFPComp(fs, ft, CMP_LE);
 
216
                break;
 
217
 
 
218
        case 7: //ule
 
219
        case 15: //ngt
 
220
                CompFPComp(ft, fs, CMP_NLT);
 
221
                break;
 
222
 
 
223
        default:
 
224
                DISABLE;
 
225
        }
 
226
}
 
227
 
 
228
static u32 mxcsrTemp;
 
229
 
 
230
void Jit::Comp_FPU2op(MIPSOpcode op) {
 
231
        CONDITIONAL_DISABLE;
 
232
        
 
233
        int fs = _FS;
 
234
        int fd = _FD;
 
235
 
 
236
        auto execRounding = [&](void (XEmitter::*conv)(X64Reg, OpArg), int setMXCSR) {
 
237
                fpr.SpillLock(fd, fs);
 
238
                fpr.MapReg(fd, fs == fd, true);
 
239
 
 
240
                // Small optimization: 0 is our default mode anyway.
 
241
                if (setMXCSR == 0 && !js.hasSetRounding) {
 
242
                        setMXCSR = -1;
 
243
                }
 
244
                if (setMXCSR != -1) {
 
245
                        STMXCSR(M(&mxcsrTemp));
 
246
                        MOV(32, R(TEMPREG), M(&mxcsrTemp));
 
247
                        AND(32, R(TEMPREG), Imm32(~(3 << 13)));
 
248
                        OR(32, R(TEMPREG), Imm32(setMXCSR << 13));
 
249
                        MOV(32, M(&mips_->temp), R(TEMPREG));
 
250
                        LDMXCSR(M(&mips_->temp));
 
251
                }
 
252
 
 
253
                (this->*conv)(TEMPREG, fpr.R(fs));
 
254
 
 
255
                // Did we get an indefinite integer value?
 
256
                CMP(32, R(TEMPREG), Imm32(0x80000000));
 
257
                FixupBranch skip = J_CC(CC_NE);
 
258
                if (fd != fs) {
 
259
                        CopyFPReg(fpr.RX(fd), fpr.R(fs));
 
260
                }
 
261
                XORPS(XMM1, R(XMM1));
 
262
                CMPSS(fpr.RX(fd), R(XMM1), CMP_LT);
 
263
 
 
264
                // At this point, -inf = 0xffffffff, inf/nan = 0x00000000.
 
265
                // We want -inf to be 0x80000000 inf/nan to be 0x7fffffff, so we flip those bits.
 
266
                MOVD_xmm(R(TEMPREG), fpr.RX(fd));
 
267
                XOR(32, R(TEMPREG), Imm32(0x7fffffff));
 
268
 
 
269
                SetJumpTarget(skip);
 
270
                MOVD_xmm(fpr.RX(fd), R(TEMPREG));
 
271
 
 
272
                if (setMXCSR != -1) {
 
273
                        LDMXCSR(M(&mxcsrTemp));
 
274
                }
 
275
        };
 
276
 
 
277
        switch (op & 0x3f) {
 
278
        case 5: //F(fd) = fabsf(F(fs)); break; //abs
 
279
                fpr.SpillLock(fd, fs);
 
280
                fpr.MapReg(fd, fd == fs, true);
 
281
                if (fd != fs && fpr.IsMapped(fs)) {
 
282
                        MOVAPS(fpr.RX(fd), M(ssNoSignMask));
 
283
                        ANDPS(fpr.RX(fd), fpr.R(fs));
 
284
                } else {
 
285
                        if (fd != fs) {
 
286
                                MOVSS(fpr.RX(fd), fpr.R(fs));
 
287
                        }
 
288
                        ANDPS(fpr.RX(fd), M(ssNoSignMask));
 
289
                }
 
290
                break;
 
291
 
 
292
        case 6: //F(fd) = F(fs);                                break; //mov
 
293
                if (fd != fs) {
 
294
                        fpr.SpillLock(fd, fs);
 
295
                        fpr.MapReg(fd, fd == fs, true);
 
296
                        CopyFPReg(fpr.RX(fd), fpr.R(fs));
 
297
                }
 
298
                break;
 
299
 
 
300
        case 7: //F(fd) = -F(fs);                        break; //neg
 
301
                fpr.SpillLock(fd, fs);
 
302
                fpr.MapReg(fd, fd == fs, true);
 
303
                if (fd != fs && fpr.IsMapped(fs)) {
 
304
                        MOVAPS(fpr.RX(fd), M(ssSignBits2));
 
305
                        XORPS(fpr.RX(fd), fpr.R(fs));
 
306
                } else {
 
307
                        if (fd != fs) {
 
308
                                MOVSS(fpr.RX(fd), fpr.R(fs));
 
309
                        }
 
310
                        XORPS(fpr.RX(fd), M(ssSignBits2));
 
311
                }
 
312
                break;
 
313
 
 
314
 
 
315
        case 4: //F(fd) = sqrtf(F(fs)); break; //sqrt
 
316
                fpr.SpillLock(fd, fs);
 
317
                fpr.MapReg(fd, fd == fs, true);
 
318
                SQRTSS(fpr.RX(fd), fpr.R(fs));
 
319
                break;
 
320
 
 
321
        case 13: //FsI(fd) = F(fs)>=0 ? (int)floorf(F(fs)) : (int)ceilf(F(fs)); break;//trunc.w.s
 
322
                execRounding(&XEmitter::CVTTSS2SI, -1);
 
323
                break;
 
324
 
 
325
        case 32: //F(fd)        = (float)FsI(fs);                       break; //cvt.s.w
 
326
                fpr.SpillLock(fd, fs);
 
327
                fpr.MapReg(fd, fs == fd, true);
 
328
                if (fpr.IsMapped(fs)) {
 
329
                        CVTDQ2PS(fpr.RX(fd), fpr.R(fs));
 
330
                } else {
 
331
                        // If fs was fd, we'd be in the case above since we mapped fd.
 
332
                        MOVSS(fpr.RX(fd), fpr.R(fs));
 
333
                        CVTDQ2PS(fpr.RX(fd), fpr.R(fd));
 
334
                }
 
335
                break;
 
336
 
 
337
        case 36: //FsI(fd) = (int)      F(fs);                   break; //cvt.w.s
 
338
                // Uses the current rounding mode.
 
339
                execRounding(&XEmitter::CVTSS2SI, -1);
 
340
                break;
 
341
 
 
342
        case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
 
343
                execRounding(&XEmitter::CVTSS2SI, 0);
 
344
                break;
 
345
        case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s
 
346
                execRounding(&XEmitter::CVTSS2SI, 2);
 
347
                break;
 
348
        case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s
 
349
                execRounding(&XEmitter::CVTSS2SI, 1);
 
350
                break;
 
351
        default:
 
352
                DISABLE;
 
353
                return;
 
354
        }
 
355
        fpr.ReleaseSpillLocks();
 
356
}
 
357
 
 
358
void Jit::Comp_mxc1(MIPSOpcode op) {
 
359
        CONDITIONAL_DISABLE;
 
360
 
 
361
        int fs = _FS;
 
362
        MIPSGPReg rt = _RT;
 
363
 
 
364
        switch ((op >> 21) & 0x1f) {
 
365
        case 0: // R(rt) = FI(fs); break; //mfc1
 
366
                if (rt == MIPS_REG_ZERO)
 
367
                        return;
 
368
                gpr.MapReg(rt, false, true);
 
369
                // If fs is not mapped, most likely it's being abandoned.
 
370
                // Just load from memory in that case.
 
371
                if (fpr.R(fs).IsSimpleReg()) {
 
372
                        MOVD_xmm(gpr.R(rt), fpr.RX(fs));
 
373
                } else {
 
374
                        MOV(32, gpr.R(rt), fpr.R(fs));
 
375
                }
 
376
                break;
 
377
 
 
378
        case 2: // R(rt) = currentMIPS->ReadFCR(fs); break; //cfc1
 
379
                if (rt == MIPS_REG_ZERO)
 
380
                        return;
 
381
                if (fs == 31) {
 
382
                        bool wasImm = gpr.IsImm(MIPS_REG_FPCOND);
 
383
                        if (!wasImm) {
 
384
                                gpr.Lock(rt, MIPS_REG_FPCOND);
 
385
                                gpr.MapReg(MIPS_REG_FPCOND, true, false);
 
386
                        }
 
387
                        gpr.MapReg(rt, false, true);
 
388
                        MOV(32, gpr.R(rt), M(&mips_->fcr31));
 
389
                        if (wasImm) {
 
390
                                if (gpr.GetImm(MIPS_REG_FPCOND) & 1) {
 
391
                                        OR(32, gpr.R(rt), Imm32(1 << 23));
 
392
                                } else {
 
393
                                        AND(32, gpr.R(rt), Imm32(~(1 << 23)));
 
394
                                }
 
395
                        } else {
 
396
                                AND(32, gpr.R(rt), Imm32(~(1 << 23)));
 
397
                                MOV(32, R(TEMPREG), gpr.R(MIPS_REG_FPCOND));
 
398
                                AND(32, R(TEMPREG), Imm32(1));
 
399
                                SHL(32, R(TEMPREG), Imm8(23));
 
400
                                OR(32, gpr.R(rt), R(TEMPREG));
 
401
                        }
 
402
                        gpr.UnlockAll();
 
403
                } else if (fs == 0) {
 
404
                        gpr.SetImm(rt, MIPSState::FCR0_VALUE);
 
405
                } else {
 
406
                        Comp_Generic(op);
 
407
                }
 
408
                return;
 
409
 
 
410
        case 4: //FI(fs) = R(rt);       break; //mtc1
 
411
                fpr.MapReg(fs, false, true);
 
412
                if (gpr.IsImm(rt) && gpr.GetImm(rt) == 0) {
 
413
                        XORPS(fpr.RX(fs), fpr.R(fs));
 
414
                } else {
 
415
                        gpr.KillImmediate(rt, true, false);
 
416
                        MOVD_xmm(fpr.RX(fs), gpr.R(rt));
 
417
                }
 
418
                return;
 
419
 
 
420
        case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1
 
421
                if (fs == 31) {
 
422
                        // Must clear before setting, since ApplyRoundingMode() assumes it was cleared.
 
423
                        RestoreRoundingMode();
 
424
                        if (gpr.IsImm(rt)) {
 
425
                                gpr.SetImm(MIPS_REG_FPCOND, (gpr.GetImm(rt) >> 23) & 1);
 
426
                                MOV(32, M(&mips_->fcr31), Imm32(gpr.GetImm(rt) & 0x0181FFFF));
 
427
                                if ((gpr.GetImm(rt) & 0x1000003) == 0) {
 
428
                                        // Default nearest / no-flush mode, just leave it cleared.
 
429
                                } else {
 
430
                                        UpdateRoundingMode();
 
431
                                        ApplyRoundingMode();
 
432
                                }
 
433
                        } else {
 
434
                                gpr.Lock(rt, MIPS_REG_FPCOND);
 
435
                                gpr.MapReg(rt, true, false);
 
436
                                gpr.MapReg(MIPS_REG_FPCOND, false, true);
 
437
                                MOV(32, gpr.R(MIPS_REG_FPCOND), gpr.R(rt));
 
438
                                SHR(32, gpr.R(MIPS_REG_FPCOND), Imm8(23));
 
439
                                AND(32, gpr.R(MIPS_REG_FPCOND), Imm32(1));
 
440
                                MOV(32, M(&mips_->fcr31), gpr.R(rt));
 
441
                                AND(32, M(&mips_->fcr31), Imm32(0x0181FFFF));
 
442
                                gpr.UnlockAll();
 
443
                                UpdateRoundingMode();
 
444
                                ApplyRoundingMode();
 
445
                        }
 
446
                } else {
 
447
                        Comp_Generic(op);
 
448
                }
 
449
                return;
 
450
        }
 
451
}
 
452
 
 
453
}       // namespace MIPSComp