1 
2 /*---------------------------------------------------------------*/
3 /*--- begin                             guest_arm64_helpers.c ---*/
4 /*---------------------------------------------------------------*/
5 
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9 
10    Copyright (C) 2013-2015 OpenWorks
11       info@open-works.net
12 
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17 
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26    02110-1301, USA.
27 
28    The GNU General Public License is contained in the file COPYING.
29 */
30 
31 #include "libvex_basictypes.h"
32 #include "libvex_emnote.h"
33 #include "libvex_guest_arm64.h"
34 #include "libvex_ir.h"
35 #include "libvex.h"
36 
37 #include "main_util.h"
38 #include "main_globals.h"
39 #include "guest_generic_bb_to_IR.h"
40 #include "guest_arm64_defs.h"
41 
42 
43 /* This file contains helper functions for arm guest code.  Calls to
44    these functions are generated by the back end.  These calls are of
45    course in the host machine code and this file will be compiled to
46    host machine code, so that all makes sense.
47 
48    Only change the signatures of these helper functions very
49    carefully.  If you change the signature here, you'll have to change
50    the parameters passed to it in the IR calls constructed by
51    guest_arm64_toIR.c.
52 */
53 
54 
55 /* Set to 1 to get detailed profiling info about individual N, Z, C
56    and V flag evaluation. */
57 #define PROFILE_NZCV_FLAGS 0
58 
59 #if PROFILE_NZCV_FLAGS
60 
61 static UInt tab_eval[ARM64G_CC_OP_NUMBER][16];
62 static UInt initted = 0;
63 static UInt tot_evals = 0;
64 
initCounts(void)65 static void initCounts ( void )
66 {
67    UInt i, j;
68    for (i = 0; i < ARM64G_CC_OP_NUMBER; i++) {
69       for (j = 0; j < 16; j++) {
70          tab_eval[i][j] = 0;
71       }
72    }
73    initted = 1;
74 }
75 
showCounts(void)76 static void showCounts ( void )
77 {
78    const HChar* nameCC[16]
79       = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
80           "HI", "LS", "GE", "LT", "GT", "LE", "AL", "NV" };
81    UInt i, j;
82    ULong sum = 0;
83    vex_printf("\nCC_OP          0         1         2         3    "
84               "     4         5         6\n");
85    vex_printf(  "--------------------------------------------------"
86               "--------------------------\n");
87    for (j = 0; j < 16; j++) {
88       vex_printf("%2d %s  ", j, nameCC[j]);
89       for (i = 0; i < ARM64G_CC_OP_NUMBER; i++) {
90          vex_printf("%9d ", tab_eval[i][j]);
91          sum += tab_eval[i][j];
92       }
93       vex_printf("\n");
94    }
95    vex_printf("(In total %llu calls)\n", sum);
96 }
97 
98 #define NOTE_EVAL(_cc_op, _cond) \
99    do { \
100       if (!initted) initCounts(); \
101       vassert( ((UInt)(_cc_op)) < ARM64G_CC_OP_NUMBER); \
102       vassert( ((UInt)(_cond)) < 16); \
103       tab_eval[(UInt)(_cc_op)][(UInt)(cond)]++;  \
104       tot_evals++; \
105       if (0 == (tot_evals & 0x7FFF)) \
106         showCounts(); \
107    } while (0)
108 
109 #endif /* PROFILE_NZCV_FLAGS */
110 
111 
112 /* Calculate the N flag from the supplied thunk components, in the
113    least significant bit of the word.  Returned bits 63:1 are zero. */
114 static
arm64g_calculate_flag_n(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)115 ULong arm64g_calculate_flag_n ( ULong cc_op, ULong cc_dep1,
116                                 ULong cc_dep2, ULong cc_dep3 )
117 {
118    switch (cc_op) {
119       case ARM64G_CC_OP_COPY: {
120          /* (nzcv:28x0, unused, unused) */
121          ULong nf   = (cc_dep1 >> ARM64G_CC_SHIFT_N) & 1;
122          return nf;
123       }
124       case ARM64G_CC_OP_ADD32: {
125          /* (argL, argR, unused) */
126          UInt  argL = (UInt)cc_dep1;
127          UInt  argR = (UInt)cc_dep2;
128          UInt  res  = argL + argR;
129          ULong nf   = (ULong)(res >> 31);
130          return nf;
131       }
132       case ARM64G_CC_OP_ADD64: {
133          /* (argL, argR, unused) */
134          ULong argL = cc_dep1;
135          ULong argR = cc_dep2;
136          ULong res  = argL + argR;
137          ULong nf   = (ULong)(res >> 63);
138          return nf;
139       }
140       case ARM64G_CC_OP_SUB32: {
141          /* (argL, argR, unused) */
142          UInt  argL = (UInt)cc_dep1;
143          UInt  argR = (UInt)cc_dep2;
144          UInt  res  = argL - argR;
145          ULong nf   = (ULong)(res >> 31);
146          return nf;
147       }
148       case ARM64G_CC_OP_SUB64: {
149          /* (argL, argR, unused) */
150          ULong argL = cc_dep1;
151          ULong argR = cc_dep2;
152          ULong res  = argL - argR;
153          ULong nf   = res >> 63;
154          return nf;
155       }
156       case ARM64G_CC_OP_ADC32: {
157          /* (argL, argR, oldC) */
158          UInt  argL = cc_dep1;
159          UInt  argR = cc_dep2;
160          UInt  oldC = cc_dep3;
161          vassert((oldC & ~1) == 0);
162          UInt  res  = argL + argR + oldC;
163          ULong nf   = (ULong)(res >> 31);
164          return nf;
165       }
166       case ARM64G_CC_OP_ADC64: {
167          /* (argL, argR, oldC) */
168          ULong argL = cc_dep1;
169          ULong argR = cc_dep2;
170          ULong oldC = cc_dep3;
171          vassert((oldC & ~1) == 0);
172          ULong res  = argL + argR + oldC;
173          ULong nf   = res >> 63;
174          return nf;
175       }
176       case ARM64G_CC_OP_SBC32: {
177          /* (argL, argR, oldC) */
178          UInt  argL = cc_dep1;
179          UInt  argR = cc_dep2;
180          UInt  oldC = cc_dep3;
181          vassert((oldC & ~1) == 0);
182          UInt  res  = argL - argR - (oldC ^ 1);
183          ULong nf   = (ULong)(res >> 31);
184          return nf;
185       }
186       case ARM64G_CC_OP_SBC64: {
187          /* (argL, argR, oldC) */
188          ULong argL = cc_dep1;
189          ULong argR = cc_dep2;
190          ULong oldC = cc_dep3;
191          vassert((oldC & ~1) == 0);
192          ULong res  = argL - argR - (oldC ^ 1);
193          ULong nf   = res >> 63;
194          return nf;
195       }
196       case ARM64G_CC_OP_LOGIC32: {
197          /* (res, unused, unused) */
198          UInt  res = (UInt)cc_dep1;
199          ULong nf  = res >> 31;
200          return nf;
201       }
202       case ARM64G_CC_OP_LOGIC64: {
203          /* (res, unused, unused) */
204          ULong res = cc_dep1;
205          ULong nf  = res >> 63;
206          return nf;
207       }
208 //ZZ       case ARMG_CC_OP_MUL: {
209 //ZZ          /* (res, unused, oldC:oldV) */
210 //ZZ          UInt res  = cc_dep1;
211 //ZZ          UInt nf   = res >> 31;
212 //ZZ          return nf;
213 //ZZ       }
214 //ZZ       case ARMG_CC_OP_MULL: {
215 //ZZ          /* (resLo32, resHi32, oldC:oldV) */
216 //ZZ          UInt resHi32 = cc_dep2;
217 //ZZ          UInt nf      = resHi32 >> 31;
218 //ZZ          return nf;
219 //ZZ       }
220       default:
221          /* shouldn't really make these calls from generated code */
222          vex_printf("arm64g_calculate_flag_n"
223                     "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
224                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
225          vpanic("arm64g_calculate_flag_n");
226    }
227 }
228 
229 
230 /* Calculate the Z flag from the supplied thunk components, in the
231    least significant bit of the word.  Returned bits 63:1 are zero. */
232 static
arm64g_calculate_flag_z(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)233 ULong arm64g_calculate_flag_z ( ULong cc_op, ULong cc_dep1,
234                                 ULong cc_dep2, ULong cc_dep3 )
235 {
236    switch (cc_op) {
237       case ARM64G_CC_OP_COPY: {
238          /* (nzcv:28x0, unused, unused) */
239          ULong zf   = (cc_dep1 >> ARM64G_CC_SHIFT_Z) & 1;
240          return zf;
241       }
242       case ARM64G_CC_OP_ADD32: {
243          /* (argL, argR, unused) */
244          UInt  argL = (UInt)cc_dep1;
245          UInt  argR = (UInt)cc_dep2;
246          UInt  res  = argL + argR;
247          ULong zf   = res == 0;
248          return zf;
249       }
250       case ARM64G_CC_OP_ADD64: {
251          /* (argL, argR, unused) */
252          ULong argL = cc_dep1;
253          ULong argR = cc_dep2;
254          ULong res  = argL + argR;
255          ULong zf   = res == 0;
256          return zf;
257       }
258       case ARM64G_CC_OP_SUB32: {
259          /* (argL, argR, unused) */
260          UInt  argL = (UInt)cc_dep1;
261          UInt  argR = (UInt)cc_dep2;
262          UInt  res  = argL - argR;
263          ULong zf   = res == 0;
264          return zf;
265       }
266       case ARM64G_CC_OP_SUB64: {
267          /* (argL, argR, unused) */
268          ULong argL = cc_dep1;
269          ULong argR = cc_dep2;
270          ULong res  = argL - argR;
271          ULong zf   = res == 0;
272          return zf;
273       }
274       case ARM64G_CC_OP_ADC32: {
275          /* (argL, argR, oldC) */
276          UInt  argL = cc_dep1;
277          UInt  argR = cc_dep2;
278          UInt  oldC = cc_dep3;
279          vassert((oldC & ~1) == 0);
280          UInt  res  = argL + argR + oldC;
281          ULong zf   = res == 0;
282          return zf;
283       }
284       case ARM64G_CC_OP_ADC64: {
285          /* (argL, argR, oldC) */
286          ULong argL = cc_dep1;
287          ULong argR = cc_dep2;
288          ULong oldC = cc_dep3;
289          vassert((oldC & ~1) == 0);
290          ULong res  = argL + argR + oldC;
291          ULong zf   = res == 0;
292          return zf;
293       }
294       case ARM64G_CC_OP_SBC32: {
295          /* (argL, argR, oldC) */
296          UInt  argL = cc_dep1;
297          UInt  argR = cc_dep2;
298          UInt  oldC = cc_dep3;
299          vassert((oldC & ~1) == 0);
300          UInt  res  = argL - argR - (oldC ^ 1);
301          ULong zf   = res == 0;
302          return zf;
303       }
304       case ARM64G_CC_OP_SBC64: {
305          /* (argL, argR, oldC) */
306          ULong argL = cc_dep1;
307          ULong argR = cc_dep2;
308          ULong oldC = cc_dep3;
309          vassert((oldC & ~1) == 0);
310          ULong res  = argL - argR - (oldC ^ 1);
311          ULong zf   = res == 0;
312          return zf;
313       }
314       case ARM64G_CC_OP_LOGIC32: {
315          /* (res, unused, unused) */
316          UInt  res  = (UInt)cc_dep1;
317          ULong zf   = res == 0;
318          return zf;
319       }
320       case ARM64G_CC_OP_LOGIC64: {
321          /* (res, unused, unused) */
322          ULong res  = cc_dep1;
323          ULong zf   = res == 0;
324          return zf;
325       }
326 //ZZ       case ARMG_CC_OP_MUL: {
327 //ZZ          /* (res, unused, oldC:oldV) */
328 //ZZ          UInt res  = cc_dep1;
329 //ZZ          UInt zf   = res == 0;
330 //ZZ          return zf;
331 //ZZ       }
332 //ZZ       case ARMG_CC_OP_MULL: {
333 //ZZ          /* (resLo32, resHi32, oldC:oldV) */
334 //ZZ          UInt resLo32 = cc_dep1;
335 //ZZ          UInt resHi32 = cc_dep2;
336 //ZZ          UInt zf      = (resHi32|resLo32) == 0;
337 //ZZ          return zf;
338 //ZZ       }
339       default:
340          /* shouldn't really make these calls from generated code */
341          vex_printf("arm64g_calculate_flag_z"
342                     "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
343                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
344          vpanic("arm64g_calculate_flag_z");
345    }
346 }
347 
348 
349 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
350 /* Calculate the C flag from the supplied thunk components, in the
351    least significant bit of the word.  Returned bits 63:1 are zero. */
arm64g_calculate_flag_c(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)352 ULong arm64g_calculate_flag_c ( ULong cc_op, ULong cc_dep1,
353                                 ULong cc_dep2, ULong cc_dep3 )
354 {
355    switch (cc_op) {
356       case ARM64G_CC_OP_COPY: {
357          /* (nzcv:28x0, unused, unused) */
358          ULong cf = (cc_dep1 >> ARM64G_CC_SHIFT_C) & 1;
359          return cf;
360       }
361       case ARM64G_CC_OP_ADD32: {
362          /* (argL, argR, unused) */
363          UInt  argL = (UInt)cc_dep1;
364          UInt  argR = (UInt)cc_dep2;
365          UInt  res  = argL + argR;
366          ULong cf   = res < argL;
367          return cf;
368       }
369       case ARM64G_CC_OP_ADD64: {
370          /* (argL, argR, unused) */
371          ULong argL = cc_dep1;
372          ULong argR = cc_dep2;
373          ULong res  = argL + argR;
374          ULong cf   = res < argL;
375          return cf;
376       }
377       case ARM64G_CC_OP_SUB32: {
378          /* (argL, argR, unused) */
379          UInt  argL = (UInt)cc_dep1;
380          UInt  argR = (UInt)cc_dep2;
381          ULong cf   = argL >= argR;
382          return cf;
383       }
384       case ARM64G_CC_OP_SUB64: {
385          /* (argL, argR, unused) */
386          ULong argL = cc_dep1;
387          ULong argR = cc_dep2;
388          ULong cf   = argL >= argR;
389          return cf;
390       }
391       case ARM64G_CC_OP_ADC32: {
392          /* (argL, argR, oldC) */
393          UInt  argL = cc_dep1;
394          UInt  argR = cc_dep2;
395          UInt  oldC = cc_dep3;
396          vassert((oldC & ~1) == 0);
397          UInt  res  = argL + argR + oldC;
398          ULong cf   = oldC ? (res <= argL) : (res < argL);
399          return cf;
400       }
401       case ARM64G_CC_OP_ADC64: {
402          /* (argL, argR, oldC) */
403          ULong argL = cc_dep1;
404          ULong argR = cc_dep2;
405          ULong oldC = cc_dep3;
406          vassert((oldC & ~1) == 0);
407          ULong res  = argL + argR + oldC;
408          ULong cf   = oldC ? (res <= argL) : (res < argL);
409          return cf;
410       }
411       case ARM64G_CC_OP_SBC32: {
412          /* (argL, argR, oldC) */
413          UInt  argL = cc_dep1;
414          UInt  argR = cc_dep2;
415          UInt  oldC = cc_dep3;
416          vassert((oldC & ~1) == 0);
417          ULong cf   = oldC ? (argL >= argR) : (argL > argR);
418          return cf;
419       }
420       case ARM64G_CC_OP_SBC64: {
421          /* (argL, argR, oldC) */
422          ULong argL = cc_dep1;
423          ULong argR = cc_dep2;
424          ULong oldC = cc_dep3;
425          vassert((oldC & ~1) == 0);
426          ULong cf   = oldC ? (argL >= argR) : (argL > argR);
427          return cf;
428       }
429       case ARM64G_CC_OP_LOGIC32:
430       case ARM64G_CC_OP_LOGIC64: {
431          /* (res, unused, unused) */
432          return 0; // C after logic is zero on arm64
433       }
434 //ZZ       case ARMG_CC_OP_MUL: {
435 //ZZ          /* (res, unused, oldC:oldV) */
436 //ZZ          UInt oldC = (cc_dep3 >> 1) & 1;
437 //ZZ          vassert((cc_dep3 & ~3) == 0);
438 //ZZ          UInt cf   = oldC;
439 //ZZ          return cf;
440 //ZZ       }
441 //ZZ       case ARMG_CC_OP_MULL: {
442 //ZZ          /* (resLo32, resHi32, oldC:oldV) */
443 //ZZ          UInt oldC    = (cc_dep3 >> 1) & 1;
444 //ZZ          vassert((cc_dep3 & ~3) == 0);
445 //ZZ          UInt cf      = oldC;
446 //ZZ          return cf;
447 //ZZ       }
448       default:
449          /* shouldn't really make these calls from generated code */
450          vex_printf("arm64g_calculate_flag_c"
451                     "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
452                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
453          vpanic("arm64g_calculate_flag_c");
454    }
455 }
456 
457 
458 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
459 /* Calculate the V flag from the supplied thunk components, in the
460    least significant bit of the word.  Returned bits 63:1 are zero. */
461 static
arm64g_calculate_flag_v(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)462 ULong arm64g_calculate_flag_v ( ULong cc_op, ULong cc_dep1,
463                                 ULong cc_dep2, ULong cc_dep3 )
464 {
465    switch (cc_op) {
466       case ARM64G_CC_OP_COPY: {
467          /* (nzcv:28x0, unused, unused) */
468          ULong vf   = (cc_dep1 >> ARM64G_CC_SHIFT_V) & 1;
469          return vf;
470       }
471       case ARM64G_CC_OP_ADD32: {
472          /* (argL, argR, unused) */
473          UInt  argL = (UInt)cc_dep1;
474          UInt  argR = (UInt)cc_dep2;
475          UInt  res  = argL + argR;
476          ULong vf   = (ULong)(((res ^ argL) & (res ^ argR)) >> 31);
477          return vf;
478       }
479       case ARM64G_CC_OP_ADD64: {
480          /* (argL, argR, unused) */
481          ULong argL = cc_dep1;
482          ULong argR = cc_dep2;
483          ULong res  = argL + argR;
484          ULong vf   = ((res ^ argL) & (res ^ argR)) >> 63;
485          return vf;
486       }
487       case ARM64G_CC_OP_SUB32: {
488          /* (argL, argR, unused) */
489          UInt  argL = (UInt)cc_dep1;
490          UInt  argR = (UInt)cc_dep2;
491          UInt  res  = argL - argR;
492          ULong vf   = (ULong)(((argL ^ argR) & (argL ^ res)) >> 31);
493          return vf;
494       }
495       case ARM64G_CC_OP_SUB64: {
496          /* (argL, argR, unused) */
497          ULong argL = cc_dep1;
498          ULong argR = cc_dep2;
499          ULong res  = argL - argR;
500          ULong vf   = (((argL ^ argR) & (argL ^ res))) >> 63;
501          return vf;
502       }
503       case ARM64G_CC_OP_ADC32: {
504          /* (argL, argR, oldC) */
505          UInt  argL = cc_dep1;
506          UInt  argR = cc_dep2;
507          UInt  oldC = cc_dep3;
508          vassert((oldC & ~1) == 0);
509          UInt  res  = argL + argR + oldC;
510          ULong vf   = (ULong)(((res ^ argL) & (res ^ argR)) >> 31);
511          return vf;
512       }
513       case ARM64G_CC_OP_ADC64: {
514          /* (argL, argR, oldC) */
515          ULong argL = cc_dep1;
516          ULong argR = cc_dep2;
517          ULong oldC = cc_dep3;
518          vassert((oldC & ~1) == 0);
519          ULong res  = argL + argR + oldC;
520          ULong vf   = ((res ^ argL) & (res ^ argR)) >> 63;
521          return vf;
522       }
523       case ARM64G_CC_OP_SBC32: {
524          /* (argL, argR, oldC) */
525          UInt  argL = cc_dep1;
526          UInt  argR = cc_dep2;
527          UInt  oldC = cc_dep3;
528          vassert((oldC & ~1) == 0);
529          UInt  res  = argL - argR - (oldC ^ 1);
530          ULong vf   = (ULong)(((argL ^ argR) & (argL ^ res)) >> 31);
531          return vf;
532       }
533       case ARM64G_CC_OP_SBC64: {
534          /* (argL, argR, oldC) */
535          ULong argL = cc_dep1;
536          ULong argR = cc_dep2;
537          ULong oldC = cc_dep3;
538          vassert((oldC & ~1) == 0);
539          ULong res  = argL - argR - (oldC ^ 1);
540          ULong vf   = ((argL ^ argR) & (argL ^ res)) >> 63;
541          return vf;
542       }
543       case ARM64G_CC_OP_LOGIC32:
544       case ARM64G_CC_OP_LOGIC64: {
545          /* (res, unused, unused) */
546          return 0; // V after logic is zero on arm64
547       }
548 //ZZ       case ARMG_CC_OP_MUL: {
549 //ZZ          /* (res, unused, oldC:oldV) */
550 //ZZ          UInt oldV = (cc_dep3 >> 0) & 1;
551 //ZZ          vassert((cc_dep3 & ~3) == 0);
552 //ZZ          UInt vf   = oldV;
553 //ZZ          return vf;
554 //ZZ       }
555 //ZZ       case ARMG_CC_OP_MULL: {
556 //ZZ          /* (resLo32, resHi32, oldC:oldV) */
557 //ZZ          UInt oldV    = (cc_dep3 >> 0) & 1;
558 //ZZ          vassert((cc_dep3 & ~3) == 0);
559 //ZZ          UInt vf      = oldV;
560 //ZZ          return vf;
561 //ZZ       }
562       default:
563          /* shouldn't really make these calls from generated code */
564          vex_printf("arm64g_calculate_flag_v"
565                     "( op=%llu, dep1=0x%llx, dep2=0x%llx, dep3=0x%llx )\n",
566                     cc_op, cc_dep1, cc_dep2, cc_dep3 );
567          vpanic("arm64g_calculate_flag_v");
568    }
569 }
570 
571 
572 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
573 /* Calculate NZCV from the supplied thunk components, in the positions
574    they appear in the CPSR, viz bits 31:28 for N Z C V respectively.
575    Returned bits 27:0 are zero. */
arm64g_calculate_flags_nzcv(ULong cc_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)576 ULong arm64g_calculate_flags_nzcv ( ULong cc_op, ULong cc_dep1,
577                                     ULong cc_dep2, ULong cc_dep3 )
578 {
579    ULong f;
580    ULong res = 0;
581    f = 1 & arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
582    res |= (f << ARM64G_CC_SHIFT_N);
583    f = 1 & arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
584    res |= (f << ARM64G_CC_SHIFT_Z);
585    f = 1 & arm64g_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
586    res |= (f << ARM64G_CC_SHIFT_C);
587    f = 1 & arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
588    res |= (f << ARM64G_CC_SHIFT_V);
589    return res;
590 }
591 
592 //ZZ
593 //ZZ /* CALLED FROM GENERATED CODE: CLEAN HELPER */
594 //ZZ /* Calculate the QC flag from the arguments, in the lowest bit
595 //ZZ    of the word (bit 0).  Urr, having this out of line is bizarre.
596 //ZZ    Push back inline. */
597 //ZZ UInt armg_calculate_flag_qc ( UInt resL1, UInt resL2,
598 //ZZ                               UInt resR1, UInt resR2 )
599 //ZZ {
600 //ZZ    if (resL1 != resR1 || resL2 != resR2)
601 //ZZ       return 1;
602 //ZZ    else
603 //ZZ       return 0;
604 //ZZ }
605 
606 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
607 /* Calculate the specified condition from the thunk components, in the
608    lowest bit of the word (bit 0).  Returned bits 63:1 are zero. */
arm64g_calculate_condition(ULong cond_n_op,ULong cc_dep1,ULong cc_dep2,ULong cc_dep3)609 ULong arm64g_calculate_condition ( /* ARM64Condcode << 4 | cc_op */
610                                    ULong cond_n_op ,
611                                    ULong cc_dep1,
612                                    ULong cc_dep2, ULong cc_dep3 )
613 {
614    ULong cond  = cond_n_op >> 4;
615    ULong cc_op = cond_n_op & 0xF;
616    ULong inv   = cond & 1;
617    ULong nf, zf, vf, cf;
618 
619 #  if PROFILE_NZCV_FLAGS
620    NOTE_EVAL(cc_op, cond);
621 #  endif
622 
623    //   vex_printf("XXXXXXXX %llx %llx %llx %llx\n",
624    //              cond_n_op, cc_dep1, cc_dep2, cc_dep3);
625 
626    switch (cond) {
627       case ARM64CondEQ:    // Z=1         => z
628       case ARM64CondNE:    // Z=0
629          zf = arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
630          return inv ^ zf;
631 
632       case ARM64CondCS:    // C=1         => c
633       case ARM64CondCC:    // C=0
634          cf = arm64g_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
635          return inv ^ cf;
636 
637       case ARM64CondMI:    // N=1         => n
638       case ARM64CondPL:    // N=0
639          nf = arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
640          return inv ^ nf;
641 
642       case ARM64CondVS:    // V=1         => v
643       case ARM64CondVC:    // V=0
644          vf = arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
645          return inv ^ vf;
646 
647       case ARM64CondHI:    // C=1 && Z=0   => c & ~z
648       case ARM64CondLS:    // C=0 || Z=1
649          cf = arm64g_calculate_flag_c(cc_op, cc_dep1, cc_dep2, cc_dep3);
650          zf = arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
651          return inv ^ (1 & (cf & ~zf));
652 
653       case ARM64CondGE:    // N=V          => ~(n^v)
654       case ARM64CondLT:    // N!=V
655          nf = arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
656          vf = arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
657          return inv ^ (1 & ~(nf ^ vf));
658 
659       case ARM64CondGT:    // Z=0 && N=V   => ~z & ~(n^v)  =>  ~(z | (n^v))
660       case ARM64CondLE:    // Z=1 || N!=V
661          nf = arm64g_calculate_flag_n(cc_op, cc_dep1, cc_dep2, cc_dep3);
662          vf = arm64g_calculate_flag_v(cc_op, cc_dep1, cc_dep2, cc_dep3);
663          zf = arm64g_calculate_flag_z(cc_op, cc_dep1, cc_dep2, cc_dep3);
664          return inv ^ (1 & ~(zf | (nf ^ vf)));
665 
666       case ARM64CondAL:    // 1
667       case ARM64CondNV:    // 1
668          return 1;
669 
670       default:
671          /* shouldn't really make these calls from generated code */
672          vex_printf("arm64g_calculate_condition(ARM64)"
673                     "( %llu, %llu, 0x%llx, 0x%llx, 0x%llx )\n",
674                     cond, cc_op, cc_dep1, cc_dep2, cc_dep3 );
675          vpanic("armg_calculate_condition(ARM64)");
676    }
677 }
678 
679 
680 /* CALLED FROM GENERATED CODE */
681 /* DIRTY HELPER (non-referentially-transparent) */
682 /* Horrible hack.  On non-arm64 platforms, return 0. */
arm64g_dirtyhelper_MRS_CNTVCT_EL0(void)683 ULong arm64g_dirtyhelper_MRS_CNTVCT_EL0 ( void )
684 {
685 #  if defined(__aarch64__) && !defined(__arm__)
686    ULong w = 0x5555555555555555ULL; /* overwritten */
687    __asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(w));
688    return w;
689 #  else
690    return 0ULL;
691 #  endif
692 }
693 
694 
695 /*---------------------------------------------------------------*/
696 /*--- Flag-helpers translation-time function specialisers.    ---*/
697 /*--- These help iropt specialise calls the above run-time    ---*/
698 /*--- flags functions.                                        ---*/
699 /*---------------------------------------------------------------*/
700 
701 /* Used by the optimiser to try specialisations.  Returns an
702    equivalent expression, or NULL if none. */
703 
isU64(IRExpr * e,ULong n)704 static Bool isU64 ( IRExpr* e, ULong n )
705 {
706    return
707       toBool( e->tag == Iex_Const
708               && e->Iex.Const.con->tag == Ico_U64
709               && e->Iex.Const.con->Ico.U64 == n );
710 }
711 
guest_arm64_spechelper(const HChar * function_name,IRExpr ** args,IRStmt ** precedingStmts,Int n_precedingStmts)712 IRExpr* guest_arm64_spechelper ( const HChar* function_name,
713                                  IRExpr** args,
714                                  IRStmt** precedingStmts,
715                                  Int      n_precedingStmts )
716 {
717 #  define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
718 #  define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
719 #  define mkU64(_n) IRExpr_Const(IRConst_U64(_n))
720 #  define mkU8(_n)  IRExpr_Const(IRConst_U8(_n))
721 
722    Int i, arity = 0;
723    for (i = 0; args[i]; i++)
724       arity++;
725 //ZZ #  if 0
726 //ZZ    vex_printf("spec request:\n");
727 //ZZ    vex_printf("   %s  ", function_name);
728 //ZZ    for (i = 0; i < arity; i++) {
729 //ZZ       vex_printf("  ");
730 //ZZ       ppIRExpr(args[i]);
731 //ZZ    }
732 //ZZ    vex_printf("\n");
733 //ZZ #  endif
734 
735    /* --------- specialising "arm64g_calculate_condition" --------- */
736 
737    if (vex_streq(function_name, "arm64g_calculate_condition")) {
738 
739       /* specialise calls to the "arm64g_calculate_condition" function.
740          Not sure whether this is strictly necessary, but: the
741          replacement IR must produce only the values 0 or 1.  Bits
742          63:1 are required to be zero. */
743       IRExpr *cond_n_op, *cc_dep1, *cc_dep2  ; //, *cc_ndep;
744       vassert(arity == 4);
745       cond_n_op = args[0]; /* (ARM64Condcode << 4)  |  ARM64G_CC_OP_* */
746       cc_dep1   = args[1];
747       cc_dep2   = args[2];
748       //cc_ndep   = args[3];
749 
750       /*---------------- SUB64 ----------------*/
751 
752       /* 0, 1 */
753       if (isU64(cond_n_op, (ARM64CondEQ << 4) | ARM64G_CC_OP_SUB64)) {
754          /* EQ after SUB --> test argL == argR */
755          return unop(Iop_1Uto64,
756                      binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
757       }
758       if (isU64(cond_n_op, (ARM64CondNE << 4) | ARM64G_CC_OP_SUB64)) {
759          /* NE after SUB --> test argL != argR */
760          return unop(Iop_1Uto64,
761                      binop(Iop_CmpNE64, cc_dep1, cc_dep2));
762       }
763 
764       /* 2, 3 */
765       if (isU64(cond_n_op, (ARM64CondCS << 4) | ARM64G_CC_OP_SUB64)) {
766          /* CS after SUB --> test argL >=u argR
767                          --> test argR <=u argL */
768          return unop(Iop_1Uto64,
769                      binop(Iop_CmpLE64U, cc_dep2, cc_dep1));
770       }
771       if (isU64(cond_n_op, (ARM64CondCC << 4) | ARM64G_CC_OP_SUB64)) {
772          /* CC after SUB --> test argL <u argR */
773          return unop(Iop_1Uto64,
774                      binop(Iop_CmpLT64U, cc_dep1, cc_dep2));
775       }
776 
777       /* 8, 9 */
778       if (isU64(cond_n_op, (ARM64CondLS << 4) | ARM64G_CC_OP_SUB64)) {
779          /* LS after SUB --> test argL <=u argR */
780          return unop(Iop_1Uto64,
781                      binop(Iop_CmpLE64U, cc_dep1, cc_dep2));
782       }
783       if (isU64(cond_n_op, (ARM64CondHI << 4) | ARM64G_CC_OP_SUB64)) {
784          /* HI after SUB --> test argL >u argR
785                          --> test argR <u argL */
786          return unop(Iop_1Uto64,
787                      binop(Iop_CmpLT64U, cc_dep2, cc_dep1));
788       }
789 
790       /* 10, 11 */
791       if (isU64(cond_n_op, (ARM64CondLT << 4) | ARM64G_CC_OP_SUB64)) {
792          /* LT after SUB --> test argL <s argR */
793          return unop(Iop_1Uto64,
794                      binop(Iop_CmpLT64S, cc_dep1, cc_dep2));
795       }
796       if (isU64(cond_n_op, (ARM64CondGE << 4) | ARM64G_CC_OP_SUB64)) {
797          /* GE after SUB --> test argL >=s argR
798                          --> test argR <=s argL */
799          return unop(Iop_1Uto64,
800                      binop(Iop_CmpLE64S, cc_dep2, cc_dep1));
801       }
802 
803       /* 12, 13 */
804       if (isU64(cond_n_op, (ARM64CondGT << 4) | ARM64G_CC_OP_SUB64)) {
805          /* GT after SUB --> test argL >s argR
806                          --> test argR <s argL */
807          return unop(Iop_1Uto64,
808                      binop(Iop_CmpLT64S, cc_dep2, cc_dep1));
809       }
810       if (isU64(cond_n_op, (ARM64CondLE << 4) | ARM64G_CC_OP_SUB64)) {
811          /* LE after SUB --> test argL <=s argR */
812          return unop(Iop_1Uto64,
813                      binop(Iop_CmpLE64S, cc_dep1, cc_dep2));
814       }
815 
816       /*---------------- SUB32 ----------------*/
817 
818       /* 0, 1 */
819       if (isU64(cond_n_op, (ARM64CondEQ << 4) | ARM64G_CC_OP_SUB32)) {
820          /* EQ after SUB --> test argL == argR */
821          return unop(Iop_1Uto64,
822                      binop(Iop_CmpEQ32, unop(Iop_64to32, cc_dep1),
823                                         unop(Iop_64to32, cc_dep2)));
824       }
825       if (isU64(cond_n_op, (ARM64CondNE << 4) | ARM64G_CC_OP_SUB32)) {
826          /* NE after SUB --> test argL != argR */
827          return unop(Iop_1Uto64,
828                      binop(Iop_CmpNE32, unop(Iop_64to32, cc_dep1),
829                                         unop(Iop_64to32, cc_dep2)));
830       }
831 
832       /* 2, 3 */
833       if (isU64(cond_n_op, (ARM64CondCS << 4) | ARM64G_CC_OP_SUB32)) {
834          /* CS after SUB --> test argL >=u argR
835                          --> test argR <=u argL */
836          return unop(Iop_1Uto64,
837                      binop(Iop_CmpLE32U, unop(Iop_64to32, cc_dep2),
838                                          unop(Iop_64to32, cc_dep1)));
839       }
840       if (isU64(cond_n_op, (ARM64CondCC << 4) | ARM64G_CC_OP_SUB32)) {
841          /* CC after SUB --> test argL <u argR */
842          return unop(Iop_1Uto64,
843                      binop(Iop_CmpLT32U, unop(Iop_64to32, cc_dep1),
844                                          unop(Iop_64to32, cc_dep2)));
845       }
846 
847       /* 8, 9 */
848       if (isU64(cond_n_op, (ARM64CondLS << 4) | ARM64G_CC_OP_SUB32)) {
849          /* LS after SUB --> test argL <=u argR */
850          return unop(Iop_1Uto64,
851                      binop(Iop_CmpLE32U, unop(Iop_64to32, cc_dep1),
852                                          unop(Iop_64to32, cc_dep2)));
853       }
854       if (isU64(cond_n_op, (ARM64CondHI << 4) | ARM64G_CC_OP_SUB32)) {
855          /* HI after SUB --> test argL >u argR
856                          --> test argR <u argL */
857          return unop(Iop_1Uto64,
858                      binop(Iop_CmpLT32U, unop(Iop_64to32, cc_dep2),
859                                          unop(Iop_64to32, cc_dep1)));
860       }
861 
862       /* 10, 11 */
863       if (isU64(cond_n_op, (ARM64CondLT << 4) | ARM64G_CC_OP_SUB32)) {
864          /* LT after SUB --> test argL <s argR */
865          return unop(Iop_1Uto64,
866                      binop(Iop_CmpLT32S, unop(Iop_64to32, cc_dep1),
867                                          unop(Iop_64to32, cc_dep2)));
868       }
869       if (isU64(cond_n_op, (ARM64CondGE << 4) | ARM64G_CC_OP_SUB32)) {
870          /* GE after SUB --> test argL >=s argR
871                          --> test argR <=s argL */
872          return unop(Iop_1Uto64,
873                      binop(Iop_CmpLE32S, unop(Iop_64to32, cc_dep2),
874                                          unop(Iop_64to32, cc_dep1)));
875       }
876 
877       /* 12, 13 */
878       if (isU64(cond_n_op, (ARM64CondGT << 4) | ARM64G_CC_OP_SUB32)) {
879          /* GT after SUB --> test argL >s argR
880                          --> test argR <s argL */
881          return unop(Iop_1Uto64,
882                      binop(Iop_CmpLT32S, unop(Iop_64to32, cc_dep2),
883                                          unop(Iop_64to32, cc_dep1)));
884       }
885       if (isU64(cond_n_op, (ARM64CondLE << 4) | ARM64G_CC_OP_SUB32)) {
886          /* LE after SUB --> test argL <=s argR */
887          return unop(Iop_1Uto64,
888                      binop(Iop_CmpLE32S, unop(Iop_64to32, cc_dep1),
889                                          unop(Iop_64to32, cc_dep2)));
890       }
891 
892 //ZZ       /*---------------- SBB ----------------*/
893 //ZZ
894 //ZZ       if (isU32(cond_n_op, (ARMCondHS << 4) | ARMG_CC_OP_SBB)) {
895 //ZZ          /* This seems to happen a lot in softfloat code, eg __divdf3+140 */
896 //ZZ          /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
897 //ZZ          /* HS after SBB (same as C after SBB below)
898 //ZZ             --> oldC ? (argL >=u argR) : (argL >u argR)
899 //ZZ             --> oldC ? (argR <=u argL) : (argR <u argL)
900 //ZZ          */
901 //ZZ          return
902 //ZZ             IRExpr_ITE(
903 //ZZ                binop(Iop_CmpNE32, cc_ndep, mkU32(0)),
904 //ZZ                /* case oldC != 0 */
905 //ZZ                unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1)),
906 //ZZ                /* case oldC == 0 */
907 //ZZ                unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1))
908 //ZZ             );
909 //ZZ       }
910 //ZZ
911 //ZZ       /*---------------- LOGIC ----------------*/
912 //ZZ
913 //ZZ       if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_LOGIC)) {
914 //ZZ          /* EQ after LOGIC --> test res == 0 */
915 //ZZ          return unop(Iop_1Uto32,
916 //ZZ                      binop(Iop_CmpEQ32, cc_dep1, mkU32(0)));
917 //ZZ       }
918 //ZZ       if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_LOGIC)) {
919 //ZZ          /* NE after LOGIC --> test res != 0 */
920 //ZZ          return unop(Iop_1Uto32,
921 //ZZ                      binop(Iop_CmpNE32, cc_dep1, mkU32(0)));
922 //ZZ       }
923 //ZZ
924 //ZZ       if (isU32(cond_n_op, (ARMCondPL << 4) | ARMG_CC_OP_LOGIC)) {
925 //ZZ          /* PL after LOGIC --> test (res >> 31) == 0 */
926 //ZZ          return unop(Iop_1Uto32,
927 //ZZ                      binop(Iop_CmpEQ32,
928 //ZZ                            binop(Iop_Shr32, cc_dep1, mkU8(31)),
929 //ZZ                            mkU32(0)));
930 //ZZ       }
931 //ZZ       if (isU32(cond_n_op, (ARMCondMI << 4) | ARMG_CC_OP_LOGIC)) {
932 //ZZ          /* MI after LOGIC --> test (res >> 31) == 1 */
933 //ZZ          return unop(Iop_1Uto32,
934 //ZZ                      binop(Iop_CmpEQ32,
935 //ZZ                            binop(Iop_Shr32, cc_dep1, mkU8(31)),
936 //ZZ                            mkU32(1)));
937 //ZZ       }
938 
939       /*---------------- COPY ----------------*/
940 
941       if (isU64(cond_n_op, (ARM64CondEQ << 4) | ARM64G_CC_OP_COPY)) {
942          /* EQ after COPY --> (cc_dep1 >> ARM64G_CC_SHIFT_Z) & 1 */
943          return binop(Iop_And64,
944                       binop(Iop_Shr64, cc_dep1,
945                                        mkU8(ARM64G_CC_SHIFT_Z)),
946                       mkU64(1));
947       }
948       if (isU64(cond_n_op, (ARM64CondNE << 4) | ARM64G_CC_OP_COPY)) {
949          /* NE after COPY --> ((cc_dep1 >> ARM64G_CC_SHIFT_Z) ^ 1) & 1 */
950          return binop(Iop_And64,
951                       binop(Iop_Xor64,
952                             binop(Iop_Shr64, cc_dep1,
953                                              mkU8(ARM64G_CC_SHIFT_Z)),
954                             mkU64(1)),
955                       mkU64(1));
956       }
957 
958 //ZZ       /*----------------- AL -----------------*/
959 //ZZ
960 //ZZ       /* A critically important case for Thumb code.
961 //ZZ
962 //ZZ          What we're trying to spot is the case where cond_n_op is an
963 //ZZ          expression of the form Or32(..., 0xE0) since that means the
964 //ZZ          caller is asking for CondAL and we can simply return 1
965 //ZZ          without caring what the ... part is.  This is a potentially
966 //ZZ          dodgy kludge in that it assumes that the ... part has zeroes
967 //ZZ          in bits 7:4, so that the result of the Or32 is guaranteed to
968 //ZZ          be 0xE in bits 7:4.  Given that the places where this first
969 //ZZ          arg are constructed (in guest_arm_toIR.c) are very
970 //ZZ          constrained, we can get away with this.  To make this
971 //ZZ          guaranteed safe would require to have a new primop, Slice44
972 //ZZ          or some such, thusly
973 //ZZ
974 //ZZ          Slice44(arg1, arg2) = 0--(24)--0 arg1[7:4] arg2[3:0]
975 //ZZ
976 //ZZ          and we would then look for Slice44(0xE0, ...)
977 //ZZ          which would give the required safety property.
978 //ZZ
979 //ZZ          It would be infeasibly expensive to scan backwards through
980 //ZZ          the entire block looking for an assignment to the temp, so
981 //ZZ          just look at the previous 16 statements.  That should find it
982 //ZZ          if it is an interesting case, as a result of how the
983 //ZZ          boilerplate guff at the start of each Thumb insn translation
984 //ZZ          is made.
985 //ZZ       */
986 //ZZ       if (cond_n_op->tag == Iex_RdTmp) {
987 //ZZ          Int    j;
988 //ZZ          IRTemp look_for = cond_n_op->Iex.RdTmp.tmp;
989 //ZZ          Int    limit    = n_precedingStmts - 16;
990 //ZZ          if (limit < 0) limit = 0;
991 //ZZ          if (0) vex_printf("scanning %d .. %d\n", n_precedingStmts-1, limit);
992 //ZZ          for (j = n_precedingStmts - 1; j >= limit; j--) {
993 //ZZ             IRStmt* st = precedingStmts[j];
994 //ZZ             if (st->tag == Ist_WrTmp
995 //ZZ                 && st->Ist.WrTmp.tmp == look_for
996 //ZZ                 && st->Ist.WrTmp.data->tag == Iex_Binop
997 //ZZ                 && st->Ist.WrTmp.data->Iex.Binop.op == Iop_Or32
998 //ZZ                 && isU32(st->Ist.WrTmp.data->Iex.Binop.arg2, (ARMCondAL << 4)))
999 //ZZ                return mkU32(1);
1000 //ZZ          }
1001 //ZZ          /* Didn't find any useful binding to the first arg
1002 //ZZ             in the previous 16 stmts. */
1003 //ZZ       }
1004    }
1005 
1006 //ZZ    /* --------- specialising "armg_calculate_flag_c" --------- */
1007 //ZZ
1008 //ZZ    else
1009 //ZZ    if (vex_streq(function_name, "armg_calculate_flag_c")) {
1010 //ZZ
1011 //ZZ       /* specialise calls to the "armg_calculate_flag_c" function.
1012 //ZZ          Note that the returned value must be either 0 or 1; nonzero
1013 //ZZ          bits 31:1 are not allowed.  In turn, incoming oldV and oldC
1014 //ZZ          values (from the thunk) are assumed to have bits 31:1
1015 //ZZ          clear. */
1016 //ZZ       IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
1017 //ZZ       vassert(arity == 4);
1018 //ZZ       cc_op   = args[0]; /* ARMG_CC_OP_* */
1019 //ZZ       cc_dep1 = args[1];
1020 //ZZ       cc_dep2 = args[2];
1021 //ZZ       cc_ndep = args[3];
1022 //ZZ
1023 //ZZ       if (isU32(cc_op, ARMG_CC_OP_LOGIC)) {
1024 //ZZ          /* Thunk args are (result, shco, oldV) */
1025 //ZZ          /* C after LOGIC --> shco */
1026 //ZZ          return cc_dep2;
1027 //ZZ       }
1028 //ZZ
1029 //ZZ       if (isU32(cc_op, ARMG_CC_OP_SUB)) {
1030 //ZZ          /* Thunk args are (argL, argR, unused) */
1031 //ZZ          /* C after SUB --> argL >=u argR
1032 //ZZ                         --> argR <=u argL */
1033 //ZZ          return unop(Iop_1Uto32,
1034 //ZZ                      binop(Iop_CmpLE32U, cc_dep2, cc_dep1));
1035 //ZZ       }
1036 //ZZ
1037 //ZZ       if (isU32(cc_op, ARMG_CC_OP_SBB)) {
1038 //ZZ          /* This happens occasionally in softfloat code, eg __divdf3+140 */
1039 //ZZ          /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
1040 //ZZ          /* C after SBB (same as HS after SBB above)
1041 //ZZ             --> oldC ? (argL >=u argR) : (argL >u argR)
1042 //ZZ             --> oldC ? (argR <=u argL) : (argR <u argL)
1043 //ZZ          */
1044 //ZZ          return
1045 //ZZ             IRExpr_ITE(
1046 //ZZ                binop(Iop_CmpNE32, cc_ndep, mkU32(0)),
1047 //ZZ                /* case oldC != 0 */
1048 //ZZ                unop(Iop_1Uto32, binop(Iop_CmpLE32U, cc_dep2, cc_dep1)),
1049 //ZZ                /* case oldC == 0 */
1050 //ZZ                unop(Iop_1Uto32, binop(Iop_CmpLT32U, cc_dep2, cc_dep1))
1051 //ZZ             );
1052 //ZZ       }
1053 //ZZ
1054 //ZZ    }
1055 //ZZ
1056 //ZZ    /* --------- specialising "armg_calculate_flag_v" --------- */
1057 //ZZ
1058 //ZZ    else
1059 //ZZ    if (vex_streq(function_name, "armg_calculate_flag_v")) {
1060 //ZZ
1061 //ZZ       /* specialise calls to the "armg_calculate_flag_v" function.
1062 //ZZ          Note that the returned value must be either 0 or 1; nonzero
1063 //ZZ          bits 31:1 are not allowed.  In turn, incoming oldV and oldC
1064 //ZZ          values (from the thunk) are assumed to have bits 31:1
1065 //ZZ          clear. */
1066 //ZZ       IRExpr *cc_op, *cc_dep1, *cc_dep2, *cc_ndep;
1067 //ZZ       vassert(arity == 4);
1068 //ZZ       cc_op   = args[0]; /* ARMG_CC_OP_* */
1069 //ZZ       cc_dep1 = args[1];
1070 //ZZ       cc_dep2 = args[2];
1071 //ZZ       cc_ndep = args[3];
1072 //ZZ
1073 //ZZ       if (isU32(cc_op, ARMG_CC_OP_LOGIC)) {
1074 //ZZ          /* Thunk args are (result, shco, oldV) */
1075 //ZZ          /* V after LOGIC --> oldV */
1076 //ZZ          return cc_ndep;
1077 //ZZ       }
1078 //ZZ
1079 //ZZ       if (isU32(cc_op, ARMG_CC_OP_SUB)) {
1080 //ZZ          /* Thunk args are (argL, argR, unused) */
1081 //ZZ          /* V after SUB
1082 //ZZ             --> let res = argL - argR
1083 //ZZ                 in ((argL ^ argR) & (argL ^ res)) >> 31
1084 //ZZ             --> ((argL ^ argR) & (argL ^ (argL - argR))) >> 31
1085 //ZZ          */
1086 //ZZ          IRExpr* argL = cc_dep1;
1087 //ZZ          IRExpr* argR = cc_dep2;
1088 //ZZ          return
1089 //ZZ             binop(Iop_Shr32,
1090 //ZZ                   binop(Iop_And32,
1091 //ZZ                         binop(Iop_Xor32, argL, argR),
1092 //ZZ                         binop(Iop_Xor32, argL, binop(Iop_Sub32, argL, argR))
1093 //ZZ                   ),
1094 //ZZ                   mkU8(31)
1095 //ZZ             );
1096 //ZZ       }
1097 //ZZ
1098 //ZZ       if (isU32(cc_op, ARMG_CC_OP_SBB)) {
1099 //ZZ          /* This happens occasionally in softfloat code, eg __divdf3+140 */
1100 //ZZ          /* thunk is: (dep1=argL, dep2=argR, ndep=oldC) */
1101 //ZZ          /* V after SBB
1102 //ZZ             --> let res = argL - argR - (oldC ^ 1)
1103 //ZZ                 in  (argL ^ argR) & (argL ^ res) & 1
1104 //ZZ          */
1105 //ZZ          return
1106 //ZZ             binop(
1107 //ZZ                Iop_And32,
1108 //ZZ                binop(
1109 //ZZ                   Iop_And32,
1110 //ZZ                   // argL ^ argR
1111 //ZZ                   binop(Iop_Xor32, cc_dep1, cc_dep2),
1112 //ZZ                   // argL ^ (argL - argR - (oldC ^ 1))
1113 //ZZ                   binop(Iop_Xor32,
1114 //ZZ                         cc_dep1,
1115 //ZZ                         binop(Iop_Sub32,
1116 //ZZ                               binop(Iop_Sub32, cc_dep1, cc_dep2),
1117 //ZZ                               binop(Iop_Xor32, cc_ndep, mkU32(1)))
1118 //ZZ                   )
1119 //ZZ                ),
1120 //ZZ                mkU32(1)
1121 //ZZ             );
1122 //ZZ       }
1123 //ZZ
1124 //ZZ    }
1125 
1126 #  undef unop
1127 #  undef binop
1128 #  undef mkU64
1129 #  undef mkU8
1130 
1131    return NULL;
1132 }
1133 
1134 
1135 /*----------------------------------------------*/
1136 /*--- The exported fns ..                    ---*/
1137 /*----------------------------------------------*/
1138 
1139 //ZZ /* VISIBLE TO LIBVEX CLIENT */
1140 //ZZ #if 0
1141 //ZZ void LibVEX_GuestARM_put_flags ( UInt flags_native,
1142 //ZZ                                  /*OUT*/VexGuestARMState* vex_state )
1143 //ZZ {
1144 //ZZ    vassert(0); // FIXME
1145 //ZZ
1146 //ZZ    /* Mask out everything except N Z V C. */
1147 //ZZ    flags_native
1148 //ZZ       &= (ARMG_CC_MASK_N | ARMG_CC_MASK_Z | ARMG_CC_MASK_V | ARMG_CC_MASK_C);
1149 //ZZ
1150 //ZZ    vex_state->guest_CC_OP   = ARMG_CC_OP_COPY;
1151 //ZZ    vex_state->guest_CC_DEP1 = flags_native;
1152 //ZZ    vex_state->guest_CC_DEP2 = 0;
1153 //ZZ    vex_state->guest_CC_NDEP = 0;
1154 //ZZ }
1155 //ZZ #endif
1156 
1157 /* VISIBLE TO LIBVEX CLIENT */
LibVEX_GuestARM64_get_nzcv(const VexGuestARM64State * vex_state)1158 ULong LibVEX_GuestARM64_get_nzcv ( /*IN*/const VexGuestARM64State* vex_state )
1159 {
1160    ULong nzcv = 0;
1161    // NZCV
1162    nzcv |= arm64g_calculate_flags_nzcv(
1163                vex_state->guest_CC_OP,
1164                vex_state->guest_CC_DEP1,
1165                vex_state->guest_CC_DEP2,
1166                vex_state->guest_CC_NDEP
1167             );
1168    vassert(0 == (nzcv & 0xFFFFFFFF0FFFFFFFULL));
1169 //ZZ    // Q
1170 //ZZ    if (vex_state->guest_QFLAG32 > 0)
1171 //ZZ       cpsr |= (1 << 27);
1172 //ZZ    // GE
1173 //ZZ    if (vex_state->guest_GEFLAG0 > 0)
1174 //ZZ       cpsr |= (1 << 16);
1175 //ZZ    if (vex_state->guest_GEFLAG1 > 0)
1176 //ZZ       cpsr |= (1 << 17);
1177 //ZZ    if (vex_state->guest_GEFLAG2 > 0)
1178 //ZZ       cpsr |= (1 << 18);
1179 //ZZ    if (vex_state->guest_GEFLAG3 > 0)
1180 //ZZ       cpsr |= (1 << 19);
1181 //ZZ    // M
1182 //ZZ    cpsr |= (1 << 4); // 0b10000 means user-mode
1183 //ZZ    // J,T   J (bit 24) is zero by initialisation above
1184 //ZZ    // T  we copy from R15T[0]
1185 //ZZ    if (vex_state->guest_R15T & 1)
1186 //ZZ       cpsr |= (1 << 5);
1187 //ZZ    // ITSTATE we punt on for the time being.  Could compute it
1188 //ZZ    // if needed though.
1189 //ZZ    // E, endianness, 0 (littleendian) from initialisation above
1190 //ZZ    // A,I,F disable some async exceptions.  Not sure about these.
1191 //ZZ    // Leave as zero for the time being.
1192    return nzcv;
1193 }
1194 
1195 /* VISIBLE TO LIBVEX CLIENT */
LibVEX_GuestARM64_get_fpsr(const VexGuestARM64State * vex_state)1196 ULong LibVEX_GuestARM64_get_fpsr ( const VexGuestARM64State* vex_state )
1197 {
1198    UInt w32 = vex_state->guest_QCFLAG[0] | vex_state->guest_QCFLAG[1]
1199               | vex_state->guest_QCFLAG[2] | vex_state->guest_QCFLAG[3];
1200    ULong fpsr = 0;
1201    // QC
1202    if (w32 != 0)
1203       fpsr |= (1 << 27);
1204    return fpsr;
1205 }
1206 
LibVEX_GuestARM64_set_fpsr(VexGuestARM64State * vex_state,ULong fpsr)1207 void LibVEX_GuestARM64_set_fpsr ( /*MOD*/VexGuestARM64State* vex_state,
1208                                   ULong fpsr )
1209 {
1210    // QC
1211    vex_state->guest_QCFLAG[0] = (UInt)((fpsr >> 27) & 1);
1212    vex_state->guest_QCFLAG[1] = 0;
1213    vex_state->guest_QCFLAG[2] = 0;
1214    vex_state->guest_QCFLAG[3] = 0;
1215 }
1216 
1217 /* VISIBLE TO LIBVEX CLIENT */
LibVEX_GuestARM64_initialise(VexGuestARM64State * vex_state)1218 void LibVEX_GuestARM64_initialise ( /*OUT*/VexGuestARM64State* vex_state )
1219 {
1220    vex_bzero(vex_state, sizeof(*vex_state));
1221 //ZZ    vex_state->host_EvC_FAILADDR = 0;
1222 //ZZ    vex_state->host_EvC_COUNTER = 0;
1223 //ZZ
1224 //ZZ    vex_state->guest_R0  = 0;
1225 //ZZ    vex_state->guest_R1  = 0;
1226 //ZZ    vex_state->guest_R2  = 0;
1227 //ZZ    vex_state->guest_R3  = 0;
1228 //ZZ    vex_state->guest_R4  = 0;
1229 //ZZ    vex_state->guest_R5  = 0;
1230 //ZZ    vex_state->guest_R6  = 0;
1231 //ZZ    vex_state->guest_R7  = 0;
1232 //ZZ    vex_state->guest_R8  = 0;
1233 //ZZ    vex_state->guest_R9  = 0;
1234 //ZZ    vex_state->guest_R10 = 0;
1235 //ZZ    vex_state->guest_R11 = 0;
1236 //ZZ    vex_state->guest_R12 = 0;
1237 //ZZ    vex_state->guest_R13 = 0;
1238 //ZZ    vex_state->guest_R14 = 0;
1239 //ZZ    vex_state->guest_R15T = 0;  /* NB: implies ARM mode */
1240 //ZZ
1241    vex_state->guest_CC_OP   = ARM64G_CC_OP_COPY;
1242 //ZZ    vex_state->guest_CC_DEP1 = 0;
1243 //ZZ    vex_state->guest_CC_DEP2 = 0;
1244 //ZZ    vex_state->guest_CC_NDEP = 0;
1245 //ZZ    vex_state->guest_QFLAG32 = 0;
1246 //ZZ    vex_state->guest_GEFLAG0 = 0;
1247 //ZZ    vex_state->guest_GEFLAG1 = 0;
1248 //ZZ    vex_state->guest_GEFLAG2 = 0;
1249 //ZZ    vex_state->guest_GEFLAG3 = 0;
1250 //ZZ
1251 //ZZ    vex_state->guest_EMNOTE  = EmNote_NONE;
1252 //ZZ    vex_state->guest_CMSTART = 0;
1253 //ZZ    vex_state->guest_CMLEN   = 0;
1254 //ZZ    vex_state->guest_NRADDR  = 0;
1255 //ZZ    vex_state->guest_IP_AT_SYSCALL = 0;
1256 //ZZ
1257 //ZZ    vex_state->guest_D0  = 0;
1258 //ZZ    vex_state->guest_D1  = 0;
1259 //ZZ    vex_state->guest_D2  = 0;
1260 //ZZ    vex_state->guest_D3  = 0;
1261 //ZZ    vex_state->guest_D4  = 0;
1262 //ZZ    vex_state->guest_D5  = 0;
1263 //ZZ    vex_state->guest_D6  = 0;
1264 //ZZ    vex_state->guest_D7  = 0;
1265 //ZZ    vex_state->guest_D8  = 0;
1266 //ZZ    vex_state->guest_D9  = 0;
1267 //ZZ    vex_state->guest_D10 = 0;
1268 //ZZ    vex_state->guest_D11 = 0;
1269 //ZZ    vex_state->guest_D12 = 0;
1270 //ZZ    vex_state->guest_D13 = 0;
1271 //ZZ    vex_state->guest_D14 = 0;
1272 //ZZ    vex_state->guest_D15 = 0;
1273 //ZZ    vex_state->guest_D16 = 0;
1274 //ZZ    vex_state->guest_D17 = 0;
1275 //ZZ    vex_state->guest_D18 = 0;
1276 //ZZ    vex_state->guest_D19 = 0;
1277 //ZZ    vex_state->guest_D20 = 0;
1278 //ZZ    vex_state->guest_D21 = 0;
1279 //ZZ    vex_state->guest_D22 = 0;
1280 //ZZ    vex_state->guest_D23 = 0;
1281 //ZZ    vex_state->guest_D24 = 0;
1282 //ZZ    vex_state->guest_D25 = 0;
1283 //ZZ    vex_state->guest_D26 = 0;
1284 //ZZ    vex_state->guest_D27 = 0;
1285 //ZZ    vex_state->guest_D28 = 0;
1286 //ZZ    vex_state->guest_D29 = 0;
1287 //ZZ    vex_state->guest_D30 = 0;
1288 //ZZ    vex_state->guest_D31 = 0;
1289 //ZZ
1290 //ZZ    /* ARM encoded; zero is the default as it happens (result flags
1291 //ZZ       (NZCV) cleared, FZ disabled, round to nearest, non-vector mode,
1292 //ZZ       all exns masked, all exn sticky bits cleared). */
1293 //ZZ    vex_state->guest_FPSCR = 0;
1294 //ZZ
1295 //ZZ    vex_state->guest_TPIDRURO = 0;
1296 //ZZ
1297 //ZZ    /* Not in a Thumb IT block. */
1298 //ZZ    vex_state->guest_ITSTATE = 0;
1299 //ZZ
1300 //ZZ    vex_state->padding1 = 0;
1301 //ZZ    vex_state->padding2 = 0;
1302 //ZZ    vex_state->padding3 = 0;
1303 //ZZ    vex_state->padding4 = 0;
1304 //ZZ    vex_state->padding5 = 0;
1305 }
1306 
1307 
1308 /*-----------------------------------------------------------*/
1309 /*--- Describing the arm guest state, for the benefit     ---*/
1310 /*--- of iropt and instrumenters.                         ---*/
1311 /*-----------------------------------------------------------*/
1312 
1313 /* Figure out if any part of the guest state contained in minoff
1314    .. maxoff requires precise memory exceptions.  If in doubt return
1315    True (but this generates significantly slower code).
1316 
1317    We enforce precise exns for guest SP, PC, 29(FP), 30(LR).
1318    That might be overkill (for 29 and 30); I don't know.
1319 */
guest_arm64_state_requires_precise_mem_exns(Int minoff,Int maxoff,VexRegisterUpdates pxControl)1320 Bool guest_arm64_state_requires_precise_mem_exns (
1321         Int minoff, Int maxoff, VexRegisterUpdates pxControl
1322      )
1323 {
1324    Int xsp_min = offsetof(VexGuestARM64State, guest_XSP);
1325    Int xsp_max = xsp_min + 8 - 1;
1326    Int pc_min  = offsetof(VexGuestARM64State, guest_PC);
1327    Int pc_max  = pc_min + 8 - 1;
1328 
1329    if (maxoff < xsp_min || minoff > xsp_max) {
1330       /* no overlap with xsp */
1331       if (pxControl == VexRegUpdSpAtMemAccess)
1332          return False; // We only need to check stack pointer.
1333    } else {
1334       return True;
1335    }
1336 
1337    if (maxoff < pc_min || minoff > pc_max) {
1338       /* no overlap with pc */
1339    } else {
1340       return True;
1341    }
1342 
1343    /* Guessing that we need PX for FP, but I don't really know. */
1344    Int x29_min = offsetof(VexGuestARM64State, guest_X29);
1345    Int x29_max = x29_min + 8 - 1;
1346 
1347    if (maxoff < x29_min || minoff > x29_max) {
1348       /* no overlap with x29 */
1349    } else {
1350       return True;
1351    }
1352 
1353    /* Guessing that we need PX for LR, but I don't really know. */
1354    Int x30_min = offsetof(VexGuestARM64State, guest_X30);
1355    Int x30_max = x30_min + 8 - 1;
1356 
1357    if (maxoff < x30_min || minoff > x30_max) {
1358       /* no overlap with r30 */
1359    } else {
1360       return True;
1361    }
1362 
1363    return False;
1364 }
1365 
1366 
1367 #define ALWAYSDEFD(field)                             \
1368     { offsetof(VexGuestARM64State, field),            \
1369       (sizeof ((VexGuestARM64State*)0)->field) }
1370 VexGuestLayout
1371    arm64Guest_layout
1372       = {
1373           /* Total size of the guest state, in bytes. */
1374           .total_sizeB = sizeof(VexGuestARM64State),
1375 
1376           /* Describe the stack pointer. */
1377           .offset_SP = offsetof(VexGuestARM64State,guest_XSP),
1378           .sizeof_SP = 8,
1379 
1380           /* Describe the instruction pointer. */
1381           .offset_IP = offsetof(VexGuestARM64State,guest_PC),
1382           .sizeof_IP = 8,
1383 
1384           /* Describe any sections to be regarded by Memcheck as
1385              'always-defined'. */
1386           .n_alwaysDefd = 9,
1387 
1388           /* flags thunk: OP is always defd, whereas DEP1 and DEP2
1389              have to be tracked.  See detailed comment in gdefs.h on
1390              meaning of thunk fields. */
1391           .alwaysDefd
1392              = { /* 0 */ ALWAYSDEFD(guest_PC),
1393                  /* 1 */ ALWAYSDEFD(guest_CC_OP),
1394                  /* 2 */ ALWAYSDEFD(guest_CC_NDEP),
1395                  /* 3 */ ALWAYSDEFD(guest_EMNOTE),
1396                  /* 4 */ ALWAYSDEFD(guest_CMSTART),
1397                  /* 5 */ ALWAYSDEFD(guest_CMLEN),
1398                  /* 6 */ ALWAYSDEFD(guest_NRADDR),
1399                  /* 7 */ ALWAYSDEFD(guest_IP_AT_SYSCALL),
1400                  /* 8 */ ALWAYSDEFD(guest_TPIDR_EL0)
1401                }
1402         };
1403 
1404 
1405 /*---------------------------------------------------------------*/
1406 /*--- end                               guest_arm64_helpers.c ---*/
1407 /*---------------------------------------------------------------*/
1408