国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

x86平臺SIMD編程入門(1):SIMD基礎(chǔ)知識

這篇具有很好參考價值的文章主要介紹了x86平臺SIMD編程入門(1):SIMD基礎(chǔ)知識。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1、簡介

SIMD(Single Instruction, Multiple Data)是一種并行計算技術(shù),它通過向量寄存器存儲多個數(shù)據(jù)元素,并使用單條指令同時對這些數(shù)據(jù)元素進行處理,從而提高了計算效率。SIMD已被廣泛應(yīng)用于需要大量數(shù)據(jù)并行計算的領(lǐng)域,包括圖像處理、視頻編碼、信號處理、科學(xué)計算等。許多現(xiàn)代處理器都提供了SIMD指令集擴展,例如x86平臺的SSE/AVX,以及ARM平臺的NEON,本文只討論x86平臺下的SIMD指令。

在C++程序中使用SIMD指令有兩種方案,一種是使用內(nèi)聯(lián)匯編,另一種是使用intrinsic函數(shù)。以簡單的數(shù)組相乘為例,代碼的常規(guī)寫法、內(nèi)聯(lián)匯編寫法以及intrinsic函數(shù)寫法分別如下:

float a[4] = { 1.0, 2.0, 3.0, 4.0 };
float b[4] = { 5.0, 6.0, 7.0, 8.0 };
float c[4];

// 常規(guī)寫法,用循環(huán)實現(xiàn)數(shù)組相乘
for (int i = 0; i < 4; ++i)
{
    c[i] = a[i] * b[i];
}

// 使用SIMD指令的內(nèi)聯(lián)匯編
__asm
{
    movups xmm0, [a];  // 將a所指內(nèi)存的128位數(shù)據(jù)放入xmm0寄存器
    movups xmm1, [b];  // 將b所指內(nèi)存的128位數(shù)據(jù)放入xmm1寄存器
    mulps xmm0, xmm1;  // 計算xmm0 * xmm1(4個32位單精度浮點數(shù)對位相乘),結(jié)果放入xmm0
    movups[c], xmm0;   // 將xmm0的數(shù)據(jù)放入c所指內(nèi)存
}

// 使用intrinsic函數(shù)
__m128 va = _mm_loadu_ps(a);
__m128 vb = _mm_loadu_ps(b);
__m128 vc = _mm_mul_ps(va, vb);
_mm_storeu_ps(c, vc);

intrinsic函數(shù)是對匯編指令的封裝,編譯時這些函數(shù)會被內(nèi)聯(lián)成匯編,所以不會產(chǎn)生函數(shù)調(diào)用的開銷。當(dāng)CPU不支持指令集時,intrinsic函數(shù)可能會模擬對應(yīng)的功能。完整的intrinsic函數(shù)使用指南可以參考Intel官方文檔。

2、指令集的發(fā)展

2.1、MMX

1996年,Intel推出了多媒體擴展指令集MMX(Multi-Media Extensions),它最初是為了加速多媒體應(yīng)用程序而設(shè)計的,共包含57條指令,可用于整數(shù)的加法、減法、乘法、邏輯運算和移位等。MMX引入了8個64位寄存器,被稱為MM0~MM7,每個寄存器可以被看做是2個32位整數(shù)、或是4個16位整數(shù)、或是8個8位整數(shù)。不過,這些MMX寄存器并不是獨立的寄存器,而是復(fù)用了浮點數(shù)寄存器,所以MMX指令和浮點數(shù)操作不能同時工作。

2.2、SSE

SSE(Streaming SIMD Extensions)指令集發(fā)布于1999年,作為對MMX指令集的增強和擴展。SSE支持單精度浮點數(shù)運算以及整數(shù)運算等指令,并引入了8個獨立的128位寄存器,稱為XMM0~XMM7。后續(xù)發(fā)布的SSE2指令集則一方面添加了對雙精度浮點數(shù)的支持,另一方面也增添了整數(shù)處理指令,這些新的整數(shù)處理指令能夠覆蓋MMX指令的功能,從而讓舊的MMX指令顯得多余。2003年,AMD推出AMD64架構(gòu)時,又新增了8個XMM寄存器,它們被稱為XMM8~XMM15。當(dāng)CPU處于32位模式時,可用的XMM寄存器為XMM0~XMM7,而當(dāng)CPU處于64位模式時,可用的XMM寄存器為XMM0~XMM15。此后推出的SSE3/SSE4又添加了更多了SIMD指令。

