[llvm] r340111 - [GISel]: Add Legalization/lowering code for bit counting operations

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 20 23:07:21 PDT 2018



On 08/20/2018 10:11 PM, Aditya Nandakumar wrote:
> Also, the right fix is to make the order deterministic (pulling the 
> nested builds outside) which I’ll do - I just attached the CHECKDAG 
> patch to see if this is the issue.

It passes fir me with this too.

> 
> The right patch (if this is indeed an ordering issue) would be something 
> like.
> 
>> On Aug 20, 2018, at 12:10 PM, Aditya Nandakumar via llvm-commits <llvm-commits at lists.llvm.org> wrote:
>> 
>> Hi Mikael,
>> 
>> It doesn’t reproduce for me unfortunately (on MacOS). I suspect this might be due to this nested call
>>      MIRBuilder.buildInstr(
>>          TargetOpcode::G_SUB, MI.getOperand(0).getReg(),
>>          MIRBuilder.buildConstant(Ty, Len),
>>          MIRBuilder.buildInstr(TargetOpcode::G_CTLZ, Ty, MIBTmp));
>> Where the order of building G_CONSTANT and G_CTLZ may not be the same.
>> 
>> Would it be possible for you to test it with this patch (you’ll also need to revert 340186 which reverted this patch). I’d appreciate it if you’re able to test this.
>> 
>> <diffOrdering.patch>
>> 
>> 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
>> 
>> _______________________________________________
>> 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