Repository navigation
[DAGCombiner] Only fold deinterleave to undef when all operands are undef - #240057
Joel-Wwalker wants to merge 2 commits into
Conversation
Baseline tests for llvm#238711. The input of each deinterleave is poison in its first part only, so the results still hold defined lanes. The SelectionDAG checks currently show the results folded to undef. Assisted by Claude (Anthropic).
…ndef visitVECTOR_DEINTERLEAVE folded every result to undef when operand 0 was undef. The operands are consecutive pieces of the input vector and every result takes lanes from all of them, so a defined later operand still feeds every result. The fold deleted the code that used them. Check all operands, as visitVECTOR_INTERLEAVE already does. Fixes llvm#238711. Assisted by Claude (Anthropic).
|
@llvm/pr-subscribers-llvm-selectiondag @llvm/pr-subscribers-backend-aarch64 Author: Joel Walker (Joel-Wwalker) Changes
Check that all operands are undef, as The first commit adds the tests with the current output, the second has the fix. Fixes #238711. Assisted by Claude (Anthropic). Full diff: https://github.com/llvm/llvm-project/pull/240057.diff 2 Files Affected:
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 5b02ccb18ef23d..ff143ac71fcadf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -28283,10 +28283,10 @@ SDValue DAGCombiner::visitVECTOR_INTERLEAVE(SDNode *N) {
SDValue DAGCombiner::visitVECTOR_DEINTERLEAVE(SDNode *N) {
EVT VT = N->getValueType(0);
- SDValue Op0 = N->getOperand(0);
- // Canonicalize shuffle undef -> {undef, undef, ..}
- if (Op0.isUndef()) {
+ // Canonicalize shuffle undef, undef -> {undef, undef, ..}
+ // Every result takes lanes from every operand, so all operands must be undef.
+ if (all_of(N->op_values(), [](SDValue Op) { return Op.isUndef(); })) {
SDLoc DL(N);
SmallVector<SDValue> Ops(N->getNumValues(), DAG.getUNDEF(VT));
return DAG.getMergeValues(Ops, DL);
diff --git a/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll b/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
index ba8b2d4af20914..e24c16de6edd9f 100644
--- a/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
+++ b/llvm/test/CodeGen/AArch64/fixed-vector-deinterleave.ll
@@ -873,3 +873,67 @@ define {<8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8
%retval = call {<8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>} @llvm.vector.deinterleave8.v64bf16(<64 x bfloat> %ins7)
ret {<8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>, <8 x bfloat>} %retval
}
+
+; Only the low half of the deinterleaved vector is poison, so the results are
+; not poison: lanes 2 and 3 of each result come from %v.
+define void @deinterleave2_v8i8_lo_poison(ptr %p, ptr %o) {
+; CHECK-SD-LABEL: deinterleave2_v8i8_lo_poison:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: ldr s0, [x0]
+; CHECK-SD-NEXT: ushll v0.8h, v0.8b, #0
+; CHECK-SD-NEXT: uzp2 v1.4h, v0.4h, v0.4h
+; CHECK-SD-NEXT: uzp1 v0.4h, v0.4h, v0.4h
+; CHECK-SD-NEXT: zip2 v0.2s, v0.2s, v1.2s
+; CHECK-SD-NEXT: uzp1 v0.8b, v0.8b, v0.8b
+; CHECK-SD-NEXT: str s0, [x1]
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: deinterleave2_v8i8_lo_poison:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: ld1 { v0.s }[1], [x0]
+; CHECK-GI-NEXT: adrp x8, .LCPI42_0
+; CHECK-GI-NEXT: uzp1 v1.8b, v0.8b, v0.8b
+; CHECK-GI-NEXT: uzp2 v0.8b, v0.8b, v0.8b
+; CHECK-GI-NEXT: mov v1.d[1], v0.d[0]
+; CHECK-GI-NEXT: ldr d0, [x8, :lo12:.LCPI42_0]
+; CHECK-GI-NEXT: tbl v0.16b, { v1.16b }, v0.16b
+; CHECK-GI-NEXT: str s0, [x1]
+; CHECK-GI-NEXT: ret
+ %v = load <4 x i8>, ptr %p
+ %x = shufflevector <4 x i8> %v, <4 x i8> poison, <8 x i32> <i32 poison, i32 poison, i32 poison, i32 poison, i32 0, i32 1, i32 2, i32 3>
+ %d = call {<4 x i8>, <4 x i8>} @llvm.vector.deinterleave2.v8i8(<8 x i8> %x)
+ %even = extractvalue {<4 x i8>, <4 x i8>} %d, 0
+ %odd = extractvalue {<4 x i8>, <4 x i8>} %d, 1
+ %r = shufflevector <4 x i8> %even, <4 x i8> %odd, <4 x i32> <i32 2, i32 3, i32 6, i32 7>
+ store <4 x i8> %r, ptr %o
+ ret void
+}
+
+define <4 x i32> @deinterleave2_v8i32_lo_poison(<4 x i32> %v) {
+; CHECK-LABEL: deinterleave2_v8i32_lo_poison:
+; CHECK: // %bb.0:
+; CHECK-NEXT: uzp1 v0.4s, v0.4s, v0.4s
+; CHECK-NEXT: ret
+ %x = shufflevector <4 x i32> %v, <4 x i32> poison, <8 x i32> <i32 poison, i32 poison, i32 poison, i32 poison, i32 0, i32 1, i32 2, i32 3>
+ %d = call {<4 x i32>, <4 x i32>} @llvm.vector.deinterleave2.v8i32(<8 x i32> %x)
+ %even = extractvalue {<4 x i32>, <4 x i32>} %d, 0
+ ret <4 x i32> %even
+}
+
+define <2 x i32> @deinterleave3_v6i32_first_poison(<2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: deinterleave3_v6i32_first_poison:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sub sp, sp, #32
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: add x8, sp, #8
+; CHECK-NEXT: stp d0, d1, [sp, #16]
+; CHECK-NEXT: ld3 { v31.2s, v0.2s, v1.2s }, [x8]
+; CHECK-NEXT: // kill: def $d0 killed $d0 killed $d31_d0_d1
+; CHECK-NEXT: add sp, sp, #32
+; CHECK-NEXT: ret
+ %bc = shufflevector <2 x i32> %b, <2 x i32> %c, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %x = shufflevector <4 x i32> %bc, <4 x i32> poison, <6 x i32> <i32 poison, i32 poison, i32 0, i32 1, i32 2, i32 3>
+ %d = call {<2 x i32>, <2 x i32>, <2 x i32>} @llvm.vector.deinterleave3.v6i32(<6 x i32> %x)
+ %r = extractvalue {<2 x i32>, <2 x i32>, <2 x i32>} %d, 1
+ ret <2 x i32> %r
+}
|
visitVECTOR_DEINTERLEAVEfolded every result to undef when only operand 0 was undef. The operands ofVECTOR_DEINTERLEAVEare consecutive pieces of the input (Result[I][J] = CONCAT_VECTORS(...)[I + N * J]), so every result takes lanes from all of them. In the reproducer from #238711 the low half of adeinterleave2input is poison and the high half is a loaded vector, and the whole function was reduced toret.Check that all operands are undef, as
visitVECTOR_INTERLEAVEdoes. The fold came from #228858, whose description already says "all undef inputs"; itsdeinterleave3_poisontest is unchanged.The first commit adds the tests with the current output, the second has the fix.
Fixes #238711.
Assisted by Claude (Anthropic).