This is an archive of the discontinued LLVM Phabricator instance.

Clarify semantic of reserved registers.
ClosedPublic

Authored by MatzeB on Nov 14 2016, 4:06 PM.

Details

Summary

This commit should clarify semantics and issues related to reserved registers. Extend the machine verifier to check for the super register rule.

Diff Detail

Repository
rL LLVM

Event Timeline

MatzeB updated this revision to Diff 77908.Nov 14 2016, 4:06 PM
MatzeB retitled this revision from to Clarify semantic of reserved registers..
MatzeB updated this object.
MatzeB added a reviewer: qcolombet.
MatzeB set the repository for this revision to rL LLVM.
MatzeB added a subscriber: llvm-commits.
arsenm added a subscriber: arsenm.Nov 14 2016, 4:10 PM
arsenm added inline comments.
include/llvm/Target/TargetRegisterInfo.h
492

s/life/live

This is an early patch to get the discussion going. Some things are still missing:

  • A bunch of targets violate the superreg rule (e.g. AArch64 reserving XZR but not tuples like %XZR_X0). AArch64, ARM, Hexagon, Mips and PowerPC currently fail the verifier. So far it looks like actual target bugs to me.
  • I think we should add this rule: "If a reserved subregister has subregister at least one subregister (or register unit) must be reserved", yes?

This is an early patch to get the discussion going. Some things are still missing:

  • A bunch of targets violate the superreg rule (e.g. AArch64 reserving XZR but not tuples like %XZR_X0). AArch64, ARM, Hexagon, Mips and PowerPC currently fail the verifier. So far it looks like actual target bugs to me.
  • I think we should add this rule: "If a reserved subregister has subregister at least one subregister (or register unit) must be reserved", yes?

AMDGPU has hit bugs from only reserving the super register before, and not the subregisters

MatzeB updated this revision to Diff 77915.Nov 14 2016, 4:23 PM
MatzeB marked an inline comment as done.

Update comment, include the "at least 1 subregister must be reserved rule".

For the next version: I will add the check for the 1 subregister reserved rule; I'll move the checking from the machine verifier into MachineRegisterInfo::freezeReserved() (under #ifndef NDEBUG of course).

qcolombet edited edge metadata.Nov 14 2016, 5:26 PM

Hi Matthias,

Thanks for clarifying that. That could lead to subtle bugs :).

I miss one thing in this patch: a helper function that given a set of reserved registers adds the super registers (transitively). Then hint in the comment that TargetRegisterInfo::getReservedRegs could use such helper.

Cheers,
-Quentin

include/llvm/Target/TargetRegisterInfo.h
496

Looks good to me.

Hi Matthias,

Thanks for clarifying that. That could lead to subtle bugs :).

I miss one thing in this patch: a helper function that given a set of reserved registers adds the super registers (transitively). Then hint in the comment that TargetRegisterInfo::getReservedRegs could use such helper.

Indeed, I am currently fixing the existing targets and added such a function for them anyway. BTW: It seems most of the problems are benign, a common pattern is the 64bit registers not getting reserved in 32bit mode. That should be fine as you probably won't see a 64bit operand in 32bit mode anyway. However fixing it properly is worth it so we can add the checking/assert.

Cheers,
-Quentin

