xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Mips/MipsSEISelLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- MipsSEISelLowering.cpp - MipsSE DAG Lowering Interface -------------===//
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 // Subclass of MipsTargetLowering specialized for mips32/64.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "MipsSEISelLowering.h"
140b57cec5SDimitry Andric #include "MipsMachineFunction.h"
150b57cec5SDimitry Andric #include "MipsRegisterInfo.h"
160b57cec5SDimitry Andric #include "MipsSubtarget.h"
170b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
180b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
190b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/CallingConvLower.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/ISDOpcodes.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/ValueTypes.h"
33*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/MachineValueType.h"
340b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
350b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
36480093f4SDimitry Andric #include "llvm/IR/IntrinsicsMips.h"
370b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
380b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
390b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
400b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
410b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
420b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
4306c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
440b57cec5SDimitry Andric #include <algorithm>
450b57cec5SDimitry Andric #include <cassert>
460b57cec5SDimitry Andric #include <cstdint>
470b57cec5SDimitry Andric #include <iterator>
480b57cec5SDimitry Andric #include <utility>
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric using namespace llvm;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric #define DEBUG_TYPE "mips-isel"
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric static cl::opt<bool>
550b57cec5SDimitry Andric UseMipsTailCalls("mips-tail-calls", cl::Hidden,
560b57cec5SDimitry Andric                     cl::desc("MIPS: permit tail calls."), cl::init(false));
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric static cl::opt<bool> NoDPLoadStore("mno-ldc1-sdc1", cl::init(false),
590b57cec5SDimitry Andric                                    cl::desc("Expand double precision loads and "
600b57cec5SDimitry Andric                                             "stores to their single precision "
610b57cec5SDimitry Andric                                             "counterparts"));
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric MipsSETargetLowering::MipsSETargetLowering(const MipsTargetMachine &TM,
640b57cec5SDimitry Andric                                            const MipsSubtarget &STI)
650b57cec5SDimitry Andric     : MipsTargetLowering(TM, STI) {
660b57cec5SDimitry Andric   // Set up the register classes
670b57cec5SDimitry Andric   addRegisterClass(MVT::i32, &Mips::GPR32RegClass);
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   if (Subtarget.isGP64bit())
700b57cec5SDimitry Andric     addRegisterClass(MVT::i64, &Mips::GPR64RegClass);
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   if (Subtarget.hasDSP() || Subtarget.hasMSA()) {
730b57cec5SDimitry Andric     // Expand all truncating stores and extending loads.
748bcb0991SDimitry Andric     for (MVT VT0 : MVT::fixedlen_vector_valuetypes()) {
758bcb0991SDimitry Andric       for (MVT VT1 : MVT::fixedlen_vector_valuetypes()) {
760b57cec5SDimitry Andric         setTruncStoreAction(VT0, VT1, Expand);
770b57cec5SDimitry Andric         setLoadExtAction(ISD::SEXTLOAD, VT0, VT1, Expand);
780b57cec5SDimitry Andric         setLoadExtAction(ISD::ZEXTLOAD, VT0, VT1, Expand);
790b57cec5SDimitry Andric         setLoadExtAction(ISD::EXTLOAD, VT0, VT1, Expand);
800b57cec5SDimitry Andric       }
810b57cec5SDimitry Andric     }
820b57cec5SDimitry Andric   }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   if (Subtarget.hasDSP()) {
850b57cec5SDimitry Andric     MVT::SimpleValueType VecTys[2] = {MVT::v2i16, MVT::v4i8};
860b57cec5SDimitry Andric 
8704eeddc0SDimitry Andric     for (const auto &VecTy : VecTys) {
8804eeddc0SDimitry Andric       addRegisterClass(VecTy, &Mips::DSPRRegClass);
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric       // Expand all builtin opcodes.
910b57cec5SDimitry Andric       for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc)
9204eeddc0SDimitry Andric         setOperationAction(Opc, VecTy, Expand);
930b57cec5SDimitry Andric 
9404eeddc0SDimitry Andric       setOperationAction(ISD::ADD, VecTy, Legal);
9504eeddc0SDimitry Andric       setOperationAction(ISD::SUB, VecTy, Legal);
9604eeddc0SDimitry Andric       setOperationAction(ISD::LOAD, VecTy, Legal);
9704eeddc0SDimitry Andric       setOperationAction(ISD::STORE, VecTy, Legal);
9804eeddc0SDimitry Andric       setOperationAction(ISD::BITCAST, VecTy, Legal);
990b57cec5SDimitry Andric     }
1000b57cec5SDimitry Andric 
10181ad6265SDimitry Andric     setTargetDAGCombine(
10281ad6265SDimitry Andric         {ISD::SHL, ISD::SRA, ISD::SRL, ISD::SETCC, ISD::VSELECT});
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric     if (Subtarget.hasMips32r2()) {
1050b57cec5SDimitry Andric       setOperationAction(ISD::ADDC, MVT::i32, Legal);
1060b57cec5SDimitry Andric       setOperationAction(ISD::ADDE, MVT::i32, Legal);
1070b57cec5SDimitry Andric     }
1080b57cec5SDimitry Andric   }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   if (Subtarget.hasDSPR2())
1110b57cec5SDimitry Andric     setOperationAction(ISD::MUL, MVT::v2i16, Legal);
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   if (Subtarget.hasMSA()) {
1140b57cec5SDimitry Andric     addMSAIntType(MVT::v16i8, &Mips::MSA128BRegClass);
1150b57cec5SDimitry Andric     addMSAIntType(MVT::v8i16, &Mips::MSA128HRegClass);
1160b57cec5SDimitry Andric     addMSAIntType(MVT::v4i32, &Mips::MSA128WRegClass);
1170b57cec5SDimitry Andric     addMSAIntType(MVT::v2i64, &Mips::MSA128DRegClass);
1180b57cec5SDimitry Andric     addMSAFloatType(MVT::v8f16, &Mips::MSA128HRegClass);
1190b57cec5SDimitry Andric     addMSAFloatType(MVT::v4f32, &Mips::MSA128WRegClass);
1200b57cec5SDimitry Andric     addMSAFloatType(MVT::v2f64, &Mips::MSA128DRegClass);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     // f16 is a storage-only type, always promote it to f32.
1230b57cec5SDimitry Andric     addRegisterClass(MVT::f16, &Mips::MSA128HRegClass);
1240b57cec5SDimitry Andric     setOperationAction(ISD::SETCC, MVT::f16, Promote);
1250b57cec5SDimitry Andric     setOperationAction(ISD::BR_CC, MVT::f16, Promote);
1260b57cec5SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f16, Promote);
1270b57cec5SDimitry Andric     setOperationAction(ISD::SELECT, MVT::f16, Promote);
1280b57cec5SDimitry Andric     setOperationAction(ISD::FADD, MVT::f16, Promote);
1290b57cec5SDimitry Andric     setOperationAction(ISD::FSUB, MVT::f16, Promote);
1300b57cec5SDimitry Andric     setOperationAction(ISD::FMUL, MVT::f16, Promote);
1310b57cec5SDimitry Andric     setOperationAction(ISD::FDIV, MVT::f16, Promote);
1320b57cec5SDimitry Andric     setOperationAction(ISD::FREM, MVT::f16, Promote);
1330b57cec5SDimitry Andric     setOperationAction(ISD::FMA, MVT::f16, Promote);
1340b57cec5SDimitry Andric     setOperationAction(ISD::FNEG, MVT::f16, Promote);
1350b57cec5SDimitry Andric     setOperationAction(ISD::FABS, MVT::f16, Promote);
1360b57cec5SDimitry Andric     setOperationAction(ISD::FCEIL, MVT::f16, Promote);
1370b57cec5SDimitry Andric     setOperationAction(ISD::FCOPYSIGN, MVT::f16, Promote);
1380b57cec5SDimitry Andric     setOperationAction(ISD::FCOS, MVT::f16, Promote);
1390b57cec5SDimitry Andric     setOperationAction(ISD::FP_EXTEND, MVT::f16, Promote);
1400b57cec5SDimitry Andric     setOperationAction(ISD::FFLOOR, MVT::f16, Promote);
1410b57cec5SDimitry Andric     setOperationAction(ISD::FNEARBYINT, MVT::f16, Promote);
1420b57cec5SDimitry Andric     setOperationAction(ISD::FPOW, MVT::f16, Promote);
1430b57cec5SDimitry Andric     setOperationAction(ISD::FPOWI, MVT::f16, Promote);
1440b57cec5SDimitry Andric     setOperationAction(ISD::FRINT, MVT::f16, Promote);
1450b57cec5SDimitry Andric     setOperationAction(ISD::FSIN, MVT::f16, Promote);
1460b57cec5SDimitry Andric     setOperationAction(ISD::FSINCOS, MVT::f16, Promote);
1470b57cec5SDimitry Andric     setOperationAction(ISD::FSQRT, MVT::f16, Promote);
1480b57cec5SDimitry Andric     setOperationAction(ISD::FEXP, MVT::f16, Promote);
1490b57cec5SDimitry Andric     setOperationAction(ISD::FEXP2, MVT::f16, Promote);
1500b57cec5SDimitry Andric     setOperationAction(ISD::FLOG, MVT::f16, Promote);
1510b57cec5SDimitry Andric     setOperationAction(ISD::FLOG2, MVT::f16, Promote);
1520b57cec5SDimitry Andric     setOperationAction(ISD::FLOG10, MVT::f16, Promote);
1530b57cec5SDimitry Andric     setOperationAction(ISD::FROUND, MVT::f16, Promote);
1540b57cec5SDimitry Andric     setOperationAction(ISD::FTRUNC, MVT::f16, Promote);
1550b57cec5SDimitry Andric     setOperationAction(ISD::FMINNUM, MVT::f16, Promote);
1560b57cec5SDimitry Andric     setOperationAction(ISD::FMAXNUM, MVT::f16, Promote);
1570b57cec5SDimitry Andric     setOperationAction(ISD::FMINIMUM, MVT::f16, Promote);
1580b57cec5SDimitry Andric     setOperationAction(ISD::FMAXIMUM, MVT::f16, Promote);
1590b57cec5SDimitry Andric 
16081ad6265SDimitry Andric     setTargetDAGCombine({ISD::AND, ISD::OR, ISD::SRA, ISD::VSELECT, ISD::XOR});
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   if (!Subtarget.useSoftFloat()) {
1640b57cec5SDimitry Andric     addRegisterClass(MVT::f32, &Mips::FGR32RegClass);
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric     // When dealing with single precision only, use libcalls
1670b57cec5SDimitry Andric     if (!Subtarget.isSingleFloat()) {
1680b57cec5SDimitry Andric       if (Subtarget.isFP64bit())
1690b57cec5SDimitry Andric         addRegisterClass(MVT::f64, &Mips::FGR64RegClass);
1700b57cec5SDimitry Andric       else
1710b57cec5SDimitry Andric         addRegisterClass(MVT::f64, &Mips::AFGR64RegClass);
1720b57cec5SDimitry Andric     }
1730b57cec5SDimitry Andric   }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   setOperationAction(ISD::SMUL_LOHI,          MVT::i32, Custom);
1760b57cec5SDimitry Andric   setOperationAction(ISD::UMUL_LOHI,          MVT::i32, Custom);
1770b57cec5SDimitry Andric   setOperationAction(ISD::MULHS,              MVT::i32, Custom);
1780b57cec5SDimitry Andric   setOperationAction(ISD::MULHU,              MVT::i32, Custom);
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   if (Subtarget.hasCnMips())
1810b57cec5SDimitry Andric     setOperationAction(ISD::MUL,              MVT::i64, Legal);
1820b57cec5SDimitry Andric   else if (Subtarget.isGP64bit())
1830b57cec5SDimitry Andric     setOperationAction(ISD::MUL,              MVT::i64, Custom);
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   if (Subtarget.isGP64bit()) {
1860b57cec5SDimitry Andric     setOperationAction(ISD::SMUL_LOHI,        MVT::i64, Custom);
1870b57cec5SDimitry Andric     setOperationAction(ISD::UMUL_LOHI,        MVT::i64, Custom);
1880b57cec5SDimitry Andric     setOperationAction(ISD::MULHS,            MVT::i64, Custom);
1890b57cec5SDimitry Andric     setOperationAction(ISD::MULHU,            MVT::i64, Custom);
1900b57cec5SDimitry Andric     setOperationAction(ISD::SDIVREM,          MVT::i64, Custom);
1910b57cec5SDimitry Andric     setOperationAction(ISD::UDIVREM,          MVT::i64, Custom);
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::i64, Custom);
1950b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_W_CHAIN,  MVT::i64, Custom);
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   setOperationAction(ISD::SDIVREM, MVT::i32, Custom);
1980b57cec5SDimitry Andric   setOperationAction(ISD::UDIVREM, MVT::i32, Custom);
1990b57cec5SDimitry Andric   setOperationAction(ISD::ATOMIC_FENCE,       MVT::Other, Custom);
200*0fca6ea1SDimitry Andric   if (Subtarget.hasMips32r6()) {
201*0fca6ea1SDimitry Andric     setOperationAction(ISD::LOAD,               MVT::i32, Legal);
202*0fca6ea1SDimitry Andric     setOperationAction(ISD::STORE,              MVT::i32, Legal);
203*0fca6ea1SDimitry Andric   } else {
2040b57cec5SDimitry Andric     setOperationAction(ISD::LOAD,               MVT::i32, Custom);
2050b57cec5SDimitry Andric     setOperationAction(ISD::STORE,              MVT::i32, Custom);
206*0fca6ea1SDimitry Andric   }
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric   setTargetDAGCombine(ISD::MUL);
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
2110b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
2120b57cec5SDimitry Andric   setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   if (Subtarget.hasMips32r2() && !Subtarget.useSoftFloat() &&
2150b57cec5SDimitry Andric       !Subtarget.hasMips64()) {
2160b57cec5SDimitry Andric     setOperationAction(ISD::BITCAST, MVT::i64, Custom);
2170b57cec5SDimitry Andric   }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric   if (NoDPLoadStore) {
2200b57cec5SDimitry Andric     setOperationAction(ISD::LOAD, MVT::f64, Custom);
2210b57cec5SDimitry Andric     setOperationAction(ISD::STORE, MVT::f64, Custom);
2220b57cec5SDimitry Andric   }
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   if (Subtarget.hasMips32r6()) {
2250b57cec5SDimitry Andric     // MIPS32r6 replaces the accumulator-based multiplies with a three register
2260b57cec5SDimitry Andric     // instruction
2270b57cec5SDimitry Andric     setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
2280b57cec5SDimitry Andric     setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
2290b57cec5SDimitry Andric     setOperationAction(ISD::MUL, MVT::i32, Legal);
2300b57cec5SDimitry Andric     setOperationAction(ISD::MULHS, MVT::i32, Legal);
2310b57cec5SDimitry Andric     setOperationAction(ISD::MULHU, MVT::i32, Legal);
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric     // MIPS32r6 replaces the accumulator-based division/remainder with separate
2340b57cec5SDimitry Andric     // three register division and remainder instructions.
2350b57cec5SDimitry Andric     setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
2360b57cec5SDimitry Andric     setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
2370b57cec5SDimitry Andric     setOperationAction(ISD::SDIV, MVT::i32, Legal);
2380b57cec5SDimitry Andric     setOperationAction(ISD::UDIV, MVT::i32, Legal);
2390b57cec5SDimitry Andric     setOperationAction(ISD::SREM, MVT::i32, Legal);
2400b57cec5SDimitry Andric     setOperationAction(ISD::UREM, MVT::i32, Legal);
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric     // MIPS32r6 replaces conditional moves with an equivalent that removes the
2430b57cec5SDimitry Andric     // need for three GPR read ports.
2440b57cec5SDimitry Andric     setOperationAction(ISD::SETCC, MVT::i32, Legal);
2450b57cec5SDimitry Andric     setOperationAction(ISD::SELECT, MVT::i32, Legal);
2460b57cec5SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::i32, Expand);
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric     setOperationAction(ISD::SETCC, MVT::f32, Legal);
2490b57cec5SDimitry Andric     setOperationAction(ISD::SELECT, MVT::f32, Legal);
2500b57cec5SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric     assert(Subtarget.isFP64bit() && "FR=1 is required for MIPS32r6");
2530b57cec5SDimitry Andric     setOperationAction(ISD::SETCC, MVT::f64, Legal);
2540b57cec5SDimitry Andric     setOperationAction(ISD::SELECT, MVT::f64, Custom);
2550b57cec5SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric     setOperationAction(ISD::BRCOND, MVT::Other, Legal);
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric     // Floating point > and >= are supported via < and <=
2600b57cec5SDimitry Andric     setCondCodeAction(ISD::SETOGE, MVT::f32, Expand);
2610b57cec5SDimitry Andric     setCondCodeAction(ISD::SETOGT, MVT::f32, Expand);
2620b57cec5SDimitry Andric     setCondCodeAction(ISD::SETUGE, MVT::f32, Expand);
2630b57cec5SDimitry Andric     setCondCodeAction(ISD::SETUGT, MVT::f32, Expand);
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric     setCondCodeAction(ISD::SETOGE, MVT::f64, Expand);
2660b57cec5SDimitry Andric     setCondCodeAction(ISD::SETOGT, MVT::f64, Expand);
2670b57cec5SDimitry Andric     setCondCodeAction(ISD::SETUGE, MVT::f64, Expand);
2680b57cec5SDimitry Andric     setCondCodeAction(ISD::SETUGT, MVT::f64, Expand);
2690b57cec5SDimitry Andric   }
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric   if (Subtarget.hasMips64r6()) {
2720b57cec5SDimitry Andric     // MIPS64r6 replaces the accumulator-based multiplies with a three register
2730b57cec5SDimitry Andric     // instruction
2740b57cec5SDimitry Andric     setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand);
2750b57cec5SDimitry Andric     setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand);
2760b57cec5SDimitry Andric     setOperationAction(ISD::MUL, MVT::i64, Legal);
2770b57cec5SDimitry Andric     setOperationAction(ISD::MULHS, MVT::i64, Legal);
2780b57cec5SDimitry Andric     setOperationAction(ISD::MULHU, MVT::i64, Legal);
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric     // MIPS32r6 replaces the accumulator-based division/remainder with separate
2810b57cec5SDimitry Andric     // three register division and remainder instructions.
2820b57cec5SDimitry Andric     setOperationAction(ISD::SDIVREM, MVT::i64, Expand);
2830b57cec5SDimitry Andric     setOperationAction(ISD::UDIVREM, MVT::i64, Expand);
2840b57cec5SDimitry Andric     setOperationAction(ISD::SDIV, MVT::i64, Legal);
2850b57cec5SDimitry Andric     setOperationAction(ISD::UDIV, MVT::i64, Legal);
2860b57cec5SDimitry Andric     setOperationAction(ISD::SREM, MVT::i64, Legal);
2870b57cec5SDimitry Andric     setOperationAction(ISD::UREM, MVT::i64, Legal);
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric     // MIPS64r6 replaces conditional moves with an equivalent that removes the
2900b57cec5SDimitry Andric     // need for three GPR read ports.
2910b57cec5SDimitry Andric     setOperationAction(ISD::SETCC, MVT::i64, Legal);
2920b57cec5SDimitry Andric     setOperationAction(ISD::SELECT, MVT::i64, Legal);
2930b57cec5SDimitry Andric     setOperationAction(ISD::SELECT_CC, MVT::i64, Expand);
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric   computeRegisterProperties(Subtarget.getRegisterInfo());
2970b57cec5SDimitry Andric }
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric const MipsTargetLowering *
3000b57cec5SDimitry Andric llvm::createMipsSETargetLowering(const MipsTargetMachine &TM,
3010b57cec5SDimitry Andric                                  const MipsSubtarget &STI) {
3020b57cec5SDimitry Andric   return new MipsSETargetLowering(TM, STI);
3030b57cec5SDimitry Andric }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric const TargetRegisterClass *
3060b57cec5SDimitry Andric MipsSETargetLowering::getRepRegClassFor(MVT VT) const {
3070b57cec5SDimitry Andric   if (VT == MVT::Untyped)
3080b57cec5SDimitry Andric     return Subtarget.hasDSP() ? &Mips::ACC64DSPRegClass : &Mips::ACC64RegClass;
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   return TargetLowering::getRepRegClassFor(VT);
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric // Enable MSA support for the given integer type and Register class.
3140b57cec5SDimitry Andric void MipsSETargetLowering::
3150b57cec5SDimitry Andric addMSAIntType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) {
3160b57cec5SDimitry Andric   addRegisterClass(Ty, RC);
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   // Expand all builtin opcodes.
3190b57cec5SDimitry Andric   for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc)
3200b57cec5SDimitry Andric     setOperationAction(Opc, Ty, Expand);
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric   setOperationAction(ISD::BITCAST, Ty, Legal);
3230b57cec5SDimitry Andric   setOperationAction(ISD::LOAD, Ty, Legal);
3240b57cec5SDimitry Andric   setOperationAction(ISD::STORE, Ty, Legal);
3250b57cec5SDimitry Andric   setOperationAction(ISD::EXTRACT_VECTOR_ELT, Ty, Custom);
3260b57cec5SDimitry Andric   setOperationAction(ISD::INSERT_VECTOR_ELT, Ty, Legal);
3270b57cec5SDimitry Andric   setOperationAction(ISD::BUILD_VECTOR, Ty, Custom);
3288bcb0991SDimitry Andric   setOperationAction(ISD::UNDEF, Ty, Legal);
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric   setOperationAction(ISD::ADD, Ty, Legal);
3310b57cec5SDimitry Andric   setOperationAction(ISD::AND, Ty, Legal);
3320b57cec5SDimitry Andric   setOperationAction(ISD::CTLZ, Ty, Legal);
3330b57cec5SDimitry Andric   setOperationAction(ISD::CTPOP, Ty, Legal);
3340b57cec5SDimitry Andric   setOperationAction(ISD::MUL, Ty, Legal);
3350b57cec5SDimitry Andric   setOperationAction(ISD::OR, Ty, Legal);
3360b57cec5SDimitry Andric   setOperationAction(ISD::SDIV, Ty, Legal);
3370b57cec5SDimitry Andric   setOperationAction(ISD::SREM, Ty, Legal);
3380b57cec5SDimitry Andric   setOperationAction(ISD::SHL, Ty, Legal);
3390b57cec5SDimitry Andric   setOperationAction(ISD::SRA, Ty, Legal);
3400b57cec5SDimitry Andric   setOperationAction(ISD::SRL, Ty, Legal);
3410b57cec5SDimitry Andric   setOperationAction(ISD::SUB, Ty, Legal);
3420b57cec5SDimitry Andric   setOperationAction(ISD::SMAX, Ty, Legal);
3430b57cec5SDimitry Andric   setOperationAction(ISD::SMIN, Ty, Legal);
3440b57cec5SDimitry Andric   setOperationAction(ISD::UDIV, Ty, Legal);
3450b57cec5SDimitry Andric   setOperationAction(ISD::UREM, Ty, Legal);
3460b57cec5SDimitry Andric   setOperationAction(ISD::UMAX, Ty, Legal);
3470b57cec5SDimitry Andric   setOperationAction(ISD::UMIN, Ty, Legal);
3480b57cec5SDimitry Andric   setOperationAction(ISD::VECTOR_SHUFFLE, Ty, Custom);
3490b57cec5SDimitry Andric   setOperationAction(ISD::VSELECT, Ty, Legal);
3500b57cec5SDimitry Andric   setOperationAction(ISD::XOR, Ty, Legal);
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric   if (Ty == MVT::v4i32 || Ty == MVT::v2i64) {
3530b57cec5SDimitry Andric     setOperationAction(ISD::FP_TO_SINT, Ty, Legal);
3540b57cec5SDimitry Andric     setOperationAction(ISD::FP_TO_UINT, Ty, Legal);
3550b57cec5SDimitry Andric     setOperationAction(ISD::SINT_TO_FP, Ty, Legal);
3560b57cec5SDimitry Andric     setOperationAction(ISD::UINT_TO_FP, Ty, Legal);
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   setOperationAction(ISD::SETCC, Ty, Legal);
3600b57cec5SDimitry Andric   setCondCodeAction(ISD::SETNE, Ty, Expand);
3610b57cec5SDimitry Andric   setCondCodeAction(ISD::SETGE, Ty, Expand);
3620b57cec5SDimitry Andric   setCondCodeAction(ISD::SETGT, Ty, Expand);
3630b57cec5SDimitry Andric   setCondCodeAction(ISD::SETUGE, Ty, Expand);
3640b57cec5SDimitry Andric   setCondCodeAction(ISD::SETUGT, Ty, Expand);
3650b57cec5SDimitry Andric }
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric // Enable MSA support for the given floating-point type and Register class.
3680b57cec5SDimitry Andric void MipsSETargetLowering::
3690b57cec5SDimitry Andric addMSAFloatType(MVT::SimpleValueType Ty, const TargetRegisterClass *RC) {
3700b57cec5SDimitry Andric   addRegisterClass(Ty, RC);
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   // Expand all builtin opcodes.
3730b57cec5SDimitry Andric   for (unsigned Opc = 0; Opc < ISD::BUILTIN_OP_END; ++Opc)
3740b57cec5SDimitry Andric     setOperationAction(Opc, Ty, Expand);
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   setOperationAction(ISD::LOAD, Ty, Legal);
3770b57cec5SDimitry Andric   setOperationAction(ISD::STORE, Ty, Legal);
3780b57cec5SDimitry Andric   setOperationAction(ISD::BITCAST, Ty, Legal);
3790b57cec5SDimitry Andric   setOperationAction(ISD::EXTRACT_VECTOR_ELT, Ty, Legal);
3800b57cec5SDimitry Andric   setOperationAction(ISD::INSERT_VECTOR_ELT, Ty, Legal);
3810b57cec5SDimitry Andric   setOperationAction(ISD::BUILD_VECTOR, Ty, Custom);
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric   if (Ty != MVT::v8f16) {
3840b57cec5SDimitry Andric     setOperationAction(ISD::FABS,  Ty, Legal);
3850b57cec5SDimitry Andric     setOperationAction(ISD::FADD,  Ty, Legal);
3860b57cec5SDimitry Andric     setOperationAction(ISD::FDIV,  Ty, Legal);
3870b57cec5SDimitry Andric     setOperationAction(ISD::FEXP2, Ty, Legal);
3880b57cec5SDimitry Andric     setOperationAction(ISD::FLOG2, Ty, Legal);
3890b57cec5SDimitry Andric     setOperationAction(ISD::FMA,   Ty, Legal);
3900b57cec5SDimitry Andric     setOperationAction(ISD::FMUL,  Ty, Legal);
3910b57cec5SDimitry Andric     setOperationAction(ISD::FRINT, Ty, Legal);
3920b57cec5SDimitry Andric     setOperationAction(ISD::FSQRT, Ty, Legal);
3930b57cec5SDimitry Andric     setOperationAction(ISD::FSUB,  Ty, Legal);
3940b57cec5SDimitry Andric     setOperationAction(ISD::VSELECT, Ty, Legal);
3950b57cec5SDimitry Andric 
3960b57cec5SDimitry Andric     setOperationAction(ISD::SETCC, Ty, Legal);
3970b57cec5SDimitry Andric     setCondCodeAction(ISD::SETOGE, Ty, Expand);
3980b57cec5SDimitry Andric     setCondCodeAction(ISD::SETOGT, Ty, Expand);
3990b57cec5SDimitry Andric     setCondCodeAction(ISD::SETUGE, Ty, Expand);
4000b57cec5SDimitry Andric     setCondCodeAction(ISD::SETUGT, Ty, Expand);
4010b57cec5SDimitry Andric     setCondCodeAction(ISD::SETGE,  Ty, Expand);
4020b57cec5SDimitry Andric     setCondCodeAction(ISD::SETGT,  Ty, Expand);
4030b57cec5SDimitry Andric   }
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
4070b57cec5SDimitry Andric   if(!Subtarget.hasMips32r6())
4080b57cec5SDimitry Andric     return MipsTargetLowering::LowerOperation(Op, DAG);
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
4110b57cec5SDimitry Andric   SDLoc DL(Op);
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   // Although MTC1_D64 takes an i32 and writes an f64, the upper 32 bits of the
4140b57cec5SDimitry Andric   // floating point register are undefined. Not really an issue as sel.d, which
4150b57cec5SDimitry Andric   // is produced from an FSELECT node, only looks at bit 0.
4160b57cec5SDimitry Andric   SDValue Tmp = DAG.getNode(MipsISD::MTC1_D64, DL, MVT::f64, Op->getOperand(0));
4170b57cec5SDimitry Andric   return DAG.getNode(MipsISD::FSELECT, DL, ResTy, Tmp, Op->getOperand(1),
4180b57cec5SDimitry Andric                      Op->getOperand(2));
4190b57cec5SDimitry Andric }
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric bool MipsSETargetLowering::allowsMisalignedMemoryAccesses(
422bdd1243dSDimitry Andric     EVT VT, unsigned, Align, MachineMemOperand::Flags, unsigned *Fast) const {
4230b57cec5SDimitry Andric   MVT::SimpleValueType SVT = VT.getSimpleVT().SimpleTy;
4240b57cec5SDimitry Andric 
4250b57cec5SDimitry Andric   if (Subtarget.systemSupportsUnalignedAccess()) {
4260b57cec5SDimitry Andric     // MIPS32r6/MIPS64r6 is required to support unaligned access. It's
4270b57cec5SDimitry Andric     // implementation defined whether this is handled by hardware, software, or
4280b57cec5SDimitry Andric     // a hybrid of the two but it's expected that most implementations will
4290b57cec5SDimitry Andric     // handle the majority of cases in hardware.
4300b57cec5SDimitry Andric     if (Fast)
431bdd1243dSDimitry Andric       *Fast = 1;
4320b57cec5SDimitry Andric     return true;
433*0fca6ea1SDimitry Andric   } else if (Subtarget.hasMips32r6()) {
434*0fca6ea1SDimitry Andric     return false;
4350b57cec5SDimitry Andric   }
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   switch (SVT) {
4380b57cec5SDimitry Andric   case MVT::i64:
4390b57cec5SDimitry Andric   case MVT::i32:
4400b57cec5SDimitry Andric     if (Fast)
441bdd1243dSDimitry Andric       *Fast = 1;
4420b57cec5SDimitry Andric     return true;
4430b57cec5SDimitry Andric   default:
4440b57cec5SDimitry Andric     return false;
4450b57cec5SDimitry Andric   }
4460b57cec5SDimitry Andric }
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric SDValue MipsSETargetLowering::LowerOperation(SDValue Op,
4490b57cec5SDimitry Andric                                              SelectionDAG &DAG) const {
4500b57cec5SDimitry Andric   switch(Op.getOpcode()) {
4510b57cec5SDimitry Andric   case ISD::LOAD:  return lowerLOAD(Op, DAG);
4520b57cec5SDimitry Andric   case ISD::STORE: return lowerSTORE(Op, DAG);
4530b57cec5SDimitry Andric   case ISD::SMUL_LOHI: return lowerMulDiv(Op, MipsISD::Mult, true, true, DAG);
4540b57cec5SDimitry Andric   case ISD::UMUL_LOHI: return lowerMulDiv(Op, MipsISD::Multu, true, true, DAG);
4550b57cec5SDimitry Andric   case ISD::MULHS:     return lowerMulDiv(Op, MipsISD::Mult, false, true, DAG);
4560b57cec5SDimitry Andric   case ISD::MULHU:     return lowerMulDiv(Op, MipsISD::Multu, false, true, DAG);
4570b57cec5SDimitry Andric   case ISD::MUL:       return lowerMulDiv(Op, MipsISD::Mult, true, false, DAG);
4580b57cec5SDimitry Andric   case ISD::SDIVREM:   return lowerMulDiv(Op, MipsISD::DivRem, true, true, DAG);
4590b57cec5SDimitry Andric   case ISD::UDIVREM:   return lowerMulDiv(Op, MipsISD::DivRemU, true, true,
4600b57cec5SDimitry Andric                                           DAG);
4610b57cec5SDimitry Andric   case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG);
4620b57cec5SDimitry Andric   case ISD::INTRINSIC_W_CHAIN:  return lowerINTRINSIC_W_CHAIN(Op, DAG);
4630b57cec5SDimitry Andric   case ISD::INTRINSIC_VOID:     return lowerINTRINSIC_VOID(Op, DAG);
4640b57cec5SDimitry Andric   case ISD::EXTRACT_VECTOR_ELT: return lowerEXTRACT_VECTOR_ELT(Op, DAG);
4650b57cec5SDimitry Andric   case ISD::BUILD_VECTOR:       return lowerBUILD_VECTOR(Op, DAG);
4660b57cec5SDimitry Andric   case ISD::VECTOR_SHUFFLE:     return lowerVECTOR_SHUFFLE(Op, DAG);
4670b57cec5SDimitry Andric   case ISD::SELECT:             return lowerSELECT(Op, DAG);
4680b57cec5SDimitry Andric   case ISD::BITCAST:            return lowerBITCAST(Op, DAG);
4690b57cec5SDimitry Andric   }
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   return MipsTargetLowering::LowerOperation(Op, DAG);
4720b57cec5SDimitry Andric }
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric // Fold zero extensions into MipsISD::VEXTRACT_[SZ]EXT_ELT
4750b57cec5SDimitry Andric //
4760b57cec5SDimitry Andric // Performs the following transformations:
4770b57cec5SDimitry Andric // - Changes MipsISD::VEXTRACT_[SZ]EXT_ELT to zero extension if its
4780b57cec5SDimitry Andric //   sign/zero-extension is completely overwritten by the new one performed by
4790b57cec5SDimitry Andric //   the ISD::AND.
4800b57cec5SDimitry Andric // - Removes redundant zero extensions performed by an ISD::AND.
4810b57cec5SDimitry Andric static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG,
4820b57cec5SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
4830b57cec5SDimitry Andric                                  const MipsSubtarget &Subtarget) {
4840b57cec5SDimitry Andric   if (!Subtarget.hasMSA())
4850b57cec5SDimitry Andric     return SDValue();
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   SDValue Op0 = N->getOperand(0);
4880b57cec5SDimitry Andric   SDValue Op1 = N->getOperand(1);
4890b57cec5SDimitry Andric   unsigned Op0Opcode = Op0->getOpcode();
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric   // (and (MipsVExtract[SZ]Ext $a, $b, $c), imm:$d)
4920b57cec5SDimitry Andric   // where $d + 1 == 2^n and n == 32
4930b57cec5SDimitry Andric   // or    $d + 1 == 2^n and n <= 32 and ZExt
4940b57cec5SDimitry Andric   // -> (MipsVExtractZExt $a, $b, $c)
4950b57cec5SDimitry Andric   if (Op0Opcode == MipsISD::VEXTRACT_SEXT_ELT ||
4960b57cec5SDimitry Andric       Op0Opcode == MipsISD::VEXTRACT_ZEXT_ELT) {
4970b57cec5SDimitry Andric     ConstantSDNode *Mask = dyn_cast<ConstantSDNode>(Op1);
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric     if (!Mask)
5000b57cec5SDimitry Andric       return SDValue();
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric     int32_t Log2IfPositive = (Mask->getAPIntValue() + 1).exactLogBase2();
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric     if (Log2IfPositive <= 0)
5050b57cec5SDimitry Andric       return SDValue(); // Mask+1 is not a power of 2
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric     SDValue Op0Op2 = Op0->getOperand(2);
5080b57cec5SDimitry Andric     EVT ExtendTy = cast<VTSDNode>(Op0Op2)->getVT();
5090b57cec5SDimitry Andric     unsigned ExtendTySize = ExtendTy.getSizeInBits();
5100b57cec5SDimitry Andric     unsigned Log2 = Log2IfPositive;
5110b57cec5SDimitry Andric 
5120b57cec5SDimitry Andric     if ((Op0Opcode == MipsISD::VEXTRACT_ZEXT_ELT && Log2 >= ExtendTySize) ||
5130b57cec5SDimitry Andric         Log2 == ExtendTySize) {
5140b57cec5SDimitry Andric       SDValue Ops[] = { Op0->getOperand(0), Op0->getOperand(1), Op0Op2 };
5150b57cec5SDimitry Andric       return DAG.getNode(MipsISD::VEXTRACT_ZEXT_ELT, SDLoc(Op0),
5160b57cec5SDimitry Andric                          Op0->getVTList(),
517bdd1243dSDimitry Andric                          ArrayRef(Ops, Op0->getNumOperands()));
5180b57cec5SDimitry Andric     }
5190b57cec5SDimitry Andric   }
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric   return SDValue();
5220b57cec5SDimitry Andric }
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric // Determine if the specified node is a constant vector splat.
5250b57cec5SDimitry Andric //
5260b57cec5SDimitry Andric // Returns true and sets Imm if:
5270b57cec5SDimitry Andric // * N is a ISD::BUILD_VECTOR representing a constant splat
5280b57cec5SDimitry Andric //
5290b57cec5SDimitry Andric // This function is quite similar to MipsSEDAGToDAGISel::selectVSplat. The
5300b57cec5SDimitry Andric // differences are that it assumes the MSA has already been checked and the
5310b57cec5SDimitry Andric // arbitrary requirement for a maximum of 32-bit integers isn't applied (and
5320b57cec5SDimitry Andric // must not be in order for binsri.d to be selectable).
5330b57cec5SDimitry Andric static bool isVSplat(SDValue N, APInt &Imm, bool IsLittleEndian) {
5340b57cec5SDimitry Andric   BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N.getNode());
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric   if (!Node)
5370b57cec5SDimitry Andric     return false;
5380b57cec5SDimitry Andric 
5390b57cec5SDimitry Andric   APInt SplatValue, SplatUndef;
5400b57cec5SDimitry Andric   unsigned SplatBitSize;
5410b57cec5SDimitry Andric   bool HasAnyUndefs;
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric   if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
5440b57cec5SDimitry Andric                              8, !IsLittleEndian))
5450b57cec5SDimitry Andric     return false;
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric   Imm = SplatValue;
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric   return true;
5500b57cec5SDimitry Andric }
5510b57cec5SDimitry Andric 
5520b57cec5SDimitry Andric // Test whether the given node is an all-ones build_vector.
5530b57cec5SDimitry Andric static bool isVectorAllOnes(SDValue N) {
5540b57cec5SDimitry Andric   // Look through bitcasts. Endianness doesn't matter because we are looking
5550b57cec5SDimitry Andric   // for an all-ones value.
5560b57cec5SDimitry Andric   if (N->getOpcode() == ISD::BITCAST)
5570b57cec5SDimitry Andric     N = N->getOperand(0);
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric   BuildVectorSDNode *BVN = dyn_cast<BuildVectorSDNode>(N);
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric   if (!BVN)
5620b57cec5SDimitry Andric     return false;
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric   APInt SplatValue, SplatUndef;
5650b57cec5SDimitry Andric   unsigned SplatBitSize;
5660b57cec5SDimitry Andric   bool HasAnyUndefs;
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric   // Endianness doesn't matter in this context because we are looking for
5690b57cec5SDimitry Andric   // an all-ones value.
5700b57cec5SDimitry Andric   if (BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs))
571349cc55cSDimitry Andric     return SplatValue.isAllOnes();
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric   return false;
5740b57cec5SDimitry Andric }
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric // Test whether N is the bitwise inverse of OfNode.
5770b57cec5SDimitry Andric static bool isBitwiseInverse(SDValue N, SDValue OfNode) {
5780b57cec5SDimitry Andric   if (N->getOpcode() != ISD::XOR)
5790b57cec5SDimitry Andric     return false;
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric   if (isVectorAllOnes(N->getOperand(0)))
5820b57cec5SDimitry Andric     return N->getOperand(1) == OfNode;
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric   if (isVectorAllOnes(N->getOperand(1)))
5850b57cec5SDimitry Andric     return N->getOperand(0) == OfNode;
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric   return false;
5880b57cec5SDimitry Andric }
5890b57cec5SDimitry Andric 
5900b57cec5SDimitry Andric // Perform combines where ISD::OR is the root node.
5910b57cec5SDimitry Andric //
5920b57cec5SDimitry Andric // Performs the following transformations:
5930b57cec5SDimitry Andric // - (or (and $a, $mask), (and $b, $inv_mask)) => (vselect $mask, $a, $b)
5940b57cec5SDimitry Andric //   where $inv_mask is the bitwise inverse of $mask and the 'or' has a 128-bit
5950b57cec5SDimitry Andric //   vector type.
5960b57cec5SDimitry Andric static SDValue performORCombine(SDNode *N, SelectionDAG &DAG,
5970b57cec5SDimitry Andric                                 TargetLowering::DAGCombinerInfo &DCI,
5980b57cec5SDimitry Andric                                 const MipsSubtarget &Subtarget) {
5990b57cec5SDimitry Andric   if (!Subtarget.hasMSA())
6000b57cec5SDimitry Andric     return SDValue();
6010b57cec5SDimitry Andric 
6020b57cec5SDimitry Andric   EVT Ty = N->getValueType(0);
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric   if (!Ty.is128BitVector())
6050b57cec5SDimitry Andric     return SDValue();
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric   SDValue Op0 = N->getOperand(0);
6080b57cec5SDimitry Andric   SDValue Op1 = N->getOperand(1);
6090b57cec5SDimitry Andric 
6100b57cec5SDimitry Andric   if (Op0->getOpcode() == ISD::AND && Op1->getOpcode() == ISD::AND) {
6110b57cec5SDimitry Andric     SDValue Op0Op0 = Op0->getOperand(0);
6120b57cec5SDimitry Andric     SDValue Op0Op1 = Op0->getOperand(1);
6130b57cec5SDimitry Andric     SDValue Op1Op0 = Op1->getOperand(0);
6140b57cec5SDimitry Andric     SDValue Op1Op1 = Op1->getOperand(1);
6150b57cec5SDimitry Andric     bool IsLittleEndian = !Subtarget.isLittle();
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric     SDValue IfSet, IfClr, Cond;
6180b57cec5SDimitry Andric     bool IsConstantMask = false;
6190b57cec5SDimitry Andric     APInt Mask, InvMask;
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric     // If Op0Op0 is an appropriate mask, try to find it's inverse in either
6220b57cec5SDimitry Andric     // Op1Op0, or Op1Op1. Keep track of the Cond, IfSet, and IfClr nodes, while
6230b57cec5SDimitry Andric     // looking.
6240b57cec5SDimitry Andric     // IfClr will be set if we find a valid match.
6250b57cec5SDimitry Andric     if (isVSplat(Op0Op0, Mask, IsLittleEndian)) {
6260b57cec5SDimitry Andric       Cond = Op0Op0;
6270b57cec5SDimitry Andric       IfSet = Op0Op1;
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric       if (isVSplat(Op1Op0, InvMask, IsLittleEndian) &&
6300b57cec5SDimitry Andric           Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask)
6310b57cec5SDimitry Andric         IfClr = Op1Op1;
6320b57cec5SDimitry Andric       else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) &&
6330b57cec5SDimitry Andric                Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask)
6340b57cec5SDimitry Andric         IfClr = Op1Op0;
6350b57cec5SDimitry Andric 
6360b57cec5SDimitry Andric       IsConstantMask = true;
6370b57cec5SDimitry Andric     }
6380b57cec5SDimitry Andric 
6390b57cec5SDimitry Andric     // If IfClr is not yet set, and Op0Op1 is an appropriate mask, try the same
6400b57cec5SDimitry Andric     // thing again using this mask.
6410b57cec5SDimitry Andric     // IfClr will be set if we find a valid match.
6420b57cec5SDimitry Andric     if (!IfClr.getNode() && isVSplat(Op0Op1, Mask, IsLittleEndian)) {
6430b57cec5SDimitry Andric       Cond = Op0Op1;
6440b57cec5SDimitry Andric       IfSet = Op0Op0;
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric       if (isVSplat(Op1Op0, InvMask, IsLittleEndian) &&
6470b57cec5SDimitry Andric           Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask)
6480b57cec5SDimitry Andric         IfClr = Op1Op1;
6490b57cec5SDimitry Andric       else if (isVSplat(Op1Op1, InvMask, IsLittleEndian) &&
6500b57cec5SDimitry Andric                Mask.getBitWidth() == InvMask.getBitWidth() && Mask == ~InvMask)
6510b57cec5SDimitry Andric         IfClr = Op1Op0;
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric       IsConstantMask = true;
6540b57cec5SDimitry Andric     }
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric     // If IfClr is not yet set, try looking for a non-constant match.
6570b57cec5SDimitry Andric     // IfClr will be set if we find a valid match amongst the eight
6580b57cec5SDimitry Andric     // possibilities.
6590b57cec5SDimitry Andric     if (!IfClr.getNode()) {
6600b57cec5SDimitry Andric       if (isBitwiseInverse(Op0Op0, Op1Op0)) {
6610b57cec5SDimitry Andric         Cond = Op1Op0;
6620b57cec5SDimitry Andric         IfSet = Op1Op1;
6630b57cec5SDimitry Andric         IfClr = Op0Op1;
6640b57cec5SDimitry Andric       } else if (isBitwiseInverse(Op0Op1, Op1Op0)) {
6650b57cec5SDimitry Andric         Cond = Op1Op0;
6660b57cec5SDimitry Andric         IfSet = Op1Op1;
6670b57cec5SDimitry Andric         IfClr = Op0Op0;
6680b57cec5SDimitry Andric       } else if (isBitwiseInverse(Op0Op0, Op1Op1)) {
6690b57cec5SDimitry Andric         Cond = Op1Op1;
6700b57cec5SDimitry Andric         IfSet = Op1Op0;
6710b57cec5SDimitry Andric         IfClr = Op0Op1;
6720b57cec5SDimitry Andric       } else if (isBitwiseInverse(Op0Op1, Op1Op1)) {
6730b57cec5SDimitry Andric         Cond = Op1Op1;
6740b57cec5SDimitry Andric         IfSet = Op1Op0;
6750b57cec5SDimitry Andric         IfClr = Op0Op0;
6760b57cec5SDimitry Andric       } else if (isBitwiseInverse(Op1Op0, Op0Op0)) {
6770b57cec5SDimitry Andric         Cond = Op0Op0;
6780b57cec5SDimitry Andric         IfSet = Op0Op1;
6790b57cec5SDimitry Andric         IfClr = Op1Op1;
6800b57cec5SDimitry Andric       } else if (isBitwiseInverse(Op1Op1, Op0Op0)) {
6810b57cec5SDimitry Andric         Cond = Op0Op0;
6820b57cec5SDimitry Andric         IfSet = Op0Op1;
6830b57cec5SDimitry Andric         IfClr = Op1Op0;
6840b57cec5SDimitry Andric       } else if (isBitwiseInverse(Op1Op0, Op0Op1)) {
6850b57cec5SDimitry Andric         Cond = Op0Op1;
6860b57cec5SDimitry Andric         IfSet = Op0Op0;
6870b57cec5SDimitry Andric         IfClr = Op1Op1;
6880b57cec5SDimitry Andric       } else if (isBitwiseInverse(Op1Op1, Op0Op1)) {
6890b57cec5SDimitry Andric         Cond = Op0Op1;
6900b57cec5SDimitry Andric         IfSet = Op0Op0;
6910b57cec5SDimitry Andric         IfClr = Op1Op0;
6920b57cec5SDimitry Andric       }
6930b57cec5SDimitry Andric     }
6940b57cec5SDimitry Andric 
6950b57cec5SDimitry Andric     // At this point, IfClr will be set if we have a valid match.
6960b57cec5SDimitry Andric     if (!IfClr.getNode())
6970b57cec5SDimitry Andric       return SDValue();
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric     assert(Cond.getNode() && IfSet.getNode());
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric     // Fold degenerate cases.
7020b57cec5SDimitry Andric     if (IsConstantMask) {
703349cc55cSDimitry Andric       if (Mask.isAllOnes())
7040b57cec5SDimitry Andric         return IfSet;
7050b57cec5SDimitry Andric       else if (Mask == 0)
7060b57cec5SDimitry Andric         return IfClr;
7070b57cec5SDimitry Andric     }
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric     // Transform the DAG into an equivalent VSELECT.
7100b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, SDLoc(N), Ty, Cond, IfSet, IfClr);
7110b57cec5SDimitry Andric   }
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric   return SDValue();
7140b57cec5SDimitry Andric }
7150b57cec5SDimitry Andric 
7160b57cec5SDimitry Andric static bool shouldTransformMulToShiftsAddsSubs(APInt C, EVT VT,
7170b57cec5SDimitry Andric                                                SelectionDAG &DAG,
7180b57cec5SDimitry Andric                                                const MipsSubtarget &Subtarget) {
7190b57cec5SDimitry Andric   // Estimate the number of operations the below transform will turn a
7200b57cec5SDimitry Andric   // constant multiply into. The number is approximately equal to the minimal
7210b57cec5SDimitry Andric   // number of powers of two that constant can be broken down to by adding
7220b57cec5SDimitry Andric   // or subtracting them.
7230b57cec5SDimitry Andric   //
7240b57cec5SDimitry Andric   // If we have taken more than 12[1] / 8[2] steps to attempt the
7250b57cec5SDimitry Andric   // optimization for a native sized value, it is more than likely that this
7260b57cec5SDimitry Andric   // optimization will make things worse.
7270b57cec5SDimitry Andric   //
7280b57cec5SDimitry Andric   // [1] MIPS64 requires 6 instructions at most to materialize any constant,
7290b57cec5SDimitry Andric   //     multiplication requires at least 4 cycles, but another cycle (or two)
7300b57cec5SDimitry Andric   //     to retrieve the result from the HI/LO registers.
7310b57cec5SDimitry Andric   //
7320b57cec5SDimitry Andric   // [2] For MIPS32, more than 8 steps is expensive as the constant could be
7330b57cec5SDimitry Andric   //     materialized in 2 instructions, multiplication requires at least 4
7340b57cec5SDimitry Andric   //     cycles, but another cycle (or two) to retrieve the result from the
7350b57cec5SDimitry Andric   //     HI/LO registers.
7360b57cec5SDimitry Andric   //
7370b57cec5SDimitry Andric   // TODO:
7380b57cec5SDimitry Andric   // - MaxSteps needs to consider the `VT` of the constant for the current
7390b57cec5SDimitry Andric   //   target.
7400b57cec5SDimitry Andric   // - Consider to perform this optimization after type legalization.
7410b57cec5SDimitry Andric   //   That allows to remove a workaround for types not supported natively.
7420b57cec5SDimitry Andric   // - Take in account `-Os, -Oz` flags because this optimization
7430b57cec5SDimitry Andric   //   increases code size.
7440b57cec5SDimitry Andric   unsigned MaxSteps = Subtarget.isABI_O32() ? 8 : 12;
7450b57cec5SDimitry Andric 
7460b57cec5SDimitry Andric   SmallVector<APInt, 16> WorkStack(1, C);
7470b57cec5SDimitry Andric   unsigned Steps = 0;
7480b57cec5SDimitry Andric   unsigned BitWidth = C.getBitWidth();
7490b57cec5SDimitry Andric 
7500b57cec5SDimitry Andric   while (!WorkStack.empty()) {
7510b57cec5SDimitry Andric     APInt Val = WorkStack.pop_back_val();
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric     if (Val == 0 || Val == 1)
7540b57cec5SDimitry Andric       continue;
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric     if (Steps >= MaxSteps)
7570b57cec5SDimitry Andric       return false;
7580b57cec5SDimitry Andric 
7590b57cec5SDimitry Andric     if (Val.isPowerOf2()) {
7600b57cec5SDimitry Andric       ++Steps;
7610b57cec5SDimitry Andric       continue;
7620b57cec5SDimitry Andric     }
7630b57cec5SDimitry Andric 
7640b57cec5SDimitry Andric     APInt Floor = APInt(BitWidth, 1) << Val.logBase2();
7650b57cec5SDimitry Andric     APInt Ceil = Val.isNegative() ? APInt(BitWidth, 0)
7660b57cec5SDimitry Andric                                   : APInt(BitWidth, 1) << C.ceilLogBase2();
7670b57cec5SDimitry Andric     if ((Val - Floor).ule(Ceil - Val)) {
7680b57cec5SDimitry Andric       WorkStack.push_back(Floor);
7690b57cec5SDimitry Andric       WorkStack.push_back(Val - Floor);
7700b57cec5SDimitry Andric     } else {
7710b57cec5SDimitry Andric       WorkStack.push_back(Ceil);
7720b57cec5SDimitry Andric       WorkStack.push_back(Ceil - Val);
7730b57cec5SDimitry Andric     }
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric     ++Steps;
7760b57cec5SDimitry Andric   }
7770b57cec5SDimitry Andric 
7780b57cec5SDimitry Andric   // If the value being multiplied is not supported natively, we have to pay
7790b57cec5SDimitry Andric   // an additional legalization cost, conservatively assume an increase in the
7800b57cec5SDimitry Andric   // cost of 3 instructions per step. This values for this heuristic were
7810b57cec5SDimitry Andric   // determined experimentally.
7820b57cec5SDimitry Andric   unsigned RegisterSize = DAG.getTargetLoweringInfo()
7830b57cec5SDimitry Andric                               .getRegisterType(*DAG.getContext(), VT)
7840b57cec5SDimitry Andric                               .getSizeInBits();
7850b57cec5SDimitry Andric   Steps *= (VT.getSizeInBits() != RegisterSize) * 3;
7860b57cec5SDimitry Andric   if (Steps > 27)
7870b57cec5SDimitry Andric     return false;
7880b57cec5SDimitry Andric 
7890b57cec5SDimitry Andric   return true;
7900b57cec5SDimitry Andric }
7910b57cec5SDimitry Andric 
7920b57cec5SDimitry Andric static SDValue genConstMult(SDValue X, APInt C, const SDLoc &DL, EVT VT,
7930b57cec5SDimitry Andric                             EVT ShiftTy, SelectionDAG &DAG) {
7940b57cec5SDimitry Andric   // Return 0.
7950b57cec5SDimitry Andric   if (C == 0)
7960b57cec5SDimitry Andric     return DAG.getConstant(0, DL, VT);
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric   // Return x.
7990b57cec5SDimitry Andric   if (C == 1)
8000b57cec5SDimitry Andric     return X;
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric   // If c is power of 2, return (shl x, log2(c)).
8030b57cec5SDimitry Andric   if (C.isPowerOf2())
8040b57cec5SDimitry Andric     return DAG.getNode(ISD::SHL, DL, VT, X,
8050b57cec5SDimitry Andric                        DAG.getConstant(C.logBase2(), DL, ShiftTy));
8060b57cec5SDimitry Andric 
8070b57cec5SDimitry Andric   unsigned BitWidth = C.getBitWidth();
8080b57cec5SDimitry Andric   APInt Floor = APInt(BitWidth, 1) << C.logBase2();
8090b57cec5SDimitry Andric   APInt Ceil = C.isNegative() ? APInt(BitWidth, 0) :
8100b57cec5SDimitry Andric                                 APInt(BitWidth, 1) << C.ceilLogBase2();
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric   // If |c - floor_c| <= |c - ceil_c|,
8130b57cec5SDimitry Andric   // where floor_c = pow(2, floor(log2(c))) and ceil_c = pow(2, ceil(log2(c))),
8140b57cec5SDimitry Andric   // return (add constMult(x, floor_c), constMult(x, c - floor_c)).
8150b57cec5SDimitry Andric   if ((C - Floor).ule(Ceil - C)) {
8160b57cec5SDimitry Andric     SDValue Op0 = genConstMult(X, Floor, DL, VT, ShiftTy, DAG);
8170b57cec5SDimitry Andric     SDValue Op1 = genConstMult(X, C - Floor, DL, VT, ShiftTy, DAG);
8180b57cec5SDimitry Andric     return DAG.getNode(ISD::ADD, DL, VT, Op0, Op1);
8190b57cec5SDimitry Andric   }
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric   // If |c - floor_c| > |c - ceil_c|,
8220b57cec5SDimitry Andric   // return (sub constMult(x, ceil_c), constMult(x, ceil_c - c)).
8230b57cec5SDimitry Andric   SDValue Op0 = genConstMult(X, Ceil, DL, VT, ShiftTy, DAG);
8240b57cec5SDimitry Andric   SDValue Op1 = genConstMult(X, Ceil - C, DL, VT, ShiftTy, DAG);
8250b57cec5SDimitry Andric   return DAG.getNode(ISD::SUB, DL, VT, Op0, Op1);
8260b57cec5SDimitry Andric }
8270b57cec5SDimitry Andric 
8280b57cec5SDimitry Andric static SDValue performMULCombine(SDNode *N, SelectionDAG &DAG,
8290b57cec5SDimitry Andric                                  const TargetLowering::DAGCombinerInfo &DCI,
8300b57cec5SDimitry Andric                                  const MipsSETargetLowering *TL,
8310b57cec5SDimitry Andric                                  const MipsSubtarget &Subtarget) {
8320b57cec5SDimitry Andric   EVT VT = N->getValueType(0);
8330b57cec5SDimitry Andric 
8340b57cec5SDimitry Andric   if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1)))
8350b57cec5SDimitry Andric     if (!VT.isVector() && shouldTransformMulToShiftsAddsSubs(
8360b57cec5SDimitry Andric                               C->getAPIntValue(), VT, DAG, Subtarget))
8370b57cec5SDimitry Andric       return genConstMult(N->getOperand(0), C->getAPIntValue(), SDLoc(N), VT,
8380b57cec5SDimitry Andric                           TL->getScalarShiftAmountTy(DAG.getDataLayout(), VT),
8390b57cec5SDimitry Andric                           DAG);
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric   return SDValue(N, 0);
8420b57cec5SDimitry Andric }
8430b57cec5SDimitry Andric 
8440b57cec5SDimitry Andric static SDValue performDSPShiftCombine(unsigned Opc, SDNode *N, EVT Ty,
8450b57cec5SDimitry Andric                                       SelectionDAG &DAG,
8460b57cec5SDimitry Andric                                       const MipsSubtarget &Subtarget) {
8470b57cec5SDimitry Andric   // See if this is a vector splat immediate node.
8480b57cec5SDimitry Andric   APInt SplatValue, SplatUndef;
8490b57cec5SDimitry Andric   unsigned SplatBitSize;
8500b57cec5SDimitry Andric   bool HasAnyUndefs;
8510b57cec5SDimitry Andric   unsigned EltSize = Ty.getScalarSizeInBits();
8520b57cec5SDimitry Andric   BuildVectorSDNode *BV = dyn_cast<BuildVectorSDNode>(N->getOperand(1));
8530b57cec5SDimitry Andric 
8540b57cec5SDimitry Andric   if (!Subtarget.hasDSP())
8550b57cec5SDimitry Andric     return SDValue();
8560b57cec5SDimitry Andric 
8570b57cec5SDimitry Andric   if (!BV ||
8580b57cec5SDimitry Andric       !BV->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs,
8590b57cec5SDimitry Andric                            EltSize, !Subtarget.isLittle()) ||
8600b57cec5SDimitry Andric       (SplatBitSize != EltSize) ||
8610b57cec5SDimitry Andric       (SplatValue.getZExtValue() >= EltSize))
8620b57cec5SDimitry Andric     return SDValue();
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   SDLoc DL(N);
8650b57cec5SDimitry Andric   return DAG.getNode(Opc, DL, Ty, N->getOperand(0),
8660b57cec5SDimitry Andric                      DAG.getConstant(SplatValue.getZExtValue(), DL, MVT::i32));
8670b57cec5SDimitry Andric }
8680b57cec5SDimitry Andric 
8690b57cec5SDimitry Andric static SDValue performSHLCombine(SDNode *N, SelectionDAG &DAG,
8700b57cec5SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
8710b57cec5SDimitry Andric                                  const MipsSubtarget &Subtarget) {
8720b57cec5SDimitry Andric   EVT Ty = N->getValueType(0);
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric   if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8))
8750b57cec5SDimitry Andric     return SDValue();
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric   return performDSPShiftCombine(MipsISD::SHLL_DSP, N, Ty, DAG, Subtarget);
8780b57cec5SDimitry Andric }
8790b57cec5SDimitry Andric 
8800b57cec5SDimitry Andric // Fold sign-extensions into MipsISD::VEXTRACT_[SZ]EXT_ELT for MSA and fold
8810b57cec5SDimitry Andric // constant splats into MipsISD::SHRA_DSP for DSPr2.
8820b57cec5SDimitry Andric //
8830b57cec5SDimitry Andric // Performs the following transformations:
8840b57cec5SDimitry Andric // - Changes MipsISD::VEXTRACT_[SZ]EXT_ELT to sign extension if its
8850b57cec5SDimitry Andric //   sign/zero-extension is completely overwritten by the new one performed by
8860b57cec5SDimitry Andric //   the ISD::SRA and ISD::SHL nodes.
8870b57cec5SDimitry Andric // - Removes redundant sign extensions performed by an ISD::SRA and ISD::SHL
8880b57cec5SDimitry Andric //   sequence.
8890b57cec5SDimitry Andric //
8900b57cec5SDimitry Andric // See performDSPShiftCombine for more information about the transformation
8910b57cec5SDimitry Andric // used for DSPr2.
8920b57cec5SDimitry Andric static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG,
8930b57cec5SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
8940b57cec5SDimitry Andric                                  const MipsSubtarget &Subtarget) {
8950b57cec5SDimitry Andric   EVT Ty = N->getValueType(0);
8960b57cec5SDimitry Andric 
8970b57cec5SDimitry Andric   if (Subtarget.hasMSA()) {
8980b57cec5SDimitry Andric     SDValue Op0 = N->getOperand(0);
8990b57cec5SDimitry Andric     SDValue Op1 = N->getOperand(1);
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric     // (sra (shl (MipsVExtract[SZ]Ext $a, $b, $c), imm:$d), imm:$d)
9020b57cec5SDimitry Andric     // where $d + sizeof($c) == 32
9030b57cec5SDimitry Andric     // or    $d + sizeof($c) <= 32 and SExt
9040b57cec5SDimitry Andric     // -> (MipsVExtractSExt $a, $b, $c)
9050b57cec5SDimitry Andric     if (Op0->getOpcode() == ISD::SHL && Op1 == Op0->getOperand(1)) {
9060b57cec5SDimitry Andric       SDValue Op0Op0 = Op0->getOperand(0);
9070b57cec5SDimitry Andric       ConstantSDNode *ShAmount = dyn_cast<ConstantSDNode>(Op1);
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric       if (!ShAmount)
9100b57cec5SDimitry Andric         return SDValue();
9110b57cec5SDimitry Andric 
9120b57cec5SDimitry Andric       if (Op0Op0->getOpcode() != MipsISD::VEXTRACT_SEXT_ELT &&
9130b57cec5SDimitry Andric           Op0Op0->getOpcode() != MipsISD::VEXTRACT_ZEXT_ELT)
9140b57cec5SDimitry Andric         return SDValue();
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric       EVT ExtendTy = cast<VTSDNode>(Op0Op0->getOperand(2))->getVT();
9170b57cec5SDimitry Andric       unsigned TotalBits = ShAmount->getZExtValue() + ExtendTy.getSizeInBits();
9180b57cec5SDimitry Andric 
9190b57cec5SDimitry Andric       if (TotalBits == 32 ||
9200b57cec5SDimitry Andric           (Op0Op0->getOpcode() == MipsISD::VEXTRACT_SEXT_ELT &&
9210b57cec5SDimitry Andric            TotalBits <= 32)) {
9220b57cec5SDimitry Andric         SDValue Ops[] = { Op0Op0->getOperand(0), Op0Op0->getOperand(1),
9230b57cec5SDimitry Andric                           Op0Op0->getOperand(2) };
9240b57cec5SDimitry Andric         return DAG.getNode(MipsISD::VEXTRACT_SEXT_ELT, SDLoc(Op0Op0),
9250b57cec5SDimitry Andric                            Op0Op0->getVTList(),
926bdd1243dSDimitry Andric                            ArrayRef(Ops, Op0Op0->getNumOperands()));
9270b57cec5SDimitry Andric       }
9280b57cec5SDimitry Andric     }
9290b57cec5SDimitry Andric   }
9300b57cec5SDimitry Andric 
9310b57cec5SDimitry Andric   if ((Ty != MVT::v2i16) && ((Ty != MVT::v4i8) || !Subtarget.hasDSPR2()))
9320b57cec5SDimitry Andric     return SDValue();
9330b57cec5SDimitry Andric 
9340b57cec5SDimitry Andric   return performDSPShiftCombine(MipsISD::SHRA_DSP, N, Ty, DAG, Subtarget);
9350b57cec5SDimitry Andric }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric static SDValue performSRLCombine(SDNode *N, SelectionDAG &DAG,
9390b57cec5SDimitry Andric                                  TargetLowering::DAGCombinerInfo &DCI,
9400b57cec5SDimitry Andric                                  const MipsSubtarget &Subtarget) {
9410b57cec5SDimitry Andric   EVT Ty = N->getValueType(0);
9420b57cec5SDimitry Andric 
9430b57cec5SDimitry Andric   if (((Ty != MVT::v2i16) || !Subtarget.hasDSPR2()) && (Ty != MVT::v4i8))
9440b57cec5SDimitry Andric     return SDValue();
9450b57cec5SDimitry Andric 
9460b57cec5SDimitry Andric   return performDSPShiftCombine(MipsISD::SHRL_DSP, N, Ty, DAG, Subtarget);
9470b57cec5SDimitry Andric }
9480b57cec5SDimitry Andric 
9490b57cec5SDimitry Andric static bool isLegalDSPCondCode(EVT Ty, ISD::CondCode CC) {
9500b57cec5SDimitry Andric   bool IsV216 = (Ty == MVT::v2i16);
9510b57cec5SDimitry Andric 
9520b57cec5SDimitry Andric   switch (CC) {
9530b57cec5SDimitry Andric   case ISD::SETEQ:
9540b57cec5SDimitry Andric   case ISD::SETNE:  return true;
9550b57cec5SDimitry Andric   case ISD::SETLT:
9560b57cec5SDimitry Andric   case ISD::SETLE:
9570b57cec5SDimitry Andric   case ISD::SETGT:
9580b57cec5SDimitry Andric   case ISD::SETGE:  return IsV216;
9590b57cec5SDimitry Andric   case ISD::SETULT:
9600b57cec5SDimitry Andric   case ISD::SETULE:
9610b57cec5SDimitry Andric   case ISD::SETUGT:
9620b57cec5SDimitry Andric   case ISD::SETUGE: return !IsV216;
9630b57cec5SDimitry Andric   default:          return false;
9640b57cec5SDimitry Andric   }
9650b57cec5SDimitry Andric }
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG) {
9680b57cec5SDimitry Andric   EVT Ty = N->getValueType(0);
9690b57cec5SDimitry Andric 
9700b57cec5SDimitry Andric   if ((Ty != MVT::v2i16) && (Ty != MVT::v4i8))
9710b57cec5SDimitry Andric     return SDValue();
9720b57cec5SDimitry Andric 
9730b57cec5SDimitry Andric   if (!isLegalDSPCondCode(Ty, cast<CondCodeSDNode>(N->getOperand(2))->get()))
9740b57cec5SDimitry Andric     return SDValue();
9750b57cec5SDimitry Andric 
9760b57cec5SDimitry Andric   return DAG.getNode(MipsISD::SETCC_DSP, SDLoc(N), Ty, N->getOperand(0),
9770b57cec5SDimitry Andric                      N->getOperand(1), N->getOperand(2));
9780b57cec5SDimitry Andric }
9790b57cec5SDimitry Andric 
9800b57cec5SDimitry Andric static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) {
9810b57cec5SDimitry Andric   EVT Ty = N->getValueType(0);
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric   if (Ty == MVT::v2i16 || Ty == MVT::v4i8) {
9840b57cec5SDimitry Andric     SDValue SetCC = N->getOperand(0);
9850b57cec5SDimitry Andric 
9860b57cec5SDimitry Andric     if (SetCC.getOpcode() != MipsISD::SETCC_DSP)
9870b57cec5SDimitry Andric       return SDValue();
9880b57cec5SDimitry Andric 
9890b57cec5SDimitry Andric     return DAG.getNode(MipsISD::SELECT_CC_DSP, SDLoc(N), Ty,
9900b57cec5SDimitry Andric                        SetCC.getOperand(0), SetCC.getOperand(1),
9910b57cec5SDimitry Andric                        N->getOperand(1), N->getOperand(2), SetCC.getOperand(2));
9920b57cec5SDimitry Andric   }
9930b57cec5SDimitry Andric 
9940b57cec5SDimitry Andric   return SDValue();
9950b57cec5SDimitry Andric }
9960b57cec5SDimitry Andric 
9970b57cec5SDimitry Andric static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG,
9980b57cec5SDimitry Andric                                  const MipsSubtarget &Subtarget) {
9990b57cec5SDimitry Andric   EVT Ty = N->getValueType(0);
10000b57cec5SDimitry Andric 
10010b57cec5SDimitry Andric   if (Subtarget.hasMSA() && Ty.is128BitVector() && Ty.isInteger()) {
10020b57cec5SDimitry Andric     // Try the following combines:
10030b57cec5SDimitry Andric     //   (xor (or $a, $b), (build_vector allones))
10040b57cec5SDimitry Andric     //   (xor (or $a, $b), (bitcast (build_vector allones)))
10050b57cec5SDimitry Andric     SDValue Op0 = N->getOperand(0);
10060b57cec5SDimitry Andric     SDValue Op1 = N->getOperand(1);
10070b57cec5SDimitry Andric     SDValue NotOp;
10080b57cec5SDimitry Andric 
10090b57cec5SDimitry Andric     if (ISD::isBuildVectorAllOnes(Op0.getNode()))
10100b57cec5SDimitry Andric       NotOp = Op1;
10110b57cec5SDimitry Andric     else if (ISD::isBuildVectorAllOnes(Op1.getNode()))
10120b57cec5SDimitry Andric       NotOp = Op0;
10130b57cec5SDimitry Andric     else
10140b57cec5SDimitry Andric       return SDValue();
10150b57cec5SDimitry Andric 
10160b57cec5SDimitry Andric     if (NotOp->getOpcode() == ISD::OR)
10170b57cec5SDimitry Andric       return DAG.getNode(MipsISD::VNOR, SDLoc(N), Ty, NotOp->getOperand(0),
10180b57cec5SDimitry Andric                          NotOp->getOperand(1));
10190b57cec5SDimitry Andric   }
10200b57cec5SDimitry Andric 
10210b57cec5SDimitry Andric   return SDValue();
10220b57cec5SDimitry Andric }
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric SDValue
10250b57cec5SDimitry Andric MipsSETargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const {
10260b57cec5SDimitry Andric   SelectionDAG &DAG = DCI.DAG;
10270b57cec5SDimitry Andric   SDValue Val;
10280b57cec5SDimitry Andric 
10290b57cec5SDimitry Andric   switch (N->getOpcode()) {
10300b57cec5SDimitry Andric   case ISD::AND:
10310b57cec5SDimitry Andric     Val = performANDCombine(N, DAG, DCI, Subtarget);
10320b57cec5SDimitry Andric     break;
10330b57cec5SDimitry Andric   case ISD::OR:
10340b57cec5SDimitry Andric     Val = performORCombine(N, DAG, DCI, Subtarget);
10350b57cec5SDimitry Andric     break;
10360b57cec5SDimitry Andric   case ISD::MUL:
10370b57cec5SDimitry Andric     return performMULCombine(N, DAG, DCI, this, Subtarget);
10380b57cec5SDimitry Andric   case ISD::SHL:
10390b57cec5SDimitry Andric     Val = performSHLCombine(N, DAG, DCI, Subtarget);
10400b57cec5SDimitry Andric     break;
10410b57cec5SDimitry Andric   case ISD::SRA:
10420b57cec5SDimitry Andric     return performSRACombine(N, DAG, DCI, Subtarget);
10430b57cec5SDimitry Andric   case ISD::SRL:
10440b57cec5SDimitry Andric     return performSRLCombine(N, DAG, DCI, Subtarget);
10450b57cec5SDimitry Andric   case ISD::VSELECT:
10460b57cec5SDimitry Andric     return performVSELECTCombine(N, DAG);
10470b57cec5SDimitry Andric   case ISD::XOR:
10480b57cec5SDimitry Andric     Val = performXORCombine(N, DAG, Subtarget);
10490b57cec5SDimitry Andric     break;
10500b57cec5SDimitry Andric   case ISD::SETCC:
10510b57cec5SDimitry Andric     Val = performSETCCCombine(N, DAG);
10520b57cec5SDimitry Andric     break;
10530b57cec5SDimitry Andric   }
10540b57cec5SDimitry Andric 
10550b57cec5SDimitry Andric   if (Val.getNode()) {
10560b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\nMipsSE DAG Combine:\n";
10570b57cec5SDimitry Andric                N->printrWithDepth(dbgs(), &DAG); dbgs() << "\n=> \n";
10580b57cec5SDimitry Andric                Val.getNode()->printrWithDepth(dbgs(), &DAG); dbgs() << "\n");
10590b57cec5SDimitry Andric     return Val;
10600b57cec5SDimitry Andric   }
10610b57cec5SDimitry Andric 
10620b57cec5SDimitry Andric   return MipsTargetLowering::PerformDAGCombine(N, DCI);
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric MachineBasicBlock *
10660b57cec5SDimitry Andric MipsSETargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
10670b57cec5SDimitry Andric                                                   MachineBasicBlock *BB) const {
10680b57cec5SDimitry Andric   switch (MI.getOpcode()) {
10690b57cec5SDimitry Andric   default:
10700b57cec5SDimitry Andric     return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB);
10710b57cec5SDimitry Andric   case Mips::BPOSGE32_PSEUDO:
10720b57cec5SDimitry Andric     return emitBPOSGE32(MI, BB);
10730b57cec5SDimitry Andric   case Mips::SNZ_B_PSEUDO:
10740b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BNZ_B);
10750b57cec5SDimitry Andric   case Mips::SNZ_H_PSEUDO:
10760b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BNZ_H);
10770b57cec5SDimitry Andric   case Mips::SNZ_W_PSEUDO:
10780b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BNZ_W);
10790b57cec5SDimitry Andric   case Mips::SNZ_D_PSEUDO:
10800b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BNZ_D);
10810b57cec5SDimitry Andric   case Mips::SNZ_V_PSEUDO:
10820b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BNZ_V);
10830b57cec5SDimitry Andric   case Mips::SZ_B_PSEUDO:
10840b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BZ_B);
10850b57cec5SDimitry Andric   case Mips::SZ_H_PSEUDO:
10860b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BZ_H);
10870b57cec5SDimitry Andric   case Mips::SZ_W_PSEUDO:
10880b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BZ_W);
10890b57cec5SDimitry Andric   case Mips::SZ_D_PSEUDO:
10900b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BZ_D);
10910b57cec5SDimitry Andric   case Mips::SZ_V_PSEUDO:
10920b57cec5SDimitry Andric     return emitMSACBranchPseudo(MI, BB, Mips::BZ_V);
10930b57cec5SDimitry Andric   case Mips::COPY_FW_PSEUDO:
10940b57cec5SDimitry Andric     return emitCOPY_FW(MI, BB);
10950b57cec5SDimitry Andric   case Mips::COPY_FD_PSEUDO:
10960b57cec5SDimitry Andric     return emitCOPY_FD(MI, BB);
10970b57cec5SDimitry Andric   case Mips::INSERT_FW_PSEUDO:
10980b57cec5SDimitry Andric     return emitINSERT_FW(MI, BB);
10990b57cec5SDimitry Andric   case Mips::INSERT_FD_PSEUDO:
11000b57cec5SDimitry Andric     return emitINSERT_FD(MI, BB);
11010b57cec5SDimitry Andric   case Mips::INSERT_B_VIDX_PSEUDO:
11020b57cec5SDimitry Andric   case Mips::INSERT_B_VIDX64_PSEUDO:
11030b57cec5SDimitry Andric     return emitINSERT_DF_VIDX(MI, BB, 1, false);
11040b57cec5SDimitry Andric   case Mips::INSERT_H_VIDX_PSEUDO:
11050b57cec5SDimitry Andric   case Mips::INSERT_H_VIDX64_PSEUDO:
11060b57cec5SDimitry Andric     return emitINSERT_DF_VIDX(MI, BB, 2, false);
11070b57cec5SDimitry Andric   case Mips::INSERT_W_VIDX_PSEUDO:
11080b57cec5SDimitry Andric   case Mips::INSERT_W_VIDX64_PSEUDO:
11090b57cec5SDimitry Andric     return emitINSERT_DF_VIDX(MI, BB, 4, false);
11100b57cec5SDimitry Andric   case Mips::INSERT_D_VIDX_PSEUDO:
11110b57cec5SDimitry Andric   case Mips::INSERT_D_VIDX64_PSEUDO:
11120b57cec5SDimitry Andric     return emitINSERT_DF_VIDX(MI, BB, 8, false);
11130b57cec5SDimitry Andric   case Mips::INSERT_FW_VIDX_PSEUDO:
11140b57cec5SDimitry Andric   case Mips::INSERT_FW_VIDX64_PSEUDO:
11150b57cec5SDimitry Andric     return emitINSERT_DF_VIDX(MI, BB, 4, true);
11160b57cec5SDimitry Andric   case Mips::INSERT_FD_VIDX_PSEUDO:
11170b57cec5SDimitry Andric   case Mips::INSERT_FD_VIDX64_PSEUDO:
11180b57cec5SDimitry Andric     return emitINSERT_DF_VIDX(MI, BB, 8, true);
11190b57cec5SDimitry Andric   case Mips::FILL_FW_PSEUDO:
11200b57cec5SDimitry Andric     return emitFILL_FW(MI, BB);
11210b57cec5SDimitry Andric   case Mips::FILL_FD_PSEUDO:
11220b57cec5SDimitry Andric     return emitFILL_FD(MI, BB);
11230b57cec5SDimitry Andric   case Mips::FEXP2_W_1_PSEUDO:
11240b57cec5SDimitry Andric     return emitFEXP2_W_1(MI, BB);
11250b57cec5SDimitry Andric   case Mips::FEXP2_D_1_PSEUDO:
11260b57cec5SDimitry Andric     return emitFEXP2_D_1(MI, BB);
11270b57cec5SDimitry Andric   case Mips::ST_F16:
11280b57cec5SDimitry Andric     return emitST_F16_PSEUDO(MI, BB);
11290b57cec5SDimitry Andric   case Mips::LD_F16:
11300b57cec5SDimitry Andric     return emitLD_F16_PSEUDO(MI, BB);
11310b57cec5SDimitry Andric   case Mips::MSA_FP_EXTEND_W_PSEUDO:
11320b57cec5SDimitry Andric     return emitFPEXTEND_PSEUDO(MI, BB, false);
11330b57cec5SDimitry Andric   case Mips::MSA_FP_ROUND_W_PSEUDO:
11340b57cec5SDimitry Andric     return emitFPROUND_PSEUDO(MI, BB, false);
11350b57cec5SDimitry Andric   case Mips::MSA_FP_EXTEND_D_PSEUDO:
11360b57cec5SDimitry Andric     return emitFPEXTEND_PSEUDO(MI, BB, true);
11370b57cec5SDimitry Andric   case Mips::MSA_FP_ROUND_D_PSEUDO:
11380b57cec5SDimitry Andric     return emitFPROUND_PSEUDO(MI, BB, true);
11390b57cec5SDimitry Andric   }
11400b57cec5SDimitry Andric }
11410b57cec5SDimitry Andric 
11420b57cec5SDimitry Andric bool MipsSETargetLowering::isEligibleForTailCallOptimization(
11430b57cec5SDimitry Andric     const CCState &CCInfo, unsigned NextStackOffset,
11440b57cec5SDimitry Andric     const MipsFunctionInfo &FI) const {
11450b57cec5SDimitry Andric   if (!UseMipsTailCalls)
11460b57cec5SDimitry Andric     return false;
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric   // Exception has to be cleared with eret.
11490b57cec5SDimitry Andric   if (FI.isISR())
11500b57cec5SDimitry Andric     return false;
11510b57cec5SDimitry Andric 
11520b57cec5SDimitry Andric   // Return false if either the callee or caller has a byval argument.
11530b57cec5SDimitry Andric   if (CCInfo.getInRegsParamsCount() > 0 || FI.hasByvalArg())
11540b57cec5SDimitry Andric     return false;
11550b57cec5SDimitry Andric 
11560b57cec5SDimitry Andric   // Return true if the callee's argument area is no larger than the
11570b57cec5SDimitry Andric   // caller's.
11580b57cec5SDimitry Andric   return NextStackOffset <= FI.getIncomingArgSize();
11590b57cec5SDimitry Andric }
11600b57cec5SDimitry Andric 
11610b57cec5SDimitry Andric void MipsSETargetLowering::
11620b57cec5SDimitry Andric getOpndList(SmallVectorImpl<SDValue> &Ops,
11630b57cec5SDimitry Andric             std::deque<std::pair<unsigned, SDValue>> &RegsToPass,
11640b57cec5SDimitry Andric             bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage,
11650b57cec5SDimitry Andric             bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee,
11660b57cec5SDimitry Andric             SDValue Chain) const {
11670b57cec5SDimitry Andric   Ops.push_back(Callee);
11680b57cec5SDimitry Andric   MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal,
11690b57cec5SDimitry Andric                                   InternalLinkage, IsCallReloc, CLI, Callee,
11700b57cec5SDimitry Andric                                   Chain);
11710b57cec5SDimitry Andric }
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerLOAD(SDValue Op, SelectionDAG &DAG) const {
11740b57cec5SDimitry Andric   LoadSDNode &Nd = *cast<LoadSDNode>(Op);
11750b57cec5SDimitry Andric 
11760b57cec5SDimitry Andric   if (Nd.getMemoryVT() != MVT::f64 || !NoDPLoadStore)
11770b57cec5SDimitry Andric     return MipsTargetLowering::lowerLOAD(Op, DAG);
11780b57cec5SDimitry Andric 
11790b57cec5SDimitry Andric   // Replace a double precision load with two i32 loads and a buildpair64.
11800b57cec5SDimitry Andric   SDLoc DL(Op);
11810b57cec5SDimitry Andric   SDValue Ptr = Nd.getBasePtr(), Chain = Nd.getChain();
11820b57cec5SDimitry Andric   EVT PtrVT = Ptr.getValueType();
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric   // i32 load from lower address.
11850b57cec5SDimitry Andric   SDValue Lo = DAG.getLoad(MVT::i32, DL, Chain, Ptr, MachinePointerInfo(),
118681ad6265SDimitry Andric                            Nd.getAlign(), Nd.getMemOperand()->getFlags());
11870b57cec5SDimitry Andric 
11880b57cec5SDimitry Andric   // i32 load from higher address.
11890b57cec5SDimitry Andric   Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, DAG.getConstant(4, DL, PtrVT));
11900b57cec5SDimitry Andric   SDValue Hi = DAG.getLoad(
11910b57cec5SDimitry Andric       MVT::i32, DL, Lo.getValue(1), Ptr, MachinePointerInfo(),
119281ad6265SDimitry Andric       commonAlignment(Nd.getAlign(), 4), Nd.getMemOperand()->getFlags());
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric   if (!Subtarget.isLittle())
11950b57cec5SDimitry Andric     std::swap(Lo, Hi);
11960b57cec5SDimitry Andric 
11970b57cec5SDimitry Andric   SDValue BP = DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, Lo, Hi);
11980b57cec5SDimitry Andric   SDValue Ops[2] = {BP, Hi.getValue(1)};
11990b57cec5SDimitry Andric   return DAG.getMergeValues(Ops, DL);
12000b57cec5SDimitry Andric }
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerSTORE(SDValue Op, SelectionDAG &DAG) const {
12030b57cec5SDimitry Andric   StoreSDNode &Nd = *cast<StoreSDNode>(Op);
12040b57cec5SDimitry Andric 
12050b57cec5SDimitry Andric   if (Nd.getMemoryVT() != MVT::f64 || !NoDPLoadStore)
12060b57cec5SDimitry Andric     return MipsTargetLowering::lowerSTORE(Op, DAG);
12070b57cec5SDimitry Andric 
12080b57cec5SDimitry Andric   // Replace a double precision store with two extractelement64s and i32 stores.
12090b57cec5SDimitry Andric   SDLoc DL(Op);
12100b57cec5SDimitry Andric   SDValue Val = Nd.getValue(), Ptr = Nd.getBasePtr(), Chain = Nd.getChain();
12110b57cec5SDimitry Andric   EVT PtrVT = Ptr.getValueType();
12120b57cec5SDimitry Andric   SDValue Lo = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32,
12130b57cec5SDimitry Andric                            Val, DAG.getConstant(0, DL, MVT::i32));
12140b57cec5SDimitry Andric   SDValue Hi = DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32,
12150b57cec5SDimitry Andric                            Val, DAG.getConstant(1, DL, MVT::i32));
12160b57cec5SDimitry Andric 
12170b57cec5SDimitry Andric   if (!Subtarget.isLittle())
12180b57cec5SDimitry Andric     std::swap(Lo, Hi);
12190b57cec5SDimitry Andric 
12200b57cec5SDimitry Andric   // i32 store to lower address.
122181ad6265SDimitry Andric   Chain = DAG.getStore(Chain, DL, Lo, Ptr, MachinePointerInfo(), Nd.getAlign(),
12220b57cec5SDimitry Andric                        Nd.getMemOperand()->getFlags(), Nd.getAAInfo());
12230b57cec5SDimitry Andric 
12240b57cec5SDimitry Andric   // i32 store to higher address.
12250b57cec5SDimitry Andric   Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Ptr, DAG.getConstant(4, DL, PtrVT));
12260b57cec5SDimitry Andric   return DAG.getStore(Chain, DL, Hi, Ptr, MachinePointerInfo(),
122781ad6265SDimitry Andric                       commonAlignment(Nd.getAlign(), 4),
12280b57cec5SDimitry Andric                       Nd.getMemOperand()->getFlags(), Nd.getAAInfo());
12290b57cec5SDimitry Andric }
12300b57cec5SDimitry Andric 
12310b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerBITCAST(SDValue Op,
12320b57cec5SDimitry Andric                                            SelectionDAG &DAG) const {
12330b57cec5SDimitry Andric   SDLoc DL(Op);
12340b57cec5SDimitry Andric   MVT Src = Op.getOperand(0).getValueType().getSimpleVT();
12350b57cec5SDimitry Andric   MVT Dest = Op.getValueType().getSimpleVT();
12360b57cec5SDimitry Andric 
12370b57cec5SDimitry Andric   // Bitcast i64 to double.
12380b57cec5SDimitry Andric   if (Src == MVT::i64 && Dest == MVT::f64) {
123906c3fb27SDimitry Andric     SDValue Lo, Hi;
124006c3fb27SDimitry Andric     std::tie(Lo, Hi) =
124106c3fb27SDimitry Andric         DAG.SplitScalar(Op.getOperand(0), DL, MVT::i32, MVT::i32);
12420b57cec5SDimitry Andric     return DAG.getNode(MipsISD::BuildPairF64, DL, MVT::f64, Lo, Hi);
12430b57cec5SDimitry Andric   }
12440b57cec5SDimitry Andric 
12450b57cec5SDimitry Andric   // Bitcast double to i64.
12460b57cec5SDimitry Andric   if (Src == MVT::f64 && Dest == MVT::i64) {
12470b57cec5SDimitry Andric     SDValue Lo =
12480b57cec5SDimitry Andric         DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0),
12490b57cec5SDimitry Andric                     DAG.getConstant(0, DL, MVT::i32));
12500b57cec5SDimitry Andric     SDValue Hi =
12510b57cec5SDimitry Andric         DAG.getNode(MipsISD::ExtractElementF64, DL, MVT::i32, Op.getOperand(0),
12520b57cec5SDimitry Andric                     DAG.getConstant(1, DL, MVT::i32));
12530b57cec5SDimitry Andric     return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Lo, Hi);
12540b57cec5SDimitry Andric   }
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric   // Skip other cases of bitcast and use default lowering.
12570b57cec5SDimitry Andric   return SDValue();
12580b57cec5SDimitry Andric }
12590b57cec5SDimitry Andric 
12600b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerMulDiv(SDValue Op, unsigned NewOpc,
12610b57cec5SDimitry Andric                                           bool HasLo, bool HasHi,
12620b57cec5SDimitry Andric                                           SelectionDAG &DAG) const {
12630b57cec5SDimitry Andric   // MIPS32r6/MIPS64r6 removed accumulator based multiplies.
12640b57cec5SDimitry Andric   assert(!Subtarget.hasMips32r6());
12650b57cec5SDimitry Andric 
12660b57cec5SDimitry Andric   EVT Ty = Op.getOperand(0).getValueType();
12670b57cec5SDimitry Andric   SDLoc DL(Op);
12680b57cec5SDimitry Andric   SDValue Mult = DAG.getNode(NewOpc, DL, MVT::Untyped,
12690b57cec5SDimitry Andric                              Op.getOperand(0), Op.getOperand(1));
12700b57cec5SDimitry Andric   SDValue Lo, Hi;
12710b57cec5SDimitry Andric 
12720b57cec5SDimitry Andric   if (HasLo)
12730b57cec5SDimitry Andric     Lo = DAG.getNode(MipsISD::MFLO, DL, Ty, Mult);
12740b57cec5SDimitry Andric   if (HasHi)
12750b57cec5SDimitry Andric     Hi = DAG.getNode(MipsISD::MFHI, DL, Ty, Mult);
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric   if (!HasLo || !HasHi)
12780b57cec5SDimitry Andric     return HasLo ? Lo : Hi;
12790b57cec5SDimitry Andric 
12800b57cec5SDimitry Andric   SDValue Vals[] = { Lo, Hi };
12810b57cec5SDimitry Andric   return DAG.getMergeValues(Vals, DL);
12820b57cec5SDimitry Andric }
12830b57cec5SDimitry Andric 
12840b57cec5SDimitry Andric static SDValue initAccumulator(SDValue In, const SDLoc &DL, SelectionDAG &DAG) {
128506c3fb27SDimitry Andric   SDValue InLo, InHi;
128606c3fb27SDimitry Andric   std::tie(InLo, InHi) = DAG.SplitScalar(In, DL, MVT::i32, MVT::i32);
12870b57cec5SDimitry Andric   return DAG.getNode(MipsISD::MTLOHI, DL, MVT::Untyped, InLo, InHi);
12880b57cec5SDimitry Andric }
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric static SDValue extractLOHI(SDValue Op, const SDLoc &DL, SelectionDAG &DAG) {
12910b57cec5SDimitry Andric   SDValue Lo = DAG.getNode(MipsISD::MFLO, DL, MVT::i32, Op);
12920b57cec5SDimitry Andric   SDValue Hi = DAG.getNode(MipsISD::MFHI, DL, MVT::i32, Op);
12930b57cec5SDimitry Andric   return DAG.getNode(ISD::BUILD_PAIR, DL, MVT::i64, Lo, Hi);
12940b57cec5SDimitry Andric }
12950b57cec5SDimitry Andric 
12960b57cec5SDimitry Andric // This function expands mips intrinsic nodes which have 64-bit input operands
12970b57cec5SDimitry Andric // or output values.
12980b57cec5SDimitry Andric //
12990b57cec5SDimitry Andric // out64 = intrinsic-node in64
13000b57cec5SDimitry Andric // =>
13010b57cec5SDimitry Andric // lo = copy (extract-element (in64, 0))
13020b57cec5SDimitry Andric // hi = copy (extract-element (in64, 1))
13030b57cec5SDimitry Andric // mips-specific-node
13040b57cec5SDimitry Andric // v0 = copy lo
13050b57cec5SDimitry Andric // v1 = copy hi
13060b57cec5SDimitry Andric // out64 = merge-values (v0, v1)
13070b57cec5SDimitry Andric //
13080b57cec5SDimitry Andric static SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) {
13090b57cec5SDimitry Andric   SDLoc DL(Op);
13100b57cec5SDimitry Andric   bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other;
13110b57cec5SDimitry Andric   SmallVector<SDValue, 3> Ops;
13120b57cec5SDimitry Andric   unsigned OpNo = 0;
13130b57cec5SDimitry Andric 
13140b57cec5SDimitry Andric   // See if Op has a chain input.
13150b57cec5SDimitry Andric   if (HasChainIn)
13160b57cec5SDimitry Andric     Ops.push_back(Op->getOperand(OpNo++));
13170b57cec5SDimitry Andric 
13180b57cec5SDimitry Andric   // The next operand is the intrinsic opcode.
13190b57cec5SDimitry Andric   assert(Op->getOperand(OpNo).getOpcode() == ISD::TargetConstant);
13200b57cec5SDimitry Andric 
13210b57cec5SDimitry Andric   // See if the next operand has type i64.
13220b57cec5SDimitry Andric   SDValue Opnd = Op->getOperand(++OpNo), In64;
13230b57cec5SDimitry Andric 
13240b57cec5SDimitry Andric   if (Opnd.getValueType() == MVT::i64)
13250b57cec5SDimitry Andric     In64 = initAccumulator(Opnd, DL, DAG);
13260b57cec5SDimitry Andric   else
13270b57cec5SDimitry Andric     Ops.push_back(Opnd);
13280b57cec5SDimitry Andric 
13290b57cec5SDimitry Andric   // Push the remaining operands.
13300b57cec5SDimitry Andric   for (++OpNo ; OpNo < Op->getNumOperands(); ++OpNo)
13310b57cec5SDimitry Andric     Ops.push_back(Op->getOperand(OpNo));
13320b57cec5SDimitry Andric 
13330b57cec5SDimitry Andric   // Add In64 to the end of the list.
13340b57cec5SDimitry Andric   if (In64.getNode())
13350b57cec5SDimitry Andric     Ops.push_back(In64);
13360b57cec5SDimitry Andric 
13370b57cec5SDimitry Andric   // Scan output.
13380b57cec5SDimitry Andric   SmallVector<EVT, 2> ResTys;
13390b57cec5SDimitry Andric 
13405ffd83dbSDimitry Andric   for (EVT Ty : Op->values())
13415ffd83dbSDimitry Andric     ResTys.push_back((Ty == MVT::i64) ? MVT::Untyped : Ty);
13420b57cec5SDimitry Andric 
13430b57cec5SDimitry Andric   // Create node.
13440b57cec5SDimitry Andric   SDValue Val = DAG.getNode(Opc, DL, ResTys, Ops);
13450b57cec5SDimitry Andric   SDValue Out = (ResTys[0] == MVT::Untyped) ? extractLOHI(Val, DL, DAG) : Val;
13460b57cec5SDimitry Andric 
13470b57cec5SDimitry Andric   if (!HasChainIn)
13480b57cec5SDimitry Andric     return Out;
13490b57cec5SDimitry Andric 
13500b57cec5SDimitry Andric   assert(Val->getValueType(1) == MVT::Other);
13510b57cec5SDimitry Andric   SDValue Vals[] = { Out, SDValue(Val.getNode(), 1) };
13520b57cec5SDimitry Andric   return DAG.getMergeValues(Vals, DL);
13530b57cec5SDimitry Andric }
13540b57cec5SDimitry Andric 
13550b57cec5SDimitry Andric // Lower an MSA copy intrinsic into the specified SelectionDAG node
13560b57cec5SDimitry Andric static SDValue lowerMSACopyIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) {
13570b57cec5SDimitry Andric   SDLoc DL(Op);
13580b57cec5SDimitry Andric   SDValue Vec = Op->getOperand(1);
13590b57cec5SDimitry Andric   SDValue Idx = Op->getOperand(2);
13600b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
13610b57cec5SDimitry Andric   EVT EltTy = Vec->getValueType(0).getVectorElementType();
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric   SDValue Result = DAG.getNode(Opc, DL, ResTy, Vec, Idx,
13640b57cec5SDimitry Andric                                DAG.getValueType(EltTy));
13650b57cec5SDimitry Andric 
13660b57cec5SDimitry Andric   return Result;
13670b57cec5SDimitry Andric }
13680b57cec5SDimitry Andric 
13690b57cec5SDimitry Andric static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) {
13700b57cec5SDimitry Andric   EVT ResVecTy = Op->getValueType(0);
13710b57cec5SDimitry Andric   EVT ViaVecTy = ResVecTy;
13720b57cec5SDimitry Andric   bool BigEndian = !DAG.getSubtarget().getTargetTriple().isLittleEndian();
13730b57cec5SDimitry Andric   SDLoc DL(Op);
13740b57cec5SDimitry Andric 
13750b57cec5SDimitry Andric   // When ResVecTy == MVT::v2i64, LaneA is the upper 32 bits of the lane and
13760b57cec5SDimitry Andric   // LaneB is the lower 32-bits. Otherwise LaneA and LaneB are alternating
13770b57cec5SDimitry Andric   // lanes.
13780b57cec5SDimitry Andric   SDValue LaneA = Op->getOperand(OpNr);
13790b57cec5SDimitry Andric   SDValue LaneB;
13800b57cec5SDimitry Andric 
13810b57cec5SDimitry Andric   if (ResVecTy == MVT::v2i64) {
13820b57cec5SDimitry Andric     // In case of the index being passed as an immediate value, set the upper
13830b57cec5SDimitry Andric     // lane to 0 so that the splati.d instruction can be matched.
13840b57cec5SDimitry Andric     if (isa<ConstantSDNode>(LaneA))
13850b57cec5SDimitry Andric       LaneB = DAG.getConstant(0, DL, MVT::i32);
13860b57cec5SDimitry Andric     // Having the index passed in a register, set the upper lane to the same
13870b57cec5SDimitry Andric     // value as the lower - this results in the BUILD_VECTOR node not being
13880b57cec5SDimitry Andric     // expanded through stack. This way we are able to pattern match the set of
13890b57cec5SDimitry Andric     // nodes created here to splat.d.
13900b57cec5SDimitry Andric     else
13910b57cec5SDimitry Andric       LaneB = LaneA;
13920b57cec5SDimitry Andric     ViaVecTy = MVT::v4i32;
13930b57cec5SDimitry Andric     if(BigEndian)
13940b57cec5SDimitry Andric       std::swap(LaneA, LaneB);
13950b57cec5SDimitry Andric   } else
13960b57cec5SDimitry Andric     LaneB = LaneA;
13970b57cec5SDimitry Andric 
13980b57cec5SDimitry Andric   SDValue Ops[16] = { LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB,
13990b57cec5SDimitry Andric                       LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB };
14000b57cec5SDimitry Andric 
14010b57cec5SDimitry Andric   SDValue Result = DAG.getBuildVector(
1402bdd1243dSDimitry Andric       ViaVecTy, DL, ArrayRef(Ops, ViaVecTy.getVectorNumElements()));
14030b57cec5SDimitry Andric 
14040b57cec5SDimitry Andric   if (ViaVecTy != ResVecTy) {
14050b57cec5SDimitry Andric     SDValue One = DAG.getConstant(1, DL, ViaVecTy);
14060b57cec5SDimitry Andric     Result = DAG.getNode(ISD::BITCAST, DL, ResVecTy,
14070b57cec5SDimitry Andric                          DAG.getNode(ISD::AND, DL, ViaVecTy, Result, One));
14080b57cec5SDimitry Andric   }
14090b57cec5SDimitry Andric 
14100b57cec5SDimitry Andric   return Result;
14110b57cec5SDimitry Andric }
14120b57cec5SDimitry Andric 
14130b57cec5SDimitry Andric static SDValue lowerMSASplatImm(SDValue Op, unsigned ImmOp, SelectionDAG &DAG,
14140b57cec5SDimitry Andric                                 bool IsSigned = false) {
14150b57cec5SDimitry Andric   auto *CImm = cast<ConstantSDNode>(Op->getOperand(ImmOp));
14160b57cec5SDimitry Andric   return DAG.getConstant(
14170b57cec5SDimitry Andric       APInt(Op->getValueType(0).getScalarType().getSizeInBits(),
14180b57cec5SDimitry Andric             IsSigned ? CImm->getSExtValue() : CImm->getZExtValue(), IsSigned),
14190b57cec5SDimitry Andric       SDLoc(Op), Op->getValueType(0));
14200b57cec5SDimitry Andric }
14210b57cec5SDimitry Andric 
14220b57cec5SDimitry Andric static SDValue getBuildVectorSplat(EVT VecTy, SDValue SplatValue,
14230b57cec5SDimitry Andric                                    bool BigEndian, SelectionDAG &DAG) {
14240b57cec5SDimitry Andric   EVT ViaVecTy = VecTy;
14250b57cec5SDimitry Andric   SDValue SplatValueA = SplatValue;
14260b57cec5SDimitry Andric   SDValue SplatValueB = SplatValue;
14270b57cec5SDimitry Andric   SDLoc DL(SplatValue);
14280b57cec5SDimitry Andric 
14290b57cec5SDimitry Andric   if (VecTy == MVT::v2i64) {
14300b57cec5SDimitry Andric     // v2i64 BUILD_VECTOR must be performed via v4i32 so split into i32's.
14310b57cec5SDimitry Andric     ViaVecTy = MVT::v4i32;
14320b57cec5SDimitry Andric 
14330b57cec5SDimitry Andric     SplatValueA = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValue);
14340b57cec5SDimitry Andric     SplatValueB = DAG.getNode(ISD::SRL, DL, MVT::i64, SplatValue,
14350b57cec5SDimitry Andric                               DAG.getConstant(32, DL, MVT::i32));
14360b57cec5SDimitry Andric     SplatValueB = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValueB);
14370b57cec5SDimitry Andric   }
14380b57cec5SDimitry Andric 
14390b57cec5SDimitry Andric   // We currently hold the parts in little endian order. Swap them if
14400b57cec5SDimitry Andric   // necessary.
14410b57cec5SDimitry Andric   if (BigEndian)
14420b57cec5SDimitry Andric     std::swap(SplatValueA, SplatValueB);
14430b57cec5SDimitry Andric 
14440b57cec5SDimitry Andric   SDValue Ops[16] = { SplatValueA, SplatValueB, SplatValueA, SplatValueB,
14450b57cec5SDimitry Andric                       SplatValueA, SplatValueB, SplatValueA, SplatValueB,
14460b57cec5SDimitry Andric                       SplatValueA, SplatValueB, SplatValueA, SplatValueB,
14470b57cec5SDimitry Andric                       SplatValueA, SplatValueB, SplatValueA, SplatValueB };
14480b57cec5SDimitry Andric 
14490b57cec5SDimitry Andric   SDValue Result = DAG.getBuildVector(
1450bdd1243dSDimitry Andric       ViaVecTy, DL, ArrayRef(Ops, ViaVecTy.getVectorNumElements()));
14510b57cec5SDimitry Andric 
14520b57cec5SDimitry Andric   if (VecTy != ViaVecTy)
14530b57cec5SDimitry Andric     Result = DAG.getNode(ISD::BITCAST, DL, VecTy, Result);
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric   return Result;
14560b57cec5SDimitry Andric }
14570b57cec5SDimitry Andric 
14580b57cec5SDimitry Andric static SDValue lowerMSABinaryBitImmIntr(SDValue Op, SelectionDAG &DAG,
14590b57cec5SDimitry Andric                                         unsigned Opc, SDValue Imm,
14600b57cec5SDimitry Andric                                         bool BigEndian) {
14610b57cec5SDimitry Andric   EVT VecTy = Op->getValueType(0);
14620b57cec5SDimitry Andric   SDValue Exp2Imm;
14630b57cec5SDimitry Andric   SDLoc DL(Op);
14640b57cec5SDimitry Andric 
14650b57cec5SDimitry Andric   // The DAG Combiner can't constant fold bitcasted vectors yet so we must do it
14660b57cec5SDimitry Andric   // here for now.
14670b57cec5SDimitry Andric   if (VecTy == MVT::v2i64) {
14680b57cec5SDimitry Andric     if (ConstantSDNode *CImm = dyn_cast<ConstantSDNode>(Imm)) {
14690b57cec5SDimitry Andric       APInt BitImm = APInt(64, 1) << CImm->getAPIntValue();
14700b57cec5SDimitry Andric 
14710b57cec5SDimitry Andric       SDValue BitImmHiOp = DAG.getConstant(BitImm.lshr(32).trunc(32), DL,
14720b57cec5SDimitry Andric                                            MVT::i32);
14730b57cec5SDimitry Andric       SDValue BitImmLoOp = DAG.getConstant(BitImm.trunc(32), DL, MVT::i32);
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric       if (BigEndian)
14760b57cec5SDimitry Andric         std::swap(BitImmLoOp, BitImmHiOp);
14770b57cec5SDimitry Andric 
14780b57cec5SDimitry Andric       Exp2Imm = DAG.getNode(
14790b57cec5SDimitry Andric           ISD::BITCAST, DL, MVT::v2i64,
14800b57cec5SDimitry Andric           DAG.getBuildVector(MVT::v4i32, DL,
14810b57cec5SDimitry Andric                              {BitImmLoOp, BitImmHiOp, BitImmLoOp, BitImmHiOp}));
14820b57cec5SDimitry Andric     }
14830b57cec5SDimitry Andric   }
14840b57cec5SDimitry Andric 
14850b57cec5SDimitry Andric   if (!Exp2Imm.getNode()) {
14860b57cec5SDimitry Andric     // We couldnt constant fold, do a vector shift instead
14870b57cec5SDimitry Andric 
14880b57cec5SDimitry Andric     // Extend i32 to i64 if necessary. Sign or zero extend doesn't matter since
14890b57cec5SDimitry Andric     // only values 0-63 are valid.
14900b57cec5SDimitry Andric     if (VecTy == MVT::v2i64)
14910b57cec5SDimitry Andric       Imm = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Imm);
14920b57cec5SDimitry Andric 
14930b57cec5SDimitry Andric     Exp2Imm = getBuildVectorSplat(VecTy, Imm, BigEndian, DAG);
14940b57cec5SDimitry Andric 
14950b57cec5SDimitry Andric     Exp2Imm = DAG.getNode(ISD::SHL, DL, VecTy, DAG.getConstant(1, DL, VecTy),
14960b57cec5SDimitry Andric                           Exp2Imm);
14970b57cec5SDimitry Andric   }
14980b57cec5SDimitry Andric 
14990b57cec5SDimitry Andric   return DAG.getNode(Opc, DL, VecTy, Op->getOperand(1), Exp2Imm);
15000b57cec5SDimitry Andric }
15010b57cec5SDimitry Andric 
15020b57cec5SDimitry Andric static SDValue truncateVecElts(SDValue Op, SelectionDAG &DAG) {
15030b57cec5SDimitry Andric   SDLoc DL(Op);
15040b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
15050b57cec5SDimitry Andric   SDValue Vec = Op->getOperand(2);
15060b57cec5SDimitry Andric   bool BigEndian = !DAG.getSubtarget().getTargetTriple().isLittleEndian();
15070b57cec5SDimitry Andric   MVT ResEltTy = ResTy == MVT::v2i64 ? MVT::i64 : MVT::i32;
15080b57cec5SDimitry Andric   SDValue ConstValue = DAG.getConstant(Vec.getScalarValueSizeInBits() - 1,
15090b57cec5SDimitry Andric                                        DL, ResEltTy);
15100b57cec5SDimitry Andric   SDValue SplatVec = getBuildVectorSplat(ResTy, ConstValue, BigEndian, DAG);
15110b57cec5SDimitry Andric 
15120b57cec5SDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Vec, SplatVec);
15130b57cec5SDimitry Andric }
15140b57cec5SDimitry Andric 
15150b57cec5SDimitry Andric static SDValue lowerMSABitClear(SDValue Op, SelectionDAG &DAG) {
15160b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
15170b57cec5SDimitry Andric   SDLoc DL(Op);
15180b57cec5SDimitry Andric   SDValue One = DAG.getConstant(1, DL, ResTy);
15190b57cec5SDimitry Andric   SDValue Bit = DAG.getNode(ISD::SHL, DL, ResTy, One, truncateVecElts(Op, DAG));
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Op->getOperand(1),
15220b57cec5SDimitry Andric                      DAG.getNOT(DL, Bit, ResTy));
15230b57cec5SDimitry Andric }
15240b57cec5SDimitry Andric 
15250b57cec5SDimitry Andric static SDValue lowerMSABitClearImm(SDValue Op, SelectionDAG &DAG) {
15260b57cec5SDimitry Andric   SDLoc DL(Op);
15270b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
15280b57cec5SDimitry Andric   APInt BitImm = APInt(ResTy.getScalarSizeInBits(), 1)
1529647cbc5dSDimitry Andric                  << Op->getConstantOperandAPInt(2);
15300b57cec5SDimitry Andric   SDValue BitMask = DAG.getConstant(~BitImm, DL, ResTy);
15310b57cec5SDimitry Andric 
15320b57cec5SDimitry Andric   return DAG.getNode(ISD::AND, DL, ResTy, Op->getOperand(1), BitMask);
15330b57cec5SDimitry Andric }
15340b57cec5SDimitry Andric 
15350b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op,
15360b57cec5SDimitry Andric                                                       SelectionDAG &DAG) const {
15370b57cec5SDimitry Andric   SDLoc DL(Op);
1538647cbc5dSDimitry Andric   unsigned Intrinsic = Op->getConstantOperandVal(0);
15390b57cec5SDimitry Andric   switch (Intrinsic) {
15400b57cec5SDimitry Andric   default:
15410b57cec5SDimitry Andric     return SDValue();
15420b57cec5SDimitry Andric   case Intrinsic::mips_shilo:
15430b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::SHILO);
15440b57cec5SDimitry Andric   case Intrinsic::mips_dpau_h_qbl:
15450b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBL);
15460b57cec5SDimitry Andric   case Intrinsic::mips_dpau_h_qbr:
15470b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPAU_H_QBR);
15480b57cec5SDimitry Andric   case Intrinsic::mips_dpsu_h_qbl:
15490b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBL);
15500b57cec5SDimitry Andric   case Intrinsic::mips_dpsu_h_qbr:
15510b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPSU_H_QBR);
15520b57cec5SDimitry Andric   case Intrinsic::mips_dpa_w_ph:
15530b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPA_W_PH);
15540b57cec5SDimitry Andric   case Intrinsic::mips_dps_w_ph:
15550b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPS_W_PH);
15560b57cec5SDimitry Andric   case Intrinsic::mips_dpax_w_ph:
15570b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPAX_W_PH);
15580b57cec5SDimitry Andric   case Intrinsic::mips_dpsx_w_ph:
15590b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPSX_W_PH);
15600b57cec5SDimitry Andric   case Intrinsic::mips_mulsa_w_ph:
15610b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MULSA_W_PH);
15620b57cec5SDimitry Andric   case Intrinsic::mips_mult:
15630b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::Mult);
15640b57cec5SDimitry Andric   case Intrinsic::mips_multu:
15650b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::Multu);
15660b57cec5SDimitry Andric   case Intrinsic::mips_madd:
15670b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MAdd);
15680b57cec5SDimitry Andric   case Intrinsic::mips_maddu:
15690b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MAddu);
15700b57cec5SDimitry Andric   case Intrinsic::mips_msub:
15710b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MSub);
15720b57cec5SDimitry Andric   case Intrinsic::mips_msubu:
15730b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MSubu);
15740b57cec5SDimitry Andric   case Intrinsic::mips_addv_b:
15750b57cec5SDimitry Andric   case Intrinsic::mips_addv_h:
15760b57cec5SDimitry Andric   case Intrinsic::mips_addv_w:
15770b57cec5SDimitry Andric   case Intrinsic::mips_addv_d:
15780b57cec5SDimitry Andric     return DAG.getNode(ISD::ADD, DL, Op->getValueType(0), Op->getOperand(1),
15790b57cec5SDimitry Andric                        Op->getOperand(2));
15800b57cec5SDimitry Andric   case Intrinsic::mips_addvi_b:
15810b57cec5SDimitry Andric   case Intrinsic::mips_addvi_h:
15820b57cec5SDimitry Andric   case Intrinsic::mips_addvi_w:
15830b57cec5SDimitry Andric   case Intrinsic::mips_addvi_d:
15840b57cec5SDimitry Andric     return DAG.getNode(ISD::ADD, DL, Op->getValueType(0), Op->getOperand(1),
15850b57cec5SDimitry Andric                        lowerMSASplatImm(Op, 2, DAG));
15860b57cec5SDimitry Andric   case Intrinsic::mips_and_v:
15870b57cec5SDimitry Andric     return DAG.getNode(ISD::AND, DL, Op->getValueType(0), Op->getOperand(1),
15880b57cec5SDimitry Andric                        Op->getOperand(2));
15890b57cec5SDimitry Andric   case Intrinsic::mips_andi_b:
15900b57cec5SDimitry Andric     return DAG.getNode(ISD::AND, DL, Op->getValueType(0), Op->getOperand(1),
15910b57cec5SDimitry Andric                        lowerMSASplatImm(Op, 2, DAG));
15920b57cec5SDimitry Andric   case Intrinsic::mips_bclr_b:
15930b57cec5SDimitry Andric   case Intrinsic::mips_bclr_h:
15940b57cec5SDimitry Andric   case Intrinsic::mips_bclr_w:
15950b57cec5SDimitry Andric   case Intrinsic::mips_bclr_d:
15960b57cec5SDimitry Andric     return lowerMSABitClear(Op, DAG);
15970b57cec5SDimitry Andric   case Intrinsic::mips_bclri_b:
15980b57cec5SDimitry Andric   case Intrinsic::mips_bclri_h:
15990b57cec5SDimitry Andric   case Intrinsic::mips_bclri_w:
16000b57cec5SDimitry Andric   case Intrinsic::mips_bclri_d:
16010b57cec5SDimitry Andric     return lowerMSABitClearImm(Op, DAG);
16020b57cec5SDimitry Andric   case Intrinsic::mips_binsli_b:
16030b57cec5SDimitry Andric   case Intrinsic::mips_binsli_h:
16040b57cec5SDimitry Andric   case Intrinsic::mips_binsli_w:
16050b57cec5SDimitry Andric   case Intrinsic::mips_binsli_d: {
16060b57cec5SDimitry Andric     // binsli_x(IfClear, IfSet, nbits) -> (vselect LBitsMask, IfSet, IfClear)
16070b57cec5SDimitry Andric     EVT VecTy = Op->getValueType(0);
16080b57cec5SDimitry Andric     EVT EltTy = VecTy.getVectorElementType();
16090b57cec5SDimitry Andric     if (Op->getConstantOperandVal(3) >= EltTy.getSizeInBits())
16100b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
16110b57cec5SDimitry Andric     APInt Mask = APInt::getHighBitsSet(EltTy.getSizeInBits(),
16120b57cec5SDimitry Andric                                        Op->getConstantOperandVal(3) + 1);
16130b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, VecTy,
16140b57cec5SDimitry Andric                        DAG.getConstant(Mask, DL, VecTy, true),
16150b57cec5SDimitry Andric                        Op->getOperand(2), Op->getOperand(1));
16160b57cec5SDimitry Andric   }
16170b57cec5SDimitry Andric   case Intrinsic::mips_binsri_b:
16180b57cec5SDimitry Andric   case Intrinsic::mips_binsri_h:
16190b57cec5SDimitry Andric   case Intrinsic::mips_binsri_w:
16200b57cec5SDimitry Andric   case Intrinsic::mips_binsri_d: {
16210b57cec5SDimitry Andric     // binsri_x(IfClear, IfSet, nbits) -> (vselect RBitsMask, IfSet, IfClear)
16220b57cec5SDimitry Andric     EVT VecTy = Op->getValueType(0);
16230b57cec5SDimitry Andric     EVT EltTy = VecTy.getVectorElementType();
16240b57cec5SDimitry Andric     if (Op->getConstantOperandVal(3) >= EltTy.getSizeInBits())
16250b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
16260b57cec5SDimitry Andric     APInt Mask = APInt::getLowBitsSet(EltTy.getSizeInBits(),
16270b57cec5SDimitry Andric                                       Op->getConstantOperandVal(3) + 1);
16280b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, VecTy,
16290b57cec5SDimitry Andric                        DAG.getConstant(Mask, DL, VecTy, true),
16300b57cec5SDimitry Andric                        Op->getOperand(2), Op->getOperand(1));
16310b57cec5SDimitry Andric   }
16320b57cec5SDimitry Andric   case Intrinsic::mips_bmnz_v:
16330b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3),
16340b57cec5SDimitry Andric                        Op->getOperand(2), Op->getOperand(1));
16350b57cec5SDimitry Andric   case Intrinsic::mips_bmnzi_b:
16360b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0),
16370b57cec5SDimitry Andric                        lowerMSASplatImm(Op, 3, DAG), Op->getOperand(2),
16380b57cec5SDimitry Andric                        Op->getOperand(1));
16390b57cec5SDimitry Andric   case Intrinsic::mips_bmz_v:
16400b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0), Op->getOperand(3),
16410b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
16420b57cec5SDimitry Andric   case Intrinsic::mips_bmzi_b:
16430b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0),
16440b57cec5SDimitry Andric                        lowerMSASplatImm(Op, 3, DAG), Op->getOperand(1),
16450b57cec5SDimitry Andric                        Op->getOperand(2));
16460b57cec5SDimitry Andric   case Intrinsic::mips_bneg_b:
16470b57cec5SDimitry Andric   case Intrinsic::mips_bneg_h:
16480b57cec5SDimitry Andric   case Intrinsic::mips_bneg_w:
16490b57cec5SDimitry Andric   case Intrinsic::mips_bneg_d: {
16500b57cec5SDimitry Andric     EVT VecTy = Op->getValueType(0);
16510b57cec5SDimitry Andric     SDValue One = DAG.getConstant(1, DL, VecTy);
16520b57cec5SDimitry Andric 
16530b57cec5SDimitry Andric     return DAG.getNode(ISD::XOR, DL, VecTy, Op->getOperand(1),
16540b57cec5SDimitry Andric                        DAG.getNode(ISD::SHL, DL, VecTy, One,
16550b57cec5SDimitry Andric                                    truncateVecElts(Op, DAG)));
16560b57cec5SDimitry Andric   }
16570b57cec5SDimitry Andric   case Intrinsic::mips_bnegi_b:
16580b57cec5SDimitry Andric   case Intrinsic::mips_bnegi_h:
16590b57cec5SDimitry Andric   case Intrinsic::mips_bnegi_w:
16600b57cec5SDimitry Andric   case Intrinsic::mips_bnegi_d:
16610b57cec5SDimitry Andric     return lowerMSABinaryBitImmIntr(Op, DAG, ISD::XOR, Op->getOperand(2),
16620b57cec5SDimitry Andric                                     !Subtarget.isLittle());
16630b57cec5SDimitry Andric   case Intrinsic::mips_bnz_b:
16640b57cec5SDimitry Andric   case Intrinsic::mips_bnz_h:
16650b57cec5SDimitry Andric   case Intrinsic::mips_bnz_w:
16660b57cec5SDimitry Andric   case Intrinsic::mips_bnz_d:
16670b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VALL_NONZERO, DL, Op->getValueType(0),
16680b57cec5SDimitry Andric                        Op->getOperand(1));
16690b57cec5SDimitry Andric   case Intrinsic::mips_bnz_v:
16700b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VANY_NONZERO, DL, Op->getValueType(0),
16710b57cec5SDimitry Andric                        Op->getOperand(1));
16720b57cec5SDimitry Andric   case Intrinsic::mips_bsel_v:
16730b57cec5SDimitry Andric     // bsel_v(Mask, IfClear, IfSet) -> (vselect Mask, IfSet, IfClear)
16740b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0),
16750b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(3),
16760b57cec5SDimitry Andric                        Op->getOperand(2));
16770b57cec5SDimitry Andric   case Intrinsic::mips_bseli_b:
16780b57cec5SDimitry Andric     // bseli_v(Mask, IfClear, IfSet) -> (vselect Mask, IfSet, IfClear)
16790b57cec5SDimitry Andric     return DAG.getNode(ISD::VSELECT, DL, Op->getValueType(0),
16800b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 3, DAG),
16810b57cec5SDimitry Andric                        Op->getOperand(2));
16820b57cec5SDimitry Andric   case Intrinsic::mips_bset_b:
16830b57cec5SDimitry Andric   case Intrinsic::mips_bset_h:
16840b57cec5SDimitry Andric   case Intrinsic::mips_bset_w:
16850b57cec5SDimitry Andric   case Intrinsic::mips_bset_d: {
16860b57cec5SDimitry Andric     EVT VecTy = Op->getValueType(0);
16870b57cec5SDimitry Andric     SDValue One = DAG.getConstant(1, DL, VecTy);
16880b57cec5SDimitry Andric 
16890b57cec5SDimitry Andric     return DAG.getNode(ISD::OR, DL, VecTy, Op->getOperand(1),
16900b57cec5SDimitry Andric                        DAG.getNode(ISD::SHL, DL, VecTy, One,
16910b57cec5SDimitry Andric                                    truncateVecElts(Op, DAG)));
16920b57cec5SDimitry Andric   }
16930b57cec5SDimitry Andric   case Intrinsic::mips_bseti_b:
16940b57cec5SDimitry Andric   case Intrinsic::mips_bseti_h:
16950b57cec5SDimitry Andric   case Intrinsic::mips_bseti_w:
16960b57cec5SDimitry Andric   case Intrinsic::mips_bseti_d:
16970b57cec5SDimitry Andric     return lowerMSABinaryBitImmIntr(Op, DAG, ISD::OR, Op->getOperand(2),
16980b57cec5SDimitry Andric                                     !Subtarget.isLittle());
16990b57cec5SDimitry Andric   case Intrinsic::mips_bz_b:
17000b57cec5SDimitry Andric   case Intrinsic::mips_bz_h:
17010b57cec5SDimitry Andric   case Intrinsic::mips_bz_w:
17020b57cec5SDimitry Andric   case Intrinsic::mips_bz_d:
17030b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VALL_ZERO, DL, Op->getValueType(0),
17040b57cec5SDimitry Andric                        Op->getOperand(1));
17050b57cec5SDimitry Andric   case Intrinsic::mips_bz_v:
17060b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VANY_ZERO, DL, Op->getValueType(0),
17070b57cec5SDimitry Andric                        Op->getOperand(1));
17080b57cec5SDimitry Andric   case Intrinsic::mips_ceq_b:
17090b57cec5SDimitry Andric   case Intrinsic::mips_ceq_h:
17100b57cec5SDimitry Andric   case Intrinsic::mips_ceq_w:
17110b57cec5SDimitry Andric   case Intrinsic::mips_ceq_d:
17120b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17130b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETEQ);
17140b57cec5SDimitry Andric   case Intrinsic::mips_ceqi_b:
17150b57cec5SDimitry Andric   case Intrinsic::mips_ceqi_h:
17160b57cec5SDimitry Andric   case Intrinsic::mips_ceqi_w:
17170b57cec5SDimitry Andric   case Intrinsic::mips_ceqi_d:
17180b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17190b57cec5SDimitry Andric                         lowerMSASplatImm(Op, 2, DAG, true), ISD::SETEQ);
17200b57cec5SDimitry Andric   case Intrinsic::mips_cle_s_b:
17210b57cec5SDimitry Andric   case Intrinsic::mips_cle_s_h:
17220b57cec5SDimitry Andric   case Intrinsic::mips_cle_s_w:
17230b57cec5SDimitry Andric   case Intrinsic::mips_cle_s_d:
17240b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17250b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETLE);
17260b57cec5SDimitry Andric   case Intrinsic::mips_clei_s_b:
17270b57cec5SDimitry Andric   case Intrinsic::mips_clei_s_h:
17280b57cec5SDimitry Andric   case Intrinsic::mips_clei_s_w:
17290b57cec5SDimitry Andric   case Intrinsic::mips_clei_s_d:
17300b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17310b57cec5SDimitry Andric                         lowerMSASplatImm(Op, 2, DAG, true), ISD::SETLE);
17320b57cec5SDimitry Andric   case Intrinsic::mips_cle_u_b:
17330b57cec5SDimitry Andric   case Intrinsic::mips_cle_u_h:
17340b57cec5SDimitry Andric   case Intrinsic::mips_cle_u_w:
17350b57cec5SDimitry Andric   case Intrinsic::mips_cle_u_d:
17360b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17370b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETULE);
17380b57cec5SDimitry Andric   case Intrinsic::mips_clei_u_b:
17390b57cec5SDimitry Andric   case Intrinsic::mips_clei_u_h:
17400b57cec5SDimitry Andric   case Intrinsic::mips_clei_u_w:
17410b57cec5SDimitry Andric   case Intrinsic::mips_clei_u_d:
17420b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17430b57cec5SDimitry Andric                         lowerMSASplatImm(Op, 2, DAG), ISD::SETULE);
17440b57cec5SDimitry Andric   case Intrinsic::mips_clt_s_b:
17450b57cec5SDimitry Andric   case Intrinsic::mips_clt_s_h:
17460b57cec5SDimitry Andric   case Intrinsic::mips_clt_s_w:
17470b57cec5SDimitry Andric   case Intrinsic::mips_clt_s_d:
17480b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17490b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETLT);
17500b57cec5SDimitry Andric   case Intrinsic::mips_clti_s_b:
17510b57cec5SDimitry Andric   case Intrinsic::mips_clti_s_h:
17520b57cec5SDimitry Andric   case Intrinsic::mips_clti_s_w:
17530b57cec5SDimitry Andric   case Intrinsic::mips_clti_s_d:
17540b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17550b57cec5SDimitry Andric                         lowerMSASplatImm(Op, 2, DAG, true), ISD::SETLT);
17560b57cec5SDimitry Andric   case Intrinsic::mips_clt_u_b:
17570b57cec5SDimitry Andric   case Intrinsic::mips_clt_u_h:
17580b57cec5SDimitry Andric   case Intrinsic::mips_clt_u_w:
17590b57cec5SDimitry Andric   case Intrinsic::mips_clt_u_d:
17600b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17610b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETULT);
17620b57cec5SDimitry Andric   case Intrinsic::mips_clti_u_b:
17630b57cec5SDimitry Andric   case Intrinsic::mips_clti_u_h:
17640b57cec5SDimitry Andric   case Intrinsic::mips_clti_u_w:
17650b57cec5SDimitry Andric   case Intrinsic::mips_clti_u_d:
17660b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
17670b57cec5SDimitry Andric                         lowerMSASplatImm(Op, 2, DAG), ISD::SETULT);
17680b57cec5SDimitry Andric   case Intrinsic::mips_copy_s_b:
17690b57cec5SDimitry Andric   case Intrinsic::mips_copy_s_h:
17700b57cec5SDimitry Andric   case Intrinsic::mips_copy_s_w:
17710b57cec5SDimitry Andric     return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT);
17720b57cec5SDimitry Andric   case Intrinsic::mips_copy_s_d:
17730b57cec5SDimitry Andric     if (Subtarget.hasMips64())
17740b57cec5SDimitry Andric       // Lower directly into VEXTRACT_SEXT_ELT since i64 is legal on Mips64.
17750b57cec5SDimitry Andric       return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_SEXT_ELT);
17760b57cec5SDimitry Andric     else {
17770b57cec5SDimitry Andric       // Lower into the generic EXTRACT_VECTOR_ELT node and let the type
17780b57cec5SDimitry Andric       // legalizer and EXTRACT_VECTOR_ELT lowering sort it out.
17790b57cec5SDimitry Andric       return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(Op),
17800b57cec5SDimitry Andric                          Op->getValueType(0), Op->getOperand(1),
17810b57cec5SDimitry Andric                          Op->getOperand(2));
17820b57cec5SDimitry Andric     }
17830b57cec5SDimitry Andric   case Intrinsic::mips_copy_u_b:
17840b57cec5SDimitry Andric   case Intrinsic::mips_copy_u_h:
17850b57cec5SDimitry Andric   case Intrinsic::mips_copy_u_w:
17860b57cec5SDimitry Andric     return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT);
17870b57cec5SDimitry Andric   case Intrinsic::mips_copy_u_d:
17880b57cec5SDimitry Andric     if (Subtarget.hasMips64())
17890b57cec5SDimitry Andric       // Lower directly into VEXTRACT_ZEXT_ELT since i64 is legal on Mips64.
17900b57cec5SDimitry Andric       return lowerMSACopyIntr(Op, DAG, MipsISD::VEXTRACT_ZEXT_ELT);
17910b57cec5SDimitry Andric     else {
17920b57cec5SDimitry Andric       // Lower into the generic EXTRACT_VECTOR_ELT node and let the type
17930b57cec5SDimitry Andric       // legalizer and EXTRACT_VECTOR_ELT lowering sort it out.
17940b57cec5SDimitry Andric       // Note: When i64 is illegal, this results in copy_s.w instructions
17950b57cec5SDimitry Andric       // instead of copy_u.w instructions. This makes no difference to the
17960b57cec5SDimitry Andric       // behaviour since i64 is only illegal when the register file is 32-bit.
17970b57cec5SDimitry Andric       return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SDLoc(Op),
17980b57cec5SDimitry Andric                          Op->getValueType(0), Op->getOperand(1),
17990b57cec5SDimitry Andric                          Op->getOperand(2));
18000b57cec5SDimitry Andric     }
18010b57cec5SDimitry Andric   case Intrinsic::mips_div_s_b:
18020b57cec5SDimitry Andric   case Intrinsic::mips_div_s_h:
18030b57cec5SDimitry Andric   case Intrinsic::mips_div_s_w:
18040b57cec5SDimitry Andric   case Intrinsic::mips_div_s_d:
18050b57cec5SDimitry Andric     return DAG.getNode(ISD::SDIV, DL, Op->getValueType(0), Op->getOperand(1),
18060b57cec5SDimitry Andric                        Op->getOperand(2));
18070b57cec5SDimitry Andric   case Intrinsic::mips_div_u_b:
18080b57cec5SDimitry Andric   case Intrinsic::mips_div_u_h:
18090b57cec5SDimitry Andric   case Intrinsic::mips_div_u_w:
18100b57cec5SDimitry Andric   case Intrinsic::mips_div_u_d:
18110b57cec5SDimitry Andric     return DAG.getNode(ISD::UDIV, DL, Op->getValueType(0), Op->getOperand(1),
18120b57cec5SDimitry Andric                        Op->getOperand(2));
18130b57cec5SDimitry Andric   case Intrinsic::mips_fadd_w:
18140b57cec5SDimitry Andric   case Intrinsic::mips_fadd_d:
18150b57cec5SDimitry Andric     // TODO: If intrinsics have fast-math-flags, propagate them.
18160b57cec5SDimitry Andric     return DAG.getNode(ISD::FADD, DL, Op->getValueType(0), Op->getOperand(1),
18170b57cec5SDimitry Andric                        Op->getOperand(2));
18180b57cec5SDimitry Andric   // Don't lower mips_fcaf_[wd] since LLVM folds SETFALSE condcodes away
18190b57cec5SDimitry Andric   case Intrinsic::mips_fceq_w:
18200b57cec5SDimitry Andric   case Intrinsic::mips_fceq_d:
18210b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18220b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETOEQ);
18230b57cec5SDimitry Andric   case Intrinsic::mips_fcle_w:
18240b57cec5SDimitry Andric   case Intrinsic::mips_fcle_d:
18250b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18260b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETOLE);
18270b57cec5SDimitry Andric   case Intrinsic::mips_fclt_w:
18280b57cec5SDimitry Andric   case Intrinsic::mips_fclt_d:
18290b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18300b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETOLT);
18310b57cec5SDimitry Andric   case Intrinsic::mips_fcne_w:
18320b57cec5SDimitry Andric   case Intrinsic::mips_fcne_d:
18330b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18340b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETONE);
18350b57cec5SDimitry Andric   case Intrinsic::mips_fcor_w:
18360b57cec5SDimitry Andric   case Intrinsic::mips_fcor_d:
18370b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18380b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETO);
18390b57cec5SDimitry Andric   case Intrinsic::mips_fcueq_w:
18400b57cec5SDimitry Andric   case Intrinsic::mips_fcueq_d:
18410b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18420b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETUEQ);
18430b57cec5SDimitry Andric   case Intrinsic::mips_fcule_w:
18440b57cec5SDimitry Andric   case Intrinsic::mips_fcule_d:
18450b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18460b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETULE);
18470b57cec5SDimitry Andric   case Intrinsic::mips_fcult_w:
18480b57cec5SDimitry Andric   case Intrinsic::mips_fcult_d:
18490b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18500b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETULT);
18510b57cec5SDimitry Andric   case Intrinsic::mips_fcun_w:
18520b57cec5SDimitry Andric   case Intrinsic::mips_fcun_d:
18530b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18540b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETUO);
18550b57cec5SDimitry Andric   case Intrinsic::mips_fcune_w:
18560b57cec5SDimitry Andric   case Intrinsic::mips_fcune_d:
18570b57cec5SDimitry Andric     return DAG.getSetCC(DL, Op->getValueType(0), Op->getOperand(1),
18580b57cec5SDimitry Andric                         Op->getOperand(2), ISD::SETUNE);
18590b57cec5SDimitry Andric   case Intrinsic::mips_fdiv_w:
18600b57cec5SDimitry Andric   case Intrinsic::mips_fdiv_d:
18610b57cec5SDimitry Andric     // TODO: If intrinsics have fast-math-flags, propagate them.
18620b57cec5SDimitry Andric     return DAG.getNode(ISD::FDIV, DL, Op->getValueType(0), Op->getOperand(1),
18630b57cec5SDimitry Andric                        Op->getOperand(2));
18640b57cec5SDimitry Andric   case Intrinsic::mips_ffint_u_w:
18650b57cec5SDimitry Andric   case Intrinsic::mips_ffint_u_d:
18660b57cec5SDimitry Andric     return DAG.getNode(ISD::UINT_TO_FP, DL, Op->getValueType(0),
18670b57cec5SDimitry Andric                        Op->getOperand(1));
18680b57cec5SDimitry Andric   case Intrinsic::mips_ffint_s_w:
18690b57cec5SDimitry Andric   case Intrinsic::mips_ffint_s_d:
18700b57cec5SDimitry Andric     return DAG.getNode(ISD::SINT_TO_FP, DL, Op->getValueType(0),
18710b57cec5SDimitry Andric                        Op->getOperand(1));
18720b57cec5SDimitry Andric   case Intrinsic::mips_fill_b:
18730b57cec5SDimitry Andric   case Intrinsic::mips_fill_h:
18740b57cec5SDimitry Andric   case Intrinsic::mips_fill_w:
18750b57cec5SDimitry Andric   case Intrinsic::mips_fill_d: {
18760b57cec5SDimitry Andric     EVT ResTy = Op->getValueType(0);
18770b57cec5SDimitry Andric     SmallVector<SDValue, 16> Ops(ResTy.getVectorNumElements(),
18780b57cec5SDimitry Andric                                  Op->getOperand(1));
18790b57cec5SDimitry Andric 
18800b57cec5SDimitry Andric     // If ResTy is v2i64 then the type legalizer will break this node down into
18810b57cec5SDimitry Andric     // an equivalent v4i32.
18820b57cec5SDimitry Andric     return DAG.getBuildVector(ResTy, DL, Ops);
18830b57cec5SDimitry Andric   }
18840b57cec5SDimitry Andric   case Intrinsic::mips_fexp2_w:
18850b57cec5SDimitry Andric   case Intrinsic::mips_fexp2_d: {
18860b57cec5SDimitry Andric     // TODO: If intrinsics have fast-math-flags, propagate them.
18870b57cec5SDimitry Andric     EVT ResTy = Op->getValueType(0);
18880b57cec5SDimitry Andric     return DAG.getNode(
18890b57cec5SDimitry Andric         ISD::FMUL, SDLoc(Op), ResTy, Op->getOperand(1),
18900b57cec5SDimitry Andric         DAG.getNode(ISD::FEXP2, SDLoc(Op), ResTy, Op->getOperand(2)));
18910b57cec5SDimitry Andric   }
18920b57cec5SDimitry Andric   case Intrinsic::mips_flog2_w:
18930b57cec5SDimitry Andric   case Intrinsic::mips_flog2_d:
18940b57cec5SDimitry Andric     return DAG.getNode(ISD::FLOG2, DL, Op->getValueType(0), Op->getOperand(1));
18950b57cec5SDimitry Andric   case Intrinsic::mips_fmadd_w:
18960b57cec5SDimitry Andric   case Intrinsic::mips_fmadd_d:
18970b57cec5SDimitry Andric     return DAG.getNode(ISD::FMA, SDLoc(Op), Op->getValueType(0),
18980b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2), Op->getOperand(3));
18990b57cec5SDimitry Andric   case Intrinsic::mips_fmul_w:
19000b57cec5SDimitry Andric   case Intrinsic::mips_fmul_d:
19010b57cec5SDimitry Andric     // TODO: If intrinsics have fast-math-flags, propagate them.
19020b57cec5SDimitry Andric     return DAG.getNode(ISD::FMUL, DL, Op->getValueType(0), Op->getOperand(1),
19030b57cec5SDimitry Andric                        Op->getOperand(2));
19040b57cec5SDimitry Andric   case Intrinsic::mips_fmsub_w:
19050b57cec5SDimitry Andric   case Intrinsic::mips_fmsub_d: {
19060b57cec5SDimitry Andric     // TODO: If intrinsics have fast-math-flags, propagate them.
19070b57cec5SDimitry Andric     return DAG.getNode(MipsISD::FMS, SDLoc(Op), Op->getValueType(0),
19080b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2), Op->getOperand(3));
19090b57cec5SDimitry Andric   }
19100b57cec5SDimitry Andric   case Intrinsic::mips_frint_w:
19110b57cec5SDimitry Andric   case Intrinsic::mips_frint_d:
19120b57cec5SDimitry Andric     return DAG.getNode(ISD::FRINT, DL, Op->getValueType(0), Op->getOperand(1));
19130b57cec5SDimitry Andric   case Intrinsic::mips_fsqrt_w:
19140b57cec5SDimitry Andric   case Intrinsic::mips_fsqrt_d:
19150b57cec5SDimitry Andric     return DAG.getNode(ISD::FSQRT, DL, Op->getValueType(0), Op->getOperand(1));
19160b57cec5SDimitry Andric   case Intrinsic::mips_fsub_w:
19170b57cec5SDimitry Andric   case Intrinsic::mips_fsub_d:
19180b57cec5SDimitry Andric     // TODO: If intrinsics have fast-math-flags, propagate them.
19190b57cec5SDimitry Andric     return DAG.getNode(ISD::FSUB, DL, Op->getValueType(0), Op->getOperand(1),
19200b57cec5SDimitry Andric                        Op->getOperand(2));
19210b57cec5SDimitry Andric   case Intrinsic::mips_ftrunc_u_w:
19220b57cec5SDimitry Andric   case Intrinsic::mips_ftrunc_u_d:
19230b57cec5SDimitry Andric     return DAG.getNode(ISD::FP_TO_UINT, DL, Op->getValueType(0),
19240b57cec5SDimitry Andric                        Op->getOperand(1));
19250b57cec5SDimitry Andric   case Intrinsic::mips_ftrunc_s_w:
19260b57cec5SDimitry Andric   case Intrinsic::mips_ftrunc_s_d:
19270b57cec5SDimitry Andric     return DAG.getNode(ISD::FP_TO_SINT, DL, Op->getValueType(0),
19280b57cec5SDimitry Andric                        Op->getOperand(1));
19290b57cec5SDimitry Andric   case Intrinsic::mips_ilvev_b:
19300b57cec5SDimitry Andric   case Intrinsic::mips_ilvev_h:
19310b57cec5SDimitry Andric   case Intrinsic::mips_ilvev_w:
19320b57cec5SDimitry Andric   case Intrinsic::mips_ilvev_d:
19330b57cec5SDimitry Andric     return DAG.getNode(MipsISD::ILVEV, DL, Op->getValueType(0),
19340b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
19350b57cec5SDimitry Andric   case Intrinsic::mips_ilvl_b:
19360b57cec5SDimitry Andric   case Intrinsic::mips_ilvl_h:
19370b57cec5SDimitry Andric   case Intrinsic::mips_ilvl_w:
19380b57cec5SDimitry Andric   case Intrinsic::mips_ilvl_d:
19390b57cec5SDimitry Andric     return DAG.getNode(MipsISD::ILVL, DL, Op->getValueType(0),
19400b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
19410b57cec5SDimitry Andric   case Intrinsic::mips_ilvod_b:
19420b57cec5SDimitry Andric   case Intrinsic::mips_ilvod_h:
19430b57cec5SDimitry Andric   case Intrinsic::mips_ilvod_w:
19440b57cec5SDimitry Andric   case Intrinsic::mips_ilvod_d:
19450b57cec5SDimitry Andric     return DAG.getNode(MipsISD::ILVOD, DL, Op->getValueType(0),
19460b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
19470b57cec5SDimitry Andric   case Intrinsic::mips_ilvr_b:
19480b57cec5SDimitry Andric   case Intrinsic::mips_ilvr_h:
19490b57cec5SDimitry Andric   case Intrinsic::mips_ilvr_w:
19500b57cec5SDimitry Andric   case Intrinsic::mips_ilvr_d:
19510b57cec5SDimitry Andric     return DAG.getNode(MipsISD::ILVR, DL, Op->getValueType(0),
19520b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
19530b57cec5SDimitry Andric   case Intrinsic::mips_insert_b:
19540b57cec5SDimitry Andric   case Intrinsic::mips_insert_h:
19550b57cec5SDimitry Andric   case Intrinsic::mips_insert_w:
19560b57cec5SDimitry Andric   case Intrinsic::mips_insert_d:
19570b57cec5SDimitry Andric     return DAG.getNode(ISD::INSERT_VECTOR_ELT, SDLoc(Op), Op->getValueType(0),
19580b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(3), Op->getOperand(2));
19590b57cec5SDimitry Andric   case Intrinsic::mips_insve_b:
19600b57cec5SDimitry Andric   case Intrinsic::mips_insve_h:
19610b57cec5SDimitry Andric   case Intrinsic::mips_insve_w:
19620b57cec5SDimitry Andric   case Intrinsic::mips_insve_d: {
19630b57cec5SDimitry Andric     // Report an error for out of range values.
19640b57cec5SDimitry Andric     int64_t Max;
19650b57cec5SDimitry Andric     switch (Intrinsic) {
19660b57cec5SDimitry Andric     case Intrinsic::mips_insve_b: Max = 15; break;
19670b57cec5SDimitry Andric     case Intrinsic::mips_insve_h: Max = 7; break;
19680b57cec5SDimitry Andric     case Intrinsic::mips_insve_w: Max = 3; break;
19690b57cec5SDimitry Andric     case Intrinsic::mips_insve_d: Max = 1; break;
19700b57cec5SDimitry Andric     default: llvm_unreachable("Unmatched intrinsic");
19710b57cec5SDimitry Andric     }
19720b57cec5SDimitry Andric     int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
19730b57cec5SDimitry Andric     if (Value < 0 || Value > Max)
19740b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
19750b57cec5SDimitry Andric     return DAG.getNode(MipsISD::INSVE, DL, Op->getValueType(0),
19760b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2), Op->getOperand(3),
19770b57cec5SDimitry Andric                        DAG.getConstant(0, DL, MVT::i32));
19780b57cec5SDimitry Andric     }
19790b57cec5SDimitry Andric   case Intrinsic::mips_ldi_b:
19800b57cec5SDimitry Andric   case Intrinsic::mips_ldi_h:
19810b57cec5SDimitry Andric   case Intrinsic::mips_ldi_w:
19820b57cec5SDimitry Andric   case Intrinsic::mips_ldi_d:
19830b57cec5SDimitry Andric     return lowerMSASplatImm(Op, 1, DAG, true);
19840b57cec5SDimitry Andric   case Intrinsic::mips_lsa:
19850b57cec5SDimitry Andric   case Intrinsic::mips_dlsa: {
19860b57cec5SDimitry Andric     EVT ResTy = Op->getValueType(0);
19870b57cec5SDimitry Andric     return DAG.getNode(ISD::ADD, SDLoc(Op), ResTy, Op->getOperand(1),
19880b57cec5SDimitry Andric                        DAG.getNode(ISD::SHL, SDLoc(Op), ResTy,
19890b57cec5SDimitry Andric                                    Op->getOperand(2), Op->getOperand(3)));
19900b57cec5SDimitry Andric   }
19910b57cec5SDimitry Andric   case Intrinsic::mips_maddv_b:
19920b57cec5SDimitry Andric   case Intrinsic::mips_maddv_h:
19930b57cec5SDimitry Andric   case Intrinsic::mips_maddv_w:
19940b57cec5SDimitry Andric   case Intrinsic::mips_maddv_d: {
19950b57cec5SDimitry Andric     EVT ResTy = Op->getValueType(0);
19960b57cec5SDimitry Andric     return DAG.getNode(ISD::ADD, SDLoc(Op), ResTy, Op->getOperand(1),
19970b57cec5SDimitry Andric                        DAG.getNode(ISD::MUL, SDLoc(Op), ResTy,
19980b57cec5SDimitry Andric                                    Op->getOperand(2), Op->getOperand(3)));
19990b57cec5SDimitry Andric   }
20000b57cec5SDimitry Andric   case Intrinsic::mips_max_s_b:
20010b57cec5SDimitry Andric   case Intrinsic::mips_max_s_h:
20020b57cec5SDimitry Andric   case Intrinsic::mips_max_s_w:
20030b57cec5SDimitry Andric   case Intrinsic::mips_max_s_d:
20040b57cec5SDimitry Andric     return DAG.getNode(ISD::SMAX, DL, Op->getValueType(0),
20050b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
20060b57cec5SDimitry Andric   case Intrinsic::mips_max_u_b:
20070b57cec5SDimitry Andric   case Intrinsic::mips_max_u_h:
20080b57cec5SDimitry Andric   case Intrinsic::mips_max_u_w:
20090b57cec5SDimitry Andric   case Intrinsic::mips_max_u_d:
20100b57cec5SDimitry Andric     return DAG.getNode(ISD::UMAX, DL, Op->getValueType(0),
20110b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
20120b57cec5SDimitry Andric   case Intrinsic::mips_maxi_s_b:
20130b57cec5SDimitry Andric   case Intrinsic::mips_maxi_s_h:
20140b57cec5SDimitry Andric   case Intrinsic::mips_maxi_s_w:
20150b57cec5SDimitry Andric   case Intrinsic::mips_maxi_s_d:
20160b57cec5SDimitry Andric     return DAG.getNode(ISD::SMAX, DL, Op->getValueType(0),
20170b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG, true));
20180b57cec5SDimitry Andric   case Intrinsic::mips_maxi_u_b:
20190b57cec5SDimitry Andric   case Intrinsic::mips_maxi_u_h:
20200b57cec5SDimitry Andric   case Intrinsic::mips_maxi_u_w:
20210b57cec5SDimitry Andric   case Intrinsic::mips_maxi_u_d:
20220b57cec5SDimitry Andric     return DAG.getNode(ISD::UMAX, DL, Op->getValueType(0),
20230b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
20240b57cec5SDimitry Andric   case Intrinsic::mips_min_s_b:
20250b57cec5SDimitry Andric   case Intrinsic::mips_min_s_h:
20260b57cec5SDimitry Andric   case Intrinsic::mips_min_s_w:
20270b57cec5SDimitry Andric   case Intrinsic::mips_min_s_d:
20280b57cec5SDimitry Andric     return DAG.getNode(ISD::SMIN, DL, Op->getValueType(0),
20290b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
20300b57cec5SDimitry Andric   case Intrinsic::mips_min_u_b:
20310b57cec5SDimitry Andric   case Intrinsic::mips_min_u_h:
20320b57cec5SDimitry Andric   case Intrinsic::mips_min_u_w:
20330b57cec5SDimitry Andric   case Intrinsic::mips_min_u_d:
20340b57cec5SDimitry Andric     return DAG.getNode(ISD::UMIN, DL, Op->getValueType(0),
20350b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
20360b57cec5SDimitry Andric   case Intrinsic::mips_mini_s_b:
20370b57cec5SDimitry Andric   case Intrinsic::mips_mini_s_h:
20380b57cec5SDimitry Andric   case Intrinsic::mips_mini_s_w:
20390b57cec5SDimitry Andric   case Intrinsic::mips_mini_s_d:
20400b57cec5SDimitry Andric     return DAG.getNode(ISD::SMIN, DL, Op->getValueType(0),
20410b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG, true));
20420b57cec5SDimitry Andric   case Intrinsic::mips_mini_u_b:
20430b57cec5SDimitry Andric   case Intrinsic::mips_mini_u_h:
20440b57cec5SDimitry Andric   case Intrinsic::mips_mini_u_w:
20450b57cec5SDimitry Andric   case Intrinsic::mips_mini_u_d:
20460b57cec5SDimitry Andric     return DAG.getNode(ISD::UMIN, DL, Op->getValueType(0),
20470b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
20480b57cec5SDimitry Andric   case Intrinsic::mips_mod_s_b:
20490b57cec5SDimitry Andric   case Intrinsic::mips_mod_s_h:
20500b57cec5SDimitry Andric   case Intrinsic::mips_mod_s_w:
20510b57cec5SDimitry Andric   case Intrinsic::mips_mod_s_d:
20520b57cec5SDimitry Andric     return DAG.getNode(ISD::SREM, DL, Op->getValueType(0), Op->getOperand(1),
20530b57cec5SDimitry Andric                        Op->getOperand(2));
20540b57cec5SDimitry Andric   case Intrinsic::mips_mod_u_b:
20550b57cec5SDimitry Andric   case Intrinsic::mips_mod_u_h:
20560b57cec5SDimitry Andric   case Intrinsic::mips_mod_u_w:
20570b57cec5SDimitry Andric   case Intrinsic::mips_mod_u_d:
20580b57cec5SDimitry Andric     return DAG.getNode(ISD::UREM, DL, Op->getValueType(0), Op->getOperand(1),
20590b57cec5SDimitry Andric                        Op->getOperand(2));
20600b57cec5SDimitry Andric   case Intrinsic::mips_mulv_b:
20610b57cec5SDimitry Andric   case Intrinsic::mips_mulv_h:
20620b57cec5SDimitry Andric   case Intrinsic::mips_mulv_w:
20630b57cec5SDimitry Andric   case Intrinsic::mips_mulv_d:
20640b57cec5SDimitry Andric     return DAG.getNode(ISD::MUL, DL, Op->getValueType(0), Op->getOperand(1),
20650b57cec5SDimitry Andric                        Op->getOperand(2));
20660b57cec5SDimitry Andric   case Intrinsic::mips_msubv_b:
20670b57cec5SDimitry Andric   case Intrinsic::mips_msubv_h:
20680b57cec5SDimitry Andric   case Intrinsic::mips_msubv_w:
20690b57cec5SDimitry Andric   case Intrinsic::mips_msubv_d: {
20700b57cec5SDimitry Andric     EVT ResTy = Op->getValueType(0);
20710b57cec5SDimitry Andric     return DAG.getNode(ISD::SUB, SDLoc(Op), ResTy, Op->getOperand(1),
20720b57cec5SDimitry Andric                        DAG.getNode(ISD::MUL, SDLoc(Op), ResTy,
20730b57cec5SDimitry Andric                                    Op->getOperand(2), Op->getOperand(3)));
20740b57cec5SDimitry Andric   }
20750b57cec5SDimitry Andric   case Intrinsic::mips_nlzc_b:
20760b57cec5SDimitry Andric   case Intrinsic::mips_nlzc_h:
20770b57cec5SDimitry Andric   case Intrinsic::mips_nlzc_w:
20780b57cec5SDimitry Andric   case Intrinsic::mips_nlzc_d:
20790b57cec5SDimitry Andric     return DAG.getNode(ISD::CTLZ, DL, Op->getValueType(0), Op->getOperand(1));
20800b57cec5SDimitry Andric   case Intrinsic::mips_nor_v: {
20810b57cec5SDimitry Andric     SDValue Res = DAG.getNode(ISD::OR, DL, Op->getValueType(0),
20820b57cec5SDimitry Andric                               Op->getOperand(1), Op->getOperand(2));
20830b57cec5SDimitry Andric     return DAG.getNOT(DL, Res, Res->getValueType(0));
20840b57cec5SDimitry Andric   }
20850b57cec5SDimitry Andric   case Intrinsic::mips_nori_b: {
20860b57cec5SDimitry Andric     SDValue Res =  DAG.getNode(ISD::OR, DL, Op->getValueType(0),
20870b57cec5SDimitry Andric                                Op->getOperand(1),
20880b57cec5SDimitry Andric                                lowerMSASplatImm(Op, 2, DAG));
20890b57cec5SDimitry Andric     return DAG.getNOT(DL, Res, Res->getValueType(0));
20900b57cec5SDimitry Andric   }
20910b57cec5SDimitry Andric   case Intrinsic::mips_or_v:
20920b57cec5SDimitry Andric     return DAG.getNode(ISD::OR, DL, Op->getValueType(0), Op->getOperand(1),
20930b57cec5SDimitry Andric                        Op->getOperand(2));
20940b57cec5SDimitry Andric   case Intrinsic::mips_ori_b:
20950b57cec5SDimitry Andric     return DAG.getNode(ISD::OR, DL, Op->getValueType(0),
20960b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
20970b57cec5SDimitry Andric   case Intrinsic::mips_pckev_b:
20980b57cec5SDimitry Andric   case Intrinsic::mips_pckev_h:
20990b57cec5SDimitry Andric   case Intrinsic::mips_pckev_w:
21000b57cec5SDimitry Andric   case Intrinsic::mips_pckev_d:
21010b57cec5SDimitry Andric     return DAG.getNode(MipsISD::PCKEV, DL, Op->getValueType(0),
21020b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
21030b57cec5SDimitry Andric   case Intrinsic::mips_pckod_b:
21040b57cec5SDimitry Andric   case Intrinsic::mips_pckod_h:
21050b57cec5SDimitry Andric   case Intrinsic::mips_pckod_w:
21060b57cec5SDimitry Andric   case Intrinsic::mips_pckod_d:
21070b57cec5SDimitry Andric     return DAG.getNode(MipsISD::PCKOD, DL, Op->getValueType(0),
21080b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2));
21090b57cec5SDimitry Andric   case Intrinsic::mips_pcnt_b:
21100b57cec5SDimitry Andric   case Intrinsic::mips_pcnt_h:
21110b57cec5SDimitry Andric   case Intrinsic::mips_pcnt_w:
21120b57cec5SDimitry Andric   case Intrinsic::mips_pcnt_d:
21130b57cec5SDimitry Andric     return DAG.getNode(ISD::CTPOP, DL, Op->getValueType(0), Op->getOperand(1));
21140b57cec5SDimitry Andric   case Intrinsic::mips_sat_s_b:
21150b57cec5SDimitry Andric   case Intrinsic::mips_sat_s_h:
21160b57cec5SDimitry Andric   case Intrinsic::mips_sat_s_w:
21170b57cec5SDimitry Andric   case Intrinsic::mips_sat_s_d:
21180b57cec5SDimitry Andric   case Intrinsic::mips_sat_u_b:
21190b57cec5SDimitry Andric   case Intrinsic::mips_sat_u_h:
21200b57cec5SDimitry Andric   case Intrinsic::mips_sat_u_w:
21210b57cec5SDimitry Andric   case Intrinsic::mips_sat_u_d: {
21220b57cec5SDimitry Andric     // Report an error for out of range values.
21230b57cec5SDimitry Andric     int64_t Max;
21240b57cec5SDimitry Andric     switch (Intrinsic) {
21250b57cec5SDimitry Andric     case Intrinsic::mips_sat_s_b:
21260b57cec5SDimitry Andric     case Intrinsic::mips_sat_u_b: Max = 7;  break;
21270b57cec5SDimitry Andric     case Intrinsic::mips_sat_s_h:
21280b57cec5SDimitry Andric     case Intrinsic::mips_sat_u_h: Max = 15; break;
21290b57cec5SDimitry Andric     case Intrinsic::mips_sat_s_w:
21300b57cec5SDimitry Andric     case Intrinsic::mips_sat_u_w: Max = 31; break;
21310b57cec5SDimitry Andric     case Intrinsic::mips_sat_s_d:
21320b57cec5SDimitry Andric     case Intrinsic::mips_sat_u_d: Max = 63; break;
21330b57cec5SDimitry Andric     default: llvm_unreachable("Unmatched intrinsic");
21340b57cec5SDimitry Andric     }
21350b57cec5SDimitry Andric     int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
21360b57cec5SDimitry Andric     if (Value < 0 || Value > Max)
21370b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
21380b57cec5SDimitry Andric     return SDValue();
21390b57cec5SDimitry Andric   }
21400b57cec5SDimitry Andric   case Intrinsic::mips_shf_b:
21410b57cec5SDimitry Andric   case Intrinsic::mips_shf_h:
21420b57cec5SDimitry Andric   case Intrinsic::mips_shf_w: {
21430b57cec5SDimitry Andric     int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
21440b57cec5SDimitry Andric     if (Value < 0 || Value > 255)
21450b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
21460b57cec5SDimitry Andric     return DAG.getNode(MipsISD::SHF, DL, Op->getValueType(0),
21470b57cec5SDimitry Andric                        Op->getOperand(2), Op->getOperand(1));
21480b57cec5SDimitry Andric   }
21490b57cec5SDimitry Andric   case Intrinsic::mips_sldi_b:
21500b57cec5SDimitry Andric   case Intrinsic::mips_sldi_h:
21510b57cec5SDimitry Andric   case Intrinsic::mips_sldi_w:
21520b57cec5SDimitry Andric   case Intrinsic::mips_sldi_d: {
21530b57cec5SDimitry Andric     // Report an error for out of range values.
21540b57cec5SDimitry Andric     int64_t Max;
21550b57cec5SDimitry Andric     switch (Intrinsic) {
21560b57cec5SDimitry Andric     case Intrinsic::mips_sldi_b: Max = 15; break;
21570b57cec5SDimitry Andric     case Intrinsic::mips_sldi_h: Max = 7; break;
21580b57cec5SDimitry Andric     case Intrinsic::mips_sldi_w: Max = 3; break;
21590b57cec5SDimitry Andric     case Intrinsic::mips_sldi_d: Max = 1; break;
21600b57cec5SDimitry Andric     default: llvm_unreachable("Unmatched intrinsic");
21610b57cec5SDimitry Andric     }
21620b57cec5SDimitry Andric     int64_t Value = cast<ConstantSDNode>(Op->getOperand(3))->getSExtValue();
21630b57cec5SDimitry Andric     if (Value < 0 || Value > Max)
21640b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
21650b57cec5SDimitry Andric     return SDValue();
21660b57cec5SDimitry Andric   }
21670b57cec5SDimitry Andric   case Intrinsic::mips_sll_b:
21680b57cec5SDimitry Andric   case Intrinsic::mips_sll_h:
21690b57cec5SDimitry Andric   case Intrinsic::mips_sll_w:
21700b57cec5SDimitry Andric   case Intrinsic::mips_sll_d:
21710b57cec5SDimitry Andric     return DAG.getNode(ISD::SHL, DL, Op->getValueType(0), Op->getOperand(1),
21720b57cec5SDimitry Andric                        truncateVecElts(Op, DAG));
21730b57cec5SDimitry Andric   case Intrinsic::mips_slli_b:
21740b57cec5SDimitry Andric   case Intrinsic::mips_slli_h:
21750b57cec5SDimitry Andric   case Intrinsic::mips_slli_w:
21760b57cec5SDimitry Andric   case Intrinsic::mips_slli_d:
21770b57cec5SDimitry Andric     return DAG.getNode(ISD::SHL, DL, Op->getValueType(0),
21780b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
21790b57cec5SDimitry Andric   case Intrinsic::mips_splat_b:
21800b57cec5SDimitry Andric   case Intrinsic::mips_splat_h:
21810b57cec5SDimitry Andric   case Intrinsic::mips_splat_w:
21820b57cec5SDimitry Andric   case Intrinsic::mips_splat_d:
21830b57cec5SDimitry Andric     // We can't lower via VECTOR_SHUFFLE because it requires constant shuffle
21840b57cec5SDimitry Andric     // masks, nor can we lower via BUILD_VECTOR & EXTRACT_VECTOR_ELT because
21850b57cec5SDimitry Andric     // EXTRACT_VECTOR_ELT can't extract i64's on MIPS32.
21860b57cec5SDimitry Andric     // Instead we lower to MipsISD::VSHF and match from there.
21870b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0),
21880b57cec5SDimitry Andric                        lowerMSASplatZExt(Op, 2, DAG), Op->getOperand(1),
21890b57cec5SDimitry Andric                        Op->getOperand(1));
21900b57cec5SDimitry Andric   case Intrinsic::mips_splati_b:
21910b57cec5SDimitry Andric   case Intrinsic::mips_splati_h:
21920b57cec5SDimitry Andric   case Intrinsic::mips_splati_w:
21930b57cec5SDimitry Andric   case Intrinsic::mips_splati_d:
21940b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0),
21950b57cec5SDimitry Andric                        lowerMSASplatImm(Op, 2, DAG), Op->getOperand(1),
21960b57cec5SDimitry Andric                        Op->getOperand(1));
21970b57cec5SDimitry Andric   case Intrinsic::mips_sra_b:
21980b57cec5SDimitry Andric   case Intrinsic::mips_sra_h:
21990b57cec5SDimitry Andric   case Intrinsic::mips_sra_w:
22000b57cec5SDimitry Andric   case Intrinsic::mips_sra_d:
22010b57cec5SDimitry Andric     return DAG.getNode(ISD::SRA, DL, Op->getValueType(0), Op->getOperand(1),
22020b57cec5SDimitry Andric                        truncateVecElts(Op, DAG));
22030b57cec5SDimitry Andric   case Intrinsic::mips_srai_b:
22040b57cec5SDimitry Andric   case Intrinsic::mips_srai_h:
22050b57cec5SDimitry Andric   case Intrinsic::mips_srai_w:
22060b57cec5SDimitry Andric   case Intrinsic::mips_srai_d:
22070b57cec5SDimitry Andric     return DAG.getNode(ISD::SRA, DL, Op->getValueType(0),
22080b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
22090b57cec5SDimitry Andric   case Intrinsic::mips_srari_b:
22100b57cec5SDimitry Andric   case Intrinsic::mips_srari_h:
22110b57cec5SDimitry Andric   case Intrinsic::mips_srari_w:
22120b57cec5SDimitry Andric   case Intrinsic::mips_srari_d: {
22130b57cec5SDimitry Andric     // Report an error for out of range values.
22140b57cec5SDimitry Andric     int64_t Max;
22150b57cec5SDimitry Andric     switch (Intrinsic) {
22160b57cec5SDimitry Andric     case Intrinsic::mips_srari_b: Max = 7; break;
22170b57cec5SDimitry Andric     case Intrinsic::mips_srari_h: Max = 15; break;
22180b57cec5SDimitry Andric     case Intrinsic::mips_srari_w: Max = 31; break;
22190b57cec5SDimitry Andric     case Intrinsic::mips_srari_d: Max = 63; break;
22200b57cec5SDimitry Andric     default: llvm_unreachable("Unmatched intrinsic");
22210b57cec5SDimitry Andric     }
22220b57cec5SDimitry Andric     int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
22230b57cec5SDimitry Andric     if (Value < 0 || Value > Max)
22240b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
22250b57cec5SDimitry Andric     return SDValue();
22260b57cec5SDimitry Andric   }
22270b57cec5SDimitry Andric   case Intrinsic::mips_srl_b:
22280b57cec5SDimitry Andric   case Intrinsic::mips_srl_h:
22290b57cec5SDimitry Andric   case Intrinsic::mips_srl_w:
22300b57cec5SDimitry Andric   case Intrinsic::mips_srl_d:
22310b57cec5SDimitry Andric     return DAG.getNode(ISD::SRL, DL, Op->getValueType(0), Op->getOperand(1),
22320b57cec5SDimitry Andric                        truncateVecElts(Op, DAG));
22330b57cec5SDimitry Andric   case Intrinsic::mips_srli_b:
22340b57cec5SDimitry Andric   case Intrinsic::mips_srli_h:
22350b57cec5SDimitry Andric   case Intrinsic::mips_srli_w:
22360b57cec5SDimitry Andric   case Intrinsic::mips_srli_d:
22370b57cec5SDimitry Andric     return DAG.getNode(ISD::SRL, DL, Op->getValueType(0),
22380b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
22390b57cec5SDimitry Andric   case Intrinsic::mips_srlri_b:
22400b57cec5SDimitry Andric   case Intrinsic::mips_srlri_h:
22410b57cec5SDimitry Andric   case Intrinsic::mips_srlri_w:
22420b57cec5SDimitry Andric   case Intrinsic::mips_srlri_d: {
22430b57cec5SDimitry Andric     // Report an error for out of range values.
22440b57cec5SDimitry Andric     int64_t Max;
22450b57cec5SDimitry Andric     switch (Intrinsic) {
22460b57cec5SDimitry Andric     case Intrinsic::mips_srlri_b: Max = 7; break;
22470b57cec5SDimitry Andric     case Intrinsic::mips_srlri_h: Max = 15; break;
22480b57cec5SDimitry Andric     case Intrinsic::mips_srlri_w: Max = 31; break;
22490b57cec5SDimitry Andric     case Intrinsic::mips_srlri_d: Max = 63; break;
22500b57cec5SDimitry Andric     default: llvm_unreachable("Unmatched intrinsic");
22510b57cec5SDimitry Andric     }
22520b57cec5SDimitry Andric     int64_t Value = cast<ConstantSDNode>(Op->getOperand(2))->getSExtValue();
22530b57cec5SDimitry Andric     if (Value < 0 || Value > Max)
22540b57cec5SDimitry Andric       report_fatal_error("Immediate out of range");
22550b57cec5SDimitry Andric     return SDValue();
22560b57cec5SDimitry Andric   }
22570b57cec5SDimitry Andric   case Intrinsic::mips_subv_b:
22580b57cec5SDimitry Andric   case Intrinsic::mips_subv_h:
22590b57cec5SDimitry Andric   case Intrinsic::mips_subv_w:
22600b57cec5SDimitry Andric   case Intrinsic::mips_subv_d:
22610b57cec5SDimitry Andric     return DAG.getNode(ISD::SUB, DL, Op->getValueType(0), Op->getOperand(1),
22620b57cec5SDimitry Andric                        Op->getOperand(2));
22630b57cec5SDimitry Andric   case Intrinsic::mips_subvi_b:
22640b57cec5SDimitry Andric   case Intrinsic::mips_subvi_h:
22650b57cec5SDimitry Andric   case Intrinsic::mips_subvi_w:
22660b57cec5SDimitry Andric   case Intrinsic::mips_subvi_d:
22670b57cec5SDimitry Andric     return DAG.getNode(ISD::SUB, DL, Op->getValueType(0),
22680b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
22690b57cec5SDimitry Andric   case Intrinsic::mips_vshf_b:
22700b57cec5SDimitry Andric   case Intrinsic::mips_vshf_h:
22710b57cec5SDimitry Andric   case Intrinsic::mips_vshf_w:
22720b57cec5SDimitry Andric   case Intrinsic::mips_vshf_d:
22730b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0),
22740b57cec5SDimitry Andric                        Op->getOperand(1), Op->getOperand(2), Op->getOperand(3));
22750b57cec5SDimitry Andric   case Intrinsic::mips_xor_v:
22760b57cec5SDimitry Andric     return DAG.getNode(ISD::XOR, DL, Op->getValueType(0), Op->getOperand(1),
22770b57cec5SDimitry Andric                        Op->getOperand(2));
22780b57cec5SDimitry Andric   case Intrinsic::mips_xori_b:
22790b57cec5SDimitry Andric     return DAG.getNode(ISD::XOR, DL, Op->getValueType(0),
22800b57cec5SDimitry Andric                        Op->getOperand(1), lowerMSASplatImm(Op, 2, DAG));
22810b57cec5SDimitry Andric   case Intrinsic::thread_pointer: {
22820b57cec5SDimitry Andric     EVT PtrVT = getPointerTy(DAG.getDataLayout());
22830b57cec5SDimitry Andric     return DAG.getNode(MipsISD::ThreadPointer, DL, PtrVT);
22840b57cec5SDimitry Andric   }
22850b57cec5SDimitry Andric   }
22860b57cec5SDimitry Andric }
22870b57cec5SDimitry Andric 
22880b57cec5SDimitry Andric static SDValue lowerMSALoadIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr,
22890b57cec5SDimitry Andric                                 const MipsSubtarget &Subtarget) {
22900b57cec5SDimitry Andric   SDLoc DL(Op);
22910b57cec5SDimitry Andric   SDValue ChainIn = Op->getOperand(0);
22920b57cec5SDimitry Andric   SDValue Address = Op->getOperand(2);
22930b57cec5SDimitry Andric   SDValue Offset  = Op->getOperand(3);
22940b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
22950b57cec5SDimitry Andric   EVT PtrTy = Address->getValueType(0);
22960b57cec5SDimitry Andric 
22970b57cec5SDimitry Andric   // For N64 addresses have the underlying type MVT::i64. This intrinsic
22980b57cec5SDimitry Andric   // however takes an i32 signed constant offset. The actual type of the
22990b57cec5SDimitry Andric   // intrinsic is a scaled signed i10.
23000b57cec5SDimitry Andric   if (Subtarget.isABI_N64())
23010b57cec5SDimitry Andric     Offset = DAG.getNode(ISD::SIGN_EXTEND, DL, PtrTy, Offset);
23020b57cec5SDimitry Andric 
23030b57cec5SDimitry Andric   Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset);
23040b57cec5SDimitry Andric   return DAG.getLoad(ResTy, DL, ChainIn, Address, MachinePointerInfo(),
2305e8d8bef9SDimitry Andric                      Align(16));
23060b57cec5SDimitry Andric }
23070b57cec5SDimitry Andric 
23080b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op,
23090b57cec5SDimitry Andric                                                      SelectionDAG &DAG) const {
2310647cbc5dSDimitry Andric   unsigned Intr = Op->getConstantOperandVal(1);
23110b57cec5SDimitry Andric   switch (Intr) {
23120b57cec5SDimitry Andric   default:
23130b57cec5SDimitry Andric     return SDValue();
23140b57cec5SDimitry Andric   case Intrinsic::mips_extp:
23150b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::EXTP);
23160b57cec5SDimitry Andric   case Intrinsic::mips_extpdp:
23170b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::EXTPDP);
23180b57cec5SDimitry Andric   case Intrinsic::mips_extr_w:
23190b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::EXTR_W);
23200b57cec5SDimitry Andric   case Intrinsic::mips_extr_r_w:
23210b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::EXTR_R_W);
23220b57cec5SDimitry Andric   case Intrinsic::mips_extr_rs_w:
23230b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::EXTR_RS_W);
23240b57cec5SDimitry Andric   case Intrinsic::mips_extr_s_h:
23250b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::EXTR_S_H);
23260b57cec5SDimitry Andric   case Intrinsic::mips_mthlip:
23270b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MTHLIP);
23280b57cec5SDimitry Andric   case Intrinsic::mips_mulsaq_s_w_ph:
23290b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MULSAQ_S_W_PH);
23300b57cec5SDimitry Andric   case Intrinsic::mips_maq_s_w_phl:
23310b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHL);
23320b57cec5SDimitry Andric   case Intrinsic::mips_maq_s_w_phr:
23330b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MAQ_S_W_PHR);
23340b57cec5SDimitry Andric   case Intrinsic::mips_maq_sa_w_phl:
23350b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHL);
23360b57cec5SDimitry Andric   case Intrinsic::mips_maq_sa_w_phr:
23370b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::MAQ_SA_W_PHR);
23380b57cec5SDimitry Andric   case Intrinsic::mips_dpaq_s_w_ph:
23390b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_S_W_PH);
23400b57cec5SDimitry Andric   case Intrinsic::mips_dpsq_s_w_ph:
23410b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_S_W_PH);
23420b57cec5SDimitry Andric   case Intrinsic::mips_dpaq_sa_l_w:
23430b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPAQ_SA_L_W);
23440b57cec5SDimitry Andric   case Intrinsic::mips_dpsq_sa_l_w:
23450b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPSQ_SA_L_W);
23460b57cec5SDimitry Andric   case Intrinsic::mips_dpaqx_s_w_ph:
23470b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_S_W_PH);
23480b57cec5SDimitry Andric   case Intrinsic::mips_dpaqx_sa_w_ph:
23490b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPAQX_SA_W_PH);
23500b57cec5SDimitry Andric   case Intrinsic::mips_dpsqx_s_w_ph:
23510b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_S_W_PH);
23520b57cec5SDimitry Andric   case Intrinsic::mips_dpsqx_sa_w_ph:
23530b57cec5SDimitry Andric     return lowerDSPIntr(Op, DAG, MipsISD::DPSQX_SA_W_PH);
23540b57cec5SDimitry Andric   case Intrinsic::mips_ld_b:
23550b57cec5SDimitry Andric   case Intrinsic::mips_ld_h:
23560b57cec5SDimitry Andric   case Intrinsic::mips_ld_w:
23570b57cec5SDimitry Andric   case Intrinsic::mips_ld_d:
23580b57cec5SDimitry Andric    return lowerMSALoadIntr(Op, DAG, Intr, Subtarget);
23590b57cec5SDimitry Andric   }
23600b57cec5SDimitry Andric }
23610b57cec5SDimitry Andric 
23620b57cec5SDimitry Andric static SDValue lowerMSAStoreIntr(SDValue Op, SelectionDAG &DAG, unsigned Intr,
23630b57cec5SDimitry Andric                                  const MipsSubtarget &Subtarget) {
23640b57cec5SDimitry Andric   SDLoc DL(Op);
23650b57cec5SDimitry Andric   SDValue ChainIn = Op->getOperand(0);
23660b57cec5SDimitry Andric   SDValue Value   = Op->getOperand(2);
23670b57cec5SDimitry Andric   SDValue Address = Op->getOperand(3);
23680b57cec5SDimitry Andric   SDValue Offset  = Op->getOperand(4);
23690b57cec5SDimitry Andric   EVT PtrTy = Address->getValueType(0);
23700b57cec5SDimitry Andric 
23710b57cec5SDimitry Andric   // For N64 addresses have the underlying type MVT::i64. This intrinsic
23720b57cec5SDimitry Andric   // however takes an i32 signed constant offset. The actual type of the
23730b57cec5SDimitry Andric   // intrinsic is a scaled signed i10.
23740b57cec5SDimitry Andric   if (Subtarget.isABI_N64())
23750b57cec5SDimitry Andric     Offset = DAG.getNode(ISD::SIGN_EXTEND, DL, PtrTy, Offset);
23760b57cec5SDimitry Andric 
23770b57cec5SDimitry Andric   Address = DAG.getNode(ISD::ADD, DL, PtrTy, Address, Offset);
23780b57cec5SDimitry Andric 
23790b57cec5SDimitry Andric   return DAG.getStore(ChainIn, DL, Value, Address, MachinePointerInfo(),
2380e8d8bef9SDimitry Andric                       Align(16));
23810b57cec5SDimitry Andric }
23820b57cec5SDimitry Andric 
23830b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerINTRINSIC_VOID(SDValue Op,
23840b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
2385647cbc5dSDimitry Andric   unsigned Intr = Op->getConstantOperandVal(1);
23860b57cec5SDimitry Andric   switch (Intr) {
23870b57cec5SDimitry Andric   default:
23880b57cec5SDimitry Andric     return SDValue();
23890b57cec5SDimitry Andric   case Intrinsic::mips_st_b:
23900b57cec5SDimitry Andric   case Intrinsic::mips_st_h:
23910b57cec5SDimitry Andric   case Intrinsic::mips_st_w:
23920b57cec5SDimitry Andric   case Intrinsic::mips_st_d:
23930b57cec5SDimitry Andric     return lowerMSAStoreIntr(Op, DAG, Intr, Subtarget);
23940b57cec5SDimitry Andric   }
23950b57cec5SDimitry Andric }
23960b57cec5SDimitry Andric 
23970b57cec5SDimitry Andric // Lower ISD::EXTRACT_VECTOR_ELT into MipsISD::VEXTRACT_SEXT_ELT.
23980b57cec5SDimitry Andric //
23990b57cec5SDimitry Andric // The non-value bits resulting from ISD::EXTRACT_VECTOR_ELT are undefined. We
24000b57cec5SDimitry Andric // choose to sign-extend but we could have equally chosen zero-extend. The
24010b57cec5SDimitry Andric // DAGCombiner will fold any sign/zero extension of the ISD::EXTRACT_VECTOR_ELT
24020b57cec5SDimitry Andric // result into this node later (possibly changing it to a zero-extend in the
24030b57cec5SDimitry Andric // process).
24040b57cec5SDimitry Andric SDValue MipsSETargetLowering::
24050b57cec5SDimitry Andric lowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) const {
24060b57cec5SDimitry Andric   SDLoc DL(Op);
24070b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
24080b57cec5SDimitry Andric   SDValue Op0 = Op->getOperand(0);
24090b57cec5SDimitry Andric   EVT VecTy = Op0->getValueType(0);
24100b57cec5SDimitry Andric 
24110b57cec5SDimitry Andric   if (!VecTy.is128BitVector())
24120b57cec5SDimitry Andric     return SDValue();
24130b57cec5SDimitry Andric 
24140b57cec5SDimitry Andric   if (ResTy.isInteger()) {
24150b57cec5SDimitry Andric     SDValue Op1 = Op->getOperand(1);
24160b57cec5SDimitry Andric     EVT EltTy = VecTy.getVectorElementType();
24170b57cec5SDimitry Andric     return DAG.getNode(MipsISD::VEXTRACT_SEXT_ELT, DL, ResTy, Op0, Op1,
24180b57cec5SDimitry Andric                        DAG.getValueType(EltTy));
24190b57cec5SDimitry Andric   }
24200b57cec5SDimitry Andric 
24210b57cec5SDimitry Andric   return Op;
24220b57cec5SDimitry Andric }
24230b57cec5SDimitry Andric 
24240b57cec5SDimitry Andric static bool isConstantOrUndef(const SDValue Op) {
24250b57cec5SDimitry Andric   if (Op->isUndef())
24260b57cec5SDimitry Andric     return true;
24270b57cec5SDimitry Andric   if (isa<ConstantSDNode>(Op))
24280b57cec5SDimitry Andric     return true;
24290b57cec5SDimitry Andric   if (isa<ConstantFPSDNode>(Op))
24300b57cec5SDimitry Andric     return true;
24310b57cec5SDimitry Andric   return false;
24320b57cec5SDimitry Andric }
24330b57cec5SDimitry Andric 
24340b57cec5SDimitry Andric static bool isConstantOrUndefBUILD_VECTOR(const BuildVectorSDNode *Op) {
24350b57cec5SDimitry Andric   for (unsigned i = 0; i < Op->getNumOperands(); ++i)
24360b57cec5SDimitry Andric     if (isConstantOrUndef(Op->getOperand(i)))
24370b57cec5SDimitry Andric       return true;
24380b57cec5SDimitry Andric   return false;
24390b57cec5SDimitry Andric }
24400b57cec5SDimitry Andric 
24410b57cec5SDimitry Andric // Lowers ISD::BUILD_VECTOR into appropriate SelectionDAG nodes for the
24420b57cec5SDimitry Andric // backend.
24430b57cec5SDimitry Andric //
24440b57cec5SDimitry Andric // Lowers according to the following rules:
24450b57cec5SDimitry Andric // - Constant splats are legal as-is as long as the SplatBitSize is a power of
24460b57cec5SDimitry Andric //   2 less than or equal to 64 and the value fits into a signed 10-bit
24470b57cec5SDimitry Andric //   immediate
24480b57cec5SDimitry Andric // - Constant splats are lowered to bitconverted BUILD_VECTORs if SplatBitSize
24490b57cec5SDimitry Andric //   is a power of 2 less than or equal to 64 and the value does not fit into a
24500b57cec5SDimitry Andric //   signed 10-bit immediate
24510b57cec5SDimitry Andric // - Non-constant splats are legal as-is.
24520b57cec5SDimitry Andric // - Non-constant non-splats are lowered to sequences of INSERT_VECTOR_ELT.
24530b57cec5SDimitry Andric // - All others are illegal and must be expanded.
24540b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerBUILD_VECTOR(SDValue Op,
24550b57cec5SDimitry Andric                                                 SelectionDAG &DAG) const {
24560b57cec5SDimitry Andric   BuildVectorSDNode *Node = cast<BuildVectorSDNode>(Op);
24570b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
24580b57cec5SDimitry Andric   SDLoc DL(Op);
24590b57cec5SDimitry Andric   APInt SplatValue, SplatUndef;
24600b57cec5SDimitry Andric   unsigned SplatBitSize;
24610b57cec5SDimitry Andric   bool HasAnyUndefs;
24620b57cec5SDimitry Andric 
24630b57cec5SDimitry Andric   if (!Subtarget.hasMSA() || !ResTy.is128BitVector())
24640b57cec5SDimitry Andric     return SDValue();
24650b57cec5SDimitry Andric 
24660b57cec5SDimitry Andric   if (Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize,
24670b57cec5SDimitry Andric                             HasAnyUndefs, 8,
24680b57cec5SDimitry Andric                             !Subtarget.isLittle()) && SplatBitSize <= 64) {
24690b57cec5SDimitry Andric     // We can only cope with 8, 16, 32, or 64-bit elements
24700b57cec5SDimitry Andric     if (SplatBitSize != 8 && SplatBitSize != 16 && SplatBitSize != 32 &&
24710b57cec5SDimitry Andric         SplatBitSize != 64)
24720b57cec5SDimitry Andric       return SDValue();
24730b57cec5SDimitry Andric 
24740b57cec5SDimitry Andric     // If the value isn't an integer type we will have to bitcast
24750b57cec5SDimitry Andric     // from an integer type first. Also, if there are any undefs, we must
24760b57cec5SDimitry Andric     // lower them to defined values first.
24770b57cec5SDimitry Andric     if (ResTy.isInteger() && !HasAnyUndefs)
24780b57cec5SDimitry Andric       return Op;
24790b57cec5SDimitry Andric 
24800b57cec5SDimitry Andric     EVT ViaVecTy;
24810b57cec5SDimitry Andric 
24820b57cec5SDimitry Andric     switch (SplatBitSize) {
24830b57cec5SDimitry Andric     default:
24840b57cec5SDimitry Andric       return SDValue();
24850b57cec5SDimitry Andric     case 8:
24860b57cec5SDimitry Andric       ViaVecTy = MVT::v16i8;
24870b57cec5SDimitry Andric       break;
24880b57cec5SDimitry Andric     case 16:
24890b57cec5SDimitry Andric       ViaVecTy = MVT::v8i16;
24900b57cec5SDimitry Andric       break;
24910b57cec5SDimitry Andric     case 32:
24920b57cec5SDimitry Andric       ViaVecTy = MVT::v4i32;
24930b57cec5SDimitry Andric       break;
24940b57cec5SDimitry Andric     case 64:
24950b57cec5SDimitry Andric       // There's no fill.d to fall back on for 64-bit values
24960b57cec5SDimitry Andric       return SDValue();
24970b57cec5SDimitry Andric     }
24980b57cec5SDimitry Andric 
24990b57cec5SDimitry Andric     // SelectionDAG::getConstant will promote SplatValue appropriately.
25000b57cec5SDimitry Andric     SDValue Result = DAG.getConstant(SplatValue, DL, ViaVecTy);
25010b57cec5SDimitry Andric 
25020b57cec5SDimitry Andric     // Bitcast to the type we originally wanted
25030b57cec5SDimitry Andric     if (ViaVecTy != ResTy)
25040b57cec5SDimitry Andric       Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result);
25050b57cec5SDimitry Andric 
25060b57cec5SDimitry Andric     return Result;
25070b57cec5SDimitry Andric   } else if (DAG.isSplatValue(Op, /* AllowUndefs */ false))
25080b57cec5SDimitry Andric     return Op;
25090b57cec5SDimitry Andric   else if (!isConstantOrUndefBUILD_VECTOR(Node)) {
25100b57cec5SDimitry Andric     // Use INSERT_VECTOR_ELT operations rather than expand to stores.
25110b57cec5SDimitry Andric     // The resulting code is the same length as the expansion, but it doesn't
25120b57cec5SDimitry Andric     // use memory operations
25130b57cec5SDimitry Andric     EVT ResTy = Node->getValueType(0);
25140b57cec5SDimitry Andric 
25150b57cec5SDimitry Andric     assert(ResTy.isVector());
25160b57cec5SDimitry Andric 
25170b57cec5SDimitry Andric     unsigned NumElts = ResTy.getVectorNumElements();
25180b57cec5SDimitry Andric     SDValue Vector = DAG.getUNDEF(ResTy);
25190b57cec5SDimitry Andric     for (unsigned i = 0; i < NumElts; ++i) {
25200b57cec5SDimitry Andric       Vector = DAG.getNode(ISD::INSERT_VECTOR_ELT, DL, ResTy, Vector,
25210b57cec5SDimitry Andric                            Node->getOperand(i),
25220b57cec5SDimitry Andric                            DAG.getConstant(i, DL, MVT::i32));
25230b57cec5SDimitry Andric     }
25240b57cec5SDimitry Andric     return Vector;
25250b57cec5SDimitry Andric   }
25260b57cec5SDimitry Andric 
25270b57cec5SDimitry Andric   return SDValue();
25280b57cec5SDimitry Andric }
25290b57cec5SDimitry Andric 
25300b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into SHF (if possible).
25310b57cec5SDimitry Andric //
25320b57cec5SDimitry Andric // SHF splits the vector into blocks of four elements, then shuffles these
25330b57cec5SDimitry Andric // elements according to a <4 x i2> constant (encoded as an integer immediate).
25340b57cec5SDimitry Andric //
25350b57cec5SDimitry Andric // It is therefore possible to lower into SHF when the mask takes the form:
25360b57cec5SDimitry Andric //   <a, b, c, d, a+4, b+4, c+4, d+4, a+8, b+8, c+8, d+8, ...>
25370b57cec5SDimitry Andric // When undef's appear they are treated as if they were whatever value is
25380b57cec5SDimitry Andric // necessary in order to fit the above forms.
25390b57cec5SDimitry Andric //
25400b57cec5SDimitry Andric // For example:
25410b57cec5SDimitry Andric //   %2 = shufflevector <8 x i16> %0, <8 x i16> undef,
25420b57cec5SDimitry Andric //                      <8 x i32> <i32 3, i32 2, i32 1, i32 0,
25430b57cec5SDimitry Andric //                                 i32 7, i32 6, i32 5, i32 4>
25440b57cec5SDimitry Andric // is lowered to:
25450b57cec5SDimitry Andric //   (SHF_H $w0, $w1, 27)
25460b57cec5SDimitry Andric // where the 27 comes from:
25470b57cec5SDimitry Andric //   3 + (2 << 2) + (1 << 4) + (0 << 6)
25480b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_SHF(SDValue Op, EVT ResTy,
25490b57cec5SDimitry Andric                                        SmallVector<int, 16> Indices,
25500b57cec5SDimitry Andric                                        SelectionDAG &DAG) {
25510b57cec5SDimitry Andric   int SHFIndices[4] = { -1, -1, -1, -1 };
25520b57cec5SDimitry Andric 
25530b57cec5SDimitry Andric   if (Indices.size() < 4)
25540b57cec5SDimitry Andric     return SDValue();
25550b57cec5SDimitry Andric 
25560b57cec5SDimitry Andric   for (unsigned i = 0; i < 4; ++i) {
25570b57cec5SDimitry Andric     for (unsigned j = i; j < Indices.size(); j += 4) {
25580b57cec5SDimitry Andric       int Idx = Indices[j];
25590b57cec5SDimitry Andric 
25600b57cec5SDimitry Andric       // Convert from vector index to 4-element subvector index
25610b57cec5SDimitry Andric       // If an index refers to an element outside of the subvector then give up
25620b57cec5SDimitry Andric       if (Idx != -1) {
25630b57cec5SDimitry Andric         Idx -= 4 * (j / 4);
25640b57cec5SDimitry Andric         if (Idx < 0 || Idx >= 4)
25650b57cec5SDimitry Andric           return SDValue();
25660b57cec5SDimitry Andric       }
25670b57cec5SDimitry Andric 
25680b57cec5SDimitry Andric       // If the mask has an undef, replace it with the current index.
25690b57cec5SDimitry Andric       // Note that it might still be undef if the current index is also undef
25700b57cec5SDimitry Andric       if (SHFIndices[i] == -1)
25710b57cec5SDimitry Andric         SHFIndices[i] = Idx;
25720b57cec5SDimitry Andric 
25730b57cec5SDimitry Andric       // Check that non-undef values are the same as in the mask. If they
25740b57cec5SDimitry Andric       // aren't then give up
25750b57cec5SDimitry Andric       if (!(Idx == -1 || Idx == SHFIndices[i]))
25760b57cec5SDimitry Andric         return SDValue();
25770b57cec5SDimitry Andric     }
25780b57cec5SDimitry Andric   }
25790b57cec5SDimitry Andric 
25800b57cec5SDimitry Andric   // Calculate the immediate. Replace any remaining undefs with zero
25810b57cec5SDimitry Andric   APInt Imm(32, 0);
25820b57cec5SDimitry Andric   for (int i = 3; i >= 0; --i) {
25830b57cec5SDimitry Andric     int Idx = SHFIndices[i];
25840b57cec5SDimitry Andric 
25850b57cec5SDimitry Andric     if (Idx == -1)
25860b57cec5SDimitry Andric       Idx = 0;
25870b57cec5SDimitry Andric 
25880b57cec5SDimitry Andric     Imm <<= 2;
25890b57cec5SDimitry Andric     Imm |= Idx & 0x3;
25900b57cec5SDimitry Andric   }
25910b57cec5SDimitry Andric 
25920b57cec5SDimitry Andric   SDLoc DL(Op);
25930b57cec5SDimitry Andric   return DAG.getNode(MipsISD::SHF, DL, ResTy,
25948bcb0991SDimitry Andric                      DAG.getTargetConstant(Imm, DL, MVT::i32),
25958bcb0991SDimitry Andric                      Op->getOperand(0));
25960b57cec5SDimitry Andric }
25970b57cec5SDimitry Andric 
25980b57cec5SDimitry Andric /// Determine whether a range fits a regular pattern of values.
25990b57cec5SDimitry Andric /// This function accounts for the possibility of jumping over the End iterator.
26000b57cec5SDimitry Andric template <typename ValType>
26010b57cec5SDimitry Andric static bool
26020b57cec5SDimitry Andric fitsRegularPattern(typename SmallVectorImpl<ValType>::const_iterator Begin,
26030b57cec5SDimitry Andric                    unsigned CheckStride,
26040b57cec5SDimitry Andric                    typename SmallVectorImpl<ValType>::const_iterator End,
26050b57cec5SDimitry Andric                    ValType ExpectedIndex, unsigned ExpectedIndexStride) {
26060b57cec5SDimitry Andric   auto &I = Begin;
26070b57cec5SDimitry Andric 
26080b57cec5SDimitry Andric   while (I != End) {
26090b57cec5SDimitry Andric     if (*I != -1 && *I != ExpectedIndex)
26100b57cec5SDimitry Andric       return false;
26110b57cec5SDimitry Andric     ExpectedIndex += ExpectedIndexStride;
26120b57cec5SDimitry Andric 
26130b57cec5SDimitry Andric     // Incrementing past End is undefined behaviour so we must increment one
26140b57cec5SDimitry Andric     // step at a time and check for End at each step.
26150b57cec5SDimitry Andric     for (unsigned n = 0; n < CheckStride && I != End; ++n, ++I)
26160b57cec5SDimitry Andric       ; // Empty loop body.
26170b57cec5SDimitry Andric   }
26180b57cec5SDimitry Andric   return true;
26190b57cec5SDimitry Andric }
26200b57cec5SDimitry Andric 
26210b57cec5SDimitry Andric // Determine whether VECTOR_SHUFFLE is a SPLATI.
26220b57cec5SDimitry Andric //
26230b57cec5SDimitry Andric // It is a SPLATI when the mask is:
26240b57cec5SDimitry Andric //   <x, x, x, ...>
26250b57cec5SDimitry Andric // where x is any valid index.
26260b57cec5SDimitry Andric //
26270b57cec5SDimitry Andric // When undef's appear in the mask they are treated as if they were whatever
26280b57cec5SDimitry Andric // value is necessary in order to fit the above form.
26290b57cec5SDimitry Andric static bool isVECTOR_SHUFFLE_SPLATI(SDValue Op, EVT ResTy,
26300b57cec5SDimitry Andric                                     SmallVector<int, 16> Indices,
26310b57cec5SDimitry Andric                                     SelectionDAG &DAG) {
26320b57cec5SDimitry Andric   assert((Indices.size() % 2) == 0);
26330b57cec5SDimitry Andric 
26340b57cec5SDimitry Andric   int SplatIndex = -1;
26350b57cec5SDimitry Andric   for (const auto &V : Indices) {
26360b57cec5SDimitry Andric     if (V != -1) {
26370b57cec5SDimitry Andric       SplatIndex = V;
26380b57cec5SDimitry Andric       break;
26390b57cec5SDimitry Andric     }
26400b57cec5SDimitry Andric   }
26410b57cec5SDimitry Andric 
26420b57cec5SDimitry Andric   return fitsRegularPattern<int>(Indices.begin(), 1, Indices.end(), SplatIndex,
26430b57cec5SDimitry Andric                                  0);
26440b57cec5SDimitry Andric }
26450b57cec5SDimitry Andric 
26460b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into ILVEV (if possible).
26470b57cec5SDimitry Andric //
26480b57cec5SDimitry Andric // ILVEV interleaves the even elements from each vector.
26490b57cec5SDimitry Andric //
26500b57cec5SDimitry Andric // It is possible to lower into ILVEV when the mask consists of two of the
26510b57cec5SDimitry Andric // following forms interleaved:
26520b57cec5SDimitry Andric //   <0, 2, 4, ...>
26530b57cec5SDimitry Andric //   <n, n+2, n+4, ...>
26540b57cec5SDimitry Andric // where n is the number of elements in the vector.
26550b57cec5SDimitry Andric // For example:
26560b57cec5SDimitry Andric //   <0, 0, 2, 2, 4, 4, ...>
26570b57cec5SDimitry Andric //   <0, n, 2, n+2, 4, n+4, ...>
26580b57cec5SDimitry Andric //
26590b57cec5SDimitry Andric // When undef's appear in the mask they are treated as if they were whatever
26600b57cec5SDimitry Andric // value is necessary in order to fit the above forms.
26610b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_ILVEV(SDValue Op, EVT ResTy,
26620b57cec5SDimitry Andric                                          SmallVector<int, 16> Indices,
26630b57cec5SDimitry Andric                                          SelectionDAG &DAG) {
26640b57cec5SDimitry Andric   assert((Indices.size() % 2) == 0);
26650b57cec5SDimitry Andric 
26660b57cec5SDimitry Andric   SDValue Wt;
26670b57cec5SDimitry Andric   SDValue Ws;
26680b57cec5SDimitry Andric   const auto &Begin = Indices.begin();
26690b57cec5SDimitry Andric   const auto &End = Indices.end();
26700b57cec5SDimitry Andric 
26710b57cec5SDimitry Andric   // Check even elements are taken from the even elements of one half or the
26720b57cec5SDimitry Andric   // other and pick an operand accordingly.
26730b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, 0, 2))
26740b57cec5SDimitry Andric     Wt = Op->getOperand(0);
26750b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size(), 2))
26760b57cec5SDimitry Andric     Wt = Op->getOperand(1);
26770b57cec5SDimitry Andric   else
26780b57cec5SDimitry Andric     return SDValue();
26790b57cec5SDimitry Andric 
26800b57cec5SDimitry Andric   // Check odd elements are taken from the even elements of one half or the
26810b57cec5SDimitry Andric   // other and pick an operand accordingly.
26820b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 2))
26830b57cec5SDimitry Andric     Ws = Op->getOperand(0);
26840b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size(), 2))
26850b57cec5SDimitry Andric     Ws = Op->getOperand(1);
26860b57cec5SDimitry Andric   else
26870b57cec5SDimitry Andric     return SDValue();
26880b57cec5SDimitry Andric 
26890b57cec5SDimitry Andric   return DAG.getNode(MipsISD::ILVEV, SDLoc(Op), ResTy, Ws, Wt);
26900b57cec5SDimitry Andric }
26910b57cec5SDimitry Andric 
26920b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into ILVOD (if possible).
26930b57cec5SDimitry Andric //
26940b57cec5SDimitry Andric // ILVOD interleaves the odd elements from each vector.
26950b57cec5SDimitry Andric //
26960b57cec5SDimitry Andric // It is possible to lower into ILVOD when the mask consists of two of the
26970b57cec5SDimitry Andric // following forms interleaved:
26980b57cec5SDimitry Andric //   <1, 3, 5, ...>
26990b57cec5SDimitry Andric //   <n+1, n+3, n+5, ...>
27000b57cec5SDimitry Andric // where n is the number of elements in the vector.
27010b57cec5SDimitry Andric // For example:
27020b57cec5SDimitry Andric //   <1, 1, 3, 3, 5, 5, ...>
27030b57cec5SDimitry Andric //   <1, n+1, 3, n+3, 5, n+5, ...>
27040b57cec5SDimitry Andric //
27050b57cec5SDimitry Andric // When undef's appear in the mask they are treated as if they were whatever
27060b57cec5SDimitry Andric // value is necessary in order to fit the above forms.
27070b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_ILVOD(SDValue Op, EVT ResTy,
27080b57cec5SDimitry Andric                                          SmallVector<int, 16> Indices,
27090b57cec5SDimitry Andric                                          SelectionDAG &DAG) {
27100b57cec5SDimitry Andric   assert((Indices.size() % 2) == 0);
27110b57cec5SDimitry Andric 
27120b57cec5SDimitry Andric   SDValue Wt;
27130b57cec5SDimitry Andric   SDValue Ws;
27140b57cec5SDimitry Andric   const auto &Begin = Indices.begin();
27150b57cec5SDimitry Andric   const auto &End = Indices.end();
27160b57cec5SDimitry Andric 
27170b57cec5SDimitry Andric   // Check even elements are taken from the odd elements of one half or the
27180b57cec5SDimitry Andric   // other and pick an operand accordingly.
27190b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, 1, 2))
27200b57cec5SDimitry Andric     Wt = Op->getOperand(0);
27210b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size() + 1, 2))
27220b57cec5SDimitry Andric     Wt = Op->getOperand(1);
27230b57cec5SDimitry Andric   else
27240b57cec5SDimitry Andric     return SDValue();
27250b57cec5SDimitry Andric 
27260b57cec5SDimitry Andric   // Check odd elements are taken from the odd elements of one half or the
27270b57cec5SDimitry Andric   // other and pick an operand accordingly.
27280b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, 1, 2))
27290b57cec5SDimitry Andric     Ws = Op->getOperand(0);
27300b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size() + 1, 2))
27310b57cec5SDimitry Andric     Ws = Op->getOperand(1);
27320b57cec5SDimitry Andric   else
27330b57cec5SDimitry Andric     return SDValue();
27340b57cec5SDimitry Andric 
27350b57cec5SDimitry Andric   return DAG.getNode(MipsISD::ILVOD, SDLoc(Op), ResTy, Wt, Ws);
27360b57cec5SDimitry Andric }
27370b57cec5SDimitry Andric 
27380b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into ILVR (if possible).
27390b57cec5SDimitry Andric //
27400b57cec5SDimitry Andric // ILVR interleaves consecutive elements from the right (lowest-indexed) half of
27410b57cec5SDimitry Andric // each vector.
27420b57cec5SDimitry Andric //
27430b57cec5SDimitry Andric // It is possible to lower into ILVR when the mask consists of two of the
27440b57cec5SDimitry Andric // following forms interleaved:
27450b57cec5SDimitry Andric //   <0, 1, 2, ...>
27460b57cec5SDimitry Andric //   <n, n+1, n+2, ...>
27470b57cec5SDimitry Andric // where n is the number of elements in the vector.
27480b57cec5SDimitry Andric // For example:
27490b57cec5SDimitry Andric //   <0, 0, 1, 1, 2, 2, ...>
27500b57cec5SDimitry Andric //   <0, n, 1, n+1, 2, n+2, ...>
27510b57cec5SDimitry Andric //
27520b57cec5SDimitry Andric // When undef's appear in the mask they are treated as if they were whatever
27530b57cec5SDimitry Andric // value is necessary in order to fit the above forms.
27540b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_ILVR(SDValue Op, EVT ResTy,
27550b57cec5SDimitry Andric                                         SmallVector<int, 16> Indices,
27560b57cec5SDimitry Andric                                         SelectionDAG &DAG) {
27570b57cec5SDimitry Andric   assert((Indices.size() % 2) == 0);
27580b57cec5SDimitry Andric 
27590b57cec5SDimitry Andric   SDValue Wt;
27600b57cec5SDimitry Andric   SDValue Ws;
27610b57cec5SDimitry Andric   const auto &Begin = Indices.begin();
27620b57cec5SDimitry Andric   const auto &End = Indices.end();
27630b57cec5SDimitry Andric 
27640b57cec5SDimitry Andric   // Check even elements are taken from the right (lowest-indexed) elements of
27650b57cec5SDimitry Andric   // one half or the other and pick an operand accordingly.
27660b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, 0, 1))
27670b57cec5SDimitry Andric     Wt = Op->getOperand(0);
27680b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size(), 1))
27690b57cec5SDimitry Andric     Wt = Op->getOperand(1);
27700b57cec5SDimitry Andric   else
27710b57cec5SDimitry Andric     return SDValue();
27720b57cec5SDimitry Andric 
27730b57cec5SDimitry Andric   // Check odd elements are taken from the right (lowest-indexed) elements of
27740b57cec5SDimitry Andric   // one half or the other and pick an operand accordingly.
27750b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, 0, 1))
27760b57cec5SDimitry Andric     Ws = Op->getOperand(0);
27770b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size(), 1))
27780b57cec5SDimitry Andric     Ws = Op->getOperand(1);
27790b57cec5SDimitry Andric   else
27800b57cec5SDimitry Andric     return SDValue();
27810b57cec5SDimitry Andric 
27820b57cec5SDimitry Andric   return DAG.getNode(MipsISD::ILVR, SDLoc(Op), ResTy, Ws, Wt);
27830b57cec5SDimitry Andric }
27840b57cec5SDimitry Andric 
27850b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into ILVL (if possible).
27860b57cec5SDimitry Andric //
27870b57cec5SDimitry Andric // ILVL interleaves consecutive elements from the left (highest-indexed) half
27880b57cec5SDimitry Andric // of each vector.
27890b57cec5SDimitry Andric //
27900b57cec5SDimitry Andric // It is possible to lower into ILVL when the mask consists of two of the
27910b57cec5SDimitry Andric // following forms interleaved:
27920b57cec5SDimitry Andric //   <x, x+1, x+2, ...>
27930b57cec5SDimitry Andric //   <n+x, n+x+1, n+x+2, ...>
27940b57cec5SDimitry Andric // where n is the number of elements in the vector and x is half n.
27950b57cec5SDimitry Andric // For example:
27960b57cec5SDimitry Andric //   <x, x, x+1, x+1, x+2, x+2, ...>
27970b57cec5SDimitry Andric //   <x, n+x, x+1, n+x+1, x+2, n+x+2, ...>
27980b57cec5SDimitry Andric //
27990b57cec5SDimitry Andric // When undef's appear in the mask they are treated as if they were whatever
28000b57cec5SDimitry Andric // value is necessary in order to fit the above forms.
28010b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_ILVL(SDValue Op, EVT ResTy,
28020b57cec5SDimitry Andric                                         SmallVector<int, 16> Indices,
28030b57cec5SDimitry Andric                                         SelectionDAG &DAG) {
28040b57cec5SDimitry Andric   assert((Indices.size() % 2) == 0);
28050b57cec5SDimitry Andric 
28060b57cec5SDimitry Andric   unsigned HalfSize = Indices.size() / 2;
28070b57cec5SDimitry Andric   SDValue Wt;
28080b57cec5SDimitry Andric   SDValue Ws;
28090b57cec5SDimitry Andric   const auto &Begin = Indices.begin();
28100b57cec5SDimitry Andric   const auto &End = Indices.end();
28110b57cec5SDimitry Andric 
28120b57cec5SDimitry Andric   // Check even elements are taken from the left (highest-indexed) elements of
28130b57cec5SDimitry Andric   // one half or the other and pick an operand accordingly.
28140b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin, 2, End, HalfSize, 1))
28150b57cec5SDimitry Andric     Wt = Op->getOperand(0);
28160b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 2, End, Indices.size() + HalfSize, 1))
28170b57cec5SDimitry Andric     Wt = Op->getOperand(1);
28180b57cec5SDimitry Andric   else
28190b57cec5SDimitry Andric     return SDValue();
28200b57cec5SDimitry Andric 
28210b57cec5SDimitry Andric   // Check odd elements are taken from the left (highest-indexed) elements of
28220b57cec5SDimitry Andric   // one half or the other and pick an operand accordingly.
28230b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin + 1, 2, End, HalfSize, 1))
28240b57cec5SDimitry Andric     Ws = Op->getOperand(0);
28250b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin + 1, 2, End, Indices.size() + HalfSize,
28260b57cec5SDimitry Andric                                    1))
28270b57cec5SDimitry Andric     Ws = Op->getOperand(1);
28280b57cec5SDimitry Andric   else
28290b57cec5SDimitry Andric     return SDValue();
28300b57cec5SDimitry Andric 
28310b57cec5SDimitry Andric   return DAG.getNode(MipsISD::ILVL, SDLoc(Op), ResTy, Ws, Wt);
28320b57cec5SDimitry Andric }
28330b57cec5SDimitry Andric 
28340b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into PCKEV (if possible).
28350b57cec5SDimitry Andric //
28360b57cec5SDimitry Andric // PCKEV copies the even elements of each vector into the result vector.
28370b57cec5SDimitry Andric //
28380b57cec5SDimitry Andric // It is possible to lower into PCKEV when the mask consists of two of the
28390b57cec5SDimitry Andric // following forms concatenated:
28400b57cec5SDimitry Andric //   <0, 2, 4, ...>
28410b57cec5SDimitry Andric //   <n, n+2, n+4, ...>
28420b57cec5SDimitry Andric // where n is the number of elements in the vector.
28430b57cec5SDimitry Andric // For example:
28440b57cec5SDimitry Andric //   <0, 2, 4, ..., 0, 2, 4, ...>
28450b57cec5SDimitry Andric //   <0, 2, 4, ..., n, n+2, n+4, ...>
28460b57cec5SDimitry Andric //
28470b57cec5SDimitry Andric // When undef's appear in the mask they are treated as if they were whatever
28480b57cec5SDimitry Andric // value is necessary in order to fit the above forms.
28490b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_PCKEV(SDValue Op, EVT ResTy,
28500b57cec5SDimitry Andric                                          SmallVector<int, 16> Indices,
28510b57cec5SDimitry Andric                                          SelectionDAG &DAG) {
28520b57cec5SDimitry Andric   assert((Indices.size() % 2) == 0);
28530b57cec5SDimitry Andric 
28540b57cec5SDimitry Andric   SDValue Wt;
28550b57cec5SDimitry Andric   SDValue Ws;
28560b57cec5SDimitry Andric   const auto &Begin = Indices.begin();
28570b57cec5SDimitry Andric   const auto &Mid = Indices.begin() + Indices.size() / 2;
28580b57cec5SDimitry Andric   const auto &End = Indices.end();
28590b57cec5SDimitry Andric 
28600b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin, 1, Mid, 0, 2))
28610b57cec5SDimitry Andric     Wt = Op->getOperand(0);
28620b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 1, Mid, Indices.size(), 2))
28630b57cec5SDimitry Andric     Wt = Op->getOperand(1);
28640b57cec5SDimitry Andric   else
28650b57cec5SDimitry Andric     return SDValue();
28660b57cec5SDimitry Andric 
28670b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Mid, 1, End, 0, 2))
28680b57cec5SDimitry Andric     Ws = Op->getOperand(0);
28690b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Mid, 1, End, Indices.size(), 2))
28700b57cec5SDimitry Andric     Ws = Op->getOperand(1);
28710b57cec5SDimitry Andric   else
28720b57cec5SDimitry Andric     return SDValue();
28730b57cec5SDimitry Andric 
28740b57cec5SDimitry Andric   return DAG.getNode(MipsISD::PCKEV, SDLoc(Op), ResTy, Ws, Wt);
28750b57cec5SDimitry Andric }
28760b57cec5SDimitry Andric 
28770b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into PCKOD (if possible).
28780b57cec5SDimitry Andric //
28790b57cec5SDimitry Andric // PCKOD copies the odd elements of each vector into the result vector.
28800b57cec5SDimitry Andric //
28810b57cec5SDimitry Andric // It is possible to lower into PCKOD when the mask consists of two of the
28820b57cec5SDimitry Andric // following forms concatenated:
28830b57cec5SDimitry Andric //   <1, 3, 5, ...>
28840b57cec5SDimitry Andric //   <n+1, n+3, n+5, ...>
28850b57cec5SDimitry Andric // where n is the number of elements in the vector.
28860b57cec5SDimitry Andric // For example:
28870b57cec5SDimitry Andric //   <1, 3, 5, ..., 1, 3, 5, ...>
28880b57cec5SDimitry Andric //   <1, 3, 5, ..., n+1, n+3, n+5, ...>
28890b57cec5SDimitry Andric //
28900b57cec5SDimitry Andric // When undef's appear in the mask they are treated as if they were whatever
28910b57cec5SDimitry Andric // value is necessary in order to fit the above forms.
28920b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_PCKOD(SDValue Op, EVT ResTy,
28930b57cec5SDimitry Andric                                          SmallVector<int, 16> Indices,
28940b57cec5SDimitry Andric                                          SelectionDAG &DAG) {
28950b57cec5SDimitry Andric   assert((Indices.size() % 2) == 0);
28960b57cec5SDimitry Andric 
28970b57cec5SDimitry Andric   SDValue Wt;
28980b57cec5SDimitry Andric   SDValue Ws;
28990b57cec5SDimitry Andric   const auto &Begin = Indices.begin();
29000b57cec5SDimitry Andric   const auto &Mid = Indices.begin() + Indices.size() / 2;
29010b57cec5SDimitry Andric   const auto &End = Indices.end();
29020b57cec5SDimitry Andric 
29030b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Begin, 1, Mid, 1, 2))
29040b57cec5SDimitry Andric     Wt = Op->getOperand(0);
29050b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Begin, 1, Mid, Indices.size() + 1, 2))
29060b57cec5SDimitry Andric     Wt = Op->getOperand(1);
29070b57cec5SDimitry Andric   else
29080b57cec5SDimitry Andric     return SDValue();
29090b57cec5SDimitry Andric 
29100b57cec5SDimitry Andric   if (fitsRegularPattern<int>(Mid, 1, End, 1, 2))
29110b57cec5SDimitry Andric     Ws = Op->getOperand(0);
29120b57cec5SDimitry Andric   else if (fitsRegularPattern<int>(Mid, 1, End, Indices.size() + 1, 2))
29130b57cec5SDimitry Andric     Ws = Op->getOperand(1);
29140b57cec5SDimitry Andric   else
29150b57cec5SDimitry Andric     return SDValue();
29160b57cec5SDimitry Andric 
29170b57cec5SDimitry Andric   return DAG.getNode(MipsISD::PCKOD, SDLoc(Op), ResTy, Ws, Wt);
29180b57cec5SDimitry Andric }
29190b57cec5SDimitry Andric 
29200b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into VSHF.
29210b57cec5SDimitry Andric //
29220b57cec5SDimitry Andric // This mostly consists of converting the shuffle indices in Indices into a
29230b57cec5SDimitry Andric // BUILD_VECTOR and adding it as an operand to the resulting VSHF. There is
29240b57cec5SDimitry Andric // also code to eliminate unused operands of the VECTOR_SHUFFLE. For example,
29250b57cec5SDimitry Andric // if the type is v8i16 and all the indices are less than 8 then the second
29260b57cec5SDimitry Andric // operand is unused and can be replaced with anything. We choose to replace it
29270b57cec5SDimitry Andric // with the used operand since this reduces the number of instructions overall.
29280b57cec5SDimitry Andric static SDValue lowerVECTOR_SHUFFLE_VSHF(SDValue Op, EVT ResTy,
292904eeddc0SDimitry Andric                                         const SmallVector<int, 16> &Indices,
29300b57cec5SDimitry Andric                                         SelectionDAG &DAG) {
29310b57cec5SDimitry Andric   SmallVector<SDValue, 16> Ops;
29320b57cec5SDimitry Andric   SDValue Op0;
29330b57cec5SDimitry Andric   SDValue Op1;
29340b57cec5SDimitry Andric   EVT MaskVecTy = ResTy.changeVectorElementTypeToInteger();
29350b57cec5SDimitry Andric   EVT MaskEltTy = MaskVecTy.getVectorElementType();
29360b57cec5SDimitry Andric   bool Using1stVec = false;
29370b57cec5SDimitry Andric   bool Using2ndVec = false;
29380b57cec5SDimitry Andric   SDLoc DL(Op);
29390b57cec5SDimitry Andric   int ResTyNumElts = ResTy.getVectorNumElements();
29400b57cec5SDimitry Andric 
29410b57cec5SDimitry Andric   for (int i = 0; i < ResTyNumElts; ++i) {
29420b57cec5SDimitry Andric     // Idx == -1 means UNDEF
29430b57cec5SDimitry Andric     int Idx = Indices[i];
29440b57cec5SDimitry Andric 
29450b57cec5SDimitry Andric     if (0 <= Idx && Idx < ResTyNumElts)
29460b57cec5SDimitry Andric       Using1stVec = true;
29470b57cec5SDimitry Andric     if (ResTyNumElts <= Idx && Idx < ResTyNumElts * 2)
29480b57cec5SDimitry Andric       Using2ndVec = true;
29490b57cec5SDimitry Andric   }
29500b57cec5SDimitry Andric 
295104eeddc0SDimitry Andric   for (int Idx : Indices)
295204eeddc0SDimitry Andric     Ops.push_back(DAG.getTargetConstant(Idx, DL, MaskEltTy));
29530b57cec5SDimitry Andric 
29540b57cec5SDimitry Andric   SDValue MaskVec = DAG.getBuildVector(MaskVecTy, DL, Ops);
29550b57cec5SDimitry Andric 
29560b57cec5SDimitry Andric   if (Using1stVec && Using2ndVec) {
29570b57cec5SDimitry Andric     Op0 = Op->getOperand(0);
29580b57cec5SDimitry Andric     Op1 = Op->getOperand(1);
29590b57cec5SDimitry Andric   } else if (Using1stVec)
29600b57cec5SDimitry Andric     Op0 = Op1 = Op->getOperand(0);
29610b57cec5SDimitry Andric   else if (Using2ndVec)
29620b57cec5SDimitry Andric     Op0 = Op1 = Op->getOperand(1);
29630b57cec5SDimitry Andric   else
29640b57cec5SDimitry Andric     llvm_unreachable("shuffle vector mask references neither vector operand?");
29650b57cec5SDimitry Andric 
29660b57cec5SDimitry Andric   // VECTOR_SHUFFLE concatenates the vectors in an vectorwise fashion.
29670b57cec5SDimitry Andric   // <0b00, 0b01> + <0b10, 0b11> -> <0b00, 0b01, 0b10, 0b11>
29680b57cec5SDimitry Andric   // VSHF concatenates the vectors in a bitwise fashion:
29690b57cec5SDimitry Andric   // <0b00, 0b01> + <0b10, 0b11> ->
29700b57cec5SDimitry Andric   // 0b0100       + 0b1110       -> 0b01001110
29710b57cec5SDimitry Andric   //                                <0b10, 0b11, 0b00, 0b01>
29720b57cec5SDimitry Andric   // We must therefore swap the operands to get the correct result.
29730b57cec5SDimitry Andric   return DAG.getNode(MipsISD::VSHF, DL, ResTy, MaskVec, Op1, Op0);
29740b57cec5SDimitry Andric }
29750b57cec5SDimitry Andric 
29760b57cec5SDimitry Andric // Lower VECTOR_SHUFFLE into one of a number of instructions depending on the
29770b57cec5SDimitry Andric // indices in the shuffle.
29780b57cec5SDimitry Andric SDValue MipsSETargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
29790b57cec5SDimitry Andric                                                   SelectionDAG &DAG) const {
29800b57cec5SDimitry Andric   ShuffleVectorSDNode *Node = cast<ShuffleVectorSDNode>(Op);
29810b57cec5SDimitry Andric   EVT ResTy = Op->getValueType(0);
29820b57cec5SDimitry Andric 
29830b57cec5SDimitry Andric   if (!ResTy.is128BitVector())
29840b57cec5SDimitry Andric     return SDValue();
29850b57cec5SDimitry Andric 
29860b57cec5SDimitry Andric   int ResTyNumElts = ResTy.getVectorNumElements();
29870b57cec5SDimitry Andric   SmallVector<int, 16> Indices;
29880b57cec5SDimitry Andric 
29890b57cec5SDimitry Andric   for (int i = 0; i < ResTyNumElts; ++i)
29900b57cec5SDimitry Andric     Indices.push_back(Node->getMaskElt(i));
29910b57cec5SDimitry Andric 
29920b57cec5SDimitry Andric   // splati.[bhwd] is preferable to the others but is matched from
29930b57cec5SDimitry Andric   // MipsISD::VSHF.
29940b57cec5SDimitry Andric   if (isVECTOR_SHUFFLE_SPLATI(Op, ResTy, Indices, DAG))
29950b57cec5SDimitry Andric     return lowerVECTOR_SHUFFLE_VSHF(Op, ResTy, Indices, DAG);
29960b57cec5SDimitry Andric   SDValue Result;
29970b57cec5SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_ILVEV(Op, ResTy, Indices, DAG)))
29980b57cec5SDimitry Andric     return Result;
29990b57cec5SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_ILVOD(Op, ResTy, Indices, DAG)))
30000b57cec5SDimitry Andric     return Result;
30010b57cec5SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_ILVL(Op, ResTy, Indices, DAG)))
30020b57cec5SDimitry Andric     return Result;
30030b57cec5SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_ILVR(Op, ResTy, Indices, DAG)))
30040b57cec5SDimitry Andric     return Result;
30050b57cec5SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_PCKEV(Op, ResTy, Indices, DAG)))
30060b57cec5SDimitry Andric     return Result;
30070b57cec5SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_PCKOD(Op, ResTy, Indices, DAG)))
30080b57cec5SDimitry Andric     return Result;
30090b57cec5SDimitry Andric   if ((Result = lowerVECTOR_SHUFFLE_SHF(Op, ResTy, Indices, DAG)))
30100b57cec5SDimitry Andric     return Result;
30110b57cec5SDimitry Andric   return lowerVECTOR_SHUFFLE_VSHF(Op, ResTy, Indices, DAG);
30120b57cec5SDimitry Andric }
30130b57cec5SDimitry Andric 
30140b57cec5SDimitry Andric MachineBasicBlock *
30150b57cec5SDimitry Andric MipsSETargetLowering::emitBPOSGE32(MachineInstr &MI,
30160b57cec5SDimitry Andric                                    MachineBasicBlock *BB) const {
30170b57cec5SDimitry Andric   // $bb:
30180b57cec5SDimitry Andric   //  bposge32_pseudo $vr0
30190b57cec5SDimitry Andric   //  =>
30200b57cec5SDimitry Andric   // $bb:
30210b57cec5SDimitry Andric   //  bposge32 $tbb
30220b57cec5SDimitry Andric   // $fbb:
30230b57cec5SDimitry Andric   //  li $vr2, 0
30240b57cec5SDimitry Andric   //  b $sink
30250b57cec5SDimitry Andric   // $tbb:
30260b57cec5SDimitry Andric   //  li $vr1, 1
30270b57cec5SDimitry Andric   // $sink:
30280b57cec5SDimitry Andric   //  $vr0 = phi($vr2, $fbb, $vr1, $tbb)
30290b57cec5SDimitry Andric 
30300b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
30310b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
30320b57cec5SDimitry Andric   const TargetRegisterClass *RC = &Mips::GPR32RegClass;
30330b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
30340b57cec5SDimitry Andric   const BasicBlock *LLVM_BB = BB->getBasicBlock();
30350b57cec5SDimitry Andric   MachineFunction::iterator It = std::next(MachineFunction::iterator(BB));
30360b57cec5SDimitry Andric   MachineFunction *F = BB->getParent();
30370b57cec5SDimitry Andric   MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB);
30380b57cec5SDimitry Andric   MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB);
30390b57cec5SDimitry Andric   MachineBasicBlock *Sink  = F->CreateMachineBasicBlock(LLVM_BB);
30400b57cec5SDimitry Andric   F->insert(It, FBB);
30410b57cec5SDimitry Andric   F->insert(It, TBB);
30420b57cec5SDimitry Andric   F->insert(It, Sink);
30430b57cec5SDimitry Andric 
30440b57cec5SDimitry Andric   // Transfer the remainder of BB and its successor edges to Sink.
30450b57cec5SDimitry Andric   Sink->splice(Sink->begin(), BB, std::next(MachineBasicBlock::iterator(MI)),
30460b57cec5SDimitry Andric                BB->end());
30470b57cec5SDimitry Andric   Sink->transferSuccessorsAndUpdatePHIs(BB);
30480b57cec5SDimitry Andric 
30490b57cec5SDimitry Andric   // Add successors.
30500b57cec5SDimitry Andric   BB->addSuccessor(FBB);
30510b57cec5SDimitry Andric   BB->addSuccessor(TBB);
30520b57cec5SDimitry Andric   FBB->addSuccessor(Sink);
30530b57cec5SDimitry Andric   TBB->addSuccessor(Sink);
30540b57cec5SDimitry Andric 
30550b57cec5SDimitry Andric   // Insert the real bposge32 instruction to $BB.
30560b57cec5SDimitry Andric   BuildMI(BB, DL, TII->get(Mips::BPOSGE32)).addMBB(TBB);
30570b57cec5SDimitry Andric   // Insert the real bposge32c instruction to $BB.
30580b57cec5SDimitry Andric   BuildMI(BB, DL, TII->get(Mips::BPOSGE32C_MMR3)).addMBB(TBB);
30590b57cec5SDimitry Andric 
30600b57cec5SDimitry Andric   // Fill $FBB.
30618bcb0991SDimitry Andric   Register VR2 = RegInfo.createVirtualRegister(RC);
30620b57cec5SDimitry Andric   BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), VR2)
30630b57cec5SDimitry Andric     .addReg(Mips::ZERO).addImm(0);
30640b57cec5SDimitry Andric   BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink);
30650b57cec5SDimitry Andric 
30660b57cec5SDimitry Andric   // Fill $TBB.
30678bcb0991SDimitry Andric   Register VR1 = RegInfo.createVirtualRegister(RC);
30680b57cec5SDimitry Andric   BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), VR1)
30690b57cec5SDimitry Andric     .addReg(Mips::ZERO).addImm(1);
30700b57cec5SDimitry Andric 
30710b57cec5SDimitry Andric   // Insert phi function to $Sink.
30720b57cec5SDimitry Andric   BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI),
30730b57cec5SDimitry Andric           MI.getOperand(0).getReg())
30740b57cec5SDimitry Andric       .addReg(VR2)
30750b57cec5SDimitry Andric       .addMBB(FBB)
30760b57cec5SDimitry Andric       .addReg(VR1)
30770b57cec5SDimitry Andric       .addMBB(TBB);
30780b57cec5SDimitry Andric 
30790b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
30800b57cec5SDimitry Andric   return Sink;
30810b57cec5SDimitry Andric }
30820b57cec5SDimitry Andric 
30830b57cec5SDimitry Andric MachineBasicBlock *MipsSETargetLowering::emitMSACBranchPseudo(
30840b57cec5SDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB, unsigned BranchOp) const {
30850b57cec5SDimitry Andric   // $bb:
30860b57cec5SDimitry Andric   //  vany_nonzero $rd, $ws
30870b57cec5SDimitry Andric   //  =>
30880b57cec5SDimitry Andric   // $bb:
30890b57cec5SDimitry Andric   //  bnz.b $ws, $tbb
30900b57cec5SDimitry Andric   //  b $fbb
30910b57cec5SDimitry Andric   // $fbb:
30920b57cec5SDimitry Andric   //  li $rd1, 0
30930b57cec5SDimitry Andric   //  b $sink
30940b57cec5SDimitry Andric   // $tbb:
30950b57cec5SDimitry Andric   //  li $rd2, 1
30960b57cec5SDimitry Andric   // $sink:
30970b57cec5SDimitry Andric   //  $rd = phi($rd1, $fbb, $rd2, $tbb)
30980b57cec5SDimitry Andric 
30990b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
31000b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
31010b57cec5SDimitry Andric   const TargetRegisterClass *RC = &Mips::GPR32RegClass;
31020b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
31030b57cec5SDimitry Andric   const BasicBlock *LLVM_BB = BB->getBasicBlock();
31040b57cec5SDimitry Andric   MachineFunction::iterator It = std::next(MachineFunction::iterator(BB));
31050b57cec5SDimitry Andric   MachineFunction *F = BB->getParent();
31060b57cec5SDimitry Andric   MachineBasicBlock *FBB = F->CreateMachineBasicBlock(LLVM_BB);
31070b57cec5SDimitry Andric   MachineBasicBlock *TBB = F->CreateMachineBasicBlock(LLVM_BB);
31080b57cec5SDimitry Andric   MachineBasicBlock *Sink  = F->CreateMachineBasicBlock(LLVM_BB);
31090b57cec5SDimitry Andric   F->insert(It, FBB);
31100b57cec5SDimitry Andric   F->insert(It, TBB);
31110b57cec5SDimitry Andric   F->insert(It, Sink);
31120b57cec5SDimitry Andric 
31130b57cec5SDimitry Andric   // Transfer the remainder of BB and its successor edges to Sink.
31140b57cec5SDimitry Andric   Sink->splice(Sink->begin(), BB, std::next(MachineBasicBlock::iterator(MI)),
31150b57cec5SDimitry Andric                BB->end());
31160b57cec5SDimitry Andric   Sink->transferSuccessorsAndUpdatePHIs(BB);
31170b57cec5SDimitry Andric 
31180b57cec5SDimitry Andric   // Add successors.
31190b57cec5SDimitry Andric   BB->addSuccessor(FBB);
31200b57cec5SDimitry Andric   BB->addSuccessor(TBB);
31210b57cec5SDimitry Andric   FBB->addSuccessor(Sink);
31220b57cec5SDimitry Andric   TBB->addSuccessor(Sink);
31230b57cec5SDimitry Andric 
31240b57cec5SDimitry Andric   // Insert the real bnz.b instruction to $BB.
31250b57cec5SDimitry Andric   BuildMI(BB, DL, TII->get(BranchOp))
31260b57cec5SDimitry Andric       .addReg(MI.getOperand(1).getReg())
31270b57cec5SDimitry Andric       .addMBB(TBB);
31280b57cec5SDimitry Andric 
31290b57cec5SDimitry Andric   // Fill $FBB.
31308bcb0991SDimitry Andric   Register RD1 = RegInfo.createVirtualRegister(RC);
31310b57cec5SDimitry Andric   BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::ADDiu), RD1)
31320b57cec5SDimitry Andric     .addReg(Mips::ZERO).addImm(0);
31330b57cec5SDimitry Andric   BuildMI(*FBB, FBB->end(), DL, TII->get(Mips::B)).addMBB(Sink);
31340b57cec5SDimitry Andric 
31350b57cec5SDimitry Andric   // Fill $TBB.
31368bcb0991SDimitry Andric   Register RD2 = RegInfo.createVirtualRegister(RC);
31370b57cec5SDimitry Andric   BuildMI(*TBB, TBB->end(), DL, TII->get(Mips::ADDiu), RD2)
31380b57cec5SDimitry Andric     .addReg(Mips::ZERO).addImm(1);
31390b57cec5SDimitry Andric 
31400b57cec5SDimitry Andric   // Insert phi function to $Sink.
31410b57cec5SDimitry Andric   BuildMI(*Sink, Sink->begin(), DL, TII->get(Mips::PHI),
31420b57cec5SDimitry Andric           MI.getOperand(0).getReg())
31430b57cec5SDimitry Andric       .addReg(RD1)
31440b57cec5SDimitry Andric       .addMBB(FBB)
31450b57cec5SDimitry Andric       .addReg(RD2)
31460b57cec5SDimitry Andric       .addMBB(TBB);
31470b57cec5SDimitry Andric 
31480b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
31490b57cec5SDimitry Andric   return Sink;
31500b57cec5SDimitry Andric }
31510b57cec5SDimitry Andric 
31520b57cec5SDimitry Andric // Emit the COPY_FW pseudo instruction.
31530b57cec5SDimitry Andric //
31540b57cec5SDimitry Andric // copy_fw_pseudo $fd, $ws, n
31550b57cec5SDimitry Andric // =>
31560b57cec5SDimitry Andric // copy_u_w $rt, $ws, $n
31570b57cec5SDimitry Andric // mtc1     $rt, $fd
31580b57cec5SDimitry Andric //
31590b57cec5SDimitry Andric // When n is zero, the equivalent operation can be performed with (potentially)
31600b57cec5SDimitry Andric // zero instructions due to register overlaps. This optimization is never valid
31610b57cec5SDimitry Andric // for lane 1 because it would require FR=0 mode which isn't supported by MSA.
31620b57cec5SDimitry Andric MachineBasicBlock *
31630b57cec5SDimitry Andric MipsSETargetLowering::emitCOPY_FW(MachineInstr &MI,
31640b57cec5SDimitry Andric                                   MachineBasicBlock *BB) const {
31650b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
31660b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
31670b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
31688bcb0991SDimitry Andric   Register Fd = MI.getOperand(0).getReg();
31698bcb0991SDimitry Andric   Register Ws = MI.getOperand(1).getReg();
31700b57cec5SDimitry Andric   unsigned Lane = MI.getOperand(2).getImm();
31710b57cec5SDimitry Andric 
31720b57cec5SDimitry Andric   if (Lane == 0) {
31730b57cec5SDimitry Andric     unsigned Wt = Ws;
31740b57cec5SDimitry Andric     if (!Subtarget.useOddSPReg()) {
31750b57cec5SDimitry Andric       // We must copy to an even-numbered MSA register so that the
31760b57cec5SDimitry Andric       // single-precision sub-register is also guaranteed to be even-numbered.
31770b57cec5SDimitry Andric       Wt = RegInfo.createVirtualRegister(&Mips::MSA128WEvensRegClass);
31780b57cec5SDimitry Andric 
31790b57cec5SDimitry Andric       BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Wt).addReg(Ws);
31800b57cec5SDimitry Andric     }
31810b57cec5SDimitry Andric 
31820b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_lo);
31830b57cec5SDimitry Andric   } else {
31848bcb0991SDimitry Andric     Register Wt = RegInfo.createVirtualRegister(
31858bcb0991SDimitry Andric         Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass
31868bcb0991SDimitry Andric                                 : &Mips::MSA128WEvensRegClass);
31870b57cec5SDimitry Andric 
31880b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_W), Wt).addReg(Ws).addImm(Lane);
31890b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_lo);
31900b57cec5SDimitry Andric   }
31910b57cec5SDimitry Andric 
31920b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
31930b57cec5SDimitry Andric   return BB;
31940b57cec5SDimitry Andric }
31950b57cec5SDimitry Andric 
31960b57cec5SDimitry Andric // Emit the COPY_FD pseudo instruction.
31970b57cec5SDimitry Andric //
31980b57cec5SDimitry Andric // copy_fd_pseudo $fd, $ws, n
31990b57cec5SDimitry Andric // =>
32000b57cec5SDimitry Andric // splati.d $wt, $ws, $n
32010b57cec5SDimitry Andric // copy $fd, $wt:sub_64
32020b57cec5SDimitry Andric //
32030b57cec5SDimitry Andric // When n is zero, the equivalent operation can be performed with (potentially)
32040b57cec5SDimitry Andric // zero instructions due to register overlaps. This optimization is always
32050b57cec5SDimitry Andric // valid because FR=1 mode which is the only supported mode in MSA.
32060b57cec5SDimitry Andric MachineBasicBlock *
32070b57cec5SDimitry Andric MipsSETargetLowering::emitCOPY_FD(MachineInstr &MI,
32080b57cec5SDimitry Andric                                   MachineBasicBlock *BB) const {
32090b57cec5SDimitry Andric   assert(Subtarget.isFP64bit());
32100b57cec5SDimitry Andric 
32110b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
32120b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
32138bcb0991SDimitry Andric   Register Fd = MI.getOperand(0).getReg();
32148bcb0991SDimitry Andric   Register Ws = MI.getOperand(1).getReg();
32150b57cec5SDimitry Andric   unsigned Lane = MI.getOperand(2).getImm() * 2;
32160b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
32170b57cec5SDimitry Andric 
32180b57cec5SDimitry Andric   if (Lane == 0)
32190b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Ws, 0, Mips::sub_64);
32200b57cec5SDimitry Andric   else {
32218bcb0991SDimitry Andric     Register Wt = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass);
32220b57cec5SDimitry Andric 
32230b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_D), Wt).addReg(Ws).addImm(1);
32240b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Fd).addReg(Wt, 0, Mips::sub_64);
32250b57cec5SDimitry Andric   }
32260b57cec5SDimitry Andric 
32270b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
32280b57cec5SDimitry Andric   return BB;
32290b57cec5SDimitry Andric }
32300b57cec5SDimitry Andric 
32310b57cec5SDimitry Andric // Emit the INSERT_FW pseudo instruction.
32320b57cec5SDimitry Andric //
32330b57cec5SDimitry Andric // insert_fw_pseudo $wd, $wd_in, $n, $fs
32340b57cec5SDimitry Andric // =>
32350b57cec5SDimitry Andric // subreg_to_reg $wt:sub_lo, $fs
32360b57cec5SDimitry Andric // insve_w $wd[$n], $wd_in, $wt[0]
32370b57cec5SDimitry Andric MachineBasicBlock *
32380b57cec5SDimitry Andric MipsSETargetLowering::emitINSERT_FW(MachineInstr &MI,
32390b57cec5SDimitry Andric                                     MachineBasicBlock *BB) const {
32400b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
32410b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
32420b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
32438bcb0991SDimitry Andric   Register Wd = MI.getOperand(0).getReg();
32448bcb0991SDimitry Andric   Register Wd_in = MI.getOperand(1).getReg();
32450b57cec5SDimitry Andric   unsigned Lane = MI.getOperand(2).getImm();
32468bcb0991SDimitry Andric   Register Fs = MI.getOperand(3).getReg();
32478bcb0991SDimitry Andric   Register Wt = RegInfo.createVirtualRegister(
32488bcb0991SDimitry Andric       Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass
32498bcb0991SDimitry Andric                               : &Mips::MSA128WEvensRegClass);
32500b57cec5SDimitry Andric 
32510b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt)
32520b57cec5SDimitry Andric       .addImm(0)
32530b57cec5SDimitry Andric       .addReg(Fs)
32540b57cec5SDimitry Andric       .addImm(Mips::sub_lo);
32550b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_W), Wd)
32560b57cec5SDimitry Andric       .addReg(Wd_in)
32570b57cec5SDimitry Andric       .addImm(Lane)
32580b57cec5SDimitry Andric       .addReg(Wt)
32590b57cec5SDimitry Andric       .addImm(0);
32600b57cec5SDimitry Andric 
32610b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
32620b57cec5SDimitry Andric   return BB;
32630b57cec5SDimitry Andric }
32640b57cec5SDimitry Andric 
32650b57cec5SDimitry Andric // Emit the INSERT_FD pseudo instruction.
32660b57cec5SDimitry Andric //
32670b57cec5SDimitry Andric // insert_fd_pseudo $wd, $fs, n
32680b57cec5SDimitry Andric // =>
32690b57cec5SDimitry Andric // subreg_to_reg $wt:sub_64, $fs
32700b57cec5SDimitry Andric // insve_d $wd[$n], $wd_in, $wt[0]
32710b57cec5SDimitry Andric MachineBasicBlock *
32720b57cec5SDimitry Andric MipsSETargetLowering::emitINSERT_FD(MachineInstr &MI,
32730b57cec5SDimitry Andric                                     MachineBasicBlock *BB) const {
32740b57cec5SDimitry Andric   assert(Subtarget.isFP64bit());
32750b57cec5SDimitry Andric 
32760b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
32770b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
32780b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
32798bcb0991SDimitry Andric   Register Wd = MI.getOperand(0).getReg();
32808bcb0991SDimitry Andric   Register Wd_in = MI.getOperand(1).getReg();
32810b57cec5SDimitry Andric   unsigned Lane = MI.getOperand(2).getImm();
32828bcb0991SDimitry Andric   Register Fs = MI.getOperand(3).getReg();
32838bcb0991SDimitry Andric   Register Wt = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass);
32840b57cec5SDimitry Andric 
32850b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt)
32860b57cec5SDimitry Andric       .addImm(0)
32870b57cec5SDimitry Andric       .addReg(Fs)
32880b57cec5SDimitry Andric       .addImm(Mips::sub_64);
32890b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::INSVE_D), Wd)
32900b57cec5SDimitry Andric       .addReg(Wd_in)
32910b57cec5SDimitry Andric       .addImm(Lane)
32920b57cec5SDimitry Andric       .addReg(Wt)
32930b57cec5SDimitry Andric       .addImm(0);
32940b57cec5SDimitry Andric 
32950b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
32960b57cec5SDimitry Andric   return BB;
32970b57cec5SDimitry Andric }
32980b57cec5SDimitry Andric 
32990b57cec5SDimitry Andric // Emit the INSERT_([BHWD]|F[WD])_VIDX pseudo instruction.
33000b57cec5SDimitry Andric //
33010b57cec5SDimitry Andric // For integer:
33020b57cec5SDimitry Andric // (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $rs)
33030b57cec5SDimitry Andric // =>
33040b57cec5SDimitry Andric // (SLL $lanetmp1, $lane, <log2size)
33050b57cec5SDimitry Andric // (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1)
33060b57cec5SDimitry Andric // (INSERT_[BHWD], $wdtmp2, $wdtmp1, 0, $rs)
33070b57cec5SDimitry Andric // (NEG $lanetmp2, $lanetmp1)
33080b57cec5SDimitry Andric // (SLD_B $wd, $wdtmp2, $wdtmp2,  $lanetmp2)
33090b57cec5SDimitry Andric //
33100b57cec5SDimitry Andric // For floating point:
33110b57cec5SDimitry Andric // (INSERT_([BHWD]|F[WD])_PSEUDO $wd, $wd_in, $n, $fs)
33120b57cec5SDimitry Andric // =>
33130b57cec5SDimitry Andric // (SUBREG_TO_REG $wt, $fs, <subreg>)
33140b57cec5SDimitry Andric // (SLL $lanetmp1, $lane, <log2size)
33150b57cec5SDimitry Andric // (SLD_B $wdtmp1, $wd_in, $wd_in, $lanetmp1)
33160b57cec5SDimitry Andric // (INSVE_[WD], $wdtmp2, 0, $wdtmp1, 0)
33170b57cec5SDimitry Andric // (NEG $lanetmp2, $lanetmp1)
33180b57cec5SDimitry Andric // (SLD_B $wd, $wdtmp2, $wdtmp2,  $lanetmp2)
33190b57cec5SDimitry Andric MachineBasicBlock *MipsSETargetLowering::emitINSERT_DF_VIDX(
33200b57cec5SDimitry Andric     MachineInstr &MI, MachineBasicBlock *BB, unsigned EltSizeInBytes,
33210b57cec5SDimitry Andric     bool IsFP) const {
33220b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
33230b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
33240b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
33258bcb0991SDimitry Andric   Register Wd = MI.getOperand(0).getReg();
33268bcb0991SDimitry Andric   Register SrcVecReg = MI.getOperand(1).getReg();
33278bcb0991SDimitry Andric   Register LaneReg = MI.getOperand(2).getReg();
33288bcb0991SDimitry Andric   Register SrcValReg = MI.getOperand(3).getReg();
33290b57cec5SDimitry Andric 
33300b57cec5SDimitry Andric   const TargetRegisterClass *VecRC = nullptr;
33310b57cec5SDimitry Andric   // FIXME: This should be true for N32 too.
33320b57cec5SDimitry Andric   const TargetRegisterClass *GPRRC =
33330b57cec5SDimitry Andric       Subtarget.isABI_N64() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass;
33340b57cec5SDimitry Andric   unsigned SubRegIdx = Subtarget.isABI_N64() ? Mips::sub_32 : 0;
33350b57cec5SDimitry Andric   unsigned ShiftOp = Subtarget.isABI_N64() ? Mips::DSLL : Mips::SLL;
33360b57cec5SDimitry Andric   unsigned EltLog2Size;
33370b57cec5SDimitry Andric   unsigned InsertOp = 0;
33380b57cec5SDimitry Andric   unsigned InsveOp = 0;
33390b57cec5SDimitry Andric   switch (EltSizeInBytes) {
33400b57cec5SDimitry Andric   default:
33410b57cec5SDimitry Andric     llvm_unreachable("Unexpected size");
33420b57cec5SDimitry Andric   case 1:
33430b57cec5SDimitry Andric     EltLog2Size = 0;
33440b57cec5SDimitry Andric     InsertOp = Mips::INSERT_B;
33450b57cec5SDimitry Andric     InsveOp = Mips::INSVE_B;
33460b57cec5SDimitry Andric     VecRC = &Mips::MSA128BRegClass;
33470b57cec5SDimitry Andric     break;
33480b57cec5SDimitry Andric   case 2:
33490b57cec5SDimitry Andric     EltLog2Size = 1;
33500b57cec5SDimitry Andric     InsertOp = Mips::INSERT_H;
33510b57cec5SDimitry Andric     InsveOp = Mips::INSVE_H;
33520b57cec5SDimitry Andric     VecRC = &Mips::MSA128HRegClass;
33530b57cec5SDimitry Andric     break;
33540b57cec5SDimitry Andric   case 4:
33550b57cec5SDimitry Andric     EltLog2Size = 2;
33560b57cec5SDimitry Andric     InsertOp = Mips::INSERT_W;
33570b57cec5SDimitry Andric     InsveOp = Mips::INSVE_W;
33580b57cec5SDimitry Andric     VecRC = &Mips::MSA128WRegClass;
33590b57cec5SDimitry Andric     break;
33600b57cec5SDimitry Andric   case 8:
33610b57cec5SDimitry Andric     EltLog2Size = 3;
33620b57cec5SDimitry Andric     InsertOp = Mips::INSERT_D;
33630b57cec5SDimitry Andric     InsveOp = Mips::INSVE_D;
33640b57cec5SDimitry Andric     VecRC = &Mips::MSA128DRegClass;
33650b57cec5SDimitry Andric     break;
33660b57cec5SDimitry Andric   }
33670b57cec5SDimitry Andric 
33680b57cec5SDimitry Andric   if (IsFP) {
33698bcb0991SDimitry Andric     Register Wt = RegInfo.createVirtualRegister(VecRC);
33700b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Wt)
33710b57cec5SDimitry Andric         .addImm(0)
33720b57cec5SDimitry Andric         .addReg(SrcValReg)
33730b57cec5SDimitry Andric         .addImm(EltSizeInBytes == 8 ? Mips::sub_64 : Mips::sub_lo);
33740b57cec5SDimitry Andric     SrcValReg = Wt;
33750b57cec5SDimitry Andric   }
33760b57cec5SDimitry Andric 
33770b57cec5SDimitry Andric   // Convert the lane index into a byte index
33780b57cec5SDimitry Andric   if (EltSizeInBytes != 1) {
33798bcb0991SDimitry Andric     Register LaneTmp1 = RegInfo.createVirtualRegister(GPRRC);
33800b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(ShiftOp), LaneTmp1)
33810b57cec5SDimitry Andric         .addReg(LaneReg)
33820b57cec5SDimitry Andric         .addImm(EltLog2Size);
33830b57cec5SDimitry Andric     LaneReg = LaneTmp1;
33840b57cec5SDimitry Andric   }
33850b57cec5SDimitry Andric 
33860b57cec5SDimitry Andric   // Rotate bytes around so that the desired lane is element zero
33878bcb0991SDimitry Andric   Register WdTmp1 = RegInfo.createVirtualRegister(VecRC);
33880b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), WdTmp1)
33890b57cec5SDimitry Andric       .addReg(SrcVecReg)
33900b57cec5SDimitry Andric       .addReg(SrcVecReg)
33910b57cec5SDimitry Andric       .addReg(LaneReg, 0, SubRegIdx);
33920b57cec5SDimitry Andric 
33938bcb0991SDimitry Andric   Register WdTmp2 = RegInfo.createVirtualRegister(VecRC);
33940b57cec5SDimitry Andric   if (IsFP) {
33950b57cec5SDimitry Andric     // Use insve.df to insert to element zero
33960b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(InsveOp), WdTmp2)
33970b57cec5SDimitry Andric         .addReg(WdTmp1)
33980b57cec5SDimitry Andric         .addImm(0)
33990b57cec5SDimitry Andric         .addReg(SrcValReg)
34000b57cec5SDimitry Andric         .addImm(0);
34010b57cec5SDimitry Andric   } else {
34020b57cec5SDimitry Andric     // Use insert.df to insert to element zero
34030b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(InsertOp), WdTmp2)
34040b57cec5SDimitry Andric         .addReg(WdTmp1)
34050b57cec5SDimitry Andric         .addReg(SrcValReg)
34060b57cec5SDimitry Andric         .addImm(0);
34070b57cec5SDimitry Andric   }
34080b57cec5SDimitry Andric 
34090b57cec5SDimitry Andric   // Rotate elements the rest of the way for a full rotation.
34100b57cec5SDimitry Andric   // sld.df inteprets $rt modulo the number of columns so we only need to negate
34110b57cec5SDimitry Andric   // the lane index to do this.
34128bcb0991SDimitry Andric   Register LaneTmp2 = RegInfo.createVirtualRegister(GPRRC);
34130b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Subtarget.isABI_N64() ? Mips::DSUB : Mips::SUB),
34140b57cec5SDimitry Andric           LaneTmp2)
34150b57cec5SDimitry Andric       .addReg(Subtarget.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO)
34160b57cec5SDimitry Andric       .addReg(LaneReg);
34170b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::SLD_B), Wd)
34180b57cec5SDimitry Andric       .addReg(WdTmp2)
34190b57cec5SDimitry Andric       .addReg(WdTmp2)
34200b57cec5SDimitry Andric       .addReg(LaneTmp2, 0, SubRegIdx);
34210b57cec5SDimitry Andric 
34220b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
34230b57cec5SDimitry Andric   return BB;
34240b57cec5SDimitry Andric }
34250b57cec5SDimitry Andric 
34260b57cec5SDimitry Andric // Emit the FILL_FW pseudo instruction.
34270b57cec5SDimitry Andric //
34280b57cec5SDimitry Andric // fill_fw_pseudo $wd, $fs
34290b57cec5SDimitry Andric // =>
34300b57cec5SDimitry Andric // implicit_def $wt1
34310b57cec5SDimitry Andric // insert_subreg $wt2:subreg_lo, $wt1, $fs
34320b57cec5SDimitry Andric // splati.w $wd, $wt2[0]
34330b57cec5SDimitry Andric MachineBasicBlock *
34340b57cec5SDimitry Andric MipsSETargetLowering::emitFILL_FW(MachineInstr &MI,
34350b57cec5SDimitry Andric                                   MachineBasicBlock *BB) const {
34360b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
34370b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
34380b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
34398bcb0991SDimitry Andric   Register Wd = MI.getOperand(0).getReg();
34408bcb0991SDimitry Andric   Register Fs = MI.getOperand(1).getReg();
34418bcb0991SDimitry Andric   Register Wt1 = RegInfo.createVirtualRegister(
34420b57cec5SDimitry Andric       Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass
34430b57cec5SDimitry Andric                               : &Mips::MSA128WEvensRegClass);
34448bcb0991SDimitry Andric   Register Wt2 = RegInfo.createVirtualRegister(
34450b57cec5SDimitry Andric       Subtarget.useOddSPReg() ? &Mips::MSA128WRegClass
34460b57cec5SDimitry Andric                               : &Mips::MSA128WEvensRegClass);
34470b57cec5SDimitry Andric 
34480b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::IMPLICIT_DEF), Wt1);
34490b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_SUBREG), Wt2)
34500b57cec5SDimitry Andric       .addReg(Wt1)
34510b57cec5SDimitry Andric       .addReg(Fs)
34520b57cec5SDimitry Andric       .addImm(Mips::sub_lo);
34530b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_W), Wd).addReg(Wt2).addImm(0);
34540b57cec5SDimitry Andric 
34550b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
34560b57cec5SDimitry Andric   return BB;
34570b57cec5SDimitry Andric }
34580b57cec5SDimitry Andric 
34590b57cec5SDimitry Andric // Emit the FILL_FD pseudo instruction.
34600b57cec5SDimitry Andric //
34610b57cec5SDimitry Andric // fill_fd_pseudo $wd, $fs
34620b57cec5SDimitry Andric // =>
34630b57cec5SDimitry Andric // implicit_def $wt1
34640b57cec5SDimitry Andric // insert_subreg $wt2:subreg_64, $wt1, $fs
34650b57cec5SDimitry Andric // splati.d $wd, $wt2[0]
34660b57cec5SDimitry Andric MachineBasicBlock *
34670b57cec5SDimitry Andric MipsSETargetLowering::emitFILL_FD(MachineInstr &MI,
34680b57cec5SDimitry Andric                                   MachineBasicBlock *BB) const {
34690b57cec5SDimitry Andric   assert(Subtarget.isFP64bit());
34700b57cec5SDimitry Andric 
34710b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
34720b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
34730b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
34748bcb0991SDimitry Andric   Register Wd = MI.getOperand(0).getReg();
34758bcb0991SDimitry Andric   Register Fs = MI.getOperand(1).getReg();
34768bcb0991SDimitry Andric   Register Wt1 = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass);
34778bcb0991SDimitry Andric   Register Wt2 = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass);
34780b57cec5SDimitry Andric 
34790b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::IMPLICIT_DEF), Wt1);
34800b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_SUBREG), Wt2)
34810b57cec5SDimitry Andric       .addReg(Wt1)
34820b57cec5SDimitry Andric       .addReg(Fs)
34830b57cec5SDimitry Andric       .addImm(Mips::sub_64);
34840b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::SPLATI_D), Wd).addReg(Wt2).addImm(0);
34850b57cec5SDimitry Andric 
34860b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
34870b57cec5SDimitry Andric   return BB;
34880b57cec5SDimitry Andric }
34890b57cec5SDimitry Andric 
34900b57cec5SDimitry Andric // Emit the ST_F16_PSEDUO instruction to store a f16 value from an MSA
34910b57cec5SDimitry Andric // register.
34920b57cec5SDimitry Andric //
34930b57cec5SDimitry Andric // STF16 MSA128F16:$wd, mem_simm10:$addr
34940b57cec5SDimitry Andric // =>
34950b57cec5SDimitry Andric //  copy_u.h $rtemp,$wd[0]
34960b57cec5SDimitry Andric //  sh $rtemp, $addr
34970b57cec5SDimitry Andric //
34980b57cec5SDimitry Andric // Safety: We can't use st.h & co as they would over write the memory after
34990b57cec5SDimitry Andric // the destination. It would require half floats be allocated 16 bytes(!) of
35000b57cec5SDimitry Andric // space.
35010b57cec5SDimitry Andric MachineBasicBlock *
35020b57cec5SDimitry Andric MipsSETargetLowering::emitST_F16_PSEUDO(MachineInstr &MI,
35030b57cec5SDimitry Andric                                        MachineBasicBlock *BB) const {
35040b57cec5SDimitry Andric 
35050b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
35060b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
35070b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
35088bcb0991SDimitry Andric   Register Ws = MI.getOperand(0).getReg();
35098bcb0991SDimitry Andric   Register Rt = MI.getOperand(1).getReg();
35100b57cec5SDimitry Andric   const MachineMemOperand &MMO = **MI.memoperands_begin();
35110b57cec5SDimitry Andric   unsigned Imm = MMO.getOffset();
35120b57cec5SDimitry Andric 
35130b57cec5SDimitry Andric   // Caution: A load via the GOT can expand to a GPR32 operand, a load via
35140b57cec5SDimitry Andric   //          spill and reload can expand as a GPR64 operand. Examine the
35150b57cec5SDimitry Andric   //          operand in detail and default to ABI.
35160b57cec5SDimitry Andric   const TargetRegisterClass *RC =
35170b57cec5SDimitry Andric       MI.getOperand(1).isReg() ? RegInfo.getRegClass(MI.getOperand(1).getReg())
35180b57cec5SDimitry Andric                                : (Subtarget.isABI_O32() ? &Mips::GPR32RegClass
35190b57cec5SDimitry Andric                                                         : &Mips::GPR64RegClass);
35200b57cec5SDimitry Andric   const bool UsingMips32 = RC == &Mips::GPR32RegClass;
35218bcb0991SDimitry Andric   Register Rs = RegInfo.createVirtualRegister(&Mips::GPR32RegClass);
35220b57cec5SDimitry Andric 
35230b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::COPY_U_H), Rs).addReg(Ws).addImm(0);
35240b57cec5SDimitry Andric   if(!UsingMips32) {
35258bcb0991SDimitry Andric     Register Tmp = RegInfo.createVirtualRegister(&Mips::GPR64RegClass);
35260b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::SUBREG_TO_REG), Tmp)
35270b57cec5SDimitry Andric         .addImm(0)
35280b57cec5SDimitry Andric         .addReg(Rs)
35290b57cec5SDimitry Andric         .addImm(Mips::sub_32);
35300b57cec5SDimitry Andric     Rs = Tmp;
35310b57cec5SDimitry Andric   }
35320b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(UsingMips32 ? Mips::SH : Mips::SH64))
35330b57cec5SDimitry Andric       .addReg(Rs)
35340b57cec5SDimitry Andric       .addReg(Rt)
35350b57cec5SDimitry Andric       .addImm(Imm)
35360b57cec5SDimitry Andric       .addMemOperand(BB->getParent()->getMachineMemOperand(
35370b57cec5SDimitry Andric           &MMO, MMO.getOffset(), MMO.getSize()));
35380b57cec5SDimitry Andric 
35390b57cec5SDimitry Andric   MI.eraseFromParent();
35400b57cec5SDimitry Andric   return BB;
35410b57cec5SDimitry Andric }
35420b57cec5SDimitry Andric 
35430b57cec5SDimitry Andric // Emit the LD_F16_PSEDUO instruction to load a f16 value into an MSA register.
35440b57cec5SDimitry Andric //
35450b57cec5SDimitry Andric // LD_F16 MSA128F16:$wd, mem_simm10:$addr
35460b57cec5SDimitry Andric // =>
35470b57cec5SDimitry Andric //  lh $rtemp, $addr
35480b57cec5SDimitry Andric //  fill.h $wd, $rtemp
35490b57cec5SDimitry Andric //
35500b57cec5SDimitry Andric // Safety: We can't use ld.h & co as they over-read from the source.
35510b57cec5SDimitry Andric // Additionally, if the address is not modulo 16, 2 cases can occur:
35520b57cec5SDimitry Andric //  a) Segmentation fault as the load instruction reads from a memory page
35530b57cec5SDimitry Andric //     memory it's not supposed to.
35540b57cec5SDimitry Andric //  b) The load crosses an implementation specific boundary, requiring OS
35550b57cec5SDimitry Andric //     intervention.
35560b57cec5SDimitry Andric MachineBasicBlock *
35570b57cec5SDimitry Andric MipsSETargetLowering::emitLD_F16_PSEUDO(MachineInstr &MI,
35580b57cec5SDimitry Andric                                        MachineBasicBlock *BB) const {
35590b57cec5SDimitry Andric 
35600b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
35610b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
35620b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
35638bcb0991SDimitry Andric   Register Wd = MI.getOperand(0).getReg();
35640b57cec5SDimitry Andric 
35650b57cec5SDimitry Andric   // Caution: A load via the GOT can expand to a GPR32 operand, a load via
35660b57cec5SDimitry Andric   //          spill and reload can expand as a GPR64 operand. Examine the
35670b57cec5SDimitry Andric   //          operand in detail and default to ABI.
35680b57cec5SDimitry Andric   const TargetRegisterClass *RC =
35690b57cec5SDimitry Andric       MI.getOperand(1).isReg() ? RegInfo.getRegClass(MI.getOperand(1).getReg())
35700b57cec5SDimitry Andric                                : (Subtarget.isABI_O32() ? &Mips::GPR32RegClass
35710b57cec5SDimitry Andric                                                         : &Mips::GPR64RegClass);
35720b57cec5SDimitry Andric 
35730b57cec5SDimitry Andric   const bool UsingMips32 = RC == &Mips::GPR32RegClass;
35748bcb0991SDimitry Andric   Register Rt = RegInfo.createVirtualRegister(RC);
35750b57cec5SDimitry Andric 
35760b57cec5SDimitry Andric   MachineInstrBuilder MIB =
35770b57cec5SDimitry Andric       BuildMI(*BB, MI, DL, TII->get(UsingMips32 ? Mips::LH : Mips::LH64), Rt);
35784824e7fdSDimitry Andric   for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
35794824e7fdSDimitry Andric     MIB.add(MO);
35800b57cec5SDimitry Andric 
35810b57cec5SDimitry Andric   if(!UsingMips32) {
35828bcb0991SDimitry Andric     Register Tmp = RegInfo.createVirtualRegister(&Mips::GPR32RegClass);
35830b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::COPY), Tmp).addReg(Rt, 0, Mips::sub_32);
35840b57cec5SDimitry Andric     Rt = Tmp;
35850b57cec5SDimitry Andric   }
35860b57cec5SDimitry Andric 
35870b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::FILL_H), Wd).addReg(Rt);
35880b57cec5SDimitry Andric 
35890b57cec5SDimitry Andric   MI.eraseFromParent();
35900b57cec5SDimitry Andric   return BB;
35910b57cec5SDimitry Andric }
35920b57cec5SDimitry Andric 
35930b57cec5SDimitry Andric // Emit the FPROUND_PSEUDO instruction.
35940b57cec5SDimitry Andric //
35950b57cec5SDimitry Andric // Round an FGR64Opnd, FGR32Opnd to an f16.
35960b57cec5SDimitry Andric //
35970b57cec5SDimitry Andric // Safety: Cycle the operand through the GPRs so the result always ends up
35980b57cec5SDimitry Andric //         the correct MSA register.
35990b57cec5SDimitry Andric //
36000b57cec5SDimitry Andric // FIXME: This copying is strictly unnecessary. If we could tie FGR32Opnd:$Fs
36010b57cec5SDimitry Andric //        / FGR64Opnd:$Fs and MSA128F16:$Wd to the same physical register
36020b57cec5SDimitry Andric //        (which they can be, as the MSA registers are defined to alias the
36030b57cec5SDimitry Andric //        FPU's 64 bit and 32 bit registers) the result can be accessed using
36040b57cec5SDimitry Andric //        the correct register class. That requires operands be tie-able across
36050b57cec5SDimitry Andric //        register classes which have a sub/super register class relationship.
36060b57cec5SDimitry Andric //
36070b57cec5SDimitry Andric // For FPG32Opnd:
36080b57cec5SDimitry Andric //
36090b57cec5SDimitry Andric // FPROUND MSA128F16:$wd, FGR32Opnd:$fs
36100b57cec5SDimitry Andric // =>
36110b57cec5SDimitry Andric //  mfc1 $rtemp, $fs
36120b57cec5SDimitry Andric //  fill.w $rtemp, $wtemp
36130b57cec5SDimitry Andric //  fexdo.w $wd, $wtemp, $wtemp
36140b57cec5SDimitry Andric //
36150b57cec5SDimitry Andric // For FPG64Opnd on mips32r2+:
36160b57cec5SDimitry Andric //
36170b57cec5SDimitry Andric // FPROUND MSA128F16:$wd, FGR64Opnd:$fs
36180b57cec5SDimitry Andric // =>
36190b57cec5SDimitry Andric //  mfc1 $rtemp, $fs
36200b57cec5SDimitry Andric //  fill.w $rtemp, $wtemp
36210b57cec5SDimitry Andric //  mfhc1 $rtemp2, $fs
36220b57cec5SDimitry Andric //  insert.w $wtemp[1], $rtemp2
36230b57cec5SDimitry Andric //  insert.w $wtemp[3], $rtemp2
36240b57cec5SDimitry Andric //  fexdo.w $wtemp2, $wtemp, $wtemp
36250b57cec5SDimitry Andric //  fexdo.h $wd, $temp2, $temp2
36260b57cec5SDimitry Andric //
36270b57cec5SDimitry Andric // For FGR64Opnd on mips64r2+:
36280b57cec5SDimitry Andric //
36290b57cec5SDimitry Andric // FPROUND MSA128F16:$wd, FGR64Opnd:$fs
36300b57cec5SDimitry Andric // =>
36310b57cec5SDimitry Andric //  dmfc1 $rtemp, $fs
36320b57cec5SDimitry Andric //  fill.d $rtemp, $wtemp
36330b57cec5SDimitry Andric //  fexdo.w $wtemp2, $wtemp, $wtemp
36340b57cec5SDimitry Andric //  fexdo.h $wd, $wtemp2, $wtemp2
36350b57cec5SDimitry Andric //
36360b57cec5SDimitry Andric // Safety note: As $wtemp is UNDEF, we may provoke a spurious exception if the
36370b57cec5SDimitry Andric //              undef bits are "just right" and the exception enable bits are
36380b57cec5SDimitry Andric //              set. By using fill.w to replicate $fs into all elements over
36390b57cec5SDimitry Andric //              insert.w for one element, we avoid that potiential case. If
36400b57cec5SDimitry Andric //              fexdo.[hw] causes an exception in, the exception is valid and it
36410b57cec5SDimitry Andric //              occurs for all elements.
36420b57cec5SDimitry Andric MachineBasicBlock *
36430b57cec5SDimitry Andric MipsSETargetLowering::emitFPROUND_PSEUDO(MachineInstr &MI,
36440b57cec5SDimitry Andric                                          MachineBasicBlock *BB,
36450b57cec5SDimitry Andric                                          bool IsFGR64) const {
36460b57cec5SDimitry Andric 
36470b57cec5SDimitry Andric   // Strictly speaking, we need MIPS32R5 to support MSA. We'll be generous
36480b57cec5SDimitry Andric   // here. It's technically doable to support MIPS32 here, but the ISA forbids
36490b57cec5SDimitry Andric   // it.
36500b57cec5SDimitry Andric   assert(Subtarget.hasMSA() && Subtarget.hasMips32r2());
36510b57cec5SDimitry Andric 
36520b57cec5SDimitry Andric   bool IsFGR64onMips64 = Subtarget.hasMips64() && IsFGR64;
36530b57cec5SDimitry Andric   bool IsFGR64onMips32 = !Subtarget.hasMips64() && IsFGR64;
36540b57cec5SDimitry Andric 
36550b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
36560b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
36578bcb0991SDimitry Andric   Register Wd = MI.getOperand(0).getReg();
36588bcb0991SDimitry Andric   Register Fs = MI.getOperand(1).getReg();
36590b57cec5SDimitry Andric 
36600b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
36618bcb0991SDimitry Andric   Register Wtemp = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
36620b57cec5SDimitry Andric   const TargetRegisterClass *GPRRC =
36630b57cec5SDimitry Andric       IsFGR64onMips64 ? &Mips::GPR64RegClass : &Mips::GPR32RegClass;
36640b57cec5SDimitry Andric   unsigned MFC1Opc = IsFGR64onMips64
36650b57cec5SDimitry Andric                          ? Mips::DMFC1
36660b57cec5SDimitry Andric                          : (IsFGR64onMips32 ? Mips::MFC1_D64 : Mips::MFC1);
36670b57cec5SDimitry Andric   unsigned FILLOpc = IsFGR64onMips64 ? Mips::FILL_D : Mips::FILL_W;
36680b57cec5SDimitry Andric 
36690b57cec5SDimitry Andric   // Perform the register class copy as mentioned above.
36708bcb0991SDimitry Andric   Register Rtemp = RegInfo.createVirtualRegister(GPRRC);
36710b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(MFC1Opc), Rtemp).addReg(Fs);
36720b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(FILLOpc), Wtemp).addReg(Rtemp);
36730b57cec5SDimitry Andric   unsigned WPHI = Wtemp;
36740b57cec5SDimitry Andric 
36750b57cec5SDimitry Andric   if (IsFGR64onMips32) {
36768bcb0991SDimitry Andric     Register Rtemp2 = RegInfo.createVirtualRegister(GPRRC);
36770b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::MFHC1_D64), Rtemp2).addReg(Fs);
36788bcb0991SDimitry Andric     Register Wtemp2 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
36798bcb0991SDimitry Andric     Register Wtemp3 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
36800b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_W), Wtemp2)
36810b57cec5SDimitry Andric         .addReg(Wtemp)
36820b57cec5SDimitry Andric         .addReg(Rtemp2)
36830b57cec5SDimitry Andric         .addImm(1);
36840b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::INSERT_W), Wtemp3)
36850b57cec5SDimitry Andric         .addReg(Wtemp2)
36860b57cec5SDimitry Andric         .addReg(Rtemp2)
36870b57cec5SDimitry Andric         .addImm(3);
36880b57cec5SDimitry Andric     WPHI = Wtemp3;
36890b57cec5SDimitry Andric   }
36900b57cec5SDimitry Andric 
36910b57cec5SDimitry Andric   if (IsFGR64) {
36928bcb0991SDimitry Andric     Register Wtemp2 = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
36930b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::FEXDO_W), Wtemp2)
36940b57cec5SDimitry Andric         .addReg(WPHI)
36950b57cec5SDimitry Andric         .addReg(WPHI);
36960b57cec5SDimitry Andric     WPHI = Wtemp2;
36970b57cec5SDimitry Andric   }
36980b57cec5SDimitry Andric 
36990b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::FEXDO_H), Wd).addReg(WPHI).addReg(WPHI);
37000b57cec5SDimitry Andric 
37010b57cec5SDimitry Andric   MI.eraseFromParent();
37020b57cec5SDimitry Andric   return BB;
37030b57cec5SDimitry Andric }
37040b57cec5SDimitry Andric 
37050b57cec5SDimitry Andric // Emit the FPEXTEND_PSEUDO instruction.
37060b57cec5SDimitry Andric //
37070b57cec5SDimitry Andric // Expand an f16 to either a FGR32Opnd or FGR64Opnd.
37080b57cec5SDimitry Andric //
37090b57cec5SDimitry Andric // Safety: Cycle the result through the GPRs so the result always ends up
37100b57cec5SDimitry Andric //         the correct floating point register.
37110b57cec5SDimitry Andric //
37120b57cec5SDimitry Andric // FIXME: This copying is strictly unnecessary. If we could tie FGR32Opnd:$Fd
37130b57cec5SDimitry Andric //        / FGR64Opnd:$Fd and MSA128F16:$Ws to the same physical register
37140b57cec5SDimitry Andric //        (which they can be, as the MSA registers are defined to alias the
37150b57cec5SDimitry Andric //        FPU's 64 bit and 32 bit registers) the result can be accessed using
37160b57cec5SDimitry Andric //        the correct register class. That requires operands be tie-able across
37170b57cec5SDimitry Andric //        register classes which have a sub/super register class relationship. I
37180b57cec5SDimitry Andric //        haven't checked.
37190b57cec5SDimitry Andric //
37200b57cec5SDimitry Andric // For FGR32Opnd:
37210b57cec5SDimitry Andric //
37220b57cec5SDimitry Andric // FPEXTEND FGR32Opnd:$fd, MSA128F16:$ws
37230b57cec5SDimitry Andric // =>
37240b57cec5SDimitry Andric //  fexupr.w $wtemp, $ws
37250b57cec5SDimitry Andric //  copy_s.w $rtemp, $ws[0]
37260b57cec5SDimitry Andric //  mtc1 $rtemp, $fd
37270b57cec5SDimitry Andric //
37280b57cec5SDimitry Andric // For FGR64Opnd on Mips64:
37290b57cec5SDimitry Andric //
37300b57cec5SDimitry Andric // FPEXTEND FGR64Opnd:$fd, MSA128F16:$ws
37310b57cec5SDimitry Andric // =>
37320b57cec5SDimitry Andric //  fexupr.w $wtemp, $ws
37330b57cec5SDimitry Andric //  fexupr.d $wtemp2, $wtemp
37340b57cec5SDimitry Andric //  copy_s.d $rtemp, $wtemp2s[0]
37350b57cec5SDimitry Andric //  dmtc1 $rtemp, $fd
37360b57cec5SDimitry Andric //
37370b57cec5SDimitry Andric // For FGR64Opnd on Mips32:
37380b57cec5SDimitry Andric //
37390b57cec5SDimitry Andric // FPEXTEND FGR64Opnd:$fd, MSA128F16:$ws
37400b57cec5SDimitry Andric // =>
37410b57cec5SDimitry Andric //  fexupr.w $wtemp, $ws
37420b57cec5SDimitry Andric //  fexupr.d $wtemp2, $wtemp
37430b57cec5SDimitry Andric //  copy_s.w $rtemp, $wtemp2[0]
37440b57cec5SDimitry Andric //  mtc1 $rtemp, $ftemp
37450b57cec5SDimitry Andric //  copy_s.w $rtemp2, $wtemp2[1]
37460b57cec5SDimitry Andric //  $fd = mthc1 $rtemp2, $ftemp
37470b57cec5SDimitry Andric MachineBasicBlock *
37480b57cec5SDimitry Andric MipsSETargetLowering::emitFPEXTEND_PSEUDO(MachineInstr &MI,
37490b57cec5SDimitry Andric                                           MachineBasicBlock *BB,
37500b57cec5SDimitry Andric                                           bool IsFGR64) const {
37510b57cec5SDimitry Andric 
37520b57cec5SDimitry Andric   // Strictly speaking, we need MIPS32R5 to support MSA. We'll be generous
37530b57cec5SDimitry Andric   // here. It's technically doable to support MIPS32 here, but the ISA forbids
37540b57cec5SDimitry Andric   // it.
37550b57cec5SDimitry Andric   assert(Subtarget.hasMSA() && Subtarget.hasMips32r2());
37560b57cec5SDimitry Andric 
37570b57cec5SDimitry Andric   bool IsFGR64onMips64 = Subtarget.hasMips64() && IsFGR64;
37580b57cec5SDimitry Andric   bool IsFGR64onMips32 = !Subtarget.hasMips64() && IsFGR64;
37590b57cec5SDimitry Andric 
37600b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
37610b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
37620b57cec5SDimitry Andric   Register Fd = MI.getOperand(0).getReg();
37630b57cec5SDimitry Andric   Register Ws = MI.getOperand(1).getReg();
37640b57cec5SDimitry Andric 
37650b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
37660b57cec5SDimitry Andric   const TargetRegisterClass *GPRRC =
37670b57cec5SDimitry Andric       IsFGR64onMips64 ? &Mips::GPR64RegClass : &Mips::GPR32RegClass;
37680b57cec5SDimitry Andric   unsigned MTC1Opc = IsFGR64onMips64
37690b57cec5SDimitry Andric                          ? Mips::DMTC1
37700b57cec5SDimitry Andric                          : (IsFGR64onMips32 ? Mips::MTC1_D64 : Mips::MTC1);
37710b57cec5SDimitry Andric   Register COPYOpc = IsFGR64onMips64 ? Mips::COPY_S_D : Mips::COPY_S_W;
37720b57cec5SDimitry Andric 
37730b57cec5SDimitry Andric   Register Wtemp = RegInfo.createVirtualRegister(&Mips::MSA128WRegClass);
37740b57cec5SDimitry Andric   Register WPHI = Wtemp;
37750b57cec5SDimitry Andric 
37760b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::FEXUPR_W), Wtemp).addReg(Ws);
37770b57cec5SDimitry Andric   if (IsFGR64) {
37780b57cec5SDimitry Andric     WPHI = RegInfo.createVirtualRegister(&Mips::MSA128DRegClass);
37790b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::FEXUPR_D), WPHI).addReg(Wtemp);
37800b57cec5SDimitry Andric   }
37810b57cec5SDimitry Andric 
37820b57cec5SDimitry Andric   // Perform the safety regclass copy mentioned above.
37830b57cec5SDimitry Andric   Register Rtemp = RegInfo.createVirtualRegister(GPRRC);
37840b57cec5SDimitry Andric   Register FPRPHI = IsFGR64onMips32
37850b57cec5SDimitry Andric                         ? RegInfo.createVirtualRegister(&Mips::FGR64RegClass)
37860b57cec5SDimitry Andric                         : Fd;
37870b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(COPYOpc), Rtemp).addReg(WPHI).addImm(0);
37880b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(MTC1Opc), FPRPHI).addReg(Rtemp);
37890b57cec5SDimitry Andric 
37900b57cec5SDimitry Andric   if (IsFGR64onMips32) {
37910b57cec5SDimitry Andric     Register Rtemp2 = RegInfo.createVirtualRegister(GPRRC);
37920b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::COPY_S_W), Rtemp2)
37930b57cec5SDimitry Andric         .addReg(WPHI)
37940b57cec5SDimitry Andric         .addImm(1);
37950b57cec5SDimitry Andric     BuildMI(*BB, MI, DL, TII->get(Mips::MTHC1_D64), Fd)
37960b57cec5SDimitry Andric         .addReg(FPRPHI)
37970b57cec5SDimitry Andric         .addReg(Rtemp2);
37980b57cec5SDimitry Andric   }
37990b57cec5SDimitry Andric 
38000b57cec5SDimitry Andric   MI.eraseFromParent();
38010b57cec5SDimitry Andric   return BB;
38020b57cec5SDimitry Andric }
38030b57cec5SDimitry Andric 
38040b57cec5SDimitry Andric // Emit the FEXP2_W_1 pseudo instructions.
38050b57cec5SDimitry Andric //
38060b57cec5SDimitry Andric // fexp2_w_1_pseudo $wd, $wt
38070b57cec5SDimitry Andric // =>
38080b57cec5SDimitry Andric // ldi.w $ws, 1
38090b57cec5SDimitry Andric // fexp2.w $wd, $ws, $wt
38100b57cec5SDimitry Andric MachineBasicBlock *
38110b57cec5SDimitry Andric MipsSETargetLowering::emitFEXP2_W_1(MachineInstr &MI,
38120b57cec5SDimitry Andric                                     MachineBasicBlock *BB) const {
38130b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
38140b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
38150b57cec5SDimitry Andric   const TargetRegisterClass *RC = &Mips::MSA128WRegClass;
38168bcb0991SDimitry Andric   Register Ws1 = RegInfo.createVirtualRegister(RC);
38178bcb0991SDimitry Andric   Register Ws2 = RegInfo.createVirtualRegister(RC);
38180b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
38190b57cec5SDimitry Andric 
38200b57cec5SDimitry Andric   // Splat 1.0 into a vector
38210b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::LDI_W), Ws1).addImm(1);
38220b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::FFINT_U_W), Ws2).addReg(Ws1);
38230b57cec5SDimitry Andric 
38240b57cec5SDimitry Andric   // Emit 1.0 * fexp2(Wt)
38250b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::FEXP2_W), MI.getOperand(0).getReg())
38260b57cec5SDimitry Andric       .addReg(Ws2)
38270b57cec5SDimitry Andric       .addReg(MI.getOperand(1).getReg());
38280b57cec5SDimitry Andric 
38290b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
38300b57cec5SDimitry Andric   return BB;
38310b57cec5SDimitry Andric }
38320b57cec5SDimitry Andric 
38330b57cec5SDimitry Andric // Emit the FEXP2_D_1 pseudo instructions.
38340b57cec5SDimitry Andric //
38350b57cec5SDimitry Andric // fexp2_d_1_pseudo $wd, $wt
38360b57cec5SDimitry Andric // =>
38370b57cec5SDimitry Andric // ldi.d $ws, 1
38380b57cec5SDimitry Andric // fexp2.d $wd, $ws, $wt
38390b57cec5SDimitry Andric MachineBasicBlock *
38400b57cec5SDimitry Andric MipsSETargetLowering::emitFEXP2_D_1(MachineInstr &MI,
38410b57cec5SDimitry Andric                                     MachineBasicBlock *BB) const {
38420b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
38430b57cec5SDimitry Andric   MachineRegisterInfo &RegInfo = BB->getParent()->getRegInfo();
38440b57cec5SDimitry Andric   const TargetRegisterClass *RC = &Mips::MSA128DRegClass;
38458bcb0991SDimitry Andric   Register Ws1 = RegInfo.createVirtualRegister(RC);
38468bcb0991SDimitry Andric   Register Ws2 = RegInfo.createVirtualRegister(RC);
38470b57cec5SDimitry Andric   DebugLoc DL = MI.getDebugLoc();
38480b57cec5SDimitry Andric 
38490b57cec5SDimitry Andric   // Splat 1.0 into a vector
38500b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::LDI_D), Ws1).addImm(1);
38510b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::FFINT_U_D), Ws2).addReg(Ws1);
38520b57cec5SDimitry Andric 
38530b57cec5SDimitry Andric   // Emit 1.0 * fexp2(Wt)
38540b57cec5SDimitry Andric   BuildMI(*BB, MI, DL, TII->get(Mips::FEXP2_D), MI.getOperand(0).getReg())
38550b57cec5SDimitry Andric       .addReg(Ws2)
38560b57cec5SDimitry Andric       .addReg(MI.getOperand(1).getReg());
38570b57cec5SDimitry Andric 
38580b57cec5SDimitry Andric   MI.eraseFromParent(); // The pseudo instruction is gone now.
38590b57cec5SDimitry Andric   return BB;
38600b57cec5SDimitry Andric }
3861