451ab91e |
1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus - gspecial.c * |
3 | * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * |
4 | * Copyright (C) 2007 Richard Goedeken (Richard42) * |
5 | * Copyright (C) 2002 Hacktarux * |
6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * |
9 | * the Free Software Foundation; either version 2 of the License, or * |
10 | * (at your option) any later version. * |
11 | * * |
12 | * This program is distributed in the hope that it will be useful, * |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
15 | * GNU General Public License for more details. * |
16 | * * |
17 | * You should have received a copy of the GNU General Public License * |
18 | * along with this program; if not, write to the * |
19 | * Free Software Foundation, Inc., * |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
21 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
22 | |
23 | #include <stdio.h> |
24 | |
25 | #include "assemble.h" |
26 | #include "interpret.h" |
27 | |
28 | #include "r4300/recomph.h" |
29 | #include "r4300/recomp.h" |
30 | #include "r4300/r4300.h" |
31 | #include "r4300/ops.h" |
32 | #include "r4300/macros.h" |
33 | #include "r4300/exception.h" |
34 | |
35 | #if !defined(offsetof) |
36 | # define offsetof(TYPE,MEMBER) ((unsigned int) &((TYPE*)0)->MEMBER) |
37 | #endif |
38 | |
39 | void gensll(void) |
40 | { |
41 | #if defined(COUNT_INSTR) |
42 | inc_m32rel(&instr_count[55]); |
43 | #endif |
44 | #ifdef INTERPRET_SLL |
45 | gencallinterp((unsigned long long)cached_interpreter_table.SLL, 0); |
46 | #else |
47 | int rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
48 | int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
49 | |
50 | mov_reg32_reg32(rd, rt); |
51 | shl_reg32_imm8(rd, dst->f.r.sa); |
52 | #endif |
53 | } |
54 | |
55 | void gensrl(void) |
56 | { |
57 | #if defined(COUNT_INSTR) |
58 | inc_m32rel(&instr_count[56]); |
59 | #endif |
60 | #ifdef INTERPRET_SRL |
61 | gencallinterp((unsigned long long)cached_interpreter_table.SRL, 0); |
62 | #else |
63 | int rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
64 | int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
65 | |
66 | mov_reg32_reg32(rd, rt); |
67 | shr_reg32_imm8(rd, dst->f.r.sa); |
68 | #endif |
69 | } |
70 | |
71 | void gensra(void) |
72 | { |
73 | #if defined(COUNT_INSTR) |
74 | inc_m32rel(&instr_count[57]); |
75 | #endif |
76 | #ifdef INTERPRET_SRA |
77 | gencallinterp((unsigned long long)cached_interpreter_table.SRA, 0); |
78 | #else |
79 | int rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
80 | int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
81 | |
82 | mov_reg32_reg32(rd, rt); |
83 | sar_reg32_imm8(rd, dst->f.r.sa); |
84 | #endif |
85 | } |
86 | |
87 | void gensllv(void) |
88 | { |
89 | #if defined(COUNT_INSTR) |
90 | inc_m32rel(&instr_count[58]); |
91 | #endif |
92 | #ifdef INTERPRET_SLLV |
93 | gencallinterp((unsigned long long)cached_interpreter_table.SLLV, 0); |
94 | #else |
95 | int rt, rd; |
96 | allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); |
97 | |
98 | rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
99 | rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
100 | |
101 | if (rd != ECX) |
102 | { |
103 | mov_reg32_reg32(rd, rt); |
104 | shl_reg32_cl(rd); |
105 | } |
106 | else |
107 | { |
108 | int temp = lru_register(); |
109 | free_register(temp); |
110 | mov_reg32_reg32(temp, rt); |
111 | shl_reg32_cl(temp); |
112 | mov_reg32_reg32(rd, temp); |
113 | } |
114 | #endif |
115 | } |
116 | |
117 | void gensrlv(void) |
118 | { |
119 | #if defined(COUNT_INSTR) |
120 | inc_m32rel(&instr_count[59]); |
121 | #endif |
122 | #ifdef INTERPRET_SRLV |
123 | gencallinterp((unsigned long long)cached_interpreter_table.SRLV, 0); |
124 | #else |
125 | int rt, rd; |
126 | allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); |
127 | |
128 | rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
129 | rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
130 | |
131 | if (rd != ECX) |
132 | { |
133 | mov_reg32_reg32(rd, rt); |
134 | shr_reg32_cl(rd); |
135 | } |
136 | else |
137 | { |
138 | int temp = lru_register(); |
139 | free_register(temp); |
140 | mov_reg32_reg32(temp, rt); |
141 | shr_reg32_cl(temp); |
142 | mov_reg32_reg32(rd, temp); |
143 | } |
144 | #endif |
145 | } |
146 | |
147 | void gensrav(void) |
148 | { |
149 | #if defined(COUNT_INSTR) |
150 | inc_m32rel(&instr_count[60]); |
151 | #endif |
152 | #ifdef INTERPRET_SRAV |
153 | gencallinterp((unsigned long long)cached_interpreter_table.SRAV, 0); |
154 | #else |
155 | int rt, rd; |
156 | allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); |
157 | |
158 | rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
159 | rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
160 | |
161 | if (rd != ECX) |
162 | { |
163 | mov_reg32_reg32(rd, rt); |
164 | sar_reg32_cl(rd); |
165 | } |
166 | else |
167 | { |
168 | int temp = lru_register(); |
169 | free_register(temp); |
170 | mov_reg32_reg32(temp, rt); |
171 | sar_reg32_cl(temp); |
172 | mov_reg32_reg32(rd, temp); |
173 | } |
174 | #endif |
175 | } |
176 | |
177 | void genjr(void) |
178 | { |
179 | #if defined(COUNT_INSTR) |
180 | inc_m32rel(&instr_count[61]); |
181 | #endif |
182 | #ifdef INTERPRET_JR |
183 | gencallinterp((unsigned long long)cached_interpreter_table.JR, 1); |
184 | #else |
185 | static unsigned int precomp_instr_size = sizeof(precomp_instr); |
186 | unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); |
187 | unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); |
188 | unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); |
189 | |
190 | if (((dst->addr & 0xFFF) == 0xFFC && |
191 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
192 | { |
193 | gencallinterp((unsigned long long)cached_interpreter_table.JR, 1); |
194 | return; |
195 | } |
196 | |
197 | free_registers_move_start(); |
198 | |
199 | mov_xreg32_m32rel(EAX, (unsigned int *)dst->f.i.rs); |
200 | mov_m32rel_xreg32((unsigned int *)&local_rs, EAX); |
201 | |
202 | gendelayslot(); |
203 | |
204 | mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); |
205 | mov_m32rel_xreg32((unsigned int *)&last_addr, EAX); |
206 | |
207 | gencheck_interupt_reg(); |
208 | |
209 | mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); |
210 | mov_reg32_reg32(EBX, EAX); |
211 | and_eax_imm32(0xFFFFF000); |
212 | cmp_eax_imm32(dst_block->start & 0xFFFFF000); |
213 | je_near_rj(0); |
214 | |
215 | jump_start_rel32(); |
216 | |
217 | mov_m32rel_xreg32(&jump_to_address, EBX); |
218 | mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); |
219 | mov_m64rel_xreg64((unsigned long long *)(&PC), RAX); |
220 | mov_reg64_imm64(RAX, (unsigned long long) jump_to_func); |
221 | call_reg64(RAX); /* will never return from call */ |
222 | |
223 | jump_end_rel32(); |
224 | |
225 | mov_reg64_imm64(RSI, (unsigned long long) dst_block->block); |
226 | mov_reg32_reg32(EAX, EBX); |
227 | sub_eax_imm32(dst_block->start); |
228 | shr_reg32_imm8(EAX, 2); |
229 | mul_m32rel((unsigned int *)(&precomp_instr_size)); |
230 | |
231 | mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); |
232 | cmp_reg32_imm32(EBX, 1); |
233 | jne_rj(11); |
234 | |
235 | add_reg32_imm32(EAX, diff_wrap); // 6 |
236 | add_reg64_reg64(RAX, RSI); // 3 |
237 | jmp_reg64(RAX); // 2 |
238 | |
239 | mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); |
240 | mov_rax_memoffs64((unsigned long long *) &dst_block->code); |
241 | add_reg64_reg64(RAX, RBX); |
242 | jmp_reg64(RAX); |
243 | #endif |
244 | } |
245 | |
246 | void genjalr(void) |
247 | { |
248 | #if defined(COUNT_INSTR) |
249 | inc_m32rel(&instr_count[62]); |
250 | #endif |
251 | #ifdef INTERPRET_JALR |
252 | gencallinterp((unsigned long long)cached_interpreter_table.JALR, 0); |
253 | #else |
254 | static unsigned int precomp_instr_size = sizeof(precomp_instr); |
255 | unsigned int diff = (unsigned int) offsetof(precomp_instr, local_addr); |
256 | unsigned int diff_need = (unsigned int) offsetof(precomp_instr, reg_cache_infos.need_map); |
257 | unsigned int diff_wrap = (unsigned int) offsetof(precomp_instr, reg_cache_infos.jump_wrapper); |
258 | |
259 | if (((dst->addr & 0xFFF) == 0xFFC && |
260 | (dst->addr < 0x80000000 || dst->addr >= 0xC0000000))||no_compiled_jump) |
261 | { |
262 | gencallinterp((unsigned long long)cached_interpreter_table.JALR, 1); |
263 | return; |
264 | } |
265 | |
266 | free_registers_move_start(); |
267 | |
268 | mov_xreg32_m32rel(EAX, (unsigned int *)dst->f.r.rs); |
269 | mov_m32rel_xreg32((unsigned int *)&local_rs, EAX); |
270 | |
271 | gendelayslot(); |
272 | |
273 | mov_m32rel_imm32((unsigned int *)(dst-1)->f.r.rd, dst->addr+4); |
274 | if ((dst->addr+4) & 0x80000000) |
275 | mov_m32rel_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0xFFFFFFFF); |
276 | else |
277 | mov_m32rel_imm32(((unsigned int *)(dst-1)->f.r.rd)+1, 0); |
278 | |
279 | mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); |
280 | mov_m32rel_xreg32((unsigned int *)&last_addr, EAX); |
281 | |
282 | gencheck_interupt_reg(); |
283 | |
284 | mov_xreg32_m32rel(EAX, (unsigned int *)&local_rs); |
285 | mov_reg32_reg32(EBX, EAX); |
286 | and_eax_imm32(0xFFFFF000); |
287 | cmp_eax_imm32(dst_block->start & 0xFFFFF000); |
288 | je_near_rj(0); |
289 | |
290 | jump_start_rel32(); |
291 | |
292 | mov_m32rel_xreg32(&jump_to_address, EBX); |
293 | mov_reg64_imm64(RAX, (unsigned long long) (dst+1)); |
294 | mov_m64rel_xreg64((unsigned long long *)(&PC), RAX); |
295 | mov_reg64_imm64(RAX, (unsigned long long) jump_to_func); |
296 | call_reg64(RAX); /* will never return from call */ |
297 | |
298 | jump_end_rel32(); |
299 | |
300 | mov_reg64_imm64(RSI, (unsigned long long) dst_block->block); |
301 | mov_reg32_reg32(EAX, EBX); |
302 | sub_eax_imm32(dst_block->start); |
303 | shr_reg32_imm8(EAX, 2); |
304 | mul_m32rel((unsigned int *)(&precomp_instr_size)); |
305 | |
306 | mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff_need); |
307 | cmp_reg32_imm32(EBX, 1); |
308 | jne_rj(11); |
309 | |
310 | add_reg32_imm32(EAX, diff_wrap); // 6 |
311 | add_reg64_reg64(RAX, RSI); // 3 |
312 | jmp_reg64(RAX); // 2 |
313 | |
314 | mov_reg32_preg64preg64pimm32(EBX, RAX, RSI, diff); |
315 | mov_rax_memoffs64((unsigned long long *) &dst_block->code); |
316 | add_reg64_reg64(RAX, RBX); |
317 | jmp_reg64(RAX); |
318 | #endif |
319 | } |
320 | |
321 | void gensyscall(void) |
322 | { |
323 | #if defined(COUNT_INSTR) |
324 | inc_m32rel(&instr_count[63]); |
325 | #endif |
326 | #ifdef INTERPRET_SYSCALL |
327 | gencallinterp((unsigned long long)cached_interpreter_table.SYSCALL, 0); |
328 | #else |
329 | free_registers_move_start(); |
330 | |
331 | mov_m32rel_imm32(&Cause, 8 << 2); |
332 | gencallinterp((unsigned long long)exception_general, 0); |
333 | #endif |
334 | } |
335 | |
336 | void gensync(void) |
337 | { |
338 | } |
339 | |
340 | void genmfhi(void) |
341 | { |
342 | #if defined(COUNT_INSTR) |
343 | inc_m32rel(&instr_count[64]); |
344 | #endif |
345 | #ifdef INTERPRET_MFHI |
346 | gencallinterp((unsigned long long)cached_interpreter_table.MFHI, 0); |
347 | #else |
348 | int rd = allocate_register_64_w((unsigned long long *) dst->f.r.rd); |
349 | int _hi = allocate_register_64((unsigned long long *) &hi); |
350 | |
351 | mov_reg64_reg64(rd, _hi); |
352 | #endif |
353 | } |
354 | |
355 | void genmthi(void) |
356 | { |
357 | #if defined(COUNT_INSTR) |
358 | inc_m32rel(&instr_count[65]); |
359 | #endif |
360 | #ifdef INTERPRET_MTHI |
361 | gencallinterp((unsigned long long)cached_interpreter_table.MTHI, 0); |
362 | #else |
363 | int _hi = allocate_register_64_w((unsigned long long *) &hi); |
364 | int rs = allocate_register_64((unsigned long long *) dst->f.r.rs); |
365 | |
366 | mov_reg64_reg64(_hi, rs); |
367 | #endif |
368 | } |
369 | |
370 | void genmflo(void) |
371 | { |
372 | #if defined(COUNT_INSTR) |
373 | inc_m32rel(&instr_count[66]); |
374 | #endif |
375 | #ifdef INTERPRET_MFLO |
376 | gencallinterp((unsigned long long)cached_interpreter_table.MFLO, 0); |
377 | #else |
378 | int rd = allocate_register_64_w((unsigned long long *) dst->f.r.rd); |
379 | int _lo = allocate_register_64((unsigned long long *) &lo); |
380 | |
381 | mov_reg64_reg64(rd, _lo); |
382 | #endif |
383 | } |
384 | |
385 | void genmtlo(void) |
386 | { |
387 | #if defined(COUNT_INSTR) |
388 | inc_m32rel(&instr_count[67]); |
389 | #endif |
390 | #ifdef INTERPRET_MTLO |
391 | gencallinterp((unsigned long long)cached_interpreter_table.MTLO, 0); |
392 | #else |
393 | int _lo = allocate_register_64_w((unsigned long long *)&lo); |
394 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
395 | |
396 | mov_reg64_reg64(_lo, rs); |
397 | #endif |
398 | } |
399 | |
400 | void gendsllv(void) |
401 | { |
402 | #if defined(COUNT_INSTR) |
403 | inc_m32rel(&instr_count[68]); |
404 | #endif |
405 | #ifdef INTERPRET_DSLLV |
406 | gencallinterp((unsigned long long)cached_interpreter_table.DSLLV, 0); |
407 | #else |
408 | int rt, rd; |
409 | allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); |
410 | |
411 | rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
412 | rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
413 | |
414 | if (rd != ECX) |
415 | { |
416 | mov_reg64_reg64(rd, rt); |
417 | shl_reg64_cl(rd); |
418 | } |
419 | else |
420 | { |
421 | int temp; |
422 | temp = lru_register(); |
423 | free_register(temp); |
424 | |
425 | mov_reg64_reg64(temp, rt); |
426 | shl_reg64_cl(temp); |
427 | mov_reg64_reg64(rd, temp); |
428 | } |
429 | #endif |
430 | } |
431 | |
432 | void gendsrlv(void) |
433 | { |
434 | #if defined(COUNT_INSTR) |
435 | inc_m32rel(&instr_count[69]); |
436 | #endif |
437 | #ifdef INTERPRET_DSRLV |
438 | gencallinterp((unsigned long long)cached_interpreter_table.DSRLV, 0); |
439 | #else |
440 | int rt, rd; |
441 | allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); |
442 | |
443 | rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
444 | rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
445 | |
446 | if (rd != ECX) |
447 | { |
448 | mov_reg64_reg64(rd, rt); |
449 | shr_reg64_cl(rd); |
450 | } |
451 | else |
452 | { |
453 | int temp; |
454 | temp = lru_register(); |
455 | free_register(temp); |
456 | |
457 | mov_reg64_reg64(temp, rt); |
458 | shr_reg64_cl(temp); |
459 | mov_reg64_reg64(rd, temp); |
460 | } |
461 | #endif |
462 | } |
463 | |
464 | void gendsrav(void) |
465 | { |
466 | #if defined(COUNT_INSTR) |
467 | inc_m32rel(&instr_count[70]); |
468 | #endif |
469 | #ifdef INTERPRET_DSRAV |
470 | gencallinterp((unsigned long long)cached_interpreter_table.DSRAV, 0); |
471 | #else |
472 | int rt, rd; |
473 | allocate_register_32_manually(ECX, (unsigned int *)dst->f.r.rs); |
474 | |
475 | rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
476 | rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
477 | |
478 | if (rd != ECX) |
479 | { |
480 | mov_reg64_reg64(rd, rt); |
481 | sar_reg64_cl(rd); |
482 | } |
483 | else |
484 | { |
485 | int temp; |
486 | temp = lru_register(); |
487 | free_register(temp); |
488 | |
489 | mov_reg64_reg64(temp, rt); |
490 | sar_reg64_cl(temp); |
491 | mov_reg64_reg64(rd, temp); |
492 | } |
493 | #endif |
494 | } |
495 | |
496 | void genmult(void) |
497 | { |
498 | #if defined(COUNT_INSTR) |
499 | inc_m32rel(&instr_count[71]); |
500 | #endif |
501 | #ifdef INTERPRET_MULT |
502 | gencallinterp((unsigned long long)cached_interpreter_table.MULT, 0); |
503 | #else |
504 | int rs, rt; |
505 | allocate_register_32_manually_w(EAX, (unsigned int *)&lo); /* these must be done first so they are not assigned by allocate_register() */ |
506 | allocate_register_32_manually_w(EDX, (unsigned int *)&hi); |
507 | rs = allocate_register_32((unsigned int*)dst->f.r.rs); |
508 | rt = allocate_register_32((unsigned int*)dst->f.r.rt); |
509 | mov_reg32_reg32(EAX, rs); |
510 | imul_reg32(rt); |
511 | #endif |
512 | } |
513 | |
514 | void genmultu(void) |
515 | { |
516 | #if defined(COUNT_INSTR) |
517 | inc_m32rel(&instr_count[72]); |
518 | #endif |
519 | #ifdef INTERPRET_MULTU |
520 | gencallinterp((unsigned long long)cached_interpreter_table.MULTU, 0); |
521 | #else |
522 | int rs, rt; |
523 | allocate_register_32_manually_w(EAX, (unsigned int *)&lo); |
524 | allocate_register_32_manually_w(EDX, (unsigned int *)&hi); |
525 | rs = allocate_register_32((unsigned int*)dst->f.r.rs); |
526 | rt = allocate_register_32((unsigned int*)dst->f.r.rt); |
527 | mov_reg32_reg32(EAX, rs); |
528 | mul_reg32(rt); |
529 | #endif |
530 | } |
531 | |
532 | void gendiv(void) |
533 | { |
534 | #if defined(COUNT_INSTR) |
535 | inc_m32rel(&instr_count[73]); |
536 | #endif |
537 | #ifdef INTERPRET_DIV |
538 | gencallinterp((unsigned long long)cached_interpreter_table.DIV, 0); |
539 | #else |
540 | int rs, rt; |
541 | allocate_register_32_manually_w(EAX, (unsigned int *)&lo); |
542 | allocate_register_32_manually_w(EDX, (unsigned int *)&hi); |
543 | rs = allocate_register_32((unsigned int*)dst->f.r.rs); |
544 | rt = allocate_register_32((unsigned int*)dst->f.r.rt); |
545 | cmp_reg32_imm32(rt, 0); |
546 | je_rj((rs == EAX ? 0 : 2) + 1 + 2); |
547 | mov_reg32_reg32(EAX, rs); // 0 or 2 |
548 | cdq(); // 1 |
549 | idiv_reg32(rt); // 2 |
550 | #endif |
551 | } |
552 | |
553 | void gendivu(void) |
554 | { |
555 | #if defined(COUNT_INSTR) |
556 | inc_m32rel(&instr_count[74]); |
557 | #endif |
558 | #ifdef INTERPRET_DIVU |
559 | gencallinterp((unsigned long long)cached_interpreter_table.DIVU, 0); |
560 | #else |
561 | int rs, rt; |
562 | allocate_register_32_manually_w(EAX, (unsigned int *)&lo); |
563 | allocate_register_32_manually_w(EDX, (unsigned int *)&hi); |
564 | rs = allocate_register_32((unsigned int*)dst->f.r.rs); |
565 | rt = allocate_register_32((unsigned int*)dst->f.r.rt); |
566 | cmp_reg32_imm32(rt, 0); |
567 | je_rj((rs == EAX ? 0 : 2) + 2 + 2); |
568 | mov_reg32_reg32(EAX, rs); // 0 or 2 |
569 | xor_reg32_reg32(EDX, EDX); // 2 |
570 | div_reg32(rt); // 2 |
571 | #endif |
572 | } |
573 | |
574 | void gendmult(void) |
575 | { |
576 | #if defined(COUNT_INSTR) |
577 | inc_m32rel(&instr_count[75]); |
578 | #endif |
579 | gencallinterp((unsigned long long)cached_interpreter_table.DMULT, 0); |
580 | } |
581 | |
582 | void gendmultu(void) |
583 | { |
584 | #if defined(COUNT_INSTR) |
585 | inc_m32rel(&instr_count[76]); |
586 | #endif |
587 | #ifdef INTERPRET_DMULTU |
588 | gencallinterp((unsigned long long)cached_interpreter_table.DMULTU, 0); |
589 | #else |
590 | free_registers_move_start(); |
591 | |
592 | mov_xreg64_m64rel(RAX, (unsigned long long *) dst->f.r.rs); |
593 | mov_xreg64_m64rel(RDX, (unsigned long long *) dst->f.r.rt); |
594 | mul_reg64(RDX); |
595 | mov_m64rel_xreg64((unsigned long long *) &lo, RAX); |
596 | mov_m64rel_xreg64((unsigned long long *) &hi, RDX); |
597 | #endif |
598 | } |
599 | |
600 | void genddiv(void) |
601 | { |
602 | #if defined(COUNT_INSTR) |
603 | inc_m32rel(&instr_count[77]); |
604 | #endif |
605 | gencallinterp((unsigned long long)cached_interpreter_table.DDIV, 0); |
606 | } |
607 | |
608 | void genddivu(void) |
609 | { |
610 | #if defined(COUNT_INSTR) |
611 | inc_m32rel(&instr_count[78]); |
612 | #endif |
613 | gencallinterp((unsigned long long)cached_interpreter_table.DDIVU, 0); |
614 | } |
615 | |
616 | void genadd(void) |
617 | { |
618 | #if defined(COUNT_INSTR) |
619 | inc_m32rel(&instr_count[79]); |
620 | #endif |
621 | #ifdef INTERPRET_ADD |
622 | gencallinterp((unsigned long long)cached_interpreter_table.ADD, 0); |
623 | #else |
624 | int rs = allocate_register_32((unsigned int *)dst->f.r.rs); |
625 | int rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
626 | int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
627 | |
628 | if (rs == rd) |
629 | add_reg32_reg32(rd, rt); |
630 | else if (rt == rd) |
631 | add_reg32_reg32(rd, rs); |
632 | else |
633 | { |
634 | mov_reg32_reg32(rd, rs); |
635 | add_reg32_reg32(rd, rt); |
636 | } |
637 | #endif |
638 | } |
639 | |
640 | void genaddu(void) |
641 | { |
642 | #if defined(COUNT_INSTR) |
643 | inc_m32rel(&instr_count[80]); |
644 | #endif |
645 | #ifdef INTERPRET_ADDU |
646 | gencallinterp((unsigned long long)cached_interpreter_table.ADDU, 0); |
647 | #else |
648 | int rs = allocate_register_32((unsigned int *)dst->f.r.rs); |
649 | int rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
650 | int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
651 | |
652 | if (rs == rd) |
653 | add_reg32_reg32(rd, rt); |
654 | else if (rt == rd) |
655 | add_reg32_reg32(rd, rs); |
656 | else |
657 | { |
658 | mov_reg32_reg32(rd, rs); |
659 | add_reg32_reg32(rd, rt); |
660 | } |
661 | #endif |
662 | } |
663 | |
664 | void gensub(void) |
665 | { |
666 | #if defined(COUNT_INSTR) |
667 | inc_m32rel(&instr_count[81]); |
668 | #endif |
669 | #ifdef INTERPRET_SUB |
670 | gencallinterp((unsigned long long)cached_interpreter_table.SUB, 0); |
671 | #else |
672 | int rs = allocate_register_32((unsigned int *)dst->f.r.rs); |
673 | int rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
674 | int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
675 | |
676 | if (rs == rd) |
677 | sub_reg32_reg32(rd, rt); |
678 | else if (rt == rd) |
679 | { |
680 | neg_reg32(rd); |
681 | add_reg32_reg32(rd, rs); |
682 | } |
683 | else |
684 | { |
685 | mov_reg32_reg32(rd, rs); |
686 | sub_reg32_reg32(rd, rt); |
687 | } |
688 | #endif |
689 | } |
690 | |
691 | void gensubu(void) |
692 | { |
693 | #if defined(COUNT_INSTR) |
694 | inc_m32rel(&instr_count[82]); |
695 | #endif |
696 | #ifdef INTERPRET_SUBU |
697 | gencallinterp((unsigned long long)cached_interpreter_table.SUBU, 0); |
698 | #else |
699 | int rs = allocate_register_32((unsigned int *)dst->f.r.rs); |
700 | int rt = allocate_register_32((unsigned int *)dst->f.r.rt); |
701 | int rd = allocate_register_32_w((unsigned int *)dst->f.r.rd); |
702 | |
703 | if (rs == rd) |
704 | sub_reg32_reg32(rd, rt); |
705 | else if (rt == rd) |
706 | { |
707 | neg_reg32(rd); |
708 | add_reg32_reg32(rd, rs); |
709 | } |
710 | else |
711 | { |
712 | mov_reg32_reg32(rd, rs); |
713 | sub_reg32_reg32(rd, rt); |
714 | } |
715 | #endif |
716 | } |
717 | |
718 | void genand(void) |
719 | { |
720 | #if defined(COUNT_INSTR) |
721 | inc_m32rel(&instr_count[83]); |
722 | #endif |
723 | #ifdef INTERPRET_AND |
724 | gencallinterp((unsigned long long)cached_interpreter_table.AND, 0); |
725 | #else |
726 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
727 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
728 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
729 | |
730 | if (rs == rd) |
731 | and_reg64_reg64(rd, rt); |
732 | else if (rt == rd) |
733 | and_reg64_reg64(rd, rs); |
734 | else |
735 | { |
736 | mov_reg64_reg64(rd, rs); |
737 | and_reg64_reg64(rd, rt); |
738 | } |
739 | #endif |
740 | } |
741 | |
742 | void genor(void) |
743 | { |
744 | #if defined(COUNT_INSTR) |
745 | inc_m32rel(&instr_count[84]); |
746 | #endif |
747 | #ifdef INTERPRET_OR |
748 | gencallinterp((unsigned long long)cached_interpreter_table.OR, 0); |
749 | #else |
750 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
751 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
752 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
753 | |
754 | if (rs == rd) |
755 | or_reg64_reg64(rd, rt); |
756 | else if (rt == rd) |
757 | or_reg64_reg64(rd, rs); |
758 | else |
759 | { |
760 | mov_reg64_reg64(rd, rs); |
761 | or_reg64_reg64(rd, rt); |
762 | } |
763 | #endif |
764 | } |
765 | |
766 | void genxor(void) |
767 | { |
768 | #if defined(COUNT_INSTR) |
769 | inc_m32rel(&instr_count[85]); |
770 | #endif |
771 | #ifdef INTERPRET_XOR |
772 | gencallinterp((unsigned long long)cached_interpreter_table.XOR, 0); |
773 | #else |
774 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
775 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
776 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
777 | |
778 | if (rs == rd) |
779 | xor_reg64_reg64(rd, rt); |
780 | else if (rt == rd) |
781 | xor_reg64_reg64(rd, rs); |
782 | else |
783 | { |
784 | mov_reg64_reg64(rd, rs); |
785 | xor_reg64_reg64(rd, rt); |
786 | } |
787 | #endif |
788 | } |
789 | |
790 | void gennor(void) |
791 | { |
792 | #if defined(COUNT_INSTR) |
793 | inc_m32rel(&instr_count[86]); |
794 | #endif |
795 | #ifdef INTERPRET_NOR |
796 | gencallinterp((unsigned long long)cached_interpreter_table.NOR, 0); |
797 | #else |
798 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
799 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
800 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
801 | |
802 | if (rs == rd) |
803 | { |
804 | or_reg64_reg64(rd, rt); |
805 | not_reg64(rd); |
806 | } |
807 | else if (rt == rd) |
808 | { |
809 | or_reg64_reg64(rd, rs); |
810 | not_reg64(rd); |
811 | } |
812 | else |
813 | { |
814 | mov_reg64_reg64(rd, rs); |
815 | or_reg64_reg64(rd, rt); |
816 | not_reg64(rd); |
817 | } |
818 | #endif |
819 | } |
820 | |
821 | void genslt(void) |
822 | { |
823 | #if defined(COUNT_INSTR) |
824 | inc_m32rel(&instr_count[87]); |
825 | #endif |
826 | #ifdef INTERPRET_SLT |
827 | gencallinterp((unsigned long long)cached_interpreter_table.SLT, 0); |
828 | #else |
829 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
830 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
831 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
832 | |
833 | cmp_reg64_reg64(rs, rt); |
834 | setl_reg8(rd); |
835 | and_reg64_imm8(rd, 1); |
836 | #endif |
837 | } |
838 | |
839 | void gensltu(void) |
840 | { |
841 | #if defined(COUNT_INSTR) |
842 | inc_m32rel(&instr_count[88]); |
843 | #endif |
844 | #ifdef INTERPRET_SLTU |
845 | gencallinterp((unsigned long long)cached_interpreter_table.SLTU, 0); |
846 | #else |
847 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
848 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
849 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
850 | |
851 | cmp_reg64_reg64(rs, rt); |
852 | setb_reg8(rd); |
853 | and_reg64_imm8(rd, 1); |
854 | #endif |
855 | } |
856 | |
857 | void gendadd(void) |
858 | { |
859 | #if defined(COUNT_INSTR) |
860 | inc_m32rel(&instr_count[89]); |
861 | #endif |
862 | #ifdef INTERPRET_DADD |
863 | gencallinterp((unsigned long long)cached_interpreter_table.DADD, 0); |
864 | #else |
865 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
866 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
867 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
868 | |
869 | if (rs == rd) |
870 | add_reg64_reg64(rd, rt); |
871 | else if (rt == rd) |
872 | add_reg64_reg64(rd, rs); |
873 | else |
874 | { |
875 | mov_reg64_reg64(rd, rs); |
876 | add_reg64_reg64(rd, rt); |
877 | } |
878 | #endif |
879 | } |
880 | |
881 | void gendaddu(void) |
882 | { |
883 | #if defined(COUNT_INSTR) |
884 | inc_m32rel(&instr_count[90]); |
885 | #endif |
886 | #ifdef INTERPRET_DADDU |
887 | gencallinterp((unsigned long long)cached_interpreter_table.DADDU, 0); |
888 | #else |
889 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
890 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
891 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
892 | |
893 | if (rs == rd) |
894 | add_reg64_reg64(rd, rt); |
895 | else if (rt == rd) |
896 | add_reg64_reg64(rd, rs); |
897 | else |
898 | { |
899 | mov_reg64_reg64(rd, rs); |
900 | add_reg64_reg64(rd, rt); |
901 | } |
902 | #endif |
903 | } |
904 | |
905 | void gendsub(void) |
906 | { |
907 | #if defined(COUNT_INSTR) |
908 | inc_m32rel(&instr_count[91]); |
909 | #endif |
910 | #ifdef INTERPRET_DSUB |
911 | gencallinterp((unsigned long long)cached_interpreter_table.DSUB, 0); |
912 | #else |
913 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
914 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
915 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
916 | |
917 | if (rs == rd) |
918 | sub_reg64_reg64(rd, rt); |
919 | else if (rt == rd) |
920 | { |
921 | neg_reg64(rd); |
922 | add_reg64_reg64(rd, rs); |
923 | } |
924 | else |
925 | { |
926 | mov_reg64_reg64(rd, rs); |
927 | sub_reg64_reg64(rd, rt); |
928 | } |
929 | #endif |
930 | } |
931 | |
932 | void gendsubu(void) |
933 | { |
934 | #if defined(COUNT_INSTR) |
935 | inc_m32rel(&instr_count[92]); |
936 | #endif |
937 | #ifdef INTERPRET_DSUBU |
938 | gencallinterp((unsigned long long)cached_interpreter_table.DSUBU, 0); |
939 | #else |
940 | int rs = allocate_register_64((unsigned long long *)dst->f.r.rs); |
941 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
942 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
943 | |
944 | if (rs == rd) |
945 | sub_reg64_reg64(rd, rt); |
946 | else if (rt == rd) |
947 | { |
948 | neg_reg64(rd); |
949 | add_reg64_reg64(rd, rs); |
950 | } |
951 | else |
952 | { |
953 | mov_reg64_reg64(rd, rs); |
954 | sub_reg64_reg64(rd, rt); |
955 | } |
956 | #endif |
957 | } |
958 | |
959 | void genteq(void) |
960 | { |
961 | #if defined(COUNT_INSTR) |
962 | inc_m32rel(&instr_count[96]); |
963 | #endif |
964 | gencallinterp((unsigned long long)cached_interpreter_table.TEQ, 0); |
965 | } |
966 | |
967 | void gendsll(void) |
968 | { |
969 | #if defined(COUNT_INSTR) |
970 | inc_m32rel(&instr_count[93]); |
971 | #endif |
972 | #ifdef INTERPRET_DSLL |
973 | gencallinterp((unsigned long long)cached_interpreter_table.DSLL, 0); |
974 | #else |
975 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
976 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
977 | |
978 | mov_reg64_reg64(rd, rt); |
979 | shl_reg64_imm8(rd, dst->f.r.sa); |
980 | #endif |
981 | } |
982 | |
983 | void gendsrl(void) |
984 | { |
985 | #if defined(COUNT_INSTR) |
986 | inc_m32rel(&instr_count[94]); |
987 | #endif |
988 | #ifdef INTERPRET_DSRL |
989 | gencallinterp((unsigned long long)cached_interpreter_table.DSRL, 0); |
990 | #else |
991 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
992 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
993 | |
994 | mov_reg64_reg64(rd, rt); |
995 | shr_reg64_imm8(rd, dst->f.r.sa); |
996 | #endif |
997 | } |
998 | |
999 | void gendsra(void) |
1000 | { |
1001 | #if defined(COUNT_INSTR) |
1002 | inc_m32rel(&instr_count[95]); |
1003 | #endif |
1004 | #ifdef INTERPRET_DSRA |
1005 | gencallinterp((unsigned long long)cached_interpreter_table.DSRA, 0); |
1006 | #else |
1007 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
1008 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
1009 | |
1010 | mov_reg64_reg64(rd, rt); |
1011 | sar_reg64_imm8(rd, dst->f.r.sa); |
1012 | #endif |
1013 | } |
1014 | |
1015 | void gendsll32(void) |
1016 | { |
1017 | #if defined(COUNT_INSTR) |
1018 | inc_m32rel(&instr_count[97]); |
1019 | #endif |
1020 | #ifdef INTERPRET_DSLL32 |
1021 | gencallinterp((unsigned long long)cached_interpreter_table.DSLL32, 0); |
1022 | #else |
1023 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
1024 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
1025 | |
1026 | mov_reg64_reg64(rd, rt); |
1027 | shl_reg64_imm8(rd, dst->f.r.sa + 32); |
1028 | #endif |
1029 | } |
1030 | |
1031 | void gendsrl32(void) |
1032 | { |
1033 | #if defined(COUNT_INSTR) |
1034 | inc_m32rel(&instr_count[98]); |
1035 | #endif |
1036 | #ifdef INTERPRET_DSRL32 |
1037 | gencallinterp((unsigned long long)cached_interpreter_table.DSRL32, 0); |
1038 | #else |
1039 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
1040 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
1041 | |
1042 | mov_reg64_reg64(rd, rt); |
1043 | shr_reg64_imm8(rd, dst->f.r.sa + 32); |
1044 | #endif |
1045 | } |
1046 | |
1047 | void gendsra32(void) |
1048 | { |
1049 | #if defined(COUNT_INSTR) |
1050 | inc_m32rel(&instr_count[99]); |
1051 | #endif |
1052 | #ifdef INTERPRET_DSRA32 |
1053 | gencallinterp((unsigned long long)cached_interpreter_table.DSRA32, 0); |
1054 | #else |
1055 | int rt = allocate_register_64((unsigned long long *)dst->f.r.rt); |
1056 | int rd = allocate_register_64_w((unsigned long long *)dst->f.r.rd); |
1057 | |
1058 | mov_reg64_reg64(rd, rt); |
1059 | sar_reg64_imm8(rd, dst->f.r.sa + 32); |
1060 | #endif |
1061 | } |
1062 | |