[code generation] basic to-llvm lowering

This commit is contained in:
Philippe Tillet
2019-01-05 14:50:31 -05:00
parent f131ebb0bc
commit ec656af57c
23 changed files with 320 additions and 56 deletions

View File

@@ -5,8 +5,8 @@ include(CTest)
# FLEX/YACC
find_package(BISON)
find_package(FLEX)
BISON_TARGET(Parser ${CMAKE_CURRENT_SOURCE_DIR}/include/parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp)
FLEX_TARGET(Lexer ${CMAKE_CURRENT_SOURCE_DIR}/include/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/scanner.cpp)
BISON_TARGET(Parser ${CMAKE_CURRENT_SOURCE_DIR}/include/ast/parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp)
FLEX_TARGET(Lexer ${CMAKE_CURRENT_SOURCE_DIR}/include/ast/scanner.l ${CMAKE_CURRENT_BINARY_DIR}/scanner.cpp)
get_filename_component(BISON_Parser_INCLUDE_DIRECTORIES ${BISON_Parser_OUTPUT_HEADER} DIRECTORY)
include_directories(${BISON_Parser_INCLUDE_DIRECTORIES})

4
TODO Normal file
View File

@@ -0,0 +1,4 @@
[Intermediate Representation]
- proper naming scheme
- symbols table
- name conflicts on globals?

View File

@@ -1,8 +1,9 @@
#include <cstring>
#include <cstdio>
#include "ast.h"
#include "ast/ast.h"
#include "ir/context.h"
#include "ir/module.h"
#include "codegen/lowering.h"
typedef struct yy_buffer_state * YY_BUFFER_STATE;
extern int yyparse();

View File

@@ -6,7 +6,7 @@ class node;
}
using namespace tdl::ast;
#define YYSTYPE node*
#include "../include/ast.h"
#include "../include/ast/ast.h"
extern char* yytext;
void yyerror(const char *s);

10
include/codegen/layout.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef TDL_INCLUDE_IR_CODEGEN_LAYOUT_H
#define TDL_INCLUDE_IR_CODEGEN_LAYOUT_H
namespace tdl{
namespace codegen{
}
}
#endif

View File

@@ -0,0 +1,10 @@
#ifndef TDL_INCLUDE_IR_CODEGEN_LIVENESS_H
#define TDL_INCLUDE_IR_CODEGEN_LIVENESS_H
namespace tdl{
namespace codegen{
}
}
#endif

118
include/codegen/lowering.h Normal file
View File

