1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes 2; Check that we can fold operations with (gep null) inputs. 3; Note: the LLParser already does some constant folding, check that output first: 4; RUN: opt -passes=verify -S < %s | FileCheck %s --check-prefixes=ALL,LLPARSER 5; We should be able to fold almost everything in InstSimplify other than the final test which requries InstCombine 6; RUN: opt -S -passes=instsimplify < %s | FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,INTEGRAL,INSTSIMPLIFY,INTEGRAL-INSTSIMPLIFY 7; RUN: opt -S -passes=instcombine < %s | FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,INTEGRAL,INSTCOMBINE,INTEGRAL-INSTCOMBINE 8; Non-integral pointers limit certain transformations on pointers: 9; RUN: sed -e 's/p:64:64:64:64/p:64:64:64:64-ni:1/g' %s | opt -S -passes=instsimplify | \ 10; RUN: FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,NONINTEGRAL,INSTSIMPLIFY,NONINTEGRAL-INSTSIMPLIFY 11; RUN: sed -e 's/p:64:64:64:64/p:64:64:64:64-ni:1/g' %s | opt -S -passes=instcombine | \ 12; RUN: FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,NONINTEGRAL,INSTCOMBINE,NONINTEGRAL-INSTCOMBINE 13target datalayout = "p:64:64:64:64" 14 15declare void @use_i64(i64) 16declare void @use_ptr(ptr addrspace(1)) 17 18define i64 @constant_fold_ptrtoint_gep_zero() { 19; ALL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_zero() { 20; ALL-NEXT: ret i64 0 21; 22 ret i64 ptrtoint (ptr addrspace(1) null to i64) 23} 24define i64 @constant_fold_ptrtoint_gep_nonzero() { 25; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() { 26; LLPARSER-NEXT: ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64) 27; 28; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() { 29; INSTSIMPLIFY-NEXT: ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64) 30; 31; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() { 32; INSTCOMBINE-NEXT: ret i64 4936 33; 34 ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64) 35} 36 37define i64 @constant_fold_ptrtoint_gep_zero_inbounds() { 38; ALL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_zero_inbounds() { 39; ALL-NEXT: ret i64 0 40; 41 ret i64 ptrtoint (ptr addrspace(1) null to i64) 42} 43 44; In theory we could fold this to poison/null, but that would break offsetof 45; implementations that don't use __builtin_offsetof. 46; TODO: should Clang special case ((INTEGER)&((TYPE *)0)->MEMBER) to emit a non-inbounds GEP? 47define i64 @constant_fold_ptrtoint_gep_nonzero_inbounds() { 48; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() { 49; LLPARSER-NEXT: ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64) 50; 51; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() { 52; INSTSIMPLIFY-NEXT: ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64) 53; 54; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() { 55; INSTCOMBINE-NEXT: ret i64 4936 56; 57 ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64) 58} 59 60; Check all combinations of inbounds+non-inbounds GEP with the outer GEP having a non-zero offset 61define void @constant_fold_ptrtoint_of_gep_of_nullgep() { 62; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() { 63; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 64; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 65; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 66; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 67; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 68; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 69; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 70; LLPARSER-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 71; 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)) 72; 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)) 73; 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)) 74; 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)) 75; LLPARSER-NEXT: ret void 76; 77; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() { 78; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 79; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 80; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 81; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 82; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 83; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 84; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 85; INSTSIMPLIFY-NEXT: call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 86; 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)) 87; 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)) 88; 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)) 89; 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)) 90; INSTSIMPLIFY-NEXT: ret void 91; 92; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() { 93; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 94; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 95; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 96; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 97; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 98; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 99; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 100; INSTCOMBINE-NEXT: call void @use_i64(i64 1234) 101; INSTCOMBINE-NEXT: call void @use_i64(i64 0) 102; INSTCOMBINE-NEXT: call void @use_i64(i64 0) 103; INSTCOMBINE-NEXT: call void @use_i64(i64 0) 104; INSTCOMBINE-NEXT: call void @use_i64(i64 0) 105; INSTCOMBINE-NEXT: ret void 106; 107 call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 108 call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 109 call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64)) 110 call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64)) 111 ; Same again but this time with the inner GEP using the non-zero offset 112 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)) 113 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)) 114 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)) 115 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)) 116 ; And finally with two constants that sum to zero 117 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)) 118 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)) 119 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)) 120 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)) 121 ret void 122} 123 124; Another set of tests for instructions instead of constants 125define i64 @fold_ptrtoint_nullgep_zero() { 126; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero() { 127; LLPARSER-NEXT: [[OFFSET:%.*]] = add i64 0, 0 128; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[OFFSET]] 129; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 130; LLPARSER-NEXT: ret i64 [[RET]] 131; 132; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero() { 133; CHECK-NEXT: ret i64 0 134; 135 %offset = add i64 0, 0 136 %ptr = getelementptr i8, ptr addrspace(1) null, i64 %offset 137 %ret = ptrtoint ptr addrspace(1) %ptr to i64 138 ret i64 %ret 139} 140 141define i64 @fold_ptrtoint_nullgep_zero_inbounds() { 142; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero_inbounds() { 143; LLPARSER-NEXT: [[OFFSET:%.*]] = add i64 0, 0 144; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[OFFSET]] 145; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 146; LLPARSER-NEXT: ret i64 [[RET]] 147; 148; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero_inbounds() { 149; CHECK-NEXT: ret i64 0 150; 151 %offset = add i64 0, 0 152 %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %offset 153 %ret = ptrtoint ptr addrspace(1) %ptr to i64 154 ret i64 %ret 155} 156 157define i64 @fold_ptrtoint_nullgep_nonzero() { 158; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() { 159; LLPARSER-NEXT: [[OFFSET:%.*]] = add i64 1234, 0 160; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[OFFSET]] 161; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 162; LLPARSER-NEXT: ret i64 [[RET]] 163; 164; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() { 165; CHECK-NEXT: ret i64 1234 166; 167 %offset = add i64 1234, 0 168 %ptr = getelementptr i8, ptr addrspace(1) null, i64 %offset 169 %ret = ptrtoint ptr addrspace(1) %ptr to i64 170 ret i64 %ret 171} 172 173; Inbounds constant null-GEP with non-zero could be constant-folded to null/poison, 174; but folding it to the value makes ((INTEGER)&((TYPE *)0)->MEMBER) work. 175define i64 @fold_ptrtoint_nullgep_nonzero_inbounds() { 176; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() { 177; LLPARSER-NEXT: [[OFFSET:%.*]] = add i64 1234, 0 178; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[OFFSET]] 179; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 180; LLPARSER-NEXT: ret i64 [[RET]] 181; 182; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() { 183; CHECK-NEXT: ret i64 1234 184; 185 %offset = add i64 1234, 0 186 %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %offset 187 %ret = ptrtoint ptr addrspace(1) %ptr to i64 188 ret i64 %ret 189} 190 191; We should be able to fold ptrtoint(gep null, x) to x 192define i64 @fold_ptrtoint_nullgep_variable(i64 %val) { 193; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable 194; LLPARSER-SAME: (i64 [[VAL:%.*]]) { 195; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]] 196; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 197; LLPARSER-NEXT: ret i64 [[RET]] 198; 199; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable 200; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) { 201; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]] 202; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 203; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 204; 205; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable 206; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) { 207; INSTCOMBINE-NEXT: ret i64 [[VAL]] 208; 209 %ptr = getelementptr i8, ptr addrspace(1) null, i64 %val 210 %ret = ptrtoint ptr addrspace(1) %ptr to i64 211 ret i64 %ret 212} 213 214; Inbounds null-GEP with non-zero offset could be folded to poison/null. 215define i64 @fold_ptrtoint_nullgep_variable_known_nonzero(i64 %val) { 216; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero 217; LLPARSER-SAME: (i64 [[VAL:%.*]]) { 218; LLPARSER-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 219; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]] 220; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 221; LLPARSER-NEXT: ret i64 [[RET]] 222; 223; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero 224; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) { 225; INSTSIMPLIFY-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 226; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]] 227; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 228; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 229; 230; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero 231; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) { 232; INSTCOMBINE-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 233; INSTCOMBINE-NEXT: ret i64 [[NON_ZERO_OFFSET]] 234; 235 %non_zero_offset = or i64 %val, 1 236 %ptr = getelementptr i8, ptr addrspace(1) null, i64 %non_zero_offset 237 %ret = ptrtoint ptr addrspace(1) %ptr to i64 238 ret i64 %ret 239} 240 241; This is only valid if %val is zero so we could fold the result to 0. 242define i64 @fold_ptrtoint_nullgep_variable_inbounds(i64 %val) { 243; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds 244; LLPARSER-SAME: (i64 [[VAL:%.*]]) { 245; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[VAL]] 246; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 247; LLPARSER-NEXT: ret i64 [[RET]] 248; 249; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds 250; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) { 251; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[VAL]] 252; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 253; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 254; 255; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds 256; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) { 257; INSTCOMBINE-NEXT: ret i64 [[VAL]] 258; 259 %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %val 260 %ret = ptrtoint ptr addrspace(1) %ptr to i64 261 ret i64 %ret 262} 263 264; A non-constant but known-non-zero GEP could be folded to poison/null 265define i64 @fold_ptrtoint_nullgep_variable_known_nonzero_inbounds(i64 %val) { 266; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds 267; LLPARSER-SAME: (i64 [[VAL:%.*]]) { 268; LLPARSER-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 269; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]] 270; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 271; LLPARSER-NEXT: ret i64 [[RET]] 272; 273; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds 274; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) { 275; INSTSIMPLIFY-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 276; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]] 277; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 278; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 279; 280; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds 281; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) { 282; INSTCOMBINE-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 283; INSTCOMBINE-NEXT: ret i64 [[NON_ZERO_OFFSET]] 284; 285 %non_zero_offset = or i64 %val, 1 286 %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %non_zero_offset 287 %ret = ptrtoint ptr addrspace(1) %ptr to i64 288 ret i64 %ret 289} 290 291; A non-constant but known-non-zero GEP could be folded to poison/null 292define i64 @fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices(i64 %val) { 293; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices 294; LLPARSER-SAME: (i64 [[VAL:%.*]]) { 295; LLPARSER-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 296; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]], i32 1 297; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 298; LLPARSER-NEXT: ret i64 [[RET]] 299; 300; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices 301; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) { 302; INSTSIMPLIFY-NEXT: [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1 303; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]], i32 1 304; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 305; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 306; 307; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices 308; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) { 309; INSTCOMBINE-NEXT: [[NON_ZERO_OFFSET:%.*]] = shl i64 [[VAL]], 1 310; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = or i64 [[NON_ZERO_OFFSET]], 3 311; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]] 312; 313 %non_zero_offset = or i64 %val, 1 314 %ptr = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 %non_zero_offset, i32 1 315 %ret = ptrtoint ptr addrspace(1) %ptr to i64 316 ret i64 %ret 317} 318 319; We can't fold non-i8 GEPs in InstSimplify since that would require adding new arithmetic. 320; However, InstCombine can decompose the null gep and convert it to a shift. 321define i64 @fold_ptrtoint_nullgep_i32_variable(i64 %val) { 322; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable 323; LLPARSER-SAME: (i64 [[VAL:%.*]]) { 324; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i32, ptr addrspace(1) null, i64 [[VAL]] 325; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 326; LLPARSER-NEXT: ret i64 [[RET]] 327; 328; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable 329; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) { 330; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i32, ptr addrspace(1) null, i64 [[VAL]] 331; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 332; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 333; 334; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable 335; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) { 336; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[VAL]], 2 337; INSTCOMBINE-NEXT: ret i64 [[PTR_IDX]] 338; 339 %ptr = getelementptr i32, ptr addrspace(1) null, i64 %val 340 %ret = ptrtoint ptr addrspace(1) %ptr to i64 341 ret i64 %ret 342} 343 344; ptrtoint type does not match index type so requires requite a new trunc instruction 345define i32 @fold_ptrtoint_nullgep_variable_trunc(i64 %val) { 346; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc 347; LLPARSER-SAME: (i64 [[VAL:%.*]]) { 348; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]] 349; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i32 350; LLPARSER-NEXT: ret i32 [[RET]] 351; 352; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc 353; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) { 354; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]] 355; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i32 356; INSTSIMPLIFY-NEXT: ret i32 [[RET]] 357; 358; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc 359; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) { 360; INSTCOMBINE-NEXT: [[RET:%.*]] = trunc i64 [[VAL]] to i32 361; INSTCOMBINE-NEXT: ret i32 [[RET]] 362; 363 %ptr = getelementptr i8, ptr addrspace(1) null, i64 %val 364 %ret = ptrtoint ptr addrspace(1) %ptr to i32 365 ret i32 %ret 366} 367 368; For the following three tests, we could fold the result to poison/null since there is at least 369; one inbounds GEP on null with a non-zero offset. 370define i64 @fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() { 371; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() { 372; LLPARSER-NEXT: [[NONZERO_OFFSET:%.*]] = add i64 1234, 0 373; LLPARSER-NEXT: [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234 374; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NONZERO_OFFSET]] 375; LLPARSER-NEXT: [[PTR2:%.*]] = getelementptr i8, ptr addrspace(1) [[PTR]], i64 [[ZERO_OFFSET]] 376; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64 377; LLPARSER-NEXT: ret i64 [[RET]] 378; 379; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() { 380; CHECK-NEXT: ret i64 1234 381; 382 %nonzero_offset = add i64 1234, 0 383 %zero_offset = sub i64 %nonzero_offset, 1234 384 %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %nonzero_offset 385 %ptr2 = getelementptr i8, ptr addrspace(1) %ptr, i64 %zero_offset 386 %ret = ptrtoint ptr addrspace(1) %ptr2 to i64 387 ret i64 %ret 388} 389 390define i64 @fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() { 391; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() { 392; LLPARSER-NEXT: [[NONZERO_OFFSET:%.*]] = add i64 1234, 0 393; LLPARSER-NEXT: [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234 394; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[ZERO_OFFSET]] 395; LLPARSER-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[PTR]], i64 [[NONZERO_OFFSET]] 396; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64 397; LLPARSER-NEXT: ret i64 [[RET]] 398; 399; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() { 400; CHECK-NEXT: ret i64 1234 401; 402 %nonzero_offset = add i64 1234, 0 403 %zero_offset = sub i64 %nonzero_offset, 1234 404 %ptr = getelementptr i8, ptr addrspace(1) null, i64 %zero_offset 405 %ptr2 = getelementptr inbounds i8, ptr addrspace(1) %ptr, i64 %nonzero_offset 406 %ret = ptrtoint ptr addrspace(1) %ptr2 to i64 407 ret i64 %ret 408} 409 410; We should also be able to fold GEPs with multiple indices. 411%struct.S = type { [2 x %struct.K] } 412%struct.K = type { [32 x i8] } 413 414define i64 @fold_complex_index_last_nonzero(i64 %x) local_unnamed_addr #0 { 415; LLPARSER-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero 416; LLPARSER-SAME: (i64 [[X:%.*]]) local_unnamed_addr { 417; LLPARSER-NEXT: entry: 418; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 [[X]] 419; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 420; LLPARSER-NEXT: ret i64 [[RET]] 421; 422; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero 423; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) local_unnamed_addr { 424; INSTSIMPLIFY-NEXT: entry: 425; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 [[X]] 426; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 427; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 428; 429; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero 430; INSTCOMBINE-SAME: (i64 [[X:%.*]]) local_unnamed_addr { 431; INSTCOMBINE-NEXT: entry: 432; INSTCOMBINE-NEXT: ret i64 [[X]] 433; 434entry: 435 %ptr = getelementptr inbounds %struct.S, ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 %x 436 %ret = ptrtoint ptr addrspace(1) %ptr to i64 437 ret i64 %ret 438} 439 440define i64 @fold_complex_index_multiple_nonzero(i64 %x) local_unnamed_addr #0 { 441; LLPARSER-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero 442; LLPARSER-SAME: (i64 [[X:%.*]]) local_unnamed_addr { 443; LLPARSER-NEXT: entry: 444; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 [[X]] 445; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 446; LLPARSER-NEXT: ret i64 [[RET]] 447; 448; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero 449; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) local_unnamed_addr { 450; INSTSIMPLIFY-NEXT: entry: 451; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 [[X]] 452; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 453; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 454; 455; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero 456; INSTCOMBINE-SAME: (i64 [[X:%.*]]) local_unnamed_addr { 457; INSTCOMBINE-NEXT: entry: 458; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add nsw i64 [[X]], 96 459; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]] 460; 461entry: 462 %ptr = getelementptr inbounds %struct.S, ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 %x 463 %ret = ptrtoint ptr addrspace(1) %ptr to i64 464 ret i64 %ret 465} 466 467define i64 @fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() { 468; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() { 469; LLPARSER-NEXT: [[NONZERO_OFFSET:%.*]] = add i64 1234, 0 470; LLPARSER-NEXT: [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234 471; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NONZERO_OFFSET]] 472; LLPARSER-NEXT: [[PTR2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[PTR]], i64 [[ZERO_OFFSET]] 473; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64 474; LLPARSER-NEXT: ret i64 [[RET]] 475; 476; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() { 477; CHECK-NEXT: ret i64 1234 478; 479 %nonzero_offset = add i64 1234, 0 480 %zero_offset = sub i64 %nonzero_offset, 1234 481 %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %nonzero_offset 482 %ptr2 = getelementptr inbounds i8, ptr addrspace(1) %ptr, i64 %zero_offset 483 %ret = ptrtoint ptr addrspace(1) %ptr2 to i64 484 ret i64 %ret 485} 486 487; Check that InstCombine can convert ptrtoint(gep null) with multiple indices 488define i64 @fold_ptrtoint_nullgep_array_one_var_1(i64 %x) { 489; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1 490; LLPARSER-SAME: (i64 [[X:%.*]]) { 491; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 3 492; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 493; LLPARSER-NEXT: ret i64 [[RET]] 494; 495; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1 496; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) { 497; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 3 498; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 499; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 500; 501; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1 502; INSTCOMBINE-SAME: (i64 [[X:%.*]]) { 503; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 2 504; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], 6 505; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]] 506; 507 %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 3 508 %ret = ptrtoint ptr addrspace(1) %ptr to i64 509 ret i64 %ret 510} 511 512define i64 @fold_ptrtoint_nullgep_array_one_var_2(i64 %x) { 513; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2 514; LLPARSER-SAME: (i64 [[X:%.*]]) { 515; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 [[X]] 516; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 517; LLPARSER-NEXT: ret i64 [[RET]] 518; 519; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2 520; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) { 521; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 [[X]] 522; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 523; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 524; 525; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2 526; INSTCOMBINE-SAME: (i64 [[X:%.*]]) { 527; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 1 528; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], 28 529; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]] 530; 531 %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 %x 532 %ret = ptrtoint ptr addrspace(1) %ptr to i64 533 ret i64 %ret 534} 535 536define i64 @fold_ptrtoint_nested_array_two_vars(i64 %x, i64 %y) { 537; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars 538; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 539; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]] 540; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 541; LLPARSER-NEXT: ret i64 [[RET]] 542; 543; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars 544; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 545; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]] 546; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 547; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 548; 549; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars 550; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 551; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 2 552; INSTCOMBINE-NEXT: [[PTR_IDX1:%.*]] = shl i64 [[Y]], 1 553; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]] 554; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]] 555; 556 557 %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 %y 558 %ret = ptrtoint ptr addrspace(1) %ptr to i64 559 ret i64 %ret 560} 561 562define i64 @fold_ptrtoint_nested_array_two_vars_plus_zero(i64 %x, i64 %y) { 563; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero 564; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 565; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 0 566; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 567; LLPARSER-NEXT: ret i64 [[RET]] 568; 569; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero 570; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 571; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 0 572; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 573; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 574; 575; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero 576; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 577; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 3 578; INSTCOMBINE-NEXT: [[PTR_IDX1:%.*]] = shl i64 [[Y]], 2 579; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]] 580; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS]] 581; 582 %ptr = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 %x, i64 %y, i64 0 583 %ret = ptrtoint ptr addrspace(1) %ptr to i64 584 ret i64 %ret 585} 586 587define i64 @fold_ptrtoint_nested_array_two_vars_plus_const(i64 %x, i64 %y) { 588; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const 589; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 590; LLPARSER-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 1 591; LLPARSER-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 592; LLPARSER-NEXT: ret i64 [[RET]] 593; 594; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const 595; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 596; INSTSIMPLIFY-NEXT: [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 1 597; INSTSIMPLIFY-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 598; INSTSIMPLIFY-NEXT: ret i64 [[RET]] 599; 600; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const 601; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 602; INSTCOMBINE-NEXT: [[PTR_IDX:%.*]] = shl i64 [[X]], 3 603; INSTCOMBINE-NEXT: [[PTR_IDX1:%.*]] = shl i64 [[Y]], 2 604; INSTCOMBINE-NEXT: [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]] 605; INSTCOMBINE-NEXT: [[PTR_OFFS2:%.*]] = or disjoint i64 [[PTR_OFFS]], 2 606; INSTCOMBINE-NEXT: ret i64 [[PTR_OFFS2]] 607; 608 %ptr = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 %x, i64 %y, i64 1 609 %ret = ptrtoint ptr addrspace(1) %ptr to i64 610 ret i64 %ret 611} 612 613; Negative test -- should not be folded since there are multiple GEP uses 614define i64 @fold_ptrtoint_nested_nullgep_array_variable_multiple_uses(i64 %x, i64 %y) { 615; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_nullgep_array_variable_multiple_uses 616; ALL-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) { 617; ALL-NEXT: [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]] 618; ALL-NEXT: call void @use_ptr(ptr addrspace(1) [[PTR]]) 619; ALL-NEXT: [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64 620; ALL-NEXT: ret i64 [[RET]] 621; 622 %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 %y 623 call void @use_ptr(ptr addrspace(1) %ptr) 624 %ret = ptrtoint ptr addrspace(1) %ptr to i64 625 ret i64 %ret 626} 627