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] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}};
297 FCmp32Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F32, CmpInst::ICMP_SGE}};
298 FCmp32Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT}};
299 FCmp32Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F32, CmpInst::ICMP_SLE}};
300 FCmp32Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
301 FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
302 FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_SGE}};
303 FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_SGT}};
304 FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SLE}};
305 FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_SLT}};
306 FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_NE}};
307 FCmp32Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F32, CmpInst::ICMP_NE}};
308 FCmp32Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT},
309 {RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
310 FCmp32Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ},
311 {RTLIB::UO_F32, CmpInst::ICMP_NE}};
312
313 FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
314 FCmp64Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}};
315 FCmp64Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F64, CmpInst::ICMP_SGE}};
316 FCmp64Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT}};
317 FCmp64Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F64, CmpInst::ICMP_SLE}};
318 FCmp64Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
319 FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
320 FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_SGE}};
321 FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_SGT}};
322 FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SLE}};
323 FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_SLT}};
324 FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_NE}};
325 FCmp64Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F64, CmpInst::ICMP_NE}};
326 FCmp64Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT},
327 {RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
328 FCmp64Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ},
329 {RTLIB::UO_F64, CmpInst::ICMP_NE}};
330}
331
332ARMLegalizerInfo::FCmpLibcallsList
333ARMLegalizerInfo::getFCmpLibcalls(CmpInst::Predicate Predicate,
334 unsigned Size) const {
335 assert(CmpInst::isFPPredicate(Predicate) && "Unsupported FCmp predicate");
336 if (Size == 32)
337 return FCmp32Libcalls[Predicate];
338 if (Size == 64)
339 return FCmp64Libcalls[Predicate];
340 llvm_unreachable("Unsupported size for FCmp predicate");
341}
342
344 LostDebugLocObserver &LocObserver) const {
345 using namespace TargetOpcode;
346
347 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
348 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
349 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
350
351 switch (MI.getOpcode()) {
352 default:
353 return false;
354 case G_SREM:
355 case G_UREM: {
356 Register OriginalResult = MI.getOperand(0).getReg();
357 auto Size = MRI.getType(OriginalResult).getSizeInBits();
358 if (Size != 32)
359 return false;
360
361 auto Libcall =
362 MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
363
364 // Our divmod libcalls return a struct containing the quotient and the
365 // remainder. Create a new, unused register for the quotient and use the
366 // destination of the original instruction for the remainder.
367 Type *ArgTy = Type::getInt32Ty(Ctx);
368 StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);
370 OriginalResult};
371 auto Status = Helper.createLibcall(Libcall, {RetRegs, RetTy, 0},
372 {{MI.getOperand(1).getReg(), ArgTy, 0},
373 {MI.getOperand(2).getReg(), ArgTy, 0}},
374 LocObserver, &MI);
376 return false;
377 break;
378 }
379 case G_FCMP: {
380 assert(MRI.getType(MI.getOperand(2).getReg()) ==
381 MRI.getType(MI.getOperand(3).getReg()) &&
382 "Mismatched operands for G_FCMP");
383 auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
384
385 auto OriginalResult = MI.getOperand(0).getReg();
386 auto Predicate =
387 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
388 auto Libcalls = getFCmpLibcalls(Predicate, OpSize);
389
390 if (Libcalls.empty()) {
391 assert((Predicate == CmpInst::FCMP_TRUE ||
392 Predicate == CmpInst::FCMP_FALSE) &&
393 "Predicate needs libcalls, but none specified");
394 MIRBuilder.buildConstant(OriginalResult,
395 Predicate == CmpInst::FCMP_TRUE ? 1 : 0);
396 MI.eraseFromParent();
397 return true;
398 }
399
400 assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");
401 auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx);
402 auto *RetTy = Type::getInt32Ty(Ctx);
403
405 for (auto Libcall : Libcalls) {
406 auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));
407 auto Status =
408 Helper.createLibcall(Libcall.LibcallID, {LibcallResult, RetTy, 0},
409 {{MI.getOperand(2).getReg(), ArgTy, 0},
410 {MI.getOperand(3).getReg(), ArgTy, 0}},
411 LocObserver, &MI);
412
414 return false;
415
416 auto ProcessedResult =
417 Libcalls.size() == 1
418 ? OriginalResult
419 : MRI.createGenericVirtualRegister(MRI.getType(OriginalResult));
420
421 // We have a result, but we need to transform it into a proper 1-bit 0 or
422 // 1, taking into account the different peculiarities of the values
423 // returned by the comparison functions.
424 CmpInst::Predicate ResultPred = Libcall.Predicate;
425 if (ResultPred == CmpInst::BAD_ICMP_PREDICATE) {
426 // We have a nice 0 or 1, and we just need to truncate it back to 1 bit
427 // to keep the types consistent.
428 MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);
429 } else {
430 // We need to compare against 0.
431 assert(CmpInst::isIntPredicate(ResultPred) && "Unsupported predicate");
432 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
433 MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);
434 }
435 Results.push_back(ProcessedResult);
436 }
437
438 if (Results.size() != 1) {
439 assert(Results.size() == 2 && "Unexpected number of results");
440 MIRBuilder.buildOr(OriginalResult, Results[0], Results[1]);
441 }
442 break;
443 }
444 case G_CONSTANT: {
445 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
446 uint64_t ImmVal = ConstVal->getZExtValue();
447 if (ConstantMaterializationCost(ImmVal, &ST) > 2 && !ST.genExecuteOnly())
449 return true;
450 }
451 case G_FCONSTANT: {
452 // Convert to integer constants, while preserving the binary representation.
453 auto AsInteger =
454 MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();
455 MIRBuilder.buildConstant(MI.getOperand(0),
456 *ConstantInt::get(Ctx, AsInteger));
457 break;
458 }
459 case G_SET_FPMODE: {
460 // New FPSCR = (FPSCR & FPStatusBits) | (Modes & ~FPStatusBits)
461 LLT FPEnvTy = LLT::scalar(32);
462 auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);
463 Register Modes = MI.getOperand(0).getReg();
464 MIRBuilder.buildGetFPEnv(FPEnv);
465 auto StatusBitMask = MIRBuilder.buildConstant(FPEnvTy, ARM::FPStatusBits);
466 auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);
467 auto NotStatusBitMask =
468 MIRBuilder.buildConstant(FPEnvTy, ~ARM::FPStatusBits);
469 auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);
470 auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);
471 MIRBuilder.buildSetFPEnv(NewFPSCR);
472 break;
473 }
474 case G_RESET_FPMODE: {
475 // To get the default FP mode all control bits are cleared:
476 // FPSCR = FPSCR & (FPStatusBits | FPReservedBits)
477 LLT FPEnvTy = LLT::scalar(32);
478 auto FPEnv = MIRBuilder.buildGetFPEnv(FPEnvTy);
479 auto NotModeBitMask = MIRBuilder.buildConstant(
481 auto NewFPSCR = MIRBuilder.buildAnd(FPEnvTy, FPEnv, NotModeBitMask);
482 MIRBuilder.buildSetFPEnv(NewFPSCR);
483 break;
484 }
485 }
486
487 MI.eraseFromParent();
488 return true;
489}
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,...