簡體   English   中英

交換具有C / gcc內在函數的NEON向量的一半:VSWP沒有內在函數嗎?

[英]Swap halves of a NEON vector with C/gcc intrinsics: no intrinsic for VSWP?

我正在嘗試使用NEON向量指令來做相對簡單的事情:給定uint64x2_t ,我想交換64位成員的位置。

再說,如果這是一個簡單的普通代碼:

typedef struct {
    U64 u[2];
} u64x2;


u64x2 swap(u64x2 in)
{
    u64x2 out;
    out.u[0] = in.u[1];
    out.u[1] = in.u[0];
    return out;
}

令人驚訝的是,我找不到它的內在因素。 顯然有一個針對它的匯編指令( VSWP ),但是沒有相應的內部指令。

真奇怪 這大約是一項微不足道的操作,因此它必須是可能的。 問題是:如何?

編輯 :供參考,使用@Jake回答godbolt結果: https ://godbolt.org/z/ueJ6nB。 沒有vswp ,但是vext效果很好。

沒錯,NEON內部函數不支持VSWP指令。

但是,您可以求助於VEXT指令,該指令也可以在內部函數中使用。

out = vextq_u64(in, in, 1);


或者,您可以使用vcombine (並祈禱編譯器不會搞亂它):

out = vcombine_U64(vget_high_u64(in), vget_low_u64(in));

但是請注意,編譯器在看到vcombine和/或vget時往往會生成FUBAR機器代碼。

留在前者,這是我的建議。

表達這種混洗的另一種方法是使用GNU C本機向量內建函數,該內建函數提供了與目標無關的方式來執行給定操作。 根據目標的支持,可以將編譯時常量混洗掩碼優化為立即混洗。 但是,取決於目標ISA的支持,運行時變量改組可能效率很低。

#include <arm_neon.h>

#ifndef __clang__
uint64x2_t swap_GNU_shuffle(uint64x2_t in)
{
    uint64x2_t mask = {1,0};
    uint64x2_t out = __builtin_shuffle (in, mask);
    return out;
}
#endif

Godbolt上的AArch64 gcc8.2實際上可以編譯為Jake建議的相同改組 ,而不是SWP:

swap_GNU_shuffle:
        ext     v0.16b, v0.16b, v0.16b, #8
        ret

Clang還優化了我們大多數對ext指令的pure-C嘗試,包括使用memcpy對您的普通結構進行類型雙關(punch)並返回的指令。 與GCC不同,后者沒有那么好的混洗優化器。 (在Godbolt上,將下拉菜單中的任何clang-O3 -target arm64一起使用-O3 -target arm64通常是在默認情況下構建的,支持多個目標ISA,這與GCC不同。)

因此,無論這些編譯器已經錯過了調整=通用和優化-mcpu=cortex-a53a57a75 ,否則ext實際上是一個不錯的選擇,也許不比swp其中有寫2個輸出寄存器,而不是邏輯寫作一個全角寄存器。 但是通常這對ARM來說不是問題。 大量的說明可以做到這一點,並且通常可以提高效率。

ARM的Cortex-A8時序信息對 vextvswp具有相同的編號(從QnQ輸出均為1個周期的延遲,而從QmQ輸出均為2個周期)。 我沒有檢查過較新的內核(或任何64位內核)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM