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