260 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3 4; Constant-indexed GEP instructions in a chain of GEP instructions should be5; swapped to the end whenever such transformation is valid. This allows them to6; be merged.7 8declare void @use(i1)9 10 11; The constant-indexed GEP instruction should be swapped to the end, even12; without merging.13; result = (((ptr) p + a) + b) + 114define ptr @basic(ptr %p, i64 %a, i64 %b) {15; CHECK-LABEL: @basic(16; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P:%.*]], i64 417; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[A:%.*]]18; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 [[B:%.*]]19; CHECK-NEXT: ret ptr [[TMP3]]20;21 %1 = getelementptr inbounds i32, ptr %p, i64 122 %2 = getelementptr inbounds i32, ptr %1, i64 %a23 %3 = getelementptr inbounds i32, ptr %2, i64 %b24 ret ptr %325}26 27; GEP with the last index being a constant should also be swapped.28define ptr @partialConstant1(ptr %p, i64 %a, i64 %b) {29; CHECK-LABEL: @partialConstant1(30; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[B:%.*]]31; CHECK-NEXT: ret ptr [[TMP1]]32;33 %1 = getelementptr inbounds [4 x i32], ptr %p, i64 %a, i64 134 %2 = getelementptr inbounds i32, ptr %p, i64 %b35 ret ptr %236}37 38; Negative test. GEP should not be swapped if the last index is not a constant.39define ptr @partialConstant2(ptr %p, i64 %a, i64 %b) {40; CHECK-LABEL: @partialConstant2(41; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[B:%.*]]42; CHECK-NEXT: ret ptr [[TMP1]]43;44 %1 = getelementptr inbounds [4 x i32], ptr %p, i64 1, i64 %a45 %2 = getelementptr inbounds i32, ptr %p, i64 %b46 ret ptr %247}48 49; Constant-indexed GEP are merged after swawpping.50; result = ((ptr) p + a) + 351define ptr @merge(ptr %p, i64 %a) {52; CHECK-LABEL: @merge(53; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[A:%.*]]54; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[TMP1]], i64 1255; CHECK-NEXT: ret ptr [[TMP2]]56;57 %1 = getelementptr inbounds i32, ptr %p, i64 158 %2 = getelementptr inbounds i32, ptr %1, i64 %a59 %3 = getelementptr inbounds i32, ptr %2, i64 260 ret ptr %361}62 63; Multiple constant-indexed GEP. Note that the first two cannot be merged at64; first, but after the second and third are merged, the result can be merged65; with the first one on the next pass.66; result = (ptr) ((ptr) ((ptr) ptr + a) + (a * b)) + 967define ptr @nested(ptr %p, i64 %a, i64 %b) {68; CHECK-LABEL: @nested(69; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[A:%.*]]70; CHECK-NEXT: [[TMP2:%.*]] = mul i64 [[A]], [[B:%.*]]71; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i16, ptr [[TMP1]], i64 [[TMP2]]72; CHECK-NEXT: [[TMP4:%.*]] = getelementptr i8, ptr [[TMP3]], i64 16073; CHECK-NEXT: ret ptr [[TMP4]]74;75 %1 = getelementptr inbounds <3 x i32>, ptr %p, i64 176 %2 = getelementptr inbounds i8, ptr %1, i64 %a77 %3 = mul i64 %a, %b78 %4 = getelementptr inbounds <5 x i32>, ptr %2, i64 479 %5 = getelementptr inbounds i16, ptr %4, i64 %380 %6 = getelementptr inbounds <4 x i32>, ptr %5, i64 181 ret ptr %682}83 84; It is valid to swap if the source operand of the first GEP has multiple uses.85define ptr @multipleUses1(ptr %p) {86; CHECK-LABEL: @multipleUses1(87; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P:%.*]], i64 488; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[P]] to i6489; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[TMP2]]90; CHECK-NEXT: ret ptr [[TMP3]]91;92 %1 = getelementptr inbounds i32, ptr %p, i64 193 %2 = ptrtoint ptr %p to i6494 %3 = getelementptr inbounds i32, ptr %1, i64 %295 ret ptr %396}97 98; It is valid to swap if the second GEP has multiple uses.99define ptr @multipleUses2(ptr %p, i64 %a) {100; CHECK-LABEL: @multipleUses2(101; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P:%.*]], i64 4102; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[A:%.*]]103; CHECK-NEXT: call void @use(ptr nonnull [[TMP2]])104; CHECK-NEXT: ret ptr [[TMP2]]105;106 %1 = getelementptr inbounds i32, ptr %p, i64 1107 %2 = getelementptr inbounds i32, ptr %1, i64 %a108 call void @use(ptr %2)109 ret ptr %2110}111 112; Negative test. It is not valid to swap if the first GEP has multiple uses.113define ptr @multipleUses3(ptr %p) {114; CHECK-LABEL: @multipleUses3(115; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds nuw i8, ptr [[P:%.*]], i64 4116; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i64117; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[TMP2]]118; CHECK-NEXT: ret ptr [[TMP3]]119;120 %1 = getelementptr inbounds i32, ptr %p, i64 1121 %2 = ptrtoint ptr %1 to i64122 %3 = getelementptr inbounds i32, ptr %1, i64 %2123 ret ptr %3124}125 126define ptr @merge_nuw(ptr %p, i64 %a) {127; CHECK-LABEL: @merge_nuw(128; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nuw i32, ptr [[P:%.*]], i64 [[A:%.*]]129; CHECK-NEXT: [[GEP3:%.*]] = getelementptr nuw i8, ptr [[GEP2]], i64 5130; CHECK-NEXT: ret ptr [[GEP3]]131;132 %gep1 = getelementptr nuw i8, ptr %p, i64 1133 %gep2 = getelementptr nuw i32, ptr %gep1, i64 %a134 %gep3 = getelementptr nuw i32, ptr %gep2, i64 1135 ret ptr %gep3136}137 138define ptr @merge_nuw_inbounds(ptr %p, i64 %a) {139; CHECK-LABEL: @merge_nuw_inbounds(140; CHECK-NEXT: [[GEP2:%.*]] = getelementptr inbounds nuw i32, ptr [[P:%.*]], i64 [[A:%.*]]141; CHECK-NEXT: [[GEP3:%.*]] = getelementptr inbounds nuw i8, ptr [[GEP2]], i64 5142; CHECK-NEXT: ret ptr [[GEP3]]143;144 %gep1 = getelementptr inbounds nuw i8, ptr %p, i64 1145 %gep2 = getelementptr inbounds nuw i32, ptr %gep1, i64 %a146 %gep3 = getelementptr inbounds nuw i32, ptr %gep2, i64 1147 ret ptr %gep3148}149 150; It would be okay to preserve nusw here, as the constant addition does not151; overflow.152define ptr @merge_nuw_nusw(ptr %p, i64 %a) {153; CHECK-LABEL: @merge_nuw_nusw(154; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nusw nuw i32, ptr [[P:%.*]], i64 [[A:%.*]]155; CHECK-NEXT: [[GEP3:%.*]] = getelementptr nuw i8, ptr [[GEP2]], i64 5156; CHECK-NEXT: ret ptr [[GEP3]]157;158 %gep1 = getelementptr nusw nuw i8, ptr %p, i64 1159 %gep2 = getelementptr nusw nuw i32, ptr %gep1, i64 %a160 %gep3 = getelementptr nusw nuw i32, ptr %gep2, i64 1161 ret ptr %gep3162}163 164; Can't preserve nusw on the final GEP165define ptr @merge_nuw_nusw_overflow(ptr %p, i64 %a) {166; CHECK-LABEL: @merge_nuw_nusw_overflow(167; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nusw nuw i32, ptr [[P:%.*]], i64 [[A:%.*]]168; CHECK-NEXT: [[GEP3:%.*]] = getelementptr nuw i8, ptr [[GEP2]], i64 -2305843009213693952169; CHECK-NEXT: ret ptr [[GEP3]]170;171 %gep1 = getelementptr nusw nuw i8, ptr %p, i64 u0x7000000000000000172 %gep2 = getelementptr nusw nuw i32, ptr %gep1, i64 %a173 %gep3 = getelementptr nusw nuw i8, ptr %gep2, i64 u0x7000000000000000174 ret ptr %gep3175}176 177define ptr @merge_missing_nuw1(ptr %p, i64 %a) {178; CHECK-LABEL: @merge_missing_nuw1(179; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[A:%.*]]180; CHECK-NEXT: [[GEP3:%.*]] = getelementptr i8, ptr [[GEP2]], i64 5181; CHECK-NEXT: ret ptr [[GEP3]]182;183 %gep1 = getelementptr i8, ptr %p, i64 1184 %gep2 = getelementptr nuw i32, ptr %gep1, i64 %a185 %gep3 = getelementptr nuw i32, ptr %gep2, i64 1186 ret ptr %gep3187}188 189define ptr @merge_missing_nuw2(ptr %p, i64 %a) {190; CHECK-LABEL: @merge_missing_nuw2(191; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[A:%.*]]192; CHECK-NEXT: [[GEP3:%.*]] = getelementptr i8, ptr [[GEP2]], i64 5193; CHECK-NEXT: ret ptr [[GEP3]]194;195 %gep1 = getelementptr nuw i8, ptr %p, i64 1196 %gep2 = getelementptr i32, ptr %gep1, i64 %a197 %gep3 = getelementptr nuw i32, ptr %gep2, i64 1198 ret ptr %gep3199}200 201define ptr @merge_missing_nuw3(ptr %p, i64 %a) {202; CHECK-LABEL: @merge_missing_nuw3(203; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nuw i32, ptr [[P:%.*]], i64 [[A:%.*]]204; CHECK-NEXT: [[GEP3:%.*]] = getelementptr i8, ptr [[GEP2]], i64 5205; CHECK-NEXT: ret ptr [[GEP3]]206;207 %gep1 = getelementptr nuw i8, ptr %p, i64 1208 %gep2 = getelementptr nuw i32, ptr %gep1, i64 %a209 %gep3 = getelementptr i32, ptr %gep2, i64 1210 ret ptr %gep3211}212 213define ptr @merge_nuw_missing_inbounds(ptr %p, i64 %a) {214; CHECK-LABEL: @merge_nuw_missing_inbounds(215; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nuw i32, ptr [[P:%.*]], i64 [[A:%.*]]216; CHECK-NEXT: [[GEP3:%.*]] = getelementptr nuw i8, ptr [[GEP2]], i64 5217; CHECK-NEXT: ret ptr [[GEP3]]218;219 %gep1 = getelementptr nuw i8, ptr %p, i64 1220 %gep2 = getelementptr inbounds nuw i32, ptr %gep1, i64 %a221 %gep3 = getelementptr inbounds nuw i32, ptr %gep2, i64 1222 ret ptr %gep3223}224 225define ptr @merge_nuw_missing_nusw(ptr %p, i64 %a) {226; CHECK-LABEL: @merge_nuw_missing_nusw(227; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nuw i32, ptr [[P:%.*]], i64 [[A:%.*]]228; CHECK-NEXT: [[GEP3:%.*]] = getelementptr nuw i8, ptr [[GEP2]], i64 5229; CHECK-NEXT: ret ptr [[GEP3]]230;231 %gep1 = getelementptr nusw nuw i8, ptr %p, i64 1232 %gep2 = getelementptr nuw i32, ptr %gep1, i64 %a233 %gep3 = getelementptr nusw nuw i32, ptr %gep2, i64 1234 ret ptr %gep3235}236 237define ptr @merge_inbounds_missing_nuw(ptr %p, i64 %a) {238; CHECK-LABEL: @merge_inbounds_missing_nuw(239; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[A:%.*]]240; CHECK-NEXT: [[GEP3:%.*]] = getelementptr i8, ptr [[GEP2]], i64 5241; CHECK-NEXT: ret ptr [[GEP3]]242;243 %gep1 = getelementptr inbounds nuw i8, ptr %p, i64 1244 %gep2 = getelementptr inbounds i32, ptr %gep1, i64 %a245 %gep3 = getelementptr inbounds nuw i32, ptr %gep2, i64 1246 ret ptr %gep3247}248 249define ptr @merge_nusw_missing_nuw(ptr %p, i64 %a) {250; CHECK-LABEL: @merge_nusw_missing_nuw(251; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[A:%.*]]252; CHECK-NEXT: [[GEP3:%.*]] = getelementptr i8, ptr [[GEP2]], i64 5253; CHECK-NEXT: ret ptr [[GEP3]]254;255 %gep1 = getelementptr nusw nuw i8, ptr %p, i64 1256 %gep2 = getelementptr nusw i32, ptr %gep1, i64 %a257 %gep3 = getelementptr nusw nuw i32, ptr %gep2, i64 1258 ret ptr %gep3259}260