/* -*- mode: C; c-basic-offset: 3; -*- */

/*---------------------------------------------------------------*/
/*--- begin                                  host_s390_defs.h ---*/
/*---------------------------------------------------------------*/

/*
   This file is part of Valgrind, a dynamic binary instrumentation
   framework.

   Copyright IBM Corp. 2010-2020

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, see <http://www.gnu.org/licenses/>.

   The GNU General Public License is contained in the file COPYING.
*/

/* Contributed by Florian Krohm */

#ifndef __VEX_HOST_S390_DEFS_H
#define __VEX_HOST_S390_DEFS_H

#include "libvex_basictypes.h"            /* Bool */
#include "libvex.h"                       /* VexArchInfo */
#include "host_generic_regs.h"            /* HReg */
#include "s390_defs.h"                    /* s390_cc_t */

/* --------- Registers --------- */
const HChar *s390_hreg_as_string(HReg);
HReg s390_hreg_gpr(UInt regno);
HReg s390_hreg_fpr(UInt regno);
HReg s390_hreg_vr(UInt regno);

/* Dedicated registers */
HReg s390_hreg_guest_state_pointer(void);
HReg s390_hreg_stack_pointer(void);


/* Given the index of a function argument, return the number of the
   general purpose register in which it is being passed. Arguments are
   counted 0, 1, 2, ... and they are being passed in r2, r3, r4, ... */
static __inline__ UInt
s390_gprno_from_arg_index(UInt ix)
{
   return ix + 2;
}

/* --------- Memory address expressions (amodes). --------- */

/* These are the address modes:
   (1) b12:  base register + 12-bit unsigned offset   (e.g. RS)
   (2) b20:  base register + 20-bit signed offset     (e.g. RSY)
   (3) bx12: base register + index register + 12-bit unsigned offset (e.g. RX)
   (4) bx20: base register + index register + 20-bit signed offset   (e.g. RXY)
   fixs390: There is also pc-relative stuff.. e.g. LARL
*/

typedef enum {
   S390_AMODE_B12,
   S390_AMODE_B20,
   S390_AMODE_BX12,
   S390_AMODE_BX20
} s390_amode_t;

typedef struct {
   s390_amode_t tag;
   HReg b;
   HReg x;       /* hregNumber(x) == 0  for S390_AMODE_B12/B20 kinds */
   Int  d;       /* 12 bit unsigned or 20 bit signed */
} s390_amode;


s390_amode *s390_amode_b12(Int d, HReg b);
s390_amode *s390_amode_b20(Int d, HReg b);
s390_amode *s390_amode_bx12(Int d, HReg b, HReg x);
s390_amode *s390_amode_bx20(Int d, HReg b, HReg x);
s390_amode *s390_amode_for_guest_state(Int d);
s390_amode *s390_amode_for_stack_pointer(Int d);
Bool        s390_amode_is_sane(const s390_amode *);

const HChar *s390_amode_as_string(const s390_amode *);

/* ------------- 2nd (right) operand of binary operation ---------------- */

typedef enum {
   S390_OPND_REG,
   S390_OPND_IMMEDIATE,
   S390_OPND_AMODE
} s390_opnd_t;


/* Naming convention for operand locations:
   R    - GPR
   I    - immediate value
   M    - memory (any Amode may be used)
*/

/* An operand that is either in a GPR or is addressable via a BX20 amode */
typedef struct {
   s390_opnd_t tag;
   union {
      HReg        reg;
      s390_amode *am;
      ULong       imm;
   } variant;
} s390_opnd_RMI;


