1
2 /*---------------------------------------------------------------*/
3 /*--- begin host_mips_defs.c ---*/
4 /*---------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2010-2017 RT-RK
11 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
39 /* Register number for guest state pointer in host code. */
40 #define GuestSP 23
41
42
43 /*---------------- Registers ----------------*/
44
getRRegUniverse_MIPS(Bool mode64)45 const RRegUniverse* getRRegUniverse_MIPS ( Bool mode64 )
46 {
47 /* The real-register universe is a big constant, so we just want to
48 initialise it once. rRegUniverse_MIPS_initted values: 0=not initted,
49 1=initted for 32-bit-mode, 2=initted for 64-bit-mode */
50 static RRegUniverse rRegUniverse_MIPS;
51 static UInt rRegUniverse_MIPS_initted = 0;
52
53 /* Handy shorthand, nothing more */
54 RRegUniverse* ru = &rRegUniverse_MIPS;
55
56 /* This isn't thread-safe. Sigh. */
57 UInt howNeeded = mode64 ? 2 : 1;
58 if (LIKELY(rRegUniverse_MIPS_initted == howNeeded))
59 return ru;
60
61 RRegUniverse__init(ru);
62
63 /* Add the registers. The initial segment of this array must be
64 those available for allocation by reg-alloc, and those that
65 follow are not available for allocation. */
66 ru->regs[ru->size++] = hregMIPS_GPR16(mode64);
67 ru->regs[ru->size++] = hregMIPS_GPR17(mode64);
68 ru->regs[ru->size++] = hregMIPS_GPR18(mode64);
69 ru->regs[ru->size++] = hregMIPS_GPR19(mode64);
70 ru->regs[ru->size++] = hregMIPS_GPR20(mode64);
71 ru->regs[ru->size++] = hregMIPS_GPR21(mode64);
72 ru->regs[ru->size++] = hregMIPS_GPR22(mode64);
73
74 ru->regs[ru->size++] = hregMIPS_GPR12(mode64);
75 ru->regs[ru->size++] = hregMIPS_GPR13(mode64);
76 ru->regs[ru->size++] = hregMIPS_GPR14(mode64);
77 ru->regs[ru->size++] = hregMIPS_GPR15(mode64);
78 ru->regs[ru->size++] = hregMIPS_GPR24(mode64);
79 /* s7 (=guest_state) */
80 ru->regs[ru->size++] = hregMIPS_F16(mode64);
81 ru->regs[ru->size++] = hregMIPS_F18(mode64);
82 ru->regs[ru->size++] = hregMIPS_F20(mode64);
83 ru->regs[ru->size++] = hregMIPS_F22(mode64);
84 ru->regs[ru->size++] = hregMIPS_F24(mode64);
85 ru->regs[ru->size++] = hregMIPS_F26(mode64);
86 ru->regs[ru->size++] = hregMIPS_F28(mode64);
87 ru->regs[ru->size++] = hregMIPS_F30(mode64);
88 if (!mode64) {
89 /* Fake double floating point */
90 ru->regs[ru->size++] = hregMIPS_D0(mode64);
91 ru->regs[ru->size++] = hregMIPS_D1(mode64);
92 ru->regs[ru->size++] = hregMIPS_D2(mode64);
93 ru->regs[ru->size++] = hregMIPS_D3(mode64);
94 ru->regs[ru->size++] = hregMIPS_D4(mode64);
95 ru->regs[ru->size++] = hregMIPS_D5(mode64);
96 ru->regs[ru->size++] = hregMIPS_D6(mode64);
97 ru->regs[ru->size++] = hregMIPS_D7(mode64);
98 }
99
100 ru->allocable = ru->size;
101 /* And other regs, not available to the allocator. */
102
103 ru->regs[ru->size++] = hregMIPS_HI(mode64);
104 ru->regs[ru->size++] = hregMIPS_LO(mode64);
105 ru->regs[ru->size++] = hregMIPS_GPR0(mode64);
106 ru->regs[ru->size++] = hregMIPS_GPR1(mode64);
107 ru->regs[ru->size++] = hregMIPS_GPR2(mode64);
108 ru->regs[ru->size++] = hregMIPS_GPR3(mode64);
109 ru->regs[ru->size++] = hregMIPS_GPR4(mode64);
110 ru->regs[ru->size++] = hregMIPS_GPR5(mode64);
111 ru->regs[ru->size++] = hregMIPS_GPR6(mode64);
112 ru->regs[ru->size++] = hregMIPS_GPR7(mode64);
113 ru->regs[ru->size++] = hregMIPS_GPR8(mode64);
114 ru->regs[ru->size++] = hregMIPS_GPR9(mode64);
115 ru->regs[ru->size++] = hregMIPS_GPR10(mode64);
116 ru->regs[ru->size++] = hregMIPS_GPR11(mode64);
117 ru->regs[ru->size++] = hregMIPS_GPR23(mode64);
118 ru->regs[ru->size++] = hregMIPS_GPR25(mode64);
119 ru->regs[ru->size++] = hregMIPS_GPR29(mode64);
120 ru->regs[ru->size++] = hregMIPS_GPR31(mode64);
121
122 rRegUniverse_MIPS_initted = howNeeded;
123
124 RRegUniverse__check_is_sane(ru);
125 return ru;
126 }
127
128
ppHRegMIPS(HReg reg,Bool mode64)129 void ppHRegMIPS(HReg reg, Bool mode64)
130 {
131 Int r;
132 static const HChar *ireg32_names[35]
133 = { "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
134 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
135 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
136 "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
137 "%32", "%33", "%34",
138 };
139
140 static const HChar *freg32_names[32]
141 = { "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
142 "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
143 "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
144 "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "f30", "$f31"
145 };
146
147 static const HChar *freg64_names[32]
148 = { "$d0", "$d1", "$d2", "$d3", "$d4", "$d5", "$d6", "$d7",
149 "$d8", "$d9", "$d10", "$d11", "$d12", "$d13", "$d14", "$d15",
150 };
151
152 /* Be generic for all virtual regs. */
153 if (hregIsVirtual(reg)) {
154 ppHReg(reg);
155 return;
156 }
157
158 /* But specific for real regs. */
159 vassert(hregClass(reg) == HRcInt32 || hregClass(reg) == HRcInt64 ||
160 hregClass(reg) == HRcFlt32 || hregClass(reg) == HRcFlt64);
161
162 /* But specific for real regs. */
163 switch (hregClass(reg)) {
164 case HRcInt32:
165 r = hregEncoding(reg);
166 vassert(r >= 0 && r < 32);
167 vex_printf("%s", ireg32_names[r]);
168 return;
169 case HRcInt64:
170 r = hregEncoding (reg);
171 vassert (r >= 0 && r < 32);
172 vex_printf ("%s", ireg32_names[r]);
173 return;
174 case HRcFlt32:
175 r = hregEncoding(reg);
176 vassert(r >= 0 && r < 32);
177 vex_printf("%s", freg32_names[r]);
178 return;
179 case HRcFlt64:
180 r = hregEncoding(reg);
181 vassert(r >= 0 && r < 32);
182 vex_printf("%s", freg64_names[r]);
183 return;
184 default:
185 vpanic("ppHRegMIPS");
186 break;
187 }
188
189 return;
190 }
191
192
193 /*----------------- Condition Codes ----------------------*/
194
showMIPSCondCode(MIPSCondCode cond)195 const HChar *showMIPSCondCode(MIPSCondCode cond)
196 {
197 const HChar* ret;
198 switch (cond) {
199 case MIPScc_EQ:
200 ret = "EQ"; /* equal */
201 break;
202 case MIPScc_NE:
203 ret = "NEQ"; /* not equal */
204 break;
205 case MIPScc_HS:
206 ret = "GE"; /* >=u (Greater Than or Equal) */
207 break;
208 case MIPScc_LO:
209 ret = "LT"; /* <u (lower) */
210 break;
211 case MIPScc_MI:
212 ret = "MI"; /* minus (negative) */
213 break;
214 case MIPScc_PL:
215 ret = "PL"; /* plus (zero or +ve) */
216 break;
217 case MIPScc_VS:
218 ret = "VS"; /* overflow */
219 break;
220 case MIPScc_VC:
221 ret = "VC"; /* no overflow */
222 break;
223 case MIPScc_HI:
224 ret = "HI"; /* >u (higher) */
225 break;
226 case MIPScc_LS:
227 ret = "LS"; /* <=u (lower or same) */
228 break;
229 case MIPScc_GE:
230 ret = "GE"; /* >=s (signed greater or equal) */
231 break;
232 case MIPScc_LT:
233 ret = "LT"; /* <s (signed less than) */
234 break;
235 case MIPScc_GT:
236 ret = "GT"; /* >s (signed greater) */
237 break;
238 case MIPScc_LE:
239 ret = "LE"; /* <=s (signed less or equal) */
240 break;
241 case MIPScc_AL:
242 ret = "AL"; /* always (unconditional) */
243 break;
244 case MIPScc_NV:
245 ret = "NV"; /* never (unconditional): */
246 break;
247 default:
248 vpanic("showMIPSCondCode");
249 break;
250 }
251 return ret;
252 }
253
showMIPSFpOp(MIPSFpOp op)254 const HChar *showMIPSFpOp(MIPSFpOp op)
255 {
256 const HChar *ret;
257 switch (op) {
258 case Mfp_ADDD:
259 ret = "add.d";
260 break;
261 case Mfp_SUBD:
262 ret = "sub.d";
263 break;
264 case Mfp_MULD:
265 ret = "mul.d";
266 break;
267 case Mfp_DIVD:
268 ret = "div.d";
269 break;
270 case Mfp_MADDD:
271 ret = "madd.d";
272 break;
273 case Mfp_MSUBD:
274 ret = "msub.d";
275 break;
276 case Mfp_MADDS:
277 ret = "madd.s";
278 break;
279 case Mfp_MSUBS:
280 ret = "msub.s";
281 break;
282 case Mfp_ADDS:
283 ret = "add.s";
284 break;
285 case Mfp_SUBS:
286 ret = "sub.s";
287 break;
288 case Mfp_MULS:
289 ret = "mul.s";
290 break;
291 case Mfp_DIVS:
292 ret = "div.s";
293 break;
294 case Mfp_SQRTS:
295 ret = "sqrt.s";
296 break;
297 case Mfp_SQRTD:
298 ret = "sqrt.d";
299 break;
300 case Mfp_ABSS:
301 ret = "abs.s";
302 break;
303 case Mfp_ABSD:
304 ret = "abs.d";
305 break;
306 case Mfp_NEGS:
307 ret = "neg.s";
308 break;
309 case Mfp_NEGD:
310 ret = "neg.d";
311 break;
312 case Mfp_MOVS:
313 ret = "mov.s";
314 break;
315 case Mfp_MOVD:
316 ret = "mov.d";
317 break;
318 case Mfp_ROUNDWS:
319 ret = "round.w.s";
320 break;
321 case Mfp_ROUNDWD:
322 ret = "round.w.d";
323 break;
324 case Mfp_ROUNDLD:
325 ret = "round.l.d";
326 break;
327 case Mfp_FLOORWS:
328 ret = "floor.w.s";
329 break;
330 case Mfp_FLOORWD:
331 ret = "floor.w.d";
332 break;
333 case Mfp_CVTDW:
334 ret = "cvt.d.w";
335 break;
336 case Mfp_CVTDL:
337 ret = "cvt.d.l";
338 break;
339 case Mfp_CVTDS:
340 ret = "cvt.d.s";
341 break;
342 case Mfp_CVTSD:
343 ret = "cvt.s.d";
344 break;
345 case Mfp_CVTSW:
346 ret = "cvt.s.w";
347 break;
348 case Mfp_CVTWS:
349 ret = "cvt.w.s";
350 break;
351 case Mfp_CVTWD:
352 ret = "cvt.w.d";
353 break;
354 case Mfp_CVTLD:
355 ret = "cvt.l.d";
356 break;
357 case Mfp_CVTLS:
358 ret = "cvt.l.s";
359 break;
360 case Mfp_TRUWD:
361 ret = "trunc.w.d";
362 break;
363 case Mfp_TRUWS:
364 ret = "trunc.w.s";
365 break;
366 case Mfp_TRULD:
367 ret = "trunc.l.d";
368 break;
369 case Mfp_TRULS:
370 ret = "trunc.l.s";
371 break;
372 case Mfp_CEILWS:
373 ret = "ceil.w.s";
374 break;
375 case Mfp_CEILWD:
376 ret = "ceil.w.d";
377 break;
378 case Mfp_CEILLS:
379 ret = "ceil.l.s";
380 break;
381 case Mfp_CEILLD:
382 ret = "ceil.l.d";
383 break;
384 case Mfp_CMP_UN:
385 ret = "c.un.d";
386 break;
387 case Mfp_CMP_EQ:
388 ret = "c.eq.d";
389 break;
390 case Mfp_CMP_LT:
391 ret = "c.lt.d";
392 break;
393 case Mfp_CMP_NGT:
394 ret = "c.ngt.d";
395 break;
396 default:
397 vex_printf("Unknown op: %d", (Int)op);
398 vpanic("showMIPSFpOp");
399 break;
400 }
401 return ret;
402 }
403
404 /* Show move from/to fpr to/from gpr */
showMIPSFpGpMoveOp(MIPSFpGpMoveOp op)405 const HChar* showMIPSFpGpMoveOp ( MIPSFpGpMoveOp op )
406 {
407 const HChar *ret;
408 switch (op) {
409 case MFpGpMove_mfc1:
410 ret = "mfc1";
411 break;
412 case MFpGpMove_dmfc1:
413 ret = "dmfc1";
414 break;
415 case MFpGpMove_mtc1:
416 ret = "mtc1";
417 break;
418 case MFpGpMove_dmtc1:
419 ret = "dmtc1";
420 break;
421 default:
422 vpanic("showMIPSFpGpMoveOp");
423 break;
424 }
425 return ret;
426 }
427
428 /* Show floating point move conditional */
showMIPSMoveCondOp(MIPSMoveCondOp op)429 const HChar* showMIPSMoveCondOp ( MIPSMoveCondOp op )
430 {
431 const HChar *ret;
432 switch (op) {
433 case MFpMoveCond_movns:
434 ret = "movn.s";
435 break;
436 case MFpMoveCond_movnd:
437 ret = "movn.d";
438 break;
439 case MMoveCond_movn:
440 ret = "movn";
441 break;
442 default:
443 vpanic("showMIPSFpMoveCondOp");
444 break;
445 }
446 return ret;
447 }
448
449 /* --------- MIPSAMode: memory address expressions. --------- */
450
MIPSAMode_IR(Int idx,HReg base)451 MIPSAMode *MIPSAMode_IR(Int idx, HReg base)
452 {
453 MIPSAMode *am = LibVEX_Alloc_inline(sizeof(MIPSAMode));
454 am->tag = Mam_IR;
455 am->Mam.IR.base = base;
456 am->Mam.IR.index = idx;
457
458 return am;
459 }
460
MIPSAMode_RR(HReg idx,HReg base)461 MIPSAMode *MIPSAMode_RR(HReg idx, HReg base)
462 {
463 MIPSAMode *am = LibVEX_Alloc_inline(sizeof(MIPSAMode));
464 am->tag = Mam_RR;
465 am->Mam.RR.base = base;
466 am->Mam.RR.index = idx;
467
468 return am;
469 }
470
dopyMIPSAMode(MIPSAMode * am)471 MIPSAMode *dopyMIPSAMode(MIPSAMode * am)
472 {
473 MIPSAMode* ret;
474 switch (am->tag) {
475 case Mam_IR:
476 ret = MIPSAMode_IR(am->Mam.IR.index, am->Mam.IR.base);
477 break;
478 case Mam_RR:
479 ret = MIPSAMode_RR(am->Mam.RR.index, am->Mam.RR.base);
480 break;
481 default:
482 vpanic("dopyMIPSAMode");
483 break;
484 }
485 return ret;
486 }
487
nextMIPSAModeFloat(MIPSAMode * am)488 MIPSAMode *nextMIPSAModeFloat(MIPSAMode * am)
489 {
490 MIPSAMode* ret;
491 switch (am->tag) {
492 case Mam_IR:
493 ret = MIPSAMode_IR(am->Mam.IR.index + 4, am->Mam.IR.base);
494 break;
495 case Mam_RR:
496 /* We can't do anything with the RR case, so if it appears
497 we simply have to give up. */
498 /* fallthrough */
499 default:
500 vpanic("nextMIPSAModeFloat");
501 break;
502 }
503 return ret;
504 }
505
nextMIPSAModeInt(MIPSAMode * am)506 MIPSAMode *nextMIPSAModeInt(MIPSAMode * am)
507 {
508 MIPSAMode* ret;
509 switch (am->tag) {
510 case Mam_IR:
511 ret = MIPSAMode_IR(am->Mam.IR.index + 4, am->Mam.IR.base);
512 break;
513 case Mam_RR:
514 /* We can't do anything with the RR case, so if it appears
515 we simply have to give up. */
516 /* fallthrough */
517 default:
518 vpanic("nextMIPSAModeInt");
519 break;
520 }
521 return ret;
522 }
523
ppMIPSAMode(MIPSAMode * am,Bool mode64)524 void ppMIPSAMode(MIPSAMode * am, Bool mode64)
525 {
526 switch (am->tag) {
527 case Mam_IR:
528 if (am->Mam.IR.index == 0)
529 vex_printf("0(");
530 else
531 vex_printf("%d(", (Int) am->Mam.IR.index);
532 ppHRegMIPS(am->Mam.IR.base, mode64);
533 vex_printf(")");
534 return;
535 case Mam_RR:
536 ppHRegMIPS(am->Mam.RR.base, mode64);
537 vex_printf(", ");
538 ppHRegMIPS(am->Mam.RR.index, mode64);
539 return;
540 default:
541 vpanic("ppMIPSAMode");
542 break;
543 }
544 }
545
addRegUsage_MIPSAMode(HRegUsage * u,MIPSAMode * am)546 static void addRegUsage_MIPSAMode(HRegUsage * u, MIPSAMode * am)
547 {
548 switch (am->tag) {
549 case Mam_IR:
550 addHRegUse(u, HRmRead, am->Mam.IR.base);
551 return;
552 case Mam_RR:
553 addHRegUse(u, HRmRead, am->Mam.RR.base);
554 addHRegUse(u, HRmRead, am->Mam.RR.index);
555 return;
556 default:
557 vpanic("addRegUsage_MIPSAMode");
558 break;
559 }
560 }
561
mapRegs_MIPSAMode(HRegRemap * m,MIPSAMode * am)562 static void mapRegs_MIPSAMode(HRegRemap * m, MIPSAMode * am)
563 {
564 switch (am->tag) {
565 case Mam_IR:
566 am->Mam.IR.base = lookupHRegRemap(m, am->Mam.IR.base);
567 return;
568 case Mam_RR:
569 am->Mam.RR.base = lookupHRegRemap(m, am->Mam.RR.base);
570 am->Mam.RR.index = lookupHRegRemap(m, am->Mam.RR.index);
571 return;
572 default:
573 vpanic("mapRegs_MIPSAMode");
574 break;
575 }
576 }
577
578 /* --------- Operand, which can be a reg or a u16/s16. --------- */
579
MIPSRH_Imm(Bool syned,UShort imm16)580 MIPSRH *MIPSRH_Imm(Bool syned, UShort imm16)
581 {
582 MIPSRH *op = LibVEX_Alloc_inline(sizeof(MIPSRH));
583 op->tag = Mrh_Imm;
584 op->Mrh.Imm.syned = syned;
585 op->Mrh.Imm.imm16 = imm16;
586 /* If this is a signed value, ensure it's not -32768, so that we
587 are guaranteed always to be able to negate if needed. */
588 if (syned)
589 vassert(imm16 != 0x8000);
590 vassert(syned == True || syned == False);
591 return op;
592 }
593
MIPSRH_Reg(HReg reg)594 MIPSRH *MIPSRH_Reg(HReg reg)
595 {
596 MIPSRH *op = LibVEX_Alloc_inline(sizeof(MIPSRH));
597 op->tag = Mrh_Reg;
598 op->Mrh.Reg.reg = reg;
599 return op;
600 }
601
ppMIPSRH(MIPSRH * op,Bool mode64)602 void ppMIPSRH(MIPSRH * op, Bool mode64)
603 {
604 MIPSRHTag tag = op->tag;
605 switch (tag) {
606 case Mrh_Imm:
607 if (op->Mrh.Imm.syned)
608 vex_printf("%d", (Int) (Short) op->Mrh.Imm.imm16);
609 else
610 vex_printf("%u", (UInt) (UShort) op->Mrh.Imm.imm16);
611 return;
612 case Mrh_Reg:
613 ppHRegMIPS(op->Mrh.Reg.reg, mode64);
614 return;
615 default:
616 vpanic("ppMIPSRH");
617 break;
618 }
619 }
620
621 /* An MIPSRH can only be used in a "read" context (what would it mean
622 to write or modify a literal?) and so we enumerate its registers
623 accordingly. */
addRegUsage_MIPSRH(HRegUsage * u,MIPSRH * op)624 static void addRegUsage_MIPSRH(HRegUsage * u, MIPSRH * op)
625 {
626 switch (op->tag) {
627 case Mrh_Imm:
628 return;
629 case Mrh_Reg:
630 addHRegUse(u, HRmRead, op->Mrh.Reg.reg);
631 return;
632 default:
633 vpanic("addRegUsage_MIPSRH");
634 break;
635 }
636 }
637
mapRegs_MIPSRH(HRegRemap * m,MIPSRH * op)638 static void mapRegs_MIPSRH(HRegRemap * m, MIPSRH * op)
639 {
640 switch (op->tag) {
641 case Mrh_Imm:
642 return;
643 case Mrh_Reg:
644 op->Mrh.Reg.reg = lookupHRegRemap(m, op->Mrh.Reg.reg);
645 return;
646 default:
647 vpanic("mapRegs_MIPSRH");
648 break;
649 }
650 }
651
652 /* --------- Instructions. --------- */
653
showMIPSUnaryOp(MIPSUnaryOp op)654 const HChar *showMIPSUnaryOp(MIPSUnaryOp op)
655 {
656 const HChar* ret;
657 switch (op) {
658 case Mun_CLO:
659 ret = "clo";
660 break;
661 case Mun_CLZ:
662 ret = "clz";
663 break;
664 case Mun_NOP:
665 ret = "nop";
666 break;
667 case Mun_DCLO:
668 ret = "dclo";
669 break;
670 case Mun_DCLZ:
671 ret = "dclz";
672 break;
673 default:
674 vpanic("showMIPSUnaryOp");
675 break;
676 }
677 return ret;
678 }
679
showMIPSAluOp(MIPSAluOp op,Bool immR)680 const HChar *showMIPSAluOp(MIPSAluOp op, Bool immR)
681 {
682 const HChar* ret;
683 switch (op) {
684 case Malu_ADD:
685 ret = immR ? "addiu" : "addu";
686 break;
687 case Malu_SUB:
688 ret = "subu";
689 break;
690 case Malu_AND:
691 ret = immR ? "andi" : "and";
692 break;
693 case Malu_OR:
694 ret = immR ? "ori" : "or";
695 break;
696 case Malu_NOR:
697 vassert(immR == False); /*there's no nor with an immediate operand!? */
698 ret = "nor";
699 break;
700 case Malu_XOR:
701 ret = immR ? "xori" : "xor";
702 break;
703 case Malu_DADD:
704 ret = immR ? "daddi" : "dadd";
705 break;
706 case Malu_DSUB:
707 ret = immR ? "dsubi" : "dsub";
708 break;
709 case Malu_SLT:
710 ret = immR ? "slti" : "slt";
711 break;
712 default:
713 vpanic("showMIPSAluOp");
714 break;
715 }
716 return ret;
717 }
718
showMIPSShftOp(MIPSShftOp op,Bool immR,Bool sz32)719 const HChar *showMIPSShftOp(MIPSShftOp op, Bool immR, Bool sz32)
720 {
721 const HChar *ret;
722 switch (op) {
723 case Mshft_SRA:
724 ret = immR ? (sz32 ? "sra" : "dsra") : (sz32 ? "srav" : "dsrav");
725 break;
726 case Mshft_SLL:
727 ret = immR ? (sz32 ? "sll" : "dsll") : (sz32 ? "sllv" : "dsllv");
728 break;
729 case Mshft_SRL:
730 ret = immR ? (sz32 ? "srl" : "dsrl") : (sz32 ? "srlv" : "dsrlv");
731 break;
732 default:
733 vpanic("showMIPSShftOp");
734 break;
735 }
736 return ret;
737 }
738
showMIPSMaccOp(MIPSMaccOp op,Bool variable)739 const HChar *showMIPSMaccOp(MIPSMaccOp op, Bool variable)
740 {
741 const HChar *ret;
742 switch (op) {
743 case Macc_ADD:
744 ret = variable ? "madd" : "maddu";
745 break;
746 case Macc_SUB:
747 ret = variable ? "msub" : "msubu";
748 break;
749 default:
750 vpanic("showMIPSAccOp");
751 break;
752 }
753 return ret;
754 }
755
MIPSInstr_LI(HReg dst,ULong imm)756 MIPSInstr *MIPSInstr_LI(HReg dst, ULong imm)
757 {
758 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
759 i->tag = Min_LI;
760 i->Min.LI.dst = dst;
761 i->Min.LI.imm = imm;
762 return i;
763 }
764
MIPSInstr_Alu(MIPSAluOp op,HReg dst,HReg srcL,MIPSRH * srcR)765 MIPSInstr *MIPSInstr_Alu(MIPSAluOp op, HReg dst, HReg srcL, MIPSRH * srcR)
766 {
767 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
768 i->tag = Min_Alu;
769 i->Min.Alu.op = op;
770 i->Min.Alu.dst = dst;
771 i->Min.Alu.srcL = srcL;
772 i->Min.Alu.srcR = srcR;
773 return i;
774 }
775
MIPSInstr_Shft(MIPSShftOp op,Bool sz32,HReg dst,HReg srcL,MIPSRH * srcR)776 MIPSInstr *MIPSInstr_Shft(MIPSShftOp op, Bool sz32, HReg dst, HReg srcL,
777 MIPSRH * srcR)
778 {
779 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
780 i->tag = Min_Shft;
781 i->Min.Shft.op = op;
782 i->Min.Shft.sz32 = sz32;
783 i->Min.Shft.dst = dst;
784 i->Min.Shft.srcL = srcL;
785 i->Min.Shft.srcR = srcR;
786 return i;
787 }
788
MIPSInstr_Unary(MIPSUnaryOp op,HReg dst,HReg src)789 MIPSInstr *MIPSInstr_Unary(MIPSUnaryOp op, HReg dst, HReg src)
790 {
791 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
792 i->tag = Min_Unary;
793 i->Min.Unary.op = op;
794 i->Min.Unary.dst = dst;
795 i->Min.Unary.src = src;
796 return i;
797 }
798
MIPSInstr_Cmp(Bool syned,Bool sz32,HReg dst,HReg srcL,HReg srcR,MIPSCondCode cond)799 MIPSInstr *MIPSInstr_Cmp(Bool syned, Bool sz32, HReg dst, HReg srcL, HReg srcR,
800 MIPSCondCode cond)
801 {
802 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
803 i->tag = Min_Cmp;
804 i->Min.Cmp.syned = syned;
805 i->Min.Cmp.sz32 = sz32;
806 i->Min.Cmp.dst = dst;
807 i->Min.Cmp.srcL = srcL;
808 i->Min.Cmp.srcR = srcR;
809 i->Min.Cmp.cond = cond;
810 return i;
811 }
812
813 /* multiply */
MIPSInstr_Mul(Bool syned,Bool wid,Bool sz32,HReg dst,HReg srcL,HReg srcR)814 MIPSInstr *MIPSInstr_Mul(Bool syned, Bool wid, Bool sz32, HReg dst, HReg srcL,
815 HReg srcR)
816 {
817 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
818 i->tag = Min_Mul;
819 i->Min.Mul.syned = syned;
820 i->Min.Mul.widening = wid; /* widen=True else False */
821 i->Min.Mul.sz32 = sz32; /* True = 32 bits */
822 i->Min.Mul.dst = dst;
823 i->Min.Mul.srcL = srcL;
824 i->Min.Mul.srcR = srcR;
825 return i;
826 }
827
828 /* msub */
MIPSInstr_Msub(Bool syned,HReg srcL,HReg srcR)829 MIPSInstr *MIPSInstr_Msub(Bool syned, HReg srcL, HReg srcR)
830 {
831 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
832 i->tag = Min_Macc;
833
834 i->Min.Macc.op = Macc_SUB;
835 i->Min.Macc.syned = syned;
836 i->Min.Macc.srcL = srcL;
837 i->Min.Macc.srcR = srcR;
838 return i;
839 }
840
841 /* madd */
MIPSInstr_Madd(Bool syned,HReg srcL,HReg srcR)842 MIPSInstr *MIPSInstr_Madd(Bool syned, HReg srcL, HReg srcR)
843 {
844 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
845 i->tag = Min_Macc;
846
847 i->Min.Macc.op = Macc_ADD;
848 i->Min.Macc.syned = syned;
849 i->Min.Macc.srcL = srcL;
850 i->Min.Macc.srcR = srcR;
851 return i;
852 }
853
854 /* div */
MIPSInstr_Div(Bool syned,Bool sz32,HReg srcL,HReg srcR)855 MIPSInstr *MIPSInstr_Div(Bool syned, Bool sz32, HReg srcL, HReg srcR)
856 {
857 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
858 i->tag = Min_Div;
859 i->Min.Div.syned = syned;
860 i->Min.Div.sz32 = sz32; /* True = 32 bits */
861 i->Min.Div.srcL = srcL;
862 i->Min.Div.srcR = srcR;
863 return i;
864 }
865
MIPSInstr_Call(MIPSCondCode cond,Addr64 target,UInt argiregs,HReg src,RetLoc rloc)866 MIPSInstr *MIPSInstr_Call ( MIPSCondCode cond, Addr64 target, UInt argiregs,
867 HReg src, RetLoc rloc )
868 {
869 UInt mask;
870 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
871 i->tag = Min_Call;
872 i->Min.Call.cond = cond;
873 i->Min.Call.target = target;
874 i->Min.Call.argiregs = argiregs;
875 i->Min.Call.src = src;
876 i->Min.Call.rloc = rloc;
877 /* Only $4 .. $7/$11 inclusive may be used as arg regs. */
878 mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
879 | (1 << 10) | (1 << 11);
880 vassert(0 == (argiregs & ~mask));
881 vassert(is_sane_RetLoc(rloc));
882 return i;
883 }
884
MIPSInstr_CallAlways(MIPSCondCode cond,Addr64 target,UInt argiregs,RetLoc rloc)885 MIPSInstr *MIPSInstr_CallAlways ( MIPSCondCode cond, Addr64 target,
886 UInt argiregs, RetLoc rloc )
887 {
888 UInt mask;
889 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
890 i->tag = Min_Call;
891 i->Min.Call.cond = cond;
892 i->Min.Call.target = target;
893 i->Min.Call.argiregs = argiregs;
894 i->Min.Call.rloc = rloc;
895 /* Only $4 .. $7/$11 inclusive may be used as arg regs. */
896 mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
897 | (1 << 10) | (1 << 11);
898 vassert(0 == (argiregs & ~mask));
899 vassert(is_sane_RetLoc(rloc));
900 return i;
901 }
902
MIPSInstr_XDirect(Addr64 dstGA,MIPSAMode * amPC,MIPSCondCode cond,Bool toFastEP)903 MIPSInstr *MIPSInstr_XDirect ( Addr64 dstGA, MIPSAMode* amPC,
904 MIPSCondCode cond, Bool toFastEP ) {
905 MIPSInstr* i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
906 i->tag = Min_XDirect;
907 i->Min.XDirect.dstGA = dstGA;
908 i->Min.XDirect.amPC = amPC;
909 i->Min.XDirect.cond = cond;
910 i->Min.XDirect.toFastEP = toFastEP;
911 return i;
912 }
913
MIPSInstr_XIndir(HReg dstGA,MIPSAMode * amPC,MIPSCondCode cond)914 MIPSInstr *MIPSInstr_XIndir ( HReg dstGA, MIPSAMode* amPC,
915 MIPSCondCode cond ) {
916 MIPSInstr* i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
917 i->tag = Min_XIndir;
918 i->Min.XIndir.dstGA = dstGA;
919 i->Min.XIndir.amPC = amPC;
920 i->Min.XIndir.cond = cond;
921 return i;
922 }
923
MIPSInstr_XAssisted(HReg dstGA,MIPSAMode * amPC,MIPSCondCode cond,IRJumpKind jk)924 MIPSInstr *MIPSInstr_XAssisted ( HReg dstGA, MIPSAMode* amPC,
925 MIPSCondCode cond, IRJumpKind jk ) {
926 MIPSInstr* i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
927 i->tag = Min_XAssisted;
928 i->Min.XAssisted.dstGA = dstGA;
929 i->Min.XAssisted.amPC = amPC;
930 i->Min.XAssisted.cond = cond;
931 i->Min.XAssisted.jk = jk;
932 return i;
933 }
934
MIPSInstr_Load(UChar sz,HReg dst,MIPSAMode * src,Bool mode64)935 MIPSInstr *MIPSInstr_Load(UChar sz, HReg dst, MIPSAMode * src, Bool mode64)
936 {
937 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
938 i->tag = Min_Load;
939 i->Min.Load.sz = sz;
940 i->Min.Load.src = src;
941 i->Min.Load.dst = dst;
942 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
943
944 if (sz == 8)
945 vassert(mode64);
946 return i;
947 }
948
MIPSInstr_Store(UChar sz,MIPSAMode * dst,HReg src,Bool mode64)949 MIPSInstr *MIPSInstr_Store(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
950 {
951 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
952 i->tag = Min_Store;
953 i->Min.Store.sz = sz;
954 i->Min.Store.src = src;
955 i->Min.Store.dst = dst;
956 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
957
958 if (sz == 8)
959 vassert(mode64);
960 return i;
961 }
962
MIPSInstr_LoadL(UChar sz,HReg dst,MIPSAMode * src,Bool mode64)963 MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src, Bool mode64)
964 {
965 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
966 i->tag = Min_LoadL;
967 i->Min.LoadL.sz = sz;
968 i->Min.LoadL.src = src;
969 i->Min.LoadL.dst = dst;
970 vassert(sz == 4 || sz == 8);
971
972 if (sz == 8)
973 vassert(mode64);
974 return i;
975 }
976
MIPSInstr_Cas(UChar sz,HReg old,HReg addr,HReg expd,HReg data,Bool mode64)977 MIPSInstr *MIPSInstr_Cas(UChar sz, HReg old, HReg addr,
978 HReg expd, HReg data, Bool mode64)
979 {
980 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
981 i->tag = Min_Cas;
982 i->Min.Cas.sz = sz;
983 i->Min.Cas.old = old;
984 i->Min.Cas.addr = addr;
985 i->Min.Cas.expd = expd;
986 i->Min.Cas.data = data;
987 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
988
989 if (sz == 8)
990 vassert(mode64);
991 return i;
992 }
993
MIPSInstr_StoreC(UChar sz,MIPSAMode * dst,HReg src,Bool mode64)994 MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
995 {
996 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
997 i->tag = Min_StoreC;
998 i->Min.StoreC.sz = sz;
999 i->Min.StoreC.src = src;
1000 i->Min.StoreC.dst = dst;
1001 vassert(sz == 4 || sz == 8);
1002
1003 if (sz == 8)
1004 vassert(mode64);
1005 return i;
1006 }
1007
MIPSInstr_Mthi(HReg src)1008 MIPSInstr *MIPSInstr_Mthi(HReg src)
1009 {
1010 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1011 i->tag = Min_Mthi;
1012 i->Min.MtHL.src = src;
1013 return i;
1014 }
1015
MIPSInstr_Mtlo(HReg src)1016 MIPSInstr *MIPSInstr_Mtlo(HReg src)
1017 {
1018 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1019 i->tag = Min_Mtlo;
1020 i->Min.MtHL.src = src;
1021 return i;
1022 }
1023
MIPSInstr_Mfhi(HReg dst)1024 MIPSInstr *MIPSInstr_Mfhi(HReg dst)
1025 {
1026 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1027 i->tag = Min_Mfhi;
1028 i->Min.MfHL.dst = dst;
1029 return i;
1030 }
1031
MIPSInstr_Mflo(HReg dst)1032 MIPSInstr *MIPSInstr_Mflo(HReg dst)
1033 {
1034 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1035 i->tag = Min_Mflo;
1036 i->Min.MfHL.dst = dst;
1037 return i;
1038 }
1039
1040 /* Read/Write Link Register */
MIPSInstr_RdWrLR(Bool wrLR,HReg gpr)1041 MIPSInstr *MIPSInstr_RdWrLR(Bool wrLR, HReg gpr)
1042 {
1043 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1044 i->tag = Min_RdWrLR;
1045 i->Min.RdWrLR.wrLR = wrLR;
1046 i->Min.RdWrLR.gpr = gpr;
1047 return i;
1048 }
1049
MIPSInstr_FpLdSt(Bool isLoad,UChar sz,HReg reg,MIPSAMode * addr)1050 MIPSInstr *MIPSInstr_FpLdSt(Bool isLoad, UChar sz, HReg reg, MIPSAMode * addr)
1051 {
1052 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1053 i->tag = Min_FpLdSt;
1054 i->Min.FpLdSt.isLoad = isLoad;
1055 i->Min.FpLdSt.sz = sz;
1056 i->Min.FpLdSt.reg = reg;
1057 i->Min.FpLdSt.addr = addr;
1058 vassert(sz == 4 || sz == 8);
1059 return i;
1060 }
1061
MIPSInstr_FpUnary(MIPSFpOp op,HReg dst,HReg src)1062 MIPSInstr *MIPSInstr_FpUnary(MIPSFpOp op, HReg dst, HReg src)
1063 {
1064 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1065 i->tag = Min_FpUnary;
1066 i->Min.FpUnary.op = op;
1067 i->Min.FpUnary.dst = dst;
1068 i->Min.FpUnary.src = src;
1069 return i;
1070 }
1071
MIPSInstr_FpBinary(MIPSFpOp op,HReg dst,HReg srcL,HReg srcR)1072 MIPSInstr *MIPSInstr_FpBinary(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR)
1073 {
1074 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1075 i->tag = Min_FpBinary;
1076 i->Min.FpBinary.op = op;
1077 i->Min.FpBinary.dst = dst;
1078 i->Min.FpBinary.srcL = srcL;
1079 i->Min.FpBinary.srcR = srcR;
1080 return i;
1081 }
1082
MIPSInstr_FpTernary(MIPSFpOp op,HReg dst,HReg src1,HReg src2,HReg src3)1083 MIPSInstr *MIPSInstr_FpTernary ( MIPSFpOp op, HReg dst, HReg src1, HReg src2,
1084 HReg src3 )
1085 {
1086 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1087 i->tag = Min_FpTernary;
1088 i->Min.FpTernary.op = op;
1089 i->Min.FpTernary.dst = dst;
1090 i->Min.FpTernary.src1 = src1;
1091 i->Min.FpTernary.src2 = src2;
1092 i->Min.FpTernary.src3 = src3;
1093 return i;
1094 }
1095
MIPSInstr_FpConvert(MIPSFpOp op,HReg dst,HReg src)1096 MIPSInstr *MIPSInstr_FpConvert(MIPSFpOp op, HReg dst, HReg src)
1097 {
1098 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1099 i->tag = Min_FpConvert;
1100 i->Min.FpConvert.op = op;
1101 i->Min.FpConvert.dst = dst;
1102 i->Min.FpConvert.src = src;
1103 return i;
1104
1105 }
1106
MIPSInstr_FpCompare(MIPSFpOp op,HReg dst,HReg srcL,HReg srcR)1107 MIPSInstr *MIPSInstr_FpCompare(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR)
1108 {
1109 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1110 i->tag = Min_FpCompare;
1111 i->Min.FpCompare.op = op;
1112 i->Min.FpCompare.dst = dst;
1113 i->Min.FpCompare.srcL = srcL;
1114 i->Min.FpCompare.srcR = srcR;
1115 return i;
1116 }
1117
MIPSInstr_MtFCSR(HReg src)1118 MIPSInstr *MIPSInstr_MtFCSR(HReg src)
1119 {
1120 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1121 i->tag = Min_MtFCSR;
1122 i->Min.MtFCSR.src = src;
1123 return i;
1124 }
1125
MIPSInstr_MfFCSR(HReg dst)1126 MIPSInstr *MIPSInstr_MfFCSR(HReg dst)
1127 {
1128 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1129 i->tag = Min_MfFCSR;
1130 i->Min.MfFCSR.dst = dst;
1131 return i;
1132 }
1133
MIPSInstr_FpGpMove(MIPSFpGpMoveOp op,HReg dst,HReg src)1134 MIPSInstr *MIPSInstr_FpGpMove ( MIPSFpGpMoveOp op, HReg dst, HReg src )
1135 {
1136 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1137 i->tag = Min_FpGpMove;
1138 i->Min.FpGpMove.op = op;
1139 i->Min.FpGpMove.dst = dst;
1140 i->Min.FpGpMove.src = src;
1141 return i;
1142 }
1143
MIPSInstr_MoveCond(MIPSMoveCondOp op,HReg dst,HReg src,HReg cond)1144 MIPSInstr *MIPSInstr_MoveCond ( MIPSMoveCondOp op, HReg dst, HReg src,
1145 HReg cond )
1146 {
1147 MIPSInstr *i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1148 i->tag = Min_MoveCond;
1149 i->Min.MoveCond.op = op;
1150 i->Min.MoveCond.dst = dst;
1151 i->Min.MoveCond.src = src;
1152 i->Min.MoveCond.cond = cond;
1153 return i;
1154 }
1155
MIPSInstr_EvCheck(MIPSAMode * amCounter,MIPSAMode * amFailAddr)1156 MIPSInstr *MIPSInstr_EvCheck ( MIPSAMode* amCounter,
1157 MIPSAMode* amFailAddr ) {
1158 MIPSInstr* i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1159 i->tag = Min_EvCheck;
1160 i->Min.EvCheck.amCounter = amCounter;
1161 i->Min.EvCheck.amFailAddr = amFailAddr;
1162 return i;
1163 }
1164
MIPSInstr_ProfInc(void)1165 MIPSInstr* MIPSInstr_ProfInc ( void ) {
1166 MIPSInstr* i = LibVEX_Alloc_inline(sizeof(MIPSInstr));
1167 i->tag = Min_ProfInc;
1168 return i;
1169 }
1170
1171 /* -------- Pretty Print instructions ------------- */
ppLoadImm(HReg dst,ULong imm,Bool mode64)1172 static void ppLoadImm(HReg dst, ULong imm, Bool mode64)
1173 {
1174 vex_printf("li ");
1175 ppHRegMIPS(dst, mode64);
1176 vex_printf(",0x%016llx", imm);
1177 }
1178
ppMIPSInstr(const MIPSInstr * i,Bool mode64)1179 void ppMIPSInstr(const MIPSInstr * i, Bool mode64)
1180 {
1181 switch (i->tag) {
1182 case Min_LI:
1183 ppLoadImm(i->Min.LI.dst, i->Min.LI.imm, mode64);
1184 break;
1185 case Min_Alu: {
1186 HReg r_srcL = i->Min.Alu.srcL;
1187 MIPSRH *rh_srcR = i->Min.Alu.srcR;
1188 /* generic */
1189 vex_printf("%s ", showMIPSAluOp(i->Min.Alu.op,
1190 toBool(rh_srcR->tag == Mrh_Imm)));
1191 ppHRegMIPS(i->Min.Alu.dst, mode64);
1192 vex_printf(",");
1193 ppHRegMIPS(r_srcL, mode64);
1194 vex_printf(",");
1195 ppMIPSRH(rh_srcR, mode64);
1196 return;
1197 }
1198 case Min_Shft: {
1199 HReg r_srcL = i->Min.Shft.srcL;
1200 MIPSRH *rh_srcR = i->Min.Shft.srcR;
1201 vex_printf("%s ", showMIPSShftOp(i->Min.Shft.op,
1202 toBool(rh_srcR->tag == Mrh_Imm),
1203 i->Min.Shft.sz32));
1204 ppHRegMIPS(i->Min.Shft.dst, mode64);
1205 vex_printf(",");
1206 ppHRegMIPS(r_srcL, mode64);
1207 vex_printf(",");
1208 ppMIPSRH(rh_srcR, mode64);
1209 return;
1210 }
1211 case Min_Unary: {
1212 vex_printf("%s ", showMIPSUnaryOp(i->Min.Unary.op));
1213 ppHRegMIPS(i->Min.Unary.dst, mode64);
1214 vex_printf(",");
1215 ppHRegMIPS(i->Min.Unary.src, mode64);
1216 return;
1217 }
1218 case Min_Cmp: {
1219 vex_printf("word_compare ");
1220 ppHRegMIPS(i->Min.Cmp.dst, mode64);
1221 vex_printf(" = %s ( ", showMIPSCondCode(i->Min.Cmp.cond));
1222 ppHRegMIPS(i->Min.Cmp.srcL, mode64);
1223 vex_printf(", ");
1224 ppHRegMIPS(i->Min.Cmp.srcR, mode64);
1225 vex_printf(" )");
1226
1227 return;
1228 }
1229 case Min_Mul: {
1230 switch (i->Min.Mul.widening) {
1231 case False:
1232 vex_printf("mul ");
1233 ppHRegMIPS(i->Min.Mul.dst, mode64);
1234 vex_printf(", ");
1235 ppHRegMIPS(i->Min.Mul.srcL, mode64);
1236 vex_printf(", ");
1237 ppHRegMIPS(i->Min.Mul.srcR, mode64);
1238 return;
1239 case True:
1240 vex_printf("%s%s ", i->Min.Mul.sz32 ? "mult" : "dmult",
1241 i->Min.Mul.syned ? "" : "u");
1242 ppHRegMIPS(i->Min.Mul.dst, mode64);
1243 vex_printf(", ");
1244 ppHRegMIPS(i->Min.Mul.srcL, mode64);
1245 vex_printf(", ");
1246 ppHRegMIPS(i->Min.Mul.srcR, mode64);
1247 return;
1248 }
1249 break;
1250 }
1251 case Min_Mthi: {
1252 vex_printf("mthi ");
1253 ppHRegMIPS(i->Min.MtHL.src, mode64);
1254 return;
1255 }
1256 case Min_Mtlo: {
1257 vex_printf("mtlo ");
1258 ppHRegMIPS(i->Min.MtHL.src, mode64);
1259 return;
1260 }
1261 case Min_Mfhi: {
1262 vex_printf("mfhi ");
1263 ppHRegMIPS(i->Min.MfHL.dst, mode64);
1264 return;
1265 }
1266 case Min_Mflo: {
1267 vex_printf("mflo ");
1268 ppHRegMIPS(i->Min.MfHL.dst, mode64);
1269 return;
1270 }
1271 case Min_Macc: {
1272 vex_printf("%s ", showMIPSMaccOp(i->Min.Macc.op, i->Min.Macc.syned));
1273 ppHRegMIPS(i->Min.Macc.srcL, mode64);
1274 vex_printf(", ");
1275 ppHRegMIPS(i->Min.Macc.srcR, mode64);
1276 return;
1277 }
1278 case Min_Div: {
1279 if (!i->Min.Div.sz32)
1280 vex_printf("d");
1281 vex_printf("div");
1282 vex_printf("%s ", i->Min.Div.syned ? "s" : "u");
1283 ppHRegMIPS(i->Min.Div.srcL, mode64);
1284 vex_printf(", ");
1285 ppHRegMIPS(i->Min.Div.srcR, mode64);
1286 return;
1287 }
1288 case Min_Call: {
1289 Int n;
1290 vex_printf("call: ");
1291 if (i->Min.Call.cond != MIPScc_AL) {
1292 vex_printf("if (%s) ", showMIPSCondCode(i->Min.Call.cond));
1293 }
1294 vex_printf(" {");
1295 if (!mode64)
1296 vex_printf(" addiu $29, $29, -16");
1297
1298 ppLoadImm(hregMIPS_GPR25(mode64), i->Min.Call.target, mode64);
1299
1300 vex_printf(" ; jarl $31, $25; # args [");
1301 for (n = 0; n < 32; n++) {
1302 if (i->Min.Call.argiregs & (1 << n)) {
1303 vex_printf("$%d", n);
1304 if ((i->Min.Call.argiregs >> n) > 1)
1305 vex_printf(",");
1306 }
1307 }
1308 vex_printf("] nop; ");
1309 if (!mode64)
1310 vex_printf("addiu $29, $29, 16; ]");
1311
1312 break;
1313 }
1314 case Min_XDirect:
1315 vex_printf("(xDirect) ");
1316 vex_printf("if (guest_COND.%s) { ",
1317 showMIPSCondCode(i->Min.XDirect.cond));
1318 vex_printf("move $9, 0x%x,", (UInt)i->Min.XDirect.dstGA);
1319 vex_printf("; sw $9, ");
1320 ppMIPSAMode(i->Min.XDirect.amPC, mode64);
1321 vex_printf("; move $9, $disp_cp_chain_me_to_%sEP; jalr $9; nop}",
1322 i->Min.XDirect.toFastEP ? "fast" : "slow");
1323 return;
1324 case Min_XIndir:
1325 vex_printf("(xIndir) ");
1326 vex_printf("if (guest_COND.%s) { sw ",
1327 showMIPSCondCode(i->Min.XIndir.cond));
1328 ppHRegMIPS(i->Min.XIndir.dstGA, mode64);
1329 vex_printf(", ");
1330 ppMIPSAMode(i->Min.XIndir.amPC, mode64);
1331 vex_printf("; move $9, $disp_indir; jalr $9; nop}");
1332 return;
1333 case Min_XAssisted:
1334 vex_printf("(xAssisted) ");
1335 vex_printf("if (guest_COND.%s) { ",
1336 showMIPSCondCode(i->Min.XAssisted.cond));
1337 vex_printf("sw ");
1338 ppHRegMIPS(i->Min.XAssisted.dstGA, mode64);
1339 vex_printf(", ");
1340 ppMIPSAMode(i->Min.XAssisted.amPC, mode64);
1341 vex_printf("; move $9, $IRJumpKind_to_TRCVAL(%d)",
1342 (Int)i->Min.XAssisted.jk);
1343 vex_printf("; move $9, $disp_assisted; jalr $9; nop; }");
1344 return;
1345 case Min_Load: {
1346 Bool idxd = toBool(i->Min.Load.src->tag == Mam_RR);
1347 UChar sz = i->Min.Load.sz;
1348 HChar c_sz = sz == 1 ? 'b' : sz == 2 ? 'h' : sz == 4 ? 'w' : 'd';
1349 vex_printf("l%c%s ", c_sz, idxd ? "x" : "");
1350 ppHRegMIPS(i->Min.Load.dst, mode64);
1351 vex_printf(",");
1352 ppMIPSAMode(i->Min.Load.src, mode64);
1353 return;
1354 }
1355 case Min_Store: {
1356 UChar sz = i->Min.Store.sz;
1357 Bool idxd = toBool(i->Min.Store.dst->tag == Mam_RR);
1358 HChar c_sz = sz == 1 ? 'b' : sz == 2 ? 'h' : sz == 4 ? 'w' : 'd';
1359 vex_printf("s%c%s ", c_sz, idxd ? "x" : "");
1360 ppHRegMIPS(i->Min.Store.src, mode64);
1361 vex_printf(",");
1362 ppMIPSAMode(i->Min.Store.dst, mode64);
1363 return;
1364 }
1365 case Min_LoadL: {
1366 vex_printf("ll ");
1367 ppHRegMIPS(i->Min.LoadL.dst, mode64);
1368 vex_printf(",");
1369 ppMIPSAMode(i->Min.LoadL.src, mode64);
1370 return;
1371 }
1372 case Min_Cas: {
1373 Bool sz8 = toBool(i->Min.Cas.sz == 8);
1374 /*
1375 * ll(d) old, 0(addr)
1376 * bne old, expd, end
1377 * nop
1378 * (d)addiu old, old, 1
1379 * sc(d) data, 0(addr)
1380 * movn old, expd, data
1381 * end:
1382 */
1383 // ll(d) old, 0(addr)
1384 vex_printf("cas: ");
1385
1386 vex_printf("%s ", sz8 ? "lld" : "ll");
1387 ppHRegMIPS(i->Min.Cas.old , mode64);
1388 vex_printf(", 0(");
1389 ppHRegMIPS(i->Min.Cas.addr , mode64);
1390 vex_printf(")\n");
1391
1392 vex_printf("bne ");
1393 ppHRegMIPS(i->Min.Cas.old , mode64);
1394 vex_printf(", ");
1395 ppHRegMIPS(i->Min.Cas.expd , mode64);
1396 vex_printf(", end\n");
1397
1398 vex_printf("nop\n");
1399
1400 vex_printf("%s ", sz8 ? "daddiu" : "addiu");
1401 ppHRegMIPS(i->Min.Cas.old , mode64);
1402 vex_printf(", ");
1403 ppHRegMIPS(i->Min.Cas.old , mode64);
1404 vex_printf(", 1\n");
1405
1406 vex_printf("%s ", sz8 ? "scd" : "sc");
1407 ppHRegMIPS(i->Min.Cas.data , mode64);
1408 vex_printf(", 0(");
1409 ppHRegMIPS(i->Min.Cas.addr , mode64);
1410 vex_printf(")\n");
1411
1412 vex_printf("movn ");
1413 ppHRegMIPS(i->Min.Cas.old , mode64);
1414 vex_printf(", ");
1415 ppHRegMIPS(i->Min.Cas.expd , mode64);
1416 vex_printf(", ");
1417 ppHRegMIPS(i->Min.Cas.data , mode64);
1418 vex_printf("\nend:");
1419 return;
1420 }
1421 case Min_StoreC: {
1422 vex_printf("sc ");
1423 ppHRegMIPS(i->Min.StoreC.src, mode64);
1424 vex_printf(",");
1425 ppMIPSAMode(i->Min.StoreC.dst, mode64);
1426 return;
1427 }
1428 case Min_RdWrLR: {
1429 vex_printf("%s ", i->Min.RdWrLR.wrLR ? "mtlr" : "mflr");
1430 ppHRegMIPS(i->Min.RdWrLR.gpr, mode64);
1431 return;
1432 }
1433 case Min_FpUnary:
1434 vex_printf("%s ", showMIPSFpOp(i->Min.FpUnary.op));
1435 ppHRegMIPS(i->Min.FpUnary.dst, mode64);
1436 vex_printf(",");
1437 ppHRegMIPS(i->Min.FpUnary.src, mode64);
1438 return;
1439 case Min_FpBinary:
1440 vex_printf("%s", showMIPSFpOp(i->Min.FpBinary.op));
1441 ppHRegMIPS(i->Min.FpBinary.dst, mode64);
1442 vex_printf(",");
1443 ppHRegMIPS(i->Min.FpBinary.srcL, mode64);
1444 vex_printf(",");
1445 ppHRegMIPS(i->Min.FpBinary.srcR, mode64);
1446 return;
1447 case Min_FpTernary:
1448 vex_printf("%s", showMIPSFpOp(i->Min.FpTernary.op));
1449 ppHRegMIPS(i->Min.FpTernary.dst, mode64);
1450 vex_printf(",");
1451 ppHRegMIPS(i->Min.FpTernary.src1, mode64);
1452 vex_printf(",");
1453 ppHRegMIPS(i->Min.FpTernary.src2, mode64);
1454 vex_printf(",");
1455 ppHRegMIPS(i->Min.FpTernary.src3, mode64);
1456 return;
1457 case Min_FpConvert:
1458 vex_printf("%s", showMIPSFpOp(i->Min.FpConvert.op));
1459 ppHRegMIPS(i->Min.FpConvert.dst, mode64);
1460 vex_printf(",");
1461 ppHRegMIPS(i->Min.FpConvert.src, mode64);
1462 return;
1463 case Min_FpCompare:
1464 vex_printf("%s ", showMIPSFpOp(i->Min.FpCompare.op));
1465 ppHRegMIPS(i->Min.FpCompare.srcL, mode64);
1466 vex_printf(",");
1467 ppHRegMIPS(i->Min.FpCompare.srcR, mode64);
1468 return;
1469 case Min_FpMulAcc:
1470 vex_printf("%s ", showMIPSFpOp(i->Min.FpMulAcc.op));
1471 ppHRegMIPS(i->Min.FpMulAcc.dst, mode64);
1472 vex_printf(",");
1473 ppHRegMIPS(i->Min.FpMulAcc.srcML, mode64);
1474 vex_printf(",");
1475 ppHRegMIPS(i->Min.FpMulAcc.srcMR, mode64);
1476 vex_printf(",");
1477 ppHRegMIPS(i->Min.FpMulAcc.srcAcc, mode64);
1478 return;
1479 case Min_FpLdSt: {
1480 if (i->Min.FpLdSt.sz == 4) {
1481 if (i->Min.FpLdSt.isLoad) {
1482 vex_printf("lwc1 ");
1483 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1484 vex_printf(",");
1485 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1486 } else {
1487 vex_printf("swc1 ");
1488 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1489 vex_printf(",");
1490 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1491 }
1492 } else if (i->Min.FpLdSt.sz == 8) {
1493 if (i->Min.FpLdSt.isLoad) {
1494 vex_printf("ldc1 ");
1495 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1496 vex_printf(",");
1497 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1498 } else {
1499 vex_printf("sdc1 ");
1500 ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
1501 vex_printf(",");
1502 ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
1503 }
1504 }
1505 return;
1506 }
1507 case Min_MtFCSR: {
1508 vex_printf("ctc1 ");
1509 ppHRegMIPS(i->Min.MtFCSR.src, mode64);
1510 vex_printf(", $31");
1511 return;
1512 }
1513 case Min_MfFCSR: {
1514 vex_printf("cfc1 ");
1515 ppHRegMIPS(i->Min.MfFCSR.dst, mode64);
1516 vex_printf(", $31");
1517 return;
1518 }
1519 case Min_FpGpMove: {
1520 vex_printf("%s ", showMIPSFpGpMoveOp(i->Min.FpGpMove.op));
1521 ppHRegMIPS(i->Min.FpGpMove.dst, mode64);
1522 vex_printf(", ");
1523 ppHRegMIPS(i->Min.FpGpMove.src, mode64);
1524 return;
1525 }
1526 case Min_MoveCond: {
1527 vex_printf("%s", showMIPSMoveCondOp(i->Min.MoveCond.op));
1528 ppHRegMIPS(i->Min.MoveCond.dst, mode64);
1529 vex_printf(", ");
1530 ppHRegMIPS(i->Min.MoveCond.src, mode64);
1531 vex_printf(", ");
1532 ppHRegMIPS(i->Min.MoveCond.cond, mode64);
1533 return;
1534 }
1535 case Min_EvCheck:
1536 vex_printf("(evCheck) lw $9, ");
1537 ppMIPSAMode(i->Min.EvCheck.amCounter, mode64);
1538 vex_printf("; addiu $9, $9, -1");
1539 vex_printf("; sw $9, ");
1540 ppMIPSAMode(i->Min.EvCheck.amCounter, mode64);
1541 vex_printf("; bgez $t9, nofail; jalr *");
1542 ppMIPSAMode(i->Min.EvCheck.amFailAddr, mode64);
1543 vex_printf("; nofail:");
1544 return;
1545 case Min_ProfInc:
1546 if (mode64)
1547 vex_printf("(profInc) move $9, ($NotKnownYet); "
1548 "ld $8, 0($9); "
1549 "daddiu $8, $8, 1; "
1550 "sd $8, 0($9); " );
1551 else
1552 vex_printf("(profInc) move $9, ($NotKnownYet); "
1553 "lw $8, 0($9); "
1554 "addiu $8, $8, 1; "
1555 "sw $8, 0($9); "
1556 "sltiu $1, $8, 1; "
1557 "lw $8, 4($9); "
1558 "addu $8, $8, $1; "
1559 "sw $8, 4($9); " );
1560 return;
1561 default:
1562 vpanic("ppMIPSInstr");
1563 break;
1564 }
1565 }
1566
1567 /* --------- Helpers for register allocation. --------- */
1568
getRegUsage_MIPSInstr(HRegUsage * u,const MIPSInstr * i,Bool mode64)1569 void getRegUsage_MIPSInstr(HRegUsage * u, const MIPSInstr * i, Bool mode64)
1570 {
1571 initHRegUsage(u);
1572 switch (i->tag) {
1573 case Min_LI:
1574 addHRegUse(u, HRmWrite, i->Min.LI.dst);
1575 break;
1576 case Min_Alu:
1577 addHRegUse(u, HRmRead, i->Min.Alu.srcL);
1578 addRegUsage_MIPSRH(u, i->Min.Alu.srcR);
1579 addHRegUse(u, HRmWrite, i->Min.Alu.dst);
1580 return;
1581 case Min_Shft:
1582 addHRegUse(u, HRmRead, i->Min.Shft.srcL);
1583 addRegUsage_MIPSRH(u, i->Min.Shft.srcR);
1584 addHRegUse(u, HRmWrite, i->Min.Shft.dst);
1585 return;
1586 case Min_Cmp:
1587 addHRegUse(u, HRmRead, i->Min.Cmp.srcL);
1588 addHRegUse(u, HRmRead, i->Min.Cmp.srcR);
1589 addHRegUse(u, HRmWrite, i->Min.Cmp.dst);
1590 return;
1591 case Min_Unary:
1592 addHRegUse(u, HRmRead, i->Min.Unary.src);
1593 addHRegUse(u, HRmWrite, i->Min.Unary.dst);
1594 return;
1595 case Min_Mul:
1596 addHRegUse(u, HRmWrite, i->Min.Mul.dst);
1597 addHRegUse(u, HRmRead, i->Min.Mul.srcL);
1598 addHRegUse(u, HRmRead, i->Min.Mul.srcR);
1599 return;
1600 case Min_Mthi:
1601 case Min_Mtlo:
1602 addHRegUse(u, HRmWrite, hregMIPS_HI(mode64));
1603 addHRegUse(u, HRmWrite, hregMIPS_LO(mode64));
1604 addHRegUse(u, HRmRead, i->Min.MtHL.src);
1605 return;
1606 case Min_Mfhi:
1607 case Min_Mflo:
1608 addHRegUse(u, HRmRead, hregMIPS_HI(mode64));
1609 addHRegUse(u, HRmRead, hregMIPS_LO(mode64));
1610 addHRegUse(u, HRmWrite, i->Min.MfHL.dst);
1611 return;
1612 case Min_MtFCSR:
1613 addHRegUse(u, HRmRead, i->Min.MtFCSR.src);
1614 return;
1615 case Min_MfFCSR:
1616 addHRegUse(u, HRmWrite, i->Min.MfFCSR.dst);
1617 return;
1618 case Min_Macc:
1619 addHRegUse(u, HRmModify, hregMIPS_HI(mode64));
1620 addHRegUse(u, HRmModify, hregMIPS_LO(mode64));
1621 addHRegUse(u, HRmRead, i->Min.Macc.srcL);
1622 addHRegUse(u, HRmRead, i->Min.Macc.srcR);
1623 return;
1624 case Min_Div:
1625 addHRegUse(u, HRmWrite, hregMIPS_HI(mode64));
1626 addHRegUse(u, HRmWrite, hregMIPS_LO(mode64));
1627 addHRegUse(u, HRmRead, i->Min.Div.srcL);
1628 addHRegUse(u, HRmRead, i->Min.Div.srcR);
1629 return;
1630 case Min_Call: {
1631 /* Logic and comments copied/modified from x86, ppc and arm back end.
1632 First off, claim it trashes all the caller-saved regs
1633 which fall within the register allocator's jurisdiction. */
1634 if (i->Min.Call.cond != MIPScc_AL)
1635 addHRegUse(u, HRmRead, i->Min.Call.src);
1636 UInt argir;
1637 addHRegUse(u, HRmWrite, hregMIPS_GPR1(mode64));
1638
1639 addHRegUse(u, HRmWrite, hregMIPS_GPR2(mode64));
1640 addHRegUse(u, HRmWrite, hregMIPS_GPR3(mode64));
1641
1642 addHRegUse(u, HRmWrite, hregMIPS_GPR4(mode64));
1643 addHRegUse(u, HRmWrite, hregMIPS_GPR5(mode64));
1644 addHRegUse(u, HRmWrite, hregMIPS_GPR6(mode64));
1645 addHRegUse(u, HRmWrite, hregMIPS_GPR7(mode64));
1646
1647 addHRegUse(u, HRmWrite, hregMIPS_GPR8(mode64));
1648 addHRegUse(u, HRmWrite, hregMIPS_GPR9(mode64));
1649 addHRegUse(u, HRmWrite, hregMIPS_GPR10(mode64));
1650 addHRegUse(u, HRmWrite, hregMIPS_GPR11(mode64));
1651 addHRegUse(u, HRmWrite, hregMIPS_GPR12(mode64));
1652 addHRegUse(u, HRmWrite, hregMIPS_GPR13(mode64));
1653 addHRegUse(u, HRmWrite, hregMIPS_GPR14(mode64));
1654 addHRegUse(u, HRmWrite, hregMIPS_GPR15(mode64));
1655
1656 addHRegUse(u, HRmWrite, hregMIPS_GPR24(mode64));
1657 addHRegUse(u, HRmWrite, hregMIPS_GPR25(mode64));
1658 addHRegUse(u, HRmWrite, hregMIPS_GPR31(mode64));
1659
1660 /* Now we have to state any parameter-carrying registers
1661 which might be read. This depends on the argiregs field. */
1662 argir = i->Min.Call.argiregs;
1663 if (argir & (1<<11)) addHRegUse(u, HRmRead, hregMIPS_GPR11(mode64));
1664 if (argir & (1<<10)) addHRegUse(u, HRmRead, hregMIPS_GPR10(mode64));
1665 if (argir & (1<<9)) addHRegUse(u, HRmRead, hregMIPS_GPR9(mode64));
1666 if (argir & (1<<8)) addHRegUse(u, HRmRead, hregMIPS_GPR8(mode64));
1667 if (argir & (1<<7)) addHRegUse(u, HRmRead, hregMIPS_GPR7(mode64));
1668 if (argir & (1<<6)) addHRegUse(u, HRmRead, hregMIPS_GPR6(mode64));
1669 if (argir & (1<<5)) addHRegUse(u, HRmRead, hregMIPS_GPR5(mode64));
1670 if (argir & (1<<4)) addHRegUse(u, HRmRead, hregMIPS_GPR4(mode64));
1671
1672 vassert(0 == (argir & ~((1 << 4) | (1 << 5) | (1 << 6)
1673 | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10)
1674 | (1 << 11))));
1675
1676 return;
1677 }
1678 /* XDirect/XIndir/XAssisted are also a bit subtle. They
1679 conditionally exit the block. Hence we only need to list (1)
1680 the registers that they read, and (2) the registers that they
1681 write in the case where the block is not exited. (2) is
1682 empty, hence only (1) is relevant here. */
1683 case Min_XDirect:
1684 addRegUsage_MIPSAMode(u, i->Min.XDirect.amPC);
1685 return;
1686 case Min_XIndir:
1687 addHRegUse(u, HRmRead, i->Min.XIndir.dstGA);
1688 addRegUsage_MIPSAMode(u, i->Min.XIndir.amPC);
1689 return;
1690 case Min_XAssisted:
1691 addHRegUse(u, HRmRead, i->Min.XAssisted.dstGA);
1692 addRegUsage_MIPSAMode(u, i->Min.XAssisted.amPC);
1693 return;
1694 case Min_Load:
1695 addRegUsage_MIPSAMode(u, i->Min.Load.src);
1696 addHRegUse(u, HRmWrite, i->Min.Load.dst);
1697 return;
1698 case Min_Store:
1699 addHRegUse(u, HRmRead, i->Min.Store.src);
1700 addRegUsage_MIPSAMode(u, i->Min.Store.dst);
1701 return;
1702 case Min_LoadL:
1703 addRegUsage_MIPSAMode(u, i->Min.LoadL.src);
1704 addHRegUse(u, HRmWrite, i->Min.LoadL.dst);
1705 return;
1706 case Min_Cas:
1707 addHRegUse(u, HRmWrite, i->Min.Cas.old);
1708 addHRegUse(u, HRmRead, i->Min.Cas.addr);
1709 addHRegUse(u, HRmRead, i->Min.Cas.expd);
1710 addHRegUse(u, HRmModify, i->Min.Cas.data);
1711 return;
1712 case Min_StoreC:
1713 addHRegUse(u, HRmWrite, i->Min.StoreC.src);
1714 addHRegUse(u, HRmRead, i->Min.StoreC.src);
1715 addRegUsage_MIPSAMode(u, i->Min.StoreC.dst);
1716 return;
1717 case Min_RdWrLR:
1718 addHRegUse(u, (i->Min.RdWrLR.wrLR ? HRmRead : HRmWrite),
1719 i->Min.RdWrLR.gpr);
1720 return;
1721 case Min_FpLdSt:
1722 if (i->Min.FpLdSt.sz == 4) {
1723 addHRegUse(u, (i->Min.FpLdSt.isLoad ? HRmWrite : HRmRead),
1724 i->Min.FpLdSt.reg);
1725 addRegUsage_MIPSAMode(u, i->Min.FpLdSt.addr);
1726 return;
1727 } else if (i->Min.FpLdSt.sz == 8) {
1728 addHRegUse(u, (i->Min.FpLdSt.isLoad ? HRmWrite : HRmRead),
1729 i->Min.FpLdSt.reg);
1730 addRegUsage_MIPSAMode(u, i->Min.FpLdSt.addr);
1731 return;
1732 }
1733 break;
1734 case Min_FpUnary:
1735 addHRegUse(u, HRmWrite, i->Min.FpUnary.dst);
1736 addHRegUse(u, HRmRead, i->Min.FpUnary.src);
1737 return;
1738 case Min_FpBinary:
1739 addHRegUse(u, HRmWrite, i->Min.FpBinary.dst);
1740 addHRegUse(u, HRmRead, i->Min.FpBinary.srcL);
1741 addHRegUse(u, HRmRead, i->Min.FpBinary.srcR);
1742 return;
1743 case Min_FpTernary:
1744 addHRegUse(u, HRmWrite, i->Min.FpTernary.dst);
1745 addHRegUse(u, HRmRead, i->Min.FpTernary.src1);
1746 addHRegUse(u, HRmRead, i->Min.FpTernary.src2);
1747 addHRegUse(u, HRmRead, i->Min.FpTernary.src3);
1748 return;
1749 case Min_FpConvert:
1750 addHRegUse(u, HRmWrite, i->Min.FpConvert.dst);
1751 addHRegUse(u, HRmRead, i->Min.FpConvert.src);
1752 return;
1753 case Min_FpCompare:
1754 addHRegUse(u, HRmWrite, i->Min.FpCompare.dst);
1755 addHRegUse(u, HRmRead, i->Min.FpCompare.srcL);
1756 addHRegUse(u, HRmRead, i->Min.FpCompare.srcR);
1757 return;
1758 case Min_FpGpMove:
1759 addHRegUse(u, HRmWrite, i->Min.FpGpMove.dst);
1760 addHRegUse(u, HRmRead, i->Min.FpGpMove.src);
1761 return;
1762 case Min_MoveCond:
1763 addHRegUse(u, HRmModify, i->Min.MoveCond.dst);
1764 addHRegUse(u, HRmRead, i->Min.MoveCond.src);
1765 addHRegUse(u, HRmRead, i->Min.MoveCond.cond);
1766 return;
1767 case Min_EvCheck:
1768 /* We expect both amodes only to mention %ebp, so this is in
1769 fact pointless, since %ebp isn't allocatable, but anyway.. */
1770 addRegUsage_MIPSAMode(u, i->Min.EvCheck.amCounter);
1771 addRegUsage_MIPSAMode(u, i->Min.EvCheck.amFailAddr);
1772 return;
1773 case Min_ProfInc:
1774 /* does not use any registers. */
1775 return;
1776 default:
1777 ppMIPSInstr(i, mode64);
1778 vpanic("getRegUsage_MIPSInstr");
1779 break;
1780 }
1781 }
1782
1783 /* local helper */
mapReg(HRegRemap * m,HReg * r)1784 static void mapReg(HRegRemap * m, HReg * r)
1785 {
1786 *r = lookupHRegRemap(m, *r);
1787 }
1788
mapRegs_MIPSInstr(HRegRemap * m,MIPSInstr * i,Bool mode64)1789 void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64)
1790 {
1791 switch (i->tag) {
1792 case Min_LI:
1793 mapReg(m, &i->Min.LI.dst);
1794 break;
1795 case Min_Alu:
1796 mapReg(m, &i->Min.Alu.srcL);
1797 mapRegs_MIPSRH(m, i->Min.Alu.srcR);
1798 mapReg(m, &i->Min.Alu.dst);
1799 return;
1800 case Min_Shft:
1801 mapReg(m, &i->Min.Shft.srcL);
1802 mapRegs_MIPSRH(m, i->Min.Shft.srcR);
1803 mapReg(m, &i->Min.Shft.dst);
1804 return;
1805 case Min_Cmp:
1806 mapReg(m, &i->Min.Cmp.srcL);
1807 mapReg(m, &i->Min.Cmp.srcR);
1808 mapReg(m, &i->Min.Cmp.dst);
1809 return;
1810 case Min_Unary:
1811 mapReg(m, &i->Min.Unary.src);
1812 mapReg(m, &i->Min.Unary.dst);
1813 return;
1814 case Min_Mul:
1815 mapReg(m, &i->Min.Mul.dst);
1816 mapReg(m, &i->Min.Mul.srcL);
1817 mapReg(m, &i->Min.Mul.srcR);
1818 return;
1819 case Min_Mthi:
1820 case Min_Mtlo:
1821 mapReg(m, &i->Min.MtHL.src);
1822 return;
1823 case Min_Mfhi:
1824 case Min_Mflo:
1825 mapReg(m, &i->Min.MfHL.dst);
1826 return;
1827 case Min_Macc:
1828 mapReg(m, &i->Min.Macc.srcL);
1829 mapReg(m, &i->Min.Macc.srcR);
1830 return;
1831 case Min_Div:
1832 mapReg(m, &i->Min.Div.srcL);
1833 mapReg(m, &i->Min.Div.srcR);
1834 return;
1835 case Min_Call:
1836 {
1837 if (i->Min.Call.cond != MIPScc_AL)
1838 mapReg(m, &i->Min.Call.src);
1839 return;
1840 }
1841 case Min_XDirect:
1842 mapRegs_MIPSAMode(m, i->Min.XDirect.amPC);
1843 return;
1844 case Min_XIndir:
1845 mapReg(m, &i->Min.XIndir.dstGA);
1846 mapRegs_MIPSAMode(m, i->Min.XIndir.amPC);
1847 return;
1848 case Min_XAssisted:
1849 mapReg(m, &i->Min.XAssisted.dstGA);
1850 mapRegs_MIPSAMode(m, i->Min.XAssisted.amPC);
1851 return;
1852 case Min_Load:
1853 mapRegs_MIPSAMode(m, i->Min.Load.src);
1854 mapReg(m, &i->Min.Load.dst);
1855 return;
1856 case Min_Store:
1857 mapReg(m, &i->Min.Store.src);
1858 mapRegs_MIPSAMode(m, i->Min.Store.dst);
1859 return;
1860 case Min_LoadL:
1861 mapRegs_MIPSAMode(m, i->Min.LoadL.src);
1862 mapReg(m, &i->Min.LoadL.dst);
1863 return;
1864 case Min_Cas:
1865 mapReg(m, &i->Min.Cas.old);
1866 mapReg(m, &i->Min.Cas.addr);
1867 mapReg(m, &i->Min.Cas.expd);
1868 mapReg(m, &i->Min.Cas.data);
1869 return;
1870 case Min_StoreC:
1871 mapReg(m, &i->Min.StoreC.src);
1872 mapRegs_MIPSAMode(m, i->Min.StoreC.dst);
1873 return;
1874 case Min_RdWrLR:
1875 mapReg(m, &i->Min.RdWrLR.gpr);
1876 return;
1877 case Min_FpLdSt:
1878 if (i->Min.FpLdSt.sz == 4) {
1879 mapReg(m, &i->Min.FpLdSt.reg);
1880 mapRegs_MIPSAMode(m, i->Min.FpLdSt.addr);
1881 return;
1882 } else if (i->Min.FpLdSt.sz == 8) {
1883 mapReg(m, &i->Min.FpLdSt.reg);
1884 mapRegs_MIPSAMode(m, i->Min.FpLdSt.addr);
1885 return;
1886 }
1887 break;
1888 case Min_FpUnary:
1889 mapReg(m, &i->Min.FpUnary.dst);
1890 mapReg(m, &i->Min.FpUnary.src);
1891 return;
1892 case Min_FpBinary:
1893 mapReg(m, &i->Min.FpBinary.dst);
1894 mapReg(m, &i->Min.FpBinary.srcL);
1895 mapReg(m, &i->Min.FpBinary.srcR);
1896 return;
1897 case Min_FpTernary:
1898 mapReg(m, &i->Min.FpTernary.dst);
1899 mapReg(m, &i->Min.FpTernary.src1);
1900 mapReg(m, &i->Min.FpTernary.src2);
1901 mapReg(m, &i->Min.FpTernary.src3);
1902 return;
1903 case Min_FpConvert:
1904 mapReg(m, &i->Min.FpConvert.dst);
1905 mapReg(m, &i->Min.FpConvert.src);
1906 return;
1907 case Min_FpCompare:
1908 mapReg(m, &i->Min.FpCompare.dst);
1909 mapReg(m, &i->Min.FpCompare.srcL);
1910 mapReg(m, &i->Min.FpCompare.srcR);
1911 return;
1912 case Min_MtFCSR:
1913 mapReg(m, &i->Min.MtFCSR.src);
1914 return;
1915 case Min_MfFCSR:
1916 mapReg(m, &i->Min.MfFCSR.dst);
1917 return;
1918 case Min_FpGpMove:
1919 mapReg(m, &i->Min.FpGpMove.dst);
1920 mapReg(m, &i->Min.FpGpMove.src);
1921 return;
1922 case Min_MoveCond:
1923 mapReg(m, &i->Min.MoveCond.dst);
1924 mapReg(m, &i->Min.MoveCond.src);
1925 mapReg(m, &i->Min.MoveCond.cond);
1926 return;
1927 case Min_EvCheck:
1928 /* We expect both amodes only to mention %ebp, so this is in
1929 fact pointless, since %ebp isn't allocatable, but anyway.. */
1930 mapRegs_MIPSAMode(m, i->Min.EvCheck.amCounter);
1931 mapRegs_MIPSAMode(m, i->Min.EvCheck.amFailAddr);
1932 return;
1933 case Min_ProfInc:
1934 /* does not use any registers. */
1935 return;
1936 default:
1937 ppMIPSInstr(i, mode64);
1938 vpanic("mapRegs_MIPSInstr");
1939 break;
1940 }
1941
1942 }
1943
1944 /* Figure out if i represents a reg-reg move, and if so assign the
1945 source and destination to *src and *dst. If in doubt say No. Used
1946 by the register allocator to do move coalescing.
1947 */
isMove_MIPSInstr(const MIPSInstr * i,HReg * src,HReg * dst)1948 Bool isMove_MIPSInstr(const MIPSInstr * i, HReg * src, HReg * dst)
1949 {
1950 /* Moves between integer regs */
1951 if (i->tag == Min_Alu) {
1952 /* or Rd,Rs,Rs == mr Rd,Rs */
1953 if (i->Min.Alu.op != Malu_OR)
1954 return False;
1955 if (i->Min.Alu.srcR->tag != Mrh_Reg)
1956 return False;
1957 if (!sameHReg(i->Min.Alu.srcR->Mrh.Reg.reg, i->Min.Alu.srcL))
1958 return False;
1959 *src = i->Min.Alu.srcL;
1960 *dst = i->Min.Alu.dst;
1961 return True;
1962 }
1963 return False;
1964 }
1965
1966 /* Generate mips spill/reload instructions under the direction of the
1967 register allocator. */
genSpill_MIPS(HInstr ** i1,HInstr ** i2,HReg rreg,Int offsetB,Bool mode64)1968 void genSpill_MIPS( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
1969 Int offsetB, Bool mode64)
1970 {
1971 MIPSAMode *am;
1972 vassert(offsetB >= 0);
1973 vassert(!hregIsVirtual(rreg));
1974 *i1 = *i2 = NULL;
1975 am = MIPSAMode_IR(offsetB, GuestStatePointer(mode64));
1976
1977 switch (hregClass(rreg)) {
1978 case HRcInt64:
1979 vassert(mode64);
1980 *i1 = MIPSInstr_Store(8, am, rreg, mode64);
1981 break;
1982 case HRcInt32:
1983 vassert(!mode64);
1984 *i1 = MIPSInstr_Store(4, am, rreg, mode64);
1985 break;
1986 case HRcFlt32:
1987 vassert(!mode64);
1988 *i1 = MIPSInstr_FpLdSt(False /*Store */ , 4, rreg, am);
1989 break;
1990 case HRcFlt64:
1991 *i1 = MIPSInstr_FpLdSt(False /*Store */ , 8, rreg, am);
1992 break;
1993 default:
1994 ppHRegClass(hregClass(rreg));
1995 vpanic("genSpill_MIPS: unimplemented regclass");
1996 break;
1997 }
1998 }
1999
genReload_MIPS(HInstr ** i1,HInstr ** i2,HReg rreg,Int offsetB,Bool mode64)2000 void genReload_MIPS( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
2001 Int offsetB, Bool mode64)
2002 {
2003 MIPSAMode *am;
2004 vassert(!hregIsVirtual(rreg));
2005 am = MIPSAMode_IR(offsetB, GuestStatePointer(mode64));
2006
2007 switch (hregClass(rreg)) {
2008 case HRcInt64:
2009 vassert(mode64);
2010 *i1 = MIPSInstr_Load(8, rreg, am, mode64);
2011 break;
2012 case HRcInt32:
2013 vassert(!mode64);
2014 *i1 = MIPSInstr_Load(4, rreg, am, mode64);
2015 break;
2016 case HRcFlt32:
2017 if (mode64)
2018 *i1 = MIPSInstr_FpLdSt(True /*Load */ , 8, rreg, am);
2019 else
2020 *i1 = MIPSInstr_FpLdSt(True /*Load */ , 4, rreg, am);
2021 break;
2022 case HRcFlt64:
2023 *i1 = MIPSInstr_FpLdSt(True /*Load */ , 8, rreg, am);
2024 break;
2025 default:
2026 ppHRegClass(hregClass(rreg));
2027 vpanic("genReload_MIPS: unimplemented regclass");
2028 break;
2029 }
2030 }
2031
2032 /* --------- The mips assembler --------- */
2033
iregNo(HReg r,Bool mode64)2034 inline static UInt iregNo(HReg r, Bool mode64)
2035 {
2036 UInt n;
2037 vassert(hregClass(r) == (mode64 ? HRcInt64 : HRcInt32));
2038 vassert(!hregIsVirtual(r));
2039 n = hregEncoding(r);
2040 vassert(n <= 32);
2041 return n;
2042 }
2043
fregNo(HReg r,Bool mode64)2044 inline static UInt fregNo(HReg r, Bool mode64)
2045 {
2046 UInt n;
2047 vassert(!hregIsVirtual(r));
2048 n = hregEncoding(r);
2049 vassert(n <= 31);
2050 return n;
2051 }
2052
dregNo(HReg r)2053 inline static UInt dregNo(HReg r)
2054 {
2055 UInt n;
2056 vassert(!hregIsVirtual(r));
2057 n = hregEncoding(r);
2058 vassert(n <= 31);
2059 return n;
2060 }
2061
2062 /* Emit 32bit instruction */
emit32(UChar * p,UInt w32)2063 static UChar *emit32(UChar * p, UInt w32)
2064 {
2065 #if defined (_MIPSEL)
2066 *p++ = toUChar(w32 & 0x000000FF);
2067 *p++ = toUChar((w32 >> 8) & 0x000000FF);
2068 *p++ = toUChar((w32 >> 16) & 0x000000FF);
2069 *p++ = toUChar((w32 >> 24) & 0x000000FF);
2070 /* HACK !!!!
2071 MIPS endianess is decided at compile time using gcc defined
2072 symbols _MIPSEL or _MIPSEB. When compiling libvex in a cross-arch
2073 setup, then none of these is defined. We just choose here by default
2074 mips Big Endian to allow libvexmultiarch_test to work when using
2075 a mips host architecture.
2076 A cleaner way would be to either have mips using 'dynamic endness'
2077 (like ppc64be or le, decided at runtime) or at least defining
2078 by default _MIPSEB when compiling on a non mips system.
2079 #elif defined (_MIPSEB).
2080 */
2081 #else
2082 *p++ = toUChar((w32 >> 24) & 0x000000FF);
2083 *p++ = toUChar((w32 >> 16) & 0x000000FF);
2084 *p++ = toUChar((w32 >> 8) & 0x000000FF);
2085 *p++ = toUChar(w32 & 0x000000FF);
2086 #endif
2087 return p;
2088 }
2089 /* Fetch an instruction */
fetch32(UChar * p)2090 static UInt fetch32 ( UChar* p )
2091 {
2092 UInt w32 = 0;
2093 #if defined (_MIPSEL)
2094 w32 |= ((0xFF & (UInt)p[0]) << 0);
2095 w32 |= ((0xFF & (UInt)p[1]) << 8);
2096 w32 |= ((0xFF & (UInt)p[2]) << 16);
2097 w32 |= ((0xFF & (UInt)p[3]) << 24);
2098 #elif defined (_MIPSEB)
2099 w32 |= ((0xFF & (UInt)p[0]) << 24);
2100 w32 |= ((0xFF & (UInt)p[1]) << 16);
2101 w32 |= ((0xFF & (UInt)p[2]) << 8);
2102 w32 |= ((0xFF & (UInt)p[3]) << 0);
2103 #endif
2104 return w32;
2105 }
2106
2107 /* physical structure of mips instructions */
2108 /* type I : opcode - 6 bits
2109 rs - 5 bits
2110 rt - 5 bits
2111 immediate - 16 bits
2112 */
mkFormI(UChar * p,UInt opc,UInt rs,UInt rt,UInt imm)2113 static UChar *mkFormI(UChar * p, UInt opc, UInt rs, UInt rt, UInt imm)
2114 {
2115 UInt theInstr;
2116 vassert(opc < 0x40);
2117 vassert(rs < 0x20);
2118 vassert(rt < 0x20);
2119 imm = imm & 0xFFFF;
2120 theInstr = ((opc << 26) | (rs << 21) | (rt << 16) | (imm));
2121 return emit32(p, theInstr);
2122 }
2123
2124 /* type R: opcode - 6 bits
2125 rs - 5 bits
2126 rt - 5 bits
2127 rd - 5 bits
2128 sa - 5 bits
2129 func - 6 bits
2130 */
mkFormR(UChar * p,UInt opc,UInt rs,UInt rt,UInt rd,UInt sa,UInt func)2131 static UChar *mkFormR(UChar * p, UInt opc, UInt rs, UInt rt, UInt rd, UInt sa,
2132 UInt func)
2133 {
2134 if (rs >= 0x20)
2135 vex_printf("rs = %u\n", rs);
2136 UInt theInstr;
2137 vassert(opc < 0x40);
2138 vassert(rs < 0x20);
2139 vassert(rt < 0x20);
2140 vassert(rd < 0x20);
2141 vassert(sa < 0x20);
2142 func = func & 0xFFFF;
2143 theInstr = ((opc << 26) | (rs << 21) | (rt << 16) | (rd << 11) | (sa << 6) |
2144 (func));
2145
2146 return emit32(p, theInstr);
2147 }
2148
mkFormS(UChar * p,UInt opc1,UInt rRD,UInt rRS,UInt rRT,UInt sa,UInt opc2)2149 static UChar *mkFormS(UChar * p, UInt opc1, UInt rRD, UInt rRS, UInt rRT,
2150 UInt sa, UInt opc2)
2151 {
2152 UInt theInstr;
2153 vassert(opc1 <= 0x3F);
2154 vassert(rRD < 0x20);
2155 vassert(rRS < 0x20);
2156 vassert(rRT < 0x20);
2157 vassert(opc2 <= 0x3F);
2158 vassert(sa >= 0 && sa <= 0x3F);
2159
2160 theInstr = ((opc1 << 26) | (rRS << 21) | (rRT << 16) | (rRD << 11) |
2161 ((sa & 0x1F) << 6) | (opc2));
2162
2163 return emit32(p, theInstr);
2164 }
2165
doAMode_IR(UChar * p,UInt opc1,UInt rSD,MIPSAMode * am,Bool mode64)2166 static UChar *doAMode_IR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am,
2167 Bool mode64)
2168 {
2169 UInt rA, idx, r_dst;
2170 vassert(am->tag == Mam_IR);
2171 vassert(am->Mam.IR.index < 0x10000);
2172
2173 rA = iregNo(am->Mam.IR.base, mode64);
2174 idx = am->Mam.IR.index;
2175
2176 if (rSD == 33 || rSD == 34)
2177 r_dst = 24;
2178 else
2179 r_dst = rSD;
2180
2181 if (opc1 < 40) {
2182 /* load */
2183 if (rSD == 33)
2184 /* mfhi */
2185 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2186 else if (rSD == 34)
2187 /* mflo */
2188 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2189 }
2190
2191 p = mkFormI(p, opc1, rA, r_dst, idx);
2192
2193 if (opc1 >= 40) {
2194 /* store */
2195 if (rSD == 33)
2196 /* mthi */
2197 p = mkFormR(p, 0, r_dst, 0, 0, 0, 17);
2198 else if (rSD == 34)
2199 /* mtlo */
2200 p = mkFormR(p, 0, r_dst, 0, 0, 0, 19);
2201 }
2202
2203 return p;
2204 }
2205
doAMode_RR(UChar * p,UInt opc1,UInt rSD,MIPSAMode * am,Bool mode64)2206 static UChar *doAMode_RR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am,
2207 Bool mode64)
2208 {
2209 UInt rA, rB, r_dst;
2210 vassert(am->tag == Mam_RR);
2211
2212 rA = iregNo(am->Mam.RR.base, mode64);
2213 rB = iregNo(am->Mam.RR.index, mode64);
2214
2215 if (rSD == 33 || rSD == 34)
2216 r_dst = 24;
2217 else
2218 r_dst = rSD;
2219
2220 if (opc1 < 40) {
2221 /* load */
2222 if (rSD == 33)
2223 /* mfhi */
2224 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2225 else if (rSD == 34)
2226 /* mflo */
2227 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2228 }
2229
2230 if (mode64) {
2231 /* daddu rA, rA, rB$
2232 sd/ld r_dst, 0(rA)$
2233 dsubu rA, rA, rB */
2234 p = mkFormR(p, 0, rA, rB, rA, 0, 45);
2235 p = mkFormI(p, opc1, rA, r_dst, 0);
2236 p = mkFormR(p, 0, rA, rB, rA, 0, 47);
2237 } else {
2238 /* addu rA, rA, rB
2239 sw/lw r_dst, 0(rA)
2240 subu rA, rA, rB */
2241 p = mkFormR(p, 0, rA, rB, rA, 0, 33);
2242 p = mkFormI(p, opc1, rA, r_dst, 0);
2243 p = mkFormR(p, 0, rA, rB, rA, 0, 35);
2244 }
2245 if (opc1 >= 40) {
2246 /* store */
2247 if (rSD == 33)
2248 /* mthi */
2249 p = mkFormR(p, 0, r_dst, 0, 0, 0, 17);
2250 else if (rSD == 34)
2251 /* mtlo */
2252 p = mkFormR(p, 0, r_dst, 0, 0, 0, 19);
2253 }
2254
2255 return p;
2256 }
2257
2258 /* Load imm to r_dst */
mkLoadImm(UChar * p,UInt r_dst,ULong imm,Bool mode64)2259 static UChar *mkLoadImm(UChar * p, UInt r_dst, ULong imm, Bool mode64)
2260 {
2261 if (!mode64) {
2262 vassert(r_dst < 0x20);
2263 UInt u32 = (UInt) imm;
2264 Int s32 = (Int) u32;
2265 Long s64 = (Long) s32;
2266 imm = (ULong) s64;
2267 }
2268
2269 if (imm >= 0xFFFFFFFFFFFF8000ULL || imm < 0x8000) {
2270 /* sign-extendable from 16 bits
2271 addiu r_dst, 0, imm => li r_dst, imm */
2272 p = mkFormI(p, 9, 0, r_dst, imm & 0xFFFF);
2273 } else {
2274 if (imm >= 0xFFFFFFFF80000000ULL || imm < 0x80000000ULL) {
2275 /* sign-extendable from 32 bits
2276 addiu r_dst, r0, (imm >> 16) => lis r_dst, (imm >> 16)
2277 lui r_dst, (imm >> 16) */
2278 p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
2279 /* ori r_dst, r_dst, (imm & 0xFFFF) */
2280 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2281 } else {
2282 vassert(mode64);
2283 /* lui load in upper half of low word */
2284 p = mkFormI(p, 15, 0, r_dst, (imm >> 48) & 0xFFFF);
2285 /* ori */
2286 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 32) & 0xFFFF);
2287 /* shift */
2288 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2289 /* ori */
2290 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 16) & 0xFFFF);
2291 /* shift */
2292 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2293 /* ori */
2294 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2295 }
2296 }
2297 return p;
2298 }
2299
2300 /* A simplified version of mkLoadImm that always generates 2 or 6
2301 instructions (32 or 64 bits respectively) even if it could generate
2302 fewer. This is needed for generating fixed sized patchable
2303 sequences. */
mkLoadImm_EXACTLY2or6(UChar * p,UInt r_dst,ULong imm,Bool mode64)2304 static UChar* mkLoadImm_EXACTLY2or6 ( UChar* p,
2305 UInt r_dst, ULong imm, Bool mode64)
2306 {
2307 vassert(r_dst < 0x20);
2308
2309 if (!mode64) {
2310 /* In 32-bit mode, make sure the top 32 bits of imm are a sign
2311 extension of the bottom 32 bits. (Probably unnecessary.) */
2312 UInt u32 = (UInt)imm;
2313 Int s32 = (Int)u32;
2314 Long s64 = (Long)s32;
2315 imm = (ULong)s64;
2316 }
2317
2318 if (!mode64) {
2319 /* sign-extendable from 32 bits
2320 addiu r_dst, r0, (imm >> 16) => lis r_dst, (imm >> 16)
2321 lui r_dst, (imm >> 16) */
2322 p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
2323 /* ori r_dst, r_dst, (imm & 0xFFFF) */
2324 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2325 } else {
2326 /* full 64bit immediate load: 6 (six!) insns. */
2327 vassert(mode64);
2328 /* lui load in upper half of low word */
2329 p = mkFormI(p, 15, 0, r_dst, (imm >> 48) & 0xFFFF);
2330 /* ori */
2331 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 32) & 0xFFFF);
2332 /* shift */
2333 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2334 /* ori */
2335 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 16) & 0xFFFF);
2336 /* shift */
2337 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2338 /* ori */
2339 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2340 }
2341 return p;
2342 }
2343
2344 /* Checks whether the sequence of bytes at p was indeed created
2345 by mkLoadImm_EXACTLY2or6 with the given parameters. */
isLoadImm_EXACTLY2or6(UChar * p_to_check,UInt r_dst,ULong imm,Bool mode64)2346 static Bool isLoadImm_EXACTLY2or6 ( UChar* p_to_check,
2347 UInt r_dst, ULong imm, Bool mode64 )
2348 {
2349 vassert(r_dst < 0x20);
2350 Bool ret;
2351 if (!mode64) {
2352 /* In 32-bit mode, make sure the top 32 bits of imm are a sign
2353 extension of the bottom 32 bits. (Probably unnecessary.) */
2354 UInt u32 = (UInt)imm;
2355 Int s32 = (Int)u32;
2356 Long s64 = (Long)s32;
2357 imm = (ULong)s64;
2358 }
2359
2360 if (!mode64) {
2361 UInt expect[2] = { 0, 0 };
2362 UChar* p = (UChar*)&expect[0];
2363 /* lui r_dst, (immi >> 16) */
2364 p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
2365 /* ori r_dst, r_dst, (imm & 0xFFFF) */
2366 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2367 vassert(p == (UChar*)&expect[2]);
2368
2369 ret = fetch32(p_to_check + 0) == expect[0]
2370 && fetch32(p_to_check + 4) == expect[1];
2371 } else {
2372 UInt expect[6] = { 0, 0, 0, 0, 0, 0};
2373 UChar* p = (UChar*)&expect[0];
2374 /* lui load in upper half of low word */
2375 p = mkFormI(p, 15, 0, r_dst, (imm >> 48) & 0xFFFF);
2376 /* ori */
2377 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 32) & 0xFFFF);
2378 /* shift */
2379 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2380 /* ori */
2381 p = mkFormI(p, 13, r_dst, r_dst, (imm >> 16) & 0xFFFF);
2382 /* shift */
2383 p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
2384 /* ori */
2385 p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
2386 vassert(p == (UChar*)&expect[6]);
2387
2388 ret = fetch32(p_to_check + 0) == expect[0]
2389 && fetch32(p_to_check + 4) == expect[1]
2390 && fetch32(p_to_check + 8) == expect[2]
2391 && fetch32(p_to_check + 12) == expect[3]
2392 && fetch32(p_to_check + 16) == expect[4]
2393 && fetch32(p_to_check + 20) == expect[5];
2394 }
2395 return ret;
2396 }
2397
2398 /* Generate a machine-word sized load or store. Simplified version of
2399 the Min_Load and Min_Store cases below.
2400 This will generate 32-bit load/store on MIPS32, and 64-bit load/store on
2401 MIPS64 platforms.
2402 */
do_load_or_store_machine_word(UChar * p,Bool isLoad,UInt reg,MIPSAMode * am,Bool mode64)2403 static UChar* do_load_or_store_machine_word ( UChar* p, Bool isLoad, UInt reg,
2404 MIPSAMode* am, Bool mode64 )
2405 {
2406 if (isLoad) { /* load */
2407 switch (am->tag) {
2408 case Mam_IR:
2409 if (mode64) {
2410 vassert(0 == (am->Mam.IR.index & 3));
2411 }
2412 p = doAMode_IR(p, mode64 ? 55 : 35, reg, am, mode64);
2413 break;
2414 case Mam_RR:
2415 /* we could handle this case, but we don't expect to ever
2416 need to. */
2417 vassert(0);
2418 break;
2419 default:
2420 vassert(0);
2421 break;
2422 }
2423 } else /* store */ {
2424 switch (am->tag) {
2425 case Mam_IR:
2426 if (mode64) {
2427 vassert(0 == (am->Mam.IR.index & 3));
2428 }
2429 p = doAMode_IR(p, mode64 ? 63 : 43, reg, am, mode64);
2430 break;
2431 case Mam_RR:
2432 /* we could handle this case, but we don't expect to ever
2433 need to. */
2434 vassert(0);
2435 break;
2436 default:
2437 vassert(0);
2438 break;
2439 }
2440 }
2441 return p;
2442 }
2443
2444 /* Generate a 32-bit sized load or store. Simplified version of
2445 do_load_or_store_machine_word above. */
do_load_or_store_word32(UChar * p,Bool isLoad,UInt reg,MIPSAMode * am,Bool mode64)2446 static UChar* do_load_or_store_word32 ( UChar* p, Bool isLoad, UInt reg,
2447 MIPSAMode* am, Bool mode64 )
2448 {
2449 if (isLoad) { /* load */
2450 switch (am->tag) {
2451 case Mam_IR:
2452 if (mode64) {
2453 vassert(0 == (am->Mam.IR.index & 3));
2454 }
2455 p = doAMode_IR(p, 35, reg, am, mode64);
2456 break;
2457 case Mam_RR:
2458 /* we could handle this case, but we don't expect to ever
2459 need to. */
2460 vassert(0);
2461 break;
2462 default:
2463 vassert(0);
2464 break;
2465 }
2466 } else /* store */ {
2467 switch (am->tag) {
2468 case Mam_IR:
2469 if (mode64) {
2470 vassert(0 == (am->Mam.IR.index & 3));
2471 }
2472 p = doAMode_IR(p, 43, reg, am, mode64);
2473 break;
2474 case Mam_RR:
2475 /* we could handle this case, but we don't expect to ever
2476 need to. */
2477 vassert(0);
2478 break;
2479 default:
2480 vassert(0);
2481 break;
2482 }
2483 }
2484 return p;
2485 }
2486
2487 /* Move r_dst to r_src */
mkMoveReg(UChar * p,UInt r_dst,UInt r_src)2488 static UChar *mkMoveReg(UChar * p, UInt r_dst, UInt r_src)
2489 {
2490 vassert(r_dst < 0x20);
2491 vassert(r_src < 0x20);
2492
2493 if (r_dst != r_src) {
2494 /* or r_dst, r_src, r_src */
2495 p = mkFormR(p, 0, r_src, r_src, r_dst, 0, 37);
2496 }
2497 return p;
2498 }
2499
2500 /* Emit an instruction into buf and return the number of bytes used.
2501 Note that buf is not the insn's final place, and therefore it is
2502 imperative to emit position-independent code. If the emitted
2503 instruction was a profiler inc, set *is_profInc to True, else
2504 leave it unchanged. */
emit_MIPSInstr(Bool * is_profInc,UChar * buf,Int nbuf,const MIPSInstr * i,Bool mode64,VexEndness endness_host,const void * disp_cp_chain_me_to_slowEP,const void * disp_cp_chain_me_to_fastEP,const void * disp_cp_xindir,const void * disp_cp_xassisted)2505 Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc,
2506 UChar* buf, Int nbuf, const MIPSInstr* i,
2507 Bool mode64,
2508 VexEndness endness_host,
2509 const void* disp_cp_chain_me_to_slowEP,
2510 const void* disp_cp_chain_me_to_fastEP,
2511 const void* disp_cp_xindir,
2512 const void* disp_cp_xassisted )
2513 {
2514 UChar *p = &buf[0];
2515 UChar *ptmp = p;
2516 vassert(nbuf >= 32);
2517
2518 switch (i->tag) {
2519 case Min_LI:
2520 p = mkLoadImm(p, iregNo(i->Min.LI.dst, mode64), i->Min.LI.imm, mode64);
2521 goto done;
2522
2523 case Min_Alu: {
2524 MIPSRH *srcR = i->Min.Alu.srcR;
2525 Bool immR = toBool(srcR->tag == Mrh_Imm);
2526 UInt r_dst = iregNo(i->Min.Alu.dst, mode64);
2527 UInt r_srcL = iregNo(i->Min.Alu.srcL, mode64);
2528 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->Mrh.Reg.reg,
2529 mode64);
2530 switch (i->Min.Alu.op) {
2531 /* Malu_ADD, Malu_SUB, Malu_AND, Malu_OR, Malu_NOR, Malu_XOR, Malu_SLT */
2532 case Malu_ADD:
2533 if (immR) {
2534 vassert(srcR->Mrh.Imm.syned);
2535 /* addiu */
2536 p = mkFormI(p, 9, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2537 } else {
2538 /* addu */
2539 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 33);
2540 }
2541 break;
2542 case Malu_SUB:
2543 if (immR) {
2544 /* addiu , but with negated imm */
2545 vassert(srcR->Mrh.Imm.syned);
2546 vassert(srcR->Mrh.Imm.imm16 != 0x8000);
2547 p = mkFormI(p, 9, r_srcL, r_dst, (-srcR->Mrh.Imm.imm16));
2548 } else {
2549 /* subu */
2550 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 35);
2551 }
2552 break;
2553 case Malu_AND:
2554 if (immR) {
2555 /* andi */
2556 vassert(!srcR->Mrh.Imm.syned);
2557 p = mkFormI(p, 12, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2558 } else {
2559 /* and */
2560 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 36);
2561 }
2562 break;
2563 case Malu_OR:
2564 if (immR) {
2565 /* ori */
2566 vassert(!srcR->Mrh.Imm.syned);
2567 p = mkFormI(p, 13, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2568 } else {
2569 /* or */
2570 if (r_srcL == 33)
2571 /* MFHI */
2572 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2573 else if (r_srcL == 34)
2574 /* MFLO */
2575 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2576 else if (r_dst == 33)
2577 /* MTHI */
2578 p = mkFormR(p, 0, r_srcL, 0, 0, 0, 17);
2579 else if (r_dst == 34)
2580 /* MTLO */
2581 p = mkFormR(p, 0, r_srcL, 0, 0, 0, 19);
2582 else
2583 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 37);
2584 }
2585 break;
2586 case Malu_NOR:
2587 /* nor */
2588 vassert(!immR);
2589 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 39);
2590 break;
2591 case Malu_XOR:
2592 if (immR) {
2593 /* xori */
2594 vassert(!srcR->Mrh.Imm.syned);
2595 p = mkFormI(p, 14, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2596 } else {
2597 /* xor */
2598 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
2599 }
2600 break;
2601 case Malu_DADD:
2602 if (immR) {
2603 vassert(srcR->Mrh.Imm.syned);
2604 vassert(srcR->Mrh.Imm.imm16 != 0x8000);
2605 p = mkFormI(p, 25, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2606 } else {
2607 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 45);
2608 }
2609 break;
2610 case Malu_DSUB:
2611 if (immR) {
2612 p = mkFormI(p, 25, r_srcL, r_dst, (-srcR->Mrh.Imm.imm16));
2613 } else {
2614 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 47);
2615 }
2616 break;
2617 case Malu_SLT:
2618 if (immR) {
2619 goto bad;
2620 } else {
2621 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
2622 }
2623 break;
2624
2625 default:
2626 goto bad;
2627 }
2628 goto done;
2629 }
2630
2631 case Min_Shft: {
2632 MIPSRH *srcR = i->Min.Shft.srcR;
2633 Bool sz32 = i->Min.Shft.sz32;
2634 Bool immR = toBool(srcR->tag == Mrh_Imm);
2635 UInt r_dst = iregNo(i->Min.Shft.dst, mode64);
2636 UInt r_srcL = iregNo(i->Min.Shft.srcL, mode64);
2637 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->Mrh.Reg.reg,
2638 mode64);
2639 if (!mode64)
2640 vassert(sz32);
2641 switch (i->Min.Shft.op) {
2642 case Mshft_SLL:
2643 if (sz32) {
2644 if (immR) {
2645 UInt n = srcR->Mrh.Imm.imm16;
2646 vassert(n >= 0 && n <= 32);
2647 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 0);
2648 } else {
2649 /* shift variable */
2650 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 4);
2651 }
2652 } else {
2653 if (immR) {
2654 UInt n = srcR->Mrh.Imm.imm16;
2655 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
2656 if (n >= 0 && n < 32) {
2657 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 56);
2658 } else {
2659 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 60);
2660 }
2661 } else {
2662 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 20);
2663 }
2664 }
2665 break;
2666
2667 case Mshft_SRL:
2668 if (sz32) {
2669 /* SRL, SRLV */
2670 if (immR) {
2671 UInt n = srcR->Mrh.Imm.imm16;
2672 vassert(n >= 0 && n < 32);
2673 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 2);
2674 } else {
2675 /* shift variable */
2676 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 6);
2677 }
2678 } else {
2679 /* DSRL, DSRL32, DSRLV */
2680 if (immR) {
2681 UInt n = srcR->Mrh.Imm.imm16;
2682 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
2683 if (n >= 0 && n < 32) {
2684 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 58);
2685 } else {
2686 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 62);
2687 }
2688 } else {
2689 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 22);
2690 }
2691 }
2692 break;
2693
2694 case Mshft_SRA:
2695 if (sz32) {
2696 /* SRA, SRAV */
2697 if (immR) {
2698 UInt n = srcR->Mrh.Imm.imm16;
2699 vassert(n >= 0 && n < 32);
2700 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 3);
2701 } else {
2702 /* shift variable */
2703 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 7);
2704 }
2705 } else {
2706 /* DSRA, DSRA32, DSRAV */
2707 if (immR) {
2708 UInt n = srcR->Mrh.Imm.imm16;
2709 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
2710 if (n >= 0 && n < 32) {
2711 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 59);
2712 } else {
2713 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 63);
2714 }
2715 } else {
2716 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 23);
2717 }
2718 }
2719 break;
2720
2721 default:
2722 goto bad;
2723 }
2724
2725 goto done;
2726 }
2727
2728 case Min_Unary: {
2729 UInt r_dst = iregNo(i->Min.Unary.dst, mode64);
2730 UInt r_src = iregNo(i->Min.Unary.src, mode64);
2731
2732 switch (i->Min.Unary.op) {
2733 /* Mun_CLO, Mun_CLZ, Mun_NOP, Mun_DCLO, Mun_DCLZ */
2734 case Mun_CLO: /* clo */
2735 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 33);
2736 break;
2737 case Mun_CLZ: /* clz */
2738 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 32);
2739 break;
2740 case Mun_NOP: /* nop (sll r0,r0,0) */
2741 p = mkFormR(p, 0, 0, 0, 0, 0, 0);
2742 break;
2743 case Mun_DCLO: /* clo */
2744 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 37);
2745 break;
2746 case Mun_DCLZ: /* clz */
2747 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 36);
2748 break;
2749 }
2750 goto done;
2751 }
2752
2753 case Min_Cmp: {
2754 UInt r_srcL = iregNo(i->Min.Cmp.srcL, mode64);
2755 UInt r_srcR = iregNo(i->Min.Cmp.srcR, mode64);
2756 UInt r_dst = iregNo(i->Min.Cmp.dst, mode64);
2757
2758 switch (i->Min.Cmp.cond) {
2759 case MIPScc_EQ:
2760 /* xor r_dst, r_srcL, r_srcR
2761 sltiu r_dst, r_dst, 1 */
2762 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
2763 p = mkFormI(p, 11, r_dst, r_dst, 1);
2764 break;
2765 case MIPScc_NE:
2766 /* xor r_dst, r_srcL, r_srcR
2767 sltu r_dst, zero, r_dst */
2768 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
2769 p = mkFormR(p, 0, 0, r_dst, r_dst, 0, 43);
2770 break;
2771 case MIPScc_LT:
2772 /* slt r_dst, r_srcL, r_srcR */
2773 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
2774 break;
2775 case MIPScc_LO:
2776 /* sltu r_dst, r_srcL, r_srcR */
2777 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 43);
2778 break;
2779 case MIPScc_LE:
2780 /* slt r_dst, r_srcR, r_srcL
2781 xori r_dst, r_dst, 1 */
2782 p = mkFormR(p, 0, r_srcR, r_srcL, r_dst, 0, 42);
2783 p = mkFormI(p, 14, r_dst, r_dst, 1);
2784 break;
2785 case MIPScc_LS:
2786 /* sltu r_dst, rsrcR, r_srcL
2787 xori r_dsr, r_dst, 1 */
2788 p = mkFormR(p, 0, r_srcR, r_srcL, r_dst, 0, 43);
2789 p = mkFormI(p, 14, r_dst, r_dst, 1);
2790 break;
2791 default:
2792 goto bad;
2793 }
2794 goto done;
2795 }
2796
2797 case Min_Mul: {
2798 Bool syned = i->Min.Mul.syned;
2799 Bool widening = i->Min.Mul.widening;
2800 Bool sz32 = i->Min.Mul.sz32;
2801 UInt r_srcL = iregNo(i->Min.Mul.srcL, mode64);
2802 UInt r_srcR = iregNo(i->Min.Mul.srcR, mode64);
2803 UInt r_dst = iregNo(i->Min.Mul.dst, mode64);
2804 if (widening) {
2805 if (sz32) {
2806 if (syned)
2807 /* mult */
2808 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 24);
2809 else
2810 /* multu */
2811 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 25);
2812 } else {
2813 if (syned) /* DMULT r_dst,r_srcL,r_srcR */
2814 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 28);
2815 else /* DMULTU r_dst,r_srcL,r_srcR */
2816 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 29);
2817 }
2818 } else {
2819 if (sz32)
2820 /* mul */
2821 p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
2822 else if (mode64 && !sz32)
2823 p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
2824 else
2825 goto bad;
2826 }
2827 goto done;
2828 }
2829
2830 case Min_Macc: {
2831 Bool syned = i->Min.Macc.syned;
2832 UInt r_srcL = iregNo(i->Min.Macc.srcL, mode64);
2833 UInt r_srcR = iregNo(i->Min.Macc.srcR, mode64);
2834
2835 if (syned) {
2836 switch (i->Min.Macc.op) {
2837 case Macc_ADD:
2838 /* madd */
2839 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0, 0);
2840 break;
2841 case Macc_SUB:
2842 /* msub */
2843 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
2844 4);
2845 break;
2846 default:
2847 goto bad;
2848 }
2849 } else {
2850 switch (i->Min.Macc.op) {
2851 case Macc_ADD:
2852 /* maddu */
2853 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
2854 1);
2855 break;
2856 case Macc_SUB:
2857 /* msubu */
2858 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
2859 5);
2860 break;
2861 default:
2862 goto bad;
2863 }
2864 }
2865
2866 goto done;
2867 }
2868
2869 case Min_Div: {
2870 Bool syned = i->Min.Div.syned;
2871 Bool sz32 = i->Min.Div.sz32;
2872 UInt r_srcL = iregNo(i->Min.Div.srcL, mode64);
2873 UInt r_srcR = iregNo(i->Min.Div.srcR, mode64);
2874 if (sz32) {
2875 if (syned) {
2876 /* div */
2877 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 26);
2878 } else
2879 /* divu */
2880 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 27);
2881 goto done;
2882 } else {
2883 if (syned) {
2884 /* ddiv */
2885 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 30);
2886 } else
2887 /* ddivu */
2888 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 31);
2889 goto done;
2890 }
2891 }
2892
2893 case Min_Mthi: {
2894 UInt r_src = iregNo(i->Min.MtHL.src, mode64);
2895 p = mkFormR(p, 0, r_src, 0, 0, 0, 17);
2896 goto done;
2897 }
2898
2899 case Min_Mtlo: {
2900 UInt r_src = iregNo(i->Min.MtHL.src, mode64);
2901 p = mkFormR(p, 0, r_src, 0, 0, 0, 19);
2902 goto done;
2903 }
2904
2905 case Min_Mfhi: {
2906 UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
2907 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2908 goto done;
2909 }
2910
2911 case Min_Mflo: {
2912 UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
2913 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2914 goto done;
2915 }
2916
2917 case Min_MtFCSR: {
2918 UInt r_src = iregNo(i->Min.MtFCSR.src, mode64);
2919 /* ctc1 */
2920 p = mkFormR(p, 17, 6, r_src, 31, 0, 0);
2921 goto done;
2922 }
2923
2924 case Min_MfFCSR: {
2925 UInt r_dst = iregNo(i->Min.MfFCSR.dst, mode64);
2926 /* cfc1 */
2927 p = mkFormR(p, 17, 2, r_dst, 31, 0, 0);
2928 goto done;
2929 }
2930
2931 case Min_Call: {
2932 if (i->Min.Call.cond != MIPScc_AL
2933 && i->Min.Call.rloc.pri != RLPri_None) {
2934 /* The call might not happen (it isn't unconditional) and
2935 it returns a result. In this case we will need to
2936 generate a control flow diamond to put 0x555..555 in
2937 the return register(s) in the case where the call
2938 doesn't happen. If this ever becomes necessary, maybe
2939 copy code from the ARM equivalent. Until that day,
2940 just give up. */
2941 goto bad;
2942 }
2943 MIPSCondCode cond = i->Min.Call.cond;
2944 UInt r_dst = 25; /* using %r25 as address temporary -
2945 see getRegUsage_MIPSInstr */
2946
2947 /* jump over the following insns if condition does not hold */
2948 if (cond != MIPScc_AL) {
2949 /* jmp fwds if !condition */
2950 /* don't know how many bytes to jump over yet...
2951 make space for a jump instruction + nop!!! and fill in later. */
2952 ptmp = p; /* fill in this bit later */
2953 p += 8; /* p += 8 */
2954 }
2955
2956 if (!mode64) {
2957 /* addiu $29, $29, -16 */
2958 p = mkFormI(p, 9, 29, 29, 0xFFF0);
2959 }
2960
2961 /* load target to r_dst; p += 4|8 */
2962 p = mkLoadImm(p, r_dst, i->Min.Call.target, mode64);
2963
2964 /* jalr r_dst */
2965 p = mkFormR(p, 0, r_dst, 0, 31, 0, 9); /* p += 4 */
2966 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
2967
2968 if (!mode64) {
2969 /* addiu $29, $29, 16 */
2970 p = mkFormI(p, 9, 29, 29, 0x0010);
2971 }
2972
2973 /* Fix up the conditional jump, if there was one. */
2974 if (cond != MIPScc_AL) {
2975 UInt r_src = iregNo(i->Min.Call.src, mode64);
2976 Int delta = p - ptmp;
2977
2978 vassert(delta >= 20 && delta <= 32);
2979 /* blez r_src, delta/4-1
2980 nop */
2981 ptmp = mkFormI(ptmp, 6, r_src, 0, delta / 4 - 1);
2982 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
2983 }
2984 goto done;
2985 }
2986
2987 case Min_XDirect: {
2988 /* NB: what goes on here has to be very closely coordinated
2989 with the chainXDirect_MIPS and unchainXDirect_MIPS below. */
2990 /* We're generating chain-me requests here, so we need to be
2991 sure this is actually allowed -- no-redir translations
2992 can't use chain-me's. Hence: */
2993 vassert(disp_cp_chain_me_to_slowEP != NULL);
2994 vassert(disp_cp_chain_me_to_fastEP != NULL);
2995
2996 /* Use ptmp for backpatching conditional jumps. */
2997 ptmp = NULL;
2998
2999 /* First off, if this is conditional, create a conditional
3000 jump over the rest of it. Or at least, leave a space for
3001 it that we will shortly fill in. */
3002 if (i->Min.XDirect.cond != MIPScc_AL) {
3003 vassert(i->Min.XDirect.cond != MIPScc_NV);
3004 ptmp = p;
3005 p += 12;
3006 }
3007
3008 /* Update the guest PC. */
3009 /* move r9, dstGA */
3010 /* sw/sd r9, amPC */
3011 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, (ULong)i->Min.XDirect.dstGA,
3012 mode64);
3013 p = do_load_or_store_machine_word(p, False /*!isLoad*/ , /*r*/ 9,
3014 i->Min.XDirect.amPC, mode64);
3015
3016 /* --- FIRST PATCHABLE BYTE follows --- */
3017 /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're
3018 calling to) backs up the return address, so as to find the
3019 address of the first patchable byte. So: don't change the
3020 number of instructions (3) below. */
3021 /* move r9, VG_(disp_cp_chain_me_to_{slowEP,fastEP}) */
3022 /* jr r9 */
3023 const void* disp_cp_chain_me
3024 = i->Min.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
3025 : disp_cp_chain_me_to_slowEP;
3026 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3027 (Addr)disp_cp_chain_me, mode64);
3028 /* jalr $9 */
3029 /* nop */
3030 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3031 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3032 /* --- END of PATCHABLE BYTES --- */
3033
3034 /* Fix up the conditional jump, if there was one. */
3035 if (i->Min.XDirect.cond != MIPScc_AL) {
3036 Int delta = p - ptmp;
3037 delta = delta / 4 - 3;
3038 vassert(delta > 0 && delta < 40);
3039
3040 /* lw $9, COND_OFFSET(GuestSP)
3041 beq $9, $0, 2
3042 nop */
3043 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
3044 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
3045 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
3046 }
3047 goto done;
3048 }
3049
3050 case Min_XIndir: {
3051 /* We're generating transfers that could lead indirectly to a
3052 chain-me, so we need to be sure this is actually allowed --
3053 no-redir translations are not allowed to reach normal
3054 translations without going through the scheduler. That means
3055 no XDirects or XIndirs out from no-redir translations.
3056 Hence: */
3057 vassert(disp_cp_xindir != NULL);
3058
3059 /* Use ptmp for backpatching conditional jumps. */
3060 ptmp = NULL;
3061
3062 /* First off, if this is conditional, create a conditional
3063 jump over the rest of it. */
3064 if (i->Min.XIndir.cond != MIPScc_AL) {
3065 vassert(i->Min.XIndir.cond != MIPScc_NV);
3066 ptmp = p;
3067 p += 12;
3068 }
3069
3070 /* Update the guest PC. */
3071 /* sw/sd r-dstGA, amPC */
3072 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
3073 iregNo(i->Min.XIndir.dstGA, mode64),
3074 i->Min.XIndir.amPC, mode64);
3075
3076 /* move r9, VG_(disp_cp_xindir) */
3077 /* jalr r9 */
3078 /* nop */
3079 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3080 (Addr)disp_cp_xindir, mode64);
3081 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3082 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3083
3084 /* Fix up the conditional jump, if there was one. */
3085 if (i->Min.XIndir.cond != MIPScc_AL) {
3086 Int delta = p - ptmp;
3087 delta = delta / 4 - 3;
3088 vassert(delta > 0 && delta < 40);
3089
3090 /* lw $9, COND_OFFSET($GuestSP)
3091 beq $9, $0, 2
3092 nop */
3093 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
3094 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
3095 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
3096 }
3097 goto done;
3098 }
3099
3100 case Min_XAssisted: {
3101 /* First off, if this is conditional, create a conditional jump
3102 over the rest of it. Or at least, leave a space for it that
3103 we will shortly fill in. */
3104 ptmp = NULL;
3105 if (i->Min.XAssisted.cond != MIPScc_AL) {
3106 vassert(i->Min.XAssisted.cond != MIPScc_NV);
3107 ptmp = p;
3108 p += 12;
3109 }
3110
3111 /* Update the guest PC. */
3112 /* sw/sd r-dstGA, amPC */
3113 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
3114 iregNo(i->Min.XIndir.dstGA, mode64),
3115 i->Min.XIndir.amPC, mode64);
3116
3117 /* imm32/64 r31, $magic_number */
3118 UInt trcval = 0;
3119 switch (i->Min.XAssisted.jk) {
3120 case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
3121 case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
3122 /* case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break; */
3123 case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
3124 case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
3125 case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
3126 /* case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break; */
3127 case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
3128 case Ijk_InvalICache: trcval = VEX_TRC_JMP_INVALICACHE; break;
3129 case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
3130 case Ijk_SigILL: trcval = VEX_TRC_JMP_SIGILL; break;
3131 case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
3132 /* case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; */
3133 case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break;
3134 case Ijk_SigFPE_IntDiv: trcval = VEX_TRC_JMP_SIGFPE_INTDIV; break;
3135 case Ijk_SigFPE_IntOvf: trcval = VEX_TRC_JMP_SIGFPE_INTOVF; break;
3136 case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
3137 /* We don't expect to see the following being assisted.
3138 case Ijk_Ret:
3139 case Ijk_Call:
3140 fallthrough */
3141 default:
3142 ppIRJumpKind(i->Min.XAssisted.jk);
3143 vpanic("emit_MIPSInstr.Min_XAssisted: unexpected jump kind");
3144 }
3145 vassert(trcval != 0);
3146 p = mkLoadImm_EXACTLY2or6(p, /*r*/ GuestSP, trcval, mode64);
3147
3148 /* move r9, VG_(disp_cp_xassisted) */
3149 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3150 (ULong)(Addr)disp_cp_xassisted, mode64);
3151 /* jalr $9
3152 nop */
3153 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3154 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3155
3156 /* Fix up the conditional jump, if there was one. */
3157 if (i->Min.XAssisted.cond != MIPScc_AL) {
3158 Int delta = p - ptmp;
3159 delta = delta / 4 - 3;
3160 vassert(delta > 0 && delta < 40);
3161
3162 /* lw $9, COND_OFFSET($GuestSP)
3163 beq $9, $0, 2
3164 nop */
3165 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
3166 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
3167 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
3168 }
3169 goto done;
3170 }
3171
3172 case Min_Load: {
3173 MIPSAMode *am_addr = i->Min.Load.src;
3174 if (am_addr->tag == Mam_IR) {
3175 UInt r_dst = iregNo(i->Min.Load.dst, mode64);
3176 UInt opc, sz = i->Min.Load.sz;
3177 if (mode64 && (sz == 4 || sz == 8)) {
3178 /* should be guaranteed to us by iselWordExpr_AMode */
3179 vassert(0 == (am_addr->Mam.IR.index & 3));
3180 }
3181 switch (sz) {
3182 case 1:
3183 opc = 32;
3184 break;
3185 case 2:
3186 opc = 33;
3187 break;
3188 case 4:
3189 opc = 35;
3190 break;
3191 case 8:
3192 opc = 55;
3193 vassert(mode64);
3194 break;
3195 default:
3196 goto bad;
3197 }
3198
3199 p = doAMode_IR(p, opc, r_dst, am_addr, mode64);
3200 goto done;
3201 } else if (am_addr->tag == Mam_RR) {
3202 UInt r_dst = iregNo(i->Min.Load.dst, mode64);
3203 UInt opc, sz = i->Min.Load.sz;
3204
3205 switch (sz) {
3206 case 1:
3207 opc = 32;
3208 break;
3209 case 2:
3210 opc = 33;
3211 break;
3212 case 4:
3213 opc = 35;
3214 break;
3215 case 8:
3216 opc = 55;
3217 vassert(mode64);
3218 break;
3219 default:
3220 goto bad;
3221 }
3222
3223 p = doAMode_RR(p, opc, r_dst, am_addr, mode64);
3224 goto done;
3225 }
3226 break;
3227 }
3228
3229 case Min_Store: {
3230 MIPSAMode *am_addr = i->Min.Store.dst;
3231 if (am_addr->tag == Mam_IR) {
3232 UInt r_src = iregNo(i->Min.Store.src, mode64);
3233 UInt opc, sz = i->Min.Store.sz;
3234 if (mode64 && (sz == 4 || sz == 8)) {
3235 /* should be guaranteed to us by iselWordExpr_AMode */
3236 vassert(0 == (am_addr->Mam.IR.index & 3));
3237 }
3238 switch (sz) {
3239 case 1:
3240 opc = 40;
3241 break;
3242 case 2:
3243 opc = 41;
3244 break;
3245 case 4:
3246 opc = 43;
3247 break;
3248 case 8:
3249 vassert(mode64);
3250 opc = 63;
3251 break;
3252 default:
3253 goto bad;
3254 }
3255
3256 p = doAMode_IR(p, opc, r_src, am_addr, mode64);
3257 goto done;
3258 } else if (am_addr->tag == Mam_RR) {
3259 UInt r_src = iregNo(i->Min.Store.src, mode64);
3260 UInt opc, sz = i->Min.Store.sz;
3261
3262 switch (sz) {
3263 case 1:
3264 opc = 40;
3265 break;
3266 case 2:
3267 opc = 41;
3268 break;
3269 case 4:
3270 opc = 43;
3271 break;
3272 case 8:
3273 vassert(mode64);
3274 opc = 63;
3275 break;
3276 default:
3277 goto bad;
3278 }
3279
3280 p = doAMode_RR(p, opc, r_src, am_addr, mode64);
3281 goto done;
3282 }
3283 break;
3284 }
3285 case Min_LoadL: {
3286 MIPSAMode *am_addr = i->Min.LoadL.src;
3287 UInt r_src = iregNo(am_addr->Mam.IR.base, mode64);
3288 UInt idx = am_addr->Mam.IR.index;
3289 UInt r_dst = iregNo(i->Min.LoadL.dst, mode64);
3290
3291 if (i->Min.LoadL.sz == 4)
3292 p = mkFormI(p, 0x30, r_src, r_dst, idx);
3293 else
3294 p = mkFormI(p, 0x34, r_src, r_dst, idx);
3295 goto done;
3296 }
3297 case Min_StoreC: {
3298 MIPSAMode *am_addr = i->Min.StoreC.dst;
3299 UInt r_src = iregNo(i->Min.StoreC.src, mode64);
3300 UInt idx = am_addr->Mam.IR.index;
3301 UInt r_dst = iregNo(am_addr->Mam.IR.base, mode64);
3302
3303 if (i->Min.StoreC.sz == 4)
3304 p = mkFormI(p, 0x38, r_dst, r_src, idx);
3305 else
3306 p = mkFormI(p, 0x3C, r_dst, r_src, idx);
3307 goto done;
3308 }
3309 case Min_Cas: {
3310 if (i->Min.Cas.sz != 8 && i->Min.Cas.sz != 4)
3311 goto bad;
3312 UInt old = iregNo(i->Min.Cas.old, mode64);
3313 UInt addr = iregNo(i->Min.Cas.addr, mode64);
3314 UInt expd = iregNo(i->Min.Cas.expd, mode64);
3315 UInt data = iregNo(i->Min.Cas.data, mode64);
3316 Bool sz8 = toBool(i->Min.Cas.sz == 8);
3317
3318 /*
3319 * ll(d) old, 0(addr)
3320 * bne old, expd, end
3321 * nop
3322 * (d)addiu old, old, 1
3323 * sc(d) data, 0(addr)
3324 * movn old, expd, data
3325 * end:
3326 */
3327 // ll(d) old, 0(addr)
3328 p = mkFormI(p, sz8 ? 0x34 : 0x30, addr, old, 0);
3329 // bne old, expd, end
3330 p = mkFormI(p, 5, old, expd, 4);
3331 // nop
3332 p = mkFormR(p, 0, 0, 0, 0, 0, 0);
3333 // (d)addiu old, old, 1
3334 p = mkFormI(p, sz8 ? 25 : 9, old, old, 1);
3335 // sc(d) data, 0(addr)
3336 p = mkFormI(p, sz8 ? 0x3C : 0x38, addr, data, 0);
3337 // movn old, expd, data
3338 p = mkFormR(p, 0, expd, data, old, 0, 0xb);
3339
3340 goto done;
3341 }
3342 case Min_RdWrLR: {
3343 UInt reg = iregNo(i->Min.RdWrLR.gpr, mode64);
3344 Bool wrLR = i->Min.RdWrLR.wrLR;
3345 if (wrLR)
3346 p = mkMoveReg(p, 31, reg);
3347 else
3348 p = mkMoveReg(p, reg, 31);
3349 goto done;
3350 }
3351
3352 /* Floating point */
3353 case Min_FpLdSt: {
3354 MIPSAMode *am_addr = i->Min.FpLdSt.addr;
3355 UChar sz = i->Min.FpLdSt.sz;
3356 vassert(sz == 4 || sz == 8);
3357 if (sz == 4) {
3358 UInt f_reg = fregNo(i->Min.FpLdSt.reg, mode64);
3359 if (i->Min.FpLdSt.isLoad) {
3360 if (am_addr->tag == Mam_IR)
3361 p = doAMode_IR(p, 0x31, f_reg, am_addr, mode64);
3362 else if (am_addr->tag == Mam_RR)
3363 p = doAMode_RR(p, 0x31, f_reg, am_addr, mode64);
3364 } else {
3365 if (am_addr->tag == Mam_IR)
3366 p = doAMode_IR(p, 0x39, f_reg, am_addr, mode64);
3367 else if (am_addr->tag == Mam_RR)
3368 p = doAMode_RR(p, 0x39, f_reg, am_addr, mode64);
3369 }
3370 } else if (sz == 8) {
3371 UInt f_reg = dregNo(i->Min.FpLdSt.reg);
3372 if (i->Min.FpLdSt.isLoad) {
3373 if (am_addr->tag == Mam_IR) {
3374 p = doAMode_IR(p, 0x35, f_reg, am_addr, mode64);
3375 } else if (am_addr->tag == Mam_RR) {
3376 p = doAMode_RR(p, 0x35, f_reg, am_addr, mode64);
3377 }
3378 } else {
3379 if (am_addr->tag == Mam_IR) {
3380 p = doAMode_IR(p, 0x3d, f_reg, am_addr, mode64);
3381 } else if (am_addr->tag == Mam_RR) {
3382 p = doAMode_RR(p, 0x3d, f_reg, am_addr, mode64);
3383 }
3384 }
3385 }
3386 goto done;
3387 }
3388
3389 case Min_FpUnary: {
3390 switch (i->Min.FpUnary.op) {
3391 case Mfp_MOVS: { /* FP move */
3392 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3393 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3394 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x6);
3395 break;
3396 }
3397 case Mfp_MOVD: { /* FP move */
3398 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3399 UInt fr_src = dregNo(i->Min.FpUnary.src);
3400 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x6);
3401 break;
3402 }
3403 case Mfp_ABSS: { /* ABS.S */
3404 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3405 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3406 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x5);
3407 break;
3408 }
3409 case Mfp_ABSD: { /* ABS.D */
3410 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3411 UInt fr_src = dregNo(i->Min.FpUnary.src);
3412 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x5);
3413 break;
3414 }
3415 case Mfp_NEGS: { /* NEG.S */
3416 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3417 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3418 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x7);
3419 break;
3420 }
3421 case Mfp_NEGD: { /* NEG.D */
3422 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3423 UInt fr_src = dregNo(i->Min.FpUnary.src);
3424 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x7);
3425 break;
3426 }
3427 case Mfp_SQRTS: { /* SQRT.S */
3428 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3429 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3430 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x04);
3431 break;
3432 }
3433 case Mfp_SQRTD: { /* SQRT.D */
3434 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3435 UInt fr_src = dregNo(i->Min.FpUnary.src);
3436 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x04);
3437 break;
3438 }
3439 default:
3440 goto bad;
3441 }
3442 goto done;
3443 }
3444
3445 case Min_FpBinary: {
3446 switch (i->Min.FpBinary.op) {
3447 case Mfp_ADDS: {
3448 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3449 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3450 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3451 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 0);
3452 break;
3453 }
3454 case Mfp_SUBS: {
3455 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3456 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3457 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3458 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 1);
3459 break;
3460 }
3461 case Mfp_MULS: {
3462 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3463 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3464 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3465 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 2);
3466 break;
3467 }
3468 case Mfp_DIVS: {
3469 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3470 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3471 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3472 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 3);
3473 break;
3474 }
3475 case Mfp_ADDD: {
3476 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3477 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3478 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3479 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 0);
3480 break;
3481 }
3482 case Mfp_SUBD: {
3483 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3484 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3485 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3486 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 1);
3487 break;
3488 }
3489 case Mfp_MULD: {
3490 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3491 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3492 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3493 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 2);
3494 break;
3495 }
3496 case Mfp_DIVD: {
3497 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3498 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3499 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3500 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 3);
3501 break;
3502 }
3503 default:
3504 goto bad;
3505 }
3506 goto done;
3507 }
3508
3509 case Min_FpTernary: {
3510 switch (i->Min.FpTernary.op) {
3511 case Mfp_MADDS: {
3512 UInt fr_dst = fregNo(i->Min.FpTernary.dst, mode64);
3513 UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64);
3514 UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64);
3515 UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64);
3516 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x20);
3517 break;
3518 }
3519 case Mfp_MADDD: {
3520 UInt fr_dst = dregNo(i->Min.FpTernary.dst);
3521 UInt fr_src1 = dregNo(i->Min.FpTernary.src1);
3522 UInt fr_src2 = dregNo(i->Min.FpTernary.src2);
3523 UInt fr_src3 = dregNo(i->Min.FpTernary.src3);
3524 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x21);
3525 break;
3526 }
3527 case Mfp_MSUBS: {
3528 UInt fr_dst = fregNo(i->Min.FpTernary.dst, mode64);
3529 UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64);
3530 UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64);
3531 UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64);
3532 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x28);
3533 break;
3534 }
3535 case Mfp_MSUBD: {
3536 UInt fr_dst = dregNo(i->Min.FpTernary.dst);
3537 UInt fr_src1 = dregNo(i->Min.FpTernary.src1);
3538 UInt fr_src2 = dregNo(i->Min.FpTernary.src2);
3539 UInt fr_src3 = dregNo(i->Min.FpTernary.src3);
3540 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x29);
3541 break;
3542 }
3543 default:
3544 goto bad;
3545 }
3546 goto done;
3547 }
3548
3549 case Min_FpConvert: {
3550 switch (i->Min.FpConvert.op) {
3551 UInt fr_dst, fr_src;
3552 case Mfp_CVTSD:
3553 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3554 fr_src = dregNo(i->Min.FpConvert.src);
3555 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x20);
3556 break;
3557 case Mfp_CVTSW:
3558 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3559 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3560 p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x20);
3561 break;
3562 case Mfp_CVTWD:
3563 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3564 fr_src = dregNo(i->Min.FpConvert.src);
3565 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x24);
3566 break;
3567 case Mfp_CVTWS:
3568 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3569 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3570 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x24);
3571 break;
3572 case Mfp_CVTDW:
3573 fr_dst = dregNo(i->Min.FpConvert.dst);
3574 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3575 p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x21);
3576 break;
3577 case Mfp_CVTDL:
3578 fr_dst = dregNo(i->Min.FpConvert.dst);
3579 fr_src = dregNo(i->Min.FpConvert.src);
3580 p = mkFormR(p, 0x11, 0x15, 0, fr_src, fr_dst, 0x21);
3581 break;
3582 case Mfp_CVTDS:
3583 fr_dst = dregNo(i->Min.FpConvert.dst);
3584 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3585 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x21);
3586 break;
3587 case Mfp_CVTSL:
3588 fr_dst = dregNo(i->Min.FpConvert.dst);
3589 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3590 p = mkFormR(p, 0x11, 0x15, 0, fr_src, fr_dst, 0x20);
3591 break;
3592 case Mfp_CVTLS:
3593 if (mode64) {
3594 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3595 fr_src = dregNo(i->Min.FpConvert.src);
3596 } else {
3597 fr_dst = dregNo(i->Min.FpConvert.dst);
3598 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3599 }
3600 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x25);
3601 break;
3602 case Mfp_CVTLD:
3603 fr_dst = dregNo(i->Min.FpConvert.dst);
3604 fr_src = dregNo(i->Min.FpConvert.src);
3605 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x25);
3606 break;
3607 case Mfp_TRUWS:
3608 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3609 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3610 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0D);
3611 break;
3612 case Mfp_TRUWD:
3613 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3614 fr_src = dregNo(i->Min.FpConvert.src);
3615 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0D);
3616 break;
3617 case Mfp_TRULS:
3618 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3619 fr_src = dregNo(i->Min.FpConvert.src);
3620 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x09);
3621 break;
3622 case Mfp_TRULD:
3623 fr_dst = dregNo(i->Min.FpConvert.dst);
3624 fr_src = dregNo(i->Min.FpConvert.src);
3625 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x09);
3626 break;
3627 case Mfp_CEILWS:
3628 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3629 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3630 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0E);
3631 break;
3632 case Mfp_CEILWD:
3633 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3634 fr_src = dregNo(i->Min.FpConvert.src);
3635 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0E);
3636 break;
3637 case Mfp_CEILLS:
3638 fr_dst = dregNo(i->Min.FpConvert.dst);
3639 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3640 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0A);
3641 break;
3642 case Mfp_CEILLD:
3643 fr_dst = dregNo(i->Min.FpConvert.dst);
3644 fr_src = dregNo(i->Min.FpConvert.src);
3645 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0A);
3646 break;
3647 case Mfp_ROUNDWS:
3648 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3649 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3650 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0C);
3651 break;
3652 case Mfp_ROUNDWD:
3653 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3654 fr_src = dregNo(i->Min.FpConvert.src);
3655 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0C);
3656 break;
3657 case Mfp_ROUNDLD:
3658 fr_dst = dregNo(i->Min.FpConvert.dst);
3659 fr_src = dregNo(i->Min.FpConvert.src);
3660 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x08);
3661 break;
3662 case Mfp_FLOORWS:
3663 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3664 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3665 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0F);
3666 break;
3667 case Mfp_FLOORWD:
3668 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3669 fr_src = dregNo(i->Min.FpConvert.src);
3670 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0F);
3671 break;
3672 case Mfp_FLOORLD:
3673 fr_dst = dregNo(i->Min.FpConvert.dst);
3674 fr_src = dregNo(i->Min.FpConvert.src);
3675 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0B);
3676 break;
3677
3678 default:
3679 goto bad;
3680 }
3681 goto done;
3682 }
3683
3684 case Min_FpCompare: {
3685 UInt r_dst = iregNo(i->Min.FpCompare.dst, mode64);
3686 UInt fr_srcL = dregNo(i->Min.FpCompare.srcL);
3687 UInt fr_srcR = dregNo(i->Min.FpCompare.srcR);
3688
3689 UInt op;
3690 switch (i->Min.FpConvert.op) {
3691 case Mfp_CMP_UN:
3692 op = 1;
3693 break;
3694 case Mfp_CMP_EQ:
3695 op = 2;
3696 break;
3697 case Mfp_CMP_LT:
3698 op = 12;
3699 break;
3700 case Mfp_CMP_NGT:
3701 op = 15;
3702 break;
3703 default:
3704 goto bad;
3705 }
3706 /* c.cond.d fr_srcL, fr_srcR
3707 cfc1 r_dst, $31
3708 srl r_dst, r_dst, 23
3709 andi r_dst, r_dst, 1 */
3710 p = mkFormR(p, 0x11, 0x11, fr_srcL, fr_srcR, 0, op + 48);
3711 p = mkFormR(p, 0x11, 0x2, r_dst, 31, 0, 0);
3712 p = mkFormS(p, 0, r_dst, 0, r_dst, 23, 2);
3713 p = mkFormI(p, 12, r_dst, r_dst, 1);
3714 goto done;
3715 }
3716
3717 case Min_FpGpMove: {
3718 switch (i->Min.FpGpMove.op) {
3719 UInt rt, fs;
3720 case MFpGpMove_mfc1: {
3721 rt = iregNo(i->Min.FpGpMove.dst, mode64);
3722 fs = fregNo(i->Min.FpGpMove.src, mode64);
3723 p = mkFormR(p, 0x11, 0x0, rt, fs, 0x0, 0x0);
3724 break;
3725 }
3726 case MFpGpMove_dmfc1: {
3727 vassert(mode64);
3728 rt = iregNo(i->Min.FpGpMove.dst, mode64);
3729 fs = fregNo(i->Min.FpGpMove.src, mode64);
3730 p = mkFormR(p, 0x11, 0x1, rt, fs, 0x0, 0x0);
3731 break;
3732 }
3733 case MFpGpMove_mtc1: {
3734 rt = iregNo(i->Min.FpGpMove.src, mode64);
3735 fs = fregNo(i->Min.FpGpMove.dst, mode64);
3736 p = mkFormR(p, 0x11, 0x4, rt, fs, 0x0, 0x0);
3737 break;
3738 }
3739 case MFpGpMove_dmtc1: {
3740 vassert(mode64);
3741 rt = iregNo(i->Min.FpGpMove.src, mode64);
3742 fs = fregNo(i->Min.FpGpMove.dst, mode64);
3743 p = mkFormR(p, 0x11, 0x5, rt, fs, 0x0, 0x0);
3744 break;
3745 }
3746 default:
3747 goto bad;
3748 }
3749 goto done;
3750 }
3751
3752 case Min_MoveCond: {
3753 switch (i->Min.MoveCond.op) {
3754 UInt d, s, t;
3755 case MFpMoveCond_movns: {
3756 d = fregNo(i->Min.MoveCond.dst, mode64);
3757 s = fregNo(i->Min.MoveCond.src, mode64);
3758 t = iregNo(i->Min.MoveCond.cond, mode64);
3759 p = mkFormR(p, 0x11, 0x10, t, s, d, 0x13);
3760 break;
3761 }
3762 case MFpMoveCond_movnd: {
3763 d = dregNo(i->Min.MoveCond.dst);
3764 s = dregNo(i->Min.MoveCond.src);
3765 t = iregNo(i->Min.MoveCond.cond, mode64);
3766 p = mkFormR(p, 0x11, 0x11, t, s, d, 0x13);
3767 break;
3768 }
3769 case MMoveCond_movn: {
3770 d = iregNo(i->Min.MoveCond.dst, mode64);
3771 s = iregNo(i->Min.MoveCond.src, mode64);
3772 t = iregNo(i->Min.MoveCond.cond, mode64);
3773 p = mkFormR(p, 0, s, t, d, 0, 0xb);
3774 break;
3775 }
3776 default:
3777 goto bad;
3778 }
3779 goto done;
3780 }
3781
3782 case Min_EvCheck: {
3783 /* This requires a 32-bit dec/test in 32 mode. */
3784 /* We generate:
3785 lw r9, amCounter
3786 addiu r9, r9, -1
3787 sw r9, amCounter
3788 bgez r9, nofail
3789 lw r9, amFailAddr
3790 jalr r9
3791 nop
3792 nofail:
3793 */
3794 UChar* p0 = p;
3795 /* lw r9, amCounter */
3796 p = do_load_or_store_word32(p, True /*isLoad*/ , /*r*/ 9,
3797 i->Min.EvCheck.amCounter, mode64);
3798 /* addiu r9,r9,-1 */
3799 p = mkFormI(p, 9, 9, 9, 0xFFFF);
3800 /* sw r30, amCounter */
3801 p = do_load_or_store_word32(p, False /*!isLoad*/ , /*r*/ 9,
3802 i->Min.EvCheck.amCounter, mode64);
3803 /* bgez t9, nofail */
3804 p = mkFormI(p, 1, 9, 1, 3);
3805 /* lw/ld r9, amFailAddr */
3806 p = do_load_or_store_machine_word(p, True /*isLoad*/ , /*r*/ 9,
3807 i->Min.EvCheck.amFailAddr, mode64);
3808 /* jalr $9 */
3809 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3810 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3811 /* nofail: */
3812
3813 /* Crosscheck */
3814 vassert(evCheckSzB_MIPS() == (UChar*)p - (UChar*)p0);
3815 goto done;
3816 }
3817
3818 case Min_ProfInc: {
3819 /* Generate a code template to increment a memory location whose
3820 address will be known later as an immediate value. This code
3821 template will be patched once the memory location is known.
3822 For now we do this with address == 0x65556555. */
3823 if (mode64) {
3824 /* 64-bit:
3825 move r9, 0x6555655565556555ULL
3826 ld r8, 0(r9)
3827 daddiu r8, r8, 1
3828 sd r8, 0(r9) */
3829
3830 /* move r9, 0x6555655565556555ULL */
3831 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, 0x6555655565556555ULL,
3832 True /*mode64*/);
3833 /* ld r8, 0(r9) */
3834 p = mkFormI(p, 55, 9, 8, 0);
3835
3836 /* daddiu r8, r8, 1 */
3837 p = mkFormI(p, 25, 8, 8, 1);
3838
3839 /* sd r8, 0(r9) */
3840 p = mkFormI(p, 63, 9, 8, 0);
3841 } else {
3842 /* 32-bit:
3843 move r9, 0x65556555
3844 lw r8, 0(r9)
3845 addiu r8, r8, 1 # add least significant word
3846 sw r8, 0(r9)
3847 sltiu r1, r8, 1 # set carry-in bit
3848 lw r8, 4(r9)
3849 addu r8, r8, r1
3850 sw r8, 4(r9) */
3851
3852 /* move r9, 0x65556555 */
3853 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, 0x65556555ULL,
3854 False /*!mode64*/);
3855 /* lw r8, 0(r9) */
3856 p = mkFormI(p, 35, 9, 8, 0);
3857
3858 /* addiu r8, r8, 1 # add least significant word */
3859 p = mkFormI(p, 9, 8, 8, 1);
3860
3861 /* sw r8, 0(r9) */
3862 p = mkFormI(p, 43, 9, 8, 0);
3863
3864 /* sltiu r1, r8, 1 # set carry-in bit */
3865 p = mkFormI(p, 11, 8, 1, 1);
3866
3867 /* lw r8, 4(r9) */
3868 p = mkFormI(p, 35, 9, 8, 4);
3869
3870 /* addu r8, r8, r1 */
3871 p = mkFormR(p, 0, 8, 1, 8, 0, 33);
3872
3873 /* sw r8, 4(r9) */
3874 p = mkFormI(p, 43, 9, 8, 4);
3875
3876 }
3877 /* Tell the caller .. */
3878 vassert(!(*is_profInc));
3879 *is_profInc = True;
3880 goto done;
3881 }
3882
3883 default:
3884 goto bad;
3885
3886 }
3887
3888 bad:
3889 vex_printf("\n=> ");
3890 ppMIPSInstr(i, mode64);
3891 vpanic("emit_MIPSInstr");
3892 /* NOTREACHED */ done:
3893 vassert(p - &buf[0] <= 128);
3894 return p - &buf[0];
3895 }
3896
3897 /* How big is an event check? See case for Min_EvCheck in
3898 emit_MIPSInstr just above. That crosschecks what this returns, so
3899 we can tell if we're inconsistent. */
evCheckSzB_MIPS(void)3900 Int evCheckSzB_MIPS (void)
3901 {
3902 UInt kInstrSize = 4;
3903 return 7*kInstrSize;
3904 }
3905
3906 /* NB: what goes on here has to be very closely coordinated with the
3907 emitInstr case for XDirect, above. */
chainXDirect_MIPS(VexEndness endness_host,void * place_to_chain,const void * disp_cp_chain_me_EXPECTED,const void * place_to_jump_to,Bool mode64)3908 VexInvalRange chainXDirect_MIPS ( VexEndness endness_host,
3909 void* place_to_chain,
3910 const void* disp_cp_chain_me_EXPECTED,
3911 const void* place_to_jump_to,
3912 Bool mode64 )
3913 {
3914 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
3915 /* What we're expecting to see is:
3916 move r9, disp_cp_chain_me_to_EXPECTED
3917 jalr r9
3918 nop
3919 viz
3920 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
3921 0x120F809 # jalr r9
3922 0x00000000 # nop
3923 */
3924 UChar* p = (UChar*)place_to_chain;
3925 vassert(0 == (3 & (HWord)p));
3926 vassert(isLoadImm_EXACTLY2or6(p, /*r*/9,
3927 (UInt)(Addr)disp_cp_chain_me_EXPECTED,
3928 mode64));
3929 vassert(fetch32(p + (mode64 ? 24 : 8) + 0) == 0x120F809);
3930 vassert(fetch32(p + (mode64 ? 24 : 8) + 4) == 0x00000000);
3931 /* And what we want to change it to is either:
3932 move r9, place_to_jump_to
3933 jalr r9
3934 nop
3935 viz
3936 <8 bytes generated by mkLoadImm_EXACTLY2or6>
3937 0x120F809 # jalr r9
3938 0x00000000 # nop
3939
3940 The replacement has the same length as the original.
3941 */
3942
3943 p = mkLoadImm_EXACTLY2or6(p, /*r*/9,
3944 (Addr)place_to_jump_to, mode64);
3945 p = emit32(p, 0x120F809);
3946 p = emit32(p, 0x00000000);
3947
3948 Int len = p - (UChar*)place_to_chain;
3949 vassert(len == (mode64 ? 32 : 16)); /* stay sane */
3950 VexInvalRange vir = {(HWord)place_to_chain, len};
3951 return vir;
3952 }
3953
3954 /* NB: what goes on here has to be very closely coordinated with the
3955 emitInstr case for XDirect, above. */
unchainXDirect_MIPS(VexEndness endness_host,void * place_to_unchain,const void * place_to_jump_to_EXPECTED,const void * disp_cp_chain_me,Bool mode64)3956 VexInvalRange unchainXDirect_MIPS ( VexEndness endness_host,
3957 void* place_to_unchain,
3958 const void* place_to_jump_to_EXPECTED,
3959 const void* disp_cp_chain_me,
3960 Bool mode64 )
3961 {
3962 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
3963 /* What we're expecting to see is:
3964 move r9, place_to_jump_to_EXPECTED
3965 jalr r9
3966 nop
3967 viz
3968 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
3969 0x120F809 # jalr r9
3970 0x00000000 # nop
3971 */
3972 UChar* p = (UChar*)place_to_unchain;
3973 vassert(0 == (3 & (HWord)p));
3974 vassert(isLoadImm_EXACTLY2or6(p, /*r*/ 9,
3975 (Addr)place_to_jump_to_EXPECTED,
3976 mode64));
3977 vassert(fetch32(p + (mode64 ? 24 : 8) + 0) == 0x120F809);
3978 vassert(fetch32(p + (mode64 ? 24 : 8) + 4) == 0x00000000);
3979 /* And what we want to change it to is:
3980 move r9, disp_cp_chain_me
3981 jalr r9
3982 nop
3983 viz
3984 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
3985 0x120F809 # jalr r9
3986 0x00000000 # nop
3987 The replacement has the same length as the original.
3988 */
3989 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3990 (Addr)disp_cp_chain_me, mode64);
3991 p = emit32(p, 0x120F809);
3992 p = emit32(p, 0x00000000);
3993
3994 Int len = p - (UChar*)place_to_unchain;
3995 vassert(len == (mode64 ? 32 : 16)); /* stay sane */
3996 VexInvalRange vir = {(HWord)place_to_unchain, len};
3997 return vir;
3998 }
3999
4000 /* Patch the counter address into a profile inc point, as previously
4001 created by the Min_ProfInc case for emit_MIPSInstr. */
patchProfInc_MIPS(VexEndness endness_host,void * place_to_patch,const ULong * location_of_counter,Bool mode64)4002 VexInvalRange patchProfInc_MIPS ( VexEndness endness_host,
4003 void* place_to_patch,
4004 const ULong* location_of_counter,
4005 Bool mode64 )
4006 {
4007 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
4008 if (mode64) {
4009 vassert(sizeof(ULong*) == 8);
4010 } else {
4011 vassert(sizeof(ULong*) == 4);
4012 }
4013 UChar* p = (UChar*)place_to_patch;
4014 vassert(0 == (3 & (HWord)p));
4015 vassert(isLoadImm_EXACTLY2or6((UChar *)p, /*r*/9,
4016 mode64 ? 0x6555655565556555ULL : 0x65556555,
4017 mode64));
4018
4019 if (mode64) {
4020 vassert(fetch32(p + 24 + 0) == 0xDD280000);
4021 vassert(fetch32(p + 24 + 4) == 0x65080001);
4022 vassert(fetch32(p + 24 + 8) == 0xFD280000);
4023 } else {
4024 vassert(fetch32(p + 8 + 0) == 0x8D280000);
4025 vassert(fetch32(p + 8 + 4) == 0x25080001);
4026 vassert(fetch32(p + 8 + 8) == 0xAD280000);
4027 vassert(fetch32(p + 8 + 12) == 0x2d010001);
4028 vassert(fetch32(p + 8 + 16) == 0x8d280004);
4029 vassert(fetch32(p + 8 + 20) == 0x01014021);
4030 vassert(fetch32(p + 8 + 24) == 0xad280004);
4031 }
4032
4033 p = mkLoadImm_EXACTLY2or6(p, /*r*/9,
4034 (Addr)location_of_counter, mode64);
4035
4036 VexInvalRange vir = {(HWord)p, 8};
4037 return vir;
4038 }
4039
4040
4041 /*---------------------------------------------------------------*/
4042 /*--- end host_mips_defs.c ---*/
4043 /*---------------------------------------------------------------*/
4044