mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Revert "Revert rr340111 "[GISel]: Add Legalization/lowering code for bit counting operations""
This reverts commit d1341152d91398e9a882ba2ee924147ea2f9b589. This patch originally made use of Nested MachineIRBuilder buildInstr calls, and since order of argument processing is not well defined, the instructions were built slightly in a different order (still correct). I've removed the nested buildInstr calls to have a defined order now. Patch was tested by Mikael. llvm-svn: 340309
This commit is contained in:
parent
f61226a39c
commit
1dea0652da
@ -49,6 +49,7 @@ public:
|
||||
};
|
||||
|
||||
LegalizerHelper(MachineFunction &MF);
|
||||
LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI);
|
||||
|
||||
/// Replace \p MI by a sequence of legal instructions that can implement the
|
||||
/// same operation. Note that this means \p MI may be deleted, so any iterator
|
||||
@ -112,6 +113,8 @@ private:
|
||||
void extractParts(unsigned Reg, LLT Ty, int NumParts,
|
||||
SmallVectorImpl<unsigned> &VRegs);
|
||||
|
||||
LegalizeResult lowerBitCount(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
|
||||
MachineRegisterInfo &MRI;
|
||||
const LegalizerInfo &LI;
|
||||
};
|
||||
|
@ -668,6 +668,11 @@ public:
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred,
|
||||
unsigned Res, unsigned Op0, unsigned Op1);
|
||||
template <typename DstTy, typename... UseArgsTy>
|
||||
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, DstTy &&Dst,
|
||||
UseArgsTy &&... UseArgs) {
|
||||
return buildICmp(Pred, getDestFromArg(Dst), getRegFromArg(UseArgs)...);
|
||||
}
|
||||
|
||||
/// Build and insert a \p Res = G_FCMP \p Pred\p Op0, \p Op1
|
||||
///
|
||||
@ -696,6 +701,10 @@ public:
|
||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||
MachineInstrBuilder buildSelect(unsigned Res, unsigned Tst,
|
||||
unsigned Op0, unsigned Op1);
|
||||
template <typename DstTy, typename... UseArgsTy>
|
||||
MachineInstrBuilder buildSelect(DstTy &&Dst, UseArgsTy &&... UseArgs) {
|
||||
return buildSelect(getDestFromArg(Dst), getRegFromArg(UseArgs)...);
|
||||
}
|
||||
|
||||
/// Build and insert \p Res = G_INSERT_VECTOR_ELT \p Val,
|
||||
/// \p Elt, \p Idx
|
||||
|
@ -83,6 +83,11 @@ def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFFECTS, intrinsic_void>;
|
||||
def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFFECTS, intrinsic_w_chain>;
|
||||
def : GINodeEquiv<G_BR, br>;
|
||||
def : GINodeEquiv<G_BSWAP, bswap>;
|
||||
def : GINodeEquiv<G_CTLZ, ctlz>;
|
||||
def : GINodeEquiv<G_CTTZ, cttz>;
|
||||
def : GINodeEquiv<G_CTLZ_ZERO_UNDEF, ctlz_zero_undef>;
|
||||
def : GINodeEquiv<G_CTTZ_ZERO_UNDEF, cttz_zero_undef>;
|
||||
def : GINodeEquiv<G_CTPOP, ctpop>;
|
||||
|
||||
// Broadly speaking G_LOAD is equivalent to ISD::LOAD but there are some
|
||||
// complications that tablegen must take care of. For example, Predicates such
|
||||
|
@ -17,12 +17,13 @@
|
||||
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
||||
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/TargetInstrInfo.h"
|
||||
#include "llvm/CodeGen/TargetLowering.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
|
||||
#define DEBUG_TYPE "legalizer"
|
||||
|
||||
using namespace llvm;
|
||||
@ -33,6 +34,10 @@ LegalizerHelper::LegalizerHelper(MachineFunction &MF)
|
||||
MIRBuilder.setMF(MF);
|
||||
}
|
||||
|
||||
LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI)
|
||||
: MRI(MF.getRegInfo()), LI(LI) {
|
||||
MIRBuilder.setMF(MF);
|
||||
}
|
||||
LegalizerHelper::LegalizeResult
|
||||
LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
|
||||
LLVM_DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
|
||||
@ -984,6 +989,12 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
|
||||
|
||||
return UnableToLegalize;
|
||||
}
|
||||
case TargetOpcode::G_CTLZ_ZERO_UNDEF:
|
||||
case TargetOpcode::G_CTTZ_ZERO_UNDEF:
|
||||
case TargetOpcode::G_CTLZ:
|
||||
case TargetOpcode::G_CTTZ:
|
||||
case TargetOpcode::G_CTPOP:
|
||||
return lowerBitCount(MI, TypeIdx, Ty);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1024,3 +1035,113 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LegalizerHelper::LegalizeResult
|
||||
LegalizerHelper::lowerBitCount(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
|
||||
unsigned Opc = MI.getOpcode();
|
||||
auto &TII = *MI.getMF()->getSubtarget().getInstrInfo();
|
||||
auto isLegalOrCustom = [this](const LegalityQuery &Q) {
|
||||
auto QAction = LI.getAction(Q).Action;
|
||||
return QAction == Legal || QAction == Custom;
|
||||
};
|
||||
switch (Opc) {
|
||||
default:
|
||||
return UnableToLegalize;
|
||||
case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
|
||||
// This trivially expands to CTLZ.
|
||||
MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
|
||||
MIRBuilder.recordInsertion(&MI);
|
||||
return Legalized;
|
||||
}
|
||||
case TargetOpcode::G_CTLZ: {
|
||||
unsigned SrcReg = MI.getOperand(1).getReg();
|
||||
unsigned Len = Ty.getSizeInBits();
|
||||
if (isLegalOrCustom({TargetOpcode::G_CTLZ_ZERO_UNDEF, {Ty}})) {
|
||||
// If CTLZ_ZERO_UNDEF is legal or custom, emit that and a select with
|
||||
// zero.
|
||||
auto MIBCtlzZU =
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, Ty, SrcReg);
|
||||
auto MIBZero = MIRBuilder.buildConstant(Ty, 0);
|
||||
auto MIBLen = MIRBuilder.buildConstant(Ty, Len);
|
||||
auto MIBICmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
|
||||
SrcReg, MIBZero);
|
||||
MIRBuilder.buildSelect(MI.getOperand(0).getReg(), MIBICmp, MIBLen,
|
||||
MIBCtlzZU);
|
||||
MI.eraseFromParent();
|
||||
return Legalized;
|
||||
}
|
||||
// for now, we do this:
|
||||
// NewLen = NextPowerOf2(Len);
|
||||
// x = x | (x >> 1);
|
||||
// x = x | (x >> 2);
|
||||
// ...
|
||||
// x = x | (x >>16);
|
||||
// x = x | (x >>32); // for 64-bit input
|
||||
// Upto NewLen/2
|
||||
// return Len - popcount(x);
|
||||
//
|
||||
// Ref: "Hacker's Delight" by Henry Warren
|
||||
unsigned Op = SrcReg;
|
||||
unsigned NewLen = PowerOf2Ceil(Len);
|
||||
for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
|
||||
auto MIBShiftAmt = MIRBuilder.buildConstant(Ty, 1ULL << i);
|
||||
auto MIBOp = MIRBuilder.buildInstr(
|
||||
TargetOpcode::G_OR, Ty, Op,
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_LSHR, Ty, Op, MIBShiftAmt));
|
||||
Op = MIBOp->getOperand(0).getReg();
|
||||
}
|
||||
auto MIBPop = MIRBuilder.buildInstr(TargetOpcode::G_CTPOP, Ty, Op);
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_SUB, MI.getOperand(0).getReg(),
|
||||
MIRBuilder.buildConstant(Ty, Len), MIBPop);
|
||||
MI.eraseFromParent();
|
||||
return Legalized;
|
||||
}
|
||||
case TargetOpcode::G_CTTZ_ZERO_UNDEF: {
|
||||
// This trivially expands to CTTZ.
|
||||
MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
|
||||
MIRBuilder.recordInsertion(&MI);
|
||||
return Legalized;
|
||||
}
|
||||
case TargetOpcode::G_CTTZ: {
|
||||
unsigned SrcReg = MI.getOperand(1).getReg();
|
||||
unsigned Len = Ty.getSizeInBits();
|
||||
if (isLegalOrCustom({TargetOpcode::G_CTTZ_ZERO_UNDEF, {Ty}})) {
|
||||
// If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with
|
||||
// zero.
|
||||
auto MIBCttzZU =
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, Ty, SrcReg);
|
||||
auto MIBZero = MIRBuilder.buildConstant(Ty, 0);
|
||||
auto MIBLen = MIRBuilder.buildConstant(Ty, Len);
|
||||
auto MIBICmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
|
||||
SrcReg, MIBZero);
|
||||
MIRBuilder.buildSelect(MI.getOperand(0).getReg(), MIBICmp, MIBLen,
|
||||
MIBCttzZU);
|
||||
MI.eraseFromParent();
|
||||
return Legalized;
|
||||
}
|
||||
// for now, we use: { return popcount(~x & (x - 1)); }
|
||||
// unless the target has ctlz but not ctpop, in which case we use:
|
||||
// { return 32 - nlz(~x & (x-1)); }
|
||||
// Ref: "Hacker's Delight" by Henry Warren
|
||||
auto MIBCstNeg1 = MIRBuilder.buildConstant(Ty, -1);
|
||||
auto MIBNot =
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_XOR, Ty, SrcReg, MIBCstNeg1);
|
||||
auto MIBTmp = MIRBuilder.buildInstr(
|
||||
TargetOpcode::G_AND, Ty, MIBNot,
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_ADD, Ty, SrcReg, MIBCstNeg1));
|
||||
if (!isLegalOrCustom({TargetOpcode::G_CTPOP, {Ty}}) &&
|
||||
isLegalOrCustom({TargetOpcode::G_CTLZ, {Ty}})) {
|
||||
auto MIBCstLen = MIRBuilder.buildConstant(Ty, Len);
|
||||
MIRBuilder.buildInstr(
|
||||
TargetOpcode::G_SUB, MI.getOperand(0).getReg(),
|
||||
MIBCstLen,
|
||||
MIRBuilder.buildInstr(TargetOpcode::G_CTLZ, Ty, MIBTmp));
|
||||
MI.eraseFromParent();
|
||||
return Legalized;
|
||||
}
|
||||
MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
|
||||
MI.getOperand(1).setReg(MIBTmp->getOperand(0).getReg());
|
||||
return Legalized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,4 +12,5 @@ set(LLVM_LINK_COMPONENTS
|
||||
add_llvm_unittest(GlobalISelTests
|
||||
LegalizerInfoTest.cpp
|
||||
PatternMatchTest.cpp
|
||||
LegalizerHelperTest.cpp
|
||||
)
|
||||
|
188
unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
Normal file
188
unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
//===- PatternMatchTest.cpp -----------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "LegalizerHelperTest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Test CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom,
|
||||
// in which case it becomes CTTZ_ZERO_UNDEF with select.
|
||||
TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ0) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
// Declare your legalization info
|
||||
DefineLegalizerInfo(
|
||||
A, { getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF).legalFor({s64}); });
|
||||
// Build Instr
|
||||
auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, LLT::scalar(64), Copies[0]);
|
||||
AInfo Info(MF->getSubtarget());
|
||||
LegalizerHelper Helper(*MF, Info);
|
||||
// Perform Legalization
|
||||
ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
|
||||
LegalizerHelper::LegalizeResult::Legalized);
|
||||
|
||||
auto CheckStr = R"(
|
||||
CHECK: [[CZU:%[0-9]+]]:_(s64) = G_CTTZ_ZERO_UNDEF %0
|
||||
CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
|
||||
CHECK: [[SIXTY4:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
|
||||
CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]]
|
||||
CHECK: [[SEL:%[0-9]+]]:_(s64) = G_SELECT [[CMP]]:_(s1), [[SIXTY4]]:_, [[CZU]]
|
||||
)";
|
||||
|
||||
// Check
|
||||
ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
|
||||
}
|
||||
|
||||
// CTTZ expansion in terms of CTLZ
|
||||
TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ1) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
// Declare your legalization info
|
||||
DefineLegalizerInfo(A,
|
||||
{ getActionDefinitionsBuilder(G_CTLZ).legalFor({s64}); });
|
||||
// Build Instr
|
||||
auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, LLT::scalar(64), Copies[0]);
|
||||
AInfo Info(MF->getSubtarget());
|
||||
LegalizerHelper Helper(*MF, Info);
|
||||
// Perform Legalization
|
||||
ASSERT_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
|
||||
ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
|
||||
}
|
||||
|
||||
// CTTZ expansion in terms of CTPOP
|
||||
TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ2) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
// Declare your legalization info
|
||||
DefineLegalizerInfo(
|
||||
A, { getActionDefinitionsBuilder(G_CTPOP).legalFor({s64}); });
|
||||
// Build
|
||||
auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, LLT::scalar(64), Copies[0]);
|
||||
AInfo Info(MF->getSubtarget());
|
||||
LegalizerHelper Helper(*MF, Info);
|
||||
ASSERT_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
|
||||
ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
|
||||
}
|
||||
|
||||
// CTTZ_ZERO_UNDEF expansion in terms of CTTZ
|
||||
TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ3) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
// Declare your legalization info
|
||||
DefineLegalizerInfo(A,
|
||||
{ getActionDefinitionsBuilder(G_CTTZ).legalFor({s64}); });
|
||||
// Build
|
||||
auto MIBCTTZ =
|
||||
B.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, LLT::scalar(64), Copies[0]);
|
||||
AInfo Info(MF->getSubtarget());
|
||||
LegalizerHelper Helper(*MF, Info);
|
||||
ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
|
||||
LegalizerHelper::LegalizeResult::Legalized);
|
||||
|
||||
auto CheckStr = R"(
|
||||
CHECK: CTTZ
|
||||
)";
|
||||
|
||||
// Check
|
||||
ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
|
||||
}
|
||||
|
||||
// CTLZ expansion in terms of CTLZ_ZERO_UNDEF
|
||||
TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ0) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
// Declare your legalization info
|
||||
DefineLegalizerInfo(
|
||||
A, { getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF).legalFor({s64}); });
|
||||
// Build
|
||||
auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, LLT::scalar(64), Copies[0]);
|
||||
AInfo Info(MF->getSubtarget());
|
||||
LegalizerHelper Helper(*MF, Info);
|
||||
ASSERT_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: [[SIXTY4:%[0-9]+]]:_(s64) = G_CONSTANT i64 64
|
||||
CHECK: [[CMP:%[0-9]+]]:_(s1) = G_ICMP intpred(eq), %0:_(s64), [[ZERO]]
|
||||
CHECK: [[SEL:%[0-9]+]]:_(s64) = G_SELECT [[CMP]]:_(s1), [[SIXTY4]]:_, [[CZU]]
|
||||
)";
|
||||
|
||||
// Check
|
||||
ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
|
||||
}
|
||||
|
||||
// CTLZ expansion
|
||||
TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ1) {
|
||||
if (!TM)
|
||||
return;
|
||||
|
||||
// Declare your legalization info
|
||||
DefineLegalizerInfo(A,
|
||||
{ getActionDefinitionsBuilder(G_CTPOP).legalFor({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());
|
||||
LegalizerHelper Helper(*MF, Info);
|
||||
ASSERT_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
|
||||
ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
|
||||
}
|
||||
} // namespace
|
190
unittests/CodeGen/GlobalISel/LegalizerHelperTest.h
Normal file
190
unittests/CodeGen/GlobalISel/LegalizerHelperTest.h
Normal file
@ -0,0 +1,190 @@
|
||||
//===- LegalizerHelperTest.h
|
||||
//-----------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
|
||||
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||
#include "llvm/CodeGen/MIRParser/MIRParser.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||
#include "llvm/CodeGen/TargetInstrInfo.h"
|
||||
#include "llvm/CodeGen/TargetLowering.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include "llvm/Support/FileCheck.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace MIPatternMatch;
|
||||
|
||||
void initLLVM() {
|
||||
InitializeAllTargets();
|
||||
InitializeAllTargetMCs();
|
||||
InitializeAllAsmPrinters();
|
||||
InitializeAllAsmParsers();
|
||||
|
||||
PassRegistry *Registry = PassRegistry::getPassRegistry();
|
||||
initializeCore(*Registry);
|
||||
initializeCodeGen(*Registry);
|
||||
}
|
||||
|
||||
/// Create a TargetMachine. As we lack a dedicated always available target for
|
||||
/// unittests, we go for "AArch64".
|
||||
std::unique_ptr<TargetMachine> createTargetMachine() {
|
||||
Triple TargetTriple("aarch64--");
|
||||
std::string Error;
|
||||
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
|
||||
if (!T)
|
||||
return nullptr;
|
||||
|
||||
TargetOptions Options;
|
||||
return std::unique_ptr<TargetMachine>(T->createTargetMachine(
|
||||
"AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive));
|
||||
}
|
||||
|
||||
std::unique_ptr<Module> parseMIR(LLVMContext &Context,
|
||||
std::unique_ptr<MIRParser> &MIR,
|
||||
const TargetMachine &TM, StringRef MIRCode,
|
||||
const char *FuncName, MachineModuleInfo &MMI) {
|
||||
SMDiagnostic Diagnostic;
|
||||
std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
|
||||
MIR = createMIRParser(std::move(MBuffer), Context);
|
||||
if (!MIR)
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<Module> M = MIR->parseIRModule();
|
||||
if (!M)
|
||||
return nullptr;
|
||||
|
||||
M->setDataLayout(TM.createDataLayout());
|
||||
|
||||
if (MIR->parseMachineFunctions(*M, MMI))
|
||||
return nullptr;
|
||||
|
||||
return M;
|
||||
}
|
||||
|
||||
std::pair<std::unique_ptr<Module>, std::unique_ptr<MachineModuleInfo>>
|
||||
createDummyModule(LLVMContext &Context, const TargetMachine &TM,
|
||||
StringRef MIRFunc) {
|
||||
SmallString<512> S;
|
||||
StringRef MIRString = (Twine(R"MIR(
|
||||
---
|
||||
...
|
||||
name: func
|
||||
registers:
|
||||
- { id: 0, class: _ }
|
||||
- { id: 1, class: _ }
|
||||
- { id: 2, class: _ }
|
||||
- { id: 3, class: _ }
|
||||
body: |
|
||||
bb.1:
|
||||
%0(s64) = COPY $x0
|
||||
%1(s64) = COPY $x1
|
||||
%2(s64) = COPY $x2
|
||||
)MIR") + Twine(MIRFunc) + Twine("...\n"))
|
||||
.toNullTerminatedStringRef(S);
|
||||
std::unique_ptr<MIRParser> MIR;
|
||||
auto MMI = make_unique<MachineModuleInfo>(&TM);
|
||||
std::unique_ptr<Module> M =
|
||||
parseMIR(Context, MIR, TM, MIRString, "func", *MMI);
|
||||
return make_pair(std::move(M), std::move(MMI));
|
||||
}
|
||||
|
||||
static MachineFunction *getMFFromMMI(const Module *M,
|
||||
const MachineModuleInfo *MMI) {
|
||||
Function *F = M->getFunction("func");
|
||||
auto *MF = MMI->getMachineFunction(*F);
|
||||
return MF;
|
||||
}
|
||||
|
||||
static void collectCopies(SmallVectorImpl<unsigned> &Copies,
|
||||
MachineFunction *MF) {
|
||||
for (auto &MBB : *MF)
|
||||
for (MachineInstr &MI : MBB) {
|
||||
if (MI.getOpcode() == TargetOpcode::COPY)
|
||||
Copies.push_back(MI.getOperand(0).getReg());
|
||||
}
|
||||
}
|
||||
|
||||
class LegalizerHelperTest : public ::testing::Test {
|
||||
protected:
|
||||
LegalizerHelperTest() : ::testing::Test() {
|
||||
TM = createTargetMachine();
|
||||
if (!TM)
|
||||
return;
|
||||
ModuleMMIPair = createDummyModule(Context, *TM, "");
|
||||
MF = getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
|
||||
collectCopies(Copies, MF);
|
||||
EntryMBB = &*MF->begin();
|
||||
B.setMF(*MF);
|
||||
MRI = &MF->getRegInfo();
|
||||
B.setInsertPt(*EntryMBB, EntryMBB->end());
|
||||
}
|
||||
LLVMContext Context;
|
||||
std::unique_ptr<TargetMachine> TM;
|
||||
MachineFunction *MF;
|
||||
std::pair<std::unique_ptr<Module>, std::unique_ptr<MachineModuleInfo>>
|
||||
ModuleMMIPair;
|
||||
SmallVector<unsigned, 4> Copies;
|
||||
MachineBasicBlock *EntryMBB;
|
||||
MachineIRBuilder B;
|
||||
MachineRegisterInfo *MRI;
|
||||
};
|
||||
|
||||
#define DefineLegalizerInfo(Name, SettingUpActionsBlock) \
|
||||
class Name##Info : public LegalizerInfo { \
|
||||
public: \
|
||||
Name##Info(const TargetSubtargetInfo &ST) { \
|
||||
using namespace TargetOpcode; \
|
||||
const LLT s8 = LLT::scalar(8); \
|
||||
(void)s8; \
|
||||
const LLT s16 = LLT::scalar(16); \
|
||||
(void)s16; \
|
||||
const LLT s32 = LLT::scalar(32); \
|
||||
(void)s32; \
|
||||
const LLT s64 = LLT::scalar(64); \
|
||||
(void)s64; \
|
||||
do \
|
||||
SettingUpActionsBlock while (0); \
|
||||
computeTables(); \
|
||||
verify(*ST.getInstrInfo()); \
|
||||
} \
|
||||
};
|
||||
|
||||
static bool CheckMachineFunction(const MachineFunction &MF,
|
||||
StringRef CheckStr) {
|
||||
SmallString<512> Msg;
|
||||
raw_svector_ostream OS(Msg);
|
||||
MF.print(OS);
|
||||
auto OutputBuf = MemoryBuffer::getMemBuffer(Msg, "Output", false);
|
||||
auto CheckBuf = MemoryBuffer::getMemBuffer(CheckStr, "");
|
||||
SmallString<4096> CheckFileBuffer;
|
||||
FileCheckRequest Req;
|
||||
FileCheck FC(Req);
|
||||
StringRef CheckFileText =
|
||||
FC.CanonicalizeFile(*CheckBuf.get(), CheckFileBuffer);
|
||||
SourceMgr SM;
|
||||
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(CheckFileText, "CheckFile"),
|
||||
SMLoc());
|
||||
Regex PrefixRE = FC.buildCheckPrefixRegex();
|
||||
std::vector<FileCheckString> CheckStrings;
|
||||
FC.ReadCheckFile(SM, CheckFileText, PrefixRE, CheckStrings);
|
||||
auto OutBuffer = OutputBuf->getBuffer();
|
||||
SM.AddNewSourceBuffer(std::move(OutputBuf), SMLoc());
|
||||
return FC.CheckInput(SM, OutBuffer, CheckStrings);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user