cpu.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  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 SHA512Support: boolean;inline;
  52. function FMASupport: boolean;inline;
  53. function CMPXCHG16BSupport: boolean;inline;
  54. function POPCNTSupport: boolean;inline;
  55. function LZCNTSupport: boolean;inline;
  56. function SSE3Support: boolean;inline;
  57. function SSSE3Support: boolean;inline;
  58. function SSE41Support: boolean;inline;
  59. function SSE42Support: boolean;inline;
  60. function MOVBESupport: boolean;inline;
  61. function F16CSupport: boolean;inline;
  62. function RDRANDSupport: boolean;inline;
  63. function RTMSupport: boolean;inline;
  64. function BMI1Support: boolean;inline;
  65. function BMI2Support: boolean;inline;
  66. var
  67. is_sse3_cpu : boolean = false;
  68. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
  69. implementation
  70. {$asmmode att}
  71. var
  72. data: record
  73. cpuid1, cpuid7_0, cpuid7_1: TCpuidResult;
  74. AVXSupport,
  75. LZCNTSupport: boolean;
  76. end;
  77. procedure CPUID(in_eax: uint32; in_ecx: uint32; out res: TCpuidResult); assembler; nostackframe;
  78. // ^ 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,
  79. // that's why this internal version with "out res" exists...
  80. // Win64: ecx = in_eax, edx = in_ecx, r8 = res.
  81. // SysV: edi = in_eax, esi = in_ecx, rdx = res.
  82. asm
  83. push %rbx
  84. {$ifndef win64}
  85. mov %rdx, %r8 // r8 = res
  86. {$endif}
  87. mov in_eax, %eax
  88. mov in_ecx, %ecx
  89. cpuid
  90. mov %eax, TCpuidResult.eax(%r8)
  91. mov %ebx, TCpuidResult.ebx(%r8)
  92. mov %ecx, TCpuidResult.ecx(%r8)
  93. mov %edx, TCpuidResult.edx(%r8)
  94. pop %rbx
  95. end;
  96. function CPUID(in_eax: uint32; in_ecx: uint32 = 0): TCpuidResult;
  97. begin
  98. CPUID(in_eax, in_ecx, result);
  99. end;
  100. function CPUBrandString: shortstring;
  101. begin
  102. if CPUID($80000000).eax<$80000004 then
  103. exit('');
  104. TCpuidResult(pointer(@result[1])^):=CPUID($80000002);
  105. TCpuidResult(pointer(@result[17])^):=CPUID($80000003);
  106. TCpuidResult(pointer(@result[33])^):=CPUID($80000004);
  107. result[49]:=#0;
  108. result[0]:=chr(length(PAnsiChar(@result[1])));
  109. end;
  110. function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec; assembler;
  111. {
  112. win64:
  113. rcx ... pointer to result
  114. rdx ... target
  115. r8 ... NewValue
  116. r9 ... Comperand
  117. }
  118. {$ifdef win64}
  119. asm
  120. pushq %rbx
  121. { store result pointer for later use }
  122. pushq %rcx
  123. { load new value }
  124. movq (%r8),%rbx
  125. movq 8(%r8),%rcx
  126. { save target pointer for later use }
  127. movq %rdx,%r8
  128. { load comperand }
  129. movq (%r9),%rax
  130. movq 8(%r9),%rdx
  131. {$ifdef oldbinutils}
  132. .byte 0xF0,0x49,0x0F,0xC7,0x08
  133. {$else}
  134. lock cmpxchg16b (%r8)
  135. {$endif}
  136. { restore result pointer }
  137. popq %rcx
  138. { store result }
  139. movq %rax,(%rcx)
  140. movq %rdx,8(%rcx)
  141. popq %rbx
  142. end;
  143. {$else win64}
  144. {
  145. linux:
  146. rdi ... target
  147. [rsi:rdx] ... NewValue
  148. [rcx:r8] ... Comperand
  149. [rdx:rax] ... result
  150. }
  151. asm
  152. pushq %rbx
  153. movq %rsi,%rbx // new value low
  154. movq %rcx,%rax // comperand low
  155. movq %rdx,%rcx // new value high
  156. movq %r8,%rdx // comperand high
  157. {$ifdef oldbinutils}
  158. .byte 0xF0,0x48,0x0F,0xC7,0x0F
  159. {$else}
  160. lock cmpxchg16b (%rdi)
  161. {$endif}
  162. popq %rbx
  163. end;
  164. {$endif win64}
  165. function XGETBV(i : dword) : int64;assembler;
  166. asm
  167. {$ifndef win64}
  168. movq %rdi,%rcx
  169. {$endif win64}
  170. // older FPCs don't know the xgetbv opcode
  171. .byte 0x0f,0x01,0xd0
  172. andl $0xffffffff,%eax
  173. shlq $32,%rdx
  174. orq %rdx,%rax
  175. end;
  176. procedure SetupSupport;
  177. var
  178. maxcpuidvalue : longint;
  179. begin
  180. maxcpuidvalue:=CPUID(0).eax;
  181. CPUID(1, 0, data.cpuid1);
  182. { very early x86-64 CPUs might not support eax=7 }
  183. if maxcpuidvalue>=7 then
  184. begin
  185. CPUID(7, 0, data.cpuid7_0);
  186. CPUID(7, 1, data.cpuid7_1);
  187. end;
  188. is_sse3_cpu:=(data.cpuid1.ecx and (1 shl 0))<>0;
  189. data.AVXSupport:=
  190. { cpuid(1).ecx[27]: XGETBV support, cpuid(1).ecx[28]: AVX support }
  191. (data.cpuid1.ecx shr 27 and %11=%11) and
  192. { xmm and ymm state enabled? }
  193. ((XGETBV(0) and %110)=%110);
  194. data.LZCNTSupport:=(CPUID($80000001).ecx and (1 shl 5))<>0;
  195. end;
  196. function InterlockedCompareExchange128Support : boolean;inline;
  197. begin
  198. result:=(data.cpuid1.ecx and (1 shl 13))<>0;
  199. end;
  200. function CMOVSupport : boolean;
  201. begin
  202. result:=true;
  203. end;
  204. function AESSupport : boolean;inline;
  205. begin
  206. result:=(data.cpuid1.ecx and (1 shl 25))<>0;
  207. end;
  208. function AVXSupport: boolean;inline;
  209. begin
  210. result:=data.AVXSupport;
  211. end;
  212. function AVX2Support: boolean;inline;
  213. begin
  214. result:=data.AVXSupport and ((data.cpuid7_0.ebx and (1 shl 5))<>0);
  215. end;
  216. function AVX512FSupport: boolean;inline;
  217. begin
  218. result:=(data.cpuid7_0.ebx and (1 shl 16))<>0;
  219. end;
  220. function AVX512DQSupport: boolean;inline;
  221. begin
  222. result:=(data.cpuid7_0.ebx and (1 shl 17))<>0;
  223. end;
  224. function AVX512IFMASupport: boolean;inline;
  225. begin
  226. result:=(data.cpuid7_0.ebx and (1 shl 21))<>0;
  227. end;
  228. function AVX512PFSupport: boolean;inline;
  229. begin
  230. result:=(data.cpuid7_0.ebx and (1 shl 26))<>0;
  231. end;
  232. function AVX512ERSupport: boolean;inline;
  233. begin
  234. result:=(data.cpuid7_0.ebx and (1 shl 27))<>0;
  235. end;
  236. function AVX512CDSupport: boolean;inline;
  237. begin
  238. result:=(data.cpuid7_0.ebx and (1 shl 28))<>0;
  239. end;
  240. function AVX512BWSupport: boolean;inline;
  241. begin
  242. result:=(data.cpuid7_0.ebx and (1 shl 30))<>0;
  243. end;
  244. function AVX512VLSupport: boolean;inline;
  245. begin
  246. result:=(data.cpuid7_0.ebx and (1 shl 31))<>0;
  247. end;
  248. function AVX512VBMISupport: boolean;inline;
  249. begin
  250. result:=(data.cpuid7_0.ecx and (1 shl 1))<>0;
  251. end;
  252. function AVX512VBMI2Support: boolean;inline;
  253. begin
  254. result:=(data.cpuid7_0.ecx and (1 shl 6))<>0;
  255. end;
  256. function VAESSupport: boolean;inline;
  257. begin
  258. result:=(data.cpuid7_0.ecx and (1 shl 9))<>0;
  259. end;
  260. function VCLMULSupport: boolean;inline;
  261. begin
  262. result:=(data.cpuid7_0.ecx and (1 shl 10))<>0;
  263. end;
  264. function AVX512VNNISupport: boolean;inline;
  265. begin
  266. result:=(data.cpuid7_0.ecx and (1 shl 11))<>0;
  267. end;
  268. function AVX512BITALGSupport: boolean;inline;
  269. begin
  270. result:=(data.cpuid7_0.ecx and (1 shl 12))<>0;
  271. end;
  272. function RDSEEDSupport: boolean;inline;
  273. begin
  274. result:=(data.cpuid7_0.ebx and (1 shl 18))<>0;
  275. end;
  276. function ADXSupport: boolean;inline;
  277. begin
  278. result:=(data.cpuid7_0.ebx and (1 shl 19))<>0;
  279. end;
  280. function SHASupport: boolean;inline;
  281. begin
  282. result:=(data.cpuid7_0.ebx and (1 shl 29))<>0;
  283. end;
  284. function SHA512Support: boolean;inline;
  285. begin
  286. result:=(data.cpuid7_1.eax and 1)<>0;
  287. end;
  288. function FMASupport: boolean;inline;
  289. begin
  290. result:=data.AVXSupport and ((data.cpuid1.ecx and (1 shl 12))<>0);
  291. end;
  292. function CMPXCHG16BSupport: boolean;inline;
  293. begin
  294. result:=(data.cpuid1.ecx and (1 shl 13))<>0;
  295. end;
  296. function POPCNTSupport: boolean;inline;
  297. begin
  298. result:=(data.cpuid1.ecx and (1 shl 23))<>0;
  299. end;
  300. function LZCNTSupport: boolean;inline;
  301. begin
  302. result:=data.LZCNTSupport;
  303. end;
  304. function SSE3Support: boolean;inline;
  305. begin
  306. result:=(data.cpuid1.ecx and (1 shl 0))<>0;
  307. end;
  308. function SSSE3Support: boolean;inline;
  309. begin
  310. result:=(data.cpuid1.ecx and (1 shl 9))<>0;
  311. end;
  312. function SSE41Support: boolean;inline;
  313. begin
  314. result:=(data.cpuid1.ecx and (1 shl 19))<>0;
  315. end;
  316. function SSE42Support: boolean;inline;
  317. begin
  318. result:=(data.cpuid1.ecx and (1 shl 20))<>0;
  319. end;
  320. function MOVBESupport: boolean;inline;
  321. begin
  322. result:=(data.cpuid1.ecx and (1 shl 22))<>0;
  323. end;
  324. function F16CSupport: boolean;inline;
  325. begin
  326. result:=(data.cpuid1.ecx and (1 shl 29))<>0;
  327. end;
  328. function RDRANDSupport: boolean;inline;
  329. begin
  330. result:=(data.cpuid1.ecx and (1 shl 30))<>0;
  331. end;
  332. function RTMSupport: boolean;inline;
  333. begin
  334. result:=((data.cpuid7_0.ebx and (1 shl 11))<>0) and (data.cpuid7_0.edx and (1 shl 11)=0 {RTM_ALWAYS_ABORT});
  335. end;
  336. function BMI1Support: boolean;inline;
  337. begin
  338. result:=(data.cpuid7_0.ebx and (1 shl 3))<>0;
  339. end;
  340. function BMI2Support: boolean;inline;
  341. begin
  342. result:=(data.cpuid7_0.ebx and (1 shl 8))<>0;
  343. end;
  344. begin
  345. SetupSupport;
  346. end.