1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00
llvm-mirror/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
Matt Arsenault 0f6cb1fbd8 GlobalISel: Set instr/debugloc before any legalizer action
It was annoying enough that every custom lowering needed to set the
insert point, but this was made worse since now these all needed to be
updated to setInstrAndDebugLoc. Consolidate these so every
legalization action has the right insert position by default.

This should fix dropping debug info in every custom AMDGPU
legalization.
2020-06-09 15:37:02 -04:00

3056 lines
99 KiB
C++

//===- 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: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 255
CHECK: [[AND:%[0-9]+]]:_(s16) = G_AND [[ADD]]:_, [[CST]]:_
CHECK: G_ICMP intpred(ne), [[ADD]]:_(s16), [[AND]]:_
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: [[CST:%[0-9]+]]:_(s16) = G_CONSTANT i16 255
CHECK: [[AND:%[0-9]+]]:_(s16) = G_AND [[SUB]]:_, [[CST]]:_
CHECK: G_ICMP intpred(ne), [[SUB]]:_(s16), [[AND]]:_
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<Register, 8> 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<Register, 8> Merge1Ops;
for (int I = 0; I != 7; ++I)
Merge1Ops.push_back(B.buildConstant(S3, I).getReg(0));
auto Merge1 = B.buildMerge(S21, Merge1Ops);
SmallVector<Register, 8> 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: [[EXTR:%[0-9]+]]:_(<2 x s32>) = G_EXTRACT [[FREEZE]]:_(<4 x s32>), 0
)";
// Check
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
}
} // namespace