Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 160 additions & 66 deletions src/core/cpuid.d
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@
* Source: $(DRUNTIMESRC core/_cpuid.d)
*/

/* Copyright Don Clugston 2007 - 2009.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*/
module core.cpuid;

@trusted:
Expand Down Expand Up @@ -120,113 +115,101 @@ public:
// Note: When we deprecate it, we simply make it private.
__gshared CacheInfo[5] datacache;

@property {
@property pure
{
/// The data caches. If there are fewer than 5 physical caches levels,
/// the remaining levels are set to size_t.max (== entire memory space)
const(CacheInfo)[5] dataCaches() { return datacache; }
const(CacheInfo)[5] dataCaches() { return _dataCaches; }

/// Returns vendor string, for display purposes only.
/// Do NOT use this to determine features!
/// Note that some CPUs have programmable vendorIDs.
string vendor() {return cast(string)vendorID;}
string vendor() {return _vendor;}
/// Returns processor string, for display purposes only
string processor() {return processorName;}
string processor() {return _processor;}

/// Does it have an x87 FPU on-chip?
bool x87onChip() {return (features&FPU_BIT)!=0;}
bool x87onChip() {return _x87onChip;}
/// Is MMX supported?
bool mmx() {return (features&MMX_BIT)!=0;}
bool mmx() {return _mmx;}
/// Is SSE supported?
bool sse() {return (features&SSE_BIT)!=0;}
bool sse() {return _sse;}
/// Is SSE2 supported?
bool sse2() {return (features&SSE2_BIT)!=0;}
bool sse2() {return _sse2;}
/// Is SSE3 supported?
bool sse3() {return (miscfeatures&SSE3_BIT)!=0;}
bool sse3() {return _sse3;}
/// Is SSSE3 supported?
bool ssse3() {return (miscfeatures&SSSE3_BIT)!=0;}
bool ssse3() {return _ssse3;}
/// Is SSE4.1 supported?
bool sse41() {return (miscfeatures&SSE41_BIT)!=0;}
bool sse41() {return _sse41;}
/// Is SSE4.2 supported?
bool sse42() {return (miscfeatures&SSE42_BIT)!=0;}
bool sse42() {return _sse42;}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW - why not just make miscfeature immutable and leave functions as is? Is it broken cross-module inlining again? If it's the latter just make them templates...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just make miscfeature immutable and leave functions as is

Really good idea. You could make the storage a single immutable struct, then set the value from the shared static ctor based on calling some function.

/// Is SSE4a supported?
bool sse4a() {return (amdmiscfeatures&SSE4A_BIT)!=0;}
bool sse4a() {return _sse4a;}
/// Is AES supported
bool aes() {return (miscfeatures&AES_BIT)!=0;}
bool aes() {return _aes;}
/// Is pclmulqdq supported
bool hasPclmulqdq() {return (miscfeatures&PCLMULQDQ_BIT)!=0;}
bool hasPclmulqdq() {return _hasPclmulqdq;}
/// Is rdrand supported
bool hasRdrand() {return (miscfeatures&RDRAND_BIT)!=0;}
bool hasRdrand() {return _hasRdrand;}
/// Is AVX supported
bool avx()
{
enum mask = XF_SSE_BIT|XF_YMM_BIT;
return (xfeatures & mask) == mask && (miscfeatures&AVX_BIT)!=0;
}
bool avx() {return _avx;}
/// Is VEX-Encoded AES supported
bool vaes() {return avx && aes;}
bool vaes() {return _vaes;}
/// Is vpclmulqdq supported
bool hasVpclmulqdq(){return avx && hasPclmulqdq; }
bool hasVpclmulqdq(){return _hasVpclmulqdq; }
/// Is FMA supported
bool fma() {return avx && (miscfeatures&FMA_BIT)!=0;}
bool fma() {return _fma;}
/// Is FP16C supported
bool fp16c() {return avx && (miscfeatures&FP16C_BIT)!=0;}
bool fp16c() {return _fp16c;}
/// Is AVX2 supported
bool avx2() {return avx && (extfeatures & AVX2_BIT) != 0;}
bool avx2() {return _avx2;}
/// Is HLE (hardware lock elision) supported
bool hle() {return (extfeatures & HLE_BIT) != 0;}
bool hle() {return _hle;}
/// Is RTM (restricted transactional memory) supported
bool rtm() {return (extfeatures & RTM_BIT) != 0;}
bool rtm() {return _rtm;}
/// Is rdseed supported
bool hasRdseed() {return (extfeatures&RDSEED_BIT)!=0;}
bool hasRdseed() {return _hasRdseed;}
/// Is SHA supported
bool hasSha() {return (extfeatures&SHA_BIT)!=0;}
bool hasSha() {return _hasSha;}
/// Is AMD 3DNOW supported?
bool amd3dnow() {return (amdfeatures&AMD_3DNOW_BIT)!=0;}
bool amd3dnow() {return _amd3dnow;}
/// Is AMD 3DNOW Ext supported?
bool amd3dnowExt() {return (amdfeatures&AMD_3DNOW_EXT_BIT)!=0;}
bool amd3dnowExt() {return _amd3dnowExt;}
/// Are AMD extensions to MMX supported?
bool amdMmx() {return (amdfeatures&AMD_MMX_BIT)!=0;}
bool amdMmx() {return amdMmx;}
/// Is fxsave/fxrstor supported?
bool hasFxsr() {return (features&FXSR_BIT)!=0;}
bool hasFxsr() {return _hasFxsr;}
/// Is cmov supported?
bool hasCmov() {return (features&CMOV_BIT)!=0;}
bool hasCmov() {return _hasCmov;}
/// Is rdtsc supported?
bool hasRdtsc() {return (features&TIMESTAMP_BIT)!=0;}
bool hasRdtsc() {return _hasRdtsc;}
/// Is cmpxchg8b supported?
bool hasCmpxchg8b() {return (features&CMPXCHG8B_BIT)!=0;}
bool hasCmpxchg8b() {return _hasCmpxchg8b;}
/// Is cmpxchg8b supported?
bool hasCmpxchg16b() {return (miscfeatures&CMPXCHG16B_BIT)!=0;}
bool hasCmpxchg16b() {return _hasCmpxchg16b;}
/// Is SYSENTER/SYSEXIT supported?
bool hasSysEnterSysExit() {
// The SYSENTER/SYSEXIT features were buggy on Pentium Pro and early PentiumII.
// (REF: www.geoffchappell.com).
if (probablyIntel && (family < 6 || (family==6 && (model< 3 || (model==3 && stepping<3)))))
return false;
return (features & SYSENTERSYSEXIT_BIT)!=0;
}


bool hasSysEnterSysExit() {return _hasSysEnterSysExit;}
/// Is 3DNow prefetch supported?
bool has3dnowPrefetch()
{return (amdmiscfeatures&AMD_3DNOW_PREFETCH_BIT)!=0;}
bool has3dnowPrefetch() {return _has3dnowPrefetch;}
/// Are LAHF and SAHF supported in 64-bit mode?
bool hasLahfSahf() {return (amdmiscfeatures&LAHFSAHF_BIT)!=0;}
bool hasLahfSahf() {return _hasLahfSahf;}
/// Is POPCNT supported?
bool hasPopcnt() {return (miscfeatures&POPCNT_BIT)!=0;}
bool hasPopcnt() {return _hasPopcnt;}
/// Is LZCNT supported?
bool hasLzcnt() {return (amdmiscfeatures&LZCNT_BIT)!=0;}
bool hasLzcnt() {return _hasLzcnt;}
/// Is this an Intel64 or AMD 64?
bool isX86_64() {return (amdfeatures&AMD64_BIT)!=0;}
bool isX86_64() {return _isX86_64;}

/// Is this an IA64 (Itanium) processor?
bool isItanium() { return (features&IA64_BIT)!=0; }
bool isItanium() { return _isItanium; }

/// Is hyperthreading supported?
bool hyperThreading() { return maxThreads>maxCores; }
bool hyperThreading() { return _hyperThreading; }
/// Returns number of threads per CPU
uint threadsPerCPU() {return maxThreads;}
uint threadsPerCPU() {return _threadsPerCPU;}
/// Returns number of cores in CPU
uint coresPerCPU() {return maxCores;}
uint coresPerCPU() {return _coresPerCPU;}

/// Optimisation hints for assembly code.
///
Expand Down Expand Up @@ -254,12 +237,66 @@ public:
/// instruction set improvements occur within each dynasty.

/// Does this CPU perform better on AMD K7 code than PentiumPro..Core2 code?
bool preferAthlon() { return probablyAMD && family >=6; }
bool preferAthlon() { return _preferAthlon; }
/// Does this CPU perform better on Pentium4 code than PentiumPro..Core2 code?
bool preferPentium4() { return probablyIntel && family == 0xF; }
bool preferPentium4() { return _preferPentium4; }
/// Does this CPU perform better on Pentium I code than Pentium Pro code?
bool preferPentium1() { return family < 6 || (family==6 && model < 0xF && !probablyIntel); }
}
bool preferPentium1() { return _preferPentium1; }
}

