cpu.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  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. {$IFDEF FPC_DOTTEDUNITS}
  24. uses
  25. System.SysUtils;
  26. {$ELSE FPC_DOTTEDUNITS}
  27. uses
  28. sysutils;
  29. {$ENDIF FPC_DOTTEDUNITS}
  30. type
  31. TCpuidResult = record
  32. eax, ebx, ecx, edx: uint32;
  33. end;
  34. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult; inline;
  35. function CPUBrandString: shortstring;
  36. function InterlockedCompareExchange128Support : boolean;inline;
  37. function CMOVSupport : boolean;inline;
  38. function AESSupport : boolean;inline;
  39. function AVXSupport : boolean;inline;
  40. function AVX2Support: boolean;inline;
  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 VAESSupport: boolean;inline;
  53. function VCLMULSupport: boolean;inline;
  54. function AVX512BITALGSupport: boolean;inline;
  55. function RDSEEDSupport: boolean;inline;
  56. function ADXSupport: boolean;inline;
  57. function SHASupport: boolean;inline;
  58. function FMASupport: boolean;inline;
  59. function CMPXCHG16BSupport: 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 att}
  77. var
  78. _AESSupport,
  79. _AVXSupport,
  80. _InterlockedCompareExchange128Support,
  81. _AVX2Support,
  82. _AVX512FSupport,
  83. _AVX512DQSupport,
  84. _AVX512IFMASupport,
  85. _AVX512PFSupport,
  86. _AVX512ERSupport,
  87. _AVX512CDSupport,
  88. _AVX512BWSupport,
  89. _AVX512VLSupport,
  90. _AVX512VBMISupport,
  91. _AVX512VBMI2Support,
  92. _CMPXCHG16BSupport,
  93. _VAESSupport,
  94. _VCLMULSupport,
  95. _AVX512VNNISupport,
  96. _AVX512BITALGSupport,
  97. _RDSEEDSupport,
  98. _ADXSupport,
  99. _SHASupport,
  100. _FMASupport,
  101. _POPCNTSupport,
  102. _LZCNTSupport,
  103. _SSE3Support,
  104. _SSSE3Support,
  105. _SSE41Support,
  106. _SSE42Support,
  107. _MOVBESupport,
  108. _F16CSupport,
  109. _RDRANDSupport,
  110. _RTMSupport,
  111. _BMI1Support,
  112. _BMI2Support: boolean;
  113. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  114. // ^ 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,
  115. // that's why this internal version with "out res" exists...
  116. // Win64: ecx = in_eax, edx = in_ecx, r8 = res.
  117. // SysV: edi = in_eax, esi = in_ecx, rdx = res.
  118. asm
  119. push %rbx
  120. {$ifndef win64}
  121. mov %rdx, %r8 // r8 = res
  122. {$endif}
  123. mov in_eax, %eax
  124. mov in_ecx, %ecx
  125. cpuid
  126. mov %eax, TCpuidResult.eax(%r8)
  127. mov %ebx, TCpuidResult.ebx(%r8)
  128. mov %ecx, TCpuidResult.ecx(%r8)
  129. mov %edx, TCpuidResult.edx(%r8)
  130. pop %rbx
  131. end;
  132. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  133. begin
  134. CPUID(in_eax, in_ecx, result);
  135. end;
  136. function CPUBrandString: shortstring;
  137. begin
  138. if CPUID($80000000).eax<$80000004 then
  139. exit('');
  140. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  141. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  142. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  143. result[49]:=#0;
  144. result[0]:=chr(length(PAnsiChar(@result[1])));
  145. end;
  146. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec; assembler;
  147. {
  148. win64:
  149. rcx ... pointer to result
  150. rdx ... target
  151. r8 ... NewValue
  152. r9 ... Comperand
  153. }
  154. {$ifdef win64}
  155. asm
  156. pushq %rbx
  157. { store result pointer for later use }
  158. pushq %rcx
  159. { load new value }
  160. movq (%r8),%rbx
  161. movq 8(%r8),%rcx
  162. { save target pointer for later use }
  163. movq %rdx,%r8
  164. { load comperand }
  165. movq (%r9),%rax
  166. movq 8(%r9),%rdx
  167. {$ifdef oldbinutils}
  168. .byte 0xF0,0x49,0x0F,0xC7,0x08
  169. {$else}
  170. lock cmpxchg16b (%r8)
  171. {$endif}
  172. { restore result pointer }
  173. popq %rcx
  174. { store result }
  175. movq %rax,(%rcx)
  176. movq %rdx,8(%rcx)
  177. popq %rbx
  178. end;
  179. {$else win64}
  180. {
  181. linux:
  182. rdi ... target
  183. [rsi:rdx] ... NewValue
  184. [rcx:r8] ... Comperand
  185. [rdx:rax] ... result
  186. }
  187. asm
  188. pushq %rbx
  189. movq %rsi,%rbx // new value low
  190. movq %rcx,%rax // comperand low
  191. movq %rdx,%rcx // new value high
  192. movq %r8,%rdx // comperand high
  193. {$ifdef oldbinutils}
  194. .byte 0xF0,0x48,0x0F,0xC7,0x0F
  195. {$else}
  196. lock cmpxchg16b (%rdi)
  197. {$endif}
  198. popq %rbx
  199. end;
  200. {$endif win64}
  201. function XGETBV(i : dword) : int64;assembler;
  202. asm
  203. {$ifndef win64}
  204. movq %rdi,%rcx
  205. {$endif win64}
  206. // older FPCs don't know the xgetbv opcode
  207. .byte 0x0f,0x01,0xd0
  208. andl $0xffffffff,%eax
  209. shlq $32,%rdx
  210. orq %rdx,%rax
  211. end;
  212. procedure SetupSupport;
  213. var
  214. maxcpuidvalue : longint;
  215. cpuid1,cpuid7 : TCpuidResult;
  216. begin
  217. maxcpuidvalue:=CPUID(0).eax;
  218. cpuid1:=CPUID(1);
  219. _InterlockedCompareExchange128Support:=(cpuid1.ecx and $2000)<>0;
  220. _AESSupport:=(cpuid1.ecx and $2000000)<>0;
  221. _POPCNTSupport:=(cpuid1.ecx and $800000)<>0;
  222. _SSE3Support:=(cpuid1.ecx and $1)<>0;
  223. _SSSE3Support:=(cpuid1.ecx and $200)<>0;
  224. _SSE41Support:=(cpuid1.ecx and $80000)<>0;
  225. _SSE42Support:=(cpuid1.ecx and $100000)<>0;
  226. _MOVBESupport:=(cpuid1.ecx and $400000)<>0;
  227. _F16CSupport:=(cpuid1.ecx and $20000000)<>0;
  228. _RDRANDSupport:=(cpuid1.ecx and $40000000)<>0;
  229. _AVXSupport:=
  230. { XGETBV suspport? }
  231. ((cpuid1.ecx and $08000000)<>0) and
  232. { xmm and ymm state enabled? }
  233. ((XGETBV(0) and %110)=%110) and
  234. { avx supported? }
  235. ((cpuid1.ecx and $10000000)<>0);
  236. is_sse3_cpu:=(cpuid1.ecx and $1)<>0;
  237. _FMASupport:=_AVXSupport and ((cpuid1.ecx and $1000)<>0);
  238. _CMPXCHG16BSupport:=(cpuid1.ecx and $2000)<>0;
  239. _LZCNTSupport:=(CPUID($80000001).ecx and $20)<>0;
  240. { very early x86-64 CPUs might not support eax=7 }
  241. if maxcpuidvalue>=7 then
  242. begin
  243. cpuid7:=CPUID(7);
  244. _AVX2Support:=_AVXSupport and ((cpuid7.ebx and $20)<>0);
  245. _AVX512FSupport:=(cpuid7.ebx and $10000)<>0;
  246. _AVX512DQSupport:=(cpuid7.ebx and $20000)<>0;
  247. _RDSEEDSupport:=(cpuid7.ebx and $40000)<>0;
  248. _ADXSupport:=(cpuid7.ebx and $80000)<>0;
  249. _AVX512IFMASupport:=(cpuid7.ebx and $200000)<>0;
  250. _AVX512PFSupport:=(cpuid7.ebx and $4000000)<>0;
  251. _AVX512ERSupport:=(cpuid7.ebx and $8000000)<>0;
  252. _AVX512CDSupport:=(cpuid7.ebx and $10000000)<>0;
  253. _SHASupport:=(cpuid7.ebx and $20000000)<>0;
  254. _AVX512BWSupport:=(cpuid7.ebx and $40000000)<>0;
  255. _AVX512VLSupport:=(cpuid7.ebx and $80000000)<>0;
  256. _AVX512VBMISupport:=(cpuid7.ecx and $00000002)<>0;
  257. _AVX512VBMI2Support:=(cpuid7.ecx and $00000040)<>0;
  258. _VAESSupport:=(cpuid7.ecx and $00000200)<>0;
  259. _VCLMULSupport:=(cpuid7.ecx and $00000400)<>0;
  260. _AVX512VNNISupport:=(cpuid7.ecx and $00000800)<>0;
  261. _AVX512BITALGSupport:=(cpuid7.ecx and $00001000)<>0;
  262. _BMI1Support:=(cpuid7.ebx and $8)<>0;
  263. _BMI2Support:=(cpuid7.ebx and $100)<>0;
  264. _RTMSupport:=((cpuid7.ebx and $800)<>0) and (cpuid7.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  265. end;
  266. end;
  267. function InterlockedCompareExchange128Support : boolean;inline;
  268. begin
  269. result:=_InterlockedCompareExchange128Support;
  270. end;
  271. function CMOVSupport : boolean;
  272. begin
  273. result:=true;
  274. end;
  275. function AESSupport : boolean;inline;
  276. begin
  277. result:=_AESSupport;
  278. end;
  279. function AVXSupport: boolean;inline;
  280. begin
  281. result:=_AVXSupport;
  282. end;
  283. function AVX2Support: boolean;inline;
  284. begin
  285. result:=_AVX2Support;
  286. end;
  287. function AVX512FSupport: boolean;inline;
  288. begin
  289. result:=_AVX512FSupport;
  290. end;
  291. function AVX512DQSupport: boolean;inline;
  292. begin
  293. result:=_AVX512DQSupport;
  294. end;
  295. function AVX512IFMASupport: boolean;inline;
  296. begin
  297. result:=_AVX512IFMASupport;
  298. end;
  299. function AVX512PFSupport: boolean;inline;
  300. begin
  301. result:=_AVX512PFSupport;
  302. end;
  303. function AVX512ERSupport: boolean;inline;
  304. begin
  305. result:=_AVX512ERSupport;
  306. end;
  307. function AVX512CDSupport: boolean;inline;
  308. begin
  309. result:=_AVX512CDSupport;
  310. end;
  311. function AVX512BWSupport: boolean;inline;
  312. begin
  313. result:=_AVX512BWSupport;
  314. end;
  315. function AVX512VLSupport: boolean;inline;
  316. begin
  317. result:=_AVX512VLSupport;
  318. end;
  319. function AVX512VBMISupport: boolean;inline;
  320. begin
  321. result:=_AVX512VBMISupport;
  322. end;
  323. function AVX512VBMI2Support: boolean;inline;
  324. begin
  325. result:=_AVX512VBMI2Support;
  326. end;
  327. function VAESSupport: boolean;inline;
  328. begin
  329. result:=_VAESSupport;
  330. end;
  331. function VCLMULSupport: boolean;inline;
  332. begin
  333. result:=_VCLMULSupport;
  334. end;
  335. function AVX512VNNISupport: boolean;inline;
  336. begin
  337. result:=_AVX512VNNISupport;
  338. end;
  339. function AVX512BITALGSupport: boolean;inline;
  340. begin
  341. result:=_AVX512BITALGSupport;
  342. end;
  343. function RDSEEDSupport: boolean;inline;
  344. begin
  345. result:=_RDSEEDSupport;
  346. end;
  347. function ADXSupport: boolean;inline;
  348. begin
  349. result:=_ADXSupport;
  350. end;
  351. function SHASupport: boolean;inline;
  352. begin
  353. result:=_SHASupport;
  354. end;
  355. function FMASupport: boolean;inline;
  356. begin
  357. result:=_FMASupport;
  358. end;
  359. function CMPXCHG16BSupport: boolean;inline;
  360. begin
  361. result:=_CMPXCHG16BSupport;
  362. end;
  363. function POPCNTSupport: boolean;inline;
  364. begin
  365. result:=_POPCNTSupport;
  366. end;
  367. function LZCNTSupport: boolean;inline;
  368. begin
  369. result:=_LZCNTSupport;
  370. end;
  371. function SSE3Support: boolean;inline;
  372. begin
  373. result:=_SSE3Support;
  374. end;
  375. function SSSE3Support: boolean;inline;
  376. begin
  377. result:=_SSSE3Support;
  378. end;
  379. function SSE41Support: boolean;inline;
  380. begin
  381. result:=_SSE41Support;
  382. end;
  383. function SSE42Support: boolean;inline;
  384. begin
  385. result:=_SSE42Support;
  386. end;
  387. function MOVBESupport: boolean;inline;
  388. begin
  389. result:=_MOVBESupport;
  390. end;
  391. function F16CSupport: boolean;inline;
  392. begin
  393. result:=_F16CSupport;
  394. end;
  395. function RDRANDSupport: boolean;inline;
  396. begin
  397. result:=_RDRANDSupport;
  398. end;
  399. function RTMSupport: boolean;inline;
  400. begin
  401. result:=_RTMSupport;
  402. end;
  403. function BMI1Support: boolean;inline;
  404. begin
  405. result:=_BMI1Support;
  406. end;
  407. function BMI2Support: boolean;inline;
  408. begin
  409. result:=_BMI2Support;
  410. end;
  411. begin
  412. SetupSupport;
  413. end.