clang 8.0.0从c ++ 20引入了对char8_t
类型的支持。但是,我希望以下函数具有相同的编译器输出
#include <algorithm>
bool compare4(char const* pcha, char const* pchB, int n) {
return std::equal(pcha, pcha+4, pchB);
}
bool compare4(char8_t const* pchA, char8_t const* pchB, int n) {
return std::equal(pchA, pchA+4, pchB);
}
但是,他们-std=c++2a -O2
下的compile到
compare4(char const*, char const*, int): # @compare4(char const*, char const*, int)
mov eax, dword ptr [rdi]
cmp eax, dword ptr [rsi]
sete al
ret
_Z8compare4PKDuS0_i: # @_Z8compare4PKDuS0_i
mov al, byte ptr [rdi]
cmp al, byte ptr [rsi]
jne .LBB1_4
mov al, byte ptr [rdi + 1]
cmp al, byte ptr [rsi + 1]
jne .LBB1_4
mov al, byte ptr [rdi + 2]
cmp al, byte ptr [rsi + 2]
jne .LBB1_4
mov al, byte ptr [rdi + 3]
cmp al, byte ptr [rsi + 3]
sete al
ret
.LBB1_4:
xor eax, eax
ret
显然,后者的优化程度较差。
是否有原因(我在标准中找不到)或这是clang中的错误?
答案 0 :(得分:4)
这不是Clang中的“错误”;只是错过的优化机会。
您可以使用相同的函数replicate the Clang compiler output并使用基础类型为enum class
的{{1}}。相比之下,GCC会识别基础类型为unsigned char
和unsigned char
的枚举数之间的差异。它为char8_t
和unsigned char
发出相同的代码,但为char8_t
情况发出更复杂的代码。
因此,关于Clang enum class
的实现似乎更多地将其视为用户定义的枚举,而不是基本类型。最好只是将其视为该标准的早期实施。
应注意,char8_t
和unsigned char
之间最重要的区别之一是别名要求。 char8_t
指针可能还带有其他别名。相反,unsigned char
指针不能。因此,可以合理地预期(在 mature 实现上,而不是超出其实现的市场标准)在不同情况下发出不同的代码。诀窍在于,char8_t
代码如果有所不同,则应该更高,因为编译器不再需要发出执行额外工作来处理来自商店的潜在别名的代码。
答案 1 :(得分:4)
在libstdc ++中,std::equal
在检测到参数“简单”时调用__builtin_memcmp
,否则将使用朴素的for循环。这里的“简单”表示指向相同整数或指针类型的指针(或指针周围的某些迭代器包装器)。(relevant source code)
__is_integer
特征是否检测到类型是否为整数类型,但是libstdc ++ 8.2.0(godbolt.org上使用的版本)没有专门针对char8_t
定义此特征,因此后者未检测为整数类型。(relevant source code)__builtin_memcmp
情况相比, Clang(具有此特定配置)在for循环情况下生成的详细组装。 (但前者不一定在性能上有所优化。请参见Loop_unrolling。)
因此存在这种差异是有原因的,这不是IMO叮当声中的错误。