This is an archive of the discontinued LLVM Phabricator instance.

[X86] Special-case ADD of two identical registers in convertToThreeAddress
ClosedPublic

Authored by foad on Sep 30 2021, 6:37 AM.

Details

Summary

X86InstrInfo::convertToThreeAddress would convert this:

%1:gr32 = ADD32rr killed %0:gr32(tied-def 0), %0:gr32, implicit-def dead $eflags

to this:

undef %2.sub_32bit:gr64 = COPY killed %0:gr32
undef %3.sub_32bit:gr64_nosp = COPY %0:gr32
%1:gr32 = LEA64_32r killed %2:gr64, 1, killed %3:gr64_nosp, 0, $noreg

Note that in the ADD32rr, %0 was used twice and the first use had a kill
flag, which is MachineInstr::addRegisterKilled does.

In the converted code, each use of %0 is copied to a new reg, and the
first COPY inherits the kill flags from the ADD32rr. This causes
machine verification to fail (if you force it to run after
TwoAddressInstructionPass) because the second COPY uses %0 after it is
killed. Note that machine verification is currently disabled after
TwoAddressInstructionPass but this is a step towards being able to
enable it.

Fix this by not inserting more than one COPY from the same source
register.

Diff Detail

Event Timeline

foad created this revision.Sep 30 2021, 6:37 AM
foad requested review of this revision.Sep 30 2021, 6:37 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 30 2021, 6:37 AM
  1. I don't know if it's safe to rely on the kill flag being on the first operand that uses a particular reg. If not I'll rework the patch.
  2. I don't know how to test this without removing the false from addPass(&TwoAddressInstructionPassID, false) in TargetPassConfig, which will currently still fail for a few other reasons.
MatzeB added a subscriber: MatzeB.Oct 1 2021, 9:34 AM

On a general note, having the kill flag appear only on one operand seems sketchy to me:

Note that in the ADD32rr, %0 was used twice and the first use had a kill flag, which is MachineInstr::addRegisterKilled does.

Glancing at addRegisterKilled seems to me like it would add the flag to all uses within an instruction (at least for vregs). There is a shortcut that aborts if it finds a pre-existing killflag where it wouldn't continue adding it to the other operands. But if that is the case then some other code beforehand got us into the odd situation of having the kill flag only on some operands.

I think ideally we would enforce that kill flag use is consistent within in instruction (either all uses of the same vreg use or do not use the kill flag). But it seems we are currently not so that would be work cleaning that up and enforcing it with the machine verifier. Anyway that seems out of the scope of this change, so for now we probably have to assume the kill flag is inconsistent between operands.

I don't know if it's safe to rely on the kill flag being on the first operand that uses a particular reg. If not I'll rework the patch.

This seems accidental. I think ideally we would enforce consistency of the flag within an instruction. Short of that we better not assume anything like just the first operand having a kill flag...

I don't know how to test this without removing the false from addPass(&TwoAddressInstructionPassID, false) in TargetPassConfig, which will currently still fail for a few other reasons.

Maybe using llc -run-pass liveintervals,twiaddressinstruction in a .mir test would work?

foad added a reviewer: MatzeB.Oct 1 2021, 10:21 AM
foad updated this revision to Diff 376587.Oct 1 2021, 11:44 AM

Rebase on a test case that I will pre-commit.

I don't know if it's safe to rely on the kill flag being on the first operand that uses a particular reg. If not I'll rework the patch.

This seems accidental. I think ideally we would enforce consistency of the flag within an instruction. Short of that we better not assume anything like just the first operand having a kill flag...

That's definitely accidental and I agree it would be best to enforce that the flag is set on all operands within an instruction but this is, like Matthias said, outside of the scope of this PR.

foad updated this revision to Diff 376854.Oct 4 2021, 3:50 AM

Don't rely on the order of kill flags.

foad edited the summary of this revision. (Show Details)Oct 4 2021, 3:50 AM
MatzeB accepted this revision.Oct 4 2021, 9:48 AM

Could you try if the suggested edits restore the kill flag in the test?

If yes then LGTM.

llvm/lib/Target/X86/X86InstrInfo.cpp
1213–1214

Can we use MI.killsRegister(SrcReg); here, so things work as expected in case of inconsistent kill-flags as discussed earlier?

1227–1228
llvm/test/CodeGen/X86/twoaddr-mul2.ll
11 ↗(On Diff #376854)

Why isn't this COPY killed [[COPY]] anymore? Are we loosing a kill-flag now?

This revision is now accepted and ready to land.Oct 4 2021, 9:48 AM
foad updated this revision to Diff 377249.Oct 5 2021, 7:59 AM

Switch to MIR test case.

foad retitled this revision from [X86] Copy registers in reverse order in convertToThreeAddress to [X86] Special-case ADD of two identical registers in convertToThreeAddress.Oct 5 2021, 8:00 AM
foad added inline comments.Oct 5 2021, 9:33 AM
llvm/test/CodeGen/X86/twoaddr-mul2.ll
11 ↗(On Diff #376854)

Because the use is copied from the second use operand in %1:gr32 = ADD32rr killed %0:gr32(tied-def 0), %0:gr32, implicit-def dead $eflags, which does not have the killed flag.

Yes we could implement more code here to try to preserve the kill flag from the first use operand, but I thought it might be better to fix the root cause instead, and work out why the second use operand of the ADD32rr was not killed?

foad updated this revision to Diff 377297.Oct 5 2021, 10:54 AM

Use MI.killsRegister to detect kills even if only some uses of SrcReg
are marked as killed.

foad added inline comments.Oct 7 2021, 4:22 AM
llvm/lib/Target/X86/X86InstrInfo.cpp
1238

@MatzeB are you happy with this bit? Your suggested changes didn't go quite far enough to get a "kill" on the inserted COPY.

MatzeB accepted this revision.Oct 7 2021, 10:51 AM

Still LGTM

llvm/lib/Target/X86/X86InstrInfo.cpp
1238

Yes makes sense.

.addReg(Src, getKillRegState(isKill)) above.

This revision was landed with ongoing or failed builds.Oct 7 2021, 11:50 AM
This revision was automatically updated to reflect the committed changes.