Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[InstcombineCompares] generates incorrect code for double comparision #23101

Closed
llvmbot opened this issue Feb 27, 2015 · 15 comments
Closed

[InstcombineCompares] generates incorrect code for double comparision #23101

llvmbot opened this issue Feb 27, 2015 · 15 comments
Labels
bugzilla Issues migrated from bugzilla llvm:instcombine question A question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!

Comments

@llvmbot
Copy link
Collaborator

llvmbot commented Feb 27, 2015

Bugzilla Link 22727
Version trunk
OS All
Attachments input file to reproduce the problem.
Reporter LLVM Bugzilla Contributor
CC @majnemer,@hfinkel,@aqjune,@arsenm,@rnk

Extended Description

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 d883ca0
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.
@rnk
Copy link
Collaborator

rnk commented Feb 27, 2015

Doesn't the 'uitofp' conversion imply that we know that %conv is >= 0? I think this transformation is correct.

@arsenm
Copy link
Contributor

arsenm commented Feb 27, 2015

I also think this looks correct. How did you run into this?

@llvmbot
Copy link
Collaborator Author

llvmbot commented Feb 28, 2015

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.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Mar 2, 2015

input c++ program

@llvmbot
Copy link
Collaborator Author

llvmbot commented Mar 2, 2015

input to opt

@llvmbot
Copy link
Collaborator Author

llvmbot commented Mar 2, 2015

output of opt

@llvmbot
Copy link
Collaborator Author

llvmbot commented Mar 2, 2015

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.

@majnemer
Copy link
Mannequin

majnemer mannequin commented Mar 5, 2015

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.

@rnk
Copy link
Collaborator

rnk commented Mar 5, 2015

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.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Mar 6, 2015

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.

@rnk
Copy link
Collaborator

rnk commented Mar 7, 2015

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.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Mar 9, 2015

Yes. Apologies for that, as it is incorrect test. Please look into comment #​4 and the attached testcase.

@llvmbot
Copy link
Collaborator Author

llvmbot commented Mar 17, 2015

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;
}
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(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(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?

@aqjune
Copy link
Contributor

aqjune commented Nov 11, 2020

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

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 9, 2021
@nikic
Copy link
Contributor

nikic commented Jun 8, 2022

Closing as per above comments, there is no bug in LLVM here.

@nikic nikic closed this as completed Jun 8, 2022
@EugeneZelenko EugeneZelenko added question A question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead! llvm:instcombine labels Jun 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla llvm:instcombine question A question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!
Projects
None yet
Development

No branches or pull requests

6 participants