assembly - 强制 clang 发出 pmull2/umull2 操作码变体
问题描述
我有这段(和类似的)代码,我希望在其中发出 umull2 或 pmull2 指令。编译器 clang-11.0.1,选项-O3 -std=c++11 -target aarch64
#include "stdint.h"
#include "arm_neon.h"
inline poly16x8_t vmull_low_p8(poly8x16_t a, poly8x16_t b) {
return vmull_p8(vget_low_p8(a), vget_low_p8(b));
}
// evaluates polynomials of length `len > 0` using Horner's method
// for 16 points `x`, `X = x 2^m mod n`
poly16x8x2_t p(const uint8_t *input, int len, poly8x16_t x, poly8x16_t X) {
auto ptr = input + len;
auto L = vdupq_n_p16(*--ptr), H = L;
while (ptr > input) {
auto s = vuzpq_p8(vreinterpretq_p8_p16(L), vreinterpretq_p8_p16(H));
auto a = vmull_low_p8(s.val[0], x);
auto b = vmull_high_p8(s.val[0], x);
auto A = vmull_low_p8(s.val[1], X);
auto B = vmull_high_p8(s.val[1], X);
auto C = vdupq_n_p16(*--ptr);
L = C ^ a ^ A;
H = C ^ b ^ B;
}
return {L,H};
}
而不是像这样的代码
ldrb w9, [x8, #-1]!
uzp1 v6.16b, v2.16b, v3.16b
uzp2 v2.16b, v2.16b, v3.16b
pmull v3.8h, v6.8b, v0.8b
pmull2 v7.8h, v6.8b, v0.8b
pmull v6.8h, v6.8b, v4.8b
pmull2 v2.8h, v2.8b, v4.8b
编译器选择
ldrb w9, [x8, #-1]!
uzp1 v6.16b, v2.16b, v3.16b
uzp2 v2.16b, v2.16b, v3.16b
pmull v3.8h, v6.8b, v0.8b
ext v6.16b, v6.16b, v6.16b, #8 // aligns top 8 bytes over bottom 8 bytes
pmull v7.8h, v2.8b, v1.8b // uses a copy of v0.8 also shifted by 8 bytes
ext v2.16b, v2.16b, v2.16b, #8
pmull v6.8h, v6.8b, v4.8b
pmull v2.8h, v2.8b, v5.8b
在 uint8x16_t 或 uint16x8_t 上工作并不重要——这似乎是 clang 避免访问寄存器的最高位的一个反复出现的主题。我还没有找到-mtune=cortex-73
一种会强制生成不同代码的选项,所以我至少可以评估这是否通常性能较低(我希望它在小内核上)。ARM64 gcc 按预期工作。
ext
如果已知指令与pmull
where 两个pmull
s 不会发生双重问题,这可能无关紧要(除了大小和分配的寄存器较少) 。
解决方案
推荐阅读
- sql - 如何为工作时间创建 SQL 查询
- c# - 如何更改 RectTransform 的锚点以更改面板的宽度?
- angular - 如何使用 Angular Material 为特定日期启用/禁用 Angular 日期选择器?
- pandas - 在 Python 中使用 Pandas 提高处理大型 csv 文件的速度
- django - Permission.objects.get() 方法在 Django 中为单元测试创建测试数据库时不起作用
- soapui - 访问WADL下其他资源中的资源响应内容
- packer - 如何使用打包器 hcl 动态创建多个磁盘
- wcf - 在 WCF 的自定义属性中抛出自定义异常
- terraform - Terraform - 创建对象地图
- kubernetes - Kubernetes 在非默认命名空间中拉取镜像错误