This is an archive of the discontinued LLVM Phabricator instance.

[AArch64] Fix ldst-opt of multiple disjunct subregs.
ClosedPublic

Authored by fhahn on Jun 3 2020, 9:30 AM.

Details

Summary

Currently aarch64-ldst-opt will incorrectly rename registers with
multiple disjunct subregisters (e.g. result of LD3). This patch updates
the canRenameUpToDef to bail out if it encounters such a register class
that contains the register to rename.

Fixes PR46105.

Diff Detail

Event Timeline

fhahn created this revision.Jun 3 2020, 9:30 AM
efriedma added inline comments.Jun 3 2020, 11:48 AM
llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
1296

The fact that this doesn't whitelist specific opcodes makes me suspicious this is overlooking other potential issues. Some instructions with two outputs require that they aren't equal. A call instruction modifies a fixed register. Some instructions have restricted register classes.

fhahn marked an inline comment as done.Jun 3 2020, 12:31 PM
fhahn added inline comments.
llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
1296

I initially thought relying on renamable should be enough for the cases mentioned above. The code to pick registers should already only pick out of the most restrictive register class. It seemed to work quite well in practice so far. The problem with the disjunct sub register case is that those are represented as a single register in the result, but with as individual register when accessed by their users.

But it would probably be safer to have a whitelist. Do you know if there's a convenient way to do so for machine instructions, other than providing a really long list of opcodes?

efriedma added inline comments.Jun 4 2020, 9:25 AM
llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
1296

Hmm, you're right, "renamable" should have the right meaning.

Maybe worth clarifying the rules on whether isRenamable() should return true for something like the AArch64 LDP, where the two results have to be placed in distinct registers. I guess you could argue renaming two defs to the same register should never be legal anyway. even if the instructions set attaches some meaning to it. But I'm not sure this pass handles it correctly, in that case. (In particular, I'm concerned what would happen if one of the results of an ldp was marked "undef".)

That said, this check still seems a little fragile: it's depending on the specific structure of the AArch64 register file. In particular, the fact that you can't overwrite a "subregister" without overwriting the whole register. Probably worth explicitly noting.

fhahn marked an inline comment as done.Jun 4 2020, 3:05 PM
fhahn added inline comments.
llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
1296

Maybe worth clarifying the rules on whether isRenamable() should return true for something like the AArch64 LDP, where the two results have to be placed in distinct registers. I guess you could argue renaming two defs to the same register should never be legal anyway. even if the instructions set attaches some meaning to it. But I'm not sure this pass handles it correctly, in that case. (In particular, I'm concerned what would happen if one of the results of an ldp was marked "undef".)

I think the way we choose rename registers prevents using a register that is defined by the same instruction we are renaming. I can see if I can add a test case for that.

That said, this check still seems a little fragile: it's depending on the specific structure of the AArch64 register file. In particular, the fact that you can't overwrite a "subregister" without overwriting the whole register. Probably worth explicitly noting.

I agree it is a bit fragile unfortunately, as it is easy to miss subtleties of AArch64 MIR, but I guess the only way around that would be a whitelist. Would you be happy with the current approach (with an added note as you suggested?)

efriedma added inline comments.Jun 4 2020, 3:56 PM
llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
1296

Would you be happy with the current approach (with an added note as you suggested?)

It's probably okay if you call it out.

In the future, that might be something we should consider explicitly tracking, if we ever want to do this sort of thing in target-independent code.

fhahn updated this revision to Diff 268944.Jun 5 2020, 2:33 PM

Add note about relying on the structure of the AArch64 register file as suggested.

fhahn marked an inline comment as done.Jun 5 2020, 2:33 PM
fhahn added inline comments.
llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
1296

Thanks Eli, I added a note!

efriedma accepted this revision.Jun 5 2020, 5:40 PM

LGTM with one minor question.

I think the way we choose rename registers prevents using a register that is defined by the same instruction we are renaming. I can see if I can add a test case for that.

Did you ever come up with a testcase for this?

This revision is now accepted and ready to land.Jun 5 2020, 5:40 PM
fhahn added a comment.Jun 8 2020, 10:51 AM

LGTM with one minor question.

Thanks Eli!

I think the way we choose rename registers prevents using a register that is defined by the same instruction we are renaming. I can see if I can add a test case for that.

Did you ever come up with a testcase for this?

I pushed a test with an LDP with an undef operand in 22c2dc5931a73eebf2a2e2b2d7a8cf757907dc3e. The undef register would be the next one to pick, but it is skipped (because it is also a def). Was that what you had in mind?

I pushed a test with an LDP with an undef operand in 22c2dc5931a73eebf2a2e2b2d7a8cf757907dc3e. The undef register would be the next one to pick, but it is skipped (because it is also a def). Was that what you had in mind?

Yes; thanks.

This revision was automatically updated to reflect the committed changes.