Mercurial > projects > ldc
diff druntime/src/compiler/dmd/util/cpuid.d @ 759:d3eb054172f9
Added copy of druntime from DMD 2.020 modified for LDC.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:52:37 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/druntime/src/compiler/dmd/util/cpuid.d Tue Nov 11 01:52:37 2008 +0100 @@ -0,0 +1,464 @@ +/** + * Identify the characteristics of the host CPU. + * + * Implemented according to: + +- AP-485 Intel(C) Processor Identification and the CPUID Instruction + $(LINK http://www.intel.com/design/xeon/applnots/241618.htm) + +- Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 2A: Instruction Set Reference, A-M + $(LINK http://developer.intel.com/design/pentium4/manuals/index_new.htm) + +- AMD CPUID Specification Publication # 25481 + $(LINK http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf) + +Example: +--- +import std.cpuid; +import std.stdio; + +void main() +{ + writefln(std.cpuid.toString()); +} +--- + +AUTHORS: Tomas Lindquist Olsen <tomas@famolsen.dk> + (slightly altered by Walter Bright) +COPYRIGHT: Public Domain + + * BUGS: Only works on x86 CPUs + * + * Macros: + * WIKI = Phobos/StdCpuid + * COPYRIGHT = Public Domain + */ + +/* + * Modified by Sean Kelly for use with the D Runtime Project + */ + +module rt.util.cpuid; + +private import stdc.string; + +version(D_InlineAsm_X86) +{ + /// Returns vendor string + char[] vendor() {return vendorStr;} + /// Returns processor string + string processor() {return processorStr;} + + /// Is MMX supported? + bool mmx() {return (flags&MMX_BIT)!=0;} + /// Is FXSR supported? + bool fxsr() {return (flags&FXSR_BIT)!=0;} + /// Is SSE supported? + bool sse() {return (flags&SSE_BIT)!=0;} + /// Is SSE2 supported? + bool sse2() {return (flags&SSE2_BIT)!=0;} + /// Is SSE3 supported? + bool sse3() {return (misc&SSE3_BIT)!=0;} + /// Is SSSE3 supported? + bool ssse3() {return (misc&SSSE3_BIT)!=0;} + + /// Is AMD 3DNOW supported? + bool amd3dnow() {return (exflags&AMD_3DNOW_BIT)!=0;} + /// Is AMD 3DNOW Ext supported? + bool amd3dnowExt() {return (exflags&AMD_3DNOW_EXT_BIT)!=0;} + /// Is AMD MMX supported? + bool amdMmx() {return (exflags&AMD_MMX_BIT)!=0;} + + /// Is this an Intel Architecture IA64? + bool ia64() {return (flags&IA64_BIT)!=0;} + /// Is this an AMD 64? + bool amd64() {return (exflags&AMD64_BIT)!=0;} + + /// Is hyperthreading supported? + bool hyperThreading() {return (flags&HTT_BIT)!=0;} + /// Returns number of threads per CPU + uint threadsPerCPU() {return maxThreads;} + /// Returns number of cores in CPU + uint coresPerCPU() {return maxCores;} + + /// Is this an Intel processor? + bool intel() {return manufac==INTEL;} + /// Is this an AMD processor? + bool amd() {return manufac==AMD;} + + /// Returns stepping + uint stepping() {return _stepping;} + /// Returns model + uint model() {return _model;} + /// Returns family + uint family() {return _family;} + //uint processorType() {return (signature>>>12)&0x3;} + + static this() + { + getVendorString(); + getProcessorString(); + getFeatureFlags(); + + // stepping / family / model + _stepping = signature&0xF; + uint fbase = (signature>>>8)&0xF; + uint fex = (signature>>>20)&0xFF; + uint mbase = (signature>>>4)&0xF; + uint mex = (signature>>>16)&0xF; + + // vendor specific + void function() threadFn; + switch(vendorStr) + { + case "GenuineIntel": + manufac = INTEL; + threadFn = &getThreadingIntel; + if (fbase == 0xF) + _family = fbase+fex; + else + _family = fbase; + if (_family == 0x6 || _family == 0xF) + _model = mbase+(mex<<4); + else + _model = mbase; + break; + + case "AuthenticAMD": + manufac = AMD; + threadFn = &getThreadingAMD; + if (fbase < 0xF) + { + _family = fbase; + _model = mbase; + } + else + { + _family = fbase+fex; + _model = mbase+(mex<<4); + } + break; + + default: + manufac = OTHER; + } + + // threading details + if (hyperThreading && threadFn !is null) + { + threadFn(); + } + } + +private: + // feature flags + enum : uint + { + MMX_BIT = 1<<23, + FXSR_BIT = 1<<24, + SSE_BIT = 1<<25, + SSE2_BIT = 1<<26, + HTT_BIT = 1<<28, + IA64_BIT = 1<<30 + } + // feature flags misc + enum : uint + { + SSE3_BIT = 1, + SSSE3_BIT = 1<<9 + } + // extended feature flags + enum : uint + { + AMD_MMX_BIT = 1<<22, + AMD64_BIT = 1<<29, + AMD_3DNOW_EXT_BIT = 1<<30, + AMD_3DNOW_BIT = 1<<31 + } + // manufacturer + enum + { + OTHER, + INTEL, + AMD + } + + uint flags, misc, exflags, apic, signature; + uint _stepping, _model, _family; + + char[12] vendorStr = 0; + string processorStr = ""; + + uint maxThreads=1; + uint maxCores=1; + uint manufac=OTHER; + + /* ** + * fetches the cpu vendor string + */ + private void getVendorString() + { + char* dst = vendorStr.ptr; + // puts the vendor string into dst + asm + { + mov EAX, 0 ; + cpuid ; + mov EAX, dst ; + mov [EAX], EBX ; + mov [EAX+4], EDX ; + mov [EAX+8], ECX ; + } + } + + private void getProcessorString() + { + char[48] buffer; + char* dst = buffer.ptr; + // puts the processor string into dst + asm + { + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0004 ; + jb PSLabel ; // no support + push EDI ; + mov EDI, dst ; + mov EAX, 0x8000_0002 ; + cpuid ; + mov [EDI], EAX ; + mov [EDI+4], EBX ; + mov [EDI+8], ECX ; + mov [EDI+12], EDX ; + mov EAX, 0x8000_0003 ; + cpuid ; + mov [EDI+16], EAX ; + mov [EDI+20], EBX ; + mov [EDI+24], ECX ; + mov [EDI+28], EDX ; + mov EAX, 0x8000_0004 ; + cpuid ; + mov [EDI+32], EAX ; + mov [EDI+36], EBX ; + mov [EDI+40], ECX ; + mov [EDI+44], EDX ; + pop EDI ; + PSLabel: ; + } + + if (buffer[0] == char.init) // no support + return; + + // seems many intel processors prepend whitespace + processorStr = cast(string)strip(toString(dst)).dup; + } + + private void getFeatureFlags() + { + uint f,m,e,a,s; + asm + { + mov EAX, 0 ; + cpuid ; + cmp EAX, 1 ; + jb FeatLabel ; // no support + mov EAX, 1 ; + cpuid ; + mov f, EDX ; + mov m, ECX ; + mov a, EBX ; + mov s, EAX ; + + FeatLabel: ; + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0001 ; + jb FeatLabel2 ; // no support + mov EAX, 0x8000_0001 ; + cpuid ; + mov e, EDX ; + + FeatLabel2: + ; + } + flags = f; + misc = m; + exflags = e; + apic = a; + signature = s; + } + + private void getThreadingIntel() + { + uint n; + ubyte b = 0; + asm + { + mov EAX, 0 ; + cpuid ; + cmp EAX, 4 ; + jb IntelSingle ; + mov EAX, 4 ; + mov ECX, 0 ; + cpuid ; + mov n, EAX ; + mov b, 1 ; + IntelSingle: ; + } + if (b != 0) + { + maxCores = ((n>>>26)&0x3F)+1; + maxThreads = (apic>>>16)&0xFF; + } + else + { + maxCores = maxThreads = 1; + } + } + + private void getThreadingAMD() + { + ubyte n; + ubyte b = 0; + asm + { + mov EAX, 0x8000_0000 ; + cpuid ; + cmp EAX, 0x8000_0008 ; + jb AMDSingle ; + mov EAX, 0x8000_0008 ; + cpuid ; + mov n, CL ; + mov b, 1 ; + AMDSingle: ; + } + if (b != 0) + { + maxCores = n+1; + maxThreads = (apic>>>16)&0xFF; + } + else + { + maxCores = maxThreads = 1; + } + } + + /*************************************************************************** + * Support code for above, from std.string and std.ctype + ***************************************************************************/ + + private + { + enum + { + _SPC = 8, + _CTL = 0x20, + _BLK = 0x40, + _HEX = 0x80, + _UC = 1, + _LC = 2, + _PNC = 0x10, + _DIG = 4, + _ALP = _UC|_LC, + } + + ubyte _ctype[128] = + [ + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL, + _SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX, + _PNC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC, + _UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC, + _PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC, + _LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL + ]; + + /** + * Returns !=0 if c is a space, tab, vertical tab, form feed, + * carriage return, or linefeed. + */ + int isspace(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_SPC) : 0; } + + /***************************************** + * Strips leading or trailing whitespace, or both. + */ + char[] stripl(char[] s) + { + uint i; + + for (i = 0; i < s.length; i++) + { + if (!isspace(s[i])) + break; + } + return s[i .. s.length]; + } + + char[] stripr(char[] s) /// ditto + { + uint i; + + for (i = s.length; i > 0; i--) + { + if (!isspace(s[i - 1])) + break; + } + return s[0 .. i]; + } + + char[] strip(char[] s) /// ditto + { + return stripr(stripl(s)); + } + + char[] toString(char* s) + { + return s ? s[0 .. strlen(s)] : null; + } + + string toString(invariant(char)* s) + { + return s ? s[0 .. strlen(s)] : null; + } + } +} +else +{ + char[] vendor() {return "unknown vendor"; } + char[] processor() {return "unknown processor"; } + + bool mmx() {return false; } + bool fxsr() {return false; } + bool sse() {return false; } + bool sse2() {return false; } + bool sse3() {return false; } + bool ssse3() {return false; } + + bool amd3dnow() {return false; } + bool amd3dnowExt() {return false; } + bool amdMmx() {return false; } + + bool ia64() {return false; } + bool amd64() {return false; } + + bool hyperThreading() {return false; } + uint threadsPerCPU() {return 0; } + uint coresPerCPU() {return 0; } + + bool intel() {return false; } + bool amd() {return false; } + + uint stepping() {return 0; } + uint model() {return 0; } + uint family() {return 0; } +}