Repository navigation
[SLP]Support freeze as copyable main op - #239999
alexey-bataev wants to merge 2 commits into
Conversation
Created using spr 1.3.7
|
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-vectorizers Author: Alexey Bataev (alexey-bataev) ChangesModel non-freeze lanes as freeze(V), which refines V, so mixed Assisted-by: Cursor Full diff: https://github.com/llvm/llvm-project/pull/239999.diff 5 Files Affected:
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index e7fb2b024fa0a..f7e2cdcc8f18a 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -10342,9 +10342,12 @@ class InstructionsCompatibilityAnalysis {
/// lanes are inserted into it. A single-index scalar GEP is supported: the
/// copyable lanes are modeled as zero-index GEPs of the lane values
/// themselves. A scalar zext is supported: the copyable lanes are constants
- /// modeled as zexts of truncated constants.
+ /// modeled as zexts of truncated constants. A freeze is supported: the
+ /// copyable lanes are modeled as freezes of the lane values, which refine
+ /// them.
static bool isSupportedMainOp(Instruction *I) {
- return isSupportedOpcode(I->getOpcode()) || isa<MinMaxIntrinsic>(I) ||
+ return isSupportedOpcode(I->getOpcode()) ||
+ isa<MinMaxIntrinsic, FreezeInst>(I) ||
RecurrenceDescriptor::isFMulAddIntrinsic(I) ||
(isa<ExtractElementInst>(I) && isVectorLikeInstWithConstOps(I) &&
isa<FixedVectorType>(I->getOperand(0)->getType())) ||
@@ -10587,6 +10590,9 @@ class InstructionsCompatibilityAnalysis {
if (MainOpcode == Instruction::ZExt)
return {ConstantExpr::getTrunc(cast<Constant>(V),
cast<CastInst>(MainOp)->getSrcTy())};
+ // freeze(V) refines V.
+ if (MainOpcode == Instruction::Freeze)
+ return {V};
assert(isSupportedMainOp(MainOp) && "Unsupported opcode");
Type *Ty = V->getType();
if (PoisonPlaceholder &&
@@ -11264,11 +11270,12 @@ class InstructionsCompatibilityAnalysis {
Candidates.emplace_back(V1, (I1 || I2) ? V2 : V1);
};
if (VL.size() == 2) {
- // The operand-pairing heuristic below does not apply to calls, GEPs
- // and casts; defer to the full tree cost computation instead of
+ // The operand-pairing heuristic below does not apply to calls, GEPs,
+ // casts and freezes; defer to the full tree cost computation instead of
// pre-rejecting here.
if (MainOpcode == Instruction::Call ||
- MainOpcode == Instruction::GetElementPtr || isa<CastInst>(MainOp))
+ MainOpcode == Instruction::GetElementPtr ||
+ isa<CastInst, FreezeInst>(MainOp))
return S;
// Check if the operands allow better vectorization.
SmallVector<std::pair<Value *, Value *>, 4> Candidates1, Candidates2;
@@ -11322,10 +11329,10 @@ class InstructionsCompatibilityAnalysis {
return OrigS;
return S;
}
- // Casts are the only 1-operand and fma/fmuladd are the only 3-operand
- // copyables.
+ // Casts and freezes are the only 1-operand and fma/fmuladd are the only
+ // 3-operand copyables.
assert((Operands.size() == 2 ||
- (Operands.size() == 1 && isa<CastInst>(MainOp)) ||
+ (Operands.size() == 1 && isa<CastInst, FreezeInst>(MainOp)) ||
(Operands.size() == 3 && isFMAOrFMulAdd(MainOp))) &&
"Unexpected number of operands!");
if (CopyableNum < VL.size() / 2)
@@ -11390,7 +11397,7 @@ class InstructionsCompatibilityAnalysis {
return OrigS;
// Check the operand holding the copyable values.
if (!CheckOperand(Operands[S.getCopyableOpIdx()])) {
- if (Operands.size() == 2)
+ if (!isFMAOrFMulAdd(MainOp))
return OrigS;
// Retry with the copyable modeled as the first multiplicand.
S.setCopyableOpIdx(0);
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/copyable-freeze.ll b/llvm/test/Transforms/SLPVectorizer/X86/copyable-freeze.ll
index cc0a358531095..a145052849d97 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/copyable-freeze.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/copyable-freeze.ll
@@ -4,17 +4,8 @@
define void @one_copyable(ptr %p, ptr %q) {
; CHECK-LABEL: @one_copyable(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[G2:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 2
-; CHECK-NEXT: [[G3:%.*]] = getelementptr i32, ptr [[P]], i64 3
-; CHECK-NEXT: [[A2:%.*]] = load i32, ptr [[G2]], align 4
-; CHECK-NEXT: [[A3:%.*]] = load i32, ptr [[G3]], align 4
-; CHECK-NEXT: [[F2:%.*]] = freeze i32 [[A2]]
-; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i32>, ptr [[P]], align 4
-; CHECK-NEXT: [[TMP1:%.*]] = freeze <2 x i32> [[TMP0]]
-; CHECK-NEXT: [[TMP2:%.*]] = insertelement <4 x i32> poison, i32 [[F2]], i64 2
-; CHECK-NEXT: [[TMP3:%.*]] = insertelement <4 x i32> [[TMP2]], i32 [[A3]], i64 3
-; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
-; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <4 x i32> [[TMP3]], <4 x i32> [[TMP4]], <4 x i32> <i32 4, i32 5, i32 2, i32 3>
+; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[TMP5:%.*]] = freeze <4 x i32> [[TMP0]]
; CHECK-NEXT: [[TMP6:%.*]] = mul <4 x i32> [[TMP5]], <i32 3, i32 5, i32 7, i32 9>
; CHECK-NEXT: store <4 x i32> [[TMP6]], ptr [[Q:%.*]], align 4
; CHECK-NEXT: ret void
@@ -47,22 +38,9 @@ entry:
define void @half_copyable_loads(ptr %p, ptr %q) {
; CHECK-LABEL: @half_copyable_loads(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[G1:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 1
-; CHECK-NEXT: [[G2:%.*]] = getelementptr i32, ptr [[P]], i64 2
-; CHECK-NEXT: [[G3:%.*]] = getelementptr i32, ptr [[P]], i64 3
-; CHECK-NEXT: [[A0:%.*]] = load i32, ptr [[P]], align 4
-; CHECK-NEXT: [[A1:%.*]] = load i32, ptr [[G1]], align 4
-; CHECK-NEXT: [[A2:%.*]] = load i32, ptr [[G2]], align 4
-; CHECK-NEXT: [[A3:%.*]] = load i32, ptr [[G3]], align 4
-; CHECK-NEXT: [[F0:%.*]] = freeze i32 [[A0]]
-; CHECK-NEXT: [[F2:%.*]] = freeze i32 [[A2]]
-; CHECK-NEXT: [[H1:%.*]] = getelementptr i32, ptr [[Q:%.*]], i64 1
-; CHECK-NEXT: [[H2:%.*]] = getelementptr i32, ptr [[Q]], i64 2
-; CHECK-NEXT: [[H3:%.*]] = getelementptr i32, ptr [[Q]], i64 3
-; CHECK-NEXT: store i32 [[F0]], ptr [[Q]], align 4
-; CHECK-NEXT: store i32 [[A1]], ptr [[H1]], align 4
-; CHECK-NEXT: store i32 [[F2]], ptr [[H2]], align 4
-; CHECK-NEXT: store i32 [[A3]], ptr [[H3]], align 4
+; CHECK-NEXT: [[TMP0:%.*]] = load <4 x i32>, ptr [[P:%.*]], align 4
+; CHECK-NEXT: [[TMP1:%.*]] = freeze <4 x i32> [[TMP0]]
+; CHECK-NEXT: store <4 x i32> [[TMP1]], ptr [[Q:%.*]], align 4
; CHECK-NEXT: ret void
;
entry:
@@ -119,13 +97,9 @@ entry:
define void @two_lanes(ptr %p, ptr %q) {
; CHECK-LABEL: @two_lanes(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[G1:%.*]] = getelementptr i64, ptr [[P:%.*]], i64 1
-; CHECK-NEXT: [[A0:%.*]] = load i64, ptr [[P]], align 8
-; CHECK-NEXT: [[A1:%.*]] = load i64, ptr [[G1]], align 8
-; CHECK-NEXT: [[F0:%.*]] = freeze i64 [[A0]]
-; CHECK-NEXT: [[H1:%.*]] = getelementptr i64, ptr [[Q:%.*]], i64 1
-; CHECK-NEXT: store i64 [[F0]], ptr [[Q]], align 8
-; CHECK-NEXT: store i64 [[A1]], ptr [[H1]], align 8
+; CHECK-NEXT: [[TMP0:%.*]] = load <2 x i64>, ptr [[P:%.*]], align 8
+; CHECK-NEXT: [[TMP1:%.*]] = freeze <2 x i64> [[TMP0]]
+; CHECK-NEXT: store <2 x i64> [[TMP1]], ptr [[Q:%.*]], align 8
; CHECK-NEXT: ret void
;
entry:
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/select-copyable-cmp-poison.ll b/llvm/test/Transforms/SLPVectorizer/X86/select-copyable-cmp-poison.ll
index bf64a3c6cc0eb..429fc26bccfc0 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/select-copyable-cmp-poison.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/select-copyable-cmp-poison.ll
@@ -10,30 +10,28 @@ define i32 @foo(i32 %v2, ptr byval(%struct.S2) align 8 %v5, i1 %cmp3644) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br label %[[BB4:.*]]
; CHECK: [[BB4]]:
-; CHECK-NEXT: [[TMP0:%.*]] = insertelement <8 x i32> poison, i32 [[V2]], i64 1
+; CHECK-NEXT: [[TMP0:%.*]] = insertelement <4 x i32> poison, i32 [[V2]], i64 0
; CHECK-NEXT: br label %[[BB5:.*]]
; CHECK: [[BB5]]:
; CHECK-NEXT: [[F1783:%.*]] = getelementptr i8, ptr [[V5]], i64 108
; CHECK-NEXT: [[F2354:%.*]] = getelementptr i8, ptr [[V5]], i64 88
; CHECK-NEXT: [[F2882:%.*]] = getelementptr i8, ptr [[V5]], i64 100
; CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[F2354]], align 8
-; CHECK-NEXT: [[DOTFR5727:%.*]] = freeze i32 [[TMP2]]
; CHECK-NEXT: [[TMP3:%.*]] = load <4 x i32>, ptr [[F2882]], align 4
-; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <4 x i32> [[TMP3]], <4 x i32> poison, <2 x i32> <i32 0, i32 3>
-; CHECK-NEXT: [[TMP4:%.*]] = freeze <2 x i32> [[TMP5]]
+; CHECK-NEXT: [[TMP8:%.*]] = shufflevector <4 x i32> [[TMP3]], <4 x i32> poison, <2 x i32> <i32 3, i32 0>
+; CHECK-NEXT: [[TMP4:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[TMP2]], i64 1
+; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP8]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <4 x i32> [[TMP4]], <4 x i32> [[TMP5]], <4 x i32> <i32 0, i32 1, i32 4, i32 5>
+; CHECK-NEXT: [[TMP7:%.*]] = freeze <4 x i32> [[TMP6]]
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[F1783]], align 4
; CHECK-NEXT: [[DOTFR5726:%.*]] = freeze i32 [[TMP1]]
-; CHECK-NEXT: [[TMP6:%.*]] = insertelement <8 x i32> [[TMP0]], i32 [[DOTFR5727]], i64 0
-; CHECK-NEXT: [[TMP7:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> poison, <8 x i32> <i32 1, i32 poison, i32 0, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT: [[TMP31:%.*]] = shufflevector <8 x i32> [[TMP6]], <8 x i32> [[TMP7]], <8 x i32> <i32 0, i32 1, i32 poison, i32 8, i32 poison, i32 10, i32 poison, i32 poison>
+; CHECK-NEXT: [[TMP31:%.*]] = shufflevector <4 x i32> [[TMP7]], <4 x i32> poison, <8 x i32> <i32 0, i32 poison, i32 1, i32 2, i32 poison, i32 3, i32 poison, i32 poison>
; CHECK-NEXT: [[TMP32:%.*]] = insertelement <8 x i32> [[TMP31]], i32 [[DOTFR5726]], i64 6
-; CHECK-NEXT: [[TMP33:%.*]] = shufflevector <8 x i32> [[TMP32]], <8 x i32> poison, <8 x i32> <i32 0, i32 1, i32 1, i32 3, i32 0, i32 5, i32 6, i32 1>
+; CHECK-NEXT: [[TMP33:%.*]] = shufflevector <8 x i32> [[TMP32]], <8 x i32> poison, <8 x i32> <i32 0, i32 0, i32 2, i32 3, i32 2, i32 5, i32 6, i32 0>
; CHECK-NEXT: [[TMP34:%.*]] = srem <8 x i32> [[TMP33]], splat (i32 46337)
-; CHECK-NEXT: [[TMP14:%.*]] = shufflevector <8 x i32> [[TMP34]], <8 x i32> poison, <8 x i32> <i32 2, i32 1, i32 0, i32 3, i32 4, i32 5, i32 6, i32 7>
-; CHECK-NEXT: [[TMP13:%.*]] = shufflevector <8 x i32> [[TMP34]], <8 x i32> poison, <8 x i32> <i32 2, i32 1, i32 0, i32 3, i32 0, i32 5, i32 6, i32 2>
-; CHECK-NEXT: [[TMP9:%.*]] = or <8 x i32> [[TMP13]], zeroinitializer
-; CHECK-NEXT: [[TMP10:%.*]] = icmp slt <8 x i32> [[TMP14]], zeroinitializer
-; CHECK-NEXT: [[TMP11:%.*]] = shufflevector <8 x i32> [[TMP34]], <8 x i32> <i32 0, i32 0, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 0>, <8 x i32> <i32 8, i32 9, i32 0, i32 3, i32 0, i32 5, i32 6, i32 15>
+; CHECK-NEXT: [[TMP9:%.*]] = or <8 x i32> [[TMP34]], zeroinitializer
+; CHECK-NEXT: [[TMP10:%.*]] = icmp slt <8 x i32> [[TMP34]], zeroinitializer
+; CHECK-NEXT: [[TMP11:%.*]] = shufflevector <8 x i32> [[TMP34]], <8 x i32> <i32 0, i32 0, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 0>, <8 x i32> <i32 8, i32 9, i32 2, i32 3, i32 2, i32 5, i32 6, i32 15>
; CHECK-NEXT: [[TMP12:%.*]] = select <8 x i1> [[TMP10]], <8 x i32> [[TMP9]], <8 x i32> [[TMP11]]
; CHECK-NEXT: [[TMP18:%.*]] = load <21 x i32>, ptr [[V5]], align 4
; CHECK-NEXT: [[TMP19:%.*]] = shufflevector <21 x i32> [[TMP18]], <21 x i32> poison, <4 x i32> <i32 0, i32 1, i32 14, i32 20>
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/shl-to-add-transformation5.ll b/llvm/test/Transforms/SLPVectorizer/X86/shl-to-add-transformation5.ll
index ecd944e47bd81..1948fa219364f 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/shl-to-add-transformation5.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/shl-to-add-transformation5.ll
@@ -164,9 +164,9 @@ entry:
define void @shl_add(ptr %p, i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: define void @shl_add(
; CHECK-SAME: ptr [[P:%.*]], i32 [[A:%.*]], i32 [[B:%.*]], i32 [[C:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[TMP1:%.*]] = freeze i32 [[A]]
-; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x i32> poison, i32 [[TMP1]], i64 0
-; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i32> [[TMP4]], i32 [[B]], i64 1
+; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i32> poison, i32 [[A]], i64 0
+; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x i32> [[TMP1]], i32 [[B]], i64 1
+; CHECK-NEXT: [[TMP2:%.*]] = freeze <2 x i32> [[TMP4]]
; CHECK-NEXT: [[TMP3:%.*]] = insertelement <2 x i32> [[TMP2]], i32 [[C]], i64 1
; CHECK-NEXT: [[TMP6:%.*]] = add <2 x i32> [[TMP2]], [[TMP3]]
; CHECK-NEXT: store <2 x i32> [[TMP6]], ptr [[P]], align 4
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/shuffle-mask-emission.ll b/llvm/test/Transforms/SLPVectorizer/X86/shuffle-mask-emission.ll
index f99703d8e3562..8bce3616902bf 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/shuffle-mask-emission.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/shuffle-mask-emission.ll
@@ -4,13 +4,10 @@
define i1 @test() {
; CHECK-LABEL: define i1 @test() {
; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: [[H_PROMOTED118_I_FR:%.*]] = freeze i32 1
-; CHECK-NEXT: [[TMP3:%.*]] = insertelement <4 x i32> <i32 0, i32 0, i32 poison, i32 0>, i32 [[H_PROMOTED118_I_FR]], i64 2
-; CHECK-NEXT: [[TMP2:%.*]] = add <4 x i32> zeroinitializer, [[TMP3]]
-; CHECK-NEXT: [[TMP9:%.*]] = insertelement <4 x i32> <i32 poison, i32 0, i32 poison, i32 poison>, i32 [[H_PROMOTED118_I_FR]], i64 0
-; CHECK-NEXT: [[TMP10:%.*]] = shufflevector <4 x i32> [[TMP9]], <4 x i32> poison, <4 x i32> <i32 0, i32 0, i32 1, i32 0>
+; CHECK-NEXT: [[TMP10:%.*]] = freeze <4 x i32> <i32 0, i32 0, i32 1, i32 0>
; CHECK-NEXT: [[TMP4:%.*]] = add <4 x i32> zeroinitializer, [[TMP10]]
-; CHECK-NEXT: [[TMP5:%.*]] = add <4 x i32> [[TMP2]], [[TMP4]]
+; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <4 x i32> [[TMP10]], <4 x i32> [[TMP4]], <4 x i32> <i32 2, i32 2, i32 7, i32 2>
+; CHECK-NEXT: [[TMP5:%.*]] = add <4 x i32> [[TMP4]], [[TMP2]]
; CHECK-NEXT: [[TMP6:%.*]] = and <4 x i32> [[TMP5]], <i32 0, i32 1, i32 1, i32 1>
; CHECK-NEXT: [[TMP7:%.*]] = icmp eq <4 x i32> [[TMP6]], <i32 1, i32 0, i32 0, i32 0>
; CHECK-NEXT: [[TMP8:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP7]])
|
| ; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i32> [[TMP4]], i32 [[B]], i64 1 | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i32> poison, i32 [[A]], i64 0 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x i32> [[TMP1]], i32 [[B]], i64 1 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = freeze <2 x i32> [[TMP4]] |
There was a problem hiding this comment.
This freezes extra lane, should be just scalar a
There was a problem hiding this comment.
It should be ok, technically, but having it after gather/buildvector is not ok, will add extra check/trim
There was a problem hiding this comment.
Yeap, it seems like SLP catches buildvector [freeze a, b] here.
| ; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i32> [[TMP4]], i32 [[B]], i64 1 | ||
| ; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i32> poison, i32 [[A]], i64 0 | ||
| ; CHECK-NEXT: [[TMP4:%.*]] = insertelement <2 x i32> [[TMP1]], i32 [[B]], i64 1 | ||
| ; CHECK-NEXT: [[TMP2:%.*]] = freeze <2 x i32> [[TMP4]] |
There was a problem hiding this comment.
Yeap, it seems like SLP catches buildvector [freeze a, b] here.
| return isSupportedOpcode(I->getOpcode()) || | ||
| isa<MinMaxIntrinsic, FreezeInst>(I) || |
There was a problem hiding this comment.
I wonder how it works on a tie. Would it be dependent on an order of the lanes? Note, that freeze is not BinaryOp to be handled by findAndSetMainInstruction.
Created using spr 1.3.7
Model non-freeze lanes as freeze(V), which refines V, so mixed
bundles become a single vector freeze instead of a gather.
Assisted-by: Cursor