| ; 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 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 |
| ; |
| ; 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 0) |
| ; INSTSIMPLIFY-NEXT: call void @use_i64(i64 0) |
| ; INSTSIMPLIFY-NEXT: call void @use_i64(i64 0) |
| ; INSTSIMPLIFY-NEXT: call void @use_i64(i64 0) |
| ; 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 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 |
| } |