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