/* The kind of instructions */
typedef enum {
   S390_INSN_LOAD,   /* load register from memory */
   S390_INSN_STORE,  /* store register to memory */
   S390_INSN_MOVE,   /* from register to register */
   S390_INSN_MEMCPY, /* from memory to memory */
   S390_INSN_COND_MOVE, /* conditonal "move" to register */
   S390_INSN_LOAD_IMMEDIATE,
   S390_INSN_ALU,
   S390_INSN_SMUL,   /*   signed multiply; n-bit operands; 2n-bit result */
   S390_INSN_UMUL,   /* unsigned multiply; n-bit operands; 2n-bit result */
   S390_INSN_SDIV,   /*   signed division; 2n-bit / n-bit -> n-bit quot/rem */
   S390_INSN_UDIV,   /* unsigned division; 2n-bit / n-bit -> n-bit quot/rem */
   S390_INSN_DIVS,   /* n-bit dividend; n-bit divisor; n-bit quot/rem */
   S390_INSN_CLZ,    /* count left-most zeroes */
   S390_INSN_UNOP,
   S390_INSN_TEST,   /* test operand and set cc */
   S390_INSN_CC2BOOL,/* convert condition code to 0/1 */
   S390_INSN_COMPARE,
   S390_INSN_HELPER_CALL,
   S390_INSN_CAS,    /* compare and swap */
   S390_INSN_CDAS,   /* compare double and swap */
   S390_INSN_BFP_BINOP, /* Binary floating point */
   S390_INSN_BFP_UNOP,
   S390_INSN_BFP_TRIOP,
   S390_INSN_BFP_COMPARE,
   S390_INSN_BFP_CONVERT,
   S390_INSN_DFP_BINOP, /* Decimal floating point */
   S390_INSN_DFP_UNOP,
   S390_INSN_DFP_INTOP,
   S390_INSN_DFP_COMPARE,
   S390_INSN_DFP_CONVERT,
   S390_INSN_DFP_REROUND,
   S390_INSN_FP_CONVERT,
   S390_INSN_MFENCE,
   S390_INSN_MIMM,    /* Assign an immediate constant to a memory location */
   S390_INSN_MADD,    /* Add a value to a memory location */
   S390_INSN_SET_FPC_BFPRM, /* Set the bfp rounding mode in the FPC */
   S390_INSN_SET_FPC_DFPRM, /* Set the dfp rounding mode in the FPC */
   /* The following 5 insns are mandated by translation chaining */
   S390_INSN_XDIRECT,     /* direct transfer to guest address */
   S390_INSN_XINDIR,      /* indirect transfer to guest address */
   S390_INSN_XASSISTED,   /* assisted transfer to guest address */
   S390_INSN_EVCHECK,     /* Event check */
   S390_INSN_PROFINC,     /* 64-bit profile counter increment */
   S390_INSN_VEC_AMODEOP,
   S390_INSN_VEC_AMODEINTOP,
   S390_INSN_VEC_UNOP,
   S390_INSN_VEC_BINOP,
   S390_INSN_VEC_TRIOP,
   S390_INSN_VEC_REPLICATE
} s390_insn_tag;


/* The kind of ALU instructions */
typedef enum {
   S390_ALU_ADD,
   S390_ALU_SUB,
   S390_ALU_MUL,   /* n-bit operands; result is lower n-bit of product */
   S390_ALU_AND,
   S390_ALU_OR,
   S390_ALU_XOR,
   S390_ALU_ILIH,  /* insert low half of 2nd operand into high half of 1st
                      operand */
   S390_ALU_LSH,
   S390_ALU_RSH,
   S390_ALU_RSHA   /* arithmetic */
} s390_alu_t;


/* The kind of unary integer operations */
typedef enum {
   S390_ZERO_EXTEND_8,
   S390_ZERO_EXTEND_16,
   S390_ZERO_EXTEND_32,
   S390_SIGN_EXTEND_8,
   S390_SIGN_EXTEND_16,
   S390_SIGN_EXTEND_32,
   S390_NEGATE,
   S390_VEC_FILL,
   S390_VEC_DUPLICATE,
   S390_VEC_UNPACKLOWS,
   S390_VEC_UNPACKLOWU,
   S390_VEC_ABS,
   S390_VEC_COUNT_LEADING_ZEROES,
   S390_VEC_COUNT_TRAILING_ZEROES,
   S390_VEC_COUNT_ONES,
   S390_VEC_FLOAT_NEG,
   S390_VEC_FLOAT_ABS,
   S390_VEC_FLOAT_NABS,
   S390_VEC_FLOAT_SQRT,
   S390_UNOP_T_INVALID
} s390_unop_t;

/* The kind of ternary BFP operations */
typedef enum {
   S390_BFP_MADD,
   S390_BFP_MSUB,
} s390_bfp_triop_t;

/* The kind of binary BFP operations */
typedef enum {
   S390_BFP_ADD,
   S390_BFP_SUB,
   S390_BFP_MUL,
   S390_BFP_DIV
} s390_bfp_binop_t;

/* The kind of unary BFP operations */
typedef enum {
   S390_BFP_ABS,
   S390_BFP_NABS,
   S390_BFP_NEG,
   S390_BFP_SQRT
} s390_bfp_unop_t;

/* Type conversion operations: to and/or from binary floating point */
typedef enum {
   S390_BFP_I32_TO_F32,
   S390_BFP_I32_TO_F64,
   S390_BFP_I32_TO_F128,
   S390_BFP_I64_TO_F32,
   S390_BFP_I64_TO_F64,
   S390_BFP_I64_TO_F128,
   S390_BFP_U32_TO_F32,
   S390_BFP_U32_TO_F64,
   S390_BFP_U32_TO_F128,
   S390_BFP_U64_TO_F32,
   S390_BFP_U64_TO_F64,
   S390_BFP_U64_TO_F128,
   S390_BFP_F32_TO_I32,
   S390_BFP_F32_TO_I64,
   S390_BFP_F32_TO_U32,
   S390_BFP_F32_TO_U64,
   S390_BFP_F32_TO_F64,
   S390_BFP_F32_TO_F128,
   S390_BFP_F64_TO_I32,
   S390_BFP_F64_TO_I64,
   S390_BFP_F64_TO_U32,
   S390_BFP_F64_TO_U64,
   S390_BFP_F64_TO_F32,
   S390_BFP_F64_TO_F128,
   S390_BFP_F128_TO_I32,
   S390_BFP_F128_TO_I64,
   S390_BFP_F128_TO_U32,
   S390_BFP_F128_TO_U64,
   S390_BFP_F128_TO_F32,
   S390_BFP_F128_TO_F64,
   S390_BFP_F32_TO_F32I,
   S390_BFP_F64_TO_F64I,
   S390_BFP_F128_TO_F128I
} s390_bfp_conv_t;

