Skip to content

Invalid instcombine of inttoptr -> gep #2839

@efriedma-quic

Description

@efriedma-quic
Bugzilla Link 2467
Resolution DUPLICATE
Resolved on Oct 16, 2008 00:40
Version unspecified
OS Linux
CC @asl,@nlewycky

Extended Description

The current inttoptr ->gep optimization in InstCombiner::visitIntToPtr will always optimize inttoptr(add (ptrtoint x), cst) to gep x, cst. This is an invalid transformation in general because unlike integer arithmetic, overflow for a GEP is undefined. Therefore, the transformation is only valid if the resultant pointer is guaranteed to be valid. (There are a few ways to make this guarantee: one is if the resulting pointer is immediately loaded from, another is to ensure x is an object of known size.)

Sample program that breaks when run through clang -emit-llvm-bc | opt -std-compile-opts (it's a little complicated because it has to trigger both the bad optimization and an undefined overflow optimization):

int* a(int* a, int i) {return (int*)((unsigned)((int*)((unsigned)(a)+0x80000000))+0x80000000)+i;}
unsigned b(int* b, int i) {return a(b, i) == b+i;}
int main(int argc, char** argv) {if (!b(&argc, argc)) abort();}

Output of clang -emit-llvm-bc for this program run through mem2reg:
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i686-pc-linux-gnu"

define i32* @​a(i32* %a, i32 %i) {
entry:
%conv = ptrtoint i32* %a to i32
%add = add i32 %conv, -2147483648
%conv1 = inttoptr i32 %add to i32*
%conv2 = ptrtoint i32* %conv1 to i32
%add3 = add i32 %conv2, -2147483648
%conv4 = inttoptr i32 %add3 to i32*
%add.ptr = getelementptr i32* %conv4, i32 %i
ret i32* %add.ptr
}

define i32 @​b(i32* %b, i32 %i) {
entry:
%call = call i32* @​a( i32* %b, i32 %i )
%add.ptr = getelementptr i32* %b, i32 %i
%cmp = icmp eq i32* %call, %add.ptr
%cmp.ext = zext i1 %cmp to i32
ret i32 %cmp.ext
}

define i32 @​main(i32 %argc, i8** %argv) {
entry:
%argc.addr = alloca i32
store i32 %argc, i32* %argc.addr
%tmp = load i32* %argc.addr
%call = call i32 @​b( i32* %argc.addr, i32 %tmp )
%tobool = icmp ne i32 %call, 0
%lnot = xor i1 %tobool, true
br i1 %lnot, label %ifthen, label %ifend

ifthen: ; preds = %entry
%call1 = call i32 (...)* @​abort( )
br label %ifend

ifend: ; preds = %ifthen, %entry
ret i32 undef
}

Resultant program after running this through opt -std-compile-opts:
; ModuleID = ''
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i686-pc-linux-gnu"

define i32* @​a(i32* %a, i32 %i) nounwind {
entry:
%conv1.sum = add i32 %i, -1073741824
%add.ptr = getelementptr i32* %a, i32 %conv1.sum
ret i32* %add.ptr
}

define i32 @​b(i32* %b, i32 %i) nounwind {
entry:
%conv1.sum.i = add i32 %i, -1073741824
%cmp = icmp eq i32 %conv1.sum.i, %i
%cmp.ext = zext i1 %cmp to i32
ret i32 %cmp.ext
}

define i32 @​main(i32 %argc, i8** %argv) {
entry:
%conv1.sum.i.i = add i32 %argc, -1073741824
%cmp.i = icmp eq i32 %conv1.sum.i.i, %argc
br i1 %cmp.i, label %ifend, label %ifthen

ifthen: ; preds = %entry
%call1 = tail call i32 (...)* @​abort( )
ret i32 undef

ifend: ; preds = %entry
ret i32 undef
}

declare i32 @​abort(...)

There's also another issue with the optimization: it doesn't make sure that the ptrtoint doesn't lose information by casting to a narrower type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugzillaIssues migrated from bugzilladuplicateResolved as duplicate

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions