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