docs: document IR
This commit is contained in:
@@ -10,13 +10,26 @@
|
|||||||
namespace furlang {
|
namespace furlang {
|
||||||
namespace ir {
|
namespace ir {
|
||||||
|
|
||||||
// https://en.wikipedia.org/wiki/Basic_block
|
/**
|
||||||
|
* @brief Basic block.
|
||||||
|
*
|
||||||
|
* A basic block of IR instructions. https://en.wikipedia.org/wiki/Basic_block
|
||||||
|
*/
|
||||||
class block {
|
class block {
|
||||||
public:
|
public:
|
||||||
using value_type = std::unique_ptr<instruction>;
|
using value_type = std::unique_ptr<instruction>; /**< Value type */
|
||||||
public:
|
public:
|
||||||
block() = default;
|
block() = default;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Emplaces a new instruction.
|
||||||
|
*
|
||||||
|
* Emplaces a new instruction, if exit instruction hasn't been emplaced in this block yet.
|
||||||
|
*
|
||||||
|
* @tparam T Type of the instruction to emplace.
|
||||||
|
* @param args Arguments to call the constructor with.
|
||||||
|
* @return true if the instruction has been emplaced successfully.
|
||||||
|
*/
|
||||||
template <typename T, typename... Args, typename = std::enable_if_t<std::is_base_of_v<instruction, T>>>
|
template <typename T, typename... Args, typename = std::enable_if_t<std::is_base_of_v<instruction, T>>>
|
||||||
bool emplace(Args&&... args) {
|
bool emplace(Args&&... args) {
|
||||||
if (has_exit()) return false;
|
if (has_exit()) return false;
|
||||||
@@ -29,11 +42,39 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this block's instructions.
|
||||||
|
*
|
||||||
|
* @return The instructions.
|
||||||
|
*/
|
||||||
std::vector<value_type>& instructions() { return m_instructions; }
|
std::vector<value_type>& instructions() { return m_instructions; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this block's instructions.
|
||||||
|
*
|
||||||
|
* @return The instructions.
|
||||||
|
*/
|
||||||
const std::vector<value_type>& instructions() const { return m_instructions; }
|
const std::vector<value_type>& instructions() const { return m_instructions; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks whether an exit instruction has been emplaced in this block yet.
|
||||||
|
*
|
||||||
|
* @return true if the exit instruction has been emplaced.
|
||||||
|
*/
|
||||||
bool has_exit() const { return m_exit != nullptr; }
|
bool has_exit() const { return m_exit != nullptr; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this block's exit instruction.
|
||||||
|
*
|
||||||
|
* @return The exit instruction.
|
||||||
|
*/
|
||||||
value_type& exit() { return m_exit; }
|
value_type& exit() { return m_exit; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this block's exit instruction.
|
||||||
|
*
|
||||||
|
* @return The exit instruction.
|
||||||
|
*/
|
||||||
const value_type& exit() const { return m_exit; }
|
const value_type& exit() const { return m_exit; }
|
||||||
private:
|
private:
|
||||||
std::vector<value_type> m_instructions;
|
std::vector<value_type> m_instructions;
|
||||||
|
|||||||
@@ -9,20 +9,51 @@
|
|||||||
namespace furlang {
|
namespace furlang {
|
||||||
namespace ir {
|
namespace ir {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IR function.
|
||||||
|
*
|
||||||
|
* Consists of a name and blocks.
|
||||||
|
* @see block
|
||||||
|
*/
|
||||||
class function {
|
class function {
|
||||||
public:
|
public:
|
||||||
using value_type = std::shared_ptr<block>;
|
using value_type = std::shared_ptr<block>; /**< Value type. */
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new IR function.
|
||||||
|
*
|
||||||
|
* @param name Name to copy.
|
||||||
|
*/
|
||||||
function(const std::string& name)
|
function(const std::string& name)
|
||||||
: m_name(name) {}
|
: m_name(name) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new IR function.
|
||||||
|
*
|
||||||
|
* @param name Name to move.
|
||||||
|
*/
|
||||||
function(std::string&& name)
|
function(std::string&& name)
|
||||||
: m_name(std::move(name)) {}
|
: m_name(std::move(name)) {}
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this function's name.
|
||||||
|
*
|
||||||
|
* @return The name.
|
||||||
|
*/
|
||||||
const std::string& name() const { return m_name; }
|
const std::string& name() const { return m_name; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes and returns a new IR block.
|
||||||
|
*
|
||||||
|
* @return The new IR block.
|
||||||
|
*/
|
||||||
value_type push() { return m_blocks.emplace_back(std::make_shared<block>()); }
|
value_type push() { return m_blocks.emplace_back(std::make_shared<block>()); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this function's IR blocks.
|
||||||
|
*
|
||||||
|
* @return The IR blocks.
|
||||||
|
*/
|
||||||
const std::vector<value_type>& blocks() const { return m_blocks; }
|
const std::vector<value_type>& blocks() const { return m_blocks; }
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
|||||||
@@ -10,16 +10,25 @@
|
|||||||
namespace furlang {
|
namespace furlang {
|
||||||
namespace ir {
|
namespace ir {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IR instruction type.
|
||||||
|
*/
|
||||||
enum class instruction_t {
|
enum class instruction_t {
|
||||||
Alloca,
|
Alloca, /**< Unused */
|
||||||
Assign,
|
Assign, /**< Assign */
|
||||||
BinaryOp,
|
BinaryOp, /**< Binary operation */
|
||||||
Call,
|
Call, /**< Call */
|
||||||
Branch,
|
Branch, /**< Branch */
|
||||||
BranchCond,
|
BranchCond, /**< Conditional branch */
|
||||||
Return,
|
Return, /**< Return */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if an instruction type exits.
|
||||||
|
*
|
||||||
|
* @param type Instruction type.
|
||||||
|
* @return true if the instruction type exits.
|
||||||
|
*/
|
||||||
static inline bool is_exit_instruction(instruction_t type) {
|
static inline bool is_exit_instruction(instruction_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case instruction_t::Branch:
|
case instruction_t::Branch:
|
||||||
@@ -29,54 +38,137 @@ static inline bool is_exit_instruction(instruction_t type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IR instruction
|
||||||
|
*/
|
||||||
class instruction {
|
class instruction {
|
||||||
public:
|
public:
|
||||||
instruction() = default;
|
instruction() = default;
|
||||||
virtual ~instruction() = default;
|
virtual ~instruction() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
instruction(instruction&&) = default;
|
instruction(instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
instruction& operator=(instruction&&) = default;
|
instruction& operator=(instruction&&) = default;
|
||||||
|
|
||||||
instruction(const instruction&) = delete;
|
instruction(const instruction&) = delete;
|
||||||
|
|
||||||
instruction& operator=(const instruction&) = delete;
|
instruction& operator=(const instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's type.
|
||||||
|
*
|
||||||
|
* @return The type.
|
||||||
|
*/
|
||||||
virtual instruction_t type() const = 0;
|
virtual instruction_t type() const = 0;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Prints an instruction to an output stream.
|
||||||
|
*
|
||||||
|
* Equivalent to calling instruction.print(os).
|
||||||
|
*
|
||||||
|
* @param os Output stream.
|
||||||
|
* @param instruction Instruction to print.
|
||||||
|
* @return The output stream.
|
||||||
|
*/
|
||||||
friend std::ostream& operator<<(std::ostream& os, const instruction& instruction) { return instruction.print(os); }
|
friend std::ostream& operator<<(std::ostream& os, const instruction& instruction) { return instruction.print(os); }
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Prints this instruction to an output stream.
|
||||||
|
*
|
||||||
|
* @param os Output stream.
|
||||||
|
* @return The output stream.
|
||||||
|
*/
|
||||||
virtual std::ostream& print(std::ostream& os) const = 0;
|
virtual std::ostream& print(std::ostream& os) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Alloca instruction
|
||||||
|
*/
|
||||||
class alloca_instruction final : public instruction {
|
class alloca_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
alloca_instruction() {}
|
alloca_instruction() {}
|
||||||
|
|
||||||
~alloca_instruction() override = default;
|
~alloca_instruction() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
alloca_instruction(alloca_instruction&&) = default;
|
alloca_instruction(alloca_instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
alloca_instruction& operator=(alloca_instruction&&) = default;
|
alloca_instruction& operator=(alloca_instruction&&) = default;
|
||||||
|
|
||||||
alloca_instruction(const alloca_instruction&) = delete;
|
alloca_instruction(const alloca_instruction&) = delete;
|
||||||
|
|
||||||
alloca_instruction& operator=(const alloca_instruction&) = delete;
|
alloca_instruction& operator=(const alloca_instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's type.
|
||||||
|
*
|
||||||
|
* @return instruction_t::Alloca.
|
||||||
|
*/
|
||||||
instruction_t type() const override { return instruction_t::Alloca; }
|
instruction_t type() const override { return instruction_t::Alloca; }
|
||||||
protected:
|
protected:
|
||||||
std::ostream& print(std::ostream& os) const override { return os << "alloca"; }
|
std::ostream& print(std::ostream& os) const override { return os << "alloca"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assign instruction
|
||||||
|
*/
|
||||||
class assign_instruction final : public instruction {
|
class assign_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new assign instruction.
|
||||||
|
*
|
||||||
|
* @param src Source operand.
|
||||||
|
* @param dst Destination operand.
|
||||||
|
*/
|
||||||
assign_instruction(operand&& src, operand&& dst)
|
assign_instruction(operand&& src, operand&& dst)
|
||||||
: m_source(std::move(src)), m_destination(std::move(dst)) {}
|
: m_source(std::move(src)), m_destination(std::move(dst)) {}
|
||||||
|
|
||||||
~assign_instruction() override = default;
|
~assign_instruction() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
assign_instruction(assign_instruction&&) = default;
|
assign_instruction(assign_instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
assign_instruction& operator=(assign_instruction&&) = default;
|
assign_instruction& operator=(assign_instruction&&) = default;
|
||||||
|
|
||||||
assign_instruction(const assign_instruction&) = delete;
|
assign_instruction(const assign_instruction&) = delete;
|
||||||
|
|
||||||
assign_instruction& operator=(const assign_instruction&) = delete;
|
assign_instruction& operator=(const assign_instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's type.
|
||||||
|
*
|
||||||
|
* @return instruction_t::Assign.
|
||||||
|
*/
|
||||||
instruction_t type() const override { return instruction_t::Assign; }
|
instruction_t type() const override { return instruction_t::Assign; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's source.
|
||||||
|
*
|
||||||
|
* @return The source.
|
||||||
|
*/
|
||||||
const operand& source() const { return m_source; }
|
const operand& source() const { return m_source; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's destination.
|
||||||
|
*
|
||||||
|
* @return The destination.
|
||||||
|
*/
|
||||||
const operand& destination() const { return m_destination; }
|
const operand& destination() const { return m_destination; }
|
||||||
private:
|
private:
|
||||||
operand m_source;
|
operand m_source;
|
||||||
@@ -87,19 +179,22 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Binary operation instruction type
|
||||||
|
*/
|
||||||
enum class binary_op_instruction_t {
|
enum class binary_op_instruction_t {
|
||||||
Add,
|
Add, /**< Addition */
|
||||||
Sub,
|
Sub, /**< Subtraction */
|
||||||
Mul,
|
Mul, /**< Multiplication */
|
||||||
Div,
|
Div, /**< Division */
|
||||||
Mod,
|
Mod, /**< Modulo */
|
||||||
|
|
||||||
Eq,
|
Eq, /**< Equal */
|
||||||
NotEq,
|
NotEq, /**< Not equal */
|
||||||
LessThan,
|
LessThan, /**< Less than */
|
||||||
GreaterThan,
|
GreaterThan, /**< Greater than */
|
||||||
LessEq,
|
LessEq, /**< Less or equal */
|
||||||
GreaterEq,
|
GreaterEq, /**< Greater or equal */
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::ostream& operator<<(std::ostream& os, binary_op_instruction_t type) {
|
static inline std::ostream& operator<<(std::ostream& os, binary_op_instruction_t type) {
|
||||||
@@ -119,103 +214,242 @@ static inline std::ostream& operator<<(std::ostream& os, binary_op_instruction_t
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Binary operation instruction
|
||||||
|
*/
|
||||||
class binary_op_instruction final : public instruction {
|
class binary_op_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new binary operation instruction.
|
||||||
|
*
|
||||||
|
* @param type Operation type.
|
||||||
|
* @param lhs Left-hand-side operand.
|
||||||
|
* @param rhs Right-hand-side operand.
|
||||||
|
* @param dst Destination operand.
|
||||||
|
*/
|
||||||
binary_op_instruction(binary_op_instruction_t type, operand&& lhs, operand&& rhs, operand&& dst)
|
binary_op_instruction(binary_op_instruction_t type, operand&& lhs, operand&& rhs, operand&& dst)
|
||||||
: m_type(type), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)), m_dst(std::move(dst)) {}
|
: m_type(type), m_lhs(std::move(lhs)), m_rhs(std::move(rhs)), m_dst(std::move(dst)) {}
|
||||||
|
|
||||||
~binary_op_instruction() override = default;
|
~binary_op_instruction() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
binary_op_instruction(binary_op_instruction&&) = default;
|
binary_op_instruction(binary_op_instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
binary_op_instruction& operator=(binary_op_instruction&&) = default;
|
binary_op_instruction& operator=(binary_op_instruction&&) = default;
|
||||||
|
|
||||||
binary_op_instruction(const binary_op_instruction&) = delete;
|
binary_op_instruction(const binary_op_instruction&) = delete;
|
||||||
|
|
||||||
binary_op_instruction& operator=(const binary_op_instruction&) = delete;
|
binary_op_instruction& operator=(const binary_op_instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's type.
|
||||||
|
*
|
||||||
|
* @return instruction_t::BinaryOp.
|
||||||
|
*/
|
||||||
instruction_t type() const override { return instruction_t::BinaryOp; }
|
instruction_t type() const override { return instruction_t::BinaryOp; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's operation type.
|
||||||
|
*
|
||||||
|
* @return The operation type.
|
||||||
|
*/
|
||||||
binary_op_instruction_t op_type() const { return m_type; }
|
binary_op_instruction_t op_type() const { return m_type; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's left-hand-side operand.
|
||||||
|
*
|
||||||
|
* @return The operand.
|
||||||
|
*/
|
||||||
const operand& lhs() const { return m_lhs; }
|
const operand& lhs() const { return m_lhs; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's right-hand-side operand.
|
||||||
|
*
|
||||||
|
* @return The operand.
|
||||||
|
*/
|
||||||
const operand& rhs() const { return m_rhs; }
|
const operand& rhs() const { return m_rhs; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's destination operand.
|
||||||
|
*
|
||||||
|
* @return The operand.
|
||||||
|
*/
|
||||||
const operand& dst() const { return m_dst; }
|
const operand& dst() const { return m_dst; }
|
||||||
private:
|
private:
|
||||||
binary_op_instruction_t m_type;
|
binary_op_instruction_t m_type;
|
||||||
operand m_lhs;
|
operand m_lhs /**< Left-hand-side operand */;
|
||||||
operand m_rhs;
|
operand m_rhs /**< Right-hand-side operand */;
|
||||||
operand m_dst;
|
operand m_dst /**< Destination operand */;
|
||||||
protected:
|
protected:
|
||||||
std::ostream& print(std::ostream& os) const override {
|
std::ostream& print(std::ostream& os) const override {
|
||||||
return os << "binop(" << m_type << ") " << m_lhs << ", " << m_rhs << ", " << m_dst;
|
return os << "binop(" << m_type << ") " << m_lhs << ", " << m_rhs << ", " << m_dst;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using block_index = std::uint64_t;
|
using block_index = std::uint64_t; /**< IR block index alias */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Branch instruction
|
||||||
|
*/
|
||||||
class branch_instruction final : public instruction {
|
class branch_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new branch instruction.
|
||||||
|
*
|
||||||
|
* @param block Destination block index.
|
||||||
|
*/
|
||||||
branch_instruction(block_index block)
|
branch_instruction(block_index block)
|
||||||
: m_block(block) {}
|
: m_block(block) {}
|
||||||
|
|
||||||
~branch_instruction() override = default;
|
~branch_instruction() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
branch_instruction(branch_instruction&&) = default;
|
branch_instruction(branch_instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
branch_instruction& operator=(branch_instruction&&) = default;
|
branch_instruction& operator=(branch_instruction&&) = default;
|
||||||
|
|
||||||
branch_instruction(const branch_instruction&) = delete;
|
branch_instruction(const branch_instruction&) = delete;
|
||||||
|
|
||||||
branch_instruction& operator=(const branch_instruction&) = delete;
|
branch_instruction& operator=(const branch_instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's type.
|
||||||
|
*
|
||||||
|
* @return instruction_t::Branch.
|
||||||
|
*/
|
||||||
instruction_t type() const override { return instruction_t::Branch; }
|
instruction_t type() const override { return instruction_t::Branch; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's destination block index.
|
||||||
|
*
|
||||||
|
* @return The destination block index.
|
||||||
|
*/
|
||||||
block_index block() const { return m_block; }
|
block_index block() const { return m_block; }
|
||||||
private:
|
private:
|
||||||
block_index m_block;
|
block_index m_block; /**< Destination block index. */
|
||||||
protected:
|
protected:
|
||||||
std::ostream& print(std::ostream& os) const override { return os << "branch #" << m_block; }
|
std::ostream& print(std::ostream& os) const override { return os << "branch #" << m_block; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Conditional branch instruction
|
||||||
|
*/
|
||||||
class branch_cond_instruction final : public instruction {
|
class branch_cond_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new conditional branch instruction.
|
||||||
|
*
|
||||||
|
* @param condition Condition operand.
|
||||||
|
* @param ifBlock Destination block index.
|
||||||
|
* @param elseBlock Else block index.
|
||||||
|
*/
|
||||||
branch_cond_instruction(operand&& condition, block_index ifBlock, block_index elseBlock)
|
branch_cond_instruction(operand&& condition, block_index ifBlock, block_index elseBlock)
|
||||||
: m_condition(std::move(condition)), m_ifBlock(ifBlock), m_elseBlock(elseBlock) {}
|
: m_condition(std::move(condition)), m_ifBlock(ifBlock), m_elseBlock(elseBlock) {}
|
||||||
|
|
||||||
~branch_cond_instruction() override = default;
|
~branch_cond_instruction() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
branch_cond_instruction(branch_cond_instruction&&) = default;
|
branch_cond_instruction(branch_cond_instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
branch_cond_instruction& operator=(branch_cond_instruction&&) = default;
|
branch_cond_instruction& operator=(branch_cond_instruction&&) = default;
|
||||||
|
|
||||||
branch_cond_instruction(const branch_cond_instruction&) = delete;
|
branch_cond_instruction(const branch_cond_instruction&) = delete;
|
||||||
|
|
||||||
branch_cond_instruction& operator=(const branch_cond_instruction&) = delete;
|
branch_cond_instruction& operator=(const branch_cond_instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
instruction_t type() const override { return instruction_t::BranchCond; }
|
instruction_t type() const override { return instruction_t::BranchCond; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's condition operand.
|
||||||
|
*
|
||||||
|
* @return The operand.
|
||||||
|
*/
|
||||||
const operand& condition() const { return m_condition; }
|
const operand& condition() const { return m_condition; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's destination block index.
|
||||||
|
*
|
||||||
|
* @return The destination block index.
|
||||||
|
*/
|
||||||
block_index if_block() const { return m_ifBlock; }
|
block_index if_block() const { return m_ifBlock; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's else block index.
|
||||||
|
*
|
||||||
|
* @return The else block index.
|
||||||
|
*/
|
||||||
block_index else_block() const { return m_elseBlock; }
|
block_index else_block() const { return m_elseBlock; }
|
||||||
private:
|
private:
|
||||||
operand m_condition;
|
operand m_condition /**< Condition operand. */;
|
||||||
block_index m_ifBlock;
|
block_index m_ifBlock /**< Destination block index. */;
|
||||||
block_index m_elseBlock;
|
block_index m_elseBlock /**< Else block index. */;
|
||||||
protected:
|
protected:
|
||||||
std::ostream& print(std::ostream& os) const override {
|
std::ostream& print(std::ostream& os) const override {
|
||||||
return os << "branch_cond " << m_condition << ", #" << m_ifBlock << ", #" << m_elseBlock;
|
return os << "branch_cond " << m_condition << ", #" << m_ifBlock << ", #" << m_elseBlock;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return instruction
|
||||||
|
*/
|
||||||
class return_instruction final : public instruction {
|
class return_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
return_instruction() {}
|
return_instruction() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new return instruction.
|
||||||
|
*
|
||||||
|
* @param value Return value operand.
|
||||||
|
*/
|
||||||
return_instruction(operand&& value)
|
return_instruction(operand&& value)
|
||||||
: m_value(std::move(value)) {}
|
: m_value(std::move(value)) {}
|
||||||
|
|
||||||
~return_instruction() override = default;
|
~return_instruction() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
return_instruction(return_instruction&&) = default;
|
return_instruction(return_instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
return_instruction& operator=(return_instruction&&) = default;
|
return_instruction& operator=(return_instruction&&) = default;
|
||||||
|
|
||||||
return_instruction(const return_instruction&) = delete;
|
return_instruction(const return_instruction&) = delete;
|
||||||
|
|
||||||
return_instruction& operator=(const return_instruction&) = delete;
|
return_instruction& operator=(const return_instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's type.
|
||||||
|
*
|
||||||
|
* @return instruction_t::Return.
|
||||||
|
*/
|
||||||
instruction_t type() const override { return instruction_t::Return; }
|
instruction_t type() const override { return instruction_t::Return; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's return value operand.
|
||||||
|
*
|
||||||
|
* @return The operand.
|
||||||
|
*/
|
||||||
const std::optional<operand>& value() const { return m_value; }
|
const std::optional<operand>& value() const { return m_value; }
|
||||||
private:
|
private:
|
||||||
std::optional<operand> m_value;
|
std::optional<operand> m_value; /**< The return value operand. */
|
||||||
protected:
|
protected:
|
||||||
std::ostream& print(std::ostream& os) const override {
|
std::ostream& print(std::ostream& os) const override {
|
||||||
os << "return";
|
os << "return";
|
||||||
|
|||||||
@@ -9,18 +9,38 @@
|
|||||||
namespace furlang {
|
namespace furlang {
|
||||||
namespace ir {
|
namespace ir {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IR module
|
||||||
|
*/
|
||||||
class module {
|
class module {
|
||||||
public:
|
public:
|
||||||
using value_type = std::unique_ptr<function>;
|
using value_type = std::unique_ptr<function>; /**< Value type. */
|
||||||
public:
|
public:
|
||||||
module() = default;
|
module() = default;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Pushes and returns a new IR function.
|
||||||
|
*
|
||||||
|
* @param args Arguments to call the constructor with.
|
||||||
|
* @return The new IR function.
|
||||||
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
value_type& push(Args&&... args) {
|
value_type& push(Args&&... args) {
|
||||||
return m_functions.emplace_back(std::forward<Args>(args)...);
|
return m_functions.emplace_back(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this module's functions.
|
||||||
|
*
|
||||||
|
* @return The functions.
|
||||||
|
*/
|
||||||
std::vector<value_type>& functions() { return m_functions; }
|
std::vector<value_type>& functions() { return m_functions; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this module's functions.
|
||||||
|
*
|
||||||
|
* @return The functions.
|
||||||
|
*/
|
||||||
const std::vector<value_type>& functions() const { return m_functions; }
|
const std::vector<value_type>& functions() const { return m_functions; }
|
||||||
private:
|
private:
|
||||||
std::vector<value_type> m_functions;
|
std::vector<value_type> m_functions;
|
||||||
|
|||||||
@@ -8,19 +8,41 @@
|
|||||||
namespace furlang {
|
namespace furlang {
|
||||||
namespace ir {
|
namespace ir {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Operand type
|
||||||
|
*/
|
||||||
enum class operand_t {
|
enum class operand_t {
|
||||||
None,
|
None, /**< None */
|
||||||
Register,
|
Register, /**< Register */
|
||||||
Variable,
|
Variable, /**< Variable */
|
||||||
Integer,
|
Integer, /**< Integer */
|
||||||
String,
|
String, /**< String */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register operand alias.
|
||||||
|
* @see operand_t::Register
|
||||||
|
*/
|
||||||
using register_operand = std::uint32_t;
|
using register_operand = std::uint32_t;
|
||||||
|
/**
|
||||||
|
* @brief Variable operand alias.
|
||||||
|
* @see operand_t::Variable
|
||||||
|
*/
|
||||||
using variable_operand = std::string;
|
using variable_operand = std::string;
|
||||||
|
/**
|
||||||
|
* @brief Integer operand alias.
|
||||||
|
* @see operand_t::Integer
|
||||||
|
*/
|
||||||
using integer_operand = std::uint64_t;
|
using integer_operand = std::uint64_t;
|
||||||
|
/**
|
||||||
|
* @brief String operand alias.
|
||||||
|
* @see operand_t::String
|
||||||
|
*/
|
||||||
using string_operand = std::string;
|
using string_operand = std::string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief IR operand
|
||||||
|
*/
|
||||||
class operand {
|
class operand {
|
||||||
public:
|
public:
|
||||||
~operand() {
|
~operand() {
|
||||||
@@ -29,6 +51,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
operand(operand&& other) noexcept
|
operand(operand&& other) noexcept
|
||||||
: m_type(other.m_type) {
|
: m_type(other.m_type) {
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
@@ -49,6 +74,9 @@ public:
|
|||||||
other.m_value.destroy(other.m_type);
|
other.m_value.destroy(other.m_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor.
|
||||||
|
*/
|
||||||
operand& operator=(operand&& other) noexcept {
|
operand& operator=(operand&& other) noexcept {
|
||||||
if (this == &other) return *this;
|
if (this == &other) return *this;
|
||||||
m_type = other.m_type;
|
m_type = other.m_type;
|
||||||
@@ -74,6 +102,12 @@ public:
|
|||||||
operand(const operand&) = delete;
|
operand(const operand&) = delete;
|
||||||
operand& operator=(const operand&) = delete;
|
operand& operator=(const operand&) = delete;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new register operand.
|
||||||
|
*
|
||||||
|
* @param value Value of the new register operand.
|
||||||
|
* @return The register operand.
|
||||||
|
*/
|
||||||
static operand new_reg(register_operand value) {
|
static operand new_reg(register_operand value) {
|
||||||
operand operand;
|
operand operand;
|
||||||
operand.m_type = operand_t::Register;
|
operand.m_type = operand_t::Register;
|
||||||
@@ -81,6 +115,12 @@ public:
|
|||||||
return operand;
|
return operand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new variable operand.
|
||||||
|
*
|
||||||
|
* @param value Value of the new variable operand.
|
||||||
|
* @return The variable operand.
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static operand new_variable(T&& value) {
|
static operand new_variable(T&& value) {
|
||||||
operand operand;
|
operand operand;
|
||||||
@@ -89,6 +129,12 @@ public:
|
|||||||
return operand;
|
return operand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new integer operand.
|
||||||
|
*
|
||||||
|
* @param value Value of the new integer operand.
|
||||||
|
* @return The integer operand.
|
||||||
|
*/
|
||||||
static operand new_integer(integer_operand value) {
|
static operand new_integer(integer_operand value) {
|
||||||
operand operand;
|
operand operand;
|
||||||
operand.m_type = operand_t::Integer;
|
operand.m_type = operand_t::Integer;
|
||||||
@@ -96,6 +142,12 @@ public:
|
|||||||
return operand;
|
return operand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Construct a new string operand.
|
||||||
|
*
|
||||||
|
* @param value Value of the new string operand.
|
||||||
|
* @return The string operand.
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static operand new_string(T&& value) {
|
static operand new_string(T&& value) {
|
||||||
operand operand;
|
operand operand;
|
||||||
@@ -104,11 +156,34 @@ public:
|
|||||||
return operand;
|
return operand;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this operand's type.
|
||||||
|
*
|
||||||
|
* @return The operand type.
|
||||||
|
*/
|
||||||
operand_t type() const { return m_type; }
|
operand_t type() const { return m_type; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this operand's register value.
|
||||||
|
*
|
||||||
|
* @return The register value.
|
||||||
|
*/
|
||||||
register_operand reg() const { return m_value.reg; }
|
register_operand reg() const { return m_value.reg; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this operand's integer value.
|
||||||
|
*
|
||||||
|
* @return The integer value.
|
||||||
|
*/
|
||||||
integer_operand integer() const { return m_value.integer; }
|
integer_operand integer() const { return m_value.integer; }
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Prints an operand to an output stream.
|
||||||
|
*
|
||||||
|
* @param os Output stream.
|
||||||
|
* @param operand Operand to print.
|
||||||
|
* @return The output stream.
|
||||||
|
*/
|
||||||
friend std::ostream& operator<<(std::ostream& os, const operand& operand) {
|
friend std::ostream& operator<<(std::ostream& os, const operand& operand) {
|
||||||
switch (operand.m_type) {
|
switch (operand.m_type) {
|
||||||
case operand_t::None: return os << "none";
|
case operand_t::None: return os << "none";
|
||||||
|
|||||||
Reference in New Issue
Block a user