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