51#define DEBUG_TYPE "scalarizer"
57 if (isa<PHINode>(Itr))
73using ScatterMap = std::map<std::pair<Value *, Type *>, ValueVector>;
84 unsigned NumPacked = 0;
88 unsigned NumFragments = 0;
91 Type *SplitTy =
nullptr;
95 Type *RemainderTy =
nullptr;
97 Type *getFragmentType(
unsigned I)
const {
98 return RemainderTy &&
I == NumFragments - 1 ? RemainderTy : SplitTy;
106 Scatterer() =
default;
112 const VectorSplit &VS, ValueVector *cachePtr =
nullptr);
115 Value *operator[](
unsigned I);
118 unsigned size()
const {
return VS.NumFragments; }
126 ValueVector *CachePtr;
133 FCmpSplitter(
FCmpInst &fci) : FCI(fci) {}
146 ICmpSplitter(
ICmpInst &ici) : ICI(ici) {}
158struct UnarySplitter {
170struct BinarySplitter {
183 VectorLayout() =
default;
186 Align getFragmentAlign(
unsigned Frag) {
200static bool isStructOfMatchingFixedVectors(
Type *Ty) {
201 if (!isa<StructType>(Ty))
210 for (
unsigned I = 1;
I < StructSize;
I++) {
222 unsigned NumElements = VS.VecTy->getNumElements();
226 if (VS.NumPacked > 1) {
229 ExtendMask.
resize(NumElements, -1);
230 for (
unsigned I = 0;
I < VS.NumPacked; ++
I)
233 InsertMask.
resize(NumElements);
234 for (
unsigned I = 0;
I < NumElements; ++
I)
239 for (
unsigned I = 0;
I < VS.NumFragments; ++
I) {
240 Value *Fragment = Fragments[
I];
242 unsigned NumPacked = VS.NumPacked;
243 if (
I == VS.NumFragments - 1 && VS.RemainderTy) {
244 if (
auto *RemVecTy = dyn_cast<FixedVectorType>(VS.RemainderTy))
245 NumPacked = RemVecTy->getNumElements();
250 if (NumPacked == 1) {
258 for (
unsigned J = 0; J < NumPacked; ++J)
259 InsertMask[
I * VS.NumPacked + J] = NumElements + J;
262 for (
unsigned J = 0; J < NumPacked; ++J)
263 InsertMask[
I * VS.NumPacked + J] =
I * VS.NumPacked + J;
271class ScalarizerVisitor :
public InstVisitor<ScalarizerVisitor, bool> {
276 ScalarizeVariableInsertExtract(
Options.ScalarizeVariableInsertExtract),
277 ScalarizeLoadStore(
Options.ScalarizeLoadStore),
278 ScalarizeMinBits(
Options.ScalarizeMinBits) {}
305 void gather(
Instruction *
Op,
const ValueVector &CV,
const VectorSplit &VS);
307 bool canTransferMetadata(
unsigned Kind);
308 void transferMetadataAndIRFlags(
Instruction *
Op,
const ValueVector &CV);
309 std::optional<VectorSplit> getVectorSplit(
Type *Ty);
310 std::optional<VectorLayout> getVectorLayout(
Type *Ty,
Align Alignment,
314 template<
typename T>
bool splitUnary(
Instruction &,
const T &);
315 template<
typename T>
bool splitBinary(
Instruction &,
const T &);
319 ScatterMap Scattered;
328 const bool ScalarizeVariableInsertExtract;
329 const bool ScalarizeLoadStore;
330 const unsigned ScalarizeMinBits;
348void ScalarizerLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
354char ScalarizerLegacyPass::ID = 0;
356 "Scalarize vector operations",
false,
false)
362 const VectorSplit &VS, ValueVector *cachePtr)
363 : BB(bb), BBI(bbi), V(v), VS(VS), CachePtr(cachePtr) {
364 IsPointer = V->getType()->isPointerTy();
366 Tmp.resize(VS.NumFragments,
nullptr);
368 assert((CachePtr->empty() || VS.NumFragments == CachePtr->size() ||
370 "Inconsistent vector sizes");
371 if (VS.NumFragments > CachePtr->size())
372 CachePtr->resize(VS.NumFragments,
nullptr);
377Value *Scatterer::operator[](
unsigned Frag) {
378 ValueVector &CV = CachePtr ? *CachePtr : Tmp;
387 CV[Frag] = Builder.CreateConstGEP1_32(
VS.SplitTy, V, Frag,
388 V->getName() +
".i" +
Twine(Frag));
392 Type *FragmentTy =
VS.getFragmentType(Frag);
394 if (
auto *VecTy = dyn_cast<FixedVectorType>(FragmentTy)) {
396 for (
unsigned J = 0; J < VecTy->getNumElements(); ++J)
397 Mask.push_back(Frag *
VS.NumPacked + J);
400 V->getName() +
".i" +
Twine(Frag));
412 unsigned J =
Idx->getZExtValue();
414 if (Frag *
VS.NumPacked == J) {
415 CV[Frag] =
Insert->getOperand(1);
419 if (
VS.NumPacked == 1 && !CV[J]) {
423 CV[J] =
Insert->getOperand(1);
426 CV[Frag] = Builder.CreateExtractElement(V, Frag *
VS.NumPacked,
427 V->getName() +
".i" +
Twine(Frag));
433bool ScalarizerLegacyPass::runOnFunction(
Function &
F) {
437 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
439 &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
441 return Impl.visit(
F);
445 return new ScalarizerLegacyPass(
Options);
448bool ScalarizerVisitor::visit(
Function &
F) {
449 assert(Gathered.empty() && Scattered.empty());
461 if (
Done &&
I->getType()->isVoidTy()) {
462 I->eraseFromParent();
473 const VectorSplit &VS) {
474 if (
Argument *VArg = dyn_cast<Argument>(V)) {
479 return Scatterer(BB, BB->
begin(), V, VS, &Scattered[{V, VS.SplitTy}]);
496 &Scattered[{
V,
VS.SplitTy}]);
507void ScalarizerVisitor::gather(
Instruction *
Op,
const ValueVector &CV,
508 const VectorSplit &VS) {
509 transferMetadataAndIRFlags(
Op, CV);
513 ValueVector &SV = Scattered[{
Op,
VS.SplitTy}];
515 for (
unsigned I = 0, E = SV.size();
I != E; ++
I) {
517 if (V ==
nullptr || SV[
I] == CV[
I])
521 if (isa<Instruction>(CV[
I]))
522 CV[
I]->takeName(Old);
524 PotentiallyDeadInstrs.emplace_back(Old);
528 Gathered.push_back(GatherList::value_type(
Op, &SV));
534 Op->replaceAllUsesWith(CV);
535 PotentiallyDeadInstrs.emplace_back(
Op);
542bool ScalarizerVisitor::canTransferMetadata(
unsigned Tag) {
543 return (Tag == LLVMContext::MD_tbaa
544 || Tag == LLVMContext::MD_fpmath
545 || Tag == LLVMContext::MD_tbaa_struct
546 || Tag == LLVMContext::MD_invariant_load
547 || Tag == LLVMContext::MD_alias_scope
548 || Tag == LLVMContext::MD_noalias
549 || Tag == LLVMContext::MD_mem_parallel_loop_access
550 || Tag == LLVMContext::MD_access_group);
555void ScalarizerVisitor::transferMetadataAndIRFlags(
Instruction *
Op,
556 const ValueVector &CV) {
558 Op->getAllMetadataOtherThanDebugLoc(MDs);
559 for (
Value *V : CV) {
561 for (
const auto &MD : MDs)
562 if (canTransferMetadata(MD.first))
563 New->setMetadata(MD.first, MD.second);
564 New->copyIRFlags(
Op);
565 if (
Op->getDebugLoc() && !
New->getDebugLoc())
566 New->setDebugLoc(
Op->getDebugLoc());
572std::optional<VectorSplit> ScalarizerVisitor::getVectorSplit(
Type *Ty) {
574 Split.VecTy = dyn_cast<FixedVectorType>(Ty);
578 unsigned NumElems =
Split.VecTy->getNumElements();
579 Type *ElemTy =
Split.VecTy->getElementType();
584 Split.NumFragments = NumElems;
585 Split.SplitTy = ElemTy;
588 if (
Split.NumPacked >= NumElems)
594 unsigned RemainderElems = NumElems %
Split.NumPacked;
595 if (RemainderElems > 1)
597 else if (RemainderElems == 1)
598 Split.RemainderTy = ElemTy;
607std::optional<VectorLayout>
608ScalarizerVisitor::getVectorLayout(
Type *Ty,
Align Alignment,
610 std::optional<VectorSplit>
VS = getVectorSplit(Ty);
617 if (!
DL.typeSizeEqualsStoreSize(
VS->SplitTy) ||
618 (
VS->RemainderTy && !
DL.typeSizeEqualsStoreSize(
VS->RemainderTy)))
620 Layout.VecAlign = Alignment;
621 Layout.SplitSize =
DL.getTypeStoreSize(
VS->SplitTy);
627template<
typename Splitter>
628bool ScalarizerVisitor::splitUnary(
Instruction &
I,
const Splitter &Split) {
629 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
633 std::optional<VectorSplit> OpVS;
634 if (
I.getOperand(0)->getType() ==
I.getType()) {
637 OpVS = getVectorSplit(
I.getOperand(0)->getType());
638 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
643 Scatterer
Op = scatter(&
I,
I.getOperand(0), *OpVS);
644 assert(
Op.size() ==
VS->NumFragments &&
"Mismatched unary operation");
646 Res.resize(
VS->NumFragments);
647 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag)
648 Res[Frag] =
Split(Builder,
Op[Frag],
I.getName() +
".i" +
Twine(Frag));
649 gather(&
I, Res, *VS);
655template<
typename Splitter>
656bool ScalarizerVisitor::splitBinary(
Instruction &
I,
const Splitter &Split) {
657 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
661 std::optional<VectorSplit> OpVS;
662 if (
I.getOperand(0)->getType() ==
I.getType()) {
665 OpVS = getVectorSplit(
I.getOperand(0)->getType());
666 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
671 Scatterer VOp0 = scatter(&
I,
I.getOperand(0), *OpVS);
672 Scatterer VOp1 = scatter(&
I,
I.getOperand(1), *OpVS);
673 assert(VOp0.size() ==
VS->NumFragments &&
"Mismatched binary operation");
674 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched binary operation");
676 Res.resize(
VS->NumFragments);
677 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag) {
678 Value *Op0 = VOp0[Frag];
679 Value *Op1 = VOp1[Frag];
680 Res[Frag] =
Split(Builder, Op0, Op1,
I.getName() +
".i" +
Twine(Frag));
682 gather(&
I, Res, *VS);
688bool ScalarizerVisitor::splitCall(
CallInst &CI) {
690 bool AreAllVectorsOfMatchingSize = isStructOfMatchingFixedVectors(CallType);
691 std::optional<VectorSplit>
VS;
692 if (AreAllVectorsOfMatchingSize)
695 VS = getVectorSplit(CallType);
711 ValueVector ScalarOperands(NumArgs);
720 if (AreAllVectorsOfMatchingSize) {
722 std::optional<VectorSplit> CurrVS =
730 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
738 for (
unsigned I = 0;
I != NumArgs; ++
I) {
740 if ([[maybe_unused]]
auto *OpVecTy =
741 dyn_cast<FixedVectorType>(OpI->
getType())) {
742 assert(OpVecTy->getNumElements() ==
VS->VecTy->getNumElements());
743 std::optional<VectorSplit> OpVS = getVectorSplit(OpI->
getType());
744 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
755 Scattered[
I] = scatter(&CI, OpI, *OpVS);
757 OverloadIdx[
I] = Tys.
size();
761 ScalarOperands[
I] = OpI;
767 ValueVector Res(
VS->NumFragments);
768 ValueVector ScalarCallOps(NumArgs);
775 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
776 bool IsRemainder =
I ==
VS->NumFragments - 1 &&
VS->RemainderTy;
777 ScalarCallOps.clear();
780 Tys[0] =
VS->RemainderTy;
782 for (
unsigned J = 0; J != NumArgs; ++J) {
784 ScalarCallOps.push_back(ScalarOperands[J]);
786 ScalarCallOps.push_back(Scattered[J][
I]);
787 if (IsRemainder && OverloadIdx[J] >= 0)
788 Tys[OverloadIdx[J]] = Scattered[J][
I]->getType();
795 Res[
I] = Builder.CreateCall(NewIntrin, ScalarCallOps,
799 gather(&CI, Res, *VS);
803bool ScalarizerVisitor::visitSelectInst(
SelectInst &SI) {
804 std::optional<VectorSplit>
VS = getVectorSplit(
SI.getType());
808 std::optional<VectorSplit> CondVS;
809 if (isa<FixedVectorType>(
SI.getCondition()->getType())) {
810 CondVS = getVectorSplit(
SI.getCondition()->getType());
811 if (!CondVS || CondVS->NumPacked !=
VS->NumPacked) {
818 Scatterer VOp1 = scatter(&SI,
SI.getOperand(1), *VS);
819 Scatterer VOp2 = scatter(&SI,
SI.getOperand(2), *VS);
820 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched select");
821 assert(VOp2.size() ==
VS->NumFragments &&
"Mismatched select");
823 Res.resize(
VS->NumFragments);
826 Scatterer VOp0 = scatter(&SI,
SI.getOperand(0), *CondVS);
827 assert(VOp0.size() == CondVS->NumFragments &&
"Mismatched select");
828 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
832 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
837 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
840 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
844 gather(&SI, Res, *VS);
848bool ScalarizerVisitor::visitICmpInst(
ICmpInst &ICI) {
849 return splitBinary(ICI, ICmpSplitter(ICI));
852bool ScalarizerVisitor::visitFCmpInst(
FCmpInst &FCI) {
853 return splitBinary(FCI, FCmpSplitter(FCI));
856bool ScalarizerVisitor::visitUnaryOperator(
UnaryOperator &UO) {
857 return splitUnary(UO, UnarySplitter(UO));
861 return splitBinary(BO, BinarySplitter(BO));
865 std::optional<VectorSplit>
VS = getVectorSplit(GEPI.
getType());
876 for (
unsigned I = 0;
I < 1 + NumIndices; ++
I) {
879 std::optional<VectorSplit> OpVS = getVectorSplit(VecTy);
880 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
884 ScatterOps[
I] = scatter(&GEPI, GEPI.
getOperand(
I), *OpVS);
891 Res.resize(
VS->NumFragments);
892 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
894 SplitOps.
resize(1 + NumIndices);
895 for (
unsigned J = 0; J < 1 + NumIndices; ++J) {
897 SplitOps[J] = ScalarOps[J];
899 SplitOps[J] = ScatterOps[J][
I];
906 NewGEPI->setIsInBounds();
908 gather(&GEPI, Res, *VS);
912bool ScalarizerVisitor::visitCastInst(
CastInst &CI) {
913 std::optional<VectorSplit> DestVS = getVectorSplit(CI.
getDestTy());
917 std::optional<VectorSplit> SrcVS = getVectorSplit(CI.
getSrcTy());
918 if (!SrcVS || SrcVS->NumPacked != DestVS->NumPacked)
922 Scatterer Op0 = scatter(&CI, CI.
getOperand(0), *SrcVS);
923 assert(Op0.size() == SrcVS->NumFragments &&
"Mismatched cast");
925 Res.resize(DestVS->NumFragments);
926 for (
unsigned I = 0;
I < DestVS->NumFragments; ++
I)
928 Builder.CreateCast(CI.
getOpcode(), Op0[
I], DestVS->getFragmentType(
I),
930 gather(&CI, Res, *DestVS);
934bool ScalarizerVisitor::visitBitCastInst(
BitCastInst &BCI) {
935 std::optional<VectorSplit> DstVS = getVectorSplit(BCI.
getDestTy());
936 std::optional<VectorSplit> SrcVS = getVectorSplit(BCI.
getSrcTy());
937 if (!DstVS || !SrcVS || DstVS->RemainderTy || SrcVS->RemainderTy)
940 const bool isPointerTy = DstVS->VecTy->getElementType()->isPointerTy();
946 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
948 Res.resize(DstVS->NumFragments);
950 unsigned DstSplitBits = DstVS->SplitTy->getPrimitiveSizeInBits();
951 unsigned SrcSplitBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
954 assert(DstVS->NumFragments == SrcVS->NumFragments);
955 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
956 Res[
I] = Builder.CreateBitCast(Op0[
I], DstVS->getFragmentType(
I),
959 }
else if (SrcSplitBits % DstSplitBits == 0) {
963 MidVS.NumPacked = DstVS->NumPacked;
964 MidVS.NumFragments = SrcSplitBits / DstSplitBits;
966 MidVS.NumPacked * MidVS.NumFragments);
967 MidVS.SplitTy = DstVS->SplitTy;
970 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
976 while ((VI = dyn_cast<Instruction>(V)) &&
977 VI->getOpcode() == Instruction::BitCast)
978 V =
VI->getOperand(0);
980 V = Builder.CreateBitCast(V, MidVS.VecTy,
V->getName() +
".cast");
982 Scatterer Mid = scatter(&BCI, V, MidVS);
983 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
984 Res[ResI++] = Mid[J];
986 }
else if (DstSplitBits % SrcSplitBits == 0) {
990 MidVS.NumFragments = DstSplitBits / SrcSplitBits;
991 MidVS.NumPacked = SrcVS->NumPacked;
993 MidVS.NumPacked * MidVS.NumFragments);
994 MidVS.SplitTy = SrcVS->SplitTy;
998 ConcatOps.
resize(MidVS.NumFragments);
999 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1000 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1001 ConcatOps[J] = Op0[SrcI++];
1002 Value *
V = concatenate(Builder, ConcatOps, MidVS,
1004 Res[
I] = Builder.CreateBitCast(V, DstVS->getFragmentType(
I),
1011 gather(&BCI, Res, *DstVS);
1016 std::optional<VectorSplit>
VS = getVectorSplit(IEI.
getType());
1021 Scatterer Op0 = scatter(&IEI, IEI.
getOperand(0), *VS);
1026 Res.resize(
VS->NumFragments);
1028 if (
auto *CI = dyn_cast<ConstantInt>(InsIdx)) {
1029 unsigned Idx = CI->getZExtValue();
1030 unsigned Fragment =
Idx /
VS->NumPacked;
1031 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1032 if (
I == Fragment) {
1034 if (Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1035 !
VS->RemainderTy->isVectorTy())
1039 Builder.CreateInsertElement(Op0[
I], NewElt,
Idx %
VS->NumPacked);
1049 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1052 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1053 Value *ShouldReplace =
1054 Builder.CreateICmpEQ(InsIdx, ConstantInt::get(InsIdx->
getType(),
I),
1057 Res[
I] = Builder.CreateSelect(ShouldReplace, NewElt, OldElt,
1062 gather(&IEI, Res, *VS);
1068 Type *OpTy =
Op->getType();
1070 if (!isStructOfMatchingFixedVectors(OpTy))
1084 std::optional<VectorSplit>
VS = getVectorSplit(VecType);
1088 std::optional<VectorSplit> CurrVS =
1096 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
1100 Scatterer Op0 = scatter(&EVI,
Op, *VS);
1105 Value *ResElem = Builder.CreateExtractValue(
1107 Res.push_back(ResElem);
1111 std::optional<VectorSplit> AVS = getVectorSplit(ActualVecType);
1112 gather(&EVI, Res, *AVS);
1122 Scatterer Op0 = scatter(&EEI, EEI.
getOperand(0), *VS);
1125 if (
auto *CI = dyn_cast<ConstantInt>(ExtIdx)) {
1126 unsigned Idx = CI->getZExtValue();
1127 unsigned Fragment =
Idx /
VS->NumPacked;
1128 Value *Res = Op0[Fragment];
1130 if (Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1131 !
VS->RemainderTy->isVectorTy())
1134 Res = Builder.CreateExtractElement(Res,
Idx %
VS->NumPacked);
1135 replaceUses(&EEI, Res);
1140 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1144 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1145 Value *ShouldExtract =
1146 Builder.CreateICmpEQ(ExtIdx, ConstantInt::get(ExtIdx->
getType(),
I),
1149 Res = Builder.CreateSelect(ShouldExtract, Elt, Res,
1152 replaceUses(&EEI, Res);
1157 std::optional<VectorSplit>
VS = getVectorSplit(SVI.
getType());
1158 std::optional<VectorSplit> VSOp =
1160 if (!VS || !VSOp ||
VS->NumPacked > 1 || VSOp->NumPacked > 1)
1163 Scatterer Op0 = scatter(&SVI, SVI.
getOperand(0), *VSOp);
1164 Scatterer Op1 = scatter(&SVI, SVI.
getOperand(1), *VSOp);
1166 Res.resize(
VS->NumFragments);
1168 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1172 else if (
unsigned(Selector) < Op0.size())
1173 Res[
I] = Op0[Selector];
1175 Res[
I] = Op1[Selector - Op0.size()];
1177 gather(&SVI, Res, *VS);
1181bool ScalarizerVisitor::visitPHINode(
PHINode &
PHI) {
1182 std::optional<VectorSplit>
VS = getVectorSplit(
PHI.getType());
1188 Res.resize(
VS->NumFragments);
1190 unsigned NumOps =
PHI.getNumOperands();
1191 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1192 Res[
I] = Builder.CreatePHI(
VS->getFragmentType(
I), NumOps,
1196 for (
unsigned I = 0;
I < NumOps; ++
I) {
1197 Scatterer
Op = scatter(&
PHI,
PHI.getIncomingValue(
I), *VS);
1199 for (
unsigned J = 0; J <
VS->NumFragments; ++J)
1200 cast<PHINode>(Res[J])->addIncoming(
Op[J], IncomingBlock);
1202 gather(&
PHI, Res, *VS);
1206bool ScalarizerVisitor::visitLoadInst(
LoadInst &LI) {
1207 if (!ScalarizeLoadStore)
1212 std::optional<VectorLayout> Layout = getVectorLayout(
1220 Res.resize(Layout->VS.NumFragments);
1222 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1223 Res[
I] = Builder.CreateAlignedLoad(Layout->VS.getFragmentType(
I),
Ptr[
I],
1224 Align(Layout->getFragmentAlign(
I)),
1227 gather(&LI, Res, Layout->VS);
1231bool ScalarizerVisitor::visitStoreInst(
StoreInst &SI) {
1232 if (!ScalarizeLoadStore)
1237 Value *FullValue =
SI.getValueOperand();
1238 std::optional<VectorLayout> Layout = getVectorLayout(
1239 FullValue->
getType(),
SI.getAlign(),
SI.getDataLayout());
1244 Scatterer VPtr = scatter(&SI,
SI.getPointerOperand(), Layout->VS);
1245 Scatterer VVal = scatter(&SI, FullValue, Layout->VS);
1248 Stores.resize(Layout->VS.NumFragments);
1249 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1253 Builder.CreateAlignedStore(Val,
Ptr, Layout->getFragmentAlign(
I));
1255 transferMetadataAndIRFlags(&SI, Stores);
1259bool ScalarizerVisitor::visitCallInst(
CallInst &CI) {
1260 return splitCall(CI);
1263bool ScalarizerVisitor::visitFreezeInst(
FreezeInst &FI) {
1271bool ScalarizerVisitor::finish() {
1274 if (Gathered.empty() && Scattered.empty() && !Scalarized)
1276 for (
const auto &GMI : Gathered) {
1278 ValueVector &CV = *GMI.second;
1279 if (!
Op->use_empty()) {
1283 if (
auto *Ty = dyn_cast<FixedVectorType>(
Op->getType())) {
1286 if (isa<PHINode>(
Op))
1289 VectorSplit
VS = *getVectorSplit(Ty);
1290 assert(
VS.NumFragments == CV.size());
1292 Res = concatenate(Builder, CV, VS,
Op->getName());
1295 }
else if (
auto *Ty = dyn_cast<StructType>(
Op->getType())) {
1298 if (isa<PHINode>(
Op))
1302 unsigned NumOfStructElements = Ty->getNumElements();
1304 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1305 for (
auto *CVelem : CV) {
1307 CVelem,
I,
Op->getName() +
".elem" +
Twine(
I));
1308 ElemCV[
I].push_back(Elem);
1312 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1313 Type *ElemTy = Ty->getElementType(
I);
1314 assert(isa<FixedVectorType>(ElemTy) &&
1315 "Only Structs of all FixedVectorType supported");
1316 VectorSplit
VS = *getVectorSplit(ElemTy);
1317 assert(
VS.NumFragments == CV.size());
1319 Value *ConcatenatedVector =
1320 concatenate(Builder, ElemCV[
I], VS,
Op->getName());
1322 Op->getName() +
".insert");
1325 assert(CV.size() == 1 &&
Op->getType() == CV[0]->getType());
1330 Op->replaceAllUsesWith(Res);
1332 PotentiallyDeadInstrs.emplace_back(
Op);
1346 ScalarizerVisitor Impl(DT,
TTI, Options);
1347 bool Changed = Impl.visit(
F);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Module.h This file contains the declarations for the Module class.
MachineInstr unsigned OpIdx
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
Scalarize vector operations
This pass converts vector operations into scalar operations (or, optionally, operations on smaller ve...
This file defines the SmallVector class.
A container for analyses that lazily runs them and caches their results.
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.
This class represents an incoming formal argument to a Function.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool empty() const
empty - Check if the array is empty.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
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.
InstListType::iterator iterator
Instruction iterators...
This class represents a no-op cast from one type to another.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
unsigned arg_size() const
This class represents a function call, abstracting a target machine's calling convention.
This is the base class for all instructions that perform data casts.
Type * getSrcTy() const
Return the source type, as a convenience.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
Type * getDestTy() const
Return the destination type, as a convenience.
This is the shared class of boolean and integer constants.
This class represents an Operation in the Expression.
A parsed version of the target data layout string in and methods for querying it.
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
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)
This class represents a freeze function that returns random concrete value if an operand is either a ...
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
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 * CreateFCmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Value * CreateFreeze(Value *V, const Twine &Name="")
Value * CreateUnOp(Instruction::UnaryOps Opc, Value *V, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateShuffleVector(Value *V1, Value *V2, Value *Mask, const Twine &Name="")
Value * CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Value * CreateICmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name="")
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
This instruction inserts a single (scalar) element into a VectorType value.
VectorType * getType() const
Overload to return most specific vector type.
Base class for instruction visitors.
RetTy visitFreezeInst(FreezeInst &I)
RetTy visitFCmpInst(FCmpInst &I)
RetTy visitExtractElementInst(ExtractElementInst &I)
RetTy visitShuffleVectorInst(ShuffleVectorInst &I)
RetTy visitBitCastInst(BitCastInst &I)
void visit(Iterator Start, Iterator End)
RetTy visitPHINode(PHINode &I)
RetTy visitExtractValueInst(ExtractValueInst &I)
RetTy visitUnaryOperator(UnaryOperator &I)
RetTy visitStoreInst(StoreInst &I)
RetTy visitInsertElementInst(InsertElementInst &I)
RetTy visitBinaryOperator(BinaryOperator &I)
RetTy visitICmpInst(ICmpInst &I)
RetTy visitCallInst(CallInst &I)
RetTy visitCastInst(CastInst &I)
RetTy visitSelectInst(SelectInst &I)
RetTy visitGetElementPtrInst(GetElementPtrInst &I)
void visitInstruction(Instruction &I)
RetTy visitLoadInst(LoadInst &I)
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
An instruction for reading from memory.
Value * getPointerOperand()
Align getAlign() const
Return the alignment of the access that is being performed.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
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.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
This class represents the LLVM 'select' instruction.
This instruction constructs a fixed permutation of two input vectors.
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 push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Analysis pass providing the TargetTransformInfo.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
unsigned getNumContainedTypes() const
Return the number of types in the derived type.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
const ParentTy * getParent() const
self_iterator getIterator()
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool isTriviallyScalarizable(Intrinsic::ID ID, const TargetTransformInfo *TTI)
Identify if the intrinsic is trivially scalarizable.
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.
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)
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
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...
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.
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...
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
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.