Skip to content

Commit f98553b

Browse files
alexey-bataevhulxv
authored andcommitted
[SLP]Flatten alternate associative chains into one reassociated node
Each lane peels only chain links with its own opcode, keeping the per-lane opcode on every combine level; emission linearizes into main-opcode chain, alt-opcode chain, and a single select shuffle. Reviewers: hiraditya, RKSimon, bababuck Pull Request: #215098
1 parent 85ab0c1 commit f98553b

6 files changed

Lines changed: 316 additions & 135 deletions

File tree

llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp

Lines changed: 220 additions & 90 deletions
Large diffs are not rendered by default.

llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/ADT/STLExtras.h"
1515
#include "llvm/ADT/SetVector.h"
1616
#include "llvm/ADT/SmallVector.h"
17+
#include "llvm/ADT/SmallVectorExtras.h"
1718
#include "llvm/Analysis/VectorUtils.h"
1819
#include "llvm/IR/Constants.h"
1920
#include "llvm/IR/InstrTypes.h"
@@ -808,4 +809,69 @@ bool isAlternateInstruction(Instruction *I, Instruction *MainOp,
808809
}
809810
return InstructionsState(MainOp, AltOp).getMatchingMainOpOrAltOp(I) == AltOp;
810811
}
812+
813+
SmallVector<SmallVector<Value *>> scanAltAssociativeOperands(
814+
const InstructionsState &S, const TargetLibraryInfo &TLI,
815+
ArrayRef<Value *> VL, ArrayRef<Value *> Op0, ArrayRef<Value *> Op1,
816+
SmallVectorImpl<Value *> &ReassocScalars, SmallBitVector &SubLanes) {
817+
assert(S.isAltShuffle() && "Expected an alternate node.");
818+
const unsigned NumLanes = VL.size();
819+
SmallVector<unsigned> LaneOpcodes =
820+
map_to_vector(seq<unsigned>(NumLanes), [&](unsigned Lane) {
821+
return isAlternateInstruction(cast<Instruction>(VL[Lane]),
822+
S.getMainOp(), S.getAltOp(), TLI)
823+
? S.getAltOpcode()
824+
: S.getOpcode();
825+
});
826+
// A lane value peels only as a single-use chain link with the lane's own
827+
// opcode, keeping every combine level on the same main/alt pattern.
828+
auto GetChainLink = [&](unsigned Lane, Value *V) -> Instruction * {
829+
auto *I = dyn_cast<Instruction>(V);
830+
if (!I || !I->hasOneUse() || I->getOpcode() != LaneOpcodes[Lane] ||
831+
!isReassocChainLink(I))
832+
return nullptr;
833+
return I;
834+
};
835+
SmallVector<SmallVector<Value *>> Columns;
836+
Columns.emplace_back(Op0.begin(), Op0.end());
837+
Columns.emplace_back(Op1.begin(), Op1.end());
838+
// The chain link of a commutative lane may sit in the second column;
839+
// normalize so every lane's link leads.
840+
for (unsigned Lane : seq<unsigned>(NumLanes)) {
841+
if (GetChainLink(Lane, Columns[0][Lane]))
842+
continue;
843+
Instruction *Link = GetChainLink(Lane, Columns[1][Lane]);
844+
if (!Link || !Link->isCommutative())
845+
return {};
846+
std::swap(Columns[0][Lane], Columns[1][Lane]);
847+
}
848+
// Peel the leading column while every lane stays a matching chain link.
849+
while (all_of(seq<unsigned>(NumLanes), [&](unsigned Lane) {
850+
return GetChainLink(Lane, Columns[0][Lane]) != nullptr;
851+
})) {
852+
SmallVector<Value *> NewColumn(NumLanes);
853+
for (unsigned Lane : seq<unsigned>(NumLanes)) {
854+
Instruction *Link = GetChainLink(Lane, Columns[0][Lane]);
855+
ReassocScalars.push_back(Link);
856+
// The chain of a commutative lane may continue in the second operand;
857+
// keep the chain link as the running value.
858+
unsigned RunningOp = Link->isCommutative() &&
859+
!GetChainLink(Lane, Link->getOperand(0)) &&
860+
GetChainLink(Lane, Link->getOperand(1))
861+
? 1
862+
: 0;
863+
NewColumn[Lane] = Link->getOperand(1 - RunningOp);
864+
Columns[0][Lane] = Link->getOperand(RunningOp);
865+
}
866+
Columns.insert(std::next(Columns.begin()), std::move(NewColumn));
867+
}
868+
assert(!ReassocScalars.empty() &&
869+
"Normalization guarantees at least one peeled level.");
870+
SubLanes.resize(NumLanes);
871+
for (unsigned Lane : seq<unsigned>(NumLanes))
872+
if (LaneOpcodes[Lane] == Instruction::Sub ||
873+
LaneOpcodes[Lane] == Instruction::FSub)
874+
SubLanes.set(Lane);
875+
return Columns;
876+
}
811877
} // namespace llvm::slpvectorizer

llvm/lib/Transforms/Vectorize/SLPVectorizer/SLPCompatibilityAnalysis.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/ArrayRef.h"
2020
#include "llvm/ADT/BitmaskEnum.h"
2121
#include "llvm/ADT/STLExtras.h"
22+
#include "llvm/ADT/SmallBitVector.h"
2223
#include "llvm/ADT/SmallVector.h"
2324
#include "llvm/Analysis/IVDescriptors.h"
2425
#include "llvm/IR/Instruction.h"
@@ -306,6 +307,18 @@ convertTo(Instruction *I, const InstructionsState &S);
306307
/// the given \p MainOp and \p AltOp instructions.
307308
bool isAlternateInstruction(Instruction *I, Instruction *MainOp,
308309
Instruction *AltOp, const TargetLibraryInfo &TLI);
310+
311+
/// Peel the per-lane associative chains of an alternate node into operand
312+
/// columns. Lanes peel in lockstep and only chain links with the lane's own
313+
/// opcode, so every combine level keeps the root's main/alt opcode pattern
314+
/// and a subtract lane never becomes an add of a negated leaf. Only the
315+
/// leading (running) column peels: peeling a subtracted subtract would flip
316+
/// signs. \p SubLanes records the subtract lanes for the realignment sign
317+
/// query. Returns the flattened columns, empty when no level peels.
318+
SmallVector<SmallVector<Value *>> scanAltAssociativeOperands(
319+
const InstructionsState &S, const TargetLibraryInfo &TLI,
320+
ArrayRef<Value *> VL, ArrayRef<Value *> Op0, ArrayRef<Value *> Op1,
321+
SmallVectorImpl<Value *> &ReassocScalars, SmallBitVector &SubLanes);
309322
} // namespace llvm::slpvectorizer
310323

311324
#endif // LLVM_LIB_TRANSFORMS_VECTORIZE_SLPVECTORIZER_SLPCOMPATIBILITYANALYSIS_H

