2
0

cpu.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  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 TSCSupport: boolean;inline;
  31. function MMXSupport: boolean;inline;
  32. function CMOVSupport : boolean;inline;
  33. function AESSupport : boolean;inline;
  34. function AVXSupport : boolean;inline;
  35. function AVX2Support: boolean;inline;
  36. function AVX101Support: boolean;inline; { AVX10.1 }
  37. function AVX102Support: boolean;inline; { AVX10.2 }
  38. function AVX10_256Support: boolean;inline; { AVX10/256 indicates that 256-bit vector support is present }
  39. function AVX10_512Support: boolean;inline; { AVX10/512 indicates that 512-bit vector support is present }
  40. function APXSupport: boolean;inline; { APX_F Advanced Performance Extension Foundation }
  41. function AVX512FSupport: boolean;inline;
  42. function AVX512DQSupport: boolean;inline;
  43. function AVX512IFMASupport: boolean;inline;
  44. function AVX512PFSupport: boolean;inline;
  45. function AVX512ERSupport: boolean;inline;
  46. function AVX512CDSupport: boolean;inline;
  47. function AVX512BWSupport: boolean;inline;
  48. function AVX512VLSupport: boolean;inline;
  49. function AVX512VBMISupport: boolean;inline;
  50. function AVX512VBMI2Support: boolean;inline;
  51. function AVX512VNNISupport: boolean;inline;
  52. function AVX512VPOPCNTDQSupport: boolean;inline;
  53. function AVX512BF16Support: boolean;inline;
  54. function AVX512FP16Support: boolean;inline;
  55. function AVX512VP2INTERSECTSupport: boolean;inline;
  56. function AVX5124VNNIWSupport: boolean;inline;
  57. function AVX5124FMAPSSupport: boolean;inline;
  58. function GFNISupport: boolean;inline;
  59. function VAESSupport: boolean;inline;
  60. function VCLMULSupport: boolean;inline;
  61. function AVX512BITALGSupport: boolean;inline;
  62. function RDSEEDSupport: boolean;inline;
  63. function ADXSupport: boolean;inline;
  64. function SHASupport: boolean;inline;
  65. function SHA512Support: boolean;inline;
  66. function SM3Support: boolean;inline;
  67. function SM4Support: boolean;inline;
  68. function FMASupport: boolean;inline;
  69. function CMPXCHG16BSupport: boolean;inline;
  70. function POPCNTSupport: boolean;inline;
  71. function LZCNTSupport: boolean;inline;
  72. function SSESupport: boolean;inline;
  73. function SSE2Support: boolean;inline;
  74. function SSE3Support: boolean;inline;
  75. function SSSE3Support: boolean;inline;
  76. function SSE41Support: boolean;inline;
  77. function SSE42Support: boolean;inline;
  78. function MOVBESupport: boolean;inline;
  79. function F16CSupport: boolean;inline;
  80. function RDRANDSupport: boolean;inline;
  81. function RTMSupport: boolean;inline;
  82. function BMI1Support: boolean;inline;
  83. function BMI2Support: boolean;inline;
  84. var
  85. is_sse3_cpu : boolean = false;
  86. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  87. implementation
  88. var
  89. data: record
  90. cpuid1, cpuid7_0, cpuid7_1 : TCpuidResult;
  91. cpuid24_0_ebx : dword;
  92. AVXSupport,
  93. LZCNTSupport: boolean;
  94. end;
  95. {$ASMMODE ATT}
  96. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  97. // ^ 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,
  98. // that's why this internal version with "out res" exists...
  99. // Win64: ecx = in_eax, edx = in_ecx, r8 = res.
  100. // SysV: edi = in_eax, esi = in_ecx, rdx = res.
  101. asm
  102. push %rbx
  103. {$ifndef win64}
  104. mov %rdx, %r8 // r8 = res
  105. {$endif}
  106. mov in_eax, %eax
  107. mov in_ecx, %ecx
  108. cpuid
  109. mov %eax, TCpuidResult.eax(%r8)
  110. mov %ebx, TCpuidResult.ebx(%r8)
  111. mov %ecx, TCpuidResult.ecx(%r8)
  112. mov %edx, TCpuidResult.edx(%r8)
  113. pop %rbx
  114. end;
  115. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  116. begin
  117. CPUID(in_eax, in_ecx, result);
  118. end;
  119. function CPUBrandString: shortstring;
  120. begin
  121. if CPUID($80000000).eax<$80000004 then
  122. exit('');
  123. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  124. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  125. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  126. result[49]:=#0;
  127. result[0]:=chr(length(PAnsiChar(@result[1])));
  128. end;
  129. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec; assembler;
  130. {
  131. win64:
  132. rcx ... pointer to result
  133. rdx ... target
  134. r8 ... NewValue
  135. r9 ... Comperand
  136. }
  137. {$ifdef win64}
  138. asm
  139. pushq %rbx
  140. { store result pointer for later use }
  141. pushq %rcx
  142. { load new value }
  143. movq (%r8),%rbx
  144. movq 8(%r8),%rcx
  145. { save target pointer for later use }
  146. movq %rdx,%r8
  147. { load comperand }
  148. movq (%r9),%rax
  149. movq 8(%r9),%rdx
  150. {$ifdef oldbinutils}
  151. .byte 0xF0,0x49,0x0F,0xC7,0x08
  152. {$else}
  153. lock cmpxchg16b (%r8)
  154. {$endif}
  155. { restore result pointer }
  156. popq %rcx
  157. { store result }
  158. movq %rax,(%rcx)
  159. movq %rdx,8(%rcx)
  160. popq %rbx
  161. end;
  162. {$else win64}
  163. {
  164. linux:
  165. rdi ... target
  166. [rsi:rdx] ... NewValue
  167. [rcx:r8] ... Comperand
  168. [rdx:rax] ... result
  169. }
  170. asm
  171. pushq %rbx
  172. movq %rsi,%rbx // new value low
  173. movq %rcx,%rax // comperand low
  174. movq %rdx,%rcx // new value high
  175. movq %r8,%rdx // comperand high
  176. {$ifdef oldbinutils}
  177. .byte 0xF0,0x48,0x0F,0xC7,0x0F
  178. {$else}
  179. lock cmpxchg16b (%rdi)
  180. {$endif}
  181. popq %rbx
  182. end;
  183. {$endif win64}
  184. function XGETBV(i : dword) : int64;assembler;
  185. asm
  186. {$ifndef win64}
  187. movq %rdi,%rcx
  188. {$endif win64}
  189. // older FPCs don't know the xgetbv opcode
  190. .byte 0x0f,0x01,0xd0
  191. shlq $32,%rdx
  192. orq %rdx,%rax
  193. end;
  194. procedure SetupSupport;
  195. var
  196. maxcpuidvalue : longint;
  197. begin
  198. maxcpuidvalue:=CPUID(0).eax;
  199. CPUID(1, 0, data.cpuid1);
  200. { very early x86-64 CPUs might not support eax=7 }
  201. if maxcpuidvalue>=7 then
  202. begin
  203. CPUID(7, 0, data.cpuid7_0);
  204. CPUID(7, 1, data.cpuid7_1);
  205. end;
  206. is_sse3_cpu:=(data.cpuid1.ecx and (1 shl 0))<>0;
  207. data.AVXSupport:=
  208. { cpuid(1).ecx[27]: XGETBV support, cpuid(1).ecx[28]: AVX support }
  209. (data.cpuid1.ecx shr 27 and %11=%11) and
  210. { xmm and ymm state enabled? }
  211. ((XGETBV(0) and %110)=%110);
  212. if (data.cpuid7_1.edx and (1 shl 19))<>0 then { CPUID.(EAX=24H) leaf is supported }
  213. data.cpuid24_0_ebx:=CPUID($24, 0).ebx;
  214. data.LZCNTSupport:=(CPUID($80000001).ecx and (1 shl 5))<>0;
  215. end;
  216. function InterlockedCompareExchange128Support : boolean;inline;
  217. begin
  218. result:=(data.cpuid1.ecx and (1 shl 13))<>0;
  219. end;
  220. function TSCSupport: boolean;
  221. begin
  222. result:=(data.cpuid1.edx and (1 shl 4))<>0;
  223. end;
  224. function MMXSupport: boolean;
  225. begin
  226. result:=(data.cpuid1.edx and (1 shl 23))<>0;
  227. end;
  228. function CMOVSupport : boolean;
  229. begin
  230. result:=true;
  231. end;
  232. function AESSupport : boolean;inline;
  233. begin
  234. result:=(data.cpuid1.ecx and (1 shl 25))<>0;
  235. end;
  236. function AVXSupport: boolean;inline;
  237. begin
  238. result:=data.AVXSupport;
  239. end;
  240. function AVX2Support: boolean;inline;
  241. begin
  242. result:=data.AVXSupport and ((data.cpuid7_0.ebx and (1 shl 5))<>0);
  243. end;
  244. function AVX101Support: boolean;inline; { AVX10.1 }
  245. begin
  246. result:=(data.cpuid24_0_ebx and $ff)>=1;
  247. end;
  248. function AVX102Support: boolean;inline; { AVX10.2 }
  249. begin
  250. result:=(data.cpuid24_0_ebx and $ff)>=2;
  251. end;
  252. function AVX10_256Support: boolean;inline; { AVX10/256 }
  253. begin
  254. result:=(data.cpuid24_0_ebx and (1 shl 17))<>0;
  255. end;
  256. function AVX10_512Support: boolean;inline; { AVX10/512 }
  257. begin
  258. result:=(data.cpuid24_0_ebx and (1 shl 18))<>0;
  259. end;
  260. function APXSupport: boolean;inline; { APX_F Advanced Performance Extension Foundation }
  261. begin
  262. result:=(data.cpuid7_1.edx and (1 shl 21))<>0;
  263. end;
  264. function AVX512FSupport: boolean;inline;
  265. begin
  266. result:=(data.cpuid7_0.ebx and (1 shl 16))<>0;
  267. end;
  268. function AVX512DQSupport: boolean;inline;
  269. begin
  270. result:=(data.cpuid7_0.ebx and (1 shl 17))<>0;
  271. end;
  272. function AVX512IFMASupport: boolean;inline;
  273. begin
  274. result:=(data.cpuid7_0.ebx and (1 shl 21))<>0;
  275. end;
  276. function AVX512PFSupport: boolean;inline;
  277. begin
  278. result:=(data.cpuid7_0.ebx and (1 shl 26))<>0;
  279. end;
  280. function AVX512ERSupport: boolean;inline;
  281. begin
  282. result:=(data.cpuid7_0.ebx and (1 shl 27))<>0;
  283. end;
  284. function AVX512CDSupport: boolean;inline;
  285. begin
  286. result:=(data.cpuid7_0.ebx and (1 shl 28))<>0;
  287. end;
  288. function AVX512BWSupport: boolean;inline;
  289. begin
  290. result:=(data.cpuid7_0.ebx and (1 shl 30))<>0;
  291. end;
  292. function AVX512VLSupport: boolean;inline;
  293. begin
  294. result:=(data.cpuid7_0.ebx and (1 shl 31))<>0;
  295. end;
  296. function AVX512VBMISupport: boolean;inline;
  297. begin
  298. result:=(data.cpuid7_0.ecx and (1 shl 1))<>0;
  299. end;
  300. function AVX512VBMI2Support: boolean;inline;
  301. begin
  302. result:=(data.cpuid7_0.ecx and (1 shl 6))<>0;
  303. end;
  304. function GFNISupport: boolean;inline;
  305. begin
  306. result:=(data.cpuid7_0.ecx and (1 shl 8))<>0;
  307. end;
  308. function VAESSupport: boolean;inline;
  309. begin
  310. result:=(data.cpuid7_0.ecx and (1 shl 9))<>0;
  311. end;
  312. function VCLMULSupport: boolean;inline;
  313. begin
  314. result:=(data.cpuid7_0.ecx and (1 shl 10))<>0;
  315. end;
  316. function AVX512VNNISupport: boolean;inline;
  317. begin
  318. result:=(data.cpuid7_0.ecx and (1 shl 11))<>0;
  319. end;
  320. function AVX512BITALGSupport: boolean;inline;
  321. begin
  322. result:=(data.cpuid7_0.ecx and (1 shl 12))<>0;
  323. end;
  324. function AVX512VPOPCNTDQSupport: boolean;inline;
  325. begin
  326. result:=(data.cpuid7_0.ecx and (1 shl 14))<>0;
  327. end;
  328. function AVX512BF16Support: boolean;inline;
  329. begin
  330. result:=(data.cpuid7_1.eax and (1 shl 5))<>0;
  331. end;
  332. function AVX512FP16Support: boolean;inline;
  333. begin
  334. result:=(data.cpuid7_0.edx and (1 shl 23))<>0;
  335. end;
  336. function AVX512VP2INTERSECTSupport: boolean;inline;
  337. begin
  338. result:=(data.cpuid7_0.edx and (1 shl 8))<>0;
  339. end;
  340. function AVX5124VNNIWSupport: boolean;inline;
  341. begin
  342. result:=(data.cpuid7_0.edx and (1 shl 2))<>0;
  343. end;
  344. function AVX5124FMAPSSupport: boolean;inline;
  345. begin
  346. result:=(data.cpuid7_0.edx and (1 shl 3))<>0;
  347. end;
  348. function RDSEEDSupport: boolean;inline;
  349. begin
  350. result:=(data.cpuid7_0.ebx and (1 shl 18))<>0;
  351. end;
  352. function ADXSupport: boolean;inline;
  353. begin
  354. result:=(data.cpuid7_0.ebx and (1 shl 19))<>0;
  355. end;
  356. function SHASupport: boolean;inline;
  357. begin
  358. result:=(data.cpuid7_0.ebx and (1 shl 29))<>0;
  359. end;
  360. function SHA512Support: boolean;inline;
  361. begin
  362. result:=(data.cpuid7_1.eax and 1)<>0;
  363. end;
  364. function SM3Support: boolean;inline;
  365. begin
  366. result:=(data.cpuid7_1.eax and (1 shl 1))<>0;
  367. end;
  368. function SM4Support: boolean;inline;
  369. begin
  370. result:=(data.cpuid7_1.eax and (1 shl 2))<>0;
  371. end;
  372. function FMASupport: boolean;inline;
  373. begin
  374. result:=data.AVXSupport and ((data.cpuid1.ecx and (1 shl 12))<>0);
  375. end;
  376. function CMPXCHG16BSupport: boolean;inline;
  377. begin
  378. result:=(data.cpuid1.ecx and (1 shl 13))<>0;
  379. end;
  380. function POPCNTSupport: boolean;inline;
  381. begin
  382. result:=(data.cpuid1.ecx and (1 shl 23))<>0;
  383. end;
  384. function LZCNTSupport: boolean;inline;
  385. begin
  386. result:=data.LZCNTSupport;
  387. end;
  388. function SSESupport: boolean;inline;
  389. begin
  390. result:=true;
  391. end;
  392. function SSE2Support: boolean;inline;
  393. begin
  394. result:=true;
  395. end;
  396. function SSE3Support: boolean;inline;
  397. begin
  398. result:=(data.cpuid1.ecx and (1 shl 0))<>0;
  399. end;
  400. function SSSE3Support: boolean;inline;
  401. begin
  402. result:=(data.cpuid1.ecx and (1 shl 9))<>0;
  403. end;
  404. function SSE41Support: boolean;inline;
  405. begin
  406. result:=(data.cpuid1.ecx and (1 shl 19))<>0;
  407. end;
  408. function SSE42Support: boolean;inline;
  409. begin
  410. result:=(data.cpuid1.ecx and (1 shl 20))<>0;
  411. end;
  412. function MOVBESupport: boolean;inline;
  413. begin
  414. result:=(data.cpuid1.ecx and (1 shl 22))<>0;
  415. end;
  416. function F16CSupport: boolean;inline;
  417. begin
  418. result:=(data.cpuid1.ecx and (1 shl 29))<>0;
  419. end;
  420. function RDRANDSupport: boolean;inline;
  421. begin
  422. result:=(data.cpuid1.ecx and (1 shl 30))<>0;
  423. end;
  424. function RTMSupport: boolean;inline;
  425. begin
  426. result:=((data.cpuid7_0.ebx and (1 shl 11))<>0) and (data.cpuid7_0.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  427. end;
  428. function BMI1Support: boolean;inline;
  429. begin
  430. result:=(data.cpuid7_0.ebx and (1 shl 3))<>0;
  431. end;
  432. function BMI2Support: boolean;inline;
  433. begin
  434. result:=(data.cpuid7_0.ebx and (1 shl 8))<>0;
  435. end;
  436. begin
  437. SetupSupport;
  438. end.