diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h --- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h @@ -300,7 +300,7 @@ for (unsigned i = 0; i < NumSrcs; ++i) SrcRegs[i] = SrcMerge->getSourceReg(i); - Builder.buildMergeLikeInstr(DstReg, SrcRegs); + Builder.buildMergeValues(DstReg, SrcRegs); UpdatedDefs.push_back(DstReg); } else { // Unable to combine diff --git a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h --- a/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -968,6 +968,21 @@ /// Build and insert \p Res = IMPLICIT_DEF. MachineInstrBuilder buildUndef(const DstOp &Res); + /// Build and insert \p Res = G_MERGE_VALUES \p Op0, ... + /// + /// G_MERGE_VALUES combines the input elements contiguously into a larger + /// register. It should only be used when the destination register is not a + /// vector. + /// + /// \pre setBasicBlock or setMI must have been called. + /// \pre The entire register \p Res (and no more) must be covered by the input + /// registers. + /// \pre The type of all \p Ops registers must be identical. + /// + /// \return a MachineInstrBuilder for the newly created instruction. + MachineInstrBuilder buildMergeValues(const DstOp &Res, + ArrayRef Ops); + /// Build and insert \p Res = G_MERGE_VALUES \p Op0, ... /// or \p Res = G_BUILD_VECTOR \p Op0, ... /// or \p Res = G_CONCAT_VECTORS \p Op0, ... diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp --- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp @@ -388,7 +388,7 @@ unsigned SrcSize = PartLLT.getSizeInBits().getFixedValue() * Regs.size(); if (SrcSize == OrigTy.getSizeInBits()) - B.buildMergeLikeInstr(OrigRegs[0], Regs); + B.buildMergeValues(OrigRegs[0], Regs); else { auto Widened = B.buildMergeLikeInstr(LLT::scalar(SrcSize), Regs); B.buildTrunc(OrigRegs[0], Widened); diff --git a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp --- a/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -597,6 +597,16 @@ return buildInstr(TargetOpcode::G_IMPLICIT_DEF, {Res}, {}); } +MachineInstrBuilder MachineIRBuilder::buildMergeValues(const DstOp &Res, + ArrayRef Ops) { + // Unfortunately to convert from ArrayRef to ArrayRef, + // we need some temporary storage for the DstOp objects. Here we use a + // sufficiently large SmallVector to not go through the heap. + SmallVector TmpVec(Ops.begin(), Ops.end()); + assert(TmpVec.size() > 1); + return buildInstr(TargetOpcode::G_MERGE_VALUES, Res, TmpVec); +} + MachineInstrBuilder MachineIRBuilder::buildMergeLikeInstr(const DstOp &Res, ArrayRef Ops) { diff --git a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp @@ -361,6 +361,39 @@ EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } +using MachineIRBuilderDeathTest = AArch64GISelMITest; + +TEST_F(MachineIRBuilderDeathTest, BuildMergeValues) { + setUp(); + if (!TM) + return; + + LLT S32 = LLT::scalar(32); + Register RegC0 = B.buildConstant(S32, 0).getReg(0); + Register RegC1 = B.buildConstant(S32, 1).getReg(0); + Register RegC2 = B.buildConstant(S32, 2).getReg(0); + Register RegC3 = B.buildConstant(S32, 3).getReg(0); + + // Merging scalar constants should produce a G_MERGE_VALUES. + B.buildMergeValues(LLT::scalar(128), {RegC0, RegC1, RegC2, RegC3}); + + // Using a vector destination type should assert. + LLT V2x32 = LLT::fixed_vector(2, 32); + EXPECT_DEBUG_DEATH( + B.buildMergeValues(V2x32, {RegC0, RegC1}), + "vectors should be built with G_CONCAT_VECTOR or G_BUILD_VECTOR"); + + auto CheckStr = R"( + ; CHECK: [[C0:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 + ; CHECK: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 + ; CHECK: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 2 + ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 3 + ; CHECK: {{%[0-9]+}}:_(s128) = G_MERGE_VALUES [[C0]]:_(s32), [[C1]]:_(s32), [[C2]]:_(s32), [[C3]]:_(s32) + )"; + + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +} + TEST_F(AArch64GISelMITest, BuildAddoSubo) { setUp(); if (!TM)