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