Skip to content

Commit a1bdb01

Browse files
committed
[VectorCombine] Change shuffleToIdentity to use Use. NFC
When looking up through shuffles, a Value can be multiple different leaf types (for example an identity from one position, a splat from another). We currently detect this by recalculating which type of leaf it is when generating, but as more types of leafs are added (#94954) this doesn't scale very well. This patch switches it to use Use, not Value, to more accurately detect which type of leaf each Use should have.
1 parent 57b8be4 commit a1bdb01

File tree

2 files changed

+65
-56
lines changed

2 files changed

+65
-56
lines changed

llvm/lib/Transforms/Vectorize/VectorCombine.cpp

Lines changed: 52 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,63 +1669,59 @@ bool VectorCombine::foldShuffleOfShuffles(Instruction &I) {
16691669
return true;
16701670
}
16711671

1672-
using InstLane = std::pair<Value *, int>;
1672+
using InstLane = std::pair<Use *, int>;
16731673

1674-
static InstLane lookThroughShuffles(Value *V, int Lane) {
1675-
while (auto *SV = dyn_cast<ShuffleVectorInst>(V)) {
1674+
static InstLane lookThroughShuffles(Use *U, int Lane) {
1675+
while (auto *SV = dyn_cast<ShuffleVectorInst>(U->get())) {
16761676
unsigned NumElts =
16771677
cast<FixedVectorType>(SV->getOperand(0)->getType())->getNumElements();
16781678
int M = SV->getMaskValue(Lane);
16791679
if (M < 0)
16801680
return {nullptr, PoisonMaskElem};
16811681
if (static_cast<unsigned>(M) < NumElts) {
1682-
V = SV->getOperand(0);
1682+
U = &SV->getOperandUse(0);
16831683
Lane = M;
16841684
} else {
1685-
V = SV->getOperand(1);
1685+
U = &SV->getOperandUse(1);
16861686
Lane = M - NumElts;
16871687
}
16881688
}
1689-
return InstLane{V, Lane};
1689+
return InstLane{U, Lane};
16901690
}
16911691

16921692
static SmallVector<InstLane>
16931693
generateInstLaneVectorFromOperand(ArrayRef<InstLane> Item, int Op) {
16941694
SmallVector<InstLane> NItem;
16951695
for (InstLane IL : Item) {
1696-
auto [V, Lane] = IL;
1696+
auto [U, Lane] = IL;
16971697
InstLane OpLane =
1698-
V ? lookThroughShuffles(cast<Instruction>(V)->getOperand(Op), Lane)
1698+
U ? lookThroughShuffles(&cast<Instruction>(U->get())->getOperandUse(Op),
1699+
Lane)
16991700
: InstLane{nullptr, PoisonMaskElem};
17001701
NItem.emplace_back(OpLane);
17011702
}
17021703
return NItem;
17031704
}
17041705

17051706
static Value *generateNewInstTree(ArrayRef<InstLane> Item, FixedVectorType *Ty,
1706-
const SmallPtrSet<Value *, 4> &IdentityLeafs,
1707-
const SmallPtrSet<Value *, 4> &SplatLeafs,
1707+
const SmallPtrSet<Use *, 4> &IdentityLeafs,
1708+
const SmallPtrSet<Use *, 4> &SplatLeafs,
17081709
IRBuilder<> &Builder) {
1709-
auto [FrontV, FrontLane] = Item.front();
1710-
1711-
if (IdentityLeafs.contains(FrontV) &&
1712-
all_of(drop_begin(enumerate(Item)), [Item](const auto &E) {
1713-
Value *FrontV = Item.front().first;
1714-
auto [V, Lane] = E.value();
1715-
return !V || (V == FrontV && Lane == (int)E.index());
1716-
})) {
1717-
return FrontV;
1710+
auto [FrontU, FrontLane] = Item.front();
1711+
1712+
if (IdentityLeafs.contains(FrontU)) {
1713+
return FrontU->get();
17181714
}
1719-
if (SplatLeafs.contains(FrontV)) {
1720-
if (auto *ILI = dyn_cast<Instruction>(FrontV))
1715+
if (SplatLeafs.contains(FrontU)) {
1716+
if (auto *ILI = dyn_cast<Instruction>(FrontU))
17211717
Builder.SetInsertPoint(*ILI->getInsertionPointAfterDef());
1722-
else if (auto *Arg = dyn_cast<Argument>(FrontV))
1718+
else if (auto *Arg = dyn_cast<Argument>(FrontU))
17231719
Builder.SetInsertPointPastAllocas(Arg->getParent());
17241720
SmallVector<int, 16> Mask(Ty->getNumElements(), FrontLane);
1725-
return Builder.CreateShuffleVector(FrontV, Mask);
1721+
return Builder.CreateShuffleVector(FrontU->get(), Mask);
17261722
}
17271723

1728-
auto *I = cast<Instruction>(FrontV);
1724+
auto *I = cast<Instruction>(FrontU->get());
17291725
auto *II = dyn_cast<IntrinsicInst>(I);
17301726
unsigned NumOps = I->getNumOperands() - (II ? 1 : 0);
17311727
SmallVector<Value *> Ops(NumOps);
@@ -1741,7 +1737,7 @@ static Value *generateNewInstTree(ArrayRef<InstLane> Item, FixedVectorType *Ty,
17411737
SmallVector<Value *, 8> ValueList;
17421738
for (const auto &Lane : Item)
17431739
if (Lane.first)
1744-
ValueList.push_back(Lane.first);
1740+
ValueList.push_back(Lane.first->get());
17451741

17461742
Builder.SetInsertPoint(I);
17471743
Type *DstTy =
@@ -1785,69 +1781,69 @@ static Value *generateNewInstTree(ArrayRef<InstLane> Item, FixedVectorType *Ty,
17851781
// do so.
17861782
bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
17871783
auto *Ty = dyn_cast<FixedVectorType>(I.getType());
1788-
if (!Ty)
1784+
if (!Ty || I.use_empty())
17891785
return false;
17901786

17911787
SmallVector<InstLane> Start(Ty->getNumElements());
17921788
for (unsigned M = 0, E = Ty->getNumElements(); M < E; ++M)
1793-
Start[M] = lookThroughShuffles(&I, M);
1789+
Start[M] = lookThroughShuffles(&*I.use_begin(), M);
17941790

17951791
SmallVector<SmallVector<InstLane>> Worklist;
17961792
Worklist.push_back(Start);
1797-
SmallPtrSet<Value *, 4> IdentityLeafs, SplatLeafs;
1793+
SmallPtrSet<Use *, 4> IdentityLeafs, SplatLeafs;
17981794
unsigned NumVisited = 0;
17991795

18001796
while (!Worklist.empty()) {
18011797
if (++NumVisited > MaxInstrsToScan)
18021798
return false;
18031799

18041800
SmallVector<InstLane> Item = Worklist.pop_back_val();
1805-
auto [FrontV, FrontLane] = Item.front();
1801+
auto [FrontU, FrontLane] = Item.front();
18061802

18071803
// If we found an undef first lane then bail out to keep things simple.
1808-
if (!FrontV)
1804+
if (!FrontU)
18091805
return false;
18101806

18111807
// Look for an identity value.
1812-
if (!FrontLane &&
1813-
cast<FixedVectorType>(FrontV->getType())->getNumElements() ==
1808+
if (FrontLane == 0 &&
1809+
cast<FixedVectorType>(FrontU->get()->getType())->getNumElements() ==
18141810
Ty->getNumElements() &&
18151811
all_of(drop_begin(enumerate(Item)), [Item](const auto &E) {
1816-
Value *FrontV = Item.front().first;
1817-
return !E.value().first || (E.value().first == FrontV &&
1812+
Value *FrontV = Item.front().first->get();
1813+
return !E.value().first || (E.value().first->get() == FrontV &&
18181814
E.value().second == (int)E.index());
18191815
})) {
1820-
IdentityLeafs.insert(FrontV);
1816+
IdentityLeafs.insert(FrontU);
18211817
continue;
18221818
}
18231819
// Look for constants, for the moment only supporting constant splats.
1824-
if (auto *C = dyn_cast<Constant>(FrontV);
1820+
if (auto *C = dyn_cast<Constant>(FrontU);
18251821
C && C->getSplatValue() &&
18261822
all_of(drop_begin(Item), [Item](InstLane &IL) {
1827-
Value *FrontV = Item.front().first;
1828-
Value *V = IL.first;
1829-
return !V || V == FrontV;
1823+
Value *FrontV = Item.front().first->get();
1824+
Use *U = IL.first;
1825+
return !U || U->get() == FrontV;
18301826
})) {
1831-
SplatLeafs.insert(FrontV);
1827+
SplatLeafs.insert(FrontU);
18321828
continue;
18331829
}
18341830
// Look for a splat value.
18351831
if (all_of(drop_begin(Item), [Item](InstLane &IL) {
1836-
auto [FrontV, FrontLane] = Item.front();
1837-
auto [V, Lane] = IL;
1838-
return !V || (V == FrontV && Lane == FrontLane);
1832+
auto [FrontU, FrontLane] = Item.front();
1833+
auto [U, Lane] = IL;
1834+
return !U || (U->get() == FrontU->get() && Lane == FrontLane);
18391835
})) {
1840-
SplatLeafs.insert(FrontV);
1836+
SplatLeafs.insert(FrontU);
18411837
continue;
18421838
}
18431839

18441840
// We need each element to be the same type of value, and check that each
18451841
// element has a single use.
18461842
if (!all_of(drop_begin(Item), [Item](InstLane IL) {
1847-
Value *FrontV = Item.front().first;
1848-
Value *V = IL.first;
1849-
if (!V)
1843+
Value *FrontV = Item.front().first->get();
1844+
if (!IL.first)
18501845
return true;
1846+
Value *V = IL.first->get();
18511847
if (auto *I = dyn_cast<Instruction>(V); I && !I->hasOneUse())
18521848
return false;
18531849
if (V->getValueID() != FrontV->getValueID())
@@ -1869,25 +1865,25 @@ bool VectorCombine::foldShuffleToIdentity(Instruction &I) {
18691865

18701866
// Check the operator is one that we support. We exclude div/rem in case
18711867
// they hit UB from poison lanes.
1872-
if ((isa<BinaryOperator>(FrontV) &&
1873-
!cast<BinaryOperator>(FrontV)->isIntDivRem()) ||
1874-
isa<CmpInst>(FrontV)) {
1868+
if ((isa<BinaryOperator>(FrontU) &&
1869+
!cast<BinaryOperator>(FrontU)->isIntDivRem()) ||
1870+
isa<CmpInst>(FrontU)) {
18751871
Worklist.push_back(generateInstLaneVectorFromOperand(Item, 0));
18761872
Worklist.push_back(generateInstLaneVectorFromOperand(Item, 1));
1877-
} else if (isa<UnaryOperator, TruncInst, ZExtInst, SExtInst>(FrontV)) {
1873+
} else if (isa<UnaryOperator, TruncInst, ZExtInst, SExtInst>(FrontU)) {
18781874
Worklist.push_back(generateInstLaneVectorFromOperand(Item, 0));
1879-
} else if (isa<SelectInst>(FrontV)) {
1875+
} else if (isa<SelectInst>(FrontU)) {
18801876
Worklist.push_back(generateInstLaneVectorFromOperand(Item, 0));
18811877
Worklist.push_back(generateInstLaneVectorFromOperand(Item, 1));
18821878
Worklist.push_back(generateInstLaneVectorFromOperand(Item, 2));
1883-
} else if (auto *II = dyn_cast<IntrinsicInst>(FrontV);
1879+
} else if (auto *II = dyn_cast<IntrinsicInst>(FrontU);
18841880
II && isTriviallyVectorizable(II->getIntrinsicID())) {
18851881
for (unsigned Op = 0, E = II->getNumOperands() - 1; Op < E; Op++) {
18861882
if (isVectorIntrinsicWithScalarOpAtArg(II->getIntrinsicID(), Op)) {
18871883
if (!all_of(drop_begin(Item), [Item, Op](InstLane &IL) {
1888-
Value *FrontV = Item.front().first;
1889-
Value *V = IL.first;
1890-
return !V || (cast<Instruction>(V)->getOperand(Op) ==
1884+
Value *FrontV = Item.front().first->get();
1885+
Use *U = IL.first;
1886+
return !U || (cast<Instruction>(U->get())->getOperand(Op) ==
18911887
cast<Instruction>(FrontV)->getOperand(Op));
18921888
}))
18931889
return false;

llvm/test/Transforms/VectorCombine/AArch64/shuffletoidentity.ll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,19 @@ define <8 x i8> @abs_different(<8 x i8> %a) {
202202
ret <8 x i8> %r
203203
}
204204

205+
define <4 x i32> @poison_intrinsic(<2 x i16> %l256) {
206+
; CHECK-LABEL: @poison_intrinsic(
207+
; CHECK-NEXT: [[L266:%.*]] = call <2 x i16> @llvm.abs.v2i16(<2 x i16> [[L256:%.*]], i1 false)
208+
; CHECK-NEXT: [[L267:%.*]] = zext <2 x i16> [[L266]] to <2 x i32>
209+
; CHECK-NEXT: [[L271:%.*]] = shufflevector <2 x i32> [[L267]], <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
210+
; CHECK-NEXT: ret <4 x i32> [[L271]]
211+
;
212+
%l266 = call <2 x i16> @llvm.abs.v2i16(<2 x i16> %l256, i1 false)
213+
%l267 = zext <2 x i16> %l266 to <2 x i32>
214+
%l271 = shufflevector <2 x i32> %l267, <2 x i32> poison, <4 x i32> <i32 0, i32 1, i32 poison, i32 poison>
215+
ret <4 x i32> %l271
216+
}
217+
205218
define <8 x half> @splat0(<8 x half> %a, <8 x half> %b) {
206219
; CHECK-LABEL: @splat0(
207220
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <8 x half> [[B:%.*]], <8 x half> poison, <8 x i32> zeroinitializer

0 commit comments

Comments
 (0)