Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r73621 - trunk/libs/spirit/example/qi/compiler_tutorial/conjure3
From: joel_at_[hidden]
Date: 2011-08-09 10:39:04


Author: djowel
Date: 2011-08-09 10:39:03 EDT (Tue, 09 Aug 2011)
New Revision: 73621
URL: http://svn.boost.org/trac/boost/changeset/73621

Log:
refactoring: moving low-level llvm stuff into separate classes
Text files modified:
   trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp | 277 +++++++++++++++++++++++++++------------
   trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp | 116 +++++++--------
   2 files changed, 244 insertions(+), 149 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 10:39:03 EDT (Tue, 09 Aug 2011)
@@ -39,6 +39,26 @@
         builder(rhs.builder)
     {}
 
+ bool value::is_lvalue() const
+ {
+ return is_lvalue_;
+ }
+
+ bool value::is_valid() const
+ {
+ return v != 0;
+ }
+
+ void value::name(char const* id)
+ {
+ v->setName(id);
+ }
+
+ void value::name(std::string const& id)
+ {
+ v->setName(id);
+ }
+
     value::operator llvm::Value*() const
     {
         if (is_lvalue_)
@@ -227,11 +247,80 @@
         );
     }
 
+ struct function::to_value
+ {
+ typedef value result_type;
+ llvm_compiler* c;
+ to_value(llvm_compiler* c = 0) : c(c) {}
+ value operator()(llvm::Value& v) const
+ {
+ return c->val(&v);
+ }
+ };
+
+ bool basic_block::has_terminator() const
+ {
+ return b->getTerminator() != 0;
+ }
+
+ bool basic_block::is_valid() const
+ {
+ return b != 0;
+ }
+
+ function::operator llvm::Function*() const
+ {
+ return f;
+ }
+
+ std::size_t function::arg_size() const
+ {
+ return f->arg_size();
+ }
+
     void function::add(basic_block const& b)
     {
         f->getBasicBlockList().push_back(b);
     }
 
+ void function::erase_from_parent()
+ {
+ f->eraseFromParent();
+ }
+
+ basic_block function::last_block()
+ {
+ return &f->getBasicBlockList().back();
+ }
+
+ bool function::empty() const
+ {
+ return f->empty();
+ }
+
+ std::string function::name() const
+ {
+ return f->getName();
+ }
+
+ function::arg_range function::args() const
+ {
+ BOOST_ASSERT(c != 0);
+ argval_iterator first(f->arg_begin(), to_value());
+ argval_iterator last(f->arg_end(), to_value());
+ return arg_range(first, last);
+ }
+
+ bool function::is_valid() const
+ {
+ return f != 0;
+ }
+
+ void function::verify() const
+ {
+ llvm::verifyFunction(*f);
+ }
+
     value llvm_compiler::val(unsigned int x)
     {
         return value(
@@ -300,31 +389,30 @@
                 return x;
             }
         };
+ }
 
- template <typename C>
- llvm::Value* call_impl(
- llvm::IRBuilder<>& llvm_builder,
- function callee,
- C const& args_)
- {
- // Sigh. LLVM requires CreateCall arguments to be random access.
- // It would have been better if it can accept forward iterators.
- // I guess it needs the arguments to be in contiguous memory.
- // So, we have to put the args into a temporary std::vector.
- std::vector<llvm::Value*> args(
- args_.begin(), args_.end());
-
- // Check the args for null values. We can't have null values.
- // Return 0 if we find one to flag error.
- BOOST_FOREACH(llvm::Value* arg, args)
- {
- if (arg == 0)
- return 0;
- }
+ template <typename C>
+ llvm::Value* llvm_compiler::call_impl(
+ function callee,
+ C const& args_)
+ {
+ // Sigh. LLVM requires CreateCall arguments to be random access.
+ // It would have been better if it can accept forward iterators.
+ // I guess it needs the arguments to be in contiguous memory.
+ // So, we have to put the args into a temporary std::vector.
+ std::vector<llvm::Value*> args(
+ args_.begin(), args_.end());
 
- return llvm_builder.CreateCall(
- callee, args.begin(), args.end(), "call_tmp");
+ // Check the args for null values. We can't have null values.
+ // Return 0 if we find one to flag error.
+ BOOST_FOREACH(llvm::Value* arg, args)
+ {
+ if (arg == 0)
+ return 0;
         }
+
+ return llvm_builder.CreateCall(
+ callee, args.begin(), args.end(), "call_tmp");
     }
 
     template <typename Container>
@@ -333,7 +421,7 @@
         Container const& args)
     {
         llvm::Value* call = call_impl(
- llvm_builder, callee,
+ callee,
             args | boost::adaptors::transformed(llvm_value()));
 
         if (call == 0)
@@ -341,15 +429,15 @@
         return value(call, false, &llvm_builder);
     }
 
