LLVM 24.0.0git
Scalarizer.cpp
Go to the documentation of this file.
1//===- Scalarizer.cpp - Scalarize vector operations -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass converts vector operations into scalar operations (or, optionally,
10// operations on smaller vector widths), in order to expose optimization
11// opportunities on the individual scalar operations.
12// It is mainly intended for targets that do not have vector units, but it
13// may also be useful for revectorizing code to different vector widths.
14//
15//===----------------------------------------------------------------------===//
16
20#include "llvm/ADT/Twine.h"
23#include "llvm/IR/Argument.h"
24#include "llvm/IR/BasicBlock.h"
25#include "llvm/IR/Constants.h"
26#include "llvm/IR/DataLayout.h"
28#include "llvm/IR/Dominators.h"
29#include "llvm/IR/Function.h"
30#include "llvm/IR/IRBuilder.h"
31#include "llvm/IR/InstVisitor.h"
32#include "llvm/IR/InstrTypes.h"
33#include "llvm/IR/Instruction.h"
35#include "llvm/IR/Intrinsics.h"
36#include "llvm/IR/LLVMContext.h"
37#include "llvm/IR/Module.h"
38#include "llvm/IR/Type.h"
39#include "llvm/IR/Value.h"
43#include <cassert>
44#include <cstdint>
45#include <iterator>
46#include <map>
47#include <utility>
48
49using namespace llvm;
50
51#define DEBUG_TYPE "scalarizer"
52
54 BasicBlock *BB = Itr->getParent();
55 if (isa<PHINode>(Itr))
56 Itr = BB->getFirstInsertionPt();
57 if (Itr != BB->end())
58 Itr = skipDebugIntrinsics(Itr);
59 return Itr;
60}
61
62// Used to store the scattered form of a vector.
64
65// Used to map a vector Value and associated type to its scattered form.
66// The associated type is only non-null for pointer values that are "scattered"
67// when used as pointer operands to load or store.
68//
69// We use std::map because we want iterators to persist across insertion and
70// because the values are relatively large.
71using ScatterMap = std::map<std::pair<Value *, Type *>, ValueVector>;
72
73// Lists Instructions that have been replaced with scalar implementations,
74// along with a pointer to their scattered forms.
76
77namespace {
78
79struct VectorSplit {
80 // The type of the vector.
81 FixedVectorType *VecTy = nullptr;
82
83 // The number of elements packed in a fragment (other than the remainder).
84 unsigned NumPacked = 0;
85
86 // The number of fragments (scalars or smaller vectors) into which the vector
87 // shall be split.
88 unsigned NumFragments = 0;
89
90 // The type of each complete fragment.
91 Type *SplitTy = nullptr;
92
93 // The type of the remainder (last) fragment; null if all fragments are
94 // complete.
95 Type *RemainderTy = nullptr;
96
97 Type *getFragmentType(unsigned I) const {
98 return RemainderTy && I == NumFragments - 1 ? RemainderTy : SplitTy;
99 }
100};
101
102// Provides a very limited vector-like interface for lazily accessing one
103// component of a scattered vector or vector pointer.
104class Scatterer {
105public:
106 Scatterer() = default;
107
108 // Scatter V into Size components. If new instructions are needed,
109 // insert them before BBI in BB. If Cache is nonnull, use it to cache
110 // the results.
111 Scatterer(BasicBlock *bb, BasicBlock::iterator bbi, Value *v,
112 const VectorSplit &VS, ValueVector *cachePtr = nullptr);
113
114 // Return component I, creating a new Value for it if necessary.
115 Value *operator[](unsigned I);
116
117 // Return the number of components.
118 unsigned size() const { return VS.NumFragments; }
119
120private:
121 BasicBlock *BB;
123 Value *V;
124 VectorSplit VS;
125 bool IsPointer;
126 ValueVector *CachePtr;
127 ValueVector Tmp;
128};
129
130// FCmpSplitter(FCI)(Builder, X, Y, Name) uses Builder to create an FCmp
131// called Name that compares X and Y in the same way as FCI.
132struct FCmpSplitter {
133 FCmpSplitter(FCmpInst &fci) : FCI(fci) {}
134
135 Value *operator()(IRBuilder<> &Builder, Value *Op0, Value *Op1,
136 const Twine &Name) const {
137 return Builder.CreateFCmp(FCI.getPredicate(), Op0, Op1, Name);
138 }
139
140 FCmpInst &FCI;
141};
142
143// ICmpSplitter(ICI)(Builder, X, Y, Name) uses Builder to create an ICmp
144// called Name that compares X and Y in the same way as ICI.
145struct ICmpSplitter {
146 ICmpSplitter(ICmpInst &ici) : ICI(ici) {}
147
148 Value *operator()(IRBuilder<> &Builder, Value *Op0, Value *Op1,
149 const Twine &Name) const {
150 return Builder.CreateICmp(ICI.getPredicate(), Op0, Op1, Name);
151 }
152
153 ICmpInst &ICI;
154};
155
156// UnarySplitter(UO)(Builder, X, Name) uses Builder to create
157// a unary operator like UO called Name with operand X.
158struct UnarySplitter {
159 UnarySplitter(UnaryOperator &uo) : UO(uo) {}
160
161 Value *operator()(IRBuilder<> &Builder, Value *Op, const Twine &Name) const {
162 return Builder.CreateUnOp(UO.getOpcode(), Op, Name);
163 }
164
165 UnaryOperator &UO;
166};
167
168// BinarySplitter(BO)(Builder, X, Y, Name) uses Builder to create
169// a binary operator like BO called Name with operands X and Y.
170struct BinarySplitter {
171 BinarySplitter(BinaryOperator &bo) : BO(bo) {}
172
173 Value *operator()(IRBuilder<> &Builder, Value *Op0, Value *Op1,
174 const Twine &Name) const {
175 return Builder.CreateBinOp(BO.getOpcode(), Op0, Op1, Name);
176 }
177
178 BinaryOperator &BO;
179};
180
181// Information about a load or store that we're scalarizing.
182struct VectorLayout {
183 VectorLayout() = default;
184
185 // Return the alignment of fragment Frag.
186 Align getFragmentAlign(unsigned Frag) {
187 return commonAlignment(VecAlign, Frag * SplitSize);
188 }
189
190 // The split of the underlying vector type.
191 VectorSplit VS;
192
193 // The alignment of the vector.
194 Align VecAlign;
195
196 // The size of each (non-remainder) fragment in bytes.
197 uint64_t SplitSize = 0;
198};
199} // namespace
200
202 if (!isa<StructType>(Ty))
203 return false;
204 unsigned StructSize = Ty->getNumContainedTypes();
205 if (StructSize < 1)
206 return false;
207 FixedVectorType *VecTy = dyn_cast<FixedVectorType>(Ty->getContainedType(0));
208 if (!VecTy)
209 return false;
210 unsigned VecSize = VecTy->getNumElements();
211 for (unsigned I = 1; I < StructSize; I++) {
212 VecTy = dyn_cast<FixedVectorType>(Ty->getContainedType(I));
213 if (!VecTy || VecSize != VecTy->getNumElements())
214 return false;
215 }
216 return true;
217}
218
219/// Concatenate the given fragments to a single vector value of the type
220/// described in @p VS.
221static Value *concatenate(IRBuilder<> &Builder, ArrayRef<Value *> Fragments,
222 const VectorSplit &VS, Twine Name) {
223 unsigned NumElements = VS.VecTy->getNumElements();
224 SmallVector<int> ExtendMask;
225 SmallVector<int> InsertMask;
226
227 if (VS.NumPacked > 1) {
228 // Prepare the shufflevector masks once and re-use them for all
229 // fragments.
230 ExtendMask.resize(NumElements, -1);
231 for (unsigned I = 0; I < VS.NumPacked; ++I)
232 ExtendMask[I] = I;
233
234 InsertMask.resize(NumElements);
235 for (unsigned I = 0; I < NumElements; ++I)
236 InsertMask[I] = I;
237 }
238
239 Value *Res = PoisonValue::get(VS.VecTy);
240 for (unsigned I = 0; I < VS.NumFragments; ++I) {
241 Value *Fragment = Fragments[I];
242
243 unsigned NumPacked = VS.NumPacked;
244 if (I == VS.NumFragments - 1 && VS.RemainderTy) {
245 if (auto *RemVecTy = dyn_cast<FixedVectorType>(VS.RemainderTy))
246 NumPacked = RemVecTy->getNumElements();
247 else
248 NumPacked = 1;
249 }
250
251 if (NumPacked == 1) {
252 Res = Builder.CreateInsertElement(Res, Fragment, I * VS.NumPacked,
253 Name + ".upto" + Twine(I));
254 } else {
255 if (NumPacked < VS.NumPacked) {
256 // If last pack of remained bits not match current ExtendMask size.
257 ExtendMask.truncate(NumPacked);
258 ExtendMask.resize(NumElements, -1);
259 }
260
261 Fragment = Builder.CreateShuffleVector(
262 Fragment, PoisonValue::get(Fragment->getType()), ExtendMask);
263 if (I == 0) {
264 Res = Fragment;
265 } else {
266 for (unsigned J = 0; J < NumPacked; ++J)
267 InsertMask[I * VS.NumPacked + J] = NumElements + J;
268 Res = Builder.CreateShuffleVector(Res, Fragment, InsertMask,
269 Name + ".upto" + Twine(I));
270 for (unsigned J = 0; J < NumPacked; ++J)
271 InsertMask[I * VS.NumPacked + J] = I * VS.NumPacked + J;
272 }
273 }
274 }
275
276 return Res;
277}
278
279namespace {
280class ScalarizerVisitor : public InstVisitor<ScalarizerVisitor, bool> {
281public:
282 ScalarizerVisitor(DominatorTree *DT, const TargetTransformInfo *TTI,
283 ScalarizerPassOptions Options)
284 : DT(DT), TTI(TTI),
285 ScalarizeVariableInsertExtract(Options.ScalarizeVariableInsertExtract),
286 ScalarizeLoadStore(Options.ScalarizeLoadStore),
287 ScalarizeMinBits(Options.ScalarizeMinBits) {}
288
289 bool visit(Function &F);
290
291 // InstVisitor methods. They return true if the instruction was scalarized,
292 // false if nothing changed.
293 bool visitInstruction(Instruction &I) { return false; }
294 bool visitSelectInst(SelectInst &SI);
295 bool visitICmpInst(ICmpInst &ICI);
296 bool visitFCmpInst(FCmpInst &FCI);
297 bool visitUnaryOperator(UnaryOperator &UO);
298 bool visitBinaryOperator(BinaryOperator &BO);
299 bool visitGetElementPtrInst(GetElementPtrInst &GEPI);
300 bool visitCastInst(CastInst &CI);
301 bool visitBitCastInst(BitCastInst &BCI);
302 bool visitInsertElementInst(InsertElementInst &IEI);
303 bool visitExtractElementInst(ExtractElementInst &EEI);
304 bool visitExtractValueInst(ExtractValueInst &EVI);
305 bool visitShuffleVectorInst(ShuffleVectorInst &SVI);
306 bool visitPHINode(PHINode &PHI);
307 bool visitLoadInst(LoadInst &LI);
308 bool visitStoreInst(StoreInst &SI);
309 bool visitCallInst(CallInst &ICI);
310 bool visitFreezeInst(FreezeInst &FI);
311
312private:
313 Scatterer scatter(Instruction *Point, Value *V, const VectorSplit &VS);
314 void gather(Instruction *Op, const ValueVector &CV, const VectorSplit &VS);
315 void replaceUses(Instruction *Op, Value *CV);
316 bool canTransferMetadata(unsigned Kind);
317 void transferMetadataAndIRFlags(Instruction *Op, const ValueVector &CV);
318 std::optional<VectorSplit> getVectorSplit(Type *Ty);
319 std::optional<VectorLayout> getVectorLayout(Type *Ty, Align Alignment,
320 const DataLayout &DL);
321 bool finish();
322
323 template<typename T> bool splitUnary(Instruction &, const T &);
324 template<typename T> bool splitBinary(Instruction &, const T &);
325
326 bool splitCall(CallInst &CI);
327
328 ScatterMap Scattered;
329 GatherList Gathered;
330 bool Scalarized;
331
332 SmallVector<WeakTrackingVH, 32> PotentiallyDeadInstrs;
333
334 DominatorTree *DT;
335 const TargetTransformInfo *TTI;
336
337 const bool ScalarizeVariableInsertExtract;
338 const bool ScalarizeLoadStore;
339 const unsigned ScalarizeMinBits;
340};
341
342class ScalarizerLegacyPass : public FunctionPass {
343public:
344 static char ID;
345 ScalarizerPassOptions Options;
346 ScalarizerLegacyPass() : FunctionPass(ID), Options() {}
347 ScalarizerLegacyPass(const ScalarizerPassOptions &Options);
348 bool runOnFunction(Function &F) override;
349 void getAnalysisUsage(AnalysisUsage &AU) const override;
350};
351
352} // end anonymous namespace
353
354ScalarizerLegacyPass::ScalarizerLegacyPass(const ScalarizerPassOptions &Options)
355 : FunctionPass(ID), Options(Options) {}
356
357void ScalarizerLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const {
358 AU.addRequired<DominatorTreeWrapperPass>();
359 AU.addRequired<TargetTransformInfoWrapperPass>();
360 AU.addPreserved<DominatorTreeWrapperPass>();
361}
362
363char ScalarizerLegacyPass::ID = 0;
364INITIALIZE_PASS_BEGIN(ScalarizerLegacyPass, "scalarizer",
365 "Scalarize vector operations", false, false)
368INITIALIZE_PASS_END(ScalarizerLegacyPass, "scalarizer",
369 "Scalarize vector operations", false, false)
370
371Scatterer::Scatterer(BasicBlock *bb, BasicBlock::iterator bbi, Value *v,
372 const VectorSplit &VS, ValueVector *cachePtr)
373 : BB(bb), BBI(bbi), V(v), VS(VS), CachePtr(cachePtr) {
374 IsPointer = V->getType()->isPointerTy();
375 if (!CachePtr) {
376 Tmp.resize(VS.NumFragments, nullptr);
377 } else {
378 assert((CachePtr->empty() || VS.NumFragments == CachePtr->size() ||
379 IsPointer) &&
380 "Inconsistent vector sizes");
381 if (VS.NumFragments > CachePtr->size())
382 CachePtr->resize(VS.NumFragments, nullptr);
383 }
384}
385
386// Return fragment Frag, creating a new Value for it if necessary.
387Value *Scatterer::operator[](unsigned Frag) {
388 ValueVector &CV = CachePtr ? *CachePtr : Tmp;
389 // Try to reuse a previous value.
390 if (CV[Frag])
391 return CV[Frag];
392 IRBuilder<> Builder(BB, BBI);
393 if (IsPointer) {
394 if (Frag == 0)
395 CV[Frag] = V;
396 else
397 CV[Frag] = Builder.CreateConstGEP1_32(VS.SplitTy, V, Frag,
398 V->getName() + ".i" + Twine(Frag));
399 return CV[Frag];
400 }
401
402 Type *FragmentTy = VS.getFragmentType(Frag);
403
404 if (auto *VecTy = dyn_cast<FixedVectorType>(FragmentTy)) {
405 SmallVector<int> Mask;
406 for (unsigned J = 0; J < VecTy->getNumElements(); ++J)
407 Mask.push_back(Frag * VS.NumPacked + J);
408 CV[Frag] =
409 Builder.CreateShuffleVector(V, PoisonValue::get(V->getType()), Mask,
410 V->getName() + ".i" + Twine(Frag));
411 } else {
412 // Search through a chain of InsertElementInsts looking for element Frag.
413 // Record other elements in the cache. The new V is still suitable
414 // for all uncached indices.
415 while (true) {
416 InsertElementInst *Insert = dyn_cast<InsertElementInst>(V);
417 if (!Insert)
418 break;
419 ConstantInt *Idx = dyn_cast<ConstantInt>(Insert->getOperand(2));
420 if (!Idx)
421 break;
422 unsigned J = Idx->getZExtValue();
423 V = Insert->getOperand(0);
424 if (Frag * VS.NumPacked == J) {
425 CV[Frag] = Insert->getOperand(1);
426 return CV[Frag];
427 }
428
429 if (VS.NumPacked == 1 && !CV[J]) {
430 // Only cache the first entry we find for each index we're not actively
431 // searching for. This prevents us from going too far up the chain and
432 // caching incorrect entries.
433 CV[J] = Insert->getOperand(1);
434 }
435 }
436 CV[Frag] = Builder.CreateExtractElement(V, Frag * VS.NumPacked,
437 V->getName() + ".i" + Twine(Frag));
438 }
439
440 return CV[Frag];
441}
442
443bool ScalarizerLegacyPass::runOnFunction(Function &F) {
444 if (skipFunction(F))
445 return false;
446
447 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
448 const TargetTransformInfo *TTI =
449 &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
450 ScalarizerVisitor Impl(DT, TTI, Options);
451 return Impl.visit(F);
452}
453
455 return new ScalarizerLegacyPass(Options);
456}
457
458bool ScalarizerVisitor::visit(Function &F) {
459 assert(Gathered.empty() && Scattered.empty());
460
461 Scalarized = false;
462
463 // To ensure we replace gathered components correctly we need to do an ordered
464 // traversal of the basic blocks in the function.
465 ReversePostOrderTraversal<BasicBlock *> RPOT(&F.getEntryBlock());
466 for (BasicBlock *BB : RPOT) {
467 for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE;) {
468 Instruction *I = &*II;
469 bool Done = InstVisitor::visit(I);
470 ++II;
471 if (Done && I->getType()->isVoidTy()) {
472 I->eraseFromParent();
473 Scalarized = true;
474 }
475 }
476 }
477 return finish();
478}
479
480// Return a scattered form of V that can be accessed by Point. V must be a
481// vector or a pointer to a vector.
482Scatterer ScalarizerVisitor::scatter(Instruction *Point, Value *V,
483 const VectorSplit &VS) {
484 if (Argument *VArg = dyn_cast<Argument>(V)) {
485 // Put the scattered form of arguments in the entry block,
486 // so that it can be used everywhere.
487 Function *F = VArg->getParent();
488 BasicBlock *BB = &F->getEntryBlock();
489 return Scatterer(BB, BB->begin(), V, VS, &Scattered[{V, VS.SplitTy}]);
490 }
491 if (Instruction *VOp = dyn_cast<Instruction>(V)) {
492 // When scalarizing PHI nodes we might try to examine/rewrite InsertElement
493 // nodes in predecessors. If those predecessors are unreachable from entry,
494 // then the IR in those blocks could have unexpected properties resulting in
495 // infinite loops in Scatterer::operator[]. By simply treating values
496 // originating from instructions in unreachable blocks as undef we do not
497 // need to analyse them further.
498 if (!DT->isReachableFromEntry(VOp->getParent()))
499 return Scatterer(Point->getParent(), Point->getIterator(),
500 PoisonValue::get(V->getType()), VS);
501 // Put the scattered form of an instruction directly after the
502 // instruction, skipping over PHI nodes and debug intrinsics.
503 BasicBlock *BB = VOp->getParent();
504 return Scatterer(
505 BB, skipPastPhiNodesAndDbg(std::next(BasicBlock::iterator(VOp))), V, VS,
506 &Scattered[{V, VS.SplitTy}]);
507 }
508 // In the fallback case, just put the scattered before Point and
509 // keep the result local to Point.
510 return Scatterer(Point->getParent(), Point->getIterator(), V, VS);
511}
512
513// Replace Op with the gathered form of the components in CV. Defer the
514// deletion of Op and creation of the gathered form to the end of the pass,
515// so that we can avoid creating the gathered form if all uses of Op are
516// replaced with uses of CV.
517void ScalarizerVisitor::gather(Instruction *Op, const ValueVector &CV,
518 const VectorSplit &VS) {
519 transferMetadataAndIRFlags(Op, CV);
520
521 // If we already have a scattered form of Op (created from ExtractElements
522 // of Op itself), replace them with the new form.
523 ValueVector &SV = Scattered[{Op, VS.SplitTy}];
524 if (!SV.empty()) {
525 for (unsigned I = 0, E = SV.size(); I != E; ++I) {
526 Value *V = SV[I];
527 if (V == nullptr || SV[I] == CV[I])
528 continue;
529
531 if (isa<Instruction>(CV[I]))
532 CV[I]->takeName(Old);
533 Old->replaceAllUsesWith(CV[I]);
534 PotentiallyDeadInstrs.emplace_back(Old);
535 }
536 }
537 SV = CV;
538 Gathered.push_back(GatherList::value_type(Op, &SV));
539}
540
541// Replace Op with CV and collect Op has a potentially dead instruction.
542void ScalarizerVisitor::replaceUses(Instruction *Op, Value *CV) {
543 if (CV != Op) {
544 Op->replaceAllUsesWith(CV);
545 PotentiallyDeadInstrs.emplace_back(Op);
546 Scalarized = true;
547 }
548}
549
550// Return true if it is safe to transfer the given metadata tag from
551// vector to scalar instructions.
552bool ScalarizerVisitor::canTransferMetadata(unsigned Tag) {
553 return (Tag == LLVMContext::MD_tbaa
554 || Tag == LLVMContext::MD_fpmath
555 || Tag == LLVMContext::MD_tbaa_struct
556 || Tag == LLVMContext::MD_invariant_load
557 || Tag == LLVMContext::MD_alias_scope
558 || Tag == LLVMContext::MD_noalias
559 || Tag == LLVMContext::MD_mem_parallel_loop_access
560 || Tag == LLVMContext::MD_access_group);
561}
562
563// Transfer metadata from Op to the instructions in CV if it is known
564// to be safe to do so.
565void ScalarizerVisitor::transferMetadataAndIRFlags(Instruction *Op,
566 const ValueVector &CV) {
568 Op->getAllMetadataOtherThanDebugLoc(MDs);
569 for (Value *V : CV) {
570 if (Instruction *New = dyn_cast<Instruction>(V)) {
571 for (const auto &MD : MDs)
572 if (canTransferMetadata(MD.first))
573 New->setMetadata(MD.first, MD.second);
574 New->copyIRFlags(Op);
575 if (Op->getDebugLoc() && !New->getDebugLoc())
576 New->setDebugLoc(Op->getDebugLoc());
577 }
578 }
579}
580
581// Determine how Ty is split, if at all.
582std::optional<VectorSplit> ScalarizerVisitor::getVectorSplit(Type *Ty) {
583 VectorSplit Split;
585 if (!Split.VecTy)
586 return {};
587
588 unsigned NumElems = Split.VecTy->getNumElements();
589 Type *ElemTy = Split.VecTy->getElementType();
590
591 if (NumElems == 1 || ElemTy->isPointerTy() ||
592 2 * ElemTy->getScalarSizeInBits() > ScalarizeMinBits) {
593 Split.NumPacked = 1;
594 Split.NumFragments = NumElems;
595 Split.SplitTy = ElemTy;
596 } else {
597 Split.NumPacked = ScalarizeMinBits / ElemTy->getScalarSizeInBits();
598 if (Split.NumPacked >= NumElems)
599 return {};
600
601 Split.NumFragments = divideCeil(NumElems, Split.NumPacked);
602 Split.SplitTy = FixedVectorType::get(ElemTy, Split.NumPacked);
603
604 unsigned RemainderElems = NumElems % Split.NumPacked;
605 if (RemainderElems > 1)
606 Split.RemainderTy = FixedVectorType::get(ElemTy, RemainderElems);
607 else if (RemainderElems == 1)
608 Split.RemainderTy = ElemTy;
609 }
610
611 return Split;
612}
613
614// Try to fill in Layout from Ty, returning true on success. Alignment is
615// the alignment of the vector, or std::nullopt if the ABI default should be
616// used.
617std::optional<VectorLayout>
618ScalarizerVisitor::getVectorLayout(Type *Ty, Align Alignment,
619 const DataLayout &DL) {
620 std::optional<VectorSplit> VS = getVectorSplit(Ty);
621 if (!VS)
622 return {};
623
624 VectorLayout Layout;
625 Layout.VS = *VS;
626 // Check that we're dealing with full-byte fragments.
627 if (!DL.typeSizeEqualsStoreSize(VS->SplitTy) ||
628 (VS->RemainderTy && !DL.typeSizeEqualsStoreSize(VS->RemainderTy)))
629 return {};
630 Layout.VecAlign = Alignment;
631 Layout.SplitSize = DL.getTypeStoreSize(VS->SplitTy);
632 return Layout;
633}
634
635// Scalarize one-operand instruction I, using Split(Builder, X, Name)
636// to create an instruction like I with operand X and name Name.
637template<typename Splitter>
638bool ScalarizerVisitor::splitUnary(Instruction &I, const Splitter &Split) {
639 std::optional<VectorSplit> VS = getVectorSplit(I.getType());
640 if (!VS)
641 return false;
642
643 std::optional<VectorSplit> OpVS;
644 if (I.getOperand(0)->getType() == I.getType()) {
645 OpVS = VS;
646 } else {
647 OpVS = getVectorSplit(I.getOperand(0)->getType());
648 if (!OpVS || VS->NumPacked != OpVS->NumPacked)
649 return false;
650 }
651
652 IRBuilder<> Builder(&I);
653 Scatterer Op = scatter(&I, I.getOperand(0), *OpVS);
654 assert(Op.size() == VS->NumFragments && "Mismatched unary operation");
655 ValueVector Res;
656 Res.resize(VS->NumFragments);
657 for (unsigned Frag = 0; Frag < VS->NumFragments; ++Frag)
658 Res[Frag] = Split(Builder, Op[Frag], I.getName() + ".i" + Twine(Frag));
659 gather(&I, Res, *VS);
660 return true;
661}
662
663// Scalarize two-operand instruction I, using Split(Builder, X, Y, Name)
664// to create an instruction like I with operands X and Y and name Name.
665template<typename Splitter>
666bool ScalarizerVisitor::splitBinary(Instruction &I, const Splitter &Split) {
667 std::optional<VectorSplit> VS = getVectorSplit(I.getType());
668 if (!VS)
669 return false;
670
671 std::optional<VectorSplit> OpVS;
672 if (I.getOperand(0)->getType() == I.getType()) {
673 OpVS = VS;
674 } else {
675 OpVS = getVectorSplit(I.getOperand(0)->getType());
676 if (!OpVS || VS->NumPacked != OpVS->NumPacked)
677 return false;
678 }
679
680 IRBuilder<> Builder(&I);
681 Scatterer VOp0 = scatter(&I, I.getOperand(0), *OpVS);
682 Scatterer VOp1 = scatter(&I, I.getOperand(1), *OpVS);
683 assert(VOp0.size() == VS->NumFragments && "Mismatched binary operation");
684 assert(VOp1.size() == VS->NumFragments && "Mismatched binary operation");
685 ValueVector Res;
686 Res.resize(VS->NumFragments);
687 for (unsigned Frag = 0; Frag < VS->NumFragments; ++Frag) {
688 Value *Op0 = VOp0[Frag];
689 Value *Op1 = VOp1[Frag];
690 Res[Frag] = Split(Builder, Op0, Op1, I.getName() + ".i" + Twine(Frag));
691 }
692 gather(&I, Res, *VS);
693 return true;
694}
695
696/// If a call to a vector typed intrinsic function, split into a scalar call per
697/// element if possible for the intrinsic.
698bool ScalarizerVisitor::splitCall(CallInst &CI) {
699 Type *CallType = CI.getType();
700 bool AreAllVectorsOfMatchingSize = isStructOfMatchingFixedVectors(CallType);
701 std::optional<VectorSplit> VS;
702 if (AreAllVectorsOfMatchingSize)
703 VS = getVectorSplit(CallType->getContainedType(0));
704 else
705 VS = getVectorSplit(CallType);
706 if (!VS)
707 return false;
708
710 if (!F)
711 return false;
712
713 Intrinsic::ID ID = F->getIntrinsicID();
714
716 return false;
717
718 // unsigned NumElems = VT->getNumElements();
719 unsigned NumArgs = CI.arg_size();
720
721 ValueVector ScalarOperands(NumArgs);
722 SmallVector<Scatterer, 8> Scattered(NumArgs);
723 SmallVector<int> OverloadIdx(NumArgs, -1);
724
726 // Add return type if intrinsic is overloaded on it.
728 Tys.push_back(VS->SplitTy);
729
730 if (AreAllVectorsOfMatchingSize) {
731 for (unsigned I = 1; I < CallType->getNumContainedTypes(); I++) {
732 std::optional<VectorSplit> CurrVS =
733 getVectorSplit(cast<FixedVectorType>(CallType->getContainedType(I)));
734 // It is possible for VectorSplit.NumPacked >= NumElems. If that happens a
735 // VectorSplit is not returned and we will bailout of handling this call.
736 // The secondary bailout case is if NumPacked does not match. This can
737 // happen if ScalarizeMinBits is not set to the default. This means with
738 // certain ScalarizeMinBits intrinsics like frexp will only scalarize when
739 // the struct elements have the same bitness.
740 if (!CurrVS || CurrVS->NumPacked != VS->NumPacked)
741 return false;
743 Tys.push_back(CurrVS->SplitTy);
744 }
745 }
746 // Assumes that any vector type has the same number of elements as the return
747 // vector type, which is true for all current intrinsics.
748 for (unsigned I = 0; I != NumArgs; ++I) {
749 Value *OpI = CI.getOperand(I);
750 if ([[maybe_unused]] auto *OpVecTy =
752 assert(OpVecTy->getNumElements() == VS->VecTy->getNumElements());
753 std::optional<VectorSplit> OpVS = getVectorSplit(OpI->getType());
754 if (!OpVS || OpVS->NumPacked != VS->NumPacked) {
755 // The natural split of the operand doesn't match the result. This could
756 // happen if the vector elements are different and the ScalarizeMinBits
757 // option is used.
758 //
759 // We could in principle handle this case as well, at the cost of
760 // complicating the scattering machinery to support multiple scattering
761 // granularities for a single value.
762 return false;
763 }
764
765 Scattered[I] = scatter(&CI, OpI, *OpVS);
767 OverloadIdx[I] = Tys.size();
768 Tys.push_back(OpVS->SplitTy);
769 }
770 } else {
771 ScalarOperands[I] = OpI;
773 Tys.push_back(OpI->getType());
774 }
775 }
776
777 ValueVector Res(VS->NumFragments);
778 ValueVector ScalarCallOps(NumArgs);
779
780 Function *NewIntrin =
781 Intrinsic::getOrInsertDeclaration(F->getParent(), ID, Tys);
782 IRBuilder<> Builder(&CI);
783
784 // Perform actual scalarization, taking care to preserve any scalar operands.
785 for (unsigned I = 0; I < VS->NumFragments; ++I) {
786 bool IsRemainder = I == VS->NumFragments - 1 && VS->RemainderTy;
787 ScalarCallOps.clear();
788
789 if (IsRemainder)
790 Tys[0] = VS->RemainderTy;
791
792 for (unsigned J = 0; J != NumArgs; ++J) {
794 ScalarCallOps.push_back(ScalarOperands[J]);
795 } else {
796 ScalarCallOps.push_back(Scattered[J][I]);
797 if (IsRemainder && OverloadIdx[J] >= 0)
798 Tys[OverloadIdx[J]] = Scattered[J][I]->getType();
799 }
800 }
801
802 if (IsRemainder)
803 NewIntrin = Intrinsic::getOrInsertDeclaration(F->getParent(), ID, Tys);
804
805 Res[I] = Builder.CreateCall(NewIntrin, ScalarCallOps,
806 CI.getName() + ".i" + Twine(I));
807 }
808
809 gather(&CI, Res, *VS);
810 return true;
811}
812
813bool ScalarizerVisitor::visitSelectInst(SelectInst &SI) {
814 std::optional<VectorSplit> VS = getVectorSplit(SI.getType());
815 if (!VS)
816 return false;
817
818 std::optional<VectorSplit> CondVS;
819 if (isa<FixedVectorType>(SI.getCondition()->getType())) {
820 CondVS = getVectorSplit(SI.getCondition()->getType());
821 if (!CondVS || CondVS->NumPacked != VS->NumPacked) {
822 // This happens when ScalarizeMinBits is used.
823 return false;
824 }
825 }
826
827 IRBuilder<> Builder(&SI);
828 Scatterer VOp1 = scatter(&SI, SI.getOperand(1), *VS);
829 Scatterer VOp2 = scatter(&SI, SI.getOperand(2), *VS);
830 assert(VOp1.size() == VS->NumFragments && "Mismatched select");
831 assert(VOp2.size() == VS->NumFragments && "Mismatched select");
832 ValueVector Res;
833 Res.resize(VS->NumFragments);
834
835 if (CondVS) {
836 Scatterer VOp0 = scatter(&SI, SI.getOperand(0), *CondVS);
837 assert(VOp0.size() == CondVS->NumFragments && "Mismatched select");
838 for (unsigned I = 0; I < VS->NumFragments; ++I) {
839 Value *Op0 = VOp0[I];
840 Value *Op1 = VOp1[I];
841 Value *Op2 = VOp2[I];
842 Res[I] = Builder.CreateSelect(Op0, Op1, Op2,
843 SI.getName() + ".i" + Twine(I));
844 }
845 } else {
846 Value *Op0 = SI.getOperand(0);
847 for (unsigned I = 0; I < VS->NumFragments; ++I) {
848 Value *Op1 = VOp1[I];
849 Value *Op2 = VOp2[I];
850 Res[I] = Builder.CreateSelect(Op0, Op1, Op2,
851 SI.getName() + ".i" + Twine(I));
852 }
853 }
854 gather(&SI, Res, *VS);
855 return true;
856}
857
858bool ScalarizerVisitor::visitICmpInst(ICmpInst &ICI) {
859 return splitBinary(ICI, ICmpSplitter(ICI));
860}
861
862bool ScalarizerVisitor::visitFCmpInst(FCmpInst &FCI) {
863 return splitBinary(FCI, FCmpSplitter(FCI));
864}
865
866bool ScalarizerVisitor::visitUnaryOperator(UnaryOperator &UO) {
867 return splitUnary(UO, UnarySplitter(UO));
868}
869
870bool ScalarizerVisitor::visitBinaryOperator(BinaryOperator &BO) {
871 return splitBinary(BO, BinarySplitter(BO));
872}
873
874bool ScalarizerVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) {
875 std::optional<VectorSplit> VS = getVectorSplit(GEPI.getType());
876 if (!VS)
877 return false;
878
879 IRBuilder<> Builder(&GEPI);
880 unsigned NumIndices = GEPI.getNumIndices();
881
882 // The base pointer and indices might be scalar even if it's a vector GEP.
883 SmallVector<Value *, 8> ScalarOps{1 + NumIndices};
884 SmallVector<Scatterer, 8> ScatterOps{1 + NumIndices};
885
886 for (unsigned I = 0; I < 1 + NumIndices; ++I) {
887 if (auto *VecTy =
889 std::optional<VectorSplit> OpVS = getVectorSplit(VecTy);
890 if (!OpVS || OpVS->NumPacked != VS->NumPacked) {
891 // This can happen when ScalarizeMinBits is used.
892 return false;
893 }
894 ScatterOps[I] = scatter(&GEPI, GEPI.getOperand(I), *OpVS);
895 } else {
896 ScalarOps[I] = GEPI.getOperand(I);
897 }
898 }
899
900 ValueVector Res;
901 Res.resize(VS->NumFragments);
902 for (unsigned I = 0; I < VS->NumFragments; ++I) {
903 SmallVector<Value *, 8> SplitOps;
904 SplitOps.resize(1 + NumIndices);
905 for (unsigned J = 0; J < 1 + NumIndices; ++J) {
906 if (ScalarOps[J])
907 SplitOps[J] = ScalarOps[J];
908 else
909 SplitOps[J] = ScatterOps[J][I];
910 }
911 Res[I] = Builder.CreateGEP(GEPI.getSourceElementType(), SplitOps[0],
912 ArrayRef(SplitOps).drop_front(),
913 GEPI.getName() + ".i" + Twine(I));
914 if (GEPI.isInBounds())
915 if (GetElementPtrInst *NewGEPI = dyn_cast<GetElementPtrInst>(Res[I]))
916 NewGEPI->setIsInBounds();
917 }
918 gather(&GEPI, Res, *VS);
919 return true;
920}
921
922bool ScalarizerVisitor::visitCastInst(CastInst &CI) {
923 std::optional<VectorSplit> DestVS = getVectorSplit(CI.getDestTy());
924 if (!DestVS)
925 return false;
926
927 std::optional<VectorSplit> SrcVS = getVectorSplit(CI.getSrcTy());
928 if (!SrcVS || SrcVS->NumPacked != DestVS->NumPacked)
929 return false;
930
931 IRBuilder<> Builder(&CI);
932 Scatterer Op0 = scatter(&CI, CI.getOperand(0), *SrcVS);
933 assert(Op0.size() == SrcVS->NumFragments && "Mismatched cast");
934 ValueVector Res;
935 Res.resize(DestVS->NumFragments);
936 for (unsigned I = 0; I < DestVS->NumFragments; ++I)
937 Res[I] =
938 Builder.CreateCast(CI.getOpcode(), Op0[I], DestVS->getFragmentType(I),
939 CI.getName() + ".i" + Twine(I));
940 gather(&CI, Res, *DestVS);
941 return true;
942}
943
944bool ScalarizerVisitor::visitBitCastInst(BitCastInst &BCI) {
945 std::optional<VectorSplit> DstVS = getVectorSplit(BCI.getDestTy());
946 std::optional<VectorSplit> SrcVS = getVectorSplit(BCI.getSrcTy());
947
948 if (DstVS && !SrcVS && BCI.getSrcTy()->isIntegerTy() && !DstVS->RemainderTy &&
949 DstVS->NumPacked == 1 && DstVS->SplitTy->isIntegerTy()) {
950 IRBuilder<> Builder(&BCI);
951 Builder.SetCurrentDebugLocation(BCI.getDebugLoc());
952 ValueVector Res(DstVS->NumFragments);
953 unsigned FragmentBits = DstVS->SplitTy->getPrimitiveSizeInBits();
954 bool IsBigEndian = BCI.getDataLayout().isBigEndian();
955 for (unsigned I = 0; I < DstVS->NumFragments; ++I) {
956 unsigned FragmentIndex = IsBigEndian ? DstVS->NumFragments - I - 1 : I;
957 Value *Fragment = BCI.getOperand(0);
958 if (FragmentIndex)
959 Fragment = Builder.CreateLShr(Fragment, FragmentIndex * FragmentBits);
960 Res[I] = Builder.CreateTruncOrBitCast(Fragment, DstVS->getFragmentType(I),
961 BCI.getName() + ".i" + Twine(I));
962 }
963 gather(&BCI, Res, *DstVS);
964 return true;
965 }
966
967 if (!DstVS && SrcVS && BCI.getDestTy()->isIntegerTy() &&
968 !SrcVS->RemainderTy && SrcVS->NumPacked == 1 &&
969 SrcVS->SplitTy->isIntegerTy()) {
970 IRBuilder<> Builder(&BCI);
971 Builder.SetCurrentDebugLocation(BCI.getDebugLoc());
972 Scatterer Op0 = scatter(&BCI, BCI.getOperand(0), *SrcVS);
973 Value *Result = nullptr;
974 unsigned FragmentBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
975 bool IsBigEndian = BCI.getDataLayout().isBigEndian();
976 for (unsigned I = 0; I < SrcVS->NumFragments; ++I) {
977 unsigned FragmentIndex = IsBigEndian ? SrcVS->NumFragments - I - 1 : I;
978 Value *Fragment = Builder.CreateZExtOrTrunc(Op0[I], BCI.getDestTy());
979 if (FragmentIndex)
980 Fragment = Builder.CreateShl(Fragment, FragmentIndex * FragmentBits);
981 Result = Result ? Builder.CreateOr(Result, Fragment) : Fragment;
982 }
983 replaceUses(&BCI, Result);
984 return true;
985 }
986
987 if (!DstVS || !SrcVS || DstVS->RemainderTy || SrcVS->RemainderTy)
988 return false;
989
990 const bool isPointerTy = DstVS->VecTy->getElementType()->isPointerTy();
991
992 // Vectors of pointers are always fully scalarized.
993 assert(!isPointerTy || (DstVS->NumPacked == 1 && SrcVS->NumPacked == 1));
994
995 IRBuilder<> Builder(&BCI);
996 Scatterer Op0 = scatter(&BCI, BCI.getOperand(0), *SrcVS);
997 ValueVector Res;
998 Res.resize(DstVS->NumFragments);
999
1000 unsigned DstSplitBits = DstVS->SplitTy->getPrimitiveSizeInBits();
1001 unsigned SrcSplitBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
1002
1003 if (isPointerTy || DstSplitBits == SrcSplitBits) {
1004 assert(DstVS->NumFragments == SrcVS->NumFragments);
1005 for (unsigned I = 0; I < DstVS->NumFragments; ++I) {
1006 Res[I] = Builder.CreateBitCast(Op0[I], DstVS->getFragmentType(I),
1007 BCI.getName() + ".i" + Twine(I));
1008 }
1009 } else if (SrcSplitBits % DstSplitBits == 0) {
1010 // Convert each source fragment to the same-sized destination vector and
1011 // then scatter the result to the destination.
1012 VectorSplit MidVS;
1013 MidVS.NumPacked = DstVS->NumPacked;
1014 MidVS.NumFragments = SrcSplitBits / DstSplitBits;
1015 MidVS.VecTy = FixedVectorType::get(DstVS->VecTy->getElementType(),
1016 MidVS.NumPacked * MidVS.NumFragments);
1017 MidVS.SplitTy = DstVS->SplitTy;
1018
1019 unsigned ResI = 0;
1020 for (unsigned I = 0; I < SrcVS->NumFragments; ++I) {
1021 Value *V = Op0[I];
1022
1023 // Look through any existing bitcasts before converting to <N x t2>.
1024 // In the best case, the resulting conversion might be a no-op.
1025 Instruction *VI;
1026 while ((VI = dyn_cast<Instruction>(V)) &&
1027 VI->getOpcode() == Instruction::BitCast)
1028 V = VI->getOperand(0);
1029
1030 V = Builder.CreateBitCast(V, MidVS.VecTy, V->getName() + ".cast");
1031
1032 Scatterer Mid = scatter(&BCI, V, MidVS);
1033 for (unsigned J = 0; J < MidVS.NumFragments; ++J)
1034 Res[ResI++] = Mid[J];
1035 }
1036 } else if (DstSplitBits % SrcSplitBits == 0) {
1037 // Gather enough source fragments to make up a destination fragment and
1038 // then convert to the destination type.
1039 VectorSplit MidVS;
1040 MidVS.NumFragments = DstSplitBits / SrcSplitBits;
1041 MidVS.NumPacked = SrcVS->NumPacked;
1042 MidVS.VecTy = FixedVectorType::get(SrcVS->VecTy->getElementType(),
1043 MidVS.NumPacked * MidVS.NumFragments);
1044 MidVS.SplitTy = SrcVS->SplitTy;
1045
1046 unsigned SrcI = 0;
1047 SmallVector<Value *, 8> ConcatOps;
1048 ConcatOps.resize(MidVS.NumFragments);
1049 for (unsigned I = 0; I < DstVS->NumFragments; ++I) {
1050 for (unsigned J = 0; J < MidVS.NumFragments; ++J)
1051 ConcatOps[J] = Op0[SrcI++];
1052 Value *V = concatenate(Builder, ConcatOps, MidVS,
1053 BCI.getName() + ".i" + Twine(I));
1054 Res[I] = Builder.CreateBitCast(V, DstVS->getFragmentType(I),
1055 BCI.getName() + ".i" + Twine(I));
1056 }
1057 } else {
1058 return false;
1059 }
1060
1061 gather(&BCI, Res, *DstVS);
1062 return true;
1063}
1064
1065bool ScalarizerVisitor::visitInsertElementInst(InsertElementInst &IEI) {
1066 std::optional<VectorSplit> VS = getVectorSplit(IEI.getType());
1067 if (!VS)
1068 return false;
1069
1070 IRBuilder<> Builder(&IEI);
1071 Scatterer Op0 = scatter(&IEI, IEI.getOperand(0), *VS);
1072 Value *NewElt = IEI.getOperand(1);
1073 Value *InsIdx = IEI.getOperand(2);
1074
1075 ValueVector Res;
1076 Res.resize(VS->NumFragments);
1077
1078 if (auto *CI = dyn_cast<ConstantInt>(InsIdx)) {
1079 unsigned Idx = CI->getZExtValue();
1080 unsigned Fragment = Idx / VS->NumPacked;
1081 for (unsigned I = 0; I < VS->NumFragments; ++I) {
1082 if (I == Fragment) {
1083 bool IsPacked = VS->NumPacked > 1;
1084 if (Fragment == VS->NumFragments - 1 && VS->RemainderTy &&
1085 !VS->RemainderTy->isVectorTy())
1086 IsPacked = false;
1087 if (IsPacked) {
1088 Res[I] =
1089 Builder.CreateInsertElement(Op0[I], NewElt, Idx % VS->NumPacked);
1090 } else {
1091 Res[I] = NewElt;
1092 }
1093 } else {
1094 Res[I] = Op0[I];
1095 }
1096 }
1097 } else {
1098 // Never split a variable insertelement that isn't fully scalarized.
1099 if (!ScalarizeVariableInsertExtract || VS->NumPacked > 1)
1100 return false;
1101
1102 for (unsigned I = 0; I < VS->NumFragments; ++I) {
1103 Value *ShouldReplace =
1104 Builder.CreateICmpEQ(InsIdx, ConstantInt::get(InsIdx->getType(), I),
1105 InsIdx->getName() + ".is." + Twine(I));
1106 Value *OldElt = Op0[I];
1107 Res[I] = Builder.CreateSelect(ShouldReplace, NewElt, OldElt,
1108 IEI.getName() + ".i" + Twine(I));
1109 }
1110 }
1111
1112 gather(&IEI, Res, *VS);
1113 return true;
1114}
1115
1116bool ScalarizerVisitor::visitExtractValueInst(ExtractValueInst &EVI) {
1117 Value *Op = EVI.getOperand(0);
1118 Type *OpTy = Op->getType();
1119 ValueVector Res;
1121 return false;
1122 if (CallInst *CI = dyn_cast<CallInst>(Op)) {
1123 Function *F = CI->getCalledFunction();
1124 if (!F)
1125 return false;
1126 Intrinsic::ID ID = F->getIntrinsicID();
1128 return false;
1129 // Note: Fall through means Operand is a`CallInst` and it is defined in
1130 // `isTriviallyScalarizable`.
1131 } else
1132 return false;
1133 Type *VecType = cast<FixedVectorType>(OpTy->getContainedType(0));
1134 std::optional<VectorSplit> VS = getVectorSplit(VecType);
1135 if (!VS)
1136 return false;
1137 for (unsigned I = 1; I < OpTy->getNumContainedTypes(); I++) {
1138 std::optional<VectorSplit> CurrVS =
1139 getVectorSplit(cast<FixedVectorType>(OpTy->getContainedType(I)));
1140 // It is possible for VectorSplit.NumPacked >= NumElems. If that happens a
1141 // VectorSplit is not returned and we will bailout of handling this call.
1142 // The secondary bailout case is if NumPacked does not match. This can
1143 // happen if ScalarizeMinBits is not set to the default. This means with
1144 // certain ScalarizeMinBits intrinsics like frexp will only scalarize when
1145 // the struct elements have the same bitness.
1146 if (!CurrVS || CurrVS->NumPacked != VS->NumPacked)
1147 return false;
1148 }
1149 IRBuilder<> Builder(&EVI);
1150 Scatterer Op0 = scatter(&EVI, Op, *VS);
1151 assert(!EVI.getIndices().empty() && "Make sure an index exists");
1152 // Note for our use case we only care about the top level index.
1153 unsigned Index = EVI.getIndices()[0];
1154 for (unsigned OpIdx = 0; OpIdx < Op0.size(); ++OpIdx) {
1155 Value *ResElem = Builder.CreateExtractValue(
1156 Op0[OpIdx], Index, EVI.getName() + ".elem" + Twine(Index));
1157 Res.push_back(ResElem);
1158 }
1159
1160 Type *ActualVecType = cast<FixedVectorType>(OpTy->getContainedType(Index));
1161 std::optional<VectorSplit> AVS = getVectorSplit(ActualVecType);
1162 gather(&EVI, Res, *AVS);
1163 return true;
1164}
1165
1166bool ScalarizerVisitor::visitExtractElementInst(ExtractElementInst &EEI) {
1167 std::optional<VectorSplit> VS = getVectorSplit(EEI.getOperand(0)->getType());
1168 if (!VS)
1169 return false;
1170
1171 IRBuilder<> Builder(&EEI);
1172 Scatterer Op0 = scatter(&EEI, EEI.getOperand(0), *VS);
1173 Value *ExtIdx = EEI.getOperand(1);
1174
1175 if (auto *CI = dyn_cast<ConstantInt>(ExtIdx)) {
1176 unsigned Idx = CI->getZExtValue();
1177 if (Idx >= VS->VecTy->getNumElements())
1178 return false;
1179 unsigned Fragment = Idx / VS->NumPacked;
1180 Value *Res = Op0[Fragment];
1181 bool IsPacked = VS->NumPacked > 1;
1182 if (Fragment == VS->NumFragments - 1 && VS->RemainderTy &&
1183 !VS->RemainderTy->isVectorTy())
1184 IsPacked = false;
1185 if (IsPacked)
1186 Res = Builder.CreateExtractElement(Res, Idx % VS->NumPacked);
1187 replaceUses(&EEI, Res);
1188 return true;
1189 }
1190
1191 // Never split a variable extractelement that isn't fully scalarized.
1192 if (!ScalarizeVariableInsertExtract || VS->NumPacked > 1)
1193 return false;
1194
1195 Value *Res = PoisonValue::get(VS->VecTy->getElementType());
1196 for (unsigned I = 0; I < VS->NumFragments; ++I) {
1197 Value *ShouldExtract =
1198 Builder.CreateICmpEQ(ExtIdx, ConstantInt::get(ExtIdx->getType(), I),
1199 ExtIdx->getName() + ".is." + Twine(I));
1200 Value *Elt = Op0[I];
1201 Res = Builder.CreateSelect(ShouldExtract, Elt, Res,
1202 EEI.getName() + ".upto" + Twine(I));
1203 }
1204 replaceUses(&EEI, Res);
1205 return true;
1206}
1207
1208bool ScalarizerVisitor::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
1209 std::optional<VectorSplit> VS = getVectorSplit(SVI.getType());
1210 std::optional<VectorSplit> VSOp =
1211 getVectorSplit(SVI.getOperand(0)->getType());
1212 if (!VS || !VSOp || VS->NumPacked > 1 || VSOp->NumPacked > 1)
1213 return false;
1214
1215 Scatterer Op0 = scatter(&SVI, SVI.getOperand(0), *VSOp);
1216 Scatterer Op1 = scatter(&SVI, SVI.getOperand(1), *VSOp);
1217 ValueVector Res;
1218 Res.resize(VS->NumFragments);
1219
1220 for (unsigned I = 0; I < VS->NumFragments; ++I) {
1221 int Selector = SVI.getMaskValue(I);
1222 if (Selector < 0)
1223 Res[I] = PoisonValue::get(VS->VecTy->getElementType());
1224 else if (unsigned(Selector) < Op0.size())
1225 Res[I] = Op0[Selector];
1226 else
1227 Res[I] = Op1[Selector - Op0.size()];
1228 }
1229 gather(&SVI, Res, *VS);
1230 return true;
1231}
1232
1233bool ScalarizerVisitor::visitPHINode(PHINode &PHI) {
1234 std::optional<VectorSplit> VS = getVectorSplit(PHI.getType());
1235 if (!VS)
1236 return false;
1237
1238 IRBuilder<> Builder(&PHI);
1239 ValueVector Res;
1240 Res.resize(VS->NumFragments);
1241
1242 unsigned NumOps = PHI.getNumOperands();
1243 for (unsigned I = 0; I < VS->NumFragments; ++I) {
1244 Res[I] = Builder.CreatePHI(VS->getFragmentType(I), NumOps,
1245 PHI.getName() + ".i" + Twine(I));
1246 }
1247
1248 for (unsigned I = 0; I < NumOps; ++I) {
1249 Scatterer Op = scatter(&PHI, PHI.getIncomingValue(I), *VS);
1250 BasicBlock *IncomingBlock = PHI.getIncomingBlock(I);
1251 for (unsigned J = 0; J < VS->NumFragments; ++J)
1252 cast<PHINode>(Res[J])->addIncoming(Op[J], IncomingBlock);
1253 }
1254 gather(&PHI, Res, *VS);
1255 return true;
1256}
1257
1258bool ScalarizerVisitor::visitLoadInst(LoadInst &LI) {
1259 if (!ScalarizeLoadStore)
1260 return false;
1261 if (!LI.isSimple())
1262 return false;
1263
1264 std::optional<VectorLayout> Layout = getVectorLayout(
1265 LI.getType(), LI.getAlign(), LI.getDataLayout());
1266 if (!Layout)
1267 return false;
1268
1269 IRBuilder<> Builder(&LI);
1270 Scatterer Ptr = scatter(&LI, LI.getPointerOperand(), Layout->VS);
1271 ValueVector Res;
1272 Res.resize(Layout->VS.NumFragments);
1273
1274 for (unsigned I = 0; I < Layout->VS.NumFragments; ++I) {
1275 Res[I] = Builder.CreateAlignedLoad(Layout->VS.getFragmentType(I), Ptr[I],
1276 Align(Layout->getFragmentAlign(I)),
1277 LI.getName() + ".i" + Twine(I));
1278 }
1279 gather(&LI, Res, Layout->VS);
1280 return true;
1281}
1282
1283bool ScalarizerVisitor::visitStoreInst(StoreInst &SI) {
1284 if (!ScalarizeLoadStore)
1285 return false;
1286 if (!SI.isSimple())
1287 return false;
1288
1289 Value *FullValue = SI.getValueOperand();
1290 std::optional<VectorLayout> Layout = getVectorLayout(
1291 FullValue->getType(), SI.getAlign(), SI.getDataLayout());
1292 if (!Layout)
1293 return false;
1294
1295 IRBuilder<> Builder(&SI);
1296 Scatterer VPtr = scatter(&SI, SI.getPointerOperand(), Layout->VS);
1297 Scatterer VVal = scatter(&SI, FullValue, Layout->VS);
1298
1299 ValueVector Stores;
1300 Stores.resize(Layout->VS.NumFragments);
1301 for (unsigned I = 0; I < Layout->VS.NumFragments; ++I) {
1302 Value *Val = VVal[I];
1303 Value *Ptr = VPtr[I];
1304 Stores[I] =
1305 Builder.CreateAlignedStore(Val, Ptr, Layout->getFragmentAlign(I));
1306 }
1307 transferMetadataAndIRFlags(&SI, Stores);
1308 return true;
1309}
1310
1311bool ScalarizerVisitor::visitCallInst(CallInst &CI) {
1312 return splitCall(CI);
1313}
1314
1315bool ScalarizerVisitor::visitFreezeInst(FreezeInst &FI) {
1316 return splitUnary(FI, [](IRBuilder<> &Builder, Value *Op, const Twine &Name) {
1317 return Builder.CreateFreeze(Op, Name);
1318 });
1319}
1320
1321// Delete the instructions that we scalarized. If a full vector result
1322// is still needed, recreate it using InsertElements.
1323bool ScalarizerVisitor::finish() {
1324 // The presence of data in Gathered or Scattered indicates changes
1325 // made to the Function.
1326 if (Gathered.empty() && Scattered.empty() && !Scalarized)
1327 return false;
1328 for (const auto &GMI : Gathered) {
1329 Instruction *Op = GMI.first;
1330 ValueVector &CV = *GMI.second;
1331 if (!Op->use_empty()) {
1332 // The value is still needed, so recreate it using a series of
1333 // insertelements and/or shufflevectors.
1334 Value *Res;
1335 if (auto *Ty = dyn_cast<FixedVectorType>(Op->getType())) {
1336 BasicBlock *BB = Op->getParent();
1337 IRBuilder<> Builder(Op);
1338 if (isa<PHINode>(Op))
1339 Builder.SetInsertPoint(BB, BB->getFirstInsertionPt());
1340
1341 VectorSplit VS = *getVectorSplit(Ty);
1342 assert(VS.NumFragments == CV.size());
1343
1344 Res = concatenate(Builder, CV, VS, Op->getName());
1345
1346 Res->takeName(Op);
1347 } else if (auto *Ty = dyn_cast<StructType>(Op->getType())) {
1348 BasicBlock *BB = Op->getParent();
1349 IRBuilder<> Builder(Op);
1350 if (isa<PHINode>(Op))
1351 Builder.SetInsertPoint(BB, BB->getFirstInsertionPt());
1352
1353 // Iterate over each element in the struct
1354 unsigned NumOfStructElements = Ty->getNumElements();
1355 SmallVector<ValueVector, 4> ElemCV(NumOfStructElements);
1356 for (unsigned I = 0; I < NumOfStructElements; ++I) {
1357 for (auto *CVelem : CV) {
1358 Value *Elem = Builder.CreateExtractValue(
1359 CVelem, I, Op->getName() + ".elem" + Twine(I));
1360 ElemCV[I].push_back(Elem);
1361 }
1362 }
1363 Res = PoisonValue::get(Ty);
1364 for (unsigned I = 0; I < NumOfStructElements; ++I) {
1365 Type *ElemTy = Ty->getElementType(I);
1366 assert(isa<FixedVectorType>(ElemTy) &&
1367 "Only Structs of all FixedVectorType supported");
1368 VectorSplit VS = *getVectorSplit(ElemTy);
1369 assert(VS.NumFragments == CV.size());
1370
1371 Value *ConcatenatedVector =
1372 concatenate(Builder, ElemCV[I], VS, Op->getName());
1373 Res = Builder.CreateInsertValue(Res, ConcatenatedVector, I,
1374 Op->getName() + ".insert");
1375 }
1376 } else {
1377 assert(CV.size() == 1 && Op->getType() == CV[0]->getType());
1378 Res = CV[0];
1379 if (Op == Res)
1380 continue;
1381 }
1382 Op->replaceAllUsesWith(Res);
1383 }
1384 PotentiallyDeadInstrs.emplace_back(Op);
1385 }
1386 Gathered.clear();
1387 Scattered.clear();
1388 Scalarized = false;
1389
1391
1392 return true;
1393}
1394
1398 ScalarizerVisitor Impl(DT, TTI, Options);
1399 bool Changed = Impl.visit(F);
1402 return Changed ? PA : PreservedAnalyses::all();
1403}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
aarch64 promote const
unsigned uint64_t
Rewrite undef for PHI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
Module.h This file contains the declarations for the Module class.
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
static LVOptions Options
Definition LVOptions.cpp:25
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
SmallVector< std::pair< Instruction *, ValueVector * >, 16 > GatherList
static BasicBlock::iterator skipPastPhiNodesAndDbg(BasicBlock::iterator Itr)
static bool isStructOfMatchingFixedVectors(Type *Ty)
std::map< std::pair< Value *, Type * >, ValueVector > ScatterMap
SmallVector< Value *, 8 > ValueVector
static Value * concatenate(IRBuilder<> &Builder, ArrayRef< Value * > Fragments, const VectorSplit &VS, Twine Name)
Concatenate the given fragments to a single vector value of the type described in VS.
This pass converts vector operations into scalar operations (or, optionally, operations on smaller ve...
This file defines the SmallVector class.
This pass exposes codegen information to IR-level passes.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
LLVM Basic Block Representation.
Definition BasicBlock.h:62
iterator end()
Definition BasicBlock.h:459
iterator begin()
Instruction iterator methods.
Definition BasicBlock.h:446
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
const Function * getParent() const
Return the enclosing method, or null if none.
Definition BasicBlock.h:213
InstListType::iterator iterator
Instruction iterators...
Definition BasicBlock.h:170
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
unsigned arg_size() const
Type * getSrcTy() const
Return the source type, as a convenience.
Definition InstrTypes.h:679
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
Definition InstrTypes.h:674
Type * getDestTy() const
Return the destination type, as a convenience.
Definition InstrTypes.h:681
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:168
bool isBigEndian() const
Definition DataLayout.h:218
Analysis pass which computes a DominatorTree.
Definition Dominators.h:241
Legacy analysis pass which computes a DominatorTree.
Definition Dominators.h:277
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
ArrayRef< unsigned > getIndices() const
This instruction compares its operands according to the predicate given to the constructor.
Class to represent fixed width SIMD vectors.
unsigned getNumElements() const
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:867
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
LLVM_ABI bool isInBounds() const
Determine whether the GEP has the inbounds flag.
Type * getSourceElementType() const
unsigned getNumIndices() const
This instruction compares its operands according to the predicate given to the constructor.
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition IRBuilder.h:2733
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition IRBuilder.h:2726
Value * CreateFreeze(Value *V, const Twine &Name="")
Definition IRBuilder.h:2745
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:181
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2910
VectorType * getType() const
Overload to return most specific vector type.
Base class for instruction visitors.
Definition InstVisitor.h:78
void visit(Iterator Start, Iterator End)
Definition InstVisitor.h:87
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Value * getPointerOperand()
bool isSimple() const
Align getAlign() const
Return the alignment of the access that is being performed.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
int getMaskValue(unsigned Elt) const
Return the shuffle mask value of this instruction for the given element index.
VectorType * getType() const
Overload to return most specific vector type.
void truncate(size_type N)
Like resize, but requires that N is less than size().
void resize(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetTransformInfo.
Wrapper pass for TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:282
unsigned getNumContainedTypes() const
Return the number of types in the derived type.
Definition Type.h:403
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:232
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
Definition Type.h:397
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:400
const ParentTy * getParent() const
Definition ilist_node.h:34
self_iterator getIterator()
Definition ilist_node.h:123
Changed
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1669
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Done
Definition Threading.h:60
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI BasicBlock::iterator skipDebugIntrinsics(BasicBlock::iterator It)
Advance It while it points to a debug instruction and return the result.
bool isPointerTy(const Type *T)
Definition SPIRVUtils.h:383
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ABI bool isTriviallyScalarizable(Intrinsic::ID ID)
Identify if the intrinsic is trivially scalarizable.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
LLVM_ABI bool isVectorIntrinsicWithStructReturnOverloadAtField(Intrinsic::ID ID, int RetIdx, const TargetTransformInfo *TTI)
Identifies if the vector form of the intrinsic that returns a struct is overloaded at the struct elem...
TargetTransformInfo TTI
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI bool isVectorIntrinsicWithScalarOpAtArg(Intrinsic::ID ID, unsigned ScalarOpdIdx, const TargetTransformInfo *TTI)
Identifies if the vector form of the intrinsic has a scalar operand.
DWARFExpression::Operation Op
LLVM_ABI FunctionPass * createScalarizerPass(const ScalarizerPassOptions &Options=ScalarizerPassOptions())
Create a legacy pass manager instance of the Scalarizer pass.
ArrayRef(const T &OneElt) -> ArrayRef< T >
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructionsPermissive(SmallVectorImpl< WeakTrackingVH > &DeadInsts, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
Same functionality as RecursivelyDeleteTriviallyDeadInstructions, but allow instructions that are not...
Definition Local.cpp:537
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:201
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID, int OpdIdx, const TargetTransformInfo *TTI)
Identifies if the vector form of the intrinsic is overloaded on the type of the operand at index OpdI...
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39