LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 22727 - [InstcombineCompares] generates incorrect code for double comparision
Summary: [InstcombineCompares] generates incorrect code for double comparision
Status: NEW
Alias: None
Product: libraries
Classification: Unclassified
Component: Scalar Optimizations (show other bugs)
Version: trunk
Hardware: All All
: P normal
Assignee: Unassigned LLVM Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-02-27 09:58 PST by SHIVARAMA RAO
Modified: 2020-11-10 21:03 PST (History)
7 users (show)

See Also:
Fixed By Commit(s):


Attachments
input file to reproduce the problem. (418 bytes, application/octet-stream)
2015-02-27 09:58 PST, SHIVARAMA RAO
Details
input c++ program (189 bytes, text/plain)
2015-03-02 01:36 PST, SHIVARAMA RAO
Details
input to opt (2.08 KB, application/octet-stream)
2015-03-02 01:37 PST, SHIVARAMA RAO
Details
output of opt (1.15 KB, application/octet-stream)
2015-03-02 01:37 PST, SHIVARAMA RAO
Details

Note You need to log in before you can comment on or make changes to this bug.
Description SHIVARAMA RAO 2015-02-27 09:58:49 PST
Created attachment 13960 [details]
input file to reproduce the problem.

for the attached testcase with following IR:

  %i = ptrtoint i64*  %add.ptr to i64
  %conv = uitofp i64 %i to double
  %cmp = fcmp ogt double %conv, 0.000000e+00
  br i1 %cmp, label %if.then, label %if.else

opt -O2 generates following output


  %i = ptrtoint i64* %add.ptr to i64
  %cmp = icmp eq i64 %i, 0
  br i1 %cmp, label %if.else, label %if.then

In the input test we had fcmp ogt, which  got transformed into icmp eq which doesnt seem to be correct. In the test input we are checking add.ptr > 0.0 whereas in the transformed code it is checked if %add.ptr == 0

The issue presents in trunk and is result of following checkin

commit d883ca0ca713c329deed614fa389230c7266d0e4
Author: Matt Arsenault <Matthew.Arsenault@amd.com>
Date:   Tue Jan 6 15:50:59 2015 +0000

    Convert fcmp with 0.0 from casted integers to icmp

    This is already handled in general when it is known the
    conversion can't lose bits with smaller integer types
    casted into wider floating point types.
Comment 1 Reid Kleckner 2015-02-27 11:49:13 PST
Doesn't the 'uitofp' conversion imply that we know that %conv is >= 0? I think this transformation is correct.
Comment 2 Matt Arsenault 2015-02-27 14:55:15 PST
I also think this looks correct. How did you run into this?
Comment 3 SHIVARAMA RAO 2015-02-28 01:59:11 PST
My apologies.. looks like the code generated is correct.

