[SLP] Fix assertion "Deleting out-of-tree value" for struct-typed vectorized operands#199679
Conversation
Created using spr 1.3.7
|
@llvm/pr-subscribers-llvm-transforms Author: Alexey Bataev (alexey-bataev) ChangesWhen an external-use scalar had a struct-typed vectorized operand, OperandIsScalar
Full diff: https://github.com/llvm/llvm-project/pull/199679.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index bdd5311ab55ad..caee72eb0547a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -19708,6 +19708,8 @@ InstructionCost BoUpSLP::getTreeCost(InstructionCost TreeCost,
return !EE->hasOneUse() || !MustGather.contains(EE);
return true;
}
+ if (isa<StructType>(V->getType()))
+ return false;
return ValueToExtUses->contains(V);
};
bool CanBeUsedAsScalar = all_of(Inst->operands(), OperandIsScalar);
diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/slp-extval-struct-operand-no-scalar-reuse.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/slp-extval-struct-operand-no-scalar-reuse.ll
new file mode 100644
index 0000000000000..2f84803994136
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/slp-extval-struct-operand-no-scalar-reuse.ll
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S --passes=slp-vectorizer -slp-threshold=-10 -mtriple=arm64-apple-macosx12.0.0 < %s | FileCheck %s
+
+
+define [2 x i64] @test() {
+; CHECK-LABEL: define [2 x i64] @test() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> zeroinitializer, <2 x i32> zeroinitializer)
+; CHECK-NEXT: [[TMP1:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> zeroinitializer, <2 x i32> [[TMP0]])
+; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { <2 x i32>, <2 x i1> } [[TMP1]], 0
+; CHECK-NEXT: [[TMP3:%.*]] = extractelement <2 x i32> [[TMP2]], i32 0
+; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { <2 x i32>, <2 x i1> } [[TMP1]], 1
+; CHECK-NEXT: [[TMP5:%.*]] = extractelement <2 x i1> [[TMP4]], i32 0
+; CHECK-NEXT: [[RETVAL_SROA_5_8_INSERT_SHIFT_I52_I:%.*]] = select i1 [[TMP5]], i64 0, i64 0
+; CHECK-NEXT: [[TMP6:%.*]] = zext <2 x i1> [[TMP4]] to <2 x i64>
+; CHECK-NEXT: store <2 x i64> [[TMP6]], ptr getelementptr inbounds nuw (i8, ptr null, i64 104), align 8
+; CHECK-NEXT: ret [2 x i64] zeroinitializer
+;
+entry:
+ %retval.0.i.i.i.i.i14.i.i.i = tail call i32 @llvm.sadd.sat.i32(i32 0, i32 0)
+ %0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 0, i32 %retval.0.i.i.i.i.i14.i.i.i)
+ %1 = extractvalue { i32, i1 } %0, 0
+ %2 = extractvalue { i32, i1 } %0, 1
+ %3 = zext i1 %2 to i64
+ store i64 %3, ptr getelementptr inbounds nuw (i8, ptr null, i64 104), align 8
+ %retval.sroa.5.8.insert.shift.i52.i = select i1 %2, i64 0, i64 0
+ %retval.0.i.i.i.i.i13.i.i.i = tail call i32 @llvm.sadd.sat.i32(i32 0, i32 0)
+ %4 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 0, i32 %retval.0.i.i.i.i.i13.i.i.i)
+ %5 = extractvalue { i32, i1 } %4, 1
+ %6 = zext i1 %5 to i64
+ store i64 %6, ptr getelementptr inbounds nuw (i8, ptr null, i64 112), align 8
+ ret [2 x i64] zeroinitializer
+}
+
+declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32)
+
+declare i32 @llvm.sadd.sat.i32(i32, i32)
+
|
|
@llvm/pr-subscribers-vectorizers Author: Alexey Bataev (alexey-bataev) ChangesWhen an external-use scalar had a struct-typed vectorized operand, OperandIsScalar
Full diff: https://github.com/llvm/llvm-project/pull/199679.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index bdd5311ab55ad..caee72eb0547a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -19708,6 +19708,8 @@ InstructionCost BoUpSLP::getTreeCost(InstructionCost TreeCost,
return !EE->hasOneUse() || !MustGather.contains(EE);
return true;
}
+ if (isa<StructType>(V->getType()))
+ return false;
return ValueToExtUses->contains(V);
};
bool CanBeUsedAsScalar = all_of(Inst->operands(), OperandIsScalar);
diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/slp-extval-struct-operand-no-scalar-reuse.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/slp-extval-struct-operand-no-scalar-reuse.ll
new file mode 100644
index 0000000000000..2f84803994136
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/slp-extval-struct-operand-no-scalar-reuse.ll
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S --passes=slp-vectorizer -slp-threshold=-10 -mtriple=arm64-apple-macosx12.0.0 < %s | FileCheck %s
+
+
+define [2 x i64] @test() {
+; CHECK-LABEL: define [2 x i64] @test() {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[TMP0:%.*]] = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> zeroinitializer, <2 x i32> zeroinitializer)
+; CHECK-NEXT: [[TMP1:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.ssub.with.overflow.v2i32(<2 x i32> zeroinitializer, <2 x i32> [[TMP0]])
+; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { <2 x i32>, <2 x i1> } [[TMP1]], 0
+; CHECK-NEXT: [[TMP3:%.*]] = extractelement <2 x i32> [[TMP2]], i32 0
+; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { <2 x i32>, <2 x i1> } [[TMP1]], 1
+; CHECK-NEXT: [[TMP5:%.*]] = extractelement <2 x i1> [[TMP4]], i32 0
+; CHECK-NEXT: [[RETVAL_SROA_5_8_INSERT_SHIFT_I52_I:%.*]] = select i1 [[TMP5]], i64 0, i64 0
+; CHECK-NEXT: [[TMP6:%.*]] = zext <2 x i1> [[TMP4]] to <2 x i64>
+; CHECK-NEXT: store <2 x i64> [[TMP6]], ptr getelementptr inbounds nuw (i8, ptr null, i64 104), align 8
+; CHECK-NEXT: ret [2 x i64] zeroinitializer
+;
+entry:
+ %retval.0.i.i.i.i.i14.i.i.i = tail call i32 @llvm.sadd.sat.i32(i32 0, i32 0)
+ %0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 0, i32 %retval.0.i.i.i.i.i14.i.i.i)
+ %1 = extractvalue { i32, i1 } %0, 0
+ %2 = extractvalue { i32, i1 } %0, 1
+ %3 = zext i1 %2 to i64
+ store i64 %3, ptr getelementptr inbounds nuw (i8, ptr null, i64 104), align 8
+ %retval.sroa.5.8.insert.shift.i52.i = select i1 %2, i64 0, i64 0
+ %retval.0.i.i.i.i.i13.i.i.i = tail call i32 @llvm.sadd.sat.i32(i32 0, i32 0)
+ %4 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 0, i32 %retval.0.i.i.i.i.i13.i.i.i)
+ %5 = extractvalue { i32, i1 } %4, 1
+ %6 = zext i1 %5 to i64
+ store i64 %6, ptr getelementptr inbounds nuw (i8, ptr null, i64 112), align 8
+ ret [2 x i64] zeroinitializer
+}
+
+declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32)
+
+declare i32 @llvm.sadd.sat.i32(i32, i32)
+
|
…t-typed vectorized operands When an external-use scalar had a struct-typed vectorized operand, OperandIsScalar incorrectly returned true (because the struct scalar was in ValueToExtUses), causing the scalar to be cloned into ExternalUsesAsOriginalScalar. The clone used the struct scalar directly, but struct-typed vectorized scalars are deleted after vectorization - their external-use handling erases the extractvalue user rather than replacing the struct value via replaceAllUsesWith. Reviewers: Pull Request: llvm/llvm-project#199679
…t-typed vectorized operands When an external-use scalar had a struct-typed vectorized operand, OperandIsScalar incorrectly returned true (because the struct scalar was in ValueToExtUses), causing the scalar to be cloned into ExternalUsesAsOriginalScalar. The clone used the struct scalar directly, but struct-typed vectorized scalars are deleted after vectorization - their external-use handling erases the extractvalue user rather than replacing the struct value via replaceAllUsesWith. Reviewers: Pull Request: llvm/llvm-project#199679
When an external-use scalar had a struct-typed vectorized operand, OperandIsScalar
incorrectly returned true (because the struct scalar was in ValueToExtUses), causing
the scalar to be cloned into ExternalUsesAsOriginalScalar. The clone used the struct
scalar directly, but struct-typed vectorized scalars are deleted after vectorization
struct value via replaceAllUsesWith.