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