gpt4 book ai didi

delphi - 代码检测到 MMX/SSE/AVX 但未检测到 AVX2

转载 作者:行者123 更新时间:2023-12-03 00:21:37 25 4
gpt4 key购买 nike

我希望有一种通用的方法来检测特定的 CPU 功能。对于此任务,我创建了此函数,该函数采用 EAX 叶编号、寄存器名称和位编号并返回 true 或 false。它适用于 MMX/SSEx/AVX (EAX=1),但无法检测到 AVX2 (EAX=7)。

CPU:i5-4670k操作系统:Windows 7

DetectCPUFeature('1','EDX',23) //DETECTS MMX CORRECTLY
DetectCPUFeature('1','EDX',25) //DETECTS SSE CORRECTLY
DetectCPUFeature('1','EDX',26) //DETECTS SSE2 CORRECTLY
DetectCPUFeature('1','ECX',0) //DETECTS SSE3 CORRECTLY
DetectCPUFeature('1','ECX',9) //DETECTS SSSE3 CORRECTLY
DetectCPUFeature('1','ECX',19) //DETECTS SSE4.1 CORRECTLY
DetectCPUFeature('1','ECX',20) //DETECTS SSE4.2 CORRECTLY
DetectCPUFeature('1','ECX',28) //DETECTS AVX CORRECTLY

DetectCPUFeature('7','EBX',5) //DOES NOT DETECT AVX2!

.

function DetectCPUFeature(EAX_Leaf_HEX,Register_Name:string;Bit:byte):boolean;
var _eax,_ebx,_ecx,_edx,EAX_Leaf,_Result: Longword;
x:integer;
Binary_mask:string;
Decimal_mask:int64;
begin

EAX_Leaf:=HexToInt(EAX_Leaf_HEX);
Binary_mask:='1';
for x:=1 to Bit do Binary_mask:=Binary_mask+'0';
Decimal_mask:=BinToInt(Binary_mask);

if AnsiUpperCase(Register_Name)='EDX' then
begin
asm
mov eax,EAX_Leaf // https://en.wikipedia.org/wiki/CPUID
db $0F,$A2 // db $0F,$A2 = CPUID instruction
mov _Result,edx
end;
end;

if AnsiUpperCase(Register_Name)='ECX' then
begin
asm
mov eax,EAX_Leaf
db $0F,$A2
mov _Result,ecx
end;
end;

if AnsiUpperCase(Register_Name)='EBX' then
begin
asm
mov eax,EAX_Leaf
db $0F,$A2
mov _Result,ebx
end;
end;

if (_Result and Decimal_mask) = Decimal_mask then DetectCPUFeature:=true
else DetectCPUFeature:=false;

end;

最佳答案

这种代码非常可疑,将 asm 与 Pascal 代码混合在一起。 asm block 中的代码修改了寄存器,但无法恢复它们。这很容易与编译器的寄存器使用发生冲突。我强烈建议您不要以这种方式混合使用 asm 和 Pascal。始终使用纯 Pascal 或纯 asm。

您需要一个函数来执行CPUID指令并返回结构中的所有寄存器。然后您可以使用 Pascal 代码从中挑选出您想要的内容。

此外,正如 @J... 指出的,在调用 CPUID 指令之前,您需要在 ECX 寄存器中指定子叶值。这是许多最近添加的 CPUID 参数的要求。

这是您需要的功能:

type
TCPUID = record
EAX: Cardinal;
EBX: Cardinal;
ECX: Cardinal;
EDX: Cardinal;
end;

function GetCPUID(Leaf, Subleaf: Cardinal): TCPUID;
asm
push ebx
push edi
mov edi, ecx
mov ecx, edx
cpuid
mov [edi+$0], eax
mov [edi+$4], ebx
mov [edi+$8], ecx
mov [edi+$c], edx
pop edi
pop ebx
end;

我是为 32 位代码编写的,但如果您也需要支持 64 位代码,那么添加支持很容易。

function GetCPUID(Leaf, Subleaf: Integer): TCPUID;
asm
{$IF Defined(CPUX86)}
push ebx
push edi
mov edi, ecx
mov ecx, edx
cpuid
mov [edi+$0], eax
mov [edi+$4], ebx
mov [edi+$8], ecx
mov [edi+$c], edx
pop edi
pop ebx
{$ELSEIF Defined(CPUX64)}
mov r9,rcx
mov ecx,r8d
mov r8,rbx
mov eax,edx
cpuid
mov [r9+$0], eax
mov [r9+$4], ebx
mov [r9+$8], ecx
mov [r9+$c], edx
mov rbx, r8
{$ELSE}
{$Message Fatal 'GetCPUID has not been implemented for this architecture.'}
{$IFEND}
end;

有了这个,您就可以调用 CPUID 传递任何值作为输入,并检索所有 4 个输出寄存器,然后您可以用它们做任何您想做的事情。

您创建位掩码的代码效率极低,而且与惯用语相去甚远。使用 1 shl N 在位置 N 处创建一个具有单个位集的值。

代码如下:

if (_Result and Decimal_mask) = Decimal_mask then DetectCPUFeature:=true 
else DetectCPUFeature:=false;

也与惯用语有些不同。通常会这样写:

DetectCPUFeature := value and mask <> 0;

您最终可能会得到如下所示的包装函数:

type
TCPUIDRegister = (regEAX, regEBX, regECX, regEDX);

function GetCPUIDRegister(CPUID: TCPUID; Reg: TCPUIDRegister): Cardinal;
begin
case Reg of
regEAX:
Result := CPUID.EAX;
regEBX:
Result := CPUID.EBX;
regECX:
Result := CPUID.ECX;
regEDX:
Result := CPUID.EDX;
end;
end;

function CPUFeatureEnabled(Leaf, Subleaf: Cardinal; Reg: TCPUIDRegister; Bit: Integer): Boolean;
var
value: Cardinal;
begin
value := GetCPUIDRegister(GetCPUID(Leaf, Subleaf), Reg);
Result := value and (1 shl Bit) <> 0;
end;

关于delphi - 代码检测到 MMX/SSE/AVX 但未检测到 AVX2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41507019/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com