diff options
Diffstat (limited to 'backend/lib/CodeGen/MachineFunction.cpp')
| -rw-r--r-- | backend/lib/CodeGen/MachineFunction.cpp | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/backend/lib/CodeGen/MachineFunction.cpp b/backend/lib/CodeGen/MachineFunction.cpp new file mode 100644 index 0000000..e19c115 --- /dev/null +++ b/backend/lib/CodeGen/MachineFunction.cpp @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rcc/CodeGen/MachineFunction.h" + +#include "rcc/CodeGen/MachineBasicBlock.h" +#include "rcc/CodeGen/MachineCFGUpdater.h" +#include "rcc/CodeGen/MachineInstr.h" +#include "rcc/CodeGen/MachineMemOperand.h" + +#include <algorithm> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <memory_resource> +#include <new> +#include <utility> +#include <vector> + +namespace rcc { + +class MachineArena final { +public: + MachineArena() = default; + MachineArena(const MachineArena &) = delete; + MachineArena &operator=(const MachineArena &) = delete; + MachineArena(MachineArena &&) = delete; + MachineArena &operator=(MachineArena &&) = delete; + + ~MachineArena() { + for (auto Position = Destructors.rbegin(); Position != Destructors.rend(); ++Position) + Position->Destroy(Position->Object); + } + + template <typename ObjectT, typename... ArgumentTs> + [[nodiscard]] ObjectT *create(ArgumentTs &&...Arguments) { + void *Storage = Resource.allocate(sizeof(ObjectT), alignof(ObjectT)); + ObjectT *Object = ::new (Storage) ObjectT(std::forward<ArgumentTs>(Arguments)...); + try { + Destructors.push_back(DestructorRecord{ + Object, + [](void *RawObject) noexcept { std::destroy_at(static_cast<ObjectT *>(RawObject)); }, + }); + } catch (...) { + std::destroy_at(Object); + throw; + } + return Object; + } + +private: + struct DestructorRecord final { + void *Object; + void (*Destroy)(void *) noexcept; + }; + + std::pmr::monotonic_buffer_resource Resource; + std::vector<DestructorRecord> Destructors; +}; + +Expected<std::unique_ptr<MachineFunction>> +MachineFunction::create(std::string Name, MachineFunctionStableID StableID) { + if (Name.empty()) + return makeUnexpected(ErrorCode::InvalidArgument, "machine function name cannot be empty"); + if (!StableID.isValid()) + return makeUnexpected(ErrorCode::InvalidArgument, "machine function StableID must be valid"); + return std::unique_ptr<MachineFunction>(new MachineFunction(std::move(Name), StableID)); +} + +MachineFunction::MachineFunction(std::string Name, MachineFunctionStableID StableID) + : Name(std::move(Name)), StableID(StableID), Arena(std::make_unique<MachineArena>()) {} + +MachineFunction::~MachineFunction() { + for (MachineBasicBlock *Block = FirstBlock; Block != nullptr; Block = Block->NextBlock) { + Block->clearInstructions(); + Block->Predecessors.clear(); + Block->Successors.clear(); + } +} + +Expected<MachineBasicBlock *> MachineFunction::createBasicBlock() { + auto ID = BlockIDGenerator.allocate(); + if (!ID) + return std::unexpected(ID.error()); + MachineBasicBlock *Block = Arena->create<MachineBasicBlock>(*this, *ID); + AllBlocks.push_back(Block); + return Block; +} + +Expected<MachineInstr *> MachineFunction::createInstruction(Opcode InstructionOpcode) { + if (!InstructionOpcode.isValid()) + return makeUnexpected(ErrorCode::InvalidArgument, "machine opcode must be nonzero"); + + auto ID = InstrIDGenerator.allocate(); + if (!ID) + return std::unexpected(ID.error()); + MachineInstr *Instruction = Arena->create<MachineInstr>(*this, InstructionOpcode, *ID); + AllInstructions.push_back(Instruction); + return Instruction; +} + +Expected<const MachineMemOperand *> +MachineFunction::createMemOperand(MachineMemOperandDesc Description) { + auto MemOperand = MachineMemOperand::create(std::move(Description)); + if (!MemOperand) + return std::unexpected(MemOperand.error()); + + const MachineMemOperand *Stored = Arena->create<MachineMemOperand>(std::move(*MemOperand)); + AllMemOperands.push_back(Stored); + return Stored; +} + +Expected<void> MachineFunction::appendBlock(MachineBasicBlock &Block) { + if (Block.OwnerFunction != this) + return makeUnexpected(ErrorCode::InvalidArgument, + "basic block belongs to another machine function"); + if (Block.IsLinked) + return makeUnexpected(ErrorCode::InvalidArgument, "basic block is already linked"); + + Block.PreviousBlock = LastBlock; + Block.NextBlock = nullptr; + if (LastBlock != nullptr) + LastBlock->NextBlock = &Block; + else + FirstBlock = &Block; + LastBlock = &Block; + Block.IsLinked = true; + renumberBlocks(); + return {}; +} + +Expected<void> MachineFunction::insertBlockBefore(MachineBasicBlock &Position, + MachineBasicBlock &Block) { + if (Position.OwnerFunction != this || !Position.IsLinked) + return makeUnexpected(ErrorCode::InvalidArgument, + "block insertion position is not linked to this function"); + if (Block.OwnerFunction != this || Block.IsLinked) + return makeUnexpected(ErrorCode::InvalidArgument, + "inserted block is linked or belongs to another function"); + + Block.PreviousBlock = Position.PreviousBlock; + Block.NextBlock = &Position; + if (Position.PreviousBlock != nullptr) + Position.PreviousBlock->NextBlock = &Block; + else + FirstBlock = &Block; + Position.PreviousBlock = &Block; + Block.IsLinked = true; + renumberBlocks(); + return {}; +} + +Expected<void> MachineFunction::removeBlock(MachineBasicBlock &Block) { + if (Block.OwnerFunction != this || !Block.IsLinked) + return makeUnexpected(ErrorCode::InvalidArgument, + "removed block is not linked to this function"); + if (!Block.Predecessors.empty() || !Block.Successors.empty()) { + return makeUnexpected(ErrorCode::VerificationError, + "disconnect CFG edges before removing a basic block"); + } + + Block.clearInstructions(); + if (Block.PreviousBlock != nullptr) + Block.PreviousBlock->NextBlock = Block.NextBlock; + else + FirstBlock = Block.NextBlock; + if (Block.NextBlock != nullptr) + Block.NextBlock->PreviousBlock = Block.PreviousBlock; + else + LastBlock = Block.PreviousBlock; + + Block.IsLinked = false; + Block.PreviousBlock = nullptr; + Block.NextBlock = nullptr; + Block.DenseNumber.reset(); + Block.LayoutIndex.reset(); + renumberBlocks(); + return {}; +} + +std::size_t MachineFunction::blockCount() const noexcept { + std::size_t Count = 0; + for (const MachineBasicBlock *Block = FirstBlock; Block != nullptr; Block = Block->next()) { + ++Count; + } + return Count; +} + +bool MachineFunction::ownsMemOperand(const MachineMemOperand &MemOperand) const noexcept { + return std::ranges::find(AllMemOperands, &MemOperand) != AllMemOperands.end(); +} + +MachineCFGUpdater MachineFunction::cfgUpdater() noexcept { + return MachineCFGUpdater(*this); +} + +void MachineFunction::renumberBlocks() noexcept { + std::uint32_t Number = 0; + for (MachineBasicBlock *Block = FirstBlock; Block != nullptr; Block = Block->NextBlock) { + Block->DenseNumber = Number; + Block->LayoutIndex = Number; + ++Number; + } +} + +} // namespace rcc |
