blob: f60beea74e605379b7b270f4032e126ac040e302 [file] [log] [blame]
sewardj2019a972011-03-07 16:04:07 +00001/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*---------------------------------------------------------------*/
4/*--- begin host_s390_defs.c ---*/
5/*---------------------------------------------------------------*/
6
7/*
8 This file is part of Valgrind, a dynamic binary instrumentation
9 framework.
10
11 Copyright IBM Corp. 2010-2011
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 02110-1301, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31/* Contributed by Florian Krohm */
32
33#include "libvex_basictypes.h"
34#include "libvex.h"
35#include "libvex_trc_values.h"
sewardj2019a972011-03-07 16:04:07 +000036#include "libvex_s390x_common.h"
37
38#include "main_util.h"
39#include "main_globals.h"
40#include "host_generic_regs.h"
41#include "host_s390_defs.h"
42#include "host_s390_disasm.h"
florian428dfdd2012-03-27 03:09:49 +000043#include "guest_s390_defs.h" /* S390X_GUEST_OFFSET */
sewardj2019a972011-03-07 16:04:07 +000044#include <stdarg.h>
45
46/* KLUDGE: We need to know the hwcaps of the host when generating
47 code. But that info is not passed to emit_S390Instr. Only mode64 is
48 being passed. So, ideally, we want this passed as an argument, too.
49 Until then, we use a global variable. This variable is set as a side
50 effect of iselSB_S390. This is safe because instructions are selected
51 before they are emitted. */
florianf26994a2012-04-21 03:34:54 +000052UInt s390_host_hwcaps;
sewardj2019a972011-03-07 16:04:07 +000053
florianb4df7682011-07-05 02:09:01 +000054
55/*------------------------------------------------------------*/
56/*--- Forward declarations ---*/
57/*------------------------------------------------------------*/
58
59static Bool s390_insn_is_reg_reg_move(const s390_insn *, HReg *src, HReg *dst);
60static void s390_insn_map_regs(HRegRemap *, s390_insn *);
61static void s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *);
florian1c857042012-04-15 04:11:07 +000062static UInt s390_tchain_load64_len(void);
florianb4df7682011-07-05 02:09:01 +000063
64
sewardj2019a972011-03-07 16:04:07 +000065/*------------------------------------------------------------*/
66/*--- Registers ---*/
67/*------------------------------------------------------------*/
68
69/* Decompile the given register into a static buffer and return it */
70const HChar *
71s390_hreg_as_string(HReg reg)
72{
73 static HChar buf[10];
74
75 static const HChar ireg_names[16][5] = {
76 "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
77 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
78 };
79
80 static const HChar freg_names[16][5] = {
81 "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
82 "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15"
83 };
84
85 UInt r; /* hregNumber() returns an UInt */
86
87 r = hregNumber(reg);
88
89 /* Be generic for all virtual regs. */
90 if (hregIsVirtual(reg)) {
91 buf[0] = '\0';
92 switch (hregClass(reg)) {
93 case HRcInt64: vex_sprintf(buf, "%%vR%d", r); break;
94 case HRcFlt64: vex_sprintf(buf, "%%vF%d", r); break;
95 default: goto fail;
96 }
97 return buf;
98 }
99
100 /* But specific for real regs. */
101 vassert(r < 16);
102
103 switch (hregClass(reg)) {
104 case HRcInt64: return ireg_names[r];
105 case HRcFlt64: return freg_names[r];
106 default: goto fail;
107 }
108
109 fail: vpanic("s390_hreg_as_string");
110}
111
112
113/* Tell the register allocator which registers can be allocated. */
florianb4df7682011-07-05 02:09:01 +0000114static void
sewardj2019a972011-03-07 16:04:07 +0000115s390_hreg_get_allocable(Int *nregs, HReg **arr)
116{
117 UInt i;
118
119 /* Total number of allocable registers (all classes) */
120 *nregs = 16 /* GPRs */
121 - 1 /* r0 */
florian8844a632012-04-13 04:04:06 +0000122 - 1 /* r12 scratch register for translation chaining support */
sewardj2019a972011-03-07 16:04:07 +0000123 - 1 /* r13 guest state pointer */
124 - 1 /* r14 link register */
125 - 1 /* r15 stack pointer */
126 + 16 /* FPRs */
127 ;
128
129 *arr = LibVEX_Alloc(*nregs * sizeof(HReg));
130
131 i = 0;
132
133 /* GPR0 is not available because it is interpreted as 0, when used
134 as a base or index register. */
135 (*arr)[i++] = mkHReg(1, HRcInt64, False);
136 (*arr)[i++] = mkHReg(2, HRcInt64, False);
137 (*arr)[i++] = mkHReg(3, HRcInt64, False);
138 (*arr)[i++] = mkHReg(4, HRcInt64, False);
139 (*arr)[i++] = mkHReg(5, HRcInt64, False);
140 (*arr)[i++] = mkHReg(6, HRcInt64, False);
141 (*arr)[i++] = mkHReg(7, HRcInt64, False);
142 (*arr)[i++] = mkHReg(8, HRcInt64, False);
143 (*arr)[i++] = mkHReg(9, HRcInt64, False);
144 /* GPR10 and GPR11 are used for instructions that use register pairs.
145 Otherwise, they are available to the allocator */
146 (*arr)[i++] = mkHReg(10, HRcInt64, False);
147 (*arr)[i++] = mkHReg(11, HRcInt64, False);
florian8844a632012-04-13 04:04:06 +0000148 /* GPR12 is not available because it us used as a scratch register
149 in translation chaining. */
sewardj2019a972011-03-07 16:04:07 +0000150 /* GPR13 is not available because it is used as guest state pointer */
151 /* GPR14 is not available because it is used as link register */
152 /* GPR15 is not available because it is used as stack pointer */
153
154 /* Add the available real (non-virtual) FPRs */
155 (*arr)[i++] = mkHReg(0, HRcFlt64, False);
156 (*arr)[i++] = mkHReg(1, HRcFlt64, False);
157 (*arr)[i++] = mkHReg(2, HRcFlt64, False);
158 (*arr)[i++] = mkHReg(3, HRcFlt64, False);
159 (*arr)[i++] = mkHReg(4, HRcFlt64, False);
160 (*arr)[i++] = mkHReg(5, HRcFlt64, False);
161 (*arr)[i++] = mkHReg(6, HRcFlt64, False);
162 (*arr)[i++] = mkHReg(7, HRcFlt64, False);
163 (*arr)[i++] = mkHReg(8, HRcFlt64, False);
164 (*arr)[i++] = mkHReg(9, HRcFlt64, False);
165 (*arr)[i++] = mkHReg(10, HRcFlt64, False);
166 (*arr)[i++] = mkHReg(11, HRcFlt64, False);
167 (*arr)[i++] = mkHReg(12, HRcFlt64, False);
168 (*arr)[i++] = mkHReg(13, HRcFlt64, False);
169 (*arr)[i++] = mkHReg(14, HRcFlt64, False);
170 (*arr)[i++] = mkHReg(15, HRcFlt64, False);
171 /* FPR12 - FPR15 are also used as register pairs for 128-bit
172 floating point operations */
173}
174
175
176/* Return the real register that holds the guest state pointer */
177HReg
178s390_hreg_guest_state_pointer(void)
179{
180 return mkHReg(S390_REGNO_GUEST_STATE_POINTER, HRcInt64, False);
181}
182
florian8844a632012-04-13 04:04:06 +0000183
sewardj2019a972011-03-07 16:04:07 +0000184/* Is VALUE within the domain of a 20-bit signed integer. */
185static __inline__ Bool
186fits_signed_20bit(Int value)
187{
188 return ((value << 12) >> 12) == value;
189}
190
191
192/* Is VALUE within the domain of a 12-bit unsigned integer. */
193static __inline__ Bool
194fits_unsigned_12bit(Int value)
195{
196 return (value & 0xFFF) == value;
197}
198
199/*------------------------------------------------------------*/
200/*--- Addressing modes (amodes) ---*/
201/*------------------------------------------------------------*/
202
203/* Construct a b12 amode. */
204s390_amode *
205s390_amode_b12(Int d, HReg b)
206{
207 s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
208
209 vassert(fits_unsigned_12bit(d));
210
211 am->tag = S390_AMODE_B12;
212 am->d = d;
213 am->b = b;
214 am->x = 0; /* hregNumber(0) == 0 */
215
216 return am;
217}
218
219
220/* Construct a b20 amode. */
221s390_amode *
222s390_amode_b20(Int d, HReg b)
223{
224 s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
225
226 vassert(fits_signed_20bit(d));
227
228 am->tag = S390_AMODE_B20;
229 am->d = d;
230 am->b = b;
231 am->x = 0; /* hregNumber(0) == 0 */
232
233 return am;
234}
235
236
237/* Construct a bx12 amode. */
238s390_amode *
239s390_amode_bx12(Int d, HReg b, HReg x)
240{
241 s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
242
243 vassert(fits_unsigned_12bit(d));
244 vassert(b != 0);
245 vassert(x != 0);
246
247 am->tag = S390_AMODE_BX12;
248 am->d = d;
249 am->b = b;
250 am->x = x;
251
252 return am;
253}
254
255
256/* Construct a bx20 amode. */
257s390_amode *
258s390_amode_bx20(Int d, HReg b, HReg x)
259{
260 s390_amode *am = LibVEX_Alloc(sizeof(s390_amode));
261
262 vassert(fits_signed_20bit(d));
263 vassert(b != 0);
264 vassert(x != 0);
265
266 am->tag = S390_AMODE_BX20;
267 am->d = d;
268 am->b = b;
269 am->x = x;
270
271 return am;
272}
273
274
275/* Construct an AMODE for accessing the guest state at OFFSET */
276s390_amode *
277s390_amode_for_guest_state(Int offset)
278{
279 if (fits_unsigned_12bit(offset))
280 return s390_amode_b12(offset, s390_hreg_guest_state_pointer());
sewardj2019a972011-03-07 16:04:07 +0000281
282 vpanic("invalid guest state offset");
283}
284
285
286/* Decompile the given amode into a static buffer and return it. */
287const HChar *
288s390_amode_as_string(const s390_amode *am)
289{
290 static HChar buf[30];
291 HChar *p;
292
293 buf[0] = '\0';
294 p = buf;
295
296 switch (am->tag) {
297 case S390_AMODE_B12:
298 case S390_AMODE_B20:
299 vex_sprintf(p, "%d(%s)", am->d, s390_hreg_as_string(am->b));
300 break;
301
302 case S390_AMODE_BX12:
303 case S390_AMODE_BX20:
304 /* s390_hreg_as_string returns pointer to local buffer. Need to
305 split this into two printfs */
306 p += vex_sprintf(p, "%d(%s,", am->d, s390_hreg_as_string(am->x));
307 vex_sprintf(p, "%s)", s390_hreg_as_string(am->b));
308 break;
309
310 default:
311 vpanic("s390_amode_as_string");
312 }
313
314 return buf;
315}
316
317
318/* Helper function for s390_amode_is_sane */
319static __inline__ Bool
320is_virtual_gpr(HReg reg)
321{
322 return hregIsVirtual(reg) && hregClass(reg) == HRcInt64;
323}
324
325
326/* Sanity check for an amode */
327Bool
328s390_amode_is_sane(const s390_amode *am)
329{
330 switch (am->tag) {
331 case S390_AMODE_B12:
332 return is_virtual_gpr(am->b) && fits_unsigned_12bit(am->d);
333
334 case S390_AMODE_B20:
335 return is_virtual_gpr(am->b) && fits_signed_20bit(am->d);
336
337 case S390_AMODE_BX12:
338 return is_virtual_gpr(am->b) && is_virtual_gpr(am->x) &&
339 fits_unsigned_12bit(am->d);
340
341 case S390_AMODE_BX20:
342 return is_virtual_gpr(am->b) && is_virtual_gpr(am->x) &&
343 fits_signed_20bit(am->d);
344
345 default:
346 vpanic("s390_amode_is_sane");
347 }
348}
349
350
351/* Record the register use of an amode */
florianb4df7682011-07-05 02:09:01 +0000352static void
sewardj2019a972011-03-07 16:04:07 +0000353s390_amode_get_reg_usage(HRegUsage *u, const s390_amode *am)
354{
355 switch (am->tag) {
356 case S390_AMODE_B12:
357 case S390_AMODE_B20:
358 addHRegUse(u, HRmRead, am->b);
359 return;
360
361 case S390_AMODE_BX12:
362 case S390_AMODE_BX20:
363 addHRegUse(u, HRmRead, am->b);
364 addHRegUse(u, HRmRead, am->x);
365 return;
366
367 default:
368 vpanic("s390_amode_get_reg_usage");
369 }
370}
371
372
florianb4df7682011-07-05 02:09:01 +0000373static void
sewardj2019a972011-03-07 16:04:07 +0000374s390_amode_map_regs(HRegRemap *m, s390_amode *am)
375{
376 switch (am->tag) {
377 case S390_AMODE_B12:
378 case S390_AMODE_B20:
379 am->b = lookupHRegRemap(m, am->b);
380 return;
381
382 case S390_AMODE_BX12:
383 case S390_AMODE_BX20:
384 am->b = lookupHRegRemap(m, am->b);
385 am->x = lookupHRegRemap(m, am->x);
386 return;
387
388 default:
389 vpanic("s390_amode_map_regs");
390 }
391}
392
393
sewardj2019a972011-03-07 16:04:07 +0000394void
florianb4df7682011-07-05 02:09:01 +0000395ppS390AMode(s390_amode *am)
sewardj2019a972011-03-07 16:04:07 +0000396{
397 vex_printf("%s", s390_amode_as_string(am));
398}
399
400void
florianb4df7682011-07-05 02:09:01 +0000401ppS390Instr(s390_insn *insn, Bool mode64)
sewardj2019a972011-03-07 16:04:07 +0000402{
403 vex_printf("%s", s390_insn_as_string(insn));
404}
405
406void
407ppHRegS390(HReg reg)
408{
409 vex_printf("%s", s390_hreg_as_string(reg));
410}
411
412/*------------------------------------------------------------*/
413/*--- Helpers for register allocation ---*/
414/*------------------------------------------------------------*/
415
416/* Called once per translation. */
417void
418getAllocableRegs_S390(Int *nregs, HReg **arr, Bool mode64)
419{
420 s390_hreg_get_allocable(nregs, arr);
421}
422
423
424/* Tell the register allocator how the given instruction uses the registers
425 it refers to. */
426void
florianb4df7682011-07-05 02:09:01 +0000427getRegUsage_S390Instr(HRegUsage *u, s390_insn *insn, Bool mode64)
sewardj2019a972011-03-07 16:04:07 +0000428{
429 s390_insn_get_reg_usage(u, insn);
430}
431
432
433/* Map the registers of the given instruction */
434void
florianb4df7682011-07-05 02:09:01 +0000435mapRegs_S390Instr(HRegRemap *m, s390_insn *insn, Bool mode64)
sewardj2019a972011-03-07 16:04:07 +0000436{
437 s390_insn_map_regs(m, insn);
438}
439
440
441/* Figure out if the given insn represents a reg-reg move, and if so
442 assign the source and destination to *src and *dst. If in doubt say No.
443 Used by the register allocator to do move coalescing. */
444Bool
florianb4df7682011-07-05 02:09:01 +0000445isMove_S390Instr(s390_insn *insn, HReg *src, HReg *dst)
sewardj2019a972011-03-07 16:04:07 +0000446{
447 return s390_insn_is_reg_reg_move(insn, src, dst);
448}
449
450
451/* Generate s390 spill/reload instructions under the direction of the
452 register allocator. Note it's critical these don't write the
453 condition codes. This is like an Ist_Put */
454void
455genSpill_S390(HInstr **i1, HInstr **i2, HReg rreg, Int offsetB, Bool mode64)
456{
457 s390_amode *am;
458
459 vassert(offsetB >= 0);
460 vassert(offsetB <= (1 << 12)); /* because we use b12 amode */
461 vassert(!hregIsVirtual(rreg));
462
463 *i1 = *i2 = NULL;
464
465 am = s390_amode_for_guest_state(offsetB);
466
467 switch (hregClass(rreg)) {
468 case HRcInt64:
469 case HRcFlt64:
470 *i1 = s390_insn_store(8, am, rreg);
471 return;
472
473 default:
474 ppHRegClass(hregClass(rreg));
475 vpanic("genSpill_S390: unimplemented regclass");
476 }
477}
478
479
480/* This is like an Iex_Get */
481void
482genReload_S390(HInstr **i1, HInstr **i2, HReg rreg, Int offsetB, Bool mode64)
483{
484 s390_amode *am;
485
486 vassert(offsetB >= 0);
487 vassert(offsetB <= (1 << 12)); /* because we use b12 amode */
488 vassert(!hregIsVirtual(rreg));
489
490 *i1 = *i2 = NULL;
491
492 am = s390_amode_for_guest_state(offsetB);
493
494 switch (hregClass(rreg)) {
495 case HRcInt64:
496 case HRcFlt64:
497 *i1 = s390_insn_load(8, rreg, am);
498 return;
499
500 default:
501 ppHRegClass(hregClass(rreg));
502 vpanic("genReload_S390: unimplemented regclass");
503 }
504}
505
506/* Helper function for s390_insn_get_reg_usage */
507static void
508s390_opnd_RMI_get_reg_usage(HRegUsage *u, s390_opnd_RMI op)
509{
510 switch (op.tag) {
511 case S390_OPND_REG:
512 addHRegUse(u, HRmRead, op.variant.reg);
513 break;
514
515 case S390_OPND_AMODE:
516 s390_amode_get_reg_usage(u, op.variant.am);
517 break;
518
519 case S390_OPND_IMMEDIATE:
520 break;
521
522 default:
523 vpanic("s390_opnd_RMI_get_reg_usage");
524 }
525}
526
527
528/* Tell the register allocator how the given insn uses the registers */
florianb4df7682011-07-05 02:09:01 +0000529static void
sewardj2019a972011-03-07 16:04:07 +0000530s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
531{
532 initHRegUsage(u);
533
534 switch (insn->tag) {
535 case S390_INSN_LOAD:
536 addHRegUse(u, HRmWrite, insn->variant.load.dst);
537 s390_amode_get_reg_usage(u, insn->variant.load.src);
538 break;
539
540 case S390_INSN_LOAD_IMMEDIATE:
541 addHRegUse(u, HRmWrite, insn->variant.load_immediate.dst);
542 break;
543
544 case S390_INSN_STORE:
545 addHRegUse(u, HRmRead, insn->variant.store.src);
546 s390_amode_get_reg_usage(u, insn->variant.store.dst);
547 break;
548
549 case S390_INSN_MOVE:
550 addHRegUse(u, HRmRead, insn->variant.move.src);
551 addHRegUse(u, HRmWrite, insn->variant.move.dst);
552 break;
553
554 case S390_INSN_COND_MOVE:
555 s390_opnd_RMI_get_reg_usage(u, insn->variant.cond_move.src);
556 addHRegUse(u, HRmWrite, insn->variant.cond_move.dst);
557 break;
558
559 case S390_INSN_ALU:
560 addHRegUse(u, HRmWrite, insn->variant.alu.dst);
561 addHRegUse(u, HRmRead, insn->variant.alu.dst); /* op1 */
562 s390_opnd_RMI_get_reg_usage(u, insn->variant.alu.op2);
563 break;
564
565 case S390_INSN_MUL:
566 addHRegUse(u, HRmRead, insn->variant.mul.dst_lo); /* op1 */
567 addHRegUse(u, HRmWrite, insn->variant.mul.dst_lo);
568 addHRegUse(u, HRmWrite, insn->variant.mul.dst_hi);
569 s390_opnd_RMI_get_reg_usage(u, insn->variant.mul.op2);
570 break;
571
572 case S390_INSN_DIV:
573 addHRegUse(u, HRmRead, insn->variant.div.op1_lo);
574 addHRegUse(u, HRmRead, insn->variant.div.op1_hi);
575 addHRegUse(u, HRmWrite, insn->variant.div.op1_lo);
576 addHRegUse(u, HRmWrite, insn->variant.div.op1_hi);
577 s390_opnd_RMI_get_reg_usage(u, insn->variant.div.op2);
578 break;
579
580 case S390_INSN_DIVS:
581 addHRegUse(u, HRmRead, insn->variant.divs.op1);
582 addHRegUse(u, HRmWrite, insn->variant.divs.op1); /* quotient */
583 addHRegUse(u, HRmWrite, insn->variant.divs.rem); /* remainder */
584 s390_opnd_RMI_get_reg_usage(u, insn->variant.divs.op2);
585 break;
586
sewardj611b06e2011-03-24 08:57:29 +0000587 case S390_INSN_CLZ:
588 addHRegUse(u, HRmWrite, insn->variant.clz.num_bits);
589 addHRegUse(u, HRmWrite, insn->variant.clz.clobber);
590 s390_opnd_RMI_get_reg_usage(u, insn->variant.clz.src);
sewardj2019a972011-03-07 16:04:07 +0000591 break;
592
593 case S390_INSN_UNOP:
594 addHRegUse(u, HRmWrite, insn->variant.unop.dst);
595 s390_opnd_RMI_get_reg_usage(u, insn->variant.unop.src);
596 break;
597
598 case S390_INSN_TEST:
599 s390_opnd_RMI_get_reg_usage(u, insn->variant.test.src);
600 break;
601
602 case S390_INSN_CC2BOOL:
603 addHRegUse(u, HRmWrite, insn->variant.cc2bool.dst);
604 break;
605
606 case S390_INSN_CAS:
607 addHRegUse(u, HRmRead, insn->variant.cas.op1);
608 s390_amode_get_reg_usage(u, insn->variant.cas.op2);
609 addHRegUse(u, HRmRead, insn->variant.cas.op3);
610 addHRegUse(u, HRmWrite, insn->variant.cas.old_mem);
611 break;
612
613 case S390_INSN_COMPARE:
614 addHRegUse(u, HRmRead, insn->variant.compare.src1);
615 s390_opnd_RMI_get_reg_usage(u, insn->variant.compare.src2);
616 break;
617
sewardj2019a972011-03-07 16:04:07 +0000618 case S390_INSN_HELPER_CALL: {
619 UInt i;
620
621 /* Assume that all volatile registers are clobbered. ABI says,
622 volatile registers are: r0 - r5. Valgrind's register allocator
623 does not know about r0, so we can leave that out */
624 for (i = 1; i <= 5; ++i) {
625 addHRegUse(u, HRmWrite, mkHReg(i, HRcInt64, False));
626 }
627
628 /* Ditto for floating point registers. f0 - f7 are volatile */
629 for (i = 0; i <= 7; ++i) {
630 addHRegUse(u, HRmWrite, mkHReg(i, HRcFlt64, False));
631 }
632
633 /* The registers that are used for passing arguments will be read.
634 Not all of them may, but in general we need to assume that. */
635 for (i = 0; i < insn->variant.helper_call.num_args; ++i) {
636 addHRegUse(u, HRmRead, mkHReg(s390_gprno_from_arg_index(i),
637 HRcInt64, False));
638 }
639
640 /* s390_insn_helper_call_emit also reads / writes the link register
641 and stack pointer. But those registers are not visible to the
642 register allocator. So we don't need to do anything for them. */
643 break;
644 }
645
646 case S390_INSN_BFP_TRIOP:
647 addHRegUse(u, HRmWrite, insn->variant.bfp_triop.dst);
648 addHRegUse(u, HRmRead, insn->variant.bfp_triop.dst); /* first */
649 addHRegUse(u, HRmRead, insn->variant.bfp_triop.op2); /* second */
650 addHRegUse(u, HRmRead, insn->variant.bfp_triop.op3); /* third */
651 break;
652
653 case S390_INSN_BFP_BINOP:
654 addHRegUse(u, HRmWrite, insn->variant.bfp_binop.dst);
655 addHRegUse(u, HRmRead, insn->variant.bfp_binop.dst); /* left */
656 addHRegUse(u, HRmRead, insn->variant.bfp_binop.op2); /* right */
657 break;
658
659 case S390_INSN_BFP_UNOP:
660 addHRegUse(u, HRmWrite, insn->variant.bfp_unop.dst);
661 addHRegUse(u, HRmRead, insn->variant.bfp_unop.op); /* operand */
662 break;
663
664 case S390_INSN_BFP_COMPARE:
665 addHRegUse(u, HRmWrite, insn->variant.bfp_compare.dst);
666 addHRegUse(u, HRmRead, insn->variant.bfp_compare.op1); /* left */
667 addHRegUse(u, HRmRead, insn->variant.bfp_compare.op2); /* right */
668 break;
669
670 case S390_INSN_BFP128_BINOP:
671 addHRegUse(u, HRmWrite, insn->variant.bfp128_binop.dst_hi);
672 addHRegUse(u, HRmWrite, insn->variant.bfp128_binop.dst_lo);
673 addHRegUse(u, HRmRead, insn->variant.bfp128_binop.dst_hi); /* left */
674 addHRegUse(u, HRmRead, insn->variant.bfp128_binop.dst_lo); /* left */
675 addHRegUse(u, HRmRead, insn->variant.bfp128_binop.op2_hi); /* right */
676 addHRegUse(u, HRmRead, insn->variant.bfp128_binop.op2_lo); /* right */
677 break;
678
679 case S390_INSN_BFP128_COMPARE:
680 addHRegUse(u, HRmWrite, insn->variant.bfp128_compare.dst);
681 addHRegUse(u, HRmRead, insn->variant.bfp128_compare.op1_hi); /* left */
682 addHRegUse(u, HRmRead, insn->variant.bfp128_compare.op1_lo); /* left */
683 addHRegUse(u, HRmRead, insn->variant.bfp128_compare.op2_hi); /* right */
684 addHRegUse(u, HRmRead, insn->variant.bfp128_compare.op2_lo); /* right */
685 break;
686
687 case S390_INSN_BFP128_UNOP:
688 addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_hi);
689 addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_lo);
690 addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_hi);
691 addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_lo);
692 break;
693
694 case S390_INSN_BFP128_CONVERT_TO:
695 addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_hi);
696 addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_lo);
697 addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_hi);
698 break;
699
700 case S390_INSN_BFP128_CONVERT_FROM:
701 addHRegUse(u, HRmWrite, insn->variant.bfp128_unop.dst_hi);
702 addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_hi);
703 addHRegUse(u, HRmRead, insn->variant.bfp128_unop.op_lo);
704 break;
705
sewardja52e37e2011-04-28 18:48:06 +0000706 case S390_INSN_MFENCE:
florianad43b3a2012-02-20 15:01:14 +0000707 case S390_INSN_GZERO:
708 case S390_INSN_GADD:
sewardja52e37e2011-04-28 18:48:06 +0000709 break;
710
florian8844a632012-04-13 04:04:06 +0000711 case S390_INSN_EVCHECK:
712 s390_amode_get_reg_usage(u, insn->variant.evcheck.counter);
713 s390_amode_get_reg_usage(u, insn->variant.evcheck.fail_addr);
714 break;
715
716 case S390_INSN_PROFINC:
717 /* Does not use any register visible to the register allocator */
718 break;
719
720 case S390_INSN_XDIRECT:
721 s390_amode_get_reg_usage(u, insn->variant.xdirect.guest_IA);
722 break;
723
724 case S390_INSN_XINDIR:
725 addHRegUse(u, HRmRead, insn->variant.xindir.dst);
726 s390_amode_get_reg_usage(u, insn->variant.xindir.guest_IA);
727 break;
728
729 case S390_INSN_XASSISTED:
730 addHRegUse(u, HRmRead, insn->variant.xassisted.dst);
731 s390_amode_get_reg_usage(u, insn->variant.xassisted.guest_IA);
732 break;
733
sewardj2019a972011-03-07 16:04:07 +0000734 default:
735 vpanic("s390_insn_get_reg_usage");
736 }
737}
738
739
740/* Helper function for s390_insn_map_regs */
741static void
742s390_opnd_RMI_map_regs(HRegRemap *m, s390_opnd_RMI *op)
743{
744 switch (op->tag) {
745 case S390_OPND_REG:
746 op->variant.reg = lookupHRegRemap(m, op->variant.reg);
747 break;
748
749 case S390_OPND_IMMEDIATE:
750 break;
751
752 case S390_OPND_AMODE:
753 s390_amode_map_regs(m, op->variant.am);
754 break;
755
756 default:
757 vpanic("s390_opnd_RMI_map_regs");
758 }
759}
760
761
florianb4df7682011-07-05 02:09:01 +0000762static void
sewardj2019a972011-03-07 16:04:07 +0000763s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
764{
765 switch (insn->tag) {
766 case S390_INSN_LOAD:
767 insn->variant.load.dst = lookupHRegRemap(m, insn->variant.load.dst);
768 s390_amode_map_regs(m, insn->variant.load.src);
769 break;
770
771 case S390_INSN_STORE:
772 s390_amode_map_regs(m, insn->variant.store.dst);
773 insn->variant.store.src = lookupHRegRemap(m, insn->variant.store.src);
774 break;
775
776 case S390_INSN_MOVE:
777 insn->variant.move.dst = lookupHRegRemap(m, insn->variant.move.dst);
778 insn->variant.move.src = lookupHRegRemap(m, insn->variant.move.src);
779 break;
780
781 case S390_INSN_COND_MOVE:
782 insn->variant.cond_move.dst = lookupHRegRemap(m, insn->variant.cond_move.dst);
783 s390_opnd_RMI_map_regs(m, &insn->variant.cond_move.src);
784 break;
785
786 case S390_INSN_LOAD_IMMEDIATE:
787 insn->variant.load_immediate.dst =
788 lookupHRegRemap(m, insn->variant.load_immediate.dst);
789 break;
790
791 case S390_INSN_ALU:
792 insn->variant.alu.dst = lookupHRegRemap(m, insn->variant.alu.dst);
793 s390_opnd_RMI_map_regs(m, &insn->variant.alu.op2);
794 break;
795
796 case S390_INSN_MUL:
797 insn->variant.mul.dst_hi = lookupHRegRemap(m, insn->variant.mul.dst_hi);
798 insn->variant.mul.dst_lo = lookupHRegRemap(m, insn->variant.mul.dst_lo);
799 s390_opnd_RMI_map_regs(m, &insn->variant.mul.op2);
800 break;
801
802 case S390_INSN_DIV:
803 insn->variant.div.op1_hi = lookupHRegRemap(m, insn->variant.div.op1_hi);
804 insn->variant.div.op1_lo = lookupHRegRemap(m, insn->variant.div.op1_lo);
805 s390_opnd_RMI_map_regs(m, &insn->variant.div.op2);
806 break;
807
808 case S390_INSN_DIVS:
809 insn->variant.divs.op1 = lookupHRegRemap(m, insn->variant.divs.op1);
810 insn->variant.divs.rem = lookupHRegRemap(m, insn->variant.divs.rem);
811 s390_opnd_RMI_map_regs(m, &insn->variant.divs.op2);
812 break;
813
sewardj611b06e2011-03-24 08:57:29 +0000814 case S390_INSN_CLZ:
815 insn->variant.clz.num_bits = lookupHRegRemap(m, insn->variant.clz.num_bits);
816 insn->variant.clz.clobber = lookupHRegRemap(m, insn->variant.clz.clobber);
817 s390_opnd_RMI_map_regs(m, &insn->variant.clz.src);
sewardj2019a972011-03-07 16:04:07 +0000818 break;
819
820 case S390_INSN_UNOP:
821 insn->variant.unop.dst = lookupHRegRemap(m, insn->variant.unop.dst);
822 s390_opnd_RMI_map_regs(m, &insn->variant.unop.src);
823 break;
824
825 case S390_INSN_TEST:
826 s390_opnd_RMI_map_regs(m, &insn->variant.test.src);
827 break;
828
829 case S390_INSN_CC2BOOL:
830 insn->variant.cc2bool.dst = lookupHRegRemap(m, insn->variant.cc2bool.dst);
831 break;
832
833 case S390_INSN_CAS:
834 insn->variant.cas.op1 = lookupHRegRemap(m, insn->variant.cas.op1);
835 s390_amode_map_regs(m, insn->variant.cas.op2);
836 insn->variant.cas.op3 = lookupHRegRemap(m, insn->variant.cas.op3);
837 insn->variant.cas.old_mem = lookupHRegRemap(m, insn->variant.cas.old_mem);
838 break;
839
840 case S390_INSN_COMPARE:
841 insn->variant.compare.src1 = lookupHRegRemap(m, insn->variant.compare.src1);
842 s390_opnd_RMI_map_regs(m, &insn->variant.compare.src2);
843 break;
844
sewardj2019a972011-03-07 16:04:07 +0000845 case S390_INSN_HELPER_CALL:
846 /* s390_insn_helper_call_emit also reads / writes the link register
847 and stack pointer. But those registers are not visible to the
848 register allocator. So we don't need to do anything for them.
849 As for the arguments of the helper call -- they will be loaded into
850 non-virtual registers. Again, we don't need to do anything for those
851 here. */
852 break;
853
854 case S390_INSN_BFP_TRIOP:
855 insn->variant.bfp_triop.dst = lookupHRegRemap(m, insn->variant.bfp_triop.dst);
856 insn->variant.bfp_triop.op2 = lookupHRegRemap(m, insn->variant.bfp_triop.op2);
857 insn->variant.bfp_triop.op3 = lookupHRegRemap(m, insn->variant.bfp_triop.op3);
858 break;
859
860 case S390_INSN_BFP_BINOP:
861 insn->variant.bfp_binop.dst = lookupHRegRemap(m, insn->variant.bfp_binop.dst);
862 insn->variant.bfp_binop.op2 = lookupHRegRemap(m, insn->variant.bfp_binop.op2);
863 break;
864
865 case S390_INSN_BFP_UNOP:
866 insn->variant.bfp_unop.dst = lookupHRegRemap(m, insn->variant.bfp_unop.dst);
867 insn->variant.bfp_unop.op = lookupHRegRemap(m, insn->variant.bfp_unop.op);
868 break;
869
870 case S390_INSN_BFP_COMPARE:
871 insn->variant.bfp_compare.dst = lookupHRegRemap(m, insn->variant.bfp_compare.dst);
872 insn->variant.bfp_compare.op1 = lookupHRegRemap(m, insn->variant.bfp_compare.op1);
873 insn->variant.bfp_compare.op2 = lookupHRegRemap(m, insn->variant.bfp_compare.op2);
874 break;
875
876 case S390_INSN_BFP128_BINOP:
877 insn->variant.bfp128_binop.dst_hi =
878 lookupHRegRemap(m, insn->variant.bfp128_binop.dst_hi);
879 insn->variant.bfp128_binop.dst_lo =
880 lookupHRegRemap(m, insn->variant.bfp128_binop.dst_lo);
881 insn->variant.bfp128_binop.op2_hi =
882 lookupHRegRemap(m, insn->variant.bfp128_binop.op2_hi);
883 insn->variant.bfp128_binop.op2_lo =
884 lookupHRegRemap(m, insn->variant.bfp128_binop.op2_lo);
885 break;
886
887 case S390_INSN_BFP128_COMPARE:
888 insn->variant.bfp128_compare.dst =
889 lookupHRegRemap(m, insn->variant.bfp128_compare.dst);
890 insn->variant.bfp128_compare.op1_hi =
891 lookupHRegRemap(m, insn->variant.bfp128_compare.op1_hi);
892 insn->variant.bfp128_compare.op1_lo =
893 lookupHRegRemap(m, insn->variant.bfp128_compare.op1_lo);
894 insn->variant.bfp128_compare.op2_hi =
895 lookupHRegRemap(m, insn->variant.bfp128_compare.op2_hi);
896 insn->variant.bfp128_compare.op2_lo =
897 lookupHRegRemap(m, insn->variant.bfp128_compare.op2_lo);
898 break;
899
900 case S390_INSN_BFP128_UNOP:
901 insn->variant.bfp128_unop.dst_hi =
902 lookupHRegRemap(m, insn->variant.bfp128_unop.dst_hi);
903 insn->variant.bfp128_unop.dst_lo =
904 lookupHRegRemap(m, insn->variant.bfp128_unop.dst_lo);
905 insn->variant.bfp128_unop.op_hi =
906 lookupHRegRemap(m, insn->variant.bfp128_unop.op_hi);
907 insn->variant.bfp128_unop.op_lo =
908 lookupHRegRemap(m, insn->variant.bfp128_unop.op_lo);
909 break;
910
911 case S390_INSN_BFP128_CONVERT_TO:
912 insn->variant.bfp128_unop.dst_hi =
913 lookupHRegRemap(m, insn->variant.bfp128_unop.dst_hi);
914 insn->variant.bfp128_unop.dst_lo =
915 lookupHRegRemap(m, insn->variant.bfp128_unop.dst_lo);
916 insn->variant.bfp128_unop.op_hi =
917 lookupHRegRemap(m, insn->variant.bfp128_unop.op_hi);
918 break;
919
920 case S390_INSN_BFP128_CONVERT_FROM:
921 insn->variant.bfp128_unop.dst_hi =
922 lookupHRegRemap(m, insn->variant.bfp128_unop.dst_hi);
923 insn->variant.bfp128_unop.op_hi =
924 lookupHRegRemap(m, insn->variant.bfp128_unop.op_hi);
925 insn->variant.bfp128_unop.op_lo =
926 lookupHRegRemap(m, insn->variant.bfp128_unop.op_lo);
927 break;
928
sewardja52e37e2011-04-28 18:48:06 +0000929 case S390_INSN_MFENCE:
florianad43b3a2012-02-20 15:01:14 +0000930 case S390_INSN_GZERO:
931 case S390_INSN_GADD:
sewardja52e37e2011-04-28 18:48:06 +0000932 break;
933
florian8844a632012-04-13 04:04:06 +0000934 case S390_INSN_EVCHECK:
935 s390_amode_map_regs(m, insn->variant.evcheck.counter);
936 s390_amode_map_regs(m, insn->variant.evcheck.fail_addr);
937 break;
938
939 case S390_INSN_PROFINC:
940 /* Does not use any register visible to the register allocator */
941 break;
942
943 case S390_INSN_XDIRECT:
944 s390_amode_map_regs(m, insn->variant.xdirect.guest_IA);
945 break;
946
947 case S390_INSN_XINDIR:
948 s390_amode_map_regs(m, insn->variant.xindir.guest_IA);
949 insn->variant.xindir.dst =
950 lookupHRegRemap(m, insn->variant.xindir.dst);
951 break;
952
953 case S390_INSN_XASSISTED:
954 s390_amode_map_regs(m, insn->variant.xassisted.guest_IA);
955 insn->variant.xassisted.dst =
956 lookupHRegRemap(m, insn->variant.xassisted.dst);
957 break;
958
sewardj2019a972011-03-07 16:04:07 +0000959 default:
960 vpanic("s390_insn_map_regs");
961 }
962}
963
964
965/* Return True, if INSN is a move between two registers of the same class.
966 In that case assign the source and destination registers to SRC and DST,
967 respectively. */
florianb4df7682011-07-05 02:09:01 +0000968static Bool
sewardj2019a972011-03-07 16:04:07 +0000969s390_insn_is_reg_reg_move(const s390_insn *insn, HReg *src, HReg *dst)
970{
971 if (insn->tag == S390_INSN_MOVE &&
972 hregClass(insn->variant.move.src) == hregClass(insn->variant.move.dst)) {
973 *src = insn->variant.move.src;
974 *dst = insn->variant.move.dst;
975 return True;
976 }
977
978 return False;
979}
980
981
sewardj2019a972011-03-07 16:04:07 +0000982/*------------------------------------------------------------*/
983/*--- Functions to emit a sequence of bytes ---*/
984/*------------------------------------------------------------*/
985
sewardj2019a972011-03-07 16:04:07 +0000986static __inline__ UChar *
987emit_2bytes(UChar *p, ULong val)
988{
989 return (UChar *)__builtin_memcpy(p, ((UChar *)&val) + 6, 2) + 2;
990}
991
992
993static __inline__ UChar *
994emit_4bytes(UChar *p, ULong val)
995{
996 return (UChar *)__builtin_memcpy(p, ((UChar *)&val) + 4, 4) + 4;
997}
998
999
1000static __inline__ UChar *
1001emit_6bytes(UChar *p, ULong val)
1002{
1003 return (UChar *)__builtin_memcpy(p, ((UChar *)&val) + 2, 6) + 6;
1004}
1005
1006
1007/*------------------------------------------------------------*/
1008/*--- Functions to emit various instruction formats ---*/
1009/*------------------------------------------------------------*/
1010
sewardj2019a972011-03-07 16:04:07 +00001011static UChar *
1012emit_RI(UChar *p, UInt op, UChar r1, UShort i2)
1013{
1014 ULong the_insn = op;
1015
1016 the_insn |= ((ULong)r1) << 20;
1017 the_insn |= ((ULong)i2) << 0;
1018
1019 return emit_4bytes(p, the_insn);
1020}
1021
1022
1023static UChar *
1024emit_RIL(UChar *p, ULong op, UChar r1, UInt i2)
1025{
1026 ULong the_insn = op;
1027
1028 the_insn |= ((ULong)r1) << 36;
1029 the_insn |= ((ULong)i2) << 0;
1030
1031 return emit_6bytes(p, the_insn);
1032}
1033
1034
1035static UChar *
1036emit_RR(UChar *p, UInt op, UChar r1, UChar r2)
1037{
1038 ULong the_insn = op;
1039
1040 the_insn |= ((ULong)r1) << 4;
1041 the_insn |= ((ULong)r2) << 0;
1042
1043 return emit_2bytes(p, the_insn);
1044}
1045
1046
1047static UChar *
1048emit_RRE(UChar *p, UInt op, UChar r1, UChar r2)
1049{
1050 ULong the_insn = op;
1051
1052 the_insn |= ((ULong)r1) << 4;
1053 the_insn |= ((ULong)r2) << 0;
1054
1055 return emit_4bytes(p, the_insn);
1056}
1057
1058
1059static UChar *
1060emit_RRF(UChar *p, UInt op, UChar r1, UChar r3, UChar r2)
1061{
1062 ULong the_insn = op;
1063
1064 the_insn |= ((ULong)r1) << 12;
1065 the_insn |= ((ULong)r3) << 4;
1066 the_insn |= ((ULong)r2) << 0;
1067
1068 return emit_4bytes(p, the_insn);
1069}
1070
1071
1072static UChar *
1073emit_RRF3(UChar *p, UInt op, UChar r3, UChar r1, UChar r2)
1074{
1075 ULong the_insn = op;
1076
1077 the_insn |= ((ULong)r3) << 12;
1078 the_insn |= ((ULong)r1) << 4;
1079 the_insn |= ((ULong)r2) << 0;
1080
1081 return emit_4bytes(p, the_insn);
1082}
1083
1084
1085static UChar *
1086emit_RS(UChar *p, UInt op, UChar r1, UChar r3, UChar b2, UShort d2)
1087{
1088 ULong the_insn = op;
1089
1090 the_insn |= ((ULong)r1) << 20;
1091 the_insn |= ((ULong)r3) << 16;
1092 the_insn |= ((ULong)b2) << 12;
1093 the_insn |= ((ULong)d2) << 0;
1094
1095 return emit_4bytes(p, the_insn);
1096}
1097
1098
1099static UChar *
1100emit_RSY(UChar *p, ULong op, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
1101{
1102 ULong the_insn = op;
1103
1104 the_insn |= ((ULong)r1) << 36;
1105 the_insn |= ((ULong)r3) << 32;
1106 the_insn |= ((ULong)b2) << 28;
1107 the_insn |= ((ULong)dl2) << 16;
1108 the_insn |= ((ULong)dh2) << 8;
1109
1110 return emit_6bytes(p, the_insn);
1111}
1112
1113
1114static UChar *
1115emit_RX(UChar *p, UInt op, UChar r1, UChar x2, UChar b2, UShort d2)
1116{
1117 ULong the_insn = op;
1118
1119 the_insn |= ((ULong)r1) << 20;
1120 the_insn |= ((ULong)x2) << 16;
1121 the_insn |= ((ULong)b2) << 12;
1122 the_insn |= ((ULong)d2) << 0;
1123
1124 return emit_4bytes(p, the_insn);
1125}
1126
1127
1128static UChar *
1129emit_RXY(UChar *p, ULong op, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1130{
1131 ULong the_insn = op;
1132
1133 the_insn |= ((ULong)r1) << 36;
1134 the_insn |= ((ULong)x2) << 32;
1135 the_insn |= ((ULong)b2) << 28;
1136 the_insn |= ((ULong)dl2) << 16;
1137 the_insn |= ((ULong)dh2) << 8;
1138
1139 return emit_6bytes(p, the_insn);
1140}
1141
1142
1143static UChar *
1144emit_S(UChar *p, UInt op, UChar b2, UShort d2)
1145{
1146 ULong the_insn = op;
1147
1148 the_insn |= ((ULong)b2) << 12;
1149 the_insn |= ((ULong)d2) << 0;
1150
1151 return emit_4bytes(p, the_insn);
1152}
1153
1154
florianad43b3a2012-02-20 15:01:14 +00001155static UChar *
1156emit_SIY(UChar *p, ULong op, UChar i2, UChar b1, UShort dl1, UChar dh1)
1157{
1158 ULong the_insn = op;
1159
1160 the_insn |= ((ULong)i2) << 32;
1161 the_insn |= ((ULong)b1) << 28;
1162 the_insn |= ((ULong)dl1) << 16;
1163 the_insn |= ((ULong)dh1) << 8;
1164
1165 return emit_6bytes(p, the_insn);
1166}
1167
1168
1169static UChar *
1170emit_SSa(UChar *p, ULong op, UChar l, UChar b1, UShort d1, UChar b2, UShort d2)
1171{
1172 ULong the_insn = op;
1173
1174 the_insn |= ((ULong)l) << 32;
1175 the_insn |= ((ULong)b1) << 28;
1176 the_insn |= ((ULong)d1) << 16;
1177 the_insn |= ((ULong)b2) << 12;
1178 the_insn |= ((ULong)d2) << 0;
1179
1180 return emit_6bytes(p, the_insn);
1181}
1182
1183
sewardj2019a972011-03-07 16:04:07 +00001184/*------------------------------------------------------------*/
1185/*--- Functions to emit particular instructions ---*/
1186/*------------------------------------------------------------*/
1187
sewardj9d31dfd2011-03-15 12:36:44 +00001188static UChar *
sewardj2019a972011-03-07 16:04:07 +00001189s390_emit_AR(UChar *p, UChar r1, UChar r2)
1190{
sewardj7ee97522011-05-09 21:45:04 +00001191 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001192 s390_disasm(ENC3(MNM, GPR, GPR), "ar", r1, r2);
1193
1194 return emit_RR(p, 0x1a00, r1, r2);
1195}
1196
1197
sewardj9d31dfd2011-03-15 12:36:44 +00001198static UChar *
sewardj2019a972011-03-07 16:04:07 +00001199s390_emit_AGR(UChar *p, UChar r1, UChar r2)
1200{
sewardj7ee97522011-05-09 21:45:04 +00001201 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001202 s390_disasm(ENC3(MNM, GPR, GPR), "agr", r1, r2);
1203
1204 return emit_RRE(p, 0xb9080000, r1, r2);
1205}
1206
1207
sewardj9d31dfd2011-03-15 12:36:44 +00001208static UChar *
sewardj2019a972011-03-07 16:04:07 +00001209s390_emit_A(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1210{
sewardj7ee97522011-05-09 21:45:04 +00001211 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001212 s390_disasm(ENC3(MNM, GPR, UDXB), "a", r1, d2, x2, b2);
1213
1214 return emit_RX(p, 0x5a000000, r1, x2, b2, d2);
1215}
1216
1217
sewardj9d31dfd2011-03-15 12:36:44 +00001218static UChar *
sewardj2019a972011-03-07 16:04:07 +00001219s390_emit_AY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1220{
sewardj652b56a2011-04-13 15:38:17 +00001221 vassert(s390_host_has_ldisp);
1222
sewardj7ee97522011-05-09 21:45:04 +00001223 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001224 s390_disasm(ENC3(MNM, GPR, SDXB), "ay", r1, dh2, dl2, x2, b2);
1225
1226 return emit_RXY(p, 0xe3000000005aULL, r1, x2, b2, dl2, dh2);
1227}
1228
1229
sewardj9d31dfd2011-03-15 12:36:44 +00001230static UChar *
sewardj2019a972011-03-07 16:04:07 +00001231s390_emit_AG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1232{
sewardj652b56a2011-04-13 15:38:17 +00001233 vassert(s390_host_has_ldisp || dh2 == 0);
1234
sewardj7ee97522011-05-09 21:45:04 +00001235 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001236 s390_disasm(ENC3(MNM, GPR, SDXB), "ag", r1, dh2, dl2, x2, b2);
1237
1238 return emit_RXY(p, 0xe30000000008ULL, r1, x2, b2, dl2, dh2);
1239}
1240
1241
sewardj9d31dfd2011-03-15 12:36:44 +00001242static UChar *
sewardj2019a972011-03-07 16:04:07 +00001243s390_emit_AFI(UChar *p, UChar r1, UInt i2)
1244{
sewardj652b56a2011-04-13 15:38:17 +00001245 vassert(s390_host_has_eimm);
1246
sewardj7ee97522011-05-09 21:45:04 +00001247 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001248 s390_disasm(ENC3(MNM, GPR, INT), "afi", r1, i2);
1249
1250 return emit_RIL(p, 0xc20900000000ULL, r1, i2);
1251}
1252
1253
sewardj9d31dfd2011-03-15 12:36:44 +00001254static UChar *
sewardj2019a972011-03-07 16:04:07 +00001255s390_emit_AGFI(UChar *p, UChar r1, UInt i2)
1256{
sewardj652b56a2011-04-13 15:38:17 +00001257 vassert(s390_host_has_eimm);
1258
sewardj7ee97522011-05-09 21:45:04 +00001259 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001260 s390_disasm(ENC3(MNM, GPR, INT), "agfi", r1, i2);
1261
1262 return emit_RIL(p, 0xc20800000000ULL, r1, i2);
1263}
1264
1265
sewardj9d31dfd2011-03-15 12:36:44 +00001266static UChar *
sewardj2019a972011-03-07 16:04:07 +00001267s390_emit_AH(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1268{
sewardj7ee97522011-05-09 21:45:04 +00001269 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001270 s390_disasm(ENC3(MNM, GPR, UDXB), "ah", r1, d2, x2, b2);
1271
1272 return emit_RX(p, 0x4a000000, r1, x2, b2, d2);
1273}
1274
1275
sewardj9d31dfd2011-03-15 12:36:44 +00001276static UChar *
sewardj2019a972011-03-07 16:04:07 +00001277s390_emit_AHY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1278{
sewardj652b56a2011-04-13 15:38:17 +00001279 vassert(s390_host_has_ldisp);
1280
sewardj7ee97522011-05-09 21:45:04 +00001281 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001282 s390_disasm(ENC3(MNM, GPR, SDXB), "ahy", r1, dh2, dl2, x2, b2);
1283
1284 return emit_RXY(p, 0xe3000000007aULL, r1, x2, b2, dl2, dh2);
1285}
1286
1287
sewardj9d31dfd2011-03-15 12:36:44 +00001288static UChar *
sewardj2019a972011-03-07 16:04:07 +00001289s390_emit_AHI(UChar *p, UChar r1, UShort i2)
1290{
sewardj7ee97522011-05-09 21:45:04 +00001291 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001292 s390_disasm(ENC3(MNM, GPR, INT), "ahi", r1, (Int)(Short)i2);
1293
1294 return emit_RI(p, 0xa70a0000, r1, i2);
1295}
1296
1297
sewardj9d31dfd2011-03-15 12:36:44 +00001298static UChar *
sewardj2019a972011-03-07 16:04:07 +00001299s390_emit_AGHI(UChar *p, UChar r1, UShort i2)
1300{
sewardj7ee97522011-05-09 21:45:04 +00001301 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001302 s390_disasm(ENC3(MNM, GPR, INT), "aghi", r1, (Int)(Short)i2);
1303
1304 return emit_RI(p, 0xa70b0000, r1, i2);
1305}
1306
1307
sewardj9d31dfd2011-03-15 12:36:44 +00001308static UChar *
florianad43b3a2012-02-20 15:01:14 +00001309s390_emit_AGSI(UChar *p, UChar i2, UChar b1, UShort dl1, UChar dh1)
1310{
1311 vassert(s390_host_has_gie);
1312
1313 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
florian061dc422012-05-12 16:14:08 +00001314 s390_disasm(ENC3(MNM, SDXB, INT), "agsi", dh1, dl1, 0, b1, (Int)(Char)i2);
florianad43b3a2012-02-20 15:01:14 +00001315
1316 return emit_SIY(p, 0xeb000000007aULL, i2, b1, dl1, dh1);
1317}
1318
1319
1320static UChar *
florian0e047d62012-04-21 16:06:04 +00001321s390_emit_ASI(UChar *p, UChar i2, UChar b1, UShort dl1, UChar dh1)
1322{
1323 vassert(s390_host_has_gie);
1324
1325 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
florian061dc422012-05-12 16:14:08 +00001326 s390_disasm(ENC3(MNM, SDXB, INT), "asi", dh1, dl1, 0, b1, (Int)(Char)i2);
florian0e047d62012-04-21 16:06:04 +00001327
1328 return emit_SIY(p, 0xeb000000006aULL, i2, b1, dl1, dh1);
1329}
1330
1331
1332static UChar *
sewardj2019a972011-03-07 16:04:07 +00001333s390_emit_NR(UChar *p, UChar r1, UChar r2)
1334{
sewardj7ee97522011-05-09 21:45:04 +00001335 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001336 s390_disasm(ENC3(MNM, GPR, GPR), "nr", r1, r2);
1337
1338 return emit_RR(p, 0x1400, r1, r2);
1339}
1340
1341
sewardj9d31dfd2011-03-15 12:36:44 +00001342static UChar *
sewardj2019a972011-03-07 16:04:07 +00001343s390_emit_NGR(UChar *p, UChar r1, UChar r2)
1344{
sewardj7ee97522011-05-09 21:45:04 +00001345 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001346 s390_disasm(ENC3(MNM, GPR, GPR), "ngr", r1, r2);
1347
1348 return emit_RRE(p, 0xb9800000, r1, r2);
1349}
1350
1351
sewardj9d31dfd2011-03-15 12:36:44 +00001352static UChar *
sewardj2019a972011-03-07 16:04:07 +00001353s390_emit_N(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1354{
sewardj7ee97522011-05-09 21:45:04 +00001355 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001356 s390_disasm(ENC3(MNM, GPR, UDXB), "n", r1, d2, x2, b2);
1357
1358 return emit_RX(p, 0x54000000, r1, x2, b2, d2);
1359}
1360
1361
sewardj9d31dfd2011-03-15 12:36:44 +00001362static UChar *
sewardj2019a972011-03-07 16:04:07 +00001363s390_emit_NY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1364{
sewardj652b56a2011-04-13 15:38:17 +00001365 vassert(s390_host_has_ldisp);
1366
sewardj7ee97522011-05-09 21:45:04 +00001367 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001368 s390_disasm(ENC3(MNM, GPR, SDXB), "ny", r1, dh2, dl2, x2, b2);
1369
1370 return emit_RXY(p, 0xe30000000054ULL, r1, x2, b2, dl2, dh2);
1371}
1372
1373
sewardj9d31dfd2011-03-15 12:36:44 +00001374static UChar *
sewardj2019a972011-03-07 16:04:07 +00001375s390_emit_NG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1376{
sewardj652b56a2011-04-13 15:38:17 +00001377 vassert(s390_host_has_ldisp || dh2 == 0);
1378
sewardj7ee97522011-05-09 21:45:04 +00001379 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001380 s390_disasm(ENC3(MNM, GPR, SDXB), "ng", r1, dh2, dl2, x2, b2);
1381
1382 return emit_RXY(p, 0xe30000000080ULL, r1, x2, b2, dl2, dh2);
1383}
1384
1385
sewardj9d31dfd2011-03-15 12:36:44 +00001386static UChar *
sewardj2019a972011-03-07 16:04:07 +00001387s390_emit_NIHF(UChar *p, UChar r1, UInt i2)
1388{
sewardj652b56a2011-04-13 15:38:17 +00001389 vassert(s390_host_has_eimm);
1390
sewardj7ee97522011-05-09 21:45:04 +00001391 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001392 s390_disasm(ENC3(MNM, GPR, UINT), "nihf", r1, i2);
1393
1394 return emit_RIL(p, 0xc00a00000000ULL, r1, i2);
1395}
1396
1397
sewardj9d31dfd2011-03-15 12:36:44 +00001398static UChar *
sewardj2019a972011-03-07 16:04:07 +00001399s390_emit_NILF(UChar *p, UChar r1, UInt i2)
1400{
sewardj652b56a2011-04-13 15:38:17 +00001401 vassert(s390_host_has_eimm);
1402
sewardj7ee97522011-05-09 21:45:04 +00001403 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001404 s390_disasm(ENC3(MNM, GPR, UINT), "nilf", r1, i2);
1405
1406 return emit_RIL(p, 0xc00b00000000ULL, r1, i2);
1407}
1408
1409
sewardj9d31dfd2011-03-15 12:36:44 +00001410static UChar *
sewardj2019a972011-03-07 16:04:07 +00001411s390_emit_NILL(UChar *p, UChar r1, UShort i2)
1412{
sewardj7ee97522011-05-09 21:45:04 +00001413 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001414 s390_disasm(ENC3(MNM, GPR, UINT), "nill", r1, i2);
1415
1416 return emit_RI(p, 0xa5070000, r1, i2);
1417}
1418
1419
sewardj9d31dfd2011-03-15 12:36:44 +00001420static UChar *
sewardj2019a972011-03-07 16:04:07 +00001421s390_emit_BASR(UChar *p, UChar r1, UChar r2)
1422{
sewardj7ee97522011-05-09 21:45:04 +00001423 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001424 s390_disasm(ENC3(MNM, GPR, GPR), "basr", r1, r2);
1425
1426 return emit_RR(p, 0x0d00, r1, r2);
1427}
1428
1429
sewardj9d31dfd2011-03-15 12:36:44 +00001430static UChar *
sewardj2019a972011-03-07 16:04:07 +00001431s390_emit_BCR(UChar *p, UChar r1, UChar r2)
1432{
sewardj7ee97522011-05-09 21:45:04 +00001433 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001434 s390_disasm(ENC2(XMNM, GPR), S390_XMNM_BCR, r1, r2);
1435
1436 return emit_RR(p, 0x0700, r1, r2);
1437}
1438
1439
sewardj9d31dfd2011-03-15 12:36:44 +00001440static UChar *
sewardj2019a972011-03-07 16:04:07 +00001441s390_emit_BRC(UChar *p, UChar r1, UShort i2)
1442{
sewardj7ee97522011-05-09 21:45:04 +00001443 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001444 s390_disasm(ENC2(XMNM, PCREL), S390_XMNM_BRC, r1, (Int)(Short)i2);
1445
1446 return emit_RI(p, 0xa7040000, r1, i2);
1447}
1448
1449
sewardj9d31dfd2011-03-15 12:36:44 +00001450static UChar *
florian8844a632012-04-13 04:04:06 +00001451s390_emit_BRCL(UChar *p, UChar r1, ULong i2)
1452{
1453 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
1454 s390_disasm(ENC2(XMNM, PCREL), S390_XMNM_BRCL, r1, i2);
1455
1456 return emit_RIL(p, 0xc00400000000ULL, r1, i2);
1457}
1458
1459
1460static UChar *
sewardj2019a972011-03-07 16:04:07 +00001461s390_emit_CR(UChar *p, UChar r1, UChar r2)
1462{
sewardj7ee97522011-05-09 21:45:04 +00001463 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001464 s390_disasm(ENC3(MNM, GPR, GPR), "cr", r1, r2);
1465
1466 return emit_RR(p, 0x1900, r1, r2);
1467}
1468
1469
sewardj9d31dfd2011-03-15 12:36:44 +00001470static UChar *
sewardj2019a972011-03-07 16:04:07 +00001471s390_emit_CGR(UChar *p, UChar r1, UChar r2)
1472{
sewardj7ee97522011-05-09 21:45:04 +00001473 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001474 s390_disasm(ENC3(MNM, GPR, GPR), "cgr", r1, r2);
1475
1476 return emit_RRE(p, 0xb9200000, r1, r2);
1477}
1478
1479
sewardj9d31dfd2011-03-15 12:36:44 +00001480static UChar *
sewardj2019a972011-03-07 16:04:07 +00001481s390_emit_C(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1482{
sewardj7ee97522011-05-09 21:45:04 +00001483 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001484 s390_disasm(ENC3(MNM, GPR, UDXB), "c", r1, d2, x2, b2);
1485
1486 return emit_RX(p, 0x59000000, r1, x2, b2, d2);
1487}
1488
1489
sewardj9d31dfd2011-03-15 12:36:44 +00001490static UChar *
sewardj2019a972011-03-07 16:04:07 +00001491s390_emit_CY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1492{
sewardj652b56a2011-04-13 15:38:17 +00001493 vassert(s390_host_has_ldisp);
1494
sewardj7ee97522011-05-09 21:45:04 +00001495 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001496 s390_disasm(ENC3(MNM, GPR, SDXB), "cy", r1, dh2, dl2, x2, b2);
1497
1498 return emit_RXY(p, 0xe30000000059ULL, r1, x2, b2, dl2, dh2);
1499}
1500
1501
sewardj9d31dfd2011-03-15 12:36:44 +00001502static UChar *
sewardj2019a972011-03-07 16:04:07 +00001503s390_emit_CG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1504{
sewardj652b56a2011-04-13 15:38:17 +00001505 vassert(s390_host_has_ldisp || dh2 == 0);
1506
sewardj7ee97522011-05-09 21:45:04 +00001507 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001508 s390_disasm(ENC3(MNM, GPR, SDXB), "cg", r1, dh2, dl2, x2, b2);
1509
1510 return emit_RXY(p, 0xe30000000020ULL, r1, x2, b2, dl2, dh2);
1511}
1512
1513
sewardj9d31dfd2011-03-15 12:36:44 +00001514static UChar *
sewardj2019a972011-03-07 16:04:07 +00001515s390_emit_CFI(UChar *p, UChar r1, UInt i2)
1516{
sewardj652b56a2011-04-13 15:38:17 +00001517 vassert(s390_host_has_eimm);
1518
sewardj7ee97522011-05-09 21:45:04 +00001519 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001520 s390_disasm(ENC3(MNM, GPR, INT), "cfi", r1, i2);
1521
1522 return emit_RIL(p, 0xc20d00000000ULL, r1, i2);
1523}
1524
1525
sewardj9d31dfd2011-03-15 12:36:44 +00001526static UChar *
florian07d34552012-05-26 01:59:21 +00001527s390_emit_CGFI(UChar *p, UChar r1, UInt i2)
1528{
1529 vassert(s390_host_has_eimm);
1530
1531 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
1532 s390_disasm(ENC3(MNM, GPR, INT), "cgfi", r1, i2);
1533
1534 return emit_RIL(p, 0xc20c00000000ULL, r1, i2);
1535}
1536
1537
1538static UChar *
sewardj2019a972011-03-07 16:04:07 +00001539s390_emit_CS(UChar *p, UChar r1, UChar r3, UChar b2, UShort d2)
1540{
sewardj7ee97522011-05-09 21:45:04 +00001541 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001542 s390_disasm(ENC4(MNM, GPR, GPR, UDXB), "cs", r1, r3, d2, 0, b2);
1543
1544 return emit_RS(p, 0xba000000, r1, r3, b2, d2);
1545}
1546
1547
sewardj9d31dfd2011-03-15 12:36:44 +00001548static UChar *
sewardj2019a972011-03-07 16:04:07 +00001549s390_emit_CSY(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
1550{
sewardj652b56a2011-04-13 15:38:17 +00001551 vassert(s390_host_has_ldisp);
1552
sewardj7ee97522011-05-09 21:45:04 +00001553 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001554 s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "csy", r1, r3, dh2, dl2, 0, b2);
1555
1556 return emit_RSY(p, 0xeb0000000014ULL, r1, r3, b2, dl2, dh2);
1557}
1558
1559
sewardj9d31dfd2011-03-15 12:36:44 +00001560static UChar *
sewardj2019a972011-03-07 16:04:07 +00001561s390_emit_CSG(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
1562{
sewardj652b56a2011-04-13 15:38:17 +00001563 vassert(s390_host_has_ldisp || dh2 == 0);
1564
sewardj7ee97522011-05-09 21:45:04 +00001565 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001566 s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "csg", r1, r3, dh2, dl2, 0, b2);
1567
1568 return emit_RSY(p, 0xeb0000000030ULL, r1, r3, b2, dl2, dh2);
1569}
1570
1571
sewardj9d31dfd2011-03-15 12:36:44 +00001572static UChar *
sewardj2019a972011-03-07 16:04:07 +00001573s390_emit_CLR(UChar *p, UChar r1, UChar r2)
1574{
sewardj7ee97522011-05-09 21:45:04 +00001575 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001576 s390_disasm(ENC3(MNM, GPR, GPR), "clr", r1, r2);
1577
1578 return emit_RR(p, 0x1500, r1, r2);
1579}
1580
1581
sewardj9d31dfd2011-03-15 12:36:44 +00001582static UChar *
sewardj2019a972011-03-07 16:04:07 +00001583s390_emit_CLGR(UChar *p, UChar r1, UChar r2)
1584{
sewardj7ee97522011-05-09 21:45:04 +00001585 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001586 s390_disasm(ENC3(MNM, GPR, GPR), "clgr", r1, r2);
1587
1588 return emit_RRE(p, 0xb9210000, r1, r2);
1589}
1590
1591
sewardj9d31dfd2011-03-15 12:36:44 +00001592static UChar *
sewardj2019a972011-03-07 16:04:07 +00001593s390_emit_CL(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1594{
sewardj7ee97522011-05-09 21:45:04 +00001595 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001596 s390_disasm(ENC3(MNM, GPR, UDXB), "cl", r1, d2, x2, b2);
1597
1598 return emit_RX(p, 0x55000000, r1, x2, b2, d2);
1599}
1600
1601
sewardj9d31dfd2011-03-15 12:36:44 +00001602static UChar *
sewardj2019a972011-03-07 16:04:07 +00001603s390_emit_CLY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1604{
sewardj652b56a2011-04-13 15:38:17 +00001605 vassert(s390_host_has_ldisp);
1606
sewardj7ee97522011-05-09 21:45:04 +00001607 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001608 s390_disasm(ENC3(MNM, GPR, SDXB), "cly", r1, dh2, dl2, x2, b2);
1609
1610 return emit_RXY(p, 0xe30000000055ULL, r1, x2, b2, dl2, dh2);
1611}
1612
1613
sewardj9d31dfd2011-03-15 12:36:44 +00001614static UChar *
sewardj2019a972011-03-07 16:04:07 +00001615s390_emit_CLG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1616{
sewardj652b56a2011-04-13 15:38:17 +00001617 vassert(s390_host_has_ldisp || dh2 == 0);
1618
sewardj7ee97522011-05-09 21:45:04 +00001619 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001620 s390_disasm(ENC3(MNM, GPR, SDXB), "clg", r1, dh2, dl2, x2, b2);
1621
1622 return emit_RXY(p, 0xe30000000021ULL, r1, x2, b2, dl2, dh2);
1623}
1624
1625
sewardj9d31dfd2011-03-15 12:36:44 +00001626static UChar *
sewardj2019a972011-03-07 16:04:07 +00001627s390_emit_CLFI(UChar *p, UChar r1, UInt i2)
1628{
sewardj652b56a2011-04-13 15:38:17 +00001629 vassert(s390_host_has_eimm);
1630
sewardj7ee97522011-05-09 21:45:04 +00001631 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001632 s390_disasm(ENC3(MNM, GPR, UINT), "clfi", r1, i2);
1633
1634 return emit_RIL(p, 0xc20f00000000ULL, r1, i2);
1635}
1636
1637
sewardj9d31dfd2011-03-15 12:36:44 +00001638static UChar *
florian07d34552012-05-26 01:59:21 +00001639s390_emit_CLGFI(UChar *p, UChar r1, UInt i2)
1640{
1641 vassert(s390_host_has_eimm);
1642
1643 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
1644 s390_disasm(ENC3(MNM, GPR, UINT), "clgfi", r1, i2);
1645
1646 return emit_RIL(p, 0xc20e00000000ULL, r1, i2);
1647}
1648
1649
1650static UChar *
sewardj2019a972011-03-07 16:04:07 +00001651s390_emit_DR(UChar *p, UChar r1, UChar r2)
1652{
sewardj7ee97522011-05-09 21:45:04 +00001653 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001654 s390_disasm(ENC3(MNM, GPR, GPR), "dr", r1, r2);
1655
1656 return emit_RR(p, 0x1d00, r1, r2);
1657}
1658
1659
sewardj9d31dfd2011-03-15 12:36:44 +00001660static UChar *
sewardj2019a972011-03-07 16:04:07 +00001661s390_emit_D(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1662{
sewardj7ee97522011-05-09 21:45:04 +00001663 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001664 s390_disasm(ENC3(MNM, GPR, UDXB), "d", r1, d2, x2, b2);
1665
1666 return emit_RX(p, 0x5d000000, r1, x2, b2, d2);
1667}
1668
1669
sewardj9d31dfd2011-03-15 12:36:44 +00001670static UChar *
sewardj2019a972011-03-07 16:04:07 +00001671s390_emit_DLR(UChar *p, UChar r1, UChar r2)
1672{
sewardj7ee97522011-05-09 21:45:04 +00001673 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001674 s390_disasm(ENC3(MNM, GPR, GPR), "dlr", r1, r2);
1675
1676 return emit_RRE(p, 0xb9970000, r1, r2);
1677}
1678
1679
sewardj9d31dfd2011-03-15 12:36:44 +00001680static UChar *
sewardj2019a972011-03-07 16:04:07 +00001681s390_emit_DLGR(UChar *p, UChar r1, UChar r2)
1682{
sewardj7ee97522011-05-09 21:45:04 +00001683 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001684 s390_disasm(ENC3(MNM, GPR, GPR), "dlgr", r1, r2);
1685
1686 return emit_RRE(p, 0xb9870000, r1, r2);
1687}
1688
1689
sewardj9d31dfd2011-03-15 12:36:44 +00001690static UChar *
sewardj2019a972011-03-07 16:04:07 +00001691s390_emit_DL(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1692{
sewardj652b56a2011-04-13 15:38:17 +00001693 vassert(s390_host_has_ldisp || dh2 == 0);
1694
sewardj7ee97522011-05-09 21:45:04 +00001695 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001696 s390_disasm(ENC3(MNM, GPR, SDXB), "dl", r1, dh2, dl2, x2, b2);
1697
1698 return emit_RXY(p, 0xe30000000097ULL, r1, x2, b2, dl2, dh2);
1699}
1700
1701
sewardj9d31dfd2011-03-15 12:36:44 +00001702static UChar *
sewardj2019a972011-03-07 16:04:07 +00001703s390_emit_DLG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1704{
sewardj652b56a2011-04-13 15:38:17 +00001705 vassert(s390_host_has_ldisp || dh2 == 0);
1706
sewardj7ee97522011-05-09 21:45:04 +00001707 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001708 s390_disasm(ENC3(MNM, GPR, SDXB), "dlg", r1, dh2, dl2, x2, b2);
1709
1710 return emit_RXY(p, 0xe30000000087ULL, r1, x2, b2, dl2, dh2);
1711}
1712
1713
sewardj9d31dfd2011-03-15 12:36:44 +00001714static UChar *
sewardj2019a972011-03-07 16:04:07 +00001715s390_emit_DSGR(UChar *p, UChar r1, UChar r2)
1716{
sewardj7ee97522011-05-09 21:45:04 +00001717 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001718 s390_disasm(ENC3(MNM, GPR, GPR), "dsgr", r1, r2);
1719
1720 return emit_RRE(p, 0xb90d0000, r1, r2);
1721}
1722
1723
sewardj9d31dfd2011-03-15 12:36:44 +00001724static UChar *
sewardj2019a972011-03-07 16:04:07 +00001725s390_emit_DSG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1726{
sewardj652b56a2011-04-13 15:38:17 +00001727 vassert(s390_host_has_ldisp || dh2 == 0);
1728
sewardj7ee97522011-05-09 21:45:04 +00001729 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001730 s390_disasm(ENC3(MNM, GPR, SDXB), "dsg", r1, dh2, dl2, x2, b2);
1731
1732 return emit_RXY(p, 0xe3000000000dULL, r1, x2, b2, dl2, dh2);
1733}
1734
1735
sewardj9d31dfd2011-03-15 12:36:44 +00001736static UChar *
sewardj2019a972011-03-07 16:04:07 +00001737s390_emit_XR(UChar *p, UChar r1, UChar r2)
1738{
sewardj7ee97522011-05-09 21:45:04 +00001739 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001740 s390_disasm(ENC3(MNM, GPR, GPR), "xr", r1, r2);
1741
1742 return emit_RR(p, 0x1700, r1, r2);
1743}
1744
1745
sewardj9d31dfd2011-03-15 12:36:44 +00001746static UChar *
sewardj2019a972011-03-07 16:04:07 +00001747s390_emit_XGR(UChar *p, UChar r1, UChar r2)
1748{
sewardj7ee97522011-05-09 21:45:04 +00001749 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001750 s390_disasm(ENC3(MNM, GPR, GPR), "xgr", r1, r2);
1751
1752 return emit_RRE(p, 0xb9820000, r1, r2);
1753}
1754
1755
sewardj9d31dfd2011-03-15 12:36:44 +00001756static UChar *
sewardj2019a972011-03-07 16:04:07 +00001757s390_emit_X(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1758{
sewardj7ee97522011-05-09 21:45:04 +00001759 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001760 s390_disasm(ENC3(MNM, GPR, UDXB), "x", r1, d2, x2, b2);
1761
1762 return emit_RX(p, 0x57000000, r1, x2, b2, d2);
1763}
1764
1765
sewardj9d31dfd2011-03-15 12:36:44 +00001766static UChar *
sewardj2019a972011-03-07 16:04:07 +00001767s390_emit_XY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1768{
sewardj652b56a2011-04-13 15:38:17 +00001769 vassert(s390_host_has_ldisp);
1770
sewardj7ee97522011-05-09 21:45:04 +00001771 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001772 s390_disasm(ENC3(MNM, GPR, SDXB), "xy", r1, dh2, dl2, x2, b2);
1773
1774 return emit_RXY(p, 0xe30000000057ULL, r1, x2, b2, dl2, dh2);
1775}
1776
1777
sewardj9d31dfd2011-03-15 12:36:44 +00001778static UChar *
sewardj2019a972011-03-07 16:04:07 +00001779s390_emit_XG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1780{
sewardj652b56a2011-04-13 15:38:17 +00001781 vassert(s390_host_has_ldisp || dh2 == 0);
1782
sewardj7ee97522011-05-09 21:45:04 +00001783 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001784 s390_disasm(ENC3(MNM, GPR, SDXB), "xg", r1, dh2, dl2, x2, b2);
1785
1786 return emit_RXY(p, 0xe30000000082ULL, r1, x2, b2, dl2, dh2);
1787}
1788
1789
sewardj9d31dfd2011-03-15 12:36:44 +00001790static UChar *
sewardj2019a972011-03-07 16:04:07 +00001791s390_emit_XIHF(UChar *p, UChar r1, UInt i2)
1792{
sewardj652b56a2011-04-13 15:38:17 +00001793 vassert(s390_host_has_eimm);
1794
sewardj7ee97522011-05-09 21:45:04 +00001795 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001796 s390_disasm(ENC3(MNM, GPR, UINT), "xihf", r1, i2);
1797
1798 return emit_RIL(p, 0xc00600000000ULL, r1, i2);
1799}
1800
1801
sewardj9d31dfd2011-03-15 12:36:44 +00001802static UChar *
sewardj2019a972011-03-07 16:04:07 +00001803s390_emit_XILF(UChar *p, UChar r1, UInt i2)
1804{
sewardj652b56a2011-04-13 15:38:17 +00001805 vassert(s390_host_has_eimm);
1806
sewardj7ee97522011-05-09 21:45:04 +00001807 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001808 s390_disasm(ENC3(MNM, GPR, UINT), "xilf", r1, i2);
1809
1810 return emit_RIL(p, 0xc00700000000ULL, r1, i2);
1811}
1812
1813
sewardj9d31dfd2011-03-15 12:36:44 +00001814static UChar *
florianad43b3a2012-02-20 15:01:14 +00001815s390_emit_XC(UChar *p, UInt l, UChar b1, UShort d1, UChar b2, UShort d2)
1816{
1817 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
1818 s390_disasm(ENC3(MNM, UDLB, UDXB), "xc", d1, l, b1, d2, 0, b2);
1819
1820 return emit_SSa(p, 0xd70000000000ULL, l, b1, d1, b2, d2);
1821}
1822
1823
1824static UChar *
sewardj2019a972011-03-07 16:04:07 +00001825s390_emit_FLOGR(UChar *p, UChar r1, UChar r2)
1826{
sewardj652b56a2011-04-13 15:38:17 +00001827 vassert(s390_host_has_eimm);
1828
sewardj7ee97522011-05-09 21:45:04 +00001829 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001830 s390_disasm(ENC3(MNM, GPR, GPR), "flogr", r1, r2);
1831
1832 return emit_RRE(p, 0xb9830000, r1, r2);
1833}
1834
1835
sewardj9d31dfd2011-03-15 12:36:44 +00001836static UChar *
sewardj2019a972011-03-07 16:04:07 +00001837s390_emit_IC(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1838{
sewardj7ee97522011-05-09 21:45:04 +00001839 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001840 s390_disasm(ENC3(MNM, GPR, UDXB), "ic", r1, d2, x2, b2);
1841
1842 return emit_RX(p, 0x43000000, r1, x2, b2, d2);
1843}
1844
1845
sewardj9d31dfd2011-03-15 12:36:44 +00001846static UChar *
sewardj2019a972011-03-07 16:04:07 +00001847s390_emit_ICY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1848{
sewardj652b56a2011-04-13 15:38:17 +00001849 vassert(s390_host_has_ldisp);
1850
sewardj7ee97522011-05-09 21:45:04 +00001851 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001852 s390_disasm(ENC3(MNM, GPR, SDXB), "icy", r1, dh2, dl2, x2, b2);
1853
1854 return emit_RXY(p, 0xe30000000073ULL, r1, x2, b2, dl2, dh2);
1855}
1856
1857
sewardj9d31dfd2011-03-15 12:36:44 +00001858static UChar *
sewardj2019a972011-03-07 16:04:07 +00001859s390_emit_IIHF(UChar *p, UChar r1, UInt i2)
1860{
sewardj652b56a2011-04-13 15:38:17 +00001861 vassert(s390_host_has_eimm);
1862
sewardj7ee97522011-05-09 21:45:04 +00001863 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001864 s390_disasm(ENC3(MNM, GPR, UINT), "iihf", r1, i2);
1865
1866 return emit_RIL(p, 0xc00800000000ULL, r1, i2);
1867}
1868
1869
sewardj9d31dfd2011-03-15 12:36:44 +00001870static UChar *
sewardj2019a972011-03-07 16:04:07 +00001871s390_emit_IIHH(UChar *p, UChar r1, UShort i2)
1872{
sewardj7ee97522011-05-09 21:45:04 +00001873 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001874 s390_disasm(ENC3(MNM, GPR, UINT), "iihh", r1, i2);
1875
1876 return emit_RI(p, 0xa5000000, r1, i2);
1877}
1878
1879
sewardj9d31dfd2011-03-15 12:36:44 +00001880static UChar *
sewardj2019a972011-03-07 16:04:07 +00001881s390_emit_IIHL(UChar *p, UChar r1, UShort i2)
1882{
sewardj7ee97522011-05-09 21:45:04 +00001883 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001884 s390_disasm(ENC3(MNM, GPR, UINT), "iihl", r1, i2);
1885
1886 return emit_RI(p, 0xa5010000, r1, i2);
1887}
1888
1889
sewardj9d31dfd2011-03-15 12:36:44 +00001890static UChar *
sewardj2019a972011-03-07 16:04:07 +00001891s390_emit_IILF(UChar *p, UChar r1, UInt i2)
1892{
sewardj652b56a2011-04-13 15:38:17 +00001893 vassert(s390_host_has_eimm);
1894
sewardj7ee97522011-05-09 21:45:04 +00001895 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001896 s390_disasm(ENC3(MNM, GPR, UINT), "iilf", r1, i2);
1897
1898 return emit_RIL(p, 0xc00900000000ULL, r1, i2);
1899}
1900
1901
sewardj9d31dfd2011-03-15 12:36:44 +00001902static UChar *
sewardj2019a972011-03-07 16:04:07 +00001903s390_emit_IILH(UChar *p, UChar r1, UShort i2)
1904{
sewardj7ee97522011-05-09 21:45:04 +00001905 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001906 s390_disasm(ENC3(MNM, GPR, UINT), "iilh", r1, i2);
1907
1908 return emit_RI(p, 0xa5020000, r1, i2);
1909}
1910
1911
sewardj9d31dfd2011-03-15 12:36:44 +00001912static UChar *
sewardj2019a972011-03-07 16:04:07 +00001913s390_emit_IILL(UChar *p, UChar r1, UShort i2)
1914{
sewardj7ee97522011-05-09 21:45:04 +00001915 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001916 s390_disasm(ENC3(MNM, GPR, UINT), "iill", r1, i2);
1917
1918 return emit_RI(p, 0xa5030000, r1, i2);
1919}
1920
1921
sewardj9d31dfd2011-03-15 12:36:44 +00001922static UChar *
sewardj2019a972011-03-07 16:04:07 +00001923s390_emit_IPM(UChar *p, UChar r1, UChar r2)
1924{
sewardj7ee97522011-05-09 21:45:04 +00001925 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001926 s390_disasm(ENC2(MNM, GPR), "ipm", r1);
1927
1928 return emit_RRE(p, 0xb2220000, r1, r2);
1929}
1930
1931
sewardj9d31dfd2011-03-15 12:36:44 +00001932static UChar *
sewardj2019a972011-03-07 16:04:07 +00001933s390_emit_LR(UChar *p, UChar r1, UChar r2)
1934{
sewardj7ee97522011-05-09 21:45:04 +00001935 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001936 s390_disasm(ENC3(MNM, GPR, GPR), "lr", r1, r2);
1937
1938 return emit_RR(p, 0x1800, r1, r2);
1939}
1940
1941
sewardj9d31dfd2011-03-15 12:36:44 +00001942static UChar *
sewardj2019a972011-03-07 16:04:07 +00001943s390_emit_LGR(UChar *p, UChar r1, UChar r2)
1944{
sewardj7ee97522011-05-09 21:45:04 +00001945 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001946 s390_disasm(ENC3(MNM, GPR, GPR), "lgr", r1, r2);
1947
1948 return emit_RRE(p, 0xb9040000, r1, r2);
1949}
1950
1951
sewardj9d31dfd2011-03-15 12:36:44 +00001952static UChar *
sewardj2019a972011-03-07 16:04:07 +00001953s390_emit_LGFR(UChar *p, UChar r1, UChar r2)
1954{
sewardj7ee97522011-05-09 21:45:04 +00001955 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001956 s390_disasm(ENC3(MNM, GPR, GPR), "lgfr", r1, r2);
1957
1958 return emit_RRE(p, 0xb9140000, r1, r2);
1959}
1960
1961
sewardj9d31dfd2011-03-15 12:36:44 +00001962static UChar *
sewardj2019a972011-03-07 16:04:07 +00001963s390_emit_L(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
1964{
sewardj7ee97522011-05-09 21:45:04 +00001965 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001966 s390_disasm(ENC3(MNM, GPR, UDXB), "l", r1, d2, x2, b2);
1967
1968 return emit_RX(p, 0x58000000, r1, x2, b2, d2);
1969}
1970
1971
sewardj9d31dfd2011-03-15 12:36:44 +00001972static UChar *
sewardj2019a972011-03-07 16:04:07 +00001973s390_emit_LY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1974{
sewardj652b56a2011-04-13 15:38:17 +00001975 vassert(s390_host_has_ldisp);
1976
sewardj7ee97522011-05-09 21:45:04 +00001977 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001978 s390_disasm(ENC3(MNM, GPR, SDXB), "ly", r1, dh2, dl2, x2, b2);
1979
1980 return emit_RXY(p, 0xe30000000058ULL, r1, x2, b2, dl2, dh2);
1981}
1982
1983
sewardj9d31dfd2011-03-15 12:36:44 +00001984static UChar *
sewardj2019a972011-03-07 16:04:07 +00001985s390_emit_LG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1986{
sewardj652b56a2011-04-13 15:38:17 +00001987 vassert(s390_host_has_ldisp || dh2 == 0);
1988
sewardj7ee97522011-05-09 21:45:04 +00001989 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00001990 s390_disasm(ENC3(MNM, GPR, SDXB), "lg", r1, dh2, dl2, x2, b2);
1991
1992 return emit_RXY(p, 0xe30000000004ULL, r1, x2, b2, dl2, dh2);
1993}
1994
1995
sewardj9d31dfd2011-03-15 12:36:44 +00001996static UChar *
sewardj2019a972011-03-07 16:04:07 +00001997s390_emit_LGF(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
1998{
sewardj652b56a2011-04-13 15:38:17 +00001999 vassert(s390_host_has_ldisp || dh2 == 0);
2000
sewardj7ee97522011-05-09 21:45:04 +00002001 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002002 s390_disasm(ENC3(MNM, GPR, SDXB), "lgf", r1, dh2, dl2, x2, b2);
2003
2004 return emit_RXY(p, 0xe30000000014ULL, r1, x2, b2, dl2, dh2);
2005}
2006
2007
sewardj9d31dfd2011-03-15 12:36:44 +00002008static UChar *
sewardj2019a972011-03-07 16:04:07 +00002009s390_emit_LGFI(UChar *p, UChar r1, UInt i2)
2010{
sewardj652b56a2011-04-13 15:38:17 +00002011 vassert(s390_host_has_eimm);
2012
sewardj7ee97522011-05-09 21:45:04 +00002013 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002014 s390_disasm(ENC3(MNM, GPR, INT), "lgfi", r1, i2);
2015
2016 return emit_RIL(p, 0xc00100000000ULL, r1, i2);
2017}
2018
2019
sewardj9d31dfd2011-03-15 12:36:44 +00002020static UChar *
sewardj2019a972011-03-07 16:04:07 +00002021s390_emit_LTR(UChar *p, UChar r1, UChar r2)
2022{
sewardj7ee97522011-05-09 21:45:04 +00002023 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002024 s390_disasm(ENC3(MNM, GPR, GPR), "ltr", r1, r2);
2025
2026 return emit_RR(p, 0x1200, r1, r2);
2027}
2028
2029
sewardj9d31dfd2011-03-15 12:36:44 +00002030static UChar *
sewardj2019a972011-03-07 16:04:07 +00002031s390_emit_LTGR(UChar *p, UChar r1, UChar r2)
2032{
sewardj7ee97522011-05-09 21:45:04 +00002033 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002034 s390_disasm(ENC3(MNM, GPR, GPR), "ltgr", r1, r2);
2035
2036 return emit_RRE(p, 0xb9020000, r1, r2);
2037}
2038
2039
sewardj9d31dfd2011-03-15 12:36:44 +00002040static UChar *
sewardj2019a972011-03-07 16:04:07 +00002041s390_emit_LT(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2042{
sewardj652b56a2011-04-13 15:38:17 +00002043 vassert(s390_host_has_eimm);
2044
sewardj7ee97522011-05-09 21:45:04 +00002045 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002046 s390_disasm(ENC3(MNM, GPR, SDXB), "lt", r1, dh2, dl2, x2, b2);
2047
2048 return emit_RXY(p, 0xe30000000012ULL, r1, x2, b2, dl2, dh2);
2049}
2050
2051
sewardj9d31dfd2011-03-15 12:36:44 +00002052static UChar *
sewardj2019a972011-03-07 16:04:07 +00002053s390_emit_LTG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2054{
sewardj652b56a2011-04-13 15:38:17 +00002055 vassert(s390_host_has_eimm);
2056
sewardj7ee97522011-05-09 21:45:04 +00002057 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002058 s390_disasm(ENC3(MNM, GPR, SDXB), "ltg", r1, dh2, dl2, x2, b2);
2059
2060 return emit_RXY(p, 0xe30000000002ULL, r1, x2, b2, dl2, dh2);
2061}
2062
2063
sewardj9d31dfd2011-03-15 12:36:44 +00002064static UChar *
sewardj2019a972011-03-07 16:04:07 +00002065s390_emit_LBR(UChar *p, UChar r1, UChar r2)
2066{
sewardj652b56a2011-04-13 15:38:17 +00002067 vassert(s390_host_has_eimm);
2068
sewardj7ee97522011-05-09 21:45:04 +00002069 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002070 s390_disasm(ENC3(MNM, GPR, GPR), "lbr", r1, r2);
2071
2072 return emit_RRE(p, 0xb9260000, r1, r2);
2073}
2074
2075
sewardj9d31dfd2011-03-15 12:36:44 +00002076static UChar *
sewardj2019a972011-03-07 16:04:07 +00002077s390_emit_LGBR(UChar *p, UChar r1, UChar r2)
2078{
sewardj652b56a2011-04-13 15:38:17 +00002079 vassert(s390_host_has_eimm);
2080
sewardj7ee97522011-05-09 21:45:04 +00002081 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002082 s390_disasm(ENC3(MNM, GPR, GPR), "lgbr", r1, r2);
2083
2084 return emit_RRE(p, 0xb9060000, r1, r2);
2085}
2086
2087
sewardj9d31dfd2011-03-15 12:36:44 +00002088static UChar *
sewardj2019a972011-03-07 16:04:07 +00002089s390_emit_LB(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2090{
sewardj652b56a2011-04-13 15:38:17 +00002091 vassert(s390_host_has_ldisp);
2092
sewardj7ee97522011-05-09 21:45:04 +00002093 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002094 s390_disasm(ENC3(MNM, GPR, SDXB), "lb", r1, dh2, dl2, x2, b2);
2095
2096 return emit_RXY(p, 0xe30000000076ULL, r1, x2, b2, dl2, dh2);
2097}
2098
2099
sewardj9d31dfd2011-03-15 12:36:44 +00002100static UChar *
sewardj2019a972011-03-07 16:04:07 +00002101s390_emit_LGB(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2102{
sewardj652b56a2011-04-13 15:38:17 +00002103 vassert(s390_host_has_ldisp);
2104
sewardj7ee97522011-05-09 21:45:04 +00002105 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002106 s390_disasm(ENC3(MNM, GPR, SDXB), "lgb", r1, dh2, dl2, x2, b2);
2107
2108 return emit_RXY(p, 0xe30000000077ULL, r1, x2, b2, dl2, dh2);
2109}
2110
2111
sewardj9d31dfd2011-03-15 12:36:44 +00002112static UChar *
sewardj2019a972011-03-07 16:04:07 +00002113s390_emit_LCR(UChar *p, UChar r1, UChar r2)
2114{
sewardj7ee97522011-05-09 21:45:04 +00002115 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002116 s390_disasm(ENC3(MNM, GPR, GPR), "lcr", r1, r2);
2117
2118 return emit_RR(p, 0x1300, r1, r2);
2119}
2120
2121
sewardj9d31dfd2011-03-15 12:36:44 +00002122static UChar *
sewardj2019a972011-03-07 16:04:07 +00002123s390_emit_LCGR(UChar *p, UChar r1, UChar r2)
2124{
sewardj7ee97522011-05-09 21:45:04 +00002125 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002126 s390_disasm(ENC3(MNM, GPR, GPR), "lcgr", r1, r2);
2127
2128 return emit_RRE(p, 0xb9030000, r1, r2);
2129}
2130
2131
sewardj9d31dfd2011-03-15 12:36:44 +00002132static UChar *
sewardj2019a972011-03-07 16:04:07 +00002133s390_emit_LHR(UChar *p, UChar r1, UChar r2)
2134{
sewardj652b56a2011-04-13 15:38:17 +00002135 vassert(s390_host_has_eimm);
2136
sewardj7ee97522011-05-09 21:45:04 +00002137 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002138 s390_disasm(ENC3(MNM, GPR, GPR), "lhr", r1, r2);
2139
2140 return emit_RRE(p, 0xb9270000, r1, r2);
2141}
2142
2143
sewardj9d31dfd2011-03-15 12:36:44 +00002144static UChar *
sewardj2019a972011-03-07 16:04:07 +00002145s390_emit_LGHR(UChar *p, UChar r1, UChar r2)
2146{
sewardj652b56a2011-04-13 15:38:17 +00002147 vassert(s390_host_has_eimm);
2148
sewardj7ee97522011-05-09 21:45:04 +00002149 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002150 s390_disasm(ENC3(MNM, GPR, GPR), "lghr", r1, r2);
2151
2152 return emit_RRE(p, 0xb9070000, r1, r2);
2153}
2154
2155
sewardj9d31dfd2011-03-15 12:36:44 +00002156static UChar *
sewardj2019a972011-03-07 16:04:07 +00002157s390_emit_LH(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2158{
sewardj7ee97522011-05-09 21:45:04 +00002159 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002160 s390_disasm(ENC3(MNM, GPR, UDXB), "lh", r1, d2, x2, b2);
2161
2162 return emit_RX(p, 0x48000000, r1, x2, b2, d2);
2163}
2164
2165
sewardj9d31dfd2011-03-15 12:36:44 +00002166static UChar *
sewardj2019a972011-03-07 16:04:07 +00002167s390_emit_LHY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2168{
sewardj652b56a2011-04-13 15:38:17 +00002169 vassert(s390_host_has_ldisp);
2170
sewardj7ee97522011-05-09 21:45:04 +00002171 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002172 s390_disasm(ENC3(MNM, GPR, SDXB), "lhy", r1, dh2, dl2, x2, b2);
2173
2174 return emit_RXY(p, 0xe30000000078ULL, r1, x2, b2, dl2, dh2);
2175}
2176
2177
sewardj9d31dfd2011-03-15 12:36:44 +00002178static UChar *
sewardj2019a972011-03-07 16:04:07 +00002179s390_emit_LGH(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2180{
sewardj652b56a2011-04-13 15:38:17 +00002181 vassert(s390_host_has_ldisp || dh2 == 0);
2182
sewardj7ee97522011-05-09 21:45:04 +00002183 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002184 s390_disasm(ENC3(MNM, GPR, SDXB), "lgh", r1, dh2, dl2, x2, b2);
2185
2186 return emit_RXY(p, 0xe30000000015ULL, r1, x2, b2, dl2, dh2);
2187}
2188
2189
sewardj9d31dfd2011-03-15 12:36:44 +00002190static UChar *
sewardj2019a972011-03-07 16:04:07 +00002191s390_emit_LHI(UChar *p, UChar r1, UShort i2)
2192{
sewardj7ee97522011-05-09 21:45:04 +00002193 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002194 s390_disasm(ENC3(MNM, GPR, INT), "lhi", r1, (Int)(Short)i2);
2195
2196 return emit_RI(p, 0xa7080000, r1, i2);
2197}
2198
2199
sewardj9d31dfd2011-03-15 12:36:44 +00002200static UChar *
sewardj2019a972011-03-07 16:04:07 +00002201s390_emit_LGHI(UChar *p, UChar r1, UShort i2)
2202{
sewardj7ee97522011-05-09 21:45:04 +00002203 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002204 s390_disasm(ENC3(MNM, GPR, INT), "lghi", r1, (Int)(Short)i2);
2205
2206 return emit_RI(p, 0xa7090000, r1, i2);
2207}
2208
2209
sewardj9d31dfd2011-03-15 12:36:44 +00002210static UChar *
sewardj2019a972011-03-07 16:04:07 +00002211s390_emit_LLGFR(UChar *p, UChar r1, UChar r2)
2212{
sewardj7ee97522011-05-09 21:45:04 +00002213 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002214 s390_disasm(ENC3(MNM, GPR, GPR), "llgfr", r1, r2);
2215
2216 return emit_RRE(p, 0xb9160000, r1, r2);
2217}
2218
2219
sewardj9d31dfd2011-03-15 12:36:44 +00002220static UChar *
sewardj2019a972011-03-07 16:04:07 +00002221s390_emit_LLGF(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2222{
sewardj652b56a2011-04-13 15:38:17 +00002223 vassert(s390_host_has_ldisp || dh2 == 0);
2224
sewardj7ee97522011-05-09 21:45:04 +00002225 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002226 s390_disasm(ENC3(MNM, GPR, SDXB), "llgf", r1, dh2, dl2, x2, b2);
2227
2228 return emit_RXY(p, 0xe30000000016ULL, r1, x2, b2, dl2, dh2);
2229}
2230
2231
sewardj9d31dfd2011-03-15 12:36:44 +00002232static UChar *
sewardj2019a972011-03-07 16:04:07 +00002233s390_emit_LLCR(UChar *p, UChar r1, UChar r2)
2234{
sewardj652b56a2011-04-13 15:38:17 +00002235 vassert(s390_host_has_eimm);
2236
sewardj7ee97522011-05-09 21:45:04 +00002237 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002238 s390_disasm(ENC3(MNM, GPR, GPR), "llcr", r1, r2);
2239
2240 return emit_RRE(p, 0xb9940000, r1, r2);
2241}
2242
2243
sewardj9d31dfd2011-03-15 12:36:44 +00002244static UChar *
sewardj2019a972011-03-07 16:04:07 +00002245s390_emit_LLGCR(UChar *p, UChar r1, UChar r2)
2246{
sewardj652b56a2011-04-13 15:38:17 +00002247 vassert(s390_host_has_eimm);
2248
sewardj7ee97522011-05-09 21:45:04 +00002249 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002250 s390_disasm(ENC3(MNM, GPR, GPR), "llgcr", r1, r2);
2251
2252 return emit_RRE(p, 0xb9840000, r1, r2);
2253}
2254
2255
sewardj9d31dfd2011-03-15 12:36:44 +00002256static UChar *
sewardj2019a972011-03-07 16:04:07 +00002257s390_emit_LLC(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2258{
sewardj652b56a2011-04-13 15:38:17 +00002259 vassert(s390_host_has_eimm);
2260
sewardj7ee97522011-05-09 21:45:04 +00002261 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002262 s390_disasm(ENC3(MNM, GPR, SDXB), "llc", r1, dh2, dl2, x2, b2);
2263
2264 return emit_RXY(p, 0xe30000000094ULL, r1, x2, b2, dl2, dh2);
2265}
2266
2267
sewardj9d31dfd2011-03-15 12:36:44 +00002268static UChar *
sewardj2019a972011-03-07 16:04:07 +00002269s390_emit_LLGC(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2270{
sewardj652b56a2011-04-13 15:38:17 +00002271 vassert(s390_host_has_ldisp || dh2 == 0);
2272
sewardj7ee97522011-05-09 21:45:04 +00002273 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002274 s390_disasm(ENC3(MNM, GPR, SDXB), "llgc", r1, dh2, dl2, x2, b2);
2275
2276 return emit_RXY(p, 0xe30000000090ULL, r1, x2, b2, dl2, dh2);
2277}
2278
2279
sewardj9d31dfd2011-03-15 12:36:44 +00002280static UChar *
sewardj2019a972011-03-07 16:04:07 +00002281s390_emit_LLHR(UChar *p, UChar r1, UChar r2)
2282{
sewardj652b56a2011-04-13 15:38:17 +00002283 vassert(s390_host_has_eimm);
2284
sewardj7ee97522011-05-09 21:45:04 +00002285 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002286 s390_disasm(ENC3(MNM, GPR, GPR), "llhr", r1, r2);
2287
2288 return emit_RRE(p, 0xb9950000, r1, r2);
2289}
2290
2291
sewardj9d31dfd2011-03-15 12:36:44 +00002292static UChar *
sewardj2019a972011-03-07 16:04:07 +00002293s390_emit_LLGHR(UChar *p, UChar r1, UChar r2)
2294{
sewardj652b56a2011-04-13 15:38:17 +00002295 vassert(s390_host_has_eimm);
2296
sewardj7ee97522011-05-09 21:45:04 +00002297 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002298 s390_disasm(ENC3(MNM, GPR, GPR), "llghr", r1, r2);
2299
2300 return emit_RRE(p, 0xb9850000, r1, r2);
2301}
2302
2303
sewardj9d31dfd2011-03-15 12:36:44 +00002304static UChar *
sewardj2019a972011-03-07 16:04:07 +00002305s390_emit_LLH(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2306{
sewardj652b56a2011-04-13 15:38:17 +00002307 vassert(s390_host_has_eimm);
2308
sewardj7ee97522011-05-09 21:45:04 +00002309 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002310 s390_disasm(ENC3(MNM, GPR, SDXB), "llh", r1, dh2, dl2, x2, b2);
2311
2312 return emit_RXY(p, 0xe30000000095ULL, r1, x2, b2, dl2, dh2);
2313}
2314
2315
sewardj9d31dfd2011-03-15 12:36:44 +00002316static UChar *
sewardj2019a972011-03-07 16:04:07 +00002317s390_emit_LLGH(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2318{
sewardj652b56a2011-04-13 15:38:17 +00002319 vassert(s390_host_has_ldisp || dh2 == 0);
2320
sewardj7ee97522011-05-09 21:45:04 +00002321 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002322 s390_disasm(ENC3(MNM, GPR, SDXB), "llgh", r1, dh2, dl2, x2, b2);
2323
2324 return emit_RXY(p, 0xe30000000091ULL, r1, x2, b2, dl2, dh2);
2325}
2326
2327
sewardj9d31dfd2011-03-15 12:36:44 +00002328static UChar *
sewardj2019a972011-03-07 16:04:07 +00002329s390_emit_LLILF(UChar *p, UChar r1, UInt i2)
2330{
sewardj652b56a2011-04-13 15:38:17 +00002331 vassert(s390_host_has_eimm);
2332
sewardj7ee97522011-05-09 21:45:04 +00002333 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002334 s390_disasm(ENC3(MNM, GPR, UINT), "llilf", r1, i2);
2335
2336 return emit_RIL(p, 0xc00f00000000ULL, r1, i2);
2337}
2338
2339
sewardj9d31dfd2011-03-15 12:36:44 +00002340static UChar *
sewardj2019a972011-03-07 16:04:07 +00002341s390_emit_LLILH(UChar *p, UChar r1, UShort i2)
2342{
sewardj7ee97522011-05-09 21:45:04 +00002343 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002344 s390_disasm(ENC3(MNM, GPR, UINT), "llilh", r1, i2);
2345
2346 return emit_RI(p, 0xa50e0000, r1, i2);
2347}
2348
2349
sewardj9d31dfd2011-03-15 12:36:44 +00002350static UChar *
sewardj2019a972011-03-07 16:04:07 +00002351s390_emit_LLILL(UChar *p, UChar r1, UShort i2)
2352{
sewardj7ee97522011-05-09 21:45:04 +00002353 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002354 s390_disasm(ENC3(MNM, GPR, UINT), "llill", r1, i2);
2355
2356 return emit_RI(p, 0xa50f0000, r1, i2);
2357}
2358
2359
sewardj9d31dfd2011-03-15 12:36:44 +00002360static UChar *
sewardj2019a972011-03-07 16:04:07 +00002361s390_emit_MR(UChar *p, UChar r1, UChar r2)
2362{
sewardj7ee97522011-05-09 21:45:04 +00002363 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002364 s390_disasm(ENC3(MNM, GPR, GPR), "mr", r1, r2);
2365
2366 return emit_RR(p, 0x1c00, r1, r2);
2367}
2368
2369
sewardj9d31dfd2011-03-15 12:36:44 +00002370static UChar *
sewardj2019a972011-03-07 16:04:07 +00002371s390_emit_M(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2372{
sewardj7ee97522011-05-09 21:45:04 +00002373 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002374 s390_disasm(ENC3(MNM, GPR, UDXB), "m", r1, d2, x2, b2);
2375
2376 return emit_RX(p, 0x5c000000, r1, x2, b2, d2);
2377}
2378
2379
sewardj9d31dfd2011-03-15 12:36:44 +00002380static UChar *
sewardj2019a972011-03-07 16:04:07 +00002381s390_emit_MFY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2382{
sewardj652b56a2011-04-13 15:38:17 +00002383 vassert(s390_host_has_gie);
2384
sewardj7ee97522011-05-09 21:45:04 +00002385 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002386 s390_disasm(ENC3(MNM, GPR, SDXB), "mfy", r1, dh2, dl2, x2, b2);
2387
2388 return emit_RXY(p, 0xe3000000005cULL, r1, x2, b2, dl2, dh2);
2389}
2390
2391
sewardj9d31dfd2011-03-15 12:36:44 +00002392static UChar *
sewardj2019a972011-03-07 16:04:07 +00002393s390_emit_MH(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2394{
sewardj7ee97522011-05-09 21:45:04 +00002395 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002396 s390_disasm(ENC3(MNM, GPR, UDXB), "mh", r1, d2, x2, b2);
2397
2398 return emit_RX(p, 0x4c000000, r1, x2, b2, d2);
2399}
2400
2401
sewardj9d31dfd2011-03-15 12:36:44 +00002402static UChar *
sewardj2019a972011-03-07 16:04:07 +00002403s390_emit_MHY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2404{
sewardj652b56a2011-04-13 15:38:17 +00002405 vassert(s390_host_has_gie);
2406
sewardj7ee97522011-05-09 21:45:04 +00002407 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002408 s390_disasm(ENC3(MNM, GPR, SDXB), "mhy", r1, dh2, dl2, x2, b2);
2409
2410 return emit_RXY(p, 0xe3000000007cULL, r1, x2, b2, dl2, dh2);
2411}
2412
2413
sewardj9d31dfd2011-03-15 12:36:44 +00002414static UChar *
sewardj2019a972011-03-07 16:04:07 +00002415s390_emit_MHI(UChar *p, UChar r1, UShort i2)
2416{
sewardj7ee97522011-05-09 21:45:04 +00002417 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002418 s390_disasm(ENC3(MNM, GPR, INT), "mhi", r1, (Int)(Short)i2);
2419
2420 return emit_RI(p, 0xa70c0000, r1, i2);
2421}
2422
2423
sewardj9d31dfd2011-03-15 12:36:44 +00002424static UChar *
sewardj2019a972011-03-07 16:04:07 +00002425s390_emit_MLR(UChar *p, UChar r1, UChar r2)
2426{
sewardj7ee97522011-05-09 21:45:04 +00002427 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002428 s390_disasm(ENC3(MNM, GPR, GPR), "mlr", r1, r2);
2429
2430 return emit_RRE(p, 0xb9960000, r1, r2);
2431}
2432
2433
sewardj9d31dfd2011-03-15 12:36:44 +00002434static UChar *
sewardj2019a972011-03-07 16:04:07 +00002435s390_emit_MLGR(UChar *p, UChar r1, UChar r2)
2436{
sewardj7ee97522011-05-09 21:45:04 +00002437 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002438 s390_disasm(ENC3(MNM, GPR, GPR), "mlgr", r1, r2);
2439
2440 return emit_RRE(p, 0xb9860000, r1, r2);
2441}
2442
2443
sewardj9d31dfd2011-03-15 12:36:44 +00002444static UChar *
sewardj2019a972011-03-07 16:04:07 +00002445s390_emit_ML(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2446{
sewardj652b56a2011-04-13 15:38:17 +00002447 vassert(s390_host_has_ldisp || dh2 == 0);
2448
sewardj7ee97522011-05-09 21:45:04 +00002449 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002450 s390_disasm(ENC3(MNM, GPR, SDXB), "ml", r1, dh2, dl2, x2, b2);
2451
2452 return emit_RXY(p, 0xe30000000096ULL, r1, x2, b2, dl2, dh2);
2453}
2454
2455
sewardj9d31dfd2011-03-15 12:36:44 +00002456static UChar *
sewardj2019a972011-03-07 16:04:07 +00002457s390_emit_MLG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2458{
sewardj652b56a2011-04-13 15:38:17 +00002459 vassert(s390_host_has_ldisp || dh2 == 0);
2460
sewardj7ee97522011-05-09 21:45:04 +00002461 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002462 s390_disasm(ENC3(MNM, GPR, SDXB), "mlg", r1, dh2, dl2, x2, b2);
2463
2464 return emit_RXY(p, 0xe30000000086ULL, r1, x2, b2, dl2, dh2);
2465}
2466
2467
sewardj9d31dfd2011-03-15 12:36:44 +00002468static UChar *
sewardj2019a972011-03-07 16:04:07 +00002469s390_emit_MSR(UChar *p, UChar r1, UChar r2)
2470{
sewardj7ee97522011-05-09 21:45:04 +00002471 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002472 s390_disasm(ENC3(MNM, GPR, GPR), "msr", r1, r2);
2473
2474 return emit_RRE(p, 0xb2520000, r1, r2);
2475}
2476
2477
sewardj9d31dfd2011-03-15 12:36:44 +00002478static UChar *
sewardj2019a972011-03-07 16:04:07 +00002479s390_emit_MSGR(UChar *p, UChar r1, UChar r2)
2480{
sewardj7ee97522011-05-09 21:45:04 +00002481 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002482 s390_disasm(ENC3(MNM, GPR, GPR), "msgr", r1, r2);
2483
2484 return emit_RRE(p, 0xb90c0000, r1, r2);
2485}
2486
2487
sewardj9d31dfd2011-03-15 12:36:44 +00002488static UChar *
sewardj2019a972011-03-07 16:04:07 +00002489s390_emit_MS(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2490{
sewardj7ee97522011-05-09 21:45:04 +00002491 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002492 s390_disasm(ENC3(MNM, GPR, UDXB), "ms", r1, d2, x2, b2);
2493
2494 return emit_RX(p, 0x71000000, r1, x2, b2, d2);
2495}
2496
2497
sewardj9d31dfd2011-03-15 12:36:44 +00002498static UChar *
sewardj2019a972011-03-07 16:04:07 +00002499s390_emit_MSY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2500{
sewardj652b56a2011-04-13 15:38:17 +00002501 vassert(s390_host_has_ldisp);
2502
sewardj7ee97522011-05-09 21:45:04 +00002503 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002504 s390_disasm(ENC3(MNM, GPR, SDXB), "msy", r1, dh2, dl2, x2, b2);
2505
2506 return emit_RXY(p, 0xe30000000051ULL, r1, x2, b2, dl2, dh2);
2507}
2508
2509
sewardj9d31dfd2011-03-15 12:36:44 +00002510static UChar *
sewardj2019a972011-03-07 16:04:07 +00002511s390_emit_MSG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2512{
sewardj652b56a2011-04-13 15:38:17 +00002513 vassert(s390_host_has_ldisp || dh2 == 0);
2514
sewardj7ee97522011-05-09 21:45:04 +00002515 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002516 s390_disasm(ENC3(MNM, GPR, SDXB), "msg", r1, dh2, dl2, x2, b2);
2517
2518 return emit_RXY(p, 0xe3000000000cULL, r1, x2, b2, dl2, dh2);
2519}
2520
2521
sewardj9d31dfd2011-03-15 12:36:44 +00002522static UChar *
sewardj2019a972011-03-07 16:04:07 +00002523s390_emit_MSFI(UChar *p, UChar r1, UInt i2)
2524{
sewardj652b56a2011-04-13 15:38:17 +00002525 vassert(s390_host_has_gie);
2526
sewardj7ee97522011-05-09 21:45:04 +00002527 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002528 s390_disasm(ENC3(MNM, GPR, INT), "msfi", r1, i2);
2529
2530 return emit_RIL(p, 0xc20100000000ULL, r1, i2);
2531}
2532
2533
sewardj9d31dfd2011-03-15 12:36:44 +00002534static UChar *
sewardj2019a972011-03-07 16:04:07 +00002535s390_emit_MSGFI(UChar *p, UChar r1, UInt i2)
2536{
sewardj652b56a2011-04-13 15:38:17 +00002537 vassert(s390_host_has_gie);
2538
sewardj7ee97522011-05-09 21:45:04 +00002539 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002540 s390_disasm(ENC3(MNM, GPR, INT), "msgfi", r1, i2);
2541
2542 return emit_RIL(p, 0xc20000000000ULL, r1, i2);
2543}
2544
2545
sewardj9d31dfd2011-03-15 12:36:44 +00002546static UChar *
sewardj2019a972011-03-07 16:04:07 +00002547s390_emit_OR(UChar *p, UChar r1, UChar r2)
2548{
sewardj7ee97522011-05-09 21:45:04 +00002549 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002550 s390_disasm(ENC3(MNM, GPR, GPR), "or", r1, r2);
2551
2552 return emit_RR(p, 0x1600, r1, r2);
2553}
2554
2555
sewardj9d31dfd2011-03-15 12:36:44 +00002556static UChar *
sewardj2019a972011-03-07 16:04:07 +00002557s390_emit_OGR(UChar *p, UChar r1, UChar r2)
2558{
sewardj7ee97522011-05-09 21:45:04 +00002559 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002560 s390_disasm(ENC3(MNM, GPR, GPR), "ogr", r1, r2);
2561
2562 return emit_RRE(p, 0xb9810000, r1, r2);
2563}
2564
2565
sewardj9d31dfd2011-03-15 12:36:44 +00002566static UChar *
sewardj2019a972011-03-07 16:04:07 +00002567s390_emit_O(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2568{
sewardj7ee97522011-05-09 21:45:04 +00002569 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002570 s390_disasm(ENC3(MNM, GPR, UDXB), "o", r1, d2, x2, b2);
2571
2572 return emit_RX(p, 0x56000000, r1, x2, b2, d2);
2573}
2574
2575
sewardj9d31dfd2011-03-15 12:36:44 +00002576static UChar *
sewardj2019a972011-03-07 16:04:07 +00002577s390_emit_OY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2578{
sewardj652b56a2011-04-13 15:38:17 +00002579 vassert(s390_host_has_ldisp);
2580
sewardj7ee97522011-05-09 21:45:04 +00002581 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002582 s390_disasm(ENC3(MNM, GPR, SDXB), "oy", r1, dh2, dl2, x2, b2);
2583
2584 return emit_RXY(p, 0xe30000000056ULL, r1, x2, b2, dl2, dh2);
2585}
2586
2587
sewardj9d31dfd2011-03-15 12:36:44 +00002588static UChar *
sewardj2019a972011-03-07 16:04:07 +00002589s390_emit_OG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2590{
sewardj652b56a2011-04-13 15:38:17 +00002591 vassert(s390_host_has_ldisp || dh2 == 0);
2592
sewardj7ee97522011-05-09 21:45:04 +00002593 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002594 s390_disasm(ENC3(MNM, GPR, SDXB), "og", r1, dh2, dl2, x2, b2);
2595
2596 return emit_RXY(p, 0xe30000000081ULL, r1, x2, b2, dl2, dh2);
2597}
2598
2599
sewardj9d31dfd2011-03-15 12:36:44 +00002600static UChar *
sewardj2019a972011-03-07 16:04:07 +00002601s390_emit_OIHF(UChar *p, UChar r1, UInt i2)
2602{
sewardj652b56a2011-04-13 15:38:17 +00002603 vassert(s390_host_has_eimm);
2604
sewardj7ee97522011-05-09 21:45:04 +00002605 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002606 s390_disasm(ENC3(MNM, GPR, UINT), "oihf", r1, i2);
2607
2608 return emit_RIL(p, 0xc00c00000000ULL, r1, i2);
2609}
2610
2611
sewardj9d31dfd2011-03-15 12:36:44 +00002612static UChar *
sewardj2019a972011-03-07 16:04:07 +00002613s390_emit_OILF(UChar *p, UChar r1, UInt i2)
2614{
sewardj652b56a2011-04-13 15:38:17 +00002615 vassert(s390_host_has_eimm);
2616
sewardj7ee97522011-05-09 21:45:04 +00002617 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002618 s390_disasm(ENC3(MNM, GPR, UINT), "oilf", r1, i2);
2619
2620 return emit_RIL(p, 0xc00d00000000ULL, r1, i2);
2621}
2622
2623
sewardj9d31dfd2011-03-15 12:36:44 +00002624static UChar *
sewardj2019a972011-03-07 16:04:07 +00002625s390_emit_OILL(UChar *p, UChar r1, UShort i2)
2626{
sewardj7ee97522011-05-09 21:45:04 +00002627 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002628 s390_disasm(ENC3(MNM, GPR, UINT), "oill", r1, i2);
2629
2630 return emit_RI(p, 0xa50b0000, r1, i2);
2631}
2632
2633
sewardj9d31dfd2011-03-15 12:36:44 +00002634static UChar *
sewardj3c49aaa2011-04-05 14:00:37 +00002635s390_emit_SLL(UChar *p, UChar r1, UChar b2, UShort d2)
sewardj2019a972011-03-07 16:04:07 +00002636{
sewardj7ee97522011-05-09 21:45:04 +00002637 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002638 s390_disasm(ENC3(MNM, GPR, UDXB), "sll", r1, d2, 0, b2);
2639
sewardj3c49aaa2011-04-05 14:00:37 +00002640 return emit_RS(p, 0x89000000, r1, 0, b2, d2);
sewardj2019a972011-03-07 16:04:07 +00002641}
2642
2643
sewardj9d31dfd2011-03-15 12:36:44 +00002644static UChar *
sewardj2019a972011-03-07 16:04:07 +00002645s390_emit_SLLG(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
2646{
sewardj652b56a2011-04-13 15:38:17 +00002647 vassert(s390_host_has_ldisp || dh2 == 0);
2648
sewardj7ee97522011-05-09 21:45:04 +00002649 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002650 s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "sllg", r1, r3, dh2, dl2, 0, b2);
2651
2652 return emit_RSY(p, 0xeb000000000dULL, r1, r3, b2, dl2, dh2);
2653}
2654
2655
sewardj9d31dfd2011-03-15 12:36:44 +00002656static UChar *
sewardj3c49aaa2011-04-05 14:00:37 +00002657s390_emit_SRA(UChar *p, UChar r1, UChar b2, UShort d2)
sewardj2019a972011-03-07 16:04:07 +00002658{
sewardj7ee97522011-05-09 21:45:04 +00002659 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002660 s390_disasm(ENC3(MNM, GPR, UDXB), "sra", r1, d2, 0, b2);
2661
sewardj3c49aaa2011-04-05 14:00:37 +00002662 return emit_RS(p, 0x8a000000, r1, 0, b2, d2);
sewardj2019a972011-03-07 16:04:07 +00002663}
2664
2665
sewardj9d31dfd2011-03-15 12:36:44 +00002666static UChar *
sewardj2019a972011-03-07 16:04:07 +00002667s390_emit_SRAG(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
2668{
sewardj652b56a2011-04-13 15:38:17 +00002669 vassert(s390_host_has_ldisp || dh2 == 0);
2670
sewardj7ee97522011-05-09 21:45:04 +00002671 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002672 s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "srag", r1, r3, dh2, dl2, 0, b2);
2673
2674 return emit_RSY(p, 0xeb000000000aULL, r1, r3, b2, dl2, dh2);
2675}
2676
2677
sewardj9d31dfd2011-03-15 12:36:44 +00002678static UChar *
sewardj3c49aaa2011-04-05 14:00:37 +00002679s390_emit_SRL(UChar *p, UChar r1, UChar b2, UShort d2)
sewardj2019a972011-03-07 16:04:07 +00002680{
sewardj7ee97522011-05-09 21:45:04 +00002681 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002682 s390_disasm(ENC3(MNM, GPR, UDXB), "srl", r1, d2, 0, b2);
2683
sewardj3c49aaa2011-04-05 14:00:37 +00002684 return emit_RS(p, 0x88000000, r1, 0, b2, d2);
sewardj2019a972011-03-07 16:04:07 +00002685}
2686
2687
sewardj9d31dfd2011-03-15 12:36:44 +00002688static UChar *
sewardj2019a972011-03-07 16:04:07 +00002689s390_emit_SRLG(UChar *p, UChar r1, UChar r3, UChar b2, UShort dl2, UChar dh2)
2690{
sewardj652b56a2011-04-13 15:38:17 +00002691 vassert(s390_host_has_ldisp || dh2 == 0);
2692
sewardj7ee97522011-05-09 21:45:04 +00002693 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002694 s390_disasm(ENC4(MNM, GPR, GPR, SDXB), "srlg", r1, r3, dh2, dl2, 0, b2);
2695
2696 return emit_RSY(p, 0xeb000000000cULL, r1, r3, b2, dl2, dh2);
2697}
2698
2699
sewardj9d31dfd2011-03-15 12:36:44 +00002700static UChar *
sewardj2019a972011-03-07 16:04:07 +00002701s390_emit_ST(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2702{
sewardj7ee97522011-05-09 21:45:04 +00002703 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002704 s390_disasm(ENC3(MNM, GPR, UDXB), "st", r1, d2, x2, b2);
2705
2706 return emit_RX(p, 0x50000000, r1, x2, b2, d2);
2707}
2708
2709
sewardj9d31dfd2011-03-15 12:36:44 +00002710static UChar *
sewardj2019a972011-03-07 16:04:07 +00002711s390_emit_STY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2712{
sewardj652b56a2011-04-13 15:38:17 +00002713 vassert(s390_host_has_ldisp);
2714
sewardj7ee97522011-05-09 21:45:04 +00002715 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002716 s390_disasm(ENC3(MNM, GPR, SDXB), "sty", r1, dh2, dl2, x2, b2);
2717
2718 return emit_RXY(p, 0xe30000000050ULL, r1, x2, b2, dl2, dh2);
2719}
2720
2721
sewardj9d31dfd2011-03-15 12:36:44 +00002722static UChar *
sewardj2019a972011-03-07 16:04:07 +00002723s390_emit_STG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2724{
sewardj652b56a2011-04-13 15:38:17 +00002725 vassert(s390_host_has_ldisp || dh2 == 0);
2726
sewardj7ee97522011-05-09 21:45:04 +00002727 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002728 s390_disasm(ENC3(MNM, GPR, SDXB), "stg", r1, dh2, dl2, x2, b2);
2729
2730 return emit_RXY(p, 0xe30000000024ULL, r1, x2, b2, dl2, dh2);
2731}
2732
2733
sewardj9d31dfd2011-03-15 12:36:44 +00002734static UChar *
sewardj2019a972011-03-07 16:04:07 +00002735s390_emit_STC(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2736{
sewardj7ee97522011-05-09 21:45:04 +00002737 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002738 s390_disasm(ENC3(MNM, GPR, UDXB), "stc", r1, d2, x2, b2);
2739
2740 return emit_RX(p, 0x42000000, r1, x2, b2, d2);
2741}
2742
2743
sewardj9d31dfd2011-03-15 12:36:44 +00002744static UChar *
sewardj2019a972011-03-07 16:04:07 +00002745s390_emit_STCY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2746{
sewardj652b56a2011-04-13 15:38:17 +00002747 vassert(s390_host_has_ldisp);
2748
sewardj7ee97522011-05-09 21:45:04 +00002749 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002750 s390_disasm(ENC3(MNM, GPR, SDXB), "stcy", r1, dh2, dl2, x2, b2);
2751
2752 return emit_RXY(p, 0xe30000000072ULL, r1, x2, b2, dl2, dh2);
2753}
2754
2755
sewardj9d31dfd2011-03-15 12:36:44 +00002756static UChar *
sewardj2019a972011-03-07 16:04:07 +00002757s390_emit_STH(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2758{
sewardj7ee97522011-05-09 21:45:04 +00002759 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002760 s390_disasm(ENC3(MNM, GPR, UDXB), "sth", r1, d2, x2, b2);
2761
2762 return emit_RX(p, 0x40000000, r1, x2, b2, d2);
2763}
2764
2765
sewardj9d31dfd2011-03-15 12:36:44 +00002766static UChar *
sewardj2019a972011-03-07 16:04:07 +00002767s390_emit_STHY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2768{
sewardj652b56a2011-04-13 15:38:17 +00002769 vassert(s390_host_has_ldisp);
2770
sewardj7ee97522011-05-09 21:45:04 +00002771 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002772 s390_disasm(ENC3(MNM, GPR, SDXB), "sthy", r1, dh2, dl2, x2, b2);
2773
2774 return emit_RXY(p, 0xe30000000070ULL, r1, x2, b2, dl2, dh2);
2775}
2776
2777
sewardj9d31dfd2011-03-15 12:36:44 +00002778static UChar *
sewardj2019a972011-03-07 16:04:07 +00002779s390_emit_SR(UChar *p, UChar r1, UChar r2)
2780{
sewardj7ee97522011-05-09 21:45:04 +00002781 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002782 s390_disasm(ENC3(MNM, GPR, GPR), "sr", r1, r2);
2783
2784 return emit_RR(p, 0x1b00, r1, r2);
2785}
2786
2787
sewardj9d31dfd2011-03-15 12:36:44 +00002788static UChar *
sewardj2019a972011-03-07 16:04:07 +00002789s390_emit_SGR(UChar *p, UChar r1, UChar r2)
2790{
sewardj7ee97522011-05-09 21:45:04 +00002791 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002792 s390_disasm(ENC3(MNM, GPR, GPR), "sgr", r1, r2);
2793
2794 return emit_RRE(p, 0xb9090000, r1, r2);
2795}
2796
2797
sewardj9d31dfd2011-03-15 12:36:44 +00002798static UChar *
sewardj2019a972011-03-07 16:04:07 +00002799s390_emit_S(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2800{
sewardj7ee97522011-05-09 21:45:04 +00002801 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002802 s390_disasm(ENC3(MNM, GPR, UDXB), "s", r1, d2, x2, b2);
2803
2804 return emit_RX(p, 0x5b000000, r1, x2, b2, d2);
2805}
2806
2807
sewardj9d31dfd2011-03-15 12:36:44 +00002808static UChar *
sewardj2019a972011-03-07 16:04:07 +00002809s390_emit_SY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2810{
sewardj652b56a2011-04-13 15:38:17 +00002811 vassert(s390_host_has_ldisp);
2812
sewardj7ee97522011-05-09 21:45:04 +00002813 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002814 s390_disasm(ENC3(MNM, GPR, SDXB), "sy", r1, dh2, dl2, x2, b2);
2815
2816 return emit_RXY(p, 0xe3000000005bULL, r1, x2, b2, dl2, dh2);
2817}
2818
2819
sewardj9d31dfd2011-03-15 12:36:44 +00002820static UChar *
sewardj2019a972011-03-07 16:04:07 +00002821s390_emit_SG(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2822{
sewardj652b56a2011-04-13 15:38:17 +00002823 vassert(s390_host_has_ldisp || dh2 == 0);
2824
sewardj7ee97522011-05-09 21:45:04 +00002825 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002826 s390_disasm(ENC3(MNM, GPR, SDXB), "sg", r1, dh2, dl2, x2, b2);
2827
2828 return emit_RXY(p, 0xe30000000009ULL, r1, x2, b2, dl2, dh2);
2829}
2830
2831
sewardj9d31dfd2011-03-15 12:36:44 +00002832static UChar *
sewardj2019a972011-03-07 16:04:07 +00002833s390_emit_SH(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2834{
sewardj7ee97522011-05-09 21:45:04 +00002835 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002836 s390_disasm(ENC3(MNM, GPR, UDXB), "sh", r1, d2, x2, b2);
2837
2838 return emit_RX(p, 0x4b000000, r1, x2, b2, d2);
2839}
2840
2841
sewardj9d31dfd2011-03-15 12:36:44 +00002842static UChar *
sewardj2019a972011-03-07 16:04:07 +00002843s390_emit_SHY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2844{
sewardj652b56a2011-04-13 15:38:17 +00002845 vassert(s390_host_has_ldisp);
2846
sewardj7ee97522011-05-09 21:45:04 +00002847 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002848 s390_disasm(ENC3(MNM, GPR, SDXB), "shy", r1, dh2, dl2, x2, b2);
2849
2850 return emit_RXY(p, 0xe3000000007bULL, r1, x2, b2, dl2, dh2);
2851}
2852
2853
sewardj9d31dfd2011-03-15 12:36:44 +00002854static UChar *
sewardj2019a972011-03-07 16:04:07 +00002855s390_emit_SLFI(UChar *p, UChar r1, UInt i2)
2856{
sewardj652b56a2011-04-13 15:38:17 +00002857 vassert(s390_host_has_eimm);
2858
sewardj7ee97522011-05-09 21:45:04 +00002859 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002860 s390_disasm(ENC3(MNM, GPR, UINT), "slfi", r1, i2);
2861
2862 return emit_RIL(p, 0xc20500000000ULL, r1, i2);
2863}
2864
2865
sewardj9d31dfd2011-03-15 12:36:44 +00002866static UChar *
sewardjb13a92a2011-04-13 14:44:29 +00002867s390_emit_SLGFI(UChar *p, UChar r1, UInt i2)
2868{
sewardj7ee97522011-05-09 21:45:04 +00002869 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardjb13a92a2011-04-13 14:44:29 +00002870 s390_disasm(ENC3(MNM, GPR, UINT), "slgfi", r1, i2);
2871
2872 return emit_RIL(p, 0xc20400000000ULL, r1, i2);
2873}
2874
2875
2876static UChar *
sewardj2019a972011-03-07 16:04:07 +00002877s390_emit_LDR(UChar *p, UChar r1, UChar r2)
2878{
sewardj7ee97522011-05-09 21:45:04 +00002879 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002880 s390_disasm(ENC3(MNM, FPR, FPR), "ldr", r1, r2);
2881
2882 return emit_RR(p, 0x2800, r1, r2);
2883}
2884
2885
sewardj9d31dfd2011-03-15 12:36:44 +00002886static UChar *
sewardj2019a972011-03-07 16:04:07 +00002887s390_emit_LE(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2888{
sewardj7ee97522011-05-09 21:45:04 +00002889 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002890 s390_disasm(ENC3(MNM, FPR, UDXB), "le", r1, d2, x2, b2);
2891
2892 return emit_RX(p, 0x78000000, r1, x2, b2, d2);
2893}
2894
2895
sewardj9d31dfd2011-03-15 12:36:44 +00002896static UChar *
sewardj2019a972011-03-07 16:04:07 +00002897s390_emit_LD(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2898{
sewardj7ee97522011-05-09 21:45:04 +00002899 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002900 s390_disasm(ENC3(MNM, FPR, UDXB), "ld", r1, d2, x2, b2);
2901
2902 return emit_RX(p, 0x68000000, r1, x2, b2, d2);
2903}
2904
2905
sewardj9d31dfd2011-03-15 12:36:44 +00002906static UChar *
sewardj2019a972011-03-07 16:04:07 +00002907s390_emit_LEY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2908{
sewardj652b56a2011-04-13 15:38:17 +00002909 vassert(s390_host_has_ldisp);
2910
sewardj7ee97522011-05-09 21:45:04 +00002911 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002912 s390_disasm(ENC3(MNM, FPR, SDXB), "ley", r1, dh2, dl2, x2, b2);
2913
2914 return emit_RXY(p, 0xed0000000064ULL, r1, x2, b2, dl2, dh2);
2915}
2916
2917
sewardj9d31dfd2011-03-15 12:36:44 +00002918static UChar *
sewardj2019a972011-03-07 16:04:07 +00002919s390_emit_LDY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
2920{
sewardj652b56a2011-04-13 15:38:17 +00002921 vassert(s390_host_has_ldisp);
2922
sewardj7ee97522011-05-09 21:45:04 +00002923 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002924 s390_disasm(ENC3(MNM, FPR, SDXB), "ldy", r1, dh2, dl2, x2, b2);
2925
2926 return emit_RXY(p, 0xed0000000065ULL, r1, x2, b2, dl2, dh2);
2927}
2928
2929
sewardj9d31dfd2011-03-15 12:36:44 +00002930static UChar *
sewardj2019a972011-03-07 16:04:07 +00002931s390_emit_LFPC(UChar *p, UChar b2, UShort d2)
2932{
sewardj7ee97522011-05-09 21:45:04 +00002933 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002934 s390_disasm(ENC2(MNM, UDXB), "lfpc", d2, 0, b2);
2935
2936 return emit_S(p, 0xb29d0000, b2, d2);
2937}
2938
2939
sewardj9d31dfd2011-03-15 12:36:44 +00002940static UChar *
sewardj2019a972011-03-07 16:04:07 +00002941s390_emit_LDGR(UChar *p, UChar r1, UChar r2)
2942{
sewardjd07b8562011-04-27 11:58:22 +00002943 vassert(s390_host_has_fgx);
2944
sewardj7ee97522011-05-09 21:45:04 +00002945 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002946 s390_disasm(ENC3(MNM, FPR, GPR), "ldgr", r1, r2);
2947
2948 return emit_RRE(p, 0xb3c10000, r1, r2);
2949}
2950
2951
sewardj9d31dfd2011-03-15 12:36:44 +00002952static UChar *
sewardj2019a972011-03-07 16:04:07 +00002953s390_emit_LGDR(UChar *p, UChar r1, UChar r2)
2954{
sewardjd07b8562011-04-27 11:58:22 +00002955 vassert(s390_host_has_fgx);
2956
sewardj7ee97522011-05-09 21:45:04 +00002957 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002958 s390_disasm(ENC3(MNM, GPR, FPR), "lgdr", r1, r2);
2959
2960 return emit_RRE(p, 0xb3cd0000, r1, r2);
2961}
2962
2963
sewardj9d31dfd2011-03-15 12:36:44 +00002964static UChar *
sewardj2019a972011-03-07 16:04:07 +00002965s390_emit_LZER(UChar *p, UChar r1, UChar r2)
2966{
sewardj7ee97522011-05-09 21:45:04 +00002967 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002968 s390_disasm(ENC2(MNM, FPR), "lzer", r1);
2969
2970 return emit_RRE(p, 0xb3740000, r1, r2);
2971}
2972
2973
sewardj9d31dfd2011-03-15 12:36:44 +00002974static UChar *
sewardj2019a972011-03-07 16:04:07 +00002975s390_emit_LZDR(UChar *p, UChar r1, UChar r2)
2976{
sewardj7ee97522011-05-09 21:45:04 +00002977 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002978 s390_disasm(ENC2(MNM, FPR), "lzdr", r1);
2979
2980 return emit_RRE(p, 0xb3750000, r1, r2);
2981}
2982
2983
sewardj9d31dfd2011-03-15 12:36:44 +00002984static UChar *
sewardj2019a972011-03-07 16:04:07 +00002985s390_emit_SFPC(UChar *p, UChar r1, UChar r2)
2986{
sewardj7ee97522011-05-09 21:45:04 +00002987 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002988 s390_disasm(ENC2(MNM, GPR), "sfpc", r1);
2989
2990 return emit_RRE(p, 0xb3840000, r1, r2);
2991}
2992
2993
sewardj9d31dfd2011-03-15 12:36:44 +00002994static UChar *
sewardj2019a972011-03-07 16:04:07 +00002995s390_emit_STE(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
2996{
sewardj7ee97522011-05-09 21:45:04 +00002997 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00002998 s390_disasm(ENC3(MNM, FPR, UDXB), "ste", r1, d2, x2, b2);
2999
3000 return emit_RX(p, 0x70000000, r1, x2, b2, d2);
3001}
3002
3003
sewardj9d31dfd2011-03-15 12:36:44 +00003004static UChar *
sewardj2019a972011-03-07 16:04:07 +00003005s390_emit_STD(UChar *p, UChar r1, UChar x2, UChar b2, UShort d2)
3006{
sewardj7ee97522011-05-09 21:45:04 +00003007 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003008 s390_disasm(ENC3(MNM, FPR, UDXB), "std", r1, d2, x2, b2);
3009
3010 return emit_RX(p, 0x60000000, r1, x2, b2, d2);
3011}
3012
3013
sewardj9d31dfd2011-03-15 12:36:44 +00003014static UChar *
sewardj2019a972011-03-07 16:04:07 +00003015s390_emit_STEY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
3016{
sewardj652b56a2011-04-13 15:38:17 +00003017 vassert(s390_host_has_ldisp);
3018
sewardj7ee97522011-05-09 21:45:04 +00003019 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003020 s390_disasm(ENC3(MNM, FPR, SDXB), "stey", r1, dh2, dl2, x2, b2);
3021
3022 return emit_RXY(p, 0xed0000000066ULL, r1, x2, b2, dl2, dh2);
3023}
3024
3025
sewardj9d31dfd2011-03-15 12:36:44 +00003026static UChar *
sewardj2019a972011-03-07 16:04:07 +00003027s390_emit_STDY(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
3028{
sewardj652b56a2011-04-13 15:38:17 +00003029 vassert(s390_host_has_ldisp);
3030
sewardj7ee97522011-05-09 21:45:04 +00003031 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003032 s390_disasm(ENC3(MNM, FPR, SDXB), "stdy", r1, dh2, dl2, x2, b2);
3033
3034 return emit_RXY(p, 0xed0000000067ULL, r1, x2, b2, dl2, dh2);
3035}
3036
3037
sewardj9d31dfd2011-03-15 12:36:44 +00003038static UChar *
sewardj2019a972011-03-07 16:04:07 +00003039s390_emit_STFPC(UChar *p, UChar b2, UShort d2)
3040{
sewardj7ee97522011-05-09 21:45:04 +00003041 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003042 s390_disasm(ENC2(MNM, UDXB), "stfpc", d2, 0, b2);
3043
3044 return emit_S(p, 0xb29c0000, b2, d2);
3045}
3046
3047
sewardj9d31dfd2011-03-15 12:36:44 +00003048static UChar *
sewardj2019a972011-03-07 16:04:07 +00003049s390_emit_AEBR(UChar *p, UChar r1, UChar r2)
3050{
sewardj7ee97522011-05-09 21:45:04 +00003051 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003052 s390_disasm(ENC3(MNM, FPR, FPR), "aebr", r1, r2);
3053
3054 return emit_RRE(p, 0xb30a0000, r1, r2);
3055}
3056
3057
sewardj9d31dfd2011-03-15 12:36:44 +00003058static UChar *
sewardj2019a972011-03-07 16:04:07 +00003059s390_emit_ADBR(UChar *p, UChar r1, UChar r2)
3060{
sewardj7ee97522011-05-09 21:45:04 +00003061 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003062 s390_disasm(ENC3(MNM, FPR, FPR), "adbr", r1, r2);
3063
3064 return emit_RRE(p, 0xb31a0000, r1, r2);
3065}
3066
3067
sewardj9d31dfd2011-03-15 12:36:44 +00003068static UChar *
sewardj2019a972011-03-07 16:04:07 +00003069s390_emit_AXBR(UChar *p, UChar r1, UChar r2)
3070{
sewardj7ee97522011-05-09 21:45:04 +00003071 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003072 s390_disasm(ENC3(MNM, FPR, FPR), "axbr", r1, r2);
3073
3074 return emit_RRE(p, 0xb34a0000, r1, r2);
3075}
3076
3077
sewardj9d31dfd2011-03-15 12:36:44 +00003078static UChar *
sewardj2019a972011-03-07 16:04:07 +00003079s390_emit_CEBR(UChar *p, UChar r1, UChar r2)
3080{
sewardj7ee97522011-05-09 21:45:04 +00003081 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003082 s390_disasm(ENC3(MNM, FPR, FPR), "cebr", r1, r2);
3083
3084 return emit_RRE(p, 0xb3090000, r1, r2);
3085}
3086
3087
sewardj9d31dfd2011-03-15 12:36:44 +00003088static UChar *
sewardj2019a972011-03-07 16:04:07 +00003089s390_emit_CDBR(UChar *p, UChar r1, UChar r2)
3090{
sewardj7ee97522011-05-09 21:45:04 +00003091 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003092 s390_disasm(ENC3(MNM, FPR, FPR), "cdbr", r1, r2);
3093
3094 return emit_RRE(p, 0xb3190000, r1, r2);
3095}
3096
3097
sewardj9d31dfd2011-03-15 12:36:44 +00003098static UChar *
sewardj2019a972011-03-07 16:04:07 +00003099s390_emit_CXBR(UChar *p, UChar r1, UChar r2)
3100{
sewardj7ee97522011-05-09 21:45:04 +00003101 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003102 s390_disasm(ENC3(MNM, FPR, FPR), "cxbr", r1, r2);
3103
3104 return emit_RRE(p, 0xb3490000, r1, r2);
3105}
3106
3107
sewardj9d31dfd2011-03-15 12:36:44 +00003108static UChar *
sewardj2019a972011-03-07 16:04:07 +00003109s390_emit_CEFBR(UChar *p, UChar r1, UChar r2)
3110{
sewardj7ee97522011-05-09 21:45:04 +00003111 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003112 s390_disasm(ENC3(MNM, FPR, GPR), "cefbr", r1, r2);
3113
3114 return emit_RRE(p, 0xb3940000, r1, r2);
3115}
3116
3117
sewardj9d31dfd2011-03-15 12:36:44 +00003118static UChar *
sewardj2019a972011-03-07 16:04:07 +00003119s390_emit_CDFBR(UChar *p, UChar r1, UChar r2)
3120{
sewardj7ee97522011-05-09 21:45:04 +00003121 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003122 s390_disasm(ENC3(MNM, FPR, GPR), "cdfbr", r1, r2);
3123
3124 return emit_RRE(p, 0xb3950000, r1, r2);
3125}
3126
3127
sewardj9d31dfd2011-03-15 12:36:44 +00003128static UChar *
sewardj2019a972011-03-07 16:04:07 +00003129s390_emit_CXFBR(UChar *p, UChar r1, UChar r2)
3130{
sewardj7ee97522011-05-09 21:45:04 +00003131 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003132 s390_disasm(ENC3(MNM, FPR, GPR), "cxfbr", r1, r2);
3133
3134 return emit_RRE(p, 0xb3960000, r1, r2);
3135}
3136
3137
sewardj9d31dfd2011-03-15 12:36:44 +00003138static UChar *
sewardj2019a972011-03-07 16:04:07 +00003139s390_emit_CEGBR(UChar *p, UChar r1, UChar r2)
3140{
sewardj7ee97522011-05-09 21:45:04 +00003141 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003142 s390_disasm(ENC3(MNM, FPR, GPR), "cegbr", r1, r2);
3143
3144 return emit_RRE(p, 0xb3a40000, r1, r2);
3145}
3146
3147
sewardj9d31dfd2011-03-15 12:36:44 +00003148static UChar *
sewardj2019a972011-03-07 16:04:07 +00003149s390_emit_CDGBR(UChar *p, UChar r1, UChar r2)
3150{
sewardj7ee97522011-05-09 21:45:04 +00003151 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003152 s390_disasm(ENC3(MNM, FPR, GPR), "cdgbr", r1, r2);
3153
3154 return emit_RRE(p, 0xb3a50000, r1, r2);
3155}
3156
3157
sewardj9d31dfd2011-03-15 12:36:44 +00003158static UChar *
sewardj2019a972011-03-07 16:04:07 +00003159s390_emit_CXGBR(UChar *p, UChar r1, UChar r2)
3160{
sewardj7ee97522011-05-09 21:45:04 +00003161 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003162 s390_disasm(ENC3(MNM, FPR, GPR), "cxgbr", r1, r2);
3163
3164 return emit_RRE(p, 0xb3a60000, r1, r2);
3165}
3166
3167
sewardj9d31dfd2011-03-15 12:36:44 +00003168static UChar *
sewardj2019a972011-03-07 16:04:07 +00003169s390_emit_CFEBR(UChar *p, UChar r3, UChar r1, UChar r2)
3170{
sewardj7ee97522011-05-09 21:45:04 +00003171 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003172 s390_disasm(ENC4(MNM, GPR, UINT, FPR), "cfebr", r1, r3, r2);
3173
3174 return emit_RRF3(p, 0xb3980000, r3, r1, r2);
3175}
3176
3177
sewardj9d31dfd2011-03-15 12:36:44 +00003178static UChar *
sewardj2019a972011-03-07 16:04:07 +00003179s390_emit_CFDBR(UChar *p, UChar r3, UChar r1, UChar r2)
3180{
sewardj7ee97522011-05-09 21:45:04 +00003181 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003182 s390_disasm(ENC4(MNM, GPR, UINT, FPR), "cfdbr", r1, r3, r2);
3183
3184 return emit_RRF3(p, 0xb3990000, r3, r1, r2);
3185}
3186
3187
sewardj9d31dfd2011-03-15 12:36:44 +00003188static UChar *
sewardj2019a972011-03-07 16:04:07 +00003189s390_emit_CFXBR(UChar *p, UChar r3, UChar r1, UChar r2)
3190{
sewardj7ee97522011-05-09 21:45:04 +00003191 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003192 s390_disasm(ENC4(MNM, GPR, UINT, FPR), "cfxbr", r1, r3, r2);
3193
3194 return emit_RRF3(p, 0xb39a0000, r3, r1, r2);
3195}
3196
3197
sewardj9d31dfd2011-03-15 12:36:44 +00003198static UChar *
sewardj2019a972011-03-07 16:04:07 +00003199s390_emit_CGEBR(UChar *p, UChar r3, UChar r1, UChar r2)
3200{
sewardj7ee97522011-05-09 21:45:04 +00003201 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003202 s390_disasm(ENC4(MNM, GPR, UINT, FPR), "cgebr", r1, r3, r2);
3203
3204 return emit_RRF3(p, 0xb3a80000, r3, r1, r2);
3205}
3206
3207
sewardj9d31dfd2011-03-15 12:36:44 +00003208static UChar *
sewardj2019a972011-03-07 16:04:07 +00003209s390_emit_CGDBR(UChar *p, UChar r3, UChar r1, UChar r2)
3210{
sewardj7ee97522011-05-09 21:45:04 +00003211 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003212 s390_disasm(ENC4(MNM, GPR, UINT, FPR), "cgdbr", r1, r3, r2);
3213
3214 return emit_RRF3(p, 0xb3a90000, r3, r1, r2);
3215}
3216
3217
sewardj9d31dfd2011-03-15 12:36:44 +00003218static UChar *
sewardj2019a972011-03-07 16:04:07 +00003219s390_emit_CGXBR(UChar *p, UChar r3, UChar r1, UChar r2)
3220{
sewardj7ee97522011-05-09 21:45:04 +00003221 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003222 s390_disasm(ENC4(MNM, GPR, UINT, FPR), "cgxbr", r1, r3, r2);
3223
3224 return emit_RRF3(p, 0xb3aa0000, r3, r1, r2);
3225}
3226
3227
sewardj9d31dfd2011-03-15 12:36:44 +00003228static UChar *
sewardj2019a972011-03-07 16:04:07 +00003229s390_emit_DEBR(UChar *p, UChar r1, UChar r2)
3230{
sewardj7ee97522011-05-09 21:45:04 +00003231 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003232 s390_disasm(ENC3(MNM, FPR, FPR), "debr", r1, r2);
3233
3234 return emit_RRE(p, 0xb30d0000, r1, r2);
3235}
3236
3237
sewardj9d31dfd2011-03-15 12:36:44 +00003238static UChar *
sewardj2019a972011-03-07 16:04:07 +00003239s390_emit_DDBR(UChar *p, UChar r1, UChar r2)
3240{
sewardj7ee97522011-05-09 21:45:04 +00003241 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003242 s390_disasm(ENC3(MNM, FPR, FPR), "ddbr", r1, r2);
3243
3244 return emit_RRE(p, 0xb31d0000, r1, r2);
3245}
3246
3247
sewardj9d31dfd2011-03-15 12:36:44 +00003248static UChar *
sewardj2019a972011-03-07 16:04:07 +00003249s390_emit_DXBR(UChar *p, UChar r1, UChar r2)
3250{
sewardj7ee97522011-05-09 21:45:04 +00003251 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003252 s390_disasm(ENC3(MNM, FPR, FPR), "dxbr", r1, r2);
3253
3254 return emit_RRE(p, 0xb34d0000, r1, r2);
3255}
3256
3257
sewardj9d31dfd2011-03-15 12:36:44 +00003258static UChar *
sewardj2019a972011-03-07 16:04:07 +00003259s390_emit_LCEBR(UChar *p, UChar r1, UChar r2)
3260{
sewardj7ee97522011-05-09 21:45:04 +00003261 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003262 s390_disasm(ENC3(MNM, FPR, FPR), "lcebr", r1, r2);
3263
3264 return emit_RRE(p, 0xb3030000, r1, r2);
3265}
3266
3267
sewardj9d31dfd2011-03-15 12:36:44 +00003268static UChar *
sewardj2019a972011-03-07 16:04:07 +00003269s390_emit_LCDBR(UChar *p, UChar r1, UChar r2)
3270{
sewardj7ee97522011-05-09 21:45:04 +00003271 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003272 s390_disasm(ENC3(MNM, FPR, FPR), "lcdbr", r1, r2);
3273
3274 return emit_RRE(p, 0xb3130000, r1, r2);
3275}
3276
3277
sewardj9d31dfd2011-03-15 12:36:44 +00003278static UChar *
sewardj2019a972011-03-07 16:04:07 +00003279s390_emit_LCXBR(UChar *p, UChar r1, UChar r2)
3280{
sewardj7ee97522011-05-09 21:45:04 +00003281 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003282 s390_disasm(ENC3(MNM, FPR, FPR), "lcxbr", r1, r2);
3283
3284 return emit_RRE(p, 0xb3430000, r1, r2);
3285}
3286
3287
sewardj9d31dfd2011-03-15 12:36:44 +00003288static UChar *
sewardj2019a972011-03-07 16:04:07 +00003289s390_emit_LDEBR(UChar *p, UChar r1, UChar r2)
3290{
sewardj7ee97522011-05-09 21:45:04 +00003291 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003292 s390_disasm(ENC3(MNM, FPR, FPR), "ldebr", r1, r2);
3293
3294 return emit_RRE(p, 0xb3040000, r1, r2);
3295}
3296
3297
sewardj9d31dfd2011-03-15 12:36:44 +00003298static UChar *
sewardj2019a972011-03-07 16:04:07 +00003299s390_emit_LXDBR(UChar *p, UChar r1, UChar r2)
3300{
sewardj7ee97522011-05-09 21:45:04 +00003301 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003302 s390_disasm(ENC3(MNM, FPR, FPR), "lxdbr", r1, r2);
3303
3304 return emit_RRE(p, 0xb3050000, r1, r2);
3305}
3306
3307
sewardj9d31dfd2011-03-15 12:36:44 +00003308static UChar *
sewardj2019a972011-03-07 16:04:07 +00003309s390_emit_LXEBR(UChar *p, UChar r1, UChar r2)
3310{
sewardj7ee97522011-05-09 21:45:04 +00003311 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003312 s390_disasm(ENC3(MNM, FPR, FPR), "lxebr", r1, r2);
3313
3314 return emit_RRE(p, 0xb3060000, r1, r2);
3315}
3316
3317
sewardj9d31dfd2011-03-15 12:36:44 +00003318static UChar *
sewardj2019a972011-03-07 16:04:07 +00003319s390_emit_LNEBR(UChar *p, UChar r1, UChar r2)
3320{
sewardj7ee97522011-05-09 21:45:04 +00003321 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003322 s390_disasm(ENC3(MNM, FPR, FPR), "lnebr", r1, r2);
3323
3324 return emit_RRE(p, 0xb3010000, r1, r2);
3325}
3326
3327
sewardj9d31dfd2011-03-15 12:36:44 +00003328static UChar *
sewardj2019a972011-03-07 16:04:07 +00003329s390_emit_LNDBR(UChar *p, UChar r1, UChar r2)
3330{
sewardj7ee97522011-05-09 21:45:04 +00003331 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003332 s390_disasm(ENC3(MNM, FPR, FPR), "lndbr", r1, r2);
3333
3334 return emit_RRE(p, 0xb3110000, r1, r2);
3335}
3336
3337
sewardj9d31dfd2011-03-15 12:36:44 +00003338static UChar *
sewardj2019a972011-03-07 16:04:07 +00003339s390_emit_LNXBR(UChar *p, UChar r1, UChar r2)
3340{
sewardj7ee97522011-05-09 21:45:04 +00003341 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003342 s390_disasm(ENC3(MNM, FPR, FPR), "lnxbr", r1, r2);
3343
3344 return emit_RRE(p, 0xb3410000, r1, r2);
3345}
3346
3347
sewardj9d31dfd2011-03-15 12:36:44 +00003348static UChar *
sewardj2019a972011-03-07 16:04:07 +00003349s390_emit_LPEBR(UChar *p, UChar r1, UChar r2)
3350{
sewardj7ee97522011-05-09 21:45:04 +00003351 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003352 s390_disasm(ENC3(MNM, FPR, FPR), "lpebr", r1, r2);
3353
3354 return emit_RRE(p, 0xb3000000, r1, r2);
3355}
3356
3357
sewardj9d31dfd2011-03-15 12:36:44 +00003358static UChar *
sewardj2019a972011-03-07 16:04:07 +00003359s390_emit_LPDBR(UChar *p, UChar r1, UChar r2)
3360{
sewardj7ee97522011-05-09 21:45:04 +00003361 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003362 s390_disasm(ENC3(MNM, FPR, FPR), "lpdbr", r1, r2);
3363
3364 return emit_RRE(p, 0xb3100000, r1, r2);
3365}
3366
3367
sewardj9d31dfd2011-03-15 12:36:44 +00003368static UChar *
sewardj2019a972011-03-07 16:04:07 +00003369s390_emit_LPXBR(UChar *p, UChar r1, UChar r2)
3370{
sewardj7ee97522011-05-09 21:45:04 +00003371 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003372 s390_disasm(ENC3(MNM, FPR, FPR), "lpxbr", r1, r2);
3373
3374 return emit_RRE(p, 0xb3400000, r1, r2);
3375}
3376
3377
sewardj9d31dfd2011-03-15 12:36:44 +00003378static UChar *
sewardj2019a972011-03-07 16:04:07 +00003379s390_emit_LEDBR(UChar *p, UChar r1, UChar r2)
3380{
sewardj7ee97522011-05-09 21:45:04 +00003381 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003382 s390_disasm(ENC3(MNM, FPR, FPR), "ledbr", r1, r2);
3383
3384 return emit_RRE(p, 0xb3440000, r1, r2);
3385}
3386
3387
sewardj9d31dfd2011-03-15 12:36:44 +00003388static UChar *
sewardj2019a972011-03-07 16:04:07 +00003389s390_emit_LDXBR(UChar *p, UChar r1, UChar r2)
3390{
sewardj7ee97522011-05-09 21:45:04 +00003391 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003392 s390_disasm(ENC3(MNM, FPR, FPR), "ldxbr", r1, r2);
3393
3394 return emit_RRE(p, 0xb3450000, r1, r2);
3395}
3396
3397
sewardj9d31dfd2011-03-15 12:36:44 +00003398static UChar *
sewardj2019a972011-03-07 16:04:07 +00003399s390_emit_LEXBR(UChar *p, UChar r1, UChar r2)
3400{
sewardj7ee97522011-05-09 21:45:04 +00003401 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003402 s390_disasm(ENC3(MNM, FPR, FPR), "lexbr", r1, r2);
3403
3404 return emit_RRE(p, 0xb3460000, r1, r2);
3405}
3406
3407
sewardj9d31dfd2011-03-15 12:36:44 +00003408static UChar *
sewardj2019a972011-03-07 16:04:07 +00003409s390_emit_MEEBR(UChar *p, UChar r1, UChar r2)
3410{
sewardj7ee97522011-05-09 21:45:04 +00003411 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003412 s390_disasm(ENC3(MNM, FPR, FPR), "meebr", r1, r2);
3413
3414 return emit_RRE(p, 0xb3170000, r1, r2);
3415}
3416
3417
sewardj9d31dfd2011-03-15 12:36:44 +00003418static UChar *
sewardj2019a972011-03-07 16:04:07 +00003419s390_emit_MDBR(UChar *p, UChar r1, UChar r2)
3420{
sewardj7ee97522011-05-09 21:45:04 +00003421 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003422 s390_disasm(ENC3(MNM, FPR, FPR), "mdbr", r1, r2);
3423
3424 return emit_RRE(p, 0xb31c0000, r1, r2);
3425}
3426
3427
sewardj9d31dfd2011-03-15 12:36:44 +00003428static UChar *
sewardj2019a972011-03-07 16:04:07 +00003429s390_emit_MXBR(UChar *p, UChar r1, UChar r2)
3430{
sewardj7ee97522011-05-09 21:45:04 +00003431 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003432 s390_disasm(ENC3(MNM, FPR, FPR), "mxbr", r1, r2);
3433
3434 return emit_RRE(p, 0xb34c0000, r1, r2);
3435}
3436
3437
sewardj9d31dfd2011-03-15 12:36:44 +00003438static UChar *
sewardj2019a972011-03-07 16:04:07 +00003439s390_emit_MAEBR(UChar *p, UChar r1, UChar r3, UChar r2)
3440{
sewardj7ee97522011-05-09 21:45:04 +00003441 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003442 s390_disasm(ENC4(MNM, FPR, FPR, FPR), "maebr", r1, r3, r2);
3443
3444 return emit_RRF(p, 0xb30e0000, r1, r3, r2);
3445}
3446
3447
sewardj9d31dfd2011-03-15 12:36:44 +00003448static UChar *
sewardj2019a972011-03-07 16:04:07 +00003449s390_emit_MADBR(UChar *p, UChar r1, UChar r3, UChar r2)
3450{
sewardj7ee97522011-05-09 21:45:04 +00003451 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003452 s390_disasm(ENC4(MNM, FPR, FPR, FPR), "madbr", r1, r3, r2);
3453
3454 return emit_RRF(p, 0xb31e0000, r1, r3, r2);
3455}
3456
3457
sewardj9d31dfd2011-03-15 12:36:44 +00003458static UChar *
sewardj2019a972011-03-07 16:04:07 +00003459s390_emit_MSEBR(UChar *p, UChar r1, UChar r3, UChar r2)
3460{
sewardj7ee97522011-05-09 21:45:04 +00003461 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003462 s390_disasm(ENC4(MNM, FPR, FPR, FPR), "msebr", r1, r3, r2);
3463
3464 return emit_RRF(p, 0xb30f0000, r1, r3, r2);
3465}
3466
3467
sewardj9d31dfd2011-03-15 12:36:44 +00003468static UChar *
sewardj2019a972011-03-07 16:04:07 +00003469s390_emit_MSDBR(UChar *p, UChar r1, UChar r3, UChar r2)
3470{
sewardj7ee97522011-05-09 21:45:04 +00003471 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003472 s390_disasm(ENC4(MNM, FPR, FPR, FPR), "msdbr", r1, r3, r2);
3473
3474 return emit_RRF(p, 0xb31f0000, r1, r3, r2);
3475}
3476
3477
sewardj9d31dfd2011-03-15 12:36:44 +00003478static UChar *
sewardj2019a972011-03-07 16:04:07 +00003479s390_emit_SQEBR(UChar *p, UChar r1, UChar r2)
3480{
sewardj7ee97522011-05-09 21:45:04 +00003481 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003482 s390_disasm(ENC3(MNM, FPR, FPR), "sqebr", r1, r2);
3483
3484 return emit_RRE(p, 0xb3140000, r1, r2);
3485}
3486
3487
sewardj9d31dfd2011-03-15 12:36:44 +00003488static UChar *
sewardj2019a972011-03-07 16:04:07 +00003489s390_emit_SQDBR(UChar *p, UChar r1, UChar r2)
3490{
sewardj7ee97522011-05-09 21:45:04 +00003491 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003492 s390_disasm(ENC3(MNM, FPR, FPR), "sqdbr", r1, r2);
3493
3494 return emit_RRE(p, 0xb3150000, r1, r2);
3495}
3496
3497
sewardj9d31dfd2011-03-15 12:36:44 +00003498static UChar *
sewardj2019a972011-03-07 16:04:07 +00003499s390_emit_SQXBR(UChar *p, UChar r1, UChar r2)
3500{
sewardj7ee97522011-05-09 21:45:04 +00003501 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003502 s390_disasm(ENC3(MNM, FPR, FPR), "sqxbr", r1, r2);
3503
3504 return emit_RRE(p, 0xb3160000, r1, r2);
3505}
3506
3507
sewardj9d31dfd2011-03-15 12:36:44 +00003508static UChar *
sewardj2019a972011-03-07 16:04:07 +00003509s390_emit_SEBR(UChar *p, UChar r1, UChar r2)
3510{
sewardj7ee97522011-05-09 21:45:04 +00003511 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003512 s390_disasm(ENC3(MNM, FPR, FPR), "sebr", r1, r2);
3513
3514 return emit_RRE(p, 0xb30b0000, r1, r2);
3515}
3516
3517
sewardj9d31dfd2011-03-15 12:36:44 +00003518static UChar *
sewardj2019a972011-03-07 16:04:07 +00003519s390_emit_SDBR(UChar *p, UChar r1, UChar r2)
3520{
sewardj7ee97522011-05-09 21:45:04 +00003521 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003522 s390_disasm(ENC3(MNM, FPR, FPR), "sdbr", r1, r2);
3523
3524 return emit_RRE(p, 0xb31b0000, r1, r2);
3525}
3526
3527
sewardj9d31dfd2011-03-15 12:36:44 +00003528static UChar *
sewardj2019a972011-03-07 16:04:07 +00003529s390_emit_SXBR(UChar *p, UChar r1, UChar r2)
3530{
sewardj7ee97522011-05-09 21:45:04 +00003531 if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM))
sewardj2019a972011-03-07 16:04:07 +00003532 s390_disasm(ENC3(MNM, FPR, FPR), "sxbr", r1, r2);
3533
3534 return emit_RRE(p, 0xb34b0000, r1, r2);
3535}
3536
sewardj2019a972011-03-07 16:04:07 +00003537
3538/* Provide a symbolic name for register "R0" */
3539#define R0 0
3540
3541/* Split up a 20-bit displacement into its high and low piece
3542 suitable for passing as function arguments */
sewardjcd2b0252011-05-09 20:35:41 +00003543#define DISP20(d) (((UInt)d) & 0xFFF), ((((UInt)d) >> 12) & 0xFF)
sewardj2019a972011-03-07 16:04:07 +00003544
3545/*---------------------------------------------------------------*/
3546/*--- Helper functions ---*/
3547/*---------------------------------------------------------------*/
3548
3549static __inline__ Bool
3550uint_fits_signed_16bit(UInt val)
3551{
3552 int v = val & 0xFFFFu;
3553
3554 /* sign extend */
3555 v = (v << 16) >> 16;
3556
3557 return val == (UInt)v;
3558}
3559
3560
3561static __inline__ Bool
3562ulong_fits_signed_16bit(ULong val)
3563{
3564 Long v = val & 0xFFFFu;
3565
3566 /* sign extend */
3567 v = (v << 48) >> 48;
3568
3569 return val == (ULong)v;
3570}
3571
3572
3573static __inline__ Bool
3574ulong_fits_signed_32bit(ULong val)
3575{
3576 Long v = val & 0xFFFFFFFFu;
3577
3578 /* sign extend */
3579 v = (v << 32) >> 32;
3580
3581 return val == (ULong)v;
3582}
3583
3584
3585static __inline__ Bool
3586ulong_fits_unsigned_32bit(ULong val)
3587{
3588 return (val & 0xFFFFFFFFu) == val;
3589}
3590
3591
3592/* Load a 64-bit immediate VAL into register REG. */
3593static UChar *
3594s390_emit_load_64imm(UChar *p, UChar reg, ULong val)
3595{
3596 if (ulong_fits_signed_16bit(val)) {
3597 return s390_emit_LGHI(p, reg, val);
3598 }
3599
3600 if (s390_host_has_eimm) {
3601 if (ulong_fits_unsigned_32bit(val)) {
3602 return s390_emit_LLILF(p, reg, val);
3603 }
3604 if (ulong_fits_signed_32bit(val)) {
3605 /* LGFI's sign extension will recreate the correct 64-bit value */
3606 return s390_emit_LGFI(p, reg, val);
3607 }
3608 /* Do it in two steps: upper half [0:31] and lower half [32:63] */
3609 p = s390_emit_IIHF(p, reg, val >> 32);
3610 return s390_emit_IILF(p, reg, val & 0xFFFFFFFF);
3611 }
3612
3613 /* Fall back */
3614 if (ulong_fits_unsigned_32bit(val)) {
3615 p = s390_emit_LLILH(p, reg, (val >> 16) & 0xFFFF); /* sets val[32:47]
3616 val[0:31] = 0 */
3617 p = s390_emit_IILL(p, reg, val & 0xFFFF); /* sets val[48:63] */
3618 return p;
3619 }
3620
3621 p = s390_emit_IIHH(p, reg, (val >> 48) & 0xFFFF);
3622 p = s390_emit_IIHL(p, reg, (val >> 32) & 0xFFFF);
3623 p = s390_emit_IILH(p, reg, (val >> 16) & 0xFFFF);
3624 p = s390_emit_IILL(p, reg, val & 0xFFFF);
3625
3626 return p;
3627}
3628
3629/* Load a 32-bit immediate VAL into register REG. */
3630static UChar *
3631s390_emit_load_32imm(UChar *p, UChar reg, UInt val)
3632{
3633 if (uint_fits_signed_16bit(val)) {
3634 /* LHI's sign extension will recreate the correct 32-bit value */
3635 return s390_emit_LHI(p, reg, val);
3636 }
3637 if (s390_host_has_eimm) {
3638 return s390_emit_IILF(p, reg, val);
3639 }
3640 /* val[0:15] --> (val >> 16) & 0xFFFF
3641 val[16:31] --> val & 0xFFFF */
3642 p = s390_emit_IILH(p, reg, (val >> 16) & 0xFFFF);
3643 return s390_emit_IILL(p, reg, val & 0xFFFF);
3644}
3645
3646/*------------------------------------------------------------*/
3647/*--- Wrapper functions ---*/
3648/*------------------------------------------------------------*/
3649
sewardjeae8db52011-03-24 09:01:50 +00003650/* r1[32:63],r1+1[32:63] = r1+1[32:63] * memory[op2addr][0:31] */
sewardj2019a972011-03-07 16:04:07 +00003651static UChar *
3652s390_emit_MFYw(UChar *p, UChar r1, UChar x, UChar b, UShort dl, UChar dh)
3653{
3654 if (s390_host_has_gie) {
3655 return s390_emit_MFY(p, r1, x, b, dl, dh);
3656 }
3657
3658 /* Load from memory into R0, then MULTIPLY with R1 */
3659 p = s390_emit_LY(p, R0, x, b, dl, dh);
3660 return s390_emit_MR(p, r1, R0);
3661}
3662
sewardjeae8db52011-03-24 09:01:50 +00003663/* r1[32:63] = r1[32:63] * memory[op2addr][0:15] */
3664static UChar *
3665s390_emit_MHYw(UChar *p, UChar r1, UChar x, UChar b, UShort dl, UChar dh)
3666{
3667 if (s390_host_has_gie) {
3668 return s390_emit_MHY(p, r1, x, b, dl, dh);
3669 }
3670
3671 /* Load from memory into R0, then MULTIPLY with R1 */
3672 p = s390_emit_LHY(p, R0, x, b, dl, dh);
3673 return s390_emit_MSR(p, r1, R0);
3674}
3675
sewardj2019a972011-03-07 16:04:07 +00003676/* r1[32:63] = r1[32:63] * i2 */
3677static UChar *
3678s390_emit_MSFIw(UChar *p, UChar r1, UInt i2)
3679{
3680 if (s390_host_has_gie) {
3681 return s390_emit_MSFI(p, r1, i2);
3682 }
3683
3684 /* Load I2 into R0; then MULTIPLY R0 with R1 */
3685 p = s390_emit_load_32imm(p, R0, i2);
3686 return s390_emit_MSR(p, r1, R0);
3687}
3688
3689
3690/* r1[32:63] = r1[32:63] & i2 */
3691static UChar *
3692s390_emit_NILFw(UChar *p, UChar r1, UInt i2)
3693{
3694 if (s390_host_has_eimm) {
3695 return s390_emit_NILF(p, r1, i2);
3696 }
3697
3698 /* Load I2 into R0; then AND R0 with R1 */
3699 p = s390_emit_load_32imm(p, R0, i2);
3700 return s390_emit_NR(p, r1, R0);
3701}
3702
3703
3704/* r1[32:63] = r1[32:63] | i2 */
3705static UChar *
3706s390_emit_OILFw(UChar *p, UChar r1, UInt i2)
3707{
3708 if (s390_host_has_eimm) {
3709 return s390_emit_OILF(p, r1, i2);
3710 }
3711
3712 /* Load I2 into R0; then AND R0 with R1 */
3713 p = s390_emit_load_32imm(p, R0, i2);
3714 return s390_emit_OR(p, r1, R0);
3715}
3716
3717
3718/* r1[32:63] = r1[32:63] ^ i2 */
3719static UChar *
3720s390_emit_XILFw(UChar *p, UChar r1, UInt i2)
3721{
3722 if (s390_host_has_eimm) {
3723 return s390_emit_XILF(p, r1, i2);
3724 }
3725
3726 /* Load I2 into R0; then AND R0 with R1 */
3727 p = s390_emit_load_32imm(p, R0, i2);
3728 return s390_emit_XR(p, r1, R0);
3729}
3730
3731
sewardj652b56a2011-04-13 15:38:17 +00003732/* r1[32:63] = sign_extend(mem[op2addr][0:7]) */
3733static UChar *
3734s390_emit_LBw(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
3735{
3736 vassert(s390_host_has_ldisp || dh2 == 0);
3737
3738 if (s390_host_has_ldisp) {
3739 return s390_emit_LB(p, r1, x2, b2, dl2, dh2);
3740 }
3741
3742 p = s390_emit_IC(p, r1, x2, b2, dl2); /* r1[56:63] = mem[op2addr][0:7] */
3743 p = s390_emit_SLL(p, r1, R0, 24); /* r1 = r1 << 24 */
3744 return s390_emit_SRA(p, r1, R0, 24); /* r1 = r1 >>a 24 */
3745}
3746
3747
sewardj2019a972011-03-07 16:04:07 +00003748/* r1[32:63] = sign_extend(r2[56:63]) */
3749static UChar *
3750s390_emit_LBRw(UChar *p, UChar r1, UChar r2)
3751{
3752 if (s390_host_has_eimm) {
3753 return s390_emit_LBR(p, r1, r2);
3754 }
3755
3756 p = s390_emit_LR(p, r1, r2); /* r1 = r2 */
sewardj3c49aaa2011-04-05 14:00:37 +00003757 p = s390_emit_SLL(p, r1, R0, 24); /* r1 = r1 << 24 */
3758 return s390_emit_SRA(p, r1, R0, 24); /* r1 = r1 >>a 24 */
sewardj2019a972011-03-07 16:04:07 +00003759}
3760
3761
sewardj652b56a2011-04-13 15:38:17 +00003762/* r1[0:63] = sign_extend(mem[op2addr][0:7]) */
3763static UChar *
3764s390_emit_LGBw(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
3765{
3766 vassert(s390_host_has_ldisp || dh2 == 0);
3767
3768 if (s390_host_has_ldisp) {
3769 return s390_emit_LGB(p, r1, x2, b2, dl2, dh2);
3770 }
3771
3772 p = s390_emit_IC(p, r1, x2, b2, dl2); /* r1[56:63] = mem[op2addr][0:7] */
3773 p = s390_emit_SLLG(p, r1, r1, R0, DISP20(56)); /* r1 = r1 << 56 */
3774 return s390_emit_SRAG(p, r1, r1, R0, DISP20(56)); /* r1 = r1 >>a 56 */
3775}
3776
3777
sewardj2019a972011-03-07 16:04:07 +00003778/* r1[0:63] = sign_extend(r2[56:63]) */
3779static UChar *
3780s390_emit_LGBRw(UChar *p, UChar r1, UChar r2)
3781{
3782 if (s390_host_has_eimm) {
3783 return s390_emit_LGBR(p, r1, r2);
3784 }
3785
3786 p = s390_emit_LR(p, r1, r2); /* r1 = r2 */
3787 p = s390_emit_SLLG(p, r1, r1, R0, DISP20(56)); /* r1 = r1 << 56 */
3788 return s390_emit_SRAG(p, r1, r1, R0, DISP20(56)); /* r1 = r1 >>a 56 */
3789}
3790
3791
3792/* r1[32:63] = sign_extend(r2[48:63]) */
3793static UChar *
3794s390_emit_LHRw(UChar *p, UChar r1, UChar r2)
3795{
3796 if (s390_host_has_eimm) {
3797 return s390_emit_LHR(p, r1, r2);
3798 }
3799
3800 p = s390_emit_LR(p, r1, r2); /* r1 = r2 */
sewardj3c49aaa2011-04-05 14:00:37 +00003801 p = s390_emit_SLL(p, r1, R0, 16); /* r1 = r1 << 16 */
3802 return s390_emit_SRA(p, r1, R0, 16); /* r1 = r1 >>a 16 */
sewardj2019a972011-03-07 16:04:07 +00003803}
3804
3805
3806/* r1[0:63] = sign_extend(r2[48:63]) */
3807static UChar *
3808s390_emit_LGHRw(UChar *p, UChar r1, UChar r2)
3809{
3810 if (s390_host_has_eimm) {
3811 return s390_emit_LGHR(p, r1, r2);
3812 }
3813
3814 p = s390_emit_LR(p, r1, r2); /* r1 = r2 */
3815 p = s390_emit_SLLG(p, r1, r1, R0, DISP20(48)); /* r1 = r1 << 48 */
3816 return s390_emit_SRAG(p, r1, r1, R0, DISP20(48)); /* r1 = r1 >>a 48 */
3817}
3818
3819
3820/* r1[0:63] = sign_extend(i2) */
3821static UChar *
3822s390_emit_LGFIw(UChar *p, UChar r1, UInt i2)
3823{
3824 if (s390_host_has_eimm) {
3825 return s390_emit_LGFI(p, r1, i2);
3826 }
3827
3828 p = s390_emit_load_32imm(p, R0, i2);
3829 return s390_emit_LGFR(p, r1, R0);
3830}
3831
3832
3833/* r1[32:63] = zero_extend($r2[56:63]) */
3834static UChar *
3835s390_emit_LLCRw(UChar *p, UChar r1, UChar r2)
3836{
3837 if (s390_host_has_eimm) {
3838 return s390_emit_LLCR(p, r1, r2);
3839 }
3840
3841 p = s390_emit_LR(p, r1, r2);
3842 p = s390_emit_LHI(p, R0, 0xFF);
3843 return s390_emit_NR(p, r1, R0);
3844}
3845
3846
3847/* r1[0:63] = zero_extend($r2[56:63]) */
3848static UChar *
3849s390_emit_LLGCRw(UChar *p, UChar r1, UChar r2)
3850{
3851 if (s390_host_has_eimm) {
3852 return s390_emit_LLGCR(p, r1, r2);
3853 }
3854
3855 p = s390_emit_LR(p, r1, r2);
3856 p = s390_emit_LLILL(p, R0, 0xFF);
3857 return s390_emit_NGR(p, r1, R0);
3858}
3859
3860
3861/* r1[32:63] = zero_extend(r2[48:63]) */
3862static UChar *
3863s390_emit_LLHRw(UChar *p, UChar r1, UChar r2)
3864{
3865 if (s390_host_has_eimm) {
3866 return s390_emit_LLHR(p, r1, r2);
3867 }
3868
3869 p = s390_emit_LR(p, r1, r2);
3870 p = s390_emit_LLILL(p, R0, 0xFFFF);
3871 return s390_emit_NR(p, r1, R0);
3872}
3873
3874
3875/* r1[0:63] = zero_extend(r2[48:63]) */
3876static UChar *
3877s390_emit_LLGHRw(UChar *p, UChar r1, UChar r2)
3878{
3879 if (s390_host_has_eimm) {
3880 return s390_emit_LLGHR(p, r1, r2);
3881 }
3882
3883 p = s390_emit_LR(p, r1, r2);
3884 p = s390_emit_LLILL(p, R0, 0xFFFF);
3885 return s390_emit_NGR(p, r1, R0);
3886}
3887
3888
3889/* r1[32:63] = zero_extend(mem[op2addr][0:7]) */
3890static UChar *
3891s390_emit_LLCw(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl, UChar dh)
3892{
3893 if (s390_host_has_eimm) {
3894 return s390_emit_LLC(p, r1, x2, b2, dl, dh);
3895 }
3896
3897 if (dh == 0) {
3898 p = s390_emit_IC(p, r1, x2, b2, dl);
3899 } else {
3900 p = s390_emit_ICY(p, r1, x2, b2, dl, dh);
3901 }
3902 p = s390_emit_LLILL(p, R0, 0xFF);
3903 return s390_emit_NR(p, r1, R0);
3904}
3905
3906
3907/* r1[32:63] = zero_extend(mem[op2addr][0:15]) */
3908static UChar *
3909s390_emit_LLHw(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl, UChar dh)
3910{
3911 if (s390_host_has_eimm) {
3912 return s390_emit_LLH(p, r1, x2, b2, dl, dh);
3913 }
3914
3915 p = s390_emit_LLGH(p, r1, x2, b2, dl, dh);
3916 p = s390_emit_LLILL(p, R0, 0xFFFF);
3917 return s390_emit_NR(p, r1, R0);
3918}
3919
3920
3921/* r1[0:63] = zero_extend(i2) */
3922static UChar *
3923s390_emit_LLILFw(UChar *p, UChar r1, UInt i2)
3924{
3925 if (s390_host_has_eimm) {
3926 return s390_emit_LLILF(p, r1, i2);
3927 }
3928
3929 p = s390_emit_LLILH(p, r1, (i2 >> 16) & 0xFFFF); /* i2[0:15] */
3930 return s390_emit_OILL(p, r1, i2 & 0xFFFF);
3931}
3932
3933
3934/* r1[32:63] = r1[32:63] + i2 */
3935static UChar *
3936s390_emit_AFIw(UChar *p, UChar r1, UInt i2)
3937{
3938 if (s390_host_has_eimm) {
3939 return s390_emit_AFI(p, r1, i2);
3940 }
3941 /* Load 32 bit immediate to R0 then add */
3942 p = s390_emit_load_32imm(p, R0, i2);
3943 return s390_emit_AR(p, r1, R0);
3944}
3945
3946
3947/* r1[32:63] = r1[32:63] - i2 */
3948static UChar *
3949s390_emit_SLFIw(UChar *p, UChar r1, UInt i2)
3950{
3951 if (s390_host_has_eimm) {
3952 return s390_emit_SLFI(p, r1, i2);
3953 }
3954
3955 /* Load 32 bit immediate to R0 then subtract */
3956 p = s390_emit_load_32imm(p, R0, i2);
3957 return s390_emit_SR(p, r1, R0);
3958}
3959
3960
sewardjb13a92a2011-04-13 14:44:29 +00003961/* r1[0:63] = r1[0:63] - zero_extend(i2) */
3962static UChar *
3963s390_emit_SLGFIw(UChar *p, UChar r1, UInt i2)
3964{
3965 if (s390_host_has_eimm) {
3966 return s390_emit_SLGFI(p, r1, i2);
3967 }
3968
3969 /* Load zero-extended 32 bit immediate to R0 then subtract */
3970 p = s390_emit_load_64imm(p, R0, i2);
3971 return s390_emit_SGR(p, r1, R0);
3972}
3973
3974
sewardj2019a972011-03-07 16:04:07 +00003975static UChar *
3976s390_emit_LTw(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl, UChar dh)
3977{
3978 if (s390_host_has_eimm) {
3979 return s390_emit_LT(p, r1, x2, b2, dl, dh);
3980 }
3981 /* Load 32 bit from memory to R0 then compare */
3982 if (dh == 0) {
3983 p = s390_emit_L(p, R0, x2, b2, dl);
3984 } else {
3985 p = s390_emit_LY(p, R0, x2, b2, dl, dh);
3986 }
3987 return s390_emit_LTR(p, r1, R0);
3988}
3989
3990
3991static UChar *
3992s390_emit_LTGw(UChar *p, UChar r1, UChar x2, UChar b2, UShort dl, UChar dh)
3993{
3994 if (s390_host_has_eimm) {
3995 return s390_emit_LTG(p, r1, x2, b2, dl, dh);
3996 }
3997 /* Load 64 bit from memory to R0 then compare */
3998 p = s390_emit_LG(p, R0, x2, b2, dl, dh);
3999 return s390_emit_LTGR(p, r1, R0);
4000}
4001
4002
4003static UChar *
4004s390_emit_CFIw(UChar *p, UChar r1, UInt i2)
4005{
4006 if (s390_host_has_eimm) {
4007 return s390_emit_CFI(p, r1, i2);
4008 }
4009 /* Load 32 bit immediate to R0 then compare */
4010 p = s390_emit_load_32imm(p, R0, i2);
4011 return s390_emit_CR(p, r1, R0);
4012}
4013
4014
4015static UChar *
4016s390_emit_CLFIw(UChar *p, UChar r1, UInt i2)
4017{
4018 if (s390_host_has_eimm) {
4019 return s390_emit_CLFI(p, r1, i2);
4020 }
4021 /* Load 32 bit immediate to R0 then compare */
4022 p = s390_emit_load_32imm(p, R0, i2);
4023 return s390_emit_CLR(p, r1, R0);
4024}
4025
sewardjd07b8562011-04-27 11:58:22 +00004026
4027static UChar *
4028s390_emit_LGDRw(UChar *p, UChar r1, UChar r2)
4029{
4030 if (s390_host_has_fgx) {
4031 return s390_emit_LGDR(p, r1, r2);
4032 }
4033
4034 /* Store the FPR at memory[sp - 8]. This is safe because SP grows towards
4035 smaller addresses and is 8-byte aligned. Then load the GPR from that
4036 memory location/ */
4037 if (s390_host_has_ldisp) {
4038 p = s390_emit_STDY(p, r2, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
4039 return s390_emit_LG(p, r1, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
4040 }
4041
4042 /* No long displacement. Need to adjust SP explicitly as to avoid negative
4043 displacements. */
4044 p = s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, -8);
4045 p = s390_emit_STD(p, r2, R0, S390_REGNO_STACK_POINTER, 0);
4046 p = s390_emit_LG(p, r1, R0, S390_REGNO_STACK_POINTER, DISP20(0));
4047 return s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, 8);
4048}
4049
4050
4051static UChar *
4052s390_emit_LDGRw(UChar *p, UChar r1, UChar r2)
4053{
4054 if (s390_host_has_fgx) {
4055 return s390_emit_LDGR(p, r1, r2);
4056 }
4057
4058 /* Store the GPR at memory[sp - 8]. This is safe because SP grows towards
4059 smaller addresses and is 8-byte aligned. Then load the FPR from that
4060 memory location/ */
4061 if (s390_host_has_ldisp) {
4062 p = s390_emit_STG(p, r2, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
4063 return s390_emit_LDY(p, r1, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
4064 }
4065
4066 /* No long displacement. Need to adjust SP explicitly as to avoid negative
4067 displacements. */
4068 p = s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, -8);
4069 p = s390_emit_STG(p, r2, R0, S390_REGNO_STACK_POINTER, DISP20(0));
4070 p = s390_emit_LD(p, r1, R0, S390_REGNO_STACK_POINTER, 0);
4071 return s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, 8);
4072}
4073
4074
sewardj2019a972011-03-07 16:04:07 +00004075/*---------------------------------------------------------------*/
4076/*--- Constructors for the various s390_insn kinds ---*/
4077/*---------------------------------------------------------------*/
4078
4079s390_insn *
4080s390_insn_load(UChar size, HReg dst, s390_amode *src)
4081{
4082 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4083
4084 insn->tag = S390_INSN_LOAD;
4085 insn->size = size;
4086 insn->variant.load.src = src;
4087 insn->variant.load.dst = dst;
4088
4089 vassert(size == 1 || size == 2 || size == 4 || size == 8);
4090
4091 return insn;
4092}
4093
4094
4095s390_insn *
4096s390_insn_store(UChar size, s390_amode *dst, HReg src)
4097{
4098 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4099
4100 insn->tag = S390_INSN_STORE;
4101 insn->size = size;
4102 insn->variant.store.src = src;
4103 insn->variant.store.dst = dst;
4104
4105 vassert(size == 1 || size == 2 || size == 4 || size == 8);
4106
4107 return insn;
4108}
4109
4110
4111s390_insn *
4112s390_insn_move(UChar size, HReg dst, HReg src)
4113{
4114 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4115
4116 insn->tag = S390_INSN_MOVE;
4117 insn->size = size;
4118 insn->variant.move.src = src;
4119 insn->variant.move.dst = dst;
4120
4121 vassert(size == 1 || size == 2 || size == 4 || size == 8);
4122
4123 return insn;
4124}
4125
4126
4127s390_insn *
4128s390_insn_cond_move(UChar size, s390_cc_t cond, HReg dst, s390_opnd_RMI src)
4129{
4130 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4131
4132 insn->tag = S390_INSN_COND_MOVE;
4133 insn->size = size;
4134 insn->variant.cond_move.cond = cond;
4135 insn->variant.cond_move.src = src;
4136 insn->variant.cond_move.dst = dst;
4137
4138 vassert(size == 1 || size == 2 || size == 4 || size == 8);
4139
4140 return insn;
4141}
4142
4143
4144s390_insn *
4145s390_insn_load_immediate(UChar size, HReg dst, ULong value)
4146{
4147 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4148
4149 insn->tag = S390_INSN_LOAD_IMMEDIATE;
4150 insn->size = size;
4151 insn->variant.load_immediate.dst = dst;
4152 insn->variant.load_immediate.value = value;
4153
4154 return insn;
4155}
4156
4157
4158s390_insn *
4159s390_insn_alu(UChar size, s390_alu_t tag, HReg dst, s390_opnd_RMI op2)
4160{
4161 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4162
4163 insn->tag = S390_INSN_ALU;
4164 insn->size = size;
4165 insn->variant.alu.tag = tag;
4166 insn->variant.alu.dst = dst;
4167 insn->variant.alu.op2 = op2;
4168
4169 return insn;
4170}
4171
4172
4173s390_insn *
4174s390_insn_mul(UChar size, HReg dst_hi, HReg dst_lo, s390_opnd_RMI op2,
4175 Bool signed_multiply)
4176{
4177 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4178
4179 vassert(! hregIsVirtual(dst_hi));
4180 vassert(! hregIsVirtual(dst_lo));
4181
4182 insn->tag = S390_INSN_MUL;
4183 insn->size = size;
4184 insn->variant.mul.dst_hi = dst_hi;
4185 insn->variant.mul.dst_lo = dst_lo;
4186 insn->variant.mul.op2 = op2;
4187 insn->variant.mul.signed_multiply = signed_multiply;
4188
4189 return insn;
4190}
4191
4192
4193s390_insn *
4194s390_insn_div(UChar size, HReg op1_hi, HReg op1_lo, s390_opnd_RMI op2,
4195 Bool signed_divide)
4196{
4197 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4198
4199 vassert(size == 4 || size == 8);
4200 vassert(! hregIsVirtual(op1_hi));
4201 vassert(! hregIsVirtual(op1_lo));
4202
4203 insn->tag = S390_INSN_DIV;
4204 insn->size = size;
4205 insn->variant.div.op1_hi = op1_hi;
4206 insn->variant.div.op1_lo = op1_lo;
4207 insn->variant.div.op2 = op2;
4208 insn->variant.div.signed_divide = signed_divide;
4209
4210 return insn;
4211}
4212
4213
4214s390_insn *
4215s390_insn_divs(UChar size, HReg rem, HReg op1, s390_opnd_RMI op2)
4216{
4217 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4218
4219 vassert(size == 8);
4220 vassert(! hregIsVirtual(op1));
4221 vassert(! hregIsVirtual(rem));
4222
4223 insn->tag = S390_INSN_DIVS;
4224 insn->size = size;
4225 insn->variant.divs.rem = rem; /* remainder */
4226 insn->variant.divs.op1 = op1; /* also quotient */
4227 insn->variant.divs.op2 = op2;
4228
4229 return insn;
4230}
4231
4232
4233s390_insn *
sewardj611b06e2011-03-24 08:57:29 +00004234s390_insn_clz(UChar size, HReg num_bits, HReg clobber, s390_opnd_RMI src)
sewardj2019a972011-03-07 16:04:07 +00004235{
4236 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4237
4238 vassert(size == 8);
sewardj611b06e2011-03-24 08:57:29 +00004239 vassert(! hregIsVirtual(num_bits));
4240 vassert(! hregIsVirtual(clobber));
sewardj2019a972011-03-07 16:04:07 +00004241
sewardj611b06e2011-03-24 08:57:29 +00004242 insn->tag = S390_INSN_CLZ;
sewardj2019a972011-03-07 16:04:07 +00004243 insn->size = size;
sewardj611b06e2011-03-24 08:57:29 +00004244 insn->variant.clz.num_bits = num_bits;
4245 insn->variant.clz.clobber = clobber;
4246 insn->variant.clz.src = src;
sewardj2019a972011-03-07 16:04:07 +00004247
4248 return insn;
4249}
4250
4251
4252s390_insn *
4253s390_insn_unop(UChar size, s390_unop_t tag, HReg dst, s390_opnd_RMI opnd)
4254{
4255 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4256
4257 insn->tag = S390_INSN_UNOP;
4258 insn->size = size;
4259 insn->variant.unop.tag = tag;
4260 insn->variant.unop.dst = dst;
4261 insn->variant.unop.src = opnd;
4262
4263 return insn;
4264}
4265
4266
4267s390_insn *
4268s390_insn_test(UChar size, s390_opnd_RMI src)
4269{
4270 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4271
4272 vassert(size == 4 || size == 8);
4273
4274 insn->tag = S390_INSN_TEST;
4275 insn->size = size;
4276 insn->variant.test.src = src;
4277
4278 return insn;
4279}
4280
4281
4282s390_insn *
4283s390_insn_cc2bool(HReg dst, s390_cc_t cond)
4284{
4285 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4286
4287 insn->tag = S390_INSN_CC2BOOL;
4288 insn->size = 0; /* does not matter */
4289 insn->variant.cc2bool.cond = cond;
4290 insn->variant.cc2bool.dst = dst;
4291
4292 return insn;
4293}
4294
4295
4296s390_insn *
4297s390_insn_cas(UChar size, HReg op1, s390_amode *op2, HReg op3, HReg old_mem)
4298{
4299 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4300
4301 vassert(size == 4 || size == 8);
4302 vassert(op2->x == 0);
4303
4304 insn->tag = S390_INSN_CAS;
4305 insn->size = size;
4306 insn->variant.cas.op1 = op1;
4307 insn->variant.cas.op2 = op2;
4308 insn->variant.cas.op3 = op3;
4309 insn->variant.cas.old_mem = old_mem;
4310
4311 return insn;
4312}
4313
4314
4315s390_insn *
4316s390_insn_compare(UChar size, HReg src1, s390_opnd_RMI src2,
4317 Bool signed_comparison)
4318{
4319 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4320
4321 vassert(size == 4 || size == 8);
4322
4323 insn->tag = S390_INSN_COMPARE;
4324 insn->size = size;
4325 insn->variant.compare.src1 = src1;
4326 insn->variant.compare.src2 = src2;
4327 insn->variant.compare.signed_comparison = signed_comparison;
4328
4329 return insn;
4330}
4331
4332
4333s390_insn *
sewardj2019a972011-03-07 16:04:07 +00004334s390_insn_helper_call(s390_cc_t cond, Addr64 target, UInt num_args,
4335 HChar *name)
4336{
4337 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4338
4339 insn->tag = S390_INSN_HELPER_CALL;
4340 insn->size = 0; /* does not matter */
4341 insn->variant.helper_call.cond = cond;
4342 insn->variant.helper_call.target = target;
4343 insn->variant.helper_call.num_args = num_args;
4344 insn->variant.helper_call.name = name;
4345
4346 return insn;
4347}
4348
4349
4350s390_insn *
4351s390_insn_bfp_triop(UChar size, s390_bfp_triop_t tag, HReg dst, HReg op2,
4352 HReg op3, s390_round_t rounding_mode)
4353{
4354 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4355
4356 insn->tag = S390_INSN_BFP_TRIOP;
4357 insn->size = size;
4358 insn->variant.bfp_triop.tag = tag;
4359 insn->variant.bfp_triop.dst = dst;
4360 insn->variant.bfp_triop.op2 = op2;
4361 insn->variant.bfp_triop.op3 = op3;
4362 insn->variant.bfp_triop.rounding_mode = rounding_mode;
4363
4364 return insn;
4365}
4366
4367
4368s390_insn *
4369s390_insn_bfp_binop(UChar size, s390_bfp_binop_t tag, HReg dst, HReg op2,
4370 s390_round_t rounding_mode)
4371{
4372 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4373
4374 insn->tag = S390_INSN_BFP_BINOP;
4375 insn->size = size;
4376 insn->variant.bfp_binop.tag = tag;
4377 insn->variant.bfp_binop.dst = dst;
4378 insn->variant.bfp_binop.op2 = op2;
4379 insn->variant.bfp_binop.rounding_mode = rounding_mode;
4380
4381 return insn;
4382}
4383
4384
4385s390_insn *
4386s390_insn_bfp_unop(UChar size, s390_bfp_unop_t tag, HReg dst, HReg op,
4387 s390_round_t rounding_mode)
4388{
4389 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4390
4391 insn->tag = S390_INSN_BFP_UNOP;
4392 insn->size = size;
4393 insn->variant.bfp_unop.tag = tag;
4394 insn->variant.bfp_unop.dst = dst;
4395 insn->variant.bfp_unop.op = op;
4396 insn->variant.bfp_unop.rounding_mode = rounding_mode;
4397
4398 return insn;
4399}
4400
4401
4402s390_insn *
4403s390_insn_bfp_compare(UChar size, HReg dst, HReg op1, HReg op2)
4404{
4405 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4406
4407 vassert(size == 4 || size == 8);
4408
4409 insn->tag = S390_INSN_BFP_COMPARE;
4410 insn->size = size;
4411 insn->variant.bfp_compare.dst = dst;
4412 insn->variant.bfp_compare.op1 = op1;
4413 insn->variant.bfp_compare.op2 = op2;
4414
4415 return insn;
4416}
4417
4418
4419s390_insn *
4420s390_insn_bfp128_binop(UChar size, s390_bfp_binop_t tag, HReg dst_hi,
4421 HReg dst_lo, HReg op2_hi, HReg op2_lo,
4422 s390_round_t rounding_mode)
4423{
4424 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4425
4426 insn->tag = S390_INSN_BFP128_BINOP;
4427 insn->size = size;
4428 insn->variant.bfp128_binop.tag = tag;
4429 insn->variant.bfp128_binop.dst_hi = dst_hi;
4430 insn->variant.bfp128_binop.dst_lo = dst_lo;
4431 insn->variant.bfp128_binop.op2_hi = op2_hi;
4432 insn->variant.bfp128_binop.op2_lo = op2_lo;
4433 insn->variant.bfp128_binop.rounding_mode = rounding_mode;
4434
4435 return insn;
4436}
4437
4438
4439s390_insn *
sewardja970c402011-04-28 18:38:42 +00004440s390_insn_bfp128_unop(UChar size, s390_bfp_unop_t tag, HReg dst_hi,
sewardj2019a972011-03-07 16:04:07 +00004441 HReg dst_lo, HReg op_hi, HReg op_lo,
4442 s390_round_t rounding_mode)
4443{
4444 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4445
4446 insn->tag = S390_INSN_BFP128_UNOP;
4447 insn->size = size;
4448 insn->variant.bfp128_unop.tag = tag;
4449 insn->variant.bfp128_unop.dst_hi = dst_hi;
4450 insn->variant.bfp128_unop.dst_lo = dst_lo;
4451 insn->variant.bfp128_unop.op_hi = op_hi;
4452 insn->variant.bfp128_unop.op_lo = op_lo;
4453 insn->variant.bfp128_unop.rounding_mode = rounding_mode;
4454
4455 return insn;
4456}
4457
4458
4459s390_insn *
4460s390_insn_bfp128_compare(UChar size, HReg dst, HReg op1_hi, HReg op1_lo,
4461 HReg op2_hi, HReg op2_lo)
4462{
4463 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4464
4465 insn->tag = S390_INSN_BFP128_COMPARE;
4466 insn->size = size;
4467 insn->variant.bfp128_compare.dst = dst;
4468 insn->variant.bfp128_compare.op1_hi = op1_hi;
4469 insn->variant.bfp128_compare.op1_lo = op1_lo;
4470 insn->variant.bfp128_compare.op2_hi = op2_hi;
4471 insn->variant.bfp128_compare.op2_lo = op2_lo;
4472
4473 return insn;
4474}
4475
4476
4477s390_insn *
4478s390_insn_bfp128_convert_to(UChar size, s390_bfp_unop_t tag, HReg dst_hi,
4479 HReg dst_lo, HReg op)
4480{
4481 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4482
4483 insn->tag = S390_INSN_BFP128_CONVERT_TO;
4484 insn->size = size;
4485 insn->variant.bfp128_unop.tag = tag;
4486 insn->variant.bfp128_unop.dst_hi = dst_hi;
4487 insn->variant.bfp128_unop.dst_lo = dst_lo;
4488 insn->variant.bfp128_unop.op_hi = op;
4489 insn->variant.bfp128_unop.op_lo = INVALID_HREG; /* unused */
4490 insn->variant.bfp128_unop.rounding_mode = S390_ROUND_NEAREST_EVEN; /* unused */
4491
4492 return insn;
4493}
4494
4495
4496s390_insn *
4497s390_insn_bfp128_convert_from(UChar size, s390_bfp_unop_t tag, HReg dst,
4498 HReg op_hi, HReg op_lo,
4499 s390_round_t rounding_mode)
4500{
4501 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4502
4503 insn->tag = S390_INSN_BFP128_CONVERT_FROM;
4504 insn->size = size;
4505 insn->variant.bfp128_unop.tag = tag;
4506 insn->variant.bfp128_unop.dst_hi = dst;
4507 insn->variant.bfp128_unop.dst_lo = INVALID_HREG; /* unused */
4508 insn->variant.bfp128_unop.op_hi = op_hi;
4509 insn->variant.bfp128_unop.op_lo = op_lo;
4510 insn->variant.bfp128_unop.rounding_mode = rounding_mode;
4511
4512 return insn;
4513}
4514
4515
sewardja52e37e2011-04-28 18:48:06 +00004516s390_insn *
4517s390_insn_mfence(void)
4518{
4519 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4520
4521 insn->tag = S390_INSN_MFENCE;
4522 insn->size = 0; /* not needed */
4523
4524 return insn;
4525}
4526
4527
florianad43b3a2012-02-20 15:01:14 +00004528s390_insn *
4529s390_insn_gzero(UChar size, UInt offset)
4530{
4531 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4532
4533 insn->tag = S390_INSN_GZERO;
4534 insn->size = size;
4535 insn->variant.gzero.offset = offset;
4536
4537 return insn;
4538}
4539
4540
4541s390_insn *
4542s390_insn_gadd(UChar size, UInt offset, UChar delta, ULong value)
4543{
4544 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4545
4546 insn->tag = S390_INSN_GADD;
4547 insn->size = size;
4548 insn->variant.gadd.offset = offset;
4549 insn->variant.gadd.delta = delta;
4550 insn->variant.gadd.value = value;
4551
4552 return insn;
4553}
4554
4555
florian8844a632012-04-13 04:04:06 +00004556s390_insn *
4557s390_insn_xdirect(s390_cc_t cond, Addr64 dst, s390_amode *guest_IA,
4558 Bool to_fast_entry)
4559{
4560 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4561
4562 insn->tag = S390_INSN_XDIRECT;
4563 insn->size = 0; /* does not matter */
4564
4565 insn->variant.xdirect.cond = cond;
4566 insn->variant.xdirect.dst = dst;
4567 insn->variant.xdirect.guest_IA = guest_IA;
4568 insn->variant.xdirect.to_fast_entry = to_fast_entry;
4569
4570 return insn;
4571}
4572
4573
4574s390_insn *
4575s390_insn_xindir(s390_cc_t cond, HReg dst, s390_amode *guest_IA)
4576{
4577 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4578
florian7346c7a2012-04-13 21:14:24 +00004579 insn->tag = S390_INSN_XINDIR;
florian8844a632012-04-13 04:04:06 +00004580 insn->size = 0; /* does not matter */
4581
florian7346c7a2012-04-13 21:14:24 +00004582 insn->variant.xindir.cond = cond;
4583 insn->variant.xindir.dst = dst;
4584 insn->variant.xindir.guest_IA = guest_IA;
florian8844a632012-04-13 04:04:06 +00004585
4586 return insn;
4587}
4588
4589
4590s390_insn *
4591s390_insn_xassisted(s390_cc_t cond, HReg dst, s390_amode *guest_IA,
4592 IRJumpKind kind)
4593{
4594 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4595
4596 insn->tag = S390_INSN_XASSISTED;
4597 insn->size = 0; /* does not matter */
4598
4599 insn->variant.xassisted.cond = cond;
4600 insn->variant.xassisted.dst = dst;
4601 insn->variant.xassisted.guest_IA = guest_IA;
4602 insn->variant.xassisted.kind = kind;
4603
4604 return insn;
4605}
4606
4607
4608s390_insn *
4609s390_insn_evcheck(s390_amode *counter, s390_amode *fail_addr)
4610{
4611 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4612
florianbf516d12012-04-21 15:53:13 +00004613 vassert(counter->tag == S390_AMODE_B12);
4614 vassert(fail_addr->tag == S390_AMODE_B12);
florian8844a632012-04-13 04:04:06 +00004615
4616 insn->tag = S390_INSN_EVCHECK;
4617 insn->size = 0; /* does not matter */
4618
4619 insn->variant.evcheck.counter = counter;
4620 insn->variant.evcheck.fail_addr = fail_addr;
4621
4622 return insn;
4623}
4624
4625
4626s390_insn *
4627s390_insn_profinc(void)
4628{
4629 s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
4630
4631 insn->tag = S390_INSN_PROFINC;
4632 insn->size = 0; /* does not matter */
4633
4634 return insn;
4635}
4636
4637
sewardj2019a972011-03-07 16:04:07 +00004638/*---------------------------------------------------------------*/
4639/*--- Debug print ---*/
4640/*---------------------------------------------------------------*/
4641
4642static const HChar *
4643s390_cc_as_string(s390_cc_t cc)
4644{
4645 switch (cc) {
4646 case S390_CC_NEVER: return "never";
4647 case S390_CC_OVFL: return "overflow";
4648 case S390_CC_H: return "greater than"; /* A > B ; high */
4649 case S390_CC_NLE: return "not low or equal";
4650 case S390_CC_L: return "less than"; /* A < B ; low */
4651 case S390_CC_NHE: return "not high or equal";
4652 case S390_CC_LH: return "low or high";
4653 case S390_CC_NE: return "not equal"; /* A != B ; not zero */
4654 case S390_CC_E: return "equal"; /* A == B ; zero */
4655 case S390_CC_NLH: return "not low or high";
4656 case S390_CC_HE: return "greater or equal"; /* A >= B ; high or equal*/
4657 case S390_CC_NL: return "not low"; /* not low */
4658 case S390_CC_LE: return "less or equal"; /* A <= B ; low or equal */
4659 case S390_CC_NH: return "not high";
4660 case S390_CC_NO: return "not overflow";
4661 case S390_CC_ALWAYS: return "always";
4662 default:
4663 vpanic("s390_cc_as_string");
4664 }
4665}
4666
4667
florian8844a632012-04-13 04:04:06 +00004668static const HChar *
4669s390_jump_kind_as_string(IRJumpKind kind)
4670{
4671 switch (kind) {
4672 case Ijk_Boring: return "Boring";
4673 case Ijk_Call: return "Call";
4674 case Ijk_Ret: return "Return";
4675 case Ijk_ClientReq: return "ClientReq";
4676 case Ijk_Yield: return "Yield";
4677 case Ijk_EmWarn: return "EmWarn";
4678 case Ijk_EmFail: return "EmFail";
4679 case Ijk_NoDecode: return "NoDecode";
4680 case Ijk_MapFail: return "MapFail";
4681 case Ijk_TInval: return "Invalidate";
4682 case Ijk_NoRedir: return "NoRedir";
4683 case Ijk_SigTRAP: return "SigTRAP";
4684 case Ijk_SigSEGV: return "SigSEGV";
4685 case Ijk_SigBUS: return "SigBUS";
4686 case Ijk_Sys_syscall: return "Sys_syscall";
4687 default:
4688 vpanic("s390_jump_kind_as_string");
4689 }
4690}
4691
4692
sewardj2019a972011-03-07 16:04:07 +00004693/* Helper function for writing out a V insn */
4694static void
4695s390_sprintf(HChar *buf, HChar *fmt, ...)
4696{
4697 HChar *p;
4698 ULong value;
4699 va_list args;
4700 va_start(args, fmt);
4701
4702 p = buf;
4703 for ( ; *fmt; ++fmt) {
4704 Int c = *fmt;
4705
4706 if (c != '%') {
4707 *p++ = c;
4708 continue;
4709 }
4710
4711 c = *++fmt; /* next char */
4712 switch (c) {
4713 case '%':
4714 *p++ = c; /* %% */
4715 continue;
4716
4717 case 's': /* %s */
4718 p += vex_sprintf(p, "%s", va_arg(args, HChar *));
4719 continue;
4720
4721 case 'M': /* %M = mnemonic */
4722 p += vex_sprintf(p, "%-8s", va_arg(args, HChar *));
4723 continue;
4724
4725 case 'R': /* %R = register */
4726 p += vex_sprintf(p, "%s", s390_hreg_as_string(va_arg(args, HReg)));
4727 continue;
4728
4729 case 'A': /* %A = amode */
4730 p += vex_sprintf(p, "%s",
4731 s390_amode_as_string(va_arg(args, s390_amode *)));
4732 continue;
4733
florianad43b3a2012-02-20 15:01:14 +00004734 case 'G': /* %G = guest state @ offset */
4735 p += vex_sprintf(p, "guest[%d]", va_arg(args, UInt));
4736 continue;
4737
sewardj2019a972011-03-07 16:04:07 +00004738 case 'C': /* %C = condition code */
4739 p += vex_sprintf(p, "%s", s390_cc_as_string(va_arg(args, s390_cc_t)));
4740 continue;
4741
florian8844a632012-04-13 04:04:06 +00004742 case 'J': /* &J = jump kind */
4743 p += vex_sprintf(p, "%s",
4744 s390_jump_kind_as_string(va_arg(args, IRJumpKind)));
4745 continue;
4746
sewardj2019a972011-03-07 16:04:07 +00004747 case 'L': { /* %L = argument list in helper call*/
4748 UInt i, num_args;
4749
4750 num_args = va_arg(args, UInt);
4751
4752 for (i = 0; i < num_args; ++i) {
4753 if (i != 0) p += vex_sprintf(p, ", ");
4754 p += vex_sprintf(p, "r%d", s390_gprno_from_arg_index(i));
4755 }
4756 continue;
4757 }
4758
4759 case 'O': { /* %O = RMI operand */
4760 s390_opnd_RMI *op = va_arg(args, s390_opnd_RMI *);
4761
4762 switch (op->tag) {
4763 case S390_OPND_REG:
4764 p += vex_sprintf(p, "%s", s390_hreg_as_string(op->variant.reg));
4765 continue;
4766
4767 case S390_OPND_AMODE:
4768 p += vex_sprintf(p, "%s", s390_amode_as_string(op->variant.am));
4769 continue;
4770
4771 case S390_OPND_IMMEDIATE:
4772 value = op->variant.imm;
4773 goto print_value;
4774
4775 default:
4776 goto fail;
4777 }
4778 }
4779
4780 case 'I': /* %I = immediate value */
4781 value = va_arg(args, ULong);
4782 goto print_value;
4783
4784 print_value:
4785 if ((Long)value < 0)
4786 p += vex_sprintf(p, "%lld", (Long)value);
4787 else if (value < 100)
4788 p += vex_sprintf(p, "%llu", value);
4789 else
4790 p += vex_sprintf(p, "0x%llx", value);
4791 continue;
4792
4793 default:
4794 goto fail;
4795 }
4796 }
4797 *p = '\0';
4798 va_end(args);
4799
4800 return;
4801
4802 fail: vpanic("s390_printf");
4803}
4804
4805
4806/* Decompile the given insn into a static buffer and return it */
4807const HChar *
4808s390_insn_as_string(const s390_insn *insn)
4809{
4810 static HChar buf[300];
4811 const HChar *op;
4812 HChar *p;
4813
4814 buf[0] = '\0';
4815
4816 switch (insn->tag) {
4817 case S390_INSN_LOAD:
4818 s390_sprintf(buf, "%M %R,%A", "v-load", insn->variant.load.dst,
4819 insn->variant.load.src);
4820 break;
4821
4822 case S390_INSN_STORE:
4823 s390_sprintf(buf, "%M %R,%A", "v-store", insn->variant.store.src,
4824 insn->variant.store.dst);
4825 break;
4826
4827 case S390_INSN_MOVE:
4828 s390_sprintf(buf, "%M %R,%R", "v-move", insn->variant.move.dst,
4829 insn->variant.move.src);
4830 break;
4831
4832 case S390_INSN_COND_MOVE:
4833 s390_sprintf(buf, "%M if (%C) %R,%O", "v-move",
4834 insn->variant.cond_move.cond, insn->variant.cond_move.dst,
4835 &insn->variant.cond_move.src);
4836 break;
4837
4838 case S390_INSN_LOAD_IMMEDIATE:
4839 s390_sprintf(buf, "%M %R,%I", "v-loadi", insn->variant.load_immediate.dst,
4840 insn->variant.load_immediate.value);
4841 break;
4842
4843 case S390_INSN_ALU:
4844 switch (insn->variant.alu.tag) {
4845 case S390_ALU_ADD: op = "v-add"; break;
4846 case S390_ALU_SUB: op = "v-sub"; break;
4847 case S390_ALU_MUL: op = "v-mul"; break;
4848 case S390_ALU_AND: op = "v-and"; break;
4849 case S390_ALU_OR: op = "v-or"; break;
4850 case S390_ALU_XOR: op = "v-xor"; break;
4851 case S390_ALU_LSH: op = "v-lsh"; break;
4852 case S390_ALU_RSH: op = "v-rsh"; break;
4853 case S390_ALU_RSHA: op = "v-rsha"; break;
4854 default: goto fail;
4855 }
4856 s390_sprintf(buf, "%M %R,%R,%O", op, insn->variant.alu.dst,
4857 insn->variant.alu.dst /* op1 same as dst */,
4858 &insn->variant.alu.op2);
4859 break;
4860
4861 case S390_INSN_MUL:
4862 if (insn->variant.mul.signed_multiply) {
4863 op = "v-muls";
4864 } else {
4865 op = "v-mulu";
4866 }
4867 s390_sprintf(buf, "%M %R,%O", op, insn->variant.mul.dst_hi,
4868 &insn->variant.mul.op2);
4869 break;
4870
4871 case S390_INSN_DIV:
4872 if (insn->variant.div.signed_divide) {
4873 op = "v-divs";
4874 } else {
4875 op = "v-divu";
4876 }
4877 s390_sprintf(buf, "%M %R,%O", op, insn->variant.div.op1_hi,
4878 &insn->variant.div.op2);
4879 break;
4880
4881 case S390_INSN_DIVS:
4882 s390_sprintf(buf, "%M %R,%O", "v-divsi", insn->variant.divs.op1,
4883 &insn->variant.divs.op2);
4884 break;
4885
sewardj611b06e2011-03-24 08:57:29 +00004886 case S390_INSN_CLZ:
4887 s390_sprintf(buf, "%M %R,%O", "v-clz", insn->variant.clz.num_bits,
4888 &insn->variant.clz.src);
sewardj2019a972011-03-07 16:04:07 +00004889 break;
4890
4891 case S390_INSN_UNOP:
4892 switch (insn->variant.unop.tag) {
4893 case S390_ZERO_EXTEND_8:
4894 case S390_ZERO_EXTEND_16:
4895 case S390_ZERO_EXTEND_32:
4896 op = "v-zerox";
4897 break;
4898
4899 case S390_SIGN_EXTEND_8:
4900 case S390_SIGN_EXTEND_16:
4901 case S390_SIGN_EXTEND_32:
4902 op = "v-signx";
4903 break;
4904
4905 case S390_NEGATE:
4906 op = "v-neg";
4907 break;
4908
4909 default:
4910 goto fail;
4911 }
4912 s390_sprintf(buf, "%M %R,%O", op, insn->variant.unop.dst,
4913 &insn->variant.unop.src);
4914 break;
4915
4916 case S390_INSN_TEST:
4917 s390_sprintf(buf, "%M %O", "v-test", &insn->variant.test.src);
4918 break;
4919
4920 case S390_INSN_CC2BOOL:
4921 s390_sprintf(buf, "%M %R,%C", "v-cc2b", insn->variant.cc2bool.dst,
4922 insn->variant.cc2bool.cond);
4923 break;
4924
4925 case S390_INSN_CAS:
4926 s390_sprintf(buf, "%M %R,%A,%R,%R", "v-cas", insn->variant.cas.op1,
4927 insn->variant.cas.op2, insn->variant.cas.op3,
4928 insn->variant.cas.old_mem);
4929 break;
4930
4931 case S390_INSN_COMPARE:
4932 if (insn->variant.compare.signed_comparison) {
4933 op = "v-cmps";
4934 } else {
4935 op = "v-cmpu";
4936 }
4937 s390_sprintf(buf, "%M %R,%O", op, insn->variant.compare.src1,
4938 &insn->variant.compare.src2);
4939 break;
4940
sewardj2019a972011-03-07 16:04:07 +00004941 case S390_INSN_HELPER_CALL: {
florian8844a632012-04-13 04:04:06 +00004942 s390_sprintf(buf, "%M if (%C) %s{%I}(%L)", "v-call",
4943 insn->variant.helper_call.cond,
4944 insn->variant.helper_call.name,
4945 insn->variant.helper_call.target,
4946 insn->variant.helper_call.num_args);
4947 return buf; /* avoid printing "size = ..." which is meaningless */
sewardj2019a972011-03-07 16:04:07 +00004948 }
4949
4950 case S390_INSN_BFP_TRIOP:
4951 switch (insn->variant.bfp_triop.tag) {
4952 case S390_BFP_MADD: op = "v-fmadd"; break;
4953 case S390_BFP_MSUB: op = "v-fmsub"; break;
4954 default: goto fail;
4955 }
4956 s390_sprintf(buf, "%M %R,%R,%R,%R", op, insn->variant.bfp_triop.dst,
4957 insn->variant.bfp_triop.dst /* op1 same as dst */,
4958 insn->variant.bfp_triop.op2, insn->variant.bfp_triop.op3);
4959 break;
4960
4961 case S390_INSN_BFP_BINOP:
4962 switch (insn->variant.bfp_binop.tag) {
4963 case S390_BFP_ADD: op = "v-fadd"; break;
4964 case S390_BFP_SUB: op = "v-fsub"; break;
4965 case S390_BFP_MUL: op = "v-fmul"; break;
4966 case S390_BFP_DIV: op = "v-fdiv"; break;
4967 default: goto fail;
4968 }
4969 s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.bfp_binop.dst,
4970 insn->variant.bfp_binop.dst /* op1 same as dst */,
4971 insn->variant.bfp_binop.op2);
4972 break;
4973
4974 case S390_INSN_BFP_COMPARE:
4975 s390_sprintf(buf, "%M %R,%R,%R", "v-fcmp", insn->variant.bfp_compare.dst,
4976 insn->variant.bfp_compare.op1, insn->variant.bfp_compare.op2);
4977 break;
4978
4979 case S390_INSN_BFP_UNOP:
4980 switch (insn->variant.bfp_unop.tag) {
4981 case S390_BFP_ABS: op = "v-fabs"; break;
4982 case S390_BFP_NABS: op = "v-fnabs"; break;
4983 case S390_BFP_NEG: op = "v-fneg"; break;
4984 case S390_BFP_SQRT: op = "v-fsqrt"; break;
4985 case S390_BFP_I32_TO_F32:
4986 case S390_BFP_I32_TO_F64:
4987 case S390_BFP_I32_TO_F128:
4988 case S390_BFP_I64_TO_F32:
4989 case S390_BFP_I64_TO_F64:
4990 case S390_BFP_I64_TO_F128: op = "v-i2f"; break;
4991 case S390_BFP_F32_TO_I32:
4992 case S390_BFP_F32_TO_I64:
4993 case S390_BFP_F64_TO_I32:
4994 case S390_BFP_F64_TO_I64:
4995 case S390_BFP_F128_TO_I32:
4996 case S390_BFP_F128_TO_I64: op = "v-f2i"; break;
4997 case S390_BFP_F32_TO_F64:
4998 case S390_BFP_F32_TO_F128:
4999 case S390_BFP_F64_TO_F32:
5000 case S390_BFP_F64_TO_F128:
5001 case S390_BFP_F128_TO_F32:
5002 case S390_BFP_F128_TO_F64: op = "v-f2f"; break;
5003 default: goto fail;
5004 }
5005 s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp_unop.dst,
5006 insn->variant.bfp_unop.op);
5007 break;
5008
5009 case S390_INSN_BFP128_BINOP:
5010 switch (insn->variant.bfp128_binop.tag) {
5011 case S390_BFP_ADD: op = "v-fadd"; break;
5012 case S390_BFP_SUB: op = "v-fsub"; break;
5013 case S390_BFP_MUL: op = "v-fmul"; break;
5014 case S390_BFP_DIV: op = "v-fdiv"; break;
5015 default: goto fail;
5016 }
5017 /* Only write the register that identifies the register pair */
5018 s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.bfp128_binop.dst_hi,
5019 insn->variant.bfp128_binop.dst_hi /* op1 same as dst */,
5020 insn->variant.bfp128_binop.op2_hi);
5021 break;
5022
5023 case S390_INSN_BFP128_COMPARE:
5024 /* Only write the register that identifies the register pair */
5025 s390_sprintf(buf, "%M %R,%R,%R", "v-fcmp", insn->variant.bfp128_compare.dst,
5026 insn->variant.bfp128_compare.op1_hi,
5027 insn->variant.bfp128_compare.op2_hi);
5028 break;
5029
5030 case S390_INSN_BFP128_UNOP:
5031 case S390_INSN_BFP128_CONVERT_TO:
5032 case S390_INSN_BFP128_CONVERT_FROM:
5033 switch (insn->variant.bfp128_unop.tag) {
5034 case S390_BFP_ABS: op = "v-fabs"; break;
5035 case S390_BFP_NABS: op = "v-fnabs"; break;
5036 case S390_BFP_NEG: op = "v-fneg"; break;
5037 case S390_BFP_SQRT: op = "v-fsqrt"; break;
5038 case S390_BFP_I32_TO_F128:
5039 case S390_BFP_I64_TO_F128: op = "v-i2f"; break;
5040 case S390_BFP_F128_TO_I32:
5041 case S390_BFP_F128_TO_I64: op = "v-f2i"; break;
5042 case S390_BFP_F32_TO_F128:
5043 case S390_BFP_F64_TO_F128:
5044 case S390_BFP_F128_TO_F32:
5045 case S390_BFP_F128_TO_F64: op = "v-f2f"; break;
5046 default: goto fail;
5047 }
5048 /* Only write the register that identifies the register pair */
5049 s390_sprintf(buf, "%M %R,%R", op, insn->variant.bfp128_unop.dst_hi,
5050 insn->variant.bfp128_unop.op_hi);
5051 break;
5052
sewardja52e37e2011-04-28 18:48:06 +00005053 case S390_INSN_MFENCE:
5054 s390_sprintf(buf, "%M", "v-mfence");
5055 return buf; /* avoid printing "size = ..." which is meaningless */
5056
florianad43b3a2012-02-20 15:01:14 +00005057 case S390_INSN_GZERO:
5058 s390_sprintf(buf, "%M %G", "v-gzero", insn->variant.gzero.offset);
5059 break;
5060
5061 case S390_INSN_GADD:
5062 s390_sprintf(buf, "%M %G += %I (= %I)", "v-gadd",
5063 insn->variant.gadd.offset,
5064 (Long)(Char)insn->variant.gadd.delta,
5065 insn->variant.gadd.value);
5066 break;
5067
florian8844a632012-04-13 04:04:06 +00005068 case S390_INSN_EVCHECK:
5069 s390_sprintf(buf, "%M counter = %A, fail-addr = %A", "v-evcheck",
5070 insn->variant.evcheck.counter,
5071 insn->variant.evcheck.fail_addr);
5072 return buf; /* avoid printing "size = ..." which is meaningless */
5073
5074 case S390_INSN_PROFINC:
5075 s390_sprintf(buf, "%M", "v-profinc");
5076 return buf; /* avoid printing "size = ..." which is meaningless */
5077
5078 case S390_INSN_XDIRECT:
5079 s390_sprintf(buf, "%M if (%C) %A = %I %s", "v-xdirect",
5080 insn->variant.xdirect.cond,
5081 insn->variant.xdirect.guest_IA,
5082 insn->variant.xdirect.dst,
5083 insn->variant.xdirect.to_fast_entry ? "fast" : "slow");
5084 return buf; /* avoid printing "size = ..." which is meaningless */
5085
5086 case S390_INSN_XINDIR:
5087 s390_sprintf(buf, "%M if (%C) %A = %R", "v-xindir",
5088 insn->variant.xindir.cond,
5089 insn->variant.xindir.guest_IA,
5090 insn->variant.xindir.dst);
5091 return buf; /* avoid printing "size = ..." which is meaningless */
5092
5093 case S390_INSN_XASSISTED:
5094 s390_sprintf(buf, "%M if (%C) %J %A = %R", "v-xassisted",
5095 insn->variant.xassisted.cond,
5096 insn->variant.xassisted.kind,
5097 insn->variant.xassisted.guest_IA,
5098 insn->variant.xassisted.dst);
5099 return buf; /* avoid printing "size = ..." which is meaningless */
5100
sewardj2019a972011-03-07 16:04:07 +00005101 default: goto fail;
5102 }
5103
5104 /* Write out how many bytes are involved in the operation */
5105
5106 {
5107 UInt len, i;
5108
5109 for (p = buf; *p; ++p)
5110 continue;
5111
5112 len = p - buf;
5113
5114 if (len < 32) {
5115 for (i = len; i < 32; ++i)
5116 p += vex_sprintf(p, " ");
5117 } else {
5118 p += vex_sprintf(p, "\t");
5119 }
5120 }
5121
5122 /* Special cases first */
5123 switch (insn->tag) {
5124 case S390_INSN_UNOP:
5125 switch (insn->variant.unop.tag) {
5126 case S390_SIGN_EXTEND_8:
5127 case S390_ZERO_EXTEND_8: p += vex_sprintf(p, "1 -> "); goto common;
5128 case S390_SIGN_EXTEND_16:
5129 case S390_ZERO_EXTEND_16: p += vex_sprintf(p, "2 -> "); goto common;
5130 case S390_SIGN_EXTEND_32:
5131 case S390_ZERO_EXTEND_32: p += vex_sprintf(p, "4 -> "); goto common;
5132 default:
5133 goto common;
5134 }
5135
5136 case S390_INSN_BFP_UNOP:
5137 switch (insn->variant.bfp_unop.tag) {
5138 case S390_BFP_I32_TO_F32:
5139 case S390_BFP_I32_TO_F64:
5140 case S390_BFP_I32_TO_F128:
5141 case S390_BFP_F32_TO_I32:
5142 case S390_BFP_F32_TO_I64:
5143 case S390_BFP_F32_TO_F64:
5144 case S390_BFP_F32_TO_F128: p += vex_sprintf(p, "4 -> "); goto common;
5145 case S390_BFP_I64_TO_F32:
5146 case S390_BFP_I64_TO_F64:
5147 case S390_BFP_I64_TO_F128:
5148 case S390_BFP_F64_TO_I32:
5149 case S390_BFP_F64_TO_I64:
5150 case S390_BFP_F64_TO_F32:
5151 case S390_BFP_F64_TO_F128: p += vex_sprintf(p, "8 -> "); goto common;
5152 case S390_BFP_F128_TO_I32:
5153 case S390_BFP_F128_TO_I64:
5154 case S390_BFP_F128_TO_F32:
5155 case S390_BFP_F128_TO_F64: p += vex_sprintf(p, "16 -> "); goto common;
5156 default:
5157 goto common;
5158 }
5159
5160 case S390_INSN_BFP128_UNOP:
5161 case S390_INSN_BFP128_CONVERT_TO:
5162 case S390_INSN_BFP128_CONVERT_FROM:
5163 switch (insn->variant.bfp128_unop.tag) {
5164 case S390_BFP_I32_TO_F128:
5165 case S390_BFP_F32_TO_F128: p += vex_sprintf(p, "4 -> "); goto common;
5166 case S390_BFP_I64_TO_F128:
5167 case S390_BFP_F64_TO_F128: p += vex_sprintf(p, "8 -> "); goto common;
5168 case S390_BFP_F128_TO_I32:
5169 case S390_BFP_F128_TO_I64:
5170 case S390_BFP_F128_TO_F32:
5171 case S390_BFP_F128_TO_F64: p += vex_sprintf(p, "16 -> "); goto common;
5172 default:
5173 goto common;
5174 }
5175
5176 default:
5177 goto common;
5178 }
5179
5180 /* Common case */
5181 common:
5182 vex_sprintf(p, "%u bytes", (UInt)insn->size);
5183
5184 return buf;
5185
5186 fail: vpanic("s390_insn_as_string");
5187}
5188
5189
5190
5191/* Load NUM bytes from memory into register REG using addressing mode AM. */
5192static UChar *
5193s390_emit_load_mem(UChar *p, UInt num, UChar reg, const s390_amode *am)
5194{
5195 UInt b = hregNumber(am->b);
5196 UInt x = hregNumber(am->x); /* 0 for B12 and B20 */
5197 UInt d = am->d;
5198
5199 switch (am->tag) {
5200 case S390_AMODE_B12:
5201 case S390_AMODE_BX12:
5202 switch (num) {
5203 case 1: return s390_emit_IC(p, reg, x, b, d);
5204 case 2: return s390_emit_LH(p, reg, x, b, d);
5205 case 4: return s390_emit_L(p, reg, x, b, d);
5206 case 8: return s390_emit_LG(p, reg, x, b, DISP20(d));
5207 default: goto fail;
5208 }
5209 break;
5210
5211 case S390_AMODE_B20:
5212 case S390_AMODE_BX20:
5213 switch (num) {
5214 case 1: return s390_emit_ICY(p, reg, x, b, DISP20(d));
5215 case 2: return s390_emit_LHY(p, reg, x, b, DISP20(d));
5216 case 4: return s390_emit_LY(p, reg, x, b, DISP20(d));
5217 case 8: return s390_emit_LG(p, reg, x, b, DISP20(d));
5218 default: goto fail;
5219 }
5220 break;
5221
5222 default: goto fail;
5223 }
5224
5225 fail:
5226 vpanic("s390_emit_load_mem");
5227}
5228
5229
5230/* Load condition code into register REG */
5231static UChar *
5232s390_emit_load_cc(UChar *p, UChar reg)
5233{
5234 p = s390_emit_LGHI(p, reg, 0); /* Clear out, cc not affected */
5235 p = s390_emit_IPM(p, reg, reg);
5236 /* Shift 28 bits to the right --> [0,1,2,3] */
sewardjf74c86f2011-04-05 14:04:53 +00005237 return s390_emit_SRL(p, reg, 0, 28); /* REG = cc */
sewardj2019a972011-03-07 16:04:07 +00005238}
5239
5240
5241/*---------------------------------------------------------------*/
5242/*--- Code generation ---*/
5243/*---------------------------------------------------------------*/
5244
5245/* Do not load more bytes than requested. */
5246static UChar *
5247s390_insn_load_emit(UChar *buf, const s390_insn *insn)
5248{
5249 UInt r, x, b, d;
5250 const s390_amode *src;
5251
5252 src = insn->variant.load.src;
5253
5254 r = hregNumber(insn->variant.load.dst);
5255
5256 if (hregClass(insn->variant.load.dst) == HRcFlt64) {
5257 b = hregNumber(src->b);
5258 x = hregNumber(src->x); /* 0 for B12 and B20 */
5259 d = src->d;
5260
5261 switch (insn->size) {
5262
5263 case 4:
5264 switch (src->tag) {
5265 case S390_AMODE_B12:
5266 case S390_AMODE_BX12:
5267 return s390_emit_LE(buf, r, x, b, d);
5268
5269 case S390_AMODE_B20:
5270 case S390_AMODE_BX20:
5271 return s390_emit_LEY(buf, r, x, b, DISP20(d));
5272 }
5273 break;
5274
5275 case 8:
5276 switch (src->tag) {
5277 case S390_AMODE_B12:
5278 case S390_AMODE_BX12:
5279 return s390_emit_LD(buf, r, x, b, d);
5280
5281 case S390_AMODE_B20:
5282 case S390_AMODE_BX20:
5283 return s390_emit_LDY(buf, r, x, b, DISP20(d));
5284 }
5285 break;
5286 }
5287 vpanic("s390_insn_load_emit");
5288 }
5289
5290 /* Integer stuff */
5291 return s390_emit_load_mem(buf, insn->size, r, src);
5292}
5293
5294
5295static UChar *
5296s390_insn_store_emit(UChar *buf, const s390_insn *insn)
5297{
5298 UInt r, x, b, d;
5299 const s390_amode *dst;
5300
5301 dst = insn->variant.store.dst;
5302
5303 r = hregNumber(insn->variant.store.src);
5304 b = hregNumber(dst->b);
5305 x = hregNumber(dst->x); /* 0 for B12 and B20 */
5306 d = dst->d;
5307
5308 if (hregClass(insn->variant.store.src) == HRcFlt64) {
5309 switch (insn->size) {
5310
5311 case 4:
5312 switch (dst->tag) {
5313 case S390_AMODE_B12:
5314 case S390_AMODE_BX12:
5315 return s390_emit_STE(buf, r, x, b, d);
5316
5317 case S390_AMODE_B20:
5318 case S390_AMODE_BX20:
5319 return s390_emit_STEY(buf, r, x, b, DISP20(d));
5320 }
5321 break;
5322
5323 case 8:
5324 switch (dst->tag) {
5325 case S390_AMODE_B12:
5326 case S390_AMODE_BX12:
5327 return s390_emit_STD(buf, r, x, b, d);
5328
5329 case S390_AMODE_B20:
5330 case S390_AMODE_BX20:
5331 return s390_emit_STDY(buf, r, x, b, DISP20(d));
5332 }
5333 break;
5334 }
5335 vpanic("s390_insn_store_emit");
5336 }
5337
5338 /* Integer stuff */
5339 switch (insn->size) {
5340 case 1:
5341 switch (dst->tag) {
5342 case S390_AMODE_B12:
5343 case S390_AMODE_BX12:
5344 return s390_emit_STC(buf, r, x, b, d);
5345
5346 case S390_AMODE_B20:
5347 case S390_AMODE_BX20:
5348 return s390_emit_STCY(buf, r, x, b, DISP20(d));
5349 }
5350 break;
5351
5352 case 2:
5353 switch (dst->tag) {
5354 case S390_AMODE_B12:
5355 case S390_AMODE_BX12:
5356 return s390_emit_STH(buf, r, x, b, d);
5357
5358 case S390_AMODE_B20:
5359 case S390_AMODE_BX20:
5360 return s390_emit_STHY(buf, r, x, b, DISP20(d));
5361 }
5362 break;
5363
5364 case 4:
5365 switch (dst->tag) {
5366 case S390_AMODE_B12:
5367 case S390_AMODE_BX12:
5368 return s390_emit_ST(buf, r, x, b, d);
5369
5370 case S390_AMODE_B20:
5371 case S390_AMODE_BX20:
5372 return s390_emit_STY(buf, r, x, b, DISP20(d));
5373 }
5374 break;
5375
5376 case 8:
5377 return s390_emit_STG(buf, r, x, b, DISP20(d));
5378
5379 default:
5380 break;
5381 }
5382
5383 vpanic("s390_insn_store_emit");
5384}
5385
5386
5387static UChar *
5388s390_insn_move_emit(UChar *buf, const s390_insn *insn)
5389{
5390 UInt dst, src;
5391 HRegClass dst_class, src_class;
5392
5393 dst = hregNumber(insn->variant.move.dst);
5394 src = hregNumber(insn->variant.move.src);
5395
5396 dst_class = hregClass(insn->variant.move.dst);
5397 src_class = hregClass(insn->variant.move.src);
5398
5399 if (dst_class == src_class) {
5400 if (dst_class == HRcInt64)
5401 return s390_emit_LGR(buf, dst, src);
5402 if (dst_class == HRcFlt64)
5403 return s390_emit_LDR(buf, dst, src);
5404 } else {
floriana782a172011-12-18 15:51:54 +00005405 if (dst_class == HRcFlt64 && src_class == HRcInt64) {
5406 if (insn->size == 4) {
5407 buf = s390_emit_SLLG(buf, R0, src, 0, DISP20(32)); /* r0 = src << 32 */
5408 return s390_emit_LDGRw(buf, dst, R0);
5409 } else {
5410 return s390_emit_LDGRw(buf, dst, src);
5411 }
5412 }
5413 if (dst_class == HRcInt64 && src_class == HRcFlt64) {
5414 if (insn->size == 4) {
5415 buf = s390_emit_LGDRw(buf, dst, src);
5416 return s390_emit_SRLG(buf, dst, dst, 0, DISP20(32)); /* dst >>= 32 */
5417 } else {
5418 return s390_emit_LGDRw(buf, dst, src);
5419 }
5420 }
sewardj2019a972011-03-07 16:04:07 +00005421 /* A move between floating point registers and general purpose
5422 registers of different size should never occur and indicates
5423 an error elsewhere. */
5424 }
5425
5426 vpanic("s390_insn_move_emit");
5427}
5428
5429
5430static UChar *
5431s390_insn_load_immediate_emit(UChar *buf, const s390_insn *insn)
5432{
5433 UInt r;
5434 ULong value = insn->variant.load_immediate.value;
5435
5436 r = hregNumber(insn->variant.load_immediate.dst);
5437
5438 if (hregClass(insn->variant.load_immediate.dst) == HRcFlt64) {
5439 vassert(value == 0);
5440 switch (insn->size) {
5441 case 4: return s390_emit_LZER(buf, r, value);
5442 case 8: return s390_emit_LZDR(buf, r, value);
5443 }
5444 vpanic("s390_insn_load_immediate_emit");
5445 }
5446
5447 switch (insn->size) {
5448 case 1:
5449 case 2:
5450 /* Load the immediate values as a 4 byte value. That does not hurt as
5451 those extra bytes will not be looked at. Fall through .... */
5452 case 4:
5453 return s390_emit_load_32imm(buf, r, value);
5454
5455 case 8:
5456 return s390_emit_load_64imm(buf, r, value);
5457 }
5458
5459 vpanic("s390_insn_load_immediate_emit");
5460}
5461
5462
5463/* There is no easy way to do ALU operations on 1-byte or 2-byte operands.
5464 So we simply perform a 4-byte operation. Doing so uses possibly undefined
5465 bits and produces an undefined result in those extra bit positions. But
5466 upstream does not look at those positions, so this is OK. */
5467static UChar *
5468s390_insn_alu_emit(UChar *buf, const s390_insn *insn)
5469{
5470 s390_opnd_RMI op2;
5471 UInt dst;
5472
5473 dst = hregNumber(insn->variant.alu.dst);
5474 op2 = insn->variant.alu.op2;
5475
5476 /* Second operand is in a register */
5477 if (op2.tag == S390_OPND_REG) {
5478 UInt r2 = hregNumber(op2.variant.reg);
5479
5480 switch (insn->size) {
5481 case 1:
5482 case 2:
5483 case 4:
5484 switch (insn->variant.alu.tag) {
5485 case S390_ALU_ADD: return s390_emit_AR(buf, dst, r2);
5486 case S390_ALU_SUB: return s390_emit_SR(buf, dst, r2);
5487 case S390_ALU_MUL: return s390_emit_MSR(buf, dst, r2);
5488 case S390_ALU_AND: return s390_emit_NR(buf, dst, r2);
5489 case S390_ALU_OR: return s390_emit_OR(buf, dst, r2);
5490 case S390_ALU_XOR: return s390_emit_XR(buf, dst, r2);
sewardj3c49aaa2011-04-05 14:00:37 +00005491 case S390_ALU_LSH: return s390_emit_SLL(buf, dst, r2, 0);
5492 case S390_ALU_RSH: return s390_emit_SRL(buf, dst, r2, 0);
5493 case S390_ALU_RSHA: return s390_emit_SRA(buf, dst, r2, 0);
sewardj2019a972011-03-07 16:04:07 +00005494 }
5495 goto fail;
5496
5497 case 8:
5498 switch (insn->variant.alu.tag) {
5499 case S390_ALU_ADD: return s390_emit_AGR(buf, dst, r2);
5500 case S390_ALU_SUB: return s390_emit_SGR(buf, dst, r2);
5501 case S390_ALU_MUL: return s390_emit_MSGR(buf, dst, r2);
5502 case S390_ALU_AND: return s390_emit_NGR(buf, dst, r2);
5503 case S390_ALU_OR: return s390_emit_OGR(buf, dst, r2);
5504 case S390_ALU_XOR: return s390_emit_XGR(buf, dst, r2);
5505 case S390_ALU_LSH: return s390_emit_SLLG(buf, dst, dst, r2, DISP20(0));
5506 case S390_ALU_RSH: return s390_emit_SRLG(buf, dst, dst, r2, DISP20(0));
5507 case S390_ALU_RSHA: return s390_emit_SRAG(buf, dst, dst, r2, DISP20(0));
5508 }
5509 goto fail;
5510 }
5511 goto fail;
5512 }
5513
5514 /* 2nd operand is in memory */
5515 if (op2.tag == S390_OPND_AMODE) {
5516 UInt b, x, d;
5517 const s390_amode *src = op2.variant.am;
5518
5519 b = hregNumber(src->b);
5520 x = hregNumber(src->x); /* 0 for B12 and B20 */
5521 d = src->d;
5522
5523 /* Shift operands are special here as there are no opcodes that
sewardje0dd77e2011-04-27 12:07:01 +00005524 allow a memory operand. So we first load the 2nd operand into
5525 some register. R0 is used to save restore the contents of the
5526 chosen register.. */
sewardj652b56a2011-04-13 15:38:17 +00005527
sewardj2019a972011-03-07 16:04:07 +00005528 if (insn->variant.alu.tag == S390_ALU_LSH ||
5529 insn->variant.alu.tag == S390_ALU_RSH ||
5530 insn->variant.alu.tag == S390_ALU_RSHA) {
sewardje0dd77e2011-04-27 12:07:01 +00005531 UInt b2;
sewardj2019a972011-03-07 16:04:07 +00005532
sewardje0dd77e2011-04-27 12:07:01 +00005533 /* Choose a register (other than DST or R0) into which to stick the
5534 shift amount. The following works because r15 is reserved and
5535 thusly dst != 15. */
5536 vassert(dst != 15); /* extra paranoia */
5537 b2 = (dst + 1) % 16;
5538
5539 buf = s390_emit_LGR(buf, R0, b2); /* save */
5540
5541 /* Loading SRC to B2 does not modify R0. */
5542 buf = s390_emit_load_mem(buf, insn->size, b2, src);
sewardj2019a972011-03-07 16:04:07 +00005543
5544 if (insn->size == 8) {
sewardje0dd77e2011-04-27 12:07:01 +00005545 switch (insn->variant.alu.tag) {
5546 case S390_ALU_LSH:
5547 buf = s390_emit_SLLG(buf, dst, dst, b2, DISP20(0));
5548 break;
5549 case S390_ALU_RSH:
5550 buf = s390_emit_SRLG(buf, dst, dst, b2, DISP20(0));
5551 break;
5552 case S390_ALU_RSHA:
5553 buf = s390_emit_SRAG(buf, dst, dst, b2, DISP20(0));
5554 break;
5555 default: /* unreachable */
5556 goto fail;
5557 }
sewardj2019a972011-03-07 16:04:07 +00005558 } else {
sewardje0dd77e2011-04-27 12:07:01 +00005559 switch (insn->variant.alu.tag) {
5560 case S390_ALU_LSH:
5561 buf = s390_emit_SLL(buf, dst, b2, 0);
5562 break;
5563 case S390_ALU_RSH:
5564 buf = s390_emit_SRL(buf, dst, b2, 0);
5565 break;
5566 case S390_ALU_RSHA:
5567 buf = s390_emit_SRA(buf, dst, b2, 0);
5568 break;
5569 default: /* unreachable */
5570 goto fail;
5571 }
sewardj2019a972011-03-07 16:04:07 +00005572 }
sewardje0dd77e2011-04-27 12:07:01 +00005573 return s390_emit_LGR(buf, b2, R0); /* restore */
sewardj2019a972011-03-07 16:04:07 +00005574 }
5575
5576 switch (insn->size) {
5577 case 1:
5578 /* Move the byte from memory into scratch register r0 */
5579 buf = s390_emit_load_mem(buf, 1, R0, src);
5580
5581 switch (insn->variant.alu.tag) {
5582 case S390_ALU_ADD: return s390_emit_AR(buf, dst, R0);
5583 case S390_ALU_SUB: return s390_emit_SR(buf, dst, R0);
5584 case S390_ALU_MUL: return s390_emit_MSR(buf, dst, R0);
5585 case S390_ALU_AND: return s390_emit_NR(buf, dst, R0);
5586 case S390_ALU_OR: return s390_emit_OR(buf, dst, R0);
5587 case S390_ALU_XOR: return s390_emit_XR(buf, dst, R0);
5588 case S390_ALU_LSH:
5589 case S390_ALU_RSH:
5590 case S390_ALU_RSHA: ; /* avoid GCC warning */
5591 }
5592 goto fail;
5593
5594 case 2:
5595 switch (src->tag) {
5596 case S390_AMODE_B12:
5597 case S390_AMODE_BX12:
5598 switch (insn->variant.alu.tag) {
5599 case S390_ALU_ADD:
5600 return s390_emit_AH(buf, dst, x, b, d);
5601
5602 case S390_ALU_SUB:
5603 return s390_emit_SH(buf, dst, x, b, d);
5604
5605 case S390_ALU_MUL:
5606 return s390_emit_MH(buf, dst, x, b, d);
5607
5608 /* For bitwise operations: Move two bytes from memory into scratch
5609 register r0; then perform operation */
5610 case S390_ALU_AND:
5611 buf = s390_emit_LH(buf, R0, x, b, d);
5612 return s390_emit_NR(buf, dst, R0);
5613
5614 case S390_ALU_OR:
5615 buf = s390_emit_LH(buf, R0, x, b, d);
5616 return s390_emit_OR(buf, dst, R0);
5617
5618 case S390_ALU_XOR:
5619 buf = s390_emit_LH(buf, R0, x, b, d);
5620 return s390_emit_XR(buf, dst, R0);
5621
5622 case S390_ALU_LSH:
5623 case S390_ALU_RSH:
5624 case S390_ALU_RSHA: ; /* avoid GCC warning */
5625 }
5626 goto fail;
5627
5628 case S390_AMODE_B20:
5629 case S390_AMODE_BX20:
5630 switch (insn->variant.alu.tag) {
5631 case S390_ALU_ADD:
5632 return s390_emit_AHY(buf, dst, x, b, DISP20(d));
5633
5634 case S390_ALU_SUB:
5635 return s390_emit_SHY(buf, dst, x, b, DISP20(d));
5636
5637 case S390_ALU_MUL:
sewardjeae8db52011-03-24 09:01:50 +00005638 return s390_emit_MHYw(buf, dst, x, b, DISP20(d));
sewardj2019a972011-03-07 16:04:07 +00005639
5640 /* For bitwise operations: Move two bytes from memory into scratch
5641 register r0; then perform operation */
5642 case S390_ALU_AND:
5643 buf = s390_emit_LHY(buf, R0, x, b, DISP20(d));
5644 return s390_emit_NR(buf, dst, R0);
5645
5646 case S390_ALU_OR:
5647 buf = s390_emit_LHY(buf, R0, x, b, DISP20(d));
5648 return s390_emit_OR(buf, dst, R0);
5649
5650 case S390_ALU_XOR:
5651 buf = s390_emit_LHY(buf, R0, x, b, DISP20(d));
5652 return s390_emit_XR(buf, dst, R0);
5653
5654 case S390_ALU_LSH:
5655 case S390_ALU_RSH:
5656 case S390_ALU_RSHA: ; /* avoid GCC warning */
5657 }
5658 goto fail;
5659 }
5660 goto fail;
5661
5662 case 4:
5663 switch (src->tag) {
5664 case S390_AMODE_B12:
5665 case S390_AMODE_BX12:
5666 switch (insn->variant.alu.tag) {
5667 case S390_ALU_ADD: return s390_emit_A(buf, dst, x, b, d);
5668 case S390_ALU_SUB: return s390_emit_S(buf, dst, x, b, d);
5669 case S390_ALU_MUL: return s390_emit_MS(buf, dst, x, b, d);
5670 case S390_ALU_AND: return s390_emit_N(buf, dst, x, b, d);
5671 case S390_ALU_OR: return s390_emit_O(buf, dst, x, b, d);
5672 case S390_ALU_XOR: return s390_emit_X(buf, dst, x, b, d);
5673 case S390_ALU_LSH:
5674 case S390_ALU_RSH:
5675 case S390_ALU_RSHA: ; /* avoid GCC warning */
5676 }
5677 goto fail;
5678
5679 case S390_AMODE_B20:
5680 case S390_AMODE_BX20:
5681 switch (insn->variant.alu.tag) {
5682 case S390_ALU_ADD: return s390_emit_AY(buf, dst, x, b, DISP20(d));
5683 case S390_ALU_SUB: return s390_emit_SY(buf, dst, x, b, DISP20(d));
5684 case S390_ALU_MUL: return s390_emit_MSY(buf, dst, x, b, DISP20(d));
5685 case S390_ALU_AND: return s390_emit_NY(buf, dst, x, b, DISP20(d));
5686 case S390_ALU_OR: return s390_emit_OY(buf, dst, x, b, DISP20(d));
5687 case S390_ALU_XOR: return s390_emit_XY(buf, dst, x, b, DISP20(d));
5688 case S390_ALU_LSH:
5689 case S390_ALU_RSH:
5690 case S390_ALU_RSHA: ; /* avoid GCC warning */
5691 }
5692 goto fail;
5693 }
5694 goto fail;
5695
5696 case 8:
5697 switch (insn->variant.alu.tag) {
5698 case S390_ALU_ADD: return s390_emit_AG(buf, dst, x, b, DISP20(d));
5699 case S390_ALU_SUB: return s390_emit_SG(buf, dst, x, b, DISP20(d));
5700 case S390_ALU_MUL: return s390_emit_MSG(buf, dst, x, b, DISP20(d));
5701 case S390_ALU_AND: return s390_emit_NG(buf, dst, x, b, DISP20(d));
5702 case S390_ALU_OR: return s390_emit_OG(buf, dst, x, b, DISP20(d));
5703 case S390_ALU_XOR: return s390_emit_XG(buf, dst, x, b, DISP20(d));
5704 case S390_ALU_LSH:
5705 case S390_ALU_RSH:
5706 case S390_ALU_RSHA: ; /* avoid GCC warning */
5707 }
5708 goto fail;
5709 }
5710 goto fail;
5711 }
5712
5713 /* 2nd operand is an immediate value */
5714 if (op2.tag == S390_OPND_IMMEDIATE) {
5715 ULong value;
5716
5717 /* No masking of the value is required as it is not sign extended */
5718 value = op2.variant.imm;
5719
5720 switch (insn->size) {
5721 case 1:
5722 case 2:
5723 /* There is no 1-byte opcode. Do the computation in
5724 2 bytes. The extra byte will be ignored. */
5725 switch (insn->variant.alu.tag) {
5726 case S390_ALU_ADD:
5727 return s390_emit_AHI(buf, dst, value);
5728
5729 case S390_ALU_SUB:
sewardjb13a92a2011-04-13 14:44:29 +00005730 return s390_emit_SLFIw(buf, dst, value);
sewardj2019a972011-03-07 16:04:07 +00005731
5732 case S390_ALU_MUL:
5733 return s390_emit_MHI(buf, dst, value);
5734
5735 case S390_ALU_AND: return s390_emit_NILL(buf, dst, value);
5736 case S390_ALU_OR: return s390_emit_OILL(buf, dst, value);
5737 case S390_ALU_XOR:
5738 /* There is no XILL instruction. Load the immediate value into
5739 R0 and combine with the destination register. */
5740 buf = s390_emit_LHI(buf, R0, value);
5741 return s390_emit_XR(buf, dst, R0);
5742
5743 case S390_ALU_LSH:
sewardj3c49aaa2011-04-05 14:00:37 +00005744 return s390_emit_SLL(buf, dst, 0, value);
sewardj2019a972011-03-07 16:04:07 +00005745
5746 case S390_ALU_RSH:
sewardj3c49aaa2011-04-05 14:00:37 +00005747 return s390_emit_SRL(buf, dst, 0, value);
sewardj2019a972011-03-07 16:04:07 +00005748
5749 case S390_ALU_RSHA:
sewardj3c49aaa2011-04-05 14:00:37 +00005750 return s390_emit_SRA(buf, dst, 0, value);
sewardj2019a972011-03-07 16:04:07 +00005751 }
5752 goto fail;
5753
5754 case 4:
5755 switch (insn->variant.alu.tag) {
5756 case S390_ALU_ADD:
5757 if (uint_fits_signed_16bit(value)) {
5758 return s390_emit_AHI(buf, dst, value);
5759 }
5760 return s390_emit_AFIw(buf, dst, value);
5761
5762 case S390_ALU_SUB: return s390_emit_SLFIw(buf, dst, value);
5763 case S390_ALU_MUL: return s390_emit_MSFIw(buf, dst, value);
5764 case S390_ALU_AND: return s390_emit_NILFw(buf, dst, value);
5765 case S390_ALU_OR: return s390_emit_OILFw(buf, dst, value);
5766 case S390_ALU_XOR: return s390_emit_XILFw(buf, dst, value);
sewardj3c49aaa2011-04-05 14:00:37 +00005767 case S390_ALU_LSH: return s390_emit_SLL(buf, dst, 0, value);
5768 case S390_ALU_RSH: return s390_emit_SRL(buf, dst, 0, value);
5769 case S390_ALU_RSHA: return s390_emit_SRA(buf, dst, 0, value);
sewardj2019a972011-03-07 16:04:07 +00005770 }
5771 goto fail;
5772
5773 case 8:
5774 switch (insn->variant.alu.tag) {
5775 case S390_ALU_ADD:
5776 if (ulong_fits_signed_16bit(value)) {
5777 return s390_emit_AGHI(buf, dst, value);
5778 }
5779 if (ulong_fits_signed_32bit(value) && s390_host_has_eimm) {
5780 return s390_emit_AGFI(buf, dst, value);
5781 }
5782 /* Load constant into R0 then add */
5783 buf = s390_emit_load_64imm(buf, R0, value);
5784 return s390_emit_AGR(buf, dst, R0);
5785
5786 case S390_ALU_SUB:
sewardjb13a92a2011-04-13 14:44:29 +00005787 if (ulong_fits_unsigned_32bit(value)) {
5788 return s390_emit_SLGFIw(buf, dst, value);
5789 }
sewardj2019a972011-03-07 16:04:07 +00005790 /* Load value into R0; then subtract from destination reg */
5791 buf = s390_emit_load_64imm(buf, R0, value);
5792 return s390_emit_SGR(buf, dst, R0);
5793
5794 case S390_ALU_MUL:
5795 if (ulong_fits_signed_32bit(value) && s390_host_has_gie) {
5796 return s390_emit_MSGFI(buf, dst, value);
5797 }
5798 /* Load constant into R0 then add */
5799 buf = s390_emit_load_64imm(buf, R0, value);
5800 return s390_emit_MSGR(buf, dst, R0);
5801
5802 /* Do it in two steps: upper half [0:31] and lower half [32:63] */
5803 case S390_ALU_AND:
5804 if (s390_host_has_eimm) {
5805 buf = s390_emit_NIHF(buf, dst, value >> 32);
5806 return s390_emit_NILF(buf, dst, value & 0xFFFFFFFF);
5807 }
5808 /* Load value into R0; then combine with destination reg */
5809 buf = s390_emit_load_64imm(buf, R0, value);
5810 return s390_emit_NGR(buf, dst, R0);
5811
5812 case S390_ALU_OR:
5813 if (s390_host_has_eimm) {
5814 buf = s390_emit_OIHF(buf, dst, value >> 32);
5815 return s390_emit_OILF(buf, dst, value & 0xFFFFFFFF);
5816 }
5817 /* Load value into R0; then combine with destination reg */
5818 buf = s390_emit_load_64imm(buf, R0, value);
5819 return s390_emit_OGR(buf, dst, R0);
5820
5821 case S390_ALU_XOR:
5822 if (s390_host_has_eimm) {
5823 buf = s390_emit_XIHF(buf, dst, value >> 32);
5824 return s390_emit_XILF(buf, dst, value & 0xFFFFFFFF);
5825 }
5826 /* Load value into R0; then combine with destination reg */
5827 buf = s390_emit_load_64imm(buf, R0, value);
5828 return s390_emit_XGR(buf, dst, R0);
5829
sewardj652b56a2011-04-13 15:38:17 +00005830 /* No special considerations for long displacement here. Only the six
5831 least significant bits of VALUE will be taken; all other bits are
5832 ignored. So the DH2 bits are irrelevant and do not influence the
5833 shift operation, independent of whether long-displacement is available
5834 or not. */
sewardj2019a972011-03-07 16:04:07 +00005835 case S390_ALU_LSH: return s390_emit_SLLG(buf, dst, dst, 0, DISP20(value));
5836 case S390_ALU_RSH: return s390_emit_SRLG(buf, dst, dst, 0, DISP20(value));
5837 case S390_ALU_RSHA: return s390_emit_SRAG(buf, dst, dst, 0, DISP20(value));
5838 }
5839 goto fail;
5840 }
5841 goto fail;
5842 }
5843
5844 fail:
5845 vpanic("s390_insn_alu_emit");
5846}
5847
5848
5849static UChar *
5850s390_widen_emit(UChar *buf, const s390_insn *insn, UInt from_size,
5851 Bool sign_extend)
5852{
sewardj06122e72011-03-28 12:14:48 +00005853 s390_opnd_RMI opnd = insn->variant.unop.src;
sewardj2019a972011-03-07 16:04:07 +00005854
5855 switch (opnd.tag) {
5856 case S390_OPND_REG: {
5857 UChar r1 = hregNumber(insn->variant.unop.dst);
5858 UChar r2 = hregNumber(opnd.variant.reg);
5859
5860 switch (from_size) {
5861 case 1:
5862 /* Widening to a half-word is implemented like widening to a word
5863 because the upper half-word will not be looked at. */
5864 if (insn->size == 4 || insn->size == 2) { /* 8 --> 32 8 --> 16 */
5865 if (sign_extend)
5866 return s390_emit_LBRw(buf, r1, r2);
5867 else
5868 return s390_emit_LLCRw(buf, r1, r2);
5869 }
5870 if (insn->size == 8) { /* 8 --> 64 */
5871 if (sign_extend)
5872 return s390_emit_LGBRw(buf, r1, r2);
5873 else
5874 return s390_emit_LLGCRw(buf, r1, r2);
5875 }
5876 goto fail;
5877
5878 case 2:
5879 if (insn->size == 4) { /* 16 --> 32 */
5880 if (sign_extend)
5881 return s390_emit_LHRw(buf, r1, r2);
5882 else
5883 return s390_emit_LLHRw(buf, r1, r2);
5884 }
5885 if (insn->size == 8) { /* 16 --> 64 */
5886 if (sign_extend)
5887 return s390_emit_LGHRw(buf, r1, r2);
5888 else
5889 return s390_emit_LLGHRw(buf, r1, r2);
5890 }
5891 goto fail;
5892
5893 case 4:
5894 if (insn->size == 8) { /* 32 --> 64 */
5895 if (sign_extend)
5896 return s390_emit_LGFR(buf, r1, r2);
5897 else
5898 return s390_emit_LLGFR(buf, r1, r2);
5899 }
5900 goto fail;
5901
5902 default: /* unexpected "from" size */
5903 goto fail;
5904 }
5905 }
5906
5907 case S390_OPND_AMODE: {
5908 UChar r1 = hregNumber(insn->variant.unop.dst);
5909 const s390_amode *src = opnd.variant.am;
5910 UChar b = hregNumber(src->b);
5911 UChar x = hregNumber(src->x);
5912 Int d = src->d;
5913
5914 switch (from_size) {
5915 case 1:
5916 if (insn->size == 4 || insn->size == 2) {
5917 if (sign_extend)
sewardj652b56a2011-04-13 15:38:17 +00005918 return s390_emit_LBw(buf, r1, x, b, DISP20(d));
sewardj2019a972011-03-07 16:04:07 +00005919 else
5920 return s390_emit_LLCw(buf, r1, x, b, DISP20(d));
5921 }
5922 if (insn->size == 8) {
5923 if (sign_extend)
sewardj652b56a2011-04-13 15:38:17 +00005924 return s390_emit_LGBw(buf, r1, x, b, DISP20(d));
sewardj2019a972011-03-07 16:04:07 +00005925 else
sewardj2019a972011-03-07 16:04:07 +00005926 return s390_emit_LLGC(buf, r1, x, b, DISP20(d));
5927 }
5928 goto fail;
5929
5930 case 2:
5931 if (insn->size == 4) { /* 16 --> 32 */
5932 if (sign_extend == 0)
5933 return s390_emit_LLHw(buf, r1, x, b, DISP20(d));
5934
5935 switch (src->tag) {
5936 case S390_AMODE_B12:
5937 case S390_AMODE_BX12:
5938 return s390_emit_LH(buf, r1, x, b, d);
5939
5940 case S390_AMODE_B20:
5941 case S390_AMODE_BX20:
5942 return s390_emit_LHY(buf, r1, x, b, DISP20(d));
5943 }
5944 goto fail;
5945 }
5946 if (insn->size == 8) { /* 16 --> 64 */
sewardj2019a972011-03-07 16:04:07 +00005947 if (sign_extend)
5948 return s390_emit_LGH(buf, r1, x, b, DISP20(d));
5949 else
5950 return s390_emit_LLGH(buf, r1, x, b, DISP20(d));
5951 }
5952 goto fail;
5953
5954 case 4:
5955 if (insn->size == 8) { /* 32 --> 64 */
sewardj2019a972011-03-07 16:04:07 +00005956 if (sign_extend)
5957 return s390_emit_LGF(buf, r1, x, b, DISP20(d));
5958 else
5959 return s390_emit_LLGF(buf, r1, x, b, DISP20(d));
5960 }
5961 goto fail;
5962
5963 default: /* unexpected "from" size */
5964 goto fail;
5965 }
5966 }
5967
5968 case S390_OPND_IMMEDIATE: {
5969 UChar r1 = hregNumber(insn->variant.unop.dst);
5970 ULong value = opnd.variant.imm;
5971
5972 switch (from_size) {
5973 case 1:
5974 if (insn->size == 4 || insn->size == 2) { /* 8 --> 32 8 --> 16 */
5975 if (sign_extend) {
5976 /* host can do the sign extension to 16-bit; LHI does the rest */
5977 return s390_emit_LHI(buf, r1, (Short)(Char)(UChar)value);
5978 } else {
5979 return s390_emit_LHI(buf, r1, value);
5980 }
5981 }
5982 if (insn->size == 8) { /* 8 --> 64 */
5983 if (sign_extend) {
5984 /* host can do the sign extension to 16-bit; LGHI does the rest */
5985 return s390_emit_LGHI(buf, r1, (Short)(Char)(UChar)value);
5986 } else {
5987 return s390_emit_LGHI(buf, r1, value);
5988 }
5989 }
5990 goto fail;
5991
5992 case 2:
5993 if (insn->size == 4) { /* 16 --> 32 */
5994 return s390_emit_LHI(buf, r1, value);
5995 }
5996 if (insn->size == 8) { /* 16 --> 64 */
5997 if (sign_extend)
5998 return s390_emit_LGHI(buf, r1, value);
5999 else
6000 return s390_emit_LLILL(buf, r1, value);
6001 }
6002 goto fail;
6003
6004 case 4:
6005 if (insn->size == 8) { /* 32 --> 64 */
6006 if (sign_extend)
6007 return s390_emit_LGFIw(buf, r1, value);
6008 else
6009 return s390_emit_LLILFw(buf, r1, value);
6010 }
6011 goto fail;
6012
6013 default: /* unexpected "from" size */
6014 goto fail;
6015 }
6016 }
6017 }
6018
6019 fail:
6020 vpanic("s390_widen_emit");
6021}
6022
6023
6024static UChar *
6025s390_negate_emit(UChar *buf, const s390_insn *insn)
6026{
6027 s390_opnd_RMI opnd;
6028
6029 opnd = insn->variant.unop.src;
6030
6031 switch (opnd.tag) {
6032 case S390_OPND_REG: {
6033 UChar r1 = hregNumber(insn->variant.unop.dst);
6034 UChar r2 = hregNumber(opnd.variant.reg);
6035
6036 switch (insn->size) {
6037 case 1:
6038 case 2:
6039 case 4:
6040 return s390_emit_LCR(buf, r1, r2);
6041
6042 case 8:
6043 return s390_emit_LCGR(buf, r1, r2);
6044
6045 default:
6046 goto fail;
6047 }
6048 }
6049
6050 case S390_OPND_AMODE: {
6051 UChar r1 = hregNumber(insn->variant.unop.dst);
6052
6053 /* Load bytes into scratch register R0, then negate */
6054 buf = s390_emit_load_mem(buf, insn->size, R0, opnd.variant.am);
6055
6056 switch (insn->size) {
6057 case 1:
6058 case 2:
6059 case 4:
6060 return s390_emit_LCR(buf, r1, R0);
6061
6062 case 8:
6063 return s390_emit_LCGR(buf, r1, R0);
6064
6065 default:
6066 goto fail;
6067 }
6068 }
6069
6070 case S390_OPND_IMMEDIATE: {
6071 UChar r1 = hregNumber(insn->variant.unop.dst);
6072 ULong value = opnd.variant.imm;
6073
6074 value = ~value + 1; /* two's complement */
6075
6076 switch (insn->size) {
6077 case 1:
6078 case 2:
6079 /* Load the immediate values as a 4 byte value. That does not hurt as
6080 those extra bytes will not be looked at. Fall through .... */
6081 case 4:
6082 return s390_emit_load_32imm(buf, r1, value);
6083
6084 case 8:
6085 return s390_emit_load_64imm(buf, r1, value);
6086
6087 default:
6088 goto fail;
6089 }
6090 }
6091 }
6092
6093 fail:
6094 vpanic("s390_negate_emit");
6095}
6096
6097
6098static UChar *
6099s390_insn_unop_emit(UChar *buf, const s390_insn *insn)
6100{
6101 switch (insn->variant.unop.tag) {
6102 case S390_ZERO_EXTEND_8: return s390_widen_emit(buf, insn, 1, 0);
6103 case S390_ZERO_EXTEND_16: return s390_widen_emit(buf, insn, 2, 0);
6104 case S390_ZERO_EXTEND_32: return s390_widen_emit(buf, insn, 4, 0);
6105
6106 case S390_SIGN_EXTEND_8: return s390_widen_emit(buf, insn, 1, 1);
6107 case S390_SIGN_EXTEND_16: return s390_widen_emit(buf, insn, 2, 1);
6108 case S390_SIGN_EXTEND_32: return s390_widen_emit(buf, insn, 4, 1);
6109
6110 case S390_NEGATE: return s390_negate_emit(buf, insn);
6111 }
6112
6113 vpanic("s390_insn_unop_emit");
6114}
6115
6116
6117/* Only 4-byte and 8-byte operands are handled. 1-byte and 2-byte
6118 comparisons will have been converted to 4-byte comparisons in
6119 s390_isel_cc and should not occur here. */
6120static UChar *
6121s390_insn_test_emit(UChar *buf, const s390_insn *insn)
6122{
6123 s390_opnd_RMI opnd;
6124
6125 opnd = insn->variant.test.src;
6126
6127 switch (opnd.tag) {
6128 case S390_OPND_REG: {
6129 UInt reg = hregNumber(opnd.variant.reg);
6130
6131 switch (insn->size) {
6132 case 4:
6133 return s390_emit_LTR(buf, reg, reg);
6134
6135 case 8:
6136 return s390_emit_LTGR(buf, reg, reg);
6137
6138 default:
6139 goto fail;
6140 }
6141 }
6142
6143 case S390_OPND_AMODE: {
6144 const s390_amode *am = opnd.variant.am;
6145 UChar b = hregNumber(am->b);
6146 UChar x = hregNumber(am->x);
6147 Int d = am->d;
6148
6149 switch (insn->size) {
6150 case 4:
6151 return s390_emit_LTw(buf, R0, x, b, DISP20(d));
6152
6153 case 8:
6154 return s390_emit_LTGw(buf, R0, x, b, DISP20(d));
6155
6156 default:
6157 goto fail;
6158 }
6159 }
6160
6161 case S390_OPND_IMMEDIATE: {
6162 ULong value = opnd.variant.imm;
6163
6164 switch (insn->size) {
6165 case 4:
6166 buf = s390_emit_load_32imm(buf, R0, value);
6167 return s390_emit_LTR(buf, R0, R0);
6168
6169 case 8:
6170 buf = s390_emit_load_64imm(buf, R0, value);
6171 return s390_emit_LTGR(buf, R0, R0);
6172
6173 default:
6174 goto fail;
6175 }
6176 }
6177
6178 default:
6179 goto fail;
6180 }
6181
6182 fail:
6183 vpanic("s390_insn_test_emit");
6184}
6185
6186
6187static UChar *
6188s390_insn_cc2bool_emit(UChar *buf, const s390_insn *insn)
6189{
6190 UChar r1 = hregNumber(insn->variant.cc2bool.dst);
6191 s390_cc_t cond = insn->variant.cc2bool.cond;
6192
6193 /* Make the destination register be 1 or 0, depending on whether
6194 the relevant condition holds. A 64-bit value is computed. */
6195 if (cond == S390_CC_ALWAYS)
6196 return s390_emit_LGHI(buf, r1, 1); /* r1 = 1 */
6197
6198 buf = s390_emit_load_cc(buf, r1); /* r1 = cc */
6199 buf = s390_emit_LGHI(buf, R0, cond); /* r0 = mask */
6200 buf = s390_emit_SLLG(buf, r1, R0, r1, DISP20(0)); /* r1 = mask << cc */
6201 buf = s390_emit_SRLG(buf, r1, r1, 0, DISP20(3)); /* r1 = r1 >> 3 */
6202 buf = s390_emit_NILL(buf, r1, 1); /* r1 = r1 & 0x1 */
6203
6204 return buf;
6205}
6206
6207
6208/* Only 4-byte and 8-byte operands are handled. */
6209static UChar *
6210s390_insn_cas_emit(UChar *buf, const s390_insn *insn)
6211{
6212 UChar r1, r3, b, old;
6213 Int d;
6214 s390_amode *am;
6215
6216 r1 = hregNumber(insn->variant.cas.op1); /* expected value */
6217 r3 = hregNumber(insn->variant.cas.op3);
6218 old= hregNumber(insn->variant.cas.old_mem);
6219 am = insn->variant.cas.op2;
6220 b = hregNumber(am->b);
6221 d = am->d;
6222
6223 switch (insn->size) {
6224 case 4:
6225 /* r1 must no be overwritten. So copy it to R0 and let CS clobber it */
6226 buf = s390_emit_LR(buf, R0, r1);
6227 if (am->tag == S390_AMODE_B12)
6228 buf = s390_emit_CS(buf, R0, r3, b, d);
6229 else
6230 buf = s390_emit_CSY(buf, R0, r3, b, DISP20(d));
6231 /* Now copy R0 which has the old memory value to OLD */
6232 return s390_emit_LR(buf, old, R0);
6233
6234 case 8:
6235 /* r1 must no be overwritten. So copy it to R0 and let CS clobber it */
6236 buf = s390_emit_LGR(buf, R0, r1);
6237 buf = s390_emit_CSG(buf, R0, r3, b, DISP20(d));
6238 /* Now copy R0 which has the old memory value to OLD */
6239 return s390_emit_LGR(buf, old, R0);
6240
6241 default:
6242 goto fail;
6243 }
6244
6245 fail:
6246 vpanic("s390_insn_cas_emit");
6247}
6248
6249
6250/* Only 4-byte and 8-byte comparisons are handled. 1-byte and 2-byte
6251 comparisons will have been converted to 4-byte comparisons in
6252 s390_isel_cc and should not occur here. */
6253static UChar *
6254s390_insn_compare_emit(UChar *buf, const s390_insn *insn)
6255{
6256 s390_opnd_RMI op2;
6257 HReg op1;
6258 Bool signed_comparison;
6259
6260 op1 = insn->variant.compare.src1;
6261 op2 = insn->variant.compare.src2;
6262 signed_comparison = insn->variant.compare.signed_comparison;
6263
6264 switch (op2.tag) {
6265 case S390_OPND_REG: {
6266 UInt r1 = hregNumber(op1);
6267 UInt r2 = hregNumber(op2.variant.reg);
6268
6269 switch (insn->size) {
6270 case 4:
6271 if (signed_comparison)
6272 return s390_emit_CR(buf, r1, r2);
6273 else
6274 return s390_emit_CLR(buf, r1, r2);
6275
6276 case 8:
6277 if (signed_comparison)
6278 return s390_emit_CGR(buf, r1, r2);
6279 else
6280 return s390_emit_CLGR(buf, r1, r2);
6281
6282 default:
6283 goto fail;
6284 }
6285 }
6286
6287 case S390_OPND_AMODE: {
6288 UChar r1 = hregNumber(op1);
6289 const s390_amode *am = op2.variant.am;
6290 UChar b = hregNumber(am->b);
6291 UChar x = hregNumber(am->x);
6292 Int d = am->d;
6293
6294 switch (insn->size) {
6295 case 4:
6296 switch (am->tag) {
6297 case S390_AMODE_B12:
6298 case S390_AMODE_BX12:
6299 if (signed_comparison)
6300 return s390_emit_C(buf, r1, x, b, d);
6301 else
6302 return s390_emit_CL(buf, r1, x, b, d);
6303
6304 case S390_AMODE_B20:
6305 case S390_AMODE_BX20:
6306 if (signed_comparison)
6307 return s390_emit_CY(buf, r1, x, b, DISP20(d));
6308 else
6309 return s390_emit_CLY(buf, r1, x, b, DISP20(d));
6310 }
6311 goto fail;
6312
6313 case 8:
6314 if (signed_comparison)
6315 return s390_emit_CG(buf, r1, x, b, DISP20(d));
6316 else
6317 return s390_emit_CLG(buf, r1, x, b, DISP20(d));
6318
6319 default:
6320 goto fail;
6321 }
6322 }
6323
6324 case S390_OPND_IMMEDIATE: {
6325 UChar r1 = hregNumber(op1);
6326 ULong value = op2.variant.imm;
6327
6328 switch (insn->size) {
6329 case 4:
6330 if (signed_comparison)
6331 return s390_emit_CFIw(buf, r1, value);
6332 else
6333 return s390_emit_CLFIw(buf, r1, value);
6334
6335 case 8:
florian07d34552012-05-26 01:59:21 +00006336 if (s390_host_has_eimm) {
6337 if (signed_comparison) {
6338 if (ulong_fits_signed_32bit(value))
6339 return s390_emit_CGFI(buf, r1, value);
6340 } else {
6341 if (ulong_fits_unsigned_32bit(value))
6342 return s390_emit_CLGFI(buf, r1, value);
6343 }
6344 }
sewardj2019a972011-03-07 16:04:07 +00006345 buf = s390_emit_load_64imm(buf, R0, value);
6346 if (signed_comparison)
6347 return s390_emit_CGR(buf, r1, R0);
6348 else
6349 return s390_emit_CLGR(buf, r1, R0);
6350
6351 default:
6352 goto fail;
6353 }
6354 }
6355
6356 default:
6357 goto fail;
6358 }
6359
6360 fail:
6361 vpanic("s390_insn_compare_emit");
6362}
6363
6364
6365static UChar *
6366s390_insn_mul_emit(UChar *buf, const s390_insn *insn)
6367{
6368 s390_opnd_RMI op2;
6369 UChar r1;
6370 Bool signed_multiply;
6371
6372 /* The register number identifying the register pair */
6373 r1 = hregNumber(insn->variant.mul.dst_hi);
6374
6375 op2 = insn->variant.mul.op2;
6376 signed_multiply = insn->variant.mul.signed_multiply;
6377
6378 switch (op2.tag) {
6379 case S390_OPND_REG: {
6380 UInt r2 = hregNumber(op2.variant.reg);
6381
6382 switch (insn->size) {
6383 case 1:
6384 case 2:
6385 case 4:
6386 if (signed_multiply)
6387 return s390_emit_MR(buf, r1, r2);
6388 else
6389 return s390_emit_MLR(buf, r1, r2);
6390
6391 case 8:
6392 if (signed_multiply)
6393 vpanic("s390_insn_mul_emit");
6394 else
6395 return s390_emit_MLGR(buf, r1, r2);
6396
6397 default:
6398 goto fail;
6399 }
6400 }
6401
6402 case S390_OPND_AMODE: {
6403 const s390_amode *am = op2.variant.am;
6404 UChar b = hregNumber(am->b);
6405 UChar x = hregNumber(am->x);
6406 Int d = am->d;
6407
6408 switch (insn->size) {
6409 case 1:
6410 case 2:
6411 /* Load bytes into scratch register R0, then multiply */
6412 buf = s390_emit_load_mem(buf, insn->size, R0, am);
6413 if (signed_multiply)
6414 return s390_emit_MR(buf, r1, R0);
6415 else
6416 return s390_emit_MLR(buf, r1, R0);
6417
6418 case 4:
6419 switch (am->tag) {
6420 case S390_AMODE_B12:
6421 case S390_AMODE_BX12:
6422 if (signed_multiply)
6423 return s390_emit_M(buf, r1, x, b, d);
6424 else
6425 return s390_emit_ML(buf, r1, x, b, DISP20(d));
6426
6427 case S390_AMODE_B20:
6428 case S390_AMODE_BX20:
6429 if (signed_multiply)
6430 return s390_emit_MFYw(buf, r1, x, b, DISP20(d));
6431 else
sewardjb13a92a2011-04-13 14:44:29 +00006432 return s390_emit_ML(buf, r1, x, b, DISP20(d));
sewardj2019a972011-03-07 16:04:07 +00006433 }
6434 goto fail;
6435
6436 case 8:
6437 if (signed_multiply)
6438 vpanic("s390_insn_mul_emit");
6439 else
6440 return s390_emit_MLG(buf, r1, x, b, DISP20(d));
6441
6442 default:
6443 goto fail;
6444 }
6445 }
6446
6447 case S390_OPND_IMMEDIATE: {
6448 ULong value = op2.variant.imm;
6449
6450 switch (insn->size) {
6451 case 1:
6452 case 2:
6453 case 4:
6454 buf = s390_emit_load_32imm(buf, R0, value);
6455 if (signed_multiply)
6456 return s390_emit_MR(buf, r1, R0);
6457 else
6458 return s390_emit_MLR(buf, r1, R0);
6459
6460 case 8:
6461 buf = s390_emit_load_64imm(buf, R0, value);
6462 if (signed_multiply)
6463 vpanic("s390_insn_mul_emit");
6464 else
6465 return s390_emit_MLGR(buf, r1, R0);
6466
6467 default:
6468 goto fail;
6469 }
6470 }
6471
6472 default:
6473 goto fail;
6474 }
6475
6476 fail:
6477 vpanic("s390_insn_mul_emit");
6478}
6479
6480
6481static UChar *
6482s390_insn_div_emit(UChar *buf, const s390_insn *insn)
6483{
6484 s390_opnd_RMI op2;
6485 UChar r1;
6486 Bool signed_divide;
6487
6488 r1 = hregNumber(insn->variant.div.op1_hi);
6489 op2 = insn->variant.div.op2;
6490 signed_divide = insn->variant.div.signed_divide;
6491
6492 switch (op2.tag) {
6493 case S390_OPND_REG: {
6494 UInt r2 = hregNumber(op2.variant.reg);
6495
6496 switch (insn->size) {
6497 case 4:
6498 if (signed_divide)
6499 return s390_emit_DR(buf, r1, r2);
6500 else
6501 return s390_emit_DLR(buf, r1, r2);
6502
6503 case 8:
6504 if (signed_divide)
6505 vpanic("s390_insn_div_emit");
6506 else
6507 return s390_emit_DLGR(buf, r1, r2);
6508
6509 default:
6510 goto fail;
6511 }
6512 }
6513
6514 case S390_OPND_AMODE: {
6515 const s390_amode *am = op2.variant.am;
6516 UChar b = hregNumber(am->b);
6517 UChar x = hregNumber(am->x);
6518 Int d = am->d;
6519
6520 switch (insn->size) {
6521 case 4:
6522 switch (am->tag) {
6523 case S390_AMODE_B12:
6524 case S390_AMODE_BX12:
6525 if (signed_divide)
6526 return s390_emit_D(buf, r1, x, b, d);
6527 else
6528 return s390_emit_DL(buf, r1, x, b, DISP20(d));
6529
6530 case S390_AMODE_B20:
6531 case S390_AMODE_BX20:
sewardjb13a92a2011-04-13 14:44:29 +00006532 if (signed_divide) {
6533 buf = s390_emit_LY(buf, R0, x, b, DISP20(d));
sewardj2019a972011-03-07 16:04:07 +00006534 return s390_emit_DR(buf, r1, R0);
sewardjb13a92a2011-04-13 14:44:29 +00006535 } else
6536 return s390_emit_DL(buf, r1, x, b, DISP20(d));
sewardj2019a972011-03-07 16:04:07 +00006537 }
6538 goto fail;
6539
6540 case 8:
6541 if (signed_divide)
6542 vpanic("s390_insn_div_emit");
6543 else
6544 return s390_emit_DLG(buf, r1, x, b, DISP20(d));
6545
6546 default:
6547 goto fail;
6548 }
6549 }
6550
6551 case S390_OPND_IMMEDIATE: {
6552 ULong value = op2.variant.imm;
6553
6554 switch (insn->size) {
6555 case 4:
6556 buf = s390_emit_load_32imm(buf, R0, value);
6557 if (signed_divide)
6558 return s390_emit_DR(buf, r1, R0);
6559 else
6560 return s390_emit_DLR(buf, r1, R0);
6561
6562 case 8:
6563 buf = s390_emit_load_64imm(buf, R0, value);
6564 if (signed_divide)
6565 vpanic("s390_insn_div_emit");
6566 else
6567 return s390_emit_DLGR(buf, r1, R0);
6568
6569 default:
6570 goto fail;
6571 }
6572 }
6573
6574 default:
6575 goto fail;
6576 }
6577
6578 fail:
6579 vpanic("s390_insn_div_emit");
6580}
6581
6582
6583static UChar *
6584s390_insn_divs_emit(UChar *buf, const s390_insn *insn)
6585{
6586 s390_opnd_RMI op2;
6587 UChar r1;
6588
6589 r1 = hregNumber(insn->variant.divs.rem);
6590 op2 = insn->variant.divs.op2;
6591
6592 switch (op2.tag) {
6593 case S390_OPND_REG: {
6594 UInt r2 = hregNumber(op2.variant.reg);
6595
6596 return s390_emit_DSGR(buf, r1, r2);
6597 }
6598
6599 case S390_OPND_AMODE: {
6600 const s390_amode *am = op2.variant.am;
6601 UChar b = hregNumber(am->b);
6602 UChar x = hregNumber(am->x);
6603 Int d = am->d;
6604
6605 return s390_emit_DSG(buf, r1, x, b, DISP20(d));
6606 }
6607
6608 case S390_OPND_IMMEDIATE: {
6609 ULong value = op2.variant.imm;
6610
6611 buf = s390_emit_load_64imm(buf, R0, value);
6612 return s390_emit_DSGR(buf, r1, R0);
6613 }
6614
6615 default:
6616 goto fail;
6617 }
6618
6619 fail:
6620 vpanic("s390_insn_divs_emit");
6621}
6622
6623
6624static UChar *
sewardj611b06e2011-03-24 08:57:29 +00006625s390_insn_clz_emit(UChar *buf, const s390_insn *insn)
sewardj2019a972011-03-07 16:04:07 +00006626{
6627 s390_opnd_RMI src;
sewardj611b06e2011-03-24 08:57:29 +00006628 UChar r1, r1p1, r2, *p;
sewardj2019a972011-03-07 16:04:07 +00006629
sewardj611b06e2011-03-24 08:57:29 +00006630 r1 = hregNumber(insn->variant.clz.num_bits);
6631 r1p1 = hregNumber(insn->variant.clz.clobber);
sewardj2019a972011-03-07 16:04:07 +00006632
6633 vassert((r1 & 0x1) == 0);
6634 vassert(r1p1 == r1 + 1);
6635
sewardj611b06e2011-03-24 08:57:29 +00006636 p = buf;
6637 src = insn->variant.clz.src;
sewardj2019a972011-03-07 16:04:07 +00006638
sewardj611b06e2011-03-24 08:57:29 +00006639 /* Get operand and move it to r2 */
sewardj2019a972011-03-07 16:04:07 +00006640 switch (src.tag) {
sewardj611b06e2011-03-24 08:57:29 +00006641 case S390_OPND_REG:
6642 r2 = hregNumber(src.variant.reg);
6643 break;
sewardj2019a972011-03-07 16:04:07 +00006644
6645 case S390_OPND_AMODE: {
6646 const s390_amode *am = src.variant.am;
6647 UChar b = hregNumber(am->b);
6648 UChar x = hregNumber(am->x);
6649 Int d = am->d;
6650
sewardj611b06e2011-03-24 08:57:29 +00006651 p = s390_emit_LG(p, R0, x, b, DISP20(d));
6652 r2 = R0;
6653 break;
sewardj2019a972011-03-07 16:04:07 +00006654 }
6655
6656 case S390_OPND_IMMEDIATE: {
6657 ULong value = src.variant.imm;
6658
sewardj611b06e2011-03-24 08:57:29 +00006659 p = s390_emit_load_64imm(p, R0, value);
6660 r2 = R0;
6661 break;
sewardj2019a972011-03-07 16:04:07 +00006662 }
6663
6664 default:
6665 goto fail;
6666 }
6667
sewardj611b06e2011-03-24 08:57:29 +00006668 /* Use FLOGR if you can */
6669 if (s390_host_has_eimm) {
6670 return s390_emit_FLOGR(p, r1, r2);
6671 }
6672
6673 /*
6674 r0 = r2;
6675 r1 = 64;
6676 while (r0 != 0) {
6677 r1 -= 1;
6678 r0 >>= 1;
6679 }
6680 */
6681 p = s390_emit_LTGR(p, R0, r2);
6682 p = s390_emit_LLILL(p, r1, 64);
6683
6684 p = s390_emit_BRC(p, S390_CC_E, (4 + 4 + 6 + 4 + 4)/ 2); /* 4 bytes */
6685 p = s390_emit_AGHI(p, r1, (UShort)-1); /* r1 -= 1; 4 bytes */
6686 p = s390_emit_SRLG(p, R0, R0, R0, DISP20(1)); /* r0 >>= 1; 6 bytes */
6687 p = s390_emit_LTGR(p, R0, R0); /* set cc 4 bytes */
6688 p = s390_emit_BRC(p, S390_CC_NE, /* 4 bytes */
6689 (UShort)(-(4 + 6 + 4) / 2));
6690 return p;
6691
sewardj2019a972011-03-07 16:04:07 +00006692 fail:
sewardj611b06e2011-03-24 08:57:29 +00006693 vpanic("s390_insn_clz_emit");
sewardj2019a972011-03-07 16:04:07 +00006694}
6695
6696
6697static UChar *
sewardj2019a972011-03-07 16:04:07 +00006698s390_insn_helper_call_emit(UChar *buf, const s390_insn *insn)
6699{
6700 s390_cc_t cond;
6701 ULong target;
6702 UChar *ptmp = buf;
6703
6704 cond = insn->variant.helper_call.cond;
6705 target = insn->variant.helper_call.target;
6706
6707 if (cond != S390_CC_ALWAYS) {
6708 /* So we have something like this
6709 if (cond) call X;
6710 Y: ...
6711 We convert this into
6712 if (! cond) goto Y; // BRC opcode; 4 bytes
6713 call X;
6714 Y:
6715 */
6716 /* 4 bytes (a BRC insn) to be filled in here */
6717 buf += 4;
6718 }
6719
6720 /* Load the target address into a register, that
6721 (a) is not used for passing parameters to the helper and
6722 (b) can be clobbered by the callee
6723 r1 looks like a good choice.
6724 Also, need to arrange for the return address be put into the
6725 link-register */
6726 buf = s390_emit_load_64imm(buf, 1, target);
6727
6728 /* Stash away the client's FPC register because the helper might change it. */
6729 buf = s390_emit_STFPC(buf, S390_REGNO_STACK_POINTER, S390_OFFSET_SAVED_FPC_C);
6730
6731 /* Before we can call the helper, we need to save the link register,
6732 because the BASR will overwrite it. We cannot use a register for that.
6733 (a) Volatile registers will be modified by the helper.
6734 (b) For saved registers the client code assumes that they have not
6735 changed after the function returns. So we cannot use it to store
6736 the link register.
6737 In the dispatcher, before calling the client code, we have arranged for
6738 a location on the stack for this purpose. See dispatch-s390x-linux.S. */
6739 buf = s390_emit_STG(buf, S390_REGNO_LINK_REGISTER, 0, // save LR
6740 S390_REGNO_STACK_POINTER, S390_OFFSET_SAVED_LR, 0);
6741 buf = s390_emit_BASR(buf, S390_REGNO_LINK_REGISTER, 1); // call helper
6742 buf = s390_emit_LG(buf, S390_REGNO_LINK_REGISTER, 0, // restore LR
6743 S390_REGNO_STACK_POINTER, S390_OFFSET_SAVED_LR, 0);
6744 buf = s390_emit_LFPC(buf, S390_REGNO_STACK_POINTER, // restore FPC
6745 S390_OFFSET_SAVED_FPC_C);
6746
6747 if (cond != S390_CC_ALWAYS) {
6748 Int delta = buf - ptmp;
6749
6750 delta >>= 1; /* immediate constant is #half-words */
6751 vassert(delta > 0 && delta < (1 << 16));
6752 s390_emit_BRC(ptmp, s390_cc_invert(cond), delta);
6753 }
6754
6755 return buf;
6756}
6757
6758
6759static UChar *
6760s390_insn_cond_move_emit(UChar *buf, const s390_insn *insn)
6761{
6762 HReg dst;
6763 s390_opnd_RMI src;
6764 s390_cc_t cond;
6765 UChar *p, *ptmp = 0; /* avoid compiler warnings */
6766
6767 cond = insn->variant.cond_move.cond;
6768 dst = insn->variant.cond_move.dst;
6769 src = insn->variant.cond_move.src;
6770
6771 p = buf;
6772
6773 /* Branch (if cond fails) over move instrs */
6774 if (cond != S390_CC_ALWAYS) {
6775 /* Don't know how many bytes to jump over yet.
6776 Make space for a BRC instruction (4 bytes) and fill in later. */
6777 ptmp = p; /* to be filled in here */
6778 p += 4;
6779 }
6780
6781 // cond true: move src => dst
6782
6783 switch (src.tag) {
6784 case S390_OPND_REG:
6785 p = s390_emit_LGR(p, hregNumber(dst), hregNumber(src.variant.reg));
6786 break;
6787
6788 case S390_OPND_AMODE:
6789 p = s390_emit_load_mem(p, insn->size, hregNumber(dst), src.variant.am);
6790 break;
6791
6792 case S390_OPND_IMMEDIATE: {
6793 ULong value = src.variant.imm;
6794 UInt r = hregNumber(dst);
6795
6796 switch (insn->size) {
6797 case 1:
6798 case 2:
6799 /* Load the immediate values as a 4 byte value. That does not hurt as
6800 those extra bytes will not be looked at. Fall through .... */
6801 case 4:
6802 p = s390_emit_load_32imm(p, r, value);
6803 break;
6804
6805 case 8:
6806 p = s390_emit_load_64imm(p, r, value);
6807 break;
6808 }
6809 break;
6810 }
6811
6812 default:
6813 goto fail;
6814 }
6815
6816 if (cond != S390_CC_ALWAYS) {
6817 Int delta = p - ptmp;
6818
6819 delta >>= 1; /* immediate constant is #half-words */
6820 vassert(delta > 0 && delta < (1 << 16));
6821 s390_emit_BRC(ptmp, s390_cc_invert(cond), delta);
6822 }
6823
6824 return p;
6825
6826 fail:
6827 vpanic("s390_insn_cond_move_emit");
6828}
6829
6830
6831/* Little helper function to the rounding mode in the real FPC
6832 register */
6833static UChar *
6834s390_set_fpc_rounding_mode(UChar *buf, s390_round_t rounding_mode)
6835{
6836 UChar bits;
6837
6838 /* Determine BFP rounding bits */
6839 switch (rounding_mode) {
6840 case S390_ROUND_NEAREST_EVEN: bits = 0; break;
6841 case S390_ROUND_ZERO: bits = 1; break;
6842 case S390_ROUND_POSINF: bits = 2; break;
6843 case S390_ROUND_NEGINF: bits = 3; break;
6844 default: vpanic("invalid rounding mode\n");
6845 }
6846
6847 /* Copy FPC from guest state to R0 and OR in the new rounding mode */
6848 buf = s390_emit_L(buf, R0, 0, S390_REGNO_GUEST_STATE_POINTER,
florian428dfdd2012-03-27 03:09:49 +00006849 S390X_GUEST_OFFSET(guest_fpc)); // r0 = guest_fpc
sewardj2019a972011-03-07 16:04:07 +00006850
6851 buf = s390_emit_NILL(buf, R0, 0xFFFC); /* Clear out right-most 2 bits */
6852 buf = s390_emit_OILL(buf, R0, bits); /* OR in the new rounding mode */
6853 buf = s390_emit_SFPC(buf, R0, 0); /* Load FPC register from R0 */
6854
6855 return buf;
6856}
6857
6858
6859static UChar *
6860s390_insn_bfp_triop_emit(UChar *buf, const s390_insn *insn)
6861{
6862 UInt r1 = hregNumber(insn->variant.bfp_triop.dst);
6863 UInt r2 = hregNumber(insn->variant.bfp_triop.op2);
6864 UInt r3 = hregNumber(insn->variant.bfp_triop.op3);
6865 s390_round_t rounding_mode = insn->variant.bfp_triop.rounding_mode;
6866
6867 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
6868 buf = s390_set_fpc_rounding_mode(buf, rounding_mode);
6869 }
6870
6871 switch (insn->size) {
6872 case 4:
6873 switch (insn->variant.bfp_triop.tag) {
6874 case S390_BFP_MADD: buf = s390_emit_MAEBR(buf, r1, r3, r2); break;
6875 case S390_BFP_MSUB: buf = s390_emit_MSEBR(buf, r1, r3, r2); break;
6876 default: goto fail;
6877 }
6878 break;
6879
6880 case 8:
6881 switch (insn->variant.bfp_triop.tag) {
6882 case S390_BFP_MADD: buf = s390_emit_MADBR(buf, r1, r3, r2); break;
6883 case S390_BFP_MSUB: buf = s390_emit_MSDBR(buf, r1, r3, r2); break;
6884 default: goto fail;
6885 }
6886 break;
6887
6888 default: goto fail;
6889 }
6890
6891 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
6892 /* Restore FPC register from guest state */
6893 buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER,
florian428dfdd2012-03-27 03:09:49 +00006894 S390X_GUEST_OFFSET(guest_fpc)); // fpc = guest_fpc
sewardj2019a972011-03-07 16:04:07 +00006895 }
6896 return buf;
6897
6898 fail:
6899 vpanic("s390_insn_bfp_triop_emit");
6900}
6901
6902
6903static UChar *
6904s390_insn_bfp_binop_emit(UChar *buf, const s390_insn *insn)
6905{
6906 UInt r1 = hregNumber(insn->variant.bfp_binop.dst);
6907 UInt r2 = hregNumber(insn->variant.bfp_binop.op2);
6908 s390_round_t rounding_mode = insn->variant.bfp_binop.rounding_mode;
6909
6910 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
6911 buf = s390_set_fpc_rounding_mode(buf, rounding_mode);
6912 }
6913
6914 switch (insn->size) {
6915 case 4:
6916 switch (insn->variant.bfp_binop.tag) {
6917 case S390_BFP_ADD: buf = s390_emit_AEBR(buf, r1, r2); break;
6918 case S390_BFP_SUB: buf = s390_emit_SEBR(buf, r1, r2); break;
6919 case S390_BFP_MUL: buf = s390_emit_MEEBR(buf, r1, r2); break;
6920 case S390_BFP_DIV: buf = s390_emit_DEBR(buf, r1, r2); break;
6921 default: goto fail;
6922 }
6923 break;
6924
6925 case 8:
6926 switch (insn->variant.bfp_binop.tag) {
6927 case S390_BFP_ADD: buf = s390_emit_ADBR(buf, r1, r2); break;
6928 case S390_BFP_SUB: buf = s390_emit_SDBR(buf, r1, r2); break;
6929 case S390_BFP_MUL: buf = s390_emit_MDBR(buf, r1, r2); break;
6930 case S390_BFP_DIV: buf = s390_emit_DDBR(buf, r1, r2); break;
6931 default: goto fail;
6932 }
6933 break;
6934
6935 default: goto fail;
6936 }
6937
6938 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
6939 /* Restore FPC register from guest state */
6940 buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER,
florian428dfdd2012-03-27 03:09:49 +00006941 S390X_GUEST_OFFSET(guest_fpc));
sewardj2019a972011-03-07 16:04:07 +00006942 }
6943 return buf;
6944
6945 fail:
6946 vpanic("s390_insn_bfp_binop_emit");
6947}
6948
6949
6950static UChar *
6951s390_insn_bfp_unop_emit(UChar *buf, const s390_insn *insn)
6952{
6953 UInt r1 = hregNumber(insn->variant.bfp_unop.dst);
6954 UInt r2 = hregNumber(insn->variant.bfp_unop.op);
6955 s390_round_t rounding_mode = insn->variant.bfp_unop.rounding_mode;
6956 s390_round_t m3 = rounding_mode;
6957
6958 /* The "convert to fixed" instructions have a field for the rounding
6959 mode and no FPC modification is necessary. So we handle them
6960 upfront. */
6961 switch (insn->variant.bfp_unop.tag) {
6962 case S390_BFP_F32_TO_I32: return s390_emit_CFEBR(buf, m3, r1, r2);
6963 case S390_BFP_F64_TO_I32: return s390_emit_CFDBR(buf, m3, r1, r2);
6964 case S390_BFP_F32_TO_I64: return s390_emit_CGEBR(buf, m3, r1, r2);
6965 case S390_BFP_F64_TO_I64: return s390_emit_CGDBR(buf, m3, r1, r2);
6966 default: break;
6967 }
6968
6969 /* For all other insns if a special rounding mode is requested,
6970 we need to set the FPC first and restore it later. */
6971 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
6972 buf = s390_set_fpc_rounding_mode(buf, rounding_mode);
6973 }
6974
6975 switch (insn->variant.bfp_unop.tag) {
6976 case S390_BFP_ABS:
6977 switch (insn->size) {
6978 case 4: buf = s390_emit_LPEBR(buf, r1, r2); break;
6979 case 8: buf = s390_emit_LPDBR(buf, r1, r2); break;
6980 case 16: buf = s390_emit_LPXBR(buf, r1, r2); break;
6981 default: goto fail;
6982 }
6983 break;
6984
6985 case S390_BFP_NABS:
6986 switch (insn->size) {
6987 case 4: buf = s390_emit_LNEBR(buf, r1, r2); break;
6988 case 8: buf = s390_emit_LNDBR(buf, r1, r2); break;
6989 case 16: buf = s390_emit_LNXBR(buf, r1, r2); break;
6990 default: goto fail;
6991 }
6992 break;
6993
6994 case S390_BFP_NEG:
6995 switch (insn->size) {
6996 case 4: buf = s390_emit_LCEBR(buf, r1, r2); break;
6997 case 8: buf = s390_emit_LCDBR(buf, r1, r2); break;
6998 case 16: buf = s390_emit_LCXBR(buf, r1, r2); break;
6999 default: goto fail;
7000 }
7001 break;
7002
7003 case S390_BFP_SQRT:
7004 switch (insn->size) {
7005 case 4: buf = s390_emit_SQEBR(buf, r1, r2); break;
7006 case 8: buf = s390_emit_SQDBR(buf, r1, r2); break;
7007 case 16: buf = s390_emit_SQXBR(buf, r1, r2); break;
7008 default: goto fail;
7009 }
7010 break;
7011
7012 case S390_BFP_I32_TO_F32: buf = s390_emit_CEFBR(buf, r1, r2); break;
7013 case S390_BFP_I32_TO_F64: buf = s390_emit_CDFBR(buf, r1, r2); break;
7014 case S390_BFP_I32_TO_F128: buf = s390_emit_CXFBR(buf, r1, r2); break;
7015 case S390_BFP_I64_TO_F32: buf = s390_emit_CEGBR(buf, r1, r2); break;
7016 case S390_BFP_I64_TO_F64: buf = s390_emit_CDGBR(buf, r1, r2); break;
7017 case S390_BFP_I64_TO_F128: buf = s390_emit_CXGBR(buf, r1, r2); break;
7018
7019 case S390_BFP_F32_TO_F64: buf = s390_emit_LDEBR(buf, r1, r2); break;
7020 case S390_BFP_F32_TO_F128: buf = s390_emit_LXEBR(buf, r1, r2); break;
7021 case S390_BFP_F64_TO_F32: buf = s390_emit_LEDBR(buf, r1, r2); break;
7022 case S390_BFP_F64_TO_F128: buf = s390_emit_LXDBR(buf, r1, r2); break;
7023
7024 default: goto fail;
7025 }
7026
7027 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
7028 /* Restore FPC register from guest state */
7029 buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER,
florian428dfdd2012-03-27 03:09:49 +00007030 S390X_GUEST_OFFSET(guest_fpc)); // fpc = guest_fpc
sewardj2019a972011-03-07 16:04:07 +00007031 }
7032 return buf;
7033
7034 fail:
7035 vpanic("s390_insn_bfp_unop_emit");
7036}
7037
7038
7039static UChar *
7040s390_insn_bfp_compare_emit(UChar *buf, const s390_insn *insn)
7041{
7042 UInt dst = hregNumber(insn->variant.bfp_compare.dst);
7043 UInt r1 = hregNumber(insn->variant.bfp_compare.op1);
7044 UInt r2 = hregNumber(insn->variant.bfp_compare.op2);
7045
7046 switch (insn->size) {
7047 case 4:
7048 buf = s390_emit_CEBR(buf, r1, r2);
7049 break;
7050
7051 case 8:
7052 buf = s390_emit_CDBR(buf, r1, r2);
7053 break;
7054
7055 default: goto fail;
7056 }
7057
7058 return s390_emit_load_cc(buf, dst); /* Load condition code into DST */
7059
7060 fail:
7061 vpanic("s390_insn_bfp_compare_emit");
7062}
7063
7064
7065static UChar *
7066s390_insn_bfp128_binop_emit(UChar *buf, const s390_insn *insn)
7067{
7068 UInt r1_hi = hregNumber(insn->variant.bfp128_binop.dst_hi);
7069 UInt r1_lo = hregNumber(insn->variant.bfp128_binop.dst_lo);
7070 UInt r2_hi = hregNumber(insn->variant.bfp128_binop.op2_hi);
7071 UInt r2_lo = hregNumber(insn->variant.bfp128_binop.op2_lo);
7072 s390_round_t rounding_mode = insn->variant.bfp_binop.rounding_mode;
7073
7074 /* Paranoia */
7075 vassert(insn->size == 16);
7076 vassert(r1_lo == r1_hi + 2);
7077 vassert(r2_lo == r2_hi + 2);
7078 vassert((r1_hi & 0x2) == 0);
7079 vassert((r2_hi & 0x2) == 0);
7080
7081 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
7082 buf = s390_set_fpc_rounding_mode(buf, rounding_mode);
7083 }
7084
7085 switch (insn->variant.bfp128_binop.tag) {
7086 case S390_BFP_ADD: buf = s390_emit_AXBR(buf, r1_hi, r2_hi); break;
7087 case S390_BFP_SUB: buf = s390_emit_SXBR(buf, r1_hi, r2_hi); break;
7088 case S390_BFP_MUL: buf = s390_emit_MXBR(buf, r1_hi, r2_hi); break;
7089 case S390_BFP_DIV: buf = s390_emit_DXBR(buf, r1_hi, r2_hi); break;
7090 default: goto fail;
7091 }
7092
7093 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
7094 /* Restore FPC register from guest state */
7095 buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER,
florian428dfdd2012-03-27 03:09:49 +00007096 S390X_GUEST_OFFSET(guest_fpc)); // fpc = guest_fpc
sewardj2019a972011-03-07 16:04:07 +00007097 }
7098 return buf;
7099
7100 fail:
7101 vpanic("s390_insn_bfp128_binop_emit");
7102}
7103
7104
7105static UChar *
7106s390_insn_bfp128_compare_emit(UChar *buf, const s390_insn *insn)
7107{
7108 UInt dst = hregNumber(insn->variant.bfp128_compare.dst);
7109 UInt r1_hi = hregNumber(insn->variant.bfp128_compare.op1_hi);
7110 UInt r1_lo = hregNumber(insn->variant.bfp128_compare.op1_lo);
7111 UInt r2_hi = hregNumber(insn->variant.bfp128_compare.op2_hi);
7112 UInt r2_lo = hregNumber(insn->variant.bfp128_compare.op2_lo);
7113
7114 /* Paranoia */
7115 vassert(insn->size == 16);
7116 vassert(r1_lo == r1_hi + 2);
7117 vassert(r2_lo == r2_hi + 2);
7118 vassert((r1_hi & 0x2) == 0);
7119 vassert((r2_hi & 0x2) == 0);
7120
7121 buf = s390_emit_CXBR(buf, r1_hi, r2_hi);
7122
7123 /* Load condition code into DST */
7124 return s390_emit_load_cc(buf, dst);
7125}
7126
7127
7128static UChar *
7129s390_insn_bfp128_unop_emit(UChar *buf, const s390_insn *insn)
7130{
7131 UInt r1_hi = hregNumber(insn->variant.bfp128_unop.dst_hi);
7132 UInt r1_lo = hregNumber(insn->variant.bfp128_unop.dst_lo);
7133 UInt r2_hi = hregNumber(insn->variant.bfp128_unop.op_hi);
7134 UInt r2_lo = hregNumber(insn->variant.bfp128_unop.op_lo);
7135 s390_round_t rounding_mode = insn->variant.bfp_binop.rounding_mode;
7136
7137 /* Paranoia */
7138 vassert(insn->size == 16);
7139 vassert(r1_lo == r1_hi + 2);
7140 vassert(r2_lo == r2_hi + 2);
7141 vassert((r1_hi & 0x2) == 0);
7142 vassert((r2_hi & 0x2) == 0);
7143
7144 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
7145 buf = s390_set_fpc_rounding_mode(buf, rounding_mode);
7146 }
7147
7148 switch (insn->variant.bfp128_unop.tag) {
7149 case S390_BFP_ABS: buf = s390_emit_LPXBR(buf, r1_hi, r2_hi); break;
7150 case S390_BFP_NABS: buf = s390_emit_LNXBR(buf, r1_hi, r2_hi); break;
7151 case S390_BFP_NEG: buf = s390_emit_LCXBR(buf, r1_hi, r2_hi); break;
7152 case S390_BFP_SQRT: buf = s390_emit_SQXBR(buf, r1_hi, r2_hi); break;
7153 case S390_BFP_F128_TO_F32: buf = s390_emit_LEXBR(buf, r1_hi, r2_hi); break;
7154 case S390_BFP_F128_TO_F64: buf = s390_emit_LDXBR(buf, r1_hi, r2_hi); break;
7155 default: goto fail;
7156 }
7157
7158 if (rounding_mode != S390_ROUND_NEAREST_EVEN) {
7159 /* Restore FPC register from guest state */
7160 buf = s390_emit_LFPC(buf, S390_REGNO_GUEST_STATE_POINTER,
florian428dfdd2012-03-27 03:09:49 +00007161 S390X_GUEST_OFFSET(guest_fpc)); // fpc = guest_fpc
sewardj2019a972011-03-07 16:04:07 +00007162 }
7163 return buf;
7164
7165 fail:
7166 vpanic("s390_insn_bfp128_unop_emit");
7167}
7168
7169
7170/* Conversion to 128-bit BFP does not require a rounding mode */
7171static UChar *
7172s390_insn_bfp128_convert_to_emit(UChar *buf, const s390_insn *insn)
7173{
7174 UInt r1_hi = hregNumber(insn->variant.bfp128_unop.dst_hi);
7175 UInt r1_lo = hregNumber(insn->variant.bfp128_unop.dst_lo);
7176 UInt r2 = hregNumber(insn->variant.bfp128_unop.op_hi);
7177
7178 /* Paranoia */
7179 vassert(insn->size == 16);
7180 vassert(r1_lo == r1_hi + 2);
7181 vassert((r1_hi & 0x2) == 0);
7182
7183 switch (insn->variant.bfp128_unop.tag) {
7184 case S390_BFP_I32_TO_F128: buf = s390_emit_CXFBR(buf, r1_hi, r2); break;
7185 case S390_BFP_I64_TO_F128: buf = s390_emit_CXGBR(buf, r1_hi, r2); break;
7186 case S390_BFP_F32_TO_F128: buf = s390_emit_LXEBR(buf, r1_hi, r2); break;
7187 case S390_BFP_F64_TO_F128: buf = s390_emit_LXDBR(buf, r1_hi, r2); break;
7188 default: goto fail;
7189 }
7190
7191 return buf;
7192
7193 fail:
7194 vpanic("s390_insn_bfp128_convert_to_emit");
7195}
7196
7197
7198static UChar *
7199s390_insn_bfp128_convert_from_emit(UChar *buf, const s390_insn *insn)
7200{
7201 UInt r1 = hregNumber(insn->variant.bfp128_unop.dst_hi);
7202 UInt r2_hi = hregNumber(insn->variant.bfp128_unop.op_hi);
7203 UInt r2_lo = hregNumber(insn->variant.bfp128_unop.op_lo);
7204 s390_round_t rounding_mode = insn->variant.bfp_binop.rounding_mode;
7205
7206 /* Paranoia */
7207 vassert(insn->size != 16);
7208 vassert(r2_lo == r2_hi + 2);
7209 vassert((r2_hi & 0x2) == 0);
7210
7211 /* The "convert to fixed" instructions have a field for the rounding
7212 mode and no FPC modification is necessary. So we handle them
7213 upfront. */
7214 switch (insn->variant.bfp_unop.tag) {
7215 case S390_BFP_F128_TO_I32: return s390_emit_CFXBR(buf, rounding_mode,
7216 r1, r2_hi); break;
7217 case S390_BFP_F128_TO_I64: return s390_emit_CGXBR(buf, rounding_mode,
7218 r1, r2_hi); break;
7219 default: break;
7220 }
7221
7222 vpanic("s390_insn_bfp128_convert_from_emit");
7223}
7224
7225
sewardja52e37e2011-04-28 18:48:06 +00007226static UChar *
7227s390_insn_mfence_emit(UChar *buf, const s390_insn *insn)
7228{
7229 return s390_emit_BCR(buf, 0xF, 0x0);
7230}
7231
7232
florianad43b3a2012-02-20 15:01:14 +00007233static UChar *
7234s390_insn_gzero_emit(UChar *buf, const s390_insn *insn)
7235{
7236 return s390_emit_XC(buf, insn->size - 1,
7237 S390_REGNO_GUEST_STATE_POINTER, insn->variant.gzero.offset,
7238 S390_REGNO_GUEST_STATE_POINTER, insn->variant.gzero.offset);
7239}
7240
7241
7242static UChar *
7243s390_insn_gadd_emit(UChar *buf, const s390_insn *insn)
7244{
7245 return s390_emit_AGSI(buf, insn->variant.gadd.delta,
7246 S390_REGNO_GUEST_STATE_POINTER,
7247 DISP20(insn->variant.gadd.offset));
7248}
7249
7250
florian8844a632012-04-13 04:04:06 +00007251/* Define convenience functions needed for translation chaining.
7252 Any changes need to be applied to the functions in concert. */
7253
florian1c857042012-04-15 04:11:07 +00007254static __inline__ Bool
7255s390_insn_is_BRCL(const UChar *p, UChar condition)
7256{
7257 return p[0] == 0xc0 && p[1] == ((condition << 4) | 0x04);
7258}
7259
7260static __inline__ Bool
7261s390_insn_is_BR(const UChar *p, UChar reg)
7262{
7263 return p[0] == 0x07 && p[1] == (0xF0 | reg); /* BCR 15,reg */
7264}
7265
florianebaf8d92012-04-22 17:38:46 +00007266
7267/* The length of the BASR insn */
7268#define S390_BASR_LEN 2
7269
florian1c857042012-04-15 04:11:07 +00007270
florian8844a632012-04-13 04:04:06 +00007271/* Load the 64-bit VALUE into REG. Note that this function must NOT
7272 optimise the generated code by looking at the value. I.e. using
floriane09e8bb2012-05-07 03:28:18 +00007273 LGHI if value == 0 would be very wrong. */
florian8844a632012-04-13 04:04:06 +00007274static UChar *
7275s390_tchain_load64(UChar *buf, UChar regno, ULong value)
7276{
florian1c857042012-04-15 04:11:07 +00007277 UChar *begin = buf;
7278
florian1c2b4db2012-04-22 17:46:31 +00007279 if (s390_host_has_eimm) {
7280 /* Do it in two steps: upper half [0:31] and lower half [32:63] */
7281 buf = s390_emit_IIHF(buf, regno, value >> 32);
7282 buf = s390_emit_IILF(buf, regno, value & 0xFFFFFFFF);
7283 } else {
7284 buf = s390_emit_IILL(buf, regno, value & 0xFFFF);
7285 value >>= 16;
7286 buf = s390_emit_IILH(buf, regno, value & 0xFFFF);
7287 value >>= 16;
7288 buf = s390_emit_IIHL(buf, regno, value & 0xFFFF);
7289 value >>= 16;
7290 buf = s390_emit_IIHH(buf, regno, value & 0xFFFF);
7291 }
florian8844a632012-04-13 04:04:06 +00007292
florian1c857042012-04-15 04:11:07 +00007293 vassert(buf - begin == s390_tchain_load64_len());
7294
florian8844a632012-04-13 04:04:06 +00007295 return buf;
7296}
7297
7298/* Return number of bytes generated by s390_tchain_load64 */
7299static UInt
7300s390_tchain_load64_len(void)
7301{
florian1c2b4db2012-04-22 17:46:31 +00007302 if (s390_host_has_eimm) {
7303 return 6 + 6; /* IIHF + IILF */
7304 }
florianebaf8d92012-04-22 17:38:46 +00007305 return 4 + 4 + 4 + 4; /* IIHH + IIHL + IILH + IILL */
florian8844a632012-04-13 04:04:06 +00007306}
7307
7308/* Verify that CODE is the code sequence generated by s390_tchain_load64
7309 to load VALUE into REGNO. Return pointer to the byte following the
7310 insn sequence. */
7311static const UChar *
7312s390_tchain_verify_load64(const UChar *code, UChar regno, ULong value)
7313{
7314 UInt regmask = regno << 4;
7315 UInt hw;
7316
florian1c2b4db2012-04-22 17:46:31 +00007317 if (s390_host_has_eimm) {
7318 /* Check for IIHF */
7319 vassert(code[0] == 0xC0);
7320 vassert(code[1] == (0x08 | regmask));
7321 vassert(*(const UInt *)&code[2] == (value >> 32));
7322 /* Check for IILF */
7323 vassert(code[6] == 0xC0);
7324 vassert(code[7] == (0x09 | regmask));
7325 vassert(*(const UInt *)&code[8] == (value & 0xFFFFFFFF));
7326 } else {
7327 /* Check for IILL */
7328 hw = value & 0xFFFF;
7329 vassert(code[0] == 0xA5);
7330 vassert(code[1] == (0x03 | regmask));
7331 vassert(code[2] == (hw >> 8));
7332 vassert(code[3] == (hw & 0xFF));
florian8844a632012-04-13 04:04:06 +00007333
florian1c2b4db2012-04-22 17:46:31 +00007334 /* Check for IILH */
7335 hw = (value >> 16) & 0xFFFF;
7336 vassert(code[4] == 0xA5);
7337 vassert(code[5] == (0x02 | regmask));
7338 vassert(code[6] == (hw >> 8));
7339 vassert(code[7] == (hw & 0xFF));
florian8844a632012-04-13 04:04:06 +00007340
florian1c2b4db2012-04-22 17:46:31 +00007341 /* Check for IIHL */
7342 hw = (value >> 32) & 0xFFFF;
7343 vassert(code[8] == 0xA5);
7344 vassert(code[9] == (0x01 | regmask));
7345 vassert(code[10] == (hw >> 8));
7346 vassert(code[11] == (hw & 0xFF));
florian8844a632012-04-13 04:04:06 +00007347
florian1c2b4db2012-04-22 17:46:31 +00007348 /* Check for IIHH */
7349 hw = (value >> 48) & 0xFFFF;
7350 vassert(code[12] == 0xA5);
7351 vassert(code[13] == (0x00 | regmask));
7352 vassert(code[14] == (hw >> 8));
7353 vassert(code[15] == (hw & 0xFF));
7354 }
florian8844a632012-04-13 04:04:06 +00007355
florian1c857042012-04-15 04:11:07 +00007356 return code + s390_tchain_load64_len();
florian8844a632012-04-13 04:04:06 +00007357}
7358
7359/* CODE points to the code sequence as generated by s390_tchain_load64.
7360 Change the loaded value to VALUE. Return pointer to the byte following
7361 the patched code sequence. */
7362static UChar *
7363s390_tchain_patch_load64(UChar *code, ULong imm64)
7364{
florian1c2b4db2012-04-22 17:46:31 +00007365 if (s390_host_has_eimm) {
7366 /* Patch IIHF */
7367 *(UInt *)&code[2] = imm64 >> 32;
7368 /* Patch IILF */
7369 *(UInt *)&code[8] = imm64 & 0xFFFFFFFF;
7370 } else {
7371 code[3] = imm64 & 0xFF; imm64 >>= 8;
7372 code[2] = imm64 & 0xFF; imm64 >>= 8;
7373 code[7] = imm64 & 0xFF; imm64 >>= 8;
7374 code[6] = imm64 & 0xFF; imm64 >>= 8;
7375 code[11] = imm64 & 0xFF; imm64 >>= 8;
7376 code[10] = imm64 & 0xFF; imm64 >>= 8;
7377 code[15] = imm64 & 0xFF; imm64 >>= 8;
7378 code[14] = imm64 & 0xFF; imm64 >>= 8;
7379 }
florian8844a632012-04-13 04:04:06 +00007380
florian1c857042012-04-15 04:11:07 +00007381 return code + s390_tchain_load64_len();
florian8844a632012-04-13 04:04:06 +00007382}
7383
7384
7385/* NB: what goes on here has to be very closely coordinated with the
7386 chainXDirect_S390 and unchainXDirect_S390 below. */
7387static UChar *
7388s390_insn_xdirect_emit(UChar *buf, const s390_insn *insn,
7389 void *disp_cp_chain_me_to_slowEP,
7390 void *disp_cp_chain_me_to_fastEP)
7391{
7392 /* We're generating chain-me requests here, so we need to be
7393 sure this is actually allowed -- no-redir translations can't
7394 use chain-me's. Hence: */
7395 vassert(disp_cp_chain_me_to_slowEP != NULL);
7396 vassert(disp_cp_chain_me_to_fastEP != NULL);
7397
7398 /* Use ptmp for backpatching conditional jumps. */
7399 UChar *ptmp = buf;
7400
7401 /* First off, if this is conditional, create a conditional
7402 jump over the rest of it. */
7403 s390_cc_t cond = insn->variant.xdirect.cond;
7404
7405 if (cond != S390_CC_ALWAYS) {
7406 /* So we have something like this
7407 if (cond) do_xdirect;
7408 Y: ...
7409 We convert this into
7410 if (! cond) goto Y; // BRC opcode; 4 bytes
7411 do_xdirect;
7412 Y:
7413 */
7414 /* 4 bytes (a BRC insn) to be filled in here */
7415 buf += 4;
7416 }
7417
7418 /* Update the guest IA. */
7419 buf = s390_emit_load_64imm(buf, R0, insn->variant.xdirect.dst);
7420
7421 const s390_amode *amode = insn->variant.xdirect.guest_IA;
florianbf516d12012-04-21 15:53:13 +00007422 vassert(amode->tag == S390_AMODE_B12);
florian8844a632012-04-13 04:04:06 +00007423 UInt b = hregNumber(amode->b);
florian8844a632012-04-13 04:04:06 +00007424 UInt d = amode->d;
7425
florianbf516d12012-04-21 15:53:13 +00007426 buf = s390_emit_STG(buf, R0, 0, b, DISP20(d));
florian8844a632012-04-13 04:04:06 +00007427
florian8844a632012-04-13 04:04:06 +00007428 /* Load the chosen entry point into the scratch reg */
7429 void *disp_cp_chain_me;
7430
7431 disp_cp_chain_me =
7432 insn->variant.xdirect.to_fast_entry ? disp_cp_chain_me_to_fastEP
7433 : disp_cp_chain_me_to_slowEP;
florianebaf8d92012-04-22 17:38:46 +00007434 /* Get the address of the beginning of the load64 code sequence into %r1.
7435 Do not change the register! This is part of the protocol with the
7436 dispatcher. */
7437 buf = s390_emit_BASR(buf, 1, R0);
florian8844a632012-04-13 04:04:06 +00007438
florianebaf8d92012-04-22 17:38:46 +00007439 /* --- FIRST PATCHABLE BYTE follows (must not modify %r1) --- */
florian8844a632012-04-13 04:04:06 +00007440 ULong addr = Ptr_to_ULong(disp_cp_chain_me);
7441 buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH, addr);
7442
florianebaf8d92012-04-22 17:38:46 +00007443 /* goto *tchain_scratch */
7444 buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
florian8844a632012-04-13 04:04:06 +00007445
7446 /* --- END of PATCHABLE BYTES --- */
7447
7448 /* Fix up the conditional jump, if there was one. */
7449 if (cond != S390_CC_ALWAYS) {
7450 Int delta = buf - ptmp;
7451
7452 delta >>= 1; /* immediate constant is #half-words */
7453 vassert(delta > 0 && delta < (1 << 16));
7454 s390_emit_BRC(ptmp, s390_cc_invert(cond), delta);
7455 }
7456
7457 return buf;
7458}
7459
7460/* Return the number of patchable bytes from an xdirect insn. */
7461static UInt
7462s390_xdirect_patchable_len(void)
7463{
florianebaf8d92012-04-22 17:38:46 +00007464 return s390_tchain_load64_len() + S390_BASR_LEN;
florian8844a632012-04-13 04:04:06 +00007465}
7466
7467
7468static UChar *
7469s390_insn_xindir_emit(UChar *buf, const s390_insn *insn, void *disp_cp_xindir)
7470{
7471 /* We're generating transfers that could lead indirectly to a
7472 chain-me, so we need to be sure this is actually allowed --
7473 no-redir translations are not allowed to reach normal
7474 translations without going through the scheduler. That means
7475 no XDirects or XIndirs out from no-redir translations.
7476 Hence: */
7477 vassert(disp_cp_xindir != NULL);
7478
7479 /* Use ptmp for backpatching conditional jumps. */
7480 UChar *ptmp = buf;
7481
7482 /* First off, if this is conditional, create a conditional
7483 jump over the rest of it. */
7484 s390_cc_t cond = insn->variant.xdirect.cond;
7485
7486 if (cond != S390_CC_ALWAYS) {
7487 /* So we have something like this
7488 if (cond) do_xdirect;
7489 Y: ...
7490 We convert this into
7491 if (! cond) goto Y; // BRC opcode; 4 bytes
7492 do_xdirect;
7493 Y:
7494 */
7495 /* 4 bytes (a BRC insn) to be filled in here */
7496 buf += 4;
7497 }
7498
7499 /* Update the guest IA with the address in xdirect.dst. */
florian7346c7a2012-04-13 21:14:24 +00007500 const s390_amode *amode = insn->variant.xindir.guest_IA;
florian8844a632012-04-13 04:04:06 +00007501
florianbf516d12012-04-21 15:53:13 +00007502 vassert(amode->tag == S390_AMODE_B12);
florian8844a632012-04-13 04:04:06 +00007503 UInt b = hregNumber(amode->b);
florian8844a632012-04-13 04:04:06 +00007504 UInt d = amode->d;
florian7346c7a2012-04-13 21:14:24 +00007505 UInt regno = hregNumber(insn->variant.xindir.dst);
florian8844a632012-04-13 04:04:06 +00007506
florianbf516d12012-04-21 15:53:13 +00007507 buf = s390_emit_STG(buf, regno, 0, b, DISP20(d));
florian8844a632012-04-13 04:04:06 +00007508
7509 /* load tchain_scratch, #disp_indir */
7510 buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH,
7511 Ptr_to_ULong(disp_cp_xindir));
florianebaf8d92012-04-22 17:38:46 +00007512 /* goto *tchain_direct */
florian8844a632012-04-13 04:04:06 +00007513 buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
7514
7515 /* Fix up the conditional jump, if there was one. */
7516 if (cond != S390_CC_ALWAYS) {
7517 Int delta = buf - ptmp;
7518
7519 delta >>= 1; /* immediate constant is #half-words */
7520 vassert(delta > 0 && delta < (1 << 16));
7521 s390_emit_BRC(ptmp, s390_cc_invert(cond), delta);
7522 }
7523
7524 return buf;
7525}
7526
7527static UChar *
7528s390_insn_xassisted_emit(UChar *buf, const s390_insn *insn,
7529 void *disp_cp_xassisted)
7530{
7531 /* Use ptmp for backpatching conditional jumps. */
7532 UChar *ptmp = buf;
7533
7534 /* First off, if this is conditional, create a conditional
7535 jump over the rest of it. */
7536 s390_cc_t cond = insn->variant.xdirect.cond;
7537
7538 if (cond != S390_CC_ALWAYS) {
7539 /* So we have something like this
7540 if (cond) do_xdirect;
7541 Y: ...
7542 We convert this into
7543 if (! cond) goto Y; // BRC opcode; 4 bytes
7544 do_xdirect;
7545 Y:
7546 */
7547 /* 4 bytes (a BRC insn) to be filled in here */
7548 buf += 4;
7549 }
7550
7551 /* Update the guest IA with the address in xassisted.dst. */
7552 const s390_amode *amode = insn->variant.xassisted.guest_IA;
7553
florianbf516d12012-04-21 15:53:13 +00007554 vassert(amode->tag == S390_AMODE_B12);
florian8844a632012-04-13 04:04:06 +00007555 UInt b = hregNumber(amode->b);
florian8844a632012-04-13 04:04:06 +00007556 UInt d = amode->d;
7557 UInt regno = hregNumber(insn->variant.xassisted.dst);
7558
florianbf516d12012-04-21 15:53:13 +00007559 buf = s390_emit_STG(buf, regno, 0, b, DISP20(d));
florian8844a632012-04-13 04:04:06 +00007560
7561 UInt trcval = 0;
7562
7563 switch (insn->variant.xassisted.kind) {
7564 case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
7565 case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
florian8844a632012-04-13 04:04:06 +00007566 case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
7567 case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
7568 case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break;
7569 case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
7570 case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break;
7571 case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
7572 case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
7573 case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break;
7574 case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
7575 /* We don't expect to see the following being assisted. */
7576 case Ijk_Ret:
7577 case Ijk_Call:
7578 /* fallthrough */
7579 default:
7580 ppIRJumpKind(insn->variant.xassisted.kind);
7581 vpanic("s390_insn_xassisted_emit: unexpected jump kind");
7582 }
7583
7584 vassert(trcval != 0);
7585
7586 /* guest_state_pointer = trcval */
7587 buf = s390_emit_LGHI(buf, S390_REGNO_GUEST_STATE_POINTER, trcval);
7588
7589 /* load tchain_scratch, #disp_assisted */
7590 buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH,
7591 Ptr_to_ULong(disp_cp_xassisted));
7592
florianebaf8d92012-04-22 17:38:46 +00007593 /* goto *tchain_direct */
florian8844a632012-04-13 04:04:06 +00007594 buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
7595
7596 /* Fix up the conditional jump, if there was one. */
7597 if (cond != S390_CC_ALWAYS) {
7598 Int delta = buf - ptmp;
7599
7600 delta >>= 1; /* immediate constant is #half-words */
7601 vassert(delta > 0 && delta < (1 << 16));
7602 s390_emit_BRC(ptmp, s390_cc_invert(cond), delta);
7603 }
7604
7605 return buf;
7606}
7607
7608
7609/* Pseudo code:
7610
7611 guest_state[host_EvC_COUNTER] -= 1;
7612 if (guest_state[host_EvC_COUNTER] >= 0) goto nofail;
7613 goto guest_state[host_EvC_FAILADDR];
7614 nofail: ;
7615
7616 The dispatch counter is a 32-bit value. */
7617static UChar *
7618s390_insn_evcheck_emit(UChar *buf, const s390_insn *insn)
7619{
7620 s390_amode *amode;
florianbf516d12012-04-21 15:53:13 +00007621 UInt b, d;
florian8844a632012-04-13 04:04:06 +00007622 UChar *code_begin, *code_end;
7623
7624 code_begin = buf;
7625
7626 amode = insn->variant.evcheck.counter;
florianbf516d12012-04-21 15:53:13 +00007627 vassert(amode->tag == S390_AMODE_B12);
florian8844a632012-04-13 04:04:06 +00007628 b = hregNumber(amode->b);
florian8844a632012-04-13 04:04:06 +00007629 d = amode->d;
7630
7631 /* Decrement the dispatch counter in the guest state */
florian0e047d62012-04-21 16:06:04 +00007632 if (s390_host_has_gie) {
7633 buf = s390_emit_ASI(buf, -1, b, DISP20(d)); /* 6 bytes */
7634 } else {
7635 buf = s390_emit_LHI(buf, R0, -1); /* 4 bytes */
7636 buf = s390_emit_A(buf, R0, 0, b, d); /* 4 bytes */
7637 buf = s390_emit_ST(buf, R0, 0, b, d); /* 4 bytes */
7638 }
florian8844a632012-04-13 04:04:06 +00007639
7640 /* Jump over the next insn if >= 0 */
7641 buf = s390_emit_BRC(buf, S390_CC_HE, (4 + 6 + 2) / 2); /* 4 bytes */
7642
7643 /* Computed goto to fail_address */
7644 amode = insn->variant.evcheck.fail_addr;
7645 b = hregNumber(amode->b);
florian8844a632012-04-13 04:04:06 +00007646 d = amode->d;
florianbf516d12012-04-21 15:53:13 +00007647 buf = s390_emit_LG(buf, S390_REGNO_TCHAIN_SCRATCH, 0, b, DISP20(d)); /* 6 bytes */
florian8844a632012-04-13 04:04:06 +00007648 buf = s390_emit_BCR(buf, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH); /* 2 bytes */
7649
7650 code_end = buf;
7651
7652 /* Make sure the size of the generated code is identical to the size
7653 returned by evCheckSzB_S390 */
7654 vassert(evCheckSzB_S390() == code_end - code_begin);
7655
7656 return buf;
7657}
7658
7659
7660static UChar *
7661s390_insn_profinc_emit(UChar *buf,
7662 const s390_insn *insn __attribute__((unused)))
7663{
7664 /* Generate a code template to increment a memory location whose
7665 address will be known later as an immediate value. This code
7666 template will be patched once the memory location is known.
7667 For now we do this with address == 0. */
7668 buf = s390_tchain_load64(buf, S390_REGNO_TCHAIN_SCRATCH, 0);
florian0e047d62012-04-21 16:06:04 +00007669 if (s390_host_has_gie) {
7670 buf = s390_emit_AGSI(buf, 1, S390_REGNO_TCHAIN_SCRATCH, DISP20(0));
7671 } else {
7672 buf = s390_emit_LGHI(buf, R0, 1);
7673 buf = s390_emit_AG( buf, R0, 0, S390_REGNO_TCHAIN_SCRATCH, DISP20(0));
7674 buf = s390_emit_STG(buf, R0, 0, S390_REGNO_TCHAIN_SCRATCH, DISP20(0));
7675 }
florian8844a632012-04-13 04:04:06 +00007676
7677 return buf;
7678}
7679
7680
sewardj2019a972011-03-07 16:04:07 +00007681Int
florian8844a632012-04-13 04:04:06 +00007682emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn,
7683 Bool mode64, void *disp_cp_chain_me_to_slowEP,
7684 void *disp_cp_chain_me_to_fastEP, void *disp_cp_xindir,
7685 void *disp_cp_xassisted)
sewardj2019a972011-03-07 16:04:07 +00007686{
7687 UChar *end;
7688
7689 switch (insn->tag) {
7690 case S390_INSN_LOAD:
7691 end = s390_insn_load_emit(buf, insn);
7692 break;
7693
7694 case S390_INSN_STORE:
7695 end = s390_insn_store_emit(buf, insn);
7696 break;
7697
7698 case S390_INSN_MOVE:
7699 end = s390_insn_move_emit(buf, insn);
7700 break;
7701
7702 case S390_INSN_COND_MOVE:
7703 end = s390_insn_cond_move_emit(buf, insn);
7704 break;
7705
7706 case S390_INSN_LOAD_IMMEDIATE:
7707 end = s390_insn_load_immediate_emit(buf, insn);
7708 break;
7709
7710 case S390_INSN_ALU:
7711 end = s390_insn_alu_emit(buf, insn);
7712 break;
7713
7714 case S390_INSN_MUL:
7715 end = s390_insn_mul_emit(buf, insn);
7716 break;
7717
7718 case S390_INSN_DIV:
7719 end = s390_insn_div_emit(buf, insn);
7720 break;
7721
7722 case S390_INSN_DIVS:
7723 end = s390_insn_divs_emit(buf, insn);
7724 break;
7725
sewardj611b06e2011-03-24 08:57:29 +00007726 case S390_INSN_CLZ:
7727 end = s390_insn_clz_emit(buf, insn);
sewardj2019a972011-03-07 16:04:07 +00007728 break;
7729
7730 case S390_INSN_UNOP:
7731 end = s390_insn_unop_emit(buf, insn);
7732 break;
7733
7734 case S390_INSN_TEST:
7735 end = s390_insn_test_emit(buf, insn);
7736 break;
7737
7738 case S390_INSN_CC2BOOL:
7739 end = s390_insn_cc2bool_emit(buf, insn);
7740 break;
7741
7742 case S390_INSN_CAS:
7743 end = s390_insn_cas_emit(buf, insn);
7744 break;
7745
7746 case S390_INSN_COMPARE:
7747 end = s390_insn_compare_emit(buf, insn);
7748 break;
7749
sewardj2019a972011-03-07 16:04:07 +00007750 case S390_INSN_HELPER_CALL:
7751 end = s390_insn_helper_call_emit(buf, insn);
7752 break;
7753
7754 case S390_INSN_BFP_TRIOP:
7755 end = s390_insn_bfp_triop_emit(buf, insn);
7756 break;
7757
7758 case S390_INSN_BFP_BINOP:
7759 end = s390_insn_bfp_binop_emit(buf, insn);
7760 break;
7761
7762 case S390_INSN_BFP_UNOP:
7763 end = s390_insn_bfp_unop_emit(buf, insn);
7764 break;
7765
7766 case S390_INSN_BFP_COMPARE:
7767 end = s390_insn_bfp_compare_emit(buf, insn);
7768 break;
7769
7770 case S390_INSN_BFP128_BINOP:
7771 end = s390_insn_bfp128_binop_emit(buf, insn);
7772 break;
7773
7774 case S390_INSN_BFP128_COMPARE:
7775 end = s390_insn_bfp128_compare_emit(buf, insn);
7776 break;
7777
7778 case S390_INSN_BFP128_UNOP:
7779 end = s390_insn_bfp128_unop_emit(buf, insn);
7780 break;
7781
7782 case S390_INSN_BFP128_CONVERT_TO:
7783 end = s390_insn_bfp128_convert_to_emit(buf, insn);
7784 break;
7785
7786 case S390_INSN_BFP128_CONVERT_FROM:
7787 end = s390_insn_bfp128_convert_from_emit(buf, insn);
7788 break;
7789
sewardja52e37e2011-04-28 18:48:06 +00007790 case S390_INSN_MFENCE:
7791 end = s390_insn_mfence_emit(buf, insn);
7792 break;
7793
florianad43b3a2012-02-20 15:01:14 +00007794 case S390_INSN_GZERO:
7795 end = s390_insn_gzero_emit(buf, insn);
7796 break;
7797
7798 case S390_INSN_GADD:
7799 end = s390_insn_gadd_emit(buf, insn);
7800 break;
7801
florian8844a632012-04-13 04:04:06 +00007802 case S390_INSN_PROFINC:
7803 end = s390_insn_profinc_emit(buf, insn);
7804 /* Tell the caller .. */
7805 vassert(*is_profinc == False);
7806 *is_profinc = True;
7807 break;
7808
7809 case S390_INSN_EVCHECK:
7810 end = s390_insn_evcheck_emit(buf, insn);
7811 break;
7812
7813 case S390_INSN_XDIRECT:
7814 end = s390_insn_xdirect_emit(buf, insn, disp_cp_chain_me_to_slowEP,
7815 disp_cp_chain_me_to_fastEP);
7816 break;
7817
7818 case S390_INSN_XINDIR:
7819 end = s390_insn_xindir_emit(buf, insn, disp_cp_xindir);
7820 break;
7821
7822 case S390_INSN_XASSISTED:
7823 end = s390_insn_xassisted_emit(buf, insn, disp_cp_xassisted);
7824 break;
7825
sewardj2019a972011-03-07 16:04:07 +00007826 default:
florian616458b2012-03-25 16:17:18 +00007827 vpanic("emit_S390Instr");
sewardj2019a972011-03-07 16:04:07 +00007828 }
7829
7830 vassert(end - buf <= nbuf);
7831
7832 return end - buf;
7833}
7834
7835
florian8844a632012-04-13 04:04:06 +00007836/* Return the number of bytes emitted for an S390_INSN_EVCHECK.
7837 See s390_insn_evcheck_emit */
7838Int
7839evCheckSzB_S390(void)
7840{
florian0e047d62012-04-21 16:06:04 +00007841 return s390_host_has_gie ? 18 : 24;
florian8844a632012-04-13 04:04:06 +00007842}
7843
7844
7845/* Patch the counter address into CODE_TO_PATCH as previously
7846 generated by s390_insn_profinc_emit. */
7847VexInvalRange
7848patchProfInc_S390(void *code_to_patch, ULong *location_of_counter)
7849{
7850 vassert(sizeof(ULong *) == 8);
7851
7852 s390_tchain_verify_load64(code_to_patch, S390_REGNO_TCHAIN_SCRATCH, 0);
7853
7854 s390_tchain_patch_load64(code_to_patch, Ptr_to_ULong(location_of_counter));
7855
7856 VexInvalRange vir = {0, 0};
7857 return vir;
7858}
7859
7860
7861/* NB: what goes on here has to be very closely coordinated with the
7862 s390_insn_xdirect_emit code above. */
7863VexInvalRange
7864chainXDirect_S390(void *place_to_chain,
7865 void *disp_cp_chain_me_EXPECTED,
7866 void *place_to_jump_to)
7867{
florianebaf8d92012-04-22 17:38:46 +00007868 /* What we're expecting to see @ PLACE_TO_CHAIN is:
florian8844a632012-04-13 04:04:06 +00007869
florianebaf8d92012-04-22 17:38:46 +00007870 load tchain_scratch, #disp_cp_chain_me_EXPECTED
7871 goto *tchain_scratch
florian8844a632012-04-13 04:04:06 +00007872 */
7873 const UChar *next;
7874 next = s390_tchain_verify_load64(place_to_chain, S390_REGNO_TCHAIN_SCRATCH,
7875 Ptr_to_ULong(disp_cp_chain_me_EXPECTED));
florianebaf8d92012-04-22 17:38:46 +00007876 vassert(s390_insn_is_BR(next, S390_REGNO_TCHAIN_SCRATCH));
florian8844a632012-04-13 04:04:06 +00007877
7878 /* And what we want to change it to is either:
7879 (general case):
7880
florianebaf8d92012-04-22 17:38:46 +00007881 load tchain_scratch, #place_to_jump_to
7882 goto *tchain_scratch
florian8844a632012-04-13 04:04:06 +00007883
7884 ---OR---
7885
7886 in the case where the displacement is small enough
7887
7888 BRCL delta where delta is in half-words
7889 invalid opcodes
7890
7891 In both cases the replacement has the same length as the original.
7892 To remain sane & verifiable,
7893 (1) limit the displacement for the short form to
7894 (say) +/- one billion, so as to avoid wraparound
7895 off-by-ones
7896 (2) even if the short form is applicable, once every (say)
7897 1024 times use the long form anyway, so as to maintain
7898 verifiability
7899 */
7900
7901 /* This is the delta we need to put into a BRCL insn. Note, that the
7902 offset in BRCL is in half-words. Hence division by 2. */
7903 Long delta = (Long)((UChar *)place_to_jump_to - (UChar *)place_to_chain) / 2;
7904 Bool shortOK = delta >= -1000*1000*1000 && delta < 1000*1000*1000;
7905
7906 static UInt shortCTR = 0; /* DO NOT MAKE NON-STATIC */
7907 if (shortOK) {
7908 shortCTR++; // thread safety bleh
7909 if (0 == (shortCTR & 0x3FF)) {
7910 shortOK = False;
7911 if (0)
7912 vex_printf("QQQ chainXDirect_S390: shortCTR = %u, "
7913 "using long jmp\n", shortCTR);
7914 }
7915 }
7916
7917 /* And make the modifications. */
7918 UChar *p = (UChar *)place_to_chain;
7919 if (shortOK) {
7920 p = s390_emit_BRCL(p, S390_CC_ALWAYS, delta); /* 6 bytes */
7921
florian48cb9612012-04-20 02:50:28 +00007922 /* Make sure that BRCL fits into the patchable part of an xdirect
florian1c857042012-04-15 04:11:07 +00007923 code sequence */
florian48cb9612012-04-20 02:50:28 +00007924 vassert(6 <= s390_xdirect_patchable_len());
florian1c857042012-04-15 04:11:07 +00007925
florian8844a632012-04-13 04:04:06 +00007926 /* Fill remaining bytes with 0x00 (invalid opcode) */
7927 Int i;
7928 for (i = 0; i < s390_xdirect_patchable_len() - 6; ++i)
7929 p[i] = 0x00;
7930 } else {
florian1c857042012-04-15 04:11:07 +00007931 /*
florianebaf8d92012-04-22 17:38:46 +00007932 load tchain_scratch, #place_to_jump_to
7933 goto *tchain_scratch
florian1c857042012-04-15 04:11:07 +00007934 */
7935 ULong addr = Ptr_to_ULong(place_to_jump_to);
7936 p = s390_tchain_load64(p, S390_REGNO_TCHAIN_SCRATCH, addr);
florianebaf8d92012-04-22 17:38:46 +00007937 /* There is not need to emit a BCR here, as it is already there. */
florian8844a632012-04-13 04:04:06 +00007938 }
7939
7940 VexInvalRange vir = {0, 0};
7941 return vir;
7942}
7943
7944
7945/* NB: what goes on here has to be very closely coordinated with the
7946 s390_insn_xdirect_emit code above. */
7947VexInvalRange
7948unchainXDirect_S390(void *place_to_unchain,
7949 void *place_to_jump_to_EXPECTED,
7950 void *disp_cp_chain_me)
7951{
7952 /* What we're expecting to see @ PLACE_TO_UNCHAIN:
7953
florianebaf8d92012-04-22 17:38:46 +00007954 load tchain_scratch, #place_to_jump_to_EXPECTED
7955 goto *tchain_scratch
florian8844a632012-04-13 04:04:06 +00007956
7957 ---OR---
7958 in the case where the displacement falls within 32 bits
7959
7960 BRCL delta
7961 invalid opcodes
7962 */
7963 UChar *p = place_to_unchain;
florian1c857042012-04-15 04:11:07 +00007964
florianebaf8d92012-04-22 17:38:46 +00007965 Bool uses_short_form = False;
7966
florian1c857042012-04-15 04:11:07 +00007967 if (s390_insn_is_BRCL(p, S390_CC_ALWAYS)) {
florian8844a632012-04-13 04:04:06 +00007968 /* Looks like the short form */
7969 Int num_hw = *(Int *)&p[2];
7970 Int delta = 2 *num_hw;
7971
7972 vassert(p + delta == place_to_jump_to_EXPECTED);
7973
florian8844a632012-04-13 04:04:06 +00007974 Int i;
7975 for (i = 0; i < s390_xdirect_patchable_len() - 6; ++i)
florian1c857042012-04-15 04:11:07 +00007976 vassert(p[6+i] == 0x00);
florianebaf8d92012-04-22 17:38:46 +00007977 uses_short_form = True;
florian8844a632012-04-13 04:04:06 +00007978 } else {
7979 /* Should be the long form */
7980 const UChar *next;
7981
7982 next = s390_tchain_verify_load64(p, S390_REGNO_TCHAIN_SCRATCH,
7983 Ptr_to_ULong(place_to_jump_to_EXPECTED));
7984 /* Check for BR *tchain_scratch */
florian1c857042012-04-15 04:11:07 +00007985 vassert(s390_insn_is_BR(next, S390_REGNO_TCHAIN_SCRATCH));
florian8844a632012-04-13 04:04:06 +00007986 }
7987
7988 /* And what we want to change it to is:
7989
7990 load tchain_scratch, #disp_cp_chain_me
florianebaf8d92012-04-22 17:38:46 +00007991 goto *tchain_scratch
florian8844a632012-04-13 04:04:06 +00007992 */
florianebaf8d92012-04-22 17:38:46 +00007993
7994 /* Get the address of the beginning of the load64 code sequence into %r1.
7995 Do not change the register! This is part of the protocol with the
7996 dispatcher.
7997 Note: the incoming argument PLACE_TO_CHAIN points to the beginning of the
7998 load64 insn sequence. That sequence is prefixed with a BASR to get its
7999 address (see s390_insn_xdirect_emit). */
8000 p = s390_emit_BASR(p - S390_BASR_LEN, 1, R0);
8001
florian8844a632012-04-13 04:04:06 +00008002 ULong addr = Ptr_to_ULong(disp_cp_chain_me);
8003 p = s390_tchain_load64(p, S390_REGNO_TCHAIN_SCRATCH, addr);
florianebaf8d92012-04-22 17:38:46 +00008004
8005 /* Emit the BCR in case the short form was used. In case of the long
8006 form, the BCR is already there. */
8007 if (uses_short_form)
8008 s390_emit_BCR(p, S390_CC_ALWAYS, S390_REGNO_TCHAIN_SCRATCH);
florian8844a632012-04-13 04:04:06 +00008009
8010 VexInvalRange vir = {0, 0};
8011 return vir;
8012}
8013
sewardj2019a972011-03-07 16:04:07 +00008014/*---------------------------------------------------------------*/
8015/*--- end host_s390_defs.c ---*/
8016/*---------------------------------------------------------------*/