private immutable
{
/* These exist as immutables so that the query property functions can
* be backwards compatible with code that called them with ().
* Also, immutables can only be set by the static this().
*/
const(CacheInfo)[5] _dataCaches;
string _vendor;
string _processor;
bool _x87onChip;
bool _mmx;
bool _sse;
bool _sse2;
bool _sse3;
bool _ssse3;
bool _sse41;
bool _sse42;
bool _sse4a;
bool _aes;
bool _hasPclmulqdq;
bool _hasRdrand;
bool _avx;
bool _vaes;
bool _hasVpclmulqdq;
bool _fma;
bool _fp16c;
bool _avx2;
bool _hle;
bool _rtm;
bool _hasRdseed;
bool _hasSha;
bool _amd3dnow;
bool _amd3dnowExt;
bool _amdMmx;
bool _hasFxsr;
bool _hasCmov;
bool _hasRdtsc;
bool _hasCmpxchg8b;
bool _hasCmpxchg16b;
bool _hasSysEnterSysExit;
bool _has3dnowPrefetch;
bool _hasLahfSahf;
bool _hasPopcnt;
bool _hasLzcnt;
bool _isX86_64;
bool _isItanium;
bool _hyperThreading;
uint _threadsPerCPU;
uint _coresPerCPU;
bool _preferAthlon;
bool _preferPentium4;
bool _preferPentium1;
}

