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