37#include "llvm/IR/IntrinsicsHexagon.h"
60#define DEBUG_TYPE "hexagon-vc"
65#define DEFAULT_HVX_VTCM_PAGE_SIZE 131072
80 MinLoadGroupSizeForAlignment(
"hvc-ld-min-group-size-for-alignment",
83class HexagonVectorCombine {
89 :
F(F_),
DL(
F.getDataLayout()),
AA(AA_), AC(AC_), DT(DT_), SE(SE_),
100 Type *getByteTy(
int ElemCount = 0)
const;
103 Type *getBoolTy(
int ElemCount = 0)
const;
105 ConstantInt *getConstInt(
int Val,
unsigned Width = 32)
const;
107 std::optional<APInt> getIntValue(
const Value *Val)
const;
113 bool isTrue(
const Value *Val)
const;
115 bool isFalse(
const Value *Val)
const;
124 int getSizeOf(
const Value *Val, SizeKind Kind =
Store)
const;
125 int getSizeOf(
const Type *Ty, SizeKind Kind =
Store)
const;
126 int getTypeAlignment(
Type *Ty)
const;
127 size_t length(
Value *Val)
const;
128 size_t length(
Type *Ty)
const;
133 int Length,
int Where)
const;
157 unsigned ToWidth)
const;
161 std::optional<int> calculatePointerDifference(
Value *Ptr0,
Value *Ptr1)
const;
163 unsigned getNumSignificantBits(
const Value *V,
170 template <
typename T = std::vector<Instruction *>>
173 const T &IgnoreInsts = {})
const;
176 [[maybe_unused]]
bool isByteVecTy(
Type *Ty)
const;
190 int Start,
int Length)
const;
209 AlignVectors(
const HexagonVectorCombine &HVC_) : HVC(HVC_) {}
214 using InstList = std::vector<Instruction *>;
218 AddrInfo(
const AddrInfo &) =
default;
219 AddrInfo &operator=(
const AddrInfo &) =
default;
222 : Inst(
I), Addr(
A), ValTy(
T), HaveAlign(
H),
223 NeedAlign(HVC.getTypeAlignment(ValTy)) {}
234 using AddrList = std::vector<AddrInfo>;
238 return A->comesBefore(
B);
241 using DepList = std::set<Instruction *, InstrLess>;
245 :
Base(
B), Main{AI.Inst}, Clones{}, IsHvx(Hvx), IsLoad(
Load) {}
246 MoveGroup() =
default;
254 using MoveList = std::vector<MoveGroup>;
274 Segment(
Value *Val,
int Begin,
int Len)
275 : Val(Val), Start(Begin),
Size(Len) {}
276 Segment(
const Segment &Seg) =
default;
277 Segment &operator=(
const Segment &Seg) =
default;
284 Block(
Value *Val,
int Len,
int Pos) : Seg(Val, 0, Len), Pos(Pos) {}
286 : Seg(Val, Off, Len), Pos(Pos) {}
294 ByteSpan section(
int Start,
int Length)
const;
295 ByteSpan &shift(
int Offset);
298 int size()
const {
return Blocks.size(); }
299 Block &operator[](
int i) {
return Blocks[i]; }
300 const Block &operator[](
int i)
const {
return Blocks[i]; }
302 std::vector<Block> Blocks;
305 iterator begin() {
return Blocks.begin(); }
306 iterator end() {
return Blocks.end(); }
312 std::optional<AddrInfo> getAddrInfo(
Instruction &In)
const;
313 bool isHvx(
const AddrInfo &AI)
const;
315 [[maybe_unused]]
bool isSectorTy(
Type *Ty)
const;
323 const InstMap &CloneMap = InstMap())
const;
326 const InstMap &CloneMap = InstMap())
const;
350 bool createAddressGroups();
351 MoveList createLoadGroups(
const AddrList &Group)
const;
352 MoveList createStoreGroups(
const AddrList &Group)
const;
353 bool moveTogether(MoveGroup &Move)
const;
354 template <
typename T>
357 void realignLoadGroup(
IRBuilderBase &Builder,
const ByteSpan &VSpan,
358 int ScLen,
Value *AlignVal,
Value *AlignAddr)
const;
359 void realignStoreGroup(
IRBuilderBase &Builder,
const ByteSpan &VSpan,
360 int ScLen,
Value *AlignVal,
Value *AlignAddr)
const;
361 bool realignGroup(
const MoveGroup &Move);
363 int Alignment)
const;
366 AddrGroupMap AddrGroups;
383 const HexagonVectorCombine &HVC;
387 const AlignVectors::AddrGroupMap &AG) {
388 OS <<
"Printing AddrGroups:"
390 for (
auto &It : AG) {
391 OS <<
"\n\tInstruction: ";
393 OS <<
"\n\tAddrInfo: ";
394 for (
auto &AI : It.second)
401 const AlignVectors::AddrList &AL) {
402 OS <<
"\n *** Addr List: ***\n";
403 for (
auto &AG : AL) {
404 OS <<
"\n *** Addr Group: ***\n";
412 const AlignVectors::AddrInfo &AI) {
413 OS <<
"Inst: " << AI.Inst <<
" " << *AI.Inst <<
'\n';
414 OS <<
"Addr: " << *AI.Addr <<
'\n';
415 OS <<
"Type: " << *AI.ValTy <<
'\n';
416 OS <<
"HaveAlign: " << AI.HaveAlign.
value() <<
'\n';
417 OS <<
"NeedAlign: " << AI.NeedAlign.
value() <<
'\n';
418 OS <<
"Offset: " << AI.Offset;
423 const AlignVectors::MoveList &
ML) {
424 OS <<
"\n *** Move List: ***\n";
425 for (
auto &MG :
ML) {
426 OS <<
"\n *** Move Group: ***\n";
434 const AlignVectors::MoveGroup &MG) {
435 OS <<
"IsLoad:" << (MG.IsLoad ?
"yes" :
"no");
436 OS <<
", IsHvx:" << (MG.IsHvx ?
"yes" :
"no") <<
'\n';
439 OS <<
" " << *
I <<
'\n';
442 OS <<
" " << *
I <<
'\n';
444 for (
auto [K, V] : MG.Clones) {
446 K->printAsOperand(OS,
false);
447 OS <<
"\t-> " << *V <<
'\n';
454 OS <<
" @" <<
B.Pos <<
" [" <<
B.Seg.Start <<
',' <<
B.Seg.Size <<
"] ";
455 if (
B.Seg.Val ==
reinterpret_cast<const Value *
>(&
B)) {
456 OS <<
"(self:" <<
B.Seg.Val <<
')';
457 }
else if (
B.Seg.Val !=
nullptr) {
466 const AlignVectors::ByteSpan &BS) {
467 OS <<
"ByteSpan[size=" << BS.size() <<
", extent=" << BS.extent() <<
'\n';
468 for (
const AlignVectors::ByteSpan::Block &
B : BS)
488 HvxIdioms(
const HexagonVectorCombine &HVC_) : HVC(HVC_) {
489 auto *Int32Ty = HVC.getIntTy(32);
490 HvxI32Ty = HVC.getHvxTy(Int32Ty,
false);
491 HvxP32Ty = HVC.getHvxTy(Int32Ty,
true);
512 std::optional<unsigned> RoundAt;
517 -> std::pair<unsigned, Signedness>;
518 auto canonSgn(SValue
X, SValue
Y)
const -> std::pair<SValue, SValue>;
520 auto matchFxpMul(
Instruction &In)
const -> std::optional<FxpOp>;
524 const FxpOp &
Op)
const ->
Value *;
526 bool Rounding)
const ->
Value *;
528 bool Rounding)
const ->
Value *;
531 Value *CarryIn =
nullptr)
const
532 -> std::pair<Value *, Value *>;
537 -> std::pair<Value *, Value *>;
549 std::optional<uint64_t>
552 std::optional<uint64_t> getPHIBaseMinAlignment(
Instruction &In,
563 const HexagonVectorCombine &HVC;
569 const HvxIdioms::FxpOp &
Op) {
570 static const char *SgnNames[] = {
"Positive",
"Signed",
"Unsigned"};
572 if (
Op.RoundAt.has_value()) {
573 if (
Op.Frac != 0 && *
Op.RoundAt ==
Op.Frac - 1) {
576 OS <<
" + 1<<" << *
Op.RoundAt;
579 OS <<
"\n X:(" << SgnNames[
Op.X.Sgn] <<
") " << *
Op.X.Val <<
"\n"
580 <<
" Y:(" << SgnNames[
Op.Y.Sgn] <<
") " << *
Op.Y.Val;
588template <
typename T>
T *getIfUnordered(
T *MaybeT) {
589 return MaybeT && MaybeT->isUnordered() ? MaybeT :
nullptr;
602template <
typename Pred,
typename T>
void erase_if(
T &&container, Pred p) {
640auto AlignVectors::ByteSpan::extent()
const ->
int {
643 int Min = Blocks[0].Pos;
644 int Max = Blocks[0].Pos + Blocks[0].Seg.Size;
645 for (
int i = 1, e =
size(); i !=
e; ++i) {
646 Min = std::min(Min, Blocks[i].Pos);
647 Max = std::max(Max, Blocks[i].Pos + Blocks[i].Seg.Size);
652auto AlignVectors::ByteSpan::section(
int Start,
int Length)
const -> ByteSpan {
654 for (
const ByteSpan::Block &
B : Blocks) {
655 int L = std::max(
B.Pos, Start);
656 int R = std::min(
B.Pos +
B.Seg.Size, Start +
Length);
659 int Off =
L >
B.Pos ?
L -
B.Pos : 0;
660 Section.Blocks.emplace_back(
B.Seg.Val,
B.Seg.Start + Off, R - L, L);
666auto AlignVectors::ByteSpan::shift(
int Offset) -> ByteSpan & {
673 SmallVector<Value *, 8>
Values(Blocks.size());
674 for (
int i = 0, e = Blocks.size(); i != e; ++i)
675 Values[i] = Blocks[i].Seg.Val;
686 return Align(
DL.getABITypeAlign(ValTy).value());
689auto AlignVectors::getAddrInfo(Instruction &In)
const
690 -> std::optional<AddrInfo> {
692 return AddrInfo(HVC, L,
L->getPointerOperand(),
L->getType(),
695 return AddrInfo(HVC, S, S->getPointerOperand(),
696 S->getValueOperand()->getType(), S->getAlign());
700 case Intrinsic::masked_load:
701 return AddrInfo(HVC,
II,
II->getArgOperand(0),
II->getType(),
702 II->getParamAlign(0).valueOrOne());
703 case Intrinsic::masked_store:
704 return AddrInfo(HVC,
II,
II->getArgOperand(1),
705 II->getArgOperand(0)->getType(),
706 II->getParamAlign(1).valueOrOne());
712auto AlignVectors::isHvx(
const AddrInfo &AI)
const ->
bool {
716auto AlignVectors::getPayload(
Value *Val)
const ->
Value * {
720 ID =
II->getIntrinsicID();
722 return In->getOperand(0);
727auto AlignVectors::getMask(
Value *Val)
const ->
Value * {
729 switch (
II->getIntrinsicID()) {
730 case Intrinsic::masked_load:
731 return II->getArgOperand(1);
732 case Intrinsic::masked_store:
733 return II->getArgOperand(2);
737 Type *ValTy = getPayload(Val)->getType();
743auto AlignVectors::getPassThrough(
Value *Val)
const ->
Value * {
745 if (
II->getIntrinsicID() == Intrinsic::masked_load)
746 return II->getArgOperand(2);
751auto AlignVectors::createAdjustedPointer(IRBuilderBase &Builder,
Value *Ptr,
752 Type *ValTy,
int Adjust,
753 const InstMap &CloneMap)
const
756 if (Instruction *New = CloneMap.lookup(
I))
758 return Builder.CreatePtrAdd(Ptr, HVC.getConstInt(Adjust),
"gep");
761auto AlignVectors::createAlignedPointer(IRBuilderBase &Builder,
Value *Ptr,
762 Type *ValTy,
int Alignment,
763 const InstMap &CloneMap)
const
767 for (
auto [Old, New] : CloneMap)
768 I->replaceUsesOfWith(Old, New);
773 Value *AsInt = Builder.CreatePtrToInt(Ptr, HVC.getIntTy(),
"pti");
774 Value *
Mask = HVC.getConstInt(-Alignment);
775 Value *
And = Builder.CreateAnd(remap(AsInt), Mask,
"and");
776 return Builder.CreateIntToPtr(
780auto AlignVectors::createLoad(IRBuilderBase &Builder,
Type *ValTy,
Value *Ptr,
787 "Expectning scalar predicate");
788 if (HVC.isFalse(Predicate))
790 if (!HVC.isTrue(Predicate)) {
791 Value *
Load = createPredicatedLoad(Builder, ValTy, Ptr, Predicate,
792 Alignment, MDSources);
793 return Builder.CreateSelect(Mask,
Load, PassThru);
797 assert(!HVC.isUndef(Mask));
798 if (HVC.isZero(Mask))
802 if (HVC.isTrue(Mask))
803 return createSimpleLoad(Builder, ValTy, Ptr, EffA.
value(), MDSources);
806 Builder.CreateMaskedLoad(ValTy, Ptr, EffA, Mask, PassThru,
"mld");
812auto AlignVectors::createSimpleLoad(IRBuilderBase &Builder,
Type *ValTy,
813 Value *Ptr,
int Alignment,
817 Instruction *
Load = Builder.CreateAlignedLoad(ValTy, Ptr, EffA,
"ald");
823auto AlignVectors::createPredicatedLoad(IRBuilderBase &Builder,
Type *ValTy,
829 "Predicates 'scalar' vector loads not yet supported");
831 assert(!
Predicate->getType()->isVectorTy() &&
"Expectning scalar predicate");
833 assert(HVC.getSizeOf(ValTy, HVC.Alloc) % EffA.
value() == 0);
835 if (HVC.isFalse(Predicate))
837 if (HVC.isTrue(Predicate))
838 return createSimpleLoad(Builder, ValTy, Ptr, EffA.
value(), MDSources);
840 auto V6_vL32b_pred_ai = HVC.HST.
getIntrinsicId(Hexagon::V6_vL32b_pred_ai);
842 return HVC.createHvxIntrinsic(Builder, V6_vL32b_pred_ai, ValTy,
843 {
Predicate, Ptr, HVC.getConstInt(0)}, {},
847auto AlignVectors::createStore(IRBuilderBase &Builder,
Value *Val,
Value *Ptr,
850 if (HVC.isZero(Mask) || HVC.isUndef(Val) || HVC.isUndef(Mask))
853 "Expectning scalar predicate"));
855 if (HVC.isFalse(Predicate))
857 if (HVC.isTrue(Predicate))
862 if (HVC.isTrue(Mask)) {
864 return createPredicatedStore(Builder, Val, Ptr, Predicate, Alignment,
868 return createSimpleStore(Builder, Val, Ptr, Alignment, MDSources);
874 Builder.CreateMaskedStore(Val, Ptr,
Align(Alignment), Mask);
881 Value *PredLoad = createPredicatedLoad(Builder, Val->getType(), Ptr,
882 Predicate, Alignment, MDSources);
883 Value *Mux = Builder.CreateSelect(Mask, Val, PredLoad);
884 return createPredicatedStore(Builder, Mux, Ptr, Predicate, Alignment,
888auto AlignVectors::createSimpleStore(IRBuilderBase &Builder,
Value *Val,
889 Value *Ptr,
int Alignment,
899auto AlignVectors::createPredicatedStore(IRBuilderBase &Builder,
Value *Val,
906 "Predicates 'scalar' vector stores not yet supported");
908 if (HVC.isFalse(Predicate))
910 if (HVC.isTrue(Predicate))
911 return createSimpleStore(Builder, Val, Ptr, EffA.
value(), MDSources);
913 assert(HVC.getSizeOf(Val, HVC.Alloc) % EffA.
value() == 0);
914 auto V6_vS32b_pred_ai = HVC.HST.
getIntrinsicId(Hexagon::V6_vS32b_pred_ai);
916 return HVC.createHvxIntrinsic(Builder, V6_vS32b_pred_ai,
nullptr,
917 {
Predicate, Ptr, HVC.getConstInt(0), Val}, {},
921auto AlignVectors::getUpwardDeps(Instruction *In, Instruction *
Base)
const
925 "Base and In should be in the same block");
926 assert(
Base->comesBefore(In) &&
"Base should come before In");
929 std::deque<Instruction *> WorkQ = {
In};
930 while (!WorkQ.empty()) {
937 if (
I->getParent() == Parent &&
Base->comesBefore(
I))
945auto AlignVectors::createAddressGroups() ->
bool {
950 auto findBaseAndOffset = [&](AddrInfo &AI) -> std::pair<Instruction *, int> {
951 for (AddrInfo &W : WorkStack) {
952 if (
auto D = HVC.calculatePointerDifference(AI.Addr,
W.Addr))
953 return std::make_pair(
W.Inst, *
D);
955 return std::make_pair(
nullptr, 0);
958 auto traverseBlock = [&](
DomTreeNode *DomN,
auto Visit) ->
void {
960 for (Instruction &
I :
Block) {
961 auto AI = this->getAddrInfo(
I);
964 auto F = findBaseAndOffset(*AI);
966 if (Instruction *BI =
F.first) {
967 AI->Offset =
F.second;
970 WorkStack.push_back(*AI);
971 GroupInst = AI->Inst;
973 AddrGroups[GroupInst].push_back(*AI);
979 while (!WorkStack.empty() && WorkStack.back().Inst->getParent() == &
Block)
980 WorkStack.pop_back();
983 traverseBlock(HVC.DT.
getRootNode(), traverseBlock);
984 assert(WorkStack.empty());
988 AddrGroups.
remove_if([](
auto &
G) {
return G.second.size() == 1; });
992 G.second, [&](
auto &
I) { return HVC.HST.isTypeForHVX(I.ValTy); });
996 return !AddrGroups.
empty();
999auto AlignVectors::createLoadGroups(
const AddrList &Group)
const -> MoveList {
1007 auto tryAddTo = [&](
const AddrInfo &
Info, MoveGroup &Move) {
1008 assert(!Move.Main.empty() &&
"Move group should have non-empty Main");
1010 HVC.ORE.
emit([&]() {
1011 return OptimizationRemarkMissed(
DEBUG_TYPE,
"GroupSizeLimitExceeded",
1012 Info.Inst->getDebugLoc(),
1013 Info.Inst->getParent())
1014 <<
"alignment group exceeds size limit";
1019 if (Move.IsHvx != isHvx(Info))
1023 if (
Base->getParent() !=
Info.Inst->getParent())
1026 if (!HVC.isSafeToMoveBeforeInBB(*
Info.Inst,
Base->getIterator())) {
1027 HVC.ORE.
emit([&]() {
1028 return OptimizationRemarkMissed(
DEBUG_TYPE,
"UnsafeToRelocate",
1029 Info.Inst->getDebugLoc(),
1030 Info.Inst->getParent())
1031 <<
"unsafe to relocate memory access for alignment";
1037 return HVC.isSafeToMoveBeforeInBB(*
I,
Base->getIterator()) &&
1038 HVC.isSafeToClone(*
I);
1040 DepList Deps = getUpwardDeps(
Info.Inst,
Base);
1044 Move.Main.push_back(
Info.Inst);
1049 MoveList LoadGroups;
1051 for (
const AddrInfo &Info : Group) {
1052 if (!
Info.Inst->mayReadFromMemory())
1054 if (LoadGroups.empty() || !tryAddTo(Info, LoadGroups.back()))
1055 LoadGroups.emplace_back(Info, Group.front().Inst, isHvx(Info),
true);
1059 unsigned LoadGroupSizeLimit = MinLoadGroupSizeForAlignment;
1060 erase_if(LoadGroups, [LoadGroupSizeLimit](
const MoveGroup &
G) {
1061 return G.Main.size() < LoadGroupSizeLimit;
1067 llvm::any_of(LoadGroups, [](
const MoveGroup &
G) {
return G.IsHvx; });
1068 erase_if(LoadGroups, [](
const MoveGroup &
G) {
return G.IsHvx; });
1070 HVC.ORE.
emit([&]() {
1071 return OptimizationRemarkMissed(
DEBUG_TYPE,
"HvxVersionTooLow",
1073 <<
"HVX version too low for predicated load operations";
1082auto AlignVectors::createStoreGroups(
const AddrList &Group)
const -> MoveList {
1090 auto tryAddTo = [&](
const AddrInfo &
Info, MoveGroup &Move) {
1091 assert(!Move.Main.empty() &&
"Move group should have non-empty Main");
1093 HVC.ORE.
emit([&]() {
1094 return OptimizationRemarkMissed(
DEBUG_TYPE,
"GroupSizeLimitExceeded",
1095 Info.Inst->getDebugLoc(),
1096 Info.Inst->getParent())
1097 <<
"alignment group exceeds size limit";
1104 "Not handling stores with return values");
1106 if (Move.IsHvx != isHvx(Info))
1112 if (
Base->getParent() !=
Info.Inst->getParent())
1114 if (!HVC.isSafeToMoveBeforeInBB(*
Info.Inst,
Base->getIterator(),
1116 HVC.ORE.
emit([&]() {
1117 return OptimizationRemarkMissed(
DEBUG_TYPE,
"UnsafeToRelocate",
1118 Info.Inst->getDebugLoc(),
1119 Info.Inst->getParent())
1120 <<
"unsafe to relocate memory access for alignment";
1124 Move.Main.push_back(
Info.Inst);
1128 MoveList StoreGroups;
1130 for (
auto I = Group.rbegin(),
E = Group.rend();
I !=
E; ++
I) {
1131 const AddrInfo &
Info = *
I;
1132 if (!
Info.Inst->mayWriteToMemory())
1134 if (StoreGroups.empty() || !tryAddTo(Info, StoreGroups.back()))
1135 StoreGroups.emplace_back(Info, Group.front().Inst, isHvx(Info),
false);
1139 erase_if(StoreGroups, [](
const MoveGroup &
G) {
return G.Main.size() <= 1; });
1144 llvm::any_of(StoreGroups, [](
const MoveGroup &
G) {
return G.IsHvx; });
1145 erase_if(StoreGroups, [](
const MoveGroup &
G) {
return G.IsHvx; });
1147 HVC.ORE.
emit([&]() {
1148 return OptimizationRemarkMissed(
DEBUG_TYPE,
"HvxVersionTooLow",
1150 <<
"HVX version too low for predicated store operations";
1158 if (!VADoFullStores) {
1159 erase_if(StoreGroups, [
this](
const MoveGroup &
G) {
1161 auto MaybeInfo = this->getAddrInfo(*S);
1162 assert(MaybeInfo.has_value());
1163 return HVC.HST.isHVXVectorType(
1164 EVT::getEVT(MaybeInfo->ValTy, false));
1172auto AlignVectors::moveTogether(MoveGroup &Move)
const ->
bool {
1174 assert(!Move.Main.empty() &&
"Move group should have non-empty Main");
1180 Move.Clones = cloneBefore(Where->
getIterator(), Move.Deps);
1183 for (Instruction *M : Main) {
1185 M->moveAfter(Where);
1186 for (
auto [Old, New] : Move.Clones)
1187 M->replaceUsesOfWith(Old, New);
1191 for (
int i = 0, e = Move.Deps.size(); i != e; ++i)
1192 Move.Deps[i] = Move.Clones[Move.Deps[i]];
1197 assert(Move.Deps.empty());
1200 for (Instruction *M : Main.drop_front(1)) {
1206 return Move.Main.size() + Move.Deps.size() > 1;
1209template <
typename T>
1214 for (Instruction *
I : Insts) {
1215 assert(HVC.isSafeToClone(*
I));
1217 C->setName(Twine(
"c.") +
I->getName() +
".");
1218 C->insertBefore(To);
1220 for (
auto [Old, New] : Map)
1221 C->replaceUsesOfWith(Old, New);
1222 Map.insert(std::make_pair(
I,
C));
1227auto AlignVectors::realignLoadGroup(IRBuilderBase &Builder,
1228 const ByteSpan &VSpan,
int ScLen,
1233 Type *SecTy = HVC.getByteTy(ScLen);
1234 int NumSectors = (VSpan.extent() + ScLen - 1) / ScLen;
1235 bool DoAlign = !HVC.isZero(AlignVal);
1237 BasicBlock *BaseBlock = Builder.GetInsertBlock();
1267 for (
int Index = 0;
Index != NumSectors; ++
Index)
1268 ASpan.Blocks.emplace_back(
nullptr, ScLen, Index * ScLen);
1269 for (
int Index = 0;
Index != NumSectors; ++
Index) {
1270 ASpan.Blocks[
Index].Seg.Val =
1271 reinterpret_cast<Value *
>(&ASpan.Blocks[
Index]);
1277 DenseMap<void *, Instruction *> EarliestUser;
1283 assert(
A->getParent() ==
B->getParent());
1284 return A->comesBefore(
B);
1286 auto earliestUser = [&](
const auto &
Uses) {
1288 for (
const Use &U :
Uses) {
1290 assert(
I !=
nullptr &&
"Load used in a non-instruction?");
1294 if (
I->getParent() == BaseBlock) {
1296 User = std::min(User,
I, isEarlier);
1304 for (
const ByteSpan::Block &
B : VSpan) {
1305 ByteSpan ASection = ASpan.section(
B.Pos,
B.Seg.Size);
1306 for (
const ByteSpan::Block &S : ASection) {
1307 auto &EU = EarliestUser[S.Seg.Val];
1308 EU = std::min(EU, earliestUser(
B.Seg.Val->uses()), isEarlier);
1313 dbgs() <<
"ASpan:\n" << ASpan <<
'\n';
1314 dbgs() <<
"Earliest users of ASpan:\n";
1315 for (
auto &[Val, User] : EarliestUser) {
1316 dbgs() << Val <<
"\n ->" << *
User <<
'\n';
1320 auto createLoad = [&](IRBuilderBase &Builder,
const ByteSpan &VSpan,
1321 int Index,
bool MakePred) {
1323 createAdjustedPointer(Builder, AlignAddr, SecTy, Index * ScLen);
1325 MakePred ? makeTestIfUnaligned(Builder, AlignVal, ScLen) : nullptr;
1330 int Width = (1 + DoAlign) * ScLen;
1331 return this->createLoad(Builder, SecTy, Ptr, Predicate, ScLen, True,
Undef,
1332 VSpan.section(Start, Width).values());
1337 assert(
In->getParent() == To->getParent());
1338 DepList Deps = getUpwardDeps(&*In, &*To);
1341 InstMap
Map = cloneBefore(In, Deps);
1342 for (
auto [Old, New] : Map)
1343 In->replaceUsesOfWith(Old, New);
1348 for (
int Index = 0;
Index != NumSectors + 1; ++
Index) {
1356 DoAlign &&
Index > 0 ? EarliestUser[&ASpan[
Index - 1]] :
nullptr;
1358 Index < NumSectors ? EarliestUser[&ASpan[
Index]] :
nullptr;
1359 if (
auto *Where = std::min(PrevAt, ThisAt, isEarlier)) {
1362 createLoad(Builder, VSpan, Index, DoAlign && Index == NumSectors);
1370 if (!HVC.isSafeToMoveBeforeInBB(*
Load, BasePos))
1371 moveBefore(
Load->getIterator(), BasePos);
1373 LLVM_DEBUG(
dbgs() <<
"Loads[" << Index <<
"]:" << *Loads[Index] <<
'\n');
1379 for (
int Index = 0;
Index != NumSectors; ++
Index) {
1380 ASpan[
Index].Seg.Val =
nullptr;
1381 if (
auto *Where = EarliestUser[&ASpan[Index]]) {
1387 assert(NextLoad !=
nullptr);
1388 Val = HVC.vralignb(Builder, Val, NextLoad, AlignVal);
1390 ASpan[
Index].Seg.Val = Val;
1395 for (
const ByteSpan::Block &
B : VSpan) {
1396 ByteSpan ASection = ASpan.section(
B.Pos,
B.Seg.Size).shift(-
B.Pos);
1403 std::vector<ByteSpan::Block *> ABlocks;
1404 for (ByteSpan::Block &S : ASection) {
1405 if (S.Seg.Val !=
nullptr)
1406 ABlocks.push_back(&S);
1409 [&](
const ByteSpan::Block *
A,
const ByteSpan::Block *
B) {
1413 for (ByteSpan::Block *S : ABlocks) {
1418 Value *Pay = HVC.vbytes(Builder, getPayload(S->Seg.Val));
1420 HVC.insertb(Builder, Accum, Pay, S->Seg.Start, S->Seg.Size, S->Pos);
1428 Type *ValTy = getPayload(
B.Seg.Val)->getType();
1431 getPassThrough(
B.Seg.Val),
"sel");
1436auto AlignVectors::realignStoreGroup(IRBuilderBase &Builder,
1437 const ByteSpan &VSpan,
int ScLen,
1442 Type *SecTy = HVC.getByteTy(ScLen);
1443 int NumSectors = (VSpan.extent() + ScLen - 1) / ScLen;
1444 bool DoAlign = !HVC.isZero(AlignVal);
1447 ByteSpan ASpanV, ASpanM;
1451 auto MakeVec = [](IRBuilderBase &Builder,
Value *Val) ->
Value * {
1455 auto *VecTy = VectorType::get(Ty, 1,
false);
1461 for (
int Index = (DoAlign ? -1 : 0);
Index != NumSectors + DoAlign; ++
Index) {
1465 VSpan.section(Index * ScLen, ScLen).shift(-Index * ScLen);
1470 for (ByteSpan::Block &S : VSection) {
1471 Value *Pay = getPayload(S.Seg.Val);
1473 Pay->
getType(), HVC.getByteTy());
1474 Value *PartM = HVC.insertb(Builder, Zero, HVC.vbytes(Builder, Mask),
1475 S.Seg.Start, S.Seg.Size, S.Pos);
1476 AccumM = Builder.
CreateOr(AccumM, PartM);
1478 Value *PartV = HVC.insertb(Builder,
Undef, HVC.vbytes(Builder, Pay),
1479 S.Seg.Start, S.Seg.Size, S.Pos);
1484 ASpanV.Blocks.emplace_back(AccumV, ScLen, Index * ScLen);
1485 ASpanM.Blocks.emplace_back(AccumM, ScLen, Index * ScLen);
1489 dbgs() <<
"ASpanV before vlalign:\n" << ASpanV <<
'\n';
1490 dbgs() <<
"ASpanM before vlalign:\n" << ASpanM <<
'\n';
1495 for (
int Index = 1;
Index != NumSectors + 2; ++
Index) {
1496 Value *PrevV = ASpanV[
Index - 1].Seg.Val, *ThisV = ASpanV[
Index].Seg.Val;
1497 Value *PrevM = ASpanM[
Index - 1].Seg.Val, *ThisM = ASpanM[
Index].Seg.Val;
1499 ASpanV[
Index - 1].Seg.Val = HVC.vlalignb(Builder, PrevV, ThisV, AlignVal);
1500 ASpanM[
Index - 1].Seg.Val = HVC.vlalignb(Builder, PrevM, ThisM, AlignVal);
1505 dbgs() <<
"ASpanV after vlalign:\n" << ASpanV <<
'\n';
1506 dbgs() <<
"ASpanM after vlalign:\n" << ASpanM <<
'\n';
1509 auto createStore = [&](IRBuilderBase &Builder,
const ByteSpan &ASpanV,
1510 const ByteSpan &ASpanM,
int Index,
bool MakePred) {
1513 if (HVC.isUndef(Val) || HVC.isZero(Mask))
1516 createAdjustedPointer(Builder, AlignAddr, SecTy, Index * ScLen);
1518 MakePred ? makeTestIfUnaligned(Builder, AlignVal, ScLen) : nullptr;
1523 int Width = (1 + DoAlign) * ScLen;
1524 this->createStore(Builder, Val, Ptr, Predicate, ScLen,
1525 HVC.vlsb(Builder, Mask),
1526 VSpan.section(Start, Width).values());
1529 for (
int Index = 0;
Index != NumSectors + DoAlign; ++
Index) {
1530 createStore(Builder, ASpanV, ASpanM, Index, DoAlign && Index == NumSectors);
1534auto AlignVectors::realignGroup(
const MoveGroup &Move) ->
bool {
1543 auto getMaxOf = [](
auto Range,
auto GetValue) {
1545 return GetValue(
A) < GetValue(
B);
1549 AddrList &BaseInfos = AddrGroups[Move.Base];
1564 std::set<Instruction *> TestSet(Move.Main.begin(), Move.Main.end());
1568 BaseInfos, std::back_inserter(MoveInfos),
1569 [&TestSet](
const AddrInfo &AI) {
return TestSet.count(AI.Inst); });
1572 const AddrInfo &WithMaxAlign =
1573 getMaxOf(MoveInfos, [](
const AddrInfo &AI) {
return AI.HaveAlign; });
1574 Align MaxGiven = WithMaxAlign.HaveAlign;
1577 const AddrInfo &WithMinOffset =
1578 getMaxOf(MoveInfos, [](
const AddrInfo &AI) {
return -AI.Offset; });
1580 const AddrInfo &WithMaxNeeded =
1581 getMaxOf(MoveInfos, [](
const AddrInfo &AI) {
return AI.NeedAlign; });
1582 Align MinNeeded = WithMaxNeeded.NeedAlign;
1595 InstSimplifyFolder(HVC.DL));
1596 Value *AlignAddr =
nullptr;
1597 Value *AlignVal =
nullptr;
1599 if (MinNeeded <= MaxGiven) {
1600 int Start = WithMinOffset.Offset;
1601 int OffAtMax = WithMaxAlign.Offset;
1608 int Adjust = -
alignTo(OffAtMax - Start, MinNeeded.value());
1609 AlignAddr = createAdjustedPointer(Builder, WithMaxAlign.Addr,
1610 WithMaxAlign.ValTy, Adjust, Move.Clones);
1611 int Diff =
Start - (OffAtMax + Adjust);
1612 AlignVal = HVC.getConstInt(Diff);
1614 assert(
static_cast<decltype(MinNeeded.value())
>(Diff) < MinNeeded.value());
1624 createAlignedPointer(Builder, WithMinOffset.Addr, WithMinOffset.ValTy,
1625 MinNeeded.value(), Move.Clones);
1627 Builder.
CreatePtrToInt(WithMinOffset.Addr, HVC.getIntTy(),
"pti");
1629 for (
auto [Old, New] : Move.Clones)
1630 I->replaceUsesOfWith(Old, New);
1635 for (
const AddrInfo &AI : MoveInfos) {
1636 VSpan.Blocks.emplace_back(AI.Inst, HVC.getSizeOf(AI.ValTy),
1637 AI.Offset - WithMinOffset.Offset);
1644 : std::max<int>(MinNeeded.value(), 4);
1645 assert(!Move.IsHvx || ScLen == 64 || ScLen == 128);
1646 assert(Move.IsHvx || ScLen == 4 || ScLen == 8);
1649 dbgs() <<
"ScLen: " << ScLen <<
"\n";
1650 dbgs() <<
"AlignVal:" << *AlignVal <<
"\n";
1651 dbgs() <<
"AlignAddr:" << *AlignAddr <<
"\n";
1652 dbgs() <<
"VSpan:\n" << VSpan <<
'\n';
1656 realignLoadGroup(Builder, VSpan, ScLen, AlignVal, AlignAddr);
1658 realignStoreGroup(Builder, VSpan, ScLen, AlignVal, AlignAddr);
1661 HVC.ORE.
emit([&]() {
1662 return OptimizationRemark(
DEBUG_TYPE,
"VectorsAligned",
1664 <<
"aligned vector memory operations";
1667 for (
auto *Inst : Move.Main)
1668 Inst->eraseFromParent();
1673auto AlignVectors::makeTestIfUnaligned(IRBuilderBase &Builder,
Value *AlignVal,
1674 int Alignment)
const ->
Value * {
1675 auto *AlignTy = AlignVal->getType();
1677 AlignVal, ConstantInt::get(AlignTy, Alignment - 1),
"and");
1678 Value *
Zero = ConstantInt::get(AlignTy, 0);
1682auto AlignVectors::isSectorTy(
Type *Ty)
const ->
bool {
1683 if (!HVC.isByteVecTy(Ty))
1685 int Size = HVC.getSizeOf(Ty);
1691auto AlignVectors::run() ->
bool {
1694 if (!createAddressGroups())
1698 dbgs() <<
"Address groups(" << AddrGroups.
size() <<
"):\n";
1699 for (
auto &[In, AL] : AddrGroups) {
1700 for (
const AddrInfo &AI : AL)
1701 dbgs() <<
"---\n" << AI <<
'\n';
1706 MoveList LoadGroups, StoreGroups;
1708 for (
auto &
G : AddrGroups) {
1714 dbgs() <<
"\nLoad groups(" << LoadGroups.size() <<
"):\n";
1715 for (
const MoveGroup &
G : LoadGroups)
1716 dbgs() <<
G <<
"\n";
1717 dbgs() <<
"Store groups(" << StoreGroups.size() <<
"):\n";
1718 for (
const MoveGroup &
G : StoreGroups)
1719 dbgs() <<
G <<
"\n";
1723 unsigned CountLimit = VAGroupCountLimit;
1724 if (CountLimit == 0)
1727 if (LoadGroups.size() > CountLimit) {
1728 LoadGroups.resize(CountLimit);
1729 StoreGroups.clear();
1731 unsigned StoreLimit = CountLimit - LoadGroups.size();
1732 if (StoreGroups.size() > StoreLimit)
1733 StoreGroups.resize(StoreLimit);
1736 for (
auto &M : LoadGroups)
1738 for (
auto &M : StoreGroups)
1743 for (
auto &M : LoadGroups)
1745 for (
auto &M : StoreGroups)
1755auto HvxIdioms::getNumSignificantBits(
Value *V, Instruction *In)
const
1756 -> std::pair<unsigned, Signedness> {
1757 unsigned Bits = HVC.getNumSignificantBits(V, In);
1763 KnownBits
Known = HVC.getKnownBits(V, In);
1764 Signedness Sign =
Signed;
1765 unsigned NumToTest = 0;
1769 NumToTest =
Bits - 1;
1771 if (NumToTest != 0 &&
Known.Zero.ashr(NumToTest).isAllOnes()) {
1779 if (
Known.Zero.ashr(Pow2 - 1).isAllOnes())
1782 return {
Bits, Sign};
1785auto HvxIdioms::canonSgn(SValue
X, SValue
Y)
const
1786 -> std::pair<SValue, SValue> {
1799auto HvxIdioms::matchFxpMul(Instruction &In)
const -> std::optional<FxpOp> {
1800 using namespace PatternMatch;
1801 auto *Ty =
In.getType();
1804 return std::nullopt;
1813 auto m_Shr = [](
auto &&
V,
auto &&S) {
1825 if (
Op.Frac > Width)
1826 return std::nullopt;
1833 return std::nullopt;
1841 Op.Opcode = Instruction::Mul;
1843 Op.X.Sgn = getNumSignificantBits(
Op.X.Val, &In).second;
1844 Op.Y.Sgn = getNumSignificantBits(
Op.Y.Val, &In).second;
1849 return std::nullopt;
1852auto HvxIdioms::processFxpMul(Instruction &In,
const FxpOp &
Op)
const
1854 assert(
Op.X.Val->getType() ==
Op.Y.Val->getType());
1857 if (VecTy ==
nullptr)
1860 unsigned ElemWidth = ElemTy->getBitWidth();
1863 if ((HVC.length(VecTy) * ElemWidth) % (8 * HVC.HST.
getVectorLength()) != 0)
1873 if (ElemWidth <= 32 &&
Op.Frac == 0)
1876 auto [BitsX, SignX] = getNumSignificantBits(
Op.X.Val, &In);
1877 auto [BitsY, SignY] = getNumSignificantBits(
Op.Y.Val, &In);
1883 InstSimplifyFolder(HVC.DL));
1885 auto roundUpWidth = [](
unsigned Width) ->
unsigned {
1891 if (Width > 32 && Width % 32 != 0) {
1898 BitsX = roundUpWidth(BitsX);
1899 BitsY = roundUpWidth(BitsY);
1904 unsigned Width = std::max(BitsX, BitsY);
1906 auto *ResizeTy = VectorType::get(HVC.getIntTy(Width), VecTy);
1907 if (Width < ElemWidth) {
1910 }
else if (Width > ElemWidth) {
1917 assert(
X->getType() ==
Y->getType() &&
X->getType() == ResizeTy);
1919 unsigned VecLen = HVC.length(ResizeTy);
1920 unsigned ChopLen = (8 * HVC.HST.
getVectorLength()) / std::min(Width, 32u);
1924 ChopOp.ResTy = VectorType::get(
Op.ResTy->getElementType(), ChopLen,
false);
1926 for (
unsigned V = 0;
V != VecLen / ChopLen; ++
V) {
1927 ChopOp.X.Val = HVC.subvector(Builder,
X, V * ChopLen, ChopLen);
1928 ChopOp.Y.Val = HVC.subvector(Builder,
Y, V * ChopLen, ChopLen);
1929 Results.push_back(processFxpMulChopped(Builder, In, ChopOp));
1944inline bool HvxIdioms::matchScatter(Instruction &In)
const {
1948 return (
II->getIntrinsicID() == Intrinsic::masked_scatter);
1951inline bool HvxIdioms::matchGather(Instruction &In)
const {
1955 return (
II->getIntrinsicID() == Intrinsic::masked_gather);
1958inline bool HvxIdioms::matchMLoad(Instruction &In)
const {
1962 return (
II->getIntrinsicID() == Intrinsic::masked_load);
1965inline bool HvxIdioms::matchMStore(Instruction &In)
const {
1969 return (
II->getIntrinsicID() == Intrinsic::masked_store);
1977 case Instruction::Add:
1978 case Instruction::Sub:
1979 case Instruction::Mul:
1980 case Instruction::And:
1981 case Instruction::Or:
1982 case Instruction::Xor:
1983 case Instruction::AShr:
1984 case Instruction::LShr:
1985 case Instruction::Shl:
1986 case Instruction::UDiv:
1994 assert(Ptr &&
"Unable to extract pointer");
2000 if (
II->getIntrinsicID() == Intrinsic::masked_store)
2001 return II->getOperand(1);
2007 HvxIdioms::DstQualifier &Qual) {
2013 Qual = HvxIdioms::LdSt;
2015 if (
II->getIntrinsicID() == Intrinsic::masked_gather) {
2017 Qual = HvxIdioms::LLVM_Gather;
2018 }
else if (
II->getIntrinsicID() == Intrinsic::masked_scatter) {
2020 Qual = HvxIdioms::LLVM_Scatter;
2021 }
else if (
II->getIntrinsicID() == Intrinsic::masked_store) {
2023 Qual = HvxIdioms::LdSt;
2024 }
else if (
II->getIntrinsicID() ==
2025 Intrinsic::hexagon_V6_vgather_vscattermh) {
2027 Qual = HvxIdioms::HEX_Gather_Scatter;
2028 }
else if (
II->getIntrinsicID() == Intrinsic::hexagon_V6_vscattermh_128B) {
2030 Qual = HvxIdioms::HEX_Scatter;
2031 }
else if (
II->getIntrinsicID() == Intrinsic::hexagon_V6_vgathermh_128B) {
2033 Qual = HvxIdioms::HEX_Gather;
2041 Qual = HvxIdioms::Call;
2046 Qual = HvxIdioms::Arithmetic;
2066 for (
auto &U : In->uses()) {
2070 Users.push_back(Destination);
2082 assert(In &&
"Bad instruction");
2086 "Not a gather Intrinsic");
2115 if (
II &&
II->getIntrinsicID() == Intrinsic::masked_gather)
2125 auto *Src = IE->getOperand(1);
2140 LLVM_DEBUG(
dbgs() <<
" Unable to locate Address from intrinsic\n");
2152 if (
II->getIntrinsicID() == Intrinsic::masked_load)
2153 return II->getType();
2154 if (
II->getIntrinsicID() == Intrinsic::masked_store)
2155 return II->getOperand(0)->getType();
2157 return In->getType();
2166 if (
II->getIntrinsicID() == Intrinsic::masked_load)
2168 if (
II->getIntrinsicID() == Intrinsic::masked_gather)
2180 return cstDataVector;
2182 return GEPIndex->getOperand(0);
2198 LLVM_DEBUG(
dbgs() <<
" Unable to locate Index from intrinsic\n");
2208 assert(
I &&
"Unable to reinterprete cast");
2209 Type *NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2210 std::vector<unsigned> shuffleMask;
2211 for (
unsigned i = 0; i < 64; ++i)
2212 shuffleMask.push_back(i);
2214 Value *CastShuffle =
2215 Builder.CreateShuffleVector(
I,
I, Mask,
"identity_shuffle");
2216 return Builder.CreateBitCast(CastShuffle, NT,
"cst64_i16_to_32_i32");
2223 assert(
I &&
"Unable to reinterprete cast");
2224 Type *NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2225 std::vector<unsigned> shuffleMask;
2226 for (
unsigned i = 0; i < 128; ++i)
2227 shuffleMask.push_back(i);
2229 Value *CastShuffle =
2230 Builder.CreateShuffleVector(
I,
I, Mask,
"identity_shuffle");
2231 return Builder.CreateBitCast(CastShuffle, NT,
"cst128_i8_to_32_i32");
2237 unsigned int pattern) {
2238 std::vector<unsigned int> byteMask;
2239 for (
unsigned i = 0; i < 32; ++i)
2240 byteMask.push_back(pattern);
2242 return Builder.CreateIntrinsic(
2244 {llvm::ConstantDataVector::get(Ctx, byteMask), HVC.getConstInt(~0)},
2248Value *HvxIdioms::processVScatter(Instruction &In)
const {
2250 assert(InpTy &&
"Cannot handle no vector type for llvm.scatter/gather");
2251 unsigned InpSize = HVC.getSizeOf(InpTy);
2252 auto *
F =
In.getFunction();
2253 LLVMContext &Ctx =
F->getContext();
2255 assert(ElemTy &&
"llvm.scatter needs integer type argument");
2258 unsigned Elements = HVC.length(InpTy);
2259 dbgs() <<
"\n[Process scatter](" <<
In <<
")\n" << *
In.getParent() <<
"\n";
2260 dbgs() <<
" Input type(" << *InpTy <<
") elements(" <<
Elements
2261 <<
") VecLen(" << InpSize <<
") type(" << *ElemTy <<
") ElemWidth("
2262 << ElemWidth <<
")\n";
2266 InstSimplifyFolder(HVC.DL));
2268 auto *ValueToScatter =
In.getOperand(0);
2269 LLVM_DEBUG(
dbgs() <<
" ValueToScatter : " << *ValueToScatter <<
"\n");
2273 <<
") for vscatter\n");
2298 Value *CastIndex =
nullptr;
2299 if (cstDataVector) {
2301 Type *IndexVectorType = HVC.getHvxTy(HVC.getIntTy(32),
false);
2302 AllocaInst *IndexesAlloca = Builder.
CreateAlloca(IndexVectorType);
2303 [[maybe_unused]]
auto *StoreIndexes =
2304 Builder.
CreateStore(cstDataVector, IndexesAlloca);
2305 LLVM_DEBUG(
dbgs() <<
" StoreIndexes : " << *StoreIndexes <<
"\n");
2307 Builder.
CreateLoad(IndexVectorType, IndexesAlloca,
"reload_index");
2312 CastIndex = Indexes;
2316 if (ElemWidth == 1) {
2319 Type *
NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2325 HVC.getHvxTy(HVC.getIntTy(32),
true), V6_vunpack, CastIndexes,
nullptr);
2326 LLVM_DEBUG(
dbgs() <<
" UnpackedIndexes : " << *UnpackedIndexes <<
")\n");
2330 [[maybe_unused]]
Value *IndexHi =
2331 HVC.createHvxIntrinsic(Builder, V6_hi, NT, UnpackedIndexes);
2332 [[maybe_unused]]
Value *IndexLo =
2333 HVC.createHvxIntrinsic(Builder, V6_lo, NT, UnpackedIndexes);
2341 HVC.getHvxTy(HVC.getIntTy(32),
true), V6_vunpack, CastSrc,
nullptr);
2342 LLVM_DEBUG(
dbgs() <<
" UnpackedValToScat: " << *UnpackedValueToScatter
2345 [[maybe_unused]]
Value *UVSHi =
2346 HVC.createHvxIntrinsic(Builder, V6_hi, NT, UnpackedValueToScatter);
2347 [[maybe_unused]]
Value *UVSLo =
2348 HVC.createHvxIntrinsic(Builder, V6_lo, NT, UnpackedValueToScatter);
2353 auto *QByteMask =
get_i32_Mask(HVC, Builder, Ctx, 0x00ff00ff);
2356 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermhq_128B,
2362 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermhq_128B,
2366 }
else if (ElemWidth == 2) {
2371 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermh_128B,
2375 }
else if (ElemWidth == 4) {
2377 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermw_128B,
2387Value *HvxIdioms::processVGather(Instruction &In)
const {
2388 [[maybe_unused]]
auto *InpTy =
2390 assert(InpTy &&
"Cannot handle no vector type for llvm.gather");
2391 [[maybe_unused]]
auto *ElemTy =
2393 assert(ElemTy &&
"llvm.gather needs vector of ptr argument");
2394 auto *
F =
In.getFunction();
2395 LLVMContext &Ctx =
F->getContext();
2397 << *
In.getParent() <<
"\n");
2399 << HVC.length(InpTy) <<
") VecLen(" << HVC.getSizeOf(InpTy)
2400 <<
") type(" << *ElemTy <<
") Access alignment("
2401 << *
In.getOperand(1) <<
") AddressSpace("
2402 << ElemTy->getAddressSpace() <<
")\n");
2406 "llvm.gather needs vector for mask");
2408 InstSimplifyFolder(HVC.DL));
2413 HvxIdioms::DstQualifier Qual = HvxIdioms::Undefined;
2419 LLVM_DEBUG(
dbgs() <<
" Destination : " << *Dst <<
" Qual(" << Qual
2425 LLVM_DEBUG(
dbgs() <<
"Could not locate vgather destination ptr\n");
2431 assert(DstType &&
"Cannot handle non vector dst type for llvm.gather");
2445 Value *Gather =
nullptr;
2446 Type *
NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2447 if (Qual == HvxIdioms::LdSt || Qual == HvxIdioms::Arithmetic) {
2451 unsigned OutputSize = HVC.getSizeOf(DstType);
2455 <<
" Address space ("
2457 <<
" Result type : " << *DstType
2458 <<
"\n Size in bytes : " << OutputSize
2459 <<
" element type(" << *DstElemTy
2460 <<
")\n ElemWidth : " << ElemWidth <<
" bytes\n");
2463 assert(IndexType &&
"Cannot handle non vector index type for llvm.gather");
2464 unsigned IndexWidth = HVC.DL.
getTypeAllocSize(IndexType->getElementType());
2469 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2478 if (ElemWidth == 1) {
2483 Value *CastIndexes =
2486 auto *UnpackedIndexes =
2488 V6_vunpack, CastIndexes,
nullptr);
2494 [[maybe_unused]]
Value *IndexHi =
2495 HVC.createHvxIntrinsic(Builder, V6_hi, NT, UnpackedIndexes);
2496 [[maybe_unused]]
Value *IndexLo =
2497 HVC.createHvxIntrinsic(Builder, V6_lo, NT, UnpackedIndexes);
2501 auto *QByteMask =
get_i32_Mask(HVC, Builder, Ctx, 0x00ff00ff);
2505 auto V6_vgather = HVC.HST.
getIntrinsicId(Hexagon::V6_vgathermhq);
2507 Type::getVoidTy(Ctx), V6_vgather,
2508 {Ptr, QByteMask, CastedPtr,
2514 HVC.getHvxTy(HVC.getIntTy(32),
false), Ptr,
"temp_result_hi");
2515 LLVM_DEBUG(
dbgs() <<
" LoadedResultHi : " << *LoadedResultHi <<
"\n");
2520 Type::getVoidTy(Ctx), V6_vgather,
2521 {Ptr, QByteMask, CastedPtr,
2526 HVC.getHvxTy(HVC.getIntTy(32),
false), Ptr,
"temp_result_lo");
2527 LLVM_DEBUG(
dbgs() <<
" LoadedResultLo : " << *LoadedResultLo <<
"\n");
2534 NT, V6_vpackeb, {LoadedResultHi, LoadedResultLo},
nullptr);
2536 [[maybe_unused]]
auto *StoreRes = Builder.
CreateStore(Res, Ptr);
2538 }
else if (ElemWidth == 2) {
2540 if (IndexWidth == 2) {
2548 Value *AdjustedIndex = HVC.createHvxIntrinsic(
2549 Builder, V6_vaslh, NT, {CastIndex, HVC.getConstInt(1)});
2551 <<
" Shifted half index: " << *AdjustedIndex <<
")\n");
2557 Type::getVoidTy(Ctx), V6_vgather,
2561 for (
auto &U : Dst->uses()) {
2563 dbgs() <<
" dst used by: " << *UI <<
"\n";
2565 for (
auto &U :
In.uses()) {
2567 dbgs() <<
" In used by : " << *UI <<
"\n";
2572 HVC.getHvxTy(HVC.getIntTy(16),
false), Ptr,
"temp_result");
2573 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2574 In.replaceAllUsesWith(LoadedResult);
2576 dbgs() <<
" Unhandled index type for vgather\n";
2579 }
else if (ElemWidth == 4) {
2580 if (IndexWidth == 4) {
2583 Value *AdjustedIndex = HVC.createHvxIntrinsic(
2584 Builder, V6_vaslh, NT, {Indexes, HVC.getConstInt(2)});
2586 <<
" Shifted word index: " << *AdjustedIndex <<
")\n");
2588 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermw_128B,
2611 Dst->eraseFromParent();
2612 }
else if (Qual == HvxIdioms::LLVM_Scatter) {
2616 assert(DstInpTy &&
"Cannot handle no vector type for llvm.scatter");
2617 unsigned DstInpSize = HVC.getSizeOf(DstInpTy);
2618 unsigned DstElements = HVC.length(DstInpTy);
2620 assert(DstElemTy &&
"llvm.scatter needs vector of ptr argument");
2621 dbgs() <<
" Gather feeds into scatter\n Values to scatter : "
2622 << *Dst->getOperand(0) <<
"\n";
2623 dbgs() <<
" Dst type(" << *DstInpTy <<
") elements(" << DstElements
2624 <<
") VecLen(" << DstInpSize <<
") type(" << *DstElemTy
2625 <<
") Access alignment(" << *Dst->getOperand(2) <<
")\n";
2639 Src, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2659 Value *AdjustedIndex = HVC.createHvxIntrinsic(
2660 Builder, V6_vaslh, NT, {CastIndex, HVC.getConstInt(1)});
2661 LLVM_DEBUG(
dbgs() <<
" Shifted half index: " << *AdjustedIndex <<
")\n");
2664 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2668 }
else if (Qual == HvxIdioms::HEX_Gather_Scatter) {
2676 if (cstDataVector) {
2681 [[maybe_unused]]
auto *StoreIndexes =
2682 Builder.
CreateStore(cstDataVector, IndexesAlloca);
2683 LLVM_DEBUG(
dbgs() <<
" StoreIndexes : " << *StoreIndexes <<
"\n");
2684 Value *LoadedIndex =
2685 Builder.
CreateLoad(NT, IndexesAlloca,
"reload_index");
2687 LLVM_DEBUG(
dbgs() <<
" ResultAlloca : " << *ResultAlloca <<
"\n");
2690 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2694 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2695 {ResultAlloca, CastedSrc,
2699 HVC.getHvxTy(HVC.getIntTy(16),
false), ResultAlloca,
"temp_result");
2700 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2702 In.replaceAllUsesWith(LoadedResult);
2712 Src, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2725 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgather_vscattermh,
2731 }
else if (Qual == HvxIdioms::HEX_Scatter) {
2738 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2745 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2750 HVC.getHvxTy(HVC.getIntTy(16),
false), ResultAlloca,
"temp_result");
2751 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2752 In.replaceAllUsesWith(LoadedResult);
2753 }
else if (Qual == HvxIdioms::HEX_Gather) {
2758 if (cstDataVector) {
2762 [[maybe_unused]]
auto *StoreIndexes =
2763 Builder.
CreateStore(cstDataVector, IndexesAlloca);
2764 LLVM_DEBUG(
dbgs() <<
" StoreIndexes : " << *StoreIndexes <<
"\n");
2765 Value *LoadedIndex =
2766 Builder.
CreateLoad(NT, IndexesAlloca,
"reload_index");
2769 <<
"\n AddressSpace: "
2773 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2777 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2778 {ResultAlloca, CastedSrc,
2782 HVC.getHvxTy(HVC.getIntTy(16),
false), ResultAlloca,
"temp_result");
2783 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2785 In.replaceAllUsesWith(LoadedResult);
2788 }
else if (Qual == HvxIdioms::LLVM_Gather) {
2790 errs() <<
" Underimplemented vgather to vgather sequence\n";
2800std::optional<uint64_t> HvxIdioms::getPHIBaseMinAlignment(Instruction &In,
2801 PHINode *PN)
const {
2803 return std::nullopt;
2805 SmallVector<Value *, 16> Worklist;
2806 SmallPtrSet<Value *, 16> Visited;
2807 uint64_t minPHIAlignment = Value::MaximumAlignment;
2810 while (!Worklist.
empty()) {
2813 if (!Visited.
insert(V).second)
2825 if (KnownAlign.
value() < minPHIAlignment)
2826 minPHIAlignment = KnownAlign.
value();
2829 if (minPHIAlignment != Value::MaximumAlignment)
2830 return minPHIAlignment;
2831 return std::nullopt;
2835std::optional<uint64_t> HvxIdioms::getAlignment(Instruction &In,
2837 SmallPtrSet<Value *, 16> Visited;
2838 return getAlignmentImpl(In, ptr, Visited);
2841std::optional<uint64_t>
2842HvxIdioms::getAlignmentImpl(Instruction &In,
Value *ptr,
2843 SmallPtrSet<Value *, 16> &Visited)
const {
2846 if (!Visited.
insert(ptr).second)
2847 return std::nullopt;
2851 if (KnownAlign.
value() > 1) {
2853 return KnownAlign.
value();
2859 auto baseAlignmentOpt = getPHIBaseMinAlignment(In, PN);
2860 if (!baseAlignmentOpt)
2861 return std::nullopt;
2863 uint64_t minBaseAlignment = *baseAlignmentOpt;
2865 if (minBaseAlignment == 1)
2868 uint64_t minPHIAlignment = minBaseAlignment;
2870 <<
")nodes and min base aligned to (" << minBaseAlignment
2877 uint64_t MemberAlignment = Value::MaximumAlignment;
2879 MemberAlignment = *res;
2881 return std::nullopt;
2883 if (minPHIAlignment > MemberAlignment)
2884 minPHIAlignment = MemberAlignment;
2886 LLVM_DEBUG(
dbgs() <<
" total PHI alignment(" << minPHIAlignment <<
")\n");
2887 return minPHIAlignment;
2891 auto *GEPPtr =
GEP->getPointerOperand();
2894 if (&In == GEPPtr) {
2896 GEPPtr->getType()->getPointerAddressSpace()),
2898 if (
GEP->accumulateConstantOffset(HVC.DL,
Offset)) {
2900 <<
Offset.getZExtValue() <<
")\n");
2901 return Offset.getZExtValue();
2906 return std::nullopt;
2909Value *HvxIdioms::processMStore(Instruction &In)
const {
2910 [[maybe_unused]]
auto *InpTy =
2912 assert(InpTy &&
"Cannot handle no vector type for llvm.masked.store");
2915 << *
In.getParent() <<
"\n");
2917 << HVC.length(InpTy) <<
") VecLen(" << HVC.getSizeOf(InpTy)
2918 <<
") type(" << *InpTy->getElementType() <<
") of size("
2919 << InpTy->getScalarSizeInBits() <<
")bits\n");
2921 assert(CI &&
"Expected llvm.masked.store to be a call");
2922 Align HaveAlign = CI->getParamAlign(1).valueOrOne();
2930 Type *ValTy =
In.getOperand(0)->getType();
2934 if (EffA < HaveAlign)
2938 AttrBuilder AttrB(CI->getContext());
2939 AttrB.addAlignmentAttr(EffA);
2941 CI->getAttributes().addParamAttributes(CI->getContext(), 1, AttrB));
2945Value *HvxIdioms::processMLoad(Instruction &In)
const {
2947 assert(InpTy &&
"Cannot handle non vector type for llvm.masked.store");
2949 << *
In.getParent() <<
"\n");
2951 << HVC.length(InpTy) <<
") VecLen(" << HVC.getSizeOf(InpTy)
2952 <<
") type(" << *InpTy->getElementType() <<
") of size("
2953 << InpTy->getScalarSizeInBits() <<
")bits\n");
2955 assert(CI &&
"Expected to be a call to llvm.masked.load");
2957 Align HaveAlign = CI->getParamAlign(0).valueOrOne();
2965 Type *ValTy =
In.getType();
2968 if (EffA < HaveAlign)
2974 AttrBuilder AttrB(CI->getContext());
2975 AttrB.addAlignmentAttr(EffA);
2977 CI->getAttributes().addParamAttributes(CI->getContext(), 0, AttrB));
2981auto HvxIdioms::processFxpMulChopped(IRBuilderBase &Builder, Instruction &In,
2982 const FxpOp &
Op)
const ->
Value * {
2983 assert(
Op.X.Val->getType() ==
Op.Y.Val->getType());
2985 unsigned Width = InpTy->getScalarSizeInBits();
2988 if (!
Op.RoundAt || *
Op.RoundAt ==
Op.Frac - 1) {
2991 Value *QMul =
nullptr;
2993 QMul = createMulQ15(Builder,
Op.X,
Op.Y, Rounding);
2994 }
else if (Width == 32) {
2995 QMul = createMulQ31(Builder,
Op.X,
Op.Y, Rounding);
2997 if (QMul !=
nullptr)
3003 assert(Width < 32 || Width % 32 == 0);
3013 assert(
Op.Frac != 0 &&
"Unshifted mul should have been skipped");
3014 if (
Op.Frac == 16) {
3016 if (
Value *MulH = createMulH16(Builder,
Op.X,
Op.Y))
3020 Value *Prod32 = createMul16(Builder,
Op.X,
Op.Y);
3023 ConstantInt::get(Prod32->
getType(), 1ull << *
Op.RoundAt);
3024 Prod32 = Builder.
CreateAdd(Prod32, RoundVal,
"add");
3029 ? Builder.
CreateAShr(Prod32, ShiftAmt,
"asr")
3030 : Builder.
CreateLShr(Prod32, ShiftAmt,
"lsr");
3031 return Builder.
CreateTrunc(Shifted, InpTy,
"trn");
3038 auto WordX = HVC.splitVectorElements(Builder,
Op.X.Val, 32);
3039 auto WordY = HVC.splitVectorElements(Builder,
Op.Y.Val, 32);
3040 auto WordP = createMulLong(Builder, WordX,
Op.X.Sgn, WordY,
Op.Y.Sgn);
3045 if (
Op.RoundAt.has_value()) {
3048 RoundV[*
Op.RoundAt / 32] =
3049 ConstantInt::get(HvxWordTy, 1ull << (*
Op.RoundAt % 32));
3050 WordP = createAddLong(Builder, WordP, RoundV);
3056 unsigned SkipWords =
Op.Frac / 32;
3057 Constant *ShiftAmt = ConstantInt::get(HvxWordTy,
Op.Frac % 32);
3059 for (
int Dst = 0, End = WordP.size() - SkipWords; Dst != End; ++Dst) {
3060 int Src = Dst + SkipWords;
3062 if (Src + 1 < End) {
3073 WordP.resize(WordP.size() - SkipWords);
3075 return HVC.joinVectorElements(Builder, WordP,
Op.ResTy);
3078auto HvxIdioms::createMulQ15(IRBuilderBase &Builder, SValue
X, SValue
Y,
3079 bool Rounding)
const ->
Value * {
3080 assert(
X.Val->getType() ==
Y.Val->getType());
3081 assert(
X.Val->getType()->getScalarType() == HVC.getIntTy(16));
3088 auto V6_vmpyhvsrs = HVC.HST.
getIntrinsicId(Hexagon::V6_vmpyhvsrs);
3089 return HVC.createHvxIntrinsic(Builder, V6_vmpyhvsrs,
X.Val->getType(),
3093auto HvxIdioms::createMulQ31(IRBuilderBase &Builder, SValue
X, SValue
Y,
3094 bool Rounding)
const ->
Value * {
3095 Type *InpTy =
X.Val->getType();
3096 assert(InpTy ==
Y.Val->getType());
3108 HVC.createHvxIntrinsic(Builder, V6_vmpyewuh, InpTy, {
X.Val,
Y.Val});
3109 return HVC.createHvxIntrinsic(Builder, V6_vmpyo_acc, InpTy,
3110 {
V1,
X.Val,
Y.Val});
3113auto HvxIdioms::createAddCarry(IRBuilderBase &Builder,
Value *
X,
Value *
Y,
3114 Value *CarryIn)
const
3115 -> std::pair<Value *, Value *> {
3116 assert(
X->getType() ==
Y->getType());
3125 if (CarryIn ==
nullptr)
3127 Args.push_back(CarryIn);
3129 Value *Ret = HVC.createHvxIntrinsic(Builder, AddCarry,
3133 return {
Result, CarryOut};
3140 if (CarryIn !=
nullptr) {
3141 unsigned Width = VecTy->getScalarSizeInBits();
3144 for (
unsigned i = 0, e = 32 / Width; i !=
e; ++i)
3145 Mask = (Mask << Width) | 1;
3149 HVC.createHvxIntrinsic(Builder, V6_vandqrt,
nullptr,
3150 {CarryIn, HVC.getConstInt(Mask)});
3151 Result1 = Builder.
CreateAdd(
X, ValueIn,
"add");
3157 return {Result2, Builder.
CreateOr(CarryOut1, CarryOut2,
"orb")};
3160auto HvxIdioms::createMul16(IRBuilderBase &Builder, SValue
X, SValue
Y)
const
3163 std::tie(
X,
Y) = canonSgn(
X,
Y);
3176 HVC.createHvxIntrinsic(Builder, V6_vmpyh, HvxP32Ty, {
Y.Val,
X.Val});
3178 return HVC.vshuff(Builder, HVC.sublo(Builder,
P), HVC.subhi(Builder,
P));
3181auto HvxIdioms::createMulH16(IRBuilderBase &Builder, SValue
X, SValue
Y)
const
3183 Type *HvxI16Ty = HVC.getHvxTy(HVC.getIntTy(16),
false);
3188 return HVC.createHvxIntrinsic(Builder, V6_vmpyuhvs, HvxI16Ty,
3193 Type *HvxP16Ty = HVC.getHvxTy(HVC.getIntTy(16),
true);
3196 unsigned Len = HVC.length(HvxP16Ty) / 2;
3198 SmallVector<int, 128> PickOdd(Len);
3199 for (
int i = 0; i !=
static_cast<int>(
Len); ++i)
3200 PickOdd[i] = 2 * i + 1;
3203 HVC.sublo(Builder, Pair16), HVC.subhi(Builder, Pair16), PickOdd,
"shf");
3206auto HvxIdioms::createMul32(IRBuilderBase &Builder, SValue
X, SValue
Y)
const
3207 -> std::pair<Value *, Value *> {
3208 assert(
X.Val->getType() ==
Y.Val->getType());
3209 assert(
X.Val->getType() == HvxI32Ty);
3212 std::tie(
X,
Y) = canonSgn(
X,
Y);
3215 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyss_parts;
3217 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyus_parts;
3219 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyuu_parts;
3222 Value *Parts = HVC.createHvxIntrinsic(Builder, V6_vmpy_parts,
nullptr,
3223 {
X.Val,
Y.Val}, {HvxI32Ty});
3232 assert(WordX.size() == WordY.size());
3233 unsigned Idx = 0,
Length = WordX.size();
3237 if (HVC.isZero(WordX[Idx]))
3238 Sum[Idx] = WordY[Idx];
3239 else if (HVC.isZero(WordY[Idx]))
3240 Sum[Idx] = WordX[Idx];
3246 Value *Carry =
nullptr;
3247 for (; Idx !=
Length; ++Idx) {
3248 std::tie(Sum[Idx], Carry) =
3249 createAddCarry(Builder, WordX[Idx], WordY[Idx], Carry);
3263 for (
int i = 0, e = WordX.size(); i != e; ++i) {
3264 for (
int j = 0, f = WordY.size(); j != f; ++j) {
3266 Signedness SX = (i + 1 ==
e) ? SgnX :
Unsigned;
3268 auto [
Lo,
Hi] = createMul32(Builder, {WordX[i], SX}, {WordY[
j],
SY});
3269 Products[i +
j + 0].push_back(
Lo);
3270 Products[i +
j + 1].push_back(
Hi);
3284 for (
int i = 0, e = Products.size(); i != e; ++i) {
3285 while (Products[i].
size() > 1) {
3286 Value *Carry =
nullptr;
3287 for (
int j = i;
j !=
e; ++
j) {
3288 auto &ProdJ = Products[
j];
3289 auto [Sum, CarryOut] = createAddCarry(Builder, pop_back_or_zero(ProdJ),
3290 pop_back_or_zero(ProdJ), Carry);
3291 ProdJ.insert(ProdJ.begin(), Sum);
3298 for (
auto &
P : Products) {
3299 assert(
P.size() == 1 &&
"Should have been added together");
3306auto HvxIdioms::run() ->
bool {
3309 for (BasicBlock &
B : HVC.F) {
3310 for (
auto It =
B.rbegin(); It !=
B.rend(); ++It) {
3311 if (
auto Fxm = matchFxpMul(*It)) {
3312 Value *
New = processFxpMul(*It, *Fxm);
3318 It->replaceAllUsesWith(New);
3320 It = StartOver ?
B.rbegin()
3323 }
else if (matchGather(*It)) {
3329 It->eraseFromParent();
3333 }
else if (matchScatter(*It)) {
3339 It->eraseFromParent();
3343 }
else if (matchMLoad(*It)) {
3349 }
else if (matchMStore(*It)) {
3364auto HexagonVectorCombine::run() ->
bool {
3366 dbgs() <<
"Module before HexagonVectorCombine\n" << *
F.getParent();
3369 if (HST.useHVXOps()) {
3371 Changed |= AlignVectors(*this).run();
3373 Changed |= HvxIdioms(*this).run();
3377 dbgs() <<
"Module " << (
Changed ?
"(modified)" :
"(unchanged)")
3378 <<
" after HexagonVectorCombine\n"
3384auto HexagonVectorCombine::getIntTy(
unsigned Width)
const -> IntegerType * {
3388auto HexagonVectorCombine::getByteTy(
int ElemCount)
const ->
Type * {
3390 IntegerType *ByteTy = Type::getInt8Ty(
F.getContext());
3393 return VectorType::get(ByteTy, ElemCount,
false);
3396auto HexagonVectorCombine::getBoolTy(
int ElemCount)
const ->
Type * {
3398 IntegerType *BoolTy = Type::getInt1Ty(
F.getContext());
3401 return VectorType::get(BoolTy, ElemCount,
false);
3404auto HexagonVectorCombine::getConstInt(
int Val,
unsigned Width)
const
3409auto HexagonVectorCombine::isZero(
const Value *Val)
const ->
bool {
3411 return C->isNullValue();
3415auto HexagonVectorCombine::getIntValue(
const Value *Val)
const
3416 -> std::optional<APInt> {
3418 return CI->getValue();
3419 return std::nullopt;
3422auto HexagonVectorCombine::isUndef(
const Value *Val)
const ->
bool {
3426auto HexagonVectorCombine::isTrue(
const Value *Val)
const ->
bool {
3430auto HexagonVectorCombine::isFalse(
const Value *Val)
const ->
bool {
3434auto HexagonVectorCombine::getHvxTy(
Type *ElemTy,
bool Pair)
const
3440 "Invalid HVX element type");
3441 unsigned HwLen = HST.getVectorLength();
3443 return VectorType::get(ElemTy, Pair ? 2 * NumElems : NumElems,
3447auto HexagonVectorCombine::getSizeOf(
const Value *Val, SizeKind Kind)
const
3449 return getSizeOf(Val->
getType(), Kind);
3452auto HexagonVectorCombine::getSizeOf(
const Type *Ty, SizeKind Kind)
const
3454 auto *NcTy =
const_cast<Type *
>(Ty);
3457 return DL.getTypeStoreSize(NcTy).getFixedValue();
3459 return DL.getTypeAllocSize(NcTy).getFixedValue();
3464auto HexagonVectorCombine::getTypeAlignment(
Type *Ty)
const ->
int {
3467 if (HST.isTypeForHVX(Ty))
3468 return HST.getVectorLength();
3469 return DL.getABITypeAlign(Ty).value();
3472auto HexagonVectorCombine::length(
Value *Val)
const ->
size_t {
3473 return length(Val->
getType());
3476auto HexagonVectorCombine::length(
Type *Ty)
const ->
size_t {
3478 assert(VecTy &&
"Must be a vector type");
3479 return VecTy->getElementCount().getFixedValue();
3482auto HexagonVectorCombine::simplify(
Value *V)
const ->
Value * {
3484 SimplifyQuery Q(
DL, &TLI, &DT, &AC, In);
3491auto HexagonVectorCombine::insertb(IRBuilderBase &Builder,
Value *Dst,
3493 int Where)
const ->
Value * {
3494 assert(isByteVecTy(Dst->getType()) && isByteVecTy(Src->getType()));
3495 int SrcLen = getSizeOf(Src);
3496 int DstLen = getSizeOf(Dst);
3502 Value *P2Src = vresize(Builder, Src, P2Len,
Poison);
3503 Value *P2Dst = vresize(Builder, Dst, P2Len,
Poison);
3506 for (
int i = 0; i != P2Len; ++i) {
3510 (Where <= i && i < Where +
Length) ? P2Len + Start + (i - Where) : i;
3514 return vresize(Builder, P2Insert, DstLen,
Poison);
3517auto HexagonVectorCombine::vlalignb(IRBuilderBase &Builder,
Value *
Lo,
3519 assert(
Lo->getType() ==
Hi->getType() &&
"Argument type mismatch");
3522 int VecLen = getSizeOf(
Hi);
3523 if (
auto IntAmt = getIntValue(Amt))
3524 return getElementRange(Builder,
Lo,
Hi, VecLen - IntAmt->getSExtValue(),
3527 if (HST.isTypeForHVX(
Hi->getType())) {
3528 assert(
static_cast<unsigned>(VecLen) == HST.getVectorLength() &&
3529 "Expecting an exact HVX type");
3530 return createHvxIntrinsic(Builder, HST.getIntrinsicId(Hexagon::V6_vlalignb),
3531 Hi->getType(), {Hi, Lo, Amt});
3539 Builder.
CreateTrunc(Shift, Type::getInt32Ty(
F.getContext()),
"trn");
3544 return vralignb(Builder,
Lo,
Hi,
Sub);
3549auto HexagonVectorCombine::vralignb(IRBuilderBase &Builder,
Value *
Lo,
3551 assert(
Lo->getType() ==
Hi->getType() &&
"Argument type mismatch");
3554 int VecLen = getSizeOf(
Lo);
3555 if (
auto IntAmt = getIntValue(Amt))
3556 return getElementRange(Builder,
Lo,
Hi, IntAmt->getSExtValue(), VecLen);
3558 if (HST.isTypeForHVX(
Lo->getType())) {
3559 assert(
static_cast<unsigned>(VecLen) == HST.getVectorLength() &&
3560 "Expecting an exact HVX type");
3561 return createHvxIntrinsic(Builder, HST.getIntrinsicId(Hexagon::V6_valignb),
3562 Lo->getType(), {Hi, Lo, Amt});
3569 Builder.
CreateTrunc(Shift, Type::getInt32Ty(
F.getContext()),
"trn");
3573 Type *Int64Ty = Type::getInt64Ty(
F.getContext());
3585auto HexagonVectorCombine::concat(IRBuilderBase &Builder,
3589 std::vector<Value *> Work[2];
3590 int ThisW = 0, OtherW = 1;
3592 Work[ThisW].assign(Vecs.begin(), Vecs.end());
3593 while (Work[ThisW].
size() > 1) {
3595 SMask.
resize(length(Ty) * 2);
3596 std::iota(SMask.
begin(), SMask.
end(), 0);
3598 Work[OtherW].clear();
3599 if (Work[ThisW].
size() % 2 != 0)
3601 for (
int i = 0, e = Work[ThisW].
size(); i <
e; i += 2) {
3603 Work[ThisW][i], Work[ThisW][i + 1], SMask,
"shf");
3604 Work[OtherW].push_back(Joined);
3612 SMask.
resize(Vecs.size() * length(Vecs.front()->getType()));
3613 std::iota(SMask.
begin(), SMask.
end(), 0);
3618auto HexagonVectorCombine::vresize(IRBuilderBase &Builder,
Value *Val,
3622 assert(ValTy->getElementType() == Pad->getType());
3624 int CurSize = length(ValTy);
3625 if (CurSize == NewSize)
3628 if (CurSize > NewSize)
3629 return getElementRange(Builder, Val, Val, 0, NewSize);
3631 SmallVector<int, 128> SMask(NewSize);
3632 std::iota(SMask.
begin(), SMask.
begin() + CurSize, 0);
3633 std::fill(SMask.
begin() + CurSize, SMask.
end(), CurSize);
3638auto HexagonVectorCombine::rescale(IRBuilderBase &Builder,
Value *Mask,
3645 Type *FromSTy = FromTy->getScalarType();
3646 Type *ToSTy = ToTy->getScalarType();
3647 if (FromSTy == ToSTy)
3650 int FromSize = getSizeOf(FromSTy);
3651 int ToSize = getSizeOf(ToSTy);
3652 assert(FromSize % ToSize == 0 || ToSize % FromSize == 0);
3655 int FromCount = length(MaskTy);
3656 int ToCount = (FromCount * FromSize) / ToSize;
3657 assert((FromCount * FromSize) % ToSize == 0);
3659 auto *FromITy =
getIntTy(FromSize * 8);
3660 auto *ToITy =
getIntTy(ToSize * 8);
3665 Mask, VectorType::get(FromITy, FromCount,
false),
"sxt");
3667 Ext, VectorType::get(ToITy, ToCount,
false),
"cst");
3669 Cast, VectorType::get(getBoolTy(), ToCount,
false),
"trn");
3673auto HexagonVectorCombine::vlsb(IRBuilderBase &Builder,
Value *Val)
const
3676 if (ScalarTy == getBoolTy())
3679 Value *Bytes = vbytes(Builder, Val);
3681 return Builder.
CreateTrunc(Bytes, getBoolTy(getSizeOf(VecTy)),
"trn");
3684 return Builder.
CreateTrunc(Bytes, getBoolTy(),
"trn");
3688auto HexagonVectorCombine::vbytes(IRBuilderBase &Builder,
Value *Val)
const
3691 if (ScalarTy == getByteTy())
3694 if (ScalarTy != getBoolTy())
3695 return Builder.
CreateBitCast(Val, getByteTy(getSizeOf(Val)),
"cst");
3698 return Builder.
CreateSExt(Val, VectorType::get(getByteTy(), VecTy),
"sxt");
3699 return Builder.
CreateSExt(Val, getByteTy(),
"sxt");
3702auto HexagonVectorCombine::subvector(IRBuilderBase &Builder,
Value *Val,
3703 unsigned Start,
unsigned Length)
const
3706 return getElementRange(Builder, Val, Val, Start,
Length);
3709auto HexagonVectorCombine::sublo(IRBuilderBase &Builder,
Value *Val)
const
3711 size_t Len = length(Val);
3712 assert(Len % 2 == 0 &&
"Length should be even");
3713 return subvector(Builder, Val, 0, Len / 2);
3716auto HexagonVectorCombine::subhi(IRBuilderBase &Builder,
Value *Val)
const
3718 size_t Len = length(Val);
3719 assert(Len % 2 == 0 &&
"Length should be even");
3720 return subvector(Builder, Val, Len / 2, Len / 2);
3723auto HexagonVectorCombine::vdeal(IRBuilderBase &Builder,
Value *Val0,
3725 assert(Val0->getType() == Val1->getType());
3726 int Len = length(Val0);
3727 SmallVector<int, 128>
Mask(2 * Len);
3729 for (
int i = 0; i !=
Len; ++i) {
3736auto HexagonVectorCombine::vshuff(IRBuilderBase &Builder,
Value *Val0,
3738 assert(Val0->getType() == Val1->getType());
3739 int Len = length(Val0);
3740 SmallVector<int, 128>
Mask(2 * Len);
3742 for (
int i = 0; i !=
Len; ++i) {
3743 Mask[2 * i + 0] = i;
3749auto HexagonVectorCombine::createHvxIntrinsic(IRBuilderBase &Builder,
3755 auto getCast = [&](IRBuilderBase &Builder,
Value *Val,
3757 Type *SrcTy = Val->getType();
3758 if (SrcTy == DestTy)
3763 assert(HST.isTypeForHVX(SrcTy,
true));
3765 Type *BoolTy = Type::getInt1Ty(
F.getContext());
3770 unsigned HwLen = HST.getVectorLength();
3771 Intrinsic::ID TC = HwLen == 64 ? Intrinsic::hexagon_V6_pred_typecast
3772 : Intrinsic::hexagon_V6_pred_typecast_128B;
3781 SmallVector<Value *, 4> IntrArgs;
3782 for (
int i = 0, e =
Args.size(); i != e; ++i) {
3784 Type *
T = IntrTy->getParamType(i);
3785 if (
A->getType() !=
T) {
3791 StringRef MaybeName = !IntrTy->getReturnType()->isVoidTy() ?
"cup" :
"";
3792 CallInst *
Call = Builder.
CreateCall(IntrFn, IntrArgs, MaybeName);
3799 if (RetTy ==
nullptr || CallTy == RetTy)
3802 assert(HST.isTypeForHVX(CallTy,
true));
3803 return getCast(Builder,
Call, RetTy);
3806auto HexagonVectorCombine::splitVectorElements(IRBuilderBase &Builder,
3808 unsigned ToWidth)
const
3823 assert(VecTy->getElementType()->isIntegerTy());
3824 unsigned FromWidth = VecTy->getScalarSizeInBits();
3826 assert(ToWidth <= FromWidth &&
"Breaking up into wider elements?");
3827 unsigned NumResults = FromWidth / ToWidth;
3831 unsigned Length = length(VecTy);
3835 auto splitInHalf = [&](
unsigned Begin,
unsigned End,
auto splitFunc) ->
void {
3839 if (Begin + 1 == End)
3845 auto *VTy = VectorType::get(
getIntTy(Width / 2), 2 *
Length,
false);
3848 Value *Res =
vdeal(Builder, sublo(Builder, VVal), subhi(Builder, VVal));
3850 unsigned Half = (Begin + End) / 2;
3851 Results[Begin] = sublo(Builder, Res);
3852 Results[Half] = subhi(Builder, Res);
3854 splitFunc(Begin, Half, splitFunc);
3855 splitFunc(Half, End, splitFunc);
3858 splitInHalf(0, NumResults, splitInHalf);
3862auto HexagonVectorCombine::joinVectorElements(IRBuilderBase &Builder,
3864 VectorType *ToType)
const
3866 assert(ToType->getElementType()->isIntegerTy());
3877 unsigned ToWidth = ToType->getScalarSizeInBits();
3878 unsigned Width = Inputs.front()->getType()->getScalarSizeInBits();
3879 assert(Width <= ToWidth);
3881 unsigned Length = length(Inputs.front()->getType());
3883 unsigned NeedInputs = ToWidth / Width;
3884 if (Inputs.size() != NeedInputs) {
3889 Last, ConstantInt::get(
Last->getType(), Width - 1),
"asr");
3890 Inputs.resize(NeedInputs, Sign);
3893 while (Inputs.size() > 1) {
3896 for (
int i = 0, e = Inputs.size(); i < e; i += 2) {
3897 Value *Res =
vshuff(Builder, Inputs[i], Inputs[i + 1]);
3900 Inputs.resize(Inputs.size() / 2);
3903 assert(Inputs.front()->getType() == ToType);
3904 return Inputs.front();
3907auto HexagonVectorCombine::calculatePointerDifference(
Value *Ptr0,
3909 -> std::optional<int> {
3911 const SCEV *Scev0 = SE.getSCEV(Ptr0);
3912 const SCEV *Scev1 = SE.getSCEV(Ptr1);
3913 const SCEV *ScevDiff = SE.getMinusSCEV(Scev0, Scev1);
3915 APInt
V =
Const->getAPInt();
3916 if (
V.isSignedIntN(8 *
sizeof(
int)))
3917 return static_cast<int>(
V.getSExtValue());
3924 I->eraseFromParent();
3926 SmallVector<Instruction *, 8> ToErase;
3929#define CallBuilder(B, F) \
3932 if (auto *I = dyn_cast<Instruction>(V)) \
3933 B_.ToErase.push_back(I); \
3937 auto Simplify = [
this](
Value *
V) {
3943 auto StripBitCast = [](
Value *
V) {
3945 V =
C->getOperand(0);
3949 Ptr0 = StripBitCast(Ptr0);
3950 Ptr1 = StripBitCast(Ptr1);
3952 return std::nullopt;
3956 if (Gep0->getPointerOperand() != Gep1->getPointerOperand())
3957 return std::nullopt;
3958 if (Gep0->getSourceElementType() != Gep1->getSourceElementType())
3959 return std::nullopt;
3961 Builder
B(Gep0->getParent());
3962 int Scale = getSizeOf(Gep0->getSourceElementType(),
Alloc);
3965 if (Gep0->getNumOperands() != 2 || Gep1->getNumOperands() != 2)
3966 return std::nullopt;
3968 Value *Idx0 = Gep0->getOperand(1);
3969 Value *Idx1 = Gep1->getOperand(1);
3974 return Diff->getSExtValue() * Scale;
3976 KnownBits Known0 = getKnownBits(Idx0, Gep0);
3977 KnownBits Known1 = getKnownBits(Idx1, Gep1);
3980 return std::nullopt;
3988 Diff0 =
C->getSExtValue();
3990 return std::nullopt;
3999 Diff1 =
C->getSExtValue();
4001 return std::nullopt;
4004 return (Diff0 + Diff1) * Scale;
4009auto HexagonVectorCombine::getNumSignificantBits(
const Value *V,
4010 const Instruction *CtxI)
const
4015auto HexagonVectorCombine::getKnownBits(
const Value *V,
4016 const Instruction *CtxI)
const
4021auto HexagonVectorCombine::isSafeToClone(
const Instruction &In)
const ->
bool {
4022 if (
In.mayHaveSideEffects() ||
In.isAtomic() ||
In.isVolatile() ||
4023 In.isFenceLike() ||
In.mayReadOrWriteMemory()) {
4031template <
typename T>
4032auto HexagonVectorCombine::isSafeToMoveBeforeInBB(
const Instruction &In,
4034 const T &IgnoreInsts)
const
4037 [
this](
const Instruction &
I) -> std::optional<MemoryLocation> {
4039 switch (
II->getIntrinsicID()) {
4040 case Intrinsic::masked_load:
4042 case Intrinsic::masked_store:
4058 bool MayWrite =
In.mayWriteToMemory();
4059 auto MaybeLoc = getLocOrNone(In);
4061 auto From =
In.getIterator();
4064 bool MoveUp = (To !=
Block.end() && To->comesBefore(&In));
4066 MoveUp ? std::make_pair(To, From) : std::make_pair(std::next(From), To);
4067 for (
auto It =
Range.first; It !=
Range.second; ++It) {
4068 const Instruction &I = *It;
4069 if (llvm::is_contained(IgnoreInsts, &I))
4072 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
4073 if (II->getIntrinsicID() == Intrinsic::assume)
4080 if (!CB->hasFnAttr(Attribute::WillReturn))
4082 if (!CB->hasFnAttr(Attribute::NoSync))
4085 if (
I.mayReadOrWriteMemory()) {
4086 auto MaybeLocI = getLocOrNone(I);
4087 if (MayWrite || I.mayWriteToMemory()) {
4088 if (!MaybeLoc || !MaybeLocI)
4090 if (!AA.isNoAlias(*MaybeLoc, *MaybeLocI))
4098auto HexagonVectorCombine::isByteVecTy(
Type *Ty)
const ->
bool {
4100 return VecTy->getElementType() == getByteTy();
4104auto HexagonVectorCombine::getElementRange(IRBuilderBase &Builder,
Value *
Lo,
4108 SmallVector<int, 128> SMask(
Length);
4109 std::iota(SMask.
begin(), SMask.
end(), Start);
4116class HexagonVectorCombineLegacy :
public FunctionPass {
4120 HexagonVectorCombineLegacy() : FunctionPass(
ID) {}
4122 StringRef getPassName()
const override {
return "Hexagon Vector Combine"; }
4124 void getAnalysisUsage(AnalysisUsage &AU)
const override {
4132 AU.
addRequired<OptimizationRemarkEmitterWrapperPass>();
4133 FunctionPass::getAnalysisUsage(AU);
4137 if (skipFunction(
F))
4139 AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
4140 AssumptionCache &AC =
4141 getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
4142 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
4143 ScalarEvolution &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
4144 TargetLibraryInfo &TLI =
4145 getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
4146 auto &TM = getAnalysis<TargetPassConfig>().getTM<HexagonTargetMachine>();
4147 auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
4148 HexagonVectorCombine HVC(
F, AA, AC, DT, SE, TLI, TM, ORE);
4154char HexagonVectorCombineLegacy::ID = 0;
4157 "Hexagon Vector Combine",
false,
false)
4169 return new HexagonVectorCombineLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
static IntegerType * getIntTy(IRBuilderBase &B, const TargetLibraryInfo *TLI)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseMap class.
static bool runOnFunction(Function &F, bool PostInlining)
static cl::opt< unsigned > SizeLimit("eif-limit", cl::init(6), cl::Hidden, cl::desc("Size limit in Hexagon early if-conversion"))
static Value * locateIndexesFromIntrinsic(Instruction *In)
Instruction * locateDestination(Instruction *In, HvxIdioms::DstQualifier &Qual)
Value * getReinterpretiveCast_i8_to_i32(const HexagonVectorCombine &HVC, IRBuilderBase &Builder, LLVMContext &Ctx, Value *I)
static Value * locateIndexesFromGEP(Value *In)
#define CallBuilder(B, F)
Value * getPointer(Value *Ptr)
#define DEFAULT_HVX_VTCM_PAGE_SIZE
static Value * locateAddressFromIntrinsic(Instruction *In)
static Instruction * selectDestination(Instruction *In, HvxIdioms::DstQualifier &Qual)
Value * get_i32_Mask(const HexagonVectorCombine &HVC, IRBuilderBase &Builder, LLVMContext &Ctx, unsigned int pattern)
bool isArithmetic(unsigned Opc)
static Type * getIndexType(Value *In)
GetElementPtrInst * locateGepFromIntrinsic(Instruction *In)
Value * getReinterpretiveCast_i16_to_i32(const HexagonVectorCombine &HVC, IRBuilderBase &Builder, LLVMContext &Ctx, Value *I)
static Align effectiveAlignForValueTy(const DataLayout &DL, Type *ValTy, int Requested)
iv Induction Variable Users
static std::pair< Value *, APInt > getMask(Value *WideMask, unsigned Factor, ElementCount LeafValueEC)
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
static bool isCandidate(const MachineInstr *MI, Register &DefedReg, Register FrameReg)
static bool isUndef(const MachineInstr &MI)
This file implements a map that provides insertion order iteration.
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
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)
Remove Loads Into Fake Uses
This file defines the SmallVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static SymbolRef::Type getType(const Symbol *Sym)
Target-Independent Code Generator Pass Configuration Options pass.
static uint32_t getAlignment(const MCSectionCOFF &Sec)
static const uint32_t IV[8]
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
unsigned getAddressSpace() const
Return the address space for the allocation.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
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.
InstListType::const_iterator const_iterator
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
AttributeList getAttributes() const
Return the attributes for this call.
@ ICMP_ULT
unsigned less than
static LLVM_ABI Constant * get(LLVMContext &Context, ArrayRef< uint8_t > Elts)
get() constructors - Return a constant with vector type with an element count and element type matchi...
This is the shared class of boolean and integer constants.
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
This is an important base class in LLVM.
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
unsigned getPointerSizeInBits(unsigned AS=0) const
The size in bits of the pointer representation in a given address space.
LLVM_ABI Align getABITypeAlign(Type *Ty) const
Returns the minimum ABI-required alignment for the specified type.
LLVM_ABI TypeSize getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
iterator_range< iterator > children()
DomTreeNodeBase< NodeT > * getRootNode()
getRootNode - This returns the entry node for the CFG of the function.
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.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
const BasicBlock & front() const
const BasicBlock & back() const
DISubprogram * getSubprogram() const
Get the attached subprogram.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
Value * getPointerOperand()
bool isHVXVectorType(EVT VecTy, bool IncludeBool=false) const
bool useHVXV62Ops() const
bool useHVXV69Ops() const
unsigned getVectorLength() const
bool useHVXV66Ops() const
bool isTypeForHVX(Type *VecTy, bool IncludeBool=false) const
Intrinsic::ID getIntrinsicId(unsigned Opc) const
Common base class shared among various IRBuilders.
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
LLVM_ABI Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Value * CreateSExt(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateBitOrPointerCast(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Value * CreateShuffleVector(Value *V1, Value *V2, Value *Mask, const Twine &Name="")
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Value * CreateAShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Value * CreateICmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
const char * getOpcodeName() const
Class to represent integer types.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
This class implements a map that also provides access to all stored values in a deterministic order.
void remove_if(Predicate Pred)
Remove the elements that match the predicate.
bool doesNotAccessMemory() const
Whether this function accesses no memory.
bool onlyAccessesInaccessibleMem() const
Whether this function only (at most) accesses inaccessible memory.
static LLVM_ABI std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
static LLVM_ABI MemoryLocation getForArgument(const CallBase *Call, unsigned ArgIdx, const TargetLibraryInfo *TLI)
Return a location representing a particular argument of a call.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
The main scalar evolution driver.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
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.
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.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
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.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
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.
const ParentTy * getParent() const
self_iterator getIterator()
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Abstract Attribute helper functions.
Rounding
Possible values of current rounding mode, which is specified in bits 23:22 of FPCR.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
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.
@ 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.
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
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.
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
initializer< Ty > init(const Ty &Val)
@ User
could "use" a pointer
friend class Instruction
Iterator for Instructions in a `BasicBlock.
LLVM_ABI Instruction * getTerminator() const
LLVM_ABI Instruction & front() const
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.
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.
LLVM_ABI 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.
RelativeUniformCounterPtr Values
@ Known
Known to have no common set bits.
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
LLVM_ABI 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.
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
LLVM_ABI Value * simplifyInstruction(Instruction *I, const SimplifyQuery &Q)
See if we can compute a simplified version of this instruction.
DomTreeNodeBase< BasicBlock > DomTreeNode
Align getKnownAlignment(Value *V, const DataLayout &DL, const Instruction *CxtI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr)
Try to infer an alignment for the specified pointer.
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)
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
LLVM_ABI 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.
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
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 raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ And
Bitwise or logical AND of integers.
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
LLVM_ABI unsigned ComputeMaxSignificantBits(const Value *Op, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Get the upper bound on bit size for this Value Op as a signed integer.
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
AAResults AliasAnalysis
Temporary typedef for legacy code that uses a generic AliasAnalysis pointer or reference.
LLVM_ABI 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.
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
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 LLVM_ABI 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.