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