//===- 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" using namespace LegalizeActions; using namespace LegalizeMutations; using namespace LegalityPredicates; 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 CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom, // in which case it becomes CTTZ_ZERO_UNDEF with select. TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ0) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF).legalFor({{s32, s64}}); }); // Build Instr auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(32)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*MIBCTTZ, 0, LLT::scalar(64))); auto CheckStr = R"( CHECK: [[CZU:%[0-9]+]]:_(s32) = G_CTTZ_ZERO_UNDEF %0 CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0 CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]] CHECK: [[SIXTY4:%[0-9]+]]:_(s32) = G_CONSTANT i32 64 CHECK: [[SEL:%[0-9]+]]:_(s32) = G_SELECT [[CMP]]:_(s1), [[SIXTY4]]:_, [[CZU]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTTZ expansion in terms of CTLZ TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ1) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTLZ).legalFor({{s64, s64}}); }); // Build Instr auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[NEG1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1 CHECK: [[NOT:%[0-9]+]]:_(s64) = G_XOR %0:_, [[NEG1]] CHECK: [[SUB1:%[0-9]+]]:_(s64) = G_ADD %0:_, [[NEG1]] CHECK: [[AND1:%[0-9]+]]:_(s64) = G_AND [[NOT]]:_, [[SUB1]]:_ CHECK: [[CST64:%[0-9]+]]:_(s64) = G_CONSTANT i64 64 CHECK: [[CTLZ:%[0-9]+]]:_(s64) = G_CTLZ [[AND1]]:_ CHECK: G_SUB [[CST64]]:_, [[CTLZ]]:_ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTLZ scalar narrowing TEST_F(AArch64GISelMITest, NarrowScalarCTLZ) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTLZ).legalFor({{s32, s32}}); }); // Build Instr auto CTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {LLT::scalar(32)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*CTLZ, 1, LLT::scalar(32))); auto CheckStr = R"( CHECK: [[UNMERGE_LO:%[0-9]+]]:_(s32), [[UNMERGE_HI:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES %0:_(s64) CHECK: [[ZERO:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), [[UNMERGE_HI]]:_(s32), [[ZERO]]:_ CHECK: [[CTLZ_LO:%[0-9]+]]:_(s32) = G_CTLZ [[UNMERGE_LO]]:_(s32) CHECK: [[THIRTYTWO:%[0-9]+]]:_(s32) = G_CONSTANT i32 32 CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[CTLZ_LO]]:_, [[THIRTYTWO]]:_ CHECK: [[CTLZ_HI:%[0-9]+]]:_(s32) = G_CTLZ_ZERO_UNDEF [[UNMERGE_HI]]:_(s32) CHECK: %{{[0-9]+}}:_(s32) = G_SELECT [[CMP]]:_(s1), [[ADD]]:_, [[CTLZ_HI]]:_ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTTZ scalar narrowing TEST_F(AArch64GISelMITest, NarrowScalarCTTZ) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTTZ).legalFor({{s32, s64}}); }); // Build Instr auto CTTZ = B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(32)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*CTTZ, 1, LLT::scalar(32))); auto CheckStr = R"( CHECK: [[UNMERGE_LO:%[0-9]+]]:_(s32), [[UNMERGE_HI:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES %0:_(s64) CHECK: [[ZERO:%[0-9]+]]:_(s32) = G_CONSTANT i32 0 CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), [[UNMERGE_LO]]:_(s32), [[ZERO]]:_ CHECK: [[CTTZ_HI:%[0-9]+]]:_(s32) = G_CTTZ [[UNMERGE_HI]]:_(s32) CHECK: [[THIRTYTWO:%[0-9]+]]:_(s32) = G_CONSTANT i32 32 CHECK: [[ADD:%[0-9]+]]:_(s32) = G_ADD [[CTTZ_HI]]:_, [[THIRTYTWO]]:_ CHECK: [[CTTZ_LO:%[0-9]+]]:_(s32) = G_CTTZ_ZERO_UNDEF [[UNMERGE_LO]]:_(s32) CHECK: %{{[0-9]+}}:_(s32) = G_SELECT [[CMP]]:_(s1), [[ADD]]:_, [[CTTZ_LO]]:_ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTTZ expansion in terms of CTPOP TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ2) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({{s64, s64}}); }); // Build auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); B.setInsertPt(*EntryMBB, MIBCTTZ->getIterator()); EXPECT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[NEG1:%[0-9]+]]:_(s64) = G_CONSTANT i64 -1 CHECK: [[NOT:%[0-9]+]]:_(s64) = G_XOR %0:_, [[NEG1]] CHECK: [[SUB1:%[0-9]+]]:_(s64) = G_ADD %0:_, [[NEG1]] CHECK: [[AND1:%[0-9]+]]:_(s64) = G_AND [[NOT]]:_, [[SUB1]]:_ CHECK: [[POP:%[0-9]+]]:_(s64) = G_CTPOP [[AND1]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTPOP widening. TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP1) { if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTPOP = B.buildInstr(TargetOpcode::G_CTPOP, {s16}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*MIBCTPOP, 1, s16)); auto CheckStr = R"( CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC %0:_(s64) CHECK: [[ZEXT:%[0-9]+]]:_(s16) = G_ZEXT [[TRUNC]]:_(s8) CHECK: [[CTPOP:%[0-9]+]]:_(s16) = G_CTPOP [[ZEXT]] CHECK: [[COPY:%[0-9]+]]:_(s16) = COPY [[CTPOP]]:_(s16) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test a strange case where the result is wider than the source TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP2) { if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({{s32, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; LLT s32{LLT::scalar(32)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTPOP = B.buildInstr(TargetOpcode::G_CTPOP, {s32}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*MIBCTPOP, 1, s16)); auto CheckStr = R"( CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC %0:_(s64) CHECK: [[ZEXT:%[0-9]+]]:_(s16) = G_ZEXT [[TRUNC]]:_(s8) CHECK: [[CTPOP:%[0-9]+]]:_(s16) = G_CTPOP [[ZEXT]] CHECK: [[COPY:%[0-9]+]]:_(s32) = G_ZEXT [[CTPOP]]:_(s16) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTTZ_ZERO_UNDEF expansion in terms of CTTZ TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ3) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTTZ).legalFor({{s64, s64}}); }); // Build auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: CTTZ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF TEST_F(AArch64GISelMITest, LowerBitCountingCTLZ0) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF).legalFor({{s64, s64}}); }); // Build auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {LLT::scalar(64)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.lower(*MIBCTLZ, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[CZU:%[0-9]+]]:_(s64) = G_CTLZ_ZERO_UNDEF %0 CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0 CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]] CHECK: [[SIXTY4:%[0-9]+]]:_(s64) = G_CONSTANT i64 64 CHECK: [[SEL:%[0-9]+]]:_(s64) = G_SELECT [[CMP]]:_(s1), [[SIXTY4]]:_, [[CZU]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF if the latter is a libcall TEST_F(AArch64GISelMITest, LowerBitCountingCTLZLibcall) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF).libcallFor({{s32, s64}}); }); // Build auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {LLT::scalar(32)}, {Copies[0]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*MIBCTLZ, 0, LLT::scalar(32))); auto CheckStr = R"( CHECK: [[CZU:%[0-9]+]]:_(s32) = G_CTLZ_ZERO_UNDEF %0 CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0 CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]] CHECK: [[THIRTY2:%[0-9]+]]:_(s32) = G_CONSTANT i32 64 CHECK: [[SEL:%[0-9]+]]:_(s32) = G_SELECT [[CMP]]:_(s1), [[THIRTY2]]:_, [[CZU]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTLZ expansion TEST_F(AArch64GISelMITest, LowerBitCountingCTLZ1) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({{s8, s8}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.lower(*MIBCTLZ, 0, s8) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[Cst1:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 CHECK: [[Sh1:%[0-9]+]]:_(s8) = G_LSHR [[Trunc]]:_, [[Cst1]]:_ CHECK: [[Or1:%[0-9]+]]:_(s8) = G_OR [[Trunc]]:_, [[Sh1]]:_ CHECK: [[Cst2:%[0-9]+]]:_(s8) = G_CONSTANT i8 2 CHECK: [[Sh2:%[0-9]+]]:_(s8) = G_LSHR [[Or1]]:_, [[Cst2]]:_ CHECK: [[Or2:%[0-9]+]]:_(s8) = G_OR [[Or1]]:_, [[Sh2]]:_ CHECK: [[Cst4:%[0-9]+]]:_(s8) = G_CONSTANT i8 4 CHECK: [[Sh4:%[0-9]+]]:_(s8) = G_LSHR [[Or2]]:_, [[Cst4]]:_ CHECK: [[Or4:%[0-9]+]]:_(s8) = G_OR [[Or2]]:_, [[Sh4]]:_ CHECK: [[CTPOP:%[0-9]+]]:_(s8) = G_CTPOP [[Or4]]:_ CHECK: [[Len:%[0-9]+]]:_(s8) = G_CONSTANT i8 8 CHECK: [[Sub:%[0-9]+]]:_(s8) = G_SUB [[Len]]:_, [[CTPOP]]:_ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTLZ widening. TEST_F(AArch64GISelMITest, WidenBitCountingCTLZ) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTLZ).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBCTLZ, 1, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[Ctlz:%[0-9]+]]:_(s16) = G_CTLZ [[Zext]] CHECK: [[Cst8:%[0-9]+]]:_(s16) = G_CONSTANT i16 8 CHECK: [[Sub:%[0-9]+]]:_(s16) = G_SUB [[Ctlz]]:_, [[Cst8]]:_ CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Sub]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTLZ_ZERO_UNDEF widening. TEST_F(AArch64GISelMITest, WidenBitCountingCTLZZeroUndef) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTLZ_ZU = B.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBCTLZ_ZU, 1, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[CtlzZu:%[0-9]+]]:_(s16) = G_CTLZ_ZERO_UNDEF [[Zext]] CHECK: [[Cst8:%[0-9]+]]:_(s16) = G_CONSTANT i16 8 CHECK: [[Sub:%[0-9]+]]:_(s16) = G_SUB [[CtlzZu]]:_, [[Cst8]]:_ CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Sub]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTPOP widening. TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTPOP = B.buildInstr(TargetOpcode::G_CTPOP, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBCTPOP, 1, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[Ctpop:%[0-9]+]]:_(s16) = G_CTPOP [[Zext]] CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Ctpop]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTTZ_ZERO_UNDEF widening. TEST_F(AArch64GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTTZ_ZERO_UNDEF = B.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBCTTZ_ZERO_UNDEF, 1, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[CttzZu:%[0-9]+]]:_(s16) = G_CTTZ_ZERO_UNDEF [[Zext]] CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[CttzZu]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // CTTZ widening. TEST_F(AArch64GISelMITest, WidenBitCountingCTTZ) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTTZ).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, {s8}, {MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBCTTZ, 1, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[Zext:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[Cst:%[0-9]+]]:_(s16) = G_CONSTANT i16 256 CHECK: [[Or:%[0-9]+]]:_(s16) = G_OR [[Zext]]:_, [[Cst]] CHECK: [[Cttz:%[0-9]+]]:_(s16) = G_CTTZ [[Or]] CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC [[Cttz]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // UADDO widening. TEST_F(AArch64GISelMITest, WidenUADDO) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_ADD).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1)); auto MIBUAddO = B.buildInstr(TargetOpcode::G_UADDO, {s8, CarryReg}, {MIBTrunc, MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBUAddO, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[LHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[RHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[ADD:%[0-9]+]]:_(s16) = G_ADD [[LHS]]:_, [[RHS]]:_ CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[ADD]] CHECK: [[ZEXT:%[0-9]+]]:_(s16) = G_ZEXT [[TRUNC1]] CHECK: G_ICMP intpred(ne), [[ADD]]:_(s16), [[ZEXT]]:_ CHECK: G_TRUNC [[ADD]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // USUBO widening. TEST_F(AArch64GISelMITest, WidenUSUBO) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_SUB).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1)); auto MIBUSUBO = B.buildInstr(TargetOpcode::G_USUBO, {s8, CarryReg}, {MIBTrunc, MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBUSUBO, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[LHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[RHS:%[0-9]+]]:_(s16) = G_ZEXT [[Trunc]] CHECK: [[SUB:%[0-9]+]]:_(s16) = G_SUB [[LHS]]:_, [[RHS]]:_ CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[SUB]] CHECK: [[ZEXT:%[0-9]+]]:_(s16) = G_ZEXT [[TRUNC1]] CHECK: G_ICMP intpred(ne), [[SUB]]:_(s16), [[ZEXT]]:_ CHECK: G_TRUNC [[SUB]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // SADDO widening. TEST_F(AArch64GISelMITest, WidenSADDO) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_ADD).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1)); auto MIBSAddO = B.buildInstr(TargetOpcode::G_SADDO, {s8, CarryReg}, {MIBTrunc, MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBSAddO, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[LHS:%[0-9]+]]:_(s16) = G_SEXT [[Trunc]] CHECK: [[RHS:%[0-9]+]]:_(s16) = G_SEXT [[Trunc]] CHECK: [[ADD:%[0-9]+]]:_(s16) = G_ADD [[LHS]]:_, [[RHS]]:_ CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[ADD]] CHECK: [[SEXT:%[0-9]+]]:_(s16) = G_SEXT [[TRUNC1]] CHECK: G_ICMP intpred(ne), [[ADD]]:_(s16), [[SEXT]]:_ CHECK: G_TRUNC [[ADD]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // SSUBO widening. TEST_F(AArch64GISelMITest, WidenSSUBO) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_SUB).legalFor({{s16, s16}}); }); // Build // Trunc it to s8. LLT s8{LLT::scalar(8)}; LLT s16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(s8, Copies[0]); unsigned CarryReg = MRI->createGenericVirtualRegister(LLT::scalar(1)); auto MIBSSUBO = B.buildInstr(TargetOpcode::G_SSUBO, {s8, CarryReg}, {MIBTrunc, MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.widenScalar(*MIBSSUBO, 0, s16) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[Trunc:%[0-9]+]]:_(s8) = G_TRUNC CHECK: [[LHS:%[0-9]+]]:_(s16) = G_SEXT [[Trunc]] CHECK: [[RHS:%[0-9]+]]:_(s16) = G_SEXT [[Trunc]] CHECK: [[SUB:%[0-9]+]]:_(s16) = G_SUB [[LHS]]:_, [[RHS]]:_ CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[SUB]] CHECK: [[SEXT:%[0-9]+]]:_(s16) = G_SEXT [[TRUNC1]] CHECK: G_ICMP intpred(ne), [[SUB]]:_(s16), [[SEXT]]:_ CHECK: G_TRUNC [[SUB]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, FewerElementsAnd) { if (!TM) return; const LLT V2S32 = LLT::vector(2, 32); const LLT V5S32 = LLT::vector(5, 32); // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_AND) .legalFor({s32}); }); auto Op0 = B.buildUndef(V5S32); auto Op1 = B.buildUndef(V5S32); auto And = B.buildAnd(V5S32, Op0, Op1); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_TRUE(Helper.fewerElementsVector(*And, 0, V2S32) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[IMP_DEF0:%[0-9]+]]:_(<5 x s32>) = G_IMPLICIT_DEF CHECK: [[IMP_DEF1:%[0-9]+]]:_(<5 x s32>) = G_IMPLICIT_DEF CHECK: [[IMP_DEF2:%[0-9]+]]:_(<5 x s32>) = G_IMPLICIT_DEF CHECK: [[EXTRACT0:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[IMP_DEF0]]:_(<5 x s32>), 0 CHECK: [[EXTRACT1:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[IMP_DEF1]]:_(<5 x s32>), 0 CHECK: [[AND0:%[0-9]+]]:_(<2 x s32>) = G_AND [[EXTRACT0]]:_, [[EXTRACT1]]:_ CHECK: [[INSERT0:%[0-9]+]]:_(<5 x s32>) = G_INSERT [[IMP_DEF2]]:_, [[AND0]]:_(<2 x s32>), 0 CHECK: [[EXTRACT2:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[IMP_DEF0]]:_(<5 x s32>), 64 CHECK: [[EXTRACT3:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[IMP_DEF1]]:_(<5 x s32>), 64 CHECK: [[AND1:%[0-9]+]]:_(<2 x s32>) = G_AND [[EXTRACT2]]:_, [[EXTRACT3]]:_ CHECK: [[INSERT1:%[0-9]+]]:_(<5 x s32>) = G_INSERT [[INSERT0]]:_, [[AND1]]:_(<2 x s32>), 64 CHECK: [[EXTRACT4:%[0-9]+]]:_(s32) = G_EXTRACT [[IMP_DEF0]]:_(<5 x s32>), 128 CHECK: [[EXTRACT5:%[0-9]+]]:_(s32) = G_EXTRACT [[IMP_DEF1]]:_(<5 x s32>), 128 CHECK: [[AND2:%[0-9]+]]:_(s32) = G_AND [[EXTRACT4]]:_, [[EXTRACT5]]:_ CHECK: [[INSERT2:%[0-9]+]]:_(<5 x s32>) = G_INSERT [[INSERT1]]:_, [[AND2]]:_(s32), 128 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, MoreElementsAnd) { if (!TM) return; LLT s32 = LLT::scalar(32); LLT v2s32 = LLT::vector(2, 32); LLT v6s32 = LLT::vector(6, 32); LegalizerInfo LI; LI.getActionDefinitionsBuilder(TargetOpcode::G_AND) .legalFor({v6s32}) .clampMinNumElements(0, s32, 6); LI.computeTables(); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, LI, Observer, B); B.setInsertPt(*EntryMBB, EntryMBB->end()); auto Val0 = B.buildBitcast(v2s32, Copies[0]); auto Val1 = B.buildBitcast(v2s32, Copies[1]); auto And = B.buildAnd(v2s32, Val0, Val1); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.moreElementsVector(*And, 0, v6s32)); auto CheckStr = R"( CHECK: [[BITCAST0:%[0-9]+]]:_(<2 x s32>) = G_BITCAST CHECK: [[BITCAST1:%[0-9]+]]:_(<2 x s32>) = G_BITCAST CHECK: [[IMP_DEF0:%[0-9]+]]:_(<2 x s32>) = G_IMPLICIT_DEF CHECK: [[CONCAT0:%[0-9]+]]:_(<6 x s32>) = G_CONCAT_VECTORS [[BITCAST0]]:_(<2 x s32>), [[IMP_DEF0]]:_(<2 x s32>), [[IMP_DEF0]]:_(<2 x s32>) CHECK: [[IMP_DEF1:%[0-9]+]]:_(<2 x s32>) = G_IMPLICIT_DEF CHECK: [[CONCAT1:%[0-9]+]]:_(<6 x s32>) = G_CONCAT_VECTORS [[BITCAST1]]:_(<2 x s32>), [[IMP_DEF1]]:_(<2 x s32>), [[IMP_DEF1]]:_(<2 x s32>) CHECK: [[AND:%[0-9]+]]:_(<6 x s32>) = G_AND [[CONCAT0]]:_, [[CONCAT1]]:_ CHECK: (<2 x s32>) = G_EXTRACT [[AND]]:_(<6 x s32>), 0 )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, FewerElementsPhi) { if (!TM) return; LLT s1 = LLT::scalar(1); LLT s32 = LLT::scalar(32); LLT s64 = LLT::scalar(64); LLT v2s32 = LLT::vector(2, 32); LLT v5s32 = LLT::vector(5, 32); LegalizerInfo LI; LI.getActionDefinitionsBuilder(TargetOpcode::G_PHI) .legalFor({v2s32}) .clampMinNumElements(0, s32, 2); LI.computeTables(); LLT PhiTy = v5s32; DummyGISelObserver Observer; LegalizerHelper Helper(*MF, LI, Observer, B); B.setMBB(*EntryMBB); MachineBasicBlock *MidMBB = MF->CreateMachineBasicBlock(); MachineBasicBlock *EndMBB = MF->CreateMachineBasicBlock(); MF->insert(MF->end(), MidMBB); MF->insert(MF->end(), EndMBB); EntryMBB->addSuccessor(MidMBB); EntryMBB->addSuccessor(EndMBB); MidMBB->addSuccessor(EndMBB); auto InitVal = B.buildUndef(PhiTy); auto InitOtherVal = B.buildConstant(s64, 999); auto ICmp = B.buildICmp(CmpInst::ICMP_EQ, s1, Copies[0], Copies[1]); B.buildBrCond(ICmp.getReg(0), *MidMBB); B.buildBr(*EndMBB); B.setMBB(*MidMBB); auto MidVal = B.buildUndef(PhiTy); auto MidOtherVal = B.buildConstant(s64, 345); B.buildBr(*EndMBB); B.setMBB(*EndMBB); auto Phi = B.buildInstr(TargetOpcode::G_PHI) .addDef(MRI->createGenericVirtualRegister(PhiTy)) .addUse(InitVal.getReg(0)) .addMBB(EntryMBB) .addUse(MidVal.getReg(0)) .addMBB(MidMBB); // Insert another irrelevant phi to make sure the rebuild is inserted after // it. B.buildInstr(TargetOpcode::G_PHI) .addDef(MRI->createGenericVirtualRegister(s64)) .addUse(InitOtherVal.getReg(0)) .addMBB(EntryMBB) .addUse(MidOtherVal.getReg(0)) .addMBB(MidMBB); // Add some use instruction after the phis. B.buildAnd(PhiTy, Phi.getReg(0), Phi.getReg(0)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.fewerElementsVector(*Phi, 0, v2s32)); auto CheckStr = R"( CHECK: [[INITVAL:%[0-9]+]]:_(<5 x s32>) = G_IMPLICIT_DEF CHECK: [[EXTRACT0:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[INITVAL]]:_(<5 x s32>), 0 CHECK: [[EXTRACT1:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[INITVAL]]:_(<5 x s32>), 64 CHECK: [[EXTRACT2:%[0-9]+]]:_(s32) = G_EXTRACT [[INITVAL]]:_(<5 x s32>), 128 CHECK: G_BRCOND CHECK: [[MIDVAL:%[0-9]+]]:_(<5 x s32>) = G_IMPLICIT_DEF CHECK: [[EXTRACT3:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[MIDVAL]]:_(<5 x s32>), 0 CHECK: [[EXTRACT4:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[MIDVAL]]:_(<5 x s32>), 64 CHECK: [[EXTRACT5:%[0-9]+]]:_(s32) = G_EXTRACT [[MIDVAL]]:_(<5 x s32>), 128 CHECK: G_BR CHECK: [[PHI0:%[0-9]+]]:_(<2 x s32>) = G_PHI [[EXTRACT0]]:_(<2 x s32>), %bb.0, [[EXTRACT3]]:_(<2 x s32>), %bb.1 CHECK: [[PHI1:%[0-9]+]]:_(<2 x s32>) = G_PHI [[EXTRACT1]]:_(<2 x s32>), %bb.0, [[EXTRACT4]]:_(<2 x s32>), %bb.1 CHECK: [[PHI2:%[0-9]+]]:_(s32) = G_PHI [[EXTRACT2]]:_(s32), %bb.0, [[EXTRACT5]]:_(s32), %bb.1 CHECK: [[OTHER_PHI:%[0-9]+]]:_(s64) = G_PHI CHECK: [[REBUILD_VAL_IMPDEF:%[0-9]+]]:_(<5 x s32>) = G_IMPLICIT_DEF CHECK: [[INSERT0:%[0-9]+]]:_(<5 x s32>) = G_INSERT [[REBUILD_VAL_IMPDEF]]:_, [[PHI0]]:_(<2 x s32>), 0 CHECK: [[INSERT1:%[0-9]+]]:_(<5 x s32>) = G_INSERT [[INSERT0]]:_, [[PHI1]]:_(<2 x s32>), 64 CHECK: [[INSERT2:%[0-9]+]]:_(<5 x s32>) = G_INSERT [[INSERT1]]:_, [[PHI2]]:_(s32), 128 CHECK: [[USE_OP:%[0-9]+]]:_(<5 x s32>) = G_AND [[INSERT2]]:_, [[INSERT2]]:_ )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // FNEG expansion in terms of FSUB TEST_F(AArch64GISelMITest, LowerFNEG) { if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FSUB).legalFor({s64}); }); // Build Instr. Make sure FMF are preserved. auto FAdd = B.buildInstr(TargetOpcode::G_FADD, {LLT::scalar(64)}, {Copies[0], Copies[1]}, MachineInstr::MIFlag::FmNsz); // Should not propagate the flags of src instruction. auto FNeg0 = B.buildInstr(TargetOpcode::G_FNEG, {LLT::scalar(64)}, {FAdd.getReg(0)}, {MachineInstr::MIFlag::FmArcp}); // Preserve the one flag. auto FNeg1 = B.buildInstr(TargetOpcode::G_FNEG, {LLT::scalar(64)}, {Copies[0]}, MachineInstr::MIFlag::FmNoInfs); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*FNeg0, 0, LLT::scalar(64))); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*FNeg1, 0, LLT::scalar(64))); auto CheckStr = R"( CHECK: [[FADD:%[0-9]+]]:_(s64) = nsz G_FADD %0:_, %1:_ CHECK: [[CONST0:%[0-9]+]]:_(s64) = G_FCONSTANT double -0.000000e+00 CHECK: [[FSUB0:%[0-9]+]]:_(s64) = arcp G_FSUB [[CONST0]]:_, [[FADD]]:_ CHECK: [[CONST1:%[0-9]+]]:_(s64) = G_FCONSTANT double -0.000000e+00 CHECK: [[FSUB1:%[0-9]+]]:_(s64) = ninf G_FSUB [[CONST1]]:_, %0:_ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LowerMinMax) { if (!TM) return; LLT s64 = LLT::scalar(64); LLT v2s32 = LLT::vector(2, 32); DefineLegalizerInfo(A, { getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) .lowerFor({s64, LLT::vector(2, s32)}); }); auto SMin = B.buildSMin(s64, Copies[0], Copies[1]); auto SMax = B.buildSMax(s64, Copies[0], Copies[1]); auto UMin = B.buildUMin(s64, Copies[0], Copies[1]); auto UMax = B.buildUMax(s64, Copies[0], Copies[1]); auto VecVal0 = B.buildBitcast(v2s32, Copies[0]); auto VecVal1 = B.buildBitcast(v2s32, Copies[1]); auto SMinV = B.buildSMin(v2s32, VecVal0, VecVal1); auto SMaxV = B.buildSMax(v2s32, VecVal0, VecVal1); auto UMinV = B.buildUMin(v2s32, VecVal0, VecVal1); auto UMaxV = B.buildUMax(v2s32, VecVal0, VecVal1); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*SMin, 0, s64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*SMax, 0, s64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*UMin, 0, s64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*UMax, 0, s64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*SMinV, 0, v2s32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*SMaxV, 0, v2s32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*UMinV, 0, v2s32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*UMaxV, 0, v2s32)); auto CheckStr = R"( CHECK: [[CMP0:%[0-9]+]]:_(s1) = G_ICMP intpred(slt), %0:_(s64), %1:_ CHECK: [[SMIN:%[0-9]+]]:_(s64) = G_SELECT [[CMP0]]:_(s1), %0:_, %1:_ CHECK: [[CMP1:%[0-9]+]]:_(s1) = G_ICMP intpred(sgt), %0:_(s64), %1:_ CHECK: [[SMAX:%[0-9]+]]:_(s64) = G_SELECT [[CMP1]]:_(s1), %0:_, %1:_ CHECK: [[CMP2:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), %0:_(s64), %1:_ CHECK: [[UMIN:%[0-9]+]]:_(s64) = G_SELECT [[CMP2]]:_(s1), %0:_, %1:_ CHECK: [[CMP3:%[0-9]+]]:_(s1) = G_ICMP intpred(ugt), %0:_(s64), %1:_ CHECK: [[UMAX:%[0-9]+]]:_(s64) = G_SELECT [[CMP3]]:_(s1), %0:_, %1:_ CHECK: [[VEC0:%[0-9]+]]:_(<2 x s32>) = G_BITCAST %0:_(s64) CHECK: [[VEC1:%[0-9]+]]:_(<2 x s32>) = G_BITCAST %1:_(s64) CHECK: [[VCMP0:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(slt), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ CHECK: [[SMINV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP0]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ CHECK: [[VCMP1:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(sgt), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ CHECK: [[SMAXV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP1]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ CHECK: [[VCMP2:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(ult), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ CHECK: [[UMINV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP2]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ CHECK: [[VCMP3:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(ugt), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ CHECK: [[UMAXV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP3]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, WidenScalarBuildVector) { if (!TM) return; LLT S32 = LLT::scalar(32); LLT S16 = LLT::scalar(16); LLT V2S16 = LLT::vector(2, S16); LLT V2S32 = LLT::vector(2, S32); DefineLegalizerInfo(A, { getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) .lowerFor({s64, LLT::vector(2, s32)}); }); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); B.setInsertPt(*EntryMBB, EntryMBB->end()); Register Constant0 = B.buildConstant(S16, 1).getReg(0); Register Constant1 = B.buildConstant(S16, 2).getReg(0); auto BV0 = B.buildBuildVector(V2S16, {Constant0, Constant1}); auto BV1 = B.buildBuildVector(V2S16, {Constant0, Constant1}); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*BV0, 0, V2S32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*BV1, 1, S32)); auto CheckStr = R"( CHECK: [[K0:%[0-9]+]]:_(s16) = G_CONSTANT i16 1 CHECK-NEXT: [[K1:%[0-9]+]]:_(s16) = G_CONSTANT i16 2 CHECK-NEXT: [[EXT_K0_0:%[0-9]+]]:_(s32) = G_ANYEXT [[K0]] CHECK-NEXT: [[EXT_K1_0:%[0-9]+]]:_(s32) = G_ANYEXT [[K1]] CHECK-NEXT: [[BV0:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[EXT_K0_0]]:_(s32), [[EXT_K1_0]]:_(s32) CHECK-NEXT: [[BV0_TRUNC:%[0-9]+]]:_(<2 x s16>) = G_TRUNC [[BV0]] CHECK: [[EXT_K0_1:%[0-9]+]]:_(s32) = G_ANYEXT [[K0]] CHECK-NEXT: [[EXT_K1_1:%[0-9]+]]:_(s32) = G_ANYEXT [[K1]] CHECK-NEXT: [[BV1:%[0-9]+]]:_(<2 x s16>) = G_BUILD_VECTOR_TRUNC [[EXT_K0_1]]:_(s32), [[EXT_K1_1]]:_(s32) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LowerMergeValues) { if (!TM) return; const LLT S32 = LLT::scalar(32); const LLT S24 = LLT::scalar(24); const LLT S21 = LLT::scalar(21); const LLT S16 = LLT::scalar(16); const LLT S9 = LLT::scalar(9); const LLT S8 = LLT::scalar(8); const LLT S3 = LLT::scalar(3); DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_UNMERGE_VALUES) .widenScalarIf(typeIs(1, LLT::scalar(3)), changeTo(1, LLT::scalar(9))); }); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); B.setInsertPt(*EntryMBB, EntryMBB->end()); // 24 = 3 3 3 3 3 3 3 3 // => 9 // // This can do 3 merges, but need an extra implicit_def. SmallVector Merge0Ops; for (int I = 0; I != 8; ++I) Merge0Ops.push_back(B.buildConstant(S3, I).getReg(0)); auto Merge0 = B.buildMerge(S24, Merge0Ops); // 21 = 3 3 3 3 3 3 3 // => 9, 2 extra implicit_def needed // SmallVector Merge1Ops; for (int I = 0; I != 7; ++I) Merge1Ops.push_back(B.buildConstant(S3, I).getReg(0)); auto Merge1 = B.buildMerge(S21, Merge1Ops); SmallVector Merge2Ops; for (int I = 0; I != 2; ++I) Merge2Ops.push_back(B.buildConstant(S8, I).getReg(0)); auto Merge2 = B.buildMerge(S16, Merge2Ops); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*Merge0, 1, S9)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*Merge1, 1, S9)); // Request a source size greater than the original destination size. EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*Merge2, 1, S32)); auto CheckStr = R"( CHECK: [[K0:%[0-9]+]]:_(s3) = G_CONSTANT i3 0 CHECK-NEXT: [[K1:%[0-9]+]]:_(s3) = G_CONSTANT i3 1 CHECK-NEXT: [[K2:%[0-9]+]]:_(s3) = G_CONSTANT i3 2 CHECK-NEXT: [[K3:%[0-9]+]]:_(s3) = G_CONSTANT i3 3 CHECK-NEXT: [[K4:%[0-9]+]]:_(s3) = G_CONSTANT i3 -4 CHECK-NEXT: [[K5:%[0-9]+]]:_(s3) = G_CONSTANT i3 -3 CHECK-NEXT: [[K6:%[0-9]+]]:_(s3) = G_CONSTANT i3 -2 CHECK-NEXT: [[K7:%[0-9]+]]:_(s3) = G_CONSTANT i3 -1 CHECK-NEXT: [[IMPDEF0:%[0-9]+]]:_(s3) = G_IMPLICIT_DEF CHECK-NEXT: [[MERGE0:%[0-9]+]]:_(s9) = G_MERGE_VALUES [[K0]]:_(s3), [[K1]]:_(s3), [[K2]]:_(s3) CHECK-NEXT: [[MERGE1:%[0-9]+]]:_(s9) = G_MERGE_VALUES [[K3]]:_(s3), [[K4]]:_(s3), [[K5]]:_(s3) CHECK-NEXT: [[MERGE2:%[0-9]+]]:_(s9) = G_MERGE_VALUES [[K6]]:_(s3), [[K7]]:_(s3), [[IMPDEF0]]:_(s3) CHECK-NEXT: [[MERGE3:%[0-9]+]]:_(s27) = G_MERGE_VALUES [[MERGE0]]:_(s9), [[MERGE1]]:_(s9), [[MERGE2]]:_(s9) CHECK-NEXT: (s24) = G_TRUNC [[MERGE3]]:_(s27) CHECK: [[K8:%[0-9]+]]:_(s3) = G_CONSTANT i3 0 CHECK-NEXT: [[K9:%[0-9]+]]:_(s3) = G_CONSTANT i3 1 CHECK-NEXT: [[K10:%[0-9]+]]:_(s3) = G_CONSTANT i3 2 CHECK-NEXT: [[K11:%[0-9]+]]:_(s3) = G_CONSTANT i3 3 CHECK-NEXT: [[K12:%[0-9]+]]:_(s3) = G_CONSTANT i3 -4 CHECK-NEXT: [[K13:%[0-9]+]]:_(s3) = G_CONSTANT i3 -3 CHECK-NEXT: [[K14:%[0-9]+]]:_(s3) = G_CONSTANT i3 -2 CHECK-NEXT: [[IMPDEF1:%[0-9]+]]:_(s3) = G_IMPLICIT_DEF CHECK-NEXT: [[MERGE4:%[0-9]+]]:_(s9) = G_MERGE_VALUES [[K8]]:_(s3), [[K9]]:_(s3), [[K10]]:_(s3) CHECK-NEXT: [[MERGE5:%[0-9]+]]:_(s9) = G_MERGE_VALUES [[K11]]:_(s3), [[K12]]:_(s3), [[K13]]:_(s3) CHECK-NEXT: [[MERGE6:%[0-9]+]]:_(s9) = G_MERGE_VALUES [[K14]]:_(s3), [[IMPDEF1]]:_(s3), [[IMPDEF1]]:_(s3) CHECK-NEXT: [[MERGE7:%[0-9]+]]:_(s27) = G_MERGE_VALUES [[MERGE4]]:_(s9), [[MERGE5]]:_(s9), [[MERGE6]]:_(s9) CHECK-NEXT: (s21) = G_TRUNC [[MERGE7]]:_(s27) CHECK: [[K15:%[0-9]+]]:_(s8) = G_CONSTANT i8 0 CHECK-NEXT: [[K16:%[0-9]+]]:_(s8) = G_CONSTANT i8 1 CHECK-NEXT: [[ZEXT_K15:[0-9]+]]:_(s32) = G_ZEXT [[K15]]:_(s8) CHECK-NEXT: [[ZEXT_K16:[0-9]+]]:_(s32) = G_ZEXT [[K16]]:_(s8) [[K16:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 [[SHL:%[0-9]+]]:_(s32) = G_SHL [[ZEXT_K16]]:_, [[K16]]:_(s32) [[OR:%[0-9]+]]:_(s32) = G_OR [[ZEXT_K16]]:_, [[SHL]]:_ (s16) = G_TRUNC [[OR]]:_(s32) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, WidenScalarMergeValuesPointer) { if (!TM) return; DefineLegalizerInfo(A, {}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); B.setInsertPt(*EntryMBB, EntryMBB->end()); const LLT S32 = LLT::scalar(32); const LLT S64 = LLT::scalar(64); const LLT P0 = LLT::pointer(0, 64); auto Lo = B.buildTrunc(S32, Copies[0]); auto Hi = B.buildTrunc(S32, Copies[1]); auto Merge = B.buildMerge(P0, {Lo, Hi}); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*Merge, 1, S64)); auto CheckStr = R"( CHECK: [[TRUNC0:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ZEXT_TRUNC0:%[0-9]+]]:_(s64) = G_ZEXT [[TRUNC0]] CHECK: [[ZEXT_TRUNC1:%[0-9]+]]:_(s64) = G_ZEXT [[TRUNC1]] CHECK: [[SHIFT_AMT:%[0-9]+]]:_(s64) = G_CONSTANT i64 32 CHECK: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[ZEXT_TRUNC1]]:_, [[SHIFT_AMT]] CHECK: [[OR:%[0-9]+]]:_(s64) = G_OR [[ZEXT_TRUNC0]]:_, [[SHL]] CHECK: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[OR]]:_(s64) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, WidenSEXTINREG) { if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_SEXT_INREG).legalForTypeWithAnyImm({s64}); }); // Build Instr auto MIB = B.buildInstr( TargetOpcode::G_SEXT_INREG, {LLT::scalar(32)}, {B.buildInstr(TargetOpcode::G_TRUNC, {LLT::scalar(32)}, {Copies[0]}), uint64_t(8)}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization ASSERT_TRUE(Helper.widenScalar(*MIB, 0, LLT::scalar(64)) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[T0:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[T1:%[0-9]+]]:_(s64) = G_ANYEXT [[T0]]:_(s32) CHECK: [[T2:%[0-9]+]]:_(s64) = G_SEXT_INREG [[T1]]:_, 8 CHECK: [[T3:%[0-9]+]]:_(s32) = G_TRUNC [[T2]]:_(s64) )"; // Check ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } TEST_F(AArch64GISelMITest, NarrowSEXTINREG) { if (!TM) return; // Declare your legalization info, these aren't actually relevant to the test. DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_SEXT_INREG).legalForTypeWithAnyImm({s64}); }); // Build Instr auto MIB = B.buildInstr( TargetOpcode::G_SEXT_INREG, {LLT::scalar(16)}, {B.buildInstr(TargetOpcode::G_TRUNC, {LLT::scalar(16)}, {Copies[0]}), uint64_t(8)}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization ASSERT_TRUE(Helper.narrowScalar(*MIB, 0, LLT::scalar(10)) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[T0:%[0-9]+]]:_(s16) = G_TRUNC CHECK: [[T1:%[0-9]+]]:_(s10) = G_TRUNC [[T0]]:_(s16) CHECK: [[T2:%[0-9]+]]:_(s10) = G_SEXT_INREG [[T1]]:_, 8 CHECK: [[T3:%[0-9]+]]:_(s16) = G_SEXT [[T2]]:_(s10) )"; // Check ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } TEST_F(AArch64GISelMITest, NarrowSEXTINREG2) { if (!TM) return; // Declare your legalization info, these aren't actually relevant to the test. DefineLegalizerInfo( A, { getActionDefinitionsBuilder(G_SEXT_INREG).legalForTypeWithAnyImm({s64}); }); // Build Instr auto MIB = B.buildInstr( TargetOpcode::G_SEXT_INREG, {LLT::scalar(32)}, {B.buildInstr(TargetOpcode::G_TRUNC, {LLT::scalar(32)}, {Copies[0]}), uint64_t(9)}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization ASSERT_TRUE(Helper.narrowScalar(*MIB, 0, LLT::scalar(8)) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[T0:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[T1:%[0-9]+]]:_(s8), [[T2:%[0-9]+]]:_(s8), [[T3:%[0-9]+]]:_(s8), [[T4:%[0-9]+]]:_(s8) = G_UNMERGE_VALUES [[T0]]:_(s32) CHECK: [[CST2:%[0-9]+]]:_(s8) = G_CONSTANT i8 7 CHECK: [[T5:%[0-9]+]]:_(s8) = G_SEXT_INREG [[T2]]:_, 1 CHECK: [[T6:%[0-9]+]]:_(s8) = G_ASHR [[T5]]:_, [[CST2]]:_ CHECK: [[T7:%[0-9]+]]:_(s32) = G_MERGE_VALUES [[T1]]:_(s8), [[T5]]:_(s8), [[T6]]:_(s8), [[T6]]:_(s8) )"; // Check ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } TEST_F(AArch64GISelMITest, LowerSEXTINREG) { if (!TM) return; // Declare your legalization info, these aren't actually relevant to the test. DefineLegalizerInfo( A, { getActionDefinitionsBuilder(G_SEXT_INREG).legalForTypeWithAnyImm({s64}); }); // Build Instr auto MIB = B.buildInstr( TargetOpcode::G_SEXT_INREG, {LLT::scalar(32)}, {B.buildInstr(TargetOpcode::G_TRUNC, {LLT::scalar(32)}, {Copies[0]}), uint64_t(8)}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization ASSERT_TRUE(Helper.lower(*MIB, 0, LLT()) == LegalizerHelper::LegalizeResult::Legalized); auto CheckStr = R"( CHECK: [[T1:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[CST:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 CHECK: [[T2:%[0-9]+]]:_(s32) = G_SHL [[T1]]:_, [[CST]]:_ CHECK: [[T3:%[0-9]+]]:_(s32) = G_ASHR [[T2]]:_, [[CST]]:_ )"; // Check ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } TEST_F(AArch64GISelMITest, LibcallFPExt) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s32, s16}, {s128, s64}}); }); LLT S16{LLT::scalar(16)}; LLT S32{LLT::scalar(32)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S16, Copies[0]); auto MIBFPExt1 = B.buildInstr(TargetOpcode::G_FPEXT, {S32}, {MIBTrunc}); auto MIBFPExt2 = B.buildInstr(TargetOpcode::G_FPEXT, {S128}, {Copies[1]}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFPExt1)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFPExt2)); auto CheckStr = R"( CHECK: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC CHECK: $h0 = COPY [[TRUNC]] CHECK: BL &__gnu_h2f_ieee CHECK: $d0 = COPY CHECK: BL &__extenddftf2 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFPTrunc) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s16, s32}, {s64, s128}}); }); LLT S16{LLT::scalar(16)}; LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBFPTrunc1 = B.buildInstr(TargetOpcode::G_FPTRUNC, {S16}, {MIBTrunc}); auto MIBMerge = B.buildMerge(S128, {Copies[1], Copies[2]}); auto MIBFPTrunc2 = B.buildInstr(TargetOpcode::G_FPTRUNC, {S64}, {MIBMerge}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFPTrunc1)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFPTrunc2)); auto CheckStr = R"( CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &__gnu_f2h_ieee CHECK: $q0 = COPY CHECK: BL &__trunctfdf2 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallSimple) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FADD).libcallFor({s16}); }); LLT S16{LLT::scalar(16)}; auto MIBTrunc = B.buildTrunc(S16, Copies[0]); auto MIBFADD = B.buildInstr(TargetOpcode::G_FADD, {S16}, {MIBTrunc, MIBTrunc}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Make sure we do not crash anymore EXPECT_EQ(LegalizerHelper::LegalizeResult::UnableToLegalize, Helper.libcall(*MIBFADD)); } TEST_F(AArch64GISelMITest, LibcallSRem) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_SREM).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBSRem32 = B.buildInstr(TargetOpcode::G_SREM, {S32}, {MIBTrunc, MIBTrunc}); auto MIBSRem64 = B.buildInstr(TargetOpcode::G_SREM, {S64}, {Copies[0], Copies[0]}); auto MIBSRem128 = B.buildInstr(TargetOpcode::G_SREM, {S128}, {MIBExt, MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSRem32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSRem64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSRem128)); auto CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $w0 = COPY [[TRUNC]] CHECK: $w1 = COPY [[TRUNC]] CHECK: BL &__modsi3 CHECK: $x0 = COPY [[COPY]] CHECK: $x1 = COPY [[COPY]] CHECK: BL &__moddi3 CHECK: [[UV:%[0-9]+]]:_(s64), [[UV1:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[ANYEXT]] CHECK: [[UV2:%[0-9]+]]:_(s64), [[UV3:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[ANYEXT]] CHECK: $x0 = COPY [[UV]] CHECK: $x1 = COPY [[UV1]] CHECK: $x2 = COPY [[UV2]] CHECK: $x3 = COPY [[UV3]] CHECK: BL &__modti3 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallURem) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_UREM).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBURem32 = B.buildInstr(TargetOpcode::G_UREM, {S32}, {MIBTrunc, MIBTrunc}); auto MIBURem64 = B.buildInstr(TargetOpcode::G_UREM, {S64}, {Copies[0], Copies[0]}); auto MIBURem128 = B.buildInstr(TargetOpcode::G_UREM, {S128}, {MIBExt, MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBURem32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBURem64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBURem128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $w0 = COPY [[TRUNC]] CHECK: $w1 = COPY [[TRUNC]] CHECK: BL &__umodsi3 CHECK: $x0 = COPY [[COPY]] CHECK: $x1 = COPY [[COPY]] CHECK: BL &__umoddi3 CHECK: [[UV:%[0-9]+]]:_(s64), [[UV1:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[ANYEXT]] CHECK: [[UV2:%[0-9]+]]:_(s64), [[UV3:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[ANYEXT]] CHECK: $x0 = COPY [[UV]] CHECK: $x1 = COPY [[UV1]] CHECK: $x2 = COPY [[UV2]] CHECK: $x3 = COPY [[UV3]] CHECK: BL &__umodti3 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallCtlzZeroUndef) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF) .libcallFor({{s32, s32}, {s64, s64}, {s128, s128}}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBCtlz32 = B.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, {S32}, {MIBTrunc}); auto MIBCtlz64 = B.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, {S64}, {Copies[0]}); auto MIBCtlz128 = B.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBCtlz32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBCtlz64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBCtlz128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $w0 = COPY [[TRUNC]] CHECK: BL &__clzsi2 CHECK: $x0 = COPY [[COPY]] CHECK: BL &__clzdi2 CHECK: [[UV:%[0-9]+]]:_(s64), [[UV1:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[ANYEXT]] CHECK: $x0 = COPY [[UV]] CHECK: $x1 = COPY [[UV1]] CHECK: BL &__clzti2 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFAdd) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FADD).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBAdd32 = B.buildInstr(TargetOpcode::G_FADD, {S32}, {MIBTrunc, MIBTrunc}); auto MIBAdd64 = B.buildInstr(TargetOpcode::G_FADD, {S64}, {Copies[0], Copies[0]}); auto MIBAdd128 = B.buildInstr(TargetOpcode::G_FADD, {S128}, {MIBExt, MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBAdd32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBAdd64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBAdd128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: $s1 = COPY [[TRUNC]] CHECK: BL &__addsf3 CHECK: $d0 = COPY [[COPY]] CHECK: $d1 = COPY [[COPY]] CHECK: BL &__adddf3 CHECK: $q0 = COPY [[ANYEXT]] CHECK: $q1 = COPY [[ANYEXT]] CHECK: BL &__addtf3 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFSub) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FSUB).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBSub32 = B.buildInstr(TargetOpcode::G_FSUB, {S32}, {MIBTrunc, MIBTrunc}); auto MIBSub64 = B.buildInstr(TargetOpcode::G_FSUB, {S64}, {Copies[0], Copies[0]}); auto MIBSub128 = B.buildInstr(TargetOpcode::G_FSUB, {S128}, {MIBExt, MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSub32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSub64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSub128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: $s1 = COPY [[TRUNC]] CHECK: BL &__subsf3 CHECK: $d0 = COPY [[COPY]] CHECK: $d1 = COPY [[COPY]] CHECK: BL &__subdf3 CHECK: $q0 = COPY [[ANYEXT]] CHECK: $q1 = COPY [[ANYEXT]] CHECK: BL &__subtf3 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFMul) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FMUL).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBMul32 = B.buildInstr(TargetOpcode::G_FMUL, {S32}, {MIBTrunc, MIBTrunc}); auto MIBMul64 = B.buildInstr(TargetOpcode::G_FMUL, {S64}, {Copies[0], Copies[0]}); auto MIBMul128 = B.buildInstr(TargetOpcode::G_FMUL, {S128}, {MIBExt, MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMul32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMul64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMul128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: $s1 = COPY [[TRUNC]] CHECK: BL &__mulsf3 CHECK: $d0 = COPY [[COPY]] CHECK: $d1 = COPY [[COPY]] CHECK: BL &__muldf3 CHECK: $q0 = COPY [[ANYEXT]] CHECK: $q1 = COPY [[ANYEXT]] CHECK: BL &__multf3 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFDiv) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FDIV).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBDiv32 = B.buildInstr(TargetOpcode::G_FDIV, {S32}, {MIBTrunc, MIBTrunc}); auto MIBDiv64 = B.buildInstr(TargetOpcode::G_FDIV, {S64}, {Copies[0], Copies[0]}); auto MIBDiv128 = B.buildInstr(TargetOpcode::G_FDIV, {S128}, {MIBExt, MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBDiv32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBDiv64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBDiv128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: $s1 = COPY [[TRUNC]] CHECK: BL &__divsf3 CHECK: $d0 = COPY [[COPY]] CHECK: $d1 = COPY [[COPY]] CHECK: BL &__divdf3 CHECK: $q0 = COPY [[ANYEXT]] CHECK: $q1 = COPY [[ANYEXT]] CHECK: BL &__divtf3 )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFExp) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FEXP).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBExp32 = B.buildInstr(TargetOpcode::G_FEXP, {S32}, {MIBTrunc}); auto MIBExp64 = B.buildInstr(TargetOpcode::G_FEXP, {S64}, {Copies[0]}); auto MIBExp128 = B.buildInstr(TargetOpcode::G_FEXP, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBExp32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBExp64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBExp128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &expf CHECK: $d0 = COPY [[COPY]] CHECK: BL &exp CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &expl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFExp2) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FEXP2).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBExp232 = B.buildInstr(TargetOpcode::G_FEXP2, {S32}, {MIBTrunc}); auto MIBExp264 = B.buildInstr(TargetOpcode::G_FEXP2, {S64}, {Copies[0]}); auto MIBExp2128 = B.buildInstr(TargetOpcode::G_FEXP2, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBExp232)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBExp264)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBExp2128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &exp2f CHECK: $d0 = COPY [[COPY]] CHECK: BL &exp2 CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &exp2l )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFRem) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FREM).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBFRem32 = B.buildInstr(TargetOpcode::G_FREM, {S32}, {MIBTrunc}); auto MIBFRem64 = B.buildInstr(TargetOpcode::G_FREM, {S64}, {Copies[0]}); auto MIBFRem128 = B.buildInstr(TargetOpcode::G_FREM, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFRem32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFRem64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFRem128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &fmodf CHECK: $d0 = COPY [[COPY]] CHECK: BL &fmod CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &fmodl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFPow) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FPOW).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBPow32 = B.buildInstr(TargetOpcode::G_FPOW, {S32}, {MIBTrunc}); auto MIBPow64 = B.buildInstr(TargetOpcode::G_FPOW, {S64}, {Copies[0]}); auto MIBPow128 = B.buildInstr(TargetOpcode::G_FPOW, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBPow32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBPow64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBPow128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &powf CHECK: $d0 = COPY [[COPY]] CHECK: BL &pow CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &powl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFMa) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBMa32 = B.buildInstr(TargetOpcode::G_FMA, {S32}, {MIBTrunc, MIBTrunc}); auto MIBMa64 = B.buildInstr(TargetOpcode::G_FMA, {S64}, {Copies[0], Copies[0]}); auto MIBMa128 = B.buildInstr(TargetOpcode::G_FMA, {S128}, {MIBExt, MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMa32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMa64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMa128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &fmaf CHECK: $d0 = COPY [[COPY]] CHECK: BL &fma CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &fmal )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFCeil) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FCEIL).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBCeil32 = B.buildInstr(TargetOpcode::G_FCEIL, {S32}, {MIBTrunc}); auto MIBCeil64 = B.buildInstr(TargetOpcode::G_FCEIL, {S64}, {Copies[0]}); auto MIBCeil128 = B.buildInstr(TargetOpcode::G_FCEIL, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBCeil32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBCeil64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBCeil128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &ceilf CHECK: $d0 = COPY [[COPY]] CHECK: BL &ceil CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &ceill )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFFloor) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FFLOOR).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBFloor32 = B.buildInstr(TargetOpcode::G_FFLOOR, {S32}, {MIBTrunc}); auto MIBFloor64 = B.buildInstr(TargetOpcode::G_FFLOOR, {S64}, {Copies[0]}); auto MIBFloor128 = B.buildInstr(TargetOpcode::G_FFLOOR, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFloor32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFloor64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBFloor128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &floorf CHECK: $d0 = COPY [[COPY]] CHECK: BL &floor CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &floorl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFMinNum) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FMINNUM).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBMin32 = B.buildFMinNum(S32, MIBTrunc, MIBTrunc); auto MIBMin64 = B.buildFMinNum(S64, Copies[0], Copies[0]); auto MIBMin128 = B.buildFMinNum(S128, MIBExt, MIBExt); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMin32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMin64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMin128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: $s1 = COPY [[TRUNC]] CHECK: BL &fminf CHECK: $d0 = COPY [[COPY]] CHECK: $d1 = COPY [[COPY]] CHECK: BL &fmin CHECK: $q0 = COPY [[ANYEXT]] CHECK: $q1 = COPY [[ANYEXT]] CHECK: BL &fminl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFMaxNum) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FMAXNUM).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBMax32 = B.buildFMaxNum(S32, MIBTrunc, MIBTrunc); auto MIBMax64 = B.buildFMaxNum(S64, Copies[0], Copies[0]); auto MIBMax128 = B.buildFMaxNum(S128, MIBExt, MIBExt); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMax32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMax64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBMax128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: $s1 = COPY [[TRUNC]] CHECK: BL &fmaxf CHECK: $d0 = COPY [[COPY]] CHECK: $d1 = COPY [[COPY]] CHECK: BL &fmax CHECK: $q0 = COPY [[ANYEXT]] CHECK: $q1 = COPY [[ANYEXT]] CHECK: BL &fmaxl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFSqrt) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FSQRT).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBSqrt32 = B.buildInstr(TargetOpcode::G_FSQRT, {S32}, {MIBTrunc}); auto MIBSqrt64 = B.buildInstr(TargetOpcode::G_FSQRT, {S64}, {Copies[0]}); auto MIBSqrt128 = B.buildInstr(TargetOpcode::G_FSQRT, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSqrt32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSqrt64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBSqrt128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &sqrtf CHECK: $d0 = COPY [[COPY]] CHECK: BL &sqrt CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &sqrtl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFRint) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FRINT).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBRint32 = B.buildInstr(TargetOpcode::G_FRINT, {S32}, {MIBTrunc}); auto MIBRint64 = B.buildInstr(TargetOpcode::G_FRINT, {S64}, {Copies[0]}); auto MIBRint128 = B.buildInstr(TargetOpcode::G_FRINT, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBRint32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBRint64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBRint128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &rintf CHECK: $d0 = COPY [[COPY]] CHECK: BL &rint CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &rintl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LibcallFNearbyInt) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_FNEARBYINT).libcallFor({s32, s64, s128}); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; auto MIBTrunc = B.buildTrunc(S32, Copies[0]); auto MIBExt = B.buildAnyExt(S128, Copies[0]); auto MIBNearbyInt32 = B.buildInstr(TargetOpcode::G_FNEARBYINT, {S32}, {MIBTrunc}); auto MIBNearbyInt64 = B.buildInstr(TargetOpcode::G_FNEARBYINT, {S64}, {Copies[0]}); auto MIBNearbyInt128 = B.buildInstr(TargetOpcode::G_FNEARBYINT, {S128}, {MIBExt}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBNearbyInt32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBNearbyInt64)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.libcall(*MIBNearbyInt128)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT CHECK: $s0 = COPY [[TRUNC]] CHECK: BL &nearbyintf CHECK: $d0 = COPY [[COPY]] CHECK: BL &nearbyint CHECK: $q0 = COPY [[ANYEXT]] CHECK: BL &nearbyintl )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, NarrowScalarExtract) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}}); getActionDefinitionsBuilder(G_EXTRACT).legalForTypeWithAnyImm({{s16, s32}}); }); LLT S16{LLT::scalar(16)}; LLT S32{LLT::scalar(32)}; auto MIBExtractS32 = B.buildExtract(S32, Copies[1], 32); auto MIBExtractS16 = B.buildExtract(S16, Copies[1], 0); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*MIBExtractS32, 1, S32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*MIBExtractS16, 1, S32)); const auto *CheckStr = R"( CHECK: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY [[UV1]] CHECK: [[UV3:%[0-9]+]]:_(s32), [[UV4:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES CHECK: [[EXTR:%[0-9]+]]:_(s16) = G_EXTRACT [[UV3]]:_(s32), 0 CHECK: [[COPY:%[0-9]+]]:_(s16) = COPY [[EXTR]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, LowerInsert) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, { getActionDefinitionsBuilder(G_INSERT).lower(); }); LLT S32{LLT::scalar(32)}; LLT S64{LLT::scalar(64)}; LLT P0{LLT::pointer(0, 64)}; LLT P1{LLT::pointer(1, 32)}; LLT V2S32{LLT::vector(2, 32)}; auto TruncS32 = B.buildTrunc(S32, Copies[0]); auto IntToPtrP0 = B.buildIntToPtr(P0, Copies[0]); auto IntToPtrP1 = B.buildIntToPtr(P1, TruncS32); auto BitcastV2S32 = B.buildBitcast(V2S32, Copies[0]); auto InsertS64S32 = B.buildInsert(S64, Copies[0], TruncS32, 0); auto InsertS64P1 = B.buildInsert(S64, Copies[0], IntToPtrP1, 8); auto InsertP0S32 = B.buildInsert(P0, IntToPtrP0, TruncS32, 16); auto InsertP0P1 = B.buildInsert(P0, IntToPtrP0, IntToPtrP1, 4); auto InsertV2S32S32 = B.buildInsert(V2S32, BitcastV2S32, TruncS32, 32); auto InsertV2S32P1 = B.buildInsert(V2S32, BitcastV2S32, IntToPtrP1, 0); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*InsertS64S32, 0, LLT{})); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*InsertS64P1, 0, LLT{})); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*InsertP0S32, 0, LLT{})); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*InsertP0P1, 0, LLT{})); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*InsertV2S32S32, 0, LLT{})); EXPECT_EQ(LegalizerHelper::LegalizeResult::UnableToLegalize, Helper.lower(*InsertV2S32P1, 0, LLT{})); const auto *CheckStr = R"( CHECK: [[S64:%[0-9]+]]:_(s64) = COPY CHECK: [[S32:%[0-9]+]]:_(s32) = G_TRUNC [[S64]] CHECK: [[P0:%[0-9]+]]:_(p0) = G_INTTOPTR [[S64]] CHECK: [[P1:%[0-9]+]]:_(p1) = G_INTTOPTR [[S32]] CHECK: [[V2S32:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[S64]] CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[S32]] CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[S64]]:_, [[C]]:_ CHECK: [[OR:%[0-9]+]]:_(s64) = G_OR [[AND]]:_, [[ZEXT]]:_ CHECK: [[PTRTOINT:%[0-9]+]]:_(s32) = G_PTRTOINT [[P1]] CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[PTRTOINT]] CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[ZEXT]]:_, [[C]]:_(s64) CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[S64]]:_, [[C]]:_ CHECK: [[OR:%[0-9]+]]:_(s64) = G_OR [[AND]]:_, [[SHL]]:_ CHECK: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[P0]] CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[S32]] CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[ZEXT]]:_, [[C]]:_(s64) CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[PTRTOINT]]:_, [[C]]:_ CHECK: [[OR:%[0-9]+]]:_(s64) = G_OR [[AND]]:_, [[SHL]]:_ CHECK: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[OR]] CHECK: [[PTRTOINT:%[0-9]+]]:_(s64) = G_PTRTOINT [[P0]] CHECK: [[PTRTOINT1:%[0-9]+]]:_(s32) = G_PTRTOINT [[P1]] CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[PTRTOINT1]] CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[ZEXT]]:_, [[C]]:_(s64) CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[PTRTOINT]]:_, [[C]]:_ CHECK: [[OR:%[0-9]+]]:_(s64) = G_OR [[AND]]:_, [[SHL]]:_ CHECK: [[INTTOPTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[OR]] CHECK: [[BITCAST:%[0-9]+]]:_(s64) = G_BITCAST [[V2S32]] CHECK: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT [[S32]] CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[SHL:%[0-9]+]]:_(s64) = G_SHL [[ZEXT]]:_, [[C]]:_(s64) CHECK: [[C:%[0-9]+]]:_(s64) = G_CONSTANT CHECK: [[AND:%[0-9]+]]:_(s64) = G_AND [[BITCAST]]:_, [[C]]:_ CHECK: [[OR:%[0-9]+]]:_(s64) = G_OR [[AND]]:_, [[SHL]]:_ CHECK: [[BITCAST:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[OR]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test lowering of G_FFLOOR TEST_F(AArch64GISelMITest, LowerFFloor) { setUp(); if (!TM) return; // Declare your legalization info DefineLegalizerInfo(A, {}); // Build Instr auto Floor = B.buildFFloor(LLT::scalar(64), Copies[0], MachineInstr::MIFlag::FmNoInfs); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*Floor, 0, LLT())); auto CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s64) = ninf G_INTRINSIC_TRUNC [[COPY]] CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_FCONSTANT double 0.000000e+00 CHECK: [[CMP0:%[0-9]+]]:_(s1) = ninf G_FCMP floatpred(olt), [[COPY]]:_(s64), [[ZERO]]:_ CHECK: [[CMP1:%[0-9]+]]:_(s1) = ninf G_FCMP floatpred(one), [[COPY]]:_(s64), [[TRUNC]]:_ CHECK: [[AND:%[0-9]+]]:_(s1) = G_AND [[CMP0]]:_, [[CMP1]]:_ CHECK: [[ITOFP:%[0-9]+]]:_(s64) = G_SITOFP [[AND]] = ninf G_FADD [[TRUNC]]:_, [[ITOFP]]:_ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test lowering of G_BSWAP TEST_F(AArch64GISelMITest, LowerBSWAP) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); // Make sure vector lowering doesn't assert. auto Cast = B.buildBitcast(LLT::vector(2, 32), Copies[0]); auto BSwap = B.buildBSwap(LLT::vector(2, 32), Cast); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.lower(*BSwap, 0, LLT())); auto CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[VEC:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[COPY]] CHECK: [[K24:%[0-9]+]]:_(s32) = G_CONSTANT i32 24 CHECK: [[SPLAT24:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[K24]]:_(s32), [[K24]]:_(s32) CHECK: [[SHL0:%[0-9]+]]:_(<2 x s32>) = G_SHL [[VEC]]:_, [[SPLAT24]] CHECK: [[SHR0:%[0-9]+]]:_(<2 x s32>) = G_LSHR [[VEC]]:_, [[SPLAT24]] CHECK: [[OR0:%[0-9]+]]:_(<2 x s32>) = G_OR [[SHR0]]:_, [[SHL0]]:_ CHECK: [[KMASK:%[0-9]+]]:_(s32) = G_CONSTANT i32 65280 CHECK: [[SPLATMASK:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[KMASK]]:_(s32), [[KMASK]]:_(s32) CHECK: [[K8:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 CHECK: [[SPLAT8:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[K8]]:_(s32), [[K8]]:_(s32) CHECK: [[AND0:%[0-9]+]]:_(<2 x s32>) = G_AND [[VEC]]:_, [[SPLATMASK]]:_ CHECK: [[SHL1:%[0-9]+]]:_(<2 x s32>) = G_SHL [[AND0]]:_, [[SPLAT8]] CHECK: [[OR1:%[0-9]+]]:_(<2 x s32>) = G_OR [[OR0]]:_, [[SHL1]]:_ CHECK: [[SHR1:%[0-9]+]]:_(<2 x s32>) = G_LSHR [[VEC]]:_, [[SPLAT8]] CHECK: [[AND1:%[0-9]+]]:_(<2 x s32>) = G_AND [[SHR1]]:_, [[SPLATMASK]]:_ CHECK: [[BSWAP:%[0-9]+]]:_(<2 x s32>) = G_OR [[OR1]]:_, [[AND1]]:_ )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test widening of G_UNMERGE_VALUES TEST_F(AArch64GISelMITest, WidenUnmerge) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); // Check that widening G_UNMERGE_VALUES to a larger type than the source type // works as expected LLT P0{LLT::pointer(0, 64)}; LLT S32{LLT::scalar(32)}; LLT S96{LLT::scalar(96)}; auto IntToPtr = B.buildIntToPtr(P0, Copies[0]); auto UnmergePtr = B.buildUnmerge(S32, IntToPtr); auto UnmergeScalar = B.buildUnmerge(S32, Copies[0]); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*UnmergePtr, 0, S96)); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*UnmergeScalar, 0, S96)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[PTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[COPY]] CHECK: [[INT:%[0-9]+]]:_(s64) = G_PTRTOINT [[PTR]] CHECK: [[ANYEXT:%[0-9]+]]:_(s96) = G_ANYEXT [[INT]] CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[ANYEXT]] CHECK: [[C:%[0-9]+]]:_(s96) = G_CONSTANT i96 32 CHECK: [[LSHR:%[0-9]+]]:_(s96) = G_LSHR [[ANYEXT]]:_, [[C]] CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[LSHR]] CHECK: [[ANYEXT:%[0-9]+]]:_(s96) = G_ANYEXT [[COPY]] CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[ANYEXT]] CHECK: [[C:%[0-9]+]]:_(s96) = G_CONSTANT i96 32 CHECK: [[LSHR:%[0-9]+]]:_(s96) = G_LSHR [[ANYEXT]]:_, [[C]] CHECK: [[TRUNC1:%[0-9]+]]:_(s32) = G_TRUNC [[LSHR]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, BitcastLoad) { setUp(); if (!TM) return; LLT P0 = LLT::pointer(0, 64); LLT S32 = LLT::scalar(32); LLT V4S8 = LLT::vector(4, 8); auto Ptr = B.buildUndef(P0); DefineLegalizerInfo(A, {}); MachineMemOperand *MMO = B.getMF().getMachineMemOperand( MachinePointerInfo(), MachineMemOperand::MOLoad, 4, Align(4)); auto Load = B.buildLoad(V4S8, Ptr, *MMO); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; B.setInsertPt(*EntryMBB, Load->getIterator()); LegalizerHelper Helper(*MF, Info, Observer, B); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.bitcast(*Load, 0, S32)); auto CheckStr = R"( CHECK: [[PTR:%[0-9]+]]:_(p0) = G_IMPLICIT_DEF CHECK: [[LOAD:%[0-9]+]]:_(s32) = G_LOAD CHECK: [[CAST:%[0-9]+]]:_(<4 x s8>) = G_BITCAST [[LOAD]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, BitcastStore) { setUp(); if (!TM) return; LLT P0 = LLT::pointer(0, 64); LLT S32 = LLT::scalar(32); LLT V4S8 = LLT::vector(4, 8); auto Ptr = B.buildUndef(P0); DefineLegalizerInfo(A, {}); MachineMemOperand *MMO = B.getMF().getMachineMemOperand( MachinePointerInfo(), MachineMemOperand::MOStore, 4, Align(4)); auto Val = B.buildUndef(V4S8); auto Store = B.buildStore(Val, Ptr, *MMO); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); B.setInsertPt(*EntryMBB, Store->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.bitcast(*Store, 0, S32)); auto CheckStr = R"( CHECK: [[VAL:%[0-9]+]]:_(<4 x s8>) = G_IMPLICIT_DEF CHECK: [[CAST:%[0-9]+]]:_(s32) = G_BITCAST [[VAL]] CHECK: G_STORE [[CAST]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, BitcastSelect) { setUp(); if (!TM) return; LLT S1 = LLT::scalar(1); LLT S32 = LLT::scalar(32); LLT V4S8 = LLT::vector(4, 8); DefineLegalizerInfo(A, {}); auto Cond = B.buildUndef(S1); auto Val0 = B.buildConstant(V4S8, 123); auto Val1 = B.buildConstant(V4S8, 99); auto Select = B.buildSelect(V4S8, Cond, Val0, Val1); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); B.setInsertPt(*EntryMBB, Select->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.bitcast(*Select, 0, S32)); auto CheckStr = R"( CHECK: [[VAL0:%[0-9]+]]:_(<4 x s8>) = G_BUILD_VECTOR CHECK: [[VAL1:%[0-9]+]]:_(<4 x s8>) = G_BUILD_VECTOR CHECK: [[CAST0:%[0-9]+]]:_(s32) = G_BITCAST [[VAL0]] CHECK: [[CAST1:%[0-9]+]]:_(s32) = G_BITCAST [[VAL1]] CHECK: [[SELECT:%[0-9]+]]:_(s32) = G_SELECT %{{[0-9]+}}:_(s1), [[CAST0]]:_, [[CAST1]]:_ CHECK: [[CAST2:%[0-9]+]]:_(<4 x s8>) = G_BITCAST [[SELECT]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; // Doesn't make sense auto VCond = B.buildUndef(LLT::vector(4, 1)); auto VSelect = B.buildSelect(V4S8, VCond, Val0, Val1); B.setInsertPt(*EntryMBB, VSelect->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::UnableToLegalize, Helper.bitcast(*VSelect, 0, S32)); EXPECT_EQ(LegalizerHelper::LegalizeResult::UnableToLegalize, Helper.bitcast(*VSelect, 1, LLT::scalar(4))); } TEST_F(AArch64GISelMITest, BitcastBitOps) { setUp(); if (!TM) return; LLT S32 = LLT::scalar(32); LLT V4S8 = LLT::vector(4, 8); DefineLegalizerInfo(A, {}); auto Val0 = B.buildConstant(V4S8, 123); auto Val1 = B.buildConstant(V4S8, 99); auto And = B.buildAnd(V4S8, Val0, Val1); auto Or = B.buildOr(V4S8, Val0, Val1); auto Xor = B.buildXor(V4S8, Val0, Val1); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); B.setInsertPt(*EntryMBB, And->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.bitcast(*And, 0, S32)); B.setInsertPt(*EntryMBB, Or->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.bitcast(*Or, 0, S32)); B.setInsertPt(*EntryMBB, Xor->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.bitcast(*Xor, 0, S32)); auto CheckStr = R"( CHECK: [[VAL0:%[0-9]+]]:_(<4 x s8>) = G_BUILD_VECTOR CHECK: [[VAL1:%[0-9]+]]:_(<4 x s8>) = G_BUILD_VECTOR CHECK: [[CAST0:%[0-9]+]]:_(s32) = G_BITCAST [[VAL0]] CHECK: [[CAST1:%[0-9]+]]:_(s32) = G_BITCAST [[VAL1]] CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[CAST0]]:_, [[CAST1]]:_ CHECK: [[CAST_AND:%[0-9]+]]:_(<4 x s8>) = G_BITCAST [[AND]] CHECK: [[CAST2:%[0-9]+]]:_(s32) = G_BITCAST [[VAL0]] CHECK: [[CAST3:%[0-9]+]]:_(s32) = G_BITCAST [[VAL1]] CHECK: [[OR:%[0-9]+]]:_(s32) = G_OR [[CAST2]]:_, [[CAST3]]:_ CHECK: [[CAST_OR:%[0-9]+]]:_(<4 x s8>) = G_BITCAST [[OR]] CHECK: [[CAST4:%[0-9]+]]:_(s32) = G_BITCAST [[VAL0]] CHECK: [[CAST5:%[0-9]+]]:_(s32) = G_BITCAST [[VAL1]] CHECK: [[XOR:%[0-9]+]]:_(s32) = G_XOR [[CAST4]]:_, [[CAST5]]:_ CHECK: [[CAST_XOR:%[0-9]+]]:_(<4 x s8>) = G_BITCAST [[XOR]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, CreateLibcall) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LLVMContext &Ctx = MF->getFunction().getContext(); auto *RetTy = Type::getVoidTy(Ctx); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, createLibcall(B, "abort", {{}, RetTy}, {}, CallingConv::C)); auto CheckStr = R"( CHECK: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp CHECK: BL &abort CHECK: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test narrowing of G_IMPLICIT_DEF TEST_F(AArch64GISelMITest, NarrowImplicitDef) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); // Make sure that G_IMPLICIT_DEF can be narrowed if the original size is not a // multiple of narrow size LLT S32{LLT::scalar(32)}; LLT S48{LLT::scalar(48)}; LLT S64{LLT::scalar(64)}; LLT V2S64{{LLT::vector(2, 64)}}; auto Implicit1 = B.buildUndef(S64); auto Implicit2 = B.buildUndef(S64); auto Implicit3 = B.buildUndef(V2S64); auto Implicit4 = B.buildUndef(V2S64); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization B.setInsertPt(*EntryMBB, Implicit1->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*Implicit1, 0, S48)); B.setInsertPt(*EntryMBB, Implicit2->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*Implicit2, 0, S32)); B.setInsertPt(*EntryMBB, Implicit3->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*Implicit3, 0, S48)); B.setInsertPt(*EntryMBB, Implicit4->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*Implicit4, 0, S32)); const auto *CheckStr = R"( CHECK: [[DEF:%[0-9]+]]:_(s48) = G_IMPLICIT_DEF CHECK: [[ANYEXT:%[0-9]+]]:_(s64) = G_ANYEXT [[DEF]] CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[DEF1:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[DEF]]:_(s32), [[DEF1]] CHECK: [[DEF:%[0-9]+]]:_(<2 x s48>) = G_IMPLICIT_DEF CHECK: [[ANYEXT:%[0-9]+]]:_(<2 x s64>) = G_ANYEXT [[DEF]] CHECK: [[DEF:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[DEF1:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[DEF2:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[DEF3:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[BV:%[0-9]+]]:_(<2 x s64>) = G_BUILD_VECTOR [[DEF]]:_(s32), [[DEF1]]:_(s32), [[DEF2]]:_(s32), [[DEF3]]:_(s32) )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test widening of G_FREEZE TEST_F(AArch64GISelMITest, WidenFreeze) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); // Make sure that G_FREEZE is widened with anyext LLT S64{LLT::scalar(64)}; LLT S128{LLT::scalar(128)}; LLT V2S32{LLT::vector(2, 32)}; LLT V2S64{LLT::vector(2, 64)}; auto Vector = B.buildBitcast(V2S32, Copies[0]); auto FreezeScalar = B.buildInstr(TargetOpcode::G_FREEZE, {S64}, {Copies[0]}); auto FreezeVector = B.buildInstr(TargetOpcode::G_FREEZE, {V2S32}, {Vector}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization B.setInsertPt(*EntryMBB, FreezeScalar->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*FreezeScalar, 0, S128)); B.setInsertPt(*EntryMBB, FreezeVector->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*FreezeVector, 0, V2S64)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[BITCAST:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[COPY]] CHECK: [[ANYEXT:%[0-9]+]]:_(s128) = G_ANYEXT [[COPY]] CHECK: [[FREEZE:%[0-9]+]]:_(s128) = G_FREEZE [[ANYEXT]] CHECK: [[TRUNC:%[0-9]+]]:_(s64) = G_TRUNC [[FREEZE]] CHECK: [[ANYEXT1:%[0-9]+]]:_(<2 x s64>) = G_ANYEXT [[BITCAST]] CHECK: [[FREEZE1:%[0-9]+]]:_(<2 x s64>) = G_FREEZE [[ANYEXT1]] CHECK: [[TRUNC1:%[0-9]+]]:_(<2 x s32>) = G_TRUNC [[FREEZE1]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test narrowing of G_FREEZE TEST_F(AArch64GISelMITest, NarrowFreeze) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); // Make sure that G_FREEZE is narrowed using unmerge/extract LLT S16{LLT::scalar(16)}; LLT S32{LLT::scalar(32)}; LLT S33{LLT::scalar(33)}; LLT S64{LLT::scalar(64)}; LLT V2S16{LLT::vector(2, 16)}; LLT V2S32{LLT::vector(2, 32)}; auto Trunc = B.buildTrunc(S33, {Copies[0]}); auto Vector = B.buildBitcast(V2S32, Copies[0]); auto FreezeScalar = B.buildInstr(TargetOpcode::G_FREEZE, {S64}, {Copies[0]}); auto FreezeOdd = B.buildInstr(TargetOpcode::G_FREEZE, {S33}, {Trunc}); auto FreezeVector = B.buildInstr(TargetOpcode::G_FREEZE, {V2S32}, {Vector}); auto FreezeVector1 = B.buildInstr(TargetOpcode::G_FREEZE, {V2S32}, {Vector}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization B.setInsertPt(*EntryMBB, FreezeScalar->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*FreezeScalar, 0, S32)); B.setInsertPt(*EntryMBB, FreezeOdd->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*FreezeOdd, 0, S32)); B.setInsertPt(*EntryMBB, FreezeVector->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*FreezeVector, 0, V2S16)); B.setInsertPt(*EntryMBB, FreezeVector1->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.narrowScalar(*FreezeVector1, 0, S16)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[TRUNC:%[0-9]+]]:_(s33) = G_TRUNC [[COPY]] CHECK: [[BITCAST:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[COPY]] CHECK: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[COPY]] CHECK: [[FREEZE:%[0-9]+]]:_(s32) = G_FREEZE [[UV]] CHECK: [[FREEZE1:%[0-9]+]]:_(s32) = G_FREEZE [[UV1]] CHECK: [[MV:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[FREEZE]]:_(s32), [[FREEZE1]] CHECK: (s1) = G_UNMERGE_VALUES [[TRUNC]]:_(s33) CHECK: [[UNDEF:%[0-9]+]]:_(s1) = G_IMPLICIT_DEF CHECK: [[MV1:%[0-9]+]]:_(s32) = G_MERGE_VALUES CHECK: [[MV2:%[0-9]+]]:_(s32) = G_MERGE_VALUES CHECK: [[UNDEF1:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[FREEZE2:%[0-9]+]]:_(s32) = G_FREEZE [[MV1]] CHECK: [[FREEZE3:%[0-9]+]]:_(s32) = G_FREEZE [[MV2]] CHECK: [[UNDEF2:%[0-9]+]]:_(s32) = G_IMPLICIT_DEF CHECK: [[MV3:%[0-9]+]]:_(s1056) = G_MERGE_VALUES [[FREEZE2]]:_(s32), [[FREEZE3]]:_(s32), [[UNDEF2]] CHECK: [[TRUNC1:%[0-9]+]]:_(s33) = G_TRUNC [[MV3]] CHECK: [[BITCAST1:%[0-9]+]]:_(s64) = G_BITCAST [[BITCAST]] CHECK: [[UV2:%[0-9]+]]:_(s32), [[UV3:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[BITCAST1]] CHECK: [[FREEZE4:%[0-9]+]]:_(s32) = G_FREEZE [[UV2]] CHECK: [[FREEZE5:%[0-9]+]]:_(s32) = G_FREEZE [[UV3]] CHECK: [[MV4:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[FREEZE4]]:_(s32), [[FREEZE5]]:_(s32) CHECK: [[BITCAST2:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[MV4]] CHECK: [[BITCAST3:%[0-9]+]]:_(s64) = G_BITCAST [[BITCAST]] CHECK: [[UV4:%[0-9]+]]:_(s16), [[UV5:%[0-9]+]]:_(s16), [[UV6:%[0-9]+]]:_(s16), [[UV7:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[BITCAST3]] CHECK: [[FREEZE6:%[0-9]+]]:_(s16) = G_FREEZE [[UV4]] CHECK: [[FREEZE7:%[0-9]+]]:_(s16) = G_FREEZE [[UV5]] CHECK: [[FREEZE8:%[0-9]+]]:_(s16) = G_FREEZE [[UV6]] CHECK: [[FREEZE9:%[0-9]+]]:_(s16) = G_FREEZE [[UV7]] CHECK: [[MV5:%[0-9]+]]:_(s64) = G_MERGE_VALUES [[FREEZE6]]:_(s16), [[FREEZE7]]:_(s16), [[FREEZE8]]:_(s16), [[FREEZE9]] CHECK: [[BITCAST3:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[MV5]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test fewer elements of G_FREEZE TEST_F(AArch64GISelMITest, FewerElementsFreeze) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); LLT S32{LLT::scalar(32)}; LLT V2S16{LLT::vector(2, 16)}; LLT V2S32{LLT::vector(2, 32)}; LLT V4S16{LLT::vector(4, 16)}; auto Vector1 = B.buildBitcast(V2S32, Copies[0]); auto Vector2 = B.buildBitcast(V4S16, Copies[0]); auto FreezeVector1 = B.buildInstr(TargetOpcode::G_FREEZE, {V2S32}, {Vector1}); auto FreezeVector2 = B.buildInstr(TargetOpcode::G_FREEZE, {V4S16}, {Vector2}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization B.setInsertPt(*EntryMBB, FreezeVector1->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.fewerElementsVector(*FreezeVector1, 0, S32)); B.setInsertPt(*EntryMBB, FreezeVector2->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.fewerElementsVector(*FreezeVector2, 0, V2S16)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[BITCAST:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[COPY]] CHECK: [[BITCAST1:%[0-9]+]]:_(<4 x s16>) = G_BITCAST [[COPY]] CHECK: [[UV:%[0-9]+]]:_(s32), [[UV1:%[0-9]+]]:_(s32) = G_UNMERGE_VALUES [[BITCAST]] CHECK: [[FREEZE:%[0-9]+]]:_(s32) = G_FREEZE [[UV]] CHECK: [[FREEZE1:%[0-9]+]]:_(s32) = G_FREEZE [[UV1]] CHECK: [[MV:%[0-9]+]]:_(<2 x s32>) = G_BUILD_VECTOR [[FREEZE]]:_(s32), [[FREEZE1]] CHECK: [[UV:%[0-9]+]]:_(<2 x s16>), [[UV1:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[BITCAST1]] CHECK: [[FREEZE2:%[0-9]+]]:_(<2 x s16>) = G_FREEZE [[UV]] CHECK: [[FREEZE3:%[0-9]+]]:_(<2 x s16>) = G_FREEZE [[UV1]] CHECK: [[MV:%[0-9]+]]:_(<4 x s16>) = G_CONCAT_VECTORS [[FREEZE2]]:_(<2 x s16>), [[FREEZE3]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test more elements of G_FREEZE TEST_F(AArch64GISelMITest, MoreElementsFreeze) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); LLT V2S32{LLT::vector(2, 32)}; LLT V4S32{LLT::vector(4, 32)}; auto Vector1 = B.buildBitcast(V2S32, Copies[0]); auto FreezeVector1 = B.buildInstr(TargetOpcode::G_FREEZE, {V2S32}, {Vector1}); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization B.setInsertPt(*EntryMBB, FreezeVector1->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.moreElementsVector(*FreezeVector1, 0, V4S32)); const auto *CheckStr = R"( CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY CHECK: [[BITCAST:%[0-9]+]]:_(<2 x s32>) = G_BITCAST [[COPY]] CHECK: [[UNDEF:%[0-9]+]]:_(<2 x s32>) = G_IMPLICIT_DEF CHECK: [[CV:%[0-9]+]]:_(<4 x s32>) = G_CONCAT_VECTORS [[BITCAST]]:_(<2 x s32>), [[UNDEF]] CHECK: [[FREEZE:%[0-9]+]]:_(<4 x s32>) = G_FREEZE [[CV]] CHECK: [[EXTR0:%[0-9]+]]:_(<2 x s32>), [[EXTR1:%[0-9]+]]:_(<2 x s32>) = G_UNMERGE_VALUES [[FREEZE]]:_(<4 x s32>) )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test fewer elements of G_INSERT_VECTOR_ELEMENT TEST_F(AArch64GISelMITest, FewerElementsInsertVectorElt) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); LLT P0{LLT::pointer(0, 64)}; LLT S64{LLT::scalar(64)}; LLT S16{LLT::scalar(16)}; LLT V2S16{LLT::vector(2, 16)}; LLT V3S16{LLT::vector(3, 16)}; LLT V8S16{LLT::vector(8, 16)}; auto Ptr0 = B.buildIntToPtr(P0, Copies[0]); auto VectorV8 = B.buildLoad(V8S16, Ptr0, MachinePointerInfo(), Align(8)); auto Value = B.buildTrunc(S16, Copies[1]); auto Seven = B.buildConstant(S64, 7); auto InsertV8Constant7_0 = B.buildInsertVectorElement(V8S16, VectorV8, Value, Seven); auto InsertV8Constant7_1 = B.buildInsertVectorElement(V8S16, VectorV8, Value, Seven); B.buildStore(InsertV8Constant7_0, Ptr0, MachinePointerInfo(), Align(8), MachineMemOperand::MOVolatile); B.buildStore(InsertV8Constant7_1, Ptr0, MachinePointerInfo(), Align(8), MachineMemOperand::MOVolatile); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization B.setInsertPt(*EntryMBB, InsertV8Constant7_0->getIterator()); // This should index the high element of the 4th piece of an unmerge. EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.fewerElementsVector(*InsertV8Constant7_0, 0, V2S16)); // This case requires extracting an intermediate vector type into the target // v4s16. B.setInsertPt(*EntryMBB, InsertV8Constant7_1->getIterator()); EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.fewerElementsVector(*InsertV8Constant7_1, 0, V3S16)); const auto *CheckStr = R"( CHECK: [[COPY0:%[0-9]+]]:_(s64) = COPY CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY CHECK: [[PTR0:%[0-9]+]]:_(p0) = G_INTTOPTR [[COPY0]] CHECK: [[VEC8:%[0-9]+]]:_(<8 x s16>) = G_LOAD [[PTR0]]:_(p0) :: (load 16, align 8) CHECK: [[INSERT_VAL:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]] CHECK: [[UNMERGE0:%[0-9]+]]:_(<2 x s16>), [[UNMERGE1:%[0-9]+]]:_(<2 x s16>), [[UNMERGE2:%[0-9]+]]:_(<2 x s16>), [[UNMERGE3:%[0-9]+]]:_(<2 x s16>) = G_UNMERGE_VALUES [[VEC8]] CHECK: [[ONE:%[0-9]+]]:_(s64) = G_CONSTANT i64 1 CHECK: [[SUB_INSERT_7:%[0-9]+]]:_(<2 x s16>) = G_INSERT_VECTOR_ELT [[UNMERGE3]]:_, [[INSERT_VAL]]:_(s16), [[ONE]] CHECK: [[INSERT_V8_7_0:%[0-9]+]]:_(<8 x s16>) = G_CONCAT_VECTORS [[UNMERGE0]]:_(<2 x s16>), [[UNMERGE1]]:_(<2 x s16>), [[UNMERGE2]]:_(<2 x s16>), [[SUB_INSERT_7]]:_(<2 x s16>) CHECK: [[UNMERGE1_0:%[0-9]+]]:_(s16), [[UNMERGE1_1:%[0-9]+]]:_(s16), [[UNMERGE1_2:%[0-9]+]]:_(s16), [[UNMERGE1_3:%[0-9]+]]:_(s16), [[UNMERGE1_4:%[0-9]+]]:_(s16), [[UNMERGE1_5:%[0-9]+]]:_(s16), [[UNMERGE1_6:%[0-9]+]]:_(s16), [[UNMERGE1_7:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[VEC8]]:_(<8 x s16>) CHECK: [[IMPDEF_S16:%[0-9]+]]:_(s16) = G_IMPLICIT_DEF CHECK: [[BUILD0:%[0-9]+]]:_(<3 x s16>) = G_BUILD_VECTOR [[UNMERGE1_0]]:_(s16), [[UNMERGE1_1]]:_(s16), [[UNMERGE1_2]]:_(s16) CHECK: [[BUILD1:%[0-9]+]]:_(<3 x s16>) = G_BUILD_VECTOR [[UNMERGE1_3]]:_(s16), [[UNMERGE1_4]]:_(s16), [[UNMERGE1_5]]:_(s16) CHECK: [[BUILD2:%[0-9]+]]:_(<3 x s16>) = G_BUILD_VECTOR [[UNMERGE1_6]]:_(s16), [[UNMERGE1_7]]:_(s16), [[IMPDEF_S16]]:_(s16) CHECK: [[IMPDEF_V3S16:%[0-9]+]]:_(<3 x s16>) = G_IMPLICIT_DEF CHECK: [[ONE_1:%[0-9]+]]:_(s64) = G_CONSTANT i64 1 CHECK: [[SUB_INSERT_7_V3S16:%[0-9]+]]:_(<3 x s16>) = G_INSERT_VECTOR_ELT [[BUILD2]]:_, [[INSERT_VAL]]:_(s16), [[ONE_1]] CHECK: [[WIDE_CONCAT_DEAD:%[0-9]+]]:_(<24 x s16>) = G_CONCAT_VECTORS [[BUILD0]]:_(<3 x s16>), [[BUILD1]]:_(<3 x s16>), [[SUB_INSERT_7_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>) CHECK: [[WIDE_CONCAT:%[0-9]+]]:_(<24 x s16>) = G_CONCAT_VECTORS [[BUILD0]]:_(<3 x s16>), [[BUILD1]]:_(<3 x s16>), [[SUB_INSERT_7_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>), [[IMPDEF_V3S16]]:_(<3 x s16>) CHECK: [[INSERT_V8_7_1:%[0-9]+]]:_(<8 x s16>), %{{[0-9]+}}:_(<8 x s16>), %{{[0-9]+}}:_(<8 x s16>) = G_UNMERGE_VALUES [[WIDE_CONCAT]]:_(<24 x s16>) CHECK: G_STORE [[INSERT_V8_7_0]] CHECK: G_STORE [[INSERT_V8_7_1]] )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // Test widen scalar of G_UNMERGE_VALUES TEST_F(AArch64GISelMITest, widenScalarUnmerge) { setUp(); if (!TM) return; DefineLegalizerInfo(A, {}); LLT S96{LLT::scalar(96)}; LLT S64{LLT::scalar(64)}; LLT S48{LLT::scalar(48)}; auto Src = B.buildAnyExt(S96, Copies[0]); auto Unmerge = B.buildUnmerge(S48, Src); AInfo Info(MF->getSubtarget()); DummyGISelObserver Observer; LegalizerHelper Helper(*MF, Info, Observer, B); // Perform Legalization B.setInsertPt(*EntryMBB, Unmerge->getIterator()); // This should create unmerges to a GCD type (S16), then remerge to S48 EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, Helper.widenScalar(*Unmerge, 0, S64)); const auto *CheckStr = R"( CHECK: [[COPY0:%[0-9]+]]:_(s64) = COPY CHECK: [[COPY1:%[0-9]+]]:_(s64) = COPY CHECK: [[COPY2:%[0-9]+]]:_(s64) = COPY CHECK: [[ANYEXT:%[0-9]+]]:_(s96) = G_ANYEXT [[COPY0]] CHECK: [[ANYEXT1:%[0-9]+]]:_(s192) = G_ANYEXT [[ANYEXT]] CHECK: [[UNMERGE:%[0-9]+]]:_(s64), [[UNMERGE1:%[0-9]+]]:_(s64), [[UNMERGE2:%[0-9]+]]:_(s64) = G_UNMERGE_VALUES [[ANYEXT1]] CHECK: [[UNMERGE3:%[0-9]+]]:_(s16), [[UNMERGE4:%[0-9]+]]:_(s16), [[UNMERGE5:%[0-9]+]]:_(s16), [[UNMERGE6:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[UNMERGE]] CHECK: [[UNMERGE7:%[0-9]+]]:_(s16), [[UNMERGE8:%[0-9]+]]:_(s16), [[UNMERGE9:%[0-9]+]]:_(s16), [[UNMERGE10:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[UNMERGE1]] CHECK: [[UNMERGE11:%[0-9]+]]:_(s16), [[UNMERGE12:%[0-9]+]]:_(s16), [[UNMERGE13:%[0-9]+]]:_(s16), [[UNMERGE14:%[0-9]+]]:_(s16) = G_UNMERGE_VALUES [[UNMERGE2]] CHECK: [[MERGE:%[0-9]+]]:_(s48) = G_MERGE_VALUES [[UNMERGE3]]:_(s16), [[UNMERGE4]]:_(s16), [[UNMERGE5]]:_(s16) CHECK: [[MERGE1:%[0-9]+]]:_(s48) = G_MERGE_VALUES [[UNMERGE6]]:_(s16), [[UNMERGE7]]:_(s16), [[UNMERGE8]]:_(s16) )"; // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } } // namespace