32#include "llvm/IR/IntrinsicsHexagon.h"
54#define DEBUG_TYPE "hexagon-vc"
59class HexagonVectorCombine {
64 :
F(F_),
DL(
F.getParent()->getDataLayout()), AA(AA_), AC(AC_), DT(DT_),
74 Type *getByteTy(
int ElemCount = 0)
const;
77 Type *getBoolTy(
int ElemCount = 0)
const;
81 std::optional<APInt> getIntValue(
const Value *Val)
const;
94 int getSizeOf(
const Value *Val, SizeKind Kind = Store)
const;
95 int getSizeOf(
const Type *Ty, SizeKind Kind = Store)
const;
96 int getTypeAlignment(
Type *Ty)
const;
97 size_t length(
Value *Val)
const;
98 size_t length(
Type *Ty)
const;
107 int Length,
int Where)
const;
130 unsigned ToWidth)
const;
134 std::optional<int> calculatePointerDifference(
Value *Ptr0,
Value *Ptr1)
const;
136 unsigned getNumSignificantBits(
const Value *V,
141 template <
typename T = std::vector<Instruction *>>
144 const T &IgnoreInsts = {})
const;
147 [[maybe_unused]]
bool isByteVecTy(
Type *Ty)
const;
159 int Start,
int Length)
const;
164 AlignVectors(
const HexagonVectorCombine &HVC_) : HVC(HVC_) {}
169 using InstList = std::vector<Instruction *>;
178 AddrInfo(
const AddrInfo &) =
default;
181 : Inst(
I),
Addr(
A), ValTy(
T), HaveAlign(
H),
182 NeedAlign(HVC.getTypeAlignment(ValTy)) {}
183 AddrInfo &operator=(
const AddrInfo &) =
default;
194 using AddrList = std::vector<AddrInfo>;
198 return A->comesBefore(
B);
201 using DepList = std::set<Instruction *, InstrLess>;
204 MoveGroup(
const AddrInfo &AI,
Instruction *
B,
bool Hvx,
bool Load)
205 :
Base(
B), Main{AI.Inst}, IsHvx(Hvx), IsLoad(Load) {}
212 using MoveList = std::vector<MoveGroup>;
217 Segment(
Value *Val,
int Begin,
int Len)
218 : Val(Val), Start(Begin), Size(Len) {}
219 Segment(
const Segment &Seg) =
default;
220 Segment &operator=(
const Segment &Seg) =
default;
227 Block(
Value *Val,
int Len,
int Pos) : Seg(Val, 0, Len), Pos(Pos) {}
228 Block(
Value *Val,
int Off,
int Len,
int Pos)
229 : Seg(Val, Off, Len), Pos(Pos) {}
230 Block(
const Block &Blk) =
default;
231 Block &operator=(
const Block &Blk) =
default;
237 ByteSpan section(
int Start,
int Length)
const;
238 ByteSpan &shift(
int Offset);
241 int size()
const {
return Blocks.size(); }
242 Block &operator[](
int i) {
return Blocks[i]; }
244 std::vector<Block> Blocks;
246 using iterator =
decltype(Blocks)::iterator;
247 iterator begin() {
return Blocks.
begin(); }
248 iterator end() {
return Blocks.
end(); }
254 Align getAlignFromValue(
const Value *V)
const;
256 std::optional<AddrInfo> getAddrInfo(
Instruction &In)
const;
257 bool isHvx(
const AddrInfo &AI)
const;
259 [[maybe_unused]]
bool isSectorTy(
Type *Ty)
const;
268 int Alignment)
const;
270 int Alignment,
Value *Mask,
Value *PassThru)
const;
272 int Alignment,
Value *Mask)
const;
275 bool createAddressGroups();
276 MoveList createLoadGroups(
const AddrList &Group)
const;
277 MoveList createStoreGroups(
const AddrList &Group)
const;
278 bool move(
const MoveGroup &Move)
const;
280 int ScLen,
Value *AlignVal,
Value *AlignAddr)
const;
282 int ScLen,
Value *AlignVal,
Value *AlignAddr)
const;
283 bool realignGroup(
const MoveGroup &Move)
const;
290 std::map<Instruction *, AddrList> AddrGroups;
291 const HexagonVectorCombine &HVC;
296 OS <<
"Inst: " << AI.Inst <<
" " << *AI.Inst <<
'\n';
297 OS <<
"Addr: " << *AI.Addr <<
'\n';
298 OS <<
"Type: " << *AI.ValTy <<
'\n';
299 OS <<
"HaveAlign: " << AI.HaveAlign.value() <<
'\n';
300 OS <<
"NeedAlign: " << AI.NeedAlign.value() <<
'\n';
301 OS <<
"Offset: " << AI.Offset;
307 OS <<
"IsLoad:" << (MG.IsLoad ?
"yes" :
"no");
308 OS <<
", IsHvx:" << (MG.IsHvx ?
"yes" :
"no") <<
'\n';
311 OS <<
" " << *
I <<
'\n';
314 OS <<
" " << *
I <<
'\n';
320 const AlignVectors::ByteSpan::Block &
B) {
321 OS <<
" @" <<
B.Pos <<
" [" <<
B.Seg.Start <<
',' <<
B.Seg.Size <<
"] ";
322 if (
B.Seg.Val ==
reinterpret_cast<const Value *
>(&
B)) {
323 OS <<
"(self:" <<
B.Seg.Val <<
')';
324 }
else if (
B.Seg.Val !=
nullptr) {
334 OS <<
"ByteSpan[size=" << BS.size() <<
", extent=" << BS.extent() <<
'\n';
335 for (
const AlignVectors::ByteSpan::Block &
B : BS)
343 HvxIdioms(
const HexagonVectorCombine &HVC_) : HVC(HVC_) {
344 auto *
Int32Ty = HVC.getIntTy(32);
345 HvxI32Ty = HVC.getHvxTy(
Int32Ty,
false);
346 HvxP32Ty = HVC.getHvxTy(
Int32Ty,
true);
352 enum Signedness { Positive, Signed, Unsigned };
367 std::optional<unsigned> RoundAt;
372 -> std::pair<unsigned, Signedness>;
373 auto canonSgn(SValue
X, SValue
Y)
const -> std::pair<SValue, SValue>;
375 auto matchFxpMul(
Instruction &In)
const -> std::optional<FxpOp>;
379 const FxpOp &Op)
const ->
Value *;
381 bool Rounding)
const ->
Value *;
383 bool Rounding)
const ->
Value *;
386 Value *CarryIn =
nullptr)
const
387 -> std::pair<Value *, Value *>;
392 -> std::pair<Value *, Value *>;
401 const HexagonVectorCombine &HVC;
407 const HvxIdioms::FxpOp &Op) {
408 static const char *SgnNames[] = {
"Positive",
"Signed",
"Unsigned"};
410 if (Op.RoundAt.has_value()) {
411 if (Op.Frac != 0 && *Op.RoundAt == Op.Frac - 1) {
414 OS <<
" + 1<<" << *Op.RoundAt;
417 OS <<
"\n X:(" << SgnNames[Op.X.Sgn] <<
") " << *Op.X.Val <<
"\n"
418 <<
" Y:(" << SgnNames[Op.Y.Sgn] <<
") " << *Op.Y.Val;
426template <
typename T>
T *getIfUnordered(
T *MaybeT) {
427 return MaybeT && MaybeT->isUnordered() ? MaybeT :
nullptr;
430 return dyn_cast<T>(In);
433 return getIfUnordered(dyn_cast<LoadInst>(In));
436 return getIfUnordered(dyn_cast<StoreInst>(In));
439#if !defined(_MSC_VER) || _MSC_VER >= 1926
443template <
typename Pred,
typename... Ts>
444void erase_if(std::map<Ts...> &map, Pred p)
446template <
typename Pred,
typename T,
typename U>
447void erase_if(std::map<T, U> &map, Pred p)
450 for (
auto i = map.begin(), e = map.end(); i != e;) {
459template <
typename Pred,
typename T>
void erase_if(
T &&container, Pred p) {
467auto AlignVectors::ByteSpan::extent()
const ->
int {
470 int Min = Blocks[0].Pos;
471 int Max = Blocks[0].Pos + Blocks[0].Seg.Size;
472 for (
int i = 1, e =
size(); i !=
e; ++i) {
473 Min = std::min(Min, Blocks[i].Pos);
474 Max = std::max(Max, Blocks[i].Pos + Blocks[i].Seg.Size);
479auto AlignVectors::ByteSpan::section(
int Start,
int Length)
const -> ByteSpan {
481 for (
const ByteSpan::Block &
B : Blocks) {
482 int L = std::max(
B.Pos, Start);
483 int R = std::min(
B.Pos +
B.Seg.Size, Start +
Length);
486 int Off =
L >
B.Pos ?
L -
B.Pos : 0;
487 Section.Blocks.emplace_back(
B.Seg.Val,
B.Seg.Start + Off, R - L, L);
493auto AlignVectors::ByteSpan::shift(
int Offset) -> ByteSpan & {
494 for (Block &
B : Blocks)
501 for (
int i = 0, e = Blocks.size(); i != e; ++i)
502 Values[i] = Blocks[i].Seg.Val;
506auto AlignVectors::getAlignFromValue(
const Value *V)
const ->
Align {
507 const auto *
C = dyn_cast<ConstantInt>(V);
508 assert(
C &&
"Alignment must be a compile-time constant integer");
509 return C->getAlignValue();
512auto AlignVectors::getAddrInfo(
Instruction &In)
const
513 -> std::optional<AddrInfo> {
514 if (
auto *L = isCandidate<LoadInst>(&In))
515 return AddrInfo(HVC, L,
L->getPointerOperand(),
L->getType(),
517 if (
auto *S = isCandidate<StoreInst>(&In))
518 return AddrInfo(HVC, S, S->getPointerOperand(),
519 S->getValueOperand()->getType(), S->getAlign());
520 if (
auto *II = isCandidate<IntrinsicInst>(&In)) {
523 case Intrinsic::masked_load:
524 return AddrInfo(HVC, II, II->getArgOperand(0), II->getType(),
525 getAlignFromValue(II->getArgOperand(1)));
526 case Intrinsic::masked_store:
527 return AddrInfo(HVC, II, II->getArgOperand(1),
528 II->getArgOperand(0)->getType(),
529 getAlignFromValue(II->getArgOperand(2)));
535auto AlignVectors::isHvx(
const AddrInfo &AI)
const ->
bool {
536 return HVC.HST.isTypeForHVX(AI.ValTy);
539auto AlignVectors::getPayload(
Value *Val)
const ->
Value * {
540 if (
auto *In = dyn_cast<Instruction>(Val)) {
542 if (
auto *II = dyn_cast<IntrinsicInst>(In))
543 ID = II->getIntrinsicID();
544 if (isa<StoreInst>(In) ||
ID == Intrinsic::masked_store)
545 return In->getOperand(0);
550auto AlignVectors::getMask(
Value *Val)
const ->
Value * {
551 if (
auto *II = dyn_cast<IntrinsicInst>(Val)) {
552 switch (II->getIntrinsicID()) {
553 case Intrinsic::masked_load:
554 return II->getArgOperand(2);
555 case Intrinsic::masked_store:
556 return II->getArgOperand(3);
560 Type *ValTy = getPayload(Val)->getType();
561 if (
auto *VecTy = dyn_cast<VectorType>(ValTy))
562 return HVC.getFullValue(HVC.getBoolTy(HVC.length(VecTy)));
563 return HVC.getFullValue(HVC.getBoolTy());
566auto AlignVectors::getPassThrough(
Value *Val)
const ->
Value * {
567 if (
auto *II = dyn_cast<IntrinsicInst>(Val)) {
568 if (II->getIntrinsicID() == Intrinsic::masked_load)
569 return II->getArgOperand(3);
575 Type *ValTy,
int Adjust)
const
579 auto *PtrTy = cast<PointerType>(
Ptr->getType());
580 if (!PtrTy->isOpaque()) {
582 int ElemSize = HVC.getSizeOf(ElemTy, HVC.Alloc);
583 if (Adjust % ElemSize == 0 && Adjust != 0) {
585 ElemTy,
Ptr, HVC.getConstInt(Adjust / ElemSize),
"gep");
593 HVC.getConstInt(Adjust),
"gep");
598 Type *ValTy,
int Alignment)
const
601 Value *
Mask = HVC.getConstInt(-Alignment);
609 assert(!HVC.isUndef(Mask));
610 if (HVC.isZero(Mask))
614 return Builder.CreateMaskedLoad(ValTy,
Ptr,
Align(Alignment), Mask, PassThru,
621 if (HVC.isZero(Mask) || HVC.isUndef(Val) || HVC.isUndef(Mask))
632 "Base and In should be in the same block");
633 assert(
Base->comesBefore(In) &&
"Base should come before In");
636 std::deque<Instruction *> WorkQ = {
In};
637 while (!WorkQ.empty()) {
641 for (
Value *Op :
D->operands()) {
642 if (
auto *
I = dyn_cast<Instruction>(Op)) {
643 if (
I->getParent() == Parent &&
Base->comesBefore(
I))
651auto AlignVectors::createAddressGroups() ->
bool {
656 auto findBaseAndOffset = [&](AddrInfo &AI) -> std::pair<Instruction *, int> {
657 for (AddrInfo &W : WorkStack) {
658 if (
auto D = HVC.calculatePointerDifference(AI.Addr,
W.Addr))
659 return std::make_pair(
W.Inst, *
D);
661 return std::make_pair(
nullptr, 0);
664 auto traverseBlock = [&](
DomTreeNode *DomN,
auto Visit) ->
void {
667 auto AI = this->getAddrInfo(
I);
670 auto F = findBaseAndOffset(*AI);
673 AI->Offset =
F.second;
676 WorkStack.push_back(*AI);
677 GroupInst = AI->Inst;
679 AddrGroups[GroupInst].push_back(*AI);
685 while (!WorkStack.empty() && WorkStack.back().Inst->getParent() == &Block)
686 WorkStack.pop_back();
689 traverseBlock(HVC.DT.getRootNode(), traverseBlock);
690 assert(WorkStack.empty());
695 erase_if(AddrGroups, [](
auto &
G) {
return G.second.size() == 1; });
699 G.second, [&](
auto &
I) { return HVC.HST.isTypeForHVX(I.ValTy); });
702 return !AddrGroups.empty();
705auto AlignVectors::createLoadGroups(
const AddrList &Group)
const -> MoveList {
710 auto tryAddTo = [&](
const AddrInfo &
Info, MoveGroup &Move) {
711 assert(!Move.Main.empty() &&
"Move group should have non-empty Main");
713 if (Move.IsHvx != isHvx(Info))
717 if (
Base->getParent() !=
Info.Inst->getParent())
721 return HVC.isSafeToMoveBeforeInBB(*
I,
Base->getIterator());
723 DepList Deps = getUpwardDeps(
Info.Inst,
Base);
729 Deps.erase(
Info.Inst);
730 auto inAddrMap = [&](
Instruction *
I) {
return AddrGroups.count(
I) > 0; };
733 Move.Main.push_back(
Info.Inst);
740 for (
const AddrInfo &Info : Group) {
741 if (!
Info.Inst->mayReadFromMemory())
743 if (LoadGroups.empty() || !tryAddTo(Info, LoadGroups.back()))
744 LoadGroups.emplace_back(Info, Group.front().Inst, isHvx(Info),
true);
748 erase_if(LoadGroups, [](
const MoveGroup &
G) {
return G.Main.size() <= 1; });
752auto AlignVectors::createStoreGroups(
const AddrList &Group)
const -> MoveList {
757 auto tryAddTo = [&](
const AddrInfo &
Info, MoveGroup &Move) {
758 assert(!Move.Main.empty() &&
"Move group should have non-empty Main");
762 "Not handling stores with return values");
764 if (Move.IsHvx != isHvx(Info))
770 if (
Base->getParent() !=
Info.Inst->getParent())
772 if (!HVC.isSafeToMoveBeforeInBB(*
Info.Inst,
Base->getIterator(), Move.Main))
774 Move.Main.push_back(
Info.Inst);
778 MoveList StoreGroups;
780 for (
auto I = Group.rbegin(),
E = Group.rend();
I !=
E; ++
I) {
781 const AddrInfo &
Info = *
I;
782 if (!
Info.Inst->mayWriteToMemory())
784 if (StoreGroups.empty() || !tryAddTo(Info, StoreGroups.back()))
785 StoreGroups.emplace_back(Info, Group.front().Inst, isHvx(Info),
false);
789 erase_if(StoreGroups, [](
const MoveGroup &
G) {
return G.Main.size() <= 1; });
793auto AlignVectors::move(
const MoveGroup &Move)
const ->
bool {
794 assert(!Move.Main.empty() &&
"Move group should have non-empty Main");
800 D->moveBefore(Where);
810 assert(Move.Deps.empty());
814 M->moveBefore(Where);
819 return Move.Main.size() + Move.Deps.size() > 1;
823 const ByteSpan &VSpan,
int ScLen,
828 Type *SecTy = HVC.getByteTy(ScLen);
829 int NumSectors = (VSpan.extent() + ScLen - 1) / ScLen;
830 bool DoAlign = !HVC.isZero(AlignVal);
835 auto *True = HVC.getFullValue(HVC.getBoolTy(ScLen));
858 ASpan.Blocks.emplace_back(
nullptr, ScLen,
Index * ScLen);
860 ASpan.Blocks[
Index].Seg.Val =
861 reinterpret_cast<Value *
>(&ASpan.Blocks[
Index]);
873 assert(
A->getParent() ==
B->getParent());
874 return A->comesBefore(
B);
876 auto earliestUser = [&](
const auto &
Uses) {
879 auto *
I = dyn_cast<Instruction>(
U.getUser());
880 assert(
I !=
nullptr &&
"Load used in a non-instruction?");
884 if (
I->getParent() == BaseBlock) {
885 if (!isa<PHINode>(
I))
894 for (
const ByteSpan::Block &
B : VSpan) {
895 ByteSpan ASection = ASpan.section(
B.Pos,
B.Seg.Size);
896 for (
const ByteSpan::Block &S : ASection) {
897 EarliestUser[S.Seg.Val] = std::min(
898 EarliestUser[S.Seg.Val], earliestUser(
B.Seg.Val->uses()), isEarlier);
903 dbgs() <<
"ASpan:\n" << ASpan <<
'\n';
904 dbgs() <<
"Earliest users of ASpan:\n";
905 for (
auto &[Val,
User] : EarliestUser) {
906 dbgs() << Val <<
"\n ->" << *
User <<
'\n';
913 createAdjustedPointer(Builder, AlignAddr, SecTy,
Index * ScLen);
915 Value *
Load = createAlignedLoad(Builder, SecTy,
Ptr, ScLen, True, Undef);
918 int Start = (
Index - DoAlign) * ScLen;
919 int Width = (1 + DoAlign) * ScLen;
921 VSpan.section(Start, Width).values());
922 return cast<Instruction>(Load);
927 assert(
In->getParent() == To->getParent());
928 DepList Deps = getUpwardDeps(In, To);
944 DoAlign &&
Index > 0 ? EarliestUser[&ASpan[
Index - 1]] :
nullptr;
946 Index < NumSectors ? EarliestUser[&ASpan[
Index]] :
nullptr;
947 if (
auto *Where = std::min(PrevAt, ThisAt, isEarlier)) {
949 Loads[
Index] = createLoad(Builder, VSpan,
Index);
956 if (!HVC.isSafeToMoveBeforeInBB(*Loads[
Index], BasePos))
957 moveBefore(Loads[
Index], &*BasePos);
965 ASpan[
Index].Seg.Val =
nullptr;
966 if (
auto *Where = EarliestUser[&ASpan[
Index]]) {
972 assert(NextLoad !=
nullptr);
973 Val = HVC.vralignb(Builder, Val, NextLoad, AlignVal);
975 ASpan[
Index].Seg.Val = Val;
980 for (
const ByteSpan::Block &
B : VSpan) {
981 ByteSpan ASection = ASpan.section(
B.Pos,
B.Seg.Size).shift(-
B.Pos);
983 Builder.SetInsertPoint(cast<Instruction>(
B.Seg.Val));
988 std::vector<ByteSpan::Block *> ABlocks;
989 for (ByteSpan::Block &S : ASection) {
990 if (S.Seg.Val !=
nullptr)
991 ABlocks.push_back(&S);
994 [&](
const ByteSpan::Block *
A,
const ByteSpan::Block *
B) {
995 return isEarlier(cast<Instruction>(
A->Seg.Val),
996 cast<Instruction>(
B->Seg.Val));
998 for (ByteSpan::Block *S : ABlocks) {
1001 Instruction *SegI = cast<Instruction>(S->Seg.Val);
1003 Value *Pay = HVC.vbytes(Builder, getPayload(S->Seg.Val));
1005 HVC.insertb(Builder, Accum, Pay, S->Seg.Start, S->Seg.Size, S->Pos);
1013 Type *ValTy = getPayload(
B.Seg.Val)->getType();
1014 Value *Cast =
Builder.CreateBitCast(Accum, ValTy,
"cst");
1016 getPassThrough(
B.Seg.Val),
"sel");
1017 B.Seg.Val->replaceAllUsesWith(Sel);
1022 const ByteSpan &VSpan,
int ScLen,
1027 Type *SecTy = HVC.getByteTy(ScLen);
1028 int NumSectors = (VSpan.extent() + ScLen - 1) / ScLen;
1029 bool DoAlign = !HVC.isZero(AlignVal);
1032 ByteSpan ASpanV, ASpanM;
1040 auto *VecTy = VectorType::get(Ty, 1,
false);
1041 return Builder.CreateBitCast(Val, VecTy,
"cst");
1046 for (
int i = (DoAlign ? -1 : 0); i != NumSectors + DoAlign; ++i) {
1049 ByteSpan VSection = VSpan.section(i * ScLen, ScLen).shift(-i * ScLen);
1051 Value *AccumM = HVC.getNullValue(SecTy);
1052 for (ByteSpan::Block &S : VSection) {
1053 Value *Pay = getPayload(S.Seg.Val);
1054 Value *
Mask = HVC.rescale(Builder, MakeVec(Builder, getMask(S.Seg.Val)),
1055 Pay->
getType(), HVC.getByteTy());
1056 AccumM = HVC.insertb(Builder, AccumM, HVC.vbytes(Builder, Mask),
1057 S.Seg.Start, S.Seg.Size, S.Pos);
1058 AccumV = HVC.insertb(Builder, AccumV, HVC.vbytes(Builder, Pay),
1059 S.Seg.Start, S.Seg.Size, S.Pos);
1061 ASpanV.Blocks.emplace_back(AccumV, ScLen, i * ScLen);
1062 ASpanM.Blocks.emplace_back(AccumM, ScLen, i * ScLen);
1067 for (
int j = 1;
j != NumSectors + 2; ++
j) {
1068 Value *PrevV = ASpanV[
j - 1].Seg.Val, *ThisV = ASpanV[
j].Seg.Val;
1069 Value *PrevM = ASpanM[
j - 1].Seg.Val, *ThisM = ASpanM[
j].Seg.Val;
1071 ASpanV[
j - 1].Seg.Val = HVC.vlalignb(Builder, PrevV, ThisV, AlignVal);
1072 ASpanM[
j - 1].Seg.Val = HVC.vlalignb(Builder, PrevM, ThisM, AlignVal);
1076 for (
int i = 0; i != NumSectors + DoAlign; ++i) {
1077 Value *
Ptr = createAdjustedPointer(Builder, AlignAddr, SecTy, i * ScLen);
1078 Value *Val = ASpanV[i].Seg.Val;
1080 if (!HVC.isUndef(Val) && !HVC.isZero(Mask)) {
1082 createAlignedStore(Builder, Val,
Ptr, ScLen, HVC.vlsb(Builder, Mask));
1085 int Start = (i - DoAlign) * ScLen;
1086 int Width = (1 + DoAlign) * ScLen;
1088 VSpan.section(Start, Width).values());
1093auto AlignVectors::realignGroup(
const MoveGroup &Move)
const ->
bool {
1102 auto getMaxOf = [](
auto Range,
auto GetValue) {
1103 return *std::max_element(
1105 [&GetValue](
auto &
A,
auto &
B) { return GetValue(A) < GetValue(B); });
1108 const AddrList &BaseInfos = AddrGroups.at(Move.Base);
1123 std::set<Instruction *> TestSet(Move.Main.begin(), Move.Main.end());
1126 BaseInfos, std::back_inserter(MoveInfos),
1127 [&TestSet](
const AddrInfo &AI) {
return TestSet.count(AI.Inst); });
1130 const AddrInfo &WithMaxAlign =
1131 getMaxOf(MoveInfos, [](
const AddrInfo &AI) {
return AI.HaveAlign; });
1132 Align MaxGiven = WithMaxAlign.HaveAlign;
1135 const AddrInfo &WithMinOffset =
1136 getMaxOf(MoveInfos, [](
const AddrInfo &AI) {
return -AI.Offset; });
1138 const AddrInfo &WithMaxNeeded =
1139 getMaxOf(MoveInfos, [](
const AddrInfo &AI) {
return AI.NeedAlign; });
1140 Align MinNeeded = WithMaxNeeded.NeedAlign;
1154 Value *AlignAddr =
nullptr;
1155 Value *AlignVal =
nullptr;
1157 if (MinNeeded <= MaxGiven) {
1158 int Start = WithMinOffset.Offset;
1159 int OffAtMax = WithMaxAlign.Offset;
1166 int Adjust = -
alignTo(OffAtMax - Start, MinNeeded.value());
1167 AlignAddr = createAdjustedPointer(Builder, WithMaxAlign.Addr,
1168 WithMaxAlign.ValTy, Adjust);
1169 int Diff = Start - (OffAtMax + Adjust);
1170 AlignVal = HVC.getConstInt(Diff);
1172 assert(
static_cast<decltype(MinNeeded.
value())
>(Diff) < MinNeeded.value());
1181 AlignAddr = createAlignedPointer(Builder, WithMinOffset.Addr,
1182 WithMinOffset.ValTy, MinNeeded.value());
1184 Builder.CreatePtrToInt(WithMinOffset.Addr, HVC.getIntTy(),
"pti");
1188 for (
const AddrInfo &AI : MoveInfos) {
1189 VSpan.Blocks.emplace_back(AI.Inst, HVC.getSizeOf(AI.ValTy),
1190 AI.Offset - WithMinOffset.Offset);
1196 int ScLen = Move.IsHvx ? HVC.HST.getVectorLength()
1197 : std::max<int>(MinNeeded.value(), 4);
1198 assert(!Move.IsHvx || ScLen == 64 || ScLen == 128);
1199 assert(Move.IsHvx || ScLen == 4 || ScLen == 8);
1202 dbgs() <<
"ScLen: " << ScLen <<
"\n";
1203 dbgs() <<
"AlignVal:" << *AlignVal <<
"\n";
1204 dbgs() <<
"AlignAddr:" << *AlignAddr <<
"\n";
1205 dbgs() <<
"VSpan:\n" << VSpan <<
'\n';
1209 realignLoadGroup(Builder, VSpan, ScLen, AlignVal, AlignAddr);
1211 realignStoreGroup(Builder, VSpan, ScLen, AlignVal, AlignAddr);
1213 for (
auto *Inst : Move.Main)
1214 Inst->eraseFromParent();
1219auto AlignVectors::isSectorTy(
Type *Ty)
const ->
bool {
1220 if (!HVC.isByteVecTy(Ty))
1222 int Size = HVC.getSizeOf(Ty);
1223 if (HVC.HST.isTypeForHVX(Ty))
1224 return Size ==
static_cast<int>(HVC.HST.getVectorLength());
1228auto AlignVectors::run() ->
bool {
1230 if (!createAddressGroups())
1234 dbgs() <<
"Address groups(" << AddrGroups.size() <<
"):\n";
1235 for (
auto &[In, AL] : AddrGroups) {
1236 for (
const AddrInfo &AI : AL)
1237 dbgs() <<
"---\n" << AI <<
'\n';
1241 bool Changed =
false;
1242 MoveList LoadGroups, StoreGroups;
1244 for (
auto &
G : AddrGroups) {
1250 dbgs() <<
"\nLoad groups(" << LoadGroups.size() <<
"):\n";
1251 for (
const MoveGroup &
G : LoadGroups)
1252 dbgs() <<
G <<
"\n";
1253 dbgs() <<
"Store groups(" << StoreGroups.size() <<
"):\n";
1254 for (
const MoveGroup &
G : StoreGroups)
1255 dbgs() <<
G <<
"\n";
1258 for (
auto &M : LoadGroups)
1260 for (
auto &M : StoreGroups)
1265 for (
auto &M : LoadGroups)
1266 Changed |= realignGroup(M);
1267 for (
auto &M : StoreGroups)
1268 Changed |= realignGroup(M);
1278 -> std::pair<unsigned, Signedness> {
1279 unsigned Bits = HVC.getNumSignificantBits(V, In);
1285 KnownBits Known = HVC.getKnownBits(V, In);
1286 Signedness Sign =
Signed;
1287 unsigned NumToTest = 0;
1291 NumToTest =
Bits - 1;
1304 return {
Bits, Sign};
1307auto HvxIdioms::canonSgn(SValue
X, SValue
Y)
const
1308 -> std::pair<SValue, SValue> {
1321auto HvxIdioms::matchFxpMul(
Instruction &In)
const -> std::optional<FxpOp> {
1322 using namespace PatternMatch;
1323 auto *Ty =
In.getType();
1326 return std::nullopt;
1335 auto m_Shr = [](
auto &&
V,
auto &&S) {
1339 const APInt *Qn =
nullptr;
1347 if (
Op.Frac > Width)
1348 return std::nullopt;
1351 const APInt *
C =
nullptr;
1355 return std::nullopt;
1363 Op.Opcode = Instruction::Mul;
1365 Op.X.Sgn = getNumSignificantBits(
Op.X.Val, &In).second;
1366 Op.Y.Sgn = getNumSignificantBits(
Op.Y.Val, &In).second;
1367 Op.ResTy = cast<VectorType>(Ty);
1371 return std::nullopt;
1374auto HvxIdioms::processFxpMul(
Instruction &In,
const FxpOp &Op)
const
1376 assert(
Op.X.Val->getType() ==
Op.Y.Val->getType());
1378 auto *VecTy = dyn_cast<VectorType>(
Op.X.Val->getType());
1379 if (VecTy ==
nullptr)
1381 auto *ElemTy = cast<IntegerType>(VecTy->getElementType());
1382 unsigned ElemWidth = ElemTy->getBitWidth();
1385 if ((HVC.length(VecTy) * ElemWidth) % (8 * HVC.HST.getVectorLength()) != 0)
1395 if (ElemWidth <= 32 &&
Op.Frac == 0)
1398 auto [BitsX, SignX] = getNumSignificantBits(
Op.X.Val, &In);
1399 auto [BitsY, SignY] = getNumSignificantBits(
Op.Y.Val, &In);
1407 auto roundUpWidth = [](
unsigned Width) ->
unsigned {
1413 if (Width > 32 && Width % 32 != 0) {
1420 BitsX = roundUpWidth(BitsX);
1421 BitsY = roundUpWidth(BitsY);
1426 unsigned Width = std::max(BitsX, BitsY);
1428 auto *ResizeTy = VectorType::get(HVC.getIntTy(Width), VecTy);
1429 if (Width < ElemWidth) {
1430 X =
Builder.CreateTrunc(
X, ResizeTy,
"trn");
1431 Y =
Builder.CreateTrunc(
Y, ResizeTy,
"trn");
1432 }
else if (Width > ElemWidth) {
1434 :
Builder.CreateZExt(
X, ResizeTy,
"zxt");
1436 :
Builder.CreateZExt(
Y, ResizeTy,
"zxt");
1439 assert(
X->getType() ==
Y->getType() &&
X->getType() == ResizeTy);
1441 unsigned VecLen = HVC.length(ResizeTy);
1442 unsigned ChopLen = (8 * HVC.HST.getVectorLength()) / std::min(Width, 32u);
1446 ChopOp.ResTy = VectorType::get(
Op.ResTy->getElementType(), ChopLen,
false);
1448 for (
unsigned V = 0;
V != VecLen / ChopLen; ++
V) {
1449 ChopOp.X.Val = HVC.subvector(Builder,
X, V * ChopLen, ChopLen);
1450 ChopOp.Y.Val = HVC.subvector(Builder,
Y, V * ChopLen, ChopLen);
1451 Results.push_back(processFxpMulChopped(Builder, In, ChopOp));
1461 ?
Builder.CreateSExt(Cat, VecTy,
"sxt")
1462 :
Builder.CreateZExt(Cat, VecTy,
"zxt");
1467 const FxpOp &Op)
const ->
Value * {
1468 assert(
Op.X.Val->getType() ==
Op.Y.Val->getType());
1469 auto *InpTy = cast<VectorType>(
Op.X.Val->getType());
1470 unsigned Width = InpTy->getScalarSizeInBits();
1473 if (!
Op.RoundAt || *
Op.RoundAt ==
Op.Frac - 1) {
1476 Value *QMul =
nullptr;
1478 QMul = createMulQ15(Builder,
Op.X,
Op.Y, Rounding);
1479 }
else if (Width == 32) {
1480 QMul = createMulQ31(Builder,
Op.X,
Op.Y, Rounding);
1482 if (QMul !=
nullptr)
1488 assert(Width < 32 || Width % 32 == 0);
1498 assert(
Op.Frac != 0 &&
"Unshifted mul should have been skipped");
1499 if (
Op.Frac == 16) {
1501 if (
Value *MulH = createMulH16(Builder,
Op.X,
Op.Y))
1505 Value *Prod32 = createMul16(Builder,
Op.X,
Op.Y);
1507 Value *RoundVal = HVC.getConstSplat(Prod32->
getType(), 1 << *
Op.RoundAt);
1508 Prod32 =
Builder.CreateAdd(Prod32, RoundVal,
"add");
1513 ?
Builder.CreateAShr(Prod32, ShiftAmt,
"asr")
1514 :
Builder.CreateLShr(Prod32, ShiftAmt,
"lsr");
1515 return Builder.CreateTrunc(Shifted, InpTy,
"trn");
1522 auto WordX = HVC.splitVectorElements(Builder,
Op.X.Val, 32);
1523 auto WordY = HVC.splitVectorElements(Builder,
Op.Y.Val, 32);
1524 auto WordP = createMulLong(Builder, WordX,
Op.X.Sgn, WordY,
Op.Y.Sgn);
1526 auto *HvxWordTy = cast<VectorType>(WordP.front()->getType());
1529 if (
Op.RoundAt.has_value()) {
1532 RoundV[*
Op.RoundAt / 32] =
1533 HVC.getConstSplat(HvxWordTy, 1 << (*
Op.RoundAt % 32));
1534 WordP = createAddLong(Builder, WordP, RoundV);
1540 unsigned SkipWords =
Op.Frac / 32;
1541 Constant *ShiftAmt = HVC.getConstSplat(HvxWordTy,
Op.Frac % 32);
1543 for (
int Dst = 0, End = WordP.size() - SkipWords; Dst != End; ++Dst) {
1544 int Src = Dst + SkipWords;
1546 if (Src + 1 < End) {
1548 WordP[Dst] =
Builder.CreateIntrinsic(HvxWordTy, Intrinsic::fshr,
1553 WordP[Dst] =
Builder.CreateAShr(
Lo, ShiftAmt,
"asr");
1557 WordP.resize(WordP.size() - SkipWords);
1559 return HVC.joinVectorElements(Builder, WordP,
Op.ResTy);
1562auto HvxIdioms::createMulQ15(
IRBuilderBase &Builder, SValue
X, SValue
Y,
1563 bool Rounding)
const ->
Value * {
1564 assert(
X.Val->getType() ==
Y.Val->getType());
1565 assert(
X.Val->getType()->getScalarType() == HVC.getIntTy(16));
1572 auto V6_vmpyhvsrs = HVC.HST.getIntrinsicId(Hexagon::V6_vmpyhvsrs);
1573 return HVC.createHvxIntrinsic(Builder, V6_vmpyhvsrs,
X.Val->getType(),
1577auto HvxIdioms::createMulQ31(
IRBuilderBase &Builder, SValue
X, SValue
Y,
1578 bool Rounding)
const ->
Value * {
1579 Type *InpTy =
X.Val->getType();
1580 assert(InpTy ==
Y.Val->getType());
1587 auto V6_vmpyewuh = HVC.HST.getIntrinsicId(Hexagon::V6_vmpyewuh);
1589 ? HVC.HST.getIntrinsicId(Hexagon::V6_vmpyowh_rnd_sacc)
1590 : HVC.HST.getIntrinsicId(Hexagon::V6_vmpyowh_sacc);
1592 HVC.createHvxIntrinsic(Builder, V6_vmpyewuh, InpTy, {
X.Val,
Y.Val});
1593 return HVC.createHvxIntrinsic(Builder, V6_vmpyo_acc, InpTy,
1594 {V1,
X.Val,
Y.Val});
1598 Value *CarryIn)
const
1599 -> std::pair<Value *, Value *> {
1600 assert(
X->getType() ==
Y->getType());
1601 auto VecTy = cast<VectorType>(
X->getType());
1602 if (VecTy == HvxI32Ty && HVC.HST.useHVXV62Ops()) {
1605 if (CarryIn ==
nullptr && HVC.HST.useHVXV66Ops()) {
1606 AddCarry = HVC.HST.getIntrinsicId(Hexagon::V6_vaddcarryo);
1608 AddCarry = HVC.HST.getIntrinsicId(Hexagon::V6_vaddcarry);
1609 if (CarryIn ==
nullptr)
1610 CarryIn = HVC.getNullValue(HVC.getBoolTy(HVC.length(VecTy)));
1611 Args.push_back(CarryIn);
1613 Value *
Ret = HVC.createHvxIntrinsic(Builder, AddCarry,
1616 Value *CarryOut =
Builder.CreateExtractValue(Ret, {1},
"ext");
1617 return {
Result, CarryOut};
1624 if (CarryIn !=
nullptr) {
1625 unsigned Width = VecTy->getScalarSizeInBits();
1628 for (
unsigned i = 0, e = 32 / Width; i !=
e; ++i)
1629 Mask = (Mask << Width) | 1;
1631 auto V6_vandqrt = HVC.HST.getIntrinsicId(Hexagon::V6_vandqrt);
1633 HVC.createHvxIntrinsic(Builder, V6_vandqrt,
nullptr,
1634 {CarryIn, HVC.getConstInt(Mask)});
1635 Result1 =
Builder.CreateAdd(
X, ValueIn,
"add");
1641 return {Result2,
Builder.CreateOr(CarryOut1, CarryOut2,
"orb")};
1644auto HvxIdioms::createMul16(
IRBuilderBase &Builder, SValue
X, SValue
Y)
const
1647 std::tie(
X,
Y) = canonSgn(
X,
Y);
1650 V6_vmpyh = HVC.HST.getIntrinsicId(Hexagon::V6_vmpyhv);
1653 V6_vmpyh = HVC.HST.getIntrinsicId(Hexagon::V6_vmpyhus);
1655 V6_vmpyh = HVC.HST.getIntrinsicId(Hexagon::V6_vmpyuhv);
1660 HVC.createHvxIntrinsic(Builder, V6_vmpyh, HvxP32Ty, {
Y.Val,
X.Val});
1662 return HVC.vshuff(Builder, HVC.sublo(Builder,
P), HVC.subhi(Builder,
P));
1665auto HvxIdioms::createMulH16(
IRBuilderBase &Builder, SValue
X, SValue
Y)
const
1667 Type *HvxI16Ty = HVC.getHvxTy(HVC.getIntTy(16),
false);
1669 if (HVC.HST.useHVXV69Ops()) {
1671 auto V6_vmpyuhvs = HVC.HST.getIntrinsicId(Hexagon::V6_vmpyuhvs);
1672 return HVC.createHvxIntrinsic(Builder, V6_vmpyuhvs, HvxI16Ty,
1677 Type *HvxP16Ty = HVC.getHvxTy(HVC.getIntTy(16),
true);
1679 Builder.CreateBitCast(createMul16(Builder,
X,
Y), HvxP16Ty,
"cst");
1680 unsigned Len = HVC.length(HvxP16Ty) / 2;
1683 for (
int i = 0; i !=
static_cast<int>(
Len); ++i)
1684 PickOdd[i] = 2 * i + 1;
1686 return Builder.CreateShuffleVector(
1687 HVC.sublo(Builder, Pair16), HVC.subhi(Builder, Pair16), PickOdd,
"shf");
1690auto HvxIdioms::createMul32(
IRBuilderBase &Builder, SValue
X, SValue
Y)
const
1691 -> std::pair<Value *, Value *> {
1692 assert(
X.Val->getType() ==
Y.Val->getType());
1693 assert(
X.Val->getType() == HvxI32Ty);
1696 std::tie(
X,
Y) = canonSgn(
X,
Y);
1699 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyss_parts;
1701 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyus_parts;
1703 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyuu_parts;
1706 Value *Parts = HVC.createHvxIntrinsic(Builder, V6_vmpy_parts,
nullptr,
1707 {
X.Val,
Y.Val}, {HvxI32Ty});
1716 assert(WordX.size() == WordY.size());
1717 unsigned Idx = 0,
Length = WordX.size();
1721 if (HVC.isZero(WordX[
Idx]))
1723 else if (HVC.isZero(WordY[
Idx]))
1730 Value *Carry =
nullptr;
1732 std::tie(Sum[
Idx], Carry) =
1733 createAddCarry(Builder, WordX[
Idx], WordY[
Idx], Carry);
1747 for (
int i = 0, e = WordX.size(); i != e; ++i) {
1748 for (
int j = 0, f = WordY.size(); j != f; ++j) {
1750 Signedness SX = (i + 1 ==
e) ? SgnX :
Unsigned;
1752 auto [
Lo,
Hi] = createMul32(Builder, {WordX[i], SX}, {WordY[
j],
SY});
1753 Products[i +
j + 0].push_back(
Lo);
1754 Products[i +
j + 1].push_back(
Hi);
1768 for (
int i = 0, e = Products.size(); i !=
e; ++i) {
1769 while (Products[i].
size() > 1) {
1770 Value *Carry =
nullptr;
1771 for (
int j = i;
j !=
e; ++
j) {
1772 auto &ProdJ = Products[
j];
1773 auto [Sum, CarryOut] = createAddCarry(Builder, pop_back_or_zero(ProdJ),
1774 pop_back_or_zero(ProdJ), Carry);
1775 ProdJ.insert(ProdJ.begin(), Sum);
1782 for (
auto &
P : Products) {
1783 assert(
P.size() == 1 &&
"Should have been added together");
1790auto HvxIdioms::run() ->
bool {
1791 bool Changed =
false;
1794 for (
auto It =
B.rbegin(); It !=
B.rend(); ++It) {
1795 if (
auto Fxm = matchFxpMul(*It)) {
1796 Value *
New = processFxpMul(*It, *Fxm);
1801 bool StartOver = !isa<Instruction>(New);
1802 It->replaceAllUsesWith(New);
1804 It = StartOver ?
B.rbegin()
1805 : cast<Instruction>(New)->getReverseIterator();
1816auto HexagonVectorCombine::run() ->
bool {
1817 if (!HST.useHVXOps())
1820 bool Changed =
false;
1821 Changed |= AlignVectors(*this).run();
1822 Changed |= HvxIdioms(*this).run();
1827auto HexagonVectorCombine::getIntTy(
unsigned Width)
const ->
IntegerType * {
1831auto HexagonVectorCombine::getByteTy(
int ElemCount)
const ->
Type * {
1836 return VectorType::get(ByteTy, ElemCount,
false);
1839auto HexagonVectorCombine::getBoolTy(
int ElemCount)
const ->
Type * {
1844 return VectorType::get(BoolTy, ElemCount,
false);
1847auto HexagonVectorCombine::getConstInt(
int Val,
unsigned Width)
const
1852auto HexagonVectorCombine::isZero(
const Value *Val)
const ->
bool {
1853 if (
auto *
C = dyn_cast<Constant>(Val))
1854 return C->isZeroValue();
1858auto HexagonVectorCombine::getIntValue(
const Value *Val)
const
1859 -> std::optional<APInt> {
1860 if (
auto *CI = dyn_cast<ConstantInt>(Val))
1861 return CI->getValue();
1862 return std::nullopt;
1865auto HexagonVectorCombine::isUndef(
const Value *Val)
const ->
bool {
1866 return isa<UndefValue>(Val);
1869auto HexagonVectorCombine::getHvxTy(
Type *ElemTy,
bool Pair)
const
1875 "Invalid HVX element type");
1876 unsigned HwLen = HST.getVectorLength();
1878 return VectorType::get(ElemTy, Pair ? 2 * NumElems : NumElems,
1882auto HexagonVectorCombine::getSizeOf(
const Value *Val, SizeKind Kind)
const
1884 return getSizeOf(Val->
getType(), Kind);
1887auto HexagonVectorCombine::getSizeOf(
const Type *Ty, SizeKind Kind)
const
1889 auto *NcTy =
const_cast<Type *
>(Ty);
1892 return DL.getTypeStoreSize(NcTy).getFixedValue();
1894 return DL.getTypeAllocSize(NcTy).getFixedValue();
1899auto HexagonVectorCombine::getTypeAlignment(
Type *Ty)
const ->
int {
1902 if (HST.isTypeForHVX(Ty))
1903 return HST.getVectorLength();
1904 return DL.getABITypeAlign(Ty).value();
1907auto HexagonVectorCombine::length(
Value *Val)
const ->
size_t {
1908 return length(Val->
getType());
1911auto HexagonVectorCombine::length(
Type *Ty)
const ->
size_t {
1912 auto *VecTy = dyn_cast<VectorType>(Ty);
1913 assert(VecTy &&
"Must be a vector type");
1914 return VecTy->getElementCount().getFixedValue();
1917auto HexagonVectorCombine::getNullValue(
Type *Ty)
const ->
Constant * {
1920 if (
auto *VecTy = dyn_cast<VectorType>(Ty))
1925auto HexagonVectorCombine::getFullValue(
Type *Ty)
const ->
Constant * {
1928 if (
auto *VecTy = dyn_cast<VectorType>(Ty))
1933auto HexagonVectorCombine::getConstSplat(
Type *Ty,
int Val)
const
1936 auto VecTy = cast<VectorType>(Ty);
1937 Type *ElemTy = VecTy->getElementType();
1944auto HexagonVectorCombine::simplify(
Value *V)
const ->
Value * {
1945 if (
auto *In = dyn_cast<Instruction>(V)) {
1955 int Where)
const ->
Value * {
1956 assert(isByteVecTy(Dst->getType()) && isByteVecTy(Src->getType()));
1957 int SrcLen = getSizeOf(Src);
1958 int DstLen = getSizeOf(Dst);
1964 Value *P2Src = vresize(Builder, Src, P2Len, Undef);
1965 Value *P2Dst = vresize(Builder, Dst, P2Len, Undef);
1968 for (
int i = 0; i != P2Len; ++i) {
1972 (Where <= i && i < Where +
Length) ? P2Len + Start + (i - Where) : i;
1975 Value *P2Insert =
Builder.CreateShuffleVector(P2Dst, P2Src, SMask,
"shf");
1976 return vresize(Builder, P2Insert, DstLen, Undef);
1981 assert(
Lo->getType() ==
Hi->getType() &&
"Argument type mismatch");
1984 int VecLen = getSizeOf(
Hi);
1985 if (
auto IntAmt = getIntValue(Amt))
1986 return getElementRange(Builder,
Lo,
Hi, VecLen - IntAmt->getSExtValue(),
1989 if (HST.isTypeForHVX(
Hi->getType())) {
1990 assert(
static_cast<unsigned>(VecLen) == HST.getVectorLength() &&
1991 "Expecting an exact HVX type");
1992 return createHvxIntrinsic(Builder, HST.getIntrinsicId(Hexagon::V6_vlalignb),
1993 Hi->getType(), {Hi, Lo, Amt});
1999 Builder.CreateLShr(
Builder.CreateShl(Pair, Amt,
"shl"), 32,
"lsr");
2002 return Builder.CreateBitCast(Trunc,
Hi->getType(),
"cst");
2006 return vralignb(Builder,
Lo,
Hi, Sub);
2013 assert(
Lo->getType() ==
Hi->getType() &&
"Argument type mismatch");
2016 int VecLen = getSizeOf(
Lo);
2017 if (
auto IntAmt = getIntValue(Amt))
2018 return getElementRange(Builder,
Lo,
Hi, IntAmt->getSExtValue(), VecLen);
2020 if (HST.isTypeForHVX(
Lo->getType())) {
2021 assert(
static_cast<unsigned>(VecLen) == HST.getVectorLength() &&
2022 "Expecting an exact HVX type");
2023 return createHvxIntrinsic(Builder, HST.getIntrinsicId(Hexagon::V6_valignb),
2024 Lo->getType(), {Hi, Lo, Amt});
2032 return Builder.CreateBitCast(Trunc,
Lo->getType(),
"cst");
2039 Intrinsic::hexagon_S2_valignrb);
2041 return Builder.CreateBitCast(Call,
Lo->getType(),
"cst");
2051 std::vector<Value *> Work[2];
2052 int ThisW = 0, OtherW = 1;
2054 Work[ThisW].
assign(Vecs.begin(), Vecs.end());
2055 while (Work[ThisW].
size() > 1) {
2056 auto *Ty = cast<VectorType>(Work[ThisW].front()->
getType());
2057 SMask.
resize(length(Ty) * 2);
2058 std::iota(SMask.
begin(), SMask.
end(), 0);
2060 Work[OtherW].clear();
2061 if (Work[ThisW].
size() % 2 != 0)
2063 for (
int i = 0, e = Work[ThisW].
size(); i <
e; i += 2) {
2065 Work[ThisW][i], Work[ThisW][i + 1], SMask,
"shf");
2066 Work[OtherW].push_back(Joined);
2074 SMask.
resize(Vecs.size() * length(Vecs.front()->getType()));
2075 std::iota(SMask.
begin(), SMask.
end(), 0);
2077 return Builder.CreateShuffleVector(
Total, SMask,
"shf");
2083 auto *ValTy = cast<VectorType>(Val->
getType());
2084 assert(ValTy->getElementType() == Pad->getType());
2086 int CurSize = length(ValTy);
2087 if (CurSize == NewSize)
2090 if (CurSize > NewSize)
2091 return getElementRange(Builder, Val, Val, 0, NewSize);
2094 std::iota(SMask.
begin(), SMask.
begin() + CurSize, 0);
2095 std::fill(SMask.
begin() + CurSize, SMask.
end(), CurSize);
2096 Value *PadVec =
Builder.CreateVectorSplat(CurSize, Pad,
"spt");
2097 return Builder.CreateShuffleVector(Val, PadVec, SMask,
"shf");
2109 if (FromSTy == ToSTy)
2112 int FromSize = getSizeOf(FromSTy);
2113 int ToSize = getSizeOf(ToSTy);
2114 assert(FromSize % ToSize == 0 || ToSize % FromSize == 0);
2116 auto *MaskTy = cast<VectorType>(
Mask->getType());
2117 int FromCount = length(MaskTy);
2118 int ToCount = (FromCount * FromSize) / ToSize;
2119 assert((FromCount * FromSize) % ToSize == 0);
2121 auto *FromITy =
getIntTy(FromSize * 8);
2122 auto *ToITy =
getIntTy(ToSize * 8);
2127 Mask, VectorType::get(FromITy, FromCount,
false),
"sxt");
2129 Ext, VectorType::get(ToITy, ToCount,
false),
"cst");
2131 Cast, VectorType::get(getBoolTy(), ToCount,
false),
"trn");
2138 if (ScalarTy == getBoolTy())
2141 Value *Bytes = vbytes(Builder, Val);
2142 if (
auto *VecTy = dyn_cast<VectorType>(Bytes->
getType()))
2143 return Builder.CreateTrunc(Bytes, getBoolTy(getSizeOf(VecTy)),
"trn");
2146 return Builder.CreateTrunc(Bytes, getBoolTy(),
"trn");
2153 if (ScalarTy == getByteTy())
2156 if (ScalarTy != getBoolTy())
2157 return Builder.CreateBitCast(Val, getByteTy(getSizeOf(Val)),
"cst");
2159 if (
auto *VecTy = dyn_cast<VectorType>(Val->
getType()))
2160 return Builder.CreateSExt(Val, VectorType::get(getByteTy(), VecTy),
"sxt");
2161 return Builder.CreateSExt(Val, getByteTy(),
"sxt");
2165 unsigned Start,
unsigned Length)
const
2168 return getElementRange(Builder, Val, Val, Start,
Length);
2173 size_t Len = length(Val);
2174 assert(Len % 2 == 0 &&
"Length should be even");
2175 return subvector(Builder, Val, 0, Len / 2);
2180 size_t Len = length(Val);
2181 assert(Len % 2 == 0 &&
"Length should be even");
2182 return subvector(Builder, Val, Len / 2, Len / 2);
2187 assert(Val0->getType() == Val1->getType());
2188 int Len = length(Val0);
2191 for (
int i = 0; i !=
Len; ++i) {
2195 return Builder.CreateShuffleVector(Val0, Val1, Mask,
"shf");
2200 assert(Val0->getType() == Val1->getType());
2201 int Len = length(Val0);
2204 for (
int i = 0; i !=
Len; ++i) {
2205 Mask[2 * i + 0] = i;
2208 return Builder.CreateShuffleVector(Val0, Val1, Mask,
"shf");
2211auto HexagonVectorCombine::createHvxIntrinsic(
IRBuilderBase &Builder,
2218 Type *SrcTy = Val->getType();
2219 if (SrcTy == DestTy)
2224 assert(HST.isTypeForHVX(SrcTy,
true));
2227 if (cast<VectorType>(SrcTy)->getElementType() != BoolTy)
2228 return Builder.CreateBitCast(Val, DestTy,
"cst");
2231 unsigned HwLen = HST.getVectorLength();
2232 Intrinsic::ID TC = HwLen == 64 ? Intrinsic::hexagon_V6_pred_typecast
2233 : Intrinsic::hexagon_V6_pred_typecast_128B;
2236 return Builder.CreateCall(FI, {Val},
"cup");
2243 for (
int i = 0, e =
Args.size(); i != e; ++i) {
2245 Type *
T = IntrTy->getParamType(i);
2246 if (
A->getType() !=
T) {
2258 assert(HST.isTypeForHVX(CallTy,
true));
2259 return getCast(Builder, Call,
RetTy);
2262auto HexagonVectorCombine::splitVectorElements(
IRBuilderBase &Builder,
2264 unsigned ToWidth)
const
2278 auto *VecTy = cast<VectorType>(Vec->getType());
2279 assert(VecTy->getElementType()->isIntegerTy());
2280 unsigned FromWidth = VecTy->getScalarSizeInBits();
2282 assert(ToWidth <= FromWidth &&
"Breaking up into wider elements?");
2283 unsigned NumResults = FromWidth / ToWidth;
2287 unsigned Length = length(VecTy);
2291 auto splitInHalf = [&](
unsigned Begin,
unsigned End,
auto splitFunc) ->
void {
2295 if (Begin + 1 == End)
2301 auto *VTy = VectorType::get(
getIntTy(Width / 2), 2 *
Length,
false);
2304 Value *Res =
vdeal(Builder, sublo(Builder, VVal), subhi(Builder, VVal));
2306 unsigned Half = (Begin + End) / 2;
2307 Results[Begin] = sublo(Builder, Res);
2308 Results[Half] = subhi(Builder, Res);
2310 splitFunc(Begin, Half, splitFunc);
2311 splitFunc(Half, End, splitFunc);
2314 splitInHalf(0, NumResults, splitInHalf);
2318auto HexagonVectorCombine::joinVectorElements(
IRBuilderBase &Builder,
2322 assert(ToType->getElementType()->isIntegerTy());
2333 unsigned ToWidth = ToType->getScalarSizeInBits();
2334 unsigned Width = Inputs.front()->getType()->getScalarSizeInBits();
2335 assert(Width <= ToWidth);
2337 unsigned Length = length(Inputs.front()->getType());
2339 unsigned NeedInputs = ToWidth /
Width;
2340 if (Inputs.size() != NeedInputs) {
2345 Last, getConstSplat(
Last->getType(), Width - 1),
"asr");
2346 Inputs.resize(NeedInputs, Sign);
2349 while (Inputs.size() > 1) {
2352 for (
int i = 0, e = Inputs.size(); i < e; i += 2) {
2353 Value *Res =
vshuff(Builder, Inputs[i], Inputs[i + 1]);
2354 Inputs[i / 2] =
Builder.CreateBitCast(Res, VTy,
"cst");
2356 Inputs.resize(Inputs.size() / 2);
2359 assert(Inputs.front()->getType() == ToType);
2360 return Inputs.front();
2363auto HexagonVectorCombine::calculatePointerDifference(
Value *Ptr0,
2365 -> std::optional<int> {
2370 I->eraseFromParent();
2375#define CallBuilder(B, F) \
2378 if (auto *I = dyn_cast<Instruction>(V)) \
2379 B_.ToErase.push_back(I); \
2389 auto StripBitCast = [](
Value *
V) {
2390 while (
auto *
C = dyn_cast<BitCastInst>(V))
2391 V =
C->getOperand(0);
2395 Ptr0 = StripBitCast(Ptr0);
2396 Ptr1 = StripBitCast(Ptr1);
2397 if (!isa<GetElementPtrInst>(Ptr0) || !isa<GetElementPtrInst>(Ptr1))
2398 return std::nullopt;
2400 auto *Gep0 = cast<GetElementPtrInst>(Ptr0);
2401 auto *Gep1 = cast<GetElementPtrInst>(Ptr1);
2402 if (Gep0->getPointerOperand() != Gep1->getPointerOperand())
2403 return std::nullopt;
2404 if (Gep0->getSourceElementType() != Gep1->getSourceElementType())
2405 return std::nullopt;
2408 int Scale = getSizeOf(Gep0->getSourceElementType(), Alloc);
2411 if (Gep0->getNumOperands() != 2 || Gep1->getNumOperands() != 2)
2412 return std::nullopt;
2414 Value *Idx0 = Gep0->getOperand(1);
2415 Value *Idx1 = Gep1->getOperand(1);
2418 if (
auto *Diff = dyn_cast<ConstantInt>(
2420 return Diff->getSExtValue() * Scale;
2422 KnownBits Known0 = getKnownBits(Idx0, Gep0);
2423 KnownBits Known1 = getKnownBits(Idx1, Gep1);
2426 return std::nullopt;
2433 if (
auto *
C = dyn_cast<ConstantInt>(SubU)) {
2434 Diff0 =
C->getSExtValue();
2436 return std::nullopt;
2444 if (
auto *
C = dyn_cast<ConstantInt>(SubK)) {
2445 Diff1 =
C->getSExtValue();
2447 return std::nullopt;
2450 return (Diff0 + Diff1) * Scale;
2455auto HexagonVectorCombine::getNumSignificantBits(
const Value *V,
2461auto HexagonVectorCombine::getKnownBits(
const Value *V,
2468template <
typename T>
2469auto HexagonVectorCombine::isSafeToMoveBeforeInBB(
const Instruction &In,
2471 const T &IgnoreInsts)
const
2474 [
this](
const Instruction &
I) -> std::optional<MemoryLocation> {
2475 if (
const auto *II = dyn_cast<IntrinsicInst>(&
I)) {
2476 switch (II->getIntrinsicID()) {
2477 case Intrinsic::masked_load:
2479 case Intrinsic::masked_store:
2488 assert(
Block.begin() == To ||
Block.end() == To || To->getParent() == &Block);
2490 if (isa<PHINode>(In) || (To !=
Block.end() && isa<PHINode>(*To)))
2495 bool MayWrite =
In.mayWriteToMemory();
2496 auto MaybeLoc = getLocOrNone(In);
2498 auto From =
In.getIterator();
2501 bool MoveUp = (To !=
Block.end() && To->comesBefore(&In));
2503 MoveUp ? std::make_pair(To,
From) :
std::make_pair(
std::next(
From), To);
2504 for (
auto It =
Range.first; It !=
Range.second; ++It) {
2509 if (
auto *II = dyn_cast<IntrinsicInst>(&
I)) {
2510 if (II->getIntrinsicID() == Intrinsic::assume)
2516 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
2517 if (!CB->hasFnAttr(Attribute::WillReturn))
2519 if (!CB->hasFnAttr(Attribute::NoSync))
2522 if (
I.mayReadOrWriteMemory()) {
2523 auto MaybeLocI = getLocOrNone(
I);
2524 if (MayWrite ||
I.mayWriteToMemory()) {
2525 if (!MaybeLoc || !MaybeLocI)
2527 if (!AA.isNoAlias(*MaybeLoc, *MaybeLocI))
2535auto HexagonVectorCombine::isByteVecTy(
Type *Ty)
const ->
bool {
2536 if (
auto *VecTy = dyn_cast<VectorType>(Ty))
2537 return VecTy->getElementType() == getByteTy();
2546 std::iota(SMask.
begin(), SMask.
end(), Start);
2547 return Builder.CreateShuffleVector(
Lo,
Hi, SMask,
"shf");
2558class HexagonVectorCombineLegacy :
public FunctionPass {
2579 AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
2581 getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
2582 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
2584 getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
2586 HexagonVectorCombine HVC(
F, AA, AC, DT, TLI,
TM);
2592char HexagonVectorCombineLegacy::ID = 0;
2595 "Hexagon Vector Combine",
false,
false)
2605 return new HexagonVectorCombineLegacy();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file implements a class to represent arbitrary precision integral constant values and operations...
SmallPtrSet< MachineInstr *, 2 > Uses
Function Alias Analysis Results
BlockVerifier::State From
static IntegerType * getIntTy(IRBuilderBase &B, const TargetLibraryInfo *TLI)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Analysis containing CSE Info
#define LLVM_ATTRIBUTE_UNUSED
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Given that RA is a live value
Mark the given Function as meaning that it cannot be changed in any way mark any values that are used as this function s parameters or by its return values(according to Uses) live as well. void DeadArgumentEliminationPass
This file defines the DenseMap class.
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
static bool isUndef(ArrayRef< int > Mask)
#define CallBuilder(B, F)
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
static bool isCandidate(const MachineInstr *MI, Register &DefedReg, Register FrameReg)
return ToRemove size() > 0
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static MemoryLocation getLocation(Instruction *I)
static ConstantInt * getConstInt(MDNode *MD, unsigned NumOp)
This file defines the SmallVector class.
static SymbolRef::Type getType(const Symbol *Sym)
Target-Independent Code Generator Pass Configuration Options pass.
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
bool isAllOnes() const
Determine if all bits are set. This is true for zero-width values.
APInt ashr(unsigned ShiftAmt) const
Arithmetic right-shift function.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
void setPreservesCFG()
This function should be called by the pass, iff they do not:
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
An immutable pass that tracks lazily created AssumptionCache objects.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
InstListType::const_iterator const_iterator
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
@ ICMP_ULT
unsigned less than
This is the shared class of boolean and integer constants.
static ConstantInt * getTrue(LLVMContext &Context)
static Constant * get(Type *Ty, uint64_t V, bool IsSigned=false)
If Ty is a vector type, return a Constant with a splat of the given value.
static ConstantInt * getSigned(IntegerType *Ty, int64_t V)
Return a ConstantInt with the specified value for the specified type.
static Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
iterator_range< iterator > children()
Legacy analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
bool skipFunction(const Function &F) const
Optional passes call this function to check whether the pass should be skipped.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
const BasicBlock & back() const
Common base class shared among various IRBuilders.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.
const BasicBlock * getParent() const
const char * getOpcodeName() const
Class to represent integer types.
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
An instruction for reading from memory.
static std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx, const TargetLibraryInfo *TLI)
Return a location representing a particular argument of a call.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
void assign(size_type NumElts, ValueParamT Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
Provides information about what library functions are available for the current target.
Primary interface to the complete machine description for the target machine.
virtual const TargetSubtargetInfo * getSubtargetImpl(const Function &) const
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Target-Independent Code Generator Pass Configuration Options.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
PointerType * getPointerTo(unsigned AddrSpace=0) const
Return a pointer to the current type.
bool isIntOrIntVectorTy() const
Return true if this is an integer type or a vector of integer types.
static IntegerType * getInt1Ty(LLVMContext &C)
Type * getNonOpaquePointerElementType() const
Only use this method in code that is not reachable with opaque pointers, or part of deprecated method...
unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
static IntegerType * getInt8Ty(LLVMContext &C)
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
static IntegerType * getInt32Ty(LLVMContext &C)
static IntegerType * getInt64Ty(LLVMContext &C)
bool isIntegerTy() const
True if this is an instance of IntegerType.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
self_iterator getIterator()
This class implements an extremely fast bulk output stream that can only output to a stream.
friend const_iterator begin(StringRef path, Style style)
Get begin iterator over path.
friend const_iterator end(StringRef path)
Get end iterator over path.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Rounding
Possible values of current rounding mode, which is specified in bits 23:22 of FPCR.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
BinaryOp_match< LHS, RHS, Instruction::Add > m_Add(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::AShr > m_AShr(const LHS &L, const RHS &R)
bool match(Val *V, const Pattern &P)
BinOpPred_match< LHS, RHS, is_right_shift_op > m_Shr(const LHS &L, const RHS &R)
Matches logical shift operations.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
apint_match m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
match_combine_or< LTy, RTy > m_CombineOr(const LTy &L, const RTy &R)
Combine two pattern matchers matching L || R.
@ Undef
Value of the register doesn't matter.
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createHexagonVectorCombineLegacyPass()
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
If the specified value is a trivially dead instruction, delete it.
void append_range(Container &C, Range &&R)
Wrapper function to append a range to a container.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Instruction * propagateMetadata(Instruction *I, ArrayRef< Value * > VL)
Specifically, let Kinds = [MD_tbaa, MD_alias_scope, MD_noalias, MD_fpmath, MD_nontemporal,...
OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P)
Provide wrappers to std::copy_if which take ranges instead of having to pass begin/end explicitly.
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&... Ranges)
Concatenated range across two or more ranges.
void initializeHexagonVectorCombineLegacyPass(PassRegistry &)
void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, unsigned Depth=0, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, OptimizationRemarkEmitter *ORE=nullptr, bool UseInstrInfo=true)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q, OptimizationRemarkEmitter *ORE=nullptr)
See if we can compute a simplified version of this instruction.
@ And
Bitwise or logical AND of integers.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
unsigned ComputeMaxSignificantBits(const Value *Op, const DataLayout &DL, unsigned Depth=0, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr)
Get the upper bound on bit size for this Value Op as a signed integer.
bool mayHaveNonDefUseDependency(const Instruction &I)
Returns true if the result or effects of the given instructions I depend values not reachable through...
MaskT vshuff(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
MaskT vdeal(ArrayRef< int > Vu, ArrayRef< int > Vv, unsigned Size, bool TakeOdd)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
This struct is a compact representation of a valid (non-zero power of two) alignment.
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
static EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.