我正在寻找使用NEON内在函数测试128 NEON寄存器是否包含全零的最快方法。 我目前正在使用3个OR操作和2个MOV:
uint32x4_t vr = vorrq_u32(vcmp0, vcmp1);
uint64x2_t v0 = vreinterpretq_u64_u32(vr);
uint64x1_t v0or = vorr_u64(vget_high_u64(v0), vget_low_u64(v0));
uint32x2_t v1 = vreinterpret_u32_u64 (v0or);
uint32_t r = vget_lane_u32(v1, 0) | vget_lane_u32(v1, 1);
if (r == 0) { // do stuff }
这通过gcc转换为以下汇编代码:
VORR q9, q9, q10
VORR d16, d18, d19
VMOV.32 r3, d16[0]
VMOV.32 r2, d16[1]
VORRS r2, r2, r3
BEQ ...
有没有人想过更快的方法?
答案 0 :(得分:6)
虽然这个答案可能有点晚,但只有3条指令而没有额外的寄存器,有一种简单的方法可以进行测试:
[HttpPost] // some browsers have URL length limits
[ValidateInput(false)] // or throws HttpRequestValidationException
public ActionResult Index(string xHtml)
{
Response.ContentType = "application/pdf";
Response.AppendHeader(
"Content-Disposition", "attachment; filename=test.pdf"
);
using (var stringReader = new StringReader(xHtml))
{
using (Document document = new Document())
{
PdfWriter writer = PdfWriter.GetInstance(
document, Response.OutputStream
);
document.Open();
XMLWorkerHelper.GetInstance().ParseXHtml(
writer, document, stringReader
);
}
}
return new EmptyResult();
}
如果设置了128位NEON寄存器中的任何位,则返回值将为非零值。
答案 1 :(得分:2)
如果您要定位AArch64 NEON,则只需使用以下两条说明即可使用以下内容获取测试值:
inline uint64_t is_not_zero(uint32x4_t v)
{
uint64x2_t v64 = vreinterpretq_u64_u32(v);
uint32x2_t v32 = vqmovn_u64(v64);
uint64x1_t result = vreinterpret_u64_u32(v32);
return result[0];
}
答案 2 :(得分:1)
您似乎在寻找内在函数,这就是方法:
inline bool is_zero(int32x4_t v) noexcept
{
v = v == int32x4{};
return !int32x2_t(
vtbl2_s8(
int8x8x2_t{
int8x8_t(vget_low_s32(v)),
int8x8_t(vget_high_s32(v))
},
int8x8_t{0, 4, 8, 12}
)
)[0];
}
Nils Pipenbrinck的答案有一个缺陷,即他认为QC,累积饱和度标志是明确的。
答案 3 :(得分:0)
如果您有AArch64,您可以更轻松地完成它。他们为此设计了新的指令。
inline uint32_t is_not_zero(uint32x4_t v)
{
return vaddvq_u32(v);
}
答案 4 :(得分:0)
我会避免函数返回仅应解释为bool的整数值。更好的方法是,例如,定义一个辅助函数以返回4个泳道的最大无符号值:
inline uint32_t max_lane_value_u32(const uint32x4_t& v)
{
#if defined(_WIN32) && defined(_ARM64_)
// Windows 64-bit
return neon_umaxvq32(v);
#elif defined(__LP64__)
// Linux/Android 64-bit
return vmaxvq_u32(v);
#else
// Windows/Linux/Android 32-bit
uint32x2_t result = vmax_u32(vget_low_u32(v), vget_high_u32(v));
return vget_lane_u32(vpmax_u32(result, result), 0);
#endif
}
然后您可以使用:
if (0 == max_lane_value_u32(v))
{
...
}
在您的代码中,这样的功能在其他地方也可能有用。另外,您可以使用完全相同的代码编写 is_not_zero()函数,但是最好是返回 bool 的形式。
请注意,您需要定义一个辅助函数的唯一原因是因为vmaxvq_u32()在32位上不可用,并且可能不会在Windows的arm64_neon.h中从neon_umaxvq32()别名。