This is an archive of the discontinued LLVM Phabricator instance.

Propagate tied operands when copying a MachineInstr.
ClosedPublic

Authored by simon_tatham on Oct 7 2022, 2:54 AM.

Details

Summary

MachineInstr's copy constructor works by calling the addOperand method
to add each operand of the old MachineInstr to the new one, one by
one. But addOperand deliberately avoids trying to replicate ties
between operands, on the grounds that the tie refers to operands by
index, and the indices aren't necessarily finalized yet.

This led to a code generation fault when the machine pipeliner cloned
an Arm conditional instruction, and lost the tie between the output
register and the input value to be used when the condition failed to
execute.

Diff Detail

Event Timeline

simon_tatham created this revision.Oct 7 2022, 2:54 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 7 2022, 2:54 AM
simon_tatham requested review of this revision.Oct 7 2022, 2:54 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 7 2022, 2:54 AM

This sounds OK to me, and is probably how I would fix this. But it will effect more than just the MachinePipeliner, anything that goes through CloneMachineInstr. Looking at where that is uses, that seems like most the uses should be OK. I'm don't think many backends will use these implicit tied uses, and copying them sounds more correct during a clone.

There are used for inline assembly though. There is a bit of code in the Pipeliner that:

MachineInstr *NewMI = MF.CloneMachineInstr(OldMI);
// Check for tied operands in inline asm instructions. This should be handled
// elsewhere, but I'm not sure of the best solution.
if (OldMI->isInlineAsm()) {
  ... tie operands together

Can this be removed now? I don't see any pipelining + inline assembly tests in the test suite. And with inline asm usually acting as a barrier it wasn't easy for me to make an example. It may be trying to tie operands together twice now.

arsenm added a subscriber: arsenm.Oct 9 2022, 9:23 AM

Is there a missing verifier check?

This sounds OK to me, and is probably how I would fix this. But it will effect more than just the MachinePipeliner, anything that goes through CloneMachineInstr. Looking at where that is uses, that seems like most the uses should be OK. I'm don't think many backends will use these implicit tied uses, and copying them sounds more correct during a clone.

Yes, I think that specifically because this is in the copy constructor, it seems to me that the expectation is that the output MachineInstr looks semantically identical to the input one.

Can this be removed now? I don't see any pipelining + inline assembly tests in the test suite.

I agree that it looks as if that code ought to be redundant now. But I tried removing that code and my fix, and the only test that failed was my own new one. So I also agree that we don't seem to have any tests of it, unfortunately!

Is there a missing verifier check?

That sounds very plausible. I did try -verify-machineinstrs on the example that originally failed for me, and was a bit surprised that it reported no problems and still generated incorrect output code. So yes, it might well be that someone who knows the MachineVerifier might be able to add a check for ties based on checking the MachineInstr against the MCID. But it's large and has many confusing subfunctions and I'm not familiar enough with it to be able to dash that off quickly, so I hope it need not block fixing the actual correctness issue.

This sounds OK to me, and is probably how I would fix this. But it will effect more than just the MachinePipeliner, anything that goes through CloneMachineInstr. Looking at where that is uses, that seems like most the uses should be OK. I'm don't think many backends will use these implicit tied uses, and copying them sounds more correct during a clone.

Yes, I think that specifically because this is in the copy constructor, it seems to me that the expectation is that the output MachineInstr looks semantically identical to the input one.

Can this be removed now? I don't see any pipelining + inline assembly tests in the test suite.

I agree that it looks as if that code ought to be redundant now. But I tried removing that code and my fix, and the only test that failed was my own new one. So I also agree that we don't seem to have any tests of it, unfortunately!

I agree that this is an improvement for the copy constructor. I worry that that if that code is left is and there is a case where the inlineasm is copied, we end up trying to copy the tied-operands twice and end up crashing. It seems that the pipeliner is OK with inline-asm in general, so it's probably worth making a test case if we can.

Going by the new test llvm/test/CodeGen/Thumb2/pipeliner-inlineasm, the two pieces of code don't conflict if both are present. But the code in the pipeliner also doesn't seem to be necessary any more. So I've revised this patch to remove it, and do all tie propagation centrally in MachineInstr's copy constructor.

I think the changes in this patch, moving the handling to tied operands to CloneMachineInstr and removing the code
from ModuleSchedule.cpp, is a good change. I'm sure there is a test case for this in the Hexagon internal repo. Adding
@sgundapa in case he is able to check? I don't remember why I added this code to MachinePipeliner rather than
change CloneMachineInstr, other than I was trying to quickly fix a pipeliner bug and wasn't sure what effect changing
CloneMachineInstr would cause. But it does make more sense to put it in CloneMachineInstr.

dmgreen accepted this revision.Oct 11 2022, 7:03 AM

Yeah this SGTM. It might have a larger effect than just the MachinePipeliner, but it seems like a better, less error prone default for cloning instructions. Providing you run update_mir_test_checks on the new file, LGTM.

This revision is now accepted and ready to land.Oct 11 2022, 7:03 AM
This revision was automatically updated to reflect the committed changes.