SFINAE 组装?
SFINAE on assembly?
是否可以使用元编程技巧允许 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;
}
由于下面列出的多种原因,不可能按照问题的表述方式实现问题中表述的内容。然而,通过概括这个想法,它可能会成为有意义的东西,包括到语言的某些未来修订版中。
不行的原因:
asm
块对 C++ 编译器是不透明的。此类块的语法是特定于编译器的。我认为 MS VC++ 接受 clobber 列表的方式与 GCC 和 Intel 编译器支持的方式不同。此外,Microsoft 的 x86_64 编译器停止支持汇编块,因为它们迫使人们使用内部函数。顺便说一句,也许依靠内在函数的存在可以用来提供编译时 CPU 调度?可能值得探索这个想法。
asm
块是特定于目标体系结构的。还有其他方法可以在编译时检测目标架构。
指令是 present/absent 的概念非常模糊。哪个实体有权对任何给定的 asm
表达式做出决定:将其文本翻译成机器代码的汇编程序或 运行 是实际代码的目标处理器本身?这两种选择都是有问题的。
- 例如,"MOV" 是许多体系结构的流行助记名称。但是在所有情况下都是相同的指令吗?绑定到助记符的语义不太可能在不相关的体系结构之间匹配。
- 仅仅组装成功并不意味着它会执行得很好。例如,在 Intel 64 架构上,一条指令可能会出现#UD(未定义指令信号)错误,即使它是正确的,因为它的行为取决于 运行 由操作系统控制的 CR0 和 CR4 寄存器的时间值。在任何情况下,汇编程序都能很好地处理它。必须 运行 代码。但是,如果我们进行交叉编译,并且由于目标处理器与主机处理器不匹配而不能 运行 怎么办?
实际上,如果不先执行不透明块,就无法知道它的结果。因此,编译器可能希望调用任意程序来 return 一个值,然后将其用于模板扩展。然后,这样的程序可以进行处理器或指令感应,return 其发现可以进一步指导编译。
现在这看起来足够抽象,可以成为一种语言特性,因为我们没有对这种外部程序的性质做出任何假设。仍然存在可移植性(+交叉编译)问题和安全性(运行使用外部程序是有风险的)问题。总而言之,在我看来,依赖从环境中进入编译器的现有宏定义更好。
是否可以使用元编程技巧允许 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;
}
由于下面列出的多种原因,不可能按照问题的表述方式实现问题中表述的内容。然而,通过概括这个想法,它可能会成为有意义的东西,包括到语言的某些未来修订版中。
不行的原因:
asm
块对 C++ 编译器是不透明的。此类块的语法是特定于编译器的。我认为 MS VC++ 接受 clobber 列表的方式与 GCC 和 Intel 编译器支持的方式不同。此外,Microsoft 的 x86_64 编译器停止支持汇编块,因为它们迫使人们使用内部函数。顺便说一句,也许依靠内在函数的存在可以用来提供编译时 CPU 调度?可能值得探索这个想法。asm
块是特定于目标体系结构的。还有其他方法可以在编译时检测目标架构。指令是 present/absent 的概念非常模糊。哪个实体有权对任何给定的
asm
表达式做出决定:将其文本翻译成机器代码的汇编程序或 运行 是实际代码的目标处理器本身?这两种选择都是有问题的。- 例如,"MOV" 是许多体系结构的流行助记名称。但是在所有情况下都是相同的指令吗?绑定到助记符的语义不太可能在不相关的体系结构之间匹配。
- 仅仅组装成功并不意味着它会执行得很好。例如,在 Intel 64 架构上,一条指令可能会出现#UD(未定义指令信号)错误,即使它是正确的,因为它的行为取决于 运行 由操作系统控制的 CR0 和 CR4 寄存器的时间值。在任何情况下,汇编程序都能很好地处理它。必须 运行 代码。但是,如果我们进行交叉编译,并且由于目标处理器与主机处理器不匹配而不能 运行 怎么办?
实际上,如果不先执行不透明块,就无法知道它的结果。因此,编译器可能希望调用任意程序来 return 一个值,然后将其用于模板扩展。然后,这样的程序可以进行处理器或指令感应,return 其发现可以进一步指导编译。
现在这看起来足够抽象,可以成为一种语言特性,因为我们没有对这种外部程序的性质做出任何假设。仍然存在可移植性(+交叉编译)问题和安全性(运行使用外部程序是有风险的)问题。总而言之,在我看来,依赖从环境中进入编译器的现有宏定义更好。