; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -passes=vector-combine -S | FileCheck %s define i16 @test_reduce_v8i16(<8 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v8i16( ; CHECK-SAME: <8 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.vector.reduce.umin.v8i16(<8 x i16> [[A0]]) ; CHECK-NEXT: ret i16 [[TMP1]] ; %1 = shufflevector <8 x i16> %a0, <8 x i16> poison, <8 x i32> %2 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %a0, <8 x i16> %1) %3 = shufflevector <8 x i16> %2, <8 x i16> poison, <8 x i32> %4 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %2, <8 x i16> %3) %5 = shufflevector <8 x i16> %4, <8 x i16> poison, <8 x i32> %6 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %4, <8 x i16> %5) %7 = extractelement <8 x i16> %6, i64 0 ret i16 %7 } define i16 @test_reduce_v7i16_or(<7 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v7i16_or( ; CHECK-SAME: <7 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.vector.reduce.or.v7i16(<7 x i16> [[A0]]) ; CHECK-NEXT: ret i16 [[TMP1]] ; %1 = shufflevector <7 x i16> %a0, <7 x i16> poison, <7 x i32> %2 = or <7 x i16> %a0, %1 %3 = shufflevector <7 x i16> %2, <7 x i16> poison, <7 x i32> %4 = or <7 x i16> %2, %3 %5 = shufflevector <7 x i16> %4, <7 x i16> poison, <7 x i32> %6 = or <7 x i16> %4, %5 %7 = extractelement <7 x i16> %6, i64 0 ret i16 %7 } define i16 @test_reduce_v3i16_and(<3 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v3i16_and( ; CHECK-SAME: <3 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.vector.reduce.and.v3i16(<3 x i16> [[A0]]) ; CHECK-NEXT: ret i16 [[TMP1]] ; %1 = shufflevector <3 x i16> %a0, <3 x i16> poison, <3 x i32> %2 = and <3 x i16> %a0, %1 %3 = shufflevector <3 x i16> %2, <3 x i16> poison, <3 x i32> %4 = and <3 x i16> %2, %3 %5 = extractelement <3 x i16> %4, i64 0 ret i16 %5 } define i16 @test_no_reduce_v6i16_xor(<6 x i16> %a0) { ; CHECK-LABEL: define i16 @test_no_reduce_v6i16_xor( ; CHECK-SAME: <6 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <6 x i16> [[A0]], <6 x i16> poison, <6 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = xor <6 x i16> [[A0]], [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <6 x i16> [[TMP2]], <6 x i16> poison, <6 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = xor <6 x i16> [[TMP2]], [[TMP3]] ; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <6 x i16> [[TMP4]], <6 x i16> poison, <6 x i32> ; CHECK-NEXT: [[TMP6:%.*]] = xor <6 x i16> [[TMP4]], [[TMP5]] ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <6 x i16> [[TMP6]], i64 0 ; CHECK-NEXT: ret i16 [[TMP7]] ; %1 = shufflevector <6 x i16> %a0, <6 x i16> poison, <6 x i32> %2 = xor <6 x i16> %a0, %1 %3 = shufflevector <6 x i16> %2, <6 x i16> poison, <6 x i32> %4 = xor <6 x i16> %2, %3 %5 = shufflevector <6 x i16> %4, <6 x i16> poison, <6 x i32> %6 = xor <6 x i16> %4, %5 %7 = extractelement <6 x i16> %6, i64 0 ret i16 %7 } ; Non-idempotent op (add) on a non-power-of-2 vector: can't fold into reduction. define i32 @test_no_reduce_v3i32_add(<3 x i32> %a0) { ; CHECK-LABEL: define i32 @test_no_reduce_v3i32_add( ; CHECK-SAME: <3 x i32> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x i32> [[A0]], <3 x i32> poison, <3 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = add <3 x i32> [[A0]], [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <3 x i32> [[TMP2]], <3 x i32> poison, <3 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = add <3 x i32> [[TMP2]], [[TMP3]] ; CHECK-NEXT: [[TMP5:%.*]] = extractelement <3 x i32> [[TMP4]], i64 0 ; CHECK-NEXT: ret i32 [[TMP5]] ; %1 = shufflevector <3 x i32> %a0, <3 x i32> poison, <3 x i32> %2 = add <3 x i32> %a0, %1 %3 = shufflevector <3 x i32> %2, <3 x i32> poison, <3 x i32> %4 = add <3 x i32> %2, %3 %5 = extractelement <3 x i32> %4, i64 0 ret i32 %5 } ; Idempotent op (smax) on a non-power-of-2 vector: lane duplication is harmless define i16 @test_reduce_v3i16_smax(<3 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v3i16_smax( ; CHECK-SAME: <3 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.vector.reduce.smax.v3i16(<3 x i16> [[A0]]) ; CHECK-NEXT: ret i16 [[TMP1]] ; %1 = shufflevector <3 x i16> %a0, <3 x i16> poison, <3 x i32> %2 = tail call <3 x i16> @llvm.smax.v3i16(<3 x i16> %a0, <3 x i16> %1) %3 = shufflevector <3 x i16> %2, <3 x i16> poison, <3 x i32> %4 = tail call <3 x i16> @llvm.smax.v3i16(<3 x i16> %2, <3 x i16> %3) %5 = extractelement <3 x i16> %4, i64 0 ret i16 %5 } define i16 @test_reduce_v8i16_2(<8 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v8i16_2( ; CHECK-SAME: <8 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i16> [[A0]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[A0]], <8 x i16> [[TMP1]]) ; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <8 x i16> [[TMP2]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP2]], <8 x i16> [[TMP3]]) ; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x i16> [[TMP4]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP6:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP4]], <8 x i16> [[TMP5]]) ; CHECK-NEXT: [[TMP13:%.*]] = call i16 @llvm.vector.reduce.umin.v8i16(<8 x i16> [[A0]]) ; CHECK-NEXT: [[TMP8:%.*]] = shufflevector <8 x i16> [[TMP6]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP9:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[A0]], <8 x i16> [[TMP8]]) ; CHECK-NEXT: [[TMP10:%.*]] = shufflevector <8 x i16> [[TMP9]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP11:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP9]], <8 x i16> [[TMP10]]) ; CHECK-NEXT: [[TMP12:%.*]] = shufflevector <8 x i16> [[TMP11]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP16:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP11]], <8 x i16> [[TMP12]]) ; CHECK-NEXT: [[TMP14:%.*]] = extractelement <8 x i16> [[TMP16]], i64 0 ; CHECK-NEXT: [[TMP15:%.*]] = tail call i16 @llvm.umin.i16(i16 [[TMP13]], i16 [[TMP14]]) ; CHECK-NEXT: ret i16 [[TMP15]] ; %1 = shufflevector <8 x i16> %a0, <8 x i16> poison, <8 x i32> %2 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %a0, <8 x i16> %1) %3 = shufflevector <8 x i16> %2, <8 x i16> poison, <8 x i32> %4 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %2, <8 x i16> %3) %5 = shufflevector <8 x i16> %4, <8 x i16> poison, <8 x i32> %6 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %4, <8 x i16> %5) %7 = extractelement <8 x i16> %6, i64 0 %8 = shufflevector <8 x i16> %6, <8 x i16> poison, <8 x i32> %9 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %a0, <8 x i16> %8) %10 = shufflevector <8 x i16> %9, <8 x i16> poison, <8 x i32> %11 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %9, <8 x i16> %10) %12 = shufflevector <8 x i16> %11, <8 x i16> poison, <8 x i32> %13 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %11, <8 x i16> %12) %14 = extractelement <8 x i16> %13, i64 0 %15 = tail call i16 @llvm.umin.i16(i16 %7, i16 %14) ret i16 %15 } define i16 @test_reduce_v8i16_neg1(<8 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v8i16_neg1( ; CHECK-SAME: <8 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i16> [[A0]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[A0]], <8 x i16> [[TMP1]]) ; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <8 x i16> [[TMP2]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP2]], <8 x i16> [[TMP3]]) ; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x i16> [[TMP4]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP6:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP4]], <8 x i16> [[TMP5]]) ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <8 x i16> [[TMP6]], i64 0 ; CHECK-NEXT: ret i16 [[TMP7]] ; %1 = shufflevector <8 x i16> %a0, <8 x i16> poison, <8 x i32> %2 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %a0, <8 x i16> %1) %3 = shufflevector <8 x i16> %2, <8 x i16> poison, <8 x i32> %4 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %2, <8 x i16> %3) %5 = shufflevector <8 x i16> %4, <8 x i16> poison, <8 x i32> %6 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %4, <8 x i16> %5) %7 = extractelement <8 x i16> %6, i64 0 ret i16 %7 } define i16 @test_reduce_v8i16_neg2(<8 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v8i16_neg2( ; CHECK-SAME: <8 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i16> [[A0]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[A0]], <8 x i16> [[TMP1]]) ; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <8 x i16> [[TMP2]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP2]], <8 x i16> [[TMP3]]) ; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x i16> [[TMP4]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP6:%.*]] = tail call <8 x i16> @llvm.umax.v8i16(<8 x i16> [[TMP4]], <8 x i16> [[TMP5]]) ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <8 x i16> [[TMP6]], i64 0 ; CHECK-NEXT: ret i16 [[TMP7]] ; %1 = shufflevector <8 x i16> %a0, <8 x i16> poison, <8 x i32> %2 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %a0, <8 x i16> %1) %3 = shufflevector <8 x i16> %2, <8 x i16> poison, <8 x i32> %4 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %2, <8 x i16> %3) %5 = shufflevector <8 x i16> %4, <8 x i16> poison, <8 x i32> %6 = tail call <8 x i16> @llvm.umax.v8i16(<8 x i16> %4, <8 x i16> %5) %7 = extractelement <8 x i16> %6, i64 0 ret i16 %7 } define i16 @test_reduce_v8i16_neg3(<8 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v8i16_neg3( ; CHECK-SAME: <8 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i16> [[A0]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[A0]], <8 x i16> [[TMP1]]) ; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <8 x i16> [[TMP2]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP2]], <8 x i16> [[TMP3]]) ; CHECK-NEXT: [[TMP5:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP2]], <8 x i16> [[TMP3]]) ; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <8 x i16> [[TMP4]], <8 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP7:%.*]] = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> [[TMP5]], <8 x i16> [[TMP6]]) ; CHECK-NEXT: [[TMP8:%.*]] = extractelement <8 x i16> [[TMP7]], i64 0 ; CHECK-NEXT: ret i16 [[TMP8]] ; %1 = shufflevector <8 x i16> %a0, <8 x i16> poison, <8 x i32> %2 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %a0, <8 x i16> %1) %3 = shufflevector <8 x i16> %2, <8 x i16> poison, <8 x i32> %4 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %2, <8 x i16> %3) %5 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %2, <8 x i16> %3) %6 = shufflevector <8 x i16> %4, <8 x i16> poison, <8 x i32> %7 = tail call <8 x i16> @llvm.umin.v8i16(<8 x i16> %5, <8 x i16> %6) %8 = extractelement <8 x i16> %7, i64 0 ret i16 %8 } define i16 @test_reduce_v6i16_xor_neg(<6 x i16> %a0) { ; CHECK-LABEL: define i16 @test_reduce_v6i16_xor_neg( ; CHECK-SAME: <6 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <6 x i16> [[A0]], <6 x i16> poison, <6 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = xor <6 x i16> [[A0]], [[TMP1]] ; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <6 x i16> [[TMP2]], <6 x i16> poison, <6 x i32> ; CHECK-NEXT: [[TMP4:%.*]] = xor <6 x i16> [[TMP2]], [[TMP3]] ; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <6 x i16> [[TMP4]], <6 x i16> poison, <6 x i32> ; CHECK-NEXT: [[TMP6:%.*]] = xor <6 x i16> [[TMP4]], [[TMP5]] ; CHECK-NEXT: [[TMP7:%.*]] = extractelement <6 x i16> [[TMP6]], i64 0 ; CHECK-NEXT: ret i16 [[TMP7]] ; %1 = shufflevector <6 x i16> %a0, <6 x i16> poison, <6 x i32> %2 = xor <6 x i16> %a0, %1 %3 = shufflevector <6 x i16> %2, <6 x i16> poison, <6 x i32> %4 = xor <6 x i16> %2, %3 %5 = shufflevector <6 x i16> %4, <6 x i16> poison, <6 x i32> %6 = xor <6 x i16> %4, %5 %7 = extractelement <6 x i16> %6, i64 0 ret i16 %7 } ; Partial reduction: reduce lower 8 elements of a 16-element vector using smax. define i16 @test_partial_reduce_v16i16_v8i16_smax(<16 x i16> %a0) { ; CHECK-LABEL: define i16 @test_partial_reduce_v16i16_v8i16_smax( ; CHECK-SAME: <16 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <16 x i16> [[A0]], <16 x i16> poison, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.vector.reduce.smax.v8i16(<8 x i16> [[TMP1]]) ; CHECK-NEXT: ret i16 [[TMP2]] ; %1 = shufflevector <16 x i16> %a0, <16 x i16> poison, <16 x i32> %2 = tail call <16 x i16> @llvm.smax.v16i16(<16 x i16> %a0, <16 x i16> %1) %3 = shufflevector <16 x i16> %2, <16 x i16> poison, <16 x i32> %4 = tail call <16 x i16> @llvm.smax.v16i16(<16 x i16> %2, <16 x i16> %3) %5 = shufflevector <16 x i16> %4, <16 x i16> poison, <16 x i32> %6 = tail call <16 x i16> @llvm.smax.v16i16(<16 x i16> %4, <16 x i16> %5) %7 = extractelement <16 x i16> %6, i64 0 ret i16 %7 } ; Partial reduction: reduce lower 4 elements of an 8-element vector using add. define i32 @test_partial_reduce_v8i32_v4i32_add(<8 x i32> %a0) { ; CHECK-LABEL: define i32 @test_partial_reduce_v8i32_v4i32_add( ; CHECK-SAME: <8 x i32> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x i32> [[A0]], <8 x i32> poison, <4 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[TMP1]]) ; CHECK-NEXT: ret i32 [[TMP2]] ; %1 = shufflevector <8 x i32> %a0, <8 x i32> poison, <8 x i32> %2 = add <8 x i32> %a0, %1 %3 = shufflevector <8 x i32> %2, <8 x i32> poison, <8 x i32> %4 = add <8 x i32> %2, %3 %5 = extractelement <8 x i32> %4, i64 0 ret i32 %5 } ; Partial reduction: reduce lower 4 elements of a 16-element vector using umin. define i16 @test_partial_reduce_v16i16_v4i16_umin(<16 x i16> %a0) { ; CHECK-LABEL: define i16 @test_partial_reduce_v16i16_v4i16_umin( ; CHECK-SAME: <16 x i16> [[A0:%.*]]) { ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <16 x i16> [[A0]], <16 x i16> poison, <4 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = call i16 @llvm.vector.reduce.umin.v4i16(<4 x i16> [[TMP1]]) ; CHECK-NEXT: ret i16 [[TMP2]] ; %1 = shufflevector <16 x i16> %a0, <16 x i16> poison, <16 x i32> %2 = tail call <16 x i16> @llvm.umin.v16i16(<16 x i16> %a0, <16 x i16> %1) %3 = shufflevector <16 x i16> %2, <16 x i16> poison, <16 x i32> %4 = tail call <16 x i16> @llvm.umin.v16i16(<16 x i16> %2, <16 x i16> %3) %5 = extractelement <16 x i16> %4, i64 0 ret i16 %5 } ; Negative test: partial reduction on non-power-of-2 vectors is rejected because ; parity-based shuffle masks cause lane duplication in the reduction tree. define i32 @test_no_partial_reduce_v6i32_add(<6 x i32> %a) { ; CHECK-LABEL: define i32 @test_no_partial_reduce_v6i32_add( ; CHECK-SAME: <6 x i32> [[A:%.*]]) { ; CHECK-NEXT: [[S1:%.*]] = shufflevector <6 x i32> [[A]], <6 x i32> poison, <6 x i32> ; CHECK-NEXT: [[A1:%.*]] = add <6 x i32> [[A]], [[S1]] ; CHECK-NEXT: [[S2:%.*]] = shufflevector <6 x i32> [[A1]], <6 x i32> poison, <6 x i32> ; CHECK-NEXT: [[A2:%.*]] = add <6 x i32> [[A1]], [[S2]] ; CHECK-NEXT: [[R:%.*]] = extractelement <6 x i32> [[A2]], i64 0 ; CHECK-NEXT: ret i32 [[R]] ; %s1 = shufflevector <6 x i32> %a, <6 x i32> poison, <6 x i32> %a1 = add <6 x i32> %a, %s1 %s2 = shufflevector <6 x i32> %a1, <6 x i32> poison, <6 x i32> %a2 = add <6 x i32> %a1, %s2 %r = extractelement <6 x i32> %a2, i64 0 ret i32 %r }