Wrong float value stored in LLVM IR code

Hi everyone,

I'm learning how to use LLVM API and JIT engine and I've come across with an issue I haven't been able to figure out.

The problem I'm having is that the wrong float is being stored in a float global variable.

The code snippet I use to generate the float value is as follow:

     llvm::Type* type = // initialize with the global variable type;
     std::string real_value = // initialized with the float value from std input.
     ...
     return ConstantFP::get(type,real_value);

I am using the code snippet above to store a float and double value, the double value works, the float value not. This can be seen with the following LLVM IR I am generating:

What the functions do is just:
  1. backup current value of global variable
  2. store new value
  3. call a C function which returns the value of the global variable in that same module
  4. Compare against the value used in step 2
  5. restore the initial value
  6. return true or false if the values were equal.

/**
   float gfloat = 3.141592;
*/
define i32 @test_getgfloat_0() {
block_test_getgfloat_0:
   %0 = load float* @gfloat
   store float 0x400921FB00000000, float* @gfloat // wrong value stored
   %1 = call float @getgfloat()
   %2 = fcmp oeq float %1, 0x400921FA00000000 // wrong value stored
   %3 = zext i1 %2 to i32
   store float %0, float* @gfloat
   ret i32 %3
}

/**
   double gdouble = 2.52340;
  */
define i32 @test_getdouble_0() {
block_test_getdouble_0:
   %0 = load double* @gdouble
   store double 2.523400e+00, double* @gdouble // correct value stored
   %1 = call double @getdouble()
   %2 = fcmp oeq double %1, 2.523400e+00 // correct value stored
   %3 = zext i1 %2 to i32
   store double %0, double* @gdouble
   ret i32 %3
}

Do you have any idea of why I'm having this problem?

Thank you.

Here you store .....FB.....

  %2 = fcmp oeq float %1, 0x400921FA00000000 // wrong value stored

Here you compare with .....FA..... - is that what you intended?

Jim

Is the problem that the store and the fcmp have different single-precision constants to eachother, or is it that neither constant is what you expected?

If it's the latter, then the constants look correct to me. Hexadecimal floating point values in LLVM-IR are in double precision format for both single and double precision values. When used for a single-precision constant, the double-precision constant must be convertible to single-precision without rounding. See the paragraph starting 'The one non-intuitive notation ...' at http://llvm.org/docs/LangRef.html#simple-constants.

I'm not sure why the store and fcmp constants differ though. 3.141592 isn't exactly representable in single precision but I would have expected both constants to be rounded the same way.

Originally was the latter, but after carefully debugging it turned out the former. In summary, I was storing the floating point value in a string and using ConstantFP::get() to get a
float value in two different lines in my code. The problem was that in one line for debugging reasons I was converting the string value to a C++ float type, and then again back to string thus I lost some precision there and a few digits were lost, and two different constants were generated (I know, I looked at the code and seems I needed a cup of coffee... :slight_smile: ). Solution was to call ConstantFP::get() with the same string in both places with no castings to other type.

However, the information you provided was really helpful as I looked over my code and detected some bugs related to floats precision I was generating related to the explanation below (aside that silly bug from above).

Thanks everyone for your help.