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
AArch64RegisterBankInfo(const TargetRegisterInfo & TRI)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
copyCost(const RegisterBank & A,const RegisterBank & B,const TypeSize Size) const2205ffd83dbSDimitry 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 &
getRegBankFromRegClass(const TargetRegisterClass & RC,LLT) const2425ffd83dbSDimitry 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
getInstrAlternativeMappings(const MachineInstr & MI) const2985ffd83dbSDimitry 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
applyMappingImpl(MachineIRBuilder & Builder,const OperandsMapper & OpdMapper) const4055ffd83dbSDimitry 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 &
getSameKindOfOperandsMapping(const MachineInstr & MI) const4335ffd83dbSDimitry 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.
isFPIntrinsic(const MachineRegisterInfo & MRI,const MachineInstr & MI)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
isPHIWithFPContraints(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,const unsigned Depth) const503*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
hasFPConstraints(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,unsigned Depth) const517e8d8bef9SDimitry 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
onlyUsesFP(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,unsigned Depth) const5555ffd83dbSDimitry 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
onlyDefinesFP(const MachineInstr & MI,const MachineRegisterInfo & MRI,const TargetRegisterInfo & TRI,unsigned Depth) const572e8d8bef9SDimitry 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
isLoadFromFPType(const MachineInstr & MI) const6105f757f3fSDimitry 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 &
getInstrMapping(const MachineInstr & MI) const6485ffd83dbSDimitry 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