1bdd1243dSDimitry Andric //===-- RISCVLegalizerInfo.cpp ----------------------------------*- C++ -*-===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric /// \file 906c3fb27SDimitry Andric /// This file implements the targeting of the Machinelegalizer class for RISC-V. 10bdd1243dSDimitry Andric /// \todo This should be generated by TableGen. 11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 12bdd1243dSDimitry Andric 13bdd1243dSDimitry Andric #include "RISCVLegalizerInfo.h" 14*0fca6ea1SDimitry Andric #include "MCTargetDesc/RISCVMatInt.h" 155f757f3fSDimitry Andric #include "RISCVMachineFunctionInfo.h" 1606c3fb27SDimitry Andric #include "RISCVSubtarget.h" 17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h" 185f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 195f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 205f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 21*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 225f757f3fSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 23bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 24bdd1243dSDimitry Andric #include "llvm/CodeGen/ValueTypes.h" 25bdd1243dSDimitry Andric #include "llvm/IR/DerivedTypes.h" 26bdd1243dSDimitry Andric #include "llvm/IR/Type.h" 27bdd1243dSDimitry Andric 28bdd1243dSDimitry Andric using namespace llvm; 295f757f3fSDimitry Andric using namespace LegalityPredicates; 305f757f3fSDimitry Andric using namespace LegalizeMutations; 31bdd1243dSDimitry Andric 325f757f3fSDimitry Andric // Is this type supported by scalar FP arithmetic operations given the current 335f757f3fSDimitry Andric // subtarget. 345f757f3fSDimitry Andric static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx, 355f757f3fSDimitry Andric const RISCVSubtarget &ST) { 365f757f3fSDimitry Andric return [=, &ST](const LegalityQuery &Query) { 375f757f3fSDimitry Andric return Query.Types[TypeIdx].isScalar() && 38*0fca6ea1SDimitry Andric ((ST.hasStdExtZfh() && Query.Types[TypeIdx].getSizeInBits() == 16) || 39*0fca6ea1SDimitry Andric (ST.hasStdExtF() && Query.Types[TypeIdx].getSizeInBits() == 32) || 405f757f3fSDimitry Andric (ST.hasStdExtD() && Query.Types[TypeIdx].getSizeInBits() == 64)); 415f757f3fSDimitry Andric }; 425f757f3fSDimitry Andric } 435f757f3fSDimitry Andric 44*0fca6ea1SDimitry Andric static LegalityPredicate 45*0fca6ea1SDimitry Andric typeIsLegalIntOrFPVec(unsigned TypeIdx, 46*0fca6ea1SDimitry Andric std::initializer_list<LLT> IntOrFPVecTys, 47*0fca6ea1SDimitry Andric const RISCVSubtarget &ST) { 48*0fca6ea1SDimitry Andric LegalityPredicate P = [=, &ST](const LegalityQuery &Query) { 49*0fca6ea1SDimitry Andric return ST.hasVInstructions() && 50*0fca6ea1SDimitry Andric (Query.Types[TypeIdx].getScalarSizeInBits() != 64 || 51*0fca6ea1SDimitry Andric ST.hasVInstructionsI64()) && 52*0fca6ea1SDimitry Andric (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 || 53*0fca6ea1SDimitry Andric ST.getELen() == 64); 54*0fca6ea1SDimitry Andric }; 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric return all(typeInSet(TypeIdx, IntOrFPVecTys), P); 57*0fca6ea1SDimitry Andric } 58*0fca6ea1SDimitry Andric 59*0fca6ea1SDimitry Andric static LegalityPredicate 60*0fca6ea1SDimitry Andric typeIsLegalBoolVec(unsigned TypeIdx, std::initializer_list<LLT> BoolVecTys, 61*0fca6ea1SDimitry Andric const RISCVSubtarget &ST) { 62*0fca6ea1SDimitry Andric LegalityPredicate P = [=, &ST](const LegalityQuery &Query) { 63*0fca6ea1SDimitry Andric return ST.hasVInstructions() && 64*0fca6ea1SDimitry Andric (Query.Types[TypeIdx].getElementCount().getKnownMinValue() != 1 || 65*0fca6ea1SDimitry Andric ST.getELen() == 64); 66*0fca6ea1SDimitry Andric }; 67*0fca6ea1SDimitry Andric return all(typeInSet(TypeIdx, BoolVecTys), P); 68*0fca6ea1SDimitry Andric } 69*0fca6ea1SDimitry Andric 705f757f3fSDimitry Andric RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) 715f757f3fSDimitry Andric : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) { 725f757f3fSDimitry Andric const LLT sDoubleXLen = LLT::scalar(2 * XLen); 735f757f3fSDimitry Andric const LLT p0 = LLT::pointer(0, XLen); 745f757f3fSDimitry Andric const LLT s1 = LLT::scalar(1); 755f757f3fSDimitry Andric const LLT s8 = LLT::scalar(8); 765f757f3fSDimitry Andric const LLT s16 = LLT::scalar(16); 775f757f3fSDimitry Andric const LLT s32 = LLT::scalar(32); 785f757f3fSDimitry Andric const LLT s64 = LLT::scalar(64); 7906c3fb27SDimitry Andric 80*0fca6ea1SDimitry Andric const LLT nxv1s1 = LLT::scalable_vector(1, s1); 81*0fca6ea1SDimitry Andric const LLT nxv2s1 = LLT::scalable_vector(2, s1); 82*0fca6ea1SDimitry Andric const LLT nxv4s1 = LLT::scalable_vector(4, s1); 83*0fca6ea1SDimitry Andric const LLT nxv8s1 = LLT::scalable_vector(8, s1); 84*0fca6ea1SDimitry Andric const LLT nxv16s1 = LLT::scalable_vector(16, s1); 85*0fca6ea1SDimitry Andric const LLT nxv32s1 = LLT::scalable_vector(32, s1); 86*0fca6ea1SDimitry Andric const LLT nxv64s1 = LLT::scalable_vector(64, s1); 87*0fca6ea1SDimitry Andric 88297eecfbSDimitry Andric const LLT nxv1s8 = LLT::scalable_vector(1, s8); 89297eecfbSDimitry Andric const LLT nxv2s8 = LLT::scalable_vector(2, s8); 90297eecfbSDimitry Andric const LLT nxv4s8 = LLT::scalable_vector(4, s8); 91297eecfbSDimitry Andric const LLT nxv8s8 = LLT::scalable_vector(8, s8); 92297eecfbSDimitry Andric const LLT nxv16s8 = LLT::scalable_vector(16, s8); 93297eecfbSDimitry Andric const LLT nxv32s8 = LLT::scalable_vector(32, s8); 94297eecfbSDimitry Andric const LLT nxv64s8 = LLT::scalable_vector(64, s8); 95297eecfbSDimitry Andric 96297eecfbSDimitry Andric const LLT nxv1s16 = LLT::scalable_vector(1, s16); 97297eecfbSDimitry Andric const LLT nxv2s16 = LLT::scalable_vector(2, s16); 98297eecfbSDimitry Andric const LLT nxv4s16 = LLT::scalable_vector(4, s16); 99297eecfbSDimitry Andric const LLT nxv8s16 = LLT::scalable_vector(8, s16); 100297eecfbSDimitry Andric const LLT nxv16s16 = LLT::scalable_vector(16, s16); 101297eecfbSDimitry Andric const LLT nxv32s16 = LLT::scalable_vector(32, s16); 102297eecfbSDimitry Andric 103297eecfbSDimitry Andric const LLT nxv1s32 = LLT::scalable_vector(1, s32); 104297eecfbSDimitry Andric const LLT nxv2s32 = LLT::scalable_vector(2, s32); 105297eecfbSDimitry Andric const LLT nxv4s32 = LLT::scalable_vector(4, s32); 106297eecfbSDimitry Andric const LLT nxv8s32 = LLT::scalable_vector(8, s32); 107297eecfbSDimitry Andric const LLT nxv16s32 = LLT::scalable_vector(16, s32); 108297eecfbSDimitry Andric 109297eecfbSDimitry Andric const LLT nxv1s64 = LLT::scalable_vector(1, s64); 110297eecfbSDimitry Andric const LLT nxv2s64 = LLT::scalable_vector(2, s64); 111297eecfbSDimitry Andric const LLT nxv4s64 = LLT::scalable_vector(4, s64); 112297eecfbSDimitry Andric const LLT nxv8s64 = LLT::scalable_vector(8, s64); 113297eecfbSDimitry Andric 11406c3fb27SDimitry Andric using namespace TargetOpcode; 11506c3fb27SDimitry Andric 116*0fca6ea1SDimitry Andric auto BoolVecTys = {nxv1s1, nxv2s1, nxv4s1, nxv8s1, nxv16s1, nxv32s1, nxv64s1}; 117*0fca6ea1SDimitry Andric 118*0fca6ea1SDimitry Andric auto IntOrFPVecTys = {nxv1s8, nxv2s8, nxv4s8, nxv8s8, nxv16s8, nxv32s8, 119297eecfbSDimitry Andric nxv64s8, nxv1s16, nxv2s16, nxv4s16, nxv8s16, nxv16s16, 120297eecfbSDimitry Andric nxv32s16, nxv1s32, nxv2s32, nxv4s32, nxv8s32, nxv16s32, 121297eecfbSDimitry Andric nxv1s64, nxv2s64, nxv4s64, nxv8s64}; 122297eecfbSDimitry Andric 12306c3fb27SDimitry Andric getActionDefinitionsBuilder({G_ADD, G_SUB, G_AND, G_OR, G_XOR}) 1245f757f3fSDimitry Andric .legalFor({s32, sXLen}) 125*0fca6ea1SDimitry Andric .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST)) 1265f757f3fSDimitry Andric .widenScalarToNextPow2(0) 1275f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 1285f757f3fSDimitry Andric 1295f757f3fSDimitry Andric getActionDefinitionsBuilder( 1305f757f3fSDimitry Andric {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower(); 1315f757f3fSDimitry Andric 1325f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower(); 1335f757f3fSDimitry Andric 134*0fca6ea1SDimitry Andric // TODO: Use Vector Single-Width Saturating Instructions for vector types. 135*0fca6ea1SDimitry Andric getActionDefinitionsBuilder({G_UADDSAT, G_SADDSAT, G_USUBSAT, G_SSUBSAT}) 136*0fca6ea1SDimitry Andric .lower(); 137*0fca6ea1SDimitry Andric 1385f757f3fSDimitry Andric auto &ShiftActions = getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL}); 1395f757f3fSDimitry Andric if (ST.is64Bit()) 1405f757f3fSDimitry Andric ShiftActions.customFor({{s32, s32}}); 1415f757f3fSDimitry Andric ShiftActions.legalFor({{s32, s32}, {s32, sXLen}, {sXLen, sXLen}}) 1425f757f3fSDimitry Andric .widenScalarToNextPow2(0) 1435f757f3fSDimitry Andric .clampScalar(1, s32, sXLen) 1445f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 145*0fca6ea1SDimitry Andric .minScalarSameAs(1, 0) 146*0fca6ea1SDimitry Andric .widenScalarToNextPow2(1); 1475f757f3fSDimitry Andric 148*0fca6ea1SDimitry Andric auto &ExtActions = 1495f757f3fSDimitry Andric getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}) 150*0fca6ea1SDimitry Andric .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST), 151*0fca6ea1SDimitry Andric typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST))); 152*0fca6ea1SDimitry Andric if (ST.is64Bit()) { 153*0fca6ea1SDimitry Andric ExtActions.legalFor({{sXLen, s32}}); 1545f757f3fSDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG) 1555f757f3fSDimitry Andric .customFor({sXLen}) 1565f757f3fSDimitry Andric .maxScalar(0, sXLen) 1575f757f3fSDimitry Andric .lower(); 1585f757f3fSDimitry Andric } else { 1595f757f3fSDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG).maxScalar(0, sXLen).lower(); 1605f757f3fSDimitry Andric } 161*0fca6ea1SDimitry Andric ExtActions.customIf(typeIsLegalBoolVec(1, BoolVecTys, ST)) 162*0fca6ea1SDimitry Andric .maxScalar(0, sXLen); 1635f757f3fSDimitry Andric 1645f757f3fSDimitry Andric // Merge/Unmerge 1655f757f3fSDimitry Andric for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) { 166cb14a3feSDimitry Andric auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op); 1675f757f3fSDimitry Andric unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1; 1685f757f3fSDimitry Andric unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0; 1695f757f3fSDimitry Andric if (XLen == 32 && ST.hasStdExtD()) { 170cb14a3feSDimitry Andric MergeUnmergeActions.legalIf( 171cb14a3feSDimitry Andric all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32))); 1725f757f3fSDimitry Andric } 1735f757f3fSDimitry Andric MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen) 1745f757f3fSDimitry Andric .widenScalarToNextPow2(BigTyIdx, XLen) 1755f757f3fSDimitry Andric .clampScalar(LitTyIdx, sXLen, sXLen) 1765f757f3fSDimitry Andric .clampScalar(BigTyIdx, sXLen, sXLen); 1775f757f3fSDimitry Andric } 1785f757f3fSDimitry Andric 1795f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower(); 1805f757f3fSDimitry Andric 1815f757f3fSDimitry Andric auto &RotateActions = getActionDefinitionsBuilder({G_ROTL, G_ROTR}); 182647cbc5dSDimitry Andric if (ST.hasStdExtZbb() || ST.hasStdExtZbkb()) { 1835f757f3fSDimitry Andric RotateActions.legalFor({{s32, sXLen}, {sXLen, sXLen}}); 1845f757f3fSDimitry Andric // Widen s32 rotate amount to s64 so SDAG patterns will match. 1855f757f3fSDimitry Andric if (ST.is64Bit()) 1865f757f3fSDimitry Andric RotateActions.widenScalarIf(all(typeIs(0, s32), typeIs(1, s32)), 1875f757f3fSDimitry Andric changeTo(1, sXLen)); 1885f757f3fSDimitry Andric } 1895f757f3fSDimitry Andric RotateActions.lower(); 1905f757f3fSDimitry Andric 1915f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BITREVERSE).maxScalar(0, sXLen).lower(); 1925f757f3fSDimitry Andric 193*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_BITCAST).legalIf( 194*0fca6ea1SDimitry Andric all(LegalityPredicates::any(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST), 195*0fca6ea1SDimitry Andric typeIsLegalBoolVec(0, BoolVecTys, ST)), 196*0fca6ea1SDimitry Andric LegalityPredicates::any(typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST), 197*0fca6ea1SDimitry Andric typeIsLegalBoolVec(1, BoolVecTys, ST)))); 198*0fca6ea1SDimitry Andric 1995f757f3fSDimitry Andric auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP); 2001db9f3b2SDimitry Andric if (ST.hasStdExtZbb() || ST.hasStdExtZbkb()) 2015f757f3fSDimitry Andric BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen); 2025f757f3fSDimitry Andric else 2035f757f3fSDimitry Andric BSWAPActions.maxScalar(0, sXLen).lower(); 2045f757f3fSDimitry Andric 2055f757f3fSDimitry Andric auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ}); 2065f757f3fSDimitry Andric auto &CountZerosUndefActions = 2075f757f3fSDimitry Andric getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF}); 2085f757f3fSDimitry Andric if (ST.hasStdExtZbb()) { 2095f757f3fSDimitry Andric CountZerosActions.legalFor({{s32, s32}, {sXLen, sXLen}}) 2105f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 2115f757f3fSDimitry Andric .widenScalarToNextPow2(0) 2125f757f3fSDimitry Andric .scalarSameSizeAs(1, 0); 2135f757f3fSDimitry Andric } else { 2145f757f3fSDimitry Andric CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower(); 2155f757f3fSDimitry Andric CountZerosUndefActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0); 2165f757f3fSDimitry Andric } 2175f757f3fSDimitry Andric CountZerosUndefActions.lower(); 2185f757f3fSDimitry Andric 2195f757f3fSDimitry Andric auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP); 2205f757f3fSDimitry Andric if (ST.hasStdExtZbb()) { 2215f757f3fSDimitry Andric CTPOPActions.legalFor({{s32, s32}, {sXLen, sXLen}}) 2225f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 2235f757f3fSDimitry Andric .widenScalarToNextPow2(0) 2245f757f3fSDimitry Andric .scalarSameSizeAs(1, 0); 2255f757f3fSDimitry Andric } else { 2265f757f3fSDimitry Andric CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower(); 2275f757f3fSDimitry Andric } 2285f757f3fSDimitry Andric 229*0fca6ea1SDimitry Andric auto &ConstantActions = getActionDefinitionsBuilder(G_CONSTANT); 230*0fca6ea1SDimitry Andric ConstantActions.legalFor({s32, p0}); 231*0fca6ea1SDimitry Andric if (ST.is64Bit()) 232*0fca6ea1SDimitry Andric ConstantActions.customFor({s64}); 233*0fca6ea1SDimitry Andric ConstantActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen); 234*0fca6ea1SDimitry Andric 235*0fca6ea1SDimitry Andric // TODO: transform illegal vector types into legal vector type 236*0fca6ea1SDimitry Andric getActionDefinitionsBuilder( 237*0fca6ea1SDimitry Andric {G_IMPLICIT_DEF, G_CONSTANT_FOLD_BARRIER, G_FREEZE}) 2385f757f3fSDimitry Andric .legalFor({s32, sXLen, p0}) 239*0fca6ea1SDimitry Andric .legalIf(typeIsLegalBoolVec(0, BoolVecTys, ST)) 240*0fca6ea1SDimitry Andric .legalIf(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST)) 2415f757f3fSDimitry Andric .widenScalarToNextPow2(0) 2425f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 2435f757f3fSDimitry Andric 2445f757f3fSDimitry Andric getActionDefinitionsBuilder(G_ICMP) 2455f757f3fSDimitry Andric .legalFor({{sXLen, sXLen}, {sXLen, p0}}) 246*0fca6ea1SDimitry Andric .legalIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), 247*0fca6ea1SDimitry Andric typeIsLegalIntOrFPVec(1, IntOrFPVecTys, ST))) 248*0fca6ea1SDimitry Andric .widenScalarOrEltToNextPow2OrMinSize(1, 8) 2495f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen) 2505f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 2515f757f3fSDimitry Andric 252*0fca6ea1SDimitry Andric auto &SelectActions = 253*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_SELECT) 254*0fca6ea1SDimitry Andric .legalFor({{s32, sXLen}, {p0, sXLen}}) 255*0fca6ea1SDimitry Andric .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST), 256*0fca6ea1SDimitry Andric typeIsLegalBoolVec(1, BoolVecTys, ST))); 2575f757f3fSDimitry Andric if (XLen == 64 || ST.hasStdExtD()) 2585f757f3fSDimitry Andric SelectActions.legalFor({{s64, sXLen}}); 2595f757f3fSDimitry Andric SelectActions.widenScalarToNextPow2(0) 2605f757f3fSDimitry Andric .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32) 2615f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen); 2625f757f3fSDimitry Andric 2635f757f3fSDimitry Andric auto &LoadStoreActions = 2645f757f3fSDimitry Andric getActionDefinitionsBuilder({G_LOAD, G_STORE}) 2655f757f3fSDimitry Andric .legalForTypesWithMemDesc({{s32, p0, s8, 8}, 2665f757f3fSDimitry Andric {s32, p0, s16, 16}, 2675f757f3fSDimitry Andric {s32, p0, s32, 32}, 2685f757f3fSDimitry Andric {p0, p0, sXLen, XLen}}); 2695f757f3fSDimitry Andric auto &ExtLoadActions = 2705f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD}) 2715f757f3fSDimitry Andric .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}}); 2725f757f3fSDimitry Andric if (XLen == 64) { 2735f757f3fSDimitry Andric LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s8, 8}, 2745f757f3fSDimitry Andric {s64, p0, s16, 16}, 2755f757f3fSDimitry Andric {s64, p0, s32, 32}, 2765f757f3fSDimitry Andric {s64, p0, s64, 64}}); 2775f757f3fSDimitry Andric ExtLoadActions.legalForTypesWithMemDesc( 2785f757f3fSDimitry Andric {{s64, p0, s8, 8}, {s64, p0, s16, 16}, {s64, p0, s32, 32}}); 2795f757f3fSDimitry Andric } else if (ST.hasStdExtD()) { 2805f757f3fSDimitry Andric LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}}); 2815f757f3fSDimitry Andric } 2825f757f3fSDimitry Andric LoadStoreActions.clampScalar(0, s32, sXLen).lower(); 2835f757f3fSDimitry Andric ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower(); 2845f757f3fSDimitry Andric 2855f757f3fSDimitry Andric getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}}); 2865f757f3fSDimitry Andric 2875f757f3fSDimitry Andric getActionDefinitionsBuilder(G_PTRTOINT) 2885f757f3fSDimitry Andric .legalFor({{sXLen, p0}}) 2895f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 2905f757f3fSDimitry Andric 2915f757f3fSDimitry Andric getActionDefinitionsBuilder(G_INTTOPTR) 2925f757f3fSDimitry Andric .legalFor({{p0, sXLen}}) 2935f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen); 2945f757f3fSDimitry Andric 2955f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen); 2965f757f3fSDimitry Andric 2975f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}}); 2985f757f3fSDimitry Andric 2995f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0}); 3005f757f3fSDimitry Andric 3015f757f3fSDimitry Andric getActionDefinitionsBuilder(G_PHI) 3025f757f3fSDimitry Andric .legalFor({p0, sXLen}) 3035f757f3fSDimitry Andric .widenScalarToNextPow2(0) 3045f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 3055f757f3fSDimitry Andric 3065f757f3fSDimitry Andric getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL}) 3075f757f3fSDimitry Andric .legalFor({p0}); 3085f757f3fSDimitry Andric 309*0fca6ea1SDimitry Andric if (ST.hasStdExtZmmul()) { 3105f757f3fSDimitry Andric getActionDefinitionsBuilder(G_MUL) 3115f757f3fSDimitry Andric .legalFor({s32, sXLen}) 3125f757f3fSDimitry Andric .widenScalarToNextPow2(0) 3135f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 3145f757f3fSDimitry Andric 3155f757f3fSDimitry Andric // clang-format off 3165f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULH, G_UMULH}) 3175f757f3fSDimitry Andric .legalFor({sXLen}) 3185f757f3fSDimitry Andric .lower(); 3195f757f3fSDimitry Andric // clang-format on 3205f757f3fSDimitry Andric 3215f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower(); 3225f757f3fSDimitry Andric } else { 3235f757f3fSDimitry Andric getActionDefinitionsBuilder(G_MUL) 3245f757f3fSDimitry Andric .libcallFor({sXLen, sDoubleXLen}) 3255f757f3fSDimitry Andric .widenScalarToNextPow2(0) 3265f757f3fSDimitry Andric .clampScalar(0, sXLen, sDoubleXLen); 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen}); 3295f757f3fSDimitry Andric 3305f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULO, G_UMULO}) 3315f757f3fSDimitry Andric .minScalar(0, sXLen) 3325f757f3fSDimitry Andric // Widen sXLen to sDoubleXLen so we can use a single libcall to get 3335f757f3fSDimitry Andric // the low bits for the mul result and high bits to do the overflow 3345f757f3fSDimitry Andric // check. 3355f757f3fSDimitry Andric .widenScalarIf(typeIs(0, sXLen), 3365f757f3fSDimitry Andric LegalizeMutations::changeTo(0, sDoubleXLen)) 3375f757f3fSDimitry Andric .lower(); 3385f757f3fSDimitry Andric } 3395f757f3fSDimitry Andric 3405f757f3fSDimitry Andric if (ST.hasStdExtM()) { 3415f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM}) 3425f757f3fSDimitry Andric .legalFor({s32, sXLen}) 3435f757f3fSDimitry Andric .libcallFor({sDoubleXLen}) 3445f757f3fSDimitry Andric .clampScalar(0, s32, sDoubleXLen) 3455f757f3fSDimitry Andric .widenScalarToNextPow2(0); 3465f757f3fSDimitry Andric } else { 3475f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM}) 3485f757f3fSDimitry Andric .libcallFor({sXLen, sDoubleXLen}) 3495f757f3fSDimitry Andric .clampScalar(0, sXLen, sDoubleXLen) 3505f757f3fSDimitry Andric .widenScalarToNextPow2(0); 3515f757f3fSDimitry Andric } 3525f757f3fSDimitry Andric 353*0fca6ea1SDimitry Andric // TODO: Use libcall for sDoubleXLen. 354*0fca6ea1SDimitry Andric getActionDefinitionsBuilder({G_UDIVREM, G_SDIVREM}).lower(); 355*0fca6ea1SDimitry Andric 3565f757f3fSDimitry Andric auto &AbsActions = getActionDefinitionsBuilder(G_ABS); 3575f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 3585f757f3fSDimitry Andric AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen); 3595f757f3fSDimitry Andric AbsActions.lower(); 3605f757f3fSDimitry Andric 3615f757f3fSDimitry Andric auto &MinMaxActions = 3625f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN}); 3635f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 3645f757f3fSDimitry Andric MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen); 3655f757f3fSDimitry Andric MinMaxActions.lower(); 3665f757f3fSDimitry Andric 3675f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0}); 3685f757f3fSDimitry Andric 3695f757f3fSDimitry Andric getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall(); 3705f757f3fSDimitry Andric 3715f757f3fSDimitry Andric getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower(); 3725f757f3fSDimitry Andric 3735f757f3fSDimitry Andric // FP Operations 3745f757f3fSDimitry Andric 3755f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG, 3765f757f3fSDimitry Andric G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM}) 3775f757f3fSDimitry Andric .legalIf(typeIsScalarFPArith(0, ST)); 3785f757f3fSDimitry Andric 379*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_FREM) 380*0fca6ea1SDimitry Andric .libcallFor({s32, s64}) 381*0fca6ea1SDimitry Andric .minScalar(0, s32) 382*0fca6ea1SDimitry Andric .scalarize(0); 383*0fca6ea1SDimitry Andric 3845f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCOPYSIGN) 3855f757f3fSDimitry Andric .legalIf(all(typeIsScalarFPArith(0, ST), typeIsScalarFPArith(1, ST))); 3865f757f3fSDimitry Andric 387*0fca6ea1SDimitry Andric // FIXME: Use Zfhmin. 3885f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FPTRUNC).legalIf( 3895f757f3fSDimitry Andric [=, &ST](const LegalityQuery &Query) -> bool { 3905f757f3fSDimitry Andric return (ST.hasStdExtD() && typeIs(0, s32)(Query) && 391*0fca6ea1SDimitry Andric typeIs(1, s64)(Query)) || 392*0fca6ea1SDimitry Andric (ST.hasStdExtZfh() && typeIs(0, s16)(Query) && 393*0fca6ea1SDimitry Andric typeIs(1, s32)(Query)) || 394*0fca6ea1SDimitry Andric (ST.hasStdExtZfh() && ST.hasStdExtD() && typeIs(0, s16)(Query) && 3955f757f3fSDimitry Andric typeIs(1, s64)(Query)); 3965f757f3fSDimitry Andric }); 3975f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FPEXT).legalIf( 3985f757f3fSDimitry Andric [=, &ST](const LegalityQuery &Query) -> bool { 3995f757f3fSDimitry Andric return (ST.hasStdExtD() && typeIs(0, s64)(Query) && 400*0fca6ea1SDimitry Andric typeIs(1, s32)(Query)) || 401*0fca6ea1SDimitry Andric (ST.hasStdExtZfh() && typeIs(0, s32)(Query) && 402*0fca6ea1SDimitry Andric typeIs(1, s16)(Query)) || 403*0fca6ea1SDimitry Andric (ST.hasStdExtZfh() && ST.hasStdExtD() && typeIs(0, s64)(Query) && 404*0fca6ea1SDimitry Andric typeIs(1, s16)(Query)); 4055f757f3fSDimitry Andric }); 4065f757f3fSDimitry Andric 4075f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCMP) 4085f757f3fSDimitry Andric .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST))) 4095f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 4105f757f3fSDimitry Andric 4115f757f3fSDimitry Andric // TODO: Support vector version of G_IS_FPCLASS. 4125f757f3fSDimitry Andric getActionDefinitionsBuilder(G_IS_FPCLASS) 4135f757f3fSDimitry Andric .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST))); 4145f757f3fSDimitry Andric 4155f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCONSTANT) 4165f757f3fSDimitry Andric .legalIf(typeIsScalarFPArith(0, ST)) 4175f757f3fSDimitry Andric .lowerFor({s32, s64}); 4185f757f3fSDimitry Andric 4195f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 4205f757f3fSDimitry Andric .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST))) 4215f757f3fSDimitry Andric .widenScalarToNextPow2(0) 422*0fca6ea1SDimitry Andric .clampScalar(0, s32, sXLen) 423*0fca6ea1SDimitry Andric .libcall(); 4245f757f3fSDimitry Andric 4255f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) 4265f757f3fSDimitry Andric .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen}))) 4275f757f3fSDimitry Andric .widenScalarToNextPow2(1) 4285f757f3fSDimitry Andric .clampScalar(1, s32, sXLen); 4295f757f3fSDimitry Andric 4305f757f3fSDimitry Andric // FIXME: We can do custom inline expansion like SelectionDAG. 4315f757f3fSDimitry Andric // FIXME: Legal with Zfa. 4325f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR}) 4335f757f3fSDimitry Andric .libcallFor({s32, s64}); 4345f757f3fSDimitry Andric 4355f757f3fSDimitry Andric getActionDefinitionsBuilder(G_VASTART).customFor({p0}); 4365f757f3fSDimitry Andric 4375f757f3fSDimitry Andric // va_list must be a pointer, but most sized types are pretty easy to handle 4385f757f3fSDimitry Andric // as the destination. 4395f757f3fSDimitry Andric getActionDefinitionsBuilder(G_VAARG) 4405f757f3fSDimitry Andric // TODO: Implement narrowScalar and widenScalar for G_VAARG for types 4415f757f3fSDimitry Andric // outside the [s32, sXLen] range. 4425f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 4435f757f3fSDimitry Andric .lowerForCartesianProduct({s32, sXLen, p0}, {p0}); 44406c3fb27SDimitry Andric 445*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_VSCALE) 446*0fca6ea1SDimitry Andric .clampScalar(0, sXLen, sXLen) 447*0fca6ea1SDimitry Andric .customFor({sXLen}); 448*0fca6ea1SDimitry Andric 449*0fca6ea1SDimitry Andric auto &SplatActions = 450*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_SPLAT_VECTOR) 451*0fca6ea1SDimitry Andric .legalIf(all(typeIsLegalIntOrFPVec(0, IntOrFPVecTys, ST), 452*0fca6ea1SDimitry Andric typeIs(1, sXLen))) 453*0fca6ea1SDimitry Andric .customIf(all(typeIsLegalBoolVec(0, BoolVecTys, ST), typeIs(1, s1))); 454*0fca6ea1SDimitry Andric // Handle case of s64 element vectors on RV32. If the subtarget does not have 455*0fca6ea1SDimitry Andric // f64, then try to lower it to G_SPLAT_VECTOR_SPLIT_64_VL. If the subtarget 456*0fca6ea1SDimitry Andric // does have f64, then we don't know whether the type is an f64 or an i64, 457*0fca6ea1SDimitry Andric // so mark the G_SPLAT_VECTOR as legal and decide later what to do with it, 458*0fca6ea1SDimitry Andric // depending on how the instructions it consumes are legalized. They are not 459*0fca6ea1SDimitry Andric // legalized yet since legalization is in reverse postorder, so we cannot 460*0fca6ea1SDimitry Andric // make the decision at this moment. 461*0fca6ea1SDimitry Andric if (XLen == 32) { 462*0fca6ea1SDimitry Andric if (ST.hasVInstructionsF64() && ST.hasStdExtD()) 463*0fca6ea1SDimitry Andric SplatActions.legalIf(all( 464*0fca6ea1SDimitry Andric typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64))); 465*0fca6ea1SDimitry Andric else if (ST.hasVInstructionsI64()) 466*0fca6ea1SDimitry Andric SplatActions.customIf(all( 467*0fca6ea1SDimitry Andric typeInSet(0, {nxv1s64, nxv2s64, nxv4s64, nxv8s64}), typeIs(1, s64))); 468bdd1243dSDimitry Andric } 4695f757f3fSDimitry Andric 470*0fca6ea1SDimitry Andric SplatActions.clampScalar(1, sXLen, sXLen); 471*0fca6ea1SDimitry Andric 472*0fca6ea1SDimitry Andric getLegacyLegalizerInfo().computeTables(); 4735f757f3fSDimitry Andric } 4745f757f3fSDimitry Andric 4755f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, 4765f757f3fSDimitry Andric MachineInstr &MI) const { 4775f757f3fSDimitry Andric Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID(); 4785f757f3fSDimitry Andric switch (IntrinsicID) { 4795f757f3fSDimitry Andric default: 4805f757f3fSDimitry Andric return false; 4815f757f3fSDimitry Andric case Intrinsic::vacopy: { 4825f757f3fSDimitry Andric // vacopy arguments must be legal because of the intrinsic signature. 4835f757f3fSDimitry Andric // No need to check here. 4845f757f3fSDimitry Andric 4855f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 4865f757f3fSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 4875f757f3fSDimitry Andric MachineFunction &MF = *MI.getMF(); 4885f757f3fSDimitry Andric const DataLayout &DL = MIRBuilder.getDataLayout(); 4895f757f3fSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 4905f757f3fSDimitry Andric 4915f757f3fSDimitry Andric Register DstLst = MI.getOperand(1).getReg(); 4925f757f3fSDimitry Andric LLT PtrTy = MRI.getType(DstLst); 4935f757f3fSDimitry Andric 4945f757f3fSDimitry Andric // Load the source va_list 4955f757f3fSDimitry Andric Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx)); 4965f757f3fSDimitry Andric MachineMemOperand *LoadMMO = MF.getMachineMemOperand( 4975f757f3fSDimitry Andric MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment); 4985f757f3fSDimitry Andric auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO); 4995f757f3fSDimitry Andric 5005f757f3fSDimitry Andric // Store the result in the destination va_list 5015f757f3fSDimitry Andric MachineMemOperand *StoreMMO = MF.getMachineMemOperand( 5025f757f3fSDimitry Andric MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, Alignment); 503*0fca6ea1SDimitry Andric MIRBuilder.buildStore(Tmp, DstLst, *StoreMMO); 5045f757f3fSDimitry Andric 5055f757f3fSDimitry Andric MI.eraseFromParent(); 5065f757f3fSDimitry Andric return true; 5075f757f3fSDimitry Andric } 5085f757f3fSDimitry Andric } 5095f757f3fSDimitry Andric } 5105f757f3fSDimitry Andric 5115f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeShlAshrLshr( 5125f757f3fSDimitry Andric MachineInstr &MI, MachineIRBuilder &MIRBuilder, 5135f757f3fSDimitry Andric GISelChangeObserver &Observer) const { 5145f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_ASHR || 5155f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_LSHR || 5165f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_SHL); 5175f757f3fSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 5185f757f3fSDimitry Andric // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the 5195f757f3fSDimitry Andric // imported patterns can select it later. Either way, it will be legal. 5205f757f3fSDimitry Andric Register AmtReg = MI.getOperand(2).getReg(); 5215f757f3fSDimitry Andric auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI); 5225f757f3fSDimitry Andric if (!VRegAndVal) 5235f757f3fSDimitry Andric return true; 5245f757f3fSDimitry Andric // Check the shift amount is in range for an immediate form. 5255f757f3fSDimitry Andric uint64_t Amount = VRegAndVal->Value.getZExtValue(); 5265f757f3fSDimitry Andric if (Amount > 31) 5275f757f3fSDimitry Andric return true; // This will have to remain a register variant. 5285f757f3fSDimitry Andric auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount); 5295f757f3fSDimitry Andric Observer.changingInstr(MI); 5305f757f3fSDimitry Andric MI.getOperand(2).setReg(ExtCst.getReg(0)); 5315f757f3fSDimitry Andric Observer.changedInstr(MI); 5325f757f3fSDimitry Andric return true; 5335f757f3fSDimitry Andric } 5345f757f3fSDimitry Andric 5355f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI, 5365f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder) const { 5375f757f3fSDimitry Andric // Stores the address of the VarArgsFrameIndex slot into the memory location 5385f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_VASTART); 5395f757f3fSDimitry Andric MachineFunction *MF = MI.getParent()->getParent(); 5405f757f3fSDimitry Andric RISCVMachineFunctionInfo *FuncInfo = MF->getInfo<RISCVMachineFunctionInfo>(); 5415f757f3fSDimitry Andric int FI = FuncInfo->getVarArgsFrameIndex(); 5425f757f3fSDimitry Andric LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg()); 5435f757f3fSDimitry Andric auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI); 5445f757f3fSDimitry Andric assert(MI.hasOneMemOperand()); 5455f757f3fSDimitry Andric MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(), 5465f757f3fSDimitry Andric *MI.memoperands()[0]); 5475f757f3fSDimitry Andric MI.eraseFromParent(); 5485f757f3fSDimitry Andric return true; 5495f757f3fSDimitry Andric } 5505f757f3fSDimitry Andric 551*0fca6ea1SDimitry Andric bool RISCVLegalizerInfo::shouldBeInConstantPool(APInt APImm, 552*0fca6ea1SDimitry Andric bool ShouldOptForSize) const { 553*0fca6ea1SDimitry Andric assert(APImm.getBitWidth() == 32 || APImm.getBitWidth() == 64); 554*0fca6ea1SDimitry Andric int64_t Imm = APImm.getSExtValue(); 555*0fca6ea1SDimitry Andric // All simm32 constants should be handled by isel. 556*0fca6ea1SDimitry Andric // NOTE: The getMaxBuildIntsCost call below should return a value >= 2 making 557*0fca6ea1SDimitry Andric // this check redundant, but small immediates are common so this check 558*0fca6ea1SDimitry Andric // should have better compile time. 559*0fca6ea1SDimitry Andric if (isInt<32>(Imm)) 560*0fca6ea1SDimitry Andric return false; 561*0fca6ea1SDimitry Andric 562*0fca6ea1SDimitry Andric // We only need to cost the immediate, if constant pool lowering is enabled. 563*0fca6ea1SDimitry Andric if (!STI.useConstantPoolForLargeInts()) 564*0fca6ea1SDimitry Andric return false; 565*0fca6ea1SDimitry Andric 566*0fca6ea1SDimitry Andric RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(Imm, STI); 567*0fca6ea1SDimitry Andric if (Seq.size() <= STI.getMaxBuildIntsCost()) 568*0fca6ea1SDimitry Andric return false; 569*0fca6ea1SDimitry Andric 570*0fca6ea1SDimitry Andric // Optimizations below are disabled for opt size. If we're optimizing for 571*0fca6ea1SDimitry Andric // size, use a constant pool. 572*0fca6ea1SDimitry Andric if (ShouldOptForSize) 573*0fca6ea1SDimitry Andric return true; 574*0fca6ea1SDimitry Andric // 575*0fca6ea1SDimitry Andric // Special case. See if we can build the constant as (ADD (SLLI X, C), X) do 576*0fca6ea1SDimitry Andric // that if it will avoid a constant pool. 577*0fca6ea1SDimitry Andric // It will require an extra temporary register though. 578*0fca6ea1SDimitry Andric // If we have Zba we can use (ADD_UW X, (SLLI X, 32)) to handle cases where 579*0fca6ea1SDimitry Andric // low and high 32 bits are the same and bit 31 and 63 are set. 580*0fca6ea1SDimitry Andric unsigned ShiftAmt, AddOpc; 581*0fca6ea1SDimitry Andric RISCVMatInt::InstSeq SeqLo = 582*0fca6ea1SDimitry Andric RISCVMatInt::generateTwoRegInstSeq(Imm, STI, ShiftAmt, AddOpc); 583*0fca6ea1SDimitry Andric return !(!SeqLo.empty() && (SeqLo.size() + 2) <= STI.getMaxBuildIntsCost()); 584*0fca6ea1SDimitry Andric } 585*0fca6ea1SDimitry Andric 586*0fca6ea1SDimitry Andric bool RISCVLegalizerInfo::legalizeVScale(MachineInstr &MI, 587*0fca6ea1SDimitry Andric MachineIRBuilder &MIB) const { 588*0fca6ea1SDimitry Andric const LLT XLenTy(STI.getXLenVT()); 589*0fca6ea1SDimitry Andric Register Dst = MI.getOperand(0).getReg(); 590*0fca6ea1SDimitry Andric 591*0fca6ea1SDimitry Andric // We define our scalable vector types for lmul=1 to use a 64 bit known 592*0fca6ea1SDimitry Andric // minimum size. e.g. <vscale x 2 x i32>. VLENB is in bytes so we calculate 593*0fca6ea1SDimitry Andric // vscale as VLENB / 8. 594*0fca6ea1SDimitry Andric static_assert(RISCV::RVVBitsPerBlock == 64, "Unexpected bits per block!"); 595*0fca6ea1SDimitry Andric if (STI.getRealMinVLen() < RISCV::RVVBitsPerBlock) 596*0fca6ea1SDimitry Andric // Support for VLEN==32 is incomplete. 597*0fca6ea1SDimitry Andric return false; 598*0fca6ea1SDimitry Andric 599*0fca6ea1SDimitry Andric // We assume VLENB is a multiple of 8. We manually choose the best shift 600*0fca6ea1SDimitry Andric // here because SimplifyDemandedBits isn't always able to simplify it. 601*0fca6ea1SDimitry Andric uint64_t Val = MI.getOperand(1).getCImm()->getZExtValue(); 602*0fca6ea1SDimitry Andric if (isPowerOf2_64(Val)) { 603*0fca6ea1SDimitry Andric uint64_t Log2 = Log2_64(Val); 604*0fca6ea1SDimitry Andric if (Log2 < 3) { 605*0fca6ea1SDimitry Andric auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {}); 606*0fca6ea1SDimitry Andric MIB.buildLShr(Dst, VLENB, MIB.buildConstant(XLenTy, 3 - Log2)); 607*0fca6ea1SDimitry Andric } else if (Log2 > 3) { 608*0fca6ea1SDimitry Andric auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {}); 609*0fca6ea1SDimitry Andric MIB.buildShl(Dst, VLENB, MIB.buildConstant(XLenTy, Log2 - 3)); 610*0fca6ea1SDimitry Andric } else { 611*0fca6ea1SDimitry Andric MIB.buildInstr(RISCV::G_READ_VLENB, {Dst}, {}); 612*0fca6ea1SDimitry Andric } 613*0fca6ea1SDimitry Andric } else if ((Val % 8) == 0) { 614*0fca6ea1SDimitry Andric // If the multiplier is a multiple of 8, scale it down to avoid needing 615*0fca6ea1SDimitry Andric // to shift the VLENB value. 616*0fca6ea1SDimitry Andric auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {}); 617*0fca6ea1SDimitry Andric MIB.buildMul(Dst, VLENB, MIB.buildConstant(XLenTy, Val / 8)); 618*0fca6ea1SDimitry Andric } else { 619*0fca6ea1SDimitry Andric auto VLENB = MIB.buildInstr(RISCV::G_READ_VLENB, {XLenTy}, {}); 620*0fca6ea1SDimitry Andric auto VScale = MIB.buildLShr(XLenTy, VLENB, MIB.buildConstant(XLenTy, 3)); 621*0fca6ea1SDimitry Andric MIB.buildMul(Dst, VScale, MIB.buildConstant(XLenTy, Val)); 622*0fca6ea1SDimitry Andric } 623*0fca6ea1SDimitry Andric MI.eraseFromParent(); 624*0fca6ea1SDimitry Andric return true; 625*0fca6ea1SDimitry Andric } 626*0fca6ea1SDimitry Andric 627*0fca6ea1SDimitry Andric // Custom-lower extensions from mask vectors by using a vselect either with 1 628*0fca6ea1SDimitry Andric // for zero/any-extension or -1 for sign-extension: 629*0fca6ea1SDimitry Andric // (vXiN = (s|z)ext vXi1:vmask) -> (vXiN = vselect vmask, (-1 or 1), 0) 630*0fca6ea1SDimitry Andric // Note that any-extension is lowered identically to zero-extension. 631*0fca6ea1SDimitry Andric bool RISCVLegalizerInfo::legalizeExt(MachineInstr &MI, 632*0fca6ea1SDimitry Andric MachineIRBuilder &MIB) const { 633*0fca6ea1SDimitry Andric 634*0fca6ea1SDimitry Andric unsigned Opc = MI.getOpcode(); 635*0fca6ea1SDimitry Andric assert(Opc == TargetOpcode::G_ZEXT || Opc == TargetOpcode::G_SEXT || 636*0fca6ea1SDimitry Andric Opc == TargetOpcode::G_ANYEXT); 637*0fca6ea1SDimitry Andric 638*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI = *MIB.getMRI(); 639*0fca6ea1SDimitry Andric Register Dst = MI.getOperand(0).getReg(); 640*0fca6ea1SDimitry Andric Register Src = MI.getOperand(1).getReg(); 641*0fca6ea1SDimitry Andric 642*0fca6ea1SDimitry Andric LLT DstTy = MRI.getType(Dst); 643*0fca6ea1SDimitry Andric int64_t ExtTrueVal = Opc == TargetOpcode::G_SEXT ? -1 : 1; 644*0fca6ea1SDimitry Andric LLT DstEltTy = DstTy.getElementType(); 645*0fca6ea1SDimitry Andric auto SplatZero = MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, 0)); 646*0fca6ea1SDimitry Andric auto SplatTrue = 647*0fca6ea1SDimitry Andric MIB.buildSplatVector(DstTy, MIB.buildConstant(DstEltTy, ExtTrueVal)); 648*0fca6ea1SDimitry Andric MIB.buildSelect(Dst, Src, SplatTrue, SplatZero); 649*0fca6ea1SDimitry Andric 650*0fca6ea1SDimitry Andric MI.eraseFromParent(); 651*0fca6ea1SDimitry Andric return true; 652*0fca6ea1SDimitry Andric } 653*0fca6ea1SDimitry Andric 654*0fca6ea1SDimitry Andric /// Return the type of the mask type suitable for masking the provided 655*0fca6ea1SDimitry Andric /// vector type. This is simply an i1 element type vector of the same 656*0fca6ea1SDimitry Andric /// (possibly scalable) length. 657*0fca6ea1SDimitry Andric static LLT getMaskTypeFor(LLT VecTy) { 658*0fca6ea1SDimitry Andric assert(VecTy.isVector()); 659*0fca6ea1SDimitry Andric ElementCount EC = VecTy.getElementCount(); 660*0fca6ea1SDimitry Andric return LLT::vector(EC, LLT::scalar(1)); 661*0fca6ea1SDimitry Andric } 662*0fca6ea1SDimitry Andric 663*0fca6ea1SDimitry Andric /// Creates an all ones mask suitable for masking a vector of type VecTy with 664*0fca6ea1SDimitry Andric /// vector length VL. 665*0fca6ea1SDimitry Andric static MachineInstrBuilder buildAllOnesMask(LLT VecTy, const SrcOp &VL, 666*0fca6ea1SDimitry Andric MachineIRBuilder &MIB, 667*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI) { 668*0fca6ea1SDimitry Andric LLT MaskTy = getMaskTypeFor(VecTy); 669*0fca6ea1SDimitry Andric return MIB.buildInstr(RISCV::G_VMSET_VL, {MaskTy}, {VL}); 670*0fca6ea1SDimitry Andric } 671*0fca6ea1SDimitry Andric 672*0fca6ea1SDimitry Andric /// Gets the two common "VL" operands: an all-ones mask and the vector length. 673*0fca6ea1SDimitry Andric /// VecTy is a scalable vector type. 674*0fca6ea1SDimitry Andric static std::pair<MachineInstrBuilder, Register> 675*0fca6ea1SDimitry Andric buildDefaultVLOps(const DstOp &Dst, MachineIRBuilder &MIB, 676*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI) { 677*0fca6ea1SDimitry Andric LLT VecTy = Dst.getLLTTy(MRI); 678*0fca6ea1SDimitry Andric assert(VecTy.isScalableVector() && "Expecting scalable container type"); 679*0fca6ea1SDimitry Andric Register VL(RISCV::X0); 680*0fca6ea1SDimitry Andric MachineInstrBuilder Mask = buildAllOnesMask(VecTy, VL, MIB, MRI); 681*0fca6ea1SDimitry Andric return {Mask, VL}; 682*0fca6ea1SDimitry Andric } 683*0fca6ea1SDimitry Andric 684*0fca6ea1SDimitry Andric static MachineInstrBuilder 685*0fca6ea1SDimitry Andric buildSplatPartsS64WithVL(const DstOp &Dst, const SrcOp &Passthru, Register Lo, 686*0fca6ea1SDimitry Andric Register Hi, Register VL, MachineIRBuilder &MIB, 687*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI) { 688*0fca6ea1SDimitry Andric // TODO: If the Hi bits of the splat are undefined, then it's fine to just 689*0fca6ea1SDimitry Andric // splat Lo even if it might be sign extended. I don't think we have 690*0fca6ea1SDimitry Andric // introduced a case where we're build a s64 where the upper bits are undef 691*0fca6ea1SDimitry Andric // yet. 692*0fca6ea1SDimitry Andric 693*0fca6ea1SDimitry Andric // Fall back to a stack store and stride x0 vector load. 694*0fca6ea1SDimitry Andric // TODO: need to lower G_SPLAT_VECTOR_SPLIT_I64. This is done in 695*0fca6ea1SDimitry Andric // preprocessDAG in SDAG. 696*0fca6ea1SDimitry Andric return MIB.buildInstr(RISCV::G_SPLAT_VECTOR_SPLIT_I64_VL, {Dst}, 697*0fca6ea1SDimitry Andric {Passthru, Lo, Hi, VL}); 698*0fca6ea1SDimitry Andric } 699*0fca6ea1SDimitry Andric 700*0fca6ea1SDimitry Andric static MachineInstrBuilder 701*0fca6ea1SDimitry Andric buildSplatSplitS64WithVL(const DstOp &Dst, const SrcOp &Passthru, 702*0fca6ea1SDimitry Andric const SrcOp &Scalar, Register VL, 703*0fca6ea1SDimitry Andric MachineIRBuilder &MIB, MachineRegisterInfo &MRI) { 704*0fca6ea1SDimitry Andric assert(Scalar.getLLTTy(MRI) == LLT::scalar(64) && "Unexpected VecTy!"); 705*0fca6ea1SDimitry Andric auto Unmerge = MIB.buildUnmerge(LLT::scalar(32), Scalar); 706*0fca6ea1SDimitry Andric return buildSplatPartsS64WithVL(Dst, Passthru, Unmerge.getReg(0), 707*0fca6ea1SDimitry Andric Unmerge.getReg(1), VL, MIB, MRI); 708*0fca6ea1SDimitry Andric } 709*0fca6ea1SDimitry Andric 710*0fca6ea1SDimitry Andric // Lower splats of s1 types to G_ICMP. For each mask vector type, we have a 711*0fca6ea1SDimitry Andric // legal equivalently-sized i8 type, so we can use that as a go-between. 712*0fca6ea1SDimitry Andric // Splats of s1 types that have constant value can be legalized as VMSET_VL or 713*0fca6ea1SDimitry Andric // VMCLR_VL. 714*0fca6ea1SDimitry Andric bool RISCVLegalizerInfo::legalizeSplatVector(MachineInstr &MI, 715*0fca6ea1SDimitry Andric MachineIRBuilder &MIB) const { 716*0fca6ea1SDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_SPLAT_VECTOR); 717*0fca6ea1SDimitry Andric 718*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI = *MIB.getMRI(); 719*0fca6ea1SDimitry Andric 720*0fca6ea1SDimitry Andric Register Dst = MI.getOperand(0).getReg(); 721*0fca6ea1SDimitry Andric Register SplatVal = MI.getOperand(1).getReg(); 722*0fca6ea1SDimitry Andric 723*0fca6ea1SDimitry Andric LLT VecTy = MRI.getType(Dst); 724*0fca6ea1SDimitry Andric LLT XLenTy(STI.getXLenVT()); 725*0fca6ea1SDimitry Andric 726*0fca6ea1SDimitry Andric // Handle case of s64 element vectors on rv32 727*0fca6ea1SDimitry Andric if (XLenTy.getSizeInBits() == 32 && 728*0fca6ea1SDimitry Andric VecTy.getElementType().getSizeInBits() == 64) { 729*0fca6ea1SDimitry Andric auto [_, VL] = buildDefaultVLOps(Dst, MIB, MRI); 730*0fca6ea1SDimitry Andric buildSplatSplitS64WithVL(Dst, MIB.buildUndef(VecTy), SplatVal, VL, MIB, 731*0fca6ea1SDimitry Andric MRI); 732*0fca6ea1SDimitry Andric MI.eraseFromParent(); 733*0fca6ea1SDimitry Andric return true; 734*0fca6ea1SDimitry Andric } 735*0fca6ea1SDimitry Andric 736*0fca6ea1SDimitry Andric // All-zeros or all-ones splats are handled specially. 737*0fca6ea1SDimitry Andric MachineInstr &SplatValMI = *MRI.getVRegDef(SplatVal); 738*0fca6ea1SDimitry Andric if (isAllOnesOrAllOnesSplat(SplatValMI, MRI)) { 739*0fca6ea1SDimitry Andric auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second; 740*0fca6ea1SDimitry Andric MIB.buildInstr(RISCV::G_VMSET_VL, {Dst}, {VL}); 741*0fca6ea1SDimitry Andric MI.eraseFromParent(); 742*0fca6ea1SDimitry Andric return true; 743*0fca6ea1SDimitry Andric } 744*0fca6ea1SDimitry Andric if (isNullOrNullSplat(SplatValMI, MRI)) { 745*0fca6ea1SDimitry Andric auto VL = buildDefaultVLOps(VecTy, MIB, MRI).second; 746*0fca6ea1SDimitry Andric MIB.buildInstr(RISCV::G_VMCLR_VL, {Dst}, {VL}); 747*0fca6ea1SDimitry Andric MI.eraseFromParent(); 748*0fca6ea1SDimitry Andric return true; 749*0fca6ea1SDimitry Andric } 750*0fca6ea1SDimitry Andric 751*0fca6ea1SDimitry Andric // Handle non-constant mask splat (i.e. not sure if it's all zeros or all 752*0fca6ea1SDimitry Andric // ones) by promoting it to an s8 splat. 753*0fca6ea1SDimitry Andric LLT InterEltTy = LLT::scalar(8); 754*0fca6ea1SDimitry Andric LLT InterTy = VecTy.changeElementType(InterEltTy); 755*0fca6ea1SDimitry Andric auto ZExtSplatVal = MIB.buildZExt(InterEltTy, SplatVal); 756*0fca6ea1SDimitry Andric auto And = 757*0fca6ea1SDimitry Andric MIB.buildAnd(InterEltTy, ZExtSplatVal, MIB.buildConstant(InterEltTy, 1)); 758*0fca6ea1SDimitry Andric auto LHS = MIB.buildSplatVector(InterTy, And); 759*0fca6ea1SDimitry Andric auto ZeroSplat = 760*0fca6ea1SDimitry Andric MIB.buildSplatVector(InterTy, MIB.buildConstant(InterEltTy, 0)); 761*0fca6ea1SDimitry Andric MIB.buildICmp(CmpInst::Predicate::ICMP_NE, Dst, LHS, ZeroSplat); 762*0fca6ea1SDimitry Andric MI.eraseFromParent(); 763*0fca6ea1SDimitry Andric return true; 764*0fca6ea1SDimitry Andric } 765*0fca6ea1SDimitry Andric 7661db9f3b2SDimitry Andric bool RISCVLegalizerInfo::legalizeCustom( 7671db9f3b2SDimitry Andric LegalizerHelper &Helper, MachineInstr &MI, 7681db9f3b2SDimitry Andric LostDebugLocObserver &LocObserver) const { 7695f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 7705f757f3fSDimitry Andric GISelChangeObserver &Observer = Helper.Observer; 771*0fca6ea1SDimitry Andric MachineFunction &MF = *MI.getParent()->getParent(); 7725f757f3fSDimitry Andric switch (MI.getOpcode()) { 7735f757f3fSDimitry Andric default: 7745f757f3fSDimitry Andric // No idea what to do. 7755f757f3fSDimitry Andric return false; 7765f757f3fSDimitry Andric case TargetOpcode::G_ABS: 7775f757f3fSDimitry Andric return Helper.lowerAbsToMaxNeg(MI); 778*0fca6ea1SDimitry Andric // TODO: G_FCONSTANT 779*0fca6ea1SDimitry Andric case TargetOpcode::G_CONSTANT: { 780*0fca6ea1SDimitry Andric const Function &F = MF.getFunction(); 781*0fca6ea1SDimitry Andric // TODO: if PSI and BFI are present, add " || 782*0fca6ea1SDimitry Andric // llvm::shouldOptForSize(*CurMBB, PSI, BFI)". 783*0fca6ea1SDimitry Andric bool ShouldOptForSize = F.hasOptSize() || F.hasMinSize(); 784*0fca6ea1SDimitry Andric const ConstantInt *ConstVal = MI.getOperand(1).getCImm(); 785*0fca6ea1SDimitry Andric if (!shouldBeInConstantPool(ConstVal->getValue(), ShouldOptForSize)) 786*0fca6ea1SDimitry Andric return true; 787*0fca6ea1SDimitry Andric return Helper.lowerConstant(MI); 788*0fca6ea1SDimitry Andric } 7895f757f3fSDimitry Andric case TargetOpcode::G_SHL: 7905f757f3fSDimitry Andric case TargetOpcode::G_ASHR: 7915f757f3fSDimitry Andric case TargetOpcode::G_LSHR: 7925f757f3fSDimitry Andric return legalizeShlAshrLshr(MI, MIRBuilder, Observer); 7935f757f3fSDimitry Andric case TargetOpcode::G_SEXT_INREG: { 7945f757f3fSDimitry Andric // Source size of 32 is sext.w. 7955f757f3fSDimitry Andric int64_t SizeInBits = MI.getOperand(2).getImm(); 7965f757f3fSDimitry Andric if (SizeInBits == 32) 7975f757f3fSDimitry Andric return true; 7985f757f3fSDimitry Andric 7995f757f3fSDimitry Andric return Helper.lower(MI, 0, /* Unused hint type */ LLT()) == 8005f757f3fSDimitry Andric LegalizerHelper::Legalized; 8015f757f3fSDimitry Andric } 8025f757f3fSDimitry Andric case TargetOpcode::G_IS_FPCLASS: { 8035f757f3fSDimitry Andric Register GISFPCLASS = MI.getOperand(0).getReg(); 8045f757f3fSDimitry Andric Register Src = MI.getOperand(1).getReg(); 8055f757f3fSDimitry Andric const MachineOperand &ImmOp = MI.getOperand(2); 8065f757f3fSDimitry Andric MachineIRBuilder MIB(MI); 8075f757f3fSDimitry Andric 8085f757f3fSDimitry Andric // Turn LLVM IR's floating point classes to that in RISC-V, 8095f757f3fSDimitry Andric // by simply rotating the 10-bit immediate right by two bits. 8105f757f3fSDimitry Andric APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm())); 8115f757f3fSDimitry Andric auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen)); 8125f757f3fSDimitry Andric auto ConstZero = MIB.buildConstant(sXLen, 0); 8135f757f3fSDimitry Andric 8145f757f3fSDimitry Andric auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src}); 8155f757f3fSDimitry Andric auto And = MIB.buildAnd(sXLen, GFClass, FClassMask); 8165f757f3fSDimitry Andric MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero); 8175f757f3fSDimitry Andric 8185f757f3fSDimitry Andric MI.eraseFromParent(); 8195f757f3fSDimitry Andric return true; 8205f757f3fSDimitry Andric } 8215f757f3fSDimitry Andric case TargetOpcode::G_VASTART: 8225f757f3fSDimitry Andric return legalizeVAStart(MI, MIRBuilder); 823*0fca6ea1SDimitry Andric case TargetOpcode::G_VSCALE: 824*0fca6ea1SDimitry Andric return legalizeVScale(MI, MIRBuilder); 825*0fca6ea1SDimitry Andric case TargetOpcode::G_ZEXT: 826*0fca6ea1SDimitry Andric case TargetOpcode::G_SEXT: 827*0fca6ea1SDimitry Andric case TargetOpcode::G_ANYEXT: 828*0fca6ea1SDimitry Andric return legalizeExt(MI, MIRBuilder); 829*0fca6ea1SDimitry Andric case TargetOpcode::G_SPLAT_VECTOR: 830*0fca6ea1SDimitry Andric return legalizeSplatVector(MI, MIRBuilder); 8315f757f3fSDimitry Andric } 8325f757f3fSDimitry Andric 8335f757f3fSDimitry Andric llvm_unreachable("expected switch to return"); 8345f757f3fSDimitry Andric } 835