; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt -S -passes=instcombine < %s | FileCheck %s declare {ptr, i64} @bar(i64) ; Basic test. define {ptr, i64} @test1(i1 %cond1, ptr %p1, ptr %p2) { ; CHECK-LABEL: define { ptr, i64 } @test1( ; CHECK-SAME: i1 [[COND1:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) { ; CHECK-NEXT: br i1 [[COND1]], label %[[BBB1:.*]], label %[[BBB2:.*]] ; CHECK: [[BBB1]]: ; CHECK-NEXT: [[CALL1:%.*]] = call { ptr, i64 } @bar(i64 0) ; CHECK-NEXT: br label %[[EXIT:.*]] ; CHECK: [[BBB2]]: ; CHECK-NEXT: [[VAL21:%.*]] = load ptr, ptr [[P1]], align 8 ; CHECK-NEXT: [[VAL22:%.*]] = load i64, ptr [[P2]], align 4 ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr, i64 } poison, ptr [[VAL21]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr, i64 } [[TMP1]], i64 [[VAL22]], 1 ; CHECK-NEXT: br label %[[EXIT]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[RES_MERGED:%.*]] = phi { ptr, i64 } [ [[CALL1]], %[[BBB1]] ], [ [[TMP2]], %[[BBB2]] ] ; CHECK-NEXT: ret { ptr, i64 } [[RES_MERGED]] ; br i1 %cond1, label %bbb1, label %bbb2 bbb1: %call1 = call {ptr, i64} @bar(i64 0) %val11 = extractvalue { ptr, i64 } %call1, 0 %val12 = extractvalue { ptr, i64 } %call1, 1 br label %exit bbb2: %val21 = load ptr, ptr %p1 %val22 = load i64, ptr %p2 br label %exit exit: %val1 = phi ptr [%val11, %bbb1], [%val21, %bbb2] %val2 = phi i64 [%val12, %bbb1], [%val22, %bbb2] %tmp = insertvalue { ptr, i64 } poison, ptr %val1, 0 %res = insertvalue { ptr, i64 } %tmp, i64 %val2, 1 ret {ptr, i64} %res } ; Test with more predecessors. define {ptr, i64} @test2(i1 %cond1, i1 %cond2, ptr %p1, ptr %p2) { ; CHECK-LABEL: define { ptr, i64 } @test2( ; CHECK-SAME: i1 [[COND1:%.*]], i1 [[COND2:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) { ; CHECK-NEXT: br i1 [[COND1]], label %[[BBB1:.*]], label %[[BBB4:.*]] ; CHECK: [[BBB1]]: ; CHECK-NEXT: br i1 [[COND2]], label %[[BBB2:.*]], label %[[BBB3:.*]] ; CHECK: [[BBB2]]: ; CHECK-NEXT: [[CALL1:%.*]] = call { ptr, i64 } @bar(i64 0) ; CHECK-NEXT: br label %[[EXIT:.*]] ; CHECK: [[BBB3]]: ; CHECK-NEXT: [[CALL2:%.*]] = call { ptr, i64 } @bar(i64 1) ; CHECK-NEXT: br label %[[EXIT]] ; CHECK: [[BBB4]]: ; CHECK-NEXT: [[VAL31:%.*]] = load ptr, ptr [[P1]], align 8 ; CHECK-NEXT: [[VAL32:%.*]] = load i64, ptr [[P2]], align 4 ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr, i64 } poison, ptr [[VAL31]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr, i64 } [[TMP1]], i64 [[VAL32]], 1 ; CHECK-NEXT: br label %[[EXIT]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[RES_MERGED:%.*]] = phi { ptr, i64 } [ [[CALL1]], %[[BBB2]] ], [ [[CALL2]], %[[BBB3]] ], [ [[TMP2]], %[[BBB4]] ] ; CHECK-NEXT: ret { ptr, i64 } [[RES_MERGED]] ; br i1 %cond1, label %bbb1, label %bbb4 bbb1: br i1 %cond2, label %bbb2, label %bbb3 bbb2: %call1 = call {ptr, i64} @bar(i64 0) %val11 = extractvalue { ptr, i64 } %call1, 0 %val12 = extractvalue { ptr, i64 } %call1, 1 br label %exit bbb3: %call2 = call {ptr, i64} @bar(i64 1) %val21 = extractvalue { ptr, i64 } %call2, 0 %val22 = extractvalue { ptr, i64 } %call2, 1 br label %exit bbb4: %val31 = load ptr, ptr %p1 %val32 = load i64, ptr %p2 br label %exit exit: %val1 = phi ptr [%val11, %bbb2], [%val21, %bbb3], [%val31, %bbb4] %val2 = phi i64 [%val12, %bbb2], [%val22, %bbb3], [%val32, %bbb4] %tmp = insertvalue { ptr, i64 } poison, ptr %val1, 0 %res = insertvalue { ptr, i64 } %tmp, i64 %val2, 1 ret {ptr, i64} %res } ; Test with multiple PHI instructions. define {ptr, i64} @test3(i1 %cond1, i1 %cond2, ptr %val31, i64 %val32) { ; CHECK-LABEL: define { ptr, i64 } @test3( ; CHECK-SAME: i1 [[COND1:%.*]], i1 [[COND2:%.*]], ptr [[VAL31:%.*]], i64 [[VAL32:%.*]]) { ; CHECK-NEXT: br i1 [[COND1]], label %[[BBB1:.*]], label %[[BBB4:.*]] ; CHECK: [[BBB1]]: ; CHECK-NEXT: br i1 [[COND2]], label %[[BBB2:.*]], label %[[BBB3:.*]] ; CHECK: [[BBB2]]: ; CHECK-NEXT: [[CALL1:%.*]] = call { ptr, i64 } @bar(i64 0) ; CHECK-NEXT: br label %[[EXIT:.*]] ; CHECK: [[BBB3]]: ; CHECK-NEXT: [[CALL2:%.*]] = call { ptr, i64 } @bar(i64 1) ; CHECK-NEXT: br label %[[BBB5:.*]] ; CHECK: [[BBB4]]: ; CHECK-NEXT: [[CALL3:%.*]] = call { ptr, i64 } @bar(i64 2) ; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { ptr, i64 } poison, ptr [[VAL31]], 0 ; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { ptr, i64 } [[TMP1]], i64 [[VAL32]], 1 ; CHECK-NEXT: br label %[[BBB5]] ; CHECK: [[BBB5]]: ; CHECK-NEXT: [[DOTMERGED:%.*]] = phi { ptr, i64 } [ [[CALL2]], %[[BBB3]] ], [ [[TMP2]], %[[BBB4]] ] ; CHECK-NEXT: br label %[[EXIT]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[RES_MERGED:%.*]] = phi { ptr, i64 } [ [[CALL1]], %[[BBB2]] ], [ [[DOTMERGED]], %[[BBB5]] ] ; CHECK-NEXT: ret { ptr, i64 } [[RES_MERGED]] ; br i1 %cond1, label %bbb1, label %bbb4 bbb1: br i1 %cond2, label %bbb2, label %bbb3 bbb2: %call1 = call {ptr, i64} @bar(i64 0) %val11 = extractvalue { ptr, i64 } %call1, 0 %val12 = extractvalue { ptr, i64 } %call1, 1 br label %exit bbb3: %call2 = call {ptr, i64} @bar(i64 1) %val21 = extractvalue { ptr, i64 } %call2, 0 %val22 = extractvalue { ptr, i64 } %call2, 1 br label %bbb5 bbb4: %call3 = call {ptr, i64} @bar(i64 2) br label %bbb5 bbb5: %val41 = phi ptr [%val21, %bbb3], [%val31, %bbb4] %val42 = phi i64 [%val22, %bbb3], [%val32, %bbb4] br label %exit exit: %val1 = phi ptr [%val11, %bbb2], [%val41, %bbb5] %val2 = phi i64 [%val12, %bbb2], [%val42, %bbb5] %tmp = insertvalue { ptr, i64 } poison, ptr %val1, 0 %res = insertvalue { ptr, i64 } %tmp, i64 %val2, 1 ret {ptr, i64} %res } ; Negative test, bbb4 has multiple successors, so we don't add insertvalue to it. define {ptr, i64} @test4(i1 %cond1, i1 %cond2, ptr %p1, ptr %p2) { ; CHECK-LABEL: define { ptr, i64 } @test4( ; CHECK-SAME: i1 [[COND1:%.*]], i1 [[COND2:%.*]], ptr [[P1:%.*]], ptr [[P2:%.*]]) { ; CHECK-NEXT: br i1 [[COND1]], label %[[BBB1:.*]], label %[[BBB4:.*]] ; CHECK: [[BBB1]]: ; CHECK-NEXT: br i1 [[COND2]], label %[[BBB2:.*]], label %[[BBB3:.*]] ; CHECK: [[BBB2]]: ; CHECK-NEXT: [[CALL1:%.*]] = call { ptr, i64 } @bar(i64 0) ; CHECK-NEXT: [[VAL11:%.*]] = extractvalue { ptr, i64 } [[CALL1]], 0 ; CHECK-NEXT: [[VAL12:%.*]] = extractvalue { ptr, i64 } [[CALL1]], 1 ; CHECK-NEXT: br label %[[EXIT:.*]] ; CHECK: [[BBB3]]: ; CHECK-NEXT: [[CALL2:%.*]] = call { ptr, i64 } @bar(i64 1) ; CHECK-NEXT: [[VAL21:%.*]] = extractvalue { ptr, i64 } [[CALL2]], 0 ; CHECK-NEXT: [[VAL22:%.*]] = extractvalue { ptr, i64 } [[CALL2]], 1 ; CHECK-NEXT: br label %[[EXIT]] ; CHECK: [[BBB4]]: ; CHECK-NEXT: [[VAL31:%.*]] = load ptr, ptr [[P1]], align 8 ; CHECK-NEXT: [[VAL32:%.*]] = load i64, ptr [[P2]], align 4 ; CHECK-NEXT: [[COND3_NOT:%.*]] = icmp eq i64 [[VAL32]], 0 ; CHECK-NEXT: br i1 [[COND3_NOT]], label %[[EXIT]], label %[[BBB4]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[VAL1:%.*]] = phi ptr [ [[VAL11]], %[[BBB2]] ], [ [[VAL21]], %[[BBB3]] ], [ [[VAL31]], %[[BBB4]] ] ; CHECK-NEXT: [[VAL2:%.*]] = phi i64 [ [[VAL12]], %[[BBB2]] ], [ [[VAL22]], %[[BBB3]] ], [ [[VAL32]], %[[BBB4]] ] ; CHECK-NEXT: [[TMP:%.*]] = insertvalue { ptr, i64 } poison, ptr [[VAL1]], 0 ; CHECK-NEXT: [[RES:%.*]] = insertvalue { ptr, i64 } [[TMP]], i64 [[VAL2]], 1 ; CHECK-NEXT: ret { ptr, i64 } [[RES]] ; br i1 %cond1, label %bbb1, label %bbb4 bbb1: br i1 %cond2, label %bbb2, label %bbb3 bbb2: %call1 = call {ptr, i64} @bar(i64 0) %val11 = extractvalue { ptr, i64 } %call1, 0 %val12 = extractvalue { ptr, i64 } %call1, 1 br label %exit bbb3: %call2 = call {ptr, i64} @bar(i64 1) %val21 = extractvalue { ptr, i64 } %call2, 0 %val22 = extractvalue { ptr, i64 } %call2, 1 br label %exit bbb4: %val31 = load ptr, ptr %p1 %val32 = load i64, ptr %p2 %cond3 = icmp ne i64 %val32, 0 br i1 %cond3, label %bbb4, label %exit exit: %val1 = phi ptr [%val11, %bbb2], [%val21, %bbb3], [%val31, %bbb4] %val2 = phi i64 [%val12, %bbb2], [%val22, %bbb3], [%val32, %bbb4] %tmp = insertvalue { ptr, i64 } poison, ptr %val1, 0 %res = insertvalue { ptr, i64 } %tmp, i64 %val2, 1 ret {ptr, i64} %res } ; Negative test, %.elt2 is defined in bb %end, it can't be accessed from %then, ; so we can't add insertvalue to %then. define { ptr, i64 } @test5({ ptr, i64 } %src, ptr %pointer, i1 %cond) { ; CHECK-LABEL: define { ptr, i64 } @test5( ; CHECK-SAME: { ptr, i64 } [[SRC:%.*]], ptr [[POINTER:%.*]], i1 [[COND:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*:]] ; CHECK-NEXT: br i1 [[COND]], label %[[THEN:.*]], label %[[ELSE:.*]] ; CHECK: [[THEN]]: ; CHECK-NEXT: store ptr null, ptr [[POINTER]], align 8 ; CHECK-NEXT: br label %[[END:.*]] ; CHECK: [[ELSE]]: ; CHECK-NEXT: [[DOTELT1:%.*]] = extractvalue { ptr, i64 } [[SRC]], 0 ; CHECK-NEXT: br label %[[END]] ; CHECK: [[END]]: ; CHECK-NEXT: [[TMP6:%.*]] = phi ptr [ [[DOTELT1]], %[[ELSE]] ], [ null, %[[THEN]] ] ; CHECK-NEXT: [[DOTELT2:%.*]] = extractvalue { ptr, i64 } [[SRC]], 1 ; CHECK-NEXT: [[TMP7:%.*]] = insertvalue { ptr, i64 } zeroinitializer, ptr [[TMP6]], 0 ; CHECK-NEXT: [[TMP8:%.*]] = insertvalue { ptr, i64 } [[TMP7]], i64 [[DOTELT2]], 1 ; CHECK-NEXT: ret { ptr, i64 } [[TMP8]] ; entry: br i1 %cond, label %then, label %else then: store ptr null, ptr %pointer, align 8 br label %end else: %.elt1 = extractvalue { ptr, i64 } %src, 0 br label %end end: %elt = phi ptr [ %.elt1, %else ], [ null, %then ] %.elt2 = extractvalue { ptr, i64 } %src, 1 %agg1 = insertvalue { ptr, i64 } zeroinitializer, ptr %elt, 0 %res = insertvalue { ptr, i64 } %agg1, i64 %.elt2, 1 ret { ptr, i64 } %res } ; Negative test, we should not add insertvalue to inner loops. define { i64, ptr } @test6({ i64, ptr } %agg1, i1 %cond1, i1 %cond2, { i64, ptr } %agg3) { ; CHECK-LABEL: define { i64, ptr } @test6( ; CHECK-SAME: { i64, ptr } [[AGG1:%.*]], i1 [[COND1:%.*]], i1 [[COND2:%.*]], { i64, ptr } [[AGG3:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: [[F10:%.*]] = extractvalue { i64, ptr } [[AGG1]], 0 ; CHECK-NEXT: [[F11:%.*]] = extractvalue { i64, ptr } [[AGG1]], 1 ; CHECK-NEXT: br label %[[HEADER:.*]] ; CHECK: [[HEADER]]: ; CHECK-NEXT: [[DOTSROA_01_0:%.*]] = phi i64 [ [[F10]], %[[ENTRY]] ], [ [[DOTSROA_01_1:%.*]], %[[LATCH:.*]] ] ; CHECK-NEXT: [[DOTSROA_3_0:%.*]] = phi ptr [ [[F11]], %[[ENTRY]] ], [ [[DOTSROA_3_1:%.*]], %[[LATCH]] ] ; CHECK-NEXT: br i1 [[COND1]], label %[[CHECK:.*]], label %[[EXIT:.*]] ; CHECK: [[CHECK]]: ; CHECK-NEXT: br i1 [[COND2]], label %[[THEN:.*]], label %[[ELSE:.*]] ; CHECK: [[THEN]]: ; CHECK-NEXT: [[F30:%.*]] = extractvalue { i64, ptr } [[AGG3]], 0 ; CHECK-NEXT: [[F31:%.*]] = extractvalue { i64, ptr } [[AGG3]], 1 ; CHECK-NEXT: br label %[[LATCH]] ; CHECK: [[ELSE]]: ; CHECK-NEXT: br label %[[LATCH]] ; CHECK: [[LATCH]]: ; CHECK-NEXT: [[DOTSROA_01_1]] = phi i64 [ [[F30]], %[[THEN]] ], [ [[DOTSROA_01_0]], %[[ELSE]] ] ; CHECK-NEXT: [[DOTSROA_3_1]] = phi ptr [ [[F31]], %[[THEN]] ], [ [[DOTSROA_3_0]], %[[ELSE]] ] ; CHECK-NEXT: br label %[[HEADER]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[DOTFCA_0_INSERT:%.*]] = insertvalue { i64, ptr } zeroinitializer, i64 [[DOTSROA_01_0]], 0 ; CHECK-NEXT: [[DOTFCA_1_INSERT:%.*]] = insertvalue { i64, ptr } [[DOTFCA_0_INSERT]], ptr [[DOTSROA_3_0]], 1 ; CHECK-NEXT: ret { i64, ptr } [[DOTFCA_1_INSERT]] ; entry: %f10 = extractvalue { i64, ptr } %agg1, 0 %f11 = extractvalue { i64, ptr } %agg1, 1 br label %header header: %.sroa.01.0 = phi i64 [ %f10, %entry ], [ %.sroa.01.1, %latch ] %.sroa.3.0 = phi ptr [ %f11, %entry ], [ %.sroa.3.1, %latch ] br i1 %cond1, label %check, label %exit check: br i1 %cond2, label %then, label %else then: %f30 = extractvalue { i64, ptr } %agg3, 0 %f31 = extractvalue { i64, ptr } %agg3, 1 br label %latch else: br label %latch latch: %.sroa.01.1 = phi i64 [ %f30, %then ], [ %.sroa.01.0, %else ] %.sroa.3.1 = phi ptr [ %f31, %then ], [ %.sroa.3.0, %else ] br label %header exit: %.fca.0.insert = insertvalue { i64, ptr } zeroinitializer, i64 %.sroa.01.0, 0 %.fca.1.insert = insertvalue { i64, ptr } %.fca.0.insert, ptr %.sroa.3.0, 1 ret { i64, ptr } %.fca.1.insert } ; Negative test, don't construct constant aggregate. define {ptr, i64} @test7(i1 %cond1, ptr %p1) { ; CHECK-LABEL: define { ptr, i64 } @test7( ; CHECK-SAME: i1 [[COND1:%.*]], ptr [[P1:%.*]]) { ; CHECK-NEXT: br i1 [[COND1]], label %[[BBB1:.*]], label %[[BBB2:.*]] ; CHECK: [[BBB1]]: ; CHECK-NEXT: [[CALL1:%.*]] = call { ptr, i64 } @bar(i64 0) ; CHECK-NEXT: [[VAL11:%.*]] = extractvalue { ptr, i64 } [[CALL1]], 0 ; CHECK-NEXT: [[VAL12:%.*]] = extractvalue { ptr, i64 } [[CALL1]], 1 ; CHECK-NEXT: br label %[[EXIT:.*]] ; CHECK: [[BBB2]]: ; CHECK-NEXT: br label %[[EXIT]] ; CHECK: [[EXIT]]: ; CHECK-NEXT: [[VAL1:%.*]] = phi ptr [ [[VAL11]], %[[BBB1]] ], [ undef, %[[BBB2]] ] ; CHECK-NEXT: [[VAL2:%.*]] = phi i64 [ [[VAL12]], %[[BBB1]] ], [ 1, %[[BBB2]] ] ; CHECK-NEXT: [[TMP:%.*]] = insertvalue { ptr, i64 } poison, ptr [[VAL1]], 0 ; CHECK-NEXT: [[RES:%.*]] = insertvalue { ptr, i64 } [[TMP]], i64 [[VAL2]], 1 ; CHECK-NEXT: ret { ptr, i64 } [[RES]] ; br i1 %cond1, label %bbb1, label %bbb2 bbb1: %call1 = call {ptr, i64} @bar(i64 0) %val11 = extractvalue { ptr, i64 } %call1, 0 %val12 = extractvalue { ptr, i64 } %call1, 1 br label %exit bbb2: br label %exit exit: %val1 = phi ptr [%val11, %bbb1], [undef, %bbb2] %val2 = phi i64 [%val12, %bbb1], [1, %bbb2] %tmp = insertvalue { ptr, i64 } poison, ptr %val1, 0 %res = insertvalue { ptr, i64 } %tmp, i64 %val2, 1 ret {ptr, i64} %res }