static UChar *
s390_emit_LDGR(UChar *p, UChar r1, UChar r2)
{
- /* fixs390: PR 268619 */
+ vassert(s390_host_has_fgx);
+
if (unlikely(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, FPR, GPR), "ldgr", r1, r2);
static UChar *
s390_emit_LGDR(UChar *p, UChar r1, UChar r2)
{
- /* fixs390: PR 268619 */
+ vassert(s390_host_has_fgx);
+
if (unlikely(vex_traceflags & VEX_TRACE_ASM))
s390_disasm(ENC3(MNM, GPR, FPR), "lgdr", r1, r2);
return s390_emit_CLR(p, r1, R0);
}
+
+static UChar *
+s390_emit_LGDRw(UChar *p, UChar r1, UChar r2)
+{
+ if (s390_host_has_fgx) {
+ return s390_emit_LGDR(p, r1, r2);
+ }
+
+ /* Store the FPR at memory[sp - 8]. This is safe because SP grows towards
+ smaller addresses and is 8-byte aligned. Then load the GPR from that
+ memory location/ */
+ if (s390_host_has_ldisp) {
+ p = s390_emit_STDY(p, r2, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
+ return s390_emit_LG(p, r1, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
+ }
+
+ /* No long displacement. Need to adjust SP explicitly as to avoid negative
+ displacements. */
+ p = s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, -8);
+ p = s390_emit_STD(p, r2, R0, S390_REGNO_STACK_POINTER, 0);
+ p = s390_emit_LG(p, r1, R0, S390_REGNO_STACK_POINTER, DISP20(0));
+ return s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, 8);
+}
+
+
+static UChar *
+s390_emit_LDGRw(UChar *p, UChar r1, UChar r2)
+{
+ if (s390_host_has_fgx) {
+ return s390_emit_LDGR(p, r1, r2);
+ }
+
+ /* Store the GPR at memory[sp - 8]. This is safe because SP grows towards
+ smaller addresses and is 8-byte aligned. Then load the FPR from that
+ memory location/ */
+ if (s390_host_has_ldisp) {
+ p = s390_emit_STG(p, r2, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
+ return s390_emit_LDY(p, r1, R0, S390_REGNO_STACK_POINTER, DISP20(-8));
+ }
+
+ /* No long displacement. Need to adjust SP explicitly as to avoid negative
+ displacements. */
+ p = s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, -8);
+ p = s390_emit_STG(p, r2, R0, S390_REGNO_STACK_POINTER, DISP20(0));
+ p = s390_emit_LD(p, r1, R0, S390_REGNO_STACK_POINTER, 0);
+ return s390_emit_AGHI(p, S390_REGNO_STACK_POINTER, 8);
+}
+
+
/* Split up a 20-bit displacement into its high and low piece
suitable for passing as function arguments */
#define DISP20(d) ((d) & 0xFFF), (((d) >> 12) & 0xFF)
return s390_emit_LDR(buf, dst, src);
} else {
if (dst_class == HRcFlt64 && src_class == HRcInt64)
- return s390_emit_LDGR(buf, dst, src); /* fixs390: PR 268619 */
+ return s390_emit_LDGRw(buf, dst, src);
if (dst_class == HRcInt64 && src_class == HRcFlt64)
- return s390_emit_LGDR(buf, dst, src); /* fixs390: PR 268619 */
+ return s390_emit_LGDRw(buf, dst, src);
/* A move between floating point registers and general purpose
registers of different size should never occur and indicates
an error elsewhere. */
static HChar* show_hwcaps_s390x ( UInt hwcaps )
{
- const UInt LD = VEX_HWCAPS_S390X_LDISP;
- const UInt EI = VEX_HWCAPS_S390X_EIMM;
- const UInt GE = VEX_HWCAPS_S390X_GIE;
- const UInt DF = VEX_HWCAPS_S390X_DFP;
+ static const HChar prefix[] = "s390x";
+ static const HChar facilities[][6] = {
+ { "ldisp" },
+ { "eimm" },
+ { "gie" },
+ { "dfp" },
+ { "fgx" },
+ };
+ static HChar buf[sizeof facilities + sizeof prefix + 1];
+ static HChar *p;
+
+ if (buf[0] != '\0') return buf; /* already constructed */
hwcaps = VEX_HWCAPS_S390X(hwcaps);
- if (hwcaps == (LD)) return "s390x-ldisp";
- if (hwcaps == (LD|EI)) return "s390x-ldisp-eimm";
- if (hwcaps == (LD|GE)) return "s390x-ldisp-gie";
- if (hwcaps == (LD|DF)) return "s390x-ldisp-dfp";
- if (hwcaps == (LD|EI|GE)) return "s390x-ldisp-eimm-gie";
- if (hwcaps == (LD|EI|DF)) return "s390x-ldisp-eimm-dfp";
- if (hwcaps == (LD|GE|DF)) return "s390x-ldisp-gie-dfp";
- if (hwcaps == (LD|EI|GE|DF)) return "s390x-ldisp-eimm-gie-dfp";
-
- return "s390-zarch";
+ p = buf + vex_sprintf(buf, "%s", prefix);
+ if (hwcaps & VEX_HWCAPS_S390X_LDISP)
+ p = p + vex_sprintf(p, "-%s", facilities[0]);
+ if (hwcaps & VEX_HWCAPS_S390X_EIMM)
+ p = p + vex_sprintf(p, "-%s", facilities[1]);
+ if (hwcaps & VEX_HWCAPS_S390X_GIE)
+ p = p + vex_sprintf(p, "-%s", facilities[2]);
+ if (hwcaps & VEX_HWCAPS_S390X_DFP)
+ p = p + vex_sprintf(p, "-%s", facilities[3]);
+ if (hwcaps & VEX_HWCAPS_S390X_FGX)
+ p = p + vex_sprintf(p, "-%s", facilities[4]);
+
+ /* If there are no facilities, add "zarch" */
+ if (hwcaps == 0)
+ vex_sprintf(p, "-%s", "zarch");
+
+ return buf;
}
/* ---- */
[24] Extended-immediate facility
[23] General-instruction-extension facility
[22] Decimal floating point facility
- [0:21] Currently unused; reserved for future use
+ [21] FPR-GR transfer facility
+ [0:20] Currently unused; reserved for future use
*/
/* Model numbers must be assigned in chronological order.
#define VEX_S390X_MODEL_INVALID 9
#define VEX_S390X_MODEL_MASK 0x3F
-#define VEX_HWCAPS_S390X_LDISP (1<<6) /* Long-displacement facility */
-#define VEX_HWCAPS_S390X_EIMM (1<<7) /* Extended-immediate facility */
-#define VEX_HWCAPS_S390X_GIE (1<<8) /* General-instruction-extension facility */
-#define VEX_HWCAPS_S390X_DFP (1<<9) /* Decimal floating point facility */
+#define VEX_HWCAPS_S390X_LDISP (1<<6) /* Long-displacement facility */
+#define VEX_HWCAPS_S390X_EIMM (1<<7) /* Extended-immediate facility */
+#define VEX_HWCAPS_S390X_GIE (1<<8) /* General-instruction-extension facility */
+#define VEX_HWCAPS_S390X_DFP (1<<9) /* Decimal floating point facility */
+#define VEX_HWCAPS_S390X_FGX (1<<10) /* FPR-GR transfer facility */
/* Special value representing all available s390x hwcaps */
#define VEX_HWCAPS_S390X_ALL (VEX_HWCAPS_S390X_LDISP | \
VEX_HWCAPS_S390X_EIMM | \
VEX_HWCAPS_S390X_GIE | \
- VEX_HWCAPS_S390X_DFP)
+ VEX_HWCAPS_S390X_DFP | \
+ VEX_HWCAPS_S390X_FGX)
#define VEX_HWCAPS_S390X(x) ((x) & ~VEX_S390X_MODEL_MASK)
#define VEX_S390X_MODEL(x) ((x) & VEX_S390X_MODEL_MASK)