__gshared:
// All these values are set only once, and never subsequently modified.
Expand Down Expand Up @@ -939,4 +976,61 @@ shared static this()
else
++numCacheLevels;
}

// Set the immortals

_dataCaches = datacache;
_vendor = cast(string)vendorID;
_processor = processorName;
_x87onChip = (features&FPU_BIT)!=0;
_mmx = (features&MMX_BIT)!=0;
_sse = (features&SSE_BIT)!=0;
_sse2 = (features&SSE2_BIT)!=0;
_sse3 = (miscfeatures&SSE3_BIT)!=0;
_ssse3 = (miscfeatures&SSSE3_BIT)!=0;
_sse41 = (miscfeatures&SSE41_BIT)!=0;
_sse42 = (miscfeatures&SSE42_BIT)!=0;
_sse4a = (amdmiscfeatures&SSE4A_BIT)!=0;
_aes = (miscfeatures&AES_BIT)!=0;
_hasPclmulqdq = (miscfeatures&PCLMULQDQ_BIT)!=0;
_hasRdrand = (miscfeatures&RDRAND_BIT)!=0;

enum avx_mask = XF_SSE_BIT|XF_YMM_BIT;
_avx = (xfeatures & avx_mask) == avx_mask && (miscfeatures&AVX_BIT)!=0;

_vaes = avx && aes;
_hasVpclmulqdq = avx && hasPclmulqdq;
_fma = avx && (miscfeatures&FMA_BIT)!=0;
_fp16c = avx && (miscfeatures&FP16C_BIT)!=0;
_avx2 = avx && (extfeatures & AVX2_BIT) != 0;
_hle = (extfeatures & HLE_BIT) != 0;
_rtm = (extfeatures & RTM_BIT) != 0;
_hasRdseed = (extfeatures&RDSEED_BIT)!=0;
_hasSha = (extfeatures&SHA_BIT)!=0;
_amd3dnow = (amdfeatures&AMD_3DNOW_BIT)!=0;
_amd3dnowExt = (amdfeatures&AMD_3DNOW_EXT_BIT)!=0;
_amdMmx = (amdfeatures&AMD_MMX_BIT)!=0;
_hasFxsr = (features&FXSR_BIT)!=0;
_hasCmov = (features&CMOV_BIT)!=0;
_hasRdtsc = (features&TIMESTAMP_BIT)!=0;
_hasCmpxchg8b = (features&CMPXCHG8B_BIT)!=0;
_hasCmpxchg16b = (miscfeatures&CMPXCHG16B_BIT)!=0;
_hasSysEnterSysExit =
// The SYSENTER/SYSEXIT features were buggy on Pentium Pro and early PentiumII.
// (REF: www.geoffchappell.com).
(probablyIntel && (family < 6 || (family==6 && (model< 3 || (model==3 && stepping<3)))))
? false
: (features & SYSENTERSYSEXIT_BIT)!=0;
_has3dnowPrefetch = (amdmiscfeatures&AMD_3DNOW_PREFETCH_BIT)!=0;
_hasLahfSahf = (amdmiscfeatures&LAHFSAHF_BIT)!=0;
_hasPopcnt = (miscfeatures&POPCNT_BIT)!=0;
_hasLzcnt = (amdmiscfeatures&LZCNT_BIT)!=0;
_isX86_64 = (amdfeatures&AMD64_BIT)!=0;
_isItanium = (features&IA64_BIT)!=0;
_hyperThreading = maxThreads>maxCores;
_threadsPerCPU = maxThreads;
_coresPerCPU = maxCores;
_preferAthlon = probablyAMD && family >=6;
_preferPentium4 = probablyIntel && family == 0xF;
_preferPentium1 = family < 6 || (family==6 && model < 0xF && !probablyIntel);
}