51#define DEBUG_TYPE "scalarizer"
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; }
133 FCmpSplitter(
FCmpInst &fci) : FCI(fci) {}
136 const Twine &Name)
const {
137 return Builder.CreateFCmp(FCI.getPredicate(), Op0, Op1, Name);
146 ICmpSplitter(
ICmpInst &ici) : ICI(ici) {}
149 const Twine &Name)
const {
150 return Builder.CreateICmp(ICI.getPredicate(), Op0, Op1, Name);
158struct UnarySplitter {
162 return Builder.CreateUnOp(UO.getOpcode(),
Op, Name);
170struct BinarySplitter {
174 const Twine &Name)
const {
175 return Builder.CreateBinOp(BO.getOpcode(), Op0, Op1, Name);
183 VectorLayout() =
default;
186 Align getFragmentAlign(
unsigned Frag) {
204 unsigned StructSize = Ty->getNumContainedTypes();
211 for (
unsigned I = 1;
I < StructSize;
I++) {
222 const VectorSplit &VS,
Twine Name) {
223 unsigned NumElements = VS.VecTy->getNumElements();
227 if (VS.NumPacked > 1) {
230 ExtendMask.
resize(NumElements, -1);
231 for (
unsigned I = 0;
I < VS.NumPacked; ++
I)
234 InsertMask.
resize(NumElements);
235 for (
unsigned I = 0;
I < NumElements; ++
I)
240 for (
unsigned I = 0;
I < VS.NumFragments; ++
I) {
241 Value *Fragment = Fragments[
I];
243 unsigned NumPacked = VS.NumPacked;
244 if (
I == VS.NumFragments - 1 && VS.RemainderTy) {
246 NumPacked = RemVecTy->getNumElements();
251 if (NumPacked == 1) {
252 Res = Builder.CreateInsertElement(Res, Fragment,
I * VS.NumPacked,
253 Name +
".upto" +
Twine(
I));
255 if (NumPacked < VS.NumPacked) {
258 ExtendMask.
resize(NumElements, -1);
261 Fragment = Builder.CreateShuffleVector(
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;
280class ScalarizerVisitor :
public InstVisitor<ScalarizerVisitor, bool> {
282 ScalarizerVisitor(DominatorTree *DT,
const TargetTransformInfo *TTI,
285 ScalarizeVariableInsertExtract(
Options.ScalarizeVariableInsertExtract),
286 ScalarizeLoadStore(
Options.ScalarizeLoadStore),
287 ScalarizeMinBits(
Options.ScalarizeMinBits) {}
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);
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);
323 template<
typename T>
bool splitUnary(Instruction &,
const T &);
324 template<
typename T>
bool splitBinary(Instruction &,
const T &);
326 bool splitCall(CallInst &CI);
335 const TargetTransformInfo *TTI;
337 const bool ScalarizeVariableInsertExtract;
338 const bool ScalarizeLoadStore;
339 const unsigned ScalarizeMinBits;
345 ScalarizerPassOptions Options;
346 ScalarizerLegacyPass() : FunctionPass(ID), Options() {}
347 ScalarizerLegacyPass(
const ScalarizerPassOptions &Options);
349 void getAnalysisUsage(AnalysisUsage &AU)
const override;
357void ScalarizerLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
363char ScalarizerLegacyPass::ID = 0;
365 "Scalarize vector operations",
false,
false)
373 : BB(bb), BBI(bbi), V(v), VS(VS), CachePtr(cachePtr) {
376 Tmp.resize(VS.NumFragments,
nullptr);
378 assert((CachePtr->empty() || VS.NumFragments == CachePtr->size() ||
380 "Inconsistent vector sizes");
381 if (VS.NumFragments > CachePtr->size())
382 CachePtr->resize(VS.NumFragments,
nullptr);
387Value *Scatterer::operator[](
unsigned Frag) {
397 CV[Frag] = Builder.CreateConstGEP1_32(VS.SplitTy, V, Frag,
398 V->
getName() +
".i" + Twine(Frag));
402 Type *FragmentTy = VS.getFragmentType(Frag);
405 SmallVector<int>
Mask;
406 for (
unsigned J = 0; J < VecTy->getNumElements(); ++J)
407 Mask.push_back(Frag * VS.NumPacked + J);
410 V->
getName() +
".i" + Twine(Frag));
423 V =
Insert->getOperand(0);
424 if (Frag * VS.NumPacked == J) {
425 CV[Frag] =
Insert->getOperand(1);
429 if (VS.NumPacked == 1 && !CV[J]) {
433 CV[J] =
Insert->getOperand(1);
436 CV[Frag] = Builder.CreateExtractElement(V, Frag * VS.NumPacked,
437 V->
getName() +
".i" + Twine(Frag));
443bool ScalarizerLegacyPass::runOnFunction(
Function &
F) {
447 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
448 const TargetTransformInfo *
TTI =
449 &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
451 return Impl.visit(
F);
455 return new ScalarizerLegacyPass(
Options);
458bool ScalarizerVisitor::visit(
Function &
F) {
471 if (
Done &&
I->getType()->isVoidTy()) {
472 I->eraseFromParent();
482Scatterer ScalarizerVisitor::scatter(Instruction *Point,
Value *V,
483 const VectorSplit &VS) {
489 return Scatterer(BB, BB->
begin(), V, VS, &Scattered[{V, VS.SplitTy}]);
506 &Scattered[{
V,
VS.SplitTy}]);
517void ScalarizerVisitor::gather(Instruction *
Op,
const ValueVector &CV,
518 const VectorSplit &VS) {
519 transferMetadataAndIRFlags(
Op, CV);
525 for (
unsigned I = 0,
E = SV.
size();
I !=
E; ++
I) {
527 if (V ==
nullptr || SV[
I] == CV[
I])
532 CV[
I]->takeName(Old);
534 PotentiallyDeadInstrs.emplace_back(Old);
542void ScalarizerVisitor::replaceUses(Instruction *
Op,
Value *CV) {
544 Op->replaceAllUsesWith(CV);
545 PotentiallyDeadInstrs.emplace_back(
Op);
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);
565void ScalarizerVisitor::transferMetadataAndIRFlags(Instruction *
Op,
568 Op->getAllMetadataOtherThanDebugLoc(MDs);
569 for (
Value *V : CV) {
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());
582std::optional<VectorSplit> ScalarizerVisitor::getVectorSplit(
Type *Ty) {
588 unsigned NumElems =
Split.VecTy->getNumElements();
589 Type *ElemTy =
Split.VecTy->getElementType();
594 Split.NumFragments = NumElems;
595 Split.SplitTy = ElemTy;
598 if (
Split.NumPacked >= NumElems)
604 unsigned RemainderElems = NumElems %
Split.NumPacked;
605 if (RemainderElems > 1)
607 else if (RemainderElems == 1)
608 Split.RemainderTy = ElemTy;
617std::optional<VectorLayout>
618ScalarizerVisitor::getVectorLayout(
Type *Ty, Align Alignment,
619 const DataLayout &
DL) {
620 std::optional<VectorSplit>
VS = getVectorSplit(Ty);
627 if (!
DL.typeSizeEqualsStoreSize(
VS->SplitTy) ||
628 (
VS->RemainderTy && !
DL.typeSizeEqualsStoreSize(
VS->RemainderTy)))
631 Layout.SplitSize =
DL.getTypeStoreSize(
VS->SplitTy);
637template<
typename Splitter>
638bool ScalarizerVisitor::splitUnary(Instruction &
I,
const Splitter &Split) {
639 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
643 std::optional<VectorSplit> OpVS;
644 if (
I.getOperand(0)->getType() ==
I.getType()) {
647 OpVS = getVectorSplit(
I.getOperand(0)->getType());
648 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
653 Scatterer
Op = scatter(&
I,
I.getOperand(0), *OpVS);
654 assert(
Op.size() ==
VS->NumFragments &&
"Mismatched unary operation");
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);
665template<
typename Splitter>
666bool ScalarizerVisitor::splitBinary(Instruction &
I,
const Splitter &Split) {
667 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
671 std::optional<VectorSplit> OpVS;
672 if (
I.getOperand(0)->getType() ==
I.getType()) {
675 OpVS = getVectorSplit(
I.getOperand(0)->getType());
676 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
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");
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));
692 gather(&
I, Res, *VS);
698bool ScalarizerVisitor::splitCall(CallInst &CI) {
701 std::optional<VectorSplit>
VS;
702 if (AreAllVectorsOfMatchingSize)
705 VS = getVectorSplit(CallType);
723 SmallVector<int> OverloadIdx(NumArgs, -1);
730 if (AreAllVectorsOfMatchingSize) {
732 std::optional<VectorSplit> CurrVS =
740 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
748 for (
unsigned I = 0;
I != NumArgs; ++
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) {
765 Scattered[
I] = scatter(&CI, OpI, *OpVS);
767 OverloadIdx[
I] = Tys.
size();
771 ScalarOperands[
I] = OpI;
785 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
786 bool IsRemainder =
I ==
VS->NumFragments - 1 &&
VS->RemainderTy;
787 ScalarCallOps.clear();
790 Tys[0] =
VS->RemainderTy;
792 for (
unsigned J = 0; J != NumArgs; ++J) {
794 ScalarCallOps.push_back(ScalarOperands[J]);
796 ScalarCallOps.push_back(Scattered[J][
I]);
797 if (IsRemainder && OverloadIdx[J] >= 0)
798 Tys[OverloadIdx[J]] = Scattered[J][
I]->getType();
805 Res[
I] = Builder.CreateCall(NewIntrin, ScalarCallOps,
809 gather(&CI, Res, *VS);
813bool ScalarizerVisitor::visitSelectInst(SelectInst &SI) {
814 std::optional<VectorSplit>
VS = getVectorSplit(
SI.getType());
818 std::optional<VectorSplit> CondVS;
820 CondVS = getVectorSplit(
SI.getCondition()->getType());
821 if (!CondVS || CondVS->NumPacked !=
VS->NumPacked) {
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");
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) {
842 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
843 SI.getName() +
".i" + Twine(
I));
847 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
850 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
851 SI.getName() +
".i" + Twine(
I));
854 gather(&SI, Res, *VS);
858bool ScalarizerVisitor::visitICmpInst(ICmpInst &ICI) {
859 return splitBinary(ICI, ICmpSplitter(ICI));
862bool ScalarizerVisitor::visitFCmpInst(FCmpInst &FCI) {
863 return splitBinary(FCI, FCmpSplitter(FCI));
866bool ScalarizerVisitor::visitUnaryOperator(UnaryOperator &UO) {
867 return splitUnary(UO, UnarySplitter(UO));
870bool ScalarizerVisitor::visitBinaryOperator(BinaryOperator &BO) {
871 return splitBinary(BO, BinarySplitter(BO));
874bool ScalarizerVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) {
875 std::optional<VectorSplit>
VS = getVectorSplit(GEPI.
getType());
883 SmallVector<Value *, 8> ScalarOps{1 + NumIndices};
886 for (
unsigned I = 0;
I < 1 + NumIndices; ++
I) {
889 std::optional<VectorSplit> OpVS = getVectorSplit(VecTy);
890 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
894 ScatterOps[
I] = scatter(&GEPI, GEPI.
getOperand(
I), *OpVS);
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) {
907 SplitOps[J] = ScalarOps[J];
909 SplitOps[J] = ScatterOps[J][
I];
916 NewGEPI->setIsInBounds();
918 gather(&GEPI, Res, *VS);
922bool ScalarizerVisitor::visitCastInst(CastInst &CI) {
923 std::optional<VectorSplit> DestVS = getVectorSplit(CI.
getDestTy());
927 std::optional<VectorSplit> SrcVS = getVectorSplit(CI.
getSrcTy());
928 if (!SrcVS || SrcVS->NumPacked != DestVS->NumPacked)
932 Scatterer Op0 = scatter(&CI, CI.
getOperand(0), *SrcVS);
933 assert(Op0.size() == SrcVS->NumFragments &&
"Mismatched cast");
935 Res.
resize(DestVS->NumFragments);
936 for (
unsigned I = 0;
I < DestVS->NumFragments; ++
I)
938 Builder.CreateCast(CI.
getOpcode(), Op0[
I], DestVS->getFragmentType(
I),
940 gather(&CI, Res, *DestVS);
944bool ScalarizerVisitor::visitBitCastInst(BitCastInst &BCI) {
945 std::optional<VectorSplit> DstVS = getVectorSplit(BCI.
getDestTy());
946 std::optional<VectorSplit> SrcVS = getVectorSplit(BCI.
getSrcTy());
947 if (!DstVS || !SrcVS || DstVS->RemainderTy || SrcVS->RemainderTy)
950 const bool isPointerTy = DstVS->VecTy->getElementType()->isPointerTy();
956 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
958 Res.
resize(DstVS->NumFragments);
960 unsigned DstSplitBits = DstVS->SplitTy->getPrimitiveSizeInBits();
961 unsigned SrcSplitBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
964 assert(DstVS->NumFragments == SrcVS->NumFragments);
965 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
966 Res[
I] = Builder.CreateBitCast(Op0[
I], DstVS->getFragmentType(
I),
969 }
else if (SrcSplitBits % DstSplitBits == 0) {
973 MidVS.NumPacked = DstVS->NumPacked;
974 MidVS.NumFragments = SrcSplitBits / DstSplitBits;
976 MidVS.NumPacked * MidVS.NumFragments);
977 MidVS.SplitTy = DstVS->SplitTy;
980 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
987 VI->getOpcode() == Instruction::BitCast)
988 V =
VI->getOperand(0);
990 V = Builder.CreateBitCast(V, MidVS.VecTy,
V->getName() +
".cast");
992 Scatterer Mid = scatter(&BCI, V, MidVS);
993 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
994 Res[ResI++] = Mid[J];
996 }
else if (DstSplitBits % SrcSplitBits == 0) {
1000 MidVS.NumFragments = DstSplitBits / SrcSplitBits;
1001 MidVS.NumPacked = SrcVS->NumPacked;
1003 MidVS.NumPacked * MidVS.NumFragments);
1004 MidVS.SplitTy = SrcVS->SplitTy;
1007 SmallVector<Value *, 8> ConcatOps;
1008 ConcatOps.
resize(MidVS.NumFragments);
1009 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1010 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1011 ConcatOps[J] = Op0[SrcI++];
1014 Res[
I] = Builder.CreateBitCast(V, DstVS->getFragmentType(
I),
1021 gather(&BCI, Res, *DstVS);
1025bool ScalarizerVisitor::visitInsertElementInst(InsertElementInst &IEI) {
1026 std::optional<VectorSplit>
VS = getVectorSplit(IEI.
getType());
1031 Scatterer Op0 = scatter(&IEI, IEI.
getOperand(0), *VS);
1039 unsigned Idx = CI->getZExtValue();
1040 unsigned Fragment = Idx /
VS->NumPacked;
1041 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1042 if (
I == Fragment) {
1044 if (Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1045 !
VS->RemainderTy->isVectorTy())
1049 Builder.CreateInsertElement(Op0[
I], NewElt, Idx %
VS->NumPacked);
1059 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1062 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1063 Value *ShouldReplace =
1064 Builder.CreateICmpEQ(InsIdx, ConstantInt::get(InsIdx->
getType(),
I),
1065 InsIdx->
getName() +
".is." + Twine(
I));
1067 Res[
I] = Builder.CreateSelect(ShouldReplace, NewElt, OldElt,
1072 gather(&IEI, Res, *VS);
1076bool ScalarizerVisitor::visitExtractValueInst(ExtractValueInst &EVI) {
1078 Type *OpTy =
Op->getType();
1094 std::optional<VectorSplit>
VS = getVectorSplit(VecType);
1098 std::optional<VectorSplit> CurrVS =
1106 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
1110 Scatterer Op0 = scatter(&EVI,
Op, *VS);
1114 for (
unsigned OpIdx = 0; OpIdx < Op0.size(); ++OpIdx) {
1115 Value *ResElem = Builder.CreateExtractValue(
1116 Op0[OpIdx], Index, EVI.
getName() +
".elem" + Twine(Index));
1121 std::optional<VectorSplit> AVS = getVectorSplit(ActualVecType);
1122 gather(&EVI, Res, *AVS);
1126bool ScalarizerVisitor::visitExtractElementInst(ExtractElementInst &EEI) {
1132 Scatterer Op0 = scatter(&EEI, EEI.
getOperand(0), *VS);
1136 unsigned Idx = CI->getZExtValue();
1137 if (Idx >=
VS->VecTy->getNumElements())
1139 unsigned Fragment = Idx /
VS->NumPacked;
1140 Value *Res = Op0[Fragment];
1142 if (Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1143 !
VS->RemainderTy->isVectorTy())
1146 Res = Builder.CreateExtractElement(Res, Idx %
VS->NumPacked);
1147 replaceUses(&EEI, Res);
1152 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1156 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1157 Value *ShouldExtract =
1158 Builder.CreateICmpEQ(ExtIdx, ConstantInt::get(ExtIdx->
getType(),
I),
1159 ExtIdx->
getName() +
".is." + Twine(
I));
1161 Res = Builder.CreateSelect(ShouldExtract, Elt, Res,
1162 EEI.
getName() +
".upto" + Twine(
I));
1164 replaceUses(&EEI, Res);
1168bool ScalarizerVisitor::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
1169 std::optional<VectorSplit>
VS = getVectorSplit(SVI.
getType());
1170 std::optional<VectorSplit> VSOp =
1172 if (!VS || !VSOp ||
VS->NumPacked > 1 || VSOp->NumPacked > 1)
1175 Scatterer Op0 = scatter(&SVI, SVI.
getOperand(0), *VSOp);
1176 Scatterer Op1 = scatter(&SVI, SVI.
getOperand(1), *VSOp);
1180 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1184 else if (
unsigned(Selector) < Op0.size())
1185 Res[
I] = Op0[Selector];
1187 Res[
I] = Op1[Selector - Op0.size()];
1189 gather(&SVI, Res, *VS);
1193bool ScalarizerVisitor::visitPHINode(PHINode &
PHI) {
1194 std::optional<VectorSplit>
VS = getVectorSplit(
PHI.getType());
1203 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1204 Res[
I] = Builder.CreatePHI(
VS->getFragmentType(
I),
NumOps,
1205 PHI.getName() +
".i" + Twine(
I));
1209 Scatterer
Op = scatter(&
PHI,
PHI.getIncomingValue(
I), *VS);
1211 for (
unsigned J = 0; J <
VS->NumFragments; ++J)
1214 gather(&
PHI, Res, *VS);
1218bool ScalarizerVisitor::visitLoadInst(LoadInst &LI) {
1219 if (!ScalarizeLoadStore)
1224 std::optional<VectorLayout> Layout = getVectorLayout(
1232 Res.
resize(Layout->VS.NumFragments);
1234 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1235 Res[
I] = Builder.CreateAlignedLoad(Layout->VS.getFragmentType(
I), Ptr[
I],
1236 Align(Layout->getFragmentAlign(
I)),
1239 gather(&LI, Res, Layout->VS);
1243bool ScalarizerVisitor::visitStoreInst(StoreInst &SI) {
1244 if (!ScalarizeLoadStore)
1249 Value *FullValue =
SI.getValueOperand();
1250 std::optional<VectorLayout> Layout = getVectorLayout(
1251 FullValue->
getType(),
SI.getAlign(),
SI.getDataLayout());
1256 Scatterer VPtr = scatter(&SI,
SI.getPointerOperand(), Layout->VS);
1257 Scatterer VVal = scatter(&SI, FullValue, Layout->VS);
1260 Stores.
resize(Layout->VS.NumFragments);
1261 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1265 Builder.CreateAlignedStore(Val, Ptr, Layout->getFragmentAlign(
I));
1267 transferMetadataAndIRFlags(&SI, Stores);
1271bool ScalarizerVisitor::visitCallInst(CallInst &CI) {
1272 return splitCall(CI);
1275bool ScalarizerVisitor::visitFreezeInst(FreezeInst &FI) {
1283bool ScalarizerVisitor::finish() {
1286 if (Gathered.
empty() && Scattered.empty() && !Scalarized)
1288 for (
const auto &GMI : Gathered) {
1291 if (!
Op->use_empty()) {
1301 VectorSplit
VS = *getVectorSplit(Ty);
1314 unsigned NumOfStructElements = Ty->getNumElements();
1316 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1317 for (
auto *CVelem : CV) {
1319 CVelem,
I,
Op->getName() +
".elem" + Twine(
I));
1320 ElemCV[
I].push_back(Elem);
1324 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1325 Type *ElemTy = Ty->getElementType(
I);
1327 "Only Structs of all FixedVectorType supported");
1328 VectorSplit
VS = *getVectorSplit(ElemTy);
1329 assert(
VS.NumFragments == CV.size());
1331 Value *ConcatenatedVector =
1334 Op->getName() +
".insert");
1337 assert(CV.size() == 1 &&
Op->getType() == CV[0]->getType());
1342 Op->replaceAllUsesWith(Res);
1344 PotentiallyDeadInstrs.emplace_back(
Op);
1358 ScalarizerVisitor Impl(DT,
TTI, Options);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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
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.
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.
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),...
bool empty() const
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...
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.
Instruction::CastOps getOpcode() const
Return the opcode of this CastInst.
Type * getDestTy() const
Return the destination type, as a convenience.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
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)
FunctionPass class - This class is used to implement most global optimizations.
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="")
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Value * CreateFreeze(Value *V, const Twine &Name="")
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
VectorType * getType() const
Overload to return most specific vector type.
Base class for instruction visitors.
void visit(Iterator Start, Iterator End)
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
Value * getPointerOperand()
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.
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)
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 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.
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 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.
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.
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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)
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...
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).
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...
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...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
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.