簡體   English   中英

如何使用 AVX2 和 SSE 從較大的整數轉換為較小的整數?

[英]How do I convert from larger integers to smaller integers using AVX2 and SSE?

有沒有一種有效的方法可以使用 AVX2 和 SSE 將較大的 integer 類型轉換為較小的 integer 類型(當然有截斷)?

如:

  • int16 -> int8
  • int32 -> int16 / int32 -> int8
  • int64 -> int32 / int64 -> int16 / int64 -> int8

我知道 AVX-512 有說明:

  • vpmovqb
  • vpmovwb

對應於內在函數,如:

  • _mm512_cvtepi16_epi8(AVX512 字節和字 ISA)
  • _mm512_cvtepi32_epi8(AVX512基金會)
  • _mm512_cvtepi32_epi16(AVX512基礎)
  • _mm512_cvtepi64_epi8(AVX512基礎)
  • _mm512_cvtepi64_epi16(AVX512基礎)
  • _mm512_cvtepi64_epi32(AVX512基金會)

哪個處理 integer 類型的縮小轉換,但是您如何在沒有此類指令的 AVX2 和 SSE 中完成此操作?

請注意,雖然上述 AVX512 內部函數有 128 位和 256 位重載,但它們在運行時仍需要 AVX512。 我正在尋找僅使用 AVX2 和/或 SSE 指令來完成相同任務的方法。

如果您不想給我我理解的完整答案,我知道這要問很多。 請向我解釋或幫助我找到可以為每次轉換復制的算法。

另請說明您的答案是否適用於有符號和無符號整數或其他。

非常感謝。

澄清; 我不打算稍后解壓這些數據。 我想在許多應用程序中使用矢量化縮小轉換,例如:

  • 代碼頁轉換(即UTF32 -> UTF8)(我知道不是轉換數據類型那么簡單)
  • 數據庫翻譯(連接2個完全不同的數據庫並在它們之間傳輸數據,其中表中單元格的數據類型不同)
  • 快速數學近似
  • 和更多!

幾乎可以做的任何事情: int32_t y = some_func(); int8_t x = static_cast<int8_t>(y);

但是矢量化了。 我已經測量了我們代碼的性能(抱歉,NDA,這里不能顯示),發現我們在類型轉換上花費了很多時間。 特別是縮小轉換。 編譯器在使用 AVX2 可用的指令對帶有符號擴展的小->大轉換進行矢量化方面做得很好,但縮小轉換似乎根本沒有被矢量化。

還要澄清一些。 我想要一種行為類似於 static_cast 的轉換方法(如截斷)

各種 PACK 指令將 int16->int8 或 int32->int16 從一對 mmx/xmm reg 轉換為單個 reg,有符號或無符號飽和(對於超出目標類型范圍的值)沒有 int64 ->int32 版本。

一種好方法是pshufb指令, _mm_shuffle_epi8 / _mm256_shuffle_epi8內在函數。 在現代 CPU 上,該指令非常快:延遲為 1 個周期,每個時鍾可以運行 2 個。

這是一個轉換 int64 -> int32 的示例,未經測試。 通過更改 shuffle 魔術向量,您可以用相同的代碼實現對話的 rest。

// Convert int64 lanes into int32 with truncation
inline __m128i cvtepi64_epi32( __m256i x )
{
    // Make a shuffle vector
    const __m256i shuffle = _mm256_setr_epi8(
        0, 1, 2, 3, 8, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 8, 9, 10, 11 );

    // Move these bytes
    // Unfortunately that instruction can only move within 16-byte halves.
    // Fortunately, it can selectively zero out bytes, so a bitwise OR is enough to combine
    x = _mm256_shuffle_epi8( x, shuffle );

    // Split into halves
    const __m128i low = _mm256_castsi256_si128( x );
    const __m128i high = _mm256_extracti128_si256( x, 1 );

    // Produce the result
    return _mm_or_si128( low, high );
}

對於 SSE 向量,它比 AVX2 更有效,您只需要一條_mm_shuffle_epi8指令。 順便說一句,對於 SSE 和 AVX,該指令可以直接從 memory 加載第二個參數,即即使該代碼沒有內聯,也不需要單獨加載來獲取置換常數。

PS 有符號/無符號與截斷無關,兩者的向下轉換操作相同。 有符號/無符號僅在您想要飽和而不是截斷時才重要,但static_cast不會使任何內容飽和,它會截斷。

暫無
暫無

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

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