llvm-ir

can't get "getelementptr" and "store" working


I am generating the following ir

  %2 = getelementptr float, ptr %0, i32 1
  store float 1.000000e+00, ptr %2, align 8
  %3 = getelementptr float, ptr %0, i32 1
  %4 = load float, ptr %3, align 4

%0 is a pointer to type {i32, float}. I expected "1.000" to be stored in the "float" field.

But when I run the above code, "0.000" is printed to the console. I think I am missing some small details here, but I can't figure it out.

For reference, here is the entire code.

; ModuleID = 'tests/var.txt'
source_filename = "tests/var.txt"

%class.Int = type { i32, float }

@0 = private unnamed_addr constant [12 x i8] c"not object\0A\00", align 1
@1 = private unnamed_addr constant [3 x i8] c"%f\00", align 1
@2 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1

define i32 @main() {
body:
  %0 = alloca %class.Int, align 8
  %1 = getelementptr i32, ptr %0, i32 0
  store i32 2, ptr %1, align 1
  %2 = getelementptr float, ptr %0, i32 1
  store float 1.000000e+00, ptr %2, align 8
  %3 = getelementptr float, ptr %0, i32 1
  %4 = load float, ptr %3, align 4
  %5 = call ptr (...) @printf(ptr @1, float %4)
  %6 = call ptr (...) @printf(ptr @2)
  ret i32 0
}

declare ptr @printf(...)

Thank you for your help!


Solution

  • The problem isn't with getelementptr or how you access the memory - it's with how you print the value.

    printf("%f", ...) expects a double, but you're passing a float. If you change the type of the field (and the instructions operating on it) to double or you convert the float to double using fpext before calling printf, it will work.