// SPDX-License-Identifier: GPL-3.0-or-later #ifndef RCC_CODEGEN_MACHINEFRAMEINFO_H #define RCC_CODEGEN_MACHINEFRAMEINFO_H #include "rcc/CodeGen/MachineDebugInfo.h" #include "rcc/CodeGen/MachineIRTypes.h" #include "rcc/CodeGen/MachineMemOperand.h" #include "rcc/CodeGen/Register.h" #include "rcc/CodeGen/StableID.h" #include "rcc/Support/Error.h" #include #include #include #include #include #include #include #include namespace rcc { enum class StackObjectKind : std::uint8_t { Default, FixedABI, FixedSpillSlot, SpillSlot, VariableSized, DynamicAlloca, CalleeSaved, EmergencySpill, Target, Count, }; class StackID final { public: constexpr StackID() noexcept = default; [[nodiscard]] static constexpr StackID defaultStack() noexcept { return StackID(DefaultStackValue); } [[nodiscard]] static constexpr StackID sgprSpillStack() noexcept { return StackID(SGPRSpillStackValue); } [[nodiscard]] static constexpr StackID scalableVectorStack() noexcept { return StackID(ScalableVectorStackValue); } [[nodiscard]] static constexpr StackID wasmLocalStack() noexcept { return StackID(WasmLocalStackValue); } [[nodiscard]] static constexpr StackID scalablePredicateVectorStack() noexcept { return StackID(ScalablePredicateVectorStackValue); } [[nodiscard]] static constexpr StackID noAllocStack() noexcept { return StackID(NoAllocStackValue); } [[nodiscard]] static Expected fromValue(std::uint32_t Value); [[nodiscard]] constexpr std::uint32_t value() const noexcept { return Value; } [[nodiscard]] constexpr bool isSpecialStack() const noexcept { return Value != DefaultStackValue; } [[nodiscard]] constexpr bool isValid() const noexcept { return Value <= ScalablePredicateVectorStackValue || Value == NoAllocStackValue; } friend constexpr bool operator==(StackID Left, StackID Right) noexcept = default; private: static constexpr std::uint32_t DefaultStackValue = 0; static constexpr std::uint32_t SGPRSpillStackValue = 1; static constexpr std::uint32_t ScalableVectorStackValue = 2; static constexpr std::uint32_t WasmLocalStackValue = 3; static constexpr std::uint32_t ScalablePredicateVectorStackValue = 4; static constexpr std::uint32_t NoAllocStackValue = 255; explicit constexpr StackID(std::uint32_t Value) noexcept : Value(Value) {} std::uint32_t Value = DefaultStackValue; }; [[nodiscard]] std::optional parseStackIDName(std::string_view Name) noexcept; [[nodiscard]] std::string_view getStackIDName(StackID ID) noexcept; struct StackObjectLifetimeRange final { MachineInstrStableID Begin; MachineInstrStableID End; friend constexpr bool operator==(StackObjectLifetimeRange Left, StackObjectLifetimeRange Right) noexcept = default; }; struct StackObjectDesc final { StackObjectKind Kind = StackObjectKind::Default; std::optional AllocaName; std::optional Size; Alignment Align; std::optional Offset; StackID Stack; bool IsDead = false; bool IsImmutable = false; bool IsAliased = false; bool AddressTaken = false; std::optional CalleeSavedRegister; bool CalleeSavedRestored = true; std::optional LocalOffset; std::vector Lifetime; std::optional DebugInfo; std::uint64_t TargetFlags = 0; friend bool operator==(const StackObjectDesc &Left, const StackObjectDesc &Right) = default; }; class StackObject final { public: [[nodiscard]] FrameIndex index() const noexcept { return Index; } [[nodiscard]] bool isTombstone() const noexcept { return std::holds_alternative(Description); } [[nodiscard]] const StackObjectDesc *description() const noexcept { return std::get_if(&Description); } [[nodiscard]] bool isSpill() const noexcept; [[nodiscard]] bool isFixed() const noexcept; [[nodiscard]] bool isVariableSized() const noexcept; private: StackObject(FrameIndex Index, StackObjectDesc Description) : Index(Index), Description(std::move(Description)) {} FrameIndex Index; std::variant Description; friend class MachineFrameInfo; }; enum class MachineFramePointerPolicy : std::uint8_t { None, NonLeaf, All, Reserved, NonLeafNoReserve, Count, }; [[nodiscard]] std::optional parseMachineFramePointerPolicy(std::string_view Name) noexcept; [[nodiscard]] std::string_view getMachineFramePointerPolicyName(MachineFramePointerPolicy Policy) noexcept; struct MachineFrameSaveRestorePoint final { MachineBlockStableID Block; std::vector Registers; friend bool operator==(const MachineFrameSaveRestorePoint &Left, const MachineFrameSaveRestorePoint &Right) = default; }; struct MachineFrameState final { bool IsFrameAddressTaken = false; bool IsReturnAddressTaken = false; bool HasStackMap = false; bool HasPatchPoint = false; std::uint64_t StackSize = 0; std::int32_t OffsetAdjustment = 0; std::optional MaxAlignment; bool AdjustsStack = false; bool HasCalls = false; MachineFramePointerPolicy FramePointerPolicy = MachineFramePointerPolicy::None; std::optional StackProtector; std::optional FunctionContext; std::optional MaxCallFrameSize; std::uint32_t CVBytesOfCalleeSavedRegisters = 0; bool HasOpaqueSPAdjustment = false; bool HasVAStart = false; bool HasMustTailInVarArgFunc = false; bool HasTailCall = false; bool IsCalleeSavedInfoValid = false; std::uint32_t LocalFrameSize = 0; std::vector SavePoints; std::vector RestorePoints; friend bool operator==(const MachineFrameState &Left, const MachineFrameState &Right) = default; }; class MachineFrameInfo final { public: MachineFrameInfo() = default; MachineFrameInfo(const MachineFrameInfo &) = delete; MachineFrameInfo &operator=(const MachineFrameInfo &) = delete; MachineFrameInfo(MachineFrameInfo &&) noexcept = default; MachineFrameInfo &operator=(MachineFrameInfo &&) noexcept = default; ~MachineFrameInfo() = default; [[nodiscard]] Expected createObject(StackObjectDesc Description); [[nodiscard]] Expected updateObject(FrameIndex Index, StackObjectDesc Description); [[nodiscard]] Expected setObjectOffset(FrameIndex Index, std::int64_t Offset); [[nodiscard]] Expected markObjectDead(FrameIndex Index); [[nodiscard]] Expected eraseObject(FrameIndex Index); [[nodiscard]] const StackObject *object(FrameIndex Index) const noexcept; [[nodiscard]] std::span objects() const noexcept { return Objects; } [[nodiscard]] std::size_t liveObjectCount() const noexcept; [[nodiscard]] bool isFrozen() const noexcept { return Frozen; } [[nodiscard]] const MachineFrameState &state() const noexcept { return State; } [[nodiscard]] std::optional staticStackSize() const noexcept { if (!Frozen) return std::nullopt; return State.StackSize; } [[nodiscard]] Alignment stackAlignment() const noexcept { return State.MaxAlignment.value_or(Alignment{}); } [[nodiscard]] std::optional maxCallFrameSize() const noexcept { return State.MaxCallFrameSize; } [[nodiscard]] Expected setState(MachineFrameState NewState); [[nodiscard]] Expected setMaxCallFrameSize(std::uint64_t Size); [[nodiscard]] Expected clearMaxCallFrameSize(); [[nodiscard]] Expected freeze(std::uint64_t Size, Alignment Align); [[nodiscard]] Expected verify() const; private: [[nodiscard]] static Expected verifyDescription(const StackObjectDesc &Description); [[nodiscard]] static Expected verifyStateStructure(const MachineFrameState &State); [[nodiscard]] Expected mutableObject(FrameIndex Index); std::vector Objects; MachineFrameState State; bool Frozen = false; }; } // namespace rcc #endif // RCC_CODEGEN_MACHINEFRAMEINFO_H