1
// Copyright 2013 Dolphin Emulator Project
2
// Licensed under GPLv2
3
// Refer to the license.txt file included.
6
#pragma warning(disable:4146) // unary minus operator applied to unsigned type, result still unsigned
11
static void ComputeRC(IREmitter::IRBuilder& ibuild, IREmitter::InstLoc val)
13
IREmitter::InstLoc res =
14
ibuild.EmitICmpCRSigned(val, ibuild.EmitIntConst(0));
15
ibuild.EmitStoreCR(res, 0);
18
void JitILBase::reg_imm(UGeckoInstruction inst)
21
JITDISABLE(bJITIntegerOff)
22
int d = inst.RD, a = inst.RA, s = inst.RS;
23
IREmitter::InstLoc val, test, c;
27
val = ibuild.EmitIntConst(inst.SIMM_16);
29
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
30
ibuild.EmitStoreGReg(val, d);
33
val = ibuild.EmitIntConst(inst.SIMM_16 << 16);
35
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), val);
36
ibuild.EmitStoreGReg(val, d);
39
val = ibuild.EmitIntConst(inst.UIMM);
40
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
41
ibuild.EmitStoreGReg(val, a);
44
val = ibuild.EmitIntConst(inst.UIMM << 16);
45
val = ibuild.EmitOr(ibuild.EmitLoadGReg(s), val);
46
ibuild.EmitStoreGReg(val, a);
49
val = ibuild.EmitIntConst(inst.UIMM);
50
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
51
ibuild.EmitStoreGReg(val, a);
52
ComputeRC(ibuild, val);
55
val = ibuild.EmitIntConst(inst.UIMM << 16);
56
val = ibuild.EmitAnd(ibuild.EmitLoadGReg(s), val);
57
ibuild.EmitStoreGReg(val, a);
58
ComputeRC(ibuild, val);
61
val = ibuild.EmitIntConst(inst.UIMM);
62
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
63
ibuild.EmitStoreGReg(val, a);
66
val = ibuild.EmitIntConst(inst.UIMM << 16);
67
val = ibuild.EmitXor(ibuild.EmitLoadGReg(s), val);
68
ibuild.EmitStoreGReg(val, a);
72
c = ibuild.EmitIntConst(inst.SIMM_16);
73
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(a), c);
74
ibuild.EmitStoreGReg(val, d);
75
test = ibuild.EmitICmpUgt(c, val);
76
ibuild.EmitStoreCarry(test);
78
ComputeRC(ibuild, val);
86
void JitILBase::cmpXX(UGeckoInstruction inst)
89
JITDISABLE(bJITIntegerOff)
90
IREmitter::InstLoc lhs, rhs, res;
91
lhs = ibuild.EmitLoadGReg(inst.RA);
95
rhs = ibuild.EmitLoadGReg(inst.RB);
96
if (inst.SUBOP10 == 32)
98
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
102
res = ibuild.EmitICmpCRSigned(lhs, rhs);
105
else if (inst.OPCD == 10)
107
rhs = ibuild.EmitIntConst(inst.UIMM);
108
res = ibuild.EmitICmpCRUnsigned(lhs, rhs);
110
else // inst.OPCD == 11
112
rhs = ibuild.EmitIntConst(inst.SIMM_16);
113
res = ibuild.EmitICmpCRSigned(lhs, rhs);
116
js.downcountAmount++; //TODO: should this be somewhere else?
118
ibuild.EmitStoreCR(res, inst.CRFD);
121
void JitILBase::boolX(UGeckoInstruction inst)
124
JITDISABLE(bJITIntegerOff)
126
IREmitter::InstLoc a = NULL;
127
IREmitter::InstLoc s = ibuild.EmitLoadGReg(inst.RS);
128
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
130
// FIXME: Some instructions does not work well in NSMBW, MP2, etc.
131
// Refer JitIL_Tables.cpp.
132
if (inst.SUBOP10 == 28) /* andx */
134
a = ibuild.EmitAnd(s, b);
136
else if (inst.SUBOP10 == 476) /* nandx */
138
a = ibuild.EmitNot(ibuild.EmitAnd(s, b));
140
else if (inst.SUBOP10 == 60) /* andcx */
142
a = ibuild.EmitAnd(s, ibuild.EmitNot(b));
144
else if (inst.SUBOP10 == 444) /* orx */
146
a = ibuild.EmitOr(s, b);
148
else if (inst.SUBOP10 == 124) /* norx */
150
a = ibuild.EmitNot(ibuild.EmitOr(s, b));
152
else if (inst.SUBOP10 == 412) /* orcx */
154
a = ibuild.EmitOr(s, ibuild.EmitNot(b));
156
else if (inst.SUBOP10 == 316) /* xorx */
158
a = ibuild.EmitXor(s, b);
160
else if (inst.SUBOP10 == 284) /* eqvx */
162
a = ibuild.EmitNot(ibuild.EmitXor(s, b));
169
ibuild.EmitStoreGReg(a, inst.RA);
171
ComputeRC(ibuild, a);
174
void JitILBase::extsbx(UGeckoInstruction inst)
177
JITDISABLE(bJITIntegerOff)
178
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
179
val = ibuild.EmitSExt8(val);
180
ibuild.EmitStoreGReg(val, inst.RA);
182
ComputeRC(ibuild, val);
185
void JitILBase::extshx(UGeckoInstruction inst)
188
JITDISABLE(bJITIntegerOff)
189
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
190
val = ibuild.EmitSExt16(val);
191
ibuild.EmitStoreGReg(val, inst.RA);
193
ComputeRC(ibuild, val);
196
void JitILBase::subfic(UGeckoInstruction inst)
199
JITDISABLE(bJITIntegerOff)
200
IREmitter::InstLoc nota, lhs, val, test;
201
nota = ibuild.EmitXor(ibuild.EmitLoadGReg(inst.RA),
202
ibuild.EmitIntConst(-1));
204
if (inst.SIMM_16 == -1)
207
test = ibuild.EmitIntConst(1);
211
lhs = ibuild.EmitIntConst(inst.SIMM_16 + 1);
212
val = ibuild.EmitAdd(nota, lhs);
213
test = ibuild.EmitICmpUgt(lhs, val);
216
ibuild.EmitStoreGReg(val, inst.RD);
217
ibuild.EmitStoreCarry(test);
220
void JitILBase::subfcx(UGeckoInstruction inst)
223
JITDISABLE(bJITIntegerOff)
224
if (inst.OE) PanicAlert("OE: subfcx");
225
IREmitter::InstLoc val, test, lhs, rhs;
226
lhs = ibuild.EmitLoadGReg(inst.RB);
227
rhs = ibuild.EmitLoadGReg(inst.RA);
228
val = ibuild.EmitSub(lhs, rhs);
229
ibuild.EmitStoreGReg(val, inst.RD);
230
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
231
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
232
ibuild.EmitStoreCarry(test);
234
ComputeRC(ibuild, val);
237
void JitILBase::subfex(UGeckoInstruction inst)
240
JITDISABLE(bJITIntegerOff)
241
if (inst.OE) PanicAlert("OE: subfex");
242
IREmitter::InstLoc val, test, lhs, rhs, carry;
243
rhs = ibuild.EmitLoadGReg(inst.RA);
244
carry = ibuild.EmitLoadCarry();
245
rhs = ibuild.EmitXor(rhs, ibuild.EmitIntConst(-1));
246
rhs = ibuild.EmitAdd(rhs, carry);
247
test = ibuild.EmitICmpEq(rhs, ibuild.EmitIntConst(0));
248
test = ibuild.EmitAnd(test, carry);
249
lhs = ibuild.EmitLoadGReg(inst.RB);
250
val = ibuild.EmitAdd(lhs, rhs);
251
ibuild.EmitStoreGReg(val, inst.RD);
252
test = ibuild.EmitOr(test, ibuild.EmitICmpUgt(lhs, val));
253
ibuild.EmitStoreCarry(test);
255
ComputeRC(ibuild, val);
258
void JitILBase::subfx(UGeckoInstruction inst)
261
JITDISABLE(bJITIntegerOff)
262
if (inst.OE) PanicAlert("OE: subfx");
263
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
264
val = ibuild.EmitSub(val, ibuild.EmitLoadGReg(inst.RA));
265
ibuild.EmitStoreGReg(val, inst.RD);
267
ComputeRC(ibuild, val);
270
void JitILBase::mulli(UGeckoInstruction inst)
273
JITDISABLE(bJITIntegerOff)
274
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
275
val = ibuild.EmitMul(val, ibuild.EmitIntConst(inst.SIMM_16));
276
ibuild.EmitStoreGReg(val, inst.RD);
279
void JitILBase::mullwx(UGeckoInstruction inst)
282
JITDISABLE(bJITIntegerOff)
283
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
284
val = ibuild.EmitMul(ibuild.EmitLoadGReg(inst.RA), val);
285
ibuild.EmitStoreGReg(val, inst.RD);
287
ComputeRC(ibuild, val);
290
void JitILBase::mulhwux(UGeckoInstruction inst)
293
JITDISABLE(bJITIntegerOff)
295
IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA);
296
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
297
IREmitter::InstLoc d = ibuild.EmitMulHighUnsigned(a, b);
298
ibuild.EmitStoreGReg(d, inst.RD);
300
ComputeRC(ibuild, d);
303
// skipped some of the special handling in here - if we get crashes, let the interpreter handle this op
304
void JitILBase::divwux(UGeckoInstruction inst)
306
Default(inst); return;
308
int a = inst.RA, b = inst.RB, d = inst.RD;
312
if (d != a && d != b)
314
gpr.LoadToX64(d, false, true);
318
gpr.LoadToX64(d, true, true);
321
MOV(32, R(EAX), gpr.R(a));
322
XOR(32, R(EDX), R(EDX));
323
gpr.KillImmediate(b);
325
MOV(32, gpr.R(d), R(EAX));
329
CALL((u8*)asm_routines.computeRc);
334
void JitILBase::addx(UGeckoInstruction inst)
337
JITDISABLE(bJITIntegerOff)
338
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RB);
339
val = ibuild.EmitAdd(ibuild.EmitLoadGReg(inst.RA), val);
340
ibuild.EmitStoreGReg(val, inst.RD);
342
ComputeRC(ibuild, val);
345
void JitILBase::addzex(UGeckoInstruction inst)
348
JITDISABLE(bJITIntegerOff)
349
IREmitter::InstLoc lhs = ibuild.EmitLoadGReg(inst.RA),
351
val = ibuild.EmitAdd(lhs, ibuild.EmitLoadCarry());
352
ibuild.EmitStoreGReg(val, inst.RD);
353
newcarry = ibuild.EmitICmpUlt(val, lhs);
354
ibuild.EmitStoreCarry(newcarry);
356
ComputeRC(ibuild, val);
359
void JitILBase::addex(UGeckoInstruction inst)
362
JITDISABLE(bJITIntegerOff)
364
IREmitter::InstLoc a = ibuild.EmitLoadGReg(inst.RA);
365
IREmitter::InstLoc b = ibuild.EmitLoadGReg(inst.RB);
367
IREmitter::InstLoc ab = ibuild.EmitAdd(a, b);
368
IREmitter::InstLoc new_carry = ibuild.EmitICmpUlt(ab, a);
370
IREmitter::InstLoc previous_carry = ibuild.EmitLoadCarry();
371
IREmitter::InstLoc abc = ibuild.EmitAdd(ab, previous_carry);
372
new_carry = ibuild.EmitOr(new_carry, ibuild.EmitICmpUlt(abc, ab));
374
ibuild.EmitStoreGReg(abc, inst.RD);
375
ibuild.EmitStoreCarry(new_carry);
377
if (inst.OE) PanicAlert("OE: addex");
379
ComputeRC(ibuild, abc);
382
void JitILBase::rlwinmx(UGeckoInstruction inst)
385
JITDISABLE(bJITIntegerOff)
386
unsigned mask = Helper_Mask(inst.MB, inst.ME);
387
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
388
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
389
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
390
ibuild.EmitStoreGReg(val, inst.RA);
392
ComputeRC(ibuild, val);
396
void JitILBase::rlwimix(UGeckoInstruction inst)
399
JITDISABLE(bJITIntegerOff)
400
unsigned mask = Helper_Mask(inst.MB, inst.ME);
401
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
402
val = ibuild.EmitRol(val, ibuild.EmitIntConst(inst.SH));
403
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
404
IREmitter::InstLoc ival = ibuild.EmitLoadGReg(inst.RA);
405
ival = ibuild.EmitAnd(ival, ibuild.EmitIntConst(~mask));
406
val = ibuild.EmitOr(ival, val);
407
ibuild.EmitStoreGReg(val, inst.RA);
409
ComputeRC(ibuild, val);
412
void JitILBase::rlwnmx(UGeckoInstruction inst)
415
JITDISABLE(bJITIntegerOff)
416
unsigned int mask = Helper_Mask(inst.MB, inst.ME);
417
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
418
val = ibuild.EmitRol(val, ibuild.EmitLoadGReg(inst.RB));
419
val = ibuild.EmitAnd(val, ibuild.EmitIntConst(mask));
420
ibuild.EmitStoreGReg(val, inst.RA);
422
ComputeRC(ibuild, val);
425
void JitILBase::negx(UGeckoInstruction inst)
428
JITDISABLE(bJITIntegerOff)
429
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RA);
430
val = ibuild.EmitSub(ibuild.EmitIntConst(0), val);
431
ibuild.EmitStoreGReg(val, inst.RD);
433
ComputeRC(ibuild, val);
436
void JitILBase::srwx(UGeckoInstruction inst)
439
JITDISABLE(bJITIntegerOff)
440
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
441
samt = ibuild.EmitLoadGReg(inst.RB),
443
// FIXME: We can do better with a cmov
444
// FIXME: We can do better on 64-bit
445
val = ibuild.EmitShrl(val, samt);
446
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
447
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
448
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
449
val = ibuild.EmitAnd(corr, val);
450
ibuild.EmitStoreGReg(val, inst.RA);
452
ComputeRC(ibuild, val);
455
void JitILBase::slwx(UGeckoInstruction inst)
458
JITDISABLE(bJITIntegerOff)
459
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS),
460
samt = ibuild.EmitLoadGReg(inst.RB),
462
// FIXME: We can do better with a cmov
463
// FIXME: We can do better on 64-bit
464
val = ibuild.EmitShl(val, samt);
465
corr = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
466
corr = ibuild.EmitSarl(corr, ibuild.EmitIntConst(31));
467
corr = ibuild.EmitXor(corr, ibuild.EmitIntConst(-1));
468
val = ibuild.EmitAnd(corr, val);
469
ibuild.EmitStoreGReg(val, inst.RA);
471
ComputeRC(ibuild, val);
474
void JitILBase::srawx(UGeckoInstruction inst)
477
JITDISABLE(bJITIntegerOff)
478
// FIXME: We can do a lot better on 64-bit
479
IREmitter::InstLoc val, samt, mask, mask2, test;
480
val = ibuild.EmitLoadGReg(inst.RS);
481
samt = ibuild.EmitLoadGReg(inst.RB);
482
mask = ibuild.EmitIntConst(-1);
483
val = ibuild.EmitSarl(val, samt);
484
mask = ibuild.EmitShl(mask, samt);
485
samt = ibuild.EmitShl(samt, ibuild.EmitIntConst(26));
486
samt = ibuild.EmitSarl(samt, ibuild.EmitIntConst(31));
487
samt = ibuild.EmitAnd(samt, ibuild.EmitIntConst(31));
488
val = ibuild.EmitSarl(val, samt);
489
ibuild.EmitStoreGReg(val, inst.RA);
490
mask = ibuild.EmitShl(mask, samt);
491
mask2 = ibuild.EmitAnd(mask, ibuild.EmitIntConst(0x7FFFFFFF));
492
test = ibuild.EmitOr(val, mask2);
493
test = ibuild.EmitICmpUgt(test, mask);
494
ibuild.EmitStoreCarry(test);
497
ComputeRC(ibuild, val);
500
void JitILBase::srawix(UGeckoInstruction inst)
503
JITDISABLE(bJITIntegerOff)
504
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS), test;
505
val = ibuild.EmitSarl(val, ibuild.EmitIntConst(inst.SH));
506
ibuild.EmitStoreGReg(val, inst.RA);
507
unsigned int mask = -1u << inst.SH;
508
test = ibuild.EmitOr(val, ibuild.EmitIntConst(mask & 0x7FFFFFFF));
509
test = ibuild.EmitICmpUgt(test, ibuild.EmitIntConst(mask));
511
ibuild.EmitStoreCarry(test);
513
ComputeRC(ibuild, val);
516
// count leading zeroes
517
void JitILBase::cntlzwx(UGeckoInstruction inst)
520
JITDISABLE(bJITIntegerOff)
521
IREmitter::InstLoc val = ibuild.EmitLoadGReg(inst.RS);
522
val = ibuild.EmitCntlzw(val);
523
ibuild.EmitStoreGReg(val, inst.RA);
525
ComputeRC(ibuild, val);