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_SUB, G_MUL}) 65 .legalFor({s32}) 66 .clampScalar(0, s32, s32); 67 68 getActionDefinitionsBuilder(G_ADD) 69 .legalIf([=, &ST](const LegalityQuery &Query) { 70 if (CheckTyN(0, Query, {s32})) 71 return true; 72 if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64})) 73 return true; 74 return false; 75 }) 76 .clampScalar(0, s32, s32); 77 78 getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO}) 79 .lowerFor({{s32, s1}}); 80 81 getActionDefinitionsBuilder(G_UMULH) 82 .legalFor({s32}) 83 .maxScalar(0, s32); 84 85 getActionDefinitionsBuilder({G_LOAD, G_STORE}) 86 .legalIf([=, &ST](const LegalityQuery &Query) { 87 if (CheckTy0Ty1MemSizeAlign(Query, {{s32, p0, 8, ST.hasMips32r6()}, 88 {s32, p0, 16, ST.hasMips32r6()}, 89 {s32, p0, 32, ST.hasMips32r6()}, 90 {p0, p0, 32, ST.hasMips32r6()}, 91 {s64, p0, 64, ST.hasMips32r6()}})) 92 return true; 93 if (ST.hasMSA() && 94 CheckTy0Ty1MemSizeAlign(Query, {{v16s8, p0, 128, false}, 95 {v8s16, p0, 128, false}, 96 {v4s32, p0, 128, false}, 97 {v2s64, p0, 128, false}})) 98 return true; 99 return false; 100 }) 101 .minScalar(0, s32); 102 103 getActionDefinitionsBuilder(G_IMPLICIT_DEF) 104 .legalFor({s32, s64}); 105 106 getActionDefinitionsBuilder(G_UNMERGE_VALUES) 107 .legalFor({{s32, s64}}); 108 109 getActionDefinitionsBuilder(G_MERGE_VALUES) 110 .legalFor({{s64, s32}}); 111 112 getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD}) 113 .legalForTypesWithMemDesc({{s32, p0, 8, 8}, 114 {s32, p0, 16, 8}}) 115 .clampScalar(0, s32, s32); 116 117 getActionDefinitionsBuilder({G_ZEXT, G_SEXT}) 118 .legalIf([](const LegalityQuery &Query) { return false; }) 119 .maxScalar(0, s32); 120 121 getActionDefinitionsBuilder(G_TRUNC) 122 .legalIf([](const LegalityQuery &Query) { return false; }) 123 .maxScalar(1, s32); 124 125 getActionDefinitionsBuilder(G_SELECT) 126 .legalForCartesianProduct({p0, s32, s64}, {s32}) 127 .minScalar(0, s32) 128 .minScalar(1, s32); 129 130 getActionDefinitionsBuilder(G_BRCOND) 131 .legalFor({s32}) 132 .minScalar(0, s32); 133 134 getActionDefinitionsBuilder(G_BRJT) 135 .legalFor({{p0, s32}}); 136 137 getActionDefinitionsBuilder(G_BRINDIRECT) 138 .legalFor({p0}); 139 140 getActionDefinitionsBuilder(G_PHI) 141 .legalFor({p0, s32, s64}) 142 .minScalar(0, s32); 143 144 getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) 145 .legalFor({s32}) 146 .clampScalar(0, s32, s32); 147 148 getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UREM, G_UDIV}) 149 .legalFor({s32}) 150 .minScalar(0, s32) 151 .libcallFor({s64}); 152 153 getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR}) 154 .legalFor({{s32, s32}}) 155 .clampScalar(1, s32, s32) 156 .clampScalar(0, s32, s32); 157 158 getActionDefinitionsBuilder(G_ICMP) 159 .legalForCartesianProduct({s32}, {s32, p0}) 160 .clampScalar(1, s32, s32) 161 .minScalar(0, s32); 162 163 getActionDefinitionsBuilder(G_CONSTANT) 164 .legalFor({s32}) 165 .clampScalar(0, s32, s32); 166 167 getActionDefinitionsBuilder({G_GEP, G_INTTOPTR}) 168 .legalFor({{p0, s32}}); 169 170 getActionDefinitionsBuilder(G_PTRTOINT) 171 .legalFor({{s32, p0}}); 172 173 getActionDefinitionsBuilder(G_FRAME_INDEX) 174 .legalFor({p0}); 175 176 getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE}) 177 .legalFor({p0}); 178 179 getActionDefinitionsBuilder(G_DYN_STACKALLOC) 180 .lowerFor({{p0, s32}}); 181 182 getActionDefinitionsBuilder(G_VASTART) 183 .legalFor({p0}); 184 185 // FP instructions 186 getActionDefinitionsBuilder(G_FCONSTANT) 187 .legalFor({s32, s64}); 188 189 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT}) 190 .legalFor({s32, s64}); 191 192 getActionDefinitionsBuilder(G_FCMP) 193 .legalFor({{s32, s32}, {s32, s64}}) 194 .minScalar(0, s32); 195 196 getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR}) 197 .libcallFor({s32, s64}); 198 199 getActionDefinitionsBuilder(G_FPEXT) 200 .legalFor({{s64, s32}}); 201 202 getActionDefinitionsBuilder(G_FPTRUNC) 203 .legalFor({{s32, s64}}); 204 205 // FP to int conversion instructions 206 getActionDefinitionsBuilder(G_FPTOSI) 207 .legalForCartesianProduct({s32}, {s64, s32}) 208 .libcallForCartesianProduct({s64}, {s64, s32}) 209 .minScalar(0, s32); 210 211 getActionDefinitionsBuilder(G_FPTOUI) 212 .libcallForCartesianProduct({s64}, {s64, s32}) 213 .lowerForCartesianProduct({s32}, {s64, s32}) 214 .minScalar(0, s32); 215 216 // Int to FP conversion instructions 217 getActionDefinitionsBuilder(G_SITOFP) 218 .legalForCartesianProduct({s64, s32}, {s32}) 219 .libcallForCartesianProduct({s64, s32}, {s64}) 220 .minScalar(1, s32); 221 222 getActionDefinitionsBuilder(G_UITOFP) 223 .libcallForCartesianProduct({s64, s32}, {s64}) 224 .customForCartesianProduct({s64, s32}, {s32}) 225 .minScalar(1, s32); 226 227 getActionDefinitionsBuilder(G_SEXT_INREG).lower(); 228 229 computeTables(); 230 verify(*ST.getInstrInfo()); 231 } 232 233 bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI, 234 MachineRegisterInfo &MRI, 235 MachineIRBuilder &MIRBuilder, 236 GISelChangeObserver &Observer) const { 237 238 using namespace TargetOpcode; 239 240 MIRBuilder.setInstr(MI); 241 const MipsSubtarget &STI = 242 static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget()); 243 const LLT s32 = LLT::scalar(32); 244 const LLT s64 = LLT::scalar(64); 245 246 switch (MI.getOpcode()) { 247 case G_UITOFP: { 248 Register Dst = MI.getOperand(0).getReg(); 249 Register Src = MI.getOperand(1).getReg(); 250 LLT DstTy = MRI.getType(Dst); 251 LLT SrcTy = MRI.getType(Src); 252 253 if (SrcTy != s32) 254 return false; 255 if (DstTy != s32 && DstTy != s64) 256 return false; 257 258 // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert 259 // unsigned to double. Mantissa has 52 bits so we use following trick: 260 // First make floating point bit mask 0x43300000ABCDEFGH. 261 // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 . 262 // Next, subtract 2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it. 263 // Done. Trunc double to float if needed. 264 265 MachineInstrBuilder Bitcast = MIRBuilder.buildInstr( 266 STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64}, 267 {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))}); 268 Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(), 269 *STI.getRegBankInfo()); 270 271 MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant( 272 s64, BitsToDouble(UINT64_C(0x4330000000000000))); 273 274 if (DstTy == s64) 275 MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP); 276 else { 277 MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP); 278 MIRBuilder.buildFPTrunc(Dst, ResF64); 279 } 280 281 MI.eraseFromParent(); 282 break; 283 } 284 default: 285 return false; 286 } 287 288 return true; 289 } 290 291 static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode, 292 MachineIRBuilder &MIRBuilder, 293 const MipsSubtarget &ST) { 294 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 295 if (!MIRBuilder.buildInstr(Opcode) 296 .add(MI.getOperand(0)) 297 .add(MI.getOperand(2)) 298 .add(MI.getOperand(3)) 299 .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(), 300 *ST.getRegBankInfo())) 301 return false; 302 MI.eraseFromParent(); 303 return true; 304 } 305 306 static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, 307 MachineIRBuilder &MIRBuilder, 308 const MipsSubtarget &ST) { 309 assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 310 MIRBuilder.buildInstr(Opcode) 311 .add(MI.getOperand(0)) 312 .add(MI.getOperand(2)) 313 .add(MI.getOperand(3)); 314 MI.eraseFromParent(); 315 return true; 316 } 317 318 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI, 319 MachineRegisterInfo &MRI, 320 MachineIRBuilder &MIRBuilder) const { 321 const MipsSubtarget &ST = 322 static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget()); 323 const MipsInstrInfo &TII = *ST.getInstrInfo(); 324 const MipsRegisterInfo &TRI = *ST.getRegisterInfo(); 325 const RegisterBankInfo &RBI = *ST.getRegBankInfo(); 326 MIRBuilder.setInstr(MI); 327 328 switch (MI.getIntrinsicID()) { 329 case Intrinsic::memcpy: 330 case Intrinsic::memset: 331 case Intrinsic::memmove: 332 if (createMemLibcall(MIRBuilder, MRI, MI) == 333 LegalizerHelper::UnableToLegalize) 334 return false; 335 MI.eraseFromParent(); 336 return true; 337 case Intrinsic::trap: { 338 MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP); 339 MI.eraseFromParent(); 340 return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI); 341 } 342 case Intrinsic::vacopy: { 343 Register Tmp = MRI.createGenericVirtualRegister(LLT::pointer(0, 32)); 344 MachinePointerInfo MPO; 345 MIRBuilder.buildLoad(Tmp, MI.getOperand(2), 346 *MI.getMF()->getMachineMemOperand( 347 MPO, MachineMemOperand::MOLoad, 4, 4)); 348 MIRBuilder.buildStore(Tmp, MI.getOperand(1), 349 *MI.getMF()->getMachineMemOperand( 350 MPO, MachineMemOperand::MOStore, 4, 4)); 351 MI.eraseFromParent(); 352 return true; 353 } 354 case Intrinsic::mips_addv_b: 355 case Intrinsic::mips_addv_h: 356 case Intrinsic::mips_addv_w: 357 case Intrinsic::mips_addv_d: 358 return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_ADD, MIRBuilder, ST); 359 case Intrinsic::mips_addvi_b: 360 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_B, MIRBuilder, ST); 361 case Intrinsic::mips_addvi_h: 362 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_H, MIRBuilder, ST); 363 case Intrinsic::mips_addvi_w: 364 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_W, MIRBuilder, ST); 365 case Intrinsic::mips_addvi_d: 366 return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_D, MIRBuilder, ST); 367 default: 368 break; 369 } 370 return true; 371 } 372