From a8a9d7d926202450645deae872d4d9dc11d63215 Mon Sep 17 00:00:00 2001 From: Richard-Qin-X Date: Sun, 2 Aug 2026 03:37:46 +0800 Subject: [CodeGen] Model machine debug metadata Replace marker-based metadata operands with scoped references and inline DIExpression values. Add structured DILocation chains, instruction debug attachments, stack variable records, and entry values with unified verification, builder support, and deterministic cloning. --- backend/lib/CodeGen/CMakeLists.txt | 4 + backend/lib/CodeGen/MachineDebugInfo.cpp | 164 +++++++++++++++++++++++++ backend/lib/CodeGen/MachineFrameInfo.cpp | 5 + backend/lib/CodeGen/MachineFunctionCloner.cpp | 6 + backend/lib/CodeGen/MachineFunctionRecords.cpp | 27 ++++ backend/lib/CodeGen/MachineIRBuilder.cpp | 34 ++++- backend/lib/CodeGen/MachineInstr.cpp | 9 ++ backend/lib/CodeGen/MachineMetadata.cpp | 13 ++ backend/lib/CodeGen/MachineOperand.cpp | 9 +- backend/lib/CodeGen/MachineVerifier.cpp | 25 +++- 10 files changed, 285 insertions(+), 11 deletions(-) create mode 100644 backend/lib/CodeGen/MachineDebugInfo.cpp (limited to 'backend/lib') diff --git a/backend/lib/CodeGen/CMakeLists.txt b/backend/lib/CodeGen/CMakeLists.txt index ec95c3c..08ca00e 100644 --- a/backend/lib/CodeGen/CMakeLists.txt +++ b/backend/lib/CodeGen/CMakeLists.txt @@ -10,6 +10,7 @@ set( MachineBasicBlock.cpp MachineCFGUpdater.cpp MachineConstantPool.cpp + MachineDebugInfo.cpp MachineFrameInfo.cpp MachineFunction.cpp MachineFunctionAttributes.cpp @@ -42,6 +43,7 @@ set( "${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/MachineConstantPool.h" + "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineDebugInfo.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/MachineFunctionAttributes.h" @@ -103,6 +105,7 @@ rcc_backend_register_format_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlock.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineConstantPool.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineDebugInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionAttributes.cpp" @@ -135,6 +138,7 @@ rcc_backend_register_tidy_files( "${CMAKE_CURRENT_SOURCE_DIR}/MachineBasicBlock.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineConstantPool.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/MachineDebugInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFrameInfo.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/MachineFunctionAttributes.cpp" diff --git a/backend/lib/CodeGen/MachineDebugInfo.cpp b/backend/lib/CodeGen/MachineDebugInfo.cpp new file mode 100644 index 0000000..35f68ca --- /dev/null +++ b/backend/lib/CodeGen/MachineDebugInfo.cpp @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachineDebugInfo.h" + +#include + +namespace rcc { + +Expected MachineMetadataValue::reference(MachineMetadataReference Reference) { + if (!Reference.isValid()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine metadata value reference must be valid"); + } + return MachineMetadataValue(Reference); +} + +MachineMetadataValue MachineMetadataValue::expression(MachineDIExpression Expression) { + return MachineMetadataValue(std::move(Expression)); +} + +Expected MachineMetadataValue::verify(const MachineMetadataInfo &Metadata) const { + if (!isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "machine metadata value has no representation"); + } + const MachineMetadataReference *Reference = reference(); + if (Reference == nullptr) + return {}; + return verifyMachineMetadataReference(*Reference, Metadata); +} + +Expected +MachineDILocation::create(std::vector InlineChain, + std::optional TerminalInlinedAt) { + MachineDILocation Result(std::move(InlineChain), TerminalInlinedAt); + auto Verification = Result.verifyStructure(); + if (!Verification) + return std::unexpected(Verification.error()); + return Result; +} + +Expected MachineDILocation::verifyStructure() const { + if (InlineChain.empty()) { + return makeUnexpected(ErrorCode::VerificationError, + "inline debug location requires at least one frame"); + } + for (const MachineDILocationFrame &Frame : InlineChain) { + if (!Frame.Scope.isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "inline debug location frame has an invalid scope"); + } + if (Frame.Scope.scope() != MachineMetadataScope::EmbeddedIR) { + return makeUnexpected(ErrorCode::VerificationError, + "inline debug location scope must reference embedded IR metadata"); + } + if (Frame.AtomGroup > MaxAtomGroup) { + return makeUnexpected(ErrorCode::VerificationError, + "inline debug location atom group exceeds 61 bits"); + } + if (Frame.AtomRank > 7) { + return makeUnexpected(ErrorCode::VerificationError, + "inline debug location atom rank exceeds three bits"); + } + } + if (TerminalInlinedAt && !TerminalInlinedAt->isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "inline debug location has an invalid terminal inlined-at reference"); + } + if (TerminalInlinedAt && TerminalInlinedAt->scope() != MachineMetadataScope::EmbeddedIR) { + return makeUnexpected(ErrorCode::VerificationError, + "inline debug location inlined-at must reference embedded IR metadata"); + } + return {}; +} + +Expected MachineDILocation::verify(const MachineMetadataInfo &Metadata) const { + auto Structure = verifyStructure(); + if (!Structure) + return Structure; + for (const MachineDILocationFrame &Frame : InlineChain) { + auto Scope = verifyMachineMetadataReference(Frame.Scope, Metadata); + if (!Scope) + return Scope; + } + if (TerminalInlinedAt) + return verifyMachineMetadataReference(*TerminalInlinedAt, Metadata); + return {}; +} + +Expected MachineDebugLocation::reference(MachineMetadataReference Reference) { + if (!Reference.isValid()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine debug location reference must be valid"); + } + if (Reference.scope() != MachineMetadataScope::EmbeddedIR) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine debug location must reference embedded IR metadata"); + } + return MachineDebugLocation(Reference); +} + +MachineDebugLocation MachineDebugLocation::inlineLocation(MachineDILocation Location) { + return MachineDebugLocation(std::move(Location)); +} + +Expected MachineDebugLocation::verify(const MachineMetadataInfo &Metadata) const { + if (!isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "machine debug location has no representation"); + } + if (const MachineMetadataReference *Reference = reference()) + return verifyMachineMetadataReference(*Reference, Metadata); + return inlineLocation()->verify(Metadata); +} + +Expected MachineVariableDebugInfo::verifyStructure() const { + if (!Variable && !Expression && !Location) { + return makeUnexpected(ErrorCode::VerificationError, + "variable debug information has no metadata"); + } + if (Variable && !Variable->isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "variable debug information has an invalid variable reference"); + } + if (Variable && Variable->scope() != MachineMetadataScope::EmbeddedIR) { + return makeUnexpected(ErrorCode::VerificationError, + "variable debug information must reference embedded IR metadata"); + } + if (Expression && !Expression->isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "variable debug information has an invalid expression"); + } + if (Expression && Expression->reference() != nullptr && + Expression->reference()->scope() != MachineMetadataScope::EmbeddedIR) { + return makeUnexpected(ErrorCode::VerificationError, + "variable debug expression must reference embedded IR metadata"); + } + if (Location && !Location->isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "variable debug information has an invalid location"); + } + return {}; +} + +Expected MachineVariableDebugInfo::verify(const MachineMetadataInfo &Metadata) const { + auto Structure = verifyStructure(); + if (!Structure) + return Structure; + if (Variable) { + auto VariableResult = verifyMachineMetadataReference(*Variable, Metadata); + if (!VariableResult) + return VariableResult; + } + if (Expression) { + auto ExpressionResult = Expression->verify(Metadata); + if (!ExpressionResult) + return ExpressionResult; + } + if (Location) + return Location->verify(Metadata); + return {}; +} + +} // namespace rcc diff --git a/backend/lib/CodeGen/MachineFrameInfo.cpp b/backend/lib/CodeGen/MachineFrameInfo.cpp index 58eab00..c4d3cda 100644 --- a/backend/lib/CodeGen/MachineFrameInfo.cpp +++ b/backend/lib/CodeGen/MachineFrameInfo.cpp @@ -77,6 +77,11 @@ Expected MachineFrameInfo::verifyDescription(const StackObjectDesc &Descri "stack object lifetime boundaries must not be reused"); } } + if (Description.DebugInfo) { + auto DebugInfoResult = Description.DebugInfo->verifyStructure(); + if (!DebugInfoResult) + return DebugInfoResult; + } return {}; } diff --git a/backend/lib/CodeGen/MachineFunctionCloner.cpp b/backend/lib/CodeGen/MachineFunctionCloner.cpp index e12e33e..dcf9712 100644 --- a/backend/lib/CodeGen/MachineFunctionCloner.cpp +++ b/backend/lib/CodeGen/MachineFunctionCloner.cpp @@ -386,6 +386,12 @@ cloneMemOperand(const MachineMemOperand &SourceOperand, CloneState &State) { if (SourceInstruction->sourceLocation()) { NewInstruction->setSourceLocation(*SourceInstruction->sourceLocation()); } + if (SourceInstruction->debugLocation()) { + auto DebugLocationResult = + NewInstruction->setDebugLocation(*SourceInstruction->debugLocation()); + if (!DebugLocationResult) + return std::unexpected(DebugLocationResult.error()); + } if (SourceInstruction->origin()) NewInstruction->setOrigin(*SourceInstruction->origin()); if (SourceInstruction->debugInstrNumber() != 0) { diff --git a/backend/lib/CodeGen/MachineFunctionRecords.cpp b/backend/lib/CodeGen/MachineFunctionRecords.cpp index 9fda0d7..0a21581 100644 --- a/backend/lib/CodeGen/MachineFunctionRecords.cpp +++ b/backend/lib/CodeGen/MachineFunctionRecords.cpp @@ -80,6 +80,14 @@ verifyDebugValueSubstitution(const MachineDebugValueSubstitution &Substitution) return {}; } +[[nodiscard]] Expected verifyEntryValue(const MachineEntryValueInfo &EntryValue) { + if (!EntryValue.Reg.isValid()) { + return makeUnexpected(ErrorCode::VerificationError, + "entry-value record requires a physical register"); + } + return EntryValue.DebugInfo.verifyStructure(); +} + } // namespace Expected @@ -143,6 +151,14 @@ MachineFunctionRecords::addDebugValueSubstitution(MachineDebugValueSubstitution return {}; } +Expected MachineFunctionRecords::addEntryValue(MachineEntryValueInfo EntryValue) { + auto Verification = verifyEntryValue(EntryValue); + if (!Verification) + return std::unexpected(Verification.error()); + EntryValues.push_back(std::move(EntryValue)); + return {}; +} + Expected MachineFunctionRecords::verify() const { if (CalleeSavedRegisters) { auto CalleeSavedVerification = verifyCalleeSavedRegisters(*CalleeSavedRegisters); @@ -210,6 +226,12 @@ Expected MachineFunctionRecords::verify() const { } CompletedDebugReferences.insert(Path.begin(), Path.end()); } + + for (const MachineEntryValueInfo &EntryValue : EntryValues) { + auto EntryValueVerification = verifyEntryValue(EntryValue); + if (!EntryValueVerification) + return EntryValueVerification; + } return {}; } @@ -258,6 +280,11 @@ MachineFunctionRecords::clone(const MachineFunctionCloneContext &CloneContext) c if (!AddResult) return std::unexpected(AddResult.error()); } + for (const MachineEntryValueInfo &Source : EntryValues) { + auto AddResult = Result.addEntryValue(Source); + if (!AddResult) + return std::unexpected(AddResult.error()); + } return Result; } diff --git a/backend/lib/CodeGen/MachineIRBuilder.cpp b/backend/lib/CodeGen/MachineIRBuilder.cpp index 7f6421b..5afdd72 100644 --- a/backend/lib/CodeGen/MachineIRBuilder.cpp +++ b/backend/lib/CodeGen/MachineIRBuilder.cpp @@ -33,8 +33,8 @@ MachineInstrBuilder::MachineInstrBuilder(MachineInstrBuilder &&Other) noexcept ExplicitOperands(std::move(Other.ExplicitOperands)), ExtraImplicitOperands(std::move(Other.ExtraImplicitOperands)), RequestedTies(std::move(Other.RequestedTies)), MemOperands(std::move(Other.MemOperands)), - Flags(Other.Flags), Location(std::move(Other.Location)), Origin(Other.Origin), - IsBuilt(Other.IsBuilt) { + Flags(Other.Flags), Location(std::move(Other.Location)), + DebugLocation(std::move(Other.DebugLocation)), Origin(Other.Origin), IsBuilt(Other.IsBuilt) { Other.Function = nullptr; Other.Target = nullptr; Other.Descriptor = nullptr; @@ -58,6 +58,7 @@ MachineInstrBuilder &MachineInstrBuilder::operator=(MachineInstrBuilder &&Other) MemOperands = std::move(Other.MemOperands); Flags = Other.Flags; Location = std::move(Other.Location); + DebugLocation = std::move(Other.DebugLocation); Origin = Other.Origin; IsBuilt = Other.IsBuilt; @@ -219,8 +220,9 @@ Expected MachineInstrBuilder::addRegisterMask(std::shared_ptr MachineInstrBuilder::addMetadata(std::string Marker, std::uint32_t TargetFlags) { - auto Operand = MachineOperand::metadata(std::move(Marker), TargetFlags); +Expected MachineInstrBuilder::addMetadata(MachineMetadataValue Value, + std::uint32_t TargetFlags) { + auto Operand = MachineOperand::metadata(std::move(Value), TargetFlags); if (!Operand) return std::unexpected(Operand.error()); return addOperand(std::move(*Operand)); @@ -301,6 +303,25 @@ Expected MachineInstrBuilder::clearSourceLocation() { return {}; } +Expected MachineInstrBuilder::setDebugLocation(MachineDebugLocation NewLocation) { + auto Pending = ensurePending(); + if (!Pending) + return std::unexpected(Pending.error()); + if (!NewLocation.isValid()) { + return makeUnexpected(ErrorCode::InvalidArgument, "builder debug location is invalid"); + } + DebugLocation = std::move(NewLocation); + return {}; +} + +Expected MachineInstrBuilder::clearDebugLocation() { + auto Pending = ensurePending(); + if (!Pending) + return std::unexpected(Pending.error()); + DebugLocation.reset(); + return {}; +} + Expected MachineInstrBuilder::setOrigin(OriginID NewOrigin) { auto Pending = ensurePending(); if (!Pending) @@ -518,6 +539,11 @@ Expected MachineInstrBuilder::build() { Result->setFlags(Flags); if (Location) Result->setSourceLocation(std::move(*Location)); + if (DebugLocation) { + auto DebugLocationResult = Result->setDebugLocation(std::move(*DebugLocation)); + if (!DebugLocationResult) + return std::unexpected(DebugLocationResult.error()); + } if (Origin) Result->setOrigin(*Origin); diff --git a/backend/lib/CodeGen/MachineInstr.cpp b/backend/lib/CodeGen/MachineInstr.cpp index aaeeacd..a8fe9b5 100644 --- a/backend/lib/CodeGen/MachineInstr.cpp +++ b/backend/lib/CodeGen/MachineInstr.cpp @@ -148,6 +148,15 @@ Expected MachineInstr::untieOperand(std::size_t Index) { return {}; } +Expected MachineInstr::setDebugLocation(MachineDebugLocation NewLocation) { + if (!NewLocation.isValid()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine instruction debug location must be valid"); + } + DebugLocation = std::move(NewLocation); + return {}; +} + Expected MachineInstr::addMemOperand(const MachineMemOperand &MemOperand) { if (!OwnerFunction->ownsMemOperand(MemOperand)) { return makeUnexpected(ErrorCode::InvalidArgument, diff --git a/backend/lib/CodeGen/MachineMetadata.cpp b/backend/lib/CodeGen/MachineMetadata.cpp index 24a04e9..f789a74 100644 --- a/backend/lib/CodeGen/MachineMetadata.cpp +++ b/backend/lib/CodeGen/MachineMetadata.cpp @@ -111,4 +111,17 @@ Expected MachineMetadataInfo::clone() const { return Result; } +Expected verifyMachineMetadataReference(MachineMetadataReference Reference, + const MachineMetadataInfo &Metadata) { + if (!Reference.isValid()) { + return makeUnexpected(ErrorCode::VerificationError, "machine metadata reference is invalid"); + } + if (Reference.scope() == MachineMetadataScope::MachineFunction && + Metadata.node(Reference.slot()) == nullptr) { + return makeUnexpected(ErrorCode::VerificationError, + "machine metadata reference uses an undefined function slot"); + } + return {}; +} + } // namespace rcc diff --git a/backend/lib/CodeGen/MachineOperand.cpp b/backend/lib/CodeGen/MachineOperand.cpp index 0e5febd..cd2d217 100644 --- a/backend/lib/CodeGen/MachineOperand.cpp +++ b/backend/lib/CodeGen/MachineOperand.cpp @@ -158,11 +158,12 @@ Expected MachineOperand::registerMask(std::shared_ptr MachineOperand::metadata(std::string Marker, std::uint32_t TargetFlags) { - if (Marker.empty()) { - return makeUnexpected(ErrorCode::InvalidArgument, "metadata operand marker cannot be empty"); +Expected MachineOperand::metadata(MachineMetadataValue Value, + std::uint32_t TargetFlags) { + if (!Value.isValid()) { + return makeUnexpected(ErrorCode::InvalidArgument, "metadata operand value must be valid"); } - return MachineOperand(Kind::Metadata, MetadataOperand{std::move(Marker)}, TargetFlags); + return MachineOperand(Kind::Metadata, MetadataOperand{std::move(Value)}, TargetFlags); } MachineOperand MachineOperand::targetIndex(TargetIndex Index, std::int64_t Offset, diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp index 2a29343..7e050ec 100644 --- a/backend/lib/CodeGen/MachineVerifier.cpp +++ b/backend/lib/CodeGen/MachineVerifier.cpp @@ -272,6 +272,11 @@ private: if (Instruction.sourceLocation() && !Instruction.sourceLocation()->isValid()) { return fail("instruction has an invalid source location"); } + if (Instruction.debugLocation()) { + auto DebugLocationResult = Instruction.debugLocation()->verify(Function.metadata()); + if (!DebugLocationResult) + return failWith("instruction debug location", DebugLocationResult.error()); + } if (Instruction.origin() && Instruction.origin()->value() == 0) return fail("instruction has an invalid origin ID"); @@ -293,9 +298,10 @@ private: Address != nullptr && (Address->FunctionName.empty() || Address->BlockName.empty())) { return fail("block-address operand has an incomplete name"); } - if (const auto *Metadata = Operand.getIf(); - Metadata != nullptr && Metadata->Marker.empty()) { - return fail("metadata operand has an empty marker"); + if (const auto *Metadata = Operand.getIf(); Metadata != nullptr) { + auto MetadataResult = Metadata->Value.verify(Function.metadata()); + if (!MetadataResult) + return failWith("metadata operand", MetadataResult.error()); } if (const auto *Symbol = Operand.getIf(); Symbol != nullptr && Symbol->Name.empty()) { @@ -342,6 +348,11 @@ private: return fail("stack object lifetime references a detached or unknown instruction"); } } + if (Description->DebugInfo) { + auto DebugInfoResult = Description->DebugInfo->verify(Function.metadata()); + if (!DebugInfoResult) + return failWith("stack object debug information", DebugInfoResult.error()); + } } return {}; } @@ -356,6 +367,14 @@ private: if (!Target.registers().isKnownPhysicalRegister(Reg)) return fail("callee-saved register list references an unknown physical register"); } + for (const MachineEntryValueInfo &EntryValue : Records.entryValues()) { + if (!Target.registers().isKnownPhysicalRegister(EntryValue.Reg)) { + return fail("entry-value record references an unknown physical register"); + } + auto DebugInfoResult = EntryValue.DebugInfo.verify(Function.metadata()); + if (!DebugInfoResult) + return failWith("entry-value debug information", DebugInfoResult.error()); + } auto VerifyCall = [this](MachineInstrStableID ID, std::string_view Kind) -> Expected { -- cgit v1.2.3