2017-02-27 41 views
3

在大多數平臺上,alloca只是歸結爲堆棧指針的內聯調整(例如,從x64上的rsp減去另外一些邏輯以保持堆棧對齊)。gcc處理alloca有什麼用?

我在看代碼gcc爲alloca生成,這很奇怪。看看下面的簡單例子:

#include <alloca.h> 
#include <stddef.h> 

volatile void *psink; 

void func(size_t x) { 
    psink = alloca(x); 
} 

這編譯成以下大會-O2

func(unsigned long): 
     push rbp 
     add  rdi, 30 
     and  rdi, -16 
     mov  rbp, rsp 
     sub  rsp, rdi 
     lea  rax, [rsp+15] 
     and  rax, -16 
     mov  QWORD PTR psink[rip], rax 
     leave 
     ret 

這裏有幾個令人困惑的事情。我知道gcc需要將分配的大小舍入爲16的倍數(以保持堆棧對齊),通常的方法是(size + 15) & ~0xF,但是相反,它會在add rdi, 30處增加30個?那是怎麼回事?

其次,我只希望alloca的結果是新的rsp值,該值已經很好地一致。取而代之的是,gcc在此:

lea  rax, [rsp+15] 
    and  rax, -16 

這似乎是「重新調整」的rsp價值爲alloca結果使用 - 但我們已經做了對齊rsp到16字節邊界在第一工作地點。

這是怎麼回事?你可以玩on godbolt。值得注意的是,clangicc至少在x86上做了「預期的事情」。有了VLA(如之前的評論中所建議的),gccclang沒有問題,而icc產生了可憎的。


1這裏,分配給psink只是消耗的alloca結果,因爲否則編譯器只是省略了它完全。

+0

評論是不適合擴展討論;這個對話已經[轉移到聊天](http://chat.stackoverflow.com/rooms/136822/discussion-on-question-by-beeonrope-whats-up-with-gccs-handling-of-alloca)。 –

回答

7

這是一個很老的普通優先級bug。代碼正常工作。只是當大小大於1個字節時,不必要地分配了16個字節。所以這不是一個正確的錯誤,這是一個小小的效率錯誤。

+0

@BeeOnRope:我認爲這個答案確實回答了「這是怎麼回事?」這個問題。 。編譯器有一個產生低效代碼的已知錯誤。 –

+0

@BeeOnRope我只是強調正確性。關於性能,編譯器無法生成最佳代碼。鐺和icc生成一個不必要的mov指令。無論這些額外的指令對執行時間有何影響,在任何現代處理器上都會非常小。當使用alloca分配數組元素或許多小對象時,額外的堆棧空間是一個問題。您可能會用完堆棧。 –