Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended support for binary ops and refactoring #489

Merged
merged 6 commits into from
Jan 12, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 108 additions & 30 deletions src/codegen/llvm/codegen_llvm_visitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,88 @@ void CodegenLLVMVisitor::emit_procedure_or_function_declaration(const ast::Block
*module);
}

llvm::Value* CodegenLLVMVisitor::visit_arithmetic_bin_op(llvm::Value* lhs,
llvm::Value* rhs,
unsigned op) {
const auto& bin_op = static_cast<ast::BinaryOp>(op);
llvm::Value* result;

switch (bin_op) {
#define DISPATCH(binary_op, llvm_fp_op, llvm_int_op) \
case binary_op: \
if (lhs->getType()->isDoubleTy()) \
pramodk marked this conversation as resolved.
Show resolved Hide resolved
result = llvm_fp_op(lhs, rhs); \
else \
result = llvm_int_op(lhs, rhs); \
return result;

DISPATCH(ast::BinaryOp::BOP_ADDITION, builder.CreateFAdd, builder.CreateAdd);
DISPATCH(ast::BinaryOp::BOP_DIVISION, builder.CreateFDiv, builder.CreateSDiv);
DISPATCH(ast::BinaryOp::BOP_MULTIPLICATION, builder.CreateFMul, builder.CreateMul);
DISPATCH(ast::BinaryOp::BOP_SUBTRACTION, builder.CreateFSub, builder.CreateSub);

#undef DISPATCH

default:
return nullptr;
}
}

void CodegenLLVMVisitor::visit_assign_op(const ast::BinaryExpression& node, llvm::Value* rhs) {
auto var = dynamic_cast<ast::VarName*>(node.get_lhs().get());
if (!var) {
throw std::runtime_error("Error: only VarName assignment is currently supported.\n");
}
pramodk marked this conversation as resolved.
Show resolved Hide resolved

const auto& identifier = var->get_name();
if (identifier->is_name()) {
llvm::Value* alloca = local_named_values->lookup(var->get_node_name());
builder.CreateStore(rhs, alloca);
} else if (identifier->is_indexed_name()) {
auto indexed_name = std::dynamic_pointer_cast<ast::IndexedName>(identifier);
builder.CreateStore(rhs, codegen_indexed_name(*indexed_name));
} else {
throw std::runtime_error("Error: Unsupported variable type");
}
}

llvm::Value* CodegenLLVMVisitor::visit_logical_bin_op(llvm::Value* lhs,
llvm::Value* rhs,
unsigned op) {
const auto& bin_op = static_cast<ast::BinaryOp>(op);
return bin_op == ast::BinaryOp::BOP_AND ? builder.CreateAnd(lhs, rhs)
: builder.CreateOr(lhs, rhs);
}

llvm::Value* CodegenLLVMVisitor::visit_comparison_bin_op(llvm::Value* lhs,
llvm::Value* rhs,
unsigned op) {
const auto& bin_op = static_cast<ast::BinaryOp>(op);
llvm::Value* result;

switch (bin_op) {
#define DISPATCH(binary_op, f_llvm_op, i_llvm_op) \
case binary_op: \
if (lhs->getType()->isDoubleTy()) \
pramodk marked this conversation as resolved.
Show resolved Hide resolved
result = f_llvm_op(lhs, rhs); \
else \
result = i_llvm_op(lhs, rhs); \
return result;

DISPATCH(ast::BinaryOp::BOP_EXACT_EQUAL, builder.CreateICmpEQ, builder.CreateFCmpOEQ);
DISPATCH(ast::BinaryOp::BOP_GREATER, builder.CreateICmpSGT, builder.CreateFCmpOGT);
DISPATCH(ast::BinaryOp::BOP_GREATER_EQUAL, builder.CreateICmpSGE, builder.CreateFCmpOGE);
DISPATCH(ast::BinaryOp::BOP_LESS, builder.CreateICmpSLT, builder.CreateFCmpOLT);
DISPATCH(ast::BinaryOp::BOP_LESS_EQUAL, builder.CreateICmpSLE, builder.CreateFCmpOLE);
DISPATCH(ast::BinaryOp::BOP_NOT_EQUAL, builder.CreateICmpNE, builder.CreateFCmpONE);

#undef DISPATCH

default:
return nullptr;
}
}

