LLVM IR中printf无法处理浮点数

3
我想将浮点变量的值打印到屏幕上。我在LLVM IR代码中声明了printf()函数,并且它成功链接。
每当我打印整数、字符数据类型或字符串时,printf()会像在C代码中一样正常地将它们打印到屏幕上。然而,如果我将一个float传递给printf(),它会打印0.000000而不是浮点数。我多次检查源代码,语法似乎是正确的。它应该打印出2.75!我看着这段代码,完全不明白为什么代码的行为与我的写法不同。
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@obj1 = global {i32, float, i8} zeroinitializer

@format_string = constant [10 x i8] c"%i %f %c\0A\00"

declare i32 @printf(i8*, ...)

define i32 @main() {
entry:
    %obj1 = load {i32, float, i8}, {i32, float, i8}* @obj1

    %obj2 = insertvalue {i32, float, i8} %obj1, i32 44, 0
    %obj3 = insertvalue {i32, float, i8} %obj2, float 2.75, 1
    %obj4 = insertvalue {i32, float, i8} %obj3, i8 36, 2

    store {i32, float, i8} %obj4, {i32, float, i8}* @obj1

    %ptr.i32 = getelementptr {i32, float, i8}, {i32, float, i8}* @obj1, i32 0, i32 0
    %0 = load i32, i32* %ptr.i32
    %ptr.float = getelementptr {i32, float, i8}, {i32, float, i8}* @obj1, i32 0, i32 1
    %1 = load float, float* %ptr.float
    %ptr.i8 = getelementptr {i32, float, i8}, {i32, float, i8}* @obj1, i32 0, i32 2
    %2 = load i8, i8* %ptr.i8

    %format_ptr = getelementptr [10 x i8], [10 x i8]* @format_string, i64 0, i64 0
    call i32 (i8*, ...) @printf(i8* %format_ptr, i32 %0, float %1, i8 %2)

    ret i32 0
}


当我编译LLVM IR代码时,输出如下:
$ llvm-as code.ll -o code.bc
$ lli code.bc
44 0.000000 $

它成功地打印了整数和字符,但没有打印浮点数!


只是一个猜测:你可以试试在GEP之前重新加载obj,或者对obj4执行GEP操作。我的假设是你正在处理“旧”的数据,但整数和字符值恰好被正确打印出来了。 - undefined
1个回答

6
原因是printf是一个可变参数函数,可变参数函数会将float类型的参数提升为double类型。详见为什么printf()会将float类型提升为double类型? 因此,在将%1传递给printf之前,您应该首先将其强制转换为double类型,这也是clang所做的。例如:
void f() {
  float a = 1;
  printf("%f", a);
}

提供

@.str = private unnamed_addr constant [3 x i8] c"%f\00", align 1

define void @f() {
  %1 = alloca float, align 4
  store float 1.000000e+00, float* %1, align 4
  %2 = load float, float* %1, align 4
  %3 = fpext float %2 to double
  %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x 
            i8], [3 x i8]* @.str, i64 0, i64 0), double %3)
  ret void
}

请注意使用fpext

我认为%lfdouble类型的格式说明符。我提供了%f,这是float类型的格式说明符。 - undefined
至少当我尝试在C/C++代码中使用float数据类型调用printf()时,它可以正常工作,而无需将float转换为double。LLVM IR是否使用与C/C++不同的printf()版本? - undefined
printf llvm 调用的是你在 libc 中熟悉的函数。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接