blob: abaddd601dcf7becf440850d88caaf68aa40fb56 [file] [log] [blame]
sewardj362cf842012-06-07 08:59:53 +00001
2/*---------------------------------------------------------------*/
3/*--- begin host_mips_defs.c ---*/
4/*---------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
petarjb92a9542013-02-27 22:57:17 +000010 Copyright (C) 2010-2013 RT-RK
sewardj362cf842012-06-07 08:59:53 +000011 mips-valgrind@rt-rk.com
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31#include "libvex_basictypes.h"
32#include "libvex.h"
33#include "libvex_trc_values.h"
34
35#include "main_util.h"
36#include "host_generic_regs.h"
37#include "host_mips_defs.h"
38
petarjb92a9542013-02-27 22:57:17 +000039/* guest_COND offset. */
dejanj0e006f22014-02-19 11:56:29 +000040#define COND_OFFSET(__mode64) (__mode64 ? 612 : 448)
petarjb92a9542013-02-27 22:57:17 +000041
42/* Register number for guest state pointer in host code. */
43#define GuestSP 23
44
45#define MkHRegGPR(_n, _mode64) \
46 mkHReg(_n, _mode64 ? HRcInt64 : HRcInt32, False)
47
48#define MkHRegFPR(_n, _mode64) \
49 mkHReg(_n, _mode64 ? HRcFlt64 : HRcFlt32, False)
50
sewardj362cf842012-06-07 08:59:53 +000051/*---------------- Registers ----------------*/
52
53void ppHRegMIPS(HReg reg, Bool mode64)
54{
55 Int r;
florian55085f82012-11-21 00:36:55 +000056 static const HChar *ireg32_names[35]
sewardj362cf842012-06-07 08:59:53 +000057 = { "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
58 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
59 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
60 "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
61 "%32", "%33", "%34",
62 };
63
florian55085f82012-11-21 00:36:55 +000064 static const HChar *freg32_names[32]
sewardj362cf842012-06-07 08:59:53 +000065 = { "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
66 "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
67 "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
68 "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "f30", "$f31"
69 };
70
florian55085f82012-11-21 00:36:55 +000071 static const HChar *freg64_names[32]
sewardj362cf842012-06-07 08:59:53 +000072 = { "$d0", "$d1", "$d2", "$d3", "$d4", "$d5", "$d6", "$d7",
73 "$d8", "$d9", "$d10", "$d11", "$d12", "$d13", "$d14", "$d15",
74 };
75
76 /* Be generic for all virtual regs. */
77 if (hregIsVirtual(reg)) {
78 ppHReg(reg);
79 return;
80 }
81
82 /* But specific for real regs. */
83 vassert(hregClass(reg) == HRcInt32 || hregClass(reg) == HRcInt64 ||
dejanj0e006f22014-02-19 11:56:29 +000084 hregClass(reg) == HRcFlt32 || hregClass(reg) == HRcFlt64);
sewardj362cf842012-06-07 08:59:53 +000085
86 /* But specific for real regs. */
petarjb92a9542013-02-27 22:57:17 +000087 switch (hregClass(reg)) {
88 case HRcInt32:
89 r = hregNumber(reg);
90 vassert(r >= 0 && r < 32);
91 vex_printf("%s", ireg32_names[r]);
92 return;
93 case HRcInt64:
petarjb92a9542013-02-27 22:57:17 +000094 r = hregNumber (reg);
95 vassert (r >= 0 && r < 32);
96 vex_printf ("%s", ireg32_names[r]);
97 return;
98 case HRcFlt32:
99 r = hregNumber(reg);
100 vassert(r >= 0 && r < 32);
101 vex_printf("%s", freg32_names[r]);
102 return;
103 case HRcFlt64:
104 r = hregNumber(reg);
105 vassert(r >= 0 && r < 32);
106 vex_printf("%s", freg64_names[r]);
107 return;
108 default:
109 vpanic("ppHRegMIPS");
110 break;
sewardj362cf842012-06-07 08:59:53 +0000111 }
112
113 return;
114}
115
sewardj362cf842012-06-07 08:59:53 +0000116HReg hregMIPS_GPR0(Bool mode64)
117{
118 return MkHRegGPR(0, mode64);
119}
120
121HReg hregMIPS_GPR1(Bool mode64)
122{
123 return MkHRegGPR(1, mode64);
124}
125
126HReg hregMIPS_GPR2(Bool mode64)
127{
128 return MkHRegGPR(2, mode64);
129}
130
131HReg hregMIPS_GPR3(Bool mode64)
132{
133 return MkHRegGPR(3, mode64);
134}
135
136HReg hregMIPS_GPR4(Bool mode64)
137{
138 return MkHRegGPR(4, mode64);
139}
140
141HReg hregMIPS_GPR5(Bool mode64)
142{
143 return MkHRegGPR(5, mode64);
144}
145
146HReg hregMIPS_GPR6(Bool mode64)
147{
148 return MkHRegGPR(6, mode64);
149}
150
151HReg hregMIPS_GPR7(Bool mode64)
152{
153 return MkHRegGPR(7, mode64);
154}
155
156HReg hregMIPS_GPR8(Bool mode64)
157{
158 return MkHRegGPR(8, mode64);
159}
160
161HReg hregMIPS_GPR9(Bool mode64)
162{
163 return MkHRegGPR(9, mode64);
164}
165
166HReg hregMIPS_GPR10(Bool mode64)
167{
168 return MkHRegGPR(10, mode64);
169}
170
171HReg hregMIPS_GPR11(Bool mode64)
172{
173 return MkHRegGPR(11, mode64);
174}
175
176HReg hregMIPS_GPR12(Bool mode64)
177{
178 return MkHRegGPR(12, mode64);
179}
180
181HReg hregMIPS_GPR13(Bool mode64)
182{
183 return MkHRegGPR(13, mode64);
184}
185
186HReg hregMIPS_GPR14(Bool mode64)
187{
188 return MkHRegGPR(14, mode64);
189}
190
191HReg hregMIPS_GPR15(Bool mode64)
192{
193 return MkHRegGPR(15, mode64);
194}
195
196HReg hregMIPS_GPR16(Bool mode64)
197{
198 return MkHRegGPR(16, mode64);
199}
200
201HReg hregMIPS_GPR17(Bool mode64)
202{
203 return MkHRegGPR(17, mode64);
204}
205
206HReg hregMIPS_GPR18(Bool mode64)
207{
208 return MkHRegGPR(18, mode64);
209}
210
211HReg hregMIPS_GPR19(Bool mode64)
212{
213 return MkHRegGPR(19, mode64);
214}
215
216HReg hregMIPS_GPR20(Bool mode64)
217{
218 return MkHRegGPR(20, mode64);
219}
220
221HReg hregMIPS_GPR21(Bool mode64)
222{
223 return MkHRegGPR(21, mode64);
224}
225
226HReg hregMIPS_GPR22(Bool mode64)
227{
228 return MkHRegGPR(22, mode64);
229}
230
231HReg hregMIPS_GPR23(Bool mode64)
232{
233 return MkHRegGPR(23, mode64);
234}
235
236HReg hregMIPS_GPR24(Bool mode64)
237{
238 return MkHRegGPR(24, mode64);
239}
240
241HReg hregMIPS_GPR25(Bool mode64)
242{
243 return MkHRegGPR(25, mode64);
244}
245
246HReg hregMIPS_GPR26(Bool mode64)
247{
248 return MkHRegGPR(26, mode64);
249}
250
251HReg hregMIPS_GPR27(Bool mode64)
252{
253 return MkHRegGPR(27, mode64);
254}
255
256HReg hregMIPS_GPR28(Bool mode64)
257{
258 return MkHRegGPR(28, mode64);
259}
260
261HReg hregMIPS_GPR29(Bool mode64)
262{
263 return MkHRegGPR(29, mode64);
264}
265
266HReg hregMIPS_GPR30(Bool mode64)
267{
268 return MkHRegGPR(30, mode64);
269}
270
271HReg hregMIPS_GPR31(Bool mode64)
272{
273 return MkHRegGPR(31, mode64);
274}
275
sewardj362cf842012-06-07 08:59:53 +0000276HReg hregMIPS_F0(Bool mode64)
277{
278 return MkHRegFPR(0, mode64);
279}
280
281HReg hregMIPS_F1(Bool mode64)
282{
283 return MkHRegFPR(1, mode64);
284}
285
286HReg hregMIPS_F2(Bool mode64)
287{
288 return MkHRegFPR(2, mode64);
289}
290
291HReg hregMIPS_F3(Bool mode64)
292{
293 return MkHRegFPR(3, mode64);
294}
295
296HReg hregMIPS_F4(Bool mode64)
297{
298 return MkHRegFPR(4, mode64);
299}
300
301HReg hregMIPS_F5(Bool mode64)
302{
303 return MkHRegFPR(5, mode64);
304}
305
306HReg hregMIPS_F6(Bool mode64)
307{
308 return MkHRegFPR(6, mode64);
309}
310
311HReg hregMIPS_F7(Bool mode64)
312{
313 return MkHRegFPR(7, mode64);
314}
315
316HReg hregMIPS_F8(Bool mode64)
317{
318 return MkHRegFPR(8, mode64);
319}
320
321HReg hregMIPS_F9(Bool mode64)
322{
323 return MkHRegFPR(9, mode64);
324}
325
326HReg hregMIPS_F10(Bool mode64)
327{
328 return MkHRegFPR(10, mode64);
329}
330
331HReg hregMIPS_F11(Bool mode64)
332{
333 return MkHRegFPR(11, mode64);
334}
335
336HReg hregMIPS_F12(Bool mode64)
337{
338 return MkHRegFPR(12, mode64);
339}
340
341HReg hregMIPS_F13(Bool mode64)
342{
343 return MkHRegFPR(13, mode64);
344}
345
346HReg hregMIPS_F14(Bool mode64)
347{
348 return MkHRegFPR(14, mode64);
349}
350
351HReg hregMIPS_F15(Bool mode64)
352{
353 return MkHRegFPR(15, mode64);
354}
355
356HReg hregMIPS_F16(Bool mode64)
357{
358 return MkHRegFPR(16, mode64);
359}
360
361HReg hregMIPS_F17(Bool mode64)
362{
363 return MkHRegFPR(17, mode64);
364}
365
366HReg hregMIPS_F18(Bool mode64)
367{
368 return MkHRegFPR(18, mode64);
369}
370
371HReg hregMIPS_F19(Bool mode64)
372{
373 return MkHRegFPR(19, mode64);
374}
375
376HReg hregMIPS_F20(Bool mode64)
377{
378 return MkHRegFPR(20, mode64);
379}
380
381HReg hregMIPS_F21(Bool mode64)
382{
383 return MkHRegFPR(21, mode64);
384}
385
386HReg hregMIPS_F22(Bool mode64)
387{
388 return MkHRegFPR(22, mode64);
389}
390
391HReg hregMIPS_F23(Bool mode64)
392{
393 return MkHRegFPR(23, mode64);
394}
395
396HReg hregMIPS_F24(Bool mode64)
397{
398 return MkHRegFPR(24, mode64);
399}
400
401HReg hregMIPS_F25(Bool mode64)
402{
403 return MkHRegFPR(25, mode64);
404}
405
406HReg hregMIPS_F26(Bool mode64)
407{
408 return MkHRegFPR(26, mode64);
409}
410
411HReg hregMIPS_F27(Bool mode64)
412{
413 return MkHRegFPR(27, mode64);
414}
415
416HReg hregMIPS_F28(Bool mode64)
417{
418 return MkHRegFPR(28, mode64);
419}
420
421HReg hregMIPS_F29(Bool mode64)
422{
423 return MkHRegFPR(29, mode64);
424}
425
426HReg hregMIPS_F30(Bool mode64)
427{
428 return MkHRegFPR(30, mode64);
429}
430
431HReg hregMIPS_F31(Bool mode64)
432{
433 return MkHRegFPR(31, mode64);
434}
435
436HReg hregMIPS_PC(Bool mode64)
437{
438 return mkHReg(32, mode64 ? HRcFlt64 : HRcFlt32, False);
439}
440
441HReg hregMIPS_HI(Bool mode64)
442{
443 return mkHReg(33, mode64 ? HRcFlt64 : HRcFlt32, False);
444}
445
446HReg hregMIPS_LO(Bool mode64)
447{
448 return mkHReg(34, mode64 ? HRcFlt64 : HRcFlt32, False);
449}
450
451HReg hregMIPS_D0(void)
452{
453 return mkHReg(0, HRcFlt64, False);
454}
455
456HReg hregMIPS_D1(void)
457{
458 return mkHReg(2, HRcFlt64, False);
459}
460
461HReg hregMIPS_D2(void)
462{
463 return mkHReg(4, HRcFlt64, False);
464}
465
466HReg hregMIPS_D3(void)
467{
468 return mkHReg(6, HRcFlt64, False);
469}
470
471HReg hregMIPS_D4(void)
472{
473 return mkHReg(8, HRcFlt64, False);
474}
475
476HReg hregMIPS_D5(void)
477{
478 return mkHReg(10, HRcFlt64, False);
479}
480
481HReg hregMIPS_D6(void)
482{
483 return mkHReg(12, HRcFlt64, False);
484}
485
486HReg hregMIPS_D7(void)
487{
488 return mkHReg(14, HRcFlt64, False);
489}
490
491HReg hregMIPS_D8(void)
492{
493 return mkHReg(16, HRcFlt64, False);
494}
495
496HReg hregMIPS_D9(void)
497{
498 return mkHReg(18, HRcFlt64, False);
499}
500
501HReg hregMIPS_D10(void)
502{
503 return mkHReg(20, HRcFlt64, False);
504}
505
506HReg hregMIPS_D11(void)
507{
508 return mkHReg(22, HRcFlt64, False);
509}
510
511HReg hregMIPS_D12(void)
512{
513 return mkHReg(24, HRcFlt64, False);
514}
515
516HReg hregMIPS_D13(void)
517{
518 return mkHReg(26, HRcFlt64, False);
519}
520
521HReg hregMIPS_D14(void)
522{
523 return mkHReg(28, HRcFlt64, False);
524}
525
526HReg hregMIPS_D15(void)
527{
528 return mkHReg(30, HRcFlt64, False);
529}
530
531HReg hregMIPS_FIR(void)
532{
533 return mkHReg(35, HRcInt32, False);
534}
535
536HReg hregMIPS_FCCR(void)
537{
538 return mkHReg(36, HRcInt32, False);
539}
540
541HReg hregMIPS_FEXR(void)
542{
543 return mkHReg(37, HRcInt32, False);
544}
545
546HReg hregMIPS_FENR(void)
547{
548 return mkHReg(38, HRcInt32, False);
549}
550
551HReg hregMIPS_FCSR(void)
552{
553 return mkHReg(39, HRcInt32, False);
554}
555
556HReg hregMIPS_COND(void)
557{
558 return mkHReg(47, HRcInt32, False);
559}
560
561void getAllocableRegs_MIPS(Int * nregs, HReg ** arr, Bool mode64)
562{
petarjb92a9542013-02-27 22:57:17 +0000563 /* The list of allocable registers is shorten to fit MIPS32 mode on Loongson.
564 More precisely, we workaround Loongson MIPS32 issues by avoiding usage of
565 odd single precision FP registers. */
sewardj362cf842012-06-07 08:59:53 +0000566 if (mode64)
petarjb92a9542013-02-27 22:57:17 +0000567 *nregs = 20;
sewardj362cf842012-06-07 08:59:53 +0000568 else
petarjb92a9542013-02-27 22:57:17 +0000569 *nregs = 28;
sewardj362cf842012-06-07 08:59:53 +0000570 UInt i = 0;
571 *arr = LibVEX_Alloc(*nregs * sizeof(HReg));
572
petarjb92a9542013-02-27 22:57:17 +0000573 /* ZERO = constant 0
574 AT = assembler temporary
575 callee saves ones are listed first, since we prefer them
576 if they're available */
sewardj362cf842012-06-07 08:59:53 +0000577 (*arr)[i++] = hregMIPS_GPR16(mode64);
578 (*arr)[i++] = hregMIPS_GPR17(mode64);
579 (*arr)[i++] = hregMIPS_GPR18(mode64);
580 (*arr)[i++] = hregMIPS_GPR19(mode64);
581 (*arr)[i++] = hregMIPS_GPR20(mode64);
582 (*arr)[i++] = hregMIPS_GPR21(mode64);
583 (*arr)[i++] = hregMIPS_GPR22(mode64);
sewardj362cf842012-06-07 08:59:53 +0000584
sewardj362cf842012-06-07 08:59:53 +0000585 (*arr)[i++] = hregMIPS_GPR12(mode64);
586 (*arr)[i++] = hregMIPS_GPR13(mode64);
587 (*arr)[i++] = hregMIPS_GPR14(mode64);
588 (*arr)[i++] = hregMIPS_GPR15(mode64);
589 (*arr)[i++] = hregMIPS_GPR24(mode64);
petarjb92a9542013-02-27 22:57:17 +0000590 /* s7 (=guest_state) */
petarj98f11702012-09-21 00:06:14 +0000591 (*arr)[i++] = hregMIPS_F16(mode64);
592 (*arr)[i++] = hregMIPS_F18(mode64);
sewardj362cf842012-06-07 08:59:53 +0000593 (*arr)[i++] = hregMIPS_F20(mode64);
sewardj362cf842012-06-07 08:59:53 +0000594 (*arr)[i++] = hregMIPS_F22(mode64);
sewardj362cf842012-06-07 08:59:53 +0000595 (*arr)[i++] = hregMIPS_F24(mode64);
sewardj362cf842012-06-07 08:59:53 +0000596 (*arr)[i++] = hregMIPS_F26(mode64);
sewardj362cf842012-06-07 08:59:53 +0000597 (*arr)[i++] = hregMIPS_F28(mode64);
sewardj362cf842012-06-07 08:59:53 +0000598 (*arr)[i++] = hregMIPS_F30(mode64);
599 if (!mode64) {
600 /* Fake double floating point */
601 (*arr)[i++] = hregMIPS_D0();
602 (*arr)[i++] = hregMIPS_D1();
603 (*arr)[i++] = hregMIPS_D2();
604 (*arr)[i++] = hregMIPS_D3();
605 (*arr)[i++] = hregMIPS_D4();
606 (*arr)[i++] = hregMIPS_D5();
607 (*arr)[i++] = hregMIPS_D6();
608 (*arr)[i++] = hregMIPS_D7();
sewardj362cf842012-06-07 08:59:53 +0000609 }
610 vassert(i == *nregs);
611
612}
613
614/*----------------- Condition Codes ----------------------*/
615
florian55085f82012-11-21 00:36:55 +0000616const HChar *showMIPSCondCode(MIPSCondCode cond)
sewardj362cf842012-06-07 08:59:53 +0000617{
florian55085f82012-11-21 00:36:55 +0000618 const HChar* ret;
sewardj362cf842012-06-07 08:59:53 +0000619 switch (cond) {
620 case MIPScc_EQ:
petarjb92a9542013-02-27 22:57:17 +0000621 ret = "EQ"; /* equal */
sewardj362cf842012-06-07 08:59:53 +0000622 break;
623 case MIPScc_NE:
petarjb92a9542013-02-27 22:57:17 +0000624 ret = "NEQ"; /* not equal */
sewardj362cf842012-06-07 08:59:53 +0000625 break;
626 case MIPScc_HS:
petarjb92a9542013-02-27 22:57:17 +0000627 ret = "GE"; /* >=u (Greater Than or Equal) */
sewardj362cf842012-06-07 08:59:53 +0000628 break;
629 case MIPScc_LO:
petarjb92a9542013-02-27 22:57:17 +0000630 ret = "LT"; /* <u (lower) */
sewardj362cf842012-06-07 08:59:53 +0000631 break;
632 case MIPScc_MI:
petarjb92a9542013-02-27 22:57:17 +0000633 ret = "MI"; /* minus (negative) */
sewardj362cf842012-06-07 08:59:53 +0000634 break;
635 case MIPScc_PL:
petarjb92a9542013-02-27 22:57:17 +0000636 ret = "PL"; /* plus (zero or +ve) */
sewardj362cf842012-06-07 08:59:53 +0000637 break;
638 case MIPScc_VS:
petarjb92a9542013-02-27 22:57:17 +0000639 ret = "VS"; /* overflow */
sewardj362cf842012-06-07 08:59:53 +0000640 break;
641 case MIPScc_VC:
petarjb92a9542013-02-27 22:57:17 +0000642 ret = "VC"; /* no overflow */
sewardj362cf842012-06-07 08:59:53 +0000643 break;
644 case MIPScc_HI:
petarjb92a9542013-02-27 22:57:17 +0000645 ret = "HI"; /* >u (higher) */
sewardj362cf842012-06-07 08:59:53 +0000646 break;
647 case MIPScc_LS:
petarjb92a9542013-02-27 22:57:17 +0000648 ret = "LS"; /* <=u (lower or same) */
sewardj362cf842012-06-07 08:59:53 +0000649 break;
650 case MIPScc_GE:
petarjb92a9542013-02-27 22:57:17 +0000651 ret = "GE"; /* >=s (signed greater or equal) */
sewardj362cf842012-06-07 08:59:53 +0000652 break;
653 case MIPScc_LT:
petarjb92a9542013-02-27 22:57:17 +0000654 ret = "LT"; /* <s (signed less than) */
sewardj362cf842012-06-07 08:59:53 +0000655 break;
656 case MIPScc_GT:
petarjb92a9542013-02-27 22:57:17 +0000657 ret = "GT"; /* >s (signed greater) */
sewardj362cf842012-06-07 08:59:53 +0000658 break;
659 case MIPScc_LE:
petarjb92a9542013-02-27 22:57:17 +0000660 ret = "LE"; /* <=s (signed less or equal) */
sewardj362cf842012-06-07 08:59:53 +0000661 break;
662 case MIPScc_AL:
petarjb92a9542013-02-27 22:57:17 +0000663 ret = "AL"; /* always (unconditional) */
sewardj362cf842012-06-07 08:59:53 +0000664 break;
665 case MIPScc_NV:
petarjb92a9542013-02-27 22:57:17 +0000666 ret = "NV"; /* never (unconditional): */
sewardj362cf842012-06-07 08:59:53 +0000667 break;
668 default:
669 vpanic("showMIPSCondCode");
670 break;
671 }
672 return ret;
673}
674
florian55085f82012-11-21 00:36:55 +0000675const HChar *showMIPSFpOp(MIPSFpOp op)
sewardj362cf842012-06-07 08:59:53 +0000676{
florian55085f82012-11-21 00:36:55 +0000677 const HChar *ret;
sewardj362cf842012-06-07 08:59:53 +0000678 switch (op) {
679 case Mfp_ADDD:
dejanjc3fee0d2013-07-25 09:08:03 +0000680 ret = "add.d";
sewardj362cf842012-06-07 08:59:53 +0000681 break;
682 case Mfp_SUBD:
dejanjc3fee0d2013-07-25 09:08:03 +0000683 ret = "sub.d";
sewardj362cf842012-06-07 08:59:53 +0000684 break;
685 case Mfp_MULD:
dejanjc3fee0d2013-07-25 09:08:03 +0000686 ret = "mul.d";
sewardj362cf842012-06-07 08:59:53 +0000687 break;
688 case Mfp_DIVD:
dejanjc3fee0d2013-07-25 09:08:03 +0000689 ret = "div.d";
sewardj362cf842012-06-07 08:59:53 +0000690 break;
691 case Mfp_MADDD:
dejanjc3fee0d2013-07-25 09:08:03 +0000692 ret = "madd.d";
sewardj362cf842012-06-07 08:59:53 +0000693 break;
694 case Mfp_MSUBD:
dejanjc3fee0d2013-07-25 09:08:03 +0000695 ret = "msub.d";
sewardj362cf842012-06-07 08:59:53 +0000696 break;
697 case Mfp_MADDS:
dejanjc3fee0d2013-07-25 09:08:03 +0000698 ret = "madd.s";
sewardj362cf842012-06-07 08:59:53 +0000699 break;
700 case Mfp_MSUBS:
dejanjc3fee0d2013-07-25 09:08:03 +0000701 ret = "msub.s";
sewardj362cf842012-06-07 08:59:53 +0000702 break;
703 case Mfp_ADDS:
dejanjc3fee0d2013-07-25 09:08:03 +0000704 ret = "add.s";
sewardj362cf842012-06-07 08:59:53 +0000705 break;
706 case Mfp_SUBS:
dejanjc3fee0d2013-07-25 09:08:03 +0000707 ret = "sub.s";
sewardj362cf842012-06-07 08:59:53 +0000708 break;
709 case Mfp_MULS:
dejanjc3fee0d2013-07-25 09:08:03 +0000710 ret = "mul.s";
sewardj362cf842012-06-07 08:59:53 +0000711 break;
712 case Mfp_DIVS:
dejanjc3fee0d2013-07-25 09:08:03 +0000713 ret = "div.s";
sewardj362cf842012-06-07 08:59:53 +0000714 break;
715 case Mfp_SQRTS:
dejanjc3fee0d2013-07-25 09:08:03 +0000716 ret = "sqrt.s";
sewardj362cf842012-06-07 08:59:53 +0000717 break;
718 case Mfp_SQRTD:
dejanjc3fee0d2013-07-25 09:08:03 +0000719 ret = "sqrt.d";
sewardj362cf842012-06-07 08:59:53 +0000720 break;
721 case Mfp_ABSS:
dejanjc3fee0d2013-07-25 09:08:03 +0000722 ret = "abs.s";
sewardj362cf842012-06-07 08:59:53 +0000723 break;
724 case Mfp_ABSD:
dejanjc3fee0d2013-07-25 09:08:03 +0000725 ret = "abs.d";
sewardj362cf842012-06-07 08:59:53 +0000726 break;
727 case Mfp_NEGS:
dejanjc3fee0d2013-07-25 09:08:03 +0000728 ret = "neg.s";
sewardj362cf842012-06-07 08:59:53 +0000729 break;
730 case Mfp_NEGD:
dejanjc3fee0d2013-07-25 09:08:03 +0000731 ret = "neg.d";
sewardj362cf842012-06-07 08:59:53 +0000732 break;
733 case Mfp_MOVS:
dejanjc3fee0d2013-07-25 09:08:03 +0000734 ret = "mov.s";
sewardj362cf842012-06-07 08:59:53 +0000735 break;
736 case Mfp_MOVD:
dejanjc3fee0d2013-07-25 09:08:03 +0000737 ret = "mov.d";
sewardj362cf842012-06-07 08:59:53 +0000738 break;
sewardj362cf842012-06-07 08:59:53 +0000739 case Mfp_ROUNDWS:
dejanjc3fee0d2013-07-25 09:08:03 +0000740 ret = "round.w.s";
sewardj362cf842012-06-07 08:59:53 +0000741 break;
742 case Mfp_ROUNDWD:
dejanjc3fee0d2013-07-25 09:08:03 +0000743 ret = "round.w.d";
sewardj362cf842012-06-07 08:59:53 +0000744 break;
dejanja759d172013-09-19 13:35:45 +0000745 case Mfp_ROUNDLD:
746 ret = "round.l.d";
747 break;
sewardj362cf842012-06-07 08:59:53 +0000748 case Mfp_FLOORWS:
dejanjc3fee0d2013-07-25 09:08:03 +0000749 ret = "floor.w.s";
sewardj362cf842012-06-07 08:59:53 +0000750 break;
751 case Mfp_FLOORWD:
dejanjc3fee0d2013-07-25 09:08:03 +0000752 ret = "floor.w.d";
sewardj362cf842012-06-07 08:59:53 +0000753 break;
754 case Mfp_CVTDW:
dejanjc3fee0d2013-07-25 09:08:03 +0000755 ret = "cvt.d.w";
petarjb92a9542013-02-27 22:57:17 +0000756 break;
757 case Mfp_CVTDL:
dejanjc3fee0d2013-07-25 09:08:03 +0000758 ret = "cvt.d.l";
petarjb92a9542013-02-27 22:57:17 +0000759 break;
760 case Mfp_CVTDS:
dejanjc3fee0d2013-07-25 09:08:03 +0000761 ret = "cvt.d.s";
sewardj362cf842012-06-07 08:59:53 +0000762 break;
763 case Mfp_CVTSD:
dejanjc3fee0d2013-07-25 09:08:03 +0000764 ret = "cvt.s.d";
765 break;
sewardj362cf842012-06-07 08:59:53 +0000766 case Mfp_CVTSW:
dejanjc3fee0d2013-07-25 09:08:03 +0000767 ret = "cvt.s.w";
sewardj362cf842012-06-07 08:59:53 +0000768 break;
769 case Mfp_CVTWS:
dejanjc3fee0d2013-07-25 09:08:03 +0000770 ret = "cvt.w.s";
771 break;
sewardj362cf842012-06-07 08:59:53 +0000772 case Mfp_CVTWD:
dejanjc3fee0d2013-07-25 09:08:03 +0000773 ret = "cvt.w.d";
sewardj362cf842012-06-07 08:59:53 +0000774 break;
dejanj0e006f22014-02-19 11:56:29 +0000775 case Mfp_CVTLD:
776 ret = "cvt.l.d";
777 break;
778 case Mfp_CVTLS:
779 ret = "cvt.l.s";
780 break;
sewardj362cf842012-06-07 08:59:53 +0000781 case Mfp_TRUWD:
dejanjc3fee0d2013-07-25 09:08:03 +0000782 ret = "trunc.w.d";
783 break;
sewardj362cf842012-06-07 08:59:53 +0000784 case Mfp_TRUWS:
dejanjc3fee0d2013-07-25 09:08:03 +0000785 ret = "trunc.w.s";
sewardj362cf842012-06-07 08:59:53 +0000786 break;
787 case Mfp_TRULD:
dejanjc3fee0d2013-07-25 09:08:03 +0000788 ret = "trunc.l.d";
789 break;
sewardj362cf842012-06-07 08:59:53 +0000790 case Mfp_TRULS:
dejanjc3fee0d2013-07-25 09:08:03 +0000791 ret = "trunc.l.s";
sewardj362cf842012-06-07 08:59:53 +0000792 break;
793 case Mfp_CEILWS:
dejanjc3fee0d2013-07-25 09:08:03 +0000794 ret = "ceil.w.s";
795 break;
sewardj362cf842012-06-07 08:59:53 +0000796 case Mfp_CEILWD:
dejanjc3fee0d2013-07-25 09:08:03 +0000797 ret = "ceil.w.d";
sewardj362cf842012-06-07 08:59:53 +0000798 break;
799 case Mfp_CEILLS:
dejanjc3fee0d2013-07-25 09:08:03 +0000800 ret = "ceil.l.s";
801 break;
sewardj362cf842012-06-07 08:59:53 +0000802 case Mfp_CEILLD:
dejanjc3fee0d2013-07-25 09:08:03 +0000803 ret = "ceil.l.d";
sewardj362cf842012-06-07 08:59:53 +0000804 break;
dejanjf37c0862014-02-25 15:25:49 +0000805 case Mfp_CMP_UN:
806 ret = "c.un.d";
807 break;
808 case Mfp_CMP_EQ:
809 ret = "c.eq.d";
810 break;
811 case Mfp_CMP_LT:
812 ret = "c.lt.d";
813 break;
814 case Mfp_CMP_NGT:
815 ret = "c.ngt.d";
sewardj362cf842012-06-07 08:59:53 +0000816 break;
817 default:
dejanj0e006f22014-02-19 11:56:29 +0000818 vex_printf("Unknown op: %d", op);
sewardj362cf842012-06-07 08:59:53 +0000819 vpanic("showMIPSFpOp");
820 break;
821 }
822 return ret;
823}
824
petarjb92a9542013-02-27 22:57:17 +0000825/* Show move from/to fpr to/from gpr */
826const HChar* showMIPSFpGpMoveOp ( MIPSFpGpMoveOp op )
827{
828 const HChar *ret;
829 switch (op) {
830 case MFpGpMove_mfc1:
831 ret = "mfc1";
832 break;
833 case MFpGpMove_dmfc1:
834 ret = "dmfc1";
835 break;
836 case MFpGpMove_mtc1:
837 ret = "mtc1";
838 break;
839 case MFpGpMove_dmtc1:
840 ret = "dmtc1";
841 break;
842 default:
843 vpanic("showMIPSFpGpMoveOp");
844 break;
845 }
846 return ret;
847}
848
849/* Show floating point move conditional */
850const HChar* showMIPSMoveCondOp ( MIPSMoveCondOp op )
851{
852 const HChar *ret;
853 switch (op) {
854 case MFpMoveCond_movns:
855 ret = "movn.s";
856 break;
857 case MFpMoveCond_movnd:
858 ret = "movn.d";
859 break;
860 case MMoveCond_movn:
861 ret = "movn";
862 break;
863 default:
864 vpanic("showMIPSFpMoveCondOp");
865 break;
866 }
867 return ret;
868}
869
sewardj362cf842012-06-07 08:59:53 +0000870/* --------- MIPSAMode: memory address expressions. --------- */
871
872MIPSAMode *MIPSAMode_IR(Int idx, HReg base)
873{
874 MIPSAMode *am = LibVEX_Alloc(sizeof(MIPSAMode));
875 am->tag = Mam_IR;
876 am->Mam.IR.base = base;
877 am->Mam.IR.index = idx;
878
879 return am;
880}
881
882MIPSAMode *MIPSAMode_RR(HReg idx, HReg base)
883{
884 MIPSAMode *am = LibVEX_Alloc(sizeof(MIPSAMode));
885 am->tag = Mam_RR;
886 am->Mam.RR.base = base;
887 am->Mam.RR.index = idx;
888
889 return am;
890}
891
892MIPSAMode *dopyMIPSAMode(MIPSAMode * am)
893{
894 MIPSAMode* ret;
895 switch (am->tag) {
896 case Mam_IR:
897 ret = MIPSAMode_IR(am->Mam.IR.index, am->Mam.IR.base);
898 break;
899 case Mam_RR:
900 ret = MIPSAMode_RR(am->Mam.RR.index, am->Mam.RR.base);
901 break;
902 default:
903 vpanic("dopyMIPSAMode");
904 break;
905 }
906 return ret;
907}
908
909MIPSAMode *nextMIPSAModeFloat(MIPSAMode * am)
910{
911 MIPSAMode* ret;
912 switch (am->tag) {
913 case Mam_IR:
petarj1ec43e02012-09-04 13:45:42 +0000914 ret = MIPSAMode_IR(am->Mam.IR.index + 4, am->Mam.IR.base);
sewardj362cf842012-06-07 08:59:53 +0000915 break;
916 case Mam_RR:
petarja81d9be2013-01-30 18:06:26 +0000917 ret = MIPSAMode_RR(mkHReg(hregNumber(am->Mam.RR.index) + 1,
918 hregClass(am->Mam.RR.index),
919 hregIsVirtual(am->Mam.RR.index)),
920 am->Mam.RR.base);
sewardj362cf842012-06-07 08:59:53 +0000921 break;
922 default:
923 vpanic("dopyMIPSAMode");
924 break;
925 }
926 return ret;
927}
928
929MIPSAMode *nextMIPSAModeInt(MIPSAMode * am)
930{
931 MIPSAMode* ret;
932 switch (am->tag) {
933 case Mam_IR:
934 ret = MIPSAMode_IR(am->Mam.IR.index + 4, am->Mam.IR.base);
935 break;
936 case Mam_RR:
petarja81d9be2013-01-30 18:06:26 +0000937 ret = MIPSAMode_RR(mkHReg(hregNumber(am->Mam.RR.index) + 1,
938 hregClass(am->Mam.RR.index),
939 hregIsVirtual(am->Mam.RR.index)),
940 am->Mam.RR.base);
sewardj362cf842012-06-07 08:59:53 +0000941 break;
942 default:
943 vpanic("dopyMIPSAMode");
944 break;
945 }
946 return ret;
947}
948
949void ppMIPSAMode(MIPSAMode * am, Bool mode64)
950{
951 switch (am->tag) {
952 case Mam_IR:
953 if (am->Mam.IR.index == 0)
954 vex_printf("0(");
955 else
956 vex_printf("%d(", (Int) am->Mam.IR.index);
957 ppHRegMIPS(am->Mam.IR.base, mode64);
958 vex_printf(")");
959 return;
960 case Mam_RR:
961 ppHRegMIPS(am->Mam.RR.base, mode64);
962 vex_printf(", ");
963 ppHRegMIPS(am->Mam.RR.index, mode64);
964 return;
965 default:
966 vpanic("ppMIPSAMode");
967 break;
968 }
969}
970
971static void addRegUsage_MIPSAMode(HRegUsage * u, MIPSAMode * am)
972{
973 switch (am->tag) {
974 case Mam_IR:
975 addHRegUse(u, HRmRead, am->Mam.IR.base);
976 return;
977 case Mam_RR:
978 addHRegUse(u, HRmRead, am->Mam.RR.base);
979 addHRegUse(u, HRmRead, am->Mam.RR.index);
980 return;
981 default:
982 vpanic("addRegUsage_MIPSAMode");
983 break;
984 }
985}
986
987static void mapRegs_MIPSAMode(HRegRemap * m, MIPSAMode * am)
988{
989 switch (am->tag) {
990 case Mam_IR:
991 am->Mam.IR.base = lookupHRegRemap(m, am->Mam.IR.base);
992 return;
993 case Mam_RR:
994 am->Mam.RR.base = lookupHRegRemap(m, am->Mam.RR.base);
995 am->Mam.RR.index = lookupHRegRemap(m, am->Mam.RR.index);
996 return;
997 default:
998 vpanic("mapRegs_MIPSAMode");
999 break;
1000 }
1001}
1002
1003/* --------- Operand, which can be a reg or a u16/s16. --------- */
1004
1005MIPSRH *MIPSRH_Imm(Bool syned, UShort imm16)
1006{
1007 MIPSRH *op = LibVEX_Alloc(sizeof(MIPSRH));
1008 op->tag = Mrh_Imm;
1009 op->Mrh.Imm.syned = syned;
1010 op->Mrh.Imm.imm16 = imm16;
1011 /* If this is a signed value, ensure it's not -32768, so that we
1012 are guaranteed always to be able to negate if needed. */
1013 if (syned)
1014 vassert(imm16 != 0x8000);
1015 vassert(syned == True || syned == False);
1016 return op;
1017}
1018
1019MIPSRH *MIPSRH_Reg(HReg reg)
1020{
1021 MIPSRH *op = LibVEX_Alloc(sizeof(MIPSRH));
1022 op->tag = Mrh_Reg;
1023 op->Mrh.Reg.reg = reg;
1024 return op;
1025}
1026
1027void ppMIPSRH(MIPSRH * op, Bool mode64)
1028{
1029 MIPSRHTag tag = op->tag;
1030 switch (tag) {
1031 case Mrh_Imm:
1032 if (op->Mrh.Imm.syned)
1033 vex_printf("%d", (Int) (Short) op->Mrh.Imm.imm16);
1034 else
1035 vex_printf("%u", (UInt) (UShort) op->Mrh.Imm.imm16);
1036 return;
1037 case Mrh_Reg:
1038 ppHRegMIPS(op->Mrh.Reg.reg, mode64);
1039 return;
1040 default:
1041 vpanic("ppMIPSRH");
1042 break;
1043 }
1044}
1045
1046/* An MIPSRH can only be used in a "read" context (what would it mean
1047 to write or modify a literal?) and so we enumerate its registers
1048 accordingly. */
1049static void addRegUsage_MIPSRH(HRegUsage * u, MIPSRH * op)
1050{
1051 switch (op->tag) {
1052 case Mrh_Imm:
1053 return;
1054 case Mrh_Reg:
1055 addHRegUse(u, HRmRead, op->Mrh.Reg.reg);
1056 return;
1057 default:
1058 vpanic("addRegUsage_MIPSRH");
1059 break;
1060 }
1061}
1062
1063static void mapRegs_MIPSRH(HRegRemap * m, MIPSRH * op)
1064{
1065 switch (op->tag) {
1066 case Mrh_Imm:
1067 return;
1068 case Mrh_Reg:
1069 op->Mrh.Reg.reg = lookupHRegRemap(m, op->Mrh.Reg.reg);
1070 return;
1071 default:
1072 vpanic("mapRegs_MIPSRH");
1073 break;
1074 }
1075}
1076
1077/* --------- Instructions. --------- */
1078
florian55085f82012-11-21 00:36:55 +00001079const HChar *showMIPSUnaryOp(MIPSUnaryOp op)
sewardj362cf842012-06-07 08:59:53 +00001080{
florian55085f82012-11-21 00:36:55 +00001081 const HChar* ret;
sewardj362cf842012-06-07 08:59:53 +00001082 switch (op) {
1083 case Mun_CLO:
1084 ret = "clo";
1085 break;
1086 case Mun_CLZ:
1087 ret = "clz";
1088 break;
1089 case Mun_NOP:
1090 ret = "nop";
1091 break;
petarjb92a9542013-02-27 22:57:17 +00001092 case Mun_DCLO:
1093 ret = "dclo";
1094 break;
1095 case Mun_DCLZ:
1096 ret = "dclz";
1097 break;
sewardj362cf842012-06-07 08:59:53 +00001098 default:
1099 vpanic("showMIPSUnaryOp");
1100 break;
1101 }
1102 return ret;
1103}
1104
florian55085f82012-11-21 00:36:55 +00001105const HChar *showMIPSAluOp(MIPSAluOp op, Bool immR)
sewardj362cf842012-06-07 08:59:53 +00001106{
florian55085f82012-11-21 00:36:55 +00001107 const HChar* ret;
sewardj362cf842012-06-07 08:59:53 +00001108 switch (op) {
1109 case Malu_ADD:
1110 ret = immR ? "addiu" : "addu";
1111 break;
1112 case Malu_SUB:
1113 ret = "subu";
1114 break;
1115 case Malu_AND:
1116 ret = immR ? "andi" : "and";
1117 break;
1118 case Malu_OR:
1119 ret = immR ? "ori" : "or";
1120 break;
1121 case Malu_NOR:
1122 vassert(immR == False); /*there's no nor with an immediate operand!? */
1123 ret = "nor";
1124 break;
1125 case Malu_XOR:
1126 ret = immR ? "xori" : "xor";
1127 break;
petarjb92a9542013-02-27 22:57:17 +00001128 case Malu_DADD:
1129 ret = immR ? "daddi" : "dadd";
1130 break;
1131 case Malu_DSUB:
1132 ret = immR ? "dsubi" : "dsub";
1133 break;
1134 case Malu_SLT:
1135 ret = immR ? "slti" : "slt";
1136 break;
sewardj362cf842012-06-07 08:59:53 +00001137 default:
1138 vpanic("showMIPSAluOp");
1139 break;
1140 }
1141 return ret;
1142}
1143
florian55085f82012-11-21 00:36:55 +00001144const HChar *showMIPSShftOp(MIPSShftOp op, Bool immR, Bool sz32)
sewardj362cf842012-06-07 08:59:53 +00001145{
florian55085f82012-11-21 00:36:55 +00001146 const HChar *ret;
sewardj362cf842012-06-07 08:59:53 +00001147 switch (op) {
1148 case Mshft_SRA:
dejanjc3fee0d2013-07-25 09:08:03 +00001149 ret = immR ? (sz32 ? "sra" : "dsra") : (sz32 ? "srav" : "dsrav");
sewardj362cf842012-06-07 08:59:53 +00001150 break;
1151 case Mshft_SLL:
1152 ret = immR ? (sz32 ? "sll" : "dsll") : (sz32 ? "sllv" : "dsllv");
1153 break;
1154 case Mshft_SRL:
1155 ret = immR ? (sz32 ? "srl" : "dsrl") : (sz32 ? "srlv" : "dsrlv");
1156 break;
1157 default:
1158 vpanic("showMIPSShftOp");
1159 break;
1160 }
1161 return ret;
1162}
1163
florian55085f82012-11-21 00:36:55 +00001164const HChar *showMIPSMaccOp(MIPSMaccOp op, Bool variable)
sewardj362cf842012-06-07 08:59:53 +00001165{
florian55085f82012-11-21 00:36:55 +00001166 const HChar *ret;
sewardj362cf842012-06-07 08:59:53 +00001167 switch (op) {
1168 case Macc_ADD:
1169 ret = variable ? "madd" : "maddu";
1170 break;
1171 case Macc_SUB:
1172 ret = variable ? "msub" : "msubu";
1173 break;
1174 default:
1175 vpanic("showMIPSAccOp");
1176 break;
1177 }
1178 return ret;
1179}
1180
1181MIPSInstr *MIPSInstr_LI(HReg dst, ULong imm)
1182{
1183 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1184 i->tag = Min_LI;
1185 i->Min.LI.dst = dst;
1186 i->Min.LI.imm = imm;
1187 return i;
1188}
1189
1190MIPSInstr *MIPSInstr_Alu(MIPSAluOp op, HReg dst, HReg srcL, MIPSRH * srcR)
1191{
1192 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1193 i->tag = Min_Alu;
1194 i->Min.Alu.op = op;
1195 i->Min.Alu.dst = dst;
1196 i->Min.Alu.srcL = srcL;
1197 i->Min.Alu.srcR = srcR;
1198 return i;
1199}
1200
1201MIPSInstr *MIPSInstr_Shft(MIPSShftOp op, Bool sz32, HReg dst, HReg srcL,
1202 MIPSRH * srcR)
1203{
1204 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1205 i->tag = Min_Shft;
1206 i->Min.Shft.op = op;
1207 i->Min.Shft.sz32 = sz32;
1208 i->Min.Shft.dst = dst;
1209 i->Min.Shft.srcL = srcL;
1210 i->Min.Shft.srcR = srcR;
1211 return i;
1212}
1213
1214MIPSInstr *MIPSInstr_Unary(MIPSUnaryOp op, HReg dst, HReg src)
1215{
1216 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1217 i->tag = Min_Unary;
1218 i->Min.Unary.op = op;
1219 i->Min.Unary.dst = dst;
1220 i->Min.Unary.src = src;
1221 return i;
1222}
1223
1224MIPSInstr *MIPSInstr_Cmp(Bool syned, Bool sz32, HReg dst, HReg srcL, HReg srcR,
1225 MIPSCondCode cond)
1226{
1227 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1228 i->tag = Min_Cmp;
1229 i->Min.Cmp.syned = syned;
1230 i->Min.Cmp.sz32 = sz32;
1231 i->Min.Cmp.dst = dst;
1232 i->Min.Cmp.srcL = srcL;
1233 i->Min.Cmp.srcR = srcR;
1234 i->Min.Cmp.cond = cond;
1235 return i;
1236}
1237
1238/* multiply */
1239MIPSInstr *MIPSInstr_Mul(Bool syned, Bool wid, Bool sz32, HReg dst, HReg srcL,
1240 HReg srcR)
1241{
1242 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1243 i->tag = Min_Mul;
1244 i->Min.Mul.syned = syned;
1245 i->Min.Mul.widening = wid; /* widen=True else False */
1246 i->Min.Mul.sz32 = sz32; /* True = 32 bits */
1247 i->Min.Mul.dst = dst;
1248 i->Min.Mul.srcL = srcL;
1249 i->Min.Mul.srcR = srcR;
1250 return i;
1251}
1252
1253/* msub */
1254MIPSInstr *MIPSInstr_Msub(Bool syned, HReg srcL, HReg srcR)
1255{
1256 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1257 i->tag = Min_Macc;
1258
1259 i->Min.Macc.op = Macc_SUB;
1260 i->Min.Macc.syned = syned;
1261 i->Min.Macc.srcL = srcL;
1262 i->Min.Macc.srcR = srcR;
1263 return i;
1264}
1265
1266/* madd */
1267MIPSInstr *MIPSInstr_Madd(Bool syned, HReg srcL, HReg srcR)
1268{
1269 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1270 i->tag = Min_Macc;
1271
1272 i->Min.Macc.op = Macc_ADD;
1273 i->Min.Macc.syned = syned;
1274 i->Min.Macc.srcL = srcL;
1275 i->Min.Macc.srcR = srcR;
1276 return i;
1277}
1278
1279/* div */
1280MIPSInstr *MIPSInstr_Div(Bool syned, Bool sz32, HReg srcL, HReg srcR)
1281{
1282 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1283 i->tag = Min_Div;
1284 i->Min.Div.syned = syned;
1285 i->Min.Div.sz32 = sz32; /* True = 32 bits */
1286 i->Min.Div.srcL = srcL;
1287 i->Min.Div.srcR = srcR;
1288 return i;
1289}
1290
petarjb92a9542013-02-27 22:57:17 +00001291MIPSInstr *MIPSInstr_Call ( MIPSCondCode cond, Addr64 target, UInt argiregs,
1292 HReg src, RetLoc rloc )
sewardj362cf842012-06-07 08:59:53 +00001293{
1294 UInt mask;
1295 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1296 i->tag = Min_Call;
1297 i->Min.Call.cond = cond;
1298 i->Min.Call.target = target;
1299 i->Min.Call.argiregs = argiregs;
1300 i->Min.Call.src = src;
sewardjcfe046e2013-01-17 14:23:53 +00001301 i->Min.Call.rloc = rloc;
petarjb92a9542013-02-27 22:57:17 +00001302 /* Only $4 .. $7/$11 inclusive may be used as arg regs. */
1303 mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
1304 | (1 << 10) | (1 << 11);
sewardj362cf842012-06-07 08:59:53 +00001305 vassert(0 == (argiregs & ~mask));
sewardj74142b82013-08-08 10:28:59 +00001306 vassert(is_sane_RetLoc(rloc));
sewardj362cf842012-06-07 08:59:53 +00001307 return i;
1308}
1309
petarjb92a9542013-02-27 22:57:17 +00001310MIPSInstr *MIPSInstr_CallAlways ( MIPSCondCode cond, Addr64 target,
1311 UInt argiregs, RetLoc rloc )
sewardj362cf842012-06-07 08:59:53 +00001312{
1313 UInt mask;
1314 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1315 i->tag = Min_Call;
1316 i->Min.Call.cond = cond;
1317 i->Min.Call.target = target;
1318 i->Min.Call.argiregs = argiregs;
sewardjcfe046e2013-01-17 14:23:53 +00001319 i->Min.Call.rloc = rloc;
petarjb92a9542013-02-27 22:57:17 +00001320 /* Only $4 .. $7/$11 inclusive may be used as arg regs. */
1321 mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
1322 | (1 << 10) | (1 << 11);
sewardj362cf842012-06-07 08:59:53 +00001323 vassert(0 == (argiregs & ~mask));
sewardj74142b82013-08-08 10:28:59 +00001324 vassert(is_sane_RetLoc(rloc));
sewardj362cf842012-06-07 08:59:53 +00001325 return i;
1326}
1327
petarjb92a9542013-02-27 22:57:17 +00001328MIPSInstr *MIPSInstr_XDirect ( Addr64 dstGA, MIPSAMode* amPC,
sewardj362cf842012-06-07 08:59:53 +00001329 MIPSCondCode cond, Bool toFastEP ) {
1330 MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
1331 i->tag = Min_XDirect;
1332 i->Min.XDirect.dstGA = dstGA;
1333 i->Min.XDirect.amPC = amPC;
1334 i->Min.XDirect.cond = cond;
1335 i->Min.XDirect.toFastEP = toFastEP;
1336 return i;
1337}
1338
1339MIPSInstr *MIPSInstr_XIndir ( HReg dstGA, MIPSAMode* amPC,
1340 MIPSCondCode cond ) {
1341 MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
1342 i->tag = Min_XIndir;
1343 i->Min.XIndir.dstGA = dstGA;
1344 i->Min.XIndir.amPC = amPC;
1345 i->Min.XIndir.cond = cond;
1346 return i;
1347}
1348
1349MIPSInstr *MIPSInstr_XAssisted ( HReg dstGA, MIPSAMode* amPC,
1350 MIPSCondCode cond, IRJumpKind jk ) {
1351 MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
1352 i->tag = Min_XAssisted;
1353 i->Min.XAssisted.dstGA = dstGA;
1354 i->Min.XAssisted.amPC = amPC;
1355 i->Min.XAssisted.cond = cond;
1356 i->Min.XAssisted.jk = jk;
1357 return i;
1358}
1359
1360MIPSInstr *MIPSInstr_Load(UChar sz, HReg dst, MIPSAMode * src, Bool mode64)
1361{
1362 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1363 i->tag = Min_Load;
1364 i->Min.Load.sz = sz;
1365 i->Min.Load.src = src;
1366 i->Min.Load.dst = dst;
1367 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
1368
1369 if (sz == 8)
1370 vassert(mode64);
1371 return i;
1372}
1373
1374MIPSInstr *MIPSInstr_Store(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
1375{
1376 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1377 i->tag = Min_Store;
1378 i->Min.Store.sz = sz;
1379 i->Min.Store.src = src;
1380 i->Min.Store.dst = dst;
1381 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
1382
1383 if (sz == 8)
1384 vassert(mode64);
1385 return i;
1386}
1387
1388MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src, Bool mode64)
1389{
1390 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1391 i->tag = Min_LoadL;
1392 i->Min.LoadL.sz = sz;
1393 i->Min.LoadL.src = src;
1394 i->Min.LoadL.dst = dst;
1395 vassert(sz == 4 || sz == 8);
1396
1397 if (sz == 8)
1398 vassert(mode64);
1399 return i;
1400}
1401
dejanj6ced72b2014-06-04 11:28:07 +00001402MIPSInstr *MIPSInstr_Cas(UChar sz, HReg old, HReg addr,
1403 HReg expd, HReg data, Bool mode64)
1404{
1405 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1406 i->tag = Min_Cas;
1407 i->Min.Cas.sz = sz;
1408 i->Min.Cas.old = old;
1409 i->Min.Cas.addr = addr;
1410 i->Min.Cas.expd = expd;
1411 i->Min.Cas.data = data;
1412 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
1413
1414 if (sz == 8)
1415 vassert(mode64);
1416 return i;
1417}
1418
sewardj362cf842012-06-07 08:59:53 +00001419MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
1420{
1421 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1422 i->tag = Min_StoreC;
1423 i->Min.StoreC.sz = sz;
1424 i->Min.StoreC.src = src;
1425 i->Min.StoreC.dst = dst;
1426 vassert(sz == 4 || sz == 8);
1427
1428 if (sz == 8)
1429 vassert(mode64);
1430 return i;
1431}
1432
1433MIPSInstr *MIPSInstr_Mthi(HReg src)
1434{
1435 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1436 i->tag = Min_Mthi;
1437 i->Min.MtHL.src = src;
1438 return i;
1439}
1440
1441MIPSInstr *MIPSInstr_Mtlo(HReg src)
1442{
1443 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1444 i->tag = Min_Mtlo;
1445 i->Min.MtHL.src = src;
1446 return i;
1447}
1448
1449MIPSInstr *MIPSInstr_Mfhi(HReg dst)
1450{
1451 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1452 i->tag = Min_Mfhi;
1453 i->Min.MfHL.dst = dst;
1454 return i;
1455}
1456
1457MIPSInstr *MIPSInstr_Mflo(HReg dst)
1458{
1459 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1460 i->tag = Min_Mflo;
1461 i->Min.MfHL.dst = dst;
1462 return i;
1463}
1464
1465/* Read/Write Link Register */
1466MIPSInstr *MIPSInstr_RdWrLR(Bool wrLR, HReg gpr)
1467{
1468 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1469 i->tag = Min_RdWrLR;
1470 i->Min.RdWrLR.wrLR = wrLR;
1471 i->Min.RdWrLR.gpr = gpr;
1472 return i;
1473}
1474
1475MIPSInstr *MIPSInstr_FpLdSt(Bool isLoad, UChar sz, HReg reg, MIPSAMode * addr)
1476{
1477 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1478 i->tag = Min_FpLdSt;
1479 i->Min.FpLdSt.isLoad = isLoad;
1480 i->Min.FpLdSt.sz = sz;
1481 i->Min.FpLdSt.reg = reg;
1482 i->Min.FpLdSt.addr = addr;
1483 vassert(sz == 4 || sz == 8);
1484 return i;
1485}
1486
1487MIPSInstr *MIPSInstr_FpUnary(MIPSFpOp op, HReg dst, HReg src)
1488{
1489 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1490 i->tag = Min_FpUnary;
1491 i->Min.FpUnary.op = op;
1492 i->Min.FpUnary.dst = dst;
1493 i->Min.FpUnary.src = src;
1494 return i;
1495}
1496
1497MIPSInstr *MIPSInstr_FpBinary(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR)
1498{
1499 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1500 i->tag = Min_FpBinary;
1501 i->Min.FpBinary.op = op;
1502 i->Min.FpBinary.dst = dst;
1503 i->Min.FpBinary.srcL = srcL;
1504 i->Min.FpBinary.srcR = srcR;
1505 return i;
1506}
1507
petarjb92a9542013-02-27 22:57:17 +00001508MIPSInstr *MIPSInstr_FpTernary ( MIPSFpOp op, HReg dst, HReg src1, HReg src2,
1509 HReg src3 )
1510{
1511 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1512 i->tag = Min_FpTernary;
1513 i->Min.FpTernary.op = op;
1514 i->Min.FpTernary.dst = dst;
1515 i->Min.FpTernary.src1 = src1;
1516 i->Min.FpTernary.src2 = src2;
1517 i->Min.FpTernary.src3 = src3;
1518 return i;
1519}
1520
sewardj362cf842012-06-07 08:59:53 +00001521MIPSInstr *MIPSInstr_FpConvert(MIPSFpOp op, HReg dst, HReg src)
1522{
1523 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1524 i->tag = Min_FpConvert;
1525 i->Min.FpConvert.op = op;
1526 i->Min.FpConvert.dst = dst;
1527 i->Min.FpConvert.src = src;
1528 return i;
1529
1530}
1531
dejanjf37c0862014-02-25 15:25:49 +00001532MIPSInstr *MIPSInstr_FpCompare(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR)
sewardj362cf842012-06-07 08:59:53 +00001533{
1534 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1535 i->tag = Min_FpCompare;
1536 i->Min.FpCompare.op = op;
1537 i->Min.FpCompare.dst = dst;
1538 i->Min.FpCompare.srcL = srcL;
1539 i->Min.FpCompare.srcR = srcR;
sewardj362cf842012-06-07 08:59:53 +00001540 return i;
1541}
1542
sewardj362cf842012-06-07 08:59:53 +00001543MIPSInstr *MIPSInstr_MtFCSR(HReg src)
1544{
1545 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1546 i->tag = Min_MtFCSR;
1547 i->Min.MtFCSR.src = src;
1548 return i;
1549}
1550
1551MIPSInstr *MIPSInstr_MfFCSR(HReg dst)
1552{
1553 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1554 i->tag = Min_MfFCSR;
1555 i->Min.MfFCSR.dst = dst;
1556 return i;
1557}
1558
petarjb92a9542013-02-27 22:57:17 +00001559MIPSInstr *MIPSInstr_FpGpMove ( MIPSFpGpMoveOp op, HReg dst, HReg src )
1560{
1561 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1562 i->tag = Min_FpGpMove;
1563 i->Min.FpGpMove.op = op;
1564 i->Min.FpGpMove.dst = dst;
1565 i->Min.FpGpMove.src = src;
1566 return i;
1567}
1568
1569MIPSInstr *MIPSInstr_MoveCond ( MIPSMoveCondOp op, HReg dst, HReg src,
1570 HReg cond )
1571{
1572 MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
1573 i->tag = Min_MoveCond;
1574 i->Min.MoveCond.op = op;
1575 i->Min.MoveCond.dst = dst;
1576 i->Min.MoveCond.src = src;
1577 i->Min.MoveCond.cond = cond;
1578 return i;
1579}
1580
sewardj362cf842012-06-07 08:59:53 +00001581MIPSInstr *MIPSInstr_EvCheck ( MIPSAMode* amCounter,
1582 MIPSAMode* amFailAddr ) {
1583 MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
1584 i->tag = Min_EvCheck;
1585 i->Min.EvCheck.amCounter = amCounter;
1586 i->Min.EvCheck.amFailAddr = amFailAddr;
1587 return i;
1588}
1589
1590MIPSInstr* MIPSInstr_ProfInc ( void ) {
1591 MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
1592 i->tag = Min_ProfInc;
1593 return i;
1594}
1595
1596/* -------- Pretty Print instructions ------------- */
1597static void ppLoadImm(HReg dst, ULong imm, Bool mode64)
1598{
1599 vex_printf("li ");
1600 ppHRegMIPS(dst, mode64);
1601 vex_printf(",0x%016llx", imm);
1602}
1603
floriand8c64e02014-10-08 08:54:44 +00001604void ppMIPSInstr(const MIPSInstr * i, Bool mode64)
sewardj362cf842012-06-07 08:59:53 +00001605{
1606 switch (i->tag) {
1607 case Min_LI:
1608 ppLoadImm(i->Min.LI.dst, i->Min.LI.imm, mode64);
1609 break;
1610 case Min_Alu: {
1611 HReg r_srcL = i->Min.Alu.srcL;
1612 MIPSRH *rh_srcR = i->Min.Alu.srcR;
1613 /* generic */
1614 vex_printf("%s ", showMIPSAluOp(i->Min.Alu.op,
1615 toBool(rh_srcR->tag == Mrh_Imm)));
1616 ppHRegMIPS(i->Min.Alu.dst, mode64);
1617 vex_printf(",");
1618 ppHRegMIPS(r_srcL, mode64);
1619 vex_printf(",");
1620 ppMIPSRH(rh_srcR, mode64);
1621 return;
1622 }
1623 case Min_Shft: {
1624 HReg r_srcL = i->Min.Shft.srcL;
1625 MIPSRH *rh_srcR = i->Min.Shft.srcR;
1626 vex_printf("%s ", showMIPSShftOp(i->Min.Shft.op,
1627 toBool(rh_srcR->tag == Mrh_Imm),
1628 i->Min.Shft.sz32));
1629 ppHRegMIPS(i->Min.Shft.dst, mode64);
1630 vex_printf(",");
1631 ppHRegMIPS(r_srcL, mode64);
1632 vex_printf(",");
1633 ppMIPSRH(rh_srcR, mode64);
1634 return;
1635 }
1636 case Min_Unary: {
1637 vex_printf("%s ", showMIPSUnaryOp(i->Min.Unary.op));
1638 ppHRegMIPS(i->Min.Unary.dst, mode64);
1639 vex_printf(",");
1640 ppHRegMIPS(i->Min.Unary.src, mode64);
1641 return;
1642 }
1643 case Min_Cmp: {
1644 vex_printf("word_compare ");
1645 ppHRegMIPS(i->Min.Cmp.dst, mode64);
1646 vex_printf(" = %s ( ", showMIPSCondCode(i->Min.Cmp.cond));
1647 ppHRegMIPS(i->Min.Cmp.srcL, mode64);
1648 vex_printf(", ");
1649 ppHRegMIPS(i->Min.Cmp.srcR, mode64);
1650 vex_printf(" )");
1651
1652 return;
1653 }
1654 case Min_Mul: {
1655 switch (i->Min.Mul.widening) {
1656 case False:
1657 vex_printf("mul ");
1658 ppHRegMIPS(i->Min.Mul.dst, mode64);
1659 vex_printf(", ");
1660 ppHRegMIPS(i->Min.Mul.srcL, mode64);
1661 vex_printf(", ");
1662 ppHRegMIPS(i->Min.Mul.srcR, mode64);
1663 return;
1664 case True:
1665 vex_printf("%s%s ", i->Min.Mul.sz32 ? "mult" : "dmult",
1666 i->Min.Mul.syned ? "" : "u");
1667 ppHRegMIPS(i->Min.Mul.dst, mode64);
1668 vex_printf(", ");
1669 ppHRegMIPS(i->Min.Mul.srcL, mode64);
1670 vex_printf(", ");
1671 ppHRegMIPS(i->Min.Mul.srcR, mode64);
1672 return;
1673 }
1674 break;
1675 }
1676 case Min_Mthi: {
1677 vex_printf("mthi ");
1678 ppHRegMIPS(i->Min.MtHL.src, mode64);
1679 return;
1680 }
1681 case Min_Mtlo: {
1682 vex_printf("mtlo ");
1683 ppHRegMIPS(i->Min.MtHL.src, mode64);
1684 return;
1685 }
1686 case Min_Mfhi: {
1687 vex_printf("mfhi ");
1688 ppHRegMIPS(i->Min.MfHL.dst, mode64);
1689 return;
1690 }
1691 case Min_Mflo: {
1692 vex_printf("mflo ");
1693 ppHRegMIPS(i->Min.MfHL.dst, mode64);
1694 return;
1695 }
1696 case Min_Macc: {
1697 vex_printf("%s ", showMIPSMaccOp(i->Min.Macc.op, i->Min.Macc.syned));
1698 ppHRegMIPS(i->Min.Macc.srcL, mode64);
1699 vex_printf(", ");
1700 ppHRegMIPS(i->Min.Macc.srcR, mode64);
1701 return;
1702 }
1703 case Min_Div: {
1704 if (!i->Min.Div.sz32)
1705 vex_printf("d");
1706 vex_printf("div");
1707 vex_printf("%s ", i->Min.Div.syned ? "s" : "u");
1708 ppHRegMIPS(i->Min.Div.srcL, mode64);
1709 vex_printf(", ");
1710 ppHRegMIPS(i->Min.Div.srcR, mode64);
1711 return;
1712 }
1713 case Min_Call: {
1714 Int n;
1715 vex_printf("call: ");
1716 if (i->Min.Call.cond != MIPScc_AL) {
1717 vex_printf("if (%s) ", showMIPSCondCode(i->Min.Call.cond));
1718 }
petarjb92a9542013-02-27 22:57:17 +00001719 vex_printf(" {");
1720 if (!mode64)
1721 vex_printf(" addiu $29, $29, -16");
sewardj362cf842012-06-07 08:59:53 +00001722
petarjb92a9542013-02-27 22:57:17 +00001723 ppLoadImm(hregMIPS_GPR25(mode64), i->Min.Call.target, mode64);
1724
1725 vex_printf(" ; jarl $31, $25; # args [");
sewardj362cf842012-06-07 08:59:53 +00001726 for (n = 0; n < 32; n++) {
1727 if (i->Min.Call.argiregs & (1 << n)) {
petarjb92a9542013-02-27 22:57:17 +00001728 vex_printf("$%d", n);
sewardj362cf842012-06-07 08:59:53 +00001729 if ((i->Min.Call.argiregs >> n) > 1)
1730 vex_printf(",");
1731 }
1732 }
petarjb92a9542013-02-27 22:57:17 +00001733 vex_printf("] nop; ");
1734 if (!mode64)
1735 vex_printf("addiu $29, $29, 16; ]");
1736
sewardj362cf842012-06-07 08:59:53 +00001737 break;
1738 }
1739 case Min_XDirect:
1740 vex_printf("(xDirect) ");
1741 vex_printf("if (guest_COND.%s) { ",
1742 showMIPSCondCode(i->Min.XDirect.cond));
petarjb92a9542013-02-27 22:57:17 +00001743 vex_printf("move $9, 0x%x,", (UInt)i->Min.XDirect.dstGA);
sewardj362cf842012-06-07 08:59:53 +00001744 vex_printf("; sw $9, ");
1745 ppMIPSAMode(i->Min.XDirect.amPC, mode64);
1746 vex_printf("; move $9, $disp_cp_chain_me_to_%sEP; jalr $9; nop}",
1747 i->Min.XDirect.toFastEP ? "fast" : "slow");
1748 return;
1749 case Min_XIndir:
1750 vex_printf("(xIndir) ");
1751 vex_printf("if (guest_COND.%s) { sw ",
dejanjc3fee0d2013-07-25 09:08:03 +00001752 showMIPSCondCode(i->Min.XIndir.cond));
sewardj362cf842012-06-07 08:59:53 +00001753 ppHRegMIPS(i->Min.XIndir.dstGA, mode64);
1754 vex_printf(", ");
1755 ppMIPSAMode(i->Min.XIndir.amPC, mode64);
1756 vex_printf("; move $9, $disp_indir; jalr $9; nop}");
1757 return;
1758 case Min_XAssisted:
1759 vex_printf("(xAssisted) ");
1760 vex_printf("if (guest_COND.%s) { ",
1761 showMIPSCondCode(i->Min.XAssisted.cond));
1762 vex_printf("sw ");
1763 ppHRegMIPS(i->Min.XAssisted.dstGA, mode64);
1764 vex_printf(", ");
1765 ppMIPSAMode(i->Min.XAssisted.amPC, mode64);
1766 vex_printf("; move $9, $IRJumpKind_to_TRCVAL(%d)",
1767 (Int)i->Min.XAssisted.jk);
1768 vex_printf("; move $9, $disp_assisted; jalr $9; nop; }");
1769 return;
1770 case Min_Load: {
1771 Bool idxd = toBool(i->Min.Load.src->tag == Mam_RR);
1772 UChar sz = i->Min.Load.sz;
florian5df8ab02012-10-13 19:34:19 +00001773 HChar c_sz = sz == 1 ? 'b' : sz == 2 ? 'h' : sz == 4 ? 'w' : 'd';
sewardj362cf842012-06-07 08:59:53 +00001774 vex_printf("l%c%s ", c_sz, idxd ? "x" : "");
1775 ppHRegMIPS(i->Min.Load.dst, mode64);
1776 vex_printf(",");
1777 ppMIPSAMode(i->Min.Load.src, mode64);
1778 return;
1779 }
1780 case Min_Store: {
1781 UChar sz = i->Min.Store.sz;
1782 Bool idxd = toBool(i->Min.Store.dst->tag == Mam_RR);
florian5df8ab02012-10-13 19:34:19 +00001783 HChar c_sz = sz == 1 ? 'b' : sz == 2 ? 'h' : sz == 4 ? 'w' : 'd';
sewardj362cf842012-06-07 08:59:53 +00001784 vex_printf("s%c%s ", c_sz, idxd ? "x" : "");
1785 ppHRegMIPS(i->Min.Store.src, mode64);
1786 vex_printf(",");
1787 ppMIPSAMode(i->Min.Store.dst, mode64);
1788 return;
1789 }
1790 case Min_LoadL: {
1791 vex_printf("ll ");
1792 ppHRegMIPS(i->Min.LoadL.dst, mode64);
1793 vex_printf(",");
1794 ppMIPSAMode(i->Min.LoadL.src, mode64);
1795 return;
1796 }
dejanj6ced72b2014-06-04 11:28:07 +00001797 case Min_Cas: {
1798 Bool sz8 = toBool(i->Min.Cas.sz == 8);
1799 /*
1800 * ll(d) old, 0(addr)
1801 * bne old, expd, end
1802 * nop
1803 * (d)addiu old, old, 1
1804 * sc(d) data, 0(addr)
1805 * movn old, expd, data
1806 * end:
1807 */
1808 // ll(d) old, 0(addr)
1809 vex_printf("cas: ");
1810
1811 vex_printf("%s ", sz8 ? "lld" : "ll");
1812 ppHRegMIPS(i->Min.Cas.old , mode64);
1813 vex_printf(", 0(");
1814 ppHRegMIPS(i->Min.Cas.addr , mode64);
1815 vex_printf(")\n");
1816
1817 vex_printf("bne ");
1818 ppHRegMIPS(i->Min.Cas.old , mode64);
1819 vex_printf(", ");
1820 ppHRegMIPS(i->Min.Cas.expd , mode64);
1821 vex_printf(", end\n");
1822
1823 vex_printf("nop\n");
1824
1825 vex_printf("%s ", sz8 ? "daddiu" : "addiu");
1826 ppHRegMIPS(i->Min.Cas.old , mode64);
1827 vex_printf(", ");
1828 ppHRegMIPS(i->Min.Cas.old , mode64);
1829 vex_printf(", 1\n");
1830
1831 vex_printf("%s ", sz8 ? "scd" : "sc");
1832 ppHRegMIPS(i->Min.Cas.data , mode64);
1833 vex_printf(", 0(");
1834 ppHRegMIPS(i->Min.Cas.addr , mode64);
1835 vex_printf(")\n");
1836
1837 vex_printf("movn ");
1838 ppHRegMIPS(i->Min.Cas.old , mode64);
1839 vex_printf(", ");
1840 ppHRegMIPS(i->Min.Cas.expd , mode64);
1841 vex_printf(", ");
1842 ppHRegMIPS(i->Min.Cas.data , mode64);
1843 vex_printf("\nend:");
1844 return;
1845 }
sewardj362cf842012-06-07 08:59:53 +00001846 case Min_StoreC: {
1847 vex_printf("sc ");
1848 ppHRegMIPS(i->Min.StoreC.src, mode64);
1849 vex_printf(",");
1850 ppMIPSAMode(i->Min.StoreC.dst, mode64);
1851 return;
1852 }
1853 case Min_RdWrLR: {
1854 vex_printf("%s ", i->Min.RdWrLR.wrLR ? "mtlr" : "mflr");
1855 ppHRegMIPS(i->Min.RdWrLR.gpr, mode64);
1856 return;
1857 }
1858 case Min_FpUnary:
1859 vex_printf("%s ", showMIPSFpOp(i->Min.FpUnary.op));
1860 ppHRegMIPS(i->Min.FpUnary.dst, mode64);
1861 vex_printf(",");
1862 ppHRegMIPS(i->Min.FpUnary.src, mode64);
1863 return;
1864 case Min_FpBinary:
1865 vex_printf("%s", showMIPSFpOp(i->Min.FpBinary.op));
1866 ppHRegMIPS(i->Min.FpBinary.dst, mode64);
1867 vex_printf(",");
1868 ppHRegMIPS(i->Min.FpBinary.srcL, mode64);
1869 vex_printf(",");
1870 ppHRegMIPS(i->Min.FpBinary.srcR, mode64);
1871 return;
petarjb92a9542013-02-27 22:57:17 +00001872 case Min_FpTernary:
1873 vex_printf("%s", showMIPSFpOp(i->Min.FpTernary.op));
1874 ppHRegMIPS(i->Min.FpTernary.dst, mode64);
1875 vex_printf(",");
1876 ppHRegMIPS(i->Min.FpTernary.src1, mode64);
1877 vex_printf(",");
1878 ppHRegMIPS(i->Min.FpTernary.src2, mode64);
1879 vex_printf(",");
1880 ppHRegMIPS(i->Min.FpTernary.src3, mode64);
1881 return;
sewardj362cf842012-06-07 08:59:53 +00001882 case Min_FpConvert:
1883 vex_printf("%s", showMIPSFpOp(i->Min.FpConvert.op));
1884 ppHRegMIPS(i->Min.FpConvert.dst, mode64);
1885 vex_printf(",");
1886 ppHRegMIPS(i->Min.FpConvert.src, mode64);
1887 return;
1888 case Min_FpCompare:
1889 vex_printf("%s ", showMIPSFpOp(i->Min.FpCompare.op));
1890 ppHRegMIPS(i->Min.FpCompare.srcL, mode64);
1891 vex_printf(",");
1892 ppHRegMIPS(i->Min.FpCompare.srcR, mode64);
sewardj362cf842012-06-07 08:59:53 +00001893 return;
1894 case Min_FpMulAcc:
1895 vex_printf("%s ", showMIPSFpOp(i->Min.FpMulAcc.op));
1896 ppHRegMIPS(i->Min.FpMulAcc.dst, mode64);
1897 vex_printf(",");
1898 ppHRegMIPS(i->Min.FpMulAcc.srcML, mode64);
1899 vex_printf(",");
1900 ppHRegMIPS(i->Min.FpMulAcc.srcMR, mode64);
1901 vex_printf(",");
1902 ppHRegMIPS(i->Min.FpMulAcc.srcAcc, mode64);
1903 return;
1904 case Min_FpLdSt: {
1905 if (i->Min.FpLdSt.sz == 4) {
1906 if (i->Min.FpLdSt.isLoad) {
1907 vex_printf("lwc1 ");
1908 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1909 vex_printf(",");
1910 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1911 } else {
1912 vex_printf("swc1 ");
1913 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1914 vex_printf(",");
1915 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1916 }
1917 } else if (i->Min.FpLdSt.sz == 8) {
1918 if (i->Min.FpLdSt.isLoad) {
petarj1ec43e02012-09-04 13:45:42 +00001919 vex_printf("ldc1 ");
sewardj362cf842012-06-07 08:59:53 +00001920 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1921 vex_printf(",");
1922 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1923 } else {
petarj1ec43e02012-09-04 13:45:42 +00001924 vex_printf("sdc1 ");
sewardj362cf842012-06-07 08:59:53 +00001925 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1926 vex_printf(",");
1927 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1928 }
1929 }
1930 return;
1931 }
sewardj362cf842012-06-07 08:59:53 +00001932 case Min_MtFCSR: {
dejanjc3fee0d2013-07-25 09:08:03 +00001933 vex_printf("ctc1 ");
sewardj362cf842012-06-07 08:59:53 +00001934 ppHRegMIPS(i->Min.MtFCSR.src, mode64);
1935 vex_printf(", $31");
1936 return;
1937 }
sewardj362cf842012-06-07 08:59:53 +00001938 case Min_MfFCSR: {
dejanjc3fee0d2013-07-25 09:08:03 +00001939 vex_printf("ctc1 ");
sewardj362cf842012-06-07 08:59:53 +00001940 ppHRegMIPS(i->Min.MfFCSR.dst, mode64);
1941 vex_printf(", $31");
1942 return;
1943 }
petarjb92a9542013-02-27 22:57:17 +00001944 case Min_FpGpMove: {
dejanj0e006f22014-02-19 11:56:29 +00001945 vex_printf("%s ", showMIPSFpGpMoveOp(i->Min.FpGpMove.op));
petarjb92a9542013-02-27 22:57:17 +00001946 ppHRegMIPS(i->Min.FpGpMove.dst, mode64);
1947 vex_printf(", ");
1948 ppHRegMIPS(i->Min.FpGpMove.src, mode64);
1949 return;
1950 }
1951 case Min_MoveCond: {
1952 vex_printf("%s", showMIPSMoveCondOp(i->Min.MoveCond.op));
1953 ppHRegMIPS(i->Min.MoveCond.dst, mode64);
1954 vex_printf(", ");
1955 ppHRegMIPS(i->Min.MoveCond.src, mode64);
1956 vex_printf(", ");
1957 ppHRegMIPS(i->Min.MoveCond.cond, mode64);
1958 return;
1959 }
sewardj362cf842012-06-07 08:59:53 +00001960 case Min_EvCheck:
1961 vex_printf("(evCheck) lw $9, ");
1962 ppMIPSAMode(i->Min.EvCheck.amCounter, mode64);
1963 vex_printf("; addiu $9, $9, -1");
1964 vex_printf("; sw $9, ");
1965 ppMIPSAMode(i->Min.EvCheck.amCounter, mode64);
1966 vex_printf("; bgez $t9, nofail; jalr *");
1967 ppMIPSAMode(i->Min.EvCheck.amFailAddr, mode64);
1968 vex_printf("; nofail:");
1969 return;
1970 case Min_ProfInc:
petarjb92a9542013-02-27 22:57:17 +00001971 if (mode64)
1972 vex_printf("(profInc) move $9, ($NotKnownYet); "
1973 "ld $8, 0($9); "
1974 "daddiu $8, $8, 1; "
1975 "sd $8, 0($9); " );
1976 else
1977 vex_printf("(profInc) move $9, ($NotKnownYet); "
1978 "lw $8, 0($9); "
1979 "addiu $8, $8, 1; "
1980 "sw $8, 0($9); "
1981 "sltiu $1, $8, 1; "
1982 "lw $8, 4($9); "
1983 "addu $8, $8, $1; "
1984 "sw $8, 4($9); " );
sewardj362cf842012-06-07 08:59:53 +00001985 return;
1986 default:
1987 vpanic("ppMIPSInstr");
1988 break;
1989 }
1990}
1991
1992/* --------- Helpers for register allocation. --------- */
1993
floriand8c64e02014-10-08 08:54:44 +00001994void getRegUsage_MIPSInstr(HRegUsage * u, const MIPSInstr * i, Bool mode64)
sewardj362cf842012-06-07 08:59:53 +00001995{
1996 initHRegUsage(u);
1997 switch (i->tag) {
1998 case Min_LI:
1999 addHRegUse(u, HRmWrite, i->Min.LI.dst);
2000 break;
2001 case Min_Alu:
2002 addHRegUse(u, HRmRead, i->Min.Alu.srcL);
2003 addRegUsage_MIPSRH(u, i->Min.Alu.srcR);
2004 addHRegUse(u, HRmWrite, i->Min.Alu.dst);
2005 return;
2006 case Min_Shft:
2007 addHRegUse(u, HRmRead, i->Min.Shft.srcL);
2008 addRegUsage_MIPSRH(u, i->Min.Shft.srcR);
2009 addHRegUse(u, HRmWrite, i->Min.Shft.dst);
2010 return;
2011 case Min_Cmp:
2012 addHRegUse(u, HRmRead, i->Min.Cmp.srcL);
2013 addHRegUse(u, HRmRead, i->Min.Cmp.srcR);
2014 addHRegUse(u, HRmWrite, i->Min.Cmp.dst);
2015 return;
2016 case Min_Unary:
2017 addHRegUse(u, HRmRead, i->Min.Unary.src);
2018 addHRegUse(u, HRmWrite, i->Min.Unary.dst);
2019 return;
2020 case Min_Mul:
2021 addHRegUse(u, HRmWrite, i->Min.Mul.dst);
2022 addHRegUse(u, HRmRead, i->Min.Mul.srcL);
2023 addHRegUse(u, HRmRead, i->Min.Mul.srcR);
2024 return;
2025 case Min_Mthi:
2026 case Min_Mtlo:
2027 addHRegUse(u, HRmWrite, hregMIPS_HI(mode64));
2028 addHRegUse(u, HRmWrite, hregMIPS_LO(mode64));
2029 addHRegUse(u, HRmRead, i->Min.MtHL.src);
2030 return;
2031 case Min_Mfhi:
2032 case Min_Mflo:
2033 addHRegUse(u, HRmRead, hregMIPS_HI(mode64));
2034 addHRegUse(u, HRmRead, hregMIPS_LO(mode64));
2035 addHRegUse(u, HRmWrite, i->Min.MfHL.dst);
2036 return;
2037 case Min_MtFCSR:
2038 addHRegUse(u, HRmRead, i->Min.MtFCSR.src);
2039 return;
2040 case Min_MfFCSR:
2041 addHRegUse(u, HRmWrite, i->Min.MfFCSR.dst);
2042 return;
2043 case Min_Macc:
2044 addHRegUse(u, HRmModify, hregMIPS_HI(mode64));
2045 addHRegUse(u, HRmModify, hregMIPS_LO(mode64));
2046 addHRegUse(u, HRmRead, i->Min.Macc.srcL);
2047 addHRegUse(u, HRmRead, i->Min.Macc.srcR);
2048 return;
2049 case Min_Div:
2050 addHRegUse(u, HRmWrite, hregMIPS_HI(mode64));
2051 addHRegUse(u, HRmWrite, hregMIPS_LO(mode64));
2052 addHRegUse(u, HRmRead, i->Min.Div.srcL);
2053 addHRegUse(u, HRmRead, i->Min.Div.srcR);
2054 return;
2055 case Min_Call: {
petarjb92a9542013-02-27 22:57:17 +00002056 /* Logic and comments copied/modified from x86, ppc and arm back end.
2057 First off, claim it trashes all the caller-saved regs
2058 which fall within the register allocator's jurisdiction. */
sewardj362cf842012-06-07 08:59:53 +00002059 if (i->Min.Call.cond != MIPScc_AL)
2060 addHRegUse(u, HRmRead, i->Min.Call.src);
2061 UInt argir;
2062 addHRegUse(u, HRmWrite, hregMIPS_GPR1(mode64));
2063
2064 addHRegUse(u, HRmWrite, hregMIPS_GPR2(mode64));
2065 addHRegUse(u, HRmWrite, hregMIPS_GPR3(mode64));
2066
2067 addHRegUse(u, HRmWrite, hregMIPS_GPR4(mode64));
2068 addHRegUse(u, HRmWrite, hregMIPS_GPR5(mode64));
2069 addHRegUse(u, HRmWrite, hregMIPS_GPR6(mode64));
2070 addHRegUse(u, HRmWrite, hregMIPS_GPR7(mode64));
2071
2072 addHRegUse(u, HRmWrite, hregMIPS_GPR8(mode64));
2073 addHRegUse(u, HRmWrite, hregMIPS_GPR9(mode64));
2074 addHRegUse(u, HRmWrite, hregMIPS_GPR10(mode64));
2075 addHRegUse(u, HRmWrite, hregMIPS_GPR11(mode64));
2076 addHRegUse(u, HRmWrite, hregMIPS_GPR12(mode64));
2077 addHRegUse(u, HRmWrite, hregMIPS_GPR13(mode64));
2078 addHRegUse(u, HRmWrite, hregMIPS_GPR14(mode64));
2079 addHRegUse(u, HRmWrite, hregMIPS_GPR15(mode64));
2080
2081 addHRegUse(u, HRmWrite, hregMIPS_GPR24(mode64));
2082 addHRegUse(u, HRmWrite, hregMIPS_GPR25(mode64));
petarjb92a9542013-02-27 22:57:17 +00002083 addHRegUse(u, HRmWrite, hregMIPS_GPR31(mode64));
sewardj362cf842012-06-07 08:59:53 +00002084
2085 /* Now we have to state any parameter-carrying registers
petarjb92a9542013-02-27 22:57:17 +00002086 which might be read. This depends on the argiregs field. */
sewardj362cf842012-06-07 08:59:53 +00002087 argir = i->Min.Call.argiregs;
petarjb92a9542013-02-27 22:57:17 +00002088 if (argir & (1<<11)) addHRegUse(u, HRmRead, hregMIPS_GPR11(mode64));
2089 if (argir & (1<<10)) addHRegUse(u, HRmRead, hregMIPS_GPR10(mode64));
2090 if (argir & (1<<9)) addHRegUse(u, HRmRead, hregMIPS_GPR9(mode64));
2091 if (argir & (1<<8)) addHRegUse(u, HRmRead, hregMIPS_GPR8(mode64));
2092 if (argir & (1<<7)) addHRegUse(u, HRmRead, hregMIPS_GPR7(mode64));
2093 if (argir & (1<<6)) addHRegUse(u, HRmRead, hregMIPS_GPR6(mode64));
2094 if (argir & (1<<5)) addHRegUse(u, HRmRead, hregMIPS_GPR5(mode64));
2095 if (argir & (1<<4)) addHRegUse(u, HRmRead, hregMIPS_GPR4(mode64));
sewardj362cf842012-06-07 08:59:53 +00002096
petarjb92a9542013-02-27 22:57:17 +00002097 vassert(0 == (argir & ~((1 << 4) | (1 << 5) | (1 << 6)
2098 | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)
2099 | (1 << 11))));
2100
sewardj362cf842012-06-07 08:59:53 +00002101 return;
2102 }
2103 /* XDirect/XIndir/XAssisted are also a bit subtle. They
2104 conditionally exit the block. Hence we only need to list (1)
2105 the registers that they read, and (2) the registers that they
2106 write in the case where the block is not exited. (2) is
2107 empty, hence only (1) is relevant here. */
2108 case Min_XDirect:
2109 addRegUsage_MIPSAMode(u, i->Min.XDirect.amPC);
2110 return;
2111 case Min_XIndir:
2112 addHRegUse(u, HRmRead, i->Min.XIndir.dstGA);
2113 addRegUsage_MIPSAMode(u, i->Min.XIndir.amPC);
2114 return;
2115 case Min_XAssisted:
2116 addHRegUse(u, HRmRead, i->Min.XAssisted.dstGA);
2117 addRegUsage_MIPSAMode(u, i->Min.XAssisted.amPC);
2118 return;
2119 case Min_Load:
2120 addRegUsage_MIPSAMode(u, i->Min.Load.src);
2121 addHRegUse(u, HRmWrite, i->Min.Load.dst);
2122 return;
2123 case Min_Store:
2124 addHRegUse(u, HRmRead, i->Min.Store.src);
2125 addRegUsage_MIPSAMode(u, i->Min.Store.dst);
2126 return;
2127 case Min_LoadL:
2128 addRegUsage_MIPSAMode(u, i->Min.LoadL.src);
2129 addHRegUse(u, HRmWrite, i->Min.LoadL.dst);
2130 return;
dejanj6ced72b2014-06-04 11:28:07 +00002131 case Min_Cas:
2132 addHRegUse(u, HRmWrite, i->Min.Cas.old);
2133 addHRegUse(u, HRmRead, i->Min.Cas.addr);
2134 addHRegUse(u, HRmRead, i->Min.Cas.expd);
2135 addHRegUse(u, HRmModify, i->Min.Cas.data);
2136 return;
sewardj362cf842012-06-07 08:59:53 +00002137 case Min_StoreC:
2138 addHRegUse(u, HRmWrite, i->Min.StoreC.src);
2139 addHRegUse(u, HRmRead, i->Min.StoreC.src);
2140 addRegUsage_MIPSAMode(u, i->Min.StoreC.dst);
2141 return;
2142 case Min_RdWrLR:
2143 addHRegUse(u, (i->Min.RdWrLR.wrLR ? HRmRead : HRmWrite),
2144 i->Min.RdWrLR.gpr);
2145 return;
2146 case Min_FpLdSt:
2147 if (i->Min.FpLdSt.sz == 4) {
2148 addHRegUse(u, (i->Min.FpLdSt.isLoad ? HRmWrite : HRmRead),
2149 i->Min.FpLdSt.reg);
2150 addRegUsage_MIPSAMode(u, i->Min.FpLdSt.addr);
2151 return;
2152 } else if (i->Min.FpLdSt.sz == 8) {
petarj1ec43e02012-09-04 13:45:42 +00002153 addHRegUse(u, (i->Min.FpLdSt.isLoad ? HRmWrite : HRmRead),
2154 i->Min.FpLdSt.reg);
2155 addRegUsage_MIPSAMode(u, i->Min.FpLdSt.addr);
sewardj362cf842012-06-07 08:59:53 +00002156 return;
2157 }
2158 break;
2159 case Min_FpUnary:
petarjb92a9542013-02-27 22:57:17 +00002160 addHRegUse(u, HRmWrite, i->Min.FpUnary.dst);
2161 addHRegUse(u, HRmRead, i->Min.FpUnary.src);
2162 return;
sewardj362cf842012-06-07 08:59:53 +00002163 case Min_FpBinary:
2164 addHRegUse(u, HRmWrite, i->Min.FpBinary.dst);
2165 addHRegUse(u, HRmRead, i->Min.FpBinary.srcL);
2166 addHRegUse(u, HRmRead, i->Min.FpBinary.srcR);
2167 return;
petarjb92a9542013-02-27 22:57:17 +00002168 case Min_FpTernary:
2169 addHRegUse(u, HRmWrite, i->Min.FpTernary.dst);
2170 addHRegUse(u, HRmRead, i->Min.FpTernary.src1);
2171 addHRegUse(u, HRmRead, i->Min.FpTernary.src2);
2172 addHRegUse(u, HRmRead, i->Min.FpTernary.src3);
2173 return;
sewardj362cf842012-06-07 08:59:53 +00002174 case Min_FpConvert:
2175 addHRegUse(u, HRmWrite, i->Min.FpConvert.dst);
2176 addHRegUse(u, HRmRead, i->Min.FpConvert.src);
2177 return;
2178 case Min_FpCompare:
2179 addHRegUse(u, HRmWrite, i->Min.FpCompare.dst);
2180 addHRegUse(u, HRmRead, i->Min.FpCompare.srcL);
2181 addHRegUse(u, HRmRead, i->Min.FpCompare.srcR);
2182 return;
petarjb92a9542013-02-27 22:57:17 +00002183 case Min_FpGpMove:
2184 addHRegUse(u, HRmWrite, i->Min.FpGpMove.dst);
2185 addHRegUse(u, HRmRead, i->Min.FpGpMove.src);
2186 return;
2187 case Min_MoveCond:
dejanj781f1bd2013-10-23 14:05:15 +00002188 addHRegUse(u, HRmModify, i->Min.MoveCond.dst);
petarjb92a9542013-02-27 22:57:17 +00002189 addHRegUse(u, HRmRead, i->Min.MoveCond.src);
2190 addHRegUse(u, HRmRead, i->Min.MoveCond.cond);
sewardj362cf842012-06-07 08:59:53 +00002191 return;
2192 case Min_EvCheck:
2193 /* We expect both amodes only to mention %ebp, so this is in
2194 fact pointless, since %ebp isn't allocatable, but anyway.. */
2195 addRegUsage_MIPSAMode(u, i->Min.EvCheck.amCounter);
2196 addRegUsage_MIPSAMode(u, i->Min.EvCheck.amFailAddr);
2197 return;
2198 case Min_ProfInc:
2199 /* does not use any registers. */
2200 return;
2201 default:
2202 ppMIPSInstr(i, mode64);
2203 vpanic("getRegUsage_MIPSInstr");
2204 break;
2205 }
2206}
2207
2208/* local helper */
2209static void mapReg(HRegRemap * m, HReg * r)
2210{
2211 *r = lookupHRegRemap(m, *r);
2212}
2213
2214void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64)
2215{
2216 switch (i->tag) {
2217 case Min_LI:
2218 mapReg(m, &i->Min.LI.dst);
2219 break;
2220 case Min_Alu:
2221 mapReg(m, &i->Min.Alu.srcL);
2222 mapRegs_MIPSRH(m, i->Min.Alu.srcR);
2223 mapReg(m, &i->Min.Alu.dst);
2224 return;
2225 case Min_Shft:
2226 mapReg(m, &i->Min.Shft.srcL);
2227 mapRegs_MIPSRH(m, i->Min.Shft.srcR);
2228 mapReg(m, &i->Min.Shft.dst);
2229 return;
2230 case Min_Cmp:
2231 mapReg(m, &i->Min.Cmp.srcL);
2232 mapReg(m, &i->Min.Cmp.srcR);
2233 mapReg(m, &i->Min.Cmp.dst);
2234 return;
2235 case Min_Unary:
2236 mapReg(m, &i->Min.Unary.src);
2237 mapReg(m, &i->Min.Unary.dst);
2238 return;
2239 case Min_Mul:
2240 mapReg(m, &i->Min.Mul.dst);
2241 mapReg(m, &i->Min.Mul.srcL);
2242 mapReg(m, &i->Min.Mul.srcR);
2243 return;
2244 case Min_Mthi:
2245 case Min_Mtlo:
2246 mapReg(m, &i->Min.MtHL.src);
2247 return;
2248 case Min_Mfhi:
2249 case Min_Mflo:
2250 mapReg(m, &i->Min.MfHL.dst);
2251 return;
2252 case Min_Macc:
2253 mapReg(m, &i->Min.Macc.srcL);
2254 mapReg(m, &i->Min.Macc.srcR);
2255 return;
2256 case Min_Div:
2257 mapReg(m, &i->Min.Div.srcL);
2258 mapReg(m, &i->Min.Div.srcR);
2259 return;
2260 case Min_Call:
2261 {
2262 if (i->Min.Call.cond != MIPScc_AL)
2263 mapReg(m, &i->Min.Call.src);
2264 return;
2265 }
2266 case Min_XDirect:
2267 mapRegs_MIPSAMode(m, i->Min.XDirect.amPC);
2268 return;
2269 case Min_XIndir:
2270 mapReg(m, &i->Min.XIndir.dstGA);
2271 mapRegs_MIPSAMode(m, i->Min.XIndir.amPC);
2272 return;
2273 case Min_XAssisted:
2274 mapReg(m, &i->Min.XAssisted.dstGA);
2275 mapRegs_MIPSAMode(m, i->Min.XAssisted.amPC);
2276 return;
2277 case Min_Load:
2278 mapRegs_MIPSAMode(m, i->Min.Load.src);
2279 mapReg(m, &i->Min.Load.dst);
2280 return;
2281 case Min_Store:
2282 mapReg(m, &i->Min.Store.src);
2283 mapRegs_MIPSAMode(m, i->Min.Store.dst);
2284 return;
2285 case Min_LoadL:
2286 mapRegs_MIPSAMode(m, i->Min.LoadL.src);
2287 mapReg(m, &i->Min.LoadL.dst);
2288 return;
dejanj6ced72b2014-06-04 11:28:07 +00002289 case Min_Cas:
2290 mapReg(m, &i->Min.Cas.old);
2291 mapReg(m, &i->Min.Cas.addr);
2292 mapReg(m, &i->Min.Cas.expd);
2293 mapReg(m, &i->Min.Cas.data);
2294 return;
sewardj362cf842012-06-07 08:59:53 +00002295 case Min_StoreC:
2296 mapReg(m, &i->Min.StoreC.src);
2297 mapRegs_MIPSAMode(m, i->Min.StoreC.dst);
2298 return;
2299 case Min_RdWrLR:
2300 mapReg(m, &i->Min.RdWrLR.gpr);
2301 return;
2302 case Min_FpLdSt:
2303 if (i->Min.FpLdSt.sz == 4) {
2304 mapReg(m, &i->Min.FpLdSt.reg);
2305 mapRegs_MIPSAMode(m, i->Min.FpLdSt.addr);
2306 return;
2307 } else if (i->Min.FpLdSt.sz == 8) {
petarj1ec43e02012-09-04 13:45:42 +00002308 mapReg(m, &i->Min.FpLdSt.reg);
2309 mapRegs_MIPSAMode(m, i->Min.FpLdSt.addr);
sewardj362cf842012-06-07 08:59:53 +00002310 return;
2311 }
2312 break;
2313 case Min_FpUnary:
petarjb92a9542013-02-27 22:57:17 +00002314 mapReg(m, &i->Min.FpUnary.dst);
2315 mapReg(m, &i->Min.FpUnary.src);
2316 return;
sewardj362cf842012-06-07 08:59:53 +00002317 case Min_FpBinary:
2318 mapReg(m, &i->Min.FpBinary.dst);
2319 mapReg(m, &i->Min.FpBinary.srcL);
2320 mapReg(m, &i->Min.FpBinary.srcR);
2321 return;
petarjb92a9542013-02-27 22:57:17 +00002322 case Min_FpTernary:
2323 mapReg(m, &i->Min.FpTernary.dst);
2324 mapReg(m, &i->Min.FpTernary.src1);
2325 mapReg(m, &i->Min.FpTernary.src2);
2326 mapReg(m, &i->Min.FpTernary.src3);
2327 return;
sewardj362cf842012-06-07 08:59:53 +00002328 case Min_FpConvert:
2329 mapReg(m, &i->Min.FpConvert.dst);
2330 mapReg(m, &i->Min.FpConvert.src);
2331 return;
2332 case Min_FpCompare:
2333 mapReg(m, &i->Min.FpCompare.dst);
2334 mapReg(m, &i->Min.FpCompare.srcL);
2335 mapReg(m, &i->Min.FpCompare.srcR);
2336 return;
2337 case Min_MtFCSR:
2338 mapReg(m, &i->Min.MtFCSR.src);
2339 return;
2340 case Min_MfFCSR:
2341 mapReg(m, &i->Min.MfFCSR.dst);
2342 return;
petarjb92a9542013-02-27 22:57:17 +00002343 case Min_FpGpMove:
2344 mapReg(m, &i->Min.FpGpMove.dst);
2345 mapReg(m, &i->Min.FpGpMove.src);
2346 return;
2347 case Min_MoveCond:
2348 mapReg(m, &i->Min.MoveCond.dst);
2349 mapReg(m, &i->Min.MoveCond.src);
2350 mapReg(m, &i->Min.MoveCond.cond);
sewardj362cf842012-06-07 08:59:53 +00002351 return;
2352 case Min_EvCheck:
2353 /* We expect both amodes only to mention %ebp, so this is in
2354 fact pointless, since %ebp isn't allocatable, but anyway.. */
2355 mapRegs_MIPSAMode(m, i->Min.EvCheck.amCounter);
2356 mapRegs_MIPSAMode(m, i->Min.EvCheck.amFailAddr);
2357 return;
2358 case Min_ProfInc:
2359 /* does not use any registers. */
2360 return;
2361 default:
2362 ppMIPSInstr(i, mode64);
2363 vpanic("mapRegs_MIPSInstr");
2364 break;
2365 }
2366
2367}
2368
2369/* Figure out if i represents a reg-reg move, and if so assign the
2370 source and destination to *src and *dst. If in doubt say No. Used
dejanjc3fee0d2013-07-25 09:08:03 +00002371 by the register allocator to do move coalescing.
sewardj362cf842012-06-07 08:59:53 +00002372*/
floriand8c64e02014-10-08 08:54:44 +00002373Bool isMove_MIPSInstr(const MIPSInstr * i, HReg * src, HReg * dst)
sewardj362cf842012-06-07 08:59:53 +00002374{
2375 /* Moves between integer regs */
2376 if (i->tag == Min_Alu) {
petarjb92a9542013-02-27 22:57:17 +00002377 /* or Rd,Rs,Rs == mr Rd,Rs */
sewardj362cf842012-06-07 08:59:53 +00002378 if (i->Min.Alu.op != Malu_OR)
2379 return False;
2380 if (i->Min.Alu.srcR->tag != Mrh_Reg)
2381 return False;
dejanjc3fee0d2013-07-25 09:08:03 +00002382 if (hregNumber(i->Min.Alu.srcR->Mrh.Reg.reg)
petarja81d9be2013-01-30 18:06:26 +00002383 != hregNumber(i->Min.Alu.srcL))
sewardj362cf842012-06-07 08:59:53 +00002384 return False;
2385 *src = i->Min.Alu.srcL;
2386 *dst = i->Min.Alu.dst;
2387 return True;
2388 }
2389 return False;
2390}
2391
2392/* Generate mips spill/reload instructions under the direction of the
petarjb92a9542013-02-27 22:57:17 +00002393 register allocator. */
sewardj362cf842012-06-07 08:59:53 +00002394void genSpill_MIPS( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
2395 Int offsetB, Bool mode64)
2396{
2397 MIPSAMode *am;
2398 vassert(offsetB >= 0);
2399 vassert(!hregIsVirtual(rreg));
2400 *i1 = *i2 = NULL;
2401 am = MIPSAMode_IR(offsetB, GuestStatePointer(mode64));
2402
2403 switch (hregClass(rreg)) {
2404 case HRcInt64:
2405 vassert(mode64);
2406 *i1 = MIPSInstr_Store(8, am, rreg, mode64);
2407 break;
2408 case HRcInt32:
2409 vassert(!mode64);
2410 *i1 = MIPSInstr_Store(4, am, rreg, mode64);
2411 break;
2412 case HRcFlt32:
2413 vassert(!mode64);
2414 *i1 = MIPSInstr_FpLdSt(False /*Store */ , 4, rreg, am);
2415 break;
2416 case HRcFlt64:
2417 *i1 = MIPSInstr_FpLdSt(False /*Store */ , 8, rreg, am);
2418 break;
2419 default:
2420 ppHRegClass(hregClass(rreg));
2421 vpanic("genSpill_MIPS: unimplemented regclass");
2422 break;
2423 }
2424}
2425
2426void genReload_MIPS( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
2427 Int offsetB, Bool mode64)
2428{
2429 MIPSAMode *am;
2430 vassert(!hregIsVirtual(rreg));
2431 am = MIPSAMode_IR(offsetB, GuestStatePointer(mode64));
2432
2433 switch (hregClass(rreg)) {
2434 case HRcInt64:
2435 vassert(mode64);
2436 *i1 = MIPSInstr_Load(8, rreg, am, mode64);
2437 break;
2438 case HRcInt32:
2439 vassert(!mode64);
2440 *i1 = MIPSInstr_Load(4, rreg, am, mode64);
2441 break;
2442 case HRcFlt32:
2443 if (mode64)
2444 *i1 = MIPSInstr_FpLdSt(True /*Load */ , 8, rreg, am);
2445 else
2446 *i1 = MIPSInstr_FpLdSt(True /*Load */ , 4, rreg, am);
2447 break;
2448 case HRcFlt64:
2449 *i1 = MIPSInstr_FpLdSt(True /*Load */ , 8, rreg, am);
2450 break;
2451 default:
2452 ppHRegClass(hregClass(rreg));
2453 vpanic("genReload_MIPS: unimplemented regclass");
2454 break;
2455 }
2456}
2457
2458/* --------- The mips assembler --------- */
2459
2460static UInt iregNo(HReg r, Bool mode64)
2461{
2462 UInt n;
petarj4b5abc22013-01-20 23:13:14 +00002463 vassert(hregClass(r) == (mode64 ? HRcInt64 : HRcInt32));
sewardj362cf842012-06-07 08:59:53 +00002464 vassert(!hregIsVirtual(r));
2465 n = hregNumber(r);
2466 vassert(n <= 32);
2467 return n;
2468}
2469
2470static UChar fregNo(HReg r, Bool mode64)
2471{
2472 UInt n;
sewardj362cf842012-06-07 08:59:53 +00002473 vassert(!hregIsVirtual(r));
2474 n = hregNumber(r);
2475 vassert(n <= 31);
2476 return n;
2477}
2478
2479static UChar dregNo(HReg r)
2480{
2481 UInt n;
sewardj362cf842012-06-07 08:59:53 +00002482 vassert(!hregIsVirtual(r));
2483 n = hregNumber(r);
2484 vassert(n <= 31);
2485 return n;
2486}
2487
2488/* Emit 32bit instruction */
2489static UChar *emit32(UChar * p, UInt w32)
2490{
2491#if defined (_MIPSEL)
2492 *p++ = toUChar(w32 & 0x000000FF);
2493 *p++ = toUChar((w32 >> 8) & 0x000000FF);
2494 *p++ = toUChar((w32 >> 16) & 0x000000FF);
2495 *p++ = toUChar((w32 >> 24) & 0x000000FF);
2496#elif defined (_MIPSEB)
2497 *p++ = toUChar((w32 >> 24) & 0x000000FF);
2498 *p++ = toUChar((w32 >> 16) & 0x000000FF);
2499 *p++ = toUChar((w32 >> 8) & 0x000000FF);
2500 *p++ = toUChar(w32 & 0x000000FF);
2501#endif
2502 return p;
2503}
2504/* Fetch an instruction */
2505static UInt fetch32 ( UChar* p )
2506{
2507 UInt w32 = 0;
2508#if defined (_MIPSEL)
2509 w32 |= ((0xFF & (UInt)p[0]) << 0);
2510 w32 |= ((0xFF & (UInt)p[1]) << 8);
2511 w32 |= ((0xFF & (UInt)p[2]) << 16);
2512 w32 |= ((0xFF & (UInt)p[3]) << 24);
2513#elif defined (_MIPSEB)
2514 w32 |= ((0xFF & (UInt)p[0]) << 24);
2515 w32 |= ((0xFF & (UInt)p[1]) << 16);
2516 w32 |= ((0xFF & (UInt)p[2]) << 8);
2517 w32 |= ((0xFF & (UInt)p[3]) << 0);
2518#endif
2519 return w32;
2520}
2521
2522/* physical structure of mips instructions */
dejanjc3fee0d2013-07-25 09:08:03 +00002523/* type I : opcode - 6 bits
sewardj362cf842012-06-07 08:59:53 +00002524 rs - 5 bits
2525 rt - 5 bits
2526 immediate - 16 bits
2527*/
2528static UChar *mkFormI(UChar * p, UInt opc, UInt rs, UInt rt, UInt imm)
2529{
2530 UInt theInstr;
2531 vassert(opc < 0x40);
2532 vassert(rs < 0x20);
2533 vassert(rt < 0x20);
2534 imm = imm & 0xFFFF;
2535 theInstr = ((opc << 26) | (rs << 21) | (rt << 16) | (imm));
2536 return emit32(p, theInstr);
2537}
2538
2539/* type R: opcode - 6 bits
2540 rs - 5 bits
2541 rt - 5 bits
2542 rd - 5 bits
2543 sa - 5 bits
2544 func - 6 bits
2545*/
2546static UChar *mkFormR(UChar * p, UInt opc, UInt rs, UInt rt, UInt rd, UInt sa,
2547 UInt func)
2548{
2549 if (rs >= 0x20)
2550 vex_printf("rs = %d\n", rs);
2551 UInt theInstr;
2552 vassert(opc < 0x40);
2553 vassert(rs < 0x20);
2554 vassert(rt < 0x20);
2555 vassert(rd < 0x20);
2556 vassert(sa < 0x20);
2557 func = func & 0xFFFF;
2558 theInstr = ((opc << 26) | (rs << 21) | (rt << 16) | (rd << 11) | (sa << 6) |
2559 (func));
2560
2561 return emit32(p, theInstr);
2562}
2563
2564static UChar *mkFormS(UChar * p, UInt opc1, UInt rRD, UInt rRS, UInt rRT,
2565 UInt sa, UInt opc2)
2566{
2567 UInt theInstr;
2568 vassert(opc1 <= 0x3F);
2569 vassert(rRD < 0x20);
2570 vassert(rRS < 0x20);
2571 vassert(rRT < 0x20);
2572 vassert(opc2 <= 0x3F);
2573 vassert(sa >= 0 && sa <= 0x3F);
2574
2575 theInstr = ((opc1 << 26) | (rRS << 21) | (rRT << 16) | (rRD << 11) |
2576 ((sa & 0x1F) << 6) | (opc2));
2577
2578 return emit32(p, theInstr);
2579}
2580
2581static UChar *doAMode_IR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am,
2582 Bool mode64)
2583{
2584 UInt rA, idx, r_dst;
2585 vassert(am->tag == Mam_IR);
2586 vassert(am->Mam.IR.index < 0x10000);
2587
2588 rA = iregNo(am->Mam.IR.base, mode64);
2589 idx = am->Mam.IR.index;
2590
2591 if (rSD == 33 || rSD == 34)
2592 r_dst = 24;
2593 else
2594 r_dst = rSD;
2595
2596 if (opc1 < 40) {
petarjb92a9542013-02-27 22:57:17 +00002597 /* load */
sewardj362cf842012-06-07 08:59:53 +00002598 if (rSD == 33)
2599 /* mfhi */
2600 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2601 else if (rSD == 34)
2602 /* mflo */
2603 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2604 }
2605
2606 p = mkFormI(p, opc1, rA, r_dst, idx);
2607
2608 if (opc1 >= 40) {
petarjb92a9542013-02-27 22:57:17 +00002609 /* store */
sewardj362cf842012-06-07 08:59:53 +00002610 if (rSD == 33)
2611 /* mthi */
2612 p = mkFormR(p, 0, r_dst, 0, 0, 0, 17);
2613 else if (rSD == 34)
2614 /* mtlo */
2615 p = mkFormR(p, 0, r_dst, 0, 0, 0, 19);
2616 }
2617
2618 return p;
2619}
2620
2621static UChar *doAMode_RR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am,
2622 Bool mode64)
2623{
2624 UInt rA, rB, r_dst;
2625 vassert(am->tag == Mam_RR);
2626
2627 rA = iregNo(am->Mam.RR.base, mode64);
2628 rB = iregNo(am->Mam.RR.index, mode64);
2629
2630 if (rSD == 33 || rSD == 34)
2631 r_dst = 24;
2632 else
2633 r_dst = rSD;
2634
2635 if (opc1 < 40) {
petarjb92a9542013-02-27 22:57:17 +00002636 /* load */
sewardj362cf842012-06-07 08:59:53 +00002637 if (rSD == 33)
2638 /* mfhi */
2639 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2640 else if (rSD == 34)
2641 /* mflo */
2642 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2643 }
petarjb92a9542013-02-27 22:57:17 +00002644
sewardj362cf842012-06-07 08:59:53 +00002645 if (mode64) {
dejanja759d172013-09-19 13:35:45 +00002646 /* daddu rA, rA, rB$
2647 sd/ld r_dst, 0(rA)$
2648 dsubu rA, rA, rB */
sewardj362cf842012-06-07 08:59:53 +00002649 p = mkFormR(p, 0, rA, rB, rA, 0, 45);
2650 p = mkFormI(p, opc1, rA, r_dst, 0);
dejanja759d172013-09-19 13:35:45 +00002651 p = mkFormR(p, 0, rA, rB, rA, 0, 47);
sewardj362cf842012-06-07 08:59:53 +00002652 } else {
dejanja759d172013-09-19 13:35:45 +00002653 /* addu rA, rA, rB
2654 sw/lw r_dst, 0(rA)
2655 subu rA, rA, rB */
sewardj362cf842012-06-07 08:59:53 +00002656 p = mkFormR(p, 0, rA, rB, rA, 0, 33);
2657 p = mkFormI(p, opc1, rA, r_dst, 0);
dejanja759d172013-09-19 13:35:45 +00002658 p = mkFormR(p, 0, rA, rB, rA, 0, 35);
sewardj362cf842012-06-07 08:59:53 +00002659 }
2660 if (opc1 >= 40) {
petarjb92a9542013-02-27 22:57:17 +00002661 /* store */
sewardj362cf842012-06-07 08:59:53 +00002662 if (rSD == 33)
2663 /* mthi */
2664 p = mkFormR(p, 0, r_dst, 0, 0, 0, 17);
2665 else if (rSD == 34)
2666 /* mtlo */
2667 p = mkFormR(p, 0, r_dst, 0, 0, 0, 19);
2668 }
2669
2670 return p;
2671}
2672
2673/* Load imm to r_dst */
2674static UChar *mkLoadImm(UChar * p, UInt r_dst, ULong imm, Bool mode64)
2675{
2676 if (!mode64) {
2677 vassert(r_dst < 0x20);
2678 UInt u32 = (UInt) imm;
2679 Int s32 = (Int) u32;
2680 Long s64 = (Long) s32;
2681 imm = (ULong) s64;
2682 }
2683
2684 if (imm >= 0xFFFFFFFFFFFF8000ULL || imm < 0x8000) {
petarjb92a9542013-02-27 22:57:17 +00002685 /* sign-extendable from 16 bits
2686 addiu r_dst, 0, imm => li r_dst, imm */
sewardj362cf842012-06-07 08:59:53 +00002687 p = mkFormI(p, 9, 0, r_dst, imm & 0xFFFF);
2688 } else {
2689 if (imm >= 0xFFFFFFFF80000000ULL || imm < 0x80000000ULL) {
petarjb92a9542013-02-27 22:57:17 +00002690 /* sign-extendable from 32 bits
2691 addiu r_dst, r0, (imm >> 16) => lis r_dst, (imm >> 16)
2692 lui r_dst, (imm >> 16) */
sewardj362cf842012-06-07 08:59:53 +00002693 p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
petarjb92a9542013-02-27 22:57:17 +00002694 /* ori r_dst, r_dst, (imm & 0xFFFF) */
sewardj362cf842012-06-07 08:59:53 +00002695 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2696 } else {
2697 vassert(mode64);
petarjb92a9542013-02-27 22:57:17 +00002698 /* lui load in upper half of low word */
sewardj362cf842012-06-07 08:59:53 +00002699 p = mkFormI(p, 15, 0, r_dst, (imm >> 48) & 0xFFFF);
petarjb92a9542013-02-27 22:57:17 +00002700 /* ori */
sewardj362cf842012-06-07 08:59:53 +00002701 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 32) & 0xFFFF);
petarjb92a9542013-02-27 22:57:17 +00002702 /* shift */
sewardj362cf842012-06-07 08:59:53 +00002703 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
petarjb92a9542013-02-27 22:57:17 +00002704 /* ori */
sewardj362cf842012-06-07 08:59:53 +00002705 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 16) & 0xFFFF);
petarjb92a9542013-02-27 22:57:17 +00002706 /* shift */
sewardj362cf842012-06-07 08:59:53 +00002707 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
petarjb92a9542013-02-27 22:57:17 +00002708 /* ori */
sewardj362cf842012-06-07 08:59:53 +00002709 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2710 }
2711 }
2712 return p;
2713}
2714
petarjb92a9542013-02-27 22:57:17 +00002715/* A simplified version of mkLoadImm that always generates 2 or 6
sewardj362cf842012-06-07 08:59:53 +00002716 instructions (32 or 64 bits respectively) even if it could generate
2717 fewer. This is needed for generating fixed sized patchable
2718 sequences. */
petarjb92a9542013-02-27 22:57:17 +00002719static UChar* mkLoadImm_EXACTLY2or6 ( UChar* p,
2720 UInt r_dst, ULong imm, Bool mode64)
sewardj362cf842012-06-07 08:59:53 +00002721{
2722 vassert(r_dst < 0x20);
2723
2724 if (!mode64) {
2725 /* In 32-bit mode, make sure the top 32 bits of imm are a sign
petarjb92a9542013-02-27 22:57:17 +00002726 extension of the bottom 32 bits. (Probably unnecessary.) */
sewardj362cf842012-06-07 08:59:53 +00002727 UInt u32 = (UInt)imm;
2728 Int s32 = (Int)u32;
2729 Long s64 = (Long)s32;
2730 imm = (ULong)s64;
2731 }
2732
2733 if (!mode64) {
petarjb92a9542013-02-27 22:57:17 +00002734 /* sign-extendable from 32 bits
2735 addiu r_dst, r0, (imm >> 16) => lis r_dst, (imm >> 16)
2736 lui r_dst, (imm >> 16) */
sewardj362cf842012-06-07 08:59:53 +00002737 p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
petarjb92a9542013-02-27 22:57:17 +00002738 /* ori r_dst, r_dst, (imm & 0xFFFF) */
sewardj362cf842012-06-07 08:59:53 +00002739 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2740 } else {
petarjb92a9542013-02-27 22:57:17 +00002741 /* full 64bit immediate load: 6 (six!) insns. */
2742 vassert(mode64);
2743 /* lui load in upper half of low word */
2744 p = mkFormI(p, 15, 0, r_dst, (imm >> 48) & 0xFFFF);
2745 /* ori */
2746 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 32) & 0xFFFF);
2747 /* shift */
2748 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2749 /* ori */
2750 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 16) & 0xFFFF);
2751 /* shift */
2752 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2753 /* ori */
2754 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
sewardj362cf842012-06-07 08:59:53 +00002755 }
2756 return p;
2757}
2758
2759/* Checks whether the sequence of bytes at p was indeed created
petarjb92a9542013-02-27 22:57:17 +00002760 by mkLoadImm_EXACTLY2or6 with the given parameters. */
2761static Bool isLoadImm_EXACTLY2or6 ( UChar* p_to_check,
sewardj362cf842012-06-07 08:59:53 +00002762 UInt r_dst, ULong imm, Bool mode64 )
2763{
2764 vassert(r_dst < 0x20);
2765 Bool ret;
2766 if (!mode64) {
2767 /* In 32-bit mode, make sure the top 32 bits of imm are a sign
2768 extension of the bottom 32 bits. (Probably unnecessary.) */
2769 UInt u32 = (UInt)imm;
2770 Int s32 = (Int)u32;
2771 Long s64 = (Long)s32;
2772 imm = (ULong)s64;
2773 }
2774
2775 if (!mode64) {
2776 UInt expect[2] = { 0, 0 };
2777 UChar* p = (UChar*)&expect[0];
petarjb92a9542013-02-27 22:57:17 +00002778 /* lui r_dst, (immi >> 16) */
sewardj362cf842012-06-07 08:59:53 +00002779 p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
petarjb92a9542013-02-27 22:57:17 +00002780 /* ori r_dst, r_dst, (imm & 0xFFFF) */
sewardj362cf842012-06-07 08:59:53 +00002781 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2782 vassert(p == (UChar*)&expect[2]);
2783
2784 ret = fetch32(p_to_check + 0) == expect[0]
petarjb92a9542013-02-27 22:57:17 +00002785 && fetch32(p_to_check + 4) == expect[1];
sewardj362cf842012-06-07 08:59:53 +00002786 } else {
petarjb92a9542013-02-27 22:57:17 +00002787 UInt expect[6] = { 0, 0, 0, 0, 0, 0};
2788 UChar* p = (UChar*)&expect[0];
2789 /* lui load in upper half of low word */
2790 p = mkFormI(p, 15, 0, r_dst, (imm >> 48) & 0xFFFF);
2791 /* ori */
2792 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 32) & 0xFFFF);
2793 /* shift */
2794 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2795 /* ori */
2796 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 16) & 0xFFFF);
2797 /* shift */
2798 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2799 /* ori */
2800 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2801 vassert(p == (UChar*)&expect[6]);
2802
2803 ret = fetch32(p_to_check + 0) == expect[0]
2804 && fetch32(p_to_check + 4) == expect[1]
2805 && fetch32(p_to_check + 8) == expect[2]
2806 && fetch32(p_to_check + 12) == expect[3]
2807 && fetch32(p_to_check + 16) == expect[4]
2808 && fetch32(p_to_check + 20) == expect[5];
sewardj362cf842012-06-07 08:59:53 +00002809 }
2810 return ret;
2811}
2812
petarj0c30de82013-04-19 12:35:00 +00002813/* Generate a machine-word sized load or store. Simplified version of
2814 the Min_Load and Min_Store cases below.
2815 This will generate 32-bit load/store on MIPS32, and 64-bit load/store on
2816 MIPS64 platforms.
2817*/
2818static UChar* do_load_or_store_machine_word ( UChar* p, Bool isLoad, UInt reg,
2819 MIPSAMode* am, Bool mode64 )
sewardj362cf842012-06-07 08:59:53 +00002820{
2821 if (isLoad) { /* load */
sewardj362cf842012-06-07 08:59:53 +00002822 switch (am->tag) {
2823 case Mam_IR:
2824 if (mode64) {
2825 vassert(0 == (am->Mam.IR.index & 3));
2826 }
petarj4b5abc22013-01-20 23:13:14 +00002827 p = doAMode_IR(p, mode64 ? 55 : 35, reg, am, mode64);
sewardj362cf842012-06-07 08:59:53 +00002828 break;
2829 case Mam_RR:
2830 /* we could handle this case, but we don't expect to ever
2831 need to. */
2832 vassert(0);
2833 break;
2834 default:
2835 vassert(0);
2836 break;
2837 }
2838 } else /* store */ {
sewardj362cf842012-06-07 08:59:53 +00002839 switch (am->tag) {
2840 case Mam_IR:
2841 if (mode64) {
2842 vassert(0 == (am->Mam.IR.index & 3));
2843 }
petarj4b5abc22013-01-20 23:13:14 +00002844 p = doAMode_IR(p, mode64 ? 63 : 43, reg, am, mode64);
sewardj362cf842012-06-07 08:59:53 +00002845 break;
2846 case Mam_RR:
2847 /* we could handle this case, but we don't expect to ever
2848 need to. */
2849 vassert(0);
2850 break;
2851 default:
2852 vassert(0);
2853 break;
2854 }
2855 }
2856 return p;
2857}
2858
petarj0c30de82013-04-19 12:35:00 +00002859/* Generate a 32-bit sized load or store. Simplified version of
2860 do_load_or_store_machine_word above. */
2861static UChar* do_load_or_store_word32 ( UChar* p, Bool isLoad, UInt reg,
2862 MIPSAMode* am, Bool mode64 )
2863{
2864 if (isLoad) { /* load */
2865 switch (am->tag) {
2866 case Mam_IR:
2867 if (mode64) {
2868 vassert(0 == (am->Mam.IR.index & 3));
2869 }
2870 p = doAMode_IR(p, 35, reg, am, mode64);
2871 break;
2872 case Mam_RR:
2873 /* we could handle this case, but we don't expect to ever
2874 need to. */
2875 vassert(0);
2876 break;
2877 default:
2878 vassert(0);
2879 break;
2880 }
2881 } else /* store */ {
2882 switch (am->tag) {
2883 case Mam_IR:
2884 if (mode64) {
2885 vassert(0 == (am->Mam.IR.index & 3));
2886 }
2887 p = doAMode_IR(p, 43, reg, am, mode64);
2888 break;
2889 case Mam_RR:
2890 /* we could handle this case, but we don't expect to ever
2891 need to. */
2892 vassert(0);
2893 break;
2894 default:
2895 vassert(0);
2896 break;
2897 }
2898 }
2899 return p;
2900}
2901
sewardj362cf842012-06-07 08:59:53 +00002902/* Move r_dst to r_src */
2903static UChar *mkMoveReg(UChar * p, UInt r_dst, UInt r_src)
2904{
2905 vassert(r_dst < 0x20);
2906 vassert(r_src < 0x20);
2907
2908 if (r_dst != r_src) {
2909 /* or r_dst, r_src, r_src */
2910 p = mkFormR(p, 0, r_src, r_src, r_dst, 0, 37);
2911 }
2912 return p;
2913}
2914
2915/* Emit an instruction into buf and return the number of bytes used.
2916 Note that buf is not the insn's final place, and therefore it is
2917 imperative to emit position-independent code. If the emitted
2918 instruction was a profiler inc, set *is_profInc to True, else
2919 leave it unchanged. */
2920Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc,
floriand8c64e02014-10-08 08:54:44 +00002921 UChar* buf, Int nbuf, const MIPSInstr* i,
sewardj362cf842012-06-07 08:59:53 +00002922 Bool mode64,
sewardj9b769162014-07-24 12:42:03 +00002923 VexEndness endness_host,
florian8462d112014-09-24 15:18:09 +00002924 const void* disp_cp_chain_me_to_slowEP,
2925 const void* disp_cp_chain_me_to_fastEP,
2926 const void* disp_cp_xindir,
2927 const void* disp_cp_xassisted )
sewardj362cf842012-06-07 08:59:53 +00002928{
2929 UChar *p = &buf[0];
2930 UChar *ptmp = p;
2931 vassert(nbuf >= 32);
2932
2933 switch (i->tag) {
sewardj362cf842012-06-07 08:59:53 +00002934 case Min_LI:
2935 p = mkLoadImm(p, iregNo(i->Min.LI.dst, mode64), i->Min.LI.imm, mode64);
2936 goto done;
petarjb92a9542013-02-27 22:57:17 +00002937
sewardj362cf842012-06-07 08:59:53 +00002938 case Min_Alu: {
2939 MIPSRH *srcR = i->Min.Alu.srcR;
2940 Bool immR = toBool(srcR->tag == Mrh_Imm);
2941 UInt r_dst = iregNo(i->Min.Alu.dst, mode64);
2942 UInt r_srcL = iregNo(i->Min.Alu.srcL, mode64);
petarjb92a9542013-02-27 22:57:17 +00002943 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->Mrh.Reg.reg,
2944 mode64);
sewardj362cf842012-06-07 08:59:53 +00002945 switch (i->Min.Alu.op) {
petarjb92a9542013-02-27 22:57:17 +00002946 /* Malu_ADD, Malu_SUB, Malu_AND, Malu_OR, Malu_NOR, Malu_XOR, Malu_SLT */
sewardj362cf842012-06-07 08:59:53 +00002947 case Malu_ADD:
2948 if (immR) {
2949 vassert(srcR->Mrh.Imm.imm16 != 0x8000);
2950 if (srcR->Mrh.Imm.syned)
2951 /* addi */
2952 p = mkFormI(p, 9, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2953 else
2954 /* addiu */
2955 p = mkFormI(p, 9, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2956 } else {
2957 /* addu */
2958 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 33);
2959 }
2960 break;
2961 case Malu_SUB:
2962 if (immR) {
2963 /* addi , but with negated imm */
2964 vassert(srcR->Mrh.Imm.syned);
2965 vassert(srcR->Mrh.Imm.imm16 != 0x8000);
2966 p = mkFormI(p, 8, r_srcL, r_dst, (-srcR->Mrh.Imm.imm16));
2967 } else {
2968 /* subu */
2969 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 35);
2970 }
2971 break;
2972 case Malu_AND:
2973 if (immR) {
2974 /* andi */
2975 vassert(!srcR->Mrh.Imm.syned);
2976 p = mkFormI(p, 12, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2977 } else {
2978 /* and */
2979 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 36);
2980 }
2981 break;
2982 case Malu_OR:
2983 if (immR) {
2984 /* ori */
2985 vassert(!srcR->Mrh.Imm.syned);
2986 p = mkFormI(p, 13, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2987 } else {
2988 /* or */
2989 if (r_srcL == 33)
petarjb92a9542013-02-27 22:57:17 +00002990 /* MFHI */
sewardj362cf842012-06-07 08:59:53 +00002991 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2992 else if (r_srcL == 34)
petarjb92a9542013-02-27 22:57:17 +00002993 /* MFLO */
sewardj362cf842012-06-07 08:59:53 +00002994 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2995 else if (r_dst == 33)
petarjb92a9542013-02-27 22:57:17 +00002996 /* MTHI */
sewardj362cf842012-06-07 08:59:53 +00002997 p = mkFormR(p, 0, r_srcL, 0, 0, 0, 17);
2998 else if (r_dst == 34)
petarjb92a9542013-02-27 22:57:17 +00002999 /* MTLO */
sewardj362cf842012-06-07 08:59:53 +00003000 p = mkFormR(p, 0, r_srcL, 0, 0, 0, 19);
3001 else
3002 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 37);
3003 }
3004 break;
3005 case Malu_NOR:
3006 /* nor */
3007 vassert(!immR);
3008 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 39);
3009 break;
3010 case Malu_XOR:
3011 if (immR) {
3012 /* xori */
3013 vassert(!srcR->Mrh.Imm.syned);
3014 p = mkFormI(p, 14, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
3015 } else {
3016 /* xor */
3017 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
3018 }
3019 break;
petarjb92a9542013-02-27 22:57:17 +00003020 case Malu_DADD:
3021 if (immR) {
3022 vassert(srcR->Mrh.Imm.syned);
3023 vassert(srcR->Mrh.Imm.imm16 != 0x8000);
3024 p = mkFormI(p, 25, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
3025 } else {
3026 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 45);
3027 }
3028 break;
3029 case Malu_DSUB:
3030 if (immR) {
3031 p = mkFormI(p, 25, r_srcL, r_dst, (-srcR->Mrh.Imm.imm16));
3032 } else {
3033 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 47);
3034 }
3035 break;
3036 case Malu_SLT:
3037 if (immR) {
3038 goto bad;
3039 } else {
3040 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
3041 }
3042 break;
3043
sewardj362cf842012-06-07 08:59:53 +00003044 default:
3045 goto bad;
3046 }
3047 goto done;
3048 }
3049
3050 case Min_Shft: {
3051 MIPSRH *srcR = i->Min.Shft.srcR;
3052 Bool sz32 = i->Min.Shft.sz32;
3053 Bool immR = toBool(srcR->tag == Mrh_Imm);
3054 UInt r_dst = iregNo(i->Min.Shft.dst, mode64);
3055 UInt r_srcL = iregNo(i->Min.Shft.srcL, mode64);
3056 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->Mrh.Reg.reg,
3057 mode64);
3058 if (!mode64)
3059 vassert(sz32);
3060 switch (i->Min.Shft.op) {
3061 case Mshft_SLL:
3062 if (sz32) {
3063 if (immR) {
3064 UInt n = srcR->Mrh.Imm.imm16;
petarjb92a9542013-02-27 22:57:17 +00003065 vassert(n >= 0 && n <= 32);
sewardj362cf842012-06-07 08:59:53 +00003066 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 0);
3067 } else {
3068 /* shift variable */
3069 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 4);
3070 }
3071 } else {
3072 if (immR) {
3073 UInt n = srcR->Mrh.Imm.imm16;
3074 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
3075 if (n >= 0 && n < 32) {
3076 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 56);
3077 } else {
3078 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 60);
3079 }
3080 } else {
3081 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 20);
3082 }
3083 }
3084 break;
petarjb92a9542013-02-27 22:57:17 +00003085
sewardj362cf842012-06-07 08:59:53 +00003086 case Mshft_SRL:
3087 if (sz32) {
petarjb92a9542013-02-27 22:57:17 +00003088 /* SRL, SRLV */
sewardj362cf842012-06-07 08:59:53 +00003089 if (immR) {
3090 UInt n = srcR->Mrh.Imm.imm16;
3091 vassert(n >= 0 && n < 32);
3092 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 2);
3093 } else {
3094 /* shift variable */
3095 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 6);
3096 }
3097 } else {
petarjb92a9542013-02-27 22:57:17 +00003098 /* DSRL, DSRL32, DSRLV */
sewardj362cf842012-06-07 08:59:53 +00003099 if (immR) {
3100 UInt n = srcR->Mrh.Imm.imm16;
3101 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
3102 if (n >= 0 && n < 32) {
3103 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 58);
3104 } else {
3105 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 62);
3106 }
3107 } else {
3108 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 22);
3109 }
3110 }
3111 break;
petarjb92a9542013-02-27 22:57:17 +00003112
sewardj362cf842012-06-07 08:59:53 +00003113 case Mshft_SRA:
3114 if (sz32) {
petarjb92a9542013-02-27 22:57:17 +00003115 /* SRA, SRAV */
sewardj362cf842012-06-07 08:59:53 +00003116 if (immR) {
3117 UInt n = srcR->Mrh.Imm.imm16;
3118 vassert(n >= 0 && n < 32);
3119 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 3);
3120 } else {
3121 /* shift variable */
3122 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 7);
3123 }
3124 } else {
petarjb92a9542013-02-27 22:57:17 +00003125 /* DSRA, DSRA32, DSRAV */
sewardj362cf842012-06-07 08:59:53 +00003126 if (immR) {
3127 UInt n = srcR->Mrh.Imm.imm16;
3128 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
3129 if (n >= 0 && n < 32) {
3130 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 59);
3131 } else {
3132 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 63);
3133 }
3134 } else {
3135 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 23);
3136 }
3137 }
3138 break;
dejanjc3fee0d2013-07-25 09:08:03 +00003139
sewardj362cf842012-06-07 08:59:53 +00003140 default:
3141 goto bad;
3142 }
3143
3144 goto done;
3145 }
petarjb92a9542013-02-27 22:57:17 +00003146
sewardj362cf842012-06-07 08:59:53 +00003147 case Min_Unary: {
3148 UInt r_dst = iregNo(i->Min.Unary.dst, mode64);
3149 UInt r_src = iregNo(i->Min.Unary.src, mode64);
3150
3151 switch (i->Min.Unary.op) {
petarjb92a9542013-02-27 22:57:17 +00003152 /* Mun_CLO, Mun_CLZ, Mun_NOP, Mun_DCLO, Mun_DCLZ */
3153 case Mun_CLO: /* clo */
dejanjc3fee0d2013-07-25 09:08:03 +00003154 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 33);
sewardj362cf842012-06-07 08:59:53 +00003155 break;
petarjb92a9542013-02-27 22:57:17 +00003156 case Mun_CLZ: /* clz */
dejanjc3fee0d2013-07-25 09:08:03 +00003157 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 32);
sewardj362cf842012-06-07 08:59:53 +00003158 break;
petarjb92a9542013-02-27 22:57:17 +00003159 case Mun_NOP: /* nop (sll r0,r0,0) */
sewardj362cf842012-06-07 08:59:53 +00003160 p = mkFormR(p, 0, 0, 0, 0, 0, 0);
3161 break;
petarjb92a9542013-02-27 22:57:17 +00003162 case Mun_DCLO: /* clo */
dejanjc3fee0d2013-07-25 09:08:03 +00003163 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 37);
petarjb92a9542013-02-27 22:57:17 +00003164 break;
3165 case Mun_DCLZ: /* clz */
dejanjc3fee0d2013-07-25 09:08:03 +00003166 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 36);
petarjb92a9542013-02-27 22:57:17 +00003167 break;
sewardj362cf842012-06-07 08:59:53 +00003168 }
3169 goto done;
3170 }
petarjb92a9542013-02-27 22:57:17 +00003171
sewardj362cf842012-06-07 08:59:53 +00003172 case Min_Cmp: {
3173 UInt r_srcL = iregNo(i->Min.Cmp.srcL, mode64);
3174 UInt r_srcR = iregNo(i->Min.Cmp.srcR, mode64);
3175 UInt r_dst = iregNo(i->Min.Cmp.dst, mode64);
3176
3177 switch (i->Min.Cmp.cond) {
3178 case MIPScc_EQ:
dejanja759d172013-09-19 13:35:45 +00003179 /* xor r_dst, r_srcL, r_srcR
3180 sltiu r_dst, r_dst, 1 */
3181 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
3182 p = mkFormI(p, 11, r_dst, r_dst, 1);
sewardj362cf842012-06-07 08:59:53 +00003183 break;
3184 case MIPScc_NE:
dejanja759d172013-09-19 13:35:45 +00003185 /* xor r_dst, r_srcL, r_srcR
3186 sltu r_dst, zero, r_dst */
3187 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
3188 p = mkFormR(p, 0, 0, r_dst, r_dst, 0, 43);
sewardj362cf842012-06-07 08:59:53 +00003189 break;
3190 case MIPScc_LT:
petarjb92a9542013-02-27 22:57:17 +00003191 /* slt r_dst, r_srcL, r_srcR */
sewardj362cf842012-06-07 08:59:53 +00003192 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
3193 break;
3194 case MIPScc_LO:
petarjb92a9542013-02-27 22:57:17 +00003195 /* sltu r_dst, r_srcL, r_srcR */
sewardj362cf842012-06-07 08:59:53 +00003196 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 43);
3197 break;
3198 case MIPScc_LE:
dejanja759d172013-09-19 13:35:45 +00003199 /* slt r_dst, r_srcR, r_srcL
3200 xori r_dst, r_dst, 1 */
3201 p = mkFormR(p, 0, r_srcR, r_srcL, r_dst, 0, 42);
3202 p = mkFormI(p, 14, r_dst, r_dst, 1);
sewardj362cf842012-06-07 08:59:53 +00003203 break;
3204 case MIPScc_LS:
dejanja759d172013-09-19 13:35:45 +00003205 /* sltu r_dst, rsrcR, r_srcL
3206 xori r_dsr, r_dst, 1 */
3207 p = mkFormR(p, 0, r_srcR, r_srcL, r_dst, 0, 43);
3208 p = mkFormI(p, 14, r_dst, r_dst, 1);
sewardj362cf842012-06-07 08:59:53 +00003209 break;
3210 default:
3211 goto bad;
3212 }
3213 goto done;
3214 }
petarjb92a9542013-02-27 22:57:17 +00003215
sewardj362cf842012-06-07 08:59:53 +00003216 case Min_Mul: {
3217 Bool syned = i->Min.Mul.syned;
3218 Bool widening = i->Min.Mul.widening;
3219 Bool sz32 = i->Min.Mul.sz32;
3220 UInt r_srcL = iregNo(i->Min.Mul.srcL, mode64);
3221 UInt r_srcR = iregNo(i->Min.Mul.srcR, mode64);
3222 UInt r_dst = iregNo(i->Min.Mul.dst, mode64);
sewardj362cf842012-06-07 08:59:53 +00003223 if (widening) {
3224 if (sz32) {
3225 if (syned)
3226 /* mult */
3227 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 24);
3228 else
3229 /* multu */
3230 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 25);
3231 } else {
3232 if (syned) /* DMULT r_dst,r_srcL,r_srcR */
3233 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 28);
3234 else /* DMULTU r_dst,r_srcL,r_srcR */
3235 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 29);
3236 }
3237 } else {
3238 if (sz32)
3239 /* mul */
3240 p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
3241 else if (mode64 && !sz32)
3242 p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
3243 else
3244 goto bad;
3245 }
3246 goto done;
3247 }
petarjb92a9542013-02-27 22:57:17 +00003248
sewardj362cf842012-06-07 08:59:53 +00003249 case Min_Macc: {
3250 Bool syned = i->Min.Macc.syned;
3251 UInt r_srcL = iregNo(i->Min.Macc.srcL, mode64);
3252 UInt r_srcR = iregNo(i->Min.Macc.srcR, mode64);
3253
3254 if (syned) {
3255 switch (i->Min.Macc.op) {
3256 case Macc_ADD:
petarjb92a9542013-02-27 22:57:17 +00003257 /* madd */
sewardj362cf842012-06-07 08:59:53 +00003258 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0, 0);
3259 break;
3260 case Macc_SUB:
petarjb92a9542013-02-27 22:57:17 +00003261 /* msub */
sewardj362cf842012-06-07 08:59:53 +00003262 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
3263 4);
3264 break;
3265 default:
3266 goto bad;
3267 }
3268 } else {
3269 switch (i->Min.Macc.op) {
3270 case Macc_ADD:
petarjb92a9542013-02-27 22:57:17 +00003271 /* maddu */
sewardj362cf842012-06-07 08:59:53 +00003272 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
3273 1);
3274 break;
3275 case Macc_SUB:
petarjb92a9542013-02-27 22:57:17 +00003276 /* msubu */
sewardj362cf842012-06-07 08:59:53 +00003277 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
3278 5);
3279 break;
3280 default:
3281 goto bad;
3282 }
3283 }
3284
3285 goto done;
3286 }
3287
3288 case Min_Div: {
3289 Bool syned = i->Min.Div.syned;
3290 Bool sz32 = i->Min.Div.sz32;
3291 UInt r_srcL = iregNo(i->Min.Div.srcL, mode64);
3292 UInt r_srcR = iregNo(i->Min.Div.srcR, mode64);
3293 if (sz32) {
3294 if (syned) {
3295 /* div */
3296 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 26);
3297 } else
3298 /* divu */
3299 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 27);
3300 goto done;
3301 } else {
3302 if (syned) {
3303 /* ddiv */
3304 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 30);
3305 } else
3306 /* ddivu */
3307 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 31);
3308 goto done;
3309 }
3310 }
petarjb92a9542013-02-27 22:57:17 +00003311
sewardj362cf842012-06-07 08:59:53 +00003312 case Min_Mthi: {
3313 UInt r_src = iregNo(i->Min.MtHL.src, mode64);
3314 p = mkFormR(p, 0, r_src, 0, 0, 0, 17);
3315 goto done;
3316 }
petarjb92a9542013-02-27 22:57:17 +00003317
sewardj362cf842012-06-07 08:59:53 +00003318 case Min_Mtlo: {
3319 UInt r_src = iregNo(i->Min.MtHL.src, mode64);
3320 p = mkFormR(p, 0, r_src, 0, 0, 0, 19);
3321 goto done;
3322 }
petarjb92a9542013-02-27 22:57:17 +00003323
sewardj362cf842012-06-07 08:59:53 +00003324 case Min_Mfhi: {
3325 UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
3326 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
3327 goto done;
3328 }
petarjb92a9542013-02-27 22:57:17 +00003329
sewardj362cf842012-06-07 08:59:53 +00003330 case Min_Mflo: {
3331 UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
3332 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
3333 goto done;
3334 }
petarjb92a9542013-02-27 22:57:17 +00003335
sewardj362cf842012-06-07 08:59:53 +00003336 case Min_MtFCSR: {
3337 UInt r_src = iregNo(i->Min.MtFCSR.src, mode64);
3338 /* ctc1 */
3339 p = mkFormR(p, 17, 6, r_src, 31, 0, 0);
3340 goto done;
3341 }
petarjb92a9542013-02-27 22:57:17 +00003342
sewardj362cf842012-06-07 08:59:53 +00003343 case Min_MfFCSR: {
3344 UInt r_dst = iregNo(i->Min.MfFCSR.dst, mode64);
3345 /* cfc1 */
3346 p = mkFormR(p, 17, 2, r_dst, 31, 0, 0);
3347 goto done;
3348 }
petarjb92a9542013-02-27 22:57:17 +00003349
sewardj362cf842012-06-07 08:59:53 +00003350 case Min_Call: {
sewardj74142b82013-08-08 10:28:59 +00003351 if (i->Min.Call.cond != MIPScc_AL
3352 && i->Min.Call.rloc.pri != RLPri_None) {
sewardjcfe046e2013-01-17 14:23:53 +00003353 /* The call might not happen (it isn't unconditional) and
3354 it returns a result. In this case we will need to
3355 generate a control flow diamond to put 0x555..555 in
3356 the return register(s) in the case where the call
3357 doesn't happen. If this ever becomes necessary, maybe
3358 copy code from the ARM equivalent. Until that day,
3359 just give up. */
3360 goto bad;
3361 }
sewardj362cf842012-06-07 08:59:53 +00003362 MIPSCondCode cond = i->Min.Call.cond;
dejanjc3fee0d2013-07-25 09:08:03 +00003363 UInt r_dst = 25; /* using %r25 as address temporary -
petarjb92a9542013-02-27 22:57:17 +00003364 see getRegUsage_MIPSInstr */
sewardj362cf842012-06-07 08:59:53 +00003365
3366 /* jump over the following insns if condition does not hold */
3367 if (cond != MIPScc_AL) {
3368 /* jmp fwds if !condition */
3369 /* don't know how many bytes to jump over yet...
3370 make space for a jump instruction + nop!!! and fill in later. */
petarjb92a9542013-02-27 22:57:17 +00003371 ptmp = p; /* fill in this bit later */
3372 p += 8; /* p += 8 */
sewardj362cf842012-06-07 08:59:53 +00003373 }
3374
petarjb92a9542013-02-27 22:57:17 +00003375 if (!mode64) {
3376 /* addiu $29, $29, -16 */
3377 p = mkFormI(p, 9, 29, 29, 0xFFF0);
3378 }
3379
3380 /* load target to r_dst; p += 4|8 */
sewardj362cf842012-06-07 08:59:53 +00003381 p = mkLoadImm(p, r_dst, i->Min.Call.target, mode64);
3382
petarjb92a9542013-02-27 22:57:17 +00003383 /* jalr r_dst */
3384 p = mkFormR(p, 0, r_dst, 0, 31, 0, 9); /* p += 4 */
3385 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3386
3387 if (!mode64) {
3388 /* addiu $29, $29, 16 */
3389 p = mkFormI(p, 9, 29, 29, 0x0010);
3390 }
sewardj362cf842012-06-07 08:59:53 +00003391
3392 /* Fix up the conditional jump, if there was one. */
3393 if (cond != MIPScc_AL) {
3394 UInt r_src = iregNo(i->Min.Call.src, mode64);
3395 Int delta = p - ptmp;
3396
3397 vassert(delta >= 20 && delta <= 32);
petarjb92a9542013-02-27 22:57:17 +00003398 /* blez r_src, delta/4-1
3399 nop */
sewardj362cf842012-06-07 08:59:53 +00003400 ptmp = mkFormI(ptmp, 6, r_src, 0, delta / 4 - 1);
petarja81d9be2013-01-30 18:06:26 +00003401 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
sewardj362cf842012-06-07 08:59:53 +00003402 }
3403 goto done;
3404 }
3405
3406 case Min_XDirect: {
3407 /* NB: what goes on here has to be very closely coordinated
3408 with the chainXDirect_MIPS and unchainXDirect_MIPS below. */
3409 /* We're generating chain-me requests here, so we need to be
3410 sure this is actually allowed -- no-redir translations
3411 can't use chain-me's. Hence: */
3412 vassert(disp_cp_chain_me_to_slowEP != NULL);
3413 vassert(disp_cp_chain_me_to_fastEP != NULL);
3414
3415 /* Use ptmp for backpatching conditional jumps. */
3416 ptmp = NULL;
3417
3418 /* First off, if this is conditional, create a conditional
3419 jump over the rest of it. Or at least, leave a space for
3420 it that we will shortly fill in. */
3421 if (i->Min.XDirect.cond != MIPScc_AL) {
3422 vassert(i->Min.XDirect.cond != MIPScc_NV);
3423 ptmp = p;
3424 p += 12;
3425 }
3426
3427 /* Update the guest PC. */
3428 /* move r9, dstGA */
petarjb92a9542013-02-27 22:57:17 +00003429 /* sw/sd r9, amPC */
3430 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, (ULong)i->Min.XDirect.dstGA,
3431 mode64);
3432 p = do_load_or_store_machine_word(p, False /*!isLoad*/ , /*r*/ 9,
3433 i->Min.XDirect.amPC, mode64);
sewardj362cf842012-06-07 08:59:53 +00003434
3435 /* --- FIRST PATCHABLE BYTE follows --- */
3436 /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're
3437 calling to) backs up the return address, so as to find the
3438 address of the first patchable byte. So: don't change the
3439 number of instructions (3) below. */
3440 /* move r9, VG_(disp_cp_chain_me_to_{slowEP,fastEP}) */
3441 /* jr r9 */
florian8462d112014-09-24 15:18:09 +00003442 const void* disp_cp_chain_me
dejanjc3fee0d2013-07-25 09:08:03 +00003443 = i->Min.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
sewardj362cf842012-06-07 08:59:53 +00003444 : disp_cp_chain_me_to_slowEP;
petarjb92a9542013-02-27 22:57:17 +00003445 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
sewardj362cf842012-06-07 08:59:53 +00003446 Ptr_to_ULong(disp_cp_chain_me), mode64);
3447 /* jalr $9 */
3448 /* nop */
petarjb92a9542013-02-27 22:57:17 +00003449 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3450 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
sewardj362cf842012-06-07 08:59:53 +00003451 /* --- END of PATCHABLE BYTES --- */
3452
3453 /* Fix up the conditional jump, if there was one. */
3454 if (i->Min.XDirect.cond != MIPScc_AL) {
3455 Int delta = p - ptmp;
3456 delta = delta / 4 - 3;
3457 vassert(delta > 0 && delta < 40);
petarjb92a9542013-02-27 22:57:17 +00003458
3459 /* lw $9, COND_OFFSET(GuestSP)
sewardj362cf842012-06-07 08:59:53 +00003460 beq $9, $0, 2
petarjb92a9542013-02-27 22:57:17 +00003461 nop */
3462 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
sewardj362cf842012-06-07 08:59:53 +00003463 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
petarja81d9be2013-01-30 18:06:26 +00003464 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
sewardj362cf842012-06-07 08:59:53 +00003465 }
3466 goto done;
3467 }
3468
3469 case Min_XIndir: {
3470 /* We're generating transfers that could lead indirectly to a
3471 chain-me, so we need to be sure this is actually allowed --
3472 no-redir translations are not allowed to reach normal
3473 translations without going through the scheduler. That means
3474 no XDirects or XIndirs out from no-redir translations.
3475 Hence: */
3476 vassert(disp_cp_xindir != NULL);
3477
3478 /* Use ptmp for backpatching conditional jumps. */
3479 ptmp = NULL;
3480
3481 /* First off, if this is conditional, create a conditional
3482 jump over the rest of it. */
3483 if (i->Min.XIndir.cond != MIPScc_AL) {
3484 vassert(i->Min.XIndir.cond != MIPScc_NV);
3485 ptmp = p;
3486 p += 12;
3487 }
3488
3489 /* Update the guest PC. */
petarj0c30de82013-04-19 12:35:00 +00003490 /* sw/sd r-dstGA, amPC */
petarjb92a9542013-02-27 22:57:17 +00003491 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
sewardj362cf842012-06-07 08:59:53 +00003492 iregNo(i->Min.XIndir.dstGA, mode64),
3493 i->Min.XIndir.amPC, mode64);
3494
3495 /* move r9, VG_(disp_cp_xindir) */
3496 /* jalr r9 */
3497 /* nop */
petarjb92a9542013-02-27 22:57:17 +00003498 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3499 Ptr_to_ULong(disp_cp_xindir), mode64);
3500 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3501 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
sewardj362cf842012-06-07 08:59:53 +00003502
3503 /* Fix up the conditional jump, if there was one. */
3504 if (i->Min.XIndir.cond != MIPScc_AL) {
3505 Int delta = p - ptmp;
3506 delta = delta / 4 - 3;
3507 vassert(delta > 0 && delta < 40);
petarjb92a9542013-02-27 22:57:17 +00003508
3509 /* lw $9, COND_OFFSET($GuestSP)
sewardj362cf842012-06-07 08:59:53 +00003510 beq $9, $0, 2
petarjb92a9542013-02-27 22:57:17 +00003511 nop */
3512 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
sewardj362cf842012-06-07 08:59:53 +00003513 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
petarja81d9be2013-01-30 18:06:26 +00003514 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
sewardj362cf842012-06-07 08:59:53 +00003515 }
3516 goto done;
3517 }
3518
3519 case Min_XAssisted: {
3520 /* First off, if this is conditional, create a conditional jump
3521 over the rest of it. Or at least, leave a space for it that
3522 we will shortly fill in. */
3523 ptmp = NULL;
3524 if (i->Min.XAssisted.cond != MIPScc_AL) {
3525 vassert(i->Min.XAssisted.cond != MIPScc_NV);
3526 ptmp = p;
3527 p += 12;
3528 }
3529
3530 /* Update the guest PC. */
petarjb92a9542013-02-27 22:57:17 +00003531 /* sw/sd r-dstGA, amPC */
3532 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
sewardj362cf842012-06-07 08:59:53 +00003533 iregNo(i->Min.XIndir.dstGA, mode64),
3534 i->Min.XIndir.amPC, mode64);
3535
3536 /* imm32/64 r31, $magic_number */
3537 UInt trcval = 0;
3538 switch (i->Min.XAssisted.jk) {
petarja6a19862012-10-19 14:55:58 +00003539 case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
3540 case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
dejanj6ced72b2014-06-04 11:28:07 +00003541 /* case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break; */
3542 case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
petarja6a19862012-10-19 14:55:58 +00003543 case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
3544 case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
petarjb92a9542013-02-27 22:57:17 +00003545 /* case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break; */
petarja6a19862012-10-19 14:55:58 +00003546 case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
sewardj05f5e012014-05-04 10:52:11 +00003547 case Ijk_InvalICache: trcval = VEX_TRC_JMP_INVALICACHE; break;
petarja6a19862012-10-19 14:55:58 +00003548 case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
dejanj0e006f22014-02-19 11:56:29 +00003549 case Ijk_SigILL: trcval = VEX_TRC_JMP_SIGILL; break;
petarja6a19862012-10-19 14:55:58 +00003550 case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
petarjb92a9542013-02-27 22:57:17 +00003551 /* case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; */
petarja6a19862012-10-19 14:55:58 +00003552 case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break;
3553 case Ijk_SigFPE_IntDiv: trcval = VEX_TRC_JMP_SIGFPE_INTDIV; break;
3554 case Ijk_SigFPE_IntOvf: trcval = VEX_TRC_JMP_SIGFPE_INTOVF; break;
3555 case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
petarjb92a9542013-02-27 22:57:17 +00003556 /* We don't expect to see the following being assisted.
3557 case Ijk_Ret:
3558 case Ijk_Call:
3559 fallthrough */
dejanjc3fee0d2013-07-25 09:08:03 +00003560 default:
sewardj362cf842012-06-07 08:59:53 +00003561 ppIRJumpKind(i->Min.XAssisted.jk);
3562 vpanic("emit_MIPSInstr.Min_XAssisted: unexpected jump kind");
3563 }
3564 vassert(trcval != 0);
petarjb92a9542013-02-27 22:57:17 +00003565 p = mkLoadImm_EXACTLY2or6(p, /*r*/ GuestSP, trcval, mode64);
sewardj362cf842012-06-07 08:59:53 +00003566
3567 /* move r9, VG_(disp_cp_xassisted) */
petarjb92a9542013-02-27 22:57:17 +00003568 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
sewardj362cf842012-06-07 08:59:53 +00003569 (ULong)Ptr_to_ULong(disp_cp_xassisted), mode64);
3570 /* jalr $9
3571 nop */
petarjb92a9542013-02-27 22:57:17 +00003572 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3573 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
sewardj362cf842012-06-07 08:59:53 +00003574
3575 /* Fix up the conditional jump, if there was one. */
3576 if (i->Min.XAssisted.cond != MIPScc_AL) {
3577 Int delta = p - ptmp;
3578 delta = delta / 4 - 3;
3579 vassert(delta > 0 && delta < 40);
petarjb92a9542013-02-27 22:57:17 +00003580
3581 /* lw $9, COND_OFFSET($GuestSP)
sewardj362cf842012-06-07 08:59:53 +00003582 beq $9, $0, 2
petarjb92a9542013-02-27 22:57:17 +00003583 nop */
3584 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
sewardj362cf842012-06-07 08:59:53 +00003585 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
petarja81d9be2013-01-30 18:06:26 +00003586 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
sewardj362cf842012-06-07 08:59:53 +00003587 }
3588 goto done;
3589 }
3590
3591 case Min_Load: {
3592 MIPSAMode *am_addr = i->Min.Load.src;
3593 if (am_addr->tag == Mam_IR) {
3594 UInt r_dst = iregNo(i->Min.Load.dst, mode64);
3595 UInt opc, sz = i->Min.Load.sz;
3596 if (mode64 && (sz == 4 || sz == 8)) {
3597 /* should be guaranteed to us by iselWordExpr_AMode */
3598 vassert(0 == (am_addr->Mam.IR.index & 3));
3599 }
3600 switch (sz) {
3601 case 1:
3602 opc = 32;
3603 break;
3604 case 2:
3605 opc = 33;
3606 break;
3607 case 4:
3608 opc = 35;
3609 break;
3610 case 8:
3611 opc = 55;
3612 vassert(mode64);
3613 break;
sewardj362cf842012-06-07 08:59:53 +00003614 default:
3615 goto bad;
3616 }
3617
3618 p = doAMode_IR(p, opc, r_dst, am_addr, mode64);
3619 goto done;
3620 } else if (am_addr->tag == Mam_RR) {
3621 UInt r_dst = iregNo(i->Min.Load.dst, mode64);
3622 UInt opc, sz = i->Min.Load.sz;
3623
3624 switch (sz) {
3625 case 1:
3626 opc = 32;
3627 break;
3628 case 2:
3629 opc = 33;
3630 break;
3631 case 4:
3632 opc = 35;
3633 break;
3634 case 8:
3635 opc = 55;
3636 vassert(mode64);
3637 break;
sewardj362cf842012-06-07 08:59:53 +00003638 default:
3639 goto bad;
3640 }
3641
3642 p = doAMode_RR(p, opc, r_dst, am_addr, mode64);
3643 goto done;
3644 }
3645 break;
3646 }
petarjb92a9542013-02-27 22:57:17 +00003647
sewardj362cf842012-06-07 08:59:53 +00003648 case Min_Store: {
3649 MIPSAMode *am_addr = i->Min.Store.dst;
3650 if (am_addr->tag == Mam_IR) {
3651 UInt r_src = iregNo(i->Min.Store.src, mode64);
3652 UInt opc, sz = i->Min.Store.sz;
3653 if (mode64 && (sz == 4 || sz == 8)) {
3654 /* should be guaranteed to us by iselWordExpr_AMode */
3655 vassert(0 == (am_addr->Mam.IR.index & 3));
3656 }
3657 switch (sz) {
3658 case 1:
3659 opc = 40;
3660 break;
3661 case 2:
3662 opc = 41;
3663 break;
3664 case 4:
3665 opc = 43;
3666 break;
3667 case 8:
3668 vassert(mode64);
3669 opc = 63;
3670 break;
3671 default:
3672 goto bad;
3673 }
3674
3675 p = doAMode_IR(p, opc, r_src, am_addr, mode64);
3676 goto done;
3677 } else if (am_addr->tag == Mam_RR) {
3678 UInt r_src = iregNo(i->Min.Store.src, mode64);
3679 UInt opc, sz = i->Min.Store.sz;
3680
3681 switch (sz) {
3682 case 1:
3683 opc = 40;
3684 break;
3685 case 2:
3686 opc = 41;
3687 break;
3688 case 4:
3689 opc = 43;
3690 break;
3691 case 8:
3692 vassert(mode64);
3693 opc = 63;
3694 break;
3695 default:
3696 goto bad;
3697 }
3698
3699 p = doAMode_RR(p, opc, r_src, am_addr, mode64);
3700 goto done;
3701 }
3702 break;
3703 }
3704 case Min_LoadL: {
3705 MIPSAMode *am_addr = i->Min.LoadL.src;
3706 UInt r_src = iregNo(am_addr->Mam.IR.base, mode64);
3707 UInt idx = am_addr->Mam.IR.index;
3708 UInt r_dst = iregNo(i->Min.LoadL.dst, mode64);
3709
petarjb92a9542013-02-27 22:57:17 +00003710 if (i->Min.LoadL.sz == 4)
3711 p = mkFormI(p, 0x30, r_src, r_dst, idx);
3712 else
3713 p = mkFormI(p, 0x34, r_src, r_dst, idx);
sewardj362cf842012-06-07 08:59:53 +00003714 goto done;
3715 }
3716 case Min_StoreC: {
3717 MIPSAMode *am_addr = i->Min.StoreC.dst;
3718 UInt r_src = iregNo(i->Min.StoreC.src, mode64);
3719 UInt idx = am_addr->Mam.IR.index;
3720 UInt r_dst = iregNo(am_addr->Mam.IR.base, mode64);
3721
petarjb92a9542013-02-27 22:57:17 +00003722 if (i->Min.StoreC.sz == 4)
3723 p = mkFormI(p, 0x38, r_dst, r_src, idx);
3724 else
3725 p = mkFormI(p, 0x3C, r_dst, r_src, idx);
sewardj362cf842012-06-07 08:59:53 +00003726 goto done;
3727 }
dejanj6ced72b2014-06-04 11:28:07 +00003728 case Min_Cas: {
3729 if (i->Min.Cas.sz != 8 && i->Min.Cas.sz != 4)
3730 goto bad;
3731 UInt old = iregNo(i->Min.Cas.old, mode64);
3732 UInt addr = iregNo(i->Min.Cas.addr, mode64);
3733 UInt expd = iregNo(i->Min.Cas.expd, mode64);
3734 UInt data = iregNo(i->Min.Cas.data, mode64);
3735 Bool sz8 = toBool(i->Min.Cas.sz == 8);
3736
3737 /*
3738 * ll(d) old, 0(addr)
3739 * bne old, expd, end
3740 * nop
3741 * (d)addiu old, old, 1
3742 * sc(d) data, 0(addr)
3743 * movn old, expd, data
3744 * end:
3745 */
3746 // ll(d) old, 0(addr)
3747 p = mkFormI(p, sz8 ? 0x34 : 0x30, addr, old, 0);
3748 // bne old, expd, end
3749 p = mkFormI(p, 5, old, expd, 4);
3750 // nop
3751 p = mkFormR(p, 0, 0, 0, 0, 0, 0);
3752 // (d)addiu old, old, 1
3753 p = mkFormI(p, sz8 ? 25 : 9, old, old, 1);
3754 // sc(d) data, 0(addr)
3755 p = mkFormI(p, sz8 ? 0x3C : 0x38, addr, data, 0);
3756 // movn old, expd, data
3757 p = mkFormR(p, 0, expd, data, old, 0, 0xb);
3758
3759 goto done;
3760 }
sewardj362cf842012-06-07 08:59:53 +00003761 case Min_RdWrLR: {
3762 UInt reg = iregNo(i->Min.RdWrLR.gpr, mode64);
3763 Bool wrLR = i->Min.RdWrLR.wrLR;
3764 if (wrLR)
3765 p = mkMoveReg(p, 31, reg);
3766 else
3767 p = mkMoveReg(p, reg, 31);
3768 goto done;
3769 }
petarjb92a9542013-02-27 22:57:17 +00003770
3771 /* Floating point */
sewardj362cf842012-06-07 08:59:53 +00003772 case Min_FpLdSt: {
3773 MIPSAMode *am_addr = i->Min.FpLdSt.addr;
3774 UChar sz = i->Min.FpLdSt.sz;
3775 vassert(sz == 4 || sz == 8);
3776 if (sz == 4) {
3777 UInt f_reg = fregNo(i->Min.FpLdSt.reg, mode64);
3778 if (i->Min.FpLdSt.isLoad) {
3779 if (am_addr->tag == Mam_IR)
3780 p = doAMode_IR(p, 0x31, f_reg, am_addr, mode64);
3781 else if (am_addr->tag == Mam_RR)
3782 p = doAMode_RR(p, 0x31, f_reg, am_addr, mode64);
3783 } else {
3784 if (am_addr->tag == Mam_IR)
3785 p = doAMode_IR(p, 0x39, f_reg, am_addr, mode64);
3786 else if (am_addr->tag == Mam_RR)
3787 p = doAMode_RR(p, 0x39, f_reg, am_addr, mode64);
3788 }
3789 } else if (sz == 8) {
3790 UInt f_reg = dregNo(i->Min.FpLdSt.reg);
3791 if (i->Min.FpLdSt.isLoad) {
3792 if (am_addr->tag == Mam_IR) {
petarj1ec43e02012-09-04 13:45:42 +00003793 p = doAMode_IR(p, 0x35, f_reg, am_addr, mode64);
sewardj362cf842012-06-07 08:59:53 +00003794 } else if (am_addr->tag == Mam_RR) {
petarj1ec43e02012-09-04 13:45:42 +00003795 p = doAMode_RR(p, 0x35, f_reg, am_addr, mode64);
sewardj362cf842012-06-07 08:59:53 +00003796 }
3797 } else {
3798 if (am_addr->tag == Mam_IR) {
petarj1ec43e02012-09-04 13:45:42 +00003799 p = doAMode_IR(p, 0x3d, f_reg, am_addr, mode64);
sewardj362cf842012-06-07 08:59:53 +00003800 } else if (am_addr->tag == Mam_RR) {
petarj1ec43e02012-09-04 13:45:42 +00003801 p = doAMode_RR(p, 0x3d, f_reg, am_addr, mode64);
sewardj362cf842012-06-07 08:59:53 +00003802 }
3803 }
3804 }
3805 goto done;
3806 }
3807
3808 case Min_FpUnary: {
3809 switch (i->Min.FpUnary.op) {
petarjb92a9542013-02-27 22:57:17 +00003810 case Mfp_MOVS: { /* FP move */
sewardj362cf842012-06-07 08:59:53 +00003811 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3812 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3813 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x6);
3814 break;
3815 }
petarjb92a9542013-02-27 22:57:17 +00003816 case Mfp_MOVD: { /* FP move */
sewardj362cf842012-06-07 08:59:53 +00003817 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3818 UInt fr_src = dregNo(i->Min.FpUnary.src);
3819 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x6);
3820 break;
3821 }
dejanjc3fee0d2013-07-25 09:08:03 +00003822 case Mfp_ABSS: { /* ABS.S */
sewardj362cf842012-06-07 08:59:53 +00003823 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3824 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3825 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x5);
3826 break;
3827 }
dejanjc3fee0d2013-07-25 09:08:03 +00003828 case Mfp_ABSD: { /* ABS.D */
sewardj362cf842012-06-07 08:59:53 +00003829 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3830 UInt fr_src = dregNo(i->Min.FpUnary.src);
3831 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x5);
3832 break;
3833 }
dejanjc3fee0d2013-07-25 09:08:03 +00003834 case Mfp_NEGS: { /* NEG.S */
sewardj362cf842012-06-07 08:59:53 +00003835 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3836 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3837 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x7);
3838 break;
3839 }
dejanjc3fee0d2013-07-25 09:08:03 +00003840 case Mfp_NEGD: { /* NEG.D */
sewardj362cf842012-06-07 08:59:53 +00003841 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3842 UInt fr_src = dregNo(i->Min.FpUnary.src);
3843 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x7);
3844 break;
3845 }
petarjb92a9542013-02-27 22:57:17 +00003846 case Mfp_SQRTS: { /* SQRT.S */
sewardj362cf842012-06-07 08:59:53 +00003847 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3848 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3849 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x04);
3850 break;
3851 }
petarjb92a9542013-02-27 22:57:17 +00003852 case Mfp_SQRTD: { /* SQRT.D */
sewardj362cf842012-06-07 08:59:53 +00003853 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3854 UInt fr_src = dregNo(i->Min.FpUnary.src);
3855 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x04);
3856 break;
3857 }
sewardj362cf842012-06-07 08:59:53 +00003858 default:
3859 goto bad;
3860 }
3861 goto done;
3862 }
3863
3864 case Min_FpBinary: {
3865 switch (i->Min.FpBinary.op) {
3866 case Mfp_ADDS: {
3867 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3868 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3869 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3870 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 0);
3871 break;
3872 }
3873 case Mfp_SUBS: {
3874 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3875 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3876 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3877 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 1);
3878 break;
3879 }
3880 case Mfp_MULS: {
3881 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3882 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3883 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3884 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 2);
3885 break;
3886 }
3887 case Mfp_DIVS: {
3888 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3889 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3890 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3891 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 3);
3892 break;
3893 }
3894 case Mfp_ADDD: {
3895 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3896 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3897 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3898 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 0);
3899 break;
3900 }
3901 case Mfp_SUBD: {
3902 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3903 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3904 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3905 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 1);
3906 break;
3907 }
3908 case Mfp_MULD: {
3909 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3910 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3911 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3912 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 2);
3913 break;
3914 }
3915 case Mfp_DIVD: {
3916 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3917 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3918 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3919 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 3);
3920 break;
3921 }
3922 default:
3923 goto bad;
3924 }
3925 goto done;
3926 }
3927
petarjb92a9542013-02-27 22:57:17 +00003928 case Min_FpTernary: {
3929 switch (i->Min.FpTernary.op) {
3930 case Mfp_MADDS: {
3931 UInt fr_dst = fregNo(i->Min.FpTernary.dst, mode64);
3932 UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64);
3933 UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64);
3934 UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64);
3935 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x20);
3936 break;
3937 }
3938 case Mfp_MADDD: {
3939 UInt fr_dst = dregNo(i->Min.FpTernary.dst);
3940 UInt fr_src1 = dregNo(i->Min.FpTernary.src1);
3941 UInt fr_src2 = dregNo(i->Min.FpTernary.src2);
3942 UInt fr_src3 = dregNo(i->Min.FpTernary.src3);
3943 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x21);
3944 break;
3945 }
3946 case Mfp_MSUBS: {
3947 UInt fr_dst = fregNo(i->Min.FpTernary.dst, mode64);
3948 UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64);
3949 UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64);
3950 UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64);
3951 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x28);
3952 break;
3953 }
3954 case Mfp_MSUBD: {
3955 UInt fr_dst = dregNo(i->Min.FpTernary.dst);
3956 UInt fr_src1 = dregNo(i->Min.FpTernary.src1);
3957 UInt fr_src2 = dregNo(i->Min.FpTernary.src2);
3958 UInt fr_src3 = dregNo(i->Min.FpTernary.src3);
3959 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x29);
3960 break;
3961 }
3962 default:
3963 goto bad;
3964 }
3965 goto done;
3966 }
3967
sewardj362cf842012-06-07 08:59:53 +00003968 case Min_FpConvert: {
3969 switch (i->Min.FpConvert.op) {
3970 UInt fr_dst, fr_src;
3971 case Mfp_CVTSD:
3972 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3973 fr_src = dregNo(i->Min.FpConvert.src);
3974 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x20);
3975 break;
3976 case Mfp_CVTSW:
3977 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3978 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3979 p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x20);
3980 break;
3981 case Mfp_CVTWD:
3982 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3983 fr_src = dregNo(i->Min.FpConvert.src);
3984 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x24);
3985 break;
3986 case Mfp_CVTWS:
3987 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3988 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3989 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x24);
3990 break;
3991 case Mfp_CVTDW:
3992 fr_dst = dregNo(i->Min.FpConvert.dst);
3993 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3994 p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x21);
3995 break;
petarjb92a9542013-02-27 22:57:17 +00003996 case Mfp_CVTDL:
3997 fr_dst = dregNo(i->Min.FpConvert.dst);
3998 fr_src = dregNo(i->Min.FpConvert.src);
3999 p = mkFormR(p, 0x11, 0x15, 0, fr_src, fr_dst, 0x21);
4000 break;
4001 case Mfp_CVTDS:
4002 fr_dst = dregNo(i->Min.FpConvert.dst);
4003 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4004 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x21);
4005 break;
4006 case Mfp_CVTSL:
4007 fr_dst = dregNo(i->Min.FpConvert.dst);
4008 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4009 p = mkFormR(p, 0x11, 0x15, 0, fr_src, fr_dst, 0x20);
4010 break;
4011 case Mfp_CVTLS:
dejanj0e006f22014-02-19 11:56:29 +00004012 if (mode64) {
4013 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4014 fr_src = dregNo(i->Min.FpConvert.src);
4015 } else {
4016 fr_dst = dregNo(i->Min.FpConvert.dst);
4017 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4018 }
petarjb92a9542013-02-27 22:57:17 +00004019 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x25);
4020 break;
4021 case Mfp_CVTLD:
4022 fr_dst = dregNo(i->Min.FpConvert.dst);
4023 fr_src = dregNo(i->Min.FpConvert.src);
4024 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x25);
4025 break;
sewardj362cf842012-06-07 08:59:53 +00004026 case Mfp_TRUWS:
4027 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4028 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4029 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0D);
4030 break;
4031 case Mfp_TRUWD:
4032 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4033 fr_src = dregNo(i->Min.FpConvert.src);
4034 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0D);
4035 break;
4036 case Mfp_TRULS:
4037 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4038 fr_src = dregNo(i->Min.FpConvert.src);
4039 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x09);
4040 break;
4041 case Mfp_TRULD:
4042 fr_dst = dregNo(i->Min.FpConvert.dst);
4043 fr_src = dregNo(i->Min.FpConvert.src);
4044 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x09);
4045 break;
4046 case Mfp_CEILWS:
4047 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4048 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4049 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0E);
4050 break;
4051 case Mfp_CEILWD:
4052 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4053 fr_src = dregNo(i->Min.FpConvert.src);
4054 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0E);
4055 break;
4056 case Mfp_CEILLS:
4057 fr_dst = dregNo(i->Min.FpConvert.dst);
4058 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4059 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0A);
4060 break;
4061 case Mfp_CEILLD:
4062 fr_dst = dregNo(i->Min.FpConvert.dst);
4063 fr_src = dregNo(i->Min.FpConvert.src);
4064 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0A);
4065 break;
4066 case Mfp_ROUNDWS:
4067 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4068 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4069 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0C);
4070 break;
4071 case Mfp_ROUNDWD:
4072 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4073 fr_src = dregNo(i->Min.FpConvert.src);
4074 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0C);
4075 break;
dejanja759d172013-09-19 13:35:45 +00004076 case Mfp_ROUNDLD:
4077 fr_dst = dregNo(i->Min.FpConvert.dst);
4078 fr_src = dregNo(i->Min.FpConvert.src);
4079 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x08);
4080 break;
sewardj362cf842012-06-07 08:59:53 +00004081 case Mfp_FLOORWS:
4082 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4083 fr_src = fregNo(i->Min.FpConvert.src, mode64);
4084 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0F);
4085 break;
4086 case Mfp_FLOORWD:
4087 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
4088 fr_src = dregNo(i->Min.FpConvert.src);
4089 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0F);
4090 break;
dejanj3bc88cc2013-10-07 10:28:56 +00004091 case Mfp_FLOORLD:
4092 fr_dst = dregNo(i->Min.FpConvert.dst);
4093 fr_src = dregNo(i->Min.FpConvert.src);
4094 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0B);
4095 break;
sewardj362cf842012-06-07 08:59:53 +00004096
4097 default:
4098 goto bad;
4099 }
4100 goto done;
4101 }
4102
4103 case Min_FpCompare: {
dejanjf37c0862014-02-25 15:25:49 +00004104 UInt r_dst = iregNo(i->Min.FpCompare.dst, mode64);
sewardj362cf842012-06-07 08:59:53 +00004105 UInt fr_srcL = dregNo(i->Min.FpCompare.srcL);
4106 UInt fr_srcR = dregNo(i->Min.FpCompare.srcR);
4107
dejanjf37c0862014-02-25 15:25:49 +00004108 UInt op;
sewardj362cf842012-06-07 08:59:53 +00004109 switch (i->Min.FpConvert.op) {
dejanjf37c0862014-02-25 15:25:49 +00004110 case Mfp_CMP_UN:
4111 op = 1;
sewardj362cf842012-06-07 08:59:53 +00004112 break;
dejanjf37c0862014-02-25 15:25:49 +00004113 case Mfp_CMP_EQ:
4114 op = 2;
4115 break;
4116 case Mfp_CMP_LT:
4117 op = 12;
4118 break;
4119 case Mfp_CMP_NGT:
4120 op = 15;
4121 break;
sewardj362cf842012-06-07 08:59:53 +00004122 default:
4123 goto bad;
4124 }
dejanjf37c0862014-02-25 15:25:49 +00004125 /* c.cond.d fr_srcL, fr_srcR
4126 cfc1 r_dst, $31
4127 srl r_dst, r_dst, 23
4128 andi r_dst, r_dst, 1 */
4129 p = mkFormR(p, 0x11, 0x11, fr_srcL, fr_srcR, 0, op + 48);
4130 p = mkFormR(p, 0x11, 0x2, r_dst, 31, 0, 0);
4131 p = mkFormS(p, 0, r_dst, 0, r_dst, 23, 2);
4132 p = mkFormI(p, 12, r_dst, r_dst, 1);
sewardj362cf842012-06-07 08:59:53 +00004133 goto done;
4134 }
petarjb92a9542013-02-27 22:57:17 +00004135
4136 case Min_FpGpMove: {
4137 switch (i->Min.FpGpMove.op) {
4138 UInt rt, fs;
4139 case MFpGpMove_mfc1: {
4140 rt = iregNo(i->Min.FpGpMove.dst, mode64);
4141 fs = fregNo(i->Min.FpGpMove.src, mode64);
4142 p = mkFormR(p, 0x11, 0x0, rt, fs, 0x0, 0x0);
4143 break;
4144 }
4145 case MFpGpMove_dmfc1: {
4146 vassert(mode64);
4147 rt = iregNo(i->Min.FpGpMove.dst, mode64);
4148 fs = fregNo(i->Min.FpGpMove.src, mode64);
4149 p = mkFormR(p, 0x11, 0x1, rt, fs, 0x0, 0x0);
4150 break;
4151 }
4152 case MFpGpMove_mtc1: {
4153 rt = iregNo(i->Min.FpGpMove.src, mode64);
4154 fs = fregNo(i->Min.FpGpMove.dst, mode64);
4155 p = mkFormR(p, 0x11, 0x4, rt, fs, 0x0, 0x0);
4156 break;
4157 }
4158 case MFpGpMove_dmtc1: {
4159 vassert(mode64);
4160 rt = iregNo(i->Min.FpGpMove.src, mode64);
4161 fs = fregNo(i->Min.FpGpMove.dst, mode64);
4162 p = mkFormR(p, 0x11, 0x5, rt, fs, 0x0, 0x0);
4163 break;
4164 }
4165 default:
4166 goto bad;
4167 }
4168 goto done;
4169 }
4170
4171 case Min_MoveCond: {
4172 switch (i->Min.MoveCond.op) {
4173 UInt d, s, t;
4174 case MFpMoveCond_movns: {
4175 d = fregNo(i->Min.MoveCond.dst, mode64);
4176 s = fregNo(i->Min.MoveCond.src, mode64);
4177 t = iregNo(i->Min.MoveCond.cond, mode64);
4178 p = mkFormR(p, 0x11, 0x10, t, s, d, 0x13);
4179 break;
4180 }
4181 case MFpMoveCond_movnd: {
4182 d = dregNo(i->Min.MoveCond.dst);
4183 s = dregNo(i->Min.MoveCond.src);
4184 t = iregNo(i->Min.MoveCond.cond, mode64);
4185 p = mkFormR(p, 0x11, 0x11, t, s, d, 0x13);
4186 break;
4187 }
4188 case MMoveCond_movn: {
4189 d = iregNo(i->Min.MoveCond.dst, mode64);
4190 s = iregNo(i->Min.MoveCond.src, mode64);
4191 t = iregNo(i->Min.MoveCond.cond, mode64);
4192 p = mkFormR(p, 0, s, t, d, 0, 0xb);
4193 break;
4194 }
4195 default:
4196 goto bad;
4197 }
4198 goto done;
4199 }
4200
sewardj362cf842012-06-07 08:59:53 +00004201 case Min_EvCheck: {
4202 /* This requires a 32-bit dec/test in 32 mode. */
4203 /* We generate:
4204 lw r9, amCounter
4205 addiu r9, r9, -1
4206 sw r9, amCounter
4207 bgez r9, nofail
4208 lw r9, amFailAddr
4209 jalr r9
4210 nop
4211 nofail:
4212 */
4213 UChar* p0 = p;
4214 /* lw r9, amCounter */
petarj0c30de82013-04-19 12:35:00 +00004215 p = do_load_or_store_word32(p, True /*isLoad*/ , /*r*/ 9,
sewardj362cf842012-06-07 08:59:53 +00004216 i->Min.EvCheck.amCounter, mode64);
4217 /* addiu r9,r9,-1 */
4218 p = mkFormI(p, 9, 9, 9, 0xFFFF);
4219 /* sw r30, amCounter */
petarj0c30de82013-04-19 12:35:00 +00004220 p = do_load_or_store_word32(p, False /*!isLoad*/ , /*r*/ 9,
sewardj362cf842012-06-07 08:59:53 +00004221 i->Min.EvCheck.amCounter, mode64);
4222 /* bgez t9, nofail */
4223 p = mkFormI(p, 1, 9, 1, 3);
petarj0c30de82013-04-19 12:35:00 +00004224 /* lw/ld r9, amFailAddr */
petarjb92a9542013-02-27 22:57:17 +00004225 p = do_load_or_store_machine_word(p, True /*isLoad*/ , /*r*/ 9,
sewardj362cf842012-06-07 08:59:53 +00004226 i->Min.EvCheck.amFailAddr, mode64);
4227 /* jalr $9 */
petarjb92a9542013-02-27 22:57:17 +00004228 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
4229 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
sewardj362cf842012-06-07 08:59:53 +00004230 /* nofail: */
petarjb92a9542013-02-27 22:57:17 +00004231
sewardj362cf842012-06-07 08:59:53 +00004232 /* Crosscheck */
sewardj9b769162014-07-24 12:42:03 +00004233 vassert(evCheckSzB_MIPS(endness_host) == (UChar*)p - (UChar*)p0);
sewardj362cf842012-06-07 08:59:53 +00004234 goto done;
4235 }
4236
4237 case Min_ProfInc: {
4238 /* Generate a code template to increment a memory location whose
4239 address will be known later as an immediate value. This code
4240 template will be patched once the memory location is known.
petarjb92a9542013-02-27 22:57:17 +00004241 For now we do this with address == 0x65556555. */
sewardj362cf842012-06-07 08:59:53 +00004242 if (mode64) {
petarjb92a9542013-02-27 22:57:17 +00004243 /* 64-bit:
4244 move r9, 0x6555655565556555ULL
4245 ld r8, 0(r9)
4246 daddiu r8, r8, 1
4247 sd r8, 0(r9) */
4248
4249 /* move r9, 0x6555655565556555ULL */
4250 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, 0x6555655565556555ULL,
4251 True /*mode64*/);
4252 /* ld r8, 0(r9) */
4253 p = mkFormI(p, 55, 9, 8, 0);
4254
4255 /* daddiu r8, r8, 1 */
4256 p = mkFormI(p, 25, 8, 8, 1);
4257
4258 /* sd r8, 0(r9) */
4259 p = mkFormI(p, 63, 9, 8, 0);
sewardj362cf842012-06-07 08:59:53 +00004260 } else {
petarjb92a9542013-02-27 22:57:17 +00004261 /* 32-bit:
4262 move r9, 0x65556555
4263 lw r8, 0(r9)
4264 addiu r8, r8, 1 # add least significant word
4265 sw r8, 0(r9)
4266 sltiu r1, r8, 1 # set carry-in bit
4267 lw r8, 4(r9)
4268 addu r8, r8, r1
4269 sw r8, 4(r9) */
4270
4271 /* move r9, 0x65556555 */
4272 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, 0x65556555ULL,
4273 False /*!mode64*/);
4274 /* lw r8, 0(r9) */
sewardj362cf842012-06-07 08:59:53 +00004275 p = mkFormI(p, 35, 9, 8, 0);
4276
petarjb92a9542013-02-27 22:57:17 +00004277 /* addiu r8, r8, 1 # add least significant word */
sewardj362cf842012-06-07 08:59:53 +00004278 p = mkFormI(p, 9, 8, 8, 1);
4279
petarjb92a9542013-02-27 22:57:17 +00004280 /* sw r8, 0(r9) */
sewardj362cf842012-06-07 08:59:53 +00004281 p = mkFormI(p, 43, 9, 8, 0);
4282
petarjb92a9542013-02-27 22:57:17 +00004283 /* sltiu r1, r8, 1 # set carry-in bit */
sewardj362cf842012-06-07 08:59:53 +00004284 p = mkFormI(p, 11, 8, 1, 1);
4285
petarjb92a9542013-02-27 22:57:17 +00004286 /* lw r8, 4(r9) */
sewardj362cf842012-06-07 08:59:53 +00004287 p = mkFormI(p, 35, 9, 8, 4);
4288
petarjb92a9542013-02-27 22:57:17 +00004289 /* addu r8, r8, r1 */
sewardj362cf842012-06-07 08:59:53 +00004290 p = mkFormR(p, 0, 8, 1, 8, 0, 33);
4291
petarjb92a9542013-02-27 22:57:17 +00004292 /* sw r8, 4(r9) */
sewardj362cf842012-06-07 08:59:53 +00004293 p = mkFormI(p, 43, 9, 8, 4);
4294
4295 }
4296 /* Tell the caller .. */
4297 vassert(!(*is_profInc));
4298 *is_profInc = True;
4299 goto done;
4300 }
petarjb92a9542013-02-27 22:57:17 +00004301
sewardj362cf842012-06-07 08:59:53 +00004302 default:
4303 goto bad;
4304
4305 }
4306
4307 bad:
4308 vex_printf("\n=> ");
4309 ppMIPSInstr(i, mode64);
4310 vpanic("emit_MIPSInstr");
petarjb92a9542013-02-27 22:57:17 +00004311 /* NOTREACHED */ done:
4312 vassert(p - &buf[0] <= 128);
sewardj362cf842012-06-07 08:59:53 +00004313 return p - &buf[0];
4314}
4315
4316/* How big is an event check? See case for Min_EvCheck in
4317 emit_MIPSInstr just above. That crosschecks what this returns, so
4318 we can tell if we're inconsistent. */
sewardj9b769162014-07-24 12:42:03 +00004319Int evCheckSzB_MIPS ( VexEndness endness_host )
sewardj362cf842012-06-07 08:59:53 +00004320{
4321 UInt kInstrSize = 4;
4322 return 7*kInstrSize;
4323}
4324
4325/* NB: what goes on here has to be very closely coordinated with the
4326 emitInstr case for XDirect, above. */
sewardj9b769162014-07-24 12:42:03 +00004327VexInvalRange chainXDirect_MIPS ( VexEndness endness_host,
4328 void* place_to_chain,
florian7d6f81d2014-09-22 21:43:37 +00004329 const void* disp_cp_chain_me_EXPECTED,
4330 const void* place_to_jump_to,
sewardj362cf842012-06-07 08:59:53 +00004331 Bool mode64 )
4332{
sewardj9b769162014-07-24 12:42:03 +00004333 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
sewardj362cf842012-06-07 08:59:53 +00004334 /* What we're expecting to see is:
4335 move r9, disp_cp_chain_me_to_EXPECTED
4336 jalr r9
4337 nop
4338 viz
petarjb92a9542013-02-27 22:57:17 +00004339 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
4340 0x120F809 # jalr r9
4341 0x00000000 # nop
sewardj362cf842012-06-07 08:59:53 +00004342 */
4343 UChar* p = (UChar*)place_to_chain;
4344 vassert(0 == (3 & (HWord)p));
petarjb92a9542013-02-27 22:57:17 +00004345 vassert(isLoadImm_EXACTLY2or6(p, /*r*/9,
sewardj362cf842012-06-07 08:59:53 +00004346 (UInt)Ptr_to_ULong(disp_cp_chain_me_EXPECTED),
4347 mode64));
petarjb92a9542013-02-27 22:57:17 +00004348 vassert(fetch32(p + (mode64 ? 24 : 8) + 0) == 0x120F809);
4349 vassert(fetch32(p + (mode64 ? 24 : 8) + 4) == 0x00000000);
sewardj362cf842012-06-07 08:59:53 +00004350 /* And what we want to change it to is either:
4351 move r9, place_to_jump_to
4352 jalr r9
4353 nop
4354 viz
petarjb92a9542013-02-27 22:57:17 +00004355 <8 bytes generated by mkLoadImm_EXACTLY2or6>
4356 0x120F809 # jalr r9
4357 0x00000000 # nop
sewardj362cf842012-06-07 08:59:53 +00004358
4359 The replacement has the same length as the original.
4360 */
4361
petarjb92a9542013-02-27 22:57:17 +00004362 p = mkLoadImm_EXACTLY2or6(p, /*r*/9,
sewardj362cf842012-06-07 08:59:53 +00004363 Ptr_to_ULong(place_to_jump_to), mode64);
4364 p = emit32(p, 0x120F809);
4365 p = emit32(p, 0x00000000);
4366
4367 Int len = p - (UChar*)place_to_chain;
petarjb92a9542013-02-27 22:57:17 +00004368 vassert(len == (mode64 ? 32 : 16)); /* stay sane */
sewardj362cf842012-06-07 08:59:53 +00004369 VexInvalRange vir = {(HWord)place_to_chain, len};
4370 return vir;
4371}
4372
4373/* NB: what goes on here has to be very closely coordinated with the
4374 emitInstr case for XDirect, above. */
sewardj9b769162014-07-24 12:42:03 +00004375VexInvalRange unchainXDirect_MIPS ( VexEndness endness_host,
4376 void* place_to_unchain,
florian7d6f81d2014-09-22 21:43:37 +00004377 const void* place_to_jump_to_EXPECTED,
4378 const void* disp_cp_chain_me,
sewardj362cf842012-06-07 08:59:53 +00004379 Bool mode64 )
4380{
sewardj9b769162014-07-24 12:42:03 +00004381 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
sewardj362cf842012-06-07 08:59:53 +00004382 /* What we're expecting to see is:
4383 move r9, place_to_jump_to_EXPECTED
4384 jalr r9
4385 nop
4386 viz
petarjb92a9542013-02-27 22:57:17 +00004387 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
4388 0x120F809 # jalr r9
4389 0x00000000 # nop
sewardj362cf842012-06-07 08:59:53 +00004390 */
4391 UChar* p = (UChar*)place_to_unchain;
4392 vassert(0 == (3 & (HWord)p));
petarjb92a9542013-02-27 22:57:17 +00004393 vassert(isLoadImm_EXACTLY2or6(p, /*r*/ 9,
sewardj362cf842012-06-07 08:59:53 +00004394 Ptr_to_ULong(place_to_jump_to_EXPECTED),
4395 mode64));
petarjb92a9542013-02-27 22:57:17 +00004396 vassert(fetch32(p + (mode64 ? 24 : 8) + 0) == 0x120F809);
4397 vassert(fetch32(p + (mode64 ? 24 : 8) + 4) == 0x00000000);
sewardj362cf842012-06-07 08:59:53 +00004398 /* And what we want to change it to is:
4399 move r9, disp_cp_chain_me
4400 jalr r9
4401 nop
4402 viz
petarjb92a9542013-02-27 22:57:17 +00004403 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
4404 0x120F809 # jalr r9
4405 0x00000000 # nop
sewardj362cf842012-06-07 08:59:53 +00004406 The replacement has the same length as the original.
4407 */
petarjb92a9542013-02-27 22:57:17 +00004408 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
sewardj362cf842012-06-07 08:59:53 +00004409 Ptr_to_ULong(disp_cp_chain_me), mode64);
4410 p = emit32(p, 0x120F809);
4411 p = emit32(p, 0x00000000);
4412
4413 Int len = p - (UChar*)place_to_unchain;
petarjb92a9542013-02-27 22:57:17 +00004414 vassert(len == (mode64 ? 32 : 16)); /* stay sane */
sewardj362cf842012-06-07 08:59:53 +00004415 VexInvalRange vir = {(HWord)place_to_unchain, len};
4416 return vir;
4417}
4418
4419/* Patch the counter address into a profile inc point, as previously
4420 created by the Min_ProfInc case for emit_MIPSInstr. */
sewardj9b769162014-07-24 12:42:03 +00004421VexInvalRange patchProfInc_MIPS ( VexEndness endness_host,
4422 void* place_to_patch,
florian7d6f81d2014-09-22 21:43:37 +00004423 const ULong* location_of_counter,
4424 Bool mode64 )
sewardj362cf842012-06-07 08:59:53 +00004425{
sewardj9b769162014-07-24 12:42:03 +00004426 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
4427 if (mode64) {
petarjb92a9542013-02-27 22:57:17 +00004428 vassert(sizeof(ULong*) == 8);
sewardj9b769162014-07-24 12:42:03 +00004429 } else {
petarjb92a9542013-02-27 22:57:17 +00004430 vassert(sizeof(ULong*) == 4);
sewardj9b769162014-07-24 12:42:03 +00004431 }
sewardj362cf842012-06-07 08:59:53 +00004432 UChar* p = (UChar*)place_to_patch;
4433 vassert(0 == (3 & (HWord)p));
petarjb92a9542013-02-27 22:57:17 +00004434 vassert(isLoadImm_EXACTLY2or6((UChar *)p, /*r*/9,
4435 mode64 ? 0x6555655565556555ULL : 0x65556555,
4436 mode64));
sewardj362cf842012-06-07 08:59:53 +00004437
petarjb92a9542013-02-27 22:57:17 +00004438 if (mode64) {
4439 vassert(fetch32(p + 24 + 0) == 0xDD280000);
4440 vassert(fetch32(p + 24 + 4) == 0x65080001);
4441 vassert(fetch32(p + 24 + 8) == 0xFD280000);
4442 } else {
4443 vassert(fetch32(p + 8 + 0) == 0x8D280000);
4444 vassert(fetch32(p + 8 + 4) == 0x25080001);
4445 vassert(fetch32(p + 8 + 8) == 0xAD280000);
4446 vassert(fetch32(p + 8 + 12) == 0x2d010001);
4447 vassert(fetch32(p + 8 + 16) == 0x8d280004);
4448 vassert(fetch32(p + 8 + 20) == 0x01014021);
4449 vassert(fetch32(p + 8 + 24) == 0xad280004);
4450 }
sewardj362cf842012-06-07 08:59:53 +00004451
petarjb92a9542013-02-27 22:57:17 +00004452 p = mkLoadImm_EXACTLY2or6(p, /*r*/9,
sewardj362cf842012-06-07 08:59:53 +00004453 Ptr_to_ULong(location_of_counter), mode64);
4454
4455 VexInvalRange vir = {(HWord)p, 8};
4456 return vir;
4457}
4458
4459
4460/*---------------------------------------------------------------*/
4461/*--- end host_mips_defs.c ---*/
4462/*---------------------------------------------------------------*/