- function llvm_compiler::get_function(char const* name) const
+ function llvm_compiler::get_function(char const* name)
     {
- return vm.module()->getFunction(name);
+ return function(vm.module()->getFunction(name), this);
     }
 
- function llvm_compiler::get_current_function() const
+ function llvm_compiler::get_current_function()
     {
         // get the current function
- return llvm_builder.GetInsertBlock()->getParent();
+ return function(llvm_builder.GetInsertBlock()->getParent(), this);
     }
 
     function llvm_compiler::declare_function(
@@ -367,9 +455,9 @@
         llvm::FunctionType* function_type =
             llvm::FunctionType::get(void_return ? void_type : int_type, ints, false);
 
- return llvm::Function::Create(
+ return function(llvm::Function::Create(
                 function_type, llvm::Function::ExternalLinkage,
- name, vm.module());
+ name, vm.module()), this);
     }
 
     basic_block llvm_compiler::make_basic_block(
@@ -380,6 +468,53 @@
         return llvm::BasicBlock::Create(context(), name, parent, before);
     }
 
+ value llvm_compiler::var(std::string const& name)
+ {
+ return var(name.c_str());
+ }
+
+ function llvm_compiler::get_function(std::string const& name)
+ {
+ return get_function(name.c_str());
+ }
+
+ basic_block llvm_compiler::get_insert_block()
+ {
+ return llvm_builder.GetInsertBlock();
+ }
+
+ void llvm_compiler::set_insert_point(basic_block b)
+ {
+ llvm_builder.SetInsertPoint(b);
+ }
+
+ void llvm_compiler::conditional_branch(
+ value cond, basic_block true_br, basic_block false_br)
+ {
+ llvm_builder.CreateCondBr(cond, true_br, false_br);
+ }
+
+ void llvm_compiler::branch(basic_block b)
+ {
+ llvm_builder.CreateBr(b);
+ }
+
+ void llvm_compiler::return_()
+ {
+ llvm_builder.CreateRetVoid();
+ }
+
+ void llvm_compiler::return_(value v)
+ {
+ llvm_builder.CreateRet(v);
+ }
+
+ void llvm_compiler::optimize_function(function f)
+ {
+ // Optimize the function.
+ fpm.run(*f);
+ }
+
     void llvm_compiler::init_fpm()
     {
         // Set up the optimizer pipeline. Start with registering info about how the
@@ -487,7 +622,7 @@
     value compiler::operator()(ast::function_call const& x)
     {
         function callee = get_function(x.function_name.name);
- if (!callee)
+ if (!callee.is_valid())
         {
             error_handler(x.function_name.id,
                 "Function not found: " + x.function_name.name);
@@ -860,25 +995,6 @@
         return true;
     }
 
- namespace
- {
- struct set_arg_name
- {
- typedef std::list<ast::identifier>::const_iterator ast_iter;
- typedef void result_type;
-
- mutable ast_iter i;
- set_arg_name(ast_iter i)
- : i(i) {}
-
- void operator()(value arg) const
- {
- arg.name(i->name.c_str());
- ++i;
- }
- };
- }
-
     function compiler::function_decl(ast::function const& x)
     {
         void_return = x.return_type == "void";
@@ -918,48 +1034,35 @@
             }
 
             // Set names for all arguments.
- for_each_arg(f, set_arg_name(x.args.begin()));
- }
- return f;
- }
-
- namespace
- {
- struct make_arg
- {
- typedef std::list<ast::identifier>::const_iterator ast_iter;
- typedef void result_type;
-
- llvm_compiler& c;
- std::map<std::string, value>& locals;
- mutable ast_iter i;
-
- 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
+ function::arg_range rng = f.args();
+ function::arg_range::const_iterator iter = rng.begin();
+ BOOST_FOREACH(ast::identifier const& arg, x.args)
             {
- // 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;
+ iter->name(arg.name);
+ ++iter;
             }
- };
+ }
+ return f;
     }
 
     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()));
+ function::arg_range rng = f.args();
+ function::arg_range::const_iterator iter = rng.begin();
+ BOOST_FOREACH(ast::identifier const& arg, x.args)
+ {
+ // Create an arg_ for this variable.
+ value arg_ = var(arg.name);
+
+ // Store the initial value into the arg_.
+ arg_.assign(*iter);
+
+ // Add arguments to variable symbol table.
+ locals[arg.name] = arg_;
+ ++iter;
+ }
 
         if (!void_return)
         {
@@ -973,7 +1076,7 @@
         ///////////////////////////////////////////////////////////////////////
         // the signature:
         function f = function_decl(x);
- if (f == 0)
+ if (!f.is_valid())
             return false;
 
         ///////////////////////////////////////////////////////////////////////
@@ -1011,13 +1114,11 @@
             else
                 return_(return_var);
 
- //~ vm.module()->dump();
-
             // Validate the generated code, checking for consistency.
- llvm::verifyFunction(*f);
+ f.verify();
 
             // Optimize the function.
- fpm.run(*f);
+ optimize_function(f);
         }
 
         return true;

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 10:39:03 EDT (Tue, 09 Aug 2011)
@@ -17,6 +17,7 @@
 #include <boost/spirit/include/phoenix_core.hpp>
 #include <boost/spirit/include/phoenix_function.hpp>
 #include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/iterator/transform_iterator.hpp>
 
 #include <llvm/DerivedTypes.h>
 #include <llvm/Constants.h>
