LLVM: lib/Target/Hexagon/HexagonGenWideningVecInstr.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
21#include "llvm/IR/IntrinsicsHexagon.h"
28#include
29#include
30
31using namespace llvm;
32
33
34
36 "hexagon-widen-short-vector",
37 cl::desc("Generate widening instructions for short vectors."), cl::Hidden);
38
39namespace llvm {
42}
43
44namespace {
45
46class HexagonGenWideningVecInstr : public FunctionPass {
47public:
48 static char ID;
49
52 }
53
54 HexagonGenWideningVecInstr(const HexagonTargetMachine *TM)
55 : FunctionPass(ID), TM(TM) {
57 }
58
59 StringRef getPassName() const override {
60 return "Hexagon generate widening vector instructions";
61 }
62
64
65 void getAnalysisUsage(AnalysisUsage &AU) const override {
66 FunctionPass::getAnalysisUsage(AU);
67 }
68
69private:
71 const HexagonTargetMachine *TM = nullptr;
72 const HexagonSubtarget *HST = nullptr;
73 unsigned HwVLen;
74 enum OPKind { OP_None = 0, OP_Add, OP_Sub, OP_Mul, OP_Shl };
75
76 struct OPInfo {
77 Value *OP = nullptr;
78 Value *ExtInOP = nullptr;
79 bool IsZExt = false;
80 unsigned ExtInSize = 0;
81 bool IsScalar = false;
82 };
83
84 bool visitBlock(BasicBlock *B);
85 bool processInstruction(Instruction *Inst);
86 bool replaceWithIntrinsic(Instruction *Inst, OPKind OPK, OPInfo &OP1Info,
87 OPInfo &OP2Info);
89 bool isExtendedConstant(Constant *C, bool IsSigned);
90 unsigned getElementSizeInBits(Value *V, bool IsZExt);
92
94 unsigned NewEltsize, unsigned NumElts);
95
96 Intrinsic::ID getIntrinsic(OPKind OPK, bool IsOP1ZExt, bool IsOP2ZExt,
97 unsigned NewOpEltSize, unsigned NewResEltSize,
98 bool IsConstScalar, int ConstOpNum);
99
100 std::pair<Value *, Value *> opSplit(Value *OP, Instruction *Inst,
101 Type *NewOpType);
102
104 Value *NewOP2, Type *ResType, unsigned NumElts,
105 bool Interleave);
106 bool processInstructionForVMPA(Instruction *Inst);
107 bool getVmpaOperandInfo(Value *V, OPInfo &OPI);
108 void reorderVmpaOperands(OPInfo *OPI);
109 bool replaceWithVmpaIntrinsic(Instruction *Inst, OPInfo *OPI);
110 bool genSaturatingInst(Instruction *Inst);
111 bool getMinMax(Constant *MinC, Constant *MaxC, std::pair<int, int> &MinMax);
112 bool isSaturatingVAsr(Instruction *Inst, Value *S, int MinV, int MaxV,
113 bool &IsResSigned);
115 Intrinsic::ID getVAsrIntrinsic(bool IsInSigned, bool IsResSigned);
116 Value *createVAsrIntrinsic(Instruction *Inst, Value *VecOP, Value *ShiftByVal,
117 bool IsResSigned);
118 bool genVAvg(Instruction *Inst);
119 bool checkConstantVector(Value *OP, int64_t &SplatVal, bool IsOPZExt);
120 void updateMPYConst(Intrinsic::ID IntId, int64_t &SplatVal, bool IsOPZExt,
124};
125
126}
127
128char HexagonGenWideningVecInstr::ID = 0;
129
131 "Hexagon generate "
132 "widening vector instructions",
133 false, false)
136 "Hexagon generate "
137 "widening vector instructions",
139
141 if (Value *SplatV = C->getSplatValue()) {
142 auto *CI = dyn_cast(SplatV);
143 assert(CI);
144 return CI->getValue().isNegative();
145 }
147 for (unsigned i = 0, e = NumElts; i != e; ++i) {
150 if (CI->getValue().isNegative())
151 return true;
152 continue;
153 }
154 return false;
155}
156
157bool HexagonGenWideningVecInstr::getOperandInfo(Value *V, OPInfo &OPI) {
158 using namespace PatternMatch;
159 OPI.OP = V;
160 Value *ExtV = nullptr;
162
163 bool Match = false;
167 m_Poison(), m_ZeroMask()))))) {
168 OPI.ExtInOP = ExtV;
169 OPI.IsZExt = true;
170 }
171
172 if (!Match &&
176 m_Poison(), m_ZeroMask()))))) {
177 OPI.ExtInOP = ExtV;
178 OPI.IsZExt = false;
179 }
180 if (!Match &&
181 (Match =
183 m_Poison(), m_ZeroMask()))))) {
185 OPI.ExtInOP = ExtV;
186 OPI.IsZExt = true;
187 OPI.ExtInSize = 8;
188 return true;
189 }
191 OPI.ExtInOP = ExtV;
192 OPI.IsZExt = true;
193 OPI.ExtInSize = 16;
194 return true;
195 }
196 return false;
197 }
198
200 if (!isExtendedConstant(C, false) && !isExtendedConstant(C, true))
201 return false;
202 OPI.ExtInOP = C;
204 }
205
206 if (!Match)
207 return false;
208
209
210 if (OPI.ExtInOP)
211 OPI.ExtInSize = getElementSizeInBits(OPI.ExtInOP, OPI.IsZExt);
212 return true;
213}
214
215bool HexagonGenWideningVecInstr::isExtendedConstant(Constant *C,
216 bool IsSigned) {
219 unsigned HalfSize = EltSize / 2;
220 if (Value *SplatV = C->getSplatValue()) {
222 return IsSigned ? isIntN(HalfSize, CI->getSExtValue())
223 : isUIntN(HalfSize, CI->getZExtValue());
224 return false;
225 }
227 for (unsigned i = 0, e = NumElts; i != e; ++i) {
229 if ((IsSigned && (HalfSize, CI->getSExtValue())) ||
230 (!IsSigned && (HalfSize, CI->getZExtValue())))
231 return false;
232 continue;
233 }
234 return false;
235 }
236 return true;
237}
238
239unsigned HexagonGenWideningVecInstr::getElementSizeInBits(Value *V,
240 bool IsZExt = false) {
241 using namespace PatternMatch;
242 Type *ValTy = V->getType();
243 Type *EltTy = ValTy;
247 ->getElementType()
248 ->getPrimitiveSizeInBits()
249 .getKnownMinValue();
250 unsigned ReducedSize = EltSize / 2;
251
252 while (ReducedSize >= 8) {
253 for (unsigned i = 0, e = NumElts; i != e; ++i) {
255 if (IsZExt) {
256 if ((ReducedSize, CI->getZExtValue()))
257 return EltSize;
258 } else if ((ReducedSize, CI->getSExtValue()))
259 return EltSize;
260 }
261 }
262 EltSize = ReducedSize;
263 ReducedSize = ReducedSize / 2;
264 }
265 return EltSize;
266 }
267
271}
272
273Value *HexagonGenWideningVecInstr::adjustExtensionForOp(OPInfo &OPI,
275 unsigned NewExtSize,
276 unsigned NumElts) {
278 bool IsZExt = OPI.IsZExt;
279 unsigned EltSize = getElementSizeInBits(OPI.ExtInOP, OPI.IsZExt);
280 Type *EltType = getElementTy(NewExtSize, IRB);
282
285
286 if (V->getType()->isVectorTy()) {
287 if (NewExtSize == EltSize)
288 return V;
289 assert(NewExtSize == 16);
292 }
293
294
295
296
298 assert(I && I->getOpcode() == Instruction::ShuffleVector);
299
300 if (NewExtSize > EltSize)
302 else if (NewExtSize < EltSize)
304
307
309 for (unsigned i = 0; i < NumElts; ++i)
311
314}
315
316Intrinsic::ID HexagonGenWideningVecInstr::getIntrinsic(
317 OPKind OPK, bool IsOP1ZExt, bool IsOP2ZExt, unsigned InEltSize,
318 unsigned ResEltSize, bool IsConstScalar, int ConstOpNum) {
319
320 switch (OPK) {
321 case OP_Add:
322
323 assert(IsOP1ZExt == IsOP2ZExt);
324 if (InEltSize == 8 && ResEltSize == 16) {
325
326
327 assert(IsOP1ZExt && "Operands must be zero-extended");
328 return Intrinsic::hexagon_vadd_uu;
329 }
330 if (InEltSize == 16 && ResEltSize == 32)
331 return (IsOP1ZExt) ? Intrinsic::hexagon_vadd_uu
332 : Intrinsic::hexagon_vadd_ss;
333
334 llvm_unreachable("Incorrect input and output operand sizes");
335
336 case OP_Sub:
337
338 assert(IsOP1ZExt == IsOP2ZExt);
339 if (InEltSize == 8 && ResEltSize == 16) {
340
341
342 assert(IsOP1ZExt && "Operands must be zero-extended");
343 return Intrinsic::hexagon_vsub_uu;
344 }
345 if (InEltSize == 16 && ResEltSize == 32)
346 return (IsOP1ZExt) ? Intrinsic::hexagon_vsub_uu
347 : Intrinsic::hexagon_vsub_ss;
348
349 llvm_unreachable("Incorrect input and output operand sizes");
350
351 case OP_Mul:
352 assert(ResEltSize == 2 * InEltSize);
353
354 if (IsConstScalar) {
355
356 if (InEltSize == 8 && ResEltSize == 16) {
357
358
359 if (ConstOpNum == 2 && IsOP1ZExt) {
360
361
362 return (IsOP2ZExt) ? Intrinsic::hexagon_vmpy_ub_ub
363 : Intrinsic::hexagon_vmpy_ub_b;
364 } else if (ConstOpNum == 1 && IsOP2ZExt) {
365 return (IsOP1ZExt) ? Intrinsic::hexagon_vmpy_ub_ub
366 : Intrinsic::hexagon_vmpy_ub_b;
367 }
368 }
369
370
371 if (InEltSize == 16 && ResEltSize == 32) {
372 if (IsOP1ZExt && IsOP2ZExt) {
373
374
375 return Intrinsic::hexagon_vmpy_uh_uh;
376 } else if (!IsOP1ZExt && !IsOP2ZExt) {
377
378
379 return Intrinsic::hexagon_vmpy_h_h;
380 }
381 }
382 }
383 if (IsOP1ZExt)
384 return IsOP2ZExt ? Intrinsic::hexagon_vmpy_uu
385 : Intrinsic::hexagon_vmpy_us;
386 else
387 return IsOP2ZExt ? Intrinsic::hexagon_vmpy_su
388 : Intrinsic::hexagon_vmpy_ss;
389 default:
391 }
392}
393
394Type *HexagonGenWideningVecInstr::getElementTy(unsigned size,
396 switch (size) {
397 case 8:
399 case 16:
401 case 32:
403 default:
405 }
406}
407
408Value *HexagonGenWideningVecInstr::createIntrinsic(
410 Type *ResType, unsigned NumElts, bool Interleave = true) {
414 if (Interleave) {
415
417 unsigned HalfElts = NumElts / 2;
418 for (unsigned i = 0; i < HalfElts; ++i) {
421 }
424 }
425 return NewIn;
426}
427
428std::pair<Value *, Value *>
429HexagonGenWideningVecInstr::opSplit(Value *OP, Instruction *Inst,
430 Type *NewOpType) {
435
436
437
438
439
440 assert(NumElts % 2 == 0 && "Unexpected Vector Type!!");
441 unsigned HalfElts = NumElts / 2;
444 for (unsigned i = 0; i < HalfElts; ++i)
446 for (unsigned i = 0; i < HalfElts; ++i)
448
453 return std::pair<Value *, Value *>(Hi, Lo);
454 }
455
456 Intrinsic::ID IntHi = Intrinsic::hexagon_V6_hi_128B;
457 Intrinsic::ID IntLo = Intrinsic::hexagon_V6_lo_128B;
466 return std::pair<Value *, Value *>(Hi, Lo);
467}
468
469bool HexagonGenWideningVecInstr::checkConstantVector(Value *OP,
470 int64_t &SplatVal,
471 bool IsOPZExt) {
473 if (Value *SplatV = C1->getSplatValue()) {
475 if (IsOPZExt) {
476 SplatVal = CI->getZExtValue();
477 } else {
478 SplatVal = CI->getSExtValue();
479 }
480 return true;
481 }
482 }
483 return false;
484}
485
486void HexagonGenWideningVecInstr::updateMPYConst(Intrinsic::ID IntId,
487 int64_t &SplatVal,
488 bool IsOPZExt, Value *&OP,
490 if ((IntId == Intrinsic::hexagon_vmpy_uu ||
491 IntId == Intrinsic::hexagon_vmpy_us ||
492 IntId == Intrinsic::hexagon_vmpy_su ||
493 IntId == Intrinsic::hexagon_vmpy_ss) &&
494 OP->getType()->isVectorTy()) {
495
497 Value *scalar = IRB.getIntN(VecTy->getScalarSizeInBits(),
498 static_cast<uint32_t>(SplatVal));
501 OP = IsOPZExt ? IRB.CreateZExt(splatVector, VecTy)
502 : IRB.CreateSExt(splatVector, VecTy);
503 } else {
504 packConstant(IntId, SplatVal, OP, IRB);
505 }
506}
507
508void HexagonGenWideningVecInstr::packConstant(Intrinsic::ID IntId,
509 int64_t &SplatVal, Value *&OP,
511 uint32_t Val32 = static_cast<uint32_t>(SplatVal);
512 if (IntId == Intrinsic::hexagon_vmpy_ub_ub) {
513 assert(SplatVal >= 0 && SplatVal <= UINT8_MAX);
514 uint32_t packed = (Val32 << 24) | (Val32 << 16) | (Val32 << 8) | Val32;
516 } else if (IntId == Intrinsic::hexagon_vmpy_ub_b) {
517 assert(SplatVal >= INT8_MIN && SplatVal <= INT8_MAX);
518 uint32_t packed = (Val32 << 24) | ((Val32 << 16) & ((1 << 24) - 1)) |
519 ((Val32 << 8) & ((1 << 16) - 1)) |
520 (Val32 & ((1 << 8) - 1));
522 } else if (IntId == Intrinsic::hexagon_vmpy_uh_uh) {
523 assert(SplatVal >= 0 && SplatVal <= UINT16_MAX);
524 uint32_t packed = (Val32 << 16) | Val32;
526 } else if (IntId == Intrinsic::hexagon_vmpy_h_h) {
527 assert(SplatVal >= INT16_MIN && SplatVal <= INT16_MAX);
528 uint32_t packed = (Val32 << 16) | (Val32 & ((1 << 16) - 1));
530 }
531}
532
533bool HexagonGenWideningVecInstr::replaceWithIntrinsic(Instruction *Inst,
534 OPKind OPK,
535 OPInfo &OP1Info,
536 OPInfo &OP2Info) {
541
542 bool IsOP1ZExt = OP1Info.IsZExt;
543 bool IsOP2ZExt = OP2Info.IsZExt;
544
545
546 bool IsResZExt = (OPK == OP_Mul || OPK == OP_Shl)
547 ? (OP1Info.IsZExt && OP2Info.IsZExt)
548 : false;
549
550 unsigned MaxEltSize = std::max(OP1Info.ExtInSize, OP2Info.ExtInSize);
551 unsigned NewOpEltSize = MaxEltSize;
552 unsigned NewResEltSize = 2 * MaxEltSize;
553
554
555
556
557
558
559
560 if (OPK != OP_Mul && OPK != OP_Shl &&
561 (IsOP1ZExt != IsOP2ZExt || (!IsOP1ZExt && NewOpEltSize == 8)))
562 NewOpEltSize = 2 * NewOpEltSize;
563
564 unsigned ResVLen = NewResEltSize * NumElts;
566 return false;
567 if (NewOpEltSize > 16 || ((ResVLen > HwVLen) && (ResVLen % HwVLen) != 0))
568 return false;
569
571 Value *NewOP1 = adjustExtensionForOp(OP1Info, IRB, NewOpEltSize, NumElts);
572 Value *NewOP2 = adjustExtensionForOp(OP2Info, IRB, NewOpEltSize, NumElts);
573
574 if (NewOpEltSize == NewResEltSize) {
575 assert(OPK != OP_Mul && OPK != OP_Shl);
576
578 NewOP1, NewOP2);
579 if (InstEltSize > NewResEltSize)
580 NewIn = IRB.CreateSExt(NewIn, InstTy);
582 return true;
583 }
584
585 bool IsConstScalar = false;
586 int64_t SplatVal = 0;
587 int ConstOpNum = 1;
588 if (OPK == OP_Mul || OPK == OP_Shl) {
589 IsConstScalar = checkConstantVector(NewOP1, SplatVal, IsOP1ZExt);
590 if (!IsConstScalar) {
591 IsConstScalar = checkConstantVector(NewOP2, SplatVal, IsOP2ZExt);
592 ConstOpNum = 2;
593 }
594 }
595
596 if (IsConstScalar && OPK == OP_Shl) {
597 if (((NewOpEltSize == 8) && (SplatVal > 0) && (SplatVal < 8)) ||
598 ((NewOpEltSize == 16) && (SplatVal > 0) && (SplatVal < 16))) {
599 SplatVal = 1LL << SplatVal;
600 OPK = OP_Mul;
601 } else {
602 return false;
603 }
604 } else if (!IsConstScalar && OPK == OP_Shl) {
605 return false;
606 }
607
608 Intrinsic::ID IntId = getIntrinsic(OPK, IsOP1ZExt, IsOP2ZExt, NewOpEltSize,
609 NewResEltSize, IsConstScalar, ConstOpNum);
610
611 if (IsConstScalar) {
612 updateMPYConst(IntId, SplatVal, IsOP2ZExt, NewOP2, IRB);
613 }
614
615
616 if (ResVLen > 2 * HwVLen) {
617 assert(ResVLen == 4 * HwVLen);
618
619 unsigned HalfElts = NumElts / 2;
620 auto *NewOpType =
622 auto *ResType =
624 std::pair<Value *, Value *> SplitOP1 = opSplit(NewOP1, Inst, NewOpType);
625 std::pair<Value *, Value *> SplitOP2;
626 if (IsConstScalar && (IntId == Intrinsic::hexagon_vmpy_h_h ||
627 IntId == Intrinsic::hexagon_vmpy_uh_uh)) {
628 SplitOP2 = std::pair<Value *, Value *>(NewOP2, NewOP2);
629 } else {
630 SplitOP2 = opSplit(NewOP2, Inst, NewOpType);
631 }
632 Value *NewInHi = createIntrinsic(IntId, Inst, SplitOP1.first,
633 SplitOP2.first, ResType, HalfElts, true);
634 Value *NewInLo = createIntrinsic(IntId, Inst, SplitOP1.second,
635 SplitOP2.second, ResType, HalfElts, true);
636 assert(InstEltSize == NewResEltSize);
638 for (unsigned i = 0; i < NumElts; ++i)
640
643
645 return true;
646 }
647
648 auto *ResType =
651 createIntrinsic(IntId, Inst, NewOP1, NewOP2, ResType, NumElts, true);
652 if (InstEltSize > NewResEltSize)
653 NewIn = (IsResZExt) ? IRB.CreateZExt(NewIn, InstTy)
655
657
658 return true;
659}
660
661
662
663bool HexagonGenWideningVecInstr::processInstruction(Instruction *Inst) {
667 return false;
670 return false;
672 return false;
673
674 using namespace PatternMatch;
675
676 OPKind OPK;
679 OPK = OP_Sub;
681 OPK = OP_Add;
683 OPK = OP_Mul;
685 OPK = OP_Shl;
686 else
687 return false;
688
689 OPInfo OP1Info, OP2Info;
690
692 return false;
693
694
695 if (!OP1Info.ExtInOP || !OP2Info.ExtInOP)
696 return false;
697
698 return replaceWithIntrinsic(Inst, OPK, OP1Info, OP2Info);
699}
700
701bool HexagonGenWideningVecInstr::getVmpaOperandInfo(Value *V, OPInfo &OPI) {
702 using namespace PatternMatch;
703 OPI.OP = V;
705
708 m_Poison(), m_ZeroMask()))) ||
711 m_Poison(), m_ZeroMask()))) {
712 OPI.ExtInOP = ExtV;
713 OPI.IsZExt = true;
714 OPI.IsScalar = true;
716 return true;
717 }
718
719 ConstantInt *I = nullptr;
721 m_Poison(), m_ZeroMask())))) {
723 uint32_t IValue = I->getZExtValue();
724 if (IValue <= 255) {
725 OPI.ExtInOP = ExtV;
726 OPI.IsZExt = true;
727 OPI.ExtInSize = 8;
728 OPI.IsScalar = true;
729 return true;
730 }
731 }
732 }
733
734
736}
737
738
739bool HexagonGenWideningVecInstr::processInstructionForVMPA(Instruction *Inst) {
740 using namespace PatternMatch;
742
743
745 return false;
746
749 return false;
750
751 Value *OP[4] = {nullptr, nullptr, nullptr, nullptr};
754 return false;
755
756 OPInfo OP_Info[4];
757 for (unsigned i = 0; i < 4; i++)
758 if (!getVmpaOperandInfo(OP[i], OP_Info[i]) || !OP_Info[i].ExtInOP)
759 return false;
760
761 return replaceWithVmpaIntrinsic(Inst, OP_Info);
762}
763
764
765
766void HexagonGenWideningVecInstr::reorderVmpaOperands(OPInfo *OPI) {
767 for (unsigned i = 0; i < 2; i++)
768 if (!OPI[2 * i].ExtInOP->getType()->isVectorTy()) {
769 OPInfo Temp;
770 Temp = OPI[2 * i];
771 OPI[2 * i] = OPI[2 * i + 1];
772 OPI[2 * i + 1] = Temp;
773 }
774}
775
776
777
778
779bool HexagonGenWideningVecInstr::replaceWithVmpaIntrinsic(Instruction *Inst,
780 OPInfo *OPI) {
781 reorderVmpaOperands(OPI);
782
783
784
785 if (!OPI[1].IsScalar || !OPI[3].IsScalar || OPI[0].IsScalar ||
786 OPI[2].IsScalar)
787 return false;
788
789 OPInfo SOPI1 = OPI[1];
790 OPInfo SOPI2 = OPI[3];
791
792
793 if (SOPI1.ExtInSize != SOPI2.ExtInSize || SOPI1.ExtInSize != 8)
794 return false;
795
800
801 unsigned MaxVEltSize = std::max(OPI[0].ExtInSize, OPI[2].ExtInSize);
802 unsigned NewVOpEltSize = MaxVEltSize;
803 unsigned NewResEltSize = 2 * MaxVEltSize;
804
805 if (NumElts * NewVOpEltSize < HwVLen) {
806
807 NewVOpEltSize = 2 * NewVOpEltSize;
808 NewResEltSize = 2 * NewResEltSize;
809 }
810
812
813
814 Value *NewSOP1 = SOPI1.ExtInOP;
815 Value *NewSOP2 = SOPI2.ExtInOP;
816
823
826 Intrinsic::ID CombineIntID = Intrinsic::hexagon_A2_combine_ll;
829
830
831 Value *NewVOP1 = adjustExtensionForOp(OPI[0], IRB, NewVOpEltSize, NumElts);
832 Value *NewVOP2 = adjustExtensionForOp(OPI[2], IRB, NewVOpEltSize, NumElts);
833
834
835 Intrinsic::ID VCombineIntID = Intrinsic::hexagon_V6_vcombine_128B;
841
843 ? Intrinsic::hexagon_V6_vmpabus_128B
844 : Intrinsic::hexagon_V6_vmpauhb_128B;
846 auto *ResType =
850
851 if (InstEltSize > NewResEltSize)
852
853 NewIn = IRB.CreateSExt(NewIn, InstTy);
854
855
857 unsigned HalfElts = NumElts / 2;
858 for (unsigned i = 0; i < HalfElts; ++i) {
861 }
864
866 return true;
867}
868
869bool HexagonGenWideningVecInstr::genSaturatingInst(Instruction *Inst) {
873 return false;
874
875 using namespace PatternMatch;
876 CmpPredicate P1, P2;
877 Value *L1 = nullptr, *T1 = nullptr, *L2 = nullptr, *T2 = nullptr,
878 *L3 = nullptr;
879 Constant *RC1 = nullptr, *FC1 = nullptr, *RC2 = nullptr, *FC2 = nullptr,
880 *RC3 = nullptr;
881
882
883
886
888
890 std::pair<int, int> MinMax;
891
892 if (getMinMax(RC1, RC2, MinMax)) {
893 bool IsResSigned;
894
895 if (isSaturatingVAsr(Inst, L2, MinMax.first, MinMax.second,
896 IsResSigned)) {
897
898 ConstantInt *shift_val =
900 if (shift_val) {
902 createVAsrIntrinsic(Inst, L3, shift_val, IsResSigned);
904 return true;
905 }
906 }
907 }
908 }
909 }
910 }
911
914 (T1 != L1 || FC1 != RC1))
915 return false;
916
919 (T2 != L2 || FC2 != RC2))
920 return false;
921
924 return false;
925
926 std::pair<int, int> MinMax;
928 if (!getMinMax(RC1, RC2, MinMax))
929 return false;
930 } else if (!getMinMax(RC2, RC1, MinMax))
931 return false;
932
933 Value *S = L2;
934
935
936
937 Value *OP1 = nullptr, *ShiftByVal = nullptr;
942 return false;
943
944 bool IsResSigned;
945 if (!isSaturatingVAsr(Inst, S, MinMax.first, MinMax.second, IsResSigned))
946 return false;
947
948 Value *NewIn = createVAsrIntrinsic(Inst, OP1, ShiftByVal, IsResSigned);
950 return true;
951}
952
953Value *HexagonGenWideningVecInstr::extendShiftByVal(Value *ShiftByVal,
955 using namespace PatternMatch;
958 return A;
960}
961
962bool HexagonGenWideningVecInstr::getMinMax(Constant *MinC, Constant *MaxC,
963 std::pair<int, int> &MinMax) {
966 return false;
968 return false;
969
973 return true;
974}
975
976bool HexagonGenWideningVecInstr::isSaturatingVAsr(Instruction *Inst, Value *S,
977 int MinV, int MaxV,
978 bool &IsResSigned) {
979 if (MinV >= MaxV)
980 return false;
981
982 IsResSigned = true;
986
987 int MaxRange, MinRange;
988 if (MinV < 0) {
989 MaxRange = (1 << (TruncSize - 1)) - 1;
990 MinRange = -(1 << (TruncSize - 1));
991 } else if (MinV == 0) {
992 MaxRange = (1 << (TruncSize)) - 1;
993 MinRange = 0;
994 IsResSigned = false;
995 } else
996 return false;
997
998 if (MinV != MinRange || MaxV != MaxRange)
999 return false;
1000
1002 if (SInst->getOpcode() == Instruction::AShr) {
1003 Type *SInstTy = SInst->getType();
1006 if (SInstEltSize != 2 * TruncSize || TruncSize > 16)
1007 return false;
1008 }
1009 return true;
1010}
1011
1012Intrinsic::ID HexagonGenWideningVecInstr::getVAsrIntrinsic(bool IsInSigned,
1013 bool IsResSigned) {
1014 if (!IsResSigned)
1015 return (IsInSigned) ? Intrinsic::hexagon_vasrsat_su
1016 : Intrinsic::hexagon_vasrsat_uu;
1017 return Intrinsic::hexagon_vasrsat_ss;
1018}
1019
1020Value *HexagonGenWideningVecInstr::createVAsrIntrinsic(Instruction *Inst,
1022 Value *ShiftByVal,
1023 bool IsResSigned) {
1025 Type *ShiftByTy = ShiftByVal->getType();
1027 ShiftByVal = extendShiftByVal(ShiftByVal, IRB);
1028
1033
1034
1035
1036
1038 unsigned HalfElts = NumElts / 2;
1039
1040 for (unsigned i = 0; i < HalfElts; ++i)
1042
1043 for (unsigned i = 0; i < HalfElts; ++i)
1045
1048
1049 auto *InVecOPTy =
1051 std::pair<Value *, Value *> HiLo = opSplit(VecOP, Inst, InVecOPTy);
1052 Intrinsic::ID IntID = getVAsrIntrinsic(true, IsResSigned);
1054 Value *NewIn = IRB.CreateCall(F, {HiLo.first, HiLo.second, ShiftByVal});
1056}
1057
1058
1059bool HexagonGenWideningVecInstr::genVAvg(Instruction *Inst) {
1060 using namespace PatternMatch;
1063
1064 bool Match = false;
1066 bool IsSigned;
1070 IsSigned = false;
1071 if (!Match &&
1077 IsSigned = true;
1078
1079 if (!Match)
1080 return false;
1081
1082 unsigned OP1EltSize = getElementSizeInBits(OP1);
1083 unsigned OP2EltSize = getElementSizeInBits(OP2);
1084 unsigned NewEltSize = std::max(OP1EltSize, OP2EltSize);
1085
1089
1090
1091
1092 if (InstEltSize < NewEltSize || (InstLen > 2 * HwVLen))
1093 return false;
1094
1095 if ((InstLen > HwVLen) && (InstLen % HwVLen != 0))
1096 return false;
1097
1100 auto *AvgInstTy =
1102 if (OP1EltSize < NewEltSize)
1103 OP1 = (IsSigned) ? IRB.CreateSExt(OP1, AvgInstTy)
1105 if (OP2EltSize < NewEltSize)
1106 OP2 = (IsSigned) ? IRB.CreateSExt(OP2, AvgInstTy)
1108
1110 (IsSigned) ? Intrinsic::hexagon_vavgs : Intrinsic::hexagon_vavgu;
1111 Value *NewIn = nullptr;
1112
1113
1114 if (NewEltSize * NumElts > HwVLen) {
1115 unsigned HalfElts = NumElts / 2;
1116 auto *ResType =
1118 std::pair<Value *, Value *> SplitOP1 = opSplit(OP1, Inst, ResType);
1119 std::pair<Value *, Value *> SplitOP2 = opSplit(OP2, Inst, ResType);
1120 Value *NewHi = createIntrinsic(AvgIntID, Inst, SplitOP1.first,
1121 SplitOP2.first, ResType, NumElts, false);
1122 Value *NewLo = createIntrinsic(AvgIntID, Inst, SplitOP1.second,
1123 SplitOP2.second, ResType, NumElts, false);
1125 for (unsigned i = 0; i < NumElts; ++i)
1127
1128 NewIn =
1130 } else
1131 NewIn =
1132 createIntrinsic(AvgIntID, Inst, OP1, OP2, AvgInstTy, NumElts, false);
1133
1134 if (InstEltSize > NewEltSize)
1135
1136 NewIn = (IsSigned) ? IRB.CreateSExt(NewIn, InstTy)
1139 return true;
1140}
1141
1142bool HexagonGenWideningVecInstr::visitBlock(BasicBlock *B) {
1145 Type *InstTy = I.getType();
1147 continue;
1148
1151 continue;
1152
1153 Changed |= processInstructionForVMPA(&I);
1154 Changed |= genSaturatingInst(&I);
1156 }
1157
1159 Changed |= processInstruction(&I);
1161}
1162
1163bool HexagonGenWideningVecInstr::runOnFunction(Function &F) {
1164 M = F.getParent();
1166
1167
1168
1169
1171 return false;
1172
1173 HwVLen = HST->getVectorLength() * 8;
1177
1179}
1180
1181FunctionPass *
1183 return new HexagonGenWideningVecInstr(&TM);
1184}
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
widening Hexagon generate widening vector static false bool hasNegativeValues(Constant *C)
Definition HexagonGenWideningVecInstr.cpp:140
static cl::opt< bool > WidenShortVector("hexagon-widen-short-vector", cl::desc("Generate widening instructions for short vectors."), cl::Hidden)
Machine Check Debug Module
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static std::optional< OperandInfo > getOperandInfo(const MachineOperand &MO)
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
@ ICMP_SLT
signed less than
@ ICMP_SGT
signed greater than
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
Legacy analysis pass which computes a DominatorTree.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
FunctionPass class - This class is used to implement most global optimizations.
unsigned getVectorLength() const
bool useHVX128BOps() const
bool isTypeForHVX(Type *VecTy, bool IncludeBool=false) const
const HexagonSubtarget * getSubtargetImpl(const Function &F) const override
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Value * CreateSExt(Value *V, Type *DestTy, const Twine &Name="")
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
IntegerType * getInt16Ty()
Fetch the type representing a 16-bit integer.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
ConstantInt * getIntN(unsigned N, uint64_t C)
Get a constant N-bit value, zero extended or truncated from a 64-bit value.
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="")
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)
Value * CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
void push_back(const T &Elt)
bool isVectorTy() const
True if this is an instance of VectorType.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ C
The default llvm calling convention, compatible with C.
@ SHL
Shift and rotation operations.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
class_match< PoisonValue > m_Poison()
Match an arbitrary poison constant.
BinaryOp_match< LHS, RHS, Instruction::And > m_And(const LHS &L, const RHS &R)
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)
class_match< Constant > m_Constant()
Match an arbitrary Constant and ignore it.
CastInst_match< OpTy, TruncInst > m_Trunc(const OpTy &Op)
Matches Trunc.
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
bool match(Val *V, const Pattern &P)
class_match< ConstantInt > m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
IntrinsicID_match m_Intrinsic()
Match intrinsic calls like this: m_IntrinsicIntrinsic::fabs(m_Value(X))
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
TwoOps_match< V1_t, V2_t, Instruction::ShuffleVector > m_Shuffle(const V1_t &v1, const V2_t &v2)
Matches ShuffleVectorInst independently of mask value.
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::LShr > m_LShr(const LHS &L, const RHS &R)
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
ThreeOps_match< Val_t, Elt_t, Idx_t, Instruction::InsertElement > m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx)
Matches InsertElementInst.
BinaryOp_match< LHS, RHS, Instruction::Sub > m_Sub(const LHS &L, const RHS &R)
support::detail::packed_endian_specific_integral< T, E, support::unaligned > packed
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
constexpr bool isUIntN(unsigned N, uint64_t x)
Checks if an unsigned integer fits into the given (dynamic) bit width.
void initializeHexagonGenWideningVecInstrPass(PassRegistry &)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
constexpr bool isIntN(unsigned N, int64_t x)
Checks if an signed integer fits into the given (dynamic) bit width.
FunctionPass * createHexagonGenWideningVecInstr(const HexagonTargetMachine &)
Definition HexagonGenWideningVecInstr.cpp:1182