Change the way Vex represents architecture variants into something
more flexible. Prior to this change, the type VexSubArch effectively
imposed a total ordering on subarchitecture capabilities, which was
overly restrictive. This change moves to effectively using a bit-set,
allowing some features (instruction groups) to be supported or not
supported independently of each other.
git-svn-id: svn://svn.valgrind.org/vex/trunk@1555 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/main/vex_main.c b/priv/main/vex_main.c
index b232fbf..a93a17a 100644
--- a/priv/main/vex_main.c
+++ b/priv/main/vex_main.c
@@ -70,6 +70,12 @@
/* This file contains the top level interface to the library. */
+/* --------- fwds ... --------- */
+
+static Bool are_valid_hwcaps ( VexArch arch, UInt hwcaps );
+static HChar* show_hwcaps ( VexArch arch, UInt hwcaps );
+
+
/* --------- Initialise the library. --------- */
/* Exported to library client. */
@@ -253,9 +259,7 @@
emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_X86Instr;
host_is_bigendian = False;
host_word_type = Ity_I32;
- vassert(vta->archinfo_host.subarch == VexSubArchX86_sse0
- || vta->archinfo_host.subarch == VexSubArchX86_sse1
- || vta->archinfo_host.subarch == VexSubArchX86_sse2);
+ vassert(are_valid_hwcaps(VexArchX86, vta->archinfo_host.hwcaps));
vassert(vta->dispatch != NULL); /* jump-to-dispatcher scheme */
break;
@@ -274,7 +278,7 @@
emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_AMD64Instr;
host_is_bigendian = False;
host_word_type = Ity_I64;
- vassert(vta->archinfo_host.subarch == VexSubArch_NONE);
+ vassert(are_valid_hwcaps(VexArchAMD64, vta->archinfo_host.hwcaps));
vassert(vta->dispatch != NULL); /* jump-to-dispatcher scheme */
break;
@@ -293,9 +297,7 @@
emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_PPCInstr;
host_is_bigendian = True;
host_word_type = Ity_I32;
- vassert(vta->archinfo_guest.subarch == VexSubArchPPC32_I
- || vta->archinfo_guest.subarch == VexSubArchPPC32_FI
- || vta->archinfo_guest.subarch == VexSubArchPPC32_VFI);
+ vassert(are_valid_hwcaps(VexArchPPC32, vta->archinfo_host.hwcaps));
vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
break;
@@ -314,8 +316,7 @@
emit = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_PPCInstr;
host_is_bigendian = True;
host_word_type = Ity_I64;
- vassert(vta->archinfo_guest.subarch == VexSubArchPPC64_FI
- || vta->archinfo_guest.subarch == VexSubArchPPC64_VFI);
+ vassert(are_valid_hwcaps(VexArchPPC64, vta->archinfo_host.hwcaps));
vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
break;
@@ -335,9 +336,7 @@
guest_layout = &x86guest_layout;
offB_TISTART = offsetof(VexGuestX86State,guest_TISTART);
offB_TILEN = offsetof(VexGuestX86State,guest_TILEN);
- vassert(vta->archinfo_guest.subarch == VexSubArchX86_sse0
- || vta->archinfo_guest.subarch == VexSubArchX86_sse1
- || vta->archinfo_guest.subarch == VexSubArchX86_sse2);
+ vassert(are_valid_hwcaps(VexArchX86, vta->archinfo_guest.hwcaps));
vassert(0 == sizeof(VexGuestX86State) % 8);
vassert(sizeof( ((VexGuestX86State*)0)->guest_TISTART) == 4);
vassert(sizeof( ((VexGuestX86State*)0)->guest_TILEN ) == 4);
@@ -353,7 +352,7 @@
guest_layout = &amd64guest_layout;
offB_TISTART = offsetof(VexGuestAMD64State,guest_TISTART);
offB_TILEN = offsetof(VexGuestAMD64State,guest_TILEN);
- vassert(vta->archinfo_guest.subarch == VexSubArch_NONE);
+ vassert(are_valid_hwcaps(VexArchAMD64, vta->archinfo_guest.hwcaps));
vassert(0 == sizeof(VexGuestAMD64State) % 8);
vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TISTART ) == 8);
vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TILEN ) == 8);
@@ -369,7 +368,7 @@
guest_layout = &armGuest_layout;
offB_TISTART = 0; /* hack ... arm has bitrot */
offB_TILEN = 0; /* hack ... arm has bitrot */
- vassert(vta->archinfo_guest.subarch == VexSubArchARM_v4);
+ vassert(are_valid_hwcaps(VexArchARM, vta->archinfo_guest.hwcaps));
break;
case VexArchPPC32:
@@ -381,9 +380,7 @@
guest_layout = &ppc32Guest_layout;
offB_TISTART = offsetof(VexGuestPPC32State,guest_TISTART);
offB_TILEN = offsetof(VexGuestPPC32State,guest_TILEN);
- vassert(vta->archinfo_guest.subarch == VexSubArchPPC32_I
- || vta->archinfo_guest.subarch == VexSubArchPPC32_FI
- || vta->archinfo_guest.subarch == VexSubArchPPC32_VFI);
+ vassert(are_valid_hwcaps(VexArchPPC32, vta->archinfo_guest.hwcaps));
vassert(0 == sizeof(VexGuestPPC32State) % 8);
vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TISTART ) == 4);
vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TILEN ) == 4);
@@ -399,8 +396,7 @@
guest_layout = &ppc64Guest_layout;
offB_TISTART = offsetof(VexGuestPPC64State,guest_TISTART);
offB_TILEN = offsetof(VexGuestPPC64State,guest_TILEN);
- vassert(vta->archinfo_guest.subarch == VexSubArchPPC64_FI
- || vta->archinfo_guest.subarch == VexSubArchPPC64_VFI);
+ vassert(are_valid_hwcaps(VexArchPPC64, vta->archinfo_guest.hwcaps));
vassert(0 == sizeof(VexGuestPPC64State) % 16);
vassert(sizeof( ((VexGuestPPC64State*)0)->guest_TISTART ) == 8);
vassert(sizeof( ((VexGuestPPC64State*)0)->guest_TILEN ) == 8);
@@ -416,7 +412,7 @@
/* doesn't necessarily have to be true, but if it isn't it means
we are simulating one flavour of an architecture a different
flavour of the same architecture, which is pretty strange. */
- vassert(vta->archinfo_guest.subarch == vta->archinfo_host.subarch);
+ vassert(vta->archinfo_guest.hwcaps == vta->archinfo_host.hwcaps);
}
vexAllocSanityCheck();
@@ -675,7 +671,7 @@
}
}
-/* --------- Arch/Subarch stuff. --------- */
+/* ------------------ Arch/HwCaps stuff. ------------------ */
const HChar* LibVEX_ppVexArch ( VexArch arch )
{
@@ -690,32 +686,117 @@
}
}
-const HChar* LibVEX_ppVexSubArch ( VexSubArch subarch )
+const HChar* LibVEX_ppVexHwCaps ( VexArch arch, UInt hwcaps )
{
- switch (subarch) {
- case VexSubArch_INVALID: return "INVALID";
- case VexSubArch_NONE: return "NONE";
- case VexSubArchX86_sse0: return "x86-sse0";
- case VexSubArchX86_sse1: return "x86-sse1";
- case VexSubArchX86_sse2: return "x86-sse2";
- case VexSubArchARM_v4: return "arm-v4";
- case VexSubArchPPC32_I: return "ppc32-int-only";
- case VexSubArchPPC32_FI: return "ppc32-int-and-fp";
- case VexSubArchPPC32_VFI: return "ppc32-int-fp-and-AV";
- case VexSubArchPPC64_FI: return "ppc64-int-and-fp";
- case VexSubArchPPC64_VFI: return "ppc64-int-fp-and-AV";
- default: return "VexSubArch???";
- }
+ HChar* str = show_hwcaps(arch,hwcaps);
+ return str ? str : "INVALID";
}
+
+
/* Write default settings info *vai. */
void LibVEX_default_VexArchInfo ( /*OUT*/VexArchInfo* vai )
{
- vai->subarch = VexSubArch_INVALID;
+ vai->hwcaps = 0;
vai->ppc_cache_line_szB = 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. */
+
+static HChar* show_hwcaps_x86 ( UInt hwcaps )
+{
+ /* Monotonic, SSE3 > SSE2 > SSE1 > baseline. */
+ if (hwcaps == 0)
+ return "x86-sse0";
+ if (hwcaps == VEX_HWCAPS_X86_SSE1)
+ return "x86-sse1";
+ if (hwcaps == (VEX_HWCAPS_X86_SSE1 | VEX_HWCAPS_X86_SSE2))
+ return "x86-sse1-sse2";
+ if (hwcaps == (VEX_HWCAPS_X86_SSE1
+ | VEX_HWCAPS_X86_SSE2 | VEX_HWCAPS_X86_SSE3))
+ return "x86-sse1-sse2-sse3";
+
+ return False;
+}
+
+static HChar* show_hwcaps_amd64 ( UInt hwcaps )
+{
+ /* Monotonic, SSE3 > baseline. */
+ if (hwcaps == 0)
+ return "amd64-sse2";
+ if (hwcaps == VEX_HWCAPS_AMD64_SSE3)
+ return "amd64-sse3";
+ return False;
+}
+
+static 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;
+ 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";
+ return NULL;
+}
+
+static 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_PPC32_V;
+ const UInt FX = VEX_HWCAPS_PPC32_FX;
+ const UInt GX = VEX_HWCAPS_PPC32_GX;
+ 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";
+ return NULL;
+}
+
+static HChar* show_hwcaps_arm ( UInt hwcaps )
+{
+ if (hwcaps == 0) return "arm-baseline";
+ return NULL;
+}
+
+/* ---- */
+static HChar* show_hwcaps ( VexArch arch, UInt hwcaps )
+{
+ switch (arch) {
+ case VexArchX86: return show_hwcaps_x86(hwcaps);
+ case VexArchAMD64: return show_hwcaps_amd64(hwcaps);
+ case VexArchPPC32: return show_hwcaps_ppc32(hwcaps);
+ case VexArchPPC64: return show_hwcaps_ppc64(hwcaps);
+ case VexArchARM: return show_hwcaps_arm(hwcaps);
+ default: return NULL;
+ }
+}
+
+static Bool are_valid_hwcaps ( VexArch arch, UInt hwcaps )
+{
+ return show_hwcaps(arch,hwcaps) != NULL;
+}
+
+
/*---------------------------------------------------------------*/
/*--- end main/vex_main.c ---*/
/*---------------------------------------------------------------*/