519 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt -S -passes=instcombine < %s | FileCheck %s3 4declare void @usei32(i32)5 6; If we have a phi of extractvalues, we can sink it,7; Here, we only need a PHI for extracted values.8define i32 @test0({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {9; CHECK-LABEL: @test0(10; CHECK-NEXT: entry:11; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]12; CHECK: left:13; CHECK-NEXT: br label [[END:%.*]]14; CHECK: right:15; CHECK-NEXT: br label [[END]]16; CHECK: end:17; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]18; CHECK-NEXT: [[R:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN]], 019; CHECK-NEXT: ret i32 [[R]]20;21entry:22 br i1 %c, label %left, label %right23 24left:25 %i0 = extractvalue { i32, i32 } %agg_left, 026 br label %end27 28right:29 %i1 = extractvalue { i32, i32 } %agg_right, 030 br label %end31 32end:33 %r = phi i32 [ %i0, %left ], [ %i1, %right ]34 ret i32 %r35}36 37; But only if the extractvalues have no extra uses38define i32 @test1_extrause0({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {39; CHECK-LABEL: @test1_extrause0(40; CHECK-NEXT: entry:41; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]42; CHECK: left:43; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 044; CHECK-NEXT: call void @usei32(i32 [[I0]])45; CHECK-NEXT: br label [[END:%.*]]46; CHECK: right:47; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 048; CHECK-NEXT: br label [[END]]49; CHECK: end:50; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]51; CHECK-NEXT: ret i32 [[R]]52;53entry:54 br i1 %c, label %left, label %right55 56left:57 %i0 = extractvalue { i32, i32 } %agg_left, 058 call void @usei32(i32 %i0)59 br label %end60 61right:62 %i1 = extractvalue { i32, i32 } %agg_right, 063 br label %end64 65end:66 %r = phi i32 [ %i0, %left ], [ %i1, %right ]67 ret i32 %r68}69define i32 @test2_extrause1({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {70; CHECK-LABEL: @test2_extrause1(71; CHECK-NEXT: entry:72; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]73; CHECK: left:74; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 075; CHECK-NEXT: br label [[END:%.*]]76; CHECK: right:77; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 078; CHECK-NEXT: call void @usei32(i32 [[I1]])79; CHECK-NEXT: br label [[END]]80; CHECK: end:81; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]82; CHECK-NEXT: ret i32 [[R]]83;84entry:85 br i1 %c, label %left, label %right86 87left:88 %i0 = extractvalue { i32, i32 } %agg_left, 089 br label %end90 91right:92 %i1 = extractvalue { i32, i32 } %agg_right, 093 call void @usei32(i32 %i1)94 br label %end95 96end:97 %r = phi i32 [ %i0, %left ], [ %i1, %right ]98 ret i32 %r99}100define i32 @test3_extrause2({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {101; CHECK-LABEL: @test3_extrause2(102; CHECK-NEXT: entry:103; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]104; CHECK: left:105; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0106; CHECK-NEXT: call void @usei32(i32 [[I0]])107; CHECK-NEXT: br label [[END:%.*]]108; CHECK: right:109; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0110; CHECK-NEXT: call void @usei32(i32 [[I1]])111; CHECK-NEXT: br label [[END]]112; CHECK: end:113; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]114; CHECK-NEXT: ret i32 [[R]]115;116entry:117 br i1 %c, label %left, label %right118 119left:120 %i0 = extractvalue { i32, i32 } %agg_left, 0121 call void @usei32(i32 %i0)122 br label %end123 124right:125 %i1 = extractvalue { i32, i32 } %agg_right, 0126 call void @usei32(i32 %i1)127 br label %end128 129end:130 %r = phi i32 [ %i0, %left ], [ %i1, %right ]131 ret i32 %r132}133 134; But the indices must match135define i32 @test4({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) {136; CHECK-LABEL: @test4(137; CHECK-NEXT: entry:138; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]139; CHECK: left:140; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0141; CHECK-NEXT: br label [[END:%.*]]142; CHECK: right:143; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 1144; CHECK-NEXT: br label [[END]]145; CHECK: end:146; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]147; CHECK-NEXT: ret i32 [[R]]148;149entry:150 br i1 %c, label %left, label %right151 152left:153 %i0 = extractvalue { i32, i32 } %agg_left, 0154 br label %end155 156right:157 %i1 = extractvalue { i32, i32 } %agg_right, 1158 br label %end159 160end:161 %r = phi i32 [ %i0, %left ], [ %i1, %right ]162 ret i32 %r163}164 165; More complex aggregates are fine, too, as long as indices match.166define i32 @test5({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) {167; CHECK-LABEL: @test5(168; CHECK-NEXT: entry:169; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]170; CHECK: left:171; CHECK-NEXT: br label [[END:%.*]]172; CHECK: right:173; CHECK-NEXT: br label [[END]]174; CHECK: end:175; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { { i32, i32 }, { i32, i32 } } [ [[AGG_LEFT:%.*]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]176; CHECK-NEXT: [[R:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT_PN]], 0, 0177; CHECK-NEXT: ret i32 [[R]]178;179entry:180 br i1 %c, label %left, label %right181 182left:183 %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0184 br label %end185 186right:187 %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 0, 0188 br label %end189 190end:191 %r = phi i32 [ %i0, %left ], [ %i1, %right ]192 ret i32 %r193}194 195; The indices must fully match, on all levels.196define i32 @test6({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) {197; CHECK-LABEL: @test6(198; CHECK-NEXT: entry:199; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]200; CHECK: left:201; CHECK-NEXT: [[I0:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT:%.*]], 0, 0202; CHECK-NEXT: br label [[END:%.*]]203; CHECK: right:204; CHECK-NEXT: [[I1:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_RIGHT:%.*]], 0, 1205; CHECK-NEXT: br label [[END]]206; CHECK: end:207; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]208; CHECK-NEXT: ret i32 [[R]]209;210entry:211 br i1 %c, label %left, label %right212 213left:214 %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0215 br label %end216 217right:218 %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 0, 1219 br label %end220 221end:222 %r = phi i32 [ %i0, %left ], [ %i1, %right ]223 ret i32 %r224}225define i32 @test7({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) {226; CHECK-LABEL: @test7(227; CHECK-NEXT: entry:228; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]229; CHECK: left:230; CHECK-NEXT: [[I0:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT:%.*]], 0, 0231; CHECK-NEXT: br label [[END:%.*]]232; CHECK: right:233; CHECK-NEXT: [[I1:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_RIGHT:%.*]], 1, 0234; CHECK-NEXT: br label [[END]]235; CHECK: end:236; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]237; CHECK-NEXT: ret i32 [[R]]238;239entry:240 br i1 %c, label %left, label %right241 242left:243 %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0244 br label %end245 246right:247 %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 1, 0248 br label %end249 250end:251 %r = phi i32 [ %i0, %left ], [ %i1, %right ]252 ret i32 %r253}254define i32 @test8({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) {255; CHECK-LABEL: @test8(256; CHECK-NEXT: entry:257; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]258; CHECK: left:259; CHECK-NEXT: [[I0:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT:%.*]], 0, 0260; CHECK-NEXT: br label [[END:%.*]]261; CHECK: right:262; CHECK-NEXT: [[I1:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_RIGHT:%.*]], 1, 1263; CHECK-NEXT: br label [[END]]264; CHECK: end:265; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]266; CHECK-NEXT: ret i32 [[R]]267;268entry:269 br i1 %c, label %left, label %right270 271left:272 %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0273 br label %end274 275right:276 %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 1, 1277 br label %end278 279end:280 %r = phi i32 [ %i0, %left ], [ %i1, %right ]281 ret i32 %r282}283 284; Also, unlike PHI-of-insertvalues, here the base aggregates of extractvalue285; can have different types, and just checking the indices is not enough.286define i32 @test9({ i32, i32 } %agg_left, { i32, { i32, i32 } } %agg_right, i1 %c) {287; CHECK-LABEL: @test9(288; CHECK-NEXT: entry:289; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]290; CHECK: left:291; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0292; CHECK-NEXT: br label [[END:%.*]]293; CHECK: right:294; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, { i32, i32 } } [[AGG_RIGHT:%.*]], 0295; CHECK-NEXT: br label [[END]]296; CHECK: end:297; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]298; CHECK-NEXT: ret i32 [[R]]299;300entry:301 br i1 %c, label %left, label %right302 303left:304 %i0 = extractvalue { i32, i32 } %agg_left, 0305 br label %end306 307right:308 %i1 = extractvalue { i32, { i32, i32 } } %agg_right, 0309 br label %end310 311end:312 %r = phi i32 [ %i0, %left ], [ %i1, %right ]313 ret i32 %r314}315 316; It is fine if there are multiple uses of the PHI's value, as long as they are all in the PHI node itself317define i32 @test10({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0, i1 %c1) {318; CHECK-LABEL: @test10(319; CHECK-NEXT: entry:320; CHECK-NEXT: br i1 [[C0:%.*]], label [[END:%.*]], label [[DISPATCH:%.*]]321; CHECK: dispatch:322; CHECK-NEXT: br i1 [[C1:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]323; CHECK: left:324; CHECK-NEXT: br label [[END]]325; CHECK: right:326; CHECK-NEXT: br label [[END]]327; CHECK: end:328; CHECK-NEXT: [[AGG_LEFT_PN:%.*]] = phi { i32, i32 } [ [[AGG_LEFT:%.*]], [[ENTRY:%.*]] ], [ [[AGG_LEFT]], [[LEFT]] ], [ [[AGG_RIGHT:%.*]], [[RIGHT]] ]329; CHECK-NEXT: [[R:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT_PN]], 0330; CHECK-NEXT: ret i32 [[R]]331;332entry:333 %i0 = extractvalue { i32, i32 } %agg_left, 0334 %i1 = extractvalue { i32, i32 } %agg_right, 0335 br i1 %c0, label %end, label %dispatch336 337dispatch:338 br i1 %c1, label %left, label %right339 340left:341 br label %end342 343right:344 br label %end345 346end:347 %r = phi i32 [ %i0, %entry ], [ %i0, %left ], [ %i1, %right ]348 ret i32 %r349}350; Which isn't the case here, there is a legitimate external use.351define i32 @test11({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c0, i1 %c1) {352; CHECK-LABEL: @test11(353; CHECK-NEXT: entry:354; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0355; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0356; CHECK-NEXT: call void @usei32(i32 [[I0]])357; CHECK-NEXT: br i1 [[C0:%.*]], label [[END:%.*]], label [[DISPATCH:%.*]]358; CHECK: dispatch:359; CHECK-NEXT: br i1 [[C1:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]360; CHECK: left:361; CHECK-NEXT: br label [[END]]362; CHECK: right:363; CHECK-NEXT: br label [[END]]364; CHECK: end:365; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[ENTRY:%.*]] ], [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ]366; CHECK-NEXT: ret i32 [[R]]367;368entry:369 %i0 = extractvalue { i32, i32 } %agg_left, 0370 %i1 = extractvalue { i32, i32 } %agg_right, 0371 call void @usei32(i32 %i0)372 br i1 %c0, label %end, label %dispatch373 374dispatch:375 br i1 %c1, label %left, label %right376 377left:378 br label %end379 380right:381 br label %end382 383end:384 %r = phi i32 [ %i0, %entry ], [ %i0, %left ], [ %i1, %right ]385 ret i32 %r386}387 388define i32 @extractvalue_of_constant_phi(i1 %c) {389; CHECK-LABEL: @extractvalue_of_constant_phi(390; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]391; CHECK: if:392; CHECK-NEXT: br label [[JOIN:%.*]]393; CHECK: else:394; CHECK-NEXT: br label [[JOIN]]395; CHECK: join:396; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 1, [[IF]] ], [ 3, [[ELSE]] ]397; CHECK-NEXT: ret i32 [[PHI]]398;399 br i1 %c, label %if, label %else400 401if:402 br label %join403 404else:405 br label %join406 407join:408 %phi = phi { i32, i32 } [ { i32 1, i32 2 }, %if ], [ { i32 3, i32 4 }, %else ]409 %ev = extractvalue { i32, i32 } %phi, 0410 ret i32 %ev411}412 413define i32 @extractvalue_of_one_constant_phi(i1 %c, { i32, i32 } %arg) {414; CHECK-LABEL: @extractvalue_of_one_constant_phi(415; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]416; CHECK: if:417; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i32 } [[ARG:%.*]], 0418; CHECK-NEXT: br label [[JOIN:%.*]]419; CHECK: else:420; CHECK-NEXT: br label [[JOIN]]421; CHECK: join:422; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[TMP1]], [[IF]] ], [ 3, [[ELSE]] ]423; CHECK-NEXT: ret i32 [[PHI]]424;425 br i1 %c, label %if, label %else426 427if:428 br label %join429 430else:431 br label %join432 433join:434 %phi = phi { i32, i32 } [ %arg, %if ], [ { i32 3, i32 4 }, %else ]435 %ev = extractvalue { i32, i32 } %phi, 0436 ret i32 %ev437}438 439define i32 @extractvalue_of_constant_phi_multi_index(i1 %c) {440; CHECK-LABEL: @extractvalue_of_constant_phi_multi_index(441; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]442; CHECK: if:443; CHECK-NEXT: br label [[JOIN:%.*]]444; CHECK: else:445; CHECK-NEXT: br label [[JOIN]]446; CHECK: join:447; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 3, [[IF]] ], [ 6, [[ELSE]] ]448; CHECK-NEXT: ret i32 [[PHI]]449;450 br i1 %c, label %if, label %else451 452if:453 br label %join454 455else:456 br label %join457 458join:459 %phi = phi { i32, { i32, i32 } } [ { i32 1, { i32, i32 } { i32 2, i32 3 } }, %if ], [ { i32 4, { i32, i32 } { i32 5, i32 6 } }, %else ]460 %ev = extractvalue { i32, { i32, i32 } } %phi, 1, 1461 ret i32 %ev462}463 464define i32 @extractvalue_of_one_constant_phi_multi_index(i1 %c, { i32, { i32, i32 } } %arg) {465; CHECK-LABEL: @extractvalue_of_one_constant_phi_multi_index(466; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]467; CHECK: if:468; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, { i32, i32 } } [[ARG:%.*]], 1, 1469; CHECK-NEXT: br label [[JOIN:%.*]]470; CHECK: else:471; CHECK-NEXT: br label [[JOIN]]472; CHECK: join:473; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[TMP1]], [[IF]] ], [ 6, [[ELSE]] ]474; CHECK-NEXT: ret i32 [[PHI]]475;476 br i1 %c, label %if, label %else477 478if:479 br label %join480 481else:482 br label %join483 484join:485 %phi = phi { i32, { i32, i32 } } [ %arg, %if ], [ { i32 4, { i32, i32 } { i32 5, i32 6 } }, %else ]486 %ev = extractvalue { i32, { i32, i32 } } %phi, 1, 1487 ret i32 %ev488}489 490define i32 @extractvalue_of_constant_phi_multiuse(i1 %c) {491; CHECK-LABEL: @extractvalue_of_constant_phi_multiuse(492; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]]493; CHECK: if:494; CHECK-NEXT: br label [[JOIN:%.*]]495; CHECK: else:496; CHECK-NEXT: br label [[JOIN]]497; CHECK: join:498; CHECK-NEXT: [[PHI:%.*]] = phi { i32, i32 } [ { i32 1, i32 2 }, [[IF]] ], [ { i32 3, i32 4 }, [[ELSE]] ]499; CHECK-NEXT: [[EV0:%.*]] = extractvalue { i32, i32 } [[PHI]], 0500; CHECK-NEXT: [[EV1:%.*]] = extractvalue { i32, i32 } [[PHI]], 1501; CHECK-NEXT: [[ADD:%.*]] = add i32 [[EV0]], [[EV1]]502; CHECK-NEXT: ret i32 [[ADD]]503;504 br i1 %c, label %if, label %else505 506if:507 br label %join508 509else:510 br label %join511 512join:513 %phi = phi { i32, i32 } [ { i32 1, i32 2 }, %if ], [ { i32 3, i32 4 }, %else ]514 %ev0 = extractvalue { i32, i32 } %phi, 0515 %ev1 = extractvalue { i32, i32 } %phi, 1516 %add = add i32 %ev0, %ev1517 ret i32 %add518}519