Registers and isel type inference

So I tried adding a new register class to the x86 target:

  def WIDE32 : RegisterClass<"X86", [i32, f32], 32, (add GR32, FR32)>;

I thought this would be a harmless thing to do since the new register class is not being referenced anywhere. I was wrong, it caused all kinds of assertion failures from tablegen's isel pattern generator.

It appears that tablegen is inferring the 'type' of an individual register by enumerating all the register classes it appears in. Some things, like using implicit defs in SDNodes, only works for registers with a unique type. My WIDE32 class caused GR32 registers to no longer have a unique type, breaking the world.

This seems too fragile to me. Besides my current experiments with wide register classes, Blackfin's general purpose registers can hold both i32 and v2i16 types. Does that mean Blackfin instructions can't use GPR implicit defs as SDNode results?

I would like to fix this, but I am not sure how. I could:

- Disable type inference for individual registers entirely, or

- Add a ValueType field to the Register tablegen class, so types are not inferred by enumerating register classes.

Any suggestions?

/jakob

Jakob Stoklund Olesen <stoklund@2pi.dk> writes:

It appears that tablegen is inferring the 'type' of an individual
register by enumerating all the register classes it appears in. Some
things, like using implicit defs in SDNodes, only works for registers
with a unique type. My WIDE32 class caused GR32 registers to no
longer have a unique type, breaking the world.

I can't remeber the specific situation, but I remember running into
this kind of problem before.

This seems too fragile to me.

Yes, it is. :frowning:

- Disable type inference for individual registers entirely, or

- Add a ValueType field to the Register tablegen class, so types are
  not inferred by enumerating register classes.

I tend to think the second would be preferable, but how would we handle
registers than can hold different types of values?

                       -Dave

AFAIK, the type inference is only a convenience, you can always use explicit casts to get at the other types.

It's the use of HasOneImplicitDefWithKnownVT() that scares me, I don't think there is any workaround for that.

/jakob

/// HasOneImplicitDefWithKnownVT - If the instruction has at least one
/// implicit def and it has a known VT, return the VT, otherwise return
/// MVT::Other.
MVT::SimpleValueType CodeGenInstruction::
HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const {
  if (ImplicitDefs.empty()) return MVT::Other;

  // Check to see if the first implicit def has a resolvable type.
  Record *FirstImplicitDef = ImplicitDefs[0];
  assert(FirstImplicitDef->isSubClassOf("Register"));
  const std::vector<MVT::SimpleValueType> &RegVTs =
    TargetInfo.getRegisterVTs(FirstImplicitDef);
  if (RegVTs.size() == 1)
    return RegVTs[0];
  return MVT::Other;
}

Jakob Stoklund Olesen <stoklund@2pi.dk> writes:

- Disable type inference for individual registers entirely, or

- Add a ValueType field to the Register tablegen class, so types are
not inferred by enumerating register classes.

I tend to think the second would be preferable, but how would we handle
registers than can hold different types of values?

AFAIK, the type inference is only a convenience, you can always use
explicit casts to get at the other types.

True. Wouldn't that also work for implicit defs?

It's the use of HasOneImplicitDefWithKnownVT() that scares me, I don't
think there is any workaround for that.

Can you explain more? I'm not quiet following. What workaround is
needed? Are you saying that in the current system it's broken because
it relies on a single type for a register or that replacing it with
something in a new scheme won't be possible?

                                 -Dave

Jakob Stoklund Olesen <stoklund@2pi.dk> writes:

- Disable type inference for individual registers entirely, or

- Add a ValueType field to the Register tablegen class, so types are
not inferred by enumerating register classes.

I tend to think the second would be preferable, but how would we handle
registers than can hold different types of values?

AFAIK, the type inference is only a convenience, you can always use
explicit casts to get at the other types.

True. Wouldn't that also work for implicit defs?

Yes, I think so.

It's the use of HasOneImplicitDefWithKnownVT() that scares me, I don't
think there is any workaround for that.

Can you explain more? I'm not quiet following. What workaround is
needed? Are you saying that in the current system it's broken because
it relies on a single type for a register or that replacing it with
something in a new scheme won't be possible?

It seems that the current system only works for singly typed registers. I don't know if that is a fundamental constraint. Possibly not.

/jakob