10b57cec5SDimitry Andric //===-- Mips16ISelLowering.h - Mips16 DAG Lowering Interface ----*- C++ -*-===// 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 mips16. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric #include "Mips16ISelLowering.h" 130b57cec5SDimitry Andric #include "MCTargetDesc/MipsBaseInfo.h" 140b57cec5SDimitry Andric #include "Mips16HardFloatInfo.h" 150b57cec5SDimitry Andric #include "MipsMachineFunction.h" 160b57cec5SDimitry Andric #include "MipsRegisterInfo.h" 170b57cec5SDimitry Andric #include "MipsTargetMachine.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 200b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #define DEBUG_TYPE "mips-lower" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric static cl::opt<bool> DontExpandCondPseudos16( 270b57cec5SDimitry Andric "mips16-dont-expand-cond-pseudo", 280b57cec5SDimitry Andric cl::init(false), 290b57cec5SDimitry Andric cl::desc("Don't expand conditional move related " 300b57cec5SDimitry Andric "pseudos for Mips 16"), 310b57cec5SDimitry Andric cl::Hidden); 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric namespace { 340b57cec5SDimitry Andric struct Mips16Libcall { 350b57cec5SDimitry Andric RTLIB::Libcall Libcall; 360b57cec5SDimitry Andric const char *Name; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric bool operator<(const Mips16Libcall &RHS) const { 390b57cec5SDimitry Andric return std::strcmp(Name, RHS.Name) < 0; 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric }; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric struct Mips16IntrinsicHelperType{ 440b57cec5SDimitry Andric const char* Name; 450b57cec5SDimitry Andric const char* Helper; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric bool operator<(const Mips16IntrinsicHelperType &RHS) const { 480b57cec5SDimitry Andric return std::strcmp(Name, RHS.Name) < 0; 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric bool operator==(const Mips16IntrinsicHelperType &RHS) const { 510b57cec5SDimitry Andric return std::strcmp(Name, RHS.Name) == 0; 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric }; 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric // Libcalls for which no helper is generated. Sorted by name for binary search. 570b57cec5SDimitry Andric static const Mips16Libcall HardFloatLibCalls[] = { 580b57cec5SDimitry Andric { RTLIB::ADD_F64, "__mips16_adddf3" }, 590b57cec5SDimitry Andric { RTLIB::ADD_F32, "__mips16_addsf3" }, 600b57cec5SDimitry Andric { RTLIB::DIV_F64, "__mips16_divdf3" }, 610b57cec5SDimitry Andric { RTLIB::DIV_F32, "__mips16_divsf3" }, 620b57cec5SDimitry Andric { RTLIB::OEQ_F64, "__mips16_eqdf2" }, 630b57cec5SDimitry Andric { RTLIB::OEQ_F32, "__mips16_eqsf2" }, 640b57cec5SDimitry Andric { RTLIB::FPEXT_F32_F64, "__mips16_extendsfdf2" }, 650b57cec5SDimitry Andric { RTLIB::FPTOSINT_F64_I32, "__mips16_fix_truncdfsi" }, 660b57cec5SDimitry Andric { RTLIB::FPTOSINT_F32_I32, "__mips16_fix_truncsfsi" }, 670b57cec5SDimitry Andric { RTLIB::SINTTOFP_I32_F64, "__mips16_floatsidf" }, 680b57cec5SDimitry Andric { RTLIB::SINTTOFP_I32_F32, "__mips16_floatsisf" }, 690b57cec5SDimitry Andric { RTLIB::UINTTOFP_I32_F64, "__mips16_floatunsidf" }, 700b57cec5SDimitry Andric { RTLIB::UINTTOFP_I32_F32, "__mips16_floatunsisf" }, 710b57cec5SDimitry Andric { RTLIB::OGE_F64, "__mips16_gedf2" }, 720b57cec5SDimitry Andric { RTLIB::OGE_F32, "__mips16_gesf2" }, 730b57cec5SDimitry Andric { RTLIB::OGT_F64, "__mips16_gtdf2" }, 740b57cec5SDimitry Andric { RTLIB::OGT_F32, "__mips16_gtsf2" }, 750b57cec5SDimitry Andric { RTLIB::OLE_F64, "__mips16_ledf2" }, 760b57cec5SDimitry Andric { RTLIB::OLE_F32, "__mips16_lesf2" }, 770b57cec5SDimitry Andric { RTLIB::OLT_F64, "__mips16_ltdf2" }, 780b57cec5SDimitry Andric { RTLIB::OLT_F32, "__mips16_ltsf2" }, 790b57cec5SDimitry Andric { RTLIB::MUL_F64, "__mips16_muldf3" }, 800b57cec5SDimitry Andric { RTLIB::MUL_F32, "__mips16_mulsf3" }, 810b57cec5SDimitry Andric { RTLIB::UNE_F64, "__mips16_nedf2" }, 820b57cec5SDimitry Andric { RTLIB::UNE_F32, "__mips16_nesf2" }, 830b57cec5SDimitry Andric { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_dc" }, // No associated libcall. 840b57cec5SDimitry Andric { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_df" }, // No associated libcall. 850b57cec5SDimitry Andric { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_sc" }, // No associated libcall. 860b57cec5SDimitry Andric { RTLIB::UNKNOWN_LIBCALL, "__mips16_ret_sf" }, // No associated libcall. 870b57cec5SDimitry Andric { RTLIB::SUB_F64, "__mips16_subdf3" }, 880b57cec5SDimitry Andric { RTLIB::SUB_F32, "__mips16_subsf3" }, 890b57cec5SDimitry Andric { RTLIB::FPROUND_F64_F32, "__mips16_truncdfsf2" }, 900b57cec5SDimitry Andric { RTLIB::UO_F64, "__mips16_unorddf2" }, 910b57cec5SDimitry Andric { RTLIB::UO_F32, "__mips16_unordsf2" } 920b57cec5SDimitry Andric }; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric static const Mips16IntrinsicHelperType Mips16IntrinsicHelper[] = { 950b57cec5SDimitry Andric {"__fixunsdfsi", "__mips16_call_stub_2" }, 960b57cec5SDimitry Andric {"ceil", "__mips16_call_stub_df_2"}, 970b57cec5SDimitry Andric {"ceilf", "__mips16_call_stub_sf_1"}, 980b57cec5SDimitry Andric {"copysign", "__mips16_call_stub_df_10"}, 990b57cec5SDimitry Andric {"copysignf", "__mips16_call_stub_sf_5"}, 1000b57cec5SDimitry Andric {"cos", "__mips16_call_stub_df_2"}, 1010b57cec5SDimitry Andric {"cosf", "__mips16_call_stub_sf_1"}, 1020b57cec5SDimitry Andric {"exp2", "__mips16_call_stub_df_2"}, 1030b57cec5SDimitry Andric {"exp2f", "__mips16_call_stub_sf_1"}, 1040b57cec5SDimitry Andric {"floor", "__mips16_call_stub_df_2"}, 1050b57cec5SDimitry Andric {"floorf", "__mips16_call_stub_sf_1"}, 1060b57cec5SDimitry Andric {"log2", "__mips16_call_stub_df_2"}, 1070b57cec5SDimitry Andric {"log2f", "__mips16_call_stub_sf_1"}, 1080b57cec5SDimitry Andric {"nearbyint", "__mips16_call_stub_df_2"}, 1090b57cec5SDimitry Andric {"nearbyintf", "__mips16_call_stub_sf_1"}, 1100b57cec5SDimitry Andric {"rint", "__mips16_call_stub_df_2"}, 1110b57cec5SDimitry Andric {"rintf", "__mips16_call_stub_sf_1"}, 1120b57cec5SDimitry Andric {"sin", "__mips16_call_stub_df_2"}, 1130b57cec5SDimitry Andric {"sinf", "__mips16_call_stub_sf_1"}, 1140b57cec5SDimitry Andric {"sqrt", "__mips16_call_stub_df_2"}, 1150b57cec5SDimitry Andric {"sqrtf", "__mips16_call_stub_sf_1"}, 1160b57cec5SDimitry Andric {"trunc", "__mips16_call_stub_df_2"}, 1170b57cec5SDimitry Andric {"truncf", "__mips16_call_stub_sf_1"}, 1180b57cec5SDimitry Andric }; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric Mips16TargetLowering::Mips16TargetLowering(const MipsTargetMachine &TM, 1210b57cec5SDimitry Andric const MipsSubtarget &STI) 1220b57cec5SDimitry Andric : MipsTargetLowering(TM, STI) { 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // Set up the register classes 1250b57cec5SDimitry Andric addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric if (!Subtarget.useSoftFloat()) 1280b57cec5SDimitry Andric setMips16HardFloatLibCalls(); 1290b57cec5SDimitry Andric 130*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, LibCall); 131*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, LibCall); 132*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, LibCall); 133*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, LibCall); 134*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, LibCall); 135*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, LibCall); 136*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, LibCall); 137*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, LibCall); 138*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, LibCall); 139*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, LibCall); 140*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, LibCall); 141*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, LibCall); 142*5f757f3fSDimitry Andric setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, LibCall); 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric setOperationAction(ISD::ROTR, MVT::i32, Expand); 1450b57cec5SDimitry Andric setOperationAction(ISD::ROTR, MVT::i64, Expand); 1460b57cec5SDimitry Andric setOperationAction(ISD::BSWAP, MVT::i32, Expand); 1470b57cec5SDimitry Andric setOperationAction(ISD::BSWAP, MVT::i64, Expand); 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric computeRegisterProperties(STI.getRegisterInfo()); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric const MipsTargetLowering * 1530b57cec5SDimitry Andric llvm::createMips16TargetLowering(const MipsTargetMachine &TM, 1540b57cec5SDimitry Andric const MipsSubtarget &STI) { 1550b57cec5SDimitry Andric return new Mips16TargetLowering(TM, STI); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric bool Mips16TargetLowering::allowsMisalignedMemoryAccesses( 159bdd1243dSDimitry Andric EVT VT, unsigned, Align, MachineMemOperand::Flags, unsigned *Fast) const { 1600b57cec5SDimitry Andric return false; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric MachineBasicBlock * 1640b57cec5SDimitry Andric Mips16TargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, 1650b57cec5SDimitry Andric MachineBasicBlock *BB) const { 1660b57cec5SDimitry Andric switch (MI.getOpcode()) { 1670b57cec5SDimitry Andric default: 1680b57cec5SDimitry Andric return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB); 1690b57cec5SDimitry Andric case Mips::SelBeqZ: 1700b57cec5SDimitry Andric return emitSel16(Mips::BeqzRxImm16, MI, BB); 1710b57cec5SDimitry Andric case Mips::SelBneZ: 1720b57cec5SDimitry Andric return emitSel16(Mips::BnezRxImm16, MI, BB); 1730b57cec5SDimitry Andric case Mips::SelTBteqZCmpi: 1740b57cec5SDimitry Andric return emitSeliT16(Mips::Bteqz16, Mips::CmpiRxImmX16, MI, BB); 1750b57cec5SDimitry Andric case Mips::SelTBteqZSlti: 1760b57cec5SDimitry Andric return emitSeliT16(Mips::Bteqz16, Mips::SltiRxImmX16, MI, BB); 1770b57cec5SDimitry Andric case Mips::SelTBteqZSltiu: 1780b57cec5SDimitry Andric return emitSeliT16(Mips::Bteqz16, Mips::SltiuRxImmX16, MI, BB); 1790b57cec5SDimitry Andric case Mips::SelTBtneZCmpi: 1800b57cec5SDimitry Andric return emitSeliT16(Mips::Btnez16, Mips::CmpiRxImmX16, MI, BB); 1810b57cec5SDimitry Andric case Mips::SelTBtneZSlti: 1820b57cec5SDimitry Andric return emitSeliT16(Mips::Btnez16, Mips::SltiRxImmX16, MI, BB); 1830b57cec5SDimitry Andric case Mips::SelTBtneZSltiu: 1840b57cec5SDimitry Andric return emitSeliT16(Mips::Btnez16, Mips::SltiuRxImmX16, MI, BB); 1850b57cec5SDimitry Andric case Mips::SelTBteqZCmp: 1860b57cec5SDimitry Andric return emitSelT16(Mips::Bteqz16, Mips::CmpRxRy16, MI, BB); 1870b57cec5SDimitry Andric case Mips::SelTBteqZSlt: 1880b57cec5SDimitry Andric return emitSelT16(Mips::Bteqz16, Mips::SltRxRy16, MI, BB); 1890b57cec5SDimitry Andric case Mips::SelTBteqZSltu: 1900b57cec5SDimitry Andric return emitSelT16(Mips::Bteqz16, Mips::SltuRxRy16, MI, BB); 1910b57cec5SDimitry Andric case Mips::SelTBtneZCmp: 1920b57cec5SDimitry Andric return emitSelT16(Mips::Btnez16, Mips::CmpRxRy16, MI, BB); 1930b57cec5SDimitry Andric case Mips::SelTBtneZSlt: 1940b57cec5SDimitry Andric return emitSelT16(Mips::Btnez16, Mips::SltRxRy16, MI, BB); 1950b57cec5SDimitry Andric case Mips::SelTBtneZSltu: 1960b57cec5SDimitry Andric return emitSelT16(Mips::Btnez16, Mips::SltuRxRy16, MI, BB); 1970b57cec5SDimitry Andric case Mips::BteqzT8CmpX16: 1980b57cec5SDimitry Andric return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::CmpRxRy16, MI, BB); 1990b57cec5SDimitry Andric case Mips::BteqzT8SltX16: 2000b57cec5SDimitry Andric return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::SltRxRy16, MI, BB); 2010b57cec5SDimitry Andric case Mips::BteqzT8SltuX16: 2020b57cec5SDimitry Andric // TBD: figure out a way to get this or remove the instruction 2030b57cec5SDimitry Andric // altogether. 2040b57cec5SDimitry Andric return emitFEXT_T8I816_ins(Mips::Bteqz16, Mips::SltuRxRy16, MI, BB); 2050b57cec5SDimitry Andric case Mips::BtnezT8CmpX16: 2060b57cec5SDimitry Andric return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::CmpRxRy16, MI, BB); 2070b57cec5SDimitry Andric case Mips::BtnezT8SltX16: 2080b57cec5SDimitry Andric return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::SltRxRy16, MI, BB); 2090b57cec5SDimitry Andric case Mips::BtnezT8SltuX16: 2100b57cec5SDimitry Andric // TBD: figure out a way to get this or remove the instruction 2110b57cec5SDimitry Andric // altogether. 2120b57cec5SDimitry Andric return emitFEXT_T8I816_ins(Mips::Btnez16, Mips::SltuRxRy16, MI, BB); 2130b57cec5SDimitry Andric case Mips::BteqzT8CmpiX16: return emitFEXT_T8I8I16_ins( 2140b57cec5SDimitry Andric Mips::Bteqz16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, false, MI, BB); 2150b57cec5SDimitry Andric case Mips::BteqzT8SltiX16: return emitFEXT_T8I8I16_ins( 2160b57cec5SDimitry Andric Mips::Bteqz16, Mips::SltiRxImm16, Mips::SltiRxImmX16, true, MI, BB); 2170b57cec5SDimitry Andric case Mips::BteqzT8SltiuX16: return emitFEXT_T8I8I16_ins( 2180b57cec5SDimitry Andric Mips::Bteqz16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, false, MI, BB); 2190b57cec5SDimitry Andric case Mips::BtnezT8CmpiX16: return emitFEXT_T8I8I16_ins( 2200b57cec5SDimitry Andric Mips::Btnez16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, false, MI, BB); 2210b57cec5SDimitry Andric case Mips::BtnezT8SltiX16: return emitFEXT_T8I8I16_ins( 2220b57cec5SDimitry Andric Mips::Btnez16, Mips::SltiRxImm16, Mips::SltiRxImmX16, true, MI, BB); 2230b57cec5SDimitry Andric case Mips::BtnezT8SltiuX16: return emitFEXT_T8I8I16_ins( 2240b57cec5SDimitry Andric Mips::Btnez16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, false, MI, BB); 2250b57cec5SDimitry Andric break; 2260b57cec5SDimitry Andric case Mips::SltCCRxRy16: 2270b57cec5SDimitry Andric return emitFEXT_CCRX16_ins(Mips::SltRxRy16, MI, BB); 2280b57cec5SDimitry Andric break; 2290b57cec5SDimitry Andric case Mips::SltiCCRxImmX16: 2300b57cec5SDimitry Andric return emitFEXT_CCRXI16_ins 2310b57cec5SDimitry Andric (Mips::SltiRxImm16, Mips::SltiRxImmX16, MI, BB); 2320b57cec5SDimitry Andric case Mips::SltiuCCRxImmX16: 2330b57cec5SDimitry Andric return emitFEXT_CCRXI16_ins 2340b57cec5SDimitry Andric (Mips::SltiuRxImm16, Mips::SltiuRxImmX16, MI, BB); 2350b57cec5SDimitry Andric case Mips::SltuCCRxRy16: 2360b57cec5SDimitry Andric return emitFEXT_CCRX16_ins 2370b57cec5SDimitry Andric (Mips::SltuRxRy16, MI, BB); 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric bool Mips16TargetLowering::isEligibleForTailCallOptimization( 2420b57cec5SDimitry Andric const CCState &CCInfo, unsigned NextStackOffset, 2430b57cec5SDimitry Andric const MipsFunctionInfo &FI) const { 2440b57cec5SDimitry Andric // No tail call optimization for mips16. 2450b57cec5SDimitry Andric return false; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric void Mips16TargetLowering::setMips16HardFloatLibCalls() { 249bdd1243dSDimitry Andric for (unsigned I = 0; I != std::size(HardFloatLibCalls); ++I) { 2500b57cec5SDimitry Andric assert((I == 0 || HardFloatLibCalls[I - 1] < HardFloatLibCalls[I]) && 2510b57cec5SDimitry Andric "Array not sorted!"); 2520b57cec5SDimitry Andric if (HardFloatLibCalls[I].Libcall != RTLIB::UNKNOWN_LIBCALL) 2530b57cec5SDimitry Andric setLibcallName(HardFloatLibCalls[I].Libcall, HardFloatLibCalls[I].Name); 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric // 2580b57cec5SDimitry Andric // The Mips16 hard float is a crazy quilt inherited from gcc. I have a much 2590b57cec5SDimitry Andric // cleaner way to do all of this but it will have to wait until the traditional 2600b57cec5SDimitry Andric // gcc mechanism is completed. 2610b57cec5SDimitry Andric // 2620b57cec5SDimitry Andric // For Pic, in order for Mips16 code to call Mips32 code which according the abi 2630b57cec5SDimitry Andric // have either arguments or returned values placed in floating point registers, 2640b57cec5SDimitry Andric // we use a set of helper functions. (This includes functions which return type 2650b57cec5SDimitry Andric // complex which on Mips are returned in a pair of floating point registers). 2660b57cec5SDimitry Andric // 2670b57cec5SDimitry Andric // This is an encoding that we inherited from gcc. 2680b57cec5SDimitry Andric // In Mips traditional O32, N32 ABI, floating point numbers are passed in 2690b57cec5SDimitry Andric // floating point argument registers 1,2 only when the first and optionally 2700b57cec5SDimitry Andric // the second arguments are float (sf) or double (df). 2710b57cec5SDimitry Andric // For Mips16 we are only concerned with the situations where floating point 2720b57cec5SDimitry Andric // arguments are being passed in floating point registers by the ABI, because 2730b57cec5SDimitry Andric // Mips16 mode code cannot execute floating point instructions to load those 2740b57cec5SDimitry Andric // values and hence helper functions are needed. 2750b57cec5SDimitry Andric // The possibilities are (), (sf), (sf, sf), (sf, df), (df), (df, sf), (df, df) 2760b57cec5SDimitry Andric // the helper function suffixs for these are: 2770b57cec5SDimitry Andric // 0, 1, 5, 9, 2, 6, 10 2780b57cec5SDimitry Andric // this suffix can then be calculated as follows: 2790b57cec5SDimitry Andric // for a given argument Arg: 2800b57cec5SDimitry Andric // Arg1x, Arg2x = 1 : Arg is sf 2810b57cec5SDimitry Andric // 2 : Arg is df 2820b57cec5SDimitry Andric // 0: Arg is neither sf or df 2830b57cec5SDimitry Andric // So this stub is the string for number Arg1x + Arg2x*4. 2840b57cec5SDimitry Andric // However not all numbers between 0 and 10 are possible, we check anyway and 2850b57cec5SDimitry Andric // assert if the impossible exists. 2860b57cec5SDimitry Andric // 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric unsigned int Mips16TargetLowering::getMips16HelperFunctionStubNumber 2890b57cec5SDimitry Andric (ArgListTy &Args) const { 2900b57cec5SDimitry Andric unsigned int resultNum = 0; 2910b57cec5SDimitry Andric if (Args.size() >= 1) { 2920b57cec5SDimitry Andric Type *t = Args[0].Ty; 2930b57cec5SDimitry Andric if (t->isFloatTy()) { 2940b57cec5SDimitry Andric resultNum = 1; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric else if (t->isDoubleTy()) { 2970b57cec5SDimitry Andric resultNum = 2; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric } 3000b57cec5SDimitry Andric if (resultNum) { 3010b57cec5SDimitry Andric if (Args.size() >=2) { 3020b57cec5SDimitry Andric Type *t = Args[1].Ty; 3030b57cec5SDimitry Andric if (t->isFloatTy()) { 3040b57cec5SDimitry Andric resultNum += 4; 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric else if (t->isDoubleTy()) { 3070b57cec5SDimitry Andric resultNum += 8; 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric return resultNum; 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric // 3150b57cec5SDimitry Andric // Prefixes are attached to stub numbers depending on the return type. 3160b57cec5SDimitry Andric // return type: float sf_ 3170b57cec5SDimitry Andric // double df_ 3180b57cec5SDimitry Andric // single complex sc_ 3190b57cec5SDimitry Andric // double complext dc_ 3200b57cec5SDimitry Andric // others NO PREFIX 3210b57cec5SDimitry Andric // 3220b57cec5SDimitry Andric // 3230b57cec5SDimitry Andric // The full name of a helper function is__mips16_call_stub + 3240b57cec5SDimitry Andric // return type dependent prefix + stub number 3250b57cec5SDimitry Andric // 3260b57cec5SDimitry Andric // FIXME: This is something that probably should be in a different source file 3270b57cec5SDimitry Andric // and perhaps done differently but my main purpose is to not waste runtime 3280b57cec5SDimitry Andric // on something that we can enumerate in the source. Another possibility is 3290b57cec5SDimitry Andric // to have a python script to generate these mapping tables. This will do 3300b57cec5SDimitry Andric // for now. There are a whole series of helper function mapping arrays, one 3310b57cec5SDimitry Andric // for each return type class as outlined above. There there are 11 possible 3320b57cec5SDimitry Andric // entries. Ones with 0 are ones which should never be selected. 3330b57cec5SDimitry Andric // 3340b57cec5SDimitry Andric // All the arrays are similar except for ones which return neither 3350b57cec5SDimitry Andric // sf, df, sc, dc, in which we only care about ones which have sf or df as a 3360b57cec5SDimitry Andric // first parameter. 3370b57cec5SDimitry Andric // 3380b57cec5SDimitry Andric #define P_ "__mips16_call_stub_" 3390b57cec5SDimitry Andric #define MAX_STUB_NUMBER 10 3400b57cec5SDimitry Andric #define T1 P "1", P "2", 0, 0, P "5", P "6", 0, 0, P "9", P "10" 3410b57cec5SDimitry Andric #define T P "0" , T1 3420b57cec5SDimitry Andric #define P P_ 3430b57cec5SDimitry Andric static char const * vMips16Helper[MAX_STUB_NUMBER+1] = 3440b57cec5SDimitry Andric {nullptr, T1 }; 3450b57cec5SDimitry Andric #undef P 3460b57cec5SDimitry Andric #define P P_ "sf_" 3470b57cec5SDimitry Andric static char const * sfMips16Helper[MAX_STUB_NUMBER+1] = 3480b57cec5SDimitry Andric { T }; 3490b57cec5SDimitry Andric #undef P 3500b57cec5SDimitry Andric #define P P_ "df_" 3510b57cec5SDimitry Andric static char const * dfMips16Helper[MAX_STUB_NUMBER+1] = 3520b57cec5SDimitry Andric { T }; 3530b57cec5SDimitry Andric #undef P 3540b57cec5SDimitry Andric #define P P_ "sc_" 3550b57cec5SDimitry Andric static char const * scMips16Helper[MAX_STUB_NUMBER+1] = 3560b57cec5SDimitry Andric { T }; 3570b57cec5SDimitry Andric #undef P 3580b57cec5SDimitry Andric #define P P_ "dc_" 3590b57cec5SDimitry Andric static char const * dcMips16Helper[MAX_STUB_NUMBER+1] = 3600b57cec5SDimitry Andric { T }; 3610b57cec5SDimitry Andric #undef P 3620b57cec5SDimitry Andric #undef P_ 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric 3650b57cec5SDimitry Andric const char* Mips16TargetLowering:: 3660b57cec5SDimitry Andric getMips16HelperFunction 3670b57cec5SDimitry Andric (Type* RetTy, ArgListTy &Args, bool &needHelper) const { 3680b57cec5SDimitry Andric const unsigned int stubNum = getMips16HelperFunctionStubNumber(Args); 3690b57cec5SDimitry Andric #ifndef NDEBUG 3700b57cec5SDimitry Andric const unsigned int maxStubNum = 10; 3710b57cec5SDimitry Andric assert(stubNum <= maxStubNum); 3720b57cec5SDimitry Andric const bool validStubNum[maxStubNum+1] = 3730b57cec5SDimitry Andric {true, true, true, false, false, true, true, false, false, true, true}; 3740b57cec5SDimitry Andric assert(validStubNum[stubNum]); 3750b57cec5SDimitry Andric #endif 3760b57cec5SDimitry Andric const char *result; 3770b57cec5SDimitry Andric if (RetTy->isFloatTy()) { 3780b57cec5SDimitry Andric result = sfMips16Helper[stubNum]; 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric else if (RetTy ->isDoubleTy()) { 3810b57cec5SDimitry Andric result = dfMips16Helper[stubNum]; 3820b57cec5SDimitry Andric } else if (StructType *SRetTy = dyn_cast<StructType>(RetTy)) { 3830b57cec5SDimitry Andric // check if it's complex 3840b57cec5SDimitry Andric if (SRetTy->getNumElements() == 2) { 3850b57cec5SDimitry Andric if ((SRetTy->getElementType(0)->isFloatTy()) && 3860b57cec5SDimitry Andric (SRetTy->getElementType(1)->isFloatTy())) { 3870b57cec5SDimitry Andric result = scMips16Helper[stubNum]; 3880b57cec5SDimitry Andric } else if ((SRetTy->getElementType(0)->isDoubleTy()) && 3890b57cec5SDimitry Andric (SRetTy->getElementType(1)->isDoubleTy())) { 3900b57cec5SDimitry Andric result = dcMips16Helper[stubNum]; 3910b57cec5SDimitry Andric } else { 3920b57cec5SDimitry Andric llvm_unreachable("Uncovered condition"); 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric } else { 3950b57cec5SDimitry Andric llvm_unreachable("Uncovered condition"); 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric } else { 3980b57cec5SDimitry Andric if (stubNum == 0) { 3990b57cec5SDimitry Andric needHelper = false; 4000b57cec5SDimitry Andric return ""; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric result = vMips16Helper[stubNum]; 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric needHelper = true; 4050b57cec5SDimitry Andric return result; 4060b57cec5SDimitry Andric } 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric void Mips16TargetLowering:: 4090b57cec5SDimitry Andric getOpndList(SmallVectorImpl<SDValue> &Ops, 4100b57cec5SDimitry Andric std::deque< std::pair<unsigned, SDValue> > &RegsToPass, 4110b57cec5SDimitry Andric bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage, 4120b57cec5SDimitry Andric bool IsCallReloc, CallLoweringInfo &CLI, SDValue Callee, 4130b57cec5SDimitry Andric SDValue Chain) const { 4140b57cec5SDimitry Andric SelectionDAG &DAG = CLI.DAG; 4150b57cec5SDimitry Andric MachineFunction &MF = DAG.getMachineFunction(); 4160b57cec5SDimitry Andric MipsFunctionInfo *FuncInfo = MF.getInfo<MipsFunctionInfo>(); 4170b57cec5SDimitry Andric const char* Mips16HelperFunction = nullptr; 4180b57cec5SDimitry Andric bool NeedMips16Helper = false; 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric if (Subtarget.inMips16HardFloat()) { 4210b57cec5SDimitry Andric // 4220b57cec5SDimitry Andric // currently we don't have symbols tagged with the mips16 or mips32 4230b57cec5SDimitry Andric // qualifier so we will assume that we don't know what kind it is. 4240b57cec5SDimitry Andric // and generate the helper 4250b57cec5SDimitry Andric // 4260b57cec5SDimitry Andric bool LookupHelper = true; 4270b57cec5SDimitry Andric if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(CLI.Callee)) { 4280b57cec5SDimitry Andric Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, S->getSymbol() }; 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric if (std::binary_search(std::begin(HardFloatLibCalls), 4310b57cec5SDimitry Andric std::end(HardFloatLibCalls), Find)) 4320b57cec5SDimitry Andric LookupHelper = false; 4330b57cec5SDimitry Andric else { 4340b57cec5SDimitry Andric const char *Symbol = S->getSymbol(); 4350b57cec5SDimitry Andric Mips16IntrinsicHelperType IntrinsicFind = { Symbol, "" }; 4360b57cec5SDimitry Andric const Mips16HardFloatInfo::FuncSignature *Signature = 4370b57cec5SDimitry Andric Mips16HardFloatInfo::findFuncSignature(Symbol); 4380b57cec5SDimitry Andric if (!IsPICCall && (Signature && (FuncInfo->StubsNeeded.find(Symbol) == 4390b57cec5SDimitry Andric FuncInfo->StubsNeeded.end()))) { 4400b57cec5SDimitry Andric FuncInfo->StubsNeeded[Symbol] = Signature; 4410b57cec5SDimitry Andric // 4420b57cec5SDimitry Andric // S2 is normally saved if the stub is for a function which 4430b57cec5SDimitry Andric // returns a float or double value and is not otherwise. This is 4440b57cec5SDimitry Andric // because more work is required after the function the stub 4450b57cec5SDimitry Andric // is calling completes, and so the stub cannot directly return 4460b57cec5SDimitry Andric // and the stub has no stack space to store the return address so 4470b57cec5SDimitry Andric // S2 is used for that purpose. 4480b57cec5SDimitry Andric // In order to take advantage of not saving S2, we need to also 4490b57cec5SDimitry Andric // optimize the call in the stub and this requires some further 4500b57cec5SDimitry Andric // functionality in MipsAsmPrinter which we don't have yet. 4510b57cec5SDimitry Andric // So for now we always save S2. The optimization will be done 4520b57cec5SDimitry Andric // in a follow-on patch. 4530b57cec5SDimitry Andric // 45404eeddc0SDimitry Andric if (true || (Signature->RetSig != Mips16HardFloatInfo::NoFPRet)) 4550b57cec5SDimitry Andric FuncInfo->setSaveS2(); 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric // one more look at list of intrinsics 4580b57cec5SDimitry Andric const Mips16IntrinsicHelperType *Helper = 4590b57cec5SDimitry Andric llvm::lower_bound(Mips16IntrinsicHelper, IntrinsicFind); 4600b57cec5SDimitry Andric if (Helper != std::end(Mips16IntrinsicHelper) && 4610b57cec5SDimitry Andric *Helper == IntrinsicFind) { 4620b57cec5SDimitry Andric Mips16HelperFunction = Helper->Helper; 4630b57cec5SDimitry Andric NeedMips16Helper = true; 4640b57cec5SDimitry Andric LookupHelper = false; 4650b57cec5SDimitry Andric } 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric } else if (GlobalAddressSDNode *G = 4690b57cec5SDimitry Andric dyn_cast<GlobalAddressSDNode>(CLI.Callee)) { 4700b57cec5SDimitry Andric Mips16Libcall Find = { RTLIB::UNKNOWN_LIBCALL, 4710b57cec5SDimitry Andric G->getGlobal()->getName().data() }; 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric if (std::binary_search(std::begin(HardFloatLibCalls), 4740b57cec5SDimitry Andric std::end(HardFloatLibCalls), Find)) 4750b57cec5SDimitry Andric LookupHelper = false; 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric if (LookupHelper) 4780b57cec5SDimitry Andric Mips16HelperFunction = 4790b57cec5SDimitry Andric getMips16HelperFunction(CLI.RetTy, CLI.getArgs(), NeedMips16Helper); 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric SDValue JumpTarget = Callee; 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric // T9 should contain the address of the callee function if 4850b57cec5SDimitry Andric // -relocation-model=pic or it is an indirect call. 4860b57cec5SDimitry Andric if (IsPICCall || !GlobalOrExternal) { 4870b57cec5SDimitry Andric unsigned V0Reg = Mips::V0; 4880b57cec5SDimitry Andric if (NeedMips16Helper) { 4890b57cec5SDimitry Andric RegsToPass.push_front(std::make_pair(V0Reg, Callee)); 4900b57cec5SDimitry Andric JumpTarget = DAG.getExternalSymbol(Mips16HelperFunction, 4910b57cec5SDimitry Andric getPointerTy(DAG.getDataLayout())); 4920b57cec5SDimitry Andric ExternalSymbolSDNode *S = cast<ExternalSymbolSDNode>(JumpTarget); 4930b57cec5SDimitry Andric JumpTarget = getAddrGlobal(S, CLI.DL, JumpTarget.getValueType(), DAG, 4940b57cec5SDimitry Andric MipsII::MO_GOT, Chain, 4955ffd83dbSDimitry Andric FuncInfo->callPtrInfo(MF, S->getSymbol())); 4960b57cec5SDimitry Andric } else 4970b57cec5SDimitry Andric RegsToPass.push_front(std::make_pair((unsigned)Mips::T9, Callee)); 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric Ops.push_back(JumpTarget); 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal, 5030b57cec5SDimitry Andric InternalLinkage, IsCallReloc, CLI, Callee, 5040b57cec5SDimitry Andric Chain); 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric 5070b57cec5SDimitry Andric MachineBasicBlock * 5080b57cec5SDimitry Andric Mips16TargetLowering::emitSel16(unsigned Opc, MachineInstr &MI, 5090b57cec5SDimitry Andric MachineBasicBlock *BB) const { 5100b57cec5SDimitry Andric if (DontExpandCondPseudos16) 5110b57cec5SDimitry Andric return BB; 5120b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 5130b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 5140b57cec5SDimitry Andric // To "insert" a SELECT_CC instruction, we actually have to insert the 5150b57cec5SDimitry Andric // diamond control-flow pattern. The incoming instruction knows the 5160b57cec5SDimitry Andric // destination vreg to set, the condition code register to branch on, the 5170b57cec5SDimitry Andric // true/false values to select between, and a branch opcode to use. 5180b57cec5SDimitry Andric const BasicBlock *LLVM_BB = BB->getBasicBlock(); 5190b57cec5SDimitry Andric MachineFunction::iterator It = ++BB->getIterator(); 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric // thisMBB: 5220b57cec5SDimitry Andric // ... 5230b57cec5SDimitry Andric // TrueVal = ... 5240b57cec5SDimitry Andric // setcc r1, r2, r3 5250b57cec5SDimitry Andric // bNE r1, r0, copy1MBB 5260b57cec5SDimitry Andric // fallthrough --> copy0MBB 5270b57cec5SDimitry Andric MachineBasicBlock *thisMBB = BB; 5280b57cec5SDimitry Andric MachineFunction *F = BB->getParent(); 5290b57cec5SDimitry Andric MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); 5300b57cec5SDimitry Andric MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); 5310b57cec5SDimitry Andric F->insert(It, copy0MBB); 5320b57cec5SDimitry Andric F->insert(It, sinkMBB); 5330b57cec5SDimitry Andric 5340b57cec5SDimitry Andric // Transfer the remainder of BB and its successor edges to sinkMBB. 5350b57cec5SDimitry Andric sinkMBB->splice(sinkMBB->begin(), BB, 5360b57cec5SDimitry Andric std::next(MachineBasicBlock::iterator(MI)), BB->end()); 5370b57cec5SDimitry Andric sinkMBB->transferSuccessorsAndUpdatePHIs(BB); 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric // Next, add the true and fallthrough blocks as its successors. 5400b57cec5SDimitry Andric BB->addSuccessor(copy0MBB); 5410b57cec5SDimitry Andric BB->addSuccessor(sinkMBB); 5420b57cec5SDimitry Andric 5430b57cec5SDimitry Andric BuildMI(BB, DL, TII->get(Opc)) 5440b57cec5SDimitry Andric .addReg(MI.getOperand(3).getReg()) 5450b57cec5SDimitry Andric .addMBB(sinkMBB); 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric // copy0MBB: 5480b57cec5SDimitry Andric // %FalseValue = ... 5490b57cec5SDimitry Andric // # fallthrough to sinkMBB 5500b57cec5SDimitry Andric BB = copy0MBB; 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric // Update machine-CFG edges 5530b57cec5SDimitry Andric BB->addSuccessor(sinkMBB); 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric // sinkMBB: 5560b57cec5SDimitry Andric // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] 5570b57cec5SDimitry Andric // ... 5580b57cec5SDimitry Andric BB = sinkMBB; 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric BuildMI(*BB, BB->begin(), DL, TII->get(Mips::PHI), MI.getOperand(0).getReg()) 5610b57cec5SDimitry Andric .addReg(MI.getOperand(1).getReg()) 5620b57cec5SDimitry Andric .addMBB(thisMBB) 5630b57cec5SDimitry Andric .addReg(MI.getOperand(2).getReg()) 5640b57cec5SDimitry Andric .addMBB(copy0MBB); 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now. 5670b57cec5SDimitry Andric return BB; 5680b57cec5SDimitry Andric } 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric MachineBasicBlock * 5710b57cec5SDimitry Andric Mips16TargetLowering::emitSelT16(unsigned Opc1, unsigned Opc2, MachineInstr &MI, 5720b57cec5SDimitry Andric MachineBasicBlock *BB) const { 5730b57cec5SDimitry Andric if (DontExpandCondPseudos16) 5740b57cec5SDimitry Andric return BB; 5750b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 5760b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 5770b57cec5SDimitry Andric // To "insert" a SELECT_CC instruction, we actually have to insert the 5780b57cec5SDimitry Andric // diamond control-flow pattern. The incoming instruction knows the 5790b57cec5SDimitry Andric // destination vreg to set, the condition code register to branch on, the 5800b57cec5SDimitry Andric // true/false values to select between, and a branch opcode to use. 5810b57cec5SDimitry Andric const BasicBlock *LLVM_BB = BB->getBasicBlock(); 5820b57cec5SDimitry Andric MachineFunction::iterator It = ++BB->getIterator(); 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric // thisMBB: 5850b57cec5SDimitry Andric // ... 5860b57cec5SDimitry Andric // TrueVal = ... 5870b57cec5SDimitry Andric // setcc r1, r2, r3 5880b57cec5SDimitry Andric // bNE r1, r0, copy1MBB 5890b57cec5SDimitry Andric // fallthrough --> copy0MBB 5900b57cec5SDimitry Andric MachineBasicBlock *thisMBB = BB; 5910b57cec5SDimitry Andric MachineFunction *F = BB->getParent(); 5920b57cec5SDimitry Andric MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); 5930b57cec5SDimitry Andric MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); 5940b57cec5SDimitry Andric F->insert(It, copy0MBB); 5950b57cec5SDimitry Andric F->insert(It, sinkMBB); 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric // Transfer the remainder of BB and its successor edges to sinkMBB. 5980b57cec5SDimitry Andric sinkMBB->splice(sinkMBB->begin(), BB, 5990b57cec5SDimitry Andric std::next(MachineBasicBlock::iterator(MI)), BB->end()); 6000b57cec5SDimitry Andric sinkMBB->transferSuccessorsAndUpdatePHIs(BB); 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric // Next, add the true and fallthrough blocks as its successors. 6030b57cec5SDimitry Andric BB->addSuccessor(copy0MBB); 6040b57cec5SDimitry Andric BB->addSuccessor(sinkMBB); 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric BuildMI(BB, DL, TII->get(Opc2)) 6070b57cec5SDimitry Andric .addReg(MI.getOperand(3).getReg()) 6080b57cec5SDimitry Andric .addReg(MI.getOperand(4).getReg()); 6090b57cec5SDimitry Andric BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB); 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric // copy0MBB: 6120b57cec5SDimitry Andric // %FalseValue = ... 6130b57cec5SDimitry Andric // # fallthrough to sinkMBB 6140b57cec5SDimitry Andric BB = copy0MBB; 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric // Update machine-CFG edges 6170b57cec5SDimitry Andric BB->addSuccessor(sinkMBB); 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric // sinkMBB: 6200b57cec5SDimitry Andric // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] 6210b57cec5SDimitry Andric // ... 6220b57cec5SDimitry Andric BB = sinkMBB; 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric BuildMI(*BB, BB->begin(), DL, TII->get(Mips::PHI), MI.getOperand(0).getReg()) 6250b57cec5SDimitry Andric .addReg(MI.getOperand(1).getReg()) 6260b57cec5SDimitry Andric .addMBB(thisMBB) 6270b57cec5SDimitry Andric .addReg(MI.getOperand(2).getReg()) 6280b57cec5SDimitry Andric .addMBB(copy0MBB); 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now. 6310b57cec5SDimitry Andric return BB; 6320b57cec5SDimitry Andric 6330b57cec5SDimitry Andric } 6340b57cec5SDimitry Andric 6350b57cec5SDimitry Andric MachineBasicBlock * 6360b57cec5SDimitry Andric Mips16TargetLowering::emitSeliT16(unsigned Opc1, unsigned Opc2, 6370b57cec5SDimitry Andric MachineInstr &MI, 6380b57cec5SDimitry Andric MachineBasicBlock *BB) const { 6390b57cec5SDimitry Andric if (DontExpandCondPseudos16) 6400b57cec5SDimitry Andric return BB; 6410b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 6420b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 6430b57cec5SDimitry Andric // To "insert" a SELECT_CC instruction, we actually have to insert the 6440b57cec5SDimitry Andric // diamond control-flow pattern. The incoming instruction knows the 6450b57cec5SDimitry Andric // destination vreg to set, the condition code register to branch on, the 6460b57cec5SDimitry Andric // true/false values to select between, and a branch opcode to use. 6470b57cec5SDimitry Andric const BasicBlock *LLVM_BB = BB->getBasicBlock(); 6480b57cec5SDimitry Andric MachineFunction::iterator It = ++BB->getIterator(); 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric // thisMBB: 6510b57cec5SDimitry Andric // ... 6520b57cec5SDimitry Andric // TrueVal = ... 6530b57cec5SDimitry Andric // setcc r1, r2, r3 6540b57cec5SDimitry Andric // bNE r1, r0, copy1MBB 6550b57cec5SDimitry Andric // fallthrough --> copy0MBB 6560b57cec5SDimitry Andric MachineBasicBlock *thisMBB = BB; 6570b57cec5SDimitry Andric MachineFunction *F = BB->getParent(); 6580b57cec5SDimitry Andric MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB); 6590b57cec5SDimitry Andric MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); 6600b57cec5SDimitry Andric F->insert(It, copy0MBB); 6610b57cec5SDimitry Andric F->insert(It, sinkMBB); 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric // Transfer the remainder of BB and its successor edges to sinkMBB. 6640b57cec5SDimitry Andric sinkMBB->splice(sinkMBB->begin(), BB, 6650b57cec5SDimitry Andric std::next(MachineBasicBlock::iterator(MI)), BB->end()); 6660b57cec5SDimitry Andric sinkMBB->transferSuccessorsAndUpdatePHIs(BB); 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric // Next, add the true and fallthrough blocks as its successors. 6690b57cec5SDimitry Andric BB->addSuccessor(copy0MBB); 6700b57cec5SDimitry Andric BB->addSuccessor(sinkMBB); 6710b57cec5SDimitry Andric 6720b57cec5SDimitry Andric BuildMI(BB, DL, TII->get(Opc2)) 6730b57cec5SDimitry Andric .addReg(MI.getOperand(3).getReg()) 6740b57cec5SDimitry Andric .addImm(MI.getOperand(4).getImm()); 6750b57cec5SDimitry Andric BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB); 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric // copy0MBB: 6780b57cec5SDimitry Andric // %FalseValue = ... 6790b57cec5SDimitry Andric // # fallthrough to sinkMBB 6800b57cec5SDimitry Andric BB = copy0MBB; 6810b57cec5SDimitry Andric 6820b57cec5SDimitry Andric // Update machine-CFG edges 6830b57cec5SDimitry Andric BB->addSuccessor(sinkMBB); 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric // sinkMBB: 6860b57cec5SDimitry Andric // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] 6870b57cec5SDimitry Andric // ... 6880b57cec5SDimitry Andric BB = sinkMBB; 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric BuildMI(*BB, BB->begin(), DL, TII->get(Mips::PHI), MI.getOperand(0).getReg()) 6910b57cec5SDimitry Andric .addReg(MI.getOperand(1).getReg()) 6920b57cec5SDimitry Andric .addMBB(thisMBB) 6930b57cec5SDimitry Andric .addReg(MI.getOperand(2).getReg()) 6940b57cec5SDimitry Andric .addMBB(copy0MBB); 6950b57cec5SDimitry Andric 6960b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now. 6970b57cec5SDimitry Andric return BB; 6980b57cec5SDimitry Andric 6990b57cec5SDimitry Andric } 7000b57cec5SDimitry Andric 7010b57cec5SDimitry Andric MachineBasicBlock * 7020b57cec5SDimitry Andric Mips16TargetLowering::emitFEXT_T8I816_ins(unsigned BtOpc, unsigned CmpOpc, 7030b57cec5SDimitry Andric MachineInstr &MI, 7040b57cec5SDimitry Andric MachineBasicBlock *BB) const { 7050b57cec5SDimitry Andric if (DontExpandCondPseudos16) 7060b57cec5SDimitry Andric return BB; 7070b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 7088bcb0991SDimitry Andric Register regX = MI.getOperand(0).getReg(); 7098bcb0991SDimitry Andric Register regY = MI.getOperand(1).getReg(); 7100b57cec5SDimitry Andric MachineBasicBlock *target = MI.getOperand(2).getMBB(); 7110b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(CmpOpc)) 7120b57cec5SDimitry Andric .addReg(regX) 7130b57cec5SDimitry Andric .addReg(regY); 7140b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(BtOpc)).addMBB(target); 7150b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now. 7160b57cec5SDimitry Andric return BB; 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric MachineBasicBlock *Mips16TargetLowering::emitFEXT_T8I8I16_ins( 7200b57cec5SDimitry Andric unsigned BtOpc, unsigned CmpiOpc, unsigned CmpiXOpc, bool ImmSigned, 7210b57cec5SDimitry Andric MachineInstr &MI, MachineBasicBlock *BB) const { 7220b57cec5SDimitry Andric if (DontExpandCondPseudos16) 7230b57cec5SDimitry Andric return BB; 7240b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 7258bcb0991SDimitry Andric Register regX = MI.getOperand(0).getReg(); 7260b57cec5SDimitry Andric int64_t imm = MI.getOperand(1).getImm(); 7270b57cec5SDimitry Andric MachineBasicBlock *target = MI.getOperand(2).getMBB(); 7280b57cec5SDimitry Andric unsigned CmpOpc; 7290b57cec5SDimitry Andric if (isUInt<8>(imm)) 7300b57cec5SDimitry Andric CmpOpc = CmpiOpc; 7310b57cec5SDimitry Andric else if ((!ImmSigned && isUInt<16>(imm)) || 7320b57cec5SDimitry Andric (ImmSigned && isInt<16>(imm))) 7330b57cec5SDimitry Andric CmpOpc = CmpiXOpc; 7340b57cec5SDimitry Andric else 7350b57cec5SDimitry Andric llvm_unreachable("immediate field not usable"); 7360b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(CmpOpc)).addReg(regX).addImm(imm); 7370b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(BtOpc)).addMBB(target); 7380b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now. 7390b57cec5SDimitry Andric return BB; 7400b57cec5SDimitry Andric } 7410b57cec5SDimitry Andric 7420b57cec5SDimitry Andric static unsigned Mips16WhichOp8uOr16simm 7430b57cec5SDimitry Andric (unsigned shortOp, unsigned longOp, int64_t Imm) { 7440b57cec5SDimitry Andric if (isUInt<8>(Imm)) 7450b57cec5SDimitry Andric return shortOp; 7460b57cec5SDimitry Andric else if (isInt<16>(Imm)) 7470b57cec5SDimitry Andric return longOp; 7480b57cec5SDimitry Andric else 7490b57cec5SDimitry Andric llvm_unreachable("immediate field not usable"); 7500b57cec5SDimitry Andric } 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric MachineBasicBlock * 7530b57cec5SDimitry Andric Mips16TargetLowering::emitFEXT_CCRX16_ins(unsigned SltOpc, MachineInstr &MI, 7540b57cec5SDimitry Andric MachineBasicBlock *BB) const { 7550b57cec5SDimitry Andric if (DontExpandCondPseudos16) 7560b57cec5SDimitry Andric return BB; 7570b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 7588bcb0991SDimitry Andric Register CC = MI.getOperand(0).getReg(); 7598bcb0991SDimitry Andric Register regX = MI.getOperand(1).getReg(); 7608bcb0991SDimitry Andric Register regY = MI.getOperand(2).getReg(); 7610b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(SltOpc)) 7620b57cec5SDimitry Andric .addReg(regX) 7630b57cec5SDimitry Andric .addReg(regY); 7640b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(Mips::MoveR3216), CC) 7650b57cec5SDimitry Andric .addReg(Mips::T8); 7660b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now. 7670b57cec5SDimitry Andric return BB; 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric MachineBasicBlock * 7710b57cec5SDimitry Andric Mips16TargetLowering::emitFEXT_CCRXI16_ins(unsigned SltiOpc, unsigned SltiXOpc, 7720b57cec5SDimitry Andric MachineInstr &MI, 7730b57cec5SDimitry Andric MachineBasicBlock *BB) const { 7740b57cec5SDimitry Andric if (DontExpandCondPseudos16) 7750b57cec5SDimitry Andric return BB; 7760b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget.getInstrInfo(); 7778bcb0991SDimitry Andric Register CC = MI.getOperand(0).getReg(); 7788bcb0991SDimitry Andric Register regX = MI.getOperand(1).getReg(); 7790b57cec5SDimitry Andric int64_t Imm = MI.getOperand(2).getImm(); 7800b57cec5SDimitry Andric unsigned SltOpc = Mips16WhichOp8uOr16simm(SltiOpc, SltiXOpc, Imm); 7810b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(SltOpc)).addReg(regX).addImm(Imm); 7820b57cec5SDimitry Andric BuildMI(*BB, MI, MI.getDebugLoc(), TII->get(Mips::MoveR3216), CC) 7830b57cec5SDimitry Andric .addReg(Mips::T8); 7840b57cec5SDimitry Andric MI.eraseFromParent(); // The pseudo instruction is gone now. 7850b57cec5SDimitry Andric return BB; 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric } 788