2.3、AVX

2011年,AVX(Advanced Vector Extensions)指令集將浮點運算寬度從128位擴展到了256位,新的寄存器名為YMM0~YMM15,其128位的下半部分仍可作為XMM0~XMM15訪問。2013年,AVX2將整數(shù)運算指令擴展至256位,同時也支持了FMA(Fused Multiply Accumulate)指令。2016年,AVX-512將浮點與整數(shù)運算寬度擴展到了512位,主要用于多媒體信息處理、科學(xué)計算、數(shù)據(jù)加密和壓縮、以及深度學(xué)習(xí)等高性能計算場景。

2.4、對比總結(jié)

每一代的指令集都兼容上一代,也就是說新一代的指令集也支持使用上一代的指令和寄存器(但硬件實現(xiàn)可能有區(qū)別)。此外,AVX對之前的部分指令進行了重構(gòu),所以不同代際之間相同功能的函數(shù)可能具有不同的接口。不同代際的指令盡量不要混用,因為每次狀態(tài)切換會有性能消耗,從而拖慢程序的運行速度。代際之間對寄存器及其位寬的更新情況如下:

指令集 寄存器 浮點位寬 整型位寬
MMX MM0~MM7 64
SSE XMM0~XMM7 128
SSE2 XMM0~XMM15 128 128
AVX YMM0~YMM15 256 128
AVX2 YMM0~YMM15 256 256

3、SIMD編程基礎(chǔ)

3.1、頭文件

#include <mmintrin.h>   // MMX
#include <xmmintrin.h>  // SSE(include mmintrin.h)
#include <emmintrin.h>  // SSE2(include xmmintrin.h)
#include <pmmintrin.h>  // SSE3(include emmintrin.h)
#include <tmmintrin.h>  // SSSE3(include pmmintrin.h)
#include <smmintrin.h>  // SSE4.1(include tmmintrin.h)
#include <nmmintrin.h>  // SSE4.2(include smmintrin.h)
#include <ammintrin.h>  // SSE4A
#include <wmmintrin.h>  // AES(include nmmintrin.h)
#include <immintrin.h>  // AVX, AVX2, FMA(include wmmintrin.h)
  • 每一代SIMD指令集的頭文件如上,實際使用時只需包含最高支持的指令集頭文件即可。
  • SSE4A是AMD獨有的指令集,除<ammintrin.h>之外的每一個頭文件都包含了它前面的那個頭文件。
  • 部分編譯器還有<zmmintrin.h>用于支持AVX-512。
  • 如果想要包含全部頭文件,在GCC/Clang環(huán)境下可以包含頭文件<x86intrin.h>,在MSVC環(huán)境下則需要包含<intrin.h>

3.2、內(nèi)存對齊

有很多SIMD指令都要求內(nèi)存對齊。例如SSE指令_mm_load_ps就要求輸入地址是16字節(jié)對齊的,否則可能導(dǎo)致程序崩潰或者得不到正確結(jié)果;如果程序無法保證輸入地址是對齊的,那就得使用不要求內(nèi)存對齊的版本_mm_loadu_ps。內(nèi)存不對齊的版本通常運行更慢,不過在較新的CPU上這種性能差距已經(jīng)基本可以忽略了。

在棧上內(nèi)存定義變量時,可以使用如下兩種方法進行16字節(jié)的內(nèi)存對齊:

_MM_ALIGN16 float a[4] = { 1.0, 2.0, 3.0, 4.0 }; //_MM_ALIGN16是頭文件xmmintrin.h中定義的宏
alignas(16) float b[4] = { 5.0, 6.0, 7.0, 8.0 }; //alignas是C++11中引入的關(guān)鍵字

