diff --git a/llvm/lib/CodeGen/MachineVerifier.cpp b/llvm/lib/CodeGen/MachineVerifier.cpp --- a/llvm/lib/CodeGen/MachineVerifier.cpp +++ b/llvm/lib/CodeGen/MachineVerifier.cpp @@ -1311,17 +1311,38 @@ break; } case TargetOpcode::G_UNMERGE_VALUES: { + unsigned NumDsts = MI->getNumOperands() - 1; LLT DstTy = MRI->getType(MI->getOperand(0).getReg()); - LLT SrcTy = MRI->getType(MI->getOperand(MI->getNumOperands()-1).getReg()); - // For now G_UNMERGE can split vectors. - for (unsigned i = 0; i < MI->getNumOperands()-1; ++i) { - if (MRI->getType(MI->getOperand(i).getReg()) != DstTy) + for (unsigned i = 1; i < NumDsts; ++i) { + if (MRI->getType(MI->getOperand(i).getReg()) != DstTy) { report("G_UNMERGE_VALUES destination types do not match", MI); + break; + } } - if (SrcTy.getSizeInBits() != - (DstTy.getSizeInBits() * (MI->getNumOperands() - 1))) { - report("G_UNMERGE_VALUES source operand does not cover dest operands", - MI); + + LLT SrcTy = MRI->getType(MI->getOperand(NumDsts).getReg()); + if (DstTy.isVector()) { + // This case is the converse of G_CONCAT_VECTORS. + if (!SrcTy.isVector() || SrcTy.getScalarType() != DstTy.getScalarType() || + SrcTy.getNumElements() != NumDsts * DstTy.getNumElements()) + report("G_UNMERGE_VALUES source operand does not match vector " + "destination operands", + MI); + } else if (SrcTy.isVector()) { + // This case is the converse of G_BUILD_VECTOR, but relaxed to allow + // mismatched types as long as the total size matches: + // %0:_(s64), %1:_(s64) = G_UNMERGE_VALUES %2:_(<4 x s32>) + if (SrcTy.getSizeInBits() != NumDsts * DstTy.getSizeInBits()) + report("G_UNMERGE_VALUES vector source operand does not match scalar " + "destination operands", + MI); + } else { + // This case is the converse of G_MERGE_VALUES. + if (SrcTy.getSizeInBits() != NumDsts * DstTy.getSizeInBits()) { + report("G_UNMERGE_VALUES scalar source operand does not match scalar " + "destination operands", + MI); + } } break; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-unmerge.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-unmerge.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-unmerge.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-unmerge.mir @@ -328,13 +328,13 @@ body: | bb.1: ; CHECK-LABEL: name: test_combine_unmerge_dead_to_trunc_vec_in_n_out - ; CHECK: [[COPY:%[0-9]+]]:_(<2 x s32>) = COPY $x0 - ; CHECK: [[BITCAST:%[0-9]+]]:_(s64) = G_BITCAST [[COPY]](<2 x s32>) + ; CHECK: [[COPY:%[0-9]+]]:_(<4 x s16>) = COPY $x0 + ; CHECK: [[BITCAST:%[0-9]+]]:_(s64) = G_BITCAST [[COPY]](<4 x s16>) ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[BITCAST]](s64) ; CHECK: [[BITCAST1:%[0-9]+]]:_(<2 x s16>) = G_BITCAST [[TRUNC]](s32) ; CHECK: $w0 = COPY [[BITCAST1]](<2 x s16>) - %0:_(<2 x s32>) = COPY $x0 - %1:_(<2 x s16>),%2:_(<2 x s16>) = G_UNMERGE_VALUES %0(<2 x s32>) + %0:_(<4 x s16>) = COPY $x0 + %1:_(<2 x s16>),%2:_(<2 x s16>) = G_UNMERGE_VALUES %0(<4 x s16>) $w0 = COPY %1(<2 x s16>) ... @@ -354,22 +354,6 @@ $h0 = COPY %1(s16) ... -# Transform unmerge into trunc when only the first definition is live, even -# if the output type are vector. ---- -name: test_combine_unmerge_dead_to_trunc_vec_out -body: | - bb.1: - ; CHECK-LABEL: name: test_combine_unmerge_dead_to_trunc_vec_out - ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 - ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64) - ; CHECK: [[BITCAST:%[0-9]+]]:_(<2 x s16>) = G_BITCAST [[TRUNC]](s32) - ; CHECK: $w0 = COPY [[BITCAST]](<2 x s16>) - %0:_(s64) = COPY $x0 - %1:_(<2 x s16>),%2:_(<2 x s16>) = G_UNMERGE_VALUES %0(s64) - $w0 = COPY %1(<2 x s16>) -... - # Transform unmerge(zext) into zext. # In that test, the source of the zext is same size as the first definition # of the unmerge. Therefore a we can just reuse the input of the zext for @@ -456,23 +440,3 @@ $w0 = COPY %1(s32) $w1 = COPY %2(s32) ... - -# Check that we don't apply the unmerge(zext) to zext transformation -# when the destination type is a vector type. -# We could actually handle this case but we would need to insert a cast. ---- -name: test_dont_combine_unmerge_zext_to_zext_dst_vector -body: | - bb.1: - ; CHECK-LABEL: name: test_dont_combine_unmerge_zext_to_zext_dst_vector - ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 - ; CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[COPY]](s32) - ; CHECK: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[ZEXT]](s64) - ; CHECK: $w0 = COPY [[UV]](<2 x s16>) - ; CHECK: $w1 = COPY [[UV1]](<2 x s16>) - %0:_(s32) = COPY $w0 - %3:_(s64) = G_ZEXT %0(s32) - %1:_(<2 x s16>),%2:_(<2 x s16>) = G_UNMERGE_VALUES %3(s64) - $w0 = COPY %1(<2 x s16>) - $w1 = COPY %2(<2 x s16>) -... diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-unmerge-values.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-unmerge-values.mir --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-unmerge-values.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-unmerge-values.mir @@ -215,11 +215,9 @@ ; CHECK-NEXT: [[ZEXT1:%[0-9]+]]:_(s32) = G_ZEXT [[ANYEXT1]](s16) ; CHECK-NEXT: [[ZEXT2:%[0-9]+]]:_(s32) = G_ZEXT [[ANYEXT]](s16) ; CHECK-NEXT: [[ZEXT3:%[0-9]+]]:_(s32) = G_ZEXT [[ANYEXT1]](s16) - ; CHECK-NEXT: [[BITCAST:%[0-9]+]]:_(<2 x s16>) = G_BITCAST [[ZEXT]](s32) - ; CHECK-NEXT: [[BITCAST1:%[0-9]+]]:_(<2 x s16>) = G_BITCAST [[ZEXT1]](s32) - ; CHECK-NEXT: [[BITCAST2:%[0-9]+]]:_(<2 x s16>) = G_BITCAST [[ZEXT2]](s32) - ; CHECK-NEXT: [[BITCAST3:%[0-9]+]]:_(<2 x s16>) = G_BITCAST [[ZEXT3]](s32) - ; CHECK-NEXT: S_ENDPGM 0, implicit [[BITCAST]](<2 x s16>), implicit [[BITCAST1]](<2 x s16>), implicit [[BITCAST2]](<2 x s16>), implicit [[BITCAST3]](<2 x s16>) + ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[ZEXT]](s32), [[ZEXT1]](s32) + ; CHECK-NEXT: [[BUILD_VECTOR1:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[ZEXT2]](s32), [[ZEXT3]](s32) + ; CHECK-NEXT: S_ENDPGM 0, implicit [[BUILD_VECTOR]](<2 x s32>), implicit [[BUILD_VECTOR1]](<2 x s32>) %0:_(<2 x s32>) = COPY $vgpr0_vgpr1 %1:_(<2 x s32>) = COPY $vgpr0_vgpr1 %2:_(s32), %3:_(s32) = G_UNMERGE_VALUES %0(<2 x s32>) @@ -230,8 +228,8 @@ %9:_(s16) = G_ANYEXT %7 %10:_(<4 x s16>) = G_BUILD_VECTOR %8, %9, %8, %9 %11:_(<4 x s32>) = G_ZEXT %10 - %12:_(<2 x s16>), %13:_(<2 x s16>), %14:_(<2 x s16>), %15:_(<2 x s16>) = G_UNMERGE_VALUES %11 - S_ENDPGM 0, implicit %12, implicit %13, implicit %14, implicit %15 + %12:_(<2 x s32>), %13:_(<2 x s32>) = G_UNMERGE_VALUES %11 + S_ENDPGM 0, implicit %12, implicit %13 ... diff --git a/llvm/test/MachineVerifier/test_g_unmerge_values.mir b/llvm/test/MachineVerifier/test_g_unmerge_values.mir new file mode 100644 --- /dev/null +++ b/llvm/test/MachineVerifier/test_g_unmerge_values.mir @@ -0,0 +1,33 @@ +# RUN: not --crash llc -o - -march=arm64 -run-pass=none -verify-machineinstrs %s 2>&1 | FileCheck %s +# REQUIRES: aarch64-registered-target + +--- +name: g_unmerge_values +tracksRegLiveness: true +body: | + bb.0: + ; CHECK: Bad machine code: G_UNMERGE_VALUES destination types do not match + %0:_(s64) = IMPLICIT_DEF + %1:_(s32), %2:_(s16) = G_UNMERGE_VALUES %0 + + ; CHECK: Bad machine code: G_UNMERGE_VALUES source operand does not match vector destination operands + %3:_(<4 x s32>) = IMPLICIT_DEF + %4:_(<3 x s32>), %5:_(<3 x s32>) = G_UNMERGE_VALUES %3 + + ; CHECK: Bad machine code: G_UNMERGE_VALUES source operand does not match vector destination operands + %6:_(<2 x s16>), %7:_(<2 x s16>) = G_UNMERGE_VALUES %3 + + ; CHECK: Bad machine code: G_UNMERGE_VALUES vector source operand does not match scalar destination operands + %8:_(<2 x s32>) = IMPLICIT_DEF + %9:_(s32), %10:_(s32), %11:_(s32) = G_UNMERGE_VALUES %8 + + ; CHECK: Bad machine code: G_UNMERGE_VALUES vector source operand does not match scalar destination operands + %12:_(s16), %13:_(s16) = G_UNMERGE_VALUES %8 + + ; CHECK: Bad machine code: G_UNMERGE_VALUES scalar source operand does not match scalar destination operands + %14:_(s64) = IMPLICIT_DEF + %15:_(s16), %16:_(s16) = G_UNMERGE_VALUES %14 + + ; CHECK: Bad machine code: G_UNMERGE_VALUES scalar source operand does not match scalar destination operands + %17:_(s32), %18:_(s32), %19:_(s32) = G_UNMERGE_VALUES %14 +...