From c9634fa9f529afbdf622a9cd96741bd09d14ef86 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sat, 1 Aug 2026 13:55:21 +0800 Subject: [CodeGen] Add MachineFrameInfo Model stable frame indices, stack object kinds, tombstones, lifetimes, and frozen layouts. Validate owned frame references in the builder and verifier, and remap complete frame state during MachineFunction cloning. --- backend/lib/CodeGen/CMakeLists.txt | 4 + backend/lib/CodeGen/MachineFrameInfo.cpp | 234 ++++++++++++++++++++++++++ backend/lib/CodeGen/MachineFunctionCloner.cpp | 85 +++++++++- backend/lib/CodeGen/MachineIRBuilder.cpp | 22 +++ backend/lib/CodeGen/MachineVerifier.cpp | 45 ++++- 5 files changed, 385 insertions(+), 5 deletions(-) create mode 100644 backend/lib/CodeGen/MachineFrameInfo.cpp (limited to 'backend/lib/CodeGen') diff --git a/backend/lib/CodeGen/CMakeLists.txt b/backend/lib/CodeGen/CMakeLists.txt index d19aaba..283727c 100644 --- a/backend/lib/CodeGen/CMakeLists.txt +++ b/backend/lib/CodeGen/CMakeLists.txt @@ -6,6 +6,7 @@ set( LowLevelType.cpp MachineBasicBlock.cpp MachineCFGUpdater.cpp + MachineFrameInfo.cpp MachineFunction.cpp MachineFunctionCloner.cpp MachineIRTypes.cpp @@ -25,6 +26,7 @@ set( "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/LowLevelType.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineBasicBlock.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineCFGUpdater.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFrameInfo.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFunction.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFunctionCloner.h" "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineIRTypes.h" @@ -73,6 +75,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/LowLevelType.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlock.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionCloner.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRTypes.cpp" @@ -92,6 +95,7 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/LowLevelType.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlock.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionCloner.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRTypes.cpp" diff --git a/backend/lib/CodeGen/MachineFrameInfo.cpp b/backend/lib/CodeGen/MachineFrameInfo.cpp new file mode 100644 index 0000000..58eab00 --- /dev/null +++ b/backend/lib/CodeGen/MachineFrameInfo.cpp @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachineFrameInfo.h" + +#include +#include +#include +#include +#include + +namespace rcc { + +Expected StackID::targetStack(std::uint32_t Value) { + if (Value < FirstTargetStackValue) { + return makeUnexpected(ErrorCode::InvalidArgument, + "target stack ID must not overlap a built-in stack ID"); + } + return StackID(Value); +} + +bool StackObject::isSpill() const noexcept { + const StackObjectDesc *Desc = description(); + if (Desc == nullptr) + return false; + return Desc->Kind == StackObjectKind::SpillSlot || Desc->Kind == StackObjectKind::CalleeSaved || + Desc->Kind == StackObjectKind::EmergencySpill; +} + +bool StackObject::isFixed() const noexcept { + const StackObjectDesc *Desc = description(); + return Desc != nullptr && Desc->Kind == StackObjectKind::FixedABI; +} + +bool StackObject::isVariableSized() const noexcept { + const StackObjectDesc *Desc = description(); + return Desc != nullptr && (Desc->Kind == StackObjectKind::VariableSized || + Desc->Kind == StackObjectKind::DynamicAlloca); +} + +Expected MachineFrameInfo::verifyDescription(const StackObjectDesc &Description) { + if (Description.Kind >= StackObjectKind::Count) + return makeUnexpected(ErrorCode::InvalidArgument, "stack object kind is invalid"); + if (!Description.Stack.isValid()) + return makeUnexpected(ErrorCode::InvalidArgument, "stack object has an invalid stack ID"); + + const bool IsVariable = Description.Kind == StackObjectKind::VariableSized || + Description.Kind == StackObjectKind::DynamicAlloca; + if (IsVariable) { + if (Description.Size || Description.Offset) { + return makeUnexpected(ErrorCode::InvalidArgument, + "variable-sized stack objects cannot have a fixed size or offset"); + } + } else if (!Description.Size || *Description.Size == 0) { + return makeUnexpected(ErrorCode::InvalidArgument, + "fixed-size stack objects require a nonzero size"); + } + + if (Description.Kind == StackObjectKind::FixedABI && !Description.Offset) { + return makeUnexpected(ErrorCode::InvalidArgument, + "fixed ABI stack objects require a fixed offset"); + } + if (Description.Kind == StackObjectKind::Target && !Description.Stack.isTargetStack() && + Description.TargetFlags == 0) { + return makeUnexpected(ErrorCode::InvalidArgument, + "target stack objects require a target stack ID or nonzero target flags"); + } + + std::unordered_set LifetimeBoundaries; + for (const StackObjectLifetimeRange &Range : Description.Lifetime) { + if (!Range.Begin.isValid() || !Range.End.isValid() || Range.Begin == Range.End) { + return makeUnexpected(ErrorCode::InvalidArgument, + "stack object lifetime boundaries must be valid and distinct"); + } + if (!LifetimeBoundaries.insert(Range.Begin).second || + !LifetimeBoundaries.insert(Range.End).second) { + return makeUnexpected(ErrorCode::InvalidArgument, + "stack object lifetime boundaries must not be reused"); + } + } + return {}; +} + +Expected MachineFrameInfo::createObject(StackObjectDesc Description) { + if (Frozen) + return makeUnexpected(ErrorCode::InvalidArgument, "frozen frame cannot create stack objects"); + auto DescriptionResult = verifyDescription(Description); + if (!DescriptionResult) + return std::unexpected(DescriptionResult.error()); + if (Objects.size() > std::numeric_limits::max()) { + return makeUnexpected(ErrorCode::Unsupported, "stack object index space is exhausted"); + } + + const FrameIndex Index = FrameIndex::fromValue(static_cast(Objects.size())); + Objects.push_back(StackObject(Index, std::move(Description))); + return Index; +} + +Expected MachineFrameInfo::mutableObject(FrameIndex Index) { + if (Frozen) + return makeUnexpected(ErrorCode::InvalidArgument, "frozen frame cannot modify stack objects"); + if (Index.value() >= Objects.size()) + return makeUnexpected(ErrorCode::InvalidArgument, "stack object index is out of range"); + StackObject &Object = Objects[Index.value()]; + if (Object.isTombstone()) + return makeUnexpected(ErrorCode::InvalidArgument, "stack object index is a tombstone"); + return &Object; +} + +Expected MachineFrameInfo::updateObject(FrameIndex Index, StackObjectDesc Description) { + auto DescriptionResult = verifyDescription(Description); + if (!DescriptionResult) + return std::unexpected(DescriptionResult.error()); + auto Object = mutableObject(Index); + if (!Object) + return std::unexpected(Object.error()); + (*Object)->Description.emplace(std::move(Description)); + return {}; +} + +Expected MachineFrameInfo::setObjectOffset(FrameIndex Index, std::int64_t Offset) { + auto Object = mutableObject(Index); + if (!Object) + return std::unexpected(Object.error()); + StackObjectDesc *CurrentDescription = std::get_if(&(*Object)->Description); + if (CurrentDescription == nullptr) { + return makeUnexpected(ErrorCode::InternalError, + "live stack object unexpectedly lacks a description"); + } + StackObjectDesc Description = *CurrentDescription; + if ((*Object)->isVariableSized()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "variable-sized stack object cannot have a fixed offset"); + } + Description.Offset = Offset; + (*Object)->Description.emplace(std::move(Description)); + return {}; +} + +Expected MachineFrameInfo::markObjectDead(FrameIndex Index) { + auto Object = mutableObject(Index); + if (!Object) + return std::unexpected(Object.error()); + StackObjectDesc *Description = std::get_if(&(*Object)->Description); + if (Description == nullptr) { + return makeUnexpected(ErrorCode::InternalError, + "live stack object unexpectedly lacks a description"); + } + Description->IsDead = true; + return {}; +} + +Expected MachineFrameInfo::eraseObject(FrameIndex Index) { + auto Object = mutableObject(Index); + if (!Object) + return std::unexpected(Object.error()); + (*Object)->Description.emplace(); + return {}; +} + +const StackObject *MachineFrameInfo::object(FrameIndex Index) const noexcept { + if (Index.value() >= Objects.size() || Objects[Index.value()].isTombstone()) + return nullptr; + return &Objects[Index.value()]; +} + +std::size_t MachineFrameInfo::liveObjectCount() const noexcept { + std::size_t Count = 0; + for (const StackObject &Object : Objects) { + if (!Object.isTombstone()) + ++Count; + } + return Count; +} + +Expected MachineFrameInfo::setMaxCallFrameSize(std::uint64_t Size) { + if (Frozen) + return makeUnexpected(ErrorCode::InvalidArgument, + "frozen frame cannot change its maximum call-frame size"); + MaxCallFrameSize = Size; + return {}; +} + +Expected MachineFrameInfo::freeze(std::uint64_t Size, Alignment Align) { + if (Frozen) + return makeUnexpected(ErrorCode::InvalidArgument, "frame layout is already frozen"); + for (const StackObject &Object : Objects) { + if (Object.isTombstone() || Object.isVariableSized()) + continue; + if (!Object.description()->Offset) { + return makeUnexpected(ErrorCode::VerificationError, + "fixed-size stack object is missing its final offset"); + } + } + if (Size % Align.bytes() != 0) { + return makeUnexpected(ErrorCode::InvalidArgument, + "static stack size must be aligned to the stack alignment"); + } + + StaticStackSize = Size; + StackAlign = Align; + Frozen = true; + return {}; +} + +Expected MachineFrameInfo::verify() const { + for (std::size_t Position = 0; Position < Objects.size(); ++Position) { + const StackObject &Object = Objects[Position]; + if (Object.index() != FrameIndex::fromValue(static_cast(Position))) { + return makeUnexpected(ErrorCode::VerificationError, + "stack object index does not match its stable table position"); + } + if (Object.isTombstone()) + continue; + auto DescriptionResult = verifyDescription(*Object.description()); + if (!DescriptionResult) + return std::unexpected(DescriptionResult.error()); + if (Frozen && !Object.isVariableSized() && !Object.description()->Offset) { + return makeUnexpected(ErrorCode::VerificationError, + "frozen fixed-size stack object has no final offset"); + } + } + + if (Frozen != StaticStackSize.has_value()) { + return makeUnexpected(ErrorCode::VerificationError, + "frame frozen state and static stack size are inconsistent"); + } + if (Frozen && *StaticStackSize % StackAlign.bytes() != 0) { + return makeUnexpected(ErrorCode::VerificationError, + "frozen static stack size violates stack alignment"); + } + return {}; +} + +} // namespace rcc diff --git a/backend/lib/CodeGen/MachineFunctionCloner.cpp b/backend/lib/CodeGen/MachineFunctionCloner.cpp index d452546..46fed6c 100644 --- a/backend/lib/CodeGen/MachineFunctionCloner.cpp +++ b/backend/lib/CodeGen/MachineFunctionCloner.cpp @@ -5,6 +5,7 @@ #include "rcc/CodeGen/InstructionDescriptor.h" #include "rcc/CodeGen/MachineBasicBlock.h" #include "rcc/CodeGen/MachineCFGUpdater.h" +#include "rcc/CodeGen/MachineFrameInfo.h" #include "rcc/CodeGen/MachineFunction.h" #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineMemOperand.h" @@ -86,8 +87,12 @@ struct CloneState final { if (Frame == nullptr) { return makeUnexpected(ErrorCode::VerificationError, "source frame-index operand is invalid"); } - State.Result.FrameIndices.emplace(Frame->Index, Frame->Index); - return SourceOperand.cloneDetached(); + const auto Position = State.Result.FrameIndices.find(Frame->Index); + if (Position == State.Result.FrameIndices.end()) { + return makeUnexpected(ErrorCode::VerificationError, + "source operand references an unmapped frame index"); + } + return MachineOperand::frameIndex(Position->second, Frame->Offset, SourceOperand.targetFlags()); } case MachineOperand::Kind::ConstantPoolIndex: { const auto *Constant = SourceOperand.getIf(); @@ -123,8 +128,6 @@ struct CloneState final { void recordMemoryIndexMappings(const MachineMemOperandDesc &Description, MachineFunctionCloneResult &Result) { - if (const auto Frame = Description.Base.frameIndex()) - Result.FrameIndices.emplace(*Frame, *Frame); if (const auto Constant = Description.Base.constantPoolIndex()) Result.ConstantPoolIndices.emplace(*Constant, *Constant); if (const auto JumpTable = Description.Base.jumpTableIndex()) @@ -139,6 +142,14 @@ cloneMemOperand(const MachineMemOperand &SourceOperand, CloneState &State) { MachineMemOperandDesc Description = SourceOperand.description(); recordMemoryIndexMappings(Description, State.Result); + if (const auto Frame = Description.Base.frameIndex()) { + const auto Position = State.Result.FrameIndices.find(*Frame); + if (Position == State.Result.FrameIndices.end()) { + return makeUnexpected(ErrorCode::VerificationError, + "source MMO references an unmapped frame index"); + } + Description.Base = MemoryBase::frameIndex(Position->second); + } auto DestinationOperand = State.Destination.createMemOperand(std::move(Description)); if (!DestinationOperand) return std::unexpected(DestinationOperand.error()); @@ -207,6 +218,23 @@ cloneMemOperand(const MachineMemOperand &SourceOperand, CloneState &State) { return {}; } +[[nodiscard]] Expected cloneFrameObjects(CloneState &State) { + for (const StackObject &SourceObject : State.Source.frameInfo().objects()) { + const StackObjectDesc *Description = SourceObject.description(); + if (Description == nullptr) + continue; + auto DestinationIndex = State.Destination.frameInfo().createObject(*Description); + if (!DestinationIndex) + return std::unexpected(DestinationIndex.error()); + State.Result.FrameIndices.emplace(SourceObject.index(), *DestinationIndex); + } + auto CallFrameResult = State.Destination.frameInfo().setMaxCallFrameSize( + State.Source.frameInfo().maxCallFrameSize()); + if (!CallFrameResult) + return std::unexpected(CallFrameResult.error()); + return {}; +} + [[nodiscard]] Expected cloneBlocks(CloneState &State) { for (const MachineBasicBlock *SourceBlock = State.Source.firstBlock(); SourceBlock != nullptr; SourceBlock = SourceBlock->next()) { @@ -294,6 +322,49 @@ cloneMemOperand(const MachineMemOperand &SourceOperand, CloneState &State) { return {}; } +[[nodiscard]] Expected finalizeFrameClone(CloneState &State) { + for (const StackObject &SourceObject : State.Source.frameInfo().objects()) { + const StackObjectDesc *SourceDescription = SourceObject.description(); + if (SourceDescription == nullptr) + continue; + const auto FramePosition = State.Result.FrameIndices.find(SourceObject.index()); + if (FramePosition == State.Result.FrameIndices.end()) { + return makeUnexpected(ErrorCode::InternalError, + "source stack object was not mapped before frame finalization"); + } + + StackObjectDesc DestinationDescription = *SourceDescription; + for (StackObjectLifetimeRange &Range : DestinationDescription.Lifetime) { + const auto Begin = State.Result.InstructionStableIDs.find(Range.Begin); + const auto End = State.Result.InstructionStableIDs.find(Range.End); + if (Begin == State.Result.InstructionStableIDs.end() || + End == State.Result.InstructionStableIDs.end()) { + return makeUnexpected(ErrorCode::VerificationError, + "source stack lifetime references an unmapped instruction"); + } + Range.Begin = Begin->second; + Range.End = End->second; + } + auto UpdateResult = State.Destination.frameInfo().updateObject( + FramePosition->second, std::move(DestinationDescription)); + if (!UpdateResult) + return std::unexpected(UpdateResult.error()); + } + + if (State.Source.frameInfo().isFrozen()) { + const auto StackSize = State.Source.frameInfo().staticStackSize(); + if (!StackSize) { + return makeUnexpected(ErrorCode::InternalError, + "verified frozen source frame has no static stack size"); + } + auto FreezeResult = + State.Destination.frameInfo().freeze(*StackSize, State.Source.frameInfo().stackAlignment()); + if (!FreezeResult) + return std::unexpected(FreezeResult.error()); + } + return {}; +} + [[nodiscard]] Expected cloneCFG(CloneState &State) { MachineCFGUpdater Updater = State.Destination.cfgUpdater(); for (const MachineBasicBlock *SourceBlock = State.Source.firstBlock(); SourceBlock != nullptr; @@ -353,12 +424,18 @@ Expected cloneMachineFunction(const MachineFunction auto RegisterResult = cloneRegisterConfiguration(State); if (!RegisterResult) return std::unexpected(RegisterResult.error()); + auto FrameResult = cloneFrameObjects(State); + if (!FrameResult) + return std::unexpected(FrameResult.error()); auto BlockResult = cloneBlocks(State); if (!BlockResult) return std::unexpected(BlockResult.error()); auto InstructionResult = cloneInstructions(State); if (!InstructionResult) return std::unexpected(InstructionResult.error()); + auto FrameFinalizationResult = finalizeFrameClone(State); + if (!FrameFinalizationResult) + return std::unexpected(FrameFinalizationResult.error()); auto CFGResult = cloneCFG(State); if (!CFGResult) return std::unexpected(CFGResult.error()); diff --git a/backend/lib/CodeGen/MachineIRBuilder.cpp b/backend/lib/CodeGen/MachineIRBuilder.cpp index 8f80ad6..185b7df 100644 --- a/backend/lib/CodeGen/MachineIRBuilder.cpp +++ b/backend/lib/CodeGen/MachineIRBuilder.cpp @@ -3,6 +3,7 @@ #include "rcc/CodeGen/MachineIRBuilder.h" #include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineFrameInfo.h" #include "rcc/CodeGen/MachineFunction.h" #include "rcc/CodeGen/MachineInstr.h" #include "rcc/CodeGen/MachineMemOperand.h" @@ -332,6 +333,15 @@ Expected MachineInstrBuilder::validateInsertionPoint() const { return {}; } +Expected MachineInstrBuilder::validateFrameReference(FrameIndex Index) const { + const StackObject *Object = Function->frameInfo().object(Index); + if (Object == nullptr || Object->description()->IsDead) { + return makeUnexpected(ErrorCode::InvalidArgument, + "builder references an unknown or dead stack object"); + } + return {}; +} + Expected MachineInstrBuilder::validateOperandOwnership(const MachineOperand &Operand) const { if (Operand.parent() != nullptr) { return makeUnexpected(ErrorCode::InvalidArgument, @@ -349,6 +359,11 @@ Expected MachineInstrBuilder::validateOperandOwnership(const MachineOperan return makeUnexpected(ErrorCode::InvalidArgument, "builder operand references an unknown virtual register"); } + if (const auto *Frame = Operand.getIf(); Frame != nullptr) { + auto FrameResult = validateFrameReference(Frame->Index); + if (!FrameResult) + return FrameResult; + } return {}; } @@ -389,6 +404,13 @@ Expected MachineInstrBuilder::build() { if (!Ownership) return std::unexpected(Ownership.error()); } + for (const MachineMemOperand *MemOperand : MemOperands) { + if (const auto Frame = MemOperand->description().Base.frameIndex()) { + auto FrameResult = validateFrameReference(*Frame); + if (!FrameResult) + return std::unexpected(FrameResult.error()); + } + } auto ExplicitValidation = Instructions->validateExplicitOperands( Descriptor->InstructionOpcode, ExplicitOperands, Function->registerInfo()); diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp index 450f8e3..6331366 100644 --- a/backend/lib/CodeGen/MachineVerifier.cpp +++ b/backend/lib/CodeGen/MachineVerifier.cpp @@ -3,6 +3,7 @@ #include "rcc/CodeGen/MachineVerifier.h" #include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineFrameInfo.h" #include "rcc/CodeGen/MachineFunction.h" #include "rcc/CodeGen/MachineFunctionProperties.h" #include "rcc/CodeGen/MachineInstr.h" @@ -36,9 +37,15 @@ public: auto CatalogResult = catalogArenaObjects(); if (!CatalogResult) return CatalogResult; + auto FrameResult = Function.frameInfo().verify(); + if (!FrameResult) + return failWith("frame info", FrameResult.error()); auto LayoutResult = verifyBlockLayout(); if (!LayoutResult) return LayoutResult; + auto FrameLifetimeResult = verifyFrameLifetimes(); + if (!FrameLifetimeResult) + return FrameLifetimeResult; auto CFGResult = verifyCFG(); if (!CFGResult) return CFGResult; @@ -209,6 +216,7 @@ private: return fail("block layout references an unregistered instruction"); if (!LinkedInstructions.insert(Instruction).second) return fail("instruction layout contains a cycle or duplicate instruction"); + LinkedInstructionIDs.insert(Instruction->stableID()); if (Instruction->parent() != &Block || Instruction->previous() != Previous) { return fail("instruction parent or previous link is inconsistent"); } @@ -270,6 +278,29 @@ private: return {}; } + [[nodiscard]] Expected verifyFrameIndex(FrameIndex Index) const { + const StackObject *Object = Function.frameInfo().object(Index); + const StackObjectDesc *Description = Object == nullptr ? nullptr : Object->description(); + if (Description == nullptr || Description->IsDead) + return fail("live instruction references an unknown or dead stack object"); + return {}; + } + + [[nodiscard]] Expected verifyFrameLifetimes() const { + for (const StackObject &Object : Function.frameInfo().objects()) { + const StackObjectDesc *Description = Object.description(); + if (Description == nullptr) + continue; + for (const StackObjectLifetimeRange &Range : Description->Lifetime) { + if (!LinkedInstructionIDs.contains(Range.Begin) || + !LinkedInstructionIDs.contains(Range.End)) { + return fail("stack object lifetime references a detached or unknown instruction"); + } + } + } + return {}; + } + [[nodiscard]] Expected verifyLiveInstruction(const MachineInstr &Instruction) { auto LocalResult = verifyInstructionLocalState(Instruction); if (!LocalResult) @@ -297,8 +328,12 @@ private: const auto Operands = Instruction.operands(); for (std::size_t Index = 0; Index < Operands.size(); ++Index) { const MachineOperand &Operand = Operands[Index]; - if (Operand.kind() == MachineOperand::Kind::FrameIndex) + if (const auto *Frame = Operand.getIf(); Frame != nullptr) { HasFrameIndex = true; + auto FrameResult = verifyFrameIndex(Frame->Index); + if (!FrameResult) + return FrameResult; + } if (const auto *Block = Operand.getIf(); Block != nullptr && @@ -328,6 +363,13 @@ private: HasUnrewrittenTie = true; } } + for (const MachineMemOperand *MemOperand : Instruction.memOperands()) { + if (const auto Frame = MemOperand->description().Base.frameIndex()) { + auto FrameResult = verifyFrameIndex(*Frame); + if (!FrameResult) + return FrameResult; + } + } return {}; } @@ -480,6 +522,7 @@ private: std::unordered_set LinkedBlocks; std::unordered_set RegisteredInstructions; std::unordered_set LinkedInstructions; + std::unordered_set LinkedInstructionIDs; std::unordered_set RegisteredMemOperands; std::unordered_map VirtualDefCounts; bool HasPhi = false; -- cgit v1.2.3