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-2015 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", (Int)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 = %u\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.syned);
2538 /* addiu */
2539 p = mkFormI(p, 9, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2540 } else {
2541 /* addu */
2542 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 33);
2543 }
2544 break;
2545 case Malu_SUB:
2546 if (immR) {
2547 /* addiu , but with negated imm */
2548 vassert(srcR->Mrh.Imm.syned);
2549 vassert(srcR->Mrh.Imm.imm16 != 0x8000);
2550 p = mkFormI(p, 9, r_srcL, r_dst, (-srcR->Mrh.Imm.imm16));
2551 } else {
2552 /* subu */
2553 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 35);
2554 }
2555 break;
2556 case Malu_AND:
2557 if (immR) {
2558 /* andi */
2559 vassert(!srcR->Mrh.Imm.syned);
2560 p = mkFormI(p, 12, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2561 } else {
2562 /* and */
2563 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 36);
2564 }
2565 break;
2566 case Malu_OR:
2567 if (immR) {
2568 /* ori */
2569 vassert(!srcR->Mrh.Imm.syned);
2570 p = mkFormI(p, 13, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2571 } else {
2572 /* or */
2573 if (r_srcL == 33)
2574 /* MFHI */
2575 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2576 else if (r_srcL == 34)
2577 /* MFLO */
2578 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2579 else if (r_dst == 33)
2580 /* MTHI */
2581 p = mkFormR(p, 0, r_srcL, 0, 0, 0, 17);
2582 else if (r_dst == 34)
2583 /* MTLO */
2584 p = mkFormR(p, 0, r_srcL, 0, 0, 0, 19);
2585 else
2586 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 37);
2587 }
2588 break;
2589 case Malu_NOR:
2590 /* nor */
2591 vassert(!immR);
2592 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 39);
2593 break;
2594 case Malu_XOR:
2595 if (immR) {
2596 /* xori */
2597 vassert(!srcR->Mrh.Imm.syned);
2598 p = mkFormI(p, 14, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2599 } else {
2600 /* xor */
2601 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
2602 }
2603 break;
2604 case Malu_DADD:
2605 if (immR) {
2606 vassert(srcR->Mrh.Imm.syned);
2607 vassert(srcR->Mrh.Imm.imm16 != 0x8000);
2608 p = mkFormI(p, 25, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
2609 } else {
2610 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 45);
2611 }
2612 break;
2613 case Malu_DSUB:
2614 if (immR) {
2615 p = mkFormI(p, 25, r_srcL, r_dst, (-srcR->Mrh.Imm.imm16));
2616 } else {
2617 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 47);
2618 }
2619 break;
2620 case Malu_SLT:
2621 if (immR) {
2622 goto bad;
2623 } else {
2624 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
2625 }
2626 break;
2627
2628 default:
2629 goto bad;
2630 }
2631 goto done;
2632 }
2633
2634 case Min_Shft: {
2635 MIPSRH *srcR = i->Min.Shft.srcR;
2636 Bool sz32 = i->Min.Shft.sz32;
2637 Bool immR = toBool(srcR->tag == Mrh_Imm);
2638 UInt r_dst = iregNo(i->Min.Shft.dst, mode64);
2639 UInt r_srcL = iregNo(i->Min.Shft.srcL, mode64);
2640 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->Mrh.Reg.reg,
2641 mode64);
2642 if (!mode64)
2643 vassert(sz32);
2644 switch (i->Min.Shft.op) {
2645 case Mshft_SLL:
2646 if (sz32) {
2647 if (immR) {
2648 UInt n = srcR->Mrh.Imm.imm16;
2649 vassert(n >= 0 && n <= 32);
2650 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 0);
2651 } else {
2652 /* shift variable */
2653 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 4);
2654 }
2655 } else {
2656 if (immR) {
2657 UInt n = srcR->Mrh.Imm.imm16;
2658 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
2659 if (n >= 0 && n < 32) {
2660 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 56);
2661 } else {
2662 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 60);
2663 }
2664 } else {
2665 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 20);
2666 }
2667 }
2668 break;
2669
2670 case Mshft_SRL:
2671 if (sz32) {
2672 /* SRL, SRLV */
2673 if (immR) {
2674 UInt n = srcR->Mrh.Imm.imm16;
2675 vassert(n >= 0 && n < 32);
2676 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 2);
2677 } else {
2678 /* shift variable */
2679 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 6);
2680 }
2681 } else {
2682 /* DSRL, DSRL32, DSRLV */
2683 if (immR) {
2684 UInt n = srcR->Mrh.Imm.imm16;
2685 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
2686 if (n >= 0 && n < 32) {
2687 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 58);
2688 } else {
2689 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 62);
2690 }
2691 } else {
2692 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 22);
2693 }
2694 }
2695 break;
2696
2697 case Mshft_SRA:
2698 if (sz32) {
2699 /* SRA, SRAV */
2700 if (immR) {
2701 UInt n = srcR->Mrh.Imm.imm16;
2702 vassert(n >= 0 && n < 32);
2703 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 3);
2704 } else {
2705 /* shift variable */
2706 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 7);
2707 }
2708 } else {
2709 /* DSRA, DSRA32, DSRAV */
2710 if (immR) {
2711 UInt n = srcR->Mrh.Imm.imm16;
2712 vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
2713 if (n >= 0 && n < 32) {
2714 p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 59);
2715 } else {
2716 p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 63);
2717 }
2718 } else {
2719 p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 23);
2720 }
2721 }
2722 break;
2723
2724 default:
2725 goto bad;
2726 }
2727
2728 goto done;
2729 }
2730
2731 case Min_Unary: {
2732 UInt r_dst = iregNo(i->Min.Unary.dst, mode64);
2733 UInt r_src = iregNo(i->Min.Unary.src, mode64);
2734
2735 switch (i->Min.Unary.op) {
2736 /* Mun_CLO, Mun_CLZ, Mun_NOP, Mun_DCLO, Mun_DCLZ */
2737 case Mun_CLO: /* clo */
2738 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 33);
2739 break;
2740 case Mun_CLZ: /* clz */
2741 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 32);
2742 break;
2743 case Mun_NOP: /* nop (sll r0,r0,0) */
2744 p = mkFormR(p, 0, 0, 0, 0, 0, 0);
2745 break;
2746 case Mun_DCLO: /* clo */
2747 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 37);
2748 break;
2749 case Mun_DCLZ: /* clz */
2750 p = mkFormR(p, 28, r_src, r_dst , r_dst, 0, 36);
2751 break;
2752 }
2753 goto done;
2754 }
2755
2756 case Min_Cmp: {
2757 UInt r_srcL = iregNo(i->Min.Cmp.srcL, mode64);
2758 UInt r_srcR = iregNo(i->Min.Cmp.srcR, mode64);
2759 UInt r_dst = iregNo(i->Min.Cmp.dst, mode64);
2760
2761 switch (i->Min.Cmp.cond) {
2762 case MIPScc_EQ:
2763 /* xor r_dst, r_srcL, r_srcR
2764 sltiu r_dst, r_dst, 1 */
2765 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
2766 p = mkFormI(p, 11, r_dst, r_dst, 1);
2767 break;
2768 case MIPScc_NE:
2769 /* xor r_dst, r_srcL, r_srcR
2770 sltu r_dst, zero, r_dst */
2771 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
2772 p = mkFormR(p, 0, 0, r_dst, r_dst, 0, 43);
2773 break;
2774 case MIPScc_LT:
2775 /* slt r_dst, r_srcL, r_srcR */
2776 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
2777 break;
2778 case MIPScc_LO:
2779 /* sltu r_dst, r_srcL, r_srcR */
2780 p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 43);
2781 break;
2782 case MIPScc_LE:
2783 /* slt r_dst, r_srcR, r_srcL
2784 xori r_dst, r_dst, 1 */
2785 p = mkFormR(p, 0, r_srcR, r_srcL, r_dst, 0, 42);
2786 p = mkFormI(p, 14, r_dst, r_dst, 1);
2787 break;
2788 case MIPScc_LS:
2789 /* sltu r_dst, rsrcR, r_srcL
2790 xori r_dsr, r_dst, 1 */
2791 p = mkFormR(p, 0, r_srcR, r_srcL, r_dst, 0, 43);
2792 p = mkFormI(p, 14, r_dst, r_dst, 1);
2793 break;
2794 default:
2795 goto bad;
2796 }
2797 goto done;
2798 }
2799
2800 case Min_Mul: {
2801 Bool syned = i->Min.Mul.syned;
2802 Bool widening = i->Min.Mul.widening;
2803 Bool sz32 = i->Min.Mul.sz32;
2804 UInt r_srcL = iregNo(i->Min.Mul.srcL, mode64);
2805 UInt r_srcR = iregNo(i->Min.Mul.srcR, mode64);
2806 UInt r_dst = iregNo(i->Min.Mul.dst, mode64);
2807 if (widening) {
2808 if (sz32) {
2809 if (syned)
2810 /* mult */
2811 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 24);
2812 else
2813 /* multu */
2814 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 25);
2815 } else {
2816 if (syned) /* DMULT r_dst,r_srcL,r_srcR */
2817 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 28);
2818 else /* DMULTU r_dst,r_srcL,r_srcR */
2819 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 29);
2820 }
2821 } else {
2822 if (sz32)
2823 /* mul */
2824 p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
2825 else if (mode64 && !sz32)
2826 p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
2827 else
2828 goto bad;
2829 }
2830 goto done;
2831 }
2832
2833 case Min_Macc: {
2834 Bool syned = i->Min.Macc.syned;
2835 UInt r_srcL = iregNo(i->Min.Macc.srcL, mode64);
2836 UInt r_srcR = iregNo(i->Min.Macc.srcR, mode64);
2837
2838 if (syned) {
2839 switch (i->Min.Macc.op) {
2840 case Macc_ADD:
2841 /* madd */
2842 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0, 0);
2843 break;
2844 case Macc_SUB:
2845 /* msub */
2846 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
2847 4);
2848 break;
2849 default:
2850 goto bad;
2851 }
2852 } else {
2853 switch (i->Min.Macc.op) {
2854 case Macc_ADD:
2855 /* maddu */
2856 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
2857 1);
2858 break;
2859 case Macc_SUB:
2860 /* msubu */
2861 p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
2862 5);
2863 break;
2864 default:
2865 goto bad;
2866 }
2867 }
2868
2869 goto done;
2870 }
2871
2872 case Min_Div: {
2873 Bool syned = i->Min.Div.syned;
2874 Bool sz32 = i->Min.Div.sz32;
2875 UInt r_srcL = iregNo(i->Min.Div.srcL, mode64);
2876 UInt r_srcR = iregNo(i->Min.Div.srcR, mode64);
2877 if (sz32) {
2878 if (syned) {
2879 /* div */
2880 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 26);
2881 } else
2882 /* divu */
2883 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 27);
2884 goto done;
2885 } else {
2886 if (syned) {
2887 /* ddiv */
2888 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 30);
2889 } else
2890 /* ddivu */
2891 p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 31);
2892 goto done;
2893 }
2894 }
2895
2896 case Min_Mthi: {
2897 UInt r_src = iregNo(i->Min.MtHL.src, mode64);
2898 p = mkFormR(p, 0, r_src, 0, 0, 0, 17);
2899 goto done;
2900 }
2901
2902 case Min_Mtlo: {
2903 UInt r_src = iregNo(i->Min.MtHL.src, mode64);
2904 p = mkFormR(p, 0, r_src, 0, 0, 0, 19);
2905 goto done;
2906 }
2907
2908 case Min_Mfhi: {
2909 UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
2910 p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
2911 goto done;
2912 }
2913
2914 case Min_Mflo: {
2915 UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
2916 p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
2917 goto done;
2918 }
2919
2920 case Min_MtFCSR: {
2921 UInt r_src = iregNo(i->Min.MtFCSR.src, mode64);
2922 /* ctc1 */
2923 p = mkFormR(p, 17, 6, r_src, 31, 0, 0);
2924 goto done;
2925 }
2926
2927 case Min_MfFCSR: {
2928 UInt r_dst = iregNo(i->Min.MfFCSR.dst, mode64);
2929 /* cfc1 */
2930 p = mkFormR(p, 17, 2, r_dst, 31, 0, 0);
2931 goto done;
2932 }
2933
2934 case Min_Call: {
2935 if (i->Min.Call.cond != MIPScc_AL
2936 && i->Min.Call.rloc.pri != RLPri_None) {
2937 /* The call might not happen (it isn't unconditional) and
2938 it returns a result. In this case we will need to
2939 generate a control flow diamond to put 0x555..555 in
2940 the return register(s) in the case where the call
2941 doesn't happen. If this ever becomes necessary, maybe
2942 copy code from the ARM equivalent. Until that day,
2943 just give up. */
2944 goto bad;
2945 }
2946 MIPSCondCode cond = i->Min.Call.cond;
2947 UInt r_dst = 25; /* using %r25 as address temporary -
2948 see getRegUsage_MIPSInstr */
2949
2950 /* jump over the following insns if condition does not hold */
2951 if (cond != MIPScc_AL) {
2952 /* jmp fwds if !condition */
2953 /* don't know how many bytes to jump over yet...
2954 make space for a jump instruction + nop!!! and fill in later. */
2955 ptmp = p; /* fill in this bit later */
2956 p += 8; /* p += 8 */
2957 }
2958
2959 if (!mode64) {
2960 /* addiu $29, $29, -16 */
2961 p = mkFormI(p, 9, 29, 29, 0xFFF0);
2962 }
2963
2964 /* load target to r_dst; p += 4|8 */
2965 p = mkLoadImm(p, r_dst, i->Min.Call.target, mode64);
2966
2967 /* jalr r_dst */
2968 p = mkFormR(p, 0, r_dst, 0, 31, 0, 9); /* p += 4 */
2969 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
2970
2971 if (!mode64) {
2972 /* addiu $29, $29, 16 */
2973 p = mkFormI(p, 9, 29, 29, 0x0010);
2974 }
2975
2976 /* Fix up the conditional jump, if there was one. */
2977 if (cond != MIPScc_AL) {
2978 UInt r_src = iregNo(i->Min.Call.src, mode64);
2979 Int delta = p - ptmp;
2980
2981 vassert(delta >= 20 && delta <= 32);
2982 /* blez r_src, delta/4-1
2983 nop */
2984 ptmp = mkFormI(ptmp, 6, r_src, 0, delta / 4 - 1);
2985 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
2986 }
2987 goto done;
2988 }
2989
2990 case Min_XDirect: {
2991 /* NB: what goes on here has to be very closely coordinated
2992 with the chainXDirect_MIPS and unchainXDirect_MIPS below. */
2993 /* We're generating chain-me requests here, so we need to be
2994 sure this is actually allowed -- no-redir translations
2995 can't use chain-me's. Hence: */
2996 vassert(disp_cp_chain_me_to_slowEP != NULL);
2997 vassert(disp_cp_chain_me_to_fastEP != NULL);
2998
2999 /* Use ptmp for backpatching conditional jumps. */
3000 ptmp = NULL;
3001
3002 /* First off, if this is conditional, create a conditional
3003 jump over the rest of it. Or at least, leave a space for
3004 it that we will shortly fill in. */
3005 if (i->Min.XDirect.cond != MIPScc_AL) {
3006 vassert(i->Min.XDirect.cond != MIPScc_NV);
3007 ptmp = p;
3008 p += 12;
3009 }
3010
3011 /* Update the guest PC. */
3012 /* move r9, dstGA */
3013 /* sw/sd r9, amPC */
3014 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, (ULong)i->Min.XDirect.dstGA,
3015 mode64);
3016 p = do_load_or_store_machine_word(p, False /*!isLoad*/ , /*r*/ 9,
3017 i->Min.XDirect.amPC, mode64);
3018
3019 /* --- FIRST PATCHABLE BYTE follows --- */
3020 /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're
3021 calling to) backs up the return address, so as to find the
3022 address of the first patchable byte. So: don't change the
3023 number of instructions (3) below. */
3024 /* move r9, VG_(disp_cp_chain_me_to_{slowEP,fastEP}) */
3025 /* jr r9 */
3026 const void* disp_cp_chain_me
3027 = i->Min.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
3028 : disp_cp_chain_me_to_slowEP;
3029 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3030 (Addr)disp_cp_chain_me, mode64);
3031 /* jalr $9 */
3032 /* nop */
3033 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3034 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3035 /* --- END of PATCHABLE BYTES --- */
3036
3037 /* Fix up the conditional jump, if there was one. */
3038 if (i->Min.XDirect.cond != MIPScc_AL) {
3039 Int delta = p - ptmp;
3040 delta = delta / 4 - 3;
3041 vassert(delta > 0 && delta < 40);
3042
3043 /* lw $9, COND_OFFSET(GuestSP)
3044 beq $9, $0, 2
3045 nop */
3046 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
3047 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
3048 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
3049 }
3050 goto done;
3051 }
3052
3053 case Min_XIndir: {
3054 /* We're generating transfers that could lead indirectly to a
3055 chain-me, so we need to be sure this is actually allowed --
3056 no-redir translations are not allowed to reach normal
3057 translations without going through the scheduler. That means
3058 no XDirects or XIndirs out from no-redir translations.
3059 Hence: */
3060 vassert(disp_cp_xindir != NULL);
3061
3062 /* Use ptmp for backpatching conditional jumps. */
3063 ptmp = NULL;
3064
3065 /* First off, if this is conditional, create a conditional
3066 jump over the rest of it. */
3067 if (i->Min.XIndir.cond != MIPScc_AL) {
3068 vassert(i->Min.XIndir.cond != MIPScc_NV);
3069 ptmp = p;
3070 p += 12;
3071 }
3072
3073 /* Update the guest PC. */
3074 /* sw/sd r-dstGA, amPC */
3075 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
3076 iregNo(i->Min.XIndir.dstGA, mode64),
3077 i->Min.XIndir.amPC, mode64);
3078
3079 /* move r9, VG_(disp_cp_xindir) */
3080 /* jalr r9 */
3081 /* nop */
3082 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3083 (Addr)disp_cp_xindir, mode64);
3084 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3085 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3086
3087 /* Fix up the conditional jump, if there was one. */
3088 if (i->Min.XIndir.cond != MIPScc_AL) {
3089 Int delta = p - ptmp;
3090 delta = delta / 4 - 3;
3091 vassert(delta > 0 && delta < 40);
3092
3093 /* lw $9, COND_OFFSET($GuestSP)
3094 beq $9, $0, 2
3095 nop */
3096 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
3097 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
3098 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
3099 }
3100 goto done;
3101 }
3102
3103 case Min_XAssisted: {
3104 /* First off, if this is conditional, create a conditional jump
3105 over the rest of it. Or at least, leave a space for it that
3106 we will shortly fill in. */
3107 ptmp = NULL;
3108 if (i->Min.XAssisted.cond != MIPScc_AL) {
3109 vassert(i->Min.XAssisted.cond != MIPScc_NV);
3110 ptmp = p;
3111 p += 12;
3112 }
3113
3114 /* Update the guest PC. */
3115 /* sw/sd r-dstGA, amPC */
3116 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
3117 iregNo(i->Min.XIndir.dstGA, mode64),
3118 i->Min.XIndir.amPC, mode64);
3119
3120 /* imm32/64 r31, $magic_number */
3121 UInt trcval = 0;
3122 switch (i->Min.XAssisted.jk) {
3123 case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
3124 case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
3125 /* case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break; */
3126 case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
3127 case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
3128 case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
3129 /* case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break; */
3130 case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
3131 case Ijk_InvalICache: trcval = VEX_TRC_JMP_INVALICACHE; break;
3132 case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
3133 case Ijk_SigILL: trcval = VEX_TRC_JMP_SIGILL; break;
3134 case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
3135 /* case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break; */
3136 case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break;
3137 case Ijk_SigFPE_IntDiv: trcval = VEX_TRC_JMP_SIGFPE_INTDIV; break;
3138 case Ijk_SigFPE_IntOvf: trcval = VEX_TRC_JMP_SIGFPE_INTOVF; break;
3139 case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
3140 /* We don't expect to see the following being assisted.
3141 case Ijk_Ret:
3142 case Ijk_Call:
3143 fallthrough */
3144 default:
3145 ppIRJumpKind(i->Min.XAssisted.jk);
3146 vpanic("emit_MIPSInstr.Min_XAssisted: unexpected jump kind");
3147 }
3148 vassert(trcval != 0);
3149 p = mkLoadImm_EXACTLY2or6(p, /*r*/ GuestSP, trcval, mode64);
3150
3151 /* move r9, VG_(disp_cp_xassisted) */
3152 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3153 (ULong)(Addr)disp_cp_xassisted, mode64);
3154 /* jalr $9
3155 nop */
3156 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3157 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3158
3159 /* Fix up the conditional jump, if there was one. */
3160 if (i->Min.XAssisted.cond != MIPScc_AL) {
3161 Int delta = p - ptmp;
3162 delta = delta / 4 - 3;
3163 vassert(delta > 0 && delta < 40);
3164
3165 /* lw $9, COND_OFFSET($GuestSP)
3166 beq $9, $0, 2
3167 nop */
3168 ptmp = mkFormI(ptmp, 35, GuestSP, 9, COND_OFFSET(mode64));
3169 ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
3170 mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
3171 }
3172 goto done;
3173 }
3174
3175 case Min_Load: {
3176 MIPSAMode *am_addr = i->Min.Load.src;
3177 if (am_addr->tag == Mam_IR) {
3178 UInt r_dst = iregNo(i->Min.Load.dst, mode64);
3179 UInt opc, sz = i->Min.Load.sz;
3180 if (mode64 && (sz == 4 || sz == 8)) {
3181 /* should be guaranteed to us by iselWordExpr_AMode */
3182 vassert(0 == (am_addr->Mam.IR.index & 3));
3183 }
3184 switch (sz) {
3185 case 1:
3186 opc = 32;
3187 break;
3188 case 2:
3189 opc = 33;
3190 break;
3191 case 4:
3192 opc = 35;
3193 break;
3194 case 8:
3195 opc = 55;
3196 vassert(mode64);
3197 break;
3198 default:
3199 goto bad;
3200 }
3201
3202 p = doAMode_IR(p, opc, r_dst, am_addr, mode64);
3203 goto done;
3204 } else if (am_addr->tag == Mam_RR) {
3205 UInt r_dst = iregNo(i->Min.Load.dst, mode64);
3206 UInt opc, sz = i->Min.Load.sz;
3207
3208 switch (sz) {
3209 case 1:
3210 opc = 32;
3211 break;
3212 case 2:
3213 opc = 33;
3214 break;
3215 case 4:
3216 opc = 35;
3217 break;
3218 case 8:
3219 opc = 55;
3220 vassert(mode64);
3221 break;
3222 default:
3223 goto bad;
3224 }
3225
3226 p = doAMode_RR(p, opc, r_dst, am_addr, mode64);
3227 goto done;
3228 }
3229 break;
3230 }
3231
3232 case Min_Store: {
3233 MIPSAMode *am_addr = i->Min.Store.dst;
3234 if (am_addr->tag == Mam_IR) {
3235 UInt r_src = iregNo(i->Min.Store.src, mode64);
3236 UInt opc, sz = i->Min.Store.sz;
3237 if (mode64 && (sz == 4 || sz == 8)) {
3238 /* should be guaranteed to us by iselWordExpr_AMode */
3239 vassert(0 == (am_addr->Mam.IR.index & 3));
3240 }
3241 switch (sz) {
3242 case 1:
3243 opc = 40;
3244 break;
3245 case 2:
3246 opc = 41;
3247 break;
3248 case 4:
3249 opc = 43;
3250 break;
3251 case 8:
3252 vassert(mode64);
3253 opc = 63;
3254 break;
3255 default:
3256 goto bad;
3257 }
3258
3259 p = doAMode_IR(p, opc, r_src, am_addr, mode64);
3260 goto done;
3261 } else if (am_addr->tag == Mam_RR) {
3262 UInt r_src = iregNo(i->Min.Store.src, mode64);
3263 UInt opc, sz = i->Min.Store.sz;
3264
3265 switch (sz) {
3266 case 1:
3267 opc = 40;
3268 break;
3269 case 2:
3270 opc = 41;
3271 break;
3272 case 4:
3273 opc = 43;
3274 break;
3275 case 8:
3276 vassert(mode64);
3277 opc = 63;
3278 break;
3279 default:
3280 goto bad;
3281 }
3282
3283 p = doAMode_RR(p, opc, r_src, am_addr, mode64);
3284 goto done;
3285 }
3286 break;
3287 }
3288 case Min_LoadL: {
3289 MIPSAMode *am_addr = i->Min.LoadL.src;
3290 UInt r_src = iregNo(am_addr->Mam.IR.base, mode64);
3291 UInt idx = am_addr->Mam.IR.index;
3292 UInt r_dst = iregNo(i->Min.LoadL.dst, mode64);
3293
3294 if (i->Min.LoadL.sz == 4)
3295 p = mkFormI(p, 0x30, r_src, r_dst, idx);
3296 else
3297 p = mkFormI(p, 0x34, r_src, r_dst, idx);
3298 goto done;
3299 }
3300 case Min_StoreC: {
3301 MIPSAMode *am_addr = i->Min.StoreC.dst;
3302 UInt r_src = iregNo(i->Min.StoreC.src, mode64);
3303 UInt idx = am_addr->Mam.IR.index;
3304 UInt r_dst = iregNo(am_addr->Mam.IR.base, mode64);
3305
3306 if (i->Min.StoreC.sz == 4)
3307 p = mkFormI(p, 0x38, r_dst, r_src, idx);
3308 else
3309 p = mkFormI(p, 0x3C, r_dst, r_src, idx);
3310 goto done;
3311 }
3312 case Min_Cas: {
3313 if (i->Min.Cas.sz != 8 && i->Min.Cas.sz != 4)
3314 goto bad;
3315 UInt old = iregNo(i->Min.Cas.old, mode64);
3316 UInt addr = iregNo(i->Min.Cas.addr, mode64);
3317 UInt expd = iregNo(i->Min.Cas.expd, mode64);
3318 UInt data = iregNo(i->Min.Cas.data, mode64);
3319 Bool sz8 = toBool(i->Min.Cas.sz == 8);
3320
3321 /*
3322 * ll(d) old, 0(addr)
3323 * bne old, expd, end
3324 * nop
3325 * (d)addiu old, old, 1
3326 * sc(d) data, 0(addr)
3327 * movn old, expd, data
3328 * end:
3329 */
3330 // ll(d) old, 0(addr)
3331 p = mkFormI(p, sz8 ? 0x34 : 0x30, addr, old, 0);
3332 // bne old, expd, end
3333 p = mkFormI(p, 5, old, expd, 4);
3334 // nop
3335 p = mkFormR(p, 0, 0, 0, 0, 0, 0);
3336 // (d)addiu old, old, 1
3337 p = mkFormI(p, sz8 ? 25 : 9, old, old, 1);
3338 // sc(d) data, 0(addr)
3339 p = mkFormI(p, sz8 ? 0x3C : 0x38, addr, data, 0);
3340 // movn old, expd, data
3341 p = mkFormR(p, 0, expd, data, old, 0, 0xb);
3342
3343 goto done;
3344 }
3345 case Min_RdWrLR: {
3346 UInt reg = iregNo(i->Min.RdWrLR.gpr, mode64);
3347 Bool wrLR = i->Min.RdWrLR.wrLR;
3348 if (wrLR)
3349 p = mkMoveReg(p, 31, reg);
3350 else
3351 p = mkMoveReg(p, reg, 31);
3352 goto done;
3353 }
3354
3355 /* Floating point */
3356 case Min_FpLdSt: {
3357 MIPSAMode *am_addr = i->Min.FpLdSt.addr;
3358 UChar sz = i->Min.FpLdSt.sz;
3359 vassert(sz == 4 || sz == 8);
3360 if (sz == 4) {
3361 UInt f_reg = fregNo(i->Min.FpLdSt.reg, mode64);
3362 if (i->Min.FpLdSt.isLoad) {
3363 if (am_addr->tag == Mam_IR)
3364 p = doAMode_IR(p, 0x31, f_reg, am_addr, mode64);
3365 else if (am_addr->tag == Mam_RR)
3366 p = doAMode_RR(p, 0x31, f_reg, am_addr, mode64);
3367 } else {
3368 if (am_addr->tag == Mam_IR)
3369 p = doAMode_IR(p, 0x39, f_reg, am_addr, mode64);
3370 else if (am_addr->tag == Mam_RR)
3371 p = doAMode_RR(p, 0x39, f_reg, am_addr, mode64);
3372 }
3373 } else if (sz == 8) {
3374 UInt f_reg = dregNo(i->Min.FpLdSt.reg);
3375 if (i->Min.FpLdSt.isLoad) {
3376 if (am_addr->tag == Mam_IR) {
3377 p = doAMode_IR(p, 0x35, f_reg, am_addr, mode64);
3378 } else if (am_addr->tag == Mam_RR) {
3379 p = doAMode_RR(p, 0x35, f_reg, am_addr, mode64);
3380 }
3381 } else {
3382 if (am_addr->tag == Mam_IR) {
3383 p = doAMode_IR(p, 0x3d, f_reg, am_addr, mode64);
3384 } else if (am_addr->tag == Mam_RR) {
3385 p = doAMode_RR(p, 0x3d, f_reg, am_addr, mode64);
3386 }
3387 }
3388 }
3389 goto done;
3390 }
3391
3392 case Min_FpUnary: {
3393 switch (i->Min.FpUnary.op) {
3394 case Mfp_MOVS: { /* FP move */
3395 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3396 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3397 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x6);
3398 break;
3399 }
3400 case Mfp_MOVD: { /* FP move */
3401 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3402 UInt fr_src = dregNo(i->Min.FpUnary.src);
3403 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x6);
3404 break;
3405 }
3406 case Mfp_ABSS: { /* ABS.S */
3407 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3408 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3409 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x5);
3410 break;
3411 }
3412 case Mfp_ABSD: { /* ABS.D */
3413 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3414 UInt fr_src = dregNo(i->Min.FpUnary.src);
3415 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x5);
3416 break;
3417 }
3418 case Mfp_NEGS: { /* NEG.S */
3419 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3420 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3421 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x7);
3422 break;
3423 }
3424 case Mfp_NEGD: { /* NEG.D */
3425 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3426 UInt fr_src = dregNo(i->Min.FpUnary.src);
3427 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x7);
3428 break;
3429 }
3430 case Mfp_SQRTS: { /* SQRT.S */
3431 UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
3432 UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
3433 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x04);
3434 break;
3435 }
3436 case Mfp_SQRTD: { /* SQRT.D */
3437 UInt fr_dst = dregNo(i->Min.FpUnary.dst);
3438 UInt fr_src = dregNo(i->Min.FpUnary.src);
3439 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x04);
3440 break;
3441 }
3442 default:
3443 goto bad;
3444 }
3445 goto done;
3446 }
3447
3448 case Min_FpBinary: {
3449 switch (i->Min.FpBinary.op) {
3450 case Mfp_ADDS: {
3451 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3452 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3453 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3454 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 0);
3455 break;
3456 }
3457 case Mfp_SUBS: {
3458 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3459 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3460 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3461 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 1);
3462 break;
3463 }
3464 case Mfp_MULS: {
3465 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3466 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3467 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3468 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 2);
3469 break;
3470 }
3471 case Mfp_DIVS: {
3472 UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
3473 UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
3474 UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
3475 p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 3);
3476 break;
3477 }
3478 case Mfp_ADDD: {
3479 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3480 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3481 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3482 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 0);
3483 break;
3484 }
3485 case Mfp_SUBD: {
3486 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3487 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3488 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3489 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 1);
3490 break;
3491 }
3492 case Mfp_MULD: {
3493 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3494 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3495 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3496 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 2);
3497 break;
3498 }
3499 case Mfp_DIVD: {
3500 UInt fr_dst = dregNo(i->Min.FpBinary.dst);
3501 UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
3502 UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
3503 p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 3);
3504 break;
3505 }
3506 default:
3507 goto bad;
3508 }
3509 goto done;
3510 }
3511
3512 case Min_FpTernary: {
3513 switch (i->Min.FpTernary.op) {
3514 case Mfp_MADDS: {
3515 UInt fr_dst = fregNo(i->Min.FpTernary.dst, mode64);
3516 UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64);
3517 UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64);
3518 UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64);
3519 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x20);
3520 break;
3521 }
3522 case Mfp_MADDD: {
3523 UInt fr_dst = dregNo(i->Min.FpTernary.dst);
3524 UInt fr_src1 = dregNo(i->Min.FpTernary.src1);
3525 UInt fr_src2 = dregNo(i->Min.FpTernary.src2);
3526 UInt fr_src3 = dregNo(i->Min.FpTernary.src3);
3527 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x21);
3528 break;
3529 }
3530 case Mfp_MSUBS: {
3531 UInt fr_dst = fregNo(i->Min.FpTernary.dst, mode64);
3532 UInt fr_src1 = fregNo(i->Min.FpTernary.src1, mode64);
3533 UInt fr_src2 = fregNo(i->Min.FpTernary.src2, mode64);
3534 UInt fr_src3 = fregNo(i->Min.FpTernary.src3, mode64);
3535 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x28);
3536 break;
3537 }
3538 case Mfp_MSUBD: {
3539 UInt fr_dst = dregNo(i->Min.FpTernary.dst);
3540 UInt fr_src1 = dregNo(i->Min.FpTernary.src1);
3541 UInt fr_src2 = dregNo(i->Min.FpTernary.src2);
3542 UInt fr_src3 = dregNo(i->Min.FpTernary.src3);
3543 p = mkFormR(p, 0x13, fr_src1, fr_src2, fr_src3, fr_dst, 0x29);
3544 break;
3545 }
3546 default:
3547 goto bad;
3548 }
3549 goto done;
3550 }
3551
3552 case Min_FpConvert: {
3553 switch (i->Min.FpConvert.op) {
3554 UInt fr_dst, fr_src;
3555 case Mfp_CVTSD:
3556 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3557 fr_src = dregNo(i->Min.FpConvert.src);
3558 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x20);
3559 break;
3560 case Mfp_CVTSW:
3561 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3562 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3563 p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x20);
3564 break;
3565 case Mfp_CVTWD:
3566 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3567 fr_src = dregNo(i->Min.FpConvert.src);
3568 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x24);
3569 break;
3570 case Mfp_CVTWS:
3571 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3572 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3573 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x24);
3574 break;
3575 case Mfp_CVTDW:
3576 fr_dst = dregNo(i->Min.FpConvert.dst);
3577 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3578 p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x21);
3579 break;
3580 case Mfp_CVTDL:
3581 fr_dst = dregNo(i->Min.FpConvert.dst);
3582 fr_src = dregNo(i->Min.FpConvert.src);
3583 p = mkFormR(p, 0x11, 0x15, 0, fr_src, fr_dst, 0x21);
3584 break;
3585 case Mfp_CVTDS:
3586 fr_dst = dregNo(i->Min.FpConvert.dst);
3587 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3588 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x21);
3589 break;
3590 case Mfp_CVTSL:
3591 fr_dst = dregNo(i->Min.FpConvert.dst);
3592 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3593 p = mkFormR(p, 0x11, 0x15, 0, fr_src, fr_dst, 0x20);
3594 break;
3595 case Mfp_CVTLS:
3596 if (mode64) {
3597 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3598 fr_src = dregNo(i->Min.FpConvert.src);
3599 } else {
3600 fr_dst = dregNo(i->Min.FpConvert.dst);
3601 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3602 }
3603 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x25);
3604 break;
3605 case Mfp_CVTLD:
3606 fr_dst = dregNo(i->Min.FpConvert.dst);
3607 fr_src = dregNo(i->Min.FpConvert.src);
3608 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x25);
3609 break;
3610 case Mfp_TRUWS:
3611 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3612 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3613 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0D);
3614 break;
3615 case Mfp_TRUWD:
3616 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3617 fr_src = dregNo(i->Min.FpConvert.src);
3618 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0D);
3619 break;
3620 case Mfp_TRULS:
3621 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3622 fr_src = dregNo(i->Min.FpConvert.src);
3623 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x09);
3624 break;
3625 case Mfp_TRULD:
3626 fr_dst = dregNo(i->Min.FpConvert.dst);
3627 fr_src = dregNo(i->Min.FpConvert.src);
3628 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x09);
3629 break;
3630 case Mfp_CEILWS:
3631 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3632 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3633 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0E);
3634 break;
3635 case Mfp_CEILWD:
3636 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3637 fr_src = dregNo(i->Min.FpConvert.src);
3638 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0E);
3639 break;
3640 case Mfp_CEILLS:
3641 fr_dst = dregNo(i->Min.FpConvert.dst);
3642 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3643 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0A);
3644 break;
3645 case Mfp_CEILLD:
3646 fr_dst = dregNo(i->Min.FpConvert.dst);
3647 fr_src = dregNo(i->Min.FpConvert.src);
3648 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0A);
3649 break;
3650 case Mfp_ROUNDWS:
3651 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3652 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3653 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0C);
3654 break;
3655 case Mfp_ROUNDWD:
3656 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3657 fr_src = dregNo(i->Min.FpConvert.src);
3658 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0C);
3659 break;
3660 case Mfp_ROUNDLD:
3661 fr_dst = dregNo(i->Min.FpConvert.dst);
3662 fr_src = dregNo(i->Min.FpConvert.src);
3663 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x08);
3664 break;
3665 case Mfp_FLOORWS:
3666 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3667 fr_src = fregNo(i->Min.FpConvert.src, mode64);
3668 p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0F);
3669 break;
3670 case Mfp_FLOORWD:
3671 fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
3672 fr_src = dregNo(i->Min.FpConvert.src);
3673 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0F);
3674 break;
3675 case Mfp_FLOORLD:
3676 fr_dst = dregNo(i->Min.FpConvert.dst);
3677 fr_src = dregNo(i->Min.FpConvert.src);
3678 p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0B);
3679 break;
3680
3681 default:
3682 goto bad;
3683 }
3684 goto done;
3685 }
3686
3687 case Min_FpCompare: {
3688 UInt r_dst = iregNo(i->Min.FpCompare.dst, mode64);
3689 UInt fr_srcL = dregNo(i->Min.FpCompare.srcL);
3690 UInt fr_srcR = dregNo(i->Min.FpCompare.srcR);
3691
3692 UInt op;
3693 switch (i->Min.FpConvert.op) {
3694 case Mfp_CMP_UN:
3695 op = 1;
3696 break;
3697 case Mfp_CMP_EQ:
3698 op = 2;
3699 break;
3700 case Mfp_CMP_LT:
3701 op = 12;
3702 break;
3703 case Mfp_CMP_NGT:
3704 op = 15;
3705 break;
3706 default:
3707 goto bad;
3708 }
3709 /* c.cond.d fr_srcL, fr_srcR
3710 cfc1 r_dst, $31
3711 srl r_dst, r_dst, 23
3712 andi r_dst, r_dst, 1 */
3713 p = mkFormR(p, 0x11, 0x11, fr_srcL, fr_srcR, 0, op + 48);
3714 p = mkFormR(p, 0x11, 0x2, r_dst, 31, 0, 0);
3715 p = mkFormS(p, 0, r_dst, 0, r_dst, 23, 2);
3716 p = mkFormI(p, 12, r_dst, r_dst, 1);
3717 goto done;
3718 }
3719
3720 case Min_FpGpMove: {
3721 switch (i->Min.FpGpMove.op) {
3722 UInt rt, fs;
3723 case MFpGpMove_mfc1: {
3724 rt = iregNo(i->Min.FpGpMove.dst, mode64);
3725 fs = fregNo(i->Min.FpGpMove.src, mode64);
3726 p = mkFormR(p, 0x11, 0x0, rt, fs, 0x0, 0x0);
3727 break;
3728 }
3729 case MFpGpMove_dmfc1: {
3730 vassert(mode64);
3731 rt = iregNo(i->Min.FpGpMove.dst, mode64);
3732 fs = fregNo(i->Min.FpGpMove.src, mode64);
3733 p = mkFormR(p, 0x11, 0x1, rt, fs, 0x0, 0x0);
3734 break;
3735 }
3736 case MFpGpMove_mtc1: {
3737 rt = iregNo(i->Min.FpGpMove.src, mode64);
3738 fs = fregNo(i->Min.FpGpMove.dst, mode64);
3739 p = mkFormR(p, 0x11, 0x4, rt, fs, 0x0, 0x0);
3740 break;
3741 }
3742 case MFpGpMove_dmtc1: {
3743 vassert(mode64);
3744 rt = iregNo(i->Min.FpGpMove.src, mode64);
3745 fs = fregNo(i->Min.FpGpMove.dst, mode64);
3746 p = mkFormR(p, 0x11, 0x5, rt, fs, 0x0, 0x0);
3747 break;
3748 }
3749 default:
3750 goto bad;
3751 }
3752 goto done;
3753 }
3754
3755 case Min_MoveCond: {
3756 switch (i->Min.MoveCond.op) {
3757 UInt d, s, t;
3758 case MFpMoveCond_movns: {
3759 d = fregNo(i->Min.MoveCond.dst, mode64);
3760 s = fregNo(i->Min.MoveCond.src, mode64);
3761 t = iregNo(i->Min.MoveCond.cond, mode64);
3762 p = mkFormR(p, 0x11, 0x10, t, s, d, 0x13);
3763 break;
3764 }
3765 case MFpMoveCond_movnd: {
3766 d = dregNo(i->Min.MoveCond.dst);
3767 s = dregNo(i->Min.MoveCond.src);
3768 t = iregNo(i->Min.MoveCond.cond, mode64);
3769 p = mkFormR(p, 0x11, 0x11, t, s, d, 0x13);
3770 break;
3771 }
3772 case MMoveCond_movn: {
3773 d = iregNo(i->Min.MoveCond.dst, mode64);
3774 s = iregNo(i->Min.MoveCond.src, mode64);
3775 t = iregNo(i->Min.MoveCond.cond, mode64);
3776 p = mkFormR(p, 0, s, t, d, 0, 0xb);
3777 break;
3778 }
3779 default:
3780 goto bad;
3781 }
3782 goto done;
3783 }
3784
3785 case Min_EvCheck: {
3786 /* This requires a 32-bit dec/test in 32 mode. */
3787 /* We generate:
3788 lw r9, amCounter
3789 addiu r9, r9, -1
3790 sw r9, amCounter
3791 bgez r9, nofail
3792 lw r9, amFailAddr
3793 jalr r9
3794 nop
3795 nofail:
3796 */
3797 UChar* p0 = p;
3798 /* lw r9, amCounter */
3799 p = do_load_or_store_word32(p, True /*isLoad*/ , /*r*/ 9,
3800 i->Min.EvCheck.amCounter, mode64);
3801 /* addiu r9,r9,-1 */
3802 p = mkFormI(p, 9, 9, 9, 0xFFFF);
3803 /* sw r30, amCounter */
3804 p = do_load_or_store_word32(p, False /*!isLoad*/ , /*r*/ 9,
3805 i->Min.EvCheck.amCounter, mode64);
3806 /* bgez t9, nofail */
3807 p = mkFormI(p, 1, 9, 1, 3);
3808 /* lw/ld r9, amFailAddr */
3809 p = do_load_or_store_machine_word(p, True /*isLoad*/ , /*r*/ 9,
3810 i->Min.EvCheck.amFailAddr, mode64);
3811 /* jalr $9 */
3812 p = mkFormR(p, 0, 9, 0, 31, 0, 9); /* p += 4 */
3813 p = mkFormR(p, 0, 0, 0, 0, 0, 0); /* p += 4 */
3814 /* nofail: */
3815
3816 /* Crosscheck */
3817 vassert(evCheckSzB_MIPS() == (UChar*)p - (UChar*)p0);
3818 goto done;
3819 }
3820
3821 case Min_ProfInc: {
3822 /* Generate a code template to increment a memory location whose
3823 address will be known later as an immediate value. This code
3824 template will be patched once the memory location is known.
3825 For now we do this with address == 0x65556555. */
3826 if (mode64) {
3827 /* 64-bit:
3828 move r9, 0x6555655565556555ULL
3829 ld r8, 0(r9)
3830 daddiu r8, r8, 1
3831 sd r8, 0(r9) */
3832
3833 /* move r9, 0x6555655565556555ULL */
3834 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, 0x6555655565556555ULL,
3835 True /*mode64*/);
3836 /* ld r8, 0(r9) */
3837 p = mkFormI(p, 55, 9, 8, 0);
3838
3839 /* daddiu r8, r8, 1 */
3840 p = mkFormI(p, 25, 8, 8, 1);
3841
3842 /* sd r8, 0(r9) */
3843 p = mkFormI(p, 63, 9, 8, 0);
3844 } else {
3845 /* 32-bit:
3846 move r9, 0x65556555
3847 lw r8, 0(r9)
3848 addiu r8, r8, 1 # add least significant word
3849 sw r8, 0(r9)
3850 sltiu r1, r8, 1 # set carry-in bit
3851 lw r8, 4(r9)
3852 addu r8, r8, r1
3853 sw r8, 4(r9) */
3854
3855 /* move r9, 0x65556555 */
3856 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9, 0x65556555ULL,
3857 False /*!mode64*/);
3858 /* lw r8, 0(r9) */
3859 p = mkFormI(p, 35, 9, 8, 0);
3860
3861 /* addiu r8, r8, 1 # add least significant word */
3862 p = mkFormI(p, 9, 8, 8, 1);
3863
3864 /* sw r8, 0(r9) */
3865 p = mkFormI(p, 43, 9, 8, 0);
3866
3867 /* sltiu r1, r8, 1 # set carry-in bit */
3868 p = mkFormI(p, 11, 8, 1, 1);
3869
3870 /* lw r8, 4(r9) */
3871 p = mkFormI(p, 35, 9, 8, 4);
3872
3873 /* addu r8, r8, r1 */
3874 p = mkFormR(p, 0, 8, 1, 8, 0, 33);
3875
3876 /* sw r8, 4(r9) */
3877 p = mkFormI(p, 43, 9, 8, 4);
3878
3879 }
3880 /* Tell the caller .. */
3881 vassert(!(*is_profInc));
3882 *is_profInc = True;
3883 goto done;
3884 }
3885
3886 default:
3887 goto bad;
3888
3889 }
3890
3891 bad:
3892 vex_printf("\n=> ");
3893 ppMIPSInstr(i, mode64);
3894 vpanic("emit_MIPSInstr");
3895 /* NOTREACHED */ done:
3896 vassert(p - &buf[0] <= 128);
3897 return p - &buf[0];
3898 }
3899
3900 /* How big is an event check? See case for Min_EvCheck in
3901 emit_MIPSInstr just above. That crosschecks what this returns, so
3902 we can tell if we're inconsistent. */
evCheckSzB_MIPS(void)3903 Int evCheckSzB_MIPS (void)
3904 {
3905 UInt kInstrSize = 4;
3906 return 7*kInstrSize;
3907 }
3908
3909 /* NB: what goes on here has to be very closely coordinated with the
3910 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)3911 VexInvalRange chainXDirect_MIPS ( VexEndness endness_host,
3912 void* place_to_chain,
3913 const void* disp_cp_chain_me_EXPECTED,
3914 const void* place_to_jump_to,
3915 Bool mode64 )
3916 {
3917 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
3918 /* What we're expecting to see is:
3919 move r9, disp_cp_chain_me_to_EXPECTED
3920 jalr r9
3921 nop
3922 viz
3923 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
3924 0x120F809 # jalr r9
3925 0x00000000 # nop
3926 */
3927 UChar* p = (UChar*)place_to_chain;
3928 vassert(0 == (3 & (HWord)p));
3929 vassert(isLoadImm_EXACTLY2or6(p, /*r*/9,
3930 (UInt)(Addr)disp_cp_chain_me_EXPECTED,
3931 mode64));
3932 vassert(fetch32(p + (mode64 ? 24 : 8) + 0) == 0x120F809);
3933 vassert(fetch32(p + (mode64 ? 24 : 8) + 4) == 0x00000000);
3934 /* And what we want to change it to is either:
3935 move r9, place_to_jump_to
3936 jalr r9
3937 nop
3938 viz
3939 <8 bytes generated by mkLoadImm_EXACTLY2or6>
3940 0x120F809 # jalr r9
3941 0x00000000 # nop
3942
3943 The replacement has the same length as the original.
3944 */
3945
3946 p = mkLoadImm_EXACTLY2or6(p, /*r*/9,
3947 (Addr)place_to_jump_to, mode64);
3948 p = emit32(p, 0x120F809);
3949 p = emit32(p, 0x00000000);
3950
3951 Int len = p - (UChar*)place_to_chain;
3952 vassert(len == (mode64 ? 32 : 16)); /* stay sane */
3953 VexInvalRange vir = {(HWord)place_to_chain, len};
3954 return vir;
3955 }
3956
3957 /* NB: what goes on here has to be very closely coordinated with the
3958 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)3959 VexInvalRange unchainXDirect_MIPS ( VexEndness endness_host,
3960 void* place_to_unchain,
3961 const void* place_to_jump_to_EXPECTED,
3962 const void* disp_cp_chain_me,
3963 Bool mode64 )
3964 {
3965 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
3966 /* What we're expecting to see is:
3967 move r9, place_to_jump_to_EXPECTED
3968 jalr r9
3969 nop
3970 viz
3971 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
3972 0x120F809 # jalr r9
3973 0x00000000 # nop
3974 */
3975 UChar* p = (UChar*)place_to_unchain;
3976 vassert(0 == (3 & (HWord)p));
3977 vassert(isLoadImm_EXACTLY2or6(p, /*r*/ 9,
3978 (Addr)place_to_jump_to_EXPECTED,
3979 mode64));
3980 vassert(fetch32(p + (mode64 ? 24 : 8) + 0) == 0x120F809);
3981 vassert(fetch32(p + (mode64 ? 24 : 8) + 4) == 0x00000000);
3982 /* And what we want to change it to is:
3983 move r9, disp_cp_chain_me
3984 jalr r9
3985 nop
3986 viz
3987 <8 or 24 bytes generated by mkLoadImm_EXACTLY2or6>
3988 0x120F809 # jalr r9
3989 0x00000000 # nop
3990 The replacement has the same length as the original.
3991 */
3992 p = mkLoadImm_EXACTLY2or6(p, /*r*/ 9,
3993 (Addr)disp_cp_chain_me, mode64);
3994 p = emit32(p, 0x120F809);
3995 p = emit32(p, 0x00000000);
3996
3997 Int len = p - (UChar*)place_to_unchain;
3998 vassert(len == (mode64 ? 32 : 16)); /* stay sane */
3999 VexInvalRange vir = {(HWord)place_to_unchain, len};
4000 return vir;
4001 }
4002
4003 /* Patch the counter address into a profile inc point, as previously
4004 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)4005 VexInvalRange patchProfInc_MIPS ( VexEndness endness_host,
4006 void* place_to_patch,
4007 const ULong* location_of_counter,
4008 Bool mode64 )
4009 {
4010 vassert(endness_host == VexEndnessLE || endness_host == VexEndnessBE);
4011 if (mode64) {
4012 vassert(sizeof(ULong*) == 8);
4013 } else {
4014 vassert(sizeof(ULong*) == 4);
4015 }
4016 UChar* p = (UChar*)place_to_patch;
4017 vassert(0 == (3 & (HWord)p));
4018 vassert(isLoadImm_EXACTLY2or6((UChar *)p, /*r*/9,
4019 mode64 ? 0x6555655565556555ULL : 0x65556555,
4020 mode64));
4021
4022 if (mode64) {
4023 vassert(fetch32(p + 24 + 0) == 0xDD280000);
4024 vassert(fetch32(p + 24 + 4) == 0x65080001);
4025 vassert(fetch32(p + 24 + 8) == 0xFD280000);
4026 } else {
4027 vassert(fetch32(p + 8 + 0) == 0x8D280000);
4028 vassert(fetch32(p + 8 + 4) == 0x25080001);
4029 vassert(fetch32(p + 8 + 8) == 0xAD280000);
4030 vassert(fetch32(p + 8 + 12) == 0x2d010001);
4031 vassert(fetch32(p + 8 + 16) == 0x8d280004);
4032 vassert(fetch32(p + 8 + 20) == 0x01014021);
4033 vassert(fetch32(p + 8 + 24) == 0xad280004);
4034 }
4035
4036 p = mkLoadImm_EXACTLY2or6(p, /*r*/9,
4037 (Addr)location_of_counter, mode64);
4038
4039 VexInvalRange vir = {(HWord)p, 8};
4040 return vir;
4041 }
4042
4043
4044 /*---------------------------------------------------------------*/
4045 /*--- end host_mips_defs.c ---*/
4046 /*---------------------------------------------------------------*/
4047