/* Type conversion operations: to and/or from decimal floating point */
typedef enum {
   S390_DFP_D32_TO_D64,
   S390_DFP_D64_TO_D32,
   S390_DFP_D64_TO_D128,
   S390_DFP_D128_TO_D64,
   S390_DFP_I32_TO_D64,
   S390_DFP_I32_TO_D128,
   S390_DFP_I64_TO_D64,
   S390_DFP_I64_TO_D128,
   S390_DFP_U32_TO_D64,
   S390_DFP_U32_TO_D128,
   S390_DFP_U64_TO_D64,
   S390_DFP_U64_TO_D128,
   S390_DFP_D64_TO_I32,
   S390_DFP_D64_TO_I64,
   S390_DFP_D64_TO_U32,
   S390_DFP_D64_TO_U64,
   S390_DFP_D128_TO_I32,
   S390_DFP_D128_TO_I64,
   S390_DFP_D128_TO_U32,
   S390_DFP_D128_TO_U64
} s390_dfp_conv_t;

typedef enum {
   S390_FP_F32_TO_D32,
   S390_FP_F32_TO_D64,
   S390_FP_F32_TO_D128,
   S390_FP_F64_TO_D32,
   S390_FP_F64_TO_D64,
   S390_FP_F64_TO_D128,
   S390_FP_F128_TO_D32,
   S390_FP_F128_TO_D64,
   S390_FP_F128_TO_D128,
   S390_FP_D32_TO_F32,
   S390_FP_D32_TO_F64,
   S390_FP_D32_TO_F128,
   S390_FP_D64_TO_F32,
   S390_FP_D64_TO_F64,
   S390_FP_D64_TO_F128,
   S390_FP_D128_TO_F32,
   S390_FP_D128_TO_F64,
   S390_FP_D128_TO_F128
} s390_fp_conv_t;

/* The kind of binary DFP operations */
typedef enum {
   S390_DFP_ADD,
   S390_DFP_SUB,
   S390_DFP_MUL,
   S390_DFP_DIV,
   S390_DFP_QUANTIZE
} s390_dfp_binop_t;

/* The kind of unary DFP operations */
typedef enum {
   S390_DFP_EXTRACT_EXP_D64,
   S390_DFP_EXTRACT_EXP_D128,
   S390_DFP_EXTRACT_SIG_D64,
   S390_DFP_EXTRACT_SIG_D128,
} s390_dfp_unop_t;

/* The DFP operations with 2 operands one of them being integer */
typedef enum {
   S390_DFP_SHIFT_LEFT,
   S390_DFP_SHIFT_RIGHT,
   S390_DFP_INSERT_EXP
} s390_dfp_intop_t;

/* The kind of DFP compare operations */
typedef enum {
   S390_DFP_COMPARE,
   S390_DFP_COMPARE_EXP,
} s390_dfp_cmp_t;

/* The vector operations with 2 operands one of them being amode */
typedef enum {
   S390_VEC_GET_ELEM,
   S390_VEC_ELEM_SHL_INT,
   S390_VEC_ELEM_SHRA_INT,
   S390_VEC_ELEM_SHRL_INT,
   S390_VEC_AMODEOP_T_INVALID
} s390_vec_amodeop_t;

/* The vector operations with three (vector, amode and integer) operands */
typedef enum {
   S390_VEC_SET_ELEM
} s390_vec_amodeintop_t;

/* The vector operations with two operands */
typedef enum {
   S390_VEC_PACK,
   S390_VEC_PACK_SATURS,
   S390_VEC_PACK_SATURU,
   S390_VEC_COMPARE_EQUAL,
   S390_VEC_OR,
   S390_VEC_ORC,
   S390_VEC_XOR,
   S390_VEC_AND,
   S390_VEC_MERGEL,
   S390_VEC_MERGEH,
   S390_VEC_NOR,
   S390_VEC_INT_ADD,
   S390_VEC_INT_SUB,
   S390_VEC_MAXU,
   S390_VEC_MAXS,
   S390_VEC_MINU,
   S390_VEC_MINS,
   S390_VEC_AVGU,
   S390_VEC_AVGS,
   S390_VEC_COMPARE_GREATERS,
   S390_VEC_COMPARE_GREATERU,
   S390_VEC_INT_MUL_HIGHS,
   S390_VEC_INT_MUL_HIGHU,
   S390_VEC_INT_MUL_LOW,
   S390_VEC_INT_MUL_EVENS,
   S390_VEC_INT_MUL_EVENU,
   S390_VEC_ELEM_SHL_V,
   S390_VEC_ELEM_SHRA_V,
   S390_VEC_ELEM_SHRL_V,
   S390_VEC_ELEM_ROLL_V,

   /* host_s390_isel depends on this order. */
   S390_VEC_SHL_BITS, S390_VEC_SHL_BYTES,
   S390_VEC_SHRL_BITS, S390_VEC_SHRL_BYTES,
   S390_VEC_SHRA_BITS, S390_VEC_SHRA_BYTES,

   S390_VEC_PWSUM_W,
   S390_VEC_PWSUM_DW,
   S390_VEC_PWSUM_QW,

   S390_VEC_INIT_FROM_GPRS,
   S390_VEC_INIT_FROM_FPRS,
   S390_VEC_FLOAT_ADD,
   S390_VEC_FLOAT_SUB,
   S390_VEC_FLOAT_MUL,
   S390_VEC_FLOAT_DIV,
   S390_VEC_FLOAT_COMPARE_EQUAL,
   S390_VEC_FLOAT_COMPARE_LESS_OR_EQUAL,
   S390_VEC_FLOAT_COMPARE_LESS,
   S390_VEC_BINOP_T_INVALID
} s390_vec_binop_t;

