cpu.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Florian Klaempfl
  4. This unit contains some routines to get informations about the
  5. processor
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$IFNDEF FPC_DOTTEDUNITS}
  14. unit cpu;
  15. {$ENDIF FPC_DOTTEDUNITS}
  16. interface
  17. {$ifdef freebsd} // FreeBSD 7/8 have binutils version that don't support cmpxchg16b
  18. // Unless overridebinutils is defined (for ports usage), use db instead of the instruction
  19. {$ifndef overridebinutils}
  20. {$define oldbinutils}
  21. {$endif}
  22. {$endif}
  23. type
  24. TCpuidResult = record
  25. eax, ebx, ecx, edx: uint32;
  26. end;
  27. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult; inline;
  28. function CPUBrandString: shortstring;
  29. function InterlockedCompareExchange128Support : boolean;inline;
  30. function CMOVSupport : boolean;inline;
  31. function AESSupport : boolean;inline;
  32. function AVXSupport : boolean;inline;
  33. function AVX2Support: boolean;inline;
  34. function AVX512FSupport: boolean;inline;
  35. function AVX512DQSupport: boolean;inline;
  36. function AVX512IFMASupport: boolean;inline;
  37. function AVX512PFSupport: boolean;inline;
  38. function AVX512ERSupport: boolean;inline;
  39. function AVX512CDSupport: boolean;inline;
  40. function AVX512BWSupport: boolean;inline;
  41. function AVX512VLSupport: boolean;inline;
  42. function AVX512VBMISupport: boolean;inline;
  43. function AVX512VBMI2Support: boolean;inline;
  44. function AVX512VNNISupport: boolean;inline;
  45. function VAESSupport: boolean;inline;
  46. function VCLMULSupport: boolean;inline;
  47. function AVX512BITALGSupport: boolean;inline;
  48. function RDSEEDSupport: boolean;inline;
  49. function ADXSupport: boolean;inline;
  50. function SHASupport: boolean;inline;
  51. function FMASupport: boolean;inline;
  52. function CMPXCHG16BSupport: boolean;inline;
  53. function POPCNTSupport: boolean;inline;
  54. function LZCNTSupport: boolean;inline;
  55. function SSE3Support: boolean;inline;
  56. function SSSE3Support: boolean;inline;
  57. function SSE41Support: boolean;inline;
  58. function SSE42Support: boolean;inline;
  59. function MOVBESupport: boolean;inline;
  60. function F16CSupport: boolean;inline;
  61. function RDRANDSupport: boolean;inline;
  62. function RTMSupport: boolean;inline;
  63. function BMI1Support: boolean;inline;
  64. function BMI2Support: boolean;inline;
  65. var
  66. is_sse3_cpu : boolean = false;
  67. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  68. implementation
  69. {$asmmode att}
  70. var
  71. data: record
  72. cpuid1, cpuid7: TCpuidResult;
  73. AVXSupport,
  74. LZCNTSupport: boolean;
  75. end;
  76. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  77. // ^ I don't know how 16-byte result is handled in SysV, if it is returned in RDX:RAX as GCC does things become complex,
  78. // that's why this internal version with "out res" exists...
  79. // Win64: ecx = in_eax, edx = in_ecx, r8 = res.
  80. // SysV: edi = in_eax, esi = in_ecx, rdx = res.
  81. asm
  82. push %rbx
  83. {$ifndef win64}
  84. mov %rdx, %r8 // r8 = res
  85. {$endif}
  86. mov in_eax, %eax
  87. mov in_ecx, %ecx
  88. cpuid
  89. mov %eax, TCpuidResult.eax(%r8)
  90. mov %ebx, TCpuidResult.ebx(%r8)
  91. mov %ecx, TCpuidResult.ecx(%r8)
  92. mov %edx, TCpuidResult.edx(%r8)
  93. pop %rbx
  94. end;
  95. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  96. begin
  97. CPUID(in_eax, in_ecx, result);
  98. end;
  99. function CPUBrandString: shortstring;
  100. begin
  101. if CPUID($80000000).eax<$80000004 then
  102. exit('');
  103. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  104. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  105. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  106. result[49]:=#0;
  107. result[0]:=chr(length(PAnsiChar(@result[1])));
  108. end;
  109. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec; assembler;
  110. {
  111. win64:
  112. rcx ... pointer to result
  113. rdx ... target
  114. r8 ... NewValue
  115. r9 ... Comperand
  116. }
  117. {$ifdef win64}
  118. asm
  119. pushq %rbx
  120. { store result pointer for later use }
  121. pushq %rcx
  122. { load new value }
  123. movq (%r8),%rbx
  124. movq 8(%r8),%rcx
  125. { save target pointer for later use }
  126. movq %rdx,%r8
  127. { load comperand }
  128. movq (%r9),%rax
  129. movq 8(%r9),%rdx
  130. {$ifdef oldbinutils}
  131. .byte 0xF0,0x49,0x0F,0xC7,0x08
  132. {$else}
  133. lock cmpxchg16b (%r8)
  134. {$endif}
  135. { restore result pointer }
  136. popq %rcx
  137. { store result }
  138. movq %rax,(%rcx)
  139. movq %rdx,8(%rcx)
  140. popq %rbx
  141. end;
  142. {$else win64}
  143. {
  144. linux:
  145. rdi ... target
  146. [rsi:rdx] ... NewValue
  147. [rcx:r8] ... Comperand
  148. [rdx:rax] ... result
  149. }
  150. asm
  151. pushq %rbx
  152. movq %rsi,%rbx // new value low
  153. movq %rcx,%rax // comperand low
  154. movq %rdx,%rcx // new value high
  155. movq %r8,%rdx // comperand high
  156. {$ifdef oldbinutils}
  157. .byte 0xF0,0x48,0x0F,0xC7,0x0F
  158. {$else}
  159. lock cmpxchg16b (%rdi)
  160. {$endif}
  161. popq %rbx
  162. end;
  163. {$endif win64}
  164. function XGETBV(i : dword) : int64;assembler;
  165. asm
  166. {$ifndef win64}
  167. movq %rdi,%rcx
  168. {$endif win64}
  169. // older FPCs don't know the xgetbv opcode
  170. .byte 0x0f,0x01,0xd0
  171. andl $0xffffffff,%eax
  172. shlq $32,%rdx
  173. orq %rdx,%rax
  174. end;
  175. procedure SetupSupport;
  176. var
  177. maxcpuidvalue : longint;
  178. begin
  179. maxcpuidvalue:=CPUID(0).eax;
  180. CPUID(1, 0, data.cpuid1);
  181. { very early x86-64 CPUs might not support eax=7 }
  182. if maxcpuidvalue>=7 then
  183. CPUID(7, 0, data.cpuid7);
  184. is_sse3_cpu:=(data.cpuid1.ecx and (1 shl 0))<>0;
  185. data.AVXSupport:=
  186. { cpuid(1).ecx[27]: XGETBV support, cpuid(1).ecx[28]: AVX support }
  187. (data.cpuid1.ecx shr 27 and %11=%11) and
  188. { xmm and ymm state enabled? }
  189. ((XGETBV(0) and %110)=%110);
  190. data.LZCNTSupport:=(CPUID($80000001).ecx and (1 shl 5))<>0;
  191. end;
  192. function InterlockedCompareExchange128Support : boolean;inline;
  193. begin
  194. result:=(data.cpuid1.ecx and (1 shl 13))<>0;
  195. end;
  196. function CMOVSupport : boolean;
  197. begin
  198. result:=true;
  199. end;
  200. function AESSupport : boolean;inline;
  201. begin
  202. result:=(data.cpuid1.ecx and (1 shl 25))<>0;
  203. end;
  204. function AVXSupport: boolean;inline;
  205. begin
  206. result:=data.AVXSupport;
  207. end;
  208. function AVX2Support: boolean;inline;
  209. begin
  210. result:=data.AVXSupport and ((data.cpuid7.ebx and (1 shl 5))<>0);
  211. end;
  212. function AVX512FSupport: boolean;inline;
  213. begin
  214. result:=(data.cpuid7.ebx and (1 shl 16))<>0;
  215. end;
  216. function AVX512DQSupport: boolean;inline;
  217. begin
  218. result:=(data.cpuid7.ebx and (1 shl 17))<>0;
  219. end;
  220. function AVX512IFMASupport: boolean;inline;
  221. begin
  222. result:=(data.cpuid7.ebx and (1 shl 21))<>0;
  223. end;
  224. function AVX512PFSupport: boolean;inline;
  225. begin
  226. result:=(data.cpuid7.ebx and (1 shl 26))<>0;
  227. end;
  228. function AVX512ERSupport: boolean;inline;
  229. begin
  230. result:=(data.cpuid7.ebx and (1 shl 27))<>0;
  231. end;
  232. function AVX512CDSupport: boolean;inline;
  233. begin
  234. result:=(data.cpuid7.ebx and (1 shl 28))<>0;
  235. end;
  236. function AVX512BWSupport: boolean;inline;
  237. begin
  238. result:=(data.cpuid7.ebx and (1 shl 30))<>0;
  239. end;
  240. function AVX512VLSupport: boolean;inline;
  241. begin
  242. result:=(data.cpuid7.ebx and (1 shl 31))<>0;
  243. end;
  244. function AVX512VBMISupport: boolean;inline;
  245. begin
  246. result:=(data.cpuid7.ecx and (1 shl 1))<>0;
  247. end;
  248. function AVX512VBMI2Support: boolean;inline;
  249. begin
  250. result:=(data.cpuid7.ecx and (1 shl 6))<>0;
  251. end;
  252. function VAESSupport: boolean;inline;
  253. begin
  254. result:=(data.cpuid7.ecx and (1 shl 9))<>0;
  255. end;
  256. function VCLMULSupport: boolean;inline;
  257. begin
  258. result:=(data.cpuid7.ecx and (1 shl 10))<>0;
  259. end;
  260. function AVX512VNNISupport: boolean;inline;
  261. begin
  262. result:=(data.cpuid7.ecx and (1 shl 11))<>0;
  263. end;
  264. function AVX512BITALGSupport: boolean;inline;
  265. begin
  266. result:=(data.cpuid7.ecx and (1 shl 12))<>0;
  267. end;
  268. function RDSEEDSupport: boolean;inline;
  269. begin
  270. result:=(data.cpuid7.ebx and (1 shl 18))<>0;
  271. end;
  272. function ADXSupport: boolean;inline;
  273. begin
  274. result:=(data.cpuid7.ebx and (1 shl 19))<>0;
  275. end;
  276. function SHASupport: boolean;inline;
  277. begin
  278. result:=(data.cpuid7.ebx and (1 shl 29))<>0;
  279. end;
  280. function FMASupport: boolean;inline;
  281. begin
  282. result:=data.AVXSupport and ((data.cpuid1.ecx and (1 shl 12))<>0);
  283. end;
  284. function CMPXCHG16BSupport: boolean;inline;
  285. begin
  286. result:=(data.cpuid1.ecx and (1 shl 13))<>0;
  287. end;
  288. function POPCNTSupport: boolean;inline;
  289. begin
  290. result:=(data.cpuid1.ecx and (1 shl 23))<>0;
  291. end;
  292. function LZCNTSupport: boolean;inline;
  293. begin
  294. result:=data.LZCNTSupport;
  295. end;
  296. function SSE3Support: boolean;inline;
  297. begin
  298. result:=(data.cpuid1.ecx and (1 shl 0))<>0;
  299. end;
  300. function SSSE3Support: boolean;inline;
  301. begin
  302. result:=(data.cpuid1.ecx and (1 shl 9))<>0;
  303. end;
  304. function SSE41Support: boolean;inline;
  305. begin
  306. result:=(data.cpuid1.ecx and (1 shl 19))<>0;
  307. end;
  308. function SSE42Support: boolean;inline;
  309. begin
  310. result:=(data.cpuid1.ecx and (1 shl 20))<>0;
  311. end;
  312. function MOVBESupport: boolean;inline;
  313. begin
  314. result:=(data.cpuid1.ecx and (1 shl 22))<>0;
  315. end;
  316. function F16CSupport: boolean;inline;
  317. begin
  318. result:=(data.cpuid1.ecx and (1 shl 29))<>0;
  319. end;
  320. function RDRANDSupport: boolean;inline;
  321. begin
  322. result:=(data.cpuid1.ecx and (1 shl 30))<>0;
  323. end;
  324. function RTMSupport: boolean;inline;
  325. begin
  326. result:=((data.cpuid7.ebx and (1 shl 11))<>0) and (data.cpuid7.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  327. end;
  328. function BMI1Support: boolean;inline;
  329. begin
  330. result:=(data.cpuid7.ebx and (1 shl 3))<>0;
  331. end;
  332. function BMI2Support: boolean;inline;
  333. begin
  334. result:=(data.cpuid7.ebx and (1 shl 8))<>0;
  335. end;
  336. begin
  337. SetupSupport;
  338. end.