對于堆上分配的動態(tài)內(nèi)存,可用下列函數(shù)進行16字節(jié)對齊內(nèi)存的分配與釋放:

float* a = (float*)_aligned_malloc(4 * sizeof(float), 16);
_aligned_free(a);

3.3、數(shù)據(jù)類型

SIMD指令使用自定義的數(shù)據(jù)類型,例如__m64、__m128__m128d、__m128i等。它們的命名通常由3部分組成:

  1. 前序:統(tǒng)一為__m
  2. 位寬:例如64、128256、512
  3. 類型:i表示整型(int),d表示雙精度浮點型(double),什么都不加表示單精度浮點型(float)

以AVX中的256位數(shù)據(jù)類型為例,它們的定義如下:

typedef union __declspec(intrin_type) __declspec(align(32)) __m256 {
    float m256_f32[8];
} __m256;

typedef struct __declspec(intrin_type) __declspec(align(32)) __m256d {
    double m256d_f64[4];
} __m256d;

typedef union  __declspec(intrin_type) __declspec(align(32)) __m256i {
    __int8              m256i_i8[32];
    __int16             m256i_i16[16];
    __int32             m256i_i32[8];
    __int64             m256i_i64[4];
    unsigned __int8     m256i_u8[32];
    unsigned __int16    m256i_u16[16];
    unsigned __int32    m256i_u32[8];
    unsigned __int64    m256i_u64[4];
} __m256i;

SIMD寄存器將自己暴露為上面這樣的數(shù)據(jù)類型供C++程序員使用,在匯編代碼中,相同位寬的數(shù)據(jù)類型對應(yīng)著同樣的寄存器,它們的區(qū)別僅在于C++的類型檢查。

編譯器會自動為寄存器分配變量,但寄存器的數(shù)量是有限的。如果定義了太多局部變量,并且代碼依賴關(guān)系復(fù)雜導(dǎo)致編譯器無法重復(fù)使用寄存器,那么部分變量可能會從寄存器中轉(zhuǎn)移到內(nèi)存上,某些情況下這會使得性能下降。

對于這些向量類型,雖然編譯器將它們定義為內(nèi)部包含數(shù)組的結(jié)構(gòu)體或聯(lián)合體,程序員可以使用這些數(shù)組來訪問向量的各個通道,但這樣的性能可能并不理想,因為編譯器在執(zhí)行此類代碼時可能會將數(shù)據(jù)在寄存器和內(nèi)存之間來回轉(zhuǎn)移。所以建議不要這樣處理SIMD向量數(shù)據(jù),而應(yīng)當(dāng)盡量使用洗牌、插入、提取等intrinsic函數(shù)來完成此類操作。

3.4、運算模式

浮點數(shù)運算模式可以分為packed和scalar兩類。packed模式一次對寄存器中的四個浮點數(shù)進行計算,而scalar模式一次只對寄存器中最低的一個浮點數(shù)進行計算。

x86平臺SIMD編程入門(1):SIMD基礎(chǔ)知識

3.5、函數(shù)命名

SIMD指令的intrinsic函數(shù)命名風(fēng)格如下:

_mm<bit_width>_<name>_<data_type>

第一部分mm<bit_width>表示數(shù)據(jù)向量的位寬,例如_mm代表64或128位,_mm256代表256位,_mm512代表512位。

第二部分<name>表示函數(shù)的功能,例如load、addstore等。此外也可以追加一個修飾字符來實現(xiàn)某種特殊作用,例如:

修飾字符 示例 作用
u loadu [unaligned] 允許內(nèi)存未對齊
s adds/subs [saturate] 當(dāng)運算結(jié)果超出數(shù)據(jù)范圍時,會被限制為該范圍的上限或者下限
h hadd/hsub [horizontal] 水平方向上做加減法
hi/lo mulhi/mullo [high/low] 相乘后保留高位/低位
r setr [reverse] 逆序初始化向量
fm fmadd/fmsub [fused multiply add] FMA運算

第三部分<data_type>表示數(shù)據(jù)類型,如下表所示:

