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