aboutsummaryrefslogtreecommitdiff
path: root/backend/lib
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib')
-rw-r--r--backend/lib/CodeGen/CMakeLists.txt4
-rw-r--r--backend/lib/CodeGen/InstructionDescriptor.cpp223
-rw-r--r--backend/lib/CodeGen/MachineIRBuilder.cpp537
-rw-r--r--backend/lib/CodeGen/MachineInstr.cpp8
4 files changed, 702 insertions, 70 deletions
diff --git a/backend/lib/CodeGen/CMakeLists.txt b/backend/lib/CodeGen/CMakeLists.txt
index d700d54..deaacb1 100644
--- a/backend/lib/CodeGen/CMakeLists.txt
+++ b/backend/lib/CodeGen/CMakeLists.txt
@@ -8,6 +8,7 @@ set(
MachineCFGUpdater.cpp
MachineFunction.cpp
MachineIRTypes.cpp
+ MachineIRBuilder.cpp
MachineInstr.cpp
MachineMemOperand.cpp
MachineOperand.cpp
@@ -24,6 +25,7 @@ set(
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineCFGUpdater.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineFunction.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineIRTypes.h"
+ "${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineIRBuilder.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineInstr.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineMemOperand.h"
"${RCC_BACKEND_SOURCE_DIR}/include/rcc/CodeGen/MachineOperand.h"
@@ -69,6 +71,7 @@ rcc_backend_register_format_files(
"${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineIRTypes.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRBuilder.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineInstr.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineMemOperand.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineOperand.cpp"
@@ -85,6 +88,7 @@ rcc_backend_register_tidy_files(
"${CMAKE_CURRENT_SOURCE_DIR}/MachineCFGUpdater.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineFunction.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineIRTypes.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/MachineIRBuilder.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineInstr.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineMemOperand.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/MachineOperand.cpp"
diff --git a/backend/lib/CodeGen/InstructionDescriptor.cpp b/backend/lib/CodeGen/InstructionDescriptor.cpp
index e5efad7..9f4a178 100644
--- a/backend/lib/CodeGen/InstructionDescriptor.cpp
+++ b/backend/lib/CodeGen/InstructionDescriptor.cpp
@@ -35,6 +35,14 @@ namespace {
(Left == RegisterOperandRole::Use && Right == RegisterOperandRole::Def);
}
+[[nodiscard]] bool isPureDef(const MachineOperand &Operand) noexcept {
+ return Operand.isRegister() && Operand.isDef() && !Operand.isUse();
+}
+
+[[nodiscard]] bool isPureUse(const MachineOperand &Operand) noexcept {
+ return Operand.isRegister() && Operand.isUse() && !Operand.isDef();
+}
+
[[nodiscard]] Expected<void> validateDescriptorStructure(const InstructionDescriptor &Descriptor) {
if (!Descriptor.InstructionOpcode.isValid())
return makeUnexpected(ErrorCode::InvalidArgument, "instruction descriptor opcode is invalid");
@@ -320,6 +328,133 @@ Expected<void> InstructionSet::validateExplicitOperands(Opcode InstructionOpcode
return validateExplicitOperands(*Descriptor, Operands, RegInfo);
}
+Expected<void> InstructionSet::validateOperandTies(const InstructionDescriptor &Descriptor,
+ std::span<const MachineOperand> ExplicitOperands,
+ std::span<const MachineOperandTie> Ties) const {
+ std::vector<std::optional<std::size_t>> Partners(ExplicitOperands.size());
+ for (const MachineOperandTie Tie : Ties) {
+ if (Tie.DefOperand >= ExplicitOperands.size() || Tie.UseOperand >= ExplicitOperands.size() ||
+ Tie.DefOperand == Tie.UseOperand || !isPureDef(ExplicitOperands[Tie.DefOperand]) ||
+ !isPureUse(ExplicitOperands[Tie.UseOperand])) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "instruction tie must connect an in-range pure register def and use");
+ }
+ if (Partners[Tie.DefOperand] || Partners[Tie.UseOperand]) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "instruction operand participates in duplicate or conflicting ties");
+ }
+ Partners[Tie.DefOperand] = Tie.UseOperand;
+ Partners[Tie.UseOperand] = Tie.DefOperand;
+ }
+
+ for (std::size_t Index = 0; Index < Descriptor.Operands.size(); ++Index) {
+ const OperandDescriptor &Operand = Descriptor.Operands[Index];
+ if (Operand.DefaultTiedOperand &&
+ (Index >= Partners.size() || Partners[Index] != Operand.DefaultTiedOperand)) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "required descriptor tie is not materialized");
+ }
+ }
+ return {};
+}
+
+Expected<void> InstructionSet::validateOperandTies(Opcode InstructionOpcode,
+ std::span<const MachineOperand> ExplicitOperands,
+ std::span<const MachineOperandTie> Ties) const {
+ const InstructionDescriptor *Descriptor = descriptor(InstructionOpcode);
+ if (Descriptor == nullptr) {
+ return makeUnexpected(ErrorCode::VerificationError, "instruction opcode is not registered");
+ }
+ return validateOperandTies(*Descriptor, ExplicitOperands, Ties);
+}
+
+Expected<void> InstructionSet::validateImplicitOperands(
+ const InstructionDescriptor &Descriptor,
+ std::span<const MachineOperand *const> ImplicitOperands) const {
+ const std::size_t DefaultCount = Descriptor.ImplicitDefs.size() + Descriptor.ImplicitUses.size();
+ if (ImplicitOperands.size() < DefaultCount ||
+ (!Descriptor.AllowExtraImplicitOperands && ImplicitOperands.size() != DefaultCount)) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "instruction implicit operand count does not match its descriptor");
+ }
+
+ std::size_t Index = 0;
+ auto ValidateDefault = [&](const ImplicitRegisterDescriptor &Implicit,
+ bool IsDef) -> Expected<void> {
+ const MachineOperand *Operand = ImplicitOperands[Index++];
+ const Register *Reg = Operand == nullptr ? nullptr : Operand->getIf<Register>();
+ if (Reg == nullptr || Reg->physicalRegister() != Implicit.Reg || Operand->isDef() != IsDef ||
+ Operand->isUse() == IsDef || !Operand->isImplicit() ||
+ Operand->registerFlags().has(RegisterOperandFlag::EarlyClobber) != Implicit.EarlyClobber ||
+ Operand->registerFlags().has(RegisterOperandFlag::Renamable) != Implicit.Renamable) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "default implicit register operand does not match its descriptor");
+ }
+ return {};
+ };
+
+ for (const ImplicitRegisterDescriptor &Implicit : Descriptor.ImplicitDefs) {
+ auto Validation = ValidateDefault(Implicit, true);
+ if (!Validation)
+ return std::unexpected(Validation.error());
+ }
+ for (const ImplicitRegisterDescriptor &Implicit : Descriptor.ImplicitUses) {
+ auto Validation = ValidateDefault(Implicit, false);
+ if (!Validation)
+ return std::unexpected(Validation.error());
+ }
+ for (; Index < ImplicitOperands.size(); ++Index) {
+ const MachineOperand *Operand = ImplicitOperands[Index];
+ if (Operand == nullptr || !Operand->isRegister() || !Operand->isImplicit()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "dynamic implicit operand must be an implicit register");
+ }
+ }
+ return {};
+}
+
+Expected<void> InstructionSet::validateImplicitOperands(
+ Opcode InstructionOpcode, std::span<const MachineOperand *const> ImplicitOperands) const {
+ const InstructionDescriptor *Descriptor = descriptor(InstructionOpcode);
+ if (Descriptor == nullptr) {
+ return makeUnexpected(ErrorCode::VerificationError, "instruction opcode is not registered");
+ }
+ return validateImplicitOperands(*Descriptor, ImplicitOperands);
+}
+
+Expected<void>
+InstructionSet::validateMemOperands(const InstructionDescriptor &Descriptor,
+ std::span<const MachineMemOperand *const> MemOperands) const {
+ const bool MayLoad = Descriptor.Flags.has(InstructionFlag::MayLoad);
+ const bool MayStore = Descriptor.Flags.has(InstructionFlag::MayStore);
+ if (Descriptor.RequiresMemoryOperands && MemOperands.empty()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "memory instruction is missing MachineMemOperand");
+ }
+ if (!MayLoad && !MayStore && !MemOperands.empty()) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "non-memory instruction carries MachineMemOperand");
+ }
+ for (const MachineMemOperand *MemOperand : MemOperands) {
+ if (MemOperand == nullptr || (MemOperand->isLoad() && !MayLoad) ||
+ (MemOperand->isStore() && !MayStore)) {
+ return makeUnexpected(ErrorCode::VerificationError,
+ "MachineMemOperand access conflicts with instruction descriptor");
+ }
+ }
+ return {};
+}
+
+Expected<void>
+InstructionSet::validateMemOperands(Opcode InstructionOpcode,
+ std::span<const MachineMemOperand *const> MemOperands) const {
+ const InstructionDescriptor *Descriptor = descriptor(InstructionOpcode);
+ if (Descriptor == nullptr) {
+ return makeUnexpected(ErrorCode::VerificationError, "instruction opcode is not registered");
+ }
+ return validateMemOperands(*Descriptor, MemOperands);
+}
+
Expected<void> InstructionSet::validateOperand(const OperandDescriptor &Descriptor,
const MachineOperand &Operand,
const MachineRegisterInfo &RegInfo) const {
@@ -402,86 +537,42 @@ Expected<void> InstructionSet::validateInstruction(const MachineInstr &Instructi
if (!ExplicitValidation)
return std::unexpected(ExplicitValidation.error());
+ std::vector<MachineOperandTie> Ties;
for (std::size_t Index = 0; Index < ExplicitCount; ++Index) {
const MachineOperand &Operand = AllOperands[Index];
- const OperandDescriptor &OperandDesc = descriptorForOperand(*Descriptor, Index);
- if (OperandDesc.DefaultTiedOperand &&
- Operand.tiedOperandIndex() != OperandDesc.DefaultTiedOperand) {
- return makeUnexpected(ErrorCode::VerificationError,
- "required descriptor tie is not materialized");
- }
if (!Operand.tiedOperandIndex())
continue;
const std::size_t OtherIndex = *Operand.tiedOperandIndex();
- if (OtherIndex >= ExplicitCount || AllOperands[OtherIndex].tiedOperandIndex() != Index ||
- !Operand.isRegister() || !AllOperands[OtherIndex].isRegister() ||
- Operand.isDef() == AllOperands[OtherIndex].isDef() ||
- Operand.isUse() == AllOperands[OtherIndex].isUse()) {
+ if (OtherIndex >= ExplicitCount || AllOperands[OtherIndex].tiedOperandIndex() != Index) {
return makeUnexpected(ErrorCode::VerificationError,
- "instruction operand tie is invalid or not reciprocal");
+ "instruction operand tie is out of range or not reciprocal");
}
+ if (Index > OtherIndex)
+ continue;
+ if (isPureUse(Operand) && isPureDef(AllOperands[OtherIndex]))
+ Ties.push_back(MachineOperandTie{OtherIndex, Index});
+ else
+ Ties.push_back(MachineOperandTie{Index, OtherIndex});
}
- const std::size_t DefaultImplicitCount =
- Descriptor->ImplicitDefs.size() + Descriptor->ImplicitUses.size();
- const std::size_t ActualImplicitCount = AllOperands.size() - ExplicitCount;
- if (ActualImplicitCount < DefaultImplicitCount ||
- (!Descriptor->AllowExtraImplicitOperands && ActualImplicitCount != DefaultImplicitCount)) {
- return makeUnexpected(ErrorCode::VerificationError,
- "instruction implicit operand count does not match its descriptor");
- }
-
- std::size_t ImplicitIndex = ExplicitCount;
- auto ValidateImplicit = [&](const ImplicitRegisterDescriptor &Implicit,
- bool IsDef) -> Expected<void> {
- const MachineOperand &Operand = AllOperands[ImplicitIndex++];
- const auto Reg = Operand.registerValue();
- if (!Reg || Reg->physicalRegister() != Implicit.Reg || Operand.isDef() != IsDef ||
- Operand.isUse() == IsDef || !Operand.isImplicit() ||
- Operand.registerFlags().has(RegisterOperandFlag::EarlyClobber) != Implicit.EarlyClobber ||
- Operand.registerFlags().has(RegisterOperandFlag::Renamable) != Implicit.Renamable) {
- return makeUnexpected(ErrorCode::VerificationError,
- "default implicit register operand does not match its descriptor");
- }
- return {};
- };
-
- for (const ImplicitRegisterDescriptor &Implicit : Descriptor->ImplicitDefs) {
- auto Validation = ValidateImplicit(Implicit, true);
- if (!Validation)
- return std::unexpected(Validation.error());
- }
- for (const ImplicitRegisterDescriptor &Implicit : Descriptor->ImplicitUses) {
- auto Validation = ValidateImplicit(Implicit, false);
- if (!Validation)
- return std::unexpected(Validation.error());
- }
- for (; ImplicitIndex < AllOperands.size(); ++ImplicitIndex) {
- if (!AllOperands[ImplicitIndex].isRegister() || !AllOperands[ImplicitIndex].isImplicit()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "dynamic implicit operand must be an implicit register");
- }
- }
+ auto TieValidation = validateOperandTies(*Descriptor, AllOperands.first(ExplicitCount), Ties);
+ if (!TieValidation)
+ return std::unexpected(TieValidation.error());
- const bool MayLoad = Descriptor->Flags.has(InstructionFlag::MayLoad);
- const bool MayStore = Descriptor->Flags.has(InstructionFlag::MayStore);
- if (Descriptor->RequiresMemoryOperands && Instruction.memOperands().empty()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "memory instruction is missing MachineMemOperand");
- }
- for (const MachineMemOperand *MemOperand : Instruction.memOperands()) {
- if (MemOperand == nullptr || (MemOperand->isLoad() && !MayLoad) ||
- (MemOperand->isStore() && !MayStore)) {
+ std::vector<const MachineOperand *> ImplicitOperands;
+ ImplicitOperands.reserve(AllOperands.size() - ExplicitCount);
+ for (std::size_t Index = ExplicitCount; Index < AllOperands.size(); ++Index) {
+ if (AllOperands[Index].tiedOperandIndex()) {
return makeUnexpected(ErrorCode::VerificationError,
- "MachineMemOperand access conflicts with instruction descriptor");
+ "implicit register operand cannot participate in a tie");
}
- }
- if (!MayLoad && !MayStore && !Instruction.memOperands().empty()) {
- return makeUnexpected(ErrorCode::VerificationError,
- "non-memory instruction carries MachineMemOperand");
+ ImplicitOperands.push_back(&AllOperands[Index]);
}
- return {};
+ auto ImplicitValidation = validateImplicitOperands(*Descriptor, ImplicitOperands);
+ if (!ImplicitValidation)
+ return std::unexpected(ImplicitValidation.error());
+ return validateMemOperands(*Descriptor, Instruction.memOperands());
}
Expected<std::vector<MachineOperand>>
diff --git a/backend/lib/CodeGen/MachineIRBuilder.cpp b/backend/lib/CodeGen/MachineIRBuilder.cpp
new file mode 100644
index 0000000..8f80ad6
--- /dev/null
+++ b/backend/lib/CodeGen/MachineIRBuilder.cpp
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "rcc/CodeGen/MachineIRBuilder.h"
+
+#include "rcc/CodeGen/MachineBasicBlock.h"
+#include "rcc/CodeGen/MachineFunction.h"
+#include "rcc/CodeGen/MachineInstr.h"
+#include "rcc/CodeGen/MachineMemOperand.h"
+#include "rcc/CodeGen/MachineRegisterInfo.h"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace rcc {
+
+MachineInstrBuilder::MachineInstrBuilder(MachineFunction &Function,
+ const InstructionSet &Instructions,
+ const InstructionDescriptor &Descriptor,
+ MachineBasicBlock &InsertBlock,
+ MachineInstr *InsertBefore) noexcept
+ : Function(&Function), Instructions(&Instructions), Descriptor(&Descriptor),
+ InsertBlock(&InsertBlock), InsertBefore(InsertBefore) {}
+
+MachineInstrBuilder::MachineInstrBuilder(MachineInstrBuilder &&Other) noexcept
+ : Function(Other.Function), Instructions(Other.Instructions), Descriptor(Other.Descriptor),
+ InsertBlock(Other.InsertBlock), InsertBefore(Other.InsertBefore),
+ 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) {
+ Other.Function = nullptr;
+ Other.Instructions = nullptr;
+ Other.Descriptor = nullptr;
+ Other.InsertBlock = nullptr;
+ Other.InsertBefore = nullptr;
+ Other.IsBuilt = true;
+}
+
+MachineInstrBuilder &MachineInstrBuilder::operator=(MachineInstrBuilder &&Other) noexcept {
+ if (this == &Other)
+ return *this;
+
+ Function = Other.Function;
+ Instructions = Other.Instructions;
+ Descriptor = Other.Descriptor;
+ InsertBlock = Other.InsertBlock;
+ InsertBefore = Other.InsertBefore;
+ 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;
+
+ Other.Function = nullptr;
+ Other.Instructions = nullptr;
+ Other.Descriptor = nullptr;
+ Other.InsertBlock = nullptr;
+ Other.InsertBefore = nullptr;
+ Other.IsBuilt = true;
+ return *this;
+}
+
+Expected<void> MachineInstrBuilder::ensurePending() const {
+ if (IsBuilt) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "machine instruction builder was already consumed");
+ }
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::addOperand(MachineOperand &&Operand) {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ if (Operand.parent() != nullptr) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder operand already belongs to an instruction");
+ }
+ if (Operand.isImplicit()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "implicit register requires addImplicitOperand");
+ }
+ ExplicitOperands.push_back(std::move(Operand));
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::addImplicitOperand(MachineOperand &&Operand) {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ if (Operand.parent() != nullptr) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder operand already belongs to an instruction");
+ }
+ if (!Operand.isRegister() || !Operand.isImplicit()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "dynamic implicit operand must be an implicit register");
+ }
+ ExtraImplicitOperands.push_back(std::move(Operand));
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::appendRegister(Register Reg, RegisterOperandFlags RegisterFlags,
+ SubRegIndex SubReg, std::uint32_t TargetFlags,
+ bool IsImplicit) {
+ auto Operand = MachineOperand::registerOperand(Reg, RegisterFlags, SubReg, TargetFlags);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ if (IsImplicit)
+ return addImplicitOperand(std::move(*Operand));
+ return addOperand(std::move(*Operand));
+}
+
+Expected<void> MachineInstrBuilder::addDef(Register Reg, RegisterOperandFlags AdditionalFlags,
+ SubRegIndex SubReg, std::uint32_t TargetFlags) {
+ AdditionalFlags.set(RegisterOperandFlag::Define);
+ return appendRegister(Reg, AdditionalFlags, SubReg, TargetFlags, false);
+}
+
+Expected<void> MachineInstrBuilder::addUse(Register Reg, RegisterOperandFlags AdditionalFlags,
+ SubRegIndex SubReg, std::uint32_t TargetFlags) {
+ AdditionalFlags.set(RegisterOperandFlag::Use);
+ return appendRegister(Reg, AdditionalFlags, SubReg, TargetFlags, false);
+}
+
+Expected<void> MachineInstrBuilder::addDefUse(Register Reg, RegisterOperandFlags AdditionalFlags,
+ SubRegIndex SubReg, std::uint32_t TargetFlags) {
+ AdditionalFlags.set(RegisterOperandFlag::Define);
+ AdditionalFlags.set(RegisterOperandFlag::Use);
+ AdditionalFlags.set(RegisterOperandFlag::InternalRead);
+ return appendRegister(Reg, AdditionalFlags, SubReg, TargetFlags, false);
+}
+
+Expected<void> MachineInstrBuilder::addImplicitDef(Register Reg,
+ RegisterOperandFlags AdditionalFlags,
+ SubRegIndex SubReg, std::uint32_t TargetFlags) {
+ AdditionalFlags.set(RegisterOperandFlag::Define);
+ AdditionalFlags.set(RegisterOperandFlag::Implicit);
+ return appendRegister(Reg, AdditionalFlags, SubReg, TargetFlags, true);
+}
+
+Expected<void> MachineInstrBuilder::addImplicitUse(Register Reg,
+ RegisterOperandFlags AdditionalFlags,
+ SubRegIndex SubReg, std::uint32_t TargetFlags) {
+ AdditionalFlags.set(RegisterOperandFlag::Use);
+ AdditionalFlags.set(RegisterOperandFlag::Implicit);
+ return appendRegister(Reg, AdditionalFlags, SubReg, TargetFlags, true);
+}
+
+Expected<void> MachineInstrBuilder::addImmediate(std::int64_t Value, std::uint32_t TargetFlags) {
+ return addOperand(MachineOperand::immediate(Value, TargetFlags));
+}
+
+Expected<void> MachineInstrBuilder::addFloatingImmediate(FloatingPointBits Bits,
+ std::uint32_t TargetFlags) {
+ return addOperand(MachineOperand::floatingImmediate(Bits, TargetFlags));
+}
+
+Expected<void> MachineInstrBuilder::addBasicBlock(MachineBasicBlock &Block,
+ std::uint32_t TargetFlags) {
+ return addOperand(MachineOperand::basicBlock(Block, TargetFlags));
+}
+
+Expected<void> MachineInstrBuilder::addFrameIndex(FrameIndex Index, std::int64_t Offset,
+ std::uint32_t TargetFlags) {
+ return addOperand(MachineOperand::frameIndex(Index, Offset, TargetFlags));
+}
+
+Expected<void> MachineInstrBuilder::addConstantPool(ConstantPoolIndex Index, std::int64_t Offset,
+ std::uint32_t TargetFlags) {
+ return addOperand(MachineOperand::constantPool(Index, Offset, TargetFlags));
+}
+
+Expected<void> MachineInstrBuilder::addJumpTable(JumpTableIndex Index, std::uint32_t TargetFlags) {
+ return addOperand(MachineOperand::jumpTable(Index, TargetFlags));
+}
+
+Expected<void> MachineInstrBuilder::addGlobalSymbol(std::string Name, std::int64_t Offset,
+ std::uint32_t TargetFlags) {
+ auto Operand = MachineOperand::globalSymbol(std::move(Name), Offset, TargetFlags);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ return addOperand(std::move(*Operand));
+}
+
+Expected<void> MachineInstrBuilder::addExternalSymbol(std::string Name, std::int64_t Offset,
+ std::uint32_t TargetFlags) {
+ auto Operand = MachineOperand::externalSymbol(std::move(Name), Offset, TargetFlags);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ return addOperand(std::move(*Operand));
+}
+
+Expected<void> MachineInstrBuilder::addBlockAddress(std::string FunctionName, std::string BlockName,
+ std::int64_t Offset,
+ std::uint32_t TargetFlags) {
+ auto Operand = MachineOperand::blockAddress(std::move(FunctionName), std::move(BlockName), Offset,
+ TargetFlags);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ return addOperand(std::move(*Operand));
+}
+
+Expected<void> MachineInstrBuilder::addRegisterMask(std::shared_ptr<const RegisterMask> Mask,
+ std::uint32_t TargetFlags) {
+ auto Operand = MachineOperand::registerMask(std::move(Mask), TargetFlags);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ return addOperand(std::move(*Operand));
+}
+
+Expected<void> MachineInstrBuilder::addMetadata(std::string Marker, std::uint32_t TargetFlags) {
+ auto Operand = MachineOperand::metadata(std::move(Marker), TargetFlags);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ return addOperand(std::move(*Operand));
+}
+
+Expected<void> MachineInstrBuilder::addTargetIndex(TargetIndex Index, std::int64_t Offset,
+ std::uint32_t TargetFlags) {
+ return addOperand(MachineOperand::targetIndex(Index, Offset, TargetFlags));
+}
+
+Expected<void> MachineInstrBuilder::addMCSymbol(std::string Name, std::int64_t Offset,
+ std::uint32_t TargetFlags) {
+ auto Operand = MachineOperand::mcSymbol(std::move(Name), Offset, TargetFlags);
+ if (!Operand)
+ return std::unexpected(Operand.error());
+ return addOperand(std::move(*Operand));
+}
+
+Expected<void> MachineInstrBuilder::tieOperands(std::size_t DefOperand, std::size_t UseOperand) {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ if (DefOperand >= ExplicitOperands.size() || UseOperand >= ExplicitOperands.size() ||
+ DefOperand == UseOperand) {
+ return makeUnexpected(ErrorCode::InvalidArgument, "builder operand tie indices are invalid");
+ }
+
+ const MachineOperand &Def = ExplicitOperands[DefOperand];
+ const MachineOperand &Use = ExplicitOperands[UseOperand];
+ if (!Def.isRegister() || !Use.isRegister() || !Def.isDef() || Def.isUse() || !Use.isUse() ||
+ Use.isDef()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder tie must connect a pure register def and use");
+ }
+
+ const MachineOperandTie Tie{DefOperand, UseOperand};
+ if (std::ranges::find(RequestedTies, Tie) == RequestedTies.end())
+ RequestedTies.push_back(Tie);
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::addMemOperand(const MachineMemOperand &MemOperand) {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ if (!Function->ownsMemOperand(MemOperand)) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder memory operand belongs to another function");
+ }
+ MemOperands.push_back(&MemOperand);
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::setFlags(MachineInstrFlags NewFlags) {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ Flags = NewFlags;
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::setSourceLocation(SourceLocation NewLocation) {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ if (!NewLocation.isValid()) {
+ return makeUnexpected(ErrorCode::InvalidArgument, "builder source location is incomplete");
+ }
+ Location = std::move(NewLocation);
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::clearSourceLocation() {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ Location.reset();
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::setOrigin(OriginID NewOrigin) {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ if (NewOrigin.value() == 0) {
+ return makeUnexpected(ErrorCode::InvalidArgument, "builder origin ID must be nonzero");
+ }
+ Origin = NewOrigin;
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::clearOrigin() {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+ Origin.reset();
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::validateInsertionPoint() const {
+ if (InsertBlock == nullptr || &InsertBlock->function() != Function || !InsertBlock->isLinked()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder insertion block is not linked to its function");
+ }
+ if (InsertBefore != nullptr && InsertBefore->parent() != InsertBlock) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder insertion cursor is no longer in its block");
+ }
+ return {};
+}
+
+Expected<void> MachineInstrBuilder::validateOperandOwnership(const MachineOperand &Operand) const {
+ if (Operand.parent() != nullptr) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder operand already belongs to an instruction");
+ }
+ if (const auto *Block = Operand.getIf<BasicBlockOperand>();
+ Block != nullptr && (Block->Block == nullptr || &Block->Block->function() != Function ||
+ !Block->Block->isLinked())) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder basic block operand is not linked to its function");
+ }
+ if (const Register *Reg = Operand.getIf<Register>();
+ Reg != nullptr && Reg->isVirtual() &&
+ !Function->registerInfo().isKnownVirtualRegister(*Reg)) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder operand references an unknown virtual register");
+ }
+ return {};
+}
+
+std::vector<MachineOperandTie> MachineInstrBuilder::collectOperandTies() const {
+ std::vector<MachineOperandTie> Result;
+ for (std::size_t Index = 0; Index < Descriptor->Operands.size(); ++Index) {
+ const OperandDescriptor &Operand = Descriptor->Operands[Index];
+ if (!Operand.DefaultTiedOperand || Index > *Operand.DefaultTiedOperand)
+ continue;
+ const std::size_t Other = *Operand.DefaultTiedOperand;
+ const bool IndexIsDef = Operand.RegisterRole == RegisterOperandRole::Def;
+ Result.push_back(IndexIsDef ? MachineOperandTie{Index, Other}
+ : MachineOperandTie{Other, Index});
+ }
+ for (const MachineOperandTie Tie : RequestedTies) {
+ if (std::ranges::find(Result, Tie) == Result.end())
+ Result.push_back(Tie);
+ }
+ return Result;
+}
+
+Expected<MachineInstr *> MachineInstrBuilder::build() {
+ auto Pending = ensurePending();
+ if (!Pending)
+ return std::unexpected(Pending.error());
+
+ auto InsertionValidation = validateInsertionPoint();
+ if (!InsertionValidation)
+ return std::unexpected(InsertionValidation.error());
+
+ for (const MachineOperand &Operand : ExplicitOperands) {
+ auto Ownership = validateOperandOwnership(Operand);
+ if (!Ownership)
+ return std::unexpected(Ownership.error());
+ }
+ for (const MachineOperand &Operand : ExtraImplicitOperands) {
+ auto Ownership = validateOperandOwnership(Operand);
+ if (!Ownership)
+ return std::unexpected(Ownership.error());
+ }
+
+ auto ExplicitValidation = Instructions->validateExplicitOperands(
+ Descriptor->InstructionOpcode, ExplicitOperands, Function->registerInfo());
+ if (!ExplicitValidation)
+ return std::unexpected(ExplicitValidation.error());
+
+ auto DefaultImplicit = Instructions->createDefaultImplicitOperands(*Descriptor);
+ if (!DefaultImplicit)
+ return std::unexpected(DefaultImplicit.error());
+
+ std::vector<const MachineOperand *> ImplicitOperands;
+ ImplicitOperands.reserve(DefaultImplicit->size() + ExtraImplicitOperands.size());
+ for (const MachineOperand &Operand : *DefaultImplicit)
+ ImplicitOperands.push_back(&Operand);
+ for (const MachineOperand &Operand : ExtraImplicitOperands)
+ ImplicitOperands.push_back(&Operand);
+ auto ImplicitValidation =
+ Instructions->validateImplicitOperands(Descriptor->InstructionOpcode, ImplicitOperands);
+ if (!ImplicitValidation)
+ return std::unexpected(ImplicitValidation.error());
+
+ const std::vector<MachineOperandTie> Ties = collectOperandTies();
+ auto TieValidation =
+ Instructions->validateOperandTies(Descriptor->InstructionOpcode, ExplicitOperands, Ties);
+ if (!TieValidation)
+ return std::unexpected(TieValidation.error());
+
+ auto MemoryValidation =
+ Instructions->validateMemOperands(Descriptor->InstructionOpcode, MemOperands);
+ if (!MemoryValidation)
+ return std::unexpected(MemoryValidation.error());
+
+ auto Instruction = Function->createInstruction(Descriptor->InstructionOpcode);
+ if (!Instruction)
+ return std::unexpected(Instruction.error());
+ MachineInstr *Result = *Instruction;
+ Result->reserveOperands(ExplicitOperands.size() + DefaultImplicit->size() +
+ ExtraImplicitOperands.size());
+
+ for (MachineOperand &Operand : ExplicitOperands) {
+ auto AddResult = Result->addOperand(std::move(Operand));
+ if (!AddResult)
+ return std::unexpected(AddResult.error());
+ }
+ for (MachineOperand &Operand : *DefaultImplicit) {
+ auto AddResult = Result->addOperand(std::move(Operand));
+ if (!AddResult)
+ return std::unexpected(AddResult.error());
+ }
+ for (MachineOperand &Operand : ExtraImplicitOperands) {
+ auto AddResult = Result->addOperand(std::move(Operand));
+ if (!AddResult)
+ return std::unexpected(AddResult.error());
+ }
+ for (const MachineOperandTie Tie : Ties) {
+ auto TieResult = Result->tieOperands(Tie.DefOperand, Tie.UseOperand);
+ if (!TieResult)
+ return std::unexpected(TieResult.error());
+ }
+ for (const MachineMemOperand *MemOperand : MemOperands) {
+ auto AddResult = Result->addMemOperand(*MemOperand);
+ if (!AddResult)
+ return std::unexpected(AddResult.error());
+ }
+
+ Result->setFlags(Flags);
+ if (Location)
+ Result->setSourceLocation(std::move(*Location));
+ if (Origin)
+ Result->setOrigin(*Origin);
+
+ Expected<void> InsertResult;
+ if (InsertBefore == nullptr)
+ InsertResult = InsertBlock->appendInstruction(*Result);
+ else
+ InsertResult = InsertBlock->insertInstructionBefore(*InsertBefore, *Result);
+ if (!InsertResult)
+ return std::unexpected(InsertResult.error());
+
+ IsBuilt = true;
+ return Result;
+}
+
+Expected<void> MachineIRBuilder::validateBlock(const MachineBasicBlock &Block) const {
+ if (&Block.function() != Function || !Block.isLinked()) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder insertion block is not linked to its function");
+ }
+ return {};
+}
+
+Expected<void> MachineIRBuilder::validateInstruction(const MachineInstr &Instruction) const {
+ if (&Instruction.function() != Function || Instruction.parent() == nullptr) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "builder insertion instruction is not linked to its function");
+ }
+ return {};
+}
+
+Expected<void> MachineIRBuilder::setInsertPoint(MachineBasicBlock &Block) {
+ auto Validation = validateBlock(Block);
+ if (!Validation)
+ return std::unexpected(Validation.error());
+ InsertBlock = &Block;
+ InsertBefore = nullptr;
+ return {};
+}
+
+Expected<void> MachineIRBuilder::setInsertPointBefore(MachineInstr &Instruction) {
+ auto Validation = validateInstruction(Instruction);
+ if (!Validation)
+ return std::unexpected(Validation.error());
+ InsertBlock = Instruction.parent();
+ InsertBefore = &Instruction;
+ return {};
+}
+
+Expected<void> MachineIRBuilder::setInsertPointAfter(MachineInstr &Instruction) {
+ auto Validation = validateInstruction(Instruction);
+ if (!Validation)
+ return std::unexpected(Validation.error());
+ InsertBlock = Instruction.parent();
+ InsertBefore = Instruction.next();
+ return {};
+}
+
+Expected<MachineInstrBuilder> MachineIRBuilder::buildInstr(Opcode InstructionOpcode) const {
+ if (InsertBlock == nullptr) {
+ return makeUnexpected(ErrorCode::InvalidArgument, "machine IR builder has no insertion point");
+ }
+ const InstructionDescriptor *Descriptor = Instructions->descriptor(InstructionOpcode);
+ if (Descriptor == nullptr) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "machine IR builder opcode is not registered");
+ }
+ auto BlockValidation = validateBlock(*InsertBlock);
+ if (!BlockValidation)
+ return std::unexpected(BlockValidation.error());
+ if (InsertBefore != nullptr && InsertBefore->parent() != InsertBlock) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "machine IR builder insertion cursor is stale");
+ }
+ return MachineInstrBuilder(*Function, *Instructions, *Descriptor, *InsertBlock, InsertBefore);
+}
+
+} // namespace rcc
diff --git a/backend/lib/CodeGen/MachineInstr.cpp b/backend/lib/CodeGen/MachineInstr.cpp
index 3692258..b201533 100644
--- a/backend/lib/CodeGen/MachineInstr.cpp
+++ b/backend/lib/CodeGen/MachineInstr.cpp
@@ -46,11 +46,11 @@ void MachineInstr::reserveOperands(std::size_t Capacity) {
Operands.reserve(Capacity);
}
-Expected<void> MachineInstr::addOperand(MachineOperand Operand) {
+Expected<void> MachineInstr::addOperand(MachineOperand &&Operand) {
return insertOperand(Operands.size(), std::move(Operand));
}
-Expected<void> MachineInstr::insertOperand(std::size_t Index, MachineOperand Operand) {
+Expected<void> MachineInstr::insertOperand(std::size_t Index, MachineOperand &&Operand) {
if (Index > Operands.size())
return makeUnexpected(ErrorCode::InvalidArgument, "operand insertion index is out of range");
if (Operand.Parent != nullptr)
@@ -93,9 +93,9 @@ Expected<void> MachineInstr::tieOperands(std::size_t DefIndex, std::size_t UseIn
MachineOperand &DefOperand = Operands[DefIndex];
MachineOperand &UseOperand = Operands[UseIndex];
if (!DefOperand.isRegister() || !UseOperand.isRegister() || !DefOperand.isDef() ||
- !UseOperand.isUse()) {
+ DefOperand.isUse() || !UseOperand.isUse() || UseOperand.isDef()) {
return makeUnexpected(ErrorCode::InvalidArgument,
- "tie must connect a register definition and use");
+ "tie must connect a pure register definition and use");
}
if (DefOperand.TiedOperandIndex || UseOperand.TiedOperandIndex) {
return makeUnexpected(ErrorCode::InvalidArgument,