Skip to content

[separate-const-offset-from-gep] miscompile for trunc #154936

@ritter-x2a

Description

@ritter-x2a

llvm commit: 15a192c

Reproduce with:

opt -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1200 -passes=separate-const-offset-from-gep -S separate-offset-from-gep-trunc-miscompile.ll

The attached code:

define ptr @src(ptr %p, i64 %a) {
  %add = add i64 %a, 8
  %trunc = trunc i64 %add to i32
  %sext = sext i32 %trunc to i64
  %arrayidx = getelementptr inbounds nuw i32, ptr %p, i64 %sext
  ret ptr %arrayidx
}

is wrongly transformed into this code:

define ptr @src(ptr %p, i64 %a) #0 {
  %1 = trunc i64 %a to i32
  %2 = sext i32 %1 to i64
  %3 = getelementptr i32, ptr %p, i64 %2
  %arrayidx2 = getelementptr i8, ptr %3, i64 32
  ret ptr %arrayidx2
}

Alive2 shows this transformation to be illegal: alive2 link.

Observations

This might be related to the (to me) unexpected handling of the NonNegative flag in ConstantOffsetExtractor::find:
It isn't cleared for trunc, but it is for zext "because zext(a) >= 0 does not imply a >= 0" -- that doesn't hold for trunc either.
The meaning of NonNegative also seems odd: the documentation, says

NonNegative -- Whether V is guaranteed to be non-negative. For example, an index of an inbounds GEP is guaranteed to be non-negative. Levaraging this, we can better split inbounds GEPs.

I don't think that's right, inbounds GEP indices can be negative.

The unchanged passing of SignExtended and ZeroExtended for trunc might also be worth checking in this context.

Found while looking into #154116.

separate-offset-from-gep-trunc-miscompile.ll.txt

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions