SFINAE在组装?

Vin*_*ent 16 c++ assembly sfinae template-meta-programming c++17

是否可以使用元编程技巧在装配块上使用SFINAE?例如,检测处理器上是否有类似"CPUID"的指令:(这不是有效的代码,但说明了我想要实现的目标)

// This should work if `CPUID` is a valid instruction on the target architecture
template <
  class... T,
  class = decltype(sizeof...(T), asm volatile("CPUID":::)
>
bool f(T...) {
    return true;
}

// This should fail because `BLAH` is not an instruction
template <
  class... T,
  class = decltype(sizeof...(T), asm volatile("BLAH":::)
>
bool f(T...) {
    return true;
}
Run Code Online (Sandbox Code Playgroud)

Gri*_*tov 1

由于下列多种原因,不可能实现问题中所阐述的内容。然而,通过概括这个想法,它可能会变得有意义,可以包含到该语言的未来修订中。

不起作用的原因:

  1. asm 块对于 C++ 编译器来说是不透明的。此类块的语法是特定于编译器的。我认为 MS VC++ 不接受 GCC 和 Intel 编译器支持的 clobber 列表方式。此外,微软的 x86_64 编译器停止支持汇编块,因为它们迫使人们使用内在函数。顺便说一句,也许依赖内部函数的存在可以用来提供编译时 CPU 调度?这个想法可能值得探索。

  2. asm块是特定于目标架构的。还有其他方法可以在编译时检测目标体系结构。

  3. 指令存在/不存在的概念非常模糊。哪个实体有权对任何给定的表达式做出决定asm:将其文本转换为机器代码的汇编程序或运行实际代码的目标处理器本身?两种选择都有问题。

    • 例如,“MOV”是多种架构的流行助记名称。但在所有情况下都是相同的指令吗?与助记符绑定的语义在不相关的体系结构之间不太可能匹配。
    • 仅仅组装成功并不意味着它会执行得很好。例如,在 Intel 64 架构上,即使指令正确,也可能会出现#UD(未定义指令信号)错误,因为其行为取决于由操作系统控制的 CR0 和 CR4 寄存器的运行时值。无论如何,汇编程序都能很好地处理它。必须运行代码。但是如果我们进行交叉编译,并且由于目标处理器与主机处理器不匹配而无法运行怎么办?

事实上,如果不先执行不透明块,就无法知道它的结果。因此,编译器可能想要调用任意程序来返回一个值,然后该值将用于模板扩展。然后,这样的程序可以进行处理器或指令感应并返回其结果以进一步指导编译。

现在,这看起来足够抽象,足以成为一种语言功能,因为我们没有对此类外部程序的性质做出任何假设。仍然存在可移植性(+交叉编译)问题和安全性(运行外部程序有风险)问题。总而言之,对我来说,依赖从环境进入编译器的现有宏定义看起来更好。