Files
clang-p2996/llvm/test/Transforms/InstCombine/ptrtoint-nullgep.ll
Nikita Popov cc158d4c0b Reapply [ConstantFold] Remove non-trivial gep-of-gep fold (#93823)
Reapply after https://github.com/llvm/llvm-project/pull/93956, which
changed clang array initialization codegen to avoid size regressions
for unoptimized builds.

-----

This fold is subtly incorrect, because DL-unaware constant folding does
not know the correct index type to use, and just performs the addition
in the type that happens to already be there. This is incorrect, since
sext(X)+sext(Y) is generally not the same as sext(X+Y). See the
`@constexpr_gep_of_gep_with_narrow_type()` for a miscompile with the
current implementation.

One could try to restrict the fold to cases where no overflow occurs,
but I'm not bothering with that here, because the DL-aware constant
folding will take care of this anyway. I've only kept the
straightforward zero-index case, where we just concatenate two GEPs.
2024-06-10 10:12:55 +02:00

627 lines
34 KiB
LLVM

; 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 -passes=verify -S < %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(ptr 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 (ptr addrspace(1) null to i64)
}
define i64 @constant_fold_ptrtoint_gep_nonzero() {
; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
; LLPARSER-NEXT: ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64)
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
; INSTSIMPLIFY-NEXT: ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64)
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
; INSTCOMBINE-NEXT: ret i64 4936
;
ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr 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 (ptr addrspace(1) null 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 (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64)
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
; INSTSIMPLIFY-NEXT: ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64)
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
; INSTCOMBINE-NEXT: ret i64 4936
;
ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr 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 (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; LLPARSER-NEXT: ret void
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
; INSTSIMPLIFY-NEXT: ret void
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 1234)
; INSTCOMBINE-NEXT: call void @use_i64(i64 0)
; INSTCOMBINE-NEXT: call void @use_i64(i64 0)
; INSTCOMBINE-NEXT: call void @use_i64(i64 0)
; INSTCOMBINE-NEXT: call void @use_i64(i64 0)
; INSTCOMBINE-NEXT: ret void
;
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
; Same again but this time with the inner GEP using the non-zero offset
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
; And finally with two constants that sum to zero
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr 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, ptr addrspace(1) null, i64 [[OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr 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, ptr addrspace(1) null, i64 %offset
%ret = ptrtoint ptr 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, ptr addrspace(1) null, i64 [[OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr 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, ptr addrspace(1) null, i64 %offset
%ret = ptrtoint ptr 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, ptr addrspace(1) null, i64 [[OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() {
; CHECK-NEXT: ret i64 1234
;
%offset = add i64 1234, 0
%ptr = getelementptr i8, ptr addrspace(1) null, i64 %offset
%ret = ptrtoint ptr 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, ptr addrspace(1) null, i64 [[OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() {
; CHECK-NEXT: ret i64 1234
;
%offset = add i64 1234, 0
%ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %offset
%ret = ptrtoint ptr 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) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable
; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable
; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable
; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
; INSTCOMBINE-NEXT: ret i64 [[VAL]]
;
%ptr = getelementptr i8, ptr addrspace(1) null, i64 %val
%ret = ptrtoint ptr 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) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero
; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
; LLPARSER-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero
; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
; INSTSIMPLIFY-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero
; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
; INSTCOMBINE-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
; INSTCOMBINE-NEXT: ret i64 [[NON_ZERO_OFFSET]]
;
%non_zero_offset = or i64 %val, 1
%ptr = getelementptr i8, ptr addrspace(1) null, i64 %non_zero_offset
%ret = ptrtoint ptr 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) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds
; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[VAL]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds
; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[VAL]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds
; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
; INSTCOMBINE-NEXT: ret i64 [[VAL]]
;
%ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %val
%ret = ptrtoint ptr 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) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds
; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
; LLPARSER-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds
; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
; INSTSIMPLIFY-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds
; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
; INSTCOMBINE-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
; INSTCOMBINE-NEXT: ret i64 [[NON_ZERO_OFFSET]]
;
%non_zero_offset = or i64 %val, 1
%ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %non_zero_offset
%ret = ptrtoint ptr 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], ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]], i32 1
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
; INSTSIMPLIFY-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]], i32 1
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
; INSTCOMBINE-NEXT: [[NON_ZERO_OFFSET:%.*]] = shl i64 [[VAL]], 1
; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = or i64 [[NON_ZERO_OFFSET]], 3
; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]]
;
%non_zero_offset = or i64 %val, 1
%ptr = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 %non_zero_offset, i32 1
%ret = ptrtoint ptr addrspace(1) %ptr to i64
ret i64 %ret
}
; We can't fold non-i8 GEPs in InstSimplify since that would require adding new arithmetic.
; However, InstCombine can decompose the null gep and convert it to a shift.
define i64 @fold_ptrtoint_nullgep_i32_variable(i64 %val) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable
; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i32, ptr addrspace(1) null, i64 [[VAL]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable
; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i32, ptr addrspace(1) null, i64 [[VAL]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable
; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[VAL]], 2
; INSTCOMBINE-NEXT: ret i64 [[PTR_IDX]]
;
%ptr = getelementptr i32, ptr addrspace(1) null, i64 %val
%ret = ptrtoint ptr 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, ptr addrspace(1) null, i64 [[VAL]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i32
; LLPARSER-NEXT: ret i32 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i32
; INSTSIMPLIFY-NEXT: ret i32 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
; INSTCOMBINE-NEXT: [[RET:%.*]] = trunc i64 [[VAL]] to i32
; INSTCOMBINE-NEXT: ret i32 [[RET]]
;
%ptr = getelementptr i8, ptr addrspace(1) null, i64 %val
%ret = ptrtoint ptr 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, ptr addrspace(1) null, i64 [[NONZERO_OFFSET]]
; LLPARSER-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr addrspace(1) [[PTR]], i64 [[ZERO_OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
; CHECK-NEXT: ret i64 1234
;
%nonzero_offset = add i64 1234, 0
%zero_offset = sub i64 %nonzero_offset, 1234
%ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %nonzero_offset
%ptr2 = getelementptr i8, ptr addrspace(1) %ptr, i64 %zero_offset
%ret = ptrtoint ptr 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, ptr addrspace(1) null, i64 [[ZERO_OFFSET]]
; LLPARSER-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[PTR]], i64 [[NONZERO_OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
; CHECK-NEXT: ret i64 1234
;
%nonzero_offset = add i64 1234, 0
%zero_offset = sub i64 %nonzero_offset, 1234
%ptr = getelementptr i8, ptr addrspace(1) null, i64 %zero_offset
%ptr2 = getelementptr inbounds i8, ptr addrspace(1) %ptr, i64 %nonzero_offset
%ret = ptrtoint ptr 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 {
; LLPARSER-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero
; LLPARSER-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
; LLPARSER-NEXT: entry:
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 [[X]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero
; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
; INSTSIMPLIFY-NEXT: entry:
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 [[X]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero
; INSTCOMBINE-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
; INSTCOMBINE-NEXT: entry:
; INSTCOMBINE-NEXT: ret i64 [[X]]
;
entry:
%ptr = getelementptr inbounds %struct.S, ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 %x
%ret = ptrtoint ptr addrspace(1) %ptr to i64
ret i64 %ret
}
define i64 @fold_complex_index_multiple_nonzero(i64 %x) local_unnamed_addr #0 {
; LLPARSER-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero
; LLPARSER-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
; LLPARSER-NEXT: entry:
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 [[X]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero
; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
; INSTSIMPLIFY-NEXT: entry:
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 [[X]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero
; INSTCOMBINE-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
; INSTCOMBINE-NEXT: entry:
; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add nsw i64 [[X]], 96
; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]]
;
entry:
%ptr = getelementptr inbounds %struct.S, ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 %x
%ret = ptrtoint ptr 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, ptr addrspace(1) null, i64 [[NONZERO_OFFSET]]
; LLPARSER-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[PTR]], i64 [[ZERO_OFFSET]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
; CHECK-NEXT: ret i64 1234
;
%nonzero_offset = add i64 1234, 0
%zero_offset = sub i64 %nonzero_offset, 1234
%ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %nonzero_offset
%ptr2 = getelementptr inbounds i8, ptr addrspace(1) %ptr, i64 %zero_offset
%ret = ptrtoint ptr 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) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1
; LLPARSER-SAME: (i64 [[X:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 3
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1
; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 3
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1
; INSTCOMBINE-SAME: (i64 [[X:%.*]]) {
; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 2
; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], 6
; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]]
;
%ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 3
%ret = ptrtoint ptr addrspace(1) %ptr to i64
ret i64 %ret
}
define i64 @fold_ptrtoint_nullgep_array_one_var_2(i64 %x) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2
; LLPARSER-SAME: (i64 [[X:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 [[X]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2
; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 [[X]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2
; INSTCOMBINE-SAME: (i64 [[X:%.*]]) {
; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 1
; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], 28
; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]]
;
%ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 %x
%ret = ptrtoint ptr addrspace(1) %ptr to i64
ret i64 %ret
}
define i64 @fold_ptrtoint_nested_array_two_vars(i64 %x, i64 %y) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars
; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]]
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars
; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]]
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars
; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 2
; INSTCOMBINE-NEXT: [[PTR_IDX1:%.*]] = shl i64 [[Y]], 1
; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]]
; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]]
;
%ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 %y
%ret = ptrtoint ptr addrspace(1) %ptr to i64
ret i64 %ret
}
define i64 @fold_ptrtoint_nested_array_two_vars_plus_zero(i64 %x, i64 %y) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero
; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 0
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero
; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 0
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero
; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 3
; INSTCOMBINE-NEXT: [[PTR_IDX1:%.*]] = shl i64 [[Y]], 2
; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]]
; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]]
;
%ptr = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 %x, i64 %y, i64 0
%ret = ptrtoint ptr addrspace(1) %ptr to i64
ret i64 %ret
}
define i64 @fold_ptrtoint_nested_array_two_vars_plus_const(i64 %x, i64 %y) {
; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const
; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 1
; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; LLPARSER-NEXT: ret i64 [[RET]]
;
; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const
; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 1
; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; INSTSIMPLIFY-NEXT: ret i64 [[RET]]
;
; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const
; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 3
; INSTCOMBINE-NEXT: [[PTR_IDX1:%.*]] = shl i64 [[Y]], 2
; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]]
; INSTCOMBINE-NEXT: [[PTR_OFFS2:%.*]] = or disjoint i64 [[PTR_OFFS]], 2
; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS2]]
;
%ptr = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 %x, i64 %y, i64 1
%ret = ptrtoint ptr 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], ptr addrspace(1) null, i64 [[X]], i64 [[Y]]
; ALL-NEXT: call void @use_ptr(ptr addrspace(1) [[PTR]])
; ALL-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
; ALL-NEXT: ret i64 [[RET]]
;
%ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 %y
call void @use_ptr(ptr addrspace(1) %ptr)
%ret = ptrtoint ptr addrspace(1) %ptr to i64
ret i64 %ret
}