llvm/test/Transforms/SLPVectorizer/X86/BinOpSameOpcodeHelper.ll

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,7 @@
44
define void @test() {
55
; CHECK-LABEL: @test(
66
; CHECK-NEXT: entry:
7-
; CHECK-NEXT: [[TMP0:%.*]] = lshr i64 0, 0
8-
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 0, 1
9-
; CHECK-NEXT: [[TMP2:%.*]] = lshr i64 [[TMP1]], 0
10-
; CHECK-NEXT: [[UMIN120:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP0]], i64 [[TMP2]])
11-
; CHECK-NEXT: [[TMP3:%.*]] = sub i64 0, 0
12-
; CHECK-NEXT: [[TMP4:%.*]] = lshr i64 [[TMP3]], 0
13-
; CHECK-NEXT: [[UMIN122:%.*]] = call i64 @llvm.umin.i64(i64 [[UMIN120]], i64 [[TMP4]])
14-
; CHECK-NEXT: [[TMP5:%.*]] = add i64 0, 1
15-
; CHECK-NEXT: [[TMP6:%.*]] = lshr i64 [[TMP5]], 0
16-
; CHECK-NEXT: [[UMIN123:%.*]] = call i64 @llvm.umin.i64(i64 [[UMIN122]], i64 [[TMP6]])
17-
; CHECK-NEXT: [[UMIN124:%.*]] = call i64 @llvm.umin.i64(i64 [[UMIN123]], i64 0)
7+
; CHECK-NEXT: [[UMIN124:%.*]] = call i64 @llvm.umin.i64(i64 0, i64 0)
188
; CHECK-NEXT: ret void
199
;
2010
entry:

llvm/test/Transforms/SLPVectorizer/X86/supernode.ll

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,10 @@ define void @test_supernode_addsub_alt(ptr %Aarray, ptr %Barray, ptr %Carray, pt
8989
; ENABLED-NEXT: [[TMP0:%.*]] = load <2 x double>, ptr [[AARRAY:%.*]], align 8
9090
; ENABLED-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[BARRAY:%.*]], align 8
9191
; ENABLED-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[CARRAY:%.*]], align 8
92-
; ENABLED-NEXT: [[TMP3:%.*]] = shufflevector <2 x double> [[TMP0]], <2 x double> [[TMP2]], <2 x i32> <i32 0, i32 3>
93-
; ENABLED-NEXT: [[TMP4:%.*]] = fsub fast <2 x double> [[TMP3]], [[TMP1]]
94-
; ENABLED-NEXT: [[TMP5:%.*]] = fadd fast <2 x double> [[TMP3]], [[TMP1]]
95-
; ENABLED-NEXT: [[TMP6:%.*]] = shufflevector <2 x double> [[TMP4]], <2 x double> [[TMP5]], <2 x i32> <i32 0, i32 3>
96-
; ENABLED-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> [[TMP2]], <2 x double> [[TMP0]], <2 x i32> <i32 0, i32 3>
97-
; ENABLED-NEXT: [[TMP8:%.*]] = fsub fast <2 x double> [[TMP6]], [[TMP7]]
98-
; ENABLED-NEXT: [[TMP9:%.*]] = fadd fast <2 x double> [[TMP6]], [[TMP7]]
92+
; ENABLED-NEXT: [[TMP4:%.*]] = fsub reassoc nsz arcp contract afn <2 x double> [[TMP0]], [[TMP1]]
93+
; ENABLED-NEXT: [[TMP8:%.*]] = fsub reassoc nsz arcp contract afn <2 x double> [[TMP4]], [[TMP2]]
94+
; ENABLED-NEXT: [[TMP5:%.*]] = fadd reassoc nsz arcp contract afn <2 x double> [[TMP0]], [[TMP1]]
95+
; ENABLED-NEXT: [[TMP9:%.*]] = fadd reassoc nsz arcp contract afn <2 x double> [[TMP5]], [[TMP2]]
9996
; ENABLED-NEXT: [[TMP10:%.*]] = shufflevector <2 x double> [[TMP8]], <2 x double> [[TMP9]], <2 x i32> <i32 0, i32 3>
10097
; ENABLED-NEXT: store <2 x double> [[TMP10]], ptr [[SARRAY:%.*]], align 8
10198
; ENABLED-NEXT: ret void
@@ -133,16 +130,12 @@ define void @test_addsub_alt_commuted(ptr %Aarray, ptr %Barray, ptr %Carray, ptr
133130
; ENABLED-NEXT: [[TMP1:%.*]] = load <2 x double>, ptr [[BARRAY:%.*]], align 8
134131
; ENABLED-NEXT: [[TMP2:%.*]] = load <2 x double>, ptr [[CARRAY:%.*]], align 8
135132
; ENABLED-NEXT: [[TMP3:%.*]] = load <2 x double>, ptr [[DARRAY:%.*]], align 8
136-
; ENABLED-NEXT: [[TMP4:%.*]] = shufflevector <2 x double> [[TMP0]], <2 x double> [[TMP2]], <2 x i32> <i32 0, i32 3>
137-
; ENABLED-NEXT: [[TMP5:%.*]] = fsub fast <2 x double> [[TMP4]], [[TMP1]]
138-
; ENABLED-NEXT: [[TMP12:%.*]] = fadd fast <2 x double> [[TMP4]], [[TMP1]]
139-
; ENABLED-NEXT: [[TMP7:%.*]] = shufflevector <2 x double> [[TMP5]], <2 x double> [[TMP12]], <2 x i32> <i32 0, i32 3>
140-
; ENABLED-NEXT: [[TMP8:%.*]] = fsub fast <2 x double> [[TMP7]], [[TMP3]]
141-
; ENABLED-NEXT: [[TMP13:%.*]] = fadd fast <2 x double> [[TMP7]], [[TMP3]]
142-
; ENABLED-NEXT: [[TMP14:%.*]] = shufflevector <2 x double> [[TMP8]], <2 x double> [[TMP13]], <2 x i32> <i32 0, i32 3>
143-
; ENABLED-NEXT: [[TMP11:%.*]] = shufflevector <2 x double> [[TMP2]], <2 x double> [[TMP0]], <2 x i32> <i32 0, i32 3>
144-
; ENABLED-NEXT: [[TMP6:%.*]] = fsub fast <2 x double> [[TMP14]], [[TMP11]]
145-
; ENABLED-NEXT: [[TMP9:%.*]] = fadd fast <2 x double> [[TMP14]], [[TMP11]]
133+
; ENABLED-NEXT: [[TMP4:%.*]] = fsub reassoc nsz arcp contract afn <2 x double> [[TMP0]], [[TMP1]]
134+
; ENABLED-NEXT: [[TMP5:%.*]] = fsub reassoc nsz arcp contract afn <2 x double> [[TMP4]], [[TMP3]]
135+
; ENABLED-NEXT: [[TMP6:%.*]] = fsub reassoc nsz arcp contract afn <2 x double> [[TMP5]], [[TMP2]]
136+
; ENABLED-NEXT: [[TMP7:%.*]] = fadd reassoc nsz arcp contract afn <2 x double> [[TMP0]], [[TMP1]]
137+
; ENABLED-NEXT: [[TMP8:%.*]] = fadd reassoc nsz arcp contract afn <2 x double> [[TMP7]], [[TMP3]]
138+
; ENABLED-NEXT: [[TMP9:%.*]] = fadd reassoc nsz arcp contract afn <2 x double> [[TMP8]], [[TMP2]]
146139
; ENABLED-NEXT: [[TMP10:%.*]] = shufflevector <2 x double> [[TMP6]], <2 x double> [[TMP9]], <2 x i32> <i32 0, i32 3>
147140
; ENABLED-NEXT: store <2 x double> [[TMP10]], ptr [[SARRAY:%.*]], align 8
148141
; ENABLED-NEXT: ret void

llvm/test/Transforms/SLPVectorizer/vectorize-reorder-alt-shuffle.ll

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,13 @@
55
define void @foo(ptr %c, ptr %d) {
66
; X86-LABEL: @foo(
77
; X86-NEXT: entry:
8-
; X86-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[C:%.*]], i64 4
9-
; X86-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1
10-
; X86-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2
8+
; X86-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds i8, ptr [[C:%.*]], i64 1
119
; X86-NEXT: [[ADD_PTR53:%.*]] = getelementptr inbounds float, ptr [[D:%.*]], i64 -4
12-
; X86-NEXT: [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX4]], align 1
13-
; X86-NEXT: [[TMP1:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
14-
; X86-NEXT: [[CONV5:%.*]] = zext i8 [[TMP0]] to i32
15-
; X86-NEXT: [[CONV2:%.*]] = zext i8 [[TMP1]] to i32
16-
; X86-NEXT: [[SHL6:%.*]] = shl nuw nsw i32 [[CONV5]], 2
17-
; X86-NEXT: [[AND:%.*]] = and i32 [[CONV2]], 3
18-
; X86-NEXT: [[TMP2:%.*]] = load <2 x i8>, ptr [[ARRAYIDX12]], align 1
19-
; X86-NEXT: [[TMP3:%.*]] = zext <2 x i8> [[TMP2]] to <2 x i16>
20-
; X86-NEXT: [[TMP4:%.*]] = shl <2 x i16> [[TMP3]], splat (i16 2)
21-
; X86-NEXT: [[TMP5:%.*]] = insertelement <4 x i32> poison, i32 [[SHL6]], i64 0
22-
; X86-NEXT: [[TMP6:%.*]] = zext <2 x i16> [[TMP4]] to <2 x i32>
23-
; X86-NEXT: [[TMP7:%.*]] = shufflevector <2 x i32> [[TMP6]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
24-
; X86-NEXT: [[TMP8:%.*]] = shufflevector <4 x i32> [[TMP5]], <4 x i32> [[TMP7]], <4 x i32> <i32 0, i32 4, i32 5, i32 poison>
25-
; X86-NEXT: [[TMP9:%.*]] = insertelement <4 x i32> [[TMP8]], i32 [[AND]], i64 3
10+
; X86-NEXT: [[TMP0:%.*]] = load <4 x i8>, ptr [[ARRAYIDX4]], align 1
11+
; X86-NEXT: [[TMP1:%.*]] = zext <4 x i8> [[TMP0]] to <4 x i32>
12+
; X86-NEXT: [[TMP2:%.*]] = shl nuw nsw <4 x i32> [[TMP1]], <i32 2, i32 2, i32 2, i32 3>
13+
; X86-NEXT: [[TMP3:%.*]] = and <4 x i32> [[TMP1]], <i32 2, i32 2, i32 2, i32 3>
14+
; X86-NEXT: [[TMP9:%.*]] = shufflevector <4 x i32> [[TMP2]], <4 x i32> [[TMP3]], <4 x i32> <i32 0, i32 1, i32 2, i32 7>
2615
; X86-NEXT: [[TMP10:%.*]] = add nsw <4 x i32> undef, [[TMP9]]
2716
; X86-NEXT: [[TMP11:%.*]] = sitofp <4 x i32> [[TMP10]] to <4 x float>
2817
; X86-NEXT: [[TMP12:%.*]] = fdiv <4 x float> [[TMP11]], undef

0 commit comments

Comments
 (0)