51#define DEBUG_TYPE "scalarizer"
82 unsigned NumPacked = 0;
86 unsigned NumFragments = 0;
89 Type *SplitTy =
nullptr;
93 Type *RemainderTy =
nullptr;
95 Type *getFragmentType(
unsigned I)
const {
96 return RemainderTy &&
I == NumFragments - 1 ? RemainderTy : SplitTy;
104 Scatterer() =
default;
113 Value *operator[](
unsigned I);
116 unsigned size()
const {
return VS.NumFragments; }
130 FCmpSplitter(
FCmpInst &fci) : FCI(fci) {}
133 const Twine &Name)
const {
134 return Builder.CreateFCmp(FCI.getPredicate(), Op0, Op1, Name);
143 ICmpSplitter(
ICmpInst &ici) : ICI(ici) {}
146 const Twine &Name)
const {
147 return Builder.CreateICmp(ICI.getPredicate(), Op0, Op1, Name);
155struct UnarySplitter {
159 return Builder.CreateUnOp(UO.getOpcode(),
Op, Name);
167struct BinarySplitter {
171 const Twine &Name)
const {
172 return Builder.CreateBinOp(BO.getOpcode(), Op0, Op1, Name);
180 VectorLayout() =
default;
183 Align getFragmentAlign(
unsigned Frag) {
201 unsigned StructSize = Ty->getNumContainedTypes();
208 for (
unsigned I = 1;
I < StructSize;
I++) {
219 const VectorSplit &VS,
Twine Name) {
220 unsigned NumElements = VS.VecTy->getNumElements();
224 if (VS.NumPacked > 1) {
227 ExtendMask.
resize(NumElements, -1);
228 for (
unsigned I = 0;
I < VS.NumPacked; ++
I)
231 InsertMask.
resize(NumElements);
232 for (
unsigned I = 0;
I < NumElements; ++
I)
237 for (
unsigned I = 0;
I < VS.NumFragments; ++
I) {
240 unsigned NumPacked = VS.NumPacked;
241 if (
I == VS.NumFragments - 1 && VS.RemainderTy) {
243 NumPacked = RemVecTy->getNumElements();
248 if (NumPacked == 1) {
249 Res = Builder.CreateInsertElement(Res,
Fragment,
I * VS.NumPacked,
250 Name +
".upto" +
Twine(
I));
252 if (NumPacked < VS.NumPacked) {
255 ExtendMask.
resize(NumElements, -1);
258 Fragment = Builder.CreateShuffleVector(
263 for (
unsigned J = 0; J < NumPacked; ++J)
264 InsertMask[
I * VS.NumPacked + J] = NumElements + J;
265 Res = Builder.CreateShuffleVector(Res,
Fragment, InsertMask,
266 Name +
".upto" +
Twine(
I));
267 for (
unsigned J = 0; J < NumPacked; ++J)
268 InsertMask[
I * VS.NumPacked + J] =
I * VS.NumPacked + J;
277class ScalarizerVisitor :
public InstVisitor<ScalarizerVisitor, bool> {
279 ScalarizerVisitor(DominatorTree *DT,
const TargetTransformInfo *TTI,
282 ScalarizeVariableInsertExtract(
Options.ScalarizeVariableInsertExtract),
283 ScalarizeLoadStore(
Options.ScalarizeLoadStore),
284 ScalarizeMinBits(
Options.ScalarizeMinBits) {}
290 bool visitInstruction(Instruction &
I) {
return false; }
291 bool visitSelectInst(SelectInst &SI);
292 bool visitICmpInst(ICmpInst &ICI);
293 bool visitFCmpInst(FCmpInst &FCI);
294 bool visitUnaryOperator(UnaryOperator &UO);
295 bool visitBinaryOperator(BinaryOperator &BO);
296 bool visitGetElementPtrInst(GetElementPtrInst &GEPI);
297 bool visitCastInst(CastInst &CI);
298 bool visitBitCastInst(BitCastInst &BCI);
299 bool visitInsertElementInst(InsertElementInst &IEI);
300 bool visitExtractElementInst(ExtractElementInst &EEI);
301 bool visitExtractValueInst(ExtractValueInst &EVI);
302 bool visitShuffleVectorInst(ShuffleVectorInst &SVI);
303 bool visitPHINode(PHINode &
PHI);
304 bool visitLoadInst(LoadInst &LI);
305 bool visitStoreInst(StoreInst &SI);
306 bool visitCallInst(CallInst &ICI);
307 bool visitFreezeInst(FreezeInst &FI);
310 Scatterer scatter(Instruction *Point,
Value *
V,
const VectorSplit &VS);
311 void gather(Instruction *
Op,
const ValueVector &CV,
const VectorSplit &VS);
312 void replaceUses(Instruction *
Op,
Value *CV);
313 bool canTransferMetadata(
unsigned Kind);
314 void transferMetadataAndIRFlags(Instruction *
Op,
const ValueVector &CV);
315 std::optional<VectorSplit> getVectorSplit(
Type *Ty);
316 std::optional<VectorLayout> getVectorLayout(
Type *Ty, Align Alignment,
317 const DataLayout &
DL);
320 template<
typename T>
bool splitUnary(Instruction &,
const T &);
321 template<
typename T>
bool splitBinary(Instruction &,
const T &);
323 bool splitCall(CallInst &CI);
332 const TargetTransformInfo *TTI;
334 const bool ScalarizeVariableInsertExtract;
335 const bool ScalarizeLoadStore;
336 const unsigned ScalarizeMinBits;
342 ScalarizerPassOptions Options;
343 ScalarizerLegacyPass() : FunctionPass(ID), Options() {}
344 ScalarizerLegacyPass(
const ScalarizerPassOptions &Options);
346 void getAnalysisUsage(AnalysisUsage &AU)
const override;
354void ScalarizerLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
360char ScalarizerLegacyPass::ID = 0;
362 "Scalarize vector operations",
false,
false)
370 : BBI(bbi),
V(v), VS(VS), CachePtr(cachePtr) {
373 Tmp.resize(VS.NumFragments,
nullptr);
375 assert((CachePtr->empty() || VS.NumFragments == CachePtr->size() ||
377 "Inconsistent vector sizes");
378 if (VS.NumFragments > CachePtr->size())
379 CachePtr->resize(VS.NumFragments,
nullptr);
384Value *Scatterer::operator[](
unsigned Frag) {
390 Builder.disableGEPCanonicalization();
395 CV[Frag] = Builder.CreateConstGEP1_32(VS.SplitTy,
V, Frag,
396 V->getName() +
".i" + Twine(Frag));
400 Type *FragmentTy = VS.getFragmentType(Frag);
403 SmallVector<int>
Mask;
404 for (
unsigned J = 0; J < VecTy->getNumElements(); ++J)
405 Mask.push_back(Frag * VS.NumPacked + J);
420 unsigned J =
Idx->getZExtValue();
422 if (Frag * VS.NumPacked == J) {
423 CV[Frag] =
Insert->getOperand(1);
427 if (VS.NumPacked == 1 && !CV[J]) {
431 CV[J] =
Insert->getOperand(1);
434 CV[Frag] = Builder.CreateExtractElement(
V, Frag * VS.NumPacked,
435 V->getName() +
".i" + Twine(Frag));
441bool ScalarizerLegacyPass::runOnFunction(
Function &
F) {
445 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
446 const TargetTransformInfo *
TTI =
447 &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
449 return Impl.visit(
F);
453 return new ScalarizerLegacyPass(
Options);
456bool ScalarizerVisitor::visit(
Function &
F) {
469 if (
Done &&
I->getType()->isVoidTy()) {
470 I->eraseFromParent();
480Scatterer ScalarizerVisitor::scatter(Instruction *Point,
Value *
V,
481 const VectorSplit &VS) {
487 return Scatterer(BB->
begin(),
V, VS, &Scattered[{V, VS.SplitTy}]);
502 VS, &Scattered[{
V,
VS.SplitTy}]);
513void ScalarizerVisitor::gather(Instruction *
Op,
const ValueVector &CV,
514 const VectorSplit &VS) {
515 transferMetadataAndIRFlags(
Op, CV);
521 for (
unsigned I = 0,
E =
SV.size();
I !=
E; ++
I) {
523 if (
V ==
nullptr || SV[
I] == CV[
I])
528 CV[
I]->takeName(Old);
530 PotentiallyDeadInstrs.emplace_back(Old);
538void ScalarizerVisitor::replaceUses(Instruction *
Op,
Value *CV) {
540 Op->replaceAllUsesWith(CV);
541 PotentiallyDeadInstrs.emplace_back(
Op);
548bool ScalarizerVisitor::canTransferMetadata(
unsigned Tag) {
549 return (
Tag == LLVMContext::MD_tbaa
550 ||
Tag == LLVMContext::MD_fpmath
551 ||
Tag == LLVMContext::MD_tbaa_struct
552 ||
Tag == LLVMContext::MD_invariant_load
553 ||
Tag == LLVMContext::MD_alias_scope
554 ||
Tag == LLVMContext::MD_noalias
555 ||
Tag == LLVMContext::MD_mem_parallel_loop_access
556 ||
Tag == LLVMContext::MD_access_group);
561void ScalarizerVisitor::transferMetadataAndIRFlags(Instruction *
Op,
564 Op->getAllMetadataOtherThanDebugLoc(MDs);
567 for (
const auto &MD : MDs)
568 if (canTransferMetadata(MD.first))
569 New->setMetadata(MD.first, MD.second);
570 New->copyIRFlags(
Op);
571 if (
Op->getDebugLoc() && !
New->getDebugLoc())
572 New->setDebugLoc(
Op->getDebugLoc());
578std::optional<VectorSplit> ScalarizerVisitor::getVectorSplit(
Type *Ty) {
584 unsigned NumElems =
Split.VecTy->getNumElements();
585 Type *ElemTy =
Split.VecTy->getElementType();
590 Split.NumFragments = NumElems;
591 Split.SplitTy = ElemTy;
594 if (
Split.NumPacked >= NumElems)
600 unsigned RemainderElems = NumElems %
Split.NumPacked;
601 if (RemainderElems > 1)
603 else if (RemainderElems == 1)
604 Split.RemainderTy = ElemTy;
613std::optional<VectorLayout>
614ScalarizerVisitor::getVectorLayout(
Type *Ty, Align Alignment,
615 const DataLayout &
DL) {
616 std::optional<VectorSplit>
VS = getVectorSplit(Ty);
623 if (!
DL.typeSizeEqualsStoreSize(
VS->SplitTy) ||
624 (
VS->RemainderTy && !
DL.typeSizeEqualsStoreSize(
VS->RemainderTy)))
627 Layout.SplitSize =
DL.getTypeStoreSize(
VS->SplitTy);
633template<
typename Splitter>
634bool ScalarizerVisitor::splitUnary(Instruction &
I,
const Splitter &Split) {
635 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
639 std::optional<VectorSplit> OpVS;
640 if (
I.getOperand(0)->getType() ==
I.getType()) {
643 OpVS = getVectorSplit(
I.getOperand(0)->getType());
644 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
649 Scatterer
Op = scatter(&
I,
I.getOperand(0), *OpVS);
650 assert(
Op.size() ==
VS->NumFragments &&
"Mismatched unary operation");
653 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag)
654 Res[Frag] =
Split(Builder,
Op[Frag],
I.getName() +
".i" + Twine(Frag));
655 gather(&
I, Res, *VS);
661template<
typename Splitter>
662bool ScalarizerVisitor::splitBinary(Instruction &
I,
const Splitter &Split) {
663 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
667 std::optional<VectorSplit> OpVS;
668 if (
I.getOperand(0)->getType() ==
I.getType()) {
671 OpVS = getVectorSplit(
I.getOperand(0)->getType());
672 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
677 Scatterer VOp0 = scatter(&
I,
I.getOperand(0), *OpVS);
678 Scatterer VOp1 = scatter(&
I,
I.getOperand(1), *OpVS);
679 assert(VOp0.size() ==
VS->NumFragments &&
"Mismatched binary operation");
680 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched binary operation");
683 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag) {
684 Value *Op0 = VOp0[Frag];
685 Value *Op1 = VOp1[Frag];
686 Res[Frag] =
Split(Builder, Op0, Op1,
I.getName() +
".i" + Twine(Frag));
688 gather(&
I, Res, *VS);
694bool ScalarizerVisitor::splitCall(CallInst &CI) {
697 std::optional<VectorSplit>
VS;
698 if (AreAllVectorsOfMatchingSize)
701 VS = getVectorSplit(CallType);
719 SmallVector<int> OverloadIdx(NumArgs, -1);
726 if (AreAllVectorsOfMatchingSize) {
728 std::optional<VectorSplit> CurrVS =
736 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
744 for (
unsigned I = 0;
I != NumArgs; ++
I) {
746 if ([[maybe_unused]]
auto *OpVecTy =
748 assert(OpVecTy->getNumElements() ==
VS->VecTy->getNumElements());
749 std::optional<VectorSplit> OpVS = getVectorSplit(OpI->
getType());
750 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
761 Scattered[
I] = scatter(&CI, OpI, *OpVS);
763 OverloadIdx[
I] = Tys.
size();
767 ScalarOperands[
I] = OpI;
781 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
782 bool IsRemainder =
I ==
VS->NumFragments - 1 &&
VS->RemainderTy;
783 ScalarCallOps.clear();
786 Tys[0] =
VS->RemainderTy;
788 for (
unsigned J = 0; J != NumArgs; ++J) {
790 ScalarCallOps.push_back(ScalarOperands[J]);
792 ScalarCallOps.push_back(Scattered[J][
I]);
793 if (IsRemainder && OverloadIdx[J] >= 0)
794 Tys[OverloadIdx[J]] = Scattered[J][
I]->getType();
801 Res[
I] = Builder.CreateCall(NewIntrin, ScalarCallOps,
805 gather(&CI, Res, *VS);
809bool ScalarizerVisitor::visitSelectInst(SelectInst &SI) {
810 std::optional<VectorSplit>
VS = getVectorSplit(
SI.getType());
814 std::optional<VectorSplit> CondVS;
816 CondVS = getVectorSplit(
SI.getCondition()->getType());
817 if (!CondVS || CondVS->NumPacked !=
VS->NumPacked) {
824 Scatterer VOp1 = scatter(&SI,
SI.getOperand(1), *VS);
825 Scatterer VOp2 = scatter(&SI,
SI.getOperand(2), *VS);
826 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched select");
827 assert(VOp2.size() ==
VS->NumFragments &&
"Mismatched select");
832 Scatterer VOp0 = scatter(&SI,
SI.getOperand(0), *CondVS);
833 assert(VOp0.size() == CondVS->NumFragments &&
"Mismatched select");
834 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
838 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
839 SI.getName() +
".i" + Twine(
I));
843 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
846 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
847 SI.getName() +
".i" + Twine(
I));
850 gather(&SI, Res, *VS);
854bool ScalarizerVisitor::visitICmpInst(ICmpInst &ICI) {
855 return splitBinary(ICI, ICmpSplitter(ICI));
858bool ScalarizerVisitor::visitFCmpInst(FCmpInst &FCI) {
859 return splitBinary(FCI, FCmpSplitter(FCI));
862bool ScalarizerVisitor::visitUnaryOperator(UnaryOperator &UO) {
863 return splitUnary(UO, UnarySplitter(UO));
866bool ScalarizerVisitor::visitBinaryOperator(BinaryOperator &BO) {
867 return splitBinary(BO, BinarySplitter(BO));
870bool ScalarizerVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) {
871 std::optional<VectorSplit>
VS = getVectorSplit(GEPI.
getType());
876 Builder.disableGEPCanonicalization();
880 SmallVector<Value *, 8> ScalarOps{1 + NumIndices};
883 for (
unsigned I = 0;
I < 1 + NumIndices; ++
I) {
886 std::optional<VectorSplit> OpVS = getVectorSplit(VecTy);
887 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
891 ScatterOps[
I] = scatter(&GEPI, GEPI.
getOperand(
I), *OpVS);
899 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
900 SmallVector<Value *, 8> SplitOps;
901 SplitOps.
resize(1 + NumIndices);
902 for (
unsigned J = 0; J < 1 + NumIndices; ++J) {
904 SplitOps[J] = ScalarOps[J];
906 SplitOps[J] = ScatterOps[J][
I];
913 NewGEPI->setIsInBounds();
915 gather(&GEPI, Res, *VS);
919bool ScalarizerVisitor::visitCastInst(CastInst &CI) {
920 std::optional<VectorSplit> DestVS = getVectorSplit(CI.
getDestTy());
924 std::optional<VectorSplit> SrcVS = getVectorSplit(CI.
getSrcTy());
925 if (!SrcVS || SrcVS->NumPacked != DestVS->NumPacked)
929 Scatterer Op0 = scatter(&CI, CI.
getOperand(0), *SrcVS);
930 assert(Op0.size() == SrcVS->NumFragments &&
"Mismatched cast");
932 Res.
resize(DestVS->NumFragments);
933 for (
unsigned I = 0;
I < DestVS->NumFragments; ++
I)
935 Builder.CreateCast(CI.
getOpcode(), Op0[
I], DestVS->getFragmentType(
I),
937 gather(&CI, Res, *DestVS);
941bool ScalarizerVisitor::visitBitCastInst(BitCastInst &BCI) {
942 std::optional<VectorSplit> DstVS = getVectorSplit(BCI.
getDestTy());
943 std::optional<VectorSplit> SrcVS = getVectorSplit(BCI.
getSrcTy());
946 DstVS->NumPacked == 1 && DstVS->SplitTy->isIntegerTy()) {
948 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
950 unsigned FragmentBits = DstVS->SplitTy->getPrimitiveSizeInBits();
952 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
953 unsigned FragmentIndex = IsBigEndian ? DstVS->NumFragments -
I - 1 :
I;
957 Res[
I] = Builder.CreateTruncOrBitCast(
Fragment, DstVS->getFragmentType(
I),
960 gather(&BCI, Res, *DstVS);
965 !SrcVS->RemainderTy && SrcVS->NumPacked == 1 &&
966 SrcVS->SplitTy->isIntegerTy()) {
968 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
969 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
971 unsigned FragmentBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
973 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
974 unsigned FragmentIndex = IsBigEndian ? SrcVS->NumFragments -
I - 1 :
I;
980 replaceUses(&BCI, Result);
984 if (!DstVS || !SrcVS || DstVS->RemainderTy || SrcVS->RemainderTy)
987 const bool isPointerTy = DstVS->VecTy->getElementType()->isPointerTy();
993 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
995 Res.
resize(DstVS->NumFragments);
997 unsigned DstSplitBits = DstVS->SplitTy->getPrimitiveSizeInBits();
998 unsigned SrcSplitBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
1000 if (
isPointerTy || DstSplitBits == SrcSplitBits) {
1001 assert(DstVS->NumFragments == SrcVS->NumFragments);
1002 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1003 Res[
I] = Builder.CreateBitCast(Op0[
I], DstVS->getFragmentType(
I),
1006 }
else if (SrcSplitBits % DstSplitBits == 0) {
1010 MidVS.NumPacked = DstVS->NumPacked;
1011 MidVS.NumFragments = SrcSplitBits / DstSplitBits;
1013 MidVS.NumPacked * MidVS.NumFragments);
1014 MidVS.SplitTy = DstVS->SplitTy;
1017 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
1024 VI->getOpcode() == Instruction::BitCast)
1025 V =
VI->getOperand(0);
1027 V = Builder.CreateBitCast(
V, MidVS.VecTy,
V->getName() +
".cast");
1029 Scatterer Mid = scatter(&BCI,
V, MidVS);
1030 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1031 Res[ResI++] = Mid[J];
1033 }
else if (DstSplitBits % SrcSplitBits == 0) {
1037 MidVS.NumFragments = DstSplitBits / SrcSplitBits;
1038 MidVS.NumPacked = SrcVS->NumPacked;
1040 MidVS.NumPacked * MidVS.NumFragments);
1041 MidVS.SplitTy = SrcVS->SplitTy;
1044 SmallVector<Value *, 8> ConcatOps;
1045 ConcatOps.
resize(MidVS.NumFragments);
1046 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1047 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1048 ConcatOps[J] = Op0[SrcI++];
1051 Res[
I] = Builder.CreateBitCast(
V, DstVS->getFragmentType(
I),
1058 gather(&BCI, Res, *DstVS);
1062bool ScalarizerVisitor::visitInsertElementInst(InsertElementInst &IEI) {
1063 std::optional<VectorSplit>
VS = getVectorSplit(IEI.
getType());
1068 Scatterer Op0 = scatter(&IEI, IEI.
getOperand(0), *VS);
1076 unsigned Idx = CI->getZExtValue();
1078 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1081 if (
Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1082 !
VS->RemainderTy->isVectorTy())
1086 Builder.CreateInsertElement(Op0[
I], NewElt, Idx %
VS->NumPacked);
1096 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1099 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1100 Value *ShouldReplace =
1101 Builder.CreateICmpEQ(InsIdx, ConstantInt::get(InsIdx->
getType(),
I),
1102 InsIdx->
getName() +
".is." + Twine(
I));
1104 Res[
I] = Builder.CreateSelect(ShouldReplace, NewElt, OldElt,
1109 gather(&IEI, Res, *VS);
1113bool ScalarizerVisitor::visitExtractValueInst(ExtractValueInst &EVI) {
1115 Type *OpTy =
Op->getType();
1131 std::optional<VectorSplit>
VS = getVectorSplit(VecType);
1135 std::optional<VectorSplit> CurrVS =
1143 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
1147 Scatterer Op0 = scatter(&EVI,
Op, *VS);
1151 for (
unsigned OpIdx = 0; OpIdx < Op0.size(); ++OpIdx) {
1152 Value *ResElem = Builder.CreateExtractValue(
1153 Op0[OpIdx], Index, EVI.
getName() +
".elem" + Twine(Index));
1158 std::optional<VectorSplit> AVS = getVectorSplit(ActualVecType);
1159 gather(&EVI, Res, *AVS);
1163bool ScalarizerVisitor::visitExtractElementInst(ExtractElementInst &EEI) {
1169 Scatterer Op0 = scatter(&EEI, EEI.
getOperand(0), *VS);
1173 unsigned Idx = CI->getZExtValue();
1174 if (Idx >=
VS->VecTy->getNumElements())
1179 if (
Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1180 !
VS->RemainderTy->isVectorTy())
1183 Res = Builder.CreateExtractElement(Res, Idx %
VS->NumPacked);
1184 replaceUses(&EEI, Res);
1189 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1193 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1194 Value *ShouldExtract =
1195 Builder.CreateICmpEQ(ExtIdx, ConstantInt::get(ExtIdx->
getType(),
I),
1196 ExtIdx->
getName() +
".is." + Twine(
I));
1198 Res = Builder.CreateSelect(ShouldExtract, Elt, Res,
1199 EEI.
getName() +
".upto" + Twine(
I));
1201 replaceUses(&EEI, Res);
1205bool ScalarizerVisitor::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
1206 std::optional<VectorSplit>
VS = getVectorSplit(SVI.
getType());
1207 std::optional<VectorSplit> VSOp =
1209 if (!VS || !VSOp ||
VS->NumPacked > 1 || VSOp->NumPacked > 1)
1212 Scatterer Op0 = scatter(&SVI, SVI.
getOperand(0), *VSOp);
1213 Scatterer Op1 = scatter(&SVI, SVI.
getOperand(1), *VSOp);
1217 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1221 else if (
unsigned(Selector) < Op0.size())
1222 Res[
I] = Op0[Selector];
1224 Res[
I] = Op1[Selector - Op0.size()];
1226 gather(&SVI, Res, *VS);
1230bool ScalarizerVisitor::visitPHINode(PHINode &
PHI) {
1231 std::optional<VectorSplit>
VS = getVectorSplit(
PHI.getType());
1240 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1241 Res[
I] = Builder.CreatePHI(
VS->getFragmentType(
I),
NumOps,
1242 PHI.getName() +
".i" + Twine(
I));
1246 Scatterer
Op = scatter(&
PHI,
PHI.getIncomingValue(
I), *VS);
1248 for (
unsigned J = 0; J <
VS->NumFragments; ++J)
1251 gather(&
PHI, Res, *VS);
1255bool ScalarizerVisitor::visitLoadInst(LoadInst &LI) {
1256 if (!ScalarizeLoadStore)
1261 std::optional<VectorLayout> Layout = getVectorLayout(
1269 Res.
resize(Layout->VS.NumFragments);
1271 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1272 Res[
I] = Builder.CreateAlignedLoad(Layout->VS.getFragmentType(
I), Ptr[
I],
1273 Align(Layout->getFragmentAlign(
I)),
1276 gather(&LI, Res, Layout->VS);
1280bool ScalarizerVisitor::visitStoreInst(StoreInst &SI) {
1281 if (!ScalarizeLoadStore)
1286 Value *FullValue =
SI.getValueOperand();
1287 std::optional<VectorLayout> Layout = getVectorLayout(
1288 FullValue->
getType(),
SI.getAlign(),
SI.getDataLayout());
1293 Scatterer VPtr = scatter(&SI,
SI.getPointerOperand(), Layout->VS);
1294 Scatterer VVal = scatter(&SI, FullValue, Layout->VS);
1297 Stores.
resize(Layout->VS.NumFragments);
1298 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1302 Builder.CreateAlignedStore(Val, Ptr, Layout->getFragmentAlign(
I));
1304 transferMetadataAndIRFlags(&SI, Stores);
1308bool ScalarizerVisitor::visitCallInst(CallInst &CI) {
1309 return splitCall(CI);
1312bool ScalarizerVisitor::visitFreezeInst(FreezeInst &FI) {
1320bool ScalarizerVisitor::finish() {
1323 if (Gathered.
empty() && Scattered.empty() && !Scalarized)
1325 for (
const auto &GMI : Gathered) {
1328 if (!
Op->use_empty()) {
1338 VectorSplit
VS = *getVectorSplit(Ty);
1351 unsigned NumOfStructElements = Ty->getNumElements();
1353 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1354 for (
auto *CVelem : CV) {
1356 CVelem,
I,
Op->getName() +
".elem" + Twine(
I));
1357 ElemCV[
I].push_back(Elem);
1361 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1362 Type *ElemTy = Ty->getElementType(
I);
1364 "Only Structs of all FixedVectorType supported");
1365 VectorSplit
VS = *getVectorSplit(ElemTy);
1366 assert(
VS.NumFragments == CV.size());
1368 Value *ConcatenatedVector =
1371 Op->getName() +
".insert");
1374 assert(CV.size() == 1 &&
Op->getType() == CV[0]->getType());
1379 Op->replaceAllUsesWith(Res);
1381 PotentiallyDeadInstrs.emplace_back(
Op);
1395 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)
static BasicBlock::iterator skipPastPhiNodes(BasicBlock::iterator Itr)
SmallVector< std::pair< Instruction *, ValueVector * >, 16 > GatherList
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.
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.
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
bool isPointerTy(const Type *T)
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
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...
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.