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" 145f757f3fSDimitry Andric #include "RISCVMachineFunctionInfo.h" 1506c3fb27SDimitry Andric #include "RISCVSubtarget.h" 165f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 175f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 185f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 195f757f3fSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 20bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 21bdd1243dSDimitry Andric #include "llvm/CodeGen/ValueTypes.h" 22bdd1243dSDimitry Andric #include "llvm/IR/DerivedTypes.h" 23bdd1243dSDimitry Andric #include "llvm/IR/Type.h" 24bdd1243dSDimitry Andric 25bdd1243dSDimitry Andric using namespace llvm; 265f757f3fSDimitry Andric using namespace LegalityPredicates; 275f757f3fSDimitry Andric using namespace LegalizeMutations; 28bdd1243dSDimitry Andric 295f757f3fSDimitry Andric // Is this type supported by scalar FP arithmetic operations given the current 305f757f3fSDimitry Andric // subtarget. 315f757f3fSDimitry Andric static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx, 325f757f3fSDimitry Andric const RISCVSubtarget &ST) { 335f757f3fSDimitry Andric return [=, &ST](const LegalityQuery &Query) { 345f757f3fSDimitry Andric return Query.Types[TypeIdx].isScalar() && 355f757f3fSDimitry Andric ((ST.hasStdExtF() && Query.Types[TypeIdx].getSizeInBits() == 32) || 365f757f3fSDimitry Andric (ST.hasStdExtD() && Query.Types[TypeIdx].getSizeInBits() == 64)); 375f757f3fSDimitry Andric }; 385f757f3fSDimitry Andric } 395f757f3fSDimitry Andric 405f757f3fSDimitry Andric RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) 415f757f3fSDimitry Andric : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) { 425f757f3fSDimitry Andric const LLT sDoubleXLen = LLT::scalar(2 * XLen); 435f757f3fSDimitry Andric const LLT p0 = LLT::pointer(0, XLen); 445f757f3fSDimitry Andric const LLT s1 = LLT::scalar(1); 455f757f3fSDimitry Andric const LLT s8 = LLT::scalar(8); 465f757f3fSDimitry Andric const LLT s16 = LLT::scalar(16); 475f757f3fSDimitry Andric const LLT s32 = LLT::scalar(32); 485f757f3fSDimitry Andric const LLT s64 = LLT::scalar(64); 4906c3fb27SDimitry Andric 5006c3fb27SDimitry Andric using namespace TargetOpcode; 5106c3fb27SDimitry Andric 5206c3fb27SDimitry Andric getActionDefinitionsBuilder({G_ADD, G_SUB, G_AND, G_OR, G_XOR}) 535f757f3fSDimitry Andric .legalFor({s32, sXLen}) 545f757f3fSDimitry Andric .widenScalarToNextPow2(0) 555f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 565f757f3fSDimitry Andric 575f757f3fSDimitry Andric getActionDefinitionsBuilder( 585f757f3fSDimitry Andric {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower(); 595f757f3fSDimitry Andric 605f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower(); 615f757f3fSDimitry Andric 625f757f3fSDimitry Andric auto &ShiftActions = getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL}); 635f757f3fSDimitry Andric if (ST.is64Bit()) 645f757f3fSDimitry Andric ShiftActions.customFor({{s32, s32}}); 655f757f3fSDimitry Andric ShiftActions.legalFor({{s32, s32}, {s32, sXLen}, {sXLen, sXLen}}) 665f757f3fSDimitry Andric .widenScalarToNextPow2(0) 675f757f3fSDimitry Andric .clampScalar(1, s32, sXLen) 685f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 695f757f3fSDimitry Andric .minScalarSameAs(1, 0); 705f757f3fSDimitry Andric 715f757f3fSDimitry Andric if (ST.is64Bit()) { 725f757f3fSDimitry Andric getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}) 735f757f3fSDimitry Andric .legalFor({{sXLen, s32}}) 745f757f3fSDimitry Andric .maxScalar(0, sXLen); 755f757f3fSDimitry Andric 765f757f3fSDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG) 775f757f3fSDimitry Andric .customFor({sXLen}) 785f757f3fSDimitry Andric .maxScalar(0, sXLen) 795f757f3fSDimitry Andric .lower(); 805f757f3fSDimitry Andric } else { 815f757f3fSDimitry Andric getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}).maxScalar(0, sXLen); 825f757f3fSDimitry Andric 835f757f3fSDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG).maxScalar(0, sXLen).lower(); 845f757f3fSDimitry Andric } 855f757f3fSDimitry Andric 865f757f3fSDimitry Andric // Merge/Unmerge 875f757f3fSDimitry Andric for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) { 88cb14a3feSDimitry Andric auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op); 895f757f3fSDimitry Andric unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1; 905f757f3fSDimitry Andric unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0; 915f757f3fSDimitry Andric if (XLen == 32 && ST.hasStdExtD()) { 92cb14a3feSDimitry Andric MergeUnmergeActions.legalIf( 93cb14a3feSDimitry Andric all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32))); 945f757f3fSDimitry Andric } 955f757f3fSDimitry Andric MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen) 965f757f3fSDimitry Andric .widenScalarToNextPow2(BigTyIdx, XLen) 975f757f3fSDimitry Andric .clampScalar(LitTyIdx, sXLen, sXLen) 985f757f3fSDimitry Andric .clampScalar(BigTyIdx, sXLen, sXLen); 995f757f3fSDimitry Andric } 1005f757f3fSDimitry Andric 1015f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower(); 1025f757f3fSDimitry Andric 1035f757f3fSDimitry Andric auto &RotateActions = getActionDefinitionsBuilder({G_ROTL, G_ROTR}); 104*647cbc5dSDimitry Andric if (ST.hasStdExtZbb() || ST.hasStdExtZbkb()) { 1055f757f3fSDimitry Andric RotateActions.legalFor({{s32, sXLen}, {sXLen, sXLen}}); 1065f757f3fSDimitry Andric // Widen s32 rotate amount to s64 so SDAG patterns will match. 1075f757f3fSDimitry Andric if (ST.is64Bit()) 1085f757f3fSDimitry Andric RotateActions.widenScalarIf(all(typeIs(0, s32), typeIs(1, s32)), 1095f757f3fSDimitry Andric changeTo(1, sXLen)); 1105f757f3fSDimitry Andric } 1115f757f3fSDimitry Andric RotateActions.lower(); 1125f757f3fSDimitry Andric 1135f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BITREVERSE).maxScalar(0, sXLen).lower(); 1145f757f3fSDimitry Andric 1155f757f3fSDimitry Andric auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP); 1165f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 1175f757f3fSDimitry Andric BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen); 1185f757f3fSDimitry Andric else 1195f757f3fSDimitry Andric BSWAPActions.maxScalar(0, sXLen).lower(); 1205f757f3fSDimitry Andric 1215f757f3fSDimitry Andric auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ}); 1225f757f3fSDimitry Andric auto &CountZerosUndefActions = 1235f757f3fSDimitry Andric getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF}); 1245f757f3fSDimitry Andric if (ST.hasStdExtZbb()) { 1255f757f3fSDimitry Andric CountZerosActions.legalFor({{s32, s32}, {sXLen, sXLen}}) 1265f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 1275f757f3fSDimitry Andric .widenScalarToNextPow2(0) 1285f757f3fSDimitry Andric .scalarSameSizeAs(1, 0); 1295f757f3fSDimitry Andric } else { 1305f757f3fSDimitry Andric CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower(); 1315f757f3fSDimitry Andric CountZerosUndefActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0); 1325f757f3fSDimitry Andric } 1335f757f3fSDimitry Andric CountZerosUndefActions.lower(); 1345f757f3fSDimitry Andric 1355f757f3fSDimitry Andric auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP); 1365f757f3fSDimitry Andric if (ST.hasStdExtZbb()) { 1375f757f3fSDimitry Andric CTPOPActions.legalFor({{s32, s32}, {sXLen, sXLen}}) 1385f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 1395f757f3fSDimitry Andric .widenScalarToNextPow2(0) 1405f757f3fSDimitry Andric .scalarSameSizeAs(1, 0); 1415f757f3fSDimitry Andric } else { 1425f757f3fSDimitry Andric CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower(); 1435f757f3fSDimitry Andric } 1445f757f3fSDimitry Andric 1455f757f3fSDimitry Andric getActionDefinitionsBuilder({G_CONSTANT, G_IMPLICIT_DEF}) 1465f757f3fSDimitry Andric .legalFor({s32, sXLen, p0}) 1475f757f3fSDimitry Andric .widenScalarToNextPow2(0) 1485f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 1495f757f3fSDimitry Andric 1505f757f3fSDimitry Andric getActionDefinitionsBuilder(G_ICMP) 1515f757f3fSDimitry Andric .legalFor({{sXLen, sXLen}, {sXLen, p0}}) 1525f757f3fSDimitry Andric .widenScalarToNextPow2(1) 1535f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen) 1545f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 1555f757f3fSDimitry Andric 1565f757f3fSDimitry Andric auto &SelectActions = getActionDefinitionsBuilder(G_SELECT).legalFor( 1575f757f3fSDimitry Andric {{s32, sXLen}, {p0, sXLen}}); 1585f757f3fSDimitry Andric if (XLen == 64 || ST.hasStdExtD()) 1595f757f3fSDimitry Andric SelectActions.legalFor({{s64, sXLen}}); 1605f757f3fSDimitry Andric SelectActions.widenScalarToNextPow2(0) 1615f757f3fSDimitry Andric .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32) 1625f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen); 1635f757f3fSDimitry Andric 1645f757f3fSDimitry Andric auto &LoadStoreActions = 1655f757f3fSDimitry Andric getActionDefinitionsBuilder({G_LOAD, G_STORE}) 1665f757f3fSDimitry Andric .legalForTypesWithMemDesc({{s32, p0, s8, 8}, 1675f757f3fSDimitry Andric {s32, p0, s16, 16}, 1685f757f3fSDimitry Andric {s32, p0, s32, 32}, 1695f757f3fSDimitry Andric {p0, p0, sXLen, XLen}}); 1705f757f3fSDimitry Andric auto &ExtLoadActions = 1715f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD}) 1725f757f3fSDimitry Andric .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}}); 1735f757f3fSDimitry Andric if (XLen == 64) { 1745f757f3fSDimitry Andric LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s8, 8}, 1755f757f3fSDimitry Andric {s64, p0, s16, 16}, 1765f757f3fSDimitry Andric {s64, p0, s32, 32}, 1775f757f3fSDimitry Andric {s64, p0, s64, 64}}); 1785f757f3fSDimitry Andric ExtLoadActions.legalForTypesWithMemDesc( 1795f757f3fSDimitry Andric {{s64, p0, s8, 8}, {s64, p0, s16, 16}, {s64, p0, s32, 32}}); 1805f757f3fSDimitry Andric } else if (ST.hasStdExtD()) { 1815f757f3fSDimitry Andric LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}}); 1825f757f3fSDimitry Andric } 1835f757f3fSDimitry Andric LoadStoreActions.clampScalar(0, s32, sXLen).lower(); 1845f757f3fSDimitry Andric ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower(); 1855f757f3fSDimitry Andric 1865f757f3fSDimitry Andric getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}}); 1875f757f3fSDimitry Andric 1885f757f3fSDimitry Andric getActionDefinitionsBuilder(G_PTRTOINT) 1895f757f3fSDimitry Andric .legalFor({{sXLen, p0}}) 1905f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 1915f757f3fSDimitry Andric 1925f757f3fSDimitry Andric getActionDefinitionsBuilder(G_INTTOPTR) 1935f757f3fSDimitry Andric .legalFor({{p0, sXLen}}) 1945f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen); 1955f757f3fSDimitry Andric 1965f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen); 1975f757f3fSDimitry Andric 1985f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}}); 1995f757f3fSDimitry Andric 2005f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0}); 2015f757f3fSDimitry Andric 2025f757f3fSDimitry Andric getActionDefinitionsBuilder(G_PHI) 2035f757f3fSDimitry Andric .legalFor({p0, sXLen}) 2045f757f3fSDimitry Andric .widenScalarToNextPow2(0) 2055f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 2065f757f3fSDimitry Andric 2075f757f3fSDimitry Andric getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL}) 2085f757f3fSDimitry Andric .legalFor({p0}); 2095f757f3fSDimitry Andric 2105f757f3fSDimitry Andric if (ST.hasStdExtM() || ST.hasStdExtZmmul()) { 2115f757f3fSDimitry Andric getActionDefinitionsBuilder(G_MUL) 2125f757f3fSDimitry Andric .legalFor({s32, sXLen}) 2135f757f3fSDimitry Andric .widenScalarToNextPow2(0) 2145f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 2155f757f3fSDimitry Andric 2165f757f3fSDimitry Andric // clang-format off 2175f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULH, G_UMULH}) 2185f757f3fSDimitry Andric .legalFor({sXLen}) 2195f757f3fSDimitry Andric .lower(); 2205f757f3fSDimitry Andric // clang-format on 2215f757f3fSDimitry Andric 2225f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower(); 2235f757f3fSDimitry Andric } else { 2245f757f3fSDimitry Andric getActionDefinitionsBuilder(G_MUL) 2255f757f3fSDimitry Andric .libcallFor({sXLen, sDoubleXLen}) 2265f757f3fSDimitry Andric .widenScalarToNextPow2(0) 2275f757f3fSDimitry Andric .clampScalar(0, sXLen, sDoubleXLen); 2285f757f3fSDimitry Andric 2295f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen}); 2305f757f3fSDimitry Andric 2315f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULO, G_UMULO}) 2325f757f3fSDimitry Andric .minScalar(0, sXLen) 2335f757f3fSDimitry Andric // Widen sXLen to sDoubleXLen so we can use a single libcall to get 2345f757f3fSDimitry Andric // the low bits for the mul result and high bits to do the overflow 2355f757f3fSDimitry Andric // check. 2365f757f3fSDimitry Andric .widenScalarIf(typeIs(0, sXLen), 2375f757f3fSDimitry Andric LegalizeMutations::changeTo(0, sDoubleXLen)) 2385f757f3fSDimitry Andric .lower(); 2395f757f3fSDimitry Andric } 2405f757f3fSDimitry Andric 2415f757f3fSDimitry Andric if (ST.hasStdExtM()) { 2425f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM}) 2435f757f3fSDimitry Andric .legalFor({s32, sXLen}) 2445f757f3fSDimitry Andric .libcallFor({sDoubleXLen}) 2455f757f3fSDimitry Andric .clampScalar(0, s32, sDoubleXLen) 2465f757f3fSDimitry Andric .widenScalarToNextPow2(0); 2475f757f3fSDimitry Andric } else { 2485f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM}) 2495f757f3fSDimitry Andric .libcallFor({sXLen, sDoubleXLen}) 2505f757f3fSDimitry Andric .clampScalar(0, sXLen, sDoubleXLen) 2515f757f3fSDimitry Andric .widenScalarToNextPow2(0); 2525f757f3fSDimitry Andric } 2535f757f3fSDimitry Andric 2545f757f3fSDimitry Andric auto &AbsActions = getActionDefinitionsBuilder(G_ABS); 2555f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 2565f757f3fSDimitry Andric AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen); 2575f757f3fSDimitry Andric AbsActions.lower(); 2585f757f3fSDimitry Andric 2595f757f3fSDimitry Andric auto &MinMaxActions = 2605f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN}); 2615f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 2625f757f3fSDimitry Andric MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen); 2635f757f3fSDimitry Andric MinMaxActions.lower(); 2645f757f3fSDimitry Andric 2655f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0}); 2665f757f3fSDimitry Andric 2675f757f3fSDimitry Andric getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall(); 2685f757f3fSDimitry Andric 2695f757f3fSDimitry Andric getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower(); 2705f757f3fSDimitry Andric 2715f757f3fSDimitry Andric // FP Operations 2725f757f3fSDimitry Andric 2735f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG, 2745f757f3fSDimitry Andric G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM}) 2755f757f3fSDimitry Andric .legalIf(typeIsScalarFPArith(0, ST)); 2765f757f3fSDimitry Andric 2775f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCOPYSIGN) 2785f757f3fSDimitry Andric .legalIf(all(typeIsScalarFPArith(0, ST), typeIsScalarFPArith(1, ST))); 2795f757f3fSDimitry Andric 2805f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FPTRUNC).legalIf( 2815f757f3fSDimitry Andric [=, &ST](const LegalityQuery &Query) -> bool { 2825f757f3fSDimitry Andric return (ST.hasStdExtD() && typeIs(0, s32)(Query) && 2835f757f3fSDimitry Andric typeIs(1, s64)(Query)); 2845f757f3fSDimitry Andric }); 2855f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FPEXT).legalIf( 2865f757f3fSDimitry Andric [=, &ST](const LegalityQuery &Query) -> bool { 2875f757f3fSDimitry Andric return (ST.hasStdExtD() && typeIs(0, s64)(Query) && 2885f757f3fSDimitry Andric typeIs(1, s32)(Query)); 2895f757f3fSDimitry Andric }); 2905f757f3fSDimitry Andric 2915f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCMP) 2925f757f3fSDimitry Andric .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST))) 2935f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 2945f757f3fSDimitry Andric 2955f757f3fSDimitry Andric // TODO: Support vector version of G_IS_FPCLASS. 2965f757f3fSDimitry Andric getActionDefinitionsBuilder(G_IS_FPCLASS) 2975f757f3fSDimitry Andric .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST))); 2985f757f3fSDimitry Andric 2995f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCONSTANT) 3005f757f3fSDimitry Andric .legalIf(typeIsScalarFPArith(0, ST)) 3015f757f3fSDimitry Andric .lowerFor({s32, s64}); 3025f757f3fSDimitry Andric 3035f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 3045f757f3fSDimitry Andric .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST))) 3055f757f3fSDimitry Andric .widenScalarToNextPow2(0) 3065f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 3075f757f3fSDimitry Andric 3085f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) 3095f757f3fSDimitry Andric .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen}))) 3105f757f3fSDimitry Andric .widenScalarToNextPow2(1) 3115f757f3fSDimitry Andric .clampScalar(1, s32, sXLen); 3125f757f3fSDimitry Andric 3135f757f3fSDimitry Andric // FIXME: We can do custom inline expansion like SelectionDAG. 3145f757f3fSDimitry Andric // FIXME: Legal with Zfa. 3155f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR}) 3165f757f3fSDimitry Andric .libcallFor({s32, s64}); 3175f757f3fSDimitry Andric 3185f757f3fSDimitry Andric getActionDefinitionsBuilder(G_VASTART).customFor({p0}); 3195f757f3fSDimitry Andric 3205f757f3fSDimitry Andric // va_list must be a pointer, but most sized types are pretty easy to handle 3215f757f3fSDimitry Andric // as the destination. 3225f757f3fSDimitry Andric getActionDefinitionsBuilder(G_VAARG) 3235f757f3fSDimitry Andric // TODO: Implement narrowScalar and widenScalar for G_VAARG for types 3245f757f3fSDimitry Andric // outside the [s32, sXLen] range. 3255f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 3265f757f3fSDimitry Andric .lowerForCartesianProduct({s32, sXLen, p0}, {p0}); 32706c3fb27SDimitry Andric 328bdd1243dSDimitry Andric getLegacyLegalizerInfo().computeTables(); 329bdd1243dSDimitry Andric } 3305f757f3fSDimitry Andric 3315f757f3fSDimitry Andric static Type *getTypeForLLT(LLT Ty, LLVMContext &C) { 3325f757f3fSDimitry Andric if (Ty.isVector()) 3335f757f3fSDimitry Andric return FixedVectorType::get(IntegerType::get(C, Ty.getScalarSizeInBits()), 3345f757f3fSDimitry Andric Ty.getNumElements()); 3355f757f3fSDimitry Andric return IntegerType::get(C, Ty.getSizeInBits()); 3365f757f3fSDimitry Andric } 3375f757f3fSDimitry Andric 3385f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, 3395f757f3fSDimitry Andric MachineInstr &MI) const { 3405f757f3fSDimitry Andric Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID(); 3415f757f3fSDimitry Andric switch (IntrinsicID) { 3425f757f3fSDimitry Andric default: 3435f757f3fSDimitry Andric return false; 3445f757f3fSDimitry Andric case Intrinsic::vacopy: { 3455f757f3fSDimitry Andric // vacopy arguments must be legal because of the intrinsic signature. 3465f757f3fSDimitry Andric // No need to check here. 3475f757f3fSDimitry Andric 3485f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 3495f757f3fSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 3505f757f3fSDimitry Andric MachineFunction &MF = *MI.getMF(); 3515f757f3fSDimitry Andric const DataLayout &DL = MIRBuilder.getDataLayout(); 3525f757f3fSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 3535f757f3fSDimitry Andric 3545f757f3fSDimitry Andric Register DstLst = MI.getOperand(1).getReg(); 3555f757f3fSDimitry Andric LLT PtrTy = MRI.getType(DstLst); 3565f757f3fSDimitry Andric 3575f757f3fSDimitry Andric // Load the source va_list 3585f757f3fSDimitry Andric Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx)); 3595f757f3fSDimitry Andric MachineMemOperand *LoadMMO = MF.getMachineMemOperand( 3605f757f3fSDimitry Andric MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment); 3615f757f3fSDimitry Andric auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO); 3625f757f3fSDimitry Andric 3635f757f3fSDimitry Andric // Store the result in the destination va_list 3645f757f3fSDimitry Andric MachineMemOperand *StoreMMO = MF.getMachineMemOperand( 3655f757f3fSDimitry Andric MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, Alignment); 3665f757f3fSDimitry Andric MIRBuilder.buildStore(DstLst, Tmp, *StoreMMO); 3675f757f3fSDimitry Andric 3685f757f3fSDimitry Andric MI.eraseFromParent(); 3695f757f3fSDimitry Andric return true; 3705f757f3fSDimitry Andric } 3715f757f3fSDimitry Andric } 3725f757f3fSDimitry Andric } 3735f757f3fSDimitry Andric 3745f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeShlAshrLshr( 3755f757f3fSDimitry Andric MachineInstr &MI, MachineIRBuilder &MIRBuilder, 3765f757f3fSDimitry Andric GISelChangeObserver &Observer) const { 3775f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_ASHR || 3785f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_LSHR || 3795f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_SHL); 3805f757f3fSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 3815f757f3fSDimitry Andric // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the 3825f757f3fSDimitry Andric // imported patterns can select it later. Either way, it will be legal. 3835f757f3fSDimitry Andric Register AmtReg = MI.getOperand(2).getReg(); 3845f757f3fSDimitry Andric auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI); 3855f757f3fSDimitry Andric if (!VRegAndVal) 3865f757f3fSDimitry Andric return true; 3875f757f3fSDimitry Andric // Check the shift amount is in range for an immediate form. 3885f757f3fSDimitry Andric uint64_t Amount = VRegAndVal->Value.getZExtValue(); 3895f757f3fSDimitry Andric if (Amount > 31) 3905f757f3fSDimitry Andric return true; // This will have to remain a register variant. 3915f757f3fSDimitry Andric auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount); 3925f757f3fSDimitry Andric Observer.changingInstr(MI); 3935f757f3fSDimitry Andric MI.getOperand(2).setReg(ExtCst.getReg(0)); 3945f757f3fSDimitry Andric Observer.changedInstr(MI); 3955f757f3fSDimitry Andric return true; 3965f757f3fSDimitry Andric } 3975f757f3fSDimitry Andric 3985f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI, 3995f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder) const { 4005f757f3fSDimitry Andric // Stores the address of the VarArgsFrameIndex slot into the memory location 4015f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_VASTART); 4025f757f3fSDimitry Andric MachineFunction *MF = MI.getParent()->getParent(); 4035f757f3fSDimitry Andric RISCVMachineFunctionInfo *FuncInfo = MF->getInfo<RISCVMachineFunctionInfo>(); 4045f757f3fSDimitry Andric int FI = FuncInfo->getVarArgsFrameIndex(); 4055f757f3fSDimitry Andric LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg()); 4065f757f3fSDimitry Andric auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI); 4075f757f3fSDimitry Andric assert(MI.hasOneMemOperand()); 4085f757f3fSDimitry Andric MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(), 4095f757f3fSDimitry Andric *MI.memoperands()[0]); 4105f757f3fSDimitry Andric MI.eraseFromParent(); 4115f757f3fSDimitry Andric return true; 4125f757f3fSDimitry Andric } 4135f757f3fSDimitry Andric 4145f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, 4155f757f3fSDimitry Andric MachineInstr &MI) const { 4165f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 4175f757f3fSDimitry Andric GISelChangeObserver &Observer = Helper.Observer; 4185f757f3fSDimitry Andric switch (MI.getOpcode()) { 4195f757f3fSDimitry Andric default: 4205f757f3fSDimitry Andric // No idea what to do. 4215f757f3fSDimitry Andric return false; 4225f757f3fSDimitry Andric case TargetOpcode::G_ABS: 4235f757f3fSDimitry Andric return Helper.lowerAbsToMaxNeg(MI); 4245f757f3fSDimitry Andric case TargetOpcode::G_SHL: 4255f757f3fSDimitry Andric case TargetOpcode::G_ASHR: 4265f757f3fSDimitry Andric case TargetOpcode::G_LSHR: 4275f757f3fSDimitry Andric return legalizeShlAshrLshr(MI, MIRBuilder, Observer); 4285f757f3fSDimitry Andric case TargetOpcode::G_SEXT_INREG: { 4295f757f3fSDimitry Andric // Source size of 32 is sext.w. 4305f757f3fSDimitry Andric int64_t SizeInBits = MI.getOperand(2).getImm(); 4315f757f3fSDimitry Andric if (SizeInBits == 32) 4325f757f3fSDimitry Andric return true; 4335f757f3fSDimitry Andric 4345f757f3fSDimitry Andric return Helper.lower(MI, 0, /* Unused hint type */ LLT()) == 4355f757f3fSDimitry Andric LegalizerHelper::Legalized; 4365f757f3fSDimitry Andric } 4375f757f3fSDimitry Andric case TargetOpcode::G_IS_FPCLASS: { 4385f757f3fSDimitry Andric Register GISFPCLASS = MI.getOperand(0).getReg(); 4395f757f3fSDimitry Andric Register Src = MI.getOperand(1).getReg(); 4405f757f3fSDimitry Andric const MachineOperand &ImmOp = MI.getOperand(2); 4415f757f3fSDimitry Andric MachineIRBuilder MIB(MI); 4425f757f3fSDimitry Andric 4435f757f3fSDimitry Andric // Turn LLVM IR's floating point classes to that in RISC-V, 4445f757f3fSDimitry Andric // by simply rotating the 10-bit immediate right by two bits. 4455f757f3fSDimitry Andric APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm())); 4465f757f3fSDimitry Andric auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen)); 4475f757f3fSDimitry Andric auto ConstZero = MIB.buildConstant(sXLen, 0); 4485f757f3fSDimitry Andric 4495f757f3fSDimitry Andric auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src}); 4505f757f3fSDimitry Andric auto And = MIB.buildAnd(sXLen, GFClass, FClassMask); 4515f757f3fSDimitry Andric MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero); 4525f757f3fSDimitry Andric 4535f757f3fSDimitry Andric MI.eraseFromParent(); 4545f757f3fSDimitry Andric return true; 4555f757f3fSDimitry Andric } 4565f757f3fSDimitry Andric case TargetOpcode::G_VASTART: 4575f757f3fSDimitry Andric return legalizeVAStart(MI, MIRBuilder); 4585f757f3fSDimitry Andric } 4595f757f3fSDimitry Andric 4605f757f3fSDimitry Andric llvm_unreachable("expected switch to return"); 4615f757f3fSDimitry Andric } 462