10b57cec5SDimitry Andric //===- MipsLegalizerInfo.cpp ------------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// This file implements the targeting of the Machinelegalizer class for Mips. 100b57cec5SDimitry Andric /// \todo This should be generated by TableGen. 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "MipsLegalizerInfo.h" 140b57cec5SDimitry Andric #include "MipsTargetMachine.h" 155f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 1781ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 18480093f4SDimitry Andric #include "llvm/IR/IntrinsicsMips.h" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric using namespace llvm; 210b57cec5SDimitry Andric 228bcb0991SDimitry Andric struct TypesAndMemOps { 238bcb0991SDimitry Andric LLT ValTy; 248bcb0991SDimitry Andric LLT PtrTy; 258bcb0991SDimitry Andric unsigned MemSize; 265ffd83dbSDimitry Andric bool SystemSupportsUnalignedAccess; 278bcb0991SDimitry Andric }; 288bcb0991SDimitry Andric 295ffd83dbSDimitry Andric // Assumes power of 2 memory size. Subtargets that have only naturally-aligned 305ffd83dbSDimitry Andric // memory access need to perform additional legalization here. 315ffd83dbSDimitry Andric static bool isUnalignedMemmoryAccess(uint64_t MemSize, uint64_t AlignInBits) { 325ffd83dbSDimitry Andric assert(isPowerOf2_64(MemSize) && "Expected power of 2 memory size"); 335ffd83dbSDimitry Andric assert(isPowerOf2_64(AlignInBits) && "Expected power of 2 align"); 345ffd83dbSDimitry Andric if (MemSize > AlignInBits) 355ffd83dbSDimitry Andric return true; 365ffd83dbSDimitry Andric return false; 375ffd83dbSDimitry Andric } 385ffd83dbSDimitry Andric 398bcb0991SDimitry Andric static bool 408bcb0991SDimitry Andric CheckTy0Ty1MemSizeAlign(const LegalityQuery &Query, 418bcb0991SDimitry Andric std::initializer_list<TypesAndMemOps> SupportedValues) { 42fe6060f1SDimitry Andric unsigned QueryMemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits(); 435ffd83dbSDimitry Andric 445ffd83dbSDimitry Andric // Non power of two memory access is never legal. 455ffd83dbSDimitry Andric if (!isPowerOf2_64(QueryMemSize)) 465ffd83dbSDimitry Andric return false; 475ffd83dbSDimitry Andric 488bcb0991SDimitry Andric for (auto &Val : SupportedValues) { 498bcb0991SDimitry Andric if (Val.ValTy != Query.Types[0]) 508bcb0991SDimitry Andric continue; 518bcb0991SDimitry Andric if (Val.PtrTy != Query.Types[1]) 528bcb0991SDimitry Andric continue; 535ffd83dbSDimitry Andric if (Val.MemSize != QueryMemSize) 548bcb0991SDimitry Andric continue; 555ffd83dbSDimitry Andric if (!Val.SystemSupportsUnalignedAccess && 565ffd83dbSDimitry Andric isUnalignedMemmoryAccess(QueryMemSize, Query.MMODescrs[0].AlignInBits)) 575ffd83dbSDimitry Andric return false; 588bcb0991SDimitry Andric return true; 598bcb0991SDimitry Andric } 608bcb0991SDimitry Andric return false; 618bcb0991SDimitry Andric } 628bcb0991SDimitry Andric 638bcb0991SDimitry Andric static bool CheckTyN(unsigned N, const LegalityQuery &Query, 648bcb0991SDimitry Andric std::initializer_list<LLT> SupportedValues) { 65fe6060f1SDimitry Andric return llvm::is_contained(SupportedValues, Query.Types[N]); 668bcb0991SDimitry Andric } 678bcb0991SDimitry Andric 680b57cec5SDimitry Andric MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) { 690b57cec5SDimitry Andric using namespace TargetOpcode; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric const LLT s1 = LLT::scalar(1); 72fe6060f1SDimitry Andric const LLT s8 = LLT::scalar(8); 73fe6060f1SDimitry Andric const LLT s16 = LLT::scalar(16); 740b57cec5SDimitry Andric const LLT s32 = LLT::scalar(32); 750b57cec5SDimitry Andric const LLT s64 = LLT::scalar(64); 76fe6060f1SDimitry Andric const LLT v16s8 = LLT::fixed_vector(16, 8); 77fe6060f1SDimitry Andric const LLT v8s16 = LLT::fixed_vector(8, 16); 78fe6060f1SDimitry Andric const LLT v4s32 = LLT::fixed_vector(4, 32); 79fe6060f1SDimitry Andric const LLT v2s64 = LLT::fixed_vector(2, 64); 800b57cec5SDimitry Andric const LLT p0 = LLT::pointer(0, 32); 810b57cec5SDimitry Andric 82480093f4SDimitry Andric getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL}) 838bcb0991SDimitry Andric .legalIf([=, &ST](const LegalityQuery &Query) { 848bcb0991SDimitry Andric if (CheckTyN(0, Query, {s32})) 858bcb0991SDimitry Andric return true; 868bcb0991SDimitry Andric if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64})) 878bcb0991SDimitry Andric return true; 888bcb0991SDimitry Andric return false; 898bcb0991SDimitry Andric }) 908bcb0991SDimitry Andric .clampScalar(0, s32, s32); 918bcb0991SDimitry Andric 920b57cec5SDimitry Andric getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO}) 930b57cec5SDimitry Andric .lowerFor({{s32, s1}}); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric getActionDefinitionsBuilder(G_UMULH) 960b57cec5SDimitry Andric .legalFor({s32}) 970b57cec5SDimitry Andric .maxScalar(0, s32); 980b57cec5SDimitry Andric 995ffd83dbSDimitry Andric // MIPS32r6 does not have alignment restrictions for memory access. 1005ffd83dbSDimitry Andric // For MIPS32r5 and older memory access must be naturally-aligned i.e. aligned 1015ffd83dbSDimitry Andric // to at least a multiple of its own size. There is however a two instruction 1025ffd83dbSDimitry Andric // combination that performs 4 byte unaligned access (lwr/lwl and swl/swr) 1035ffd83dbSDimitry Andric // therefore 4 byte load and store are legal and will use NoAlignRequirements. 1045ffd83dbSDimitry Andric bool NoAlignRequirements = true; 1055ffd83dbSDimitry Andric 1060b57cec5SDimitry Andric getActionDefinitionsBuilder({G_LOAD, G_STORE}) 1078bcb0991SDimitry Andric .legalIf([=, &ST](const LegalityQuery &Query) { 1085ffd83dbSDimitry Andric if (CheckTy0Ty1MemSizeAlign( 1095ffd83dbSDimitry Andric Query, {{s32, p0, 8, NoAlignRequirements}, 1105ffd83dbSDimitry Andric {s32, p0, 16, ST.systemSupportsUnalignedAccess()}, 1115ffd83dbSDimitry Andric {s32, p0, 32, NoAlignRequirements}, 1125ffd83dbSDimitry Andric {p0, p0, 32, NoAlignRequirements}, 1135ffd83dbSDimitry Andric {s64, p0, 64, ST.systemSupportsUnalignedAccess()}})) 1148bcb0991SDimitry Andric return true; 1155ffd83dbSDimitry Andric if (ST.hasMSA() && CheckTy0Ty1MemSizeAlign( 1165ffd83dbSDimitry Andric Query, {{v16s8, p0, 128, NoAlignRequirements}, 1175ffd83dbSDimitry Andric {v8s16, p0, 128, NoAlignRequirements}, 1185ffd83dbSDimitry Andric {v4s32, p0, 128, NoAlignRequirements}, 1195ffd83dbSDimitry Andric {v2s64, p0, 128, NoAlignRequirements}})) 1208bcb0991SDimitry Andric return true; 1218bcb0991SDimitry Andric return false; 1228bcb0991SDimitry Andric }) 1235ffd83dbSDimitry Andric // Custom lower scalar memory access, up to 8 bytes, for: 1245ffd83dbSDimitry Andric // - non-power-of-2 MemSizes 1255ffd83dbSDimitry Andric // - unaligned 2 or 8 byte MemSizes for MIPS32r5 and older 1265ffd83dbSDimitry Andric .customIf([=, &ST](const LegalityQuery &Query) { 1275ffd83dbSDimitry Andric if (!Query.Types[0].isScalar() || Query.Types[1] != p0 || 1285ffd83dbSDimitry Andric Query.Types[0] == s1) 1295ffd83dbSDimitry Andric return false; 1305ffd83dbSDimitry Andric 1315ffd83dbSDimitry Andric unsigned Size = Query.Types[0].getSizeInBits(); 132fe6060f1SDimitry Andric unsigned QueryMemSize = Query.MMODescrs[0].MemoryTy.getSizeInBits(); 1335ffd83dbSDimitry Andric assert(QueryMemSize <= Size && "Scalar can't hold MemSize"); 1345ffd83dbSDimitry Andric 1355ffd83dbSDimitry Andric if (Size > 64 || QueryMemSize > 64) 1365ffd83dbSDimitry Andric return false; 1375ffd83dbSDimitry Andric 138fe6060f1SDimitry Andric if (!isPowerOf2_64(Query.MMODescrs[0].MemoryTy.getSizeInBits())) 1395ffd83dbSDimitry Andric return true; 1405ffd83dbSDimitry Andric 1415ffd83dbSDimitry Andric if (!ST.systemSupportsUnalignedAccess() && 1425ffd83dbSDimitry Andric isUnalignedMemmoryAccess(QueryMemSize, 1435ffd83dbSDimitry Andric Query.MMODescrs[0].AlignInBits)) { 1445ffd83dbSDimitry Andric assert(QueryMemSize != 32 && "4 byte load and store are legal"); 1455ffd83dbSDimitry Andric return true; 1465ffd83dbSDimitry Andric } 1475ffd83dbSDimitry Andric 1485ffd83dbSDimitry Andric return false; 1495ffd83dbSDimitry Andric }) 150fe6060f1SDimitry Andric .minScalar(0, s32) 151fe6060f1SDimitry Andric .lower(); 1520b57cec5SDimitry Andric 1538bcb0991SDimitry Andric getActionDefinitionsBuilder(G_IMPLICIT_DEF) 1548bcb0991SDimitry Andric .legalFor({s32, s64}); 1558bcb0991SDimitry Andric 1560b57cec5SDimitry Andric getActionDefinitionsBuilder(G_UNMERGE_VALUES) 1570b57cec5SDimitry Andric .legalFor({{s32, s64}}); 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric getActionDefinitionsBuilder(G_MERGE_VALUES) 1600b57cec5SDimitry Andric .legalFor({{s64, s32}}); 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD}) 163fe6060f1SDimitry Andric .legalForTypesWithMemDesc({{s32, p0, s8, 8}, 164fe6060f1SDimitry Andric {s32, p0, s16, 8}}) 1658bcb0991SDimitry Andric .clampScalar(0, s32, s32); 1668bcb0991SDimitry Andric 1675ffd83dbSDimitry Andric getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}) 1688bcb0991SDimitry Andric .legalIf([](const LegalityQuery &Query) { return false; }) 1698bcb0991SDimitry Andric .maxScalar(0, s32); 1708bcb0991SDimitry Andric 1718bcb0991SDimitry Andric getActionDefinitionsBuilder(G_TRUNC) 1728bcb0991SDimitry Andric .legalIf([](const LegalityQuery &Query) { return false; }) 1738bcb0991SDimitry Andric .maxScalar(1, s32); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric getActionDefinitionsBuilder(G_SELECT) 1760b57cec5SDimitry Andric .legalForCartesianProduct({p0, s32, s64}, {s32}) 1770b57cec5SDimitry Andric .minScalar(0, s32) 1780b57cec5SDimitry Andric .minScalar(1, s32); 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric getActionDefinitionsBuilder(G_BRCOND) 1810b57cec5SDimitry Andric .legalFor({s32}) 1820b57cec5SDimitry Andric .minScalar(0, s32); 1830b57cec5SDimitry Andric 1848bcb0991SDimitry Andric getActionDefinitionsBuilder(G_BRJT) 1858bcb0991SDimitry Andric .legalFor({{p0, s32}}); 1868bcb0991SDimitry Andric 1878bcb0991SDimitry Andric getActionDefinitionsBuilder(G_BRINDIRECT) 1888bcb0991SDimitry Andric .legalFor({p0}); 1898bcb0991SDimitry Andric 1900b57cec5SDimitry Andric getActionDefinitionsBuilder(G_PHI) 1910b57cec5SDimitry Andric .legalFor({p0, s32, s64}) 1920b57cec5SDimitry Andric .minScalar(0, s32); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) 1950b57cec5SDimitry Andric .legalFor({s32}) 1960b57cec5SDimitry Andric .clampScalar(0, s32, s32); 1970b57cec5SDimitry Andric 198480093f4SDimitry Andric getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM}) 199480093f4SDimitry Andric .legalIf([=, &ST](const LegalityQuery &Query) { 200480093f4SDimitry Andric if (CheckTyN(0, Query, {s32})) 201480093f4SDimitry Andric return true; 202480093f4SDimitry Andric if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64})) 203480093f4SDimitry Andric return true; 204480093f4SDimitry Andric return false; 205480093f4SDimitry Andric }) 2060b57cec5SDimitry Andric .minScalar(0, s32) 2070b57cec5SDimitry Andric .libcallFor({s64}); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR}) 2108bcb0991SDimitry Andric .legalFor({{s32, s32}}) 2118bcb0991SDimitry Andric .clampScalar(1, s32, s32) 2128bcb0991SDimitry Andric .clampScalar(0, s32, s32); 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric getActionDefinitionsBuilder(G_ICMP) 2150b57cec5SDimitry Andric .legalForCartesianProduct({s32}, {s32, p0}) 2160b57cec5SDimitry Andric .clampScalar(1, s32, s32) 2170b57cec5SDimitry Andric .minScalar(0, s32); 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric getActionDefinitionsBuilder(G_CONSTANT) 2200b57cec5SDimitry Andric .legalFor({s32}) 2210b57cec5SDimitry Andric .clampScalar(0, s32, s32); 2220b57cec5SDimitry Andric 223480093f4SDimitry Andric getActionDefinitionsBuilder({G_PTR_ADD, G_INTTOPTR}) 2240b57cec5SDimitry Andric .legalFor({{p0, s32}}); 2250b57cec5SDimitry Andric 2268bcb0991SDimitry Andric getActionDefinitionsBuilder(G_PTRTOINT) 2278bcb0991SDimitry Andric .legalFor({{s32, p0}}); 2288bcb0991SDimitry Andric 2290b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FRAME_INDEX) 2300b57cec5SDimitry Andric .legalFor({p0}); 2310b57cec5SDimitry Andric 2328bcb0991SDimitry Andric getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE}) 2338bcb0991SDimitry Andric .legalFor({p0}); 2348bcb0991SDimitry Andric 2358bcb0991SDimitry Andric getActionDefinitionsBuilder(G_DYN_STACKALLOC) 2368bcb0991SDimitry Andric .lowerFor({{p0, s32}}); 2378bcb0991SDimitry Andric 2388bcb0991SDimitry Andric getActionDefinitionsBuilder(G_VASTART) 2390b57cec5SDimitry Andric .legalFor({p0}); 2400b57cec5SDimitry Andric 241480093f4SDimitry Andric getActionDefinitionsBuilder(G_BSWAP) 242480093f4SDimitry Andric .legalIf([=, &ST](const LegalityQuery &Query) { 243480093f4SDimitry Andric if (ST.hasMips32r2() && CheckTyN(0, Query, {s32})) 244480093f4SDimitry Andric return true; 245480093f4SDimitry Andric return false; 246480093f4SDimitry Andric }) 247480093f4SDimitry Andric .lowerIf([=, &ST](const LegalityQuery &Query) { 248480093f4SDimitry Andric if (!ST.hasMips32r2() && CheckTyN(0, Query, {s32})) 249480093f4SDimitry Andric return true; 250480093f4SDimitry Andric return false; 251480093f4SDimitry Andric }) 252480093f4SDimitry Andric .maxScalar(0, s32); 253480093f4SDimitry Andric 254480093f4SDimitry Andric getActionDefinitionsBuilder(G_BITREVERSE) 255480093f4SDimitry Andric .lowerFor({s32}) 256480093f4SDimitry Andric .maxScalar(0, s32); 257480093f4SDimitry Andric 2585ffd83dbSDimitry Andric getActionDefinitionsBuilder(G_CTLZ) 2595ffd83dbSDimitry Andric .legalFor({{s32, s32}}) 2605ffd83dbSDimitry Andric .maxScalar(0, s32) 2615ffd83dbSDimitry Andric .maxScalar(1, s32); 2625ffd83dbSDimitry Andric getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF) 2635ffd83dbSDimitry Andric .lowerFor({{s32, s32}}); 2645ffd83dbSDimitry Andric 2655ffd83dbSDimitry Andric getActionDefinitionsBuilder(G_CTTZ) 2665ffd83dbSDimitry Andric .lowerFor({{s32, s32}}) 2675ffd83dbSDimitry Andric .maxScalar(0, s32) 2685ffd83dbSDimitry Andric .maxScalar(1, s32); 2695ffd83dbSDimitry Andric getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF) 2705ffd83dbSDimitry Andric .lowerFor({{s32, s32}, {s64, s64}}); 2715ffd83dbSDimitry Andric 2725ffd83dbSDimitry Andric getActionDefinitionsBuilder(G_CTPOP) 2735ffd83dbSDimitry Andric .lowerFor({{s32, s32}}) 2745ffd83dbSDimitry Andric .clampScalar(0, s32, s32) 2755ffd83dbSDimitry Andric .clampScalar(1, s32, s32); 2765ffd83dbSDimitry Andric 2770b57cec5SDimitry Andric // FP instructions 2780b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FCONSTANT) 2790b57cec5SDimitry Andric .legalFor({s32, s64}); 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT}) 282480093f4SDimitry Andric .legalIf([=, &ST](const LegalityQuery &Query) { 283480093f4SDimitry Andric if (CheckTyN(0, Query, {s32, s64})) 284480093f4SDimitry Andric return true; 285480093f4SDimitry Andric if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64})) 286480093f4SDimitry Andric return true; 287480093f4SDimitry Andric return false; 288480093f4SDimitry Andric }); 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FCMP) 2910b57cec5SDimitry Andric .legalFor({{s32, s32}, {s32, s64}}) 2920b57cec5SDimitry Andric .minScalar(0, s32); 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR}) 2950b57cec5SDimitry Andric .libcallFor({s32, s64}); 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPEXT) 2980b57cec5SDimitry Andric .legalFor({{s64, s32}}); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPTRUNC) 3010b57cec5SDimitry Andric .legalFor({{s32, s64}}); 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric // FP to int conversion instructions 3040b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPTOSI) 3050b57cec5SDimitry Andric .legalForCartesianProduct({s32}, {s64, s32}) 3060b57cec5SDimitry Andric .libcallForCartesianProduct({s64}, {s64, s32}) 3070b57cec5SDimitry Andric .minScalar(0, s32); 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPTOUI) 3100b57cec5SDimitry Andric .libcallForCartesianProduct({s64}, {s64, s32}) 3118bcb0991SDimitry Andric .lowerForCartesianProduct({s32}, {s64, s32}) 3120b57cec5SDimitry Andric .minScalar(0, s32); 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric // Int to FP conversion instructions 3150b57cec5SDimitry Andric getActionDefinitionsBuilder(G_SITOFP) 3160b57cec5SDimitry Andric .legalForCartesianProduct({s64, s32}, {s32}) 3170b57cec5SDimitry Andric .libcallForCartesianProduct({s64, s32}, {s64}) 3180b57cec5SDimitry Andric .minScalar(1, s32); 3190b57cec5SDimitry Andric 3200b57cec5SDimitry Andric getActionDefinitionsBuilder(G_UITOFP) 3210b57cec5SDimitry Andric .libcallForCartesianProduct({s64, s32}, {s64}) 3228bcb0991SDimitry Andric .customForCartesianProduct({s64, s32}, {s32}) 3230b57cec5SDimitry Andric .minScalar(1, s32); 3240b57cec5SDimitry Andric 3258bcb0991SDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG).lower(); 3268bcb0991SDimitry Andric 327e8d8bef9SDimitry Andric getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE, G_MEMSET}).libcall(); 328e8d8bef9SDimitry Andric 329fe6060f1SDimitry Andric getLegacyLegalizerInfo().computeTables(); 3300b57cec5SDimitry Andric verify(*ST.getInstrInfo()); 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3331db9f3b2SDimitry Andric bool MipsLegalizerInfo::legalizeCustom( 3341db9f3b2SDimitry Andric LegalizerHelper &Helper, MachineInstr &MI, 3351db9f3b2SDimitry Andric LostDebugLocObserver &LocObserver) const { 3360b57cec5SDimitry Andric using namespace TargetOpcode; 3370b57cec5SDimitry Andric 3385ffd83dbSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 3395ffd83dbSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI(); 3405ffd83dbSDimitry Andric 3418bcb0991SDimitry Andric const LLT s32 = LLT::scalar(32); 3428bcb0991SDimitry Andric const LLT s64 = LLT::scalar(64); 3430b57cec5SDimitry Andric 3448bcb0991SDimitry Andric switch (MI.getOpcode()) { 3455ffd83dbSDimitry Andric case G_LOAD: 3465ffd83dbSDimitry Andric case G_STORE: { 347*0fca6ea1SDimitry Andric unsigned MemSize = (**MI.memoperands_begin()).getSize().getValue(); 3485ffd83dbSDimitry Andric Register Val = MI.getOperand(0).getReg(); 3495ffd83dbSDimitry Andric unsigned Size = MRI.getType(Val).getSizeInBits(); 3505ffd83dbSDimitry Andric 3515ffd83dbSDimitry Andric MachineMemOperand *MMOBase = *MI.memoperands_begin(); 3525ffd83dbSDimitry Andric 3535ffd83dbSDimitry Andric assert(MemSize <= 8 && "MemSize is too large"); 3545ffd83dbSDimitry Andric assert(Size <= 64 && "Scalar size is too large"); 3555ffd83dbSDimitry Andric 3565ffd83dbSDimitry Andric // Split MemSize into two, P2HalfMemSize is largest power of two smaller 3575ffd83dbSDimitry Andric // then MemSize. e.g. 8 = 4 + 4 , 6 = 4 + 2, 3 = 2 + 1. 3585ffd83dbSDimitry Andric unsigned P2HalfMemSize, RemMemSize; 3595ffd83dbSDimitry Andric if (isPowerOf2_64(MemSize)) { 3605ffd83dbSDimitry Andric P2HalfMemSize = RemMemSize = MemSize / 2; 3615ffd83dbSDimitry Andric } else { 3625ffd83dbSDimitry Andric P2HalfMemSize = 1 << Log2_32(MemSize); 3635ffd83dbSDimitry Andric RemMemSize = MemSize - P2HalfMemSize; 3645ffd83dbSDimitry Andric } 3655ffd83dbSDimitry Andric 3665ffd83dbSDimitry Andric Register BaseAddr = MI.getOperand(1).getReg(); 3675ffd83dbSDimitry Andric LLT PtrTy = MRI.getType(BaseAddr); 3685ffd83dbSDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 3695ffd83dbSDimitry Andric 3705ffd83dbSDimitry Andric auto P2HalfMemOp = MF.getMachineMemOperand(MMOBase, 0, P2HalfMemSize); 3715ffd83dbSDimitry Andric auto RemMemOp = MF.getMachineMemOperand(MMOBase, P2HalfMemSize, RemMemSize); 3725ffd83dbSDimitry Andric 3735ffd83dbSDimitry Andric if (MI.getOpcode() == G_STORE) { 3745ffd83dbSDimitry Andric // Widen Val to s32 or s64 in order to create legal G_LSHR or G_UNMERGE. 3755ffd83dbSDimitry Andric if (Size < 32) 3765ffd83dbSDimitry Andric Val = MIRBuilder.buildAnyExt(s32, Val).getReg(0); 3775ffd83dbSDimitry Andric if (Size > 32 && Size < 64) 3785ffd83dbSDimitry Andric Val = MIRBuilder.buildAnyExt(s64, Val).getReg(0); 3795ffd83dbSDimitry Andric 3805ffd83dbSDimitry Andric auto C_P2HalfMemSize = MIRBuilder.buildConstant(s32, P2HalfMemSize); 3815ffd83dbSDimitry Andric auto Addr = MIRBuilder.buildPtrAdd(PtrTy, BaseAddr, C_P2HalfMemSize); 3825ffd83dbSDimitry Andric 3835ffd83dbSDimitry Andric if (MI.getOpcode() == G_STORE && MemSize <= 4) { 3845ffd83dbSDimitry Andric MIRBuilder.buildStore(Val, BaseAddr, *P2HalfMemOp); 3855ffd83dbSDimitry Andric auto C_P2Half_InBits = MIRBuilder.buildConstant(s32, P2HalfMemSize * 8); 3865ffd83dbSDimitry Andric auto Shift = MIRBuilder.buildLShr(s32, Val, C_P2Half_InBits); 3875ffd83dbSDimitry Andric MIRBuilder.buildStore(Shift, Addr, *RemMemOp); 3885ffd83dbSDimitry Andric } else { 3895ffd83dbSDimitry Andric auto Unmerge = MIRBuilder.buildUnmerge(s32, Val); 3905ffd83dbSDimitry Andric MIRBuilder.buildStore(Unmerge.getReg(0), BaseAddr, *P2HalfMemOp); 3915ffd83dbSDimitry Andric MIRBuilder.buildStore(Unmerge.getReg(1), Addr, *RemMemOp); 3925ffd83dbSDimitry Andric } 3935ffd83dbSDimitry Andric } 3945ffd83dbSDimitry Andric 3955ffd83dbSDimitry Andric if (MI.getOpcode() == G_LOAD) { 3965ffd83dbSDimitry Andric 3975ffd83dbSDimitry Andric if (MemSize <= 4) { 3985ffd83dbSDimitry Andric // This is anyextending load, use 4 byte lwr/lwl. 3995ffd83dbSDimitry Andric auto *Load4MMO = MF.getMachineMemOperand(MMOBase, 0, 4); 4005ffd83dbSDimitry Andric 4015ffd83dbSDimitry Andric if (Size == 32) 4025ffd83dbSDimitry Andric MIRBuilder.buildLoad(Val, BaseAddr, *Load4MMO); 4035ffd83dbSDimitry Andric else { 4045ffd83dbSDimitry Andric auto Load = MIRBuilder.buildLoad(s32, BaseAddr, *Load4MMO); 4055ffd83dbSDimitry Andric MIRBuilder.buildTrunc(Val, Load.getReg(0)); 4065ffd83dbSDimitry Andric } 4075ffd83dbSDimitry Andric 4085ffd83dbSDimitry Andric } else { 4095ffd83dbSDimitry Andric auto C_P2HalfMemSize = MIRBuilder.buildConstant(s32, P2HalfMemSize); 4105ffd83dbSDimitry Andric auto Addr = MIRBuilder.buildPtrAdd(PtrTy, BaseAddr, C_P2HalfMemSize); 4115ffd83dbSDimitry Andric 4125ffd83dbSDimitry Andric auto Load_P2Half = MIRBuilder.buildLoad(s32, BaseAddr, *P2HalfMemOp); 4135ffd83dbSDimitry Andric auto Load_Rem = MIRBuilder.buildLoad(s32, Addr, *RemMemOp); 4145ffd83dbSDimitry Andric 4155ffd83dbSDimitry Andric if (Size == 64) 416bdd1243dSDimitry Andric MIRBuilder.buildMergeLikeInstr(Val, {Load_P2Half, Load_Rem}); 4175ffd83dbSDimitry Andric else { 418bdd1243dSDimitry Andric auto Merge = 419bdd1243dSDimitry Andric MIRBuilder.buildMergeLikeInstr(s64, {Load_P2Half, Load_Rem}); 4205ffd83dbSDimitry Andric MIRBuilder.buildTrunc(Val, Merge); 4215ffd83dbSDimitry Andric } 4225ffd83dbSDimitry Andric } 4235ffd83dbSDimitry Andric } 4245ffd83dbSDimitry Andric MI.eraseFromParent(); 4255ffd83dbSDimitry Andric break; 4265ffd83dbSDimitry Andric } 4278bcb0991SDimitry Andric case G_UITOFP: { 4288bcb0991SDimitry Andric Register Dst = MI.getOperand(0).getReg(); 4298bcb0991SDimitry Andric Register Src = MI.getOperand(1).getReg(); 4308bcb0991SDimitry Andric LLT DstTy = MRI.getType(Dst); 4318bcb0991SDimitry Andric LLT SrcTy = MRI.getType(Src); 4328bcb0991SDimitry Andric 4338bcb0991SDimitry Andric if (SrcTy != s32) 4340b57cec5SDimitry Andric return false; 4358bcb0991SDimitry Andric if (DstTy != s32 && DstTy != s64) 4368bcb0991SDimitry Andric return false; 4378bcb0991SDimitry Andric 4388bcb0991SDimitry Andric // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert 4398bcb0991SDimitry Andric // unsigned to double. Mantissa has 52 bits so we use following trick: 4408bcb0991SDimitry Andric // First make floating point bit mask 0x43300000ABCDEFGH. 4418bcb0991SDimitry Andric // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 . 4428bcb0991SDimitry Andric // Next, subtract 2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it. 4438bcb0991SDimitry Andric // Done. Trunc double to float if needed. 4448bcb0991SDimitry Andric 4455ffd83dbSDimitry Andric auto C_HiMask = MIRBuilder.buildConstant(s32, UINT32_C(0x43300000)); 446bdd1243dSDimitry Andric auto Bitcast = 447bdd1243dSDimitry Andric MIRBuilder.buildMergeLikeInstr(s64, {Src, C_HiMask.getReg(0)}); 4488bcb0991SDimitry Andric 4498bcb0991SDimitry Andric MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant( 45006c3fb27SDimitry Andric s64, llvm::bit_cast<double>(UINT64_C(0x4330000000000000))); 4518bcb0991SDimitry Andric 4528bcb0991SDimitry Andric if (DstTy == s64) 4538bcb0991SDimitry Andric MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP); 4548bcb0991SDimitry Andric else { 4558bcb0991SDimitry Andric MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP); 4568bcb0991SDimitry Andric MIRBuilder.buildFPTrunc(Dst, ResF64); 4578bcb0991SDimitry Andric } 4588bcb0991SDimitry Andric 4598bcb0991SDimitry Andric MI.eraseFromParent(); 4608bcb0991SDimitry Andric break; 4618bcb0991SDimitry Andric } 4628bcb0991SDimitry Andric default: 4638bcb0991SDimitry Andric return false; 4648bcb0991SDimitry Andric } 4658bcb0991SDimitry Andric 4668bcb0991SDimitry Andric return true; 4678bcb0991SDimitry Andric } 4688bcb0991SDimitry Andric 4698bcb0991SDimitry Andric static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode, 4708bcb0991SDimitry Andric MachineIRBuilder &MIRBuilder, 4718bcb0991SDimitry Andric const MipsSubtarget &ST) { 4728bcb0991SDimitry Andric assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 4738bcb0991SDimitry Andric if (!MIRBuilder.buildInstr(Opcode) 4748bcb0991SDimitry Andric .add(MI.getOperand(0)) 4758bcb0991SDimitry Andric .add(MI.getOperand(2)) 4768bcb0991SDimitry Andric .add(MI.getOperand(3)) 4778bcb0991SDimitry Andric .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(), 4788bcb0991SDimitry Andric *ST.getRegBankInfo())) 4798bcb0991SDimitry Andric return false; 4808bcb0991SDimitry Andric MI.eraseFromParent(); 4818bcb0991SDimitry Andric return true; 4828bcb0991SDimitry Andric } 4838bcb0991SDimitry Andric 4848bcb0991SDimitry Andric static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, 4858bcb0991SDimitry Andric MachineIRBuilder &MIRBuilder, 4868bcb0991SDimitry Andric const MipsSubtarget &ST) { 4878bcb0991SDimitry Andric assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 4888bcb0991SDimitry Andric MIRBuilder.buildInstr(Opcode) 4898bcb0991SDimitry Andric .add(MI.getOperand(0)) 4908bcb0991SDimitry Andric .add(MI.getOperand(2)) 4918bcb0991SDimitry Andric .add(MI.getOperand(3)); 4928bcb0991SDimitry Andric MI.eraseFromParent(); 4938bcb0991SDimitry Andric return true; 4948bcb0991SDimitry Andric } 4958bcb0991SDimitry Andric 496480093f4SDimitry Andric static bool MSA2OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, 497480093f4SDimitry Andric MachineIRBuilder &MIRBuilder, 498480093f4SDimitry Andric const MipsSubtarget &ST) { 499480093f4SDimitry Andric assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA."); 500480093f4SDimitry Andric MIRBuilder.buildInstr(Opcode) 501480093f4SDimitry Andric .add(MI.getOperand(0)) 502480093f4SDimitry Andric .add(MI.getOperand(2)); 503480093f4SDimitry Andric MI.eraseFromParent(); 504480093f4SDimitry Andric return true; 505480093f4SDimitry Andric } 506480093f4SDimitry Andric 5075ffd83dbSDimitry Andric bool MipsLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper, 5085ffd83dbSDimitry Andric MachineInstr &MI) const { 5095ffd83dbSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder; 51081ad6265SDimitry Andric const MipsSubtarget &ST = MI.getMF()->getSubtarget<MipsSubtarget>(); 5118bcb0991SDimitry Andric 5125f757f3fSDimitry Andric switch (cast<GIntrinsic>(MI).getIntrinsicID()) { 5138bcb0991SDimitry Andric case Intrinsic::vacopy: { 5148bcb0991SDimitry Andric MachinePointerInfo MPO; 515fe6060f1SDimitry Andric LLT PtrTy = LLT::pointer(0, 32); 5165ffd83dbSDimitry Andric auto Tmp = 517fe6060f1SDimitry Andric MIRBuilder.buildLoad(PtrTy, MI.getOperand(2), 5188bcb0991SDimitry Andric *MI.getMF()->getMachineMemOperand( 519fe6060f1SDimitry Andric MPO, MachineMemOperand::MOLoad, PtrTy, Align(4))); 5208bcb0991SDimitry Andric MIRBuilder.buildStore(Tmp, MI.getOperand(1), 5218bcb0991SDimitry Andric *MI.getMF()->getMachineMemOperand( 522fe6060f1SDimitry Andric MPO, MachineMemOperand::MOStore, PtrTy, Align(4))); 5238bcb0991SDimitry Andric MI.eraseFromParent(); 5248bcb0991SDimitry Andric return true; 5258bcb0991SDimitry Andric } 5268bcb0991SDimitry Andric case Intrinsic::mips_addv_b: 5278bcb0991SDimitry Andric case Intrinsic::mips_addv_h: 5288bcb0991SDimitry Andric case Intrinsic::mips_addv_w: 5298bcb0991SDimitry Andric case Intrinsic::mips_addv_d: 5308bcb0991SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_ADD, MIRBuilder, ST); 5318bcb0991SDimitry Andric case Intrinsic::mips_addvi_b: 5328bcb0991SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_B, MIRBuilder, ST); 5338bcb0991SDimitry Andric case Intrinsic::mips_addvi_h: 5348bcb0991SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_H, MIRBuilder, ST); 5358bcb0991SDimitry Andric case Intrinsic::mips_addvi_w: 5368bcb0991SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_W, MIRBuilder, ST); 5378bcb0991SDimitry Andric case Intrinsic::mips_addvi_d: 5388bcb0991SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_D, MIRBuilder, ST); 539480093f4SDimitry Andric case Intrinsic::mips_subv_b: 540480093f4SDimitry Andric case Intrinsic::mips_subv_h: 541480093f4SDimitry Andric case Intrinsic::mips_subv_w: 542480093f4SDimitry Andric case Intrinsic::mips_subv_d: 543480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SUB, MIRBuilder, ST); 544480093f4SDimitry Andric case Intrinsic::mips_subvi_b: 545480093f4SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_B, MIRBuilder, ST); 546480093f4SDimitry Andric case Intrinsic::mips_subvi_h: 547480093f4SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_H, MIRBuilder, ST); 548480093f4SDimitry Andric case Intrinsic::mips_subvi_w: 549480093f4SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_W, MIRBuilder, ST); 550480093f4SDimitry Andric case Intrinsic::mips_subvi_d: 551480093f4SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_D, MIRBuilder, ST); 552480093f4SDimitry Andric case Intrinsic::mips_mulv_b: 553480093f4SDimitry Andric case Intrinsic::mips_mulv_h: 554480093f4SDimitry Andric case Intrinsic::mips_mulv_w: 555480093f4SDimitry Andric case Intrinsic::mips_mulv_d: 556480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_MUL, MIRBuilder, ST); 557480093f4SDimitry Andric case Intrinsic::mips_div_s_b: 558480093f4SDimitry Andric case Intrinsic::mips_div_s_h: 559480093f4SDimitry Andric case Intrinsic::mips_div_s_w: 560480093f4SDimitry Andric case Intrinsic::mips_div_s_d: 561480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SDIV, MIRBuilder, ST); 562480093f4SDimitry Andric case Intrinsic::mips_mod_s_b: 563480093f4SDimitry Andric case Intrinsic::mips_mod_s_h: 564480093f4SDimitry Andric case Intrinsic::mips_mod_s_w: 565480093f4SDimitry Andric case Intrinsic::mips_mod_s_d: 566480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SREM, MIRBuilder, ST); 567480093f4SDimitry Andric case Intrinsic::mips_div_u_b: 568480093f4SDimitry Andric case Intrinsic::mips_div_u_h: 569480093f4SDimitry Andric case Intrinsic::mips_div_u_w: 570480093f4SDimitry Andric case Intrinsic::mips_div_u_d: 571480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_UDIV, MIRBuilder, ST); 572480093f4SDimitry Andric case Intrinsic::mips_mod_u_b: 573480093f4SDimitry Andric case Intrinsic::mips_mod_u_h: 574480093f4SDimitry Andric case Intrinsic::mips_mod_u_w: 575480093f4SDimitry Andric case Intrinsic::mips_mod_u_d: 576480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_UREM, MIRBuilder, ST); 577480093f4SDimitry Andric case Intrinsic::mips_fadd_w: 578480093f4SDimitry Andric case Intrinsic::mips_fadd_d: 579480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FADD, MIRBuilder, ST); 580480093f4SDimitry Andric case Intrinsic::mips_fsub_w: 581480093f4SDimitry Andric case Intrinsic::mips_fsub_d: 582480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FSUB, MIRBuilder, ST); 583480093f4SDimitry Andric case Intrinsic::mips_fmul_w: 584480093f4SDimitry Andric case Intrinsic::mips_fmul_d: 585480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FMUL, MIRBuilder, ST); 586480093f4SDimitry Andric case Intrinsic::mips_fdiv_w: 587480093f4SDimitry Andric case Intrinsic::mips_fdiv_d: 588480093f4SDimitry Andric return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FDIV, MIRBuilder, ST); 589480093f4SDimitry Andric case Intrinsic::mips_fmax_a_w: 590480093f4SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::FMAX_A_W, MIRBuilder, ST); 591480093f4SDimitry Andric case Intrinsic::mips_fmax_a_d: 592480093f4SDimitry Andric return SelectMSA3OpIntrinsic(MI, Mips::FMAX_A_D, MIRBuilder, ST); 593480093f4SDimitry Andric case Intrinsic::mips_fsqrt_w: 594480093f4SDimitry Andric return MSA2OpIntrinsicToGeneric(MI, TargetOpcode::G_FSQRT, MIRBuilder, ST); 595480093f4SDimitry Andric case Intrinsic::mips_fsqrt_d: 596480093f4SDimitry Andric return MSA2OpIntrinsicToGeneric(MI, TargetOpcode::G_FSQRT, MIRBuilder, ST); 5978bcb0991SDimitry Andric default: 5988bcb0991SDimitry Andric break; 5998bcb0991SDimitry Andric } 6008bcb0991SDimitry Andric return true; 6010b57cec5SDimitry Andric } 602