Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r73618 - trunk/libs/spirit/example/qi/compiler_tutorial/conjure3
From: joel_at_[hidden]
Date: 2011-08-08 23:35:07


Author: djowel
Date: 2011-08-08 23:35:05 EDT (Mon, 08 Aug 2011)
New Revision: 73618
URL: http://svn.boost.org/trac/boost/changeset/73618

Log:
refactoring: moving low-level llvm stuff into separate classes
Text files modified:
   trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.cpp | 166 +++++++++++++++++++++++++++------------
   trunk/libs/spirit/example/qi/compiler_tutorial/conjure3/compiler.hpp | 34 +++++++
   2 files changed, 146 insertions(+), 54 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-08 23:35:05 EDT (Mon, 08 Aug 2011)
@@ -11,6 +11,7 @@
 
 #include <boost/foreach.hpp>
 #include <boost/variant/apply_visitor.hpp>
+#include <boost/range/adaptor/transformed.hpp>
 #include <boost/assert.hpp>
 #include <boost/lexical_cast.hpp>
 #include <set>
@@ -258,13 +259,13 @@
         // the function. This is used for mutable variables etc.
         llvm::AllocaInst*
         create_entry_block_alloca(
- llvm::Function* function,
+ llvm::Function* f,
             char const* name,
             llvm::LLVMContext& context)
         {
             llvm::IRBuilder<> builder(
- &function->getEntryBlock(),
- function->getEntryBlock().begin());
+ &f->getEntryBlock(),
+ f->getEntryBlock().begin());
 
             return builder.CreateAlloca(
                 llvm::Type::getIntNTy(context, int_size), 0, name);
@@ -273,10 +274,10 @@
 
     value llvm_compiler::var(char const* name)
     {
- llvm::Function* function = llvm_builder.GetInsertBlock()->getParent();
+ llvm::Function* f = llvm_builder.GetInsertBlock()->getParent();
         llvm::IRBuilder<> builder(
- &function->getEntryBlock(),
- function->getEntryBlock().begin());
+ &f->getEntryBlock(),
+ f->getEntryBlock().begin());
 
         llvm::AllocaInst* alloca = builder.CreateAlloca(
             llvm::Type::getIntNTy(context(), int_size), 0, name);
@@ -284,13 +285,66 @@
         return value(alloca, true, &llvm_builder);
     }
 
+ namespace
+ {
+ struct llvm_value
+ {
+ typedef llvm::Value* result_type;
+ llvm::Value* operator()(value const& x) const
+ {
+ 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;
+ }
+
+ return llvm_builder.CreateCall(
+ callee, args.begin(), args.end(), "call_tmp");
+ }
+ }
+
+ template <typename Container>
     value llvm_compiler::call(
- llvm::Function* callee,
- std::vector<llvm::Value*> const& args)
+ function callee,
+ Container const& args)
     {
- return value(
- llvm_builder.CreateCall(callee, args.begin(), args.end(), "call_tmp"),
- false, &llvm_builder);
+ llvm::Value* call = call_impl(
+ llvm_builder, callee,
+ args | boost::adaptors::transformed(llvm_value()));
+
+ if (call == 0)
+ return val();
+ return value(call, false, &llvm_builder);
+ }
+
+ function llvm_compiler::get_function(char const* name) const
+ {
+ return vm.module()->getFunction(name);
+ }
+
+ function llvm_compiler::get_current_function() const
+ {
+ // get the current function
+ return llvm_builder.GetInsertBlock()->getParent();
     }
 
     void llvm_compiler::init_fpm()
@@ -382,30 +436,40 @@
         }
     }
 
