- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑以下代码( Compiler Explorer link ),在 gcc 和 clang 下编译,使用 -O3
优化:
#include <arm_neon.h>
void bug(int8_t *out, const int8_t *in) {
for (int i = 0; i < 2; i++) {
int8x16x4_t x;
x.val[0] = vld1q_s8(&in[16 * i]);
x.val[1] = x.val[2] = x.val[3] = vshrq_n_s8(x.val[0], 7);
vst4q_s8(&out[64 * i], x);
}
}
注意 :这是一个问题的最低可重现版本,在我实际的、更复杂的代码的许多不同功能中出现,其中充满了执行与上面完全不同的操作的算术/逻辑/置换指令。请不要批评和/或建议执行上述代码的不同方式,除非它对下面讨论的代码生成问题产生影响。
bug(signed char*, signed char const*): // @bug(signed char*, signed char const*)
ldr q0, [x1]
sshr v1.16b, v0.16b, #7
mov v2.16b, v1.16b
mov v3.16b, v1.16b
st4 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0], #64
ldr q0, [x1, #16]
sshr v1.16b, v0.16b, #7
mov v2.16b, v1.16b
mov v3.16b, v1.16b
st4 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0]
ret
至于gcc,它插入了很多不必要的操作,显然将最终输入到
st4
的寄存器清零。操作说明:
bug(signed char*, signed char const*):
sub sp, sp, #128
# mov x9, 0
# mov x8, 0
# mov x7, 0
# mov x6, 0
# mov x5, 0
# mov x4, 0
# mov x3, 0
# stp x9, x8, [sp]
# mov x2, 0
# stp x7, x6, [sp, 16]
# stp x5, x4, [sp, 32]
# str x3, [sp, 48]
ldr q0, [x1]
# stp x2, x9, [sp, 56]
# stp x8, x7, [sp, 72]
sshr v4.16b, v0.16b, 7
# str q0, [sp]
# ld1 {v0.16b - v3.16b}, [sp]
# stp x6, x5, [sp, 88]
mov v1.16b, v4.16b
# stp x4, x3, [sp, 104]
mov v2.16b, v4.16b
# str x2, [sp, 120]
mov v3.16b, v4.16b
st4 {v0.16b - v3.16b}, [x0], 64
### ldr q4, [x1, 16]
### add x1, sp, 64
### str q4, [sp, 64]
sshr v4.16b, v4.16b, 7
### ld1 {v0.16b - v3.16b}, [x1]
mov v1.16b, v4.16b
mov v2.16b, v4.16b
mov v3.16b, v4.16b
st4 {v0.16b - v3.16b}, [x0]
add sp, sp, 128
ret
我手动添加前缀
#
所有可以安全取出的指令,而不影响函数的结果。
###
为前缀的指令执行一次不必要的内存和返回(无论如何,
mov
之后的
### ld1 ...
指令覆盖了由该
ld1
指令加载的 4 个寄存器中的 3 个),并且可以被直接加载到
v0.16b
的单个加载替换-- 和
sshr
然后块中间的指令将使用
v0.16b
作为其源寄存器。
x
,作为局部变量,可以被单元化使用;即使不是,所有寄存器都已正确初始化,因此将它们清零只是为了立即用值覆盖它们是没有意义的。
__attribute__
或者我可以做的其他事情
gcc
生成健全的代码。
最佳答案
在当前开发版本的 gcc 上生成代码似乎有了很大改进,至少在这种情况下是这样。
安装后 gcc-snapshot
包(日期为 20210918),gcc 生成以下代码:
bug:
ldr q5, [x1]
sshr v4.16b, v5.16b, 7
mov v0.16b, v5.16b
mov v1.16b, v4.16b
mov v2.16b, v4.16b
mov v3.16b, v4.16b
st4 {v0.16b - v3.16b}, [x0], 64
ldr q4, [x1, 16]
mov v0.16b, v4.16b
sshr v4.16b, v4.16b, 7
mov v1.16b, v4.16b
mov v2.16b, v4.16b
mov v3.16b, v4.16b
st4 {v0.16b - v3.16b}, [x0]
ret
还不理想——至少两个
mov
通过更改
ldr
的目标寄存器,可以在每次迭代中删除指令和
sshr
,但比以前好多了。
关于c - 为什么带有 -O3 的 gcc 会不必要地清除本地 ARM NEON 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69488537/
jQuery attributeContainsPrefix [name^="value"] 对比 attributeStartsWith [name|="value"] 实际区别是什么? 最佳答案
在1.1部分在RFC 6749中,有四种角色:资源拥有者、资源服务器、客户端和授权服务器。 如果客户端和资源所有者是同一实体,OAuth 是否变得多余或不必要? 例如,我有一个封闭的 API 和一个面
我有一段代码,其中有一个带有保护子句的 raise 语句: def validate_index index # Change to SizeError raise ArgumentError
我看到了这篇文章( JPA Entity Lifecycle Events vs database trigger ),但它并没有像我在这里那样明确地询问: 当我插入 PK 值为 (null) 的行时
所以,我有一段代码看起来像 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ // Do something }
我是一名优秀的程序员,十分优秀!