This is an archive of the discontinued LLVM Phabricator instance.

[legalize-types] Remove stale entries from SoftenedFloats.
ClosedPublic

Authored by fhahn on Jan 29 2017, 2:53 PM.

Details

Summary

When replacing a SDValue, we should remove the replaced value from
SoftenedFloats (and possibly the other maps as well?).

When we revisit a Node because it needs analyzing again, we have to
remove all result values from SoftenedFloats (and possibly other maps?).

This fixes the fp128 test failures with expensive checks for X86.

I think we probably should also remove the values from the other maps
(PromotedIntegers and so on), let me know what you think.

Diff Detail

Event Timeline

fhahn created this revision.Jan 29 2017, 2:53 PM
fhahn edited the summary of this revision. (Show Details)
fhahn added a comment.Jan 30 2017, 4:31 AM

D29180 tries to fix the same issues, by updating DAGTypeLegalizer::PerformExpensiveChecks to accept values in ReplacedValues and SoftenedFloats. I still think it would be better to properly clean up the stale entries.

Just a discussion about approach, as we both worked on the same problem :)

It looks like all these arrays, PromotedIntegers, SoftededFloats etc are in fact parts of one array that contains mapping of nodes to their replacement, they differ only by operation that created the replacement. They are useful only for error checking, otherwise their separate existence is useless. If it is true, we could have only one array, ReplacedValues that contained all such replacements. For the sake of checking we could keep few bits along with the replacement (in the form of PointerIntPair for instance) and check them when the replacement node is extracted or updated. Such checks would be cheap, they do not require search in tables, and they could be enabled in regular debug builds.

I have feeling that implementation of the legalizer is overcomplicated, and if we get rid of separate arrays for replacement nodes, the legalizer will become more clear and, may be, faster.

What do you think about such solution?

fhahn added a comment.Jan 30 2017, 8:54 AM

In principle it sounds like a good idea to refactor the code and it indeed seems like the checks could be simplified. The main problem I think is that most of the code in DAGTypeLegalizer has not been touched for a very long time so it may be quite hard to find a reviewer. I think it would be ideal to merge this fix first and merge a bigger refactor later.

fhahn added a subscriber: hfinkel.Feb 1 2017, 5:15 AM

@hfinkel Thanks again for the review Hal. Any chance you could also have a look at D29265, which also deals with type legalization?

@hfinkel Thanks again for the review Hal. Any chance you could also have a look at D29265, which also deals with type legalization?

I don't quite understand what's going on here. Can we visit a node, decide it needs to be a softened float, and then visit it again and make a different decision? Can't we already have used the result from the map?

fhahn added a comment.Feb 1 2017, 9:33 AM

@hfinkel Thanks again for the review Hal. Any chance you could also have a look at D29265, which also deals with type legalization?

I don't quite understand what's going on here. Can we visit a node, decide it needs to be a softened float, and then visit it again and make a different decision? Can't we already have used the result from the map?

For the X86 fp128 tests, the following is going on as far as I understand:

There is a node t9: f128 = select t8, t2, t4. During legalization of this node the following happens

  • the result is softened
  • the operands are scanned
  • One integer operand is promoted
  • The node has to be re-analyzed again, which means it's marked as NewNode again
  • On the next iteration of the main loop, PerformExpensiveChecks fails because the result of t9: f128 = select t8, t2, t4 has been added to SoftenedFloats, but the node isn't marked as Processed yet.

But after thinking about it a little more I feel like there should be a better solution than my patch.

pirama added a reviewer: chh.Feb 1 2017, 9:56 AM
pirama edited edge metadata.Feb 1 2017, 10:00 AM

+chh for comments on fp128 legalization. I think a common ReplacedValues map that also tracks the kind of legalization performed would be useful - at the very least to understand how the different legalization steps interact and let us code in sanity checks.

chh edited edge metadata.Feb 1 2017, 11:08 AM

Could we have more info in this change or D29180?
Which recent change broke which tests? Could it be reverted?
What were the before and after regression IL trees?
Do we need new unit test?

Last time I fixed a regression related to fp128 in D26942.
The regression was introduced by a cleanup with nice intention,
but we just do not have enough unit tests. We only found
the regression too late to revert, when we tried to compile
a large Android code base. Yes, fp128 could work for all other
targets except Android's x86-64. The SoftenFloat* functions got into
infinite loop. So I would be very careful now about removing nodes
from SoftenedFloats.

