cpu.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  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. {$goto on}
  14. {$IFNDEF FPC_DOTTEDUNITS}
  15. unit cpu;
  16. {$ENDIF FPC_DOTTEDUNITS}
  17. interface
  18. { returns true, if the processor supports the cpuid instruction }
  19. function cpuid_support : boolean;
  20. type
  21. TCpuidResult = record
  22. eax, ebx, ecx, edx: uint32;
  23. end;
  24. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult; inline;
  25. function CPUBrandString: shortstring;
  26. { returns true, if floating point is done by an emulator }
  27. function floating_point_emulation : boolean;
  28. { returns the contents of the cr0 register }
  29. function cr0 : longint;
  30. function InterlockedCompareExchange128Support: boolean;
  31. function TSCSupport: boolean;inline;
  32. function MMXSupport: boolean;inline;
  33. function CMOVSupport: boolean;inline;
  34. function AESSupport: boolean;inline;
  35. function AVXSupport: boolean;inline;
  36. function AVX2Support: boolean;inline;
  37. function AVX101Support: boolean;inline; { AVX10.1 }
  38. function AVX102Support: boolean;inline; { AVX10.2 }
  39. function AVX10_256Support: boolean;inline; { AVX10/256 indicates that 256-bit vector support is present }
  40. function AVX10_512Support: boolean;inline; { AVX10/512 indicates that 512-bit vector support is present }
  41. function APXSupport: boolean;inline; { APX_F Advanced Performance Extension Foundation }
  42. function AVX512FSupport: boolean;inline;
  43. function AVX512DQSupport: boolean;inline;
  44. function AVX512IFMASupport: boolean;inline;
  45. function AVX512PFSupport: boolean;inline;
  46. function AVX512ERSupport: boolean;inline;
  47. function AVX512CDSupport: boolean;inline;
  48. function AVX512BWSupport: boolean;inline;
  49. function AVX512VLSupport: boolean;inline;
  50. function AVX512VBMISupport: boolean;inline;
  51. function AVX512VBMI2Support: boolean;inline;
  52. function AVX512VNNISupport: boolean;inline;
  53. function AVX512VPOPCNTDQSupport: boolean;inline;
  54. function AVX512BF16Support: boolean;inline;
  55. function AVX512FP16Support: boolean;inline;
  56. function AVX512VP2INTERSECTSupport: boolean;inline;
  57. function AVX5124VNNIWSupport: boolean;inline;
  58. function AVX5124FMAPSSupport: boolean;inline;
  59. function GFNISupport: boolean;inline;
  60. function VAESSupport: boolean;inline;
  61. function VCLMULSupport: boolean;inline;
  62. function AVX512BITALGSupport: boolean;inline;
  63. function RDSEEDSupport: boolean;inline;
  64. function ADXSupport: boolean;inline;
  65. function SHASupport: boolean;inline;
  66. function SHA512Support: boolean;inline;
  67. function SM3Support: boolean;inline;
  68. function SM4Support: boolean;inline;
  69. function FMASupport: 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. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  97. begin
  98. {$if FPC_FULLVERSION >= 30101}
  99. {$ifndef FPC_PIC}
  100. if RTMSupport then
  101. begin
  102. asm
  103. {$ifdef USE_REAL_INSTRUCTIONS}
  104. .Lretry:
  105. xbegin .Lretry
  106. {$else}
  107. { 3d: c7 f8 fa ff ff ff xbegin }
  108. .byte 0xc7,0xf8, 0xfa, 0xff, 0xff, 0xff
  109. {$endif}
  110. end;
  111. Result:=Target;
  112. if (Result.Lo=Comperand.Lo) and (Result.Hi=Comperand.Hi) then
  113. Target:=NewValue;
  114. asm
  115. {$ifdef USE_REAL_INSTRUCTIONS}
  116. xend
  117. {$else}
  118. { 8a: 0f 01 d5 xend }
  119. .byte 0x0f, 0x01, 0xd5
  120. {$endif}
  121. end;
  122. end
  123. else
  124. {$endif FPC_PIC}
  125. {$endif FPC_FULLVERSION >= 30101}
  126. RunError(217);
  127. end;
  128. {$ASMMODE INTEL}
  129. function cpuid_support : boolean;assembler;
  130. {
  131. Check if the ID-flag can be changed, if changed then CpuID is supported.
  132. Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
  133. }
  134. asm
  135. push ebx
  136. pushfd
  137. pushfd
  138. pop eax
  139. mov ebx,eax
  140. xor eax,200000h
  141. push eax
  142. popfd
  143. pushfd
  144. pop eax
  145. popfd
  146. and eax,200000h
  147. and ebx,200000h
  148. cmp eax,ebx
  149. setnz al
  150. pop ebx
  151. end;
  152. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  153. // eax = in_eax, edx = in_ecx, ecx = res
  154. asm
  155. push ebx
  156. push esi
  157. mov esi, ecx // esi = res
  158. mov ecx, edx // ecx = in_ecx
  159. cpuid
  160. mov TCpuidResult.eax[esi], eax
  161. mov TCpuidResult.ebx[esi], ebx
  162. mov TCpuidResult.ecx[esi], ecx
  163. mov TCpuidResult.edx[esi], edx
  164. pop esi
  165. pop ebx
  166. end;
  167. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  168. begin
  169. CPUID(in_eax, in_ecx, result);
  170. end;
  171. function CPUBrandString: shortstring;
  172. begin
  173. if not cpuid_support or (CPUID($80000000).eax<$80000004) then
  174. exit('');
  175. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  176. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  177. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  178. result[49]:=#0;
  179. result[0]:=chr(length(PAnsiChar(@result[1])));
  180. end;
  181. function cr0 : longint;assembler;
  182. asm
  183. {$ifdef USE_REAL_INSTRUCTIONS}
  184. mov eax,cr0
  185. {$else}
  186. DB 0Fh,20h,0C0h
  187. {$endif}
  188. { mov eax,cr0
  189. special registers are not allowed in the assembler
  190. parsers }
  191. end;
  192. function floating_point_emulation : boolean;
  193. begin
  194. {!!!! I don't know currently the position of the EM flag }
  195. { $4 after Ralf Brown's list }
  196. floating_point_emulation:=(cr0 and $4)<>0;
  197. end;
  198. {$ASMMODE ATT}
  199. function XGETBV(i : dword) : int64;assembler;
  200. asm
  201. movl %eax,%ecx
  202. {$ifdef USE_REAL_INSTRUCTIONS}
  203. xgetbv
  204. {$else}
  205. // older FPCs don't know the xgetbv opcode
  206. .byte 0x0f,0x01,0xd0
  207. {$endif}
  208. end;
  209. procedure SetupSupport;
  210. var
  211. maxcpuidvalue : longint;
  212. begin
  213. if cpuid_support then
  214. begin
  215. maxcpuidvalue:=CPUID(0).eax;
  216. CPUID(1, 0, data.cpuid1);
  217. if maxcpuidvalue>=7 then
  218. begin
  219. CPUID(7, 0, data.cpuid7_0);
  220. CPUID(7, 1, data.cpuid7_1);
  221. end;
  222. is_sse3_cpu:=(data.cpuid1.ecx and (1 shl 0))<>0;
  223. data.AVXSupport:=
  224. { cpuid(1).ecx[27]: XGETBV support, cpuid(1).ecx[28]: AVX support }
  225. (data.cpuid1.ecx shr 27 and %11=%11) and
  226. { xmm and ymm state enabled? }
  227. ((XGETBV(0) and %110)=%110);
  228. if (data.cpuid7_1.edx and (1 shl 19))<>0 then { CPUID.(EAX=24H) leaf is supported }
  229. data.cpuid24_0_ebx:=CPUID($24, 0).ebx;
  230. data.LZCNTSupport:=(CPUID($80000001).ecx and (1 shl 5))<>0;
  231. end;
  232. end;
  233. function InterlockedCompareExchange128Support : boolean;
  234. begin
  235. { 32 Bit CPUs have no 128 Bit interlocked exchange support,
  236. but it can simulated using RTM }
  237. result:=RTMSupport;
  238. end;
  239. function TSCSupport: boolean;
  240. begin
  241. result:=(data.cpuid1.edx and (1 shl 4))<>0;
  242. end;
  243. function MMXSupport: boolean;
  244. begin
  245. result:=(data.cpuid1.edx and (1 shl 23))<>0;
  246. end;
  247. function CMOVSupport : boolean;
  248. begin
  249. result:=(data.cpuid1.edx and (1 shl 15))<>0;
  250. end;
  251. function AESSupport : boolean;
  252. begin
  253. result:=(data.cpuid1.ecx and (1 shl 25))<>0;
  254. end;
  255. function AVXSupport: boolean;inline;
  256. begin
  257. result:=data.AVXSupport;
  258. end;
  259. function AVX2Support: boolean;inline;
  260. begin
  261. result:=data.AVXSupport and ((data.cpuid7_0.ebx and (1 shl 5))<>0);
  262. end;
  263. function AVX101Support: boolean;inline; { AVX10.1 }
  264. begin
  265. result:=(data.cpuid24_0_ebx and $ff)>=1;
  266. end;
  267. function AVX102Support: boolean;inline; { AVX10.2 }
  268. begin
  269. result:=(data.cpuid24_0_ebx and $ff)>=2;
  270. end;
  271. function AVX10_256Support: boolean;inline; { AVX10/256 }
  272. begin
  273. result:=(data.cpuid24_0_ebx and (1 shl 17))<>0;
  274. end;
  275. function AVX10_512Support: boolean;inline; { AVX10/512 }
  276. begin
  277. result:=(data.cpuid24_0_ebx and (1 shl 18))<>0;
  278. end;
  279. function APXSupport: boolean;inline; { APX_F Advanced Performance Extension Foundation }
  280. begin
  281. result:=(data.cpuid7_1.edx and (1 shl 21))<>0;
  282. end;
  283. function AVX512FSupport: boolean;inline;
  284. begin
  285. result:=(data.cpuid7_0.ebx and (1 shl 16))<>0;
  286. end;
  287. function AVX512DQSupport: boolean;inline;
  288. begin
  289. result:=(data.cpuid7_0.ebx and (1 shl 17))<>0;
  290. end;
  291. function AVX512IFMASupport: boolean;inline;
  292. begin
  293. result:=(data.cpuid7_0.ebx and (1 shl 21))<>0;
  294. end;
  295. function AVX512PFSupport: boolean;inline;
  296. begin
  297. result:=(data.cpuid7_0.ebx and (1 shl 26))<>0;
  298. end;
  299. function AVX512ERSupport: boolean;inline;
  300. begin
  301. result:=(data.cpuid7_0.ebx and (1 shl 27))<>0;
  302. end;
  303. function AVX512CDSupport: boolean;inline;
  304. begin
  305. result:=(data.cpuid7_0.ebx and (1 shl 28))<>0;
  306. end;
  307. function AVX512BWSupport: boolean;inline;
  308. begin
  309. result:=(data.cpuid7_0.ebx and (1 shl 30))<>0;
  310. end;
  311. function AVX512VLSupport: boolean;inline;
  312. begin
  313. result:=(data.cpuid7_0.ebx and (1 shl 31))<>0;
  314. end;
  315. function AVX512VBMISupport: boolean;inline;
  316. begin
  317. result:=(data.cpuid7_0.ecx and (1 shl 1))<>0;
  318. end;
  319. function AVX512VBMI2Support: boolean;inline;
  320. begin
  321. result:=(data.cpuid7_0.ecx and (1 shl 6))<>0;
  322. end;
  323. function GFNISupport: boolean;inline;
  324. begin
  325. result:=(data.cpuid7_0.ecx and (1 shl 8))<>0;
  326. end;
  327. function VAESSupport: boolean;inline;
  328. begin
  329. result:=(data.cpuid7_0.ecx and (1 shl 9))<>0;
  330. end;
  331. function VCLMULSupport: boolean;inline;
  332. begin
  333. result:=(data.cpuid7_0.ecx and (1 shl 10))<>0;
  334. end;
  335. function AVX512VNNISupport: boolean;inline;
  336. begin
  337. result:=(data.cpuid7_0.ecx and (1 shl 11))<>0;
  338. end;
  339. function AVX512BITALGSupport: boolean;inline;
  340. begin
  341. result:=(data.cpuid7_0.ecx and (1 shl 12))<>0;
  342. end;
  343. function AVX512VPOPCNTDQSupport: boolean;inline;
  344. begin
  345. result:=(data.cpuid7_0.ecx and (1 shl 14))<>0;
  346. end;
  347. function AVX512BF16Support: boolean;inline;
  348. begin
  349. result:=(data.cpuid7_1.eax and (1 shl 5))<>0;
  350. end;
  351. function AVX512FP16Support: boolean;inline;
  352. begin
  353. result:=(data.cpuid7_0.edx and (1 shl 23))<>0;
  354. end;
  355. function AVX512VP2INTERSECTSupport: boolean;inline;
  356. begin
  357. result:=(data.cpuid7_0.edx and (1 shl 8))<>0;
  358. end;
  359. function AVX5124VNNIWSupport: boolean;inline;
  360. begin
  361. result:=(data.cpuid7_0.edx and (1 shl 2))<>0;
  362. end;
  363. function AVX5124FMAPSSupport: boolean;inline;
  364. begin
  365. result:=(data.cpuid7_0.edx and (1 shl 3))<>0;
  366. end;
  367. function RDSEEDSupport: boolean;inline;
  368. begin
  369. result:=(data.cpuid7_0.ebx and (1 shl 18))<>0;
  370. end;
  371. function ADXSupport: boolean;inline;
  372. begin
  373. result:=(data.cpuid7_0.ebx and (1 shl 19))<>0;
  374. end;
  375. function SHASupport: boolean;inline;
  376. begin
  377. result:=(data.cpuid7_0.ebx and (1 shl 29))<>0;
  378. end;
  379. function SHA512Support: boolean;inline;
  380. begin
  381. result:=(data.cpuid7_1.eax and 1)<>0;
  382. end;
  383. function SM3Support: boolean;inline;
  384. begin
  385. result:=(data.cpuid7_1.eax and (1 shl 1))<>0;
  386. end;
  387. function SM4Support: boolean;inline;
  388. begin
  389. result:=(data.cpuid7_1.eax and (1 shl 2))<>0;
  390. end;
  391. function FMASupport: boolean;inline;
  392. begin
  393. result:=data.AVXSupport and ((data.cpuid1.ecx and (1 shl 12))<>0);
  394. end;
  395. function POPCNTSupport: boolean;inline;
  396. begin
  397. result:=(data.cpuid1.ecx and (1 shl 23))<>0;
  398. end;
  399. function LZCNTSupport: boolean;inline;
  400. begin
  401. result:=data.LZCNTSupport;
  402. end;
  403. function SSESupport: boolean;inline;
  404. begin
  405. result:=(data.cpuid1.edx and (1 shl 25))<>0;
  406. end;
  407. function SSE2Support: boolean;inline;
  408. begin
  409. result:=(data.cpuid1.edx and (1 shl 26))<>0;
  410. end;
  411. function SSE3Support: boolean;inline;
  412. begin
  413. result:=(data.cpuid1.ecx and (1 shl 0))<>0;
  414. end;
  415. function SSSE3Support: boolean;inline;
  416. begin
  417. result:=(data.cpuid1.ecx and (1 shl 9))<>0;
  418. end;
  419. function SSE41Support: boolean;inline;
  420. begin
  421. result:=(data.cpuid1.ecx and (1 shl 19))<>0;
  422. end;
  423. function SSE42Support: boolean;inline;
  424. begin
  425. result:=(data.cpuid1.ecx and (1 shl 20))<>0;
  426. end;
  427. function MOVBESupport: boolean;inline;
  428. begin
  429. result:=(data.cpuid1.ecx and (1 shl 22))<>0;
  430. end;
  431. function F16CSupport: boolean;inline;
  432. begin
  433. result:=(data.cpuid1.ecx and (1 shl 29))<>0;
  434. end;
  435. function RDRANDSupport: boolean;inline;
  436. begin
  437. result:=(data.cpuid1.ecx and (1 shl 30))<>0;
  438. end;
  439. function RTMSupport: boolean;inline;
  440. begin
  441. result:=((data.cpuid7_0.ebx and (1 shl 11))<>0) and (data.cpuid7_0.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  442. end;
  443. function BMI1Support: boolean;inline;
  444. begin
  445. result:=(data.cpuid7_0.ebx and (1 shl 3))<>0;
  446. end;
  447. function BMI2Support: boolean;inline;
  448. begin
  449. result:=(data.cpuid7_0.ebx and (1 shl 8))<>0;
  450. end;
  451. begin
  452. SetupSupport;
  453. end.