f6cbdf
commit 791fe5ecf909d573bcbf353b677b9404f9da0ed4
f6cbdf
Author: Mark Wielaard <mark@klomp.org>
f6cbdf
Date:   Mon May 27 22:19:27 2019 +0200
f6cbdf
f6cbdf
    Expose rdrand and f16c through cpuid also if the host only has avx.
f6cbdf
    
f6cbdf
    The amd64 CPUID dirtyhelpers are mostly static since they emulate some
f6cbdf
    existing CPU "family". The avx2 ("i7-4910MQ") CPUID variant however
f6cbdf
    can "dynamicly" enable rdrand and/or f16c if the host supports them.
f6cbdf
    Do the same for the avx_and_cx16 ("i5-2300") CPUID variant.
f6cbdf
    
f6cbdf
    https://bugs.kde.org/show_bug.cgi?id=408009
f6cbdf
f6cbdf
diff --git a/VEX/priv/guest_amd64_defs.h b/VEX/priv/guest_amd64_defs.h
f6cbdf
index 4f34b41..a5de527 100644
f6cbdf
--- a/VEX/priv/guest_amd64_defs.h
f6cbdf
+++ b/VEX/priv/guest_amd64_defs.h
f6cbdf
@@ -165,7 +165,9 @@ extern void  amd64g_dirtyhelper_storeF80le ( Addr/*addr*/, ULong/*data*/ );
f6cbdf
 extern void  amd64g_dirtyhelper_CPUID_baseline ( VexGuestAMD64State* st );
f6cbdf
 extern void  amd64g_dirtyhelper_CPUID_sse3_and_cx16 ( VexGuestAMD64State* st );
f6cbdf
 extern void  amd64g_dirtyhelper_CPUID_sse42_and_cx16 ( VexGuestAMD64State* st );
f6cbdf
-extern void  amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st );
f6cbdf
+extern void  amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st,
f6cbdf
+                                                     ULong hasF16C,
f6cbdf
+                                                     ULong hasRDRAND );
f6cbdf
 extern void  amd64g_dirtyhelper_CPUID_avx2 ( VexGuestAMD64State* st,
f6cbdf
                                              ULong hasF16C, ULong hasRDRAND );
f6cbdf
 
f6cbdf
diff --git a/VEX/priv/guest_amd64_helpers.c b/VEX/priv/guest_amd64_helpers.c
f6cbdf
index e4cf7e2..182bae0 100644
f6cbdf
--- a/VEX/priv/guest_amd64_helpers.c
f6cbdf
+++ b/VEX/priv/guest_amd64_helpers.c
f6cbdf
@@ -3141,8 +3141,11 @@ void amd64g_dirtyhelper_CPUID_sse42_and_cx16 ( VexGuestAMD64State* st )
f6cbdf
    address sizes   : 36 bits physical, 48 bits virtual
f6cbdf
    power management:
f6cbdf
 */
f6cbdf
-void amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st )
f6cbdf
+void amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st,
f6cbdf
+                                             ULong hasF16C, ULong hasRDRAND )
f6cbdf
 {
f6cbdf
+   vassert((hasF16C >> 1) == 0ULL);
f6cbdf
+   vassert((hasRDRAND >> 1) == 0ULL);
f6cbdf
 #  define SET_ABCD(_a,_b,_c,_d)                \
f6cbdf
       do { st->guest_RAX = (ULong)(_a);        \
f6cbdf
            st->guest_RBX = (ULong)(_b);        \
f6cbdf
@@ -3157,9 +3160,14 @@ void amd64g_dirtyhelper_CPUID_avx_and_cx16 ( VexGuestAMD64State* st )
f6cbdf
       case 0x00000000:
f6cbdf
          SET_ABCD(0x0000000d, 0x756e6547, 0x6c65746e, 0x49656e69);
f6cbdf
          break;
f6cbdf
-      case 0x00000001:
f6cbdf
-         SET_ABCD(0x000206a7, 0x00100800, 0x1f9ae3bf, 0xbfebfbff);
f6cbdf
+      case 0x00000001: {
f6cbdf
+         // As a baseline, advertise neither F16C (ecx:29) nor RDRAND (ecx:30),
f6cbdf
+         // but patch in support for them as directed by the caller.
f6cbdf
+         UInt ecx_extra
f6cbdf
+            = (hasF16C ? (1U << 29) : 0) | (hasRDRAND ? (1U << 30) : 0);
f6cbdf
+         SET_ABCD(0x000206a7, 0x00100800, (0x1f9ae3bf | ecx_extra), 0xbfebfbff);
f6cbdf
          break;
f6cbdf
+      }
f6cbdf
       case 0x00000002:
f6cbdf
          SET_ABCD(0x76035a01, 0x00f0b0ff, 0x00000000, 0x00ca0000);
f6cbdf
          break;
f6cbdf
diff --git a/VEX/priv/guest_amd64_toIR.c b/VEX/priv/guest_amd64_toIR.c
f6cbdf
index 56e992c..96dee38 100644
f6cbdf
--- a/VEX/priv/guest_amd64_toIR.c
f6cbdf
+++ b/VEX/priv/guest_amd64_toIR.c
f6cbdf
@@ -22007,7 +22007,8 @@ Long dis_ESC_0F (
f6cbdf
 
f6cbdf
       vassert(fName); vassert(fAddr);
f6cbdf
       IRExpr** args = NULL;
f6cbdf
-      if (fAddr == &amd64g_dirtyhelper_CPUID_avx2) {
f6cbdf
+      if (fAddr == &amd64g_dirtyhelper_CPUID_avx2
f6cbdf
+          || fAddr == &amd64g_dirtyhelper_CPUID_avx_and_cx16) {
f6cbdf
          Bool hasF16C   = (archinfo->hwcaps & VEX_HWCAPS_AMD64_F16C) != 0;
f6cbdf
          Bool hasRDRAND = (archinfo->hwcaps & VEX_HWCAPS_AMD64_RDRAND) != 0;
f6cbdf
          args = mkIRExprVec_3(IRExpr_GSPTR(),
f6cbdf
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
f6cbdf
index 3536e57..56a28d1 100644
f6cbdf
--- a/coregrind/m_machine.c
f6cbdf
+++ b/coregrind/m_machine.c
f6cbdf
@@ -1076,10 +1076,10 @@ Bool VG_(machine_get_hwcaps)( void )
f6cbdf
         have_avx2 = (ebx & (1<<5)) != 0; /* True => have AVX2 */
f6cbdf
      }
f6cbdf
 
f6cbdf
-     /* Sanity check for RDRAND and F16C.  These don't actually *need* AVX2, but
f6cbdf
-        it's convenient to restrict them to the AVX2 case since the simulated
f6cbdf
-        CPUID we'll offer them on has AVX2 as a base. */
f6cbdf
-     if (!have_avx2) {
f6cbdf
+     /* Sanity check for RDRAND and F16C.  These don't actually *need* AVX, but
f6cbdf
+        it's convenient to restrict them to the AVX case since the simulated
f6cbdf
+        CPUID we'll offer them on has AVX as a base. */
f6cbdf
+     if (!have_avx) {
f6cbdf
         have_f16c   = False;
f6cbdf
         have_rdrand = False;
f6cbdf
      }