/* The vector operations with three operands */
typedef enum {
   S390_VEC_PERM,
   S390_VEC_FLOAT_MADD,
   S390_VEC_FLOAT_MSUB
} s390_vec_triop_t;

/* The details of a CDAS insn. Carved out to keep the size of
   s390_insn low */
typedef struct {
   HReg        op1_high;
   HReg        op1_low;
   s390_amode *op2;
   HReg        op3_high;
   HReg        op3_low;
   HReg        old_mem_high;
   HReg        old_mem_low;
   HReg        scratch;
} s390_cdas;

/* The details of a binary DFP insn. Carved out to keep the size of
   s390_insn low */
typedef struct {
   s390_dfp_binop_t tag;
   s390_dfp_round_t rounding_mode;
   HReg         dst_hi; /* 128-bit result high part; 64-bit result */
   HReg         dst_lo; /* 128-bit result low part */
   HReg         op2_hi; /* 128-bit operand high part; 64-bit opnd 1 */
   HReg         op2_lo; /* 128-bit operand low part */
   HReg         op3_hi; /* 128-bit operand high part; 64-bit opnd 2 */
   HReg         op3_lo; /* 128-bit operand low part */
} s390_dfp_binop;

typedef struct {
   s390_fp_conv_t  tag;
   s390_dfp_round_t rounding_mode;
   HReg         dst_hi; /* 128-bit result high part; 32/64-bit result */
   HReg         dst_lo; /* 128-bit result low part */
   HReg         op_hi;  /* 128-bit operand high part; 32/64-bit opnd */
   HReg         op_lo;  /* 128-bit operand low part */
   HReg         r1;     /* clobbered register GPR #1 */
} s390_fp_convert;

/* Pseudo-insn for representing a helper call.
   TARGET is the absolute address of the helper function
   NUM_ARGS says how many arguments are being passed.
   All arguments have integer type and are being passed according to ABI,
   i.e. in registers r2, r3, r4, r5, and r6, with argument #0 being
   passed in r2 and so forth. */
typedef struct {
   s390_cc_t    cond     : 16;
   UInt         num_args : 16;
   RetLoc       rloc;     /* where the return value will be */
   Addr64       target;
   const HChar *name;      /* callee's name (for debugging) */
} s390_helper_call;

