xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric //===- ARMLegalizerInfo.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 ARM.
100b57cec5SDimitry Andric /// \todo This should be generated by TableGen.
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "ARMLegalizerInfo.h"
140b57cec5SDimitry Andric #include "ARMCallLowering.h"
150b57cec5SDimitry Andric #include "ARMSubtarget.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/LowLevelType.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/ValueTypes.h"
210b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
220b57cec5SDimitry Andric #include "llvm/IR/Type.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric using namespace LegalizeActions;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric /// FIXME: The following static functions are SizeChangeStrategy functions
280b57cec5SDimitry Andric /// that are meant to temporarily mimic the behaviour of the old legalization
290b57cec5SDimitry Andric /// based on doubling/halving non-legal types as closely as possible. This is
300b57cec5SDimitry Andric /// not entirly possible as only legalizing the types that are exactly a power
310b57cec5SDimitry Andric /// of 2 times the size of the legal types would require specifying all those
320b57cec5SDimitry Andric /// sizes explicitly.
330b57cec5SDimitry Andric /// In practice, not specifying those isn't a problem, and the below functions
340b57cec5SDimitry Andric /// should disappear quickly as we add support for legalizing non-power-of-2
350b57cec5SDimitry Andric /// sized types further.
36*fe6060f1SDimitry Andric static void addAndInterleaveWithUnsupported(
37*fe6060f1SDimitry Andric     LegacyLegalizerInfo::SizeAndActionsVec &result,
38*fe6060f1SDimitry Andric     const LegacyLegalizerInfo::SizeAndActionsVec &v) {
390b57cec5SDimitry Andric   for (unsigned i = 0; i < v.size(); ++i) {
400b57cec5SDimitry Andric     result.push_back(v[i]);
410b57cec5SDimitry Andric     if (i + 1 < v[i].first && i + 1 < v.size() &&
420b57cec5SDimitry Andric         v[i + 1].first != v[i].first + 1)
43*fe6060f1SDimitry Andric       result.push_back({v[i].first + 1, LegacyLegalizeActions::Unsupported});
440b57cec5SDimitry Andric   }
450b57cec5SDimitry Andric }
460b57cec5SDimitry Andric 
47*fe6060f1SDimitry Andric static LegacyLegalizerInfo::SizeAndActionsVec
48*fe6060f1SDimitry Andric widen_8_16(const LegacyLegalizerInfo::SizeAndActionsVec &v) {
490b57cec5SDimitry Andric   assert(v.size() >= 1);
500b57cec5SDimitry Andric   assert(v[0].first > 17);
51*fe6060f1SDimitry Andric   LegacyLegalizerInfo::SizeAndActionsVec result = {
52*fe6060f1SDimitry Andric       {1, LegacyLegalizeActions::Unsupported},
53*fe6060f1SDimitry Andric       {8, LegacyLegalizeActions::WidenScalar},
54*fe6060f1SDimitry Andric       {9, LegacyLegalizeActions::Unsupported},
55*fe6060f1SDimitry Andric       {16, LegacyLegalizeActions::WidenScalar},
56*fe6060f1SDimitry Andric       {17, LegacyLegalizeActions::Unsupported}};
570b57cec5SDimitry Andric   addAndInterleaveWithUnsupported(result, v);
580b57cec5SDimitry Andric   auto Largest = result.back().first;
59*fe6060f1SDimitry Andric   result.push_back({Largest + 1, LegacyLegalizeActions::Unsupported});
600b57cec5SDimitry Andric   return result;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric static bool AEABI(const ARMSubtarget &ST) {
640b57cec5SDimitry Andric   return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI();
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
680b57cec5SDimitry Andric   using namespace TargetOpcode;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   const LLT p0 = LLT::pointer(0, 32);
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   const LLT s1 = LLT::scalar(1);
730b57cec5SDimitry Andric   const LLT s8 = LLT::scalar(8);
740b57cec5SDimitry Andric   const LLT s16 = LLT::scalar(16);
750b57cec5SDimitry Andric   const LLT s32 = LLT::scalar(32);
760b57cec5SDimitry Andric   const LLT s64 = LLT::scalar(64);
770b57cec5SDimitry Andric 
78*fe6060f1SDimitry Andric   auto &LegacyInfo = getLegacyLegalizerInfo();
790b57cec5SDimitry Andric   if (ST.isThumb1Only()) {
800b57cec5SDimitry Andric     // Thumb1 is not supported yet.
81*fe6060f1SDimitry Andric     LegacyInfo.computeTables();
820b57cec5SDimitry Andric     verify(*ST.getInstrInfo());
830b57cec5SDimitry Andric     return;
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
870b57cec5SDimitry Andric       .legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16});
880b57cec5SDimitry Andric 
898bcb0991SDimitry Andric   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
908bcb0991SDimitry Andric 
910b57cec5SDimitry Andric   getActionDefinitionsBuilder({G_MUL, G_AND, G_OR, G_XOR})
920b57cec5SDimitry Andric       .legalFor({s32})
93e8d8bef9SDimitry Andric       .clampScalar(0, s32, s32);
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   if (ST.hasNEON())
960b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_ADD, G_SUB})
970b57cec5SDimitry Andric         .legalFor({s32, s64})
980b57cec5SDimitry Andric         .minScalar(0, s32);
990b57cec5SDimitry Andric   else
1000b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_ADD, G_SUB})
1010b57cec5SDimitry Andric         .legalFor({s32})
1020b57cec5SDimitry Andric         .minScalar(0, s32);
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL})
1050b57cec5SDimitry Andric     .legalFor({{s32, s32}})
1060b57cec5SDimitry Andric     .minScalar(0, s32)
1070b57cec5SDimitry Andric     .clampScalar(1, s32, s32);
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) ||
1100b57cec5SDimitry Andric                      (ST.isThumb() && ST.hasDivideInThumbMode());
1110b57cec5SDimitry Andric   if (HasHWDivide)
1120b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_SDIV, G_UDIV})
1130b57cec5SDimitry Andric         .legalFor({s32})
1140b57cec5SDimitry Andric         .clampScalar(0, s32, s32);
1150b57cec5SDimitry Andric   else
1160b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_SDIV, G_UDIV})
1170b57cec5SDimitry Andric         .libcallFor({s32})
1180b57cec5SDimitry Andric         .clampScalar(0, s32, s32);
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   for (unsigned Op : {G_SREM, G_UREM}) {
121*fe6060f1SDimitry Andric     LegacyInfo.setLegalizeScalarToDifferentSizeStrategy(Op, 0, widen_8_16);
1220b57cec5SDimitry Andric     if (HasHWDivide)
123*fe6060f1SDimitry Andric       LegacyInfo.setAction({Op, s32}, LegacyLegalizeActions::Lower);
1240b57cec5SDimitry Andric     else if (AEABI(ST))
125*fe6060f1SDimitry Andric       LegacyInfo.setAction({Op, s32}, LegacyLegalizeActions::Custom);
1260b57cec5SDimitry Andric     else
127*fe6060f1SDimitry Andric       LegacyInfo.setAction({Op, s32}, LegacyLegalizeActions::Libcall);
1280b57cec5SDimitry Andric   }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_INTTOPTR)
1310b57cec5SDimitry Andric       .legalFor({{p0, s32}})
1320b57cec5SDimitry Andric       .minScalar(1, s32);
1330b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_PTRTOINT)
1340b57cec5SDimitry Andric       .legalFor({{s32, p0}})
1350b57cec5SDimitry Andric       .minScalar(0, s32);
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_CONSTANT)
1380b57cec5SDimitry Andric       .legalFor({s32, p0})
1390b57cec5SDimitry Andric       .clampScalar(0, s32, s32);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_ICMP)
1420b57cec5SDimitry Andric       .legalForCartesianProduct({s1}, {s32, p0})
1430b57cec5SDimitry Andric       .minScalar(1, s32);
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_SELECT)
1460b57cec5SDimitry Andric       .legalForCartesianProduct({s32, p0}, {s1})
1470b57cec5SDimitry Andric       .minScalar(0, s32);
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   // We're keeping these builders around because we'll want to add support for
1500b57cec5SDimitry Andric   // floating point to them.
1510b57cec5SDimitry Andric   auto &LoadStoreBuilder = getActionDefinitionsBuilder({G_LOAD, G_STORE})
152*fe6060f1SDimitry Andric                                .legalForTypesWithMemDesc({{s8, p0, s8, 8},
153*fe6060f1SDimitry Andric                                                           {s16, p0, s16, 8},
154*fe6060f1SDimitry Andric                                                           {s32, p0, s32, 8},
155*fe6060f1SDimitry Andric                                                           {p0, p0, p0, 8}})
1560b57cec5SDimitry Andric                                .unsupportedIfMemSizeNotPow2();
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
1590b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   auto &PhiBuilder =
1620b57cec5SDimitry Andric       getActionDefinitionsBuilder(G_PHI)
1630b57cec5SDimitry Andric           .legalFor({s32, p0})
1640b57cec5SDimitry Andric           .minScalar(0, s32);
1650b57cec5SDimitry Andric 
166480093f4SDimitry Andric   getActionDefinitionsBuilder(G_PTR_ADD)
1670b57cec5SDimitry Andric       .legalFor({{p0, s32}})
1680b57cec5SDimitry Andric       .minScalar(1, s32);
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric   getActionDefinitionsBuilder(G_BRCOND).legalFor({s1});
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   if (!ST.useSoftFloat() && ST.hasVFP2Base()) {
1730b57cec5SDimitry Andric     getActionDefinitionsBuilder(
1740b57cec5SDimitry Andric         {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG})
1750b57cec5SDimitry Andric         .legalFor({s32, s64});
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric     LoadStoreBuilder
178*fe6060f1SDimitry Andric         .legalForTypesWithMemDesc({{s64, p0, s64, 32}})
1790b57cec5SDimitry Andric         .maxScalar(0, s32);
1800b57cec5SDimitry Andric     PhiBuilder.legalFor({s64});
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FCMP).legalForCartesianProduct({s1},
1830b57cec5SDimitry Andric                                                                  {s32, s64});
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_MERGE_VALUES).legalFor({{s64, s32}});
1860b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}});
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FPEXT).legalFor({{s64, s32}});
1890b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FPTRUNC).legalFor({{s32, s64}});
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
1920b57cec5SDimitry Andric         .legalForCartesianProduct({s32}, {s32, s64});
1930b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
1940b57cec5SDimitry Andric         .legalForCartesianProduct({s32, s64}, {s32});
1950b57cec5SDimitry Andric   } else {
1960b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
1970b57cec5SDimitry Andric         .libcallFor({s32, s64});
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric     LoadStoreBuilder.maxScalar(0, s32);
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric     for (auto Ty : {s32, s64})
202*fe6060f1SDimitry Andric       LegacyInfo.setAction({G_FNEG, Ty}, LegacyLegalizeActions::Lower);
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64});
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FCMP).customForCartesianProduct({s1},
2070b57cec5SDimitry Andric                                                                   {s32, s64});
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric     if (AEABI(ST))
2100b57cec5SDimitry Andric       setFCmpLibcallsAEABI();
2110b57cec5SDimitry Andric     else
2120b57cec5SDimitry Andric       setFCmpLibcallsGNU();
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s64, s32}});
2150b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s32, s64}});
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
2180b57cec5SDimitry Andric         .libcallForCartesianProduct({s32}, {s32, s64});
2190b57cec5SDimitry Andric     getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
2200b57cec5SDimitry Andric         .libcallForCartesianProduct({s32, s64}, {s32});
2210b57cec5SDimitry Andric   }
2220b57cec5SDimitry Andric 
223*fe6060f1SDimitry Andric   // Just expand whatever loads and stores are left.
224*fe6060f1SDimitry Andric   LoadStoreBuilder.lower();
225*fe6060f1SDimitry Andric 
2260b57cec5SDimitry Andric   if (!ST.useSoftFloat() && ST.hasVFP4Base())
2270b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FMA).legalFor({s32, s64});
2280b57cec5SDimitry Andric   else
2290b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64});
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64});
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   if (ST.hasV5TOps()) {
2340b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_CTLZ)
2350b57cec5SDimitry Andric         .legalFor({s32, s32})
2360b57cec5SDimitry Andric         .clampScalar(1, s32, s32)
2370b57cec5SDimitry Andric         .clampScalar(0, s32, s32);
2380b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)
2390b57cec5SDimitry Andric         .lowerFor({s32, s32})
2400b57cec5SDimitry Andric         .clampScalar(1, s32, s32)
2410b57cec5SDimitry Andric         .clampScalar(0, s32, s32);
2420b57cec5SDimitry Andric   } else {
2430b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)
2440b57cec5SDimitry Andric         .libcallFor({s32, s32})
2450b57cec5SDimitry Andric         .clampScalar(1, s32, s32)
2460b57cec5SDimitry Andric         .clampScalar(0, s32, s32);
2470b57cec5SDimitry Andric     getActionDefinitionsBuilder(G_CTLZ)
2480b57cec5SDimitry Andric         .lowerFor({s32, s32})
2490b57cec5SDimitry Andric         .clampScalar(1, s32, s32)
2500b57cec5SDimitry Andric         .clampScalar(0, s32, s32);
2510b57cec5SDimitry Andric   }
2520b57cec5SDimitry Andric 
253*fe6060f1SDimitry Andric   LegacyInfo.computeTables();
2540b57cec5SDimitry Andric   verify(*ST.getInstrInfo());
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric void ARMLegalizerInfo::setFCmpLibcallsAEABI() {
2580b57cec5SDimitry Andric   // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
2590b57cec5SDimitry Andric   // default-initialized.
2600b57cec5SDimitry Andric   FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
2610b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OEQ] = {
2620b57cec5SDimitry Andric       {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE}};
2630b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OGE] = {
2640b57cec5SDimitry Andric       {RTLIB::OGE_F32, CmpInst::BAD_ICMP_PREDICATE}};
2650b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OGT] = {
2660b57cec5SDimitry Andric       {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE}};
2670b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OLE] = {
2680b57cec5SDimitry Andric       {RTLIB::OLE_F32, CmpInst::BAD_ICMP_PREDICATE}};
2690b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OLT] = {
2700b57cec5SDimitry Andric       {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
271480093f4SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
2720b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_EQ}};
2730b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_EQ}};
2740b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_EQ}};
2750b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_EQ}};
2760b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_EQ}};
2770b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UNO] = {
2780b57cec5SDimitry Andric       {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
2790b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ONE] = {
2800b57cec5SDimitry Andric       {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE},
2810b57cec5SDimitry Andric       {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
2820b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UEQ] = {
2830b57cec5SDimitry Andric       {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE},
2840b57cec5SDimitry Andric       {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
2870b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OEQ] = {
2880b57cec5SDimitry Andric       {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE}};
2890b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OGE] = {
2900b57cec5SDimitry Andric       {RTLIB::OGE_F64, CmpInst::BAD_ICMP_PREDICATE}};
2910b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OGT] = {
2920b57cec5SDimitry Andric       {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE}};
2930b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OLE] = {
2940b57cec5SDimitry Andric       {RTLIB::OLE_F64, CmpInst::BAD_ICMP_PREDICATE}};
2950b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OLT] = {
2960b57cec5SDimitry Andric       {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
297480093f4SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
2980b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_EQ}};
2990b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_EQ}};
3000b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_EQ}};
3010b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_EQ}};
3020b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_EQ}};
3030b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UNO] = {
3040b57cec5SDimitry Andric       {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
3050b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ONE] = {
3060b57cec5SDimitry Andric       {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE},
3070b57cec5SDimitry Andric       {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
3080b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UEQ] = {
3090b57cec5SDimitry Andric       {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE},
3100b57cec5SDimitry Andric       {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
3110b57cec5SDimitry Andric }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric void ARMLegalizerInfo::setFCmpLibcallsGNU() {
3140b57cec5SDimitry Andric   // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
3150b57cec5SDimitry Andric   // default-initialized.
3160b57cec5SDimitry Andric   FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
3170b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}};
3180b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F32, CmpInst::ICMP_SGE}};
3190b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT}};
3200b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F32, CmpInst::ICMP_SLE}};
3210b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
322480093f4SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
3230b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_SGE}};
3240b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_SGT}};
3250b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SLE}};
3260b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_SLT}};
3270b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_NE}};
3280b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F32, CmpInst::ICMP_NE}};
3290b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT},
3300b57cec5SDimitry Andric                                        {RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
3310b57cec5SDimitry Andric   FCmp32Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ},
3320b57cec5SDimitry Andric                                        {RTLIB::UO_F32, CmpInst::ICMP_NE}};
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
3350b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}};
3360b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F64, CmpInst::ICMP_SGE}};
3370b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT}};
3380b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F64, CmpInst::ICMP_SLE}};
3390b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
340480093f4SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
3410b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_SGE}};
3420b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_SGT}};
3430b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SLE}};
3440b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_SLT}};
3450b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_NE}};
3460b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F64, CmpInst::ICMP_NE}};
3470b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT},
3480b57cec5SDimitry Andric                                        {RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
3490b57cec5SDimitry Andric   FCmp64Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ},
3500b57cec5SDimitry Andric                                        {RTLIB::UO_F64, CmpInst::ICMP_NE}};
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric ARMLegalizerInfo::FCmpLibcallsList
3540b57cec5SDimitry Andric ARMLegalizerInfo::getFCmpLibcalls(CmpInst::Predicate Predicate,
3550b57cec5SDimitry Andric                                   unsigned Size) const {
3560b57cec5SDimitry Andric   assert(CmpInst::isFPPredicate(Predicate) && "Unsupported FCmp predicate");
3570b57cec5SDimitry Andric   if (Size == 32)
3580b57cec5SDimitry Andric     return FCmp32Libcalls[Predicate];
3590b57cec5SDimitry Andric   if (Size == 64)
3600b57cec5SDimitry Andric     return FCmp64Libcalls[Predicate];
3610b57cec5SDimitry Andric   llvm_unreachable("Unsupported size for FCmp predicate");
3620b57cec5SDimitry Andric }
3630b57cec5SDimitry Andric 
3645ffd83dbSDimitry Andric bool ARMLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
3655ffd83dbSDimitry Andric                                       MachineInstr &MI) const {
3660b57cec5SDimitry Andric   using namespace TargetOpcode;
3670b57cec5SDimitry Andric 
3685ffd83dbSDimitry Andric   MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
3695ffd83dbSDimitry Andric   MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3700b57cec5SDimitry Andric   LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   switch (MI.getOpcode()) {
3730b57cec5SDimitry Andric   default:
3740b57cec5SDimitry Andric     return false;
3750b57cec5SDimitry Andric   case G_SREM:
3760b57cec5SDimitry Andric   case G_UREM: {
3770b57cec5SDimitry Andric     Register OriginalResult = MI.getOperand(0).getReg();
3780b57cec5SDimitry Andric     auto Size = MRI.getType(OriginalResult).getSizeInBits();
3790b57cec5SDimitry Andric     if (Size != 32)
3800b57cec5SDimitry Andric       return false;
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric     auto Libcall =
3830b57cec5SDimitry Andric         MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric     // Our divmod libcalls return a struct containing the quotient and the
3860b57cec5SDimitry Andric     // remainder. Create a new, unused register for the quotient and use the
3870b57cec5SDimitry Andric     // destination of the original instruction for the remainder.
3880b57cec5SDimitry Andric     Type *ArgTy = Type::getInt32Ty(Ctx);
3890b57cec5SDimitry Andric     StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);
3900b57cec5SDimitry Andric     Register RetRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
3910b57cec5SDimitry Andric                           OriginalResult};
392*fe6060f1SDimitry Andric     auto Status = createLibcall(MIRBuilder, Libcall, {RetRegs, RetTy, 0},
393*fe6060f1SDimitry Andric                                 {{MI.getOperand(1).getReg(), ArgTy, 0},
394*fe6060f1SDimitry Andric                                  {MI.getOperand(2).getReg(), ArgTy, 0}});
3950b57cec5SDimitry Andric     if (Status != LegalizerHelper::Legalized)
3960b57cec5SDimitry Andric       return false;
3970b57cec5SDimitry Andric     break;
3980b57cec5SDimitry Andric   }
3990b57cec5SDimitry Andric   case G_FCMP: {
4000b57cec5SDimitry Andric     assert(MRI.getType(MI.getOperand(2).getReg()) ==
4010b57cec5SDimitry Andric                MRI.getType(MI.getOperand(3).getReg()) &&
4020b57cec5SDimitry Andric            "Mismatched operands for G_FCMP");
4030b57cec5SDimitry Andric     auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric     auto OriginalResult = MI.getOperand(0).getReg();
4060b57cec5SDimitry Andric     auto Predicate =
4070b57cec5SDimitry Andric         static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
4080b57cec5SDimitry Andric     auto Libcalls = getFCmpLibcalls(Predicate, OpSize);
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric     if (Libcalls.empty()) {
4110b57cec5SDimitry Andric       assert((Predicate == CmpInst::FCMP_TRUE ||
4120b57cec5SDimitry Andric               Predicate == CmpInst::FCMP_FALSE) &&
4130b57cec5SDimitry Andric              "Predicate needs libcalls, but none specified");
4140b57cec5SDimitry Andric       MIRBuilder.buildConstant(OriginalResult,
4150b57cec5SDimitry Andric                                Predicate == CmpInst::FCMP_TRUE ? 1 : 0);
4160b57cec5SDimitry Andric       MI.eraseFromParent();
4170b57cec5SDimitry Andric       return true;
4180b57cec5SDimitry Andric     }
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric     assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");
4210b57cec5SDimitry Andric     auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx);
4220b57cec5SDimitry Andric     auto *RetTy = Type::getInt32Ty(Ctx);
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric     SmallVector<Register, 2> Results;
4250b57cec5SDimitry Andric     for (auto Libcall : Libcalls) {
4260b57cec5SDimitry Andric       auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));
427*fe6060f1SDimitry Andric       auto Status = createLibcall(MIRBuilder, Libcall.LibcallID,
428*fe6060f1SDimitry Andric                                   {LibcallResult, RetTy, 0},
429*fe6060f1SDimitry Andric                                   {{MI.getOperand(2).getReg(), ArgTy, 0},
430*fe6060f1SDimitry Andric                                    {MI.getOperand(3).getReg(), ArgTy, 0}});
4310b57cec5SDimitry Andric 
4320b57cec5SDimitry Andric       if (Status != LegalizerHelper::Legalized)
4330b57cec5SDimitry Andric         return false;
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric       auto ProcessedResult =
4360b57cec5SDimitry Andric           Libcalls.size() == 1
4370b57cec5SDimitry Andric               ? OriginalResult
4380b57cec5SDimitry Andric               : MRI.createGenericVirtualRegister(MRI.getType(OriginalResult));
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric       // We have a result, but we need to transform it into a proper 1-bit 0 or
4410b57cec5SDimitry Andric       // 1, taking into account the different peculiarities of the values
4420b57cec5SDimitry Andric       // returned by the comparison functions.
4430b57cec5SDimitry Andric       CmpInst::Predicate ResultPred = Libcall.Predicate;
4440b57cec5SDimitry Andric       if (ResultPred == CmpInst::BAD_ICMP_PREDICATE) {
4450b57cec5SDimitry Andric         // We have a nice 0 or 1, and we just need to truncate it back to 1 bit
4460b57cec5SDimitry Andric         // to keep the types consistent.
4470b57cec5SDimitry Andric         MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);
4480b57cec5SDimitry Andric       } else {
4490b57cec5SDimitry Andric         // We need to compare against 0.
4500b57cec5SDimitry Andric         assert(CmpInst::isIntPredicate(ResultPred) && "Unsupported predicate");
4515ffd83dbSDimitry Andric         auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
4520b57cec5SDimitry Andric         MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);
4530b57cec5SDimitry Andric       }
4540b57cec5SDimitry Andric       Results.push_back(ProcessedResult);
4550b57cec5SDimitry Andric     }
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric     if (Results.size() != 1) {
4580b57cec5SDimitry Andric       assert(Results.size() == 2 && "Unexpected number of results");
4590b57cec5SDimitry Andric       MIRBuilder.buildOr(OriginalResult, Results[0], Results[1]);
4600b57cec5SDimitry Andric     }
4610b57cec5SDimitry Andric     break;
4620b57cec5SDimitry Andric   }
4630b57cec5SDimitry Andric   case G_FCONSTANT: {
4640b57cec5SDimitry Andric     // Convert to integer constants, while preserving the binary representation.
4650b57cec5SDimitry Andric     auto AsInteger =
4660b57cec5SDimitry Andric         MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();
4675ffd83dbSDimitry Andric     MIRBuilder.buildConstant(MI.getOperand(0),
4680b57cec5SDimitry Andric                              *ConstantInt::get(Ctx, AsInteger));
4690b57cec5SDimitry Andric     break;
4700b57cec5SDimitry Andric   }
4710b57cec5SDimitry Andric   }
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric   MI.eraseFromParent();
4740b57cec5SDimitry Andric   return true;
4750b57cec5SDimitry Andric }
476