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) {
394 CV[Frag] = Builder.CreateConstGEP1_32(VS.SplitTy, V, Frag,
395 V->
getName() +
".i" + Twine(Frag));
399 Type *FragmentTy = VS.getFragmentType(Frag);
402 SmallVector<int>
Mask;
403 for (
unsigned J = 0; J < VecTy->getNumElements(); ++J)
404 Mask.push_back(Frag * VS.NumPacked + J);
407 V->
getName() +
".i" + Twine(Frag));
419 unsigned J =
Idx->getZExtValue();
420 V =
Insert->getOperand(0);
421 if (Frag * VS.NumPacked == J) {
422 CV[Frag] =
Insert->getOperand(1);
426 if (VS.NumPacked == 1 && !CV[J]) {
430 CV[J] =
Insert->getOperand(1);
433 CV[Frag] = Builder.CreateExtractElement(V, Frag * VS.NumPacked,
434 V->
getName() +
".i" + Twine(Frag));
440bool ScalarizerLegacyPass::runOnFunction(
Function &
F) {
444 DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
445 const TargetTransformInfo *
TTI =
446 &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
448 return Impl.visit(
F);
452 return new ScalarizerLegacyPass(
Options);
455bool ScalarizerVisitor::visit(
Function &
F) {
468 if (
Done &&
I->getType()->isVoidTy()) {
469 I->eraseFromParent();
479Scatterer ScalarizerVisitor::scatter(Instruction *Point,
Value *V,
480 const VectorSplit &VS) {
486 return Scatterer(BB->
begin(), V, VS, &Scattered[{V, VS.SplitTy}]);
501 VS, &Scattered[{
V,
VS.SplitTy}]);
512void ScalarizerVisitor::gather(Instruction *
Op,
const ValueVector &CV,
513 const VectorSplit &VS) {
514 transferMetadataAndIRFlags(
Op, CV);
520 for (
unsigned I = 0,
E =
SV.size();
I !=
E; ++
I) {
522 if (V ==
nullptr || SV[
I] == CV[
I])
527 CV[
I]->takeName(Old);
529 PotentiallyDeadInstrs.emplace_back(Old);
537void ScalarizerVisitor::replaceUses(Instruction *
Op,
Value *CV) {
539 Op->replaceAllUsesWith(CV);
540 PotentiallyDeadInstrs.emplace_back(
Op);
547bool ScalarizerVisitor::canTransferMetadata(
unsigned Tag) {
548 return (
Tag == LLVMContext::MD_tbaa
549 ||
Tag == LLVMContext::MD_fpmath
550 ||
Tag == LLVMContext::MD_tbaa_struct
551 ||
Tag == LLVMContext::MD_invariant_load
552 ||
Tag == LLVMContext::MD_alias_scope
553 ||
Tag == LLVMContext::MD_noalias
554 ||
Tag == LLVMContext::MD_mem_parallel_loop_access
555 ||
Tag == LLVMContext::MD_access_group);
560void ScalarizerVisitor::transferMetadataAndIRFlags(Instruction *
Op,
563 Op->getAllMetadataOtherThanDebugLoc(MDs);
564 for (
Value *V : CV) {
566 for (
const auto &MD : MDs)
567 if (canTransferMetadata(MD.first))
568 New->setMetadata(MD.first, MD.second);
569 New->copyIRFlags(
Op);
570 if (
Op->getDebugLoc() && !
New->getDebugLoc())
571 New->setDebugLoc(
Op->getDebugLoc());
577std::optional<VectorSplit> ScalarizerVisitor::getVectorSplit(
Type *Ty) {
583 unsigned NumElems =
Split.VecTy->getNumElements();
584 Type *ElemTy =
Split.VecTy->getElementType();
589 Split.NumFragments = NumElems;
590 Split.SplitTy = ElemTy;
593 if (
Split.NumPacked >= NumElems)
599 unsigned RemainderElems = NumElems %
Split.NumPacked;
600 if (RemainderElems > 1)
602 else if (RemainderElems == 1)
603 Split.RemainderTy = ElemTy;
612std::optional<VectorLayout>
613ScalarizerVisitor::getVectorLayout(
Type *Ty, Align Alignment,
614 const DataLayout &
DL) {
615 std::optional<VectorSplit>
VS = getVectorSplit(Ty);
622 if (!
DL.typeSizeEqualsStoreSize(
VS->SplitTy) ||
623 (
VS->RemainderTy && !
DL.typeSizeEqualsStoreSize(
VS->RemainderTy)))
626 Layout.SplitSize =
DL.getTypeStoreSize(
VS->SplitTy);
632template<
typename Splitter>
633bool ScalarizerVisitor::splitUnary(Instruction &
I,
const Splitter &Split) {
634 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
638 std::optional<VectorSplit> OpVS;
639 if (
I.getOperand(0)->getType() ==
I.getType()) {
642 OpVS = getVectorSplit(
I.getOperand(0)->getType());
643 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
648 Scatterer
Op = scatter(&
I,
I.getOperand(0), *OpVS);
649 assert(
Op.size() ==
VS->NumFragments &&
"Mismatched unary operation");
652 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag)
653 Res[Frag] =
Split(Builder,
Op[Frag],
I.getName() +
".i" + Twine(Frag));
654 gather(&
I, Res, *VS);
660template<
typename Splitter>
661bool ScalarizerVisitor::splitBinary(Instruction &
I,
const Splitter &Split) {
662 std::optional<VectorSplit>
VS = getVectorSplit(
I.getType());
666 std::optional<VectorSplit> OpVS;
667 if (
I.getOperand(0)->getType() ==
I.getType()) {
670 OpVS = getVectorSplit(
I.getOperand(0)->getType());
671 if (!OpVS ||
VS->NumPacked != OpVS->NumPacked)
676 Scatterer VOp0 = scatter(&
I,
I.getOperand(0), *OpVS);
677 Scatterer VOp1 = scatter(&
I,
I.getOperand(1), *OpVS);
678 assert(VOp0.size() ==
VS->NumFragments &&
"Mismatched binary operation");
679 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched binary operation");
682 for (
unsigned Frag = 0; Frag <
VS->NumFragments; ++Frag) {
683 Value *Op0 = VOp0[Frag];
684 Value *Op1 = VOp1[Frag];
685 Res[Frag] =
Split(Builder, Op0, Op1,
I.getName() +
".i" + Twine(Frag));
687 gather(&
I, Res, *VS);
693bool ScalarizerVisitor::splitCall(CallInst &CI) {
696 std::optional<VectorSplit>
VS;
697 if (AreAllVectorsOfMatchingSize)
700 VS = getVectorSplit(CallType);
718 SmallVector<int> OverloadIdx(NumArgs, -1);
725 if (AreAllVectorsOfMatchingSize) {
727 std::optional<VectorSplit> CurrVS =
735 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
743 for (
unsigned I = 0;
I != NumArgs; ++
I) {
745 if ([[maybe_unused]]
auto *OpVecTy =
747 assert(OpVecTy->getNumElements() ==
VS->VecTy->getNumElements());
748 std::optional<VectorSplit> OpVS = getVectorSplit(OpI->
getType());
749 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
760 Scattered[
I] = scatter(&CI, OpI, *OpVS);
762 OverloadIdx[
I] = Tys.
size();
766 ScalarOperands[
I] = OpI;
780 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
781 bool IsRemainder =
I ==
VS->NumFragments - 1 &&
VS->RemainderTy;
782 ScalarCallOps.clear();
785 Tys[0] =
VS->RemainderTy;
787 for (
unsigned J = 0; J != NumArgs; ++J) {
789 ScalarCallOps.push_back(ScalarOperands[J]);
791 ScalarCallOps.push_back(Scattered[J][
I]);
792 if (IsRemainder && OverloadIdx[J] >= 0)
793 Tys[OverloadIdx[J]] = Scattered[J][
I]->getType();
800 Res[
I] = Builder.CreateCall(NewIntrin, ScalarCallOps,
804 gather(&CI, Res, *VS);
808bool ScalarizerVisitor::visitSelectInst(SelectInst &SI) {
809 std::optional<VectorSplit>
VS = getVectorSplit(
SI.getType());
813 std::optional<VectorSplit> CondVS;
815 CondVS = getVectorSplit(
SI.getCondition()->getType());
816 if (!CondVS || CondVS->NumPacked !=
VS->NumPacked) {
823 Scatterer VOp1 = scatter(&SI,
SI.getOperand(1), *VS);
824 Scatterer VOp2 = scatter(&SI,
SI.getOperand(2), *VS);
825 assert(VOp1.size() ==
VS->NumFragments &&
"Mismatched select");
826 assert(VOp2.size() ==
VS->NumFragments &&
"Mismatched select");
831 Scatterer VOp0 = scatter(&SI,
SI.getOperand(0), *CondVS);
832 assert(VOp0.size() == CondVS->NumFragments &&
"Mismatched select");
833 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
837 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
838 SI.getName() +
".i" + Twine(
I));
842 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
845 Res[
I] = Builder.CreateSelect(Op0, Op1, Op2,
846 SI.getName() +
".i" + Twine(
I));
849 gather(&SI, Res, *VS);
853bool ScalarizerVisitor::visitICmpInst(ICmpInst &ICI) {
854 return splitBinary(ICI, ICmpSplitter(ICI));
857bool ScalarizerVisitor::visitFCmpInst(FCmpInst &FCI) {
858 return splitBinary(FCI, FCmpSplitter(FCI));
861bool ScalarizerVisitor::visitUnaryOperator(UnaryOperator &UO) {
862 return splitUnary(UO, UnarySplitter(UO));
865bool ScalarizerVisitor::visitBinaryOperator(BinaryOperator &BO) {
866 return splitBinary(BO, BinarySplitter(BO));
869bool ScalarizerVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) {
870 std::optional<VectorSplit>
VS = getVectorSplit(GEPI.
getType());
878 SmallVector<Value *, 8> ScalarOps{1 + NumIndices};
881 for (
unsigned I = 0;
I < 1 + NumIndices; ++
I) {
884 std::optional<VectorSplit> OpVS = getVectorSplit(VecTy);
885 if (!OpVS || OpVS->NumPacked !=
VS->NumPacked) {
889 ScatterOps[
I] = scatter(&GEPI, GEPI.
getOperand(
I), *OpVS);
897 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
898 SmallVector<Value *, 8> SplitOps;
899 SplitOps.
resize(1 + NumIndices);
900 for (
unsigned J = 0; J < 1 + NumIndices; ++J) {
902 SplitOps[J] = ScalarOps[J];
904 SplitOps[J] = ScatterOps[J][
I];
911 NewGEPI->setIsInBounds();
913 gather(&GEPI, Res, *VS);
917bool ScalarizerVisitor::visitCastInst(CastInst &CI) {
918 std::optional<VectorSplit> DestVS = getVectorSplit(CI.
getDestTy());
922 std::optional<VectorSplit> SrcVS = getVectorSplit(CI.
getSrcTy());
923 if (!SrcVS || SrcVS->NumPacked != DestVS->NumPacked)
927 Scatterer Op0 = scatter(&CI, CI.
getOperand(0), *SrcVS);
928 assert(Op0.size() == SrcVS->NumFragments &&
"Mismatched cast");
930 Res.
resize(DestVS->NumFragments);
931 for (
unsigned I = 0;
I < DestVS->NumFragments; ++
I)
933 Builder.CreateCast(CI.
getOpcode(), Op0[
I], DestVS->getFragmentType(
I),
935 gather(&CI, Res, *DestVS);
939bool ScalarizerVisitor::visitBitCastInst(BitCastInst &BCI) {
940 std::optional<VectorSplit> DstVS = getVectorSplit(BCI.
getDestTy());
941 std::optional<VectorSplit> SrcVS = getVectorSplit(BCI.
getSrcTy());
944 DstVS->NumPacked == 1 && DstVS->SplitTy->isIntegerTy()) {
946 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
948 unsigned FragmentBits = DstVS->SplitTy->getPrimitiveSizeInBits();
950 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
951 unsigned FragmentIndex = IsBigEndian ? DstVS->NumFragments -
I - 1 :
I;
955 Res[
I] = Builder.CreateTruncOrBitCast(
Fragment, DstVS->getFragmentType(
I),
958 gather(&BCI, Res, *DstVS);
963 !SrcVS->RemainderTy && SrcVS->NumPacked == 1 &&
964 SrcVS->SplitTy->isIntegerTy()) {
966 Builder.SetCurrentDebugLocation(BCI.
getDebugLoc());
967 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
969 unsigned FragmentBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
971 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
972 unsigned FragmentIndex = IsBigEndian ? SrcVS->NumFragments -
I - 1 :
I;
978 replaceUses(&BCI, Result);
982 if (!DstVS || !SrcVS || DstVS->RemainderTy || SrcVS->RemainderTy)
985 const bool isPointerTy = DstVS->VecTy->getElementType()->isPointerTy();
991 Scatterer Op0 = scatter(&BCI, BCI.
getOperand(0), *SrcVS);
993 Res.
resize(DstVS->NumFragments);
995 unsigned DstSplitBits = DstVS->SplitTy->getPrimitiveSizeInBits();
996 unsigned SrcSplitBits = SrcVS->SplitTy->getPrimitiveSizeInBits();
999 assert(DstVS->NumFragments == SrcVS->NumFragments);
1000 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1001 Res[
I] = Builder.CreateBitCast(Op0[
I], DstVS->getFragmentType(
I),
1004 }
else if (SrcSplitBits % DstSplitBits == 0) {
1008 MidVS.NumPacked = DstVS->NumPacked;
1009 MidVS.NumFragments = SrcSplitBits / DstSplitBits;
1011 MidVS.NumPacked * MidVS.NumFragments);
1012 MidVS.SplitTy = DstVS->SplitTy;
1015 for (
unsigned I = 0;
I < SrcVS->NumFragments; ++
I) {
1022 VI->getOpcode() == Instruction::BitCast)
1023 V =
VI->getOperand(0);
1025 V = Builder.CreateBitCast(V, MidVS.VecTy,
V->getName() +
".cast");
1027 Scatterer Mid = scatter(&BCI, V, MidVS);
1028 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1029 Res[ResI++] = Mid[J];
1031 }
else if (DstSplitBits % SrcSplitBits == 0) {
1035 MidVS.NumFragments = DstSplitBits / SrcSplitBits;
1036 MidVS.NumPacked = SrcVS->NumPacked;
1038 MidVS.NumPacked * MidVS.NumFragments);
1039 MidVS.SplitTy = SrcVS->SplitTy;
1042 SmallVector<Value *, 8> ConcatOps;
1043 ConcatOps.
resize(MidVS.NumFragments);
1044 for (
unsigned I = 0;
I < DstVS->NumFragments; ++
I) {
1045 for (
unsigned J = 0; J < MidVS.NumFragments; ++J)
1046 ConcatOps[J] = Op0[SrcI++];
1049 Res[
I] = Builder.CreateBitCast(V, DstVS->getFragmentType(
I),
1056 gather(&BCI, Res, *DstVS);
1060bool ScalarizerVisitor::visitInsertElementInst(InsertElementInst &IEI) {
1061 std::optional<VectorSplit>
VS = getVectorSplit(IEI.
getType());
1066 Scatterer Op0 = scatter(&IEI, IEI.
getOperand(0), *VS);
1074 unsigned Idx = CI->getZExtValue();
1076 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1079 if (
Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1080 !
VS->RemainderTy->isVectorTy())
1084 Builder.CreateInsertElement(Op0[
I], NewElt, Idx %
VS->NumPacked);
1094 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1097 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1098 Value *ShouldReplace =
1099 Builder.CreateICmpEQ(InsIdx, ConstantInt::get(InsIdx->
getType(),
I),
1100 InsIdx->
getName() +
".is." + Twine(
I));
1102 Res[
I] = Builder.CreateSelect(ShouldReplace, NewElt, OldElt,
1107 gather(&IEI, Res, *VS);
1111bool ScalarizerVisitor::visitExtractValueInst(ExtractValueInst &EVI) {
1113 Type *OpTy =
Op->getType();
1129 std::optional<VectorSplit>
VS = getVectorSplit(VecType);
1133 std::optional<VectorSplit> CurrVS =
1141 if (!CurrVS || CurrVS->NumPacked !=
VS->NumPacked)
1145 Scatterer Op0 = scatter(&EVI,
Op, *VS);
1149 for (
unsigned OpIdx = 0; OpIdx < Op0.size(); ++OpIdx) {
1150 Value *ResElem = Builder.CreateExtractValue(
1151 Op0[OpIdx], Index, EVI.
getName() +
".elem" + Twine(Index));
1156 std::optional<VectorSplit> AVS = getVectorSplit(ActualVecType);
1157 gather(&EVI, Res, *AVS);
1161bool ScalarizerVisitor::visitExtractElementInst(ExtractElementInst &EEI) {
1167 Scatterer Op0 = scatter(&EEI, EEI.
getOperand(0), *VS);
1171 unsigned Idx = CI->getZExtValue();
1172 if (Idx >=
VS->VecTy->getNumElements())
1177 if (
Fragment ==
VS->NumFragments - 1 &&
VS->RemainderTy &&
1178 !
VS->RemainderTy->isVectorTy())
1181 Res = Builder.CreateExtractElement(Res, Idx %
VS->NumPacked);
1182 replaceUses(&EEI, Res);
1187 if (!ScalarizeVariableInsertExtract ||
VS->NumPacked > 1)
1191 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1192 Value *ShouldExtract =
1193 Builder.CreateICmpEQ(ExtIdx, ConstantInt::get(ExtIdx->
getType(),
I),
1194 ExtIdx->
getName() +
".is." + Twine(
I));
1196 Res = Builder.CreateSelect(ShouldExtract, Elt, Res,
1197 EEI.
getName() +
".upto" + Twine(
I));
1199 replaceUses(&EEI, Res);
1203bool ScalarizerVisitor::visitShuffleVectorInst(ShuffleVectorInst &SVI) {
1204 std::optional<VectorSplit>
VS = getVectorSplit(SVI.
getType());
1205 std::optional<VectorSplit> VSOp =
1207 if (!VS || !VSOp ||
VS->NumPacked > 1 || VSOp->NumPacked > 1)
1210 Scatterer Op0 = scatter(&SVI, SVI.
getOperand(0), *VSOp);
1211 Scatterer Op1 = scatter(&SVI, SVI.
getOperand(1), *VSOp);
1215 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1219 else if (
unsigned(Selector) < Op0.size())
1220 Res[
I] = Op0[Selector];
1222 Res[
I] = Op1[Selector - Op0.size()];
1224 gather(&SVI, Res, *VS);
1228bool ScalarizerVisitor::visitPHINode(PHINode &
PHI) {
1229 std::optional<VectorSplit>
VS = getVectorSplit(
PHI.getType());
1238 for (
unsigned I = 0;
I <
VS->NumFragments; ++
I) {
1239 Res[
I] = Builder.CreatePHI(
VS->getFragmentType(
I),
NumOps,
1240 PHI.getName() +
".i" + Twine(
I));
1244 Scatterer
Op = scatter(&
PHI,
PHI.getIncomingValue(
I), *VS);
1246 for (
unsigned J = 0; J <
VS->NumFragments; ++J)
1249 gather(&
PHI, Res, *VS);
1253bool ScalarizerVisitor::visitLoadInst(LoadInst &LI) {
1254 if (!ScalarizeLoadStore)
1259 std::optional<VectorLayout> Layout = getVectorLayout(
1267 Res.
resize(Layout->VS.NumFragments);
1269 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1270 Res[
I] = Builder.CreateAlignedLoad(Layout->VS.getFragmentType(
I), Ptr[
I],
1271 Align(Layout->getFragmentAlign(
I)),
1274 gather(&LI, Res, Layout->VS);
1278bool ScalarizerVisitor::visitStoreInst(StoreInst &SI) {
1279 if (!ScalarizeLoadStore)
1284 Value *FullValue =
SI.getValueOperand();
1285 std::optional<VectorLayout> Layout = getVectorLayout(
1286 FullValue->
getType(),
SI.getAlign(),
SI.getDataLayout());
1291 Scatterer VPtr = scatter(&SI,
SI.getPointerOperand(), Layout->VS);
1292 Scatterer VVal = scatter(&SI, FullValue, Layout->VS);
1295 Stores.
resize(Layout->VS.NumFragments);
1296 for (
unsigned I = 0;
I < Layout->VS.NumFragments; ++
I) {
1300 Builder.CreateAlignedStore(Val, Ptr, Layout->getFragmentAlign(
I));
1302 transferMetadataAndIRFlags(&SI, Stores);
1306bool ScalarizerVisitor::visitCallInst(CallInst &CI) {
1307 return splitCall(CI);
1310bool ScalarizerVisitor::visitFreezeInst(FreezeInst &FI) {
1318bool ScalarizerVisitor::finish() {
1321 if (Gathered.
empty() && Scattered.empty() && !Scalarized)
1323 for (
const auto &GMI : Gathered) {
1326 if (!
Op->use_empty()) {
1336 VectorSplit
VS = *getVectorSplit(Ty);
1349 unsigned NumOfStructElements = Ty->getNumElements();
1351 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1352 for (
auto *CVelem : CV) {
1354 CVelem,
I,
Op->getName() +
".elem" + Twine(
I));
1355 ElemCV[
I].push_back(Elem);
1359 for (
unsigned I = 0;
I < NumOfStructElements; ++
I) {
1360 Type *ElemTy = Ty->getElementType(
I);
1362 "Only Structs of all FixedVectorType supported");
1363 VectorSplit
VS = *getVectorSplit(ElemTy);
1364 assert(
VS.NumFragments == CV.size());
1366 Value *ConcatenatedVector =
1369 Op->getName() +
".insert");
1372 assert(CV.size() == 1 &&
Op->getType() == CV[0]->getType());
1377 Op->replaceAllUsesWith(Res);
1379 PotentiallyDeadInstrs.emplace_back(
Op);
1393 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.