]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
s390: Add support for DFP "shift significant" insns.
authorFlorian Krohm <florian@eich-krohm.de>
Tue, 1 Jan 2013 22:19:24 +0000 (22:19 +0000)
committerFlorian Krohm <florian@eich-krohm.de>
Tue, 1 Jan 2013 22:19:24 +0000 (22:19 +0000)
Based on patch by Maran Pakkirisamy (maranp@linux.vnet.ibm.com).
Part of fixing BZ 307113.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2626

VEX/priv/guest_s390_toIR.c
VEX/priv/host_s390_defs.c
VEX/priv/host_s390_defs.h
VEX/priv/host_s390_isel.c

index 5e086587a2c19a39024295b24825a73a6a87ad81..750250b935dad08d9e833b5d5ce9f855b917ebdb 100644 (file)
@@ -9573,6 +9573,62 @@ s390_irgen_SXTRA(UChar r3, UChar m4, UChar r1, UChar r2)
    return (m4 == 0) ? "sxtr" : "sxtra";
 }
 
+static const HChar *
+s390_irgen_SLDT(UChar r3, IRTemp op2addr, UChar r1)
+{
+   IRTemp op = newTemp(Ity_D64);
+
+   vassert(s390_host_has_dfp);
+
+   assign(op, get_dpr_dw0(r3));
+   put_dpr_dw0(r1, binop(Iop_ShlD64, mkexpr(op), unop(Iop_64to8,
+               binop(Iop_And64, mkexpr(op2addr), mkU64(63)))));
+
+   return "sldt";
+}
+
+static const HChar *
+s390_irgen_SLXT(UChar r3, IRTemp op2addr, UChar r1)
+{
+   IRTemp op = newTemp(Ity_D128);
+
+   vassert(s390_host_has_dfp);
+
+   assign(op, get_dpr_pair(r3));
+   put_dpr_pair(r1, binop(Iop_ShlD128, mkexpr(op), unop(Iop_64to8,
+                binop(Iop_And64, mkexpr(op2addr), mkU64(63)))));
+
+   return "slxt";
+}
+
+static const HChar *
+s390_irgen_SRDT(UChar r3, IRTemp op2addr, UChar r1)
+{
+   IRTemp op = newTemp(Ity_D64);
+
+   vassert(s390_host_has_dfp);
+
+   assign(op, get_dpr_dw0(r3));
+   put_dpr_dw0(r1, binop(Iop_ShrD64, mkexpr(op), unop(Iop_64to8,
+               binop(Iop_And64, mkexpr(op2addr), mkU64(63)))));
+
+   return "srdt";
+}
+
+static const HChar *
+s390_irgen_SRXT(UChar r3, IRTemp op2addr, UChar r1)
+{
+   IRTemp op = newTemp(Ity_D128);
+
+   vassert(s390_host_has_dfp);
+
+   assign(op, get_dpr_pair(r3));
+   put_dpr_pair(r1, binop(Iop_ShrD128, mkexpr(op), unop(Iop_64to8,
+                binop(Iop_And64, mkexpr(op2addr), mkU64(63)))));
+
+   return "srxt";
+}
+
 static const HChar *
 s390_irgen_TDCET(UChar r1, IRTemp op2addr)
 {
@@ -15103,10 +15159,22 @@ s390_decode_6byte_and_irgen(UChar *bytes)
    case 0xed000000003dULL: /* MYH */ goto unimplemented;
    case 0xed000000003eULL: /* MAD */ goto unimplemented;
    case 0xed000000003fULL: /* MSD */ goto unimplemented;
-   case 0xed0000000040ULL: /* SLDT */ goto unimplemented;
-   case 0xed0000000041ULL: /* SRDT */ goto unimplemented;
-   case 0xed0000000048ULL: /* SLXT */ goto unimplemented;
-   case 0xed0000000049ULL: /* SRXT */ goto unimplemented;
+   case 0xed0000000040ULL: s390_format_RXF_FRRDF(s390_irgen_SLDT,
+                                                 ovl.fmt.RXF.r3, ovl.fmt.RXF.x2,
+                                                 ovl.fmt.RXF.b2, ovl.fmt.RXF.d2,
+                                                 ovl.fmt.RXF.r1);  goto ok;
+   case 0xed0000000041ULL: s390_format_RXF_FRRDF(s390_irgen_SRDT,
+                                                 ovl.fmt.RXF.r3, ovl.fmt.RXF.x2,
+                                                 ovl.fmt.RXF.b2, ovl.fmt.RXF.d2,
+                                                 ovl.fmt.RXF.r1);  goto ok;
+   case 0xed0000000048ULL: s390_format_RXF_FRRDF(s390_irgen_SLXT,
+                                                 ovl.fmt.RXF.r3, ovl.fmt.RXF.x2,
+                                                 ovl.fmt.RXF.b2, ovl.fmt.RXF.d2,
+                                                 ovl.fmt.RXF.r1);  goto ok;
+   case 0xed0000000049ULL: s390_format_RXF_FRRDF(s390_irgen_SRXT,
+                                                 ovl.fmt.RXF.r3, ovl.fmt.RXF.x2,
+                                                 ovl.fmt.RXF.b2, ovl.fmt.RXF.d2,
+                                                 ovl.fmt.RXF.r1);  goto ok;
    case 0xed0000000050ULL: s390_format_RXE_FRRD(s390_irgen_TDCET, ovl.fmt.RXE.r1,
                                                 ovl.fmt.RXE.x2, ovl.fmt.RXE.b2,
                                                 ovl.fmt.RXE.d2);  goto ok;
index 46453768368eef64a95529c8f19a09e192704ad1..6ba22d0ce2eabb668378ed20809c90a24b67c0e3 100644 (file)
@@ -731,6 +731,16 @@ s390_insn_get_reg_usage(HRegUsage *u, const s390_insn *insn)
       }
       break;
 
