aboutsummaryrefslogtreecommitdiff
path: root/backend/lib/CodeGen/MachineFunction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lib/CodeGen/MachineFunction.cpp')
-rw-r--r--backend/lib/CodeGen/MachineFunction.cpp286
1 files changed, 286 insertions, 0 deletions
diff --git a/backend/lib/CodeGen/MachineFunction.cpp b/backend/lib/CodeGen/MachineFunction.cpp
new file mode 100644
index 0000000..b870858
--- /dev/null
+++ b/backend/lib/CodeGen/MachineFunction.cpp
@@ -0,0 +1,286 @@
+// 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 <limits>
+#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)...);
+ auto DestroyObject = [](ObjectT *TypedObject) noexcept { std::destroy_at(TypedObject); };
+ std::unique_ptr<ObjectT, decltype(DestroyObject)> ConstructionGuard(Object, DestroyObject);
+ Destructors.push_back(DestructorRecord{
+ Object,
+ [](void *RawObject) noexcept { std::destroy_at(static_cast<ObjectT *>(RawObject)); },
+ });
+ return ConstructionGuard.release();
+ }
+
+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 (!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), JumpTables(*this),
+ 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<void> MachineFunction::setTargetState(TargetFunctionState State) {
+ if (TargetState.hasValue()) {
+ return makeUnexpected(ErrorCode::InvalidArgument, "machine function already has target state");
+ }
+ auto Verification = State.verify();
+ if (!Verification)
+ return std::unexpected(Verification.error());
+ TargetState = std::move(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)
+ 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::moveBlockBefore(MachineBasicBlock &Position,
+ MachineBasicBlock &Block) {
+ if (Position.OwnerFunction != this || Block.OwnerFunction != this || !Position.IsLinked ||
+ !Block.IsLinked) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "layout move requires two linked blocks in the same function");
+ }
+ if (&Position == &Block || Block.NextBlock == &Position)
+ return {};
+
+ 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.PreviousBlock = Position.PreviousBlock;
+ Block.NextBlock = &Position;
+ if (Position.PreviousBlock != nullptr)
+ Position.PreviousBlock->NextBlock = &Block;
+ else
+ FirstBlock = &Block;
+ Position.PreviousBlock = &Block;
+ renumberBlocks();
+ return {};
+}
+
+Expected<void> MachineFunction::moveBlockAfter(MachineBasicBlock &Position,
+ MachineBasicBlock &Block) {
+ if (Position.OwnerFunction != this || Block.OwnerFunction != this || !Position.IsLinked ||
+ !Block.IsLinked) {
+ return makeUnexpected(ErrorCode::InvalidArgument,
+ "layout move requires two linked blocks in the same function");
+ }
+ if (&Position == &Block || Position.NextBlock == &Block)
+ return {};
+
+ 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.PreviousBlock = &Position;
+ Block.NextBlock = Position.NextBlock;
+ if (Position.NextBlock != nullptr)
+ Position.NextBlock->PreviousBlock = &Block;
+ else
+ LastBlock = &Block;
+ Position.NextBlock = &Block;
+ 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