@@ -0,0 +1,118 @@
#ifndef TDL_INCLUDE_IR_CODEGEN_LOWERING_H
#define TDL_INCLUDE_IR_CODEGEN_LOWERING_H
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "ir/context.h"
#include "ir/module.h"
#include "ir/function.h"
#include "ir/type.h"
namespace tdl{
namespace codegen{
/* convert ir::type to llvm::Type */
llvm::Type *llvm_type(ir::type *ty, llvm::LLVMContext &ctx) {
// function
if(auto* tt = dynamic_cast<ir::function_type*>(ty)){
llvm::Type *return_ty = llvm_type(tt->get_return_ty(), ctx);
std::vector<llvm::Type*> param_tys;
std::transform(tt->params_begin(), tt->params_end(), std::back_inserter(param_tys),
[&ctx](ir::type* t){ return llvm_type(t, ctx);});
return llvm::FunctionType::get(return_ty, param_tys, false);
}
// pointer
if(ty->is_pointer_ty()){
llvm::Type *elt_ty = llvm_type(ty->get_pointer_element_ty(), ctx);
unsigned addr_space = ty->get_pointer_address_space();
return llvm::PointerType::get(elt_ty, addr_space);
}
// integer
if(ty->is_integer_ty()){
unsigned bitwidth = ty->get_integer_bitwidth();
return llvm::IntegerType::get(ctx, bitwidth);
}
// primitive types
switch(ty->get_type_id()){
case ir::type::VoidTyID: return llvm::Type::getVoidTy(ctx);
case ir::type::HalfTyID: return llvm::Type::getHalfTy(ctx);
case ir::type::FloatTyID: return llvm::Type::getFloatTy(ctx);
case ir::type::DoubleTyID: return llvm::Type::getDoubleTy(ctx);
case ir::type::X86_FP80TyID: return llvm::Type::getX86_FP80Ty(ctx);
case ir::type::PPC_FP128TyID: return llvm::Type::getPPC_FP128Ty(ctx);
case ir::type::LabelTyID: return llvm::Type::getLabelTy(ctx);
case ir::type::MetadataTyID: return llvm::Type::getMetadataTy(ctx);
case ir::type::TokenTyID: return llvm::Type::getTokenTy(ctx);
default: break;
}
// unknown type
throw std::runtime_error("unknown conversion from ir::type to llvm::Type");
}
/* convert ir::instruction to llvm::Instruction */
llvm::Instruction *llvm_inst(ir::instruction *inst, llvm::LLVMContext & ctx,
std::map<ir::value*, llvm::Value*> &v,
std::map<ir::basic_block*, llvm::BasicBlock*> &b) {
if(auto* ii = dynamic_cast<ir::cond_branch_inst*>(inst))
return llvm::BranchInst::Create(b[ii->get_true_dest()], b[ii->get_false_dest()], v[ii->get_cond()]);
if(auto* ii = dynamic_cast<ir::uncond_branch_inst*>(inst))
return llvm::BranchInst::Create(b[ii->get_dest()]);
if(auto* ii = dynamic_cast<ir::phi_node*>(inst))
return llvm::PHINode::Create(llvm_type(ii->get_type(), ctx), ii->get_num_operands(), ii->get_name());
if(auto* ii = dynamic_cast<ir::return_inst*>(inst))
return llvm::ReturnInst::Create(ctx, v[ii->get_return_value()]);
if(auto* ii = dynamic_cast<ir::binary_operator*>(inst))
return llvm::BinaryOperator::Create(ii->get_op(), v[ii->get_operand(0)], v[ii->get_operand(1)], ii->get_name());
if(auto* ii = dynamic_cast<ir::icmp_inst*>(inst))
return llvm::CmpInst::Create(llvm::Instruction::ICmp, ii->get_pred(), v[ii->get_operand(0)], v[ii->get_operand(1)], ii->get_name());
if(auto* ii = dynamic_cast<ir::fcmp_inst*>(inst))
return llvm::FCmpInst::Create(llvm::Instruction::FCmp, ii->get_pred(), v[ii->get_operand(0)], v[ii->get_operand(1)], ii->get_name());
if(auto* ii = dynamic_cast<ir::cast_inst*>(inst))
return llvm::CastInst::Create(ii->get_op(), v[ii->get_operand(0)], llvm_type(ii->get_type(), ctx), ii->get_name());
if(auto* ii = dynamic_cast<ir::getelementptr_inst*>(inst)){
std::vector<llvm::Value*> idx_vals;
std::transform(ii->idx_begin(), ii->idx_end(), std::back_inserter(idx_vals),
[&v](ir::value* x){ return v[x];});
return llvm::GetElementPtrInst::Create(llvm_type(ii->get_source_elt_ty(), ctx), v[ii->get_operand(0)], idx_vals, ii->get_name());
}
if(ir::load_inst* ii = dynamic_cast<ir::load_inst*>(inst))
return new llvm::LoadInst(v[ii->get_pointer_operand()], ii->get_name());
// unknown instruction
throw std::runtime_error("unknown conversion from ir::type to llvm::Type");
}
void lowering(ir::module &src, llvm::Module &dst){
using namespace llvm;
std::map<ir::value*, Value*> vmap;
std::map<ir::basic_block*, BasicBlock*> bmap;
LLVMContext &dst_ctx = dst.getContext();
IRBuilder<> dst_builder(dst_ctx);
// iterate over functions
for(ir::function *fn: src.get_function_list()) {
// create LLVM function
Type *fn_ty = llvm_type(fn->get_type(), dst_ctx);
Function *dst_function = (Function*)dst.getOrInsertFunction(fn->get_name(), fn_ty);
// create blocks
for(ir::basic_block *block: fn->blocks()) {
BasicBlock *dst_block = BasicBlock::Create(dst_ctx, block->get_name(), dst_function);
bmap[block] = dst_block;
}
// iterate through block
for(ir::basic_block *block: fn->blocks()) {
dst_builder.SetInsertPoint(bmap[block]);
for(ir::instruction *inst: block->get_inst_list()) {
Instruction *dst_inst = llvm_inst(inst, dst_ctx, vmap, bmap);
vmap[inst] = dst_inst;
}
}
// add phi operands
}
}
}
}
#endif

