blob: 4cccdec79f68d939516605504b85b682cb9c1cab [file] [log] [blame]
sewardj2019a972011-03-07 16:04:07 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*---------------------------------------------------------------*/
4/*--- begin guest_s390_helpers.c ---*/
5/*---------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
Elliott Hughesed398002017-06-21 14:41:24 -070011 Copyright IBM Corp. 2010-2017
sewardj2019a972011-03-07 16:04:07 +000012
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/* Contributed by Florian Krohm */
32
33#include "libvex_basictypes.h"
florian33b02432012-08-25 21:48:04 +000034#include "libvex_emnote.h"
sewardj2019a972011-03-07 16:04:07 +000035#include "libvex_guest_s390x.h"
36#include "libvex_ir.h"
37#include "libvex.h"
florian933065d2011-07-11 01:48:02 +000038#include "libvex_s390x_common.h"
sewardj2019a972011-03-07 16:04:07 +000039
40#include "main_util.h"
philippe6c46bef2012-08-14 22:29:01 +000041#include "main_globals.h"
sewardj2019a972011-03-07 16:04:07 +000042#include "guest_generic_bb_to_IR.h"
43#include "guest_s390_defs.h"
florianb0b67102012-12-24 00:14:31 +000044#include "s390_defs.h" /* S390_BFP_ROUND_xyzzy */
sewardj2019a972011-03-07 16:04:07 +000045
46void
47LibVEX_GuestS390X_initialise(VexGuestS390XState *state)
48{
49/*------------------------------------------------------------*/
50/*--- Initialise ar registers ---*/
51/*------------------------------------------------------------*/
52
53 state->guest_a0 = 0;
54 state->guest_a1 = 0;
55 state->guest_a2 = 0;
56 state->guest_a3 = 0;
57 state->guest_a4 = 0;
58 state->guest_a5 = 0;
59 state->guest_a6 = 0;
60 state->guest_a7 = 0;
61 state->guest_a8 = 0;
62 state->guest_a9 = 0;
63 state->guest_a10 = 0;
64 state->guest_a11 = 0;
65 state->guest_a12 = 0;
66 state->guest_a13 = 0;
67 state->guest_a14 = 0;
68 state->guest_a15 = 0;
69
70/*------------------------------------------------------------*/
71/*--- Initialise fpr registers ---*/
72/*------------------------------------------------------------*/
73
74 state->guest_f0 = 0;
75 state->guest_f1 = 0;
76 state->guest_f2 = 0;
77 state->guest_f3 = 0;
78 state->guest_f4 = 0;
79 state->guest_f5 = 0;
80 state->guest_f6 = 0;
81 state->guest_f7 = 0;
82 state->guest_f8 = 0;
83 state->guest_f9 = 0;
84 state->guest_f10 = 0;
85 state->guest_f11 = 0;
86 state->guest_f12 = 0;
87 state->guest_f13 = 0;
88 state->guest_f14 = 0;
89 state->guest_f15 = 0;
90
91/*------------------------------------------------------------*/
92/*--- Initialise gpr registers ---*/
93/*------------------------------------------------------------*/
94
95 state->guest_r0 = 0;
96 state->guest_r1 = 0;
97 state->guest_r2 = 0;
98 state->guest_r3 = 0;
99 state->guest_r4 = 0;
100 state->guest_r5 = 0;
101 state->guest_r6 = 0;
102 state->guest_r7 = 0;
103 state->guest_r8 = 0;
104 state->guest_r9 = 0;
105 state->guest_r10 = 0;
106 state->guest_r11 = 0;
107 state->guest_r12 = 0;
108 state->guest_r13 = 0;
109 state->guest_r14 = 0;
110 state->guest_r15 = 0;
111
112/*------------------------------------------------------------*/
113/*--- Initialise S390 miscellaneous registers ---*/
114/*------------------------------------------------------------*/
115
116 state->guest_counter = 0;
117 state->guest_fpc = 0;
118 state->guest_IA = 0;
119
120/*------------------------------------------------------------*/
121/*--- Initialise S390 pseudo registers ---*/
122/*------------------------------------------------------------*/
123
124 state->guest_SYSNO = 0;
125
126/*------------------------------------------------------------*/
127/*--- Initialise generic pseudo registers ---*/
128/*------------------------------------------------------------*/
129
130 state->guest_NRADDR = 0;
sewardj05f5e012014-05-04 10:52:11 +0000131 state->guest_CMSTART = 0;
132 state->guest_CMLEN = 0;
sewardj2019a972011-03-07 16:04:07 +0000133 state->guest_IP_AT_SYSCALL = 0;
florian6ef84be2012-08-26 03:20:07 +0000134 state->guest_EMNOTE = EmNote_NONE;
florian8844a632012-04-13 04:04:06 +0000135 state->host_EvC_COUNTER = 0;
136 state->host_EvC_FAILADDR = 0;
sewardj2019a972011-03-07 16:04:07 +0000137
138/*------------------------------------------------------------*/
139/*--- Initialise thunk ---*/
140/*------------------------------------------------------------*/
141
142 state->guest_CC_OP = 0;
143 state->guest_CC_DEP1 = 0;
144 state->guest_CC_DEP2 = 0;
145 state->guest_CC_NDEP = 0;
florian5c328c02012-05-22 01:51:26 +0000146
147 __builtin_memset(state->padding, 0x0, sizeof(state->padding));
sewardj2019a972011-03-07 16:04:07 +0000148}
149
150
151/* Figure out if any part of the guest state contained in minoff
152 .. maxoff requires precise memory exceptions. If in doubt return
philippe6c46bef2012-08-14 22:29:01 +0000153 True (but this generates significantly slower code). */
sewardj2019a972011-03-07 16:04:07 +0000154Bool
sewardjca2c3c72015-02-05 12:53:20 +0000155guest_s390x_state_requires_precise_mem_exns (
156 Int minoff, Int maxoff, VexRegisterUpdates pxControl
157)
sewardj2019a972011-03-07 16:04:07 +0000158{
sewardj60687882014-01-15 10:25:21 +0000159 Int lr_min = S390X_GUEST_OFFSET(guest_LR);
sewardj2019a972011-03-07 16:04:07 +0000160 Int lr_max = lr_min + 8 - 1;
sewardj60687882014-01-15 10:25:21 +0000161 Int sp_min = S390X_GUEST_OFFSET(guest_SP);
sewardj2019a972011-03-07 16:04:07 +0000162 Int sp_max = sp_min + 8 - 1;
sewardj60687882014-01-15 10:25:21 +0000163 Int fp_min = S390X_GUEST_OFFSET(guest_FP);
sewardj2019a972011-03-07 16:04:07 +0000164 Int fp_max = fp_min + 8 - 1;
floriane88b3c92011-07-05 02:48:39 +0000165 Int ia_min = S390X_GUEST_OFFSET(guest_IA);
sewardj2019a972011-03-07 16:04:07 +0000166 Int ia_max = ia_min + 8 - 1;
167
philippe6c46bef2012-08-14 22:29:01 +0000168 if (maxoff < sp_min || minoff > sp_max) {
169 /* No overlap with SP */
sewardjca2c3c72015-02-05 12:53:20 +0000170 if (pxControl == VexRegUpdSpAtMemAccess)
philippe6c46bef2012-08-14 22:29:01 +0000171 return False; // We only need to check stack pointer.
sewardj2019a972011-03-07 16:04:07 +0000172 } else {
173 return True;
174 }
175
philippe6c46bef2012-08-14 22:29:01 +0000176 if (maxoff < lr_min || minoff > lr_max) {
177 /* No overlap with LR */
sewardj2019a972011-03-07 16:04:07 +0000178 } else {
179 return True;
180 }
181
182 if (maxoff < fp_min || minoff > fp_max) {
183 /* No overlap with FP */
184 } else {
185 return True;
186 }
187
188 if (maxoff < ia_min || minoff > ia_max) {
189 /* No overlap with IA */
190 } else {
191 return True;
192 }
193
194 return False;
195}
196
197
198#define ALWAYSDEFD(field) \
floriane88b3c92011-07-05 02:48:39 +0000199 { S390X_GUEST_OFFSET(field), \
sewardj2019a972011-03-07 16:04:07 +0000200 (sizeof ((VexGuestS390XState*)0)->field) }
201
202VexGuestLayout s390xGuest_layout = {
203
204 /* Total size of the guest state, in bytes. */
205 .total_sizeB = sizeof(VexGuestS390XState),
206
207 /* Describe the stack pointer. */
sewardj60687882014-01-15 10:25:21 +0000208 .offset_SP = S390X_GUEST_OFFSET(guest_SP),
sewardj2019a972011-03-07 16:04:07 +0000209 .sizeof_SP = 8,
210
211 /* Describe the frame pointer. */
sewardj60687882014-01-15 10:25:21 +0000212 .offset_FP = S390X_GUEST_OFFSET(guest_FP),
sewardj2019a972011-03-07 16:04:07 +0000213 .sizeof_FP = 8,
214
215 /* Describe the instruction pointer. */
floriane88b3c92011-07-05 02:48:39 +0000216 .offset_IP = S390X_GUEST_OFFSET(guest_IA),
sewardj2019a972011-03-07 16:04:07 +0000217 .sizeof_IP = 8,
218
219 /* Describe any sections to be regarded by Memcheck as
220 'always-defined'. */
221 .n_alwaysDefd = 9,
222
223 /* Flags thunk: OP and NDEP are always defined, whereas DEP1
224 and DEP2 have to be tracked. See detailed comment in
225 gdefs.h on meaning of thunk fields. */
226 .alwaysDefd = {
227 /* 0 */ ALWAYSDEFD(guest_CC_OP), /* generic */
228 /* 1 */ ALWAYSDEFD(guest_CC_NDEP), /* generic */
florian6ef84be2012-08-26 03:20:07 +0000229 /* 2 */ ALWAYSDEFD(guest_EMNOTE), /* generic */
sewardj05f5e012014-05-04 10:52:11 +0000230 /* 3 */ ALWAYSDEFD(guest_CMSTART), /* generic */
231 /* 4 */ ALWAYSDEFD(guest_CMLEN), /* generic */
sewardj2019a972011-03-07 16:04:07 +0000232 /* 5 */ ALWAYSDEFD(guest_IP_AT_SYSCALL), /* generic */
233 /* 6 */ ALWAYSDEFD(guest_IA), /* control reg */
234 /* 7 */ ALWAYSDEFD(guest_fpc), /* control reg */
235 /* 8 */ ALWAYSDEFD(guest_counter), /* internal usage register */
236 }
237};
238
239/*------------------------------------------------------------*/
240/*--- Dirty helper for EXecute ---*/
241/*------------------------------------------------------------*/
242void
243s390x_dirtyhelper_EX(ULong torun)
244{
245 last_execute_target = torun;
246}
247
sewardj1e5fea62011-05-17 16:18:36 +0000248
249/*------------------------------------------------------------*/
250/*--- Dirty helper for Clock instructions ---*/
251/*------------------------------------------------------------*/
252#if defined(VGA_s390x)
florianae884112012-07-27 20:55:01 +0000253ULong
254s390x_dirtyhelper_STCK(ULong *addr)
sewardj1e5fea62011-05-17 16:18:36 +0000255{
florianffbd84d2012-12-09 02:06:29 +0000256 UInt cc;
sewardj1e5fea62011-05-17 16:18:36 +0000257
258 asm volatile("stck %0\n"
259 "ipm %1\n"
260 "srl %1,28\n"
261 : "+Q" (*addr), "=d" (cc) : : "cc");
262 return cc;
263}
264
florianae884112012-07-27 20:55:01 +0000265ULong
266s390x_dirtyhelper_STCKE(ULong *addr)
sewardj1e5fea62011-05-17 16:18:36 +0000267{
florianffbd84d2012-12-09 02:06:29 +0000268 UInt cc;
sewardj1e5fea62011-05-17 16:18:36 +0000269
270 asm volatile("stcke %0\n"
271 "ipm %1\n"
272 "srl %1,28\n"
273 : "+Q" (*addr), "=d" (cc) : : "cc");
274 return cc;
275}
276
277ULong s390x_dirtyhelper_STCKF(ULong *addr)
278{
florianffbd84d2012-12-09 02:06:29 +0000279 UInt cc;
sewardj1e5fea62011-05-17 16:18:36 +0000280
281 asm volatile(".insn s,0xb27c0000,%0\n"
282 "ipm %1\n"
283 "srl %1,28\n"
284 : "+Q" (*addr), "=d" (cc) : : "cc");
285 return cc;
286}
287#else
288ULong s390x_dirtyhelper_STCK(ULong *addr) {return 3;}
289ULong s390x_dirtyhelper_STCKF(ULong *addr) {return 3;}
290ULong s390x_dirtyhelper_STCKE(ULong *addr) {return 3;}
291#endif /* VGA_s390x */
292
sewardj2019a972011-03-07 16:04:07 +0000293/*------------------------------------------------------------*/
florian933065d2011-07-11 01:48:02 +0000294/*--- Dirty helper for Store Facility instruction ---*/
295/*------------------------------------------------------------*/
296#if defined(VGA_s390x)
florianb7def222012-12-04 04:45:32 +0000297static void
298s390_set_facility_bit(ULong *addr, UInt bitno, UInt value)
299{
300 addr += bitno / 64;
301 bitno = bitno % 64;
302
303 ULong mask = 1;
304 mask <<= (63 - bitno);
305
306 if (value == 1) {
307 *addr |= mask; // set
308 } else {
309 *addr &= ~mask; // clear
310 }
311}
312
florian933065d2011-07-11 01:48:02 +0000313ULong
florianae884112012-07-27 20:55:01 +0000314s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr)
florian933065d2011-07-11 01:48:02 +0000315{
316 ULong hoststfle[S390_NUM_FACILITY_DW], cc, num_dw, i;
317 register ULong reg0 asm("0") = guest_state->guest_r0 & 0xF; /* r0[56:63] */
318
319 /* We cannot store more than S390_NUM_FACILITY_DW
320 (and it makes not much sense to do so anyhow) */
321 if (reg0 > S390_NUM_FACILITY_DW - 1)
322 reg0 = S390_NUM_FACILITY_DW - 1;
323
324 num_dw = reg0 + 1; /* number of double words written */
325
326 asm volatile(" .insn s,0xb2b00000,%0\n" /* stfle */
327 "ipm %2\n"
328 "srl %2,28\n"
329 : "=m" (hoststfle), "+d"(reg0), "=d"(cc) : : "cc", "memory");
330
331 /* Update guest register 0 with what STFLE set r0 to */
332 guest_state->guest_r0 = reg0;
333
florianb7def222012-12-04 04:45:32 +0000334 /* Set default: VM facilities = host facilities */
florian933065d2011-07-11 01:48:02 +0000335 for (i = 0; i < num_dw; ++i)
florianae884112012-07-27 20:55:01 +0000336 addr[i] = hoststfle[i];
florian933065d2011-07-11 01:48:02 +0000337
florianb7def222012-12-04 04:45:32 +0000338 /* Now adjust the VM facilities according to what the VM supports */
339 s390_set_facility_bit(addr, S390_FAC_LDISP, 1);
340 s390_set_facility_bit(addr, S390_FAC_EIMM, 1);
341 s390_set_facility_bit(addr, S390_FAC_ETF2, 1);
342 s390_set_facility_bit(addr, S390_FAC_ETF3, 1);
343 s390_set_facility_bit(addr, S390_FAC_GIE, 1);
344 s390_set_facility_bit(addr, S390_FAC_EXEXT, 1);
345 s390_set_facility_bit(addr, S390_FAC_HIGHW, 1);
346
347 s390_set_facility_bit(addr, S390_FAC_HFPMAS, 0);
348 s390_set_facility_bit(addr, S390_FAC_HFPUNX, 0);
349 s390_set_facility_bit(addr, S390_FAC_XCPUT, 0);
350 s390_set_facility_bit(addr, S390_FAC_MSA, 0);
351 s390_set_facility_bit(addr, S390_FAC_PENH, 0);
352 s390_set_facility_bit(addr, S390_FAC_DFP, 0);
353 s390_set_facility_bit(addr, S390_FAC_PFPO, 0);
354 s390_set_facility_bit(addr, S390_FAC_DFPZC, 0);
355 s390_set_facility_bit(addr, S390_FAC_MISC, 0);
356 s390_set_facility_bit(addr, S390_FAC_CTREXE, 0);
357 s390_set_facility_bit(addr, S390_FAC_TREXE, 0);
358 s390_set_facility_bit(addr, S390_FAC_MSA4, 0);
359
florian933065d2011-07-11 01:48:02 +0000360 return cc;
361}
362
363#else
364
365ULong
florianae884112012-07-27 20:55:01 +0000366s390x_dirtyhelper_STFLE(VexGuestS390XState *guest_state, ULong *addr)
florian933065d2011-07-11 01:48:02 +0000367{
368 return 3;
369}
370#endif /* VGA_s390x */
371
floriana0100c92012-07-20 00:06:35 +0000372/*------------------------------------------------------------*/
373/*--- Dirty helper for the "convert unicode" insn family. ---*/
374/*------------------------------------------------------------*/
375void
376s390x_dirtyhelper_CUxy(UChar *address, ULong data, ULong num_bytes)
377{
378 UInt i;
379
380 vassert(num_bytes >= 1 && num_bytes <= 4);
381
382 /* Store the least significant NUM_BYTES bytes in DATA left to right
383 at ADDRESS. */
384 for (i = 1; i <= num_bytes; ++i) {
385 address[num_bytes - i] = data & 0xff;
386 data >>= 8;
387 }
388}
389
390
391/*------------------------------------------------------------*/
392/*--- Clean helper for CU21. ---*/
393/*------------------------------------------------------------*/
394
395/* The function performs a CU21 operation. It returns three things
396 encoded in an ULong value:
397 - the converted bytes (at most 4)
398 - the number of converted bytes
399 - an indication whether LOW_SURROGATE, if any, is invalid
400
401 64 48 16 8 0
402 +-------+-----------------+-----------+-----------------------+
403 | 0x0 | converted bytes | num_bytes | invalid_low_surrogate |
404 +-------+-----------------+-----------+-----------------------+
405*/
406ULong
407s390_do_cu21(UInt srcval, UInt low_surrogate)
408{
409 ULong retval = 0; // shut up gcc
florianae884112012-07-27 20:55:01 +0000410 UInt b1, b2, b3, b4, num_bytes, invalid_low_surrogate = 0;
floriana0100c92012-07-20 00:06:35 +0000411
412 srcval &= 0xffff;
413
414 /* Determine the number of bytes in the converted value */
415 if (srcval <= 0x007f)
416 num_bytes = 1;
417 else if (srcval >= 0x0080 && srcval <= 0x07ff)
418 num_bytes = 2;
419 else if ((srcval >= 0x0800 && srcval <= 0xd7ff) ||
420 (srcval >= 0xdc00 && srcval <= 0xffff))
421 num_bytes = 3;
422 else
423 num_bytes = 4;
424
425 /* Determine UTF-8 bytes according to calculated num_bytes */
426 switch (num_bytes){
427 case 1:
428 retval = srcval;
429 break;
430
431 case 2:
432 /* order of bytes left to right: b1, b2 */
433 b1 = 0xc0;
434 b1 |= srcval >> 6;
435
436 b2 = 0x80;
437 b2 |= srcval & 0x3f;
438
439 retval = (b1 << 8) | b2;
440 break;
441
442 case 3:
443 /* order of bytes left to right: b1, b2, b3 */
444 b1 = 0xe0;
445 b1 |= srcval >> 12;
446
447 b2 = 0x80;
448 b2 |= (srcval >> 6) & 0x3f;
449
450 b3 = 0x80;
451 b3 |= srcval & 0x3f;
452
453 retval = (b1 << 16) | (b2 << 8) | b3;
454 break;
455
456 case 4: {
457 /* order of bytes left to right: b1, b2, b3, b4 */
458 UInt high_surrogate = srcval;
459 UInt uvwxy = ((high_surrogate >> 6) & 0xf) + 1; // abcd + 1
460
461 b1 = 0xf0;
462 b1 |= uvwxy >> 2; // uvw
463
464 b2 = 0x80;
465 b2 |= (uvwxy & 0x3) << 4; // xy
466 b2 |= (high_surrogate >> 2) & 0xf; // efgh
467
468 b3 = 0x80;
469 b3 |= (high_surrogate & 0x3) << 4; // ij
470 b3 |= (low_surrogate >> 6) & 0xf; // klmn
471
472 b4 = 0x80;
473 b4 |= low_surrogate & 0x3f;
474
475 retval = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
476
477 invalid_low_surrogate = (low_surrogate & 0xfc00) != 0xdc00;
478 break;
479 }
480 }
481
482 /* At this point RETVAL contains the converted bytes.
483 Build up the final return value. */
484 return (retval << 16) | (num_bytes << 8) | invalid_low_surrogate;
485}
486
floriane711c802012-07-15 02:25:55 +0000487
488/*------------------------------------------------------------*/
florian2a415a12012-07-21 17:41:36 +0000489/*--- Clean helper for CU24. ---*/
490/*------------------------------------------------------------*/
491
492/* The function performs a CU24 operation. It returns two things
493 encoded in an ULong value:
494 - the 4 converted bytes
495 - an indication whether LOW_SURROGATE, if any, is invalid
496
497 64 40 8 0
498 +------------------------+-----------------------+
499 | 0x0 | converted bytes | invalid_low_surrogate |
500 +------------------------+-----------------------+
501*/
502ULong
503s390_do_cu24(UInt srcval, UInt low_surrogate)
504{
505 ULong retval;
506 UInt invalid_low_surrogate = 0;
507
508 srcval &= 0xffff;
509
510 if ((srcval >= 0x0000 && srcval <= 0xd7ff) ||
511 (srcval >= 0xdc00 && srcval <= 0xffff)) {
512 retval = srcval;
513 } else {
514 /* D800 - DBFF */
515 UInt high_surrogate = srcval;
516 UInt uvwxy = ((high_surrogate >> 6) & 0xf) + 1; // abcd + 1
517 UInt efghij = high_surrogate & 0x3f;
518 UInt klmnoprst = low_surrogate & 0x3ff;
519
520 retval = (uvwxy << 16) | (efghij << 10) | klmnoprst;
521
522 invalid_low_surrogate = (low_surrogate & 0xfc00) != 0xdc00;
523 }
524
525 /* At this point RETVAL contains the converted bytes.
526 Build up the final return value. */
527 return (retval << 8) | invalid_low_surrogate;
528}
529
530
531/*------------------------------------------------------------*/
florian956194b2012-07-28 22:18:32 +0000532/*--- Clean helper for CU42. ---*/
533/*------------------------------------------------------------*/
534
535/* The function performs a CU42 operation. It returns three things
536 encoded in an ULong value:
537 - the converted bytes (at most 4)
538 - the number of converted bytes (2 or 4; 0 if invalid character)
539 - an indication whether the UTF-32 character is invalid
540
541 64 48 16 8 0
542 +-------+-----------------+-----------+-------------------+
543 | 0x0 | converted bytes | num_bytes | invalid_character |
544 +-------+-----------------+-----------+-------------------+
545*/
546ULong
547s390_do_cu42(UInt srcval)
548{
549 ULong retval;
550 UInt num_bytes, invalid_character = 0;
551
552 if ((srcval >= 0x0000 && srcval <= 0xd7ff) ||
553 (srcval >= 0xdc00 && srcval <= 0xffff)) {
554 retval = srcval;
555 num_bytes = 2;
556 } else if (srcval >= 0x00010000 && srcval <= 0x0010FFFF) {
557 UInt uvwxy = srcval >> 16;
558 UInt abcd = (uvwxy - 1) & 0xf;
559 UInt efghij = (srcval >> 10) & 0x3f;
560
561 UInt high_surrogate = (0xd8 << 8) | (abcd << 6) | efghij;
562 UInt low_surrogate = (0xdc << 8) | (srcval & 0x3ff);
563
564 retval = (high_surrogate << 16) | low_surrogate;
565 num_bytes = 4;
566 } else {
567 /* D800 - DBFF or 00110000 - FFFFFFFF */
568 invalid_character = 1;
569 retval = num_bytes = 0; /* does not matter; not used */
570 }
571
572 /* At this point RETVAL contains the converted bytes.
573 Build up the final return value. */
574 return (retval << 16) | (num_bytes << 8) | invalid_character;
575}
576
577
578/*------------------------------------------------------------*/
florianaf2194f2012-08-06 00:07:54 +0000579/*--- Clean helper for CU41. ---*/
580/*------------------------------------------------------------*/
581
582/* The function performs a CU41 operation. It returns three things
583 encoded in an ULong value:
584 - the converted bytes (at most 4)
585 - the number of converted bytes (1, 2, 3, or 4; 0 if invalid character)
586 - an indication whether the UTF-32 character is invalid
587
588 64 48 16 8 0
589 +-------+-----------------+-----------+-------------------+
590 | 0x0 | converted bytes | num_bytes | invalid_character |
591 +-------+-----------------+-----------+-------------------+
592*/
593ULong
594s390_do_cu41(UInt srcval)
595{
596 ULong retval;
597 UInt num_bytes, invalid_character = 0;
598
599 if (srcval <= 0x7f) {
600 retval = srcval;
601 num_bytes = 1;
602 } else if (srcval >= 0x80 && srcval <= 0x7ff) {
603 UInt fghij = srcval >> 6;
604 UInt klmnop = srcval & 0x3f;
605 UInt byte1 = (0xc0 | fghij);
606 UInt byte2 = (0x80 | klmnop);
607
608 retval = (byte1 << 8) | byte2;
609 num_bytes = 2;
610 } else if ((srcval >= 0x800 && srcval <= 0xd7ff) ||
611 (srcval >= 0xdc00 && srcval <= 0xffff)) {
612 UInt abcd = srcval >> 12;
613 UInt efghij = (srcval >> 6) & 0x3f;
614 UInt klmnop = srcval & 0x3f;
615 UInt byte1 = 0xe0 | abcd;
616 UInt byte2 = 0x80 | efghij;
617 UInt byte3 = 0x80 | klmnop;
618
619 retval = (byte1 << 16) | (byte2 << 8) | byte3;
620 num_bytes = 3;
621 } else if (srcval >= 0x10000 && srcval <= 0x10ffff) {
622 UInt uvw = (srcval >> 18) & 0x7;
623 UInt xy = (srcval >> 16) & 0x3;
624 UInt efgh = (srcval >> 12) & 0xf;
625 UInt ijklmn = (srcval >> 6) & 0x3f;
626 UInt opqrst = srcval & 0x3f;
627 UInt byte1 = 0xf0 | uvw;
628 UInt byte2 = 0x80 | (xy << 4) | efgh;
629 UInt byte3 = 0x80 | ijklmn;
630 UInt byte4 = 0x80 | opqrst;
631
632 retval = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
633 num_bytes = 4;
634 } else {
635 /* d800 ... dbff or 00110000 ... ffffffff */
636 invalid_character = 1;
637
638 retval = 0;
639 num_bytes = 0;
640 }
641
642 /* At this point RETVAL contains the converted bytes.
643 Build up the final return value. */
644 return (retval << 16) | (num_bytes << 8) | invalid_character;
645}
646
647
648/*------------------------------------------------------------*/
florian6d9b9b22012-08-03 18:35:39 +0000649/*--- Clean helpers for CU12. ---*/
650/*------------------------------------------------------------*/
651
652/* The function looks at the first byte of an UTF-8 character and returns
653 two things encoded in an ULong value:
654
655 - the number of bytes that need to be read
656 - an indication whether the UTF-8 character is invalid
657
658 64 16 8 0
659 +-------------------+-------------------+
660 | 0x0 | num_bytes | invalid_character |
661 +-------+-----------+-------------------+
662*/
663ULong
florian3f8a96a2012-08-05 02:59:55 +0000664s390_do_cu12_cu14_helper1(UInt byte, UInt etf3_and_m3_is_1)
florian6d9b9b22012-08-03 18:35:39 +0000665{
666 vassert(byte <= 0xff);
667
668 /* Check whether the character is invalid */
669 if (byte >= 0x80 && byte <= 0xbf) return 1;
670 if (byte >= 0xf8) return 1;
671
672 if (etf3_and_m3_is_1) {
673 if (byte == 0xc0 || byte == 0xc1) return 1;
674 if (byte >= 0xf5 && byte <= 0xf7) return 1;
675 }
676
677 /* Character is valid */
678 if (byte <= 0x7f) return 1 << 8; // 1 byte
679 if (byte <= 0xdf) return 2 << 8; // 2 bytes
680 if (byte <= 0xef) return 3 << 8; // 3 bytes
681
682 return 4 << 8; // 4 bytes
683}
684
florian3f8a96a2012-08-05 02:59:55 +0000685/* The function performs a CU12 or CU14 operation. BYTE1, BYTE2, etc are the
florian6d9b9b22012-08-03 18:35:39 +0000686 bytes as read from the input stream, left to right. BYTE1 is a valid
687 byte. The function returns three things encoded in an ULong value:
688
689 - the converted bytes
690 - the number of converted bytes (2 or 4; 0 if invalid character)
691 - an indication whether the UTF-16 character is invalid
692
693 64 48 16 8 0
694 +-------+-----------------+-----------+-------------------+
695 | 0x0 | converted bytes | num_bytes | invalid_character |
696 +-------+-----------------+-----------+-------------------+
697*/
florian3f8a96a2012-08-05 02:59:55 +0000698static ULong
699s390_do_cu12_cu14_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
700 ULong stuff, Bool is_cu12)
florian6d9b9b22012-08-03 18:35:39 +0000701{
florian3f8a96a2012-08-05 02:59:55 +0000702 UInt num_src_bytes = stuff >> 1, etf3_and_m3_is_1 = stuff & 0x1;
florian6d9b9b22012-08-03 18:35:39 +0000703 UInt num_bytes = 0, invalid_character = 0;
704 ULong retval = 0;
florian6d9b9b22012-08-03 18:35:39 +0000705
706 vassert(num_src_bytes <= 4);
707
708 switch (num_src_bytes) {
709 case 1:
710 num_bytes = 2;
711 retval = byte1;
712 break;
713
714 case 2: {
715 /* Test validity */
716 if (etf3_and_m3_is_1) {
717 if (byte2 < 0x80 || byte2 > 0xbf) {
718 invalid_character = 1;
719 break;
720 }
721 }
722
723 /* OK */
724 UInt fghij = byte1 & 0x1f;
725 UInt klmnop = byte2 & 0x3f;
726
727 num_bytes = 2;
728 retval = (fghij << 6) | klmnop;
729 break;
730 }
731
732 case 3: {
733 /* Test validity */
734 if (etf3_and_m3_is_1) {
735 if (byte1 == 0xe0) {
736 if ((byte2 < 0xa0 || byte2 > 0xbf) ||
737 (byte3 < 0x80 || byte3 > 0xbf)) {
738 invalid_character = 1;
739 break;
740 }
741 }
742 if ((byte1 >= 0xe1 && byte1 <= 0xec) ||
743 byte1 == 0xee || byte1 == 0xef) {
744 if ((byte2 < 0x80 || byte2 > 0xbf) ||
745 (byte3 < 0x80 || byte3 > 0xbf)) {
746 invalid_character = 1;
747 break;
748 }
749 }
750 if (byte1 == 0xed) {
751 if ((byte2 < 0x80 || byte2 > 0x9f) ||
752 (byte3 < 0x80 || byte3 > 0xbf)) {
753 invalid_character = 1;
754 break;
755 }
756 }
757 }
758
759 /* OK */
760 UInt abcd = byte1 & 0xf;
761 UInt efghij = byte2 & 0x3f;
762 UInt klmnop = byte3 & 0x3f;
763
764 num_bytes = 2;
765 retval = (abcd << 12) | (efghij << 6) | klmnop;
766 break;
767 }
768
769 case 4: {
770 /* Test validity */
771 if (etf3_and_m3_is_1) {
772 if (byte1 == 0xf0) {
773 if ((byte2 < 0x90 || byte2 > 0xbf) ||
774 (byte3 < 0x80 || byte3 > 0xbf) ||
775 (byte4 < 0x80 || byte4 > 0xbf)) {
776 invalid_character = 1;
777 break;
778 }
779 }
780 if (byte1 == 0xf1 || byte1 == 0xf2 || byte1 == 0xf3) {
781 if ((byte2 < 0x80 || byte2 > 0xbf) ||
782 (byte3 < 0x80 || byte3 > 0xbf) ||
783 (byte4 < 0x80 || byte4 > 0xbf)) {
784 invalid_character = 1;
785 break;
786 }
787 }
788 if (byte1 == 0xf4) {
789 if ((byte2 < 0x80 || byte2 > 0x8f) ||
790 (byte3 < 0x80 || byte3 > 0xbf) ||
791 (byte4 < 0x80 || byte4 > 0xbf)) {
792 invalid_character = 1;
793 break;
794 }
795 }
796 }
797
798 /* OK */
799 UInt uvw = byte1 & 0x7;
800 UInt xy = (byte2 >> 4) & 0x3;
801 UInt uvwxy = (uvw << 2) | xy;
florian6d9b9b22012-08-03 18:35:39 +0000802 UInt efgh = byte2 & 0xf;
803 UInt ij = (byte3 >> 4) & 0x3;
804 UInt klmn = byte3 & 0xf;
805 UInt opqrst = byte4 & 0x3f;
806
florian3f8a96a2012-08-05 02:59:55 +0000807 if (is_cu12) {
808 UInt abcd = (uvwxy - 1) & 0xf;
809 UInt high_surrogate = (0xd8 << 8) | (abcd << 6) | (efgh << 2) | ij;
810 UInt low_surrogate = (0xdc << 8) | (klmn << 6) | opqrst;
florian6d9b9b22012-08-03 18:35:39 +0000811
florian3f8a96a2012-08-05 02:59:55 +0000812 num_bytes = 4;
813 retval = (high_surrogate << 16) | low_surrogate;
814 } else {
815 num_bytes = 4;
816 retval =
817 (uvwxy << 16) | (efgh << 12) | (ij << 10) | (klmn << 6) | opqrst;
818 }
florian6d9b9b22012-08-03 18:35:39 +0000819 break;
820 }
821 }
822
florian3f8a96a2012-08-05 02:59:55 +0000823 if (! is_cu12) num_bytes = 4; // for CU14, by definition
824
florian6d9b9b22012-08-03 18:35:39 +0000825 /* At this point RETVAL contains the converted bytes.
826 Build up the final return value. */
827 return (retval << 16) | (num_bytes << 8) | invalid_character;
828}
829
florian3f8a96a2012-08-05 02:59:55 +0000830ULong
831s390_do_cu12_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
832 ULong stuff)
833{
834 return s390_do_cu12_cu14_helper2(byte1, byte2, byte3, byte4, stuff,
835 /* is_cu12 = */ 1);
836}
837
838ULong
839s390_do_cu14_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
840 ULong stuff)
841{
842 return s390_do_cu12_cu14_helper2(byte1, byte2, byte3, byte4, stuff,
843 /* is_cu12 = */ 0);
844}
845
florian6d9b9b22012-08-03 18:35:39 +0000846
847/*------------------------------------------------------------*/
floriane711c802012-07-15 02:25:55 +0000848/*--- Clean helper for "convert to binary". ---*/
849/*------------------------------------------------------------*/
850#if defined(VGA_s390x)
851UInt
852s390_do_cvb(ULong decimal)
853{
854 UInt binary;
855
856 __asm__ volatile (
857 "cvb %[result],%[input]\n\t"
858 : [result] "=d"(binary)
859 : [input] "m"(decimal)
860 );
861
862 return binary;
863}
864
865#else
866UInt s390_do_cvb(ULong decimal) { return 0; }
867#endif
868
869
870/*------------------------------------------------------------*/
871/*--- Clean helper for "convert to decimal". ---*/
872/*------------------------------------------------------------*/
873#if defined(VGA_s390x)
874ULong
875s390_do_cvd(ULong binary_in)
876{
877 UInt binary = binary_in & 0xffffffffULL;
878 ULong decimal;
879
880 __asm__ volatile (
881 "cvd %[input],%[result]\n\t"
882 : [result] "=m"(decimal)
883 : [input] "d"(binary)
884 );
885
886 return decimal;
887}
888
889#else
890ULong s390_do_cvd(ULong binary) { return 0; }
891#endif
892
florian8c88cb62012-08-26 18:58:13 +0000893/*------------------------------------------------------------*/
894/*--- Clean helper for "Extract cache attribute". ---*/
895/*------------------------------------------------------------*/
896#if defined(VGA_s390x)
897ULong
898s390_do_ecag(ULong op2addr)
899{
900 ULong result;
901
902 __asm__ volatile(".insn rsy,0xEB000000004C,%[out],0,0(%[in])\n\t"
903 : [out] "=d"(result)
904 : [in] "d"(op2addr));
905 return result;
906}
907
908#else
909ULong s390_do_ecag(ULong op2addr) { return 0; }
910#endif
floriane711c802012-07-15 02:25:55 +0000911
florian933065d2011-07-11 01:48:02 +0000912/*------------------------------------------------------------*/
florian78d5ef72013-05-11 15:02:58 +0000913/*--- Clean helper for "Perform Floating Point Operation". ---*/
914/*------------------------------------------------------------*/
915#if defined(VGA_s390x)
916UInt
917s390_do_pfpo(UInt gpr0)
918{
919 UChar rm;
920 UChar op1_ty, op2_ty;
921
922 rm = gpr0 & 0xf;
923 if (rm > 1 && rm < 8)
924 return EmFail_S390X_invalid_PFPO_rounding_mode;
925
926 op1_ty = (gpr0 >> 16) & 0xff; // gpr0[40:47]
927 op2_ty = (gpr0 >> 8) & 0xff; // gpr0[48:55]
928 /* Operand type must be BFP 32, 64, 128 or DFP 32, 64, 128
929 which correspond to 0x5, 0x6, 0x7, 0x8, 0x9, 0xa respectively.
930 Any other operand type value is unsupported */
931 if ((op1_ty == op2_ty) ||
932 (op1_ty < 0x5 || op1_ty > 0xa) ||
933 (op2_ty < 0x5 || op2_ty > 0xa))
934 return EmFail_S390X_invalid_PFPO_function;
935
936 return EmNote_NONE;
937}
938#else
939UInt s390_do_pfpo(UInt gpr0) { return 0; }
940#endif
941
942/*------------------------------------------------------------*/
sewardj2019a972011-03-07 16:04:07 +0000943/*--- Helper for condition code. ---*/
944/*------------------------------------------------------------*/
945
florian83f60b52013-01-13 02:34:28 +0000946/* Convert an IRRoundingMode value to s390_bfp_round_t */
florian3d80fad2012-09-13 15:58:01 +0000947#if defined(VGA_s390x)
florian125e20d2012-10-07 15:42:37 +0000948static s390_bfp_round_t
florian19e00772012-09-06 03:13:22 +0000949decode_bfp_rounding_mode(UInt irrm)
950{
951 switch (irrm) {
florian125e20d2012-10-07 15:42:37 +0000952 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
953 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
954 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
955 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
florian19e00772012-09-06 03:13:22 +0000956 }
957 vpanic("decode_bfp_rounding_mode");
958}
florian3d80fad2012-09-13 15:58:01 +0000959#endif
florian19e00772012-09-06 03:13:22 +0000960
961
sewardj2019a972011-03-07 16:04:07 +0000962#define S390_CC_FOR_BINARY(opcode,cc_dep1,cc_dep2) \
963({ \
964 __asm__ volatile ( \
965 opcode " %[op1],%[op2]\n\t" \
966 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op1] "+d"(cc_dep1) \
967 : [op2] "d"(cc_dep2) \
968 : "cc");\
969 psw >> 28; /* cc */ \
970})
971
972#define S390_CC_FOR_TERNARY_SUBB(opcode,cc_dep1,cc_dep2,cc_ndep) \
973({ \
974 /* Recover the original DEP2 value. See comment near s390_cc_thunk_put3 \
975 for rationale. */ \
976 cc_dep2 = cc_dep2 ^ cc_ndep; \
977 __asm__ volatile ( \
978 "lghi 0,1\n\t" \
979 "sr 0,%[op3]\n\t" /* borrow to cc */ \
980 opcode " %[op1],%[op2]\n\t" /* then redo the op */\
981 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op1] "+&d"(cc_dep1) \
982 : [op2] "d"(cc_dep2), [op3] "d"(cc_ndep) \
983 : "0", "cc");\
984 psw >> 28; /* cc */ \
985})
986
987#define S390_CC_FOR_TERNARY_ADDC(opcode,cc_dep1,cc_dep2,cc_ndep) \
988({ \
989 /* Recover the original DEP2 value. See comment near s390_cc_thunk_put3 \
990 for rationale. */ \
991 cc_dep2 = cc_dep2 ^ cc_ndep; \
992 __asm__ volatile ( \
993 "lgfr 0,%[op3]\n\t" /* first load cc_ndep */ \
994 "aghi 0,0\n\t" /* and convert it into a cc */ \
995 opcode " %[op1],%[op2]\n\t" /* then redo the op */\
996 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op1] "+&d"(cc_dep1) \
997 : [op2] "d"(cc_dep2), [op3] "d"(cc_ndep) \
998 : "0", "cc");\
999 psw >> 28; /* cc */ \
1000})
1001
1002
1003#define S390_CC_FOR_BFP_RESULT(opcode,cc_dep1) \
1004({ \
1005 __asm__ volatile ( \
1006 opcode " 0,%[op]\n\t" \
1007 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1008 : [op] "f"(cc_dep1) \
1009 : "cc", "f0");\
1010 psw >> 28; /* cc */ \
1011})
1012
1013#define S390_CC_FOR_BFP128_RESULT(hi,lo) \
1014({ \
1015 __asm__ volatile ( \
1016 "ldr 4,%[high]\n\t" \
1017 "ldr 6,%[low]\n\t" \
1018 "ltxbr 0,4\n\t" \
1019 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1020 : [high] "f"(hi), [low] "f"(lo) \
1021 : "cc", "f0", "f2", "f4", "f6");\
1022 psw >> 28; /* cc */ \
1023})
1024
florian19e00772012-09-06 03:13:22 +00001025#define S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,rounding_mode) \
sewardj2019a972011-03-07 16:04:07 +00001026({ \
1027 __asm__ volatile ( \
florian19e00772012-09-06 03:13:22 +00001028 opcode " 0," #rounding_mode ",%[op]\n\t" \
sewardj2019a972011-03-07 16:04:07 +00001029 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1030 : [op] "f"(cc_dep1) \
1031 : "cc", "r0");\
1032 psw >> 28; /* cc */ \
1033})
1034
florian19e00772012-09-06 03:13:22 +00001035#define S390_CC_FOR_BFP_CONVERT(opcode,cc_dep1,cc_dep2) \
1036({ \
1037 UInt cc; \
1038 switch (decode_bfp_rounding_mode(cc_dep2)) { \
florian125e20d2012-10-07 15:42:37 +00001039 case S390_BFP_ROUND_NEAREST_EVEN: \
florian19e00772012-09-06 03:13:22 +00001040 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,4); \
1041 break; \
florian125e20d2012-10-07 15:42:37 +00001042 case S390_BFP_ROUND_ZERO: \
florian19e00772012-09-06 03:13:22 +00001043 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,5); \
1044 break; \
florian125e20d2012-10-07 15:42:37 +00001045 case S390_BFP_ROUND_POSINF: \
florian19e00772012-09-06 03:13:22 +00001046 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,6); \
1047 break; \
florian125e20d2012-10-07 15:42:37 +00001048 case S390_BFP_ROUND_NEGINF: \
florian19e00772012-09-06 03:13:22 +00001049 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,7); \
1050 break; \
1051 default: \
florian125e20d2012-10-07 15:42:37 +00001052 vpanic("unexpected bfp rounding mode"); \
florian19e00772012-09-06 03:13:22 +00001053 } \
1054 cc; \
1055})
1056
1057#define S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,rounding_mode) \
florian1c8f7ff2012-09-01 00:12:11 +00001058({ \
1059 __asm__ volatile ( \
florian19e00772012-09-06 03:13:22 +00001060 opcode ",0,%[op]," #rounding_mode ",0\n\t" \
florian1c8f7ff2012-09-01 00:12:11 +00001061 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1062 : [op] "f"(cc_dep1) \
1063 : "cc", "r0");\
1064 psw >> 28; /* cc */ \
1065})
1066
florian19e00772012-09-06 03:13:22 +00001067#define S390_CC_FOR_BFP_UCONVERT(opcode,cc_dep1,cc_dep2) \
1068({ \
1069 UInt cc; \
1070 switch (decode_bfp_rounding_mode(cc_dep2)) { \
florian125e20d2012-10-07 15:42:37 +00001071 case S390_BFP_ROUND_NEAREST_EVEN: \
florian19e00772012-09-06 03:13:22 +00001072 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,4); \
1073 break; \
florian125e20d2012-10-07 15:42:37 +00001074 case S390_BFP_ROUND_ZERO: \
florian19e00772012-09-06 03:13:22 +00001075 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,5); \
1076 break; \
florian125e20d2012-10-07 15:42:37 +00001077 case S390_BFP_ROUND_POSINF: \
florian19e00772012-09-06 03:13:22 +00001078 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,6); \
1079 break; \
florian125e20d2012-10-07 15:42:37 +00001080 case S390_BFP_ROUND_NEGINF: \
florian19e00772012-09-06 03:13:22 +00001081 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,7); \
1082 break; \
1083 default: \
florian125e20d2012-10-07 15:42:37 +00001084 vpanic("unexpected bfp rounding mode"); \
florian19e00772012-09-06 03:13:22 +00001085 } \
1086 cc; \
1087})
1088
1089#define S390_CC_FOR_BFP128_CONVERT_AUX(opcode,hi,lo,rounding_mode) \
sewardj2019a972011-03-07 16:04:07 +00001090({ \
1091 __asm__ volatile ( \
1092 "ldr 4,%[high]\n\t" \
1093 "ldr 6,%[low]\n\t" \
florian19e00772012-09-06 03:13:22 +00001094 opcode " 0," #rounding_mode ",4\n\t" \
sewardj2019a972011-03-07 16:04:07 +00001095 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1096 : [high] "f"(hi), [low] "f"(lo) \
1097 : "cc", "r0", "f4", "f6");\
1098 psw >> 28; /* cc */ \
1099})
1100
florian19e00772012-09-06 03:13:22 +00001101#define S390_CC_FOR_BFP128_CONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1102({ \
1103 UInt cc; \
1104 /* Recover the original DEP2 value. See comment near \
1105 s390_cc_thunk_put3 for rationale. */ \
1106 cc_dep2 = cc_dep2 ^ cc_ndep; \
1107 switch (decode_bfp_rounding_mode(cc_ndep)) { \
florian125e20d2012-10-07 15:42:37 +00001108 case S390_BFP_ROUND_NEAREST_EVEN: \
florian19e00772012-09-06 03:13:22 +00001109 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1110 break; \
florian125e20d2012-10-07 15:42:37 +00001111 case S390_BFP_ROUND_ZERO: \
florian19e00772012-09-06 03:13:22 +00001112 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1113 break; \
florian125e20d2012-10-07 15:42:37 +00001114 case S390_BFP_ROUND_POSINF: \
florian19e00772012-09-06 03:13:22 +00001115 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1116 break; \
florian125e20d2012-10-07 15:42:37 +00001117 case S390_BFP_ROUND_NEGINF: \
florian19e00772012-09-06 03:13:22 +00001118 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1119 break; \
1120 default: \
florian125e20d2012-10-07 15:42:37 +00001121 vpanic("unexpected bfp rounding mode"); \
florian19e00772012-09-06 03:13:22 +00001122 } \
1123 cc; \
1124})
1125
1126#define S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,hi,lo,rounding_mode) \
florian1c8f7ff2012-09-01 00:12:11 +00001127({ \
1128 __asm__ volatile ( \
1129 "ldr 4,%[high]\n\t" \
1130 "ldr 6,%[low]\n\t" \
florian19e00772012-09-06 03:13:22 +00001131 opcode ",0,4," #rounding_mode ",0\n\t" \
florian1c8f7ff2012-09-01 00:12:11 +00001132 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1133 : [high] "f"(hi), [low] "f"(lo) \
1134 : "cc", "r0", "f4", "f6");\
1135 psw >> 28; /* cc */ \
1136})
1137
florian19e00772012-09-06 03:13:22 +00001138#define S390_CC_FOR_BFP128_UCONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1139({ \
1140 UInt cc; \
1141 /* Recover the original DEP2 value. See comment near \
1142 s390_cc_thunk_put3 for rationale. */ \
1143 cc_dep2 = cc_dep2 ^ cc_ndep; \
1144 switch (decode_bfp_rounding_mode(cc_ndep)) { \
florian125e20d2012-10-07 15:42:37 +00001145 case S390_BFP_ROUND_NEAREST_EVEN: \
florian19e00772012-09-06 03:13:22 +00001146 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1147 break; \
florian125e20d2012-10-07 15:42:37 +00001148 case S390_BFP_ROUND_ZERO: \
florian19e00772012-09-06 03:13:22 +00001149 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1150 break; \
florian125e20d2012-10-07 15:42:37 +00001151 case S390_BFP_ROUND_POSINF: \
florian19e00772012-09-06 03:13:22 +00001152 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1153 break; \
florian125e20d2012-10-07 15:42:37 +00001154 case S390_BFP_ROUND_NEGINF: \
florian19e00772012-09-06 03:13:22 +00001155 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1156 break; \
1157 default: \
florian125e20d2012-10-07 15:42:37 +00001158 vpanic("unexpected bfp rounding mode"); \
florian19e00772012-09-06 03:13:22 +00001159 } \
1160 cc; \
1161})
1162
sewardj2019a972011-03-07 16:04:07 +00001163#define S390_CC_FOR_BFP_TDC(opcode,cc_dep1,cc_dep2) \
1164({ \
1165 __asm__ volatile ( \
1166 opcode " %[value],0(%[class])\n\t" \
1167 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1168 : [value] "f"(cc_dep1), \
1169 [class] "a"(cc_dep2) \
1170 : "cc");\
1171 psw >> 28; /* cc */ \
1172})
1173
1174#define S390_CC_FOR_BFP128_TDC(cc_dep1,cc_dep2,cc_ndep) \
1175({ \
floriancf1527c2012-12-27 20:59:43 +00001176 /* Recover the original DEP2 value. See comment near \
1177 s390_cc_thunk_put1f128Z for rationale. */ \
sewardj2019a972011-03-07 16:04:07 +00001178 cc_dep2 = cc_dep2 ^ cc_ndep; \
1179 __asm__ volatile ( \
1180 "ldr 4,%[high]\n\t" \
1181 "ldr 6,%[low]\n\t" \
1182 "tcxb 4,0(%[class])\n\t" \
1183 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1184 : [high] "f"(cc_dep1), [low] "f"(cc_dep2), \
1185 [class] "a"(cc_ndep) \
1186 : "cc", "f4", "f6");\
1187 psw >> 28; /* cc */ \
1188})
1189
florian79e5a482013-06-06 19:12:46 +00001190/* Convert an IRRoundingMode value to s390_dfp_round_t */
florian5f034622013-01-13 02:29:05 +00001191#if defined(VGA_s390x)
1192static s390_dfp_round_t
1193decode_dfp_rounding_mode(UInt irrm)
1194{
1195 switch (irrm) {
florian79e5a482013-06-06 19:12:46 +00001196 case Irrm_NEAREST:
florian5f034622013-01-13 02:29:05 +00001197 return S390_DFP_ROUND_NEAREST_EVEN_4;
florian79e5a482013-06-06 19:12:46 +00001198 case Irrm_NegINF:
florian5f034622013-01-13 02:29:05 +00001199 return S390_DFP_ROUND_NEGINF_7;
florian79e5a482013-06-06 19:12:46 +00001200 case Irrm_PosINF:
florian5f034622013-01-13 02:29:05 +00001201 return S390_DFP_ROUND_POSINF_6;
florian79e5a482013-06-06 19:12:46 +00001202 case Irrm_ZERO:
florian5f034622013-01-13 02:29:05 +00001203 return S390_DFP_ROUND_ZERO_5;
florian79e5a482013-06-06 19:12:46 +00001204 case Irrm_NEAREST_TIE_AWAY_0:
florian5f034622013-01-13 02:29:05 +00001205 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
florian79e5a482013-06-06 19:12:46 +00001206 case Irrm_PREPARE_SHORTER:
florian5f034622013-01-13 02:29:05 +00001207 return S390_DFP_ROUND_PREPARE_SHORT_3;
florian79e5a482013-06-06 19:12:46 +00001208 case Irrm_AWAY_FROM_ZERO:
florian5f034622013-01-13 02:29:05 +00001209 return S390_DFP_ROUND_AWAY_0;
florian79e5a482013-06-06 19:12:46 +00001210 case Irrm_NEAREST_TIE_TOWARD_0:
florian5f034622013-01-13 02:29:05 +00001211 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
1212 }
1213 vpanic("decode_dfp_rounding_mode");
1214}
1215#endif
1216
florian12390202012-11-10 22:34:14 +00001217#define S390_CC_FOR_DFP_RESULT(cc_dep1) \
1218({ \
1219 __asm__ volatile ( \
1220 ".insn rre, 0xb3d60000,0,%[op]\n\t" /* LTDTR */ \
1221 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1222 : [op] "f"(cc_dep1) \
1223 : "cc", "f0"); \
1224 psw >> 28; /* cc */ \
1225})
1226
floriane38f6412012-12-21 17:32:12 +00001227#define S390_CC_FOR_DFP128_RESULT(hi,lo) \
1228({ \
1229 __asm__ volatile ( \
floriancf1527c2012-12-27 20:59:43 +00001230 "ldr 4,%[high]\n\t" \
1231 "ldr 6,%[low]\n\t" \
1232 ".insn rre, 0xb3de0000,0,4\n\t" /* LTXTR */ \
1233 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1234 : [high] "f"(hi), [low] "f"(lo) \
1235 : "cc", "f0", "f2", "f4", "f6"); \
floriane38f6412012-12-21 17:32:12 +00001236 psw >> 28; /* cc */ \
1237})
1238
floriance9e3db2012-12-27 20:14:03 +00001239#define S390_CC_FOR_DFP_TD(opcode,cc_dep1,cc_dep2) \
1240({ \
1241 __asm__ volatile ( \
1242 opcode ",%[value],0(%[class])\n\t" \
1243 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1244 : [value] "f"(cc_dep1), \
1245 [class] "a"(cc_dep2) \
1246 : "cc"); \
1247 psw >> 28; /* cc */ \
1248})
1249
1250#define S390_CC_FOR_DFP128_TD(opcode,cc_dep1,cc_dep2,cc_ndep) \
1251({ \
1252 /* Recover the original DEP2 value. See comment near \
1253 s390_cc_thunk_put1d128Z for rationale. */ \
1254 cc_dep2 = cc_dep2 ^ cc_ndep; \
1255 __asm__ volatile ( \
1256 "ldr 4,%[high]\n\t" \
1257 "ldr 6,%[low]\n\t" \
1258 opcode ",4,0(%[class])\n\t" \
1259 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1260 : [high] "f"(cc_dep1), [low] "f"(cc_dep2), \
1261 [class] "a"(cc_ndep) \
1262 : "cc", "f4", "f6"); \
1263 psw >> 28; /* cc */ \
1264})
1265
florian5f034622013-01-13 02:29:05 +00001266#define S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,rounding_mode) \
1267 ({ \
1268 __asm__ volatile ( \
1269 opcode ",0,%[op]," #rounding_mode ",0\n\t" \
1270 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1271 : [op] "f"(cc_dep1) \
1272 : "cc", "r0"); \
1273 psw >> 28; /* cc */ \
1274 })
1275
1276#define S390_CC_FOR_DFP_CONVERT(opcode,cc_dep1,cc_dep2) \
1277 ({ \
1278 UInt cc; \
1279 switch (decode_dfp_rounding_mode(cc_dep2)) { \
1280 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1281 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1282 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,1); \
1283 break; \
1284 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1285 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1286 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,3); \
1287 break; \
1288 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1289 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1290 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,4); \
1291 break; \
1292 case S390_DFP_ROUND_ZERO_5: \
1293 case S390_DFP_ROUND_ZERO_9: \
1294 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,5); \
1295 break; \
1296 case S390_DFP_ROUND_POSINF_6: \
1297 case S390_DFP_ROUND_POSINF_10: \
1298 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,6); \
1299 break; \
1300 case S390_DFP_ROUND_NEGINF_7: \
1301 case S390_DFP_ROUND_NEGINF_11: \
1302 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,7); \
1303 break; \
1304 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1305 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,13); \
1306 break; \
1307 case S390_DFP_ROUND_AWAY_0: \
1308 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,14); \
1309 break; \
1310 default: \
1311 vpanic("unexpected dfp rounding mode"); \
1312 } \
1313 cc; \
1314 })
1315
1316#define S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,rounding_mode) \
1317 ({ \
1318 __asm__ volatile ( \
1319 opcode ",0,%[op]," #rounding_mode ",0\n\t" \
1320 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1321 : [op] "f"(cc_dep1) \
1322 : "cc", "r0"); \
1323 psw >> 28; /* cc */ \
1324 })
1325
1326#define S390_CC_FOR_DFP_UCONVERT(opcode,cc_dep1,cc_dep2) \
1327 ({ \
1328 UInt cc; \
1329 switch (decode_dfp_rounding_mode(cc_dep2)) { \
1330 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1331 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1332 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,1); \
1333 break; \
1334 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1335 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1336 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,3); \
1337 break; \
1338 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1339 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1340 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,4); \
1341 break; \
1342 case S390_DFP_ROUND_ZERO_5: \
1343 case S390_DFP_ROUND_ZERO_9: \
1344 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,5); \
1345 break; \
1346 case S390_DFP_ROUND_POSINF_6: \
1347 case S390_DFP_ROUND_POSINF_10: \
1348 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,6); \
1349 break; \
1350 case S390_DFP_ROUND_NEGINF_7: \
1351 case S390_DFP_ROUND_NEGINF_11: \
1352 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,7); \
1353 break; \
1354 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1355 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,13); \
1356 break; \
1357 case S390_DFP_ROUND_AWAY_0: \
1358 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,14); \
1359 break; \
1360 default: \
1361 vpanic("unexpected dfp rounding mode"); \
1362 } \
1363 cc; \
1364 })
1365
1366#define S390_CC_FOR_DFP128_CONVERT_AUX(opcode,hi,lo,rounding_mode) \
1367 ({ \
1368 __asm__ volatile ( \
1369 "ldr 4,%[high]\n\t" \
1370 "ldr 6,%[low]\n\t" \
1371 opcode ",0,4," #rounding_mode ",0\n\t" \
1372 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1373 : [high] "f"(hi), [low] "f"(lo) \
1374 : "cc", "r0", "f4", "f6"); \
1375 psw >> 28; /* cc */ \
1376 })
1377
1378#define S390_CC_FOR_DFP128_CONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1379 ({ \
1380 UInt cc; \
1381 /* Recover the original DEP2 value. See comment near \
1382 s390_cc_thunk_put3 for rationale. */ \
1383 cc_dep2 = cc_dep2 ^ cc_ndep; \
1384 switch (decode_dfp_rounding_mode(cc_ndep)) { \
1385 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1386 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1387 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,1); \
1388 break; \
1389 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1390 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1391 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,3); \
1392 break; \
1393 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1394 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1395 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1396 break; \
1397 case S390_DFP_ROUND_ZERO_5: \
1398 case S390_DFP_ROUND_ZERO_9: \
1399 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1400 break; \
1401 case S390_DFP_ROUND_POSINF_6: \
1402 case S390_DFP_ROUND_POSINF_10: \
1403 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1404 break; \
1405 case S390_DFP_ROUND_NEGINF_7: \
1406 case S390_DFP_ROUND_NEGINF_11: \
1407 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1408 break; \
1409 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1410 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,13); \
1411 break; \
1412 case S390_DFP_ROUND_AWAY_0: \
1413 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,14); \
1414 break; \
1415 default: \
1416 vpanic("unexpected dfp rounding mode"); \
1417 } \
1418 cc; \
1419 })
1420
1421#define S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,hi,lo,rounding_mode) \
1422 ({ \
1423 __asm__ volatile ( \
1424 "ldr 4,%[high]\n\t" \
1425 "ldr 6,%[low]\n\t" \
1426 opcode ",0,4," #rounding_mode ",0\n\t" \
1427 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1428 : [high] "f"(hi), [low] "f"(lo) \
1429 : "cc", "r0", "f4", "f6"); \
1430 psw >> 28; /* cc */ \
1431 })
1432
1433#define S390_CC_FOR_DFP128_UCONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1434 ({ \
1435 UInt cc; \
1436 /* Recover the original DEP2 value. See comment near \
1437 s390_cc_thunk_put3 for rationale. */ \
1438 cc_dep2 = cc_dep2 ^ cc_ndep; \
1439 switch (decode_dfp_rounding_mode(cc_ndep)) { \
1440 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1441 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1442 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,1); \
1443 break; \
1444 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1445 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1446 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,3); \
1447 break; \
1448 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1449 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1450 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1451 break; \
1452 case S390_DFP_ROUND_ZERO_5: \
1453 case S390_DFP_ROUND_ZERO_9: \
1454 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1455 break; \
1456 case S390_DFP_ROUND_POSINF_6: \
1457 case S390_DFP_ROUND_POSINF_10: \
1458 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1459 break; \
1460 case S390_DFP_ROUND_NEGINF_7: \
1461 case S390_DFP_ROUND_NEGINF_11: \
1462 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1463 break; \
1464 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1465 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,13); \
1466 break; \
1467 case S390_DFP_ROUND_AWAY_0: \
1468 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,14); \
1469 break; \
1470 default: \
1471 vpanic("unexpected dfp rounding mode"); \
1472 } \
1473 cc; \
1474 })
1475
sewardj2019a972011-03-07 16:04:07 +00001476
1477/* Return the value of the condition code from the supplied thunk parameters.
1478 This is not the value of the PSW. It is the value of the 2 CC bits within
1479 the PSW. The returned value is thusly in the interval [0:3]. */
1480UInt
1481s390_calculate_cc(ULong cc_op, ULong cc_dep1, ULong cc_dep2, ULong cc_ndep)
1482{
1483#if defined(VGA_s390x)
1484 UInt psw;
1485
1486 switch (cc_op) {
1487
1488 case S390_CC_OP_BITWISE:
1489 return S390_CC_FOR_BINARY("ogr", cc_dep1, (ULong)0);
1490
1491 case S390_CC_OP_SIGNED_COMPARE:
1492 return S390_CC_FOR_BINARY("cgr", cc_dep1, cc_dep2);
1493
1494 case S390_CC_OP_UNSIGNED_COMPARE:
1495 return S390_CC_FOR_BINARY("clgr", cc_dep1, cc_dep2);
1496
1497 case S390_CC_OP_SIGNED_ADD_64:
1498 return S390_CC_FOR_BINARY("agr", cc_dep1, cc_dep2);
1499
1500 case S390_CC_OP_SIGNED_ADD_32:
1501 return S390_CC_FOR_BINARY("ar", cc_dep1, cc_dep2);
1502
1503 case S390_CC_OP_SIGNED_SUB_64:
1504 return S390_CC_FOR_BINARY("sgr", cc_dep1, cc_dep2);
1505
1506 case S390_CC_OP_SIGNED_SUB_32:
1507 return S390_CC_FOR_BINARY("sr", cc_dep1, cc_dep2);
1508
1509 case S390_CC_OP_UNSIGNED_ADD_64:
1510 return S390_CC_FOR_BINARY("algr", cc_dep1, cc_dep2);
1511
1512 case S390_CC_OP_UNSIGNED_ADD_32:
1513 return S390_CC_FOR_BINARY("alr", cc_dep1, cc_dep2);
1514
1515 case S390_CC_OP_UNSIGNED_ADDC_64:
1516 return S390_CC_FOR_TERNARY_ADDC("alcgr", cc_dep1, cc_dep2, cc_ndep);
1517
1518 case S390_CC_OP_UNSIGNED_ADDC_32:
1519 return S390_CC_FOR_TERNARY_ADDC("alcr", cc_dep1, cc_dep2, cc_ndep);
1520
1521 case S390_CC_OP_UNSIGNED_SUB_64:
1522 return S390_CC_FOR_BINARY("slgr", cc_dep1, cc_dep2);
1523
1524 case S390_CC_OP_UNSIGNED_SUB_32:
1525 return S390_CC_FOR_BINARY("slr", cc_dep1, cc_dep2);
1526
1527 case S390_CC_OP_UNSIGNED_SUBB_64:
1528 return S390_CC_FOR_TERNARY_SUBB("slbgr", cc_dep1, cc_dep2, cc_ndep);
1529
1530 case S390_CC_OP_UNSIGNED_SUBB_32:
1531 return S390_CC_FOR_TERNARY_SUBB("slbr", cc_dep1, cc_dep2, cc_ndep);
1532
1533 case S390_CC_OP_LOAD_AND_TEST:
1534 /* Like signed comparison with 0 */
1535 return S390_CC_FOR_BINARY("cgr", cc_dep1, (Long)0);
1536
sewardj2019a972011-03-07 16:04:07 +00001537 case S390_CC_OP_LOAD_POSITIVE_32:
1538 __asm__ volatile (
1539 "lpr %[result],%[op]\n\t"
florianae884112012-07-27 20:55:01 +00001540 "ipm %[psw]\n\t" : [psw] "=d"(psw), [result] "=d"(cc_dep1)
1541 : [op] "d"(cc_dep1)
1542 : "cc");
sewardj2019a972011-03-07 16:04:07 +00001543 return psw >> 28; /* cc */
1544
1545 case S390_CC_OP_LOAD_POSITIVE_64:
1546 __asm__ volatile (
1547 "lpgr %[result],%[op]\n\t"
florianae884112012-07-27 20:55:01 +00001548 "ipm %[psw]\n\t" : [psw] "=d"(psw), [result] "=d"(cc_dep1)
1549 : [op] "d"(cc_dep1)
1550 : "cc");
sewardj2019a972011-03-07 16:04:07 +00001551 return psw >> 28; /* cc */
1552
1553 case S390_CC_OP_TEST_UNDER_MASK_8: {
1554 UChar value = cc_dep1;
1555 UChar mask = cc_dep2;
1556
1557 __asm__ volatile (
1558 "bras %%r2,1f\n\t" /* %r2 = address of next insn */
1559 "tm %[value],0\n\t" /* this is skipped, then EXecuted */
1560 "1: ex %[mask],0(%%r2)\n\t" /* EXecute TM after modifying mask */
1561 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1562 : [value] "m"(value), [mask] "a"(mask)
1563 : "r2", "cc");
1564 return psw >> 28; /* cc */
1565 }
1566
1567 case S390_CC_OP_TEST_UNDER_MASK_16: {
1568 /* Create a TMLL insn with the mask as given by cc_dep2 */
florian8cf66372015-02-09 23:21:07 +00001569 UInt insn = (0xA701u << 16) | cc_dep2;
sewardj2019a972011-03-07 16:04:07 +00001570 UInt value = cc_dep1;
1571
1572 __asm__ volatile (
1573 "lr 1,%[value]\n\t"
1574 "lhi 2,0x10\n\t"
1575 "ex 2,%[insn]\n\t"
1576 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1577 : [value] "d"(value), [insn] "m"(insn)
1578 : "r1", "r2", "cc");
1579 return psw >> 28; /* cc */
1580 }
1581
1582 case S390_CC_OP_SHIFT_LEFT_32:
1583 __asm__ volatile (
1584 "sla %[op],0(%[amount])\n\t"
1585 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op] "+d"(cc_dep1)
1586 : [amount] "a"(cc_dep2)
1587 : "cc");
1588 return psw >> 28; /* cc */
1589
1590 case S390_CC_OP_SHIFT_LEFT_64: {
1591 Int high = (Int)(cc_dep1 >> 32);
1592 Int low = (Int)(cc_dep1 & 0xFFFFFFFF);
1593
1594 __asm__ volatile (
1595 "lr 2,%[high]\n\t"
1596 "lr 3,%[low]\n\t"
1597 "slda 2,0(%[amount])\n\t"
florianae884112012-07-27 20:55:01 +00001598 "ipm %[psw]\n\t" : [psw] "=d"(psw), [high] "+d"(high),
1599 [low] "+d"(low)
sewardj2019a972011-03-07 16:04:07 +00001600 : [amount] "a"(cc_dep2)
1601 : "cc", "r2", "r3");
1602 return psw >> 28; /* cc */
1603 }
1604
1605 case S390_CC_OP_INSERT_CHAR_MASK_32: {
1606 Int inserted = 0;
1607 Int msb = 0;
1608
1609 if (cc_dep2 & 1) {
1610 inserted |= cc_dep1 & 0xff;
1611 msb = 0x80;
1612 }
1613 if (cc_dep2 & 2) {
1614 inserted |= cc_dep1 & 0xff00;
1615 msb = 0x8000;
1616 }
1617 if (cc_dep2 & 4) {
1618 inserted |= cc_dep1 & 0xff0000;
1619 msb = 0x800000;
1620 }
1621 if (cc_dep2 & 8) {
1622 inserted |= cc_dep1 & 0xff000000;
1623 msb = 0x80000000;
1624 }
1625
1626 if (inserted & msb) // MSB is 1
1627 return 1;
1628 if (inserted > 0)
1629 return 2;
1630 return 0;
1631 }
1632
1633 case S390_CC_OP_BFP_RESULT_32:
1634 return S390_CC_FOR_BFP_RESULT("ltebr", cc_dep1);
1635
1636 case S390_CC_OP_BFP_RESULT_64:
1637 return S390_CC_FOR_BFP_RESULT("ltdbr", cc_dep1);
1638
1639 case S390_CC_OP_BFP_RESULT_128:
1640 return S390_CC_FOR_BFP128_RESULT(cc_dep1, cc_dep2);
1641
1642 case S390_CC_OP_BFP_32_TO_INT_32:
florian19e00772012-09-06 03:13:22 +00001643 return S390_CC_FOR_BFP_CONVERT("cfebr", cc_dep1, cc_dep2);
sewardj2019a972011-03-07 16:04:07 +00001644
1645 case S390_CC_OP_BFP_64_TO_INT_32:
florian19e00772012-09-06 03:13:22 +00001646 return S390_CC_FOR_BFP_CONVERT("cfdbr", cc_dep1, cc_dep2);
sewardj2019a972011-03-07 16:04:07 +00001647
1648 case S390_CC_OP_BFP_128_TO_INT_32:
florian19e00772012-09-06 03:13:22 +00001649 return S390_CC_FOR_BFP128_CONVERT("cfxbr", cc_dep1, cc_dep2, cc_ndep);
sewardj2019a972011-03-07 16:04:07 +00001650
1651 case S390_CC_OP_BFP_32_TO_INT_64:
florian19e00772012-09-06 03:13:22 +00001652 return S390_CC_FOR_BFP_CONVERT("cgebr", cc_dep1, cc_dep2);
sewardj2019a972011-03-07 16:04:07 +00001653
1654 case S390_CC_OP_BFP_64_TO_INT_64:
florian19e00772012-09-06 03:13:22 +00001655 return S390_CC_FOR_BFP_CONVERT("cgdbr", cc_dep1, cc_dep2);
sewardj2019a972011-03-07 16:04:07 +00001656
1657 case S390_CC_OP_BFP_128_TO_INT_64:
florian19e00772012-09-06 03:13:22 +00001658 return S390_CC_FOR_BFP128_CONVERT("cgxbr", cc_dep1, cc_dep2, cc_ndep);
sewardj2019a972011-03-07 16:04:07 +00001659
1660 case S390_CC_OP_BFP_TDC_32:
1661 return S390_CC_FOR_BFP_TDC("tceb", cc_dep1, cc_dep2);
1662
1663 case S390_CC_OP_BFP_TDC_64:
1664 return S390_CC_FOR_BFP_TDC("tcdb", cc_dep1, cc_dep2);
1665
1666 case S390_CC_OP_BFP_TDC_128:
1667 return S390_CC_FOR_BFP128_TDC(cc_dep1, cc_dep2, cc_ndep);
1668
1669 case S390_CC_OP_SET:
1670 return cc_dep1;
1671
florian1c8f7ff2012-09-01 00:12:11 +00001672 case S390_CC_OP_BFP_32_TO_UINT_32:
florian19e00772012-09-06 03:13:22 +00001673 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb39c0000", cc_dep1, cc_dep2);
florian1c8f7ff2012-09-01 00:12:11 +00001674
1675 case S390_CC_OP_BFP_64_TO_UINT_32:
florian19e00772012-09-06 03:13:22 +00001676 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb39d0000", cc_dep1, cc_dep2);
florian1c8f7ff2012-09-01 00:12:11 +00001677
1678 case S390_CC_OP_BFP_128_TO_UINT_32:
florian19e00772012-09-06 03:13:22 +00001679 return S390_CC_FOR_BFP128_UCONVERT(".insn rrf,0xb39e0000", cc_dep1,
1680 cc_dep2, cc_ndep);
florian1c8f7ff2012-09-01 00:12:11 +00001681
1682 case S390_CC_OP_BFP_32_TO_UINT_64:
florian19e00772012-09-06 03:13:22 +00001683 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb3ac0000", cc_dep1, cc_dep2);
florian1c8f7ff2012-09-01 00:12:11 +00001684
1685 case S390_CC_OP_BFP_64_TO_UINT_64:
florian19e00772012-09-06 03:13:22 +00001686 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb3ad0000", cc_dep1, cc_dep2);
florian1c8f7ff2012-09-01 00:12:11 +00001687
1688 case S390_CC_OP_BFP_128_TO_UINT_64:
florian19e00772012-09-06 03:13:22 +00001689 return S390_CC_FOR_BFP128_UCONVERT(".insn rrf,0xb3ae0000", cc_dep1,
1690 cc_dep2, cc_ndep);
florian1c8f7ff2012-09-01 00:12:11 +00001691
florian12390202012-11-10 22:34:14 +00001692 case S390_CC_OP_DFP_RESULT_64:
1693 return S390_CC_FOR_DFP_RESULT(cc_dep1);
florian1c8f7ff2012-09-01 00:12:11 +00001694
floriane38f6412012-12-21 17:32:12 +00001695 case S390_CC_OP_DFP_RESULT_128:
1696 return S390_CC_FOR_DFP128_RESULT(cc_dep1, cc_dep2);
1697
floriance9e3db2012-12-27 20:14:03 +00001698 case S390_CC_OP_DFP_TDC_32: /* TDCET */
1699 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000050", cc_dep1, cc_dep2);
1700
1701 case S390_CC_OP_DFP_TDC_64: /* TDCDT */
1702 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000054", cc_dep1, cc_dep2);
1703
1704 case S390_CC_OP_DFP_TDC_128: /* TDCXT */
1705 return S390_CC_FOR_DFP128_TD(".insn rxe, 0xed0000000058", cc_dep1,
1706 cc_dep2, cc_ndep);
1707
1708 case S390_CC_OP_DFP_TDG_32: /* TDGET */
1709 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000051", cc_dep1, cc_dep2);
1710
1711 case S390_CC_OP_DFP_TDG_64: /* TDGDT */
1712 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000055", cc_dep1, cc_dep2);
1713
1714 case S390_CC_OP_DFP_TDG_128: /* TDGXT */
1715 return S390_CC_FOR_DFP128_TD(".insn rxe, 0xed0000000059", cc_dep1,
1716 cc_dep2, cc_ndep);
1717
florian5f034622013-01-13 02:29:05 +00001718 case S390_CC_OP_DFP_64_TO_INT_32: /* CFDTR */
1719 return S390_CC_FOR_DFP_CONVERT(".insn rrf,0xb9410000", cc_dep1, cc_dep2);
1720
1721 case S390_CC_OP_DFP_128_TO_INT_32: /* CFXTR */
1722 return S390_CC_FOR_DFP128_CONVERT(".insn rrf,0xb9490000", cc_dep1,
1723 cc_dep2, cc_ndep);
1724
floriana887acd2013-02-08 23:32:54 +00001725 case S390_CC_OP_DFP_64_TO_INT_64: /* CGDTR */
1726 return S390_CC_FOR_DFP_CONVERT(".insn rrf,0xb3e10000", cc_dep1, cc_dep2);
1727
1728 case S390_CC_OP_DFP_128_TO_INT_64: /* CGXTR */
1729 return S390_CC_FOR_DFP128_CONVERT(".insn rrf,0xb3e90000", cc_dep1,
1730 cc_dep2, cc_ndep);
1731
florian5f034622013-01-13 02:29:05 +00001732 case S390_CC_OP_DFP_64_TO_UINT_32: /* CLFDTR */
1733 return S390_CC_FOR_DFP_UCONVERT(".insn rrf,0xb9430000", cc_dep1, cc_dep2);
1734
1735 case S390_CC_OP_DFP_128_TO_UINT_32: /* CLFXTR */
1736 return S390_CC_FOR_DFP128_UCONVERT(".insn rrf,0xb94b0000", cc_dep1,
1737 cc_dep2, cc_ndep);
1738
1739 case S390_CC_OP_DFP_64_TO_UINT_64: /* CLGDTR */
1740 return S390_CC_FOR_DFP_UCONVERT(".insn rrf,0xb9420000", cc_dep1, cc_dep2);
1741
1742 case S390_CC_OP_DFP_128_TO_UINT_64: /* CLGXTR */
1743 return S390_CC_FOR_DFP128_UCONVERT(".insn rrf,0xb94a0000", cc_dep1,
1744 cc_dep2, cc_ndep);
1745
florian7ab421d2013-06-17 21:03:56 +00001746 case S390_CC_OP_PFPO_32: {
1747 __asm__ volatile(
1748 "ler 4, %[cc_dep1]\n\t" /* 32 bit FR move */
1749 "lr 0, %[cc_dep2]\n\t" /* 32 bit GR move */
1750 ".short 0x010a\n\t" /* PFPO */
1751 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1752 : [cc_dep1] "f"(cc_dep1),
1753 [cc_dep2] "d"(cc_dep2)
1754 : "r0", "r1", "f4");
1755 return psw >> 28; /* cc */
1756 }
1757
florian78d5ef72013-05-11 15:02:58 +00001758 case S390_CC_OP_PFPO_64: {
1759 __asm__ volatile(
1760 "ldr 4, %[cc_dep1]\n\t"
1761 "lr 0, %[cc_dep2]\n\t" /* 32 bit register move */
1762 ".short 0x010a\n\t" /* PFPO */
1763 "ipm %[psw]\n\t" : [psw] "=d"(psw)
florianc5892282013-05-12 13:57:13 +00001764 : [cc_dep1] "f"(cc_dep1),
1765 [cc_dep2] "d"(cc_dep2)
florian78d5ef72013-05-11 15:02:58 +00001766 : "r0", "r1", "f4");
1767 return psw >> 28; /* cc */
1768 }
1769
1770 case S390_CC_OP_PFPO_128: {
1771 __asm__ volatile(
1772 "ldr 4,%[cc_dep1]\n\t"
1773 "ldr 6,%[cc_dep2]\n\t"
1774 "lr 0,%[cc_ndep]\n\t" /* 32 bit register move */
1775 ".short 0x010a\n\t" /* PFPO */
1776 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1777 : [cc_dep1] "f"(cc_dep1),
1778 [cc_dep2] "f"(cc_dep2),
1779 [cc_ndep] "d"(cc_ndep)
1780 : "r0", "r1", "f0", "f2", "f4", "f6");
1781 return psw >> 28; /* cc */
1782 }
1783
sewardj2019a972011-03-07 16:04:07 +00001784 default:
1785 break;
1786 }
1787#endif
1788 vpanic("s390_calculate_cc");
1789}
1790
1791
sewardj2019a972011-03-07 16:04:07 +00001792/* Note that this does *not* return a Boolean value. The result needs to be
1793 explicitly tested against zero. */
1794UInt
1795s390_calculate_cond(ULong mask, ULong op, ULong dep1, ULong dep2, ULong ndep)
1796{
1797 UInt cc = s390_calculate_cc(op, dep1, dep2, ndep);
1798
1799 return ((mask << cc) & 0x8);
1800}
1801
1802/*------------------------------------------------------------*/
1803/*--- spechelper for performance ---*/
1804/*------------------------------------------------------------*/
1805
1806
1807/* Convenience macros */
1808#define unop(op,a1) IRExpr_Unop((op),(a1))
1809#define binop(op,a1,a2) IRExpr_Binop((op),(a1),(a2))
1810#define mkU64(v) IRExpr_Const(IRConst_U64(v))
1811#define mkU32(v) IRExpr_Const(IRConst_U32(v))
1812#define mkU8(v) IRExpr_Const(IRConst_U8(v))
1813
1814
1815static inline Bool
florian49adf862014-12-06 20:24:08 +00001816isC64(const IRExpr *expr)
sewardj2019a972011-03-07 16:04:07 +00001817{
1818 return expr->tag == Iex_Const && expr->Iex.Const.con->tag == Ico_U64;
1819}
1820
1821
1822/* The returned expression is NULL if no specialization was found. In that
1823 case the helper function will be called. Otherwise, the expression has
1824 type Ity_I32 and a Boolean value. */
1825IRExpr *
florian1ff47562012-10-21 02:09:51 +00001826guest_s390x_spechelper(const HChar *function_name, IRExpr **args,
sewardj2019a972011-03-07 16:04:07 +00001827 IRStmt **precedingStmts, Int n_precedingStmts)
1828{
1829 UInt i, arity = 0;
1830
1831 for (i = 0; args[i]; i++)
1832 arity++;
1833
1834# if 0
1835 vex_printf("spec request:\n");
1836 vex_printf(" %s ", function_name);
1837 for (i = 0; i < arity; i++) {
1838 vex_printf(" ");
1839 ppIRExpr(args[i]);
1840 }
1841 vex_printf("\n");
1842# endif
1843
1844 /* --------- Specialising "s390_calculate_cond" --------- */
1845
1846 if (vex_streq(function_name, "s390_calculate_cond")) {
1847 IRExpr *cond_expr, *cc_op_expr, *cc_dep1, *cc_dep2;
1848 ULong cond, cc_op;
1849
1850 vassert(arity == 5);
1851
1852 cond_expr = args[0];
1853 cc_op_expr = args[1];
1854
1855 /* The necessary requirement for all optimizations here is that the
1856 condition and the cc_op are constant. So check that upfront. */
1857 if (! isC64(cond_expr)) return NULL;
1858 if (! isC64(cc_op_expr)) return NULL;
1859
1860 cond = cond_expr->Iex.Const.con->Ico.U64;
1861 cc_op = cc_op_expr->Iex.Const.con->Ico.U64;
1862
1863 vassert(cond <= 15);
1864
1865 /*
1866 +------+---+---+---+---+
1867 | cc | 0 | 1 | 2 | 3 |
1868 | cond | 8 | 4 | 2 | 1 |
1869 +------+---+---+---+---+
1870 */
1871 cc_dep1 = args[2];
1872 cc_dep2 = args[3];
1873
1874 /* S390_CC_OP_SIGNED_COMPARE */
1875 if (cc_op == S390_CC_OP_SIGNED_COMPARE) {
1876 /*
1877 cc == 0 --> cc_dep1 == cc_dep2 (cond == 8)
1878 cc == 1 --> cc_dep1 < cc_dep2 (cond == 4)
1879 cc == 2 --> cc_dep1 > cc_dep2 (cond == 2)
1880
1881 Because cc == 3 cannot occur the rightmost bit of cond is
1882 a don't care.
1883 */
1884 if (cond == 8 || cond == 8 + 1) {
1885 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
1886 }
1887 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
1888 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, cc_dep2));
1889 }
1890 if (cond == 4 || cond == 4 + 1) {
1891 return unop(Iop_1Uto32, binop(Iop_CmpLT64S, cc_dep1, cc_dep2));
1892 }
1893 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
1894 return unop(Iop_1Uto32, binop(Iop_CmpLE64S, cc_dep1, cc_dep2));
1895 }
1896 /* cc_dep1 > cc_dep2 ----> cc_dep2 < cc_dep1 */
1897 if (cond == 2 || cond == 2 + 1) {
1898 return unop(Iop_1Uto32, binop(Iop_CmpLT64S, cc_dep2, cc_dep1));
1899 }
1900 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
1901 return unop(Iop_1Uto32, binop(Iop_CmpLE64S, cc_dep2, cc_dep1));
1902 }
1903 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
1904 return mkU32(1);
1905 }
1906 /* Remaining case */
1907 return mkU32(0);
1908 }
1909
1910 /* S390_CC_OP_UNSIGNED_COMPARE */
1911 if (cc_op == S390_CC_OP_UNSIGNED_COMPARE) {
1912 /*
1913 cc == 0 --> cc_dep1 == cc_dep2 (cond == 8)
1914 cc == 1 --> cc_dep1 < cc_dep2 (cond == 4)
1915 cc == 2 --> cc_dep1 > cc_dep2 (cond == 2)
1916
1917 Because cc == 3 cannot occur the rightmost bit of cond is
1918 a don't care.
1919 */
1920 if (cond == 8 || cond == 8 + 1) {
1921 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
1922 }
1923 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
1924 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, cc_dep2));
1925 }
1926 if (cond == 4 || cond == 4 + 1) {
1927 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep1, cc_dep2));
1928 }
1929 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
1930 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep1, cc_dep2));
1931 }
1932 /* cc_dep1 > cc_dep2 ----> cc_dep2 < cc_dep1 */
1933 if (cond == 2 || cond == 2 + 1) {
1934 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep2, cc_dep1));
1935 }
1936 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
1937 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep2, cc_dep1));
1938 }
1939 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
1940 return mkU32(1);
1941 }
1942 /* Remaining case */
1943 return mkU32(0);
1944 }
1945
1946 /* S390_CC_OP_LOAD_AND_TEST */
1947 if (cc_op == S390_CC_OP_LOAD_AND_TEST) {
1948 /*
1949 cc == 0 --> cc_dep1 == 0 (cond == 8)
1950 cc == 1 --> cc_dep1 < 0 (cond == 4)
1951 cc == 2 --> cc_dep1 > 0 (cond == 2)
1952
1953 Because cc == 3 cannot occur the rightmost bit of cond is
1954 a don't care.
1955 */
1956 if (cond == 8 || cond == 8 + 1) {
1957 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, mkU64(0)));
1958 }
1959 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
1960 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, mkU64(0)));
1961 }
1962 if (cond == 4 || cond == 4 + 1) {
cborntra18bf1542015-02-05 11:05:10 +00001963 /* Special case cc_dep < 0. Only check the MSB to avoid bogus
1964 memcheck complaints due to gcc magic. Fixes 343802
1965 */
1966 return unop(Iop_64to32, binop(Iop_Shr64, cc_dep1, mkU8(63)));
sewardj2019a972011-03-07 16:04:07 +00001967 }
1968 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
1969 return unop(Iop_1Uto32, binop(Iop_CmpLE64S, cc_dep1, mkU64(0)));
1970 }
1971 /* cc_dep1 > 0 ----> 0 < cc_dep1 */
1972 if (cond == 2 || cond == 2 + 1) {
1973 return unop(Iop_1Uto32, binop(Iop_CmpLT64S, mkU64(0), cc_dep1));
1974 }
1975 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
florian25e1cb22012-11-25 01:22:27 +00001976 /* Special case cc_dep >= 0. Only check the MSB to avoid bogus
1977 memcheck complaints due to gcc magic. Fixes 308427
cborntrad7f19c02012-10-15 14:03:20 +00001978 */
florian25e1cb22012-11-25 01:22:27 +00001979 return unop(Iop_64to32, binop(Iop_Xor64,
1980 binop(Iop_Shr64, cc_dep1, mkU8(63)),
1981 mkU64(1)));
sewardj2019a972011-03-07 16:04:07 +00001982 }
1983 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
1984 return mkU32(1);
1985 }
1986 /* Remaining case */
1987 return mkU32(0);
1988 }
1989
1990 /* S390_CC_OP_BITWISE */
1991 if (cc_op == S390_CC_OP_BITWISE) {
1992 /*
1993 cc_dep1 is the result of the boolean operation.
1994
1995 cc == 0 --> cc_dep1 == 0 (cond == 8)
1996 cc == 1 --> cc_dep1 != 0 (cond == 4)
1997
1998 Because cc == 2 and cc == 3 cannot occur the two rightmost bits of
1999 cond are don't cares. Therefore:
2000
2001 cond == 00xx -> always false
2002 cond == 01xx -> not equal
2003 cond == 10xx -> equal
2004 cond == 11xx -> always true
2005 */
2006 if ((cond & (8 + 4)) == 8 + 4) {
2007 return mkU32(1);
2008 }
2009 if (cond & 8) {
2010 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, mkU64(0)));
2011 }
2012 if (cond & 4) {
2013 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, mkU64(0)));
2014 }
2015 /* Remaining case */
2016 return mkU32(0);
2017 }
2018
2019 /* S390_CC_OP_INSERT_CHAR_MASK_32
2020 Since the mask comes from an immediate field in the opcode, we
2021 expect the mask to be a constant here. That simplifies matters. */
2022 if (cc_op == S390_CC_OP_INSERT_CHAR_MASK_32) {
2023 ULong mask;
2024 UInt imask = 0, shift = 0;
2025 IRExpr *word;
2026
2027 if (! isC64(cc_dep2)) goto missed;
2028
2029 mask = cc_dep2->Iex.Const.con->Ico.U64;
2030
2031 /* Extract the 32-bit value from the thunk */
2032
2033 word = unop(Iop_64to32, cc_dep1);
2034
2035 switch (mask) {
2036 case 0: shift = 0; imask = 0x00000000; break;
2037 case 1: shift = 24; imask = 0x000000FF; break;
2038 case 2: shift = 16; imask = 0x0000FF00; break;
2039 case 3: shift = 16; imask = 0x0000FFFF; break;
2040 case 4: shift = 8; imask = 0x00FF0000; break;
2041 case 5: shift = 8; imask = 0x00FF00FF; break;
2042 case 6: shift = 8; imask = 0x00FFFF00; break;
2043 case 7: shift = 8; imask = 0x00FFFFFF; break;
2044 case 8: shift = 0; imask = 0xFF000000; break;
2045 case 9: shift = 0; imask = 0xFF0000FF; break;
2046 case 10: shift = 0; imask = 0xFF00FF00; break;
2047 case 11: shift = 0; imask = 0xFF00FFFF; break;
2048 case 12: shift = 0; imask = 0xFFFF0000; break;
2049 case 13: shift = 0; imask = 0xFFFF00FF; break;
2050 case 14: shift = 0; imask = 0xFFFFFF00; break;
2051 case 15: shift = 0; imask = 0xFFFFFFFF; break;
2052 }
2053
2054 /* Select the bits that were inserted */
2055 word = binop(Iop_And32, word, mkU32(imask));
2056
2057 /* cc == 0 --> all inserted bits zero or mask == 0 (cond == 8)
2058 cc == 1 --> leftmost inserted bit is one (cond == 4)
2059 cc == 2 --> leftmost inserted bit is zero and not (cond == 2)
2060 all inserted bits are zero
2061
2062 Because cc == 0,1,2 the rightmost bit of the mask is a don't care */
2063 if (cond == 8 || cond == 8 + 1) {
2064 return unop(Iop_1Uto32, binop(Iop_CmpEQ32, word, mkU32(0)));
2065 }
2066 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
2067 return unop(Iop_1Uto32, binop(Iop_CmpNE32, word, mkU32(0)));
2068 }
2069
2070 /* Sign extend */
2071 if (shift != 0) {
2072 word = binop(Iop_Sar32, binop(Iop_Shl32, word, mkU8(shift)),
2073 mkU8(shift));
2074 }
2075
2076 if (cond == 4 || cond == 4 + 1) { /* word < 0 */
2077 return unop(Iop_1Uto32, binop(Iop_CmpLT32S, word, mkU32(0)));
2078 }
2079 if (cond == 2 || cond == 2 + 1) { /* word > 0 */
2080 return unop(Iop_1Uto32, binop(Iop_CmpLT32S, mkU32(0), word));
2081 }
2082 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
2083 return unop(Iop_1Uto32, binop(Iop_CmpLE32S, word, mkU32(0)));
2084 }
2085 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
2086 return unop(Iop_1Uto32, binop(Iop_CmpLE32S, mkU32(0), word));
2087 }
2088 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
2089 return mkU32(1);
2090 }
2091 /* Remaining case */
2092 return mkU32(0);
2093 }
2094
2095 /* S390_CC_OP_TEST_UNDER_MASK_8
2096 Since the mask comes from an immediate field in the opcode, we
2097 expect the mask to be a constant here. That simplifies matters. */
2098 if (cc_op == S390_CC_OP_TEST_UNDER_MASK_8) {
2099 ULong mask16;
2100
2101 if (! isC64(cc_dep2)) goto missed;
2102
2103 mask16 = cc_dep2->Iex.Const.con->Ico.U64;
2104
2105 /* Get rid of the mask16 == 0 case first. Some of the simplifications
2106 below (e.g. for OVFL) only hold if mask16 == 0. */
2107 if (mask16 == 0) { /* cc == 0 */
2108 if (cond & 0x8) return mkU32(1);
2109 return mkU32(0);
2110 }
2111
2112 /* cc == 2 is a don't care */
2113 if (cond == 8 || cond == 8 + 2) {
2114 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2115 binop(Iop_And64, cc_dep1, cc_dep2),
2116 mkU64(0)));
2117 }
2118 if (cond == 7 || cond == 7 - 2) {
2119 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2120 binop(Iop_And64, cc_dep1, cc_dep2),
2121 mkU64(0)));
2122 }
2123 if (cond == 1 || cond == 1 + 2) {
2124 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2125 binop(Iop_And64, cc_dep1, cc_dep2),
2126 cc_dep2));
2127 }
2128 if (cond == 14 || cond == 14 - 2) { /* ! OVFL */
2129 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2130 binop(Iop_And64, cc_dep1, cc_dep2),
2131 cc_dep2));
2132 }
2133 goto missed;
2134 }
2135
2136 /* S390_CC_OP_TEST_UNDER_MASK_16
2137 Since the mask comes from an immediate field in the opcode, we
2138 expect the mask to be a constant here. That simplifies matters. */
2139 if (cc_op == S390_CC_OP_TEST_UNDER_MASK_16) {
2140 ULong mask16;
2141 UInt msb;
2142
2143 if (! isC64(cc_dep2)) goto missed;
2144
2145 mask16 = cc_dep2->Iex.Const.con->Ico.U64;
2146
2147 /* Get rid of the mask16 == 0 case first. Some of the simplifications
2148 below (e.g. for OVFL) only hold if mask16 == 0. */
2149 if (mask16 == 0) { /* cc == 0 */
2150 if (cond & 0x8) return mkU32(1);
2151 return mkU32(0);
2152 }
2153
florian9ec12ea2015-09-08 06:25:02 +00002154 if (cond == 15) return mkU32(1);
2155
sewardj2019a972011-03-07 16:04:07 +00002156 if (cond == 8) {
2157 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2158 binop(Iop_And64, cc_dep1, cc_dep2),
2159 mkU64(0)));
2160 }
2161 if (cond == 7) {
2162 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2163 binop(Iop_And64, cc_dep1, cc_dep2),
2164 mkU64(0)));
2165 }
2166 if (cond == 1) {
2167 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2168 binop(Iop_And64, cc_dep1, cc_dep2),
2169 mkU64(mask16)));
2170 }
2171 if (cond == 14) { /* ! OVFL */
2172 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2173 binop(Iop_And64, cc_dep1, cc_dep2),
2174 mkU64(mask16)));
2175 }
2176
2177 /* Find MSB in mask */
2178 msb = 0x8000;
2179 while (msb > mask16)
2180 msb >>= 1;
2181
2182 if (cond == 2) { /* cc == 2 */
2183 IRExpr *c1, *c2;
2184
2185 /* (cc_dep & msb) != 0 && (cc_dep & mask16) != mask16 */
2186 c1 = binop(Iop_CmpNE64,
2187 binop(Iop_And64, cc_dep1, mkU64(msb)), mkU64(0));
2188 c2 = binop(Iop_CmpNE64,
2189 binop(Iop_And64, cc_dep1, cc_dep2),
2190 mkU64(mask16));
2191 return binop(Iop_And32, unop(Iop_1Uto32, c1),
2192 unop(Iop_1Uto32, c2));
2193 }
2194
2195 if (cond == 4) { /* cc == 1 */
2196 IRExpr *c1, *c2;
2197
2198 /* (cc_dep & msb) == 0 && (cc_dep & mask16) != 0 */
2199 c1 = binop(Iop_CmpEQ64,
2200 binop(Iop_And64, cc_dep1, mkU64(msb)), mkU64(0));
2201 c2 = binop(Iop_CmpNE64,
2202 binop(Iop_And64, cc_dep1, cc_dep2),
2203 mkU64(0));
2204 return binop(Iop_And32, unop(Iop_1Uto32, c1),
2205 unop(Iop_1Uto32, c2));
2206 }
2207
2208 if (cond == 11) { /* cc == 0,2,3 */
2209 IRExpr *c1, *c2;
2210
2211 c1 = binop(Iop_CmpNE64,
2212 binop(Iop_And64, cc_dep1, mkU64(msb)), mkU64(0));
2213 c2 = binop(Iop_CmpEQ64,
2214 binop(Iop_And64, cc_dep1, cc_dep2),
2215 mkU64(0));
2216 return binop(Iop_Or32, unop(Iop_1Uto32, c1),
2217 unop(Iop_1Uto32, c2));
2218 }
2219
2220 if (cond == 3) { /* cc == 2 || cc == 3 */
2221 return unop(Iop_1Uto32,
2222 binop(Iop_CmpNE64,
2223 binop(Iop_And64, cc_dep1, mkU64(msb)),
2224 mkU64(0)));
2225 }
2226 if (cond == 12) { /* cc == 0 || cc == 1 */
2227 return unop(Iop_1Uto32,
2228 binop(Iop_CmpEQ64,
2229 binop(Iop_And64, cc_dep1, mkU64(msb)),
2230 mkU64(0)));
2231 }
florian9ec12ea2015-09-08 06:25:02 +00002232 if (cond == 13) { /* cc == 0 || cc == 1 || cc == 3 */
2233 IRExpr *c01, *c3;
2234
2235 c01 = binop(Iop_CmpEQ64, binop(Iop_And64, cc_dep1, mkU64(msb)),
2236 mkU64(0));
2237 c3 = binop(Iop_CmpEQ64, binop(Iop_And64, cc_dep1, cc_dep2),
2238 mkU64(mask16));
2239 return binop(Iop_Or32, unop(Iop_1Uto32, c01),
2240 unop(Iop_1Uto32, c3));
2241 }
2242 // fixs390: handle cond = 5,6,9,10 (the missing cases)
sewardj2019a972011-03-07 16:04:07 +00002243 // vex_printf("TUM mask = 0x%llx\n", mask16);
2244 goto missed;
2245 }
2246
2247 /* S390_CC_OP_UNSIGNED_SUB_64/32 */
2248 if (cc_op == S390_CC_OP_UNSIGNED_SUB_64 ||
2249 cc_op == S390_CC_OP_UNSIGNED_SUB_32) {
2250 /*
2251 cc_dep1, cc_dep2 are the zero extended left and right operands
2252
2253 cc == 1 --> result != 0, borrow (cond == 4)
2254 cc == 2 --> result == 0, no borrow (cond == 2)
2255 cc == 3 --> result != 0, no borrow (cond == 1)
2256
2257 cc = (cc_dep1 == cc_dep2) ? 2
2258 : (cc_dep1 > cc_dep2) ? 3 : 1;
2259
2260 Because cc == 0 cannot occur the leftmost bit of cond is
2261 a don't care.
2262 */
2263 if (cond == 1 || cond == 1 + 8) { /* cc == 3 op2 < op1 */
2264 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep2, cc_dep1));
2265 }
2266 if (cond == 2 || cond == 2 + 8) { /* cc == 2 */
2267 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
2268 }
2269 if (cond == 4 || cond == 4 + 8) { /* cc == 1 */
2270 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep1, cc_dep2));
2271 }
2272 if (cond == 3 || cond == 3 + 8) { /* cc == 2 || cc == 3 */
2273 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep2, cc_dep1));
2274 }
2275 if (cond == 6 || cond == 6 + 8) { /* cc == 2 || cc == 1 */
2276 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep1, cc_dep2));
2277 }
2278
2279 if (cond == 5 || cond == 5 + 8) { /* cc == 3 || cc == 1 */
2280 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, cc_dep2));
2281 }
2282 if (cond == 7 || cond == 7 + 8) {
2283 return mkU32(1);
2284 }
2285 /* Remaining case */
2286 return mkU32(0);
2287 }
2288
2289 /* S390_CC_OP_UNSIGNED_ADD_64 */
2290 if (cc_op == S390_CC_OP_UNSIGNED_ADD_64) {
2291 /*
2292 cc_dep1, cc_dep2 are the zero extended left and right operands
2293
2294 cc == 0 --> result == 0, no carry (cond == 8)
2295 cc == 1 --> result != 0, no carry (cond == 4)
2296 cc == 2 --> result == 0, carry (cond == 2)
2297 cc == 3 --> result != 0, carry (cond == 1)
2298 */
2299 if (cond == 8) { /* cc == 0 */
2300 /* Both inputs are 0 */
2301 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2302 binop(Iop_Or64, cc_dep1, cc_dep2),
2303 mkU64(0)));
2304 }
2305 if (cond == 7) { /* cc == 1,2,3 */
2306 /* Not both inputs are 0 */
2307 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2308 binop(Iop_Or64, cc_dep1, cc_dep2),
2309 mkU64(0)));
2310 }
2311 if (cond == 8 + 2) { /* cc == 0,2 -> result is zero */
2312 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2313 binop(Iop_Add64, cc_dep1, cc_dep2),
2314 mkU64(0)));
2315 }
2316 if (cond == 4 + 1) { /* cc == 1,3 -> result is not zero */
2317 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2318 binop(Iop_Add64, cc_dep1, cc_dep2),
2319 mkU64(0)));
2320 }
2321 goto missed;
2322 }
2323
2324 /* S390_CC_OP_UNSIGNED_ADD_32 */
2325 if (cc_op == S390_CC_OP_UNSIGNED_ADD_32) {
2326 /*
2327 cc_dep1, cc_dep2 are the zero extended left and right operands
2328
2329 cc == 0 --> result == 0, no carry (cond == 8)
2330 cc == 1 --> result != 0, no carry (cond == 4)
2331 cc == 2 --> result == 0, carry (cond == 2)
2332 cc == 3 --> result != 0, carry (cond == 1)
2333 */
2334 if (cond == 8) { /* cc == 0 */
2335 /* Both inputs are 0 */
2336 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2337 binop(Iop_Or64, cc_dep1, cc_dep2),
2338 mkU64(0)));
2339 }
2340 if (cond == 7) { /* cc == 1,2,3 */
2341 /* Not both inputs are 0 */
2342 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2343 binop(Iop_Or64, cc_dep1, cc_dep2),
2344 mkU64(0)));
2345 }
2346 if (cond == 8 + 2) { /* cc == 0,2 -> result is zero */
2347 return unop(Iop_1Uto32, binop(Iop_CmpEQ32,
2348 binop(Iop_Add32,
2349 unop(Iop_64to32, cc_dep1),
2350 unop(Iop_64to32, cc_dep2)),
2351 mkU32(0)));
2352 }
2353 if (cond == 4 + 1) { /* cc == 1,3 -> result is not zero */
2354 return unop(Iop_1Uto32, binop(Iop_CmpNE32,
2355 binop(Iop_Add32,
2356 unop(Iop_64to32, cc_dep1),
2357 unop(Iop_64to32, cc_dep2)),
2358 mkU32(0)));
2359 }
2360 goto missed;
2361 }
2362
2363 /* S390_CC_OP_SET */
2364 if (cc_op == S390_CC_OP_SET) {
2365 /* cc_dep1 is the condition code
2366
2367 Return 1, if ((cond << cc_dep1) & 0x8) != 0 */
2368
2369 return unop(Iop_1Uto32,
2370 binop(Iop_CmpNE64,
2371 binop(Iop_And64,
2372 binop(Iop_Shl64, cond_expr,
2373 unop(Iop_64to8, cc_dep1)),
2374 mkU64(8)),
2375 mkU64(0)));
2376 }
2377
florianaf514c02013-09-13 21:42:14 +00002378 goto missed;
sewardj2019a972011-03-07 16:04:07 +00002379 }
2380
florian9ec12ea2015-09-08 06:25:02 +00002381 /* --------- Specialising "s390_calculate_cc" --------- */
florianaf514c02013-09-13 21:42:14 +00002382
2383 if (vex_streq(function_name, "s390_calculate_cc")) {
2384 IRExpr *cc_op_expr, *cc_dep1;
2385 ULong cc_op;
2386
2387 vassert(arity == 4);
2388
2389 cc_op_expr = args[0];
2390
2391 /* The necessary requirement for all optimizations here is that
2392 cc_op is constant. So check that upfront. */
2393 if (! isC64(cc_op_expr)) return NULL;
2394
2395 cc_op = cc_op_expr->Iex.Const.con->Ico.U64;
2396 cc_dep1 = args[1];
2397
2398 if (cc_op == S390_CC_OP_BITWISE) {
2399 return unop(Iop_1Uto32,
2400 binop(Iop_CmpNE64, cc_dep1, mkU64(0)));
2401 }
2402
2403 if (cc_op == S390_CC_OP_SET) {
2404 return unop(Iop_64to32, cc_dep1);
2405 }
2406
2407 goto missed;
2408 }
2409
2410missed:
sewardj2019a972011-03-07 16:04:07 +00002411 return NULL;
2412}
2413
2414/*---------------------------------------------------------------*/
2415/*--- end guest_s390_helpers.c ---*/
2416/*---------------------------------------------------------------*/