1bdd1243dSDimitry Andric //===-- RISCVLegalizerInfo.cpp ----------------------------------*- C++ -*-===// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric /// \file 906c3fb27SDimitry Andric /// This file implements the targeting of the Machinelegalizer class for RISC-V. 10bdd1243dSDimitry Andric /// \todo This should be generated by TableGen. 11bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 12bdd1243dSDimitry Andric 13bdd1243dSDimitry Andric #include "RISCVLegalizerInfo.h" 14*5f757f3fSDimitry Andric #include "RISCVMachineFunctionInfo.h" 1506c3fb27SDimitry Andric #include "RISCVSubtarget.h" 16*5f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 17*5f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 18*5f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 19*5f757f3fSDimitry 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; 26*5f757f3fSDimitry Andric using namespace LegalityPredicates; 27*5f757f3fSDimitry Andric using namespace LegalizeMutations; 28bdd1243dSDimitry Andric 29*5f757f3fSDimitry Andric // Is this type supported by scalar FP arithmetic operations given the current 30*5f757f3fSDimitry Andric // subtarget. 31*5f757f3fSDimitry Andric static LegalityPredicate typeIsScalarFPArith(unsigned TypeIdx, 32*5f757f3fSDimitry Andric const RISCVSubtarget &ST) { 33*5f757f3fSDimitry Andric return [=, &ST](const LegalityQuery &Query) { 34*5f757f3fSDimitry Andric return Query.Types[TypeIdx].isScalar() && 35*5f757f3fSDimitry Andric ((ST.hasStdExtF() && Query.Types[TypeIdx].getSizeInBits() == 32) || 36*5f757f3fSDimitry Andric (ST.hasStdExtD() && Query.Types[TypeIdx].getSizeInBits() == 64)); 37*5f757f3fSDimitry Andric }; 38*5f757f3fSDimitry Andric } 39*5f757f3fSDimitry Andric 40*5f757f3fSDimitry Andric RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST) 41*5f757f3fSDimitry Andric : STI(ST), XLen(STI.getXLen()), sXLen(LLT::scalar(XLen)) { 42*5f757f3fSDimitry Andric const LLT sDoubleXLen = LLT::scalar(2 * XLen); 43*5f757f3fSDimitry Andric const LLT p0 = LLT::pointer(0, XLen); 44*5f757f3fSDimitry Andric const LLT s1 = LLT::scalar(1); 45*5f757f3fSDimitry Andric const LLT s8 = LLT::scalar(8); 46*5f757f3fSDimitry Andric const LLT s16 = LLT::scalar(16); 47*5f757f3fSDimitry Andric const LLT s32 = LLT::scalar(32); 48*5f757f3fSDimitry 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}) 53*5f757f3fSDimitry Andric .legalFor({s32, sXLen}) 54*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 55*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 56*5f757f3fSDimitry Andric 57*5f757f3fSDimitry Andric getActionDefinitionsBuilder( 58*5f757f3fSDimitry Andric {G_UADDE, G_UADDO, G_USUBE, G_USUBO}).lower(); 59*5f757f3fSDimitry Andric 60*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).minScalar(0, sXLen).lower(); 61*5f757f3fSDimitry Andric 62*5f757f3fSDimitry Andric auto &ShiftActions = getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL}); 63*5f757f3fSDimitry Andric if (ST.is64Bit()) 64*5f757f3fSDimitry Andric ShiftActions.customFor({{s32, s32}}); 65*5f757f3fSDimitry Andric ShiftActions.legalFor({{s32, s32}, {s32, sXLen}, {sXLen, sXLen}}) 66*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 67*5f757f3fSDimitry Andric .clampScalar(1, s32, sXLen) 68*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 69*5f757f3fSDimitry Andric .minScalarSameAs(1, 0); 70*5f757f3fSDimitry Andric 71*5f757f3fSDimitry Andric if (ST.is64Bit()) { 72*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}) 73*5f757f3fSDimitry Andric .legalFor({{sXLen, s32}}) 74*5f757f3fSDimitry Andric .maxScalar(0, sXLen); 75*5f757f3fSDimitry Andric 76*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG) 77*5f757f3fSDimitry Andric .customFor({sXLen}) 78*5f757f3fSDimitry Andric .maxScalar(0, sXLen) 79*5f757f3fSDimitry Andric .lower(); 80*5f757f3fSDimitry Andric } else { 81*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}).maxScalar(0, sXLen); 82*5f757f3fSDimitry Andric 83*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG).maxScalar(0, sXLen).lower(); 84*5f757f3fSDimitry Andric } 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric // Merge/Unmerge 87*5f757f3fSDimitry Andric for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) { 88*5f757f3fSDimitry Andric unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1; 89*5f757f3fSDimitry Andric unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0; 90*5f757f3fSDimitry Andric auto &MergeUnmergeActions = getActionDefinitionsBuilder(Op); 91*5f757f3fSDimitry Andric if (XLen == 32 && ST.hasStdExtD()) { 92*5f757f3fSDimitry Andric LLT IdxZeroTy = G_MERGE_VALUES ? s64 : s32; 93*5f757f3fSDimitry Andric LLT IdxOneTy = G_MERGE_VALUES ? s32 : s64; 94*5f757f3fSDimitry Andric MergeUnmergeActions.legalFor({IdxZeroTy, IdxOneTy}); 95*5f757f3fSDimitry Andric } 96*5f757f3fSDimitry Andric MergeUnmergeActions.widenScalarToNextPow2(LitTyIdx, XLen) 97*5f757f3fSDimitry Andric .widenScalarToNextPow2(BigTyIdx, XLen) 98*5f757f3fSDimitry Andric .clampScalar(LitTyIdx, sXLen, sXLen) 99*5f757f3fSDimitry Andric .clampScalar(BigTyIdx, sXLen, sXLen); 100*5f757f3fSDimitry Andric } 101*5f757f3fSDimitry Andric 102*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower(); 103*5f757f3fSDimitry Andric 104*5f757f3fSDimitry Andric auto &RotateActions = getActionDefinitionsBuilder({G_ROTL, G_ROTR}); 105*5f757f3fSDimitry Andric if (ST.hasStdExtZbb()) { 106*5f757f3fSDimitry Andric RotateActions.legalFor({{s32, sXLen}, {sXLen, sXLen}}); 107*5f757f3fSDimitry Andric // Widen s32 rotate amount to s64 so SDAG patterns will match. 108*5f757f3fSDimitry Andric if (ST.is64Bit()) 109*5f757f3fSDimitry Andric RotateActions.widenScalarIf(all(typeIs(0, s32), typeIs(1, s32)), 110*5f757f3fSDimitry Andric changeTo(1, sXLen)); 111*5f757f3fSDimitry Andric } 112*5f757f3fSDimitry Andric RotateActions.lower(); 113*5f757f3fSDimitry Andric 114*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BITREVERSE).maxScalar(0, sXLen).lower(); 115*5f757f3fSDimitry Andric 116*5f757f3fSDimitry Andric auto &BSWAPActions = getActionDefinitionsBuilder(G_BSWAP); 117*5f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 118*5f757f3fSDimitry Andric BSWAPActions.legalFor({sXLen}).clampScalar(0, sXLen, sXLen); 119*5f757f3fSDimitry Andric else 120*5f757f3fSDimitry Andric BSWAPActions.maxScalar(0, sXLen).lower(); 121*5f757f3fSDimitry Andric 122*5f757f3fSDimitry Andric auto &CountZerosActions = getActionDefinitionsBuilder({G_CTLZ, G_CTTZ}); 123*5f757f3fSDimitry Andric auto &CountZerosUndefActions = 124*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF}); 125*5f757f3fSDimitry Andric if (ST.hasStdExtZbb()) { 126*5f757f3fSDimitry Andric CountZerosActions.legalFor({{s32, s32}, {sXLen, sXLen}}) 127*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 128*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 129*5f757f3fSDimitry Andric .scalarSameSizeAs(1, 0); 130*5f757f3fSDimitry Andric } else { 131*5f757f3fSDimitry Andric CountZerosActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower(); 132*5f757f3fSDimitry Andric CountZerosUndefActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0); 133*5f757f3fSDimitry Andric } 134*5f757f3fSDimitry Andric CountZerosUndefActions.lower(); 135*5f757f3fSDimitry Andric 136*5f757f3fSDimitry Andric auto &CTPOPActions = getActionDefinitionsBuilder(G_CTPOP); 137*5f757f3fSDimitry Andric if (ST.hasStdExtZbb()) { 138*5f757f3fSDimitry Andric CTPOPActions.legalFor({{s32, s32}, {sXLen, sXLen}}) 139*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 140*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 141*5f757f3fSDimitry Andric .scalarSameSizeAs(1, 0); 142*5f757f3fSDimitry Andric } else { 143*5f757f3fSDimitry Andric CTPOPActions.maxScalar(0, sXLen).scalarSameSizeAs(1, 0).lower(); 144*5f757f3fSDimitry Andric } 145*5f757f3fSDimitry Andric 146*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_CONSTANT, G_IMPLICIT_DEF}) 147*5f757f3fSDimitry Andric .legalFor({s32, sXLen, p0}) 148*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 149*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 150*5f757f3fSDimitry Andric 151*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_ICMP) 152*5f757f3fSDimitry Andric .legalFor({{sXLen, sXLen}, {sXLen, p0}}) 153*5f757f3fSDimitry Andric .widenScalarToNextPow2(1) 154*5f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen) 155*5f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 156*5f757f3fSDimitry Andric 157*5f757f3fSDimitry Andric auto &SelectActions = getActionDefinitionsBuilder(G_SELECT).legalFor( 158*5f757f3fSDimitry Andric {{s32, sXLen}, {p0, sXLen}}); 159*5f757f3fSDimitry Andric if (XLen == 64 || ST.hasStdExtD()) 160*5f757f3fSDimitry Andric SelectActions.legalFor({{s64, sXLen}}); 161*5f757f3fSDimitry Andric SelectActions.widenScalarToNextPow2(0) 162*5f757f3fSDimitry Andric .clampScalar(0, s32, (XLen == 64 || ST.hasStdExtD()) ? s64 : s32) 163*5f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen); 164*5f757f3fSDimitry Andric 165*5f757f3fSDimitry Andric auto &LoadStoreActions = 166*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_LOAD, G_STORE}) 167*5f757f3fSDimitry Andric .legalForTypesWithMemDesc({{s32, p0, s8, 8}, 168*5f757f3fSDimitry Andric {s32, p0, s16, 16}, 169*5f757f3fSDimitry Andric {s32, p0, s32, 32}, 170*5f757f3fSDimitry Andric {p0, p0, sXLen, XLen}}); 171*5f757f3fSDimitry Andric auto &ExtLoadActions = 172*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SEXTLOAD, G_ZEXTLOAD}) 173*5f757f3fSDimitry Andric .legalForTypesWithMemDesc({{s32, p0, s8, 8}, {s32, p0, s16, 16}}); 174*5f757f3fSDimitry Andric if (XLen == 64) { 175*5f757f3fSDimitry Andric LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s8, 8}, 176*5f757f3fSDimitry Andric {s64, p0, s16, 16}, 177*5f757f3fSDimitry Andric {s64, p0, s32, 32}, 178*5f757f3fSDimitry Andric {s64, p0, s64, 64}}); 179*5f757f3fSDimitry Andric ExtLoadActions.legalForTypesWithMemDesc( 180*5f757f3fSDimitry Andric {{s64, p0, s8, 8}, {s64, p0, s16, 16}, {s64, p0, s32, 32}}); 181*5f757f3fSDimitry Andric } else if (ST.hasStdExtD()) { 182*5f757f3fSDimitry Andric LoadStoreActions.legalForTypesWithMemDesc({{s64, p0, s64, 64}}); 183*5f757f3fSDimitry Andric } 184*5f757f3fSDimitry Andric LoadStoreActions.clampScalar(0, s32, sXLen).lower(); 185*5f757f3fSDimitry Andric ExtLoadActions.widenScalarToNextPow2(0).clampScalar(0, s32, sXLen).lower(); 186*5f757f3fSDimitry Andric 187*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_PTR_ADD, G_PTRMASK}).legalFor({{p0, sXLen}}); 188*5f757f3fSDimitry Andric 189*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_PTRTOINT) 190*5f757f3fSDimitry Andric .legalFor({{sXLen, p0}}) 191*5f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 192*5f757f3fSDimitry Andric 193*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_INTTOPTR) 194*5f757f3fSDimitry Andric .legalFor({{p0, sXLen}}) 195*5f757f3fSDimitry Andric .clampScalar(1, sXLen, sXLen); 196*5f757f3fSDimitry Andric 197*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRCOND).legalFor({sXLen}).minScalar(0, sXLen); 198*5f757f3fSDimitry Andric 199*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRJT).legalFor({{p0, sXLen}}); 200*5f757f3fSDimitry Andric 201*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0}); 202*5f757f3fSDimitry Andric 203*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_PHI) 204*5f757f3fSDimitry Andric .legalFor({p0, sXLen}) 205*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 206*5f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 207*5f757f3fSDimitry Andric 208*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE, G_CONSTANT_POOL}) 209*5f757f3fSDimitry Andric .legalFor({p0}); 210*5f757f3fSDimitry Andric 211*5f757f3fSDimitry Andric if (ST.hasStdExtM() || ST.hasStdExtZmmul()) { 212*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_MUL) 213*5f757f3fSDimitry Andric .legalFor({s32, sXLen}) 214*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 215*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 216*5f757f3fSDimitry Andric 217*5f757f3fSDimitry Andric // clang-format off 218*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULH, G_UMULH}) 219*5f757f3fSDimitry Andric .legalFor({sXLen}) 220*5f757f3fSDimitry Andric .lower(); 221*5f757f3fSDimitry Andric // clang-format on 222*5f757f3fSDimitry Andric 223*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULO, G_UMULO}).minScalar(0, sXLen).lower(); 224*5f757f3fSDimitry Andric } else { 225*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_MUL) 226*5f757f3fSDimitry Andric .libcallFor({sXLen, sDoubleXLen}) 227*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 228*5f757f3fSDimitry Andric .clampScalar(0, sXLen, sDoubleXLen); 229*5f757f3fSDimitry Andric 230*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULH, G_UMULH}).lowerFor({sXLen}); 231*5f757f3fSDimitry Andric 232*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SMULO, G_UMULO}) 233*5f757f3fSDimitry Andric .minScalar(0, sXLen) 234*5f757f3fSDimitry Andric // Widen sXLen to sDoubleXLen so we can use a single libcall to get 235*5f757f3fSDimitry Andric // the low bits for the mul result and high bits to do the overflow 236*5f757f3fSDimitry Andric // check. 237*5f757f3fSDimitry Andric .widenScalarIf(typeIs(0, sXLen), 238*5f757f3fSDimitry Andric LegalizeMutations::changeTo(0, sDoubleXLen)) 239*5f757f3fSDimitry Andric .lower(); 240*5f757f3fSDimitry Andric } 241*5f757f3fSDimitry Andric 242*5f757f3fSDimitry Andric if (ST.hasStdExtM()) { 243*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM}) 244*5f757f3fSDimitry Andric .legalFor({s32, sXLen}) 245*5f757f3fSDimitry Andric .libcallFor({sDoubleXLen}) 246*5f757f3fSDimitry Andric .clampScalar(0, s32, sDoubleXLen) 247*5f757f3fSDimitry Andric .widenScalarToNextPow2(0); 248*5f757f3fSDimitry Andric } else { 249*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UDIV, G_SDIV, G_UREM, G_SREM}) 250*5f757f3fSDimitry Andric .libcallFor({sXLen, sDoubleXLen}) 251*5f757f3fSDimitry Andric .clampScalar(0, sXLen, sDoubleXLen) 252*5f757f3fSDimitry Andric .widenScalarToNextPow2(0); 253*5f757f3fSDimitry Andric } 254*5f757f3fSDimitry Andric 255*5f757f3fSDimitry Andric auto &AbsActions = getActionDefinitionsBuilder(G_ABS); 256*5f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 257*5f757f3fSDimitry Andric AbsActions.customFor({s32, sXLen}).minScalar(0, sXLen); 258*5f757f3fSDimitry Andric AbsActions.lower(); 259*5f757f3fSDimitry Andric 260*5f757f3fSDimitry Andric auto &MinMaxActions = 261*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_UMAX, G_UMIN, G_SMAX, G_SMIN}); 262*5f757f3fSDimitry Andric if (ST.hasStdExtZbb()) 263*5f757f3fSDimitry Andric MinMaxActions.legalFor({sXLen}).minScalar(0, sXLen); 264*5f757f3fSDimitry Andric MinMaxActions.lower(); 265*5f757f3fSDimitry Andric 266*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0}); 267*5f757f3fSDimitry Andric 268*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall(); 269*5f757f3fSDimitry Andric 270*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_DYN_STACKALLOC).lower(); 271*5f757f3fSDimitry Andric 272*5f757f3fSDimitry Andric // FP Operations 273*5f757f3fSDimitry Andric 274*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FMA, G_FNEG, 275*5f757f3fSDimitry Andric G_FABS, G_FSQRT, G_FMAXNUM, G_FMINNUM}) 276*5f757f3fSDimitry Andric .legalIf(typeIsScalarFPArith(0, ST)); 277*5f757f3fSDimitry Andric 278*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCOPYSIGN) 279*5f757f3fSDimitry Andric .legalIf(all(typeIsScalarFPArith(0, ST), typeIsScalarFPArith(1, ST))); 280*5f757f3fSDimitry Andric 281*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FPTRUNC).legalIf( 282*5f757f3fSDimitry Andric [=, &ST](const LegalityQuery &Query) -> bool { 283*5f757f3fSDimitry Andric return (ST.hasStdExtD() && typeIs(0, s32)(Query) && 284*5f757f3fSDimitry Andric typeIs(1, s64)(Query)); 285*5f757f3fSDimitry Andric }); 286*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FPEXT).legalIf( 287*5f757f3fSDimitry Andric [=, &ST](const LegalityQuery &Query) -> bool { 288*5f757f3fSDimitry Andric return (ST.hasStdExtD() && typeIs(0, s64)(Query) && 289*5f757f3fSDimitry Andric typeIs(1, s32)(Query)); 290*5f757f3fSDimitry Andric }); 291*5f757f3fSDimitry Andric 292*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCMP) 293*5f757f3fSDimitry Andric .legalIf(all(typeIs(0, sXLen), typeIsScalarFPArith(1, ST))) 294*5f757f3fSDimitry Andric .clampScalar(0, sXLen, sXLen); 295*5f757f3fSDimitry Andric 296*5f757f3fSDimitry Andric // TODO: Support vector version of G_IS_FPCLASS. 297*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_IS_FPCLASS) 298*5f757f3fSDimitry Andric .customIf(all(typeIs(0, s1), typeIsScalarFPArith(1, ST))); 299*5f757f3fSDimitry Andric 300*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_FCONSTANT) 301*5f757f3fSDimitry Andric .legalIf(typeIsScalarFPArith(0, ST)) 302*5f757f3fSDimitry Andric .lowerFor({s32, s64}); 303*5f757f3fSDimitry Andric 304*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 305*5f757f3fSDimitry Andric .legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST))) 306*5f757f3fSDimitry Andric .widenScalarToNextPow2(0) 307*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen); 308*5f757f3fSDimitry Andric 309*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) 310*5f757f3fSDimitry Andric .legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen}))) 311*5f757f3fSDimitry Andric .widenScalarToNextPow2(1) 312*5f757f3fSDimitry Andric .clampScalar(1, s32, sXLen); 313*5f757f3fSDimitry Andric 314*5f757f3fSDimitry Andric // FIXME: We can do custom inline expansion like SelectionDAG. 315*5f757f3fSDimitry Andric // FIXME: Legal with Zfa. 316*5f757f3fSDimitry Andric getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR}) 317*5f757f3fSDimitry Andric .libcallFor({s32, s64}); 318*5f757f3fSDimitry Andric 319*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_VASTART).customFor({p0}); 320*5f757f3fSDimitry Andric 321*5f757f3fSDimitry Andric // va_list must be a pointer, but most sized types are pretty easy to handle 322*5f757f3fSDimitry Andric // as the destination. 323*5f757f3fSDimitry Andric getActionDefinitionsBuilder(G_VAARG) 324*5f757f3fSDimitry Andric // TODO: Implement narrowScalar and widenScalar for G_VAARG for types 325*5f757f3fSDimitry Andric // outside the [s32, sXLen] range. 326*5f757f3fSDimitry Andric .clampScalar(0, s32, sXLen) 327*5f757f3fSDimitry Andric .lowerForCartesianProduct({s32, sXLen, p0}, {p0}); 32806c3fb27SDimitry Andric 329bdd1243dSDimitry Andric getLegacyLegalizerInfo().computeTables(); 330bdd1243dSDimitry Andric } 331*5f757f3fSDimitry Andric 332*5f757f3fSDimitry Andric static Type *getTypeForLLT(LLT Ty, LLVMContext &C) { 333*5f757f3fSDimitry Andric if (Ty.isVector()) 334*5f757f3fSDimitry Andric return FixedVectorType::get(IntegerType::get(C, Ty.getScalarSizeInBits()), 335*5f757f3fSDimitry Andric Ty.getNumElements()); 336*5f757f3fSDimitry Andric return IntegerType::get(C, Ty.getSizeInBits()); 337*5f757f3fSDimitry Andric } 338*5f757f3fSDimitry Andric 339*5f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, 340*5f757f3fSDimitry Andric MachineInstr &MI) const { 341*5f757f3fSDimitry Andric Intrinsic::ID IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID(); 342*5f757f3fSDimitry Andric switch (IntrinsicID) { 343*5f757f3fSDimitry Andric default: 344*5f757f3fSDimitry Andric return false; 345*5f757f3fSDimitry Andric case Intrinsic::vacopy: { 346*5f757f3fSDimitry Andric // vacopy arguments must be legal because of the intrinsic signature. 347*5f757f3fSDimitry Andric // No need to check here. 348*5f757f3fSDimitry Andric 349*5f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 350*5f757f3fSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 351*5f757f3fSDimitry Andric MachineFunction &MF = *MI.getMF(); 352*5f757f3fSDimitry Andric const DataLayout &DL = MIRBuilder.getDataLayout(); 353*5f757f3fSDimitry Andric LLVMContext &Ctx = MF.getFunction().getContext(); 354*5f757f3fSDimitry Andric 355*5f757f3fSDimitry Andric Register DstLst = MI.getOperand(1).getReg(); 356*5f757f3fSDimitry Andric LLT PtrTy = MRI.getType(DstLst); 357*5f757f3fSDimitry Andric 358*5f757f3fSDimitry Andric // Load the source va_list 359*5f757f3fSDimitry Andric Align Alignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx)); 360*5f757f3fSDimitry Andric MachineMemOperand *LoadMMO = MF.getMachineMemOperand( 361*5f757f3fSDimitry Andric MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, Alignment); 362*5f757f3fSDimitry Andric auto Tmp = MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), *LoadMMO); 363*5f757f3fSDimitry Andric 364*5f757f3fSDimitry Andric // Store the result in the destination va_list 365*5f757f3fSDimitry Andric MachineMemOperand *StoreMMO = MF.getMachineMemOperand( 366*5f757f3fSDimitry Andric MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, Alignment); 367*5f757f3fSDimitry Andric MIRBuilder.buildStore(DstLst, Tmp, *StoreMMO); 368*5f757f3fSDimitry Andric 369*5f757f3fSDimitry Andric MI.eraseFromParent(); 370*5f757f3fSDimitry Andric return true; 371*5f757f3fSDimitry Andric } 372*5f757f3fSDimitry Andric } 373*5f757f3fSDimitry Andric } 374*5f757f3fSDimitry Andric 375*5f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeShlAshrLshr( 376*5f757f3fSDimitry Andric MachineInstr &MI, MachineIRBuilder &MIRBuilder, 377*5f757f3fSDimitry Andric GISelChangeObserver &Observer) const { 378*5f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_ASHR || 379*5f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_LSHR || 380*5f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_SHL); 381*5f757f3fSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 382*5f757f3fSDimitry Andric // If the shift amount is a G_CONSTANT, promote it to a 64 bit type so the 383*5f757f3fSDimitry Andric // imported patterns can select it later. Either way, it will be legal. 384*5f757f3fSDimitry Andric Register AmtReg = MI.getOperand(2).getReg(); 385*5f757f3fSDimitry Andric auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI); 386*5f757f3fSDimitry Andric if (!VRegAndVal) 387*5f757f3fSDimitry Andric return true; 388*5f757f3fSDimitry Andric // Check the shift amount is in range for an immediate form. 389*5f757f3fSDimitry Andric uint64_t Amount = VRegAndVal->Value.getZExtValue(); 390*5f757f3fSDimitry Andric if (Amount > 31) 391*5f757f3fSDimitry Andric return true; // This will have to remain a register variant. 392*5f757f3fSDimitry Andric auto ExtCst = MIRBuilder.buildConstant(LLT::scalar(64), Amount); 393*5f757f3fSDimitry Andric Observer.changingInstr(MI); 394*5f757f3fSDimitry Andric MI.getOperand(2).setReg(ExtCst.getReg(0)); 395*5f757f3fSDimitry Andric Observer.changedInstr(MI); 396*5f757f3fSDimitry Andric return true; 397*5f757f3fSDimitry Andric } 398*5f757f3fSDimitry Andric 399*5f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeVAStart(MachineInstr &MI, 400*5f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder) const { 401*5f757f3fSDimitry Andric // Stores the address of the VarArgsFrameIndex slot into the memory location 402*5f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_VASTART); 403*5f757f3fSDimitry Andric MachineFunction *MF = MI.getParent()->getParent(); 404*5f757f3fSDimitry Andric RISCVMachineFunctionInfo *FuncInfo = MF->getInfo<RISCVMachineFunctionInfo>(); 405*5f757f3fSDimitry Andric int FI = FuncInfo->getVarArgsFrameIndex(); 406*5f757f3fSDimitry Andric LLT AddrTy = MIRBuilder.getMRI()->getType(MI.getOperand(0).getReg()); 407*5f757f3fSDimitry Andric auto FINAddr = MIRBuilder.buildFrameIndex(AddrTy, FI); 408*5f757f3fSDimitry Andric assert(MI.hasOneMemOperand()); 409*5f757f3fSDimitry Andric MIRBuilder.buildStore(FINAddr, MI.getOperand(0).getReg(), 410*5f757f3fSDimitry Andric *MI.memoperands()[0]); 411*5f757f3fSDimitry Andric MI.eraseFromParent(); 412*5f757f3fSDimitry Andric return true; 413*5f757f3fSDimitry Andric } 414*5f757f3fSDimitry Andric 415*5f757f3fSDimitry Andric bool RISCVLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, 416*5f757f3fSDimitry Andric MachineInstr &MI) const { 417*5f757f3fSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 418*5f757f3fSDimitry Andric GISelChangeObserver &Observer = Helper.Observer; 419*5f757f3fSDimitry Andric switch (MI.getOpcode()) { 420*5f757f3fSDimitry Andric default: 421*5f757f3fSDimitry Andric // No idea what to do. 422*5f757f3fSDimitry Andric return false; 423*5f757f3fSDimitry Andric case TargetOpcode::G_ABS: 424*5f757f3fSDimitry Andric return Helper.lowerAbsToMaxNeg(MI); 425*5f757f3fSDimitry Andric case TargetOpcode::G_SHL: 426*5f757f3fSDimitry Andric case TargetOpcode::G_ASHR: 427*5f757f3fSDimitry Andric case TargetOpcode::G_LSHR: 428*5f757f3fSDimitry Andric return legalizeShlAshrLshr(MI, MIRBuilder, Observer); 429*5f757f3fSDimitry Andric case TargetOpcode::G_SEXT_INREG: { 430*5f757f3fSDimitry Andric // Source size of 32 is sext.w. 431*5f757f3fSDimitry Andric int64_t SizeInBits = MI.getOperand(2).getImm(); 432*5f757f3fSDimitry Andric if (SizeInBits == 32) 433*5f757f3fSDimitry Andric return true; 434*5f757f3fSDimitry Andric 435*5f757f3fSDimitry Andric return Helper.lower(MI, 0, /* Unused hint type */ LLT()) == 436*5f757f3fSDimitry Andric LegalizerHelper::Legalized; 437*5f757f3fSDimitry Andric } 438*5f757f3fSDimitry Andric case TargetOpcode::G_IS_FPCLASS: { 439*5f757f3fSDimitry Andric Register GISFPCLASS = MI.getOperand(0).getReg(); 440*5f757f3fSDimitry Andric Register Src = MI.getOperand(1).getReg(); 441*5f757f3fSDimitry Andric const MachineOperand &ImmOp = MI.getOperand(2); 442*5f757f3fSDimitry Andric MachineIRBuilder MIB(MI); 443*5f757f3fSDimitry Andric 444*5f757f3fSDimitry Andric // Turn LLVM IR's floating point classes to that in RISC-V, 445*5f757f3fSDimitry Andric // by simply rotating the 10-bit immediate right by two bits. 446*5f757f3fSDimitry Andric APInt GFpClassImm(10, static_cast<uint64_t>(ImmOp.getImm())); 447*5f757f3fSDimitry Andric auto FClassMask = MIB.buildConstant(sXLen, GFpClassImm.rotr(2).zext(XLen)); 448*5f757f3fSDimitry Andric auto ConstZero = MIB.buildConstant(sXLen, 0); 449*5f757f3fSDimitry Andric 450*5f757f3fSDimitry Andric auto GFClass = MIB.buildInstr(RISCV::G_FCLASS, {sXLen}, {Src}); 451*5f757f3fSDimitry Andric auto And = MIB.buildAnd(sXLen, GFClass, FClassMask); 452*5f757f3fSDimitry Andric MIB.buildICmp(CmpInst::ICMP_NE, GISFPCLASS, And, ConstZero); 453*5f757f3fSDimitry Andric 454*5f757f3fSDimitry Andric MI.eraseFromParent(); 455*5f757f3fSDimitry Andric return true; 456*5f757f3fSDimitry Andric } 457*5f757f3fSDimitry Andric case TargetOpcode::G_VASTART: 458*5f757f3fSDimitry Andric return legalizeVAStart(MI, MIRBuilder); 459*5f757f3fSDimitry Andric } 460*5f757f3fSDimitry Andric 461*5f757f3fSDimitry Andric llvm_unreachable("expected switch to return"); 462*5f757f3fSDimitry Andric } 463