Skip to content
12 changes: 6 additions & 6 deletions llvm/include/llvm/ADT/PointerUnion.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,14 @@ class PointerUnion
}
};

template <typename ...PTs>
bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
template <typename... PTs>
bool operator==(PointerUnion<PTs...> LHS, PointerUnion<PTs...> RHS) {
return (!LHS && !RHS) || LHS.getOpaqueValue() == RHS.getOpaqueValue();
}

template <typename ...PTs>
bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
template <typename... PTs>
bool operator!=(PointerUnion<PTs...> LHS, PointerUnion<PTs...> RHS) {
return !operator==(LHS, RHS);
}

template <typename ...PTs>
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/RegisterBankInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,10 @@ const TargetRegisterClass *RegisterBankInfo::constrainGenericRegister(

// If the register already has a class, fallback to MRI::constrainRegClass.
auto &RegClassOrBank = MRI.getRegClassOrRegBank(Reg);
if (isa<const TargetRegisterClass *>(RegClassOrBank))
if (isa_and_present<const TargetRegisterClass *>(RegClassOrBank))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think either of these 2 instances should ever encounter a register without a set class or bank, this is papering over a different bug?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Input gMIR to instruction selector shouldn't contain registers without class/bank.
Such registers are created during instruction selection if an imported SelectionDAG pattern contains several instructions in the "destination DAG" of the pattern:

def : GCNPat <
  (UniformUnaryFrag<fabs> (v2f16 SReg_32:$src)),
  (S_AND_B32 SReg_32:$src, (S_MOV_B32 (i32 0x7fff7fff)))
>;

This is what -gen-global-isel generates for this pattern:

        GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s1,
        GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(AMDGPU::S_MOV_B32),
        GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
        ...
        GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
        GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(AMDGPU::S_AND_B32),
        ...
        GIR_AddSimpleTempRegister, /*InsnID*/0, /*TempRegID*/0,
        GIR_RootConstrainSelectedInstOperands,

GIR_MakeTempReg creates a register without class/bank for the result of the S_MOV_B32. The register gets its class when executing GIR_ConstrainSelectedInstOperands action, which calls this function, which calls MRI.setRegClass() at the end.

I don't know if this should be considered a bug. If it should, I can try to address it separately (probably in #121270).


(Unrelated to this PR). Note that the type of the temporary register is s1. It is chosen arbitrarily.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GIR_MakeTempReg creates a register without class/bank for the result of the S_MOV_B32.

As I mentioned in the other PR this is broken. In no context should an incomplete virtual register be used by an instruction

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears there is another context when class/bank may not be set: 7e1f66d

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After regbankselect / in the selection pass, there must be a class or bank set. The null/null case is only valid before that, when a generic vreg must have a type

return MRI.constrainRegClass(Reg, &RC);

const RegisterBank *RB = cast<const RegisterBank *>(RegClassOrBank);
const auto *RB = dyn_cast_if_present<const RegisterBank *>(RegClassOrBank);
// Otherwise, all we can do is ensure the bank covers the class, and set it.
if (RB && !RB->covers(RC))
return nullptr;
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3708,10 +3708,10 @@ const TargetRegisterClass *
SIRegisterInfo::getConstrainedRegClassForOperand(const MachineOperand &MO,
const MachineRegisterInfo &MRI) const {
const RegClassOrRegBank &RCOrRB = MRI.getRegClassOrRegBank(MO.getReg());
if (const RegisterBank *RB = dyn_cast<const RegisterBank *>(RCOrRB))
if (const auto *RB = dyn_cast_if_present<const RegisterBank *>(RCOrRB))
return getRegClassForTypeOnBank(MRI.getType(MO.getReg()), *RB);

if (const auto *RC = dyn_cast<const TargetRegisterClass *>(RCOrRB))
if (const auto *RC = dyn_cast_if_present<const TargetRegisterClass *>(RCOrRB))
return getAllocatableClass(RC);

return nullptr;
Expand Down
13 changes: 10 additions & 3 deletions llvm/unittests/ADT/PointerUnionTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,16 @@ TEST_F(PointerUnionTest, Comparison) {
EXPECT_TRUE(i4 != l4);
EXPECT_TRUE(f4 != l4);
EXPECT_TRUE(l4 != d4);
EXPECT_TRUE(i4null != f4null);
EXPECT_TRUE(i4null != l4null);
EXPECT_TRUE(i4null != d4null);
EXPECT_TRUE(i4null == f4null);
EXPECT_FALSE(i4null != f4null);
EXPECT_TRUE(i4null == l4null);
EXPECT_FALSE(i4null != l4null);
EXPECT_TRUE(i4null == d4null);
EXPECT_FALSE(i4null != d4null);
EXPECT_FALSE(i4null == i4);
EXPECT_TRUE(i4null != i4);
EXPECT_FALSE(i4null == f4);
EXPECT_TRUE(i4null != f4);
}

TEST_F(PointerUnionTest, Null) {
Expand Down
Loading