This is an archive of the discontinued LLVM Phabricator instance.

[SystemZ] Rework subreg structure to avoid TableGen warning
Needs ReviewPublic

Authored by uweigand on Nov 27 2018, 11:07 AM.
This revision needs review, but there are no reviewers specified.

Details

Reviewers
None
Summary

We're currently seeing the following warning when building the SystemZ back-end:

warning: SubRegIndex SystemZ::subreg_h64 and SystemZ::subreg_h32 compose ambiguously as SystemZ::subreg_hh32 or SystemZ::subreg_h32

The problem appears to be that the VR128 class only has a high subreg defined (via subreg_h64), and that subreg itself also has a high subreg defined (via subreg_h32). TableGen then creates an automatic composition that allows directly accessing that composition as subreg_h32. However, the back-end also defined a *manual* composition of subreg_h64 and subreg_h32 that is defined as subreg_hh32., which is what causes the ambiguity.

The reason we need the explicit subreg_hh32 is that FP128 and GR128 both have both a low and a high 64-bit subreg (via subreg_l64 and subreg_h64), each of which itself has a high subreg via subreg_h32. Now the automatic TableGen composition here will allow accessing subreg_h32 (subreg_l64) implicitly as subreg_h32, and we need the explicit subreg_hh32 to access subreg_h32 (subreg_h64).

The reason why TableGen creates the implicit subreg_h32 (subreg_l64) but not subreg_h32 (subreg_h64) appears to be simply that in the list of subregs of FP128 and GR128, subreg_l64 is listed first.

This patch therefore removes the warning by simply reversing that order. This means that TableGen now automatically creates subreg_h32 as implicit composition for subreg_h32 (subreg_h64) on *all* register classes, and we create an explicit composition subreg_lh32 to access subreg_h32 (subreg_l64) on those registers that have a subreg_l64.

This causes no change in code generation, but avoids the warning.

Diff Detail

Event Timeline

uweigand created this revision.Nov 27 2018, 11:07 AM
bjope added a subscriber: bjope.Nov 28 2018, 3:02 AM
bjope added inline comments.
lib/Target/SystemZ/SystemZRegisterInfo.td
64

We used to have subregs specified from high to low in our OOT target. But nowadays we follow how it seems to be done for all in-tree target and specify them from low to high instead. There are some problems that comes with having them specified from high to low. I think mainly related to debug information.

If you look at SystemZGenRegisterInfo.inc before your patch you get this table with offset/size information:

extern const MCRegisterInfo::SubRegCoveredBits SystemZSubRegIdxRanges[] = {
  { 65535, 65535 },
  { 32, 32 },	// subreg_h32
  { 64, 64 },	// subreg_h64
  { 96, 32 },	// subreg_hh32
  { 64, 32 },	// subreg_hl32
  { 0, 32 },	// subreg_l32
  { 0, 64 },	// subreg_l64

with this patch you instead get

extern const MCRegisterInfo::SubRegCoveredBits SystemZSubRegIdxRanges[] = {
  { 65535, 65535 },
  { 32, 32 },	// subreg_h32
  { 64, 64 },	// subreg_h64
  { 0, 32 },	// subreg_l32
  { 0, 64 },	// subreg_l64
  { 32, 32 },	// subreg_lh32
  { 0, 32 },	// subreg_ll32
};

So both subreg_h32 and subreg_lh32 is basically pointing out bit 32-63 in a register (counting from least significant bit). When doing the subreg composition tablegen actually seems to assume that the subregs are specified from low to high when calculating the offsets.

The SubRegIdxRanges table is for example used (in calls to getSubRegIdxOffset)
by StackMaps::parseOperand and DwarfExpression::addMachineReg when generating DWARF expressions mapping a variable to a register.

If I remember correctly swapping order of subregister indices like this will result in a different order when using MCSubRegIterator. In our case this gave in different results in the last part of DwarfExpression::addMachineReg ("Otherwise, attempt to find a covering set of sub-register numbers").

I got a feeling that you wanted subreg_h32 to also act as the old subreg_hh32. That will often work, but as described above, the debug info would probably get messed up in some situations.

So if you do not care about debug info, maybe this patch is good as-is. If you care about debug info you might need to add some more hacks to work around problems in (at least) DwarfExpression::addMachineReg and StackMaps::parseOperand.

Some alternatives that perhaps can be tried (to avoid the ambiguity warnings) may involve:

  • Adding some dummy subreg index types to "fill the hole" when defining FPR64 and VR128 (they are currently lacking a low subreg).
  • Avoid reusing subreg index types for different types of registers. I'm not familiar with the SystemZ register hierarchy, so maybe this isn't an option, but the idea is to for example use the current subreg_h32, subreg_l64 etc for GPR and introduce some new indicies such as fsubreg_h32 for the FPR registers.

Not sure if any of the above really helps.
I guess the last resort would be to accept the solution in D50977.

Thanks for pointing out those debug info differences, I agree that this might be a problem.

As to using different subreg indices, that's what we used to have before @kparzysz 's patch here https://reviews.llvm.org/D50725 (which is the patch that introduced this warning). But as I understood that patch, it actually itself fixed a problem with subreg liveness tracking, see the commit message:

However, the ability to compose subreg_h64 with subreg_r32, and with
subreg_h32 and subreg_l32 at the same time makes the compositions be
treated as non-overlapping (leading to problems when tracking subreg
liveness). See D50468 for more details.

As to defining dummy low subregs, I'm also not sure that this is a good idea. These registers have the property that writing to the (singular) subreg may implicitly clobber the whole register, and I was given to understand that this fact can be modeled for TableGen by having the register *not* fully covered by subregs.

Trying a completely different track: the problem seems to be caused in the end by those implicitly defined subregs that TableGen comes up with. But at least for our target, those really only ever seem to cause problems and aren't really helpful at all. I'd much prefer to have no implicitly defined subregs at all, and explicitly define the four compositions I really need: subreg_ll32, subreg_lh32, subreg_hl32, and subreg_hh32. That would also make the usage of those subregs much clearer in back-end source code.

Could we not simply add a way for the target to tell TableGen to not define any implicit compositions?

Could we not simply add a way for the target to tell TableGen to not define any implicit compositions?

TableGen uses subregister indices (including the synthesized ones) to create a set of new register classes, which it then uses to calculate weights/costs that are later used by the compiler in register pressure calculation and scheduling. Turning off these compositions will have some sort of a domino effect, and it's not immediately clear what the final result will be.

An alternative would be to stop TableGen from associating subregister indices of a given register with its super-registers, i.e. doing:
"if Reg is a subregister of Super, and Reg has a subregister index subreg_idx, then add subreg_idx to subregister indices of Super". Instead, this should be a composition that first gets Reg from Super, and then applies subreg_idx. This will come with its own set of consequences, which aren't clear at the moment either.

My only concern here is understanding the consequences of this kind of a solution. As long as there is nothing unintended or unexpected, it should be fine. I guess the only way to make progress is to try it and see what happens.