diff --git a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp --- a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp @@ -120,20 +120,37 @@ 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. - // - // 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); + 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 registes 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 (SrcReg.isVirtual() && Src.getSubReg() == 0 /*NoSubRegister*/ && + MRI.getType(SrcReg).isValid()) { + computeKnownBitsImpl(SrcReg, Known2, DemandedElts, Depth + 1); + Known.One &= Known2.One; + Known.Zero &= Known2.Zero; + } else { + // We know nothing. + Known = KnownBits(BitWidth); + break; + } } break; } diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -99,6 +99,7 @@ --- ... name: func +tracksRegLiveness: true registers: - { id: 0, class: _ } - { id: 1, class: _ } @@ -106,6 +107,8 @@ - { id: 3, class: _ } body: | bb.1: + liveins: $x0, $x1, $x2, $x4 + %0(s64) = COPY $x0 %1(s64) = COPY $x1 %2(s64) = COPY $x2 diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp @@ -56,6 +56,110 @@ 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; + unsigned CopyReg = Copies[Copies.size() - 1]; + MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg); + unsigned SrcReg = FinalCopy->getOperand(1).getReg(); + unsigned 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; + unsigned CopyReg = Copies[Copies.size() - 1]; + MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg); + unsigned SrcReg = FinalCopy->getOperand(1).getReg(); + unsigned 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, TestKnownBitsCstWithLoopg) { + 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; + unsigned CopyReg = Copies[Copies.size() - 1]; + MachineInstr *FinalCopy = MRI->getVRegDef(CopyReg); + unsigned SrcReg = FinalCopy->getOperand(1).getReg(); + unsigned 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"