- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在将索引的地址输入到扩展的内联汇编操作中的表中,但是 GCC 在不需要时生成额外的 lea
指令,即使在使用 -Ofast 时也是如此-fomit-frame-pointer
或 -Os -f...
。 GCC 使用 RIP 相关地址。
我正在创建一个函数,用于将两个连续位转换为由两部分组成的 XMM 掩码(每位 1 个四字掩码)。为此,我使用 _mm_cvtepi8_epi64
(内部 vpmovsxbq
)和一个 8 字节表中的内存操作数,其中位作为索引。
当我使用内部函数时,GCC 生成的代码与使用扩展内联汇编的代码完全相同。
我可以直接将内存操作嵌入到 ASM 模板中,但这将始终强制使用 RIP 相对寻址(而且我不喜欢强制自己采用变通方法)。
typedef uint64_t xmm2q __attribute__ ((vector_size (16)));
// Used for converting 2 consecutive bits (as index) into a 2-elem XMM mask (pmovsxbq)
static const uint16_t MASK_TABLE[4] = { 0x0000, 0x0080, 0x8000, 0x8080 };
xmm2q mask2b(uint64_t mask) {
assert(mask < 4);
#ifdef USE_ASM
xmm2q result;
asm("vpmovsxbq %1, %0" : "=x" (result) : "m" (MASK_TABLE[mask]));
return result;
#else
// bad cast (UB?), but input should be `uint16_t*` anyways
return (xmm2q) _mm_cvtepi8_epi64(*((__m128i*) &MASK_TABLE[mask]));
#endif
}
使用 -S
输出程序集(使用 USE_ASM
和不使用):
__Z6mask2by: ## @_Z6mask2by
.cfi_startproc
## %bb.0:
leaq __ZL10MASK_TABLE(%rip), %rax
vpmovsxbq (%rax,%rdi,2), %xmm0
retq
.cfi_endproc
我所期待的(我删除了所有多余的东西):
__Z6mask2by:
vpmovsxbq __ZL10MASK_TABLE(%rip,%rdi,2), %xmm0
retq
最佳答案
唯一的 RIP 相对寻址模式是 RIP + rel32
。 RIP + reg 不可用。
(在机器代码中,32 位代码曾经有 2 种冗余方式来编码 [disp32]
。x86-64 使用较短(无 SIB)形式作为 RIP 相关,较长的 SIB 形式作为 [sign_extended_disp32]
).
如果您使用 -fno-pie -no-pie
为 Linux 编译,GCC 将能够访问具有 32 位绝对地址的静态数据,因此它可以使用类似 的模式>__ZL10MASK_TABLE(,%rdi,2)
。这对于 MacOS 是不可能的,它的基地址总是在 2^32 以上; x86-64 MacOS 完全不支持 32 位绝对寻址。
在 PIE 可执行文件(或一般的 PIC 代码,如库)中,您需要一个 RIP 相关的 LEA 来设置索引静态数组。或者静态地址不适合 32 位和/或不是链接时间常量的任何其他情况。
是的,内在函数使得从窄源表达 pmovzx/sx
加载变得非常不方便,因为缺少内在函数的指针源版本。
*((__m128i*) &MASK_TABLE[mask]
不安全:如果禁用优化,您很可能会得到一个 movdqa
16 字节加载,但地址将错位。只有当编译器将负载折叠到 pmovzxbq
的内存操作数时才是安全的,它有一个 2 字节的内存操作数,因此不需要对齐。
事实上,当前的 GCC 确实使用 movdqa
16 字节加载编译您的代码,如 movdqa xmm0, XMMWORD PTR [rax+rdi*2]
在 reg-reg pmovzx
之前。这显然是一个错过的优化。 :( clang/LLVM(MacOS 安装为 gcc
)确实将负载折叠到 pmovzx
中。
安全的方法是 _mm_cvtepi8_epi64( _mm_cvtsi32_si128(MASK_TABLE[mask]) )
之类的,然后希望编译器将零扩展从 2 字节优化到 4 字节并折叠 movd
启用优化时加载。或者尝试使用 _mm_loadu_si32
进行 32 位加载,即使您真的想要 16 位。但是上次我尝试时,编译器无法将 64 位加载内在函数折叠到 pmovzxbw< 的内存操作数中
例如。 GCC 和 clang 仍然失败,但 ICC19 成功了。 https://godbolt.org/z/IdgoKV
我之前写过:
您对 pmovsx
的选择似乎很奇怪。您不需要符号扩展,所以我会选择 pmovzx
(_mm_cvt_epu8_epi64
)。不过,它实际上并没有在任何 CPU 上更高效。
查找表在这里工作,只需要少量静态数据。如果你的 mask 范围更大,你可能想看看 is there an inverse instruction to the movemask instruction in intel avx2?对于广播 + AND +(移位或比较)等替代策略。
如果您经常这样做,使用 4x 16 字节 vector 常量的整个缓存行可能是最好的,这样您就不需要 pmovzx
指令,只需索引到 的对齐表中>xmm2
或 __m128i
vector ,它们可以是任何其他 SSE 指令的内存源。使用 alignas(64)
获取同一缓存行中的所有常量。
如果您的目标是 Intel CPU,您还可以考虑 (intrinsics for) pdep
+ movd xmm0, eax
+ pmovzxbq
reg-reg与 BMI2。 (不过,pdep
在 AMD 上运行缓慢)。
关于c++ - GCC w/inline assembly & -Ofast 为内存操作数生成额外代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56985115/
我正在优化一个简单的遗传算法和神经网络,我正在 GCC 中摆弄一些选项以生成更快的可执行文件。 在我的代码中,我有一些断言,例如 mat mat_add(mat a, mat b) { ass
我在我的程序中使用 -Ofast gcc 选项导致延迟要求。我写了一个简单的测试程序: #include #include static double quiet_NaN = std::numer
我有一个关于最新 GCC 编译器(版本 >= 5)的问题,代码如下: #include void test_nan ( const float * const __restrict__ in
考虑以下测试程序: # include # include using namespace std; int main() { double y = 50.2944, yc = 63.2128
我在 Swift 中使用 Dictionary 实现本质上是缓存。性能远低于我的预期。我读过其他一些问题,例如 this one about array sorting这似乎表明 -Ofast 是答案
在 g++ 4.6(或更高版本)中,除了 -ffast-math 之外,-Ofast 还启用了哪些额外优化? 手册页说此选项“还启用了并非对所有符合标准的程序都有效的优化”。我在哪里可以找到有关这是否
重新编译旧程序使其输出错误结果。 我想知道为什么 . 我知道-Ofast可能“无视严格的标准合规性”,但我很好奇引擎盖下会发生什么。 我将程序简化为这个 最小示例 foo1.c : #include
我只是在阅读 gcc 手册以找出 -O3 之间的区别和 -Ofast . 对于 -O3 -O3 Optimize yet more. -O3 turns on all optimizations sp
在 xcode 5 中,优化级别引入了一个名为 -Ofast 的新级别。 (最快,积极的优化)。我应该何时以及如何使用此级别? 最佳答案 在 GCC 中,-Ofast 表示允许编译器忽略浮点数的有限精
#include int main(void) { int val = 500; printf("%d\n", (int)((long double)val / 500));
我在 http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#Optimize-Options 上的 gcc 文档中找到了 Ofast leve
我在 for 循环中实现了 OpenMP 并行化,其中我有一个 sum,这是导致我的代码变慢的主要原因。当我这样做时,我发现最终结果与我为非并行化代码(用 C 编写)获得的结果不同。所以首先,人们可能
我有一个 C 程序,其中包含 math.h 并使用该 header 中的 sqrt 函数。非常奇怪,当我不传递 -Ofast 标志时,我的代码无法编译。 如果我使用以下代码编译我的代码: gcc -s
我使用 gcc -pg 和 gprof 看到了奇怪的分析结果。 我找不到更好/更小的重现方法,因此我链接了我看到问题的实际代码。 我正在使用代码here ,使用 make prof 构建 gprof
这个问题在这里已经有了答案: Does rustc / cargo have a -march=native equivalent? (1 个回答) 关闭 2 年前。 Rust 是否具有 GCC 的
我正在将索引的地址输入到扩展的内联汇编操作中的表中,但是 GCC 在不需要时生成额外的 lea 指令,即使在使用 -Ofast 时也是如此-fomit-frame-pointer 或 -Os -f..
当使用 -O3 编译下面的基准代码时,它在延迟方面的差异给我留下了深刻的印象,所以我开始怀疑编译器是否通过某种方式删除代码来“作弊”。有办法检查吗?我可以安全地使用 -O3 进行基准测试吗?期望速度提
问题 我们有一个用于模拟任务的中型程序,我们需要对其进行优化。我们已经尽最大努力将源代码优化到我们编程技能的极限,包括使用 Gprof 和 Valgrind 进行分析。 最终完成后,我们希望在多个系统
类似于的SO问题What does gcc's ffast-math actually do? 并且与 Clang optimization levels 的 SO 问题相关,我想知道什么 clang
摘要 根据我的测试,使用 -O0 时 NSArray 的平均访问时间最快。我的测试代码访问长度为 0 到 10000 的所有数组的每个元素。 循环每个数组: start = mach_absolute
我是一名优秀的程序员,十分优秀!