typedef struct {
   s390_insn_tag tag;
   /* Usually, this is the size of the result of an operation.
      Exceptions are:
      - for comparisons it is the size of the operand
   */
   UChar size;
   union {
      struct {
         HReg        dst;
         s390_amode *src;
      } load;
      struct {
         s390_amode *dst;
         HReg        src;
      } store;
      struct {
         HReg        dst;
         HReg        src;
      } move;
      struct {
         s390_amode *dst;
         s390_amode *src;
      } memcpy;
      struct {
         s390_cc_t     cond;
         HReg          dst;
         s390_opnd_RMI src;
      } cond_move;
      struct {
         HReg        dst;
         ULong       value;  /* not sign extended */
      } load_immediate;
      /* add, and, or, xor */
      struct {
         s390_alu_t    tag;
         HReg          dst; /* op1 */
         s390_opnd_RMI op2;
      } alu;
      struct {
         HReg          dst_hi;  /*           r10 */
         HReg          dst_lo;  /* also op1  r11 */
         s390_opnd_RMI op2;
      } mul;
      struct {
         HReg          op1_hi;  /* also remainder   r10 */
         HReg          op1_lo;  /* also quotient    r11 */
         s390_opnd_RMI op2;
      } div;
      struct {
         HReg          rem; /* remainder      r10 */
         HReg          op1; /* also quotient  r11 */
         s390_opnd_RMI op2;
      } divs;
      struct {
         HReg          num_bits; /* number of leftmost '0' bits  r10 */
         HReg          clobber;  /* unspecified                  r11 */
         s390_opnd_RMI src;
      } clz;
      struct {
         s390_unop_t   tag;
         HReg          dst;
         s390_opnd_RMI src;
      } unop;
      struct {
         Bool          signed_comparison;
         HReg          src1;
         s390_opnd_RMI src2;
      } compare;
      struct {
         s390_opnd_RMI src;
      } test;
      /* Convert the condition code to a boolean value. */
      struct {
         s390_cc_t cond;
         HReg      dst;
      } cc2bool;
      struct {
         HReg        op1;
         s390_amode *op2;
         HReg        op3;
         HReg        old_mem;
      } cas;
      struct {
         s390_cdas *details;
      } cdas;
      struct {
         s390_helper_call *details;
      } helper_call;

      /* Floating point instructions (including conversion to/from floating
         point

         128-bit floating point requires register pairs. As the registers
         in a register pair cannot be chosen independently it would suffice
         to store only one register of the pair in order to represent it.
         We chose not to do that as being explicit about all registers
         helps with debugging and does not require special handling in 
         e.g. s390_insn_get_reg_usage, It'd be all too easy to forget about
         the "other" register in a pair if it is implicit.

         The convention for all fp s390_insn is that the _hi register will
         be used to store the result / operand of a 32/64-bit operation.
         The _hi register holds the  8 bytes of HIgher significance of a
         128-bit value (hence the suffix). However, it is the lower numbered
         register of a register pair. POP says that the lower numbered
         register is used to identify the pair in an insn encoding. So,
         when an insn is emitted, only the _hi registers need to be looked
         at. Nothing special is needed for 128-bit BFP which is nice.
      */

      /* There are currently no ternary 128-bit BFP operations. */
      struct {
         s390_bfp_triop_t tag;
         HReg         dst;
         HReg         op2;
         HReg         op3;
      } bfp_triop;
      struct {
         s390_bfp_binop_t tag;
         HReg         dst_hi; /* 128-bit result high part; 32/64-bit result */
         HReg         dst_lo; /* 128-bit result low part */
         HReg         op2_hi; /* 128-bit operand high part; 32/64-bit opnd */
         HReg         op2_lo; /* 128-bit operand low part */
      } bfp_binop;
      struct {
         s390_bfp_unop_t  tag;
         HReg         dst_hi; /* 128-bit result high part; 32/64-bit result */
         HReg         dst_lo; /* 128-bit result low part */
         HReg         op_hi;  /* 128-bit operand high part; 32/64-bit opnd */
         HReg         op_lo;  /* 128-bit operand low part */
      } bfp_unop;
      struct {
         s390_bfp_conv_t  tag;
         s390_bfp_round_t rounding_mode;
         HReg         dst_hi; /* 128-bit result high part; 32/64-bit result */
         HReg         dst_lo; /* 128-bit result low part */
         HReg         op_hi;  /* 128-bit operand high part; 32/64-bit opnd */
         HReg         op_lo;  /* 128-bit operand low part */
      } bfp_convert;
      struct {
         HReg         dst;     /* condition code in s390 encoding */
         HReg         op1_hi;  /* 128-bit operand high part; 32/64-bit opnd */
         HReg         op1_lo;  /* 128-bit operand low part */
         HReg         op2_hi;  /* 128-bit operand high part; 32/64-bit opnd */
         HReg         op2_lo;  /* 128-bit operand low part */
      } bfp_compare;
      struct {
         s390_dfp_binop *details;
      } dfp_binop;
      struct {
         s390_dfp_unop_t tag;
         HReg         dst_hi; /* 128-bit result high part; 64-bit result */
         HReg         dst_lo; /* 128-bit result low part */
         HReg         op_hi;  /* 128-bit operand high part; 64-bit opnd */
         HReg         op_lo;  /* 128-bit operand low part */
      } dfp_unop;
      struct {
         s390_dfp_intop_t tag;
         HReg         dst_hi; /* 128-bit result high part; 64-bit result */
         HReg         dst_lo; /* 128-bit result low part */
         HReg         op2;    /* integer operand */
         HReg         op3_hi; /* 128-bit operand high part; 64-bit opnd */
         HReg         op3_lo; /* 128-bit operand low part */
      } dfp_intop;
      struct {
         s390_dfp_conv_t  tag;
         s390_dfp_round_t rounding_mode;
         HReg         dst_hi; /* 128-bit result high part; 64-bit result */
         HReg         dst_lo; /* 128-bit result low part */
         HReg         op_hi;  /* 128-bit operand high part; 64-bit opnd */
         HReg         op_lo;  /* 128-bit operand low part */
      } dfp_convert;
      struct {
         s390_fp_convert *details;
      } fp_convert;
      struct {
         s390_dfp_cmp_t tag;
         HReg         dst;     /* condition code in s390 encoding */
         HReg         op1_hi;  /* 128-bit operand high part; 64-bit opnd 1 */
         HReg         op1_lo;  /* 128-bit operand low part */
         HReg         op2_hi;  /* 128-bit operand high part; 64-bit opnd 2 */
         HReg         op2_lo;  /* 128-bit operand low part */
      } dfp_compare;
      struct {
         s390_dfp_round_t rounding_mode;
         HReg         dst_hi; /* 128-bit result high part; 64-bit result */
         HReg         dst_lo; /* 128-bit result low part */
         HReg         op2;    /* integer operand */
         HReg         op3_hi; /* 128-bit operand high part; 64-bit opnd */
         HReg         op3_lo; /* 128-bit operand low part */
      } dfp_reround;

      /* Miscellaneous */
      struct {
         s390_amode      *dst;
         ULong            value;  /* sign extended */
      } mimm;
      struct {
         s390_amode      *dst;
         UChar            delta;
         ULong            value;  /* for debugging only */
      } madd;
      struct {
         HReg             mode;
      } set_fpc_bfprm;
      struct {
         HReg             mode;
      } set_fpc_dfprm;

      /* The next 5 entries are generic to support translation chaining */

      /* Update the guest IA value, then exit requesting to chain
         to it.  May be conditional. */
      struct {
         s390_cc_t     cond;
         Bool          to_fast_entry;  /* chain to the what entry point? */
         Addr64        dst;            /* next guest address */
         s390_amode   *guest_IA;
      } xdirect;
      /* Boring transfer to a guest address not known at JIT time.
         Not chainable.  May be conditional. */
      struct {
         s390_cc_t     cond;
         HReg          dst;
         s390_amode   *guest_IA;
      } xindir;
      /* Assisted transfer to a guest address, most general case.
         Not chainable.  May be conditional. */
      struct {
         s390_cc_t     cond;
         IRJumpKind    kind;
         HReg          dst;
         s390_amode   *guest_IA;
      } xassisted;
      struct {
         /* fixs390: I don't think these are really needed
            as the gsp and the offset are fixed  no ? */
         s390_amode   *counter;    /* dispatch counter */
         s390_amode   *fail_addr;
      } evcheck;
      struct {
         /* No fields.  The address of the counter to increment is
            installed later, post-translation, by patching it in,
            as it is not known at translation time. */
      } profinc;
      struct {
         s390_vec_amodeop_t tag;
         HReg          dst;    /* 64-bit result */
         HReg          op1;    /* 128-bit operand */
         s390_amode   *op2;    /* amode operand */
      } vec_amodeop;
      struct {
         s390_vec_amodeintop_t tag;
         HReg          dst;    /* 128-bit result */
         s390_amode   *op2;    /* amode operand */
         HReg          op3;    /* integer operand */
      } vec_amodeintop;
      struct {
         s390_vec_binop_t tag;
         HReg          dst;    /* 128-bit result */
         HReg          op1;    /* 128-bit first operand */
         HReg          op2;    /* 128-bit second operand */
      } vec_binop;
      struct {
         s390_vec_triop_t tag;
         HReg          dst;    /* 128-bit result */
         HReg          op1;    /* 128-bit first operand */
         HReg          op2;    /* 128-bit second operand */
         HReg          op3;    /* 128-bit third operand */
      } vec_triop;
      struct {
         HReg          dst;    /* 128-bit result */
         HReg          op1;    /* 128-bit first operand */
         UChar         idx;    /* index of element to replicate */
      } vec_replicate;
   } variant;
} s390_insn;

