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