From: Julian Seward Date: Wed, 27 Apr 2011 11:58:22 +0000 (+0000) Subject: s390x: fpr - gpr transfer facility X-Git-Tag: svn/VALGRIND_3_7_0^2~93 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79e15aa55f692e7731545e6f68c98e97774efe7b;p=thirdparty%2Fvalgrind.git s390x: fpr - gpr transfer facility We need to introduce a new hwcap to model the presence of the fpr - gpr transfer facility. If it is not available, we cannot use the LDGR and LGDR insns and need to use a trick similar to what ppc does (write/read stack location). Fixes #268619 (vex side). (Florian Krohm, britzel@acm.org) git-svn-id: svn://svn.valgrind.org/vex/trunk@2131 --- diff --git a/VEX/priv/host_s390_defs.c b/VEX/priv/host_s390_defs.c index 17cc737757..75245164ff 100644 --- a/VEX/priv/host_s390_defs.c +++ b/VEX/priv/host_s390_defs.c @@ -2794,7 +2794,8 @@ s390_emit_LFPC(UChar *p, UChar b2, UShort d2) 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); @@ -2805,7 +2806,8 @@ s390_emit_LDGR(UChar *p, UChar r1, UChar 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); @@ -3875,6 +3877,55 @@ s390_emit_CLFIw(UChar *p, UChar r1, UInt i2) 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) @@ -5051,9 +5102,9 @@ s390_insn_move_emit(UChar *buf, const s390_insn *insn) 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. */ diff --git a/VEX/priv/host_s390_defs.h b/VEX/priv/host_s390_defs.h index e409bd5b37..0f3cc91e50 100644 --- a/VEX/priv/host_s390_defs.h +++ b/VEX/priv/host_s390_defs.h @@ -491,6 +491,8 @@ extern const VexArchInfo *s390_archinfo_host; (s390_archinfo_host->hwcaps & (VEX_HWCAPS_S390X_GIE)) #define s390_host_has_dfp \ (s390_archinfo_host->hwcaps & (VEX_HWCAPS_S390X_DFP)) +#define s390_host_has_fgx \ + (s390_archinfo_host->hwcaps & (VEX_HWCAPS_S390X_FGX)) #endif /* ndef __VEX_HOST_S390_DEFS_H */ diff --git a/VEX/priv/main_main.c b/VEX/priv/main_main.c index 12dcbfd60f..9d939017cd 100644 --- a/VEX/priv/main_main.c +++ b/VEX/priv/main_main.c @@ -933,23 +933,38 @@ static HChar* show_hwcaps_arm ( UInt hwcaps ) 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; } /* ---- */ diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 0ca5ef1cac..1e2b386683 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -104,7 +104,8 @@ typedef [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. @@ -121,16 +122,18 @@ typedef #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)