xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonISelLoweringHVX.cpp (revision 1db9f3b21e39176dd5b67cf8ac378633b172463e)
10b57cec5SDimitry Andric //===-- HexagonISelLoweringHVX.cpp --- Lowering HVX operations ------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "HexagonISelLowering.h"
100b57cec5SDimitry Andric #include "HexagonRegisterInfo.h"
110b57cec5SDimitry Andric #include "HexagonSubtarget.h"
12bdd1243dSDimitry Andric #include "llvm/ADT/SetVector.h"
13bdd1243dSDimitry Andric #include "llvm/ADT/SmallVector.h"
144824e7fdSDimitry Andric #include "llvm/Analysis/MemoryLocation.h"
15bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
16bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
17bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
18bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
19bdd1243dSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
20bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
215ffd83dbSDimitry Andric #include "llvm/IR/IntrinsicsHexagon.h"
220b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
230b57cec5SDimitry Andric 
24bdd1243dSDimitry Andric #include <algorithm>
25bdd1243dSDimitry Andric #include <string>
26bdd1243dSDimitry Andric #include <utility>
27bdd1243dSDimitry Andric 
280b57cec5SDimitry Andric using namespace llvm;
290b57cec5SDimitry Andric 
30e8d8bef9SDimitry Andric static cl::opt<unsigned> HvxWidenThreshold("hexagon-hvx-widen",
31e8d8bef9SDimitry Andric   cl::Hidden, cl::init(16),
32e8d8bef9SDimitry Andric   cl::desc("Lower threshold (in bytes) for widening to HVX vectors"));
33e8d8bef9SDimitry Andric 
340b57cec5SDimitry Andric static const MVT LegalV64[] =  { MVT::v64i8,  MVT::v32i16,  MVT::v16i32 };
350b57cec5SDimitry Andric static const MVT LegalW64[] =  { MVT::v128i8, MVT::v64i16,  MVT::v32i32 };
360b57cec5SDimitry Andric static const MVT LegalV128[] = { MVT::v128i8, MVT::v64i16,  MVT::v32i32 };
370b57cec5SDimitry Andric static const MVT LegalW128[] = { MVT::v256i8, MVT::v128i16, MVT::v64i32 };
380b57cec5SDimitry Andric 
39bdd1243dSDimitry Andric static std::tuple<unsigned, unsigned, unsigned> getIEEEProperties(MVT Ty) {
40bdd1243dSDimitry Andric   // For a float scalar type, return (exp-bits, exp-bias, fraction-bits)
41bdd1243dSDimitry Andric   MVT ElemTy = Ty.getScalarType();
42bdd1243dSDimitry Andric   switch (ElemTy.SimpleTy) {
43bdd1243dSDimitry Andric     case MVT::f16:
44bdd1243dSDimitry Andric       return std::make_tuple(5, 15, 10);
45bdd1243dSDimitry Andric     case MVT::f32:
46bdd1243dSDimitry Andric       return std::make_tuple(8, 127, 23);
47bdd1243dSDimitry Andric     case MVT::f64:
48bdd1243dSDimitry Andric       return std::make_tuple(11, 1023, 52);
49bdd1243dSDimitry Andric     default:
50bdd1243dSDimitry Andric       break;
51bdd1243dSDimitry Andric   }
52bdd1243dSDimitry Andric   llvm_unreachable(("Unexpected type: " + EVT(ElemTy).getEVTString()).c_str());
53bdd1243dSDimitry Andric }
54bdd1243dSDimitry Andric 
550b57cec5SDimitry Andric void
560b57cec5SDimitry Andric HexagonTargetLowering::initializeHVXLowering() {
570b57cec5SDimitry Andric   if (Subtarget.useHVX64BOps()) {
580b57cec5SDimitry Andric     addRegisterClass(MVT::v64i8,  &Hexagon::HvxVRRegClass);
590b57cec5SDimitry Andric     addRegisterClass(MVT::v32i16, &Hexagon::HvxVRRegClass);
600b57cec5SDimitry Andric     addRegisterClass(MVT::v16i32, &Hexagon::HvxVRRegClass);
610b57cec5SDimitry Andric     addRegisterClass(MVT::v128i8, &Hexagon::HvxWRRegClass);
620b57cec5SDimitry Andric     addRegisterClass(MVT::v64i16, &Hexagon::HvxWRRegClass);
630b57cec5SDimitry Andric     addRegisterClass(MVT::v32i32, &Hexagon::HvxWRRegClass);
640b57cec5SDimitry Andric     // These "short" boolean vector types should be legal because
650b57cec5SDimitry Andric     // they will appear as results of vector compares. If they were
660b57cec5SDimitry Andric     // not legal, type legalization would try to make them legal
670b57cec5SDimitry Andric     // and that would require using operations that do not use or
680b57cec5SDimitry Andric     // produce such types. That, in turn, would imply using custom
690b57cec5SDimitry Andric     // nodes, which would be unoptimizable by the DAG combiner.
700b57cec5SDimitry Andric     // The idea is to rely on target-independent operations as much
710b57cec5SDimitry Andric     // as possible.
720b57cec5SDimitry Andric     addRegisterClass(MVT::v16i1, &Hexagon::HvxQRRegClass);
730b57cec5SDimitry Andric     addRegisterClass(MVT::v32i1, &Hexagon::HvxQRRegClass);
740b57cec5SDimitry Andric     addRegisterClass(MVT::v64i1, &Hexagon::HvxQRRegClass);
750b57cec5SDimitry Andric   } else if (Subtarget.useHVX128BOps()) {
760b57cec5SDimitry Andric     addRegisterClass(MVT::v128i8,  &Hexagon::HvxVRRegClass);
770b57cec5SDimitry Andric     addRegisterClass(MVT::v64i16,  &Hexagon::HvxVRRegClass);
780b57cec5SDimitry Andric     addRegisterClass(MVT::v32i32,  &Hexagon::HvxVRRegClass);
790b57cec5SDimitry Andric     addRegisterClass(MVT::v256i8,  &Hexagon::HvxWRRegClass);
800b57cec5SDimitry Andric     addRegisterClass(MVT::v128i16, &Hexagon::HvxWRRegClass);
810b57cec5SDimitry Andric     addRegisterClass(MVT::v64i32,  &Hexagon::HvxWRRegClass);
820b57cec5SDimitry Andric     addRegisterClass(MVT::v32i1, &Hexagon::HvxQRRegClass);
830b57cec5SDimitry Andric     addRegisterClass(MVT::v64i1, &Hexagon::HvxQRRegClass);
840b57cec5SDimitry Andric     addRegisterClass(MVT::v128i1, &Hexagon::HvxQRRegClass);
8504eeddc0SDimitry Andric     if (Subtarget.useHVXV68Ops() && Subtarget.useHVXFloatingPoint()) {
8604eeddc0SDimitry Andric       addRegisterClass(MVT::v32f32, &Hexagon::HvxVRRegClass);
8704eeddc0SDimitry Andric       addRegisterClass(MVT::v64f16, &Hexagon::HvxVRRegClass);
8804eeddc0SDimitry Andric       addRegisterClass(MVT::v64f32, &Hexagon::HvxWRRegClass);
8904eeddc0SDimitry Andric       addRegisterClass(MVT::v128f16, &Hexagon::HvxWRRegClass);
9004eeddc0SDimitry Andric     }
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   // Set up operation actions.
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   bool Use64b = Subtarget.useHVX64BOps();
960b57cec5SDimitry Andric   ArrayRef<MVT> LegalV = Use64b ? LegalV64 : LegalV128;
970b57cec5SDimitry Andric   ArrayRef<MVT> LegalW = Use64b ? LegalW64 : LegalW128;
980b57cec5SDimitry Andric   MVT ByteV = Use64b ?  MVT::v64i8 : MVT::v128i8;
99bdd1243dSDimitry Andric   MVT WordV = Use64b ? MVT::v16i32 : MVT::v32i32;
1000b57cec5SDimitry Andric   MVT ByteW = Use64b ? MVT::v128i8 : MVT::v256i8;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   auto setPromoteTo = [this] (unsigned Opc, MVT FromTy, MVT ToTy) {
1030b57cec5SDimitry Andric     setOperationAction(Opc, FromTy, Promote);
1040b57cec5SDimitry Andric     AddPromotedToType(Opc, FromTy, ToTy);
1050b57cec5SDimitry Andric   };
1060b57cec5SDimitry Andric 
1075ffd83dbSDimitry Andric   // Handle bitcasts of vector predicates to scalars (e.g. v32i1 to i32).
1085ffd83dbSDimitry Andric   // Note: v16i1 -> i16 is handled in type legalization instead of op
1095ffd83dbSDimitry Andric   // legalization.
1105ffd83dbSDimitry Andric   setOperationAction(ISD::BITCAST,              MVT::i16, Custom);
1115ffd83dbSDimitry Andric   setOperationAction(ISD::BITCAST,              MVT::i32, Custom);
1125ffd83dbSDimitry Andric   setOperationAction(ISD::BITCAST,              MVT::i64, Custom);
1135ffd83dbSDimitry Andric   setOperationAction(ISD::BITCAST,            MVT::v16i1, Custom);
1145ffd83dbSDimitry Andric   setOperationAction(ISD::BITCAST,           MVT::v128i1, Custom);
1155ffd83dbSDimitry Andric   setOperationAction(ISD::BITCAST,             MVT::i128, Custom);
1160b57cec5SDimitry Andric   setOperationAction(ISD::VECTOR_SHUFFLE,          ByteV, Legal);
1170b57cec5SDimitry Andric   setOperationAction(ISD::VECTOR_SHUFFLE,          ByteW, Legal);
1185ffd83dbSDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
1190b57cec5SDimitry Andric 
12004eeddc0SDimitry Andric   if (Subtarget.useHVX128BOps() && Subtarget.useHVXV68Ops() &&
12104eeddc0SDimitry Andric       Subtarget.useHVXFloatingPoint()) {
12204eeddc0SDimitry Andric 
12381ad6265SDimitry Andric     static const MVT FloatV[] = { MVT::v64f16, MVT::v32f32 };
12481ad6265SDimitry Andric     static const MVT FloatW[] = { MVT::v128f16, MVT::v64f32 };
12581ad6265SDimitry Andric 
12681ad6265SDimitry Andric     for (MVT T : FloatV) {
12781ad6265SDimitry Andric       setOperationAction(ISD::FADD,              T, Legal);
12881ad6265SDimitry Andric       setOperationAction(ISD::FSUB,              T, Legal);
12981ad6265SDimitry Andric       setOperationAction(ISD::FMUL,              T, Legal);
13081ad6265SDimitry Andric       setOperationAction(ISD::FMINNUM,           T, Legal);
13181ad6265SDimitry Andric       setOperationAction(ISD::FMAXNUM,           T, Legal);
13281ad6265SDimitry Andric 
13381ad6265SDimitry Andric       setOperationAction(ISD::INSERT_SUBVECTOR,  T, Custom);
13481ad6265SDimitry Andric       setOperationAction(ISD::EXTRACT_SUBVECTOR, T, Custom);
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric       setOperationAction(ISD::SPLAT_VECTOR,      T, Legal);
13781ad6265SDimitry Andric       setOperationAction(ISD::SPLAT_VECTOR,      T, Legal);
13881ad6265SDimitry Andric 
13981ad6265SDimitry Andric       setOperationAction(ISD::MLOAD,             T, Custom);
14081ad6265SDimitry Andric       setOperationAction(ISD::MSTORE,            T, Custom);
14181ad6265SDimitry Andric       // Custom-lower BUILD_VECTOR. The standard (target-independent)
14281ad6265SDimitry Andric       // handling of it would convert it to a load, which is not always
14381ad6265SDimitry Andric       // the optimal choice.
14481ad6265SDimitry Andric       setOperationAction(ISD::BUILD_VECTOR,      T, Custom);
14581ad6265SDimitry Andric     }
14681ad6265SDimitry Andric 
14704eeddc0SDimitry Andric 
14804eeddc0SDimitry Andric     // BUILD_VECTOR with f16 operands cannot be promoted without
14904eeddc0SDimitry Andric     // promoting the result, so lower the node to vsplat or constant pool
15004eeddc0SDimitry Andric     setOperationAction(ISD::BUILD_VECTOR,      MVT::f16, Custom);
15104eeddc0SDimitry Andric     setOperationAction(ISD::INSERT_VECTOR_ELT, MVT::f16, Custom);
15204eeddc0SDimitry Andric     setOperationAction(ISD::SPLAT_VECTOR,      MVT::f16, Custom);
15381ad6265SDimitry Andric 
15404eeddc0SDimitry Andric     // Vector shuffle is always promoted to ByteV and a bitcast to f16 is
15504eeddc0SDimitry Andric     // generated.
156fb03ea46SDimitry Andric     setPromoteTo(ISD::VECTOR_SHUFFLE, MVT::v128f16, ByteW);
15704eeddc0SDimitry Andric     setPromoteTo(ISD::VECTOR_SHUFFLE,  MVT::v64f16, ByteV);
15804eeddc0SDimitry Andric     setPromoteTo(ISD::VECTOR_SHUFFLE,  MVT::v64f32, ByteW);
15904eeddc0SDimitry Andric     setPromoteTo(ISD::VECTOR_SHUFFLE,  MVT::v32f32, ByteV);
16004eeddc0SDimitry Andric 
16181ad6265SDimitry Andric     for (MVT P : FloatW) {
16281ad6265SDimitry Andric       setOperationAction(ISD::LOAD,           P, Custom);
16381ad6265SDimitry Andric       setOperationAction(ISD::STORE,          P, Custom);
16481ad6265SDimitry Andric       setOperationAction(ISD::FADD,           P, Custom);
16581ad6265SDimitry Andric       setOperationAction(ISD::FSUB,           P, Custom);
16681ad6265SDimitry Andric       setOperationAction(ISD::FMUL,           P, Custom);
16781ad6265SDimitry Andric       setOperationAction(ISD::FMINNUM,        P, Custom);
16881ad6265SDimitry Andric       setOperationAction(ISD::FMAXNUM,        P, Custom);
16906c3fb27SDimitry Andric       setOperationAction(ISD::SETCC,          P, Custom);
17081ad6265SDimitry Andric       setOperationAction(ISD::VSELECT,        P, Custom);
17104eeddc0SDimitry Andric 
17281ad6265SDimitry Andric       // Custom-lower BUILD_VECTOR. The standard (target-independent)
17381ad6265SDimitry Andric       // handling of it would convert it to a load, which is not always
17481ad6265SDimitry Andric       // the optimal choice.
17581ad6265SDimitry Andric       setOperationAction(ISD::BUILD_VECTOR,   P, Custom);
17681ad6265SDimitry Andric       // Make concat-vectors custom to handle concats of more than 2 vectors.
17781ad6265SDimitry Andric       setOperationAction(ISD::CONCAT_VECTORS, P, Custom);
17881ad6265SDimitry Andric 
17981ad6265SDimitry Andric       setOperationAction(ISD::MLOAD,          P, Custom);
18081ad6265SDimitry Andric       setOperationAction(ISD::MSTORE,         P, Custom);
18181ad6265SDimitry Andric     }
18204eeddc0SDimitry Andric 
18304eeddc0SDimitry Andric     if (Subtarget.useHVXQFloatOps()) {
18404eeddc0SDimitry Andric       setOperationAction(ISD::FP_EXTEND, MVT::v64f32, Custom);
18504eeddc0SDimitry Andric       setOperationAction(ISD::FP_ROUND,  MVT::v64f16, Legal);
18604eeddc0SDimitry Andric     } else if (Subtarget.useHVXIEEEFPOps()) {
18704eeddc0SDimitry Andric       setOperationAction(ISD::FP_EXTEND, MVT::v64f32, Legal);
18804eeddc0SDimitry Andric       setOperationAction(ISD::FP_ROUND,  MVT::v64f16, Legal);
18904eeddc0SDimitry Andric     }
19004eeddc0SDimitry Andric   }
19104eeddc0SDimitry Andric 
1920b57cec5SDimitry Andric   for (MVT T : LegalV) {
1930b57cec5SDimitry Andric     setIndexedLoadAction(ISD::POST_INC,  T, Legal);
1940b57cec5SDimitry Andric     setIndexedStoreAction(ISD::POST_INC, T, Legal);
1950b57cec5SDimitry Andric 
196bdd1243dSDimitry Andric     setOperationAction(ISD::ABS,            T, Legal);
1970b57cec5SDimitry Andric     setOperationAction(ISD::AND,            T, Legal);
1980b57cec5SDimitry Andric     setOperationAction(ISD::OR,             T, Legal);
1990b57cec5SDimitry Andric     setOperationAction(ISD::XOR,            T, Legal);
2000b57cec5SDimitry Andric     setOperationAction(ISD::ADD,            T, Legal);
2010b57cec5SDimitry Andric     setOperationAction(ISD::SUB,            T, Legal);
202e8d8bef9SDimitry Andric     setOperationAction(ISD::MUL,            T, Legal);
2030b57cec5SDimitry Andric     setOperationAction(ISD::CTPOP,          T, Legal);
2040b57cec5SDimitry Andric     setOperationAction(ISD::CTLZ,           T, Legal);
205e8d8bef9SDimitry Andric     setOperationAction(ISD::SELECT,         T, Legal);
206e8d8bef9SDimitry Andric     setOperationAction(ISD::SPLAT_VECTOR,   T, Legal);
2070b57cec5SDimitry Andric     if (T != ByteV) {
2080b57cec5SDimitry Andric       setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, T, Legal);
2090b57cec5SDimitry Andric       setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG, T, Legal);
2100b57cec5SDimitry Andric       setOperationAction(ISD::BSWAP,                    T, Legal);
2110b57cec5SDimitry Andric     }
2120b57cec5SDimitry Andric 
213e8d8bef9SDimitry Andric     setOperationAction(ISD::SMIN,           T, Legal);
214e8d8bef9SDimitry Andric     setOperationAction(ISD::SMAX,           T, Legal);
215e8d8bef9SDimitry Andric     if (T.getScalarType() != MVT::i32) {
216e8d8bef9SDimitry Andric       setOperationAction(ISD::UMIN,         T, Legal);
217e8d8bef9SDimitry Andric       setOperationAction(ISD::UMAX,         T, Legal);
218e8d8bef9SDimitry Andric     }
219e8d8bef9SDimitry Andric 
2200b57cec5SDimitry Andric     setOperationAction(ISD::CTTZ,               T, Custom);
2210b57cec5SDimitry Andric     setOperationAction(ISD::LOAD,               T, Custom);
222e8d8bef9SDimitry Andric     setOperationAction(ISD::MLOAD,              T, Custom);
223e8d8bef9SDimitry Andric     setOperationAction(ISD::MSTORE,             T, Custom);
224bdd1243dSDimitry Andric     if (T.getScalarType() != MVT::i32) {
225bdd1243dSDimitry Andric       setOperationAction(ISD::MULHS,              T, Legal);
226bdd1243dSDimitry Andric       setOperationAction(ISD::MULHU,              T, Legal);
227bdd1243dSDimitry Andric     }
228bdd1243dSDimitry Andric 
2290b57cec5SDimitry Andric     setOperationAction(ISD::BUILD_VECTOR,       T, Custom);
2300b57cec5SDimitry Andric     // Make concat-vectors custom to handle concats of more than 2 vectors.
2310b57cec5SDimitry Andric     setOperationAction(ISD::CONCAT_VECTORS,     T, Custom);
2320b57cec5SDimitry Andric     setOperationAction(ISD::INSERT_SUBVECTOR,   T, Custom);
2330b57cec5SDimitry Andric     setOperationAction(ISD::INSERT_VECTOR_ELT,  T, Custom);
2340b57cec5SDimitry Andric     setOperationAction(ISD::EXTRACT_SUBVECTOR,  T, Custom);
2350b57cec5SDimitry Andric     setOperationAction(ISD::EXTRACT_VECTOR_ELT, T, Custom);
2360b57cec5SDimitry Andric     setOperationAction(ISD::ANY_EXTEND,         T, Custom);
2370b57cec5SDimitry Andric     setOperationAction(ISD::SIGN_EXTEND,        T, Custom);
2380b57cec5SDimitry Andric     setOperationAction(ISD::ZERO_EXTEND,        T, Custom);
239bdd1243dSDimitry Andric     setOperationAction(ISD::FSHL,               T, Custom);
240bdd1243dSDimitry Andric     setOperationAction(ISD::FSHR,               T, Custom);
2410b57cec5SDimitry Andric     if (T != ByteV) {
2420b57cec5SDimitry Andric       setOperationAction(ISD::ANY_EXTEND_VECTOR_INREG, T, Custom);
2430b57cec5SDimitry Andric       // HVX only has shifts of words and halfwords.
2440b57cec5SDimitry Andric       setOperationAction(ISD::SRA,                     T, Custom);
2450b57cec5SDimitry Andric       setOperationAction(ISD::SHL,                     T, Custom);
2460b57cec5SDimitry Andric       setOperationAction(ISD::SRL,                     T, Custom);
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric       // Promote all shuffles to operate on vectors of bytes.
2490b57cec5SDimitry Andric       setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteV);
2500b57cec5SDimitry Andric     }
2510b57cec5SDimitry Andric 
252bdd1243dSDimitry Andric     if (Subtarget.useHVXFloatingPoint()) {
253bdd1243dSDimitry Andric       // Same action for both QFloat and IEEE.
25404eeddc0SDimitry Andric       setOperationAction(ISD::SINT_TO_FP, T, Custom);
25504eeddc0SDimitry Andric       setOperationAction(ISD::UINT_TO_FP, T, Custom);
25604eeddc0SDimitry Andric       setOperationAction(ISD::FP_TO_SINT, T, Custom);
25704eeddc0SDimitry Andric       setOperationAction(ISD::FP_TO_UINT, T, Custom);
25804eeddc0SDimitry Andric     }
25904eeddc0SDimitry Andric 
2600b57cec5SDimitry Andric     setCondCodeAction(ISD::SETNE,  T, Expand);
2610b57cec5SDimitry Andric     setCondCodeAction(ISD::SETLE,  T, Expand);
2620b57cec5SDimitry Andric     setCondCodeAction(ISD::SETGE,  T, Expand);
2630b57cec5SDimitry Andric     setCondCodeAction(ISD::SETLT,  T, Expand);
2640b57cec5SDimitry Andric     setCondCodeAction(ISD::SETULE, T, Expand);
2650b57cec5SDimitry Andric     setCondCodeAction(ISD::SETUGE, T, Expand);
2660b57cec5SDimitry Andric     setCondCodeAction(ISD::SETULT, T, Expand);
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   for (MVT T : LegalW) {
2700b57cec5SDimitry Andric     // Custom-lower BUILD_VECTOR for vector pairs. The standard (target-
2710b57cec5SDimitry Andric     // independent) handling of it would convert it to a load, which is
2720b57cec5SDimitry Andric     // not always the optimal choice.
2730b57cec5SDimitry Andric     setOperationAction(ISD::BUILD_VECTOR,   T, Custom);
2740b57cec5SDimitry Andric     // Make concat-vectors custom to handle concats of more than 2 vectors.
2750b57cec5SDimitry Andric     setOperationAction(ISD::CONCAT_VECTORS, T, Custom);
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric     // Custom-lower these operations for pairs. Expand them into a concat
2780b57cec5SDimitry Andric     // of the corresponding operations on individual vectors.
2790b57cec5SDimitry Andric     setOperationAction(ISD::ANY_EXTEND,               T, Custom);
2800b57cec5SDimitry Andric     setOperationAction(ISD::SIGN_EXTEND,              T, Custom);
2810b57cec5SDimitry Andric     setOperationAction(ISD::ZERO_EXTEND,              T, Custom);
2820b57cec5SDimitry Andric     setOperationAction(ISD::SIGN_EXTEND_INREG,        T, Custom);
2830b57cec5SDimitry Andric     setOperationAction(ISD::ANY_EXTEND_VECTOR_INREG,  T, Custom);
2840b57cec5SDimitry Andric     setOperationAction(ISD::SIGN_EXTEND_VECTOR_INREG, T, Legal);
2850b57cec5SDimitry Andric     setOperationAction(ISD::ZERO_EXTEND_VECTOR_INREG, T, Legal);
286e8d8bef9SDimitry Andric     setOperationAction(ISD::SPLAT_VECTOR,             T, Custom);
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric     setOperationAction(ISD::LOAD,     T, Custom);
2890b57cec5SDimitry Andric     setOperationAction(ISD::STORE,    T, Custom);
290e8d8bef9SDimitry Andric     setOperationAction(ISD::MLOAD,    T, Custom);
291e8d8bef9SDimitry Andric     setOperationAction(ISD::MSTORE,   T, Custom);
292bdd1243dSDimitry Andric     setOperationAction(ISD::ABS,      T, Custom);
2930b57cec5SDimitry Andric     setOperationAction(ISD::CTLZ,     T, Custom);
2940b57cec5SDimitry Andric     setOperationAction(ISD::CTTZ,     T, Custom);
2950b57cec5SDimitry Andric     setOperationAction(ISD::CTPOP,    T, Custom);
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric     setOperationAction(ISD::ADD,      T, Legal);
2980b57cec5SDimitry Andric     setOperationAction(ISD::SUB,      T, Legal);
2990b57cec5SDimitry Andric     setOperationAction(ISD::MUL,      T, Custom);
3000b57cec5SDimitry Andric     setOperationAction(ISD::MULHS,    T, Custom);
3010b57cec5SDimitry Andric     setOperationAction(ISD::MULHU,    T, Custom);
3020b57cec5SDimitry Andric     setOperationAction(ISD::AND,      T, Custom);
3030b57cec5SDimitry Andric     setOperationAction(ISD::OR,       T, Custom);
3040b57cec5SDimitry Andric     setOperationAction(ISD::XOR,      T, Custom);
3050b57cec5SDimitry Andric     setOperationAction(ISD::SETCC,    T, Custom);
3060b57cec5SDimitry Andric     setOperationAction(ISD::VSELECT,  T, Custom);
3070b57cec5SDimitry Andric     if (T != ByteW) {
3080b57cec5SDimitry Andric       setOperationAction(ISD::SRA,      T, Custom);
3090b57cec5SDimitry Andric       setOperationAction(ISD::SHL,      T, Custom);
3100b57cec5SDimitry Andric       setOperationAction(ISD::SRL,      T, Custom);
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric       // Promote all shuffles to operate on vectors of bytes.
3130b57cec5SDimitry Andric       setPromoteTo(ISD::VECTOR_SHUFFLE, T, ByteW);
3140b57cec5SDimitry Andric     }
315bdd1243dSDimitry Andric     setOperationAction(ISD::FSHL,     T, Custom);
316bdd1243dSDimitry Andric     setOperationAction(ISD::FSHR,     T, Custom);
317e8d8bef9SDimitry Andric 
318e8d8bef9SDimitry Andric     setOperationAction(ISD::SMIN,     T, Custom);
319e8d8bef9SDimitry Andric     setOperationAction(ISD::SMAX,     T, Custom);
320e8d8bef9SDimitry Andric     if (T.getScalarType() != MVT::i32) {
321e8d8bef9SDimitry Andric       setOperationAction(ISD::UMIN,     T, Custom);
322e8d8bef9SDimitry Andric       setOperationAction(ISD::UMAX,     T, Custom);
323e8d8bef9SDimitry Andric     }
32404eeddc0SDimitry Andric 
325bdd1243dSDimitry Andric     if (Subtarget.useHVXFloatingPoint()) {
326bdd1243dSDimitry Andric       // Same action for both QFloat and IEEE.
32704eeddc0SDimitry Andric       setOperationAction(ISD::SINT_TO_FP, T, Custom);
32804eeddc0SDimitry Andric       setOperationAction(ISD::UINT_TO_FP, T, Custom);
32904eeddc0SDimitry Andric       setOperationAction(ISD::FP_TO_SINT, T, Custom);
33004eeddc0SDimitry Andric       setOperationAction(ISD::FP_TO_UINT, T, Custom);
3310b57cec5SDimitry Andric     }
332bdd1243dSDimitry Andric   }
333bdd1243dSDimitry Andric 
334bdd1243dSDimitry Andric   // Legalize all of these to HexagonISD::[SU]MUL_LOHI.
335bdd1243dSDimitry Andric   setOperationAction(ISD::MULHS,      WordV, Custom); // -> _LOHI
336bdd1243dSDimitry Andric   setOperationAction(ISD::MULHU,      WordV, Custom); // -> _LOHI
337bdd1243dSDimitry Andric   setOperationAction(ISD::SMUL_LOHI,  WordV, Custom);
338bdd1243dSDimitry Andric   setOperationAction(ISD::UMUL_LOHI,  WordV, Custom);
3390b57cec5SDimitry Andric 
34004eeddc0SDimitry Andric   setCondCodeAction(ISD::SETNE,  MVT::v64f16, Expand);
34104eeddc0SDimitry Andric   setCondCodeAction(ISD::SETLE,  MVT::v64f16, Expand);
34204eeddc0SDimitry Andric   setCondCodeAction(ISD::SETGE,  MVT::v64f16, Expand);
34304eeddc0SDimitry Andric   setCondCodeAction(ISD::SETLT,  MVT::v64f16, Expand);
34404eeddc0SDimitry Andric   setCondCodeAction(ISD::SETONE, MVT::v64f16, Expand);
34504eeddc0SDimitry Andric   setCondCodeAction(ISD::SETOLE, MVT::v64f16, Expand);
34604eeddc0SDimitry Andric   setCondCodeAction(ISD::SETOGE, MVT::v64f16, Expand);
34704eeddc0SDimitry Andric   setCondCodeAction(ISD::SETOLT, MVT::v64f16, Expand);
34804eeddc0SDimitry Andric   setCondCodeAction(ISD::SETUNE, MVT::v64f16, Expand);
34904eeddc0SDimitry Andric   setCondCodeAction(ISD::SETULE, MVT::v64f16, Expand);
35004eeddc0SDimitry Andric   setCondCodeAction(ISD::SETUGE, MVT::v64f16, Expand);
35104eeddc0SDimitry Andric   setCondCodeAction(ISD::SETULT, MVT::v64f16, Expand);
35204eeddc0SDimitry Andric 
35304eeddc0SDimitry Andric   setCondCodeAction(ISD::SETNE,  MVT::v32f32, Expand);
35404eeddc0SDimitry Andric   setCondCodeAction(ISD::SETLE,  MVT::v32f32, Expand);
35504eeddc0SDimitry Andric   setCondCodeAction(ISD::SETGE,  MVT::v32f32, Expand);
35604eeddc0SDimitry Andric   setCondCodeAction(ISD::SETLT,  MVT::v32f32, Expand);
35704eeddc0SDimitry Andric   setCondCodeAction(ISD::SETONE, MVT::v32f32, Expand);
35804eeddc0SDimitry Andric   setCondCodeAction(ISD::SETOLE, MVT::v32f32, Expand);
35904eeddc0SDimitry Andric   setCondCodeAction(ISD::SETOGE, MVT::v32f32, Expand);
36004eeddc0SDimitry Andric   setCondCodeAction(ISD::SETOLT, MVT::v32f32, Expand);
36104eeddc0SDimitry Andric   setCondCodeAction(ISD::SETUNE, MVT::v32f32, Expand);
36204eeddc0SDimitry Andric   setCondCodeAction(ISD::SETULE, MVT::v32f32, Expand);
36304eeddc0SDimitry Andric   setCondCodeAction(ISD::SETUGE, MVT::v32f32, Expand);
36404eeddc0SDimitry Andric   setCondCodeAction(ISD::SETULT, MVT::v32f32, Expand);
36504eeddc0SDimitry Andric 
3660b57cec5SDimitry Andric   // Boolean vectors.
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   for (MVT T : LegalW) {
3690b57cec5SDimitry Andric     // Boolean types for vector pairs will overlap with the boolean
3700b57cec5SDimitry Andric     // types for single vectors, e.g.
3710b57cec5SDimitry Andric     //   v64i8  -> v64i1 (single)
3720b57cec5SDimitry Andric     //   v64i16 -> v64i1 (pair)
3730b57cec5SDimitry Andric     // Set these actions first, and allow the single actions to overwrite
3740b57cec5SDimitry Andric     // any duplicates.
3750b57cec5SDimitry Andric     MVT BoolW = MVT::getVectorVT(MVT::i1, T.getVectorNumElements());
3760b57cec5SDimitry Andric     setOperationAction(ISD::SETCC,              BoolW, Custom);
3770b57cec5SDimitry Andric     setOperationAction(ISD::AND,                BoolW, Custom);
3780b57cec5SDimitry Andric     setOperationAction(ISD::OR,                 BoolW, Custom);
3790b57cec5SDimitry Andric     setOperationAction(ISD::XOR,                BoolW, Custom);
380e8d8bef9SDimitry Andric     // Masked load/store takes a mask that may need splitting.
381e8d8bef9SDimitry Andric     setOperationAction(ISD::MLOAD,              BoolW, Custom);
382e8d8bef9SDimitry Andric     setOperationAction(ISD::MSTORE,             BoolW, Custom);
3830b57cec5SDimitry Andric   }
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   for (MVT T : LegalV) {
3860b57cec5SDimitry Andric     MVT BoolV = MVT::getVectorVT(MVT::i1, T.getVectorNumElements());
3870b57cec5SDimitry Andric     setOperationAction(ISD::BUILD_VECTOR,       BoolV, Custom);
3880b57cec5SDimitry Andric     setOperationAction(ISD::CONCAT_VECTORS,     BoolV, Custom);
3890b57cec5SDimitry Andric     setOperationAction(ISD::INSERT_SUBVECTOR,   BoolV, Custom);
3900b57cec5SDimitry Andric     setOperationAction(ISD::INSERT_VECTOR_ELT,  BoolV, Custom);
3910b57cec5SDimitry Andric     setOperationAction(ISD::EXTRACT_SUBVECTOR,  BoolV, Custom);
3920b57cec5SDimitry Andric     setOperationAction(ISD::EXTRACT_VECTOR_ELT, BoolV, Custom);
393e8d8bef9SDimitry Andric     setOperationAction(ISD::SELECT,             BoolV, Custom);
3940b57cec5SDimitry Andric     setOperationAction(ISD::AND,                BoolV, Legal);
3950b57cec5SDimitry Andric     setOperationAction(ISD::OR,                 BoolV, Legal);
3960b57cec5SDimitry Andric     setOperationAction(ISD::XOR,                BoolV, Legal);
3970b57cec5SDimitry Andric   }
3988bcb0991SDimitry Andric 
3995ffd83dbSDimitry Andric   if (Use64b) {
400480093f4SDimitry Andric     for (MVT T: {MVT::v32i8, MVT::v32i16, MVT::v16i8, MVT::v16i16, MVT::v16i32})
401480093f4SDimitry Andric       setOperationAction(ISD::SIGN_EXTEND_INREG, T, Legal);
4025ffd83dbSDimitry Andric   } else {
403480093f4SDimitry Andric     for (MVT T: {MVT::v64i8, MVT::v64i16, MVT::v32i8, MVT::v32i16, MVT::v32i32})
404480093f4SDimitry Andric       setOperationAction(ISD::SIGN_EXTEND_INREG, T, Legal);
4055ffd83dbSDimitry Andric   }
406480093f4SDimitry Andric 
407e8d8bef9SDimitry Andric   // Handle store widening for short vectors.
408e8d8bef9SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
409e8d8bef9SDimitry Andric   for (MVT ElemTy : Subtarget.getHVXElementTypes()) {
410e8d8bef9SDimitry Andric     if (ElemTy == MVT::i1)
411e8d8bef9SDimitry Andric       continue;
412e8d8bef9SDimitry Andric     int ElemWidth = ElemTy.getFixedSizeInBits();
413e8d8bef9SDimitry Andric     int MaxElems = (8*HwLen) / ElemWidth;
414e8d8bef9SDimitry Andric     for (int N = 2; N < MaxElems; N *= 2) {
415e8d8bef9SDimitry Andric       MVT VecTy = MVT::getVectorVT(ElemTy, N);
416e8d8bef9SDimitry Andric       auto Action = getPreferredVectorAction(VecTy);
417e8d8bef9SDimitry Andric       if (Action == TargetLoweringBase::TypeWidenVector) {
418e8d8bef9SDimitry Andric         setOperationAction(ISD::LOAD,         VecTy, Custom);
419e8d8bef9SDimitry Andric         setOperationAction(ISD::STORE,        VecTy, Custom);
420e8d8bef9SDimitry Andric         setOperationAction(ISD::SETCC,        VecTy, Custom);
421e8d8bef9SDimitry Andric         setOperationAction(ISD::TRUNCATE,     VecTy, Custom);
422e8d8bef9SDimitry Andric         setOperationAction(ISD::ANY_EXTEND,   VecTy, Custom);
423e8d8bef9SDimitry Andric         setOperationAction(ISD::SIGN_EXTEND,  VecTy, Custom);
424e8d8bef9SDimitry Andric         setOperationAction(ISD::ZERO_EXTEND,  VecTy, Custom);
425bdd1243dSDimitry Andric         if (Subtarget.useHVXFloatingPoint()) {
426bdd1243dSDimitry Andric           setOperationAction(ISD::FP_TO_SINT,   VecTy, Custom);
427bdd1243dSDimitry Andric           setOperationAction(ISD::FP_TO_UINT,   VecTy, Custom);
428bdd1243dSDimitry Andric           setOperationAction(ISD::SINT_TO_FP,   VecTy, Custom);
429bdd1243dSDimitry Andric           setOperationAction(ISD::UINT_TO_FP,   VecTy, Custom);
430bdd1243dSDimitry Andric         }
431e8d8bef9SDimitry Andric 
432e8d8bef9SDimitry Andric         MVT BoolTy = MVT::getVectorVT(MVT::i1, N);
433e8d8bef9SDimitry Andric         if (!isTypeLegal(BoolTy))
434e8d8bef9SDimitry Andric           setOperationAction(ISD::SETCC, BoolTy, Custom);
435e8d8bef9SDimitry Andric       }
436e8d8bef9SDimitry Andric     }
437e8d8bef9SDimitry Andric   }
438e8d8bef9SDimitry Andric 
439bdd1243dSDimitry Andric   setTargetDAGCombine({ISD::CONCAT_VECTORS, ISD::TRUNCATE, ISD::VSELECT});
4400b57cec5SDimitry Andric }
4410b57cec5SDimitry Andric 
442e8d8bef9SDimitry Andric unsigned
443e8d8bef9SDimitry Andric HexagonTargetLowering::getPreferredHvxVectorAction(MVT VecTy) const {
444e8d8bef9SDimitry Andric   MVT ElemTy = VecTy.getVectorElementType();
445e8d8bef9SDimitry Andric   unsigned VecLen = VecTy.getVectorNumElements();
446e8d8bef9SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
447e8d8bef9SDimitry Andric 
448e8d8bef9SDimitry Andric   // Split vectors of i1 that exceed byte vector length.
449e8d8bef9SDimitry Andric   if (ElemTy == MVT::i1 && VecLen > HwLen)
450e8d8bef9SDimitry Andric     return TargetLoweringBase::TypeSplitVector;
451e8d8bef9SDimitry Andric 
452e8d8bef9SDimitry Andric   ArrayRef<MVT> Tys = Subtarget.getHVXElementTypes();
453e8d8bef9SDimitry Andric   // For shorter vectors of i1, widen them if any of the corresponding
454e8d8bef9SDimitry Andric   // vectors of integers needs to be widened.
455e8d8bef9SDimitry Andric   if (ElemTy == MVT::i1) {
456e8d8bef9SDimitry Andric     for (MVT T : Tys) {
457e8d8bef9SDimitry Andric       assert(T != MVT::i1);
458e8d8bef9SDimitry Andric       auto A = getPreferredHvxVectorAction(MVT::getVectorVT(T, VecLen));
459e8d8bef9SDimitry Andric       if (A != ~0u)
460e8d8bef9SDimitry Andric         return A;
461e8d8bef9SDimitry Andric     }
462e8d8bef9SDimitry Andric     return ~0u;
463e8d8bef9SDimitry Andric   }
464e8d8bef9SDimitry Andric 
465e8d8bef9SDimitry Andric   // If the size of VecTy is at least half of the vector length,
466e8d8bef9SDimitry Andric   // widen the vector. Note: the threshold was not selected in
467e8d8bef9SDimitry Andric   // any scientific way.
468e8d8bef9SDimitry Andric   if (llvm::is_contained(Tys, ElemTy)) {
469e8d8bef9SDimitry Andric     unsigned VecWidth = VecTy.getSizeInBits();
470bdd1243dSDimitry Andric     unsigned HwWidth = 8*HwLen;
471bdd1243dSDimitry Andric     if (VecWidth > 2*HwWidth)
472bdd1243dSDimitry Andric       return TargetLoweringBase::TypeSplitVector;
473bdd1243dSDimitry Andric 
474e8d8bef9SDimitry Andric     bool HaveThreshold = HvxWidenThreshold.getNumOccurrences() > 0;
475e8d8bef9SDimitry Andric     if (HaveThreshold && 8*HvxWidenThreshold <= VecWidth)
476e8d8bef9SDimitry Andric       return TargetLoweringBase::TypeWidenVector;
477e8d8bef9SDimitry Andric     if (VecWidth >= HwWidth/2 && VecWidth < HwWidth)
478e8d8bef9SDimitry Andric       return TargetLoweringBase::TypeWidenVector;
479e8d8bef9SDimitry Andric   }
480e8d8bef9SDimitry Andric 
481e8d8bef9SDimitry Andric   // Defer to default.
482e8d8bef9SDimitry Andric   return ~0u;
483e8d8bef9SDimitry Andric }
484e8d8bef9SDimitry Andric 
485bdd1243dSDimitry Andric unsigned
486bdd1243dSDimitry Andric HexagonTargetLowering::getCustomHvxOperationAction(SDNode &Op) const {
487bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
488bdd1243dSDimitry Andric   switch (Opc) {
489bdd1243dSDimitry Andric   case HexagonISD::SMUL_LOHI:
490bdd1243dSDimitry Andric   case HexagonISD::UMUL_LOHI:
491bdd1243dSDimitry Andric   case HexagonISD::USMUL_LOHI:
492bdd1243dSDimitry Andric     return TargetLoweringBase::Custom;
493bdd1243dSDimitry Andric   }
494bdd1243dSDimitry Andric   return TargetLoweringBase::Legal;
495bdd1243dSDimitry Andric }
496bdd1243dSDimitry Andric 
4970b57cec5SDimitry Andric SDValue
4980b57cec5SDimitry Andric HexagonTargetLowering::getInt(unsigned IntId, MVT ResTy, ArrayRef<SDValue> Ops,
4990b57cec5SDimitry Andric                               const SDLoc &dl, SelectionDAG &DAG) const {
5000b57cec5SDimitry Andric   SmallVector<SDValue,4> IntOps;
5010b57cec5SDimitry Andric   IntOps.push_back(DAG.getConstant(IntId, dl, MVT::i32));
502e8d8bef9SDimitry Andric   append_range(IntOps, Ops);
5030b57cec5SDimitry Andric   return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, ResTy, IntOps);
5040b57cec5SDimitry Andric }
5050b57cec5SDimitry Andric 
5060b57cec5SDimitry Andric MVT
5070b57cec5SDimitry Andric HexagonTargetLowering::typeJoin(const TypePair &Tys) const {
5080b57cec5SDimitry Andric   assert(Tys.first.getVectorElementType() == Tys.second.getVectorElementType());
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric   MVT ElemTy = Tys.first.getVectorElementType();
5110b57cec5SDimitry Andric   return MVT::getVectorVT(ElemTy, Tys.first.getVectorNumElements() +
5120b57cec5SDimitry Andric                                   Tys.second.getVectorNumElements());
5130b57cec5SDimitry Andric }
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric HexagonTargetLowering::TypePair
5160b57cec5SDimitry Andric HexagonTargetLowering::typeSplit(MVT VecTy) const {
5170b57cec5SDimitry Andric   assert(VecTy.isVector());
5180b57cec5SDimitry Andric   unsigned NumElem = VecTy.getVectorNumElements();
5190b57cec5SDimitry Andric   assert((NumElem % 2) == 0 && "Expecting even-sized vector type");
5200b57cec5SDimitry Andric   MVT HalfTy = MVT::getVectorVT(VecTy.getVectorElementType(), NumElem/2);
5210b57cec5SDimitry Andric   return { HalfTy, HalfTy };
5220b57cec5SDimitry Andric }
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric MVT
5250b57cec5SDimitry Andric HexagonTargetLowering::typeExtElem(MVT VecTy, unsigned Factor) const {
5260b57cec5SDimitry Andric   MVT ElemTy = VecTy.getVectorElementType();
5270b57cec5SDimitry Andric   MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() * Factor);
5280b57cec5SDimitry Andric   return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
5290b57cec5SDimitry Andric }
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric MVT
5320b57cec5SDimitry Andric HexagonTargetLowering::typeTruncElem(MVT VecTy, unsigned Factor) const {
5330b57cec5SDimitry Andric   MVT ElemTy = VecTy.getVectorElementType();
5340b57cec5SDimitry Andric   MVT NewElemTy = MVT::getIntegerVT(ElemTy.getSizeInBits() / Factor);
5350b57cec5SDimitry Andric   return MVT::getVectorVT(NewElemTy, VecTy.getVectorNumElements());
5360b57cec5SDimitry Andric }
5370b57cec5SDimitry Andric 
5380b57cec5SDimitry Andric SDValue
5390b57cec5SDimitry Andric HexagonTargetLowering::opCastElem(SDValue Vec, MVT ElemTy,
5400b57cec5SDimitry Andric                                   SelectionDAG &DAG) const {
5410b57cec5SDimitry Andric   if (ty(Vec).getVectorElementType() == ElemTy)
5420b57cec5SDimitry Andric     return Vec;
5430b57cec5SDimitry Andric   MVT CastTy = tyVector(Vec.getValueType().getSimpleVT(), ElemTy);
5440b57cec5SDimitry Andric   return DAG.getBitcast(CastTy, Vec);
5450b57cec5SDimitry Andric }
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric SDValue
5480b57cec5SDimitry Andric HexagonTargetLowering::opJoin(const VectorPair &Ops, const SDLoc &dl,
5490b57cec5SDimitry Andric                               SelectionDAG &DAG) const {
5500b57cec5SDimitry Andric   return DAG.getNode(ISD::CONCAT_VECTORS, dl, typeJoin(ty(Ops)),
551bdd1243dSDimitry Andric                      Ops.first, Ops.second);
5520b57cec5SDimitry Andric }
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric HexagonTargetLowering::VectorPair
5550b57cec5SDimitry Andric HexagonTargetLowering::opSplit(SDValue Vec, const SDLoc &dl,
5560b57cec5SDimitry Andric                                SelectionDAG &DAG) const {
5570b57cec5SDimitry Andric   TypePair Tys = typeSplit(ty(Vec));
5580b57cec5SDimitry Andric   if (Vec.getOpcode() == HexagonISD::QCAT)
5590b57cec5SDimitry Andric     return VectorPair(Vec.getOperand(0), Vec.getOperand(1));
5600b57cec5SDimitry Andric   return DAG.SplitVector(Vec, dl, Tys.first, Tys.second);
5610b57cec5SDimitry Andric }
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric bool
5640b57cec5SDimitry Andric HexagonTargetLowering::isHvxSingleTy(MVT Ty) const {
5650b57cec5SDimitry Andric   return Subtarget.isHVXVectorType(Ty) &&
5660b57cec5SDimitry Andric          Ty.getSizeInBits() == 8 * Subtarget.getVectorLength();
5670b57cec5SDimitry Andric }
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric bool
5700b57cec5SDimitry Andric HexagonTargetLowering::isHvxPairTy(MVT Ty) const {
5710b57cec5SDimitry Andric   return Subtarget.isHVXVectorType(Ty) &&
5720b57cec5SDimitry Andric          Ty.getSizeInBits() == 16 * Subtarget.getVectorLength();
5730b57cec5SDimitry Andric }
5740b57cec5SDimitry Andric 
5755ffd83dbSDimitry Andric bool
5765ffd83dbSDimitry Andric HexagonTargetLowering::isHvxBoolTy(MVT Ty) const {
5775ffd83dbSDimitry Andric   return Subtarget.isHVXVectorType(Ty, true) &&
5785ffd83dbSDimitry Andric          Ty.getVectorElementType() == MVT::i1;
5795ffd83dbSDimitry Andric }
5805ffd83dbSDimitry Andric 
5815ffd83dbSDimitry Andric bool HexagonTargetLowering::allowsHvxMemoryAccess(
582bdd1243dSDimitry Andric     MVT VecTy, MachineMemOperand::Flags Flags, unsigned *Fast) const {
5835ffd83dbSDimitry Andric   // Bool vectors are excluded by default, but make it explicit to
5845ffd83dbSDimitry Andric   // emphasize that bool vectors cannot be loaded or stored.
5855ffd83dbSDimitry Andric   // Also, disallow double vector stores (to prevent unnecessary
5865ffd83dbSDimitry Andric   // store widening in DAG combiner).
5875ffd83dbSDimitry Andric   if (VecTy.getSizeInBits() > 8*Subtarget.getVectorLength())
5885ffd83dbSDimitry Andric     return false;
5895ffd83dbSDimitry Andric   if (!Subtarget.isHVXVectorType(VecTy, /*IncludeBool=*/false))
5905ffd83dbSDimitry Andric     return false;
5915ffd83dbSDimitry Andric   if (Fast)
592bdd1243dSDimitry Andric     *Fast = 1;
5935ffd83dbSDimitry Andric   return true;
5945ffd83dbSDimitry Andric }
5955ffd83dbSDimitry Andric 
5965ffd83dbSDimitry Andric bool HexagonTargetLowering::allowsHvxMisalignedMemoryAccesses(
597bdd1243dSDimitry Andric     MVT VecTy, MachineMemOperand::Flags Flags, unsigned *Fast) const {
5985ffd83dbSDimitry Andric   if (!Subtarget.isHVXVectorType(VecTy))
5995ffd83dbSDimitry Andric     return false;
6005ffd83dbSDimitry Andric   // XXX Should this be false?  vmemu are a bit slower than vmem.
6015ffd83dbSDimitry Andric   if (Fast)
602bdd1243dSDimitry Andric     *Fast = 1;
6035ffd83dbSDimitry Andric   return true;
6045ffd83dbSDimitry Andric }
6055ffd83dbSDimitry Andric 
606bdd1243dSDimitry Andric void HexagonTargetLowering::AdjustHvxInstrPostInstrSelection(
607bdd1243dSDimitry Andric     MachineInstr &MI, SDNode *Node) const {
608bdd1243dSDimitry Andric   unsigned Opc = MI.getOpcode();
609bdd1243dSDimitry Andric   const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
610bdd1243dSDimitry Andric   MachineBasicBlock &MB = *MI.getParent();
611bdd1243dSDimitry Andric   MachineFunction &MF = *MB.getParent();
612bdd1243dSDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
613bdd1243dSDimitry Andric   DebugLoc DL = MI.getDebugLoc();
614bdd1243dSDimitry Andric   auto At = MI.getIterator();
615bdd1243dSDimitry Andric 
616bdd1243dSDimitry Andric   switch (Opc) {
617bdd1243dSDimitry Andric   case Hexagon::PS_vsplatib:
618bdd1243dSDimitry Andric     if (Subtarget.useHVXV62Ops()) {
619bdd1243dSDimitry Andric       // SplatV = A2_tfrsi #imm
620bdd1243dSDimitry Andric       // OutV = V6_lvsplatb SplatV
621bdd1243dSDimitry Andric       Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
622bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
623bdd1243dSDimitry Andric         .add(MI.getOperand(1));
624bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
625bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatb), OutV)
626bdd1243dSDimitry Andric         .addReg(SplatV);
627bdd1243dSDimitry Andric     } else {
628bdd1243dSDimitry Andric       // SplatV = A2_tfrsi #imm:#imm:#imm:#imm
629bdd1243dSDimitry Andric       // OutV = V6_lvsplatw SplatV
630bdd1243dSDimitry Andric       Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
631bdd1243dSDimitry Andric       const MachineOperand &InpOp = MI.getOperand(1);
632bdd1243dSDimitry Andric       assert(InpOp.isImm());
633bdd1243dSDimitry Andric       uint32_t V = InpOp.getImm() & 0xFF;
634bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
635bdd1243dSDimitry Andric           .addImm(V << 24 | V << 16 | V << 8 | V);
636bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
637bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV).addReg(SplatV);
638bdd1243dSDimitry Andric     }
639bdd1243dSDimitry Andric     MB.erase(At);
640bdd1243dSDimitry Andric     break;
641bdd1243dSDimitry Andric   case Hexagon::PS_vsplatrb:
642bdd1243dSDimitry Andric     if (Subtarget.useHVXV62Ops()) {
643bdd1243dSDimitry Andric       // OutV = V6_lvsplatb Inp
644bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
645bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatb), OutV)
646bdd1243dSDimitry Andric         .add(MI.getOperand(1));
647bdd1243dSDimitry Andric     } else {
648bdd1243dSDimitry Andric       Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
649bdd1243dSDimitry Andric       const MachineOperand &InpOp = MI.getOperand(1);
650bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::S2_vsplatrb), SplatV)
651bdd1243dSDimitry Andric           .addReg(InpOp.getReg(), 0, InpOp.getSubReg());
652bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
653bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV)
654bdd1243dSDimitry Andric           .addReg(SplatV);
655bdd1243dSDimitry Andric     }
656bdd1243dSDimitry Andric     MB.erase(At);
657bdd1243dSDimitry Andric     break;
658bdd1243dSDimitry Andric   case Hexagon::PS_vsplatih:
659bdd1243dSDimitry Andric     if (Subtarget.useHVXV62Ops()) {
660bdd1243dSDimitry Andric       // SplatV = A2_tfrsi #imm
661bdd1243dSDimitry Andric       // OutV = V6_lvsplath SplatV
662bdd1243dSDimitry Andric       Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
663bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
664bdd1243dSDimitry Andric         .add(MI.getOperand(1));
665bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
666bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplath), OutV)
667bdd1243dSDimitry Andric         .addReg(SplatV);
668bdd1243dSDimitry Andric     } else {
669bdd1243dSDimitry Andric       // SplatV = A2_tfrsi #imm:#imm
670bdd1243dSDimitry Andric       // OutV = V6_lvsplatw SplatV
671bdd1243dSDimitry Andric       Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
672bdd1243dSDimitry Andric       const MachineOperand &InpOp = MI.getOperand(1);
673bdd1243dSDimitry Andric       assert(InpOp.isImm());
674bdd1243dSDimitry Andric       uint32_t V = InpOp.getImm() & 0xFFFF;
675bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
676bdd1243dSDimitry Andric           .addImm(V << 16 | V);
677bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
678bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV).addReg(SplatV);
679bdd1243dSDimitry Andric     }
680bdd1243dSDimitry Andric     MB.erase(At);
681bdd1243dSDimitry Andric     break;
682bdd1243dSDimitry Andric   case Hexagon::PS_vsplatrh:
683bdd1243dSDimitry Andric     if (Subtarget.useHVXV62Ops()) {
684bdd1243dSDimitry Andric       // OutV = V6_lvsplath Inp
685bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
686bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplath), OutV)
687bdd1243dSDimitry Andric         .add(MI.getOperand(1));
688bdd1243dSDimitry Andric     } else {
689bdd1243dSDimitry Andric       // SplatV = A2_combine_ll Inp, Inp
690bdd1243dSDimitry Andric       // OutV = V6_lvsplatw SplatV
691bdd1243dSDimitry Andric       Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
692bdd1243dSDimitry Andric       const MachineOperand &InpOp = MI.getOperand(1);
693bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::A2_combine_ll), SplatV)
694bdd1243dSDimitry Andric           .addReg(InpOp.getReg(), 0, InpOp.getSubReg())
695bdd1243dSDimitry Andric           .addReg(InpOp.getReg(), 0, InpOp.getSubReg());
696bdd1243dSDimitry Andric       Register OutV = MI.getOperand(0).getReg();
697bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::V6_lvsplatw), OutV).addReg(SplatV);
698bdd1243dSDimitry Andric     }
699bdd1243dSDimitry Andric     MB.erase(At);
700bdd1243dSDimitry Andric     break;
701bdd1243dSDimitry Andric   case Hexagon::PS_vsplatiw:
702bdd1243dSDimitry Andric   case Hexagon::PS_vsplatrw:
703bdd1243dSDimitry Andric     if (Opc == Hexagon::PS_vsplatiw) {
704bdd1243dSDimitry Andric       // SplatV = A2_tfrsi #imm
705bdd1243dSDimitry Andric       Register SplatV = MRI.createVirtualRegister(&Hexagon::IntRegsRegClass);
706bdd1243dSDimitry Andric       BuildMI(MB, At, DL, TII.get(Hexagon::A2_tfrsi), SplatV)
707bdd1243dSDimitry Andric         .add(MI.getOperand(1));
708bdd1243dSDimitry Andric       MI.getOperand(1).ChangeToRegister(SplatV, false);
709bdd1243dSDimitry Andric     }
710bdd1243dSDimitry Andric     // OutV = V6_lvsplatw SplatV/Inp
711bdd1243dSDimitry Andric     MI.setDesc(TII.get(Hexagon::V6_lvsplatw));
712bdd1243dSDimitry Andric     break;
713bdd1243dSDimitry Andric   }
714bdd1243dSDimitry Andric }
715bdd1243dSDimitry Andric 
7160b57cec5SDimitry Andric SDValue
7170b57cec5SDimitry Andric HexagonTargetLowering::convertToByteIndex(SDValue ElemIdx, MVT ElemTy,
7180b57cec5SDimitry Andric                                           SelectionDAG &DAG) const {
7190b57cec5SDimitry Andric   if (ElemIdx.getValueType().getSimpleVT() != MVT::i32)
7200b57cec5SDimitry Andric     ElemIdx = DAG.getBitcast(MVT::i32, ElemIdx);
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
7230b57cec5SDimitry Andric   if (ElemWidth == 8)
7240b57cec5SDimitry Andric     return ElemIdx;
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric   unsigned L = Log2_32(ElemWidth/8);
7270b57cec5SDimitry Andric   const SDLoc &dl(ElemIdx);
7280b57cec5SDimitry Andric   return DAG.getNode(ISD::SHL, dl, MVT::i32,
7290b57cec5SDimitry Andric                      {ElemIdx, DAG.getConstant(L, dl, MVT::i32)});
7300b57cec5SDimitry Andric }
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric SDValue
7330b57cec5SDimitry Andric HexagonTargetLowering::getIndexInWord32(SDValue Idx, MVT ElemTy,
7340b57cec5SDimitry Andric                                         SelectionDAG &DAG) const {
7350b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
7360b57cec5SDimitry Andric   assert(ElemWidth >= 8 && ElemWidth <= 32);
7370b57cec5SDimitry Andric   if (ElemWidth == 32)
7380b57cec5SDimitry Andric     return Idx;
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   if (ty(Idx) != MVT::i32)
7410b57cec5SDimitry Andric     Idx = DAG.getBitcast(MVT::i32, Idx);
7420b57cec5SDimitry Andric   const SDLoc &dl(Idx);
7430b57cec5SDimitry Andric   SDValue Mask = DAG.getConstant(32/ElemWidth - 1, dl, MVT::i32);
7440b57cec5SDimitry Andric   SDValue SubIdx = DAG.getNode(ISD::AND, dl, MVT::i32, {Idx, Mask});
7450b57cec5SDimitry Andric   return SubIdx;
7460b57cec5SDimitry Andric }
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric SDValue
7490b57cec5SDimitry Andric HexagonTargetLowering::getByteShuffle(const SDLoc &dl, SDValue Op0,
7500b57cec5SDimitry Andric                                       SDValue Op1, ArrayRef<int> Mask,
7510b57cec5SDimitry Andric                                       SelectionDAG &DAG) const {
7520b57cec5SDimitry Andric   MVT OpTy = ty(Op0);
7530b57cec5SDimitry Andric   assert(OpTy == ty(Op1));
7540b57cec5SDimitry Andric 
7550b57cec5SDimitry Andric   MVT ElemTy = OpTy.getVectorElementType();
7560b57cec5SDimitry Andric   if (ElemTy == MVT::i8)
7570b57cec5SDimitry Andric     return DAG.getVectorShuffle(OpTy, dl, Op0, Op1, Mask);
7580b57cec5SDimitry Andric   assert(ElemTy.getSizeInBits() >= 8);
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric   MVT ResTy = tyVector(OpTy, MVT::i8);
7610b57cec5SDimitry Andric   unsigned ElemSize = ElemTy.getSizeInBits() / 8;
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric   SmallVector<int,128> ByteMask;
7640b57cec5SDimitry Andric   for (int M : Mask) {
7650b57cec5SDimitry Andric     if (M < 0) {
7660b57cec5SDimitry Andric       for (unsigned I = 0; I != ElemSize; ++I)
7670b57cec5SDimitry Andric         ByteMask.push_back(-1);
7680b57cec5SDimitry Andric     } else {
7690b57cec5SDimitry Andric       int NewM = M*ElemSize;
7700b57cec5SDimitry Andric       for (unsigned I = 0; I != ElemSize; ++I)
7710b57cec5SDimitry Andric         ByteMask.push_back(NewM+I);
7720b57cec5SDimitry Andric     }
7730b57cec5SDimitry Andric   }
7740b57cec5SDimitry Andric   assert(ResTy.getVectorNumElements() == ByteMask.size());
7750b57cec5SDimitry Andric   return DAG.getVectorShuffle(ResTy, dl, opCastElem(Op0, MVT::i8, DAG),
7760b57cec5SDimitry Andric                               opCastElem(Op1, MVT::i8, DAG), ByteMask);
7770b57cec5SDimitry Andric }
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric SDValue
7800b57cec5SDimitry Andric HexagonTargetLowering::buildHvxVectorReg(ArrayRef<SDValue> Values,
7810b57cec5SDimitry Andric                                          const SDLoc &dl, MVT VecTy,
7820b57cec5SDimitry Andric                                          SelectionDAG &DAG) const {
7830b57cec5SDimitry Andric   unsigned VecLen = Values.size();
7840b57cec5SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
7850b57cec5SDimitry Andric   MVT ElemTy = VecTy.getVectorElementType();
7860b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
7870b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   unsigned ElemSize = ElemWidth / 8;
7900b57cec5SDimitry Andric   assert(ElemSize*VecLen == HwLen);
7910b57cec5SDimitry Andric   SmallVector<SDValue,32> Words;
7920b57cec5SDimitry Andric 
79304eeddc0SDimitry Andric   if (VecTy.getVectorElementType() != MVT::i32 &&
79404eeddc0SDimitry Andric       !(Subtarget.useHVXFloatingPoint() &&
79504eeddc0SDimitry Andric       VecTy.getVectorElementType() == MVT::f32)) {
7960b57cec5SDimitry Andric     assert((ElemSize == 1 || ElemSize == 2) && "Invalid element size");
7970b57cec5SDimitry Andric     unsigned OpsPerWord = (ElemSize == 1) ? 4 : 2;
7980b57cec5SDimitry Andric     MVT PartVT = MVT::getVectorVT(VecTy.getVectorElementType(), OpsPerWord);
7990b57cec5SDimitry Andric     for (unsigned i = 0; i != VecLen; i += OpsPerWord) {
8000b57cec5SDimitry Andric       SDValue W = buildVector32(Values.slice(i, OpsPerWord), dl, PartVT, DAG);
8010b57cec5SDimitry Andric       Words.push_back(DAG.getBitcast(MVT::i32, W));
8020b57cec5SDimitry Andric     }
8030b57cec5SDimitry Andric   } else {
80404eeddc0SDimitry Andric     for (SDValue V : Values)
80504eeddc0SDimitry Andric       Words.push_back(DAG.getBitcast(MVT::i32, V));
8060b57cec5SDimitry Andric   }
80704eeddc0SDimitry Andric   auto isSplat = [] (ArrayRef<SDValue> Values, SDValue &SplatV) {
80804eeddc0SDimitry Andric     unsigned NumValues = Values.size();
80904eeddc0SDimitry Andric     assert(NumValues > 0);
81004eeddc0SDimitry Andric     bool IsUndef = true;
81104eeddc0SDimitry Andric     for (unsigned i = 0; i != NumValues; ++i) {
81204eeddc0SDimitry Andric       if (Values[i].isUndef())
8130b57cec5SDimitry Andric         continue;
8140b57cec5SDimitry Andric       IsUndef = false;
8150b57cec5SDimitry Andric       if (!SplatV.getNode())
81604eeddc0SDimitry Andric         SplatV = Values[i];
81704eeddc0SDimitry Andric       else if (SplatV != Values[i])
81804eeddc0SDimitry Andric         return false;
8190b57cec5SDimitry Andric     }
8200b57cec5SDimitry Andric     if (IsUndef)
82104eeddc0SDimitry Andric       SplatV = Values[0];
82204eeddc0SDimitry Andric     return true;
82304eeddc0SDimitry Andric   };
82404eeddc0SDimitry Andric 
82504eeddc0SDimitry Andric   unsigned NumWords = Words.size();
82604eeddc0SDimitry Andric   SDValue SplatV;
82704eeddc0SDimitry Andric   bool IsSplat = isSplat(Words, SplatV);
82804eeddc0SDimitry Andric   if (IsSplat && isUndef(SplatV))
8290b57cec5SDimitry Andric     return DAG.getUNDEF(VecTy);
8300b57cec5SDimitry Andric   if (IsSplat) {
8310b57cec5SDimitry Andric     assert(SplatV.getNode());
8325f757f3fSDimitry Andric     if (isNullConstant(SplatV))
8330b57cec5SDimitry Andric       return getZero(dl, VecTy, DAG);
834e8d8bef9SDimitry Andric     MVT WordTy = MVT::getVectorVT(MVT::i32, HwLen/4);
835e8d8bef9SDimitry Andric     SDValue S = DAG.getNode(ISD::SPLAT_VECTOR, dl, WordTy, SplatV);
836e8d8bef9SDimitry Andric     return DAG.getBitcast(VecTy, S);
8370b57cec5SDimitry Andric   }
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric   // Delay recognizing constant vectors until here, so that we can generate
8400b57cec5SDimitry Andric   // a vsplat.
8410b57cec5SDimitry Andric   SmallVector<ConstantInt*, 128> Consts(VecLen);
8420b57cec5SDimitry Andric   bool AllConst = getBuildVectorConstInts(Values, VecTy, DAG, Consts);
8430b57cec5SDimitry Andric   if (AllConst) {
8440b57cec5SDimitry Andric     ArrayRef<Constant*> Tmp((Constant**)Consts.begin(),
8450b57cec5SDimitry Andric                             (Constant**)Consts.end());
8460b57cec5SDimitry Andric     Constant *CV = ConstantVector::get(Tmp);
8475ffd83dbSDimitry Andric     Align Alignment(HwLen);
8485ffd83dbSDimitry Andric     SDValue CP =
8495ffd83dbSDimitry Andric         LowerConstantPool(DAG.getConstantPool(CV, VecTy, Alignment), DAG);
8500b57cec5SDimitry Andric     return DAG.getLoad(VecTy, dl, DAG.getEntryNode(), CP,
8515ffd83dbSDimitry Andric                        MachinePointerInfo::getConstantPool(MF), Alignment);
8520b57cec5SDimitry Andric   }
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric   // A special case is a situation where the vector is built entirely from
8550b57cec5SDimitry Andric   // elements extracted from another vector. This could be done via a shuffle
8560b57cec5SDimitry Andric   // more efficiently, but typically, the size of the source vector will not
8570b57cec5SDimitry Andric   // match the size of the vector being built (which precludes the use of a
8580b57cec5SDimitry Andric   // shuffle directly).
8590b57cec5SDimitry Andric   // This only handles a single source vector, and the vector being built
8600b57cec5SDimitry Andric   // should be of a sub-vector type of the source vector type.
8610b57cec5SDimitry Andric   auto IsBuildFromExtracts = [this,&Values] (SDValue &SrcVec,
8620b57cec5SDimitry Andric                                              SmallVectorImpl<int> &SrcIdx) {
8630b57cec5SDimitry Andric     SDValue Vec;
8640b57cec5SDimitry Andric     for (SDValue V : Values) {
8650b57cec5SDimitry Andric       if (isUndef(V)) {
8660b57cec5SDimitry Andric         SrcIdx.push_back(-1);
8670b57cec5SDimitry Andric         continue;
8680b57cec5SDimitry Andric       }
8690b57cec5SDimitry Andric       if (V.getOpcode() != ISD::EXTRACT_VECTOR_ELT)
8700b57cec5SDimitry Andric         return false;
8710b57cec5SDimitry Andric       // All extracts should come from the same vector.
8720b57cec5SDimitry Andric       SDValue T = V.getOperand(0);
8730b57cec5SDimitry Andric       if (Vec.getNode() != nullptr && T.getNode() != Vec.getNode())
8740b57cec5SDimitry Andric         return false;
8750b57cec5SDimitry Andric       Vec = T;
8760b57cec5SDimitry Andric       ConstantSDNode *C = dyn_cast<ConstantSDNode>(V.getOperand(1));
8770b57cec5SDimitry Andric       if (C == nullptr)
8780b57cec5SDimitry Andric         return false;
8790b57cec5SDimitry Andric       int I = C->getSExtValue();
8800b57cec5SDimitry Andric       assert(I >= 0 && "Negative element index");
8810b57cec5SDimitry Andric       SrcIdx.push_back(I);
8820b57cec5SDimitry Andric     }
8830b57cec5SDimitry Andric     SrcVec = Vec;
8840b57cec5SDimitry Andric     return true;
8850b57cec5SDimitry Andric   };
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric   SmallVector<int,128> ExtIdx;
8880b57cec5SDimitry Andric   SDValue ExtVec;
8890b57cec5SDimitry Andric   if (IsBuildFromExtracts(ExtVec, ExtIdx)) {
8900b57cec5SDimitry Andric     MVT ExtTy = ty(ExtVec);
8910b57cec5SDimitry Andric     unsigned ExtLen = ExtTy.getVectorNumElements();
8920b57cec5SDimitry Andric     if (ExtLen == VecLen || ExtLen == 2*VecLen) {
8930b57cec5SDimitry Andric       // Construct a new shuffle mask that will produce a vector with the same
8940b57cec5SDimitry Andric       // number of elements as the input vector, and such that the vector we
8950b57cec5SDimitry Andric       // want will be the initial subvector of it.
8960b57cec5SDimitry Andric       SmallVector<int,128> Mask;
8970b57cec5SDimitry Andric       BitVector Used(ExtLen);
8980b57cec5SDimitry Andric 
8990b57cec5SDimitry Andric       for (int M : ExtIdx) {
9000b57cec5SDimitry Andric         Mask.push_back(M);
9010b57cec5SDimitry Andric         if (M >= 0)
9020b57cec5SDimitry Andric           Used.set(M);
9030b57cec5SDimitry Andric       }
9040b57cec5SDimitry Andric       // Fill the rest of the mask with the unused elements of ExtVec in hopes
9050b57cec5SDimitry Andric       // that it will result in a permutation of ExtVec's elements. It's still
9060b57cec5SDimitry Andric       // fine if it doesn't (e.g. if undefs are present, or elements are
9070b57cec5SDimitry Andric       // repeated), but permutations can always be done efficiently via vdelta
9080b57cec5SDimitry Andric       // and vrdelta.
9090b57cec5SDimitry Andric       for (unsigned I = 0; I != ExtLen; ++I) {
9100b57cec5SDimitry Andric         if (Mask.size() == ExtLen)
9110b57cec5SDimitry Andric           break;
9120b57cec5SDimitry Andric         if (!Used.test(I))
9130b57cec5SDimitry Andric           Mask.push_back(I);
9140b57cec5SDimitry Andric       }
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric       SDValue S = DAG.getVectorShuffle(ExtTy, dl, ExtVec,
9170b57cec5SDimitry Andric                                        DAG.getUNDEF(ExtTy), Mask);
918bdd1243dSDimitry Andric       return ExtLen == VecLen ? S : LoHalf(S, DAG);
9190b57cec5SDimitry Andric     }
9200b57cec5SDimitry Andric   }
9210b57cec5SDimitry Andric 
92204eeddc0SDimitry Andric   // Find most common element to initialize vector with. This is to avoid
92304eeddc0SDimitry Andric   // unnecessary vinsert/valign for cases where the same value is present
92404eeddc0SDimitry Andric   // many times. Creates a histogram of the vector's elements to find the
92504eeddc0SDimitry Andric   // most common element n.
9260b57cec5SDimitry Andric   assert(4*Words.size() == Subtarget.getVectorLength());
92704eeddc0SDimitry Andric   int VecHist[32];
92804eeddc0SDimitry Andric   int n = 0;
92904eeddc0SDimitry Andric   for (unsigned i = 0; i != NumWords; ++i) {
93004eeddc0SDimitry Andric     VecHist[i] = 0;
93104eeddc0SDimitry Andric     if (Words[i].isUndef())
93204eeddc0SDimitry Andric       continue;
93304eeddc0SDimitry Andric     for (unsigned j = i; j != NumWords; ++j)
93404eeddc0SDimitry Andric       if (Words[i] == Words[j])
93504eeddc0SDimitry Andric         VecHist[i]++;
93604eeddc0SDimitry Andric 
93704eeddc0SDimitry Andric     if (VecHist[i] > VecHist[n])
93804eeddc0SDimitry Andric       n = i;
9390b57cec5SDimitry Andric   }
9400b57cec5SDimitry Andric 
94104eeddc0SDimitry Andric   SDValue HalfV = getZero(dl, VecTy, DAG);
94204eeddc0SDimitry Andric   if (VecHist[n] > 1) {
94304eeddc0SDimitry Andric     SDValue SplatV = DAG.getNode(ISD::SPLAT_VECTOR, dl, VecTy, Words[n]);
94404eeddc0SDimitry Andric     HalfV = DAG.getNode(HexagonISD::VALIGN, dl, VecTy,
94504eeddc0SDimitry Andric                        {HalfV, SplatV, DAG.getConstant(HwLen/2, dl, MVT::i32)});
94604eeddc0SDimitry Andric   }
94704eeddc0SDimitry Andric   SDValue HalfV0 = HalfV;
94804eeddc0SDimitry Andric   SDValue HalfV1 = HalfV;
94904eeddc0SDimitry Andric 
95004eeddc0SDimitry Andric   // Construct two halves in parallel, then or them together. Rn and Rm count
95104eeddc0SDimitry Andric   // number of rotations needed before the next element. One last rotation is
95204eeddc0SDimitry Andric   // performed post-loop to position the last element.
95304eeddc0SDimitry Andric   int Rn = 0, Rm = 0;
95404eeddc0SDimitry Andric   SDValue Sn, Sm;
95504eeddc0SDimitry Andric   SDValue N = HalfV0;
95604eeddc0SDimitry Andric   SDValue M = HalfV1;
95704eeddc0SDimitry Andric   for (unsigned i = 0; i != NumWords/2; ++i) {
95804eeddc0SDimitry Andric     // Rotate by element count since last insertion.
95904eeddc0SDimitry Andric     if (Words[i] != Words[n] || VecHist[n] <= 1) {
96004eeddc0SDimitry Andric       Sn = DAG.getConstant(Rn, dl, MVT::i32);
96104eeddc0SDimitry Andric       HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {N, Sn});
96204eeddc0SDimitry Andric       N = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
96304eeddc0SDimitry Andric                       {HalfV0, Words[i]});
96404eeddc0SDimitry Andric       Rn = 0;
96504eeddc0SDimitry Andric     }
96604eeddc0SDimitry Andric     if (Words[i+NumWords/2] != Words[n] || VecHist[n] <= 1) {
96704eeddc0SDimitry Andric       Sm = DAG.getConstant(Rm, dl, MVT::i32);
96804eeddc0SDimitry Andric       HalfV1 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {M, Sm});
96904eeddc0SDimitry Andric       M = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy,
97004eeddc0SDimitry Andric                       {HalfV1, Words[i+NumWords/2]});
97104eeddc0SDimitry Andric       Rm = 0;
97204eeddc0SDimitry Andric     }
97304eeddc0SDimitry Andric     Rn += 4;
97404eeddc0SDimitry Andric     Rm += 4;
97504eeddc0SDimitry Andric   }
97604eeddc0SDimitry Andric   // Perform last rotation.
97704eeddc0SDimitry Andric   Sn = DAG.getConstant(Rn+HwLen/2, dl, MVT::i32);
97804eeddc0SDimitry Andric   Sm = DAG.getConstant(Rm, dl, MVT::i32);
97904eeddc0SDimitry Andric   HalfV0 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {N, Sn});
98004eeddc0SDimitry Andric   HalfV1 = DAG.getNode(HexagonISD::VROR, dl, VecTy, {M, Sm});
98104eeddc0SDimitry Andric 
98204eeddc0SDimitry Andric   SDValue T0 = DAG.getBitcast(tyVector(VecTy, MVT::i32), HalfV0);
98304eeddc0SDimitry Andric   SDValue T1 = DAG.getBitcast(tyVector(VecTy, MVT::i32), HalfV1);
98404eeddc0SDimitry Andric 
98504eeddc0SDimitry Andric   SDValue DstV = DAG.getNode(ISD::OR, dl, ty(T0), {T0, T1});
98604eeddc0SDimitry Andric 
98704eeddc0SDimitry Andric   SDValue OutV =
98804eeddc0SDimitry Andric       DAG.getBitcast(tyVector(ty(DstV), VecTy.getVectorElementType()), DstV);
98904eeddc0SDimitry Andric   return OutV;
9900b57cec5SDimitry Andric }
9910b57cec5SDimitry Andric 
9920b57cec5SDimitry Andric SDValue
9930b57cec5SDimitry Andric HexagonTargetLowering::createHvxPrefixPred(SDValue PredV, const SDLoc &dl,
9940b57cec5SDimitry Andric       unsigned BitBytes, bool ZeroFill, SelectionDAG &DAG) const {
9950b57cec5SDimitry Andric   MVT PredTy = ty(PredV);
9960b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
9970b57cec5SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric   if (Subtarget.isHVXVectorType(PredTy, true)) {
10000b57cec5SDimitry Andric     // Move the vector predicate SubV to a vector register, and scale it
10010b57cec5SDimitry Andric     // down to match the representation (bytes per type element) that VecV
10020b57cec5SDimitry Andric     // uses. The scaling down will pick every 2nd or 4th (every Scale-th
10030b57cec5SDimitry Andric     // in general) element and put them at the front of the resulting
10040b57cec5SDimitry Andric     // vector. This subvector will then be inserted into the Q2V of VecV.
10050b57cec5SDimitry Andric     // To avoid having an operation that generates an illegal type (short
10060b57cec5SDimitry Andric     // vector), generate a full size vector.
10070b57cec5SDimitry Andric     //
10080b57cec5SDimitry Andric     SDValue T = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, PredV);
10090b57cec5SDimitry Andric     SmallVector<int,128> Mask(HwLen);
10100b57cec5SDimitry Andric     // Scale = BitBytes(PredV) / Given BitBytes.
10110b57cec5SDimitry Andric     unsigned Scale = HwLen / (PredTy.getVectorNumElements() * BitBytes);
10120b57cec5SDimitry Andric     unsigned BlockLen = PredTy.getVectorNumElements() * BitBytes;
10130b57cec5SDimitry Andric 
10140b57cec5SDimitry Andric     for (unsigned i = 0; i != HwLen; ++i) {
10150b57cec5SDimitry Andric       unsigned Num = i % Scale;
10160b57cec5SDimitry Andric       unsigned Off = i / Scale;
10170b57cec5SDimitry Andric       Mask[BlockLen*Num + Off] = i;
10180b57cec5SDimitry Andric     }
10190b57cec5SDimitry Andric     SDValue S = DAG.getVectorShuffle(ByteTy, dl, T, DAG.getUNDEF(ByteTy), Mask);
10200b57cec5SDimitry Andric     if (!ZeroFill)
10210b57cec5SDimitry Andric       return S;
10220b57cec5SDimitry Andric     // Fill the bytes beyond BlockLen with 0s.
1023e8d8bef9SDimitry Andric     // V6_pred_scalar2 cannot fill the entire predicate, so it only works
1024e8d8bef9SDimitry Andric     // when BlockLen < HwLen.
1025e8d8bef9SDimitry Andric     assert(BlockLen < HwLen && "vsetq(v1) prerequisite");
10260b57cec5SDimitry Andric     MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
10270b57cec5SDimitry Andric     SDValue Q = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
10280b57cec5SDimitry Andric                          {DAG.getConstant(BlockLen, dl, MVT::i32)}, DAG);
10290b57cec5SDimitry Andric     SDValue M = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, Q);
10300b57cec5SDimitry Andric     return DAG.getNode(ISD::AND, dl, ByteTy, S, M);
10310b57cec5SDimitry Andric   }
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric   // Make sure that this is a valid scalar predicate.
10340b57cec5SDimitry Andric   assert(PredTy == MVT::v2i1 || PredTy == MVT::v4i1 || PredTy == MVT::v8i1);
10350b57cec5SDimitry Andric 
10360b57cec5SDimitry Andric   unsigned Bytes = 8 / PredTy.getVectorNumElements();
10370b57cec5SDimitry Andric   SmallVector<SDValue,4> Words[2];
10380b57cec5SDimitry Andric   unsigned IdxW = 0;
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric   SDValue W0 = isUndef(PredV)
10410b57cec5SDimitry Andric                   ? DAG.getUNDEF(MVT::i64)
10420b57cec5SDimitry Andric                   : DAG.getNode(HexagonISD::P2D, dl, MVT::i64, PredV);
1043bdd1243dSDimitry Andric   Words[IdxW].push_back(HiHalf(W0, DAG));
1044bdd1243dSDimitry Andric   Words[IdxW].push_back(LoHalf(W0, DAG));
10450b57cec5SDimitry Andric 
10460b57cec5SDimitry Andric   while (Bytes < BitBytes) {
10470b57cec5SDimitry Andric     IdxW ^= 1;
10480b57cec5SDimitry Andric     Words[IdxW].clear();
10490b57cec5SDimitry Andric 
10500b57cec5SDimitry Andric     if (Bytes < 4) {
10510b57cec5SDimitry Andric       for (const SDValue &W : Words[IdxW ^ 1]) {
10520b57cec5SDimitry Andric         SDValue T = expandPredicate(W, dl, DAG);
1053bdd1243dSDimitry Andric         Words[IdxW].push_back(HiHalf(T, DAG));
1054bdd1243dSDimitry Andric         Words[IdxW].push_back(LoHalf(T, DAG));
10550b57cec5SDimitry Andric       }
10560b57cec5SDimitry Andric     } else {
10570b57cec5SDimitry Andric       for (const SDValue &W : Words[IdxW ^ 1]) {
10580b57cec5SDimitry Andric         Words[IdxW].push_back(W);
10590b57cec5SDimitry Andric         Words[IdxW].push_back(W);
10600b57cec5SDimitry Andric       }
10610b57cec5SDimitry Andric     }
10620b57cec5SDimitry Andric     Bytes *= 2;
10630b57cec5SDimitry Andric   }
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric   assert(Bytes == BitBytes);
10660b57cec5SDimitry Andric 
10670b57cec5SDimitry Andric   SDValue Vec = ZeroFill ? getZero(dl, ByteTy, DAG) : DAG.getUNDEF(ByteTy);
10680b57cec5SDimitry Andric   SDValue S4 = DAG.getConstant(HwLen-4, dl, MVT::i32);
10690b57cec5SDimitry Andric   for (const SDValue &W : Words[IdxW]) {
10700b57cec5SDimitry Andric     Vec = DAG.getNode(HexagonISD::VROR, dl, ByteTy, Vec, S4);
10710b57cec5SDimitry Andric     Vec = DAG.getNode(HexagonISD::VINSERTW0, dl, ByteTy, Vec, W);
10720b57cec5SDimitry Andric   }
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric   return Vec;
10750b57cec5SDimitry Andric }
10760b57cec5SDimitry Andric 
10770b57cec5SDimitry Andric SDValue
10780b57cec5SDimitry Andric HexagonTargetLowering::buildHvxVectorPred(ArrayRef<SDValue> Values,
10790b57cec5SDimitry Andric                                           const SDLoc &dl, MVT VecTy,
10800b57cec5SDimitry Andric                                           SelectionDAG &DAG) const {
10810b57cec5SDimitry Andric   // Construct a vector V of bytes, such that a comparison V >u 0 would
10820b57cec5SDimitry Andric   // produce the required vector predicate.
10830b57cec5SDimitry Andric   unsigned VecLen = Values.size();
10840b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
10850b57cec5SDimitry Andric   assert(VecLen <= HwLen || VecLen == 8*HwLen);
10860b57cec5SDimitry Andric   SmallVector<SDValue,128> Bytes;
10870b57cec5SDimitry Andric   bool AllT = true, AllF = true;
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric   auto IsTrue = [] (SDValue V) {
10900b57cec5SDimitry Andric     if (const auto *N = dyn_cast<ConstantSDNode>(V.getNode()))
1091349cc55cSDimitry Andric       return !N->isZero();
10920b57cec5SDimitry Andric     return false;
10930b57cec5SDimitry Andric   };
10940b57cec5SDimitry Andric   auto IsFalse = [] (SDValue V) {
10950b57cec5SDimitry Andric     if (const auto *N = dyn_cast<ConstantSDNode>(V.getNode()))
1096349cc55cSDimitry Andric       return N->isZero();
10970b57cec5SDimitry Andric     return false;
10980b57cec5SDimitry Andric   };
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric   if (VecLen <= HwLen) {
11010b57cec5SDimitry Andric     // In the hardware, each bit of a vector predicate corresponds to a byte
11020b57cec5SDimitry Andric     // of a vector register. Calculate how many bytes does a bit of VecTy
11030b57cec5SDimitry Andric     // correspond to.
11040b57cec5SDimitry Andric     assert(HwLen % VecLen == 0);
11050b57cec5SDimitry Andric     unsigned BitBytes = HwLen / VecLen;
11060b57cec5SDimitry Andric     for (SDValue V : Values) {
11070b57cec5SDimitry Andric       AllT &= IsTrue(V);
11080b57cec5SDimitry Andric       AllF &= IsFalse(V);
11090b57cec5SDimitry Andric 
11100b57cec5SDimitry Andric       SDValue Ext = !V.isUndef() ? DAG.getZExtOrTrunc(V, dl, MVT::i8)
11110b57cec5SDimitry Andric                                  : DAG.getUNDEF(MVT::i8);
11120b57cec5SDimitry Andric       for (unsigned B = 0; B != BitBytes; ++B)
11130b57cec5SDimitry Andric         Bytes.push_back(Ext);
11140b57cec5SDimitry Andric     }
11150b57cec5SDimitry Andric   } else {
11160b57cec5SDimitry Andric     // There are as many i1 values, as there are bits in a vector register.
11170b57cec5SDimitry Andric     // Divide the values into groups of 8 and check that each group consists
11180b57cec5SDimitry Andric     // of the same value (ignoring undefs).
11190b57cec5SDimitry Andric     for (unsigned I = 0; I != VecLen; I += 8) {
11200b57cec5SDimitry Andric       unsigned B = 0;
11210b57cec5SDimitry Andric       // Find the first non-undef value in this group.
11220b57cec5SDimitry Andric       for (; B != 8; ++B) {
11230b57cec5SDimitry Andric         if (!Values[I+B].isUndef())
11240b57cec5SDimitry Andric           break;
11250b57cec5SDimitry Andric       }
11260b57cec5SDimitry Andric       SDValue F = Values[I+B];
11270b57cec5SDimitry Andric       AllT &= IsTrue(F);
11280b57cec5SDimitry Andric       AllF &= IsFalse(F);
11290b57cec5SDimitry Andric 
11300b57cec5SDimitry Andric       SDValue Ext = (B < 8) ? DAG.getZExtOrTrunc(F, dl, MVT::i8)
11310b57cec5SDimitry Andric                             : DAG.getUNDEF(MVT::i8);
11320b57cec5SDimitry Andric       Bytes.push_back(Ext);
11330b57cec5SDimitry Andric       // Verify that the rest of values in the group are the same as the
11340b57cec5SDimitry Andric       // first.
11350b57cec5SDimitry Andric       for (; B != 8; ++B)
11360b57cec5SDimitry Andric         assert(Values[I+B].isUndef() || Values[I+B] == F);
11370b57cec5SDimitry Andric     }
11380b57cec5SDimitry Andric   }
11390b57cec5SDimitry Andric 
11400b57cec5SDimitry Andric   if (AllT)
11410b57cec5SDimitry Andric     return DAG.getNode(HexagonISD::QTRUE, dl, VecTy);
11420b57cec5SDimitry Andric   if (AllF)
11430b57cec5SDimitry Andric     return DAG.getNode(HexagonISD::QFALSE, dl, VecTy);
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
11460b57cec5SDimitry Andric   SDValue ByteVec = buildHvxVectorReg(Bytes, dl, ByteTy, DAG);
11470b57cec5SDimitry Andric   return DAG.getNode(HexagonISD::V2Q, dl, VecTy, ByteVec);
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric SDValue
11510b57cec5SDimitry Andric HexagonTargetLowering::extractHvxElementReg(SDValue VecV, SDValue IdxV,
11520b57cec5SDimitry Andric       const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
11530b57cec5SDimitry Andric   MVT ElemTy = ty(VecV).getVectorElementType();
11540b57cec5SDimitry Andric 
11550b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
11560b57cec5SDimitry Andric   assert(ElemWidth >= 8 && ElemWidth <= 32);
11570b57cec5SDimitry Andric   (void)ElemWidth;
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric   SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
11600b57cec5SDimitry Andric   SDValue ExWord = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32,
11610b57cec5SDimitry Andric                                {VecV, ByteIdx});
11620b57cec5SDimitry Andric   if (ElemTy == MVT::i32)
11630b57cec5SDimitry Andric     return ExWord;
11640b57cec5SDimitry Andric 
11650b57cec5SDimitry Andric   // Have an extracted word, need to extract the smaller element out of it.
11660b57cec5SDimitry Andric   // 1. Extract the bits of (the original) IdxV that correspond to the index
11670b57cec5SDimitry Andric   //    of the desired element in the 32-bit word.
11680b57cec5SDimitry Andric   SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
11690b57cec5SDimitry Andric   // 2. Extract the element from the word.
11700b57cec5SDimitry Andric   SDValue ExVec = DAG.getBitcast(tyVector(ty(ExWord), ElemTy), ExWord);
11710b57cec5SDimitry Andric   return extractVector(ExVec, SubIdx, dl, ElemTy, MVT::i32, DAG);
11720b57cec5SDimitry Andric }
11730b57cec5SDimitry Andric 
11740b57cec5SDimitry Andric SDValue
11750b57cec5SDimitry Andric HexagonTargetLowering::extractHvxElementPred(SDValue VecV, SDValue IdxV,
11760b57cec5SDimitry Andric       const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
11770b57cec5SDimitry Andric   // Implement other return types if necessary.
11780b57cec5SDimitry Andric   assert(ResTy == MVT::i1);
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
11810b57cec5SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
11820b57cec5SDimitry Andric   SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric   unsigned Scale = HwLen / ty(VecV).getVectorNumElements();
11850b57cec5SDimitry Andric   SDValue ScV = DAG.getConstant(Scale, dl, MVT::i32);
11860b57cec5SDimitry Andric   IdxV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, ScV);
11870b57cec5SDimitry Andric 
11880b57cec5SDimitry Andric   SDValue ExtB = extractHvxElementReg(ByteVec, IdxV, dl, MVT::i32, DAG);
11890b57cec5SDimitry Andric   SDValue Zero = DAG.getTargetConstant(0, dl, MVT::i32);
11900b57cec5SDimitry Andric   return getInstr(Hexagon::C2_cmpgtui, dl, MVT::i1, {ExtB, Zero}, DAG);
11910b57cec5SDimitry Andric }
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric SDValue
11940b57cec5SDimitry Andric HexagonTargetLowering::insertHvxElementReg(SDValue VecV, SDValue IdxV,
11950b57cec5SDimitry Andric       SDValue ValV, const SDLoc &dl, SelectionDAG &DAG) const {
11960b57cec5SDimitry Andric   MVT ElemTy = ty(VecV).getVectorElementType();
11970b57cec5SDimitry Andric 
11980b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
11990b57cec5SDimitry Andric   assert(ElemWidth >= 8 && ElemWidth <= 32);
12000b57cec5SDimitry Andric   (void)ElemWidth;
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric   auto InsertWord = [&DAG,&dl,this] (SDValue VecV, SDValue ValV,
12030b57cec5SDimitry Andric                                      SDValue ByteIdxV) {
12040b57cec5SDimitry Andric     MVT VecTy = ty(VecV);
12050b57cec5SDimitry Andric     unsigned HwLen = Subtarget.getVectorLength();
12060b57cec5SDimitry Andric     SDValue MaskV = DAG.getNode(ISD::AND, dl, MVT::i32,
12070b57cec5SDimitry Andric                                 {ByteIdxV, DAG.getConstant(-4, dl, MVT::i32)});
12080b57cec5SDimitry Andric     SDValue RotV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {VecV, MaskV});
12090b57cec5SDimitry Andric     SDValue InsV = DAG.getNode(HexagonISD::VINSERTW0, dl, VecTy, {RotV, ValV});
12100b57cec5SDimitry Andric     SDValue SubV = DAG.getNode(ISD::SUB, dl, MVT::i32,
12110b57cec5SDimitry Andric                                {DAG.getConstant(HwLen, dl, MVT::i32), MaskV});
12120b57cec5SDimitry Andric     SDValue TorV = DAG.getNode(HexagonISD::VROR, dl, VecTy, {InsV, SubV});
12130b57cec5SDimitry Andric     return TorV;
12140b57cec5SDimitry Andric   };
12150b57cec5SDimitry Andric 
12160b57cec5SDimitry Andric   SDValue ByteIdx = convertToByteIndex(IdxV, ElemTy, DAG);
12170b57cec5SDimitry Andric   if (ElemTy == MVT::i32)
12180b57cec5SDimitry Andric     return InsertWord(VecV, ValV, ByteIdx);
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric   // If this is not inserting a 32-bit word, convert it into such a thing.
12210b57cec5SDimitry Andric   // 1. Extract the existing word from the target vector.
12220b57cec5SDimitry Andric   SDValue WordIdx = DAG.getNode(ISD::SRL, dl, MVT::i32,
12230b57cec5SDimitry Andric                                 {ByteIdx, DAG.getConstant(2, dl, MVT::i32)});
12240b57cec5SDimitry Andric   SDValue Ext = extractHvxElementReg(opCastElem(VecV, MVT::i32, DAG), WordIdx,
12250b57cec5SDimitry Andric                                      dl, MVT::i32, DAG);
12260b57cec5SDimitry Andric 
12270b57cec5SDimitry Andric   // 2. Treating the extracted word as a 32-bit vector, insert the given
12280b57cec5SDimitry Andric   //    value into it.
12290b57cec5SDimitry Andric   SDValue SubIdx = getIndexInWord32(IdxV, ElemTy, DAG);
12300b57cec5SDimitry Andric   MVT SubVecTy = tyVector(ty(Ext), ElemTy);
12310b57cec5SDimitry Andric   SDValue Ins = insertVector(DAG.getBitcast(SubVecTy, Ext),
12320b57cec5SDimitry Andric                              ValV, SubIdx, dl, ElemTy, DAG);
12330b57cec5SDimitry Andric 
12340b57cec5SDimitry Andric   // 3. Insert the 32-bit word back into the original vector.
12350b57cec5SDimitry Andric   return InsertWord(VecV, Ins, ByteIdx);
12360b57cec5SDimitry Andric }
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric SDValue
12390b57cec5SDimitry Andric HexagonTargetLowering::insertHvxElementPred(SDValue VecV, SDValue IdxV,
12400b57cec5SDimitry Andric       SDValue ValV, const SDLoc &dl, SelectionDAG &DAG) const {
12410b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
12420b57cec5SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
12430b57cec5SDimitry Andric   SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
12440b57cec5SDimitry Andric 
12450b57cec5SDimitry Andric   unsigned Scale = HwLen / ty(VecV).getVectorNumElements();
12460b57cec5SDimitry Andric   SDValue ScV = DAG.getConstant(Scale, dl, MVT::i32);
12470b57cec5SDimitry Andric   IdxV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, ScV);
12480b57cec5SDimitry Andric   ValV = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::i32, ValV);
12490b57cec5SDimitry Andric 
12500b57cec5SDimitry Andric   SDValue InsV = insertHvxElementReg(ByteVec, IdxV, ValV, dl, DAG);
12510b57cec5SDimitry Andric   return DAG.getNode(HexagonISD::V2Q, dl, ty(VecV), InsV);
12520b57cec5SDimitry Andric }
12530b57cec5SDimitry Andric 
12540b57cec5SDimitry Andric SDValue
1255bdd1243dSDimitry Andric HexagonTargetLowering::extractHvxSubvectorReg(SDValue OrigOp, SDValue VecV,
1256bdd1243dSDimitry Andric       SDValue IdxV, const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
12570b57cec5SDimitry Andric   MVT VecTy = ty(VecV);
12580b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
1259*1db9f3b2SDimitry Andric   unsigned Idx = IdxV.getNode()->getAsZExtVal();
12600b57cec5SDimitry Andric   MVT ElemTy = VecTy.getVectorElementType();
12610b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric   // If the source vector is a vector pair, get the single vector containing
12640b57cec5SDimitry Andric   // the subvector of interest. The subvector will never overlap two single
12650b57cec5SDimitry Andric   // vectors.
12660b57cec5SDimitry Andric   if (isHvxPairTy(VecTy)) {
1267bdd1243dSDimitry Andric     if (Idx * ElemWidth >= 8*HwLen)
12680b57cec5SDimitry Andric       Idx -= VecTy.getVectorNumElements() / 2;
1269bdd1243dSDimitry Andric 
1270bdd1243dSDimitry Andric     VecV = OrigOp;
1271bdd1243dSDimitry Andric     if (typeSplit(VecTy).first == ResTy)
12720b57cec5SDimitry Andric       return VecV;
12730b57cec5SDimitry Andric   }
12740b57cec5SDimitry Andric 
12750b57cec5SDimitry Andric   // The only meaningful subvectors of a single HVX vector are those that
12760b57cec5SDimitry Andric   // fit in a scalar register.
12770b57cec5SDimitry Andric   assert(ResTy.getSizeInBits() == 32 || ResTy.getSizeInBits() == 64);
12780b57cec5SDimitry Andric 
12790b57cec5SDimitry Andric   MVT WordTy = tyVector(VecTy, MVT::i32);
12800b57cec5SDimitry Andric   SDValue WordVec = DAG.getBitcast(WordTy, VecV);
12810b57cec5SDimitry Andric   unsigned WordIdx = (Idx*ElemWidth) / 32;
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric   SDValue W0Idx = DAG.getConstant(WordIdx, dl, MVT::i32);
12840b57cec5SDimitry Andric   SDValue W0 = extractHvxElementReg(WordVec, W0Idx, dl, MVT::i32, DAG);
12850b57cec5SDimitry Andric   if (ResTy.getSizeInBits() == 32)
12860b57cec5SDimitry Andric     return DAG.getBitcast(ResTy, W0);
12870b57cec5SDimitry Andric 
12880b57cec5SDimitry Andric   SDValue W1Idx = DAG.getConstant(WordIdx+1, dl, MVT::i32);
12890b57cec5SDimitry Andric   SDValue W1 = extractHvxElementReg(WordVec, W1Idx, dl, MVT::i32, DAG);
1290bdd1243dSDimitry Andric   SDValue WW = getCombine(W1, W0, dl, MVT::i64, DAG);
12910b57cec5SDimitry Andric   return DAG.getBitcast(ResTy, WW);
12920b57cec5SDimitry Andric }
12930b57cec5SDimitry Andric 
12940b57cec5SDimitry Andric SDValue
12950b57cec5SDimitry Andric HexagonTargetLowering::extractHvxSubvectorPred(SDValue VecV, SDValue IdxV,
12960b57cec5SDimitry Andric       const SDLoc &dl, MVT ResTy, SelectionDAG &DAG) const {
12970b57cec5SDimitry Andric   MVT VecTy = ty(VecV);
12980b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
12990b57cec5SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
13000b57cec5SDimitry Andric   SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
13010b57cec5SDimitry Andric   // IdxV is required to be a constant.
1302*1db9f3b2SDimitry Andric   unsigned Idx = IdxV.getNode()->getAsZExtVal();
13030b57cec5SDimitry Andric 
13040b57cec5SDimitry Andric   unsigned ResLen = ResTy.getVectorNumElements();
13050b57cec5SDimitry Andric   unsigned BitBytes = HwLen / VecTy.getVectorNumElements();
13060b57cec5SDimitry Andric   unsigned Offset = Idx * BitBytes;
13070b57cec5SDimitry Andric   SDValue Undef = DAG.getUNDEF(ByteTy);
13080b57cec5SDimitry Andric   SmallVector<int,128> Mask;
13090b57cec5SDimitry Andric 
13100b57cec5SDimitry Andric   if (Subtarget.isHVXVectorType(ResTy, true)) {
13110b57cec5SDimitry Andric     // Converting between two vector predicates. Since the result is shorter
13120b57cec5SDimitry Andric     // than the source, it will correspond to a vector predicate with the
13130b57cec5SDimitry Andric     // relevant bits replicated. The replication count is the ratio of the
13140b57cec5SDimitry Andric     // source and target vector lengths.
13150b57cec5SDimitry Andric     unsigned Rep = VecTy.getVectorNumElements() / ResLen;
13160b57cec5SDimitry Andric     assert(isPowerOf2_32(Rep) && HwLen % Rep == 0);
13170b57cec5SDimitry Andric     for (unsigned i = 0; i != HwLen/Rep; ++i) {
13180b57cec5SDimitry Andric       for (unsigned j = 0; j != Rep; ++j)
13190b57cec5SDimitry Andric         Mask.push_back(i + Offset);
13200b57cec5SDimitry Andric     }
13210b57cec5SDimitry Andric     SDValue ShuffV = DAG.getVectorShuffle(ByteTy, dl, ByteVec, Undef, Mask);
13220b57cec5SDimitry Andric     return DAG.getNode(HexagonISD::V2Q, dl, ResTy, ShuffV);
13230b57cec5SDimitry Andric   }
13240b57cec5SDimitry Andric 
13250b57cec5SDimitry Andric   // Converting between a vector predicate and a scalar predicate. In the
13260b57cec5SDimitry Andric   // vector predicate, a group of BitBytes bits will correspond to a single
13270b57cec5SDimitry Andric   // i1 element of the source vector type. Those bits will all have the same
13280b57cec5SDimitry Andric   // value. The same will be true for ByteVec, where each byte corresponds
13290b57cec5SDimitry Andric   // to a bit in the vector predicate.
13300b57cec5SDimitry Andric   // The algorithm is to traverse the ByteVec, going over the i1 values from
13310b57cec5SDimitry Andric   // the source vector, and generate the corresponding representation in an
13320b57cec5SDimitry Andric   // 8-byte vector. To avoid repeated extracts from ByteVec, shuffle the
13330b57cec5SDimitry Andric   // elements so that the interesting 8 bytes will be in the low end of the
13340b57cec5SDimitry Andric   // vector.
13350b57cec5SDimitry Andric   unsigned Rep = 8 / ResLen;
13360b57cec5SDimitry Andric   // Make sure the output fill the entire vector register, so repeat the
13370b57cec5SDimitry Andric   // 8-byte groups as many times as necessary.
13380b57cec5SDimitry Andric   for (unsigned r = 0; r != HwLen/ResLen; ++r) {
13390b57cec5SDimitry Andric     // This will generate the indexes of the 8 interesting bytes.
13400b57cec5SDimitry Andric     for (unsigned i = 0; i != ResLen; ++i) {
13410b57cec5SDimitry Andric       for (unsigned j = 0; j != Rep; ++j)
13420b57cec5SDimitry Andric         Mask.push_back(Offset + i*BitBytes);
13430b57cec5SDimitry Andric     }
13440b57cec5SDimitry Andric   }
13450b57cec5SDimitry Andric 
13460b57cec5SDimitry Andric   SDValue Zero = getZero(dl, MVT::i32, DAG);
13470b57cec5SDimitry Andric   SDValue ShuffV = DAG.getVectorShuffle(ByteTy, dl, ByteVec, Undef, Mask);
13480b57cec5SDimitry Andric   // Combine the two low words from ShuffV into a v8i8, and byte-compare
13490b57cec5SDimitry Andric   // them against 0.
13500b57cec5SDimitry Andric   SDValue W0 = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32, {ShuffV, Zero});
13510b57cec5SDimitry Andric   SDValue W1 = DAG.getNode(HexagonISD::VEXTRACTW, dl, MVT::i32,
13520b57cec5SDimitry Andric                            {ShuffV, DAG.getConstant(4, dl, MVT::i32)});
1353bdd1243dSDimitry Andric   SDValue Vec64 = getCombine(W1, W0, dl, MVT::v8i8, DAG);
13540b57cec5SDimitry Andric   return getInstr(Hexagon::A4_vcmpbgtui, dl, ResTy,
13550b57cec5SDimitry Andric                   {Vec64, DAG.getTargetConstant(0, dl, MVT::i32)}, DAG);
13560b57cec5SDimitry Andric }
13570b57cec5SDimitry Andric 
13580b57cec5SDimitry Andric SDValue
13590b57cec5SDimitry Andric HexagonTargetLowering::insertHvxSubvectorReg(SDValue VecV, SDValue SubV,
13600b57cec5SDimitry Andric       SDValue IdxV, const SDLoc &dl, SelectionDAG &DAG) const {
13610b57cec5SDimitry Andric   MVT VecTy = ty(VecV);
13620b57cec5SDimitry Andric   MVT SubTy = ty(SubV);
13630b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
13640b57cec5SDimitry Andric   MVT ElemTy = VecTy.getVectorElementType();
13650b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
13660b57cec5SDimitry Andric 
13670b57cec5SDimitry Andric   bool IsPair = isHvxPairTy(VecTy);
13680b57cec5SDimitry Andric   MVT SingleTy = MVT::getVectorVT(ElemTy, (8*HwLen)/ElemWidth);
13690b57cec5SDimitry Andric   // The two single vectors that VecV consists of, if it's a pair.
13700b57cec5SDimitry Andric   SDValue V0, V1;
13710b57cec5SDimitry Andric   SDValue SingleV = VecV;
13720b57cec5SDimitry Andric   SDValue PickHi;
13730b57cec5SDimitry Andric 
13740b57cec5SDimitry Andric   if (IsPair) {
1375bdd1243dSDimitry Andric     V0 = LoHalf(VecV, DAG);
1376bdd1243dSDimitry Andric     V1 = HiHalf(VecV, DAG);
13770b57cec5SDimitry Andric 
13780b57cec5SDimitry Andric     SDValue HalfV = DAG.getConstant(SingleTy.getVectorNumElements(),
13790b57cec5SDimitry Andric                                     dl, MVT::i32);
13800b57cec5SDimitry Andric     PickHi = DAG.getSetCC(dl, MVT::i1, IdxV, HalfV, ISD::SETUGT);
13810b57cec5SDimitry Andric     if (isHvxSingleTy(SubTy)) {
13820b57cec5SDimitry Andric       if (const auto *CN = dyn_cast<const ConstantSDNode>(IdxV.getNode())) {
13830b57cec5SDimitry Andric         unsigned Idx = CN->getZExtValue();
13840b57cec5SDimitry Andric         assert(Idx == 0 || Idx == VecTy.getVectorNumElements()/2);
13850b57cec5SDimitry Andric         unsigned SubIdx = (Idx == 0) ? Hexagon::vsub_lo : Hexagon::vsub_hi;
13860b57cec5SDimitry Andric         return DAG.getTargetInsertSubreg(SubIdx, dl, VecTy, VecV, SubV);
13870b57cec5SDimitry Andric       }
13880b57cec5SDimitry Andric       // If IdxV is not a constant, generate the two variants: with the
13890b57cec5SDimitry Andric       // SubV as the high and as the low subregister, and select the right
13900b57cec5SDimitry Andric       // pair based on the IdxV.
13910b57cec5SDimitry Andric       SDValue InLo = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {SubV, V1});
13920b57cec5SDimitry Andric       SDValue InHi = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {V0, SubV});
13930b57cec5SDimitry Andric       return DAG.getNode(ISD::SELECT, dl, VecTy, PickHi, InHi, InLo);
13940b57cec5SDimitry Andric     }
13950b57cec5SDimitry Andric     // The subvector being inserted must be entirely contained in one of
13960b57cec5SDimitry Andric     // the vectors V0 or V1. Set SingleV to the correct one, and update
13970b57cec5SDimitry Andric     // IdxV to be the index relative to the beginning of that vector.
13980b57cec5SDimitry Andric     SDValue S = DAG.getNode(ISD::SUB, dl, MVT::i32, IdxV, HalfV);
13990b57cec5SDimitry Andric     IdxV = DAG.getNode(ISD::SELECT, dl, MVT::i32, PickHi, S, IdxV);
14000b57cec5SDimitry Andric     SingleV = DAG.getNode(ISD::SELECT, dl, SingleTy, PickHi, V1, V0);
14010b57cec5SDimitry Andric   }
14020b57cec5SDimitry Andric 
14030b57cec5SDimitry Andric   // The only meaningful subvectors of a single HVX vector are those that
14040b57cec5SDimitry Andric   // fit in a scalar register.
14050b57cec5SDimitry Andric   assert(SubTy.getSizeInBits() == 32 || SubTy.getSizeInBits() == 64);
14060b57cec5SDimitry Andric   // Convert IdxV to be index in bytes.
14070b57cec5SDimitry Andric   auto *IdxN = dyn_cast<ConstantSDNode>(IdxV.getNode());
1408349cc55cSDimitry Andric   if (!IdxN || !IdxN->isZero()) {
14090b57cec5SDimitry Andric     IdxV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
14100b57cec5SDimitry Andric                        DAG.getConstant(ElemWidth/8, dl, MVT::i32));
14110b57cec5SDimitry Andric     SingleV = DAG.getNode(HexagonISD::VROR, dl, SingleTy, SingleV, IdxV);
14120b57cec5SDimitry Andric   }
14130b57cec5SDimitry Andric   // When inserting a single word, the rotation back to the original position
14140b57cec5SDimitry Andric   // would be by HwLen-Idx, but if two words are inserted, it will need to be
14150b57cec5SDimitry Andric   // by (HwLen-4)-Idx.
14160b57cec5SDimitry Andric   unsigned RolBase = HwLen;
141706c3fb27SDimitry Andric   if (SubTy.getSizeInBits() == 32) {
14180b57cec5SDimitry Andric     SDValue V = DAG.getBitcast(MVT::i32, SubV);
141906c3fb27SDimitry Andric     SingleV = DAG.getNode(HexagonISD::VINSERTW0, dl, SingleTy, SingleV, V);
14200b57cec5SDimitry Andric   } else {
14210b57cec5SDimitry Andric     SDValue V = DAG.getBitcast(MVT::i64, SubV);
1422bdd1243dSDimitry Andric     SDValue R0 = LoHalf(V, DAG);
1423bdd1243dSDimitry Andric     SDValue R1 = HiHalf(V, DAG);
14240b57cec5SDimitry Andric     SingleV = DAG.getNode(HexagonISD::VINSERTW0, dl, SingleTy, SingleV, R0);
14250b57cec5SDimitry Andric     SingleV = DAG.getNode(HexagonISD::VROR, dl, SingleTy, SingleV,
14260b57cec5SDimitry Andric                           DAG.getConstant(4, dl, MVT::i32));
14270b57cec5SDimitry Andric     SingleV = DAG.getNode(HexagonISD::VINSERTW0, dl, SingleTy, SingleV, R1);
14280b57cec5SDimitry Andric     RolBase = HwLen-4;
14290b57cec5SDimitry Andric   }
14300b57cec5SDimitry Andric   // If the vector wasn't ror'ed, don't ror it back.
1431349cc55cSDimitry Andric   if (RolBase != 4 || !IdxN || !IdxN->isZero()) {
14320b57cec5SDimitry Andric     SDValue RolV = DAG.getNode(ISD::SUB, dl, MVT::i32,
14330b57cec5SDimitry Andric                                DAG.getConstant(RolBase, dl, MVT::i32), IdxV);
14340b57cec5SDimitry Andric     SingleV = DAG.getNode(HexagonISD::VROR, dl, SingleTy, SingleV, RolV);
14350b57cec5SDimitry Andric   }
14360b57cec5SDimitry Andric 
14370b57cec5SDimitry Andric   if (IsPair) {
14380b57cec5SDimitry Andric     SDValue InLo = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {SingleV, V1});
14390b57cec5SDimitry Andric     SDValue InHi = DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, {V0, SingleV});
14400b57cec5SDimitry Andric     return DAG.getNode(ISD::SELECT, dl, VecTy, PickHi, InHi, InLo);
14410b57cec5SDimitry Andric   }
14420b57cec5SDimitry Andric   return SingleV;
14430b57cec5SDimitry Andric }
14440b57cec5SDimitry Andric 
14450b57cec5SDimitry Andric SDValue
14460b57cec5SDimitry Andric HexagonTargetLowering::insertHvxSubvectorPred(SDValue VecV, SDValue SubV,
14470b57cec5SDimitry Andric       SDValue IdxV, const SDLoc &dl, SelectionDAG &DAG) const {
14480b57cec5SDimitry Andric   MVT VecTy = ty(VecV);
14490b57cec5SDimitry Andric   MVT SubTy = ty(SubV);
14500b57cec5SDimitry Andric   assert(Subtarget.isHVXVectorType(VecTy, true));
14510b57cec5SDimitry Andric   // VecV is an HVX vector predicate. SubV may be either an HVX vector
14520b57cec5SDimitry Andric   // predicate as well, or it can be a scalar predicate.
14530b57cec5SDimitry Andric 
14540b57cec5SDimitry Andric   unsigned VecLen = VecTy.getVectorNumElements();
14550b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
14560b57cec5SDimitry Andric   assert(HwLen % VecLen == 0 && "Unexpected vector type");
14570b57cec5SDimitry Andric 
14580b57cec5SDimitry Andric   unsigned Scale = VecLen / SubTy.getVectorNumElements();
14590b57cec5SDimitry Andric   unsigned BitBytes = HwLen / VecLen;
14600b57cec5SDimitry Andric   unsigned BlockLen = HwLen / Scale;
14610b57cec5SDimitry Andric 
14620b57cec5SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
14630b57cec5SDimitry Andric   SDValue ByteVec = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, VecV);
14640b57cec5SDimitry Andric   SDValue ByteSub = createHvxPrefixPred(SubV, dl, BitBytes, false, DAG);
14650b57cec5SDimitry Andric   SDValue ByteIdx;
14660b57cec5SDimitry Andric 
14670b57cec5SDimitry Andric   auto *IdxN = dyn_cast<ConstantSDNode>(IdxV.getNode());
1468349cc55cSDimitry Andric   if (!IdxN || !IdxN->isZero()) {
14690b57cec5SDimitry Andric     ByteIdx = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
14700b57cec5SDimitry Andric                           DAG.getConstant(BitBytes, dl, MVT::i32));
14710b57cec5SDimitry Andric     ByteVec = DAG.getNode(HexagonISD::VROR, dl, ByteTy, ByteVec, ByteIdx);
14720b57cec5SDimitry Andric   }
14730b57cec5SDimitry Andric 
14740b57cec5SDimitry Andric   // ByteVec is the target vector VecV rotated in such a way that the
14750b57cec5SDimitry Andric   // subvector should be inserted at index 0. Generate a predicate mask
14760b57cec5SDimitry Andric   // and use vmux to do the insertion.
1477e8d8bef9SDimitry Andric   assert(BlockLen < HwLen && "vsetq(v1) prerequisite");
14780b57cec5SDimitry Andric   MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
14790b57cec5SDimitry Andric   SDValue Q = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
14800b57cec5SDimitry Andric                        {DAG.getConstant(BlockLen, dl, MVT::i32)}, DAG);
14810b57cec5SDimitry Andric   ByteVec = getInstr(Hexagon::V6_vmux, dl, ByteTy, {Q, ByteSub, ByteVec}, DAG);
14820b57cec5SDimitry Andric   // Rotate ByteVec back, and convert to a vector predicate.
1483349cc55cSDimitry Andric   if (!IdxN || !IdxN->isZero()) {
14840b57cec5SDimitry Andric     SDValue HwLenV = DAG.getConstant(HwLen, dl, MVT::i32);
14850b57cec5SDimitry Andric     SDValue ByteXdi = DAG.getNode(ISD::SUB, dl, MVT::i32, HwLenV, ByteIdx);
14860b57cec5SDimitry Andric     ByteVec = DAG.getNode(HexagonISD::VROR, dl, ByteTy, ByteVec, ByteXdi);
14870b57cec5SDimitry Andric   }
14880b57cec5SDimitry Andric   return DAG.getNode(HexagonISD::V2Q, dl, VecTy, ByteVec);
14890b57cec5SDimitry Andric }
14900b57cec5SDimitry Andric 
14910b57cec5SDimitry Andric SDValue
14920b57cec5SDimitry Andric HexagonTargetLowering::extendHvxVectorPred(SDValue VecV, const SDLoc &dl,
14930b57cec5SDimitry Andric       MVT ResTy, bool ZeroExt, SelectionDAG &DAG) const {
14940b57cec5SDimitry Andric   // Sign- and any-extending of a vector predicate to a vector register is
14950b57cec5SDimitry Andric   // equivalent to Q2V. For zero-extensions, generate a vmux between 0 and
14960b57cec5SDimitry Andric   // a vector of 1s (where the 1s are of type matching the vector type).
14970b57cec5SDimitry Andric   assert(Subtarget.isHVXVectorType(ResTy));
14980b57cec5SDimitry Andric   if (!ZeroExt)
14990b57cec5SDimitry Andric     return DAG.getNode(HexagonISD::Q2V, dl, ResTy, VecV);
15000b57cec5SDimitry Andric 
15010b57cec5SDimitry Andric   assert(ty(VecV).getVectorNumElements() == ResTy.getVectorNumElements());
1502e8d8bef9SDimitry Andric   SDValue True = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
15030b57cec5SDimitry Andric                              DAG.getConstant(1, dl, MVT::i32));
15040b57cec5SDimitry Andric   SDValue False = getZero(dl, ResTy, DAG);
15050b57cec5SDimitry Andric   return DAG.getSelect(dl, ResTy, VecV, True, False);
15060b57cec5SDimitry Andric }
15070b57cec5SDimitry Andric 
15080b57cec5SDimitry Andric SDValue
15095ffd83dbSDimitry Andric HexagonTargetLowering::compressHvxPred(SDValue VecQ, const SDLoc &dl,
15105ffd83dbSDimitry Andric       MVT ResTy, SelectionDAG &DAG) const {
15115ffd83dbSDimitry Andric   // Given a predicate register VecQ, transfer bits VecQ[0..HwLen-1]
15125ffd83dbSDimitry Andric   // (i.e. the entire predicate register) to bits [0..HwLen-1] of a
15135ffd83dbSDimitry Andric   // vector register. The remaining bits of the vector register are
15145ffd83dbSDimitry Andric   // unspecified.
15155ffd83dbSDimitry Andric 
15165ffd83dbSDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
15175ffd83dbSDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
15185ffd83dbSDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
15195ffd83dbSDimitry Andric   MVT PredTy = ty(VecQ);
15205ffd83dbSDimitry Andric   unsigned PredLen = PredTy.getVectorNumElements();
15215ffd83dbSDimitry Andric   assert(HwLen % PredLen == 0);
15225ffd83dbSDimitry Andric   MVT VecTy = MVT::getVectorVT(MVT::getIntegerVT(8*HwLen/PredLen), PredLen);
15235ffd83dbSDimitry Andric 
15245ffd83dbSDimitry Andric   Type *Int8Ty = Type::getInt8Ty(*DAG.getContext());
15255ffd83dbSDimitry Andric   SmallVector<Constant*, 128> Tmp;
15265ffd83dbSDimitry Andric   // Create an array of bytes (hex): 01,02,04,08,10,20,40,80, 01,02,04,08,...
15275ffd83dbSDimitry Andric   // These are bytes with the LSB rotated left with respect to their index.
15285ffd83dbSDimitry Andric   for (unsigned i = 0; i != HwLen/8; ++i) {
15295ffd83dbSDimitry Andric     for (unsigned j = 0; j != 8; ++j)
15305ffd83dbSDimitry Andric       Tmp.push_back(ConstantInt::get(Int8Ty, 1ull << j));
15315ffd83dbSDimitry Andric   }
15325ffd83dbSDimitry Andric   Constant *CV = ConstantVector::get(Tmp);
15335ffd83dbSDimitry Andric   Align Alignment(HwLen);
15345ffd83dbSDimitry Andric   SDValue CP =
15355ffd83dbSDimitry Andric       LowerConstantPool(DAG.getConstantPool(CV, ByteTy, Alignment), DAG);
15365ffd83dbSDimitry Andric   SDValue Bytes =
15375ffd83dbSDimitry Andric       DAG.getLoad(ByteTy, dl, DAG.getEntryNode(), CP,
15385ffd83dbSDimitry Andric                   MachinePointerInfo::getConstantPool(MF), Alignment);
15395ffd83dbSDimitry Andric 
15405ffd83dbSDimitry Andric   // Select the bytes that correspond to true bits in the vector predicate.
15415ffd83dbSDimitry Andric   SDValue Sel = DAG.getSelect(dl, VecTy, VecQ, DAG.getBitcast(VecTy, Bytes),
15425ffd83dbSDimitry Andric       getZero(dl, VecTy, DAG));
15435ffd83dbSDimitry Andric   // Calculate the OR of all bytes in each group of 8. That will compress
15445ffd83dbSDimitry Andric   // all the individual bits into a single byte.
15455ffd83dbSDimitry Andric   // First, OR groups of 4, via vrmpy with 0x01010101.
15465ffd83dbSDimitry Andric   SDValue All1 =
15475ffd83dbSDimitry Andric       DAG.getSplatBuildVector(MVT::v4i8, dl, DAG.getConstant(1, dl, MVT::i32));
15485ffd83dbSDimitry Andric   SDValue Vrmpy = getInstr(Hexagon::V6_vrmpyub, dl, ByteTy, {Sel, All1}, DAG);
15495ffd83dbSDimitry Andric   // Then rotate the accumulated vector by 4 bytes, and do the final OR.
15505ffd83dbSDimitry Andric   SDValue Rot = getInstr(Hexagon::V6_valignbi, dl, ByteTy,
15515ffd83dbSDimitry Andric       {Vrmpy, Vrmpy, DAG.getTargetConstant(4, dl, MVT::i32)}, DAG);
15525ffd83dbSDimitry Andric   SDValue Vor = DAG.getNode(ISD::OR, dl, ByteTy, {Vrmpy, Rot});
15535ffd83dbSDimitry Andric 
15545ffd83dbSDimitry Andric   // Pick every 8th byte and coalesce them at the beginning of the output.
15555ffd83dbSDimitry Andric   // For symmetry, coalesce every 1+8th byte after that, then every 2+8th
15565ffd83dbSDimitry Andric   // byte and so on.
15575ffd83dbSDimitry Andric   SmallVector<int,128> Mask;
15585ffd83dbSDimitry Andric   for (unsigned i = 0; i != HwLen; ++i)
15595ffd83dbSDimitry Andric     Mask.push_back((8*i) % HwLen + i/(HwLen/8));
15605ffd83dbSDimitry Andric   SDValue Collect =
15615ffd83dbSDimitry Andric       DAG.getVectorShuffle(ByteTy, dl, Vor, DAG.getUNDEF(ByteTy), Mask);
15625ffd83dbSDimitry Andric   return DAG.getBitcast(ResTy, Collect);
15635ffd83dbSDimitry Andric }
15645ffd83dbSDimitry Andric 
15655ffd83dbSDimitry Andric SDValue
1566bdd1243dSDimitry Andric HexagonTargetLowering::resizeToWidth(SDValue VecV, MVT ResTy, bool Signed,
1567bdd1243dSDimitry Andric                                      const SDLoc &dl, SelectionDAG &DAG) const {
1568bdd1243dSDimitry Andric   // Take a vector and resize the element type to match the given type.
1569bdd1243dSDimitry Andric   MVT InpTy = ty(VecV);
1570bdd1243dSDimitry Andric   if (InpTy == ResTy)
1571bdd1243dSDimitry Andric     return VecV;
1572bdd1243dSDimitry Andric 
1573bdd1243dSDimitry Andric   unsigned InpWidth = InpTy.getSizeInBits();
1574bdd1243dSDimitry Andric   unsigned ResWidth = ResTy.getSizeInBits();
1575bdd1243dSDimitry Andric 
1576bdd1243dSDimitry Andric   if (InpTy.isFloatingPoint()) {
1577bdd1243dSDimitry Andric     return InpWidth < ResWidth ? DAG.getNode(ISD::FP_EXTEND, dl, ResTy, VecV)
1578bdd1243dSDimitry Andric                                : DAG.getNode(ISD::FP_ROUND, dl, ResTy, VecV,
1579bdd1243dSDimitry Andric                                              getZero(dl, MVT::i32, DAG));
1580bdd1243dSDimitry Andric   }
1581bdd1243dSDimitry Andric 
1582bdd1243dSDimitry Andric   assert(InpTy.isInteger());
1583bdd1243dSDimitry Andric 
1584bdd1243dSDimitry Andric   if (InpWidth < ResWidth) {
1585bdd1243dSDimitry Andric     unsigned ExtOpc = Signed ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND;
1586bdd1243dSDimitry Andric     return DAG.getNode(ExtOpc, dl, ResTy, VecV);
1587bdd1243dSDimitry Andric   } else {
1588bdd1243dSDimitry Andric     unsigned NarOpc = Signed ? HexagonISD::SSAT : HexagonISD::USAT;
1589bdd1243dSDimitry Andric     return DAG.getNode(NarOpc, dl, ResTy, VecV, DAG.getValueType(ResTy));
1590bdd1243dSDimitry Andric   }
1591bdd1243dSDimitry Andric }
1592bdd1243dSDimitry Andric 
1593bdd1243dSDimitry Andric SDValue
1594bdd1243dSDimitry Andric HexagonTargetLowering::extractSubvector(SDValue Vec, MVT SubTy, unsigned SubIdx,
1595bdd1243dSDimitry Andric       SelectionDAG &DAG) const {
1596bdd1243dSDimitry Andric   assert(ty(Vec).getSizeInBits() % SubTy.getSizeInBits() == 0);
1597bdd1243dSDimitry Andric 
1598bdd1243dSDimitry Andric   const SDLoc &dl(Vec);
1599bdd1243dSDimitry Andric   unsigned ElemIdx = SubIdx * SubTy.getVectorNumElements();
1600bdd1243dSDimitry Andric   return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, SubTy,
1601bdd1243dSDimitry Andric                      {Vec, DAG.getConstant(ElemIdx, dl, MVT::i32)});
1602bdd1243dSDimitry Andric }
1603bdd1243dSDimitry Andric 
1604bdd1243dSDimitry Andric SDValue
16050b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxBuildVector(SDValue Op, SelectionDAG &DAG)
16060b57cec5SDimitry Andric       const {
16070b57cec5SDimitry Andric   const SDLoc &dl(Op);
16080b57cec5SDimitry Andric   MVT VecTy = ty(Op);
16090b57cec5SDimitry Andric 
16100b57cec5SDimitry Andric   unsigned Size = Op.getNumOperands();
16110b57cec5SDimitry Andric   SmallVector<SDValue,128> Ops;
16120b57cec5SDimitry Andric   for (unsigned i = 0; i != Size; ++i)
16130b57cec5SDimitry Andric     Ops.push_back(Op.getOperand(i));
16140b57cec5SDimitry Andric 
161581ad6265SDimitry Andric   // First, split the BUILD_VECTOR for vector pairs. We could generate
161681ad6265SDimitry Andric   // some pairs directly (via splat), but splats should be generated
161781ad6265SDimitry Andric   // by the combiner prior to getting here.
161881ad6265SDimitry Andric   if (VecTy.getSizeInBits() == 16*Subtarget.getVectorLength()) {
161981ad6265SDimitry Andric     ArrayRef<SDValue> A(Ops);
162081ad6265SDimitry Andric     MVT SingleTy = typeSplit(VecTy).first;
162181ad6265SDimitry Andric     SDValue V0 = buildHvxVectorReg(A.take_front(Size/2), dl, SingleTy, DAG);
162281ad6265SDimitry Andric     SDValue V1 = buildHvxVectorReg(A.drop_front(Size/2), dl, SingleTy, DAG);
162381ad6265SDimitry Andric     return DAG.getNode(ISD::CONCAT_VECTORS, dl, VecTy, V0, V1);
162481ad6265SDimitry Andric   }
162581ad6265SDimitry Andric 
16260b57cec5SDimitry Andric   if (VecTy.getVectorElementType() == MVT::i1)
16270b57cec5SDimitry Andric     return buildHvxVectorPred(Ops, dl, VecTy, DAG);
16280b57cec5SDimitry Andric 
162904eeddc0SDimitry Andric   // In case of MVT::f16 BUILD_VECTOR, since MVT::f16 is
163004eeddc0SDimitry Andric   // not a legal type, just bitcast the node to use i16
163104eeddc0SDimitry Andric   // types and bitcast the result back to f16
163204eeddc0SDimitry Andric   if (VecTy.getVectorElementType() == MVT::f16) {
163304eeddc0SDimitry Andric     SmallVector<SDValue,64> NewOps;
163404eeddc0SDimitry Andric     for (unsigned i = 0; i != Size; i++)
163504eeddc0SDimitry Andric       NewOps.push_back(DAG.getBitcast(MVT::i16, Ops[i]));
163604eeddc0SDimitry Andric 
163704eeddc0SDimitry Andric     SDValue T0 = DAG.getNode(ISD::BUILD_VECTOR, dl,
163804eeddc0SDimitry Andric         tyVector(VecTy, MVT::i16), NewOps);
163904eeddc0SDimitry Andric     return DAG.getBitcast(tyVector(VecTy, MVT::f16), T0);
164004eeddc0SDimitry Andric   }
164104eeddc0SDimitry Andric 
16420b57cec5SDimitry Andric   return buildHvxVectorReg(Ops, dl, VecTy, DAG);
16430b57cec5SDimitry Andric }
16440b57cec5SDimitry Andric 
16450b57cec5SDimitry Andric SDValue
164604eeddc0SDimitry Andric HexagonTargetLowering::LowerHvxSplatVector(SDValue Op, SelectionDAG &DAG)
164704eeddc0SDimitry Andric       const {
164804eeddc0SDimitry Andric   const SDLoc &dl(Op);
164904eeddc0SDimitry Andric   MVT VecTy = ty(Op);
165004eeddc0SDimitry Andric   MVT ArgTy = ty(Op.getOperand(0));
165104eeddc0SDimitry Andric 
165204eeddc0SDimitry Andric   if (ArgTy == MVT::f16) {
165304eeddc0SDimitry Andric     MVT SplatTy =  MVT::getVectorVT(MVT::i16, VecTy.getVectorNumElements());
165404eeddc0SDimitry Andric     SDValue ToInt16 = DAG.getBitcast(MVT::i16, Op.getOperand(0));
165504eeddc0SDimitry Andric     SDValue ToInt32 = DAG.getNode(ISD::ANY_EXTEND, dl, MVT::i32, ToInt16);
165604eeddc0SDimitry Andric     SDValue Splat = DAG.getNode(ISD::SPLAT_VECTOR, dl, SplatTy, ToInt32);
165704eeddc0SDimitry Andric     return DAG.getBitcast(VecTy, Splat);
165804eeddc0SDimitry Andric   }
165904eeddc0SDimitry Andric 
166004eeddc0SDimitry Andric   return SDValue();
166104eeddc0SDimitry Andric }
166204eeddc0SDimitry Andric 
166304eeddc0SDimitry Andric SDValue
16640b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxConcatVectors(SDValue Op, SelectionDAG &DAG)
16650b57cec5SDimitry Andric       const {
16660b57cec5SDimitry Andric   // Vector concatenation of two integer (non-bool) vectors does not need
16670b57cec5SDimitry Andric   // special lowering. Custom-lower concats of bool vectors and expand
16680b57cec5SDimitry Andric   // concats of more than 2 vectors.
16690b57cec5SDimitry Andric   MVT VecTy = ty(Op);
16700b57cec5SDimitry Andric   const SDLoc &dl(Op);
16710b57cec5SDimitry Andric   unsigned NumOp = Op.getNumOperands();
16720b57cec5SDimitry Andric   if (VecTy.getVectorElementType() != MVT::i1) {
16730b57cec5SDimitry Andric     if (NumOp == 2)
16740b57cec5SDimitry Andric       return Op;
16750b57cec5SDimitry Andric     // Expand the other cases into a build-vector.
16760b57cec5SDimitry Andric     SmallVector<SDValue,8> Elems;
16770b57cec5SDimitry Andric     for (SDValue V : Op.getNode()->ops())
16780b57cec5SDimitry Andric       DAG.ExtractVectorElements(V, Elems);
16790b57cec5SDimitry Andric     // A vector of i16 will be broken up into a build_vector of i16's.
16800b57cec5SDimitry Andric     // This is a problem, since at the time of operation legalization,
16810b57cec5SDimitry Andric     // all operations are expected to be type-legalized, and i16 is not
16820b57cec5SDimitry Andric     // a legal type. If any of the extracted elements is not of a valid
16830b57cec5SDimitry Andric     // type, sign-extend it to a valid one.
16840b57cec5SDimitry Andric     for (unsigned i = 0, e = Elems.size(); i != e; ++i) {
16850b57cec5SDimitry Andric       SDValue V = Elems[i];
16860b57cec5SDimitry Andric       MVT Ty = ty(V);
16870b57cec5SDimitry Andric       if (!isTypeLegal(Ty)) {
1688bdd1243dSDimitry Andric         MVT NTy = typeLegalize(Ty, DAG);
16890b57cec5SDimitry Andric         if (V.getOpcode() == ISD::EXTRACT_VECTOR_ELT) {
16900b57cec5SDimitry Andric           Elems[i] = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, NTy,
16910b57cec5SDimitry Andric                                  DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, NTy,
16920b57cec5SDimitry Andric                                              V.getOperand(0), V.getOperand(1)),
16930b57cec5SDimitry Andric                                  DAG.getValueType(Ty));
16940b57cec5SDimitry Andric           continue;
16950b57cec5SDimitry Andric         }
16960b57cec5SDimitry Andric         // A few less complicated cases.
1697e8d8bef9SDimitry Andric         switch (V.getOpcode()) {
1698e8d8bef9SDimitry Andric           case ISD::Constant:
16990b57cec5SDimitry Andric             Elems[i] = DAG.getSExtOrTrunc(V, dl, NTy);
1700e8d8bef9SDimitry Andric             break;
1701e8d8bef9SDimitry Andric           case ISD::UNDEF:
17020b57cec5SDimitry Andric             Elems[i] = DAG.getUNDEF(NTy);
1703e8d8bef9SDimitry Andric             break;
1704e8d8bef9SDimitry Andric           case ISD::TRUNCATE:
1705e8d8bef9SDimitry Andric             Elems[i] = V.getOperand(0);
1706e8d8bef9SDimitry Andric             break;
1707e8d8bef9SDimitry Andric           default:
17080b57cec5SDimitry Andric             llvm_unreachable("Unexpected vector element");
17090b57cec5SDimitry Andric         }
17100b57cec5SDimitry Andric       }
1711e8d8bef9SDimitry Andric     }
17120b57cec5SDimitry Andric     return DAG.getBuildVector(VecTy, dl, Elems);
17130b57cec5SDimitry Andric   }
17140b57cec5SDimitry Andric 
17150b57cec5SDimitry Andric   assert(VecTy.getVectorElementType() == MVT::i1);
17160b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
17170b57cec5SDimitry Andric   assert(isPowerOf2_32(NumOp) && HwLen % NumOp == 0);
17180b57cec5SDimitry Andric 
17190b57cec5SDimitry Andric   SDValue Op0 = Op.getOperand(0);
17200b57cec5SDimitry Andric 
17210b57cec5SDimitry Andric   // If the operands are HVX types (i.e. not scalar predicates), then
17220b57cec5SDimitry Andric   // defer the concatenation, and create QCAT instead.
17230b57cec5SDimitry Andric   if (Subtarget.isHVXVectorType(ty(Op0), true)) {
17240b57cec5SDimitry Andric     if (NumOp == 2)
17250b57cec5SDimitry Andric       return DAG.getNode(HexagonISD::QCAT, dl, VecTy, Op0, Op.getOperand(1));
17260b57cec5SDimitry Andric 
17270b57cec5SDimitry Andric     ArrayRef<SDUse> U(Op.getNode()->ops());
17280b57cec5SDimitry Andric     SmallVector<SDValue,4> SV(U.begin(), U.end());
17290b57cec5SDimitry Andric     ArrayRef<SDValue> Ops(SV);
17300b57cec5SDimitry Andric 
17310b57cec5SDimitry Andric     MVT HalfTy = typeSplit(VecTy).first;
17320b57cec5SDimitry Andric     SDValue V0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, HalfTy,
17330b57cec5SDimitry Andric                              Ops.take_front(NumOp/2));
17340b57cec5SDimitry Andric     SDValue V1 = DAG.getNode(ISD::CONCAT_VECTORS, dl, HalfTy,
17350b57cec5SDimitry Andric                              Ops.take_back(NumOp/2));
17360b57cec5SDimitry Andric     return DAG.getNode(HexagonISD::QCAT, dl, VecTy, V0, V1);
17370b57cec5SDimitry Andric   }
17380b57cec5SDimitry Andric 
17390b57cec5SDimitry Andric   // Count how many bytes (in a vector register) each bit in VecTy
17400b57cec5SDimitry Andric   // corresponds to.
17410b57cec5SDimitry Andric   unsigned BitBytes = HwLen / VecTy.getVectorNumElements();
17420b57cec5SDimitry Andric 
17430b57cec5SDimitry Andric   SmallVector<SDValue,8> Prefixes;
17440b57cec5SDimitry Andric   for (SDValue V : Op.getNode()->op_values()) {
17450b57cec5SDimitry Andric     SDValue P = createHvxPrefixPred(V, dl, BitBytes, true, DAG);
17460b57cec5SDimitry Andric     Prefixes.push_back(P);
17470b57cec5SDimitry Andric   }
17480b57cec5SDimitry Andric 
17490b57cec5SDimitry Andric   unsigned InpLen = ty(Op.getOperand(0)).getVectorNumElements();
17500b57cec5SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
17510b57cec5SDimitry Andric   SDValue S = DAG.getConstant(InpLen*BitBytes, dl, MVT::i32);
17520b57cec5SDimitry Andric   SDValue Res = getZero(dl, ByteTy, DAG);
17530b57cec5SDimitry Andric   for (unsigned i = 0, e = Prefixes.size(); i != e; ++i) {
17540b57cec5SDimitry Andric     Res = DAG.getNode(HexagonISD::VROR, dl, ByteTy, Res, S);
17550b57cec5SDimitry Andric     Res = DAG.getNode(ISD::OR, dl, ByteTy, Res, Prefixes[e-i-1]);
17560b57cec5SDimitry Andric   }
17570b57cec5SDimitry Andric   return DAG.getNode(HexagonISD::V2Q, dl, VecTy, Res);
17580b57cec5SDimitry Andric }
17590b57cec5SDimitry Andric 
17600b57cec5SDimitry Andric SDValue
17610b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxExtractElement(SDValue Op, SelectionDAG &DAG)
17620b57cec5SDimitry Andric       const {
17630b57cec5SDimitry Andric   // Change the type of the extracted element to i32.
17640b57cec5SDimitry Andric   SDValue VecV = Op.getOperand(0);
17650b57cec5SDimitry Andric   MVT ElemTy = ty(VecV).getVectorElementType();
17660b57cec5SDimitry Andric   const SDLoc &dl(Op);
17670b57cec5SDimitry Andric   SDValue IdxV = Op.getOperand(1);
17680b57cec5SDimitry Andric   if (ElemTy == MVT::i1)
17690b57cec5SDimitry Andric     return extractHvxElementPred(VecV, IdxV, dl, ty(Op), DAG);
17700b57cec5SDimitry Andric 
17710b57cec5SDimitry Andric   return extractHvxElementReg(VecV, IdxV, dl, ty(Op), DAG);
17720b57cec5SDimitry Andric }
17730b57cec5SDimitry Andric 
17740b57cec5SDimitry Andric SDValue
17750b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxInsertElement(SDValue Op, SelectionDAG &DAG)
17760b57cec5SDimitry Andric       const {
17770b57cec5SDimitry Andric   const SDLoc &dl(Op);
177804eeddc0SDimitry Andric   MVT VecTy = ty(Op);
17790b57cec5SDimitry Andric   SDValue VecV = Op.getOperand(0);
17800b57cec5SDimitry Andric   SDValue ValV = Op.getOperand(1);
17810b57cec5SDimitry Andric   SDValue IdxV = Op.getOperand(2);
17820b57cec5SDimitry Andric   MVT ElemTy = ty(VecV).getVectorElementType();
17830b57cec5SDimitry Andric   if (ElemTy == MVT::i1)
17840b57cec5SDimitry Andric     return insertHvxElementPred(VecV, IdxV, ValV, dl, DAG);
17850b57cec5SDimitry Andric 
178604eeddc0SDimitry Andric   if (ElemTy == MVT::f16) {
178704eeddc0SDimitry Andric     SDValue T0 = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl,
178804eeddc0SDimitry Andric         tyVector(VecTy, MVT::i16),
178904eeddc0SDimitry Andric         DAG.getBitcast(tyVector(VecTy, MVT::i16), VecV),
179004eeddc0SDimitry Andric         DAG.getBitcast(MVT::i16, ValV), IdxV);
179104eeddc0SDimitry Andric     return DAG.getBitcast(tyVector(VecTy, MVT::f16), T0);
179204eeddc0SDimitry Andric   }
179304eeddc0SDimitry Andric 
17940b57cec5SDimitry Andric   return insertHvxElementReg(VecV, IdxV, ValV, dl, DAG);
17950b57cec5SDimitry Andric }
17960b57cec5SDimitry Andric 
17970b57cec5SDimitry Andric SDValue
17980b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxExtractSubvector(SDValue Op, SelectionDAG &DAG)
17990b57cec5SDimitry Andric       const {
18000b57cec5SDimitry Andric   SDValue SrcV = Op.getOperand(0);
18010b57cec5SDimitry Andric   MVT SrcTy = ty(SrcV);
18020b57cec5SDimitry Andric   MVT DstTy = ty(Op);
18030b57cec5SDimitry Andric   SDValue IdxV = Op.getOperand(1);
1804*1db9f3b2SDimitry Andric   unsigned Idx = IdxV.getNode()->getAsZExtVal();
18050b57cec5SDimitry Andric   assert(Idx % DstTy.getVectorNumElements() == 0);
18060b57cec5SDimitry Andric   (void)Idx;
18070b57cec5SDimitry Andric   const SDLoc &dl(Op);
18080b57cec5SDimitry Andric 
18090b57cec5SDimitry Andric   MVT ElemTy = SrcTy.getVectorElementType();
18100b57cec5SDimitry Andric   if (ElemTy == MVT::i1)
18110b57cec5SDimitry Andric     return extractHvxSubvectorPred(SrcV, IdxV, dl, DstTy, DAG);
18120b57cec5SDimitry Andric 
1813bdd1243dSDimitry Andric   return extractHvxSubvectorReg(Op, SrcV, IdxV, dl, DstTy, DAG);
18140b57cec5SDimitry Andric }
18150b57cec5SDimitry Andric 
18160b57cec5SDimitry Andric SDValue
18170b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxInsertSubvector(SDValue Op, SelectionDAG &DAG)
18180b57cec5SDimitry Andric       const {
18190b57cec5SDimitry Andric   // Idx does not need to be a constant.
18200b57cec5SDimitry Andric   SDValue VecV = Op.getOperand(0);
18210b57cec5SDimitry Andric   SDValue ValV = Op.getOperand(1);
18220b57cec5SDimitry Andric   SDValue IdxV = Op.getOperand(2);
18230b57cec5SDimitry Andric 
18240b57cec5SDimitry Andric   const SDLoc &dl(Op);
18250b57cec5SDimitry Andric   MVT VecTy = ty(VecV);
18260b57cec5SDimitry Andric   MVT ElemTy = VecTy.getVectorElementType();
18270b57cec5SDimitry Andric   if (ElemTy == MVT::i1)
18280b57cec5SDimitry Andric     return insertHvxSubvectorPred(VecV, ValV, IdxV, dl, DAG);
18290b57cec5SDimitry Andric 
18300b57cec5SDimitry Andric   return insertHvxSubvectorReg(VecV, ValV, IdxV, dl, DAG);
18310b57cec5SDimitry Andric }
18320b57cec5SDimitry Andric 
18330b57cec5SDimitry Andric SDValue
18340b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxAnyExt(SDValue Op, SelectionDAG &DAG) const {
18350b57cec5SDimitry Andric   // Lower any-extends of boolean vectors to sign-extends, since they
18360b57cec5SDimitry Andric   // translate directly to Q2V. Zero-extending could also be done equally
18370b57cec5SDimitry Andric   // fast, but Q2V is used/recognized in more places.
18380b57cec5SDimitry Andric   // For all other vectors, use zero-extend.
18390b57cec5SDimitry Andric   MVT ResTy = ty(Op);
18400b57cec5SDimitry Andric   SDValue InpV = Op.getOperand(0);
18410b57cec5SDimitry Andric   MVT ElemTy = ty(InpV).getVectorElementType();
18420b57cec5SDimitry Andric   if (ElemTy == MVT::i1 && Subtarget.isHVXVectorType(ResTy))
18430b57cec5SDimitry Andric     return LowerHvxSignExt(Op, DAG);
18440b57cec5SDimitry Andric   return DAG.getNode(ISD::ZERO_EXTEND, SDLoc(Op), ResTy, InpV);
18450b57cec5SDimitry Andric }
18460b57cec5SDimitry Andric 
18470b57cec5SDimitry Andric SDValue
18480b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxSignExt(SDValue Op, SelectionDAG &DAG) const {
18490b57cec5SDimitry Andric   MVT ResTy = ty(Op);
18500b57cec5SDimitry Andric   SDValue InpV = Op.getOperand(0);
18510b57cec5SDimitry Andric   MVT ElemTy = ty(InpV).getVectorElementType();
18520b57cec5SDimitry Andric   if (ElemTy == MVT::i1 && Subtarget.isHVXVectorType(ResTy))
18530b57cec5SDimitry Andric     return extendHvxVectorPred(InpV, SDLoc(Op), ty(Op), false, DAG);
18540b57cec5SDimitry Andric   return Op;
18550b57cec5SDimitry Andric }
18560b57cec5SDimitry Andric 
18570b57cec5SDimitry Andric SDValue
18580b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxZeroExt(SDValue Op, SelectionDAG &DAG) const {
18590b57cec5SDimitry Andric   MVT ResTy = ty(Op);
18600b57cec5SDimitry Andric   SDValue InpV = Op.getOperand(0);
18610b57cec5SDimitry Andric   MVT ElemTy = ty(InpV).getVectorElementType();
18620b57cec5SDimitry Andric   if (ElemTy == MVT::i1 && Subtarget.isHVXVectorType(ResTy))
18630b57cec5SDimitry Andric     return extendHvxVectorPred(InpV, SDLoc(Op), ty(Op), true, DAG);
18640b57cec5SDimitry Andric   return Op;
18650b57cec5SDimitry Andric }
18660b57cec5SDimitry Andric 
18670b57cec5SDimitry Andric SDValue
18680b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxCttz(SDValue Op, SelectionDAG &DAG) const {
18690b57cec5SDimitry Andric   // Lower vector CTTZ into a computation using CTLZ (Hacker's Delight):
18700b57cec5SDimitry Andric   // cttz(x) = bitwidth(x) - ctlz(~x & (x-1))
18710b57cec5SDimitry Andric   const SDLoc &dl(Op);
18720b57cec5SDimitry Andric   MVT ResTy = ty(Op);
18730b57cec5SDimitry Andric   SDValue InpV = Op.getOperand(0);
18740b57cec5SDimitry Andric   assert(ResTy == ty(InpV));
18750b57cec5SDimitry Andric 
18760b57cec5SDimitry Andric   // Calculate the vectors of 1 and bitwidth(x).
18770b57cec5SDimitry Andric   MVT ElemTy = ty(InpV).getVectorElementType();
18780b57cec5SDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
1879e8d8bef9SDimitry Andric 
1880e8d8bef9SDimitry Andric   SDValue Vec1 = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
1881e8d8bef9SDimitry Andric                              DAG.getConstant(1, dl, MVT::i32));
1882e8d8bef9SDimitry Andric   SDValue VecW = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
1883e8d8bef9SDimitry Andric                              DAG.getConstant(ElemWidth, dl, MVT::i32));
1884e8d8bef9SDimitry Andric   SDValue VecN1 = DAG.getNode(ISD::SPLAT_VECTOR, dl, ResTy,
18850b57cec5SDimitry Andric                               DAG.getConstant(-1, dl, MVT::i32));
1886e8d8bef9SDimitry Andric 
18870b57cec5SDimitry Andric   // Do not use DAG.getNOT, because that would create BUILD_VECTOR with
18880b57cec5SDimitry Andric   // a BITCAST. Here we can skip the BITCAST (so we don't have to handle
18890b57cec5SDimitry Andric   // it separately in custom combine or selection).
18900b57cec5SDimitry Andric   SDValue A = DAG.getNode(ISD::AND, dl, ResTy,
18910b57cec5SDimitry Andric                           {DAG.getNode(ISD::XOR, dl, ResTy, {InpV, VecN1}),
18920b57cec5SDimitry Andric                            DAG.getNode(ISD::SUB, dl, ResTy, {InpV, Vec1})});
18930b57cec5SDimitry Andric   return DAG.getNode(ISD::SUB, dl, ResTy,
18940b57cec5SDimitry Andric                      {VecW, DAG.getNode(ISD::CTLZ, dl, ResTy, A)});
18950b57cec5SDimitry Andric }
18960b57cec5SDimitry Andric 
18970b57cec5SDimitry Andric SDValue
18980b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxMulh(SDValue Op, SelectionDAG &DAG) const {
18990b57cec5SDimitry Andric   const SDLoc &dl(Op);
1900bdd1243dSDimitry Andric   MVT ResTy = ty(Op);
1901bdd1243dSDimitry Andric   assert(ResTy.getVectorElementType() == MVT::i32);
19020b57cec5SDimitry Andric 
19030b57cec5SDimitry Andric   SDValue Vs = Op.getOperand(0);
19040b57cec5SDimitry Andric   SDValue Vt = Op.getOperand(1);
19050b57cec5SDimitry Andric 
1906bdd1243dSDimitry Andric   SDVTList ResTys = DAG.getVTList(ResTy, ResTy);
1907bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
19080b57cec5SDimitry Andric 
1909bdd1243dSDimitry Andric   // On HVX v62+ producing the full product is cheap, so legalize MULH to LOHI.
1910bdd1243dSDimitry Andric   if (Opc == ISD::MULHU)
1911bdd1243dSDimitry Andric     return DAG.getNode(HexagonISD::UMUL_LOHI, dl, ResTys, {Vs, Vt}).getValue(1);
1912bdd1243dSDimitry Andric   if (Opc == ISD::MULHS)
1913bdd1243dSDimitry Andric     return DAG.getNode(HexagonISD::SMUL_LOHI, dl, ResTys, {Vs, Vt}).getValue(1);
1914bdd1243dSDimitry Andric 
1915bdd1243dSDimitry Andric #ifndef NDEBUG
1916bdd1243dSDimitry Andric   Op.dump(&DAG);
1917bdd1243dSDimitry Andric #endif
1918bdd1243dSDimitry Andric   llvm_unreachable("Unexpected mulh operation");
19190b57cec5SDimitry Andric }
19200b57cec5SDimitry Andric 
1921bdd1243dSDimitry Andric SDValue
1922bdd1243dSDimitry Andric HexagonTargetLowering::LowerHvxMulLoHi(SDValue Op, SelectionDAG &DAG) const {
1923bdd1243dSDimitry Andric   const SDLoc &dl(Op);
1924bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
1925bdd1243dSDimitry Andric   SDValue Vu = Op.getOperand(0);
1926bdd1243dSDimitry Andric   SDValue Vv = Op.getOperand(1);
19270b57cec5SDimitry Andric 
1928bdd1243dSDimitry Andric   // If the HI part is not used, convert it to a regular MUL.
1929bdd1243dSDimitry Andric   if (auto HiVal = Op.getValue(1); HiVal.use_empty()) {
1930bdd1243dSDimitry Andric     // Need to preserve the types and the number of values.
1931bdd1243dSDimitry Andric     SDValue Hi = DAG.getUNDEF(ty(HiVal));
1932bdd1243dSDimitry Andric     SDValue Lo = DAG.getNode(ISD::MUL, dl, ty(Op), {Vu, Vv});
1933bdd1243dSDimitry Andric     return DAG.getMergeValues({Lo, Hi}, dl);
1934bdd1243dSDimitry Andric   }
1935e8d8bef9SDimitry Andric 
1936bdd1243dSDimitry Andric   bool SignedVu = Opc == HexagonISD::SMUL_LOHI;
1937bdd1243dSDimitry Andric   bool SignedVv = Opc == HexagonISD::SMUL_LOHI || Opc == HexagonISD::USMUL_LOHI;
1938e8d8bef9SDimitry Andric 
1939bdd1243dSDimitry Andric   // Legal on HVX v62+, but lower it here because patterns can't handle multi-
1940bdd1243dSDimitry Andric   // valued nodes.
1941e8d8bef9SDimitry Andric   if (Subtarget.useHVXV62Ops())
1942bdd1243dSDimitry Andric     return emitHvxMulLoHiV62(Vu, SignedVu, Vv, SignedVv, dl, DAG);
1943bdd1243dSDimitry Andric 
1944bdd1243dSDimitry Andric   if (Opc == HexagonISD::SMUL_LOHI) {
1945bdd1243dSDimitry Andric     // Direct MULHS expansion is cheaper than doing the whole SMUL_LOHI,
1946bdd1243dSDimitry Andric     // for other signedness LOHI is cheaper.
1947bdd1243dSDimitry Andric     if (auto LoVal = Op.getValue(0); LoVal.use_empty()) {
1948bdd1243dSDimitry Andric       SDValue Hi = emitHvxMulHsV60(Vu, Vv, dl, DAG);
1949bdd1243dSDimitry Andric       SDValue Lo = DAG.getUNDEF(ty(LoVal));
1950bdd1243dSDimitry Andric       return DAG.getMergeValues({Lo, Hi}, dl);
1951bdd1243dSDimitry Andric     }
19520b57cec5SDimitry Andric   }
19530b57cec5SDimitry Andric 
1954bdd1243dSDimitry Andric   return emitHvxMulLoHiV60(Vu, SignedVu, Vv, SignedVv, dl, DAG);
19550b57cec5SDimitry Andric }
19560b57cec5SDimitry Andric 
19570b57cec5SDimitry Andric SDValue
19585ffd83dbSDimitry Andric HexagonTargetLowering::LowerHvxBitcast(SDValue Op, SelectionDAG &DAG) const {
1959349cc55cSDimitry Andric   SDValue Val = Op.getOperand(0);
19605ffd83dbSDimitry Andric   MVT ResTy = ty(Op);
1961349cc55cSDimitry Andric   MVT ValTy = ty(Val);
19625ffd83dbSDimitry Andric   const SDLoc &dl(Op);
19635ffd83dbSDimitry Andric 
1964349cc55cSDimitry Andric   if (isHvxBoolTy(ValTy) && ResTy.isScalarInteger()) {
19655ffd83dbSDimitry Andric     unsigned HwLen = Subtarget.getVectorLength();
19665ffd83dbSDimitry Andric     MVT WordTy = MVT::getVectorVT(MVT::i32, HwLen/4);
1967349cc55cSDimitry Andric     SDValue VQ = compressHvxPred(Val, dl, WordTy, DAG);
19685ffd83dbSDimitry Andric     unsigned BitWidth = ResTy.getSizeInBits();
19695ffd83dbSDimitry Andric 
19705ffd83dbSDimitry Andric     if (BitWidth < 64) {
19715ffd83dbSDimitry Andric       SDValue W0 = extractHvxElementReg(VQ, DAG.getConstant(0, dl, MVT::i32),
19725ffd83dbSDimitry Andric           dl, MVT::i32, DAG);
19735ffd83dbSDimitry Andric       if (BitWidth == 32)
19745ffd83dbSDimitry Andric         return W0;
19755ffd83dbSDimitry Andric       assert(BitWidth < 32u);
19765ffd83dbSDimitry Andric       return DAG.getZExtOrTrunc(W0, dl, ResTy);
19775ffd83dbSDimitry Andric     }
19785ffd83dbSDimitry Andric 
19795ffd83dbSDimitry Andric     // The result is >= 64 bits. The only options are 64 or 128.
19805ffd83dbSDimitry Andric     assert(BitWidth == 64 || BitWidth == 128);
19815ffd83dbSDimitry Andric     SmallVector<SDValue,4> Words;
19825ffd83dbSDimitry Andric     for (unsigned i = 0; i != BitWidth/32; ++i) {
19835ffd83dbSDimitry Andric       SDValue W = extractHvxElementReg(
19845ffd83dbSDimitry Andric           VQ, DAG.getConstant(i, dl, MVT::i32), dl, MVT::i32, DAG);
19855ffd83dbSDimitry Andric       Words.push_back(W);
19865ffd83dbSDimitry Andric     }
19875ffd83dbSDimitry Andric     SmallVector<SDValue,2> Combines;
19885ffd83dbSDimitry Andric     assert(Words.size() % 2 == 0);
19895ffd83dbSDimitry Andric     for (unsigned i = 0, e = Words.size(); i < e; i += 2) {
1990bdd1243dSDimitry Andric       SDValue C = getCombine(Words[i+1], Words[i], dl, MVT::i64, DAG);
19915ffd83dbSDimitry Andric       Combines.push_back(C);
19925ffd83dbSDimitry Andric     }
19935ffd83dbSDimitry Andric 
19945ffd83dbSDimitry Andric     if (BitWidth == 64)
19955ffd83dbSDimitry Andric       return Combines[0];
19965ffd83dbSDimitry Andric 
19975ffd83dbSDimitry Andric     return DAG.getNode(ISD::BUILD_PAIR, dl, ResTy, Combines);
19985ffd83dbSDimitry Andric   }
1999349cc55cSDimitry Andric   if (isHvxBoolTy(ResTy) && ValTy.isScalarInteger()) {
2000349cc55cSDimitry Andric     // Handle bitcast from i128 -> v128i1 and i64 -> v64i1.
2001349cc55cSDimitry Andric     unsigned BitWidth = ValTy.getSizeInBits();
2002349cc55cSDimitry Andric     unsigned HwLen = Subtarget.getVectorLength();
2003349cc55cSDimitry Andric     assert(BitWidth == HwLen);
2004349cc55cSDimitry Andric 
2005349cc55cSDimitry Andric     MVT ValAsVecTy = MVT::getVectorVT(MVT::i8, BitWidth / 8);
2006349cc55cSDimitry Andric     SDValue ValAsVec = DAG.getBitcast(ValAsVecTy, Val);
2007349cc55cSDimitry Andric     // Splat each byte of Val 8 times.
2008349cc55cSDimitry Andric     // Bytes = [(b0)x8, (b1)x8, ...., (b15)x8]
2009349cc55cSDimitry Andric     // where b0, b1,..., b15 are least to most significant bytes of I.
2010349cc55cSDimitry Andric     SmallVector<SDValue, 128> Bytes;
2011349cc55cSDimitry Andric     // Tmp: 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80, 0x01,0x02,0x04,0x08,...
2012349cc55cSDimitry Andric     // These are bytes with the LSB rotated left with respect to their index.
2013349cc55cSDimitry Andric     SmallVector<SDValue, 128> Tmp;
2014349cc55cSDimitry Andric     for (unsigned I = 0; I != HwLen / 8; ++I) {
2015349cc55cSDimitry Andric       SDValue Idx = DAG.getConstant(I, dl, MVT::i32);
2016349cc55cSDimitry Andric       SDValue Byte =
2017349cc55cSDimitry Andric           DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::i8, ValAsVec, Idx);
2018349cc55cSDimitry Andric       for (unsigned J = 0; J != 8; ++J) {
2019349cc55cSDimitry Andric         Bytes.push_back(Byte);
2020349cc55cSDimitry Andric         Tmp.push_back(DAG.getConstant(1ull << J, dl, MVT::i8));
2021349cc55cSDimitry Andric       }
2022349cc55cSDimitry Andric     }
2023349cc55cSDimitry Andric 
2024349cc55cSDimitry Andric     MVT ConstantVecTy = MVT::getVectorVT(MVT::i8, HwLen);
2025349cc55cSDimitry Andric     SDValue ConstantVec = DAG.getBuildVector(ConstantVecTy, dl, Tmp);
2026349cc55cSDimitry Andric     SDValue I2V = buildHvxVectorReg(Bytes, dl, ConstantVecTy, DAG);
2027349cc55cSDimitry Andric 
2028349cc55cSDimitry Andric     // Each Byte in the I2V will be set iff corresponding bit is set in Val.
2029349cc55cSDimitry Andric     I2V = DAG.getNode(ISD::AND, dl, ConstantVecTy, {I2V, ConstantVec});
2030349cc55cSDimitry Andric     return DAG.getNode(HexagonISD::V2Q, dl, ResTy, I2V);
2031349cc55cSDimitry Andric   }
20325ffd83dbSDimitry Andric 
20335ffd83dbSDimitry Andric   return Op;
20345ffd83dbSDimitry Andric }
20355ffd83dbSDimitry Andric 
20365ffd83dbSDimitry Andric SDValue
20370b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxExtend(SDValue Op, SelectionDAG &DAG) const {
20380b57cec5SDimitry Andric   // Sign- and zero-extends are legal.
20390b57cec5SDimitry Andric   assert(Op.getOpcode() == ISD::ANY_EXTEND_VECTOR_INREG);
20400b57cec5SDimitry Andric   return DAG.getNode(ISD::ZERO_EXTEND_VECTOR_INREG, SDLoc(Op), ty(Op),
20410b57cec5SDimitry Andric                      Op.getOperand(0));
20420b57cec5SDimitry Andric }
20430b57cec5SDimitry Andric 
20440b57cec5SDimitry Andric SDValue
2045e8d8bef9SDimitry Andric HexagonTargetLowering::LowerHvxSelect(SDValue Op, SelectionDAG &DAG) const {
2046e8d8bef9SDimitry Andric   MVT ResTy = ty(Op);
2047e8d8bef9SDimitry Andric   if (ResTy.getVectorElementType() != MVT::i1)
2048e8d8bef9SDimitry Andric     return Op;
2049e8d8bef9SDimitry Andric 
2050e8d8bef9SDimitry Andric   const SDLoc &dl(Op);
2051e8d8bef9SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
2052e8d8bef9SDimitry Andric   unsigned VecLen = ResTy.getVectorNumElements();
2053e8d8bef9SDimitry Andric   assert(HwLen % VecLen == 0);
2054e8d8bef9SDimitry Andric   unsigned ElemSize = HwLen / VecLen;
2055e8d8bef9SDimitry Andric 
2056e8d8bef9SDimitry Andric   MVT VecTy = MVT::getVectorVT(MVT::getIntegerVT(ElemSize * 8), VecLen);
2057e8d8bef9SDimitry Andric   SDValue S =
2058e8d8bef9SDimitry Andric       DAG.getNode(ISD::SELECT, dl, VecTy, Op.getOperand(0),
2059e8d8bef9SDimitry Andric                   DAG.getNode(HexagonISD::Q2V, dl, VecTy, Op.getOperand(1)),
2060e8d8bef9SDimitry Andric                   DAG.getNode(HexagonISD::Q2V, dl, VecTy, Op.getOperand(2)));
2061e8d8bef9SDimitry Andric   return DAG.getNode(HexagonISD::V2Q, dl, ResTy, S);
2062e8d8bef9SDimitry Andric }
2063e8d8bef9SDimitry Andric 
2064e8d8bef9SDimitry Andric SDValue
20650b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxShift(SDValue Op, SelectionDAG &DAG) const {
20660b57cec5SDimitry Andric   if (SDValue S = getVectorShiftByInt(Op, DAG))
20670b57cec5SDimitry Andric     return S;
20680b57cec5SDimitry Andric   return Op;
20690b57cec5SDimitry Andric }
20700b57cec5SDimitry Andric 
20710b57cec5SDimitry Andric SDValue
2072bdd1243dSDimitry Andric HexagonTargetLowering::LowerHvxFunnelShift(SDValue Op,
2073bdd1243dSDimitry Andric                                            SelectionDAG &DAG) const {
2074bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
2075bdd1243dSDimitry Andric   assert(Opc == ISD::FSHL || Opc == ISD::FSHR);
2076bdd1243dSDimitry Andric 
2077bdd1243dSDimitry Andric   // Make sure the shift amount is within the range of the bitwidth
2078bdd1243dSDimitry Andric   // of the element type.
2079bdd1243dSDimitry Andric   SDValue A = Op.getOperand(0);
2080bdd1243dSDimitry Andric   SDValue B = Op.getOperand(1);
2081bdd1243dSDimitry Andric   SDValue S = Op.getOperand(2);
2082bdd1243dSDimitry Andric 
2083bdd1243dSDimitry Andric   MVT InpTy = ty(A);
2084bdd1243dSDimitry Andric   MVT ElemTy = InpTy.getVectorElementType();
2085bdd1243dSDimitry Andric 
2086bdd1243dSDimitry Andric   const SDLoc &dl(Op);
2087bdd1243dSDimitry Andric   unsigned ElemWidth = ElemTy.getSizeInBits();
2088bdd1243dSDimitry Andric   bool IsLeft = Opc == ISD::FSHL;
2089bdd1243dSDimitry Andric 
2090bdd1243dSDimitry Andric   // The expansion into regular shifts produces worse code for i8 and for
2091bdd1243dSDimitry Andric   // right shift of i32 on v65+.
2092bdd1243dSDimitry Andric   bool UseShifts = ElemTy != MVT::i8;
2093bdd1243dSDimitry Andric   if (Subtarget.useHVXV65Ops() && ElemTy == MVT::i32)
2094bdd1243dSDimitry Andric     UseShifts = false;
2095bdd1243dSDimitry Andric 
2096bdd1243dSDimitry Andric   if (SDValue SplatV = getSplatValue(S, DAG); SplatV && UseShifts) {
2097bdd1243dSDimitry Andric     // If this is a funnel shift by a scalar, lower it into regular shifts.
2098bdd1243dSDimitry Andric     SDValue Mask = DAG.getConstant(ElemWidth - 1, dl, MVT::i32);
2099bdd1243dSDimitry Andric     SDValue ModS =
2100bdd1243dSDimitry Andric         DAG.getNode(ISD::AND, dl, MVT::i32,
2101bdd1243dSDimitry Andric                     {DAG.getZExtOrTrunc(SplatV, dl, MVT::i32), Mask});
2102bdd1243dSDimitry Andric     SDValue NegS =
2103bdd1243dSDimitry Andric         DAG.getNode(ISD::SUB, dl, MVT::i32,
2104bdd1243dSDimitry Andric                     {DAG.getConstant(ElemWidth, dl, MVT::i32), ModS});
2105bdd1243dSDimitry Andric     SDValue IsZero =
2106bdd1243dSDimitry Andric         DAG.getSetCC(dl, MVT::i1, ModS, getZero(dl, MVT::i32, DAG), ISD::SETEQ);
2107bdd1243dSDimitry Andric     // FSHL A, B  =>  A <<  | B >>n
2108bdd1243dSDimitry Andric     // FSHR A, B  =>  A <<n | B >>
2109bdd1243dSDimitry Andric     SDValue Part1 =
2110bdd1243dSDimitry Andric         DAG.getNode(HexagonISD::VASL, dl, InpTy, {A, IsLeft ? ModS : NegS});
2111bdd1243dSDimitry Andric     SDValue Part2 =
2112bdd1243dSDimitry Andric         DAG.getNode(HexagonISD::VLSR, dl, InpTy, {B, IsLeft ? NegS : ModS});
2113bdd1243dSDimitry Andric     SDValue Or = DAG.getNode(ISD::OR, dl, InpTy, {Part1, Part2});
2114bdd1243dSDimitry Andric     // If the shift amount was 0, pick A or B, depending on the direction.
2115bdd1243dSDimitry Andric     // The opposite shift will also be by 0, so the "Or" will be incorrect.
2116bdd1243dSDimitry Andric     return DAG.getNode(ISD::SELECT, dl, InpTy, {IsZero, (IsLeft ? A : B), Or});
2117bdd1243dSDimitry Andric   }
2118bdd1243dSDimitry Andric 
2119bdd1243dSDimitry Andric   SDValue Mask = DAG.getSplatBuildVector(
2120bdd1243dSDimitry Andric       InpTy, dl, DAG.getConstant(ElemWidth - 1, dl, ElemTy));
2121bdd1243dSDimitry Andric 
2122bdd1243dSDimitry Andric   unsigned MOpc = Opc == ISD::FSHL ? HexagonISD::MFSHL : HexagonISD::MFSHR;
2123bdd1243dSDimitry Andric   return DAG.getNode(MOpc, dl, ty(Op),
2124bdd1243dSDimitry Andric                      {A, B, DAG.getNode(ISD::AND, dl, InpTy, {S, Mask})});
2125bdd1243dSDimitry Andric }
2126bdd1243dSDimitry Andric 
2127bdd1243dSDimitry Andric SDValue
21285ffd83dbSDimitry Andric HexagonTargetLowering::LowerHvxIntrinsic(SDValue Op, SelectionDAG &DAG) const {
21295ffd83dbSDimitry Andric   const SDLoc &dl(Op);
2130647cbc5dSDimitry Andric   unsigned IntNo = Op.getConstantOperandVal(0);
2131bdd1243dSDimitry Andric   SmallVector<SDValue> Ops(Op->ops().begin(), Op->ops().end());
2132bdd1243dSDimitry Andric 
2133bdd1243dSDimitry Andric   auto Swap = [&](SDValue P) {
2134bdd1243dSDimitry Andric     return DAG.getMergeValues({P.getValue(1), P.getValue(0)}, dl);
2135bdd1243dSDimitry Andric   };
2136bdd1243dSDimitry Andric 
2137bdd1243dSDimitry Andric   switch (IntNo) {
2138bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_pred_typecast:
2139bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_pred_typecast_128B: {
2140bdd1243dSDimitry Andric     MVT ResTy = ty(Op), InpTy = ty(Ops[1]);
2141bdd1243dSDimitry Andric     if (isHvxBoolTy(ResTy) && isHvxBoolTy(InpTy)) {
2142bdd1243dSDimitry Andric       if (ResTy == InpTy)
2143bdd1243dSDimitry Andric         return Ops[1];
2144bdd1243dSDimitry Andric       return DAG.getNode(HexagonISD::TYPECAST, dl, ResTy, Ops[1]);
21455ffd83dbSDimitry Andric     }
2146bdd1243dSDimitry Andric     break;
21475ffd83dbSDimitry Andric   }
2148bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_vmpyss_parts:
2149bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_vmpyss_parts_128B:
2150bdd1243dSDimitry Andric     return Swap(DAG.getNode(HexagonISD::SMUL_LOHI, dl, Op->getVTList(),
2151bdd1243dSDimitry Andric                             {Ops[1], Ops[2]}));
2152bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_vmpyuu_parts:
2153bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_vmpyuu_parts_128B:
2154bdd1243dSDimitry Andric     return Swap(DAG.getNode(HexagonISD::UMUL_LOHI, dl, Op->getVTList(),
2155bdd1243dSDimitry Andric                             {Ops[1], Ops[2]}));
2156bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_vmpyus_parts:
2157bdd1243dSDimitry Andric   case Intrinsic::hexagon_V6_vmpyus_parts_128B: {
2158bdd1243dSDimitry Andric     return Swap(DAG.getNode(HexagonISD::USMUL_LOHI, dl, Op->getVTList(),
2159bdd1243dSDimitry Andric                             {Ops[1], Ops[2]}));
2160bdd1243dSDimitry Andric   }
2161bdd1243dSDimitry Andric   } // switch
21625ffd83dbSDimitry Andric 
21635ffd83dbSDimitry Andric   return Op;
21645ffd83dbSDimitry Andric }
21655ffd83dbSDimitry Andric 
21665ffd83dbSDimitry Andric SDValue
2167e8d8bef9SDimitry Andric HexagonTargetLowering::LowerHvxMaskedOp(SDValue Op, SelectionDAG &DAG) const {
2168e8d8bef9SDimitry Andric   const SDLoc &dl(Op);
2169e8d8bef9SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
2170e8d8bef9SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
2171e8d8bef9SDimitry Andric   auto *MaskN = cast<MaskedLoadStoreSDNode>(Op.getNode());
2172e8d8bef9SDimitry Andric   SDValue Mask = MaskN->getMask();
2173e8d8bef9SDimitry Andric   SDValue Chain = MaskN->getChain();
2174e8d8bef9SDimitry Andric   SDValue Base = MaskN->getBasePtr();
2175e8d8bef9SDimitry Andric   auto *MemOp = MF.getMachineMemOperand(MaskN->getMemOperand(), 0, HwLen);
2176e8d8bef9SDimitry Andric 
2177e8d8bef9SDimitry Andric   unsigned Opc = Op->getOpcode();
2178e8d8bef9SDimitry Andric   assert(Opc == ISD::MLOAD || Opc == ISD::MSTORE);
2179e8d8bef9SDimitry Andric 
2180e8d8bef9SDimitry Andric   if (Opc == ISD::MLOAD) {
2181e8d8bef9SDimitry Andric     MVT ValTy = ty(Op);
2182e8d8bef9SDimitry Andric     SDValue Load = DAG.getLoad(ValTy, dl, Chain, Base, MemOp);
2183e8d8bef9SDimitry Andric     SDValue Thru = cast<MaskedLoadSDNode>(MaskN)->getPassThru();
2184e8d8bef9SDimitry Andric     if (isUndef(Thru))
2185e8d8bef9SDimitry Andric       return Load;
2186e8d8bef9SDimitry Andric     SDValue VSel = DAG.getNode(ISD::VSELECT, dl, ValTy, Mask, Load, Thru);
2187e8d8bef9SDimitry Andric     return DAG.getMergeValues({VSel, Load.getValue(1)}, dl);
2188e8d8bef9SDimitry Andric   }
2189e8d8bef9SDimitry Andric 
2190e8d8bef9SDimitry Andric   // MSTORE
2191e8d8bef9SDimitry Andric   // HVX only has aligned masked stores.
2192e8d8bef9SDimitry Andric 
2193e8d8bef9SDimitry Andric   // TODO: Fold negations of the mask into the store.
2194e8d8bef9SDimitry Andric   unsigned StoreOpc = Hexagon::V6_vS32b_qpred_ai;
2195e8d8bef9SDimitry Andric   SDValue Value = cast<MaskedStoreSDNode>(MaskN)->getValue();
2196e8d8bef9SDimitry Andric   SDValue Offset0 = DAG.getTargetConstant(0, dl, ty(Base));
2197e8d8bef9SDimitry Andric 
2198e8d8bef9SDimitry Andric   if (MaskN->getAlign().value() % HwLen == 0) {
2199e8d8bef9SDimitry Andric     SDValue Store = getInstr(StoreOpc, dl, MVT::Other,
2200e8d8bef9SDimitry Andric                              {Mask, Base, Offset0, Value, Chain}, DAG);
2201e8d8bef9SDimitry Andric     DAG.setNodeMemRefs(cast<MachineSDNode>(Store.getNode()), {MemOp});
2202e8d8bef9SDimitry Andric     return Store;
2203e8d8bef9SDimitry Andric   }
2204e8d8bef9SDimitry Andric 
2205e8d8bef9SDimitry Andric   // Unaligned case.
2206e8d8bef9SDimitry Andric   auto StoreAlign = [&](SDValue V, SDValue A) {
2207e8d8bef9SDimitry Andric     SDValue Z = getZero(dl, ty(V), DAG);
2208e8d8bef9SDimitry Andric     // TODO: use funnel shifts?
2209e8d8bef9SDimitry Andric     // vlalign(Vu,Vv,Rt) rotates the pair Vu:Vv left by Rt and takes the
2210e8d8bef9SDimitry Andric     // upper half.
2211e8d8bef9SDimitry Andric     SDValue LoV = getInstr(Hexagon::V6_vlalignb, dl, ty(V), {V, Z, A}, DAG);
2212e8d8bef9SDimitry Andric     SDValue HiV = getInstr(Hexagon::V6_vlalignb, dl, ty(V), {Z, V, A}, DAG);
2213e8d8bef9SDimitry Andric     return std::make_pair(LoV, HiV);
2214e8d8bef9SDimitry Andric   };
2215e8d8bef9SDimitry Andric 
2216e8d8bef9SDimitry Andric   MVT ByteTy = MVT::getVectorVT(MVT::i8, HwLen);
2217e8d8bef9SDimitry Andric   MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
2218e8d8bef9SDimitry Andric   SDValue MaskV = DAG.getNode(HexagonISD::Q2V, dl, ByteTy, Mask);
2219e8d8bef9SDimitry Andric   VectorPair Tmp = StoreAlign(MaskV, Base);
2220e8d8bef9SDimitry Andric   VectorPair MaskU = {DAG.getNode(HexagonISD::V2Q, dl, BoolTy, Tmp.first),
2221e8d8bef9SDimitry Andric                       DAG.getNode(HexagonISD::V2Q, dl, BoolTy, Tmp.second)};
2222e8d8bef9SDimitry Andric   VectorPair ValueU = StoreAlign(Value, Base);
2223e8d8bef9SDimitry Andric 
2224e8d8bef9SDimitry Andric   SDValue Offset1 = DAG.getTargetConstant(HwLen, dl, MVT::i32);
2225e8d8bef9SDimitry Andric   SDValue StoreLo =
2226e8d8bef9SDimitry Andric       getInstr(StoreOpc, dl, MVT::Other,
2227e8d8bef9SDimitry Andric                {MaskU.first, Base, Offset0, ValueU.first, Chain}, DAG);
2228e8d8bef9SDimitry Andric   SDValue StoreHi =
2229e8d8bef9SDimitry Andric       getInstr(StoreOpc, dl, MVT::Other,
2230e8d8bef9SDimitry Andric                {MaskU.second, Base, Offset1, ValueU.second, Chain}, DAG);
2231e8d8bef9SDimitry Andric   DAG.setNodeMemRefs(cast<MachineSDNode>(StoreLo.getNode()), {MemOp});
2232e8d8bef9SDimitry Andric   DAG.setNodeMemRefs(cast<MachineSDNode>(StoreHi.getNode()), {MemOp});
2233e8d8bef9SDimitry Andric   return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, {StoreLo, StoreHi});
2234e8d8bef9SDimitry Andric }
2235e8d8bef9SDimitry Andric 
223604eeddc0SDimitry Andric SDValue HexagonTargetLowering::LowerHvxFpExtend(SDValue Op,
223704eeddc0SDimitry Andric                                                 SelectionDAG &DAG) const {
2238bdd1243dSDimitry Andric   // This conversion only applies to QFloat. IEEE extension from f16 to f32
2239bdd1243dSDimitry Andric   // is legal (done via a pattern).
224004eeddc0SDimitry Andric   assert(Subtarget.useHVXQFloatOps());
224104eeddc0SDimitry Andric 
224204eeddc0SDimitry Andric   assert(Op->getOpcode() == ISD::FP_EXTEND);
224304eeddc0SDimitry Andric 
224404eeddc0SDimitry Andric   MVT VecTy = ty(Op);
224504eeddc0SDimitry Andric   MVT ArgTy = ty(Op.getOperand(0));
224604eeddc0SDimitry Andric   const SDLoc &dl(Op);
224704eeddc0SDimitry Andric   assert(VecTy == MVT::v64f32 && ArgTy == MVT::v64f16);
224804eeddc0SDimitry Andric 
224904eeddc0SDimitry Andric   SDValue F16Vec = Op.getOperand(0);
225004eeddc0SDimitry Andric 
225104eeddc0SDimitry Andric   APFloat FloatVal = APFloat(1.0f);
225204eeddc0SDimitry Andric   bool Ignored;
225304eeddc0SDimitry Andric   FloatVal.convert(APFloat::IEEEhalf(), APFloat::rmNearestTiesToEven, &Ignored);
225404eeddc0SDimitry Andric   SDValue Fp16Ones = DAG.getConstantFP(FloatVal, dl, ArgTy);
225504eeddc0SDimitry Andric   SDValue VmpyVec =
225604eeddc0SDimitry Andric       getInstr(Hexagon::V6_vmpy_qf32_hf, dl, VecTy, {F16Vec, Fp16Ones}, DAG);
225704eeddc0SDimitry Andric 
225804eeddc0SDimitry Andric   MVT HalfTy = typeSplit(VecTy).first;
225904eeddc0SDimitry Andric   VectorPair Pair = opSplit(VmpyVec, dl, DAG);
226004eeddc0SDimitry Andric   SDValue LoVec =
226104eeddc0SDimitry Andric       getInstr(Hexagon::V6_vconv_sf_qf32, dl, HalfTy, {Pair.first}, DAG);
226204eeddc0SDimitry Andric   SDValue HiVec =
226304eeddc0SDimitry Andric       getInstr(Hexagon::V6_vconv_sf_qf32, dl, HalfTy, {Pair.second}, DAG);
226404eeddc0SDimitry Andric 
226504eeddc0SDimitry Andric   SDValue ShuffVec =
226604eeddc0SDimitry Andric       getInstr(Hexagon::V6_vshuffvdd, dl, VecTy,
226704eeddc0SDimitry Andric                {HiVec, LoVec, DAG.getConstant(-4, dl, MVT::i32)}, DAG);
226804eeddc0SDimitry Andric 
226904eeddc0SDimitry Andric   return ShuffVec;
227004eeddc0SDimitry Andric }
227104eeddc0SDimitry Andric 
227204eeddc0SDimitry Andric SDValue
2273bdd1243dSDimitry Andric HexagonTargetLowering::LowerHvxFpToInt(SDValue Op, SelectionDAG &DAG) const {
227404eeddc0SDimitry Andric   // Catch invalid conversion ops (just in case).
2275bdd1243dSDimitry Andric   assert(Op.getOpcode() == ISD::FP_TO_SINT ||
2276bdd1243dSDimitry Andric          Op.getOpcode() == ISD::FP_TO_UINT);
2277bdd1243dSDimitry Andric 
227804eeddc0SDimitry Andric   MVT ResTy = ty(Op);
227904eeddc0SDimitry Andric   MVT FpTy = ty(Op.getOperand(0)).getVectorElementType();
228004eeddc0SDimitry Andric   MVT IntTy = ResTy.getVectorElementType();
2281bdd1243dSDimitry Andric 
2282bdd1243dSDimitry Andric   if (Subtarget.useHVXIEEEFPOps()) {
2283bdd1243dSDimitry Andric     // There are only conversions from f16.
2284bdd1243dSDimitry Andric     if (FpTy == MVT::f16) {
228504eeddc0SDimitry Andric       // Other int types aren't legal in HVX, so we shouldn't see them here.
228604eeddc0SDimitry Andric       assert(IntTy == MVT::i8 || IntTy == MVT::i16 || IntTy == MVT::i32);
228704eeddc0SDimitry Andric       // Conversions to i8 and i16 are legal.
228804eeddc0SDimitry Andric       if (IntTy == MVT::i8 || IntTy == MVT::i16)
228904eeddc0SDimitry Andric         return Op;
2290bdd1243dSDimitry Andric     }
2291bdd1243dSDimitry Andric   }
2292bdd1243dSDimitry Andric 
2293bdd1243dSDimitry Andric   if (IntTy.getSizeInBits() != FpTy.getSizeInBits())
2294bdd1243dSDimitry Andric     return EqualizeFpIntConversion(Op, DAG);
2295bdd1243dSDimitry Andric 
2296bdd1243dSDimitry Andric   return ExpandHvxFpToInt(Op, DAG);
2297bdd1243dSDimitry Andric }
2298bdd1243dSDimitry Andric 
2299bdd1243dSDimitry Andric SDValue
2300bdd1243dSDimitry Andric HexagonTargetLowering::LowerHvxIntToFp(SDValue Op, SelectionDAG &DAG) const {
2301bdd1243dSDimitry Andric   // Catch invalid conversion ops (just in case).
2302bdd1243dSDimitry Andric   assert(Op.getOpcode() == ISD::SINT_TO_FP ||
2303bdd1243dSDimitry Andric          Op.getOpcode() == ISD::UINT_TO_FP);
2304bdd1243dSDimitry Andric 
2305bdd1243dSDimitry Andric   MVT ResTy = ty(Op);
230604eeddc0SDimitry Andric   MVT IntTy = ty(Op.getOperand(0)).getVectorElementType();
2307bdd1243dSDimitry Andric   MVT FpTy = ResTy.getVectorElementType();
2308bdd1243dSDimitry Andric 
2309bdd1243dSDimitry Andric   if (Subtarget.useHVXIEEEFPOps()) {
2310bdd1243dSDimitry Andric     // There are only conversions to f16.
2311bdd1243dSDimitry Andric     if (FpTy == MVT::f16) {
231204eeddc0SDimitry Andric       // Other int types aren't legal in HVX, so we shouldn't see them here.
231304eeddc0SDimitry Andric       assert(IntTy == MVT::i8 || IntTy == MVT::i16 || IntTy == MVT::i32);
231404eeddc0SDimitry Andric       // i8, i16 -> f16 is legal.
231504eeddc0SDimitry Andric       if (IntTy == MVT::i8 || IntTy == MVT::i16)
231604eeddc0SDimitry Andric         return Op;
231704eeddc0SDimitry Andric     }
2318bdd1243dSDimitry Andric   }
231904eeddc0SDimitry Andric 
2320bdd1243dSDimitry Andric   if (IntTy.getSizeInBits() != FpTy.getSizeInBits())
2321bdd1243dSDimitry Andric     return EqualizeFpIntConversion(Op, DAG);
2322bdd1243dSDimitry Andric 
2323bdd1243dSDimitry Andric   return ExpandHvxIntToFp(Op, DAG);
2324bdd1243dSDimitry Andric }
2325bdd1243dSDimitry Andric 
2326bdd1243dSDimitry Andric HexagonTargetLowering::TypePair
2327bdd1243dSDimitry Andric HexagonTargetLowering::typeExtendToWider(MVT Ty0, MVT Ty1) const {
2328bdd1243dSDimitry Andric   // Compare the widths of elements of the two types, and extend the narrower
2329bdd1243dSDimitry Andric   // type to match the with of the wider type. For vector types, apply this
2330bdd1243dSDimitry Andric   // to the element type.
2331bdd1243dSDimitry Andric   assert(Ty0.isVector() == Ty1.isVector());
2332bdd1243dSDimitry Andric 
2333bdd1243dSDimitry Andric   MVT ElemTy0 = Ty0.getScalarType();
2334bdd1243dSDimitry Andric   MVT ElemTy1 = Ty1.getScalarType();
2335bdd1243dSDimitry Andric 
2336bdd1243dSDimitry Andric   unsigned Width0 = ElemTy0.getSizeInBits();
2337bdd1243dSDimitry Andric   unsigned Width1 = ElemTy1.getSizeInBits();
2338bdd1243dSDimitry Andric   unsigned MaxWidth = std::max(Width0, Width1);
2339bdd1243dSDimitry Andric 
2340bdd1243dSDimitry Andric   auto getScalarWithWidth = [](MVT ScalarTy, unsigned Width) {
2341bdd1243dSDimitry Andric     if (ScalarTy.isInteger())
2342bdd1243dSDimitry Andric       return MVT::getIntegerVT(Width);
2343bdd1243dSDimitry Andric     assert(ScalarTy.isFloatingPoint());
2344bdd1243dSDimitry Andric     return MVT::getFloatingPointVT(Width);
2345bdd1243dSDimitry Andric   };
2346bdd1243dSDimitry Andric 
2347bdd1243dSDimitry Andric   MVT WideETy0 = getScalarWithWidth(ElemTy0, MaxWidth);
2348bdd1243dSDimitry Andric   MVT WideETy1 = getScalarWithWidth(ElemTy1, MaxWidth);
2349bdd1243dSDimitry Andric 
2350bdd1243dSDimitry Andric   if (!Ty0.isVector()) {
2351bdd1243dSDimitry Andric     // Both types are scalars.
2352bdd1243dSDimitry Andric     return {WideETy0, WideETy1};
2353bdd1243dSDimitry Andric   }
2354bdd1243dSDimitry Andric 
2355bdd1243dSDimitry Andric   // Vector types.
2356bdd1243dSDimitry Andric   unsigned NumElem = Ty0.getVectorNumElements();
2357bdd1243dSDimitry Andric   assert(NumElem == Ty1.getVectorNumElements());
2358bdd1243dSDimitry Andric 
2359bdd1243dSDimitry Andric   return {MVT::getVectorVT(WideETy0, NumElem),
2360bdd1243dSDimitry Andric           MVT::getVectorVT(WideETy1, NumElem)};
2361bdd1243dSDimitry Andric }
2362bdd1243dSDimitry Andric 
2363bdd1243dSDimitry Andric HexagonTargetLowering::TypePair
2364bdd1243dSDimitry Andric HexagonTargetLowering::typeWidenToWider(MVT Ty0, MVT Ty1) const {
2365bdd1243dSDimitry Andric   // Compare the numbers of elements of two vector types, and widen the
2366bdd1243dSDimitry Andric   // narrower one to match the number of elements in the wider one.
2367bdd1243dSDimitry Andric   assert(Ty0.isVector() && Ty1.isVector());
2368bdd1243dSDimitry Andric 
2369bdd1243dSDimitry Andric   unsigned Len0 = Ty0.getVectorNumElements();
2370bdd1243dSDimitry Andric   unsigned Len1 = Ty1.getVectorNumElements();
2371bdd1243dSDimitry Andric   if (Len0 == Len1)
2372bdd1243dSDimitry Andric     return {Ty0, Ty1};
2373bdd1243dSDimitry Andric 
2374bdd1243dSDimitry Andric   unsigned MaxLen = std::max(Len0, Len1);
2375bdd1243dSDimitry Andric   return {MVT::getVectorVT(Ty0.getVectorElementType(), MaxLen),
2376bdd1243dSDimitry Andric           MVT::getVectorVT(Ty1.getVectorElementType(), MaxLen)};
2377bdd1243dSDimitry Andric }
2378bdd1243dSDimitry Andric 
2379bdd1243dSDimitry Andric MVT
2380bdd1243dSDimitry Andric HexagonTargetLowering::typeLegalize(MVT Ty, SelectionDAG &DAG) const {
2381bdd1243dSDimitry Andric   EVT LegalTy = getTypeToTransformTo(*DAG.getContext(), Ty);
2382bdd1243dSDimitry Andric   assert(LegalTy.isSimple());
2383bdd1243dSDimitry Andric   return LegalTy.getSimpleVT();
2384bdd1243dSDimitry Andric }
2385bdd1243dSDimitry Andric 
2386bdd1243dSDimitry Andric MVT
2387bdd1243dSDimitry Andric HexagonTargetLowering::typeWidenToHvx(MVT Ty) const {
2388bdd1243dSDimitry Andric   unsigned HwWidth = 8 * Subtarget.getVectorLength();
2389bdd1243dSDimitry Andric   assert(Ty.getSizeInBits() <= HwWidth);
2390bdd1243dSDimitry Andric   if (Ty.getSizeInBits() == HwWidth)
2391bdd1243dSDimitry Andric     return Ty;
2392bdd1243dSDimitry Andric 
2393bdd1243dSDimitry Andric   MVT ElemTy = Ty.getScalarType();
2394bdd1243dSDimitry Andric   return MVT::getVectorVT(ElemTy, HwWidth / ElemTy.getSizeInBits());
2395bdd1243dSDimitry Andric }
2396bdd1243dSDimitry Andric 
2397bdd1243dSDimitry Andric HexagonTargetLowering::VectorPair
2398bdd1243dSDimitry Andric HexagonTargetLowering::emitHvxAddWithOverflow(SDValue A, SDValue B,
2399bdd1243dSDimitry Andric       const SDLoc &dl, bool Signed, SelectionDAG &DAG) const {
2400bdd1243dSDimitry Andric   // Compute A+B, return {A+B, O}, where O = vector predicate indicating
2401bdd1243dSDimitry Andric   // whether an overflow has occured.
2402bdd1243dSDimitry Andric   MVT ResTy = ty(A);
2403bdd1243dSDimitry Andric   assert(ResTy == ty(B));
2404bdd1243dSDimitry Andric   MVT PredTy = MVT::getVectorVT(MVT::i1, ResTy.getVectorNumElements());
2405bdd1243dSDimitry Andric 
2406bdd1243dSDimitry Andric   if (!Signed) {
2407bdd1243dSDimitry Andric     // V62+ has V6_vaddcarry, but it requires input predicate, so it doesn't
2408bdd1243dSDimitry Andric     // save any instructions.
2409bdd1243dSDimitry Andric     SDValue Add = DAG.getNode(ISD::ADD, dl, ResTy, {A, B});
2410bdd1243dSDimitry Andric     SDValue Ovf = DAG.getSetCC(dl, PredTy, Add, A, ISD::SETULT);
2411bdd1243dSDimitry Andric     return {Add, Ovf};
2412bdd1243dSDimitry Andric   }
2413bdd1243dSDimitry Andric 
2414bdd1243dSDimitry Andric   // Signed overflow has happened, if:
2415bdd1243dSDimitry Andric   // (A, B have the same sign) and (A+B has a different sign from either)
2416bdd1243dSDimitry Andric   // i.e. (~A xor B) & ((A+B) xor B), then check the sign bit
2417bdd1243dSDimitry Andric   SDValue Add = DAG.getNode(ISD::ADD, dl, ResTy, {A, B});
2418bdd1243dSDimitry Andric   SDValue NotA =
2419bdd1243dSDimitry Andric       DAG.getNode(ISD::XOR, dl, ResTy, {A, DAG.getConstant(-1, dl, ResTy)});
2420bdd1243dSDimitry Andric   SDValue Xor0 = DAG.getNode(ISD::XOR, dl, ResTy, {NotA, B});
2421bdd1243dSDimitry Andric   SDValue Xor1 = DAG.getNode(ISD::XOR, dl, ResTy, {Add, B});
2422bdd1243dSDimitry Andric   SDValue And = DAG.getNode(ISD::AND, dl, ResTy, {Xor0, Xor1});
2423bdd1243dSDimitry Andric   SDValue MSB =
2424bdd1243dSDimitry Andric       DAG.getSetCC(dl, PredTy, And, getZero(dl, ResTy, DAG), ISD::SETLT);
2425bdd1243dSDimitry Andric   return {Add, MSB};
2426bdd1243dSDimitry Andric }
2427bdd1243dSDimitry Andric 
2428bdd1243dSDimitry Andric HexagonTargetLowering::VectorPair
2429bdd1243dSDimitry Andric HexagonTargetLowering::emitHvxShiftRightRnd(SDValue Val, unsigned Amt,
2430bdd1243dSDimitry Andric       bool Signed, SelectionDAG &DAG) const {
2431bdd1243dSDimitry Andric   // Shift Val right by Amt bits, round the result to the nearest integer,
2432bdd1243dSDimitry Andric   // tie-break by rounding halves to even integer.
2433bdd1243dSDimitry Andric 
2434bdd1243dSDimitry Andric   const SDLoc &dl(Val);
2435bdd1243dSDimitry Andric   MVT ValTy = ty(Val);
2436bdd1243dSDimitry Andric 
2437bdd1243dSDimitry Andric   // This should also work for signed integers.
2438bdd1243dSDimitry Andric   //
2439bdd1243dSDimitry Andric   //   uint tmp0 = inp + ((1 << (Amt-1)) - 1);
2440bdd1243dSDimitry Andric   //   bool ovf = (inp > tmp0);
2441bdd1243dSDimitry Andric   //   uint rup = inp & (1 << (Amt+1));
2442bdd1243dSDimitry Andric   //
2443bdd1243dSDimitry Andric   //   uint tmp1 = inp >> (Amt-1);    // tmp1 == tmp2 iff
2444bdd1243dSDimitry Andric   //   uint tmp2 = tmp0 >> (Amt-1);   // the Amt-1 lower bits were all 0
2445bdd1243dSDimitry Andric   //   uint tmp3 = tmp2 + rup;
2446bdd1243dSDimitry Andric   //   uint frac = (tmp1 != tmp2) ? tmp2 >> 1 : tmp3 >> 1;
2447bdd1243dSDimitry Andric   unsigned ElemWidth = ValTy.getVectorElementType().getSizeInBits();
2448bdd1243dSDimitry Andric   MVT ElemTy = MVT::getIntegerVT(ElemWidth);
2449bdd1243dSDimitry Andric   MVT IntTy = tyVector(ValTy, ElemTy);
2450bdd1243dSDimitry Andric   MVT PredTy = MVT::getVectorVT(MVT::i1, IntTy.getVectorNumElements());
2451bdd1243dSDimitry Andric   unsigned ShRight = Signed ? ISD::SRA : ISD::SRL;
2452bdd1243dSDimitry Andric 
2453bdd1243dSDimitry Andric   SDValue Inp = DAG.getBitcast(IntTy, Val);
2454bdd1243dSDimitry Andric   SDValue LowBits = DAG.getConstant((1ull << (Amt - 1)) - 1, dl, IntTy);
2455bdd1243dSDimitry Andric 
2456bdd1243dSDimitry Andric   SDValue AmtP1 = DAG.getConstant(1ull << Amt, dl, IntTy);
2457bdd1243dSDimitry Andric   SDValue And = DAG.getNode(ISD::AND, dl, IntTy, {Inp, AmtP1});
2458bdd1243dSDimitry Andric   SDValue Zero = getZero(dl, IntTy, DAG);
2459bdd1243dSDimitry Andric   SDValue Bit = DAG.getSetCC(dl, PredTy, And, Zero, ISD::SETNE);
2460bdd1243dSDimitry Andric   SDValue Rup = DAG.getZExtOrTrunc(Bit, dl, IntTy);
2461bdd1243dSDimitry Andric   auto [Tmp0, Ovf] = emitHvxAddWithOverflow(Inp, LowBits, dl, Signed, DAG);
2462bdd1243dSDimitry Andric 
2463bdd1243dSDimitry Andric   SDValue AmtM1 = DAG.getConstant(Amt - 1, dl, IntTy);
2464bdd1243dSDimitry Andric   SDValue Tmp1 = DAG.getNode(ShRight, dl, IntTy, Inp, AmtM1);
2465bdd1243dSDimitry Andric   SDValue Tmp2 = DAG.getNode(ShRight, dl, IntTy, Tmp0, AmtM1);
2466bdd1243dSDimitry Andric   SDValue Tmp3 = DAG.getNode(ISD::ADD, dl, IntTy, Tmp2, Rup);
2467bdd1243dSDimitry Andric 
2468bdd1243dSDimitry Andric   SDValue Eq = DAG.getSetCC(dl, PredTy, Tmp1, Tmp2, ISD::SETEQ);
2469bdd1243dSDimitry Andric   SDValue One = DAG.getConstant(1, dl, IntTy);
2470bdd1243dSDimitry Andric   SDValue Tmp4 = DAG.getNode(ShRight, dl, IntTy, {Tmp2, One});
2471bdd1243dSDimitry Andric   SDValue Tmp5 = DAG.getNode(ShRight, dl, IntTy, {Tmp3, One});
2472bdd1243dSDimitry Andric   SDValue Mux = DAG.getNode(ISD::VSELECT, dl, IntTy, {Eq, Tmp5, Tmp4});
2473bdd1243dSDimitry Andric   return {Mux, Ovf};
247404eeddc0SDimitry Andric }
247504eeddc0SDimitry Andric 
2476e8d8bef9SDimitry Andric SDValue
2477bdd1243dSDimitry Andric HexagonTargetLowering::emitHvxMulHsV60(SDValue A, SDValue B, const SDLoc &dl,
2478bdd1243dSDimitry Andric                                        SelectionDAG &DAG) const {
2479bdd1243dSDimitry Andric   MVT VecTy = ty(A);
2480bdd1243dSDimitry Andric   MVT PairTy = typeJoin({VecTy, VecTy});
2481bdd1243dSDimitry Andric   assert(VecTy.getVectorElementType() == MVT::i32);
2482bdd1243dSDimitry Andric 
2483bdd1243dSDimitry Andric   SDValue S16 = DAG.getConstant(16, dl, MVT::i32);
2484bdd1243dSDimitry Andric 
2485bdd1243dSDimitry Andric   // mulhs(A,B) =
2486bdd1243dSDimitry Andric   //   = [(Hi(A)*2^16 + Lo(A)) *s (Hi(B)*2^16 + Lo(B))] >> 32
2487bdd1243dSDimitry Andric   //   = [Hi(A)*2^16 *s Hi(B)*2^16 + Hi(A) *su Lo(B)*2^16
2488bdd1243dSDimitry Andric   //      + Lo(A) *us (Hi(B)*2^16 + Lo(B))] >> 32
2489bdd1243dSDimitry Andric   //   = [Hi(A) *s Hi(B)*2^32 + Hi(A) *su Lo(B)*2^16 + Lo(A) *us B] >> 32
2490bdd1243dSDimitry Andric   // The low half of Lo(A)*Lo(B) will be discarded (it's not added to
2491bdd1243dSDimitry Andric   // anything, so it cannot produce any carry over to higher bits),
2492bdd1243dSDimitry Andric   // so everything in [] can be shifted by 16 without loss of precision.
2493bdd1243dSDimitry Andric   //   = [Hi(A) *s Hi(B)*2^16 + Hi(A)*su Lo(B) + Lo(A)*B >> 16] >> 16
2494bdd1243dSDimitry Andric   //   = [Hi(A) *s Hi(B)*2^16 + Hi(A)*su Lo(B) + V6_vmpyewuh(A,B)] >> 16
2495bdd1243dSDimitry Andric   // The final additions need to make sure to properly maintain any carry-
2496bdd1243dSDimitry Andric   // out bits.
2497bdd1243dSDimitry Andric   //
2498bdd1243dSDimitry Andric   //                Hi(B) Lo(B)
2499bdd1243dSDimitry Andric   //                Hi(A) Lo(A)
2500bdd1243dSDimitry Andric   //               --------------
2501bdd1243dSDimitry Andric   //                Lo(B)*Lo(A)  | T0 = V6_vmpyewuh(B,A) does this,
2502bdd1243dSDimitry Andric   //         Hi(B)*Lo(A)         |      + dropping the low 16 bits
2503bdd1243dSDimitry Andric   //         Hi(A)*Lo(B)   | T2
2504bdd1243dSDimitry Andric   //  Hi(B)*Hi(A)
2505bdd1243dSDimitry Andric 
2506bdd1243dSDimitry Andric   SDValue T0 = getInstr(Hexagon::V6_vmpyewuh, dl, VecTy, {B, A}, DAG);
2507bdd1243dSDimitry Andric   // T1 = get Hi(A) into low halves.
2508bdd1243dSDimitry Andric   SDValue T1 = getInstr(Hexagon::V6_vasrw, dl, VecTy, {A, S16}, DAG);
2509bdd1243dSDimitry Andric   // P0 = interleaved T1.h*B.uh (full precision product)
2510bdd1243dSDimitry Andric   SDValue P0 = getInstr(Hexagon::V6_vmpyhus, dl, PairTy, {T1, B}, DAG);
2511bdd1243dSDimitry Andric   // T2 = T1.even(h) * B.even(uh), i.e. Hi(A)*Lo(B)
2512bdd1243dSDimitry Andric   SDValue T2 = LoHalf(P0, DAG);
2513bdd1243dSDimitry Andric   // We need to add T0+T2, recording the carry-out, which will be 1<<16
2514bdd1243dSDimitry Andric   // added to the final sum.
2515bdd1243dSDimitry Andric   // P1 = interleaved even/odd 32-bit (unsigned) sums of 16-bit halves
2516bdd1243dSDimitry Andric   SDValue P1 = getInstr(Hexagon::V6_vadduhw, dl, PairTy, {T0, T2}, DAG);
2517bdd1243dSDimitry Andric   // P2 = interleaved even/odd 32-bit (signed) sums of 16-bit halves
2518bdd1243dSDimitry Andric   SDValue P2 = getInstr(Hexagon::V6_vaddhw, dl, PairTy, {T0, T2}, DAG);
2519bdd1243dSDimitry Andric   // T3 = full-precision(T0+T2) >> 16
2520bdd1243dSDimitry Andric   // The low halves are added-unsigned, the high ones are added-signed.
2521bdd1243dSDimitry Andric   SDValue T3 = getInstr(Hexagon::V6_vasrw_acc, dl, VecTy,
2522bdd1243dSDimitry Andric                         {HiHalf(P2, DAG), LoHalf(P1, DAG), S16}, DAG);
2523bdd1243dSDimitry Andric   SDValue T4 = getInstr(Hexagon::V6_vasrw, dl, VecTy, {B, S16}, DAG);
2524bdd1243dSDimitry Andric   // P3 = interleaved Hi(B)*Hi(A) (full precision),
2525bdd1243dSDimitry Andric   // which is now Lo(T1)*Lo(T4), so we want to keep the even product.
2526bdd1243dSDimitry Andric   SDValue P3 = getInstr(Hexagon::V6_vmpyhv, dl, PairTy, {T1, T4}, DAG);
2527bdd1243dSDimitry Andric   SDValue T5 = LoHalf(P3, DAG);
2528bdd1243dSDimitry Andric   // Add:
2529bdd1243dSDimitry Andric   SDValue T6 = DAG.getNode(ISD::ADD, dl, VecTy, {T3, T5});
2530bdd1243dSDimitry Andric   return T6;
2531bdd1243dSDimitry Andric }
2532bdd1243dSDimitry Andric 
2533bdd1243dSDimitry Andric SDValue
2534bdd1243dSDimitry Andric HexagonTargetLowering::emitHvxMulLoHiV60(SDValue A, bool SignedA, SDValue B,
2535bdd1243dSDimitry Andric                                          bool SignedB, const SDLoc &dl,
2536bdd1243dSDimitry Andric                                          SelectionDAG &DAG) const {
2537bdd1243dSDimitry Andric   MVT VecTy = ty(A);
2538bdd1243dSDimitry Andric   MVT PairTy = typeJoin({VecTy, VecTy});
2539bdd1243dSDimitry Andric   assert(VecTy.getVectorElementType() == MVT::i32);
2540bdd1243dSDimitry Andric 
2541bdd1243dSDimitry Andric   SDValue S16 = DAG.getConstant(16, dl, MVT::i32);
2542bdd1243dSDimitry Andric 
2543bdd1243dSDimitry Andric   if (SignedA && !SignedB) {
2544bdd1243dSDimitry Andric     // Make A:unsigned, B:signed.
2545bdd1243dSDimitry Andric     std::swap(A, B);
2546bdd1243dSDimitry Andric     std::swap(SignedA, SignedB);
2547bdd1243dSDimitry Andric   }
2548bdd1243dSDimitry Andric 
2549bdd1243dSDimitry Andric   // Do halfword-wise multiplications for unsigned*unsigned product, then
2550bdd1243dSDimitry Andric   // add corrections for signed and unsigned*signed.
2551bdd1243dSDimitry Andric 
2552bdd1243dSDimitry Andric   SDValue Lo, Hi;
2553bdd1243dSDimitry Andric 
2554bdd1243dSDimitry Andric   // P0:lo = (uu) products of low halves of A and B,
2555bdd1243dSDimitry Andric   // P0:hi = (uu) products of high halves.
2556bdd1243dSDimitry Andric   SDValue P0 = getInstr(Hexagon::V6_vmpyuhv, dl, PairTy, {A, B}, DAG);
2557bdd1243dSDimitry Andric 
2558bdd1243dSDimitry Andric   // Swap low/high halves in B
2559bdd1243dSDimitry Andric   SDValue T0 = getInstr(Hexagon::V6_lvsplatw, dl, VecTy,
2560bdd1243dSDimitry Andric                         {DAG.getConstant(0x02020202, dl, MVT::i32)}, DAG);
2561bdd1243dSDimitry Andric   SDValue T1 = getInstr(Hexagon::V6_vdelta, dl, VecTy, {B, T0}, DAG);
2562bdd1243dSDimitry Andric   // P1 = products of even/odd halfwords.
2563bdd1243dSDimitry Andric   // P1:lo = (uu) products of even(A.uh) * odd(B.uh)
2564bdd1243dSDimitry Andric   // P1:hi = (uu) products of odd(A.uh) * even(B.uh)
2565bdd1243dSDimitry Andric   SDValue P1 = getInstr(Hexagon::V6_vmpyuhv, dl, PairTy, {A, T1}, DAG);
2566bdd1243dSDimitry Andric 
2567bdd1243dSDimitry Andric   // P2:lo = low halves of P1:lo + P1:hi,
2568bdd1243dSDimitry Andric   // P2:hi = high halves of P1:lo + P1:hi.
2569bdd1243dSDimitry Andric   SDValue P2 = getInstr(Hexagon::V6_vadduhw, dl, PairTy,
2570bdd1243dSDimitry Andric                         {HiHalf(P1, DAG), LoHalf(P1, DAG)}, DAG);
2571bdd1243dSDimitry Andric   // Still need to add the high halves of P0:lo to P2:lo
2572bdd1243dSDimitry Andric   SDValue T2 =
2573bdd1243dSDimitry Andric       getInstr(Hexagon::V6_vlsrw, dl, VecTy, {LoHalf(P0, DAG), S16}, DAG);
2574bdd1243dSDimitry Andric   SDValue T3 = DAG.getNode(ISD::ADD, dl, VecTy, {LoHalf(P2, DAG), T2});
2575bdd1243dSDimitry Andric 
2576bdd1243dSDimitry Andric   // The high halves of T3 will contribute to the HI part of LOHI.
2577bdd1243dSDimitry Andric   SDValue T4 = getInstr(Hexagon::V6_vasrw_acc, dl, VecTy,
2578bdd1243dSDimitry Andric                         {HiHalf(P2, DAG), T3, S16}, DAG);
2579bdd1243dSDimitry Andric 
2580bdd1243dSDimitry Andric   // The low halves of P2 need to be added to high halves of the LO part.
2581bdd1243dSDimitry Andric   Lo = getInstr(Hexagon::V6_vaslw_acc, dl, VecTy,
2582bdd1243dSDimitry Andric                 {LoHalf(P0, DAG), LoHalf(P2, DAG), S16}, DAG);
2583bdd1243dSDimitry Andric   Hi = DAG.getNode(ISD::ADD, dl, VecTy, {HiHalf(P0, DAG), T4});
2584bdd1243dSDimitry Andric 
2585bdd1243dSDimitry Andric   if (SignedA) {
2586bdd1243dSDimitry Andric     assert(SignedB && "Signed A and unsigned B should have been inverted");
2587bdd1243dSDimitry Andric 
2588bdd1243dSDimitry Andric     MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
2589bdd1243dSDimitry Andric     SDValue Zero = getZero(dl, VecTy, DAG);
2590bdd1243dSDimitry Andric     SDValue Q0 = DAG.getSetCC(dl, PredTy, A, Zero, ISD::SETLT);
2591bdd1243dSDimitry Andric     SDValue Q1 = DAG.getSetCC(dl, PredTy, B, Zero, ISD::SETLT);
2592bdd1243dSDimitry Andric     SDValue X0 = DAG.getNode(ISD::VSELECT, dl, VecTy, {Q0, B, Zero});
2593bdd1243dSDimitry Andric     SDValue X1 = getInstr(Hexagon::V6_vaddwq, dl, VecTy, {Q1, X0, A}, DAG);
2594bdd1243dSDimitry Andric     Hi = getInstr(Hexagon::V6_vsubw, dl, VecTy, {Hi, X1}, DAG);
2595bdd1243dSDimitry Andric   } else if (SignedB) {
2596bdd1243dSDimitry Andric     // Same correction as for mulhus:
2597bdd1243dSDimitry Andric     // mulhus(A.uw,B.w) = mulhu(A.uw,B.uw) - (A.w if B < 0)
2598bdd1243dSDimitry Andric     MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
2599bdd1243dSDimitry Andric     SDValue Zero = getZero(dl, VecTy, DAG);
2600bdd1243dSDimitry Andric     SDValue Q1 = DAG.getSetCC(dl, PredTy, B, Zero, ISD::SETLT);
2601bdd1243dSDimitry Andric     Hi = getInstr(Hexagon::V6_vsubwq, dl, VecTy, {Q1, Hi, A}, DAG);
2602bdd1243dSDimitry Andric   } else {
2603bdd1243dSDimitry Andric     assert(!SignedA && !SignedB);
2604bdd1243dSDimitry Andric   }
2605bdd1243dSDimitry Andric 
2606bdd1243dSDimitry Andric   return DAG.getMergeValues({Lo, Hi}, dl);
2607bdd1243dSDimitry Andric }
2608bdd1243dSDimitry Andric 
2609bdd1243dSDimitry Andric SDValue
2610bdd1243dSDimitry Andric HexagonTargetLowering::emitHvxMulLoHiV62(SDValue A, bool SignedA,
2611bdd1243dSDimitry Andric                                          SDValue B, bool SignedB,
2612bdd1243dSDimitry Andric                                          const SDLoc &dl,
2613bdd1243dSDimitry Andric                                          SelectionDAG &DAG) const {
2614bdd1243dSDimitry Andric   MVT VecTy = ty(A);
2615bdd1243dSDimitry Andric   MVT PairTy = typeJoin({VecTy, VecTy});
2616bdd1243dSDimitry Andric   assert(VecTy.getVectorElementType() == MVT::i32);
2617bdd1243dSDimitry Andric 
2618bdd1243dSDimitry Andric   if (SignedA && !SignedB) {
2619bdd1243dSDimitry Andric     // Make A:unsigned, B:signed.
2620bdd1243dSDimitry Andric     std::swap(A, B);
2621bdd1243dSDimitry Andric     std::swap(SignedA, SignedB);
2622bdd1243dSDimitry Andric   }
2623bdd1243dSDimitry Andric 
2624bdd1243dSDimitry Andric   // Do S*S first, then make corrections for U*S or U*U if needed.
2625bdd1243dSDimitry Andric   SDValue P0 = getInstr(Hexagon::V6_vmpyewuh_64, dl, PairTy, {A, B}, DAG);
2626bdd1243dSDimitry Andric   SDValue P1 =
2627bdd1243dSDimitry Andric       getInstr(Hexagon::V6_vmpyowh_64_acc, dl, PairTy, {P0, A, B}, DAG);
2628bdd1243dSDimitry Andric   SDValue Lo = LoHalf(P1, DAG);
2629bdd1243dSDimitry Andric   SDValue Hi = HiHalf(P1, DAG);
2630bdd1243dSDimitry Andric 
2631bdd1243dSDimitry Andric   if (!SignedB) {
2632bdd1243dSDimitry Andric     assert(!SignedA && "Signed A and unsigned B should have been inverted");
2633bdd1243dSDimitry Andric     SDValue Zero = getZero(dl, VecTy, DAG);
2634bdd1243dSDimitry Andric     MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
2635bdd1243dSDimitry Andric 
2636bdd1243dSDimitry Andric     // Mulhu(X, Y) = Mulhs(X, Y) + (X, if Y < 0) + (Y, if X < 0).
2637bdd1243dSDimitry Andric     // def: Pat<(VecI32 (mulhu HVI32:$A, HVI32:$B)),
2638bdd1243dSDimitry Andric     //          (V6_vaddw (HiHalf (Muls64O $A, $B)),
2639bdd1243dSDimitry Andric     //                    (V6_vaddwq (V6_vgtw (V6_vd0), $B),
2640bdd1243dSDimitry Andric     //                               (V6_vandvqv (V6_vgtw (V6_vd0), $A), $B),
2641bdd1243dSDimitry Andric     //                               $A))>;
2642bdd1243dSDimitry Andric     SDValue Q0 = DAG.getSetCC(dl, PredTy, A, Zero, ISD::SETLT);
2643bdd1243dSDimitry Andric     SDValue Q1 = DAG.getSetCC(dl, PredTy, B, Zero, ISD::SETLT);
2644bdd1243dSDimitry Andric     SDValue T0 = getInstr(Hexagon::V6_vandvqv, dl, VecTy, {Q0, B}, DAG);
2645bdd1243dSDimitry Andric     SDValue T1 = getInstr(Hexagon::V6_vaddwq, dl, VecTy, {Q1, T0, A}, DAG);
2646bdd1243dSDimitry Andric     Hi = getInstr(Hexagon::V6_vaddw, dl, VecTy, {Hi, T1}, DAG);
2647bdd1243dSDimitry Andric   } else if (!SignedA) {
2648bdd1243dSDimitry Andric     SDValue Zero = getZero(dl, VecTy, DAG);
2649bdd1243dSDimitry Andric     MVT PredTy = MVT::getVectorVT(MVT::i1, VecTy.getVectorNumElements());
2650bdd1243dSDimitry Andric 
2651bdd1243dSDimitry Andric     // Mulhus(unsigned X, signed Y) = Mulhs(X, Y) + (Y, if X < 0).
2652bdd1243dSDimitry Andric     // def: Pat<(VecI32 (HexagonMULHUS HVI32:$A, HVI32:$B)),
2653bdd1243dSDimitry Andric     //          (V6_vaddwq (V6_vgtw (V6_vd0), $A),
2654bdd1243dSDimitry Andric     //                     (HiHalf (Muls64O $A, $B)),
2655bdd1243dSDimitry Andric     //                     $B)>;
2656bdd1243dSDimitry Andric     SDValue Q0 = DAG.getSetCC(dl, PredTy, A, Zero, ISD::SETLT);
2657bdd1243dSDimitry Andric     Hi = getInstr(Hexagon::V6_vaddwq, dl, VecTy, {Q0, Hi, B}, DAG);
2658bdd1243dSDimitry Andric   }
2659bdd1243dSDimitry Andric 
2660bdd1243dSDimitry Andric   return DAG.getMergeValues({Lo, Hi}, dl);
2661bdd1243dSDimitry Andric }
2662bdd1243dSDimitry Andric 
2663bdd1243dSDimitry Andric SDValue
2664bdd1243dSDimitry Andric HexagonTargetLowering::EqualizeFpIntConversion(SDValue Op, SelectionDAG &DAG)
2665bdd1243dSDimitry Andric       const {
2666bdd1243dSDimitry Andric   // Rewrite conversion between integer and floating-point in such a way that
2667bdd1243dSDimitry Andric   // the integer type is extended/narrowed to match the bitwidth of the
2668bdd1243dSDimitry Andric   // floating-point type, combined with additional integer-integer extensions
2669bdd1243dSDimitry Andric   // or narrowings to match the original input/result types.
2670bdd1243dSDimitry Andric   // E.g.  f32 -> i8  ==>  f32 -> i32 -> i8
2671bdd1243dSDimitry Andric   //
2672bdd1243dSDimitry Andric   // The input/result types are not required to be legal, but if they are
2673bdd1243dSDimitry Andric   // legal, this function should not introduce illegal types.
2674bdd1243dSDimitry Andric 
2675bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
2676bdd1243dSDimitry Andric   assert(Opc == ISD::FP_TO_SINT || Opc == ISD::FP_TO_UINT ||
2677bdd1243dSDimitry Andric          Opc == ISD::SINT_TO_FP || Opc == ISD::UINT_TO_FP);
2678bdd1243dSDimitry Andric 
2679bdd1243dSDimitry Andric   SDValue Inp = Op.getOperand(0);
2680bdd1243dSDimitry Andric   MVT InpTy = ty(Inp);
2681bdd1243dSDimitry Andric   MVT ResTy = ty(Op);
2682bdd1243dSDimitry Andric 
2683bdd1243dSDimitry Andric   if (InpTy == ResTy)
2684bdd1243dSDimitry Andric     return Op;
2685bdd1243dSDimitry Andric 
2686bdd1243dSDimitry Andric   const SDLoc &dl(Op);
2687bdd1243dSDimitry Andric   bool Signed = Opc == ISD::FP_TO_SINT || Opc == ISD::SINT_TO_FP;
2688bdd1243dSDimitry Andric 
2689bdd1243dSDimitry Andric   auto [WInpTy, WResTy] = typeExtendToWider(InpTy, ResTy);
2690bdd1243dSDimitry Andric   SDValue WInp = resizeToWidth(Inp, WInpTy, Signed, dl, DAG);
2691bdd1243dSDimitry Andric   SDValue Conv = DAG.getNode(Opc, dl, WResTy, WInp);
2692bdd1243dSDimitry Andric   SDValue Res = resizeToWidth(Conv, ResTy, Signed, dl, DAG);
2693bdd1243dSDimitry Andric   return Res;
2694bdd1243dSDimitry Andric }
2695bdd1243dSDimitry Andric 
2696bdd1243dSDimitry Andric SDValue
2697bdd1243dSDimitry Andric HexagonTargetLowering::ExpandHvxFpToInt(SDValue Op, SelectionDAG &DAG) const {
2698bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
2699bdd1243dSDimitry Andric   assert(Opc == ISD::FP_TO_SINT || Opc == ISD::FP_TO_UINT);
2700bdd1243dSDimitry Andric 
2701bdd1243dSDimitry Andric   const SDLoc &dl(Op);
2702bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
2703bdd1243dSDimitry Andric   MVT InpTy = ty(Op0);
2704bdd1243dSDimitry Andric   MVT ResTy = ty(Op);
2705bdd1243dSDimitry Andric   assert(InpTy.changeTypeToInteger() == ResTy);
2706bdd1243dSDimitry Andric 
2707bdd1243dSDimitry Andric   // int32_t conv_f32_to_i32(uint32_t inp) {
2708bdd1243dSDimitry Andric   //   // s | exp8 | frac23
2709bdd1243dSDimitry Andric   //
2710bdd1243dSDimitry Andric   //   int neg = (int32_t)inp < 0;
2711bdd1243dSDimitry Andric   //
2712bdd1243dSDimitry Andric   //   // "expm1" is the actual exponent minus 1: instead of "bias", subtract
2713bdd1243dSDimitry Andric   //   // "bias+1". When the encoded exp is "all-1" (i.e. inf/nan), this will
2714bdd1243dSDimitry Andric   //   // produce a large positive "expm1", which will result in max u/int.
2715bdd1243dSDimitry Andric   //   // In all IEEE formats, bias is the largest positive number that can be
2716bdd1243dSDimitry Andric   //   // represented in bias-width bits (i.e. 011..1).
2717bdd1243dSDimitry Andric   //   int32_t expm1 = (inp << 1) - 0x80000000;
2718bdd1243dSDimitry Andric   //   expm1 >>= 24;
2719bdd1243dSDimitry Andric   //
2720bdd1243dSDimitry Andric   //   // Always insert the "implicit 1". Subnormal numbers will become 0
2721bdd1243dSDimitry Andric   //   // regardless.
2722bdd1243dSDimitry Andric   //   uint32_t frac = (inp << 8) | 0x80000000;
2723bdd1243dSDimitry Andric   //
2724bdd1243dSDimitry Andric   //   // "frac" is the fraction part represented as Q1.31. If it was
2725bdd1243dSDimitry Andric   //   // interpreted as uint32_t, it would be the fraction part multiplied
2726bdd1243dSDimitry Andric   //   // by 2^31.
2727bdd1243dSDimitry Andric   //
2728bdd1243dSDimitry Andric   //   // Calculate the amount of right shift, since shifting further to the
2729bdd1243dSDimitry Andric   //   // left would lose significant bits. Limit it to 32, because we want
2730bdd1243dSDimitry Andric   //   // shifts by 32+ to produce 0, whereas V6_vlsrwv treats the shift
2731bdd1243dSDimitry Andric   //   // amount as a 6-bit signed value (so 33 is same as -31, i.e. shift
2732bdd1243dSDimitry Andric   //   // left by 31). "rsh" can be negative.
2733bdd1243dSDimitry Andric   //   int32_t rsh = min(31 - (expm1 + 1), 32);
2734bdd1243dSDimitry Andric   //
2735bdd1243dSDimitry Andric   //   frac >>= rsh;   // rsh == 32 will produce 0
2736bdd1243dSDimitry Andric   //
2737bdd1243dSDimitry Andric   //   // Everything up to this point is the same for conversion to signed
2738bdd1243dSDimitry Andric   //   // unsigned integer.
2739bdd1243dSDimitry Andric   //
2740bdd1243dSDimitry Andric   //   if (neg)                 // Only for signed int
2741bdd1243dSDimitry Andric   //     frac = -frac;          //
2742bdd1243dSDimitry Andric   //   if (rsh <= 0 && neg)     //   bound = neg ? 0x80000000 : 0x7fffffff
2743bdd1243dSDimitry Andric   //     frac = 0x80000000;     //   frac = rsh <= 0 ? bound : frac
2744bdd1243dSDimitry Andric   //   if (rsh <= 0 && !neg)    //
2745bdd1243dSDimitry Andric   //     frac = 0x7fffffff;     //
2746bdd1243dSDimitry Andric   //
2747bdd1243dSDimitry Andric   //   if (neg)                 // Only for unsigned int
2748bdd1243dSDimitry Andric   //     frac = 0;              //
2749bdd1243dSDimitry Andric   //   if (rsh < 0 && !neg)     //   frac = rsh < 0 ? 0x7fffffff : frac;
2750bdd1243dSDimitry Andric   //     frac = 0x7fffffff;     //   frac = neg ? 0 : frac;
2751bdd1243dSDimitry Andric   //
2752bdd1243dSDimitry Andric   //   return frac;
2753bdd1243dSDimitry Andric   // }
2754bdd1243dSDimitry Andric 
2755bdd1243dSDimitry Andric   MVT PredTy = MVT::getVectorVT(MVT::i1, ResTy.getVectorElementCount());
2756bdd1243dSDimitry Andric 
2757bdd1243dSDimitry Andric   // Zero = V6_vd0();
2758bdd1243dSDimitry Andric   // Neg = V6_vgtw(Zero, Inp);
2759bdd1243dSDimitry Andric   // One = V6_lvsplatw(1);
2760bdd1243dSDimitry Andric   // M80 = V6_lvsplatw(0x80000000);
2761bdd1243dSDimitry Andric   // Exp00 = V6_vaslwv(Inp, One);
2762bdd1243dSDimitry Andric   // Exp01 = V6_vsubw(Exp00, M80);
2763bdd1243dSDimitry Andric   // ExpM1 = V6_vasrw(Exp01, 24);
2764bdd1243dSDimitry Andric   // Frc00 = V6_vaslw(Inp, 8);
2765bdd1243dSDimitry Andric   // Frc01 = V6_vor(Frc00, M80);
2766bdd1243dSDimitry Andric   // Rsh00 = V6_vsubw(V6_lvsplatw(30), ExpM1);
2767bdd1243dSDimitry Andric   // Rsh01 = V6_vminw(Rsh00, V6_lvsplatw(32));
2768bdd1243dSDimitry Andric   // Frc02 = V6_vlsrwv(Frc01, Rsh01);
2769bdd1243dSDimitry Andric 
2770bdd1243dSDimitry Andric   // if signed int:
2771bdd1243dSDimitry Andric   // Bnd = V6_vmux(Neg, M80, V6_lvsplatw(0x7fffffff))
2772bdd1243dSDimitry Andric   // Pos = V6_vgtw(Rsh01, Zero);
2773bdd1243dSDimitry Andric   // Frc13 = V6_vsubw(Zero, Frc02);
2774bdd1243dSDimitry Andric   // Frc14 = V6_vmux(Neg, Frc13, Frc02);
2775bdd1243dSDimitry Andric   // Int = V6_vmux(Pos, Frc14, Bnd);
2776bdd1243dSDimitry Andric   //
2777bdd1243dSDimitry Andric   // if unsigned int:
2778bdd1243dSDimitry Andric   // Rsn = V6_vgtw(Zero, Rsh01)
2779bdd1243dSDimitry Andric   // Frc23 = V6_vmux(Rsn, V6_lvsplatw(0x7fffffff), Frc02)
2780bdd1243dSDimitry Andric   // Int = V6_vmux(Neg, Zero, Frc23)
2781bdd1243dSDimitry Andric 
2782bdd1243dSDimitry Andric   auto [ExpWidth, ExpBias, FracWidth] = getIEEEProperties(InpTy);
2783bdd1243dSDimitry Andric   unsigned ElemWidth = 1 + ExpWidth + FracWidth;
2784bdd1243dSDimitry Andric   assert((1ull << (ExpWidth - 1)) == (1 + ExpBias));
2785bdd1243dSDimitry Andric 
2786bdd1243dSDimitry Andric   SDValue Inp = DAG.getBitcast(ResTy, Op0);
2787bdd1243dSDimitry Andric   SDValue Zero = getZero(dl, ResTy, DAG);
2788bdd1243dSDimitry Andric   SDValue Neg = DAG.getSetCC(dl, PredTy, Inp, Zero, ISD::SETLT);
2789bdd1243dSDimitry Andric   SDValue M80 = DAG.getConstant(1ull << (ElemWidth - 1), dl, ResTy);
2790bdd1243dSDimitry Andric   SDValue M7F = DAG.getConstant((1ull << (ElemWidth - 1)) - 1, dl, ResTy);
2791bdd1243dSDimitry Andric   SDValue One = DAG.getConstant(1, dl, ResTy);
2792bdd1243dSDimitry Andric   SDValue Exp00 = DAG.getNode(ISD::SHL, dl, ResTy, {Inp, One});
2793bdd1243dSDimitry Andric   SDValue Exp01 = DAG.getNode(ISD::SUB, dl, ResTy, {Exp00, M80});
2794bdd1243dSDimitry Andric   SDValue MNE = DAG.getConstant(ElemWidth - ExpWidth, dl, ResTy);
2795bdd1243dSDimitry Andric   SDValue ExpM1 = DAG.getNode(ISD::SRA, dl, ResTy, {Exp01, MNE});
2796bdd1243dSDimitry Andric 
2797bdd1243dSDimitry Andric   SDValue ExpW = DAG.getConstant(ExpWidth, dl, ResTy);
2798bdd1243dSDimitry Andric   SDValue Frc00 = DAG.getNode(ISD::SHL, dl, ResTy, {Inp, ExpW});
2799bdd1243dSDimitry Andric   SDValue Frc01 = DAG.getNode(ISD::OR, dl, ResTy, {Frc00, M80});
2800bdd1243dSDimitry Andric 
2801bdd1243dSDimitry Andric   SDValue MN2 = DAG.getConstant(ElemWidth - 2, dl, ResTy);
2802bdd1243dSDimitry Andric   SDValue Rsh00 = DAG.getNode(ISD::SUB, dl, ResTy, {MN2, ExpM1});
2803bdd1243dSDimitry Andric   SDValue MW = DAG.getConstant(ElemWidth, dl, ResTy);
2804bdd1243dSDimitry Andric   SDValue Rsh01 = DAG.getNode(ISD::SMIN, dl, ResTy, {Rsh00, MW});
2805bdd1243dSDimitry Andric   SDValue Frc02 = DAG.getNode(ISD::SRL, dl, ResTy, {Frc01, Rsh01});
2806bdd1243dSDimitry Andric 
2807bdd1243dSDimitry Andric   SDValue Int;
2808bdd1243dSDimitry Andric 
2809bdd1243dSDimitry Andric   if (Opc == ISD::FP_TO_SINT) {
2810bdd1243dSDimitry Andric     SDValue Bnd = DAG.getNode(ISD::VSELECT, dl, ResTy, {Neg, M80, M7F});
2811bdd1243dSDimitry Andric     SDValue Pos = DAG.getSetCC(dl, PredTy, Rsh01, Zero, ISD::SETGT);
2812bdd1243dSDimitry Andric     SDValue Frc13 = DAG.getNode(ISD::SUB, dl, ResTy, {Zero, Frc02});
2813bdd1243dSDimitry Andric     SDValue Frc14 = DAG.getNode(ISD::VSELECT, dl, ResTy, {Neg, Frc13, Frc02});
2814bdd1243dSDimitry Andric     Int = DAG.getNode(ISD::VSELECT, dl, ResTy, {Pos, Frc14, Bnd});
2815bdd1243dSDimitry Andric   } else {
2816bdd1243dSDimitry Andric     assert(Opc == ISD::FP_TO_UINT);
2817bdd1243dSDimitry Andric     SDValue Rsn = DAG.getSetCC(dl, PredTy, Rsh01, Zero, ISD::SETLT);
2818bdd1243dSDimitry Andric     SDValue Frc23 = DAG.getNode(ISD::VSELECT, dl, ResTy, Rsn, M7F, Frc02);
2819bdd1243dSDimitry Andric     Int = DAG.getNode(ISD::VSELECT, dl, ResTy, Neg, Zero, Frc23);
2820bdd1243dSDimitry Andric   }
2821bdd1243dSDimitry Andric 
2822bdd1243dSDimitry Andric   return Int;
2823bdd1243dSDimitry Andric }
2824bdd1243dSDimitry Andric 
2825bdd1243dSDimitry Andric SDValue
2826bdd1243dSDimitry Andric HexagonTargetLowering::ExpandHvxIntToFp(SDValue Op, SelectionDAG &DAG) const {
2827bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
2828bdd1243dSDimitry Andric   assert(Opc == ISD::SINT_TO_FP || Opc == ISD::UINT_TO_FP);
2829bdd1243dSDimitry Andric 
2830bdd1243dSDimitry Andric   const SDLoc &dl(Op);
2831bdd1243dSDimitry Andric   SDValue Op0 = Op.getOperand(0);
2832bdd1243dSDimitry Andric   MVT InpTy = ty(Op0);
2833bdd1243dSDimitry Andric   MVT ResTy = ty(Op);
2834bdd1243dSDimitry Andric   assert(ResTy.changeTypeToInteger() == InpTy);
2835bdd1243dSDimitry Andric 
2836bdd1243dSDimitry Andric   // uint32_t vnoc1_rnd(int32_t w) {
2837bdd1243dSDimitry Andric   //   int32_t iszero = w == 0;
2838bdd1243dSDimitry Andric   //   int32_t isneg = w < 0;
2839bdd1243dSDimitry Andric   //   uint32_t u = __builtin_HEXAGON_A2_abs(w);
2840bdd1243dSDimitry Andric   //
2841bdd1243dSDimitry Andric   //   uint32_t norm_left = __builtin_HEXAGON_S2_cl0(u) + 1;
2842bdd1243dSDimitry Andric   //   uint32_t frac0 = (uint64_t)u << norm_left;
2843bdd1243dSDimitry Andric   //
2844bdd1243dSDimitry Andric   //   // Rounding:
2845bdd1243dSDimitry Andric   //   uint32_t frac1 = frac0 + ((1 << 8) - 1);
2846bdd1243dSDimitry Andric   //   uint32_t renorm = (frac0 > frac1);
2847bdd1243dSDimitry Andric   //   uint32_t rup = (int)(frac0 << 22) < 0;
2848bdd1243dSDimitry Andric   //
2849bdd1243dSDimitry Andric   //   uint32_t frac2 = frac0 >> 8;
2850bdd1243dSDimitry Andric   //   uint32_t frac3 = frac1 >> 8;
2851bdd1243dSDimitry Andric   //   uint32_t frac = (frac2 != frac3) ? frac3 >> 1 : (frac3 + rup) >> 1;
2852bdd1243dSDimitry Andric   //
2853bdd1243dSDimitry Andric   //   int32_t exp = 32 - norm_left + renorm + 127;
2854bdd1243dSDimitry Andric   //   exp <<= 23;
2855bdd1243dSDimitry Andric   //
2856bdd1243dSDimitry Andric   //   uint32_t sign = 0x80000000 * isneg;
2857bdd1243dSDimitry Andric   //   uint32_t f = sign | exp | frac;
2858bdd1243dSDimitry Andric   //   return iszero ? 0 : f;
2859bdd1243dSDimitry Andric   // }
2860bdd1243dSDimitry Andric 
2861bdd1243dSDimitry Andric   MVT PredTy = MVT::getVectorVT(MVT::i1, InpTy.getVectorElementCount());
2862bdd1243dSDimitry Andric   bool Signed = Opc == ISD::SINT_TO_FP;
2863bdd1243dSDimitry Andric 
2864bdd1243dSDimitry Andric   auto [ExpWidth, ExpBias, FracWidth] = getIEEEProperties(ResTy);
2865bdd1243dSDimitry Andric   unsigned ElemWidth = 1 + ExpWidth + FracWidth;
2866bdd1243dSDimitry Andric 
2867bdd1243dSDimitry Andric   SDValue Zero = getZero(dl, InpTy, DAG);
2868bdd1243dSDimitry Andric   SDValue One = DAG.getConstant(1, dl, InpTy);
2869bdd1243dSDimitry Andric   SDValue IsZero = DAG.getSetCC(dl, PredTy, Op0, Zero, ISD::SETEQ);
2870bdd1243dSDimitry Andric   SDValue Abs = Signed ? DAG.getNode(ISD::ABS, dl, InpTy, Op0) : Op0;
2871bdd1243dSDimitry Andric   SDValue Clz = DAG.getNode(ISD::CTLZ, dl, InpTy, Abs);
2872bdd1243dSDimitry Andric   SDValue NLeft = DAG.getNode(ISD::ADD, dl, InpTy, {Clz, One});
2873bdd1243dSDimitry Andric   SDValue Frac0 = DAG.getNode(ISD::SHL, dl, InpTy, {Abs, NLeft});
2874bdd1243dSDimitry Andric 
2875bdd1243dSDimitry Andric   auto [Frac, Ovf] = emitHvxShiftRightRnd(Frac0, ExpWidth + 1, false, DAG);
2876bdd1243dSDimitry Andric   if (Signed) {
2877bdd1243dSDimitry Andric     SDValue IsNeg = DAG.getSetCC(dl, PredTy, Op0, Zero, ISD::SETLT);
2878bdd1243dSDimitry Andric     SDValue M80 = DAG.getConstant(1ull << (ElemWidth - 1), dl, InpTy);
2879bdd1243dSDimitry Andric     SDValue Sign = DAG.getNode(ISD::VSELECT, dl, InpTy, {IsNeg, M80, Zero});
2880bdd1243dSDimitry Andric     Frac = DAG.getNode(ISD::OR, dl, InpTy, {Sign, Frac});
2881bdd1243dSDimitry Andric   }
2882bdd1243dSDimitry Andric 
2883bdd1243dSDimitry Andric   SDValue Rnrm = DAG.getZExtOrTrunc(Ovf, dl, InpTy);
2884bdd1243dSDimitry Andric   SDValue Exp0 = DAG.getConstant(ElemWidth + ExpBias, dl, InpTy);
2885bdd1243dSDimitry Andric   SDValue Exp1 = DAG.getNode(ISD::ADD, dl, InpTy, {Rnrm, Exp0});
2886bdd1243dSDimitry Andric   SDValue Exp2 = DAG.getNode(ISD::SUB, dl, InpTy, {Exp1, NLeft});
2887bdd1243dSDimitry Andric   SDValue Exp3 = DAG.getNode(ISD::SHL, dl, InpTy,
2888bdd1243dSDimitry Andric                              {Exp2, DAG.getConstant(FracWidth, dl, InpTy)});
2889bdd1243dSDimitry Andric   SDValue Flt0 = DAG.getNode(ISD::OR, dl, InpTy, {Frac, Exp3});
2890bdd1243dSDimitry Andric   SDValue Flt1 = DAG.getNode(ISD::VSELECT, dl, InpTy, {IsZero, Zero, Flt0});
2891bdd1243dSDimitry Andric   SDValue Flt = DAG.getBitcast(ResTy, Flt1);
2892bdd1243dSDimitry Andric 
2893bdd1243dSDimitry Andric   return Flt;
2894bdd1243dSDimitry Andric }
2895bdd1243dSDimitry Andric 
2896bdd1243dSDimitry Andric SDValue
2897bdd1243dSDimitry Andric HexagonTargetLowering::CreateTLWrapper(SDValue Op, SelectionDAG &DAG) const {
2898bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
2899bdd1243dSDimitry Andric   unsigned TLOpc;
2900bdd1243dSDimitry Andric   switch (Opc) {
2901bdd1243dSDimitry Andric   case ISD::ANY_EXTEND:
2902bdd1243dSDimitry Andric   case ISD::SIGN_EXTEND:
2903bdd1243dSDimitry Andric   case ISD::ZERO_EXTEND:
2904bdd1243dSDimitry Andric     TLOpc = HexagonISD::TL_EXTEND;
2905bdd1243dSDimitry Andric     break;
2906bdd1243dSDimitry Andric   case ISD::TRUNCATE:
2907bdd1243dSDimitry Andric     TLOpc = HexagonISD::TL_TRUNCATE;
2908bdd1243dSDimitry Andric     break;
2909bdd1243dSDimitry Andric #ifndef NDEBUG
2910bdd1243dSDimitry Andric     Op.dump(&DAG);
2911bdd1243dSDimitry Andric #endif
2912bdd1243dSDimitry Andric     llvm_unreachable("Unepected operator");
2913bdd1243dSDimitry Andric   }
2914bdd1243dSDimitry Andric 
2915bdd1243dSDimitry Andric   const SDLoc &dl(Op);
2916bdd1243dSDimitry Andric   return DAG.getNode(TLOpc, dl, ty(Op), Op.getOperand(0),
2917bdd1243dSDimitry Andric                      DAG.getUNDEF(MVT::i128), // illegal type
2918bdd1243dSDimitry Andric                      DAG.getConstant(Opc, dl, MVT::i32));
2919bdd1243dSDimitry Andric }
2920bdd1243dSDimitry Andric 
2921bdd1243dSDimitry Andric SDValue
2922bdd1243dSDimitry Andric HexagonTargetLowering::RemoveTLWrapper(SDValue Op, SelectionDAG &DAG) const {
2923bdd1243dSDimitry Andric   assert(Op.getOpcode() == HexagonISD::TL_EXTEND ||
2924bdd1243dSDimitry Andric          Op.getOpcode() == HexagonISD::TL_TRUNCATE);
2925647cbc5dSDimitry Andric   unsigned Opc = Op.getConstantOperandVal(2);
2926bdd1243dSDimitry Andric   return DAG.getNode(Opc, SDLoc(Op), ty(Op), Op.getOperand(0));
2927bdd1243dSDimitry Andric }
2928bdd1243dSDimitry Andric 
2929bdd1243dSDimitry Andric HexagonTargetLowering::VectorPair
2930bdd1243dSDimitry Andric HexagonTargetLowering::SplitVectorOp(SDValue Op, SelectionDAG &DAG) const {
29310b57cec5SDimitry Andric   assert(!Op.isMachineOpcode());
29320b57cec5SDimitry Andric   SmallVector<SDValue, 2> OpsL, OpsH;
29330b57cec5SDimitry Andric   const SDLoc &dl(Op);
29340b57cec5SDimitry Andric 
29350b57cec5SDimitry Andric   auto SplitVTNode = [&DAG, this](const VTSDNode *N) {
29360b57cec5SDimitry Andric     MVT Ty = typeSplit(N->getVT().getSimpleVT()).first;
29370b57cec5SDimitry Andric     SDValue TV = DAG.getValueType(Ty);
29380b57cec5SDimitry Andric     return std::make_pair(TV, TV);
29390b57cec5SDimitry Andric   };
29400b57cec5SDimitry Andric 
29410b57cec5SDimitry Andric   for (SDValue A : Op.getNode()->ops()) {
2942bdd1243dSDimitry Andric     auto [Lo, Hi] =
2943bdd1243dSDimitry Andric         ty(A).isVector() ? opSplit(A, dl, DAG) : std::make_pair(A, A);
29440b57cec5SDimitry Andric     // Special case for type operand.
2945bdd1243dSDimitry Andric     switch (Op.getOpcode()) {
2946bdd1243dSDimitry Andric       case ISD::SIGN_EXTEND_INREG:
2947bdd1243dSDimitry Andric       case HexagonISD::SSAT:
2948bdd1243dSDimitry Andric       case HexagonISD::USAT:
29490b57cec5SDimitry Andric         if (const auto *N = dyn_cast<const VTSDNode>(A.getNode()))
2950bdd1243dSDimitry Andric           std::tie(Lo, Hi) = SplitVTNode(N);
2951bdd1243dSDimitry Andric       break;
29520b57cec5SDimitry Andric     }
2953bdd1243dSDimitry Andric     OpsL.push_back(Lo);
2954bdd1243dSDimitry Andric     OpsH.push_back(Hi);
29550b57cec5SDimitry Andric   }
29560b57cec5SDimitry Andric 
29570b57cec5SDimitry Andric   MVT ResTy = ty(Op);
29580b57cec5SDimitry Andric   MVT HalfTy = typeSplit(ResTy).first;
29590b57cec5SDimitry Andric   SDValue L = DAG.getNode(Op.getOpcode(), dl, HalfTy, OpsL);
29600b57cec5SDimitry Andric   SDValue H = DAG.getNode(Op.getOpcode(), dl, HalfTy, OpsH);
2961bdd1243dSDimitry Andric   return {L, H};
29620b57cec5SDimitry Andric }
29630b57cec5SDimitry Andric 
29640b57cec5SDimitry Andric SDValue
29650b57cec5SDimitry Andric HexagonTargetLowering::SplitHvxMemOp(SDValue Op, SelectionDAG &DAG) const {
2966e8d8bef9SDimitry Andric   auto *MemN = cast<MemSDNode>(Op.getNode());
2967e8d8bef9SDimitry Andric 
2968e8d8bef9SDimitry Andric   MVT MemTy = MemN->getMemoryVT().getSimpleVT();
29690b57cec5SDimitry Andric   if (!isHvxPairTy(MemTy))
29700b57cec5SDimitry Andric     return Op;
29710b57cec5SDimitry Andric 
29720b57cec5SDimitry Andric   const SDLoc &dl(Op);
29730b57cec5SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
29740b57cec5SDimitry Andric   MVT SingleTy = typeSplit(MemTy).first;
2975e8d8bef9SDimitry Andric   SDValue Chain = MemN->getChain();
2976e8d8bef9SDimitry Andric   SDValue Base0 = MemN->getBasePtr();
29775f757f3fSDimitry Andric   SDValue Base1 =
29785f757f3fSDimitry Andric       DAG.getMemBasePlusOffset(Base0, TypeSize::getFixed(HwLen), dl);
29794824e7fdSDimitry Andric   unsigned MemOpc = MemN->getOpcode();
29800b57cec5SDimitry Andric 
29810b57cec5SDimitry Andric   MachineMemOperand *MOp0 = nullptr, *MOp1 = nullptr;
2982e8d8bef9SDimitry Andric   if (MachineMemOperand *MMO = MemN->getMemOperand()) {
29830b57cec5SDimitry Andric     MachineFunction &MF = DAG.getMachineFunction();
29844824e7fdSDimitry Andric     uint64_t MemSize = (MemOpc == ISD::MLOAD || MemOpc == ISD::MSTORE)
29854824e7fdSDimitry Andric                            ? (uint64_t)MemoryLocation::UnknownSize
29864824e7fdSDimitry Andric                            : HwLen;
29874824e7fdSDimitry Andric     MOp0 = MF.getMachineMemOperand(MMO, 0, MemSize);
29884824e7fdSDimitry Andric     MOp1 = MF.getMachineMemOperand(MMO, HwLen, MemSize);
29890b57cec5SDimitry Andric   }
29900b57cec5SDimitry Andric 
29910b57cec5SDimitry Andric   if (MemOpc == ISD::LOAD) {
2992e8d8bef9SDimitry Andric     assert(cast<LoadSDNode>(Op)->isUnindexed());
29930b57cec5SDimitry Andric     SDValue Load0 = DAG.getLoad(SingleTy, dl, Chain, Base0, MOp0);
29940b57cec5SDimitry Andric     SDValue Load1 = DAG.getLoad(SingleTy, dl, Chain, Base1, MOp1);
2995e8d8bef9SDimitry Andric     return DAG.getMergeValues(
29960b57cec5SDimitry Andric         { DAG.getNode(ISD::CONCAT_VECTORS, dl, MemTy, Load0, Load1),
29970b57cec5SDimitry Andric           DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
29980b57cec5SDimitry Andric                       Load0.getValue(1), Load1.getValue(1)) }, dl);
2999e8d8bef9SDimitry Andric   }
3000e8d8bef9SDimitry Andric   if (MemOpc == ISD::STORE) {
3001e8d8bef9SDimitry Andric     assert(cast<StoreSDNode>(Op)->isUnindexed());
30020b57cec5SDimitry Andric     VectorPair Vals = opSplit(cast<StoreSDNode>(Op)->getValue(), dl, DAG);
30030b57cec5SDimitry Andric     SDValue Store0 = DAG.getStore(Chain, dl, Vals.first, Base0, MOp0);
30040b57cec5SDimitry Andric     SDValue Store1 = DAG.getStore(Chain, dl, Vals.second, Base1, MOp1);
3005e8d8bef9SDimitry Andric     return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Store0, Store1);
30060b57cec5SDimitry Andric   }
30070b57cec5SDimitry Andric 
3008e8d8bef9SDimitry Andric   assert(MemOpc == ISD::MLOAD || MemOpc == ISD::MSTORE);
3009e8d8bef9SDimitry Andric 
3010e8d8bef9SDimitry Andric   auto MaskN = cast<MaskedLoadStoreSDNode>(Op);
3011e8d8bef9SDimitry Andric   assert(MaskN->isUnindexed());
3012e8d8bef9SDimitry Andric   VectorPair Masks = opSplit(MaskN->getMask(), dl, DAG);
3013e8d8bef9SDimitry Andric   SDValue Offset = DAG.getUNDEF(MVT::i32);
3014e8d8bef9SDimitry Andric 
3015e8d8bef9SDimitry Andric   if (MemOpc == ISD::MLOAD) {
3016e8d8bef9SDimitry Andric     VectorPair Thru =
3017e8d8bef9SDimitry Andric         opSplit(cast<MaskedLoadSDNode>(Op)->getPassThru(), dl, DAG);
3018e8d8bef9SDimitry Andric     SDValue MLoad0 =
3019e8d8bef9SDimitry Andric         DAG.getMaskedLoad(SingleTy, dl, Chain, Base0, Offset, Masks.first,
3020e8d8bef9SDimitry Andric                           Thru.first, SingleTy, MOp0, ISD::UNINDEXED,
3021e8d8bef9SDimitry Andric                           ISD::NON_EXTLOAD, false);
3022e8d8bef9SDimitry Andric     SDValue MLoad1 =
3023e8d8bef9SDimitry Andric         DAG.getMaskedLoad(SingleTy, dl, Chain, Base1, Offset, Masks.second,
3024e8d8bef9SDimitry Andric                           Thru.second, SingleTy, MOp1, ISD::UNINDEXED,
3025e8d8bef9SDimitry Andric                           ISD::NON_EXTLOAD, false);
3026e8d8bef9SDimitry Andric     return DAG.getMergeValues(
3027e8d8bef9SDimitry Andric         { DAG.getNode(ISD::CONCAT_VECTORS, dl, MemTy, MLoad0, MLoad1),
3028e8d8bef9SDimitry Andric           DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
3029e8d8bef9SDimitry Andric                       MLoad0.getValue(1), MLoad1.getValue(1)) }, dl);
3030e8d8bef9SDimitry Andric   }
3031e8d8bef9SDimitry Andric   if (MemOpc == ISD::MSTORE) {
3032e8d8bef9SDimitry Andric     VectorPair Vals = opSplit(cast<MaskedStoreSDNode>(Op)->getValue(), dl, DAG);
3033e8d8bef9SDimitry Andric     SDValue MStore0 = DAG.getMaskedStore(Chain, dl, Vals.first, Base0, Offset,
3034e8d8bef9SDimitry Andric                                          Masks.first, SingleTy, MOp0,
3035e8d8bef9SDimitry Andric                                          ISD::UNINDEXED, false, false);
3036e8d8bef9SDimitry Andric     SDValue MStore1 = DAG.getMaskedStore(Chain, dl, Vals.second, Base1, Offset,
3037e8d8bef9SDimitry Andric                                          Masks.second, SingleTy, MOp1,
3038e8d8bef9SDimitry Andric                                          ISD::UNINDEXED, false, false);
3039e8d8bef9SDimitry Andric     return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MStore0, MStore1);
3040e8d8bef9SDimitry Andric   }
3041e8d8bef9SDimitry Andric 
3042e8d8bef9SDimitry Andric   std::string Name = "Unexpected operation: " + Op->getOperationName(&DAG);
3043e8d8bef9SDimitry Andric   llvm_unreachable(Name.c_str());
3044e8d8bef9SDimitry Andric }
3045e8d8bef9SDimitry Andric 
3046e8d8bef9SDimitry Andric SDValue
3047e8d8bef9SDimitry Andric HexagonTargetLowering::WidenHvxLoad(SDValue Op, SelectionDAG &DAG) const {
3048e8d8bef9SDimitry Andric   const SDLoc &dl(Op);
3049e8d8bef9SDimitry Andric   auto *LoadN = cast<LoadSDNode>(Op.getNode());
3050e8d8bef9SDimitry Andric   assert(LoadN->isUnindexed() && "Not widening indexed loads yet");
3051e8d8bef9SDimitry Andric   assert(LoadN->getMemoryVT().getVectorElementType() != MVT::i1 &&
3052e8d8bef9SDimitry Andric          "Not widening loads of i1 yet");
3053e8d8bef9SDimitry Andric 
3054e8d8bef9SDimitry Andric   SDValue Chain = LoadN->getChain();
3055e8d8bef9SDimitry Andric   SDValue Base = LoadN->getBasePtr();
3056e8d8bef9SDimitry Andric   SDValue Offset = DAG.getUNDEF(MVT::i32);
3057e8d8bef9SDimitry Andric 
3058e8d8bef9SDimitry Andric   MVT ResTy = ty(Op);
3059e8d8bef9SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
3060e8d8bef9SDimitry Andric   unsigned ResLen = ResTy.getStoreSize();
3061e8d8bef9SDimitry Andric   assert(ResLen < HwLen && "vsetq(v1) prerequisite");
3062e8d8bef9SDimitry Andric 
3063e8d8bef9SDimitry Andric   MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
3064e8d8bef9SDimitry Andric   SDValue Mask = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
3065e8d8bef9SDimitry Andric                           {DAG.getConstant(ResLen, dl, MVT::i32)}, DAG);
3066e8d8bef9SDimitry Andric 
3067e8d8bef9SDimitry Andric   MVT LoadTy = MVT::getVectorVT(MVT::i8, HwLen);
3068e8d8bef9SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
3069e8d8bef9SDimitry Andric   auto *MemOp = MF.getMachineMemOperand(LoadN->getMemOperand(), 0, HwLen);
3070e8d8bef9SDimitry Andric 
3071e8d8bef9SDimitry Andric   SDValue Load = DAG.getMaskedLoad(LoadTy, dl, Chain, Base, Offset, Mask,
3072e8d8bef9SDimitry Andric                                    DAG.getUNDEF(LoadTy), LoadTy, MemOp,
3073e8d8bef9SDimitry Andric                                    ISD::UNINDEXED, ISD::NON_EXTLOAD, false);
3074e8d8bef9SDimitry Andric   SDValue Value = opCastElem(Load, ResTy.getVectorElementType(), DAG);
3075bdd1243dSDimitry Andric   return DAG.getMergeValues({Value, Load.getValue(1)}, dl);
3076e8d8bef9SDimitry Andric }
3077e8d8bef9SDimitry Andric 
3078e8d8bef9SDimitry Andric SDValue
3079e8d8bef9SDimitry Andric HexagonTargetLowering::WidenHvxStore(SDValue Op, SelectionDAG &DAG) const {
3080e8d8bef9SDimitry Andric   const SDLoc &dl(Op);
3081e8d8bef9SDimitry Andric   auto *StoreN = cast<StoreSDNode>(Op.getNode());
3082e8d8bef9SDimitry Andric   assert(StoreN->isUnindexed() && "Not widening indexed stores yet");
3083e8d8bef9SDimitry Andric   assert(StoreN->getMemoryVT().getVectorElementType() != MVT::i1 &&
3084e8d8bef9SDimitry Andric          "Not widening stores of i1 yet");
3085e8d8bef9SDimitry Andric 
3086e8d8bef9SDimitry Andric   SDValue Chain = StoreN->getChain();
3087e8d8bef9SDimitry Andric   SDValue Base = StoreN->getBasePtr();
3088e8d8bef9SDimitry Andric   SDValue Offset = DAG.getUNDEF(MVT::i32);
3089e8d8bef9SDimitry Andric 
3090e8d8bef9SDimitry Andric   SDValue Value = opCastElem(StoreN->getValue(), MVT::i8, DAG);
3091e8d8bef9SDimitry Andric   MVT ValueTy = ty(Value);
3092e8d8bef9SDimitry Andric   unsigned ValueLen = ValueTy.getVectorNumElements();
3093e8d8bef9SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
3094e8d8bef9SDimitry Andric   assert(isPowerOf2_32(ValueLen));
3095e8d8bef9SDimitry Andric 
3096e8d8bef9SDimitry Andric   for (unsigned Len = ValueLen; Len < HwLen; ) {
3097bdd1243dSDimitry Andric     Value = opJoin({Value, DAG.getUNDEF(ty(Value))}, dl, DAG);
3098e8d8bef9SDimitry Andric     Len = ty(Value).getVectorNumElements(); // This is Len *= 2
3099e8d8bef9SDimitry Andric   }
3100e8d8bef9SDimitry Andric   assert(ty(Value).getVectorNumElements() == HwLen);  // Paranoia
3101e8d8bef9SDimitry Andric 
3102e8d8bef9SDimitry Andric   assert(ValueLen < HwLen && "vsetq(v1) prerequisite");
3103e8d8bef9SDimitry Andric   MVT BoolTy = MVT::getVectorVT(MVT::i1, HwLen);
3104e8d8bef9SDimitry Andric   SDValue Mask = getInstr(Hexagon::V6_pred_scalar2, dl, BoolTy,
3105e8d8bef9SDimitry Andric                           {DAG.getConstant(ValueLen, dl, MVT::i32)}, DAG);
3106e8d8bef9SDimitry Andric   MachineFunction &MF = DAG.getMachineFunction();
3107e8d8bef9SDimitry Andric   auto *MemOp = MF.getMachineMemOperand(StoreN->getMemOperand(), 0, HwLen);
3108e8d8bef9SDimitry Andric   return DAG.getMaskedStore(Chain, dl, Value, Base, Offset, Mask, ty(Value),
3109e8d8bef9SDimitry Andric                             MemOp, ISD::UNINDEXED, false, false);
3110e8d8bef9SDimitry Andric }
3111e8d8bef9SDimitry Andric 
3112e8d8bef9SDimitry Andric SDValue
3113e8d8bef9SDimitry Andric HexagonTargetLowering::WidenHvxSetCC(SDValue Op, SelectionDAG &DAG) const {
3114e8d8bef9SDimitry Andric   const SDLoc &dl(Op);
3115e8d8bef9SDimitry Andric   SDValue Op0 = Op.getOperand(0), Op1 = Op.getOperand(1);
3116e8d8bef9SDimitry Andric   MVT ElemTy = ty(Op0).getVectorElementType();
3117e8d8bef9SDimitry Andric   unsigned HwLen = Subtarget.getVectorLength();
3118e8d8bef9SDimitry Andric 
3119e8d8bef9SDimitry Andric   unsigned WideOpLen = (8 * HwLen) / ElemTy.getSizeInBits();
3120e8d8bef9SDimitry Andric   assert(WideOpLen * ElemTy.getSizeInBits() == 8 * HwLen);
3121e8d8bef9SDimitry Andric   MVT WideOpTy = MVT::getVectorVT(ElemTy, WideOpLen);
3122fe6060f1SDimitry Andric   if (!Subtarget.isHVXVectorType(WideOpTy, true))
3123fe6060f1SDimitry Andric     return SDValue();
3124e8d8bef9SDimitry Andric 
3125e8d8bef9SDimitry Andric   SDValue WideOp0 = appendUndef(Op0, WideOpTy, DAG);
3126e8d8bef9SDimitry Andric   SDValue WideOp1 = appendUndef(Op1, WideOpTy, DAG);
3127e8d8bef9SDimitry Andric   EVT ResTy =
3128e8d8bef9SDimitry Andric       getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), WideOpTy);
3129e8d8bef9SDimitry Andric   SDValue SetCC = DAG.getNode(ISD::SETCC, dl, ResTy,
3130e8d8bef9SDimitry Andric                               {WideOp0, WideOp1, Op.getOperand(2)});
3131e8d8bef9SDimitry Andric 
3132bdd1243dSDimitry Andric   EVT RetTy = typeLegalize(ty(Op), DAG);
3133e8d8bef9SDimitry Andric   return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, RetTy,
3134e8d8bef9SDimitry Andric                      {SetCC, getZero(dl, MVT::i32, DAG)});
3135e8d8bef9SDimitry Andric }
3136e8d8bef9SDimitry Andric 
3137e8d8bef9SDimitry Andric SDValue
31380b57cec5SDimitry Andric HexagonTargetLowering::LowerHvxOperation(SDValue Op, SelectionDAG &DAG) const {
31390b57cec5SDimitry Andric   unsigned Opc = Op.getOpcode();
31400b57cec5SDimitry Andric   bool IsPairOp = isHvxPairTy(ty(Op)) ||
31410b57cec5SDimitry Andric                   llvm::any_of(Op.getNode()->ops(), [this] (SDValue V) {
31420b57cec5SDimitry Andric                     return isHvxPairTy(ty(V));
31430b57cec5SDimitry Andric                   });
31440b57cec5SDimitry Andric 
31450b57cec5SDimitry Andric   if (IsPairOp) {
31460b57cec5SDimitry Andric     switch (Opc) {
31470b57cec5SDimitry Andric       default:
31480b57cec5SDimitry Andric         break;
31490b57cec5SDimitry Andric       case ISD::LOAD:
31500b57cec5SDimitry Andric       case ISD::STORE:
3151e8d8bef9SDimitry Andric       case ISD::MLOAD:
3152e8d8bef9SDimitry Andric       case ISD::MSTORE:
31530b57cec5SDimitry Andric         return SplitHvxMemOp(Op, DAG);
315404eeddc0SDimitry Andric       case ISD::SINT_TO_FP:
315504eeddc0SDimitry Andric       case ISD::UINT_TO_FP:
315604eeddc0SDimitry Andric       case ISD::FP_TO_SINT:
315704eeddc0SDimitry Andric       case ISD::FP_TO_UINT:
315804eeddc0SDimitry Andric         if (ty(Op).getSizeInBits() == ty(Op.getOperand(0)).getSizeInBits())
3159bdd1243dSDimitry Andric           return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
316004eeddc0SDimitry Andric         break;
3161bdd1243dSDimitry Andric       case ISD::ABS:
31620b57cec5SDimitry Andric       case ISD::CTPOP:
31630b57cec5SDimitry Andric       case ISD::CTLZ:
31640b57cec5SDimitry Andric       case ISD::CTTZ:
31650b57cec5SDimitry Andric       case ISD::MUL:
316604eeddc0SDimitry Andric       case ISD::FADD:
316704eeddc0SDimitry Andric       case ISD::FSUB:
316804eeddc0SDimitry Andric       case ISD::FMUL:
316904eeddc0SDimitry Andric       case ISD::FMINNUM:
317004eeddc0SDimitry Andric       case ISD::FMAXNUM:
31710b57cec5SDimitry Andric       case ISD::MULHS:
31720b57cec5SDimitry Andric       case ISD::MULHU:
31730b57cec5SDimitry Andric       case ISD::AND:
31740b57cec5SDimitry Andric       case ISD::OR:
31750b57cec5SDimitry Andric       case ISD::XOR:
31760b57cec5SDimitry Andric       case ISD::SRA:
31770b57cec5SDimitry Andric       case ISD::SHL:
31780b57cec5SDimitry Andric       case ISD::SRL:
3179bdd1243dSDimitry Andric       case ISD::FSHL:
3180bdd1243dSDimitry Andric       case ISD::FSHR:
3181e8d8bef9SDimitry Andric       case ISD::SMIN:
3182e8d8bef9SDimitry Andric       case ISD::SMAX:
3183e8d8bef9SDimitry Andric       case ISD::UMIN:
3184e8d8bef9SDimitry Andric       case ISD::UMAX:
31850b57cec5SDimitry Andric       case ISD::SETCC:
31860b57cec5SDimitry Andric       case ISD::VSELECT:
31870b57cec5SDimitry Andric       case ISD::SIGN_EXTEND_INREG:
3188e8d8bef9SDimitry Andric       case ISD::SPLAT_VECTOR:
3189bdd1243dSDimitry Andric         return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
3190bdd1243dSDimitry Andric       case ISD::SIGN_EXTEND:
3191bdd1243dSDimitry Andric       case ISD::ZERO_EXTEND:
3192bdd1243dSDimitry Andric         // In general, sign- and zero-extends can't be split and still
3193bdd1243dSDimitry Andric         // be legal. The only exception is extending bool vectors.
3194bdd1243dSDimitry Andric         if (ty(Op.getOperand(0)).getVectorElementType() == MVT::i1)
3195bdd1243dSDimitry Andric           return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
3196bdd1243dSDimitry Andric         break;
31970b57cec5SDimitry Andric     }
31980b57cec5SDimitry Andric   }
31990b57cec5SDimitry Andric 
32000b57cec5SDimitry Andric   switch (Opc) {
32010b57cec5SDimitry Andric     default:
32020b57cec5SDimitry Andric       break;
32030b57cec5SDimitry Andric     case ISD::BUILD_VECTOR:            return LowerHvxBuildVector(Op, DAG);
320404eeddc0SDimitry Andric     case ISD::SPLAT_VECTOR:            return LowerHvxSplatVector(Op, DAG);
32050b57cec5SDimitry Andric     case ISD::CONCAT_VECTORS:          return LowerHvxConcatVectors(Op, DAG);
32060b57cec5SDimitry Andric     case ISD::INSERT_SUBVECTOR:        return LowerHvxInsertSubvector(Op, DAG);
32070b57cec5SDimitry Andric     case ISD::INSERT_VECTOR_ELT:       return LowerHvxInsertElement(Op, DAG);
32080b57cec5SDimitry Andric     case ISD::EXTRACT_SUBVECTOR:       return LowerHvxExtractSubvector(Op, DAG);
32090b57cec5SDimitry Andric     case ISD::EXTRACT_VECTOR_ELT:      return LowerHvxExtractElement(Op, DAG);
32105ffd83dbSDimitry Andric     case ISD::BITCAST:                 return LowerHvxBitcast(Op, DAG);
32110b57cec5SDimitry Andric     case ISD::ANY_EXTEND:              return LowerHvxAnyExt(Op, DAG);
32120b57cec5SDimitry Andric     case ISD::SIGN_EXTEND:             return LowerHvxSignExt(Op, DAG);
32130b57cec5SDimitry Andric     case ISD::ZERO_EXTEND:             return LowerHvxZeroExt(Op, DAG);
32140b57cec5SDimitry Andric     case ISD::CTTZ:                    return LowerHvxCttz(Op, DAG);
3215e8d8bef9SDimitry Andric     case ISD::SELECT:                  return LowerHvxSelect(Op, DAG);
32160b57cec5SDimitry Andric     case ISD::SRA:
32170b57cec5SDimitry Andric     case ISD::SHL:
32180b57cec5SDimitry Andric     case ISD::SRL:                     return LowerHvxShift(Op, DAG);
3219bdd1243dSDimitry Andric     case ISD::FSHL:
3220bdd1243dSDimitry Andric     case ISD::FSHR:                    return LowerHvxFunnelShift(Op, DAG);
32210b57cec5SDimitry Andric     case ISD::MULHS:
32220b57cec5SDimitry Andric     case ISD::MULHU:                   return LowerHvxMulh(Op, DAG);
3223bdd1243dSDimitry Andric     case ISD::SMUL_LOHI:
3224bdd1243dSDimitry Andric     case ISD::UMUL_LOHI:               return LowerHvxMulLoHi(Op, DAG);
32250b57cec5SDimitry Andric     case ISD::ANY_EXTEND_VECTOR_INREG: return LowerHvxExtend(Op, DAG);
32260b57cec5SDimitry Andric     case ISD::SETCC:
32270b57cec5SDimitry Andric     case ISD::INTRINSIC_VOID:          return Op;
32285ffd83dbSDimitry Andric     case ISD::INTRINSIC_WO_CHAIN:      return LowerHvxIntrinsic(Op, DAG);
3229e8d8bef9SDimitry Andric     case ISD::MLOAD:
3230e8d8bef9SDimitry Andric     case ISD::MSTORE:                  return LowerHvxMaskedOp(Op, DAG);
32310b57cec5SDimitry Andric     // Unaligned loads will be handled by the default lowering.
32320b57cec5SDimitry Andric     case ISD::LOAD:                    return SDValue();
323304eeddc0SDimitry Andric     case ISD::FP_EXTEND:               return LowerHvxFpExtend(Op, DAG);
323404eeddc0SDimitry Andric     case ISD::FP_TO_SINT:
3235bdd1243dSDimitry Andric     case ISD::FP_TO_UINT:              return LowerHvxFpToInt(Op, DAG);
323604eeddc0SDimitry Andric     case ISD::SINT_TO_FP:
3237bdd1243dSDimitry Andric     case ISD::UINT_TO_FP:              return LowerHvxIntToFp(Op, DAG);
3238bdd1243dSDimitry Andric 
3239bdd1243dSDimitry Andric     // Special nodes:
3240bdd1243dSDimitry Andric     case HexagonISD::SMUL_LOHI:
3241bdd1243dSDimitry Andric     case HexagonISD::UMUL_LOHI:
3242bdd1243dSDimitry Andric     case HexagonISD::USMUL_LOHI:       return LowerHvxMulLoHi(Op, DAG);
32430b57cec5SDimitry Andric   }
32440b57cec5SDimitry Andric #ifndef NDEBUG
32450b57cec5SDimitry Andric   Op.dumpr(&DAG);
32460b57cec5SDimitry Andric #endif
32470b57cec5SDimitry Andric   llvm_unreachable("Unhandled HVX operation");
32480b57cec5SDimitry Andric }
32490b57cec5SDimitry Andric 
3250bdd1243dSDimitry Andric SDValue
3251bdd1243dSDimitry Andric HexagonTargetLowering::ExpandHvxResizeIntoSteps(SDValue Op, SelectionDAG &DAG)
3252bdd1243dSDimitry Andric       const {
3253bdd1243dSDimitry Andric   // Rewrite the extension/truncation/saturation op into steps where each
3254bdd1243dSDimitry Andric   // step changes the type widths by a factor of 2.
3255bdd1243dSDimitry Andric   // E.g.  i8 -> i16 remains unchanged, but i8 -> i32  ==>  i8 -> i16 -> i32.
3256bdd1243dSDimitry Andric   //
3257bdd1243dSDimitry Andric   // Some of the vector types in Op may not be legal.
3258bdd1243dSDimitry Andric 
3259bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
3260bdd1243dSDimitry Andric   switch (Opc) {
3261bdd1243dSDimitry Andric     case HexagonISD::SSAT:
3262bdd1243dSDimitry Andric     case HexagonISD::USAT:
3263bdd1243dSDimitry Andric     case HexagonISD::TL_EXTEND:
3264bdd1243dSDimitry Andric     case HexagonISD::TL_TRUNCATE:
3265bdd1243dSDimitry Andric       break;
3266bdd1243dSDimitry Andric     case ISD::ANY_EXTEND:
3267bdd1243dSDimitry Andric     case ISD::ZERO_EXTEND:
3268bdd1243dSDimitry Andric     case ISD::SIGN_EXTEND:
3269bdd1243dSDimitry Andric     case ISD::TRUNCATE:
3270bdd1243dSDimitry Andric       llvm_unreachable("ISD:: ops will be auto-folded");
3271bdd1243dSDimitry Andric       break;
3272bdd1243dSDimitry Andric #ifndef NDEBUG
3273bdd1243dSDimitry Andric     Op.dump(&DAG);
3274bdd1243dSDimitry Andric #endif
3275bdd1243dSDimitry Andric     llvm_unreachable("Unexpected operation");
3276bdd1243dSDimitry Andric   }
3277bdd1243dSDimitry Andric 
3278bdd1243dSDimitry Andric   SDValue Inp = Op.getOperand(0);
3279bdd1243dSDimitry Andric   MVT InpTy = ty(Inp);
3280bdd1243dSDimitry Andric   MVT ResTy = ty(Op);
3281bdd1243dSDimitry Andric 
3282bdd1243dSDimitry Andric   unsigned InpWidth = InpTy.getVectorElementType().getSizeInBits();
3283bdd1243dSDimitry Andric   unsigned ResWidth = ResTy.getVectorElementType().getSizeInBits();
3284bdd1243dSDimitry Andric   assert(InpWidth != ResWidth);
3285bdd1243dSDimitry Andric 
3286bdd1243dSDimitry Andric   if (InpWidth == 2 * ResWidth || ResWidth == 2 * InpWidth)
3287bdd1243dSDimitry Andric     return Op;
3288bdd1243dSDimitry Andric 
3289bdd1243dSDimitry Andric   const SDLoc &dl(Op);
3290bdd1243dSDimitry Andric   unsigned NumElems = InpTy.getVectorNumElements();
3291bdd1243dSDimitry Andric   assert(NumElems == ResTy.getVectorNumElements());
3292bdd1243dSDimitry Andric 
3293bdd1243dSDimitry Andric   auto repeatOp = [&](unsigned NewWidth, SDValue Arg) {
3294bdd1243dSDimitry Andric     MVT Ty = MVT::getVectorVT(MVT::getIntegerVT(NewWidth), NumElems);
3295bdd1243dSDimitry Andric     switch (Opc) {
3296bdd1243dSDimitry Andric       case HexagonISD::SSAT:
3297bdd1243dSDimitry Andric       case HexagonISD::USAT:
3298bdd1243dSDimitry Andric         return DAG.getNode(Opc, dl, Ty, {Arg, DAG.getValueType(Ty)});
3299bdd1243dSDimitry Andric       case HexagonISD::TL_EXTEND:
3300bdd1243dSDimitry Andric       case HexagonISD::TL_TRUNCATE:
3301bdd1243dSDimitry Andric         return DAG.getNode(Opc, dl, Ty, {Arg, Op.getOperand(1), Op.getOperand(2)});
3302bdd1243dSDimitry Andric       default:
3303bdd1243dSDimitry Andric         llvm_unreachable("Unexpected opcode");
3304bdd1243dSDimitry Andric     }
3305bdd1243dSDimitry Andric   };
3306bdd1243dSDimitry Andric 
3307bdd1243dSDimitry Andric   SDValue S = Inp;
3308bdd1243dSDimitry Andric   if (InpWidth < ResWidth) {
3309bdd1243dSDimitry Andric     assert(ResWidth % InpWidth == 0 && isPowerOf2_32(ResWidth / InpWidth));
3310bdd1243dSDimitry Andric     while (InpWidth * 2 <= ResWidth)
3311bdd1243dSDimitry Andric       S = repeatOp(InpWidth *= 2, S);
3312bdd1243dSDimitry Andric   } else {
3313bdd1243dSDimitry Andric     // InpWidth > ResWidth
3314bdd1243dSDimitry Andric     assert(InpWidth % ResWidth == 0 && isPowerOf2_32(InpWidth / ResWidth));
3315bdd1243dSDimitry Andric     while (InpWidth / 2 >= ResWidth)
3316bdd1243dSDimitry Andric       S = repeatOp(InpWidth /= 2, S);
3317bdd1243dSDimitry Andric   }
3318bdd1243dSDimitry Andric   return S;
3319bdd1243dSDimitry Andric }
3320bdd1243dSDimitry Andric 
3321bdd1243dSDimitry Andric SDValue
3322bdd1243dSDimitry Andric HexagonTargetLowering::LegalizeHvxResize(SDValue Op, SelectionDAG &DAG) const {
3323bdd1243dSDimitry Andric   SDValue Inp0 = Op.getOperand(0);
3324bdd1243dSDimitry Andric   MVT InpTy = ty(Inp0);
3325bdd1243dSDimitry Andric   MVT ResTy = ty(Op);
3326bdd1243dSDimitry Andric   unsigned InpWidth = InpTy.getSizeInBits();
3327bdd1243dSDimitry Andric   unsigned ResWidth = ResTy.getSizeInBits();
3328bdd1243dSDimitry Andric   unsigned Opc = Op.getOpcode();
3329bdd1243dSDimitry Andric 
3330bdd1243dSDimitry Andric   if (shouldWidenToHvx(InpTy, DAG) || shouldWidenToHvx(ResTy, DAG)) {
3331bdd1243dSDimitry Andric     // First, make sure that the narrower type is widened to HVX.
3332bdd1243dSDimitry Andric     // This may cause the result to be wider than what the legalizer
3333bdd1243dSDimitry Andric     // expects, so insert EXTRACT_SUBVECTOR to bring it back to the
3334bdd1243dSDimitry Andric     // desired type.
3335bdd1243dSDimitry Andric     auto [WInpTy, WResTy] =
3336bdd1243dSDimitry Andric         InpWidth < ResWidth ? typeWidenToWider(typeWidenToHvx(InpTy), ResTy)
3337bdd1243dSDimitry Andric                             : typeWidenToWider(InpTy, typeWidenToHvx(ResTy));
3338bdd1243dSDimitry Andric     SDValue W = appendUndef(Inp0, WInpTy, DAG);
3339bdd1243dSDimitry Andric     SDValue S;
3340bdd1243dSDimitry Andric     if (Opc == HexagonISD::TL_EXTEND || Opc == HexagonISD::TL_TRUNCATE) {
3341bdd1243dSDimitry Andric       S = DAG.getNode(Opc, SDLoc(Op), WResTy, W, Op.getOperand(1),
3342bdd1243dSDimitry Andric                       Op.getOperand(2));
3343bdd1243dSDimitry Andric     } else {
3344bdd1243dSDimitry Andric       S = DAG.getNode(Opc, SDLoc(Op), WResTy, W, DAG.getValueType(WResTy));
3345bdd1243dSDimitry Andric     }
3346bdd1243dSDimitry Andric     SDValue T = ExpandHvxResizeIntoSteps(S, DAG);
3347bdd1243dSDimitry Andric     return extractSubvector(T, typeLegalize(ResTy, DAG), 0, DAG);
3348bdd1243dSDimitry Andric   } else if (shouldSplitToHvx(InpWidth < ResWidth ? ResTy : InpTy, DAG)) {
3349bdd1243dSDimitry Andric     return opJoin(SplitVectorOp(Op, DAG), SDLoc(Op), DAG);
3350bdd1243dSDimitry Andric   } else {
3351bdd1243dSDimitry Andric     assert(isTypeLegal(InpTy) && isTypeLegal(ResTy));
3352bdd1243dSDimitry Andric     return RemoveTLWrapper(Op, DAG);
3353bdd1243dSDimitry Andric   }
3354bdd1243dSDimitry Andric   llvm_unreachable("Unexpected situation");
3355bdd1243dSDimitry Andric }
3356bdd1243dSDimitry Andric 
33575ffd83dbSDimitry Andric void
33585ffd83dbSDimitry Andric HexagonTargetLowering::LowerHvxOperationWrapper(SDNode *N,
33595ffd83dbSDimitry Andric       SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
3360e8d8bef9SDimitry Andric   unsigned Opc = N->getOpcode();
3361e8d8bef9SDimitry Andric   SDValue Op(N, 0);
3362bdd1243dSDimitry Andric   SDValue Inp0;   // Optional first argument.
3363bdd1243dSDimitry Andric   if (N->getNumOperands() > 0)
3364bdd1243dSDimitry Andric     Inp0 = Op.getOperand(0);
3365e8d8bef9SDimitry Andric 
3366e8d8bef9SDimitry Andric   switch (Opc) {
3367e8d8bef9SDimitry Andric     case ISD::ANY_EXTEND:
3368e8d8bef9SDimitry Andric     case ISD::SIGN_EXTEND:
3369e8d8bef9SDimitry Andric     case ISD::ZERO_EXTEND:
3370bdd1243dSDimitry Andric     case ISD::TRUNCATE:
3371bdd1243dSDimitry Andric       if (Subtarget.isHVXElementType(ty(Op)) &&
3372bdd1243dSDimitry Andric           Subtarget.isHVXElementType(ty(Inp0))) {
3373bdd1243dSDimitry Andric         Results.push_back(CreateTLWrapper(Op, DAG));
3374e8d8bef9SDimitry Andric       }
3375e8d8bef9SDimitry Andric       break;
3376e8d8bef9SDimitry Andric     case ISD::SETCC:
3377bdd1243dSDimitry Andric       if (shouldWidenToHvx(ty(Inp0), DAG)) {
3378e8d8bef9SDimitry Andric         if (SDValue T = WidenHvxSetCC(Op, DAG))
3379e8d8bef9SDimitry Andric           Results.push_back(T);
3380e8d8bef9SDimitry Andric       }
3381e8d8bef9SDimitry Andric       break;
3382e8d8bef9SDimitry Andric     case ISD::STORE: {
3383e8d8bef9SDimitry Andric       if (shouldWidenToHvx(ty(cast<StoreSDNode>(N)->getValue()), DAG)) {
3384e8d8bef9SDimitry Andric         SDValue Store = WidenHvxStore(Op, DAG);
3385e8d8bef9SDimitry Andric         Results.push_back(Store);
3386e8d8bef9SDimitry Andric       }
3387e8d8bef9SDimitry Andric       break;
3388e8d8bef9SDimitry Andric     }
3389e8d8bef9SDimitry Andric     case ISD::MLOAD:
3390e8d8bef9SDimitry Andric       if (isHvxPairTy(ty(Op))) {
3391e8d8bef9SDimitry Andric         SDValue S = SplitHvxMemOp(Op, DAG);
3392e8d8bef9SDimitry Andric         assert(S->getOpcode() == ISD::MERGE_VALUES);
3393e8d8bef9SDimitry Andric         Results.push_back(S.getOperand(0));
3394e8d8bef9SDimitry Andric         Results.push_back(S.getOperand(1));
3395e8d8bef9SDimitry Andric       }
3396e8d8bef9SDimitry Andric       break;
3397e8d8bef9SDimitry Andric     case ISD::MSTORE:
3398e8d8bef9SDimitry Andric       if (isHvxPairTy(ty(Op->getOperand(1)))) {    // Stored value
3399e8d8bef9SDimitry Andric         SDValue S = SplitHvxMemOp(Op, DAG);
3400e8d8bef9SDimitry Andric         Results.push_back(S);
3401e8d8bef9SDimitry Andric       }
3402e8d8bef9SDimitry Andric       break;
3403bdd1243dSDimitry Andric     case ISD::SINT_TO_FP:
3404bdd1243dSDimitry Andric     case ISD::UINT_TO_FP:
3405bdd1243dSDimitry Andric     case ISD::FP_TO_SINT:
3406bdd1243dSDimitry Andric     case ISD::FP_TO_UINT:
3407bdd1243dSDimitry Andric       if (ty(Op).getSizeInBits() != ty(Inp0).getSizeInBits()) {
3408bdd1243dSDimitry Andric         SDValue T = EqualizeFpIntConversion(Op, DAG);
3409bdd1243dSDimitry Andric         Results.push_back(T);
3410bdd1243dSDimitry Andric       }
3411bdd1243dSDimitry Andric       break;
3412bdd1243dSDimitry Andric     case HexagonISD::SSAT:
3413bdd1243dSDimitry Andric     case HexagonISD::USAT:
3414bdd1243dSDimitry Andric     case HexagonISD::TL_EXTEND:
3415bdd1243dSDimitry Andric     case HexagonISD::TL_TRUNCATE:
3416bdd1243dSDimitry Andric       Results.push_back(LegalizeHvxResize(Op, DAG));
3417bdd1243dSDimitry Andric       break;
3418e8d8bef9SDimitry Andric     default:
3419e8d8bef9SDimitry Andric       break;
3420e8d8bef9SDimitry Andric   }
34215ffd83dbSDimitry Andric }
34225ffd83dbSDimitry Andric 
34235ffd83dbSDimitry Andric void
34245ffd83dbSDimitry Andric HexagonTargetLowering::ReplaceHvxNodeResults(SDNode *N,
34255ffd83dbSDimitry Andric       SmallVectorImpl<SDValue> &Results, SelectionDAG &DAG) const {
34265ffd83dbSDimitry Andric   unsigned Opc = N->getOpcode();
3427e8d8bef9SDimitry Andric   SDValue Op(N, 0);
3428bdd1243dSDimitry Andric   SDValue Inp0;   // Optional first argument.
3429bdd1243dSDimitry Andric   if (N->getNumOperands() > 0)
3430bdd1243dSDimitry Andric     Inp0 = Op.getOperand(0);
3431bdd1243dSDimitry Andric 
34325ffd83dbSDimitry Andric   switch (Opc) {
3433e8d8bef9SDimitry Andric     case ISD::ANY_EXTEND:
3434e8d8bef9SDimitry Andric     case ISD::SIGN_EXTEND:
3435e8d8bef9SDimitry Andric     case ISD::ZERO_EXTEND:
3436bdd1243dSDimitry Andric     case ISD::TRUNCATE:
3437bdd1243dSDimitry Andric       if (Subtarget.isHVXElementType(ty(Op)) &&
3438bdd1243dSDimitry Andric           Subtarget.isHVXElementType(ty(Inp0))) {
3439bdd1243dSDimitry Andric         Results.push_back(CreateTLWrapper(Op, DAG));
3440e8d8bef9SDimitry Andric       }
3441e8d8bef9SDimitry Andric       break;
3442e8d8bef9SDimitry Andric     case ISD::SETCC:
3443e8d8bef9SDimitry Andric       if (shouldWidenToHvx(ty(Op), DAG)) {
3444e8d8bef9SDimitry Andric         if (SDValue T = WidenHvxSetCC(Op, DAG))
3445e8d8bef9SDimitry Andric           Results.push_back(T);
3446e8d8bef9SDimitry Andric       }
3447e8d8bef9SDimitry Andric       break;
3448e8d8bef9SDimitry Andric     case ISD::LOAD: {
3449e8d8bef9SDimitry Andric       if (shouldWidenToHvx(ty(Op), DAG)) {
3450e8d8bef9SDimitry Andric         SDValue Load = WidenHvxLoad(Op, DAG);
3451e8d8bef9SDimitry Andric         assert(Load->getOpcode() == ISD::MERGE_VALUES);
3452e8d8bef9SDimitry Andric         Results.push_back(Load.getOperand(0));
3453e8d8bef9SDimitry Andric         Results.push_back(Load.getOperand(1));
3454e8d8bef9SDimitry Andric       }
3455e8d8bef9SDimitry Andric       break;
3456e8d8bef9SDimitry Andric     }
34575ffd83dbSDimitry Andric     case ISD::BITCAST:
3458bdd1243dSDimitry Andric       if (isHvxBoolTy(ty(Inp0))) {
34595ffd83dbSDimitry Andric         SDValue C = LowerHvxBitcast(Op, DAG);
34605ffd83dbSDimitry Andric         Results.push_back(C);
34615ffd83dbSDimitry Andric       }
34625ffd83dbSDimitry Andric       break;
3463bdd1243dSDimitry Andric     case ISD::FP_TO_SINT:
3464bdd1243dSDimitry Andric     case ISD::FP_TO_UINT:
3465bdd1243dSDimitry Andric       if (ty(Op).getSizeInBits() != ty(Inp0).getSizeInBits()) {
3466bdd1243dSDimitry Andric         SDValue T = EqualizeFpIntConversion(Op, DAG);
3467bdd1243dSDimitry Andric         Results.push_back(T);
3468bdd1243dSDimitry Andric       }
3469bdd1243dSDimitry Andric       break;
3470bdd1243dSDimitry Andric     case HexagonISD::SSAT:
3471bdd1243dSDimitry Andric     case HexagonISD::USAT:
3472bdd1243dSDimitry Andric     case HexagonISD::TL_EXTEND:
3473bdd1243dSDimitry Andric     case HexagonISD::TL_TRUNCATE:
3474bdd1243dSDimitry Andric       Results.push_back(LegalizeHvxResize(Op, DAG));
3475bdd1243dSDimitry Andric       break;
34765ffd83dbSDimitry Andric     default:
34775ffd83dbSDimitry Andric       break;
34785ffd83dbSDimitry Andric   }
34795ffd83dbSDimitry Andric }
34805ffd83dbSDimitry Andric 
34818bcb0991SDimitry Andric SDValue
3482bdd1243dSDimitry Andric HexagonTargetLowering::combineTruncateBeforeLegal(SDValue Op,
3483bdd1243dSDimitry Andric                                                   DAGCombinerInfo &DCI) const {
3484bdd1243dSDimitry Andric   // Simplify V:v2NiB --(bitcast)--> vNi2B --(truncate)--> vNiB
3485bdd1243dSDimitry Andric   // to extract-subvector (shuffle V, pick even, pick odd)
3486bdd1243dSDimitry Andric 
3487bdd1243dSDimitry Andric   assert(Op.getOpcode() == ISD::TRUNCATE);
3488bdd1243dSDimitry Andric   SelectionDAG &DAG = DCI.DAG;
3489bdd1243dSDimitry Andric   const SDLoc &dl(Op);
3490bdd1243dSDimitry Andric 
3491bdd1243dSDimitry Andric   if (Op.getOperand(0).getOpcode() == ISD::BITCAST)
3492bdd1243dSDimitry Andric     return SDValue();
3493bdd1243dSDimitry Andric   SDValue Cast = Op.getOperand(0);
3494bdd1243dSDimitry Andric   SDValue Src = Cast.getOperand(0);
3495bdd1243dSDimitry Andric 
3496bdd1243dSDimitry Andric   EVT TruncTy = Op.getValueType();
3497bdd1243dSDimitry Andric   EVT CastTy = Cast.getValueType();
3498bdd1243dSDimitry Andric   EVT SrcTy = Src.getValueType();
3499bdd1243dSDimitry Andric   if (SrcTy.isSimple())
3500bdd1243dSDimitry Andric     return SDValue();
3501bdd1243dSDimitry Andric   if (SrcTy.getVectorElementType() != TruncTy.getVectorElementType())
3502bdd1243dSDimitry Andric     return SDValue();
3503bdd1243dSDimitry Andric   unsigned SrcLen = SrcTy.getVectorNumElements();
3504bdd1243dSDimitry Andric   unsigned CastLen = CastTy.getVectorNumElements();
3505bdd1243dSDimitry Andric   if (2 * CastLen != SrcLen)
3506bdd1243dSDimitry Andric     return SDValue();
3507bdd1243dSDimitry Andric 
3508bdd1243dSDimitry Andric   SmallVector<int, 128> Mask(SrcLen);
3509bdd1243dSDimitry Andric   for (int i = 0; i != static_cast<int>(CastLen); ++i) {
3510bdd1243dSDimitry Andric     Mask[i] = 2 * i;
3511bdd1243dSDimitry Andric     Mask[i + CastLen] = 2 * i + 1;
3512bdd1243dSDimitry Andric   }
3513bdd1243dSDimitry Andric   SDValue Deal =
3514bdd1243dSDimitry Andric       DAG.getVectorShuffle(SrcTy, dl, Src, DAG.getUNDEF(SrcTy), Mask);
3515bdd1243dSDimitry Andric   return opSplit(Deal, dl, DAG).first;
3516bdd1243dSDimitry Andric }
3517bdd1243dSDimitry Andric 
3518bdd1243dSDimitry Andric SDValue
3519bdd1243dSDimitry Andric HexagonTargetLowering::combineConcatVectorsBeforeLegal(
3520bdd1243dSDimitry Andric     SDValue Op, DAGCombinerInfo &DCI) const {
3521bdd1243dSDimitry Andric   // Fold
3522bdd1243dSDimitry Andric   //   concat (shuffle x, y, m1), (shuffle x, y, m2)
3523bdd1243dSDimitry Andric   // into
3524bdd1243dSDimitry Andric   //   shuffle (concat x, y), undef, m3
3525bdd1243dSDimitry Andric   if (Op.getNumOperands() != 2)
3526bdd1243dSDimitry Andric     return SDValue();
3527bdd1243dSDimitry Andric 
3528bdd1243dSDimitry Andric   SelectionDAG &DAG = DCI.DAG;
3529bdd1243dSDimitry Andric   const SDLoc &dl(Op);
3530bdd1243dSDimitry Andric   SDValue V0 = Op.getOperand(0);
3531bdd1243dSDimitry Andric   SDValue V1 = Op.getOperand(1);
3532bdd1243dSDimitry Andric 
3533bdd1243dSDimitry Andric   if (V0.getOpcode() != ISD::VECTOR_SHUFFLE)
3534bdd1243dSDimitry Andric     return SDValue();
3535bdd1243dSDimitry Andric   if (V1.getOpcode() != ISD::VECTOR_SHUFFLE)
3536bdd1243dSDimitry Andric     return SDValue();
3537bdd1243dSDimitry Andric 
3538bdd1243dSDimitry Andric   SetVector<SDValue> Order;
3539bdd1243dSDimitry Andric   Order.insert(V0.getOperand(0));
3540bdd1243dSDimitry Andric   Order.insert(V0.getOperand(1));
3541bdd1243dSDimitry Andric   Order.insert(V1.getOperand(0));
3542bdd1243dSDimitry Andric   Order.insert(V1.getOperand(1));
3543bdd1243dSDimitry Andric 
3544bdd1243dSDimitry Andric   if (Order.size() > 2)
3545bdd1243dSDimitry Andric     return SDValue();
3546bdd1243dSDimitry Andric 
3547bdd1243dSDimitry Andric   // In ISD::VECTOR_SHUFFLE, the types of each input and the type of the
3548bdd1243dSDimitry Andric   // result must be the same.
3549bdd1243dSDimitry Andric   EVT InpTy = V0.getValueType();
3550bdd1243dSDimitry Andric   assert(InpTy.isVector());
3551bdd1243dSDimitry Andric   unsigned InpLen = InpTy.getVectorNumElements();
3552bdd1243dSDimitry Andric 
3553bdd1243dSDimitry Andric   SmallVector<int, 128> LongMask;
3554bdd1243dSDimitry Andric   auto AppendToMask = [&](SDValue Shuffle) {
3555bdd1243dSDimitry Andric     auto *SV = cast<ShuffleVectorSDNode>(Shuffle.getNode());
3556bdd1243dSDimitry Andric     ArrayRef<int> Mask = SV->getMask();
3557bdd1243dSDimitry Andric     SDValue X = Shuffle.getOperand(0);
3558bdd1243dSDimitry Andric     SDValue Y = Shuffle.getOperand(1);
3559bdd1243dSDimitry Andric     for (int M : Mask) {
3560bdd1243dSDimitry Andric       if (M == -1) {
3561bdd1243dSDimitry Andric         LongMask.push_back(M);
3562bdd1243dSDimitry Andric         continue;
3563bdd1243dSDimitry Andric       }
3564bdd1243dSDimitry Andric       SDValue Src = static_cast<unsigned>(M) < InpLen ? X : Y;
3565bdd1243dSDimitry Andric       if (static_cast<unsigned>(M) >= InpLen)
3566bdd1243dSDimitry Andric         M -= InpLen;
3567bdd1243dSDimitry Andric 
3568bdd1243dSDimitry Andric       int OutOffset = Order[0] == Src ? 0 : InpLen;
3569bdd1243dSDimitry Andric       LongMask.push_back(M + OutOffset);
3570bdd1243dSDimitry Andric     }
3571bdd1243dSDimitry Andric   };
3572bdd1243dSDimitry Andric 
3573bdd1243dSDimitry Andric   AppendToMask(V0);
3574bdd1243dSDimitry Andric   AppendToMask(V1);
3575bdd1243dSDimitry Andric 
3576bdd1243dSDimitry Andric   SDValue C0 = Order.front();
3577bdd1243dSDimitry Andric   SDValue C1 = Order.back();  // Can be same as front
3578bdd1243dSDimitry Andric   EVT LongTy = InpTy.getDoubleNumVectorElementsVT(*DAG.getContext());
3579bdd1243dSDimitry Andric 
3580bdd1243dSDimitry Andric   SDValue Cat = DAG.getNode(ISD::CONCAT_VECTORS, dl, LongTy, {C0, C1});
3581bdd1243dSDimitry Andric   return DAG.getVectorShuffle(LongTy, dl, Cat, DAG.getUNDEF(LongTy), LongMask);
3582bdd1243dSDimitry Andric }
3583bdd1243dSDimitry Andric 
3584bdd1243dSDimitry Andric SDValue
35858bcb0991SDimitry Andric HexagonTargetLowering::PerformHvxDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
35868bcb0991SDimitry Andric       const {
35878bcb0991SDimitry Andric   const SDLoc &dl(N);
3588e8d8bef9SDimitry Andric   SelectionDAG &DAG = DCI.DAG;
35898bcb0991SDimitry Andric   SDValue Op(N, 0);
35908bcb0991SDimitry Andric   unsigned Opc = Op.getOpcode();
3591e8d8bef9SDimitry Andric 
3592e8d8bef9SDimitry Andric   SmallVector<SDValue, 4> Ops(N->ops().begin(), N->ops().end());
3593e8d8bef9SDimitry Andric 
3594bdd1243dSDimitry Andric   if (Opc == ISD::TRUNCATE)
3595bdd1243dSDimitry Andric     return combineTruncateBeforeLegal(Op, DCI);
3596bdd1243dSDimitry Andric   if (Opc == ISD::CONCAT_VECTORS)
3597bdd1243dSDimitry Andric     return combineConcatVectorsBeforeLegal(Op, DCI);
3598bdd1243dSDimitry Andric 
3599bdd1243dSDimitry Andric   if (DCI.isBeforeLegalizeOps())
3600bdd1243dSDimitry Andric     return SDValue();
3601bdd1243dSDimitry Andric 
3602e8d8bef9SDimitry Andric   switch (Opc) {
3603e8d8bef9SDimitry Andric     case ISD::VSELECT: {
36048bcb0991SDimitry Andric       // (vselect (xor x, qtrue), v0, v1) -> (vselect x, v1, v0)
3605e8d8bef9SDimitry Andric       SDValue Cond = Ops[0];
36068bcb0991SDimitry Andric       if (Cond->getOpcode() == ISD::XOR) {
36078bcb0991SDimitry Andric         SDValue C0 = Cond.getOperand(0), C1 = Cond.getOperand(1);
3608e8d8bef9SDimitry Andric         if (C1->getOpcode() == HexagonISD::QTRUE)
3609e8d8bef9SDimitry Andric           return DAG.getNode(ISD::VSELECT, dl, ty(Op), C0, Ops[2], Ops[1]);
3610e8d8bef9SDimitry Andric       }
3611e8d8bef9SDimitry Andric       break;
3612e8d8bef9SDimitry Andric     }
3613e8d8bef9SDimitry Andric     case HexagonISD::V2Q:
3614e8d8bef9SDimitry Andric       if (Ops[0].getOpcode() == ISD::SPLAT_VECTOR) {
3615e8d8bef9SDimitry Andric         if (const auto *C = dyn_cast<ConstantSDNode>(Ops[0].getOperand(0)))
3616349cc55cSDimitry Andric           return C->isZero() ? DAG.getNode(HexagonISD::QFALSE, dl, ty(Op))
3617e8d8bef9SDimitry Andric                              : DAG.getNode(HexagonISD::QTRUE, dl, ty(Op));
3618e8d8bef9SDimitry Andric       }
3619e8d8bef9SDimitry Andric       break;
3620e8d8bef9SDimitry Andric     case HexagonISD::Q2V:
3621e8d8bef9SDimitry Andric       if (Ops[0].getOpcode() == HexagonISD::QTRUE)
3622e8d8bef9SDimitry Andric         return DAG.getNode(ISD::SPLAT_VECTOR, dl, ty(Op),
3623e8d8bef9SDimitry Andric                            DAG.getConstant(-1, dl, MVT::i32));
3624e8d8bef9SDimitry Andric       if (Ops[0].getOpcode() == HexagonISD::QFALSE)
3625e8d8bef9SDimitry Andric         return getZero(dl, ty(Op), DAG);
3626e8d8bef9SDimitry Andric       break;
3627e8d8bef9SDimitry Andric     case HexagonISD::VINSERTW0:
3628e8d8bef9SDimitry Andric       if (isUndef(Ops[1]))
362906c3fb27SDimitry Andric         return Ops[0];
3630e8d8bef9SDimitry Andric       break;
3631e8d8bef9SDimitry Andric     case HexagonISD::VROR: {
3632e8d8bef9SDimitry Andric       if (Ops[0].getOpcode() == HexagonISD::VROR) {
3633e8d8bef9SDimitry Andric         SDValue Vec = Ops[0].getOperand(0);
3634e8d8bef9SDimitry Andric         SDValue Rot0 = Ops[1], Rot1 = Ops[0].getOperand(1);
3635e8d8bef9SDimitry Andric         SDValue Rot = DAG.getNode(ISD::ADD, dl, ty(Rot0), {Rot0, Rot1});
3636e8d8bef9SDimitry Andric         return DAG.getNode(HexagonISD::VROR, dl, ty(Op), {Vec, Rot});
3637e8d8bef9SDimitry Andric       }
3638e8d8bef9SDimitry Andric       break;
36398bcb0991SDimitry Andric     }
36408bcb0991SDimitry Andric   }
3641e8d8bef9SDimitry Andric 
36428bcb0991SDimitry Andric   return SDValue();
36438bcb0991SDimitry Andric }
36448bcb0991SDimitry Andric 
36450b57cec5SDimitry Andric bool
3646bdd1243dSDimitry Andric HexagonTargetLowering::shouldSplitToHvx(MVT Ty, SelectionDAG &DAG) const {
3647bdd1243dSDimitry Andric   if (Subtarget.isHVXVectorType(Ty, true))
3648bdd1243dSDimitry Andric     return false;
3649e8d8bef9SDimitry Andric   auto Action = getPreferredHvxVectorAction(Ty);
3650bdd1243dSDimitry Andric   if (Action == TargetLoweringBase::TypeSplitVector)
3651bdd1243dSDimitry Andric     return Subtarget.isHVXVectorType(typeLegalize(Ty, DAG), true);
3652bdd1243dSDimitry Andric   return false;
3653e8d8bef9SDimitry Andric }
3654bdd1243dSDimitry Andric 
3655bdd1243dSDimitry Andric bool
3656bdd1243dSDimitry Andric HexagonTargetLowering::shouldWidenToHvx(MVT Ty, SelectionDAG &DAG) const {
3657bdd1243dSDimitry Andric   if (Subtarget.isHVXVectorType(Ty, true))
3658bdd1243dSDimitry Andric     return false;
3659bdd1243dSDimitry Andric   auto Action = getPreferredHvxVectorAction(Ty);
3660bdd1243dSDimitry Andric   if (Action == TargetLoweringBase::TypeWidenVector)
3661bdd1243dSDimitry Andric     return Subtarget.isHVXVectorType(typeLegalize(Ty, DAG), true);
3662e8d8bef9SDimitry Andric   return false;
36630b57cec5SDimitry Andric }
36645ffd83dbSDimitry Andric 
36655ffd83dbSDimitry Andric bool
3666e8d8bef9SDimitry Andric HexagonTargetLowering::isHvxOperation(SDNode *N, SelectionDAG &DAG) const {
3667e8d8bef9SDimitry Andric   if (!Subtarget.useHVXOps())
3668e8d8bef9SDimitry Andric     return false;
36695ffd83dbSDimitry Andric   // If the type of any result, or any operand type are HVX vector types,
36705ffd83dbSDimitry Andric   // this is an HVX operation.
36715ffd83dbSDimitry Andric   auto IsHvxTy = [this](EVT Ty) {
36725ffd83dbSDimitry Andric     return Ty.isSimple() && Subtarget.isHVXVectorType(Ty.getSimpleVT(), true);
36735ffd83dbSDimitry Andric   };
36745ffd83dbSDimitry Andric   auto IsHvxOp = [this](SDValue Op) {
3675e8d8bef9SDimitry Andric     return Op.getValueType().isSimple() &&
3676e8d8bef9SDimitry Andric            Subtarget.isHVXVectorType(ty(Op), true);
36775ffd83dbSDimitry Andric   };
3678e8d8bef9SDimitry Andric   if (llvm::any_of(N->values(), IsHvxTy) || llvm::any_of(N->ops(), IsHvxOp))
3679e8d8bef9SDimitry Andric     return true;
3680e8d8bef9SDimitry Andric 
3681e8d8bef9SDimitry Andric   // Check if this could be an HVX operation after type widening.
3682e8d8bef9SDimitry Andric   auto IsWidenedToHvx = [this, &DAG](SDValue Op) {
3683e8d8bef9SDimitry Andric     if (!Op.getValueType().isSimple())
3684e8d8bef9SDimitry Andric       return false;
3685e8d8bef9SDimitry Andric     MVT ValTy = ty(Op);
3686e8d8bef9SDimitry Andric     return ValTy.isVector() && shouldWidenToHvx(ValTy, DAG);
3687e8d8bef9SDimitry Andric   };
3688e8d8bef9SDimitry Andric 
3689e8d8bef9SDimitry Andric   for (int i = 0, e = N->getNumValues(); i != e; ++i) {
3690e8d8bef9SDimitry Andric     if (IsWidenedToHvx(SDValue(N, i)))
3691e8d8bef9SDimitry Andric       return true;
3692e8d8bef9SDimitry Andric   }
3693e8d8bef9SDimitry Andric   return llvm::any_of(N->ops(), IsWidenedToHvx);
36945ffd83dbSDimitry Andric }
3695