View File

@@ -0,0 +1,10 @@
#ifndef TDL_INCLUDE_IR_CODEGEN_STORAGE_ALLOC_H
#define TDL_INCLUDE_IR_CODEGEN_STORAGE_ALLOC_H
namespace tdl{
namespace codegen{
}
}
#endif

10
include/codegen/tune.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef TDL_INCLUDE_IR_CODEGEN_TUNE_H
#define TDL_INCLUDE_IR_CODEGEN_TUNE_H
namespace tdl{
namespace codegen{
}
}
#endif

View File

@@ -56,7 +56,7 @@ private:
class global_value: public constant {
public:
enum linkage_types_t {
internal
external
};
public:

View File

@@ -11,6 +11,7 @@ namespace ir{
class function;
class function_type;
class module;
class basic_block;
/* Argument */
class argument: public value{
@@ -25,29 +26,41 @@ private:
unsigned arg_no_;
};
/* Attribute */
class attribute {
};
/* Function */
class function: public global_object{
typedef std::vector<argument*> args_t;
typedef args_t::iterator arg_iterator;
typedef args_t::const_iterator const_arg_iterator;
typedef std::vector<basic_block*> blocks_t;
typedef blocks_t::iterator block_iterator;
typedef blocks_t::const_iterator const_block_iterator;
private:
function(function_type *ty, linkage_types_t linkage,
const std::string &name = "", module *parent = nullptr);
public:
arg_iterator arg_begin() { return args_.begin(); }
arg_iterator arg_end() { return args_.end(); }
const_arg_iterator arg_begin() const { return args_.begin(); }
const_arg_iterator arg_end() const { return args_.end(); }
// arguments
const args_t &args() { return args_; }
// Factory methods
static function *create(function_type *ty, linkage_types_t linkage,
const std::string &name, module *mod);
// blocks
const blocks_t &blocks() { return blocks_; }
void insert_block(basic_block* block, basic_block *next = nullptr);
private:
module *parent_;
args_t args_;
bool init_;
function_type *fn_ty_;
args_t args_;
blocks_t blocks_;
};
}

View File

@@ -69,6 +69,13 @@ public:
// Get operand
op_t get_op() const { return op_; }
// Bool
bool is_terminator() const;
bool is_binary_op() const;
bool is_int_div_rem() const;
bool is_shift() const;
bool is_cast() const;
// Wraps
void set_has_no_unsigned_wrap(bool b = true) { has_no_unsigned_wrap_ = b; }
void set_has_no_signed_wrap(bool b = true) { has_no_signed_wrap_ = b; }
@@ -98,14 +105,12 @@ public:
protected:
cmp_inst(type *ty, pred_t pred, value *lhs, value *rhs, const std::string &name, instruction *next);
static type* make_cmp_result_type(type *ty);
static bool is_fp_predicate(pred_t pred);
static bool is_int_predicate(pred_t pred);
static type* make_cmp_result_type(type *ty);
public:
pred_t get_pred() const { return pred_; }
private:
pred_t pred_;
@@ -152,7 +157,10 @@ private:
static bool is_valid(op_t op, value *arg, type *ty);
public:
// Factory methods
// accessors
op_t get_op() const { return op_; }
// factory methods
static cast_inst *create(op_t op, value *arg, type *ty,
const std::string &name = "", instruction *next = nullptr);
static cast_inst *create_integer_cast(value *arg, type *ty, bool is_signed,
@@ -191,7 +199,6 @@ class terminator_inst: public instruction{
};
// return instruction
class return_inst: public terminator_inst{
return_inst(context &ctx, value *ret_val, instruction *next);
@@ -206,26 +213,43 @@ public:
static return_inst* create(context &ctx, value *ret_val = nullptr, instruction *next = nullptr);
};
// conditional/unconditional branch instruction
// base branch instruction
class branch_inst: public terminator_inst{
branch_inst(basic_block *dst, instruction *next);
branch_inst(basic_block *if_dst, basic_block *else_dst, value *cond, instruction *next);
protected:
using terminator_inst::terminator_inst;
public:
// factory methods
static branch_inst* create(basic_block *dest,
instruction *next = nullptr);
static branch_inst* create(value *cond, basic_block *if_dest, basic_block *else_dest,
instruction *next = nullptr);
};
// conditional branch
class cond_branch_inst: public branch_inst {
cond_branch_inst(basic_block *if_dst, basic_block *else_dst, value *cond, instruction *next);
friend class branch_inst;
public:
basic_block *get_true_dest() { return (basic_block*)get_operand(0); }
basic_block *get_false_dest() { return (basic_block*)get_operand(1); }
value *get_cond() { return get_operand(2); }
};
// unconditional branch
class uncond_branch_inst: public branch_inst {
friend class branch_inst;
uncond_branch_inst(basic_block *dst, instruction *next);
public:
basic_block *get_dest() { return (basic_block*)get_operand(0); }
};
//===----------------------------------------------------------------------===//
// getelementptr_inst classes
//===----------------------------------------------------------------------===//
class getelementptr_inst: public instruction{
private:
getelementptr_inst(type *pointee_ty, value *ptr, const std::vector<value*> &idx, const std::string &name, instruction *next);
private:
@@ -234,6 +258,12 @@ private:
static type *get_indexed_type(type *ty, const std::vector<value*> &idx);
public:
// accessors
type *get_source_elt_ty() { return source_elt_ty; }
op_iterator idx_begin() { return op_begin() + 1; }
op_iterator idx_end() { return op_end(); }
// factory methods
static getelementptr_inst* create(type *pointee_ty, value *ptr, const std::vector<value*> &idx,
const std::string &name = "", instruction *next = nullptr);
@@ -250,6 +280,9 @@ class load_inst: public unary_inst{
load_inst(value *ptr, const std::string &name, instruction *next);
public:
// accessors
value *get_pointer_operand() { return get_operand(0); }
// factory method
static load_inst* create(value *ptr, const std::string &name = "",
instruction *next = nullptr);

View File

@@ -13,13 +13,26 @@ class basic_block;
class phi_node;
class value;
class context;
class function;
class attribute;
class function_type;
class constant;
class global_value;
/* Module */
class module {
typedef std::pair<std::string, basic_block*> val_key_t;
friend class function;
public:
typedef std::map<std::string, global_value*> symbols_map_t;
typedef std::vector<function*> functions_list_t;
private:
phi_node *make_phi(type *ty, unsigned num_values, basic_block *block);
value *add_phi_operands(const std::string& name, phi_node *&phi);
value *get_value_recursive(const std::string& name, basic_block *block);
void push_function(function *fn) { functions_.push_back(fn); }
public:
module(const std::string &name, context &ctx);
@@ -33,6 +46,11 @@ public:
value *get_value(const std::string& name);
// Seal block -- no more predecessors will be added
void seal_block(basic_block *block);
// Functions
const functions_list_t &get_function_list() const { return functions_; }
functions_list_t &get_function_list() { return functions_; }
function *get_or_insert_function(const std::string &name, function_type *ty);
private:
std::string name_;
@@ -41,6 +59,8 @@ private:
std::map<val_key_t, value*> values_;
std::set<basic_block*> sealed_blocks_;
std::map<basic_block*, std::map<std::string, phi_node*>> incomplete_phis_;
functions_list_t functions_;
symbols_map_t symbols_;
};
}

View File

@@ -13,6 +13,11 @@ class integer_type;
/* Type */
class type {
protected:
typedef std::vector<type*> contained_tys_vec_t;
typedef contained_tys_vec_t::iterator ty_iterator;
typedef contained_tys_vec_t::const_iterator const_ty_iterator;
public:
enum id_t {
// primitive types
@@ -91,7 +96,7 @@ private:
id_t id_;
protected:
std::vector<type*> contained_tys_;
contained_tys_vec_t contained_tys_;
};
class integer_type: public type {
@@ -162,8 +167,13 @@ private:
public:
// accessors
unsigned get_num_params() const { return contained_tys_.size() - 1; }
type* get_param_ty(unsigned i) const { return contained_tys_.at(1 + i); }
unsigned get_num_params() const { return contained_tys_.size() - 1; }
const_ty_iterator params_begin() const { return contained_tys_.begin() + 1; }
const_ty_iterator params_end() const { return contained_tys_.end(); }
ty_iterator params_begin() { return contained_tys_.begin() + 1; }
ty_iterator params_end() { return contained_tys_.end(); }
type* get_param_ty(unsigned i) const { return contained_tys_.at(1 + i); }
type* get_return_ty() const { return contained_tys_.at(0); }
// factory methods
static function_type* get(type *ret_ty, const std::vector<type*>& param_tys);
};

View File

@@ -57,6 +57,11 @@ private:
//===----------------------------------------------------------------------===//
class user: public value{
public:
typedef std::vector<use> ops_t;
typedef ops_t::iterator op_iterator;
typedef ops_t::const_iterator const_op_iterator;
protected:
void resize_ops(unsigned n) { ops_.resize(n); }
@@ -66,9 +71,11 @@ public:
: value(ty, name), ops_(num_ops){ }
// Operands
void set_operand(unsigned i, value *x);
value *get_operand(unsigned i);
unsigned get_num_operands();
op_iterator op_begin() { return ops_.begin(); }
op_iterator op_end() { return ops_.end(); }
void set_operand(unsigned i, value *x);
value *get_operand(unsigned i);
unsigned get_num_operands() const ;
private:
std::vector<use> ops_;

View File

@@ -1,6 +1,6 @@
#include <functional>
#include <algorithm>
#include "ast.h"
#include "ast/ast.h"
#include "ir/constant.h"
#include "ir/function.h"
#include "ir/module.h"
@@ -76,7 +76,7 @@ ir::type* pointer::type_impl(ir::module*, ir::type *type) const{
// Function
void function::bind_parameters(ir::module *mod, ir::function *fn) const{
std::vector<ir::value*> args(fn->arg_begin(), fn->arg_end());
std::vector<ir::argument*> args = fn->args();
assert(args.size() == args_->values().size());
for(size_t i = 0; i < args.size(); i++){
parameter *param_i = args_->values().at(i);
@@ -99,7 +99,7 @@ ir::type* function::type_impl(ir::module* mod, ir::type *type) const{
ir::value* function_definition::codegen(ir::module *mod) const{
ir::function_type *prototype = (ir::function_type*)header_->type(mod, spec_->type(mod));
const std::string &name = header_->id()->name();
ir::function *fn = ir::function::create(prototype, ir::function::internal, name, mod);
ir::function *fn = mod->get_or_insert_function(name, prototype);
header_->bind_parameters(mod, fn);
ir::basic_block *entry = ir::basic_block::create(mod->get_context(), "entry", fn);
mod->seal_block(entry);

View File

@@ -1,14 +1,18 @@
#include "ir/basic_block.h"
#include "ir/instructions.h"
#include "ir/type.h"
#include "ir/function.h"
namespace tdl {
namespace ir {
class phi_node;
basic_block::basic_block(context &ctx, const std::string &name, function *parent):
value(type::get_label_ty(ctx), name), ctx_(ctx), parent_(parent){
value(type::get_label_ty(ctx), name), ctx_(ctx), parent_(parent) {
if(parent_)
parent_->insert_block(this);
}
basic_block* basic_block::create(context &ctx, const std::string &name, function *parent){

View File

@@ -1,5 +1,6 @@
#include "ir/function.h"
#include "ir/type.h"
#include "ir/module.h"
namespace tdl{
namespace ir{
@@ -29,11 +30,19 @@ function::function(function_type *ty, linkage_types_t linkage,
type *param_ty = fn_ty_->get_param_ty(i);
args_[i] = argument::create(param_ty, "", this, i);
}
if(parent)
parent->push_function(this);
}
/* basic block */
void function::insert_block(basic_block *block, basic_block *next) {
auto it = std::find(blocks_.begin(), blocks_.end(), next);
blocks_.insert(it, block);
}
function *function::create(function_type *ty, linkage_types_t linkage,
const std::string &name, module *mod){
const std::string &name, module *mod) {
return new function(ty, linkage, name, mod);
}

View File

@@ -98,7 +98,6 @@ binary_operator *binary_operator::create_not(value *arg, const std::string &name
//===----------------------------------------------------------------------===//
// cmp_inst
cmp_inst::cmp_inst(type *ty, cmp_inst::pred_t pred, value *lhs, value *rhs, const std::string &name, instruction *next)
: instruction(ty, 2, name, next), pred_(pred) {
set_operand(0, lhs);
@@ -113,8 +112,6 @@ type* cmp_inst::make_cmp_result_type(type *ty){
}
bool cmp_inst::is_fp_predicate(pred_t pred) {
return pred >= pcmp::FIRST_FCMP_PREDICATE && pred <= pcmp::LAST_FCMP_PREDICATE;
}
@@ -124,7 +121,6 @@ bool cmp_inst::is_int_predicate(pred_t pred) {
}
// icmp_inst
icmp_inst* icmp_inst::create(pred_t pred, value *lhs, value *rhs, const std::string &name, instruction *next){
assert(is_int_predicate(pred));
type *res_ty = make_cmp_result_type(lhs->get_type());
@@ -132,7 +128,6 @@ icmp_inst* icmp_inst::create(pred_t pred, value *lhs, value *rhs, const std::str
}
// fcmp_inst
fcmp_inst* fcmp_inst::create(pred_t pred, value *lhs, value *rhs, const std::string &name, instruction *next){
assert(is_fp_predicate(pred));
type *res_ty = make_cmp_result_type(lhs->get_type());
@@ -195,7 +190,6 @@ cast_inst *cast_inst::create_integer_cast(value *arg, type *ty, bool is_signed,
// return_inst
return_inst::return_inst(context &ctx, value *ret_val, instruction *next)
: terminator_inst(type::get_void_ty(ctx), !!ret_val, "", next){
if(ret_val)
@@ -207,32 +201,32 @@ return_inst *return_inst::create(context &ctx, value *ret_val, instruction *next
}
// conditional/unconditional branch
// branch_inst
branch_inst* branch_inst::create(basic_block *dst, instruction *next) {
assert(dst && "Branch destination may not be null!");
return new uncond_branch_inst(dst, next);
}
branch_inst::branch_inst(basic_block *dst, instruction *next)
: terminator_inst(type::get_void_ty(dst->get_context()), 1, "", next){
branch_inst* branch_inst::create(value *cond, basic_block *if_dst, basic_block *else_dst, instruction *next) {
assert(cond->get_type()->is_integer_ty(1) && "May only branch on boolean predicates!");
return new cond_branch_inst(if_dst, else_dst, cond, next);
}
// uncond_branch_inst
uncond_branch_inst::uncond_branch_inst(basic_block *dst, instruction *next)
: branch_inst(type::get_void_ty(dst->get_context()), 1, "", next){
set_operand(0, dst);
}
branch_inst::branch_inst(basic_block *if_dst, basic_block *else_dst, value *cond, instruction *next)
: terminator_inst(type::get_void_ty(if_dst->get_context()), 3, "", next){
// cond_branch_inst
cond_branch_inst::cond_branch_inst(basic_block *if_dst, basic_block *else_dst, value *cond, instruction *next)
: branch_inst(type::get_void_ty(if_dst->get_context()), 3, "", next){
assert(cond->get_type()->is_integer_ty(1) && "May only branch on boolean predicates!");
set_operand(0, if_dst);
set_operand(1, else_dst);
set_operand(2, cond);
}
branch_inst* branch_inst::create(basic_block *dst, instruction *next) {
assert(dst && "Branch destination may not be null!");
return new branch_inst(dst, next);
}
branch_inst* branch_inst::create(value *cond, basic_block *if_dst, basic_block *else_dst, instruction *next) {
assert(cond->get_type()->is_integer_ty(1) && "May only branch on boolean predicates!");
return new branch_inst(if_dst, else_dst, cond, next);
}
//===----------------------------------------------------------------------===//
// getelementptr_inst classes
//===----------------------------------------------------------------------===//

View File

@@ -1,6 +1,8 @@
#include "ir/basic_block.h"
#include "ir/module.h"
#include "ir/type.h"
#include "ir/constant.h"
#include "ir/function.h"
namespace tdl{
namespace ir{
@@ -86,5 +88,14 @@ void module::seal_block(ir::basic_block *block){
sealed_blocks_.insert(block);
}
/* functions */
function *module::get_or_insert_function(const std::string &name, function_type *ty) {
function *&fn = (function*&)symbols_[name];
if(fn == nullptr)
return fn = function::create(ty, global_value::external, name, this);
return fn;
}
}
}

View File

@@ -50,7 +50,7 @@ value* user::get_operand(unsigned i){
return ops_[i];
}
unsigned user::get_num_operands(){
unsigned user::get_num_operands() const{
return ops_.size();
}