void CodegenLLVMVisitor::visit_procedure_or_function(const ast::Block& node) {
const auto& name = node.get_node_name();
const auto& parameters = node.get_parameters();
Expand Down Expand Up @@ -222,44 +304,39 @@ void CodegenLLVMVisitor::visit_binary_expression(const ast::BinaryExpression& no
llvm::Value* rhs = values.back();
values.pop_back();
if (op == ast::BinaryOp::BOP_ASSIGN) {
auto var = dynamic_cast<ast::VarName*>(node.get_lhs().get());
if (!var) {
throw std::runtime_error("Error: only VarName assignment is currently supported.\n");
}

const auto& identifier = var->get_name();
if (identifier->is_name()) {
llvm::Value* alloca = local_named_values->lookup(var->get_node_name());
builder.CreateStore(rhs, alloca);
} else if (identifier->is_indexed_name()) {
auto indexed_name = std::dynamic_pointer_cast<ast::IndexedName>(identifier);
builder.CreateStore(rhs, codegen_indexed_name(*indexed_name));
} else {
throw std::runtime_error("Error: Unsupported variable type");
}
visit_assign_op(node, rhs);
return;
}

node.get_lhs()->accept(*this);
llvm::Value* lhs = values.back();
values.pop_back();
llvm::Value* result;

// \todo: Support other binary operators
llvm::Value* result;
switch (op) {
#define DISPATCH(binary_op, llvm_op) \
case binary_op: \
result = llvm_op(lhs, rhs); \
values.push_back(result); \
case ast::BOP_ADDITION:
case ast::BOP_DIVISION:
case ast::BOP_MULTIPLICATION:
case ast::BOP_SUBTRACTION:
result = visit_arithmetic_bin_op(lhs, rhs, op);
break;

DISPATCH(ast::BinaryOp::BOP_ADDITION, builder.CreateFAdd);
DISPATCH(ast::BinaryOp::BOP_DIVISION, builder.CreateFDiv);
DISPATCH(ast::BinaryOp::BOP_MULTIPLICATION, builder.CreateFMul);
DISPATCH(ast::BinaryOp::BOP_SUBTRACTION, builder.CreateFSub);

#undef DISPATCH
case ast::BOP_AND:
case ast::BOP_OR:
result = visit_logical_bin_op(lhs, rhs, op);
break;
case ast::BOP_EXACT_EQUAL:
case ast::BOP_GREATER:
case ast::BOP_GREATER_EQUAL:
case ast::BOP_LESS:
case ast::BOP_LESS_EQUAL:
case ast::BOP_NOT_EQUAL:
result = visit_comparison_bin_op(lhs, rhs, op);
break;
default:
throw std::runtime_error("Error: binary operator is not supported\n");
}

values.push_back(result);
}

void CodegenLLVMVisitor::visit_boolean(const ast::Boolean& node) {
Expand Down Expand Up @@ -367,8 +444,9 @@ void CodegenLLVMVisitor::visit_unary_expression(const ast::UnaryExpression& node
llvm::Value* value = values.back();
values.pop_back();
if (op == ast::UOP_NEGATION) {
llvm::Value* result = builder.CreateFNeg(value);
values.push_back(result);
values.push_back(builder.CreateFNeg(value));
} else if (op == ast::UOP_NOT) {
values.push_back(builder.CreateNot(value));
} else {
// Support only `double` operators for now.
throw std::runtime_error("Error: unsupported unary operator\n");
Expand Down
34 changes: 34 additions & 0 deletions src/codegen/llvm/codegen_llvm_visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,40 @@ class CodegenLLVMVisitor: public visitor::ConstAstVisitor {
return std::move(module);
}

/**
* Visit nmodl arithmetic binary operator
* \param lhs LLVM value of evaluated lhs expression
* \param rhs LLVM value of evaluated rhs expression
* \param op the AST binary operator (ADD, DIV, MUL, SUB)
* \return LLVM IR value result
*/
llvm::Value* visit_arithmetic_bin_op(llvm::Value* lhs, llvm::Value* rhs, unsigned op);

/**
* Visit nmodl assignment operator (ASSIGN)
* \param node the AST node representing the binary expression in NMODL
* \param rhs LLVM value of evaluated rhs expression
*/
void visit_assign_op(const ast::BinaryExpression& node, llvm::Value* rhs);

/**
* Visit nmodl logical binary operator
* \param lhs LLVM value of evaluated lhs expression
* \param rhs LLVM value of evaluated rhs expression
* \param op the AST binary operator (AND, OR)
* \return LLVM IR value result
*/
llvm::Value* visit_logical_bin_op(llvm::Value* lhs, llvm::Value* rhs, unsigned op);

/**
* Visit nmodl comparison binary operator
* \param lhs LLVM value of evaluated lhs expression
* \param rhs LLVM value of evaluated rhs expression
* \param op the AST binary operator (EXACT_EQUAL, GREATER, GREATER_EQUAL, LESS, LESS_EQUAL, NOT_EQUAL)
* \return LLVM IR value result
*/
llvm::Value* visit_comparison_bin_op(llvm::Value* lhs, llvm::Value* rhs, unsigned op);

/**
* Visit nmodl function or procedure
* \param node the AST node representing the function or procedure in NMODL
Expand Down
2 changes: 1 addition & 1 deletion test/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ target_link_libraries(

if(NMODL_ENABLE_LLVM)
include_directories(${LLVM_INCLUDE_DIRS})
add_executable(testllvm visitor/main.cpp codegen/llvm.cpp)
add_executable(testllvm visitor/main.cpp codegen/codegen_llvm_ir.cpp)
add_executable(test_llvm_runner visitor/main.cpp codegen/codegen_llvm_execution.cpp)
target_link_libraries(
testllvm
Expand Down
File renamed without changes.