diff options
Diffstat (limited to 'backend/lib/CodeGen')
| -rw-r--r-- | backend/lib/CodeGen/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | backend/lib/CodeGen/InstructionDescriptor.cpp | 223 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineIRBuilder.cpp | 537 | ||||
| -rw-r--r-- | backend/lib/CodeGen/MachineInstr.cpp | 8 |
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, |