s390_insn *s390_insn_load(UChar size, HReg dst, s390_amode *src);
s390_insn *s390_insn_store(UChar size, s390_amode *dst, HReg src);
s390_insn *s390_insn_move(UChar size, HReg dst, HReg src);
s390_insn *s390_insn_memcpy(UChar size, s390_amode *dst, s390_amode *src);
s390_insn *s390_insn_cond_move(UChar size, s390_cc_t cond, HReg dst,
                               s390_opnd_RMI src);
s390_insn *s390_insn_load_immediate(UChar size, HReg dst, ULong val);
s390_insn *s390_insn_alu(UChar size, s390_alu_t, HReg dst,
                         s390_opnd_RMI op2);
s390_insn *s390_insn_mul(UChar size, HReg dst_hi, HReg dst_lo,
                         s390_opnd_RMI op2, Bool signed_multiply);
s390_insn *s390_insn_div(UChar size, HReg op1_hi, HReg op1_lo,
                         s390_opnd_RMI op2, Bool signed_divide);
s390_insn *s390_insn_divs(UChar size, HReg rem, HReg op1, s390_opnd_RMI op2);
s390_insn *s390_insn_clz(UChar size, HReg num_bits, HReg clobber,
                         s390_opnd_RMI op);
s390_insn *s390_insn_cas(UChar size, HReg op1, s390_amode *op2, HReg op3,
                         HReg old);
s390_insn *s390_insn_cdas(UChar size, HReg op1_high, HReg op1_low,
                          s390_amode *op2, HReg op3_high, HReg op3_low,
                          HReg old_high, HReg old_low, HReg scratch);
s390_insn *s390_insn_unop(UChar size, s390_unop_t tag, HReg dst,
                          s390_opnd_RMI opnd);
