2012-08-13 27 views
4

見上。我寫信給樣本功能:爲什麼LLVM不通過優化浮點指令?

source.ll:

define i32 @bleh(i32 %x) { 
entry: 
    %addtmp = add i32 %x, %x 
    %addtmp1 = add i32 %addtmp, %x 
    %addtmp2 = add i32 %addtmp1, %x 
    %addtmp3 = add i32 %addtmp2, %x 
    %addtmp4 = add i32 %addtmp3, 1 
    %addtmp5 = add i32 %addtmp4, 2 
    %addtmp6 = add i32 %addtmp5, 3 
    %multmp = mul i32 %x, 3 
    %addtmp7 = add i32 %addtmp6, %multmp 
    ret i32 %addtmp7 
} 

source-fp.ll:

define double @bleh(double %x) { 
entry: 
    %addtmp = fadd double %x, %x 
    %addtmp1 = fadd double %addtmp, %x 
    %addtmp2 = fadd double %addtmp1, %x 
    %addtmp3 = fadd double %addtmp2, %x 
    %addtmp4 = fadd double %addtmp3, 1.000000e+00 
    %addtmp5 = fadd double %addtmp4, 2.000000e+00 
    %addtmp6 = fadd double %addtmp5, 3.000000e+00 
    %multmp = fmul double %x, 3.000000e+00 
    %addtmp7 = fadd double %addtmp6, %multmp 
    ret double %addtmp7 
} 

爲什麼,當我使用

opt -O3 source[-fp].ll -o opt.source[-fp].ll -S

的同時優化功能3210得到優化,但double一個不?我預計fadd將合併爲一個fmul。相反,它看起來完全一樣。

這是由於標誌設置不同嗎?我知道i32可能對double不可行的某些優化。但是缺乏簡單的不斷摺疊是我無法理解的。

我正在使用LLVM 3.1。

+3

高度相關,雖然我不確定它是否是重複的:[爲什麼不GCC優化a * a * a * a * a到(a * a * a)*(a * a * a )?](http://stackoverflow.com/q/6430448/395760) – delnan 2012-08-13 21:33:28

+3

@delan這與許多類似的浮點問題一樣,確實是重複的。即使問題的細節有所不同,答案也是一樣的。這個問題的任何好的答案都會指出浮點算術和提及 - 數學 - 數學的非關聯性,就像這個問題的接受答案一樣。 – 2012-08-13 21:41:40

+0

謝謝你們兩位。鏈接問題的答案提出了http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html,並強調了其中的歧義部分。 – f00id 2012-08-13 21:44:27

回答

7

這是不完全正確的說,沒有優化是可能的。我會去通過第幾行,以顯示其中轉換是和不準:

%addtmp = fadd double %x, %x 

這第一行可以安全地轉化爲fmul double %x 2.0e+0,但實際上並不是在大多數架構優化(fadd一般爲快或比fmul快,並且不需要產生常數2.0)。請注意,禁止溢出,這個操作是準確的(就像所有按2的冪進行縮放)。

%addtmp1 = fadd double %addtmp, %x 

該行可以轉換爲fmul double %x 3.0e+0。爲什麼這是一個合法的轉變?因爲產生%addtmp的計算是準確的,所以只有一次舍入被髮生,無論這是計算爲x * 3還是x + x + x。由於這些是IEEE-754基本操作,因此正確舍入,結果是相同的。什麼溢出?除非另一方也如此,否則都不會溢出。

%addtmp2 = fadd double %addtmp1, %x 

這是無法合法轉換爲常量* x的第一行。 4 * x會精確計算,沒有任何舍入,而x + x + x + x會導致兩次舍入:x + x + x舍入一次,然後再次舍入x可能會舍入一次。

%addtmp3 = fadd double %addtmp2, %x 

同上這裏; 5 * x會產生一個舍入; x + x + x + x + x招致三人。

唯一可能進行轉換的行將替換x + x + x3 * x。但是,子表達式x + x已經存在於其他地方,所以優化器可以輕鬆地選擇不使用此轉換(因爲如果不存在,它可以利用現有的部分結果)。

+0

謝謝你的詳細解答。那麼做一個'fmul double%x 2.0e + 0'並且不斷傳播結果仍然比重複'fadd'慢?或者我缺少舍入問題? – f00id 2012-08-13 22:05:42

+0

'2 * x'和'x + x'在數值上是等價的;然而,在常見架構中,'x + x'不會比'2 * x'更慢(有時更快),所以優化器通常沒有理由使用'2 * x'。 – 2012-08-13 22:10:28

+0

但是計算'x + x'兩次(然後加上'x')看起來比執行像'%y1 = fadd double%x,%x','%y2 = fadd double%y1,%y1' %res = fadd double%y2,%x'。我不想強調'fmul'這可能是誤導性的。 – f00id 2012-08-13 22:41:42