數(shù)據(jù)標識 含義
epi8/epi16/epi32 有符號的8/16/32位整數(shù)向量
epu8/epu16/epu32 無符號的8/16/32位整數(shù)向量
si128/si256 未指定的128位/256位向量
ps packed single
ss scalar single
pd packed double
sd scalar double

3.6、指令集支持

MSVC沒有提供檢測指令集支持性的方法。而對于GCC來說,可以使用編譯選項來啟用各種指令集,也可以在代碼中使用宏來判斷是否支持對應(yīng)的指令集:

GCC編譯選項
-mmmx __MMX__
-msse __SSE__
-msse2 __SSE2__
-msse3 __SSE3__
-mssse3 __SSSE3__
-msse4.1 __SSE4_1__
-msse4.2 __SSE4_2__
-mavx __AVX__
-mavx2 __AVX2__

若要檢測CPU是否支持特定的SIMD指令集,可以參考這個開源項目,它包含了多種系統(tǒng)環(huán)境下檢測指令集的代碼。下面這段代碼改編自上述開源項目,可以在MSVC x86環(huán)境下檢測CPU對SIMD指令集的支持情況:

#include <intrin.h>

int main()
{
    int info[4];

    __cpuid(info, 0);
    unsigned int maximum_eax = info[0];

    if (maximum_eax >= 1)
    {
        __cpuid(info, 1);
        unsigned int ecx = info[2];
        unsigned int edx = info[3];
        bool has_mmx = edx & (1 << 23);
        bool has_sse = edx & (1 << 25);
        bool has_sse2 = edx & (1 << 26);
        bool has_sse3 = ecx & (1 << 0);
        bool has_ssse3 = ecx & (1 << 9);
        bool has_sse4_1 = ecx & (1 << 19);
        bool has_sse4_2 = ecx & (1 << 20);
        bool has_avx = ecx & (1 << 28);
        bool has_aes = ecx & (1 << 25);
    }

    if (maximum_eax >= 7)
    {
        __cpuidex(info, 7, 0);
        unsigned int ebx = info[1];
        unsigned int ecx = info[2];
        unsigned int edx = info[3];
        bool has_avx2 = ebx & (1 << 5);
        bool has_avx512_f = ebx & (1 << 16);
        bool has_avx512_dq = ebx & (1 << 17);
        bool has_avx512_ifma = ebx & (1 << 21);
        bool has_avx512_pf = ebx & (1 << 26);
        bool has_avx512_er = ebx & (1 << 27);
        bool has_avx512_cd = ebx & (1 << 28);
        bool has_avx512_bw = ebx & (1 << 30);
        bool has_avx512_vl = ebx & (1 << 31);
        bool has_avx512_vbmi = ecx & (1 << 1);
        bool has_avx512_vbmi2 = ecx & (1 << 6);
        bool has_avx512_vnni = ecx & (1 << 11);
        bool has_avx512_bitalg = ecx & (1 << 12);
        bool has_avx512_vpopcntdq = ecx & (1 << 14);
        bool has_avx512_4vnniw = edx & (1 << 2);
        bool has_avx512_4fmaps = edx & (1 << 3);
        bool has_avx512_vp2intersect = edx & (1 << 8);
    }
}

3.7、混用AVX/SSE

AVX采用了更寬的256位向量和新指令,并使用了新的VEX編碼格式。 不過AVX也包含128位的VEX編碼指令,它們相當(dāng)于傳統(tǒng)SSE的128位指令。

指令 編碼方式 使用的寄存器
256位AVX指令 VEX 256位YMM寄存器
128位AVX指令 VEX 對YMM低128位進行操作,并將高128位清零
128位傳統(tǒng)SSE指令 legacy 對XMM(即YMM的低128位)進行操作,并且不關(guān)心YMM的高128位

AVX指令與傳統(tǒng)(非VEX編碼)SSE指令混合使用時可能會導(dǎo)致性能下降,因為當(dāng)從AVX指令轉(zhuǎn)換到傳統(tǒng)SSE指令時,硬件會保存YMM寄存器高128位的內(nèi)容,然后在SSE轉(zhuǎn)換回AVX時恢復(fù)這些值,保存和恢復(fù)操作都會花費幾十個時鐘周期。

