cpu.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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. {$IFDEF FPC_DOTTEDUNITS}
  19. uses
  20. System.SysUtils;
  21. {$ELSE FPC_DOTTEDUNITS}
  22. uses
  23. sysutils;
  24. {$ENDIF FPC_DOTTEDUNITS}
  25. { returns true, if the processor supports the cpuid instruction }
  26. function cpuid_support : boolean;
  27. type
  28. TCpuidResult = record
  29. eax, ebx, ecx, edx: uint32;
  30. end;
  31. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult; inline;
  32. function CPUBrandString: shortstring;
  33. { returns true, if floating point is done by an emulator }
  34. function floating_point_emulation : boolean;
  35. { returns the contents of the cr0 register }
  36. function cr0 : longint;
  37. function CMOVSupport : boolean;inline;
  38. function InterlockedCompareExchange128Support : boolean;
  39. function AESSupport : boolean;inline;
  40. function AVXSupport: boolean;inline;
  41. function AVX2Support: boolean;inline;
  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 VAESSupport: boolean;inline;
  54. function VCLMULSupport: boolean;inline;
  55. function AVX512BITALGSupport: boolean;inline;
  56. function RDSEEDSupport: boolean;inline;
  57. function ADXSupport: boolean;inline;
  58. function SHASupport: boolean;inline;
  59. function FMASupport: boolean;inline;
  60. function POPCNTSupport: boolean;inline;
  61. function LZCNTSupport: boolean;inline;
  62. function SSE3Support: boolean;inline;
  63. function SSSE3Support: boolean;inline;
  64. function SSE41Support: boolean;inline;
  65. function SSE42Support: boolean;inline;
  66. function MOVBESupport: boolean;inline;
  67. function F16CSupport: boolean;inline;
  68. function RDRANDSupport: boolean;inline;
  69. function RTMSupport: boolean;inline;
  70. function BMI1Support: boolean;inline;
  71. function BMI2Support: boolean;inline;
  72. var
  73. is_sse3_cpu : boolean = false;
  74. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  75. implementation
  76. {$ASMMODE INTEL}
  77. var
  78. _CMOVSupport,
  79. _AESSupport,
  80. _AVXSupport,
  81. _AVX2Support,
  82. _AVX512FSupport,
  83. _AVX512DQSupport,
  84. _AVX512IFMASupport,
  85. _AVX512PFSupport,
  86. _AVX512ERSupport,
  87. _AVX512CDSupport,
  88. _AVX512BWSupport,
  89. _AVX512VLSupport,
  90. _AVX512VBMISupport,
  91. _AVX512VBMI2Support,
  92. _VAESSupport,
  93. _VCLMULSupport,
  94. _AVX512VNNISupport,
  95. _AVX512BITALGSupport,
  96. _RDSEEDSupport,
  97. _ADXSupport,
  98. _SHASupport,
  99. _FMASupport,
  100. _POPCNTSupport,
  101. _LZCNTSupport,
  102. _SSE3Support,
  103. _SSSE3Support,
  104. _SSE41Support,
  105. _SSE42Support,
  106. _MOVBESupport,
  107. _F16CSupport,
  108. _RDRANDSupport,
  109. _RTMSupport,
  110. _BMI1Support,
  111. _BMI2Support: boolean;
  112. {$ASMMODE ATT}
  113. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  114. begin
  115. {$if FPC_FULLVERSION >= 30101}
  116. {$ifndef FPC_PIC}
  117. if _RTMSupport then
  118. begin
  119. asm
  120. {$ifdef USE_REAL_INSTRUCTIONS}
  121. .Lretry:
  122. xbegin .Lretry
  123. {$else}
  124. { 3d: c7 f8 fa ff ff ff xbegin }
  125. .byte 0xc7,0xf8, 0xfa, 0xff, 0xff, 0xff
  126. {$endif}
  127. end;
  128. Result:=Target;
  129. if (Result.Lo=Comperand.Lo) and (Result.Hi=Comperand.Hi) then
  130. Target:=NewValue;
  131. asm
  132. {$ifdef USE_REAL_INSTRUCTIONS}
  133. xend
  134. {$else}
  135. { 8a: 0f 01 d5 xend }
  136. .byte 0x0f, 0x01, 0xd5
  137. {$endif}
  138. end;
  139. end
  140. else
  141. {$endif FPC_PIC}
  142. {$endif FPC_FULLVERSION >= 30101}
  143. RunError(217);
  144. end;
  145. {$ASMMODE INTEL}
  146. function cpuid_support : boolean;assembler;
  147. {
  148. Check if the ID-flag can be changed, if changed then CpuID is supported.
  149. Tested under go32v1 and Linux on c6x86 with CpuID enabled and disabled (PFV)
  150. }
  151. asm
  152. push ebx
  153. pushfd
  154. pushfd
  155. pop eax
  156. mov ebx,eax
  157. xor eax,200000h
  158. push eax
  159. popfd
  160. pushfd
  161. pop eax
  162. popfd
  163. and eax,200000h
  164. and ebx,200000h
  165. cmp eax,ebx
  166. setnz al
  167. pop ebx
  168. end;
  169. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  170. // eax = in_eax, edx = in_ecx, ecx = res
  171. asm
  172. push ebx
  173. push esi
  174. mov esi, ecx // esi = res
  175. mov ecx, edx // ecx = in_ecx
  176. cpuid
  177. mov TCpuidResult.eax[esi], eax
  178. mov TCpuidResult.ebx[esi], ebx
  179. mov TCpuidResult.ecx[esi], ecx
  180. mov TCpuidResult.edx[esi], edx
  181. pop esi
  182. pop ebx
  183. end;
  184. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  185. begin
  186. CPUID(in_eax, in_ecx, result);
  187. end;
  188. function CPUBrandString: shortstring;
  189. begin
  190. if not cpuid_support or (CPUID($80000000).eax<$80000004) then
  191. exit('');
  192. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  193. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  194. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  195. result[49]:=#0;
  196. result[0]:=chr(length(PAnsiChar(@result[1])));
  197. end;
  198. function cr0 : longint;assembler;
  199. asm
  200. {$ifdef USE_REAL_INSTRUCTIONS}
  201. mov eax,cr0
  202. {$else}
  203. DB 0Fh,20h,0C0h
  204. {$endif}
  205. { mov eax,cr0
  206. special registers are not allowed in the assembler
  207. parsers }
  208. end;
  209. function floating_point_emulation : boolean;
  210. begin
  211. {!!!! I don't know currently the position of the EM flag }
  212. { $4 after Ralf Brown's list }
  213. floating_point_emulation:=(cr0 and $4)<>0;
  214. end;
  215. {$ASMMODE ATT}
  216. function XGETBV(i : dword) : int64;assembler;
  217. asm
  218. movl %eax,%ecx
  219. {$ifdef USE_REAL_INSTRUCTIONS}
  220. xgetbv
  221. {$else}
  222. // older FPCs don't know the xgetbv opcode
  223. .byte 0x0f,0x01,0xd0
  224. {$endif}
  225. end;
  226. procedure SetupSupport;
  227. var
  228. maxcpuidvalue : longint;
  229. cpuid1,cpuid7 : TCpuidResult;
  230. begin
  231. is_sse3_cpu:=false;
  232. if cpuid_support then
  233. begin
  234. maxcpuidvalue:=CPUID(0).eax;
  235. cpuid1:=CPUID(1);
  236. _CMOVSupport:=(cpuid1.edx and $8000)<>0;
  237. _AESSupport:=(cpuid1.ecx and $2000000)<>0;
  238. _POPCNTSupport:=(cpuid1.ecx and $800000)<>0;
  239. _SSE3Support:=(cpuid1.ecx and $1)<>0;
  240. _SSSE3Support:=(cpuid1.ecx and $200)<>0;
  241. _SSE41Support:=(cpuid1.ecx and $80000)<>0;
  242. _SSE42Support:=(cpuid1.ecx and $100000)<>0;
  243. _MOVBESupport:=(cpuid1.ecx and $400000)<>0;
  244. _F16CSupport:=(cpuid1.ecx and $20000000)<>0;
  245. _RDRANDSupport:=(cpuid1.ecx and $40000000)<>0;
  246. _AVXSupport:=
  247. { XGETBV suspport? }
  248. ((cpuid1.ecx and $08000000)<>0) and
  249. { xmm and ymm state enabled? }
  250. ((XGETBV(0) and %110)=%110) and
  251. { avx supported? }
  252. ((cpuid1.ecx and $10000000)<>0);
  253. is_sse3_cpu:=(cpuid1.ecx and $1)<>0;
  254. _FMASupport:=_AVXSupport and ((cpuid1.ecx and $1000)<>0);
  255. _LZCNTSupport:=(CPUID($80000001).ecx and $20)<>0;
  256. if maxcpuidvalue>=7 then
  257. begin
  258. cpuid7:=CPUID(7);
  259. _AVX2Support:=_AVXSupport and ((cpuid7.ebx and $20)<>0);
  260. _AVX512FSupport:=(cpuid7.ebx and $10000)<>0;
  261. _AVX512DQSupport:=(cpuid7.ebx and $20000)<>0;
  262. _RDSEEDSupport:=(cpuid7.ebx and $40000)<>0;
  263. _ADXSupport:=(cpuid7.ebx and $80000)<>0;
  264. _AVX512IFMASupport:=(cpuid7.ebx and $200000)<>0;
  265. _AVX512PFSupport:=(cpuid7.ebx and $4000000)<>0;
  266. _AVX512ERSupport:=(cpuid7.ebx and $8000000)<>0;
  267. _AVX512CDSupport:=(cpuid7.ebx and $10000000)<>0;
  268. _AVX512BWSupport:=(cpuid7.ebx and $40000000)<>0;
  269. _AVX512VBMISupport:=(cpuid7.ecx and $00000002)<>0;
  270. _AVX512VBMI2Support:=(cpuid7.ecx and $00000040)<>0;
  271. _VAESSupport:=(cpuid7.ecx and $00000200)<>0;
  272. _VCLMULSupport:=(cpuid7.ecx and $00000400)<>0;
  273. _AVX512VNNISupport:=(cpuid7.ecx and $00000800)<>0;
  274. _AVX512BITALGSupport:=(cpuid7.ecx and $00001000)<>0;
  275. _SHASupport:=(cpuid7.ebx and $20000000)<>0;
  276. _AVX512VLSupport:=(cpuid7.ebx and $80000000)<>0;
  277. _BMI1Support:=(cpuid7.ebx and $8)<>0;
  278. _BMI2Support:=(cpuid7.ebx and $100)<>0;
  279. _RTMSupport:=((cpuid7.ebx and $800)<>0) and (cpuid7.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  280. end;
  281. end;
  282. end;
  283. function InterlockedCompareExchange128Support : boolean;
  284. begin
  285. { 32 Bit CPUs have no 128 Bit interlocked exchange support,
  286. but it can simulated using RTM }
  287. result:=_RTMSupport;
  288. end;
  289. function CMOVSupport : boolean;
  290. begin
  291. result:=_CMOVSupport;
  292. end;
  293. function AESSupport : boolean;
  294. begin
  295. result:=_AESSupport;
  296. end;
  297. function AVXSupport: boolean;inline;
  298. begin
  299. result:=_AVXSupport;
  300. end;
  301. function AVX2Support: boolean;inline;
  302. begin
  303. result:=_AVX2Support;
  304. end;
  305. function AVX512FSupport: boolean;inline;
  306. begin
  307. result:=_AVX512FSupport;
  308. end;
  309. function AVX512DQSupport: boolean;inline;
  310. begin
  311. result:=_AVX512DQSupport;
  312. end;
  313. function AVX512IFMASupport: boolean;inline;
  314. begin
  315. result:=_AVX512IFMASupport;
  316. end;
  317. function AVX512PFSupport: boolean;inline;
  318. begin
  319. result:=_AVX512PFSupport;
  320. end;
  321. function AVX512ERSupport: boolean;inline;
  322. begin
  323. result:=_AVX512ERSupport;
  324. end;
  325. function AVX512CDSupport: boolean;inline;
  326. begin
  327. result:=_AVX512CDSupport;
  328. end;
  329. function AVX512BWSupport: boolean;inline;
  330. begin
  331. result:=_AVX512BWSupport;
  332. end;
  333. function AVX512VLSupport: boolean;inline;
  334. begin
  335. result:=_AVX512VLSupport;
  336. end;
  337. function AVX512VBMISupport: boolean;inline;
  338. begin
  339. result:=_AVX512VBMISupport;
  340. end;
  341. function AVX512VBMI2Support: boolean;inline;
  342. begin
  343. result:=_AVX512VBMI2Support;
  344. end;
  345. function VAESSupport: boolean;inline;
  346. begin
  347. result:=_VAESSupport;
  348. end;
  349. function VCLMULSupport: boolean;inline;
  350. begin
  351. result:=_VCLMULSupport;
  352. end;
  353. function AVX512VNNISupport: boolean;inline;
  354. begin
  355. result:=_AVX512VNNISupport;
  356. end;
  357. function AVX512BITALGSupport: boolean;inline;
  358. begin
  359. result:=_AVX512BITALGSupport;
  360. end;
  361. function RDSEEDSupport: boolean;inline;
  362. begin
  363. result:=_RDSEEDSupport;
  364. end;
  365. function ADXSupport: boolean;inline;
  366. begin
  367. result:=_ADXSupport;
  368. end;
  369. function SHASupport: boolean;inline;
  370. begin
  371. result:=_SHASupport;
  372. end;
  373. function FMASupport: boolean;inline;
  374. begin
  375. result:=_FMASupport;
  376. end;
  377. function POPCNTSupport: boolean;inline;
  378. begin
  379. result:=_POPCNTSupport;
  380. end;
  381. function LZCNTSupport: boolean;inline;
  382. begin
  383. result:=_LZCNTSupport;
  384. end;
  385. function SSE3Support: boolean;inline;
  386. begin
  387. result:=_SSE3Support;
  388. end;
  389. function SSSE3Support: boolean;inline;
  390. begin
  391. result:=_SSSE3Support;
  392. end;
  393. function SSE41Support: boolean;inline;
  394. begin
  395. result:=_SSE41Support;
  396. end;
  397. function SSE42Support: boolean;inline;
  398. begin
  399. result:=_SSE42Support;
  400. end;
  401. function MOVBESupport: boolean;inline;
  402. begin
  403. result:=_MOVBESupport;
  404. end;
  405. function F16CSupport: boolean;inline;
  406. begin
  407. result:=_F16CSupport;
  408. end;
  409. function RDRANDSupport: boolean;inline;
  410. begin
  411. result:=_RDRANDSupport;
  412. end;
  413. function RTMSupport: boolean;inline;
  414. begin
  415. result:=_RTMSupport;
  416. end;
  417. function BMI1Support: boolean;inline;
  418. begin
  419. result:=_BMI1Support;
  420. end;
  421. function BMI2Support: boolean;inline;
  422. begin
  423. result:=_BMI2Support;
  424. end;
  425. begin
  426. SetupSupport;
  427. end.