1311116Sdim//===- ARMLegalizerInfo.cpp --------------------------------------*- C++ -*-==// 2311116Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6311116Sdim// 7311116Sdim//===----------------------------------------------------------------------===// 8311116Sdim/// \file 9311116Sdim/// This file implements the targeting of the Machinelegalizer class for ARM. 10311116Sdim/// \todo This should be generated by TableGen. 11311116Sdim//===----------------------------------------------------------------------===// 12311116Sdim 13311116Sdim#include "ARMLegalizerInfo.h" 14321369Sdim#include "ARMCallLowering.h" 15321369Sdim#include "ARMSubtarget.h" 16321369Sdim#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" 17321369Sdim#include "llvm/CodeGen/LowLevelType.h" 18321369Sdim#include "llvm/CodeGen/MachineRegisterInfo.h" 19327952Sdim#include "llvm/CodeGen/TargetOpcodes.h" 20311116Sdim#include "llvm/CodeGen/ValueTypes.h" 21311116Sdim#include "llvm/IR/DerivedTypes.h" 22311116Sdim#include "llvm/IR/Type.h" 23311116Sdim 24311116Sdimusing namespace llvm; 25341825Sdimusing namespace LegalizeActions; 26311116Sdim 27327952Sdim/// FIXME: The following static functions are SizeChangeStrategy functions 28327952Sdim/// that are meant to temporarily mimic the behaviour of the old legalization 29327952Sdim/// based on doubling/halving non-legal types as closely as possible. This is 30327952Sdim/// not entirly possible as only legalizing the types that are exactly a power 31327952Sdim/// of 2 times the size of the legal types would require specifying all those 32327952Sdim/// sizes explicitly. 33327952Sdim/// In practice, not specifying those isn't a problem, and the below functions 34327952Sdim/// should disappear quickly as we add support for legalizing non-power-of-2 35327952Sdim/// sized types further. 36327952Sdimstatic void 37327952SdimaddAndInterleaveWithUnsupported(LegalizerInfo::SizeAndActionsVec &result, 38327952Sdim const LegalizerInfo::SizeAndActionsVec &v) { 39327952Sdim for (unsigned i = 0; i < v.size(); ++i) { 40327952Sdim result.push_back(v[i]); 41327952Sdim if (i + 1 < v[i].first && i + 1 < v.size() && 42327952Sdim v[i + 1].first != v[i].first + 1) 43341825Sdim result.push_back({v[i].first + 1, Unsupported}); 44327952Sdim } 45327952Sdim} 46311116Sdim 47327952Sdimstatic LegalizerInfo::SizeAndActionsVec 48327952Sdimwiden_8_16(const LegalizerInfo::SizeAndActionsVec &v) { 49327952Sdim assert(v.size() >= 1); 50327952Sdim assert(v[0].first > 17); 51341825Sdim LegalizerInfo::SizeAndActionsVec result = {{1, Unsupported}, 52341825Sdim {8, WidenScalar}, 53341825Sdim {9, Unsupported}, 54341825Sdim {16, WidenScalar}, 55341825Sdim {17, Unsupported}}; 56327952Sdim addAndInterleaveWithUnsupported(result, v); 57327952Sdim auto Largest = result.back().first; 58341825Sdim result.push_back({Largest + 1, Unsupported}); 59327952Sdim return result; 60327952Sdim} 61327952Sdim 62321369Sdimstatic bool AEABI(const ARMSubtarget &ST) { 63321369Sdim return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI(); 64321369Sdim} 65321369Sdim 66321369SdimARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) { 67311116Sdim using namespace TargetOpcode; 68311116Sdim 69311116Sdim const LLT p0 = LLT::pointer(0, 32); 70311116Sdim 71321369Sdim const LLT s1 = LLT::scalar(1); 72311116Sdim const LLT s8 = LLT::scalar(8); 73311116Sdim const LLT s16 = LLT::scalar(16); 74311116Sdim const LLT s32 = LLT::scalar(32); 75321369Sdim const LLT s64 = LLT::scalar(64); 76311116Sdim 77344779Sdim if (ST.isThumb1Only()) { 78344779Sdim // Thumb1 is not supported yet. 79344779Sdim computeTables(); 80344779Sdim verify(*ST.getInstrInfo()); 81344779Sdim return; 82344779Sdim } 83311116Sdim 84344779Sdim getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT}) 85353358Sdim .legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16}); 86344779Sdim 87360784Sdim getActionDefinitionsBuilder(G_SEXT_INREG).lower(); 88360784Sdim 89353358Sdim getActionDefinitionsBuilder({G_MUL, G_AND, G_OR, G_XOR}) 90341825Sdim .legalFor({s32}) 91341825Sdim .minScalar(0, s32); 92311116Sdim 93353358Sdim if (ST.hasNEON()) 94353358Sdim getActionDefinitionsBuilder({G_ADD, G_SUB}) 95353358Sdim .legalFor({s32, s64}) 96353358Sdim .minScalar(0, s32); 97353358Sdim else 98353358Sdim getActionDefinitionsBuilder({G_ADD, G_SUB}) 99353358Sdim .legalFor({s32}) 100353358Sdim .minScalar(0, s32); 101344779Sdim 102353358Sdim getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL}) 103353358Sdim .legalFor({{s32, s32}}) 104353358Sdim .minScalar(0, s32) 105353358Sdim .clampScalar(1, s32, s32); 106344779Sdim 107353358Sdim bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) || 108353358Sdim (ST.isThumb() && ST.hasDivideInThumbMode()); 109353358Sdim if (HasHWDivide) 110341825Sdim getActionDefinitionsBuilder({G_SDIV, G_UDIV}) 111341825Sdim .legalFor({s32}) 112341825Sdim .clampScalar(0, s32, s32); 113341825Sdim else 114341825Sdim getActionDefinitionsBuilder({G_SDIV, G_UDIV}) 115341825Sdim .libcallFor({s32}) 116341825Sdim .clampScalar(0, s32, s32); 117311116Sdim 118321369Sdim for (unsigned Op : {G_SREM, G_UREM}) { 119327952Sdim setLegalizeScalarToDifferentSizeStrategy(Op, 0, widen_8_16); 120353358Sdim if (HasHWDivide) 121321369Sdim setAction({Op, s32}, Lower); 122321369Sdim else if (AEABI(ST)) 123321369Sdim setAction({Op, s32}, Custom); 124321369Sdim else 125321369Sdim setAction({Op, s32}, Libcall); 126321369Sdim } 127321369Sdim 128353358Sdim getActionDefinitionsBuilder(G_INTTOPTR) 129353358Sdim .legalFor({{p0, s32}}) 130353358Sdim .minScalar(1, s32); 131353358Sdim getActionDefinitionsBuilder(G_PTRTOINT) 132353358Sdim .legalFor({{s32, p0}}) 133353358Sdim .minScalar(0, s32); 134321369Sdim 135353358Sdim getActionDefinitionsBuilder(G_CONSTANT) 136353358Sdim .legalFor({s32, p0}) 137353358Sdim .clampScalar(0, s32, s32); 138327952Sdim 139341825Sdim getActionDefinitionsBuilder(G_ICMP) 140341825Sdim .legalForCartesianProduct({s1}, {s32, p0}) 141341825Sdim .minScalar(1, s32); 142321369Sdim 143353358Sdim getActionDefinitionsBuilder(G_SELECT) 144353358Sdim .legalForCartesianProduct({s32, p0}, {s1}) 145353358Sdim .minScalar(0, s32); 146353358Sdim 147341825Sdim // We're keeping these builders around because we'll want to add support for 148341825Sdim // floating point to them. 149353358Sdim auto &LoadStoreBuilder = getActionDefinitionsBuilder({G_LOAD, G_STORE}) 150353358Sdim .legalForTypesWithMemDesc({{s1, p0, 8, 8}, 151353358Sdim {s8, p0, 8, 8}, 152353358Sdim {s16, p0, 16, 8}, 153353358Sdim {s32, p0, 32, 8}, 154353358Sdim {p0, p0, 32, 8}}) 155353358Sdim .unsupportedIfMemSizeNotPow2(); 156353358Sdim 157353358Sdim getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0}); 158353358Sdim getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0}); 159353358Sdim 160341825Sdim auto &PhiBuilder = 161353358Sdim getActionDefinitionsBuilder(G_PHI) 162353358Sdim .legalFor({s32, p0}) 163353358Sdim .minScalar(0, s32); 164341825Sdim 165360784Sdim getActionDefinitionsBuilder(G_PTR_ADD) 166353358Sdim .legalFor({{p0, s32}}) 167353358Sdim .minScalar(1, s32); 168353358Sdim 169353358Sdim getActionDefinitionsBuilder(G_BRCOND).legalFor({s1}); 170353358Sdim 171353358Sdim if (!ST.useSoftFloat() && ST.hasVFP2Base()) { 172341825Sdim getActionDefinitionsBuilder( 173341825Sdim {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG}) 174341825Sdim .legalFor({s32, s64}); 175321369Sdim 176353358Sdim LoadStoreBuilder 177353358Sdim .legalForTypesWithMemDesc({{s64, p0, 64, 32}}) 178353358Sdim .maxScalar(0, s32); 179341825Sdim PhiBuilder.legalFor({s64}); 180321369Sdim 181341825Sdim getActionDefinitionsBuilder(G_FCMP).legalForCartesianProduct({s1}, 182341825Sdim {s32, s64}); 183327952Sdim 184341825Sdim getActionDefinitionsBuilder(G_MERGE_VALUES).legalFor({{s64, s32}}); 185341825Sdim getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}}); 186341825Sdim 187341825Sdim getActionDefinitionsBuilder(G_FPEXT).legalFor({{s64, s32}}); 188341825Sdim getActionDefinitionsBuilder(G_FPTRUNC).legalFor({{s32, s64}}); 189341825Sdim 190341825Sdim getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 191341825Sdim .legalForCartesianProduct({s32}, {s32, s64}); 192341825Sdim getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) 193341825Sdim .legalForCartesianProduct({s32, s64}, {s32}); 194321369Sdim } else { 195341825Sdim getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV}) 196341825Sdim .libcallFor({s32, s64}); 197321369Sdim 198341825Sdim LoadStoreBuilder.maxScalar(0, s32); 199321369Sdim 200341825Sdim for (auto Ty : {s32, s64}) 201341825Sdim setAction({G_FNEG, Ty}, Lower); 202341825Sdim 203341825Sdim getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64}); 204341825Sdim 205341825Sdim getActionDefinitionsBuilder(G_FCMP).customForCartesianProduct({s1}, 206341825Sdim {s32, s64}); 207341825Sdim 208321369Sdim if (AEABI(ST)) 209321369Sdim setFCmpLibcallsAEABI(); 210321369Sdim else 211321369Sdim setFCmpLibcallsGNU(); 212341825Sdim 213341825Sdim getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s64, s32}}); 214341825Sdim getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s32, s64}}); 215341825Sdim 216341825Sdim getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) 217341825Sdim .libcallForCartesianProduct({s32}, {s32, s64}); 218341825Sdim getActionDefinitionsBuilder({G_SITOFP, G_UITOFP}) 219341825Sdim .libcallForCartesianProduct({s32, s64}, {s32}); 220321369Sdim } 221321369Sdim 222353358Sdim if (!ST.useSoftFloat() && ST.hasVFP4Base()) 223341825Sdim getActionDefinitionsBuilder(G_FMA).legalFor({s32, s64}); 224341825Sdim else 225341825Sdim getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64}); 226321369Sdim 227341825Sdim getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64}); 228341825Sdim 229353358Sdim if (ST.hasV5TOps()) { 230353358Sdim getActionDefinitionsBuilder(G_CTLZ) 231353358Sdim .legalFor({s32, s32}) 232353358Sdim .clampScalar(1, s32, s32) 233353358Sdim .clampScalar(0, s32, s32); 234353358Sdim getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF) 235353358Sdim .lowerFor({s32, s32}) 236353358Sdim .clampScalar(1, s32, s32) 237353358Sdim .clampScalar(0, s32, s32); 238353358Sdim } else { 239353358Sdim getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF) 240353358Sdim .libcallFor({s32, s32}) 241353358Sdim .clampScalar(1, s32, s32) 242353358Sdim .clampScalar(0, s32, s32); 243353358Sdim getActionDefinitionsBuilder(G_CTLZ) 244353358Sdim .lowerFor({s32, s32}) 245353358Sdim .clampScalar(1, s32, s32) 246353358Sdim .clampScalar(0, s32, s32); 247353358Sdim } 248353358Sdim 249311116Sdim computeTables(); 250341825Sdim verify(*ST.getInstrInfo()); 251311116Sdim} 252321369Sdim 253321369Sdimvoid ARMLegalizerInfo::setFCmpLibcallsAEABI() { 254321369Sdim // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be 255321369Sdim // default-initialized. 256321369Sdim FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1); 257321369Sdim FCmp32Libcalls[CmpInst::FCMP_OEQ] = { 258321369Sdim {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE}}; 259321369Sdim FCmp32Libcalls[CmpInst::FCMP_OGE] = { 260321369Sdim {RTLIB::OGE_F32, CmpInst::BAD_ICMP_PREDICATE}}; 261321369Sdim FCmp32Libcalls[CmpInst::FCMP_OGT] = { 262321369Sdim {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE}}; 263321369Sdim FCmp32Libcalls[CmpInst::FCMP_OLE] = { 264321369Sdim {RTLIB::OLE_F32, CmpInst::BAD_ICMP_PREDICATE}}; 265321369Sdim FCmp32Libcalls[CmpInst::FCMP_OLT] = { 266321369Sdim {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}}; 267360784Sdim FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}}; 268321369Sdim FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_EQ}}; 269321369Sdim FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_EQ}}; 270321369Sdim FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_EQ}}; 271321369Sdim FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_EQ}}; 272321369Sdim FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_EQ}}; 273321369Sdim FCmp32Libcalls[CmpInst::FCMP_UNO] = { 274321369Sdim {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}}; 275321369Sdim FCmp32Libcalls[CmpInst::FCMP_ONE] = { 276321369Sdim {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE}, 277321369Sdim {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}}; 278321369Sdim FCmp32Libcalls[CmpInst::FCMP_UEQ] = { 279321369Sdim {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE}, 280321369Sdim {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}}; 281321369Sdim 282321369Sdim FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1); 283321369Sdim FCmp64Libcalls[CmpInst::FCMP_OEQ] = { 284321369Sdim {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE}}; 285321369Sdim FCmp64Libcalls[CmpInst::FCMP_OGE] = { 286321369Sdim {RTLIB::OGE_F64, CmpInst::BAD_ICMP_PREDICATE}}; 287321369Sdim FCmp64Libcalls[CmpInst::FCMP_OGT] = { 288321369Sdim {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE}}; 289321369Sdim FCmp64Libcalls[CmpInst::FCMP_OLE] = { 290321369Sdim {RTLIB::OLE_F64, CmpInst::BAD_ICMP_PREDICATE}}; 291321369Sdim FCmp64Libcalls[CmpInst::FCMP_OLT] = { 292321369Sdim {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}}; 293360784Sdim FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}}; 294321369Sdim FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_EQ}}; 295321369Sdim FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_EQ}}; 296321369Sdim FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_EQ}}; 297321369Sdim FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_EQ}}; 298321369Sdim FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_EQ}}; 299321369Sdim FCmp64Libcalls[CmpInst::FCMP_UNO] = { 300321369Sdim {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}}; 301321369Sdim FCmp64Libcalls[CmpInst::FCMP_ONE] = { 302321369Sdim {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE}, 303321369Sdim {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}}; 304321369Sdim FCmp64Libcalls[CmpInst::FCMP_UEQ] = { 305321369Sdim {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE}, 306321369Sdim {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}}; 307321369Sdim} 308321369Sdim 309321369Sdimvoid ARMLegalizerInfo::setFCmpLibcallsGNU() { 310321369Sdim // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be 311321369Sdim // default-initialized. 312321369Sdim FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1); 313321369Sdim FCmp32Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}}; 314321369Sdim FCmp32Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F32, CmpInst::ICMP_SGE}}; 315321369Sdim FCmp32Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT}}; 316321369Sdim FCmp32Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F32, CmpInst::ICMP_SLE}}; 317321369Sdim FCmp32Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F32, CmpInst::ICMP_SLT}}; 318360784Sdim FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}}; 319321369Sdim FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_SGE}}; 320321369Sdim FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_SGT}}; 321321369Sdim FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SLE}}; 322321369Sdim FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_SLT}}; 323321369Sdim FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_NE}}; 324321369Sdim FCmp32Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F32, CmpInst::ICMP_NE}}; 325321369Sdim FCmp32Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT}, 326321369Sdim {RTLIB::OLT_F32, CmpInst::ICMP_SLT}}; 327321369Sdim FCmp32Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}, 328321369Sdim {RTLIB::UO_F32, CmpInst::ICMP_NE}}; 329321369Sdim 330321369Sdim FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1); 331321369Sdim FCmp64Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}}; 332321369Sdim FCmp64Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F64, CmpInst::ICMP_SGE}}; 333321369Sdim FCmp64Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT}}; 334321369Sdim FCmp64Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F64, CmpInst::ICMP_SLE}}; 335321369Sdim FCmp64Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F64, CmpInst::ICMP_SLT}}; 336360784Sdim FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}}; 337321369Sdim FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_SGE}}; 338321369Sdim FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_SGT}}; 339321369Sdim FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SLE}}; 340321369Sdim FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_SLT}}; 341321369Sdim FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_NE}}; 342321369Sdim FCmp64Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F64, CmpInst::ICMP_NE}}; 343321369Sdim FCmp64Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT}, 344321369Sdim {RTLIB::OLT_F64, CmpInst::ICMP_SLT}}; 345321369Sdim FCmp64Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}, 346321369Sdim {RTLIB::UO_F64, CmpInst::ICMP_NE}}; 347321369Sdim} 348321369Sdim 349321369SdimARMLegalizerInfo::FCmpLibcallsList 350321369SdimARMLegalizerInfo::getFCmpLibcalls(CmpInst::Predicate Predicate, 351321369Sdim unsigned Size) const { 352321369Sdim assert(CmpInst::isFPPredicate(Predicate) && "Unsupported FCmp predicate"); 353321369Sdim if (Size == 32) 354321369Sdim return FCmp32Libcalls[Predicate]; 355321369Sdim if (Size == 64) 356321369Sdim return FCmp64Libcalls[Predicate]; 357321369Sdim llvm_unreachable("Unsupported size for FCmp predicate"); 358321369Sdim} 359321369Sdim 360321369Sdimbool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI, 361321369Sdim MachineRegisterInfo &MRI, 362344779Sdim MachineIRBuilder &MIRBuilder, 363344779Sdim GISelChangeObserver &Observer) const { 364321369Sdim using namespace TargetOpcode; 365321369Sdim 366321369Sdim MIRBuilder.setInstr(MI); 367341825Sdim LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); 368321369Sdim 369321369Sdim switch (MI.getOpcode()) { 370321369Sdim default: 371321369Sdim return false; 372321369Sdim case G_SREM: 373321369Sdim case G_UREM: { 374353358Sdim Register OriginalResult = MI.getOperand(0).getReg(); 375321369Sdim auto Size = MRI.getType(OriginalResult).getSizeInBits(); 376321369Sdim if (Size != 32) 377321369Sdim return false; 378321369Sdim 379321369Sdim auto Libcall = 380321369Sdim MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32; 381321369Sdim 382321369Sdim // Our divmod libcalls return a struct containing the quotient and the 383353358Sdim // remainder. Create a new, unused register for the quotient and use the 384353358Sdim // destination of the original instruction for the remainder. 385321369Sdim Type *ArgTy = Type::getInt32Ty(Ctx); 386321369Sdim StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true); 387353358Sdim Register RetRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)), 388353358Sdim OriginalResult}; 389353358Sdim auto Status = createLibcall(MIRBuilder, Libcall, {RetRegs, RetTy}, 390321369Sdim {{MI.getOperand(1).getReg(), ArgTy}, 391321369Sdim {MI.getOperand(2).getReg(), ArgTy}}); 392321369Sdim if (Status != LegalizerHelper::Legalized) 393321369Sdim return false; 394321369Sdim break; 395321369Sdim } 396321369Sdim case G_FCMP: { 397321369Sdim assert(MRI.getType(MI.getOperand(2).getReg()) == 398321369Sdim MRI.getType(MI.getOperand(3).getReg()) && 399321369Sdim "Mismatched operands for G_FCMP"); 400321369Sdim auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits(); 401321369Sdim 402321369Sdim auto OriginalResult = MI.getOperand(0).getReg(); 403321369Sdim auto Predicate = 404321369Sdim static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()); 405321369Sdim auto Libcalls = getFCmpLibcalls(Predicate, OpSize); 406321369Sdim 407321369Sdim if (Libcalls.empty()) { 408321369Sdim assert((Predicate == CmpInst::FCMP_TRUE || 409321369Sdim Predicate == CmpInst::FCMP_FALSE) && 410321369Sdim "Predicate needs libcalls, but none specified"); 411321369Sdim MIRBuilder.buildConstant(OriginalResult, 412321369Sdim Predicate == CmpInst::FCMP_TRUE ? 1 : 0); 413321369Sdim MI.eraseFromParent(); 414321369Sdim return true; 415321369Sdim } 416321369Sdim 417321369Sdim assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size"); 418321369Sdim auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx); 419321369Sdim auto *RetTy = Type::getInt32Ty(Ctx); 420321369Sdim 421353358Sdim SmallVector<Register, 2> Results; 422321369Sdim for (auto Libcall : Libcalls) { 423321369Sdim auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32)); 424321369Sdim auto Status = 425321369Sdim createLibcall(MIRBuilder, Libcall.LibcallID, {LibcallResult, RetTy}, 426321369Sdim {{MI.getOperand(2).getReg(), ArgTy}, 427321369Sdim {MI.getOperand(3).getReg(), ArgTy}}); 428321369Sdim 429321369Sdim if (Status != LegalizerHelper::Legalized) 430321369Sdim return false; 431321369Sdim 432321369Sdim auto ProcessedResult = 433321369Sdim Libcalls.size() == 1 434321369Sdim ? OriginalResult 435321369Sdim : MRI.createGenericVirtualRegister(MRI.getType(OriginalResult)); 436321369Sdim 437321369Sdim // We have a result, but we need to transform it into a proper 1-bit 0 or 438321369Sdim // 1, taking into account the different peculiarities of the values 439321369Sdim // returned by the comparison functions. 440321369Sdim CmpInst::Predicate ResultPred = Libcall.Predicate; 441321369Sdim if (ResultPred == CmpInst::BAD_ICMP_PREDICATE) { 442321369Sdim // We have a nice 0 or 1, and we just need to truncate it back to 1 bit 443321369Sdim // to keep the types consistent. 444321369Sdim MIRBuilder.buildTrunc(ProcessedResult, LibcallResult); 445321369Sdim } else { 446321369Sdim // We need to compare against 0. 447321369Sdim assert(CmpInst::isIntPredicate(ResultPred) && "Unsupported predicate"); 448321369Sdim auto Zero = MRI.createGenericVirtualRegister(LLT::scalar(32)); 449321369Sdim MIRBuilder.buildConstant(Zero, 0); 450321369Sdim MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero); 451321369Sdim } 452321369Sdim Results.push_back(ProcessedResult); 453321369Sdim } 454321369Sdim 455321369Sdim if (Results.size() != 1) { 456321369Sdim assert(Results.size() == 2 && "Unexpected number of results"); 457321369Sdim MIRBuilder.buildOr(OriginalResult, Results[0], Results[1]); 458321369Sdim } 459321369Sdim break; 460321369Sdim } 461341825Sdim case G_FCONSTANT: { 462341825Sdim // Convert to integer constants, while preserving the binary representation. 463341825Sdim auto AsInteger = 464341825Sdim MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt(); 465341825Sdim MIRBuilder.buildConstant(MI.getOperand(0).getReg(), 466341825Sdim *ConstantInt::get(Ctx, AsInteger)); 467341825Sdim break; 468321369Sdim } 469341825Sdim } 470321369Sdim 471321369Sdim MI.eraseFromParent(); 472321369Sdim return true; 473321369Sdim} 474