1 | //===-- ARMBaseInstrInfo.h - ARM Base Instruction Information ---*- 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 | // |
9 | // This file contains the Base ARM implementation of the TargetInstrInfo class. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_LIB_TARGET_ARM_ARMBASEINSTRINFO_H |
14 | #define LLVM_LIB_TARGET_ARM_ARMBASEINSTRINFO_H |
15 | |
16 | #include "ARMBaseRegisterInfo.h" |
17 | #include "MCTargetDesc/ARMBaseInfo.h" |
18 | #include "MCTargetDesc/ARMMCTargetDesc.h" |
19 | #include "llvm/ADT/DenseMap.h" |
20 | #include "llvm/ADT/SmallSet.h" |
21 | #include "llvm/CodeGen/MachineBasicBlock.h" |
22 | #include "llvm/CodeGen/MachineInstr.h" |
23 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
24 | #include "llvm/CodeGen/MachineOperand.h" |
25 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
26 | #include "llvm/CodeGen/Register.h" |
27 | #include "llvm/CodeGen/TargetInstrInfo.h" |
28 | #include "llvm/IR/IntrinsicInst.h" |
29 | #include "llvm/IR/IntrinsicsARM.h" |
30 | #include "llvm/Support/ErrorHandling.h" |
31 | #include <array> |
32 | #include <cstdint> |
33 | |
34 | #define |
35 | #include "ARMGenInstrInfo.inc" |
36 | |
37 | namespace llvm { |
38 | |
39 | class ARMBaseRegisterInfo; |
40 | class ARMSubtarget; |
41 | |
42 | class ARMBaseInstrInfo : public ARMGenInstrInfo { |
43 | const ARMSubtarget &Subtarget; |
44 | |
45 | protected: |
46 | // Can be only subclassed. |
47 | explicit ARMBaseInstrInfo(const ARMSubtarget &STI); |
48 | |
49 | void expandLoadStackGuardBase(MachineBasicBlock::iterator MI, |
50 | unsigned LoadImmOpc, unsigned LoadOpc) const; |
51 | |
52 | /// Build the equivalent inputs of a REG_SEQUENCE for the given \p MI |
53 | /// and \p DefIdx. |
54 | /// \p [out] InputRegs of the equivalent REG_SEQUENCE. Each element of |
55 | /// the list is modeled as <Reg:SubReg, SubIdx>. |
56 | /// E.g., REG_SEQUENCE %1:sub1, sub0, %2, sub1 would produce |
57 | /// two elements: |
58 | /// - %1:sub1, sub0 |
59 | /// - %2<:0>, sub1 |
60 | /// |
61 | /// \returns true if it is possible to build such an input sequence |
62 | /// with the pair \p MI, \p DefIdx. False otherwise. |
63 | /// |
64 | /// \pre MI.isRegSequenceLike(). |
65 | bool getRegSequenceLikeInputs( |
66 | const MachineInstr &MI, unsigned DefIdx, |
67 | SmallVectorImpl<RegSubRegPairAndIdx> &InputRegs) const override; |
68 | |
69 | /// Build the equivalent inputs of a EXTRACT_SUBREG for the given \p MI |
70 | /// and \p DefIdx. |
71 | /// \p [out] InputReg of the equivalent EXTRACT_SUBREG. |
72 | /// E.g., EXTRACT_SUBREG %1:sub1, sub0, sub1 would produce: |
73 | /// - %1:sub1, sub0 |
74 | /// |
75 | /// \returns true if it is possible to build such an input sequence |
76 | /// with the pair \p MI, \p DefIdx. False otherwise. |
77 | /// |
78 | /// \pre MI.isExtractSubregLike(). |
79 | bool getExtractSubregLikeInputs(const MachineInstr &MI, unsigned DefIdx, |
80 | RegSubRegPairAndIdx &InputReg) const override; |
81 | |
82 | /// Build the equivalent inputs of a INSERT_SUBREG for the given \p MI |
83 | /// and \p DefIdx. |
84 | /// \p [out] BaseReg and \p [out] InsertedReg contain |
85 | /// the equivalent inputs of INSERT_SUBREG. |
86 | /// E.g., INSERT_SUBREG %0:sub0, %1:sub1, sub3 would produce: |
87 | /// - BaseReg: %0:sub0 |
88 | /// - InsertedReg: %1:sub1, sub3 |
89 | /// |
90 | /// \returns true if it is possible to build such an input sequence |
91 | /// with the pair \p MI, \p DefIdx. False otherwise. |
92 | /// |
93 | /// \pre MI.isInsertSubregLike(). |
94 | bool |
95 | getInsertSubregLikeInputs(const MachineInstr &MI, unsigned DefIdx, |
96 | RegSubRegPair &BaseReg, |
97 | RegSubRegPairAndIdx &InsertedReg) const override; |
98 | |
99 | /// Commutes the operands in the given instruction. |
100 | /// The commutable operands are specified by their indices OpIdx1 and OpIdx2. |
101 | /// |
102 | /// Do not call this method for a non-commutable instruction or for |
103 | /// non-commutable pair of operand indices OpIdx1 and OpIdx2. |
104 | /// Even though the instruction is commutable, the method may still |
105 | /// fail to commute the operands, null pointer is returned in such cases. |
106 | MachineInstr *commuteInstructionImpl(MachineInstr &MI, bool NewMI, |
107 | unsigned OpIdx1, |
108 | unsigned OpIdx2) const override; |
109 | /// If the specific machine instruction is an instruction that moves/copies |
110 | /// value from one register to another register return destination and source |
111 | /// registers as machine operands. |
112 | std::optional<DestSourcePair> |
113 | isCopyInstrImpl(const MachineInstr &MI) const override; |
114 | |
115 | /// Specialization of \ref TargetInstrInfo::describeLoadedValue, used to |
116 | /// enhance debug entry value descriptions for ARM targets. |
117 | std::optional<ParamLoadedValue> |
118 | describeLoadedValue(const MachineInstr &MI, Register Reg) const override; |
119 | |
120 | public: |
121 | // Return whether the target has an explicit NOP encoding. |
122 | bool hasNOP() const; |
123 | |
124 | // Return the non-pre/post incrementing version of 'Opc'. Return 0 |
125 | // if there is not such an opcode. |
126 | virtual unsigned getUnindexedOpcode(unsigned Opc) const = 0; |
127 | |
128 | MachineInstr *convertToThreeAddress(MachineInstr &MI, LiveVariables *LV, |
129 | LiveIntervals *LIS) const override; |
130 | |
131 | virtual const ARMBaseRegisterInfo &getRegisterInfo() const = 0; |
132 | const ARMSubtarget &getSubtarget() const { return Subtarget; } |
133 | |
134 | ScheduleHazardRecognizer * |
135 | CreateTargetHazardRecognizer(const TargetSubtargetInfo *STI, |
136 | const ScheduleDAG *DAG) const override; |
137 | |
138 | ScheduleHazardRecognizer * |
139 | CreateTargetMIHazardRecognizer(const InstrItineraryData *II, |
140 | const ScheduleDAGMI *DAG) const override; |
141 | |
142 | ScheduleHazardRecognizer * |
143 | CreateTargetPostRAHazardRecognizer(const InstrItineraryData *II, |
144 | const ScheduleDAG *DAG) const override; |
145 | |
146 | // Branch analysis. |
147 | bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, |
148 | MachineBasicBlock *&FBB, |
149 | SmallVectorImpl<MachineOperand> &Cond, |
150 | bool AllowModify = false) const override; |
151 | unsigned removeBranch(MachineBasicBlock &MBB, |
152 | int *BytesRemoved = nullptr) const override; |
153 | unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, |
154 | MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond, |
155 | const DebugLoc &DL, |
156 | int *BytesAdded = nullptr) const override; |
157 | |
158 | bool |
159 | reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override; |
160 | |
161 | // Predication support. |
162 | bool isPredicated(const MachineInstr &MI) const override; |
163 | |
164 | // MIR printer helper function to annotate Operands with a comment. |
165 | std::string |
166 | createMIROperandComment(const MachineInstr &MI, const MachineOperand &Op, |
167 | unsigned OpIdx, |
168 | const TargetRegisterInfo *TRI) const override; |
169 | |
170 | ARMCC::CondCodes getPredicate(const MachineInstr &MI) const { |
171 | int PIdx = MI.findFirstPredOperandIdx(); |
172 | return PIdx != -1 ? (ARMCC::CondCodes)MI.getOperand(i: PIdx).getImm() |
173 | : ARMCC::AL; |
174 | } |
175 | |
176 | bool PredicateInstruction(MachineInstr &MI, |
177 | ArrayRef<MachineOperand> Pred) const override; |
178 | |
179 | bool SubsumesPredicate(ArrayRef<MachineOperand> Pred1, |
180 | ArrayRef<MachineOperand> Pred2) const override; |
181 | |
182 | bool ClobbersPredicate(MachineInstr &MI, std::vector<MachineOperand> &Pred, |
183 | bool SkipDead) const override; |
184 | |
185 | bool isPredicable(const MachineInstr &MI) const override; |
186 | |
187 | // CPSR defined in instruction |
188 | static bool isCPSRDefined(const MachineInstr &MI); |
189 | |
190 | /// GetInstSize - Returns the size of the specified MachineInstr. |
191 | /// |
192 | unsigned getInstSizeInBytes(const MachineInstr &MI) const override; |
193 | |
194 | Register isLoadFromStackSlot(const MachineInstr &MI, |
195 | int &FrameIndex) const override; |
196 | Register isStoreToStackSlot(const MachineInstr &MI, |
197 | int &FrameIndex) const override; |
198 | Register isLoadFromStackSlotPostFE(const MachineInstr &MI, |
199 | int &FrameIndex) const override; |
200 | Register isStoreToStackSlotPostFE(const MachineInstr &MI, |
201 | int &FrameIndex) const override; |
202 | |
203 | void copyToCPSR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, |
204 | unsigned SrcReg, bool KillSrc, |
205 | const ARMSubtarget &Subtarget) const; |
206 | void copyFromCPSR(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, |
207 | unsigned DestReg, bool KillSrc, |
208 | const ARMSubtarget &Subtarget) const; |
209 | |
210 | void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, |
211 | const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, |
212 | bool KillSrc) const override; |
213 | |
214 | void storeRegToStackSlot(MachineBasicBlock &MBB, |
215 | MachineBasicBlock::iterator MBBI, Register SrcReg, |
216 | bool isKill, int FrameIndex, |
217 | const TargetRegisterClass *RC, |
218 | const TargetRegisterInfo *TRI, |
219 | Register VReg) const override; |
220 | |
221 | void loadRegFromStackSlot(MachineBasicBlock &MBB, |
222 | MachineBasicBlock::iterator MBBI, Register DestReg, |
223 | int FrameIndex, const TargetRegisterClass *RC, |
224 | const TargetRegisterInfo *TRI, |
225 | Register VReg) const override; |
226 | |
227 | bool expandPostRAPseudo(MachineInstr &MI) const override; |
228 | |
229 | bool shouldSink(const MachineInstr &MI) const override; |
230 | |
231 | void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, |
232 | Register DestReg, unsigned SubIdx, |
233 | const MachineInstr &Orig, |
234 | const TargetRegisterInfo &TRI) const override; |
235 | |
236 | MachineInstr & |
237 | duplicate(MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, |
238 | const MachineInstr &Orig) const override; |
239 | |
240 | const MachineInstrBuilder &AddDReg(MachineInstrBuilder &MIB, unsigned Reg, |
241 | unsigned SubIdx, unsigned State, |
242 | const TargetRegisterInfo *TRI) const; |
243 | |
244 | bool produceSameValue(const MachineInstr &MI0, const MachineInstr &MI1, |
245 | const MachineRegisterInfo *MRI) const override; |
246 | |
247 | /// areLoadsFromSameBasePtr - This is used by the pre-regalloc scheduler to |
248 | /// determine if two loads are loading from the same base address. It should |
249 | /// only return true if the base pointers are the same and the only |
250 | /// differences between the two addresses is the offset. It also returns the |
251 | /// offsets by reference. |
252 | bool areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2, int64_t &Offset1, |
253 | int64_t &Offset2) const override; |
254 | |
255 | /// shouldScheduleLoadsNear - This is a used by the pre-regalloc scheduler to |
256 | /// determine (in conjunction with areLoadsFromSameBasePtr) if two loads |
257 | /// should be scheduled togther. On some targets if two loads are loading from |
258 | /// addresses in the same cache line, it's better if they are scheduled |
259 | /// together. This function takes two integers that represent the load offsets |
260 | /// from the common base address. It returns true if it decides it's desirable |
261 | /// to schedule the two loads together. "NumLoads" is the number of loads that |
262 | /// have already been scheduled after Load1. |
263 | bool shouldScheduleLoadsNear(SDNode *Load1, SDNode *Load2, |
264 | int64_t Offset1, int64_t Offset2, |
265 | unsigned NumLoads) const override; |
266 | |
267 | bool isSchedulingBoundary(const MachineInstr &MI, |
268 | const MachineBasicBlock *MBB, |
269 | const MachineFunction &MF) const override; |
270 | |
271 | bool isProfitableToIfCvt(MachineBasicBlock &MBB, |
272 | unsigned NumCycles, unsigned , |
273 | BranchProbability Probability) const override; |
274 | |
275 | bool isProfitableToIfCvt(MachineBasicBlock &TMBB, unsigned NumT, |
276 | unsigned , MachineBasicBlock &FMBB, |
277 | unsigned NumF, unsigned , |
278 | BranchProbability Probability) const override; |
279 | |
280 | bool isProfitableToDupForIfCvt(MachineBasicBlock &MBB, unsigned NumCycles, |
281 | BranchProbability Probability) const override { |
282 | return NumCycles == 1; |
283 | } |
284 | |
285 | unsigned (const MachineFunction &MF, |
286 | unsigned NumInsts) const override; |
287 | unsigned predictBranchSizeForIfCvt(MachineInstr &MI) const override; |
288 | |
289 | bool isProfitableToUnpredicate(MachineBasicBlock &TMBB, |
290 | MachineBasicBlock &FMBB) const override; |
291 | |
292 | /// analyzeCompare - For a comparison instruction, return the source registers |
293 | /// in SrcReg and SrcReg2 if having two register operands, and the value it |
294 | /// compares against in CmpValue. Return true if the comparison instruction |
295 | /// can be analyzed. |
296 | bool analyzeCompare(const MachineInstr &MI, Register &SrcReg, |
297 | Register &SrcReg2, int64_t &CmpMask, |
298 | int64_t &CmpValue) const override; |
299 | |
300 | /// optimizeCompareInstr - Convert the instruction to set the zero flag so |
301 | /// that we can remove a "comparison with zero"; Remove a redundant CMP |
302 | /// instruction if the flags can be updated in the same way by an earlier |
303 | /// instruction such as SUB. |
304 | bool optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg, |
305 | Register SrcReg2, int64_t CmpMask, int64_t CmpValue, |
306 | const MachineRegisterInfo *MRI) const override; |
307 | |
308 | bool analyzeSelect(const MachineInstr &MI, |
309 | SmallVectorImpl<MachineOperand> &Cond, unsigned &TrueOp, |
310 | unsigned &FalseOp, bool &Optimizable) const override; |
311 | |
312 | MachineInstr *optimizeSelect(MachineInstr &MI, |
313 | SmallPtrSetImpl<MachineInstr *> &SeenMIs, |
314 | bool) const override; |
315 | |
316 | /// foldImmediate - 'Reg' is known to be defined by a move immediate |
317 | /// instruction, try to fold the immediate into the use instruction. |
318 | bool foldImmediate(MachineInstr &UseMI, MachineInstr &DefMI, Register Reg, |
319 | MachineRegisterInfo *MRI) const override; |
320 | |
321 | unsigned getNumMicroOps(const InstrItineraryData *ItinData, |
322 | const MachineInstr &MI) const override; |
323 | |
324 | std::optional<unsigned> getOperandLatency(const InstrItineraryData *ItinData, |
325 | const MachineInstr &DefMI, |
326 | unsigned DefIdx, |
327 | const MachineInstr &UseMI, |
328 | unsigned UseIdx) const override; |
329 | std::optional<unsigned> getOperandLatency(const InstrItineraryData *ItinData, |
330 | SDNode *DefNode, unsigned DefIdx, |
331 | SDNode *UseNode, |
332 | unsigned UseIdx) const override; |
333 | |
334 | /// VFP/NEON execution domains. |
335 | std::pair<uint16_t, uint16_t> |
336 | getExecutionDomain(const MachineInstr &MI) const override; |
337 | void setExecutionDomain(MachineInstr &MI, unsigned Domain) const override; |
338 | |
339 | unsigned |
340 | getPartialRegUpdateClearance(const MachineInstr &, unsigned, |
341 | const TargetRegisterInfo *) const override; |
342 | void breakPartialRegDependency(MachineInstr &, unsigned, |
343 | const TargetRegisterInfo *TRI) const override; |
344 | |
345 | /// Get the number of addresses by LDM or VLDM or zero for unknown. |
346 | unsigned getNumLDMAddresses(const MachineInstr &MI) const; |
347 | |
348 | std::pair<unsigned, unsigned> |
349 | decomposeMachineOperandsTargetFlags(unsigned TF) const override; |
350 | ArrayRef<std::pair<unsigned, const char *>> |
351 | getSerializableDirectMachineOperandTargetFlags() const override; |
352 | ArrayRef<std::pair<unsigned, const char *>> |
353 | getSerializableBitmaskMachineOperandTargetFlags() const override; |
354 | |
355 | /// ARM supports the MachineOutliner. |
356 | bool isFunctionSafeToOutlineFrom(MachineFunction &MF, |
357 | bool OutlineFromLinkOnceODRs) const override; |
358 | std::optional<outliner::OutlinedFunction> getOutliningCandidateInfo( |
359 | std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override; |
360 | void mergeOutliningCandidateAttributes( |
361 | Function &F, std::vector<outliner::Candidate> &Candidates) const override; |
362 | outliner::InstrType getOutliningTypeImpl(MachineBasicBlock::iterator &MIT, |
363 | unsigned Flags) const override; |
364 | bool isMBBSafeToOutlineFrom(MachineBasicBlock &MBB, |
365 | unsigned &Flags) const override; |
366 | void buildOutlinedFrame(MachineBasicBlock &MBB, MachineFunction &MF, |
367 | const outliner::OutlinedFunction &OF) const override; |
368 | MachineBasicBlock::iterator |
369 | insertOutlinedCall(Module &M, MachineBasicBlock &MBB, |
370 | MachineBasicBlock::iterator &It, MachineFunction &MF, |
371 | outliner::Candidate &C) const override; |
372 | |
373 | /// Enable outlining by default at -Oz. |
374 | bool shouldOutlineFromFunctionByDefault(MachineFunction &MF) const override; |
375 | |
376 | bool isUnspillableTerminatorImpl(const MachineInstr *MI) const override { |
377 | return MI->getOpcode() == ARM::t2LoopEndDec || |
378 | MI->getOpcode() == ARM::t2DoLoopStartTP || |
379 | MI->getOpcode() == ARM::t2WhileLoopStartLR || |
380 | MI->getOpcode() == ARM::t2WhileLoopStartTP; |
381 | } |
382 | |
383 | /// Analyze loop L, which must be a single-basic-block loop, and if the |
384 | /// conditions can be understood enough produce a PipelinerLoopInfo object. |
385 | std::unique_ptr<TargetInstrInfo::PipelinerLoopInfo> |
386 | analyzeLoopForPipelining(MachineBasicBlock *LoopBB) const override; |
387 | |
388 | private: |
389 | /// Returns an unused general-purpose register which can be used for |
390 | /// constructing an outlined call if one exists. Returns 0 otherwise. |
391 | Register findRegisterToSaveLRTo(outliner::Candidate &C) const; |
392 | |
393 | /// Adds an instruction which saves the link register on top of the stack into |
394 | /// the MachineBasicBlock \p MBB at position \p It. If \p Auth is true, |
395 | /// compute and store an authentication code alongiside the link register. |
396 | /// If \p CFI is true, emit CFI instructions. |
397 | void saveLROnStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator It, |
398 | bool CFI, bool Auth) const; |
399 | |
400 | /// Adds an instruction which restores the link register from the top the |
401 | /// stack into the MachineBasicBlock \p MBB at position \p It. If \p Auth is |
402 | /// true, restore an authentication code and authenticate LR. |
403 | /// If \p CFI is true, emit CFI instructions. |
404 | void restoreLRFromStack(MachineBasicBlock &MBB, |
405 | MachineBasicBlock::iterator It, bool CFI, |
406 | bool Auth) const; |
407 | |
408 | /// Emit CFI instructions into the MachineBasicBlock \p MBB at position \p It, |
409 | /// for the case when the LR is saved in the register \p Reg. |
410 | void emitCFIForLRSaveToReg(MachineBasicBlock &MBB, |
411 | MachineBasicBlock::iterator It, |
412 | Register Reg) const; |
413 | |
414 | /// Emit CFI instructions into the MachineBasicBlock \p MBB at position \p It, |
415 | /// after the LR is was restored from a register. |
416 | void emitCFIForLRRestoreFromReg(MachineBasicBlock &MBB, |
417 | MachineBasicBlock::iterator It) const; |
418 | /// \brief Sets the offsets on outlined instructions in \p MBB which use SP |
419 | /// so that they will be valid post-outlining. |
420 | /// |
421 | /// \param MBB A \p MachineBasicBlock in an outlined function. |
422 | void fixupPostOutline(MachineBasicBlock &MBB) const; |
423 | |
424 | /// Returns true if the machine instruction offset can handle the stack fixup |
425 | /// and updates it if requested. |
426 | bool checkAndUpdateStackOffset(MachineInstr *MI, int64_t Fixup, |
427 | bool Updt) const; |
428 | |
429 | unsigned getInstBundleLength(const MachineInstr &MI) const; |
430 | |
431 | std::optional<unsigned> getVLDMDefCycle(const InstrItineraryData *ItinData, |
432 | const MCInstrDesc &DefMCID, |
433 | unsigned DefClass, unsigned DefIdx, |
434 | unsigned DefAlign) const; |
435 | std::optional<unsigned> getLDMDefCycle(const InstrItineraryData *ItinData, |
436 | const MCInstrDesc &DefMCID, |
437 | unsigned DefClass, unsigned DefIdx, |
438 | unsigned DefAlign) const; |
439 | std::optional<unsigned> getVSTMUseCycle(const InstrItineraryData *ItinData, |
440 | const MCInstrDesc &UseMCID, |
441 | unsigned UseClass, unsigned UseIdx, |
442 | unsigned UseAlign) const; |
443 | std::optional<unsigned> getSTMUseCycle(const InstrItineraryData *ItinData, |
444 | const MCInstrDesc &UseMCID, |
445 | unsigned UseClass, unsigned UseIdx, |
446 | unsigned UseAlign) const; |
447 | std::optional<unsigned> getOperandLatency(const InstrItineraryData *ItinData, |
448 | const MCInstrDesc &DefMCID, |
449 | unsigned DefIdx, unsigned DefAlign, |
450 | const MCInstrDesc &UseMCID, |
451 | unsigned UseIdx, |
452 | unsigned UseAlign) const; |
453 | |
454 | std::optional<unsigned> getOperandLatencyImpl( |
455 | const InstrItineraryData *ItinData, const MachineInstr &DefMI, |
456 | unsigned DefIdx, const MCInstrDesc &DefMCID, unsigned DefAdj, |
457 | const MachineOperand &DefMO, unsigned Reg, const MachineInstr &UseMI, |
458 | unsigned UseIdx, const MCInstrDesc &UseMCID, unsigned UseAdj) const; |
459 | |
460 | unsigned getPredicationCost(const MachineInstr &MI) const override; |
461 | |
462 | unsigned getInstrLatency(const InstrItineraryData *ItinData, |
463 | const MachineInstr &MI, |
464 | unsigned *PredCost = nullptr) const override; |
465 | |
466 | unsigned getInstrLatency(const InstrItineraryData *ItinData, |
467 | SDNode *Node) const override; |
468 | |
469 | bool hasHighOperandLatency(const TargetSchedModel &SchedModel, |
470 | const MachineRegisterInfo *MRI, |
471 | const MachineInstr &DefMI, unsigned DefIdx, |
472 | const MachineInstr &UseMI, |
473 | unsigned UseIdx) const override; |
474 | bool hasLowDefLatency(const TargetSchedModel &SchedModel, |
475 | const MachineInstr &DefMI, |
476 | unsigned DefIdx) const override; |
477 | |
478 | /// verifyInstruction - Perform target specific instruction verification. |
479 | bool verifyInstruction(const MachineInstr &MI, |
480 | StringRef &ErrInfo) const override; |
481 | |
482 | virtual void expandLoadStackGuard(MachineBasicBlock::iterator MI) const = 0; |
483 | |
484 | void expandMEMCPY(MachineBasicBlock::iterator) const; |
485 | |
486 | /// Identify instructions that can be folded into a MOVCC instruction, and |
487 | /// return the defining instruction. |
488 | MachineInstr *canFoldIntoMOVCC(Register Reg, const MachineRegisterInfo &MRI, |
489 | const TargetInstrInfo *TII) const; |
490 | |
491 | bool isReallyTriviallyReMaterializable(const MachineInstr &MI) const override; |
492 | |
493 | private: |
494 | /// Modeling special VFP / NEON fp MLA / MLS hazards. |
495 | |
496 | /// MLxEntryMap - Map fp MLA / MLS to the corresponding entry in the internal |
497 | /// MLx table. |
498 | DenseMap<unsigned, unsigned> MLxEntryMap; |
499 | |
500 | /// MLxHazardOpcodes - Set of add / sub and multiply opcodes that would cause |
501 | /// stalls when scheduled together with fp MLA / MLS opcodes. |
502 | SmallSet<unsigned, 16> MLxHazardOpcodes; |
503 | |
504 | public: |
505 | /// isFpMLxInstruction - Return true if the specified opcode is a fp MLA / MLS |
506 | /// instruction. |
507 | bool isFpMLxInstruction(unsigned Opcode) const { |
508 | return MLxEntryMap.count(Val: Opcode); |
509 | } |
510 | |
511 | /// isFpMLxInstruction - This version also returns the multiply opcode and the |
512 | /// addition / subtraction opcode to expand to. Return true for 'HasLane' for |
513 | /// the MLX instructions with an extra lane operand. |
514 | bool isFpMLxInstruction(unsigned Opcode, unsigned &MulOpc, |
515 | unsigned &AddSubOpc, bool &NegAcc, |
516 | bool &HasLane) const; |
517 | |
518 | /// canCauseFpMLxStall - Return true if an instruction of the specified opcode |
519 | /// will cause stalls when scheduled after (within 4-cycle window) a fp |
520 | /// MLA / MLS instruction. |
521 | bool canCauseFpMLxStall(unsigned Opcode) const { |
522 | return MLxHazardOpcodes.count(V: Opcode); |
523 | } |
524 | |
525 | /// Returns true if the instruction has a shift by immediate that can be |
526 | /// executed in one cycle less. |
527 | bool isSwiftFastImmShift(const MachineInstr *MI) const; |
528 | |
529 | /// Returns predicate register associated with the given frame instruction. |
530 | unsigned getFramePred(const MachineInstr &MI) const { |
531 | assert(isFrameInstr(MI)); |
532 | // Operands of ADJCALLSTACKDOWN/ADJCALLSTACKUP: |
533 | // - argument declared in the pattern: |
534 | // 0 - frame size |
535 | // 1 - arg of CALLSEQ_START/CALLSEQ_END |
536 | // 2 - predicate code (like ARMCC::AL) |
537 | // - added by predOps: |
538 | // 3 - predicate reg |
539 | return MI.getOperand(i: 3).getReg(); |
540 | } |
541 | |
542 | std::optional<RegImmPair> isAddImmediate(const MachineInstr &MI, |
543 | Register Reg) const override; |
544 | |
545 | unsigned getUndefInitOpcode(unsigned RegClassID) const override { |
546 | if (RegClassID == ARM::MQPRRegClass.getID()) |
547 | return ARM::PseudoARMInitUndefMQPR; |
548 | if (RegClassID == ARM::SPRRegClass.getID()) |
549 | return ARM::PseudoARMInitUndefSPR; |
550 | if (RegClassID == ARM::DPR_VFP2RegClass.getID()) |
551 | return ARM::PseudoARMInitUndefDPR_VFP2; |
552 | if (RegClassID == ARM::GPRRegClass.getID()) |
553 | return ARM::PseudoARMInitUndefGPR; |
554 | |
555 | llvm_unreachable("Unexpected register class." ); |
556 | } |
557 | }; |
558 | |
559 | /// Get the operands corresponding to the given \p Pred value. By default, the |
560 | /// predicate register is assumed to be 0 (no register), but you can pass in a |
561 | /// \p PredReg if that is not the case. |
562 | static inline std::array<MachineOperand, 2> predOps(ARMCC::CondCodes Pred, |
563 | unsigned PredReg = 0) { |
564 | return {._M_elems: {MachineOperand::CreateImm(Val: static_cast<int64_t>(Pred)), |
565 | MachineOperand::CreateReg(Reg: PredReg, isDef: false)}}; |
566 | } |
567 | |
568 | /// Get the operand corresponding to the conditional code result. By default, |
569 | /// this is 0 (no register). |
570 | static inline MachineOperand condCodeOp(unsigned CCReg = 0) { |
571 | return MachineOperand::CreateReg(Reg: CCReg, isDef: false); |
572 | } |
573 | |
574 | /// Get the operand corresponding to the conditional code result for Thumb1. |
575 | /// This operand will always refer to CPSR and it will have the Define flag set. |
576 | /// You can optionally set the Dead flag by means of \p isDead. |
577 | static inline MachineOperand t1CondCodeOp(bool isDead = false) { |
578 | return MachineOperand::CreateReg(Reg: ARM::CPSR, |
579 | /*Define*/ isDef: true, /*Implicit*/ isImp: false, |
580 | /*Kill*/ isKill: false, isDead); |
581 | } |
582 | |
583 | static inline |
584 | bool isUncondBranchOpcode(int Opc) { |
585 | return Opc == ARM::B || Opc == ARM::tB || Opc == ARM::t2B; |
586 | } |
587 | |
588 | // This table shows the VPT instruction variants, i.e. the different |
589 | // mask field encodings, see also B5.6. Predication/conditional execution in |
590 | // the ArmARM. |
591 | static inline bool isVPTOpcode(int Opc) { |
592 | return Opc == ARM::MVE_VPTv16i8 || Opc == ARM::MVE_VPTv16u8 || |
593 | Opc == ARM::MVE_VPTv16s8 || Opc == ARM::MVE_VPTv8i16 || |
594 | Opc == ARM::MVE_VPTv8u16 || Opc == ARM::MVE_VPTv8s16 || |
595 | Opc == ARM::MVE_VPTv4i32 || Opc == ARM::MVE_VPTv4u32 || |
596 | Opc == ARM::MVE_VPTv4s32 || Opc == ARM::MVE_VPTv4f32 || |
597 | Opc == ARM::MVE_VPTv8f16 || Opc == ARM::MVE_VPTv16i8r || |
598 | Opc == ARM::MVE_VPTv16u8r || Opc == ARM::MVE_VPTv16s8r || |
599 | Opc == ARM::MVE_VPTv8i16r || Opc == ARM::MVE_VPTv8u16r || |
600 | Opc == ARM::MVE_VPTv8s16r || Opc == ARM::MVE_VPTv4i32r || |
601 | Opc == ARM::MVE_VPTv4u32r || Opc == ARM::MVE_VPTv4s32r || |
602 | Opc == ARM::MVE_VPTv4f32r || Opc == ARM::MVE_VPTv8f16r || |
603 | Opc == ARM::MVE_VPST; |
604 | } |
605 | |
606 | static inline |
607 | unsigned VCMPOpcodeToVPT(unsigned Opcode) { |
608 | switch (Opcode) { |
609 | default: |
610 | return 0; |
611 | case ARM::MVE_VCMPf32: |
612 | return ARM::MVE_VPTv4f32; |
613 | case ARM::MVE_VCMPf16: |
614 | return ARM::MVE_VPTv8f16; |
615 | case ARM::MVE_VCMPi8: |
616 | return ARM::MVE_VPTv16i8; |
617 | case ARM::MVE_VCMPi16: |
618 | return ARM::MVE_VPTv8i16; |
619 | case ARM::MVE_VCMPi32: |
620 | return ARM::MVE_VPTv4i32; |
621 | case ARM::MVE_VCMPu8: |
622 | return ARM::MVE_VPTv16u8; |
623 | case ARM::MVE_VCMPu16: |
624 | return ARM::MVE_VPTv8u16; |
625 | case ARM::MVE_VCMPu32: |
626 | return ARM::MVE_VPTv4u32; |
627 | case ARM::MVE_VCMPs8: |
628 | return ARM::MVE_VPTv16s8; |
629 | case ARM::MVE_VCMPs16: |
630 | return ARM::MVE_VPTv8s16; |
631 | case ARM::MVE_VCMPs32: |
632 | return ARM::MVE_VPTv4s32; |
633 | |
634 | case ARM::MVE_VCMPf32r: |
635 | return ARM::MVE_VPTv4f32r; |
636 | case ARM::MVE_VCMPf16r: |
637 | return ARM::MVE_VPTv8f16r; |
638 | case ARM::MVE_VCMPi8r: |
639 | return ARM::MVE_VPTv16i8r; |
640 | case ARM::MVE_VCMPi16r: |
641 | return ARM::MVE_VPTv8i16r; |
642 | case ARM::MVE_VCMPi32r: |
643 | return ARM::MVE_VPTv4i32r; |
644 | case ARM::MVE_VCMPu8r: |
645 | return ARM::MVE_VPTv16u8r; |
646 | case ARM::MVE_VCMPu16r: |
647 | return ARM::MVE_VPTv8u16r; |
648 | case ARM::MVE_VCMPu32r: |
649 | return ARM::MVE_VPTv4u32r; |
650 | case ARM::MVE_VCMPs8r: |
651 | return ARM::MVE_VPTv16s8r; |
652 | case ARM::MVE_VCMPs16r: |
653 | return ARM::MVE_VPTv8s16r; |
654 | case ARM::MVE_VCMPs32r: |
655 | return ARM::MVE_VPTv4s32r; |
656 | } |
657 | } |
658 | |
659 | static inline |
660 | bool isCondBranchOpcode(int Opc) { |
661 | return Opc == ARM::Bcc || Opc == ARM::tBcc || Opc == ARM::t2Bcc; |
662 | } |
663 | |
664 | static inline bool isJumpTableBranchOpcode(int Opc) { |
665 | return Opc == ARM::BR_JTr || Opc == ARM::BR_JTm_i12 || |
666 | Opc == ARM::BR_JTm_rs || Opc == ARM::BR_JTadd || Opc == ARM::tBR_JTr || |
667 | Opc == ARM::t2BR_JT; |
668 | } |
669 | |
670 | static inline |
671 | bool isIndirectBranchOpcode(int Opc) { |
672 | return Opc == ARM::BX || Opc == ARM::MOVPCRX || Opc == ARM::tBRIND; |
673 | } |
674 | |
675 | static inline bool isIndirectCall(const MachineInstr &MI) { |
676 | int Opc = MI.getOpcode(); |
677 | switch (Opc) { |
678 | // indirect calls: |
679 | case ARM::BLX: |
680 | case ARM::BLX_noip: |
681 | case ARM::BLX_pred: |
682 | case ARM::BLX_pred_noip: |
683 | case ARM::BX_CALL: |
684 | case ARM::BMOVPCRX_CALL: |
685 | case ARM::TCRETURNri: |
686 | case ARM::TCRETURNrinotr12: |
687 | case ARM::TAILJMPr: |
688 | case ARM::TAILJMPr4: |
689 | case ARM::tBLXr: |
690 | case ARM::tBLXr_noip: |
691 | case ARM::tBLXNSr: |
692 | case ARM::tBLXNS_CALL: |
693 | case ARM::tBX_CALL: |
694 | case ARM::tTAILJMPr: |
695 | assert(MI.isCall(MachineInstr::IgnoreBundle)); |
696 | return true; |
697 | // direct calls: |
698 | case ARM::BL: |
699 | case ARM::BL_pred: |
700 | case ARM::BMOVPCB_CALL: |
701 | case ARM::BL_PUSHLR: |
702 | case ARM::BLXi: |
703 | case ARM::TCRETURNdi: |
704 | case ARM::TAILJMPd: |
705 | case ARM::SVC: |
706 | case ARM::HVC: |
707 | case ARM::TPsoft: |
708 | case ARM::tTAILJMPd: |
709 | case ARM::t2SMC: |
710 | case ARM::t2HVC: |
711 | case ARM::tBL: |
712 | case ARM::tBLXi: |
713 | case ARM::tBL_PUSHLR: |
714 | case ARM::tTAILJMPdND: |
715 | case ARM::tSVC: |
716 | case ARM::tTPsoft: |
717 | assert(MI.isCall(MachineInstr::IgnoreBundle)); |
718 | return false; |
719 | } |
720 | assert(!MI.isCall(MachineInstr::IgnoreBundle)); |
721 | return false; |
722 | } |
723 | |
724 | static inline bool isIndirectControlFlowNotComingBack(const MachineInstr &MI) { |
725 | int opc = MI.getOpcode(); |
726 | return MI.isReturn() || isIndirectBranchOpcode(Opc: MI.getOpcode()) || |
727 | isJumpTableBranchOpcode(Opc: opc); |
728 | } |
729 | |
730 | static inline bool isSpeculationBarrierEndBBOpcode(int Opc) { |
731 | return Opc == ARM::SpeculationBarrierISBDSBEndBB || |
732 | Opc == ARM::SpeculationBarrierSBEndBB || |
733 | Opc == ARM::t2SpeculationBarrierISBDSBEndBB || |
734 | Opc == ARM::t2SpeculationBarrierSBEndBB; |
735 | } |
736 | |
737 | static inline bool isPopOpcode(int Opc) { |
738 | return Opc == ARM::tPOP_RET || Opc == ARM::LDMIA_RET || |
739 | Opc == ARM::t2LDMIA_RET || Opc == ARM::tPOP || Opc == ARM::LDMIA_UPD || |
740 | Opc == ARM::t2LDMIA_UPD || Opc == ARM::VLDMDIA_UPD; |
741 | } |
742 | |
743 | static inline bool isPushOpcode(int Opc) { |
744 | return Opc == ARM::tPUSH || Opc == ARM::t2STMDB_UPD || |
745 | Opc == ARM::STMDB_UPD || Opc == ARM::VSTMDDB_UPD; |
746 | } |
747 | |
748 | static inline bool isSubImmOpcode(int Opc) { |
749 | return Opc == ARM::SUBri || |
750 | Opc == ARM::tSUBi3 || Opc == ARM::tSUBi8 || |
751 | Opc == ARM::tSUBSi3 || Opc == ARM::tSUBSi8 || |
752 | Opc == ARM::t2SUBri || Opc == ARM::t2SUBri12 || Opc == ARM::t2SUBSri; |
753 | } |
754 | |
755 | static inline bool isMovRegOpcode(int Opc) { |
756 | return Opc == ARM::MOVr || Opc == ARM::tMOVr || Opc == ARM::t2MOVr; |
757 | } |
758 | /// isValidCoprocessorNumber - decide whether an explicit coprocessor |
759 | /// number is legal in generic instructions like CDP. The answer can |
760 | /// vary with the subtarget. |
761 | static inline bool isValidCoprocessorNumber(unsigned Num, |
762 | const FeatureBitset& featureBits) { |
763 | // In Armv7 and Armv8-M CP10 and CP11 clash with VFP/NEON, however, the |
764 | // coprocessor is still valid for CDP/MCR/MRC and friends. Allowing it is |
765 | // useful for code which is shared with older architectures which do not know |
766 | // the new VFP/NEON mnemonics. |
767 | |
768 | // Armv8-A disallows everything *other* than 111x (CP14 and CP15). |
769 | if (featureBits[ARM::HasV8Ops] && (Num & 0xE) != 0xE) |
770 | return false; |
771 | |
772 | // Armv8.1-M disallows 100x (CP8,CP9) and 111x (CP14,CP15) |
773 | // which clash with MVE. |
774 | if (featureBits[ARM::HasV8_1MMainlineOps] && |
775 | ((Num & 0xE) == 0x8 || (Num & 0xE) == 0xE)) |
776 | return false; |
777 | |
778 | return true; |
779 | } |
780 | |
781 | static inline bool isSEHInstruction(const MachineInstr &MI) { |
782 | unsigned Opc = MI.getOpcode(); |
783 | switch (Opc) { |
784 | case ARM::SEH_StackAlloc: |
785 | case ARM::SEH_SaveRegs: |
786 | case ARM::SEH_SaveRegs_Ret: |
787 | case ARM::SEH_SaveSP: |
788 | case ARM::SEH_SaveFRegs: |
789 | case ARM::SEH_SaveLR: |
790 | case ARM::SEH_Nop: |
791 | case ARM::SEH_Nop_Ret: |
792 | case ARM::SEH_PrologEnd: |
793 | case ARM::SEH_EpilogStart: |
794 | case ARM::SEH_EpilogEnd: |
795 | return true; |
796 | default: |
797 | return false; |
798 | } |
799 | } |
800 | |
801 | /// getInstrPredicate - If instruction is predicated, returns its predicate |
802 | /// condition, otherwise returns AL. It also returns the condition code |
803 | /// register by reference. |
804 | ARMCC::CondCodes getInstrPredicate(const MachineInstr &MI, Register &PredReg); |
805 | |
806 | unsigned getMatchingCondBranchOpcode(unsigned Opc); |
807 | |
808 | /// Map pseudo instructions that imply an 'S' bit onto real opcodes. Whether |
809 | /// the instruction is encoded with an 'S' bit is determined by the optional |
810 | /// CPSR def operand. |
811 | unsigned convertAddSubFlagsOpcode(unsigned OldOpc); |
812 | |
813 | /// emitARMRegPlusImmediate / emitT2RegPlusImmediate - Emits a series of |
814 | /// instructions to materializea destreg = basereg + immediate in ARM / Thumb2 |
815 | /// code. |
816 | void emitARMRegPlusImmediate(MachineBasicBlock &MBB, |
817 | MachineBasicBlock::iterator &MBBI, |
818 | const DebugLoc &dl, Register DestReg, |
819 | Register BaseReg, int NumBytes, |
820 | ARMCC::CondCodes Pred, Register PredReg, |
821 | const ARMBaseInstrInfo &TII, unsigned MIFlags = 0); |
822 | |
823 | void emitT2RegPlusImmediate(MachineBasicBlock &MBB, |
824 | MachineBasicBlock::iterator &MBBI, |
825 | const DebugLoc &dl, Register DestReg, |
826 | Register BaseReg, int NumBytes, |
827 | ARMCC::CondCodes Pred, Register PredReg, |
828 | const ARMBaseInstrInfo &TII, unsigned MIFlags = 0); |
829 | void emitThumbRegPlusImmediate(MachineBasicBlock &MBB, |
830 | MachineBasicBlock::iterator &MBBI, |
831 | const DebugLoc &dl, Register DestReg, |
832 | Register BaseReg, int NumBytes, |
833 | const TargetInstrInfo &TII, |
834 | const ARMBaseRegisterInfo &MRI, |
835 | unsigned MIFlags = 0); |
836 | |
837 | /// Tries to add registers to the reglist of a given base-updating |
838 | /// push/pop instruction to adjust the stack by an additional |
839 | /// NumBytes. This can save a few bytes per function in code-size, but |
840 | /// obviously generates more memory traffic. As such, it only takes |
841 | /// effect in functions being optimised for size. |
842 | bool tryFoldSPUpdateIntoPushPop(const ARMSubtarget &Subtarget, |
843 | MachineFunction &MF, MachineInstr *MI, |
844 | unsigned NumBytes); |
845 | |
846 | /// rewriteARMFrameIndex / rewriteT2FrameIndex - |
847 | /// Rewrite MI to access 'Offset' bytes from the FP. Return false if the |
848 | /// offset could not be handled directly in MI, and return the left-over |
849 | /// portion by reference. |
850 | bool rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, |
851 | Register FrameReg, int &Offset, |
852 | const ARMBaseInstrInfo &TII); |
853 | |
854 | bool rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx, |
855 | Register FrameReg, int &Offset, |
856 | const ARMBaseInstrInfo &TII, |
857 | const TargetRegisterInfo *TRI); |
858 | |
859 | /// Return true if Reg is defd between From and To |
860 | bool registerDefinedBetween(unsigned Reg, MachineBasicBlock::iterator From, |
861 | MachineBasicBlock::iterator To, |
862 | const TargetRegisterInfo *TRI); |
863 | |
864 | /// Search backwards from a tBcc to find a tCMPi8 against 0, meaning |
865 | /// we can convert them to a tCBZ or tCBNZ. Return nullptr if not found. |
866 | MachineInstr *findCMPToFoldIntoCBZ(MachineInstr *Br, |
867 | const TargetRegisterInfo *TRI); |
868 | |
869 | void addUnpredicatedMveVpredNOp(MachineInstrBuilder &MIB); |
870 | void addUnpredicatedMveVpredROp(MachineInstrBuilder &MIB, Register DestReg); |
871 | |
872 | void addPredicatedMveVpredNOp(MachineInstrBuilder &MIB, unsigned Cond); |
873 | void addPredicatedMveVpredROp(MachineInstrBuilder &MIB, unsigned Cond, |
874 | unsigned Inactive); |
875 | |
876 | /// Returns the number of instructions required to materialize the given |
877 | /// constant in a register, or 3 if a literal pool load is needed. |
878 | /// If ForCodesize is specified, an approximate cost in bytes is returned. |
879 | unsigned ConstantMaterializationCost(unsigned Val, |
880 | const ARMSubtarget *Subtarget, |
881 | bool ForCodesize = false); |
882 | |
883 | /// Returns true if Val1 has a lower Constant Materialization Cost than Val2. |
884 | /// Uses the cost from ConstantMaterializationCost, first with ForCodesize as |
885 | /// specified. If the scores are equal, return the comparison for !ForCodesize. |
886 | bool HasLowerConstantMaterializationCost(unsigned Val1, unsigned Val2, |
887 | const ARMSubtarget *Subtarget, |
888 | bool ForCodesize = false); |
889 | |
890 | // Return the immediate if this is ADDri or SUBri, scaled as appropriate. |
891 | // Returns 0 for unknown instructions. |
892 | inline int getAddSubImmediate(MachineInstr &MI) { |
893 | int Scale = 1; |
894 | unsigned ImmOp; |
895 | switch (MI.getOpcode()) { |
896 | case ARM::t2ADDri: |
897 | ImmOp = 2; |
898 | break; |
899 | case ARM::t2SUBri: |
900 | case ARM::t2SUBri12: |
901 | ImmOp = 2; |
902 | Scale = -1; |
903 | break; |
904 | case ARM::tSUBi3: |
905 | case ARM::tSUBi8: |
906 | ImmOp = 3; |
907 | Scale = -1; |
908 | break; |
909 | default: |
910 | return 0; |
911 | } |
912 | return Scale * MI.getOperand(i: ImmOp).getImm(); |
913 | } |
914 | |
915 | // Given a memory access Opcode, check that the give Imm would be a valid Offset |
916 | // for this instruction using its addressing mode. |
917 | inline bool isLegalAddressImm(unsigned Opcode, int Imm, |
918 | const TargetInstrInfo *TII) { |
919 | const MCInstrDesc &Desc = TII->get(Opcode); |
920 | unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); |
921 | switch (AddrMode) { |
922 | case ARMII::AddrModeT2_i7: |
923 | return std::abs(x: Imm) < ((1 << 7) * 1); |
924 | case ARMII::AddrModeT2_i7s2: |
925 | return std::abs(x: Imm) < ((1 << 7) * 2) && Imm % 2 == 0; |
926 | case ARMII::AddrModeT2_i7s4: |
927 | return std::abs(x: Imm) < ((1 << 7) * 4) && Imm % 4 == 0; |
928 | case ARMII::AddrModeT2_i8: |
929 | return std::abs(x: Imm) < ((1 << 8) * 1); |
930 | case ARMII::AddrModeT2_i8pos: |
931 | return Imm >= 0 && Imm < ((1 << 8) * 1); |
932 | case ARMII::AddrModeT2_i8neg: |
933 | return Imm < 0 && -Imm < ((1 << 8) * 1); |
934 | case ARMII::AddrModeT2_i8s4: |
935 | return std::abs(x: Imm) < ((1 << 8) * 4) && Imm % 4 == 0; |
936 | case ARMII::AddrModeT2_i12: |
937 | return Imm >= 0 && Imm < ((1 << 12) * 1); |
938 | case ARMII::AddrMode2: |
939 | return std::abs(x: Imm) < ((1 << 12) * 1); |
940 | default: |
941 | llvm_unreachable("Unhandled Addressing mode" ); |
942 | } |
943 | } |
944 | |
945 | // Return true if the given intrinsic is a gather |
946 | inline bool isGather(IntrinsicInst *IntInst) { |
947 | if (IntInst == nullptr) |
948 | return false; |
949 | unsigned IntrinsicID = IntInst->getIntrinsicID(); |
950 | return (IntrinsicID == Intrinsic::masked_gather || |
951 | IntrinsicID == Intrinsic::arm_mve_vldr_gather_base || |
952 | IntrinsicID == Intrinsic::arm_mve_vldr_gather_base_predicated || |
953 | IntrinsicID == Intrinsic::arm_mve_vldr_gather_base_wb || |
954 | IntrinsicID == Intrinsic::arm_mve_vldr_gather_base_wb_predicated || |
955 | IntrinsicID == Intrinsic::arm_mve_vldr_gather_offset || |
956 | IntrinsicID == Intrinsic::arm_mve_vldr_gather_offset_predicated); |
957 | } |
958 | |
959 | // Return true if the given intrinsic is a scatter |
960 | inline bool isScatter(IntrinsicInst *IntInst) { |
961 | if (IntInst == nullptr) |
962 | return false; |
963 | unsigned IntrinsicID = IntInst->getIntrinsicID(); |
964 | return (IntrinsicID == Intrinsic::masked_scatter || |
965 | IntrinsicID == Intrinsic::arm_mve_vstr_scatter_base || |
966 | IntrinsicID == Intrinsic::arm_mve_vstr_scatter_base_predicated || |
967 | IntrinsicID == Intrinsic::arm_mve_vstr_scatter_base_wb || |
968 | IntrinsicID == Intrinsic::arm_mve_vstr_scatter_base_wb_predicated || |
969 | IntrinsicID == Intrinsic::arm_mve_vstr_scatter_offset || |
970 | IntrinsicID == Intrinsic::arm_mve_vstr_scatter_offset_predicated); |
971 | } |
972 | |
973 | // Return true if the given intrinsic is a gather or scatter |
974 | inline bool isGatherScatter(IntrinsicInst *IntInst) { |
975 | if (IntInst == nullptr) |
976 | return false; |
977 | return isGather(IntInst) || isScatter(IntInst); |
978 | } |
979 | |
980 | unsigned getBLXOpcode(const MachineFunction &MF); |
981 | unsigned gettBLXrOpcode(const MachineFunction &MF); |
982 | unsigned getBLXpredOpcode(const MachineFunction &MF); |
983 | |
984 | } // end namespace llvm |
985 | |
986 | #endif // LLVM_LIB_TARGET_ARM_ARMBASEINSTRINFO_H |
987 | |