今天我遇到了一個奇怪的問題,在LLVM IR中使用浮點數鑄造。我使用Windows 10和llvm-3.5.2。我在用C寫的代碼:LLVM IR浮點數鑄造
#include <stdio.h>
int main() {
double b = 2.0;
float c = b;
printf("%d\n", c == 2.0);
return 0;
}
而且我用clang -S -emit-llvm
並獲得該LLVM IR:
@.str = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
; Function Attrs: nounwind
define i32 @main() #0 {
entry:
%retval = alloca i32, align 4
%b = alloca double, align 8
%c = alloca float, align 4
store i32 0, i32* %retval
store double 2.000000e+00, double* %b, align 8
%0 = load double* %b, align 8
%conv = fptrunc double %0 to float
store float %conv, float* %c, align 4
%1 = load float* %c, align 4
%conv1 = fpext float %1 to double
%cmp = fcmp oeq double %conv1, 2.000000e+00
%conv2 = zext i1 %cmp to i32
%call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32 %conv2) #1
ret i32 0
}
; Function Attrs: nounwind
declare i32 @printf(i8*, ...) #0
其中執行(llvm-as
和lli
後)給了0
不正確的結果!
這個問題似乎在fpext
這不是很直觀,因爲它應該是這個'安全'轉換(更好的方向比fptrunc
,這是從雙重到浮動)。
我是這麼認爲的,因爲當我改變這一行:
%cmp = fcmp oeq double %conv1, 2.000000e+00
這樣:
%cmp = fcmp oeq float %1, 2.000000e+00
然後將結果如預期1
。
所以我的問題是爲什麼這樣,爲什麼這種轉換失敗?這是LLVM中的一種錯誤嗎?或者存在這種類型轉換的更好方法?或者,也許我寫了一個不安全的代碼在C?如果是這樣,那麼在使用浮點數方面存在一個巨大的問題。我在執行此轉換時對叮噹聲沒有影響。例如,假設我想輸出上面的c
。然後我寫printf("%f", c)
和叮噹生成的代碼,使c
加倍之前,將其傳遞到printf
。結果又不正確。那麼如何安全地打印一個浮點數?如何安全地使用浮動?
我不確定這個問題是否也出現在Linux上。
在我的Linux機器LLVM 3.4鏘還生產鈣鎂磷肥雙,但計算你所期望的結果。 – box
我不遵循 - 爲什麼你期望'float'和'double'的確切比較是真實的?這是不能保證的。你問「如何打印一個浮動」,但你沒有在你的實際代碼中打印浮動。你見過這個嗎? https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html –
好吧,我明白了。你有一點,當混合這些類型時,我不應該期望一般的好結果。所以現在的問題是關於印刷浮標。正如我在使用'printf(「%f」,c)''在我的機器上使用上面的代碼嘗試這樣做時所寫的,我也得到了'0'。似乎printf破壞我的浮動(因爲它真的等於2.0f時勾選)。我不知道如何解決它。 – xan