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