15ffd83dbSDimitry Andric //===- AArch64RegisterBankInfo.cpp ----------------------------------------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric /// \file 95ffd83dbSDimitry Andric /// This file implements the targeting of the RegisterBankInfo class for 105ffd83dbSDimitry Andric /// AArch64. 115ffd83dbSDimitry Andric /// \todo This should be generated by TableGen. 125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 135ffd83dbSDimitry Andric 145ffd83dbSDimitry Andric #include "AArch64RegisterBankInfo.h" 15349cc55cSDimitry Andric #include "AArch64RegisterInfo.h" 16349cc55cSDimitry Andric #include "MCTargetDesc/AArch64MCTargetDesc.h" 17e8d8bef9SDimitry Andric #include "llvm/ADT/STLExtras.h" 185ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 19349cc55cSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 20*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 21fe6060f1SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h" 2206c3fb27SDimitry Andric #include "llvm/CodeGen/LowLevelTypeUtils.h" 235ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 245ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 255ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 265ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 2781ad6265SDimitry Andric #include "llvm/CodeGen/RegisterBank.h" 2881ad6265SDimitry Andric #include "llvm/CodeGen/RegisterBankInfo.h" 295ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 305ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 315ffd83dbSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 32fe6060f1SDimitry Andric #include "llvm/IR/IntrinsicsAArch64.h" 335ffd83dbSDimitry Andric #include "llvm/Support/ErrorHandling.h" 345f757f3fSDimitry Andric #include "llvm/Support/Threading.h" 355ffd83dbSDimitry Andric #include <algorithm> 365ffd83dbSDimitry Andric #include <cassert> 375ffd83dbSDimitry Andric 385ffd83dbSDimitry Andric #define GET_TARGET_REGBANK_IMPL 395ffd83dbSDimitry Andric #include "AArch64GenRegisterBank.inc" 405ffd83dbSDimitry Andric 415ffd83dbSDimitry Andric // This file will be TableGen'ed at some point. 425ffd83dbSDimitry Andric #include "AArch64GenRegisterBankInfo.def" 435ffd83dbSDimitry Andric 445ffd83dbSDimitry Andric using namespace llvm; 455ffd83dbSDimitry Andric 4681ad6265SDimitry Andric AArch64RegisterBankInfo::AArch64RegisterBankInfo( 4781ad6265SDimitry Andric const TargetRegisterInfo &TRI) { 485ffd83dbSDimitry Andric static llvm::once_flag InitializeRegisterBankFlag; 495ffd83dbSDimitry Andric 505ffd83dbSDimitry Andric static auto InitializeRegisterBankOnce = [&]() { 515ffd83dbSDimitry Andric // We have only one set of register banks, whatever the subtarget 525ffd83dbSDimitry Andric // is. Therefore, the initialization of the RegBanks table should be 535ffd83dbSDimitry Andric // done only once. Indeed the table of all register banks 545ffd83dbSDimitry Andric // (AArch64::RegBanks) is unique in the compiler. At some point, it 555ffd83dbSDimitry Andric // will get tablegen'ed and the whole constructor becomes empty. 565ffd83dbSDimitry Andric 575ffd83dbSDimitry Andric const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID); 585ffd83dbSDimitry Andric (void)RBGPR; 595ffd83dbSDimitry Andric assert(&AArch64::GPRRegBank == &RBGPR && 605ffd83dbSDimitry Andric "The order in RegBanks is messed up"); 615ffd83dbSDimitry Andric 625ffd83dbSDimitry Andric const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); 635ffd83dbSDimitry Andric (void)RBFPR; 645ffd83dbSDimitry Andric assert(&AArch64::FPRRegBank == &RBFPR && 655ffd83dbSDimitry Andric "The order in RegBanks is messed up"); 665ffd83dbSDimitry Andric 675ffd83dbSDimitry Andric const RegisterBank &RBCCR = getRegBank(AArch64::CCRegBankID); 685ffd83dbSDimitry Andric (void)RBCCR; 695ffd83dbSDimitry Andric assert(&AArch64::CCRegBank == &RBCCR && 705ffd83dbSDimitry Andric "The order in RegBanks is messed up"); 715ffd83dbSDimitry Andric 725ffd83dbSDimitry Andric // The GPR register bank is fully defined by all the registers in 735ffd83dbSDimitry Andric // GR64all + its subclasses. 745ffd83dbSDimitry Andric assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) && 755ffd83dbSDimitry Andric "Subclass not added?"); 7606c3fb27SDimitry Andric assert(getMaximumSize(RBGPR.getID()) == 128 && 7706c3fb27SDimitry Andric "GPRs should hold up to 128-bit"); 785ffd83dbSDimitry Andric 795ffd83dbSDimitry Andric // The FPR register bank is fully defined by all the registers in 805ffd83dbSDimitry Andric // GR64all + its subclasses. 815ffd83dbSDimitry Andric assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) && 825ffd83dbSDimitry Andric "Subclass not added?"); 835ffd83dbSDimitry Andric assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) && 845ffd83dbSDimitry Andric "Subclass not added?"); 8506c3fb27SDimitry Andric assert(getMaximumSize(RBFPR.getID()) == 512 && 865ffd83dbSDimitry Andric "FPRs should hold up to 512-bit via QQQQ sequence"); 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) && 895ffd83dbSDimitry Andric "Class not added?"); 9006c3fb27SDimitry Andric assert(getMaximumSize(RBCCR.getID()) == 32 && 9106c3fb27SDimitry Andric "CCR should hold up to 32-bit"); 925ffd83dbSDimitry Andric 935ffd83dbSDimitry Andric // Check that the TableGen'ed like file is in sync we our expectations. 945ffd83dbSDimitry Andric // First, the Idx. 955ffd83dbSDimitry Andric assert(checkPartialMappingIdx(PMI_FirstGPR, PMI_LastGPR, 96fe6060f1SDimitry Andric {PMI_GPR32, PMI_GPR64, PMI_GPR128}) && 975ffd83dbSDimitry Andric "PartialMappingIdx's are incorrectly ordered"); 985ffd83dbSDimitry Andric assert(checkPartialMappingIdx(PMI_FirstFPR, PMI_LastFPR, 995ffd83dbSDimitry Andric {PMI_FPR16, PMI_FPR32, PMI_FPR64, PMI_FPR128, 1005ffd83dbSDimitry Andric PMI_FPR256, PMI_FPR512}) && 1015ffd83dbSDimitry Andric "PartialMappingIdx's are incorrectly ordered"); 1025ffd83dbSDimitry Andric // Now, the content. 1035ffd83dbSDimitry Andric // Check partial mapping. 1045ffd83dbSDimitry Andric #define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \ 1055ffd83dbSDimitry Andric do { \ 1065ffd83dbSDimitry Andric assert( \ 1075ffd83dbSDimitry Andric checkPartialMap(PartialMappingIdx::Idx, ValStartIdx, ValLength, RB) && \ 1085ffd83dbSDimitry Andric #Idx " is incorrectly initialized"); \ 1095ffd83dbSDimitry Andric } while (false) 1105ffd83dbSDimitry Andric 1115ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_GPR32, 0, 32, RBGPR); 1125ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_GPR64, 0, 64, RBGPR); 113fe6060f1SDimitry Andric CHECK_PARTIALMAP(PMI_GPR128, 0, 128, RBGPR); 1145ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_FPR16, 0, 16, RBFPR); 1155ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_FPR32, 0, 32, RBFPR); 1165ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_FPR64, 0, 64, RBFPR); 1175ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_FPR128, 0, 128, RBFPR); 1185ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_FPR256, 0, 256, RBFPR); 1195ffd83dbSDimitry Andric CHECK_PARTIALMAP(PMI_FPR512, 0, 512, RBFPR); 1205ffd83dbSDimitry Andric 1215ffd83dbSDimitry Andric // Check value mapping. 1225ffd83dbSDimitry Andric #define CHECK_VALUEMAP_IMPL(RBName, Size, Offset) \ 1235ffd83dbSDimitry Andric do { \ 1245ffd83dbSDimitry Andric assert(checkValueMapImpl(PartialMappingIdx::PMI_##RBName##Size, \ 1255ffd83dbSDimitry Andric PartialMappingIdx::PMI_First##RBName, Size, \ 1265ffd83dbSDimitry Andric Offset) && \ 1275ffd83dbSDimitry Andric #RBName #Size " " #Offset " is incorrectly initialized"); \ 1285ffd83dbSDimitry Andric } while (false) 1295ffd83dbSDimitry Andric 1305ffd83dbSDimitry Andric #define CHECK_VALUEMAP(RBName, Size) CHECK_VALUEMAP_IMPL(RBName, Size, 0) 1315ffd83dbSDimitry Andric 1325ffd83dbSDimitry Andric CHECK_VALUEMAP(GPR, 32); 1335ffd83dbSDimitry Andric CHECK_VALUEMAP(GPR, 64); 134fe6060f1SDimitry Andric CHECK_VALUEMAP(GPR, 128); 1355ffd83dbSDimitry Andric CHECK_VALUEMAP(FPR, 16); 1365ffd83dbSDimitry Andric CHECK_VALUEMAP(FPR, 32); 1375ffd83dbSDimitry Andric CHECK_VALUEMAP(FPR, 64); 1385ffd83dbSDimitry Andric CHECK_VALUEMAP(FPR, 128); 1395ffd83dbSDimitry Andric CHECK_VALUEMAP(FPR, 256); 1405ffd83dbSDimitry Andric CHECK_VALUEMAP(FPR, 512); 1415ffd83dbSDimitry Andric 1425ffd83dbSDimitry Andric // Check the value mapping for 3-operands instructions where all the operands 1435ffd83dbSDimitry Andric // map to the same value mapping. 1445ffd83dbSDimitry Andric #define CHECK_VALUEMAP_3OPS(RBName, Size) \ 1455ffd83dbSDimitry Andric do { \ 1465ffd83dbSDimitry Andric CHECK_VALUEMAP_IMPL(RBName, Size, 0); \ 1475ffd83dbSDimitry Andric CHECK_VALUEMAP_IMPL(RBName, Size, 1); \ 1485ffd83dbSDimitry Andric CHECK_VALUEMAP_IMPL(RBName, Size, 2); \ 1495ffd83dbSDimitry Andric } while (false) 1505ffd83dbSDimitry Andric 1515ffd83dbSDimitry Andric CHECK_VALUEMAP_3OPS(GPR, 32); 1525ffd83dbSDimitry Andric CHECK_VALUEMAP_3OPS(GPR, 64); 153fe6060f1SDimitry Andric CHECK_VALUEMAP_3OPS(GPR, 128); 1545ffd83dbSDimitry Andric CHECK_VALUEMAP_3OPS(FPR, 32); 1555ffd83dbSDimitry Andric CHECK_VALUEMAP_3OPS(FPR, 64); 1565ffd83dbSDimitry Andric CHECK_VALUEMAP_3OPS(FPR, 128); 1575ffd83dbSDimitry Andric CHECK_VALUEMAP_3OPS(FPR, 256); 1585ffd83dbSDimitry Andric CHECK_VALUEMAP_3OPS(FPR, 512); 1595ffd83dbSDimitry Andric 1605ffd83dbSDimitry Andric #define CHECK_VALUEMAP_CROSSREGCPY(RBNameDst, RBNameSrc, Size) \ 1615ffd83dbSDimitry Andric do { \ 1625ffd83dbSDimitry Andric unsigned PartialMapDstIdx = PMI_##RBNameDst##Size - PMI_Min; \ 1635ffd83dbSDimitry Andric unsigned PartialMapSrcIdx = PMI_##RBNameSrc##Size - PMI_Min; \ 1645ffd83dbSDimitry Andric (void)PartialMapDstIdx; \ 1655ffd83dbSDimitry Andric (void)PartialMapSrcIdx; \ 166*0fca6ea1SDimitry Andric const ValueMapping *Map = getCopyMapping(AArch64::RBNameDst##RegBankID, \ 167*0fca6ea1SDimitry Andric AArch64::RBNameSrc##RegBankID, \ 168*0fca6ea1SDimitry Andric TypeSize::getFixed(Size)); \ 1695ffd83dbSDimitry Andric (void)Map; \ 1705ffd83dbSDimitry Andric assert(Map[0].BreakDown == \ 1715ffd83dbSDimitry Andric &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \ 172*0fca6ea1SDimitry Andric Map[0].NumBreakDowns == 1 && \ 173*0fca6ea1SDimitry Andric #RBNameDst #Size " Dst is incorrectly initialized"); \ 1745ffd83dbSDimitry Andric assert(Map[1].BreakDown == \ 1755ffd83dbSDimitry Andric &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \ 176*0fca6ea1SDimitry Andric Map[1].NumBreakDowns == 1 && \ 177*0fca6ea1SDimitry Andric #RBNameSrc #Size " Src is incorrectly initialized"); \ 1785ffd83dbSDimitry Andric \ 1795ffd83dbSDimitry Andric } while (false) 1805ffd83dbSDimitry Andric 1815ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 32); 1825ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 32); 1835ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 64); 1845ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 64); 1855ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 32); 1865ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 32); 1875ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64); 1885ffd83dbSDimitry Andric CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64); 1895ffd83dbSDimitry Andric 1905ffd83dbSDimitry Andric #define CHECK_VALUEMAP_FPEXT(DstSize, SrcSize) \ 1915ffd83dbSDimitry Andric do { \ 1925ffd83dbSDimitry Andric unsigned PartialMapDstIdx = PMI_FPR##DstSize - PMI_Min; \ 1935ffd83dbSDimitry Andric unsigned PartialMapSrcIdx = PMI_FPR##SrcSize - PMI_Min; \ 1945ffd83dbSDimitry Andric (void)PartialMapDstIdx; \ 1955ffd83dbSDimitry Andric (void)PartialMapSrcIdx; \ 1965ffd83dbSDimitry Andric const ValueMapping *Map = getFPExtMapping(DstSize, SrcSize); \ 1975ffd83dbSDimitry Andric (void)Map; \ 1985ffd83dbSDimitry Andric assert(Map[0].BreakDown == \ 1995ffd83dbSDimitry Andric &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \ 2005ffd83dbSDimitry Andric Map[0].NumBreakDowns == 1 && "FPR" #DstSize \ 2015ffd83dbSDimitry Andric " Dst is incorrectly initialized"); \ 2025ffd83dbSDimitry Andric assert(Map[1].BreakDown == \ 2035ffd83dbSDimitry Andric &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \ 2045ffd83dbSDimitry Andric Map[1].NumBreakDowns == 1 && "FPR" #SrcSize \ 2055ffd83dbSDimitry Andric " Src is incorrectly initialized"); \ 2065ffd83dbSDimitry Andric \ 2075ffd83dbSDimitry Andric } while (false) 2085ffd83dbSDimitry Andric 2095ffd83dbSDimitry Andric CHECK_VALUEMAP_FPEXT(32, 16); 2105ffd83dbSDimitry Andric CHECK_VALUEMAP_FPEXT(64, 16); 2115ffd83dbSDimitry Andric CHECK_VALUEMAP_FPEXT(64, 32); 2125ffd83dbSDimitry Andric CHECK_VALUEMAP_FPEXT(128, 64); 2135ffd83dbSDimitry Andric 2145ffd83dbSDimitry Andric assert(verify(TRI) && "Invalid register bank information"); 2155ffd83dbSDimitry Andric }; 2165ffd83dbSDimitry Andric 2175ffd83dbSDimitry Andric llvm::call_once(InitializeRegisterBankFlag, InitializeRegisterBankOnce); 2185ffd83dbSDimitry Andric } 2195ffd83dbSDimitry Andric 2205ffd83dbSDimitry Andric unsigned AArch64RegisterBankInfo::copyCost(const RegisterBank &A, 2215ffd83dbSDimitry Andric const RegisterBank &B, 222*0fca6ea1SDimitry Andric const TypeSize Size) const { 2235ffd83dbSDimitry Andric // What do we do with different size? 2245ffd83dbSDimitry Andric // copy are same size. 2255ffd83dbSDimitry Andric // Will introduce other hooks for different size: 2265ffd83dbSDimitry Andric // * extract cost. 2275ffd83dbSDimitry Andric // * build_sequence cost. 2285ffd83dbSDimitry Andric 2295ffd83dbSDimitry Andric // Copy from (resp. to) GPR to (resp. from) FPR involves FMOV. 2305ffd83dbSDimitry Andric // FIXME: This should be deduced from the scheduling model. 2315ffd83dbSDimitry Andric if (&A == &AArch64::GPRRegBank && &B == &AArch64::FPRRegBank) 2325ffd83dbSDimitry Andric // FMOVXDr or FMOVWSr. 2335ffd83dbSDimitry Andric return 5; 2345ffd83dbSDimitry Andric if (&A == &AArch64::FPRRegBank && &B == &AArch64::GPRRegBank) 2355ffd83dbSDimitry Andric // FMOVDXr or FMOVSWr. 2365ffd83dbSDimitry Andric return 4; 2375ffd83dbSDimitry Andric 2385ffd83dbSDimitry Andric return RegisterBankInfo::copyCost(A, B, Size); 2395ffd83dbSDimitry Andric } 2405ffd83dbSDimitry Andric 2415ffd83dbSDimitry Andric const RegisterBank & 2425ffd83dbSDimitry Andric AArch64RegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, 2435ffd83dbSDimitry Andric LLT) const { 2445ffd83dbSDimitry Andric switch (RC.getID()) { 2455ffd83dbSDimitry Andric case AArch64::FPR8RegClassID: 2465ffd83dbSDimitry Andric case AArch64::FPR16RegClassID: 2475ffd83dbSDimitry Andric case AArch64::FPR16_loRegClassID: 2485ffd83dbSDimitry Andric case AArch64::FPR32_with_hsub_in_FPR16_loRegClassID: 2495ffd83dbSDimitry Andric case AArch64::FPR32RegClassID: 2505ffd83dbSDimitry Andric case AArch64::FPR64RegClassID: 2515ffd83dbSDimitry Andric case AArch64::FPR128RegClassID: 2525f757f3fSDimitry Andric case AArch64::FPR64_loRegClassID: 2535ffd83dbSDimitry Andric case AArch64::FPR128_loRegClassID: 2545f757f3fSDimitry Andric case AArch64::FPR128_0to7RegClassID: 2555ffd83dbSDimitry Andric case AArch64::DDRegClassID: 2565ffd83dbSDimitry Andric case AArch64::DDDRegClassID: 2575ffd83dbSDimitry Andric case AArch64::DDDDRegClassID: 2585ffd83dbSDimitry Andric case AArch64::QQRegClassID: 2595ffd83dbSDimitry Andric case AArch64::QQQRegClassID: 2605ffd83dbSDimitry Andric case AArch64::QQQQRegClassID: 261*0fca6ea1SDimitry Andric case AArch64::ZPRRegClassID: 262*0fca6ea1SDimitry Andric case AArch64::ZPR_3bRegClassID: 2635ffd83dbSDimitry Andric return getRegBank(AArch64::FPRRegBankID); 2645ffd83dbSDimitry Andric case AArch64::GPR32commonRegClassID: 2655ffd83dbSDimitry Andric case AArch64::GPR32RegClassID: 2665ffd83dbSDimitry Andric case AArch64::GPR32spRegClassID: 2675ffd83dbSDimitry Andric case AArch64::GPR32sponlyRegClassID: 2685ffd83dbSDimitry Andric case AArch64::GPR32argRegClassID: 2695ffd83dbSDimitry Andric case AArch64::GPR32allRegClassID: 2705ffd83dbSDimitry Andric case AArch64::GPR64commonRegClassID: 2715ffd83dbSDimitry Andric case AArch64::GPR64RegClassID: 2725ffd83dbSDimitry Andric case AArch64::GPR64spRegClassID: 2735ffd83dbSDimitry Andric case AArch64::GPR64sponlyRegClassID: 2745ffd83dbSDimitry Andric case AArch64::GPR64argRegClassID: 2755ffd83dbSDimitry Andric case AArch64::GPR64allRegClassID: 2765ffd83dbSDimitry Andric case AArch64::GPR64noipRegClassID: 2775ffd83dbSDimitry Andric case AArch64::GPR64common_and_GPR64noipRegClassID: 2785ffd83dbSDimitry Andric case AArch64::GPR64noip_and_tcGPR64RegClassID: 2795ffd83dbSDimitry Andric case AArch64::tcGPR64RegClassID: 280*0fca6ea1SDimitry Andric case AArch64::tcGPRx16x17RegClassID: 281*0fca6ea1SDimitry Andric case AArch64::tcGPRx17RegClassID: 282*0fca6ea1SDimitry Andric case AArch64::tcGPRnotx16RegClassID: 2835ffd83dbSDimitry Andric case AArch64::WSeqPairsClassRegClassID: 2845ffd83dbSDimitry Andric case AArch64::XSeqPairsClassRegClassID: 285bdd1243dSDimitry Andric case AArch64::MatrixIndexGPR32_8_11RegClassID: 286fe6060f1SDimitry Andric case AArch64::MatrixIndexGPR32_12_15RegClassID: 287bdd1243dSDimitry Andric case AArch64::GPR64_with_sub_32_in_MatrixIndexGPR32_8_11RegClassID: 288349cc55cSDimitry Andric case AArch64::GPR64_with_sub_32_in_MatrixIndexGPR32_12_15RegClassID: 2895ffd83dbSDimitry Andric return getRegBank(AArch64::GPRRegBankID); 2905ffd83dbSDimitry Andric case AArch64::CCRRegClassID: 2915ffd83dbSDimitry Andric return getRegBank(AArch64::CCRegBankID); 2925ffd83dbSDimitry Andric default: 2935ffd83dbSDimitry Andric llvm_unreachable("Register class not supported"); 2945ffd83dbSDimitry Andric } 2955ffd83dbSDimitry Andric } 2965ffd83dbSDimitry Andric 2975ffd83dbSDimitry Andric RegisterBankInfo::InstructionMappings 2985ffd83dbSDimitry Andric AArch64RegisterBankInfo::getInstrAlternativeMappings( 2995ffd83dbSDimitry Andric const MachineInstr &MI) const { 3005ffd83dbSDimitry Andric const MachineFunction &MF = *MI.getParent()->getParent(); 3015ffd83dbSDimitry Andric const TargetSubtargetInfo &STI = MF.getSubtarget(); 3025ffd83dbSDimitry Andric const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 3035ffd83dbSDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 3045ffd83dbSDimitry Andric 3055ffd83dbSDimitry Andric switch (MI.getOpcode()) { 3065ffd83dbSDimitry Andric case TargetOpcode::G_OR: { 3075ffd83dbSDimitry Andric // 32 and 64-bit or can be mapped on either FPR or 3085ffd83dbSDimitry Andric // GPR for the same cost. 309*0fca6ea1SDimitry Andric TypeSize Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 3105ffd83dbSDimitry Andric if (Size != 32 && Size != 64) 3115ffd83dbSDimitry Andric break; 3125ffd83dbSDimitry Andric 3135ffd83dbSDimitry Andric // If the instruction has any implicit-defs or uses, 3145ffd83dbSDimitry Andric // do not mess with it. 3155ffd83dbSDimitry Andric if (MI.getNumOperands() != 3) 3165ffd83dbSDimitry Andric break; 3175ffd83dbSDimitry Andric InstructionMappings AltMappings; 3185ffd83dbSDimitry Andric const InstructionMapping &GPRMapping = getInstructionMapping( 3195ffd83dbSDimitry Andric /*ID*/ 1, /*Cost*/ 1, getValueMapping(PMI_FirstGPR, Size), 3205ffd83dbSDimitry Andric /*NumOperands*/ 3); 3215ffd83dbSDimitry Andric const InstructionMapping &FPRMapping = getInstructionMapping( 3225ffd83dbSDimitry Andric /*ID*/ 2, /*Cost*/ 1, getValueMapping(PMI_FirstFPR, Size), 3235ffd83dbSDimitry Andric /*NumOperands*/ 3); 3245ffd83dbSDimitry Andric 3255ffd83dbSDimitry Andric AltMappings.push_back(&GPRMapping); 3265ffd83dbSDimitry Andric AltMappings.push_back(&FPRMapping); 3275ffd83dbSDimitry Andric return AltMappings; 3285ffd83dbSDimitry Andric } 3295ffd83dbSDimitry Andric case TargetOpcode::G_BITCAST: { 330*0fca6ea1SDimitry Andric TypeSize Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 3315ffd83dbSDimitry Andric if (Size != 32 && Size != 64) 3325ffd83dbSDimitry Andric break; 3335ffd83dbSDimitry Andric 3345ffd83dbSDimitry Andric // If the instruction has any implicit-defs or uses, 3355ffd83dbSDimitry Andric // do not mess with it. 3365ffd83dbSDimitry Andric if (MI.getNumOperands() != 2) 3375ffd83dbSDimitry Andric break; 3385ffd83dbSDimitry Andric 3395ffd83dbSDimitry Andric InstructionMappings AltMappings; 3405ffd83dbSDimitry Andric const InstructionMapping &GPRMapping = getInstructionMapping( 3415ffd83dbSDimitry Andric /*ID*/ 1, /*Cost*/ 1, 3425ffd83dbSDimitry Andric getCopyMapping(AArch64::GPRRegBankID, AArch64::GPRRegBankID, Size), 3435ffd83dbSDimitry Andric /*NumOperands*/ 2); 3445ffd83dbSDimitry Andric const InstructionMapping &FPRMapping = getInstructionMapping( 3455ffd83dbSDimitry Andric /*ID*/ 2, /*Cost*/ 1, 3465ffd83dbSDimitry Andric getCopyMapping(AArch64::FPRRegBankID, AArch64::FPRRegBankID, Size), 3475ffd83dbSDimitry Andric /*NumOperands*/ 2); 3485ffd83dbSDimitry Andric const InstructionMapping &GPRToFPRMapping = getInstructionMapping( 3495ffd83dbSDimitry Andric /*ID*/ 3, 3505f757f3fSDimitry Andric /*Cost*/ 3515f757f3fSDimitry Andric copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, 3525f757f3fSDimitry Andric TypeSize::getFixed(Size)), 3535ffd83dbSDimitry Andric getCopyMapping(AArch64::FPRRegBankID, AArch64::GPRRegBankID, Size), 3545ffd83dbSDimitry Andric /*NumOperands*/ 2); 3555ffd83dbSDimitry Andric const InstructionMapping &FPRToGPRMapping = getInstructionMapping( 3565ffd83dbSDimitry Andric /*ID*/ 3, 3575f757f3fSDimitry Andric /*Cost*/ 3585f757f3fSDimitry Andric copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, 3595f757f3fSDimitry Andric TypeSize::getFixed(Size)), 3605ffd83dbSDimitry Andric getCopyMapping(AArch64::GPRRegBankID, AArch64::FPRRegBankID, Size), 3615ffd83dbSDimitry Andric /*NumOperands*/ 2); 3625ffd83dbSDimitry Andric 3635ffd83dbSDimitry Andric AltMappings.push_back(&GPRMapping); 3645ffd83dbSDimitry Andric AltMappings.push_back(&FPRMapping); 3655ffd83dbSDimitry Andric AltMappings.push_back(&GPRToFPRMapping); 3665ffd83dbSDimitry Andric AltMappings.push_back(&FPRToGPRMapping); 3675ffd83dbSDimitry Andric return AltMappings; 3685ffd83dbSDimitry Andric } 3695ffd83dbSDimitry Andric case TargetOpcode::G_LOAD: { 370*0fca6ea1SDimitry Andric TypeSize Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 3715ffd83dbSDimitry Andric if (Size != 64) 3725ffd83dbSDimitry Andric break; 3735ffd83dbSDimitry Andric 3745ffd83dbSDimitry Andric // If the instruction has any implicit-defs or uses, 3755ffd83dbSDimitry Andric // do not mess with it. 3765ffd83dbSDimitry Andric if (MI.getNumOperands() != 2) 3775ffd83dbSDimitry Andric break; 3785ffd83dbSDimitry Andric 3795ffd83dbSDimitry Andric InstructionMappings AltMappings; 3805ffd83dbSDimitry Andric const InstructionMapping &GPRMapping = getInstructionMapping( 3815ffd83dbSDimitry Andric /*ID*/ 1, /*Cost*/ 1, 382*0fca6ea1SDimitry Andric getOperandsMapping( 383*0fca6ea1SDimitry Andric {getValueMapping(PMI_FirstGPR, Size), 3845ffd83dbSDimitry Andric // Addresses are GPR 64-bit. 385*0fca6ea1SDimitry Andric getValueMapping(PMI_FirstGPR, TypeSize::getFixed(64))}), 3865ffd83dbSDimitry Andric /*NumOperands*/ 2); 3875ffd83dbSDimitry Andric const InstructionMapping &FPRMapping = getInstructionMapping( 3885ffd83dbSDimitry Andric /*ID*/ 2, /*Cost*/ 1, 389*0fca6ea1SDimitry Andric getOperandsMapping( 390*0fca6ea1SDimitry Andric {getValueMapping(PMI_FirstFPR, Size), 3915ffd83dbSDimitry Andric // Addresses are GPR 64-bit. 392*0fca6ea1SDimitry Andric getValueMapping(PMI_FirstGPR, TypeSize::getFixed(64))}), 3935ffd83dbSDimitry Andric /*NumOperands*/ 2); 3945ffd83dbSDimitry Andric 3955ffd83dbSDimitry Andric AltMappings.push_back(&GPRMapping); 3965ffd83dbSDimitry Andric AltMappings.push_back(&FPRMapping); 3975ffd83dbSDimitry Andric return AltMappings; 3985ffd83dbSDimitry Andric } 3995ffd83dbSDimitry Andric default: 4005ffd83dbSDimitry Andric break; 4015ffd83dbSDimitry Andric } 4025ffd83dbSDimitry Andric return RegisterBankInfo::getInstrAlternativeMappings(MI); 4035ffd83dbSDimitry Andric } 4045ffd83dbSDimitry Andric 4055ffd83dbSDimitry Andric void AArch64RegisterBankInfo::applyMappingImpl( 4065f757f3fSDimitry Andric MachineIRBuilder &Builder, const OperandsMapper &OpdMapper) const { 407*0fca6ea1SDimitry Andric MachineInstr &MI = OpdMapper.getMI(); 408*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI = OpdMapper.getMRI(); 409*0fca6ea1SDimitry Andric 410*0fca6ea1SDimitry Andric switch (MI.getOpcode()) { 4115ffd83dbSDimitry Andric case TargetOpcode::G_OR: 4125ffd83dbSDimitry Andric case TargetOpcode::G_BITCAST: 4135ffd83dbSDimitry Andric case TargetOpcode::G_LOAD: 4145ffd83dbSDimitry Andric // Those ID must match getInstrAlternativeMappings. 4155ffd83dbSDimitry Andric assert((OpdMapper.getInstrMapping().getID() >= 1 && 4165ffd83dbSDimitry Andric OpdMapper.getInstrMapping().getID() <= 4) && 4175ffd83dbSDimitry Andric "Don't know how to handle that ID"); 4185ffd83dbSDimitry Andric return applyDefaultMapping(OpdMapper); 419*0fca6ea1SDimitry Andric case TargetOpcode::G_INSERT_VECTOR_ELT: { 420*0fca6ea1SDimitry Andric // Extend smaller gpr operands to 32 bit. 421*0fca6ea1SDimitry Andric Builder.setInsertPt(*MI.getParent(), MI.getIterator()); 422*0fca6ea1SDimitry Andric auto Ext = Builder.buildAnyExt(LLT::scalar(32), MI.getOperand(2).getReg()); 423*0fca6ea1SDimitry Andric MRI.setRegBank(Ext.getReg(0), getRegBank(AArch64::GPRRegBankID)); 424*0fca6ea1SDimitry Andric MI.getOperand(2).setReg(Ext.getReg(0)); 425*0fca6ea1SDimitry Andric return applyDefaultMapping(OpdMapper); 426*0fca6ea1SDimitry Andric } 4275ffd83dbSDimitry Andric default: 4285ffd83dbSDimitry Andric llvm_unreachable("Don't know how to handle that operation"); 4295ffd83dbSDimitry Andric } 4305ffd83dbSDimitry Andric } 4315ffd83dbSDimitry Andric 4325ffd83dbSDimitry Andric const RegisterBankInfo::InstructionMapping & 4335ffd83dbSDimitry Andric AArch64RegisterBankInfo::getSameKindOfOperandsMapping( 4345ffd83dbSDimitry Andric const MachineInstr &MI) const { 4355ffd83dbSDimitry Andric const unsigned Opc = MI.getOpcode(); 4365ffd83dbSDimitry Andric const MachineFunction &MF = *MI.getParent()->getParent(); 4375ffd83dbSDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 4385ffd83dbSDimitry Andric 4395ffd83dbSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 4405ffd83dbSDimitry Andric assert(NumOperands <= 3 && 4415ffd83dbSDimitry Andric "This code is for instructions with 3 or less operands"); 4425ffd83dbSDimitry Andric 4435ffd83dbSDimitry Andric LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 444*0fca6ea1SDimitry Andric TypeSize Size = Ty.getSizeInBits(); 4455ffd83dbSDimitry Andric bool IsFPR = Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc); 4465ffd83dbSDimitry Andric 4475ffd83dbSDimitry Andric PartialMappingIdx RBIdx = IsFPR ? PMI_FirstFPR : PMI_FirstGPR; 4485ffd83dbSDimitry Andric 4495ffd83dbSDimitry Andric #ifndef NDEBUG 4505ffd83dbSDimitry Andric // Make sure all the operands are using similar size and type. 4515ffd83dbSDimitry Andric // Should probably be checked by the machine verifier. 4525ffd83dbSDimitry Andric // This code won't catch cases where the number of lanes is 4535ffd83dbSDimitry Andric // different between the operands. 4545ffd83dbSDimitry Andric // If we want to go to that level of details, it is probably 4555ffd83dbSDimitry Andric // best to check that the types are the same, period. 4565ffd83dbSDimitry Andric // Currently, we just check that the register banks are the same 4575ffd83dbSDimitry Andric // for each types. 4585ffd83dbSDimitry Andric for (unsigned Idx = 1; Idx != NumOperands; ++Idx) { 4595ffd83dbSDimitry Andric LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg()); 4605ffd83dbSDimitry Andric assert( 4615ffd83dbSDimitry Andric AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset( 4625ffd83dbSDimitry Andric RBIdx, OpTy.getSizeInBits()) == 4635ffd83dbSDimitry Andric AArch64GenRegisterBankInfo::getRegBankBaseIdxOffset(RBIdx, Size) && 4645ffd83dbSDimitry Andric "Operand has incompatible size"); 4655ffd83dbSDimitry Andric bool OpIsFPR = OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc); 4665ffd83dbSDimitry Andric (void)OpIsFPR; 4675ffd83dbSDimitry Andric assert(IsFPR == OpIsFPR && "Operand has incompatible type"); 4685ffd83dbSDimitry Andric } 4695ffd83dbSDimitry Andric #endif // End NDEBUG. 4705ffd83dbSDimitry Andric 4715ffd83dbSDimitry Andric return getInstructionMapping(DefaultMappingID, 1, 4725ffd83dbSDimitry Andric getValueMapping(RBIdx, Size), NumOperands); 4735ffd83dbSDimitry Andric } 4745ffd83dbSDimitry Andric 47506c3fb27SDimitry Andric /// \returns true if a given intrinsic only uses and defines FPRs. 47606c3fb27SDimitry Andric static bool isFPIntrinsic(const MachineRegisterInfo &MRI, 47706c3fb27SDimitry Andric const MachineInstr &MI) { 478fe6060f1SDimitry Andric // TODO: Add more intrinsics. 4795f757f3fSDimitry Andric switch (cast<GIntrinsic>(MI).getIntrinsicID()) { 480fe6060f1SDimitry Andric default: 481fe6060f1SDimitry Andric return false; 482fe6060f1SDimitry Andric case Intrinsic::aarch64_neon_uaddlv: 48306c3fb27SDimitry Andric case Intrinsic::aarch64_neon_uaddv: 4845f757f3fSDimitry Andric case Intrinsic::aarch64_neon_saddv: 48506c3fb27SDimitry Andric case Intrinsic::aarch64_neon_umaxv: 4865f757f3fSDimitry Andric case Intrinsic::aarch64_neon_smaxv: 48706c3fb27SDimitry Andric case Intrinsic::aarch64_neon_uminv: 4885f757f3fSDimitry Andric case Intrinsic::aarch64_neon_sminv: 4895f757f3fSDimitry Andric case Intrinsic::aarch64_neon_faddv: 49006c3fb27SDimitry Andric case Intrinsic::aarch64_neon_fmaxv: 49106c3fb27SDimitry Andric case Intrinsic::aarch64_neon_fminv: 49206c3fb27SDimitry Andric case Intrinsic::aarch64_neon_fmaxnmv: 49306c3fb27SDimitry Andric case Intrinsic::aarch64_neon_fminnmv: 494fe6060f1SDimitry Andric return true; 49506c3fb27SDimitry Andric case Intrinsic::aarch64_neon_saddlv: { 49606c3fb27SDimitry Andric const LLT SrcTy = MRI.getType(MI.getOperand(2).getReg()); 49706c3fb27SDimitry Andric return SrcTy.getElementType().getSizeInBits() >= 16 && 49806c3fb27SDimitry Andric SrcTy.getElementCount().getFixedValue() >= 4; 49906c3fb27SDimitry Andric } 500fe6060f1SDimitry Andric } 501fe6060f1SDimitry Andric } 502fe6060f1SDimitry Andric 503*0fca6ea1SDimitry Andric bool AArch64RegisterBankInfo::isPHIWithFPContraints( 504*0fca6ea1SDimitry Andric const MachineInstr &MI, const MachineRegisterInfo &MRI, 505*0fca6ea1SDimitry Andric const TargetRegisterInfo &TRI, const unsigned Depth) const { 506*0fca6ea1SDimitry Andric if (!MI.isPHI() || Depth > MaxFPRSearchDepth) 507*0fca6ea1SDimitry Andric return false; 508*0fca6ea1SDimitry Andric 509*0fca6ea1SDimitry Andric return any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()), 510*0fca6ea1SDimitry Andric [&](const MachineInstr &UseMI) { 511*0fca6ea1SDimitry Andric if (onlyUsesFP(UseMI, MRI, TRI, Depth + 1)) 512*0fca6ea1SDimitry Andric return true; 513*0fca6ea1SDimitry Andric return isPHIWithFPContraints(UseMI, MRI, TRI, Depth + 1); 514*0fca6ea1SDimitry Andric }); 515*0fca6ea1SDimitry Andric } 516*0fca6ea1SDimitry Andric 517e8d8bef9SDimitry Andric bool AArch64RegisterBankInfo::hasFPConstraints(const MachineInstr &MI, 518e8d8bef9SDimitry Andric const MachineRegisterInfo &MRI, 519e8d8bef9SDimitry Andric const TargetRegisterInfo &TRI, 520e8d8bef9SDimitry Andric unsigned Depth) const { 5215ffd83dbSDimitry Andric unsigned Op = MI.getOpcode(); 52206c3fb27SDimitry Andric if (Op == TargetOpcode::G_INTRINSIC && isFPIntrinsic(MRI, MI)) 523fe6060f1SDimitry Andric return true; 5245ffd83dbSDimitry Andric 5255ffd83dbSDimitry Andric // Do we have an explicit floating point instruction? 5265ffd83dbSDimitry Andric if (isPreISelGenericFloatingPointOpcode(Op)) 5275ffd83dbSDimitry Andric return true; 5285ffd83dbSDimitry Andric 5295ffd83dbSDimitry Andric // No. Check if we have a copy-like instruction. If we do, then we could 5305ffd83dbSDimitry Andric // still be fed by floating point instructions. 531fe6060f1SDimitry Andric if (Op != TargetOpcode::COPY && !MI.isPHI() && 532fe6060f1SDimitry Andric !isPreISelGenericOptimizationHint(Op)) 5335ffd83dbSDimitry Andric return false; 5345ffd83dbSDimitry Andric 535e8d8bef9SDimitry Andric // Check if we already know the register bank. 536e8d8bef9SDimitry Andric auto *RB = getRegBank(MI.getOperand(0).getReg(), MRI, TRI); 537e8d8bef9SDimitry Andric if (RB == &AArch64::FPRRegBank) 538e8d8bef9SDimitry Andric return true; 539e8d8bef9SDimitry Andric if (RB == &AArch64::GPRRegBank) 540e8d8bef9SDimitry Andric return false; 541e8d8bef9SDimitry Andric 542e8d8bef9SDimitry Andric // We don't know anything. 543e8d8bef9SDimitry Andric // 544e8d8bef9SDimitry Andric // If we have a phi, we may be able to infer that it will be assigned a FPR 545e8d8bef9SDimitry Andric // based off of its inputs. 546e8d8bef9SDimitry Andric if (!MI.isPHI() || Depth > MaxFPRSearchDepth) 547e8d8bef9SDimitry Andric return false; 548e8d8bef9SDimitry Andric 549e8d8bef9SDimitry Andric return any_of(MI.explicit_uses(), [&](const MachineOperand &Op) { 550e8d8bef9SDimitry Andric return Op.isReg() && 551e8d8bef9SDimitry Andric onlyDefinesFP(*MRI.getVRegDef(Op.getReg()), MRI, TRI, Depth + 1); 552e8d8bef9SDimitry Andric }); 5535ffd83dbSDimitry Andric } 5545ffd83dbSDimitry Andric 5555ffd83dbSDimitry Andric bool AArch64RegisterBankInfo::onlyUsesFP(const MachineInstr &MI, 5565ffd83dbSDimitry Andric const MachineRegisterInfo &MRI, 557e8d8bef9SDimitry Andric const TargetRegisterInfo &TRI, 558e8d8bef9SDimitry Andric unsigned Depth) const { 5595ffd83dbSDimitry Andric switch (MI.getOpcode()) { 5605ffd83dbSDimitry Andric case TargetOpcode::G_FPTOSI: 5615ffd83dbSDimitry Andric case TargetOpcode::G_FPTOUI: 5625ffd83dbSDimitry Andric case TargetOpcode::G_FCMP: 563349cc55cSDimitry Andric case TargetOpcode::G_LROUND: 564349cc55cSDimitry Andric case TargetOpcode::G_LLROUND: 5655ffd83dbSDimitry Andric return true; 5665ffd83dbSDimitry Andric default: 5675ffd83dbSDimitry Andric break; 5685ffd83dbSDimitry Andric } 569e8d8bef9SDimitry Andric return hasFPConstraints(MI, MRI, TRI, Depth); 5705ffd83dbSDimitry Andric } 5715ffd83dbSDimitry Andric 572e8d8bef9SDimitry Andric bool AArch64RegisterBankInfo::onlyDefinesFP(const MachineInstr &MI, 573e8d8bef9SDimitry Andric const MachineRegisterInfo &MRI, 574e8d8bef9SDimitry Andric const TargetRegisterInfo &TRI, 575e8d8bef9SDimitry Andric unsigned Depth) const { 5765ffd83dbSDimitry Andric switch (MI.getOpcode()) { 5775ffd83dbSDimitry Andric case AArch64::G_DUP: 5785ffd83dbSDimitry Andric case TargetOpcode::G_SITOFP: 5795ffd83dbSDimitry Andric case TargetOpcode::G_UITOFP: 5805ffd83dbSDimitry Andric case TargetOpcode::G_EXTRACT_VECTOR_ELT: 5815ffd83dbSDimitry Andric case TargetOpcode::G_INSERT_VECTOR_ELT: 582fe6060f1SDimitry Andric case TargetOpcode::G_BUILD_VECTOR: 583fe6060f1SDimitry Andric case TargetOpcode::G_BUILD_VECTOR_TRUNC: 5845ffd83dbSDimitry Andric return true; 5855f757f3fSDimitry Andric case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 5865f757f3fSDimitry Andric switch (cast<GIntrinsic>(MI).getIntrinsicID()) { 5875f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld1x2: 5885f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld1x3: 5895f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld1x4: 5905f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld2: 5915f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld2lane: 5925f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld2r: 5935f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld3: 5945f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld3lane: 5955f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld3r: 5965f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld4: 5975f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld4lane: 5985f757f3fSDimitry Andric case Intrinsic::aarch64_neon_ld4r: 5995f757f3fSDimitry Andric return true; 6005f757f3fSDimitry Andric default: 6015f757f3fSDimitry Andric break; 6025f757f3fSDimitry Andric } 6035f757f3fSDimitry Andric break; 6045ffd83dbSDimitry Andric default: 6055ffd83dbSDimitry Andric break; 6065ffd83dbSDimitry Andric } 607e8d8bef9SDimitry Andric return hasFPConstraints(MI, MRI, TRI, Depth); 6085ffd83dbSDimitry Andric } 6095ffd83dbSDimitry Andric 6105f757f3fSDimitry Andric bool AArch64RegisterBankInfo::isLoadFromFPType(const MachineInstr &MI) const { 6115f757f3fSDimitry Andric // GMemOperation because we also want to match indexed loads. 6125f757f3fSDimitry Andric auto *MemOp = cast<GMemOperation>(&MI); 6135f757f3fSDimitry Andric const Value *LdVal = MemOp->getMMO().getValue(); 6145f757f3fSDimitry Andric if (!LdVal) 6155f757f3fSDimitry Andric return false; 6165f757f3fSDimitry Andric 6175f757f3fSDimitry Andric Type *EltTy = nullptr; 6185f757f3fSDimitry Andric if (const GlobalValue *GV = dyn_cast<GlobalValue>(LdVal)) { 6195f757f3fSDimitry Andric EltTy = GV->getValueType(); 6205f757f3fSDimitry Andric // Look at the first element of the struct to determine the type we are 6215f757f3fSDimitry Andric // loading 6223a079333SDimitry Andric while (StructType *StructEltTy = dyn_cast<StructType>(EltTy)) { 6233a079333SDimitry Andric if (StructEltTy->getNumElements() == 0) 6243a079333SDimitry Andric break; 6255f757f3fSDimitry Andric EltTy = StructEltTy->getTypeAtIndex(0U); 6263a079333SDimitry Andric } 6275f757f3fSDimitry Andric // Look at the first element of the array to determine its type 6285f757f3fSDimitry Andric if (isa<ArrayType>(EltTy)) 6295f757f3fSDimitry Andric EltTy = EltTy->getArrayElementType(); 6305f757f3fSDimitry Andric } else { 6315f757f3fSDimitry Andric // FIXME: grubbing around uses is pretty ugly, but with no more 6325f757f3fSDimitry Andric // `getPointerElementType` there's not much else we can do. 6335f757f3fSDimitry Andric for (const auto *LdUser : LdVal->users()) { 6345f757f3fSDimitry Andric if (isa<LoadInst>(LdUser)) { 6355f757f3fSDimitry Andric EltTy = LdUser->getType(); 6365f757f3fSDimitry Andric break; 6375f757f3fSDimitry Andric } 6385f757f3fSDimitry Andric if (isa<StoreInst>(LdUser) && LdUser->getOperand(1) == LdVal) { 6395f757f3fSDimitry Andric EltTy = LdUser->getOperand(0)->getType(); 6405f757f3fSDimitry Andric break; 6415f757f3fSDimitry Andric } 6425f757f3fSDimitry Andric } 6435f757f3fSDimitry Andric } 6445f757f3fSDimitry Andric return EltTy && EltTy->isFPOrFPVectorTy(); 6455f757f3fSDimitry Andric } 6465f757f3fSDimitry Andric 6475ffd83dbSDimitry Andric const RegisterBankInfo::InstructionMapping & 6485ffd83dbSDimitry Andric AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { 6495ffd83dbSDimitry Andric const unsigned Opc = MI.getOpcode(); 6505ffd83dbSDimitry Andric 6515ffd83dbSDimitry Andric // Try the default logic for non-generic instructions that are either copies 6525ffd83dbSDimitry Andric // or already have some operands assigned to banks. 6535ffd83dbSDimitry Andric if ((Opc != TargetOpcode::COPY && !isPreISelGenericOpcode(Opc)) || 6545ffd83dbSDimitry Andric Opc == TargetOpcode::G_PHI) { 6555ffd83dbSDimitry Andric const RegisterBankInfo::InstructionMapping &Mapping = 6565ffd83dbSDimitry Andric getInstrMappingImpl(MI); 6575ffd83dbSDimitry Andric if (Mapping.isValid()) 6585ffd83dbSDimitry Andric return Mapping; 6595ffd83dbSDimitry Andric } 6605ffd83dbSDimitry Andric 6615ffd83dbSDimitry Andric const MachineFunction &MF = *MI.getParent()->getParent(); 6625ffd83dbSDimitry Andric const MachineRegisterInfo &MRI = MF.getRegInfo(); 6635ffd83dbSDimitry Andric const TargetSubtargetInfo &STI = MF.getSubtarget(); 6645ffd83dbSDimitry Andric const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 6655ffd83dbSDimitry Andric 6665ffd83dbSDimitry Andric switch (Opc) { 6675ffd83dbSDimitry Andric // G_{F|S|U}REM are not listed because they are not legal. 6685ffd83dbSDimitry Andric // Arithmetic ops. 6695ffd83dbSDimitry Andric case TargetOpcode::G_ADD: 6705ffd83dbSDimitry Andric case TargetOpcode::G_SUB: 6715ffd83dbSDimitry Andric case TargetOpcode::G_PTR_ADD: 6725ffd83dbSDimitry Andric case TargetOpcode::G_MUL: 6735ffd83dbSDimitry Andric case TargetOpcode::G_SDIV: 6745ffd83dbSDimitry Andric case TargetOpcode::G_UDIV: 6755ffd83dbSDimitry Andric // Bitwise ops. 6765ffd83dbSDimitry Andric case TargetOpcode::G_AND: 6775ffd83dbSDimitry Andric case TargetOpcode::G_OR: 6785ffd83dbSDimitry Andric case TargetOpcode::G_XOR: 6795ffd83dbSDimitry Andric // Floating point ops. 6805ffd83dbSDimitry Andric case TargetOpcode::G_FADD: 6815ffd83dbSDimitry Andric case TargetOpcode::G_FSUB: 6825ffd83dbSDimitry Andric case TargetOpcode::G_FMUL: 6835ffd83dbSDimitry Andric case TargetOpcode::G_FDIV: 6840eae32dcSDimitry Andric case TargetOpcode::G_FMAXIMUM: 6850eae32dcSDimitry Andric case TargetOpcode::G_FMINIMUM: 6865ffd83dbSDimitry Andric return getSameKindOfOperandsMapping(MI); 6875ffd83dbSDimitry Andric case TargetOpcode::G_FPEXT: { 6885ffd83dbSDimitry Andric LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); 6895ffd83dbSDimitry Andric LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); 6905ffd83dbSDimitry Andric return getInstructionMapping( 6915ffd83dbSDimitry Andric DefaultMappingID, /*Cost*/ 1, 6925ffd83dbSDimitry Andric getFPExtMapping(DstTy.getSizeInBits(), SrcTy.getSizeInBits()), 6935ffd83dbSDimitry Andric /*NumOperands*/ 2); 6945ffd83dbSDimitry Andric } 6955ffd83dbSDimitry Andric // Shifts. 6965ffd83dbSDimitry Andric case TargetOpcode::G_SHL: 6975ffd83dbSDimitry Andric case TargetOpcode::G_LSHR: 6985ffd83dbSDimitry Andric case TargetOpcode::G_ASHR: { 6995ffd83dbSDimitry Andric LLT ShiftAmtTy = MRI.getType(MI.getOperand(2).getReg()); 7005ffd83dbSDimitry Andric LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); 7015ffd83dbSDimitry Andric if (ShiftAmtTy.getSizeInBits() == 64 && SrcTy.getSizeInBits() == 32) 7025ffd83dbSDimitry Andric return getInstructionMapping(DefaultMappingID, 1, 7035ffd83dbSDimitry Andric &ValMappings[Shift64Imm], 3); 7045ffd83dbSDimitry Andric return getSameKindOfOperandsMapping(MI); 7055ffd83dbSDimitry Andric } 7065ffd83dbSDimitry Andric case TargetOpcode::COPY: { 7075ffd83dbSDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 7085ffd83dbSDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 7095ffd83dbSDimitry Andric // Check if one of the register is not a generic register. 710bdd1243dSDimitry Andric if ((DstReg.isPhysical() || !MRI.getType(DstReg).isValid()) || 711bdd1243dSDimitry Andric (SrcReg.isPhysical() || !MRI.getType(SrcReg).isValid())) { 7125ffd83dbSDimitry Andric const RegisterBank *DstRB = getRegBank(DstReg, MRI, TRI); 7135ffd83dbSDimitry Andric const RegisterBank *SrcRB = getRegBank(SrcReg, MRI, TRI); 7145ffd83dbSDimitry Andric if (!DstRB) 7155ffd83dbSDimitry Andric DstRB = SrcRB; 7165ffd83dbSDimitry Andric else if (!SrcRB) 7175ffd83dbSDimitry Andric SrcRB = DstRB; 7185ffd83dbSDimitry Andric // If both RB are null that means both registers are generic. 7195ffd83dbSDimitry Andric // We shouldn't be here. 7205ffd83dbSDimitry Andric assert(DstRB && SrcRB && "Both RegBank were nullptr"); 721*0fca6ea1SDimitry Andric TypeSize Size = getSizeInBits(DstReg, MRI, TRI); 7225ffd83dbSDimitry Andric return getInstructionMapping( 723*0fca6ea1SDimitry Andric DefaultMappingID, copyCost(*DstRB, *SrcRB, Size), 7245ffd83dbSDimitry Andric getCopyMapping(DstRB->getID(), SrcRB->getID(), Size), 7255ffd83dbSDimitry Andric // We only care about the mapping of the destination. 7265ffd83dbSDimitry Andric /*NumOperands*/ 1); 7275ffd83dbSDimitry Andric } 7285ffd83dbSDimitry Andric // Both registers are generic, use G_BITCAST. 729bdd1243dSDimitry Andric [[fallthrough]]; 7305ffd83dbSDimitry Andric } 7315ffd83dbSDimitry Andric case TargetOpcode::G_BITCAST: { 7325ffd83dbSDimitry Andric LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); 7335ffd83dbSDimitry Andric LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); 734*0fca6ea1SDimitry Andric TypeSize Size = DstTy.getSizeInBits(); 7355ffd83dbSDimitry Andric bool DstIsGPR = !DstTy.isVector() && DstTy.getSizeInBits() <= 64; 7365ffd83dbSDimitry Andric bool SrcIsGPR = !SrcTy.isVector() && SrcTy.getSizeInBits() <= 64; 7375ffd83dbSDimitry Andric const RegisterBank &DstRB = 7385ffd83dbSDimitry Andric DstIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank; 7395ffd83dbSDimitry Andric const RegisterBank &SrcRB = 7405ffd83dbSDimitry Andric SrcIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank; 7415ffd83dbSDimitry Andric return getInstructionMapping( 742*0fca6ea1SDimitry Andric DefaultMappingID, copyCost(DstRB, SrcRB, Size), 7435ffd83dbSDimitry Andric getCopyMapping(DstRB.getID(), SrcRB.getID(), Size), 7445ffd83dbSDimitry Andric // We only care about the mapping of the destination for COPY. 7455ffd83dbSDimitry Andric /*NumOperands*/ Opc == TargetOpcode::G_BITCAST ? 2 : 1); 7465ffd83dbSDimitry Andric } 7475ffd83dbSDimitry Andric default: 7485ffd83dbSDimitry Andric break; 7495ffd83dbSDimitry Andric } 7505ffd83dbSDimitry Andric 7515ffd83dbSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 752*0fca6ea1SDimitry Andric unsigned MappingID = DefaultMappingID; 7535ffd83dbSDimitry Andric 7545ffd83dbSDimitry Andric // Track the size and bank of each register. We don't do partial mappings. 7555ffd83dbSDimitry Andric SmallVector<unsigned, 4> OpSize(NumOperands); 7565ffd83dbSDimitry Andric SmallVector<PartialMappingIdx, 4> OpRegBankIdx(NumOperands); 7575ffd83dbSDimitry Andric for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { 7585ffd83dbSDimitry Andric auto &MO = MI.getOperand(Idx); 7595ffd83dbSDimitry Andric if (!MO.isReg() || !MO.getReg()) 7605ffd83dbSDimitry Andric continue; 7615ffd83dbSDimitry Andric 7625ffd83dbSDimitry Andric LLT Ty = MRI.getType(MO.getReg()); 763bdd1243dSDimitry Andric if (!Ty.isValid()) 764bdd1243dSDimitry Andric continue; 765*0fca6ea1SDimitry Andric OpSize[Idx] = Ty.getSizeInBits().getKnownMinValue(); 7665ffd83dbSDimitry Andric 767*0fca6ea1SDimitry Andric // As a top-level guess, vectors including both scalable and non-scalable 768*0fca6ea1SDimitry Andric // ones go in FPRs, scalars and pointers in GPRs. 7695ffd83dbSDimitry Andric // For floating-point instructions, scalars go in FPRs. 770*0fca6ea1SDimitry Andric if (Ty.isVector()) 771*0fca6ea1SDimitry Andric OpRegBankIdx[Idx] = PMI_FirstFPR; 772*0fca6ea1SDimitry Andric else if (isPreISelGenericFloatingPointOpcode(Opc) || 7735ffd83dbSDimitry Andric Ty.getSizeInBits() > 64) 7745ffd83dbSDimitry Andric OpRegBankIdx[Idx] = PMI_FirstFPR; 7755ffd83dbSDimitry Andric else 7765ffd83dbSDimitry Andric OpRegBankIdx[Idx] = PMI_FirstGPR; 7775ffd83dbSDimitry Andric } 7785ffd83dbSDimitry Andric 7795ffd83dbSDimitry Andric unsigned Cost = 1; 7805ffd83dbSDimitry Andric // Some of the floating-point instructions have mixed GPR and FPR operands: 7815ffd83dbSDimitry Andric // fine-tune the computed mapping. 7825ffd83dbSDimitry Andric switch (Opc) { 7835ffd83dbSDimitry Andric case AArch64::G_DUP: { 7845ffd83dbSDimitry Andric Register ScalarReg = MI.getOperand(1).getReg(); 785fe6060f1SDimitry Andric LLT ScalarTy = MRI.getType(ScalarReg); 7865ffd83dbSDimitry Andric auto ScalarDef = MRI.getVRegDef(ScalarReg); 7875f757f3fSDimitry Andric // We want to select dup(load) into LD1R. 7885f757f3fSDimitry Andric if (ScalarDef->getOpcode() == TargetOpcode::G_LOAD) 7895f757f3fSDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR}; 790fe6060f1SDimitry Andric // s8 is an exception for G_DUP, which we always want on gpr. 7915f757f3fSDimitry Andric else if (ScalarTy.getSizeInBits() != 8 && 792fe6060f1SDimitry Andric (getRegBank(ScalarReg, MRI, TRI) == &AArch64::FPRRegBank || 793fe6060f1SDimitry Andric onlyDefinesFP(*ScalarDef, MRI, TRI))) 7945ffd83dbSDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR}; 7955ffd83dbSDimitry Andric else 7965ffd83dbSDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR}; 7975ffd83dbSDimitry Andric break; 7985ffd83dbSDimitry Andric } 7995ffd83dbSDimitry Andric case TargetOpcode::G_TRUNC: { 8005ffd83dbSDimitry Andric LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); 8015ffd83dbSDimitry Andric if (!SrcTy.isVector() && SrcTy.getSizeInBits() == 128) 8025ffd83dbSDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR}; 8035ffd83dbSDimitry Andric break; 8045ffd83dbSDimitry Andric } 8055ffd83dbSDimitry Andric case TargetOpcode::G_SITOFP: 806e8d8bef9SDimitry Andric case TargetOpcode::G_UITOFP: { 8075ffd83dbSDimitry Andric if (MRI.getType(MI.getOperand(0).getReg()).isVector()) 8085ffd83dbSDimitry Andric break; 809e8d8bef9SDimitry Andric // Integer to FP conversions don't necessarily happen between GPR -> FPR 810e8d8bef9SDimitry Andric // regbanks. They can also be done within an FPR register. 811e8d8bef9SDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 812e8d8bef9SDimitry Andric if (getRegBank(SrcReg, MRI, TRI) == &AArch64::FPRRegBank) 813e8d8bef9SDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR}; 814e8d8bef9SDimitry Andric else 8155ffd83dbSDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR}; 8165ffd83dbSDimitry Andric break; 817e8d8bef9SDimitry Andric } 8185ffd83dbSDimitry Andric case TargetOpcode::G_FPTOSI: 8195ffd83dbSDimitry Andric case TargetOpcode::G_FPTOUI: 820*0fca6ea1SDimitry Andric case TargetOpcode::G_INTRINSIC_LRINT: 821*0fca6ea1SDimitry Andric case TargetOpcode::G_INTRINSIC_LLRINT: 8225ffd83dbSDimitry Andric if (MRI.getType(MI.getOperand(0).getReg()).isVector()) 8235ffd83dbSDimitry Andric break; 8245ffd83dbSDimitry Andric OpRegBankIdx = {PMI_FirstGPR, PMI_FirstFPR}; 8255ffd83dbSDimitry Andric break; 826fe6060f1SDimitry Andric case TargetOpcode::G_FCMP: { 827fe6060f1SDimitry Andric // If the result is a vector, it must use a FPR. 828fe6060f1SDimitry Andric AArch64GenRegisterBankInfo::PartialMappingIdx Idx0 = 829fe6060f1SDimitry Andric MRI.getType(MI.getOperand(0).getReg()).isVector() ? PMI_FirstFPR 830fe6060f1SDimitry Andric : PMI_FirstGPR; 831fe6060f1SDimitry Andric OpRegBankIdx = {Idx0, 8325ffd83dbSDimitry Andric /* Predicate */ PMI_None, PMI_FirstFPR, PMI_FirstFPR}; 8335ffd83dbSDimitry Andric break; 834fe6060f1SDimitry Andric } 8355ffd83dbSDimitry Andric case TargetOpcode::G_BITCAST: 8365ffd83dbSDimitry Andric // This is going to be a cross register bank copy and this is expensive. 8375ffd83dbSDimitry Andric if (OpRegBankIdx[0] != OpRegBankIdx[1]) 8385ffd83dbSDimitry Andric Cost = copyCost( 8395ffd83dbSDimitry Andric *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[0]].RegBank, 8405ffd83dbSDimitry Andric *AArch64GenRegisterBankInfo::PartMappings[OpRegBankIdx[1]].RegBank, 8415f757f3fSDimitry Andric TypeSize::getFixed(OpSize[0])); 8425ffd83dbSDimitry Andric break; 84306c3fb27SDimitry Andric case TargetOpcode::G_LOAD: { 8445ffd83dbSDimitry Andric // Loading in vector unit is slightly more expensive. 8455ffd83dbSDimitry Andric // This is actually only true for the LD1R and co instructions, 8465ffd83dbSDimitry Andric // but anyway for the fast mode this number does not matter and 8475ffd83dbSDimitry Andric // for the greedy mode the cost of the cross bank copy will 8485ffd83dbSDimitry Andric // offset this number. 8495ffd83dbSDimitry Andric // FIXME: Should be derived from the scheduling model. 850349cc55cSDimitry Andric if (OpRegBankIdx[0] != PMI_FirstGPR) { 8515ffd83dbSDimitry Andric Cost = 2; 852349cc55cSDimitry Andric break; 853349cc55cSDimitry Andric } 854349cc55cSDimitry Andric 855349cc55cSDimitry Andric if (cast<GLoad>(MI).isAtomic()) { 856349cc55cSDimitry Andric // Atomics always use GPR destinations. Don't refine any further. 857349cc55cSDimitry Andric OpRegBankIdx[0] = PMI_FirstGPR; 858349cc55cSDimitry Andric break; 859349cc55cSDimitry Andric } 860349cc55cSDimitry Andric 86106c3fb27SDimitry Andric // Try to guess the type of the load from the MMO. 8625f757f3fSDimitry Andric if (isLoadFromFPType(MI)) { 86306c3fb27SDimitry Andric OpRegBankIdx[0] = PMI_FirstFPR; 86406c3fb27SDimitry Andric break; 86506c3fb27SDimitry Andric } 86606c3fb27SDimitry Andric 8675ffd83dbSDimitry Andric // Check if that load feeds fp instructions. 8685ffd83dbSDimitry Andric // In that case, we want the default mapping to be on FPR 8695ffd83dbSDimitry Andric // instead of blind map every scalar to GPR. 870349cc55cSDimitry Andric if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()), 871349cc55cSDimitry Andric [&](const MachineInstr &UseMI) { 872*0fca6ea1SDimitry Andric // If we have at least one direct or indirect use 873*0fca6ea1SDimitry Andric // in a FP instruction, 874349cc55cSDimitry Andric // assume this was a floating point load in the IR. If it was 875349cc55cSDimitry Andric // not, we would have had a bitcast before reaching that 876349cc55cSDimitry Andric // instruction. 877349cc55cSDimitry Andric // 878349cc55cSDimitry Andric // Int->FP conversion operations are also captured in 879349cc55cSDimitry Andric // onlyDefinesFP(). 880*0fca6ea1SDimitry Andric 881*0fca6ea1SDimitry Andric if (isPHIWithFPContraints(UseMI, MRI, TRI)) 882*0fca6ea1SDimitry Andric return true; 883*0fca6ea1SDimitry Andric 884349cc55cSDimitry Andric return onlyUsesFP(UseMI, MRI, TRI) || 885349cc55cSDimitry Andric onlyDefinesFP(UseMI, MRI, TRI); 886349cc55cSDimitry Andric })) 8875ffd83dbSDimitry Andric OpRegBankIdx[0] = PMI_FirstFPR; 8885ffd83dbSDimitry Andric break; 88906c3fb27SDimitry Andric } 8905ffd83dbSDimitry Andric case TargetOpcode::G_STORE: 8915ffd83dbSDimitry Andric // Check if that store is fed by fp instructions. 8925ffd83dbSDimitry Andric if (OpRegBankIdx[0] == PMI_FirstGPR) { 8935ffd83dbSDimitry Andric Register VReg = MI.getOperand(0).getReg(); 8945ffd83dbSDimitry Andric if (!VReg) 8955ffd83dbSDimitry Andric break; 8965ffd83dbSDimitry Andric MachineInstr *DefMI = MRI.getVRegDef(VReg); 8975ffd83dbSDimitry Andric if (onlyDefinesFP(*DefMI, MRI, TRI)) 8985ffd83dbSDimitry Andric OpRegBankIdx[0] = PMI_FirstFPR; 8995ffd83dbSDimitry Andric break; 9005ffd83dbSDimitry Andric } 9015ffd83dbSDimitry Andric break; 9025f757f3fSDimitry Andric case TargetOpcode::G_INDEXED_STORE: 9035f757f3fSDimitry Andric if (OpRegBankIdx[1] == PMI_FirstGPR) { 9045f757f3fSDimitry Andric Register VReg = MI.getOperand(1).getReg(); 9055f757f3fSDimitry Andric if (!VReg) 9065f757f3fSDimitry Andric break; 9075f757f3fSDimitry Andric MachineInstr *DefMI = MRI.getVRegDef(VReg); 9085f757f3fSDimitry Andric if (onlyDefinesFP(*DefMI, MRI, TRI)) 9095f757f3fSDimitry Andric OpRegBankIdx[1] = PMI_FirstFPR; 9105f757f3fSDimitry Andric break; 9115f757f3fSDimitry Andric } 9125f757f3fSDimitry Andric break; 9135f757f3fSDimitry Andric case TargetOpcode::G_INDEXED_SEXTLOAD: 9145f757f3fSDimitry Andric case TargetOpcode::G_INDEXED_ZEXTLOAD: 9155f757f3fSDimitry Andric // These should always be GPR. 9165f757f3fSDimitry Andric OpRegBankIdx[0] = PMI_FirstGPR; 9175f757f3fSDimitry Andric break; 9185f757f3fSDimitry Andric case TargetOpcode::G_INDEXED_LOAD: { 9195f757f3fSDimitry Andric if (isLoadFromFPType(MI)) 9205f757f3fSDimitry Andric OpRegBankIdx[0] = PMI_FirstFPR; 9215f757f3fSDimitry Andric break; 9225f757f3fSDimitry Andric } 9235ffd83dbSDimitry Andric case TargetOpcode::G_SELECT: { 9245ffd83dbSDimitry Andric // If the destination is FPR, preserve that. 9255ffd83dbSDimitry Andric if (OpRegBankIdx[0] != PMI_FirstGPR) 9265ffd83dbSDimitry Andric break; 9275ffd83dbSDimitry Andric 9285ffd83dbSDimitry Andric // If we're taking in vectors, we have no choice but to put everything on 9295ffd83dbSDimitry Andric // FPRs, except for the condition. The condition must always be on a GPR. 9305ffd83dbSDimitry Andric LLT SrcTy = MRI.getType(MI.getOperand(2).getReg()); 9315ffd83dbSDimitry Andric if (SrcTy.isVector()) { 9325ffd83dbSDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR, PMI_FirstFPR, PMI_FirstFPR}; 9335ffd83dbSDimitry Andric break; 9345ffd83dbSDimitry Andric } 9355ffd83dbSDimitry Andric 9365ffd83dbSDimitry Andric // Try to minimize the number of copies. If we have more floating point 9375ffd83dbSDimitry Andric // constrained values than not, then we'll put everything on FPR. Otherwise, 9385ffd83dbSDimitry Andric // everything has to be on GPR. 9395ffd83dbSDimitry Andric unsigned NumFP = 0; 9405ffd83dbSDimitry Andric 9415ffd83dbSDimitry Andric // Check if the uses of the result always produce floating point values. 9425ffd83dbSDimitry Andric // 9435ffd83dbSDimitry Andric // For example: 9445ffd83dbSDimitry Andric // 9455ffd83dbSDimitry Andric // %z = G_SELECT %cond %x %y 9465ffd83dbSDimitry Andric // fpr = G_FOO %z ... 9475ffd83dbSDimitry Andric if (any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()), 9485ffd83dbSDimitry Andric [&](MachineInstr &MI) { return onlyUsesFP(MI, MRI, TRI); })) 9495ffd83dbSDimitry Andric ++NumFP; 9505ffd83dbSDimitry Andric 9515ffd83dbSDimitry Andric // Check if the defs of the source values always produce floating point 9525ffd83dbSDimitry Andric // values. 9535ffd83dbSDimitry Andric // 9545ffd83dbSDimitry Andric // For example: 9555ffd83dbSDimitry Andric // 9565ffd83dbSDimitry Andric // %x = G_SOMETHING_ALWAYS_FLOAT %a ... 9575ffd83dbSDimitry Andric // %z = G_SELECT %cond %x %y 9585ffd83dbSDimitry Andric // 9595ffd83dbSDimitry Andric // Also check whether or not the sources have already been decided to be 9605ffd83dbSDimitry Andric // FPR. Keep track of this. 9615ffd83dbSDimitry Andric // 9625ffd83dbSDimitry Andric // This doesn't check the condition, since it's just whatever is in NZCV. 9635ffd83dbSDimitry Andric // This isn't passed explicitly in a register to fcsel/csel. 9645ffd83dbSDimitry Andric for (unsigned Idx = 2; Idx < 4; ++Idx) { 9655ffd83dbSDimitry Andric Register VReg = MI.getOperand(Idx).getReg(); 9665ffd83dbSDimitry Andric MachineInstr *DefMI = MRI.getVRegDef(VReg); 9675ffd83dbSDimitry Andric if (getRegBank(VReg, MRI, TRI) == &AArch64::FPRRegBank || 9685ffd83dbSDimitry Andric onlyDefinesFP(*DefMI, MRI, TRI)) 9695ffd83dbSDimitry Andric ++NumFP; 9705ffd83dbSDimitry Andric } 9715ffd83dbSDimitry Andric 9725ffd83dbSDimitry Andric // If we have more FP constraints than not, then move everything over to 9735ffd83dbSDimitry Andric // FPR. 9745ffd83dbSDimitry Andric if (NumFP >= 2) 9755ffd83dbSDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstGPR, PMI_FirstFPR, PMI_FirstFPR}; 9765ffd83dbSDimitry Andric 9775ffd83dbSDimitry Andric break; 9785ffd83dbSDimitry Andric } 9795ffd83dbSDimitry Andric case TargetOpcode::G_UNMERGE_VALUES: { 9805ffd83dbSDimitry Andric // If the first operand belongs to a FPR register bank, then make sure that 9815ffd83dbSDimitry Andric // we preserve that. 9825ffd83dbSDimitry Andric if (OpRegBankIdx[0] != PMI_FirstGPR) 9835ffd83dbSDimitry Andric break; 9845ffd83dbSDimitry Andric 9855ffd83dbSDimitry Andric LLT SrcTy = MRI.getType(MI.getOperand(MI.getNumOperands()-1).getReg()); 9865ffd83dbSDimitry Andric // UNMERGE into scalars from a vector should always use FPR. 9875ffd83dbSDimitry Andric // Likewise if any of the uses are FP instructions. 9885ffd83dbSDimitry Andric if (SrcTy.isVector() || SrcTy == LLT::scalar(128) || 9895ffd83dbSDimitry Andric any_of(MRI.use_nodbg_instructions(MI.getOperand(0).getReg()), 9905ffd83dbSDimitry Andric [&](MachineInstr &MI) { return onlyUsesFP(MI, MRI, TRI); })) { 9915ffd83dbSDimitry Andric // Set the register bank of every operand to FPR. 9925ffd83dbSDimitry Andric for (unsigned Idx = 0, NumOperands = MI.getNumOperands(); 9935ffd83dbSDimitry Andric Idx < NumOperands; ++Idx) 9945ffd83dbSDimitry Andric OpRegBankIdx[Idx] = PMI_FirstFPR; 9955ffd83dbSDimitry Andric } 9965ffd83dbSDimitry Andric break; 9975ffd83dbSDimitry Andric } 9985ffd83dbSDimitry Andric case TargetOpcode::G_EXTRACT_VECTOR_ELT: 9995ffd83dbSDimitry Andric // Destination and source need to be FPRs. 10005ffd83dbSDimitry Andric OpRegBankIdx[0] = PMI_FirstFPR; 10015ffd83dbSDimitry Andric OpRegBankIdx[1] = PMI_FirstFPR; 10025ffd83dbSDimitry Andric 10035ffd83dbSDimitry Andric // Index needs to be a GPR. 10045ffd83dbSDimitry Andric OpRegBankIdx[2] = PMI_FirstGPR; 10055ffd83dbSDimitry Andric break; 10065ffd83dbSDimitry Andric case TargetOpcode::G_INSERT_VECTOR_ELT: 10075ffd83dbSDimitry Andric OpRegBankIdx[0] = PMI_FirstFPR; 10085ffd83dbSDimitry Andric OpRegBankIdx[1] = PMI_FirstFPR; 10095ffd83dbSDimitry Andric 10105ffd83dbSDimitry Andric // The element may be either a GPR or FPR. Preserve that behaviour. 10115ffd83dbSDimitry Andric if (getRegBank(MI.getOperand(2).getReg(), MRI, TRI) == &AArch64::FPRRegBank) 10125ffd83dbSDimitry Andric OpRegBankIdx[2] = PMI_FirstFPR; 1013*0fca6ea1SDimitry Andric else { 1014*0fca6ea1SDimitry Andric // If the type is i8/i16, and the regank will be GPR, then we change the 1015*0fca6ea1SDimitry Andric // type to i32 in applyMappingImpl. 1016*0fca6ea1SDimitry Andric LLT Ty = MRI.getType(MI.getOperand(2).getReg()); 1017*0fca6ea1SDimitry Andric if (Ty.getSizeInBits() == 8 || Ty.getSizeInBits() == 16) 1018*0fca6ea1SDimitry Andric MappingID = 1; 10195ffd83dbSDimitry Andric OpRegBankIdx[2] = PMI_FirstGPR; 1020*0fca6ea1SDimitry Andric } 10215ffd83dbSDimitry Andric 10225ffd83dbSDimitry Andric // Index needs to be a GPR. 10235ffd83dbSDimitry Andric OpRegBankIdx[3] = PMI_FirstGPR; 10245ffd83dbSDimitry Andric break; 10255ffd83dbSDimitry Andric case TargetOpcode::G_EXTRACT: { 1026fe6060f1SDimitry Andric // For s128 sources we have to use fpr unless we know otherwise. 1027fe6060f1SDimitry Andric auto Src = MI.getOperand(1).getReg(); 10285ffd83dbSDimitry Andric LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); 1029fe6060f1SDimitry Andric if (SrcTy.getSizeInBits() != 128) 1030fe6060f1SDimitry Andric break; 1031fe6060f1SDimitry Andric auto Idx = MRI.getRegClassOrNull(Src) == &AArch64::XSeqPairsClassRegClass 1032fe6060f1SDimitry Andric ? PMI_FirstGPR 1033fe6060f1SDimitry Andric : PMI_FirstFPR; 1034fe6060f1SDimitry Andric OpRegBankIdx[0] = Idx; 1035fe6060f1SDimitry Andric OpRegBankIdx[1] = Idx; 10365ffd83dbSDimitry Andric break; 10375ffd83dbSDimitry Andric } 1038e8d8bef9SDimitry Andric case TargetOpcode::G_BUILD_VECTOR: { 10395ffd83dbSDimitry Andric // If the first source operand belongs to a FPR register bank, then make 10405ffd83dbSDimitry Andric // sure that we preserve that. 10415ffd83dbSDimitry Andric if (OpRegBankIdx[1] != PMI_FirstGPR) 10425ffd83dbSDimitry Andric break; 10435ffd83dbSDimitry Andric Register VReg = MI.getOperand(1).getReg(); 10445ffd83dbSDimitry Andric if (!VReg) 10455ffd83dbSDimitry Andric break; 10465ffd83dbSDimitry Andric 10475ffd83dbSDimitry Andric // Get the instruction that defined the source operand reg, and check if 10485ffd83dbSDimitry Andric // it's a floating point operation. Or, if it's a type like s16 which 1049e8d8bef9SDimitry Andric // doesn't have a exact size gpr register class. The exception is if the 1050e8d8bef9SDimitry Andric // build_vector has all constant operands, which may be better to leave as 1051e8d8bef9SDimitry Andric // gpr without copies, so it can be matched in imported patterns. 10525ffd83dbSDimitry Andric MachineInstr *DefMI = MRI.getVRegDef(VReg); 10535ffd83dbSDimitry Andric unsigned DefOpc = DefMI->getOpcode(); 10545ffd83dbSDimitry Andric const LLT SrcTy = MRI.getType(VReg); 1055e8d8bef9SDimitry Andric if (all_of(MI.operands(), [&](const MachineOperand &Op) { 1056e8d8bef9SDimitry Andric return Op.isDef() || MRI.getVRegDef(Op.getReg())->getOpcode() == 1057e8d8bef9SDimitry Andric TargetOpcode::G_CONSTANT; 1058e8d8bef9SDimitry Andric })) 1059e8d8bef9SDimitry Andric break; 10605ffd83dbSDimitry Andric if (isPreISelGenericFloatingPointOpcode(DefOpc) || 1061fe6060f1SDimitry Andric SrcTy.getSizeInBits() < 32 || 1062fe6060f1SDimitry Andric getRegBank(VReg, MRI, TRI) == &AArch64::FPRRegBank) { 10635ffd83dbSDimitry Andric // Have a floating point op. 10645ffd83dbSDimitry Andric // Make sure every operand gets mapped to a FPR register class. 10655ffd83dbSDimitry Andric unsigned NumOperands = MI.getNumOperands(); 10665ffd83dbSDimitry Andric for (unsigned Idx = 0; Idx < NumOperands; ++Idx) 10675ffd83dbSDimitry Andric OpRegBankIdx[Idx] = PMI_FirstFPR; 10685ffd83dbSDimitry Andric } 10695ffd83dbSDimitry Andric break; 10705ffd83dbSDimitry Andric } 1071e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_FADD: 1072e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_FMUL: 1073e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_FMAX: 1074e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_FMIN: 10755f757f3fSDimitry Andric case TargetOpcode::G_VECREDUCE_FMAXIMUM: 10765f757f3fSDimitry Andric case TargetOpcode::G_VECREDUCE_FMINIMUM: 1077e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_ADD: 1078e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_MUL: 1079e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_AND: 1080e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_OR: 1081e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_XOR: 1082e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_SMAX: 1083e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_SMIN: 1084e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_UMAX: 1085e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_UMIN: 1086e8d8bef9SDimitry Andric // Reductions produce a scalar value from a vector, the scalar should be on 1087e8d8bef9SDimitry Andric // FPR bank. 1088e8d8bef9SDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR}; 1089e8d8bef9SDimitry Andric break; 1090e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_SEQ_FADD: 1091e8d8bef9SDimitry Andric case TargetOpcode::G_VECREDUCE_SEQ_FMUL: 1092e8d8bef9SDimitry Andric // These reductions also take a scalar accumulator input. 1093e8d8bef9SDimitry Andric // Assign them FPR for now. 1094e8d8bef9SDimitry Andric OpRegBankIdx = {PMI_FirstFPR, PMI_FirstFPR, PMI_FirstFPR}; 1095e8d8bef9SDimitry Andric break; 10965f757f3fSDimitry Andric case TargetOpcode::G_INTRINSIC: 10975f757f3fSDimitry Andric case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: { 1098fe6060f1SDimitry Andric // Check if we know that the intrinsic has any constraints on its register 1099fe6060f1SDimitry Andric // banks. If it does, then update the mapping accordingly. 1100fe6060f1SDimitry Andric unsigned Idx = 0; 11015f757f3fSDimitry Andric if (onlyDefinesFP(MI, MRI, TRI)) 11025f757f3fSDimitry Andric for (const auto &Op : MI.defs()) { 11035f757f3fSDimitry Andric if (Op.isReg()) 11045f757f3fSDimitry Andric OpRegBankIdx[Idx] = PMI_FirstFPR; 11055f757f3fSDimitry Andric ++Idx; 11065f757f3fSDimitry Andric } 11075f757f3fSDimitry Andric else 11085f757f3fSDimitry Andric Idx += MI.getNumExplicitDefs(); 11095f757f3fSDimitry Andric 11105f757f3fSDimitry Andric if (onlyUsesFP(MI, MRI, TRI)) 11115f757f3fSDimitry Andric for (const auto &Op : MI.explicit_uses()) { 1112fe6060f1SDimitry Andric if (Op.isReg()) 1113fe6060f1SDimitry Andric OpRegBankIdx[Idx] = PMI_FirstFPR; 1114fe6060f1SDimitry Andric ++Idx; 1115fe6060f1SDimitry Andric } 1116fe6060f1SDimitry Andric break; 1117fe6060f1SDimitry Andric } 1118349cc55cSDimitry Andric case TargetOpcode::G_LROUND: 1119349cc55cSDimitry Andric case TargetOpcode::G_LLROUND: { 1120349cc55cSDimitry Andric // Source is always floating point and destination is always integer. 1121349cc55cSDimitry Andric OpRegBankIdx = {PMI_FirstGPR, PMI_FirstFPR}; 1122349cc55cSDimitry Andric break; 1123349cc55cSDimitry Andric } 1124e8d8bef9SDimitry Andric } 11255ffd83dbSDimitry Andric 11265ffd83dbSDimitry Andric // Finally construct the computed mapping. 11275ffd83dbSDimitry Andric SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); 11285ffd83dbSDimitry Andric for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { 11295ffd83dbSDimitry Andric if (MI.getOperand(Idx).isReg() && MI.getOperand(Idx).getReg()) { 1130bdd1243dSDimitry Andric LLT Ty = MRI.getType(MI.getOperand(Idx).getReg()); 1131bdd1243dSDimitry Andric if (!Ty.isValid()) 1132bdd1243dSDimitry Andric continue; 1133*0fca6ea1SDimitry Andric auto Mapping = 1134*0fca6ea1SDimitry Andric getValueMapping(OpRegBankIdx[Idx], TypeSize::getFixed(OpSize[Idx])); 11355ffd83dbSDimitry Andric if (!Mapping->isValid()) 11365ffd83dbSDimitry Andric return getInvalidInstructionMapping(); 11375ffd83dbSDimitry Andric 11385ffd83dbSDimitry Andric OpdsMapping[Idx] = Mapping; 11395ffd83dbSDimitry Andric } 11405ffd83dbSDimitry Andric } 11415ffd83dbSDimitry Andric 1142*0fca6ea1SDimitry Andric return getInstructionMapping(MappingID, Cost, getOperandsMapping(OpdsMapping), 1143*0fca6ea1SDimitry Andric NumOperands); 11445ffd83dbSDimitry Andric } 1145