s390_insn *s390_insn_cc2bool(HReg dst, s390_cc_t src);
s390_insn *s390_insn_test(UChar size, s390_opnd_RMI src);
s390_insn *s390_insn_compare(UChar size, HReg dst, s390_opnd_RMI opnd,
                             Bool signed_comparison);
s390_insn *s390_insn_helper_call(s390_cc_t cond, Addr64 target, UInt num_args,
                                 const HChar *name, RetLoc rloc);
s390_insn *s390_insn_bfp_triop(UChar size, s390_bfp_triop_t, HReg dst,
                               HReg op2, HReg op3);
s390_insn *s390_insn_bfp_binop(UChar size, s390_bfp_binop_t, HReg dst,
                               HReg op2);
s390_insn *s390_insn_bfp_unop(UChar size, s390_bfp_unop_t tag, HReg dst,
                              HReg op);
s390_insn *s390_insn_bfp_compare(UChar size, HReg dst, HReg op1, HReg op2);
s390_insn *s390_insn_bfp_convert(UChar size, s390_bfp_conv_t tag, HReg dst,
                                 HReg op, s390_bfp_round_t);
s390_insn *s390_insn_bfp128_convert(UChar size, s390_bfp_conv_t tag, HReg dst_hi,
                                    HReg dst_lo, HReg op_hi, HReg op_lo,
                                    s390_bfp_round_t rounding_mode);
s390_insn *s390_insn_bfp128_binop(UChar size, s390_bfp_binop_t, HReg dst_hi,
                                  HReg dst_lo, HReg op2_hi, HReg op2_lo);
s390_insn *s390_insn_bfp128_unop(UChar size, s390_bfp_unop_t, HReg dst_hi,
                                 HReg dst_lo, HReg op_hi, HReg op_lo);
s390_insn *s390_insn_bfp128_compare(UChar size, HReg dst, HReg op1_hi,
                                    HReg op1_lo, HReg op2_hi, HReg op2_lo);
s390_insn *s390_insn_bfp128_convert_to(UChar size, s390_bfp_conv_t,
                                       HReg dst_hi, HReg dst_lo, HReg op);
s390_insn *s390_insn_bfp128_convert_from(UChar size, s390_bfp_conv_t,
                                         HReg dst_hi, HReg dst_lo, HReg op_hi,
                                         HReg op_lo, s390_bfp_round_t);
s390_insn *s390_insn_dfp_binop(UChar size, s390_dfp_binop_t, HReg dst,
                               HReg op2, HReg op3,
                               s390_dfp_round_t rounding_mode);
s390_insn *s390_insn_dfp_unop(UChar size, s390_dfp_unop_t, HReg dst, HReg op);
s390_insn *s390_insn_dfp_intop(UChar size, s390_dfp_intop_t, HReg dst,
                               HReg op2, HReg op3);
s390_insn *s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t, HReg dst,
                                 HReg op1, HReg op2);
s390_insn *s390_insn_dfp_convert(UChar size, s390_dfp_conv_t tag, HReg dst,
                                 HReg op, s390_dfp_round_t);
s390_insn *s390_insn_dfp_reround(UChar size, HReg dst, HReg op2, HReg op3,
                                 s390_dfp_round_t);
s390_insn *s390_insn_fp_convert(UChar size, s390_fp_conv_t tag,
                                HReg dst, HReg op, HReg r1, s390_dfp_round_t);
s390_insn *s390_insn_fp128_convert(UChar size, s390_fp_conv_t tag,
                                   HReg dst_hi, HReg dst_lo, HReg op_hi,
                                   HReg op_lo, HReg r1, s390_dfp_round_t);
s390_insn *s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t, HReg dst_hi,
                                  HReg dst_lo, HReg op2_hi, HReg op2_lo,
                                  HReg op3_hi, HReg op3_lo,
                                  s390_dfp_round_t rounding_mode);
s390_insn *s390_insn_dfp128_unop(UChar size, s390_dfp_unop_t, HReg dst,
                                 HReg op_hi, HReg op_lo);
s390_insn *s390_insn_dfp128_intop(UChar size, s390_dfp_intop_t, HReg dst_hi,
                                  HReg dst_lo, HReg op2,
                                  HReg op3_hi, HReg op3_lo);
s390_insn *s390_insn_dfp128_compare(UChar size, s390_dfp_cmp_t, HReg dst,
                                    HReg op1_hi, HReg op1_lo, HReg op2_hi,
                                    HReg op2_lo);
s390_insn *s390_insn_dfp128_convert_to(UChar size, s390_dfp_conv_t,
                                       HReg dst_hi, HReg dst_lo, HReg op);
s390_insn *s390_insn_dfp128_convert_from(UChar size, s390_dfp_conv_t,
                                         HReg dst_hi, HReg dst_lo, HReg op_hi,
                                         HReg op_lo, s390_dfp_round_t);
s390_insn *s390_insn_dfp128_reround(UChar size, HReg dst_hi, HReg dst_lo,
                                    HReg op2, HReg op3_hi, HReg op3_lo,
                                    s390_dfp_round_t);