避免這種性能損失最簡單的方法就是使用編譯器標志-mavx(對于Windows則是/arch:avx),這會強制編譯器為128位指令進行VEX格式編碼。如果確實無法避免AVX與傳統(tǒng)SSE的轉(zhuǎn)換(例如需要調(diào)用使用了傳統(tǒng)SSE指令的庫),可以使用_mm256_zeroupper將YMM寄存器的高128位清零,這樣硬件就無需保存這些值,另外需要注意的是,_mm256_zeroupper指令必須在256位AVX指令之后、SSE指令之前調(diào)用,這樣才可以取消保存和還原操作,其它方法(例如XOR)不起作用。關(guān)于AVX-SSE混用問題的詳細應(yīng)對策略可以參考Intel官方文檔Avoiding AVX-SSE Transition Penalties。文章來源地址http://www.zghlxwxcb.cn/news/detail-741776.html

到了這里,關(guān)于x86平臺SIMD編程入門(1):SIMD基礎(chǔ)知識的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 服務(wù)器基礎(chǔ)知識:aarch64 arm64 arm x86有什么區(qū)別

    aarch64 和 arm64 是指基于ARM架構(gòu)的64位處理器,而 arm 是指基于ARM架構(gòu)的32位處理器。 x86 則是指基于x86架構(gòu)的處理器。 架構(gòu): aarch64 、 arm64 和 arm 都屬于ARM架構(gòu),而 x86 屬于x86架構(gòu)。 位數(shù): aarch64 和 arm64 是64位處理器架構(gòu),能夠使用64位的寄存器和指令集。 arm 是32位處理器架構(gòu)

    2024年02月08日
    瀏覽(33)
  • Spring AOP入門指南:輕松掌握面向切面編程的基礎(chǔ)知識

    Spring AOP入門指南:輕松掌握面向切面編程的基礎(chǔ)知識

    1.1 什么是AOP? AOP(Aspect Oriented Programming)面向切面編程,一種編程范式,指導(dǎo)開發(fā)者如何組織程序結(jié)構(gòu)。 OOP(Object Oriented Programming)面向?qū)ο缶幊?我們都知道OOP是一種編程思想,那么AOP也是一種編程思想,編程思想主要的內(nèi)容就是指導(dǎo)程序員該如何編寫程序,所以它們兩個是不同

    2024年02月03日
    瀏覽(29)
  • Java入門高頻考查算法邏輯基礎(chǔ)知識3-編程篇(超詳細18題1.8萬字參考編程實現(xiàn))

    準備這些面試題時,請考慮如下準備步驟: 理解問題并澄清任何可能的疑點。確保你了解了面試官的期望,包括問題限制條件和期望的解決方案。 如果可能且適用的話,嘗試先給出一個簡單的解決方案,比如暴力法,然后再逐步優(yōu)化它。 在優(yōu)化之前,先分析暴力解法的效率

    2024年01月18日
    瀏覽(27)
  • 快速上手MATLAB:科研、工程、數(shù)據(jù)分析,MATLAB入門(下)教你基礎(chǔ)知識!分享《MATLAB初學(xué)者教程 MATLAB編程-菜鳥入門(清晰版)》

    快速上手MATLAB:科研、工程、數(shù)據(jù)分析,MATLAB入門(下)教你基礎(chǔ)知識!分享《MATLAB初學(xué)者教程 MATLAB編程-菜鳥入門(清晰版)》

    1、《MATLAB完全學(xué)習(xí)手冊(視頻+課件+代碼)》 2、《MATLAB入門》 3、《詳解MATLAB在科學(xué)計算中的應(yīng)用》 4、《案例二 MATLAB與Excel交互》 5、《MATLAB初學(xué)者教程 MATLAB編程-菜鳥入門(清晰版)》 6、《MATLAB常用函數(shù)參考 MATLAB函數(shù)匯總 精通MATLAB》 7、等等。。。。 前兩天,我們在(

    2024年02月07日
    瀏覽(111)
  • 韋東山嵌入式Liunx入門驅(qū)動開發(fā)一(Hello 驅(qū)動編程、GPIO基礎(chǔ)知識、LED驅(qū)動、總線設(shè)備驅(qū)動模型)

    韋東山嵌入式Liunx入門驅(qū)動開發(fā)一(Hello 驅(qū)動編程、GPIO基礎(chǔ)知識、LED驅(qū)動、總線設(shè)備驅(qū)動模型)

    本人學(xué)習(xí)完韋老師的視頻,因此來復(fù)習(xí)鞏固,寫以筆記記之。 韋老師的課比較難,第一遍不知道在說什么,但是堅持看完一遍,再來復(fù)習(xí),基本上就水到渠成了。 看完視頻復(fù)習(xí)的同學(xué)觀看最佳! 基于 IMX6ULL-PRO 參考視頻 Linux快速入門到精通視頻 參考資料 :01_嵌入式Linux應(yīng)用

    2024年04月25日
    瀏覽(96)
  • x86 平臺運行 arm 的方法

    參考: https://github.com/multiarch/qemu-user-static 核心是使用 binfmt_misc 設(shè)定運行 arm 的默認程序為 qemu-aarch64-static 1.先下載 arm64 即 aarch64 的運行文件 2.設(shè)置默認打開方式, 即設(shè)置 binfmt_misc 以支持 arm64 程序的運行 # --reset 會刪除同名條目后重新設(shè)置 3.測試 4.不用映射qemu-*-static也可以使用

    2024年02月12日
    瀏覽(24)
  • docker在x86平臺下載arm的鏡像

    docker在x86平臺下載arm的鏡像

    6、進入該arm版本的詳細頁面,在該頁面的上方有本版本鏡像的sha校驗值。 7、復(fù)制該值,使用如下命令在x86平臺上進行下載即可。 docker pull nginx:latest@sha256:687e0e4a235ee770533f6c25fb5791b14d7b6aa603ba4ed724abbd2ed51ee11a 8、完成下載,如圖:

    2024年02月12日
    瀏覽(31)
  • Mac x86 Ollama使用入門

    Mac上可以本地運行大模型,作為Mac x86硬件,比較好的選擇是Ollama,但有一些準備工作,需要明確一下,否則坑也會比較多。 1、下載地址:?官網(wǎng) 2、也可以通過安裝Docker Desktop(下載:?x86 Docker Desktop),再下載Docker官方的Ollama。 3、安裝Ollama并運行命令:ollama run gemma 4、安裝

    2024年04月26日
    瀏覽(25)
  • 并發(fā)編程的基礎(chǔ)知識

    并發(fā)編程的優(yōu)缺點 充分利用多核CPU的計算能力:通過并發(fā)編程的形式可以將多核CPU的計算能力發(fā)揮到極致,性能得到提升 方便進行業(yè)務(wù)拆分,提升系統(tǒng)并發(fā)能力和性能:在特殊的業(yè)務(wù)場景下,先天的就適合于并發(fā)編程?,F(xiàn)在的系統(tǒng)動不動就要求百萬級甚至千萬級的并發(fā)量,

    2024年02月06日
    瀏覽(23)
  • 網(wǎng)絡(luò)基礎(chǔ)知識&socket編程

    網(wǎng)絡(luò)基礎(chǔ)知識&socket編程

    Linux 系統(tǒng)是依靠互聯(lián)網(wǎng)平臺迅速發(fā)展起來的,所以它具有強大的網(wǎng)絡(luò)功能支持,也是Linux 系統(tǒng)的一大特點?;ヂ?lián)網(wǎng)對人類社會產(chǎn)生了巨大影響,它幾乎改變了人們生活的方方面面,可見互聯(lián)網(wǎng)對人類社會的重要性! 本章我們便來學(xué)習(xí)一些網(wǎng)絡(luò)基礎(chǔ)知識,如果感興趣的讀者可以

    2024年02月10日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包