@@ -44,13 +45,13 @@
         operator llvm::Value*() const;
 
         value& operator=(value const& rhs);
- bool is_lvalue() const { return is_lvalue_; }
- bool is_valid() const { return v != 0; }
+ bool is_lvalue() const;
+ bool is_valid() const;
 
         value& assign(value const& rhs);
 
- void name(char const* id)
- { v->setName(id); }
+ void name(char const* id);
+ void name(std::string const& id);
 
         friend value operator-(value a);
         friend value operator!(value a);
@@ -100,10 +101,8 @@
         basic_block()
           : b(0) {}
 
- bool has_terminator() const
- { return b->getTerminator() != 0; }
-
- bool is_valid() const { return b != 0; }
+ bool has_terminator() const;
+ bool is_valid() const;
 
     private:
 
@@ -119,41 +118,50 @@
     };
 
     ///////////////////////////////////////////////////////////////////////////
+ struct llvm_compiler;
+
     struct function
     {
- function()
- : f(0) {}
+ private:
 
- operator llvm::Function*() const
- { return f; }
+ struct to_value;
+ typedef llvm::Function::arg_iterator arg_iterator;
+ typedef boost::transform_iterator<
+ to_value, arg_iterator>
+ argval_iterator;
 
- std::size_t arg_size() const
- { return f->arg_size(); }
+ public:
 
- void add(basic_block const& b);
+ typedef boost::iterator_range<argval_iterator> arg_range;
 
- void erase_from_parent()
- { f->eraseFromParent(); }
+ function()
+ : f(0), c(c) {}
 
- basic_block last_block()
- { return &f->getBasicBlockList().back(); }
+ std::string name() const;
 
- bool empty() const
- { return f->empty(); }
+ std::size_t arg_size() const;
+ arg_range args() const;
 
- std::string name() const
- { return f->getName(); }
+ void add(basic_block const& b);
+ void erase_from_parent();
+ basic_block last_block();
+ bool empty() const;
+
+ bool is_valid() const;
+ void verify() const;
 
     private:
 
- function(llvm::Function* f)
- : f(f) {}
+ function(llvm::Function* f, llvm_compiler* c)
+ : f(f), c(c) {}
+
+ operator llvm::Function*() const;
 
         friend struct llvm_compiler;
         llvm::Function* f;
+ llvm_compiler* c;
     };
 
-
     ///////////////////////////////////////////////////////////////////////////
     // The LLVM Compiler. Lower level compiler (does not deal with ASTs)
     ///////////////////////////////////////////////////////////////////////////
@@ -163,36 +171,22 @@
           : llvm_builder(context())
           , vm(vm)
           , fpm(vm.module())
- {
- init_fpm();
- }
+ { init_fpm(); }
 
         value val() { return value(); }
         value val(unsigned int x);
         value val(int x);
         value val(bool x);
- value val(llvm::Value* v);
 
         value var(char const* name);
- value var(std::string const& name)
- { return var(name.c_str()); }
+ value var(std::string const& name);
 
         template <typename Container>
         value call(function callee, Container const& args);
 
- function get_function(char const* name) const;
- function get_function(std::string const& name) const
- { return get_function(name.c_str()); }
-
- 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 get_function(char const* name);
+ function get_function(std::string const& name);
+ function get_current_function();
 
         function declare_function(
             bool void_return
@@ -204,26 +198,17 @@
           , 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); }
+ basic_block get_insert_block();
+ void set_insert_point(basic_block b);
 
         void conditional_branch(
- value cond, basic_block true_br, basic_block false_br)
- { llvm_builder.CreateCondBr(cond, true_br, false_br); }
+ value cond, basic_block true_br, basic_block false_br);
+ void branch(basic_block b);
 
- void branch(basic_block b)
- { llvm_builder.CreateBr(b); }
+ void return_();
+ void return_(value v);
 
- void return_()
- { llvm_builder.CreateRetVoid(); }
-
- void return_(value v)
- { llvm_builder.CreateRet(v); }
-
- struct get_llvm_value;
+ void optimize_function(function f);
 
     protected:
 
@@ -238,6 +223,15 @@
 
     private:
 
+ friend struct function::to_value;
+
+ value val(llvm::Value* v);
+
+ template <typename C>
+ llvm::Value* call_impl(
+ function callee,
+ C const& args);
+
         void init_fpm();
         llvm::IRBuilder<> llvm_builder;
     };


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