xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp (revision 647cbc5de815c5651677bf8582797f716ec7b48d)
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