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"
1781ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
1806c3fb27SDimitry Andric #include "llvm/CodeGen/LowLevelTypeUtils.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/ValueTypes.h"
220b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
230b57cec5SDimitry Andric #include "llvm/IR/Type.h"
240b57cec5SDimitry Andric
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric using namespace LegalizeActions;
270b57cec5SDimitry Andric
AEABI(const ARMSubtarget & ST)280b57cec5SDimitry Andric static bool AEABI(const ARMSubtarget &ST) {
290b57cec5SDimitry Andric return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI();
300b57cec5SDimitry Andric }
310b57cec5SDimitry Andric
ARMLegalizerInfo(const ARMSubtarget & ST)320b57cec5SDimitry Andric ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
330b57cec5SDimitry Andric using namespace TargetOpcode;
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric const LLT p0 = LLT::pointer(0, 32);
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric const LLT s1 = LLT::scalar(1);
380b57cec5SDimitry Andric const LLT s8 = LLT::scalar(8);
390b57cec5SDimitry Andric const LLT s16 = LLT::scalar(16);
400b57cec5SDimitry Andric const LLT s32 = LLT::scalar(32);
410b57cec5SDimitry Andric const LLT s64 = LLT::scalar(64);
420b57cec5SDimitry Andric
43fe6060f1SDimitry Andric auto &LegacyInfo = getLegacyLegalizerInfo();
440b57cec5SDimitry Andric if (ST.isThumb1Only()) {
450b57cec5SDimitry Andric // Thumb1 is not supported yet.
46fe6060f1SDimitry Andric LegacyInfo.computeTables();
470b57cec5SDimitry Andric verify(*ST.getInstrInfo());
480b57cec5SDimitry Andric return;
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
520b57cec5SDimitry Andric .legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16});
530b57cec5SDimitry Andric
548bcb0991SDimitry Andric getActionDefinitionsBuilder(G_SEXT_INREG).lower();
558bcb0991SDimitry Andric
560b57cec5SDimitry Andric getActionDefinitionsBuilder({G_MUL, G_AND, G_OR, G_XOR})
570b57cec5SDimitry Andric .legalFor({s32})
58e8d8bef9SDimitry Andric .clampScalar(0, s32, s32);
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric if (ST.hasNEON())
610b57cec5SDimitry Andric getActionDefinitionsBuilder({G_ADD, G_SUB})
620b57cec5SDimitry Andric .legalFor({s32, s64})
630b57cec5SDimitry Andric .minScalar(0, s32);
640b57cec5SDimitry Andric else
650b57cec5SDimitry Andric getActionDefinitionsBuilder({G_ADD, G_SUB})
660b57cec5SDimitry Andric .legalFor({s32})
670b57cec5SDimitry Andric .minScalar(0, s32);
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL})
700b57cec5SDimitry Andric .legalFor({{s32, s32}})
710b57cec5SDimitry Andric .minScalar(0, s32)
720b57cec5SDimitry Andric .clampScalar(1, s32, s32);
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) ||
750b57cec5SDimitry Andric (ST.isThumb() && ST.hasDivideInThumbMode());
760b57cec5SDimitry Andric if (HasHWDivide)
770b57cec5SDimitry Andric getActionDefinitionsBuilder({G_SDIV, G_UDIV})
780b57cec5SDimitry Andric .legalFor({s32})
790b57cec5SDimitry Andric .clampScalar(0, s32, s32);
800b57cec5SDimitry Andric else
810b57cec5SDimitry Andric getActionDefinitionsBuilder({G_SDIV, G_UDIV})
820b57cec5SDimitry Andric .libcallFor({s32})
830b57cec5SDimitry Andric .clampScalar(0, s32, s32);
840b57cec5SDimitry Andric
85*0fca6ea1SDimitry Andric auto &REMBuilder =
86*0fca6ea1SDimitry Andric getActionDefinitionsBuilder({G_SREM, G_UREM}).minScalar(0, s32);
870b57cec5SDimitry Andric if (HasHWDivide)
88*0fca6ea1SDimitry Andric REMBuilder.lowerFor({s32});
890b57cec5SDimitry Andric else if (AEABI(ST))
90*0fca6ea1SDimitry Andric REMBuilder.customFor({s32});
910b57cec5SDimitry Andric else
92*0fca6ea1SDimitry Andric REMBuilder.libcallFor({s32});
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric getActionDefinitionsBuilder(G_INTTOPTR)
950b57cec5SDimitry Andric .legalFor({{p0, s32}})
960b57cec5SDimitry Andric .minScalar(1, s32);
970b57cec5SDimitry Andric getActionDefinitionsBuilder(G_PTRTOINT)
980b57cec5SDimitry Andric .legalFor({{s32, p0}})
990b57cec5SDimitry Andric .minScalar(0, s32);
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric getActionDefinitionsBuilder(G_CONSTANT)
1020b57cec5SDimitry Andric .legalFor({s32, p0})
1030b57cec5SDimitry Andric .clampScalar(0, s32, s32);
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric getActionDefinitionsBuilder(G_ICMP)
1060b57cec5SDimitry Andric .legalForCartesianProduct({s1}, {s32, p0})
1070b57cec5SDimitry Andric .minScalar(1, s32);
1080b57cec5SDimitry Andric
1090b57cec5SDimitry Andric getActionDefinitionsBuilder(G_SELECT)
1100b57cec5SDimitry Andric .legalForCartesianProduct({s32, p0}, {s1})
1110b57cec5SDimitry Andric .minScalar(0, s32);
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric // We're keeping these builders around because we'll want to add support for
1140b57cec5SDimitry Andric // floating point to them.
1150b57cec5SDimitry Andric auto &LoadStoreBuilder = getActionDefinitionsBuilder({G_LOAD, G_STORE})
116fe6060f1SDimitry Andric .legalForTypesWithMemDesc({{s8, p0, s8, 8},
117fe6060f1SDimitry Andric {s16, p0, s16, 8},
118fe6060f1SDimitry Andric {s32, p0, s32, 8},
119fe6060f1SDimitry Andric {p0, p0, p0, 8}})
1200b57cec5SDimitry Andric .unsupportedIfMemSizeNotPow2();
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
1230b57cec5SDimitry Andric getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric auto &PhiBuilder =
1260b57cec5SDimitry Andric getActionDefinitionsBuilder(G_PHI)
1270b57cec5SDimitry Andric .legalFor({s32, p0})
1280b57cec5SDimitry Andric .minScalar(0, s32);
1290b57cec5SDimitry Andric
130480093f4SDimitry Andric getActionDefinitionsBuilder(G_PTR_ADD)
1310b57cec5SDimitry Andric .legalFor({{p0, s32}})
1320b57cec5SDimitry Andric .minScalar(1, s32);
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric getActionDefinitionsBuilder(G_BRCOND).legalFor({s1});
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric if (!ST.useSoftFloat() && ST.hasVFP2Base()) {
1370b57cec5SDimitry Andric getActionDefinitionsBuilder(
1380b57cec5SDimitry Andric {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG})
1390b57cec5SDimitry Andric .legalFor({s32, s64});
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric LoadStoreBuilder
142fe6060f1SDimitry Andric .legalForTypesWithMemDesc({{s64, p0, s64, 32}})
1430b57cec5SDimitry Andric .maxScalar(0, s32);
1440b57cec5SDimitry Andric PhiBuilder.legalFor({s64});
1450b57cec5SDimitry Andric
1460b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FCMP).legalForCartesianProduct({s1},
1470b57cec5SDimitry Andric {s32, s64});
1480b57cec5SDimitry Andric
1490b57cec5SDimitry Andric getActionDefinitionsBuilder(G_MERGE_VALUES).legalFor({{s64, s32}});
1500b57cec5SDimitry Andric getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}});
1510b57cec5SDimitry Andric
1520b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPEXT).legalFor({{s64, s32}});
1530b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPTRUNC).legalFor({{s32, s64}});
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
1560b57cec5SDimitry Andric .legalForCartesianProduct({s32}, {s32, s64});
1570b57cec5SDimitry Andric getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
1580b57cec5SDimitry Andric .legalForCartesianProduct({s32, s64}, {s32});
159*0fca6ea1SDimitry Andric
160*0fca6ea1SDimitry Andric getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_GET_FPMODE})
161*0fca6ea1SDimitry Andric .legalFor({s32});
162*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_RESET_FPENV).alwaysLegal();
163*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_SET_FPMODE).customFor({s32});
1640b57cec5SDimitry Andric } else {
1650b57cec5SDimitry Andric getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
1660b57cec5SDimitry Andric .libcallFor({s32, s64});
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric LoadStoreBuilder.maxScalar(0, s32);
1690b57cec5SDimitry Andric
170*0fca6ea1SDimitry Andric getActionDefinitionsBuilder(G_FNEG).lowerFor({s32, s64});
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64});
1730b57cec5SDimitry Andric
1740b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FCMP).customForCartesianProduct({s1},
1750b57cec5SDimitry Andric {s32, s64});
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric if (AEABI(ST))
1780b57cec5SDimitry Andric setFCmpLibcallsAEABI();
1790b57cec5SDimitry Andric else
1800b57cec5SDimitry Andric setFCmpLibcallsGNU();
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s64, s32}});
1830b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s32, s64}});
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
1860b57cec5SDimitry Andric .libcallForCartesianProduct({s32}, {s32, s64});
1870b57cec5SDimitry Andric getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
1880b57cec5SDimitry Andric .libcallForCartesianProduct({s32, s64}, {s32});
189*0fca6ea1SDimitry Andric
190*0fca6ea1SDimitry Andric getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_RESET_FPENV})
191*0fca6ea1SDimitry Andric .libcall();
192*0fca6ea1SDimitry Andric getActionDefinitionsBuilder({G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})
193*0fca6ea1SDimitry Andric .libcall();
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric
196fe6060f1SDimitry Andric // Just expand whatever loads and stores are left.
197fe6060f1SDimitry Andric LoadStoreBuilder.lower();
198fe6060f1SDimitry Andric
1990b57cec5SDimitry Andric if (!ST.useSoftFloat() && ST.hasVFP4Base())
2000b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FMA).legalFor({s32, s64});
2010b57cec5SDimitry Andric else
2020b57cec5SDimitry Andric getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64});
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64});
2050b57cec5SDimitry Andric
2060b57cec5SDimitry Andric if (ST.hasV5TOps()) {
2070b57cec5SDimitry Andric getActionDefinitionsBuilder(G_CTLZ)
2080b57cec5SDimitry Andric .legalFor({s32, s32})
2090b57cec5SDimitry Andric .clampScalar(1, s32, s32)
2100b57cec5SDimitry Andric .clampScalar(0, s32, s32);
2110b57cec5SDimitry Andric getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)
2120b57cec5SDimitry Andric .lowerFor({s32, s32})
2130b57cec5SDimitry Andric .clampScalar(1, s32, s32)
2140b57cec5SDimitry Andric .clampScalar(0, s32, s32);
2150b57cec5SDimitry Andric } else {
2160b57cec5SDimitry Andric getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)
2170b57cec5SDimitry Andric .libcallFor({s32, s32})
2180b57cec5SDimitry Andric .clampScalar(1, s32, s32)
2190b57cec5SDimitry Andric .clampScalar(0, s32, s32);
2200b57cec5SDimitry Andric getActionDefinitionsBuilder(G_CTLZ)
2210b57cec5SDimitry Andric .lowerFor({s32, s32})
2220b57cec5SDimitry Andric .clampScalar(1, s32, s32)
2230b57cec5SDimitry Andric .clampScalar(0, s32, s32);
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric
226fe6060f1SDimitry Andric LegacyInfo.computeTables();
2270b57cec5SDimitry Andric verify(*ST.getInstrInfo());
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric
setFCmpLibcallsAEABI()2300b57cec5SDimitry Andric void ARMLegalizerInfo::setFCmpLibcallsAEABI() {
2310b57cec5SDimitry Andric // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
2320b57cec5SDimitry Andric // default-initialized.
2330b57cec5SDimitry Andric FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
2340b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OEQ] = {
2350b57cec5SDimitry Andric {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE}};
2360b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OGE] = {
2370b57cec5SDimitry Andric {RTLIB::OGE_F32, CmpInst::BAD_ICMP_PREDICATE}};
2380b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OGT] = {
2390b57cec5SDimitry Andric {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE}};
2400b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OLE] = {
2410b57cec5SDimitry Andric {RTLIB::OLE_F32, CmpInst::BAD_ICMP_PREDICATE}};
2420b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OLT] = {
2430b57cec5SDimitry Andric {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
244480093f4SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
2450b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_EQ}};
2460b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_EQ}};
2470b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_EQ}};
2480b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_EQ}};
2490b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_EQ}};
2500b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UNO] = {
2510b57cec5SDimitry Andric {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
2520b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ONE] = {
2530b57cec5SDimitry Andric {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE},
2540b57cec5SDimitry Andric {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
2550b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UEQ] = {
2560b57cec5SDimitry Andric {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE},
2570b57cec5SDimitry Andric {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
2600b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OEQ] = {
2610b57cec5SDimitry Andric {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE}};
2620b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OGE] = {
2630b57cec5SDimitry Andric {RTLIB::OGE_F64, CmpInst::BAD_ICMP_PREDICATE}};
2640b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OGT] = {
2650b57cec5SDimitry Andric {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE}};
2660b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OLE] = {
2670b57cec5SDimitry Andric {RTLIB::OLE_F64, CmpInst::BAD_ICMP_PREDICATE}};
2680b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OLT] = {
2690b57cec5SDimitry Andric {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
270480093f4SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
2710b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_EQ}};
2720b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_EQ}};
2730b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_EQ}};
2740b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_EQ}};
2750b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_EQ}};
2760b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UNO] = {
2770b57cec5SDimitry Andric {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
2780b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ONE] = {
2790b57cec5SDimitry Andric {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE},
2800b57cec5SDimitry Andric {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
2810b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UEQ] = {
2820b57cec5SDimitry Andric {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE},
2830b57cec5SDimitry Andric {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
2840b57cec5SDimitry Andric }
2850b57cec5SDimitry Andric
setFCmpLibcallsGNU()2860b57cec5SDimitry Andric void ARMLegalizerInfo::setFCmpLibcallsGNU() {
2870b57cec5SDimitry Andric // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
2880b57cec5SDimitry Andric // default-initialized.
2890b57cec5SDimitry Andric FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
2900b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}};
2910b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F32, CmpInst::ICMP_SGE}};
2920b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT}};
2930b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F32, CmpInst::ICMP_SLE}};
2940b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
295480093f4SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
2960b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_SGE}};
2970b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_SGT}};
2980b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SLE}};
2990b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_SLT}};
3000b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_NE}};
3010b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F32, CmpInst::ICMP_NE}};
3020b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT},
3030b57cec5SDimitry Andric {RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
3040b57cec5SDimitry Andric FCmp32Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ},
3050b57cec5SDimitry Andric {RTLIB::UO_F32, CmpInst::ICMP_NE}};
3060b57cec5SDimitry Andric
3070b57cec5SDimitry Andric FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
3080b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}};
3090b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F64, CmpInst::ICMP_SGE}};
3100b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT}};
3110b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F64, CmpInst::ICMP_SLE}};
3120b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
313480093f4SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
3140b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_SGE}};
3150b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_SGT}};
3160b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SLE}};
3170b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_SLT}};
3180b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_NE}};
3190b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F64, CmpInst::ICMP_NE}};
3200b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT},
3210b57cec5SDimitry Andric {RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
3220b57cec5SDimitry Andric FCmp64Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ},
3230b57cec5SDimitry Andric {RTLIB::UO_F64, CmpInst::ICMP_NE}};
3240b57cec5SDimitry Andric }
3250b57cec5SDimitry Andric
3260b57cec5SDimitry Andric ARMLegalizerInfo::FCmpLibcallsList
getFCmpLibcalls(CmpInst::Predicate Predicate,unsigned Size) const3270b57cec5SDimitry Andric ARMLegalizerInfo::getFCmpLibcalls(CmpInst::Predicate Predicate,
3280b57cec5SDimitry Andric unsigned Size) const {
3290b57cec5SDimitry Andric assert(CmpInst::isFPPredicate(Predicate) && "Unsupported FCmp predicate");
3300b57cec5SDimitry Andric if (Size == 32)
3310b57cec5SDimitry Andric return FCmp32Libcalls[Predicate];
3320b57cec5SDimitry Andric if (Size == 64)
3330b57cec5SDimitry Andric return FCmp64Libcalls[Predicate];
3340b57cec5SDimitry Andric llvm_unreachable("Unsupported size for FCmp predicate");
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric
legalizeCustom(LegalizerHelper & Helper,MachineInstr & MI,LostDebugLocObserver & LocObserver) const3371db9f3b2SDimitry Andric bool ARMLegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
3381db9f3b2SDimitry Andric LostDebugLocObserver &LocObserver) const {
3390b57cec5SDimitry Andric using namespace TargetOpcode;
3400b57cec5SDimitry Andric
3415ffd83dbSDimitry Andric MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
3425ffd83dbSDimitry Andric MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3430b57cec5SDimitry Andric LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3440b57cec5SDimitry Andric
3450b57cec5SDimitry Andric switch (MI.getOpcode()) {
3460b57cec5SDimitry Andric default:
3470b57cec5SDimitry Andric return false;
3480b57cec5SDimitry Andric case G_SREM:
3490b57cec5SDimitry Andric case G_UREM: {
3500b57cec5SDimitry Andric Register OriginalResult = MI.getOperand(0).getReg();
3510b57cec5SDimitry Andric auto Size = MRI.getType(OriginalResult).getSizeInBits();
3520b57cec5SDimitry Andric if (Size != 32)
3530b57cec5SDimitry Andric return false;
3540b57cec5SDimitry Andric
3550b57cec5SDimitry Andric auto Libcall =
3560b57cec5SDimitry Andric MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
3570b57cec5SDimitry Andric
3580b57cec5SDimitry Andric // Our divmod libcalls return a struct containing the quotient and the
3590b57cec5SDimitry Andric // remainder. Create a new, unused register for the quotient and use the
3600b57cec5SDimitry Andric // destination of the original instruction for the remainder.
3610b57cec5SDimitry Andric Type *ArgTy = Type::getInt32Ty(Ctx);
3620b57cec5SDimitry Andric StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);
3630b57cec5SDimitry Andric Register RetRegs[] = {MRI.createGenericVirtualRegister(LLT::scalar(32)),
3640b57cec5SDimitry Andric OriginalResult};
365fe6060f1SDimitry Andric auto Status = createLibcall(MIRBuilder, Libcall, {RetRegs, RetTy, 0},
366fe6060f1SDimitry Andric {{MI.getOperand(1).getReg(), ArgTy, 0},
3671db9f3b2SDimitry Andric {MI.getOperand(2).getReg(), ArgTy, 0}},
3681db9f3b2SDimitry Andric LocObserver, &MI);
3690b57cec5SDimitry Andric if (Status != LegalizerHelper::Legalized)
3700b57cec5SDimitry Andric return false;
3710b57cec5SDimitry Andric break;
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric case G_FCMP: {
3740b57cec5SDimitry Andric assert(MRI.getType(MI.getOperand(2).getReg()) ==
3750b57cec5SDimitry Andric MRI.getType(MI.getOperand(3).getReg()) &&
3760b57cec5SDimitry Andric "Mismatched operands for G_FCMP");
3770b57cec5SDimitry Andric auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
3780b57cec5SDimitry Andric
3790b57cec5SDimitry Andric auto OriginalResult = MI.getOperand(0).getReg();
3800b57cec5SDimitry Andric auto Predicate =
3810b57cec5SDimitry Andric static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3820b57cec5SDimitry Andric auto Libcalls = getFCmpLibcalls(Predicate, OpSize);
3830b57cec5SDimitry Andric
3840b57cec5SDimitry Andric if (Libcalls.empty()) {
3850b57cec5SDimitry Andric assert((Predicate == CmpInst::FCMP_TRUE ||
3860b57cec5SDimitry Andric Predicate == CmpInst::FCMP_FALSE) &&
3870b57cec5SDimitry Andric "Predicate needs libcalls, but none specified");
3880b57cec5SDimitry Andric MIRBuilder.buildConstant(OriginalResult,
3890b57cec5SDimitry Andric Predicate == CmpInst::FCMP_TRUE ? 1 : 0);
3900b57cec5SDimitry Andric MI.eraseFromParent();
3910b57cec5SDimitry Andric return true;
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric
3940b57cec5SDimitry Andric assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");
3950b57cec5SDimitry Andric auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx);
3960b57cec5SDimitry Andric auto *RetTy = Type::getInt32Ty(Ctx);
3970b57cec5SDimitry Andric
3980b57cec5SDimitry Andric SmallVector<Register, 2> Results;
3990b57cec5SDimitry Andric for (auto Libcall : Libcalls) {
4000b57cec5SDimitry Andric auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));
401fe6060f1SDimitry Andric auto Status = createLibcall(MIRBuilder, Libcall.LibcallID,
402fe6060f1SDimitry Andric {LibcallResult, RetTy, 0},
403fe6060f1SDimitry Andric {{MI.getOperand(2).getReg(), ArgTy, 0},
4041db9f3b2SDimitry Andric {MI.getOperand(3).getReg(), ArgTy, 0}},
4051db9f3b2SDimitry Andric LocObserver, &MI);
4060b57cec5SDimitry Andric
4070b57cec5SDimitry Andric if (Status != LegalizerHelper::Legalized)
4080b57cec5SDimitry Andric return false;
4090b57cec5SDimitry Andric
4100b57cec5SDimitry Andric auto ProcessedResult =
4110b57cec5SDimitry Andric Libcalls.size() == 1
4120b57cec5SDimitry Andric ? OriginalResult
4130b57cec5SDimitry Andric : MRI.createGenericVirtualRegister(MRI.getType(OriginalResult));
4140b57cec5SDimitry Andric
4150b57cec5SDimitry Andric // We have a result, but we need to transform it into a proper 1-bit 0 or
4160b57cec5SDimitry Andric // 1, taking into account the different peculiarities of the values
4170b57cec5SDimitry Andric // returned by the comparison functions.
4180b57cec5SDimitry Andric CmpInst::Predicate ResultPred = Libcall.Predicate;
4190b57cec5SDimitry Andric if (ResultPred == CmpInst::BAD_ICMP_PREDICATE) {
4200b57cec5SDimitry Andric // We have a nice 0 or 1, and we just need to truncate it back to 1 bit
4210b57cec5SDimitry Andric // to keep the types consistent.
4220b57cec5SDimitry Andric MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);
4230b57cec5SDimitry Andric } else {
4240b57cec5SDimitry Andric // We need to compare against 0.
4250b57cec5SDimitry Andric assert(CmpInst::isIntPredicate(ResultPred) && "Unsupported predicate");
4265ffd83dbSDimitry Andric auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
4270b57cec5SDimitry Andric MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);
4280b57cec5SDimitry Andric }
4290b57cec5SDimitry Andric Results.push_back(ProcessedResult);
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric
4320b57cec5SDimitry Andric if (Results.size() != 1) {
4330b57cec5SDimitry Andric assert(Results.size() == 2 && "Unexpected number of results");
4340b57cec5SDimitry Andric MIRBuilder.buildOr(OriginalResult, Results[0], Results[1]);
4350b57cec5SDimitry Andric }
4360b57cec5SDimitry Andric break;
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric case G_FCONSTANT: {
4390b57cec5SDimitry Andric // Convert to integer constants, while preserving the binary representation.
4400b57cec5SDimitry Andric auto AsInteger =
4410b57cec5SDimitry Andric MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();
4425ffd83dbSDimitry Andric MIRBuilder.buildConstant(MI.getOperand(0),
4430b57cec5SDimitry Andric *ConstantInt::get(Ctx, AsInteger));
4440b57cec5SDimitry Andric break;
4450b57cec5SDimitry Andric }
446*0fca6ea1SDimitry Andric case G_SET_FPMODE: {
447*0fca6ea1SDimitry Andric // New FPSCR = (FPSCR & FPStatusBits) | (Modes & ~FPStatusBits)
448*0fca6ea1SDimitry Andric LLT FPEnvTy = LLT::scalar(32);
449*0fca6ea1SDimitry Andric auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);
450*0fca6ea1SDimitry Andric Register Modes = MI.getOperand(0).getReg();
451*0fca6ea1SDimitry Andric MIRBuilder.buildGetFPEnv(FPEnv);
452*0fca6ea1SDimitry Andric auto StatusBitMask = MIRBuilder.buildConstant(FPEnvTy, ARM::FPStatusBits);
453*0fca6ea1SDimitry Andric auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);
454*0fca6ea1SDimitry Andric auto NotStatusBitMask =
455*0fca6ea1SDimitry Andric MIRBuilder.buildConstant(FPEnvTy, ~ARM::FPStatusBits);
456*0fca6ea1SDimitry Andric auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);
457*0fca6ea1SDimitry Andric auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);
458*0fca6ea1SDimitry Andric MIRBuilder.buildSetFPEnv(NewFPSCR);
459*0fca6ea1SDimitry Andric break;
460*0fca6ea1SDimitry Andric }
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric
4630b57cec5SDimitry Andric MI.eraseFromParent();
4640b57cec5SDimitry Andric return true;
4650b57cec5SDimitry Andric }
466