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;
115 Value *operator[](
unsigned I);
118 unsigned size()
const {
return VS.NumFragments; }
132 FCmpSplitter(
FCmpInst &fci) : FCI(fci) {}
135 const Twine &Name)
const {
136 return Builder.CreateFCmp(FCI.getPredicate(), Op0, Op1, Name);
145 ICmpSplitter(
ICmpInst &ici) : ICI(ici) {}
148 const Twine &Name)
const {
149 return Builder.CreateICmp(ICI.getPredicate(), Op0, Op1, Name);
157struct UnarySplitter {
161 return Builder.CreateUnOp(UO.getOpcode(),
Op, Name);
169struct BinarySplitter {
173 const Twine &Name)
const {
174 return Builder.CreateBinOp(BO.getOpcode(), Op0, Op1, Name);
182 VectorLayout() =
default;
185 Align getFragmentAlign(
unsigned Frag) {
203 unsigned StructSize = Ty->getNumContainedTypes();
210 for (
unsigned I = 1;
I < StructSize;
I++) {
221 const VectorSplit &VS,
Twine Name) {
222 unsigned NumElements = VS.VecTy->getNumElements();
226 if (VS.NumPacked > 1) {
229 ExtendMask.
resize(NumElements, -1);
230 for (
unsigned I = 0;
I < VS.NumPacked; ++
I)
233 InsertMask.
resize(NumElements);
234 for (
unsigned I = 0;
I < NumElements; ++
I)
239 for (
unsigned I = 0;
I < VS.NumFragments; ++
I) {
242 unsigned NumPacked = VS.NumPacked;
243 if (
I == VS.NumFragments - 1 && VS.RemainderTy) {
245 NumPacked = RemVecTy->getNumElements();
250 if (NumPacked == 1) {
251 Res = Builder.CreateInsertElement(Res,
Fragment,
I * VS.NumPacked,
252 Name +
".upto" +
Twine(
I));
254 if (NumPacked < VS.NumPacked) {
257 ExtendMask.
resize(NumElements, -1);
260 Fragment = Builder.CreateShuffleVector(
265 for (
unsigned J = 0; J < NumPacked; ++J)
266 InsertMask[
I * VS.NumPacked + J] = NumElements + J;
267 Res = Builder.CreateShuffleVector(Res,
Fragment, InsertMask,
268 Name +
".upto" +
Twine(
I));
269 for (
unsigned J = 0; J < NumPacked; ++J)
270 InsertMask[
I * VS.NumPacked + J] =
I * VS.NumPacked + J;
279class ScalarizerVisitor :
public InstVisitor<ScalarizerVisitor, bool> {
281 ScalarizerVisitor(DominatorTree *DT,
const TargetTransformInfo *TTI,
284 ScalarizeVariableInsertExtract(
Options.ScalarizeVariableInsertExtract),
285 ScalarizeLoadStore(
Options.ScalarizeLoadStore),
286 ScalarizeMinBits(
Options.ScalarizeMinBits) {}
292 bool visitInstruction(Instruction &
I) {
return false; }
293 bool visitSelectInst(SelectInst &SI);
294 bool visitICmpInst(ICmpInst &ICI);
295 bool visitFCmpInst(FCmpInst &FCI);
296 bool visitUnaryOperator(UnaryOperator &UO);
297 bool visitBinaryOperator(BinaryOperator &BO);
298 bool visitGetElementPtrInst(GetElementPtrInst &GEPI);
299 bool visitCastInst(CastInst &CI);
300 bool visitBitCastInst(BitCastInst &BCI);
301 bool visitInsertElementInst(InsertElementInst &IEI);
302 bool visitExtractElementInst(ExtractElementInst &EEI);
303 bool visitExtractValueInst(ExtractValueInst &EVI);
304 bool visitShuffleVectorInst(ShuffleVectorInst &SVI);
305 bool visitPHINode(PHINode &
PHI);
306 bool visitLoadInst(LoadInst &LI);
307 bool visitStoreInst(StoreInst &SI);
308 bool visitCallInst(CallInst &ICI);
309 bool visitFreezeInst(FreezeInst &FI);
312 Scatterer scatter(Instruction *Point,
Value *V,
const VectorSplit &VS);
313 void gather(Instruction *
Op,
const ValueVector &CV,
const VectorSplit &VS);
314 void replaceUses(Instruction *
Op,
Value *CV);
315 bool canTransferMetadata(
unsigned Kind);
316 void transferMetadataAndIRFlags(Instruction *
Op,
const ValueVector &CV);
317 std::optional<VectorSplit> getVectorSplit(
Type *Ty);
318 std::optional<VectorLayout> getVectorLayout(
Type *Ty, Align Alignment,
319 const DataLayout &
DL);
322 template<
typename T>
bool splitUnary(Instruction &,
const T &);
323 template<
typename T>
bool splitBinary(Instruction &,
const T &);
325 bool splitCall(CallInst &CI);
334 const TargetTransformInfo *TTI;
336 const bool ScalarizeVariableInsertExtract;
337 const bool ScalarizeLoadStore;
338 const unsigned ScalarizeMinBits;
344 ScalarizerPassOptions Options;
345 ScalarizerLegacyPass() : FunctionPass(ID), Options() {}
346 ScalarizerLegacyPass(
const ScalarizerPassOptions &Options);
348 void getAnalysisUsage(AnalysisUsage &AU)
const override;
356void ScalarizerLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
362char ScalarizerLegacyPass::ID = 0;
364 "Scalarize vector operations",
false,
false)
372 : BBI(bbi), V(v), VS(VS), CachePtr(cachePtr) {
375 Tmp.resize(VS.NumFragments,
nullptr);
377 assert((CachePtr->empty() || VS.NumFragments == CachePtr->size() ||
379 "Inconsistent vector sizes");
380 if (VS.NumFragments > CachePtr->size())
381 CachePtr->resize(VS.NumFragments,
nullptr);
386Value *Scatterer::operator[](
unsigned Frag) {
396 CV[Frag] = Builder.CreateConstGEP1_32(VS.SplitTy, V, Frag,
397 V->
getName() +
".i" + Twine(Frag));
401 Type *FragmentTy = VS.getFragmentType(Frag);
404 SmallVector<int>
Mask;
405 for (
unsigned J = 0; J < VecTy->getNumElements(); ++J)
406 Mask.push_back(Frag * VS.NumPacked + J);
409 V->
getName() +
".i" + Twine(Frag));
421 unsigned J =
Idx->getZExtValue();
422 V =
Insert->getOperand(0);
423 if (Frag * VS.NumPacked == J) {
424 CV[Frag] =
Insert->getOperand(1);
428 if (VS.NumPacked == 1 && !CV[J]) {
432 CV[J] =
Insert->getOperand(1);
435 CV[Frag] = Builder.CreateExtractElement(V, Frag * VS.NumPacked,
436 V->
getName() +
".i" + Twine(Frag));
442bool ScalarizerLegacyPass::runOnFunction(
Function &
F) {
446 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
447 const TargetTransformInfo *
TTI =
448 &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
450 return Impl.visit(
F);
454 return new ScalarizerLegacyPass(
Options);
457bool ScalarizerVisitor::visit(
Function &
F) {
470 if (
Done &&
I->getType()->isVoidTy()) {
471 I->eraseFromParent();
481Scatterer ScalarizerVisitor::scatter(Instruction *Point,
Value *V,
482 const VectorSplit &VS) {
488 return Scatterer(BB->
begin(), V, VS, &Scattered[{V, VS.SplitTy}]);
504 &Scattered[{
V,
VS.SplitTy}]);
515void ScalarizerVisitor::gather(Instruction *
Op,
const ValueVector &CV,
516 const VectorSplit &VS) {
517 transferMetadataAndIRFlags(
Op, CV);
523 for (
unsigned I = 0,
E =
SV.size();
I !=
E; ++
I) {
525 if (V ==
nullptr || SV[
I] == CV[
I])
530 CV[
I]->takeName(Old);
532 PotentiallyDeadInstrs.emplace_back(Old);
540void ScalarizerVisitor::replaceUses(Instruction *
Op,
Value *CV) {
542 Op->replaceAllUsesWith(CV);
543 PotentiallyDeadInstrs.emplace_back(
Op);
550bool ScalarizerVisitor::canTransferMetadata(
unsigned Tag) {
551 return (
Tag == LLVMContext::MD_tbaa
552 ||
Tag == LLVMContext::MD_fpmath
553 ||
Tag == LLVMContext::MD_tbaa_struct
554 ||
Tag == LLVMContext::MD_invariant_load
555 ||
Tag == LLVMContext::MD_alias_scope
556 ||
Tag == LLVMContext::MD_noalias
557 ||
Tag == LLVMContext::MD_mem_parallel_loop_access
558 ||
Tag == LLVMContext::MD_access_group);
563void ScalarizerVisitor::transferMetadataAndIRFlags(Instruction *
Op,
566 Op->getAllMetadataOtherThanDebugLoc(MDs);
567 for (
Value *V : CV) {
569 for (
const auto &MD : MDs)
570 if (canTransferMetadata(MD.first))
571 New->setMetadata(MD.first, MD.second);
572 New->copyIRFlags(
Op);
573 if (
Op->getDebugLoc() && !
New->getDebugLoc())
574 New->setDebugLoc(
Op->getDebugLoc());
580std::optional<VectorSplit> ScalarizerVisitor::getVectorSplit(
Type *Ty) {
586 unsigned NumElems =
Split.VecTy->getNumElements();
587 Type *ElemTy =
Split.VecTy->getElementType();
592 Split.NumFragments = NumElems;
593 Split.SplitTy = ElemTy;
596 if (
Split.NumPacked >= NumElems)
602 unsigned RemainderElems = NumElems %
Split.NumPacked;
603 if (RemainderElems > 1)
605 else if (RemainderElems == 1)
606 Split.RemainderTy = ElemTy;
615std::optional<VectorLayout>
616ScalarizerVisitor::getVectorLayout(
Type *Ty, Align Alignment,
617 const DataLayout &
DL) {
618 std::optional<VectorSplit>
VS = getVectorSplit(Ty);
625 if (!
DL.typeSizeEqualsStoreSize(
VS->SplitTy) ||
626 (
VS->RemainderTy && !
DL.typeSizeEqualsStoreSize(
VS->RemainderTy)))
629 Layout.SplitSize =
DL.getTypeStoreSize(
VS->SplitTy);
635template<
typename Splitter>
636bool ScalarizerVisitor::splitUnary(Instruction &
I,
const Splitter &Split) {
637 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
641 std::optional<VectorSplit> OpVS;
642 if (
I.getOperand(0)->getType() ==
I.getType()) {
645 OpVS = getVectorSplit(
I.getOperand(0)->getType());
646 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
651 Scatterer
Op = scatter(&
I,
I.getOperand(0), *OpVS);
652 assert(
Op.size() ==
VS->NumFragments &&
"Mismatched unary operation");
655 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag)
656 Res[Frag] =
Split(Builder,
Op[Frag],
I.getName() +
".i" + Twine(Frag));
657 gather(&
I, Res, *VS);
663template<
typename Splitter>
664bool ScalarizerVisitor::splitBinary(Instruction &
I,
const Splitter &Split) {
665 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
669 std::optional<VectorSplit> OpVS;
670 if (
I.getOperand(0)->getType() ==
I.getType()) {
673 OpVS = getVectorSplit(
I.getOperand(0)->getType());
674 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
679 Scatterer VOp0 = scatter(&
I,
I.getOperand(0), *OpVS);
680 Scatterer VOp1 = scatter(&
I,
I.getOperand(1), *OpVS);
681 assert(VOp0.size() ==
VS->NumFragments &&
"Mismatched binary operation");
682 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched binary operation");
685 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag) {
686 Value *Op0 = VOp0[Frag];
687 Value *Op1 = VOp1[Frag];
688 Res[Frag] =
Split(Builder, Op0, Op1,
I.getName() +
".i" + Twine(Frag));
690 gather(&
I, Res, *VS);
696bool ScalarizerVisitor::splitCall(CallInst &CI) {
699 std::optional<VectorSplit>
VS;
700 if (AreAllVectorsOfMatchingSize)
703 VS = getVectorSplit(CallType);
721 SmallVector<int> OverloadIdx(NumArgs, -1);
728 if (AreAllVectorsOfMatchingSize) {
730 std::optional<VectorSplit> CurrVS =
738 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
746 for (
unsigned I = 0;
I != NumArgs; ++
I) {
748 if ([[maybe_unused]]
auto *OpVecTy =
750 assert(OpVecTy->getNumElements() ==
VS->VecTy->getNumElements());
751 std::optional<VectorSplit> OpVS = getVectorSplit(OpI->
getType());
752 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
763 Scattered[
I] = scatter(&CI, OpI, *OpVS);
765 OverloadIdx[
I] = Tys.
size();
769 ScalarOperands[
I] = OpI;
783 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
784 bool IsRemainder =
I ==
VS->NumFragments - 1 &&
VS->RemainderTy;
785 ScalarCallOps.clear();
788 Tys[0] =
VS->RemainderTy;
790 for (
unsigned J = 0; J != NumArgs; ++J) {
792 ScalarCallOps.push_back(ScalarOperands[J]);
794 ScalarCallOps.push_back(Scattered[J][
I]);
795 if (IsRemainder && OverloadIdx[J] >= 0)
796 Tys[OverloadIdx[J]] = Scattered[J][
I]->getType();
803 Res[
I] = Builder.CreateCall(NewIntrin, ScalarCallOps,
807 gather(&CI, Res, *VS);
811bool ScalarizerVisitor::visitSelectInst(SelectInst &SI) {
812 std::optional<VectorSplit>
VS = getVectorSplit(
SI.getType());
816 std::optional<VectorSplit> CondVS;
818 CondVS = getVectorSplit(
SI.getCondition()->getType());
819 if (!CondVS || CondVS->NumPacked !=
VS->NumPacked) {
826 Scatterer VOp1 = scatter(&SI,
SI.getOperand(1), *VS);
827 Scatterer VOp2 = scatter(&SI,
SI.getOperand(2), *VS);
828 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched select");
829 assert(VOp2.size() ==
VS->NumFragments &&
"Mismatched select");
834 Scatterer VOp0 = scatter(&SI,
SI.getOperand(0), *CondVS);
835 assert(VOp0.size() == CondVS->NumFragments &&
"Mismatched select");
836 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
840 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
841 SI.getName() +
".i" + Twine(
I));
845 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
848 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
849 SI.getName() +
".i" + Twine(
I));
852 gather(&SI, Res, *VS);
856bool ScalarizerVisitor::visitICmpInst(ICmpInst &ICI) {
857 return splitBinary(ICI, ICmpSplitter(ICI));
860bool ScalarizerVisitor::visitFCmpInst(FCmpInst &FCI) {
861 return splitBinary(FCI, FCmpSplitter(FCI));
864bool ScalarizerVisitor::visitUnaryOperator(UnaryOperator &UO) {
865 return splitUnary(UO, UnarySplitter(UO));
868bool ScalarizerVisitor::visitBinaryOperator(BinaryOperator &BO) {
869 return splitBinary(BO, BinarySplitter(BO));
872bool ScalarizerVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) {
873 std::optional<VectorSplit>
VS = getVectorSplit(GEPI.
getType());
881 SmallVector<Value *, 8> ScalarOps{1 + NumIndices};
884 for (
unsigned I = 0;
I < 1 + NumIndices; ++
I) {
887 std::optional<VectorSplit> OpVS = getVectorSplit(VecTy);
888 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
892 ScatterOps[
I] = scatter(&GEPI, GEPI.
getOperand(
I), *OpVS);
900 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
901 SmallVector<Value *, 8> SplitOps;
902 SplitOps.
resize(1 + NumIndices);
903 for (
unsigned J = 0; J < 1 + NumIndices; ++J) {
905 SplitOps[J] = ScalarOps[J];
907 SplitOps[J] = ScatterOps[J][
I];
914 NewGEPI->setIsInBounds();
916 gather(&GEPI, Res, *VS);
920bool ScalarizerVisitor::visitCastInst(CastInst &CI) {
921 std::optional<VectorSplit> DestVS = getVectorSplit(CI.
getDestTy());
925 std::optional<VectorSplit> SrcVS = getVectorSplit(CI.
getSrcTy());
926 if (!SrcVS || SrcVS->NumPacked != DestVS->NumPacked)
930 Scatterer Op0 = scatter(&CI, CI.
getOperand(0), *SrcVS);
931 assert(Op0.size() == SrcVS->NumFragments &&
"Mismatched cast");
933 Res.
resize(DestVS->NumFragments);
934 for (
unsigned I = 0;
I < DestVS->NumFragments; ++
I)
936 Builder.CreateCast(CI.
getOpcode(), Op0[
I], DestVS->getFragmentType(
I),
938 gather(&CI, Res, *DestVS);
942bool ScalarizerVisitor::visitBitCastInst(BitCastInst &BCI) {
943 std::optional<VectorSplit> DstVS = getVectorSplit(BCI.
getDestTy());
944 std::optional<VectorSplit> SrcVS = getVectorSplit(BCI.
getSrcTy());
947 DstVS->NumPacked == 1 && DstVS->SplitTy->isIntegerTy()) {
949 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
951 unsigned FragmentBits = DstVS->SplitTy->getPrimitiveSizeInBits();
953 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
954 unsigned FragmentIndex = IsBigEndian ? DstVS->NumFragments -
I - 1 :
I;
958 Res[
I] = Builder.CreateTruncOrBitCast(
Fragment, DstVS->getFragmentType(
I),
961 gather(&BCI, Res, *DstVS);
966 !SrcVS->RemainderTy && SrcVS->NumPacked == 1 &&
967 SrcVS->SplitTy->isIntegerTy()) {
969 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
970 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
972 unsigned FragmentBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
974 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
975 unsigned FragmentIndex = IsBigEndian ? SrcVS->NumFragments -
I - 1 :
I;
981 replaceUses(&BCI, Result);
985 if (!DstVS || !SrcVS || DstVS->RemainderTy || SrcVS->RemainderTy)
988 const bool isPointerTy = DstVS->VecTy->getElementType()->isPointerTy();
994 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
996 Res.
resize(DstVS->NumFragments);
998 unsigned DstSplitBits = DstVS->SplitTy->getPrimitiveSizeInBits();
999 unsigned SrcSplitBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
1001 if (
isPointerTy || DstSplitBits == SrcSplitBits) {
1002 assert(DstVS->NumFragments == SrcVS->NumFragments);
1003 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1004 Res[
I] = Builder.CreateBitCast(Op0[
I], DstVS->getFragmentType(
I),
1007 }
else if (SrcSplitBits % DstSplitBits == 0) {
1011 MidVS.NumPacked = DstVS->NumPacked;
1012 MidVS.NumFragments = SrcSplitBits / DstSplitBits;
1014 MidVS.NumPacked * MidVS.NumFragments);
1015 MidVS.SplitTy = DstVS->SplitTy;
1018 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
1025 VI->getOpcode() == Instruction::BitCast)
1026 V =
VI->getOperand(0);
1028 V = Builder.CreateBitCast(V, MidVS.VecTy,
V->getName() +
".cast");
1030 Scatterer Mid = scatter(&BCI, V, MidVS);
1031 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1032 Res[ResI++] = Mid[J];
1034 }
else if (DstSplitBits % SrcSplitBits == 0) {
1038 MidVS.NumFragments = DstSplitBits / SrcSplitBits;
1039 MidVS.NumPacked = SrcVS->NumPacked;
1041 MidVS.NumPacked * MidVS.NumFragments);
1042 MidVS.SplitTy = SrcVS->SplitTy;
1045 SmallVector<Value *, 8> ConcatOps;
1046 ConcatOps.
resize(MidVS.NumFragments);
1047 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1048 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1049 ConcatOps[J] = Op0[SrcI++];
1052 Res[
I] = Builder.CreateBitCast(V, DstVS->getFragmentType(
I),
1059 gather(&BCI, Res, *DstVS);
1063bool ScalarizerVisitor::visitInsertElementInst(InsertElementInst &IEI) {
1064 std::optional<VectorSplit>
VS = getVectorSplit(IEI.
getType());
1069 Scatterer Op0 = scatter(&IEI, IEI.
getOperand(0), *VS);
1077 unsigned Idx = CI->getZExtValue();
1079 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1082 if (
Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1083 !
VS->RemainderTy->isVectorTy())
1087 Builder.CreateInsertElement(Op0[
I], NewElt, Idx %
VS->NumPacked);
1097 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1100 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1101 Value *ShouldReplace =
1102 Builder.CreateICmpEQ(InsIdx, ConstantInt::get(InsIdx->
getType(),
I),
1103 InsIdx->
getName() +
".is." + Twine(
I));
1105 Res[
I] = Builder.CreateSelect(ShouldReplace, NewElt, OldElt,
1110 gather(&IEI, Res, *VS);
1114bool ScalarizerVisitor::visitExtractValueInst(ExtractValueInst &EVI) {
1116 Type *OpTy =
Op->getType();
1132 std::optional<VectorSplit>
VS = getVectorSplit(VecType);
1136 std::optional<VectorSplit> CurrVS =
1144 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
1148 Scatterer Op0 = scatter(&EVI,
Op, *VS);
1152 for (
unsigned OpIdx = 0; OpIdx < Op0.size(); ++OpIdx) {
1153 Value *ResElem = Builder.CreateExtractValue(
1154 Op0[OpIdx], Index, EVI.
getName() +
".elem" + Twine(Index));
1159 std::optional<VectorSplit> AVS = getVectorSplit(ActualVecType);
1160 gather(&EVI, Res, *AVS);
1164bool ScalarizerVisitor::visitExtractElementInst(ExtractElementInst &EEI) {
1170 Scatterer Op0 = scatter(&EEI, EEI.
getOperand(0), *VS);
1174 unsigned Idx = CI->getZExtValue();
1175 if (Idx >=
VS->VecTy->getNumElements())
1180 if (
Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1181 !
VS->RemainderTy->isVectorTy())
1184 Res = Builder.CreateExtractElement(Res, Idx %
VS->NumPacked);
1185 replaceUses(&EEI, Res);
1190 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1194 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1195 Value *ShouldExtract =
1196 Builder.CreateICmpEQ(ExtIdx, ConstantInt::get(ExtIdx->
getType(),
I),
1197 ExtIdx->
getName() +
".is." + Twine(
I));
1199 Res = Builder.CreateSelect(ShouldExtract, Elt, Res,
1200 EEI.
getName() +
".upto" + Twine(
I));
1202 replaceUses(&EEI, Res);
1206bool ScalarizerVisitor::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
1207 std::optional<VectorSplit>
VS = getVectorSplit(SVI.
getType());
1208 std::optional<VectorSplit> VSOp =
1210 if (!VS || !VSOp ||
VS->NumPacked > 1 || VSOp->NumPacked > 1)
1213 Scatterer Op0 = scatter(&SVI, SVI.
getOperand(0), *VSOp);
1214 Scatterer Op1 = scatter(&SVI, SVI.
getOperand(1), *VSOp);
1218 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1222 else if (
unsigned(Selector) < Op0.size())
1223 Res[
I] = Op0[Selector];
1225 Res[
I] = Op1[Selector - Op0.size()];
1227 gather(&SVI, Res, *VS);
1231bool ScalarizerVisitor::visitPHINode(PHINode &
PHI) {
1232 std::optional<VectorSplit>
VS = getVectorSplit(
PHI.getType());
1241 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1242 Res[
I] = Builder.CreatePHI(
VS->getFragmentType(
I),
NumOps,
1243 PHI.getName() +
".i" + Twine(
I));
1247 Scatterer
Op = scatter(&
PHI,
PHI.getIncomingValue(
I), *VS);
1249 for (
unsigned J = 0; J <
VS->NumFragments; ++J)
1252 gather(&
PHI, Res, *VS);
1256bool ScalarizerVisitor::visitLoadInst(LoadInst &LI) {
1257 if (!ScalarizeLoadStore)
1262 std::optional<VectorLayout> Layout = getVectorLayout(
1270 Res.
resize(Layout->VS.NumFragments);
1272 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1273 Res[
I] = Builder.CreateAlignedLoad(Layout->VS.getFragmentType(
I), Ptr[
I],
1274 Align(Layout->getFragmentAlign(
I)),
1277 gather(&LI, Res, Layout->VS);
1281bool ScalarizerVisitor::visitStoreInst(StoreInst &SI) {
1282 if (!ScalarizeLoadStore)
1287 Value *FullValue =
SI.getValueOperand();
1288 std::optional<VectorLayout> Layout = getVectorLayout(
1289 FullValue->
getType(),
SI.getAlign(),
SI.getDataLayout());
1294 Scatterer VPtr = scatter(&SI,
SI.getPointerOperand(), Layout->VS);
1295 Scatterer VVal = scatter(&SI, FullValue, Layout->VS);
1298 Stores.
resize(Layout->VS.NumFragments);
1299 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1303 Builder.CreateAlignedStore(Val, Ptr, Layout->getFragmentAlign(
I));
1305 transferMetadataAndIRFlags(&SI, Stores);
1309bool ScalarizerVisitor::visitCallInst(CallInst &CI) {
1310 return splitCall(CI);
1313bool ScalarizerVisitor::visitFreezeInst(FreezeInst &FI) {
1321bool ScalarizerVisitor::finish() {
1324 if (Gathered.
empty() && Scattered.empty() && !Scalarized)
1326 for (
const auto &GMI : Gathered) {
1329 if (!
Op->use_empty()) {
1339 VectorSplit
VS = *getVectorSplit(Ty);
1352 unsigned NumOfStructElements = Ty->getNumElements();
1354 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1355 for (
auto *CVelem : CV) {
1357 CVelem,
I,
Op->getName() +
".elem" + Twine(
I));
1358 ElemCV[
I].push_back(Elem);
1362 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1363 Type *ElemTy = Ty->getElementType(
I);
1365 "Only Structs of all FixedVectorType supported");
1366 VectorSplit
VS = *getVectorSplit(ElemTy);
1367 assert(
VS.NumFragments == CV.size());
1369 Value *ConcatenatedVector =
1372 Op->getName() +
".insert");
1375 assert(CV.size() == 1 &&
Op->getType() == CV[0]->getType());
1380 Op->replaceAllUsesWith(Res);
1382 PotentiallyDeadInstrs.emplace_back(
Op);
1396 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.
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
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)
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.