From 4d5ca22b8adfb6643466e4e9f48ba14bb48938bc Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 25 Aug 2020 13:00:37 +0300 Subject: [PATCH] [NFC][InstCombine] Tests for PHI-of-extractvalues Much like with it's sibling fold HI-of-insertvalues, it appears to be much more worthwhile than it would seem. --- .../Transforms/InstCombine/phi-of-extractvalues.ll | 284 +++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/phi-of-extractvalues.ll diff --git a/llvm/test/Transforms/InstCombine/phi-of-extractvalues.ll b/llvm/test/Transforms/InstCombine/phi-of-extractvalues.ll new file mode 100644 index 0000000..72abd9d --- /dev/null +++ b/llvm/test/Transforms/InstCombine/phi-of-extractvalues.ll @@ -0,0 +1,284 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instcombine < %s | FileCheck %s + +declare void @usei32(i32) + +; If we have a phi of extractvalues, we can sink it, +; Here, we only need a PHI for extracted values. +define i32 @test0({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { +; CHECK-LABEL: @test0( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0 +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue { i32, i32 } %agg_left, 0 + br label %end + +right: + %i1 = extractvalue { i32, i32 } %agg_right, 0 + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} + +; But only if the extractvalues have no extra uses +define i32 @test1_extrause0({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { +; CHECK-LABEL: @test1_extrause0( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0 +; CHECK-NEXT: call void @usei32(i32 [[I0]]) +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue { i32, i32 } %agg_left, 0 + call void @usei32(i32 %i0) + br label %end + +right: + %i1 = extractvalue { i32, i32 } %agg_right, 0 + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} +define i32 @test2_extrause1({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { +; CHECK-LABEL: @test2_extrause1( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0 +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0 +; CHECK-NEXT: call void @usei32(i32 [[I1]]) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue { i32, i32 } %agg_left, 0 + br label %end + +right: + %i1 = extractvalue { i32, i32 } %agg_right, 0 + call void @usei32(i32 %i1) + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} +define i32 @test3_extrause2({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { +; CHECK-LABEL: @test3_extrause2( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0 +; CHECK-NEXT: call void @usei32(i32 [[I0]]) +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 0 +; CHECK-NEXT: call void @usei32(i32 [[I1]]) +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue { i32, i32 } %agg_left, 0 + call void @usei32(i32 %i0) + br label %end + +right: + %i1 = extractvalue { i32, i32 } %agg_right, 0 + call void @usei32(i32 %i1) + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} + +; But the indicies must match +define i32 @test4({ i32, i32 } %agg_left, { i32, i32 } %agg_right, i1 %c) { +; CHECK-LABEL: @test4( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { i32, i32 } [[AGG_LEFT:%.*]], 0 +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { i32, i32 } [[AGG_RIGHT:%.*]], 1 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue { i32, i32 } %agg_left, 0 + br label %end + +right: + %i1 = extractvalue { i32, i32 } %agg_right, 1 + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} + +; More complex aggregates are fine, too, as long as indicies match. +define i32 @test5({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) { +; CHECK-LABEL: @test5( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT:%.*]], 0, 0 +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_RIGHT:%.*]], 0, 0 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0 + br label %end + +right: + %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 0, 0 + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} + +; The indicies must fully match, on all levels. +define i32 @test6({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) { +; CHECK-LABEL: @test6( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT:%.*]], 0, 0 +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_RIGHT:%.*]], 0, 1 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0 + br label %end + +right: + %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 0, 1 + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} +define i32 @test7({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) { +; CHECK-LABEL: @test7( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT:%.*]], 0, 0 +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_RIGHT:%.*]], 1, 0 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0 + br label %end + +right: + %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 1, 0 + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} +define i32 @test8({{ i32, i32 }, { i32, i32 }} %agg_left, {{ i32, i32 }, { i32, i32 }} %agg_right, i1 %c) { +; CHECK-LABEL: @test8( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]] +; CHECK: left: +; CHECK-NEXT: [[I0:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_LEFT:%.*]], 0, 0 +; CHECK-NEXT: br label [[END:%.*]] +; CHECK: right: +; CHECK-NEXT: [[I1:%.*]] = extractvalue { { i32, i32 }, { i32, i32 } } [[AGG_RIGHT:%.*]], 1, 1 +; CHECK-NEXT: br label [[END]] +; CHECK: end: +; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[I0]], [[LEFT]] ], [ [[I1]], [[RIGHT]] ] +; CHECK-NEXT: ret i32 [[R]] +; +entry: + br i1 %c, label %left, label %right + +left: + %i0 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_left, 0, 0 + br label %end + +right: + %i1 = extractvalue {{ i32, i32 }, { i32, i32 }} %agg_right, 1, 1 + br label %end + +end: + %r = phi i32 [ %i0, %left ], [ %i1, %right ] + ret i32 %r +} -- 2.7.4