aboutsummaryrefslogtreecommitdiff
path: root/backend/lib
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib')
-rw-r--r--backend/lib/CodeGen/MachineFunction.cpp14
-rw-r--r--backend/lib/CodeGen/MachineFunctionCloner.cpp6
-rw-r--r--backend/lib/CodeGen/MachineFunctionRecords.cpp77
-rw-r--r--backend/lib/CodeGen/MachineInstr.cpp26
-rw-r--r--backend/lib/CodeGen/MachineVerifier.cpp20
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;