cpu.pp 13 KB

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