This is an archive of the discontinued LLVM Phabricator instance.

[SelectionDAG][AArch64] Restrict matchUnaryPredicate to only handle SPLAT_VECTOR for scalable vectors.
ClosedPublic

Authored by craig.topper on Feb 5 2021, 1:20 PM.

Details

Summary

fde24661718c7812a20a10e518cd853e8e060107 added support for
scalable vectors to matchUnaryPredicate by handling SPLAT_VECTOR in
addition to BUILD_VECTOR. This was used to enabled UDIV/SDIV/UREM/SREM
by constant expansion in BuildUDIV/BuildSDIV in TargetLowering.cpp

The caller there expects to call getBuildVector from the match factors.
This leads to a crash right now if there is a SPLAT_VECTOR of
fixed vectors since the number of vectors won't match the number
of elements.

To fix this, this patch updates the callers to check the opcode
instead of whether the type is fixed or scalable. This assumes
that only 3 opcodes are handled by matchUnaryPredicate so
I've added an assertion to the final else to check that opcode.

Diff Detail

Event Timeline

craig.topper created this revision.Feb 5 2021, 1:20 PM
craig.topper requested review of this revision.Feb 5 2021, 1:20 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 5 2021, 1:20 PM

I think for fixed length vectors we have a number of uses of the predicate matchers that assume it will be called once per vector element - some create additional vectors on the fly inside the matchers etc.

Looking in lib/CodeGen/SelectionDAG/TargetLowering.cpp at the places where we call matchUnaryPredicate it looks like "VT.isFixedVector" and "VT.isScalableVector" calls are being used as proxies for BUILD_VECTOR and SPLAT_VECTOR. I suspect that checking for BUILD_VECTOR and SPLAT_VECTOR instead would give the right behaviour? Not suggesting that has to be fixed in this patch though...

Looking in lib/CodeGen/SelectionDAG/TargetLowering.cpp at the places where we call matchUnaryPredicate it looks like "VT.isFixedVector" and "VT.isScalableVector" calls are being used as proxies for BUILD_VECTOR and SPLAT_VECTOR. I suspect that checking for BUILD_VECTOR and SPLAT_VECTOR instead would give the right behaviour? Not suggesting that has to be fixed in this patch though...

Yeah that would work, but it feels a little like leaking implementation details of matchUnaryPredicate into the caller.

Looking in lib/CodeGen/SelectionDAG/TargetLowering.cpp at the places where we call matchUnaryPredicate it looks like "VT.isFixedVector" and "VT.isScalableVector" calls are being used as proxies for BUILD_VECTOR and SPLAT_VECTOR. I suspect that checking for BUILD_VECTOR and SPLAT_VECTOR instead would give the right behaviour? Not suggesting that has to be fixed in this patch though...

Yeah that would work, but it feels a little like leaking implementation details of matchUnaryPredicate into the caller.

Agreed. I think it's better than checking the vector type, though. Maybe matchUnaryPredicate could return something to indicate the "root" it matched against?

Looking in lib/CodeGen/SelectionDAG/TargetLowering.cpp at the places where we call matchUnaryPredicate it looks like "VT.isFixedVector" and "VT.isScalableVector" calls are being used as proxies for BUILD_VECTOR and SPLAT_VECTOR. I suspect that checking for BUILD_VECTOR and SPLAT_VECTOR instead would give the right behaviour? Not suggesting that has to be fixed in this patch though...

Yeah that would work, but it feels a little like leaking implementation details of matchUnaryPredicate into the caller.

Agreed. I think it's better than checking the vector type, though. Maybe matchUnaryPredicate could return something to indicate the "root" it matched against?

Have you got a use case where you actually need to know this?

Looking in lib/CodeGen/SelectionDAG/TargetLowering.cpp at the places where we call matchUnaryPredicate it looks like "VT.isFixedVector" and "VT.isScalableVector" calls are being used as proxies for BUILD_VECTOR and SPLAT_VECTOR. I suspect that checking for BUILD_VECTOR and SPLAT_VECTOR instead would give the right behaviour? Not suggesting that has to be fixed in this patch though...

Yeah that would work, but it feels a little like leaking implementation details of matchUnaryPredicate into the caller.

Agreed. I think it's better than checking the vector type, though. Maybe matchUnaryPredicate could return something to indicate the "root" it matched against?

Have you got a use case where you actually need to know this?

Depends on what behavior we want for this interface and code like in BuildUDIV/BuildSDIV. Here are some options

  1. SPLAT_VECTOR on fixed vectors causes matchUnaryPredicate to visit the splat value NumElements times. BuildUDIV/BuildSDIV pushes to vectors num elements times and calls getBuildVector. DAGCombine will probably create SPLAT_VECTOR from those build_vectors.
  2. SPLAT_VECTOR on fixed vectors causes matchUnaryPredicate to visit the splat value 1 time. BuildUDIV/BuildSDDIV push to the vectors 1 times and call getSplatBuildVector. DAGCombine will probably create SPLAT_VECTOR from those build_vectors.
  3. SPLAT_VECTOR on fixed vectors causes matchUnaryPredicate to visit the splat value 1 time. BuildUDIV/BuildSDDIV push to the vectors 1 times and call getSplatVector to create SPLAT_VECTOR.

I believe @david-arm is proposing option 3.

matchUnaryPredicate was added to try to encourage people to add full (non-uniform) vector support without too much legwork - a lot of combines still just have scalar / uniform support only. I'm just worried that if they have to do extra work to handle different vector cases it'll further discourage vector handling.

Maybe a different question we should ask is whether we should be allowing SPLAT_VECTOR with fixed vector types. BuildVectorSDNode already has a query for splat. If I recall correctly we've been adding special scalable vector only shuffle nodes that don't work with fixed vectors. Maybe SPLAT_VECTOR should be the same?

frasercrmck added a comment.EditedFeb 11 2021, 5:12 AM

Have you got a use case where you actually need to know this?

I don't have a use case, I was just going by the existing users of matchUnaryPredicate which already "need" to know some internal details of what was matched in a roundabout manner, since they're processing the results in different ways. If that makes sense?

david-arm added a comment.EditedFeb 11 2021, 5:18 AM

Hi, yeah I agree with @frasercrmck here. The only reason I brought this up originally is because callers of the function do something like this:

if (VT.isFixedLengthVector()) {
... Do something with BUILD_VECTOR ...
} else if (VT.isScalableVector()) {
.. Do something with SPLAT_VECTOR ...
}

It felt like since we're already doing this an alternative solution might be to check the opcode instead of the vector type. The patch you have right now does work and wouldn't want to hold up the patch if you don't have time to fix it right now. It was just a suggestion for another way of dealing with the problem.

Check the opcode instead of the type in the callers.

craig.topper edited the summary of this revision. (Show Details)Feb 15 2021, 4:39 PM
RKSimon accepted this revision.Feb 16 2021, 2:41 AM

LGTM - cheers!

This revision is now accepted and ready to land.Feb 16 2021, 2:41 AM