1/* -*- mode: C; c-basic-offset: 3; -*- */
2
3/*---------------------------------------------------------------*/
4/*--- begin                                  host_s390_defs.h ---*/
5/*---------------------------------------------------------------*/
6
7/*
8   This file is part of Valgrind, a dynamic binary instrumentation
9   framework.
10
11   Copyright IBM Corp. 2010-2012
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#ifndef __VEX_HOST_S390_DEFS_H
34#define __VEX_HOST_S390_DEFS_H
35
36#include "libvex_basictypes.h"            /* Bool */
37#include "libvex.h"                       /* VexArchInfo */
38#include "main_util.h"                    /* needed for host_generic_regs.h */
39#include "host_generic_regs.h"            /* HReg */
40
41/* --------- Registers --------- */
42const HChar *s390_hreg_as_string(HReg);
43
44/* Dedicated registers */
45HReg s390_hreg_guest_state_pointer(void);
46
47
48/* Given the index of a function argument, return the number of the
49   general purpose register in which it is being passed. Arguments are
50   counted 0, 1, 2, ... and they are being passed in r2, r3, r4, ... */
51static __inline__ unsigned
52s390_gprno_from_arg_index(unsigned ix)
53{
54   return ix + 2;
55}
56
57/* --------- Memory address expressions (amodes). --------- */
58
59/* These are the address modes:
60   (1) b12:  base register + 12-bit unsigned offset   (e.g. RS)
61   (2) b20:  base register + 20-bit signed offset     (e.g. RSY)
62   (3) bx12: base register + index register + 12-bit unsigned offset (e.g. RX)
63   (4) bx20: base register + index register + 20-bit signed offset   (e.g. RXY)
64   fixs390: There is also pc-relative stuff.. e.g. LARL
65*/
66
67typedef enum {
68   S390_AMODE_B12,
69   S390_AMODE_B20,
70   S390_AMODE_BX12,
71   S390_AMODE_BX20
72} s390_amode_t;
73
74typedef struct {
75   s390_amode_t tag;
76   HReg b;
77   HReg x;       /* hregNumber(x) == 0  for S390_AMODE_B12/B20 kinds */
78   Int  d;       /* 12 bit unsigned or 20 bit signed */
79} s390_amode;
80
81
82s390_amode *s390_amode_b12(Int d, HReg b);
83s390_amode *s390_amode_b20(Int d, HReg b);
84s390_amode *s390_amode_bx12(Int d, HReg b, HReg x);
85s390_amode *s390_amode_bx20(Int d, HReg b, HReg x);
86s390_amode *s390_amode_for_guest_state(Int d);
87Bool        s390_amode_is_sane(const s390_amode *);
88
89const HChar *s390_amode_as_string(const s390_amode *);
90
91/* ------------- 2nd (right) operand of binary operation ---------------- */
92
93typedef enum {
94   S390_OPND_REG,
95   S390_OPND_IMMEDIATE,
96   S390_OPND_AMODE
97} s390_opnd_t;
98
99
100/* Naming convention for operand locations:
101   R    - GPR
102   I    - immediate value
103   M    - memory (any Amode may be used)
104*/
105
106/* An operand that is either in a GPR or is addressable via a BX20 amode */
107typedef struct {
108   s390_opnd_t tag;
109   union {
110      HReg        reg;
111      s390_amode *am;
112      ULong       imm;
113   } variant;
114} s390_opnd_RMI;
115
116
117/* The kind of instructions */
118typedef enum {
119   S390_INSN_LOAD,   /* load register from memory */
120   S390_INSN_STORE,  /* store register to memory */
121   S390_INSN_MOVE,   /* from register to register */
122   S390_INSN_COND_MOVE, /* conditonal "move" to register */
123   S390_INSN_LOAD_IMMEDIATE,
124   S390_INSN_ALU,
125   S390_INSN_MUL,    /* n-bit operands; 2n-bit result */
126   S390_INSN_DIV,    /* 2n-bit dividend; n-bit divisor; n-bit quot/rem */
127   S390_INSN_DIVS,   /* n-bit dividend; n-bit divisor; n-bit quot/rem */
128   S390_INSN_CLZ,    /* count left-most zeroes */
129   S390_INSN_UNOP,
130   S390_INSN_TEST,   /* test operand and set cc */
131   S390_INSN_CC2BOOL,/* convert condition code to 0/1 */
132   S390_INSN_COMPARE,
133   S390_INSN_HELPER_CALL,
134   S390_INSN_CAS,    /* compare and swap */
135   S390_INSN_CDAS,   /* compare double and swap */
136   S390_INSN_BFP_BINOP, /* Binary floating point 32-bit / 64-bit */
137   S390_INSN_BFP_UNOP,
138   S390_INSN_BFP_TRIOP,
139   S390_INSN_BFP_COMPARE,
140   S390_INSN_BFP128_BINOP, /* Binary floating point 128-bit */
141   S390_INSN_BFP128_UNOP,
142   S390_INSN_BFP128_COMPARE,
143   S390_INSN_BFP128_CONVERT_TO,
144   S390_INSN_BFP128_CONVERT_FROM,
145   S390_INSN_MFENCE,
146   S390_INSN_GZERO,   /* Assign zero to a guest register */
147   S390_INSN_GADD,    /* Add a value to a guest register */
148   /* The following 5 insns are mandated by translation chaining */
149   S390_INSN_XDIRECT,     /* direct transfer to guest address */
150   S390_INSN_XINDIR,      /* indirect transfer to guest address */
151   S390_INSN_XASSISTED,   /* assisted transfer to guest address */
152   S390_INSN_EVCHECK,     /* Event check */
153   S390_INSN_PROFINC      /* 64-bit profile counter increment */
154} s390_insn_tag;
155
156
157/* The kind of ALU instructions */
158typedef enum {
159   S390_ALU_ADD,
160   S390_ALU_SUB,
161   S390_ALU_MUL,   /* n-bit operands; result is lower n-bit of product */
162   S390_ALU_AND,
163   S390_ALU_OR,
164   S390_ALU_XOR,
165   S390_ALU_LSH,
166   S390_ALU_RSH,
167   S390_ALU_RSHA   /* arithmetic */
168} s390_alu_t;
169
170
171/* The kind of unary integer operations */
172typedef enum {
173   S390_ZERO_EXTEND_8,
174   S390_ZERO_EXTEND_16,
175   S390_ZERO_EXTEND_32,
176   S390_SIGN_EXTEND_8,
177   S390_SIGN_EXTEND_16,
178   S390_SIGN_EXTEND_32,
179   S390_NEGATE
180} s390_unop_t;
181
182/* The kind of ternary BFP operations */
183typedef enum {
184   S390_BFP_MADD,
185   S390_BFP_MSUB,
186} s390_bfp_triop_t;
187
188/* The kind of binary BFP operations */
189typedef enum {
190   S390_BFP_ADD,
191   S390_BFP_SUB,
192   S390_BFP_MUL,
193   S390_BFP_DIV
194} s390_bfp_binop_t;
195
196
197/* The kind of unary BFP operations */
198typedef enum {
199   S390_BFP_ABS,
200   S390_BFP_NABS,
201   S390_BFP_NEG,
202   S390_BFP_SQRT,
203   S390_BFP_I32_TO_F32,
204   S390_BFP_I32_TO_F64,
205   S390_BFP_I32_TO_F128,
206   S390_BFP_I64_TO_F32,
207   S390_BFP_I64_TO_F64,
208   S390_BFP_I64_TO_F128,
209   S390_BFP_F32_TO_I32,
210   S390_BFP_F32_TO_I64,
211   S390_BFP_F32_TO_F64,
212   S390_BFP_F32_TO_F128,
213   S390_BFP_F64_TO_I32,
214   S390_BFP_F64_TO_I64,
215   S390_BFP_F64_TO_F32,
216   S390_BFP_F64_TO_F128,
217   S390_BFP_F128_TO_I32,
218   S390_BFP_F128_TO_I64,
219   S390_BFP_F128_TO_F32,
220   S390_BFP_F128_TO_F64
221} s390_bfp_unop_t;
222
223
224/* Condition code. The encoding of the enumerators matches the value of
225   the mask field in the various branch opcodes. */
226typedef enum {
227   S390_CC_NEVER=  0,
228   S390_CC_OVFL =  1,   /* overflow */
229   S390_CC_H    =  2,   /* A > B ; high */
230   S390_CC_NLE  =  3,   /* not low or equal */
231   S390_CC_L    =  4,   /* A < B ; low */
232   S390_CC_NHE  =  5,   /* not high or equal */
233   S390_CC_LH   =  6,   /* low or high */
234   S390_CC_NE   =  7,   /* A != B ; not zero */
235   S390_CC_E    =  8,   /* A == B ; zero */
236   S390_CC_NLH  =  9,   /* not low or high */
237   S390_CC_HE   = 10,   /* A >= B ; high or equal*/
238   S390_CC_NL   = 11,   /* not low */
239   S390_CC_LE   = 12,   /* A <= B ; low or equal */
240   S390_CC_NH   = 13,   /* not high */
241   S390_CC_NO   = 14,   /* not overflow */
242   S390_CC_ALWAYS = 15
243} s390_cc_t;
244
245
246/* Rounding mode as it is encoded in the m3/m4 fields of certain
247   instructions (e.g. CFEBR) */
248typedef enum {
249/* S390_ROUND_NEAREST_AWAY = 1, not supported */
250   S390_ROUND_NEAREST_EVEN = 4,
251   S390_ROUND_ZERO         = 5,
252   S390_ROUND_POSINF       = 6,
253   S390_ROUND_NEGINF       = 7
254} s390_round_t;
255
256
257/* Invert the condition code */
258static __inline__ s390_cc_t
259s390_cc_invert(s390_cc_t cond)
260{
261   return S390_CC_ALWAYS - cond;
262}
263
264
265typedef struct {
266   s390_insn_tag tag;
267   UChar size;            /* size of the result in bytes */
268   union {
269      struct {
270         HReg        dst;
271         s390_amode *src;
272      } load;
273      struct {
274         s390_amode *dst;
275         HReg        src;
276      } store;
277      struct {
278         HReg        dst;
279         HReg        src;
280      } move;
281      struct {
282         s390_cc_t     cond;
283         HReg          dst;
284         s390_opnd_RMI src;
285      } cond_move;
286      struct {
287         HReg        dst;
288         ULong       value;  /* not sign extended */
289      } load_immediate;
290      /* add, and, or, xor */
291      struct {
292         s390_alu_t    tag;
293         HReg          dst; /* op1 */
294         s390_opnd_RMI op2;
295      } alu;
296      struct {
297         Bool          signed_multiply;
298         HReg          dst_hi;  /*           r10 */
299         HReg          dst_lo;  /* also op1  r11 */
300         s390_opnd_RMI op2;
301      } mul;
302      struct {
303         Bool          signed_divide;
304         HReg          op1_hi;  /* also remainder   r10 */
305         HReg          op1_lo;  /* also quotient    r11 */
306         s390_opnd_RMI op2;
307      } div;
308      struct {
309         HReg          rem; /* remainder      r10 */
310         HReg          op1; /* also quotient  r11 */
311         s390_opnd_RMI op2;
312      } divs;
313      struct {
314         HReg          num_bits; /* number of leftmost '0' bits  r10 */
315         HReg          clobber;  /* unspecified                  r11 */
316         s390_opnd_RMI src;
317      } clz;
318      struct {
319         s390_unop_t   tag;
320         HReg          dst;
321         s390_opnd_RMI src;
322      } unop;
323      struct {
324         Bool          signed_comparison;
325         HReg          src1;
326         s390_opnd_RMI src2;
327      } compare;
328      struct {
329         HReg          dst;  /* condition code in s390 encoding */
330         HReg          op1;
331         HReg          op2;
332      } bfp_compare;
333      struct {
334         s390_opnd_RMI src;
335      } test;
336      /* Convert the condition code to a boolean value. */
337      struct {
338         s390_cc_t cond;
339         HReg      dst;
340      } cc2bool;
341      struct {
342         HReg        op1;
343         s390_amode *op2;
344         HReg        op3;
345         HReg        old_mem;
346      } cas;
347      struct {
348         HReg        op1_high;
349         HReg        op1_low;
350         s390_amode *op2;
351         HReg        op3_high;
352         HReg        op3_low;
353         HReg        old_mem_high;
354         HReg        old_mem_low;
355         HReg        scratch;
356      } cdas;
357      /* Pseudo-insn for representing a helper call.
358         TARGET is the absolute address of the helper function
359         NUM_ARGS says how many arguments are being passed.
360         All arguments have integer type and are being passed according to ABI,
361         i.e. in registers r2, r3, r4, r5, and r6, with argument #0 being
362         passed in r2 and so forth. */
363      struct {
364         s390_cc_t cond;
365         Addr64    target;
366         UInt      num_args;
367         HReg      dst;       /* if not INVALID_HREG, put return value here */
368         HChar    *name;      /* callee's name (for debugging) */
369      } helper_call;
370      struct {
371         s390_bfp_triop_t tag;
372         s390_round_t     rounding_mode;
373         HReg             dst; /* first operand */
374         HReg             op2; /* second operand */
375         HReg             op3; /* third operand */
376      } bfp_triop;
377      struct {
378         s390_bfp_binop_t tag;
379         s390_round_t     rounding_mode;
380         HReg             dst; /* left operand */
381         HReg             op2; /* right operand */
382      } bfp_binop;
383      struct {
384         s390_bfp_unop_t tag;
385         s390_round_t    rounding_mode;
386         HReg            dst;  /* result */
387         HReg            op;   /* operand */
388      } bfp_unop;
389      struct {
390         s390_bfp_binop_t tag;
391         s390_round_t     rounding_mode;
392         HReg             dst_hi; /* left operand; high part */
393         HReg             dst_lo; /* left operand; low part */
394         HReg             op2_hi; /* right operand; high part */
395         HReg             op2_lo; /* right operand; low part */
396      } bfp128_binop;
397      /* This variant is also used by the BFP128_CONVERT_TO and
398         BFP128_CONVERT_FROM insns. */
399      struct {
400         s390_bfp_unop_t  tag;
401         s390_round_t     rounding_mode;
402         HReg             dst_hi; /* result; high part */
403         HReg             dst_lo; /* result; low part */
404         HReg             op_hi;  /* operand; high part */
405         HReg             op_lo;  /* operand; low part */
406      } bfp128_unop;
407      struct {
408         HReg             dst;    /* condition code in s390 encoding */
409         HReg             op1_hi; /* left operand; high part */
410         HReg             op1_lo; /* left operand; low part */
411         HReg             op2_hi; /* right operand; high part */
412         HReg             op2_lo; /* right operand; low part */
413      } bfp128_compare;
414      struct {
415         UInt             offset;
416      } gzero;
417      struct {
418         UInt             offset;
419         UChar            delta;
420         ULong            value;  /* for debugging only */
421      } gadd;
422
423      /* The next 5 entries are generic to support translation chaining */
424
425      /* Update the guest IA value, then exit requesting to chain
426         to it.  May be conditional. */
427      struct {
428         s390_cc_t     cond;
429         Bool          to_fast_entry;  /* chain to the what entry point? */
430         Addr64        dst;            /* next guest address */
431         s390_amode   *guest_IA;
432      } xdirect;
433      /* Boring transfer to a guest address not known at JIT time.
434         Not chainable.  May be conditional. */
435      struct {
436         s390_cc_t     cond;
437         HReg          dst;
438         s390_amode   *guest_IA;
439      } xindir;
440      /* Assisted transfer to a guest address, most general case.
441         Not chainable.  May be conditional. */
442      struct {
443         s390_cc_t     cond;
444         IRJumpKind    kind;
445         HReg          dst;
446         s390_amode   *guest_IA;
447      } xassisted;
448      struct {
449         /* fixs390: I don't think these are really needed
450            as the gsp and the offset are fixed  no ? */
451         s390_amode   *counter;    /* dispatch counter */
452         s390_amode   *fail_addr;
453      } evcheck;
454      struct {
455         /* No fields.  The address of the counter to increment is
456            installed later, post-translation, by patching it in,
457            as it is not known at translation time. */
458      } profinc;
459
460   } variant;
461} s390_insn;
462
463s390_insn *s390_insn_load(UChar size, HReg dst, s390_amode *src);
464s390_insn *s390_insn_store(UChar size, s390_amode *dst, HReg src);
465s390_insn *s390_insn_move(UChar size, HReg dst, HReg src);
466s390_insn *s390_insn_cond_move(UChar size, s390_cc_t cond, HReg dst,
467                               s390_opnd_RMI src);
468s390_insn *s390_insn_load_immediate(UChar size, HReg dst, ULong val);
469s390_insn *s390_insn_alu(UChar size, s390_alu_t, HReg dst,
470                         s390_opnd_RMI op2);
471s390_insn *s390_insn_mul(UChar size, HReg dst_hi, HReg dst_lo,
472                         s390_opnd_RMI op2, Bool signed_multiply);
473s390_insn *s390_insn_div(UChar size, HReg op1_hi, HReg op1_lo,
474                         s390_opnd_RMI op2, Bool signed_divide);
475s390_insn *s390_insn_divs(UChar size, HReg rem, HReg op1, s390_opnd_RMI op2);
476s390_insn *s390_insn_clz(UChar size, HReg num_bits, HReg clobber,
477                         s390_opnd_RMI op);
478s390_insn *s390_insn_cas(UChar size, HReg op1, s390_amode *op2, HReg op3,
479                         HReg old);
480s390_insn *s390_insn_cdas(UChar size, HReg op1_high, HReg op1_low,
481                          s390_amode *op2, HReg op3_high, HReg op3_low,
482                          HReg old_high, HReg old_low, HReg scratch);
483s390_insn *s390_insn_unop(UChar size, s390_unop_t tag, HReg dst,
484                          s390_opnd_RMI opnd);
485s390_insn *s390_insn_cc2bool(HReg dst, s390_cc_t src);
486s390_insn *s390_insn_test(UChar size, s390_opnd_RMI src);
487s390_insn *s390_insn_compare(UChar size, HReg dst, s390_opnd_RMI opnd,
488                             Bool signed_comparison);
489s390_insn *s390_insn_helper_call(s390_cc_t cond, Addr64 target, UInt num_args,
490                                 HChar *name, HReg dst);
491s390_insn *s390_insn_bfp_triop(UChar size, s390_bfp_triop_t, HReg dst, HReg op2,
492                               HReg op3, s390_round_t);
493s390_insn *s390_insn_bfp_binop(UChar size, s390_bfp_binop_t, HReg dst, HReg op2,
494                               s390_round_t);
495s390_insn *s390_insn_bfp_unop(UChar size, s390_bfp_unop_t tag, HReg dst,
496                              HReg op, s390_round_t);
497s390_insn *s390_insn_bfp_compare(UChar size, HReg dst, HReg op1, HReg op2);
498s390_insn *s390_insn_bfp128_binop(UChar size, s390_bfp_binop_t, HReg dst_hi,
499                                  HReg dst_lo, HReg op2_hi, HReg op2_lo,
500                                  s390_round_t);
501s390_insn *s390_insn_bfp128_unop(UChar size, s390_bfp_unop_t, HReg dst_hi,
502                                 HReg dst_lo, HReg op_hi, HReg op_lo,
503                                 s390_round_t);
504s390_insn *s390_insn_bfp128_compare(UChar size, HReg dst, HReg op1_hi,
505                                    HReg op1_lo, HReg op2_hi, HReg op2_lo);
506s390_insn *s390_insn_bfp128_convert_to(UChar size, s390_bfp_unop_t,
507                                       HReg dst_hi, HReg dst_lo, HReg op);
508s390_insn *s390_insn_bfp128_convert_from(UChar size, s390_bfp_unop_t,
509                                         HReg dst, HReg op_hi, HReg op_lo,
510                                         s390_round_t);
511s390_insn *s390_insn_mfence(void);
512s390_insn *s390_insn_gzero(UChar size, UInt offset);
513s390_insn *s390_insn_gadd(UChar size, UInt offset, UChar delta, ULong value);
514
515/* Five for translation chaining */
516s390_insn *s390_insn_xdirect(s390_cc_t cond, Addr64 dst, s390_amode *guest_IA,
517                             Bool to_fast_entry);
518s390_insn *s390_insn_xindir(s390_cc_t cond, HReg dst, s390_amode *guest_IA);
519s390_insn *s390_insn_xassisted(s390_cc_t cond, HReg dst, s390_amode *guest_IA,
520                               IRJumpKind kind);
521s390_insn *s390_insn_evcheck(s390_amode *counter, s390_amode *fail_addr);
522s390_insn *s390_insn_profinc(void);
523
524const HChar *s390_insn_as_string(const s390_insn *);
525
526/*--------------------------------------------------------*/
527/* --- Interface exposed to VEX                       --- */
528/*--------------------------------------------------------*/
529
530void ppS390AMode(s390_amode *);
531void ppS390Instr(s390_insn *, Bool mode64);
532void ppHRegS390(HReg);
533
534/* Some functions that insulate the register allocator from details
535   of the underlying instruction set. */
536void  getRegUsage_S390Instr( HRegUsage *, s390_insn *, Bool );
537void  mapRegs_S390Instr    ( HRegRemap *, s390_insn *, Bool );
538Bool  isMove_S390Instr     ( s390_insn *, HReg *, HReg * );
539Int   emit_S390Instr       ( Bool *, UChar *, Int, s390_insn *, Bool,
540                             void *, void *, void *, void *);
541void  getAllocableRegs_S390( Int *, HReg **, Bool );
542void  genSpill_S390        ( HInstr **, HInstr **, HReg , Int , Bool );
543void  genReload_S390       ( HInstr **, HInstr **, HReg , Int , Bool );
544s390_insn *directReload_S390 ( s390_insn *, HReg, Short );
545HInstrArray *iselSB_S390   ( IRSB *, VexArch, VexArchInfo *, VexAbiInfo *,
546                             Int, Int, Bool, Bool, Addr64);
547
548/* Return the number of bytes of code needed for an event check */
549Int evCheckSzB_S390(void);
550
551/* Perform a chaining and unchaining of an XDirect jump. */
552VexInvalRange chainXDirect_S390(void *place_to_chain,
553                                void *disp_cp_chain_me_EXPECTED,
554                                void *place_to_jump_to);
555
556VexInvalRange unchainXDirect_S390(void *place_to_unchain,
557                                  void *place_to_jump_to_EXPECTED,
558                                  void *disp_cp_chain_me);
559
560/* Patch the counter location into an existing ProfInc point. */
561VexInvalRange patchProfInc_S390(void  *code_to_patch,
562                                ULong *location_of_counter);
563
564/* KLUDGE: See detailled comment in host_s390_defs.c. */
565extern UInt s390_host_hwcaps;
566
567/* Convenience macros to test installed facilities */
568#define s390_host_has_ldisp \
569                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_LDISP))
570#define s390_host_has_eimm \
571                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_EIMM))
572#define s390_host_has_gie \
573                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_GIE))
574#define s390_host_has_dfp \
575                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_DFP))
576#define s390_host_has_fgx \
577                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_FGX))
578#define s390_host_has_etf2 \
579                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_ETF2))
580#define s390_host_has_stfle \
581                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_STFLE))
582#define s390_host_has_etf3 \
583                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_ETF3))
584
585#endif /* ndef __VEX_HOST_S390_DEFS_H */
586
587/*---------------------------------------------------------------*/
588/*--- end                                    host_s390_defs.h ---*/
589/*---------------------------------------------------------------*/
590