[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:00 PDT 2018



On 08/20/2018 09:10 PM, Aditya Nandakumar 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.
> 

The test passes for me with this patch, even when I compile with gcc.

/Mikael


> 
> 
> 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