+ namespace
+ {
+ struct compile_args
+ {
+ compiler& c;
+ compile_args(compiler& c) : c(c) {}
+
+ typedef value result_type;
+ value operator()(ast::expression const& expr) const
+ {
+ return c(expr);
+ }
+ };
+ }
+
     value compiler::operator()(ast::function_call const& x)
     {
- llvm::Function* callee = vm.module()->getFunction(x.function_name.name);
+ function callee = get_function(x.function_name.name);
         if (!callee)
         {
- error_handler(x.function_name.id, "Function not found: " + x.function_name.name);
+ error_handler(x.function_name.id,
+ "Function not found: " + x.function_name.name);
             return val();
         }
 
- if (callee->arg_size() != x.args.size())
+ if (callee.arg_size() != x.args.size())
         {
- error_handler(x.function_name.id, "Wrong number of arguments: " + x.function_name.name);
+ error_handler(x.function_name.id,
+ "Wrong number of arguments: " + x.function_name.name);
             return val();
         }
 
- std::vector<llvm::Value*> args;
- BOOST_FOREACH(ast::expression const& expr, x.args)
- {
- args.push_back((*this)(expr));
- if (args.back() == 0)
- return val();
- }
-
- return call(callee, args);
+ return call(callee,
+ x.args | boost::adaptors::transformed(compile_args(*this)));
     }
 
     namespace
@@ -641,11 +705,11 @@
         if (!condition.is_valid())
             return false;
 
- llvm::Function* function = builder().GetInsertBlock()->getParent();
+ llvm::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", function);
+ llvm::BasicBlock* then_block = llvm::BasicBlock::Create(context(), "if.then", f);
         llvm::BasicBlock* else_block = 0;
         llvm::BasicBlock* exit_block = 0;
 