+   case S390_INSN_DFP_INTOP:
+      addHRegUse(u, HRmWrite, insn->variant.dfp_intop.dst_hi);
+      addHRegUse(u, HRmRead,  insn->variant.dfp_intop.op2);
+      addHRegUse(u, HRmRead,  insn->variant.dfp_intop.op3_hi);
+      if (insn->size == 16) {
+         addHRegUse(u, HRmWrite, insn->variant.dfp_intop.dst_lo);
+         addHRegUse(u, HRmRead,  insn->variant.dfp_intop.op3_lo);
+      }
+      break;
+
    case S390_INSN_DFP_COMPARE:
       addHRegUse(u, HRmWrite, insn->variant.dfp_compare.dst);
       addHRegUse(u, HRmRead,  insn->variant.dfp_compare.op1_hi);  /* left */
@@ -1020,6 +1030,21 @@ s390_insn_map_regs(HRegRemap *m, s390_insn *insn)
       }
       break;
 
+   case S390_INSN_DFP_INTOP:
+      insn->variant.dfp_intop.dst_hi =
+         lookupHRegRemap(m, insn->variant.dfp_intop.dst_hi);
+      insn->variant.dfp_intop.op2    =
+         lookupHRegRemap(m, insn->variant.dfp_intop.op2);
+      insn->variant.dfp_intop.op3_hi =
+         lookupHRegRemap(m, insn->variant.dfp_intop.op3_hi);
+      if (insn->size == 16) {
+         insn->variant.dfp_intop.dst_lo =
+            lookupHRegRemap(m, insn->variant.dfp_intop.dst_lo);
+         insn->variant.dfp_intop.op3_lo =
+            lookupHRegRemap(m, insn->variant.dfp_intop.op3_lo);
+      }
+      break;
+
    case S390_INSN_DFP_COMPARE:
       insn->variant.dfp_compare.dst =
          lookupHRegRemap(m, insn->variant.dfp_compare.dst);
@@ -1304,6 +1329,21 @@ emit_RX(UChar *p, UInt op, UChar r1, UChar x2, UChar b2, UShort d2)
 }
 
 
