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