1
2 /*---------------------------------------------------------------*/
3 /*--- begin host_tilegx_defs.c ---*/
4 /*---------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2010-2015 Tilera Corp.
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 02111-1307, USA.
26
27 The GNU General Public License is contained in the file COPYING.
28 */
29
30 /* Contributed by Zhi-Gang Liu <zliu at tilera dot com> */
31
32 #include "libvex_basictypes.h"
33 #include "libvex.h"
34 #include "libvex_trc_values.h"
35
36 #include "main_util.h"
37 #include "host_generic_regs.h"
38 #include "host_tilegx_defs.h"
39 #include "tilegx_disasm.h"
40
41 /* Contributed by Zhi-Gang Liu <zliu at tilera dot com> */
42
43 /* Register number for guest state pointer in host code, r50 */
44 #define GuestSP ( 50)
45 /* CONTEXT_EX0 offset */
46 #define OFFSET_EX0 (576)
47 /* CONTEXT_EX1 offset */
48 #define OFFSET_EX1 (584)
49 /* COND offset */
50 #define OFFSET_COND (608)
51 /* PC offset */
52 #define OFFSET_PC (512)
53
54 /* guest_COND offset. */
55 #define COND_OFFSET() OFFSET_COND
56
57 /*---------------- Registers ----------------*/
58
ppHRegTILEGX(HReg reg)59 void ppHRegTILEGX ( HReg reg )
60 {
61 Int r;
62 static const HChar *ireg_names[64] = {
63 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
64 "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
65 "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",
66 "r30", "r31", "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
67 "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
68 "r50", "r51", "r52", "r53", "r54", "r55",
69 "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero"
70 };
71
72 /* Be generic for all virtual regs. */
73 if (hregIsVirtual(reg)) {
74 ppHReg(reg);
75 return;
76 }
77
78 /* But specific for real regs. */
79 vassert(hregClass(reg) == HRcInt32 || hregClass(reg) == HRcInt64 ||
80 hregClass(reg) == HRcFlt32 || hregClass(reg) == HRcFlt64);
81
82 /* But specific for real regs. */
83 switch (hregClass(reg)) {
84 case HRcInt32:
85 case HRcInt64:
86 r = hregEncoding(reg);
87 vassert(r >= 0 && r < 64);
88 vex_printf("%s", ireg_names[r]);
89 return;
90 case HRcFlt32:
91 r = hregEncoding(reg);
92 vassert(r >= 0 && r < 64);
93 vex_printf("%s", ireg_names[r]);
94 return;
95 case HRcFlt64:
96 r = hregEncoding(reg);
97 vassert(r >= 0 && r < 64);
98 vex_printf("%s", ireg_names[r]);
99 return;
100 default:
101 vpanic("ppHRegTILEGX");
102 }
103
104 return;
105 }
106
107 static const HChar* tilegxUnaryOp [] =
108 {
109 "clz ",
110 "ctz ",
111 "nop "
112 };
113
114 static const HChar* tilegxAluOp [] =
115 { "Alu_invalid",
116 "Add ",
117 "Sub ",
118 "And ",
119 "Or ",
120 "Nor ",
121 "Xor "
122 };
123
124 static const HChar* tilegxShftOp [] =
125 {
126 "Shft_invalid",
127 "Sll ",
128 "Srl ",
129 "Sra ",
130 "Sll8x8 ",
131 "Srl8x8 ",
132 };
133
134 static const HChar* tilegxBfOp [] =
135 {
136 "BfExts ",
137 "BfEtxu ",
138 "BfIns "
139 };
140
141
142 static const HChar* tilegxAcasOp [] =
143 {
144 "CmpExch ",
145 "Exch ",
146 "FetchAnd ",
147 "FetchAdd ",
148 "FetchAddgez",
149 "FetchOr "
150 };
151
152 static const HChar* tilegxInstrTag [] =
153 {
154 "Imm ",
155 "ALU ",
156 "Shift ",
157 "Unary ",
158 "Cmp ",
159 "CmpI ",
160 "Mul ",
161 "Call ",
162 "XDirect ",
163 "XIndir ",
164 "XAssisted",
165 "EvCheck ",
166 "ProfInc ",
167 "RdWrLR ",
168 "Load ",
169 "Store ",
170 "MovCond ",
171 "BitField ",
172 "ACAS "
173 };
174
175 /* -------- Pretty Print instructions ------------- */
ppLoadImm(HReg dst,ULong imm)176 static void ppLoadImm ( HReg dst, ULong imm )
177 {
178 vex_printf("li ");
179 ppHRegTILEGX(dst);
180 vex_printf(",0x%016lx", (unsigned long)imm);
181 }
182
ppTILEGXInstr(const TILEGXInstr * instr)183 void ppTILEGXInstr ( const TILEGXInstr * instr )
184 {
185 vex_printf("%s ", tilegxInstrTag[instr->tag]);
186 switch (instr->tag) {
187 case GXin_LI: {
188 ppHRegTILEGX(instr->GXin.LI.dst);
189 vex_printf(",0x%016llx", instr->GXin.LI.imm);
190 }
191 break;
192
193 case GXin_Alu: {
194 HReg r_srcL = instr->GXin.Alu.srcL;
195 TILEGXRH *rh_srcR = instr->GXin.Alu.srcR;
196 /* generic */
197 vex_printf("%s ", tilegxAluOp[instr->GXin.Alu.op]);
198 ppHRegTILEGX(instr->GXin.Alu.dst);
199 vex_printf(",");
200 ppHRegTILEGX(r_srcL);
201 vex_printf(",");
202 ppTILEGXRH(rh_srcR);
203 }
204 break;
205
206 case GXin_Shft: {
207 HReg r_srcL = instr->GXin.Shft.srcL;
208 TILEGXRH *rh_srcR = instr->GXin.Shft.srcR;
209 vex_printf("%s ", tilegxShftOp[instr->GXin.Shft.op]);
210 ppHRegTILEGX(instr->GXin.Shft.dst);
211 vex_printf(",");
212 ppHRegTILEGX(r_srcL);
213 vex_printf(",");
214 ppTILEGXRH(rh_srcR);
215 }
216 break;
217
218 case GXin_Unary: {
219 vex_printf("%s ", tilegxUnaryOp[instr->GXin.Unary.op]);
220 ppHRegTILEGX(instr->GXin.Unary.dst);
221 vex_printf(",");
222 ppHRegTILEGX(instr->GXin.Unary.src);
223 }
224 break;
225
226 case GXin_Cmp: {
227 ppHRegTILEGX(instr->GXin.Cmp.dst);
228 vex_printf(" = %s ( ", showTILEGXCondCode(instr->GXin.Cmp.cond));
229 ppHRegTILEGX(instr->GXin.Cmp.srcL);
230 vex_printf(", ");
231 ppHRegTILEGX(instr->GXin.Cmp.srcR);
232 vex_printf(" )");
233 }
234 break;
235
236 case GXin_CmpI: {
237 ppHRegTILEGX(instr->GXin.CmpI.dst);
238 vex_printf(" = %s ( ", showTILEGXCondCode(instr->GXin.CmpI.cond));
239 ppHRegTILEGX(instr->GXin.CmpI.srcL);
240 vex_printf(", ");
241 ppTILEGXRH(instr->GXin.CmpI.srcR);
242 vex_printf(" )");
243 }
244 break;
245
246 case GXin_Mul: {
247 if (instr->GXin.Mul.widening == False) {
248 vex_printf("mul ");
249 ppHRegTILEGX(instr->GXin.Mul.dst);
250 vex_printf(", ");
251 ppHRegTILEGX(instr->GXin.Mul.srcL);
252 vex_printf(", ");
253 ppHRegTILEGX(instr->GXin.Mul.srcR);
254
255 } else {
256 vex_printf("%s ", instr->GXin.Mul.syned ? "mull32s" : "mull32u");
257 ppHRegTILEGX(instr->GXin.Mul.dst);
258 vex_printf(", ");
259 ppHRegTILEGX(instr->GXin.Mul.srcL);
260 vex_printf(", ");
261 ppHRegTILEGX(instr->GXin.Mul.srcR);
262 }
263 }
264 break;
265
266 case GXin_Call: {
267 Int n;
268 if (instr->GXin.Call.cond != TILEGXcc_AL) {
269 vex_printf("if (%s (", showTILEGXCondCode(instr->GXin.Call.cond));
270 ppHRegTILEGX(instr->GXin.Call.src);
271 vex_printf(",zero))");
272 }
273 else
274 vex_printf("(always) ");
275
276 vex_printf("{ ");
277 ppLoadImm(hregTILEGX_R11(), instr->GXin.Call.target);
278
279 vex_printf(" ; [");
280 for (n = 0; n < 56; n++) {
281 if (instr->GXin.Call.argiregs & (1ULL << n)) {
282 vex_printf("r%d", n);
283 if ((instr->GXin.Call.argiregs >> n) > 1)
284 vex_printf(",");
285 }
286 }
287 vex_printf("] }");
288 }
289 break;
290
291 case GXin_XDirect:
292 vex_printf("(xDirect) ");
293 vex_printf("if (guest_COND.%s) { ",
294 showTILEGXCondCode(instr->GXin.XDirect.cond));
295 vex_printf("move r11, 0x%x,", (UInt)instr->GXin.XDirect.dstGA);
296 vex_printf("; st r11, ");
297 ppTILEGXAMode(instr->GXin.XDirect.amPC);
298 vex_printf("; move r11, $disp_cp_chain_me_to_%sEP; jalr r11; nop}",
299 instr->GXin.XDirect.toFastEP ? "fast" : "slow");
300 return;
301 case GXin_XIndir:
302 vex_printf("(xIndir) ");
303 vex_printf("if (guest_COND.%s) { st ",
304 showTILEGXCondCode(instr->GXin.XIndir.cond));
305 ppHRegTILEGX(instr->GXin.XIndir.dstGA);
306 vex_printf(", ");
307 ppTILEGXAMode(instr->GXin.XIndir.amPC);
308 vex_printf("; move r11, $disp_indir; jalr r11; nop}");
309 return;
310 case GXin_XAssisted:
311 vex_printf("(xAssisted) ");
312 vex_printf("if (guest_COND.%s) { ",
313 showTILEGXCondCode(instr->GXin.XAssisted.cond));
314 vex_printf("st ");
315 ppHRegTILEGX(instr->GXin.XAssisted.dstGA);
316 vex_printf(", ");
317 ppTILEGXAMode(instr->GXin.XAssisted.amPC);
318 vex_printf("; move r50, $IRJumpKind_to_TRCVAL(%d)",
319 (Int)instr->GXin.XAssisted.jk);
320 vex_printf("; move r11, $disp_assisted; jalr r11; nop; }");
321 return;
322
323 case GXin_EvCheck:
324 vex_printf("(evCheck) ld r11, ");
325 ppTILEGXAMode(instr->GXin.EvCheck.amCounter);
326 vex_printf("; addli r11, r11, -1");
327 vex_printf("; st r11, ");
328 ppTILEGXAMode(instr->GXin.EvCheck.amCounter);
329 vex_printf("; bgez r11, nofail; jalr *");
330 ppTILEGXAMode(instr->GXin.EvCheck.amFailAddr);
331 vex_printf("; nofail:");
332 return;
333 case GXin_ProfInc:
334 vex_printf("(profInc) move r11, ($NotKnownYet); "
335 "ld r8, r11; "
336 "addi r8, r8, 1; "
337 "st r11, r8; " );
338 return;
339 case GXin_Load: {
340 UChar sz = instr->GXin.Load.sz;
341 UChar c_sz = sz == 1 ? '1' : sz == 2 ? '2' : sz == 4 ? '4' : '8';
342 vex_printf("ld%c ", c_sz);
343 ppHRegTILEGX(instr->GXin.Load.dst);
344 vex_printf(",");
345 ppTILEGXAMode(instr->GXin.Load.src);
346 }
347 break;
348
349 case GXin_Store: {
350 UChar sz = instr->GXin.Store.sz;
351 UChar c_sz = sz == 1 ? '1' : sz == 2 ? '2' : sz == 4 ? '4' : '8';
352 vex_printf("st%c ", c_sz);
353 ppTILEGXAMode(instr->GXin.Store.dst);
354 vex_printf(",");
355 ppHRegTILEGX(instr->GXin.Store.src);
356 }
357 break;
358
359 case GXin_MovCond: {
360 ppHRegTILEGX(instr->GXin.MovCond.dst);
361 vex_printf("=");
362 showTILEGXCondCode(instr->GXin.MovCond.cond);
363 vex_printf("?");
364 ppHRegTILEGX(instr->GXin.MovCond.srcL);
365 vex_printf(":");
366 ppTILEGXRH(instr->GXin.MovCond.srcR);
367 }
368 break;
369
370 case GXin_Acas: {
371 vex_printf("%s ", tilegxAcasOp[instr->GXin.Acas.op]);
372 ppHRegTILEGX(instr->GXin.Acas.old);
373 vex_printf(",");
374 if (instr->GXin.Acas.op == GXacas_CMPEXCH) {
375 ppHRegTILEGX(instr->GXin.Acas.exp);
376 vex_printf(",");
377 }
378 ppHRegTILEGX(instr->GXin.Acas.new);
379 }
380 break;
381
382 case GXin_Bf: {
383 vex_printf("%s ", tilegxBfOp[instr->GXin.Bf.op]);
384 ppHRegTILEGX(instr->GXin.Bf.dst);
385 vex_printf(",");
386 ppHRegTILEGX(instr->GXin.Bf.src);
387 vex_printf(",");
388 vex_printf("%d,%d", (Int)instr->GXin.Bf.Start, (Int)instr->GXin.Bf.End);
389 }
390 break;
391
392 default:
393 vassert(0);
394 }
395 }
396
397
getRRegUniverse_TILEGX(void)398 const RRegUniverse* getRRegUniverse_TILEGX ( void )
399 {
400 /* The 'universe' is constant and BIG, do it statically. */
401 static RRegUniverse rRegUniverse_TILEGX;
402 static UInt rRegUniverse_TILEGX_initted = False;
403
404 /* Get a pointer of the 'universe' */
405 RRegUniverse* ru = &rRegUniverse_TILEGX;
406
407 if (LIKELY(rRegUniverse_TILEGX_initted))
408 return ru;
409
410 RRegUniverse__init(ru);
411
412 /* Callee saves ones are listed first, since we prefer them
413 if they're available */
414
415 ru->regs[ru->size++] = hregTILEGX_R30();
416 ru->regs[ru->size++] = hregTILEGX_R31();
417 ru->regs[ru->size++] = hregTILEGX_R32();
418 ru->regs[ru->size++] = hregTILEGX_R33();
419 ru->regs[ru->size++] = hregTILEGX_R34();
420 ru->regs[ru->size++] = hregTILEGX_R35();
421 ru->regs[ru->size++] = hregTILEGX_R36();
422 ru->regs[ru->size++] = hregTILEGX_R37();
423 ru->regs[ru->size++] = hregTILEGX_R38();
424 ru->regs[ru->size++] = hregTILEGX_R39();
425
426 ru->regs[ru->size++] = hregTILEGX_R40();
427 ru->regs[ru->size++] = hregTILEGX_R41();
428 ru->regs[ru->size++] = hregTILEGX_R42();
429 ru->regs[ru->size++] = hregTILEGX_R43();
430 ru->regs[ru->size++] = hregTILEGX_R44();
431 ru->regs[ru->size++] = hregTILEGX_R45();
432 ru->regs[ru->size++] = hregTILEGX_R46();
433 ru->regs[ru->size++] = hregTILEGX_R47();
434 ru->regs[ru->size++] = hregTILEGX_R48();
435 ru->regs[ru->size++] = hregTILEGX_R49();
436
437 /* GPR 50 is reserved as Guest state */
438 /* GPR 51 is reserved register, mainly used to do memory
439 load and store since TileGx has no pre-displacement
440 addressing mode */
441
442 ru->regs[ru->size++] = hregTILEGX_R10();
443
444 /* GPR 11 is reserved as next guest address */
445
446 ru->regs[ru->size++] = hregTILEGX_R13();
447 ru->regs[ru->size++] = hregTILEGX_R14();
448 ru->regs[ru->size++] = hregTILEGX_R15();
449 ru->regs[ru->size++] = hregTILEGX_R16();
450 ru->regs[ru->size++] = hregTILEGX_R17();
451 ru->regs[ru->size++] = hregTILEGX_R18();
452 ru->regs[ru->size++] = hregTILEGX_R19();
453 ru->regs[ru->size++] = hregTILEGX_R20();
454 ru->regs[ru->size++] = hregTILEGX_R21();
455 ru->regs[ru->size++] = hregTILEGX_R22();
456 ru->regs[ru->size++] = hregTILEGX_R23();
457 ru->regs[ru->size++] = hregTILEGX_R24();
458 ru->regs[ru->size++] = hregTILEGX_R25();
459 ru->regs[ru->size++] = hregTILEGX_R26();
460 ru->regs[ru->size++] = hregTILEGX_R27();
461 ru->regs[ru->size++] = hregTILEGX_R28();
462 ru->regs[ru->size++] = hregTILEGX_R29();
463
464 ru->allocable = ru->size;
465
466 /* And other unallocable registers. */
467 ru->regs[ru->size++] = hregTILEGX_R0();
468 ru->regs[ru->size++] = hregTILEGX_R1();
469 ru->regs[ru->size++] = hregTILEGX_R2();
470 ru->regs[ru->size++] = hregTILEGX_R3();
471 ru->regs[ru->size++] = hregTILEGX_R4();
472 ru->regs[ru->size++] = hregTILEGX_R5();
473 ru->regs[ru->size++] = hregTILEGX_R6();
474 ru->regs[ru->size++] = hregTILEGX_R7();
475 ru->regs[ru->size++] = hregTILEGX_R8();
476 ru->regs[ru->size++] = hregTILEGX_R9();
477 ru->regs[ru->size++] = hregTILEGX_R11();
478 ru->regs[ru->size++] = hregTILEGX_R12();
479 ru->regs[ru->size++] = hregTILEGX_R50();
480 ru->regs[ru->size++] = hregTILEGX_R51();
481 ru->regs[ru->size++] = hregTILEGX_R52();
482 ru->regs[ru->size++] = hregTILEGX_R53();
483 ru->regs[ru->size++] = hregTILEGX_R54();
484 ru->regs[ru->size++] = hregTILEGX_R55();
485 ru->regs[ru->size++] = hregTILEGX_R63();
486
487 rRegUniverse_TILEGX_initted = True;
488
489 RRegUniverse__check_is_sane(ru);
490
491 return ru;
492 }
493
494 /*----------------- Condition Codes ----------------------*/
495
showTILEGXCondCode(TILEGXCondCode cond)496 const HChar *showTILEGXCondCode ( TILEGXCondCode cond )
497 {
498 switch (cond) {
499 case TILEGXcc_EQ:
500 return "e"; /* equal */
501 case TILEGXcc_EQ8x8:
502 return "e8x8"; /* equal */
503
504 case TILEGXcc_NE:
505 return "ne"; /* not equal */
506 case TILEGXcc_NE8x8:
507 return "ne8x8"; /* not equal */
508
509 case TILEGXcc_HS:
510 return "hs"; /* >=u (higher or same) */
511 case TILEGXcc_LO:
512 return "lo"; /* <u (lower) */
513
514 case TILEGXcc_MI:
515 return "mi"; /* minus (negative) */
516 case TILEGXcc_PL:
517 return "pl"; /* plus (zero or +ve) */
518
519 case TILEGXcc_VS:
520 return "vs"; /* overflow */
521 case TILEGXcc_VC:
522 return "vc"; /* no overflow */
523
524 case TILEGXcc_HI:
525 return "hi"; /* >u (higher) */
526 case TILEGXcc_LS:
527 return "ls"; /* <=u (lower or same) */
528
529 case TILEGXcc_GE:
530 return "ge"; /* >=s (signed greater or equal) */
531 case TILEGXcc_LT:
532 return "lt"; /* <s (signed less than) */
533
534 case TILEGXcc_GT:
535 return "gt"; /* >s (signed greater) */
536 case TILEGXcc_LE:
537 return "le"; /* <=s (signed less or equal) */
538
539 case TILEGXcc_AL:
540 return "al"; /* always (unconditional) */
541 case TILEGXcc_NV:
542 return "nv"; /* never (unconditional): */
543 case TILEGXcc_EZ:
544 return "ez"; /* equal 0 */
545 case TILEGXcc_NZ:
546 return "nz"; /* not equal 0 */
547
548 default:
549 vpanic("showTILEGXCondCode");
550 }
551 }
552
553
554 /* --------- TILEGXAMode: memory address expressions. --------- */
555
TILEGXAMode_IR(Int idx,HReg base)556 TILEGXAMode *TILEGXAMode_IR ( Int idx, HReg base )
557 {
558 TILEGXAMode *am = LibVEX_Alloc(sizeof(TILEGXAMode));
559 am->tag = GXam_IR;
560 am->GXam.IR.base = base;
561 am->GXam.IR.index = idx;
562
563 return am;
564 }
565
nextTILEGXAModeInt(TILEGXAMode * am)566 TILEGXAMode *nextTILEGXAModeInt ( TILEGXAMode * am )
567 {
568 if (am->tag == GXam_IR)
569 return TILEGXAMode_IR(am->GXam.IR.index + 4, am->GXam.IR.base);
570
571 vpanic("dopyTILEGXAMode");
572 }
573
ppTILEGXAMode(const TILEGXAMode * am)574 void ppTILEGXAMode ( const TILEGXAMode * am )
575 {
576 if (am->tag == GXam_IR)
577 {
578 if (am->GXam.IR.index == 0)
579 vex_printf("(");
580 else
581 vex_printf("%d(", (Int) am->GXam.IR.index);
582 ppHRegTILEGX(am->GXam.IR.base);
583 vex_printf(")");
584 return;
585 }
586 vpanic("ppTILEGXAMode");
587 }
588
addRegUsage_TILEGXAMode(HRegUsage * u,TILEGXAMode * am)589 static void addRegUsage_TILEGXAMode ( HRegUsage * u, TILEGXAMode * am )
590 {
591 if (am->tag == GXam_IR)
592 {
593 addHRegUse(u, HRmRead, am->GXam.IR.base);
594 return;
595 }
596
597 vpanic("addRegUsage_TILEGXAMode");
598 }
599
mapRegs_TILEGXAMode(HRegRemap * m,TILEGXAMode * am)600 static void mapRegs_TILEGXAMode ( HRegRemap * m, TILEGXAMode * am )
601 {
602 if (am->tag == GXam_IR)
603 {
604 am->GXam.IR.base = lookupHRegRemap(m, am->GXam.IR.base);
605 return;
606 }
607
608 vpanic("mapRegs_TILEGXAMode");
609 }
610
611 /* --------- Operand, which can be a reg or a u16/s16. --------- */
612
TILEGXRH_Imm(Bool syned,UShort imm16)613 TILEGXRH *TILEGXRH_Imm ( Bool syned, UShort imm16 )
614 {
615 TILEGXRH *op = LibVEX_Alloc(sizeof(TILEGXRH));
616 op->tag = GXrh_Imm;
617 op->GXrh.Imm.syned = syned;
618 op->GXrh.Imm.imm16 = imm16;
619 /* If this is a signed value, ensure it's not -32768, so that we
620 are guaranteed always to be able to negate if needed. */
621 if (syned)
622 vassert(imm16 != 0x8000);
623 vassert(syned == True || syned == False);
624 return op;
625 }
626
TILEGXRH_Reg(HReg reg)627 TILEGXRH *TILEGXRH_Reg ( HReg reg )
628 {
629 TILEGXRH *op = LibVEX_Alloc(sizeof(TILEGXRH));
630 op->tag = GXrh_Reg;
631 op->GXrh.Reg.reg = reg;
632 return op;
633 }
634
ppTILEGXRH(const TILEGXRH * op)635 void ppTILEGXRH ( const TILEGXRH * op )
636 {
637 TILEGXRHTag tag = op->tag;
638 switch (tag) {
639 case GXrh_Imm:
640 if (op->GXrh.Imm.syned)
641 vex_printf("%d", (Int) (Short) op->GXrh.Imm.imm16);
642 else
643 vex_printf("%u", (UInt) (UShort) op->GXrh.Imm.imm16);
644 return;
645 case GXrh_Reg:
646 ppHRegTILEGX(op->GXrh.Reg.reg);
647 return;
648 default:
649 vpanic("ppTILEGXRH");
650 }
651 }
652
653 /* An TILEGXRH can only be used in a "read" context (what would it mean
654 to write or modify a literal?) and so we enumerate its registers
655 accordingly. */
addRegUsage_TILEGXRH(HRegUsage * u,TILEGXRH * op)656 static void addRegUsage_TILEGXRH ( HRegUsage * u, TILEGXRH * op )
657 {
658 switch (op->tag) {
659 case GXrh_Imm:
660 return;
661 case GXrh_Reg:
662 addHRegUse(u, HRmRead, op->GXrh.Reg.reg);
663 return;
664 default:
665 vpanic("addRegUsage_TILEGXRH");
666 }
667 }
668
mapRegs_TILEGXRH(HRegRemap * m,TILEGXRH * op)669 static void mapRegs_TILEGXRH ( HRegRemap * m, TILEGXRH * op )
670 {
671 switch (op->tag) {
672 case GXrh_Imm:
673 return;
674 case GXrh_Reg:
675 op->GXrh.Reg.reg = lookupHRegRemap(m, op->GXrh.Reg.reg);
676 return;
677 default:
678 vpanic("mapRegs_TILEGXRH");
679 }
680 }
681
TILEGXInstr_LI(HReg dst,ULong imm)682 TILEGXInstr *TILEGXInstr_LI ( HReg dst, ULong imm )
683 {
684 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
685 i->tag = GXin_LI;
686 i->GXin.LI.dst = dst;
687 i->GXin.LI.imm = imm;
688 return i;
689 }
690
TILEGXInstr_Alu(TILEGXAluOp op,HReg dst,HReg srcL,TILEGXRH * srcR)691 TILEGXInstr *TILEGXInstr_Alu ( TILEGXAluOp op, HReg dst, HReg srcL,
692 TILEGXRH * srcR )
693 {
694 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
695 i->tag = GXin_Alu;
696 i->GXin.Alu.op = op;
697 i->GXin.Alu.dst = dst;
698 i->GXin.Alu.srcL = srcL;
699 i->GXin.Alu.srcR = srcR;
700 return i;
701 }
702
TILEGXInstr_Shft(TILEGXShftOp op,Bool sz32,HReg dst,HReg srcL,TILEGXRH * srcR)703 TILEGXInstr *TILEGXInstr_Shft ( TILEGXShftOp op, Bool sz32, HReg dst, HReg srcL,
704 TILEGXRH * srcR )
705 {
706 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
707 i->tag = GXin_Shft;
708 i->GXin.Shft.op = op;
709 i->GXin.Shft.sz32 = sz32;
710 i->GXin.Shft.dst = dst;
711 i->GXin.Shft.srcL = srcL;
712 i->GXin.Shft.srcR = srcR;
713 return i;
714 }
715
TILEGXInstr_Unary(TILEGXUnaryOp op,HReg dst,HReg src)716 TILEGXInstr *TILEGXInstr_Unary ( TILEGXUnaryOp op, HReg dst, HReg src )
717 {
718 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
719 i->tag = GXin_Unary;
720 i->GXin.Unary.op = op;
721 i->GXin.Unary.dst = dst;
722 i->GXin.Unary.src = src;
723 return i;
724 }
725
TILEGXInstr_Cmp(Bool syned,Bool sz32,HReg dst,HReg srcL,HReg srcR,TILEGXCondCode cond)726 TILEGXInstr *TILEGXInstr_Cmp ( Bool syned, Bool sz32, HReg dst,
727 HReg srcL, HReg srcR, TILEGXCondCode cond )
728 {
729 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
730 i->tag = GXin_Cmp;
731 i->GXin.Cmp.syned = syned;
732 i->GXin.Cmp.sz32 = sz32;
733 i->GXin.Cmp.dst = dst;
734 i->GXin.Cmp.srcL = srcL;
735 i->GXin.Cmp.srcR = srcR;
736 i->GXin.Cmp.cond = cond;
737 return i;
738 }
739
TILEGXInstr_CmpI(Bool syned,Bool sz32,HReg dst,HReg srcL,TILEGXRH * srcR,TILEGXCondCode cond)740 TILEGXInstr *TILEGXInstr_CmpI ( Bool syned, Bool sz32, HReg dst,
741 HReg srcL, TILEGXRH * srcR,
742 TILEGXCondCode cond )
743 {
744 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
745 i->tag = GXin_CmpI;
746 i->GXin.CmpI.syned = syned;
747 i->GXin.CmpI.sz32 = sz32;
748 i->GXin.CmpI.dst = dst;
749 i->GXin.CmpI.srcL = srcL;
750 i->GXin.CmpI.srcR = srcR;
751 i->GXin.CmpI.cond = cond;
752 return i;
753 }
754
TILEGXInstr_Bf(TILEGXBfOp op,HReg dst,HReg src,UInt Start,UInt End)755 TILEGXInstr *TILEGXInstr_Bf ( TILEGXBfOp op, HReg dst, HReg src,
756 UInt Start, UInt End )
757 {
758 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
759 i->tag = GXin_Bf;
760 i->GXin.Bf.op = op;
761 i->GXin.Bf.dst = dst;
762 i->GXin.Bf.src = src;
763 i->GXin.Bf.Start = Start;
764 i->GXin.Bf.End = End;
765 return i;
766 }
767
TILEGXInstr_Acas(TILEGXAcasOp op,HReg old,HReg addr,HReg exp,HReg new,UInt sz)768 TILEGXInstr *TILEGXInstr_Acas ( TILEGXAcasOp op, HReg old,
769 HReg addr, HReg exp, HReg new, UInt sz )
770 {
771 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
772 i->tag = GXin_Acas;
773 i->GXin.Acas.op = op;
774 i->GXin.Acas.old = old;
775 i->GXin.Acas.addr = addr;
776 i->GXin.Acas.exp = exp;
777 i->GXin.Acas.new = new;
778 i->GXin.Acas.sz = sz;
779 return i;
780 }
781
782 /* multiply */
TILEGXInstr_Mul(Bool syned,Bool wid,Bool sz32,HReg dst,HReg srcL,HReg srcR)783 TILEGXInstr *TILEGXInstr_Mul ( Bool syned, Bool wid, Bool sz32,
784 HReg dst, HReg srcL,
785 HReg srcR )
786 {
787 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
788 i->tag = GXin_Mul;
789 i->GXin.Mul.syned = syned;
790 i->GXin.Mul.widening = wid; /* widen=True else False */
791 i->GXin.Mul.sz32 = sz32; /* True = 32 bits */
792 i->GXin.Mul.dst = dst;
793 i->GXin.Mul.srcL = srcL;
794 i->GXin.Mul.srcR = srcR;
795 return i;
796 }
797
TILEGXInstr_Call(TILEGXCondCode cond,Addr64 target,ULong argiregs,HReg src)798 TILEGXInstr *TILEGXInstr_Call ( TILEGXCondCode cond, Addr64 target,
799 ULong argiregs,
800 HReg src )
801 {
802 ULong mask;
803 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
804 i->tag = GXin_Call;
805 i->GXin.Call.cond = cond;
806 i->GXin.Call.target = target;
807 i->GXin.Call.argiregs = argiregs;
808 i->GXin.Call.src = src;
809
810 /* Only r0 .. r9 inclusive may be used as arg regs. Hence: */
811 mask = (1ULL << 10) - 1;
812 vassert(0 == (argiregs & ~mask));
813 return i;
814 }
815
TILEGXInstr_CallAlways(TILEGXCondCode cond,Addr64 target,ULong argiregs)816 TILEGXInstr *TILEGXInstr_CallAlways ( TILEGXCondCode cond, Addr64 target,
817 ULong argiregs )
818 {
819 ULong mask;
820 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
821 i->tag = GXin_Call;
822 i->GXin.Call.cond = cond;
823 i->GXin.Call.target = target;
824 i->GXin.Call.argiregs = argiregs;
825
826 /* Only r0 .. r9 inclusive may be used as arg regs. Hence: */
827 mask = (1ULL << 10) - 1;
828 vassert(0 == (argiregs & ~mask));
829 return i;
830 }
831
TILEGXInstr_XDirect(Addr64 dstGA,TILEGXAMode * amPC,TILEGXCondCode cond,Bool toFastEP)832 TILEGXInstr *TILEGXInstr_XDirect ( Addr64 dstGA, TILEGXAMode* amPC,
833 TILEGXCondCode cond, Bool toFastEP )
834 {
835 TILEGXInstr* i = LibVEX_Alloc(sizeof(TILEGXInstr));
836 i->tag = GXin_XDirect;
837 i->GXin.XDirect.dstGA = dstGA;
838 i->GXin.XDirect.amPC = amPC;
839 i->GXin.XDirect.cond = cond;
840 i->GXin.XDirect.toFastEP = toFastEP;
841 return i;
842 }
843
TILEGXInstr_XIndir(HReg dstGA,TILEGXAMode * amPC,TILEGXCondCode cond)844 TILEGXInstr *TILEGXInstr_XIndir ( HReg dstGA, TILEGXAMode* amPC,
845 TILEGXCondCode cond )
846 {
847 TILEGXInstr* i = LibVEX_Alloc(sizeof(TILEGXInstr));
848 i->tag = GXin_XIndir;
849 i->GXin.XIndir.dstGA = dstGA;
850 i->GXin.XIndir.amPC = amPC;
851 i->GXin.XIndir.cond = cond;
852 return i;
853 }
854
TILEGXInstr_XAssisted(HReg dstGA,TILEGXAMode * amPC,TILEGXCondCode cond,IRJumpKind jk)855 TILEGXInstr *TILEGXInstr_XAssisted ( HReg dstGA, TILEGXAMode* amPC,
856 TILEGXCondCode cond, IRJumpKind jk )
857 {
858 TILEGXInstr* i = LibVEX_Alloc(sizeof(TILEGXInstr));
859 i->tag = GXin_XAssisted;
860 i->GXin.XAssisted.dstGA = dstGA;
861 i->GXin.XAssisted.amPC = amPC;
862 i->GXin.XAssisted.cond = cond;
863 i->GXin.XAssisted.jk = jk;
864 return i;
865 }
866
TILEGXInstr_EvCheck(TILEGXAMode * amCounter,TILEGXAMode * amFailAddr)867 TILEGXInstr *TILEGXInstr_EvCheck ( TILEGXAMode* amCounter,
868 TILEGXAMode* amFailAddr ) {
869 TILEGXInstr* i = LibVEX_Alloc(sizeof(TILEGXInstr));
870 i->tag = GXin_EvCheck;
871 i->GXin.EvCheck.amCounter = amCounter;
872 i->GXin.EvCheck.amFailAddr = amFailAddr;
873 return i;
874 }
875
TILEGXInstr_ProfInc(void)876 TILEGXInstr* TILEGXInstr_ProfInc ( void ) {
877 TILEGXInstr* i = LibVEX_Alloc(sizeof(TILEGXInstr));
878 i->tag = GXin_ProfInc;
879 return i;
880 }
881
TILEGXInstr_Load(UChar sz,HReg dst,TILEGXAMode * src)882 TILEGXInstr *TILEGXInstr_Load ( UChar sz, HReg dst, TILEGXAMode * src )
883 {
884 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
885 i->tag = GXin_Load;
886 i->GXin.Load.sz = sz;
887 i->GXin.Load.src = src;
888 i->GXin.Load.dst = dst;
889 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
890 return i;
891 }
892
TILEGXInstr_Store(UChar sz,TILEGXAMode * dst,HReg src)893 TILEGXInstr *TILEGXInstr_Store(UChar sz, TILEGXAMode * dst, HReg src)
894 {
895 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
896 i->tag = GXin_Store;
897 i->GXin.Store.sz = sz;
898 i->GXin.Store.src = src;
899 i->GXin.Store.dst = dst;
900 vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
901 return i;
902 }
903
904 /* Read/Write Link Register */
TILEGXInstr_RdWrLR(Bool wrLR,HReg gpr)905 TILEGXInstr *TILEGXInstr_RdWrLR ( Bool wrLR, HReg gpr )
906 {
907 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
908 i->tag = GXin_RdWrLR;
909 i->GXin.RdWrLR.wrLR = wrLR;
910 i->GXin.RdWrLR.gpr = gpr;
911 return i;
912 }
913
TILEGXInstr_MovCond(HReg dst,HReg argL,TILEGXRH * argR,HReg condR,TILEGXCondCode cond)914 TILEGXInstr *TILEGXInstr_MovCond ( HReg dst, HReg argL, TILEGXRH * argR,
915 HReg condR, TILEGXCondCode cond )
916 {
917 TILEGXInstr *i = LibVEX_Alloc(sizeof(TILEGXInstr));
918 i->tag = GXin_MovCond;
919 i->GXin.MovCond.dst = dst;
920 i->GXin.MovCond.srcL = argL;
921 i->GXin.MovCond.srcR = argR;
922 i->GXin.MovCond.condR = condR;
923 i->GXin.MovCond.cond = cond;
924 return i;
925 }
926
927 /* --------- Helpers for register allocation. --------- */
928
getRegUsage_TILEGXInstr(HRegUsage * u,TILEGXInstr * i)929 void getRegUsage_TILEGXInstr ( HRegUsage * u, TILEGXInstr * i )
930 {
931 initHRegUsage(u);
932 switch (i->tag) {
933 case GXin_LI:
934 addHRegUse(u, HRmWrite, i->GXin.LI.dst);
935 break;
936 case GXin_Alu:
937 addHRegUse(u, HRmRead, i->GXin.Alu.srcL);
938 addRegUsage_TILEGXRH(u, i->GXin.Alu.srcR);
939 addHRegUse(u, HRmWrite, i->GXin.Alu.dst);
940 return;
941 case GXin_CmpI:
942 addHRegUse(u, HRmRead, i->GXin.CmpI.srcL);
943 addRegUsage_TILEGXRH(u, i->GXin.CmpI.srcR);
944 addHRegUse(u, HRmWrite, i->GXin.CmpI.dst);
945 return;
946 case GXin_Shft:
947 addHRegUse(u, HRmRead, i->GXin.Shft.srcL);
948 addRegUsage_TILEGXRH(u, i->GXin.Shft.srcR);
949 addHRegUse(u, HRmWrite, i->GXin.Shft.dst);
950 return;
951 case GXin_Cmp:
952 addHRegUse(u, HRmRead, i->GXin.Cmp.srcL);
953 addHRegUse(u, HRmRead, i->GXin.Cmp.srcR);
954 addHRegUse(u, HRmWrite, i->GXin.Cmp.dst);
955 return;
956 case GXin_Bf:
957 addHRegUse(u, HRmRead, i->GXin.Bf.src);
958 addHRegUse(u, HRmWrite, i->GXin.Bf.dst);
959 return;
960 case GXin_Acas:
961 addHRegUse(u, HRmRead, i->GXin.Acas.addr);
962 addHRegUse(u, HRmRead, i->GXin.Acas.new);
963 if (i->GXin.Acas.op == GXacas_CMPEXCH)
964 addHRegUse(u, HRmRead, i->GXin.Acas.exp);
965 addHRegUse(u, HRmWrite, i->GXin.Acas.old);
966 return;
967 case GXin_Unary:
968 addHRegUse(u, HRmRead, i->GXin.Unary.src);
969 addHRegUse(u, HRmWrite, i->GXin.Unary.dst);
970 return;
971 case GXin_Mul:
972 addHRegUse(u, HRmWrite, i->GXin.Mul.dst);
973 addHRegUse(u, HRmRead, i->GXin.Mul.srcL);
974 addHRegUse(u, HRmRead, i->GXin.Mul.srcR);
975 return;
976 case GXin_Call: {
977 if (i->GXin.Call.cond != TILEGXcc_AL)
978 addHRegUse(u, HRmRead, i->GXin.Call.src);
979 ULong argir;
980
981 // Only need save r10-r29, and r0-r9 is not allocable.
982 addHRegUse(u, HRmWrite, hregTILEGX_R10());
983 addHRegUse(u, HRmWrite, hregTILEGX_R11());
984 addHRegUse(u, HRmWrite, hregTILEGX_R12());
985 addHRegUse(u, HRmWrite, hregTILEGX_R13());
986 addHRegUse(u, HRmWrite, hregTILEGX_R14());
987 addHRegUse(u, HRmWrite, hregTILEGX_R15());
988
989 addHRegUse(u, HRmWrite, hregTILEGX_R16());
990 addHRegUse(u, HRmWrite, hregTILEGX_R17());
991 addHRegUse(u, HRmWrite, hregTILEGX_R18());
992 addHRegUse(u, HRmWrite, hregTILEGX_R19());
993 addHRegUse(u, HRmWrite, hregTILEGX_R20());
994 addHRegUse(u, HRmWrite, hregTILEGX_R21());
995 addHRegUse(u, HRmWrite, hregTILEGX_R22());
996 addHRegUse(u, HRmWrite, hregTILEGX_R23());
997
998 addHRegUse(u, HRmWrite, hregTILEGX_R24());
999 addHRegUse(u, HRmWrite, hregTILEGX_R25());
1000 addHRegUse(u, HRmWrite, hregTILEGX_R26());
1001 addHRegUse(u, HRmWrite, hregTILEGX_R27());
1002
1003 addHRegUse(u, HRmWrite, hregTILEGX_R28());
1004 addHRegUse(u, HRmWrite, hregTILEGX_R29());
1005
1006 /* Now we have to state any parameter-carrying registers
1007 which might be read. This depends on the argiregs field. */
1008 argir = i->GXin.Call.argiregs;
1009 if (argir & (1 << 9))
1010 addHRegUse(u, HRmRead, hregTILEGX_R9());
1011 if (argir & (1 << 8))
1012 addHRegUse(u, HRmRead, hregTILEGX_R8());
1013 if (argir & (1 << 7))
1014 addHRegUse(u, HRmRead, hregTILEGX_R7());
1015 if (argir & (1 << 6))
1016 addHRegUse(u, HRmRead, hregTILEGX_R6());
1017 if (argir & (1 << 5))
1018 addHRegUse(u, HRmRead, hregTILEGX_R5());
1019 if (argir & (1 << 4))
1020 addHRegUse(u, HRmRead, hregTILEGX_R4());
1021 if (argir & (1 << 3))
1022 addHRegUse(u, HRmRead, hregTILEGX_R3());
1023 if (argir & (1 << 2))
1024 addHRegUse(u, HRmRead, hregTILEGX_R2());
1025 if (argir & (1 << 1))
1026 addHRegUse(u, HRmRead, hregTILEGX_R1());
1027 if (argir & (1 << 0))
1028 addHRegUse(u, HRmRead, hregTILEGX_R0());
1029
1030 vassert(0 == (argir & ~((1ULL << 10) - 1)));
1031 return;
1032 }
1033 case GXin_XDirect:
1034 addRegUsage_TILEGXAMode(u, i->GXin.XDirect.amPC);
1035 return;
1036 case GXin_XIndir:
1037 addHRegUse(u, HRmRead, i->GXin.XIndir.dstGA);
1038 addRegUsage_TILEGXAMode(u, i->GXin.XIndir.amPC);
1039 return;
1040 case GXin_XAssisted:
1041 addHRegUse(u, HRmRead, i->GXin.XAssisted.dstGA);
1042 addRegUsage_TILEGXAMode(u, i->GXin.XAssisted.amPC);
1043 return;
1044
1045 case GXin_EvCheck:
1046 addRegUsage_TILEGXAMode(u, i->GXin.EvCheck.amCounter);
1047 addRegUsage_TILEGXAMode(u, i->GXin.EvCheck.amFailAddr);
1048 return;
1049 case GXin_ProfInc:
1050 return;
1051 case GXin_Load:
1052 addRegUsage_TILEGXAMode(u, i->GXin.Load.src);
1053 addHRegUse(u, HRmWrite, i->GXin.Load.dst);
1054 return;
1055 case GXin_Store:
1056 addHRegUse(u, HRmRead, i->GXin.Store.src);
1057 addRegUsage_TILEGXAMode(u, i->GXin.Store.dst);
1058 return;
1059 case GXin_RdWrLR:
1060 addHRegUse(u, (i->GXin.RdWrLR.wrLR ? HRmRead : HRmWrite),
1061 i->GXin.RdWrLR.gpr);
1062 return;
1063 case GXin_MovCond:
1064 if (i->GXin.MovCond.srcR->tag == GXrh_Reg) {
1065 addHRegUse(u, HRmRead, i->GXin.MovCond.srcR->GXrh.Reg.reg);
1066 }
1067 addHRegUse(u, HRmRead, i->GXin.MovCond.srcL);
1068 addHRegUse(u, HRmRead, i->GXin.MovCond.condR);
1069 addHRegUse(u, HRmWrite, i->GXin.MovCond.dst);
1070 return;
1071 default:
1072 vpanic("getRegUsage_TILEGXInstr");
1073 }
1074 }
1075
1076 /* local helper */
mapReg(HRegRemap * m,HReg * r)1077 static void mapReg ( HRegRemap * m, HReg * r )
1078 {
1079 *r = lookupHRegRemap(m, *r);
1080 }
1081
mapRegs_TILEGXInstr(HRegRemap * m,TILEGXInstr * i)1082 void mapRegs_TILEGXInstr ( HRegRemap * m, TILEGXInstr * i )
1083 {
1084 switch (i->tag) {
1085 case GXin_LI:
1086 mapReg(m, &i->GXin.LI.dst);
1087 break;
1088 case GXin_Alu:
1089 mapReg(m, &i->GXin.Alu.srcL);
1090 mapRegs_TILEGXRH(m, i->GXin.Alu.srcR);
1091 mapReg(m, &i->GXin.Alu.dst);
1092 return;
1093 case GXin_CmpI:
1094 mapReg(m, &i->GXin.CmpI.srcL);
1095 mapRegs_TILEGXRH(m, i->GXin.CmpI.srcR);
1096 mapReg(m, &i->GXin.CmpI.dst);
1097 return;
1098 case GXin_Shft:
1099 mapReg(m, &i->GXin.Shft.srcL);
1100 mapRegs_TILEGXRH(m, i->GXin.Shft.srcR);
1101 mapReg(m, &i->GXin.Shft.dst);
1102 return;
1103 case GXin_Cmp:
1104 mapReg(m, &i->GXin.Cmp.srcL);
1105 mapReg(m, &i->GXin.Cmp.srcR);
1106 mapReg(m, &i->GXin.Cmp.dst);
1107 return;
1108 case GXin_Acas:
1109 mapReg(m, &i->GXin.Acas.old);
1110 mapReg(m, &i->GXin.Acas.addr);
1111 mapReg(m, &i->GXin.Acas.new);
1112 if (i->GXin.Acas.op == GXacas_CMPEXCH)
1113 mapReg(m, &i->GXin.Acas.exp);
1114 return;
1115 case GXin_Bf:
1116 mapReg(m, &i->GXin.Bf.src);
1117 mapReg(m, &i->GXin.Bf.dst);
1118 return;
1119 case GXin_Unary:
1120 mapReg(m, &i->GXin.Unary.src);
1121 mapReg(m, &i->GXin.Unary.dst);
1122 return;
1123 case GXin_Mul:
1124 mapReg(m, &i->GXin.Mul.dst);
1125 mapReg(m, &i->GXin.Mul.srcL);
1126 mapReg(m, &i->GXin.Mul.srcR);
1127 return;
1128 case GXin_Call:
1129 {
1130 if (i->GXin.Call.cond != TILEGXcc_AL)
1131 mapReg(m, &i->GXin.Call.src);
1132 return;
1133 }
1134 case GXin_XDirect:
1135 mapRegs_TILEGXAMode(m, i->GXin.XDirect.amPC);
1136 return;
1137 case GXin_XIndir:
1138 mapReg(m, &i->GXin.XIndir.dstGA);
1139 mapRegs_TILEGXAMode(m, i->GXin.XIndir.amPC);
1140 return;
1141 case GXin_XAssisted:
1142 mapReg(m, &i->GXin.XAssisted.dstGA);
1143 mapRegs_TILEGXAMode(m, i->GXin.XAssisted.amPC);
1144 return;
1145 case GXin_EvCheck:
1146 mapRegs_TILEGXAMode(m, i->GXin.EvCheck.amCounter);
1147 mapRegs_TILEGXAMode(m, i->GXin.EvCheck.amFailAddr);
1148 return;
1149 case GXin_ProfInc:
1150 return;
1151 case GXin_Load:
1152 mapRegs_TILEGXAMode(m, i->GXin.Load.src);
1153 mapReg(m, &i->GXin.Load.dst);
1154 return;
1155 case GXin_Store:
1156 mapReg(m, &i->GXin.Store.src);
1157 mapRegs_TILEGXAMode(m, i->GXin.Store.dst);
1158 return;
1159 case GXin_RdWrLR:
1160 mapReg(m, &i->GXin.RdWrLR.gpr);
1161 return;
1162 case GXin_MovCond:
1163 if (i->GXin.MovCond.srcR->tag == GXrh_Reg) {
1164 mapReg(m, &(i->GXin.MovCond.srcR->GXrh.Reg.reg));
1165 }
1166 mapReg(m, &i->GXin.MovCond.srcL);
1167 mapReg(m, &i->GXin.MovCond.condR);
1168 mapReg(m, &i->GXin.MovCond.dst);
1169
1170 return;
1171 default:
1172 vpanic("mapRegs_TILEGXInstr");
1173 }
1174 }
1175
1176 /* Figure out if i represents a reg-reg move, and if so assign the
1177 source and destination to *src and *dst. If in doubt say No. Used
1178 by the register allocator to do move coalescing.
1179 */
isMove_TILEGXInstr(TILEGXInstr * i,HReg * src,HReg * dst)1180 Bool isMove_TILEGXInstr ( TILEGXInstr * i, HReg * src, HReg * dst )
1181 {
1182 /* Moves between integer regs */
1183 if (i->tag == GXin_Alu) {
1184 // or Rd,Rs,Rs == mov Rd, Rs
1185 if (i->GXin.Alu.op != GXalu_OR)
1186 return False;
1187 if (i->GXin.Alu.srcR->tag != GXrh_Reg)
1188 return False;
1189 if (!sameHReg(i->GXin.Alu.srcR->GXrh.Reg.reg, i->GXin.Alu.srcL))
1190 return False;
1191 *src = i->GXin.Alu.srcL;
1192 *dst = i->GXin.Alu.dst;
1193 return True;
1194 }
1195 return False;
1196 }
1197
1198 /* Generate tilegx spill/reload instructions under the direction of the
1199 register allocator.
1200 */
genSpill_TILEGX(HInstr ** i1,HInstr ** i2,HReg rreg,Int offsetB)1201 void genSpill_TILEGX ( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
1202 Int offsetB )
1203 {
1204 TILEGXAMode *am;
1205 vassert(offsetB >= 0);
1206 vassert(!hregIsVirtual(rreg));
1207 *i1 = *i2 = NULL;
1208 am = TILEGXAMode_IR(offsetB, TILEGXGuestStatePointer());
1209
1210 switch (hregClass(rreg)) {
1211 case HRcInt64:
1212 *i1 = TILEGXInstr_Store(8, am, rreg);
1213 break;
1214 case HRcInt32:
1215 *i1 = TILEGXInstr_Store(4, am, rreg);
1216 break;
1217 default:
1218 ppHRegClass(hregClass(rreg));
1219 vpanic("genSpill_TILEGX: unimplemented regclass");
1220 }
1221 }
1222
genReload_TILEGX(HInstr ** i1,HInstr ** i2,HReg rreg,Int offsetB)1223 void genReload_TILEGX ( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
1224 Int offsetB )
1225 {
1226 TILEGXAMode *am;
1227 vassert(!hregIsVirtual(rreg));
1228 am = TILEGXAMode_IR(offsetB, TILEGXGuestStatePointer());
1229
1230 switch (hregClass(rreg)) {
1231 case HRcInt64:
1232 *i1 = TILEGXInstr_Load(8, rreg, am);
1233 break;
1234 case HRcInt32:
1235 *i1 = TILEGXInstr_Load(4, rreg, am);
1236 break;
1237 default:
1238 ppHRegClass(hregClass(rreg));
1239 vpanic("genReload_TILEGX: unimplemented regclass");
1240 break;
1241 }
1242 }
1243
1244 /* --------- The tilegx assembler --------- */
1245
mkInsnBin(UChar * p,ULong insn)1246 static UChar *mkInsnBin ( UChar * p, ULong insn )
1247 {
1248 vassert(insn != (ULong)(-1));
1249 if (((Addr)p) & 7) {
1250 vex_printf("p=%p\n", p);
1251 vassert((((Addr)p) & 7) == 0);
1252 }
1253 *((ULong *)(Addr)p) = insn;
1254 p += 8;
1255 return p;
1256 }
1257
display_insn(struct tilegx_decoded_instruction decoded[1])1258 static Int display_insn ( struct tilegx_decoded_instruction
1259 decoded[1] )
1260 {
1261 Int i;
1262 for (i = 0;
1263 decoded[i].opcode && (i < 1);
1264 i++) {
1265 Int n;
1266 vex_printf("%s ", decoded[i].opcode->name);
1267
1268 for (n = 0; n < decoded[i].opcode->num_operands; n++) {
1269 const struct tilegx_operand *op = decoded[i].operands[n];
1270
1271 if (op->type == TILEGX_OP_TYPE_REGISTER)
1272 vex_printf("r%d", (Int) decoded[i].operand_values[n]);
1273 else
1274 vex_printf("%llu", (ULong)decoded[i].operand_values[n]);
1275
1276 if (n != (decoded[i].opcode->num_operands - 1))
1277 vex_printf(", ");
1278 }
1279 vex_printf(" ");
1280 }
1281 return i;
1282 }
1283
1284
decode_and_display(tilegx_bundle_bits * p,Int count,ULong pc)1285 Int decode_and_display ( tilegx_bundle_bits *p, Int count, ULong pc )
1286 {
1287 struct tilegx_decoded_instruction
1288 decode[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
1289 Int i;
1290
1291 #ifdef TILEGX_DEBUG
1292 vex_printf("Insn@0x%lx\n", (ULong)p);
1293 #endif
1294
1295 if (count > 0x1000) {
1296 vex_printf("insn count: %d", count);
1297 vassert(0);
1298 }
1299
1300 for (i = 0 ; i < count ; i++) {
1301 if (pc) {
1302 vex_printf("%012llx %016llx ", pc, (ULong)p[i]);
1303 pc += 8;
1304 }
1305 parse_insn_tilegx(p[i], 0, decode);
1306
1307 Int n, k, bundled = 0;
1308
1309 for(k = 0; (k < TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE) && decode[k].opcode;
1310 k++) {
1311 if (decode[k].opcode->mnemonic != TILEGX_OPC_FNOP)
1312 bundled++;
1313 }
1314
1315 /* Print "{", ";" and "}" only if multiple instructions are bundled. */
1316 if (bundled > 1)
1317 vex_printf("{ ");
1318
1319 n = bundled;
1320 for(k = 0; (k < TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE) && decode[k].opcode;
1321 k++) {
1322 if (decode[k].opcode->mnemonic == TILEGX_OPC_FNOP)
1323 continue;
1324
1325 display_insn(&decode[k]);
1326
1327 if (--n > 0)
1328 vex_printf("; ");
1329 }
1330
1331 if (bundled > 1)
1332 vex_printf(" }");
1333
1334 vex_printf("\n");
1335 }
1336 return count;
1337 }
1338
iregNo(HReg r)1339 static UInt iregNo ( HReg r )
1340 {
1341 UInt n;
1342 vassert(hregClass(r) == HRcInt64);
1343 vassert(!hregIsVirtual(r));
1344 n = hregEncoding(r);
1345 vassert(n <= 63);
1346 return n;
1347 }
1348
doAMode_IR(UChar * p,UInt opc1,UInt rSD,TILEGXAMode * am)1349 static UChar *doAMode_IR ( UChar * p, UInt opc1, UInt rSD, TILEGXAMode * am )
1350 {
1351 UInt rA;
1352 vassert(am->tag == GXam_IR);
1353
1354 rA = iregNo(am->GXam.IR.base);
1355
1356 if (opc1 == TILEGX_OPC_ST1 || opc1 == TILEGX_OPC_ST2 ||
1357 opc1 == TILEGX_OPC_ST4 || opc1 == TILEGX_OPC_ST) {
1358 if ( am->GXam.IR.index ) {
1359 /* r51 is reserved scratch registers. */
1360 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
1361 51, rA, am->GXam.IR.index));
1362 /* store rSD to address in r51 */
1363 p = mkInsnBin(p, mkTileGxInsn(opc1, 2, 51, rSD));
1364 } else {
1365 /* store rSD to address in rA */
1366 p = mkInsnBin(p, mkTileGxInsn(opc1, 2, rA, rSD));
1367 }
1368 } else {
1369 if ( am->GXam.IR.index ) {
1370 /* r51 is reserved scratch registers. */
1371 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
1372 51, rA, am->GXam.IR.index));
1373 /* load from address in r51 to rSD. */
1374 p = mkInsnBin(p, mkTileGxInsn(opc1, 2, rSD, 51));
1375 } else {
1376 /* load from address in rA to rSD. */
1377 p = mkInsnBin(p, mkTileGxInsn(opc1, 2, rSD, rA));
1378 }
1379 }
1380 return p;
1381 }
1382
1383 /* Generate a machine-word sized load or store using exact 2 bundles.
1384 Simplified version of the GXin_Load and GXin_Store cases below. */
do_load_or_store_machine_word(UChar * p,Bool isLoad,UInt reg,TILEGXAMode * am)1385 static UChar* do_load_or_store_machine_word ( UChar* p, Bool isLoad, UInt reg,
1386 TILEGXAMode* am )
1387 {
1388 UInt rA = iregNo(am->GXam.IR.base);
1389
1390 if (am->tag != GXam_IR)
1391 vpanic(__func__);
1392
1393 if (isLoad) /* load */ {
1394 /* r51 is reserved scratch registers. */
1395 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
1396 51, rA, am->GXam.IR.index));
1397 /* load from address in r51 to rSD. */
1398 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_LD, 2, reg, 51));
1399 } else /* store */ {
1400 /* r51 is reserved scratch registers. */
1401 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
1402 51, rA, am->GXam.IR.index));
1403 /* store rSD to address in r51 */
1404 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ST, 2, 51, reg));
1405 }
1406 return p;
1407 }
1408
1409 /* Load imm to r_dst */
mkLoadImm(UChar * p,UInt r_dst,ULong imm)1410 static UChar *mkLoadImm ( UChar * p, UInt r_dst, ULong imm )
1411 {
1412 vassert(r_dst < 0x40);
1413
1414 if (imm == 0)
1415 {
1416 /* A special case, use r63 - zero register. */
1417 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MOVE, 2, r_dst, 63));
1418 }
1419 else if (imm >= 0xFFFFFFFFFFFF8000ULL || imm < 0x8000)
1420 {
1421 /* only need one 16-bit sign-extendable movli instructon. */
1422 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MOVELI, 2,
1423 r_dst, imm & 0xFFFF));
1424
1425 }
1426 else if (imm >= 0xFFFFFFFF80000000ULL || imm < 0x80000000ULL)
1427 {
1428 /* Sign-extendable moveli and a shl16insli */
1429 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MOVELI, 2,
1430 r_dst,
1431 (imm >> 16) & 0xFFFF));
1432
1433 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1434 r_dst, r_dst,
1435 (imm & 0xFFFF)));
1436
1437 }
1438 else
1439 {
1440 /* A general slower and rare case, use 4 instructions/bundles:
1441 moveli r_dst, imm[63:48]
1442 shl16insli r_dst, imm[47:32]
1443 shl16insli r_dst, imm[31:16]
1444 shl16insli r_dst, imm[15: 0]
1445 */
1446 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MOVELI, 2,
1447 r_dst,
1448 (imm >> 48) & 0xFFFF));
1449
1450 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1451 r_dst, r_dst,
1452 (imm >> 32) & 0xFFFF));
1453
1454 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1455 r_dst, r_dst,
1456 (imm >> 16) & 0xFFFF));
1457
1458 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1459 r_dst, r_dst,
1460 imm & 0xFFFF));
1461 }
1462 return p;
1463 }
1464
1465 /* Load imm to r_dst using exact 4 bundles. A special case of above
1466 mkLoadImm(...). */
mkLoadImm_EXACTLY4(UChar * p,UInt r_dst,ULong imm)1467 static UChar *mkLoadImm_EXACTLY4 ( UChar * p, UInt r_dst, ULong imm )
1468 {
1469 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MOVELI, 2,
1470 r_dst,
1471 (imm >> 48) & 0xFFFF));
1472
1473 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1474 r_dst, r_dst,
1475 (imm >> 32) & 0xFFFF));
1476
1477 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1478 r_dst, r_dst,
1479 (imm >> 16) & 0xFFFF));
1480
1481 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1482 r_dst, r_dst,
1483 (imm) & 0xFFFF));
1484 return p;
1485 }
1486
1487 /* Move r_dst to r_src */
mkMoveReg(UChar * p,UInt r_dst,UInt r_src)1488 static UChar *mkMoveReg ( UChar * p, UInt r_dst, UInt r_src )
1489 {
1490 vassert(r_dst < 0x40);
1491 vassert(r_src < 0x40);
1492
1493 if (r_dst != r_src) {
1494 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MOVE, 2,
1495 r_dst, r_src));
1496 }
1497 return p;
1498 }
1499
1500 /* Emit an instruction into buf and return the number of bytes used.
1501 Note that buf is not the insn's final place, and therefore it is
1502 imperative to emit position-independent code. */
emit_TILEGXInstr(Bool * is_profInc,UChar * buf,Int nbuf,TILEGXInstr * i,Bool mode64,VexEndness endness_host,void * disp_cp_chain_me_to_slowEP,void * disp_cp_chain_me_to_fastEP,void * disp_cp_xindir,void * disp_cp_xassisted)1503 Int emit_TILEGXInstr ( Bool* is_profInc,
1504 UChar* buf,
1505 Int nbuf,
1506 TILEGXInstr* i,
1507 Bool mode64,
1508 VexEndness endness_host,
1509 void* disp_cp_chain_me_to_slowEP,
1510 void* disp_cp_chain_me_to_fastEP,
1511 void* disp_cp_xindir,
1512 void* disp_cp_xassisted )
1513 {
1514 Int instr_bytes = 0;
1515 UChar *p = &buf[0];
1516 UChar *ptmp = p;
1517 vassert(nbuf >= 32);
1518 vassert(!((Addr)p & 0x7));
1519 vassert (mode64);
1520
1521 switch (i->tag) {
1522 case GXin_MovCond: {
1523
1524 TILEGXRH *srcR = i->GXin.MovCond.srcR;
1525 UInt condR = iregNo(i->GXin.MovCond.condR);
1526 UInt dst = iregNo(i->GXin.MovCond.dst);
1527
1528 UInt srcL = iregNo(i->GXin.MovCond.srcL);
1529
1530 if (i->GXin.MovCond.cond == TILEGXcc_EZ) {
1531 if (srcR->tag == GXrh_Reg) {
1532 p = mkMoveReg(p, dst, iregNo(srcR->GXrh.Reg.reg));
1533 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMOVEQZ, 3,
1534 dst, condR, srcL));
1535 } else {
1536 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MOVELI, 2,
1537 dst, srcR->GXrh.Imm.imm16));
1538 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMOVEQZ, 3,
1539 dst, condR, srcL));
1540 }
1541 } else {
1542 vassert(0);
1543 }
1544
1545 goto done;
1546 }
1547 case GXin_LI:
1548
1549 // Tilegx, load literal
1550 p = mkLoadImm(p, iregNo(i->GXin.LI.dst), i->GXin.LI.imm);
1551 goto done;
1552
1553 case GXin_Alu: {
1554 TILEGXRH *srcR = i->GXin.Alu.srcR;
1555 Bool immR = toBool(srcR->tag == GXrh_Imm);
1556 UInt r_dst = iregNo(i->GXin.Alu.dst);
1557 UInt r_srcL = iregNo(i->GXin.Alu.srcL);
1558 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->GXrh.Reg.reg);
1559
1560 switch (i->GXin.Alu.op) {
1561 /*GXalu_ADD, GXalu_SUB, GXalu_AND, GXalu_OR, GXalu_NOR, GXalu_XOR */
1562 case GXalu_ADD:
1563 if (immR) {
1564 vassert(srcR->GXrh.Imm.imm16 != 0x8000);
1565 if (srcR->GXrh.Imm.syned)
1566 /* addi */
1567 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
1568 r_dst, r_srcL,
1569 srcR->GXrh.Imm.imm16));
1570 else
1571 /* addiu, use shil16insli for tilegx */
1572 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL16INSLI, 3,
1573 r_dst, 63,
1574 srcR->GXrh.Imm.imm16));
1575 } else {
1576 /* addu */
1577 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADD, 3,
1578 r_dst, r_srcL,
1579 r_srcR));
1580 }
1581 break;
1582 case GXalu_SUB:
1583 if (immR) {
1584 /* addi , but with negated imm */
1585 vassert(srcR->GXrh.Imm.syned);
1586 vassert(srcR->GXrh.Imm.imm16 != 0x8000);
1587 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
1588 r_dst, r_srcL,
1589 -srcR->GXrh.Imm.imm16));
1590 } else {
1591 /* subu */
1592 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SUB, 3,
1593 r_dst, r_srcL,
1594 r_srcR));
1595 }
1596 break;
1597 case GXalu_AND:
1598 if (immR) {
1599 /* andi */
1600 vassert((srcR->GXrh.Imm.imm16 >> 8 == 0) ||
1601 (srcR->GXrh.Imm.imm16 >> 8 == 0xFF));
1602
1603 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ANDI, 3,
1604 r_dst, r_srcL,
1605 srcR->GXrh.Imm.imm16));
1606
1607 } else {
1608 /* and */
1609 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_AND, 3,
1610 r_dst, r_srcL,
1611 r_srcR));
1612 }
1613 break;
1614 case GXalu_OR:
1615 if (immR) {
1616 /* ori */
1617 vassert((srcR->GXrh.Imm.imm16 >> 8 == 0) ||
1618 (srcR->GXrh.Imm.imm16 >> 8 == 0xFF));
1619
1620 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ORI, 3,
1621 r_dst, r_srcL,
1622 srcR->GXrh.Imm.imm16));
1623 } else {
1624 /* or */
1625 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_OR, 3,
1626 r_dst, r_srcL,
1627 r_srcR));
1628 }
1629 break;
1630 case GXalu_NOR:
1631 /* nor */
1632 vassert(!immR);
1633 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOR, 3,
1634 r_dst, r_srcL,
1635 r_srcR));
1636 break;
1637 case GXalu_XOR:
1638 if (immR) {
1639 /* xori */
1640 vassert(srcR->GXrh.Imm.syned);
1641 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_XORI, 3,
1642 r_dst, r_srcL,
1643 srcR->GXrh.Imm.imm16));
1644 } else {
1645 /* xor */
1646 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_XOR, 3,
1647 r_dst, r_srcL,
1648 r_srcR));
1649 }
1650 break;
1651
1652 default:
1653 goto bad;
1654 }
1655 goto done;
1656 }
1657
1658 case GXin_Shft: {
1659 TILEGXRH *srcR = i->GXin.Shft.srcR;
1660 Bool sz32 = i->GXin.Shft.sz32;
1661 Bool immR = toBool(srcR->tag == GXrh_Imm);
1662 UInt r_dst = iregNo(i->GXin.Shft.dst);
1663 UInt r_srcL = iregNo(i->GXin.Shft.srcL);
1664 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->GXrh.Reg.reg);
1665
1666 switch (i->GXin.Shft.op) {
1667 case GXshft_SLL:
1668 if (sz32) {
1669 if (immR) {
1670 UInt n = srcR->GXrh.Imm.imm16;
1671 vassert(n >= 0 && n < 64);
1672 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHLXI, 3,
1673 r_dst, r_srcL,
1674 srcR->GXrh.Imm.imm16));
1675 } else {
1676 /* shift variable */
1677 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHLX, 3,
1678 r_dst, r_srcL,
1679 r_srcR));
1680 }
1681 } else {
1682 if (immR) {
1683 UInt n = srcR->GXrh.Imm.imm16;
1684 vassert(n >= 0 && n < 64);
1685 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHLI, 3,
1686 r_dst, r_srcL,
1687 srcR->GXrh.Imm.imm16));
1688 } else {
1689 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHL, 3,
1690 r_dst, r_srcL,
1691 r_srcR));
1692 }
1693 }
1694 break;
1695
1696 case GXshft_SLL8x8:
1697 if (immR) {
1698 UInt n = srcR->GXrh.Imm.imm16;
1699 vassert(n >= 0 && n < 64);
1700 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_V1SHLI, 3,
1701 r_dst, r_srcL,
1702 srcR->GXrh.Imm.imm16));
1703 } else {
1704 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_V1SHL, 3,
1705 r_dst, r_srcL,
1706 r_srcR));
1707 }
1708 break;
1709
1710 case GXshft_SRL8x8:
1711 if (immR) {
1712 UInt n = srcR->GXrh.Imm.imm16;
1713 vassert(n >= 0 && n < 64);
1714 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_V1SHRUI, 3,
1715 r_dst, r_srcL,
1716 srcR->GXrh.Imm.imm16));
1717 } else {
1718 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_V1SHRU, 3,
1719 r_dst, r_srcL,
1720 r_srcR));
1721 }
1722 break;
1723
1724 case GXshft_SRL:
1725 if (sz32) {
1726 // SRL, SRLV
1727 if (immR) {
1728 UInt n = srcR->GXrh.Imm.imm16;
1729 vassert(n >= 0 && n < 32);
1730 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRUXI, 3,
1731 r_dst, r_srcL,
1732 srcR->GXrh.Imm.imm16));
1733 } else {
1734 /* shift variable */
1735 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRUX, 3,
1736 r_dst, r_srcL,
1737 r_srcR));
1738 }
1739 } else {
1740 // DSRL, DSRL32, DSRLV
1741 if (immR) {
1742 UInt n = srcR->GXrh.Imm.imm16;
1743 vassert((n >= 0 && n < 64));
1744 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRUI, 3,
1745 r_dst, r_srcL,
1746 srcR->GXrh.Imm.imm16));
1747 } else {
1748 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRU, 3,
1749 r_dst, r_srcL,
1750 r_srcR));
1751 }
1752 }
1753 break;
1754
1755 case GXshft_SRA:
1756 if (sz32) {
1757 // SRA, SRAV
1758 if (immR) {
1759 UInt n = srcR->GXrh.Imm.imm16;
1760 vassert(n >= 0 && n < 64);
1761 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRSI, 3,
1762 r_dst, r_srcL,
1763 srcR->GXrh.Imm.imm16));
1764
1765 } else {
1766 /* shift variable */
1767 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRS, 3,
1768 r_dst, r_srcL,
1769 r_srcR));
1770 }
1771 } else {
1772 // DSRA, DSRA32, DSRAV
1773 if (immR) {
1774
1775 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRSI, 3,
1776 r_dst, r_srcL,
1777 srcR->GXrh.Imm.imm16));
1778 } else {
1779 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_SHRS, 3,
1780 r_dst, r_srcL,
1781 r_srcR));
1782 }
1783 }
1784 break;
1785
1786 default:
1787 goto bad;
1788 }
1789
1790 goto done;
1791 }
1792
1793 case GXin_Unary: {
1794 UInt r_dst = iregNo(i->GXin.Unary.dst);
1795 UInt r_src = iregNo(i->GXin.Unary.src);
1796
1797 switch (i->GXin.Unary.op) {
1798 /* GXun_CLZ, GXun_NOP */
1799 case GXun_CLZ: //clz
1800
1801 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CLZ, 2,
1802 r_dst, r_src));
1803 break;
1804 case GXun_CTZ: //ctz
1805
1806 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CTZ, 2,
1807 r_dst, r_src));
1808 break;
1809
1810 case GXun_NOP:
1811 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOP, 0));
1812 break;
1813 }
1814 goto done;
1815 }
1816
1817 case GXin_Cmp: {
1818
1819 Bool syned = i->GXin.Cmp.syned;
1820 UInt r_srcL = iregNo(i->GXin.Cmp.srcL);
1821 UInt r_srcR = iregNo(i->GXin.Cmp.srcR);
1822 UInt r_dst = iregNo(i->GXin.Cmp.dst);
1823
1824 switch (i->GXin.Cmp.cond) {
1825 case TILEGXcc_EQ:
1826
1827 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPEQ, 3,
1828 r_dst, r_srcL,
1829 r_srcR));
1830
1831 break;
1832
1833 case TILEGXcc_NE:
1834 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPNE, 3,
1835 r_dst, r_srcL,
1836 r_srcR));
1837
1838 break;
1839 case TILEGXcc_LT:
1840 /* slt r_dst, r_srcL, r_srcR */
1841
1842 if (syned)
1843 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPLTS, 3,
1844 r_dst, r_srcL,
1845 r_srcR));
1846 else
1847 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPLTU, 3,
1848 r_dst, r_srcL,
1849 r_srcR));
1850
1851 break;
1852 case TILEGXcc_LO:
1853 /* sltu r_dst, r_srcL, r_srcR */
1854
1855 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPLTU, 3,
1856 r_dst, r_srcL,
1857 r_srcR));
1858
1859 break;
1860 case TILEGXcc_LE:
1861 if (syned)
1862 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPLES, 3,
1863 r_dst, r_srcL,
1864 r_srcR));
1865 else
1866 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPLEU, 3,
1867 r_dst, r_srcL,
1868 r_srcR));
1869 break;
1870 case TILEGXcc_LS:
1871
1872 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPLTU, 3,
1873 r_dst, r_srcL,
1874 r_srcR));
1875 break;
1876 default:
1877 goto bad;
1878 }
1879 goto done;
1880 }
1881
1882 case GXin_CmpI: {
1883
1884 TILEGXRH *srcR = i->GXin.CmpI.srcR;
1885 Bool immR = toBool(srcR->tag == GXrh_Imm);
1886 UInt r_dst = iregNo(i->GXin.CmpI.dst);
1887 UInt r_srcL = iregNo(i->GXin.CmpI.srcL);
1888 UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->GXrh.Reg.reg);
1889
1890 switch (i->GXin.CmpI.cond) {
1891 case TILEGXcc_EQ8x8:
1892 if (immR) {
1893 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_V1CMPEQI, 3,
1894 r_dst, r_srcL,
1895 srcR->GXrh.Imm.imm16));
1896 } else {
1897 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_V1CMPEQ, 3,
1898 r_dst, r_srcL,
1899 r_srcR));
1900 }
1901 break;
1902
1903 case TILEGXcc_NE8x8:
1904 if (immR) {
1905 vassert(0);
1906 } else {
1907 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_V1CMPNE, 3,
1908 r_dst, r_srcR,
1909 r_srcL));
1910 }
1911 break;
1912 default:
1913 vassert(0);
1914 }
1915 goto done;
1916 break;
1917 }
1918
1919 case GXin_Bf: {
1920
1921 /* Bit Field */
1922 UInt r_dst = iregNo(i->GXin.Bf.dst);
1923 UInt r_src = iregNo(i->GXin.Bf.src);
1924 UInt Start = i->GXin.Bf.Start;
1925 UInt End = i->GXin.Bf.End;
1926
1927 switch (i->GXin.Bf.op) {
1928 case GXbf_EXTS:
1929 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_BFEXTS, 4,
1930 r_dst, r_src,
1931 Start, End));
1932
1933 break;
1934 case GXbf_EXTU:
1935 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_BFEXTU, 4,
1936 r_dst, r_src,
1937 Start, End));
1938
1939 break;
1940 case GXbf_INS:
1941 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_BFINS, 4,
1942 r_dst, r_src,
1943 Start, End));
1944
1945 break;
1946 default:
1947 vassert(0);
1948 }
1949 goto done;
1950 break;
1951 }
1952
1953 case GXin_Acas: {
1954
1955 /* Atomic */
1956 UInt sz = i->GXin.Acas.sz;
1957 UInt old = iregNo(i->GXin.Acas.old);
1958 UInt addr= iregNo(i->GXin.Acas.addr);
1959 UInt new = iregNo(i->GXin.Acas.new);
1960
1961 switch (i->GXin.Acas.op) {
1962 case GXacas_CMPEXCH:
1963 {
1964 UInt exp = iregNo(i->GXin.Acas.exp);
1965 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MTSPR, 2,
1966 0x2780, exp));
1967 if (sz == 8)
1968 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPEXCH, 3,
1969 old, addr, new));
1970 else
1971 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_CMPEXCH4, 3,
1972 old, addr, new));
1973 }
1974 break;
1975
1976 case GXacas_EXCH:
1977 if (sz == 8)
1978 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_EXCH, 3,
1979 old, addr, new));
1980 else
1981 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_EXCH4, 3,
1982 old, addr, new));
1983 break;
1984
1985 case GXacas_FetchAnd:
1986 if (sz == 8)
1987 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHAND, 3,
1988 old, addr, new));
1989 else
1990 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHAND4, 3,
1991 old, addr, new));
1992 break;
1993
1994 case GXacas_FetchAdd:
1995 if (sz == 8)
1996 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHADD, 3,
1997 old, addr, new));
1998 else
1999 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHADD4, 3,
2000 old, addr, new));
2001 break;
2002
2003 case GXacas_FetchAddgez:
2004 if (sz == 8)
2005 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHADDGEZ, 3,
2006 old, addr, new));
2007 else
2008 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHADDGEZ4, 3,
2009 old, addr, new));
2010 break;
2011
2012 case GXacas_FetchOr:
2013 if (sz == 8)
2014 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHOR, 3,
2015 old, addr, new));
2016 else
2017 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_FETCHOR4, 3,
2018 old, addr, new));
2019 break;
2020
2021 default: vassert(0);
2022 }
2023 goto done;
2024 break;
2025 }
2026
2027 case GXin_Mul: {
2028
2029 /* Multiplication */
2030 Bool syned = i->GXin.Mul.syned;
2031 Bool widening = i->GXin.Mul.widening;
2032 Bool sz32 = i->GXin.Mul.sz32;
2033 UInt r_srcL = iregNo(i->GXin.Mul.srcL);
2034 UInt r_srcR = iregNo(i->GXin.Mul.srcR);
2035 UInt r_dst = iregNo(i->GXin.Mul.dst);
2036
2037 vassert(widening); // always widen.
2038 vassert(!sz32); // always be 64 bits.
2039
2040 if (syned) {
2041 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MUL_LS_LS, 3,
2042 r_dst, r_srcL, r_srcR));
2043 } else {
2044 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MUL_LU_LU, 3,
2045 r_dst, r_srcL, r_srcR));
2046 }
2047 goto done;
2048 }
2049
2050 case GXin_Call: {
2051
2052 /* Function Call. */
2053 TILEGXCondCode cond = i->GXin.Call.cond;
2054 UInt r_dst = 11; /* using r11 as address temporary */
2055
2056 /* jump over the following insns if conditional. */
2057 if (cond != TILEGXcc_AL) {
2058 /* jmp fwds if !condition */
2059 /* don't know how many bytes to jump over yet...
2060 make space for a jump instruction + nop!!! and fill in later. */
2061 ptmp = p; /* fill in this bit later */
2062 p += 8;
2063 }
2064
2065 /* load target to r_dst */
2066 p = mkLoadImm(p, r_dst, i->GXin.Call.target);
2067
2068 /* jalr %r_dst */
2069 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_JALRP, 1,
2070 r_dst));
2071
2072 /* Fix up the conditional jump, if there was one. */
2073 if (cond != TILEGXcc_AL) {
2074 UInt r_src = iregNo(i->GXin.Call.src);
2075 Int delta = p - ptmp;
2076
2077 vassert(cond == TILEGXcc_EQ);
2078
2079 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_BEQZ, 2,
2080 r_src, delta / 8));
2081 }
2082 goto done;
2083 }
2084
2085 case GXin_XDirect: {
2086 /* NB: what goes on here has to be very closely coordinated
2087 with the chainXDirect_TILEGX and unchainXDirect_TILEGX below. */
2088 /* We're generating chain-me requests here, so we need to be
2089 sure this is actually allowed -- no-redir translations
2090 can't use chain-me's. Hence: */
2091 vassert(disp_cp_chain_me_to_slowEP != NULL);
2092 vassert(disp_cp_chain_me_to_fastEP != NULL);
2093
2094 /* Use ptmp for backpatching conditional jumps. */
2095 ptmp = NULL;
2096
2097 /* First, if this is conditional, create a conditional
2098 jump over the rest of it. Or at least, leave a space for
2099 it that we will shortly fill in. */
2100 if (i->GXin.XDirect.cond != TILEGXcc_AL) {
2101 vassert(i->GXin.XDirect.cond != TILEGXcc_NV);
2102 ptmp = p;
2103 p += 24;
2104 }
2105
2106 /* Update the guest PC. */
2107 /* move r11, dstGA */
2108 /* st amPC, r11 */
2109 p = mkLoadImm_EXACTLY4(p, /*r*/ 11, (ULong)i->GXin.XDirect.dstGA);
2110
2111 p = do_load_or_store_machine_word(p, False /*!isLoad*/ , /*r*/ 11,
2112 i->GXin.XDirect.amPC);
2113
2114 /* --- FIRST PATCHABLE BYTE follows --- */
2115 /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're
2116 calling to) backs up the return address, so as to find the
2117 address of the first patchable byte. So: don't change the
2118 number of instructions (3) below. */
2119 /* move r9, VG_(disp_cp_chain_me_to_{slowEP,fastEP}) */
2120 /* jr r11 */
2121 void* disp_cp_chain_me
2122 = i->GXin.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
2123 : disp_cp_chain_me_to_slowEP;
2124 p = mkLoadImm_EXACTLY4(p, /*r*/ 11,
2125 (Addr)disp_cp_chain_me);
2126 /* jalr r11 */
2127 /* nop */
2128 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_JALR, 1, 11));
2129
2130 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOP, 0));
2131
2132 /* --- END of PATCHABLE BYTES --- */
2133
2134 /* Fix up the conditional jump, if there was one. */
2135 if (i->GXin.XDirect.cond != TILEGXcc_AL) {
2136 Int delta = p - ptmp;
2137 delta = delta / 8 - 3;
2138
2139 /* ld r11, COND_OFFSET(GuestSP=r50)
2140 beqz r11, delta
2141 */
2142 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
2143 11, 50, COND_OFFSET()));
2144 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_LD, 2,
2145 11, 11));
2146
2147 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_BEQZ, 2,
2148 11, delta));
2149
2150 }
2151 goto done;
2152 }
2153
2154 case GXin_XIndir: {
2155 /* We're generating transfers that could lead indirectly to a
2156 chain-me, so we need to be sure this is actually allowed --
2157 no-redir translations are not allowed to reach normal
2158 translations without going through the scheduler. That means
2159 no XDirects or XIndirs out from no-redir translations.
2160 Hence: */
2161 vassert(disp_cp_xindir != NULL);
2162
2163 /* Use ptmp for backpatching conditional jumps. */
2164 ptmp = NULL;
2165
2166 /* First off, if this is conditional, create a conditional
2167 jump over the rest of it. */
2168 if (i->GXin.XIndir.cond != TILEGXcc_AL) {
2169 vassert(i->GXin.XIndir.cond != TILEGXcc_NV);
2170 ptmp = p;
2171 p += 24;
2172 }
2173
2174 /* Update the guest PC. */
2175 /* st amPC, dstGA */
2176 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
2177 iregNo(i->GXin.XIndir.dstGA),
2178 i->GXin.XIndir.amPC);
2179
2180 /* move r11, VG_(disp_cp_xindir), 4 bundles. */
2181 /* jalr r11 */
2182 /* nop */
2183 p = mkLoadImm_EXACTLY4(p, /*r*/ 11,
2184 (Addr)disp_cp_xindir);
2185
2186 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_JALR, 1, 11));
2187
2188 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOP, 0));
2189
2190 /* Fix up the conditional jump, if there was one. */
2191 if (i->GXin.XIndir.cond != TILEGXcc_AL) {
2192 Int delta = p - ptmp;
2193 delta = delta / 8 - 3;
2194 vassert(delta > 0 && delta < 40);
2195
2196 /* ld r11, COND_OFFSET($GuestSP)
2197 beqz r11, delta */
2198
2199 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
2200 11, 50, COND_OFFSET()));
2201 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_LD, 2,
2202 11, 11));
2203 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_BEQZ, 2,
2204 11, delta));
2205 }
2206 goto done;
2207 }
2208
2209 case GXin_XAssisted: {
2210 /* First off, if this is conditional, create a conditional jump
2211 over the rest of it. Or at least, leave a space for it that
2212 we will shortly fill in. */
2213 ptmp = NULL;
2214 if (i->GXin.XAssisted.cond != TILEGXcc_AL) {
2215 vassert(i->GXin.XAssisted.cond != TILEGXcc_NV);
2216 ptmp = p;
2217 p += 24;
2218 }
2219
2220 /* Update the guest PC. */
2221 /* st amPC, dstGA */
2222 p = do_load_or_store_machine_word(p, False /*!isLoad*/ ,
2223 iregNo(i->GXin.XIndir.dstGA),
2224 i->GXin.XIndir.amPC);
2225
2226 UInt trcval = 0;
2227 switch (i->GXin.XAssisted.jk) {
2228 case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
2229 case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
2230 case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
2231 case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
2232 case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
2233 case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
2234 case Ijk_InvalICache: trcval = VEX_TRC_JMP_INVALICACHE; break;
2235 case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
2236 case Ijk_SigILL: trcval = VEX_TRC_JMP_SIGILL; break;
2237 case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
2238 case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break;
2239 case Ijk_SigFPE_IntDiv: trcval = VEX_TRC_JMP_SIGFPE_INTDIV; break;
2240 case Ijk_SigFPE_IntOvf: trcval = VEX_TRC_JMP_SIGFPE_INTOVF; break;
2241 case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
2242 case Ijk_Ret:
2243 {
2244 /* Tilegx "iret" instruction. */
2245 trcval = VEX_TRC_JMP_BORING;
2246 /* Interrupt return "iret", setup the jump address into EX_CONTRXT_0_0.
2247 Read context_0_1 from guest_state */
2248 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
2249 51, 50, OFFSET_EX1));
2250 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_LD, 2,
2251 11, 51));
2252 /* Write into host cpu's context_0_1 spr. */
2253 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MTSPR, 2,
2254 0x2581, 11));
2255 /* Read context_0_0 from guest_state */
2256 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
2257 51, 50, OFFSET_EX0));
2258 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_LD, 2,
2259 11, 51));
2260 /* Write into host cpu's context_0_0 spr */
2261 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_MTSPR, 2,
2262 0x2580, 11));
2263 /* Update the guest PC so branch to the iret target address
2264 in EX_CONTEXT_0. */
2265 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
2266 51, 50, 512));
2267 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ST, 2,
2268 51, 11));
2269 }
2270 break;
2271 /* We don't expect to see the following being assisted.
2272 case Ijk_Call:
2273 fallthrough */
2274 default:
2275 ppIRJumpKind(i->GXin.XAssisted.jk);
2276 vpanic("emit_TILEGXInstr.GXin_XAssisted: unexpected jump kind");
2277 }
2278 vassert(trcval != 0);
2279
2280 /* moveli r50, trcval */
2281
2282 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDLI, 3, 50, 63, trcval));
2283
2284 /* move r11, VG_(disp_cp_xassisted) */
2285
2286 p = mkLoadImm_EXACTLY4(p, /*r*/ 11,
2287 (Addr)disp_cp_xassisted);
2288 /* jalr r11
2289 nop */
2290
2291 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_JALR, 1, 11));
2292 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOP, 0));
2293
2294 /* Fix up the conditional jump, if there was one. */
2295 if (i->GXin.XAssisted.cond != TILEGXcc_AL) {
2296 Int delta = p - ptmp;
2297 delta = delta / 8 - 3;
2298 vassert(delta > 0 && delta < 40);
2299
2300 /* ld r11, COND_OFFSET($GuestSP)
2301 beqz r11, delta
2302 nop */
2303
2304 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_ADDLI, 3,
2305 11, 50, COND_OFFSET()));
2306 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_LD, 2,
2307 11, 11));
2308 ptmp = mkInsnBin(ptmp, mkTileGxInsn(TILEGX_OPC_BEQZ, 2,
2309 11, delta));
2310 }
2311 goto done;
2312 }
2313
2314 case GXin_EvCheck: {
2315 /* We generate:
2316 ld r11, amCounter
2317 addi r11, r11, -1
2318 st amCounter, r11
2319 bgez r11, nofail
2320 ld r11, amFailAddr
2321 jalr r11
2322 nop
2323 nofail:
2324 */
2325 UChar* p0 = p;
2326 /* ld r11, amCounter */
2327 p = do_load_or_store_machine_word(p, True /*isLoad*/ , /*r*/ 11,
2328 i->GXin.EvCheck.amCounter);
2329
2330 /* addi r11,r11,-1 */
2331
2332 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDI, 3,
2333 11, 11, -1));
2334
2335 /* st amCounter, 11 */
2336 p = do_load_or_store_machine_word(p, False /*!isLoad*/ , /*r*/ 11,
2337 i->GXin.EvCheck.amCounter);
2338
2339 /* Reserve a bundle, fill it after the do_load_or_store_machine_word.
2340 since we are not sure how many bundles it takes. */
2341 UChar* p1 = p;
2342 p += 8;
2343 /* bgez t9, nofail */
2344
2345 /* lw/ld r9, amFailAddr */
2346 p = do_load_or_store_machine_word(p, True /*isLoad*/ , /*r*/ 11,
2347 i->GXin.EvCheck.amFailAddr);
2348
2349 mkInsnBin(p1, mkTileGxInsn(TILEGX_OPC_BGEZ, 2,
2350 11, 2 + (p - p1) / 8));
2351
2352 /* jalr r11 */
2353
2354 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_JALR, 1, 11));
2355
2356 /* nop */
2357 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOP, 0));
2358
2359 /* nofail: */
2360
2361 /* Crosscheck */
2362 vassert(evCheckSzB_TILEGX() == (UChar*)p - (UChar*)p0);
2363 goto done;
2364 }
2365
2366 case GXin_ProfInc: {
2367 /* Generate a code template to increment a memory location whose
2368 address will be known later as an immediate value. This code
2369 template will be patched once the memory location is known.
2370 For now we do this with address == 0x65556555. */
2371 /* 64-bit:
2372 move r11, 0x6555655565556555ULL
2373 ld r51, r11
2374 addi r51, r51, 1
2375 st r11, r51
2376 */
2377
2378 /* move r11, 0x6555655565556555ULL */
2379 p = mkLoadImm_EXACTLY4(p, /*r*/ 11, 0x6555655565556555ULL);
2380
2381 /* ld r51, r11 */
2382
2383 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_LD, 2, 51, 11));
2384
2385 /* addi r51, r51, 1 */
2386
2387 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ADDI, 3, 51, 51, 1));
2388
2389 /* st r11, r51 */
2390
2391 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_ST, 2, 11, 51));
2392
2393 /* Tell the caller .. */
2394 vassert(!(*is_profInc));
2395 *is_profInc = True;
2396 goto done;
2397 }
2398
2399 case GXin_Load: {
2400 TILEGXAMode *am_addr = i->GXin.Load.src;
2401 if (am_addr->tag == GXam_IR) {
2402 UInt r_dst = iregNo(i->GXin.Load.dst);
2403 UInt opc, sz = i->GXin.Load.sz;
2404 if ((sz == 4 || sz == 8)) {
2405 /* should be guaranteed to us by iselWordExpr_AMode */
2406 vassert(0 == (am_addr->GXam.IR.index & 3));
2407 }
2408
2409 // Note: Valgrind memory load has no sign-extend. We extend explicitly.
2410 switch (sz) {
2411 case 1:
2412 opc = TILEGX_OPC_LD1U;
2413 break;
2414 case 2:
2415 opc = TILEGX_OPC_LD2U;
2416 break;
2417 case 4:
2418 opc = TILEGX_OPC_LD4U;
2419 break;
2420 case 8:
2421 opc = TILEGX_OPC_LD;
2422 break;
2423 default:
2424 goto bad;
2425 }
2426
2427 p = doAMode_IR(p, opc, r_dst, am_addr);
2428 goto done;
2429
2430 }
2431 }
2432
2433 case GXin_Store: {
2434 TILEGXAMode *am_addr = i->GXin.Store.dst;
2435 if (am_addr->tag == GXam_IR) {
2436 UInt r_src = iregNo(i->GXin.Store.src);
2437 UInt opc, sz = i->GXin.Store.sz;
2438 switch (sz) {
2439 case 1:
2440 opc = TILEGX_OPC_ST1;
2441 break;
2442 case 2:
2443 opc = TILEGX_OPC_ST2;
2444 break;
2445 case 4:
2446 opc = TILEGX_OPC_ST4;
2447 break;
2448 case 8:
2449 opc = TILEGX_OPC_ST;
2450 break;
2451 default:
2452 goto bad;
2453 }
2454
2455 p = doAMode_IR(p, opc, r_src, am_addr);
2456 goto done;
2457 } else {
2458 vassert(0);
2459 }
2460 }
2461
2462 case GXin_RdWrLR: {
2463 UInt reg = iregNo(i->GXin.RdWrLR.gpr);
2464 Bool wrLR = i->GXin.RdWrLR.wrLR;
2465 if (wrLR)
2466 p = mkMoveReg(p, 55, reg);
2467 else
2468 p = mkMoveReg(p, reg, 55);
2469 goto done;
2470 }
2471
2472 default:
2473 goto bad;
2474 }
2475
2476 bad:
2477 vex_printf("\n=> ");
2478 vpanic("emit_TILEGXInstr");
2479 /*NOTREACHED*/
2480
2481 done:
2482 instr_bytes = p - &buf[0];
2483 /* Instr byte count must be modular of 8. */
2484 vassert(0 == (instr_bytes & 0x7));
2485
2486 if ( 0) {
2487 Int k;
2488 for (k = 0; k < instr_bytes; k += 8)
2489 decode_and_display((ULong *)(Addr)&buf[k], 1, 0);
2490 }
2491
2492 /* Limit the JIT size. */
2493 vassert(instr_bytes <= 256);
2494 return instr_bytes;
2495 }
2496
2497
evCheckSzB_TILEGX(void)2498 Int evCheckSzB_TILEGX ( void )
2499 {
2500 UInt kInstrSize = 8;
2501 return 10*kInstrSize;
2502 }
2503
chainXDirect_TILEGX(VexEndness endness_host,void * place_to_chain,const void * disp_cp_chain_me_EXPECTED,const void * place_to_jump_to,Bool mode64)2504 VexInvalRange chainXDirect_TILEGX ( VexEndness endness_host,
2505 void* place_to_chain,
2506 const void* disp_cp_chain_me_EXPECTED,
2507 const void* place_to_jump_to,
2508 Bool mode64 )
2509 {
2510 vassert(mode64);
2511 vassert(endness_host == VexEndnessLE);
2512 /* What we're expecting to see is:
2513 move r11, disp_cp_chain_me_to_EXPECTED
2514 jalr r11
2515 nop
2516 viz
2517 <32 bytes generated by mkLoadImm_EXACTLY4>
2518 jalr r11
2519 nop
2520 */
2521 UChar* p = (UChar*)place_to_chain;
2522 vassert(0 == (7 & (HWord)p));
2523
2524 #ifdef TILEGX_DEBUG
2525 vex_printf("chainXDirect_TILEGX: disp_cp_chain_me_EXPECTED=%p\n",
2526 disp_cp_chain_me_EXPECTED);
2527 decode_and_display(p, 6, p);
2528
2529 vex_printf("chainXDirect_TILEGX: place_to_jump_to=%p\n",
2530 place_to_jump_to);
2531 #endif
2532
2533 /* And what we want to change it to is either:
2534 move r11, place_to_jump_to
2535 jalr r11
2536 nop
2537 viz
2538 <32 bytes generated by mkLoadImm_EXACTLY4>
2539 jalr r11
2540 nop
2541
2542 The replacement has the same length as the original.
2543 */
2544
2545 p = mkLoadImm_EXACTLY4(p, /*r*/ 11,
2546 (Addr)place_to_jump_to);
2547
2548
2549 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_JALR, 1, 11));
2550
2551 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOP, 0));
2552
2553 #ifdef TILEGX_DEBUG
2554 decode_and_display((UChar*)place_to_chain, 8, place_to_chain);
2555 #endif
2556
2557 Int len = p - (UChar*)place_to_chain;
2558 vassert(len == 48); /* stay sane */
2559 VexInvalRange vir = {(HWord)place_to_chain, len};
2560 return vir;
2561 }
2562
unchainXDirect_TILEGX(VexEndness endness_host,void * place_to_unchain,const void * place_to_jump_to_EXPECTED,const void * disp_cp_chain_me,Bool mode64)2563 VexInvalRange unchainXDirect_TILEGX ( VexEndness endness_host,
2564 void* place_to_unchain,
2565 const void* place_to_jump_to_EXPECTED,
2566 const void* disp_cp_chain_me,
2567 Bool mode64 )
2568 {
2569 vassert(mode64);
2570 vassert(endness_host == VexEndnessLE);
2571 /* What we're expecting to see is:
2572 move r11, place_to_jump_to_EXPECTED
2573 jalr r11
2574 nop
2575 viz
2576 <32 bytes generated by mkLoadImm_EXACTLY4>
2577 jalr r11
2578 nop
2579 */
2580 UChar* p = (UChar*)place_to_unchain;
2581 vassert(0 == (7 & (HWord)p));
2582
2583 /* And what we want to change it to is:
2584 move r11, disp_cp_chain_me
2585 jalr r11
2586 nop
2587 viz
2588 <32 bytes generated by mkLoadImm_EXACTLY4>
2589 jalr r11
2590 nop
2591 The replacement has the same length as the original.
2592 */
2593 p = mkLoadImm_EXACTLY4(p, /*r*/ 11,
2594 (Addr)disp_cp_chain_me);
2595
2596
2597 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_JALR, 1, 11));
2598
2599 p = mkInsnBin(p, mkTileGxInsn(TILEGX_OPC_NOP, 0));
2600
2601 Int len = p - (UChar*)place_to_unchain;
2602 vassert(len == 48); /* stay sane */
2603 VexInvalRange vir = {(HWord)place_to_unchain, len};
2604 return vir;
2605 }
2606
2607 /* Patch the counter address into a profile inc point, as previously
2608 created by the GXin_ProfInc case for emit_TILEGXInstr. */
patchProfInc_TILEGX(VexEndness endness_host,void * place_to_patch,const ULong * location_of_counter,Bool mode64)2609 VexInvalRange patchProfInc_TILEGX ( VexEndness endness_host,
2610 void* place_to_patch,
2611 const ULong* location_of_counter,
2612 Bool mode64 )
2613 {
2614 vassert(mode64);
2615 vassert(endness_host == VexEndnessLE);
2616 UChar* p = (UChar*)place_to_patch;
2617 vassert(0 == (7 & (HWord)p));
2618
2619 p = mkLoadImm_EXACTLY4(p, /*r*/ 11,
2620 (Addr)location_of_counter);
2621
2622 VexInvalRange vir = {(HWord)p, 32};
2623 return vir;
2624 }
2625
2626 /*---------------------------------------------------------------*/
2627 /*--- end host_tilegx_defs.c ---*/
2628 /*---------------------------------------------------------------*/
2629