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