1 //===- AArch64InstrInfo.h - AArch64 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 AArch64 implementation of the TargetInstrInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_LIB_TARGET_AARCH64_AARCH64INSTRINFO_H
14 #define LLVM_LIB_TARGET_AARCH64_AARCH64INSTRINFO_H
15 
16 #include "AArch64.h"
17 #include "AArch64RegisterInfo.h"
18 #include "llvm/CodeGen/TargetInstrInfo.h"
19 #include "llvm/Support/TypeSize.h"
20 #include <optional>
21 
22 #define GET_INSTRINFO_HEADER
23 #include "AArch64GenInstrInfo.inc"
24 
25 namespace llvm {
26 
27 class AArch64Subtarget;
28 
29 static const MachineMemOperand::Flags MOSuppressPair =
30     MachineMemOperand::MOTargetFlag1;
31 static const MachineMemOperand::Flags MOStridedAccess =
32     MachineMemOperand::MOTargetFlag2;
33 
34 #define FALKOR_STRIDED_ACCESS_MD "falkor.strided.access"
35 
36 class AArch64InstrInfo final : public AArch64GenInstrInfo {
37   const AArch64RegisterInfo RI;
38   const AArch64Subtarget &Subtarget;
39 
40 public:
41   explicit AArch64InstrInfo(const AArch64Subtarget &STI);
42 
43   /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info.  As
44   /// such, whenever a client has an instance of instruction info, it should
45   /// always be able to get register info as well (through this method).
46   const AArch64RegisterInfo &getRegisterInfo() const { return RI; }
47 
48   unsigned getInstSizeInBytes(const MachineInstr &MI) const override;
49 
50   bool isAsCheapAsAMove(const MachineInstr &MI) const override;
51 
52   bool isCoalescableExtInstr(const MachineInstr &MI, Register &SrcReg,
53                              Register &DstReg, unsigned &SubIdx) const override;
54 
55   bool
56   areMemAccessesTriviallyDisjoint(const MachineInstr &MIa,
57                                   const MachineInstr &MIb) const override;
58 
59   unsigned isLoadFromStackSlot(const MachineInstr &MI,
60                                int &FrameIndex) const override;
61   unsigned isStoreToStackSlot(const MachineInstr &MI,
62                               int &FrameIndex) const override;
63 
64   /// Does this instruction set its full destination register to zero?
65   static bool isGPRZero(const MachineInstr &MI);
66 
67   /// Does this instruction rename a GPR without modifying bits?
68   static bool isGPRCopy(const MachineInstr &MI);
69 
70   /// Does this instruction rename an FPR without modifying bits?
71   static bool isFPRCopy(const MachineInstr &MI);
72 
73   /// Return true if pairing the given load or store is hinted to be
74   /// unprofitable.
75   static bool isLdStPairSuppressed(const MachineInstr &MI);
76 
77   /// Return true if the given load or store is a strided memory access.
78   static bool isStridedAccess(const MachineInstr &MI);
79 
80   /// Return true if it has an unscaled load/store offset.
81   static bool hasUnscaledLdStOffset(unsigned Opc);
82   static bool hasUnscaledLdStOffset(MachineInstr &MI) {
83     return hasUnscaledLdStOffset(MI.getOpcode());
84   }
85 
86   /// Returns the unscaled load/store for the scaled load/store opcode,
87   /// if there is a corresponding unscaled variant available.
88   static std::optional<unsigned> getUnscaledLdSt(unsigned Opc);
89 
90   /// Scaling factor for (scaled or unscaled) load or store.
91   static int getMemScale(unsigned Opc);
92   static int getMemScale(const MachineInstr &MI) {
93     return getMemScale(MI.getOpcode());
94   }
95 
96   /// Returns whether the instruction is a pre-indexed load.
97   static bool isPreLd(const MachineInstr &MI);
98 
99   /// Returns whether the instruction is a pre-indexed store.
100   static bool isPreSt(const MachineInstr &MI);
101 
102   /// Returns whether the instruction is a pre-indexed load/store.
103   static bool isPreLdSt(const MachineInstr &MI);
104 
105   /// Returns whether the instruction is a paired load/store.
106   static bool isPairedLdSt(const MachineInstr &MI);
107 
108   /// Returns the base register operator of a load/store.
109   static const MachineOperand &getLdStBaseOp(const MachineInstr &MI);
110 
111   /// Returns the the immediate offset operator of a load/store.
112   static const MachineOperand &getLdStOffsetOp(const MachineInstr &MI);
113 
114   /// Returns whether the instruction is FP or NEON.
115   static bool isFpOrNEON(const MachineInstr &MI);
116 
117   /// Returns whether the instruction is in H form (16 bit operands)
118   static bool isHForm(const MachineInstr &MI);
119 
120   /// Returns whether the instruction is in Q form (128 bit operands)
121   static bool isQForm(const MachineInstr &MI);
122 
123   /// Returns the index for the immediate for a given instruction.
124   static unsigned getLoadStoreImmIdx(unsigned Opc);
125 
126   /// Return true if pairing the given load or store may be paired with another.
127   static bool isPairableLdStInst(const MachineInstr &MI);
128 
129   /// Return the opcode that set flags when possible.  The caller is
130   /// responsible for ensuring the opc has a flag setting equivalent.
131   static unsigned convertToFlagSettingOpc(unsigned Opc);
132 
133   /// Return true if this is a load/store that can be potentially paired/merged.
134   bool isCandidateToMergeOrPair(const MachineInstr &MI) const;
135 
136   /// Hint that pairing the given load or store is unprofitable.
137   static void suppressLdStPair(MachineInstr &MI);
138 
139   std::optional<ExtAddrMode>
140   getAddrModeFromMemoryOp(const MachineInstr &MemI,
141                           const TargetRegisterInfo *TRI) const override;
142 
143   bool getMemOperandsWithOffsetWidth(
144       const MachineInstr &MI, SmallVectorImpl<const MachineOperand *> &BaseOps,
145       int64_t &Offset, bool &OffsetIsScalable, unsigned &Width,
146       const TargetRegisterInfo *TRI) const override;
147 
148   /// If \p OffsetIsScalable is set to 'true', the offset is scaled by `vscale`.
149   /// This is true for some SVE instructions like ldr/str that have a
150   /// 'reg + imm' addressing mode where the immediate is an index to the
151   /// scalable vector located at 'reg + imm * vscale x #bytes'.
152   bool getMemOperandWithOffsetWidth(const MachineInstr &MI,
153                                     const MachineOperand *&BaseOp,
154                                     int64_t &Offset, bool &OffsetIsScalable,
155                                     unsigned &Width,
156                                     const TargetRegisterInfo *TRI) const;
157 
158   /// Return the immediate offset of the base register in a load/store \p LdSt.
159   MachineOperand &getMemOpBaseRegImmOfsOffsetOperand(MachineInstr &LdSt) const;
160 
161   /// Returns true if opcode \p Opc is a memory operation. If it is, set
162   /// \p Scale, \p Width, \p MinOffset, and \p MaxOffset accordingly.
163   ///
164   /// For unscaled instructions, \p Scale is set to 1.
165   static bool getMemOpInfo(unsigned Opcode, TypeSize &Scale, unsigned &Width,
166                            int64_t &MinOffset, int64_t &MaxOffset);
167 
168   bool shouldClusterMemOps(ArrayRef<const MachineOperand *> BaseOps1,
169                            ArrayRef<const MachineOperand *> BaseOps2,
170                            unsigned NumLoads, unsigned NumBytes) const override;
171 
172   void copyPhysRegTuple(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
173                         const DebugLoc &DL, MCRegister DestReg,
174                         MCRegister SrcReg, bool KillSrc, unsigned Opcode,
175                         llvm::ArrayRef<unsigned> Indices) const;
176   void copyGPRRegTuple(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
177                        DebugLoc DL, unsigned DestReg, unsigned SrcReg,
178                        bool KillSrc, unsigned Opcode, unsigned ZeroReg,
179                        llvm::ArrayRef<unsigned> Indices) const;
180   void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
181                    const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg,
182                    bool KillSrc) const override;
183 
184   void storeRegToStackSlot(MachineBasicBlock &MBB,
185                            MachineBasicBlock::iterator MBBI, Register SrcReg,
186                            bool isKill, int FrameIndex,
187                            const TargetRegisterClass *RC,
188                            const TargetRegisterInfo *TRI,
189                            Register VReg) const override;
190 
191   void loadRegFromStackSlot(MachineBasicBlock &MBB,
192                             MachineBasicBlock::iterator MBBI, Register DestReg,
193                             int FrameIndex, const TargetRegisterClass *RC,
194                             const TargetRegisterInfo *TRI,
195                             Register VReg) const override;
196 
197   // This tells target independent code that it is okay to pass instructions
198   // with subreg operands to foldMemoryOperandImpl.
199   bool isSubregFoldable() const override { return true; }
200 
201   using TargetInstrInfo::foldMemoryOperandImpl;
202   MachineInstr *
203   foldMemoryOperandImpl(MachineFunction &MF, MachineInstr &MI,
204                         ArrayRef<unsigned> Ops,
205                         MachineBasicBlock::iterator InsertPt, int FrameIndex,
206                         LiveIntervals *LIS = nullptr,
207                         VirtRegMap *VRM = nullptr) const override;
208 
209   /// \returns true if a branch from an instruction with opcode \p BranchOpc
210   ///  bytes is capable of jumping to a position \p BrOffset bytes away.
211   bool isBranchOffsetInRange(unsigned BranchOpc,
212                              int64_t BrOffset) const override;
213 
214   MachineBasicBlock *getBranchDestBlock(const MachineInstr &MI) const override;
215 
216   bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
217                      MachineBasicBlock *&FBB,
218                      SmallVectorImpl<MachineOperand> &Cond,
219                      bool AllowModify = false) const override;
220   bool analyzeBranchPredicate(MachineBasicBlock &MBB,
221                               MachineBranchPredicate &MBP,
222                               bool AllowModify) const override;
223   unsigned removeBranch(MachineBasicBlock &MBB,
224                         int *BytesRemoved = nullptr) const override;
225   unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
226                         MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
227                         const DebugLoc &DL,
228                         int *BytesAdded = nullptr) const override;
229   bool
230   reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
231   bool canInsertSelect(const MachineBasicBlock &, ArrayRef<MachineOperand> Cond,
232                        Register, Register, Register, int &, int &,
233                        int &) const override;
234   void insertSelect(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
235                     const DebugLoc &DL, Register DstReg,
236                     ArrayRef<MachineOperand> Cond, Register TrueReg,
237                     Register FalseReg) const override;
238   MCInst getNop() const override;
239 
240   bool isSchedulingBoundary(const MachineInstr &MI,
241                             const MachineBasicBlock *MBB,
242                             const MachineFunction &MF) const override;
243 
244   /// analyzeCompare - For a comparison instruction, return the source registers
245   /// in SrcReg and SrcReg2, and the value it compares against in CmpValue.
246   /// Return true if the comparison instruction can be analyzed.
247   bool analyzeCompare(const MachineInstr &MI, Register &SrcReg,
248                       Register &SrcReg2, int64_t &CmpMask,
249                       int64_t &CmpValue) const override;
250   /// optimizeCompareInstr - Convert the instruction supplying the argument to
251   /// the comparison into one that sets the zero bit in the flags register.
252   bool optimizeCompareInstr(MachineInstr &CmpInstr, Register SrcReg,
253                             Register SrcReg2, int64_t CmpMask, int64_t CmpValue,
254                             const MachineRegisterInfo *MRI) const override;
255   bool optimizeCondBranch(MachineInstr &MI) const override;
256 
257   /// Return true when a code sequence can improve throughput. It
258   /// should be called only for instructions in loops.
259   /// \param Pattern - combiner pattern
260   bool isThroughputPattern(MachineCombinerPattern Pattern) const override;
261   /// Return true when there is potentially a faster code sequence
262   /// for an instruction chain ending in ``Root``. All potential patterns are
263   /// listed in the ``Patterns`` array.
264   bool
265   getMachineCombinerPatterns(MachineInstr &Root,
266                              SmallVectorImpl<MachineCombinerPattern> &Patterns,
267                              bool DoRegPressureReduce) const override;
268   /// Return true when Inst is associative and commutative so that it can be
269   /// reassociated. If Invert is true, then the inverse of Inst operation must
270   /// be checked.
271   bool isAssociativeAndCommutative(const MachineInstr &Inst,
272                                    bool Invert) const override;
273   /// When getMachineCombinerPatterns() finds patterns, this function generates
274   /// the instructions that could replace the original code sequence
275   void genAlternativeCodeSequence(
276       MachineInstr &Root, MachineCombinerPattern Pattern,
277       SmallVectorImpl<MachineInstr *> &InsInstrs,
278       SmallVectorImpl<MachineInstr *> &DelInstrs,
279       DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) const override;
280   /// AArch64 supports MachineCombiner.
281   bool useMachineCombiner() const override;
282 
283   bool expandPostRAPseudo(MachineInstr &MI) const override;
284 
285   std::pair<unsigned, unsigned>
286   decomposeMachineOperandsTargetFlags(unsigned TF) const override;
287   ArrayRef<std::pair<unsigned, const char *>>
288   getSerializableDirectMachineOperandTargetFlags() const override;
289   ArrayRef<std::pair<unsigned, const char *>>
290   getSerializableBitmaskMachineOperandTargetFlags() const override;
291   ArrayRef<std::pair<MachineMemOperand::Flags, const char *>>
292   getSerializableMachineMemOperandTargetFlags() const override;
293 
294   bool isFunctionSafeToOutlineFrom(MachineFunction &MF,
295                                    bool OutlineFromLinkOnceODRs) const override;
296   std::optional<outliner::OutlinedFunction> getOutliningCandidateInfo(
297       std::vector<outliner::Candidate> &RepeatedSequenceLocs) const override;
298   outliner::InstrType
299   getOutliningTypeImpl(MachineBasicBlock::iterator &MIT, unsigned Flags) const override;
300   SmallVector<
301       std::pair<MachineBasicBlock::iterator, MachineBasicBlock::iterator>>
302   getOutlinableRanges(MachineBasicBlock &MBB, unsigned &Flags) const override;
303   void buildOutlinedFrame(MachineBasicBlock &MBB, MachineFunction &MF,
304                           const outliner::OutlinedFunction &OF) const override;
305   MachineBasicBlock::iterator
306   insertOutlinedCall(Module &M, MachineBasicBlock &MBB,
307                      MachineBasicBlock::iterator &It, MachineFunction &MF,
308                      outliner::Candidate &C) const override;
309   bool shouldOutlineFromFunctionByDefault(MachineFunction &MF) const override;
310   /// Returns the vector element size (B, H, S or D) of an SVE opcode.
311   uint64_t getElementSizeForOpcode(unsigned Opc) const;
312   /// Returns true if the opcode is for an SVE instruction that sets the
313   /// condition codes as if it's results had been fed to a PTEST instruction
314   /// along with the same general predicate.
315   bool isPTestLikeOpcode(unsigned Opc) const;
316   /// Returns true if the opcode is for an SVE WHILE## instruction.
317   bool isWhileOpcode(unsigned Opc) const;
318   /// Returns true if the instruction has a shift by immediate that can be
319   /// executed in one cycle less.
320   static bool isFalkorShiftExtFast(const MachineInstr &MI);
321   /// Return true if the instructions is a SEH instruciton used for unwinding
322   /// on Windows.
323   static bool isSEHInstruction(const MachineInstr &MI);
324 
325   std::optional<RegImmPair> isAddImmediate(const MachineInstr &MI,
326                                            Register Reg) const override;
327 
328   std::optional<ParamLoadedValue>
329   describeLoadedValue(const MachineInstr &MI, Register Reg) const override;
330 
331   unsigned int getTailDuplicateSize(CodeGenOpt::Level OptLevel) const override;
332 
333   bool isExtendLikelyToBeFolded(MachineInstr &ExtMI,
334                                 MachineRegisterInfo &MRI) const override;
335 
336   static void decomposeStackOffsetForFrameOffsets(const StackOffset &Offset,
337                                                   int64_t &NumBytes,
338                                                   int64_t &NumPredicateVectors,
339                                                   int64_t &NumDataVectors);
340   static void decomposeStackOffsetForDwarfOffsets(const StackOffset &Offset,
341                                                   int64_t &ByteSized,
342                                                   int64_t &VGSized);
343 #define GET_INSTRINFO_HELPER_DECLS
344 #include "AArch64GenInstrInfo.inc"
345 
346 protected:
347   /// If the specific machine instruction is an instruction that moves/copies
348   /// value from one register to another register return destination and source
349   /// registers as machine operands.
350   std::optional<DestSourcePair>
351   isCopyInstrImpl(const MachineInstr &MI) const override;
352 
353 private:
354   unsigned getInstBundleLength(const MachineInstr &MI) const;
355 
356   /// Sets the offsets on outlined instructions in \p MBB which use SP
357   /// so that they will be valid post-outlining.
358   ///
359   /// \param MBB A \p MachineBasicBlock in an outlined function.
360   void fixupPostOutline(MachineBasicBlock &MBB) const;
361 
362   void instantiateCondBranch(MachineBasicBlock &MBB, const DebugLoc &DL,
363                              MachineBasicBlock *TBB,
364                              ArrayRef<MachineOperand> Cond) const;
365   bool substituteCmpToZero(MachineInstr &CmpInstr, unsigned SrcReg,
366                            const MachineRegisterInfo &MRI) const;
367   bool removeCmpToZeroOrOne(MachineInstr &CmpInstr, unsigned SrcReg,
368                             int CmpValue, const MachineRegisterInfo &MRI) const;
369 
370   /// Returns an unused general-purpose register which can be used for
371   /// constructing an outlined call if one exists. Returns 0 otherwise.
372   Register findRegisterToSaveLRTo(outliner::Candidate &C) const;
373 
374   /// Remove a ptest of a predicate-generating operation that already sets, or
375   /// can be made to set, the condition codes in an identical manner
376   bool optimizePTestInstr(MachineInstr *PTest, unsigned MaskReg,
377                           unsigned PredReg,
378                           const MachineRegisterInfo *MRI) const;
379 };
380 
381 struct UsedNZCV {
382   bool N = false;
383   bool Z = false;
384   bool C = false;
385   bool V = false;
386 
387   UsedNZCV() = default;
388 
389   UsedNZCV &operator|=(const UsedNZCV &UsedFlags) {
390     this->N |= UsedFlags.N;
391     this->Z |= UsedFlags.Z;
392     this->C |= UsedFlags.C;
393     this->V |= UsedFlags.V;
394     return *this;
395   }
396 };
397 
398 /// \returns Conditions flags used after \p CmpInstr in its MachineBB if  NZCV
399 /// flags are not alive in successors of the same \p CmpInstr and \p MI parent.
400 /// \returns std::nullopt otherwise.
401 ///
402 /// Collect instructions using that flags in \p CCUseInstrs if provided.
403 std::optional<UsedNZCV>
404 examineCFlagsUse(MachineInstr &MI, MachineInstr &CmpInstr,
405                  const TargetRegisterInfo &TRI,
406                  SmallVectorImpl<MachineInstr *> *CCUseInstrs = nullptr);
407 
408 /// Return true if there is an instruction /after/ \p DefMI and before \p UseMI
409 /// which either reads or clobbers NZCV.
410 bool isNZCVTouchedInInstructionRange(const MachineInstr &DefMI,
411                                      const MachineInstr &UseMI,
412                                      const TargetRegisterInfo *TRI);
413 
414 MCCFIInstruction createDefCFA(const TargetRegisterInfo &TRI, unsigned FrameReg,
415                               unsigned Reg, const StackOffset &Offset,
416                               bool LastAdjustmentWasScalable = true);
417 MCCFIInstruction createCFAOffset(const TargetRegisterInfo &MRI, unsigned Reg,
418                                  const StackOffset &OffsetFromDefCFA);
419 
420 /// emitFrameOffset - Emit instructions as needed to set DestReg to SrcReg
421 /// plus Offset.  This is intended to be used from within the prolog/epilog
422 /// insertion (PEI) pass, where a virtual scratch register may be allocated
423 /// if necessary, to be replaced by the scavenger at the end of PEI.
424 void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
425                      const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
426                      StackOffset Offset, const TargetInstrInfo *TII,
427                      MachineInstr::MIFlag = MachineInstr::NoFlags,
428                      bool SetNZCV = false, bool NeedsWinCFI = false,
429                      bool *HasWinCFI = nullptr, bool EmitCFAOffset = false,
430                      StackOffset InitialOffset = {},
431                      unsigned FrameReg = AArch64::SP);
432 
433 /// rewriteAArch64FrameIndex - Rewrite MI to access 'Offset' bytes from the
434 /// FP. Return false if the offset could not be handled directly in MI, and
435 /// return the left-over portion by reference.
436 bool rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
437                               unsigned FrameReg, StackOffset &Offset,
438                               const AArch64InstrInfo *TII);
439 
440 /// Use to report the frame offset status in isAArch64FrameOffsetLegal.
441 enum AArch64FrameOffsetStatus {
442   AArch64FrameOffsetCannotUpdate = 0x0, ///< Offset cannot apply.
443   AArch64FrameOffsetIsLegal = 0x1,      ///< Offset is legal.
444   AArch64FrameOffsetCanUpdate = 0x2     ///< Offset can apply, at least partly.
445 };
446 
447 /// Check if the @p Offset is a valid frame offset for @p MI.
448 /// The returned value reports the validity of the frame offset for @p MI.
449 /// It uses the values defined by AArch64FrameOffsetStatus for that.
450 /// If result == AArch64FrameOffsetCannotUpdate, @p MI cannot be updated to
451 /// use an offset.eq
452 /// If result & AArch64FrameOffsetIsLegal, @p Offset can completely be
453 /// rewritten in @p MI.
454 /// If result & AArch64FrameOffsetCanUpdate, @p Offset contains the
455 /// amount that is off the limit of the legal offset.
456 /// If set, @p OutUseUnscaledOp will contain the whether @p MI should be
457 /// turned into an unscaled operator, which opcode is in @p OutUnscaledOp.
458 /// If set, @p EmittableOffset contains the amount that can be set in @p MI
459 /// (possibly with @p OutUnscaledOp if OutUseUnscaledOp is true) and that
460 /// is a legal offset.
461 int isAArch64FrameOffsetLegal(const MachineInstr &MI, StackOffset &Offset,
462                               bool *OutUseUnscaledOp = nullptr,
463                               unsigned *OutUnscaledOp = nullptr,
464                               int64_t *EmittableOffset = nullptr);
465 
466 static inline bool isUncondBranchOpcode(int Opc) { return Opc == AArch64::B; }
467 
468 static inline bool isCondBranchOpcode(int Opc) {
469   switch (Opc) {
470   case AArch64::Bcc:
471   case AArch64::CBZW:
472   case AArch64::CBZX:
473   case AArch64::CBNZW:
474   case AArch64::CBNZX:
475   case AArch64::TBZW:
476   case AArch64::TBZX:
477   case AArch64::TBNZW:
478   case AArch64::TBNZX:
479     return true;
480   default:
481     return false;
482   }
483 }
484 
485 static inline bool isIndirectBranchOpcode(int Opc) {
486   switch (Opc) {
487   case AArch64::BR:
488   case AArch64::BRAA:
489   case AArch64::BRAB:
490   case AArch64::BRAAZ:
491   case AArch64::BRABZ:
492     return true;
493   }
494   return false;
495 }
496 
497 static inline bool isPTrueOpcode(unsigned Opc) {
498   switch (Opc) {
499   case AArch64::PTRUE_B:
500   case AArch64::PTRUE_H:
501   case AArch64::PTRUE_S:
502   case AArch64::PTRUE_D:
503     return true;
504   default:
505     return false;
506   }
507 }
508 
509 /// Return opcode to be used for indirect calls.
510 unsigned getBLRCallOpcode(const MachineFunction &MF);
511 
512 /// Return XPAC opcode to be used for a ptrauth strip using the given key.
513 static inline unsigned getXPACOpcodeForKey(AArch64PACKey::ID K) {
514   using namespace AArch64PACKey;
515   switch (K) {
516   case IA: case IB: return AArch64::XPACI;
517   case DA: case DB: return AArch64::XPACD;
518   }
519   llvm_unreachable("Unhandled AArch64PACKey::ID enum");
520 }
521 
522 /// Return AUT opcode to be used for a ptrauth auth using the given key, or its
523 /// AUT*Z variant that doesn't take a discriminator operand, using zero instead.
524 static inline unsigned getAUTOpcodeForKey(AArch64PACKey::ID K, bool Zero) {
525   using namespace AArch64PACKey;
526   switch (K) {
527   case IA: return Zero ? AArch64::AUTIZA : AArch64::AUTIA;
528   case IB: return Zero ? AArch64::AUTIZB : AArch64::AUTIB;
529   case DA: return Zero ? AArch64::AUTDZA : AArch64::AUTDA;
530   case DB: return Zero ? AArch64::AUTDZB : AArch64::AUTDB;
531   }
532 }
533 
534 /// Return PAC opcode to be used for a ptrauth sign using the given key, or its
535 /// PAC*Z variant that doesn't take a discriminator operand, using zero instead.
536 static inline unsigned getPACOpcodeForKey(AArch64PACKey::ID K, bool Zero) {
537   using namespace AArch64PACKey;
538   switch (K) {
539   case IA: return Zero ? AArch64::PACIZA : AArch64::PACIA;
540   case IB: return Zero ? AArch64::PACIZB : AArch64::PACIB;
541   case DA: return Zero ? AArch64::PACDZA : AArch64::PACDA;
542   case DB: return Zero ? AArch64::PACDZB : AArch64::PACDB;
543   }
544 }
545 
546 // struct TSFlags {
547 #define TSFLAG_ELEMENT_SIZE_TYPE(X)      (X)        // 3-bits
548 #define TSFLAG_DESTRUCTIVE_INST_TYPE(X) ((X) << 3)  // 4-bits
549 #define TSFLAG_FALSE_LANE_TYPE(X)       ((X) << 7)  // 2-bits
550 #define TSFLAG_INSTR_FLAGS(X)           ((X) << 9)  // 2-bits
551 #define TSFLAG_SME_MATRIX_TYPE(X)       ((X) << 11) // 3-bits
552 // }
553 
554 namespace AArch64 {
555 
556 enum ElementSizeType {
557   ElementSizeMask = TSFLAG_ELEMENT_SIZE_TYPE(0x7),
558   ElementSizeNone = TSFLAG_ELEMENT_SIZE_TYPE(0x0),
559   ElementSizeB    = TSFLAG_ELEMENT_SIZE_TYPE(0x1),
560   ElementSizeH    = TSFLAG_ELEMENT_SIZE_TYPE(0x2),
561   ElementSizeS    = TSFLAG_ELEMENT_SIZE_TYPE(0x3),
562   ElementSizeD    = TSFLAG_ELEMENT_SIZE_TYPE(0x4),
563 };
564 
565 enum DestructiveInstType {
566   DestructiveInstTypeMask       = TSFLAG_DESTRUCTIVE_INST_TYPE(0xf),
567   NotDestructive                = TSFLAG_DESTRUCTIVE_INST_TYPE(0x0),
568   DestructiveOther              = TSFLAG_DESTRUCTIVE_INST_TYPE(0x1),
569   DestructiveUnary              = TSFLAG_DESTRUCTIVE_INST_TYPE(0x2),
570   DestructiveBinaryImm          = TSFLAG_DESTRUCTIVE_INST_TYPE(0x3),
571   DestructiveBinaryShImmUnpred  = TSFLAG_DESTRUCTIVE_INST_TYPE(0x4),
572   DestructiveBinary             = TSFLAG_DESTRUCTIVE_INST_TYPE(0x5),
573   DestructiveBinaryComm         = TSFLAG_DESTRUCTIVE_INST_TYPE(0x6),
574   DestructiveBinaryCommWithRev  = TSFLAG_DESTRUCTIVE_INST_TYPE(0x7),
575   DestructiveTernaryCommWithRev = TSFLAG_DESTRUCTIVE_INST_TYPE(0x8),
576   DestructiveUnaryPassthru      = TSFLAG_DESTRUCTIVE_INST_TYPE(0x9),
577 };
578 
579 enum FalseLaneType {
580   FalseLanesMask  = TSFLAG_FALSE_LANE_TYPE(0x3),
581   FalseLanesZero  = TSFLAG_FALSE_LANE_TYPE(0x1),
582   FalseLanesUndef = TSFLAG_FALSE_LANE_TYPE(0x2),
583 };
584 
585 // NOTE: This is a bit field.
586 static const uint64_t InstrFlagIsWhile     = TSFLAG_INSTR_FLAGS(0x1);
587 static const uint64_t InstrFlagIsPTestLike = TSFLAG_INSTR_FLAGS(0x2);
588 
589 enum SMEMatrixType {
590   SMEMatrixTypeMask = TSFLAG_SME_MATRIX_TYPE(0x7),
591   SMEMatrixNone     = TSFLAG_SME_MATRIX_TYPE(0x0),
592   SMEMatrixTileB    = TSFLAG_SME_MATRIX_TYPE(0x1),
593   SMEMatrixTileH    = TSFLAG_SME_MATRIX_TYPE(0x2),
594   SMEMatrixTileS    = TSFLAG_SME_MATRIX_TYPE(0x3),
595   SMEMatrixTileD    = TSFLAG_SME_MATRIX_TYPE(0x4),
596   SMEMatrixTileQ    = TSFLAG_SME_MATRIX_TYPE(0x5),
597   SMEMatrixArray    = TSFLAG_SME_MATRIX_TYPE(0x6),
598 };
599 
600 #undef TSFLAG_ELEMENT_SIZE_TYPE
601 #undef TSFLAG_DESTRUCTIVE_INST_TYPE
602 #undef TSFLAG_FALSE_LANE_TYPE
603 #undef TSFLAG_INSTR_FLAGS
604 #undef TSFLAG_SME_MATRIX_TYPE
605 
606 int getSVEPseudoMap(uint16_t Opcode);
607 int getSVERevInstr(uint16_t Opcode);
608 int getSVENonRevInstr(uint16_t Opcode);
609 
610 int getSMEPseudoMap(uint16_t Opcode);
611 }
612 
613 } // end namespace llvm
614 
615 #endif
616