clang实现char8_t的方式是否存在缺陷,或者标准的某个黑暗角落是否禁止优化?
Is there a flaw in how clang implements char8_t or does some dark corner of the standard prohibit optimization?
clang 8.0.0 引入了对 C++20char8_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
下编译
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 中的错误?
-
在libstdc++中,当
std::equal
检测到参数是"简单"时,它会调用__builtin_memcmp
,否则它会使用朴素的for循环。这里的"简单"是指指向同一整数或指针类型的指针(或指针周围的某些迭代器包装器)。(相关源代码)- 一个类型是否是整数类型是由内部
__is_integer
特征检测的,但是libstdc++ 8.2.0(godbolt.org 上使用的版本)并没有将此特征专门用于char8_t
,因此后者不会被检测为整数类型。相关源代码)
- 一个类型是否是整数类型是由内部
-
Clang (使用此特定配置)在 for 循环情况下生成的程序集比在
__builtin_memcmp
情况下生成更详细的程序集。
所以这种差异是有原因的,这不是 clang IMO 中的错误。
这不是 Clang 中的"错误";只是错失了优化的机会。
您可以使用采用基础类型为unsigned char
的enum class
的相同函数来复制 Clang 编译器输出。相比之下,GCC 识别具有基础类型的unsigned char
和char8_t
的枚举器之间的差异。它为unsigned char
和char8_t
发出相同的代码,但对于enum class
情况发出更复杂的代码。
因此,关于 Clang 的char8_t
实现,似乎更多地将其视为用户定义的枚举,而不是基本类型。最好将其视为标准的早期实施。
应该注意的是,unsigned char
和char8_t
之间最重要的区别之一是混叠要求。unsigned char
指针可能与几乎所有其他内容混叠。相比之下,char8_t
指针不能。因此,可以合理地期望(在成熟的实现上,而不是超过它实现到市场的标准)在不同情况下发出不同的代码。诀窍是,如果char8_t
代码不同,它应该更有效率,因为编译器不再需要发出执行额外工作的代码来处理来自存储的潜在别名。
- 标准是否使用多余的大括号(例如 T{{{10}}})定义列表初始化?
- 编译器如何在使用SFINAE的函数和标准函数之间确定两者是否可行
- this_thread::sleep_for和计时时钟之间的关系是否由C++11标准指定
- 标准是否严格定义了该程序应该如何编译?
- 这是否符合C++标准:双响双响,例如!!(-0.0).
- C++标准是否允许<double>在没有开销的情况下实现 std::可选
- 是否允许使用带有"w+"模式的 freopen 进行标准设置?
- 移动后是否需要重置标准::列表?
- 标准是否保证无捕获的 lambda 为空?
- C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?
- 声明后,gcc 的动态大小数组是否与标准数组有效相同?
- C++11 标准是否保证零值有符号整数的一元减号为零?
- 是否有一种标准方法来计算两个 asctime() 值之间的天数
- 是否存在经过认证(ISO 26262或类似)C++标准库?
- C++规范是否特别对待标准 t 库?
- 是否有任何 C 标准函数将值"1"传递给所有 (%s)
- C++标准:是否有结果对象?
- 使用给定种子生成的随机数序列是否保证在标准版本中相同?
- 在此初始值设定项方法上将整个数组设置为 NULL 是否C++标准?
- 是否C++标准支持流程