@@ -676,7 +740,7 @@
         if (x.else_)
         {
             // Emit else block.
- function->getBasicBlockList().push_back(else_block);
+ f->getBasicBlockList().push_back(else_block);
             builder().SetInsertPoint(else_block);
             if (!(*this)(*x.else_))
                 return false;
@@ -693,7 +757,7 @@
         if (exit_block != 0)
         {
             // Emit exit block
- function->getBasicBlockList().push_back(exit_block);
+ f->getBasicBlockList().push_back(exit_block);
             builder().SetInsertPoint(exit_block);
         }
         return true;
@@ -701,9 +765,9 @@
 
     bool compiler::operator()(ast::while_statement const& x)
     {
- llvm::Function* function = builder().GetInsertBlock()->getParent();
+ llvm::Function* f = get_current_function();
 
- llvm::BasicBlock* cond_block = llvm::BasicBlock::Create(context(), "while.cond", 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");
 
@@ -713,7 +777,7 @@
         if (!condition.is_valid())
             return false;
         builder().CreateCondBr(condition, body_block, exit_block);
- function->getBasicBlockList().push_back(body_block);
+ f->getBasicBlockList().push_back(body_block);
         builder().SetInsertPoint(body_block);
 
         if (!(*this)(x.body))
@@ -723,7 +787,7 @@
             builder().CreateBr(cond_block); // loop back
 
         // Emit exit block
- function->getBasicBlockList().push_back(exit_block);
+ f->getBasicBlockList().push_back(exit_block);
         builder().SetInsertPoint(exit_block);
 
         return true;
@@ -778,21 +842,21 @@
         llvm::FunctionType* function_type =
             llvm::FunctionType::get(void_return ? void_type : int_type, ints, false);
 
- llvm::Function* function =
+ llvm::Function* f =
             llvm::Function::Create(
                 function_type, llvm::Function::ExternalLinkage,
                 current_function_name, vm.module());
 
         // If function conflicted, the function already exixts. If it has a
         // body, don't allow redefinition or reextern.
- if (function->getName() != current_function_name)
+ if (f->getName() != current_function_name)
         {
             // Delete the one we just made and get the existing one.
- function->eraseFromParent();
- function = vm.module()->getFunction(current_function_name);
+ f->eraseFromParent();
+ f = get_function(current_function_name);
 
             // If function already has a body, reject this.
- if (!function->empty())
+ if (!f->empty())
             {
                 error_handler(
                     x.function_name.id,
@@ -801,7 +865,7 @@
             }
 
             // If function took a different number of args, reject.
- if (function->arg_size() != x.args.size())
+ if (f->arg_size() != x.args.size())
             {
                 error_handler(
                     x.function_name.id,
@@ -811,21 +875,21 @@
             }
 
             // Set names for all arguments.
- llvm::Function::arg_iterator iter = function->arg_begin();
+ llvm::Function::arg_iterator iter = f->arg_begin();
             BOOST_FOREACH(ast::identifier const& arg, x.args)
             {
                 iter->setName(arg.name);
                 ++iter;
             }
         }
- return function;
+ return f;
     }
 
- void compiler::function_allocas(ast::function const& x, llvm::Function* function)
+ void compiler::function_allocas(ast::function const& x, llvm::Function* f)
     {
         // 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 = function->arg_begin();
+ llvm::Function::arg_iterator iter = f->arg_begin();
         BOOST_FOREACH(ast::identifier const& arg, x.args)
         {
             // Create an arg_ for this variable.
@@ -850,8 +914,8 @@
     {
         ///////////////////////////////////////////////////////////////////////
         // the signature:
- llvm::Function* function = function_decl(x);
- if (function == 0)
+ llvm::Function* f = function_decl(x);
+ if (f == 0)
             return false;
 
         ///////////////////////////////////////////////////////////////////////
@@ -860,21 +924,21 @@
         {
             // Create a new basic block to start insertion into.
             llvm::BasicBlock* block =
- llvm::BasicBlock::Create(context(), "entry", function);
+ llvm::BasicBlock::Create(context(), "entry", f);
             builder().SetInsertPoint(block);
 
- function_allocas(x, function);
+ function_allocas(x, f);
             return_block = llvm::BasicBlock::Create(context(), "return");
 
             if (!(*this)(*x.body))
             {
                 // Error reading body, remove function.
- function->eraseFromParent();
+ f->eraseFromParent();
                 return false;
             }
 
             llvm::BasicBlock* last_block =
- &function->getBasicBlockList().back();
+ &f->getBasicBlockList().back();
 
             // If the last block is unterminated, connect it to return_block
             if (last_block->getTerminator() == 0)
@@ -883,7 +947,7 @@
                 builder().CreateBr(return_block);
             }
 
- function->getBasicBlockList().push_back(return_block);
+ f->getBasicBlockList().push_back(return_block);
             builder().SetInsertPoint(return_block);
 
             if (void_return)
@@ -894,10 +958,10 @@
             //~ vm.module()->dump();
 
             // Validate the generated code, checking for consistency.
- llvm::verifyFunction(*function);
+ llvm::verifyFunction(*f);
 
             // Optimize the function.
- fpm.run(*function);
+ fpm.run(*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-08 23:35:05 EDT (Mon, 08 Aug 2011)
@@ -90,6 +90,27 @@
     };
 
     ///////////////////////////////////////////////////////////////////////////
+ struct function
+ {
+ function()
+ : f(0) {}
+
+ operator llvm::Function*() const
+ { return f; }
+
+ std::size_t arg_size() const
+ { return f->arg_size(); }
+
+ private:
+
+ function(llvm::Function* f)
+ : f(f) {}
+
+ friend struct llvm_compiler;
+ llvm::Function* f;
+ };
+
+ ///////////////////////////////////////////////////////////////////////////
     // The LLVM Compiler. Lower level compiler (does not deal with ASTs)
     ///////////////////////////////////////////////////////////////////////////
     struct llvm_compiler
@@ -109,10 +130,17 @@
         value val(llvm::Value* v);
 
         value var(char const* name);
+ value var(std::string const& name)
+ { return var(name.c_str()); }
+
+ 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()); }
 
- value call(
- llvm::Function* callee,
- std::vector<llvm::Value*> const& args);
+ function get_current_function() const;
 
     protected:
 


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