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.
typeIsScalarFPArith(unsigned TypeIdx,const RISCVSubtarget & ST)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 
RISCVLegalizerInfo(const RISCVSubtarget & ST)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 
50*297eecfbSDimitry Andric   const LLT nxv1s8 = LLT::scalable_vector(1, s8);
51*297eecfbSDimitry Andric   const LLT nxv2s8 = LLT::scalable_vector(2, s8);
52*297eecfbSDimitry Andric   const LLT nxv4s8 = LLT::scalable_vector(4, s8);
53*297eecfbSDimitry Andric   const LLT nxv8s8 = LLT::scalable_vector(8, s8);
54*297eecfbSDimitry Andric   const LLT nxv16s8 = LLT::scalable_vector(16, s8);
55*297eecfbSDimitry Andric   const LLT nxv32s8 = LLT::scalable_vector(32, s8);
56*297eecfbSDimitry Andric   const LLT nxv64s8 = LLT::scalable_vector(64, s8);
57*297eecfbSDimitry Andric 
58*297eecfbSDimitry Andric   const LLT nxv1s16 = LLT::scalable_vector(1, s16);
59*297eecfbSDimitry Andric   const LLT nxv2s16 = LLT::scalable_vector(2, s16);
60*297eecfbSDimitry Andric   const LLT nxv4s16 = LLT::scalable_vector(4, s16);
61*297eecfbSDimitry Andric   const LLT nxv8s16 = LLT::scalable_vector(8, s16);
62*297eecfbSDimitry Andric   const LLT nxv16s16 = LLT::scalable_vector(16, s16);
63*297eecfbSDimitry Andric   const LLT nxv32s16 = LLT::scalable_vector(32, s16);
64*297eecfbSDimitry Andric 
65*297eecfbSDimitry Andric   const LLT nxv1s32 = LLT::scalable_vector(1, s32);
66*297eecfbSDimitry Andric   const LLT nxv2s32 = LLT::scalable_vector(2, s32);
67*297eecfbSDimitry Andric   const LLT nxv4s32 = LLT::scalable_vector(4, s32);
68*297eecfbSDimitry Andric   const LLT nxv8s32 = LLT::scalable_vector(8, s32);
69*297eecfbSDimitry Andric   const LLT nxv16s32 = LLT::scalable_vector(16, s32);
70*297eecfbSDimitry Andric 
71*297eecfbSDimitry Andric   const LLT nxv1s64 = LLT::scalable_vector(1, s64);
72*297eecfbSDimitry Andric   const LLT nxv2s64 = LLT::scalable_vector(2, s64);
73*297eecfbSDimitry Andric   const LLT nxv4s64 = LLT::scalable_vector(4, s64);
74*297eecfbSDimitry Andric   const LLT nxv8s64 = LLT::scalable_vector(8, s64);
75*297eecfbSDimitry Andric 
7606c3fb27SDimitry Andric   using namespace TargetOpcode;
7706c3fb27SDimitry Andric 
78*297eecfbSDimitry Andric   auto AllVecTys = {nxv1s8,   nxv2s8,  nxv4s8,  nxv8s8,  nxv16s8, nxv32s8,
79*297eecfbSDimitry Andric                     nxv64s8,  nxv1s16, nxv2s16, nxv4s16, nxv8s16, nxv16s16,
80*297eecfbSDimitry Andric                     nxv32s16, nxv1s32, nxv2s32, nxv4s32, nxv8s32, nxv16s32,
81*297eecfbSDimitry Andric                     nxv1s64,  nxv2s64, nxv4s64, nxv8s64};
82*297eecfbSDimitry Andric 
8306c3fb27SDimitry Andric   getActionDefinitionsBuilder({G_ADD, G_SUB, G_AND, G_OR, G_XOR})
845f757f3fSDimitry Andric       .legalFor({s32, sXLen})
85*297eecfbSDimitry Andric       .legalIf(all(
86*297eecfbSDimitry Andric           typeInSet(0, AllVecTys),
87*297eecfbSDimitry Andric           LegalityPredicate([=, &ST](const LegalityQuery &Query) {
88*297eecfbSDimitry Andric             return ST.hasVInstructions() &&
89*297eecfbSDimitry Andric                    (Query.Types[0].getScalarSizeInBits() != 64 ||
90*297eecfbSDimitry Andric                     ST.hasVInstructionsI64()) &&
91*297eecfbSDimitry Andric                    (Query.Types[0].getElementCount().getKnownMinValue() != 1 ||
92*297eecfbSDimitry Andric                     ST.getELen() == 64);
93*297eecfbSDimitry Andric           })))
945f757f3fSDimitry Andric       .widenScalarToNextPow2(0)
955f757f3fSDimitry Andric       .clampScalar(0, s32, sXLen);
965f757f3fSDimitry Andric 
975f757f3fSDimitry Andric   getActionDefinitionsBuilder(
985f757f3fSDimitry Andric       {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower();
995f757f3fSDimitry Andric 
1005f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower();
1015f757f3fSDimitry Andric 
1025f757f3fSDimitry Andric   auto &ShiftActions = getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL});
1035f757f3fSDimitry Andric   if (ST.is64Bit())
1045f757f3fSDimitry Andric     ShiftActions.customFor({{s32, s32}});
1055f757f3fSDimitry Andric   ShiftActions.legalFor({{s32, s32}, {s32, sXLen}, {sXLen, sXLen}})
1065f757f3fSDimitry Andric       .widenScalarToNextPow2(0)
1075f757f3fSDimitry Andric       .clampScalar(1, s32, sXLen)
1085f757f3fSDimitry Andric       .clampScalar(0, s32, sXLen)
1095f757f3fSDimitry Andric       .minScalarSameAs(1, 0);
1105f757f3fSDimitry Andric 
1115f757f3fSDimitry Andric   if (ST.is64Bit()) {
1125f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
1135f757f3fSDimitry Andric         .legalFor({{sXLen, s32}})
1145f757f3fSDimitry Andric         .maxScalar(0, sXLen);
1155f757f3fSDimitry Andric 
1165f757f3fSDimitry Andric     getActionDefinitionsBuilder(G_SEXT_INREG)
1175f757f3fSDimitry Andric         .customFor({sXLen})
1185f757f3fSDimitry Andric         .maxScalar(0, sXLen)
1195f757f3fSDimitry Andric         .lower();
1205f757f3fSDimitry Andric   } else {
1215f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}).maxScalar(0, sXLen);
1225f757f3fSDimitry Andric 
1235f757f3fSDimitry Andric     getActionDefinitionsBuilder(G_SEXT_INREG).maxScalar(0, sXLen).lower();
1245f757f3fSDimitry Andric   }
1255f757f3fSDimitry Andric 
1265f757f3fSDimitry Andric   // Merge/Unmerge
1275f757f3fSDimitry Andric   for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
128cb14a3feSDimitry Andric     auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op);
1295f757f3fSDimitry Andric     unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
1305f757f3fSDimitry Andric     unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
1315f757f3fSDimitry Andric     if (XLen == 32 && ST.hasStdExtD()) {
132cb14a3feSDimitry Andric       MergeUnmergeActions.legalIf(
133cb14a3feSDimitry Andric           all(typeIs(BigTyIdx, s64), typeIs(LitTyIdx, s32)));
1345f757f3fSDimitry Andric     }
1355f757f3fSDimitry Andric     MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen)
1365f757f3fSDimitry Andric         .widenScalarToNextPow2(BigTyIdx, XLen)
1375f757f3fSDimitry Andric         .clampScalar(LitTyIdx, sXLen, sXLen)
1385f757f3fSDimitry Andric         .clampScalar(BigTyIdx, sXLen, sXLen);
1395f757f3fSDimitry Andric   }
1405f757f3fSDimitry Andric 
1415f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower();
1425f757f3fSDimitry Andric 
1435f757f3fSDimitry Andric   auto &RotateActions = getActionDefinitionsBuilder({G_ROTL, G_ROTR});
144647cbc5dSDimitry Andric   if (ST.hasStdExtZbb() || ST.hasStdExtZbkb()) {
1455f757f3fSDimitry Andric     RotateActions.legalFor({{s32, sXLen}, {sXLen, sXLen}});
1465f757f3fSDimitry Andric     // Widen s32 rotate amount to s64 so SDAG patterns will match.
1475f757f3fSDimitry Andric     if (ST.is64Bit())
1485f757f3fSDimitry Andric       RotateActions.widenScalarIf(all(typeIs(0, s32), typeIs(1, s32)),
1495f757f3fSDimitry Andric                                   changeTo(1, sXLen));
1505f757f3fSDimitry Andric   }
1515f757f3fSDimitry Andric   RotateActions.lower();
1525f757f3fSDimitry Andric 
1535f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_BITREVERSE).maxScalar(0, sXLen).lower();
1545f757f3fSDimitry Andric 
1555f757f3fSDimitry Andric   auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP);
1561db9f3b2SDimitry Andric   if (ST.hasStdExtZbb() || ST.hasStdExtZbkb())
1575f757f3fSDimitry Andric     BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen);
1585f757f3fSDimitry Andric   else
1595f757f3fSDimitry Andric     BSWAPActions.maxScalar(0, sXLen).lower();
1605f757f3fSDimitry Andric 
1615f757f3fSDimitry Andric   auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ});
1625f757f3fSDimitry Andric   auto &CountZerosUndefActions =
1635f757f3fSDimitry Andric       getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF});
1645f757f3fSDimitry Andric   if (ST.hasStdExtZbb()) {
1655f757f3fSDimitry Andric     CountZerosActions.legalFor({{s32, s32}, {sXLen, sXLen}})
1665f757f3fSDimitry Andric         .clampScalar(0, s32, sXLen)
1675f757f3fSDimitry Andric         .widenScalarToNextPow2(0)
1685f757f3fSDimitry Andric         .scalarSameSizeAs(1, 0);
1695f757f3fSDimitry Andric   } else {
1705f757f3fSDimitry Andric     CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
1715f757f3fSDimitry Andric     CountZerosUndefActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0);
1725f757f3fSDimitry Andric   }
1735f757f3fSDimitry Andric   CountZerosUndefActions.lower();
1745f757f3fSDimitry Andric 
1755f757f3fSDimitry Andric   auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP);
1765f757f3fSDimitry Andric   if (ST.hasStdExtZbb()) {
1775f757f3fSDimitry Andric     CTPOPActions.legalFor({{s32, s32}, {sXLen, sXLen}})
1785f757f3fSDimitry Andric         .clampScalar(0, s32, sXLen)
1795f757f3fSDimitry Andric         .widenScalarToNextPow2(0)
1805f757f3fSDimitry Andric         .scalarSameSizeAs(1, 0);
1815f757f3fSDimitry Andric   } else {
1825f757f3fSDimitry Andric     CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower();
1835f757f3fSDimitry Andric   }
1845f757f3fSDimitry Andric 
1855f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_CONSTANT, G_IMPLICIT_DEF})
1865f757f3fSDimitry Andric       .legalFor({s32, sXLen, p0})
1875f757f3fSDimitry Andric       .widenScalarToNextPow2(0)
1885f757f3fSDimitry Andric       .clampScalar(0, s32, sXLen);
1895f757f3fSDimitry Andric 
1905f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_ICMP)
1915f757f3fSDimitry Andric       .legalFor({{sXLen, sXLen}, {sXLen, p0}})
1925f757f3fSDimitry Andric       .widenScalarToNextPow2(1)
1935f757f3fSDimitry Andric       .clampScalar(1, sXLen, sXLen)
1945f757f3fSDimitry Andric       .clampScalar(0, sXLen, sXLen);
1955f757f3fSDimitry Andric 
1965f757f3fSDimitry Andric   auto &SelectActions = getActionDefinitionsBuilder(G_SELECT).legalFor(
1975f757f3fSDimitry Andric       {{s32, sXLen}, {p0, sXLen}});
1985f757f3fSDimitry Andric   if (XLen == 64 || ST.hasStdExtD())
1995f757f3fSDimitry Andric     SelectActions.legalFor({{s64, sXLen}});
2005f757f3fSDimitry Andric   SelectActions.widenScalarToNextPow2(0)
2015f757f3fSDimitry Andric       .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32)
2025f757f3fSDimitry Andric       .clampScalar(1, sXLen, sXLen);
2035f757f3fSDimitry Andric 
2045f757f3fSDimitry Andric   auto &LoadStoreActions =
2055f757f3fSDimitry Andric       getActionDefinitionsBuilder({G_LOAD, G_STORE})
2065f757f3fSDimitry Andric           .legalForTypesWithMemDesc({{s32, p0, s8, 8},
2075f757f3fSDimitry Andric                                      {s32, p0, s16, 16},
2085f757f3fSDimitry Andric                                      {s32, p0, s32, 32},
2095f757f3fSDimitry Andric                                      {p0, p0, sXLen, XLen}});
2105f757f3fSDimitry Andric   auto &ExtLoadActions =
2115f757f3fSDimitry Andric       getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD})
2125f757f3fSDimitry Andric           .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}});
2135f757f3fSDimitry Andric   if (XLen == 64) {
2145f757f3fSDimitry Andric     LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s8, 8},
2155f757f3fSDimitry Andric                                                {s64, p0, s16, 16},
2165f757f3fSDimitry Andric                                                {s64, p0, s32, 32},
2175f757f3fSDimitry Andric                                                {s64, p0, s64, 64}});
2185f757f3fSDimitry Andric     ExtLoadActions.legalForTypesWithMemDesc(
2195f757f3fSDimitry Andric         {{s64, p0, s8, 8}, {s64, p0, s16, 16}, {s64, p0, s32, 32}});
2205f757f3fSDimitry Andric   } else if (ST.hasStdExtD()) {
2215f757f3fSDimitry Andric     LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}});
2225f757f3fSDimitry Andric   }
2235f757f3fSDimitry Andric   LoadStoreActions.clampScalar(0, s32, sXLen).lower();
2245f757f3fSDimitry Andric   ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower();
2255f757f3fSDimitry Andric 
2265f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}});
2275f757f3fSDimitry Andric 
2285f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_PTRTOINT)
2295f757f3fSDimitry Andric       .legalFor({{sXLen, p0}})
2305f757f3fSDimitry Andric       .clampScalar(0, sXLen, sXLen);
2315f757f3fSDimitry Andric 
2325f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_INTTOPTR)
2335f757f3fSDimitry Andric       .legalFor({{p0, sXLen}})
2345f757f3fSDimitry Andric       .clampScalar(1, sXLen, sXLen);
2355f757f3fSDimitry Andric 
2365f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen);
2375f757f3fSDimitry Andric 
2385f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}});
2395f757f3fSDimitry Andric 
2405f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
2415f757f3fSDimitry Andric 
2425f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_PHI)
2435f757f3fSDimitry Andric       .legalFor({p0, sXLen})
2445f757f3fSDimitry Andric       .widenScalarToNextPow2(0)
2455f757f3fSDimitry Andric       .clampScalar(0, sXLen, sXLen);
2465f757f3fSDimitry Andric 
2475f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL})
2485f757f3fSDimitry Andric       .legalFor({p0});
2495f757f3fSDimitry Andric 
2505f757f3fSDimitry Andric   if (ST.hasStdExtM() || ST.hasStdExtZmmul()) {
2515f757f3fSDimitry Andric     getActionDefinitionsBuilder(G_MUL)
2525f757f3fSDimitry Andric         .legalFor({s32, sXLen})
2535f757f3fSDimitry Andric         .widenScalarToNextPow2(0)
2545f757f3fSDimitry Andric         .clampScalar(0, s32, sXLen);
2555f757f3fSDimitry Andric 
2565f757f3fSDimitry Andric     // clang-format off
2575f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_SMULH, G_UMULH})
2585f757f3fSDimitry Andric         .legalFor({sXLen})
2595f757f3fSDimitry Andric         .lower();
2605f757f3fSDimitry Andric     // clang-format on
2615f757f3fSDimitry Andric 
2625f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower();
2635f757f3fSDimitry Andric   } else {
2645f757f3fSDimitry Andric     getActionDefinitionsBuilder(G_MUL)
2655f757f3fSDimitry Andric         .libcallFor({sXLen, sDoubleXLen})
2665f757f3fSDimitry Andric         .widenScalarToNextPow2(0)
2675f757f3fSDimitry Andric         .clampScalar(0, sXLen, sDoubleXLen);
2685f757f3fSDimitry Andric 
2695f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen});
2705f757f3fSDimitry Andric 
2715f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_SMULO, G_UMULO})
2725f757f3fSDimitry Andric         .minScalar(0, sXLen)
2735f757f3fSDimitry Andric         // Widen sXLen to sDoubleXLen so we can use a single libcall to get
2745f757f3fSDimitry Andric         // the low bits for the mul result and high bits to do the overflow
2755f757f3fSDimitry Andric         // check.
2765f757f3fSDimitry Andric         .widenScalarIf(typeIs(0, sXLen),
2775f757f3fSDimitry Andric                        LegalizeMutations::changeTo(0, sDoubleXLen))
2785f757f3fSDimitry Andric         .lower();
2795f757f3fSDimitry Andric   }
2805f757f3fSDimitry Andric 
2815f757f3fSDimitry Andric   if (ST.hasStdExtM()) {
2825f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
2835f757f3fSDimitry Andric         .legalFor({s32, sXLen})
2845f757f3fSDimitry Andric         .libcallFor({sDoubleXLen})
2855f757f3fSDimitry Andric         .clampScalar(0, s32, sDoubleXLen)
2865f757f3fSDimitry Andric         .widenScalarToNextPow2(0);
2875f757f3fSDimitry Andric   } else {
2885f757f3fSDimitry Andric     getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM})
2895f757f3fSDimitry Andric         .libcallFor({sXLen, sDoubleXLen})
2905f757f3fSDimitry Andric         .clampScalar(0, sXLen, sDoubleXLen)
2915f757f3fSDimitry Andric         .widenScalarToNextPow2(0);
2925f757f3fSDimitry Andric   }
2935f757f3fSDimitry Andric 
2945f757f3fSDimitry Andric   auto &AbsActions = getActionDefinitionsBuilder(G_ABS);
2955f757f3fSDimitry Andric   if (ST.hasStdExtZbb())
2965f757f3fSDimitry Andric     AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen);
2975f757f3fSDimitry Andric   AbsActions.lower();
2985f757f3fSDimitry Andric 
2995f757f3fSDimitry Andric   auto &MinMaxActions =
3005f757f3fSDimitry Andric       getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN});
3015f757f3fSDimitry Andric   if (ST.hasStdExtZbb())
3025f757f3fSDimitry Andric     MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen);
3035f757f3fSDimitry Andric   MinMaxActions.lower();
3045f757f3fSDimitry Andric 
3055f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
3065f757f3fSDimitry Andric 
3075f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall();
3085f757f3fSDimitry Andric 
3095f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower();
3105f757f3fSDimitry Andric 
3115f757f3fSDimitry Andric   // FP Operations
3125f757f3fSDimitry Andric 
3135f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG,
3145f757f3fSDimitry Andric                                G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM})
3155f757f3fSDimitry Andric       .legalIf(typeIsScalarFPArith(0, ST));
3165f757f3fSDimitry Andric 
3175f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FCOPYSIGN)
3185f757f3fSDimitry Andric       .legalIf(all(typeIsScalarFPArith(0, ST), typeIsScalarFPArith(1, ST)));
3195f757f3fSDimitry Andric 
3205f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FPTRUNC).legalIf(
3215f757f3fSDimitry Andric       [=, &ST](const LegalityQuery &Query) -> bool {
3225f757f3fSDimitry Andric         return (ST.hasStdExtD() && typeIs(0, s32)(Query) &&
3235f757f3fSDimitry Andric                 typeIs(1, s64)(Query));
3245f757f3fSDimitry Andric       });
3255f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FPEXT).legalIf(
3265f757f3fSDimitry Andric       [=, &ST](const LegalityQuery &Query) -> bool {
3275f757f3fSDimitry Andric         return (ST.hasStdExtD() && typeIs(0, s64)(Query) &&
3285f757f3fSDimitry Andric                 typeIs(1, s32)(Query));
3295f757f3fSDimitry Andric       });
3305f757f3fSDimitry Andric 
3315f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FCMP)
3325f757f3fSDimitry Andric       .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST)))
3335f757f3fSDimitry Andric       .clampScalar(0, sXLen, sXLen);
3345f757f3fSDimitry Andric 
3355f757f3fSDimitry Andric   // TODO: Support vector version of G_IS_FPCLASS.
3365f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_IS_FPCLASS)
3375f757f3fSDimitry Andric       .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST)));
3385f757f3fSDimitry Andric 
3395f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_FCONSTANT)
3405f757f3fSDimitry Andric       .legalIf(typeIsScalarFPArith(0, ST))
3415f757f3fSDimitry Andric       .lowerFor({s32, s64});
3425f757f3fSDimitry Andric 
3435f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
3445f757f3fSDimitry Andric       .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
3455f757f3fSDimitry Andric       .widenScalarToNextPow2(0)
3465f757f3fSDimitry Andric       .clampScalar(0, s32, sXLen);
3475f757f3fSDimitry Andric 
3485f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
3495f757f3fSDimitry Andric       .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
3505f757f3fSDimitry Andric       .widenScalarToNextPow2(1)
3515f757f3fSDimitry Andric       .clampScalar(1, s32, sXLen);
3525f757f3fSDimitry Andric 
3535f757f3fSDimitry Andric   // FIXME: We can do custom inline expansion like SelectionDAG.
3545f757f3fSDimitry Andric   // FIXME: Legal with Zfa.
3555f757f3fSDimitry Andric   getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
3565f757f3fSDimitry Andric       .libcallFor({s32, s64});
3575f757f3fSDimitry Andric 
3585f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_VASTART).customFor({p0});
3595f757f3fSDimitry Andric 
3605f757f3fSDimitry Andric   // va_list must be a pointer, but most sized types are pretty easy to handle
3615f757f3fSDimitry Andric   // as the destination.
3625f757f3fSDimitry Andric   getActionDefinitionsBuilder(G_VAARG)
3635f757f3fSDimitry Andric       // TODO: Implement narrowScalar and widenScalar for G_VAARG for types
3645f757f3fSDimitry Andric       // outside the [s32, sXLen] range.
3655f757f3fSDimitry Andric       .clampScalar(0, s32, sXLen)
3665f757f3fSDimitry Andric       .lowerForCartesianProduct({s32, sXLen, p0}, {p0});
36706c3fb27SDimitry Andric 
368bdd1243dSDimitry Andric   getLegacyLegalizerInfo().computeTables();
369bdd1243dSDimitry Andric }
3705f757f3fSDimitry Andric 
getTypeForLLT(LLT Ty,LLVMContext & C)3715f757f3fSDimitry Andric static Type *getTypeForLLT(LLT Ty, LLVMContext &C) {
3725f757f3fSDimitry Andric   if (Ty.isVector())
3735f757f3fSDimitry Andric     return FixedVectorType::get(IntegerType::get(C, Ty.getScalarSizeInBits()),
3745f757f3fSDimitry Andric                                 Ty.getNumElements());
3755f757f3fSDimitry Andric   return IntegerType::get(C, Ty.getSizeInBits());
3765f757f3fSDimitry Andric }
3775f757f3fSDimitry Andric 
legalizeIntrinsic(LegalizerHelper & Helper,MachineInstr & MI) const3785f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
3795f757f3fSDimitry Andric                                            MachineInstr &MI) const {
3805f757f3fSDimitry Andric   Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
3815f757f3fSDimitry Andric   switch (IntrinsicID) {
3825f757f3fSDimitry Andric   default:
3835f757f3fSDimitry Andric     return false;
3845f757f3fSDimitry Andric   case Intrinsic::vacopy: {
3855f757f3fSDimitry Andric     // vacopy arguments must be legal because of the intrinsic signature.
3865f757f3fSDimitry Andric     // No need to check here.
3875f757f3fSDimitry Andric 
3885f757f3fSDimitry Andric     MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
3895f757f3fSDimitry Andric     MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3905f757f3fSDimitry Andric     MachineFunction &MF = *MI.getMF();
3915f757f3fSDimitry Andric     const DataLayout &DL = MIRBuilder.getDataLayout();
3925f757f3fSDimitry Andric     LLVMContext &Ctx = MF.getFunction().getContext();
3935f757f3fSDimitry Andric 
3945f757f3fSDimitry Andric     Register DstLst = MI.getOperand(1).getReg();
3955f757f3fSDimitry Andric     LLT PtrTy = MRI.getType(DstLst);
3965f757f3fSDimitry Andric 
3975f757f3fSDimitry Andric     // Load the source va_list
3985f757f3fSDimitry Andric     Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
3995f757f3fSDimitry Andric     MachineMemOperand *LoadMMO = MF.getMachineMemOperand(
4005f757f3fSDimitry Andric         MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment);
4015f757f3fSDimitry Andric     auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO);
4025f757f3fSDimitry Andric 
4035f757f3fSDimitry Andric     // Store the result in the destination va_list
4045f757f3fSDimitry Andric     MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
4055f757f3fSDimitry Andric         MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, Alignment);
4065f757f3fSDimitry Andric     MIRBuilder.buildStore(DstLst, Tmp, *StoreMMO);
4075f757f3fSDimitry Andric 
4085f757f3fSDimitry Andric     MI.eraseFromParent();
4095f757f3fSDimitry Andric     return true;
4105f757f3fSDimitry Andric   }
4115f757f3fSDimitry Andric   }
4125f757f3fSDimitry Andric }
4135f757f3fSDimitry Andric 
legalizeShlAshrLshr(MachineInstr & MI,MachineIRBuilder & MIRBuilder,GISelChangeObserver & Observer) const4145f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeShlAshrLshr(
4155f757f3fSDimitry Andric     MachineInstr &MI, MachineIRBuilder &MIRBuilder,
4165f757f3fSDimitry Andric     GISelChangeObserver &Observer) const {
4175f757f3fSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_ASHR ||
4185f757f3fSDimitry Andric          MI.getOpcode() == TargetOpcode::G_LSHR ||
4195f757f3fSDimitry Andric          MI.getOpcode() == TargetOpcode::G_SHL);
4205f757f3fSDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4215f757f3fSDimitry Andric   // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the
4225f757f3fSDimitry Andric   // imported patterns can select it later. Either way, it will be legal.
4235f757f3fSDimitry Andric   Register AmtReg = MI.getOperand(2).getReg();
4245f757f3fSDimitry Andric   auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI);
4255f757f3fSDimitry Andric   if (!VRegAndVal)
4265f757f3fSDimitry Andric     return true;
4275f757f3fSDimitry Andric   // Check the shift amount is in range for an immediate form.
4285f757f3fSDimitry Andric   uint64_t Amount = VRegAndVal->Value.getZExtValue();
4295f757f3fSDimitry Andric   if (Amount > 31)
4305f757f3fSDimitry Andric     return true; // This will have to remain a register variant.
4315f757f3fSDimitry Andric   auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount);
4325f757f3fSDimitry Andric   Observer.changingInstr(MI);
4335f757f3fSDimitry Andric   MI.getOperand(2).setReg(ExtCst.getReg(0));
4345f757f3fSDimitry Andric   Observer.changedInstr(MI);
4355f757f3fSDimitry Andric   return true;
4365f757f3fSDimitry Andric }
4375f757f3fSDimitry Andric 
legalizeVAStart(MachineInstr & MI,MachineIRBuilder & MIRBuilder) const4385f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI,
4395f757f3fSDimitry Andric                                          MachineIRBuilder &MIRBuilder) const {
4405f757f3fSDimitry Andric   // Stores the address of the VarArgsFrameIndex slot into the memory location
4415f757f3fSDimitry Andric   assert(MI.getOpcode() == TargetOpcode::G_VASTART);
4425f757f3fSDimitry Andric   MachineFunction *MF = MI.getParent()->getParent();
4435f757f3fSDimitry Andric   RISCVMachineFunctionInfo *FuncInfo = MF->getInfo<RISCVMachineFunctionInfo>();
4445f757f3fSDimitry Andric   int FI = FuncInfo->getVarArgsFrameIndex();
4455f757f3fSDimitry Andric   LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg());
4465f757f3fSDimitry Andric   auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI);
4475f757f3fSDimitry Andric   assert(MI.hasOneMemOperand());
4485f757f3fSDimitry Andric   MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(),
4495f757f3fSDimitry Andric                         *MI.memoperands()[0]);
4505f757f3fSDimitry Andric   MI.eraseFromParent();
4515f757f3fSDimitry Andric   return true;
4525f757f3fSDimitry Andric }
4535f757f3fSDimitry Andric 
legalizeCustom(LegalizerHelper & Helper,MachineInstr & MI,LostDebugLocObserver & LocObserver) const4541db9f3b2SDimitry Andric bool RISCVLegalizerInfo::legalizeCustom(
4551db9f3b2SDimitry Andric     LegalizerHelper &Helper, MachineInstr &MI,
4561db9f3b2SDimitry Andric     LostDebugLocObserver &LocObserver) const {
4575f757f3fSDimitry Andric   MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
4585f757f3fSDimitry Andric   GISelChangeObserver &Observer = Helper.Observer;
4595f757f3fSDimitry Andric   switch (MI.getOpcode()) {
4605f757f3fSDimitry Andric   default:
4615f757f3fSDimitry Andric     // No idea what to do.
4625f757f3fSDimitry Andric     return false;
4635f757f3fSDimitry Andric   case TargetOpcode::G_ABS:
4645f757f3fSDimitry Andric     return Helper.lowerAbsToMaxNeg(MI);
4655f757f3fSDimitry Andric   case TargetOpcode::G_SHL:
4665f757f3fSDimitry Andric   case TargetOpcode::G_ASHR:
4675f757f3fSDimitry Andric   case TargetOpcode::G_LSHR:
4685f757f3fSDimitry Andric     return legalizeShlAshrLshr(MI, MIRBuilder, Observer);
4695f757f3fSDimitry Andric   case TargetOpcode::G_SEXT_INREG: {
4705f757f3fSDimitry Andric     // Source size of 32 is sext.w.
4715f757f3fSDimitry Andric     int64_t SizeInBits = MI.getOperand(2).getImm();
4725f757f3fSDimitry Andric     if (SizeInBits == 32)
4735f757f3fSDimitry Andric       return true;
4745f757f3fSDimitry Andric 
4755f757f3fSDimitry Andric     return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
4765f757f3fSDimitry Andric            LegalizerHelper::Legalized;
4775f757f3fSDimitry Andric   }
4785f757f3fSDimitry Andric   case TargetOpcode::G_IS_FPCLASS: {
4795f757f3fSDimitry Andric     Register GISFPCLASS = MI.getOperand(0).getReg();
4805f757f3fSDimitry Andric     Register Src = MI.getOperand(1).getReg();
4815f757f3fSDimitry Andric     const MachineOperand &ImmOp = MI.getOperand(2);
4825f757f3fSDimitry Andric     MachineIRBuilder MIB(MI);
4835f757f3fSDimitry Andric 
4845f757f3fSDimitry Andric     // Turn LLVM IR's floating point classes to that in RISC-V,
4855f757f3fSDimitry Andric     // by simply rotating the 10-bit immediate right by two bits.
4865f757f3fSDimitry Andric     APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm()));
4875f757f3fSDimitry Andric     auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen));
4885f757f3fSDimitry Andric     auto ConstZero = MIB.buildConstant(sXLen, 0);
4895f757f3fSDimitry Andric 
4905f757f3fSDimitry Andric     auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src});
4915f757f3fSDimitry Andric     auto And = MIB.buildAnd(sXLen, GFClass, FClassMask);
4925f757f3fSDimitry Andric     MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero);
4935f757f3fSDimitry Andric 
4945f757f3fSDimitry Andric     MI.eraseFromParent();
4955f757f3fSDimitry Andric     return true;
4965f757f3fSDimitry Andric   }
4975f757f3fSDimitry Andric   case TargetOpcode::G_VASTART:
4985f757f3fSDimitry Andric     return legalizeVAStart(MI, MIRBuilder);
4995f757f3fSDimitry Andric   }
5005f757f3fSDimitry Andric 
5015f757f3fSDimitry Andric   llvm_unreachable("expected switch to return");
5025f757f3fSDimitry Andric }
503