1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141 |
- /*=============================================================================
- Copyright (c) 2001-2011 Joel de Guzman
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- =============================================================================*/
- #include "config.hpp"
- #include "compiler.hpp"
- #include "annotation.hpp"
- #include "vm.hpp"
- #include <boost/foreach.hpp>
- #include <boost/variant/apply_visitor.hpp>
- #include <boost/range/adaptor/transformed.hpp>
- #include <boost/assert.hpp>
- #include <set>
- namespace client { namespace code_gen
- {
- value::value()
- : v(0),
- is_lvalue_(false),
- builder(0)
- {}
- value::value(
- llvm::Value* v,
- bool is_lvalue_,
- llvm::IRBuilder<>* builder)
- : v(v),
- is_lvalue_(is_lvalue_),
- builder(builder)
- {}
- value::value(value const& rhs)
- : v(rhs.v),
- is_lvalue_(rhs.is_lvalue_),
- builder(rhs.builder)
- {}
- bool value::is_lvalue() const
- {
- return is_lvalue_;
- }
- bool value::is_valid() const
- {
- return v != 0;
- }
- value::operator bool() 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_)
- {
- BOOST_ASSERT(builder != 0);
- return builder->CreateLoad(v, v->getName());
- }
- return v;
- }
- value& value::operator=(value const& rhs)
- {
- v = rhs.v;
- is_lvalue_ = rhs.is_lvalue_;
- builder = rhs.builder;
- return *this;
- }
- value& value::assign(value const& rhs)
- {
- BOOST_ASSERT(is_lvalue());
- BOOST_ASSERT(builder != 0);
- builder->CreateStore(rhs, v);
- return *this;
- }
- value operator-(value a)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateNeg(a, "neg_tmp"),
- false, a.builder
- );
- }
- value operator!(value a)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateNot(a, "not_tmp"),
- false, a.builder
- );
- }
- value operator+(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateAdd(a, b, "add_tmp"),
- false, a.builder
- );
- }
- value operator-(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateSub(a, b, "sub_tmp"),
- false, a.builder
- );
- }
- value operator*(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateMul(a, b, "mul_tmp"),
- false, a.builder
- );
- }
- value operator/(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateSDiv(a, b, "div_tmp"),
- false, a.builder
- );
- }
- value operator%(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateSRem(a, b, "mod_tmp"),
- false, a.builder
- );
- }
- value operator&(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateAnd(a, b, "and_tmp"),
- false, a.builder
- );
- }
- value operator|(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateOr(a, b, "or_tmp"),
- false, a.builder
- );
- }
- value operator^(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateXor(a, b, "xor_tmp"),
- false, a.builder
- );
- }
- value operator<<(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateShl(a, b, "shl_tmp"),
- false, a.builder
- );
- }
- value operator>>(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateLShr(a, b, "shr_tmp"),
- false, a.builder
- );
- }
- value operator==(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateICmpEQ(a, b, "eq_tmp"),
- false, a.builder
- );
- }
- value operator!=(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateICmpNE(a, b, "ne_tmp"),
- false, a.builder
- );
- }
- value operator<(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateICmpSLT(a, b, "slt_tmp"),
- false, a.builder
- );
- }
- value operator<=(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateICmpSLE(a, b, "sle_tmp"),
- false, a.builder
- );
- }
- value operator>(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateICmpSGT(a, b, "sgt_tmp"),
- false, a.builder
- );
- }
- value operator>=(value a, value b)
- {
- BOOST_ASSERT(a.builder != 0);
- return value(
- a.builder->CreateICmpSGE(a, b, "sge_tmp"),
- false, a.builder
- );
- }
- 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);
- arg_val_iterator first(f->arg_begin(), to_value());
- arg_val_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(
- llvm::ConstantInt::get(context(), llvm::APInt(int_size, x)),
- false, &llvm_builder);
- }
- value llvm_compiler::val(int x)
- {
- return value(
- llvm::ConstantInt::get(context(), llvm::APInt(int_size, x)),
- false, &llvm_builder);
- }
- value llvm_compiler::val(bool x)
- {
- return value(
- llvm::ConstantInt::get(context(), llvm::APInt(1, x)),
- false, &llvm_builder);
- }
- value llvm_compiler::val(llvm::Value* v)
- {
- return value(v, false, &llvm_builder);
- }
- namespace
- {
- // Create an alloca instruction in the entry block of
- // the function. This is used for mutable variables etc.
- llvm::AllocaInst*
- make_entry_block_alloca(
- llvm::Function* f,
- char const* name,
- llvm::LLVMContext& context)
- {
- llvm::IRBuilder<> builder(
- &f->getEntryBlock(),
- f->getEntryBlock().begin());
- return builder.CreateAlloca(
- llvm::Type::getIntNTy(context, int_size), 0, name);
- }
- }
- value llvm_compiler::var(char const* name)
- {
- llvm::Function* f = llvm_builder.GetInsertBlock()->getParent();
- llvm::IRBuilder<> builder(
- &f->getEntryBlock(),
- f->getEntryBlock().begin());
- llvm::AllocaInst* alloca = builder.CreateAlloca(
- llvm::Type::getIntNTy(context(), int_size), 0, name);
- return value(alloca, true, &llvm_builder);
- }
- struct value::to_llvm_value
- {
- typedef llvm::Value* result_type;
- llvm::Value* operator()(value const& x) const
- {
- return x;
- }
- };
- 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());
- // 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(
- function callee,
- Container const& args)
- {
- llvm::Value* call = call_impl(
- callee,
- args | boost::adaptors::transformed(value::to_llvm_value()));
- if (call == 0)
- return val();
- return value(call, false, &llvm_builder);
- }
- function llvm_compiler::get_function(char const* name)
- {
- return function(vm.module()->getFunction(name), this);
- }
- function llvm_compiler::get_current_function()
- {
- // get the current function
- return function(llvm_builder.GetInsertBlock()->getParent(), this);
- }
- function llvm_compiler::declare_function(
- bool void_return
- , std::string const& name
- , std::size_t nargs)
- {
- llvm::Type const* int_type =
- llvm::Type::getIntNTy(context(), int_size);
- llvm::Type const* void_type = llvm::Type::getVoidTy(context());
- std::vector<llvm::Type const*> ints(nargs, int_type);
- llvm::Type const* return_type = void_return ? void_type : int_type;
- llvm::FunctionType* function_type =
- llvm::FunctionType::get(void_return ? void_type : int_type, ints, false);
- return function(llvm::Function::Create(
- function_type, llvm::Function::ExternalLinkage,
- name, vm.module()), this);
- }
- basic_block llvm_compiler::make_basic_block(
- char const* name
- , function parent
- , basic_block before)
- {
- 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
- // target lays out data structures.
- fpm.add(new llvm::TargetData(*vm.execution_engine()->getTargetData()));
- // Provide basic AliasAnalysis support for GVN.
- fpm.add(llvm::createBasicAliasAnalysisPass());
- // Promote allocas to registers.
- fpm.add(llvm::createPromoteMemoryToRegisterPass());
- // Do simple "peephole" optimizations and bit-twiddling optzns.
- fpm.add(llvm::createInstructionCombiningPass());
- // Reassociate expressions.
- fpm.add(llvm::createReassociatePass());
- // Eliminate Common SubExpressions.
- fpm.add(llvm::createGVNPass());
- // Simplify the control flow graph (deleting unreachable blocks, etc).
- fpm.add(llvm::createCFGSimplificationPass());
- fpm.doInitialization();
- }
- value compiler::operator()(unsigned int x)
- {
- return val(x);
- }
- value compiler::operator()(bool x)
- {
- return val(x);
- }
- value compiler::operator()(ast::primary_expr const& x)
- {
- return boost::apply_visitor(*this, x.get());
- }
- value compiler::operator()(ast::identifier const& x)
- {
- // Look this variable up in the function.
- if (locals.find(x.name) == locals.end())
- {
- error_handler(x.id, "Undeclared variable: " + x.name);
- return val();
- }
- return locals[x.name];
- }
- value compiler::operator()(ast::unary_expr const& x)
- {
- value operand = boost::apply_visitor(*this, x.operand_);
- if (!operand.is_valid())
- return val();
- switch (x.operator_)
- {
- case token_ids::compl_: return operand ^ val(-1);
- case token_ids::minus: return -operand;
- case token_ids::not_: return !operand;
- case token_ids::plus: return operand;
- case token_ids::plus_plus:
- {
- if (!operand.is_lvalue())
- {
- error_handler(x.id, "++ needs an var");
- return val();
- }
- value r = operand + val(1);
- operand.assign(r);
- return operand;
- }
- case token_ids::minus_minus:
- {
- if (!operand.is_lvalue())
- {
- error_handler(x.id, "-- needs an var");
- return val();
- }
- value r = operand - val(1);
- operand.assign(r);
- return operand;
- }
- default:
- BOOST_ASSERT(0);
- return val();
- }
- }
- 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)
- {
- function callee = get_function(x.function_name.name);
- if (!callee.is_valid())
- {
- error_handler(x.function_name.id,
- "Function not found: " + x.function_name.name);
- return val();
- }
- if (callee.arg_size() != x.args.size())
- {
- error_handler(x.function_name.id,
- "Wrong number of arguments: " + x.function_name.name);
- return val();
- }
- return call(callee,
- x.args | boost::adaptors::transformed(compile_args(*this)));
- }
- namespace
- {
- int precedence[] = {
- // precedence 1
- 1, // op_comma
- // precedence 2
- 2, // op_assign
- 2, // op_plus_assign
- 2, // op_minus_assign
- 2, // op_times_assign
- 2, // op_divide_assign
- 2, // op_mod_assign
- 2, // op_bit_and_assign
- 2, // op_bit_xor_assign
- 2, // op_bitor_assign
- 2, // op_shift_left_assign
- 2, // op_shift_right_assign
- // precedence 3
- 3, // op_logical_or
- // precedence 4
- 4, // op_logical_and
- // precedence 5
- 5, // op_bit_or
- // precedence 6
- 6, // op_bit_xor
- // precedence 7
- 7, // op_bit_and
- // precedence 8
- 8, // op_equal
- 8, // op_not_equal
- // precedence 9
- 9, // op_less
- 9, // op_less_equal
- 9, // op_greater
- 9, // op_greater_equal
- // precedence 10
- 10, // op_shift_left
- 10, // op_shift_right
- // precedence 11
- 11, // op_plus
- 11, // op_minus
- // precedence 12
- 12, // op_times
- 12, // op_divide
- 12 // op_mod
- };
- }
- inline int precedence_of(token_ids::type op)
- {
- return precedence[op & 0xFF];
- }
- value compiler::compile_binary_expression(
- value lhs, value rhs, token_ids::type op)
- {
- switch (op)
- {
- case token_ids::plus: return lhs + rhs;
- case token_ids::minus: return lhs - rhs;
- case token_ids::times: return lhs * rhs;
- case token_ids::divide: return lhs / rhs;
- case token_ids::mod: return lhs % rhs;
- case token_ids::logical_or:
- case token_ids::bit_or: return lhs | rhs;
- case token_ids::logical_and:
- case token_ids::bit_and: return lhs & rhs;
- case token_ids::bit_xor: return lhs ^ rhs;
- case token_ids::shift_left: return lhs << rhs;
- case token_ids::shift_right: return lhs >> rhs;
- case token_ids::equal: return lhs == rhs;
- case token_ids::not_equal: return lhs != rhs;
- case token_ids::less: return lhs < rhs;
- case token_ids::less_equal: return lhs <= rhs;
- case token_ids::greater: return lhs > rhs;
- case token_ids::greater_equal: return lhs >= rhs;
- default: BOOST_ASSERT(0); return val();
- }
- }
- // The Shunting-yard algorithm
- value compiler::compile_expression(
- int min_precedence,
- value lhs,
- std::list<ast::operation>::const_iterator& rest_begin,
- std::list<ast::operation>::const_iterator rest_end)
- {
- while ((rest_begin != rest_end) &&
- (precedence_of(rest_begin->operator_) >= min_precedence))
- {
- token_ids::type op = rest_begin->operator_;
- value rhs = boost::apply_visitor(*this, rest_begin->operand_);
- if (!rhs.is_valid())
- return val();
- ++rest_begin;
- while ((rest_begin != rest_end) &&
- (precedence_of(rest_begin->operator_) > precedence_of(op)))
- {
- token_ids::type next_op = rest_begin->operator_;
- rhs = compile_expression(
- precedence_of(next_op), rhs, rest_begin, rest_end);
- }
- lhs = compile_binary_expression(lhs, rhs, op);
- }
- return lhs;
- }
- value compiler::operator()(ast::expression const& x)
- {
- value lhs = boost::apply_visitor(*this, x.first);
- if (!lhs.is_valid())
- return val();
- std::list<ast::operation>::const_iterator rest_begin = x.rest.begin();
- return compile_expression(0, lhs, rest_begin, x.rest.end());
- }
- value compiler::operator()(ast::assignment const& x)
- {
- if (locals.find(x.lhs.name) == locals.end())
- {
- error_handler(x.lhs.id, "Undeclared variable: " + x.lhs.name);
- return val();
- }
- value lhs = locals[x.lhs.name];
- value rhs = (*this)(x.rhs);
- if (!rhs.is_valid())
- return val();
- if (x.operator_ == token_ids::assign)
- {
- lhs.assign(rhs);
- return lhs;
- }
- value result;
- switch (x.operator_)
- {
- case token_ids::plus_assign: result = lhs + rhs; break;
- case token_ids::minus_assign: result = lhs - rhs; break;
- case token_ids::times_assign: result = lhs * rhs; break;
- case token_ids::divide_assign: result = lhs / rhs; break;
- case token_ids::mod_assign: result = lhs % rhs; break;
- case token_ids::bit_and_assign: result = lhs & rhs; break;
- case token_ids::bit_xor_assign: result = lhs ^ rhs; break;
- case token_ids::bit_or_assign: result = lhs | rhs; break;
- case token_ids::shift_left_assign: result = lhs << rhs; break;
- case token_ids::shift_right_assign: result = lhs >> rhs; break;
- default: BOOST_ASSERT(0); return val();
- }
- lhs.assign(result);
- return lhs;
- }
- bool compiler::operator()(ast::variable_declaration const& x)
- {
- if (locals.find(x.lhs.name) != locals.end())
- {
- error_handler(x.lhs.id, "Duplicate variable: " + x.lhs.name);
- return false;
- }
- value init;
- std::string const& name = x.lhs.name;
- if (x.rhs) // if there's an RHS initializer
- {
- init = (*this)(*x.rhs);
- if (!init.is_valid()) // don't add the variable if the RHS fails
- return false;
- }
- value var_ = var(name.c_str());
- if (init.is_valid())
- var_.assign(init);
- // Remember this binding.
- locals[name] = var_;
- return true;
- }
- struct compiler::statement_compiler : compiler
- {
- typedef bool result_type;
- };
- compiler::statement_compiler& compiler::as_statement()
- {
- return *static_cast<statement_compiler*>(this);
- }
- bool compiler::operator()(ast::statement const& x)
- {
- if (boost::get<ast::nil>(&x) != 0) // empty statement
- return true;
- return boost::apply_visitor(as_statement(), x);
- }
- bool compiler::operator()(ast::statement_list const& x)
- {
- BOOST_FOREACH(ast::statement const& s, x)
- {
- if (!(*this)(s))
- return false;
- }
- return true;
- }
- bool compiler::operator()(ast::if_statement const& x)
- {
- value condition = (*this)(x.condition);
- if (!condition.is_valid())
- return false;
- function f = get_current_function();
- // Create blocks for the then and else cases. Insert the 'then' block at the
- // end of the function.
- basic_block then_block = make_basic_block("if.then", f);
- basic_block else_block;
- basic_block exit_block;
- if (x.else_)
- {
- else_block = make_basic_block("if.else");
- conditional_branch(condition, then_block, else_block);
- }
- else
- {
- exit_block = make_basic_block("if.end");
- conditional_branch(condition, then_block, exit_block);
- }
- // Emit then value.
- set_insert_point(then_block);
- if (!(*this)(x.then))
- return false;
- if (!then_block.has_terminator())
- {
- 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 = get_insert_block();
- if (x.else_)
- {
- // Emit else block.
- f.add(else_block);
- set_insert_point(else_block);
- if (!(*this)(*x.else_))
- return false;
- if (!else_block.has_terminator())
- {
- 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 = get_insert_block();
- }
- if (exit_block.is_valid())
- {
- // Emit exit block
- f.add(exit_block);
- set_insert_point(exit_block);
- }
- return true;
- }
- bool compiler::operator()(ast::while_statement const& x)
- {
- function f = get_current_function();
- 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");
- branch(cond_block);
- set_insert_point(cond_block);
- value condition = (*this)(x.condition);
- if (!condition.is_valid())
- return false;
- 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.has_terminator())
- branch(cond_block); // loop back
- // Emit exit block
- f.add(exit_block);
- set_insert_point(exit_block);
- return true;
- }
- bool compiler::operator()(ast::return_statement const& x)
- {
- if (void_return)
- {
- if (x.expr)
- {
- error_handler(
- x.id, "'void' function returning a value: ");
- return false;
- }
- }
- else
- {
- if (!x.expr)
- {
- error_handler(
- x.id, current_function_name
- + " function must return a value: ");
- return false;
- }
- }
- if (x.expr)
- {
- value return_val = (*this)(*x.expr);
- if (!return_val.is_valid())
- return false;
- return_var.assign(return_val);
- }
- branch(return_block);
- return true;
- }
- function compiler::function_decl(ast::function const& x)
- {
- void_return = x.return_type == "void";
- current_function_name = x.function_name.name;
- 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.name() != current_function_name)
- {
- // Delete the one we just made and get the existing one.
- f.erase_from_parent();
- f = get_function(current_function_name);
- // If function already has a body, reject this.
- if (!f.empty())
- {
- error_handler(
- x.function_name.id,
- "Duplicate function: " + x.function_name.name);
- return function();
- }
- // If function took a different number of args, reject.
- if (f.arg_size() != x.args.size())
- {
- error_handler(
- x.function_name.id,
- "Redefinition of function with different # args: "
- + x.function_name.name);
- return function();
- }
- // Set names for all arguments.
- function::arg_range rng = f.args();
- function::arg_range::const_iterator iter = rng.begin();
- BOOST_FOREACH(ast::identifier const& arg, x.args)
- {
- 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.
- 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)
- {
- // Create an alloca for the return value
- return_var = var("return.val");
- }
- }
- bool compiler::operator()(ast::function const& x)
- {
- ///////////////////////////////////////////////////////////////////////
- // the signature:
- function f = function_decl(x);
- if (!f.is_valid())
- return false;
- ///////////////////////////////////////////////////////////////////////
- // the body:
- if (x.body) // compile the body if this is not a prototype
- {
- // Create a new basic block to start insertion into.
- basic_block block = make_basic_block("entry", f);
- set_insert_point(block);
- function_allocas(x, f);
- return_block = make_basic_block("return");
- if (!(*this)(*x.body))
- {
- // Error reading body, remove function.
- f.erase_from_parent();
- return false;
- }
- basic_block last_block = f.last_block();
- // If the last block is unterminated, connect it to return_block
- if (!last_block.has_terminator())
- {
- set_insert_point(last_block);
- branch(return_block);
- }
- f.add(return_block);
- set_insert_point(return_block);
- if (void_return)
- return_();
- else
- return_(return_var);
- // Validate the generated code, checking for consistency.
- f.verify();
- // Optimize the function.
- optimize_function(f);
- }
- return true;
- }
- bool compiler::operator()(ast::function_list const& x)
- {
- BOOST_FOREACH(ast::function const& f, x)
- {
- locals.clear(); // clear the variables
- if (!(*this)(f))
- return false;
- }
- return true;
- }
- }}
|