
This patch fixes: third-party/unittest/googletest/include/gtest/gtest.h:1379:11: error: comparison of integers of different signs: 'const unsigned long' and 'const int' [-Werror,-Wsign-compare]
626 lines
23 KiB
C++
626 lines
23 KiB
C++
//===- CSETest.cpp -----------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "GISelMITest.h"
|
|
#include "llvm/CodeGen/GlobalISel/CSEInfo.h"
|
|
#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace {
|
|
|
|
TEST_F(AArch64GISelMITest, TestCSE) {
|
|
setUp();
|
|
if (!TM)
|
|
GTEST_SKIP();
|
|
|
|
LLT s16{LLT::scalar(16)};
|
|
LLT s32{LLT::scalar(32)};
|
|
auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]});
|
|
auto MIBInput1 = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[1]});
|
|
auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
|
|
GISelCSEInfo CSEInfo;
|
|
CSEInfo.setCSEConfig(std::make_unique<CSEConfigFull>());
|
|
CSEInfo.analyze(*MF);
|
|
B.setCSEInfo(&CSEInfo);
|
|
CSEMIRBuilder CSEB(B.getState());
|
|
|
|
CSEB.setInsertPt(B.getMBB(), B.getInsertPt());
|
|
Register AddReg = MRI->createGenericVirtualRegister(s16);
|
|
auto MIBAddCopy =
|
|
CSEB.buildInstr(TargetOpcode::G_ADD, {AddReg}, {MIBInput, MIBInput});
|
|
EXPECT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY);
|
|
auto MIBAdd2 =
|
|
CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
|
|
EXPECT_TRUE(&*MIBAdd == &*MIBAdd2);
|
|
auto MIBAdd4 =
|
|
CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
|
|
EXPECT_TRUE(&*MIBAdd == &*MIBAdd4);
|
|
auto MIBAdd5 =
|
|
CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput1});
|
|
EXPECT_TRUE(&*MIBAdd != &*MIBAdd5);
|
|
|
|
// Try building G_CONSTANTS.
|
|
auto MIBCst = CSEB.buildConstant(s32, 0);
|
|
auto MIBCst1 = CSEB.buildConstant(s32, 0);
|
|
EXPECT_TRUE(&*MIBCst == &*MIBCst1);
|
|
// Try the CFing of BinaryOps.
|
|
auto MIBCF1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s32}, {MIBCst, MIBCst});
|
|
EXPECT_TRUE(&*MIBCF1 == &*MIBCst);
|
|
|
|
// Try out building FCONSTANTs.
|
|
auto MIBFP0 = CSEB.buildFConstant(s32, 1.0);
|
|
auto MIBFP0_1 = CSEB.buildFConstant(s32, 1.0);
|
|
EXPECT_TRUE(&*MIBFP0 == &*MIBFP0_1);
|
|
CSEInfo.print();
|
|
|
|
// Make sure buildConstant with a vector type doesn't crash, and the elements
|
|
// CSE.
|
|
auto Splat0 = CSEB.buildConstant(LLT::fixed_vector(2, s32), 0);
|
|
EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, Splat0->getOpcode());
|
|
EXPECT_EQ(Splat0.getReg(1), Splat0.getReg(2));
|
|
EXPECT_EQ(&*MIBCst, MRI->getVRegDef(Splat0.getReg(1)));
|
|
|
|
auto FSplat = CSEB.buildFConstant(LLT::fixed_vector(2, s32), 1.0);
|
|
EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, FSplat->getOpcode());
|
|
EXPECT_EQ(FSplat.getReg(1), FSplat.getReg(2));
|
|
EXPECT_EQ(&*MIBFP0, MRI->getVRegDef(FSplat.getReg(1)));
|
|
|
|
// Check G_UNMERGE_VALUES
|
|
auto MIBUnmerge = CSEB.buildUnmerge({s32, s32}, Copies[0]);
|
|
auto MIBUnmerge2 = CSEB.buildUnmerge({s32, s32}, Copies[0]);
|
|
EXPECT_TRUE(&*MIBUnmerge == &*MIBUnmerge2);
|
|
|
|
// Check G_FADD
|
|
{
|
|
auto MIBFAdd = CSEB.buildFAdd(s32, Copies[0], Copies[1]);
|
|
auto MIBFAdd2 = CSEB.buildFAdd(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFAdd == &*MIBFAdd2);
|
|
|
|
auto MIBFAdd3 =
|
|
CSEB.buildFAdd(s32, Copies[0], Copies[1], MachineInstr::FmNsz);
|
|
EXPECT_FALSE(&*MIBFAdd == &*MIBFAdd3);
|
|
|
|
MIBFAdd2->setFlag(MachineInstr::FmNsz);
|
|
MIBFAdd2->clearFlag(MachineInstr::FmNsz);
|
|
EXPECT_TRUE(&*MIBFAdd == &*MIBFAdd2);
|
|
}
|
|
|
|
// Check G_FSUB
|
|
{
|
|
auto MIBFSub = CSEB.buildFSub(s32, Copies[0], Copies[1]);
|
|
auto MIBFSub2 = CSEB.buildFSub(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFSub == &*MIBFSub2);
|
|
|
|
auto MIBFSub3 =
|
|
CSEB.buildFSub(s32, Copies[0], Copies[1], MachineInstr::FmNoNans);
|
|
EXPECT_FALSE(&*MIBFSub == &*MIBFSub3);
|
|
|
|
MIBFSub2->setFlag(MachineInstr::FmNoNans);
|
|
MIBFSub2->clearFlag(MachineInstr::FmNoNans);
|
|
EXPECT_TRUE(&*MIBFSub == &*MIBFSub2);
|
|
}
|
|
|
|
// Check G_FMUL
|
|
{
|
|
auto MIBFMul = CSEB.buildFMul(s32, Copies[0], Copies[1]);
|
|
auto MIBFMul2 = CSEB.buildFMul(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFMul == &*MIBFMul2);
|
|
|
|
auto MIBFMul3 =
|
|
CSEB.buildFMul(s32, Copies[0], Copies[1], MachineInstr::FmNoNans);
|
|
EXPECT_FALSE(&*MIBFMul == &*MIBFMul3);
|
|
|
|
MIBFMul2->setFlag(MachineInstr::FmNoNans);
|
|
MIBFMul2->clearFlag(MachineInstr::FmNoNans);
|
|
EXPECT_TRUE(&*MIBFMul == &*MIBFMul2);
|
|
}
|
|
|
|
// Check G_FDIV
|
|
{
|
|
auto MIBFDiv = CSEB.buildFDiv(s32, Copies[0], Copies[1]);
|
|
auto MIBFDiv2 = CSEB.buildFDiv(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFDiv == &*MIBFDiv2);
|
|
|
|
auto MIBFDiv3 =
|
|
CSEB.buildFDiv(s32, Copies[0], Copies[1], MachineInstr::FmNoNans);
|
|
EXPECT_FALSE(&*MIBFDiv == &*MIBFDiv3);
|
|
|
|
MIBFDiv2->setFlag(MachineInstr::FmNoNans);
|
|
MIBFDiv2->clearFlag(MachineInstr::FmNoNans);
|
|
EXPECT_TRUE(&*MIBFDiv == &*MIBFDiv2);
|
|
}
|
|
|
|
// Check G_FABS
|
|
{
|
|
auto MIBFAbs = CSEB.buildFAbs(s32, Copies[0]);
|
|
auto MIBFAbs2 = CSEB.buildFAbs(s32, Copies[0]);
|
|
EXPECT_TRUE(&*MIBFAbs == &*MIBFAbs2);
|
|
|
|
auto MIBFAbs3 = CSEB.buildFAbs(s32, Copies[0], MachineInstr::FmNsz);
|
|
EXPECT_FALSE(&*MIBFAbs == &*MIBFAbs3);
|
|
|
|
MIBFAbs2->setFlag(MachineInstr::FmNsz);
|
|
MIBFAbs2->clearFlag(MachineInstr::FmNsz);
|
|
EXPECT_TRUE(&*MIBFAbs == &*MIBFAbs2);
|
|
}
|
|
|
|
// Check G_FMINNUM/F_MAXNUM:
|
|
{
|
|
auto MIBFMinNum = CSEB.buildFMinNum(s32, Copies[0], Copies[1]);
|
|
auto MIBFMinNum2 = CSEB.buildFMinNum(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFMinNum == &*MIBFMinNum2);
|
|
|
|
auto MIBFMinNum3 =
|
|
CSEB.buildFMinNum(s32, Copies[0], Copies[1], MachineInstr::FmNsz);
|
|
EXPECT_FALSE(&*MIBFMinNum == &*MIBFMinNum3);
|
|
|
|
MIBFMinNum2->setFlag(MachineInstr::FmNsz);
|
|
MIBFMinNum2->clearFlag(MachineInstr::FmNsz);
|
|
EXPECT_TRUE(&*MIBFMinNum == &*MIBFMinNum2);
|
|
}
|
|
|
|
{
|
|
auto MIBFMaxNum = CSEB.buildFMaxNum(s32, Copies[0], Copies[1]);
|
|
auto MIBFMaxNum2 = CSEB.buildFMaxNum(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFMaxNum == &*MIBFMaxNum2);
|
|
|
|
auto MIBFMaxNum3 =
|
|
CSEB.buildFMaxNum(s32, Copies[0], Copies[1], MachineInstr::FmNsz);
|
|
EXPECT_FALSE(&*MIBFMaxNum == &*MIBFMaxNum3);
|
|
|
|
MIBFMaxNum2->setFlag(MachineInstr::FmNsz);
|
|
MIBFMaxNum2->clearFlag(MachineInstr::FmNsz);
|
|
EXPECT_TRUE(&*MIBFMaxNum == &*MIBFMaxNum2);
|
|
}
|
|
|
|
// Check G_FMINNUM_IEEE/F_MAXNUM_IEEE:
|
|
{
|
|
auto MIBFMinNumIEEE = CSEB.buildFMinNumIEEE(s32, Copies[0], Copies[1]);
|
|
auto MIBFMinNumIEEE2 = CSEB.buildFMinNumIEEE(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFMinNumIEEE == &*MIBFMinNumIEEE2);
|
|
|
|
auto MIBFMinNumIEEE3 =
|
|
CSEB.buildFMinNumIEEE(s32, Copies[0], Copies[1], MachineInstr::FmNsz);
|
|
EXPECT_FALSE(&*MIBFMinNumIEEE == &*MIBFMinNumIEEE3);
|
|
|
|
MIBFMinNumIEEE2->setFlag(MachineInstr::FmNsz);
|
|
MIBFMinNumIEEE2->clearFlag(MachineInstr::FmNsz);
|
|
EXPECT_TRUE(&*MIBFMinNumIEEE == &*MIBFMinNumIEEE2);
|
|
}
|
|
|
|
{
|
|
auto MIBFMaxNumIEEE = CSEB.buildFMaxNumIEEE(s32, Copies[0], Copies[1]);
|
|
auto MIBFMaxNumIEEE2 = CSEB.buildFMaxNumIEEE(s32, Copies[0], Copies[1]);
|
|
EXPECT_TRUE(&*MIBFMaxNumIEEE == &*MIBFMaxNumIEEE2);
|
|
|
|
auto MIBFMaxNumIEEE3 =
|
|
CSEB.buildFMaxNumIEEE(s32, Copies[0], Copies[1], MachineInstr::FmNsz);
|
|
EXPECT_FALSE(&*MIBFMaxNumIEEE == &*MIBFMaxNumIEEE3);
|
|
|
|
MIBFMaxNumIEEE2->setFlag(MachineInstr::FmNsz);
|
|
MIBFMaxNumIEEE2->clearFlag(MachineInstr::FmNsz);
|
|
EXPECT_TRUE(&*MIBFMaxNumIEEE == &*MIBFMaxNumIEEE2);
|
|
}
|
|
|
|
// Check G_BUILD_VECTOR
|
|
Register Reg1 = MRI->createGenericVirtualRegister(s32);
|
|
Register Reg2 = MRI->createGenericVirtualRegister(s32);
|
|
auto BuildVec1 =
|
|
CSEB.buildBuildVector(LLT::fixed_vector(4, 32), {Reg1, Reg2, Reg1, Reg2});
|
|
auto BuildVec2 =
|
|
CSEB.buildBuildVector(LLT::fixed_vector(4, 32), {Reg1, Reg2, Reg1, Reg2});
|
|
EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, BuildVec1->getOpcode());
|
|
EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, BuildVec2->getOpcode());
|
|
EXPECT_TRUE(&*BuildVec1 == &*BuildVec2);
|
|
|
|
// Check G_BUILD_VECTOR_TRUNC
|
|
auto BuildVecTrunc1 = CSEB.buildBuildVectorTrunc(LLT::fixed_vector(4, 16),
|
|
{Reg1, Reg2, Reg1, Reg2});
|
|
auto BuildVecTrunc2 = CSEB.buildBuildVectorTrunc(LLT::fixed_vector(4, 16),
|
|
{Reg1, Reg2, Reg1, Reg2});
|
|
EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR_TRUNC, BuildVecTrunc1->getOpcode());
|
|
EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR_TRUNC, BuildVecTrunc2->getOpcode());
|
|
EXPECT_TRUE(&*BuildVecTrunc1 == &*BuildVecTrunc2);
|
|
|
|
// Check G_IMPLICIT_DEF
|
|
auto Undef0 = CSEB.buildUndef(s32);
|
|
auto Undef1 = CSEB.buildUndef(s32);
|
|
EXPECT_EQ(&*Undef0, &*Undef1);
|
|
|
|
// If the observer is installed to the MF, CSE can also
|
|
// track new instructions built without the CSEBuilder and
|
|
// the newly built instructions are available for CSEing next
|
|
// time a build call is made through the CSEMIRBuilder.
|
|
// Additionally, the CSE implementation lazily hashes instructions
|
|
// (every build call) to give chance for the instruction to be fully
|
|
// built (say using .addUse().addDef().. so on).
|
|
GISelObserverWrapper WrapperObserver(&CSEInfo);
|
|
RAIIMFObsDelInstaller Installer(*MF, WrapperObserver);
|
|
MachineIRBuilder RegularBuilder(*MF);
|
|
RegularBuilder.setInsertPt(*EntryMBB, EntryMBB->begin());
|
|
auto NonCSEFMul = RegularBuilder.buildInstr(TargetOpcode::G_AND)
|
|
.addDef(MRI->createGenericVirtualRegister(s32))
|
|
.addUse(Copies[0])
|
|
.addUse(Copies[1]);
|
|
auto CSEFMul =
|
|
CSEB.buildInstr(TargetOpcode::G_AND, {s32}, {Copies[0], Copies[1]});
|
|
EXPECT_EQ(&*CSEFMul, &*NonCSEFMul);
|
|
|
|
auto ExtractMIB = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16},
|
|
{Copies[0], static_cast<uint64_t>(0)});
|
|
auto ExtractMIB1 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16},
|
|
{Copies[0], static_cast<uint64_t>(0)});
|
|
auto ExtractMIB2 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16},
|
|
{Copies[0], static_cast<uint64_t>(1)});
|
|
EXPECT_EQ(&*ExtractMIB, &*ExtractMIB1);
|
|
EXPECT_NE(&*ExtractMIB, &*ExtractMIB2);
|
|
|
|
|
|
auto SextInRegMIB = CSEB.buildSExtInReg(s16, Copies[0], 0);
|
|
auto SextInRegMIB1 = CSEB.buildSExtInReg(s16, Copies[0], 0);
|
|
auto SextInRegMIB2 = CSEB.buildSExtInReg(s16, Copies[0], 1);
|
|
EXPECT_EQ(&*SextInRegMIB, &*SextInRegMIB1);
|
|
EXPECT_NE(&*SextInRegMIB, &*SextInRegMIB2);
|
|
}
|
|
|
|
TEST_F(AArch64GISelMITest, TestCSEConstantConfig) {
|
|
setUp();
|
|
if (!TM)
|
|
GTEST_SKIP();
|
|
|
|
LLT s16{LLT::scalar(16)};
|
|
auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]});
|
|
auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
|
|
auto MIBZero = B.buildConstant(s16, 0);
|
|
GISelCSEInfo CSEInfo;
|
|
CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>());
|
|
CSEInfo.analyze(*MF);
|
|
B.setCSEInfo(&CSEInfo);
|
|
CSEMIRBuilder CSEB(B.getState());
|
|
CSEB.setInsertPt(*EntryMBB, EntryMBB->begin());
|
|
auto MIBAdd1 =
|
|
CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
|
|
// We should CSE constants only. Adds should not be CSEd.
|
|
EXPECT_TRUE(MIBAdd1->getOpcode() != TargetOpcode::COPY);
|
|
EXPECT_TRUE(&*MIBAdd1 != &*MIBAdd);
|
|
// We should CSE constant.
|
|
auto MIBZeroTmp = CSEB.buildConstant(s16, 0);
|
|
EXPECT_TRUE(&*MIBZero == &*MIBZeroTmp);
|
|
|
|
// Check G_IMPLICIT_DEF
|
|
auto Undef0 = CSEB.buildUndef(s16);
|
|
auto Undef1 = CSEB.buildUndef(s16);
|
|
EXPECT_EQ(&*Undef0, &*Undef1);
|
|
}
|
|
|
|
TEST_F(AArch64GISelMITest, TestCSEImmediateNextCSE) {
|
|
setUp();
|
|
if (!TM)
|
|
GTEST_SKIP();
|
|
|
|
LLT s32{LLT::scalar(32)};
|
|
// We want to check that when the CSE hit is on the next instruction, i.e. at
|
|
// the current insert pt, that the insertion point is moved ahead of the
|
|
// instruction.
|
|
|
|
GISelCSEInfo CSEInfo;
|
|
CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>());
|
|
CSEInfo.analyze(*MF);
|
|
B.setCSEInfo(&CSEInfo);
|
|
CSEMIRBuilder CSEB(B.getState());
|
|
CSEB.buildConstant(s32, 0);
|
|
auto MIBCst2 = CSEB.buildConstant(s32, 2);
|
|
|
|
// Move the insert point before the second constant.
|
|
CSEB.setInsertPt(CSEB.getMBB(), --CSEB.getInsertPt());
|
|
auto MIBCst3 = CSEB.buildConstant(s32, 2);
|
|
EXPECT_TRUE(&*MIBCst2 == &*MIBCst3);
|
|
EXPECT_TRUE(CSEB.getInsertPt() == CSEB.getMBB().end());
|
|
}
|
|
|
|
TEST_F(AArch64GISelMITest, TestConstantFoldCTL) {
|
|
setUp();
|
|
if (!TM)
|
|
GTEST_SKIP();
|
|
|
|
LLT s32 = LLT::scalar(32);
|
|
|
|
GISelCSEInfo CSEInfo;
|
|
CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>());
|
|
CSEInfo.analyze(*MF);
|
|
B.setCSEInfo(&CSEInfo);
|
|
CSEMIRBuilder CSEB(B.getState());
|
|
auto Cst8 = CSEB.buildConstant(s32, 8);
|
|
auto *CtlzDef = &*CSEB.buildCTLZ(s32, Cst8);
|
|
EXPECT_TRUE(CtlzDef->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(CtlzDef->getOperand(1).getCImm()->getZExtValue() == 28);
|
|
|
|
// Test vector.
|
|
auto Cst16 = CSEB.buildConstant(s32, 16);
|
|
auto Cst32 = CSEB.buildConstant(s32, 32);
|
|
auto Cst64 = CSEB.buildConstant(s32, 64);
|
|
LLT VecTy = LLT::fixed_vector(4, s32);
|
|
auto BV = CSEB.buildBuildVector(VecTy, {Cst8.getReg(0), Cst16.getReg(0),
|
|
Cst32.getReg(0), Cst64.getReg(0)});
|
|
CSEB.buildCTLZ(VecTy, BV);
|
|
|
|
auto CheckStr = R"(
|
|
; CHECK: [[CST8:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
|
|
; CHECK: [[CST28:%[0-9]+]]:_(s32) = G_CONSTANT i32 28
|
|
; CHECK: [[CST16:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
|
|
; CHECK: [[CST32:%[0-9]+]]:_(s32) = G_CONSTANT i32 32
|
|
; CHECK: [[CST64:%[0-9]+]]:_(s32) = G_CONSTANT i32 64
|
|
; CHECK: [[BV1:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST8]]:_(s32), [[CST16]]:_(s32), [[CST32]]:_(s32), [[CST64]]:_(s32)
|
|
; CHECK: [[CST27:%[0-9]+]]:_(s32) = G_CONSTANT i32 27
|
|
; CHECK: [[CST26:%[0-9]+]]:_(s32) = G_CONSTANT i32 26
|
|
; CHECK: [[CST25:%[0-9]+]]:_(s32) = G_CONSTANT i32 25
|
|
; CHECK: [[BV2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST28]]:_(s32), [[CST27]]:_(s32), [[CST26]]:_(s32), [[CST25]]:_(s32)
|
|
)";
|
|
|
|
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
|
|
}
|
|
|
|
TEST_F(AArch64GISelMITest, TestConstantFoldCTT) {
|
|
setUp();
|
|
if (!TM)
|
|
GTEST_SKIP();
|
|
|
|
LLT s32 = LLT::scalar(32);
|
|
|
|
GISelCSEInfo CSEInfo;
|
|
CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>());
|
|
CSEInfo.analyze(*MF);
|
|
B.setCSEInfo(&CSEInfo);
|
|
CSEMIRBuilder CSEB(B.getState());
|
|
auto Cst8 = CSEB.buildConstant(s32, 8);
|
|
auto *CttzDef = &*CSEB.buildCTTZ(s32, Cst8);
|
|
EXPECT_TRUE(CttzDef->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(CttzDef->getOperand(1).getCImm()->getZExtValue() == 3);
|
|
|
|
// Test vector.
|
|
auto Cst16 = CSEB.buildConstant(s32, 16);
|
|
auto Cst32 = CSEB.buildConstant(s32, 32);
|
|
auto Cst64 = CSEB.buildConstant(s32, 64);
|
|
LLT VecTy = LLT::fixed_vector(4, s32);
|
|
auto BV = CSEB.buildBuildVector(VecTy, {Cst8.getReg(0), Cst16.getReg(0),
|
|
Cst32.getReg(0), Cst64.getReg(0)});
|
|
CSEB.buildCTTZ(VecTy, BV);
|
|
|
|
auto CheckStr = R"(
|
|
; CHECK: [[CST8:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
|
|
; CHECK: [[CST3:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
|
|
; CHECK: [[CST16:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
|
|
; CHECK: [[CST32:%[0-9]+]]:_(s32) = G_CONSTANT i32 32
|
|
; CHECK: [[CST64:%[0-9]+]]:_(s32) = G_CONSTANT i32 64
|
|
; CHECK: [[BV1:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST8]]:_(s32), [[CST16]]:_(s32), [[CST32]]:_(s32), [[CST64]]:_(s32)
|
|
; CHECK: [[CST27:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
|
|
; CHECK: [[CST26:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
|
|
; CHECK: [[CST25:%[0-9]+]]:_(s32) = G_CONSTANT i32 6
|
|
; CHECK: [[BV2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST3]]:_(s32), [[CST27]]:_(s32), [[CST26]]:_(s32), [[CST25]]:_(s32)
|
|
)";
|
|
|
|
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
|
|
}
|
|
|
|
TEST_F(AArch64GISelMITest, TestConstantFoldICMP) {
|
|
setUp();
|
|
if (!TM)
|
|
GTEST_SKIP();
|
|
|
|
LLT s32 = LLT::scalar(32);
|
|
LLT s1 = LLT::scalar(1);
|
|
|
|
GISelCSEInfo CSEInfo;
|
|
CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>());
|
|
CSEInfo.analyze(*MF);
|
|
B.setCSEInfo(&CSEInfo);
|
|
CSEMIRBuilder CSEB(B.getState());
|
|
|
|
auto One = CSEB.buildConstant(s32, 1);
|
|
auto Two = CSEB.buildConstant(s32, 2);
|
|
auto MinusOne = CSEB.buildConstant(s32, -1);
|
|
auto MinusTwo = CSEB.buildConstant(s32, -2);
|
|
|
|
// ICMP_EQ
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, s1, One, One);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_NE
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_NE, s1, One, Two);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_UGT
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_UGT, s1, Two, One);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_UGE
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_UGE, s1, One, One);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_ULT
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_ULT, s1, One, Two);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_ULE
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_ULE, s1, Two, Two);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_SGT
|
|
{
|
|
auto I =
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SGT, s1, MinusOne, MinusTwo);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_SGE
|
|
{
|
|
auto I =
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SGE, s1, MinusOne, MinusOne);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_SLT
|
|
{
|
|
auto I =
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SLT, s1, MinusTwo, MinusOne);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
// ICMP_SLE
|
|
{
|
|
auto I =
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SLE, s1, MinusTwo, MinusOne);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue());
|
|
}
|
|
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, s32, One, One);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_EQ(I->getOperand(1).getCImm()->getZExtValue(), 1U);
|
|
}
|
|
|
|
{
|
|
auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, s32, One, Two);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT);
|
|
EXPECT_EQ(I->getOperand(1).getCImm()->getZExtValue(), 0U);
|
|
}
|
|
|
|
LLT VecTy = LLT::fixed_vector(2, s32);
|
|
LLT DstTy = LLT::fixed_vector(2, s1);
|
|
auto Three = CSEB.buildConstant(s32, 3);
|
|
auto MinusThree = CSEB.buildConstant(s32, -3);
|
|
auto OneOne = CSEB.buildBuildVector(VecTy, {One.getReg(0), One.getReg(0)});
|
|
auto OneTwo = CSEB.buildBuildVector(VecTy, {One.getReg(0), Two.getReg(0)});
|
|
auto TwoThree =
|
|
CSEB.buildBuildVector(VecTy, {Two.getReg(0), Three.getReg(0)});
|
|
auto OneThree =
|
|
CSEB.buildBuildVector(VecTy, {One.getReg(0), Three.getReg(0)});
|
|
auto MinusOneOne =
|
|
CSEB.buildBuildVector(VecTy, {MinusOne.getReg(0), MinusOne.getReg(0)});
|
|
auto MinusOneTwo =
|
|
CSEB.buildBuildVector(VecTy, {MinusOne.getReg(0), MinusTwo.getReg(0)});
|
|
auto MinusTwoThree =
|
|
CSEB.buildBuildVector(VecTy, {MinusTwo.getReg(0), MinusThree.getReg(0)});
|
|
|
|
// ICMP_EQ
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, OneOne, OneOne);
|
|
|
|
// ICMP_NE
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, OneOne, OneTwo);
|
|
|
|
// ICMP_UGT
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, TwoThree, OneTwo);
|
|
|
|
// ICMP_UGE
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, OneTwo, OneOne);
|
|
|
|
// ICMP_ULT
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, OneOne, OneTwo);
|
|
|
|
// ICMP_ULE
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_ULE, DstTy, OneTwo, OneOne);
|
|
|
|
// ICMP_SGT
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SGT, DstTy, MinusOneTwo,
|
|
MinusTwoThree);
|
|
|
|
// ICMP_SGE
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SGE, DstTy, MinusOneTwo, MinusOneOne);
|
|
|
|
// ICMP_SLT
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SLT, DstTy, MinusTwoThree,
|
|
MinusOneTwo);
|
|
|
|
// ICMP_SLE
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_SLE, DstTy, MinusOneTwo, MinusOneOne);
|
|
|
|
{
|
|
auto I =
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, VecTy, OneOne, TwoThree);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
|
|
const APInt HiCst = *getIConstantVRegVal(I->getOperand(1).getReg(), *MRI);
|
|
const APInt LoCst = *getIConstantVRegVal(I->getOperand(2).getReg(), *MRI);
|
|
EXPECT_EQ(HiCst.getSExtValue(), 0);
|
|
EXPECT_EQ(LoCst.getSExtValue(), 0);
|
|
}
|
|
|
|
{
|
|
auto I =
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, VecTy, OneThree, TwoThree);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
|
|
const APInt HiCst = *getIConstantVRegVal(I->getOperand(1).getReg(), *MRI);
|
|
const APInt LoCst = *getIConstantVRegVal(I->getOperand(2).getReg(), *MRI);
|
|
EXPECT_EQ(HiCst.getSExtValue(), 0);
|
|
EXPECT_EQ(LoCst.getSExtValue(), -1);
|
|
}
|
|
|
|
{
|
|
auto I =
|
|
CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, VecTy, TwoThree, TwoThree);
|
|
EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
|
|
const APInt HiCst = *getIConstantVRegVal(I->getOperand(1).getReg(), *MRI);
|
|
const APInt LoCst = *getIConstantVRegVal(I->getOperand(2).getReg(), *MRI);
|
|
EXPECT_EQ(HiCst.getSExtValue(), -1);
|
|
EXPECT_EQ(LoCst.getSExtValue(), -1);
|
|
}
|
|
|
|
auto CheckStr = R"(
|
|
; CHECK: [[One:%[0-9]+]]:_(s32) = G_CONSTANT i32 1
|
|
; CHECK: [[Two:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
|
|
; CHECK: [[MinusOne:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1
|
|
; CHECK: [[MinusTwo:%[0-9]+]]:_(s32) = G_CONSTANT i32 -2
|
|
; CHECK: [[True:%[0-9]+]]:_(s1) = G_CONSTANT i1 true
|
|
; CHECK: [[Three:%[0-9]+]]:_(s32) = G_CONSTANT i32 3
|
|
; CHECK: [[MinusThree:%[0-9]+]]:_(s32) = G_CONSTANT i32 -3
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[One]]:_(s32), [[One]]:_(s32)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[One]]:_(s32), [[Two]]:_(s32)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[Two]]:_(s32), [[Three]]:_(s32)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[One]]:_(s32), [[Three]]:_(s32)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[MinusOne]]:_(s32), [[MinusOne]]:_(s32)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[MinusOne]]:_(s32), [[MinusTwo]]:_(s32)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[MinusTwo]]:_(s32), [[MinusThree]]:_(s32)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1)
|
|
; CHECK: [[False:%[0-9]+]]:_(s1) = G_CONSTANT i1 false
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[False]]:_(s1), [[True]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[False]]:_(s1), [[True]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[False]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[False]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1)
|
|
; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1)
|
|
)";
|
|
|
|
EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF;
|
|
}
|
|
|
|
} // namespace
|