LLVM 24.0.0git
ARMLegalizerInfo.cpp
Go to the documentation of this file.
1//===- ARMLegalizerInfo.cpp --------------------------------------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file implements the targeting of the Machinelegalizer class for ARM.
10/// \todo This should be generated by TableGen.
11//===----------------------------------------------------------------------===//
12
13#include "ARMLegalizerInfo.h"
14#include "ARMCallLowering.h"
15#include "ARMSubtarget.h"
23#include "llvm/IR/Type.h"
24
25using namespace llvm;
26using namespace LegalizeActions;
27
28static bool AEABI(const ARMSubtarget &ST) {
29 return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI();
30}
31
33 using namespace TargetOpcode;
34
35 const LLT p0 = LLT::pointer(0, 32);
36
37 const LLT s1 = LLT::scalar(1);
38 const LLT s8 = LLT::scalar(8);
39 const LLT s16 = LLT::scalar(16);
40 const LLT s32 = LLT::scalar(32);
41 const LLT s64 = LLT::scalar(64);
42
43 if (ST.isThumb1Only()) {
44 // Thumb1 is not supported yet.
45 verify(*ST.getInstrInfo());
46 return;
47 }
48
49 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
50 .legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16});
51
53 {s8, s16, s32});
54
55 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
56
57 getActionDefinitionsBuilder({G_MUL, G_AND, G_OR, G_XOR})
58 .legalFor({s32})
59 .clampScalar(0, s32, s32);
60
61 if (ST.hasNEON())
62 getActionDefinitionsBuilder({G_ADD, G_SUB})
63 .legalFor({s32, s64})
64 .minScalar(0, s32);
65 else
66 getActionDefinitionsBuilder({G_ADD, G_SUB})
67 .legalFor({s32})
68 .minScalar(0, s32);
69
70 getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL})
71 .legalFor({{s32, s32}})
72 .minScalar(0, s32)
73 .clampScalar(1, s32, s32);
74
75 bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) ||
76 (ST.isThumb() && ST.hasDivideInThumbMode());
77 if (HasHWDivide)
78 getActionDefinitionsBuilder({G_SDIV, G_UDIV})
79 .legalFor({s32})
80 .clampScalar(0, s32, s32);
81 else
82 getActionDefinitionsBuilder({G_SDIV, G_UDIV})
83 .libcallFor({s32})
84 .clampScalar(0, s32, s32);
85
86 auto &REMBuilder =
87 getActionDefinitionsBuilder({G_SREM, G_UREM}).minScalar(0, s32);
88 if (HasHWDivide)
89 REMBuilder.lowerFor({s32});
90 else if (AEABI(ST))
91 REMBuilder.customFor({s32});
92 else
93 REMBuilder.libcallFor({s32});
94
96 .legalFor({{p0, s32}})
97 .minScalar(1, s32);
99 .legalFor({{s32, p0}})
100 .minScalar(0, s32);
101
103 .customFor({s32, p0})
104 .clampScalar(0, s32, s32);
105
106 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
107
109 .legalForCartesianProduct({s1}, {s32, p0})
110 .minScalar(1, s32);
111
113 .legalForCartesianProduct({s32, p0}, {s1})
114 .minScalar(0, s32);
115
116 // We're keeping these builders around because we'll want to add support for
117 // floating point to them.
118 auto &LoadStoreBuilder = getActionDefinitionsBuilder({G_LOAD, G_STORE})
119 .legalForTypesWithMemDesc({{s8, p0, s8, 8},
120 {s16, p0, s16, 8},
121 {s32, p0, s32, 8},
122 {p0, p0, p0, 8}})
123 .unsupportedIfMemSizeNotPow2();
124
125 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
126 getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});
127
128 auto &PhiBuilder =
130 .legalFor({s32, p0})
131 .minScalar(0, s32);
132
134 .legalFor({{p0, s32}})
135 .minScalar(1, s32);
136
139
140 if (!ST.useSoftFloat() && ST.hasVFP2Base()) {
142 {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG})
143 .legalFor({s32, s64});
144
145 LoadStoreBuilder
146 .legalForTypesWithMemDesc({{s64, p0, s64, 32}})
147 .maxScalar(0, s32);
148 PhiBuilder.legalFor({s64});
149
151 {s32, s64});
152
153 getActionDefinitionsBuilder(G_MERGE_VALUES).legalFor({{s64, s32}});
154 getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}});
155
156 getActionDefinitionsBuilder(G_FPEXT).legalFor({{s64, s32}});
157 getActionDefinitionsBuilder(G_FPTRUNC).legalFor({{s32, s64}});
158
159 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
160 .legalForCartesianProduct({s32}, {s32, s64});
161 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
162 .legalForCartesianProduct({s32, s64}, {s32});
163
164 getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_GET_FPMODE})
165 .legalFor({s32});
167 getActionDefinitionsBuilder(G_SET_FPMODE).customFor({s32});
168 getActionDefinitionsBuilder(G_RESET_FPMODE).custom();
169 } else {
170 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
171 .libcallFor({s32, s64});
172
173 LoadStoreBuilder.maxScalar(0, s32);
174
175 getActionDefinitionsBuilder(G_FNEG).lowerFor({s32, s64});
176
177 getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64});
178
180 {s32, s64});
181
182 if (AEABI(ST))
183 setFCmpLibcallsAEABI();
184 else
185 setFCmpLibcallsGNU();
186
187 getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s64, s32}});
188 getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s32, s64}});
189
190 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
191 .libcallForCartesianProduct({s32}, {s32, s64});
192 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
193 .libcallForCartesianProduct({s32, s64}, {s32});
194
195 getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_RESET_FPENV})
196 .libcall();
197 getActionDefinitionsBuilder({G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})
198 .libcall();
199 }
200
201 // Just expand whatever loads and stores are left.
202 LoadStoreBuilder.lower();
203
204 if (!ST.useSoftFloat() && ST.hasVFP4Base())
205 getActionDefinitionsBuilder(G_FMA).legalFor({s32, s64});
206 else
207 getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64});
208
209 getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64});
210
211 if (ST.hasV5TOps() && !ST.isThumb1Only()) {
213 .legalFor({s32, s32})
214 .clampScalar(1, s32, s32)
215 .clampScalar(0, s32, s32);
216 getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON)
217 .lowerFor({s32, s32})
218 .clampScalar(1, s32, s32)
219 .clampScalar(0, s32, s32);
220 } else {
221 getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON)
222 .libcallFor({s32, s32})
223 .clampScalar(1, s32, s32)
224 .clampScalar(0, s32, s32);
226 .lowerFor({s32, s32})
227 .clampScalar(1, s32, s32)
228 .clampScalar(0, s32, s32);
229 }
230
231 verify(*ST.getInstrInfo());
232}
233
234void ARMLegalizerInfo::setFCmpLibcallsAEABI() {
235 // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
236 // default-initialized.
237 FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
238 FCmp32Libcalls[CmpInst::FCMP_OEQ] = {
239 {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE}};
240 FCmp32Libcalls[CmpInst::FCMP_OGE] = {
241 {RTLIB::OGE_F32, CmpInst::BAD_ICMP_PREDICATE}};
242 FCmp32Libcalls[CmpInst::FCMP_OGT] = {
243 {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE}};
244 FCmp32Libcalls[CmpInst::FCMP_OLE] = {
245 {RTLIB::OLE_F32, CmpInst::BAD_ICMP_PREDICATE}};
246 FCmp32Libcalls[CmpInst::FCMP_OLT] = {
247 {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
248 FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
249 FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_EQ}};
250 FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_EQ}};
251 FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_EQ}};
252 FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_EQ}};
253 // AEABI only provides ordered-equal; not-equal is the same call, inverted.
254 FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}};
255 FCmp32Libcalls[CmpInst::FCMP_UNO] = {
256 {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
257 FCmp32Libcalls[CmpInst::FCMP_ONE] = {
258 {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE},
259 {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
260 FCmp32Libcalls[CmpInst::FCMP_UEQ] = {
261 {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE},
262 {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
263
264 FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
265 FCmp64Libcalls[CmpInst::FCMP_OEQ] = {
266 {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE}};
267 FCmp64Libcalls[CmpInst::FCMP_OGE] = {
268 {RTLIB::OGE_F64, CmpInst::BAD_ICMP_PREDICATE}};
269 FCmp64Libcalls[CmpInst::FCMP_OGT] = {
270 {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE}};
271 FCmp64Libcalls[CmpInst::FCMP_OLE] = {
272 {RTLIB::OLE_F64, CmpInst::BAD_ICMP_PREDICATE}};
273 FCmp64Libcalls[CmpInst::FCMP_OLT] = {
274 {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
275 FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
276 FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_EQ}};
277 FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_EQ}};
278 FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_EQ}};
279 FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_EQ}};
280 // AEABI only provides ordered-equal; not-equal is the same call, inverted.
281 FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}};
282 FCmp64Libcalls[CmpInst::FCMP_UNO] = {
283 {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
284 FCmp64Libcalls[CmpInst::FCMP_ONE] = {
285 {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE},
286 {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
287 FCmp64Libcalls[CmpInst::FCMP_UEQ] = {
288 {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE},
289 {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
290}
291
292void ARMLegalizerInfo::setFCmpLibcallsGNU() {
293 // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
294 // default-initialized.
295 FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
296 FCmp32Libcalls[CmpInst::FCMP_OEQ] = {
297 {RTLIB::FCMP3_PRED_OEQ_F32, CmpInst::ICMP_EQ}};
298 FCmp32Libcalls[CmpInst::FCMP_OGE] = {
299 {RTLIB::FCMP3_PRED_OGE_F32, CmpInst::ICMP_SGE}};
300 FCmp32Libcalls[CmpInst::FCMP_OGT] = {
301 {RTLIB::FCMP3_PRED_OGT_F32, CmpInst::ICMP_SGT}};
302 FCmp32Libcalls[CmpInst::FCMP_OLE] = {
303 {RTLIB::FCMP3_PRED_OLE_F32, CmpInst::ICMP_SLE}};
304 FCmp32Libcalls[CmpInst::FCMP_OLT] = {
305 {RTLIB::FCMP3_PRED_OLT_F32, CmpInst::ICMP_SLT}};
306 FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
307 FCmp32Libcalls[CmpInst::FCMP_UGE] = {
308 {RTLIB::FCMP3_PRED_OLT_F32, CmpInst::ICMP_SGE}};
309 FCmp32Libcalls[CmpInst::FCMP_UGT] = {
310 {RTLIB::FCMP3_PRED_OLE_F32, CmpInst::ICMP_SGT}};
311 FCmp32Libcalls[CmpInst::FCMP_ULE] = {
312 {RTLIB::FCMP3_PRED_OGT_F32, CmpInst::ICMP_SLE}};
313 FCmp32Libcalls[CmpInst::FCMP_ULT] = {
314 {RTLIB::FCMP3_PRED_OGE_F32, CmpInst::ICMP_SLT}};
315 FCmp32Libcalls[CmpInst::FCMP_UNE] = {
316 {RTLIB::FCMP3_PRED_UNE_F32, CmpInst::ICMP_NE}};
317 FCmp32Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F32, CmpInst::ICMP_NE}};
318 FCmp32Libcalls[CmpInst::FCMP_ONE] = {
319 {RTLIB::FCMP3_PRED_OGT_F32, CmpInst::ICMP_SGT},
320 {RTLIB::FCMP3_PRED_OLT_F32, CmpInst::ICMP_SLT}};
321 FCmp32Libcalls[CmpInst::FCMP_UEQ] = {
322 {RTLIB::FCMP3_PRED_OEQ_F32, CmpInst::ICMP_EQ},
323 {RTLIB::UO_F32, CmpInst::ICMP_NE}};
324
325 FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
326 FCmp64Libcalls[CmpInst::FCMP_OEQ] = {
327 {RTLIB::FCMP3_PRED_OEQ_F64, CmpInst::ICMP_EQ}};
328 FCmp64Libcalls[CmpInst::FCMP_OGE] = {
329 {RTLIB::FCMP3_PRED_OGE_F64, CmpInst::ICMP_SGE}};
330 FCmp64Libcalls[CmpInst::FCMP_OGT] = {
331 {RTLIB::FCMP3_PRED_OGT_F64, CmpInst::ICMP_SGT}};
332 FCmp64Libcalls[CmpInst::FCMP_OLE] = {
333 {RTLIB::FCMP3_PRED_OLE_F64, CmpInst::ICMP_SLE}};
334 FCmp64Libcalls[CmpInst::FCMP_OLT] = {
335 {RTLIB::FCMP3_PRED_OLT_F64, CmpInst::ICMP_SLT}};
336 FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
337 FCmp64Libcalls[CmpInst::FCMP_UGE] = {
338 {RTLIB::FCMP3_PRED_OLT_F64, CmpInst::ICMP_SGE}};
339 FCmp64Libcalls[CmpInst::FCMP_UGT] = {
340 {RTLIB::FCMP3_PRED_OLE_F64, CmpInst::ICMP_SGT}};
341 FCmp64Libcalls[CmpInst::FCMP_ULE] = {
342 {RTLIB::FCMP3_PRED_OGT_F64, CmpInst::ICMP_SLE}};
343 FCmp64Libcalls[CmpInst::FCMP_ULT] = {
344 {RTLIB::FCMP3_PRED_OGE_F64, CmpInst::ICMP_SLT}};
345 FCmp64Libcalls[CmpInst::FCMP_UNE] = {
346 {RTLIB::FCMP3_PRED_UNE_F64, CmpInst::ICMP_NE}};
347 FCmp64Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F64, CmpInst::ICMP_NE}};
348 FCmp64Libcalls[CmpInst::FCMP_ONE] = {
349 {RTLIB::FCMP3_PRED_OGT_F64, CmpInst::ICMP_SGT},
350 {RTLIB::FCMP3_PRED_OLT_F64, CmpInst::ICMP_SLT}};
351 FCmp64Libcalls[CmpInst::FCMP_UEQ] = {
352 {RTLIB::FCMP3_PRED_OEQ_F64, CmpInst::ICMP_EQ},
353 {RTLIB::UO_F64, CmpInst::ICMP_NE}};
354}
355
356ARMLegalizerInfo::FCmpLibcallsList
357ARMLegalizerInfo::getFCmpLibcalls(CmpInst::Predicate Predicate,
358 unsigned Size) const {
359 assert(CmpInst::isFPPredicate(Predicate) && "Unsupported FCmp predicate");
360 if (Size == 32)
361 return FCmp32Libcalls[Predicate];
362 if (Size == 64)
363 return FCmp64Libcalls[Predicate];
364 llvm_unreachable("Unsupported size for FCmp predicate");
365}
366
368 LostDebugLocObserver &LocObserver) const {
369 using namespace TargetOpcode;
370
371 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
372 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
373 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
374
375 switch (MI.getOpcode()) {
376 default:
377 return false;
378 case G_SREM:
379 case G_UREM: {
380 Register OriginalResult = MI.getOperand(0).getReg();
381 auto Size = MRI.getType(OriginalResult).getSizeInBits();
382 if (Size != 32)
383 return false;
384
385 auto Libcall =
386 MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
387
388 // Our divmod libcalls return a struct containing the quotient and the
389 // remainder. Create a new, unused register for the quotient and use the
390 // destination of the original instruction for the remainder.
391 Type *ArgTy = Type::getInt32Ty(Ctx);
392 StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);
394 OriginalResult};
395 auto Status = Helper.createLibcall(Libcall, {RetRegs, RetTy, 0},
396 {{MI.getOperand(1).getReg(), ArgTy, 0},
397 {MI.getOperand(2).getReg(), ArgTy, 0}},
398 LocObserver, &MI);
400 return false;
401 break;
402 }
403 case G_FCMP: {
404 assert(MRI.getType(MI.getOperand(2).getReg()) ==
405 MRI.getType(MI.getOperand(3).getReg()) &&
406 "Mismatched operands for G_FCMP");
407 auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
408
409 auto OriginalResult = MI.getOperand(0).getReg();
410 auto Predicate =
411 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
412 auto Libcalls = getFCmpLibcalls(Predicate, OpSize);
413
414 if (Libcalls.empty()) {
415 assert((Predicate == CmpInst::FCMP_TRUE ||
416 Predicate == CmpInst::FCMP_FALSE) &&
417 "Predicate needs libcalls, but none specified");
418 MIRBuilder.buildConstant(OriginalResult,
419 Predicate == CmpInst::FCMP_TRUE ? 1 : 0);
420 MI.eraseFromParent();
421 return true;
422 }
423
424 assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");
425 auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx);
426 auto *RetTy = Type::getInt32Ty(Ctx);
427
429 for (auto Libcall : Libcalls) {
430 auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));
431 auto Status =
432 Helper.createLibcall(Libcall.LibcallID, {LibcallResult, RetTy, 0},
433 {{MI.getOperand(2).getReg(), ArgTy, 0},
434 {MI.getOperand(3).getReg(), ArgTy, 0}},
435 LocObserver, &MI);
436
438 return false;
439
440 auto ProcessedResult =
441 Libcalls.size() == 1
442 ? OriginalResult
443 : MRI.createGenericVirtualRegister(MRI.getType(OriginalResult));
444
445 // We have a result, but we need to transform it into a proper 1-bit 0 or
446 // 1, taking into account the different peculiarities of the values
447 // returned by the comparison functions.
448 CmpInst::Predicate ResultPred = Libcall.Predicate;
449 if (ResultPred == CmpInst::BAD_ICMP_PREDICATE) {
450 // We have a nice 0 or 1, and we just need to truncate it back to 1 bit
451 // to keep the types consistent.
452 MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);
453 } else {
454 // We need to compare against 0.
455 assert(CmpInst::isIntPredicate(ResultPred) && "Unsupported predicate");
456 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
457 MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);
458 }
459 Results.push_back(ProcessedResult);
460 }
461
462 if (Results.size() != 1) {
463 assert(Results.size() == 2 && "Unexpected number of results");
464 MIRBuilder.buildOr(OriginalResult, Results[0], Results[1]);
465 }
466 break;
467 }
468 case G_CONSTANT: {
469 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
470 uint64_t ImmVal = ConstVal->getZExtValue();
471 if (ConstantMaterializationCost(ImmVal, &ST) > 2 && !ST.genExecuteOnly())
473 return true;
474 }
475 case G_FCONSTANT: {
476 // Convert to integer constants, while preserving the binary representation.
477 auto AsInteger =
478 MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();
479 MIRBuilder.buildConstant(MI.getOperand(0),
480 *ConstantInt::get(Ctx, AsInteger));
481 break;
482 }
483 case G_SET_FPMODE: {
484 // New FPSCR = (FPSCR & FPStatusBits) | (Modes & ~FPStatusBits)
485 LLT FPEnvTy = LLT::scalar(32);
486 auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);
487 Register Modes = MI.getOperand(0).getReg();
488 MIRBuilder.buildGetFPEnv(FPEnv);
489 auto StatusBitMask = MIRBuilder.buildConstant(FPEnvTy, ARM::FPStatusBits);
490 auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);
491 auto NotStatusBitMask =
492 MIRBuilder.buildConstant(FPEnvTy, ~ARM::FPStatusBits);
493 auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);
494 auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);
495 MIRBuilder.buildSetFPEnv(NewFPSCR);
496 break;
497 }
498 case G_RESET_FPMODE: {
499 // To get the default FP mode all control bits are cleared:
500 // FPSCR = FPSCR & (FPStatusBits | FPReservedBits)
501 LLT FPEnvTy = LLT::scalar(32);
502 auto FPEnv = MIRBuilder.buildGetFPEnv(FPEnvTy);
503 auto NotModeBitMask = MIRBuilder.buildConstant(
505 auto NewFPSCR = MIRBuilder.buildAnd(FPEnvTy, FPEnv, NotModeBitMask);
506 MIRBuilder.buildSetFPEnv(NewFPSCR);
507 break;
508 }
509 }
510
511 MI.eraseFromParent();
512 return true;
513}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file describes how to lower LLVM calls to machine code calls.
static bool AEABI(const ARMSubtarget &ST)
This file declares the targeting of the Machinelegalizer class for ARM.
Function Alias Analysis Results
IRTranslator LLVM IR MI
Implement a low-level type suitable for MachineInstr level instruction selection.
This file declares the MachineIRBuilder class.
ppc ctr loops verify
ARMLegalizerInfo(const ARMSubtarget &ST)
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
Definition InstrTypes.h:757
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:755
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:745
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:754
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:748
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:751
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:752
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:749
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:756
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:753
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
Definition InstrTypes.h:742
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
bool isFPPredicate() const
Definition InstrTypes.h:845
static bool isIntPredicate(Predicate P)
Definition InstrTypes.h:839
This is the shared class of boolean and integer constants.
Definition Constants.h:87
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:168
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
void resize(typename StorageT::size_type S)
Definition IndexedMap.h:67
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & libcallFor(std::initializer_list< LLT > Types)
LegalizeRuleSet & maxScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at most as wide as Ty.
LegalizeRuleSet & customForCartesianProduct(std::initializer_list< LLT > Types)
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & lowerFor(std::initializer_list< LLT > Types)
The instruction is lowered when type index 0 is any type in the given list.
LegalizeRuleSet & clampScalar(unsigned TypeIdx, const LLT MinTy, const LLT MaxTy)
Limit the range of scalar sizes to MinTy and MaxTy.
LegalizeRuleSet & custom()
Unconditionally custom lower.
LegalizeRuleSet & alwaysLegal()
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & legalForTypesWithMemDesc(std::initializer_list< LegalityPredicates::TypePairAndMemDesc > TypesAndMemDesc)
The instruction is legal when type indexes 0 and 1 along with the memory size and minimum alignment i...
LegalizeRuleSet & customFor(std::initializer_list< LLT > Types)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
LLVM_ABI LegalizeResult createLibcall(const char *Name, const CallLowering::ArgInfo &Result, ArrayRef< CallLowering::ArgInfo > Args, CallingConv::ID CC, LostDebugLocObserver &LocObserver, MachineInstr *MI=nullptr) const
Helper function that creates a libcall to the given Name using the given calling convention CC.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI LegalizeResult lowerConstant(MachineInstr &MI)
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
MachineInstrBuilder buildGetFPEnv(const DstOp &Dst)
Build and insert Dst = G_GET_FPENV.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildSetFPEnv(const SrcOp &Src)
Build and insert G_SET_FPENV Src.
Representation of each machine instruction.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Class to represent struct types.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:477
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:287
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:286
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
const unsigned FPStatusBits
const unsigned FPReservedBits
@ Libcall
The operation should be implemented as a call to some kind of runtime support library.
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
unsigned ConstantMaterializationCost(unsigned Val, const ARMSubtarget *Subtarget, bool ForCodesize=false)
Returns the number of instructions required to materialize the given constant in a register,...