LLVM: lib/Target/ARM/ARMLegalizerInfo.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
24
25using namespace llvm;
26using namespace LegalizeActions;
27
29 return ST.isTargetAEABI() || ST.isTargetGNUAEABI() || ST.isTargetMuslAEABI();
30}
31
33 using namespace TargetOpcode;
34
36
42
44 if (ST.isThumb1Only()) {
45
46 LegacyInfo.computeTables();
47 verify(*ST.getInstrInfo());
48 return;
49 }
50
52 .legalForCartesianProduct({s8, s16, s32}, {s1, s8, s16});
53
55
57 .legalFor({s32})
58 .clampScalar(0, s32, s32);
59
60 if (ST.hasNEON())
62 .legalFor({s32, s64})
63 .minScalar(0, s32);
64 else
66 .legalFor({s32})
67 .minScalar(0, s32);
68
70 .legalFor({{s32, s32}})
71 .minScalar(0, s32)
73
74 bool HasHWDivide = (!ST.isThumb() && ST.hasDivideInARMMode()) ||
75 (ST.isThumb() && ST.hasDivideInThumbMode());
76 if (HasHWDivide)
78 .legalFor({s32})
79 .clampScalar(0, s32, s32);
80 else
82 .libcallFor({s32})
83 .clampScalar(0, s32, s32);
84
85 auto &REMBuilder =
87 if (HasHWDivide)
88 REMBuilder.lowerFor({s32});
89 else if (AEABI(ST))
90 REMBuilder.customFor({s32});
91 else
92 REMBuilder.libcallFor({s32});
93
96 .minScalar(1, s32);
99 .minScalar(0, s32);
100
103 .clampScalar(0, s32, s32);
104
106
109 .minScalar(1, s32);
110
113 .minScalar(0, s32);
114
115
116
118 .legalForTypesWithMemDesc({{s8, p0, s8, 8},
119 {s16, p0, s16, 8},
120 {s32, p0, s32, 8},
121 {p0, p0, p0, 8}})
122 .unsupportedIfMemSizeNotPow2();
123
126
127 auto &PhiBuilder =
130 .minScalar(0, s32);
131
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
145 .maxScalar(0, s32);
147
149 {s32, s64});
150
153
156
158 .legalForCartesianProduct({s32}, {s32, s64});
160 .legalForCartesianProduct({s32, s64}, {s32});
161
163 .legalFor({s32});
167 } else {
169 .libcallFor({s32, s64});
170
171 LoadStoreBuilder.maxScalar(0, s32);
172
174
176
178 {s32, s64});
179
181 setFCmpLibcallsAEABI();
182 else
183 setFCmpLibcallsGNU();
184
187
189 .libcallForCartesianProduct({s32}, {s32, s64});
191 .libcallForCartesianProduct({s32, s64}, {s32});
192
197 }
198
199
200 LoadStoreBuilder.lower();
201
202 if (!ST.useSoftFloat() && ST.hasVFP4Base())
204 else
206
208
209 if (ST.hasV5TOps()) {
212 .clampScalar(1, s32, s32)
216 .clampScalar(1, s32, s32)
218 } else {
221 .clampScalar(1, s32, s32)
225 .clampScalar(1, s32, s32)
227 }
228
229 LegacyInfo.computeTables();
230 verify(*ST.getInstrInfo());
231}
232
233void ARMLegalizerInfo::setFCmpLibcallsAEABI() {
234
235
261
287}
288
289void ARMLegalizerInfo::setFCmpLibcallsGNU() {
290
291
309
327}
328
331 unsigned Size) const {
333 if (Size == 32)
334 return FCmp32Libcalls[Predicate];
335 if (Size == 64)
336 return FCmp64Libcalls[Predicate];
338}
339
342 using namespace TargetOpcode;
343
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
359 MI.getOpcode() == G_SREM ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32;
360
361
362
363
367 OriginalResult};
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 =
385 auto Libcalls = getFCmpLibcalls(Predicate, OpSize);
386
387 if (Libcalls.empty()) {
390 "Predicate needs libcalls, but none specified");
393 MI.eraseFromParent();
394 return true;
395 }
396
397 assert((OpSize == 32 || OpSize == 64) && "Unsupported operand size");
400
402 for (auto Libcall : Libcalls) {
403 auto LibcallResult = MRI.createGenericVirtualRegister(LLT::scalar(32));
405 {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
419
420
423
424
425 MIRBuilder.buildTrunc(ProcessedResult, LibcallResult);
426 } else {
427
430 MIRBuilder.buildICmp(ResultPred, ProcessedResult, LibcallResult, Zero);
431 }
432 Results.push_back(ProcessedResult);
433 }
434
438 }
439 break;
440 }
441 case G_CONSTANT: {
442 const ConstantInt *ConstVal = MI.getOperand(1).getCImm();
446 return true;
447 }
448 case G_FCONSTANT: {
449
450 auto AsInteger =
451 MI.getOperand(1).getFPImm()->getValueAPF().bitcastToAPInt();
453 *ConstantInt::get(Ctx, AsInteger));
454 break;
455 }
456 case G_SET_FPMODE: {
457
459 auto FPEnv = MRI.createGenericVirtualRegister(FPEnvTy);
460 Register Modes = MI.getOperand(0).getReg();
463 auto StatusBits = MIRBuilder.buildAnd(FPEnvTy, FPEnv, StatusBitMask);
464 auto NotStatusBitMask =
466 auto FPModeBits = MIRBuilder.buildAnd(FPEnvTy, Modes, NotStatusBitMask);
467 auto NewFPSCR = MIRBuilder.buildOr(FPEnvTy, StatusBits, FPModeBits);
469 break;
470 }
471 case G_RESET_FPMODE: {
472
473
478 auto NewFPSCR = MIRBuilder.buildAnd(FPEnvTy, FPEnv, NotModeBitMask);
480 break;
481 }
482 }
483
484 MI.eraseFromParent();
485 return true;
486}
unsigned const MachineRegisterInfo * MRI
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
Implement a low-level type suitable for MachineInstr level instruction selection.
This file declares the MachineIRBuilder class.
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ ICMP_SLT
signed less than
@ ICMP_SLE
signed less or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ ICMP_SGT
signed greater than
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
bool isFPPredicate() const
bool isIntPredicate() const
This is the shared class of boolean and integer constants.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
void resize(typename StorageT::size_type s)
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.
This is an important class for using LLVM in a threaded context.
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.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
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,...
Wrapper class representing virtual and physical registers.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Class to represent struct types.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
The instances of the Type class are immutable: once they are created, they are never changed.
static Type * getDoubleTy(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
static Type * getFloatTy(LLVMContext &C)
#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.
This is an optimization pass for GlobalISel generic memory operations.
LegalizerHelper::LegalizeResult createLibcall(MachineIRBuilder &MIRBuilder, const char *Name, const CallLowering::ArgInfo &Result, ArrayRef< CallLowering::ArgInfo > Args, CallingConv::ID CC, LostDebugLocObserver &LocObserver, MachineInstr *MI=nullptr)
Helper function that creates a libcall to the given Name using the given calling convention CC.
unsigned ConstantMaterializationCost(unsigned Val, const ARMSubtarget *Subtarget, bool ForCodesize=false)
Returns the number of instructions required to materialize the given constant in a register,...