1 //=- AArch64MachineFunctionInfo.h - AArch64 machine function info -*- 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 declares AArch64-specific per-machine-function information. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEFUNCTIONINFO_H 14 #define LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEFUNCTIONINFO_H 15 16 #include "llvm/ADT/ArrayRef.h" 17 #include "llvm/ADT/SmallPtrSet.h" 18 #include "llvm/ADT/SmallVector.h" 19 #include "llvm/CodeGen/CallingConvLower.h" 20 #include "llvm/CodeGen/MIRYamlMapping.h" 21 #include "llvm/CodeGen/MachineFrameInfo.h" 22 #include "llvm/CodeGen/MachineFunction.h" 23 #include "llvm/IR/Function.h" 24 #include "llvm/MC/MCLinkerOptimizationHint.h" 25 #include "llvm/MC/MCSymbol.h" 26 #include <cassert> 27 #include <optional> 28 29 namespace llvm { 30 31 namespace yaml { 32 struct AArch64FunctionInfo; 33 } // end namespace yaml 34 35 class AArch64Subtarget; 36 class MachineInstr; 37 38 /// AArch64FunctionInfo - This class is derived from MachineFunctionInfo and 39 /// contains private AArch64-specific information for each MachineFunction. 40 class AArch64FunctionInfo final : public MachineFunctionInfo { 41 /// Number of bytes of arguments this function has on the stack. If the callee 42 /// is expected to restore the argument stack this should be a multiple of 16, 43 /// all usable during a tail call. 44 /// 45 /// The alternative would forbid tail call optimisation in some cases: if we 46 /// want to transfer control from a function with 8-bytes of stack-argument 47 /// space to a function with 16-bytes then misalignment of this value would 48 /// make a stack adjustment necessary, which could not be undone by the 49 /// callee. 50 unsigned BytesInStackArgArea = 0; 51 52 /// The number of bytes to restore to deallocate space for incoming 53 /// arguments. Canonically 0 in the C calling convention, but non-zero when 54 /// callee is expected to pop the args. 55 unsigned ArgumentStackToRestore = 0; 56 57 /// Space just below incoming stack pointer reserved for arguments being 58 /// passed on the stack during a tail call. This will be the difference 59 /// between the largest tail call argument space needed in this function and 60 /// what's already available by reusing space of incoming arguments. 61 unsigned TailCallReservedStack = 0; 62 63 /// HasStackFrame - True if this function has a stack frame. Set by 64 /// determineCalleeSaves(). 65 bool HasStackFrame = false; 66 67 /// Amount of stack frame size, not including callee-saved registers. 68 uint64_t LocalStackSize = 0; 69 70 /// The start and end frame indices for the SVE callee saves. 71 int MinSVECSFrameIndex = 0; 72 int MaxSVECSFrameIndex = 0; 73 74 /// Amount of stack frame size used for saving callee-saved registers. 75 unsigned CalleeSavedStackSize = 0; 76 unsigned SVECalleeSavedStackSize = 0; 77 bool HasCalleeSavedStackSize = false; 78 79 /// Number of TLS accesses using the special (combinable) 80 /// _TLS_MODULE_BASE_ symbol. 81 unsigned NumLocalDynamicTLSAccesses = 0; 82 83 /// FrameIndex for start of varargs area for arguments passed on the 84 /// stack. 85 int VarArgsStackIndex = 0; 86 87 /// Offset of start of varargs area for arguments passed on the stack. 88 unsigned VarArgsStackOffset = 0; 89 90 /// FrameIndex for start of varargs area for arguments passed in 91 /// general purpose registers. 92 int VarArgsGPRIndex = 0; 93 94 /// Size of the varargs area for arguments passed in general purpose 95 /// registers. 96 unsigned VarArgsGPRSize = 0; 97 98 /// FrameIndex for start of varargs area for arguments passed in 99 /// floating-point registers. 100 int VarArgsFPRIndex = 0; 101 102 /// Size of the varargs area for arguments passed in floating-point 103 /// registers. 104 unsigned VarArgsFPRSize = 0; 105 106 /// True if this function has a subset of CSRs that is handled explicitly via 107 /// copies. 108 bool IsSplitCSR = false; 109 110 /// True when the stack gets realigned dynamically because the size of stack 111 /// frame is unknown at compile time. e.g., in case of VLAs. 112 bool StackRealigned = false; 113 114 /// True when the callee-save stack area has unused gaps that may be used for 115 /// other stack allocations. 116 bool CalleeSaveStackHasFreeSpace = false; 117 118 /// SRetReturnReg - sret lowering includes returning the value of the 119 /// returned struct in a register. This field holds the virtual register into 120 /// which the sret argument is passed. 121 Register SRetReturnReg; 122 123 /// SVE stack size (for predicates and data vectors) are maintained here 124 /// rather than in FrameInfo, as the placement and Stack IDs are target 125 /// specific. 126 uint64_t StackSizeSVE = 0; 127 128 /// HasCalculatedStackSizeSVE indicates whether StackSizeSVE is valid. 129 bool HasCalculatedStackSizeSVE = false; 130 131 /// Has a value when it is known whether or not the function uses a 132 /// redzone, and no value otherwise. 133 /// Initialized during frame lowering, unless the function has the noredzone 134 /// attribute, in which case it is set to false at construction. 135 std::optional<bool> HasRedZone; 136 137 /// ForwardedMustTailRegParms - A list of virtual and physical registers 138 /// that must be forwarded to every musttail call. 139 SmallVector<ForwardedRegister, 1> ForwardedMustTailRegParms; 140 141 /// FrameIndex for the tagged base pointer. 142 std::optional<int> TaggedBasePointerIndex; 143 144 /// Offset from SP-at-entry to the tagged base pointer. 145 /// Tagged base pointer is set up to point to the first (lowest address) 146 /// tagged stack slot. 147 unsigned TaggedBasePointerOffset; 148 149 /// OutliningStyle denotes, if a function was outined, how it was outlined, 150 /// e.g. Tail Call, Thunk, or Function if none apply. 151 std::optional<std::string> OutliningStyle; 152 153 // Offset from SP-after-callee-saved-spills (i.e. SP-at-entry minus 154 // CalleeSavedStackSize) to the address of the frame record. 155 int CalleeSaveBaseToFrameRecordOffset = 0; 156 157 /// SignReturnAddress is true if PAC-RET is enabled for the function with 158 /// defaults being sign non-leaf functions only, with the B key. 159 bool SignReturnAddress = false; 160 161 /// SignReturnAddressAll modifies the default PAC-RET mode to signing leaf 162 /// functions as well. 163 bool SignReturnAddressAll = false; 164 165 /// SignWithBKey modifies the default PAC-RET mode to signing with the B key. 166 bool SignWithBKey = false; 167 168 /// SigningInstrOffset captures the offset of the PAC-RET signing instruction 169 /// within the prologue, so it can be re-used for authentication in the 170 /// epilogue when using PC as a second salt (FEAT_PAuth_LR) 171 MCSymbol *SignInstrLabel = nullptr; 172 173 /// BranchTargetEnforcement enables placing BTI instructions at potential 174 /// indirect branch destinations. 175 bool BranchTargetEnforcement = false; 176 177 /// Indicates that SP signing should be diversified with PC as-per PAuthLR. 178 /// This is set by -mbranch-protection and will emit NOP instructions unless 179 /// the subtarget feature +pauthlr is also used (in which case non-NOP 180 /// instructions are emitted). 181 bool BranchProtectionPAuthLR = false; 182 183 /// Whether this function has an extended frame record [Ctx, FP, LR]. If so, 184 /// bit 60 of the in-memory FP will be 1 to enable other tools to detect the 185 /// extended record. 186 bool HasSwiftAsyncContext = false; 187 188 /// The stack slot where the Swift asynchronous context is stored. 189 int SwiftAsyncContextFrameIdx = std::numeric_limits<int>::max(); 190 191 bool IsMTETagged = false; 192 193 /// The function has Scalable Vector or Scalable Predicate register argument 194 /// or return type 195 bool IsSVECC = false; 196 197 /// The frame-index for the TPIDR2 object used for lazy saves. 198 Register LazySaveTPIDR2Obj = 0; 199 200 /// Whether this function changes streaming mode within the function. 201 bool HasStreamingModeChanges = false; 202 203 /// True if the function need unwind information. 204 mutable std::optional<bool> NeedsDwarfUnwindInfo; 205 206 /// True if the function need asynchronous unwind information. 207 mutable std::optional<bool> NeedsAsyncDwarfUnwindInfo; 208 209 int64_t StackProbeSize = 0; 210 211 // Holds a register containing pstate.sm. This is set 212 // on function entry to record the initial pstate of a function. 213 Register PStateSMReg = MCRegister::NoRegister; 214 215 public: 216 AArch64FunctionInfo(const Function &F, const AArch64Subtarget *STI); 217 218 MachineFunctionInfo * 219 clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF, 220 const DenseMap<MachineBasicBlock *, MachineBasicBlock *> &Src2DstMBB) 221 const override; 222 223 Register getPStateSMReg() const { return PStateSMReg; }; 224 void setPStateSMReg(Register Reg) { PStateSMReg = Reg; }; 225 226 bool isSVECC() const { return IsSVECC; }; 227 void setIsSVECC(bool s) { IsSVECC = s; }; 228 229 unsigned getLazySaveTPIDR2Obj() const { return LazySaveTPIDR2Obj; } 230 void setLazySaveTPIDR2Obj(unsigned Reg) { LazySaveTPIDR2Obj = Reg; } 231 232 void initializeBaseYamlFields(const yaml::AArch64FunctionInfo &YamlMFI); 233 234 unsigned getBytesInStackArgArea() const { return BytesInStackArgArea; } 235 void setBytesInStackArgArea(unsigned bytes) { BytesInStackArgArea = bytes; } 236 237 unsigned getArgumentStackToRestore() const { return ArgumentStackToRestore; } 238 void setArgumentStackToRestore(unsigned bytes) { 239 ArgumentStackToRestore = bytes; 240 } 241 242 unsigned getTailCallReservedStack() const { return TailCallReservedStack; } 243 void setTailCallReservedStack(unsigned bytes) { 244 TailCallReservedStack = bytes; 245 } 246 247 bool hasCalculatedStackSizeSVE() const { return HasCalculatedStackSizeSVE; } 248 249 void setStackSizeSVE(uint64_t S) { 250 HasCalculatedStackSizeSVE = true; 251 StackSizeSVE = S; 252 } 253 254 uint64_t getStackSizeSVE() const { return StackSizeSVE; } 255 256 bool hasStackFrame() const { return HasStackFrame; } 257 void setHasStackFrame(bool s) { HasStackFrame = s; } 258 259 bool isStackRealigned() const { return StackRealigned; } 260 void setStackRealigned(bool s) { StackRealigned = s; } 261 262 bool hasCalleeSaveStackFreeSpace() const { 263 return CalleeSaveStackHasFreeSpace; 264 } 265 void setCalleeSaveStackHasFreeSpace(bool s) { 266 CalleeSaveStackHasFreeSpace = s; 267 } 268 bool isSplitCSR() const { return IsSplitCSR; } 269 void setIsSplitCSR(bool s) { IsSplitCSR = s; } 270 271 void setLocalStackSize(uint64_t Size) { LocalStackSize = Size; } 272 uint64_t getLocalStackSize() const { return LocalStackSize; } 273 274 void setOutliningStyle(std::string Style) { OutliningStyle = Style; } 275 std::optional<std::string> getOutliningStyle() const { 276 return OutliningStyle; 277 } 278 279 void setCalleeSavedStackSize(unsigned Size) { 280 CalleeSavedStackSize = Size; 281 HasCalleeSavedStackSize = true; 282 } 283 284 // When CalleeSavedStackSize has not been set (for example when 285 // some MachineIR pass is run in isolation), then recalculate 286 // the CalleeSavedStackSize directly from the CalleeSavedInfo. 287 // Note: This information can only be recalculated after PEI 288 // has assigned offsets to the callee save objects. 289 unsigned getCalleeSavedStackSize(const MachineFrameInfo &MFI) const { 290 bool ValidateCalleeSavedStackSize = false; 291 292 #ifndef NDEBUG 293 // Make sure the calculated size derived from the CalleeSavedInfo 294 // equals the cached size that was calculated elsewhere (e.g. in 295 // determineCalleeSaves). 296 ValidateCalleeSavedStackSize = HasCalleeSavedStackSize; 297 #endif 298 299 if (!HasCalleeSavedStackSize || ValidateCalleeSavedStackSize) { 300 assert(MFI.isCalleeSavedInfoValid() && "CalleeSavedInfo not calculated"); 301 if (MFI.getCalleeSavedInfo().empty()) 302 return 0; 303 304 int64_t MinOffset = std::numeric_limits<int64_t>::max(); 305 int64_t MaxOffset = std::numeric_limits<int64_t>::min(); 306 for (const auto &Info : MFI.getCalleeSavedInfo()) { 307 int FrameIdx = Info.getFrameIdx(); 308 if (MFI.getStackID(FrameIdx) != TargetStackID::Default) 309 continue; 310 int64_t Offset = MFI.getObjectOffset(FrameIdx); 311 int64_t ObjSize = MFI.getObjectSize(FrameIdx); 312 MinOffset = std::min<int64_t>(Offset, MinOffset); 313 MaxOffset = std::max<int64_t>(Offset + ObjSize, MaxOffset); 314 } 315 316 if (SwiftAsyncContextFrameIdx != std::numeric_limits<int>::max()) { 317 int64_t Offset = MFI.getObjectOffset(getSwiftAsyncContextFrameIdx()); 318 int64_t ObjSize = MFI.getObjectSize(getSwiftAsyncContextFrameIdx()); 319 MinOffset = std::min<int64_t>(Offset, MinOffset); 320 MaxOffset = std::max<int64_t>(Offset + ObjSize, MaxOffset); 321 } 322 323 unsigned Size = alignTo(MaxOffset - MinOffset, 16); 324 assert((!HasCalleeSavedStackSize || getCalleeSavedStackSize() == Size) && 325 "Invalid size calculated for callee saves"); 326 return Size; 327 } 328 329 return getCalleeSavedStackSize(); 330 } 331 332 unsigned getCalleeSavedStackSize() const { 333 assert(HasCalleeSavedStackSize && 334 "CalleeSavedStackSize has not been calculated"); 335 return CalleeSavedStackSize; 336 } 337 338 // Saves the CalleeSavedStackSize for SVE vectors in 'scalable bytes' 339 void setSVECalleeSavedStackSize(unsigned Size) { 340 SVECalleeSavedStackSize = Size; 341 } 342 unsigned getSVECalleeSavedStackSize() const { 343 return SVECalleeSavedStackSize; 344 } 345 346 void setMinMaxSVECSFrameIndex(int Min, int Max) { 347 MinSVECSFrameIndex = Min; 348 MaxSVECSFrameIndex = Max; 349 } 350 351 int getMinSVECSFrameIndex() const { return MinSVECSFrameIndex; } 352 int getMaxSVECSFrameIndex() const { return MaxSVECSFrameIndex; } 353 354 void incNumLocalDynamicTLSAccesses() { ++NumLocalDynamicTLSAccesses; } 355 unsigned getNumLocalDynamicTLSAccesses() const { 356 return NumLocalDynamicTLSAccesses; 357 } 358 359 std::optional<bool> hasRedZone() const { return HasRedZone; } 360 void setHasRedZone(bool s) { HasRedZone = s; } 361 362 int getVarArgsStackIndex() const { return VarArgsStackIndex; } 363 void setVarArgsStackIndex(int Index) { VarArgsStackIndex = Index; } 364 365 unsigned getVarArgsStackOffset() const { return VarArgsStackOffset; } 366 void setVarArgsStackOffset(unsigned Offset) { VarArgsStackOffset = Offset; } 367 368 int getVarArgsGPRIndex() const { return VarArgsGPRIndex; } 369 void setVarArgsGPRIndex(int Index) { VarArgsGPRIndex = Index; } 370 371 unsigned getVarArgsGPRSize() const { return VarArgsGPRSize; } 372 void setVarArgsGPRSize(unsigned Size) { VarArgsGPRSize = Size; } 373 374 int getVarArgsFPRIndex() const { return VarArgsFPRIndex; } 375 void setVarArgsFPRIndex(int Index) { VarArgsFPRIndex = Index; } 376 377 unsigned getVarArgsFPRSize() const { return VarArgsFPRSize; } 378 void setVarArgsFPRSize(unsigned Size) { VarArgsFPRSize = Size; } 379 380 unsigned getSRetReturnReg() const { return SRetReturnReg; } 381 void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; } 382 383 unsigned getJumpTableEntrySize(int Idx) const { 384 return JumpTableEntryInfo[Idx].first; 385 } 386 MCSymbol *getJumpTableEntryPCRelSymbol(int Idx) const { 387 return JumpTableEntryInfo[Idx].second; 388 } 389 void setJumpTableEntryInfo(int Idx, unsigned Size, MCSymbol *PCRelSym) { 390 if ((unsigned)Idx >= JumpTableEntryInfo.size()) 391 JumpTableEntryInfo.resize(Idx+1); 392 JumpTableEntryInfo[Idx] = std::make_pair(Size, PCRelSym); 393 } 394 395 using SetOfInstructions = SmallPtrSet<const MachineInstr *, 16>; 396 397 const SetOfInstructions &getLOHRelated() const { return LOHRelated; } 398 399 // Shortcuts for LOH related types. 400 class MILOHDirective { 401 MCLOHType Kind; 402 403 /// Arguments of this directive. Order matters. 404 SmallVector<const MachineInstr *, 3> Args; 405 406 public: 407 using LOHArgs = ArrayRef<const MachineInstr *>; 408 409 MILOHDirective(MCLOHType Kind, LOHArgs Args) 410 : Kind(Kind), Args(Args.begin(), Args.end()) { 411 assert(isValidMCLOHType(Kind) && "Invalid LOH directive type!"); 412 } 413 414 MCLOHType getKind() const { return Kind; } 415 LOHArgs getArgs() const { return Args; } 416 }; 417 418 using MILOHArgs = MILOHDirective::LOHArgs; 419 using MILOHContainer = SmallVector<MILOHDirective, 32>; 420 421 const MILOHContainer &getLOHContainer() const { return LOHContainerSet; } 422 423 /// Add a LOH directive of this @p Kind and this @p Args. 424 void addLOHDirective(MCLOHType Kind, MILOHArgs Args) { 425 LOHContainerSet.push_back(MILOHDirective(Kind, Args)); 426 LOHRelated.insert(Args.begin(), Args.end()); 427 } 428 429 SmallVectorImpl<ForwardedRegister> &getForwardedMustTailRegParms() { 430 return ForwardedMustTailRegParms; 431 } 432 433 std::optional<int> getTaggedBasePointerIndex() const { 434 return TaggedBasePointerIndex; 435 } 436 void setTaggedBasePointerIndex(int Index) { TaggedBasePointerIndex = Index; } 437 438 unsigned getTaggedBasePointerOffset() const { 439 return TaggedBasePointerOffset; 440 } 441 void setTaggedBasePointerOffset(unsigned Offset) { 442 TaggedBasePointerOffset = Offset; 443 } 444 445 int getCalleeSaveBaseToFrameRecordOffset() const { 446 return CalleeSaveBaseToFrameRecordOffset; 447 } 448 void setCalleeSaveBaseToFrameRecordOffset(int Offset) { 449 CalleeSaveBaseToFrameRecordOffset = Offset; 450 } 451 452 bool shouldSignReturnAddress(const MachineFunction &MF) const; 453 bool shouldSignReturnAddress(bool SpillsLR) const; 454 455 bool needsShadowCallStackPrologueEpilogue(MachineFunction &MF) const; 456 457 bool shouldSignWithBKey() const { return SignWithBKey; } 458 459 MCSymbol *getSigningInstrLabel() const { return SignInstrLabel; } 460 void setSigningInstrLabel(MCSymbol *Label) { SignInstrLabel = Label; } 461 462 bool isMTETagged() const { return IsMTETagged; } 463 464 bool branchTargetEnforcement() const { return BranchTargetEnforcement; } 465 466 bool branchProtectionPAuthLR() const { return BranchProtectionPAuthLR; } 467 468 void setHasSwiftAsyncContext(bool HasContext) { 469 HasSwiftAsyncContext = HasContext; 470 } 471 bool hasSwiftAsyncContext() const { return HasSwiftAsyncContext; } 472 473 void setSwiftAsyncContextFrameIdx(int FI) { 474 SwiftAsyncContextFrameIdx = FI; 475 } 476 int getSwiftAsyncContextFrameIdx() const { return SwiftAsyncContextFrameIdx; } 477 478 bool needsDwarfUnwindInfo(const MachineFunction &MF) const; 479 bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const; 480 481 bool hasStreamingModeChanges() const { return HasStreamingModeChanges; } 482 void setHasStreamingModeChanges(bool HasChanges) { 483 HasStreamingModeChanges = HasChanges; 484 } 485 486 bool hasStackProbing() const { return StackProbeSize != 0; } 487 488 int64_t getStackProbeSize() const { return StackProbeSize; } 489 490 private: 491 // Hold the lists of LOHs. 492 MILOHContainer LOHContainerSet; 493 SetOfInstructions LOHRelated; 494 495 SmallVector<std::pair<unsigned, MCSymbol *>, 2> JumpTableEntryInfo; 496 }; 497 498 namespace yaml { 499 struct AArch64FunctionInfo final : public yaml::MachineFunctionInfo { 500 std::optional<bool> HasRedZone; 501 502 AArch64FunctionInfo() = default; 503 AArch64FunctionInfo(const llvm::AArch64FunctionInfo &MFI); 504 505 void mappingImpl(yaml::IO &YamlIO) override; 506 ~AArch64FunctionInfo() = default; 507 }; 508 509 template <> struct MappingTraits<AArch64FunctionInfo> { 510 static void mapping(IO &YamlIO, AArch64FunctionInfo &MFI) { 511 YamlIO.mapOptional("hasRedZone", MFI.HasRedZone); 512 } 513 }; 514 515 } // end namespace yaml 516 517 } // end namespace llvm 518 519 #endif // LLVM_LIB_TARGET_AARCH64_AARCH64MACHINEFUNCTIONINFO_H 520