case S390_VEC_PWSUM_DW: op = "v-vpwsumdw"; break;
case S390_VEC_PWSUM_QW: op = "v-vpwsumqw"; break;
case S390_VEC_INIT_FROM_GPRS: op = "v-vinitfromgprs"; break;
+ case S390_VEC_INIT_FROM_FPRS: op = "v-vinitfromfprs"; break;
case S390_VEC_FLOAT_ADD: op = "v-vfloatadd"; break;
case S390_VEC_FLOAT_SUB: op = "v-vfloatsub"; break;
case S390_VEC_FLOAT_MUL: op = "v-vfloatmul"; break;
return s390_emit_LGDRw(buf, dst, src);
}
}
+ if (dst_class == HRcFlt64 && src_class == HRcVec128) {
+ return s390_emit_VLR(buf, dst, src);
+ }
/* A move between floating point registers and general purpose
registers of different size should never occur and indicates
an error elsewhere. */
return s390_emit_VSUMQ(buf, v1, v2, v3, s390_getM_from_size(size));
case S390_VEC_INIT_FROM_GPRS:
return s390_emit_VLVGP(buf, v1, v2, v3);
+ case S390_VEC_INIT_FROM_FPRS:
+ return s390_emit_VMRH(buf, v1, v2, v3, 3);
case S390_VEC_FLOAT_ADD:
return s390_emit_VFA(buf, v1, v2, v3, s390_getM_from_size(size), 0);
case S390_VEC_FLOAT_SUB:
s390_insn_vec_triop_emit(UChar *buf, const s390_insn *insn)
{
s390_vec_triop_t tag = insn->variant.vec_triop.tag;
+ UChar size = insn->size;
UChar v1 = hregNumber(insn->variant.vec_triop.dst);
UChar v2 = hregNumber(insn->variant.vec_triop.op1);
UChar v3 = hregNumber(insn->variant.vec_triop.op2);
switch (tag) {
case S390_VEC_PERM: {
- vassert(insn->size == 16);
+ vassert(size == 16);
return s390_emit_VPERM(buf, v1, v2, v3, v4);
}
case S390_VEC_FLOAT_MADD:
- return s390_emit_VFMA(buf, v1, v2, v3, v4, 0, 3);
+ return s390_emit_VFMA(buf, v1, v2, v3, v4, 0,
+ s390_getM_from_size(size));
case S390_VEC_FLOAT_MSUB:
- return s390_emit_VFMS(buf, v1, v2, v3, v4, 0, 3);
+ return s390_emit_VFMS(buf, v1, v2, v3, v4, 0,
+ s390_getM_from_size(size));
default:
goto fail;
}
vpanic("Iex_Get with F128 data");
/* --------- 4-ary OP --------- */
- case Iex_Qop:
- vpanic("Iex_Qop with F128 data");
+ case Iex_Qop: {
+ IRQop *qop = expr->Iex.Qop.details;
+ s390_vec_triop_t vecop;
+ HReg op1_hi, op1_lo, op2_hi, op2_lo, op3_hi, op3_lo;
+ HReg dst, dstv_lo, op1, op2, op3;
+
+ s390_isel_float128_expr(&op1_hi, &op1_lo, env, qop->arg2);
+ s390_isel_float128_expr(&op2_hi, &op2_lo, env, qop->arg3);
+ s390_isel_float128_expr(&op3_hi, &op3_lo, env, qop->arg4);
+
+ /* Cannot carry out with FPRs; move operands to VRs instead. */
+ op1 = newVRegV(env);
+ op2 = newVRegV(env);
+ op3 = newVRegV(env);
+ dst = newVRegV(env);
+ dstv_lo = newVRegV(env);
+ addInstr(env, s390_insn_vec_binop(8, S390_VEC_INIT_FROM_FPRS,
+ op1, op1_hi, op1_lo));
+ addInstr(env, s390_insn_vec_binop(8, S390_VEC_INIT_FROM_FPRS,
+ op2, op2_hi, op2_lo));
+ addInstr(env, s390_insn_vec_binop(8, S390_VEC_INIT_FROM_FPRS,
+ op3, op3_hi, op3_lo));
+
+ switch (qop->op) {
+ case Iop_MAddF128: vecop = S390_VEC_FLOAT_MADD; break;
+ case Iop_MSubF128: vecop = S390_VEC_FLOAT_MSUB; break;
+ default:
+ goto irreducible;
+ }
+
+ set_bfp_rounding_mode_in_fpc(env, qop->arg1);
+ addInstr(env, s390_insn_vec_triop(16, vecop, dst, op1, op2, op3));
+ addInstr(env, s390_insn_vec_binop(8, S390_VEC_MERGEL, dstv_lo, dst, dst));
+
+ /* Move result to destination FPRs. */
+ *dst_hi = newVRegF(env);
+ *dst_lo = newVRegF(env);
+ addInstr(env, s390_insn_move(8, *dst_hi, dst));
+ addInstr(env, s390_insn_move(8, *dst_lo, dstv_lo));
+ return;
+ }
/* --------- TERNARY OP --------- */
case Iex_Triop: {
}
}
+ case Iex_Qop: {
+ }
+
/* --------- MULTIPLEX --------- */
case Iex_ITE: {
IRExpr *cond_expr = expr->Iex.ITE.cond;