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