Page MenuHomePhabricator

[PowerPC] Infrastructure work. Implement getting the opcode for a spill in one place.
ClosedPublic

Authored by stefanp on Feb 8 2018, 12:50 PM.

Details

Summary

Currently we compute the opcode for a given type of register spill in a couple of different places. This means that when a register class is added or changed multiple places have to be checked to make sure that everything is updated correctly. A new function getOpcodeForSpill should now be the only place to get the opcode for a given spilled register.

Diff Detail

Repository
rL LLVM

Event Timeline

stefanp created this revision.Feb 8 2018, 12:50 PM

Huge fan of refactorings :)

Some inline comments.

-eric

lib/Target/PowerPC/PPCInstrInfo.cpp
364 ↗(On Diff #133469)

Could probably just pass the subtarget down rather than have the index.

lib/Target/PowerPC/PPCInstrInfo.h
112 ↗(On Diff #133469)

Not a huge fan of this. Perhaps just have a local data structure inside the function?

lib/Target/PowerPC/PPCRegisterInfo.h
95 ↗(On Diff #133469)

This seems unrelated?

stefanp updated this revision to Diff 133878.Feb 12 2018, 9:02 AM

Addressed comments from reviewer and removed work that was not really related to this patch.
Will split out the work that was not really related into a separate patch.

nemanjai added inline comments.Feb 15 2018, 9:25 AM
lib/Target/PowerPC/PPCInstrInfo.cpp
76 ↗(On Diff #133878)

I like the approach of having named indices into the data structure. However, I find the names a little too tied to the current opcodes. It is especially confusing when the enumerator name doesn't match the actual opcode. For example, on P9, you'll spill a VSR register using PPC::STXV which you get through the OpcodesForSpillKey::PPC_STXVD2X enumerator.

Also, it is somewhat customary and aids readability to have the name of the enum encoded in the names of the enumerators.

Can you rename them to something like enum SpillOpcodeKey for the enum and SOK_Int4Spill, SOK_Float8Spill, or something along those lines.

356 ↗(On Diff #133878)

Not that this makes a very big difference, but it is a little more obvious what is happening if you just use std::find here.

1108 ↗(On Diff #133878)

I would remove the reliance on opcodes here. You have the register class. Check it and call setSpillsCr() and setSpillsVRSAVE() accordingly.

1114 ↗(On Diff #133878)

We are once again keeping a list of opcodes separately from the function that is supposed to have the definitive list of spill opcodes. So we aren't much better off.
I think would be a much cleaner approach to just use a query for whether an opcode is an X-Form or not. A similar trick is used in PPCRegisterInfo with the use of ImmToIdxMap.

I think the most reliable solution would be to implement this in the .td files with a mapping (similar to RecFormRel), but that can be left as a refactoring exercise for the future. For now, I'd implement a set of static function where one will contain the ImmToIdxMap and the rest will just perform queries on it:

static bool PPC::isXFormLdSt(unsigned Opcode);
static bool PPC::isDFormLdSt(unsigned Opcode);
static unsigned PPC::getXFormForDForm(unsigned Opcode);
static unsigned PPC::getDFormForXForm(unsigned Opcode);

Finally, in this function, I would assert that isXFormLdSt(Opcode) || isDFormLdSt(Opcode) to ensure that if we add another opcode for spilling/restoring, we don't break things.

lib/Target/PowerPC/PPCInstrInfo.h
129 ↗(On Diff #133878)

This is a member function and you have a PPCSubtarget data member. You can check whether you're compiling for Power9 there, can't you?

stefanp updated this revision to Diff 138976.Mar 19 2018, 12:24 PM

Added the XFormMemOp flag to the td files for the instructions the require it. This flag indicates that this instructions is a memory instruction and that it is an X-Form instruction.
Used a script to compare the modifications against the ISA to make sure that the correct instructions have the flag set.

This is starting to take shape quite nicely. I suspect you're planning a similar refactoring for the loads?

lib/Target/PowerPC/PPCInstr64Bit.td
248 ↗(On Diff #138976)

For all of these, you need to move the line below so that the " lines up under the 3 (i.e. parameters on multiple lines start at the same column).

1160 ↗(On Diff #138976)

Line too long.

lib/Target/PowerPC/PPCInstrFormats.td
117 ↗(On Diff #138976)

// Base class for all X-Form memory instructions

449 ↗(On Diff #138976)

This line is too long. In any case, do we have to redefine this? Seems like just copy-paste. Can we not just inherit from both XForm_base_r3xo and XFormMemOp without a re-definition?

1066 ↗(On Diff #138976)

Similarly here. Do we have to provide a definition or can we just inherit from XX1Form and XFormMemOp?

But perhaps I've missed something.

lib/Target/PowerPC/PPCInstrInfo.cpp
1093 ↗(On Diff #138976)

I prefer that we make arguments self-documenting when possible. Please instead of 0, pass PPC::NoRegister.

1112 ↗(On Diff #138976)

This seems like a strange way to get to the flags. Can you not just get(Opcode).TSFlags since you're in PPCInstrInfo already?

2318 ↗(On Diff #138976)

Please use a ternary operator here with 0/1. They should be equivalent, but I've come across UBSan failures where we load other values - so until we figure out whether that's a PPC problem or not, I'd prefer being explicit about this.

lib/Target/PowerPC/PPCInstrInfo.td
2025 ↗(On Diff #138976)

Line too long. I probably won't notice all of them, but please be careful about this.

stefanp updated this revision to Diff 139235.Mar 20 2018, 6:25 PM

Implemented the cleanup for the loads as well.
Addressed comments from the reviewer.

Also had to fixup one test file. After both the stores and the loads were fixed some instructions that had previously incorrectly set the setHasNonRISpills() flag no longer do so.

nemanjai accepted this revision.Mar 26 2018, 5:11 AM

Thank you for your patience with this review cycle and for cleaning this up. It looks much better now and it's really nice not to have to maintain lists of opcodes in multiple places that have to be kept in sync.

Other than the few minor nits which you should feel free to fix on the commit, LGTM.

lib/Target/PowerPC/PPCInstr64Bit.td
841 ↗(On Diff #139235)

It seems that you've fixed the indentation on the above, but not on any of these. Please indent the continuation line so that the first character (") is under the first character of the parameter in the line above (3).

lib/Target/PowerPC/PPCInstrInfo.cpp
91 ↗(On Diff #139235)

Don't forget periods on comments - complete sentences.

1077 ↗(On Diff #139235)

Something is off in the formatting of the signature. Please run clang-format on the new code you've added. I think you can run clang-format-diff on the actual diff, but I haven't tried that.

1180 ↗(On Diff #139235)

Just another minor suggestion, since this is probably going to be useful in other places, can you just provide something like static bool isXFormMemOp(unsigned Opcode); in PPCInstrInfo? Then we can query it wherever we need it. I don't imagine there's anything about that query that would require an actual instance of the class, but I haven't checked so it may not be possible to make it static.

lib/Target/PowerPC/PPCInstrInfo.h
72 ↗(On Diff #139235)

/// This instruction is an X-Form memory operation.

This revision is now accepted and ready to land.Mar 26 2018, 5:11 AM
stefanp added inline comments.Mar 26 2018, 10:13 AM
lib/Target/PowerPC/PPCInstrInfo.cpp
1180 ↗(On Diff #139235)

I've created the function bool isXFormMemOp(unsigned Opcode) const;. I was not able to make it static because I have to call MCInstrInfo::get.

This revision was automatically updated to reflect the committed changes.