代码之家  ›  专栏  ›  技术社区  ›  Galaxy

printf不适用于LLVM IR中的浮点数

  •  0
  • Galaxy  · 技术社区  · 4 年前

    我想将浮点变量的值打印到屏幕上。我宣布 printf() LLVM IR代码中的函数,并且已成功链接。

    每当我打印整数、字符数据类型或字符串时, 输出函数 当它以C代码打印它们时,通常会将它们打印到屏幕上。但是,如果我通过了 float 输出函数 ,它不打印浮点数,而是打印 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 $
    

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

    0 回复  |  直到 4 年前
        1
  •  5
  •   droptop    3 年前

    原因是 printf 是一个变分函数,变分函数促进 float 论点 double 。参见 Why does printf() promote a float to a double?

    所以你应该先投 %1 在传递之前加倍 输出函数 ,这就是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