[code generation] basic to-llvm lowering
This commit is contained in:
@@ -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
4
TODO
Normal file
@@ -0,0 +1,4 @@
|
||||
[Intermediate Representation]
|
||||
- proper naming scheme
|
||||
- symbols table
|
||||
- name conflicts on globals?
|
@@ -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();
|
||||
|
@@ -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
10
include/codegen/layout.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef TDL_INCLUDE_IR_CODEGEN_LAYOUT_H
|
||||
#define TDL_INCLUDE_IR_CODEGEN_LAYOUT_H
|
||||
|
||||
namespace tdl{
|
||||
namespace codegen{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
10
include/codegen/liveness.h
Normal file
10
include/codegen/liveness.h
Normal 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
118
include/codegen/lowering.h
Normal 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
|
10
include/codegen/storage_alloc.h
Normal file
10
include/codegen/storage_alloc.h
Normal 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
10
include/codegen/tune.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef TDL_INCLUDE_IR_CODEGEN_TUNE_H
|
||||
#define TDL_INCLUDE_IR_CODEGEN_TUNE_H
|
||||
|
||||
namespace tdl{
|
||||
namespace codegen{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -56,7 +56,7 @@ private:
|
||||
class global_value: public constant {
|
||||
public:
|
||||
enum linkage_types_t {
|
||||
internal
|
||||
external
|
||||
};
|
||||
|
||||
public:
|
||||
|
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
};
|
||||
|
@@ -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_;
|
||||
|
@@ -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);
|
@@ -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){
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user