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);
1182 ArrayRef<Instruction *> Main(Move.Main);
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());
1199 ArrayRef<Instruction *> Main(Move.Main);
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 Value *AlignAddr =
nullptr;
1596 Value *AlignVal =
nullptr;
1598 if (MinNeeded <= MaxGiven) {
1599 int Start = WithMinOffset.Offset;
1600 int OffAtMax = WithMaxAlign.Offset;
1607 int Adjust = -
alignTo(OffAtMax - Start, MinNeeded.value());
1608 AlignAddr = createAdjustedPointer(Builder, WithMaxAlign.Addr,
1609 WithMaxAlign.ValTy, Adjust, Move.Clones);
1610 int Diff =
Start - (OffAtMax + Adjust);
1611 AlignVal = HVC.getConstInt(Diff);
1613 assert(
static_cast<decltype(MinNeeded.value())
>(Diff) < MinNeeded.value());
1623 createAlignedPointer(Builder, WithMinOffset.Addr, WithMinOffset.ValTy,
1624 MinNeeded.value(), Move.Clones);
1626 Builder.
CreatePtrToInt(WithMinOffset.Addr, HVC.getIntTy(),
"pti");
1628 for (
auto [Old, New] : Move.Clones)
1629 I->replaceUsesOfWith(Old, New);
1634 for (
const AddrInfo &AI : MoveInfos) {
1635 VSpan.Blocks.emplace_back(AI.Inst, HVC.getSizeOf(AI.ValTy),
1636 AI.Offset - WithMinOffset.Offset);
1643 : std::max<int>(MinNeeded.value(), 4);
1644 assert(!Move.IsHvx || ScLen == 64 || ScLen == 128);
1645 assert(Move.IsHvx || ScLen == 4 || ScLen == 8);
1648 dbgs() <<
"ScLen: " << ScLen <<
"\n";
1649 dbgs() <<
"AlignVal:" << *AlignVal <<
"\n";
1650 dbgs() <<
"AlignAddr:" << *AlignAddr <<
"\n";
1651 dbgs() <<
"VSpan:\n" << VSpan <<
'\n';
1655 realignLoadGroup(Builder, VSpan, ScLen, AlignVal, AlignAddr);
1657 realignStoreGroup(Builder, VSpan, ScLen, AlignVal, AlignAddr);
1660 HVC.ORE.
emit([&]() {
1661 return OptimizationRemark(
DEBUG_TYPE,
"VectorsAligned",
1663 <<
"aligned vector memory operations";
1666 for (
auto *Inst : Move.Main)
1667 Inst->eraseFromParent();
1672auto AlignVectors::makeTestIfUnaligned(IRBuilderBase &Builder,
Value *AlignVal,
1673 int Alignment)
const ->
Value * {
1674 auto *AlignTy = AlignVal->getType();
1676 AlignVal, ConstantInt::get(AlignTy, Alignment - 1),
"and");
1677 Value *
Zero = ConstantInt::get(AlignTy, 0);
1681auto AlignVectors::isSectorTy(
Type *Ty)
const ->
bool {
1682 if (!HVC.isByteVecTy(Ty))
1684 int Size = HVC.getSizeOf(Ty);
1690auto AlignVectors::run() ->
bool {
1693 if (!createAddressGroups())
1697 dbgs() <<
"Address groups(" << AddrGroups.
size() <<
"):\n";
1698 for (
auto &[In, AL] : AddrGroups) {
1699 for (
const AddrInfo &AI : AL)
1700 dbgs() <<
"---\n" << AI <<
'\n';
1705 MoveList LoadGroups, StoreGroups;
1707 for (
auto &
G : AddrGroups) {
1713 dbgs() <<
"\nLoad groups(" << LoadGroups.size() <<
"):\n";
1714 for (
const MoveGroup &
G : LoadGroups)
1715 dbgs() <<
G <<
"\n";
1716 dbgs() <<
"Store groups(" << StoreGroups.size() <<
"):\n";
1717 for (
const MoveGroup &
G : StoreGroups)
1718 dbgs() <<
G <<
"\n";
1722 unsigned CountLimit = VAGroupCountLimit;
1723 if (CountLimit == 0)
1726 if (LoadGroups.size() > CountLimit) {
1727 LoadGroups.resize(CountLimit);
1728 StoreGroups.clear();
1730 unsigned StoreLimit = CountLimit - LoadGroups.size();
1731 if (StoreGroups.size() > StoreLimit)
1732 StoreGroups.resize(StoreLimit);
1735 for (
auto &M : LoadGroups)
1737 for (
auto &M : StoreGroups)
1742 for (
auto &M : LoadGroups)
1744 for (
auto &M : StoreGroups)
1754auto HvxIdioms::getNumSignificantBits(
Value *V, Instruction *In)
const
1755 -> std::pair<unsigned, Signedness> {
1756 unsigned Bits = HVC.getNumSignificantBits(V, In);
1762 KnownBits
Known = HVC.getKnownBits(V, In);
1763 Signedness Sign =
Signed;
1764 unsigned NumToTest = 0;
1768 NumToTest =
Bits - 1;
1770 if (NumToTest != 0 &&
Known.Zero.ashr(NumToTest).isAllOnes()) {
1778 if (
Known.Zero.ashr(Pow2 - 1).isAllOnes())
1781 return {
Bits, Sign};
1784auto HvxIdioms::canonSgn(SValue
X, SValue
Y)
const
1785 -> std::pair<SValue, SValue> {
1798auto HvxIdioms::matchFxpMul(Instruction &In)
const -> std::optional<FxpOp> {
1799 using namespace PatternMatch;
1800 auto *Ty =
In.getType();
1803 return std::nullopt;
1812 auto m_Shr = [](
auto &&
V,
auto &&S) {
1824 if (
Op.Frac > Width)
1825 return std::nullopt;
1832 return std::nullopt;
1840 Op.Opcode = Instruction::Mul;
1842 Op.X.Sgn = getNumSignificantBits(
Op.X.Val, &In).second;
1843 Op.Y.Sgn = getNumSignificantBits(
Op.Y.Val, &In).second;
1848 return std::nullopt;
1851auto HvxIdioms::processFxpMul(Instruction &In,
const FxpOp &
Op)
const
1853 assert(
Op.X.Val->getType() ==
Op.Y.Val->getType());
1856 if (VecTy ==
nullptr)
1859 unsigned ElemWidth = ElemTy->getBitWidth();
1862 if ((HVC.length(VecTy) * ElemWidth) % (8 * HVC.HST.
getVectorLength()) != 0)
1872 if (ElemWidth <= 32 &&
Op.Frac == 0)
1875 auto [BitsX, SignX] = getNumSignificantBits(
Op.X.Val, &In);
1876 auto [BitsY, SignY] = getNumSignificantBits(
Op.Y.Val, &In);
1881 IRBuilder Builder(
In.getIterator(), InstSimplifyFolder(HVC.DL));
1883 auto roundUpWidth = [](
unsigned Width) ->
unsigned {
1889 if (Width > 32 && Width % 32 != 0) {
1896 BitsX = roundUpWidth(BitsX);
1897 BitsY = roundUpWidth(BitsY);
1902 unsigned Width = std::max(BitsX, BitsY);
1904 auto *ResizeTy = VectorType::get(HVC.getIntTy(Width), VecTy);
1905 if (Width < ElemWidth) {
1908 }
else if (Width > ElemWidth) {
1915 assert(
X->getType() ==
Y->getType() &&
X->getType() == ResizeTy);
1917 unsigned VecLen = HVC.length(ResizeTy);
1918 unsigned ChopLen = (8 * HVC.HST.
getVectorLength()) / std::min(Width, 32u);
1922 ChopOp.ResTy = VectorType::get(
Op.ResTy->getElementType(), ChopLen,
false);
1924 for (
unsigned V = 0;
V != VecLen / ChopLen; ++
V) {
1925 ChopOp.X.Val = HVC.subvector(Builder,
X, V * ChopLen, ChopLen);
1926 ChopOp.Y.Val = HVC.subvector(Builder,
Y, V * ChopLen, ChopLen);
1927 Results.push_back(processFxpMulChopped(Builder, In, ChopOp));
1942inline bool HvxIdioms::matchScatter(Instruction &In)
const {
1946 return (
II->getIntrinsicID() == Intrinsic::masked_scatter);
1949inline bool HvxIdioms::matchGather(Instruction &In)
const {
1953 return (
II->getIntrinsicID() == Intrinsic::masked_gather);
1956inline bool HvxIdioms::matchMLoad(Instruction &In)
const {
1960 return (
II->getIntrinsicID() == Intrinsic::masked_load);
1963inline bool HvxIdioms::matchMStore(Instruction &In)
const {
1967 return (
II->getIntrinsicID() == Intrinsic::masked_store);
1975 case Instruction::Add:
1976 case Instruction::Sub:
1977 case Instruction::Mul:
1978 case Instruction::And:
1979 case Instruction::Or:
1980 case Instruction::Xor:
1981 case Instruction::AShr:
1982 case Instruction::LShr:
1983 case Instruction::Shl:
1984 case Instruction::UDiv:
1992 assert(Ptr &&
"Unable to extract pointer");
1998 if (
II->getIntrinsicID() == Intrinsic::masked_store)
1999 return II->getOperand(1);
2005 HvxIdioms::DstQualifier &Qual) {
2011 Qual = HvxIdioms::LdSt;
2013 if (
II->getIntrinsicID() == Intrinsic::masked_gather) {
2015 Qual = HvxIdioms::LLVM_Gather;
2016 }
else if (
II->getIntrinsicID() == Intrinsic::masked_scatter) {
2018 Qual = HvxIdioms::LLVM_Scatter;
2019 }
else if (
II->getIntrinsicID() == Intrinsic::masked_store) {
2021 Qual = HvxIdioms::LdSt;
2022 }
else if (
II->getIntrinsicID() ==
2023 Intrinsic::hexagon_V6_vgather_vscattermh) {
2025 Qual = HvxIdioms::HEX_Gather_Scatter;
2026 }
else if (
II->getIntrinsicID() == Intrinsic::hexagon_V6_vscattermh_128B) {
2028 Qual = HvxIdioms::HEX_Scatter;
2029 }
else if (
II->getIntrinsicID() == Intrinsic::hexagon_V6_vgathermh_128B) {
2031 Qual = HvxIdioms::HEX_Gather;
2039 Qual = HvxIdioms::Call;
2044 Qual = HvxIdioms::Arithmetic;
2064 for (
auto &U : In->uses()) {
2068 Users.push_back(Destination);
2080 assert(In &&
"Bad instruction");
2084 "Not a gather Intrinsic");
2113 if (
II &&
II->getIntrinsicID() == Intrinsic::masked_gather)
2123 auto *Src = IE->getOperand(1);
2138 LLVM_DEBUG(
dbgs() <<
" Unable to locate Address from intrinsic\n");
2150 if (
II->getIntrinsicID() == Intrinsic::masked_load)
2151 return II->getType();
2152 if (
II->getIntrinsicID() == Intrinsic::masked_store)
2153 return II->getOperand(0)->getType();
2155 return In->getType();
2164 if (
II->getIntrinsicID() == Intrinsic::masked_load)
2166 if (
II->getIntrinsicID() == Intrinsic::masked_gather)
2178 return cstDataVector;
2180 return GEPIndex->getOperand(0);
2196 LLVM_DEBUG(
dbgs() <<
" Unable to locate Index from intrinsic\n");
2206 assert(
I &&
"Unable to reinterprete cast");
2207 Type *NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2208 std::vector<unsigned> shuffleMask;
2209 for (
unsigned i = 0; i < 64; ++i)
2210 shuffleMask.push_back(i);
2212 Value *CastShuffle =
2213 Builder.CreateShuffleVector(
I,
I, Mask,
"identity_shuffle");
2214 return Builder.CreateBitCast(CastShuffle, NT,
"cst64_i16_to_32_i32");
2221 assert(
I &&
"Unable to reinterprete cast");
2222 Type *NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2223 std::vector<unsigned> shuffleMask;
2224 for (
unsigned i = 0; i < 128; ++i)
2225 shuffleMask.push_back(i);
2227 Value *CastShuffle =
2228 Builder.CreateShuffleVector(
I,
I, Mask,
"identity_shuffle");
2229 return Builder.CreateBitCast(CastShuffle, NT,
"cst128_i8_to_32_i32");
2235 unsigned int pattern) {
2236 std::vector<unsigned int> byteMask;
2237 for (
unsigned i = 0; i < 32; ++i)
2238 byteMask.push_back(pattern);
2240 return Builder.CreateIntrinsic(
2242 {llvm::ConstantDataVector::get(Ctx, byteMask), HVC.getConstInt(~0)},
2246Value *HvxIdioms::processVScatter(Instruction &In)
const {
2248 assert(InpTy &&
"Cannot handle no vector type for llvm.scatter/gather");
2249 unsigned InpSize = HVC.getSizeOf(InpTy);
2250 auto *
F =
In.getFunction();
2251 LLVMContext &Ctx =
F->getContext();
2253 assert(ElemTy &&
"llvm.scatter needs integer type argument");
2256 unsigned Elements = HVC.length(InpTy);
2257 dbgs() <<
"\n[Process scatter](" <<
In <<
")\n" << *
In.getParent() <<
"\n";
2258 dbgs() <<
" Input type(" << *InpTy <<
") elements(" <<
Elements
2259 <<
") VecLen(" << InpSize <<
") type(" << *ElemTy <<
") ElemWidth("
2260 << ElemWidth <<
")\n";
2263 IRBuilder Builder(
In.getIterator(), InstSimplifyFolder(HVC.DL));
2265 auto *ValueToScatter =
In.getOperand(0);
2266 LLVM_DEBUG(
dbgs() <<
" ValueToScatter : " << *ValueToScatter <<
"\n");
2270 <<
") for vscatter\n");
2295 Value *CastIndex =
nullptr;
2296 if (cstDataVector) {
2298 Type *IndexVectorType = HVC.getHvxTy(HVC.getIntTy(32),
false);
2299 AllocaInst *IndexesAlloca = Builder.
CreateAlloca(IndexVectorType);
2300 [[maybe_unused]]
auto *StoreIndexes =
2301 Builder.
CreateStore(cstDataVector, IndexesAlloca);
2302 LLVM_DEBUG(
dbgs() <<
" StoreIndexes : " << *StoreIndexes <<
"\n");
2304 Builder.
CreateLoad(IndexVectorType, IndexesAlloca,
"reload_index");
2309 CastIndex = Indexes;
2313 if (ElemWidth == 1) {
2316 Type *
NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2322 HVC.getHvxTy(HVC.getIntTy(32),
true), V6_vunpack, CastIndexes,
nullptr);
2323 LLVM_DEBUG(
dbgs() <<
" UnpackedIndexes : " << *UnpackedIndexes <<
")\n");
2327 [[maybe_unused]]
Value *IndexHi =
2328 HVC.createHvxIntrinsic(Builder, V6_hi, NT, UnpackedIndexes);
2329 [[maybe_unused]]
Value *IndexLo =
2330 HVC.createHvxIntrinsic(Builder, V6_lo, NT, UnpackedIndexes);
2338 HVC.getHvxTy(HVC.getIntTy(32),
true), V6_vunpack, CastSrc,
nullptr);
2339 LLVM_DEBUG(
dbgs() <<
" UnpackedValToScat: " << *UnpackedValueToScatter
2342 [[maybe_unused]]
Value *UVSHi =
2343 HVC.createHvxIntrinsic(Builder, V6_hi, NT, UnpackedValueToScatter);
2344 [[maybe_unused]]
Value *UVSLo =
2345 HVC.createHvxIntrinsic(Builder, V6_lo, NT, UnpackedValueToScatter);
2350 auto *QByteMask =
get_i32_Mask(HVC, Builder, Ctx, 0x00ff00ff);
2353 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermhq_128B,
2359 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermhq_128B,
2363 }
else if (ElemWidth == 2) {
2368 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermh_128B,
2372 }
else if (ElemWidth == 4) {
2374 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vscattermw_128B,
2384Value *HvxIdioms::processVGather(Instruction &In)
const {
2385 [[maybe_unused]]
auto *InpTy =
2387 assert(InpTy &&
"Cannot handle no vector type for llvm.gather");
2388 [[maybe_unused]]
auto *ElemTy =
2390 assert(ElemTy &&
"llvm.gather needs vector of ptr argument");
2391 auto *
F =
In.getFunction();
2392 LLVMContext &Ctx =
F->getContext();
2394 << *
In.getParent() <<
"\n");
2396 << HVC.length(InpTy) <<
") VecLen(" << HVC.getSizeOf(InpTy)
2397 <<
") type(" << *ElemTy <<
") Access alignment("
2398 << *
In.getOperand(1) <<
") AddressSpace("
2399 << ElemTy->getAddressSpace() <<
")\n");
2403 "llvm.gather needs vector for mask");
2404 IRBuilder Builder(
In.getIterator(), InstSimplifyFolder(HVC.DL));
2409 HvxIdioms::DstQualifier Qual = HvxIdioms::Undefined;
2415 LLVM_DEBUG(
dbgs() <<
" Destination : " << *Dst <<
" Qual(" << Qual
2421 LLVM_DEBUG(
dbgs() <<
"Could not locate vgather destination ptr\n");
2427 assert(DstType &&
"Cannot handle non vector dst type for llvm.gather");
2441 Value *Gather =
nullptr;
2442 Type *
NT = HVC.getHvxTy(HVC.getIntTy(32),
false);
2443 if (Qual == HvxIdioms::LdSt || Qual == HvxIdioms::Arithmetic) {
2447 unsigned OutputSize = HVC.getSizeOf(DstType);
2451 <<
" Address space ("
2453 <<
" Result type : " << *DstType
2454 <<
"\n Size in bytes : " << OutputSize
2455 <<
" element type(" << *DstElemTy
2456 <<
")\n ElemWidth : " << ElemWidth <<
" bytes\n");
2459 assert(IndexType &&
"Cannot handle non vector index type for llvm.gather");
2460 unsigned IndexWidth = HVC.DL.
getTypeAllocSize(IndexType->getElementType());
2465 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2474 if (ElemWidth == 1) {
2479 Value *CastIndexes =
2482 auto *UnpackedIndexes =
2484 V6_vunpack, CastIndexes,
nullptr);
2490 [[maybe_unused]]
Value *IndexHi =
2491 HVC.createHvxIntrinsic(Builder, V6_hi, NT, UnpackedIndexes);
2492 [[maybe_unused]]
Value *IndexLo =
2493 HVC.createHvxIntrinsic(Builder, V6_lo, NT, UnpackedIndexes);
2497 auto *QByteMask =
get_i32_Mask(HVC, Builder, Ctx, 0x00ff00ff);
2501 auto V6_vgather = HVC.HST.
getIntrinsicId(Hexagon::V6_vgathermhq);
2503 Type::getVoidTy(Ctx), V6_vgather,
2504 {Ptr, QByteMask, CastedPtr,
2510 HVC.getHvxTy(HVC.getIntTy(32),
false), Ptr,
"temp_result_hi");
2511 LLVM_DEBUG(
dbgs() <<
" LoadedResultHi : " << *LoadedResultHi <<
"\n");
2516 Type::getVoidTy(Ctx), V6_vgather,
2517 {Ptr, QByteMask, CastedPtr,
2522 HVC.getHvxTy(HVC.getIntTy(32),
false), Ptr,
"temp_result_lo");
2523 LLVM_DEBUG(
dbgs() <<
" LoadedResultLo : " << *LoadedResultLo <<
"\n");
2530 NT, V6_vpackeb, {LoadedResultHi, LoadedResultLo},
nullptr);
2532 [[maybe_unused]]
auto *StoreRes = Builder.
CreateStore(Res, Ptr);
2534 }
else if (ElemWidth == 2) {
2536 if (IndexWidth == 2) {
2544 Value *AdjustedIndex = HVC.createHvxIntrinsic(
2545 Builder, V6_vaslh, NT, {CastIndex, HVC.getConstInt(1)});
2547 <<
" Shifted half index: " << *AdjustedIndex <<
")\n");
2553 Type::getVoidTy(Ctx), V6_vgather,
2557 for (
auto &U : Dst->uses()) {
2559 dbgs() <<
" dst used by: " << *UI <<
"\n";
2561 for (
auto &U :
In.uses()) {
2563 dbgs() <<
" In used by : " << *UI <<
"\n";
2568 HVC.getHvxTy(HVC.getIntTy(16),
false), Ptr,
"temp_result");
2569 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2570 In.replaceAllUsesWith(LoadedResult);
2572 dbgs() <<
" Unhandled index type for vgather\n";
2575 }
else if (ElemWidth == 4) {
2576 if (IndexWidth == 4) {
2579 Value *AdjustedIndex = HVC.createHvxIntrinsic(
2580 Builder, V6_vaslh, NT, {Indexes, HVC.getConstInt(2)});
2582 <<
" Shifted word index: " << *AdjustedIndex <<
")\n");
2584 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermw_128B,
2607 Dst->eraseFromParent();
2608 }
else if (Qual == HvxIdioms::LLVM_Scatter) {
2612 assert(DstInpTy &&
"Cannot handle no vector type for llvm.scatter");
2613 unsigned DstInpSize = HVC.getSizeOf(DstInpTy);
2614 unsigned DstElements = HVC.length(DstInpTy);
2616 assert(DstElemTy &&
"llvm.scatter needs vector of ptr argument");
2617 dbgs() <<
" Gather feeds into scatter\n Values to scatter : "
2618 << *Dst->getOperand(0) <<
"\n";
2619 dbgs() <<
" Dst type(" << *DstInpTy <<
") elements(" << DstElements
2620 <<
") VecLen(" << DstInpSize <<
") type(" << *DstElemTy
2621 <<
") Access alignment(" << *Dst->getOperand(2) <<
")\n";
2635 Src, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2655 Value *AdjustedIndex = HVC.createHvxIntrinsic(
2656 Builder, V6_vaslh, NT, {CastIndex, HVC.getConstInt(1)});
2657 LLVM_DEBUG(
dbgs() <<
" Shifted half index: " << *AdjustedIndex <<
")\n");
2660 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2664 }
else if (Qual == HvxIdioms::HEX_Gather_Scatter) {
2672 if (cstDataVector) {
2677 [[maybe_unused]]
auto *StoreIndexes =
2678 Builder.
CreateStore(cstDataVector, IndexesAlloca);
2679 LLVM_DEBUG(
dbgs() <<
" StoreIndexes : " << *StoreIndexes <<
"\n");
2680 Value *LoadedIndex =
2681 Builder.
CreateLoad(NT, IndexesAlloca,
"reload_index");
2683 LLVM_DEBUG(
dbgs() <<
" ResultAlloca : " << *ResultAlloca <<
"\n");
2686 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2690 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2691 {ResultAlloca, CastedSrc,
2695 HVC.getHvxTy(HVC.getIntTy(16),
false), ResultAlloca,
"temp_result");
2696 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2698 In.replaceAllUsesWith(LoadedResult);
2708 Src, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2721 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgather_vscattermh,
2727 }
else if (Qual == HvxIdioms::HEX_Scatter) {
2734 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2741 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2746 HVC.getHvxTy(HVC.getIntTy(16),
false), ResultAlloca,
"temp_result");
2747 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2748 In.replaceAllUsesWith(LoadedResult);
2749 }
else if (Qual == HvxIdioms::HEX_Gather) {
2754 if (cstDataVector) {
2758 [[maybe_unused]]
auto *StoreIndexes =
2759 Builder.
CreateStore(cstDataVector, IndexesAlloca);
2760 LLVM_DEBUG(
dbgs() <<
" StoreIndexes : " << *StoreIndexes <<
"\n");
2761 Value *LoadedIndex =
2762 Builder.
CreateLoad(NT, IndexesAlloca,
"reload_index");
2765 <<
"\n AddressSpace: "
2769 IndexLoad, Type::getInt32Ty(Ctx),
"cst_ptr_to_i32");
2773 Type::getVoidTy(Ctx), Intrinsic::hexagon_V6_vgathermh_128B,
2774 {ResultAlloca, CastedSrc,
2778 HVC.getHvxTy(HVC.getIntTy(16),
false), ResultAlloca,
"temp_result");
2779 LLVM_DEBUG(
dbgs() <<
" LoadedResult : " << *LoadedResult <<
"\n");
2781 In.replaceAllUsesWith(LoadedResult);
2784 }
else if (Qual == HvxIdioms::LLVM_Gather) {
2786 errs() <<
" Underimplemented vgather to vgather sequence\n";
2796std::optional<uint64_t> HvxIdioms::getPHIBaseMinAlignment(Instruction &In,
2797 PHINode *PN)
const {
2799 return std::nullopt;
2801 SmallVector<Value *, 16> Worklist;
2802 SmallPtrSet<Value *, 16> Visited;
2803 uint64_t minPHIAlignment = Value::MaximumAlignment;
2806 while (!Worklist.
empty()) {
2809 if (!Visited.
insert(V).second)
2821 if (KnownAlign.
value() < minPHIAlignment)
2822 minPHIAlignment = KnownAlign.
value();
2825 if (minPHIAlignment != Value::MaximumAlignment)
2826 return minPHIAlignment;
2827 return std::nullopt;
2831std::optional<uint64_t> HvxIdioms::getAlignment(Instruction &In,
2833 SmallPtrSet<Value *, 16> Visited;
2834 return getAlignmentImpl(In, ptr, Visited);
2837std::optional<uint64_t>
2838HvxIdioms::getAlignmentImpl(Instruction &In,
Value *ptr,
2839 SmallPtrSet<Value *, 16> &Visited)
const {
2842 if (!Visited.
insert(ptr).second)
2843 return std::nullopt;
2847 if (KnownAlign.
value() > 1) {
2849 return KnownAlign.
value();
2855 auto baseAlignmentOpt = getPHIBaseMinAlignment(In, PN);
2856 if (!baseAlignmentOpt)
2857 return std::nullopt;
2859 uint64_t minBaseAlignment = *baseAlignmentOpt;
2861 if (minBaseAlignment == 1)
2864 uint64_t minPHIAlignment = minBaseAlignment;
2866 <<
")nodes and min base aligned to (" << minBaseAlignment
2873 uint64_t MemberAlignment = Value::MaximumAlignment;
2875 MemberAlignment = *res;
2877 return std::nullopt;
2879 if (minPHIAlignment > MemberAlignment)
2880 minPHIAlignment = MemberAlignment;
2882 LLVM_DEBUG(
dbgs() <<
" total PHI alignment(" << minPHIAlignment <<
")\n");
2883 return minPHIAlignment;
2887 auto *GEPPtr =
GEP->getPointerOperand();
2890 if (&In == GEPPtr) {
2892 GEPPtr->getType()->getPointerAddressSpace()),
2894 if (
GEP->accumulateConstantOffset(HVC.DL,
Offset)) {
2896 <<
Offset.getZExtValue() <<
")\n");
2897 return Offset.getZExtValue();
2902 return std::nullopt;
2905Value *HvxIdioms::processMStore(Instruction &In)
const {
2906 [[maybe_unused]]
auto *InpTy =
2908 assert(InpTy &&
"Cannot handle no vector type for llvm.masked.store");
2911 << *
In.getParent() <<
"\n");
2913 << HVC.length(InpTy) <<
") VecLen(" << HVC.getSizeOf(InpTy)
2914 <<
") type(" << *InpTy->getElementType() <<
") of size("
2915 << InpTy->getScalarSizeInBits() <<
")bits\n");
2917 assert(CI &&
"Expected llvm.masked.store to be a call");
2918 Align HaveAlign = CI->getParamAlign(1).valueOrOne();
2926 Type *ValTy =
In.getOperand(0)->getType();
2930 if (EffA < HaveAlign)
2934 AttrBuilder AttrB(CI->getContext());
2935 AttrB.addAlignmentAttr(EffA);
2937 CI->getAttributes().addParamAttributes(CI->getContext(), 1, AttrB));
2941Value *HvxIdioms::processMLoad(Instruction &In)
const {
2943 assert(InpTy &&
"Cannot handle non vector type for llvm.masked.store");
2945 << *
In.getParent() <<
"\n");
2947 << HVC.length(InpTy) <<
") VecLen(" << HVC.getSizeOf(InpTy)
2948 <<
") type(" << *InpTy->getElementType() <<
") of size("
2949 << InpTy->getScalarSizeInBits() <<
")bits\n");
2951 assert(CI &&
"Expected to be a call to llvm.masked.load");
2953 Align HaveAlign = CI->getParamAlign(0).valueOrOne();
2961 Type *ValTy =
In.getType();
2964 if (EffA < HaveAlign)
2970 AttrBuilder AttrB(CI->getContext());
2971 AttrB.addAlignmentAttr(EffA);
2973 CI->getAttributes().addParamAttributes(CI->getContext(), 0, AttrB));
2977auto HvxIdioms::processFxpMulChopped(IRBuilderBase &Builder, Instruction &In,
2978 const FxpOp &
Op)
const ->
Value * {
2979 assert(
Op.X.Val->getType() ==
Op.Y.Val->getType());
2981 unsigned Width = InpTy->getScalarSizeInBits();
2984 if (!
Op.RoundAt || *
Op.RoundAt ==
Op.Frac - 1) {
2987 Value *QMul =
nullptr;
2989 QMul = createMulQ15(Builder,
Op.X,
Op.Y, Rounding);
2990 }
else if (Width == 32) {
2991 QMul = createMulQ31(Builder,
Op.X,
Op.Y, Rounding);
2993 if (QMul !=
nullptr)
2999 assert(Width < 32 || Width % 32 == 0);
3009 assert(
Op.Frac != 0 &&
"Unshifted mul should have been skipped");
3010 if (
Op.Frac == 16) {
3012 if (
Value *MulH = createMulH16(Builder,
Op.X,
Op.Y))
3016 Value *Prod32 = createMul16(Builder,
Op.X,
Op.Y);
3019 ConstantInt::get(Prod32->
getType(), 1ull << *
Op.RoundAt);
3020 Prod32 = Builder.
CreateAdd(Prod32, RoundVal,
"add");
3025 ? Builder.
CreateAShr(Prod32, ShiftAmt,
"asr")
3026 : Builder.
CreateLShr(Prod32, ShiftAmt,
"lsr");
3027 return Builder.
CreateTrunc(Shifted, InpTy,
"trn");
3034 auto WordX = HVC.splitVectorElements(Builder,
Op.X.Val, 32);
3035 auto WordY = HVC.splitVectorElements(Builder,
Op.Y.Val, 32);
3036 auto WordP = createMulLong(Builder, WordX,
Op.X.Sgn, WordY,
Op.Y.Sgn);
3041 if (
Op.RoundAt.has_value()) {
3044 RoundV[*
Op.RoundAt / 32] =
3045 ConstantInt::get(HvxWordTy, 1ull << (*
Op.RoundAt % 32));
3046 WordP = createAddLong(Builder, WordP, RoundV);
3052 unsigned SkipWords =
Op.Frac / 32;
3053 Constant *ShiftAmt = ConstantInt::get(HvxWordTy,
Op.Frac % 32);
3055 for (
int Dst = 0,
End = WordP.size() - SkipWords; Dst !=
End; ++Dst) {
3056 int Src = Dst + SkipWords;
3058 if (Src + 1 <
End) {
3069 WordP.resize(WordP.size() - SkipWords);
3071 return HVC.joinVectorElements(Builder, WordP,
Op.ResTy);
3074auto HvxIdioms::createMulQ15(IRBuilderBase &Builder, SValue
X, SValue
Y,
3075 bool Rounding)
const ->
Value * {
3076 assert(
X.Val->getType() ==
Y.Val->getType());
3077 assert(
X.Val->getType()->getScalarType() == HVC.getIntTy(16));
3084 auto V6_vmpyhvsrs = HVC.HST.
getIntrinsicId(Hexagon::V6_vmpyhvsrs);
3085 return HVC.createHvxIntrinsic(Builder, V6_vmpyhvsrs,
X.Val->getType(),
3089auto HvxIdioms::createMulQ31(IRBuilderBase &Builder, SValue
X, SValue
Y,
3090 bool Rounding)
const ->
Value * {
3091 Type *InpTy =
X.Val->getType();
3092 assert(InpTy ==
Y.Val->getType());
3104 HVC.createHvxIntrinsic(Builder, V6_vmpyewuh, InpTy, {
X.Val,
Y.Val});
3105 return HVC.createHvxIntrinsic(Builder, V6_vmpyo_acc, InpTy,
3106 {
V1,
X.Val,
Y.Val});
3109auto HvxIdioms::createAddCarry(IRBuilderBase &Builder,
Value *
X,
Value *
Y,
3110 Value *CarryIn)
const
3111 -> std::pair<Value *, Value *> {
3112 assert(
X->getType() ==
Y->getType());
3121 if (CarryIn ==
nullptr)
3123 Args.push_back(CarryIn);
3125 Value *Ret = HVC.createHvxIntrinsic(Builder, AddCarry,
3129 return {
Result, CarryOut};
3136 if (CarryIn !=
nullptr) {
3137 unsigned Width = VecTy->getScalarSizeInBits();
3140 for (
unsigned i = 0, e = 32 / Width; i !=
e; ++i)
3141 Mask = (Mask << Width) | 1;
3145 HVC.createHvxIntrinsic(Builder, V6_vandqrt,
nullptr,
3146 {CarryIn, HVC.getConstInt(Mask)});
3147 Result1 = Builder.
CreateAdd(
X, ValueIn,
"add");
3153 return {Result2, Builder.
CreateOr(CarryOut1, CarryOut2,
"orb")};
3156auto HvxIdioms::createMul16(IRBuilderBase &Builder, SValue
X, SValue
Y)
const
3159 std::tie(
X,
Y) = canonSgn(
X,
Y);
3172 HVC.createHvxIntrinsic(Builder, V6_vmpyh, HvxP32Ty, {
Y.Val,
X.Val});
3174 return HVC.vshuff(Builder, HVC.sublo(Builder,
P), HVC.subhi(Builder,
P));
3177auto HvxIdioms::createMulH16(IRBuilderBase &Builder, SValue
X, SValue
Y)
const
3179 Type *HvxI16Ty = HVC.getHvxTy(HVC.getIntTy(16),
false);
3184 return HVC.createHvxIntrinsic(Builder, V6_vmpyuhvs, HvxI16Ty,
3189 Type *HvxP16Ty = HVC.getHvxTy(HVC.getIntTy(16),
true);
3192 unsigned Len = HVC.length(HvxP16Ty) / 2;
3194 SmallVector<int, 128> PickOdd(Len);
3195 for (
int i = 0; i !=
static_cast<int>(
Len); ++i)
3196 PickOdd[i] = 2 * i + 1;
3199 HVC.sublo(Builder, Pair16), HVC.subhi(Builder, Pair16), PickOdd,
"shf");
3202auto HvxIdioms::createMul32(IRBuilderBase &Builder, SValue
X, SValue
Y)
const
3203 -> std::pair<Value *, Value *> {
3204 assert(
X.Val->getType() ==
Y.Val->getType());
3205 assert(
X.Val->getType() == HvxI32Ty);
3208 std::tie(
X,
Y) = canonSgn(
X,
Y);
3211 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyss_parts;
3213 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyus_parts;
3215 V6_vmpy_parts = Intrinsic::hexagon_V6_vmpyuu_parts;
3218 Value *Parts = HVC.createHvxIntrinsic(Builder, V6_vmpy_parts,
nullptr,
3219 {
X.Val,
Y.Val}, {HvxI32Ty});
3228 assert(WordX.size() == WordY.size());
3229 unsigned Idx = 0,
Length = WordX.size();
3233 if (HVC.isZero(WordX[Idx]))
3235 else if (HVC.isZero(WordY[Idx]))
3242 Value *Carry =
nullptr;
3244 std::tie(Sum[Idx], Carry) =
3245 createAddCarry(Builder, WordX[Idx], WordY[Idx], Carry);
3259 for (
int i = 0, e = WordX.size(); i != e; ++i) {
3260 for (
int j = 0, f = WordY.size(); j != f; ++j) {
3262 Signedness SX = (i + 1 ==
e) ? SgnX :
Unsigned;
3264 auto [
Lo,
Hi] = createMul32(Builder, {WordX[i], SX}, {WordY[
j],
SY});
3265 Products[i +
j + 0].push_back(
Lo);
3266 Products[i +
j + 1].push_back(
Hi);
3280 for (
int i = 0, e = Products.size(); i != e; ++i) {
3281 while (Products[i].
size() > 1) {
3282 Value *Carry =
nullptr;
3283 for (
int j = i;
j !=
e; ++
j) {
3284 auto &ProdJ = Products[
j];
3285 auto [Sum, CarryOut] = createAddCarry(Builder, pop_back_or_zero(ProdJ),
3286 pop_back_or_zero(ProdJ), Carry);
3287 ProdJ.insert(ProdJ.begin(), Sum);
3294 for (
auto &
P : Products) {
3295 assert(
P.size() == 1 &&
"Should have been added together");
3302auto HvxIdioms::run() ->
bool {
3305 for (BasicBlock &
B : HVC.F) {
3306 for (
auto It =
B.rbegin(); It !=
B.rend(); ++It) {
3307 if (
auto Fxm = matchFxpMul(*It)) {
3308 Value *
New = processFxpMul(*It, *Fxm);
3314 It->replaceAllUsesWith(New);
3316 It = StartOver ?
B.rbegin()
3319 }
else if (matchGather(*It)) {
3325 It->eraseFromParent();
3329 }
else if (matchScatter(*It)) {
3335 It->eraseFromParent();
3339 }
else if (matchMLoad(*It)) {
3345 }
else if (matchMStore(*It)) {
3360auto HexagonVectorCombine::run() ->
bool {
3362 dbgs() <<
"Module before HexagonVectorCombine\n" << *
F.getParent();
3365 if (HST.useHVXOps()) {
3367 Changed |= AlignVectors(*this).run();
3369 Changed |= HvxIdioms(*this).run();
3373 dbgs() <<
"Module " << (
Changed ?
"(modified)" :
"(unchanged)")
3374 <<
" after HexagonVectorCombine\n"
3380auto HexagonVectorCombine::getIntTy(
unsigned Width)
const -> IntegerType * {
3384auto HexagonVectorCombine::getByteTy(
int ElemCount)
const ->
Type * {
3386 IntegerType *ByteTy = Type::getInt8Ty(
F.getContext());
3389 return VectorType::get(ByteTy, ElemCount,
false);
3392auto HexagonVectorCombine::getBoolTy(
int ElemCount)
const ->
Type * {
3394 IntegerType *BoolTy = Type::getInt1Ty(
F.getContext());
3397 return VectorType::get(BoolTy, ElemCount,
false);
3400auto HexagonVectorCombine::getConstInt(
int Val,
unsigned Width)
const
3405auto HexagonVectorCombine::isZero(
const Value *Val)
const ->
bool {
3407 return C->isNullValue();
3411auto HexagonVectorCombine::getIntValue(
const Value *Val)
const
3412 -> std::optional<APInt> {
3414 return CI->getValue();
3415 return std::nullopt;
3418auto HexagonVectorCombine::isUndef(
const Value *Val)
const ->
bool {
3422auto HexagonVectorCombine::isTrue(
const Value *Val)
const ->
bool {
3426auto HexagonVectorCombine::isFalse(
const Value *Val)
const ->
bool {
3430auto HexagonVectorCombine::getHvxTy(
Type *ElemTy,
bool Pair)
const
3436 "Invalid HVX element type");
3437 unsigned HwLen = HST.getVectorLength();
3439 return VectorType::get(ElemTy, Pair ? 2 * NumElems : NumElems,
3443auto HexagonVectorCombine::getSizeOf(
const Value *Val, SizeKind Kind)
const
3445 return getSizeOf(Val->
getType(), Kind);
3448auto HexagonVectorCombine::getSizeOf(
const Type *Ty, SizeKind Kind)
const
3450 auto *NcTy =
const_cast<Type *
>(Ty);
3453 return DL.getTypeStoreSize(NcTy).getFixedValue();
3455 return DL.getTypeAllocSize(NcTy).getFixedValue();
3460auto HexagonVectorCombine::getTypeAlignment(
Type *Ty)
const ->
int {
3463 if (HST.isTypeForHVX(Ty))
3464 return HST.getVectorLength();
3465 return DL.getABITypeAlign(Ty).value();
3468auto HexagonVectorCombine::length(
Value *Val)
const ->
size_t {
3469 return length(Val->
getType());
3472auto HexagonVectorCombine::length(
Type *Ty)
const ->
size_t {
3474 assert(VecTy &&
"Must be a vector type");
3475 return VecTy->getElementCount().getFixedValue();
3478auto HexagonVectorCombine::simplify(
Value *V)
const ->
Value * {
3480 SimplifyQuery Q(
DL, &TLI, &DT, &AC, In);
3487auto HexagonVectorCombine::insertb(IRBuilderBase &Builder,
Value *Dst,
3489 int Where)
const ->
Value * {
3490 assert(isByteVecTy(Dst->getType()) && isByteVecTy(Src->getType()));
3491 int SrcLen = getSizeOf(Src);
3492 int DstLen = getSizeOf(Dst);
3498 Value *P2Src = vresize(Builder, Src, P2Len, Poison);
3499 Value *P2Dst = vresize(Builder, Dst, P2Len, Poison);
3502 for (
int i = 0; i != P2Len; ++i) {
3506 (Where <= i && i < Where +
Length) ? P2Len + Start + (i - Where) : i;
3510 return vresize(Builder, P2Insert, DstLen, Poison);
3513auto HexagonVectorCombine::vlalignb(IRBuilderBase &Builder,
Value *
Lo,
3515 assert(
Lo->getType() ==
Hi->getType() &&
"Argument type mismatch");
3518 int VecLen = getSizeOf(
Hi);
3519 if (
auto IntAmt = getIntValue(Amt))
3520 return getElementRange(Builder,
Lo,
Hi, VecLen - IntAmt->getSExtValue(),
3523 if (HST.isTypeForHVX(
Hi->getType())) {
3524 assert(
static_cast<unsigned>(VecLen) == HST.getVectorLength() &&
3525 "Expecting an exact HVX type");
3526 return createHvxIntrinsic(Builder, HST.getIntrinsicId(Hexagon::V6_vlalignb),
3527 Hi->getType(), {Hi, Lo, Amt});
3535 Builder.
CreateTrunc(Shift, Type::getInt32Ty(
F.getContext()),
"trn");
3540 return vralignb(Builder,
Lo,
Hi,
Sub);
3545auto HexagonVectorCombine::vralignb(IRBuilderBase &Builder,
Value *
Lo,
3547 assert(
Lo->getType() ==
Hi->getType() &&
"Argument type mismatch");
3550 int VecLen = getSizeOf(
Lo);
3551 if (
auto IntAmt = getIntValue(Amt))
3552 return getElementRange(Builder,
Lo,
Hi, IntAmt->getSExtValue(), VecLen);
3554 if (HST.isTypeForHVX(
Lo->getType())) {
3555 assert(
static_cast<unsigned>(VecLen) == HST.getVectorLength() &&
3556 "Expecting an exact HVX type");
3557 return createHvxIntrinsic(Builder, HST.getIntrinsicId(Hexagon::V6_valignb),
3558 Lo->getType(), {Hi, Lo, Amt});
3565 Builder.
CreateTrunc(Shift, Type::getInt32Ty(
F.getContext()),
"trn");
3569 Type *Int64Ty = Type::getInt64Ty(
F.getContext());
3581auto HexagonVectorCombine::concat(IRBuilderBase &Builder,
3585 std::vector<Value *> Work[2];
3586 int ThisW = 0, OtherW = 1;
3588 Work[ThisW].assign(Vecs.begin(), Vecs.end());
3589 while (Work[ThisW].
size() > 1) {
3591 SMask.
resize(length(Ty) * 2);
3592 std::iota(SMask.
begin(), SMask.
end(), 0);
3594 Work[OtherW].clear();
3595 if (Work[ThisW].
size() % 2 != 0)
3597 for (
int i = 0, e = Work[ThisW].
size(); i <
e; i += 2) {
3599 Work[ThisW][i], Work[ThisW][i + 1], SMask,
"shf");
3600 Work[OtherW].push_back(Joined);
3608 SMask.
resize(Vecs.size() * length(Vecs.front()->getType()));
3609 std::iota(SMask.
begin(), SMask.
end(), 0);
3614auto HexagonVectorCombine::vresize(IRBuilderBase &Builder,
Value *Val,
3618 assert(ValTy->getElementType() == Pad->getType());
3620 int CurSize = length(ValTy);
3621 if (CurSize == NewSize)
3624 if (CurSize > NewSize)
3625 return getElementRange(Builder, Val, Val, 0, NewSize);
3627 SmallVector<int, 128> SMask(NewSize);
3628 std::iota(SMask.
begin(), SMask.
begin() + CurSize, 0);
3629 std::fill(SMask.
begin() + CurSize, SMask.
end(), CurSize);
3634auto HexagonVectorCombine::rescale(IRBuilderBase &Builder,
Value *Mask,
3641 Type *FromSTy = FromTy->getScalarType();
3642 Type *ToSTy = ToTy->getScalarType();
3643 if (FromSTy == ToSTy)
3646 int FromSize = getSizeOf(FromSTy);
3647 int ToSize = getSizeOf(ToSTy);
3648 assert(FromSize % ToSize == 0 || ToSize % FromSize == 0);
3651 int FromCount = length(MaskTy);
3652 int ToCount = (FromCount * FromSize) / ToSize;
3653 assert((FromCount * FromSize) % ToSize == 0);
3655 auto *FromITy =
getIntTy(FromSize * 8);
3656 auto *ToITy =
getIntTy(ToSize * 8);
3661 Mask, VectorType::get(FromITy, FromCount,
false),
"sxt");
3663 Ext, VectorType::get(ToITy, ToCount,
false),
"cst");
3665 Cast, VectorType::get(getBoolTy(), ToCount,
false),
"trn");
3669auto HexagonVectorCombine::vlsb(IRBuilderBase &Builder,
Value *Val)
const
3672 if (ScalarTy == getBoolTy())
3675 Value *Bytes = vbytes(Builder, Val);
3677 return Builder.
CreateTrunc(Bytes, getBoolTy(getSizeOf(VecTy)),
"trn");
3680 return Builder.
CreateTrunc(Bytes, getBoolTy(),
"trn");
3684auto HexagonVectorCombine::vbytes(IRBuilderBase &Builder,
Value *Val)
const
3687 if (ScalarTy == getByteTy())
3690 if (ScalarTy != getBoolTy())
3691 return Builder.
CreateBitCast(Val, getByteTy(getSizeOf(Val)),
"cst");
3694 return Builder.
CreateSExt(Val, VectorType::get(getByteTy(), VecTy),
"sxt");
3695 return Builder.
CreateSExt(Val, getByteTy(),
"sxt");
3698auto HexagonVectorCombine::subvector(IRBuilderBase &Builder,
Value *Val,
3699 unsigned Start,
unsigned Length)
const
3702 return getElementRange(Builder, Val, Val, Start,
Length);
3705auto HexagonVectorCombine::sublo(IRBuilderBase &Builder,
Value *Val)
const
3707 size_t Len = length(Val);
3708 assert(Len % 2 == 0 &&
"Length should be even");
3709 return subvector(Builder, Val, 0, Len / 2);
3712auto HexagonVectorCombine::subhi(IRBuilderBase &Builder,
Value *Val)
const
3714 size_t Len = length(Val);
3715 assert(Len % 2 == 0 &&
"Length should be even");
3716 return subvector(Builder, Val, Len / 2, Len / 2);
3719auto HexagonVectorCombine::vdeal(IRBuilderBase &Builder,
Value *Val0,
3721 assert(Val0->getType() == Val1->getType());
3722 int Len = length(Val0);
3723 SmallVector<int, 128>
Mask(2 * Len);
3725 for (
int i = 0; i !=
Len; ++i) {
3732auto HexagonVectorCombine::vshuff(IRBuilderBase &Builder,
Value *Val0,
3734 assert(Val0->getType() == Val1->getType());
3735 int Len = length(Val0);
3736 SmallVector<int, 128>
Mask(2 * Len);
3738 for (
int i = 0; i !=
Len; ++i) {
3739 Mask[2 * i + 0] = i;
3745auto HexagonVectorCombine::createHvxIntrinsic(IRBuilderBase &Builder,
3751 auto getCast = [&](IRBuilderBase &Builder,
Value *Val,
3753 Type *SrcTy = Val->getType();
3754 if (SrcTy == DestTy)
3759 assert(HST.isTypeForHVX(SrcTy,
true));
3761 Type *BoolTy = Type::getInt1Ty(
F.getContext());
3766 unsigned HwLen = HST.getVectorLength();
3767 Intrinsic::ID TC = HwLen == 64 ? Intrinsic::hexagon_V6_pred_typecast
3768 : Intrinsic::hexagon_V6_pred_typecast_128B;
3777 SmallVector<Value *, 4> IntrArgs;
3778 for (
int i = 0, e =
Args.size(); i != e; ++i) {
3780 Type *
T = IntrTy->getParamType(i);
3781 if (
A->getType() !=
T) {
3787 StringRef MaybeName = !IntrTy->getReturnType()->isVoidTy() ?
"cup" :
"";
3788 CallInst *
Call = Builder.
CreateCall(IntrFn, IntrArgs, MaybeName);
3795 if (RetTy ==
nullptr || CallTy == RetTy)
3798 assert(HST.isTypeForHVX(CallTy,
true));
3799 return getCast(Builder,
Call, RetTy);
3802auto HexagonVectorCombine::splitVectorElements(IRBuilderBase &Builder,
3804 unsigned ToWidth)
const
3819 assert(VecTy->getElementType()->isIntegerTy());
3820 unsigned FromWidth = VecTy->getScalarSizeInBits();
3822 assert(ToWidth <= FromWidth &&
"Breaking up into wider elements?");
3823 unsigned NumResults = FromWidth / ToWidth;
3827 unsigned Length = length(VecTy);
3831 auto splitInHalf = [&](
unsigned Begin,
unsigned End,
auto splitFunc) ->
void {
3835 if (Begin + 1 ==
End)
3841 auto *VTy = VectorType::get(
getIntTy(Width / 2), 2 *
Length,
false);
3844 Value *Res =
vdeal(Builder, sublo(Builder, VVal), subhi(Builder, VVal));
3846 unsigned Half = (Begin +
End) / 2;
3847 Results[Begin] = sublo(Builder, Res);
3848 Results[Half] = subhi(Builder, Res);
3850 splitFunc(Begin, Half, splitFunc);
3851 splitFunc(Half,
End, splitFunc);
3854 splitInHalf(0, NumResults, splitInHalf);
3858auto HexagonVectorCombine::joinVectorElements(IRBuilderBase &Builder,
3860 VectorType *ToType)
const
3862 assert(ToType->getElementType()->isIntegerTy());
3873 unsigned ToWidth = ToType->getScalarSizeInBits();
3874 unsigned Width = Inputs.front()->getType()->getScalarSizeInBits();
3875 assert(Width <= ToWidth);
3877 unsigned Length = length(Inputs.front()->getType());
3879 unsigned NeedInputs = ToWidth / Width;
3880 if (Inputs.size() != NeedInputs) {
3885 Last, ConstantInt::get(
Last->getType(), Width - 1),
"asr");
3886 Inputs.resize(NeedInputs, Sign);
3889 while (Inputs.size() > 1) {
3892 for (
int i = 0, e = Inputs.size(); i < e; i += 2) {
3893 Value *Res =
vshuff(Builder, Inputs[i], Inputs[i + 1]);
3896 Inputs.resize(Inputs.size() / 2);
3899 assert(Inputs.front()->getType() == ToType);
3900 return Inputs.front();
3903auto HexagonVectorCombine::calculatePointerDifference(
Value *Ptr0,
3905 -> std::optional<int> {
3907 const SCEV *Scev0 = SE.getSCEV(Ptr0);
3908 const SCEV *Scev1 = SE.getSCEV(Ptr1);
3909 const SCEV *ScevDiff = SE.getMinusSCEV(Scev0, Scev1);
3911 APInt
V =
Const->getAPInt();
3912 if (
V.isSignedIntN(8 *
sizeof(
int)))
3913 return static_cast<int>(
V.getSExtValue());
3920 I->eraseFromParent();
3922 SmallVector<Instruction *, 8> ToErase;
3925#define CallBuilder(B, F) \
3928 if (auto *I = dyn_cast<Instruction>(V)) \
3929 B_.ToErase.push_back(I); \
3933 auto Simplify = [
this](
Value *
V) {
3939 auto StripBitCast = [](
Value *
V) {
3941 V =
C->getOperand(0);
3945 Ptr0 = StripBitCast(Ptr0);
3946 Ptr1 = StripBitCast(Ptr1);
3948 return std::nullopt;
3952 if (Gep0->getPointerOperand() != Gep1->getPointerOperand())
3953 return std::nullopt;
3954 if (Gep0->getSourceElementType() != Gep1->getSourceElementType())
3955 return std::nullopt;
3957 Builder
B(Gep0->getParent());
3958 int Scale = getSizeOf(Gep0->getSourceElementType(),
Alloc);
3961 if (Gep0->getNumOperands() != 2 || Gep1->getNumOperands() != 2)
3962 return std::nullopt;
3964 Value *Idx0 = Gep0->getOperand(1);
3965 Value *Idx1 = Gep1->getOperand(1);
3970 return Diff->getSExtValue() * Scale;
3972 KnownBits Known0 = getKnownBits(Idx0, Gep0);
3973 KnownBits Known1 = getKnownBits(Idx1, Gep1);
3976 return std::nullopt;
3984 Diff0 =
C->getSExtValue();
3986 return std::nullopt;
3995 Diff1 =
C->getSExtValue();
3997 return std::nullopt;
4000 return (Diff0 + Diff1) * Scale;
4005auto HexagonVectorCombine::getNumSignificantBits(
const Value *V,
4006 const Instruction *CtxI)
const
4011auto HexagonVectorCombine::getKnownBits(
const Value *V,
4012 const Instruction *CtxI)
const
4017auto HexagonVectorCombine::isSafeToClone(
const Instruction &In)
const ->
bool {
4018 if (
In.mayHaveSideEffects() ||
In.isAtomic() ||
In.isVolatile() ||
4019 In.isFenceLike() ||
In.mayReadOrWriteMemory()) {
4027template <
typename T>
4028auto HexagonVectorCombine::isSafeToMoveBeforeInBB(
const Instruction &In,
4030 const T &IgnoreInsts)
const
4033 [
this](
const Instruction &
I) -> std::optional<MemoryLocation> {
4035 switch (
II->getIntrinsicID()) {
4036 case Intrinsic::masked_load:
4038 case Intrinsic::masked_store:
4054 bool MayWrite =
In.mayWriteToMemory();
4055 auto MaybeLoc = getLocOrNone(In);
4057 auto From =
In.getIterator();
4060 bool MoveUp = (To !=
Block.end() && To->comesBefore(&In));
4062 MoveUp ? std::make_pair(To, From) : std::make_pair(std::next(From), To);
4063 for (
auto It =
Range.first; It !=
Range.second; ++It) {
4064 const Instruction &I = *It;
4065 if (llvm::is_contained(IgnoreInsts, &I))
4068 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
4069 if (II->getIntrinsicID() == Intrinsic::assume)
4076 if (!CB->hasFnAttr(Attribute::WillReturn))
4078 if (!CB->hasFnAttr(Attribute::NoSync))
4081 if (
I.mayReadOrWriteMemory()) {
4082 auto MaybeLocI = getLocOrNone(I);
4083 if (MayWrite || I.mayWriteToMemory()) {
4084 if (!MaybeLoc || !MaybeLocI)
4086 if (!AA.isNoAlias(*MaybeLoc, *MaybeLocI))
4094auto HexagonVectorCombine::isByteVecTy(
Type *Ty)
const ->
bool {
4096 return VecTy->getElementType() == getByteTy();
4100auto HexagonVectorCombine::getElementRange(IRBuilderBase &Builder,
Value *
Lo,
4104 SmallVector<int, 128> SMask(
Length);
4105 std::iota(SMask.
begin(), SMask.
end(), Start);
4112class HexagonVectorCombineLegacy :
public FunctionPass {
4116 HexagonVectorCombineLegacy() : FunctionPass(
ID) {}
4118 StringRef getPassName()
const override {
return "Hexagon Vector Combine"; }
4120 void getAnalysisUsage(AnalysisUsage &AU)
const override {
4128 AU.
addRequired<OptimizationRemarkEmitterWrapperPass>();
4129 FunctionPass::getAnalysisUsage(AU);
4133 if (skipFunction(
F))
4135 AliasAnalysis &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
4136 AssumptionCache &AC =
4137 getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
4138 DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
4139 ScalarEvolution &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
4140 TargetLibraryInfo &TLI =
4141 getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(
F);
4142 auto &TM = getAnalysis<TargetPassConfig>().getTM<HexagonTargetMachine>();
4143 auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
4144 HexagonVectorCombine HVC(
F, AA, AC, DT, SE, TLI, TM, ORE);
4150char HexagonVectorCombineLegacy::ID = 0;
4153 "Hexagon Vector Combine",
false,
false)
4165 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.
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CtxI=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...
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.
LLVM_ABI unsigned ComputeMaxSignificantBits(const Value *Op, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Get the upper bound on bit size for this Value Op as a signed integer.
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
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 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.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
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.
@ 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...
Align getKnownAlignment(Value *V, const DataLayout &DL, const Instruction *CtxI=nullptr, AssumptionCache *AC=nullptr, const DominatorTree *DT=nullptr)
Try to infer an alignment for the specified pointer.
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
@ End
Run the machine verifier once, at the end of the pipeline.
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.