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());
949 DstVS->NumPacked == 1 && DstVS->SplitTy->isIntegerTy()) {
951 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
953 unsigned FragmentBits = DstVS->SplitTy->getPrimitiveSizeInBits();
955 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
956 unsigned FragmentIndex = IsBigEndian ? DstVS->NumFragments -
I - 1 :
I;
959 Fragment = Builder.CreateLShr(Fragment, FragmentIndex * FragmentBits);
960 Res[
I] = Builder.CreateTruncOrBitCast(Fragment, DstVS->getFragmentType(
I),
963 gather(&BCI, Res, *DstVS);
968 !SrcVS->RemainderTy && SrcVS->NumPacked == 1 &&
969 SrcVS->SplitTy->isIntegerTy()) {
971 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
972 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
974 unsigned FragmentBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
976 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
977 unsigned FragmentIndex = IsBigEndian ? SrcVS->NumFragments -
I - 1 :
I;
980 Fragment = Builder.CreateShl(Fragment, FragmentIndex * FragmentBits);
981 Result =
Result ? Builder.CreateOr(Result, Fragment) : Fragment;
983 replaceUses(&BCI, Result);
987 if (!DstVS || !SrcVS || DstVS->RemainderTy || SrcVS->RemainderTy)
990 const bool isPointerTy = DstVS->VecTy->getElementType()->isPointerTy();
996 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
998 Res.
resize(DstVS->NumFragments);
1000 unsigned DstSplitBits = DstVS->SplitTy->getPrimitiveSizeInBits();
1001 unsigned SrcSplitBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
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),
1009 }
else if (SrcSplitBits % DstSplitBits == 0) {
1013 MidVS.NumPacked = DstVS->NumPacked;
1014 MidVS.NumFragments = SrcSplitBits / DstSplitBits;
1016 MidVS.NumPacked * MidVS.NumFragments);
1017 MidVS.SplitTy = DstVS->SplitTy;
1020 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
1027 VI->getOpcode() == Instruction::BitCast)
1028 V =
VI->getOperand(0);
1030 V = Builder.CreateBitCast(V, MidVS.VecTy,
V->getName() +
".cast");
1032 Scatterer Mid = scatter(&BCI, V, MidVS);
1033 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1034 Res[ResI++] = Mid[J];
1036 }
else if (DstSplitBits % SrcSplitBits == 0) {
1040 MidVS.NumFragments = DstSplitBits / SrcSplitBits;
1041 MidVS.NumPacked = SrcVS->NumPacked;
1043 MidVS.NumPacked * MidVS.NumFragments);
1044 MidVS.SplitTy = SrcVS->SplitTy;
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++];
1054 Res[
I] = Builder.CreateBitCast(V, DstVS->getFragmentType(
I),
1061 gather(&BCI, Res, *DstVS);
1065bool ScalarizerVisitor::visitInsertElementInst(InsertElementInst &IEI) {
1066 std::optional<VectorSplit>
VS = getVectorSplit(IEI.
getType());
1071 Scatterer Op0 = scatter(&IEI, IEI.
getOperand(0), *VS);
1079 unsigned Idx = CI->getZExtValue();
1080 unsigned Fragment = Idx /
VS->NumPacked;
1081 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1082 if (
I == Fragment) {
1084 if (Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1085 !
VS->RemainderTy->isVectorTy())
1089 Builder.CreateInsertElement(Op0[
I], NewElt, Idx %
VS->NumPacked);
1099 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
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));
1107 Res[
I] = Builder.CreateSelect(ShouldReplace, NewElt, OldElt,
1112 gather(&IEI, Res, *VS);
1116bool ScalarizerVisitor::visitExtractValueInst(ExtractValueInst &EVI) {
1118 Type *OpTy =
Op->getType();
1134 std::optional<VectorSplit>
VS = getVectorSplit(VecType);
1138 std::optional<VectorSplit> CurrVS =
1146 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
1150 Scatterer Op0 = scatter(&EVI,
Op, *VS);
1154 for (
unsigned OpIdx = 0; OpIdx < Op0.size(); ++OpIdx) {
1155 Value *ResElem = Builder.CreateExtractValue(
1156 Op0[OpIdx], Index, EVI.
getName() +
".elem" + Twine(Index));
1161 std::optional<VectorSplit> AVS = getVectorSplit(ActualVecType);
1162 gather(&EVI, Res, *AVS);
1166bool ScalarizerVisitor::visitExtractElementInst(ExtractElementInst &EEI) {
1172 Scatterer Op0 = scatter(&EEI, EEI.
getOperand(0), *VS);
1176 unsigned Idx = CI->getZExtValue();
1177 if (Idx >=
VS->VecTy->getNumElements())
1179 unsigned Fragment = Idx /
VS->NumPacked;
1180 Value *Res = Op0[Fragment];
1182 if (Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1183 !
VS->RemainderTy->isVectorTy())
1186 Res = Builder.CreateExtractElement(Res, Idx %
VS->NumPacked);
1187 replaceUses(&EEI, Res);
1192 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
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));
1201 Res = Builder.CreateSelect(ShouldExtract, Elt, Res,
1202 EEI.
getName() +
".upto" + Twine(
I));
1204 replaceUses(&EEI, Res);
1208bool ScalarizerVisitor::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
1209 std::optional<VectorSplit>
VS = getVectorSplit(SVI.
getType());
1210 std::optional<VectorSplit> VSOp =
1212 if (!VS || !VSOp ||
VS->NumPacked > 1 || VSOp->NumPacked > 1)
1215 Scatterer Op0 = scatter(&SVI, SVI.
getOperand(0), *VSOp);
1216 Scatterer Op1 = scatter(&SVI, SVI.
getOperand(1), *VSOp);
1220 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1224 else if (
unsigned(Selector) < Op0.size())
1225 Res[
I] = Op0[Selector];
1227 Res[
I] = Op1[Selector - Op0.size()];
1229 gather(&SVI, Res, *VS);
1233bool ScalarizerVisitor::visitPHINode(PHINode &
PHI) {
1234 std::optional<VectorSplit>
VS = getVectorSplit(
PHI.getType());
1243 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1244 Res[
I] = Builder.CreatePHI(
VS->getFragmentType(
I),
NumOps,
1245 PHI.getName() +
".i" + Twine(
I));
1249 Scatterer
Op = scatter(&
PHI,
PHI.getIncomingValue(
I), *VS);
1251 for (
unsigned J = 0; J <
VS->NumFragments; ++J)
1254 gather(&
PHI, Res, *VS);
1258bool ScalarizerVisitor::visitLoadInst(LoadInst &LI) {
1259 if (!ScalarizeLoadStore)
1264 std::optional<VectorLayout> Layout = getVectorLayout(
1272 Res.
resize(Layout->VS.NumFragments);
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)),
1279 gather(&LI, Res, Layout->VS);
1283bool ScalarizerVisitor::visitStoreInst(StoreInst &SI) {
1284 if (!ScalarizeLoadStore)
1289 Value *FullValue =
SI.getValueOperand();
1290 std::optional<VectorLayout> Layout = getVectorLayout(
1291 FullValue->
getType(),
SI.getAlign(),
SI.getDataLayout());
1296 Scatterer VPtr = scatter(&SI,
SI.getPointerOperand(), Layout->VS);
1297 Scatterer VVal = scatter(&SI, FullValue, Layout->VS);
1300 Stores.
resize(Layout->VS.NumFragments);
1301 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1305 Builder.CreateAlignedStore(Val, Ptr, Layout->getFragmentAlign(
I));
1307 transferMetadataAndIRFlags(&SI, Stores);
1311bool ScalarizerVisitor::visitCallInst(CallInst &CI) {
1312 return splitCall(CI);
1315bool ScalarizerVisitor::visitFreezeInst(FreezeInst &FI) {
1323bool ScalarizerVisitor::finish() {
1326 if (Gathered.
empty() && Scattered.empty() && !Scalarized)
1328 for (
const auto &GMI : Gathered) {
1331 if (!
Op->use_empty()) {
1341 VectorSplit
VS = *getVectorSplit(Ty);
1354 unsigned NumOfStructElements = Ty->getNumElements();
1356 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1357 for (
auto *CVelem : CV) {
1359 CVelem,
I,
Op->getName() +
".elem" + Twine(
I));
1360 ElemCV[
I].push_back(Elem);
1364 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1365 Type *ElemTy = Ty->getElementType(
I);
1367 "Only Structs of all FixedVectorType supported");
1368 VectorSplit
VS = *getVectorSplit(ElemTy);
1369 assert(
VS.NumFragments == CV.size());
1371 Value *ConcatenatedVector =
1374 Op->getName() +
".insert");
1377 assert(CV.size() == 1 &&
Op->getType() == CV[0]->getType());
1382 Op->replaceAllUsesWith(Res);
1384 PotentiallyDeadInstrs.emplace_back(
Op);
1398 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)
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()
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.
bool isIntegerTy() const
True if this is an instance of IntegerType.
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.