1 //===- MipsLegalizerInfo.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 Mips. 10 /// \todo This should be generated by TableGen. 11 //===----------------------------------------------------------------------===// 12 13 #include "MipsLegalizerInfo.h" 14 #include "MipsTargetMachine.h" 15 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 16 #include "llvm/IR/IntrinsicsMips.h" 17 18 using namespace llvm; 19 20 struct TypesAndMemOps { 21 LLT ValTy; 22 LLT PtrTy; 23 unsigned MemSize; 24 bool MustBeNaturallyAligned; 25 }; 26 27 static bool 28 CheckTy0Ty1MemSizeAlign(const LegalityQuery &Query, 29 std::initializer_list<TypesAndMemOps> SupportedValues) { 30 for (auto &Val : SupportedValues) { 31 if (Val.ValTy != Query.Types[0]) 32 continue; 33 if (Val.PtrTy != Query.Types[1]) 34 continue; 35 if (Val.MemSize != Query.MMODescrs[0].SizeInBits) 36 continue; 37 if (Val.MustBeNaturallyAligned && 38 Query.MMODescrs[0].SizeInBits % Query.MMODescrs[0].AlignInBits != 0) 39 continue; 40 return true; 41 } 42 return false; 43 } 44 45 static bool CheckTyN(unsigned N, const LegalityQuery &Query, 46 std::initializer_list<LLT> SupportedValues) { 47 for (auto &Val : SupportedValues) 48 if (Val == Query.Types[N]) 49 return true; 50 return false; 51 } 52 53 MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) { 54 using namespace TargetOpcode; 55 56 const LLT s1 = LLT::scalar(1); 57 const LLT s32 = LLT::scalar(32); 58 const LLT s64 = LLT::scalar(64); 59 const LLT v16s8 = LLT::vector(16, 8); 60 const LLT v8s16 = LLT::vector(8, 16); 61 const LLT v4s32 = LLT::vector(4, 32); 62 const LLT v2s64 = LLT::vector(2, 64); 63 const LLT p0 = LLT::pointer(0, 32); 64 65 getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL}) 66 .legalIf([=, &ST](const LegalityQuery &Query) { 67 if (CheckTyN(0, Query, {s32})) 68 return true; 69 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64})) 70 return true; 71 return false; 72 }) 73 .clampScalar(0, s32, s32); 74 75 getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO}) 76 .lowerFor({{s32, s1}}); 77 78 getActionDefinitionsBuilder(G_UMULH) 79 .legalFor({s32}) 80 .maxScalar(0, s32); 81 82 getActionDefinitionsBuilder({G_LOAD, G_STORE}) 83 .legalIf([=, &ST](const LegalityQuery &Query) { 84 if (CheckTy0Ty1MemSizeAlign(Query, {{s32, p0, 8, ST.hasMips32r6()}, 85 {s32, p0, 16, ST.hasMips32r6()}, 86 {s32, p0, 32, ST.hasMips32r6()}, 87 {p0, p0, 32, ST.hasMips32r6()}, 88 {s64, p0, 64, ST.hasMips32r6()}})) 89 return true; 90 if (ST.hasMSA() && 91 CheckTy0Ty1MemSizeAlign(Query, {{v16s8, p0, 128, false}, 92 {v8s16, p0, 128, false}, 93 {v4s32, p0, 128, false}, 94 {v2s64, p0, 128, false}})) 95 return true; 96 return false; 97 }) 98 .minScalar(0, s32); 99 100 getActionDefinitionsBuilder(G_IMPLICIT_DEF) 101 .legalFor({s32, s64}); 102 103 getActionDefinitionsBuilder(G_UNMERGE_VALUES) 104 .legalFor({{s32, s64}}); 105 106 getActionDefinitionsBuilder(G_MERGE_VALUES) 107 .legalFor({{s64, s32}}); 108 109 getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD}) 110 .legalForTypesWithMemDesc({{s32, p0, 8, 8}, 111 {s32, p0, 16, 8}}) 112 .clampScalar(0, s32, s32); 113 114 getActionDefinitionsBuilder({G_ZEXT, G_SEXT}) 115 .legalIf([](const LegalityQuery &Query) { return false; }) 116 .maxScalar(0, s32); 117 118 getActionDefinitionsBuilder(G_TRUNC) 119 .legalIf([](const LegalityQuery &Query) { return false; }) 120 .maxScalar(1, s32); 121 122 getActionDefinitionsBuilder(G_SELECT) 123 .legalForCartesianProduct({p0, s32, s64}, {s32}) 124 .minScalar(0, s32) 125 .minScalar(1, s32); 126 127 getActionDefinitionsBuilder(G_BRCOND) 128 .legalFor({s32}) 129 .minScalar(0, s32); 130 131 getActionDefinitionsBuilder(G_BRJT) 132 .legalFor({{p0, s32}}); 133 134 getActionDefinitionsBuilder(G_BRINDIRECT) 135 .legalFor({p0}); 136 137 getActionDefinitionsBuilder(G_PHI) 138 .legalFor({p0, s32, s64}) 139 .minScalar(0, s32); 140 141 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) 142 .legalFor({s32}) 143 .clampScalar(0, s32, s32); 144 145 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM}) 146 .legalIf([=, &ST](const LegalityQuery &Query) { 147 if (CheckTyN(0, Query, {s32})) 148 return true; 149 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64})) 150 return true; 151 return false; 152 }) 153 .minScalar(0, s32) 154 .libcallFor({s64}); 155 156 getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR}) 157 .legalFor({{s32, s32}}) 158 .clampScalar(1, s32, s32) 159 .clampScalar(0, s32, s32); 160 161 getActionDefinitionsBuilder(G_ICMP) 162 .legalForCartesianProduct({s32}, {s32, p0}) 163 .clampScalar(1, s32, s32) 164 .minScalar(0, s32); 165 166 getActionDefinitionsBuilder(G_CONSTANT) 167 .legalFor({s32}) 168 .clampScalar(0, s32, s32); 169 170 getActionDefinitionsBuilder({G_PTR_ADD, G_INTTOPTR}) 171 .legalFor({{p0, s32}}); 172 173 getActionDefinitionsBuilder(G_PTRTOINT) 174 .legalFor({{s32, p0}}); 175 176 getActionDefinitionsBuilder(G_FRAME_INDEX) 177 .legalFor({p0}); 178 179 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE}) 180 .legalFor({p0}); 181 182 getActionDefinitionsBuilder(G_DYN_STACKALLOC) 183 .lowerFor({{p0, s32}}); 184 185 getActionDefinitionsBuilder(G_VASTART) 186 .legalFor({p0}); 187 188 getActionDefinitionsBuilder(G_BSWAP) 189 .legalIf([=, &ST](const LegalityQuery &Query) { 190 if (ST.hasMips32r2() && CheckTyN(0, Query, {s32})) 191 return true; 192 return false; 193 }) 194 .lowerIf([=, &ST](const LegalityQuery &Query) { 195 if (!ST.hasMips32r2() && CheckTyN(0, Query, {s32})) 196 return true; 197 return false; 198 }) 199 .maxScalar(0, s32); 200 201 getActionDefinitionsBuilder(G_BITREVERSE) 202 .lowerFor({s32}) 203 .maxScalar(0, s32); 204 205 getActionDefinitionsBuilder(G_CTLZ) 206 .legalFor({{s32, s32}}) 207 .maxScalar(0, s32) 208 .maxScalar(1, s32); 209 getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF) 210 .lowerFor({{s32, s32}}); 211 212 getActionDefinitionsBuilder(G_CTTZ) 213 .lowerFor({{s32, s32}}) 214 .maxScalar(0, s32) 215 .maxScalar(1, s32); 216 getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF) 217 .lowerFor({{s32, s32}, {s64, s64}}); 218 219 getActionDefinitionsBuilder(G_CTPOP) 220 .lowerFor({{s32, s32}}) 221 .clampScalar(0, s32, s32) 222 .clampScalar(1, s32, s32); 223 224 // FP instructions 225 getActionDefinitionsBuilder(G_FCONSTANT) 226 .legalFor({s32, s64}); 227 228 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT}) 229 .legalIf([=, &ST](const LegalityQuery &Query) { 230 if (CheckTyN(0, Query, {s32, s64})) 231 return true; 232 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64})) 233 return true; 234 return false; 235 }); 236 237 getActionDefinitionsBuilder(G_FCMP) 238 .legalFor({{s32, s32}, {s32, s64}}) 239 .minScalar(0, s32); 240 241 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR}) 242 .libcallFor({s32, s64}); 243 244 getActionDefinitionsBuilder(G_FPEXT) 245 .legalFor({{s64, s32}}); 246 247 getActionDefinitionsBuilder(G_FPTRUNC) 248 .legalFor({{s32, s64}}); 249 250 // FP to int conversion instructions 251 getActionDefinitionsBuilder(G_FPTOSI) 252 .legalForCartesianProduct({s32}, {s64, s32}) 253 .libcallForCartesianProduct({s64}, {s64, s32}) 254 .minScalar(0, s32); 255 256 getActionDefinitionsBuilder(G_FPTOUI) 257 .libcallForCartesianProduct({s64}, {s64, s32}) 258 .lowerForCartesianProduct({s32}, {s64, s32}) 259 .minScalar(0, s32); 260 261 // Int to FP conversion instructions 262 getActionDefinitionsBuilder(G_SITOFP) 263 .legalForCartesianProduct({s64, s32}, {s32}) 264 .libcallForCartesianProduct({s64, s32}, {s64}) 265 .minScalar(1, s32); 266 267 getActionDefinitionsBuilder(G_UITOFP) 268 .libcallForCartesianProduct({s64, s32}, {s64}) 269 .customForCartesianProduct({s64, s32}, {s32}) 270 .minScalar(1, s32); 271 272 getActionDefinitionsBuilder(G_SEXT_INREG).lower(); 273 274 computeTables(); 275 verify(*ST.getInstrInfo()); 276 } 277 278 bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI, 279 MachineRegisterInfo &MRI, 280 MachineIRBuilder &MIRBuilder, 281 GISelChangeObserver &Observer) const { 282 283 using namespace TargetOpcode; 284 285 MIRBuilder.setInstr(MI); 286 const MipsSubtarget &STI = 287 static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget()); 288 const LLT s32 = LLT::scalar(32); 289 const LLT s64 = LLT::scalar(64); 290 291 switch (MI.getOpcode()) { 292 case G_UITOFP: { 293 Register Dst = MI.getOperand(0).getReg(); 294 Register Src = MI.getOperand(1).getReg(); 295 LLT DstTy = MRI.getType(Dst); 296 LLT SrcTy = MRI.getType(Src); 297 298 if (SrcTy != s32) 299 return false; 300 if (DstTy != s32 && DstTy != s64) 301 return false; 302 303 // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert 304 // unsigned to double. Mantissa has 52 bits so we use following trick: 305 // First make floating point bit mask 0x43300000ABCDEFGH. 306 // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 . 307 // Next, subtract 2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it. 308 // Done. Trunc double to float if needed. 309 310 MachineInstrBuilder Bitcast = MIRBuilder.buildInstr( 311 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64}, 312 {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))}); 313 Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(), 314 *STI.getRegBankInfo()); 315 316 MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant( 317 s64, BitsToDouble(UINT64_C(0x4330000000000000))); 318 319 if (DstTy == s64) 320 MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP); 321 else { 322 MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP); 323 MIRBuilder.buildFPTrunc(Dst, ResF64); 324 } 325 326 MI.eraseFromParent(); 327 break; 328 } 329 default: 330 return false; 331 } 332 333 return true; 334 } 335 336 static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode, 337 MachineIRBuilder &MIRBuilder, 338 const MipsSubtarget &ST) { 339 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 340 if (!MIRBuilder.buildInstr(Opcode) 341 .add(MI.getOperand(0)) 342 .add(MI.getOperand(2)) 343 .add(MI.getOperand(3)) 344 .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(), 345 *ST.getRegBankInfo())) 346 return false; 347 MI.eraseFromParent(); 348 return true; 349 } 350 351 static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, 352 MachineIRBuilder &MIRBuilder, 353 const MipsSubtarget &ST) { 354 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 355 MIRBuilder.buildInstr(Opcode) 356 .add(MI.getOperand(0)) 357 .add(MI.getOperand(2)) 358 .add(MI.getOperand(3)); 359 MI.eraseFromParent(); 360 return true; 361 } 362 363 static bool MSA2OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, 364 MachineIRBuilder &MIRBuilder, 365 const MipsSubtarget &ST) { 366 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 367 MIRBuilder.buildInstr(Opcode) 368 .add(MI.getOperand(0)) 369 .add(MI.getOperand(2)); 370 MI.eraseFromParent(); 371 return true; 372 } 373 374 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI, 375 MachineIRBuilder &MIRBuilder, 376 GISelChangeObserver &Observer) const { 377 MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 378 const MipsSubtarget &ST = 379 static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget()); 380 const MipsInstrInfo &TII = *ST.getInstrInfo(); 381 const MipsRegisterInfo &TRI = *ST.getRegisterInfo(); 382 const RegisterBankInfo &RBI = *ST.getRegBankInfo(); 383 MIRBuilder.setInstr(MI); 384 385 switch (MI.getIntrinsicID()) { 386 case Intrinsic::memcpy: 387 case Intrinsic::memset: 388 case Intrinsic::memmove: 389 if (createMemLibcall(MIRBuilder, MRI, MI) == 390 LegalizerHelper::UnableToLegalize) 391 return false; 392 MI.eraseFromParent(); 393 return true; 394 case Intrinsic::trap: { 395 MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP); 396 MI.eraseFromParent(); 397 return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI); 398 } 399 case Intrinsic::vacopy: { 400 MachinePointerInfo MPO; 401 auto Tmp = MIRBuilder.buildLoad(LLT::pointer(0, 32), MI.getOperand(2), 402 *MI.getMF()->getMachineMemOperand( 403 MPO, MachineMemOperand::MOLoad, 4, 4)); 404 MIRBuilder.buildStore(Tmp, MI.getOperand(1), 405 *MI.getMF()->getMachineMemOperand( 406 MPO, MachineMemOperand::MOStore, 4, 4)); 407 MI.eraseFromParent(); 408 return true; 409 } 410 case Intrinsic::mips_addv_b: 411 case Intrinsic::mips_addv_h: 412 case Intrinsic::mips_addv_w: 413 case Intrinsic::mips_addv_d: 414 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_ADD, MIRBuilder, ST); 415 case Intrinsic::mips_addvi_b: 416 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_B, MIRBuilder, ST); 417 case Intrinsic::mips_addvi_h: 418 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_H, MIRBuilder, ST); 419 case Intrinsic::mips_addvi_w: 420 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_W, MIRBuilder, ST); 421 case Intrinsic::mips_addvi_d: 422 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_D, MIRBuilder, ST); 423 case Intrinsic::mips_subv_b: 424 case Intrinsic::mips_subv_h: 425 case Intrinsic::mips_subv_w: 426 case Intrinsic::mips_subv_d: 427 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SUB, MIRBuilder, ST); 428 case Intrinsic::mips_subvi_b: 429 return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_B, MIRBuilder, ST); 430 case Intrinsic::mips_subvi_h: 431 return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_H, MIRBuilder, ST); 432 case Intrinsic::mips_subvi_w: 433 return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_W, MIRBuilder, ST); 434 case Intrinsic::mips_subvi_d: 435 return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_D, MIRBuilder, ST); 436 case Intrinsic::mips_mulv_b: 437 case Intrinsic::mips_mulv_h: 438 case Intrinsic::mips_mulv_w: 439 case Intrinsic::mips_mulv_d: 440 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_MUL, MIRBuilder, ST); 441 case Intrinsic::mips_div_s_b: 442 case Intrinsic::mips_div_s_h: 443 case Intrinsic::mips_div_s_w: 444 case Intrinsic::mips_div_s_d: 445 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SDIV, MIRBuilder, ST); 446 case Intrinsic::mips_mod_s_b: 447 case Intrinsic::mips_mod_s_h: 448 case Intrinsic::mips_mod_s_w: 449 case Intrinsic::mips_mod_s_d: 450 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SREM, MIRBuilder, ST); 451 case Intrinsic::mips_div_u_b: 452 case Intrinsic::mips_div_u_h: 453 case Intrinsic::mips_div_u_w: 454 case Intrinsic::mips_div_u_d: 455 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_UDIV, MIRBuilder, ST); 456 case Intrinsic::mips_mod_u_b: 457 case Intrinsic::mips_mod_u_h: 458 case Intrinsic::mips_mod_u_w: 459 case Intrinsic::mips_mod_u_d: 460 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_UREM, MIRBuilder, ST); 461 case Intrinsic::mips_fadd_w: 462 case Intrinsic::mips_fadd_d: 463 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FADD, MIRBuilder, ST); 464 case Intrinsic::mips_fsub_w: 465 case Intrinsic::mips_fsub_d: 466 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FSUB, MIRBuilder, ST); 467 case Intrinsic::mips_fmul_w: 468 case Intrinsic::mips_fmul_d: 469 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FMUL, MIRBuilder, ST); 470 case Intrinsic::mips_fdiv_w: 471 case Intrinsic::mips_fdiv_d: 472 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FDIV, MIRBuilder, ST); 473 case Intrinsic::mips_fmax_a_w: 474 return SelectMSA3OpIntrinsic(MI, Mips::FMAX_A_W, MIRBuilder, ST); 475 case Intrinsic::mips_fmax_a_d: 476 return SelectMSA3OpIntrinsic(MI, Mips::FMAX_A_D, MIRBuilder, ST); 477 case Intrinsic::mips_fsqrt_w: 478 return MSA2OpIntrinsicToGeneric(MI, TargetOpcode::G_FSQRT, MIRBuilder, ST); 479 case Intrinsic::mips_fsqrt_d: 480 return MSA2OpIntrinsicToGeneric(MI, TargetOpcode::G_FSQRT, MIRBuilder, ST); 481 default: 482 break; 483 } 484 return true; 485 } 486