Arsen Hakobyan
2013-Oct-09 11:53 UTC
[LLVMdev] Related constant folding of floating point values
Hi all, I have the following test case: #define FLT_EPSILON 1.19209290E-7 int err = -1; int main() { float a = 8.1; if (((a - 8.1) >= FLT_EPSILON) || ((a - 8.1) <= -FLT_EPSILON)) { //I am using FLT_EPSILON to check whether (a != 2.0). err = 1; } else { err = 0; } return 0; } with -O3 optimization level clang generates already incorrect LLVM IR: ; Function Attrs: nounwind uwtable define i32 @main() #0 { entry: store i32 1, i32* @err, align 4, !tbaa !0 ret i32 0 } BUT if I change the value of the variable 'a' to be '7.1'. then a correct IR is generated: ... entry: store i32 0, i32* @err, align 4, !tbaa !0 ret i32 0 ... I have already investigated the issue and found that during the EarlyCSE transformation it seems replaces the FPExt instruction with an incorrect hexadecimal value: The LLVM IR generated with O0 opt. level is: ... store float 0x4020333340000000, float* %a, align 4 %0 = load float* %a, align 4 %conv = fpext float %0 to double %sub = fsub double %conv, 8.100000e+00 %cmp = fcmp oge double %sub, 0x3E8000000102F4FD br i1 %cmp, label %if.then, label %lor.lhs.false lor.lhs.false: ; preds = %entry %1 = load float* %a, align 4 %conv2 = fpext float %1 to double %sub3 = fsub double %conv2, 8.100000e+00 %cmp4 = fcmp ole double %sub3, 0xBE8000000102F4FD br i1 %cmp4, label %if.then, label %if.else ... during the transformation the %conv is replaced with "double 0x4020333340000000" and then the result of comparison is resolved incorrectly. Is not this a bug? I have also searched for a similar issue in llvm bug list, but could not found anything. Thank you, Arsen -- View this message in context: http://llvm.1065342.n5.nabble.com/Related-constant-folding-of-floating-point-values-tp61897.html Sent from the LLVM - Dev mailing list archive at Nabble.com.
Mark Lacey
2013-Oct-09 14:43 UTC
[LLVMdev] Related constant folding of floating point values
Hi Arsen, On Oct 9, 2013, at 4:53 AM, Arsen Hakobyan <artinetstudio at gmail.com> wrote:> Hi all, > > I have the following test case: > #define FLT_EPSILON 1.19209290E-7 > > int err = -1; > int main() > { > float a = 8.1; > if (((a - 8.1) >= FLT_EPSILON) || ((a - 8.1) <= -FLT_EPSILON)) { //I am > using FLT_EPSILON to check whether (a != 2.0).It’s not clear what this comment refers to, but it doesn’t seem to be related to this code.> err = 1; > } else { > err = 0; > } > return 0; > } > > with -O3 optimization level clang generates already incorrect LLVM IR: > ; Function Attrs: nounwind uwtable > define i32 @main() #0 { > entry: > store i32 1, i32* @err, align 4, !tbaa !0 > ret i32 0 > } > > BUT if I change the value of the variable 'a' to be '7.1'. then a correct IR > is generated: > ... > entry: > store i32 0, i32* @err, align 4, !tbaa !0 > ret i32 0 > ... > > > I have already investigated the issue and found that during the EarlyCSE > transformation it seems replaces the FPExt instruction with an incorrect > hexadecimal value: > The LLVM IR generated with O0 opt. level is: > ... > store float 0x4020333340000000, float* %a, align 4 > %0 = load float* %a, align 4 > %conv = fpext float %0 to double > %sub = fsub double %conv, 8.100000e+00 > %cmp = fcmp oge double %sub, 0x3E8000000102F4FD > br i1 %cmp, label %if.then, label %lor.lhs.false > > lor.lhs.false: ; preds = %entry > %1 = load float* %a, align 4 > %conv2 = fpext float %1 to double > %sub3 = fsub double %conv2, 8.100000e+00 > %cmp4 = fcmp ole double %sub3, 0xBE8000000102F4FD > br i1 %cmp4, label %if.then, label %if.else > ... > > during the transformation the %conv is replaced with "double > 0x4020333340000000" and then the result of comparison is resolved > incorrectly. > > Is not this a bug?No. The issue is that you are taking a double (8.1), converting it to float, and then subtracting the original double from it. The rounding error introduced from the conversion is larger than the epsilon value that you are comparing to, so the first comparison (a-8.1 >= FLT_EPSILON) is always true. Mark> I have also searched for a similar issue in llvm bug list, but could not > found anything. > > Thank you, > Arsen > > > > -- > View this message in context: http://llvm.1065342.n5.nabble.com/Related-constant-folding-of-floating-point-values-tp61897.html > Sent from the LLVM - Dev mailing list archive at Nabble.com. > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev
Renato Golin
2013-Oct-09 14:47 UTC
[LLVMdev] Related constant folding of floating point values
Hi Arsen, On 9 October 2013 12:53, Arsen Hakobyan <artinetstudio at gmail.com> wrote:> if (((a - 8.1) >= FLT_EPSILON) || ((a - 8.1) <= -FLT_EPSILON)) { //I am > using FLT_EPSILON to check whether (a != 2.0). >This comment is wrong. You're trying to check if subtraction has any residual value (module) due to floating point inaccuracies that are higher than FLT_EPSILON. with -O3 optimization level clang generates already incorrect LLVM IR:> ; Function Attrs: nounwind uwtable > define i32 @main() #0 { > entry: > store i32 1, i32* @err, align 4, !tbaa !0 > ret i32 0 > } >This is correct, since FLT_EPSILON is denormalized to 0.0, thus "(a - 8.1)>= FLT_EPSILON" -> "0.0 >= 0.0", which is always true, and that branch willalways be taken, thus, err will always be equal 1. If you change your float to double, you'll see that it no longer denormalizes, and err=0; cheers, --renato -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20131009/de13bb91/attachment.html>
Renato Golin
2013-Oct-09 15:06 UTC
[LLVMdev] Related constant folding of floating point values
On 9 October 2013 15:43, Mark Lacey <mark.lacey at apple.com> wrote:> No. The issue is that you are taking a double (8.1), converting it to > float, and then subtracting the original double from it. The rounding error > introduced from the conversion is larger than the epsilon value that you > are comparing to, so the first comparison (a-8.1 >= FLT_EPSILON) is always > true. >Yes, my bad, FLT_EPSILON ends up as a double constant, so not denormalized, but the error introduced is larger than epsilon anyway. --renato -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20131009/b6ee09cb/attachment.html>
Arsen Hakobyan
2013-Oct-09 20:51 UTC
[LLVMdev] Related constant folding of floating point values
Thank you all for your responses. Just one point I have not understand well. Lets look at this part of IR code: store float 0x4020333340000000, float* %a, align 4 %0 = load float* %a, align 4 %conv = fpext float %0 to double %sub = fsub double %conv, 8.100000e+00 Here the float value is represented by hexadecimal constant value of float type ( float 0x4020333340000000). If I have correctly understood the same hex value can be converted to different result of float or double types because the IEEE 754 standard specifies a binary32 as having: (single-precision binary floating-point format) Sign bit: 1 bit Exponent width: 8 bits Significand precision: 24 (23 explicitly stored) and a binary64 as having: (double-precision binary floating-point format) Sign bit: 1 bit Exponent width: 11 bits Significand precision: 53 bits (52 explicitly stored) After this all, I think that the optimizations should not replace the conversation: %conv = fpext float 0x4020333340000000 to double, with double 0x4020333340000000 Please note, I have got during the debugging that EarlyCSE transformation does this. I think that it should be another constant hexadecimal value when its type is already a 'double'. Am I misunderstood anything? Thanks, Arsen -- View this message in context: http://llvm.1065342.n5.nabble.com/Related-constant-folding-of-floating-point-values-tp61897p61914.html Sent from the LLVM - Dev mailing list archive at Nabble.com.
Seemingly Similar Threads
- [LLVMdev] Related constant folding of floating point values
- [LLVMdev] [cfe-dev] Proposal: floating point accuracy metadata (OpenCL related)
- [LLVMdev] Passing specific register for an Instruction in target description files.
- TypePromoteFloat loses intermediate rounding operations
- TypePromoteFloat loses intermediate rounding operations