LLVM 24.0.0git
HexagonISelLoweringHVX.cpp
Go to the documentation of this file.
1//===-- HexagonISelLoweringHVX.cpp --- Lowering HVX operations ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "HexagonRegisterInfo.h"
11#include "HexagonSubtarget.h"
12#include "llvm/ADT/SetVector.h"
21#include "llvm/IR/IntrinsicsHexagon.h"
23
24#include <algorithm>
25#include <string>
26#include <utility>
27
28using namespace llvm;
29
30static cl::opt<unsigned> HvxWidenThreshold("hexagon-hvx-widen",
32 cl::desc("Lower threshold (in bytes) for widening to HVX vectors"));
33
34static cl::opt<bool>
35 EnableFpFastConvert("hexagon-fp-fast-convert", cl::Hidden, cl::init(false),
36 cl::desc("Enable FP fast conversion routine."));
37
38static const MVT LegalV64[] = { MVT::v64i8, MVT::v32i16, MVT::v16i32 };
39static const MVT LegalW64[] = { MVT::v128i8, MVT::v64i16, MVT::v32i32 };
40static const MVT LegalV128[] = { MVT::v128i8, MVT::v64i16, MVT::v32i32 };
41static const MVT LegalW128[] = { MVT::v256i8, MVT::v128i16, MVT::v64i32 };
42
43static const unsigned MaxExpandMLA = 8;
44
45static std::tuple<unsigned, unsigned, unsigned> getIEEEProperties(MVT Ty) {
46 // For a float scalar type, return (exp-bits, exp-bias, fraction-bits)
47 MVT ElemTy = Ty.getScalarType();
48 switch (ElemTy.SimpleTy) {
49 case MVT::f16:
50 return std::make_tuple(5, 15, 10);
51 case MVT::f32:
52 return std::make_tuple(8, 127, 23);
53 case MVT::f64:
54 return std::make_tuple(11, 1023, 52);
55 default:
56 break;
57 }
58 llvm_unreachable(("Unexpected type: " + EVT(ElemTy).getEVTString()).c_str());
59}
60
61void
62HexagonTargetLowering::initializeHVXLowering() {
63 if (Subtarget.useHVX64BOps()) {
64 addRegisterClass(MVT::v64i8, &Hexagon::HvxVRRegClass);
65 addRegisterClass(MVT::v32i16, &Hexagon::HvxVRRegClass);
66 addRegisterClass(MVT::v16i32, &Hexagon::HvxVRRegClass);
67 addRegisterClass(MVT::v128i8, &Hexagon::HvxWRRegClass);
68 addRegisterClass(MVT::v64i16, &Hexagon::HvxWRRegClass);
69 addRegisterClass(MVT::v32i32, &Hexagon::HvxWRRegClass);
70 // These "short" boolean vector types should be legal because
71 // they will appear as results of vector compares. If they were
72 // not legal, type legalization would try to make them legal
73 // and that would require using operations that do not use or
74 // produce such types. That, in turn, would imply using custom
75 // nodes, which would be unoptimizable by the DAG combiner.
76 // The idea is to rely on target-independent operations as much
77 // as possible.
78 addRegisterClass(MVT::v16i1, &Hexagon::HvxQRRegClass);
79 addRegisterClass(MVT::v32i1, &Hexagon::HvxQRRegClass);
80 addRegisterClass(MVT::v64i1, &Hexagon::HvxQRRegClass);
81 } else if (Subtarget.useHVX128BOps()) {
82 addRegisterClass(MVT::v128i8, &Hexagon::HvxVRRegClass);
83 addRegisterClass(MVT::v64i16, &Hexagon::HvxVRRegClass);
84 addRegisterClass(MVT::v32i32, &Hexagon::HvxVRRegClass);
85 addRegisterClass(MVT::v256i8, &Hexagon::HvxWRRegClass);
86 addRegisterClass(MVT::v128i16, &Hexagon::HvxWRRegClass);
87 addRegisterClass(MVT::v64i32, &Hexagon::HvxWRRegClass);
88 addRegisterClass(MVT::v32i1, &Hexagon::HvxQRRegClass);
89 addRegisterClass(MVT::v64i1, &Hexagon::HvxQRRegClass);
90 addRegisterClass(MVT::v128i1, &Hexagon::HvxQRRegClass);
91 if (Subtarget.useHVXV68Ops() && Subtarget.useHVXFloatingPoint()) {
92 addRegisterClass(MVT::v32f32, &Hexagon::HvxVRRegClass);
93 addRegisterClass(MVT::v64f16, &Hexagon::HvxVRRegClass);
94 addRegisterClass(MVT::v64f32, &Hexagon::HvxWRRegClass);
95 addRegisterClass(MVT::v128f16, &Hexagon::HvxWRRegClass);
96 }
97 if (Subtarget.useHVXV81Ops()) {
98 addRegisterClass(MVT::v64bf16, &Hexagon::HvxVRRegClass);
99 addRegisterClass(MVT::v128bf16, &Hexagon::HvxWRRegClass);
100 }
101 }
102
103 // Set up operation actions.
104
105 bool Use64b = Subtarget.useHVX64BOps();
106 ArrayRef<MVT> LegalV = Use64b ? LegalV64 : LegalV128;
107 ArrayRef<MVT> LegalW = Use64b ? LegalW64 : LegalW128;
108 MVT ByteV = Use64b ? MVT::v64i8 : MVT::v128i8;
109 MVT WordV = Use64b ? MVT::v16i32 : MVT::v32i32;
110 MVT ByteW = Use64b ? MVT::v128i8 : MVT::v256i8;
111
112 auto setPromoteTo = [this] (unsigned Opc, MVT FromTy, MVT ToTy) {
114 AddPromotedToType(Opc, FromTy, ToTy);
115 };
116
117 // Handle bitcasts of vector predicates to scalars (e.g. v32i1 to i32).
118 // Note: v16i1 -> i16 is handled in type legalization instead of op
119 // legalization.
129
130 if (Subtarget.useHVX128BOps()) {
134 setOperationAction(ISD::LOAD, MVT::v32i1, Custom);
136 setOperationAction(ISD::LOAD, MVT::v64i1, Custom);
137 setOperationAction(ISD::STORE, MVT::v128i1, Custom);
138 setOperationAction(ISD::LOAD, MVT::v128i1, Custom);
139 }
140 if (Subtarget.useHVX128BOps() && Subtarget.useHVXV68Ops() &&
141 Subtarget.useHVXFloatingPoint()) {
142
143 static const MVT FloatV[] = { MVT::v64f16, MVT::v32f32 };
144 static const MVT FloatW[] = { MVT::v128f16, MVT::v64f32 };
145
146 for (MVT T : FloatV) {
154
157
160
163 // Custom-lower BUILD_VECTOR. The standard (target-independent)
164 // handling of it would convert it to a load, which is not always
165 // the optimal choice.
167 }
168
169
170 // BUILD_VECTOR with f16 operands cannot be promoted without
171 // promoting the result, so lower the node to vsplat or constant pool
175
176 // Vector shuffle is always promoted to ByteV and a bitcast to f16 is
177 // generated.
178 setPromoteTo(ISD::VECTOR_SHUFFLE, MVT::v128f16, ByteW);
179 setPromoteTo(ISD::VECTOR_SHUFFLE, MVT::v64f16, ByteV);
180 setPromoteTo(ISD::VECTOR_SHUFFLE, MVT::v64f32, ByteW);
181 setPromoteTo(ISD::VECTOR_SHUFFLE, MVT::v32f32, ByteV);
182
183 if (Subtarget.useHVXV81Ops()) {
184 setPromoteTo(ISD::VECTOR_SHUFFLE, MVT::v128bf16, ByteW);
185 setPromoteTo(ISD::VECTOR_SHUFFLE, MVT::v64bf16, ByteV);
186 setPromoteTo(ISD::SETCC, MVT::v64bf16, MVT::v64f32);
187 setPromoteTo(ISD::FADD, MVT::v64bf16, MVT::v64f32);
188 setPromoteTo(ISD::FSUB, MVT::v64bf16, MVT::v64f32);
189 setPromoteTo(ISD::FMUL, MVT::v64bf16, MVT::v64f32);
190 setPromoteTo(ISD::FMINNUM, MVT::v64bf16, MVT::v64f32);
191 setPromoteTo(ISD::FMAXNUM, MVT::v64bf16, MVT::v64f32);
192
196
197 setOperationAction(ISD::LOAD, MVT::v128bf16, Custom);
198 setOperationAction(ISD::STORE, MVT::v128bf16, Custom);
199
200 setOperationAction(ISD::MLOAD, MVT::v64bf16, Custom);
201 setOperationAction(ISD::MSTORE, MVT::v64bf16, Custom);
204
205 setOperationAction(ISD::MLOAD, MVT::v128bf16, Custom);
206 setOperationAction(ISD::MSTORE, MVT::v128bf16, Custom);
209
213 }
214
215 for (MVT P : FloatW) {
227
228 // Custom-lower BUILD_VECTOR. The standard (target-independent)
229 // handling of it would convert it to a load, which is not always
230 // the optimal choice.
232 // Make concat-vectors custom to handle concats of more than 2 vectors.
234
237 }
238
239 if (Subtarget.useHVXQFloatOps()) {
242 } else if (Subtarget.useHVXIEEEFPOps()) {
245 }
246 }
247
248 for (MVT T : LegalV) {
251
267 if (T != ByteV) {
271 }
272
275 if (T.getScalarType() != MVT::i32) {
278 }
279
284 if (T.getScalarType() != MVT::i32) {
287 }
288
290 // Make concat-vectors custom to handle concats of more than 2 vectors.
301 if (T != ByteV) {
303 // HVX only has shifts of words and halfwords.
307
308 // Promote all shuffles to operate on vectors of bytes.
309 setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteV);
310 }
311
312 if (Subtarget.useHVXFloatingPoint()) {
313 // Same action for both QFloat and IEEE.
318 }
319
327 }
328
329 for (MVT T : LegalW) {
330 // Custom-lower BUILD_VECTOR for vector pairs. The standard (target-
331 // independent) handling of it would convert it to a load, which is
332 // not always the optimal choice.
334 // Make concat-vectors custom to handle concats of more than 2 vectors.
336
337 // Custom-lower these operations for pairs. Expand them into a concat
338 // of the corresponding operations on individual vectors.
347
356
371 if (T != ByteW) {
375
376 // Promote all shuffles to operate on vectors of bytes.
377 setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteW);
378 }
381
384 if (T.getScalarType() != MVT::i32) {
387 }
388
389 if (Subtarget.useHVXFloatingPoint()) {
390 // Same action for both QFloat and IEEE.
395 }
396 }
397
398 // Legalize all of these to HexagonISD::[SU]MUL_LOHI.
399 setOperationAction(ISD::MULHS, WordV, Custom); // -> _LOHI
400 setOperationAction(ISD::MULHU, WordV, Custom); // -> _LOHI
403
404 setCondCodeAction(ISD::SETNE, MVT::v64f16, Expand);
405 setCondCodeAction(ISD::SETLE, MVT::v64f16, Expand);
406 setCondCodeAction(ISD::SETGE, MVT::v64f16, Expand);
407 setCondCodeAction(ISD::SETLT, MVT::v64f16, Expand);
408 setCondCodeAction(ISD::SETONE, MVT::v64f16, Expand);
409 setCondCodeAction(ISD::SETOLE, MVT::v64f16, Expand);
410 setCondCodeAction(ISD::SETOGE, MVT::v64f16, Expand);
411 setCondCodeAction(ISD::SETOLT, MVT::v64f16, Expand);
412 setCondCodeAction(ISD::SETUNE, MVT::v64f16, Expand);
413 setCondCodeAction(ISD::SETULE, MVT::v64f16, Expand);
414 setCondCodeAction(ISD::SETUGE, MVT::v64f16, Expand);
415 setCondCodeAction(ISD::SETULT, MVT::v64f16, Expand);
416 setCondCodeAction(ISD::SETUO, MVT::v64f16, Expand);
417 setCondCodeAction(ISD::SETO, MVT::v64f16, Expand);
418
419 setCondCodeAction(ISD::SETNE, MVT::v32f32, Expand);
420 setCondCodeAction(ISD::SETLE, MVT::v32f32, Expand);
421 setCondCodeAction(ISD::SETGE, MVT::v32f32, Expand);
422 setCondCodeAction(ISD::SETLT, MVT::v32f32, Expand);
423 setCondCodeAction(ISD::SETONE, MVT::v32f32, Expand);
424 setCondCodeAction(ISD::SETOLE, MVT::v32f32, Expand);
425 setCondCodeAction(ISD::SETOGE, MVT::v32f32, Expand);
426 setCondCodeAction(ISD::SETOLT, MVT::v32f32, Expand);
427 setCondCodeAction(ISD::SETUNE, MVT::v32f32, Expand);
428 setCondCodeAction(ISD::SETULE, MVT::v32f32, Expand);
429 setCondCodeAction(ISD::SETUGE, MVT::v32f32, Expand);
430 setCondCodeAction(ISD::SETULT, MVT::v32f32, Expand);
431 setCondCodeAction(ISD::SETUO, MVT::v32f32, Expand);
432 setCondCodeAction(ISD::SETO, MVT::v32f32, Expand);
433
434 // Boolean vectors.
435
436 for (MVT T : LegalW) {
437 // Boolean types for vector pairs will overlap with the boolean
438 // types for single vectors, e.g.
439 // v64i8 -> v64i1 (single)
440 // v64i16 -> v64i1 (pair)
441 // Set these actions first, and allow the single actions to overwrite
442 // any duplicates.
443 MVT BoolW = MVT::getVectorVT(MVT::i1, T.getVectorNumElements());
448 // Masked load/store takes a mask that may need splitting.
451 }
452
453 for (MVT T : LegalV) {
454 MVT BoolV = MVT::getVectorVT(MVT::i1, T.getVectorNumElements());
465 }
466
467 if (Use64b) {
468 for (MVT T: {MVT::v32i8, MVT::v32i16, MVT::v16i8, MVT::v16i16, MVT::v16i32})
470 } else {
471 for (MVT T: {MVT::v64i8, MVT::v64i16, MVT::v32i8, MVT::v32i16, MVT::v32i32})
473 }
474
475 // Handle store widening for short vectors.
476 unsigned HwLen = Subtarget.getVectorLength();
477 for (MVT ElemTy : Subtarget.getHVXElementTypes()) {
478 if (ElemTy == MVT::i1)
479 continue;
480 int ElemWidth = ElemTy.getFixedSizeInBits();
481 int MaxElems = (8*HwLen) / ElemWidth;
482 for (int N = 2; N < MaxElems; N *= 2) {
483 MVT VecTy = MVT::getVectorVT(ElemTy, N);
484 auto Action = getPreferredVectorAction(VecTy);
493 if (Subtarget.useHVXFloatingPoint()) {
498 }
499
500 MVT BoolTy = MVT::getVectorVT(MVT::i1, N);
501 if (!isTypeLegal(BoolTy))
503 }
504 }
505 }
506
507 // Include cases which are not hander earlier
511
513
516
517 // Partial MLA reductions.
518 {
519 static const unsigned MLAOps[] = {ISD::PARTIAL_REDUCE_SMLA,
522
523 auto HvxType = [=](MVT ScalarT, unsigned Factor = 1) {
524 return MVT::getVectorVT(ScalarT, Subtarget.getVectorLength() * Factor *
525 8 / ScalarT.getSizeInBits());
526 };
527
528 // Tuple of (Acc element type, input element type, vector pair).
529 // The assumption is both the input and reduction result are of the same
530 // size so the reduction ratio is the same as the ratio of element type
531 // sizes. This may not hold for all available instructions.
532 typedef std::tuple<MVT, MVT, bool> ReductionSignature;
533
534 static const std::vector<ReductionSignature> NativeReductions = {
535 {MVT::i32, MVT::i8, false},
536 };
537
538 for (const auto &R : NativeReductions) {
539
540 MVT AccType = std::get<0>(R);
541 MVT InputType = std::get<1>(R);
542 unsigned Factor = std::get<2>(R) ? 2 : 1;
543
544 // The native size is legal.
545 setPartialReduceMLAAction(MLAOps, HvxType(AccType), HvxType(InputType),
546 Legal);
547
548 // Allow custom partial MLA reductions on larger vectors than legally
549 // supported. These reduction must be declared as Custom (or Legal)
550 // for foldPartialReduceMLAMulOp() to fold the multiply by one pattern
551 // inserted when the partial reduction intrinsic is converted to
552 // PARTIAL_REDUCE_U/S/SUMLA. Otherwise, the Split action will apply
553 // on the original pattern, including the extensions and multiplies,
554 // which will make it impossible to match.
555 // There are two independent ways to extend the
556 // input size: 1. to concatenate the result - output vector is
557 // proportionally extended, 2) to reduce the result - the output vector
558 // size stays the same. We limit allowed combinations so that the total
559 // number of generated reduction instructions is limited by a constant
560 // number. This limit is arbitrary and can be revised. On one hand, it is
561 // convenient to have more choices; on the other hand, there is a
562 // diminishing benefit of very long sequences, which should probably be
563 // written as loops instead.
564 for (unsigned ConcatFactor = 1; ConcatFactor <= MaxExpandMLA;
565 ConcatFactor <<= 1)
566 for (unsigned ReductionFactor = 1; ReductionFactor <= MaxExpandMLA;
567 ReductionFactor <<= 1)
568 if (ConcatFactor * ReductionFactor != 1 &&
569 ConcatFactor * ReductionFactor <= MaxExpandMLA)
571 MLAOps, HvxType(AccType, Factor * ConcatFactor),
572 HvxType(InputType, Factor * ConcatFactor * ReductionFactor),
573 Custom);
574 }
575 }
576}
577
578unsigned
579HexagonTargetLowering::getPreferredHvxVectorAction(MVT VecTy) const {
580 // Early exit for invalid input types
581 if (!VecTy.isVector())
582 return ~0u;
583
584 MVT ElemTy = VecTy.getVectorElementType();
585 unsigned VecLen = VecTy.getVectorNumElements();
586 unsigned HwLen = Subtarget.getVectorLength();
587
588 // Split vectors of i1 that exceed byte vector length.
589 if (ElemTy == MVT::i1 && VecLen > HwLen)
591
592 ArrayRef<MVT> Tys = Subtarget.getHVXElementTypes();
593 // For shorter vectors of i1, widen them if any of the corresponding
594 // vectors of integers needs to be widened.
595 if (ElemTy == MVT::i1) {
596 for (MVT T : Tys) {
597 assert(T != MVT::i1);
598 auto A = getPreferredHvxVectorAction(MVT::getVectorVT(T, VecLen));
599 if (A != ~0u)
600 return A;
601 }
602 return ~0u;
603 }
604
605 // If the size of VecTy is at least half of the vector length,
606 // widen the vector. Note: the threshold was not selected in
607 // any scientific way.
608 if (llvm::is_contained(Tys, ElemTy)) {
609 unsigned VecWidth = VecTy.getSizeInBits();
610 unsigned HwWidth = 8*HwLen;
611 if (VecWidth > 2*HwWidth)
613
614 bool HaveThreshold = HvxWidenThreshold.getNumOccurrences() > 0;
615 if (HaveThreshold && 8*HvxWidenThreshold <= VecWidth)
617 if (VecWidth >= HwWidth/2 && VecWidth < HwWidth)
619 }
620
621 // Defer to default.
622 return ~0u;
623}
624
625unsigned
626HexagonTargetLowering::getCustomHvxOperationAction(SDNode &Op) const {
627 unsigned Opc = Op.getOpcode();
628 switch (Opc) {
629 case HexagonISD::SMUL_LOHI:
630 case HexagonISD::UMUL_LOHI:
631 case HexagonISD::USMUL_LOHI:
633 }
635}
636
638HexagonTargetLowering::getInt(unsigned IntId, MVT ResTy, ArrayRef<SDValue> Ops,
639 const SDLoc &dl, SelectionDAG &DAG) const {
641 IntOps.push_back(DAG.getConstant(IntId, dl, MVT::i32));
642 append_range(IntOps, Ops);
643 return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, ResTy, IntOps);
644}
645
646MVT
647HexagonTargetLowering::typeJoin(const TypePair &Tys) const {
648 assert(Tys.first.getVectorElementType() == Tys.second.getVectorElementType());
649
650 MVT ElemTy = Tys.first.getVectorElementType();
651 return MVT::getVectorVT(ElemTy, Tys.first.getVectorNumElements() +
652 Tys.second.getVectorNumElements());
653}
654
655HexagonTargetLowering::TypePair
656HexagonTargetLowering::typeSplit(MVT VecTy) const {
657 assert(VecTy.isVector());
658 unsigned NumElem = VecTy.getVectorNumElements();
659 assert((NumElem % 2) == 0 && "Expecting even-sized vector type");
660 MVT HalfTy = MVT::getVectorVT(VecTy.getVectorElementType(), NumElem/2);
661 return { HalfTy, HalfTy };
662}
663
664MVT
665HexagonTargetLowering::typeExtElem(MVT VecTy, unsigned Factor) const {
666 MVT ElemTy = VecTy.getVectorElementType();
667 MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() * Factor);
668 return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
669}
670
671MVT
672HexagonTargetLowering::typeTruncElem(MVT VecTy, unsigned Factor) const {
673 MVT ElemTy = VecTy.getVectorElementType();
674 MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() / Factor);
675 return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
676}
677
679HexagonTargetLowering::opCastElem(SDValue Vec, MVT ElemTy,
680 SelectionDAG &DAG) const {
681 if (ty(Vec).getVectorElementType() == ElemTy)
682 return Vec;
683 MVT CastTy = tyVector(Vec.getValueType().getSimpleVT(), ElemTy);
684 return DAG.getBitcast(CastTy, Vec);
685}
686
688HexagonTargetLowering::opJoin(const VectorPair &Ops, const SDLoc &dl,
689 SelectionDAG &DAG) const {
690 return DAG.getNode(ISD::CONCAT_VECTORS, dl, typeJoin(ty(Ops)),
691 Ops.first, Ops.second);
692}
693
694HexagonTargetLowering::VectorPair
695HexagonTargetLowering::opSplit(SDValue Vec, const SDLoc &dl,
696 SelectionDAG &DAG) const {
697 TypePair Tys = typeSplit(ty(Vec));
698 if (Vec.getOpcode() == HexagonISD::QCAT)
699 return VectorPair(Vec.getOperand(0), Vec.getOperand(1));
700 return DAG.SplitVector(Vec, dl, Tys.first, Tys.second);
701}
702
703bool
704HexagonTargetLowering::isHvxSingleTy(MVT Ty) const {
705 return Subtarget.isHVXVectorType(Ty) &&
706 Ty.getSizeInBits() == 8 * Subtarget.getVectorLength();
707}
708
709bool
710HexagonTargetLowering::isHvxPairTy(MVT Ty) const {
711 return Subtarget.isHVXVectorType(Ty) &&
712 Ty.getSizeInBits() == 16 * Subtarget.getVectorLength();
713}
714
715bool
716HexagonTargetLowering::isHvxBoolTy(MVT Ty) const {
717 return Subtarget.isHVXVectorType(Ty, true) &&
718 Ty.getVectorElementType() == MVT::i1;
719}
720
721bool HexagonTargetLowering::allowsHvxMemoryAccess(
722 MVT VecTy, MachineMemOperand::Flags Flags, unsigned *Fast) const {
723 // Bool vectors are excluded by default, but make it explicit to
724 // emphasize that bool vectors cannot be loaded or stored.
725 // Also, disallow double vector stores (to prevent unnecessary
726 // store widening in DAG combiner).
727 if (VecTy.getSizeInBits() > 8*Subtarget.getVectorLength())
728 return false;
729 if (!Subtarget.isHVXVectorType(VecTy, /*IncludeBool=*/false))
730 return false;
731 if (Fast)
732 *Fast = 1;
733 return true;
734}
735
736bool HexagonTargetLowering::allowsHvxMisalignedMemoryAccesses(
737 MVT VecTy, MachineMemOperand::Flags Flags, unsigned *Fast) const {
738 if (!Subtarget.isHVXVectorType(VecTy))
739 return false;
740 // XXX Should this be false? vmemu are a bit slower than vmem.
741 if (Fast)
742 *Fast = 1;
743 return true;
744}
745
746void HexagonTargetLowering::AdjustHvxInstrPostInstrSelection(
747 MachineInstr &MI, SDNode *Node) const {
748 unsigned Opc = MI.getOpcode();
749 const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
750 MachineBasicBlock &MB = *MI.getParent();
751 MachineFunction &MF = *MB.getParent();
752 MachineRegisterInfo &MRI = MF.getRegInfo();
753 DebugLoc DL = MI.getDebugLoc();
754 auto At = MI.getIterator();
755
756 switch (Opc) {
757 case Hexagon::PS_vsplatib:
758 if (Subtarget.useHVXV62Ops()) {
759 // SplatV = A2_tfrsi #imm
760 // OutV = V6_lvsplatb SplatV
761 Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
762 BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
763 .add(MI.getOperand(1));
764 Register OutV = MI.getOperand(0).getReg();
765 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatb), OutV)
766 .addReg(SplatV);
767 } else {
768 // SplatV = A2_tfrsi #imm:#imm:#imm:#imm
769 // OutV = V6_lvsplatw SplatV
770 Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
771 const MachineOperand &InpOp = MI.getOperand(1);
772 assert(InpOp.isImm());
773 uint32_t V = InpOp.getImm() & 0xFF;
774 BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
775 .addImm(V << 24 | V << 16 | V << 8 | V);
776 Register OutV = MI.getOperand(0).getReg();
777 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV).addReg(SplatV);
778 }
779 MB.erase(At);
780 break;
781 case Hexagon::PS_vsplatrb:
782 if (Subtarget.useHVXV62Ops()) {
783 // OutV = V6_lvsplatb Inp
784 Register OutV = MI.getOperand(0).getReg();
785 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatb), OutV)
786 .add(MI.getOperand(1));
787 } else {
788 Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
789 const MachineOperand &InpOp = MI.getOperand(1);
790 BuildMI(MB, At, DL, TII.get(Hexagon::S2_vsplatrb), SplatV)
791 .addReg(InpOp.getReg(), {}, InpOp.getSubReg());
792 Register OutV = MI.getOperand(0).getReg();
793 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV)
794 .addReg(SplatV);
795 }
796 MB.erase(At);
797 break;
798 case Hexagon::PS_vsplatih:
799 if (Subtarget.useHVXV62Ops()) {
800 // SplatV = A2_tfrsi #imm
801 // OutV = V6_lvsplath SplatV
802 Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
803 BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
804 .add(MI.getOperand(1));
805 Register OutV = MI.getOperand(0).getReg();
806 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplath), OutV)
807 .addReg(SplatV);
808 } else {
809 // SplatV = A2_tfrsi #imm:#imm
810 // OutV = V6_lvsplatw SplatV
811 Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
812 const MachineOperand &InpOp = MI.getOperand(1);
813 assert(InpOp.isImm());
814 uint32_t V = InpOp.getImm() & 0xFFFF;
815 BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
816 .addImm(V << 16 | V);
817 Register OutV = MI.getOperand(0).getReg();
818 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV).addReg(SplatV);
819 }
820 MB.erase(At);
821 break;
822 case Hexagon::PS_vsplatrh:
823 if (Subtarget.useHVXV62Ops()) {
824 // OutV = V6_lvsplath Inp
825 Register OutV = MI.getOperand(0).getReg();
826 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplath), OutV)
827 .add(MI.getOperand(1));
828 } else {
829 // SplatV = A2_combine_ll Inp, Inp
830 // OutV = V6_lvsplatw SplatV
831 Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
832 const MachineOperand &InpOp = MI.getOperand(1);
833 BuildMI(MB, At, DL, TII.get(Hexagon::A2_combine_ll), SplatV)
834 .addReg(InpOp.getReg(), {}, InpOp.getSubReg())
835 .addReg(InpOp.getReg(), {}, InpOp.getSubReg());
836 Register OutV = MI.getOperand(0).getReg();
837 BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV).addReg(SplatV);
838 }
839 MB.erase(At);
840 break;
841 case Hexagon::PS_vsplatiw:
842 case Hexagon::PS_vsplatrw:
843 if (Opc == Hexagon::PS_vsplatiw) {
844 // SplatV = A2_tfrsi #imm
845 Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
846 BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
847 .add(MI.getOperand(1));
848 MI.getOperand(1).ChangeToRegister(SplatV, false);
849 }
850 // OutV = V6_lvsplatw SplatV/Inp
851 MI.setDesc(TII.get(Hexagon::V6_lvsplatw));
852 break;
853 }
854}
855
857HexagonTargetLowering::convertToByteIndex(SDValue ElemIdx, MVT ElemTy,
858 SelectionDAG &DAG) const {
859 if (ElemIdx.getValueType().getSimpleVT() != MVT::i32)
860 ElemIdx = DAG.getBitcast(MVT::i32, ElemIdx);
861
862 unsigned ElemWidth = ElemTy.getSizeInBits();
863 if (ElemWidth == 8)
864 return ElemIdx;
865
866 unsigned L = Log2_32(ElemWidth/8);
867 const SDLoc &dl(ElemIdx);
868 return DAG.getNode(ISD::SHL, dl, MVT::i32,
869 {ElemIdx, DAG.getConstant(L, dl, MVT::i32)});
870}
871
873HexagonTargetLowering::getIndexInWord32(SDValue Idx, MVT ElemTy,
874 SelectionDAG &DAG) const {
875 unsigned ElemWidth = ElemTy.getSizeInBits();
876 assert(ElemWidth >= 8 && ElemWidth <= 32);
877 if (ElemWidth == 32)
878 return Idx;
879
880 if (ty(Idx) != MVT::i32)
881 Idx = DAG.getBitcast(MVT::i32, Idx);
882 const SDLoc &dl(Idx);
883 SDValue Mask = DAG.getConstant(32/ElemWidth - 1, dl, MVT::i32);
884 SDValue SubIdx = DAG.getNode(ISD::AND, dl, MVT::i32, {Idx, Mask});
885 return SubIdx;
886}
887
889HexagonTargetLowering::getByteShuffle(const SDLoc &dl, SDValue Op0,
890 SDValue Op1, ArrayRef<int> Mask,
891 SelectionDAG &DAG) const {
892 MVT OpTy = ty(Op0);
893 assert(OpTy == ty(Op1));
894
895 MVT ElemTy = OpTy.getVectorElementType();
896 if (ElemTy == MVT::i8)
897 return DAG.getVectorShuffle(OpTy, dl, Op0, Op1, Mask);
898 assert(ElemTy.getSizeInBits() >= 8);
899
900 MVT ResTy = tyVector(OpTy, MVT::i8);
901 unsigned ElemSize = ElemTy.getSizeInBits() / 8;
902
903 SmallVector<int,128> ByteMask;
904 for (int M : Mask) {
905 if (M < 0) {
906 for (unsigned I = 0; I != ElemSize; ++I)
907 ByteMask.push_back(-1);
908 } else {
909 int NewM = M*ElemSize;
910 for (unsigned I = 0; I != ElemSize; ++I)
911 ByteMask.push_back(NewM+I);
912 }
913 }
914 assert(ResTy.getVectorNumElements() == ByteMask.size());
915 return DAG.getVectorShuffle(ResTy, dl, opCastElem(Op0, MVT::i8, DAG),
916 opCastElem(Op1, MVT::i8, DAG), ByteMask);
917}
918
920HexagonTargetLowering::buildHvxVectorReg(ArrayRef<SDValue> Values,
921 const SDLoc &dl, MVT VecTy,
922 SelectionDAG &DAG) const {
923 unsigned VecLen = Values.size();
924 MachineFunction &MF = DAG.getMachineFunction();
925 MVT ElemTy = VecTy.getVectorElementType();
926 unsigned ElemWidth = ElemTy.getSizeInBits();
927 unsigned HwLen = Subtarget.getVectorLength();
928
929 unsigned ElemSize = ElemWidth / 8;
930 assert(ElemSize*VecLen == HwLen);
932
933 if (VecTy.getVectorElementType() != MVT::i32 &&
934 !(Subtarget.useHVXFloatingPoint() &&
935 VecTy.getVectorElementType() == MVT::f32)) {
936 assert((ElemSize == 1 || ElemSize == 2) && "Invalid element size");
937 unsigned OpsPerWord = (ElemSize == 1) ? 4 : 2;
938 MVT PartVT = MVT::getVectorVT(VecTy.getVectorElementType(), OpsPerWord);
939 for (unsigned i = 0; i != VecLen; i += OpsPerWord) {
940 SDValue W = buildVector32(Values.slice(i, OpsPerWord), dl, PartVT, DAG);
941 Words.push_back(DAG.getBitcast(MVT::i32, W));
942 }
943 } else {
944 for (SDValue V : Values)
945 Words.push_back(DAG.getBitcast(MVT::i32, V));
946 }
947 auto isSplat = [] (ArrayRef<SDValue> Values, SDValue &SplatV) {
948 unsigned NumValues = Values.size();
949 assert(NumValues > 0);
950 bool IsUndef = true;
951 for (unsigned i = 0; i != NumValues; ++i) {
952 if (Values[i].isUndef())
953 continue;
954 IsUndef = false;
955 if (!SplatV.getNode())
956 SplatV = Values[i];
957 else if (SplatV != Values[i])
958 return false;
959 }
960 if (IsUndef)
961 SplatV = Values[0];
962 return true;
963 };
964
965 unsigned NumWords = Words.size();
966 SDValue SplatV;
967 bool IsSplat = isSplat(Words, SplatV);
968 if (IsSplat && isUndef(SplatV))
969 return DAG.getUNDEF(VecTy);
970 if (IsSplat) {
971 assert(SplatV.getNode());
972 if (isNullConstant(SplatV))
973 return getZero(dl, VecTy, DAG);
974 MVT WordTy = MVT::getVectorVT(MVT::i32, HwLen/4);
975 SDValue S = DAG.getNode(ISD::SPLAT_VECTOR, dl, WordTy, SplatV);
976 return DAG.getBitcast(VecTy, S);
977 }
978
979 // Delay recognizing constant vectors until here, so that we can generate
980 // a vsplat.
981 SmallVector<ConstantInt*, 128> Consts(VecLen);
982 bool AllConst = getBuildVectorConstInts(Values, VecTy, DAG, Consts);
983 if (AllConst) {
984 ArrayRef<Constant*> Tmp((Constant**)Consts.begin(),
985 (Constant**)Consts.end());
986 Constant *CV = ConstantVector::get(Tmp);
987 Align Alignment(HwLen);
989 DAG.getConstantPool(CV, getPointerTy(DAG.getDataLayout()), Alignment),
990 DAG);
991 return DAG.getLoad(VecTy, dl, DAG.getEntryNode(), CP,
993 }
994
995 // A special case is a situation where the vector is built entirely from
996 // elements extracted from another vector. This could be done via a shuffle
997 // more efficiently, but typically, the size of the source vector will not
998 // match the size of the vector being built (which precludes the use of a
999 // shuffle directly).
1000 // This only handles a single source vector, and the vector being built
1001 // should be of a sub-vector type of the source vector type.
1002 auto IsBuildFromExtracts = [this,&Values] (SDValue &SrcVec,
1003 SmallVectorImpl<int> &SrcIdx) {
1004 SDValue Vec;
1005 for (SDValue V : Values) {
1006 if (isUndef(V)) {
1007 SrcIdx.push_back(-1);
1008 continue;
1009 }
1010 if (V.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
1011 return false;
1012 // All extracts should come from the same vector.
1013 SDValue T = V.getOperand(0);
1014 if (Vec.getNode() != nullptr && T.getNode() != Vec.getNode())
1015 return false;
1016 Vec = T;
1017 ConstantSDNode *C = dyn_cast<ConstantSDNode>(V.getOperand(1));
1018 if (C == nullptr)
1019 return false;
1020 int I = C->getSExtValue();
1021 assert(I >= 0 && "Negative element index");
1022 SrcIdx.push_back(I);
1023 }
1024 SrcVec = Vec;
1025 return true;
1026 };
1027
1028 SmallVector<int,128> ExtIdx;
1029 SDValue ExtVec;
1030 if (IsBuildFromExtracts(ExtVec, ExtIdx)) {
1031 MVT ExtTy = ty(ExtVec);
1032 unsigned ExtLen = ExtTy.getVectorNumElements();
1033 if (ExtLen == VecLen || ExtLen == 2*VecLen) {
1034 // Construct a new shuffle mask that will produce a vector with the same
1035 // number of elements as the input vector, and such that the vector we
1036 // want will be the initial subvector of it.
1037 SmallVector<int,128> Mask;
1038 BitVector Used(ExtLen);
1039
1040 for (int M : ExtIdx) {
1041 Mask.push_back(M);
1042 if (M >= 0)
1043 Used.set(M);
1044 }
1045 // Fill the rest of the mask with the unused elements of ExtVec in hopes
1046 // that it will result in a permutation of ExtVec's elements. It's still
1047 // fine if it doesn't (e.g. if undefs are present, or elements are
1048 // repeated), but permutations can always be done efficiently via vdelta
1049 // and vrdelta.
1050 for (unsigned I = 0; I != ExtLen; ++I) {
1051 if (Mask.size() == ExtLen)
1052 break;
1053 if (!Used.test(I))
1054 Mask.push_back(I);
1055 }
1056
1057 SDValue S = DAG.getVectorShuffle(ExtTy, dl, ExtVec,
1058 DAG.getUNDEF(ExtTy), Mask);
1059 return ExtLen == VecLen ? S : LoHalf(S, DAG);
1060 }
1061 }
1062
1063 // Find most common element to initialize vector with. This is to avoid
1064 // unnecessary vinsert/valign for cases where the same value is present
1065 // many times. Creates a histogram of the vector's elements to find the
1066 // most common element n.
1067 assert(4*Words.size() == Subtarget.getVectorLength());
1068 int VecHist[32];
1069 int n = 0;
1070 for (unsigned i = 0; i != NumWords; ++i) {
1071 VecHist[i] = 0;
1072 if (Words[i].isUndef())
1073 continue;
1074 for (unsigned j = i; j != NumWords; ++j)
1075 if (Words[i] == Words[j])
1076 VecHist[i]++;
1077
1078 if (VecHist[i] > VecHist[n])
1079 n = i;
1080 }
1081
1082 SDValue HalfV = getZero(dl, VecTy, DAG);
1083 if (VecHist[n] > 1) {
1084 // Always splat at word (i32) granularity so that the SPLAT_VECTOR node
1085 // is selected as PS_vsplatrw (word broadcast) rather than PS_vsplatrb
1086 // (byte broadcast of the low byte only), which would corrupt multi-byte
1087 // element types.
1088 MVT WordVecTy = MVT::getVectorVT(MVT::i32, HwLen / 4);
1089 SDValue WordSplat = DAG.getNode(ISD::SPLAT_VECTOR, dl, WordVecTy, Words[n]);
1090 SDValue SplatV = DAG.getBitcast(VecTy, WordSplat);
1091 HalfV = DAG.getNode(HexagonISD::VALIGN, dl, VecTy,
1092 {HalfV, SplatV, DAG.getConstant(HwLen/2, dl, MVT::i32)});
1093 }
1094 SDValue HalfV0 = HalfV;
1095 SDValue HalfV1 = HalfV;
1096
1097 // Construct two halves in parallel, then or them together. Rn and Rm count
1098 // number of rotations needed before the next element. One last rotation is
1099 // performed post-loop to position the last element.
1100 int Rn = 0, Rm = 0;
1101 SDValue Sn, Sm;
1102 SDValue N = HalfV0;
1103 SDValue M = HalfV1;
1104 for (unsigned i = 0; i != NumWords/2; ++i) {
1105 // Rotate by element count since last insertion.
1106 if (Words[i] != Words[n] || VecHist[n] <= 1) {
1107 Sn = DAG.getConstant(Rn, dl, MVT::i32);
1108 HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {N, Sn});
1109 N = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
1110 {HalfV0, Words[i]});
1111 Rn = 0;
1112 }
1113 if (Words[i+NumWords/2] != Words[n] || VecHist[n] <= 1) {
1114 Sm = DAG.getConstant(Rm, dl, MVT::i32);
1115 HalfV1 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {M, Sm});
1116 M = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
1117 {HalfV1, Words[i+NumWords/2]});
1118 Rm = 0;
1119 }
1120 Rn += 4;
1121 Rm += 4;
1122 }
1123 // Perform last rotation.
1124 Sn = DAG.getConstant(Rn+HwLen/2, dl, MVT::i32);
1125 Sm = DAG.getConstant(Rm, dl, MVT::i32);
1126 HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {N, Sn});
1127 HalfV1 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {M, Sm});
1128
1129 SDValue T0 = DAG.getBitcast(tyVector(VecTy, MVT::i32), HalfV0);
1130 SDValue T1 = DAG.getBitcast(tyVector(VecTy, MVT::i32), HalfV1);
1131
1132 SDValue DstV = DAG.getNode(ISD::OR, dl, ty(T0), {T0, T1});
1133
1134 SDValue OutV =
1135 DAG.getBitcast(tyVector(ty(DstV), VecTy.getVectorElementType()), DstV);
1136 return OutV;
1137}
1138
1139SDValue
1140HexagonTargetLowering::createHvxPrefixPred(SDValue PredV, const SDLoc &dl,
1141 unsigned BitBytes, bool ZeroFill, SelectionDAG &DAG) const {
1142 MVT PredTy = ty(PredV);
1143 unsigned HwLen = Subtarget.getVectorLength();
1144 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1145
1146 if (Subtarget.isHVXVectorType(PredTy, true)) {
1147 // Move the vector predicate SubV to a vector register, and scale it
1148 // down to match the representation (bytes per type element) that VecV
1149 // uses. The scaling down will pick every 2nd or 4th (every Scale-th
1150 // in general) element and put them at the front of the resulting
1151 // vector. This subvector will then be inserted into the Q2V of VecV.
1152 // To avoid having an operation that generates an illegal type (short
1153 // vector), generate a full size vector.
1154 //
1155 SDValue T = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, PredV);
1156 SmallVector<int,128> Mask(HwLen);
1157 // Scale = BitBytes(PredV) / Given BitBytes.
1158 unsigned Scale = HwLen / (PredTy.getVectorNumElements() * BitBytes);
1159 unsigned BlockLen = PredTy.getVectorNumElements() * BitBytes;
1160
1161 for (unsigned i = 0; i != HwLen; ++i) {
1162 unsigned Num = i % Scale;
1163 unsigned Off = i / Scale;
1164 Mask[BlockLen*Num + Off] = i;
1165 }
1166 SDValue S = DAG.getVectorShuffle(ByteTy, dl, T, DAG.getUNDEF(ByteTy), Mask);
1167 if (!ZeroFill)
1168 return S;
1169 // Fill the bytes beyond BlockLen with 0s.
1170 // V6_pred_scalar2 cannot fill the entire predicate, so it only works
1171 // when BlockLen < HwLen.
1172 assert(BlockLen < HwLen && "vsetq(v1) prerequisite");
1173 MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
1174 SDValue Q = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
1175 {DAG.getConstant(BlockLen, dl, MVT::i32)}, DAG);
1176 SDValue M = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, Q);
1177 return DAG.getNode(ISD::AND, dl, ByteTy, S, M);
1178 }
1179
1180 // Make sure that this is a valid scalar predicate.
1181 assert(PredTy == MVT::v2i1 || PredTy == MVT::v4i1 || PredTy == MVT::v8i1);
1182
1183 unsigned Bytes = 8 / PredTy.getVectorNumElements();
1184 SmallVector<SDValue,4> Words[2];
1185 unsigned IdxW = 0;
1186
1187 SDValue W0 = isUndef(PredV)
1188 ? DAG.getUNDEF(MVT::i64)
1189 : DAG.getNode(HexagonISD::P2D, dl, MVT::i64, PredV);
1190 Words[IdxW].push_back(HiHalf(W0, DAG));
1191 Words[IdxW].push_back(LoHalf(W0, DAG));
1192
1193 while (Bytes < BitBytes) {
1194 IdxW ^= 1;
1195 Words[IdxW].clear();
1196
1197 if (Bytes < 4) {
1198 for (const SDValue &W : Words[IdxW ^ 1]) {
1199 SDValue T = expandPredicate(W, dl, DAG);
1200 Words[IdxW].push_back(HiHalf(T, DAG));
1201 Words[IdxW].push_back(LoHalf(T, DAG));
1202 }
1203 } else {
1204 for (const SDValue &W : Words[IdxW ^ 1]) {
1205 Words[IdxW].push_back(W);
1206 Words[IdxW].push_back(W);
1207 }
1208 }
1209 Bytes *= 2;
1210 }
1211
1212 assert(Bytes == BitBytes);
1213 SDValue Vec = ZeroFill ? getZero(dl, ByteTy, DAG) : DAG.getUNDEF(ByteTy);
1214 SDValue S4 = DAG.getConstant(HwLen-4, dl, MVT::i32);
1215 for (const SDValue &W : Words[IdxW]) {
1216 Vec = DAG.getNode(HexagonISD::VROR, dl, ByteTy, Vec, S4);
1217 Vec = DAG.getNode(HexagonISD::VINSERTW0, dl, ByteTy, Vec, W);
1218 }
1219
1220 return Vec;
1221}
1222
1223SDValue
1224HexagonTargetLowering::buildHvxVectorPred(ArrayRef<SDValue> Values,
1225 const SDLoc &dl, MVT VecTy,
1226 SelectionDAG &DAG) const {
1227 // Construct a vector V of bytes, such that a comparison V >u 0 would
1228 // produce the required vector predicate.
1229 unsigned VecLen = Values.size();
1230 unsigned HwLen = Subtarget.getVectorLength();
1231 assert(VecLen <= HwLen || VecLen == 8*HwLen);
1233 bool AllT = true, AllF = true;
1234
1235 auto IsTrue = [] (SDValue V) {
1236 if (const auto *N = dyn_cast<ConstantSDNode>(V.getNode()))
1237 return !N->isZero();
1238 return false;
1239 };
1240 auto IsFalse = [] (SDValue V) {
1241 if (const auto *N = dyn_cast<ConstantSDNode>(V.getNode()))
1242 return N->isZero();
1243 return false;
1244 };
1245
1246 if (VecLen <= HwLen) {
1247 // In the hardware, each bit of a vector predicate corresponds to a byte
1248 // of a vector register. Calculate how many bytes does a bit of VecTy
1249 // correspond to.
1250 assert(HwLen % VecLen == 0);
1251 unsigned BitBytes = HwLen / VecLen;
1252 for (SDValue V : Values) {
1253 AllT &= IsTrue(V);
1254 AllF &= IsFalse(V);
1255
1256 SDValue Ext = !V.isUndef() ? DAG.getZExtOrTrunc(V, dl, MVT::i8)
1257 : DAG.getUNDEF(MVT::i8);
1258 for (unsigned B = 0; B != BitBytes; ++B)
1259 Bytes.push_back(Ext);
1260 }
1261 } else {
1262 // There are as many i1 values, as there are bits in a vector register.
1263 // Divide the values into groups of 8 and check that each group consists
1264 // of the same value (ignoring undefs).
1265 for (unsigned I = 0; I != VecLen; I += 8) {
1266 unsigned B = 0;
1267 // Find the first non-undef value in this group.
1268 for (; B != 8; ++B) {
1269 if (!Values[I+B].isUndef())
1270 break;
1271 }
1272 SDValue F = Values[I+B];
1273 AllT &= IsTrue(F);
1274 AllF &= IsFalse(F);
1275
1276 SDValue Ext = (B < 8) ? DAG.getZExtOrTrunc(F, dl, MVT::i8)
1277 : DAG.getUNDEF(MVT::i8);
1278 Bytes.push_back(Ext);
1279 // Verify that the rest of values in the group are the same as the
1280 // first.
1281 for (; B != 8; ++B)
1282 assert(Values[I+B].isUndef() || Values[I+B] == F);
1283 }
1284 }
1285
1286 if (AllT)
1287 return DAG.getNode(HexagonISD::QTRUE, dl, VecTy);
1288 if (AllF)
1289 return DAG.getNode(HexagonISD::QFALSE, dl, VecTy);
1290
1291 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1292 SDValue ByteVec = buildHvxVectorReg(Bytes, dl, ByteTy, DAG);
1293 return DAG.getNode(HexagonISD::V2Q, dl, VecTy, ByteVec);
1294}
1295
1296SDValue
1297HexagonTargetLowering::extractHvxElementReg(SDValue VecV, SDValue IdxV,
1298 const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
1299 MVT ElemTy = ty(VecV).getVectorElementType();
1300
1301 unsigned ElemWidth = ElemTy.getSizeInBits();
1302 assert(ElemWidth >= 8 && ElemWidth <= 32);
1303 (void)ElemWidth;
1304
1305 SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
1306 SDValue ExWord = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32,
1307 {VecV, ByteIdx});
1308 if (ElemTy == MVT::i32)
1309 return ExWord;
1310
1311 // Have an extracted word, need to extract the smaller element out of it.
1312 // 1. Extract the bits of (the original) IdxV that correspond to the index
1313 // of the desired element in the 32-bit word.
1314 SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
1315 // 2. Extract the element from the word.
1316 SDValue ExVec = DAG.getBitcast(tyVector(ty(ExWord), ElemTy), ExWord);
1317 return extractVector(ExVec, SubIdx, dl, ElemTy, MVT::i32, DAG);
1318}
1319
1320SDValue
1321HexagonTargetLowering::extractHvxElementPred(SDValue VecV, SDValue IdxV,
1322 const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
1323 // Implement other return types if necessary.
1324 assert(ResTy == MVT::i1);
1325
1326 unsigned HwLen = Subtarget.getVectorLength();
1327 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1328 SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
1329
1330 unsigned Scale = HwLen / ty(VecV).getVectorNumElements();
1331 SDValue ScV = DAG.getConstant(Scale, dl, MVT::i32);
1332 IdxV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, ScV);
1333
1334 SDValue ExtB = extractHvxElementReg(ByteVec, IdxV, dl, MVT::i32, DAG);
1335 SDValue Zero = DAG.getTargetConstant(0, dl, MVT::i32);
1336 return getInstr(Hexagon::C2_cmpgtui, dl, MVT::i1, {ExtB, Zero}, DAG);
1337}
1338
1339SDValue
1340HexagonTargetLowering::insertHvxElementReg(SDValue VecV, SDValue IdxV,
1341 SDValue ValV, const SDLoc &dl, SelectionDAG &DAG) const {
1342 MVT ElemTy = ty(VecV).getVectorElementType();
1343
1344 unsigned ElemWidth = ElemTy.getSizeInBits();
1345 assert(ElemWidth >= 8 && ElemWidth <= 32);
1346 (void)ElemWidth;
1347
1348 auto InsertWord = [&DAG,&dl,this] (SDValue VecV, SDValue ValV,
1349 SDValue ByteIdxV) {
1350 MVT VecTy = ty(VecV);
1351 unsigned HwLen = Subtarget.getVectorLength();
1352 SDValue MaskV =
1353 DAG.getNode(ISD::AND, dl, MVT::i32,
1354 {ByteIdxV, DAG.getSignedConstant(-4, dl, MVT::i32)});
1355 SDValue RotV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {VecV, MaskV});
1356 SDValue InsV = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy, {RotV, ValV});
1357 SDValue SubV = DAG.getNode(ISD::SUB, dl, MVT::i32,
1358 {DAG.getConstant(HwLen, dl, MVT::i32), MaskV});
1359 SDValue TorV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {InsV, SubV});
1360 return TorV;
1361 };
1362
1363 SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
1364 if (ElemTy == MVT::i32)
1365 return InsertWord(VecV, ValV, ByteIdx);
1366
1367 // If this is not inserting a 32-bit word, convert it into such a thing.
1368 // 1. Extract the existing word from the target vector.
1369 SDValue WordIdx = DAG.getNode(ISD::SRL, dl, MVT::i32,
1370 {ByteIdx, DAG.getConstant(2, dl, MVT::i32)});
1371 SDValue Ext = extractHvxElementReg(opCastElem(VecV, MVT::i32, DAG), WordIdx,
1372 dl, MVT::i32, DAG);
1373
1374 // 2. Treating the extracted word as a 32-bit vector, insert the given
1375 // value into it.
1376 SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
1377 MVT SubVecTy = tyVector(ty(Ext), ElemTy);
1378 SDValue Ins = insertVector(DAG.getBitcast(SubVecTy, Ext),
1379 ValV, SubIdx, dl, ElemTy, DAG);
1380
1381 // 3. Insert the 32-bit word back into the original vector.
1382 return InsertWord(VecV, Ins, ByteIdx);
1383}
1384
1385SDValue
1386HexagonTargetLowering::insertHvxElementPred(SDValue VecV, SDValue IdxV,
1387 SDValue ValV, const SDLoc &dl, SelectionDAG &DAG) const {
1388 unsigned HwLen = Subtarget.getVectorLength();
1389 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1390 SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
1391
1392 unsigned Scale = HwLen / ty(VecV).getVectorNumElements();
1393 SDValue ScV = DAG.getConstant(Scale, dl, MVT::i32);
1394 IdxV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, ScV);
1395 ValV = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::i32, ValV);
1396
1397 SDValue InsV = insertHvxElementReg(ByteVec, IdxV, ValV, dl, DAG);
1398 return DAG.getNode(HexagonISD::V2Q, dl, ty(VecV), InsV);
1399}
1400
1401SDValue
1402HexagonTargetLowering::extractHvxSubvectorReg(SDValue OrigOp, SDValue VecV,
1403 SDValue IdxV, const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
1404 MVT VecTy = ty(VecV);
1405 unsigned HwLen = Subtarget.getVectorLength();
1406 unsigned Idx = IdxV.getNode()->getAsZExtVal();
1407 MVT ElemTy = VecTy.getVectorElementType();
1408 unsigned ElemWidth = ElemTy.getSizeInBits();
1409
1410 // If the source vector is a vector pair, get the single vector containing
1411 // the subvector of interest. The subvector will never overlap two single
1412 // vectors.
1413 if (isHvxPairTy(VecTy)) {
1414 unsigned SubIdx = Hexagon::vsub_lo;
1415 if (Idx * ElemWidth >= 8 * HwLen) {
1416 SubIdx = Hexagon::vsub_hi;
1417 Idx -= VecTy.getVectorNumElements() / 2;
1418 }
1419
1420 VecTy = typeSplit(VecTy).first;
1421 VecV = DAG.getTargetExtractSubreg(SubIdx, dl, VecTy, VecV);
1422 if (VecTy == ResTy)
1423 return VecV;
1424 }
1425
1426 // The only meaningful subvectors of a single HVX vector are those that
1427 // fit in a scalar register.
1428 assert(ResTy.getSizeInBits() == 32 || ResTy.getSizeInBits() == 64);
1429
1430 MVT WordTy = tyVector(VecTy, MVT::i32);
1431 SDValue WordVec = DAG.getBitcast(WordTy, VecV);
1432 unsigned WordIdx = (Idx*ElemWidth) / 32;
1433
1434 SDValue W0Idx = DAG.getConstant(WordIdx, dl, MVT::i32);
1435 SDValue W0 = extractHvxElementReg(WordVec, W0Idx, dl, MVT::i32, DAG);
1436 if (ResTy.getSizeInBits() == 32)
1437 return DAG.getBitcast(ResTy, W0);
1438
1439 SDValue W1Idx = DAG.getConstant(WordIdx+1, dl, MVT::i32);
1440 SDValue W1 = extractHvxElementReg(WordVec, W1Idx, dl, MVT::i32, DAG);
1441 SDValue WW = getCombine(W1, W0, dl, MVT::i64, DAG);
1442 return DAG.getBitcast(ResTy, WW);
1443}
1444
1445SDValue
1446HexagonTargetLowering::extractHvxSubvectorPred(SDValue VecV, SDValue IdxV,
1447 const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
1448 MVT VecTy = ty(VecV);
1449 unsigned HwLen = Subtarget.getVectorLength();
1450 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1451 SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
1452 // IdxV is required to be a constant.
1453 unsigned Idx = IdxV.getNode()->getAsZExtVal();
1454
1455 unsigned ResLen = ResTy.getVectorNumElements();
1456 unsigned BitBytes = HwLen / VecTy.getVectorNumElements();
1457 unsigned Offset = Idx * BitBytes;
1458 SDValue Undef = DAG.getUNDEF(ByteTy);
1459 SmallVector<int,128> Mask;
1460
1461 if (Subtarget.isHVXVectorType(ResTy, true)) {
1462 // Converting between two vector predicates. Since the result is shorter
1463 // than the source, it will correspond to a vector predicate with the
1464 // relevant bits replicated. The replication count is the ratio of the
1465 // source and target vector lengths.
1466 unsigned Rep = VecTy.getVectorNumElements() / ResLen;
1467 assert(isPowerOf2_32(Rep) && HwLen % Rep == 0);
1468 for (unsigned i = 0; i != HwLen/Rep; ++i) {
1469 for (unsigned j = 0; j != Rep; ++j)
1470 Mask.push_back(i + Offset);
1471 }
1472 SDValue ShuffV = DAG.getVectorShuffle(ByteTy, dl, ByteVec, Undef, Mask);
1473 return DAG.getNode(HexagonISD::V2Q, dl, ResTy, ShuffV);
1474 }
1475
1476 // Converting between a vector predicate and a scalar predicate. In the
1477 // vector predicate, a group of BitBytes bits will correspond to a single
1478 // i1 element of the source vector type. Those bits will all have the same
1479 // value. The same will be true for ByteVec, where each byte corresponds
1480 // to a bit in the vector predicate.
1481 // The algorithm is to traverse the ByteVec, going over the i1 values from
1482 // the source vector, and generate the corresponding representation in an
1483 // 8-byte vector. To avoid repeated extracts from ByteVec, shuffle the
1484 // elements so that the interesting 8 bytes will be in the low end of the
1485 // vector.
1486 unsigned Rep = 8 / ResLen;
1487 // Make sure the output fill the entire vector register, so repeat the
1488 // 8-byte groups as many times as necessary.
1489 for (unsigned r = 0; r != HwLen / 8; ++r) {
1490 // This will generate the indexes of the 8 interesting bytes.
1491 for (unsigned i = 0; i != ResLen; ++i) {
1492 for (unsigned j = 0; j != Rep; ++j)
1493 Mask.push_back(Offset + i*BitBytes);
1494 }
1495 }
1496
1497 SDValue Zero = getZero(dl, MVT::i32, DAG);
1498 SDValue ShuffV = DAG.getVectorShuffle(ByteTy, dl, ByteVec, Undef, Mask);
1499 // Combine the two low words from ShuffV into a v8i8, and byte-compare
1500 // them against 0.
1501 SDValue W0 = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32, {ShuffV, Zero});
1502 SDValue W1 = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32,
1503 {ShuffV, DAG.getConstant(4, dl, MVT::i32)});
1504 SDValue Vec64 = getCombine(W1, W0, dl, MVT::v8i8, DAG);
1505 return getInstr(Hexagon::A4_vcmpbgtui, dl, ResTy,
1506 {Vec64, DAG.getTargetConstant(0, dl, MVT::i32)}, DAG);
1507}
1508
1509SDValue
1510HexagonTargetLowering::insertHvxSubvectorReg(SDValue VecV, SDValue SubV,
1511 SDValue IdxV, const SDLoc &dl, SelectionDAG &DAG) const {
1512 MVT VecTy = ty(VecV);
1513 MVT SubTy = ty(SubV);
1514 unsigned HwLen = Subtarget.getVectorLength();
1515 MVT ElemTy = VecTy.getVectorElementType();
1516 unsigned ElemWidth = ElemTy.getSizeInBits();
1517
1518 bool IsPair = isHvxPairTy(VecTy);
1519 MVT SingleTy = MVT::getVectorVT(ElemTy, (8*HwLen)/ElemWidth);
1520 // The two single vectors that VecV consists of, if it's a pair.
1521 SDValue V0, V1;
1522 SDValue SingleV = VecV;
1523 SDValue PickHi;
1524
1525 if (IsPair) {
1526 V0 = LoHalf(VecV, DAG);
1527 V1 = HiHalf(VecV, DAG);
1528
1529 SDValue HalfV = DAG.getConstant(SingleTy.getVectorNumElements(),
1530 dl, MVT::i32);
1531 PickHi = DAG.getSetCC(dl, MVT::i1, IdxV, HalfV, ISD::SETUGT);
1532 if (isHvxSingleTy(SubTy)) {
1533 if (const auto *CN = dyn_cast<const ConstantSDNode>(IdxV.getNode())) {
1534 unsigned Idx = CN->getZExtValue();
1535 assert(Idx == 0 || Idx == VecTy.getVectorNumElements()/2);
1536 unsigned SubIdx = (Idx == 0) ? Hexagon::vsub_lo : Hexagon::vsub_hi;
1537 return DAG.getTargetInsertSubreg(SubIdx, dl, VecTy, VecV, SubV);
1538 }
1539 // If IdxV is not a constant, generate the two variants: with the
1540 // SubV as the high and as the low subregister, and select the right
1541 // pair based on the IdxV.
1542 SDValue InLo = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {SubV, V1});
1543 SDValue InHi = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {V0, SubV});
1544 return DAG.getNode(ISD::SELECT, dl, VecTy, PickHi, InHi, InLo);
1545 }
1546 // The subvector being inserted must be entirely contained in one of
1547 // the vectors V0 or V1. Set SingleV to the correct one, and update
1548 // IdxV to be the index relative to the beginning of that vector.
1549 SDValue S = DAG.getNode(ISD::SUB, dl, MVT::i32, IdxV, HalfV);
1550 IdxV = DAG.getNode(ISD::SELECT, dl, MVT::i32, PickHi, S, IdxV);
1551 SingleV = DAG.getNode(ISD::SELECT, dl, SingleTy, PickHi, V1, V0);
1552 }
1553
1554 // The only meaningful subvectors of a single HVX vector are those that
1555 // fit in a scalar register.
1556 assert(SubTy.getSizeInBits() == 32 || SubTy.getSizeInBits() == 64);
1557 // Convert IdxV to be index in bytes.
1558 auto *IdxN = dyn_cast<ConstantSDNode>(IdxV.getNode());
1559 if (!IdxN || !IdxN->isZero()) {
1560 IdxV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
1561 DAG.getConstant(ElemWidth/8, dl, MVT::i32));
1562 SingleV = DAG.getNode(HexagonISD::VROR, dl, SingleTy, SingleV, IdxV);
1563 }
1564 // When inserting a single word, the rotation back to the original position
1565 // would be by HwLen-Idx, but if two words are inserted, it will need to be
1566 // by (HwLen-4)-Idx.
1567 unsigned RolBase = HwLen;
1568 if (SubTy.getSizeInBits() == 32) {
1569 SDValue V = DAG.getBitcast(MVT::i32, SubV);
1570 SingleV = DAG.getNode(HexagonISD::VINSERTW0, dl, SingleTy, SingleV, V);
1571 } else {
1572 SDValue V = DAG.getBitcast(MVT::i64, SubV);
1573 SDValue R0 = LoHalf(V, DAG);
1574 SDValue R1 = HiHalf(V, DAG);
1575 SingleV = DAG.getNode(HexagonISD::VINSERTW0, dl, SingleTy, SingleV, R0);
1576 SingleV = DAG.getNode(HexagonISD::VROR, dl, SingleTy, SingleV,
1577 DAG.getConstant(4, dl, MVT::i32));
1578 SingleV = DAG.getNode(HexagonISD::VINSERTW0, dl, SingleTy, SingleV, R1);
1579 RolBase = HwLen-4;
1580 }
1581 // If the vector wasn't ror'ed, don't ror it back.
1582 if (RolBase != 4 || !IdxN || !IdxN->isZero()) {
1583 SDValue RolV = DAG.getNode(ISD::SUB, dl, MVT::i32,
1584 DAG.getConstant(RolBase, dl, MVT::i32), IdxV);
1585 SingleV = DAG.getNode(HexagonISD::VROR, dl, SingleTy, SingleV, RolV);
1586 }
1587
1588 if (IsPair) {
1589 SDValue InLo = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {SingleV, V1});
1590 SDValue InHi = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {V0, SingleV});
1591 return DAG.getNode(ISD::SELECT, dl, VecTy, PickHi, InHi, InLo);
1592 }
1593 return SingleV;
1594}
1595
1596SDValue
1597HexagonTargetLowering::insertHvxSubvectorPred(SDValue VecV, SDValue SubV,
1598 SDValue IdxV, const SDLoc &dl, SelectionDAG &DAG) const {
1599 MVT VecTy = ty(VecV);
1600 MVT SubTy = ty(SubV);
1601 assert(Subtarget.isHVXVectorType(VecTy, true));
1602 // VecV is an HVX vector predicate. SubV may be either an HVX vector
1603 // predicate as well, or it can be a scalar predicate.
1604
1605 unsigned VecLen = VecTy.getVectorNumElements();
1606 unsigned HwLen = Subtarget.getVectorLength();
1607 assert(HwLen % VecLen == 0 && "Unexpected vector type");
1608
1609 unsigned Scale = VecLen / SubTy.getVectorNumElements();
1610 unsigned BitBytes = HwLen / VecLen;
1611 unsigned BlockLen = HwLen / Scale;
1612
1613 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1614 SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
1615 SDValue ByteSub = createHvxPrefixPred(SubV, dl, BitBytes, false, DAG);
1616 SDValue ByteIdx;
1617
1618 auto *IdxN = dyn_cast<ConstantSDNode>(IdxV.getNode());
1619 if (!IdxN || !IdxN->isZero()) {
1620 ByteIdx = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
1621 DAG.getConstant(BitBytes, dl, MVT::i32));
1622 ByteVec = DAG.getNode(HexagonISD::VROR, dl, ByteTy, ByteVec, ByteIdx);
1623 }
1624
1625 // ByteVec is the target vector VecV rotated in such a way that the
1626 // subvector should be inserted at index 0. Generate a predicate mask
1627 // and use vmux to do the insertion.
1628 assert(BlockLen < HwLen && "vsetq(v1) prerequisite");
1629 MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
1630 SDValue Q = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
1631 {DAG.getConstant(BlockLen, dl, MVT::i32)}, DAG);
1632 ByteVec = getInstr(Hexagon::V6_vmux, dl, ByteTy, {Q, ByteSub, ByteVec}, DAG);
1633 // Rotate ByteVec back, and convert to a vector predicate.
1634 if (!IdxN || !IdxN->isZero()) {
1635 SDValue HwLenV = DAG.getConstant(HwLen, dl, MVT::i32);
1636 SDValue ByteXdi = DAG.getNode(ISD::SUB, dl, MVT::i32, HwLenV, ByteIdx);
1637 ByteVec = DAG.getNode(HexagonISD::VROR, dl, ByteTy, ByteVec, ByteXdi);
1638 }
1639 return DAG.getNode(HexagonISD::V2Q, dl, VecTy, ByteVec);
1640}
1641
1642SDValue
1643HexagonTargetLowering::extendHvxVectorPred(SDValue VecV, const SDLoc &dl,
1644 MVT ResTy, bool ZeroExt, SelectionDAG &DAG) const {
1645 // Sign- and any-extending of a vector predicate to a vector register is
1646 // equivalent to Q2V. For zero-extensions, generate a vmux between 0 and
1647 // a vector of 1s (where the 1s are of type matching the vector type).
1648 assert(Subtarget.isHVXVectorType(ResTy));
1649 if (!ZeroExt)
1650 return DAG.getNode(HexagonISD::Q2V, dl, ResTy, VecV);
1651
1652 assert(ty(VecV).getVectorNumElements() == ResTy.getVectorNumElements());
1653 SDValue True = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
1654 DAG.getConstant(1, dl, MVT::i32));
1655 SDValue False = getZero(dl, ResTy, DAG);
1656 return DAG.getSelect(dl, ResTy, VecV, True, False);
1657}
1658
1659SDValue
1660HexagonTargetLowering::compressHvxPred(SDValue VecQ, const SDLoc &dl,
1661 MVT ResTy, SelectionDAG &DAG) const {
1662 // Given a predicate register VecQ, transfer bits VecQ[0..HwLen-1]
1663 // (i.e. the entire predicate register) to bits [0..HwLen-1] of a
1664 // vector register. The remaining bits of the vector register are
1665 // unspecified.
1666
1667 MachineFunction &MF = DAG.getMachineFunction();
1668 unsigned HwLen = Subtarget.getVectorLength();
1669 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1670 MVT PredTy = ty(VecQ);
1671 unsigned PredLen = PredTy.getVectorNumElements();
1672 assert(HwLen % PredLen == 0);
1673 MVT VecTy = MVT::getVectorVT(MVT::getIntegerVT(8*HwLen/PredLen), PredLen);
1674
1675 Type *Int8Ty = Type::getInt8Ty(*DAG.getContext());
1677 // Create an array of bytes (hex): 01,02,04,08,10,20,40,80, 01,02,04,08,...
1678 // These are bytes with the LSB rotated left with respect to their index.
1679 for (unsigned i = 0; i != HwLen/8; ++i) {
1680 for (unsigned j = 0; j != 8; ++j)
1681 Tmp.push_back(ConstantInt::get(Int8Ty, 1ull << j));
1682 }
1683 Constant *CV = ConstantVector::get(Tmp);
1684 Align Alignment(HwLen);
1686 DAG.getConstantPool(CV, getPointerTy(DAG.getDataLayout()), Alignment),
1687 DAG);
1688 SDValue Bytes =
1689 DAG.getLoad(ByteTy, dl, DAG.getEntryNode(), CP,
1691
1692 // Select the bytes that correspond to true bits in the vector predicate.
1693 SDValue Sel = DAG.getSelect(dl, VecTy, VecQ, DAG.getBitcast(VecTy, Bytes),
1694 getZero(dl, VecTy, DAG));
1695 // Calculate the OR of all bytes in each group of 8. That will compress
1696 // all the individual bits into a single byte.
1697 // First, OR groups of 4, via vrmpy with 0x01010101.
1698 SDValue All1 =
1699 DAG.getSplatBuildVector(MVT::v4i8, dl, DAG.getConstant(1, dl, MVT::i32));
1700 SDValue Vrmpy = getInstr(Hexagon::V6_vrmpyub, dl, ByteTy, {Sel, All1}, DAG);
1701 // Then rotate the accumulated vector by 4 bytes, and do the final OR.
1702 SDValue Rot = getInstr(Hexagon::V6_valignbi, dl, ByteTy,
1703 {Vrmpy, Vrmpy, DAG.getTargetConstant(4, dl, MVT::i32)}, DAG);
1704 SDValue Vor = DAG.getNode(ISD::OR, dl, ByteTy, {Vrmpy, Rot});
1705
1706 // Pick every 8th byte and coalesce them at the beginning of the output.
1707 // For symmetry, coalesce every 1+8th byte after that, then every 2+8th
1708 // byte and so on.
1709 SmallVector<int,128> Mask;
1710 for (unsigned i = 0; i != HwLen; ++i)
1711 Mask.push_back((8*i) % HwLen + i/(HwLen/8));
1712 SDValue Collect =
1713 DAG.getVectorShuffle(ByteTy, dl, Vor, DAG.getUNDEF(ByteTy), Mask);
1714 return DAG.getBitcast(ResTy, Collect);
1715}
1716
1717SDValue
1718HexagonTargetLowering::resizeToWidth(SDValue VecV, MVT ResTy, bool Signed,
1719 const SDLoc &dl, SelectionDAG &DAG) const {
1720 // Take a vector and resize the element type to match the given type.
1721 MVT InpTy = ty(VecV);
1722 if (InpTy == ResTy)
1723 return VecV;
1724
1725 unsigned InpWidth = InpTy.getSizeInBits();
1726 unsigned ResWidth = ResTy.getSizeInBits();
1727
1728 if (InpTy.isFloatingPoint()) {
1729 return InpWidth < ResWidth
1730 ? DAG.getNode(ISD::FP_EXTEND, dl, ResTy, VecV)
1731 : DAG.getNode(ISD::FP_ROUND, dl, ResTy, VecV,
1732 DAG.getTargetConstant(0, dl, MVT::i32));
1733 }
1734
1735 assert(InpTy.isInteger());
1736
1737 if (InpWidth < ResWidth) {
1738 unsigned ExtOpc = Signed ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
1739 return DAG.getNode(ExtOpc, dl, ResTy, VecV);
1740 } else {
1741 unsigned NarOpc = Signed ? HexagonISD::SSAT : HexagonISD::USAT;
1742 return DAG.getNode(NarOpc, dl, ResTy, VecV, DAG.getValueType(ResTy));
1743 }
1744}
1745
1746SDValue
1747HexagonTargetLowering::extractSubvector(SDValue Vec, MVT SubTy, unsigned SubIdx,
1748 SelectionDAG &DAG) const {
1749 assert(ty(Vec).getSizeInBits() % SubTy.getSizeInBits() == 0);
1750
1751 const SDLoc &dl(Vec);
1752 unsigned ElemIdx = SubIdx * SubTy.getVectorNumElements();
1753 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, SubTy,
1754 {Vec, DAG.getConstant(ElemIdx, dl, MVT::i32)});
1755}
1756
1757SDValue
1758HexagonTargetLowering::LowerHvxBuildVector(SDValue Op, SelectionDAG &DAG)
1759 const {
1760 const SDLoc &dl(Op);
1761 MVT VecTy = ty(Op);
1762
1763 unsigned Size = Op.getNumOperands();
1765 for (unsigned i = 0; i != Size; ++i)
1766 Ops.push_back(Op.getOperand(i));
1767
1768 if (VecTy.getVectorElementType() == MVT::i1)
1769 return buildHvxVectorPred(Ops, dl, VecTy, DAG);
1770
1771 // In case of MVT::f16 BUILD_VECTOR, since MVT::f16 is
1772 // not a legal type, just bitcast the node to use i16
1773 // types and bitcast the result back to f16
1774 if (VecTy.getVectorElementType() == MVT::f16 ||
1775 VecTy.getVectorElementType() == MVT::bf16) {
1777 for (unsigned i = 0; i != Size; i++)
1778 NewOps.push_back(DAG.getBitcast(MVT::i16, Ops[i]));
1779
1780 SDValue T0 =
1781 DAG.getNode(ISD::BUILD_VECTOR, dl, tyVector(VecTy, MVT::i16), NewOps);
1782 return DAG.getBitcast(tyVector(VecTy, VecTy.getVectorElementType()), T0);
1783 }
1784
1785 // First, split the BUILD_VECTOR for vector pairs. We could generate
1786 // some pairs directly (via splat), but splats should be generated
1787 // by the combiner prior to getting here.
1788 if (VecTy.getSizeInBits() == 16 * Subtarget.getVectorLength()) {
1790 MVT SingleTy = typeSplit(VecTy).first;
1791 SDValue V0 = buildHvxVectorReg(A.take_front(Size / 2), dl, SingleTy, DAG);
1792 SDValue V1 = buildHvxVectorReg(A.drop_front(Size / 2), dl, SingleTy, DAG);
1793 return DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, V0, V1);
1794 }
1795
1796 return buildHvxVectorReg(Ops, dl, VecTy, DAG);
1797}
1798
1799SDValue
1800HexagonTargetLowering::LowerHvxSplatVector(SDValue Op, SelectionDAG &DAG)
1801 const {
1802 const SDLoc &dl(Op);
1803 MVT VecTy = ty(Op);
1804 MVT ArgTy = ty(Op.getOperand(0));
1805
1806 if (ArgTy == MVT::f16 || ArgTy == MVT::bf16) {
1807 MVT SplatTy = MVT::getVectorVT(MVT::i16, VecTy.getVectorNumElements());
1808 SDValue ToInt16 = DAG.getBitcast(MVT::i16, Op.getOperand(0));
1809 SDValue ToInt32 = DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i32, ToInt16);
1810 SDValue Splat = DAG.getNode(ISD::SPLAT_VECTOR, dl, SplatTy, ToInt32);
1811 return DAG.getBitcast(VecTy, Splat);
1812 }
1813
1814 return SDValue();
1815}
1816
1817SDValue
1818HexagonTargetLowering::LowerHvxConcatVectors(SDValue Op, SelectionDAG &DAG)
1819 const {
1820 // Vector concatenation of two integer (non-bool) vectors does not need
1821 // special lowering. Custom-lower concats of bool vectors and expand
1822 // concats of more than 2 vectors.
1823 MVT VecTy = ty(Op);
1824 const SDLoc &dl(Op);
1825 unsigned NumOp = Op.getNumOperands();
1826 if (VecTy.getVectorElementType() != MVT::i1) {
1827 if (NumOp == 2)
1828 return Op;
1829 // Expand the other cases into a build-vector.
1831 for (SDValue V : Op.getNode()->ops())
1832 DAG.ExtractVectorElements(V, Elems);
1833 // A vector of i16 will be broken up into a build_vector of i16's.
1834 // This is a problem, since at the time of operation legalization,
1835 // all operations are expected to be type-legalized, and i16 is not
1836 // a legal type. If any of the extracted elements is not of a valid
1837 // type, sign-extend it to a valid one.
1838 for (SDValue &V : Elems) {
1839 MVT Ty = ty(V);
1840 if (!isTypeLegal(Ty)) {
1841 MVT NTy = typeLegalize(Ty, DAG);
1842 if (V.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
1843 V = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, NTy,
1844 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, NTy,
1845 V.getOperand(0), V.getOperand(1)),
1846 DAG.getValueType(Ty));
1847 continue;
1848 }
1849 // A few less complicated cases.
1850 switch (V.getOpcode()) {
1851 case ISD::Constant:
1852 V = DAG.getSExtOrTrunc(V, dl, NTy);
1853 break;
1854 case ISD::UNDEF:
1855 V = DAG.getUNDEF(NTy);
1856 break;
1857 case ISD::TRUNCATE:
1858 V = V.getOperand(0);
1859 break;
1860 default:
1861 llvm_unreachable("Unexpected vector element");
1862 }
1863 }
1864 }
1865 return DAG.getBuildVector(VecTy, dl, Elems);
1866 }
1867
1868 assert(VecTy.getVectorElementType() == MVT::i1);
1869 unsigned HwLen = Subtarget.getVectorLength();
1870 assert(isPowerOf2_32(NumOp) && HwLen % NumOp == 0);
1871
1872 SDValue Op0 = Op.getOperand(0);
1873
1874 // If the operands are HVX types (i.e. not scalar predicates), then
1875 // defer the concatenation, and create QCAT instead.
1876 if (Subtarget.isHVXVectorType(ty(Op0), true)) {
1877 if (NumOp == 2)
1878 return DAG.getNode(HexagonISD::QCAT, dl, VecTy, Op0, Op.getOperand(1));
1879
1880 ArrayRef<SDUse> U(Op.getNode()->ops());
1883
1884 MVT HalfTy = typeSplit(VecTy).first;
1885 SDValue V0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, HalfTy,
1886 Ops.take_front(NumOp/2));
1887 SDValue V1 = DAG.getNode(ISD::CONCAT_VECTORS, dl, HalfTy,
1888 Ops.take_back(NumOp/2));
1889 return DAG.getNode(HexagonISD::QCAT, dl, VecTy, V0, V1);
1890 }
1891
1892 // Count how many bytes (in a vector register) each bit in VecTy
1893 // corresponds to.
1894 unsigned BitBytes = HwLen / VecTy.getVectorNumElements();
1895
1896 // Make sure that createHvxPrefixPred will only ever need to expand
1897 // the predicate, i.e. bytes-per-bit in the input is not greater than
1898 // the target bytes-per-bit in the result.
1899 SDValue Combined = combineConcatOfScalarPreds(Op, BitBytes, DAG);
1900 SmallVector<SDValue,8> Prefixes;
1901 for (SDValue V : Combined.getNode()->op_values()) {
1902 SDValue P = createHvxPrefixPred(V, dl, BitBytes, true, DAG);
1903 Prefixes.push_back(P);
1904 }
1905
1906 unsigned InpLen = ty(Combined.getOperand(0)).getVectorNumElements();
1907 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
1908 SDValue S = DAG.getConstant(HwLen - InpLen*BitBytes, dl, MVT::i32);
1909 SDValue Res = getZero(dl, ByteTy, DAG);
1910 for (unsigned i = 0, e = Prefixes.size(); i != e; ++i) {
1911 Res = DAG.getNode(HexagonISD::VROR, dl, ByteTy, Res, S);
1912 Res = DAG.getNode(ISD::OR, dl, ByteTy, Res, Prefixes[e-i-1]);
1913 }
1914 return DAG.getNode(HexagonISD::V2Q, dl, VecTy, Res);
1915}
1916
1917SDValue
1918HexagonTargetLowering::LowerHvxExtractElement(SDValue Op, SelectionDAG &DAG)
1919 const {
1920 // Change the type of the extracted element to i32.
1921 SDValue VecV = Op.getOperand(0);
1922 MVT ElemTy = ty(VecV).getVectorElementType();
1923 const SDLoc &dl(Op);
1924 SDValue IdxV = Op.getOperand(1);
1925 if (ElemTy == MVT::i1)
1926 return extractHvxElementPred(VecV, IdxV, dl, ty(Op), DAG);
1927
1928 return extractHvxElementReg(VecV, IdxV, dl, ty(Op), DAG);
1929}
1930
1931SDValue
1932HexagonTargetLowering::LowerHvxInsertElement(SDValue Op, SelectionDAG &DAG)
1933 const {
1934 const SDLoc &dl(Op);
1935 MVT VecTy = ty(Op);
1936 SDValue VecV = Op.getOperand(0);
1937 SDValue ValV = Op.getOperand(1);
1938 SDValue IdxV = Op.getOperand(2);
1939 MVT ElemTy = ty(VecV).getVectorElementType();
1940 if (ElemTy == MVT::i1)
1941 return insertHvxElementPred(VecV, IdxV, ValV, dl, DAG);
1942
1943 if (ElemTy == MVT::f16 || ElemTy == MVT::bf16) {
1945 tyVector(VecTy, MVT::i16),
1946 DAG.getBitcast(tyVector(VecTy, MVT::i16), VecV),
1947 DAG.getBitcast(MVT::i16, ValV), IdxV);
1948 return DAG.getBitcast(tyVector(VecTy, ElemTy), T0);
1949 }
1950
1951 return insertHvxElementReg(VecV, IdxV, ValV, dl, DAG);
1952}
1953
1954SDValue
1955HexagonTargetLowering::LowerHvxExtractSubvector(SDValue Op, SelectionDAG &DAG)
1956 const {
1957 SDValue SrcV = Op.getOperand(0);
1958 MVT SrcTy = ty(SrcV);
1959 MVT DstTy = ty(Op);
1960 SDValue IdxV = Op.getOperand(1);
1961 unsigned Idx = IdxV.getNode()->getAsZExtVal();
1962 assert(Idx % DstTy.getVectorNumElements() == 0);
1963 (void)Idx;
1964 const SDLoc &dl(Op);
1965
1966 MVT ElemTy = SrcTy.getVectorElementType();
1967 if (ElemTy == MVT::i1)
1968 return extractHvxSubvectorPred(SrcV, IdxV, dl, DstTy, DAG);
1969
1970 return extractHvxSubvectorReg(Op, SrcV, IdxV, dl, DstTy, DAG);
1971}
1972
1973SDValue
1974HexagonTargetLowering::LowerHvxInsertSubvector(SDValue Op, SelectionDAG &DAG)
1975 const {
1976 // Idx does not need to be a constant.
1977 SDValue VecV = Op.getOperand(0);
1978 SDValue ValV = Op.getOperand(1);
1979 SDValue IdxV = Op.getOperand(2);
1980
1981 const SDLoc &dl(Op);
1982 MVT VecTy = ty(VecV);
1983 MVT ElemTy = VecTy.getVectorElementType();
1984 if (ElemTy == MVT::i1)
1985 return insertHvxSubvectorPred(VecV, ValV, IdxV, dl, DAG);
1986
1987 return insertHvxSubvectorReg(VecV, ValV, IdxV, dl, DAG);
1988}
1989
1990SDValue
1991HexagonTargetLowering::LowerHvxAnyExt(SDValue Op, SelectionDAG &DAG) const {
1992 // Lower any-extends of boolean vectors to sign-extends, since they
1993 // translate directly to Q2V. Zero-extending could also be done equally
1994 // fast, but Q2V is used/recognized in more places.
1995 // For all other vectors, use zero-extend.
1996 MVT ResTy = ty(Op);
1997 SDValue InpV = Op.getOperand(0);
1998 MVT ElemTy = ty(InpV).getVectorElementType();
1999 if (ElemTy == MVT::i1 && Subtarget.isHVXVectorType(ResTy))
2000 return LowerHvxSignExt(Op, DAG);
2001 return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), ResTy, InpV);
2002}
2003
2004SDValue
2005HexagonTargetLowering::LowerHvxSignExt(SDValue Op, SelectionDAG &DAG) const {
2006 MVT ResTy = ty(Op);
2007 SDValue InpV = Op.getOperand(0);
2008 MVT ElemTy = ty(InpV).getVectorElementType();
2009 if (ElemTy == MVT::i1 && Subtarget.isHVXVectorType(ResTy))
2010 return extendHvxVectorPred(InpV, SDLoc(Op), ty(Op), false, DAG);
2011 return Op;
2012}
2013
2014SDValue
2015HexagonTargetLowering::LowerHvxZeroExt(SDValue Op, SelectionDAG &DAG) const {
2016 MVT ResTy = ty(Op);
2017 SDValue InpV = Op.getOperand(0);
2018 MVT ElemTy = ty(InpV).getVectorElementType();
2019 if (ElemTy == MVT::i1 && Subtarget.isHVXVectorType(ResTy))
2020 return extendHvxVectorPred(InpV, SDLoc(Op), ty(Op), true, DAG);
2021 return Op;
2022}
2023
2024SDValue
2025HexagonTargetLowering::LowerHvxCttz(SDValue Op, SelectionDAG &DAG) const {
2026 // Lower vector CTTZ into a computation using CTLZ (Hacker's Delight):
2027 // cttz(x) = bitwidth(x) - ctlz(~x & (x-1))
2028 const SDLoc &dl(Op);
2029 MVT ResTy = ty(Op);
2030 SDValue InpV = Op.getOperand(0);
2031 assert(ResTy == ty(InpV));
2032
2033 // Calculate the vectors of 1 and bitwidth(x).
2034 MVT ElemTy = ty(InpV).getVectorElementType();
2035 unsigned ElemWidth = ElemTy.getSizeInBits();
2036
2037 SDValue Vec1 = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
2038 DAG.getConstant(1, dl, MVT::i32));
2039 SDValue VecW = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
2040 DAG.getConstant(ElemWidth, dl, MVT::i32));
2041 SDValue VecN1 = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
2042 DAG.getAllOnesConstant(dl, MVT::i32));
2043
2044 // Do not use DAG.getNOT, because that would create BUILD_VECTOR with
2045 // a BITCAST. Here we can skip the BITCAST (so we don't have to handle
2046 // it separately in custom combine or selection).
2047 SDValue A = DAG.getNode(ISD::AND, dl, ResTy,
2048 {DAG.getNode(ISD::XOR, dl, ResTy, {InpV, VecN1}),
2049 DAG.getNode(ISD::SUB, dl, ResTy, {InpV, Vec1})});
2050 return DAG.getNode(ISD::SUB, dl, ResTy,
2051 {VecW, DAG.getNode(ISD::CTLZ, dl, ResTy, A)});
2052}
2053
2054SDValue
2055HexagonTargetLowering::LowerHvxMulh(SDValue Op, SelectionDAG &DAG) const {
2056 const SDLoc &dl(Op);
2057 MVT ResTy = ty(Op);
2058 assert(ResTy.getVectorElementType() == MVT::i32);
2059
2060 SDValue Vs = Op.getOperand(0);
2061 SDValue Vt = Op.getOperand(1);
2062
2063 SDVTList ResTys = DAG.getVTList(ResTy, ResTy);
2064 unsigned Opc = Op.getOpcode();
2065
2066 // On HVX v62+ producing the full product is cheap, so legalize MULH to LOHI.
2067 if (Opc == ISD::MULHU)
2068 return DAG.getNode(HexagonISD::UMUL_LOHI, dl, ResTys, {Vs, Vt}).getValue(1);
2069 if (Opc == ISD::MULHS)
2070 return DAG.getNode(HexagonISD::SMUL_LOHI, dl, ResTys, {Vs, Vt}).getValue(1);
2071
2072#ifndef NDEBUG
2073 Op.dump(&DAG);
2074#endif
2075 llvm_unreachable("Unexpected mulh operation");
2076}
2077
2078SDValue
2079HexagonTargetLowering::LowerHvxMulLoHi(SDValue Op, SelectionDAG &DAG) const {
2080 const SDLoc &dl(Op);
2081 unsigned Opc = Op.getOpcode();
2082 SDValue Vu = Op.getOperand(0);
2083 SDValue Vv = Op.getOperand(1);
2084
2085 // If the HI part is not used, convert it to a regular MUL.
2086 if (auto HiVal = Op.getValue(1); HiVal.use_empty()) {
2087 // Need to preserve the types and the number of values.
2088 SDValue Hi = DAG.getUNDEF(ty(HiVal));
2089 SDValue Lo = DAG.getNode(ISD::MUL, dl, ty(Op), {Vu, Vv});
2090 return DAG.getMergeValues({Lo, Hi}, dl);
2091 }
2092
2093 bool SignedVu = Opc == HexagonISD::SMUL_LOHI;
2094 bool SignedVv = Opc == HexagonISD::SMUL_LOHI || Opc == HexagonISD::USMUL_LOHI;
2095
2096 // Legal on HVX v62+, but lower it here because patterns can't handle multi-
2097 // valued nodes.
2098 if (Subtarget.useHVXV62Ops())
2099 return emitHvxMulLoHiV62(Vu, SignedVu, Vv, SignedVv, dl, DAG);
2100
2101 if (Opc == HexagonISD::SMUL_LOHI) {
2102 // Direct MULHS expansion is cheaper than doing the whole SMUL_LOHI,
2103 // for other signedness LOHI is cheaper.
2104 if (auto LoVal = Op.getValue(0); LoVal.use_empty()) {
2105 SDValue Hi = emitHvxMulHsV60(Vu, Vv, dl, DAG);
2106 SDValue Lo = DAG.getUNDEF(ty(LoVal));
2107 return DAG.getMergeValues({Lo, Hi}, dl);
2108 }
2109 }
2110
2111 return emitHvxMulLoHiV60(Vu, SignedVu, Vv, SignedVv, dl, DAG);
2112}
2113
2114SDValue
2115HexagonTargetLowering::LowerHvxBitcast(SDValue Op, SelectionDAG &DAG) const {
2116 SDValue Val = Op.getOperand(0);
2117 MVT ResTy = ty(Op);
2118 MVT ValTy = ty(Val);
2119 const SDLoc &dl(Op);
2120
2121 if (isHvxBoolTy(ValTy) && ResTy.isScalarInteger()) {
2122 unsigned HwLen = Subtarget.getVectorLength();
2123 MVT WordTy = MVT::getVectorVT(MVT::i32, HwLen/4);
2124
2125 // When the predicate is shorter than the predicate register, each boolean
2126 // is represented by multiple consecutive bits in the input register.
2127 // Condense the bits so each boolean is represented by one bit. This only
2128 // handles 2x and 4x compaction ratios.
2129 unsigned PredLen = ValTy.getVectorNumElements();
2130 if (PredLen < HwLen) {
2131 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
2132 Val = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, Val);
2133 if (HwLen > PredLen * 2) {
2134 assert(HwLen == PredLen * 4);
2135 PredLen *= 2;
2136 Val = getInstr(Hexagon::V6_vdealh, dl, ByteTy, Val, DAG);
2137 }
2138 if (HwLen > PredLen) {
2139 assert(HwLen == PredLen * 2);
2140 Val = getInstr(Hexagon::V6_vdealb, dl, ByteTy, Val, DAG);
2141 }
2142 Val = DAG.getNode(HexagonISD::V2Q, dl, ValTy, Val);
2143 }
2144
2145 SDValue VQ = compressHvxPred(Val, dl, WordTy, DAG);
2146 unsigned BitWidth = ResTy.getSizeInBits();
2147
2148 if (BitWidth < 64) {
2149 SDValue W0 = extractHvxElementReg(VQ, DAG.getConstant(0, dl, MVT::i32),
2150 dl, MVT::i32, DAG);
2151 if (BitWidth == 32)
2152 return W0;
2153 assert(BitWidth < 32u);
2154 return DAG.getZExtOrTrunc(W0, dl, ResTy);
2155 }
2156
2157 // The result is >= 64 bits. The only options are 64 or 128.
2158 assert(BitWidth == 64 || BitWidth == 128);
2160 for (unsigned i = 0; i != BitWidth/32; ++i) {
2161 SDValue W = extractHvxElementReg(
2162 VQ, DAG.getConstant(i, dl, MVT::i32), dl, MVT::i32, DAG);
2163 Words.push_back(W);
2164 }
2165 SmallVector<SDValue,2> Combines;
2166 assert(Words.size() % 2 == 0);
2167 for (unsigned i = 0, e = Words.size(); i < e; i += 2) {
2168 SDValue C = getCombine(Words[i+1], Words[i], dl, MVT::i64, DAG);
2169 Combines.push_back(C);
2170 }
2171
2172 if (BitWidth == 64)
2173 return Combines[0];
2174
2175 return DAG.getNode(ISD::BUILD_PAIR, dl, ResTy, Combines);
2176 }
2177
2178 // Handle bitcast from i32, v2i16, and v4i8 to v32i1.
2179 // Splat the input into a 32-element i32 vector, then AND each element
2180 // with a unique bitmask to isolate individual bits.
2181 auto bitcastI32ToV32I1 = [&](SDValue Val32) {
2182 assert(Val32.getValueType().getSizeInBits() == 32 &&
2183 "Input must be 32 bits");
2184 MVT VecTy = MVT::getVectorVT(MVT::i32, 32);
2185 SDValue Splat = DAG.getNode(ISD::SPLAT_VECTOR, dl, VecTy, Val32);
2187 for (unsigned i = 0; i < 32; ++i)
2188 Mask.push_back(DAG.getConstant(1ull << i, dl, MVT::i32));
2189
2190 SDValue MaskVec = DAG.getBuildVector(VecTy, dl, Mask);
2191 SDValue Anded = DAG.getNode(ISD::AND, dl, VecTy, Splat, MaskVec);
2192 return DAG.getNode(HexagonISD::V2Q, dl, MVT::v32i1, Anded);
2193 };
2194 // === Case: v32i1 ===
2195 if (ResTy == MVT::v32i1 &&
2196 (ValTy == MVT::i32 || ValTy == MVT::v2i16 || ValTy == MVT::v4i8) &&
2197 Subtarget.useHVX128BOps()) {
2198 SDValue Val32 = Val;
2199 if (ValTy == MVT::v2i16 || ValTy == MVT::v4i8)
2200 Val32 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Val);
2201 return bitcastI32ToV32I1(Val32);
2202 }
2203 // === Case: v64i1 ===
2204 if (ResTy == MVT::v64i1 && ValTy == MVT::i64 && Subtarget.useHVX128BOps()) {
2205 // Split i64 into lo/hi 32-bit halves.
2206 SDValue Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Val);
2207 SDValue HiShifted = DAG.getNode(ISD::SRL, dl, MVT::i64, Val,
2208 DAG.getConstant(32, dl, MVT::i64));
2209 SDValue Hi = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, HiShifted);
2210
2211 // Reuse the same 32-bit logic twice.
2212 SDValue LoRes = bitcastI32ToV32I1(Lo);
2213 SDValue HiRes = bitcastI32ToV32I1(Hi);
2214
2215 // Concatenate into a v64i1 predicate.
2216 return DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v64i1, LoRes, HiRes);
2217 }
2218
2219 if (isHvxBoolTy(ResTy) && ValTy.isScalarInteger()) {
2220 // Handle bitcast from i128 -> v128i1 and i64 -> v64i1.
2221 unsigned BitWidth = ValTy.getSizeInBits();
2222 unsigned HwLen = Subtarget.getVectorLength();
2223 assert(BitWidth == HwLen);
2224
2225 MVT ValAsVecTy = MVT::getVectorVT(MVT::i8, BitWidth / 8);
2226 SDValue ValAsVec = DAG.getBitcast(ValAsVecTy, Val);
2227 // Splat each byte of Val 8 times.
2228 // Bytes = [(b0)x8, (b1)x8, ...., (b15)x8]
2229 // where b0, b1,..., b15 are least to most significant bytes of I.
2231 // Tmp: 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, 0x01,0x02,0x04,0x08,...
2232 // These are bytes with the LSB rotated left with respect to their index.
2234 for (unsigned I = 0; I != HwLen / 8; ++I) {
2235 SDValue Idx = DAG.getConstant(I, dl, MVT::i32);
2236 SDValue Byte =
2237 DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i8, ValAsVec, Idx);
2238 for (unsigned J = 0; J != 8; ++J) {
2239 Bytes.push_back(Byte);
2240 Tmp.push_back(DAG.getConstant(1ull << J, dl, MVT::i8));
2241 }
2242 }
2243
2244 MVT ConstantVecTy = MVT::getVectorVT(MVT::i8, HwLen);
2245 SDValue ConstantVec = DAG.getBuildVector(ConstantVecTy, dl, Tmp);
2246 SDValue I2V = buildHvxVectorReg(Bytes, dl, ConstantVecTy, DAG);
2247
2248 // Each Byte in the I2V will be set iff corresponding bit is set in Val.
2249 I2V = DAG.getNode(ISD::AND, dl, ConstantVecTy, {I2V, ConstantVec});
2250 return DAG.getNode(HexagonISD::V2Q, dl, ResTy, I2V);
2251 }
2252
2253 return Op;
2254}
2255
2256SDValue HexagonTargetLowering::LowerHvxStore(SDValue Op,
2257 SelectionDAG &DAG) const {
2258 const SDLoc &dl(Op);
2259 StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
2260 SDValue Val = SN->getValue();
2261 MVT ValTy = ty(Val);
2262
2263 // Check if this is a store of an HVX bool vector (predicate)
2264 if (!isHvxBoolTy(ValTy))
2265 return SDValue();
2266
2267 unsigned NumBits = ValTy.getVectorNumElements();
2268 MachineMemOperand *MMO = SN->getMemOperand();
2269
2270 // Check alignment requirements based on predicate size
2271 unsigned RequiredAlign = (NumBits == 32) ? 4 : 8;
2272 if (MMO->getBaseAlign().value() % RequiredAlign != 0)
2273 return SDValue();
2274
2275 unsigned HwLen = Subtarget.getVectorLength();
2276 MVT WordTy = MVT::getVectorVT(MVT::i32, HwLen / 4);
2277
2278 // Compress the predicate into a vector register
2279 SDValue VQ = compressHvxPred(Val, dl, WordTy, DAG);
2280
2281 // Extract words from the compressed vector
2283 for (unsigned i = 0; i != NumBits / 32; ++i) {
2284 SDValue W = extractHvxElementReg(VQ, DAG.getConstant(i, dl, MVT::i32), dl,
2285 MVT::i32, DAG);
2286 Words.push_back(W);
2287 }
2288
2289 SDValue Chain = SN->getChain();
2290 SDValue BasePtr = SN->getBasePtr();
2291 MachinePointerInfo PtrInfo = MMO->getPointerInfo();
2292
2293 if (NumBits == 32)
2294 return DAG.getStore(Chain, dl, Words[0], BasePtr, PtrInfo,
2295 MMO->getBaseAlign());
2296
2297 if (NumBits == 64) {
2298 SDValue W64 = getCombine(Words[1], Words[0], dl, MVT::i64, DAG);
2299 return DAG.getStore(Chain, dl, W64, BasePtr, PtrInfo, MMO->getBaseAlign());
2300 }
2301
2302 if (NumBits == 128) {
2303 SDValue Lo64 = getCombine(Words[1], Words[0], dl, MVT::i64, DAG);
2304 SDValue Hi64 = getCombine(Words[3], Words[2], dl, MVT::i64, DAG);
2305
2306 Chain =
2307 DAG.getStore(Chain, dl, Lo64, BasePtr, PtrInfo, MMO->getBaseAlign());
2308
2309 SDValue Offset8 = DAG.getConstant(8, dl, MVT::i32);
2310 SDValue Ptr8 = DAG.getNode(ISD::ADD, dl, MVT::i32, BasePtr, Offset8);
2311 return DAG.getStore(Chain, dl, Hi64, Ptr8, PtrInfo.getWithOffset(8),
2312 Align(8));
2313 }
2314
2315 return SDValue();
2316}
2317
2318SDValue HexagonTargetLowering::LowerHvxLoad(SDValue Op,
2319 SelectionDAG &DAG) const {
2320 const SDLoc &dl(Op);
2321 LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
2322 MVT ResTy = ty(Op);
2323
2324 // Check if this is a load of an HVX bool vector (predicate)
2325 if (!isHvxBoolTy(ResTy))
2326 return SDValue();
2327
2328 unsigned NumBits = ResTy.getVectorNumElements();
2329 MachineMemOperand *MMO = LN->getMemOperand();
2330
2331 unsigned RequiredAlign = (NumBits == 32) ? 4 : 8;
2332 if (MMO->getBaseAlign().value() % RequiredAlign != 0)
2333 return SDValue();
2334
2335 SDValue Chain = LN->getChain();
2336 SDValue BasePtr = LN->getBasePtr();
2337 MachinePointerInfo PtrInfo = MMO->getPointerInfo();
2338
2339 if (NumBits == 32) {
2340 SDValue W32 =
2341 DAG.getLoad(MVT::i32, dl, Chain, BasePtr, PtrInfo, MMO->getBaseAlign());
2342 SDValue Pred = DAG.getNode(ISD::BITCAST, dl, MVT::v32i1, W32);
2343 SDValue Ops[] = {Pred, W32.getValue(1)};
2344 return DAG.getMergeValues(Ops, dl);
2345 }
2346
2347 if (NumBits == 64) {
2348 SDValue W64 =
2349 DAG.getLoad(MVT::i64, dl, Chain, BasePtr, PtrInfo, MMO->getBaseAlign());
2350 SDValue Pred = DAG.getNode(ISD::BITCAST, dl, MVT::v64i1, W64);
2351 SDValue Ops[] = {Pred, W64.getValue(1)};
2352 return DAG.getMergeValues(Ops, dl);
2353 }
2354
2355 if (NumBits == 128) {
2356 SDValue Lo64 =
2357 DAG.getLoad(MVT::i64, dl, Chain, BasePtr, PtrInfo, MMO->getBaseAlign());
2358 Chain = Lo64.getValue(1);
2359
2360 SDValue Offset8 = DAG.getConstant(8, dl, MVT::i32);
2361 SDValue Ptr8 = DAG.getNode(ISD::ADD, dl, MVT::i32, BasePtr, Offset8);
2362 SDValue Hi64 = DAG.getLoad(MVT::i64, dl, Chain, Ptr8,
2363 PtrInfo.getWithOffset(8), Align(8));
2364
2365 SDValue LoPred = DAG.getNode(ISD::BITCAST, dl, MVT::v64i1, Lo64);
2366 SDValue HiPred = DAG.getNode(ISD::BITCAST, dl, MVT::v64i1, Hi64);
2367 SDValue Pred =
2368 DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v128i1, LoPred, HiPred);
2369
2370 SDValue Ops[] = {Pred, Hi64.getValue(1)};
2371 return DAG.getMergeValues(Ops, dl);
2372 }
2373
2374 return SDValue();
2375}
2376
2377SDValue
2378HexagonTargetLowering::LowerHvxExtend(SDValue Op, SelectionDAG &DAG) const {
2379 // Sign- and zero-extends are legal.
2380 assert(Op.getOpcode() == ISD::ANY_EXTEND_VECTOR_INREG);
2381 return DAG.getNode(ISD::ZERO_EXTEND_VECTOR_INREG, SDLoc(Op), ty(Op),
2382 Op.getOperand(0));
2383}
2384
2385SDValue
2386HexagonTargetLowering::LowerHvxSelect(SDValue Op, SelectionDAG &DAG) const {
2387 MVT ResTy = ty(Op);
2388 if (ResTy.getVectorElementType() != MVT::i1)
2389 return Op;
2390
2391 const SDLoc &dl(Op);
2392 unsigned HwLen = Subtarget.getVectorLength();
2393 unsigned VecLen = ResTy.getVectorNumElements();
2394 assert(HwLen % VecLen == 0);
2395 unsigned ElemSize = HwLen / VecLen;
2396
2397 MVT VecTy = MVT::getVectorVT(MVT::getIntegerVT(ElemSize * 8), VecLen);
2398 SDValue S =
2399 DAG.getNode(ISD::SELECT, dl, VecTy, Op.getOperand(0),
2400 DAG.getNode(HexagonISD::Q2V, dl, VecTy, Op.getOperand(1)),
2401 DAG.getNode(HexagonISD::Q2V, dl, VecTy, Op.getOperand(2)));
2402 return DAG.getNode(HexagonISD::V2Q, dl, ResTy, S);
2403}
2404
2405SDValue
2406HexagonTargetLowering::LowerHvxShift(SDValue Op, SelectionDAG &DAG) const {
2407 if (SDValue S = getVectorShiftByInt(Op, DAG))
2408 return S;
2409 return Op;
2410}
2411
2412SDValue
2413HexagonTargetLowering::LowerHvxFunnelShift(SDValue Op,
2414 SelectionDAG &DAG) const {
2415 unsigned Opc = Op.getOpcode();
2416 assert(Opc == ISD::FSHL || Opc == ISD::FSHR);
2417
2418 // Make sure the shift amount is within the range of the bitwidth
2419 // of the element type.
2420 SDValue A = Op.getOperand(0);
2421 SDValue B = Op.getOperand(1);
2422 SDValue S = Op.getOperand(2);
2423
2424 MVT InpTy = ty(A);
2425 MVT ElemTy = InpTy.getVectorElementType();
2426
2427 const SDLoc &dl(Op);
2428 unsigned ElemWidth = ElemTy.getSizeInBits();
2429 bool IsLeft = Opc == ISD::FSHL;
2430
2431 // The expansion into regular shifts produces worse code for i8 and for
2432 // right shift of i32 on v65+.
2433 bool UseShifts = ElemTy != MVT::i8;
2434 if (Subtarget.useHVXV65Ops() && ElemTy == MVT::i32)
2435 UseShifts = false;
2436
2437 if (SDValue SplatV = getSplatValue(S, DAG); SplatV && UseShifts) {
2438 // If this is a funnel shift by a scalar, lower it into regular shifts.
2439 SDValue Mask = DAG.getConstant(ElemWidth - 1, dl, MVT::i32);
2440 SDValue ModS =
2441 DAG.getNode(ISD::AND, dl, MVT::i32,
2442 {DAG.getZExtOrTrunc(SplatV, dl, MVT::i32), Mask});
2443 SDValue NegS =
2444 DAG.getNode(ISD::SUB, dl, MVT::i32,
2445 {DAG.getConstant(ElemWidth, dl, MVT::i32), ModS});
2446 SDValue IsZero =
2447 DAG.getSetCC(dl, MVT::i1, ModS, getZero(dl, MVT::i32, DAG), ISD::SETEQ);
2448 // FSHL A, B => A << | B >>n
2449 // FSHR A, B => A <<n | B >>
2450 SDValue Part1 =
2451 DAG.getNode(HexagonISD::VASL, dl, InpTy, {A, IsLeft ? ModS : NegS});
2452 SDValue Part2 =
2453 DAG.getNode(HexagonISD::VLSR, dl, InpTy, {B, IsLeft ? NegS : ModS});
2454 SDValue Or = DAG.getNode(ISD::OR, dl, InpTy, {Part1, Part2});
2455 // If the shift amount was 0, pick A or B, depending on the direction.
2456 // The opposite shift will also be by 0, so the "Or" will be incorrect.
2457 return DAG.getNode(ISD::SELECT, dl, InpTy, {IsZero, (IsLeft ? A : B), Or});
2458 }
2459
2461 InpTy, dl, DAG.getConstant(ElemWidth - 1, dl, ElemTy));
2462
2463 unsigned MOpc = Opc == ISD::FSHL ? HexagonISD::MFSHL : HexagonISD::MFSHR;
2464 return DAG.getNode(MOpc, dl, ty(Op),
2465 {A, B, DAG.getNode(ISD::AND, dl, InpTy, {S, Mask})});
2466}
2467
2468SDValue
2469HexagonTargetLowering::LowerHvxIntrinsic(SDValue Op, SelectionDAG &DAG) const {
2470 const SDLoc &dl(Op);
2471 unsigned IntNo = Op.getConstantOperandVal(0);
2472 SmallVector<SDValue> Ops(Op->ops());
2473
2474 auto Swap = [&](SDValue P) {
2475 return DAG.getMergeValues({P.getValue(1), P.getValue(0)}, dl);
2476 };
2477
2478 switch (IntNo) {
2479 case Intrinsic::hexagon_V6_pred_typecast:
2480 case Intrinsic::hexagon_V6_pred_typecast_128B: {
2481 MVT ResTy = ty(Op), InpTy = ty(Ops[1]);
2482 if (isHvxBoolTy(ResTy) && isHvxBoolTy(InpTy)) {
2483 if (ResTy == InpTy)
2484 return Ops[1];
2485 return DAG.getNode(HexagonISD::TYPECAST, dl, ResTy, Ops[1]);
2486 }
2487 break;
2488 }
2489 case Intrinsic::hexagon_V6_vmpyss_parts:
2490 case Intrinsic::hexagon_V6_vmpyss_parts_128B:
2491 return Swap(DAG.getNode(HexagonISD::SMUL_LOHI, dl, Op->getVTList(),
2492 {Ops[1], Ops[2]}));
2493 case Intrinsic::hexagon_V6_vmpyuu_parts:
2494 case Intrinsic::hexagon_V6_vmpyuu_parts_128B:
2495 return Swap(DAG.getNode(HexagonISD::UMUL_LOHI, dl, Op->getVTList(),
2496 {Ops[1], Ops[2]}));
2497 case Intrinsic::hexagon_V6_vmpyus_parts:
2498 case Intrinsic::hexagon_V6_vmpyus_parts_128B: {
2499 return Swap(DAG.getNode(HexagonISD::USMUL_LOHI, dl, Op->getVTList(),
2500 {Ops[1], Ops[2]}));
2501 }
2502 } // switch
2503
2504 return Op;
2505}
2506
2507SDValue
2508HexagonTargetLowering::LowerHvxMaskedOp(SDValue Op, SelectionDAG &DAG) const {
2509 const SDLoc &dl(Op);
2510 unsigned HwLen = Subtarget.getVectorLength();
2511 MachineFunction &MF = DAG.getMachineFunction();
2512 auto *MaskN = cast<MaskedLoadStoreSDNode>(Op.getNode());
2513 SDValue Mask = MaskN->getMask();
2514 SDValue Chain = MaskN->getChain();
2515 SDValue Base = MaskN->getBasePtr();
2516 auto *MemOp = MF.getMachineMemOperand(MaskN->getMemOperand(), 0, HwLen);
2517
2518 unsigned Opc = Op->getOpcode();
2520
2521 if (Opc == ISD::MLOAD) {
2522 MVT ValTy = ty(Op);
2523 SDValue Load = DAG.getLoad(ValTy, dl, Chain, Base, MemOp);
2524 SDValue Thru = cast<MaskedLoadSDNode>(MaskN)->getPassThru();
2525 if (isUndef(Thru))
2526 return Load;
2527 SDValue VSel = DAG.getNode(ISD::VSELECT, dl, ValTy, Mask, Load, Thru);
2528 return DAG.getMergeValues({VSel, Load.getValue(1)}, dl);
2529 }
2530
2531 // MSTORE
2532 // HVX only has aligned masked stores.
2533
2534 // TODO: Fold negations of the mask into the store.
2535 unsigned StoreOpc = Hexagon::V6_vS32b_qpred_ai;
2536 SDValue Value = cast<MaskedStoreSDNode>(MaskN)->getValue();
2537 SDValue Offset0 = DAG.getTargetConstant(0, dl, ty(Base));
2538
2539 if (MaskN->getAlign().value() % HwLen == 0) {
2540 SDValue Store = getInstr(StoreOpc, dl, MVT::Other,
2541 {Mask, Base, Offset0, Value, Chain}, DAG);
2542 DAG.setNodeMemRefs(cast<MachineSDNode>(Store.getNode()), {MemOp});
2543 return Store;
2544 }
2545
2546 // Unaligned case.
2547 auto StoreAlign = [&](SDValue V, SDValue A) {
2548 SDValue Z = getZero(dl, ty(V), DAG);
2549 // TODO: use funnel shifts?
2550 // vlalign(Vu,Vv,Rt) rotates the pair Vu:Vv left by Rt and takes the
2551 // upper half.
2552 SDValue LoV = getInstr(Hexagon::V6_vlalignb, dl, ty(V), {V, Z, A}, DAG);
2553 SDValue HiV = getInstr(Hexagon::V6_vlalignb, dl, ty(V), {Z, V, A}, DAG);
2554 return std::make_pair(LoV, HiV);
2555 };
2556
2557 MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
2558 MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
2559 SDValue MaskV = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, Mask);
2560 VectorPair Tmp = StoreAlign(MaskV, Base);
2561 VectorPair MaskU = {DAG.getNode(HexagonISD::V2Q, dl, BoolTy, Tmp.first),
2562 DAG.getNode(HexagonISD::V2Q, dl, BoolTy, Tmp.second)};
2563 VectorPair ValueU = StoreAlign(Value, Base);
2564
2565 SDValue Offset1 = DAG.getTargetConstant(HwLen, dl, MVT::i32);
2566 SDValue StoreLo =
2567 getInstr(StoreOpc, dl, MVT::Other,
2568 {MaskU.first, Base, Offset0, ValueU.first, Chain}, DAG);
2569 SDValue StoreHi =
2570 getInstr(StoreOpc, dl, MVT::Other,
2571 {MaskU.second, Base, Offset1, ValueU.second, Chain}, DAG);
2572 DAG.setNodeMemRefs(cast<MachineSDNode>(StoreLo.getNode()), {MemOp});
2573 DAG.setNodeMemRefs(cast<MachineSDNode>(StoreHi.getNode()), {MemOp});
2574 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, {StoreLo, StoreHi});
2575}
2576
2577SDValue HexagonTargetLowering::LowerHvxFpExtend(SDValue Op,
2578 SelectionDAG &DAG) const {
2579 // This conversion only applies to QFloat. IEEE extension from f16 to f32
2580 // is legal (done via a pattern).
2581 assert(Subtarget.useHVXQFloatOps());
2582
2583 assert(Op->getOpcode() == ISD::FP_EXTEND);
2584
2585 MVT VecTy = ty(Op);
2586 MVT ArgTy = ty(Op.getOperand(0));
2587 const SDLoc &dl(Op);
2588
2589 if (ArgTy == MVT::v64bf16) {
2590 MVT HalfTy = typeSplit(VecTy).first;
2591 SDValue BF16Vec = Op.getOperand(0);
2592 SDValue Zeroes =
2593 getInstr(Hexagon::V6_vxor, dl, HalfTy, {BF16Vec, BF16Vec}, DAG);
2594 // Interleave zero vector with the bf16 vector, with zeroes in the lower
2595 // half of each 32 bit lane, effectively extending the bf16 values to fp32
2596 // values.
2597 SDValue ShuffVec =
2598 getInstr(Hexagon::V6_vshufoeh, dl, VecTy, {BF16Vec, Zeroes}, DAG);
2599 VectorPair VecPair = opSplit(ShuffVec, dl, DAG);
2600 SDValue Result = getInstr(Hexagon::V6_vshuffvdd, dl, VecTy,
2601 {VecPair.second, VecPair.first,
2602 DAG.getSignedConstant(-4, dl, MVT::i32)},
2603 DAG);
2604 return Result;
2605 }
2606
2607 assert(VecTy == MVT::v64f32 && ArgTy == MVT::v64f16);
2608
2609 SDValue F16Vec = Op.getOperand(0);
2610
2611 APFloat FloatVal = APFloat(1.0f);
2612 bool Ignored;
2614 SDValue Fp16Ones = DAG.getConstantFP(FloatVal, dl, ArgTy);
2615 SDValue VmpyVec =
2616 getInstr(Hexagon::V6_vmpy_qf32_hf, dl, VecTy, {F16Vec, Fp16Ones}, DAG);
2617
2618 MVT HalfTy = typeSplit(VecTy).first;
2619 VectorPair Pair = opSplit(VmpyVec, dl, DAG);
2620 SDValue LoVec =
2621 getInstr(Hexagon::V6_vconv_sf_qf32, dl, HalfTy, {Pair.first}, DAG);
2622 SDValue HiVec =
2623 getInstr(Hexagon::V6_vconv_sf_qf32, dl, HalfTy, {Pair.second}, DAG);
2624
2625 SDValue ShuffVec =
2626 getInstr(Hexagon::V6_vshuffvdd, dl, VecTy,
2627 {HiVec, LoVec, DAG.getSignedConstant(-4, dl, MVT::i32)}, DAG);
2628
2629 return ShuffVec;
2630}
2631
2632SDValue
2633HexagonTargetLowering::LowerHvxFpToInt(SDValue Op, SelectionDAG &DAG) const {
2634 // Catch invalid conversion ops (just in case).
2635 assert(Op.getOpcode() == ISD::FP_TO_SINT ||
2636 Op.getOpcode() == ISD::FP_TO_UINT);
2637
2638 MVT ResTy = ty(Op);
2639 MVT FpTy = ty(Op.getOperand(0)).getVectorElementType();
2640 MVT IntTy = ResTy.getVectorElementType();
2641
2642 if (Subtarget.useHVXIEEEFPOps()) {
2643 // There are only conversions from f16.
2644 if (FpTy == MVT::f16) {
2645 // Other int types aren't legal in HVX, so we shouldn't see them here.
2646 assert(IntTy == MVT::i8 || IntTy == MVT::i16 || IntTy == MVT::i32);
2647 // Conversions to i8 and i16 are legal.
2648 if (IntTy == MVT::i8 || IntTy == MVT::i16)
2649 return Op;
2650 }
2651 }
2652
2653 if (IntTy.getSizeInBits() != FpTy.getSizeInBits())
2654 return EqualizeFpIntConversion(Op, DAG);
2655
2656 return ExpandHvxFpToInt(Op, DAG);
2657}
2658
2659// For vector type v32i1 uint_to_fp/sint_to_fp to v32f32:
2660// R1 = #1, R2 holds the v32i1 param
2661// V1 = vsplat(R1)
2662// V2 = vsplat(R2)
2663// Q0 = vand(V1,R1)
2664// V0.w=prefixsum(Q0)
2665// V0.w=vsub(V0.w,V1.w)
2666// V2.w = vlsr(V2.w,V0.w)
2667// V2 = vand(V2,V1)
2668// V2.sf = V2.w
2669SDValue HexagonTargetLowering::LowerHvxPred32ToFp(SDValue PredOp,
2670 SelectionDAG &DAG) const {
2671
2672 MVT ResTy = ty(PredOp);
2673 const SDLoc &dl(PredOp);
2674
2675 SDValue Const = DAG.getTargetConstant(0x1, dl, MVT::i32);
2676 SDNode *RegConst = DAG.getMachineNode(Hexagon::A2_tfrsi, dl, MVT::i32, Const);
2677 SDNode *SplatConst = DAG.getMachineNode(Hexagon::V6_lvsplatw, dl, MVT::v32i32,
2678 SDValue(RegConst, 0));
2679 SDNode *PredTransfer =
2680 DAG.getMachineNode(Hexagon::V6_vandvrt, dl, MVT::v32i1,
2681 SDValue(SplatConst, 0), SDValue(RegConst, 0));
2682 SDNode *PrefixSum = DAG.getMachineNode(Hexagon::V6_vprefixqw, dl, MVT::v32i32,
2683 SDValue(PredTransfer, 0));
2684 SDNode *SplatParam = DAG.getMachineNode(
2685 Hexagon::V6_lvsplatw, dl, MVT::v32i32,
2686 DAG.getNode(ISD::BITCAST, dl, MVT::i32, PredOp.getOperand(0)));
2687 SDNode *Vsub =
2688 DAG.getMachineNode(Hexagon::V6_vsubw, dl, MVT::v32i32,
2689 SDValue(PrefixSum, 0), SDValue(SplatConst, 0));
2690 SDNode *IndexShift =
2691 DAG.getMachineNode(Hexagon::V6_vlsrwv, dl, MVT::v32i32,
2692 SDValue(SplatParam, 0), SDValue(Vsub, 0));
2693 SDNode *MaskOff =
2694 DAG.getMachineNode(Hexagon::V6_vand, dl, MVT::v32i32,
2695 SDValue(IndexShift, 0), SDValue(SplatConst, 0));
2696 SDNode *Convert = DAG.getMachineNode(Hexagon::V6_vconv_sf_w, dl, ResTy,
2697 SDValue(MaskOff, 0));
2698 return SDValue(Convert, 0);
2699}
2700
2701// For vector type v64i1 uint_to_fo to v64f16:
2702// i64 R32 = bitcast v64i1 R3:2 (R3:2 holds v64i1)
2703// R3 = subreg_high (R32)
2704// R2 = subreg_low (R32)
2705// R1 = #1
2706// V1 = vsplat(R1)
2707// V2 = vsplat(R2)
2708// V3 = vsplat(R3)
2709// Q0 = vand(V1,R1)
2710// V0.w=prefixsum(Q0)
2711// V0.w=vsub(V0.w,V1.w)
2712// V2.w = vlsr(V2.w,V0.w)
2713// V3.w = vlsr(V3.w,V0.w)
2714// V2 = vand(V2,V1)
2715// V3 = vand(V3,V1)
2716// V2.h = vpacke(V3.w,V2.w)
2717// V2.hf = V2.h
2718SDValue HexagonTargetLowering::LowerHvxPred64ToFp(SDValue PredOp,
2719 SelectionDAG &DAG) const {
2720
2721 MVT ResTy = ty(PredOp);
2722 const SDLoc &dl(PredOp);
2723
2724 SDValue Inp = DAG.getNode(ISD::BITCAST, dl, MVT::i64, PredOp.getOperand(0));
2725 // Get the hi and lo regs
2726 SDValue HiReg =
2727 DAG.getTargetExtractSubreg(Hexagon::isub_hi, dl, MVT::i32, Inp);
2728 SDValue LoReg =
2729 DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, Inp);
2730 // Get constant #1 and splat into vector V1
2731 SDValue Const = DAG.getTargetConstant(0x1, dl, MVT::i32);
2732 SDNode *RegConst = DAG.getMachineNode(Hexagon::A2_tfrsi, dl, MVT::i32, Const);
2733 SDNode *SplatConst = DAG.getMachineNode(Hexagon::V6_lvsplatw, dl, MVT::v32i32,
2734 SDValue(RegConst, 0));
2735 // Splat the hi and lo args
2736 SDNode *SplatHi =
2737 DAG.getMachineNode(Hexagon::V6_lvsplatw, dl, MVT::v32i32,
2738 DAG.getNode(ISD::BITCAST, dl, MVT::i32, HiReg));
2739 SDNode *SplatLo =
2740 DAG.getMachineNode(Hexagon::V6_lvsplatw, dl, MVT::v32i32,
2741 DAG.getNode(ISD::BITCAST, dl, MVT::i32, LoReg));
2742 // vand between splatted const and const
2743 SDNode *PredTransfer =
2744 DAG.getMachineNode(Hexagon::V6_vandvrt, dl, MVT::v32i1,
2745 SDValue(SplatConst, 0), SDValue(RegConst, 0));
2746 // Get the prefixsum
2747 SDNode *PrefixSum = DAG.getMachineNode(Hexagon::V6_vprefixqw, dl, MVT::v32i32,
2748 SDValue(PredTransfer, 0));
2749 // Get the vsub
2750 SDNode *Vsub =
2751 DAG.getMachineNode(Hexagon::V6_vsubw, dl, MVT::v32i32,
2752 SDValue(PrefixSum, 0), SDValue(SplatConst, 0));
2753 // Get vlsr for hi and lo
2754 SDNode *IndexShift_hi =
2755 DAG.getMachineNode(Hexagon::V6_vlsrwv, dl, MVT::v32i32,
2756 SDValue(SplatHi, 0), SDValue(Vsub, 0));
2757 SDNode *IndexShift_lo =
2758 DAG.getMachineNode(Hexagon::V6_vlsrwv, dl, MVT::v32i32,
2759 SDValue(SplatLo, 0), SDValue(Vsub, 0));
2760 // Get vand of hi and lo
2761 SDNode *MaskOff_hi =
2762 DAG.getMachineNode(Hexagon::V6_vand, dl, MVT::v32i32,
2763 SDValue(IndexShift_hi, 0), SDValue(SplatConst, 0));
2764 SDNode *MaskOff_lo =
2765 DAG.getMachineNode(Hexagon::V6_vand, dl, MVT::v32i32,
2766 SDValue(IndexShift_lo, 0), SDValue(SplatConst, 0));
2767 // Pack them
2768 SDNode *Pack =
2769 DAG.getMachineNode(Hexagon::V6_vpackeh, dl, MVT::v64i16,
2770 SDValue(MaskOff_hi, 0), SDValue(MaskOff_lo, 0));
2771 SDNode *Convert =
2772 DAG.getMachineNode(Hexagon::V6_vconv_hf_h, dl, ResTy, SDValue(Pack, 0));
2773 return SDValue(Convert, 0);
2774}
2775
2776SDValue
2777HexagonTargetLowering::LowerHvxIntToFp(SDValue Op, SelectionDAG &DAG) const {
2778 // Catch invalid conversion ops (just in case).
2779 assert(Op.getOpcode() == ISD::SINT_TO_FP ||
2780 Op.getOpcode() == ISD::UINT_TO_FP);
2781
2782 MVT ResTy = ty(Op);
2783 MVT IntTy = ty(Op.getOperand(0)).getVectorElementType();
2784 MVT FpTy = ResTy.getVectorElementType();
2785
2786 if (Op.getOpcode() == ISD::UINT_TO_FP || Op.getOpcode() == ISD::SINT_TO_FP) {
2787 if (ResTy == MVT::v32f32 && ty(Op.getOperand(0)) == MVT::v32i1)
2788 return LowerHvxPred32ToFp(Op, DAG);
2789 if (ResTy == MVT::v64f16 && ty(Op.getOperand(0)) == MVT::v64i1)
2790 return LowerHvxPred64ToFp(Op, DAG);
2791 }
2792
2793 if (Subtarget.useHVXIEEEFPOps()) {
2794 // There are only conversions to f16.
2795 if (FpTy == MVT::f16) {
2796 // Other int types aren't legal in HVX, so we shouldn't see them here.
2797 assert(IntTy == MVT::i8 || IntTy == MVT::i16 || IntTy == MVT::i32);
2798 // i8, i16 -> f16 is legal.
2799 if (IntTy == MVT::i8 || IntTy == MVT::i16)
2800 return Op;
2801 }
2802 }
2803
2804 if (IntTy.getSizeInBits() != FpTy.getSizeInBits())
2805 return EqualizeFpIntConversion(Op, DAG);
2806
2807 return ExpandHvxIntToFp(Op, DAG);
2808}
2809
2810HexagonTargetLowering::TypePair
2811HexagonTargetLowering::typeExtendToWider(MVT Ty0, MVT Ty1) const {
2812 // Compare the widths of elements of the two types, and extend the narrower
2813 // type to match the with of the wider type. For vector types, apply this
2814 // to the element type.
2815 assert(Ty0.isVector() == Ty1.isVector());
2816
2817 MVT ElemTy0 = Ty0.getScalarType();
2818 MVT ElemTy1 = Ty1.getScalarType();
2819
2820 unsigned Width0 = ElemTy0.getSizeInBits();
2821 unsigned Width1 = ElemTy1.getSizeInBits();
2822 unsigned MaxWidth = std::max(Width0, Width1);
2823
2824 auto getScalarWithWidth = [](MVT ScalarTy, unsigned Width) {
2825 if (ScalarTy.isInteger())
2826 return MVT::getIntegerVT(Width);
2827 assert(ScalarTy.isFloatingPoint());
2828 return MVT::getFloatingPointVT(Width);
2829 };
2830
2831 MVT WideETy0 = getScalarWithWidth(ElemTy0, MaxWidth);
2832 MVT WideETy1 = getScalarWithWidth(ElemTy1, MaxWidth);
2833
2834 if (!Ty0.isVector()) {
2835 // Both types are scalars.
2836 return {WideETy0, WideETy1};
2837 }
2838
2839 // Vector types.
2840 unsigned NumElem = Ty0.getVectorNumElements();
2841 assert(NumElem == Ty1.getVectorNumElements());
2842
2843 return {MVT::getVectorVT(WideETy0, NumElem),
2844 MVT::getVectorVT(WideETy1, NumElem)};
2845}
2846
2847HexagonTargetLowering::TypePair
2848HexagonTargetLowering::typeWidenToWider(MVT Ty0, MVT Ty1) const {
2849 // Compare the numbers of elements of two vector types, and widen the
2850 // narrower one to match the number of elements in the wider one.
2851 assert(Ty0.isVector() && Ty1.isVector());
2852
2853 unsigned Len0 = Ty0.getVectorNumElements();
2854 unsigned Len1 = Ty1.getVectorNumElements();
2855 if (Len0 == Len1)
2856 return {Ty0, Ty1};
2857
2858 unsigned MaxLen = std::max(Len0, Len1);
2859 return {MVT::getVectorVT(Ty0.getVectorElementType(), MaxLen),
2860 MVT::getVectorVT(Ty1.getVectorElementType(), MaxLen)};
2861}
2862
2863MVT
2864HexagonTargetLowering::typeLegalize(MVT Ty, SelectionDAG &DAG) const {
2865 EVT LegalTy = getTypeToTransformTo(*DAG.getContext(), Ty);
2866 assert(LegalTy.isSimple());
2867 return LegalTy.getSimpleVT();
2868}
2869
2870MVT
2871HexagonTargetLowering::typeWidenToHvx(MVT Ty) const {
2872 unsigned HwWidth = 8 * Subtarget.getVectorLength();
2873 assert(Ty.getSizeInBits() <= HwWidth);
2874 if (Ty.getSizeInBits() == HwWidth)
2875 return Ty;
2876
2877 MVT ElemTy = Ty.getScalarType();
2878 return MVT::getVectorVT(ElemTy, HwWidth / ElemTy.getSizeInBits());
2879}
2880
2881HexagonTargetLowering::VectorPair
2882HexagonTargetLowering::emitHvxAddWithOverflow(SDValue A, SDValue B,
2883 const SDLoc &dl, bool Signed, SelectionDAG &DAG) const {
2884 // Compute A+B, return {A+B, O}, where O = vector predicate indicating
2885 // whether an overflow has occurred.
2886 MVT ResTy = ty(A);
2887 assert(ResTy == ty(B));
2888 MVT PredTy = MVT::getVectorVT(MVT::i1, ResTy.getVectorNumElements());
2889
2890 if (!Signed) {
2891 // V62+ has V6_vaddcarry, but it requires input predicate, so it doesn't
2892 // save any instructions.
2893 SDValue Add = DAG.getNode(ISD::ADD, dl, ResTy, {A, B});
2894 SDValue Ovf = DAG.getSetCC(dl, PredTy, Add, A, ISD::SETULT);
2895 return {Add, Ovf};
2896 }
2897
2898 // Signed overflow has happened, if:
2899 // (A, B have the same sign) and (A+B has a different sign from either)
2900 // i.e. (~A xor B) & ((A+B) xor B), then check the sign bit
2901 SDValue Add = DAG.getNode(ISD::ADD, dl, ResTy, {A, B});
2902 SDValue NotA =
2903 DAG.getNode(ISD::XOR, dl, ResTy, {A, DAG.getAllOnesConstant(dl, ResTy)});
2904 SDValue Xor0 = DAG.getNode(ISD::XOR, dl, ResTy, {NotA, B});
2905 SDValue Xor1 = DAG.getNode(ISD::XOR, dl, ResTy, {Add, B});
2906 SDValue And = DAG.getNode(ISD::AND, dl, ResTy, {Xor0, Xor1});
2907 SDValue MSB =
2908 DAG.getSetCC(dl, PredTy, And, getZero(dl, ResTy, DAG), ISD::SETLT);
2909 return {Add, MSB};
2910}
2911
2912HexagonTargetLowering::VectorPair
2913HexagonTargetLowering::emitHvxShiftRightRnd(SDValue Val, unsigned Amt,
2914 bool Signed, SelectionDAG &DAG) const {
2915 // Shift Val right by Amt bits, round the result to the nearest integer,
2916 // tie-break by rounding halves to even integer.
2917
2918 const SDLoc &dl(Val);
2919 MVT ValTy = ty(Val);
2920
2921 // This should also work for signed integers.
2922 //
2923 // uint tmp0 = inp + ((1 << (Amt-1)) - 1);
2924 // bool ovf = (inp > tmp0);
2925 // uint rup = inp & (1 << (Amt+1));
2926 //
2927 // uint tmp1 = inp >> (Amt-1); // tmp1 == tmp2 iff
2928 // uint tmp2 = tmp0 >> (Amt-1); // the Amt-1 lower bits were all 0
2929 // uint tmp3 = tmp2 + rup;
2930 // uint frac = (tmp1 != tmp2) ? tmp2 >> 1 : tmp3 >> 1;
2931 unsigned ElemWidth = ValTy.getVectorElementType().getSizeInBits();
2932 MVT ElemTy = MVT::getIntegerVT(ElemWidth);
2933 MVT IntTy = tyVector(ValTy, ElemTy);
2934 MVT PredTy = MVT::getVectorVT(MVT::i1, IntTy.getVectorNumElements());
2935 unsigned ShRight = Signed ? ISD::SRA : ISD::SRL;
2936
2937 SDValue Inp = DAG.getBitcast(IntTy, Val);
2938 SDValue LowBits = DAG.getConstant((1ull << (Amt - 1)) - 1, dl, IntTy);
2939
2940 SDValue AmtP1 = DAG.getConstant(1ull << Amt, dl, IntTy);
2941 SDValue And = DAG.getNode(ISD::AND, dl, IntTy, {Inp, AmtP1});
2942 SDValue Zero = getZero(dl, IntTy, DAG);
2943 SDValue Bit = DAG.getSetCC(dl, PredTy, And, Zero, ISD::SETNE);
2944 SDValue Rup = DAG.getZExtOrTrunc(Bit, dl, IntTy);
2945 auto [Tmp0, Ovf] = emitHvxAddWithOverflow(Inp, LowBits, dl, Signed, DAG);
2946
2947 SDValue AmtM1 = DAG.getConstant(Amt - 1, dl, IntTy);
2948 SDValue Tmp1 = DAG.getNode(ShRight, dl, IntTy, Inp, AmtM1);
2949 SDValue Tmp2 = DAG.getNode(ShRight, dl, IntTy, Tmp0, AmtM1);
2950 SDValue Tmp3 = DAG.getNode(ISD::ADD, dl, IntTy, Tmp2, Rup);
2951
2952 SDValue Eq = DAG.getSetCC(dl, PredTy, Tmp1, Tmp2, ISD::SETEQ);
2953 SDValue One = DAG.getConstant(1, dl, IntTy);
2954 SDValue Tmp4 = DAG.getNode(ShRight, dl, IntTy, {Tmp2, One});
2955 SDValue Tmp5 = DAG.getNode(ShRight, dl, IntTy, {Tmp3, One});
2956 SDValue Mux = DAG.getNode(ISD::VSELECT, dl, IntTy, {Eq, Tmp5, Tmp4});
2957 return {Mux, Ovf};
2958}
2959
2960SDValue
2961HexagonTargetLowering::emitHvxMulHsV60(SDValue A, SDValue B, const SDLoc &dl,
2962 SelectionDAG &DAG) const {
2963 MVT VecTy = ty(A);
2964 MVT PairTy = typeJoin({VecTy, VecTy});
2965 assert(VecTy.getVectorElementType() == MVT::i32);
2966
2967 SDValue S16 = DAG.getConstant(16, dl, MVT::i32);
2968
2969 // mulhs(A,B) =
2970 // = [(Hi(A)*2^16 + Lo(A)) *s (Hi(B)*2^16 + Lo(B))] >> 32
2971 // = [Hi(A)*2^16 *s Hi(B)*2^16 + Hi(A) *su Lo(B)*2^16
2972 // + Lo(A) *us (Hi(B)*2^16 + Lo(B))] >> 32
2973 // = [Hi(A) *s Hi(B)*2^32 + Hi(A) *su Lo(B)*2^16 + Lo(A) *us B] >> 32
2974 // The low half of Lo(A)*Lo(B) will be discarded (it's not added to
2975 // anything, so it cannot produce any carry over to higher bits),
2976 // so everything in [] can be shifted by 16 without loss of precision.
2977 // = [Hi(A) *s Hi(B)*2^16 + Hi(A)*su Lo(B) + Lo(A)*B >> 16] >> 16
2978 // = [Hi(A) *s Hi(B)*2^16 + Hi(A)*su Lo(B) + V6_vmpyewuh(A,B)] >> 16
2979 // The final additions need to make sure to properly maintain any carry-
2980 // out bits.
2981 //
2982 // Hi(B) Lo(B)
2983 // Hi(A) Lo(A)
2984 // --------------
2985 // Lo(B)*Lo(A) | T0 = V6_vmpyewuh(B,A) does this,
2986 // Hi(B)*Lo(A) | + dropping the low 16 bits
2987 // Hi(A)*Lo(B) | T2
2988 // Hi(B)*Hi(A)
2989
2990 SDValue T0 = getInstr(Hexagon::V6_vmpyewuh, dl, VecTy, {B, A}, DAG);
2991 // T1 = get Hi(A) into low halves.
2992 SDValue T1 = getInstr(Hexagon::V6_vasrw, dl, VecTy, {A, S16}, DAG);
2993 // P0 = interleaved T1.h*B.uh (full precision product)
2994 SDValue P0 = getInstr(Hexagon::V6_vmpyhus, dl, PairTy, {T1, B}, DAG);
2995 // T2 = T1.even(h) * B.even(uh), i.e. Hi(A)*Lo(B)
2996 SDValue T2 = LoHalf(P0, DAG);
2997 // We need to add T0+T2, recording the carry-out, which will be 1<<16
2998 // added to the final sum.
2999 // P1 = interleaved even/odd 32-bit (unsigned) sums of 16-bit halves
3000 SDValue P1 = getInstr(Hexagon::V6_vadduhw, dl, PairTy, {T0, T2}, DAG);
3001 // P2 = interleaved even/odd 32-bit (signed) sums of 16-bit halves
3002 SDValue P2 = getInstr(Hexagon::V6_vaddhw, dl, PairTy, {T0, T2}, DAG);
3003 // T3 = full-precision(T0+T2) >> 16
3004 // The low halves are added-unsigned, the high ones are added-signed.
3005 SDValue T3 = getInstr(Hexagon::V6_vasrw_acc, dl, VecTy,
3006 {HiHalf(P2, DAG), LoHalf(P1, DAG), S16}, DAG);
3007 SDValue T4 = getInstr(Hexagon::V6_vasrw, dl, VecTy, {B, S16}, DAG);
3008 // P3 = interleaved Hi(B)*Hi(A) (full precision),
3009 // which is now Lo(T1)*Lo(T4), so we want to keep the even product.
3010 SDValue P3 = getInstr(Hexagon::V6_vmpyhv, dl, PairTy, {T1, T4}, DAG);
3011 SDValue T5 = LoHalf(P3, DAG);
3012 // Add:
3013 SDValue T6 = DAG.getNode(ISD::ADD, dl, VecTy, {T3, T5});
3014 return T6;
3015}
3016
3017SDValue
3018HexagonTargetLowering::emitHvxMulLoHiV60(SDValue A, bool SignedA, SDValue B,
3019 bool SignedB, const SDLoc &dl,
3020 SelectionDAG &DAG) const {
3021 MVT VecTy = ty(A);
3022 MVT PairTy = typeJoin({VecTy, VecTy});
3023 assert(VecTy.getVectorElementType() == MVT::i32);
3024
3025 SDValue S16 = DAG.getConstant(16, dl, MVT::i32);
3026
3027 if (SignedA && !SignedB) {
3028 // Make A:unsigned, B:signed.
3029 std::swap(A, B);
3030 std::swap(SignedA, SignedB);
3031 }
3032
3033 // Do halfword-wise multiplications for unsigned*unsigned product, then
3034 // add corrections for signed and unsigned*signed.
3035
3036 SDValue Lo, Hi;
3037
3038 // P0:lo = (uu) products of low halves of A and B,
3039 // P0:hi = (uu) products of high halves.
3040 SDValue P0 = getInstr(Hexagon::V6_vmpyuhv, dl, PairTy, {A, B}, DAG);
3041
3042 // Swap low/high halves in B
3043 SDValue T0 = getInstr(Hexagon::V6_lvsplatw, dl, VecTy,
3044 {DAG.getConstant(0x02020202, dl, MVT::i32)}, DAG);
3045 SDValue T1 = getInstr(Hexagon::V6_vdelta, dl, VecTy, {B, T0}, DAG);
3046 // P1 = products of even/odd halfwords.
3047 // P1:lo = (uu) products of even(A.uh) * odd(B.uh)
3048 // P1:hi = (uu) products of odd(A.uh) * even(B.uh)
3049 SDValue P1 = getInstr(Hexagon::V6_vmpyuhv, dl, PairTy, {A, T1}, DAG);
3050
3051 // P2:lo = low halves of P1:lo + P1:hi,
3052 // P2:hi = high halves of P1:lo + P1:hi.
3053 SDValue P2 = getInstr(Hexagon::V6_vadduhw, dl, PairTy,
3054 {HiHalf(P1, DAG), LoHalf(P1, DAG)}, DAG);
3055 // Still need to add the high halves of P0:lo to P2:lo
3056 SDValue T2 =
3057 getInstr(Hexagon::V6_vlsrw, dl, VecTy, {LoHalf(P0, DAG), S16}, DAG);
3058 SDValue T3 = DAG.getNode(ISD::ADD, dl, VecTy, {LoHalf(P2, DAG), T2});
3059
3060 // The high halves of T3 will contribute to the HI part of LOHI.
3061 SDValue T4 = getInstr(Hexagon::V6_vasrw_acc, dl, VecTy,
3062 {HiHalf(P2, DAG), T3, S16}, DAG);
3063
3064 // The low halves of P2 need to be added to high halves of the LO part.
3065 Lo = getInstr(Hexagon::V6_vaslw_acc, dl, VecTy,
3066 {LoHalf(P0, DAG), LoHalf(P2, DAG), S16}, DAG);
3067 Hi = DAG.getNode(ISD::ADD, dl, VecTy, {HiHalf(P0, DAG), T4});
3068
3069 if (SignedA) {
3070 assert(SignedB && "Signed A and unsigned B should have been inverted");
3071
3072 MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
3073 SDValue Zero = getZero(dl, VecTy, DAG);
3074 SDValue Q0 = DAG.getSetCC(dl, PredTy, A, Zero, ISD::SETLT);
3075 SDValue Q1 = DAG.getSetCC(dl, PredTy, B, Zero, ISD::SETLT);
3076 SDValue X0 = DAG.getNode(ISD::VSELECT, dl, VecTy, {Q0, B, Zero});
3077 SDValue X1 = getInstr(Hexagon::V6_vaddwq, dl, VecTy, {Q1, X0, A}, DAG);
3078 Hi = getInstr(Hexagon::V6_vsubw, dl, VecTy, {Hi, X1}, DAG);
3079 } else if (SignedB) {
3080 // Same correction as for mulhus:
3081 // mulhus(A.uw,B.w) = mulhu(A.uw,B.uw) - (A.w if B < 0)
3082 MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
3083 SDValue Zero = getZero(dl, VecTy, DAG);
3084 SDValue Q1 = DAG.getSetCC(dl, PredTy, B, Zero, ISD::SETLT);
3085 Hi = getInstr(Hexagon::V6_vsubwq, dl, VecTy, {Q1, Hi, A}, DAG);
3086 } else {
3087 assert(!SignedA && !SignedB);
3088 }
3089
3090 return DAG.getMergeValues({Lo, Hi}, dl);
3091}
3092
3093SDValue
3094HexagonTargetLowering::emitHvxMulLoHiV62(SDValue A, bool SignedA,
3095 SDValue B, bool SignedB,
3096 const SDLoc &dl,
3097 SelectionDAG &DAG) const {
3098 MVT VecTy = ty(A);
3099 MVT PairTy = typeJoin({VecTy, VecTy});
3100 assert(VecTy.getVectorElementType() == MVT::i32);
3101
3102 if (SignedA && !SignedB) {
3103 // Make A:unsigned, B:signed.
3104 std::swap(A, B);
3105 std::swap(SignedA, SignedB);
3106 }
3107
3108 // Do S*S first, then make corrections for U*S or U*U if needed.
3109 SDValue P0 = getInstr(Hexagon::V6_vmpyewuh_64, dl, PairTy, {A, B}, DAG);
3110 SDValue P1 =
3111 getInstr(Hexagon::V6_vmpyowh_64_acc, dl, PairTy, {P0, A, B}, DAG);
3112 SDValue Lo = LoHalf(P1, DAG);
3113 SDValue Hi = HiHalf(P1, DAG);
3114
3115 if (!SignedB) {
3116 assert(!SignedA && "Signed A and unsigned B should have been inverted");
3117 SDValue Zero = getZero(dl, VecTy, DAG);
3118 MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
3119
3120 // Mulhu(X, Y) = Mulhs(X, Y) + (X, if Y < 0) + (Y, if X < 0).
3121 // def: Pat<(VecI32 (mulhu HVI32:$A, HVI32:$B)),
3122 // (V6_vaddw (HiHalf (Muls64O $A, $B)),
3123 // (V6_vaddwq (V6_vgtw (V6_vd0), $B),
3124 // (V6_vandvqv (V6_vgtw (V6_vd0), $A), $B),
3125 // $A))>;
3126 SDValue Q0 = DAG.getSetCC(dl, PredTy, A, Zero, ISD::SETLT);
3127 SDValue Q1 = DAG.getSetCC(dl, PredTy, B, Zero, ISD::SETLT);
3128 SDValue T0 = getInstr(Hexagon::V6_vandvqv, dl, VecTy, {Q0, B}, DAG);
3129 SDValue T1 = getInstr(Hexagon::V6_vaddwq, dl, VecTy, {Q1, T0, A}, DAG);
3130 Hi = getInstr(Hexagon::V6_vaddw, dl, VecTy, {Hi, T1}, DAG);
3131 } else if (!SignedA) {
3132 SDValue Zero = getZero(dl, VecTy, DAG);
3133 MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
3134
3135 // Mulhus(unsigned X, signed Y) = Mulhs(X, Y) + (Y, if X < 0).
3136 // def: Pat<(VecI32 (HexagonMULHUS HVI32:$A, HVI32:$B)),
3137 // (V6_vaddwq (V6_vgtw (V6_vd0), $A),
3138 // (HiHalf (Muls64O $A, $B)),
3139 // $B)>;
3140 SDValue Q0 = DAG.getSetCC(dl, PredTy, A, Zero, ISD::SETLT);
3141 Hi = getInstr(Hexagon::V6_vaddwq, dl, VecTy, {Q0, Hi, B}, DAG);
3142 }
3143
3144 return DAG.getMergeValues({Lo, Hi}, dl);
3145}
3146
3147SDValue
3148HexagonTargetLowering::EqualizeFpIntConversion(SDValue Op, SelectionDAG &DAG)
3149 const {
3150 // Rewrite conversion between integer and floating-point in such a way that
3151 // the integer type is extended/narrowed to match the bitwidth of the
3152 // floating-point type, combined with additional integer-integer extensions
3153 // or narrowings to match the original input/result types.
3154 // E.g. f32 -> i8 ==> f32 -> i32 -> i8
3155 //
3156 // The input/result types are not required to be legal, but if they are
3157 // legal, this function should not introduce illegal types.
3158
3159 unsigned Opc = Op.getOpcode();
3162
3163 SDValue Inp = Op.getOperand(0);
3164 MVT InpTy = ty(Inp);
3165 MVT ResTy = ty(Op);
3166
3167 if (InpTy == ResTy)
3168 return Op;
3169
3170 const SDLoc &dl(Op);
3172
3173 auto [WInpTy, WResTy] = typeExtendToWider(InpTy, ResTy);
3174 SDValue WInp = resizeToWidth(Inp, WInpTy, Signed, dl, DAG);
3175 SDValue Conv = DAG.getNode(Opc, dl, WResTy, WInp);
3176 SDValue Res = resizeToWidth(Conv, ResTy, Signed, dl, DAG);
3177 return Res;
3178}
3179
3180SDValue
3181HexagonTargetLowering::ExpandHvxFpToInt(SDValue Op, SelectionDAG &DAG) const {
3182 unsigned Opc = Op.getOpcode();
3184
3185 const SDLoc &dl(Op);
3186 SDValue Op0 = Op.getOperand(0);
3187 MVT InpTy = ty(Op0);
3188 MVT ResTy = ty(Op);
3189 assert(InpTy.changeTypeToInteger() == ResTy);
3190
3191 // At this point this is an experiment under a flag.
3192 // In arch before V81 the rounding mode is towards nearest value.
3193 // The C/C++ standard requires rounding towards zero:
3194 // C (C99 and later): ISO/IEC 9899:2018 (C18), section 6.3.1.4 — "When a
3195 // finite value of real floating type is converted to an integer type, the
3196 // fractional part is discarded (i.e., the value is truncated toward zero)."
3197 // C++: ISO/IEC 14882:2020 (C++20), section 7.3.7 — "A prvalue of a
3198 // floating-point type can be converted to a prvalue of an integer type. The
3199 // conversion truncates; that is, the fractional part is discarded."
3200 if (InpTy == MVT::v64f16) {
3201 if (Subtarget.useHVXV81Ops()) {
3202 // This is c/c++ compliant
3203 SDValue ConvVec =
3204 getInstr(Hexagon::V6_vconv_h_hf_rnd, dl, ResTy, {Op0}, DAG);
3205 return ConvVec;
3206 } else if (EnableFpFastConvert) {
3207 // Vd32.h=Vu32.hf same as Q6_Vh_equals_Vhf
3208 SDValue ConvVec = getInstr(Hexagon::V6_vconv_h_hf, dl, ResTy, {Op0}, DAG);
3209 return ConvVec;
3210 }
3211 } else if (EnableFpFastConvert && InpTy == MVT::v32f32) {
3212 // Vd32.w=Vu32.sf same as Q6_Vw_equals_Vsf
3213 SDValue ConvVec = getInstr(Hexagon::V6_vconv_w_sf, dl, ResTy, {Op0}, DAG);
3214 return ConvVec;
3215 }
3216
3217 // int32_t conv_f32_to_i32(uint32_t inp) {
3218 // // s | exp8 | frac23
3219 //
3220 // int neg = (int32_t)inp < 0;
3221 //
3222 // // "expm1" is the actual exponent minus 1: instead of "bias", subtract
3223 // // "bias+1". When the encoded exp is "all-1" (i.e. inf/nan), this will
3224 // // produce a large positive "expm1", which will result in max u/int.
3225 // // In all IEEE formats, bias is the largest positive number that can be
3226 // // represented in bias-width bits (i.e. 011..1).
3227 // int32_t expm1 = (inp << 1) - 0x80000000;
3228 // expm1 >>= 24;
3229 //
3230 // // Always insert the "implicit 1". Subnormal numbers will become 0
3231 // // regardless.
3232 // uint32_t frac = (inp << 8) | 0x80000000;
3233 //
3234 // // "frac" is the fraction part represented as Q1.31. If it was
3235 // // interpreted as uint32_t, it would be the fraction part multiplied
3236 // // by 2^31.
3237 //
3238 // // Calculate the amount of right shift, since shifting further to the
3239 // // left would lose significant bits. Limit it to 32, because we want
3240 // // shifts by 32+ to produce 0, whereas V6_vlsrwv treats the shift
3241 // // amount as a 6-bit signed value (so 33 is same as -31, i.e. shift
3242 // // left by 31). "rsh" can be negative.
3243 // int32_t rsh = min(31 - (expm1 + 1), 32);
3244 //
3245 // frac >>= rsh; // rsh == 32 will produce 0
3246 //
3247 // // Everything up to this point is the same for conversion to signed
3248 // // unsigned integer.
3249 //
3250 // if (neg) // Only for signed int
3251 // frac = -frac; //
3252 // if (rsh <= 0 && neg) // bound = neg ? 0x80000000 : 0x7fffffff
3253 // frac = 0x80000000; // frac = rsh <= 0 ? bound : frac
3254 // if (rsh <= 0 && !neg) //
3255 // frac = 0x7fffffff; //
3256 //
3257 // if (neg) // Only for unsigned int
3258 // frac = 0; //
3259 // if (rsh < 0 && !neg) // frac = rsh < 0 ? 0x7fffffff : frac;
3260 // frac = 0x7fffffff; // frac = neg ? 0 : frac;
3261 //
3262 // return frac;
3263 // }
3264
3265 MVT PredTy = MVT::getVectorVT(MVT::i1, ResTy.getVectorElementCount());
3266
3267 // Zero = V6_vd0();
3268 // Neg = V6_vgtw(Zero, Inp);
3269 // One = V6_lvsplatw(1);
3270 // M80 = V6_lvsplatw(0x80000000);
3271 // Exp00 = V6_vaslwv(Inp, One);
3272 // Exp01 = V6_vsubw(Exp00, M80);
3273 // ExpM1 = V6_vasrw(Exp01, 24);
3274 // Frc00 = V6_vaslw(Inp, 8);
3275 // Frc01 = V6_vor(Frc00, M80);
3276 // Rsh00 = V6_vsubw(V6_lvsplatw(30), ExpM1);
3277 // Rsh01 = V6_vminw(Rsh00, V6_lvsplatw(32));
3278 // Frc02 = V6_vlsrwv(Frc01, Rsh01);
3279
3280 // if signed int:
3281 // Bnd = V6_vmux(Neg, M80, V6_lvsplatw(0x7fffffff))
3282 // Pos = V6_vgtw(Rsh01, Zero);
3283 // Frc13 = V6_vsubw(Zero, Frc02);
3284 // Frc14 = V6_vmux(Neg, Frc13, Frc02);
3285 // Int = V6_vmux(Pos, Frc14, Bnd);
3286 //
3287 // if unsigned int:
3288 // Rsn = V6_vgtw(Zero, Rsh01)
3289 // Frc23 = V6_vmux(Rsn, V6_lvsplatw(0x7fffffff), Frc02)
3290 // Int = V6_vmux(Neg, Zero, Frc23)
3291
3292 auto [ExpWidth, ExpBias, FracWidth] = getIEEEProperties(InpTy);
3293 unsigned ElemWidth = 1 + ExpWidth + FracWidth;
3294 assert((1ull << (ExpWidth - 1)) == (1 + ExpBias));
3295
3296 SDValue Inp = DAG.getBitcast(ResTy, Op0);
3297 SDValue Zero = getZero(dl, ResTy, DAG);
3298 SDValue Neg = DAG.getSetCC(dl, PredTy, Inp, Zero, ISD::SETLT);
3299 SDValue M80 = DAG.getConstant(1ull << (ElemWidth - 1), dl, ResTy);
3300 SDValue M7F = DAG.getConstant((1ull << (ElemWidth - 1)) - 1, dl, ResTy);
3301 SDValue One = DAG.getConstant(1, dl, ResTy);
3302 SDValue Exp00 = DAG.getNode(ISD::SHL, dl, ResTy, {Inp, One});
3303 SDValue Exp01 = DAG.getNode(ISD::SUB, dl, ResTy, {Exp00, M80});
3304 SDValue MNE = DAG.getConstant(ElemWidth - ExpWidth, dl, ResTy);
3305 SDValue ExpM1 = DAG.getNode(ISD::SRA, dl, ResTy, {Exp01, MNE});
3306
3307 SDValue ExpW = DAG.getConstant(ExpWidth, dl, ResTy);
3308 SDValue Frc00 = DAG.getNode(ISD::SHL, dl, ResTy, {Inp, ExpW});
3309 SDValue Frc01 = DAG.getNode(ISD::OR, dl, ResTy, {Frc00, M80});
3310
3311 SDValue MN2 = DAG.getConstant(ElemWidth - 2, dl, ResTy);
3312 SDValue Rsh00 = DAG.getNode(ISD::SUB, dl, ResTy, {MN2, ExpM1});
3313 SDValue MW = DAG.getConstant(ElemWidth, dl, ResTy);
3314 SDValue Rsh01 = DAG.getNode(ISD::SMIN, dl, ResTy, {Rsh00, MW});
3315 SDValue Frc02 = DAG.getNode(ISD::SRL, dl, ResTy, {Frc01, Rsh01});
3316
3317 SDValue Int;
3318
3319 if (Opc == ISD::FP_TO_SINT) {
3320 SDValue Bnd = DAG.getNode(ISD::VSELECT, dl, ResTy, {Neg, M80, M7F});
3321 SDValue Pos = DAG.getSetCC(dl, PredTy, Rsh01, Zero, ISD::SETGT);
3322 SDValue Frc13 = DAG.getNode(ISD::SUB, dl, ResTy, {Zero, Frc02});
3323 SDValue Frc14 = DAG.getNode(ISD::VSELECT, dl, ResTy, {Neg, Frc13, Frc02});
3324 Int = DAG.getNode(ISD::VSELECT, dl, ResTy, {Pos, Frc14, Bnd});
3325 } else {
3327 SDValue Rsn = DAG.getSetCC(dl, PredTy, Rsh01, Zero, ISD::SETLT);
3328 SDValue Frc23 = DAG.getNode(ISD::VSELECT, dl, ResTy, Rsn, M7F, Frc02);
3329 Int = DAG.getNode(ISD::VSELECT, dl, ResTy, Neg, Zero, Frc23);
3330 }
3331
3332 return Int;
3333}
3334
3335SDValue
3336HexagonTargetLowering::ExpandHvxIntToFp(SDValue Op, SelectionDAG &DAG) const {
3337 unsigned Opc = Op.getOpcode();
3339
3340 const SDLoc &dl(Op);
3341 SDValue Op0 = Op.getOperand(0);
3342 MVT InpTy = ty(Op0);
3343 MVT ResTy = ty(Op);
3344 assert(ResTy.changeTypeToInteger() == InpTy);
3345
3346 // uint32_t vnoc1_rnd(int32_t w) {
3347 // int32_t iszero = w == 0;
3348 // int32_t isneg = w < 0;
3349 // uint32_t u = __builtin_HEXAGON_A2_abs(w);
3350 //
3351 // uint32_t norm_left = __builtin_HEXAGON_S2_cl0(u) + 1;
3352 // uint32_t frac0 = (uint64_t)u << norm_left;
3353 //
3354 // // Rounding:
3355 // uint32_t frac1 = frac0 + ((1 << 8) - 1);
3356 // uint32_t renorm = (frac0 > frac1);
3357 // uint32_t rup = (int)(frac0 << 22) < 0;
3358 //
3359 // uint32_t frac2 = frac0 >> 8;
3360 // uint32_t frac3 = frac1 >> 8;
3361 // uint32_t frac = (frac2 != frac3) ? frac3 >> 1 : (frac3 + rup) >> 1;
3362 //
3363 // int32_t exp = 32 - norm_left + renorm + 127;
3364 // exp <<= 23;
3365 //
3366 // uint32_t sign = 0x80000000 * isneg;
3367 // uint32_t f = sign | exp | frac;
3368 // return iszero ? 0 : f;
3369 // }
3370
3371 MVT PredTy = MVT::getVectorVT(MVT::i1, InpTy.getVectorElementCount());
3372 bool Signed = Opc == ISD::SINT_TO_FP;
3373
3374 auto [ExpWidth, ExpBias, FracWidth] = getIEEEProperties(ResTy);
3375 unsigned ElemWidth = 1 + ExpWidth + FracWidth;
3376
3377 SDValue Zero = getZero(dl, InpTy, DAG);
3378 SDValue One = DAG.getConstant(1, dl, InpTy);
3379 SDValue IsZero = DAG.getSetCC(dl, PredTy, Op0, Zero, ISD::SETEQ);
3380 SDValue Abs = Signed ? DAG.getNode(ISD::ABS, dl, InpTy, Op0) : Op0;
3381 SDValue Clz = DAG.getNode(ISD::CTLZ, dl, InpTy, Abs);
3382 SDValue NLeft = DAG.getNode(ISD::ADD, dl, InpTy, {Clz, One});
3383 SDValue Frac0 = DAG.getNode(ISD::SHL, dl, InpTy, {Abs, NLeft});
3384
3385 auto [Frac, Ovf] = emitHvxShiftRightRnd(Frac0, ExpWidth + 1, false, DAG);
3386 if (Signed) {
3387 SDValue IsNeg = DAG.getSetCC(dl, PredTy, Op0, Zero, ISD::SETLT);
3388 SDValue M80 = DAG.getConstant(1ull << (ElemWidth - 1), dl, InpTy);
3389 SDValue Sign = DAG.getNode(ISD::VSELECT, dl, InpTy, {IsNeg, M80, Zero});
3390 Frac = DAG.getNode(ISD::OR, dl, InpTy, {Sign, Frac});
3391 }
3392
3393 SDValue Rnrm = DAG.getZExtOrTrunc(Ovf, dl, InpTy);
3394 SDValue Exp0 = DAG.getConstant(ElemWidth + ExpBias, dl, InpTy);
3395 SDValue Exp1 = DAG.getNode(ISD::ADD, dl, InpTy, {Rnrm, Exp0});
3396 SDValue Exp2 = DAG.getNode(ISD::SUB, dl, InpTy, {Exp1, NLeft});
3397 SDValue Exp3 = DAG.getNode(ISD::SHL, dl, InpTy,
3398 {Exp2, DAG.getConstant(FracWidth, dl, InpTy)});
3399 SDValue Flt0 = DAG.getNode(ISD::OR, dl, InpTy, {Frac, Exp3});
3400 SDValue Flt1 = DAG.getNode(ISD::VSELECT, dl, InpTy, {IsZero, Zero, Flt0});
3401 SDValue Flt = DAG.getBitcast(ResTy, Flt1);
3402
3403 return Flt;
3404}
3405
3406SDValue
3407HexagonTargetLowering::CreateTLWrapper(SDValue Op, SelectionDAG &DAG) const {
3408 unsigned Opc = Op.getOpcode();
3409 unsigned TLOpc;
3410 switch (Opc) {
3411 case ISD::ANY_EXTEND:
3412 case ISD::SIGN_EXTEND:
3413 case ISD::ZERO_EXTEND:
3414 TLOpc = HexagonISD::TL_EXTEND;
3415 break;
3416 case ISD::TRUNCATE:
3418 break;
3419#ifndef NDEBUG
3420 Op.dump(&DAG);
3421#endif
3422 llvm_unreachable("Unexpected operator");
3423 }
3424
3425 const SDLoc &dl(Op);
3426 return DAG.getNode(TLOpc, dl, ty(Op), Op.getOperand(0),
3427 DAG.getUNDEF(MVT::i128), // illegal type
3428 DAG.getConstant(Opc, dl, MVT::i32));
3429}
3430
3431SDValue
3432HexagonTargetLowering::RemoveTLWrapper(SDValue Op, SelectionDAG &DAG) const {
3433 assert(Op.getOpcode() == HexagonISD::TL_EXTEND ||
3434 Op.getOpcode() == HexagonISD::TL_TRUNCATE);
3435 unsigned Opc = Op.getConstantOperandVal(2);
3436 return DAG.getNode(Opc, SDLoc(Op), ty(Op), Op.getOperand(0));
3437}
3438
3439HexagonTargetLowering::VectorPair
3440HexagonTargetLowering::SplitVectorOp(SDValue Op, SelectionDAG &DAG) const {
3441 assert(!Op.isMachineOpcode());
3442 SmallVector<SDValue, 2> OpsL, OpsH;
3443 const SDLoc &dl(Op);
3444
3445 auto SplitVTNode = [&DAG, this](const VTSDNode *N) {
3446 MVT Ty = typeSplit(N->getVT().getSimpleVT()).first;
3447 SDValue TV = DAG.getValueType(Ty);
3448 return std::make_pair(TV, TV);
3449 };
3450
3451 for (SDValue A : Op.getNode()->ops()) {
3452 auto [Lo, Hi] =
3453 ty(A).isVector() ? opSplit(A, dl, DAG) : std::make_pair(A, A);
3454 // Special case for type operand.
3455 switch (Op.getOpcode()) {
3456 case ISD::SIGN_EXTEND_INREG:
3457 case HexagonISD::SSAT:
3458 case HexagonISD::USAT:
3459 if (const auto *N = dyn_cast<const VTSDNode>(A.getNode()))
3460 std::tie(Lo, Hi) = SplitVTNode(N);
3461 break;
3462 }
3463 OpsL.push_back(Lo);
3464 OpsH.push_back(Hi);
3465 }
3466
3467 MVT ResTy = ty(Op);
3468 MVT HalfTy = typeSplit(ResTy).first;
3469 SDValue L = DAG.getNode(Op.getOpcode(), dl, HalfTy, OpsL);
3470 SDValue H = DAG.getNode(Op.getOpcode(), dl, HalfTy, OpsH);
3471 return {L, H};
3472}
3473
3474SDValue
3475HexagonTargetLowering::SplitHvxMemOp(SDValue Op, SelectionDAG &DAG) const {
3476 auto *MemN = cast<MemSDNode>(Op.getNode());
3477 unsigned MemOpc = MemN->getOpcode();
3478 EVT MemTy = MemN->getMemoryVT();
3479
3480 if ((MemOpc == ISD::STORE || MemOpc == ISD::LOAD) &&
3481 (!MemTy.isSimple() || !isHvxPairTy(MemTy.getSimpleVT())))
3482 return Op;
3483
3484 EVT ValueType;
3485 if (MemOpc == ISD::STORE)
3487 else if (MemOpc == ISD::MSTORE)
3489 else // ISD::LOAD, ISD::MLOAD.
3490 ValueType = MemN->getValueType(0);
3491
3492 EVT LoVT, HiVT;
3493 std::tie(LoVT, HiVT) = DAG.GetSplitDestVTs(ValueType);
3494
3495 EVT LoMemVT, HiMemVT;
3496 bool HiIsEmpty = false;
3497 std::tie(LoMemVT, HiMemVT) =
3498 DAG.GetDependentSplitDestVTs(MemTy, LoVT, &HiIsEmpty);
3499
3500 uint64_t LoSize = LoMemVT.getSizeInBits().getFixedValue() / 8;
3501 uint64_t HiSize = HiMemVT.getSizeInBits().getFixedValue() / 8;
3502
3503 const SDLoc &dl(Op);
3504 SDValue Chain = MemN->getChain();
3505 SDValue Base0 = MemN->getBasePtr();
3506 SDValue Base1 =
3507 DAG.getMemBasePlusOffset(Base0, TypeSize::getFixed(LoSize), dl);
3508
3509 MachineMemOperand *MOp0 = nullptr, *MOp1 = nullptr;
3510 if (MachineMemOperand *MMO = MemN->getMemOperand()) {
3511 MachineFunction &MF = DAG.getMachineFunction();
3512 auto MemSize = [=](uint64_t Size) {
3513 return (MemOpc == ISD::MLOAD || MemOpc == ISD::MSTORE)
3514 ? (uint64_t)MemoryLocation::UnknownSize
3515 : Size;
3516 };
3517 // MOp1 will not be used if HiIsEmpty for masked loads and stores (MLOAD and
3518 // MSTORE). Non-masked loads and store are always of double-vector size (see
3519 // isHvxPairTy() check above).
3520 MOp0 = MF.getMachineMemOperand(MMO, 0, MemSize(LoSize));
3521 MOp1 = MF.getMachineMemOperand(MMO, LoSize, MemSize(HiSize));
3522 }
3523
3524 if (MemOpc == ISD::LOAD) {
3525 assert(cast<LoadSDNode>(Op)->isUnindexed());
3526 SDValue Load0 = DAG.getLoad(LoVT, dl, Chain, Base0, MOp0);
3527 SDValue Load1 = DAG.getLoad(HiVT, dl, Chain, Base1, MOp1);
3528 return DAG.getMergeValues(
3529 {DAG.getNode(ISD::CONCAT_VECTORS, dl, MemN->getValueType(0), Load0,
3530 Load1),
3531 DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Load0.getValue(1),
3532 Load1.getValue(1))},
3533 dl);
3534 }
3535 if (MemOpc == ISD::STORE) {
3536 assert(cast<StoreSDNode>(Op)->isUnindexed());
3537 VectorPair Vals = opSplit(cast<StoreSDNode>(Op)->getValue(), dl, DAG);
3538 SDValue Store0 = DAG.getStore(Chain, dl, Vals.first, Base0, MOp0);
3539 SDValue Store1 = DAG.getStore(Chain, dl, Vals.second, Base1, MOp1);
3540 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Store0, Store1);
3541 }
3542
3543 assert(MemOpc == ISD::MLOAD || MemOpc == ISD::MSTORE);
3544
3545 auto MaskN = cast<MaskedLoadStoreSDNode>(Op);
3546 assert(MaskN->isUnindexed());
3547 VectorPair Masks = opSplit(MaskN->getMask(), dl, DAG);
3548 SDValue Offset = DAG.getUNDEF(MVT::i32);
3549
3550 if (MemOpc == ISD::MLOAD) {
3551 VectorPair Thru =
3552 opSplit(cast<MaskedLoadSDNode>(Op)->getPassThru(), dl, DAG);
3553 SDValue MLoad0 = DAG.getMaskedLoad(LoVT, dl, Chain, Base0, Offset,
3554 Masks.first, Thru.first, LoMemVT, MOp0,
3556
3557 // The hi masked load has zero storage size. We therefore simply set it to
3558 // the low masked load and rely on subsequent removal from the chain as it
3559 // is unused. See DAGTypeLegalizer::SplitVecRes_MLOAD() for the same logic.
3560 SDValue MLoad1 =
3561 HiIsEmpty ? MLoad0
3562 : DAG.getMaskedLoad(HiVT, dl, Chain, Base1, Offset,
3563 Masks.second, Thru.second, HiMemVT, MOp1,
3565 return DAG.getMergeValues(
3566 {DAG.getNode(ISD::CONCAT_VECTORS, dl, MemN->getValueType(0), MLoad0,
3567 MLoad1),
3568 DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MLoad0.getValue(1),
3569 MLoad1.getValue(1))},
3570 dl);
3571 }
3572 if (MemOpc == ISD::MSTORE) {
3573 VectorPair Vals = opSplit(cast<MaskedStoreSDNode>(Op)->getValue(), dl, DAG);
3574 SDValue MStore0 =
3575 DAG.getMaskedStore(Chain, dl, Vals.first, Base0, Offset, Masks.first,
3576 LoMemVT, MOp0, ISD::UNINDEXED, false, false);
3577 if (HiIsEmpty)
3578 return MStore0;
3579 SDValue MStore1 =
3580 DAG.getMaskedStore(Chain, dl, Vals.second, Base1, Offset, Masks.second,
3581 HiMemVT, MOp1, ISD::UNINDEXED, false, false);
3582 return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MStore0, MStore1);
3583 }
3584
3585 std::string Name = "Unexpected operation: " + Op->getOperationName(&DAG);
3586 llvm_unreachable(Name.c_str());
3587}
3588
3589SDValue
3590HexagonTargetLowering::WidenHvxLoad(SDValue Op, SelectionDAG &DAG) const {
3591 const SDLoc &dl(Op);
3592 auto *LoadN = cast<LoadSDNode>(Op.getNode());
3593 assert(LoadN->isUnindexed() && "Not widening indexed loads yet");
3594 assert(LoadN->getMemoryVT().getVectorElementType() != MVT::i1 &&
3595 "Not widening loads of i1 yet");
3596
3597 SDValue Chain = LoadN->getChain();
3598 SDValue Base = LoadN->getBasePtr();
3599 SDValue Offset = DAG.getUNDEF(MVT::i32);
3600
3601 MVT ResTy = ty(Op);
3602 unsigned HwLen = Subtarget.getVectorLength();
3603 unsigned ResLen = ResTy.getStoreSize();
3604 assert(ResLen < HwLen && "vsetq(v1) prerequisite");
3605
3606 MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
3607 SDValue Mask = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
3608 {DAG.getConstant(ResLen, dl, MVT::i32)}, DAG);
3609
3610 MVT LoadTy = MVT::getVectorVT(MVT::i8, HwLen);
3611 MachineFunction &MF = DAG.getMachineFunction();
3612 auto *MemOp = MF.getMachineMemOperand(LoadN->getMemOperand(), 0, HwLen);
3613
3614 SDValue Load = DAG.getMaskedLoad(LoadTy, dl, Chain, Base, Offset, Mask,
3615 DAG.getUNDEF(LoadTy), LoadTy, MemOp,
3617 SDValue Value = opCastElem(Load, ResTy.getVectorElementType(), DAG);
3618 return DAG.getMergeValues({Value, Load.getValue(1)}, dl);
3619}
3620
3621SDValue
3622HexagonTargetLowering::WidenHvxStore(SDValue Op, SelectionDAG &DAG) const {
3623 const SDLoc &dl(Op);
3624 auto *StoreN = cast<StoreSDNode>(Op.getNode());
3625 assert(StoreN->isUnindexed() && "Not widening indexed stores yet");
3626 assert(StoreN->getMemoryVT().getVectorElementType() != MVT::i1 &&
3627 "Not widening stores of i1 yet");
3628
3629 SDValue Chain = StoreN->getChain();
3630 SDValue Base = StoreN->getBasePtr();
3631 SDValue Offset = DAG.getUNDEF(MVT::i32);
3632
3633 SDValue Value = opCastElem(StoreN->getValue(), MVT::i8, DAG);
3634 MVT ValueTy = ty(Value);
3635 unsigned ValueLen = ValueTy.getVectorNumElements();
3636 unsigned HwLen = Subtarget.getVectorLength();
3637 assert(isPowerOf2_32(ValueLen));
3638
3639 for (unsigned Len = ValueLen; Len < HwLen; ) {
3640 Value = opJoin({Value, DAG.getUNDEF(ty(Value))}, dl, DAG);
3641 Len = ty(Value).getVectorNumElements(); // This is Len *= 2
3642 }
3643 assert(ty(Value).getVectorNumElements() == HwLen); // Paranoia
3644
3645 assert(ValueLen < HwLen && "vsetq(v1) prerequisite");
3646 MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
3647 SDValue Mask = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
3648 {DAG.getConstant(ValueLen, dl, MVT::i32)}, DAG);
3649 MachineFunction &MF = DAG.getMachineFunction();
3650 auto *MemOp = MF.getMachineMemOperand(StoreN->getMemOperand(), 0, HwLen);
3651 return DAG.getMaskedStore(Chain, dl, Value, Base, Offset, Mask, ty(Value),
3652 MemOp, ISD::UNINDEXED, false, false);
3653}
3654
3655SDValue
3656HexagonTargetLowering::WidenHvxSetCC(SDValue Op, SelectionDAG &DAG) const {
3657 const SDLoc &dl(Op);
3658 SDValue Op0 = Op.getOperand(0), Op1 = Op.getOperand(1);
3659 MVT ElemTy = ty(Op0).getVectorElementType();
3660 unsigned HwLen = Subtarget.getVectorLength();
3661
3662 unsigned WideOpLen = (8 * HwLen) / ElemTy.getSizeInBits();
3663 assert(WideOpLen * ElemTy.getSizeInBits() == 8 * HwLen);
3664 MVT WideOpTy = MVT::getVectorVT(ElemTy, WideOpLen);
3665 if (!Subtarget.isHVXVectorType(WideOpTy, true))
3666 return SDValue();
3667
3668 SDValue WideOp0 = appendUndef(Op0, WideOpTy, DAG);
3669 SDValue WideOp1 = appendUndef(Op1, WideOpTy, DAG);
3670 EVT ResTy =
3671 getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), WideOpTy);
3672 SDValue SetCC = DAG.getNode(ISD::SETCC, dl, ResTy,
3673 {WideOp0, WideOp1, Op.getOperand(2)});
3674
3675 EVT RetTy = typeLegalize(ty(Op), DAG);
3676 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, RetTy,
3677 {SetCC, getZero(dl, MVT::i32, DAG)});
3678}
3679
3680SDValue HexagonTargetLowering::WidenHvxTruncateToBool(SDValue Op,
3681 SelectionDAG &DAG) const {
3682 // Handle truncation to boolean vector where the result boolean type
3683 // needs widening (e.g., v16i32 -> v16i1 where v16i1 is not a standard
3684 // HVX predicate type, or v16i8 -> v16i1 in 128-byte mode).
3685 // Widen the input to HVX width, perform the truncate to the widened
3686 // boolean type, then extract the result.
3687 const SDLoc &dl(Op);
3688 SDValue Inp = Op.getOperand(0);
3689 MVT InpTy = ty(Inp);
3690 MVT ResTy = ty(Op);
3691
3692 assert(ResTy.getVectorElementType() == MVT::i1 &&
3693 "Expected boolean result type");
3694
3695 MVT ElemTy = InpTy.getVectorElementType();
3696 unsigned HwLen = Subtarget.getVectorLength();
3697
3698 // Calculate the widened input type that fills the HVX register.
3699 unsigned WideLen = (8 * HwLen) / ElemTy.getSizeInBits();
3700 MVT WideInpTy = MVT::getVectorVT(ElemTy, WideLen);
3701 if (!Subtarget.isHVXVectorType(WideInpTy, false))
3702 return SDValue();
3703
3704 // Widen the input to HVX width.
3705 SDValue WideInp = appendUndef(Inp, WideInpTy, DAG);
3706
3707 // Perform the truncate to widened boolean type.
3708 MVT WideBoolTy = MVT::getVectorVT(MVT::i1, WideLen);
3709 SDValue WideTrunc = DAG.getNode(ISD::TRUNCATE, dl, WideBoolTy, WideInp);
3710
3711 // Extract the result.
3712 EVT RetTy = typeLegalize(ResTy, DAG);
3713 return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, RetTy,
3714 {WideTrunc, getZero(dl, MVT::i32, DAG)});
3715}
3716
3717SDValue
3718HexagonTargetLowering::LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const {
3719 unsigned Opc = Op.getOpcode();
3720 bool IsPairOp = isHvxPairTy(ty(Op)) ||
3721 llvm::any_of(Op.getNode()->ops(), [this] (SDValue V) {
3722 return isHvxPairTy(ty(V));
3723 });
3724
3725 if (IsPairOp) {
3726 switch (Opc) {
3727 default:
3728 break;
3729 case ISD::LOAD:
3730 case ISD::STORE:
3731 case ISD::MLOAD:
3732 case ISD::MSTORE:
3733 return SplitHvxMemOp(Op, DAG);
3734 case ISD::SINT_TO_FP:
3735 case ISD::UINT_TO_FP:
3736 case ISD::FP_TO_SINT:
3737 case ISD::FP_TO_UINT:
3738 if (ty(Op).getSizeInBits() == ty(Op.getOperand(0)).getSizeInBits())
3739 return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
3740 break;
3741 case ISD::ABS:
3742 case ISD::CTPOP:
3743 case ISD::CTLZ:
3744 case ISD::CTTZ:
3745 case ISD::MUL:
3746 case ISD::FADD:
3747 case ISD::FSUB:
3748 case ISD::FMUL:
3749 case ISD::FMINIMUMNUM:
3750 case ISD::FMAXIMUMNUM:
3751 case ISD::FMINNUM:
3752 case ISD::FMAXNUM:
3753 case ISD::MULHS:
3754 case ISD::MULHU:
3755 case ISD::AND:
3756 case ISD::OR:
3757 case ISD::XOR:
3758 case ISD::SRA:
3759 case ISD::SHL:
3760 case ISD::SRL:
3761 case ISD::FSHL:
3762 case ISD::FSHR:
3763 case ISD::SMIN:
3764 case ISD::SMAX:
3765 case ISD::UMIN:
3766 case ISD::UMAX:
3767 case ISD::SETCC:
3768 case ISD::VSELECT:
3770 case ISD::SPLAT_VECTOR:
3771 return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
3772 case ISD::SIGN_EXTEND:
3773 case ISD::ZERO_EXTEND:
3774 // In general, sign- and zero-extends can't be split and still
3775 // be legal. The only exception is extending bool vectors.
3776 if (ty(Op.getOperand(0)).getVectorElementType() == MVT::i1)
3777 return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
3778 break;
3779 }
3780 }
3781
3782 switch (Opc) {
3783 default:
3784 break;
3785 // clang-format off
3786 case ISD::BUILD_VECTOR: return LowerHvxBuildVector(Op, DAG);
3787 case ISD::SPLAT_VECTOR: return LowerHvxSplatVector(Op, DAG);
3788 case ISD::CONCAT_VECTORS: return LowerHvxConcatVectors(Op, DAG);
3789 case ISD::INSERT_SUBVECTOR: return LowerHvxInsertSubvector(Op, DAG);
3790 case ISD::INSERT_VECTOR_ELT: return LowerHvxInsertElement(Op, DAG);
3791 case ISD::EXTRACT_SUBVECTOR: return LowerHvxExtractSubvector(Op, DAG);
3792 case ISD::EXTRACT_VECTOR_ELT: return LowerHvxExtractElement(Op, DAG);
3793 case ISD::BITCAST: return LowerHvxBitcast(Op, DAG);
3794 case ISD::ANY_EXTEND: return LowerHvxAnyExt(Op, DAG);
3795 case ISD::SIGN_EXTEND: return LowerHvxSignExt(Op, DAG);
3796 case ISD::ZERO_EXTEND: return LowerHvxZeroExt(Op, DAG);
3797 case ISD::CTTZ: return LowerHvxCttz(Op, DAG);
3798 case ISD::SELECT: return LowerHvxSelect(Op, DAG);
3799 case ISD::SRA:
3800 case ISD::SHL:
3801 case ISD::SRL: return LowerHvxShift(Op, DAG);
3802 case ISD::FSHL:
3803 case ISD::FSHR: return LowerHvxFunnelShift(Op, DAG);
3804 case ISD::MULHS:
3805 case ISD::MULHU: return LowerHvxMulh(Op, DAG);
3806 case ISD::SMUL_LOHI:
3807 case ISD::UMUL_LOHI: return LowerHvxMulLoHi(Op, DAG);
3808 case ISD::ANY_EXTEND_VECTOR_INREG: return LowerHvxExtend(Op, DAG);
3809 case ISD::SETCC:
3810 case ISD::INTRINSIC_VOID: return Op;
3811 case ISD::INTRINSIC_WO_CHAIN: return LowerHvxIntrinsic(Op, DAG);
3812 case ISD::MLOAD:
3813 case ISD::MSTORE: return LowerHvxMaskedOp(Op, DAG);
3814 // Unaligned loads will be handled by the default lowering.
3815 case ISD::LOAD: return LowerHvxLoad(Op, DAG);
3816 case ISD::STORE: return LowerHvxStore(Op, DAG);
3817 case ISD::FP_EXTEND: return LowerHvxFpExtend(Op, DAG);
3818 case ISD::FP_TO_SINT:
3819 case ISD::FP_TO_UINT: return LowerHvxFpToInt(Op, DAG);
3820 case ISD::SINT_TO_FP:
3821 case ISD::UINT_TO_FP: return LowerHvxIntToFp(Op, DAG);
3822
3823 // Special nodes:
3824 case HexagonISD::SMUL_LOHI:
3825 case HexagonISD::UMUL_LOHI:
3826 case HexagonISD::USMUL_LOHI: return LowerHvxMulLoHi(Op, DAG);
3827
3831 return LowerHvxPartialReduceMLA(Op, DAG);
3832 // clang-format on
3833 }
3834#ifndef NDEBUG
3835 Op.dumpr(&DAG);
3836#endif
3837 llvm_unreachable("Unhandled HVX operation");
3838}
3839
3840SDValue
3841HexagonTargetLowering::ExpandHvxResizeIntoSteps(SDValue Op, SelectionDAG &DAG)
3842 const {
3843 // Rewrite the extension/truncation/saturation op into steps where each
3844 // step changes the type widths by a factor of 2.
3845 // E.g. i8 -> i16 remains unchanged, but i8 -> i32 ==> i8 -> i16 -> i32.
3846 //
3847 // Some of the vector types in Op may not be legal.
3848
3849 unsigned Opc = Op.getOpcode();
3850 switch (Opc) {
3851 case HexagonISD::SSAT:
3852 case HexagonISD::USAT:
3855 break;
3856 case ISD::ANY_EXTEND:
3857 case ISD::ZERO_EXTEND:
3858 case ISD::SIGN_EXTEND:
3859 case ISD::TRUNCATE:
3860 llvm_unreachable("ISD:: ops will be auto-folded");
3861 break;
3862#ifndef NDEBUG
3863 Op.dump(&DAG);
3864#endif
3865 llvm_unreachable("Unexpected operation");
3866 }
3867
3868 SDValue Inp = Op.getOperand(0);
3869 MVT InpTy = ty(Inp);
3870 MVT ResTy = ty(Op);
3871
3872 unsigned InpWidth = InpTy.getVectorElementType().getSizeInBits();
3873 unsigned ResWidth = ResTy.getVectorElementType().getSizeInBits();
3874 assert(InpWidth != ResWidth);
3875
3876 if (InpWidth == 2 * ResWidth || ResWidth == 2 * InpWidth)
3877 return Op;
3878
3879 const SDLoc &dl(Op);
3880 unsigned NumElems = InpTy.getVectorNumElements();
3881 assert(NumElems == ResTy.getVectorNumElements());
3882
3883 auto repeatOp = [&](unsigned NewWidth, SDValue Arg) {
3884 MVT Ty = MVT::getVectorVT(MVT::getIntegerVT(NewWidth), NumElems);
3885 switch (Opc) {
3886 case HexagonISD::SSAT:
3887 case HexagonISD::USAT:
3888 return DAG.getNode(Opc, dl, Ty, {Arg, DAG.getValueType(Ty)});
3891 return DAG.getNode(Opc, dl, Ty, {Arg, Op.getOperand(1), Op.getOperand(2)});
3892 default:
3893 llvm_unreachable("Unexpected opcode");
3894 }
3895 };
3896
3897 SDValue S = Inp;
3898 if (InpWidth < ResWidth) {
3899 assert(ResWidth % InpWidth == 0 && isPowerOf2_32(ResWidth / InpWidth));
3900 while (InpWidth * 2 <= ResWidth)
3901 S = repeatOp(InpWidth *= 2, S);
3902 } else {
3903 // InpWidth > ResWidth
3904 assert(InpWidth % ResWidth == 0 && isPowerOf2_32(InpWidth / ResWidth));
3905 while (InpWidth / 2 >= ResWidth)
3906 S = repeatOp(InpWidth /= 2, S);
3907 }
3908 return S;
3909}
3910
3911SDValue
3912HexagonTargetLowering::LegalizeHvxResize(SDValue Op, SelectionDAG &DAG) const {
3913 SDValue Inp0 = Op.getOperand(0);
3914 MVT InpTy = ty(Inp0);
3915 MVT ResTy = ty(Op);
3916 unsigned InpWidth = InpTy.getSizeInBits();
3917 unsigned ResWidth = ResTy.getSizeInBits();
3918 unsigned Opc = Op.getOpcode();
3919
3920 if (shouldWidenToHvx(InpTy, DAG) || shouldWidenToHvx(ResTy, DAG)) {
3921 // First, make sure that the narrower type is widened to HVX.
3922 // This may cause the result to be wider than what the legalizer
3923 // expects, so insert EXTRACT_SUBVECTOR to bring it back to the
3924 // desired type.
3925 auto [WInpTy, WResTy] =
3926 InpWidth < ResWidth ? typeWidenToWider(typeWidenToHvx(InpTy), ResTy)
3927 : typeWidenToWider(InpTy, typeWidenToHvx(ResTy));
3928 SDValue W = appendUndef(Inp0, WInpTy, DAG);
3929 SDValue S;
3931 S = DAG.getNode(Opc, SDLoc(Op), WResTy, W, Op.getOperand(1),
3932 Op.getOperand(2));
3933 } else {
3934 S = DAG.getNode(Opc, SDLoc(Op), WResTy, W, DAG.getValueType(WResTy));
3935 }
3936 SDValue T = ExpandHvxResizeIntoSteps(S, DAG);
3937 return extractSubvector(T, typeLegalize(ResTy, DAG), 0, DAG);
3938 } else if (shouldSplitToHvx(InpWidth < ResWidth ? ResTy : InpTy, DAG)) {
3939 // For multi-step extends/truncates (e.g., i8->i32), expand into
3940 // single-step operations first. Splitting a multi-step TL_EXTEND
3941 // would halve the operand type to a sub-HVX size (e.g., v128i8 ->
3942 // v64i8), creating illegal types that cause issues in the type
3943 // legalizer's map tracking. Single-step operations (e.g., i16->i32)
3944 // are safe to split because their halved operand types remain legal.
3945 SDValue T = ExpandHvxResizeIntoSteps(Op, DAG);
3946 if (T != Op)
3947 return T;
3948 return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
3949 } else {
3950 assert(isTypeLegal(InpTy) && isTypeLegal(ResTy));
3951 return RemoveTLWrapper(Op, DAG);
3952 }
3953 llvm_unreachable("Unexpected situation");
3954}
3955
3956void
3957HexagonTargetLowering::LowerHvxOperationWrapper(SDNode *N,
3959 unsigned Opc = N->getOpcode();
3960 SDValue Op(N, 0);
3961 SDValue Inp0; // Optional first argument.
3962 if (N->getNumOperands() > 0)
3963 Inp0 = Op.getOperand(0);
3964
3965 switch (Opc) {
3966 case ISD::ANY_EXTEND:
3967 case ISD::SIGN_EXTEND:
3968 case ISD::ZERO_EXTEND:
3969 if (Subtarget.isHVXElementType(ty(Op)) &&
3970 Subtarget.isHVXElementType(ty(Inp0))) {
3971 Results.push_back(CreateTLWrapper(Op, DAG));
3972 }
3973 break;
3974 case ISD::TRUNCATE:
3975 // Handle truncate to boolean vector when the input is not a
3976 // standard HVX vector type (single or pair). This covers cases
3977 // where the input needs widening (e.g., v64i8 -> v64i1 in
3978 // 128-byte mode) and cases where the result boolean type itself
3979 // needs widening (e.g., v16i32 -> v16i1). When the input is
3980 // already an HVX type, tablegen patterns handle the truncation
3981 // directly (e.g., v64i16 -> v64i1 via V6_vandvrt).
3982 if (ty(Op).getVectorElementType() == MVT::i1 &&
3983 !Subtarget.isHVXVectorType(ty(Inp0), false)) {
3984 if (SDValue T = WidenHvxTruncateToBool(Op, DAG))
3985 Results.push_back(T);
3986 } else if (Subtarget.isHVXElementType(ty(Op)) &&
3987 Subtarget.isHVXElementType(ty(Inp0))) {
3988 Results.push_back(CreateTLWrapper(Op, DAG));
3989 }
3990 break;
3991 case ISD::SETCC:
3992 if (shouldWidenToHvx(ty(Inp0), DAG)) {
3993 if (SDValue T = WidenHvxSetCC(Op, DAG))
3994 Results.push_back(T);
3995 }
3996 break;
3997 case ISD::STORE: {
3998 if (shouldWidenToHvx(ty(cast<StoreSDNode>(N)->getValue()), DAG)) {
3999 SDValue Store = WidenHvxStore(Op, DAG);
4000 Results.push_back(Store);
4001 }
4002 break;
4003 }
4004 case ISD::MLOAD:
4005 if (isHvxPairTy(ty(Op))) {
4006 SDValue S = SplitHvxMemOp(Op, DAG);
4008 Results.push_back(S.getOperand(0));
4009 Results.push_back(S.getOperand(1));
4010 }
4011 break;
4012 case ISD::MSTORE:
4013 if (isHvxPairTy(ty(Op->getOperand(1)))) { // Stored value
4014 SDValue S = SplitHvxMemOp(Op, DAG);
4015 Results.push_back(S);
4016 }
4017 break;
4018 case ISD::SINT_TO_FP:
4019 case ISD::UINT_TO_FP:
4020 case ISD::FP_TO_SINT:
4021 case ISD::FP_TO_UINT:
4022 if (ty(Op).getSizeInBits() != ty(Inp0).getSizeInBits()) {
4023 SDValue T = EqualizeFpIntConversion(Op, DAG);
4024 Results.push_back(T);
4025 }
4026 break;
4027 case HexagonISD::SSAT:
4028 case HexagonISD::USAT:
4031 Results.push_back(LegalizeHvxResize(Op, DAG));
4032 break;
4033 default:
4034 break;
4035 }
4036}
4037
4038void
4039HexagonTargetLowering::ReplaceHvxNodeResults(SDNode *N,
4041 unsigned Opc = N->getOpcode();
4042 SDValue Op(N, 0);
4043 SDValue Inp0; // Optional first argument.
4044 if (N->getNumOperands() > 0)
4045 Inp0 = Op.getOperand(0);
4046
4047 switch (Opc) {
4048 case ISD::ANY_EXTEND:
4049 case ISD::SIGN_EXTEND:
4050 case ISD::ZERO_EXTEND:
4051 if (Subtarget.isHVXElementType(ty(Op)) &&
4052 Subtarget.isHVXElementType(ty(Inp0))) {
4053 Results.push_back(CreateTLWrapper(Op, DAG));
4054 }
4055 break;
4056 case ISD::TRUNCATE:
4057 // Handle truncate to boolean vector when the input is not a
4058 // standard HVX vector type. See comment in LowerHvxOperationWrapper.
4059 if (ty(Op).getVectorElementType() == MVT::i1 &&
4060 !Subtarget.isHVXVectorType(ty(Inp0), false)) {
4061 if (SDValue T = WidenHvxTruncateToBool(Op, DAG))
4062 Results.push_back(T);
4063 } else if (Subtarget.isHVXElementType(ty(Op)) &&
4064 Subtarget.isHVXElementType(ty(Inp0))) {
4065 Results.push_back(CreateTLWrapper(Op, DAG));
4066 }
4067 break;
4068 case ISD::SETCC:
4069 if (shouldWidenToHvx(ty(Op), DAG)) {
4070 if (SDValue T = WidenHvxSetCC(Op, DAG))
4071 Results.push_back(T);
4072 }
4073 break;
4074 case ISD::LOAD: {
4075 if (shouldWidenToHvx(ty(Op), DAG)) {
4076 SDValue Load = WidenHvxLoad(Op, DAG);
4077 assert(Load->getOpcode() == ISD::MERGE_VALUES);
4078 Results.push_back(Load.getOperand(0));
4079 Results.push_back(Load.getOperand(1));
4080 }
4081 break;
4082 }
4083 case ISD::BITCAST:
4084 if (isHvxBoolTy(ty(Inp0))) {
4085 SDValue C = LowerHvxBitcast(Op, DAG);
4086 Results.push_back(C);
4087 }
4088 break;
4089 case ISD::FP_TO_SINT:
4090 case ISD::FP_TO_UINT:
4091 if (ty(Op).getSizeInBits() != ty(Inp0).getSizeInBits()) {
4092 SDValue T = EqualizeFpIntConversion(Op, DAG);
4093 Results.push_back(T);
4094 }
4095 break;
4096 case HexagonISD::SSAT:
4097 case HexagonISD::USAT:
4100 Results.push_back(LegalizeHvxResize(Op, DAG));
4101 break;
4102 default:
4103 break;
4104 }
4105}
4106
4107SDValue
4108HexagonTargetLowering::combineTruncateBeforeLegal(SDValue Op,
4109 DAGCombinerInfo &DCI) const {
4110 // Simplify V:v2NiB --(bitcast)--> vNi2B --(truncate)--> vNiB
4111 // to extract-subvector (shuffle V, pick even, pick odd)
4112
4113 assert(Op.getOpcode() == ISD::TRUNCATE);
4114 SelectionDAG &DAG = DCI.DAG;
4115 const SDLoc &dl(Op);
4116
4117 if (Op.getOperand(0).getOpcode() == ISD::BITCAST)
4118 return SDValue();
4119 SDValue Cast = Op.getOperand(0);
4120 SDValue Src = Cast.getOperand(0);
4121
4122 EVT TruncTy = Op.getValueType();
4123 EVT CastTy = Cast.getValueType();
4124 EVT SrcTy = Src.getValueType();
4125 if (SrcTy.isSimple())
4126 return SDValue();
4127 if (SrcTy.getVectorElementType() != TruncTy.getVectorElementType())
4128 return SDValue();
4129 unsigned SrcLen = SrcTy.getVectorNumElements();
4130 unsigned CastLen = CastTy.getVectorNumElements();
4131 if (2 * CastLen != SrcLen)
4132 return SDValue();
4133
4134 SmallVector<int, 128> Mask(SrcLen);
4135 for (int i = 0; i != static_cast<int>(CastLen); ++i) {
4136 Mask[i] = 2 * i;
4137 Mask[i + CastLen] = 2 * i + 1;
4138 }
4139 SDValue Deal =
4140 DAG.getVectorShuffle(SrcTy, dl, Src, DAG.getUNDEF(SrcTy), Mask);
4141 return opSplit(Deal, dl, DAG).first;
4142}
4143
4144SDValue
4145HexagonTargetLowering::combineConcatOfShuffles(SDValue Op,
4146 SelectionDAG &DAG) const {
4147 // Fold
4148 // concat (shuffle x, y, m1), (shuffle x, y, m2)
4149 // into
4150 // shuffle (concat x, y), undef, m3
4151 if (Op.getNumOperands() != 2)
4152 return SDValue();
4153
4154 const SDLoc &dl(Op);
4155 SDValue V0 = Op.getOperand(0);
4156 SDValue V1 = Op.getOperand(1);
4157
4158 if (V0.getOpcode() != ISD::VECTOR_SHUFFLE)
4159 return SDValue();
4160 if (V1.getOpcode() != ISD::VECTOR_SHUFFLE)
4161 return SDValue();
4162
4163 SetVector<SDValue> Order;
4164 Order.insert(V0.getOperand(0));
4165 Order.insert(V0.getOperand(1));
4166 Order.insert(V1.getOperand(0));
4167 Order.insert(V1.getOperand(1));
4168
4169 if (Order.size() > 2)
4170 return SDValue();
4171
4172 // In ISD::VECTOR_SHUFFLE, the types of each input and the type of the
4173 // result must be the same.
4174 EVT InpTy = V0.getValueType();
4175 assert(InpTy.isVector());
4176 unsigned InpLen = InpTy.getVectorNumElements();
4177
4178 SmallVector<int, 128> LongMask;
4179 auto AppendToMask = [&](SDValue Shuffle) {
4180 auto *SV = cast<ShuffleVectorSDNode>(Shuffle.getNode());
4181 ArrayRef<int> Mask = SV->getMask();
4182 SDValue X = Shuffle.getOperand(0);
4183 SDValue Y = Shuffle.getOperand(1);
4184 for (int M : Mask) {
4185 if (M == -1) {
4186 LongMask.push_back(M);
4187 continue;
4188 }
4189 SDValue Src = static_cast<unsigned>(M) < InpLen ? X : Y;
4190 if (static_cast<unsigned>(M) >= InpLen)
4191 M -= InpLen;
4192
4193 int OutOffset = Order[0] == Src ? 0 : InpLen;
4194 LongMask.push_back(M + OutOffset);
4195 }
4196 };
4197
4198 AppendToMask(V0);
4199 AppendToMask(V1);
4200
4201 SDValue C0 = Order.front();
4202 SDValue C1 = Order.back(); // Can be same as front
4203 EVT LongTy = InpTy.getDoubleNumVectorElementsVT(*DAG.getContext());
4204
4205 SDValue Cat = DAG.getNode(ISD::CONCAT_VECTORS, dl, LongTy, {C0, C1});
4206 return DAG.getVectorShuffle(LongTy, dl, Cat, DAG.getUNDEF(LongTy), LongMask);
4207}
4208
4209// Reassociate concat(p1, p2, ...) into
4210// concat(concat(p1, ...), concat(pi, ...), ...)
4211// where each inner concat produces a predicate where each bit corresponds
4212// to at most BitBytes bytes.
4213// Concatenating predicates decreases the number of bytes per each predicate
4214// bit.
4215SDValue
4216HexagonTargetLowering::combineConcatOfScalarPreds(SDValue Op, unsigned BitBytes,
4217 SelectionDAG &DAG) const {
4218 const SDLoc &dl(Op);
4219 SmallVector<SDValue> Ops(Op->ops());
4220 MVT ResTy = ty(Op);
4221 MVT InpTy = ty(Ops[0]);
4222 unsigned InpLen = InpTy.getVectorNumElements(); // Scalar predicate
4223 unsigned ResLen = ResTy.getVectorNumElements(); // HVX vector predicate
4224 assert(InpLen <= 8 && "Too long for scalar predicate");
4225 assert(ResLen > 8 && "Too short for HVX vector predicate");
4226
4227 unsigned Bytes = 8 / InpLen; // Bytes-per-bit in input
4228
4229 // Already in the right form?
4230 if (Bytes <= BitBytes)
4231 return Op;
4232
4233 ArrayRef<SDValue> Inputs(Ops);
4234 unsigned SliceLen = Bytes / BitBytes;
4235
4237 // (8 / BitBytes) is the desired length of the result of the inner concat.
4238 MVT InnerTy = MVT::getVectorVT(MVT::i1, 8 / BitBytes);
4239 for (unsigned i = 0; i != ResLen / (8 / BitBytes); ++i) {
4240 SDValue Cat = DAG.getNode(ISD::CONCAT_VECTORS, dl, InnerTy,
4241 Inputs.slice(SliceLen * i, SliceLen));
4242 Cats.push_back(Cat);
4243 }
4244
4245 return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResTy, Cats);
4246}
4247
4248SDValue HexagonTargetLowering::combineConcatVectorsBeforeLegal(
4249 SDValue Op, DAGCombinerInfo &DCI) const {
4250 MVT ResTy = ty(Op);
4251 MVT ElemTy = ResTy.getVectorElementType();
4252
4253 if (ElemTy != MVT::i1) {
4254 return combineConcatOfShuffles(Op, DCI.DAG);
4255 }
4256 return SDValue();
4257}
4258
4259// Create the inner partial reduction MLA that can be efficiently lowered. This
4260// function is used by partial and full reductions.
4261SDValue HexagonTargetLowering::createExtendingPartialReduceMLA(
4262 unsigned Opcode, EVT AccEltType, unsigned AccNumElements, EVT InputType,
4263 const SDValue &A, const SDValue &B, unsigned &RemainingReductionRatio,
4264 const SDLoc &DL, SelectionDAG &DAG) const {
4265 const auto &Subtarget = DAG.getSubtarget<HexagonSubtarget>();
4266 if (!Subtarget.useHVXOps())
4267 return SDValue();
4268
4269 EVT InputEltType = InputType.getVectorElementType();
4270
4271 // Find if an optimized instruction for the sub-reduction is available.
4272 unsigned NativeRatio;
4273 if (AccEltType == MVT::i32 && InputEltType == MVT::i8)
4274 NativeRatio = 4;
4275 else
4276 return SDValue();
4277
4278 // We only handle the case when additional reduction will be needed, i.e.
4279 // input is longer by a larger factor than the result.
4280 ElementCount InputEC = InputType.getVectorElementCount();
4281 if (!InputEC.isKnownMultipleOf(AccNumElements * NativeRatio))
4282 return SDValue();
4283
4284 unsigned InputNumElements = InputEC.getFixedValue();
4285 RemainingReductionRatio = InputNumElements / (AccNumElements * NativeRatio);
4286 if (RemainingReductionRatio == 1)
4287 return SDValue();
4288
4289 // Create a reduction by the natively supported factor.
4290 EVT IntermediateType = EVT::getVectorVT(*DAG.getContext(), AccEltType,
4291 InputNumElements / NativeRatio);
4292
4293 SDValue Zero = DAG.getConstant(0, DL, IntermediateType);
4294 return DAG.getNode(Opcode, DL, IntermediateType, Zero, A, B);
4295}
4296
4297static bool DetectExtendingMultiply(const SDValue &N, EVT ScalarType,
4298 unsigned &Opcode, SDValue &A, SDValue &B) {
4299 SDValue Mul = N;
4300 EVT AccType = Mul.getValueType(); // Vector input type after extension.
4301 if (ScalarType != AccType.getVectorElementType())
4302 return false;
4303 bool swap = false;
4304 if (Mul->getOpcode() != ISD::MUL)
4305 return false;
4306 A = Mul->getOperand(0);
4307 B = Mul->getOperand(1);
4308 if (A.getOpcode() == ISD::ZERO_EXTEND) {
4309 if (B.getOpcode() == ISD::ZERO_EXTEND)
4310 Opcode = ISD::PARTIAL_REDUCE_UMLA;
4311 else if (B.getOpcode() == ISD::SIGN_EXTEND) {
4312 swap = true;
4314 } else
4315 return false;
4316 } else if (A.getOpcode() == ISD::SIGN_EXTEND) {
4317 if (B.getOpcode() == ISD::ZERO_EXTEND)
4319 else if (B.getOpcode() == ISD::SIGN_EXTEND)
4320 Opcode = ISD::PARTIAL_REDUCE_SMLA;
4321 else
4322 return false;
4323 } else
4324 return false;
4325
4326 // Get multiplication arguments before extension.
4327 A = A->getOperand(0);
4328 B = B->getOperand(0);
4329 if (A.getValueType() != B.getValueType())
4330 return false;
4331
4332 if (swap)
4333 std::swap(A, B);
4334
4335 return true;
4336}
4337
4338SDValue HexagonTargetLowering::splitVecReduceAdd(SDNode *N,
4339 SelectionDAG &DAG) const {
4340 if (!Subtarget.useHVXOps())
4341 return SDValue();
4342
4343 EVT ScalarType = N->getValueType(0);
4344 unsigned Opcode;
4345 SDValue A, B;
4346 if (!DetectExtendingMultiply(N->getOperand(0), ScalarType, Opcode, A, B))
4347 return SDValue();
4348
4349 SDLoc DL(N);
4350 unsigned RemainingReductionRatio;
4351 SDValue Partial =
4352 createExtendingPartialReduceMLA(Opcode, ScalarType, 1, A.getValueType(),
4353 A, B, RemainingReductionRatio, DL, DAG);
4354 if (!Partial)
4355 return SDValue();
4356
4357 // We could have inserted a trivial MLA and rely on the folding action,
4358 // similar to how vector_partial_reduce_add is lowered to an MLA in
4359 // SelectionDAGBuilder. However, we just replace the final result since we
4360 // have analyzed the input completely.
4361 return DAG.getNode(ISD::VECREDUCE_ADD, DL, ScalarType, Partial);
4362}
4363
4364// When possible, separate an MLA reduction with extended operands but
4365// unsupported reduction factor into an extending partial reduction that
4366// can be efficiently lowered, and a follow-up partial reduction.
4367// partial_reduce_mla(a, x, y) ->
4368// partial_reduce_mla(a, partial_reduce_mla(0, x, y), 1)
4369SDValue
4370HexagonTargetLowering::splitExtendingPartialReduceMLA(SDNode *N,
4371 SelectionDAG &DAG) const {
4372 if (!Subtarget.useHVXOps())
4373 return SDValue();
4374
4375 SDValue Acc = N->getOperand(0);
4376 SDValue A = N->getOperand(1);
4377 SDValue B = N->getOperand(2);
4378 if (A.getValueType() != B.getValueType())
4379 return SDValue();
4380
4381 // The types should be declared as custom, but do not split already legal
4382 // operation.
4383 EVT AccType = Acc.getValueType();
4384 EVT InputType = A.getValueType();
4385 if (getPartialReduceMLAAction(N->getOpcode(), AccType, InputType) != Custom)
4386 return SDValue();
4387
4388 SDLoc DL(N);
4389 unsigned RemainingReductionRatio;
4390 SDValue Partial = createExtendingPartialReduceMLA(
4391 N->getOpcode(), AccType.getVectorElementType(),
4392 AccType.getVectorNumElements(), InputType, A, B, RemainingReductionRatio,
4393 DL, DAG);
4394 if (!Partial)
4395 return SDValue();
4396 assert(RemainingReductionRatio <= MaxExpandMLA);
4397
4398 // Create the reduction for the remaining ratio.
4399 EVT IntermediateType = Partial->getOperand(0).getValueType();
4400 SDValue One = DAG.getConstant(1, DL, IntermediateType);
4401 return DAG.getNode(N->getOpcode() == ISD::PARTIAL_REDUCE_UMLA
4404 DL, AccType, Acc, Partial, One);
4405}
4406
4407SDValue
4408HexagonTargetLowering::LowerHvxPartialReduceMLA(SDValue Op,
4409 SelectionDAG &DAG) const {
4410 const SDLoc &DL(Op);
4411 SDValue Acc = Op.getOperand(0);
4412 SDValue A = Op.getOperand(1);
4413 SDValue B = Op.getOperand(2);
4414
4415 // Split the input vectors into units of one HVX vector length.
4416 unsigned HwVectorSizeInBits = Subtarget.getVectorLength() * 8;
4417
4418 EVT AccType = Acc.getValueType();
4419 EVT AccEltType = AccType.getVectorElementType();
4420 unsigned AccSubvectorNumElements =
4421 HwVectorSizeInBits / AccEltType.getSizeInBits();
4422 EVT AccSubvectorType =
4423 EVT::getVectorVT(*DAG.getContext(), AccEltType, AccSubvectorNumElements);
4424
4425 EVT InputType = A.getValueType();
4426 assert(InputType.getSizeInBits() % HwVectorSizeInBits == 0);
4427 EVT InputEltType = InputType.getVectorElementType();
4428 unsigned InputSubvectorNumElements =
4429 HwVectorSizeInBits / InputEltType.getSizeInBits();
4430 EVT InputSubvectorType = EVT::getVectorVT(*DAG.getContext(), InputEltType,
4431 InputSubvectorNumElements);
4432
4433 unsigned SubvectorNum = InputType.getFixedSizeInBits() / HwVectorSizeInBits;
4435
4436 for (unsigned I = 0; I != SubvectorNum; ++I) {
4437 SDValue SubvectorAcc = DAG.getExtractSubvector(DL, AccSubvectorType, Acc,
4438 I * AccSubvectorNumElements);
4439 SDValue SubvectorA = DAG.getExtractSubvector(DL, InputSubvectorType, A,
4440 I * InputSubvectorNumElements);
4441 SDValue SubvectorB = DAG.getExtractSubvector(DL, InputSubvectorType, B,
4442 I * InputSubvectorNumElements);
4443 SDValue SubvectorMLA = DAG.getNode(Op.getOpcode(), DL, AccSubvectorType,
4444 SubvectorAcc, SubvectorA, SubvectorB);
4445 Subvectors.push_back(SubvectorMLA);
4446 }
4447
4448 return DAG.getNode(ISD::CONCAT_VECTORS, DL, AccType, Subvectors);
4449}
4450
4451SDValue
4452HexagonTargetLowering::PerformHvxDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
4453 const {
4454 const SDLoc &dl(N);
4455 SelectionDAG &DAG = DCI.DAG;
4456 SDValue Op(N, 0);
4457 unsigned Opc = Op.getOpcode();
4458
4460
4461 if (Opc == ISD::TRUNCATE)
4462 return combineTruncateBeforeLegal(Op, DCI);
4463 if (Opc == ISD::CONCAT_VECTORS)
4464 return combineConcatVectorsBeforeLegal(Op, DCI);
4465
4466 if (DCI.isBeforeLegalizeOps())
4467 return SDValue();
4468
4469 switch (Opc) {
4470 case HexagonISD::V2Q:
4471 if (Ops[0].getOpcode() == ISD::SPLAT_VECTOR) {
4472 if (const auto *C = dyn_cast<ConstantSDNode>(Ops[0].getOperand(0)))
4473 return C->isZero() ? DAG.getNode(HexagonISD::QFALSE, dl, ty(Op))
4474 : DAG.getNode(HexagonISD::QTRUE, dl, ty(Op));
4475 }
4476 break;
4477 case HexagonISD::Q2V:
4478 if (Ops[0].getOpcode() == HexagonISD::QTRUE)
4479 return DAG.getNode(ISD::SPLAT_VECTOR, dl, ty(Op),
4480 DAG.getAllOnesConstant(dl, MVT::i32));
4481 if (Ops[0].getOpcode() == HexagonISD::QFALSE)
4482 return getZero(dl, ty(Op), DAG);
4483 break;
4484 case HexagonISD::VINSERTW0:
4485 if (isUndef(Ops[1]))
4486 return Ops[0];
4487 break;
4488 case HexagonISD::VROR: {
4489 if (Ops[0].getOpcode() == HexagonISD::VROR) {
4490 SDValue Vec = Ops[0].getOperand(0);
4491 SDValue Rot0 = Ops[1], Rot1 = Ops[0].getOperand(1);
4492 SDValue Rot = DAG.getNode(ISD::ADD, dl, ty(Rot0), {Rot0, Rot1});
4493 return DAG.getNode(HexagonISD::VROR, dl, ty(Op), {Vec, Rot});
4494 }
4495 break;
4496 }
4497 }
4498
4499 return SDValue();
4500}
4501
4502bool
4503HexagonTargetLowering::shouldSplitToHvx(MVT Ty, SelectionDAG &DAG) const {
4504 if (Subtarget.isHVXVectorType(Ty, true))
4505 return false;
4506 auto Action = getPreferredHvxVectorAction(Ty);
4508 return Subtarget.isHVXVectorType(typeLegalize(Ty, DAG), true);
4509 return false;
4510}
4511
4512bool
4513HexagonTargetLowering::shouldWidenToHvx(MVT Ty, SelectionDAG &DAG) const {
4514 if (Subtarget.isHVXVectorType(Ty, true))
4515 return false;
4516 auto Action = getPreferredHvxVectorAction(Ty);
4518 return Subtarget.isHVXVectorType(typeLegalize(Ty, DAG), true);
4519 return false;
4520}
4521
4522bool
4523HexagonTargetLowering::isHvxOperation(SDNode *N, SelectionDAG &DAG) const {
4524 if (!Subtarget.useHVXOps())
4525 return false;
4526 // If the type of any result, or any operand type are HVX vector types,
4527 // this is an HVX operation.
4528 auto IsHvxTy = [this](EVT Ty) {
4529 return Ty.isSimple() && Subtarget.isHVXVectorType(Ty.getSimpleVT(), true);
4530 };
4531 auto IsHvxOp = [this](SDValue Op) {
4532 return Op.getValueType().isSimple() &&
4533 Subtarget.isHVXVectorType(ty(Op), true);
4534 };
4535 if (llvm::any_of(N->values(), IsHvxTy) || llvm::any_of(N->ops(), IsHvxOp))
4536 return true;
4537
4538 // Check if this could be an HVX operation after type widening.
4539 auto IsWidenedToHvx = [this, &DAG](SDValue Op) {
4540 if (!Op.getValueType().isSimple())
4541 return false;
4542 MVT ValTy = ty(Op);
4543 return ValTy.isVector() && shouldWidenToHvx(ValTy, DAG);
4544 };
4545
4546 for (int i = 0, e = N->getNumValues(); i != e; ++i) {
4547 if (IsWidenedToHvx(SDValue(N, i)))
4548 return true;
4549 }
4550 return llvm::any_of(N->ops(), IsWidenedToHvx);
4551}
return SDValue()
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
constexpr LLT S16
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Function Alias Analysis Results
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
const HexagonInstrInfo * TII
static std::tuple< unsigned, unsigned, unsigned > getIEEEProperties(MVT Ty)
static const unsigned MaxExpandMLA
static const MVT LegalV128[]
static const MVT LegalW128[]
static const MVT LegalW64[]
static const MVT LegalV64[]
static bool DetectExtendingMultiply(const SDValue &N, EVT ScalarType, unsigned &Opcode, SDValue &A, SDValue &B)
static cl::opt< unsigned > HvxWidenThreshold("hexagon-hvx-widen", cl::Hidden, cl::init(16), cl::desc("Lower threshold (in bytes) for widening to HVX vectors"))
static cl::opt< bool > EnableFpFastConvert("hexagon-fp-fast-convert", cl::Hidden, cl::init(false), cl::desc("Enable FP fast conversion routine."))
IRTranslator LLVM IR MI
static constexpr Value * getValue(Ty &ValueOrUse)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static bool isSplat(Value *V)
Return true if V is a splat of a value (which is used when multiplying a matrix with a scalar).
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define H(x, y, z)
Definition MD5.cpp:56
std::pair< MCSymbol *, MachineModuleInfoImpl::StubValueTy > PairTy
Promote Memory to Register
Definition Mem2Reg.cpp:110
This file provides utility analysis objects describing memory locations.
#define T
#define T1
#define P(N)
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static llvm::Type * getVectorElementType(llvm::Type *Ty)
BinaryOperator * Mul
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:345
static const fltSemantics & IEEEhalf()
Definition APFloat.h:295
LLVM_ABI opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, bool *losesInfo)
Definition APFloat.cpp:5920
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const
EVT getSetCCResultType(const DataLayout &, LLVMContext &C, EVT VT) const override
Return the ValueType of the result of SETCC operations.
LegalizeTypeAction getPreferredVectorAction(MVT VT) const override
Return the preferred vector type legalization action.
const SDValue & getBasePtr() const
Machine Value Type.
static MVT getFloatingPointVT(unsigned BitWidth)
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
bool isInteger() const
Return true if this is an integer or a vector integer type.
MVT changeTypeToInteger()
Return the type converted to an equivalently sized integer or vector with integer element type.
TypeSize getSizeInBits() const
Returns the size of the specified MVT in bits.
ElementCount getVectorElementCount() const
TypeSize getStoreSize() const
Return the number of bytes overwritten by a store of the specified value type.
bool isScalarInteger() const
Return true if this is an integer, not including vectors.
static MVT getVectorVT(MVT VT, unsigned NumElements)
MVT getVectorElementType() const
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
static MVT getIntegerVT(unsigned BitWidth)
MVT getScalarType() const
If this is a vector, return the element type, otherwise return this.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
LLVM_ABI instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
Flags
Flags values. These may be or'd together.
const MachinePointerInfo & getPointerInfo() const
Align getBaseAlign() const
Return the minimum known alignment in bytes of the base address, without the offset.
unsigned getSubReg() const
int64_t getImm() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
MachineMemOperand * getMemOperand() const
Return the unique MachineMemOperand object describing the memory reference performed by operation.
const SDValue & getChain() const
Wrapper class for IR location info (IR ordering and DebugLoc) to be passed into SDNode creation funct...
Represents one node in the SelectionDAG.
unsigned getOpcode() const
Return the SelectionDAG opcode value for this node.
iterator_range< value_op_iterator > op_values() const
uint64_t getAsZExtVal() const
Helper method returns the zero-extended integer value of a ConstantSDNode.
const SDValue & getOperand(unsigned Num) const
Unlike LLVM values, Selection DAG nodes may return multiple values as the result of a computation.
SDNode * getNode() const
get the SDNode which holds the desired result
SDValue getValue(unsigned R) const
EVT getValueType() const
Return the ValueType of the referenced return value.
const SDValue & getOperand(unsigned i) const
unsigned getOpcode() const
This is used to represent a portion of an LLVM function in a low-level Data Dependence DAG representa...
const TargetSubtargetInfo & getSubtarget() const
LLVM_ABI SDValue getMergeValues(ArrayRef< SDValue > Ops, const SDLoc &dl)
Create a MERGE_VALUES node from the given operands.
LLVM_ABI SDVTList getVTList(EVT VT)
Return an SDVTList that represents the list of values specified.
LLVM_ABI SDValue getAllOnesConstant(const SDLoc &DL, EVT VT, bool IsTarget=false, bool IsOpaque=false)
LLVM_ABI MachineSDNode * getMachineNode(unsigned Opcode, const SDLoc &dl, EVT VT)
These are used for target selectors to create a new node with specified return type(s),...
LLVM_ABI void ExtractVectorElements(SDValue Op, SmallVectorImpl< SDValue > &Args, unsigned Start=0, unsigned Count=0, EVT EltVT=EVT())
Append the extracted elements from Start to Count out of the vector Op in Args.
LLVM_ABI SDValue getConstantPool(const Constant *C, EVT VT, MaybeAlign Align=std::nullopt, int Offs=0, bool isT=false, unsigned TargetFlags=0)
LLVM_ABI SDValue getConstantFP(double Val, const SDLoc &DL, EVT VT, bool isTarget=false)
Create a ConstantFPSDNode wrapping a constant value.
SDValue getExtractSubvector(const SDLoc &DL, EVT VT, SDValue Vec, unsigned Idx)
Return the VT typed sub-vector of Vec at Idx.
LLVM_ABI SDValue getLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, MaybeAlign Alignment=MaybeAlign(), MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr)
Loads are not normal binary operators: their result type is not determined by their operands,...
SDValue getSetCC(const SDLoc &DL, EVT VT, SDValue LHS, SDValue RHS, ISD::CondCode Cond, SDValue Chain=SDValue(), bool IsSignaling=false, SDNodeFlags Flags={})
Helper function to make it easier to build SetCC's if you just have an ISD::CondCode instead of an SD...
LLVM_ABI std::pair< EVT, EVT > GetSplitDestVTs(const EVT &VT) const
Compute the VTs needed for the low/hi parts of a type which is split (or expanded) into two not neces...
SDValue getUNDEF(EVT VT)
Return an UNDEF node. UNDEF does not have a useful SDLoc.
SDValue getBuildVector(EVT VT, const SDLoc &DL, ArrayRef< SDValue > Ops)
Return an ISD::BUILD_VECTOR node.
LLVM_ABI SDValue getBitcast(EVT VT, SDValue V)
Return a bitcast using the SDLoc of the value operand, and casting to the provided type.
SDValue getSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS, SDValue RHS, SDNodeFlags Flags=SDNodeFlags())
Helper function to make it easier to build Select's if you just have operands and don't want to check...
LLVM_ABI void setNodeMemRefs(MachineSDNode *N, ArrayRef< MachineMemOperand * > NewMemRefs)
Mutate the specified machine node's memory references to the provided list.
const DataLayout & getDataLayout() const
LLVM_ABI SDValue getConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
Create a ConstantSDNode wrapping a constant value.
LLVM_ABI SDValue getMemBasePlusOffset(SDValue Base, TypeSize Offset, const SDLoc &DL, const SDNodeFlags Flags=SDNodeFlags())
Returns sum of the base pointer and offset.
LLVM_ABI std::pair< SDValue, SDValue > SplitVector(const SDValue &N, const SDLoc &DL, const EVT &LoVT, const EVT &HiVT)
Split the vector with EXTRACT_SUBVECTOR using the provided VTs and return the low/high part.
LLVM_ABI SDValue getStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Ptr, MachinePointerInfo PtrInfo, Align Alignment, MachineMemOperand::Flags MMOFlags=MachineMemOperand::MONone, const AAMDNodes &AAInfo=AAMDNodes())
Helper function to build ISD::STORE nodes.
LLVM_ABI SDValue getSignedConstant(int64_t Val, const SDLoc &DL, EVT VT, bool isTarget=false, bool isOpaque=false)
LLVM_ABI SDValue getTargetExtractSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand)
A convenience function for creating TargetInstrInfo::EXTRACT_SUBREG nodes.
LLVM_ABI SDValue getSExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either sign-extending or trunca...
LLVM_ABI SDValue getMaskedStore(SDValue Chain, const SDLoc &dl, SDValue Val, SDValue Base, SDValue Offset, SDValue Mask, EVT MemVT, MachineMemOperand *MMO, ISD::MemIndexedMode AM, bool IsTruncating=false, bool IsCompressing=false)
LLVM_ABI SDValue getValueType(EVT)
LLVM_ABI SDValue getNode(unsigned Opcode, const SDLoc &DL, EVT VT, ArrayRef< SDUse > Ops)
Gets or creates the specified node.
SDValue getTargetConstant(uint64_t Val, const SDLoc &DL, EVT VT, bool isOpaque=false)
MachineFunction & getMachineFunction() const
SDValue getSplatBuildVector(EVT VT, const SDLoc &DL, SDValue Op)
Return a splat ISD::BUILD_VECTOR node, consisting of Op splatted to all elements.
LLVM_ABI SDValue getZExtOrTrunc(SDValue Op, const SDLoc &DL, EVT VT)
Convert Op, which must be of integer type, to the integer type VT, by either zero-extending or trunca...
LLVMContext * getContext() const
LLVM_ABI std::pair< EVT, EVT > GetDependentSplitDestVTs(const EVT &VT, const EVT &EnvVT, bool *HiIsEmpty) const
Compute the VTs needed for the low/hi parts of a type, dependent on an enveloping VT that has been sp...
LLVM_ABI SDValue getTargetInsertSubreg(int SRIdx, const SDLoc &DL, EVT VT, SDValue Operand, SDValue Subreg)
A convenience function for creating TargetInstrInfo::INSERT_SUBREG nodes.
SDValue getEntryNode() const
Return the token chain corresponding to the entry of the function.
LLVM_ABI SDValue getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain, SDValue Base, SDValue Offset, SDValue Mask, SDValue Src0, EVT MemVT, MachineMemOperand *MMO, ISD::MemIndexedMode AM, ISD::LoadExtType, bool IsExpanding=false)
LLVM_ABI SDValue getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1, SDValue N2, ArrayRef< int > Mask)
Return an ISD::VECTOR_SHUFFLE node.
size_type size() const
Determine the number of elements in the SetVector.
Definition SetVector.h:103
const value_type & front() const
Return the first element of the SetVector.
Definition SetVector.h:132
const value_type & back() const
Return the last element of the SetVector.
Definition SetVector.h:138
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:151
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
const SDValue & getBasePtr() const
const SDValue & getValue() const
void setOperationAction(unsigned Op, MVT VT, LegalizeAction Action)
Indicate that the specified operation does not work with the specified type and indicate what to do a...
void setIndexedLoadAction(ArrayRef< unsigned > IdxModes, MVT VT, LegalizeAction Action)
Indicate that the specified indexed load does or does not work with the specified type and indicate w...
virtual EVT getTypeToTransformTo(LLVMContext &Context, EVT VT) const
For types supported by the target, this is an identity function.
void addRegisterClass(MVT VT, const TargetRegisterClass *RC)
Add the specified register class as an available regclass for the specified value type.
bool isTypeLegal(EVT VT) const
Return true if the target has native support for the specified value type.
void setIndexedStoreAction(ArrayRef< unsigned > IdxModes, MVT VT, LegalizeAction Action)
Indicate that the specified indexed store does or does not work with the specified type and indicate ...
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
void setPartialReduceMLAAction(unsigned Opc, MVT AccVT, MVT InputVT, LegalizeAction Action)
Indicate how a PARTIAL_REDUCE_U/SMLA node with Acc type AccVT and Input type InputVT should be treate...
LegalizeAction getPartialReduceMLAAction(unsigned Opc, EVT AccVT, EVT InputVT) const
Return how a PARTIAL_REDUCE_U/SMLA node with Acc type AccVT and Input type InputVT should be treated.
void AddPromotedToType(unsigned Opc, MVT OrigVT, MVT DestVT)
If Opc/OrigVT is specified as being promoted, the promotion code defaults to trying a larger integer/...
void setCondCodeAction(ArrayRef< ISD::CondCode > CCs, MVT VT, LegalizeAction Action)
Indicate that the specified condition code is or isn't supported on the target and indicate what to d...
void setTargetDAGCombine(ArrayRef< ISD::NodeType > NTs)
Targets should invoke this method for each target independent node that they want to provide a custom...
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:343
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:307
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
Definition TypeSize.h:180
constexpr ScalarTy getFixedValue() const
Definition TypeSize.h:200
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Fast
Attempts to make calls as fast as possible (e.g.
Definition CallingConv.h:41
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
@ SETCC
SetCC operator - This evaluates to a true value iff the condition is true.
Definition ISDOpcodes.h:829
@ MERGE_VALUES
MERGE_VALUES - This node takes multiple discrete operands and returns them all as its individual resu...
Definition ISDOpcodes.h:261
@ PARTIAL_REDUCE_SMLA
PARTIAL_REDUCE_[U|S]MLA(Accumulator, Input1, Input2) The partial reduction nodes sign or zero extend ...
@ MLOAD
Masked load and store - consecutive vector load and store operations with additional mask operand tha...
@ SMUL_LOHI
SMUL_LOHI/UMUL_LOHI - Multiply two integers of type iN, producing a signed/unsigned value of type i[2...
Definition ISDOpcodes.h:275
@ INSERT_SUBVECTOR
INSERT_SUBVECTOR(VECTOR1, VECTOR2, IDX) - Returns a vector with VECTOR2 inserted into VECTOR1.
Definition ISDOpcodes.h:602
@ BSWAP
Byte Swap and Counting operators.
Definition ISDOpcodes.h:789
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:264
@ LOAD
LOAD and STORE have token chains as their first operand, then the same operands as an LLVM load/store...
@ ANY_EXTEND
ANY_EXTEND - Used for integer types. The high bits are undefined.
Definition ISDOpcodes.h:863
@ INTRINSIC_VOID
OUTCHAIN = INTRINSIC_VOID(INCHAIN, INTRINSICID, arg1, arg2, ...) This node represents a target intrin...
Definition ISDOpcodes.h:220
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:890
@ CONCAT_VECTORS
CONCAT_VECTORS(VECTOR0, VECTOR1, ...) - Given a number of values of vector type with the same length ...
Definition ISDOpcodes.h:586
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:417
@ ABS
ABS - Determine the unsigned absolute value of a signed integer value of the same bitwidth.
Definition ISDOpcodes.h:749
@ SIGN_EXTEND_VECTOR_INREG
SIGN_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register sign-extension of the low ...
Definition ISDOpcodes.h:920
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ BUILD_PAIR
BUILD_PAIR - This is the opposite of EXTRACT_ELEMENT in some ways.
Definition ISDOpcodes.h:254
@ PARTIAL_REDUCE_UMLA
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:854
@ SSUBSAT
RESULT = [US]SUBSAT(LHS, RHS) - Perform saturation subtraction on 2 integers with the same bit width ...
Definition ISDOpcodes.h:374
@ SELECT
Select(COND, TRUEVAL, FALSEVAL).
Definition ISDOpcodes.h:806
@ UNDEF
UNDEF - An undefined node.
Definition ISDOpcodes.h:233
@ SPLAT_VECTOR
SPLAT_VECTOR(VAL) - Returns a vector with the scalar value VAL duplicated in all lanes.
Definition ISDOpcodes.h:674
@ VECREDUCE_ADD
Integer reductions may have a result type larger than the vector element type.
@ MULHU
MULHU/MULHS - Multiply high - Multiply two integers of type iN, producing an unsigned/signed value of...
Definition ISDOpcodes.h:706
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:771
@ VECTOR_SHUFFLE
VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as VEC1/VEC2.
Definition ISDOpcodes.h:651
@ EXTRACT_SUBVECTOR
EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR.
Definition ISDOpcodes.h:616
@ EXTRACT_VECTOR_ELT
EXTRACT_VECTOR_ELT(VECTOR, IDX) - Returns a single element from VECTOR identified by the (potentially...
Definition ISDOpcodes.h:578
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:860
@ FMINNUM
FMINNUM/FMAXNUM - Perform floating-point minimum maximum on two values, following IEEE-754 definition...
@ ANY_EXTEND_VECTOR_INREG
ANY_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register any-extension of the low la...
Definition ISDOpcodes.h:909
@ SIGN_EXTEND_INREG
SIGN_EXTEND_INREG - This operator atomically performs a SHL/SRA pair to sign extend a small value in ...
Definition ISDOpcodes.h:898
@ SMIN
[US]{MIN/MAX} - Binary minimum or maximum of signed or unsigned integers.
Definition ISDOpcodes.h:729
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
Definition ISDOpcodes.h:988
@ VSELECT
Select with a vector condition (op #0) and two vector operands (ops #1 and #2), returning a vector re...
Definition ISDOpcodes.h:815
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:936
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:741
@ INTRINSIC_WO_CHAIN
RESULT = INTRINSIC_WO_CHAIN(INTRINSICID, arg1, arg2, ...) This node represents a target intrinsic fun...
Definition ISDOpcodes.h:205
@ INSERT_VECTOR_ELT
INSERT_VECTOR_ELT(VECTOR, VAL, IDX) - Returns VECTOR with the element at IDX replaced with VAL.
Definition ISDOpcodes.h:567
@ TokenFactor
TokenFactor - This node takes multiple tokens as input and produces a single token result.
Definition ISDOpcodes.h:53
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:969
@ ZERO_EXTEND_VECTOR_INREG
ZERO_EXTEND_VECTOR_INREG(Vector) - This operator represents an in-register zero-extension of the low ...
Definition ISDOpcodes.h:931
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:866
@ PARTIAL_REDUCE_SUMLA
@ SADDSAT
RESULT = [US]ADDSAT(LHS, RHS) - Perform saturation addition on 2 integers with the same bit width (W)...
Definition ISDOpcodes.h:365
@ FMINIMUMNUM
FMINIMUMNUM/FMAXIMUMNUM - minimumnum/maximumnum that is same with FMINNUM_IEEE and FMAXNUM_IEEE besid...
@ BUILD_VECTOR
BUILD_VECTOR(ELT0, ELT1, ELT2, ELT3,...) - Return a fixed-width vector with the specified,...
Definition ISDOpcodes.h:558
initializer< Ty > init(const Ty &Val)
unsigned getOpcode(const VPValue *V)
Return the instruction opcode for the recipe defining V or 0 for unsupported recipes and VPValues not...
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI bool isNullConstant(SDValue V)
Returns true if V is a constant integer zero.
RelativeUniformCounterPtr Values
Definition InstrProf.h:91
@ 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.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Or
Bitwise or logical OR of integers.
@ And
Bitwise or logical AND of integers.
@ Add
Sum of integers.
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:77
Extended Value Type.
Definition ValueTypes.h:35
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:145
static EVT getVectorVT(LLVMContext &Context, EVT VT, unsigned NumElements, bool IsScalable=false)
Returns the EVT that represents a vector NumElements in length, where each element is of type VT.
Definition ValueTypes.h:70
ElementCount getVectorElementCount() const
Definition ValueTypes.h:373
EVT getDoubleNumVectorElementsVT(LLVMContext &Context) const
Definition ValueTypes.h:494
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
uint64_t getFixedSizeInBits() const
Return the size of the specified fixed width value type in bits.
Definition ValueTypes.h:404
bool isVector() const
Return true if this is a vector value type.
Definition ValueTypes.h:176
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:351
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.
MachinePointerInfo getWithOffset(int64_t O) const