|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r73619 - trunk/libs/spirit/example/qi/compiler_tutorial/conjure3
From: joel_at_[hidden]
Date: 2011-08-09 04:29:47
Author: djowel
Date: 2011-08-09 04:29:45 EDT (Tue, 09 Aug 2011)
New Revision: 73619
URL: http://svn.boost.org/trac/boost/changeset/73619
Log:
refactoring: moving low-level llvm stuff into separate classes
Text files modified:
trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp | 258 ++++++++++++++++++++++++---------------
trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp | 91 +++++++++++++
2 files changed, 244 insertions(+), 105 deletions(-)
Modified: trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp 2011-08-09 04:29:45 EDT (Tue, 09 Aug 2011)
@@ -227,6 +227,11 @@
);
}
+ void function::add(basic_block const& b)
+ {
+ f->getBasicBlockList().push_back(b);
+ }
+
value llvm_compiler::val(unsigned int x)
{
return value(
@@ -258,7 +263,7 @@
// Create an alloca instruction in the entry block of
// the function. This is used for mutable variables etc.
llvm::AllocaInst*
- create_entry_block_alloca(
+ make_entry_block_alloca(
llvm::Function* f,
char const* name,
llvm::LLVMContext& context)
@@ -347,6 +352,34 @@
return llvm_builder.GetInsertBlock()->getParent();
}
+ function llvm_compiler::declare_function(
+ bool void_return
+ , std::string const& name
+ , std::size_t nargs)
+ {
+ llvm::Type* int_type =
+ llvm::Type::getIntNTy(context(), int_size);
+ llvm::Type* void_type = llvm::Type::getVoidTy(context());
+
+ std::vector<llvm::Type*> ints(nargs, int_type);
+ llvm::Type* return_type = void_return ? void_type : int_type;
+
+ llvm::FunctionType* function_type =
+ llvm::FunctionType::get(void_return ? void_type : int_type, ints, false);
+
+ return llvm::Function::Create(
+ function_type, llvm::Function::ExternalLinkage,
+ name, vm.module());
+ }
+
+ basic_block llvm_compiler::make_basic_block(
+ char const* name
+ , function parent
+ , basic_block before)
+ {
+ return llvm::BasicBlock::Create(context(), name, parent, before);
+ }
+
void llvm_compiler::init_fpm()
{
// Set up the optimizer pipeline. Start with registering info about how the
@@ -386,12 +419,12 @@
value compiler::operator()(ast::identifier const& x)
{
// Look this variable up in the function.
- if (named_values.find(x.name) == named_values.end())
+ if (locals.find(x.name) == locals.end())
{
error_handler(x.id, "Undeclared variable: " + x.name);
return val();
}
- return named_values[x.name];
+ return locals[x.name];
}
value compiler::operator()(ast::unary_expr const& x)
@@ -608,13 +641,13 @@
value compiler::operator()(ast::assignment const& x)
{
- if (named_values.find(x.lhs.name) == named_values.end())
+ if (locals.find(x.lhs.name) == locals.end())
{
error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
return val();
}
- value lhs = named_values[x.lhs.name];
+ value lhs = locals[x.lhs.name];
value rhs = (*this)(x.rhs);
if (!rhs.is_valid())
return val();
@@ -647,7 +680,7 @@
bool compiler::operator()(ast::variable_declaration const& x)
{
- if (named_values.find(x.lhs.name) != named_values.end())
+ if (locals.find(x.lhs.name) != locals.end())
{
error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name);
return false;
@@ -664,11 +697,11 @@
}
value var_ = var(name.c_str());
- if (init)
+ if (init.is_valid())
var_.assign(init);
// Remember this binding.
- named_values[name] = var_;
+ locals[name] = var_;
return true;
}
@@ -705,90 +738,90 @@
if (!condition.is_valid())
return false;
- llvm::Function* f = get_current_function();
+ function f = get_current_function();
// Create blocks for the then and else cases. Insert the 'then' block at the
// end of the function.
- llvm::BasicBlock* then_block = llvm::BasicBlock::Create(context(), "if.then", f);
- llvm::BasicBlock* else_block = 0;
- llvm::BasicBlock* exit_block = 0;
+ basic_block then_block = make_basic_block("if.then", f);
+ basic_block else_block;
+ basic_block exit_block;
if (x.else_)
{
- else_block = llvm::BasicBlock::Create(context(), "if.else");
- builder().CreateCondBr(condition, then_block, else_block);
+ else_block = make_basic_block("if.else");
+ conditional_branch(condition, then_block, else_block);
}
else
{
- exit_block = llvm::BasicBlock::Create(context(), "if.end");
- builder().CreateCondBr(condition, then_block, exit_block);
+ exit_block = make_basic_block("if.end");
+ conditional_branch(condition, then_block, exit_block);
}
// Emit then value.
- builder().SetInsertPoint(then_block);
+ set_insert_point(then_block);
if (!(*this)(x.then))
return false;
- if (then_block->getTerminator() == 0)
+ if (!then_block.has_terminator())
{
- if (exit_block == 0)
- exit_block = llvm::BasicBlock::Create(context(), "if.end");
- builder().CreateBr(exit_block);
+ if (!exit_block.is_valid())
+ exit_block = make_basic_block("if.end");
+ branch(exit_block);
}
// Codegen of 'then' can change the current block, update then_block
- then_block = builder().GetInsertBlock();
+ then_block = get_insert_block();
if (x.else_)
{
// Emit else block.
- f->getBasicBlockList().push_back(else_block);
- builder().SetInsertPoint(else_block);
+ f.add(else_block);
+ set_insert_point(else_block);
if (!(*this)(*x.else_))
return false;
- if (else_block->getTerminator() == 0)
+ if (!else_block.has_terminator())
{
- if (exit_block == 0)
- exit_block = llvm::BasicBlock::Create(context(), "if.end");
- builder().CreateBr(exit_block);
+ if (!exit_block.is_valid())
+ exit_block = make_basic_block("if.end");
+ branch(exit_block);
}
// Codegen of 'else' can change the current block, update else_block
- else_block = builder().GetInsertBlock();
+ else_block = get_insert_block();
}
- if (exit_block != 0)
+ if (exit_block.is_valid())
{
// Emit exit block
- f->getBasicBlockList().push_back(exit_block);
- builder().SetInsertPoint(exit_block);
+ f.add(exit_block);
+ set_insert_point(exit_block);
}
return true;
}
bool compiler::operator()(ast::while_statement const& x)
{
- llvm::Function* f = get_current_function();
+ function f = get_current_function();
- llvm::BasicBlock* cond_block = llvm::BasicBlock::Create(context(), "while.cond", f);
- llvm::BasicBlock* body_block = llvm::BasicBlock::Create(context(), "while.body");
- llvm::BasicBlock* exit_block = llvm::BasicBlock::Create(context(), "while.end");
+ basic_block cond_block = make_basic_block("while.cond", f);
+ basic_block body_block = make_basic_block("while.body");
+ basic_block exit_block = make_basic_block("while.end");
- builder().CreateBr(cond_block);
- builder().SetInsertPoint(cond_block);
+ branch(cond_block);
+ set_insert_point(cond_block);
value condition = (*this)(x.condition);
if (!condition.is_valid())
return false;
- builder().CreateCondBr(condition, body_block, exit_block);
- f->getBasicBlockList().push_back(body_block);
- builder().SetInsertPoint(body_block);
+ conditional_branch(condition, body_block, exit_block);
+ f.add(body_block);
+ set_insert_point(body_block);
if (!(*this)(x.body))
return false;
- if (body_block->getTerminator() == 0)
- builder().CreateBr(cond_block); // loop back
+ if (!body_block.has_terminator())
+ branch(cond_block); // loop back
// Emit exit block
- f->getBasicBlockList().push_back(exit_block);
- builder().SetInsertPoint(exit_block);
+ f.add(exit_block);
+ set_insert_point(exit_block);
return true;
}
@@ -823,85 +856,110 @@
return_var.assign(return_val);
}
- builder().CreateBr(return_block);
+ branch(return_block);
return true;
}
- llvm::Function* compiler::function_decl(ast::function const& x)
+ namespace
{
- void_return = x.return_type == "void";
- current_function_name = x.function_name.name;
+ struct set_arg_name
+ {
+ typedef std::list<ast::identifier>::const_iterator ast_iter;
+ typedef void result_type;
- llvm::Type* int_type =
- llvm::Type::getIntNTy(context(), int_size);
- llvm::Type* void_type = llvm::Type::getVoidTy(context());
+ mutable ast_iter i;
+ set_arg_name(ast_iter i)
+ : i(i) {}
- std::vector<llvm::Type*> ints(x.args.size(), int_type);
- llvm::Type* return_type = void_return ? void_type : int_type;
+ void operator()(value arg) const
+ {
+ arg.name(i->name.c_str());
+ ++i;
+ }
+ };
+ }
- llvm::FunctionType* function_type =
- llvm::FunctionType::get(void_return ? void_type : int_type, ints, false);
+ function compiler::function_decl(ast::function const& x)
+ {
+ void_return = x.return_type == "void";
+ current_function_name = x.function_name.name;
- llvm::Function* f =
- llvm::Function::Create(
- function_type, llvm::Function::ExternalLinkage,
- current_function_name, vm.module());
+ function f =
+ declare_function(
+ void_return
+ , current_function_name
+ , x.args.size());
// If function conflicted, the function already exixts. If it has a
// body, don't allow redefinition or reextern.
- if (f->getName() != current_function_name)
+ if (f.name() != current_function_name)
{
// Delete the one we just made and get the existing one.
- f->eraseFromParent();
+ f.erase_from_parent();
f = get_function(current_function_name);
// If function already has a body, reject this.
- if (!f->empty())
+ if (!f.empty())
{
error_handler(
x.function_name.id,
"Duplicate function: " + x.function_name.name);
- return 0;
+ return function();
}
// If function took a different number of args, reject.
- if (f->arg_size() != x.args.size())
+ if (f.arg_size() != x.args.size())
{
error_handler(
x.function_name.id,
"Redefinition of function with different # args: "
+ x.function_name.name);
- return 0;
+ return function();
}
// Set names for all arguments.
- llvm::Function::arg_iterator iter = f->arg_begin();
- BOOST_FOREACH(ast::identifier const& arg, x.args)
- {
- iter->setName(arg.name);
- ++iter;
- }
+ for_each_arg(f, set_arg_name(x.args.begin()));
}
return f;
}
- void compiler::function_allocas(ast::function const& x, llvm::Function* f)
+ namespace
{
- // Create an variables for each argument and register the
- // argument in the symbol table so that references to it will succeed.
- llvm::Function::arg_iterator iter = f->arg_begin();
- BOOST_FOREACH(ast::identifier const& arg, x.args)
+ struct make_arg
{
- // Create an arg_ for this variable.
- value arg_ = var(arg.name.c_str());
+ typedef std::list<ast::identifier>::const_iterator ast_iter;
+ typedef void result_type;
- // Store the initial value into the arg_.
- arg_.assign(val(iter));
+ llvm_compiler& c;
+ std::map<std::string, value>& locals;
+ mutable ast_iter i;
- // Add arguments to variable symbol table.
- named_values[arg.name] = arg_;
- ++iter;
- }
+ make_arg(
+ llvm_compiler& c
+ , std::map<std::string, value>& locals
+ , ast_iter i)
+ : c(c), locals(locals), i(i) {}
+
+ void operator()(value arg) const
+ {
+ // Create an arg_ for this variable.
+ value arg_ = c.var(i->name.c_str());
+
+ // Store the initial value into the arg_.
+ arg_.assign(arg);
+
+ // Add arguments to variable symbol table.
+ locals[i->name] = arg_;
+ ++i;
+ }
+ };
+ }
+
+ void compiler::function_allocas(ast::function const& x, function f)
+ {
+ // Create variables for each argument and register the
+ // argument in the symbol table so that references to it will succeed.
+ for_each_arg(f, make_arg(*this, locals, x.args.begin()));
if (!void_return)
{
@@ -914,7 +972,7 @@
{
///////////////////////////////////////////////////////////////////////
// the signature:
- llvm::Function* f = function_decl(x);
+ function f = function_decl(x);
if (f == 0)
return false;
@@ -923,37 +981,35 @@
if (x.body) // compile the body if this is not a prototype
{
// Create a new basic block to start insertion into.
- llvm::BasicBlock* block =
- llvm::BasicBlock::Create(context(), "entry", f);
- builder().SetInsertPoint(block);
+ basic_block block = make_basic_block("entry", f);
+ set_insert_point(block);
function_allocas(x, f);
- return_block = llvm::BasicBlock::Create(context(), "return");
+ return_block = make_basic_block("return");
if (!(*this)(*x.body))
{
// Error reading body, remove function.
- f->eraseFromParent();
+ f.erase_from_parent();
return false;
}
- llvm::BasicBlock* last_block =
- &f->getBasicBlockList().back();
+ basic_block last_block = f.last_block();
// If the last block is unterminated, connect it to return_block
- if (last_block->getTerminator() == 0)
+ if (!last_block.has_terminator())
{
- builder().SetInsertPoint(last_block);
- builder().CreateBr(return_block);
+ set_insert_point(last_block);
+ branch(return_block);
}
- f->getBasicBlockList().push_back(return_block);
- builder().SetInsertPoint(return_block);
+ f.add(return_block);
+ set_insert_point(return_block);
if (void_return)
- builder().CreateRetVoid();
+ return_();
else
- builder().CreateRet(return_var);
+ return_(return_var);
//~ vm.module()->dump();
@@ -971,7 +1027,7 @@
{
BOOST_FOREACH(ast::function const& f, x)
{
- named_values.clear(); // clear the variables
+ locals.clear(); // clear the variables
if (!(*this)(f))
return false;
}
Modified: trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp
==============================================================================
--- trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp (original)
+++ trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp 2011-08-09 04:29:45 EDT (Tue, 09 Aug 2011)
@@ -49,6 +49,9 @@
value& assign(value const& rhs);
+ void name(char const* id)
+ { v->setName(id); }
+
friend value operator-(value a);
friend value operator!(value a);
friend value operator+(value a, value b);
@@ -90,6 +93,32 @@
};
///////////////////////////////////////////////////////////////////////////
+ struct function;
+
+ struct basic_block
+ {
+ basic_block()
+ : b(0) {}
+
+ bool has_terminator() const
+ { return b->getTerminator() != 0; }
+
+ bool is_valid() const { return b != 0; }
+
+ private:
+
+ basic_block(llvm::BasicBlock* b)
+ : b(b) {}
+
+ operator llvm::BasicBlock*() const
+ { return b; }
+
+ friend struct llvm_compiler;
+ friend struct function;
+ llvm::BasicBlock* b;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
struct function
{
function()
@@ -101,6 +130,20 @@
std::size_t arg_size() const
{ return f->arg_size(); }
+ void add(basic_block const& b);
+
+ void erase_from_parent()
+ { f->eraseFromParent(); }
+
+ basic_block last_block()
+ { return &f->getBasicBlockList().back(); }
+
+ bool empty() const
+ { return f->empty(); }
+
+ std::string name() const
+ { return f->getName(); }
+
private:
function(llvm::Function* f)
@@ -110,6 +153,7 @@
llvm::Function* f;
};
+
///////////////////////////////////////////////////////////////////////////
// The LLVM Compiler. Lower level compiler (does not deal with ASTs)
///////////////////////////////////////////////////////////////////////////
@@ -142,6 +186,45 @@
function get_current_function() const;
+ template <typename F>
+ void for_each_arg(function f, F do_)
+ {
+ typedef typename llvm::Function::arg_iterator iter;
+ for (iter i = f.f->arg_begin(); i != f.f->arg_end(); ++i)
+ do_(val(i));
+ }
+
+ function declare_function(
+ bool void_return
+ , std::string const& name
+ , std::size_t nargs);
+
+ basic_block make_basic_block(
+ char const* name
+ , function parent = function()
+ , basic_block before = basic_block());
+
+ basic_block get_insert_block()
+ { return llvm_builder.GetInsertBlock(); }
+
+ void set_insert_point(basic_block b)
+ { llvm_builder.SetInsertPoint(b); }
+
+ void conditional_branch(
+ value cond, basic_block true_br, basic_block false_br)
+ { llvm_builder.CreateCondBr(cond, true_br, false_br); }
+
+ void branch(basic_block b)
+ { llvm_builder.CreateBr(b); }
+
+ void return_()
+ { llvm_builder.CreateRetVoid(); }
+
+ void return_(value v)
+ { llvm_builder.CreateRet(v); }
+
+ struct get_llvm_value;
+
protected:
llvm::LLVMContext& context() const
@@ -211,8 +294,8 @@
struct statement_compiler;
statement_compiler& as_statement();
- llvm::Function* function_decl(ast::function const& x);
- void function_allocas(ast::function const& x, llvm::Function* function);
+ function function_decl(ast::function const& x);
+ void function_allocas(ast::function const& x, function function);
boost::function<
void(int tag, std::string const& what)>
@@ -220,8 +303,8 @@
bool void_return;
std::string current_function_name;
- std::map<std::string, value> named_values;
- llvm::BasicBlock* return_block;
+ std::map<std::string, value> locals;
+ basic_block return_block;
value return_var;
};
}}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk