据我所知,MSVC的编译选项告诉编译器使用特殊的可用指令是/arch。在clang/Linux上,我们可以使用-march=native来自动检测体系结构和“最佳”指令集。有没有一种方法可以用/arch实现同样的事情,即在当前硬件上找到这个选项的最佳参数?我在MSVC文档中找不到合适的选项。如果不存在,是否有其他解决方案(例如通过CMake)?
7dl7o3gd1#
MSVC的默认值是x86的/arch:SSE2,是x64的隐式默认值。所有版本的Windows 8.1 32位或更高版本都要求安装支持SSE 2,所有版本的Windows x64都必须将SSE 2支持作为x64平台定义的一部分。对于MSVC,只有当您选择/arch:AVX或/arch:AVX2时,才会将/arch:用于x86/x64。从技术上讲,在MSVC x86上,您可以使用/arch:IA86来尝试强制使用遗留x87指令而不是SSE/SSE 2,但这不是推荐的解决方案或场景。这也意味着代码永远不会匹配始终使用SSE/SSE 2的x64的行为。对于MSVC,当针对ARM 64平台上的Windows时,/arch:arm8.0或/arch:arm8.1的使用决定了编译器是否使用InterlockedIncrement的CPU指令。在Windows 11 for ARM 64上,整个操作系统都是使用/arch:arm8.1构建的。如果针对Windows 10 for ARM 64,您应该使用默认值(即/arch:arm8.0)。MSVC使用的另一个开关是/favor,用于Intel与AMD的优化选择。默认值是/favor:BLEND,这是两者之间的一个很好的折衷。通常情况下,只有当您专门针对Xbox(/favor:AMD64)或Intel ATOM(/favor:ATOM)时,才会使用显式/favor开关。例如,对于Xbox One,您使用/favor:AMD64 /arch:AVX。对于Xbox Series X,|S,你用/favor:AMD64 /arch:AVX2。对于Clang/Linux -march=native开关,我的理解是它从主机CPU获取信息以确定使用哪些设置,如果您正在构建仅打算在本地机器上运行的代码,这是有意义的。Clang -march与MSVC /arch的另一个区别是,如果你使用显式的intrinsic,Clang * 真的希望 * 你指定一个足够高的-march来使它有效。MSVC只是相信你知道你在做什么,如果你使用一个特定的intrinsic,你也需要避免在x64编译器中使用/arch:SSE2,因为它实际上并不支持这个选项,因为它是必需的:由于在CMake中没有一个很好的方法来告诉确切的目标架构,我使用一个构建变量设置为x86,x64,ARM,或ARM64用于Ninja场景,然后在CMake中按如下方式评估它。如果你使用VS MSBuild生成器,你可以从CMAKE_GENERATOR_PLATFORM变量中推断出来,通常通过-A设置,或者在最近的CMake中,你可以使用CMAKE_VS_PLATFORM_NAME_DEFAULT。
/arch:SSE2
/arch:AVX
/arch:AVX2
/arch:
/arch:IA86
/arch:arm8.0
/arch:arm8.1
InterlockedIncrement
/favor
/favor:BLEND
/favor:AMD64
/favor:ATOM
/favor:AMD64 /arch:AVX
/favor:AMD64 /arch:AVX2
-march=native
-march
/arch
x86
x64
ARM
ARM64
CMAKE_GENERATOR_PLATFORM
-A
CMAKE_VS_PLATFORM_NAME_DEFAULT
if(DEFINED VCPKG_TARGET_ARCHITECTURE) set(DIRECTX_ARCH ${VCPKG_TARGET_ARCHITECTURE}) elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Ww][Ii][Nn]32$") set(DIRECTX_ARCH x86) elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Xx]64$") set(DIRECTX_ARCH x64) elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Aa][Rr][Mm]$") set(DIRECTX_ARCH arm) elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Aa][Rr][Mm]64$") set(DIRECTX_ARCH arm64) elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Ww][Ii][Nn]32$") set(DIRECTX_ARCH x86) elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Xx]64$") set(DIRECTX_ARCH x64) elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Aa][Rr][Mm]$") set(DIRECTX_ARCH arm) elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Aa][Rr][Mm]64$") set(DIRECTX_ARCH arm64) endif() ... if(NOT (${DIRECTX_ARCH} MATCHES "^arm")) if(CMAKE_SIZEOF_VOID_P EQUAL 4) set(ARCH_SSE2 $<$<CXX_COMPILER_ID:MSVC>:/arch:SSE2> $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-msse2>) else() set(ARCH_SSE2 $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-msse2>) endif() target_compile_options(${PROJECT_NAME} PRIVATE ${ARCH_SSE2}) endif()
字符串
1条答案
按热度按时间7dl7o3gd1#
MSVC的默认值是x86的
/arch:SSE2
,是x64的隐式默认值。所有版本的Windows 8.1 32位或更高版本都要求安装支持SSE 2,所有版本的Windows x64都必须将SSE 2支持作为x64平台定义的一部分。对于MSVC,只有当您选择
/arch:AVX
或/arch:AVX2
时,才会将/arch:
用于x86/x64。从技术上讲,在MSVC x86上,您可以使用
/arch:IA86
来尝试强制使用遗留x87指令而不是SSE/SSE 2,但这不是推荐的解决方案或场景。这也意味着代码永远不会匹配始终使用SSE/SSE 2的x64的行为。对于MSVC,当针对ARM 64平台上的Windows时,
/arch:arm8.0
或/arch:arm8.1
的使用决定了编译器是否使用InterlockedIncrement
的CPU指令。在Windows 11 for ARM 64上,整个操作系统都是使用/arch:arm8.1
构建的。如果针对Windows 10 for ARM 64,您应该使用默认值(即/arch:arm8.0
)。MSVC使用的另一个开关是
/favor
,用于Intel与AMD的优化选择。默认值是/favor:BLEND
,这是两者之间的一个很好的折衷。通常情况下,只有当您专门针对Xbox(/favor:AMD64
)或Intel ATOM(/favor:ATOM
)时,才会使用显式/favor
开关。例如,对于Xbox One,您使用
/favor:AMD64 /arch:AVX
。对于Xbox Series X,|S,你用/favor:AMD64 /arch:AVX2
。对于Clang/Linux
-march=native
开关,我的理解是它从主机CPU获取信息以确定使用哪些设置,如果您正在构建仅打算在本地机器上运行的代码,这是有意义的。Clang
-march
与MSVC/arch
的另一个区别是,如果你使用显式的intrinsic,Clang * 真的希望 * 你指定一个足够高的-march
来使它有效。MSVC只是相信你知道你在做什么,如果你使用一个特定的intrinsic,你也需要避免在x64编译器中使用/arch:SSE2
,因为它实际上并不支持这个选项,因为它是必需的:由于在CMake中没有一个很好的方法来告诉确切的目标架构,我使用一个构建变量设置为
x86
,x64
,ARM
,或ARM64
用于Ninja场景,然后在CMake中按如下方式评估它。如果你使用VS MSBuild生成器,你可以从CMAKE_GENERATOR_PLATFORM
变量中推断出来,通常通过-A
设置,或者在最近的CMake中,你可以使用CMAKE_VS_PLATFORM_NAME_DEFAULT
。字符串