簡體   English   中英

優化C代碼中的匯編代碼冗余

[英]Assembly code redundancy in optimized C code

我正在嘗試通過研究使用-O3優化在gcc中編譯的簡單C代碼來學習矢量化。 更具體地說,編譯器的矢量化程度如何。 這是一個個人的旅程,能夠通過更復雜的計算來驗證gcc -O3的性能。 我理解傳統的觀點是編譯器比人更好,但我從不認為這種智慧是理所當然的。

然而,在我的第一個簡單測試中,我發現一些選擇gcc非常奇怪,而且老實說,在優化方面非常疏忽。 我願意假設有一些編譯器是有目的的,並且知道一些關於CPU的信息(在這種情況下是Intel i5-2557M),我不知道。 但我需要知識淵博的人做一些確認。

我的簡單測試代碼(段)是:

int i;
float a[100];

for (i=0;i<100;i++) a[i]= (float) i*i;

與for循環對應的結果匯編代碼(段)如下:

.L6:                        ; loop starts here
    movdqa  xmm0, xmm1      ; copy packed integers in xmm1 to xmm0
.L3:
    movdqa  xmm1, xmm0      ; wait, what!?  WHY!?  this is redundant.
    cvtdq2ps    xmm0, xmm0  ; convert integers to float
    add rax, 16             ; increment memory pointer for next iteration
    mulps   xmm0, xmm0      ; pack square all integers in xmm0
    paddd   xmm1, xmm2      ; pack increment all integers by 4 
    movaps  XMMWORD PTR [rax-16], xmm0   ; store result 
    cmp rax, rdx            ; test loop termination
    jne .L6                 

我理解所有步驟,並且在計算上,所有步驟都是有道理的。 但是,我不明白, gcc選擇在迭代循環中加入一個步驟,在xmm0加載xmm1之后立即加載xmm1xmm0

 .L6
        movdqa  xmm0, xmm1      ; loop starts here
 .L3
        movdqa  xmm1, xmm0      ; grrr! 

僅這一點讓我質疑優化器的完整性。 顯然,額外的MOVDQA不會干擾數據,但從面值來看,它似乎在gcc方面顯得過於疏忽。

在匯編代碼(未示出)的早期, xmm0xmm2被初始化為對於矢量化有意義的某個值,因此很明顯,在循環開始時,代碼必須跳過第一個MOVDQA。 但是為什么gcc不會簡單地重新排列,如下所示。

.L3
        movdqa  xmm1, xmm0     ; initialize xmm1 PRIOR to loop
.L6
        movdqa  xmm0, xmm1     ; loop starts here 

或者甚至更好,只需初始化xmm1而不是xmm0並完全轉儲MOVDQA xmm1xmm0步驟!

我願意相信,CPU是足夠聰明跳過多余的步驟或類似的東西,但我怎么能相信GCC全面優化復雜的代碼,如果它甚至能得到這個簡單的代碼吧? 或者有人能提供一個合理的解釋,讓我相信gcc -O3是好東西嗎?

我不是100%肯定,但看起來你的循環通過將其轉換為float來破壞xmm0 ,所以你要在xmm1得到整數值,然后復制到另一個寄存器(在本例中為xmm0 )。

雖然已知編譯器有時會發出不必要的指令,但在這種情況下我無法真正看到這種情況。

如果你想讓xmm0 (或xmm1 )保持整數,那么對於i的第一個值,不要使用float xmm0 也許你想要做的是:

 for (i=0;i<100;i++) 
    a[i]= (float)(i*i);

但另一方面,gcc 4.9.2似乎沒有這樣做:

g++ -S -O3 floop.cpp

.L2:
    cvtdq2ps    %xmm1, %xmm0
    mulps   %xmm0, %xmm0
    addq    $16, %rax
    paddd   %xmm2, %xmm1
    movaps  %xmm0, -16(%rax)
    cmpq    %rbp, %rax
    jne .L2

clang也不是(大約3周前的3.7.0)

 clang++ -S -O3 floop.cpp


    movdqa  .LCPI0_0(%rip), %xmm0   # xmm0 = [0,1,2,3]
    xorl    %eax, %eax
    .align  16, 0x90
.LBB0_1:                                # %vector.body
                                        # =>This Inner Loop Header: Depth=1
    movd    %eax, %xmm1
    pshufd  $0, %xmm1, %xmm1        # xmm1 = xmm1[0,0,0,0]
    paddd   %xmm0, %xmm1
    cvtdq2ps    %xmm1, %xmm1
    mulps   %xmm1, %xmm1
    movaps  %xmm1, (%rsp,%rax,4)
    addq    $4, %rax
    cmpq    $100, %rax
    jne .LBB0_1

我編譯的代碼:

extern int printf(const char *, ...);

int main()
{
    int i;
    float a[100];

    for (i=0;i<100;i++)
        a[i]= (float) i*i;

    for (i=0; i < 100; i++)
        printf("%f\n", a[i]);
}

(我添加了printf以避免編譯器擺脫所有代碼)

暫無
暫無

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

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