s390_insn *s390_insn_mfence(void);
s390_insn *s390_insn_mimm(UChar size, s390_amode *dst, ULong value);
s390_insn *s390_insn_madd(UChar size, s390_amode *dst, UChar delta,
                          ULong value);
s390_insn *s390_insn_set_fpc_bfprm(UChar size, HReg mode);
s390_insn *s390_insn_set_fpc_dfprm(UChar size, HReg mode);

/* Five for translation chaining */
s390_insn *s390_insn_xdirect(s390_cc_t cond, Addr64 dst, s390_amode *guest_IA,
                             Bool to_fast_entry);
s390_insn *s390_insn_xindir(s390_cc_t cond, HReg dst, s390_amode *guest_IA);
s390_insn *s390_insn_xassisted(s390_cc_t cond, HReg dst, s390_amode *guest_IA,
                               IRJumpKind kind);
s390_insn *s390_insn_evcheck(s390_amode *counter, s390_amode *fail_addr);
s390_insn *s390_insn_profinc(void);
s390_insn *s390_insn_vec_amodeop(UChar size, s390_vec_amodeop_t, HReg dst,
                                 HReg op1, s390_amode* op2);
s390_insn *s390_insn_vec_amodeintop(UChar size, s390_vec_amodeintop_t, HReg dst,
                                    s390_amode* op2, HReg op3);
s390_insn *s390_insn_vec_binop(UChar size, s390_vec_binop_t, HReg dst, HReg op1,
                               HReg op2);
s390_insn *s390_insn_vec_triop(UChar size, s390_vec_triop_t, HReg dst, HReg op1,
                               HReg op2, HReg op3);
s390_insn *s390_insn_vec_replicate(UChar size, HReg dst, HReg op1, UChar idx);

const HChar *s390_insn_as_string(const s390_insn *);

/*--------------------------------------------------------*/
/* --- Interface exposed to VEX                       --- */
/*--------------------------------------------------------*/

void ppS390AMode(const s390_amode *);
void ppS390Instr(const s390_insn *, Bool mode64);
UInt ppHRegS390(HReg);

/* Some functions that insulate the register allocator from details
   of the underlying instruction set. */
void  getRegUsage_S390Instr( HRegUsage *, const s390_insn *, Bool );
void  mapRegs_S390Instr    ( HRegRemap *, s390_insn *, Bool );
Int   emit_S390Instr       ( Bool *, UChar *, Int, const s390_insn *, Bool,
                             VexEndness, const void *, const void *,
                             const void *, const void *);
const RRegUniverse *getRRegUniverse_S390( void );
void  genSpill_S390        ( HInstr **, HInstr **, HReg , Int , Bool );
void  genReload_S390       ( HInstr **, HInstr **, HReg , Int , Bool );
HInstr* directReload_S390  ( HInstr *, HReg, Short );
extern s390_insn* genMove_S390(HReg from, HReg to, Bool mode64);
HInstrArray *iselSB_S390   ( const IRSB *, VexArch, const VexArchInfo *,
                             const VexAbiInfo *, Int, Int, Bool, Bool, Addr);

/* Return the number of bytes of code needed for an event check */
Int evCheckSzB_S390(void);

/* Perform a chaining and unchaining of an XDirect jump. */
VexInvalRange chainXDirect_S390(VexEndness endness_host,
                                void *place_to_chain,
                                const void *disp_cp_chain_me_EXPECTED,
                                const void *place_to_jump_to);

VexInvalRange unchainXDirect_S390(VexEndness endness_host,
                                  void *place_to_unchain,
                                  const void *place_to_jump_to_EXPECTED,
                                  const void *disp_cp_chain_me);

/* Patch the counter location into an existing ProfInc point. */
VexInvalRange patchProfInc_S390(VexEndness endness_host,
                                void  *code_to_patch,
                                const ULong *location_of_counter);

/* KLUDGE: See detailled comment in host_s390_defs.c. */
extern UInt s390_host_hwcaps;

/* Convenience macros to test installed facilities */
#define s390_host_has_ldisp \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_LDISP))
#define s390_host_has_eimm \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_EIMM))
#define s390_host_has_gie \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_GIE))
#define s390_host_has_dfp \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_DFP))
#define s390_host_has_fgx \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_FGX))
#define s390_host_has_etf2 \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_ETF2))
#define s390_host_has_stfle \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_STFLE))
#define s390_host_has_etf3 \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_ETF3))
#define s390_host_has_stckf \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_STCKF))
#define s390_host_has_fpext \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_FPEXT))
#define s390_host_has_lsc \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_LSC))
#define s390_host_has_pfpo \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_PFPO))
#define s390_host_has_vx \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_VX))
#define s390_host_has_msa5 \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_MSA5))
#define s390_host_has_lsc2 \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_LSC2))
#define s390_host_has_vxe \
                      (s390_host_hwcaps & (VEX_HWCAPS_S390X_VXE))
#endif /* ndef __VEX_HOST_S390_DEFS_H */

/*---------------------------------------------------------------*/
/*--- end                                    host_s390_defs.h ---*/
/*---------------------------------------------------------------*/
