[llvm] r340111 - [GISel]: Add Legalization/lowering code for bit counting operations
Aditya Nandakumar via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 20 11:11:44 PDT 2018
Hi Mikael,
Thanks for looking into this (and for getting this reverted). I missed this email. I’m looking into it now.
Thanks
Aditya
> On Aug 20, 2018, at 12:48 AM, Mikael Holmén <mikael.holmen at ericsson.com> wrote:
>
> Hi Aditya,
>
> If I compile with gcc (5.4.0) I get unittest failures with your commit:
>
> elxhw7c132-n7[llvm-patch]: build-all-bbigcc/unittests/CodeGen/GlobalISel/GlobalISelTests --gtest_filter=LegalizerHelperTest.LowerBitCountingCTTZ1
> [==========] Running 1 test from 1 test case.
> [----------] Global test environment set-up.
> [----------] 1 test from LegalizerHelperTest
> [ RUN ] LegalizerHelperTest.LowerBitCountingCTTZ1
> CheckFile:7:9: error: CHECK: expected string not found in input
> CHECK: [[CTLZ:%[0-9]+]]:_(s64) = G_CTLZ [[AND1]]:_
> ^
> Output:13:3: note: scanning from here
> %4:_(s64) = G_SUB %10:_, %9:_
> ^
> Output:13:3: note: with variable "AND1" equal to "%8"
> %4:_(s64) = G_SUB %10:_, %9:_
> ^
> ../unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp:70: Failure
> Value of: CheckMachineFunction(*MF, CheckStr)
> Actual: false
> Expected: true
> [ FAILED ] LegalizerHelperTest.LowerBitCountingCTTZ1 (6 ms)
> [----------] 1 test from LegalizerHelperTest (7 ms total)
>
> [----------] Global test environment tear-down
> [==========] 1 test from 1 test case ran. (7 ms total)
> [ PASSED ] 0 tests.
> [ FAILED ] 1 test, listed below:
> [ FAILED ] LegalizerHelperTest.LowerBitCountingCTTZ1
>
> 1 FAILED TEST
>
> Regards,
> Mikael
>
> On 08/18/2018 02:01 AM, Aditya Nandakumar via llvm-commits wrote:
>> Author: aditya_nandakumar
>> Date: Fri Aug 17 17:01:54 2018
>> New Revision: 340111
>> URL: http://llvm.org/viewvc/llvm-project?rev=340111&view=rev
>> Log:
>> [GISel]: Add Legalization/lowering code for bit counting operations
>> https://reviews.llvm.org/D48847#inline-448257
>> Ported legalization expansions for CTLZ/CTTZ from DAG to GISel.
>> Reviewed by rtereshin.
>> Added:
>> llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
>> llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.h
>> Modified:
>> llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
>> llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
>> llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
>> llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
>> llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt
>> Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h?rev=340111&r1=340110&r2=340111&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h (original)
>> +++ llvm/trunk/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h Fri Aug 17 17:01:54 2018
>> @@ -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;
>> };
>> Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h?rev=340111&r1=340110&r2=340111&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h (original)
>> +++ llvm/trunk/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h Fri Aug 17 17:01:54 2018
>> @@ -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
>> Modified: llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td?rev=340111&r1=340110&r2=340111&view=diff
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td (original)
>> +++ llvm/trunk/include/llvm/Target/GlobalISel/SelectionDAGCompat.td Fri Aug 17 17:01:54 2018
>> @@ -83,6 +83,11 @@ def : GINodeEquiv<G_INTRINSIC_W_SIDE_EFF
>> 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
>> Modified: llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp?rev=340111&r1=340110&r2=340111&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp (original)
>> +++ llvm/trunk/lib/CodeGen/GlobalISel/LegalizerHelper.cpp Fri Aug 17 17:01:54 2018
>> @@ -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(Machine
>> 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,
>> 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);
>> }
>> }
>> @@ -1023,4 +1034,113 @@ LegalizerHelper::fewerElementsVector(Mac
>> return Legalized;
>> }
>> }
>> +}
>> +
>> +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;
>> + }
>> + }
>> }
>> Modified: llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt?rev=340111&r1=340110&r2=340111&view=diff
>> ==============================================================================
>> --- llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt (original)
>> +++ llvm/trunk/unittests/CodeGen/GlobalISel/CMakeLists.txt Fri Aug 17 17:01:54 2018
>> @@ -12,4 +12,5 @@ set(LLVM_LINK_COMPONENTS
>> add_llvm_unittest(GlobalISelTests
>> LegalizerInfoTest.cpp
>> PatternMatchTest.cpp
>> + LegalizerHelperTest.cpp
>> )
>> Added: llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp?rev=340111&view=auto
>> ==============================================================================
>> --- llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp (added)
>> +++ llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp Fri Aug 17 17:01:54 2018
>> @@ -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
>> Added: llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.h
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.h?rev=340111&view=auto
>> ==============================================================================
>> --- llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.h (added)
>> +++ llvm/trunk/unittests/CodeGen/GlobalISel/LegalizerHelperTest.h Fri Aug 17 17:01:54 2018
>> @@ -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);
>> +}
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list