regtest: add check for -Wl,--no-warn-execstack
[valgrind.git] / VEX / priv / guest_s390_helpers.c
blob94d0a242db7e01738ac40782e4eab5f9d3b86c1b
1 /* -*- mode: C; c-basic-offset: 3; -*- */
3 /*---------------------------------------------------------------*/
4 /*--- begin guest_s390_helpers.c ---*/
5 /*---------------------------------------------------------------*/
7 /*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
11 Copyright IBM Corp. 2010-2020
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.
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.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
29 /* Contributed by Florian Krohm */
31 #include "libvex_basictypes.h"
32 #include "libvex_emnote.h"
33 #include "libvex_guest_s390x.h"
34 #include "libvex_ir.h"
35 #include "libvex.h"
36 #include "libvex_s390x_common.h"
38 #include "main_util.h"
39 #include "main_globals.h"
40 #include "guest_generic_bb_to_IR.h"
41 #include "guest_s390_defs.h"
42 #include "s390_defs.h" /* S390_BFP_ROUND_xyzzy */
44 void
45 LibVEX_GuestS390X_initialise(VexGuestS390XState *state)
47 /*------------------------------------------------------------*/
48 /*--- Initialise ar registers ---*/
49 /*------------------------------------------------------------*/
51 state->guest_a0 = 0;
52 state->guest_a1 = 0;
53 state->guest_a2 = 0;
54 state->guest_a3 = 0;
55 state->guest_a4 = 0;
56 state->guest_a5 = 0;
57 state->guest_a6 = 0;
58 state->guest_a7 = 0;
59 state->guest_a8 = 0;
60 state->guest_a9 = 0;
61 state->guest_a10 = 0;
62 state->guest_a11 = 0;
63 state->guest_a12 = 0;
64 state->guest_a13 = 0;
65 state->guest_a14 = 0;
66 state->guest_a15 = 0;
68 /*------------------------------------------------------------*/
69 /*--- Initialise vr registers ---*/
70 /*------------------------------------------------------------*/
72 #define VRZERO(vr) \
73 do { \
74 vr.w64[0] = vr.w64[1] = 0ULL; \
75 } while(0);
77 VRZERO(state->guest_v0)
78 VRZERO(state->guest_v1)
79 VRZERO(state->guest_v2)
80 VRZERO(state->guest_v3)
81 VRZERO(state->guest_v4)
82 VRZERO(state->guest_v5)
83 VRZERO(state->guest_v6)
84 VRZERO(state->guest_v7)
85 VRZERO(state->guest_v8)
86 VRZERO(state->guest_v9)
87 VRZERO(state->guest_v10)
88 VRZERO(state->guest_v11)
89 VRZERO(state->guest_v12)
90 VRZERO(state->guest_v13)
91 VRZERO(state->guest_v14)
92 VRZERO(state->guest_v15)
93 VRZERO(state->guest_v16)
94 VRZERO(state->guest_v17)
95 VRZERO(state->guest_v18)
96 VRZERO(state->guest_v19)
97 VRZERO(state->guest_v20)
98 VRZERO(state->guest_v21)
99 VRZERO(state->guest_v22)
100 VRZERO(state->guest_v23)
101 VRZERO(state->guest_v24)
102 VRZERO(state->guest_v25)
103 VRZERO(state->guest_v26)
104 VRZERO(state->guest_v27)
105 VRZERO(state->guest_v28)
106 VRZERO(state->guest_v29)
107 VRZERO(state->guest_v30)
108 VRZERO(state->guest_v31)
110 #undef VRZERO
111 /*------------------------------------------------------------*/
112 /*--- Initialise gpr registers ---*/
113 /*------------------------------------------------------------*/
115 state->guest_r0 = 0;
116 state->guest_r1 = 0;
117 state->guest_r2 = 0;
118 state->guest_r3 = 0;
119 state->guest_r4 = 0;
120 state->guest_r5 = 0;
121 state->guest_r6 = 0;
122 state->guest_r7 = 0;
123 state->guest_r8 = 0;
124 state->guest_r9 = 0;
125 state->guest_r10 = 0;
126 state->guest_r11 = 0;
127 state->guest_r12 = 0;
128 state->guest_r13 = 0;
129 state->guest_r14 = 0;
130 state->guest_r15 = 0;
132 /*------------------------------------------------------------*/
133 /*--- Initialise S390 miscellaneous registers ---*/
134 /*------------------------------------------------------------*/
136 state->guest_counter = 0;
137 state->guest_fpc = 0;
138 state->guest_IA = 0;
140 /*------------------------------------------------------------*/
141 /*--- Initialise S390 pseudo registers ---*/
142 /*------------------------------------------------------------*/
144 state->guest_SYSNO = 0;
146 /*------------------------------------------------------------*/
147 /*--- Initialise generic pseudo registers ---*/
148 /*------------------------------------------------------------*/
150 state->guest_NRADDR = 0;
151 state->guest_CMSTART = 0;
152 state->guest_CMLEN = 0;
153 state->guest_IP_AT_SYSCALL = 0;
154 state->guest_EMNOTE = EmNote_NONE;
155 state->host_EvC_COUNTER = 0;
156 state->host_EvC_FAILADDR = 0;
158 /*------------------------------------------------------------*/
159 /*--- Initialise thunk ---*/
160 /*------------------------------------------------------------*/
162 state->guest_CC_OP = 0;
163 state->guest_CC_DEP1 = 0;
164 state->guest_CC_DEP2 = 0;
165 state->guest_CC_NDEP = 0;
167 __builtin_memset(state->padding, 0x0, sizeof(state->padding));
171 /* Figure out if any part of the guest state contained in minoff
172 .. maxoff requires precise memory exceptions. If in doubt return
173 True (but this generates significantly slower code). */
174 Bool
175 guest_s390x_state_requires_precise_mem_exns (
176 Int minoff, Int maxoff, VexRegisterUpdates pxControl
179 Int lr_min = S390X_GUEST_OFFSET(guest_LR);
180 Int lr_max = lr_min + 8 - 1;
181 Int sp_min = S390X_GUEST_OFFSET(guest_SP);
182 Int sp_max = sp_min + 8 - 1;
183 Int fp_min = S390X_GUEST_OFFSET(guest_FP);
184 Int fp_max = fp_min + 8 - 1;
185 Int ia_min = S390X_GUEST_OFFSET(guest_IA);
186 Int ia_max = ia_min + 8 - 1;
188 if (maxoff < sp_min || minoff > sp_max) {
189 /* No overlap with SP */
190 if (pxControl == VexRegUpdSpAtMemAccess)
191 return False; // We only need to check stack pointer.
192 } else {
193 return True;
196 if (maxoff < lr_min || minoff > lr_max) {
197 /* No overlap with LR */
198 } else {
199 return True;
202 if (maxoff < fp_min || minoff > fp_max) {
203 /* No overlap with FP */
204 } else {
205 return True;
208 if (maxoff < ia_min || minoff > ia_max) {
209 /* No overlap with IA */
210 } else {
211 return True;
214 return False;
218 #define ALWAYSDEFD(field) \
219 { S390X_GUEST_OFFSET(field), \
220 (sizeof ((VexGuestS390XState*)0)->field) }
222 VexGuestLayout s390xGuest_layout = {
224 /* Total size of the guest state, in bytes. */
225 .total_sizeB = sizeof(VexGuestS390XState),
227 /* Describe the stack pointer. */
228 .offset_SP = S390X_GUEST_OFFSET(guest_SP),
229 .sizeof_SP = 8,
231 /* Describe the frame pointer. */
232 .offset_FP = S390X_GUEST_OFFSET(guest_FP),
233 .sizeof_FP = 8,
235 /* Describe the instruction pointer. */
236 .offset_IP = S390X_GUEST_OFFSET(guest_IA),
237 .sizeof_IP = 8,
239 /* Describe any sections to be regarded by Memcheck as
240 'always-defined'. */
241 .n_alwaysDefd = 9,
243 /* Flags thunk: OP and NDEP are always defined, whereas DEP1
244 and DEP2 have to be tracked. See detailed comment in
245 gdefs.h on meaning of thunk fields. */
246 .alwaysDefd = {
247 /* 0 */ ALWAYSDEFD(guest_CC_OP), /* generic */
248 /* 1 */ ALWAYSDEFD(guest_CC_NDEP), /* generic */
249 /* 2 */ ALWAYSDEFD(guest_EMNOTE), /* generic */
250 /* 3 */ ALWAYSDEFD(guest_CMSTART), /* generic */
251 /* 4 */ ALWAYSDEFD(guest_CMLEN), /* generic */
252 /* 5 */ ALWAYSDEFD(guest_IP_AT_SYSCALL), /* generic */
253 /* 6 */ ALWAYSDEFD(guest_IA), /* control reg */
254 /* 7 */ ALWAYSDEFD(guest_fpc), /* control reg */
255 /* 8 */ ALWAYSDEFD(guest_counter), /* internal usage register */
259 /*------------------------------------------------------------*/
260 /*--- Dirty helper for EXecute ---*/
261 /*------------------------------------------------------------*/
262 void
263 s390x_dirtyhelper_EX(ULong torun, Addr64 addr)
265 last_execute_target = torun;
266 guest_IA_rel_base = addr;
270 /*------------------------------------------------------------*/
271 /*--- Dirty helper for Clock instructions ---*/
272 /*------------------------------------------------------------*/
273 #if defined(VGA_s390x)
274 ULong
275 s390x_dirtyhelper_STCK(ULong *addr)
277 UInt cc;
279 asm volatile("stck %0\n"
280 "ipm %1\n"
281 "srl %1,28\n"
282 : "+Q" (*addr), "=d" (cc) : : "cc");
283 return cc;
286 ULong
287 s390x_dirtyhelper_STCKE(ULong *addr)
289 UInt cc;
291 asm volatile("stcke %0\n"
292 "ipm %1\n"
293 "srl %1,28\n"
294 : "+Q" (*addr), "=d" (cc) : : "cc");
295 return cc;
298 ULong s390x_dirtyhelper_STCKF(ULong *addr)
300 UInt cc;
302 asm volatile(".insn s,0xb27c0000,%0\n"
303 "ipm %1\n"
304 "srl %1,28\n"
305 : "+Q" (*addr), "=d" (cc) : : "cc");
306 return cc;
308 #else
309 ULong s390x_dirtyhelper_STCK(ULong *addr) {return 3;}
310 ULong s390x_dirtyhelper_STCKF(ULong *addr) {return 3;}
311 ULong s390x_dirtyhelper_STCKE(ULong *addr) {return 3;}
312 #endif /* VGA_s390x */
315 /*------------------------------------------------------------*/
316 /*--- Dirty helper for the "convert unicode" insn family. ---*/
317 /*------------------------------------------------------------*/
318 void
319 s390x_dirtyhelper_CUxy(UChar *address, ULong data, ULong num_bytes)
321 UInt i;
323 vassert(num_bytes >= 1 && num_bytes <= 4);
325 /* Store the least significant NUM_BYTES bytes in DATA left to right
326 at ADDRESS. */
327 for (i = 1; i <= num_bytes; ++i) {
328 address[num_bytes - i] = data & 0xff;
329 data >>= 8;
334 /*------------------------------------------------------------*/
335 /*--- Clean helper for CU21. ---*/
336 /*------------------------------------------------------------*/
338 /* The function performs a CU21 operation. It returns three things
339 encoded in an ULong value:
340 - the converted bytes (at most 4)
341 - the number of converted bytes
342 - an indication whether LOW_SURROGATE, if any, is invalid
344 64 48 16 8 0
345 +-------+-----------------+-----------+-----------------------+
346 | 0x0 | converted bytes | num_bytes | invalid_low_surrogate |
347 +-------+-----------------+-----------+-----------------------+
349 ULong
350 s390_do_cu21(UInt srcval, UInt low_surrogate)
352 ULong retval = 0; // shut up gcc
353 UInt b1, b2, b3, b4, num_bytes, invalid_low_surrogate = 0;
355 srcval &= 0xffff;
357 /* Determine the number of bytes in the converted value */
358 if (srcval <= 0x007f)
359 num_bytes = 1;
360 else if (srcval >= 0x0080 && srcval <= 0x07ff)
361 num_bytes = 2;
362 else if ((srcval >= 0x0800 && srcval <= 0xd7ff) ||
363 (srcval >= 0xdc00 && srcval <= 0xffff))
364 num_bytes = 3;
365 else
366 num_bytes = 4;
368 /* Determine UTF-8 bytes according to calculated num_bytes */
369 switch (num_bytes){
370 case 1:
371 retval = srcval;
372 break;
374 case 2:
375 /* order of bytes left to right: b1, b2 */
376 b1 = 0xc0;
377 b1 |= srcval >> 6;
379 b2 = 0x80;
380 b2 |= srcval & 0x3f;
382 retval = (b1 << 8) | b2;
383 break;
385 case 3:
386 /* order of bytes left to right: b1, b2, b3 */
387 b1 = 0xe0;
388 b1 |= srcval >> 12;
390 b2 = 0x80;
391 b2 |= (srcval >> 6) & 0x3f;
393 b3 = 0x80;
394 b3 |= srcval & 0x3f;
396 retval = (b1 << 16) | (b2 << 8) | b3;
397 break;
399 case 4: {
400 /* order of bytes left to right: b1, b2, b3, b4 */
401 UInt high_surrogate = srcval;
402 UInt uvwxy = ((high_surrogate >> 6) & 0xf) + 1; // abcd + 1
404 b1 = 0xf0;
405 b1 |= uvwxy >> 2; // uvw
407 b2 = 0x80;
408 b2 |= (uvwxy & 0x3) << 4; // xy
409 b2 |= (high_surrogate >> 2) & 0xf; // efgh
411 b3 = 0x80;
412 b3 |= (high_surrogate & 0x3) << 4; // ij
413 b3 |= (low_surrogate >> 6) & 0xf; // klmn
415 b4 = 0x80;
416 b4 |= low_surrogate & 0x3f;
418 retval = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
420 invalid_low_surrogate = (low_surrogate & 0xfc00) != 0xdc00;
421 break;
425 /* At this point RETVAL contains the converted bytes.
426 Build up the final return value. */
427 return (retval << 16) | (num_bytes << 8) | invalid_low_surrogate;
431 /*------------------------------------------------------------*/
432 /*--- Clean helper for CU24. ---*/
433 /*------------------------------------------------------------*/
435 /* The function performs a CU24 operation. It returns two things
436 encoded in an ULong value:
437 - the 4 converted bytes
438 - an indication whether LOW_SURROGATE, if any, is invalid
440 64 40 8 0
441 +------------------------+-----------------------+
442 | 0x0 | converted bytes | invalid_low_surrogate |
443 +------------------------+-----------------------+
445 ULong
446 s390_do_cu24(UInt srcval, UInt low_surrogate)
448 ULong retval;
449 UInt invalid_low_surrogate = 0;
451 srcval &= 0xffff;
453 if ((srcval <= 0xd7ff) ||
454 (srcval >= 0xdc00 && srcval <= 0xffff)) {
455 retval = srcval;
456 } else {
457 /* D800 - DBFF */
458 UInt high_surrogate = srcval;
459 UInt uvwxy = ((high_surrogate >> 6) & 0xf) + 1; // abcd + 1
460 UInt efghij = high_surrogate & 0x3f;
461 UInt klmnoprst = low_surrogate & 0x3ff;
463 retval = (uvwxy << 16) | (efghij << 10) | klmnoprst;
465 invalid_low_surrogate = (low_surrogate & 0xfc00) != 0xdc00;
468 /* At this point RETVAL contains the converted bytes.
469 Build up the final return value. */
470 return (retval << 8) | invalid_low_surrogate;
474 /*------------------------------------------------------------*/
475 /*--- Clean helper for CU42. ---*/
476 /*------------------------------------------------------------*/
478 /* The function performs a CU42 operation. It returns three things
479 encoded in an ULong value:
480 - the converted bytes (at most 4)
481 - the number of converted bytes (2 or 4; 0 if invalid character)
482 - an indication whether the UTF-32 character is invalid
484 64 48 16 8 0
485 +-------+-----------------+-----------+-------------------+
486 | 0x0 | converted bytes | num_bytes | invalid_character |
487 +-------+-----------------+-----------+-------------------+
489 ULong
490 s390_do_cu42(UInt srcval)
492 ULong retval;
493 UInt num_bytes, invalid_character = 0;
495 if ((srcval >= 0x0000 && srcval <= 0xd7ff) ||
496 (srcval >= 0xdc00 && srcval <= 0xffff)) {
497 retval = srcval;
498 num_bytes = 2;
499 } else if (srcval >= 0x00010000 && srcval <= 0x0010FFFF) {
500 UInt uvwxy = srcval >> 16;
501 UInt abcd = (uvwxy - 1) & 0xf;
502 UInt efghij = (srcval >> 10) & 0x3f;
504 UInt high_surrogate = (0xd8 << 8) | (abcd << 6) | efghij;
505 UInt low_surrogate = (0xdc << 8) | (srcval & 0x3ff);
507 retval = (high_surrogate << 16) | low_surrogate;
508 num_bytes = 4;
509 } else {
510 /* D800 - DBFF or 00110000 - FFFFFFFF */
511 invalid_character = 1;
512 retval = num_bytes = 0; /* does not matter; not used */
515 /* At this point RETVAL contains the converted bytes.
516 Build up the final return value. */
517 return (retval << 16) | (num_bytes << 8) | invalid_character;
521 /*------------------------------------------------------------*/
522 /*--- Clean helper for CU41. ---*/
523 /*------------------------------------------------------------*/
525 /* The function performs a CU41 operation. It returns three things
526 encoded in an ULong value:
527 - the converted bytes (at most 4)
528 - the number of converted bytes (1, 2, 3, or 4; 0 if invalid character)
529 - an indication whether the UTF-32 character is invalid
531 64 48 16 8 0
532 +-------+-----------------+-----------+-------------------+
533 | 0x0 | converted bytes | num_bytes | invalid_character |
534 +-------+-----------------+-----------+-------------------+
536 ULong
537 s390_do_cu41(UInt srcval)
539 ULong retval;
540 UInt num_bytes, invalid_character = 0;
542 if (srcval <= 0x7f) {
543 retval = srcval;
544 num_bytes = 1;
545 } else if (srcval >= 0x80 && srcval <= 0x7ff) {
546 UInt fghij = srcval >> 6;
547 UInt klmnop = srcval & 0x3f;
548 UInt byte1 = (0xc0 | fghij);
549 UInt byte2 = (0x80 | klmnop);
551 retval = (byte1 << 8) | byte2;
552 num_bytes = 2;
553 } else if ((srcval >= 0x800 && srcval <= 0xd7ff) ||
554 (srcval >= 0xdc00 && srcval <= 0xffff)) {
555 UInt abcd = srcval >> 12;
556 UInt efghij = (srcval >> 6) & 0x3f;
557 UInt klmnop = srcval & 0x3f;
558 UInt byte1 = 0xe0 | abcd;
559 UInt byte2 = 0x80 | efghij;
560 UInt byte3 = 0x80 | klmnop;
562 retval = (byte1 << 16) | (byte2 << 8) | byte3;
563 num_bytes = 3;
564 } else if (srcval >= 0x10000 && srcval <= 0x10ffff) {
565 UInt uvw = (srcval >> 18) & 0x7;
566 UInt xy = (srcval >> 16) & 0x3;
567 UInt efgh = (srcval >> 12) & 0xf;
568 UInt ijklmn = (srcval >> 6) & 0x3f;
569 UInt opqrst = srcval & 0x3f;
570 UInt byte1 = 0xf0 | uvw;
571 UInt byte2 = 0x80 | (xy << 4) | efgh;
572 UInt byte3 = 0x80 | ijklmn;
573 UInt byte4 = 0x80 | opqrst;
575 retval = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
576 num_bytes = 4;
577 } else {
578 /* d800 ... dbff or 00110000 ... ffffffff */
579 invalid_character = 1;
581 retval = 0;
582 num_bytes = 0;
585 /* At this point RETVAL contains the converted bytes.
586 Build up the final return value. */
587 return (retval << 16) | (num_bytes << 8) | invalid_character;
591 /*------------------------------------------------------------*/
592 /*--- Clean helpers for CU12. ---*/
593 /*------------------------------------------------------------*/
595 /* The function looks at the first byte of an UTF-8 character and returns
596 two things encoded in an ULong value:
598 - the number of bytes that need to be read
599 - an indication whether the UTF-8 character is invalid
601 64 16 8 0
602 +-------------------+-------------------+
603 | 0x0 | num_bytes | invalid_character |
604 +-------+-----------+-------------------+
606 ULong
607 s390_do_cu12_cu14_helper1(UInt byte, UInt etf3_and_m3_is_1)
609 vassert(byte <= 0xff);
611 /* Check whether the character is invalid */
612 if (byte >= 0x80 && byte <= 0xbf) return 1;
613 if (byte >= 0xf8) return 1;
615 if (etf3_and_m3_is_1) {
616 if (byte == 0xc0 || byte == 0xc1) return 1;
617 if (byte >= 0xf5 && byte <= 0xf7) return 1;
620 /* Character is valid */
621 if (byte <= 0x7f) return 1 << 8; // 1 byte
622 if (byte <= 0xdf) return 2 << 8; // 2 bytes
623 if (byte <= 0xef) return 3 << 8; // 3 bytes
625 return 4 << 8; // 4 bytes
628 /* The function performs a CU12 or CU14 operation. BYTE1, BYTE2, etc are the
629 bytes as read from the input stream, left to right. BYTE1 is a valid
630 byte. The function returns three things encoded in an ULong value:
632 - the converted bytes
633 - the number of converted bytes (2 or 4; 0 if invalid character)
634 - an indication whether the UTF-16 character is invalid
636 64 48 16 8 0
637 +-------+-----------------+-----------+-------------------+
638 | 0x0 | converted bytes | num_bytes | invalid_character |
639 +-------+-----------------+-----------+-------------------+
641 static ULong
642 s390_do_cu12_cu14_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
643 ULong stuff, Bool is_cu12)
645 UInt num_src_bytes = stuff >> 1, etf3_and_m3_is_1 = stuff & 0x1;
646 UInt num_bytes = 0, invalid_character = 0;
647 ULong retval = 0;
649 vassert(num_src_bytes <= 4);
651 switch (num_src_bytes) {
652 case 1:
653 num_bytes = 2;
654 retval = byte1;
655 break;
657 case 2: {
658 /* Test validity */
659 if (etf3_and_m3_is_1) {
660 if (byte2 < 0x80 || byte2 > 0xbf) {
661 invalid_character = 1;
662 break;
666 /* OK */
667 UInt fghij = byte1 & 0x1f;
668 UInt klmnop = byte2 & 0x3f;
670 num_bytes = 2;
671 retval = (fghij << 6) | klmnop;
672 break;
675 case 3: {
676 /* Test validity */
677 if (etf3_and_m3_is_1) {
678 if (byte1 == 0xe0) {
679 if ((byte2 < 0xa0 || byte2 > 0xbf) ||
680 (byte3 < 0x80 || byte3 > 0xbf)) {
681 invalid_character = 1;
682 break;
685 if ((byte1 >= 0xe1 && byte1 <= 0xec) ||
686 byte1 == 0xee || byte1 == 0xef) {
687 if ((byte2 < 0x80 || byte2 > 0xbf) ||
688 (byte3 < 0x80 || byte3 > 0xbf)) {
689 invalid_character = 1;
690 break;
693 if (byte1 == 0xed) {
694 if ((byte2 < 0x80 || byte2 > 0x9f) ||
695 (byte3 < 0x80 || byte3 > 0xbf)) {
696 invalid_character = 1;
697 break;
702 /* OK */
703 UInt abcd = byte1 & 0xf;
704 UInt efghij = byte2 & 0x3f;
705 UInt klmnop = byte3 & 0x3f;
707 num_bytes = 2;
708 retval = (abcd << 12) | (efghij << 6) | klmnop;
709 break;
712 case 4: {
713 /* Test validity */
714 if (etf3_and_m3_is_1) {
715 if (byte1 == 0xf0) {
716 if ((byte2 < 0x90 || byte2 > 0xbf) ||
717 (byte3 < 0x80 || byte3 > 0xbf) ||
718 (byte4 < 0x80 || byte4 > 0xbf)) {
719 invalid_character = 1;
720 break;
723 if (byte1 == 0xf1 || byte1 == 0xf2 || byte1 == 0xf3) {
724 if ((byte2 < 0x80 || byte2 > 0xbf) ||
725 (byte3 < 0x80 || byte3 > 0xbf) ||
726 (byte4 < 0x80 || byte4 > 0xbf)) {
727 invalid_character = 1;
728 break;
731 if (byte1 == 0xf4) {
732 if ((byte2 < 0x80 || byte2 > 0x8f) ||
733 (byte3 < 0x80 || byte3 > 0xbf) ||
734 (byte4 < 0x80 || byte4 > 0xbf)) {
735 invalid_character = 1;
736 break;
741 /* OK */
742 UInt uvw = byte1 & 0x7;
743 UInt xy = (byte2 >> 4) & 0x3;
744 UInt uvwxy = (uvw << 2) | xy;
745 UInt efgh = byte2 & 0xf;
746 UInt ij = (byte3 >> 4) & 0x3;
747 UInt klmn = byte3 & 0xf;
748 UInt opqrst = byte4 & 0x3f;
750 if (is_cu12) {
751 UInt abcd = (uvwxy - 1) & 0xf;
752 UInt high_surrogate = (0xd8 << 8) | (abcd << 6) | (efgh << 2) | ij;
753 UInt low_surrogate = (0xdc << 8) | (klmn << 6) | opqrst;
755 num_bytes = 4;
756 retval = (high_surrogate << 16) | low_surrogate;
757 } else {
758 num_bytes = 4;
759 retval =
760 (uvwxy << 16) | (efgh << 12) | (ij << 10) | (klmn << 6) | opqrst;
762 break;
766 if (! is_cu12) num_bytes = 4; // for CU14, by definition
768 /* At this point RETVAL contains the converted bytes.
769 Build up the final return value. */
770 return (retval << 16) | (num_bytes << 8) | invalid_character;
773 ULong
774 s390_do_cu12_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
775 ULong stuff)
777 return s390_do_cu12_cu14_helper2(byte1, byte2, byte3, byte4, stuff,
778 /* is_cu12 = */ 1);
781 ULong
782 s390_do_cu14_helper2(UInt byte1, UInt byte2, UInt byte3, UInt byte4,
783 ULong stuff)
785 return s390_do_cu12_cu14_helper2(byte1, byte2, byte3, byte4, stuff,
786 /* is_cu12 = */ 0);
790 /*------------------------------------------------------------*/
791 /*--- Clean helper for "convert to binary". ---*/
792 /*------------------------------------------------------------*/
793 #if defined(VGA_s390x)
794 UInt
795 s390_do_cvb(ULong decimal)
797 UInt binary;
799 __asm__ volatile (
800 "cvb %[result],%[input]\n\t"
801 : [result] "=d"(binary)
802 : [input] "R"(decimal)
805 return binary;
808 #else
809 UInt s390_do_cvb(ULong decimal) { return 0; }
810 #endif
813 /*------------------------------------------------------------*/
814 /*--- Clean helper for "convert to decimal". ---*/
815 /*------------------------------------------------------------*/
816 #if defined(VGA_s390x)
817 ULong
818 s390_do_cvd(ULong binary_in)
820 UInt binary = binary_in & 0xffffffffULL;
821 ULong decimal;
823 __asm__ volatile (
824 "cvd %[input],%[result]\n\t"
825 : [result] "=m"(decimal)
826 : [input] "d"(binary)
829 return decimal;
832 #else
833 ULong s390_do_cvd(ULong binary) { return 0; }
834 #endif
836 /*------------------------------------------------------------*/
837 /*--- Clean helper for "Extract cache attribute". ---*/
838 /*------------------------------------------------------------*/
839 #if defined(VGA_s390x)
840 ULong
841 s390_do_ecag(ULong op2addr)
843 ULong result;
845 __asm__ volatile(".insn rsy,0xEB000000004C,%[out],0,0(%[in])\n\t"
846 : [out] "=d"(result)
847 : [in] "d"(op2addr));
848 return result;
851 #else
852 ULong s390_do_ecag(ULong op2addr) { return 0; }
853 #endif
855 /*------------------------------------------------------------*/
856 /*--- Clean helper for "Perform Floating Point Operation". ---*/
857 /*------------------------------------------------------------*/
858 #if defined(VGA_s390x)
859 UInt
860 s390_do_pfpo(UInt gpr0)
862 UChar rm;
863 UChar op1_ty, op2_ty;
865 rm = gpr0 & 0xf;
866 if (rm > 1 && rm < 8)
867 return EmFail_S390X_invalid_PFPO_rounding_mode;
869 op1_ty = (gpr0 >> 16) & 0xff; // gpr0[40:47]
870 op2_ty = (gpr0 >> 8) & 0xff; // gpr0[48:55]
871 /* Operand type must be BFP 32, 64, 128 or DFP 32, 64, 128
872 which correspond to 0x5, 0x6, 0x7, 0x8, 0x9, 0xa respectively.
873 Any other operand type value is unsupported */
874 if ((op1_ty == op2_ty) ||
875 (op1_ty < 0x5 || op1_ty > 0xa) ||
876 (op2_ty < 0x5 || op2_ty > 0xa))
877 return EmFail_S390X_invalid_PFPO_function;
879 return EmNote_NONE;
881 #else
882 UInt s390_do_pfpo(UInt gpr0) { return 0; }
883 #endif
885 /*------------------------------------------------------------*/
886 /*--- Helper for condition code. ---*/
887 /*------------------------------------------------------------*/
889 #if defined(VGA_s390x)
890 typedef long double Float128;
891 union s390x_F64 { ULong i; Double f; };
892 union s390x_F128 { struct { ULong hi, lo; } i; Float128 f; };
894 /* Convert an IRRoundingMode value to s390_bfp_round_t */
895 static s390_bfp_round_t
896 decode_bfp_rounding_mode(UInt irrm)
898 switch (irrm) {
899 case Irrm_NEAREST: return S390_BFP_ROUND_NEAREST_EVEN;
900 case Irrm_NegINF: return S390_BFP_ROUND_NEGINF;
901 case Irrm_PosINF: return S390_BFP_ROUND_POSINF;
902 case Irrm_ZERO: return S390_BFP_ROUND_ZERO;
904 vpanic("decode_bfp_rounding_mode");
907 #define S390_CC_FOR_BINARY(opcode,cc_dep1,cc_dep2) \
908 ({ \
909 __asm__ volatile ( \
910 opcode " %[op1],%[op2]\n\t" \
911 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op1] "+d"(cc_dep1) \
912 : [op2] "d"(cc_dep2) \
913 : "cc");\
914 psw >> 28; /* cc */ \
917 #define S390_CC_FOR_TERNARY(opcode,cc_dep1,cc_dep2) \
918 ({ \
919 __asm__ volatile ( \
920 opcode ",%[op1],%[op1],%[op2],0\n\t" \
921 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op1] "+d"(cc_dep1) \
922 : [op2] "d"(cc_dep2) \
923 : "cc");\
924 psw >> 28; /* cc */ \
927 #define S390_CC_FOR_TERNARY_SUBB(opcode,cc_dep1,cc_dep2,cc_ndep) \
928 ({ \
929 /* Recover the original DEP2 value. See comment near s390_cc_thunk_put3 \
930 for rationale. */ \
931 cc_dep2 = cc_dep2 ^ cc_ndep; \
932 ULong tmp = 1; \
933 __asm__ volatile ( \
934 "sr %[tmp],%[op3]\n\t" /* borrow to cc */ \
935 opcode " %[op1],%[op2]\n\t" /* then redo the op */\
936 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op1] "+&d"(cc_dep1), \
937 [tmp] "+&d"(tmp) \
938 : [op2] "d"(cc_dep2), [op3] "d"(cc_ndep) \
939 : "cc");\
940 psw >> 28; /* cc */ \
943 #define S390_CC_FOR_TERNARY_ADDC(opcode,cc_dep1,cc_dep2,cc_ndep) \
944 ({ \
945 /* Recover the original DEP2 value. See comment near s390_cc_thunk_put3 \
946 for rationale. */ \
947 cc_dep2 = cc_dep2 ^ cc_ndep; \
948 ULong tmp; \
949 __asm__ volatile ( \
950 "lgfr %[tmp],%[op3]\n\t" /* first load cc_ndep */ \
951 "aghi %[tmp],0\n\t" /* and convert it into a cc */ \
952 opcode " %[op1],%[op2]\n\t" /* then redo the op */\
953 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op1] "+&d"(cc_dep1), \
954 [tmp] "=&d"(tmp) \
955 : [op2] "d"(cc_dep2), [op3] "d"(cc_ndep) \
956 : "cc");\
957 psw >> 28; /* cc */ \
961 #define S390_CC_FOR_BFP_RESULT(opcode,cc_dep1) \
962 ({ \
963 union s390x_F64 op = { .i = cc_dep1 }; \
964 Double tmp; \
965 __asm__ volatile ( \
966 opcode " %[tmp],%[op]\n\t" \
967 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
968 : [op] "f"(op.f) \
969 : "cc");\
970 psw >> 28; /* cc */ \
973 #define S390_CC_FOR_BFP128_RESULT(hi,lo) \
974 ({ \
975 union s390x_F128 op = { .i = { hi, lo } }; \
976 Float128 tmp; \
977 __asm__ volatile ( \
978 "ltxbr %[tmp],%[op]\n\t" \
979 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
980 : [op] "f"(op.f) \
981 : "cc");\
982 psw >> 28; /* cc */ \
985 #define S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,rounding_mode) \
986 ({ \
987 union s390x_F64 op = { .i = cc_dep1 }; \
988 ULong tmp; \
989 __asm__ volatile ( \
990 opcode " %[tmp]," #rounding_mode ",%[op]\n\t" \
991 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=d"(tmp) \
992 : [op] "f"(op.f) \
993 : "cc");\
994 psw >> 28; /* cc */ \
997 #define S390_CC_FOR_BFP_CONVERT(opcode,cc_dep1,cc_dep2) \
998 ({ \
999 UInt cc; \
1000 switch (decode_bfp_rounding_mode(cc_dep2)) { \
1001 case S390_BFP_ROUND_NEAREST_EVEN: \
1002 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,4); \
1003 break; \
1004 case S390_BFP_ROUND_ZERO: \
1005 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,5); \
1006 break; \
1007 case S390_BFP_ROUND_POSINF: \
1008 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,6); \
1009 break; \
1010 case S390_BFP_ROUND_NEGINF: \
1011 cc = S390_CC_FOR_BFP_CONVERT_AUX(opcode,cc_dep1,7); \
1012 break; \
1013 default: \
1014 vpanic("unexpected bfp rounding mode"); \
1016 cc; \
1019 #define S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,rounding_mode) \
1020 ({ \
1021 union s390x_F64 op = { .i = cc_dep1 }; \
1022 ULong tmp; \
1023 __asm__ volatile ( \
1024 opcode ",%[tmp],%[op]," #rounding_mode ",0\n\t" \
1025 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=d"(tmp) \
1026 : [op] "f"(op.f) \
1027 : "cc");\
1028 psw >> 28; /* cc */ \
1031 #define S390_CC_FOR_BFP_UCONVERT(opcode,cc_dep1,cc_dep2) \
1032 ({ \
1033 UInt cc; \
1034 switch (decode_bfp_rounding_mode(cc_dep2)) { \
1035 case S390_BFP_ROUND_NEAREST_EVEN: \
1036 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,4); \
1037 break; \
1038 case S390_BFP_ROUND_ZERO: \
1039 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,5); \
1040 break; \
1041 case S390_BFP_ROUND_POSINF: \
1042 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,6); \
1043 break; \
1044 case S390_BFP_ROUND_NEGINF: \
1045 cc = S390_CC_FOR_BFP_UCONVERT_AUX(opcode,cc_dep1,7); \
1046 break; \
1047 default: \
1048 vpanic("unexpected bfp rounding mode"); \
1050 cc; \
1053 #define S390_CC_FOR_BFP128_CONVERT_AUX(opcode,hi,lo,rounding_mode) \
1054 ({ \
1055 union s390x_F128 op = { .i = { hi, lo } }; \
1056 ULong tmp; \
1057 __asm__ volatile ( \
1058 opcode " %[tmp]," #rounding_mode ",%[op]\n\t" \
1059 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=d"(tmp) \
1060 : [op] "f"(op.f) \
1061 : "cc");\
1062 psw >> 28; /* cc */ \
1065 #define S390_CC_FOR_BFP128_CONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1066 ({ \
1067 UInt cc; \
1068 /* Recover the original DEP2 value. See comment near \
1069 s390_cc_thunk_put3 for rationale. */ \
1070 cc_dep2 = cc_dep2 ^ cc_ndep; \
1071 switch (decode_bfp_rounding_mode(cc_ndep)) { \
1072 case S390_BFP_ROUND_NEAREST_EVEN: \
1073 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1074 break; \
1075 case S390_BFP_ROUND_ZERO: \
1076 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1077 break; \
1078 case S390_BFP_ROUND_POSINF: \
1079 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1080 break; \
1081 case S390_BFP_ROUND_NEGINF: \
1082 cc = S390_CC_FOR_BFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1083 break; \
1084 default: \
1085 vpanic("unexpected bfp rounding mode"); \
1087 cc; \
1090 #define S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,hi,lo,rounding_mode) \
1091 ({ \
1092 union s390x_F128 op = { .i = { hi, lo } }; \
1093 ULong tmp; \
1094 __asm__ volatile ( \
1095 opcode ",%[tmp],%[op]," #rounding_mode ",0\n\t" \
1096 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=d"(tmp) \
1097 : [op] "f"(op.f) \
1098 : "cc");\
1099 psw >> 28; /* cc */ \
1102 #define S390_CC_FOR_BFP128_UCONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1103 ({ \
1104 UInt cc; \
1105 /* Recover the original DEP2 value. See comment near \
1106 s390_cc_thunk_put3 for rationale. */ \
1107 cc_dep2 = cc_dep2 ^ cc_ndep; \
1108 switch (decode_bfp_rounding_mode(cc_ndep)) { \
1109 case S390_BFP_ROUND_NEAREST_EVEN: \
1110 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1111 break; \
1112 case S390_BFP_ROUND_ZERO: \
1113 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1114 break; \
1115 case S390_BFP_ROUND_POSINF: \
1116 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1117 break; \
1118 case S390_BFP_ROUND_NEGINF: \
1119 cc = S390_CC_FOR_BFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1120 break; \
1121 default: \
1122 vpanic("unexpected bfp rounding mode"); \
1124 cc; \
1127 #define S390_CC_FOR_BFP_TDC(opcode,cc_dep1,cc_dep2) \
1128 ({ \
1129 union s390x_F64 val = { .i = cc_dep1 }; \
1130 __asm__ volatile ( \
1131 opcode " %[value],0(%[class])\n\t" \
1132 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1133 : [value] "f"(val.f), \
1134 [class] "a"(cc_dep2) \
1135 : "cc");\
1136 psw >> 28; /* cc */ \
1139 #define S390_CC_FOR_BFP128_TDC(cc_dep1,cc_dep2,cc_ndep) \
1140 ({ \
1141 /* Recover the original DEP2 value. See comment near \
1142 s390_cc_thunk_put1f128Z for rationale. */ \
1143 cc_dep2 = cc_dep2 ^ cc_ndep; \
1144 union s390x_F128 val = { .i = { cc_dep1, cc_dep2 } }; \
1145 __asm__ volatile ( \
1146 "tcxb %[value],0(%[class])\n\t" \
1147 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1148 : [value] "f"(val.f), [class] "a"(cc_ndep) \
1149 : "cc");\
1150 psw >> 28; /* cc */ \
1153 /* Convert an IRRoundingMode value to s390_dfp_round_t */
1154 static s390_dfp_round_t
1155 decode_dfp_rounding_mode(UInt irrm)
1157 switch (irrm) {
1158 case Irrm_NEAREST:
1159 return S390_DFP_ROUND_NEAREST_EVEN_4;
1160 case Irrm_NegINF:
1161 return S390_DFP_ROUND_NEGINF_7;
1162 case Irrm_PosINF:
1163 return S390_DFP_ROUND_POSINF_6;
1164 case Irrm_ZERO:
1165 return S390_DFP_ROUND_ZERO_5;
1166 case Irrm_NEAREST_TIE_AWAY_0:
1167 return S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1;
1168 case Irrm_PREPARE_SHORTER:
1169 return S390_DFP_ROUND_PREPARE_SHORT_3;
1170 case Irrm_AWAY_FROM_ZERO:
1171 return S390_DFP_ROUND_AWAY_0;
1172 case Irrm_NEAREST_TIE_TOWARD_0:
1173 return S390_DFP_ROUND_NEAREST_TIE_TOWARD_0;
1175 vpanic("decode_dfp_rounding_mode");
1178 #define S390_CC_FOR_DFP_RESULT(cc_dep1) \
1179 ({ \
1180 union s390x_F64 op = { .i = cc_dep1 }; \
1181 Double tmp; \
1182 __asm__ volatile ( \
1183 ".insn rre, 0xb3d60000,%[tmp],%[op]\n\t" /* LTDTR */ \
1184 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
1185 : [op] "f"(op.f) \
1186 : "cc");\
1187 psw >> 28; /* cc */ \
1190 #define S390_CC_FOR_DFP128_RESULT(hi,lo) \
1191 ({ \
1192 union s390x_F128 op = { .i = { hi, lo } }; \
1193 Float128 tmp; \
1194 __asm__ volatile ( \
1195 ".insn rre, 0xb3de0000,%[tmp],%[op]\n\t" /* LTXTR */ \
1196 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
1197 : [op] "f"(op.f) \
1198 : "cc"); \
1199 psw >> 28; /* cc */ \
1202 #define S390_CC_FOR_DFP_TD(opcode,cc_dep1,cc_dep2) \
1203 ({ \
1204 union s390x_F64 val = { .i = cc_dep1 }; \
1205 __asm__ volatile ( \
1206 opcode ",%[value],0(%[class])\n\t" \
1207 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1208 : [value] "f"(val.f), \
1209 [class] "a"(cc_dep2) \
1210 : "cc"); \
1211 psw >> 28; /* cc */ \
1214 #define S390_CC_FOR_DFP128_TD(opcode,cc_dep1,cc_dep2,cc_ndep) \
1215 ({ \
1216 /* Recover the original DEP2 value. See comment near \
1217 s390_cc_thunk_put1d128Z for rationale. */ \
1218 cc_dep2 = cc_dep2 ^ cc_ndep; \
1219 union s390x_F128 val = { .i = { cc_dep1, cc_dep2 } }; \
1220 __asm__ volatile ( \
1221 opcode ",%[value],0(%[class])\n\t" \
1222 "ipm %[psw]\n\t" : [psw] "=d"(psw) \
1223 : [value] "f"(val.f), \
1224 [class] "a"(cc_ndep) \
1225 : "cc"); \
1226 psw >> 28; /* cc */ \
1229 #define S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,rounding_mode) \
1230 ({ \
1231 union s390x_F64 op = { .i = cc_dep1 }; \
1232 Double tmp; \
1233 __asm__ volatile ( \
1234 opcode ",%[tmp],%[op]," #rounding_mode ",0\n\t" \
1235 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
1236 : [op] "f"(op.f) \
1237 : "cc"); \
1238 psw >> 28; /* cc */ \
1241 #define S390_CC_FOR_DFP_CONVERT(opcode,cc_dep1,cc_dep2) \
1242 ({ \
1243 UInt cc; \
1244 switch (decode_dfp_rounding_mode(cc_dep2)) { \
1245 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1246 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1247 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,1); \
1248 break; \
1249 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1250 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1251 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,3); \
1252 break; \
1253 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1254 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1255 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,4); \
1256 break; \
1257 case S390_DFP_ROUND_ZERO_5: \
1258 case S390_DFP_ROUND_ZERO_9: \
1259 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,5); \
1260 break; \
1261 case S390_DFP_ROUND_POSINF_6: \
1262 case S390_DFP_ROUND_POSINF_10: \
1263 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,6); \
1264 break; \
1265 case S390_DFP_ROUND_NEGINF_7: \
1266 case S390_DFP_ROUND_NEGINF_11: \
1267 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,7); \
1268 break; \
1269 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1270 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,13); \
1271 break; \
1272 case S390_DFP_ROUND_AWAY_0: \
1273 cc = S390_CC_FOR_DFP_CONVERT_AUX(opcode,cc_dep1,14); \
1274 break; \
1275 default: \
1276 vpanic("unexpected dfp rounding mode"); \
1278 cc; \
1281 #define S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,rounding_mode) \
1282 ({ \
1283 union s390x_F64 op = { .i = cc_dep1 }; \
1284 Double tmp; \
1285 __asm__ volatile ( \
1286 opcode ",%[tmp],%[op]," #rounding_mode ",0\n\t" \
1287 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
1288 : [op] "f"(op.f) \
1289 : "cc"); \
1290 psw >> 28; /* cc */ \
1293 #define S390_CC_FOR_DFP_UCONVERT(opcode,cc_dep1,cc_dep2) \
1294 ({ \
1295 UInt cc; \
1296 switch (decode_dfp_rounding_mode(cc_dep2)) { \
1297 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1298 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1299 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,1); \
1300 break; \
1301 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1302 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1303 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,3); \
1304 break; \
1305 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1306 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1307 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,4); \
1308 break; \
1309 case S390_DFP_ROUND_ZERO_5: \
1310 case S390_DFP_ROUND_ZERO_9: \
1311 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,5); \
1312 break; \
1313 case S390_DFP_ROUND_POSINF_6: \
1314 case S390_DFP_ROUND_POSINF_10: \
1315 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,6); \
1316 break; \
1317 case S390_DFP_ROUND_NEGINF_7: \
1318 case S390_DFP_ROUND_NEGINF_11: \
1319 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,7); \
1320 break; \
1321 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1322 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,13); \
1323 break; \
1324 case S390_DFP_ROUND_AWAY_0: \
1325 cc = S390_CC_FOR_DFP_UCONVERT_AUX(opcode,cc_dep1,14); \
1326 break; \
1327 default: \
1328 vpanic("unexpected dfp rounding mode"); \
1330 cc; \
1333 #define S390_CC_FOR_DFP128_CONVERT_AUX(opcode,hi,lo,rounding_mode) \
1334 ({ \
1335 union s390x_F128 op = { .i = { hi, lo } }; \
1336 Double tmp; \
1337 __asm__ volatile ( \
1338 opcode ",%[tmp],%[op]," #rounding_mode ",0\n\t" \
1339 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
1340 : [op] "f"(op.f) \
1341 : "cc"); \
1342 psw >> 28; /* cc */ \
1345 #define S390_CC_FOR_DFP128_CONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1346 ({ \
1347 UInt cc; \
1348 /* Recover the original DEP2 value. See comment near \
1349 s390_cc_thunk_put3 for rationale. */ \
1350 cc_dep2 = cc_dep2 ^ cc_ndep; \
1351 switch (decode_dfp_rounding_mode(cc_ndep)) { \
1352 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1353 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1354 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,1); \
1355 break; \
1356 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1357 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1358 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,3); \
1359 break; \
1360 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1361 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1362 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1363 break; \
1364 case S390_DFP_ROUND_ZERO_5: \
1365 case S390_DFP_ROUND_ZERO_9: \
1366 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1367 break; \
1368 case S390_DFP_ROUND_POSINF_6: \
1369 case S390_DFP_ROUND_POSINF_10: \
1370 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1371 break; \
1372 case S390_DFP_ROUND_NEGINF_7: \
1373 case S390_DFP_ROUND_NEGINF_11: \
1374 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1375 break; \
1376 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1377 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,13); \
1378 break; \
1379 case S390_DFP_ROUND_AWAY_0: \
1380 cc = S390_CC_FOR_DFP128_CONVERT_AUX(opcode,cc_dep1,cc_dep2,14); \
1381 break; \
1382 default: \
1383 vpanic("unexpected dfp rounding mode"); \
1385 cc; \
1388 #define S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,hi,lo,rounding_mode) \
1389 ({ \
1390 union s390x_F128 op = { .i = { hi, lo } }; \
1391 Double tmp; \
1392 __asm__ volatile ( \
1393 opcode ",%[tmp],%[op]," #rounding_mode ",0\n\t" \
1394 "ipm %[psw]\n\t" : [psw] "=d"(psw), [tmp] "=f"(tmp) \
1395 : [op] "f"(op.f) \
1396 : "cc"); \
1397 psw >> 28; /* cc */ \
1400 #define S390_CC_FOR_DFP128_UCONVERT(opcode,cc_dep1,cc_dep2,cc_ndep) \
1401 ({ \
1402 UInt cc; \
1403 /* Recover the original DEP2 value. See comment near \
1404 s390_cc_thunk_put3 for rationale. */ \
1405 cc_dep2 = cc_dep2 ^ cc_ndep; \
1406 switch (decode_dfp_rounding_mode(cc_ndep)) { \
1407 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_1: \
1408 case S390_DFP_ROUND_NEAREST_TIE_AWAY_0_12: \
1409 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,1); \
1410 break; \
1411 case S390_DFP_ROUND_PREPARE_SHORT_3: \
1412 case S390_DFP_ROUND_PREPARE_SHORT_15: \
1413 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,3); \
1414 break; \
1415 case S390_DFP_ROUND_NEAREST_EVEN_4: \
1416 case S390_DFP_ROUND_NEAREST_EVEN_8: \
1417 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,4); \
1418 break; \
1419 case S390_DFP_ROUND_ZERO_5: \
1420 case S390_DFP_ROUND_ZERO_9: \
1421 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,5); \
1422 break; \
1423 case S390_DFP_ROUND_POSINF_6: \
1424 case S390_DFP_ROUND_POSINF_10: \
1425 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,6); \
1426 break; \
1427 case S390_DFP_ROUND_NEGINF_7: \
1428 case S390_DFP_ROUND_NEGINF_11: \
1429 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,7); \
1430 break; \
1431 case S390_DFP_ROUND_NEAREST_TIE_TOWARD_0: \
1432 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,13); \
1433 break; \
1434 case S390_DFP_ROUND_AWAY_0: \
1435 cc = S390_CC_FOR_DFP128_UCONVERT_AUX(opcode,cc_dep1,cc_dep2,14); \
1436 break; \
1437 default: \
1438 vpanic("unexpected dfp rounding mode"); \
1440 cc; \
1442 #endif /* VGA_s390x */
1445 /* Return the value of the condition code from the supplied thunk parameters.
1446 This is not the value of the PSW. It is the value of the 2 CC bits within
1447 the PSW. The returned value is thusly in the interval [0:3]. */
1448 UInt
1449 s390_calculate_cc(ULong cc_op, ULong cc_dep1, ULong cc_dep2, ULong cc_ndep)
1451 #if defined(VGA_s390x)
1452 UInt psw;
1454 switch (cc_op) {
1456 case S390_CC_OP_BITWISE:
1457 return S390_CC_FOR_BINARY("ogr", cc_dep1, (ULong)0);
1459 case S390_CC_OP_SIGNED_COMPARE:
1460 return S390_CC_FOR_BINARY("cgr", cc_dep1, cc_dep2);
1462 case S390_CC_OP_UNSIGNED_COMPARE:
1463 return S390_CC_FOR_BINARY("clgr", cc_dep1, cc_dep2);
1465 case S390_CC_OP_SIGNED_ADD_64:
1466 return S390_CC_FOR_BINARY("agr", cc_dep1, cc_dep2);
1468 case S390_CC_OP_SIGNED_ADD_32:
1469 return S390_CC_FOR_BINARY("ar", cc_dep1, cc_dep2);
1471 case S390_CC_OP_SIGNED_SUB_64:
1472 return S390_CC_FOR_BINARY("sgr", cc_dep1, cc_dep2);
1474 case S390_CC_OP_SIGNED_SUB_32:
1475 return S390_CC_FOR_BINARY("sr", cc_dep1, cc_dep2);
1477 case S390_CC_OP_UNSIGNED_ADD_64:
1478 return S390_CC_FOR_BINARY("algr", cc_dep1, cc_dep2);
1480 case S390_CC_OP_UNSIGNED_ADD_32:
1481 return S390_CC_FOR_BINARY("alr", cc_dep1, cc_dep2);
1483 case S390_CC_OP_UNSIGNED_ADDC_64:
1484 return S390_CC_FOR_TERNARY_ADDC("alcgr", cc_dep1, cc_dep2, cc_ndep);
1486 case S390_CC_OP_UNSIGNED_ADDC_32:
1487 return S390_CC_FOR_TERNARY_ADDC("alcr", cc_dep1, cc_dep2, cc_ndep);
1489 case S390_CC_OP_UNSIGNED_SUB_64:
1490 return S390_CC_FOR_BINARY("slgr", cc_dep1, cc_dep2);
1492 case S390_CC_OP_UNSIGNED_SUB_32:
1493 return S390_CC_FOR_BINARY("slr", cc_dep1, cc_dep2);
1495 case S390_CC_OP_UNSIGNED_SUBB_64:
1496 return S390_CC_FOR_TERNARY_SUBB("slbgr", cc_dep1, cc_dep2, cc_ndep);
1498 case S390_CC_OP_UNSIGNED_SUBB_32:
1499 return S390_CC_FOR_TERNARY_SUBB("slbr", cc_dep1, cc_dep2, cc_ndep);
1501 case S390_CC_OP_LOAD_AND_TEST:
1502 /* Like signed comparison with 0 */
1503 return S390_CC_FOR_BINARY("cgr", cc_dep1, (Long)0);
1505 case S390_CC_OP_LOAD_POSITIVE_32:
1506 __asm__ volatile (
1507 "lpr %[result],%[op]\n\t"
1508 "ipm %[psw]\n\t" : [psw] "=d"(psw), [result] "=d"(cc_dep1)
1509 : [op] "d"(cc_dep1)
1510 : "cc");
1511 return psw >> 28; /* cc */
1513 case S390_CC_OP_LOAD_POSITIVE_64:
1514 __asm__ volatile (
1515 "lpgr %[result],%[op]\n\t"
1516 "ipm %[psw]\n\t" : [psw] "=d"(psw), [result] "=d"(cc_dep1)
1517 : [op] "d"(cc_dep1)
1518 : "cc");
1519 return psw >> 28; /* cc */
1521 case S390_CC_OP_TEST_UNDER_MASK_8: {
1522 UChar value = cc_dep1;
1523 UChar mask = cc_dep2;
1524 ULong pc;
1526 __asm__ volatile (
1527 "bras %[pc],1f\n\t" /* pc = address of next insn */
1528 "tm %[value],0\n\t" /* this is skipped, then EXecuted */
1529 "1: ex %[mask],0(%[pc])\n\t" /* EXecute TM after modifying mask */
1530 "ipm %[psw]\n\t" : [psw] "=d"(psw), [pc] "=&a"(pc)
1531 : [value] "Q"(value), [mask] "a"(mask)
1532 : "cc");
1533 return psw >> 28; /* cc */
1536 case S390_CC_OP_TEST_UNDER_MASK_16: {
1537 /* Create a TMLL insn with the mask as given by cc_dep2 */
1538 UInt insn = (0xA701u << 16) | cc_dep2;
1539 UInt value = cc_dep1;
1541 __asm__ volatile (
1542 "lr 1,%[value]\n\t"
1543 "lhi 2,0x10\n\t"
1544 "ex 2,%[insn]\n\t"
1545 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1546 : [value] "d"(value), [insn] "R"(insn)
1547 : "r1", "r2", "cc");
1548 return psw >> 28; /* cc */
1551 case S390_CC_OP_SHIFT_LEFT_32:
1552 __asm__ volatile (
1553 "sla %[op],0(%[amount])\n\t"
1554 "ipm %[psw]\n\t" : [psw] "=d"(psw), [op] "+d"(cc_dep1)
1555 : [amount] "a"(cc_dep2)
1556 : "cc");
1557 return psw >> 28; /* cc */
1559 case S390_CC_OP_SHIFT_LEFT_64: {
1560 Int high = (Int)(cc_dep1 >> 32);
1561 Int low = (Int)(cc_dep1 & 0xFFFFFFFF);
1563 __asm__ volatile (
1564 "lr 2,%[high]\n\t"
1565 "lr 3,%[low]\n\t"
1566 "slda 2,0(%[amount])\n\t"
1567 "ipm %[psw]\n\t" : [psw] "=d"(psw), [high] "+d"(high),
1568 [low] "+d"(low)
1569 : [amount] "a"(cc_dep2)
1570 : "cc", "r2", "r3");
1571 return psw >> 28; /* cc */
1574 case S390_CC_OP_INSERT_CHAR_MASK_32: {
1575 Int inserted = 0;
1576 Int msb = 0;
1578 if (cc_dep2 & 1) {
1579 inserted |= cc_dep1 & 0xff;
1580 msb = 0x80;
1582 if (cc_dep2 & 2) {
1583 inserted |= cc_dep1 & 0xff00;
1584 msb = 0x8000;
1586 if (cc_dep2 & 4) {
1587 inserted |= cc_dep1 & 0xff0000;
1588 msb = 0x800000;
1590 if (cc_dep2 & 8) {
1591 inserted |= cc_dep1 & 0xff000000;
1592 msb = 0x80000000;
1595 if (inserted & msb) // MSB is 1
1596 return 1;
1597 if (inserted > 0)
1598 return 2;
1599 return 0;
1602 case S390_CC_OP_BFP_RESULT_32:
1603 return S390_CC_FOR_BFP_RESULT("ltebr", cc_dep1);
1605 case S390_CC_OP_BFP_RESULT_64:
1606 return S390_CC_FOR_BFP_RESULT("ltdbr", cc_dep1);
1608 case S390_CC_OP_BFP_RESULT_128:
1609 return S390_CC_FOR_BFP128_RESULT(cc_dep1, cc_dep2);
1611 case S390_CC_OP_BFP_32_TO_INT_32:
1612 return S390_CC_FOR_BFP_CONVERT("cfebr", cc_dep1, cc_dep2);
1614 case S390_CC_OP_BFP_64_TO_INT_32:
1615 return S390_CC_FOR_BFP_CONVERT("cfdbr", cc_dep1, cc_dep2);
1617 case S390_CC_OP_BFP_128_TO_INT_32:
1618 return S390_CC_FOR_BFP128_CONVERT("cfxbr", cc_dep1, cc_dep2, cc_ndep);
1620 case S390_CC_OP_BFP_32_TO_INT_64:
1621 return S390_CC_FOR_BFP_CONVERT("cgebr", cc_dep1, cc_dep2);
1623 case S390_CC_OP_BFP_64_TO_INT_64:
1624 return S390_CC_FOR_BFP_CONVERT("cgdbr", cc_dep1, cc_dep2);
1626 case S390_CC_OP_BFP_128_TO_INT_64:
1627 return S390_CC_FOR_BFP128_CONVERT("cgxbr", cc_dep1, cc_dep2, cc_ndep);
1629 case S390_CC_OP_BFP_TDC_32:
1630 return S390_CC_FOR_BFP_TDC("tceb", cc_dep1, cc_dep2);
1632 case S390_CC_OP_BFP_TDC_64:
1633 return S390_CC_FOR_BFP_TDC("tcdb", cc_dep1, cc_dep2);
1635 case S390_CC_OP_BFP_TDC_128:
1636 return S390_CC_FOR_BFP128_TDC(cc_dep1, cc_dep2, cc_ndep);
1638 case S390_CC_OP_SET:
1639 return cc_dep1;
1641 case S390_CC_OP_BFP_32_TO_UINT_32:
1642 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb39c0000", cc_dep1, cc_dep2);
1644 case S390_CC_OP_BFP_64_TO_UINT_32:
1645 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb39d0000", cc_dep1, cc_dep2);
1647 case S390_CC_OP_BFP_128_TO_UINT_32:
1648 return S390_CC_FOR_BFP128_UCONVERT(".insn rrf,0xb39e0000", cc_dep1,
1649 cc_dep2, cc_ndep);
1651 case S390_CC_OP_BFP_32_TO_UINT_64:
1652 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb3ac0000", cc_dep1, cc_dep2);
1654 case S390_CC_OP_BFP_64_TO_UINT_64:
1655 return S390_CC_FOR_BFP_UCONVERT(".insn rrf,0xb3ad0000", cc_dep1, cc_dep2);
1657 case S390_CC_OP_BFP_128_TO_UINT_64:
1658 return S390_CC_FOR_BFP128_UCONVERT(".insn rrf,0xb3ae0000", cc_dep1,
1659 cc_dep2, cc_ndep);
1661 case S390_CC_OP_DFP_RESULT_64:
1662 return S390_CC_FOR_DFP_RESULT(cc_dep1);
1664 case S390_CC_OP_DFP_RESULT_128:
1665 return S390_CC_FOR_DFP128_RESULT(cc_dep1, cc_dep2);
1667 case S390_CC_OP_DFP_TDC_32: /* TDCET */
1668 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000050", cc_dep1, cc_dep2);
1670 case S390_CC_OP_DFP_TDC_64: /* TDCDT */
1671 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000054", cc_dep1, cc_dep2);
1673 case S390_CC_OP_DFP_TDC_128: /* TDCXT */
1674 return S390_CC_FOR_DFP128_TD(".insn rxe, 0xed0000000058", cc_dep1,
1675 cc_dep2, cc_ndep);
1677 case S390_CC_OP_DFP_TDG_32: /* TDGET */
1678 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000051", cc_dep1, cc_dep2);
1680 case S390_CC_OP_DFP_TDG_64: /* TDGDT */
1681 return S390_CC_FOR_DFP_TD(".insn rxe, 0xed0000000055", cc_dep1, cc_dep2);
1683 case S390_CC_OP_DFP_TDG_128: /* TDGXT */
1684 return S390_CC_FOR_DFP128_TD(".insn rxe, 0xed0000000059", cc_dep1,
1685 cc_dep2, cc_ndep);
1687 case S390_CC_OP_DFP_64_TO_INT_32: /* CFDTR */
1688 return S390_CC_FOR_DFP_CONVERT(".insn rrf,0xb9410000", cc_dep1, cc_dep2);
1690 case S390_CC_OP_DFP_128_TO_INT_32: /* CFXTR */
1691 return S390_CC_FOR_DFP128_CONVERT(".insn rrf,0xb9490000", cc_dep1,
1692 cc_dep2, cc_ndep);
1694 case S390_CC_OP_DFP_64_TO_INT_64: /* CGDTR */
1695 return S390_CC_FOR_DFP_CONVERT(".insn rrf,0xb3e10000", cc_dep1, cc_dep2);
1697 case S390_CC_OP_DFP_128_TO_INT_64: /* CGXTR */
1698 return S390_CC_FOR_DFP128_CONVERT(".insn rrf,0xb3e90000", cc_dep1,
1699 cc_dep2, cc_ndep);
1701 case S390_CC_OP_DFP_64_TO_UINT_32: /* CLFDTR */
1702 return S390_CC_FOR_DFP_UCONVERT(".insn rrf,0xb9430000", cc_dep1, cc_dep2);
1704 case S390_CC_OP_DFP_128_TO_UINT_32: /* CLFXTR */
1705 return S390_CC_FOR_DFP128_UCONVERT(".insn rrf,0xb94b0000", cc_dep1,
1706 cc_dep2, cc_ndep);
1708 case S390_CC_OP_DFP_64_TO_UINT_64: /* CLGDTR */
1709 return S390_CC_FOR_DFP_UCONVERT(".insn rrf,0xb9420000", cc_dep1, cc_dep2);
1711 case S390_CC_OP_DFP_128_TO_UINT_64: /* CLGXTR */
1712 return S390_CC_FOR_DFP128_UCONVERT(".insn rrf,0xb94a0000", cc_dep1,
1713 cc_dep2, cc_ndep);
1715 case S390_CC_OP_PFPO_32: {
1716 __asm__ volatile(
1717 "ldgr 4, %[cc_dep1]\n\t" /* Load FR from GR */
1718 "lr 0, %[cc_dep2]\n\t" /* 32 bit GR move */
1719 ".insn e,0x010a\n\t" /* PFPO */
1720 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1721 : [cc_dep1] "d"(cc_dep1),
1722 [cc_dep2] "d"(cc_dep2)
1723 : "r0", "r1", "f4");
1724 return psw >> 28; /* cc */
1727 case S390_CC_OP_PFPO_64: {
1728 __asm__ volatile(
1729 "ldgr 4, %[cc_dep1]\n\t"
1730 "lr 0, %[cc_dep2]\n\t" /* 32 bit register move */
1731 ".insn e,0x010a\n\t" /* PFPO */
1732 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1733 : [cc_dep1] "d"(cc_dep1),
1734 [cc_dep2] "d"(cc_dep2)
1735 : "r0", "r1", "f4");
1736 return psw >> 28; /* cc */
1739 case S390_CC_OP_PFPO_128: {
1740 __asm__ volatile(
1741 "ldgr 4,%[cc_dep1]\n\t"
1742 "ldgr 6,%[cc_dep2]\n\t"
1743 "lr 0,%[cc_ndep]\n\t" /* 32 bit register move */
1744 ".insn e,0x010a\n\t" /* PFPO */
1745 "ipm %[psw]\n\t" : [psw] "=d"(psw)
1746 : [cc_dep1] "d"(cc_dep1),
1747 [cc_dep2] "d"(cc_dep2),
1748 [cc_ndep] "d"(cc_ndep)
1749 : "r0", "r1", "f0", "f2", "f4", "f6");
1750 return psw >> 28; /* cc */
1753 case S390_CC_OP_MUL_32:
1754 return S390_CC_FOR_TERNARY(".insn rrf,0xb9fd0000", cc_dep1, cc_dep2);
1756 case S390_CC_OP_MUL_64:
1757 return S390_CC_FOR_TERNARY(".insn rrf,0xb9ed0000", cc_dep1, cc_dep2);
1759 default:
1760 break;
1762 #endif
1763 vpanic("s390_calculate_cc");
1767 /* Note that this does *not* return a Boolean value. The result needs to be
1768 explicitly tested against zero. */
1769 UInt
1770 s390_calculate_cond(ULong mask, ULong op, ULong dep1, ULong dep2, ULong ndep)
1772 UInt cc = s390_calculate_cc(op, dep1, dep2, ndep);
1774 return ((mask << cc) & 0x8);
1777 /*------------------------------------------------------------*/
1778 /*--- spechelper for performance ---*/
1779 /*------------------------------------------------------------*/
1782 /* Convenience macros */
1783 #define unop(op,a1) IRExpr_Unop((op),(a1))
1784 #define binop(op,a1,a2) IRExpr_Binop((op),(a1),(a2))
1785 #define mkU64(v) IRExpr_Const(IRConst_U64(v))
1786 #define mkU32(v) IRExpr_Const(IRConst_U32(v))
1787 #define mkU8(v) IRExpr_Const(IRConst_U8(v))
1790 static inline Bool
1791 isC64(const IRExpr *expr)
1793 return expr->tag == Iex_Const && expr->Iex.Const.con->tag == Ico_U64;
1796 static inline Bool
1797 isC64_exactly(const IRExpr *expr, ULong n)
1799 return expr->tag == Iex_Const && expr->Iex.Const.con->tag == Ico_U64
1800 && expr->Iex.Const.con->Ico.U64 == n;
1804 /* The returned expression is NULL if no specialization was found. In that
1805 case the helper function will be called. Otherwise, the expression has
1806 type Ity_I32 and a Boolean value. */
1807 IRExpr *
1808 guest_s390x_spechelper(const HChar *function_name, IRExpr **args,
1809 IRStmt **precedingStmts, Int n_precedingStmts)
1811 UInt i, arity = 0;
1813 for (i = 0; args[i]; i++)
1814 arity++;
1816 # if 0
1817 vex_printf("spec request:\n");
1818 vex_printf(" %s ", function_name);
1819 for (i = 0; i < arity; i++) {
1820 vex_printf(" ");
1821 ppIRExpr(args[i]);
1823 vex_printf("\n");
1824 # endif
1826 /* --------- Specialising "s390_calculate_cond" --------- */
1828 if (vex_streq(function_name, "s390_calculate_cond")) {
1829 IRExpr *cond_expr, *cc_op_expr, *cc_dep1, *cc_dep2;
1830 ULong cond, cc_op;
1832 vassert(arity == 5);
1834 cond_expr = args[0];
1835 cc_op_expr = args[1];
1837 /* The necessary requirement for all optimizations here is that the
1838 condition and the cc_op are constant. So check that upfront. */
1839 if (! isC64(cond_expr)) return NULL;
1840 if (! isC64(cc_op_expr)) return NULL;
1842 cond = cond_expr->Iex.Const.con->Ico.U64;
1843 cc_op = cc_op_expr->Iex.Const.con->Ico.U64;
1845 vassert(cond <= 15);
1848 +------+---+---+---+---+
1849 | cc | 0 | 1 | 2 | 3 |
1850 | cond | 8 | 4 | 2 | 1 |
1851 +------+---+---+---+---+
1853 cc_dep1 = args[2];
1854 cc_dep2 = args[3];
1856 /* S390_CC_OP_SIGNED_COMPARE */
1857 if (cc_op == S390_CC_OP_SIGNED_COMPARE) {
1859 cc == 0 --> cc_dep1 == cc_dep2 (cond == 8)
1860 cc == 1 --> cc_dep1 < cc_dep2 (cond == 4)
1861 cc == 2 --> cc_dep1 > cc_dep2 (cond == 2)
1863 Because cc == 3 cannot occur the rightmost bit of cond is
1864 a don't care.
1866 if (cond == 8 || cond == 8 + 1) {
1867 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
1869 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
1870 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, cc_dep2));
1872 if (cond == 4 || cond == 4 + 1) {
1873 if (isC64_exactly(cc_dep2, 0)) {
1874 /* dep1 <signed 0
1875 --> m.s.bit of dep1 == 1 */
1876 return unop(Iop_64to32,
1877 binop(Iop_And64,
1878 binop(Iop_Shr64, cc_dep1, mkU8(63)),
1879 mkU64(1)));
1881 return unop(Iop_1Uto32, binop(Iop_CmpLT64S, cc_dep1, cc_dep2));
1883 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
1884 return unop(Iop_1Uto32, binop(Iop_CmpLE64S, cc_dep1, cc_dep2));
1886 /* cc_dep1 > cc_dep2 ----> cc_dep2 < cc_dep1 */
1887 if (cond == 2 || cond == 2 + 1) {
1888 /* If we ever need the counterpart of the bug387712 fix just
1889 below, then here is the place. We'll need to give an
1890 alternative expression for the case "cc_dep2 <s 0". From a
1891 bit of simple testing, I've yet to see any such cases,
1892 however. */
1893 return unop(Iop_1Uto32, binop(Iop_CmpLT64S, cc_dep2, cc_dep1));
1895 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
1896 if (isC64_exactly(cc_dep2, 0)) {
1897 /* 0 <=signed dep1
1898 --> dep1 >=signed 0
1899 --> m.s.bit of dep1 == 0 */
1900 /* See bug 387712. This is an old trick from gcc to extract
1901 the most significant bit of a word. */
1902 return unop(Iop_64to32,
1903 binop(Iop_Xor64,
1904 binop(Iop_Shr64, cc_dep1, mkU8(63)),
1905 mkU64(1)));
1907 return unop(Iop_1Uto32, binop(Iop_CmpLE64S, cc_dep2, cc_dep1));
1909 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
1910 return mkU32(1);
1912 /* Remaining case */
1913 return mkU32(0);
1916 /* S390_CC_OP_UNSIGNED_COMPARE */
1917 if (cc_op == S390_CC_OP_UNSIGNED_COMPARE) {
1919 cc == 0 --> cc_dep1 == cc_dep2 (cond == 8)
1920 cc == 1 --> cc_dep1 < cc_dep2 (cond == 4)
1921 cc == 2 --> cc_dep1 > cc_dep2 (cond == 2)
1923 Because cc == 3 cannot occur the rightmost bit of cond is
1924 a don't care.
1926 if (isC64(cc_dep2)) {
1927 /* Avoid memcheck false positives for comparisons like `<= 0x1f',
1928 `> 0x1f', `< 0x20', or `>= 0x20', where the lower bits don't
1929 matter. Some compiler optimizations yield such comparisons when
1930 testing if any (or none) of the upper bits are set. */
1932 ULong mask = cc_dep2->Iex.Const.con->Ico.U64;
1933 ULong c = cond & (8 + 4 + 2);
1935 if ((mask & (mask - 1)) == 0) {
1936 /* Transform `< 0x20' to `<= 0x1f' and
1937 `>= 0x20' to `> 0x1f' */
1938 mask -= 1;
1939 c ^= 8;
1941 if (mask != 0 && (mask + 1) != 0 && (mask & (mask + 1)) == 0 &&
1942 (c == 8 + 4 || c == 2)) {
1943 IROp cmp = c == 8 + 4 ? Iop_CmpEQ64 : Iop_CmpNE64;
1944 return unop(Iop_1Uto32,
1945 binop(cmp, binop(Iop_And64, cc_dep1, mkU64(~mask)),
1946 mkU64(0)));
1949 if (cond == 8 || cond == 8 + 1) {
1950 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
1952 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
1953 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, cc_dep2));
1955 if (cond == 4 || cond == 4 + 1) {
1956 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep1, cc_dep2));
1958 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
1959 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep1, cc_dep2));
1961 /* cc_dep1 > cc_dep2 ----> cc_dep2 < cc_dep1 */
1962 if (cond == 2 || cond == 2 + 1) {
1963 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep2, cc_dep1));
1965 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
1966 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep2, cc_dep1));
1968 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
1969 return mkU32(1);
1971 /* Remaining case */
1972 return mkU32(0);
1975 /* S390_CC_OP_LOAD_AND_TEST */
1976 if (cc_op == S390_CC_OP_LOAD_AND_TEST) {
1978 cc == 0 --> cc_dep1 == 0 (cond == 8)
1979 cc == 1 --> cc_dep1 < 0 (cond == 4)
1980 cc == 2 --> cc_dep1 > 0 (cond == 2)
1982 Because cc == 3 cannot occur the rightmost bit of cond is
1983 a don't care.
1985 if (cond == 8 || cond == 8 + 1) {
1986 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, mkU64(0)));
1988 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
1989 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, mkU64(0)));
1991 if (cond == 4 || cond == 4 + 1) {
1992 /* Special case cc_dep < 0. Only check the MSB to avoid bogus
1993 memcheck complaints due to gcc magic. Fixes 343802
1995 return unop(Iop_64to32, binop(Iop_Shr64, cc_dep1, mkU8(63)));
1997 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
1998 return unop(Iop_1Uto32, binop(Iop_CmpLE64S, cc_dep1, mkU64(0)));
2000 /* cc_dep1 > 0 ----> 0 < cc_dep1 */
2001 if (cond == 2 || cond == 2 + 1) {
2002 return unop(Iop_1Uto32, binop(Iop_CmpLT64S, mkU64(0), cc_dep1));
2004 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
2005 /* Special case cc_dep >= 0. Only check the MSB to avoid bogus
2006 memcheck complaints due to gcc magic. Fixes 308427
2008 return unop(Iop_64to32, binop(Iop_Xor64,
2009 binop(Iop_Shr64, cc_dep1, mkU8(63)),
2010 mkU64(1)));
2012 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
2013 return mkU32(1);
2015 /* Remaining case */
2016 return mkU32(0);
2019 /* S390_CC_OP_BITWISE */
2020 if (cc_op == S390_CC_OP_BITWISE) {
2022 cc_dep1 is the result of the boolean operation.
2024 cc == 0 --> cc_dep1 == 0 (cond == 8)
2025 cc == 1 --> cc_dep1 != 0 (cond == 4)
2027 Because cc == 2 and cc == 3 cannot occur the two rightmost bits of
2028 cond are don't cares. Therefore:
2030 cond == 00xx -> always false
2031 cond == 01xx -> not equal
2032 cond == 10xx -> equal
2033 cond == 11xx -> always true
2035 if ((cond & (8 + 4)) == 8 + 4) {
2036 return mkU32(1);
2038 if (cond & 8) {
2039 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, mkU64(0)));
2041 if (cond & 4) {
2042 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, mkU64(0)));
2044 /* Remaining case */
2045 return mkU32(0);
2048 /* S390_CC_OP_INSERT_CHAR_MASK_32
2049 Since the mask comes from an immediate field in the opcode, we
2050 expect the mask to be a constant here. That simplifies matters. */
2051 if (cc_op == S390_CC_OP_INSERT_CHAR_MASK_32) {
2052 ULong mask;
2053 UInt imask = 0, shift = 0;
2054 IRExpr *word;
2056 if (! isC64(cc_dep2)) goto missed;
2058 mask = cc_dep2->Iex.Const.con->Ico.U64;
2060 /* Extract the 32-bit value from the thunk */
2062 word = unop(Iop_64to32, cc_dep1);
2064 switch (mask) {
2065 case 0: shift = 0; imask = 0x00000000; break;
2066 case 1: shift = 24; imask = 0x000000FF; break;
2067 case 2: shift = 16; imask = 0x0000FF00; break;
2068 case 3: shift = 16; imask = 0x0000FFFF; break;
2069 case 4: shift = 8; imask = 0x00FF0000; break;
2070 case 5: shift = 8; imask = 0x00FF00FF; break;
2071 case 6: shift = 8; imask = 0x00FFFF00; break;
2072 case 7: shift = 8; imask = 0x00FFFFFF; break;
2073 case 8: shift = 0; imask = 0xFF000000; break;
2074 case 9: shift = 0; imask = 0xFF0000FF; break;
2075 case 10: shift = 0; imask = 0xFF00FF00; break;
2076 case 11: shift = 0; imask = 0xFF00FFFF; break;
2077 case 12: shift = 0; imask = 0xFFFF0000; break;
2078 case 13: shift = 0; imask = 0xFFFF00FF; break;
2079 case 14: shift = 0; imask = 0xFFFFFF00; break;
2080 case 15: shift = 0; imask = 0xFFFFFFFF; break;
2083 /* Select the bits that were inserted */
2084 word = binop(Iop_And32, word, mkU32(imask));
2086 /* cc == 0 --> all inserted bits zero or mask == 0 (cond == 8)
2087 cc == 1 --> leftmost inserted bit is one (cond == 4)
2088 cc == 2 --> leftmost inserted bit is zero and not (cond == 2)
2089 all inserted bits are zero
2091 Because cc == 0,1,2 the rightmost bit of the mask is a don't care */
2092 if (cond == 8 || cond == 8 + 1) {
2093 return unop(Iop_1Uto32, binop(Iop_CmpEQ32, word, mkU32(0)));
2095 if (cond == 4 + 2 || cond == 4 + 2 + 1) {
2096 return unop(Iop_1Uto32, binop(Iop_CmpNE32, word, mkU32(0)));
2099 /* Sign extend */
2100 if (shift != 0) {
2101 word = binop(Iop_Sar32, binop(Iop_Shl32, word, mkU8(shift)),
2102 mkU8(shift));
2105 if (cond == 4 || cond == 4 + 1) { /* word < 0 */
2106 return unop(Iop_1Uto32, binop(Iop_CmpLT32S, word, mkU32(0)));
2108 if (cond == 2 || cond == 2 + 1) { /* word > 0 */
2109 return unop(Iop_1Uto32, binop(Iop_CmpLT32S, mkU32(0), word));
2111 if (cond == 8 + 4 || cond == 8 + 4 + 1) {
2112 return unop(Iop_1Uto32, binop(Iop_CmpLE32S, word, mkU32(0)));
2114 if (cond == 8 + 2 || cond == 8 + 2 + 1) {
2115 return unop(Iop_1Uto32, binop(Iop_CmpLE32S, mkU32(0), word));
2117 if (cond == 8 + 4 + 2 || cond == 8 + 4 + 2 + 1) {
2118 return mkU32(1);
2120 /* Remaining case */
2121 return mkU32(0);
2124 /* S390_CC_OP_TEST_UNDER_MASK_8
2125 Since the mask comes from an immediate field in the opcode, we
2126 expect the mask to be a constant here. That simplifies matters. */
2127 if (cc_op == S390_CC_OP_TEST_UNDER_MASK_8) {
2128 ULong mask16;
2130 if (! isC64(cc_dep2)) goto missed;
2132 mask16 = cc_dep2->Iex.Const.con->Ico.U64;
2134 /* Get rid of the mask16 == 0 case first. Some of the simplifications
2135 below (e.g. for OVFL) only hold if mask16 == 0. */
2136 if (mask16 == 0) { /* cc == 0 */
2137 if (cond & 0x8) return mkU32(1);
2138 return mkU32(0);
2141 /* cc == 2 is a don't care */
2142 if (cond == 8 || cond == 8 + 2) {
2143 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2144 binop(Iop_And64, cc_dep1, cc_dep2),
2145 mkU64(0)));
2147 if (cond == 7 || cond == 7 - 2) {
2148 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2149 binop(Iop_And64, cc_dep1, cc_dep2),
2150 mkU64(0)));
2152 if (cond == 1 || cond == 1 + 2) {
2153 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2154 binop(Iop_And64, cc_dep1, cc_dep2),
2155 cc_dep2));
2157 if (cond == 14 || cond == 14 - 2) { /* ! OVFL */
2158 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2159 binop(Iop_And64, cc_dep1, cc_dep2),
2160 cc_dep2));
2162 goto missed;
2165 /* S390_CC_OP_TEST_UNDER_MASK_16
2166 Since the mask comes from an immediate field in the opcode, we
2167 expect the mask to be a constant here. That simplifies matters. */
2168 if (cc_op == S390_CC_OP_TEST_UNDER_MASK_16) {
2169 ULong mask16;
2170 UInt msb;
2172 if (! isC64(cc_dep2)) goto missed;
2174 mask16 = cc_dep2->Iex.Const.con->Ico.U64;
2176 /* Get rid of the mask16 == 0 case first. Some of the simplifications
2177 below (e.g. for OVFL) only hold if mask16 == 0. */
2178 if (mask16 == 0) { /* cc == 0 */
2179 if (cond & 0x8) return mkU32(1);
2180 return mkU32(0);
2183 if (cond == 15) return mkU32(1);
2185 if (cond == 8) {
2186 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2187 binop(Iop_And64, cc_dep1, cc_dep2),
2188 mkU64(0)));
2190 if (cond == 7) {
2191 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2192 binop(Iop_And64, cc_dep1, cc_dep2),
2193 mkU64(0)));
2195 if (cond == 1) {
2196 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2197 binop(Iop_And64, cc_dep1, cc_dep2),
2198 mkU64(mask16)));
2200 if (cond == 14) { /* ! OVFL */
2201 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2202 binop(Iop_And64, cc_dep1, cc_dep2),
2203 mkU64(mask16)));
2206 /* Find MSB in mask */
2207 msb = 0x8000;
2208 while (msb > mask16)
2209 msb >>= 1;
2211 if (cond == 2) { /* cc == 2 */
2212 IRExpr *c1, *c2;
2214 /* (cc_dep & msb) != 0 && (cc_dep & mask16) != mask16 */
2215 c1 = binop(Iop_CmpNE64,
2216 binop(Iop_And64, cc_dep1, mkU64(msb)), mkU64(0));
2217 c2 = binop(Iop_CmpNE64,
2218 binop(Iop_And64, cc_dep1, cc_dep2),
2219 mkU64(mask16));
2220 return binop(Iop_And32, unop(Iop_1Uto32, c1),
2221 unop(Iop_1Uto32, c2));
2224 if (cond == 4) { /* cc == 1 */
2225 IRExpr *c1, *c2;
2227 /* (cc_dep & msb) == 0 && (cc_dep & mask16) != 0 */
2228 c1 = binop(Iop_CmpEQ64,
2229 binop(Iop_And64, cc_dep1, mkU64(msb)), mkU64(0));
2230 c2 = binop(Iop_CmpNE64,
2231 binop(Iop_And64, cc_dep1, cc_dep2),
2232 mkU64(0));
2233 return binop(Iop_And32, unop(Iop_1Uto32, c1),
2234 unop(Iop_1Uto32, c2));
2237 if (cond == 11) { /* cc == 0,2,3 */
2238 IRExpr *c1, *c2;
2240 c1 = binop(Iop_CmpNE64,
2241 binop(Iop_And64, cc_dep1, mkU64(msb)), mkU64(0));
2242 c2 = binop(Iop_CmpEQ64,
2243 binop(Iop_And64, cc_dep1, cc_dep2),
2244 mkU64(0));
2245 return binop(Iop_Or32, unop(Iop_1Uto32, c1),
2246 unop(Iop_1Uto32, c2));
2249 if (cond == 3) { /* cc == 2 || cc == 3 */
2250 return unop(Iop_1Uto32,
2251 binop(Iop_CmpNE64,
2252 binop(Iop_And64, cc_dep1, mkU64(msb)),
2253 mkU64(0)));
2255 if (cond == 12) { /* cc == 0 || cc == 1 */
2256 return unop(Iop_1Uto32,
2257 binop(Iop_CmpEQ64,
2258 binop(Iop_And64, cc_dep1, mkU64(msb)),
2259 mkU64(0)));
2261 if (cond == 13) { /* cc == 0 || cc == 1 || cc == 3 */
2262 IRExpr *c01, *c3;
2264 c01 = binop(Iop_CmpEQ64, binop(Iop_And64, cc_dep1, mkU64(msb)),
2265 mkU64(0));
2266 c3 = binop(Iop_CmpEQ64, binop(Iop_And64, cc_dep1, cc_dep2),
2267 mkU64(mask16));
2268 return binop(Iop_Or32, unop(Iop_1Uto32, c01),
2269 unop(Iop_1Uto32, c3));
2271 // fixs390: handle cond = 5,6,9,10 (the missing cases)
2272 // vex_printf("TUM mask = 0x%llx\n", mask16);
2273 goto missed;
2276 /* S390_CC_OP_UNSIGNED_SUB_64/32 */
2277 if (cc_op == S390_CC_OP_UNSIGNED_SUB_64 ||
2278 cc_op == S390_CC_OP_UNSIGNED_SUB_32) {
2280 cc_dep1, cc_dep2 are the zero extended left and right operands
2282 cc == 1 --> result != 0, borrow (cond == 4)
2283 cc == 2 --> result == 0, no borrow (cond == 2)
2284 cc == 3 --> result != 0, no borrow (cond == 1)
2286 cc = (cc_dep1 == cc_dep2) ? 2
2287 : (cc_dep1 > cc_dep2) ? 3 : 1;
2289 Because cc == 0 cannot occur the leftmost bit of cond is
2290 a don't care.
2292 if (cond == 1 || cond == 1 + 8) { /* cc == 3 op2 < op1 */
2293 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep2, cc_dep1));
2295 if (cond == 2 || cond == 2 + 8) { /* cc == 2 */
2296 return unop(Iop_1Uto32, binop(Iop_CmpEQ64, cc_dep1, cc_dep2));
2298 if (cond == 4 || cond == 4 + 8) { /* cc == 1 */
2299 return unop(Iop_1Uto32, binop(Iop_CmpLT64U, cc_dep1, cc_dep2));
2301 if (cond == 3 || cond == 3 + 8) { /* cc == 2 || cc == 3 */
2302 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep2, cc_dep1));
2304 if (cond == 6 || cond == 6 + 8) { /* cc == 2 || cc == 1 */
2305 return unop(Iop_1Uto32, binop(Iop_CmpLE64U, cc_dep1, cc_dep2));
2308 if (cond == 5 || cond == 5 + 8) { /* cc == 3 || cc == 1 */
2309 return unop(Iop_1Uto32, binop(Iop_CmpNE64, cc_dep1, cc_dep2));
2311 if (cond == 7 || cond == 7 + 8) {
2312 return mkU32(1);
2314 /* Remaining case */
2315 return mkU32(0);
2318 /* S390_CC_OP_UNSIGNED_ADD_64 */
2319 if (cc_op == S390_CC_OP_UNSIGNED_ADD_64) {
2321 cc_dep1, cc_dep2 are the zero extended left and right operands
2323 cc == 0 --> result == 0, no carry (cond == 8)
2324 cc == 1 --> result != 0, no carry (cond == 4)
2325 cc == 2 --> result == 0, carry (cond == 2)
2326 cc == 3 --> result != 0, carry (cond == 1)
2328 if (cond == 8) { /* cc == 0 */
2329 /* Both inputs are 0 */
2330 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2331 binop(Iop_Or64, cc_dep1, cc_dep2),
2332 mkU64(0)));
2334 if (cond == 7) { /* cc == 1,2,3 */
2335 /* Not both inputs are 0 */
2336 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2337 binop(Iop_Or64, cc_dep1, cc_dep2),
2338 mkU64(0)));
2340 if (cond == 8 + 2) { /* cc == 0,2 -> result is zero */
2341 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2342 binop(Iop_Add64, cc_dep1, cc_dep2),
2343 mkU64(0)));
2345 if (cond == 4 + 1) { /* cc == 1,3 -> result is not zero */
2346 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2347 binop(Iop_Add64, cc_dep1, cc_dep2),
2348 mkU64(0)));
2350 goto missed;
2353 /* S390_CC_OP_UNSIGNED_ADD_32 */
2354 if (cc_op == S390_CC_OP_UNSIGNED_ADD_32) {
2356 cc_dep1, cc_dep2 are the zero extended left and right operands
2358 cc == 0 --> result == 0, no carry (cond == 8)
2359 cc == 1 --> result != 0, no carry (cond == 4)
2360 cc == 2 --> result == 0, carry (cond == 2)
2361 cc == 3 --> result != 0, carry (cond == 1)
2363 if (cond == 8) { /* cc == 0 */
2364 /* Both inputs are 0 */
2365 return unop(Iop_1Uto32, binop(Iop_CmpEQ64,
2366 binop(Iop_Or64, cc_dep1, cc_dep2),
2367 mkU64(0)));
2369 if (cond == 7) { /* cc == 1,2,3 */
2370 /* Not both inputs are 0 */
2371 return unop(Iop_1Uto32, binop(Iop_CmpNE64,
2372 binop(Iop_Or64, cc_dep1, cc_dep2),
2373 mkU64(0)));
2375 if (cond == 8 + 2) { /* cc == 0,2 -> result is zero */
2376 return unop(Iop_1Uto32, binop(Iop_CmpEQ32,
2377 binop(Iop_Add32,
2378 unop(Iop_64to32, cc_dep1),
2379 unop(Iop_64to32, cc_dep2)),
2380 mkU32(0)));
2382 if (cond == 4 + 1) { /* cc == 1,3 -> result is not zero */
2383 return unop(Iop_1Uto32, binop(Iop_CmpNE32,
2384 binop(Iop_Add32,
2385 unop(Iop_64to32, cc_dep1),
2386 unop(Iop_64to32, cc_dep2)),
2387 mkU32(0)));
2389 goto missed;
2392 /* S390_CC_OP_SET */
2393 if (cc_op == S390_CC_OP_SET) {
2394 /* cc_dep1 is the condition code
2396 Return 1, if ((cond << cc_dep1) & 0x8) != 0 */
2398 return unop(Iop_1Uto32,
2399 binop(Iop_CmpNE64,
2400 binop(Iop_And64,
2401 binop(Iop_Shl64, cond_expr,
2402 unop(Iop_64to8, cc_dep1)),
2403 mkU64(8)),
2404 mkU64(0)));
2407 goto missed;
2410 /* --------- Specialising "s390_calculate_cc" --------- */
2412 if (vex_streq(function_name, "s390_calculate_cc")) {
2413 IRExpr *cc_op_expr, *cc_dep1;
2414 ULong cc_op;
2416 vassert(arity == 4);
2418 cc_op_expr = args[0];
2420 /* The necessary requirement for all optimizations here is that
2421 cc_op is constant. So check that upfront. */
2422 if (! isC64(cc_op_expr)) return NULL;
2424 cc_op = cc_op_expr->Iex.Const.con->Ico.U64;
2425 cc_dep1 = args[1];
2427 if (cc_op == S390_CC_OP_BITWISE) {
2428 return unop(Iop_1Uto32,
2429 binop(Iop_CmpNE64, cc_dep1, mkU64(0)));
2432 if (cc_op == S390_CC_OP_SET) {
2433 return unop(Iop_64to32, cc_dep1);
2436 goto missed;
2439 missed:
2440 return NULL;
2443 /*------------------------------------------------------------*/
2444 /*--- Dirty helper for vector instructions ---*/
2445 /*------------------------------------------------------------*/
2447 #if defined(VGA_s390x)
2448 ULong
2449 s390x_dirtyhelper_vec_op(VexGuestS390XState *guest_state,
2450 const ULong serialized)
2452 UInt psw;
2453 s390x_vec_op_details_t details;
2454 const s390x_vec_op_details_t* d = (const s390x_vec_op_details_t*) &details;
2456 details.serialized = serialized;
2458 vassert(d->op > S390_VEC_OP_INVALID && d->op < S390_VEC_OP_LAST);
2459 static const UChar opcodes[][2] = {
2460 {0x00, 0x00}, /* invalid */
2461 [S390_VEC_OP_VPKS] = {0xe7, 0x97},
2462 [S390_VEC_OP_VPKLS] = {0xe7, 0x95},
2463 [S390_VEC_OP_VCEQ] = {0xe7, 0xf8},
2464 [S390_VEC_OP_VTM] = {0xe7, 0xd8},
2465 [S390_VEC_OP_VGFM] = {0xe7, 0xb4},
2466 [S390_VEC_OP_VGFMA] = {0xe7, 0xbc},
2467 [S390_VEC_OP_VMAH] = {0xe7, 0xab},
2468 [S390_VEC_OP_VMALH] = {0xe7, 0xa9},
2469 [S390_VEC_OP_VCH] = {0xe7, 0xfb},
2470 [S390_VEC_OP_VCHL] = {0xe7, 0xf9},
2471 [S390_VEC_OP_VFTCI] = {0xe7, 0x4a},
2472 [S390_VEC_OP_VFMIN] = {0xe7, 0xee},
2473 [S390_VEC_OP_VFMAX] = {0xe7, 0xef},
2474 [S390_VEC_OP_VBPERM]= {0xe7, 0x85},
2475 [S390_VEC_OP_VMSL] = {0xe7, 0xb8},
2476 [S390_VEC_OP_VCNF] = {0xe6, 0x55},
2477 [S390_VEC_OP_VCLFNH]= {0xe6, 0x56},
2478 [S390_VEC_OP_VCFN] = {0xe6, 0x5d},
2479 [S390_VEC_OP_VCLFNL]= {0xe6, 0x5e},
2480 [S390_VEC_OP_VCRNF] = {0xe6, 0x75},
2483 union {
2484 struct {
2485 unsigned int op1 : 8;
2486 unsigned int v1 : 4;
2487 unsigned int v2 : 4;
2488 unsigned int v3 : 4;
2489 unsigned int : 4;
2490 unsigned int m5 : 4;
2491 unsigned int : 4;
2492 unsigned int m4 : 4;
2493 unsigned int rxb : 4;
2494 unsigned int op2 : 8;
2495 } VRR;
2496 struct {
2497 unsigned int op1 : 8;
2498 unsigned int v1 : 4;
2499 unsigned int v2 : 4;
2500 unsigned int v3 : 4;
2501 unsigned int m5 : 4;
2502 unsigned int m6 : 4;
2503 unsigned int : 4;
2504 unsigned int v4 : 4;
2505 unsigned int rxb : 4;
2506 unsigned int op2 : 8;
2507 } VRRd;
2508 struct {
2509 UInt op1 : 8;
2510 UInt v1 : 4;
2511 UInt v2 : 4;
2512 UInt v3 : 4;
2513 UInt : 4;
2514 UInt m6 : 4;
2515 UInt m5 : 4;
2516 UInt m4 : 4;
2517 UInt rxb : 4;
2518 UInt op2 : 8;
2519 } VRRc;
2520 struct {
2521 UInt op1 : 8;
2522 UInt v1 : 4;
2523 UInt v2 : 4;
2524 UInt : 12;
2525 UInt m4 : 4;
2526 UInt m3 : 4;
2527 UInt rxb : 4;
2528 UInt op2 : 8;
2529 } VRRa;
2530 struct {
2531 UInt op1 : 8;
2532 UInt v1 : 4;
2533 UInt v2 : 4;
2534 UInt i3 : 12;
2535 UInt m5 : 4;
2536 UInt m4 : 4;
2537 UInt rxb : 4;
2538 UInt op2 : 8;
2539 } VRIe;
2540 UChar bytes[6];
2541 } the_insn;
2543 the_insn.VRR.op1 = opcodes[d->op][0];
2544 the_insn.bytes[1] = the_insn.bytes[2]
2545 = the_insn.bytes[3] = the_insn.bytes[4] = 0;
2546 the_insn.VRR.op2 = opcodes[d->op][1];
2548 switch(d->op) {
2549 case S390_VEC_OP_VTM:
2550 the_insn.VRR.v1 = 2;
2551 the_insn.VRR.v2 = 3;
2552 the_insn.VRR.rxb = 0b1100;
2553 break;
2555 case S390_VEC_OP_VPKS:
2556 case S390_VEC_OP_VPKLS:
2557 case S390_VEC_OP_VCEQ:
2558 case S390_VEC_OP_VGFM:
2559 case S390_VEC_OP_VCH:
2560 case S390_VEC_OP_VCHL:
2561 the_insn.VRR.v1 = 1;
2562 the_insn.VRR.v2 = 2;
2563 the_insn.VRR.v3 = 3;
2564 the_insn.VRR.rxb = 0b1110;
2565 the_insn.VRR.m4 = d->m4;
2566 the_insn.VRR.m5 = d->m5;
2567 break;
2569 case S390_VEC_OP_VGFMA:
2570 case S390_VEC_OP_VMAH:
2571 case S390_VEC_OP_VMALH:
2572 case S390_VEC_OP_VMSL:
2573 the_insn.VRRd.v1 = 1;
2574 the_insn.VRRd.v2 = 2;
2575 the_insn.VRRd.v3 = 3;
2576 the_insn.VRRd.v4 = 4;
2577 the_insn.VRRd.rxb = 0b1111;
2578 the_insn.VRRd.m5 = d->m4;
2579 the_insn.VRRd.m6 = d->m5;
2580 break;
2582 case S390_VEC_OP_VFMIN:
2583 case S390_VEC_OP_VFMAX:
2584 case S390_VEC_OP_VBPERM:
2585 case S390_VEC_OP_VCRNF:
2586 the_insn.VRRc.v1 = 1;
2587 the_insn.VRRc.v2 = 2;
2588 the_insn.VRRc.v3 = 3;
2589 the_insn.VRRc.rxb = 0b1110;
2590 the_insn.VRRc.m4 = d->m4;
2591 the_insn.VRRc.m5 = d->m5;
2592 the_insn.VRRc.m6 = d->m6;
2593 break;
2595 case S390_VEC_OP_VCNF:
2596 case S390_VEC_OP_VCLFNH:
2597 case S390_VEC_OP_VCFN:
2598 case S390_VEC_OP_VCLFNL:
2599 the_insn.VRRa.v1 = 1;
2600 the_insn.VRRa.v2 = 2;
2601 the_insn.VRRa.rxb = 0b1100;
2602 the_insn.VRRa.m3 = d->m3;
2603 the_insn.VRRa.m4 = d->m4;
2604 break;
2606 case S390_VEC_OP_VFTCI:
2607 the_insn.VRIe.v1 = 1;
2608 the_insn.VRIe.v2 = 2;
2609 the_insn.VRIe.rxb = 0b1100;
2610 the_insn.VRIe.i3 = d->i3;
2611 the_insn.VRIe.m4 = d->m4;
2612 the_insn.VRIe.m5 = d->m5;
2613 break;
2615 default:
2616 vex_printf("operation = %d\n", d->op);
2617 vpanic("s390x_dirtyhelper_vec_op: unknown operation");
2620 const V128* guest_v = &(guest_state->guest_v0);
2621 __asm__ volatile (
2622 "lgr %%r10, %[arg1]\n"
2623 VL(2, 0, a, 000, 8)
2624 "lgr %%r10, %[arg2]\n"
2625 VL(3, 0, a, 000, 8)
2626 "lgr %%r10, %[arg3]\n"
2627 VL(4, 0, a, 000, 8)
2628 "ex %[zero], %[insn]\n"
2630 "cijne %[read_only], 0, return_cc\n"
2631 "lgr %%r10, %[res]\n"
2632 VST(1, 0, a, 000, 8)
2634 "return_cc: "
2635 "ipm %[psw]\n\t"
2636 : [psw] "=d" (psw)
2638 : [res] "r" (&guest_v[d->v1]),
2639 [arg1] "r" (&guest_v[d->v2]),
2640 [arg2] "r" (&guest_v[d->v3]),
2641 [arg3] "r" (&guest_v[d->v4]),
2643 [zero] "r" (0ULL),
2644 [insn] "R" (the_insn),
2645 [read_only] "r" (d->read_only)
2647 : "cc", "r10", "v16", "v17", "v18", "v19"
2650 return psw >> 28; /* cc */
2653 #else
2655 ULong
2656 s390x_dirtyhelper_vec_op(VexGuestS390XState *guest_state,
2657 const ULong serialized)
2658 { return 0; }
2660 #endif
2662 /*-----------------------------------------------------------------*/
2663 /*--- Dirty helper for Perform Pseudorandom number instruction ---*/
2664 /*-----------------------------------------------------------------*/
2666 /* Dummy helper that is needed to indicate load of parameter block.
2667 We have to use it because dirty helper cannot have two memory side
2668 effects.
2670 void s390x_dirtyhelper_PPNO_sha512_load_param_block( void )
2674 #if defined(VGA_s390x)
2676 /* IMPORTANT!
2677 We return here bit mask where only supported functions are set to one.
2678 If you implement new functions don't forget the supported array.
2680 void
2681 s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2)
2683 ULong supported[2] = {0x9000000000000000ULL, 0x0000000000000000ULL};
2684 ULong *result = (ULong*) guest_state->guest_r1;
2686 result[0] = supported[0];
2687 result[1] = supported[1];
2690 ULong
2691 s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2)
2693 ULong* op1 = (ULong*) (((ULong)(&guest_state->guest_r0)) + r1 * sizeof(ULong));
2694 ULong* op2 = (ULong*) (((ULong)(&guest_state->guest_r0)) + r2 * sizeof(ULong));
2696 register ULong reg0 asm("0") = guest_state->guest_r0;
2697 register ULong reg1 asm("1") = guest_state->guest_r1;
2698 register ULong reg2 asm("2") = op1[0];
2699 register ULong reg3 asm("3") = op1[1];
2700 register ULong reg4 asm("4") = op2[0];
2701 register ULong reg5 asm("5") = op2[1];
2703 ULong cc = 0;
2704 asm volatile(".insn rre, 0xb93c0000, %%r2, %%r4\n"
2705 "ipm %[cc]\n"
2706 "srl %[cc], 28\n"
2707 : "+d"(reg0), "+d"(reg1),
2708 "+d"(reg2), "+d"(reg3),
2709 "+d"(reg4), "+d"(reg5),
2710 [cc] "=d"(cc)
2712 : "cc", "memory");
2714 return cc;
2717 #else
2719 void
2720 s390x_dirtyhelper_PPNO_query(VexGuestS390XState *guest_state, ULong r1, ULong r2)
2724 ULong
2725 s390x_dirtyhelper_PPNO_sha512(VexGuestS390XState *guest_state, ULong r1, ULong r2)
2727 return 0;
2730 #endif /* VGA_s390x */
2731 /*---------------------------------------------------------------*/
2732 /*--- end guest_s390_helpers.c ---*/
2733 /*---------------------------------------------------------------*/