This is an archive of the discontinued LLVM Phabricator instance.

[GlobalISel][TableGen] Fix handling of default operands
ClosedPublic

Authored by rovka on May 10 2017, 12:11 AM.

Details

Summary

When looping through a destination pattern's operands to decide how many
default operands we need to introduce, we used to count the "expanded"
number of operands. So if one default operand would be rendered as 2
values, we'd count it as 2 operands, when in fact it needs to count as
only 1 operand regardless of how many values it expands to.

This turns out to be a problem only in some very specific cases, e.g.
when we have one operand with multiple default values followed by more
operands with default values (see the new test). In such a situation
we'd stop looping before looking at all the operands, and then error out
assuming that we don't have enough default operands to make up the
shortfall.

At the moment this only affects ARM.

The patch removes the loop counting default operands entirely and
assumes that we'll have to introduce values for any default operand that
we find (i.e. we're assuming it cannot be given as a child at all). It
also extracts the code for adding renderers for default operands into a
helper method.

Diff Detail

Repository
rL LLVM

Event Timeline

rovka created this revision.May 10 2017, 12:11 AM
rovka added inline comments.May 10 2017, 12:19 AM
utils/TableGen/GlobalISelEmitter.cpp
1519 ↗(On Diff #98408)

Hi Daniel,

Did you have some case in mind when counting things this way? It seems that for ARM instructions the predicate operand (which expands to 2 values) should be counted as only 1 operand. I tried to concoct other complicated cases with default operands but my TableGen-fu isn't strong enough and I couldn't find anything relevant in the existing instruction descriptions for any target (but I may have been looking at it the wrong way).

I ran TableGen with/without this patch for a lot of targets (including some that don't support GlobalISel yet) and the only one where I see any difference in the generated code or in the -warn-on-skipped-patterns -debug-only=gisel-emitter is ARM.

Please let me know if I'm missing something.

dsanders added inline comments.May 10 2017, 2:12 AM
utils/TableGen/GlobalISelEmitter.cpp
1519 ↗(On Diff #98408)

Hi Diana,

I didn't have a particular case in mind when doing it this way. My expectation was that we needed to determine whether the MachineInstr had a complete set of MachineOperands and fill in any that are missing from the default operands. Therefore we needed to count how many default MachineOperands we added to the MachineInstr.

Do you have a particular test case I could look at to see the difference in behaviour?

Looking at this code again, I'm also wondering if there might be a bug involving ComplexPatterns with multiple operands since that's a situation where Dst->getNumChildren() is not equal to the number of MachineOperands added to the instruction.

dsanders added inline comments.May 10 2017, 2:16 AM
utils/TableGen/GlobalISelEmitter.cpp
1519 ↗(On Diff #98408)

Do you have a particular test case I could look at to see the difference in behaviour?

I mean from ARM. In the meantime, I'll look into the one in this patch.

dsanders added inline comments.May 10 2017, 7:18 AM
utils/TableGen/GlobalISelEmitter.cpp
1519 ↗(On Diff #98408)

The bug originates from DstI.Operands.size() which doesn't have the value I'd expect on XORManyDefaults. I'd expected it to be 5 (1 def, 1 explicitly specified operands, 2 default operands from m1Z, and another from Z) but it comes out as 4 (1 def, 3 uses). As a result, the code is mis-counting the number of MO's to expect and the number that are supplied and therefore adds the wrong number of default operands.

I've also noticed that this patch unconditionally adds the default operands this will lead to duplicated operands if a pattern supplies them. I'm currently working on a patch to fix both cases.

dsanders added inline comments.May 10 2017, 8:10 AM
utils/TableGen/GlobalISelEmitter.cpp
1519 ↗(On Diff #98408)

Hmm. I'm sure I encountered a case where an OperandWithOptionalOps shouldn't insert the DefaultOps because that's what caused me to write this code but I'm unable to find it now and my attempts at supplying the optional operands in a pattern have failed.

If you agree that OperandWithOptionalOps and friends are really operands that are never provided in a pattern then I think we should add them unconditionally as per this patch. We should also be able to remove this loop and check isSubClassOf("OperandWithDefaultOps") where we currently have DefaultOperands.count(I)

rovka added inline comments.May 10 2017, 3:29 PM
utils/TableGen/GlobalISelEmitter.cpp
1519 ↗(On Diff #98408)

On ARM you can look at ADD / SUB.
I agree that DstI.Operands are a bit fishy, I'm not sure how they interact with ComplexPatterns. In any case, without a relevant test we should just go with the simplest code for now and do our best to detect funny situations. I'll have another stab at it without the loop.

rovka updated this revision to Diff 98623.May 11 2017, 5:53 AM
rovka edited the summary of this revision. (Show Details)

Removed the first loop and extracted a helper for adding renderers for default ops. I think this makes the body of the loop easier to read.

I've kept pretty much the same error detection as before. I think there might still be pathological cases that could pass by undetected, but I can't produce any with my current TableGen skills.

Anyway, with this and some changes that I committed today we can remove the handwritten code for G_ADD and G_SUB in the ARMInstructionSelector.

dsanders accepted this revision.May 16 2017, 7:58 AM

LGTM.

utils/TableGen/GlobalISelEmitter.cpp
1519 ↗(On Diff #98408)

In any case, without a relevant test we should just go with the simplest code for now and do our best to detect funny situations.

Yep, I agree.

This revision is now accepted and ready to land.May 16 2017, 7:58 AM
This revision was automatically updated to reflect the committed changes.