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