[llvm] fc00510 - [InstCombine][ConstantFold] Baseline tests for ptrtoint(gep null, x)

Alex Richardson via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 28 09:58:07 PDT 2021


Author: Alex Richardson
Date: 2021-09-28T17:57:36+01:00
New Revision: fc0051011eece1448e8d7f5a478acde5b57e1887

URL: https://github.com/llvm/llvm-project/commit/fc0051011eece1448e8d7f5a478acde5b57e1887
DIFF: https://github.com/llvm/llvm-project/commit/fc0051011eece1448e8d7f5a478acde5b57e1887.diff

LOG: [InstCombine][ConstantFold] Baseline tests for ptrtoint(gep null, x)

Differential Revision: https://reviews.llvm.org/D110244

Added: 
    llvm/test/Transforms/InstCombine/ptrtoint-nullgep.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/Transforms/InstCombine/ptrtoint-nullgep.ll b/llvm/test/Transforms/InstCombine/ptrtoint-nullgep.ll
new file mode 100644
index 000000000000..f2192712fc32
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/ptrtoint-nullgep.ll
@@ -0,0 +1,553 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
+; Check that we can fold operations with (gep null) inputs.
+; Note: the LLParser already does some constant folding, check that output first:
+; RUN: opt -S -passes=verify < %s | FileCheck %s --check-prefixes=ALL,LLPARSER
+; We should be able to fold almost everything in InstSimplify other than the final test which requries InstCombine
+; RUN: opt -S -passes=instsimplify < %s | FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,INTEGRAL,INSTSIMPLIFY,INTEGRAL-INSTSIMPLIFY
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,INTEGRAL,INSTCOMBINE,INTEGRAL-INSTCOMBINE
+; Non-integral pointers limit certain transformations on pointers:
+; RUN: sed -e 's/p:64:64:64:64/p:64:64:64:64-ni:1/g' %s | opt -S -passes=instsimplify | \
+; RUN:   FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,NONINTEGRAL,INSTSIMPLIFY,NONINTEGRAL-INSTSIMPLIFY
+; RUN: sed -e 's/p:64:64:64:64/p:64:64:64:64-ni:1/g' %s | opt -S -passes=instcombine | \
+; RUN:   FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,NONINTEGRAL,INSTCOMBINE,NONINTEGRAL-INSTCOMBINE
+target datalayout = "p:64:64:64:64"
+
+declare void @use_i64(i64)
+declare void @use_ptr(i8 addrspace(1)*)
+
+define i64 @constant_fold_ptrtoint_gep_zero() {
+; ALL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_zero() {
+; ALL-NEXT:    ret i64 0
+;
+  ret i64 ptrtoint (i32 addrspace(1)* getelementptr (i32, i32 addrspace(1)* null, i64 0) to i64)
+}
+define i64 @constant_fold_ptrtoint_gep_nonzero() {
+; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
+; LLPARSER-NEXT:    ret i64 ptrtoint (i32 addrspace(1)* getelementptr (i32, i32 addrspace(1)* null, i64 1234) to i64)
+;
+; INTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
+; INTEGRAL-INSTSIMPLIFY-NEXT:    ret i64 ptrtoint (i32 addrspace(1)* getelementptr (i32, i32 addrspace(1)* null, i64 1234) to i64)
+;
+; INTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
+; INTEGRAL-INSTCOMBINE-NEXT:    ret i64 4936
+;
+; NONINTEGRAL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
+; NONINTEGRAL-NEXT:    ret i64 ptrtoint (i32 addrspace(1)* getelementptr (i32, i32 addrspace(1)* null, i64 1234) to i64)
+;
+  ret i64 ptrtoint (i32 addrspace(1)* getelementptr (i32, i32 addrspace(1)* null, i64 1234) to i64)
+}
+
+define i64 @constant_fold_ptrtoint_gep_zero_inbounds() {
+; ALL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_zero_inbounds() {
+; ALL-NEXT:    ret i64 0
+;
+  ret i64 ptrtoint (i32 addrspace(1)* getelementptr inbounds (i32, i32 addrspace(1)* null, i64 0) to i64)
+}
+
+; In theory we could fold this to poison/null, but that would break offsetof
+; implementations that don't use __builtin_offsetof.
+; TODO: should Clang special case ((INTEGER)&((TYPE *)0)->MEMBER) to emit a non-inbounds GEP?
+define i64 @constant_fold_ptrtoint_gep_nonzero_inbounds() {
+; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
+; LLPARSER-NEXT:    ret i64 ptrtoint (i32 addrspace(1)* getelementptr inbounds (i32, i32 addrspace(1)* null, i64 1234) to i64)
+;
+; INTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
+; INTEGRAL-INSTSIMPLIFY-NEXT:    ret i64 ptrtoint (i32 addrspace(1)* getelementptr inbounds (i32, i32 addrspace(1)* null, i64 1234) to i64)
+;
+; INTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
+; INTEGRAL-INSTCOMBINE-NEXT:    ret i64 4936
+;
+; NONINTEGRAL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
+; NONINTEGRAL-NEXT:    ret i64 ptrtoint (i32 addrspace(1)* getelementptr inbounds (i32, i32 addrspace(1)* null, i64 1234) to i64)
+;
+  ret i64 ptrtoint (i32 addrspace(1)* getelementptr inbounds (i32, i32 addrspace(1)* null, i64 1234) to i64)
+}
+
+; Check all combinations of inbounds+non-inbounds GEP with the outer GEP having a non-zero offset
+define void @constant_fold_ptrtoint_of_gep_of_nullgep() {
+; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; LLPARSER-NEXT:    call void @use_i64(i64 0)
+; LLPARSER-NEXT:    call void @use_i64(i64 0)
+; LLPARSER-NEXT:    call void @use_i64(i64 0)
+; LLPARSER-NEXT:    call void @use_i64(i64 0)
+; LLPARSER-NEXT:    ret void
+;
+; INTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTSIMPLIFY-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTSIMPLIFY-NEXT:    ret void
+;
+; INTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
+; INTEGRAL-INSTCOMBINE-NEXT:    ret void
+;
+; NONINTEGRAL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64))
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 0)
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 0)
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 0)
+; NONINTEGRAL-NEXT:    call void @use_i64(i64 0)
+; NONINTEGRAL-NEXT:    ret void
+;
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 0), i64 1234) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 0), i64 1234) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 0), i64 1234) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 0), i64 1234) to i64))
+  ; Same again but this time with the inner GEP using the non-zero offset
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234), i64 0) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234), i64 0) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234), i64 0) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234), i64 0) to i64))
+  ; And finally with two constants that sum to zero
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 -1), i64 1) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 -1), i64 1) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 -1), i64 1) to i64))
+  call void @use_i64(i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 -1), i64 1) to i64))
+  ret void
+}
+
+; Another set of tests for instructions instead of constants
+define i64 @fold_ptrtoint_nullgep_zero() {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero() {
+; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 0, 0
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[OFFSET]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero() {
+; CHECK-NEXT:    ret i64 0
+;
+  %offset = add i64 0, 0
+  %ptr = getelementptr i8, i8 addrspace(1)* null, i64 %offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_nullgep_zero_inbounds() {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero_inbounds() {
+; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 0, 0
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* null, i64 [[OFFSET]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero_inbounds() {
+; CHECK-NEXT:    ret i64 0
+;
+  %offset = add i64 0, 0
+  %ptr = getelementptr inbounds i8, i8 addrspace(1)* null, i64 %offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_nullgep_nonzero() {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() {
+; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 1234, 0
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[OFFSET]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; INTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() {
+; INTEGRAL-NEXT:    ret i64 1234
+;
+; NONINTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() {
+; NONINTEGRAL-NEXT:    ret i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64)
+;
+  %offset = add i64 1234, 0
+  %ptr = getelementptr i8, i8 addrspace(1)* null, i64 %offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; Inbounds constant null-GEP with non-zero could be constant-folded to null/poison,
+; but folding it to the value makes ((INTEGER)&((TYPE *)0)->MEMBER) work.
+define i64 @fold_ptrtoint_nullgep_nonzero_inbounds() {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() {
+; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 1234, 0
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* null, i64 [[OFFSET]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; INTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() {
+; INTEGRAL-NEXT:    ret i64 1234
+;
+; NONINTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() {
+; NONINTEGRAL-NEXT:    ret i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64)
+;
+  %offset = add i64 1234, 0
+  %ptr = getelementptr inbounds i8, i8 addrspace(1)* null, i64 %offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; We should be able to fold ptrtoint(gep null, x) to x
+define i64 @fold_ptrtoint_nullgep_variable(i64 %val) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable
+; ALL-SAME: (i64 [[VAL:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[VAL]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr i8, i8 addrspace(1)* null, i64 %val
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; Inbounds null-GEP with non-zero offset could be folded to poison/null.
+define i64 @fold_ptrtoint_nullgep_variable_known_nonzero(i64 %val) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero
+; ALL-SAME: (i64 [[VAL:%.*]]) {
+; ALL-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[NON_ZERO_OFFSET]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %non_zero_offset = or i64 %val, 1
+  %ptr = getelementptr i8, i8 addrspace(1)* null, i64 %non_zero_offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; This is only valid if %val is zero so we could fold the result to 0.
+define i64 @fold_ptrtoint_nullgep_variable_inbounds(i64 %val) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds
+; ALL-SAME: (i64 [[VAL:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* null, i64 [[VAL]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr inbounds i8, i8 addrspace(1)* null, i64 %val
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; A non-constant but known-non-zero GEP could be folded to poison/null
+define i64 @fold_ptrtoint_nullgep_variable_known_nonzero_inbounds(i64 %val) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds
+; ALL-SAME: (i64 [[VAL:%.*]]) {
+; ALL-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* null, i64 [[NON_ZERO_OFFSET]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %non_zero_offset = or i64 %val, 1
+  %ptr = getelementptr inbounds i8, i8 addrspace(1)* null, i64 %non_zero_offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; A non-constant but known-non-zero GEP could be folded to poison/null
+define i64 @fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices(i64 %val) {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
+; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
+; LLPARSER-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds [2 x i8], [2 x i8] addrspace(1)* null, i64 [[NON_ZERO_OFFSET]], i32 1
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; INTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
+; INTEGRAL-INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
+; INTEGRAL-INSTSIMPLIFY-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
+; INTEGRAL-INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr inbounds [2 x i8], [2 x i8] addrspace(1)* null, i64 [[NON_ZERO_OFFSET]], i32 1
+; INTEGRAL-INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; INTEGRAL-INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
+;
+; INTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
+; INTEGRAL-INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
+; INTEGRAL-INSTCOMBINE-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
+; INTEGRAL-INSTCOMBINE-NEXT:    [[PTR:%.*]] = getelementptr inbounds [2 x i8], [2 x i8] addrspace(1)* null, i64 [[NON_ZERO_OFFSET]], i64 1
+; INTEGRAL-INSTCOMBINE-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; INTEGRAL-INSTCOMBINE-NEXT:    ret i64 [[RET]]
+;
+; NONINTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
+; NONINTEGRAL-INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr inbounds [2 x i8], [2 x i8] addrspace(1)* null, i64 [[NON_ZERO_OFFSET]], i32 1
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
+;
+; NONINTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
+; NONINTEGRAL-INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
+; NONINTEGRAL-INSTCOMBINE-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
+; NONINTEGRAL-INSTCOMBINE-NEXT:    [[PTR:%.*]] = getelementptr inbounds [2 x i8], [2 x i8] addrspace(1)* null, i64 [[NON_ZERO_OFFSET]], i64 1
+; NONINTEGRAL-INSTCOMBINE-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; NONINTEGRAL-INSTCOMBINE-NEXT:    ret i64 [[RET]]
+;
+  %non_zero_offset = or i64 %val, 1
+  %ptr = getelementptr inbounds [2 x i8], [2 x i8] addrspace(1)* null, i64 %non_zero_offset, i32 1
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; We can't fold non-i8 GEPs in InstSimplify since that would require adding new arithmetic.
+; TODO: handle this case in InstCombine
+define i64 @fold_ptrtoint_nullgep_i32_variable(i64 %val) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable
+; ALL-SAME: (i64 [[VAL:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr i32, i32 addrspace(1)* null, i64 [[VAL]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i32 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr i32, i32 addrspace(1)* null, i64 %val
+  %ret = ptrtoint i32 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; ptrtoint type does not match index type so requires requite a new trunc instruction
+define i32 @fold_ptrtoint_nullgep_variable_trunc(i64 %val) {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
+; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[VAL]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i32
+; LLPARSER-NEXT:    ret i32 [[RET]]
+;
+; INTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
+; INTEGRAL-INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
+; INTEGRAL-INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[VAL]]
+; INTEGRAL-INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i32
+; INTEGRAL-INSTSIMPLIFY-NEXT:    ret i32 [[RET]]
+;
+; INTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
+; INTEGRAL-INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
+; INTEGRAL-INSTCOMBINE-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[VAL]]
+; INTEGRAL-INSTCOMBINE-NEXT:    [[TMP1:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; INTEGRAL-INSTCOMBINE-NEXT:    [[RET:%.*]] = trunc i64 [[TMP1]] to i32
+; INTEGRAL-INSTCOMBINE-NEXT:    ret i32 [[RET]]
+;
+; NONINTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
+; NONINTEGRAL-INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[VAL]]
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i32
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    ret i32 [[RET]]
+;
+; NONINTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
+; NONINTEGRAL-INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
+; NONINTEGRAL-INSTCOMBINE-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[VAL]]
+; NONINTEGRAL-INSTCOMBINE-NEXT:    [[TMP1:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; NONINTEGRAL-INSTCOMBINE-NEXT:    [[RET:%.*]] = trunc i64 [[TMP1]] to i32
+; NONINTEGRAL-INSTCOMBINE-NEXT:    ret i32 [[RET]]
+;
+  %ptr = getelementptr i8, i8 addrspace(1)* null, i64 %val
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i32
+  ret i32 %ret
+}
+
+; For the following three tests, we could fold the result to poison/null since there is at least
+; one inbounds GEP on null with a non-zero offset.
+define i64 @fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
+; LLPARSER-NEXT:    [[NONZERO_OFFSET:%.*]] = add i64 1234, 0
+; LLPARSER-NEXT:    [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* null, i64 [[NONZERO_OFFSET]]
+; LLPARSER-NEXT:    [[PTR2:%.*]] = getelementptr i8, i8 addrspace(1)* [[PTR]], i64 [[ZERO_OFFSET]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR2]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; INTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
+; INTEGRAL-NEXT:    ret i64 1234
+;
+; NONINTEGRAL-INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
+; NONINTEGRAL-INSTSIMPLIFY-NEXT:    ret i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64)
+;
+; NONINTEGRAL-INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
+; NONINTEGRAL-INSTCOMBINE-NEXT:    ret i64 ptrtoint (i8 addrspace(1)* getelementptr (i8, i8 addrspace(1)* null, i64 1234) to i64)
+;
+  %nonzero_offset = add i64 1234, 0
+  %zero_offset = sub i64 %nonzero_offset, 1234
+  %ptr = getelementptr inbounds i8, i8 addrspace(1)* null, i64 %nonzero_offset
+  %ptr2 = getelementptr i8, i8 addrspace(1)* %ptr, i64 %zero_offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr2 to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
+; LLPARSER-NEXT:    [[NONZERO_OFFSET:%.*]] = add i64 1234, 0
+; LLPARSER-NEXT:    [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, i8 addrspace(1)* null, i64 [[ZERO_OFFSET]]
+; LLPARSER-NEXT:    [[PTR2:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[PTR]], i64 [[NONZERO_OFFSET]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR2]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; INTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
+; INTEGRAL-NEXT:    ret i64 1234
+;
+; NONINTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
+; NONINTEGRAL-NEXT:    ret i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64)
+;
+  %nonzero_offset = add i64 1234, 0
+  %zero_offset = sub i64 %nonzero_offset, 1234
+  %ptr = getelementptr i8, i8 addrspace(1)* null, i64 %zero_offset
+  %ptr2 = getelementptr inbounds i8, i8 addrspace(1)* %ptr, i64 %nonzero_offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr2 to i64
+  ret i64 %ret
+}
+
+; We should also be able to fold GEPs with multiple indices.
+%struct.S = type { [2 x %struct.K] }
+%struct.K = type { [32 x i8] }
+
+define i64 @fold_complex_index_last_nonzero(i64 %x) local_unnamed_addr #0 {
+; ALL-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero
+; ALL-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
+; ALL-NEXT:  entry:
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], [[STRUCT_S]] addrspace(1)* null, i64 0, i32 0, i64 0, i32 0, i64 [[X]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+entry:
+  %ptr = getelementptr inbounds %struct.S, %struct.S addrspace(1)* null, i64 0, i32 0, i64 0, i32 0, i64 %x
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_complex_index_multiple_nonzero(i64 %x) local_unnamed_addr #0 {
+; ALL-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero
+; ALL-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
+; ALL-NEXT:  entry:
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], [[STRUCT_S]] addrspace(1)* null, i64 1, i32 0, i64 1, i32 0, i64 [[X]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+entry:
+  %ptr = getelementptr inbounds %struct.S, %struct.S addrspace(1)* null, i64 1, i32 0, i64 1, i32 0, i64 %x
+  %ret = ptrtoint i8 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
+; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
+; LLPARSER-NEXT:    [[NONZERO_OFFSET:%.*]] = add i64 1234, 0
+; LLPARSER-NEXT:    [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234
+; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* null, i64 [[NONZERO_OFFSET]]
+; LLPARSER-NEXT:    [[PTR2:%.*]] = getelementptr inbounds i8, i8 addrspace(1)* [[PTR]], i64 [[ZERO_OFFSET]]
+; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint i8 addrspace(1)* [[PTR2]] to i64
+; LLPARSER-NEXT:    ret i64 [[RET]]
+;
+; INTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
+; INTEGRAL-NEXT:    ret i64 1234
+;
+; NONINTEGRAL-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
+; NONINTEGRAL-NEXT:    ret i64 ptrtoint (i8 addrspace(1)* getelementptr inbounds (i8, i8 addrspace(1)* null, i64 1234) to i64)
+;
+  %nonzero_offset = add i64 1234, 0
+  %zero_offset = sub i64 %nonzero_offset, 1234
+  %ptr = getelementptr inbounds i8, i8 addrspace(1)* null, i64 %nonzero_offset
+  %ptr2 = getelementptr inbounds i8, i8 addrspace(1)* %ptr, i64 %zero_offset
+  %ret = ptrtoint i8 addrspace(1)* %ptr2 to i64
+  ret i64 %ret
+}
+
+; Check that InstCombine can convert ptrtoint(gep null) with multiple indices
+define i64 @fold_ptrtoint_nullgep_array_one_var_1(i64 %x) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1
+; ALL-SAME: (i64 [[X:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 [[X]], i64 3
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i16 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 %x, i64 3
+  %ret = ptrtoint i16 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_nullgep_array_one_var_2(i64 %x) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2
+; ALL-SAME: (i64 [[X:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 7, i64 [[X]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i16 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 7, i64 %x
+  %ret = ptrtoint i16 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_nested_array_two_vars(i64 %x, i64 %y) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars
+; ALL-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 [[X]], i64 [[Y]]
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i16 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+
+  %ptr = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 %x, i64 %y
+  %ret = ptrtoint i16 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_nested_array_two_vars_plus_zero(i64 %x, i64 %y) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero
+; ALL-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr [2 x [2 x i16]], [2 x [2 x i16]] addrspace(1)* null, i64 [[X]], i64 [[Y]], i64 0
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i16 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr [2 x [2 x i16]], [2 x [2 x i16]] addrspace(1)* null, i64 %x, i64 %y, i64 0
+  %ret = ptrtoint i16 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+define i64 @fold_ptrtoint_nested_array_two_vars_plus_const(i64 %x, i64 %y) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const
+; ALL-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr [2 x [2 x i16]], [2 x [2 x i16]] addrspace(1)* null, i64 [[X]], i64 [[Y]], i64 1
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i16 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr [2 x [2 x i16]], [2 x [2 x i16]] addrspace(1)* null, i64 %x, i64 %y, i64 1
+  %ret = ptrtoint i16 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}
+
+; Negative test -- should not be folded since there are multiple GEP uses
+define i64 @fold_ptrtoint_nested_nullgep_array_variable_multiple_uses(i64 %x, i64 %y) {
+; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_nullgep_array_variable_multiple_uses
+; ALL-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
+; ALL-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 [[X]], i64 [[Y]]
+; ALL-NEXT:    [[PTRI8:%.*]] = bitcast i16 addrspace(1)* [[PTR]] to i8 addrspace(1)*
+; ALL-NEXT:    call void @use_ptr(i8 addrspace(1)* [[PTRI8]])
+; ALL-NEXT:    [[RET:%.*]] = ptrtoint i16 addrspace(1)* [[PTR]] to i64
+; ALL-NEXT:    ret i64 [[RET]]
+;
+  %ptr = getelementptr [2 x i16], [2 x i16] addrspace(1)* null, i64 %x, i64 %y
+  %ptri8 = bitcast i16 addrspace(1)* %ptr to i8 addrspace(1)*
+  call void @use_ptr(i8 addrspace(1)* %ptri8)
+  %ret = ptrtoint i16 addrspace(1)* %ptr to i64
+  ret i64 %ret
+}


        


More information about the llvm-commits mailing list