diff options
Diffstat (limited to 'backend/lib')
| -rw-r--r-- | backend/lib/CodeGen/MachineFunction.cpp | 14 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineFunctionCloner.cpp | 6 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineFunctionRecords.cpp | 77 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineInstr.cpp | 26 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineVerifier.cpp | 20 |
5 files changed, 143 insertions, 0 deletions
diff --git a/backend/lib/CodeGen/MachineFunction.cpp b/backend/lib/CodeGen/MachineFunction.cpp index 294158b..df1ceb5 100644 --- a/backend/lib/CodeGen/MachineFunction.cpp +++ b/backend/lib/CodeGen/MachineFunction.cpp @@ -10,6 +10,7 @@ #include <algorithm> #include <cstddef> #include <cstdint> +#include <limits> #include <memory> #include <memory_resource> #include <new> @@ -86,6 +87,19 @@ Expected<void> MachineFunction::setTargetState(TargetFunctionState State) { return {}; } +Expected<std::uint32_t> MachineFunction::allocateDebugInstrNumber() { + if (DebugInstrNumberingCount == std::numeric_limits<std::uint32_t>::max()) { + return makeUnexpected(ErrorCode::InternalError, + "machine debug instruction number space is exhausted"); + } + ++DebugInstrNumberingCount; + return DebugInstrNumberingCount; +} + +void MachineFunction::observeDebugInstrNumber(std::uint32_t Number) noexcept { + DebugInstrNumberingCount = std::max(DebugInstrNumberingCount, Number); +} + Expected<MachineBasicBlock *> MachineFunction::createBasicBlock() { auto ID = BlockIDGenerator.allocate(); if (!ID) diff --git a/backend/lib/CodeGen/MachineFunctionCloner.cpp b/backend/lib/CodeGen/MachineFunctionCloner.cpp index aae74ff..2f99341 100644 --- a/backend/lib/CodeGen/MachineFunctionCloner.cpp +++ b/backend/lib/CodeGen/MachineFunctionCloner.cpp @@ -388,6 +388,12 @@ cloneMemOperand(const MachineMemOperand &SourceOperand, CloneState &State) { } if (SourceInstruction->origin()) NewInstruction->setOrigin(*SourceInstruction->origin()); + if (SourceInstruction->debugInstrNumber() != 0) { + auto DebugNumberResult = + NewInstruction->setDebugInstrNumber(SourceInstruction->debugInstrNumber()); + if (!DebugNumberResult) + return std::unexpected(DebugNumberResult.error()); + } auto AppendResult = DestinationBlock->appendInstruction(*NewInstruction); if (!AppendResult) diff --git a/backend/lib/CodeGen/MachineFunctionRecords.cpp b/backend/lib/CodeGen/MachineFunctionRecords.cpp index be0d936..9fda0d7 100644 --- a/backend/lib/CodeGen/MachineFunctionRecords.cpp +++ b/backend/lib/CodeGen/MachineFunctionRecords.cpp @@ -7,6 +7,7 @@ #include <algorithm> #include <cstddef> #include <string> +#include <unordered_map> #include <unordered_set> #include <utility> @@ -55,6 +56,30 @@ verifyCalleeSavedRegisters(std::span<const PhysicalRegister> Registers) { return {}; } +[[nodiscard]] constexpr std::uint64_t +debugReferenceKey(MachineDebugValueReference Reference) noexcept { + return (static_cast<std::uint64_t>(Reference.InstructionNumber) << 32U) | + static_cast<std::uint64_t>(Reference.OperandNumber); +} + +[[nodiscard]] Expected<void> +verifyDebugValueSubstitution(const MachineDebugValueSubstitution &Substitution) { + if (Substitution.Source.InstructionNumber == 0 || + Substitution.Destination.InstructionNumber == 0) { + return makeUnexpected(ErrorCode::VerificationError, + "debug value substitution has a zero instruction number"); + } + if (Substitution.Source.InstructionNumber == Substitution.Destination.InstructionNumber) { + return makeUnexpected(ErrorCode::VerificationError, + "debug value substitution cannot replace a value within one instruction"); + } + if (Substitution.Source.OperandNumber == MachineDebugMemoryOperandNumber) { + return makeUnexpected(ErrorCode::VerificationError, + "debug value substitution cannot originate from the memory operand"); + } + return {}; +} + } // namespace Expected<void> @@ -102,6 +127,22 @@ Expected<void> MachineFunctionRecords::addPrefetchTarget(MachinePrefetchTarget T return {}; } +Expected<void> +MachineFunctionRecords::addDebugValueSubstitution(MachineDebugValueSubstitution Substitution) { + auto Verification = verifyDebugValueSubstitution(Substitution); + if (!Verification) + return std::unexpected(Verification.error()); + if (std::ranges::any_of(DebugValueSubstitutions, + [&Substitution](const MachineDebugValueSubstitution &Existing) { + return Existing.Source == Substitution.Source; + })) { + return makeUnexpected(ErrorCode::InvalidArgument, + "debug value source already has a substitution"); + } + DebugValueSubstitutions.push_back(Substitution); + return {}; +} + Expected<void> MachineFunctionRecords::verify() const { if (CalleeSavedRegisters) { auto CalleeSavedVerification = verifyCalleeSavedRegisters(*CalleeSavedRegisters); @@ -138,6 +179,37 @@ Expected<void> MachineFunctionRecords::verify() const { "prefetch target list contains a duplicate entry"); } } + + std::unordered_map<std::uint64_t, std::uint64_t> DebugSubstitutionEdges; + for (const MachineDebugValueSubstitution &Substitution : DebugValueSubstitutions) { + auto SubstitutionVerification = verifyDebugValueSubstitution(Substitution); + if (!SubstitutionVerification) + return SubstitutionVerification; + const std::uint64_t Source = debugReferenceKey(Substitution.Source); + const std::uint64_t Destination = debugReferenceKey(Substitution.Destination); + if (!DebugSubstitutionEdges.emplace(Source, Destination).second) { + return makeUnexpected(ErrorCode::VerificationError, + "multiple debug substitutions have the same source"); + } + } + + std::unordered_set<std::uint64_t> CompletedDebugReferences; + for (const auto &Edge : DebugSubstitutionEdges) { + const std::uint64_t Start = Edge.first; + std::unordered_set<std::uint64_t> Path; + std::uint64_t Current = Start; + while (!CompletedDebugReferences.contains(Current)) { + const auto Position = DebugSubstitutionEdges.find(Current); + if (Position == DebugSubstitutionEdges.end()) + break; + if (!Path.insert(Current).second) { + return makeUnexpected(ErrorCode::VerificationError, + "debug value substitutions contain a cycle"); + } + Current = Position->second; + } + CompletedDebugReferences.insert(Path.begin(), Path.end()); + } return {}; } @@ -181,6 +253,11 @@ MachineFunctionRecords::clone(const MachineFunctionCloneContext &CloneContext) c if (!AddResult) return std::unexpected(AddResult.error()); } + for (const MachineDebugValueSubstitution Source : DebugValueSubstitutions) { + auto AddResult = Result.addDebugValueSubstitution(Source); + if (!AddResult) + return std::unexpected(AddResult.error()); + } return Result; } diff --git a/backend/lib/CodeGen/MachineInstr.cpp b/backend/lib/CodeGen/MachineInstr.cpp index b201533..aaeeacd 100644 --- a/backend/lib/CodeGen/MachineInstr.cpp +++ b/backend/lib/CodeGen/MachineInstr.cpp @@ -8,7 +8,9 @@ #include "rcc/CodeGen/MachineRegisterInfo.h" #include <cstddef> +#include <cstdint> #include <functional> +#include <limits> #include <optional> #include <utility> @@ -30,6 +32,30 @@ Expected<void> MachineInstr::setOpcode(Opcode NewOpcode) { return {}; } +Expected<void> MachineInstr::setDebugInstrNumber(std::uint64_t Number) { + if (Number == 0 || Number > std::numeric_limits<std::uint32_t>::max()) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine debug instruction number must fit in nonzero uint32"); + } + if (DebugInstrNumber != 0 && DebugInstrNumber != Number) { + return makeUnexpected(ErrorCode::InvalidArgument, + "machine instruction already has a different debug number"); + } + DebugInstrNumber = static_cast<std::uint32_t>(Number); + OwnerFunction->observeDebugInstrNumber(DebugInstrNumber); + return {}; +} + +Expected<std::uint32_t> MachineInstr::assignDebugInstrNumber() { + if (DebugInstrNumber != 0) + return DebugInstrNumber; + auto Number = OwnerFunction->allocateDebugInstrNumber(); + if (!Number) + return std::unexpected(Number.error()); + DebugInstrNumber = *Number; + return DebugInstrNumber; +} + MachineOperand *MachineInstr::operandAt(std::size_t Index) noexcept { if (Index >= Operands.size()) return nullptr; diff --git a/backend/lib/CodeGen/MachineVerifier.cpp b/backend/lib/CodeGen/MachineVerifier.cpp index d1c6989..2fbbd38 100644 --- a/backend/lib/CodeGen/MachineVerifier.cpp +++ b/backend/lib/CodeGen/MachineVerifier.cpp @@ -396,6 +396,17 @@ private: if (!LinkedBlockProfileIDs.contains(Key)) return fail("prefetch target references an unknown bb_id"); } + + if (!Records.debugValueSubstitutions().empty() && + !Function.attributes().has(MachineFunctionAttribute::DebugInstrRef)) { + return fail("debug value substitutions require DebugInstrRef"); + } + for (const MachineDebugValueSubstitution &Substitution : Records.debugValueSubstitutions()) { + if (Substitution.Subregister.value() != 0 && + Target.registers().subRegIndex(Substitution.Subregister) == nullptr) { + return fail("debug value substitution references an unknown subregister index"); + } + } return {}; } @@ -421,6 +432,14 @@ private: const InstructionDescriptor *Descriptor = Target.instructionDescriptor(Instruction.opcode()); if (Descriptor == nullptr) return fail("live instruction uses an unregistered opcode"); + if (Instruction.debugInstrNumber() != 0) { + if (Descriptor->Flags.has(InstructionFlag::Meta)) { + return fail("metadata instruction has a debug value tracking number"); + } + if (!DebugInstructionNumbers.insert(Instruction.debugInstrNumber()).second) { + return fail("multiple instructions have the same debug value tracking number"); + } + } auto DescriptorResult = Target.validateInstruction(Instruction, Function.registerInfo()); if (!DescriptorResult) return failWith("instruction descriptor", DescriptorResult.error()); @@ -664,6 +683,7 @@ private: std::unordered_set<MachineInstrStableID> LinkedInstructionIDs; std::unordered_map<MachineInstrStableID, const MachineInstr *> LinkedInstructionsByID; std::unordered_set<std::uint64_t> LinkedBlockProfileIDs; + std::unordered_set<std::uint32_t> DebugInstructionNumbers; std::unordered_set<const MachineMemOperand *> RegisteredMemOperands; std::unordered_map<Register, std::size_t> VirtualDefCounts; bool HasPhi = false; |