ran into a problem with this patch when an application stopped working and the corresponding source code is as follow.

      T* lbp = bp + 1;
      double lbp1 = (double)(size_t)(lbp);
      if( lbp1 > 0.0 )
      {
         delete[]( lbp );

somehow above comparision code is transformed to following after instruction combining after this patch. 

 br i1 true, label %if.then, label %if.end, 

as noted, there is no comparision check  lpb1 > 0.0 and delete of lbp is being called when lpb1 is 0.

will try to get simplified testcase for above.
Comment 4 SHIVARAMA RAO 2015-03-02 01:36:29 PST
Created attachment 13967 [details]
input c++ program
Comment 5 SHIVARAMA RAO 2015-03-02 01:37:15 PST
Created attachment 13968 [details]
input to opt
Comment 6 SHIVARAMA RAO 2015-03-02 01:37:43 PST
Created attachment 13969 [details]
output of opt
Comment 7 SHIVARAMA RAO 2015-03-02 01:42:41 PST
The test input c++ program is attached.

as seen, the input is 
     int* lbp = bp + 1;
     double lbp1 = (double) (size_t)(lbp);
     if( lbp1 > 0.0 )
     {

the pointer bp is initialized to value "-1" outside the function and the array starts from index 1.

the explicit conversion to double in the statement

     double lbp1 = (double) (size_t)(lbp);

is removed in the llvm patch.this changes the comparison to unsigned comparision which removes the check for lbp1 > 0.0. This will make the delete to be called for 0th element, which is not initialized.

from my perspective, the source code seem to be OK. let me know otherwise.
Comment 8 David Majnemer 2015-03-04 22:43:14 PST
The optimization seems correct because we are converting an unsigned value to a double.  The fact that the underlying bit-pattern is -1 is not really relevant.
Comment 9 Reid Kleckner 2015-03-05 12:47:52 PST
(In reply to comment #8)
> The optimization seems correct because we are converting an unsigned value
> to a double.  The fact that the underlying bit-pattern is -1 is not really
> relevant.

Right, when you do the conversion, you end up with UINT_MAX, not -1. That's always bigger than 0.
Comment 10 SHIVARAMA RAO 2015-03-05 19:06:32 PST
In the case I mentioned, bp is -1 and lbp is 0

     int* lbp = bp + 1;     // bp = -1, lbp = 0
     double lbp1 = (double) (size_t)(lbp); // lbp1=0
     if( lbp1 > 0.0 )  //  condition is removed
     {

Agree that lbp1 can not be negative, but  it can be 0  and the condition check should not have been removed.
Comment 11 Reid Kleckner 2015-03-06 16:35:45 PST
(In reply to comment #10)
> Agree that lbp1 can not be negative, but  it can be 0  and the condition
> check should not have been removed.

According to your original report, the condition hasn't been removed:
  %i = ptrtoint i64* %add.ptr to i64
  %cmp = icmp eq i64 %i, 0
  br i1 %cmp, label %if.else, label %if.then

The icmp eq i64 0 is still there.
Comment 12 SHIVARAMA RAO 2015-03-09 01:46:46 PDT
Yes. Apologies for that, as it is incorrect test. Please look into comment #4 and the attached testcase.
Comment 13 Suyog Sarda 2015-03-17 04:25:04 PDT
I looked into this bug and try to dig into code base.

For the test case:

int foo(int *bp)
{
     int* lbp = bp + 1;
     double lbp1 = (double) (size_t)(lbp);
      if( lbp1 > 0.0 )
      {
         delete[]( lbp );
      }
      return 0;
}

IR before instcombine:

define i32 @_Z3fooPi(i32* %bp) #0 {
entry:
  %add.ptr = getelementptr inbounds i32, i32* %bp, i64 1
  %0 = ptrtoint i32* %add.ptr to i64
  %conv = uitofp i64 %0 to double
  %cmp = fcmp ogt double %conv, 0.000000e+00
  br i1 %cmp, label %if.then, label %if.end

if.then:                                         
  %isnull = icmp eq i32* %add.ptr, null
  br i1 %isnull, label %delete.end, label %delete.notnull

delete.notnull:                                  
  %1 = bitcast i32* %add.ptr to i8*
  call void @_ZdaPv(i8* %1) #2
  br label %delete.end

delete.end:                                       
 %if.then
  br label %if.end

if.end:                                           
  ret i32 0
}
 
Matt's checkin converts "fcmp ogt" to "icmp ugt", which is correct.

IR of comparison after conversion.

  %add.ptr = getelementptr inbounds i32, i32* %bp, i64 1
  %0 = ptrtoint i32* %add.ptr to i64
  %cmp = icmp ugt i64 %0, 0

Now further, the code again tries instruction combining in -O2 and as a part of it, instruction simplification runs on "icmp ugt" test case.

In instruction simplify, there is a call to isKnownNonZero(), which checks if %0 is non-zero. %0 is pointer to integer conversion. So, %add.ptr is checked if its non-null by isGEPKnownNonNull(). The piece of code which does this in ValueTracking.cpp file :

  if (V->getType()->isPointerTy()) {
      if (isKnownNonNull(V))
        return true; 
      if (GEPOperator *GEP = dyn_cast<GEPOperator>(V))
        if (isGEPKnownNonNull(GEP, DL, Depth, Q))
          return true;
    }

The isGEPKnownNonNull() walks the GEP operands and see if any operand introduces a non-zero offset. If so, then the GEP cannot produce a null pointer.
So it checks the index operand of the GEP, which is 1 (+ve, not zero) and hence return true.

  if (ConstantInt *OpC = dyn_cast<ConstantInt>(GTI.getOperand())) {
        if (!OpC->isZero())
          return true;
  }

The code seems to produce correct code. 

However, Lets assume that in the original test case, bp was having INT_MAX value. Adding 1 to it will make it 0. 

       int* lbp = bp + 1;

So, lbp should be 0 here. After converting it to unsigned int and double, lbp should be 0.0. So > 0.0 must be false, which is not the case with the resultant IR. The resultant IR :

  %add.ptr = getelementptr inbounds i32, i32* %bp, i64 1
  br i1 true, label %if.then, label %if.end

So the comparision is always true which might not be the case always. Isn't this a bug? Can someone confirm on this? Am i missing something?
Comment 14 Juneyoung Lee 2020-11-10 21:03:55 PST
> However, Lets assume that in the original test case, bp was having INT_MAX value. Adding 1 to it will make it 0. 
> 
>       int* lbp = bp + 1;

According to the semantics of getelementptr inbounds, lbp is poison if bp was INT_MAX.

Alive2 shows that the transformation is correct..! :) https://alive2.llvm.org/ce/z/AGEgCL