In D29265#663586, @chh wrote:

Could we have more info in this change or D29180?
Which recent change broke which tests? Could it be reverted?
What were the before and after regression IL trees?
Do we need new unit test?

There is no failing test or apparent problems in the legalizer. The intent is to run builds with expensive checks enabled on regular basis. To do this we need reach clean state, when all tests pass.

The real problem in this that expensive checks have been turned off for a long time and algorithm of checking is out of sync with current implementation of the legalizer. Both this change and D29180 try to fix the check algorithm so that it won't report problems were they absent.

Last time I fixed a regression related to fp128 in D26942.
The regression was introduced by a cleanup with nice intention,
but we just do not have enough unit tests. We only found
the regression too late to revert, when we tried to compile
a large Android code base. Yes, fp128 could work for all other
targets except Android's x86-64. The SoftenFloat* functions got into
infinite loop. So I would be very careful now about removing nodes
from SoftenedFloats.

Absolutely agree. I think we should change only the check algorithm because the legalizer itself works as needed, at least we don't see any evidence that something is wrong with it.

The particular problem solved by this patch is that the check algorithm does not allow a replacement node be in both SoftenedFloats and ReplacedValues. I think it is wrong requirement. Essentially all the maps SoftenedFloats, ReplacedValues and other are in fact the same thing, a map from a node to its replacement. Nodes from ReplacedValues are allowed to be overridden, why those from SoftenedFloats are not? Probably the legalizer could be implemented in such way that the aforementioned maps remain disjoint, but current implementation breaks this condition.

srhines added a subscriber: srhines.Feb 1 2017, 6:23 PM
chh added a comment.Feb 13 2017, 10:07 AM

Could you modify existing fp128 unit tests, especially those for Android target, to run with both current configuration and the "expensive checks". How do you enable the "expensive checks"?

I remember dealing with some differences between SoftenedFloats and ReplacedValues maps, when I twisted various configurations to get fp128 values not softened for some operators and saved in mmx registers. I am afraid that a lot of cases were not tested with the "expensive checks" enabled.

RKSimon edited edge metadata.Feb 13 2017, 11:35 AM
In D29265#675246, @chh wrote:

Could you modify existing fp128 unit tests, especially those for Android target, to run with both current configuration and the "expensive checks". How do you enable the "expensive checks"?

I remember dealing with some differences between SoftenedFloats and ReplacedValues maps, when I twisted various configurations to get fp128 values not softened for some operators and saved in mmx registers. I am afraid that a lot of cases were not tested with the "expensive checks" enabled.

To enable all expensive checks is through a build define: LLVM_ENABLE_EXPENSIVE_CHECKS, to perform it on tests you have to enable the specific check in question, in this case "-enable-legalize-types-checking"

Really we need build bot coverage that has LLVM_ENABLE_EXPENSIVE_CHECKS defined by default, but that can't happen until we have fixed all the current failures.

chh added a comment.Feb 13 2017, 3:14 PM

In D29180, I saw that fp16.ll was changed to run with -enable-legalize-types-checking. Could you add extra test runs with the -enable-legalize-types-checking flag, into current fp128 tests and some other tests depending on SoftenedFloats? Then some of those runs will pass only if this change to LegalizeTypes.cpp is applied, right?

Although I am not sure about the impact of this change to all SoftenedFloats targets, at least I have not seen regression in my local simple Android x86-64 build test. I hope someone else more familiar with this module can review this change. Thanks.

fhahn updated this revision to Diff 90232.Mar 1 2017, 2:43 PM

Thank you for all the comments and sorry for my late response, I was away for the last 4 weeks.

I've added -enable-legalize-types-checking to guard against the problem even when building without expensive checks. I've also done a quick git bisect and it seems like the failure was introduced in D11438, but after I think it looks more like the failure surfaced because the patch enabled softening for fp128 types.

chh accepted this revision.Mar 3 2017, 3:59 PM
This revision is now accepted and ready to land.Mar 3 2017, 3:59 PM
This revision was automatically updated to reflect the committed changes.
fhahn closed this revision.Mar 4 2017, 4:12 AM