+static UChar *
+emit_RXF(UChar *p, ULong op, UChar r3, UChar x2, UChar b2, UShort d2, UChar r1)
+{
+   ULong the_insn = op;
+
+   the_insn |= ((ULong)r3) << 36;
+   the_insn |= ((ULong)x2) << 32;
+   the_insn |= ((ULong)b2) << 28;
+   the_insn |= ((ULong)d2) << 16;
+   the_insn |= ((ULong)r1) << 12;
+
+   return emit_6bytes(p, the_insn);
+}
+
+
 static UChar *
 emit_RXY(UChar *p, ULong op, UChar r1, UChar x2, UChar b2, UShort dl2, UChar dh2)
 {
@@ -4286,6 +4326,54 @@ s390_emit_SXTRA(UChar *p, UChar r3, UChar m4, UChar r1, UChar r2)
 }
 
 
+static UChar *
+s390_emit_SLDT(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "sldt", r1, r3, 0, 0, r2);
+   }
+
+   return emit_RXF(p, 0xED0000000040, r3, 0, r2, 0, r1);
+}
+
+
+static UChar *
+s390_emit_SLXT(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "slxt", r1, r3, 0, 0, r2);
+   }
+
+   return emit_RXF(p, 0xED0000000048, r3, 0, r2, 0, r1);
+}
+
+
+static UChar *
+s390_emit_SRDT(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "srdt", r1, r3, 0, 0, r2);
+   }
+
+   return emit_RXF(p, 0xED0000000041, r3, 0, r2, 0, r1);
+}
+
+
+static UChar *
+s390_emit_SRXT(UChar *p, UChar r3, UChar r1, UChar r2)
+{
+   vassert(s390_host_has_dfp);
+   if (UNLIKELY(vex_traceflags & VEX_TRACE_ASM)) {
+      s390_disasm(ENC4(MNM, FPR, FPR, UDXB), "srxt", r1, r3, 0, 0, r2);
+   }
+
+   return emit_RXF(p, 0xED0000000049, r3, 0, r2, 0, r1);
+}
+
+
 static UChar *
 s390_emit_LOCGR(UChar *p, UChar m3, UChar r1, UChar r2)
 {
@@ -5438,6 +5526,27 @@ s390_insn_dfp_unop(UChar size, s390_dfp_unop_t tag, HReg dst, HReg op)
 }
 
 
+s390_insn *
+s390_insn_dfp_intop(UChar size, s390_dfp_intop_t tag, HReg dst, HReg op2,
+                    HReg op3)
+{
+   s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+   vassert(size == 8);
+
+   insn->tag  = S390_INSN_DFP_INTOP;
+   insn->size = size;
+   insn->variant.dfp_intop.tag = tag;
+   insn->variant.dfp_intop.dst_hi = dst;
+   insn->variant.dfp_intop.op2    = op2;
+   insn->variant.dfp_intop.op3_hi = op3;
+   insn->variant.dfp_intop.dst_lo = INVALID_HREG;
+   insn->variant.dfp_intop.op3_lo = INVALID_HREG;
+
+   return insn;
+}
+
+
 s390_insn *
 s390_insn_dfp_compare(UChar size, s390_dfp_cmp_t tag, HReg dst,
                       HReg op1, HReg op2)
@@ -5532,6 +5641,29 @@ s390_insn_dfp128_unop(UChar size, s390_dfp_unop_t tag, HReg dst,
 }
 
 
+s390_insn *
+s390_insn_dfp128_intop(UChar size, s390_dfp_intop_t tag, HReg dst_hi,
+                       HReg dst_lo, HReg op2, HReg op3_hi, HReg op3_lo)
+{
+   s390_insn *insn = LibVEX_Alloc(sizeof(s390_insn));
+
+   vassert(size == 16);
+   vassert(is_valid_fp128_regpair(dst_hi, dst_lo));
+   vassert(is_valid_fp128_regpair(op3_hi, op3_lo));
+
+   insn->tag  = S390_INSN_DFP_INTOP;
+   insn->size = size;
+   insn->variant.dfp_intop.tag = tag;
+   insn->variant.dfp_intop.dst_hi = dst_hi;
+   insn->variant.dfp_intop.dst_lo = dst_lo;
+   insn->variant.dfp_intop.op2    = op2;
+   insn->variant.dfp_intop.op3_hi = op3_hi;
+   insn->variant.dfp_intop.op3_lo = op3_lo;
+
+   return insn;
+}
+
+
 s390_insn *
 s390_insn_dfp128_compare(UChar size, s390_dfp_cmp_t tag, HReg dst, HReg op1_hi,
                          HReg op1_lo, HReg op2_hi, HReg op2_lo)
