[英]What is the correct way to fill a __m128i parameter, from basic type (such as short), to use with _mm256_broadcast_epi (such as _mm_broadcastw_epi16)
_mm256_broadcastb_epi8、_mm_broadcastw_epi16、_mm256_broadcastd_epi32和_mm256_broadcastq_epi64這四個函數都是VPBROADCASTB、VPBROADCASTW、VPBROADCASTD和VPBROADCASTQ指令的內在函數根據英特爾的文檔: “英特爾® 高級矢量擴展編程參考” ,這些指令可能會相應地接收 8 位、16 位、32 位、64 位內存位置。
第 5-230 頁:
源操作數是XMM寄存器中的8位、16位、32位、64位內存位置或低8位、16位、32位、64位數據
但是,這些指令的內在 API(Intel、MSVS 和 gcc)接收一個 __m128i 參數。 現在,如果我有一個基本類型的變量,據說是“short”,那么最有效和跨平台的方式(至少在 MSVS 和 gcc 之間)將該變量傳遞給相應的廣播內在函數(_mm_broadcastw_epi16 在短的情況下)是什么?
例如:
void func1(uint8_t v) {
__m256i a = _mm256_broadcastb_epi8(<convert_to__m128i>(v));
...
}
void func1(uint16t v) {
__m256i a = _mm256_broadcastw_epi16(<convert_to__m128i>(v));
...
}
void func1(uint32_t v) {
__m256i a = _mm256_broadcastd_epi32(<convert_to__m128i>(v));
...
}
void func1(uint64_t v) {
__m256i a = _mm256_broadcastq_epi64(<convert_to__m128i>(v));
...
}
<convert_to__m128i> 應該是什么,以便最高效和跨平台(如果可能)?
例如,對於 MSVS,可以執行以下操作:
void func1(uint16t v) {
__m128i vt;
vt.m128_u16[0] = v;
__m256i a = _mm256_broadcastw_epi16(vt);
...
}
但是如果沒有優化,它可以首先加載一個 xmm 寄存器,然后才在 VPBROADCASTW 中使用它。 當進行優化時,它可以直接使用 v 的內存位置。 它也僅對 MSVS 有效。
已經有序列/復合內在函數可以完全滿足您的要求:
_mm256_set1_epi8/16/32/64
來自英特爾的內在指南:
將 8 位整數 a 廣播到 dst 的所有元素。 這個內在函數可以生成 vpbroadcastb。
使用這些,您應該能夠信任編譯器生成最佳代碼。
在做這樣的事情時,我使用 Intel Intrinsics Guide,這很有幫助,因為您可以從助記符反向搜索(在這種情況下,您知道您最終想要 vpbroadcastb),它會告訴您哪些內在函數與之相關。
如果您有一個標量值開始,只需讓編譯器為_mm256_set1_epi8(scalar)
內在函數發出廣播指令,而不是__m128i
。
但是你通常也不想要_mm_broadcastb_epi8
( __m128i
結果) 或__m256i _mm256_broadcastb_epi8(__m128i)
除非你已經有一個__m128i
開始並想要低元素。
如果您不關心低 dword 的高 2 或 3 個字節,則在沒有編譯器浪費指令的情況下將標量放入__m128i
可能是 8 位或 16 位標量的實際問題; 它可能會將movzx
加載到一個整數寄存器中,然后使用vmovd
或類似的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.