These new rules break existing use in Mips :-(

Mips has 32bit floatregs F0-F31, each pair forms a double reg (F0+F1=D0, F2+F3=D1, ...). There is an option in the mips backend that aims at disabling the odd F registers, so 32bit float values only end up in F0, F2, F4, ... In this case it is actually expected that the register allocator still assigns the D0-D15 as usual even though the would indirectly use F1,F3,...

Is there another way to handle this in the mips target?

escha added a subscriber: escha.Nov 14 2016, 8:17 PM

Thanks for looking into this painful little bundle of nested semantic problems.

sdardis edited edge metadata.Nov 15 2016, 4:30 AM

@MatzeB Yes, we could rework the floating point register set definitions and instruction definitions to use difference register classes depending the floating point ABI used. Unfortunately this requires six register classes in that case, three for the no odd single precision case and 3 more for the case where odd single precisions are available. Those register classes would eliminate the need to reserve the odd registers for no-oddsp.

That's a non-trivial change which will take some time as other plumbing may need to be fixed/changed.

Some background:
The difficulty/delay arises in that MIPS has several different FPU configurations: 32bit FPUs supporting 64bit operations using a pair of single precision registers, and full 64bit FPUs. We have two floating pointing ABIs: nooddsp where the odd single precision registers are not to be used at all, and oddsp where all single precision registers can be used.

@MatzeB Yes, we could rework the floating point register set definitions and instruction definitions to use difference register classes depending the floating point ABI used. Unfortunately this requires six register classes in that case, three for the no odd single precision case and 3 more for the case where odd single precisions are available. Those register classes would eliminate the need to reserve the odd registers for no-oddsp.

That's a non-trivial change which will take some time as other plumbing may need to be fixed/changed.

Some background:
The difficulty/delay arises in that MIPS has several different FPU configurations: 32bit FPUs supporting 64bit operations using a pair of single precision registers, and full 64bit FPUs. We have two floating pointing ABIs: nooddsp where the odd single precision registers are not to be used at all, and oddsp where all single precision registers can be used.

Hi,

after working on this for a while I think the proposed rules here should rather be guidelines. They are the right thing in many situations, but not all. I reworked the commit in a way that backends can call assertAllSuperRegsMarked() at their own discretion.

MatzeB updated this revision to Diff 78039.Nov 15 2016, 11:15 AM
MatzeB edited edge metadata.
  • Make the rules less strict, marking superregs is only a recommendation now
  • Add convenience functions so that it is easy in a target to mark all super regs and to verify whether all super regs are marked
  • Fix a bug where AArch64 did not reserve tuples containing the zero register
MatzeB updated this revision to Diff 78040.Nov 15 2016, 11:19 AM
MatzeB edited edge metadata.

Cleanup, remove some accidentally included changes.

kparzysz added inline comments.
include/llvm/Target/TargetRegisterInfo.h
493

If it's ignored by liveness tracking, then there is no meaning to "live" or "dead". Maybe you could rephrase it (and the previous bullet) as something like "is ignored from the liveness point of view".

496

This should be a standalone sentence, not a bullet in the list.

MatzeB marked 2 inline comments as done.Nov 15 2016, 11:54 AM
MatzeB added inline comments.
include/llvm/Target/TargetRegisterInfo.h
493

If you take a usual liveness definition of the value will potentially be read, then they are very much live.
It's just the actual implementation of liveness tracking in LLVM that decides to not track the liveness (we avoid adding special rules for reserved regs for little gain).

496

ok.

arsenm added inline comments.Nov 15 2016, 11:58 AM
lib/CodeGen/TargetRegisterInfo.cpp
43–47

This is almost the same as SIRegisterInfo::reserveRegisterTuples, except that uses MCRegAliasIterator. Is there any real difference?

MatzeB marked 2 inline comments as done.Nov 15 2016, 12:31 PM
MatzeB added inline comments.
lib/CodeGen/TargetRegisterInfo.cpp
43–47

Given that there are no arbitrary alias definitions in your target (I see no Aliases = in your tablegen files) it has the same effect as long as you only apply it to lowest level registers and not to a tuple.

qcolombet added inline comments.Nov 15 2016, 4:06 PM
include/llvm/Target/TargetRegisterInfo.h
950

We miss a return here or change the comment.

950

What about cases where we have mixed uses:

  • Reserved as name; only the tagged name must be reserved (e.g., x86, mips, like you told me about)
  • Reserved by ABI; all the super reg must be marked as reserved

This API does not all to check that.

MatzeB updated this revision to Diff 78612.Nov 18 2016, 6:55 PM
MatzeB edited edge metadata.
  • Add a way to specify a list of exceptions for assertSuperRegsMarked() so we can use it in situations like X86 as well.
MatzeB updated this revision to Diff 78613.Nov 18 2016, 6:59 PM
MatzeB edited edge metadata.

Fix problem in assertAllSuperRegsMarked() exception handling.

qcolombet accepted this revision.Nov 30 2016, 11:59 AM
qcolombet edited edge metadata.

Hi Matthias,

LGTM.
One suggestion though.

Cheers,
-Quentin

include/llvm/Target/TargetRegisterInfo.h
950

I'd change the API a bit:

  • Rename in checkAllSuperRegsMarked
  • Return bool
  • Have the users assert on that bool.

The rationale is that in release build assert(checkAllSuperRegsMarked) can be optimized out, but assertAllSuperRegsMarked would still cause a call to an empty function.

This revision is now accepted and ready to land.Nov 30 2016, 11:59 AM
MatzeB added inline comments.Nov 30 2016, 12:48 PM
include/llvm/Target/TargetRegisterInfo.h
950

Actually my first version returned a bool and had the assert() on the caller. I changed my mind because I wanted the display a message listing the register causing the problem and writing to stderr in a check function felt wrong. Would you think writing to stderr is fine anyway? Or should I just get rid of the message and have people figure out the problematic register in a debugger?

This revision was automatically updated to reflect the committed changes.