@@ -6207,6 +6339,17 @@ s390_insn_as_string(const s390_insn *insn)
                    insn->variant.dfp_unop.op_hi);
       break;
 
+   case S390_INSN_DFP_INTOP:
+      switch (insn->variant.dfp_intop.tag) {
+      case S390_DFP_SHIFT_LEFT:  op = "v-dshl"; break;
+      case S390_DFP_SHIFT_RIGHT: op = "v-dshr"; break;
+      default: goto fail;
+      }
+      s390_sprintf(buf, "%M %R,%R,%R", op, insn->variant.dfp_intop.dst_hi,
+                   insn->variant.dfp_intop.op2,
+                   insn->variant.dfp_intop.op3_hi);
+      break;
+
    case S390_INSN_DFP_COMPARE:
       switch (insn->variant.dfp_compare.tag) {
       case S390_DFP_COMPARE:     op = "v-dcmp"; break;
@@ -8412,6 +8555,38 @@ s390_insn_dfp_unop_emit(UChar *buf, const s390_insn *insn)
 }
 
 
+static UChar *
+s390_insn_dfp_intop_emit(UChar *buf, const s390_insn *insn)
+{
+   UInt r1 = hregNumber(insn->variant.dfp_intop.dst_hi);
+   UInt r2 = hregNumber(insn->variant.dfp_intop.op2);
+   UInt r3 = hregNumber(insn->variant.dfp_intop.op3_hi);
+
+   switch (insn->size) {
+   case 8:
+      switch (insn->variant.dfp_intop.tag) {
+      case S390_DFP_SHIFT_LEFT:  return s390_emit_SLDT(buf, r3, r1, r2);
+      case S390_DFP_SHIFT_RIGHT: return s390_emit_SRDT(buf, r3, r1, r2);
+      default:  goto fail;
+      }
+      break;
+
+   case 16:
+      switch (insn->variant.dfp_intop.tag) {
+      case S390_DFP_SHIFT_LEFT:  return s390_emit_SLXT(buf, r3, r1, r2);
+      case S390_DFP_SHIFT_RIGHT: return s390_emit_SRXT(buf, r3, r1, r2);
+      default:  goto fail;
+      }
+      break;
+
+   default: goto fail;
+   }
+
+ fail:
+   vpanic("s390_insn_dfp_intop_emit");
+}
+
+
 static UChar *
 s390_insn_dfp_compare_emit(UChar *buf, const s390_insn *insn)
 {
@@ -9112,6 +9287,10 @@ emit_S390Instr(Bool *is_profinc, UChar *buf, Int nbuf, s390_insn *insn,
       end = s390_insn_dfp_unop_emit(buf, insn);
       break;
 
+   case S390_INSN_DFP_INTOP:
+      end = s390_insn_dfp_intop_emit(buf, insn);
+      break;
+
    case S390_INSN_DFP_COMPARE:
       end = s390_insn_dfp_compare_emit(buf, insn);
       break;
index 4e7fcca2e8dde97c03ddcc0f18224a781dc1c4e7..ba64bd15d3cbb68ac9f39b6dab74890bd0812527 100644 (file)
@@ -142,6 +142,7 @@ typedef enum {
    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_MFENCE,
@@ -261,6 +262,12 @@ typedef enum {
    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_intop_t;
+
 /* The kind of DFP compare operations */
 typedef enum {
    S390_DFP_COMPARE,
@@ -457,6 +464,14 @@ typedef struct {
          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;
@@ -583,6 +598,8 @@ 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,
@@ -593,6 +610,9 @@ s390_insn *s390_insn_dfp128_binop(UChar size, s390_dfp_binop_t, HReg dst_hi,
                                   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);
index bb5aef29b2c3036316aafb27c9e09f1b00222f1d..e5851195b62201c8f8a78dd9bfe25d2d83655693 100644 (file)
@@ -2443,12 +2443,50 @@ s390_isel_dfp128_expr_wrk(HReg *dst_hi, HReg *dst_lo, ISelEnv *env,
 
       /* --------- BINARY OP --------- */
    case Iex_Binop: {
+
       switch (expr->Iex.Binop.op) {
       case Iop_D64HLtoD128:
          *dst_hi = s390_isel_dfp_expr(env, expr->Iex.Binop.arg1);
          *dst_lo = s390_isel_dfp_expr(env, expr->Iex.Binop.arg2);
          return;
 
+      case Iop_ShlD128:
+      case Iop_ShrD128: {
+         HReg op1_hi, op1_lo, op2, f9, f11, f13, f15;
+         s390_dfp_intop_t intop;
+         IRExpr *left   = expr->Iex.Binop.arg1;
+         IRExpr *right  = expr->Iex.Binop.arg2;
+
+         switch (expr->Iex.Binop.op) {
+         case Iop_ShlD128: intop = S390_DFP_SHIFT_LEFT;  break;
+         case Iop_ShrD128: intop = S390_DFP_SHIFT_RIGHT; break;
+         default: goto irreducible;
+         }
+
+         /* We use non-virtual registers as pairs (f9, f11) and (f13, f15)) */
+         f9  = make_fpr(9); /* 128 bit dfp operand */
+         f11 = make_fpr(11);
+
+         f13 = make_fpr(13); /* 128 bit dfp destination */
+         f15 = make_fpr(15);
+
+         s390_isel_dfp128_expr(&op1_hi, &op1_lo, env, left);  /* dfp operand */
+         addInstr(env, s390_insn_move(8, f9,  op1_hi));
+         addInstr(env, s390_insn_move(8, f11, op1_lo));
+
+         op2 = s390_isel_int_expr(env, right);  /* int operand */
+
+         addInstr(env,
+                  s390_insn_dfp128_intop(16, intop, f13, f15, op2, f9, f11));
+
+         /* Move result to virtual destination register */
+         *dst_hi = newVRegF(env);
+         *dst_lo = newVRegF(env);
+         addInstr(env, s390_insn_move(8, *dst_hi, f13));
+         addInstr(env, s390_insn_move(8, *dst_lo, f15));
+         return;
+      }
+
       default:
          goto irreducible;
       }
@@ -2587,8 +2625,6 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
                                                 rounding_mode));
             return dst;
          }
-      default:
-         goto irreducible;
 
       case Iop_D128toD64: {
          HReg op_hi, op_lo, f13, f15;
@@ -2620,6 +2656,30 @@ s390_isel_dfp_expr_wrk(ISelEnv *env, IRExpr *expr)
          return dst;
       }
 
+      case Iop_ShlD64:
+      case Iop_ShrD64: {
+         HReg op2;
+         HReg op3;
+         s390_dfp_intop_t intop;
+         IRExpr *op1   = expr->Iex.Binop.arg1;
+         IRExpr *shift = expr->Iex.Binop.arg2;
+
+         switch (expr->Iex.Binop.op) {
+         case Iop_ShlD64: intop = S390_DFP_SHIFT_LEFT;  break;
+         case Iop_ShrD64: intop = S390_DFP_SHIFT_RIGHT; break;
+         default: goto irreducible;
+         }
+
+         op2 = s390_isel_int_expr(env, shift);
+         op3 = s390_isel_dfp_expr(env, op1);
+         dst = newVRegF(env);
+
+         addInstr(env, s390_insn_dfp_intop(size, intop, dst, op2, op3));
+         return dst;
+      }
+
+      default:
+         goto irreducible;
       }
    }