Today this is what happens when we encounter hwcaps we cannot handle:
vex: priv/main_main.c:329 (LibVEX_Translate): Assertion
`are_valid_hwcaps(VexArchAMD64, vta->archinfo_host.hwcaps)' failed.
Running with -d offers this much enlightenment:
--7732:1:main ... arch = AMD64, hwcaps = INVALID
Not a good base for a bug report...
With this change, the user experience will be smoewhat better, e.g.:
VEX: Support for AVX2 requires AVX capabilities
Found: amd64-cx16-rdtscp-sse3-avx2
Cannot continue. Good-bye
Specifically, the patch decouples showing hwcaps and deciding their validity.
show_hwcaps_<ARCH> reports the hwcaps it finds. It never returns NULL.
check_hwcaps checks the hwcaps for feasibility and does not return in case
VEX cannot deal with them.
The function are_valid_hwcaps no longer exists.
git-svn-id: svn://svn.valgrind.org/vex/trunk@3038 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/main_main.c b/priv/main_main.c
index 8f33725..58748a7 100644
--- a/priv/main_main.c
+++ b/priv/main_main.c
@@ -1,3 +1,4 @@
+/* -*- mode: C; c-basic-offset: 3; -*- */
/*---------------------------------------------------------------*/
/*--- Begin main_main.c ---*/
@@ -74,7 +75,7 @@
/* --------- fwds ... --------- */
-static Bool are_valid_hwcaps ( VexArch arch, UInt hwcaps );
+static void check_hwcaps ( VexArch arch, UInt hwcaps );
static const HChar* show_hwcaps ( VexArch arch, UInt hwcaps );
@@ -308,7 +309,6 @@
iselSB = iselSB_X86;
emit = (__typeof__(emit)) emit_X86Instr;
host_word_type = Ity_I32;
- vassert(are_valid_hwcaps(VexArchX86, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessLE);
break;
@@ -326,7 +326,6 @@
iselSB = iselSB_AMD64;
emit = (__typeof__(emit)) emit_AMD64Instr;
host_word_type = Ity_I64;
- vassert(are_valid_hwcaps(VexArchAMD64, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessLE);
break;
@@ -344,7 +343,6 @@
iselSB = iselSB_PPC;
emit = (__typeof__(emit)) emit_PPCInstr;
host_word_type = Ity_I32;
- vassert(are_valid_hwcaps(VexArchPPC32, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessBE);
break;
@@ -362,7 +360,6 @@
iselSB = iselSB_PPC;
emit = (__typeof__(emit)) emit_PPCInstr;
host_word_type = Ity_I64;
- vassert(are_valid_hwcaps(VexArchPPC64, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessBE ||
vta->archinfo_host.endness == VexEndnessLE );
break;
@@ -384,7 +381,6 @@
iselSB = iselSB_S390;
emit = (__typeof__(emit)) emit_S390Instr;
host_word_type = Ity_I64;
- vassert(are_valid_hwcaps(VexArchS390X, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessBE);
break;
@@ -402,7 +398,6 @@
iselSB = iselSB_ARM;
emit = (__typeof__(emit)) emit_ARMInstr;
host_word_type = Ity_I32;
- vassert(are_valid_hwcaps(VexArchARM, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessLE);
break;
@@ -420,7 +415,6 @@
iselSB = iselSB_ARM64;
emit = (__typeof__(emit)) emit_ARM64Instr;
host_word_type = Ity_I64;
- vassert(are_valid_hwcaps(VexArchARM64, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessLE);
break;
@@ -438,7 +432,6 @@
iselSB = iselSB_MIPS;
emit = (__typeof__(emit)) emit_MIPSInstr;
host_word_type = Ity_I32;
- vassert(are_valid_hwcaps(VexArchMIPS32, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessLE
|| vta->archinfo_host.endness == VexEndnessBE);
break;
@@ -457,7 +450,6 @@
iselSB = iselSB_MIPS;
emit = (__typeof__(emit)) emit_MIPSInstr;
host_word_type = Ity_I64;
- vassert(are_valid_hwcaps(VexArchMIPS64, vta->archinfo_host.hwcaps));
vassert(vta->archinfo_host.endness == VexEndnessLE
|| vta->archinfo_host.endness == VexEndnessBE);
break;
@@ -466,6 +458,9 @@
vpanic("LibVEX_Translate: unsupported host insn set");
}
+ // Are the host's hardware capabilities feasible. The function will
+ // not return if hwcaps are infeasible in some sense.
+ check_hwcaps(vta->arch_host, vta->archinfo_host.hwcaps);
switch (vta->arch_guest) {
@@ -482,7 +477,6 @@
szB_GUEST_IP = sizeof( ((VexGuestX86State*)0)->guest_EIP );
offB_HOST_EvC_COUNTER = offsetof(VexGuestX86State,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestX86State,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchX86, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessLE);
vassert(0 == sizeof(VexGuestX86State) % 16);
vassert(sizeof( ((VexGuestX86State*)0)->guest_CMSTART) == 4);
@@ -503,7 +497,6 @@
szB_GUEST_IP = sizeof( ((VexGuestAMD64State*)0)->guest_RIP );
offB_HOST_EvC_COUNTER = offsetof(VexGuestAMD64State,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestAMD64State,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchAMD64, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessLE);
vassert(0 == sizeof(VexGuestAMD64State) % 16);
vassert(sizeof( ((VexGuestAMD64State*)0)->guest_CMSTART ) == 8);
@@ -524,7 +517,6 @@
szB_GUEST_IP = sizeof( ((VexGuestPPC32State*)0)->guest_CIA );
offB_HOST_EvC_COUNTER = offsetof(VexGuestPPC32State,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestPPC32State,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchPPC32, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessBE);
vassert(0 == sizeof(VexGuestPPC32State) % 16);
vassert(sizeof( ((VexGuestPPC32State*)0)->guest_CMSTART ) == 4);
@@ -545,7 +537,6 @@
szB_GUEST_IP = sizeof( ((VexGuestPPC64State*)0)->guest_CIA );
offB_HOST_EvC_COUNTER = offsetof(VexGuestPPC64State,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestPPC64State,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchPPC64, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessBE ||
vta->archinfo_guest.endness == VexEndnessLE );
vassert(0 == sizeof(VexGuestPPC64State) % 16);
@@ -568,7 +559,6 @@
szB_GUEST_IP = sizeof( ((VexGuestS390XState*)0)->guest_IA);
offB_HOST_EvC_COUNTER = offsetof(VexGuestS390XState,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestS390XState,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchS390X, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessBE);
vassert(0 == sizeof(VexGuestS390XState) % 16);
vassert(sizeof( ((VexGuestS390XState*)0)->guest_CMSTART ) == 8);
@@ -589,7 +579,6 @@
szB_GUEST_IP = sizeof( ((VexGuestARMState*)0)->guest_R15T );
offB_HOST_EvC_COUNTER = offsetof(VexGuestARMState,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestARMState,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchARM, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessLE);
vassert(0 == sizeof(VexGuestARMState) % 16);
vassert(sizeof( ((VexGuestARMState*)0)->guest_CMSTART) == 4);
@@ -610,7 +599,6 @@
szB_GUEST_IP = sizeof( ((VexGuestARM64State*)0)->guest_PC );
offB_HOST_EvC_COUNTER = offsetof(VexGuestARM64State,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestARM64State,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchARM64, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessLE);
vassert(0 == sizeof(VexGuestARM64State) % 16);
vassert(sizeof( ((VexGuestARM64State*)0)->guest_CMSTART) == 8);
@@ -631,7 +619,6 @@
szB_GUEST_IP = sizeof( ((VexGuestMIPS32State*)0)->guest_PC );
offB_HOST_EvC_COUNTER = offsetof(VexGuestMIPS32State,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestMIPS32State,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchMIPS32, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessLE
|| vta->archinfo_guest.endness == VexEndnessBE);
vassert(0 == sizeof(VexGuestMIPS32State) % 16);
@@ -653,7 +640,6 @@
szB_GUEST_IP = sizeof( ((VexGuestMIPS64State*)0)->guest_PC );
offB_HOST_EvC_COUNTER = offsetof(VexGuestMIPS64State,host_EvC_COUNTER);
offB_HOST_EvC_FAILADDR = offsetof(VexGuestMIPS64State,host_EvC_FAILADDR);
- vassert(are_valid_hwcaps(VexArchMIPS64, vta->archinfo_guest.hwcaps));
vassert(vta->archinfo_guest.endness == VexEndnessLE
|| vta->archinfo_guest.endness == VexEndnessBE);
vassert(0 == sizeof(VexGuestMIPS64State) % 16);
@@ -666,6 +652,11 @@
vpanic("LibVEX_Translate: unsupported guest insn set");
}
+ // Are the guest's hardware capabilities feasible. The function will
+ // not return if hwcaps are infeasible in some sense.
+ // FIXME: how can we know the guest's hardware capabilities?
+ check_hwcaps(vta->arch_guest, vta->archinfo_guest.hwcaps);
+
/* Set up result struct. */
VexTranslateResult res;
res.status = VexTransOK;
@@ -1246,10 +1237,12 @@
}
}
+/* Return a string with the hardware capabilities to the extent as
+ they pertain to the translation process. No attempt is made, to
+ detect *all* capabilities an architecture may have. */
const HChar* LibVEX_ppVexHwCaps ( VexArch arch, UInt hwcaps )
{
- const HChar* str = show_hwcaps(arch,hwcaps);
- return str ? str : "INVALID";
+ return show_hwcaps(arch, hwcaps);
}
@@ -1283,189 +1276,166 @@
}
+/* Convenience macro to be used in show_hwcaps_ARCH functions */
+#define NUM_HWCAPS (sizeof hwcaps_list / sizeof hwcaps_list[0])
+
/* Return a string showing the hwcaps in a nice way. The string will
- be NULL for invalid combinations of flags, so these functions also
- serve as a way to validate hwcaps values. */
+ be NULL for unrecognised hardware capabilities. */
static const HChar* show_hwcaps_x86 ( UInt hwcaps )
{
- /* Monotonic, LZCNT > SSE3 > SSE2 > SSE1 > MMXEXT > baseline. */
- switch (hwcaps) {
- case 0:
- return "x86-sse0";
- case VEX_HWCAPS_X86_MMXEXT:
- return "x86-mmxext";
- case VEX_HWCAPS_X86_MMXEXT | VEX_HWCAPS_X86_SSE1:
- return "x86-mmxext-sse1";
- case VEX_HWCAPS_X86_MMXEXT | VEX_HWCAPS_X86_SSE1 | VEX_HWCAPS_X86_SSE2:
- return "x86-mmxext-sse1-sse2";
- case VEX_HWCAPS_X86_MMXEXT | VEX_HWCAPS_X86_SSE1 | VEX_HWCAPS_X86_SSE2
- | VEX_HWCAPS_X86_LZCNT:
- return "x86-mmxext-sse1-sse2-lzcnt";
- case VEX_HWCAPS_X86_MMXEXT | VEX_HWCAPS_X86_SSE1 | VEX_HWCAPS_X86_SSE2
- | VEX_HWCAPS_X86_SSE3:
- return "x86-mmxext-sse1-sse2-sse3";
- case VEX_HWCAPS_X86_MMXEXT | VEX_HWCAPS_X86_SSE1 | VEX_HWCAPS_X86_SSE2
- | VEX_HWCAPS_X86_SSE3 | VEX_HWCAPS_X86_LZCNT:
- return "x86-mmxext-sse1-sse2-sse3-lzcnt";
- default:
- return NULL;
+ static const HChar prefix[] = "x86";
+ static const struct {
+ UInt hwcaps_bit;
+ HChar name[7];
+ } hwcaps_list[] = {
+ { VEX_HWCAPS_X86_MMXEXT, "mmxext" },
+ { VEX_HWCAPS_X86_SSE1, "sse1" },
+ { VEX_HWCAPS_X86_SSE2, "sse2" },
+ { VEX_HWCAPS_X86_SSE3, "sse3" },
+ { VEX_HWCAPS_X86_LZCNT, "lzcnt" },
+ };
+ /* Allocate a large enough buffer */
+ static HChar buf[sizeof prefix +
+ NUM_HWCAPS * (sizeof hwcaps_list[0].name + 1) + 1]; // '\0'
+ if (buf[0] != '\0') return buf; /* already constructed */
+
+ HChar *p = buf + vex_sprintf(buf, "%s", prefix);
+
+ if (hwcaps == 0) {
+ vex_sprintf(p, "-%s", "sse0");
+ } else {
+ UInt i;
+ for (i = 0 ; i < NUM_HWCAPS; ++i) {
+ if (hwcaps & hwcaps_list[i].hwcaps_bit)
+ p = p + vex_sprintf(p, "-%s", hwcaps_list[i].name);
+ }
}
+ return buf;
}
static const HChar* show_hwcaps_amd64 ( UInt hwcaps )
{
- /* SSE3 and CX16 are orthogonal and > baseline, although we really
- don't expect to come across anything which can do SSE3 but can't
- do CX16. Still, we can handle that case. LZCNT is similarly
- orthogonal. */
+ static const HChar prefix[] = "amd64";
+ static const struct {
+ UInt hwcaps_bit;
+ HChar name[7];
+ } hwcaps_list[] = {
+ { VEX_HWCAPS_AMD64_CX16, "cx16" },
+ { VEX_HWCAPS_AMD64_LZCNT, "lzcnt" },
+ { VEX_HWCAPS_AMD64_RDTSCP, "rdtscp" },
+ { VEX_HWCAPS_AMD64_SSE3, "sse3" },
+ { VEX_HWCAPS_AMD64_AVX, "avx" },
+ { VEX_HWCAPS_AMD64_AVX2, "avx2" },
+ { VEX_HWCAPS_AMD64_BMI, "bmi" },
+ };
+ /* Allocate a large enough buffer */
+ static HChar buf[sizeof prefix +
+ NUM_HWCAPS * (sizeof hwcaps_list[0].name + 1) + 1]; // '\0'
+ if (buf[0] != '\0') return buf; /* already constructed */
- /* Throw out obviously stupid cases: */
- Bool have_sse3 = (hwcaps & VEX_HWCAPS_AMD64_SSE3) != 0;
- Bool have_avx = (hwcaps & VEX_HWCAPS_AMD64_AVX) != 0;
- Bool have_bmi = (hwcaps & VEX_HWCAPS_AMD64_BMI) != 0;
- Bool have_avx2 = (hwcaps & VEX_HWCAPS_AMD64_AVX2) != 0;
- /* AVX without SSE3 */
- if (have_avx && !have_sse3)
- return NULL;
- /* AVX2 or BMI without AVX */
- if ((have_avx2 || have_bmi) && !have_avx)
- return NULL;
+ HChar *p = buf + vex_sprintf(buf, "%s", prefix);
- /* This isn't threadsafe. We might need to fix it at some point. */
- static HChar buf[100] = { 0 };
- if (buf[0] != 0) return buf; /* already constructed */
-
- vex_bzero(buf, sizeof(buf));
-
- HChar* p = &buf[0];
-
- p = p + vex_sprintf(p, "%s", "amd64");
if (hwcaps == 0) {
- /* special-case the baseline case */
- p = p + vex_sprintf(p, "%s", "-sse2");
- goto out;
+ vex_sprintf(p, "-%s", "sse2");
+ } else {
+ UInt i;
+ for (i = 0 ; i < NUM_HWCAPS; ++i) {
+ if (hwcaps & hwcaps_list[i].hwcaps_bit)
+ p = p + vex_sprintf(p, "-%s", hwcaps_list[i].name);
+ }
}
- if (hwcaps & VEX_HWCAPS_AMD64_CX16) {
- p = p + vex_sprintf(p, "%s", "-cx16");
- }
- if (hwcaps & VEX_HWCAPS_AMD64_LZCNT) {
- p = p + vex_sprintf(p, "%s", "-lzcnt");
- }
- if (hwcaps & VEX_HWCAPS_AMD64_RDTSCP) {
- p = p + vex_sprintf(p, "%s", "-rdtscp");
- }
- if (hwcaps & VEX_HWCAPS_AMD64_SSE3) {
- p = p + vex_sprintf(p, "%s", "-sse3");
- }
- if (hwcaps & VEX_HWCAPS_AMD64_AVX) {
- p = p + vex_sprintf(p, "%s", "-avx");
- }
- if (hwcaps & VEX_HWCAPS_AMD64_AVX2) {
- p = p + vex_sprintf(p, "%s", "-avx2");
- }
- if (hwcaps & VEX_HWCAPS_AMD64_BMI) {
- p = p + vex_sprintf(p, "%s", "-bmi");
- }
-
- out:
- vassert(buf[sizeof(buf)-1] == 0);
return buf;
}
static const HChar* show_hwcaps_ppc32 ( UInt hwcaps )
{
- /* Monotonic with complications. Basically V > F > baseline,
- but once you have F then you can have FX or GX too. */
- const UInt F = VEX_HWCAPS_PPC32_F;
- const UInt V = VEX_HWCAPS_PPC32_V;
- const UInt FX = VEX_HWCAPS_PPC32_FX;
- const UInt GX = VEX_HWCAPS_PPC32_GX;
- const UInt VX = VEX_HWCAPS_PPC32_VX;
- const UInt DFP = VEX_HWCAPS_PPC32_DFP;
- const UInt ISA2_07 = VEX_HWCAPS_PPC32_ISA2_07;
- UInt c = hwcaps;
- if (c == 0) return "ppc32-int";
- if (c == F) return "ppc32-int-flt";
- if (c == (F|FX)) return "ppc32-int-flt-FX";
- if (c == (F|GX)) return "ppc32-int-flt-GX";
- if (c == (F|FX|GX)) return "ppc32-int-flt-FX-GX";
- if (c == (F|V)) return "ppc32-int-flt-vmx";
- if (c == (F|V|FX)) return "ppc32-int-flt-vmx-FX";
- if (c == (F|V|GX)) return "ppc32-int-flt-vmx-GX";
- if (c == (F|V|FX|GX)) return "ppc32-int-flt-vmx-FX-GX";
- if (c == (F|V|FX|GX|DFP)) return "ppc32-int-flt-vmx-FX-GX-DFP";
- if (c == (F|V|FX|GX|VX|DFP)) return "ppc32-int-flt-vmx-FX-GX-VX-DFP";
- if (c == (F|V|FX|GX|VX|DFP|ISA2_07))
- return "ppc32-int-flt-vmx-FX-GX-VX-DFP-ISA2_07";
+ static const HChar prefix[] = "ppc32-int";
+ static const struct {
+ UInt hwcaps_bit;
+ HChar name[8];
+ } hwcaps_list[] = {
+ { VEX_HWCAPS_PPC32_F, "flt" },
+ { VEX_HWCAPS_PPC32_V, "vmx" },
+ { VEX_HWCAPS_PPC32_FX, "FX" },
+ { VEX_HWCAPS_PPC32_GX, "GX" },
+ { VEX_HWCAPS_PPC32_VX, "VX" },
+ { VEX_HWCAPS_PPC32_DFP, "DFP" },
+ { VEX_HWCAPS_PPC32_ISA2_07, "ISA2_07" },
+ };
+ /* Allocate a large enough buffer */
+ static HChar buf[sizeof prefix +
+ NUM_HWCAPS * (sizeof hwcaps_list[0].name + 1) + 1]; // '\0'
+ if (buf[0] != '\0') return buf; /* already constructed */
- return NULL;
+ HChar *p = buf + vex_sprintf(buf, "%s", prefix);
+
+ if (hwcaps == 0) return buf;
+
+ UInt i;
+ for (i = 0 ; i < NUM_HWCAPS; ++i) {
+ if (hwcaps & hwcaps_list[i].hwcaps_bit)
+ p = p + vex_sprintf(p, "-%s", hwcaps_list[i].name);
+ }
+ return buf;
}
static const HChar* show_hwcaps_ppc64 ( UInt hwcaps )
{
- /* Monotonic with complications. Basically V > baseline(==F),
- but once you have F then you can have FX or GX too. */
- const UInt V = VEX_HWCAPS_PPC64_V;
- const UInt FX = VEX_HWCAPS_PPC64_FX;
- const UInt GX = VEX_HWCAPS_PPC64_GX;
- const UInt VX = VEX_HWCAPS_PPC64_VX;
- const UInt DFP = VEX_HWCAPS_PPC64_DFP;
- const UInt ISA2_07 = VEX_HWCAPS_PPC64_ISA2_07;
- UInt c = hwcaps;
- if (c == 0) return "ppc64-int-flt";
- if (c == FX) return "ppc64-int-flt-FX";
- if (c == GX) return "ppc64-int-flt-GX";
- if (c == (FX|GX)) return "ppc64-int-flt-FX-GX";
- if (c == V) return "ppc64-int-flt-vmx";
- if (c == (V|FX)) return "ppc64-int-flt-vmx-FX";
- if (c == (V|GX)) return "ppc64-int-flt-vmx-GX";
- if (c == (V|FX|GX)) return "ppc64-int-flt-vmx-FX-GX";
- if (c == (V|FX|GX|DFP)) return "ppc64-int-flt-vmx-FX-GX-DFP";
- if (c == (V|FX|GX|VX|DFP)) return "ppc64-int-flt-vmx-FX-GX-VX-DFP";
- if (c == (V|FX|GX|VX|DFP|ISA2_07))
- return "ppc64-int-flt-vmx-FX-GX-VX-DFP-ISA2_07";
- return NULL;
+ static const HChar prefix[] = "ppc64-int-flt";
+ static const struct {
+ UInt hwcaps_bit;
+ HChar name[8];
+ } hwcaps_list[] = {
+ { VEX_HWCAPS_PPC64_FX, "FX" },
+ { VEX_HWCAPS_PPC64_GX, "GX" },
+ { VEX_HWCAPS_PPC64_V, "vmx" },
+ { VEX_HWCAPS_PPC64_DFP, "DFP" },
+ { VEX_HWCAPS_PPC64_ISA2_07, "ISA2_07" },
+ };
+ /* Allocate a large enough buffer */
+ static HChar buf[sizeof prefix +
+ NUM_HWCAPS * (sizeof hwcaps_list[0].name + 1) + 1]; // '\0'
+ if (buf[0] != '\0') return buf; /* already constructed */
+
+ HChar *p = buf + vex_sprintf(buf, "%s", prefix);
+
+ if (hwcaps == 0) return buf;
+
+ UInt i;
+ for (i = 0 ; i < NUM_HWCAPS; ++i) {
+ if (hwcaps & hwcaps_list[i].hwcaps_bit)
+ p = p + vex_sprintf(p, "-%s", hwcaps_list[i].name);
+ }
+ return buf;
}
static const HChar* show_hwcaps_arm ( UInt hwcaps )
{
- Bool N = ((hwcaps & VEX_HWCAPS_ARM_NEON) != 0);
- Bool vfp = ((hwcaps & (VEX_HWCAPS_ARM_VFP |
- VEX_HWCAPS_ARM_VFP2 | VEX_HWCAPS_ARM_VFP3)) != 0);
- switch (VEX_ARM_ARCHLEVEL(hwcaps)) {
- case 5:
- if (N)
- return NULL;
- if (vfp)
- return "ARMv5-vfp";
- else
- return "ARMv5";
- return NULL;
- case 6:
- if (N)
- return NULL;
- if (vfp)
- return "ARMv6-vfp";
- else
- return "ARMv6";
- return NULL;
- case 7:
- if (vfp) {
- if (N)
- return "ARMv7-vfp-neon";
- else
- return "ARMv7-vfp";
- } else {
- if (N)
- return "ARMv7-neon";
- else
- return "ARMv7";
- }
- default:
- return NULL;
+ static const HChar prefix[] = "ARM";
+ static const struct {
+ UInt hwcaps_bit;
+ HChar name[6];
+ } hwcaps_list[] = {
+ { VEX_HWCAPS_ARM_NEON, "neon" },
+ { VEX_HWCAPS_ARM_VFP | VEX_HWCAPS_ARM_VFP2 | VEX_HWCAPS_ARM_VFP3, "vfp" },
+ };
+ /* Allocate a large enough buffer */
+ static HChar buf[sizeof prefix + 12 + // level
+ NUM_HWCAPS * (sizeof hwcaps_list[0].name + 1) + 1]; // '\0'
+ if (buf[0] != '\0') return buf; /* already constructed */
+
+ HChar *p;
+ UInt i, level;
+
+ level = VEX_ARM_ARCHLEVEL(hwcaps);
+
+ p = buf + vex_sprintf(buf, "%sv%u", prefix, level);
+ for (i = 0 ; i < NUM_HWCAPS; ++i) {
+ if (hwcaps & hwcaps_list[i].hwcaps_bit)
+ p = p + vex_sprintf(p, "-%s", hwcaps_list[i].name);
}
- return NULL;
+ return buf;
}
static const HChar* show_hwcaps_arm64 ( UInt hwcaps )
@@ -1474,7 +1444,7 @@
and declare it invalid otherwise. */
if (hwcaps == 0)
return "baseline";
- return NULL;
+ return "Unsupported";
}
static const HChar* show_hwcaps_s390x ( UInt hwcaps )
@@ -1497,15 +1467,15 @@
{ VEX_HWCAPS_S390X_LSC, "lsc" },
{ VEX_HWCAPS_S390X_PFPO, "pfpo" },
};
-#define NUM_HWCAPS (sizeof hwcaps_list / sizeof hwcaps_list[0])
+ /* Allocate a large enough buffer */
static HChar buf[sizeof prefix +
- NUM_HWCAPS * (sizeof hwcaps_list[0].name + 1) +
- 1]; // '\0'
- HChar *p;
- UInt i;
+ NUM_HWCAPS * (sizeof hwcaps_list[0].name + 1) + 1]; // '\0'
if (buf[0] != '\0') return buf; /* already constructed */
+ HChar *p;
+ UInt i;
+
hwcaps = VEX_HWCAPS_S390X(hwcaps);
p = buf + vex_sprintf(buf, "%s", prefix);
@@ -1551,7 +1521,7 @@
return "Cavium-baseline";
}
- return NULL;
+ return "Unsupported baseline";
}
static const HChar* show_hwcaps_mips64 ( UInt hwcaps )
@@ -1559,7 +1529,9 @@
return "mips64-baseline";
}
-/* ---- */
+#undef NUM_HWCAPS
+
+/* Thie function must not return NULL. */
static const HChar* show_hwcaps ( VexArch arch, UInt hwcaps )
{
switch (arch) {
@@ -1576,16 +1548,192 @@
}
}
-static Bool are_valid_hwcaps ( VexArch arch, UInt hwcaps )
+/* To be used to complain about hwcaps we cannot handle */
+__attribute__((noreturn))
+static void invalid_hwcaps ( VexArch arch, UInt hwcaps, const HChar *message )
{
- if (arch == VexArchS390X) {
- if (! s390_host_has_ldisp) {
- vpanic("Host does not have long displacement facility.\n"
- " Cannot continue. Good-bye.\n");
- }
- return True;
+ vfatal("\nVEX: %s"
+ " Found: %s\n", message, show_hwcaps(arch, hwcaps));
+}
+
+/* This function will not return iff the hwcaps don't pass the test. */
+static void check_hwcaps ( VexArch arch, UInt hwcaps )
+{
+ switch (arch) {
+ case VexArchX86: {
+ if (hwcaps == 0) return; // baseline
+
+ /* Monotonic: SSE3 > SSE2 > SSE1 > MMXEXT > baseline. */
+ static const UInt extras[] = {
+ VEX_HWCAPS_X86_MMXEXT, VEX_HWCAPS_X86_SSE1, VEX_HWCAPS_X86_SSE2,
+ VEX_HWCAPS_X86_SSE3
+ };
+
+ UInt i, caps = 0;
+ for (i = 0; i < sizeof extras / sizeof extras[0]; ++i) {
+ caps |= extras[i];
+ if (caps == hwcaps) return;
+ if ((caps & VEX_HWCAPS_X86_SSE2) != 0) {
+ if ((caps & VEX_HWCAPS_X86_LZCNT) != 0) return;
+ }
+ }
+ invalid_hwcaps(arch, hwcaps, "Cannot handle capabilities\n");
+ }
+
+ case VexArchAMD64: {
+ invalid_hwcaps(arch, hwcaps,
+ "Support for AVX2 requires AVX capabilities\n");
+ /* SSE3 and CX16 are orthogonal and > baseline, although we really
+ don't expect to come across anything which can do SSE3 but can't
+ do CX16. Still, we can handle that case. LZCNT is similarly
+ orthogonal. */
+
+ /* Throw out obviously stupid cases: */
+ Bool have_sse3 = (hwcaps & VEX_HWCAPS_AMD64_SSE3) != 0;
+ Bool have_avx = (hwcaps & VEX_HWCAPS_AMD64_AVX) != 0;
+ Bool have_bmi = (hwcaps & VEX_HWCAPS_AMD64_BMI) != 0;
+ Bool have_avx2 = (hwcaps & VEX_HWCAPS_AMD64_AVX2) != 0;
+
+ /* AVX without SSE3 */
+ if (have_avx && !have_sse3)
+ invalid_hwcaps(arch, hwcaps,
+ "Support for AVX requires SSE3 capabilities\n");
+ /* AVX2 or BMI without AVX */
+ if (have_avx2 && !have_avx)
+ invalid_hwcaps(arch, hwcaps,
+ "Support for AVX2 requires AVX capabilities\n");
+ if (have_bmi && !have_avx)
+ invalid_hwcaps(arch, hwcaps,
+ "Support for BMI requires AVX capabilities\n");
+ return;
+ }
+
+ case VexArchPPC32: {
+ /* Monotonic with complications. Basically V > F > baseline,
+ but once you have F then you can have FX or GX too. */
+ if (hwcaps == 0) return; // baseline
+
+ if ((hwcaps & VEX_HWCAPS_PPC32_F) == 0)
+ invalid_hwcaps(arch, hwcaps,
+ "Missing floating point capability\n");
+ /* V, FX, and GX can appear in any combination */
+
+ /* DFP requires V and FX and GX */
+ UInt v_fx_gx = VEX_HWCAPS_PPC32_V | VEX_HWCAPS_PPC32_FX |
+ VEX_HWCAPS_PPC32_GX;
+ Bool has_v_fx_gx = (hwcaps & v_fx_gx) == v_fx_gx;
+
+ if ((hwcaps & VEX_HWCAPS_PPC32_DFP) && ! has_v_fx_gx)
+ invalid_hwcaps(arch, hwcaps,
+ "DFP requires VMX and FX and GX capabilities\n");
+
+ /* VX requires V and FX and GX */
+ if ((hwcaps & VEX_HWCAPS_PPC32_VX) && ! has_v_fx_gx)
+ invalid_hwcaps(arch, hwcaps,
+ "VX requires VMX and FX and GX capabilities\n");
+
+ /* ISA2_07 requires everything else */
+ if ((hwcaps & VEX_HWCAPS_PPC32_ISA2_07) != 0) {
+ if (! has_v_fx_gx)
+ invalid_hwcaps(arch, hwcaps,
+ "ISA2_07 requires VMX and FX and GX capabilities\n");
+ if (! (hwcaps & VEX_HWCAPS_PPC32_VX))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA2_07 requires VX capabilities\n");
+ if (! (hwcaps & VEX_HWCAPS_PPC32_DFP))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA2_07 requires DFP capabilities\n");
+ }
+ return;
+ }
+
+ case VexArchPPC64: {
+ /* Monotonic with complications. Basically V > baseline(==F),
+ but once you have F then you can have FX or GX too. */
+ if (hwcaps == 0) return; // baseline
+
+ /* V, FX, and GX can appear in any combination */
+
+ /* DFP requires V and FX and GX */
+ UInt v_fx_gx = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX |
+ VEX_HWCAPS_PPC64_GX;
+ Bool has_v_fx_gx = (hwcaps & v_fx_gx) == v_fx_gx;
+
+ if ((hwcaps & VEX_HWCAPS_PPC64_DFP) && ! has_v_fx_gx)
+ invalid_hwcaps(arch, hwcaps,
+ "DFP requires VMX and FX and GX capabilities\n");
+
+ /* VX requires V and FX and GX */
+ if ((hwcaps & VEX_HWCAPS_PPC32_VX) && ! has_v_fx_gx)
+ invalid_hwcaps(arch, hwcaps,
+ "VX requires VMX and FX and GX capabilities\n");
+
+ /* ISA2_07 requires everything else */
+ if ((hwcaps & VEX_HWCAPS_PPC64_ISA2_07) != 0) {
+ if (! has_v_fx_gx)
+ invalid_hwcaps(arch, hwcaps,
+ "ISA2_07 requires VMX and FX and GX capabilities\n");
+ if (! (hwcaps & VEX_HWCAPS_PPC64_VX))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA2_07 requires VX capabilities\n");
+ if (! (hwcaps & VEX_HWCAPS_PPC64_DFP))
+ invalid_hwcaps(arch, hwcaps,
+ "ISA2_07 requires DFP capabilities\n");
+ }
+ return;
+ }
+
+ case VexArchARM: {
+ Bool NEON = ((hwcaps & VEX_HWCAPS_ARM_NEON) != 0);
+ UInt level = VEX_ARM_ARCHLEVEL(hwcaps);
+
+ switch (level) {
+ case 5:
+ if (NEON)
+ invalid_hwcaps(arch, hwcaps,
+ "NEON instructions are not supported for ARMv5.\n");
+ return;
+ case 6:
+ if (NEON)
+ invalid_hwcaps(arch, hwcaps,
+ "NEON instructions are not supported for ARMv6.\n");
+ return;
+ case 7:
+ return;
+ default:
+ invalid_hwcaps(arch, hwcaps,
+ "ARM architecture level is not supported.\n");
+ }
+ }
+
+ case VexArchARM64:
+ if (hwcaps != 0)
+ invalid_hwcaps(arch, hwcaps,
+ "Unsupported hardware capabilities.\n");
+ return;
+
+ case VexArchS390X:
+ if (! s390_host_has_ldisp)
+ invalid_hwcaps(arch, hwcaps,
+ "Host does not have long displacement facility.\n");
+ return;
+
+ case VexArchMIPS32:
+ switch (VEX_MIPS_COMP_ID(hwcaps)) {
+ case VEX_PRID_COMP_MIPS:
+ case VEX_PRID_COMP_BROADCOM:
+ case VEX_PRID_COMP_NETLOGIC:
+ return;
+ default:
+ invalid_hwcaps(arch, hwcaps, "Unsupported baseline\n");
+ }
+
+ case VexArchMIPS64:
+ return;
+
+ default:
+ vpanic("unknown architecture");
}
- return show_hwcaps(arch,hwcaps) != NULL;
}