This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] Ensure shuffle splat operands are type-legal
ClosedPublic

Authored by frasercrmck on May 18 2021, 6:26 AM.

Details

Summary

The use of SelectionDAG::getSplatValue isn't guaranteed to return a
type-legal splat value as it may implicitly extract a vector element
from another shuffle. It is not permitted to introduce an illegal type
when lowering shuffles.

This patch addresses the crash by adding a boolean flag to
getSplatValue, defaulting to false, which when set will ensure a
type-legal return value. If it is unable to do that it will fail to
return a splat value.

I've been through the existing uses of getSplatValue in other targets
and was unable to find a need or test cases showing a need to update
their uses. In some cases, the call is made during LegalizeVectorOps
which may still produce illegal scalar types. In other situations, the
illegally-typed splat value may be quickly patched up to a legal type
(such as any-extending the returned extract_vector_elt up to a legal
type) before LegalizeDAG notices.

Diff Detail

Event Timeline

frasercrmck created this revision.May 18 2021, 6:26 AM
frasercrmck requested review of this revision.May 18 2021, 6:26 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 18 2021, 6:26 AM
craig.topper added inline comments.May 18 2021, 9:52 AM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
1853 ↗(On Diff #346158)

This still creates the illegal type. The node just ends up unused with this patch and gets deleted before anyone notices?

Could we call getSplatSourceVector instead and create an XLenVT extract_vector_elt ourselves? Or teach getSplatValue to obey NewNodesMustHaveLegalTypes.

  • move the illegal-type fix into getSplatValue
  • create a separate X86 version as it relies on illegal types
frasercrmck added inline comments.May 19 2021, 3:42 AM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
1853 ↗(On Diff #346158)

Yeah true, I wasn't too happy with this solution to be honest.

I gave a go at fixing it in getSplatValue. Unfortunately I found that X86 relies on illegal types being returned. What's worse is the X86 backend gets into a loop with this test case when using the type-legal getSplatValue. So for now I added an X86-specific version (the original) to X86ISelLowering.

; RUN: llc < %s -mtriple=i686-unknown -mattr=+sse2

define void @shift1a(<2 x i64> %val, <2 x i64>* %dst, <2 x i64> %sh) nounwind {
entry:
  %shamt = shufflevector <2 x i64> %sh, <2 x i64> undef, <2 x i32> <i32 0, i32 0>
  %shl = shl <2 x i64> %val, %shamt
  store <2 x i64> %shl, <2 x i64>* %dst
  ret void
}

Perhaps this isn't the way forward but I thought I'd throw it up in case people had comments.

The alternative for RISC-V is, as you say, calling getSplatSourceVector ourselves. But it does feel like getSplatValue should obey NewNoesMustHaveLegalTypes.

  • restore RISCVISelLowering back to 'main'

I think the issue for X86 might be that NewNodesMustHaveLegalTypes is set after type legalization, but vector legalization is allowed to create illegal scalar types. A second type legalization runs after. Maybe we should add a bool parameter to the function that defaults to false, but can be set to true to request a legal type?

  • pass bool to getSplatValue for legal types

I think the issue for X86 might be that NewNodesMustHaveLegalTypes is set after type legalization, but vector legalization is allowed to create illegal scalar types. A second type legalization runs after. Maybe we should add a bool parameter to the function that defaults to false, but can be set to true to request a legal type?

Yeah that might be going on but I'm not sure. It's pretty finicky. I think X86 is calling this during lowering, which should be after all legalization? I think it's just managing to get the extracted scalar into a legal form before returning from the lowering method.

From a brief look, I believe that WebAssembly's use of this method would crash, but it unconditionally "any exts or truncs" the extracted value to i32, which I think (for their set of illegal types) is always folded into the extract_vector_elt and so the illegal type is quickly removed.

AArch64's use also looks suspicious but since it's for scatter/gather I found it difficult to get an IR test case together which produces the right DAG.

I think the issue for X86 might be that NewNodesMustHaveLegalTypes is set after type legalization, but vector legalization is allowed to create illegal scalar types. A second type legalization runs after. Maybe we should add a bool parameter to the function that defaults to false, but can be set to true to request a legal type?

Yeah that might be going on but I'm not sure. It's pretty finicky. I think X86 is calling this during lowering, which should be after all legalization? I think it's just managing to get the extracted scalar into a legal form before returning from the lowering method.

There are 2 different lowering stages. One in the LegalizeVectorOps and one in LegalizeDAG. There is a scalar type legalization step in between if needed. It looks like it was being called during shift lowering which would be in LegalizeVectorOps. While our SHUFFLE_VECTOR usage would be in LegalizeDAG.

From a brief look, I believe that WebAssembly's use of this method would crash, but it unconditionally "any exts or truncs" the extracted value to i32, which I think (for their set of illegal types) is always folded into the extract_vector_elt and so the illegal type is quickly removed.

AArch64's use also looks suspicious but since it's for scatter/gather I found it difficult to get an IR test case together which produces the right DAG.

This revision is now accepted and ready to land.May 20 2021, 9:47 AM
frasercrmck edited the summary of this revision. (Show Details)May 20 2021, 10:06 AM
This revision was automatically updated to reflect the committed changes.