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