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