2007-12-01 00:00:00 +00:00
/*
2014-07-15 07:33:49 -07:00
* Copyright ( c ) 1997 , 2014 , Oracle and / or its affiliates . All rights reserved .
2007-12-01 00:00:00 +00:00
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
* published by the Free Software Foundation .
*
* This code is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
2010-05-27 19:08:38 -07:00
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
2007-12-01 00:00:00 +00:00
*
*/
2010-11-23 13:22:55 -08:00
# ifndef CPU_X86_VM_VM_VERSION_X86_HPP
# define CPU_X86_VM_VM_VERSION_X86_HPP
# include "runtime/globals_extension.hpp"
# include "runtime/vm_version.hpp"
2007-12-01 00:00:00 +00:00
class VM_Version : public Abstract_VM_Version {
2015-10-08 12:49:30 -10:00
friend class VMStructs ;
2015-12-14 17:02:02 -10:00
friend class JVMCIVMStructs ;
2015-12-23 20:19:42 -10:00
public :
2007-12-01 00:00:00 +00:00
// cpuid result register layouts. These are all unions of a uint32_t
// (in case anyone wants access to the register as a whole) and a bitfield.
union StdCpuid1Eax {
uint32_t value ;
struct {
uint32_t stepping : 4 ,
model : 4 ,
family : 4 ,
proc_type : 2 ,
: 2 ,
ext_model : 4 ,
ext_family : 8 ,
: 4 ;
} bits ;
} ;
union StdCpuid1Ebx { // example, unused
uint32_t value ;
struct {
uint32_t brand_id : 8 ,
clflush_size : 8 ,
threads_per_cpu : 8 ,
apic_id : 8 ;
} bits ;
} ;
union StdCpuid1Ecx {
uint32_t value ;
struct {
uint32_t sse3 : 1 ,
2013-07-02 20:42:12 -04:00
clmul : 1 ,
: 1 ,
2007-12-01 00:00:00 +00:00
monitor : 1 ,
: 1 ,
vmx : 1 ,
: 1 ,
est : 1 ,
: 1 ,
ssse3 : 1 ,
cid : 1 ,
2016-08-26 12:17:50 -07:00
: 1 ,
fma : 1 ,
2007-12-01 00:00:00 +00:00
cmpxchg16 : 1 ,
: 4 ,
dca : 1 ,
2008-10-14 15:10:26 -07:00
sse4_1 : 1 ,
sse4_2 : 1 ,
2009-03-13 11:35:17 -07:00
: 2 ,
popcnt : 1 ,
2012-10-24 14:33:22 -07:00
: 1 ,
aes : 1 ,
: 1 ,
2011-12-14 14:54:38 -08:00
osxsave : 1 ,
avx : 1 ,
: 3 ;
2007-12-01 00:00:00 +00:00
} bits ;
} ;
union StdCpuid1Edx {
uint32_t value ;
struct {
uint32_t : 4 ,
tsc : 1 ,
: 3 ,
cmpxchg8 : 1 ,
: 6 ,
cmov : 1 ,
2011-06-28 15:04:39 -07:00
: 3 ,
clflush : 1 ,
: 3 ,
2007-12-01 00:00:00 +00:00
mmx : 1 ,
fxsr : 1 ,
sse : 1 ,
sse2 : 1 ,
: 1 ,
ht : 1 ,
: 3 ;
} bits ;
} ;
union DcpCpuid4Eax {
uint32_t value ;
struct {
uint32_t cache_type : 5 ,
: 21 ,
cores_per_cpu : 6 ;
} bits ;
} ;
union DcpCpuid4Ebx {
uint32_t value ;
struct {
uint32_t L1_line_size : 12 ,
partitions : 10 ,
associativity : 10 ;
} bits ;
} ;
2010-06-29 10:34:00 -07:00
union TplCpuidBEbx {
uint32_t value ;
struct {
uint32_t logical_cpus : 16 ,
: 16 ;
} bits ;
} ;
2007-12-01 00:00:00 +00:00
union ExtCpuid1Ecx {
uint32_t value ;
struct {
uint32_t LahfSahf : 1 ,
CmpLegacy : 1 ,
2014-03-12 11:24:26 -07:00
: 3 ,
lzcnt_intel : 1 ,
2009-05-06 00:27:52 -07:00
lzcnt : 1 ,
2007-12-01 00:00:00 +00:00
sse4a : 1 ,
misalignsse : 1 ,
prefetchw : 1 ,
: 22 ;
} bits ;
} ;
2009-02-23 12:02:30 -08:00
union ExtCpuid1Edx {
uint32_t value ;
struct {
uint32_t : 22 ,
mmx_amd : 1 ,
mmx : 1 ,
fxsr : 1 ,
: 4 ,
long_mode : 1 ,
tdnow2 : 1 ,
tdnow : 1 ;
} bits ;
} ;
2007-12-01 00:00:00 +00:00
union ExtCpuid5Ex {
uint32_t value ;
struct {
uint32_t L1_line_size : 8 ,
L1_tag_lines : 8 ,
L1_assoc : 8 ,
L1_size : 8 ;
} bits ;
} ;
2012-01-06 20:09:20 -08:00
union ExtCpuid7Edx {
uint32_t value ;
struct {
uint32_t : 8 ,
tsc_invariance : 1 ,
: 23 ;
} bits ;
} ;
2007-12-01 00:00:00 +00:00
union ExtCpuid8Ecx {
uint32_t value ;
struct {
uint32_t cores_per_cpu : 8 ,
: 24 ;
} bits ;
} ;
2011-12-14 14:54:38 -08:00
union SefCpuid7Eax {
uint32_t value ;
} ;
union SefCpuid7Ebx {
2012-01-01 11:17:59 -05:00
uint32_t value ;
struct {
2011-12-14 14:54:38 -08:00
uint32_t fsgsbase : 1 ,
: 2 ,
bmi1 : 1 ,
: 1 ,
avx2 : 1 ,
: 2 ,
bmi2 : 1 ,
2013-01-03 15:09:55 -08:00
erms : 1 ,
2014-03-20 17:49:27 -07:00
: 1 ,
2015-05-08 11:49:20 -07:00
rtm : 1 ,
: 4 ,
avx512f : 1 ,
avx512dq : 1 ,
: 1 ,
adx : 1 ,
: 6 ,
avx512pf : 1 ,
avx512er : 1 ,
avx512cd : 1 ,
2016-03-03 22:02:13 -08:00
sha : 1 ,
2015-05-08 11:49:20 -07:00
avx512bw : 1 ,
avx512vl : 1 ;
2011-12-14 14:54:38 -08:00
} bits ;
} ;
union XemXcr0Eax {
uint32_t value ;
struct {
2015-09-11 17:02:44 -07:00
uint32_t x87 : 1 ,
sse : 1 ,
ymm : 1 ,
bndregs : 1 ,
bndcsr : 1 ,
opmask : 1 ,
zmm512 : 1 ,
zmm32 : 1 ,
: 24 ;
2012-01-01 11:17:59 -05:00
} bits ;
} ;
2007-12-01 00:00:00 +00:00
protected :
2012-01-01 11:17:59 -05:00
static int _cpu ;
static int _model ;
static int _stepping ;
2014-03-14 17:28:58 -07:00
static address _cpuinfo_segv_addr ; // address of instruction which causes SEGV
static address _cpuinfo_cont_addr ; // address of instruction after the one which causes SEGV
2015-12-23 20:19:42 -10:00
enum Feature_Flag {
2015-05-08 11:49:20 -07:00
CPU_CX8 = ( 1 < < 0 ) , // next bits are from cpuid 1 (EDX)
CPU_CMOV = ( 1 < < 1 ) ,
CPU_FXSR = ( 1 < < 2 ) ,
CPU_HT = ( 1 < < 3 ) ,
CPU_MMX = ( 1 < < 4 ) ,
CPU_3DNOW_PREFETCH = ( 1 < < 5 ) , // Processor supports 3dnow prefetch and prefetchw instructions
// may not necessarily support other 3dnow instructions
CPU_SSE = ( 1 < < 6 ) ,
CPU_SSE2 = ( 1 < < 7 ) ,
CPU_SSE3 = ( 1 < < 8 ) , // SSE3 comes from cpuid 1 (ECX)
CPU_SSSE3 = ( 1 < < 9 ) ,
CPU_SSE4A = ( 1 < < 10 ) ,
CPU_SSE4_1 = ( 1 < < 11 ) ,
CPU_SSE4_2 = ( 1 < < 12 ) ,
CPU_POPCNT = ( 1 < < 13 ) ,
CPU_LZCNT = ( 1 < < 14 ) ,
CPU_TSC = ( 1 < < 15 ) ,
CPU_TSCINV = ( 1 < < 16 ) ,
CPU_AVX = ( 1 < < 17 ) ,
CPU_AVX2 = ( 1 < < 18 ) ,
CPU_AES = ( 1 < < 19 ) ,
CPU_ERMS = ( 1 < < 20 ) , // enhanced 'rep movsb/stosb' instructions
CPU_CLMUL = ( 1 < < 21 ) , // carryless multiply for CRC
CPU_BMI1 = ( 1 < < 22 ) ,
CPU_BMI2 = ( 1 < < 23 ) ,
CPU_RTM = ( 1 < < 24 ) , // Restricted Transactional Memory instructions
CPU_ADX = ( 1 < < 25 ) ,
CPU_AVX512F = ( 1 < < 26 ) , // AVX 512bit foundation instructions
CPU_AVX512DQ = ( 1 < < 27 ) ,
CPU_AVX512PF = ( 1 < < 28 ) ,
CPU_AVX512ER = ( 1 < < 29 ) ,
2016-03-03 22:02:13 -08:00
CPU_AVX512CD = ( 1 < < 30 )
// Keeping sign bit 31 unassigned.
2015-12-23 20:19:42 -10:00
} ;
2012-01-01 11:17:59 -05:00
2016-03-03 22:02:13 -08:00
# define CPU_AVX512BW ((uint64_t)UCONST64(0x100000000)) // enums are limited to 31 bit
# define CPU_AVX512VL ((uint64_t)UCONST64(0x200000000)) // EVEX instructions with smaller vector length
# define CPU_SHA ((uint64_t)UCONST64(0x400000000)) // SHA instructions
2016-08-26 12:17:50 -07:00
# define CPU_FMA ((uint64_t)UCONST64(0x800000000)) // FMA instructions
2017-05-05 19:28:54 -07:00
# define CPU_VZEROUPPER ((uint64_t)UCONST64(0x1000000000)) // Vzeroupper instruction
2015-05-08 11:49:20 -07:00
2015-12-23 20:19:42 -10:00
enum Extended_Family {
2012-01-01 11:17:59 -05:00
// AMD
2012-02-16 13:50:54 -05:00
CPU_FAMILY_AMD_11H = 0x11 ,
2012-01-01 11:17:59 -05:00
// Intel
CPU_FAMILY_INTEL_CORE = 6 ,
2012-02-16 13:50:54 -05:00
CPU_MODEL_NEHALEM = 0x1e ,
CPU_MODEL_NEHALEM_EP = 0x1a ,
CPU_MODEL_NEHALEM_EX = 0x2e ,
CPU_MODEL_WESTMERE = 0x25 ,
CPU_MODEL_WESTMERE_EP = 0x2c ,
CPU_MODEL_WESTMERE_EX = 0x2f ,
CPU_MODEL_SANDYBRIDGE = 0x2a ,
CPU_MODEL_SANDYBRIDGE_EP = 0x2d ,
2014-08-22 12:03:49 -07:00
CPU_MODEL_IVYBRIDGE_EP = 0x3a ,
CPU_MODEL_HASWELL_E3 = 0x3c ,
CPU_MODEL_HASWELL_E7 = 0x3f ,
2015-05-08 11:49:20 -07:00
CPU_MODEL_BROADWELL = 0x3d ,
CPU_MODEL_SKYLAKE = CPU_MODEL_HASWELL_E3
2015-12-23 20:19:42 -10:00
} ;
2007-12-01 00:00:00 +00:00
// cpuid information block. All info derived from executing cpuid with
// various function numbers is stored here. Intel and AMD info is
// merged in this block: accessor methods disentangle it.
//
// The info block is laid out in subblocks of 4 dwords corresponding to
// eax, ebx, ecx and edx, whether or not they contain anything useful.
struct CpuidInfo {
// cpuid function 0
uint32_t std_max_function ;
uint32_t std_vendor_name_0 ;
uint32_t std_vendor_name_1 ;
uint32_t std_vendor_name_2 ;
// cpuid function 1
StdCpuid1Eax std_cpuid1_eax ;
StdCpuid1Ebx std_cpuid1_ebx ;
StdCpuid1Ecx std_cpuid1_ecx ;
StdCpuid1Edx std_cpuid1_edx ;
// cpuid function 4 (deterministic cache parameters)
DcpCpuid4Eax dcp_cpuid4_eax ;
DcpCpuid4Ebx dcp_cpuid4_ebx ;
uint32_t dcp_cpuid4_ecx ; // unused currently
uint32_t dcp_cpuid4_edx ; // unused currently
2011-12-14 14:54:38 -08:00
// cpuid function 7 (structured extended features)
SefCpuid7Eax sef_cpuid7_eax ;
SefCpuid7Ebx sef_cpuid7_ebx ;
uint32_t sef_cpuid7_ecx ; // unused currently
uint32_t sef_cpuid7_edx ; // unused currently
2010-06-29 10:34:00 -07:00
// cpuid function 0xB (processor topology)
// ecx = 0
uint32_t tpl_cpuidB0_eax ;
TplCpuidBEbx tpl_cpuidB0_ebx ;
uint32_t tpl_cpuidB0_ecx ; // unused currently
uint32_t tpl_cpuidB0_edx ; // unused currently
// ecx = 1
uint32_t tpl_cpuidB1_eax ;
TplCpuidBEbx tpl_cpuidB1_ebx ;
uint32_t tpl_cpuidB1_ecx ; // unused currently
uint32_t tpl_cpuidB1_edx ; // unused currently
// ecx = 2
uint32_t tpl_cpuidB2_eax ;
TplCpuidBEbx tpl_cpuidB2_ebx ;
uint32_t tpl_cpuidB2_ecx ; // unused currently
uint32_t tpl_cpuidB2_edx ; // unused currently
2007-12-01 00:00:00 +00:00
// cpuid function 0x80000000 // example, unused
uint32_t ext_max_function ;
uint32_t ext_vendor_name_0 ;
uint32_t ext_vendor_name_1 ;
uint32_t ext_vendor_name_2 ;
// cpuid function 0x80000001
uint32_t ext_cpuid1_eax ; // reserved
uint32_t ext_cpuid1_ebx ; // reserved
ExtCpuid1Ecx ext_cpuid1_ecx ;
ExtCpuid1Edx ext_cpuid1_edx ;
// cpuid functions 0x80000002 thru 0x80000004: example, unused
uint32_t proc_name_0 , proc_name_1 , proc_name_2 , proc_name_3 ;
uint32_t proc_name_4 , proc_name_5 , proc_name_6 , proc_name_7 ;
uint32_t proc_name_8 , proc_name_9 , proc_name_10 , proc_name_11 ;
2012-02-16 13:50:54 -05:00
// cpuid function 0x80000005 // AMD L1, Intel reserved
2007-12-01 00:00:00 +00:00
uint32_t ext_cpuid5_eax ; // unused currently
uint32_t ext_cpuid5_ebx ; // reserved
ExtCpuid5Ex ext_cpuid5_ecx ; // L1 data cache info (AMD)
ExtCpuid5Ex ext_cpuid5_edx ; // L1 instruction cache info (AMD)
2012-01-01 11:17:59 -05:00
// cpuid function 0x80000007
uint32_t ext_cpuid7_eax ; // reserved
uint32_t ext_cpuid7_ebx ; // reserved
uint32_t ext_cpuid7_ecx ; // reserved
ExtCpuid7Edx ext_cpuid7_edx ; // tscinv
2007-12-01 00:00:00 +00:00
// cpuid function 0x80000008
uint32_t ext_cpuid8_eax ; // unused currently
uint32_t ext_cpuid8_ebx ; // reserved
ExtCpuid8Ecx ext_cpuid8_ecx ;
uint32_t ext_cpuid8_edx ; // reserved
2011-12-14 14:54:38 -08:00
// extended control register XCR0 (the XFEATURE_ENABLED_MASK register)
XemXcr0Eax xem_xcr0_eax ;
uint32_t xem_xcr0_edx ; // reserved
2014-03-14 17:28:58 -07:00
// Space to save ymm registers after signal handle
int ymm_save [ 8 * 4 ] ; // Save ymm0, ymm7, ymm8, ymm15
2015-05-08 11:49:20 -07:00
// Space to save zmm registers after signal handle
int zmm_save [ 16 * 4 ] ; // Save zmm0, zmm7, zmm8, zmm31
2007-12-01 00:00:00 +00:00
} ;
// The actual cpuid info block
static CpuidInfo _cpuid_info ;
// Extractors and predicates
static uint32_t extended_cpu_family ( ) {
uint32_t result = _cpuid_info . std_cpuid1_eax . bits . family ;
2008-10-14 15:10:26 -07:00
result + = _cpuid_info . std_cpuid1_eax . bits . ext_family ;
2007-12-01 00:00:00 +00:00
return result ;
}
2012-01-01 11:17:59 -05:00
2007-12-01 00:00:00 +00:00
static uint32_t extended_cpu_model ( ) {
uint32_t result = _cpuid_info . std_cpuid1_eax . bits . model ;
2008-10-14 15:10:26 -07:00
result | = _cpuid_info . std_cpuid1_eax . bits . ext_model < < 4 ;
2007-12-01 00:00:00 +00:00
return result ;
}
2012-01-01 11:17:59 -05:00
2007-12-01 00:00:00 +00:00
static uint32_t cpu_stepping ( ) {
uint32_t result = _cpuid_info . std_cpuid1_eax . bits . stepping ;
return result ;
}
2012-01-01 11:17:59 -05:00
2007-12-01 00:00:00 +00:00
static uint logical_processor_count ( ) {
uint result = threads_per_core ( ) ;
return result ;
}
2012-01-01 11:17:59 -05:00
2015-05-08 11:49:20 -07:00
static uint64_t feature_flags ( ) {
uint64_t result = 0 ;
2007-12-01 00:00:00 +00:00
if ( _cpuid_info . std_cpuid1_edx . bits . cmpxchg8 ! = 0 )
result | = CPU_CX8 ;
if ( _cpuid_info . std_cpuid1_edx . bits . cmov ! = 0 )
result | = CPU_CMOV ;
2010-09-09 05:24:11 -07:00
if ( _cpuid_info . std_cpuid1_edx . bits . fxsr ! = 0 | | ( is_amd ( ) & &
_cpuid_info . ext_cpuid1_edx . bits . fxsr ! = 0 ) )
2007-12-01 00:00:00 +00:00
result | = CPU_FXSR ;
// HT flag is set for multi-core processors also.
if ( threads_per_core ( ) > 1 )
result | = CPU_HT ;
2010-09-09 05:24:11 -07:00
if ( _cpuid_info . std_cpuid1_edx . bits . mmx ! = 0 | | ( is_amd ( ) & &
_cpuid_info . ext_cpuid1_edx . bits . mmx ! = 0 ) )
2007-12-01 00:00:00 +00:00
result | = CPU_MMX ;
if ( _cpuid_info . std_cpuid1_edx . bits . sse ! = 0 )
result | = CPU_SSE ;
if ( _cpuid_info . std_cpuid1_edx . bits . sse2 ! = 0 )
result | = CPU_SSE2 ;
if ( _cpuid_info . std_cpuid1_ecx . bits . sse3 ! = 0 )
result | = CPU_SSE3 ;
if ( _cpuid_info . std_cpuid1_ecx . bits . ssse3 ! = 0 )
result | = CPU_SSSE3 ;
2008-10-14 15:10:26 -07:00
if ( _cpuid_info . std_cpuid1_ecx . bits . sse4_1 ! = 0 )
result | = CPU_SSE4_1 ;
if ( _cpuid_info . std_cpuid1_ecx . bits . sse4_2 ! = 0 )
result | = CPU_SSE4_2 ;
2009-03-13 11:35:17 -07:00
if ( _cpuid_info . std_cpuid1_ecx . bits . popcnt ! = 0 )
result | = CPU_POPCNT ;
2011-12-14 14:54:38 -08:00
if ( _cpuid_info . std_cpuid1_ecx . bits . avx ! = 0 & &
_cpuid_info . std_cpuid1_ecx . bits . osxsave ! = 0 & &
_cpuid_info . xem_xcr0_eax . bits . sse ! = 0 & &
_cpuid_info . xem_xcr0_eax . bits . ymm ! = 0 ) {
result | = CPU_AVX ;
2017-05-05 19:28:54 -07:00
result | = CPU_VZEROUPPER ;
2011-12-14 14:54:38 -08:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx2 ! = 0 )
result | = CPU_AVX2 ;
2015-05-08 11:49:20 -07:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx512f ! = 0 & &
_cpuid_info . xem_xcr0_eax . bits . opmask ! = 0 & &
_cpuid_info . xem_xcr0_eax . bits . zmm512 ! = 0 & &
_cpuid_info . xem_xcr0_eax . bits . zmm32 ! = 0 ) {
result | = CPU_AVX512F ;
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx512cd ! = 0 )
result | = CPU_AVX512CD ;
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx512dq ! = 0 )
result | = CPU_AVX512DQ ;
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx512pf ! = 0 )
result | = CPU_AVX512PF ;
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx512er ! = 0 )
result | = CPU_AVX512ER ;
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx512bw ! = 0 )
result | = CPU_AVX512BW ;
if ( _cpuid_info . sef_cpuid7_ebx . bits . avx512vl ! = 0 )
result | = CPU_AVX512VL ;
}
2011-12-14 14:54:38 -08:00
}
2014-03-12 11:24:26 -07:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . bmi1 ! = 0 )
result | = CPU_BMI1 ;
2012-01-01 11:17:59 -05:00
if ( _cpuid_info . std_cpuid1_edx . bits . tsc ! = 0 )
result | = CPU_TSC ;
if ( _cpuid_info . ext_cpuid7_edx . bits . tsc_invariance ! = 0 )
result | = CPU_TSCINV ;
2012-10-24 14:33:22 -07:00
if ( _cpuid_info . std_cpuid1_ecx . bits . aes ! = 0 )
result | = CPU_AES ;
2013-01-03 15:09:55 -08:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . erms ! = 0 )
result | = CPU_ERMS ;
2013-07-02 20:42:12 -04:00
if ( _cpuid_info . std_cpuid1_ecx . bits . clmul ! = 0 )
result | = CPU_CLMUL ;
2014-03-20 17:49:27 -07:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . rtm ! = 0 )
result | = CPU_RTM ;
2009-05-06 00:27:52 -07:00
// AMD features.
if ( is_amd ( ) ) {
2011-04-11 15:30:31 -07:00
if ( ( _cpuid_info . ext_cpuid1_edx . bits . tdnow ! = 0 ) | |
( _cpuid_info . ext_cpuid1_ecx . bits . prefetchw ! = 0 ) )
result | = CPU_3DNOW_PREFETCH ;
2009-05-06 00:27:52 -07:00
if ( _cpuid_info . ext_cpuid1_ecx . bits . lzcnt ! = 0 )
result | = CPU_LZCNT ;
if ( _cpuid_info . ext_cpuid1_ecx . bits . sse4a ! = 0 )
result | = CPU_SSE4A ;
}
2014-03-12 11:24:26 -07:00
// Intel features.
if ( is_intel ( ) ) {
2014-09-02 12:48:45 -07:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . adx ! = 0 )
result | = CPU_ADX ;
2014-03-12 11:24:26 -07:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . bmi2 ! = 0 )
result | = CPU_BMI2 ;
2016-03-03 22:02:13 -08:00
if ( _cpuid_info . sef_cpuid7_ebx . bits . sha ! = 0 )
result | = CPU_SHA ;
2014-03-12 11:24:26 -07:00
if ( _cpuid_info . ext_cpuid1_ecx . bits . lzcnt_intel ! = 0 )
result | = CPU_LZCNT ;
2016-08-26 12:17:50 -07:00
if ( _cpuid_info . std_cpuid1_ecx . bits . fma ! = 0 )
result | = CPU_FMA ;
2014-09-02 12:48:45 -07:00
// for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw
if ( _cpuid_info . ext_cpuid1_ecx . bits . misalignsse ! = 0 ) {
result | = CPU_3DNOW_PREFETCH ;
}
2014-03-12 11:24:26 -07:00
}
2009-05-06 00:27:52 -07:00
2007-12-01 00:00:00 +00:00
return result ;
}
2014-03-14 17:28:58 -07:00
static bool os_supports_avx_vectors ( ) {
2015-05-08 11:49:20 -07:00
bool retVal = false ;
if ( supports_evex ( ) ) {
// Verify that OS save/restore all bits of EVEX registers
// during signal processing.
int nreg = 2 LP64_ONLY ( + 2 ) ;
retVal = true ;
for ( int i = 0 ; i < 16 * nreg ; i + + ) { // 64 bytes per zmm register
if ( _cpuid_info . zmm_save [ i ] ! = ymm_test_value ( ) ) {
retVal = false ;
break ;
}
}
} else if ( supports_avx ( ) ) {
// Verify that OS save/restore all bits of AVX registers
// during signal processing.
int nreg = 2 LP64_ONLY ( + 2 ) ;
retVal = true ;
for ( int i = 0 ; i < 8 * nreg ; i + + ) { // 32 bytes per ymm register
if ( _cpuid_info . ymm_save [ i ] ! = ymm_test_value ( ) ) {
retVal = false ;
break ;
}
2014-03-14 17:28:58 -07:00
}
2015-11-09 11:26:41 -08:00
// zmm_save will be set on a EVEX enabled machine even if we choose AVX code gen
if ( retVal = = false ) {
// Verify that OS save/restore all bits of EVEX registers
// during signal processing.
int nreg = 2 LP64_ONLY ( + 2 ) ;
retVal = true ;
for ( int i = 0 ; i < 16 * nreg ; i + + ) { // 64 bytes per zmm register
if ( _cpuid_info . zmm_save [ i ] ! = ymm_test_value ( ) ) {
retVal = false ;
break ;
}
}
}
2014-03-14 17:28:58 -07:00
}
2015-05-08 11:49:20 -07:00
return retVal ;
2014-03-14 17:28:58 -07:00
}
2007-12-01 00:00:00 +00:00
static void get_processor_features ( ) ;
public :
// Offsets for cpuid asm stub
static ByteSize std_cpuid0_offset ( ) { return byte_offset_of ( CpuidInfo , std_max_function ) ; }
static ByteSize std_cpuid1_offset ( ) { return byte_offset_of ( CpuidInfo , std_cpuid1_eax ) ; }
static ByteSize dcp_cpuid4_offset ( ) { return byte_offset_of ( CpuidInfo , dcp_cpuid4_eax ) ; }
2011-12-14 14:54:38 -08:00
static ByteSize sef_cpuid7_offset ( ) { return byte_offset_of ( CpuidInfo , sef_cpuid7_eax ) ; }
2007-12-01 00:00:00 +00:00
static ByteSize ext_cpuid1_offset ( ) { return byte_offset_of ( CpuidInfo , ext_cpuid1_eax ) ; }
static ByteSize ext_cpuid5_offset ( ) { return byte_offset_of ( CpuidInfo , ext_cpuid5_eax ) ; }
2012-01-01 11:17:59 -05:00
static ByteSize ext_cpuid7_offset ( ) { return byte_offset_of ( CpuidInfo , ext_cpuid7_eax ) ; }
2007-12-01 00:00:00 +00:00
static ByteSize ext_cpuid8_offset ( ) { return byte_offset_of ( CpuidInfo , ext_cpuid8_eax ) ; }
2010-06-29 10:34:00 -07:00
static ByteSize tpl_cpuidB0_offset ( ) { return byte_offset_of ( CpuidInfo , tpl_cpuidB0_eax ) ; }
static ByteSize tpl_cpuidB1_offset ( ) { return byte_offset_of ( CpuidInfo , tpl_cpuidB1_eax ) ; }
static ByteSize tpl_cpuidB2_offset ( ) { return byte_offset_of ( CpuidInfo , tpl_cpuidB2_eax ) ; }
2011-12-14 14:54:38 -08:00
static ByteSize xem_xcr0_offset ( ) { return byte_offset_of ( CpuidInfo , xem_xcr0_eax ) ; }
2014-03-14 17:28:58 -07:00
static ByteSize ymm_save_offset ( ) { return byte_offset_of ( CpuidInfo , ymm_save ) ; }
2015-05-08 11:49:20 -07:00
static ByteSize zmm_save_offset ( ) { return byte_offset_of ( CpuidInfo , zmm_save ) ; }
2014-03-14 17:28:58 -07:00
// The value used to check ymm register after signal handle
static int ymm_test_value ( ) { return 0xCAFEBABE ; }
2014-03-31 13:08:03 -07:00
static void get_cpu_info_wrapper ( ) ;
2014-03-14 17:28:58 -07:00
static void set_cpuinfo_segv_addr ( address pc ) { _cpuinfo_segv_addr = pc ; }
static bool is_cpuinfo_segv_addr ( address pc ) { return _cpuinfo_segv_addr = = pc ; }
static void set_cpuinfo_cont_addr ( address pc ) { _cpuinfo_cont_addr = pc ; }
static address cpuinfo_cont_addr ( ) { return _cpuinfo_cont_addr ; }
2015-12-23 20:19:42 -10:00
static void clean_cpuFeatures ( ) { _features = 0 ; }
2017-05-05 19:28:54 -07:00
static void set_avx_cpuFeatures ( ) { _features = ( CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ) ; }
static void set_evex_cpuFeatures ( ) { _features = ( CPU_AVX512F | CPU_SSE | CPU_SSE2 | CPU_VZEROUPPER ) ; }
2014-03-14 17:28:58 -07:00
2007-12-01 00:00:00 +00:00
// Initialization
static void initialize ( ) ;
2014-03-20 17:49:27 -07:00
// Override Abstract_VM_Version implementation
static bool use_biased_locking ( ) ;
2007-12-01 00:00:00 +00:00
// Asserts
static void assert_is_initialized ( ) {
assert ( _cpuid_info . std_cpuid1_eax . bits . family ! = 0 , " VM_Version not initialized " ) ;
}
//
// Processor family:
// 3 - 386
// 4 - 486
// 5 - Pentium
// 6 - PentiumPro, Pentium II, Celeron, Xeon, Pentium III, Athlon,
// Pentium M, Core Solo, Core Duo, Core2 Duo
// family 6 model: 9, 13, 14, 15
// 0x0f - Pentium 4, Opteron
//
// Note: The cpu family should be used to select between
// instruction sequences which are valid on all Intel
// processors. Use the feature test functions below to
// determine whether a particular instruction is supported.
//
static int cpu_family ( ) { return _cpu ; }
static bool is_P6 ( ) { return cpu_family ( ) > = 6 ; }
static bool is_amd ( ) { assert_is_initialized ( ) ; return _cpuid_info . std_vendor_name_0 = = 0x68747541 ; } // 'htuA'
static bool is_intel ( ) { assert_is_initialized ( ) ; return _cpuid_info . std_vendor_name_0 = = 0x756e6547 ; } // 'uneG'
2017-06-23 15:16:23 -07:00
static bool is_atom_family ( ) { return ( ( cpu_family ( ) = = 0x06 ) & & ( ( extended_cpu_model ( ) = = 0x36 ) | | ( extended_cpu_model ( ) = = 0x37 ) | | ( extended_cpu_model ( ) = = 0x4D ) ) ) ; } //Silvermont and Centerton
static bool is_knights_family ( ) { return ( ( cpu_family ( ) = = 0x06 ) & & ( ( extended_cpu_model ( ) = = 0x57 ) | | ( extended_cpu_model ( ) = = 0x85 ) ) ) ; } // Xeon Phi 3200/5200/7200 and Future Xeon Phi
2007-12-01 00:00:00 +00:00
2010-07-14 14:29:14 -07:00
static bool supports_processor_topology ( ) {
return ( _cpuid_info . std_max_function > = 0xB ) & &
// eax[4:0] | ebx[0:15] == 0 indicates invalid topology level.
// Some cpus have max cpuid >= 0xB but do not support processor topology.
2013-01-03 15:09:55 -08:00
( ( ( _cpuid_info . tpl_cpuidB0_eax & 0x1f ) | _cpuid_info . tpl_cpuidB0_ebx . bits . logical_cpus ) ! = 0 ) ;
2010-07-14 14:29:14 -07:00
}
2007-12-01 00:00:00 +00:00
static uint cores_per_cpu ( ) {
uint result = 1 ;
if ( is_intel ( ) ) {
2014-12-01 18:22:45 +04:00
bool supports_topology = supports_processor_topology ( ) ;
if ( supports_topology ) {
2010-06-29 10:34:00 -07:00
result = _cpuid_info . tpl_cpuidB1_ebx . bits . logical_cpus /
_cpuid_info . tpl_cpuidB0_ebx . bits . logical_cpus ;
2014-12-01 18:22:45 +04:00
}
if ( ! supports_topology | | result = = 0 ) {
2010-06-29 10:34:00 -07:00
result = ( _cpuid_info . dcp_cpuid4_eax . bits . cores_per_cpu + 1 ) ;
}
2007-12-01 00:00:00 +00:00
} else if ( is_amd ( ) ) {
result = ( _cpuid_info . ext_cpuid8_ecx . bits . cores_per_cpu + 1 ) ;
}
return result ;
}
static uint threads_per_core ( ) {
uint result = 1 ;
2010-07-14 14:29:14 -07:00
if ( is_intel ( ) & & supports_processor_topology ( ) ) {
2010-06-29 10:34:00 -07:00
result = _cpuid_info . tpl_cpuidB0_ebx . bits . logical_cpus ;
} else if ( _cpuid_info . std_cpuid1_edx . bits . ht ! = 0 ) {
2007-12-01 00:00:00 +00:00
result = _cpuid_info . std_cpuid1_ebx . bits . threads_per_cpu /
cores_per_cpu ( ) ;
}
2015-10-30 08:29:19 -07:00
return ( result = = 0 ? 1 : result ) ;
2007-12-01 00:00:00 +00:00
}
2014-07-15 07:33:49 -07:00
static intx L1_line_size ( ) {
2007-12-01 00:00:00 +00:00
intx result = 0 ;
if ( is_intel ( ) ) {
result = ( _cpuid_info . dcp_cpuid4_ebx . bits . L1_line_size + 1 ) ;
} else if ( is_amd ( ) ) {
result = _cpuid_info . ext_cpuid5_ecx . bits . L1_line_size ;
}
if ( result < 32 ) // not defined ?
2009-02-23 12:02:30 -08:00
result = 32 ; // 32 bytes by default on x86 and other x64
2007-12-01 00:00:00 +00:00
return result ;
}
2014-07-15 07:33:49 -07:00
static intx prefetch_data_size ( ) {
return L1_line_size ( ) ;
}
2007-12-01 00:00:00 +00:00
//
// Feature identification
//
2015-12-23 20:19:42 -10:00
static bool supports_cpuid ( ) { return _features ! = 0 ; }
static bool supports_cmpxchg8 ( ) { return ( _features & CPU_CX8 ) ! = 0 ; }
static bool supports_cmov ( ) { return ( _features & CPU_CMOV ) ! = 0 ; }
static bool supports_fxsr ( ) { return ( _features & CPU_FXSR ) ! = 0 ; }
static bool supports_ht ( ) { return ( _features & CPU_HT ) ! = 0 ; }
static bool supports_mmx ( ) { return ( _features & CPU_MMX ) ! = 0 ; }
static bool supports_sse ( ) { return ( _features & CPU_SSE ) ! = 0 ; }
static bool supports_sse2 ( ) { return ( _features & CPU_SSE2 ) ! = 0 ; }
static bool supports_sse3 ( ) { return ( _features & CPU_SSE3 ) ! = 0 ; }
static bool supports_ssse3 ( ) { return ( _features & CPU_SSSE3 ) ! = 0 ; }
static bool supports_sse4_1 ( ) { return ( _features & CPU_SSE4_1 ) ! = 0 ; }
static bool supports_sse4_2 ( ) { return ( _features & CPU_SSE4_2 ) ! = 0 ; }
static bool supports_popcnt ( ) { return ( _features & CPU_POPCNT ) ! = 0 ; }
static bool supports_avx ( ) { return ( _features & CPU_AVX ) ! = 0 ; }
static bool supports_avx2 ( ) { return ( _features & CPU_AVX2 ) ! = 0 ; }
static bool supports_tsc ( ) { return ( _features & CPU_TSC ) ! = 0 ; }
static bool supports_aes ( ) { return ( _features & CPU_AES ) ! = 0 ; }
static bool supports_erms ( ) { return ( _features & CPU_ERMS ) ! = 0 ; }
static bool supports_clmul ( ) { return ( _features & CPU_CLMUL ) ! = 0 ; }
static bool supports_rtm ( ) { return ( _features & CPU_RTM ) ! = 0 ; }
static bool supports_bmi1 ( ) { return ( _features & CPU_BMI1 ) ! = 0 ; }
static bool supports_bmi2 ( ) { return ( _features & CPU_BMI2 ) ! = 0 ; }
static bool supports_adx ( ) { return ( _features & CPU_ADX ) ! = 0 ; }
static bool supports_evex ( ) { return ( _features & CPU_AVX512F ) ! = 0 ; }
static bool supports_avx512dq ( ) { return ( _features & CPU_AVX512DQ ) ! = 0 ; }
static bool supports_avx512pf ( ) { return ( _features & CPU_AVX512PF ) ! = 0 ; }
static bool supports_avx512er ( ) { return ( _features & CPU_AVX512ER ) ! = 0 ; }
static bool supports_avx512cd ( ) { return ( _features & CPU_AVX512CD ) ! = 0 ; }
static bool supports_avx512bw ( ) { return ( _features & CPU_AVX512BW ) ! = 0 ; }
static bool supports_avx512vl ( ) { return ( _features & CPU_AVX512VL ) ! = 0 ; }
2015-06-23 12:45:08 -07:00
static bool supports_avx512vlbw ( ) { return ( supports_avx512bw ( ) & & supports_avx512vl ( ) ) ; }
2015-09-11 17:02:44 -07:00
static bool supports_avx512novl ( ) { return ( supports_evex ( ) & & ! supports_avx512vl ( ) ) ; }
2015-11-09 11:26:41 -08:00
static bool supports_avx512nobw ( ) { return ( supports_evex ( ) & & ! supports_avx512bw ( ) ) ; }
static bool supports_avx256only ( ) { return ( supports_avx2 ( ) & & ! supports_evex ( ) ) ; }
static bool supports_avxonly ( ) { return ( ( supports_avx2 ( ) | | supports_avx ( ) ) & & ! supports_evex ( ) ) ; }
2016-03-03 22:02:13 -08:00
static bool supports_sha ( ) { return ( _features & CPU_SHA ) ! = 0 ; }
2017-06-07 13:09:46 -07:00
static bool supports_fma ( ) { return ( _features & CPU_FMA ) ! = 0 & & supports_avx ( ) ; }
2017-05-05 19:28:54 -07:00
static bool supports_vzeroupper ( ) { return ( _features & CPU_VZEROUPPER ) ! = 0 ; }
2012-01-01 11:17:59 -05:00
// Intel features
static bool is_intel_family_core ( ) { return is_intel ( ) & &
extended_cpu_family ( ) = = CPU_FAMILY_INTEL_CORE ; }
static bool is_intel_tsc_synched_at_init ( ) {
if ( is_intel_family_core ( ) ) {
uint32_t ext_model = extended_cpu_model ( ) ;
2012-02-16 13:50:54 -05:00
if ( ext_model = = CPU_MODEL_NEHALEM_EP | |
ext_model = = CPU_MODEL_WESTMERE_EP | |
ext_model = = CPU_MODEL_SANDYBRIDGE_EP | |
ext_model = = CPU_MODEL_IVYBRIDGE_EP ) {
// <= 2-socket invariant tsc support. EX versions are usually used
// in > 2-socket systems and likely don't synchronize tscs at
// initialization.
// Code that uses tsc values must be prepared for them to arbitrarily
// jump forward or backward.
2012-01-01 11:17:59 -05:00
return true ;
}
}
return false ;
}
2007-12-01 00:00:00 +00:00
// AMD features
2015-12-23 20:19:42 -10:00
static bool supports_3dnow_prefetch ( ) { return ( _features & CPU_3DNOW_PREFETCH ) ! = 0 ; }
2007-12-01 00:00:00 +00:00
static bool supports_mmx_ext ( ) { return is_amd ( ) & & _cpuid_info . ext_cpuid1_edx . bits . mmx_amd ! = 0 ; }
2015-12-23 20:19:42 -10:00
static bool supports_lzcnt ( ) { return ( _features & CPU_LZCNT ) ! = 0 ; }
static bool supports_sse4a ( ) { return ( _features & CPU_SSE4A ) ! = 0 ; }
2007-12-01 00:00:00 +00:00
2012-01-01 11:17:59 -05:00
static bool is_amd_Barcelona ( ) { return is_amd ( ) & &
extended_cpu_family ( ) = = CPU_FAMILY_AMD_11H ; }
// Intel and AMD newer cores support fast timestamps well
static bool supports_tscinv_bit ( ) {
2015-12-23 20:19:42 -10:00
return ( _features & CPU_TSCINV ) ! = 0 ;
2012-01-01 11:17:59 -05:00
}
static bool supports_tscinv ( ) {
return supports_tscinv_bit ( ) & &
( ( is_amd ( ) & & ! is_amd_Barcelona ( ) ) | |
is_intel_tsc_synched_at_init ( ) ) ;
}
2010-11-02 09:00:37 -07:00
// Intel Core and newer cpus have fast IDIV instruction (excluding Atom).
static bool has_fast_idiv ( ) { return is_intel ( ) & & cpu_family ( ) = = 6 & &
supports_sse3 ( ) & & _model ! = 0x1C ; }
2007-12-01 00:00:00 +00:00
static bool supports_compare_and_exchange ( ) { return true ; }
2017-06-19 01:23:58 -07:00
static intx allocate_prefetch_distance ( bool use_watermark_prefetch ) {
2007-12-01 00:00:00 +00:00
// Hardware prefetching (distance/size in bytes):
2009-02-23 12:02:30 -08:00
// Pentium 3 - 64 / 32
2007-12-01 00:00:00 +00:00
// Pentium 4 - 256 / 128
2009-02-23 12:02:30 -08:00
// Athlon - 64 / 32 ????
2007-12-01 00:00:00 +00:00
// Opteron - 128 / 64 only when 2 sequential cache lines accessed
// Core - 128 / 64
//
// Software prefetching (distance in bytes / instruction with best score):
2009-02-23 12:02:30 -08:00
// Pentium 3 - 128 / prefetchnta
2007-12-01 00:00:00 +00:00
// Pentium 4 - 512 / prefetchnta
2009-02-23 12:02:30 -08:00
// Athlon - 128 / prefetchnta
2007-12-01 00:00:00 +00:00
// Opteron - 256 / prefetchnta
// Core - 256 / prefetchnta
// It will be used only when AllocatePrefetchStyle > 0
2017-06-19 01:23:58 -07:00
if ( is_amd ( ) ) { // AMD
if ( supports_sse2 ( ) ) {
return 256 ; // Opteron
} else {
return 128 ; // Athlon
}
} else { // Intel
if ( supports_sse3 ( ) & & cpu_family ( ) = = 6 ) {
if ( supports_sse4_2 ( ) & & supports_ht ( ) ) { // Nehalem based cpus
return 192 ;
} else if ( use_watermark_prefetch ) { // watermark prefetching on Core
# ifdef _LP64
return 384 ;
# else
return 320 ;
# endif
}
}
if ( supports_sse2 ( ) ) {
if ( cpu_family ( ) = = 6 ) {
return 256 ; // Pentium M, Core, Core2
} else {
return 512 ; // Pentium 4
}
} else {
return 128 ; // Pentium 3 (and all other old CPUs)
2007-12-01 00:00:00 +00:00
}
}
2015-09-11 17:02:44 -07:00
}
2016-03-30 17:04:14 +02:00
// SSE2 and later processors implement a 'pause' instruction
// that can be used for efficient implementation of
// the intrinsic for java.lang.Thread.onSpinWait()
static bool supports_on_spin_wait ( ) { return supports_sse2 ( ) ; }
2007-12-01 00:00:00 +00:00
} ;
2010-11-23 13:22:55 -08:00
# endif // CPU_X86_VM_VM_VERSION_X86_HPP