Revert rr340111 "[GISel]: Add Legalization/lowering code for bit counting operations"
It causes LegalizerHelperTest.LowerBitCountingCTTZ1 to fail. llvm-svn: 340186
This commit is contained in:
parent
531319388d
commit
918930adf9
|
@ -49,7 +49,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
LegalizerHelper(MachineFunction &MF);
|
LegalizerHelper(MachineFunction &MF);
|
||||||
LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI);
|
|
||||||
|
|
||||||
/// Replace \p MI by a sequence of legal instructions that can implement the
|
/// 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
|
/// same operation. Note that this means \p MI may be deleted, so any iterator
|
||||||
|
@ -113,8 +112,6 @@ private:
|
||||||
void extractParts(unsigned Reg, LLT Ty, int NumParts,
|
void extractParts(unsigned Reg, LLT Ty, int NumParts,
|
||||||
SmallVectorImpl<unsigned> &VRegs);
|
SmallVectorImpl<unsigned> &VRegs);
|
||||||
|
|
||||||
LegalizeResult lowerBitCount(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
|
||||||
|
|
||||||
MachineRegisterInfo &MRI;
|
MachineRegisterInfo &MRI;
|
||||||
const LegalizerInfo &LI;
|
const LegalizerInfo &LI;
|
||||||
};
|
};
|
||||||
|
|
|
@ -668,11 +668,6 @@ public:
|
||||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||||
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred,
|
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred,
|
||||||
unsigned Res, unsigned Op0, unsigned Op1);
|
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
|
/// Build and insert a \p Res = G_FCMP \p Pred\p Op0, \p Op1
|
||||||
///
|
///
|
||||||
|
@ -701,10 +696,6 @@ public:
|
||||||
/// \return a MachineInstrBuilder for the newly created instruction.
|
/// \return a MachineInstrBuilder for the newly created instruction.
|
||||||
MachineInstrBuilder buildSelect(unsigned Res, unsigned Tst,
|
MachineInstrBuilder buildSelect(unsigned Res, unsigned Tst,
|
||||||
unsigned Op0, unsigned Op1);
|
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,
|
/// Build and insert \p Res = G_INSERT_VECTOR_ELT \p Val,
|
||||||
/// \p Elt, \p Idx
|
/// \p Elt, \p Idx
|
||||||
|
|
|
@ -83,11 +83,6 @@ def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFFECTS, intrinsic_void>;
|
||||||
def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFFECTS, intrinsic_w_chain>;
|
def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFFECTS, intrinsic_w_chain>;
|
||||||
def : GINodeEquiv<G_BR, br>;
|
def : GINodeEquiv<G_BR, br>;
|
||||||
def : GINodeEquiv<G_BSWAP, bswap>;
|
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
|
// Broadly speaking G_LOAD is equivalent to ISD::LOAD but there are some
|
||||||
// complications that tablegen must take care of. For example, Predicates such
|
// complications that tablegen must take care of. For example, Predicates such
|
||||||
|
|
|
@ -17,13 +17,12 @@
|
||||||
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
||||||
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
|
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
|
||||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||||
#include "llvm/CodeGen/TargetInstrInfo.h"
|
|
||||||
#include "llvm/CodeGen/TargetLowering.h"
|
#include "llvm/CodeGen/TargetLowering.h"
|
||||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/MathExtras.h"
|
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG_TYPE "legalizer"
|
#define DEBUG_TYPE "legalizer"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -34,10 +33,6 @@ LegalizerHelper::LegalizerHelper(MachineFunction &MF)
|
||||||
MIRBuilder.setMF(MF);
|
MIRBuilder.setMF(MF);
|
||||||
}
|
}
|
||||||
|
|
||||||
LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI)
|
|
||||||
: MRI(MF.getRegInfo()), LI(LI) {
|
|
||||||
MIRBuilder.setMF(MF);
|
|
||||||
}
|
|
||||||
LegalizerHelper::LegalizeResult
|
LegalizerHelper::LegalizeResult
|
||||||
LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
|
LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
|
||||||
LLVM_DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
|
LLVM_DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
|
||||||
|
@ -989,12 +984,6 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
|
||||||
|
|
||||||
return UnableToLegalize;
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1035,112 +1024,3 @@ 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}})) {
|
|
||||||
MIRBuilder.buildInstr(
|
|
||||||
TargetOpcode::G_SUB, MI.getOperand(0).getReg(),
|
|
||||||
MIRBuilder.buildConstant(Ty, Len),
|
|
||||||
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,5 +12,4 @@ set(LLVM_LINK_COMPONENTS
|
||||||
add_llvm_unittest(GlobalISelTests
|
add_llvm_unittest(GlobalISelTests
|
||||||
LegalizerInfoTest.cpp
|
LegalizerInfoTest.cpp
|
||||||
PatternMatchTest.cpp
|
PatternMatchTest.cpp
|
||||||
LegalizerHelperTest.cpp
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
//===- 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
|
|
|
@ -1,190 +0,0 @@
|
||||||
//===- 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…
Reference in New Issue