106c3fb27SDimitry Andric //===-- RISCVSubtarget.h - Define Subtarget for the RISC-V ------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 906c3fb27SDimitry Andric // This file declares the RISC-V specific subclass of TargetSubtargetInfo. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_RISCV_RISCVSUBTARGET_H 140b57cec5SDimitry Andric #define LLVM_LIB_TARGET_RISCV_RISCVSUBTARGET_H 150b57cec5SDimitry Andric 16*0fca6ea1SDimitry Andric #include "GISel/RISCVRegisterBankInfo.h" 17e8d8bef9SDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h" 180b57cec5SDimitry Andric #include "RISCVFrameLowering.h" 190b57cec5SDimitry Andric #include "RISCVISelLowering.h" 200b57cec5SDimitry Andric #include "RISCVInstrInfo.h" 218bcb0991SDimitry Andric #include "llvm/CodeGen/GlobalISel/CallLowering.h" 228bcb0991SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" 238bcb0991SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGTargetInfo.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 260b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 270b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 285f757f3fSDimitry Andric #include <bitset> 290b57cec5SDimitry Andric 30b3edf446SDimitry Andric #define GET_RISCV_MACRO_FUSION_PRED_DECL 31b3edf446SDimitry Andric #include "RISCVGenMacroFusion.inc" 32b3edf446SDimitry Andric 330b57cec5SDimitry Andric #define GET_SUBTARGETINFO_HEADER 340b57cec5SDimitry Andric #include "RISCVGenSubtargetInfo.inc" 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric namespace llvm { 370b57cec5SDimitry Andric class StringRef; 380b57cec5SDimitry Andric 395f757f3fSDimitry Andric namespace RISCVTuneInfoTable { 405f757f3fSDimitry Andric 415f757f3fSDimitry Andric struct RISCVTuneInfo { 425f757f3fSDimitry Andric const char *Name; 435f757f3fSDimitry Andric uint8_t PrefFunctionAlignment; 445f757f3fSDimitry Andric uint8_t PrefLoopAlignment; 455f757f3fSDimitry Andric 465f757f3fSDimitry Andric // Information needed by LoopDataPrefetch. 475f757f3fSDimitry Andric uint16_t CacheLineSize; 485f757f3fSDimitry Andric uint16_t PrefetchDistance; 495f757f3fSDimitry Andric uint16_t MinPrefetchStride; 505f757f3fSDimitry Andric unsigned MaxPrefetchIterationsAhead; 515f757f3fSDimitry Andric 525f757f3fSDimitry Andric unsigned MinimumJumpTableEntries; 535f757f3fSDimitry Andric }; 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric #define GET_RISCVTuneInfoTable_DECL 565f757f3fSDimitry Andric #include "RISCVGenSearchableTables.inc" 575f757f3fSDimitry Andric } // namespace RISCVTuneInfoTable 585f757f3fSDimitry Andric 590b57cec5SDimitry Andric class RISCVSubtarget : public RISCVGenSubtargetInfo { 6004eeddc0SDimitry Andric public: 615f757f3fSDimitry Andric // clang-format off 6204eeddc0SDimitry Andric enum RISCVProcFamilyEnum : uint8_t { 6304eeddc0SDimitry Andric Others, 6404eeddc0SDimitry Andric SiFive7, 655f757f3fSDimitry Andric VentanaVeyron, 6604eeddc0SDimitry Andric }; 675f757f3fSDimitry Andric // clang-format on 6804eeddc0SDimitry Andric private: 690b57cec5SDimitry Andric virtual void anchor(); 7004eeddc0SDimitry Andric 7104eeddc0SDimitry Andric RISCVProcFamilyEnum RISCVProcFamily = Others; 7204eeddc0SDimitry Andric 73bdd1243dSDimitry Andric #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ 74bdd1243dSDimitry Andric bool ATTRIBUTE = DEFAULT; 75bdd1243dSDimitry Andric #include "RISCVGenSubtargetInfo.inc" 76bdd1243dSDimitry Andric 7781ad6265SDimitry Andric unsigned ZvlLen = 0; 78bdd1243dSDimitry Andric unsigned RVVVectorBitsMin; 79bdd1243dSDimitry Andric unsigned RVVVectorBitsMax; 80fe6060f1SDimitry Andric uint8_t MaxInterleaveFactor = 2; 810b57cec5SDimitry Andric RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown; 82bdd1243dSDimitry Andric std::bitset<RISCV::NUM_TARGET_REGS> UserReservedRegister; 835f757f3fSDimitry Andric const RISCVTuneInfoTable::RISCVTuneInfo *TuneInfo; 8406c3fb27SDimitry Andric 850b57cec5SDimitry Andric RISCVFrameLowering FrameLowering; 860b57cec5SDimitry Andric RISCVInstrInfo InstrInfo; 870b57cec5SDimitry Andric RISCVRegisterInfo RegInfo; 880b57cec5SDimitry Andric RISCVTargetLowering TLInfo; 890b57cec5SDimitry Andric SelectionDAGTargetInfo TSInfo; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric /// Initializes using the passed in CPU and feature strings so that we can 920b57cec5SDimitry Andric /// use initializer lists for subtarget initialization. 930b57cec5SDimitry Andric RISCVSubtarget &initializeSubtargetDependencies(const Triple &TT, 94e8d8bef9SDimitry Andric StringRef CPU, 95e8d8bef9SDimitry Andric StringRef TuneCPU, 96e8d8bef9SDimitry Andric StringRef FS, 970b57cec5SDimitry Andric StringRef ABIName); 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric public: 1000b57cec5SDimitry Andric // Initializes the data members to match that of the specified triple. 101e8d8bef9SDimitry Andric RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, 102bdd1243dSDimitry Andric StringRef FS, StringRef ABIName, unsigned RVVVectorBitsMin, 103bdd1243dSDimitry Andric unsigned RVVVectorLMULMax, const TargetMachine &TM); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric // Parses features string setting specified subtarget options. The 1060b57cec5SDimitry Andric // definition of this function is auto-generated by tblgen. 107e8d8bef9SDimitry Andric void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric const RISCVFrameLowering *getFrameLowering() const override { 1100b57cec5SDimitry Andric return &FrameLowering; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric const RISCVInstrInfo *getInstrInfo() const override { return &InstrInfo; } 1130b57cec5SDimitry Andric const RISCVRegisterInfo *getRegisterInfo() const override { 1140b57cec5SDimitry Andric return &RegInfo; 1150b57cec5SDimitry Andric } 1160b57cec5SDimitry Andric const RISCVTargetLowering *getTargetLowering() const override { 1170b57cec5SDimitry Andric return &TLInfo; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { 1200b57cec5SDimitry Andric return &TSInfo; 1210b57cec5SDimitry Andric } 1228bcb0991SDimitry Andric bool enableMachineScheduler() const override { return true; } 12304eeddc0SDimitry Andric 124*0fca6ea1SDimitry Andric bool enablePostRAScheduler() const override { return UsePostRAScheduler; } 1255f757f3fSDimitry Andric 1265f757f3fSDimitry Andric Align getPrefFunctionAlignment() const { 1275f757f3fSDimitry Andric return Align(TuneInfo->PrefFunctionAlignment); 1285f757f3fSDimitry Andric } 1295f757f3fSDimitry Andric Align getPrefLoopAlignment() const { 1305f757f3fSDimitry Andric return Align(TuneInfo->PrefLoopAlignment); 1315f757f3fSDimitry Andric } 13206c3fb27SDimitry Andric 13306c3fb27SDimitry Andric /// Returns RISC-V processor family. 13404eeddc0SDimitry Andric /// Avoid this function! CPU specifics should be kept local to this class 13504eeddc0SDimitry Andric /// and preferably modeled with SubtargetFeatures or properties in 13604eeddc0SDimitry Andric /// initializeProperties(). 13704eeddc0SDimitry Andric RISCVProcFamilyEnum getProcFamily() const { return RISCVProcFamily; } 13804eeddc0SDimitry Andric 139bdd1243dSDimitry Andric #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ 140bdd1243dSDimitry Andric bool GETTER() const { return ATTRIBUTE; } 141bdd1243dSDimitry Andric #include "RISCVGenSubtargetInfo.inc" 142bdd1243dSDimitry Andric 143bdd1243dSDimitry Andric bool hasStdExtCOrZca() const { return HasStdExtC || HasStdExtZca; } 144*0fca6ea1SDimitry Andric bool hasStdExtCOrZcd() const { return HasStdExtC || HasStdExtZcd; } 145*0fca6ea1SDimitry Andric bool hasStdExtCOrZcfOrZce() const { 146*0fca6ea1SDimitry Andric return HasStdExtC || HasStdExtZcf || HasStdExtZce; 147*0fca6ea1SDimitry Andric } 14881ad6265SDimitry Andric bool hasStdExtZvl() const { return ZvlLen != 0; } 14906c3fb27SDimitry Andric bool hasStdExtFOrZfinx() const { return HasStdExtF || HasStdExtZfinx; } 15006c3fb27SDimitry Andric bool hasStdExtDOrZdinx() const { return HasStdExtD || HasStdExtZdinx; } 15106c3fb27SDimitry Andric bool hasStdExtZfhOrZhinx() const { return HasStdExtZfh || HasStdExtZhinx; } 152cb14a3feSDimitry Andric bool hasStdExtZfhminOrZhinxmin() const { 153cb14a3feSDimitry Andric return HasStdExtZfhmin || HasStdExtZhinxmin; 15406c3fb27SDimitry Andric } 15506c3fb27SDimitry Andric bool hasHalfFPLoadStoreMove() const { 156cb14a3feSDimitry Andric return HasStdExtZfhmin || HasStdExtZfbfmin; 15706c3fb27SDimitry Andric } 1581db9f3b2SDimitry Andric 1591db9f3b2SDimitry Andric bool hasConditionalMoveFusion() const { 1601db9f3b2SDimitry Andric // Do we support fusing a branch+mv or branch+c.mv as a conditional move. 1611db9f3b2SDimitry Andric return (hasConditionalCompressedMoveFusion() && hasStdExtCOrZca()) || 1621db9f3b2SDimitry Andric hasShortForwardBranchOpt(); 1631db9f3b2SDimitry Andric } 1641db9f3b2SDimitry Andric 16506c3fb27SDimitry Andric bool is64Bit() const { return IsRV64; } 1665f757f3fSDimitry Andric MVT getXLenVT() const { 1675f757f3fSDimitry Andric return is64Bit() ? MVT::i64 : MVT::i32; 1685f757f3fSDimitry Andric } 1695f757f3fSDimitry Andric unsigned getXLen() const { 1705f757f3fSDimitry Andric return is64Bit() ? 64 : 32; 1715f757f3fSDimitry Andric } 17204eeddc0SDimitry Andric unsigned getFLen() const { 17304eeddc0SDimitry Andric if (HasStdExtD) 17404eeddc0SDimitry Andric return 64; 17504eeddc0SDimitry Andric 17604eeddc0SDimitry Andric if (HasStdExtF) 17704eeddc0SDimitry Andric return 32; 17804eeddc0SDimitry Andric 17904eeddc0SDimitry Andric return 0; 18004eeddc0SDimitry Andric } 1815f757f3fSDimitry Andric unsigned getELen() const { 18281ad6265SDimitry Andric assert(hasVInstructions() && "Expected V extension"); 18381ad6265SDimitry Andric return hasVInstructionsI64() ? 64 : 32; 18481ad6265SDimitry Andric } 18581ad6265SDimitry Andric unsigned getRealMinVLen() const { 18681ad6265SDimitry Andric unsigned VLen = getMinRVVVectorSizeInBits(); 187bdd1243dSDimitry Andric return VLen == 0 ? ZvlLen : VLen; 18881ad6265SDimitry Andric } 18981ad6265SDimitry Andric unsigned getRealMaxVLen() const { 19081ad6265SDimitry Andric unsigned VLen = getMaxRVVVectorSizeInBits(); 191bdd1243dSDimitry Andric return VLen == 0 ? 65536 : VLen; 19281ad6265SDimitry Andric } 193*0fca6ea1SDimitry Andric // If we know the exact VLEN, return it. Otherwise, return std::nullopt. 194*0fca6ea1SDimitry Andric std::optional<unsigned> getRealVLen() const { 195*0fca6ea1SDimitry Andric unsigned Min = getRealMinVLen(); 196*0fca6ea1SDimitry Andric if (Min != getRealMaxVLen()) 197*0fca6ea1SDimitry Andric return std::nullopt; 198*0fca6ea1SDimitry Andric return Min; 199*0fca6ea1SDimitry Andric } 200*0fca6ea1SDimitry Andric 201*0fca6ea1SDimitry Andric /// If the ElementCount or TypeSize \p X is scalable and VScale (VLEN) is 202*0fca6ea1SDimitry Andric /// exactly known, returns \p X converted to a fixed quantity. Otherwise 203*0fca6ea1SDimitry Andric /// returns \p X unmodified. 204*0fca6ea1SDimitry Andric template <typename Quantity> Quantity expandVScale(Quantity X) const { 205*0fca6ea1SDimitry Andric if (auto VLen = getRealVLen(); VLen && X.isScalable()) { 206*0fca6ea1SDimitry Andric const unsigned VScale = *VLen / RISCV::RVVBitsPerBlock; 207*0fca6ea1SDimitry Andric X = Quantity::getFixed(X.getKnownMinValue() * VScale); 208*0fca6ea1SDimitry Andric } 209*0fca6ea1SDimitry Andric return X; 210*0fca6ea1SDimitry Andric } 211*0fca6ea1SDimitry Andric 2120b57cec5SDimitry Andric RISCVABI::ABI getTargetABI() const { return TargetABI; } 21306c3fb27SDimitry Andric bool isSoftFPABI() const { 21406c3fb27SDimitry Andric return TargetABI == RISCVABI::ABI_LP64 || 21506c3fb27SDimitry Andric TargetABI == RISCVABI::ABI_ILP32 || 21606c3fb27SDimitry Andric TargetABI == RISCVABI::ABI_ILP32E; 21706c3fb27SDimitry Andric } 218480093f4SDimitry Andric bool isRegisterReservedByUser(Register i) const { 219480093f4SDimitry Andric assert(i < RISCV::NUM_TARGET_REGS && "Register out of range"); 220480093f4SDimitry Andric return UserReservedRegister[i]; 221480093f4SDimitry Andric } 222349cc55cSDimitry Andric 223349cc55cSDimitry Andric // Vector codegen related methods. 22481ad6265SDimitry Andric bool hasVInstructions() const { return HasStdExtZve32x; } 22581ad6265SDimitry Andric bool hasVInstructionsI64() const { return HasStdExtZve64x; } 226cb14a3feSDimitry Andric bool hasVInstructionsF16Minimal() const { return HasStdExtZvfhmin; } 22706c3fb27SDimitry Andric bool hasVInstructionsF16() const { return HasStdExtZvfh; } 2285f757f3fSDimitry Andric bool hasVInstructionsBF16() const { return HasStdExtZvfbfmin; } 2295f757f3fSDimitry Andric bool hasVInstructionsF32() const { return HasStdExtZve32f; } 2305f757f3fSDimitry Andric bool hasVInstructionsF64() const { return HasStdExtZve64d; } 231349cc55cSDimitry Andric // F16 and F64 both require F32. 232349cc55cSDimitry Andric bool hasVInstructionsAnyF() const { return hasVInstructionsF32(); } 23306c3fb27SDimitry Andric bool hasVInstructionsFullMultiply() const { return HasStdExtV; } 234fe6060f1SDimitry Andric unsigned getMaxInterleaveFactor() const { 235349cc55cSDimitry Andric return hasVInstructions() ? MaxInterleaveFactor : 1; 236fe6060f1SDimitry Andric } 2378bcb0991SDimitry Andric 23806c3fb27SDimitry Andric // Returns VLEN divided by DLEN. Where DLEN is the datapath width of the 23906c3fb27SDimitry Andric // vector hardware implementation which may be less than VLEN. 24006c3fb27SDimitry Andric unsigned getDLenFactor() const { 24106c3fb27SDimitry Andric if (DLenFactor2) 24206c3fb27SDimitry Andric return 2; 24306c3fb27SDimitry Andric return 1; 24406c3fb27SDimitry Andric } 24506c3fb27SDimitry Andric 2468bcb0991SDimitry Andric protected: 2478bcb0991SDimitry Andric // GlobalISel related APIs. 248*0fca6ea1SDimitry Andric mutable std::unique_ptr<CallLowering> CallLoweringInfo; 249*0fca6ea1SDimitry Andric mutable std::unique_ptr<InstructionSelector> InstSelector; 250*0fca6ea1SDimitry Andric mutable std::unique_ptr<LegalizerInfo> Legalizer; 251*0fca6ea1SDimitry Andric mutable std::unique_ptr<RISCVRegisterBankInfo> RegBankInfo; 2528bcb0991SDimitry Andric 25381ad6265SDimitry Andric // Return the known range for the bit length of RVV data registers as set 25481ad6265SDimitry Andric // at the command line. A value of 0 means nothing is known about that particular 25581ad6265SDimitry Andric // limit beyond what's implied by the architecture. 25681ad6265SDimitry Andric // NOTE: Please use getRealMinVLen and getRealMaxVLen instead! 25781ad6265SDimitry Andric unsigned getMaxRVVVectorSizeInBits() const; 25881ad6265SDimitry Andric unsigned getMinRVVVectorSizeInBits() const; 25981ad6265SDimitry Andric 2608bcb0991SDimitry Andric public: 2618bcb0991SDimitry Andric const CallLowering *getCallLowering() const override; 2628bcb0991SDimitry Andric InstructionSelector *getInstructionSelector() const override; 2638bcb0991SDimitry Andric const LegalizerInfo *getLegalizerInfo() const override; 264*0fca6ea1SDimitry Andric const RISCVRegisterBankInfo *getRegBankInfo() const override; 265fe6060f1SDimitry Andric 266*0fca6ea1SDimitry Andric bool isTargetAndroid() const { return getTargetTriple().isAndroid(); } 2671ac55f4cSDimitry Andric bool isTargetFuchsia() const { return getTargetTriple().isOSFuchsia(); } 2681ac55f4cSDimitry Andric 26904eeddc0SDimitry Andric bool useConstantPoolForLargeInts() const; 27004eeddc0SDimitry Andric 27104eeddc0SDimitry Andric // Maximum cost used for building integers, integers will be put into constant 27204eeddc0SDimitry Andric // pool if exceeded. 27304eeddc0SDimitry Andric unsigned getMaxBuildIntsCost() const; 27404eeddc0SDimitry Andric 275fe6060f1SDimitry Andric unsigned getMaxLMULForFixedLengthVectors() const; 276fe6060f1SDimitry Andric bool useRVVForFixedLengthVectors() const; 27781ad6265SDimitry Andric 27881ad6265SDimitry Andric bool enableSubRegLiveness() const override; 27981ad6265SDimitry Andric 28081ad6265SDimitry Andric void getPostRAMutations(std::vector<std::unique_ptr<ScheduleDAGMutation>> 28181ad6265SDimitry Andric &Mutations) const override; 2825f757f3fSDimitry Andric 2835f757f3fSDimitry Andric bool useAA() const override; 2845f757f3fSDimitry Andric 2855f757f3fSDimitry Andric unsigned getCacheLineSize() const override { 2865f757f3fSDimitry Andric return TuneInfo->CacheLineSize; 2875f757f3fSDimitry Andric }; 2885f757f3fSDimitry Andric unsigned getPrefetchDistance() const override { 2895f757f3fSDimitry Andric return TuneInfo->PrefetchDistance; 2905f757f3fSDimitry Andric }; 2915f757f3fSDimitry Andric unsigned getMinPrefetchStride(unsigned NumMemAccesses, 2925f757f3fSDimitry Andric unsigned NumStridedMemAccesses, 2935f757f3fSDimitry Andric unsigned NumPrefetches, 2945f757f3fSDimitry Andric bool HasCall) const override { 2955f757f3fSDimitry Andric return TuneInfo->MinPrefetchStride; 2965f757f3fSDimitry Andric }; 2975f757f3fSDimitry Andric unsigned getMaxPrefetchIterationsAhead() const override { 2985f757f3fSDimitry Andric return TuneInfo->MaxPrefetchIterationsAhead; 2995f757f3fSDimitry Andric }; 3005f757f3fSDimitry Andric 3015f757f3fSDimitry Andric unsigned getMinimumJumpTableEntries() const; 302*0fca6ea1SDimitry Andric 303*0fca6ea1SDimitry Andric bool supportsInitUndef() const override { return hasVInstructions(); } 3040b57cec5SDimitry Andric }; 3050b57cec5SDimitry Andric } // End llvm namespace 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric #endif 308