Commit 5d87b5d2 authored by Quentin Colombet's avatar Quentin Colombet
Browse files

[GISelKnownBits] Add support for PHIs

Teach the GISelKnowBits analysis how to deal with PHI operations.
PHIs are essentially COPYs happening on edges, so we can just reuse
the code for COPY.

This is NFC COPY-wise has we leave Depth untouched when calling
computeKnownBitsImpl for COPYs, like it was before this patch.
Increasing Depth is however required for PHIs as they may loop back to
themselves and we would end up in an infinite loop if we were not
increasing Depth.

Differential Revision: https://reviews.llvm.org/D73317
parent 81b700e3
Loading
Loading
Loading
Loading
+33 −14
Original line number Diff line number Diff line
@@ -120,20 +120,39 @@ void GISelKnownBits::computeKnownBitsImpl(Register R, KnownBits &Known,
    TL.computeKnownBitsForTargetInstr(*this, R, Known, DemandedElts, MRI,
                                      Depth);
    break;
  case TargetOpcode::COPY: {
    MachineOperand Dst = MI.getOperand(0);
    MachineOperand Src = MI.getOperand(1);
    // Look through trivial copies but don't look through trivial copies of the
    // form `%1:(s32) = OP %0:gpr32` known-bits analysis is currently unable to
    // determine the bit width of a register class.
  case TargetOpcode::COPY:
  case TargetOpcode::G_PHI:
  case TargetOpcode::PHI: {
    Known.One = APInt::getAllOnesValue(BitWidth);
    Known.Zero = APInt::getAllOnesValue(BitWidth);
    // Destination registers should not have subregisters at this
    // point of the pipeline, otherwise the main live-range will be
    // defined more than once, which is against SSA.
    assert(MI.getOperand(0).getSubReg() == 0 && "Is this code in SSA?");
    // PHI's operand are a mix of registers and basic blocks interleaved.
    // We only care about the register ones.
    for (unsigned Idx = 1; Idx < MI.getNumOperands(); Idx += 2) {
      const MachineOperand &Src = MI.getOperand(Idx);
      Register SrcReg = Src.getReg();
      // Look through trivial copies and phis but don't look through trivial
      // copies or phis of the form `%1:(s32) = OP %0:gpr32`, known-bits
      // analysis is currently unable to determine the bit width of a
      // register class.
      //
      // We can't use NoSubRegister by name as it's defined by each target but
      // it's always defined to be 0 by tablegen.
    if (Dst.getSubReg() == 0 /*NoSubRegister*/ && Src.getReg().isVirtual() &&
        Src.getSubReg() == 0 /*NoSubRegister*/ &&
        MRI.getType(Src.getReg()).isValid()) {
      // Don't increment Depth for this one since we didn't do any work.
      computeKnownBitsImpl(Src.getReg(), Known, DemandedElts, Depth);
      if (SrcReg.isVirtual() && Src.getSubReg() == 0 /*NoSubRegister*/ &&
          MRI.getType(SrcReg).isValid()) {
        // For COPYs we don't do anything, don't increase the depth.
        computeKnownBitsImpl(SrcReg, Known2, DemandedElts,
                             Depth + (Opcode != TargetOpcode::COPY));
        Known.One &= Known2.One;
        Known.Zero &= Known2.Zero;
      } else {
        // We know nothing.
        Known = KnownBits(BitWidth);
        break;
      }
    }
    break;
  }
+3 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ createDummyModule(LLVMContext &Context, const LLVMTargetMachine &TM,
---
...
name: func
tracksRegLiveness: true
registers:
  - { id: 0, class: _ }
  - { id: 1, class: _ }
@@ -106,6 +107,8 @@ registers:
  - { id: 3, class: _ }
body: |
  bb.1:
    liveins: $x0, $x1, $x2, $x4

    %0(s64) = COPY $x0
    %1(s64) = COPY $x1
    %2(s64) = COPY $x2
+104 −0
Original line number Diff line number Diff line
@@ -56,6 +56,110 @@ TEST_F(GISelMITest, TestKnownBitsCstWithClass) {
  EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue());
}

// Check that we are able to track bits through PHIs
// and get the intersections of everything we know on each operand.
TEST_F(GISelMITest, TestKnownBitsCstPHI) {
  StringRef MIRString = "  bb.10:\n"
                        "  %10:_(s8) = G_CONSTANT i8 3\n"
                        "  %11:_(s1) = G_IMPLICIT_DEF\n"
                        "  G_BRCOND %11(s1), %bb.11\n"
                        "  G_BR %bb.12\n"
                        "\n"
                        "  bb.11:\n"
                        "  %12:_(s8) = G_CONSTANT i8 2\n"
                        "  G_BR %bb.12\n"
                        "\n"
                        "  bb.12:\n"
                        "  %13:_(s8) = PHI %10(s8), %bb.10, %12(s8), %bb.11\n"
                        "  %14:_(s8) = COPY %13\n";
  setUp(MIRString);
  if (!TM)
    return;
  Register CopyReg = Copies[Copies.size() - 1];
  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
  Register SrcReg = FinalCopy->getOperand(1).getReg();
  Register DstReg = FinalCopy->getOperand(0).getReg();
  GISelKnownBits Info(*MF);
  KnownBits Res = Info.getKnownBits(SrcReg);
  EXPECT_EQ((uint64_t)2, Res.One.getZExtValue());
  EXPECT_EQ((uint64_t)0xfc, Res.Zero.getZExtValue());

  KnownBits Res2 = Info.getKnownBits(DstReg);
  EXPECT_EQ(Res.One.getZExtValue(), Res2.One.getZExtValue());
  EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue());
}

// Check that we report we know nothing when we hit a
// non-generic register.
// Note: this could be improved though!
TEST_F(GISelMITest, TestKnownBitsCstPHIToNonGenericReg) {
  StringRef MIRString = "  bb.10:\n"
                        "  %10:gpr32 = MOVi32imm 3\n"
                        "  %11:_(s1) = G_IMPLICIT_DEF\n"
                        "  G_BRCOND %11(s1), %bb.11\n"
                        "  G_BR %bb.12\n"
                        "\n"
                        "  bb.11:\n"
                        "  %12:_(s8) = G_CONSTANT i8 2\n"
                        "  G_BR %bb.12\n"
                        "\n"
                        "  bb.12:\n"
                        "  %13:_(s8) = PHI %10, %bb.10, %12(s8), %bb.11\n"
                        "  %14:_(s8) = COPY %13\n";
  setUp(MIRString);
  if (!TM)
    return;
  Register CopyReg = Copies[Copies.size() - 1];
  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
  Register SrcReg = FinalCopy->getOperand(1).getReg();
  Register DstReg = FinalCopy->getOperand(0).getReg();
  GISelKnownBits Info(*MF);
  KnownBits Res = Info.getKnownBits(SrcReg);
  EXPECT_EQ((uint64_t)0, Res.One.getZExtValue());
  EXPECT_EQ((uint64_t)0, Res.Zero.getZExtValue());

  KnownBits Res2 = Info.getKnownBits(DstReg);
  EXPECT_EQ(Res.One.getZExtValue(), Res2.One.getZExtValue());
  EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue());
}

// Check that we manage to process PHIs that loop on themselves.
// For now, the analysis just stops and assumes it knows nothing,
// eventually we could teach it how to properly track phis that
// loop back.
TEST_F(GISelMITest, TestKnownBitsCstPHIWithLoop) {
  StringRef MIRString =
      "  bb.10:\n"
      "  %10:_(s8) = G_CONSTANT i8 3\n"
      "  %11:_(s1) = G_IMPLICIT_DEF\n"
      "  G_BRCOND %11(s1), %bb.11\n"
      "  G_BR %bb.12\n"
      "\n"
      "  bb.11:\n"
      "  %12:_(s8) = G_CONSTANT i8 2\n"
      "  G_BR %bb.12\n"
      "\n"
      "  bb.12:\n"
      "  %13:_(s8) = PHI %10(s8), %bb.10, %12(s8), %bb.11, %14(s8), %bb.12\n"
      "  %14:_(s8) = COPY %13\n"
      "  G_BR %bb.12\n";
  setUp(MIRString);
  if (!TM)
    return;
  Register CopyReg = Copies[Copies.size() - 1];
  MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg);
  Register SrcReg = FinalCopy->getOperand(1).getReg();
  Register DstReg = FinalCopy->getOperand(0).getReg();
  GISelKnownBits Info(*MF);
  KnownBits Res = Info.getKnownBits(SrcReg);
  EXPECT_EQ((uint64_t)0, Res.One.getZExtValue());
  EXPECT_EQ((uint64_t)0, Res.Zero.getZExtValue());

  KnownBits Res2 = Info.getKnownBits(DstReg);
  EXPECT_EQ(Res.One.getZExtValue(), Res2.One.getZExtValue());
  EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue());
}

TEST_F(GISelMITest, TestKnownBitsPtrToIntViceVersa) {
  StringRef MIRString = "  %3:_(s16) = G_CONSTANT i16 256\n"
                        "  %4:_(p0) = G_INTTOPTR %3\n"