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 auto &LegacyInfo = getLegacyLegalizerInfo();
44 if (ST.isThumb1Only()) {
45 // Thumb1 is not supported yet.
46 LegacyInfo.computeTables();
47 verify(*ST.getInstrInfo());
48 return;
49 }
50
51 getActionDefinitionsBuilder({G_SEXT, G_ZEXT, G_ANYEXT})
52 .legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16});
53
55 {s8, s16, s32});
56
57 getActionDefinitionsBuilder(G_SEXT_INREG).lower();
58
59 getActionDefinitionsBuilder({G_MUL, G_AND, G_OR, G_XOR})
60 .legalFor({s32})
61 .clampScalar(0, s32, s32);
62
63 if (ST.hasNEON())
64 getActionDefinitionsBuilder({G_ADD, G_SUB})
65 .legalFor({s32, s64})
66 .minScalar(0, s32);
67 else
68 getActionDefinitionsBuilder({G_ADD, G_SUB})
69 .legalFor({s32})
70 .minScalar(0, s32);
71
72 getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL})
73 .legalFor({{s32, s32}})
74 .minScalar(0, s32)
75 .clampScalar(1, s32, s32);
76
77 bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) ||
78 (ST.isThumb() && ST.hasDivideInThumbMode());
79 if (HasHWDivide)
80 getActionDefinitionsBuilder({G_SDIV, G_UDIV})
81 .legalFor({s32})
82 .clampScalar(0, s32, s32);
83 else
84 getActionDefinitionsBuilder({G_SDIV, G_UDIV})
85 .libcallFor({s32})
86 .clampScalar(0, s32, s32);
87
88 auto &REMBuilder =
89 getActionDefinitionsBuilder({G_SREM, G_UREM}).minScalar(0, s32);
90 if (HasHWDivide)
91 REMBuilder.lowerFor({s32});
92 else if (AEABI(ST))
93 REMBuilder.customFor({s32});
94 else
95 REMBuilder.libcallFor({s32});
96
98 .legalFor({{p0, s32}})
99 .minScalar(1, s32);
101 .legalFor({{s32, p0}})
102 .minScalar(0, s32);
103
105 .customFor({s32, p0})
106 .clampScalar(0, s32, s32);
107
108 getActionDefinitionsBuilder(G_CONSTANT_POOL).legalFor({p0});
109
111 .legalForCartesianProduct({s1}, {s32, p0})
112 .minScalar(1, s32);
113
115 .legalForCartesianProduct({s32, p0}, {s1})
116 .minScalar(0, s32);
117
118 // We're keeping these builders around because we'll want to add support for
119 // floating point to them.
120 auto &LoadStoreBuilder = getActionDefinitionsBuilder({G_LOAD, G_STORE})
121 .legalForTypesWithMemDesc({{s8, p0, s8, 8},
122 {s16, p0, s16, 8},
123 {s32, p0, s32, 8},
124 {p0, p0, p0, 8}})
125 .unsupportedIfMemSizeNotPow2();
126
127 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
128 getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});
129
130 auto &PhiBuilder =
132 .legalFor({s32, p0})
133 .minScalar(0, s32);
134
136 .legalFor({{p0, s32}})
137 .minScalar(1, s32);
138
141
142 if (!ST.useSoftFloat() && ST.hasVFP2Base()) {
144 {G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FCONSTANT, G_FNEG})
145 .legalFor({s32, s64});
146
147 LoadStoreBuilder
148 .legalForTypesWithMemDesc({{s64, p0, s64, 32}})
149 .maxScalar(0, s32);
150 PhiBuilder.legalFor({s64});
151
153 {s32, s64});
154
155 getActionDefinitionsBuilder(G_MERGE_VALUES).legalFor({{s64, s32}});
156 getActionDefinitionsBuilder(G_UNMERGE_VALUES).legalFor({{s32, s64}});
157
158 getActionDefinitionsBuilder(G_FPEXT).legalFor({{s64, s32}});
159 getActionDefinitionsBuilder(G_FPTRUNC).legalFor({{s32, s64}});
160
161 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
162 .legalForCartesianProduct({s32}, {s32, s64});
163 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
164 .legalForCartesianProduct({s32, s64}, {s32});
165
166 getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_GET_FPMODE})
167 .legalFor({s32});
169 getActionDefinitionsBuilder(G_SET_FPMODE).customFor({s32});
170 getActionDefinitionsBuilder(G_RESET_FPMODE).custom();
171 } else {
172 getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV})
173 .libcallFor({s32, s64});
174
175 LoadStoreBuilder.maxScalar(0, s32);
176
177 getActionDefinitionsBuilder(G_FNEG).lowerFor({s32, s64});
178
179 getActionDefinitionsBuilder(G_FCONSTANT).customFor({s32, s64});
180
182 {s32, s64});
183
184 if (AEABI(ST))
185 setFCmpLibcallsAEABI();
186 else
187 setFCmpLibcallsGNU();
188
189 getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s64, s32}});
190 getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s32, s64}});
191
192 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
193 .libcallForCartesianProduct({s32}, {s32, s64});
194 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
195 .libcallForCartesianProduct({s32, s64}, {s32});
196
197 getActionDefinitionsBuilder({G_GET_FPENV, G_SET_FPENV, G_RESET_FPENV})
198 .libcall();
199 getActionDefinitionsBuilder({G_GET_FPMODE, G_SET_FPMODE, G_RESET_FPMODE})
200 .libcall();
201 }
202
203 // Just expand whatever loads and stores are left.
204 LoadStoreBuilder.lower();
205
206 if (!ST.useSoftFloat() && ST.hasVFP4Base())
207 getActionDefinitionsBuilder(G_FMA).legalFor({s32, s64});
208 else
209 getActionDefinitionsBuilder(G_FMA).libcallFor({s32, s64});
210
211 getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64});
212
213 if (ST.hasV5TOps() && !ST.isThumb1Only()) {
215 .legalFor({s32, s32})
216 .clampScalar(1, s32, s32)
217 .clampScalar(0, s32, s32);
218 getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON)
219 .lowerFor({s32, s32})
220 .clampScalar(1, s32, s32)
221 .clampScalar(0, s32, s32);
222 } else {
223 getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON)
224 .libcallFor({s32, s32})
225 .clampScalar(1, s32, s32)
226 .clampScalar(0, s32, s32);
228 .lowerFor({s32, s32})
229 .clampScalar(1, s32, s32)
230 .clampScalar(0, s32, s32);
231 }
232
233 LegacyInfo.computeTables();
234 verify(*ST.getInstrInfo());
235}
236
237void ARMLegalizerInfo::setFCmpLibcallsAEABI() {
238 // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
239 // default-initialized.
240 FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
241 FCmp32Libcalls[CmpInst::FCMP_OEQ] = {
242 {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE}};
243 FCmp32Libcalls[CmpInst::FCMP_OGE] = {
244 {RTLIB::OGE_F32, CmpInst::BAD_ICMP_PREDICATE}};
245 FCmp32Libcalls[CmpInst::FCMP_OGT] = {
246 {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE}};
247 FCmp32Libcalls[CmpInst::FCMP_OLE] = {
248 {RTLIB::OLE_F32, CmpInst::BAD_ICMP_PREDICATE}};
249 FCmp32Libcalls[CmpInst::FCMP_OLT] = {
250 {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
251 FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
252 FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_EQ}};
253 FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_EQ}};
254 FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_EQ}};
255 FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_EQ}};
256 FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_EQ}};
257 FCmp32Libcalls[CmpInst::FCMP_UNO] = {
258 {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
259 FCmp32Libcalls[CmpInst::FCMP_ONE] = {
260 {RTLIB::OGT_F32, CmpInst::BAD_ICMP_PREDICATE},
261 {RTLIB::OLT_F32, CmpInst::BAD_ICMP_PREDICATE}};
262 FCmp32Libcalls[CmpInst::FCMP_UEQ] = {
263 {RTLIB::OEQ_F32, CmpInst::BAD_ICMP_PREDICATE},
264 {RTLIB::UO_F32, CmpInst::BAD_ICMP_PREDICATE}};
265
266 FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
267 FCmp64Libcalls[CmpInst::FCMP_OEQ] = {
268 {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE}};
269 FCmp64Libcalls[CmpInst::FCMP_OGE] = {
270 {RTLIB::OGE_F64, CmpInst::BAD_ICMP_PREDICATE}};
271 FCmp64Libcalls[CmpInst::FCMP_OGT] = {
272 {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE}};
273 FCmp64Libcalls[CmpInst::FCMP_OLE] = {
274 {RTLIB::OLE_F64, CmpInst::BAD_ICMP_PREDICATE}};
275 FCmp64Libcalls[CmpInst::FCMP_OLT] = {
276 {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
277 FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
278 FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_EQ}};
279 FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_EQ}};
280 FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_EQ}};
281 FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_EQ}};
282 FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_EQ}};
283 FCmp64Libcalls[CmpInst::FCMP_UNO] = {
284 {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
285 FCmp64Libcalls[CmpInst::FCMP_ONE] = {
286 {RTLIB::OGT_F64, CmpInst::BAD_ICMP_PREDICATE},
287 {RTLIB::OLT_F64, CmpInst::BAD_ICMP_PREDICATE}};
288 FCmp64Libcalls[CmpInst::FCMP_UEQ] = {
289 {RTLIB::OEQ_F64, CmpInst::BAD_ICMP_PREDICATE},
290 {RTLIB::UO_F64, CmpInst::BAD_ICMP_PREDICATE}};
291}
292
293void ARMLegalizerInfo::setFCmpLibcallsGNU() {
294 // FCMP_TRUE and FCMP_FALSE don't need libcalls, they should be
295 // default-initialized.
296 FCmp32Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
297 FCmp32Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ}};
298 FCmp32Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F32, CmpInst::ICMP_SGE}};
299 FCmp32Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT}};
300 FCmp32Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F32, CmpInst::ICMP_SLE}};
301 FCmp32Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
302 FCmp32Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F32, CmpInst::ICMP_EQ}};
303 FCmp32Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F32, CmpInst::ICMP_SGE}};
304 FCmp32Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F32, CmpInst::ICMP_SGT}};
305 FCmp32Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SLE}};
306 FCmp32Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F32, CmpInst::ICMP_SLT}};
307 FCmp32Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F32, CmpInst::ICMP_NE}};
308 FCmp32Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F32, CmpInst::ICMP_NE}};
309 FCmp32Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F32, CmpInst::ICMP_SGT},
310 {RTLIB::OLT_F32, CmpInst::ICMP_SLT}};
311 FCmp32Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F32, CmpInst::ICMP_EQ},
312 {RTLIB::UO_F32, CmpInst::ICMP_NE}};
313
314 FCmp64Libcalls.resize(CmpInst::LAST_FCMP_PREDICATE + 1);
315 FCmp64Libcalls[CmpInst::FCMP_OEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ}};
316 FCmp64Libcalls[CmpInst::FCMP_OGE] = {{RTLIB::OGE_F64, CmpInst::ICMP_SGE}};
317 FCmp64Libcalls[CmpInst::FCMP_OGT] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT}};
318 FCmp64Libcalls[CmpInst::FCMP_OLE] = {{RTLIB::OLE_F64, CmpInst::ICMP_SLE}};
319 FCmp64Libcalls[CmpInst::FCMP_OLT] = {{RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
320 FCmp64Libcalls[CmpInst::FCMP_ORD] = {{RTLIB::UO_F64, CmpInst::ICMP_EQ}};
321 FCmp64Libcalls[CmpInst::FCMP_UGE] = {{RTLIB::OLT_F64, CmpInst::ICMP_SGE}};
322 FCmp64Libcalls[CmpInst::FCMP_UGT] = {{RTLIB::OLE_F64, CmpInst::ICMP_SGT}};
323 FCmp64Libcalls[CmpInst::FCMP_ULE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SLE}};
324 FCmp64Libcalls[CmpInst::FCMP_ULT] = {{RTLIB::OGE_F64, CmpInst::ICMP_SLT}};
325 FCmp64Libcalls[CmpInst::FCMP_UNE] = {{RTLIB::UNE_F64, CmpInst::ICMP_NE}};
326 FCmp64Libcalls[CmpInst::FCMP_UNO] = {{RTLIB::UO_F64, CmpInst::ICMP_NE}};
327 FCmp64Libcalls[CmpInst::FCMP_ONE] = {{RTLIB::OGT_F64, CmpInst::ICMP_SGT},
328 {RTLIB::OLT_F64, CmpInst::ICMP_SLT}};
329 FCmp64Libcalls[CmpInst::FCMP_UEQ] = {{RTLIB::OEQ_F64, CmpInst::ICMP_EQ},
330 {RTLIB::UO_F64, CmpInst::ICMP_NE}};
331}
332
333ARMLegalizerInfo::FCmpLibcallsList
334ARMLegalizerInfo::getFCmpLibcalls(CmpInst::Predicate Predicate,
335 unsigned Size) const {
336 assert(CmpInst::isFPPredicate(Predicate) && "Unsupported FCmp predicate");
337 if (Size == 32)
338 return FCmp32Libcalls[Predicate];
339 if (Size == 64)
340 return FCmp64Libcalls[Predicate];
341 llvm_unreachable("Unsupported size for FCmp predicate");
342}
343
345 LostDebugLocObserver &LocObserver) const {
346 using namespace TargetOpcode;
347
348 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
349 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
350 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
351
352 switch (MI.getOpcode()) {
353 default:
354 return false;
355 case G_SREM:
356 case G_UREM: {
357 Register OriginalResult = MI.getOperand(0).getReg();
358 auto Size = MRI.getType(OriginalResult).getSizeInBits();
359 if (Size != 32)
360 return false;
361
362 auto Libcall =
363 MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
364
365 // Our divmod libcalls return a struct containing the quotient and the
366 // remainder. Create a new, unused register for the quotient and use the
367 // destination of the original instruction for the remainder.
368 Type *ArgTy = Type::getInt32Ty(Ctx);
369 StructType *RetTy = StructType::get(Ctx, {ArgTy, ArgTy}, /* Packed */ true);
371 OriginalResult};
372 auto Status = Helper.createLibcall(Libcall, {RetRegs, RetTy, 0},
373 {{MI.getOperand(1).getReg(), ArgTy, 0},
374 {MI.getOperand(2).getReg(), ArgTy, 0}},
375 LocObserver, &MI);
377 return false;
378 break;
379 }
380 case G_FCMP: {
381 assert(MRI.getType(MI.getOperand(2).getReg()) ==
382 MRI.getType(MI.getOperand(3).getReg()) &&
383 "Mismatched operands for G_FCMP");
384 auto OpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits();
385
386 auto OriginalResult = MI.getOperand(0).getReg();
387 auto Predicate =
388 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
389 auto Libcalls = getFCmpLibcalls(Predicate, OpSize);
390
391 if (Libcalls.empty()) {
392 assert((Predicate == CmpInst::FCMP_TRUE ||
393 Predicate == CmpInst::FCMP_FALSE) &&
394 "Predicate needs libcalls, but none specified");
395 MIRBuilder.buildConstant(OriginalResult,
396 Predicate == CmpInst::FCMP_TRUE ? 1 : 0);
397 MI.eraseFromParent();
398 return true;
399 }
400
401 assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");
402 auto *ArgTy = OpSize == 32 ? Type::getFloatTy(Ctx) : Type::getDoubleTy(Ctx);
403 auto *RetTy = Type::getInt32Ty(Ctx);
404
406 for (auto Libcall : Libcalls) {
407 auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));
408 auto Status =
409 Helper.createLibcall(Libcall.LibcallID, {LibcallResult, RetTy, 0},
410 {{MI.getOperand(2).getReg(), ArgTy, 0},
411 {MI.getOperand(3).getReg(), ArgTy, 0}},
412 LocObserver, &MI);
413
415 return false;
416
417 auto ProcessedResult =
418 Libcalls.size() == 1
419 ? OriginalResult
420 : MRI.createGenericVirtualRegister(MRI.getType(OriginalResult));
421
422 // We have a result, but we need to transform it into a proper 1-bit 0 or
423 // 1, taking into account the different peculiarities of the values
424 // returned by the comparison functions.
425 CmpInst::Predicate ResultPred = Libcall.Predicate;
426 if (ResultPred == CmpInst::BAD_ICMP_PREDICATE) {
427 // We have a nice 0 or 1, and we just need to truncate it back to 1 bit
428 // to keep the types consistent.
429 MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);
430 } else {
431 // We need to compare against 0.
432 assert(CmpInst::isIntPredicate(ResultPred) && "Unsupported predicate");
433 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
434 MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);
435 }
436 Results.push_back(ProcessedResult);
437 }
438
439 if (Results.size() != 1) {
440 assert(Results.size() == 2 && "Unexpected number of results");
441 MIRBuilder.buildOr(OriginalResult, Results[0], Results[1]);
442 }
443 break;
444 }
445 case G_CONSTANT: {
446 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
447 uint64_t ImmVal = ConstVal->getZExtValue();
448 if (ConstantMaterializationCost(ImmVal, &ST) > 2 && !ST.genExecuteOnly())
450 return true;
451 }
452 case G_FCONSTANT: {
453 // Convert to integer constants, while preserving the binary representation.
454 auto AsInteger =
455 MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();
456 MIRBuilder.buildConstant(MI.getOperand(0),
457 *ConstantInt::get(Ctx, AsInteger));
458 break;
459 }
460 case G_SET_FPMODE: {
461 // New FPSCR = (FPSCR & FPStatusBits) | (Modes & ~FPStatusBits)
462 LLT FPEnvTy = LLT::scalar(32);
463 auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);
464 Register Modes = MI.getOperand(0).getReg();
465 MIRBuilder.buildGetFPEnv(FPEnv);
466 auto StatusBitMask = MIRBuilder.buildConstant(FPEnvTy, ARM::FPStatusBits);
467 auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);
468 auto NotStatusBitMask =
469 MIRBuilder.buildConstant(FPEnvTy, ~ARM::FPStatusBits);
470 auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);
471 auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);
472 MIRBuilder.buildSetFPEnv(NewFPSCR);
473 break;
474 }
475 case G_RESET_FPMODE: {
476 // To get the default FP mode all control bits are cleared:
477 // FPSCR = FPSCR & (FPStatusBits | FPReservedBits)
478 LLT FPEnvTy = LLT::scalar(32);
479 auto FPEnv = MIRBuilder.buildGetFPEnv(FPEnvTy);
480 auto NotModeBitMask = MIRBuilder.buildConstant(
482 auto NewFPSCR = MIRBuilder.buildAnd(FPEnvTy, FPEnv, NotModeBitMask);
483 MIRBuilder.buildSetFPEnv(NewFPSCR);
484 break;
485 }
486 }
487
488 MI.eraseFromParent();
489 return true;
490}
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:676
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:679
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
Definition InstrTypes.h:693
@ ICMP_SLT
signed less than
Definition InstrTypes.h:705
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:706
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:682
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:691
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:680
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:681
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:703
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:690
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:684
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:687
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:688
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:683
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:685
@ ICMP_NE
not equal
Definition InstrTypes.h:698
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:704
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:692
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:689
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
Definition InstrTypes.h:678
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:686
bool isFPPredicate() const
Definition InstrTypes.h:782
static bool isIntPredicate(Predicate P)
Definition InstrTypes.h:776
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:358
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.
const LegacyLegalizerInfo & getLegacyLegalizerInfo() const
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:483
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:313
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:291
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:290
#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,...