feat: introduce pointerof operation
Introduce pointerof operation and do some side-quests along the way. Refs: #34 Closes: #17
This commit is contained in:
@@ -113,6 +113,7 @@ enum class unaryop_expression_node_t {
|
|||||||
PostfixIncrement, /**< Postfix increment */
|
PostfixIncrement, /**< Postfix increment */
|
||||||
PrefixDecrement, /**< Prefix decrement */
|
PrefixDecrement, /**< Prefix decrement */
|
||||||
PostfixDecrement, /**< Postfix decrement */
|
PostfixDecrement, /**< Postfix decrement */
|
||||||
|
Pointerof, /**< Pointerof */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -147,16 +147,17 @@ static inline std::string operator+(const std::string& str, token_t type) {
|
|||||||
* @brief Keyword token.
|
* @brief Keyword token.
|
||||||
*/
|
*/
|
||||||
enum class keyword_token {
|
enum class keyword_token {
|
||||||
None, /**< None */
|
None, /**< None */
|
||||||
Func, /**< `func` */
|
Func, /**< `func` */
|
||||||
Return, /**< `return` */
|
Return, /**< `return` */
|
||||||
If, /**< `if` */
|
If, /**< `if` */
|
||||||
Else, /**< `else` */
|
Else, /**< `else` */
|
||||||
While, /**< `while` */
|
While, /**< `while` */
|
||||||
Import, /**< `import` */
|
Import, /**< `import` */
|
||||||
Native, /**< `native` */
|
Native, /**< `native` */
|
||||||
Public, /**< `public` */
|
Public, /**< `public` */
|
||||||
Private, /**< `private` */
|
Private, /**< `private` */
|
||||||
|
Pointerof, /**< `pointerof` */
|
||||||
|
|
||||||
Int32, /**< `int32` */
|
Int32, /**< `int32` */
|
||||||
};
|
};
|
||||||
@@ -173,6 +174,7 @@ static inline std::ostream& operator<<(std::ostream& os, keyword_token keyword)
|
|||||||
case keyword_token::Native: return os << "native";
|
case keyword_token::Native: return os << "native";
|
||||||
case keyword_token::Public: return os << "public";
|
case keyword_token::Public: return os << "public";
|
||||||
case keyword_token::Private: return os << "private";
|
case keyword_token::Private: return os << "private";
|
||||||
|
case keyword_token::Pointerof: return os << "pointerof";
|
||||||
case keyword_token::Int32: return os << "int32";
|
case keyword_token::Int32: return os << "int32";
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
@@ -190,6 +192,7 @@ static inline std::string operator+(const std::string& str, keyword_token keywor
|
|||||||
case keyword_token::Native: return str + "native";
|
case keyword_token::Native: return str + "native";
|
||||||
case keyword_token::Public: return str + "public";
|
case keyword_token::Public: return str + "public";
|
||||||
case keyword_token::Private: return str + "private";
|
case keyword_token::Private: return str + "private";
|
||||||
|
case keyword_token::Pointerof: return str + "pointerof";
|
||||||
case keyword_token::Int32: return str + "int32";
|
case keyword_token::Int32: return str + "int32";
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ std::ostream& operator<<(std::ostream& os, unaryop_expression_node_t type) {
|
|||||||
case unaryop_expression_node_t::PostfixIncrement: return os << "++";
|
case unaryop_expression_node_t::PostfixIncrement: return os << "++";
|
||||||
case unaryop_expression_node_t::PrefixDecrement:
|
case unaryop_expression_node_t::PrefixDecrement:
|
||||||
case unaryop_expression_node_t::PostfixDecrement: return os << "--";
|
case unaryop_expression_node_t::PostfixDecrement: return os << "--";
|
||||||
|
case unaryop_expression_node_t::Pointerof: return os << "pointerof";
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
@@ -54,6 +55,7 @@ std::ostream& unary_op_expression_node::print(std::ostream& os) const {
|
|||||||
case unaryop_expression_node_t::PrefixDecrement: return os << '(' << m_type << *m_node << ')';
|
case unaryop_expression_node_t::PrefixDecrement: return os << '(' << m_type << *m_node << ')';
|
||||||
case unaryop_expression_node_t::PostfixIncrement:
|
case unaryop_expression_node_t::PostfixIncrement:
|
||||||
case unaryop_expression_node_t::PostfixDecrement: return os << '(' << *m_node << m_type << ')';
|
case unaryop_expression_node_t::PostfixDecrement: return os << '(' << *m_node << m_type << ')';
|
||||||
|
case unaryop_expression_node_t::Pointerof: return os << "pointerof " << *m_node;
|
||||||
}
|
}
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-17
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "furlang/ir/function.hpp"
|
#include "furlang/ir/function.hpp"
|
||||||
#include "furlang/ir/instruction.hpp"
|
#include "furlang/ir/instruction.hpp"
|
||||||
#include "furvm/function.hpp"
|
|
||||||
#include "furvm/fwd.hpp"
|
#include "furvm/fwd.hpp"
|
||||||
|
|
||||||
#include <furvm/instruction.hpp>
|
#include <furvm/instruction.hpp>
|
||||||
@@ -56,21 +55,26 @@ void furvm_generator::generate_function(furvm::mod& mod, const furlang::ir::func
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline furvm::instruction_t binary_op_type(furlang::ir::binary_op_instruction_t type) {
|
static inline furvm::instruction_t op_type(furlang::ir::instruction_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case furlang::ir::binary_op_instruction_t::Add: return furvm::instruction_t::Add;
|
// Unary
|
||||||
case furlang::ir::binary_op_instruction_t::Sub: return furvm::instruction_t::Sub;
|
case furlang::ir::instruction_t::Pointerof: return furvm::instruction_t::Pointerof;
|
||||||
case furlang::ir::binary_op_instruction_t::Mul: return furvm::instruction_t::Mul;
|
|
||||||
case furlang::ir::binary_op_instruction_t::Div: return furvm::instruction_t::Div;
|
// Binary
|
||||||
case furlang::ir::binary_op_instruction_t::Mod: return furvm::instruction_t::Mod;
|
case furlang::ir::instruction_t::Add: return furvm::instruction_t::Add;
|
||||||
case furlang::ir::binary_op_instruction_t::Eq: return furvm::instruction_t::Equals;
|
case furlang::ir::instruction_t::Sub: return furvm::instruction_t::Sub;
|
||||||
case furlang::ir::binary_op_instruction_t::NotEq: return furvm::instruction_t::NotEquals;
|
case furlang::ir::instruction_t::Mul: return furvm::instruction_t::Mul;
|
||||||
case furlang::ir::binary_op_instruction_t::LessThan: return furvm::instruction_t::LessThan;
|
case furlang::ir::instruction_t::Div: return furvm::instruction_t::Div;
|
||||||
case furlang::ir::binary_op_instruction_t::GreaterThan: return furvm::instruction_t::GreaterThan;
|
case furlang::ir::instruction_t::Mod: return furvm::instruction_t::Mod;
|
||||||
case furlang::ir::binary_op_instruction_t::LessEq: return furvm::instruction_t::LessEqual;
|
case furlang::ir::instruction_t::Eq: return furvm::instruction_t::Equals;
|
||||||
case furlang::ir::binary_op_instruction_t::GreaterEq: return furvm::instruction_t::GreaterEqual;
|
case furlang::ir::instruction_t::NotEq: return furvm::instruction_t::NotEquals;
|
||||||
|
case furlang::ir::instruction_t::LessThan: return furvm::instruction_t::LessThan;
|
||||||
|
case furlang::ir::instruction_t::GreaterThan: return furvm::instruction_t::GreaterThan;
|
||||||
|
case furlang::ir::instruction_t::LessEq: return furvm::instruction_t::LessEqual;
|
||||||
|
case furlang::ir::instruction_t::GreaterEq: return furvm::instruction_t::GreaterEqual;
|
||||||
|
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
}
|
}
|
||||||
throw std::runtime_error("unreachable");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void furvm_generator::generate_instruction(furvm::mod& mod,
|
void furvm_generator::generate_instruction(furvm::mod& mod,
|
||||||
@@ -90,9 +94,30 @@ void furvm_generator::generate_instruction(furvm::mod& mod,
|
|||||||
mod.bytecode().push_back((var >> 8) & 0xFF);
|
mod.bytecode().push_back((var >> 8) & 0xFF);
|
||||||
static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed");
|
static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed");
|
||||||
} break;
|
} break;
|
||||||
case furlang::ir::instruction_t::BinaryOp: {
|
case furlang::ir::instruction_t::Add:
|
||||||
const auto& op = dynamic_cast<const furlang::ir::binary_op_instruction&>(instr);
|
case furlang::ir::instruction_t::Sub:
|
||||||
mod.bytecode().push_back(static_cast<furvm::byte>(binary_op_type(op.op_type())));
|
case furlang::ir::instruction_t::Mul:
|
||||||
|
case furlang::ir::instruction_t::Div:
|
||||||
|
case furlang::ir::instruction_t::Mod:
|
||||||
|
case furlang::ir::instruction_t::Eq:
|
||||||
|
case furlang::ir::instruction_t::NotEq:
|
||||||
|
case furlang::ir::instruction_t::LessThan:
|
||||||
|
case furlang::ir::instruction_t::GreaterThan:
|
||||||
|
case furlang::ir::instruction_t::LessEq:
|
||||||
|
case furlang::ir::instruction_t::GreaterEq: {
|
||||||
|
mod.bytecode().push_back(static_cast<furvm::byte>(op_type(instr.type())));
|
||||||
|
|
||||||
|
if (ctx.variables.find(instr.destination().reg()) == ctx.variables.end()) {
|
||||||
|
ctx.variables[instr.destination().reg()] = ctx.variableCounter++;
|
||||||
|
}
|
||||||
|
auto var = ctx.variables[instr.destination().reg()];
|
||||||
|
mod.bytecode().push_back(static_cast<furvm::byte>(furvm::instruction_t::Store));
|
||||||
|
mod.bytecode().push_back((var >> 0) & 0xFF);
|
||||||
|
mod.bytecode().push_back((var >> 8) & 0xFF);
|
||||||
|
static_assert(sizeof(var) == 2, "sizeof(furvm::variable_t) has changed");
|
||||||
|
} break;
|
||||||
|
case furlang::ir::instruction_t::Pointerof: {
|
||||||
|
mod.bytecode().push_back(static_cast<furvm::byte>(op_type(instr.type())));
|
||||||
|
|
||||||
if (ctx.variables.find(instr.destination().reg()) == ctx.variables.end()) {
|
if (ctx.variables.find(instr.destination().reg()) == ctx.variables.end()) {
|
||||||
ctx.variables[instr.destination().reg()] = ctx.variableCounter++;
|
ctx.variables[instr.destination().reg()] = ctx.variableCounter++;
|
||||||
|
|||||||
@@ -132,23 +132,35 @@ void ir_generator::visit(const ast::var_read_expression_node& node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ir_generator::visit(const ast::unary_op_expression_node& node) {
|
static inline furlang::ir::instruction_t unary_op_instruction_t(ast::unaryop_expression_node_t type) {
|
||||||
throw std::runtime_error("unimplemented");
|
switch (type) {
|
||||||
|
case ast::unaryop_expression_node_t::Pointerof: return furlang::ir::instruction_t::Pointerof;
|
||||||
|
default: throw std::runtime_error("unimplemented");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline furlang::ir::binary_op_instruction_t binary_op_instruction_t(ast::binop_expression_node_t type) {
|
void ir_generator::visit(const ast::unary_op_expression_node& node) {
|
||||||
|
node.get_node()->accept(*this);
|
||||||
|
ir_register src = m_registerCounter - 1;
|
||||||
|
ir_register dst = m_registerCounter++;
|
||||||
|
push<furlang::ir::unary_instruction>(unary_op_instruction_t(node.type()),
|
||||||
|
ir::operand::new_reg(src),
|
||||||
|
ir::operand::new_reg(dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline furlang::ir::instruction_t binary_op_instruction_t(ast::binop_expression_node_t type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ast::binop_expression_node_t::Add: return furlang::ir::binary_op_instruction_t::Add;
|
case ast::binop_expression_node_t::Add: return furlang::ir::instruction_t::Add;
|
||||||
case ast::binop_expression_node_t::Sub: return furlang::ir::binary_op_instruction_t::Sub;
|
case ast::binop_expression_node_t::Sub: return furlang::ir::instruction_t::Sub;
|
||||||
case ast::binop_expression_node_t::Mul: return furlang::ir::binary_op_instruction_t::Mul;
|
case ast::binop_expression_node_t::Mul: return furlang::ir::instruction_t::Mul;
|
||||||
case ast::binop_expression_node_t::Div: return furlang::ir::binary_op_instruction_t::Div;
|
case ast::binop_expression_node_t::Div: return furlang::ir::instruction_t::Div;
|
||||||
case ast::binop_expression_node_t::Mod: return furlang::ir::binary_op_instruction_t::Mod;
|
case ast::binop_expression_node_t::Mod: return furlang::ir::instruction_t::Mod;
|
||||||
case ast::binop_expression_node_t::Equal: return furlang::ir::binary_op_instruction_t::Eq;
|
case ast::binop_expression_node_t::Equal: return furlang::ir::instruction_t::Eq;
|
||||||
case ast::binop_expression_node_t::NotEqual: return furlang::ir::binary_op_instruction_t::NotEq;
|
case ast::binop_expression_node_t::NotEqual: return furlang::ir::instruction_t::NotEq;
|
||||||
case ast::binop_expression_node_t::LessThan: return furlang::ir::binary_op_instruction_t::LessThan;
|
case ast::binop_expression_node_t::LessThan: return furlang::ir::instruction_t::LessThan;
|
||||||
case ast::binop_expression_node_t::GreaterThan: return furlang::ir::binary_op_instruction_t::GreaterThan;
|
case ast::binop_expression_node_t::GreaterThan: return furlang::ir::instruction_t::GreaterThan;
|
||||||
case ast::binop_expression_node_t::LessEqual: return furlang::ir::binary_op_instruction_t::LessEq;
|
case ast::binop_expression_node_t::LessEqual: return furlang::ir::instruction_t::LessEq;
|
||||||
case ast::binop_expression_node_t::GreaterEqual: return furlang::ir::binary_op_instruction_t::GreaterEq;
|
case ast::binop_expression_node_t::GreaterEqual: return furlang::ir::instruction_t::GreaterEq;
|
||||||
case ast::binop_expression_node_t::None:
|
case ast::binop_expression_node_t::None:
|
||||||
default: throw std::runtime_error("unreachable");
|
default: throw std::runtime_error("unreachable");
|
||||||
}
|
}
|
||||||
@@ -160,7 +172,7 @@ void ir_generator::visit(const ast::binary_op_expression_node& node) {
|
|||||||
node.rhs()->accept(*this);
|
node.rhs()->accept(*this);
|
||||||
ir_register rhs = m_registerCounter - 1;
|
ir_register rhs = m_registerCounter - 1;
|
||||||
ir_register dst = m_registerCounter++;
|
ir_register dst = m_registerCounter++;
|
||||||
push<furlang::ir::binary_op_instruction>(binary_op_instruction_t(node.type()),
|
push<furlang::ir::binary_instruction>(binary_op_instruction_t(node.type()),
|
||||||
ir::operand::new_reg(lhs),
|
ir::operand::new_reg(lhs),
|
||||||
ir::operand::new_reg(rhs),
|
ir::operand::new_reg(rhs),
|
||||||
ir::operand::new_reg(dst));
|
ir::operand::new_reg(dst));
|
||||||
@@ -176,7 +188,7 @@ void ir_generator::visit(const ast::var_assign_expression_node& node) {
|
|||||||
|
|
||||||
auto compound = node.compound();
|
auto compound = node.compound();
|
||||||
if (compound != ast::binop_expression_node_t::None) {
|
if (compound != ast::binop_expression_node_t::None) {
|
||||||
push<ir::binary_op_instruction>(binary_op_instruction_t(compound),
|
push<ir::binary_instruction>(binary_op_instruction_t(compound),
|
||||||
ir::operand::new_reg(reg),
|
ir::operand::new_reg(reg),
|
||||||
ir::operand::new_reg(rhs),
|
ir::operand::new_reg(rhs),
|
||||||
ir::operand::new_reg(reg));
|
ir::operand::new_reg(reg));
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ token_r lexer::next_token() {
|
|||||||
{ "native", keyword_token::Native },
|
{ "native", keyword_token::Native },
|
||||||
{ "public", keyword_token::Public },
|
{ "public", keyword_token::Public },
|
||||||
{ "private", keyword_token::Private },
|
{ "private", keyword_token::Private },
|
||||||
|
{ "pointerof", keyword_token::Pointerof },
|
||||||
{ "int32", keyword_token::Int32 },
|
{ "int32", keyword_token::Int32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+26
-10
@@ -9,6 +9,7 @@
|
|||||||
#include "furc/front/token.hpp"
|
#include "furc/front/token.hpp"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -313,27 +314,42 @@ struct unaryop_info {
|
|||||||
std::uint32_t precedence;
|
std::uint32_t precedence;
|
||||||
};
|
};
|
||||||
|
|
||||||
ast::expression_node_r parser::parse_expression_unary(std::uint32_t precedence) {
|
static inline std::optional<unaryop_info> get_unaryop_info(const token_r& token) {
|
||||||
static std::unordered_map<token_t, unaryop_info> s_prefixes = {
|
static std::unordered_map<token_t, unaryop_info> s_prefixes = {
|
||||||
{ token_t::Plus, unaryop_info{ ast::unaryop_expression_node_t::Positive, 3 } },
|
{ token_t::Plus, unaryop_info{ ast::unaryop_expression_node_t::Positive, 2 } },
|
||||||
{ token_t::Minus, unaryop_info{ ast::unaryop_expression_node_t::Negative, 3 } },
|
{ token_t::Minus, unaryop_info{ ast::unaryop_expression_node_t::Negative, 2 } },
|
||||||
{ token_t::DPlus, unaryop_info{ ast::unaryop_expression_node_t::PrefixIncrement, 2 } },
|
{ token_t::DPlus, unaryop_info{ ast::unaryop_expression_node_t::PrefixIncrement, 2 } },
|
||||||
{ token_t::DMinus, unaryop_info{ ast::unaryop_expression_node_t::PrefixDecrement, 2 } },
|
{ token_t::DMinus, unaryop_info{ ast::unaryop_expression_node_t::PrefixDecrement, 2 } },
|
||||||
};
|
};
|
||||||
|
static std::unordered_map<keyword_token, unaryop_info> s_keywords = {
|
||||||
|
{ keyword_token::Pointerof, unaryop_info{ ast::unaryop_expression_node_t::Pointerof, 2 } },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (token->type == token_t::Keyword) {
|
||||||
|
auto it = s_keywords.find(token->value.keyword);
|
||||||
|
if (it == s_keywords.end()) return {};
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = s_prefixes.find(token->type);
|
||||||
|
if (it == s_prefixes.end()) return {};
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast::expression_node_r parser::parse_expression_unary(std::uint32_t precedence) {
|
||||||
std::shared_ptr<ast::unary_op_expression_node> result;
|
std::shared_ptr<ast::unary_op_expression_node> result;
|
||||||
while (true) {
|
while (true) {
|
||||||
auto it = s_prefixes.find(peek_token()->type);
|
auto opt = get_unaryop_info(peek_token());
|
||||||
if (it == s_prefixes.end()) break;
|
if (!opt.has_value()) break;
|
||||||
auto current = it->second;
|
unaryop_info current = opt.value();
|
||||||
if (current.precedence >= precedence) break;
|
if (current.precedence >= precedence) break;
|
||||||
auto token = next_token();
|
auto token = next_token();
|
||||||
|
|
||||||
ast::expression_node_p expression;
|
ast::expression_node_p expression;
|
||||||
|
|
||||||
auto nextIt = s_prefixes.find(peek_token()->type);
|
opt = get_unaryop_info(peek_token());
|
||||||
if (nextIt != s_prefixes.end()) {
|
if (opt.has_value()) {
|
||||||
auto next = nextIt->second;
|
auto next = opt.value();
|
||||||
auto expr = parse_expression_unary(current.precedence + 1);
|
auto expr = parse_expression_unary(current.precedence + 1);
|
||||||
if (expr.has_error()) {
|
if (expr.has_error()) {
|
||||||
return ast::expression_node_r(ast::error{ expr.error().location });
|
return ast::expression_node_r(ast::error{ expr.error().location });
|
||||||
@@ -464,7 +480,7 @@ ast::expression_node_r parser::parse_expression_rhs(ast::expression_node_p&& ini
|
|||||||
} else if (current.type == rhsop_info_t::FuncCall && peek_token().has_value()) {
|
} else if (current.type == rhsop_info_t::FuncCall && peek_token().has_value()) {
|
||||||
if (peek_token()->type != token_t::RParen) {
|
if (peek_token()->type != token_t::RParen) {
|
||||||
while (true) {
|
while (true) {
|
||||||
auto expr = parse_expression_unary(current.precedence + 1);
|
auto expr = parse_expression_unary(16);
|
||||||
if (expr.has_error()) {
|
if (expr.has_error()) {
|
||||||
return ast::expression_node_r(ast::error{ expr.error().location });
|
return ast::expression_node_r(ast::error{ expr.error().location });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <queue>
|
#include <queue>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -427,7 +428,17 @@ static void sccp_stage(function_context& ctx) {
|
|||||||
case furlang::ir::instruction_t::Assign: {
|
case furlang::ir::instruction_t::Assign: {
|
||||||
newLat = sccp_stage_get_lattice(latticeValues, *instr->sources().front());
|
newLat = sccp_stage_get_lattice(latticeValues, *instr->sources().front());
|
||||||
} break;
|
} break;
|
||||||
case furlang::ir::instruction_t::BinaryOp: {
|
case furlang::ir::instruction_t::Add:
|
||||||
|
case furlang::ir::instruction_t::Sub:
|
||||||
|
case furlang::ir::instruction_t::Mul:
|
||||||
|
case furlang::ir::instruction_t::Div:
|
||||||
|
case furlang::ir::instruction_t::Mod:
|
||||||
|
case furlang::ir::instruction_t::Eq:
|
||||||
|
case furlang::ir::instruction_t::NotEq:
|
||||||
|
case furlang::ir::instruction_t::LessThan:
|
||||||
|
case furlang::ir::instruction_t::GreaterThan:
|
||||||
|
case furlang::ir::instruction_t::LessEq:
|
||||||
|
case furlang::ir::instruction_t::GreaterEq: {
|
||||||
lattice lhs = sccp_stage_get_lattice(latticeValues, *instr->sources()[0]);
|
lattice lhs = sccp_stage_get_lattice(latticeValues, *instr->sources()[0]);
|
||||||
lattice rhs = sccp_stage_get_lattice(latticeValues, *instr->sources()[1]);
|
lattice rhs = sccp_stage_get_lattice(latticeValues, *instr->sources()[1]);
|
||||||
|
|
||||||
@@ -435,40 +446,31 @@ static void sccp_stage(function_context& ctx) {
|
|||||||
newLat.type = lattice::Bottom;
|
newLat.type = lattice::Bottom;
|
||||||
} else if (lhs.type == lattice::Constant && rhs.type == lattice::Constant) {
|
} else if (lhs.type == lattice::Constant && rhs.type == lattice::Constant) {
|
||||||
newLat.type = lattice::Constant;
|
newLat.type = lattice::Constant;
|
||||||
switch (dynamic_cast<const furlang::ir::binary_op_instruction&>(*instr).op_type()) {
|
switch (instr->type()) {
|
||||||
case furlang::ir::binary_op_instruction_t::Add:
|
case furlang::ir::instruction_t::Add: newLat.constant = lhs.constant + rhs.constant; break;
|
||||||
newLat.constant = lhs.constant + rhs.constant;
|
case furlang::ir::instruction_t::Sub: newLat.constant = lhs.constant - rhs.constant; break;
|
||||||
break;
|
case furlang::ir::instruction_t::Mul: newLat.constant = lhs.constant * rhs.constant; break;
|
||||||
case furlang::ir::binary_op_instruction_t::Sub:
|
case furlang::ir::instruction_t::Div: newLat.constant = lhs.constant / rhs.constant; break;
|
||||||
newLat.constant = lhs.constant - rhs.constant;
|
case furlang::ir::instruction_t::Mod: newLat.constant = lhs.constant % rhs.constant; break;
|
||||||
break;
|
case furlang::ir::instruction_t::Eq:
|
||||||
case furlang::ir::binary_op_instruction_t::Mul:
|
|
||||||
newLat.constant = lhs.constant * rhs.constant;
|
|
||||||
break;
|
|
||||||
case furlang::ir::binary_op_instruction_t::Div:
|
|
||||||
newLat.constant = lhs.constant / rhs.constant;
|
|
||||||
break;
|
|
||||||
case furlang::ir::binary_op_instruction_t::Mod:
|
|
||||||
newLat.constant = lhs.constant % rhs.constant;
|
|
||||||
break;
|
|
||||||
case furlang::ir::binary_op_instruction_t::Eq:
|
|
||||||
newLat.constant = (lhs.constant == rhs.constant) ? 1 : 0;
|
newLat.constant = (lhs.constant == rhs.constant) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case furlang::ir::binary_op_instruction_t::NotEq:
|
case furlang::ir::instruction_t::NotEq:
|
||||||
newLat.constant = (lhs.constant != rhs.constant) ? 1 : 0;
|
newLat.constant = (lhs.constant != rhs.constant) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case furlang::ir::binary_op_instruction_t::LessThan:
|
case furlang::ir::instruction_t::LessThan:
|
||||||
newLat.constant = (lhs.constant < rhs.constant) ? 1 : 0;
|
newLat.constant = (lhs.constant < rhs.constant) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case furlang::ir::binary_op_instruction_t::GreaterThan:
|
case furlang::ir::instruction_t::GreaterThan:
|
||||||
newLat.constant = (lhs.constant > rhs.constant) ? 1 : 0;
|
newLat.constant = (lhs.constant > rhs.constant) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case furlang::ir::binary_op_instruction_t::LessEq:
|
case furlang::ir::instruction_t::LessEq:
|
||||||
newLat.constant = (lhs.constant <= rhs.constant) ? 1 : 0;
|
newLat.constant = (lhs.constant <= rhs.constant) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case furlang::ir::binary_op_instruction_t::GreaterEq:
|
case furlang::ir::instruction_t::GreaterEq:
|
||||||
newLat.constant = (lhs.constant >= rhs.constant) ? 1 : 0;
|
newLat.constant = (lhs.constant >= rhs.constant) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ int main(void) {
|
|||||||
while (x < y) {
|
while (x < y) {
|
||||||
x = x + z;
|
x = x + z;
|
||||||
}
|
}
|
||||||
print(x);
|
print(pointerof x);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
furlang::arena arena{};
|
furlang::arena arena{};
|
||||||
|
|||||||
@@ -18,16 +18,51 @@ namespace ir {
|
|||||||
* @brief IR instruction type.
|
* @brief IR instruction type.
|
||||||
*/
|
*/
|
||||||
enum class instruction_t {
|
enum class instruction_t {
|
||||||
Alloca, /**< Unused */
|
Alloca, /**< Unused */
|
||||||
Assign, /**< Assign */
|
Assign, /**< Assign */
|
||||||
BinaryOp, /**< Binary operation */
|
Add, /**< Addition */
|
||||||
Call, /**< Call */
|
Sub, /**< Subtraction */
|
||||||
Branch, /**< Branch */
|
Mul, /**< Multiplication */
|
||||||
BranchCond, /**< Conditional branch */
|
Div, /**< Division */
|
||||||
Return, /**< Return */
|
Mod, /**< Modulo */
|
||||||
Phi, /**< Phi function */
|
Eq, /**< Equal */
|
||||||
|
NotEq, /**< Not equal */
|
||||||
|
LessThan, /**< Less than */
|
||||||
|
GreaterThan, /**< Greater than */
|
||||||
|
LessEq, /**< Less or equal */
|
||||||
|
GreaterEq, /**< Greater or equal */
|
||||||
|
Pointerof, /**< Pointerof */
|
||||||
|
Call, /**< Call */
|
||||||
|
Branch, /**< Branch */
|
||||||
|
BranchCond, /**< Conditional branch */
|
||||||
|
Return, /**< Return */
|
||||||
|
Phi, /**< Phi function */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline std::ostream& operator<<(std::ostream& os, instruction_t type) {
|
||||||
|
switch (type) {
|
||||||
|
case instruction_t::Alloca: return os << "alloca";
|
||||||
|
case instruction_t::Assign: return os << "assign";
|
||||||
|
case instruction_t::Add: return os << "add";
|
||||||
|
case instruction_t::Sub: return os << "sub";
|
||||||
|
case instruction_t::Mul: return os << "mul";
|
||||||
|
case instruction_t::Div: return os << "div";
|
||||||
|
case instruction_t::Mod: return os << "mod";
|
||||||
|
case instruction_t::Eq: return os << "eq";
|
||||||
|
case instruction_t::NotEq: return os << "notEq";
|
||||||
|
case instruction_t::LessThan: return os << "lessThan";
|
||||||
|
case instruction_t::GreaterThan: return os << "greaterThan";
|
||||||
|
case instruction_t::LessEq: return os << "lessEq";
|
||||||
|
case instruction_t::GreaterEq: return os << "greaterEq";
|
||||||
|
case instruction_t::Pointerof: return os << "pointerof";
|
||||||
|
case instruction_t::Call: return os << "call";
|
||||||
|
case instruction_t::Branch: return os << "branch";
|
||||||
|
case instruction_t::BranchCond: return os << "branchCond";
|
||||||
|
case instruction_t::Return: return os << "return";
|
||||||
|
case instruction_t::Phi: return os << "phi";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if an instruction type exits.
|
* @brief Checks if an instruction type exits.
|
||||||
*
|
*
|
||||||
@@ -241,78 +276,112 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Binary operation instruction type
|
* @brief Generic unary instruction
|
||||||
*/
|
*/
|
||||||
enum class binary_op_instruction_t {
|
class unary_instruction final : public instruction {
|
||||||
Add, /**< Addition */
|
public:
|
||||||
Sub, /**< Subtraction */
|
/**
|
||||||
Mul, /**< Multiplication */
|
* @brief Construct a new unary instruction.
|
||||||
Div, /**< Division */
|
*
|
||||||
Mod, /**< Modulo */
|
* @param type Instruction type.
|
||||||
|
* @param src Source operand.
|
||||||
|
* @param dst Destination operand.
|
||||||
|
*/
|
||||||
|
unary_instruction(instruction_t type, operand&& src, operand&& dst)
|
||||||
|
: m_type(type), m_src(std::move(src)), m_dst(std::move(dst)) {}
|
||||||
|
|
||||||
Eq, /**< Equal */
|
~unary_instruction() override = default;
|
||||||
NotEq, /**< Not equal */
|
|
||||||
LessThan, /**< Less than */
|
/**
|
||||||
GreaterThan, /**< Greater than */
|
* @brief Move constructor
|
||||||
LessEq, /**< Less or equal */
|
*/
|
||||||
GreaterEq, /**< Greater or equal */
|
unary_instruction(unary_instruction&&) = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move constructor
|
||||||
|
*/
|
||||||
|
unary_instruction& operator=(unary_instruction&&) = default;
|
||||||
|
|
||||||
|
unary_instruction(const unary_instruction&) = delete;
|
||||||
|
|
||||||
|
unary_instruction& operator=(const unary_instruction&) = delete;
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's type.
|
||||||
|
*
|
||||||
|
* @return The instruction type.
|
||||||
|
*/
|
||||||
|
instruction_t type() const override { return m_type; }
|
||||||
|
|
||||||
|
bool has_destination() const override { return true; }
|
||||||
|
|
||||||
|
operand& destination() override { return m_dst; }
|
||||||
|
|
||||||
|
const operand& destination() const override { return m_dst; }
|
||||||
|
|
||||||
|
std::vector<operand*> sources() override { return { &m_src }; }
|
||||||
|
|
||||||
|
std::vector<const operand*> sources() const override { return { &m_src }; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's source operand.
|
||||||
|
*
|
||||||
|
* @return The operand.
|
||||||
|
*/
|
||||||
|
const operand& src() const { return m_src; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns this instruction's destination operand.
|
||||||
|
*
|
||||||
|
* @return The operand.
|
||||||
|
*/
|
||||||
|
const operand& dst() const { return m_dst; }
|
||||||
|
private:
|
||||||
|
instruction_t m_type;
|
||||||
|
operand m_src;
|
||||||
|
operand m_dst;
|
||||||
|
protected:
|
||||||
|
std::ostream& print(std::ostream& os) const override { return os << m_dst << " = " << m_type << ' ' << m_src; }
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline std::ostream& operator<<(std::ostream& os, binary_op_instruction_t type) {
|
|
||||||
switch (type) {
|
|
||||||
case binary_op_instruction_t::Add: return os << '+';
|
|
||||||
case binary_op_instruction_t::Sub: return os << '-';
|
|
||||||
case binary_op_instruction_t::Mul: return os << '*';
|
|
||||||
case binary_op_instruction_t::Div: return os << '/';
|
|
||||||
case binary_op_instruction_t::Mod: return os << '%';
|
|
||||||
case binary_op_instruction_t::Eq: return os << "==";
|
|
||||||
case binary_op_instruction_t::NotEq: return os << "!=";
|
|
||||||
case binary_op_instruction_t::LessThan: return os << '<';
|
|
||||||
case binary_op_instruction_t::GreaterThan: return os << '>';
|
|
||||||
case binary_op_instruction_t::LessEq: return os << "<=";
|
|
||||||
case binary_op_instruction_t::GreaterEq: return os << ">=";
|
|
||||||
}
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Binary operation instruction
|
* @brief Generic binary instruction
|
||||||
*/
|
*/
|
||||||
class binary_op_instruction final : public instruction {
|
class binary_instruction final : public instruction {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new binary operation instruction.
|
* @brief Construct a new binary operation instruction.
|
||||||
*
|
*
|
||||||
* @param type Operation type.
|
* @param type Instruction type.
|
||||||
* @param lhs Left-hand-side operand.
|
* @param lhs Left-hand-side operand.
|
||||||
* @param rhs Right-hand-side operand.
|
* @param rhs Right-hand-side operand.
|
||||||
* @param dst Destination operand.
|
* @param dst Destination operand.
|
||||||
*/
|
*/
|
||||||
binary_op_instruction(binary_op_instruction_t type, operand&& lhs, operand&& rhs, operand&& dst)
|
binary_instruction(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_instruction() override = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Move constructor
|
* @brief Move constructor
|
||||||
*/
|
*/
|
||||||
binary_op_instruction(binary_op_instruction&&) = default;
|
binary_instruction(binary_instruction&&) = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Move constructor
|
* @brief Move constructor
|
||||||
*/
|
*/
|
||||||
binary_op_instruction& operator=(binary_op_instruction&&) = default;
|
binary_instruction& operator=(binary_instruction&&) = default;
|
||||||
|
|
||||||
binary_op_instruction(const binary_op_instruction&) = delete;
|
binary_instruction(const binary_instruction&) = delete;
|
||||||
|
|
||||||
binary_op_instruction& operator=(const binary_op_instruction&) = delete;
|
binary_instruction& operator=(const binary_instruction&) = delete;
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns this instruction's type.
|
* @brief Returns this instruction's type.
|
||||||
*
|
*
|
||||||
* @return instruction_t::BinaryOp.
|
* @return instruction_t::BinaryOp.
|
||||||
*/
|
*/
|
||||||
instruction_t type() const override { return instruction_t::BinaryOp; }
|
instruction_t type() const override { return m_type; }
|
||||||
|
|
||||||
bool has_destination() const override { return true; }
|
bool has_destination() const override { return true; }
|
||||||
|
|
||||||
@@ -324,13 +393,6 @@ public:
|
|||||||
|
|
||||||
std::vector<const operand*> sources() const override { return { &m_lhs, &m_rhs }; }
|
std::vector<const operand*> sources() const override { return { &m_lhs, &m_rhs }; }
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns this instruction's operation type.
|
|
||||||
*
|
|
||||||
* @return The operation type.
|
|
||||||
*/
|
|
||||||
binary_op_instruction_t op_type() const { return m_type; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns this instruction's left-hand-side operand.
|
* @brief Returns this instruction's left-hand-side operand.
|
||||||
*
|
*
|
||||||
@@ -352,13 +414,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
const operand& dst() const { return m_dst; }
|
const operand& dst() const { return m_dst; }
|
||||||
private:
|
private:
|
||||||
binary_op_instruction_t m_type;
|
instruction_t m_type;
|
||||||
operand m_lhs /**< Left-hand-side operand */;
|
operand m_lhs /**< Left-hand-side operand */;
|
||||||
operand m_rhs /**< Right-hand-side operand */;
|
operand m_rhs /**< Right-hand-side operand */;
|
||||||
operand m_dst /**< Destination operand */;
|
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 << m_dst << " = " << m_lhs << ' ' << m_type << ' ' << m_rhs;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -617,7 +679,7 @@ private:
|
|||||||
std::vector<std::pair<operand, block_index>> m_labels;
|
std::vector<std::pair<operand, block_index>> m_labels;
|
||||||
protected:
|
protected:
|
||||||
std::ostream& print(std::ostream& os) const override {
|
std::ostream& print(std::ostream& os) const override {
|
||||||
os << "phi " << m_dst << " =";
|
os << m_dst << " = phi";
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (const auto& pair : m_labels) {
|
for (const auto& pair : m_labels) {
|
||||||
if (!first) os << ',';
|
if (!first) os << ',';
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ enum class instruction_t : byte {
|
|||||||
*/
|
*/
|
||||||
GreaterEqual,
|
GreaterEqual,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes a pointer of popped-off thing onto the stack.
|
||||||
|
*/
|
||||||
|
Pointerof,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Pushes a variable onto the stack.
|
* @brief Pushes a variable onto the stack.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -114,6 +114,13 @@ public:
|
|||||||
* @return The type.
|
* @return The type.
|
||||||
*/
|
*/
|
||||||
constexpr auto type() const { return *m_type; }
|
constexpr auto type() const { return *m_type; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the thing's type.
|
||||||
|
*
|
||||||
|
* @return The shared pointer to the type.
|
||||||
|
*/
|
||||||
|
auto type() { return m_type; }
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Returns a raw data pointer.
|
* @brief Returns a raw data pointer.
|
||||||
@@ -265,7 +272,7 @@ public:
|
|||||||
|
|
||||||
thing resolve() const {
|
thing resolve() const {
|
||||||
thing rsv = { resolve_type(m_type, m_modules), m_data, m_allocator };
|
thing rsv = { resolve_type(m_type, m_modules), m_data, m_allocator };
|
||||||
while (rsv.type().t == type_t::Reference)
|
while (rsv.type()->t == type_t::Reference)
|
||||||
rsv = { rsv.m_type->reference, rsv.get<reference_t>(), std::move(rsv.m_allocator) };
|
rsv = { rsv.m_type->reference, rsv.get<reference_t>(), std::move(rsv.m_allocator) };
|
||||||
return rsv;
|
return rsv;
|
||||||
}
|
}
|
||||||
@@ -342,8 +349,8 @@ private:
|
|||||||
private:
|
private:
|
||||||
template <typename Op>
|
template <typename Op>
|
||||||
thing binary_op(const thing& rhs, const Op& op) const {
|
thing binary_op(const thing& rhs, const Op& op) const {
|
||||||
thing lhsRsv = resolve();
|
const thing lhsRsv = resolve();
|
||||||
thing rhsRsv = rhs.resolve();
|
const thing rhsRsv = rhs.resolve();
|
||||||
|
|
||||||
if (lhsRsv.type().t == type_t::Primitive && rhsRsv.type().t == type_t::Primitive) {
|
if (lhsRsv.type().t == type_t::Primitive && rhsRsv.type().t == type_t::Primitive) {
|
||||||
std::size_t size = std::max(lhsRsv.type().primitive, rhsRsv.type().primitive);
|
std::size_t size = std::max(lhsRsv.type().primitive, rhsRsv.type().primitive);
|
||||||
|
|||||||
@@ -162,6 +162,19 @@ void executor::step() {
|
|||||||
auto lhs = pop_thing();
|
auto lhs = pop_thing();
|
||||||
push_thing(lhs->greater_equals(*rhs));
|
push_thing(lhs->greater_equals(*rhs));
|
||||||
} break;
|
} break;
|
||||||
|
case instruction_t::Pointerof: {
|
||||||
|
auto thing = pop_thing()->resolve();
|
||||||
|
auto ptr = push_thing({ *m_context->at("core")->type_at(4), m_context, m_context->thing_alloc() });
|
||||||
|
switch (furvm::thing<>::resolve_type(thing.type(), m_context)->t) {
|
||||||
|
case type_t::Primitive: ptr->get<std::uintptr_t>() = reinterpret_cast<std::uintptr_t>(thing.raw()); break;
|
||||||
|
case type_t::List:
|
||||||
|
ptr->get<std::uintptr_t>() = reinterpret_cast<std::uintptr_t>(thing.get<list_t>().data);
|
||||||
|
break;
|
||||||
|
case type_t::Reference:
|
||||||
|
case type_t::Import:
|
||||||
|
default: throw std::runtime_error("unreachable");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case instruction_t::Load: {
|
case instruction_t::Load: {
|
||||||
variable_t variable = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
variable_t variable = static_cast<std::uint16_t>(frame.mod->byte(frame.position)) |
|
||||||
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
(static_cast<std::uint16_t>(frame.mod->byte(frame.position + 1)) << 8);
|
||||||
|
|||||||
Reference in New Issue
Block a user