This is an archive of the discontinued LLVM Phabricator instance.

[RISCV] Fix interleave crash on unary interleaves
ClosedPublic

Authored by luke on Apr 18 2023, 10:32 AM.

Details

Summary

We were crashing when lowering interleave shuffles like
(shuffle <0,3,1,4>, x:v4i8, y:v4i8)
Where it was technically an unary shuffle (both EvenSrc and OddSrc point
to the first operand), but the resulting extract_subvectors were out of
bounds.
This checks to make sure that the vectors being extracted are within
range.

Diff Detail

Event Timeline

luke created this revision.Apr 18 2023, 10:32 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 18 2023, 10:32 AM
luke requested review of this revision.Apr 18 2023, 10:32 AM
This revision is now accepted and ready to land.Apr 18 2023, 11:01 AM
craig.topper added inline comments.Apr 18 2023, 2:32 PM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
3283–3284

I think this needs to be int to avoid signed/unsigned comparison warnings against EvenSrc/OddSrc.

craig.topper requested changes to this revision.Apr 18 2023, 3:01 PM

I think this made us no longer support

define <8 x i8> @foo(<8 x i8> %x, <8 x i8> %y) {                                 
  ; V128-LABEL: unary_interleave_v4i8_invalid:                                   
  ; V128:       # %bb.0:                                                         
  ; V128-NEXT:    lui a0, %hi(.LCPI17_0)                                         
  ; V128-NEXT:    addi a0, a0, %lo(.LCPI17_0)                                    
  ; V128-NEXT:    vsetivli zero, 4, e8, mf4, ta, ma                              
  ; V128-NEXT:    vle8.v v10, (a0)                                               
  ; V128-NEXT:    vrgather.vv v9, v8, v10                                        
  ; V128-NEXT:    vmv1r.v v8, v9                                                 
  ; V128-NEXT:    ret                                                            
  ;                                                                              
  ; V512-LABEL: unary_interleave_v4i8_invalid:                                   
  ; V512:       # %bb.0:                                                         
  ; V512-NEXT:    lui a0, %hi(.LCPI17_0)                                         
  ; V512-NEXT:    addi a0, a0, %lo(.LCPI17_0)                                    
  ; V512-NEXT:    vsetivli zero, 4, e8, mf8, ta, ma                              
  ; V512-NEXT:    vle8.v v10, (a0)                                               
  ; V512-NEXT:    vrgather.vv v9, v8, v10                                        
  ; V512-NEXT:    vmv1r.v v8, v9                                                 
  ; V512-NEXT:    ret                                                            
    %a = shufflevector <8 x i8> %x, <8 x i8> %y, <8 x i32> <i32 0, i32 12, i32 1, i32 13, i32 2, i32 14, i32 3, i32 15>
      ret <8 x i8> %a                                                            
}
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
3297

I wonder if the fix should be

if (EvenSrc % (NumElts / 2) != 0 || OddSrc % (NumElts /2) != 0)

This revision now requires changes to proceed.Apr 18 2023, 3:01 PM
luke updated this revision to Diff 514897.Apr 19 2023, 4:06 AM

Handle more cases where there may be an offset

luke added inline comments.Apr 19 2023, 4:11 AM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
3297

That works for the first two cases mentioned but then it seems to miss the interleave in this case:

; This interleaves the first 2 elements of a vector in opposite order. With
; undefs for the remaining elements. We use to miscompile this.
define <4 x i8> @unary_interleave_10uu_v4i8(<4 x i8> %x) {
  %a = shufflevector <4 x i8> %x, <4 x i8> poison, <4 x i32> <i32 1, i32 0, i32 undef, i32 undef>
  ret <4 x i8> %a
}

I noticed we also probably want to support non-multiple-of-numelts offsets like this:

shufflevector <4 x i32> %x, <4 x i32> %y, <4 x i32> <i32 0, i32 5, i32 1, i32 6>

I've updated the patch to check the range given we know the start indices and size of each vector being interleaved, but there's probably a more elegant way of expressing this that I'm missing

craig.topper added inline comments.Apr 19 2023, 11:59 PM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
3297

Does that case in unary_interleave_10uu_v4i8 violate this rule for the extract_subvector?

/// EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.          
/// Let the result type be T, then IDX represents the starting element number  
/// from which a subvector of type T is extracted. IDX must be a constant      
/// multiple of T's known minimum vector length.
craig.topper added inline comments.Apr 20 2023, 12:09 AM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
3299

I think you maybe you want

I think maybe you can do something like

int HalfNumElts = NumElts / 2;
return (((EvenSrc % NumElts) + HalfNumElts) <= NumElts) &&
            (((OddSrc % NumElts) + HalfNumElts) <= NumElts);
luke added inline comments.Apr 24 2023, 2:23 AM
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
3297

It does, EvenSrc is 1 and size is 4 so it generates t16: v2i8 = extract_subvector t4, Constant:i64<1>. Should there not be an assertion triggering somewhere?

3299

Thanks, that's much better

luke updated this revision to Diff 516323.Apr 24 2023, 2:25 AM

Address comments

This revision is now accepted and ready to land.Apr 24 2023, 11:58 AM
This revision was landed with ongoing or failed builds.Apr 25 2023, 1:19 AM
This revision was automatically updated to reflect the committed changes.