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 @@ -394,6 +394,52 @@ return true; } + bool tryCombineTrunc(MachineInstr &MI, + SmallVectorImpl &DeadInsts, + GISelChangeObserver &Observer) { + if (MI.getOpcode() != TargetOpcode::G_TRUNC) + return false; + + // Attempt to combine: + // %2 = G_MERGE_VALUES %0, %1 + // %3 = G_TRUNC %2 + // ... = ... %3 + // to this when %0 and %3 are the same type: + // ... = ... %0 + // or to this when %0 and %3 are scalars and %3 is smaller: + // %3 = G_TRUNC %0 + // ... = ... %3 + // There are other possibilities but this should cover the common ones. + unsigned DstReg = MI.getOperand(0).getReg(); + LLT DstTy = MRI.getType(DstReg); + unsigned DefReg = lookThroughCopyInstrs(MI.getOperand(1).getReg()); + MachineInstr *DefMI = MRI.getVRegDef(DefReg); + if (!DefMI) + return false; + if (DefMI->getOpcode() == TargetOpcode::G_MERGE_VALUES) { + Register OriginReg = DefMI->getOperand(1).getReg(); + LLT OriginTy = MRI.getType(OriginReg); + Builder.setInstr(MI); + if (DstTy == OriginTy) { + if (MRI.constrainRegAttrs(DstReg, OriginReg)) + MRI.replaceRegWith(OriginReg, DstReg); + else { + Builder.buildCopy(DstReg, OriginReg); + } + markInstAndDefDead(MI, *DefMI, DeadInsts); + return true; + } + if (DstTy.getSizeInBits() < OriginTy.getSizeInBits()) { + assert(DstTy.isScalar() && OriginTy.isScalar() && + "G_MERGE_VALUES with non-scalar?"); + Builder.buildTrunc(DstReg, OriginReg); + markInstAndDefDead(MI, *DefMI, DeadInsts); + return true; + } + } + return false; + } + /// Try to combine away MI. /// Returns true if it combined away the MI. /// Adds instructions that are dead as a result of the combine @@ -420,7 +466,7 @@ case TargetOpcode::G_EXTRACT: return tryCombineExtract(MI, DeadInsts); case TargetOpcode::G_TRUNC: { - bool Changed = false; + bool Changed = tryCombineTrunc(MI, DeadInsts, WrapperObserver); for (auto &Use : MRI.use_instructions(MI.getOperand(0).getReg())) Changed |= tryCombineInstruction(Use, DeadInsts, WrapperObserver); return Changed; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-inserts.mir @@ -5,6 +5,9 @@ target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" target triple = "aarch64--" define void @test_inserts_nonpow2() { ret void } + define void @test_inserts_4() { ret void } + define void @test_inserts_5() { ret void } + define void @test_inserts_6() { ret void } ... --- @@ -27,3 +30,69 @@ $x0 = COPY %6 RET_ReallyLR ... + +--- +name: test_inserts_4 +body: | + bb.0: + liveins: $w0 + + ; A narrow insert gets surrounded by a G_ANYEXT/G_TRUNC pair. + ; CHECK-LABEL: name: test_inserts_4 + ; CHECK: [[VALEXT:%[0-9]+]]:_(s32) = COPY %2(s32) + ; CHECK: [[VAL:%[0-9]+]]:_(s32) = G_INSERT [[VALEXT]], %1(s1), 0 + ; CHECK: %5:_(s8) = G_TRUNC [[VAL]](s32) + %4:_(s32) = COPY $w0 + %0:_(s1) = G_TRUNC %4 + %5:_(s32) = COPY $w1 + %1:_(s8) = G_TRUNC %5 + %2:_(p0) = COPY $x2 + %3:_(s8) = G_INSERT %1(s8), %0(s1), 0 + G_STORE %3(s8), %2(p0) :: (store 1) + RET_ReallyLR +... + +--- +name: test_inserts_5 +body: | + bb.0: + liveins: $x0, $x1, $x2 + + + ; CHECK-LABEL: name: test_inserts_5 + ; CHECK: [[INS_LO:%[0-9]+]]:_(s32) = G_EXTRACT %2(s64), 0 + ; CHECK: [[VAL_LO:%[0-9]+]]:_(s64) = G_INSERT %0, [[INS_LO]](s32), 32 + ; CHECK: [[INS_HI:%[0-9]+]]:_(s32) = G_EXTRACT %2(s64), 32 + ; This instruction is dead but it was already processed by the legalizer + ; and as such it didn't notice. The next pass will delete it. + ; CHECK: [[VAL_HI:%[0-9]+]]:_(s64) = G_INSERT %1, [[INS_HI]](s32), 0 + ; CHECK: $x0 = COPY [[VAL_LO]](s64) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s64) = COPY $x2 + %3:_(s128) = G_MERGE_VALUES %0, %1 + %4:_(s128) = G_INSERT %3, %2, 32 + %5:_(s64) = G_TRUNC %4 + $x0 = COPY %5 + RET_ReallyLR +... + +--- +name: test_inserts_6 +body: | + bb.0: + liveins: $x0, $x1, $x2 + + + ; CHECK-LABEL: name: test_inserts_6 + ; CHECK: [[VAL_LO:%[0-9]+]]:_(s64) = G_INSERT %0, %2(s32), 32 + ; CHECK: $x0 = COPY [[VAL_LO]](s64) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s32) = COPY $w2 + %3:_(s128) = G_MERGE_VALUES %0, %1 + %4:_(s128) = G_INSERT %3, %2, 32 + %5:_(s64) = G_TRUNC %4 + $x0 = COPY %5 + RET_ReallyLR +... diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-undef.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-undef.mir --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-undef.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-undef.mir @@ -9,9 +9,7 @@ ; CHECK-LABEL: name: test_implicit_def ; CHECK: [[DEF:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF ; CHECK: [[DEF1:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF - ; CHECK: [[MV:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[DEF]](s64), [[DEF1]](s64) - ; CHECK: [[TRUNC:%[0-9]+]]:_(s64) = G_TRUNC [[MV]](s128) - ; CHECK: $x0 = COPY [[TRUNC]](s64) + ; CHECK: $x0 = COPY [[DEF]](s64) %0:_(s128) = G_IMPLICIT_DEF %1:_(s64) = G_TRUNC %0(s128) $x0 = COPY %1(s64) diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz-zero-undef.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz-zero-undef.mir --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz-zero-undef.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz-zero-undef.mir @@ -202,14 +202,11 @@ ; CHECK: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[ZEXT]](s64) ; CHECK: [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C1]](s64) ; CHECK: [[USUBO:%[0-9]+]]:_(s32), [[USUBO1:%[0-9]+]]:_(s1) = G_USUBO [[UV]], [[UV2]] + ; This instruction is dead but it was already processed by the legalizer + ; and as such it didn't notice. The next pass will delete it. ; CHECK: [[USUBE:%[0-9]+]]:_(s32), [[USUBE1:%[0-9]+]]:_(s1) = G_USUBE [[UV1]], [[UV3]], [[USUBO1]] - ; CHECK: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[USUBO]](s32), [[USUBE]](s32) - ; CHECK: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4294967295 - ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY [[MV]](s64) - ; CHECK: [[COPY3:%[0-9]+]]:_(s64) = COPY [[C2]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s64) = G_AND [[COPY2]], [[COPY3]] - ; CHECK: [[COPY4:%[0-9]+]]:_(s64) = COPY [[AND1]](s64) - ; CHECK: $vgpr0_vgpr1 = COPY [[COPY4]](s64) + ; CHECK: [[ZEXT1:%[0-9]+]]:_(s64) = G_ZEXT [[USUBO]](s32) + ; CHECK: $vgpr0_vgpr1 = COPY [[ZEXT1]](s64) %0:_(s64) = COPY $vgpr0_vgpr1 %1:_(s33) = G_TRUNC %0 %2:_(s33) = G_CTLZ_ZERO_UNDEF %1 diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz.mir --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-ctlz.mir @@ -202,14 +202,11 @@ ; CHECK: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[ZEXT]](s64) ; CHECK: [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[C1]](s64) ; CHECK: [[USUBO:%[0-9]+]]:_(s32), [[USUBO1:%[0-9]+]]:_(s1) = G_USUBO [[UV]], [[UV2]] + ; This instruction is dead but it was already processed by the legalizer + ; and as such it didn't notice. The next pass will delete it. ; CHECK: [[USUBE:%[0-9]+]]:_(s32), [[USUBE1:%[0-9]+]]:_(s1) = G_USUBE [[UV1]], [[UV3]], [[USUBO1]] - ; CHECK: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[USUBO]](s32), [[USUBE]](s32) - ; CHECK: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4294967295 - ; CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY [[MV]](s64) - ; CHECK: [[COPY3:%[0-9]+]]:_(s64) = COPY [[C2]](s64) - ; CHECK: [[AND1:%[0-9]+]]:_(s64) = G_AND [[COPY2]], [[COPY3]] - ; CHECK: [[COPY4:%[0-9]+]]:_(s64) = COPY [[AND1]](s64) - ; CHECK: $vgpr0_vgpr1 = COPY [[COPY4]](s64) + ; CHECK: [[ZEXT1:%[0-9]+]]:_(s64) = G_ZEXT [[USUBO]] + ; CHECK: $vgpr0_vgpr1 = COPY [[ZEXT1]](s64) %0:_(s64) = COPY $vgpr0_vgpr1 %1:_(s33) = G_TRUNC %0 %2:_(s33) = G_CTLZ %1 diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values.mir --- a/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values.mir +++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/legalize-unmerge-values.mir @@ -320,8 +320,7 @@ ; CHECK: [[AND1:%[0-9]+]]:_(s64) = G_AND [[UV1]], [[C1]] ; CHECK: [[MV:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[AND]](s64), [[AND1]](s64) ; CHECK: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 15 - ; CHECK: [[MV1:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C2]](s64), [[C1]](s64) - ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[MV1]](s128) + ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[C2]](s64) ; CHECK: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 64 ; CHECK: [[UV2:%[0-9]+]]:_(s64), [[UV3:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[MV]](s128) ; CHECK: [[SUB:%[0-9]+]]:_(s32) = G_SUB [[TRUNC]], [[C3]] @@ -341,8 +340,7 @@ ; CHECK: [[OR1:%[0-9]+]]:_(s64) = G_OR [[UV4]], [[SELECT]] ; CHECK: [[OR2:%[0-9]+]]:_(s64) = G_OR [[UV5]], [[SELECT2]] ; CHECK: [[C5:%[0-9]+]]:_(s64) = G_CONSTANT i64 30 - ; CHECK: [[MV2:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C5]](s64), [[C1]](s64) - ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[MV2]](s128) + ; CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[C5]](s64) ; CHECK: [[SUB2:%[0-9]+]]:_(s32) = G_SUB [[TRUNC1]], [[C3]] ; CHECK: [[SUB3:%[0-9]+]]:_(s32) = G_SUB [[C3]], [[TRUNC1]] ; CHECK: [[ICMP2:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), [[TRUNC1]](s32), [[C3]] @@ -358,8 +356,7 @@ ; CHECK: [[OR4:%[0-9]+]]:_(s64) = G_OR [[OR1]], [[SELECT3]] ; CHECK: [[OR5:%[0-9]+]]:_(s64) = G_OR [[OR2]], [[SELECT5]] ; CHECK: [[C6:%[0-9]+]]:_(s64) = G_CONSTANT i64 45 - ; CHECK: [[MV3:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C6]](s64), [[C1]](s64) - ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[MV3]](s128) + ; CHECK: [[TRUNC2:%[0-9]+]]:_(s32) = G_TRUNC [[C6]](s64) ; CHECK: [[SUB4:%[0-9]+]]:_(s32) = G_SUB [[TRUNC2]], [[C3]] ; CHECK: [[SUB5:%[0-9]+]]:_(s32) = G_SUB [[C3]], [[TRUNC2]] ; CHECK: [[ICMP4:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), [[TRUNC2]](s32), [[C3]] @@ -375,8 +372,7 @@ ; CHECK: [[OR7:%[0-9]+]]:_(s64) = G_OR [[OR4]], [[SELECT6]] ; CHECK: [[OR8:%[0-9]+]]:_(s64) = G_OR [[OR5]], [[SELECT8]] ; CHECK: [[C7:%[0-9]+]]:_(s64) = G_CONSTANT i64 60 - ; CHECK: [[MV4:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C7]](s64), [[C1]](s64) - ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[MV4]](s128) + ; CHECK: [[TRUNC3:%[0-9]+]]:_(s32) = G_TRUNC [[C7]](s64) ; CHECK: [[SUB6:%[0-9]+]]:_(s32) = G_SUB [[TRUNC3]], [[C3]] ; CHECK: [[SUB7:%[0-9]+]]:_(s32) = G_SUB [[C3]], [[TRUNC3]] ; CHECK: [[ICMP6:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), [[TRUNC3]](s32), [[C3]] @@ -392,8 +388,7 @@ ; CHECK: [[OR10:%[0-9]+]]:_(s64) = G_OR [[OR7]], [[SELECT9]] ; CHECK: [[OR11:%[0-9]+]]:_(s64) = G_OR [[OR8]], [[SELECT11]] ; CHECK: [[C8:%[0-9]+]]:_(s64) = G_CONSTANT i64 75 - ; CHECK: [[MV5:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C8]](s64), [[C1]](s64) - ; CHECK: [[TRUNC4:%[0-9]+]]:_(s32) = G_TRUNC [[MV5]](s128) + ; CHECK: [[TRUNC4:%[0-9]+]]:_(s32) = G_TRUNC [[C8]](s64) ; CHECK: [[SUB8:%[0-9]+]]:_(s32) = G_SUB [[TRUNC4]], [[C3]] ; CHECK: [[SUB9:%[0-9]+]]:_(s32) = G_SUB [[C3]], [[TRUNC4]] ; CHECK: [[ICMP8:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), [[TRUNC4]](s32), [[C3]] @@ -409,8 +404,7 @@ ; CHECK: [[OR13:%[0-9]+]]:_(s64) = G_OR [[OR10]], [[SELECT12]] ; CHECK: [[OR14:%[0-9]+]]:_(s64) = G_OR [[OR11]], [[SELECT14]] ; CHECK: [[C9:%[0-9]+]]:_(s64) = G_CONSTANT i64 90 - ; CHECK: [[MV6:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C9]](s64), [[C1]](s64) - ; CHECK: [[TRUNC5:%[0-9]+]]:_(s32) = G_TRUNC [[MV6]](s128) + ; CHECK: [[TRUNC5:%[0-9]+]]:_(s32) = G_TRUNC [[C9]](s64) ; CHECK: [[SUB10:%[0-9]+]]:_(s32) = G_SUB [[TRUNC5]], [[C3]] ; CHECK: [[SUB11:%[0-9]+]]:_(s32) = G_SUB [[C3]], [[TRUNC5]] ; CHECK: [[ICMP10:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), [[TRUNC5]](s32), [[C3]] @@ -426,8 +420,7 @@ ; CHECK: [[OR16:%[0-9]+]]:_(s64) = G_OR [[OR13]], [[SELECT15]] ; CHECK: [[OR17:%[0-9]+]]:_(s64) = G_OR [[OR14]], [[SELECT17]] ; CHECK: [[C10:%[0-9]+]]:_(s64) = G_CONSTANT i64 105 - ; CHECK: [[MV7:%[0-9]+]]:_(s128) = G_MERGE_VALUES [[C10]](s64), [[C1]](s64) - ; CHECK: [[TRUNC6:%[0-9]+]]:_(s32) = G_TRUNC [[MV7]](s128) + ; CHECK: [[TRUNC6:%[0-9]+]]:_(s32) = G_TRUNC [[C10]](s64) ; CHECK: [[SUB12:%[0-9]+]]:_(s32) = G_SUB [[TRUNC6]], [[C3]] ; CHECK: [[SUB13:%[0-9]+]]:_(s32) = G_SUB [[C3]], [[TRUNC6]] ; CHECK: [[ICMP12:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), [[TRUNC6]](s32), [[C3]] diff --git a/llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt b/llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt --- a/llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt +++ b/llvm/unittests/CodeGen/GlobalISel/CMakeLists.txt @@ -13,6 +13,7 @@ CSETest.cpp LegalizerHelperTest.cpp LegalizerInfoTest.cpp + LegalizerArtifactCombinerTest.cpp MachineIRBuilderTest.cpp GISelMITest.cpp PatternMatchTest.cpp diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -103,11 +103,16 @@ - { id: 1, class: _ } - { id: 2, class: _ } - { id: 3, class: _ } + - { id: 4, class: _ } + - { id: 5, class: _ } body: | bb.1: %0(s64) = COPY $x0 %1(s64) = COPY $x1 %2(s64) = COPY $x2 + %3(s32) = COPY $w3 + %4(s32) = COPY $w4 + %5(s32) = COPY $w5 )MIR") + Twine(MIRFunc) + Twine("...\n")) .toNullTerminatedStringRef(S); std::unique_ptr MIR; diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerArtifactCombinerTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerArtifactCombinerTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerArtifactCombinerTest.cpp @@ -0,0 +1,142 @@ +//===- LegalizerHelperTest.cpp +//-----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "GISelMITest.h" +#include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" + +namespace { + +class DummyGISelObserver : public GISelChangeObserver { +public: + void changingInstr(MachineInstr &MI) override {} + void changedInstr(MachineInstr &MI) override {} + void createdInstr(MachineInstr &MI) override {} + void erasingInstr(MachineInstr &MI) override {} +}; + +TEST_F(GISelMITest, MergeUnmerge) { + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, {}); + // Build Instr + MachineInstr *MI0 = B.buildInstr(TargetOpcode::G_MERGE_VALUES, + {LLT::scalar(128)}, {Copies[0], Copies[1]}); + MachineInstr *MI1 = B.buildInstr(TargetOpcode::G_UNMERGE_VALUES, + {LLT::scalar(64), LLT::scalar(64)}, + {MI0->getOperand(0).getReg()}); + B.buildInstr(TargetOpcode::COPY, + {MRI->getVRegDef(Copies[2])->getOperand(1).getReg()}, + {MI1->getOperand(0).getReg()}); + + AInfo Info(MF->getSubtarget()); + DummyGISelObserver Observer; + ArrayRef Observers = {&Observer}; + GISelObserverWrapper ObserverWrapper(Observers); + LegalizerHelper Helper(*MF, Info, Observer, B); + LegalizationArtifactCombiner ArtCombiner(B, MF->getRegInfo(), Info); + // Perform Legalization + SmallVector DeadInstructions; + EXPECT_TRUE(ArtCombiner.tryCombineInstruction(*MI1, DeadInstructions, ObserverWrapper)); + EXPECT_TRUE(DeadInstructions.size() == 2); + for (auto *DeadMI : DeadInstructions) { + LLVM_DEBUG(dbgs() << *DeadMI << "Is dead\n"); + DeadMI->eraseFromParentAndMarkDBGValuesForRemoval(); + } + + auto CheckStr = R"( + CHECK: [[T0:%[0-9]+]]:_(s64) = COPY $x0 + CHECK: $x2 = COPY [[T0]] + )"; + + // Check + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +} + +TEST_F(GISelMITest, MergeTrunc1) { + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, {}); + // Build Instr + MachineInstr *MI0 = B.buildInstr(TargetOpcode::G_MERGE_VALUES, + {LLT::scalar(128)}, {Copies[0], Copies[1]}); + MachineInstr *MI1 = B.buildInstr(TargetOpcode::G_TRUNC, {LLT::scalar(64)}, + {MI0->getOperand(0).getReg()}); + B.buildInstr(TargetOpcode::COPY, + {MRI->getVRegDef(Copies[2])->getOperand(1).getReg()}, + {MI1->getOperand(0).getReg()}); + + AInfo Info(MF->getSubtarget()); + DummyGISelObserver Observer; + ArrayRef Observers = {&Observer}; + GISelObserverWrapper ObserverWrapper(Observers); + LegalizerHelper Helper(*MF, Info, Observer, B); + LegalizationArtifactCombiner ArtCombiner(B, MF->getRegInfo(), Info); + // Perform Legalization + SmallVector DeadInstructions; + EXPECT_TRUE(ArtCombiner.tryCombineInstruction(*MI1, DeadInstructions, ObserverWrapper)); + EXPECT_TRUE(DeadInstructions.size() == 0); + for (auto *DeadMI : DeadInstructions) { + LLVM_DEBUG(dbgs() << *DeadMI << "Is dead\n"); + DeadMI->eraseFromParentAndMarkDBGValuesForRemoval(); + } + + auto CheckStr = R"( + CHECK: [[T0:%[0-9]+]]:_(s64) = COPY $x0 + CHECK: $x2 = COPY [[T0]] + )"; + + // Check + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +} + +TEST_F(GISelMITest, MergeTrunc2) { + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, {}); + // Build Instr + MachineInstr *MI0 = B.buildInstr(TargetOpcode::G_MERGE_VALUES, + {LLT::scalar(128)}, {Copies[0], Copies[1]}); + MachineInstr *MI1 = B.buildInstr(TargetOpcode::G_TRUNC, {LLT::scalar(32)}, + {MI0->getOperand(0).getReg()}); + B.buildInstr(TargetOpcode::COPY, + {MRI->getVRegDef(Copies[3])->getOperand(1).getReg()}, + {MI1->getOperand(0).getReg()}); + + AInfo Info(MF->getSubtarget()); + DummyGISelObserver Observer; + ArrayRef Observers = {&Observer}; + GISelObserverWrapper ObserverWrapper(Observers); + LegalizerHelper Helper(*MF, Info, Observer, B); + LegalizationArtifactCombiner ArtCombiner(B, MF->getRegInfo(), Info); + // Perform Legalization + SmallVector DeadInstructions; + EXPECT_TRUE(ArtCombiner.tryCombineInstruction(*MI1, DeadInstructions, ObserverWrapper)); + EXPECT_TRUE(DeadInstructions.size() == 0); + for (auto *DeadMI : DeadInstructions) { + errs() << *DeadMI << "Is dead\n"; + DeadMI->eraseFromParentAndMarkDBGValuesForRemoval(); + } + + auto CheckStr = R"( + CHECK: [[T0:%[0-9]+]]:_(s64) = COPY $x0 + CHECK: [[T1:%[0-9]+]]:_(s32) = G_TRUNC [[T0]] + CHECK: $w3 = COPY [[T1]] + )"; + + // Check + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +} + +} // namespace