[intermediate representation] improved skeleton

This commit is contained in:
Philippe Tillet
2019-01-02 01:06:43 -05:00
parent e7a4e70e22
commit 24bd2145df
11 changed files with 611 additions and 79 deletions

View File

@@ -9,11 +9,20 @@ namespace ir{
class context;
class function;
class instruction;
/* Basic Block */
class basic_block: public value{
public:
// Accessors
function* get_parent();
instruction* get_first_non_phi_or_dbg();
// Iterators
instruction* begin();
instruction* end();
// CFG
const std::vector<basic_block*>& get_predecessors() const;
void add_predecessor(basic_block* pred);
// Factory functions
static basic_block* create(context &ctx, const std::string &name, function *parent);
@@ -21,6 +30,7 @@ private:
context &ctx_;
std::string name_;
function *parent_;
std::vector<basic_block*> preds_;
};
}

View File

@@ -3,6 +3,7 @@
#include <vector>
#include <string>
#include "instructions.h"
namespace tdl{
namespace ir{
@@ -11,62 +12,81 @@ class basic_block;
class value;
class type;
class constant_int;
class instruction;
class context;
class phi_node;
/* Builder */
class builder{
public:
void set_insert_point(basic_block* bb);
basic_block* get_insert_block();
// Constructor
builder(context &ctx);
// Setters
void set_insert_point(instruction* instr);
void set_insert_point(basic_block* block);
basic_block* get_insert_block() { return block_; }
instruction* get_insert_point() { return insert_point_;}
// Constants
value *get_int32(unsigned val);
// Types
type *get_float_ty();
type *get_double_ty();
// Insert
template<typename InstTy>
InstTy* insert(InstTy *instr, const std::string &name = "");
// Branch instructions
value* create_br(basic_block *bb);
value* create_cond_br(value *cond, basic_block* if_bb, basic_block* else_bb);
value* create_br(basic_block *dest);
value* create_cond_br(value *cond, basic_block* if_dest, basic_block* else_dest);
// Cast instructions
value* create_si_to_fp(value *src, type *dst_ty);
value* create_ui_to_fp(value *src, type *dst_ty);
value* create_fp_to_si(value *src, type *dst_ty);
value* create_fp_to_ui(value *src, type *dst_ty);
value* create_fp_ext(value *src, type *dst_ty);
value* create_fp_trunc(value *src, type *dst_ty);
value* create_int_cast(value *src, type *dst_ty, bool is_signed);
// Call instruction
value* create_call(value *fn, const std::vector<value*> &args);
value *create_cast(cast_inst::op_t op, value *v, type *dst_ty, const std::string &name = "");
value* create_si_to_fp(value *src, type *dst_ty, const std::string &name = "");
value* create_ui_to_fp(value *src, type *dst_ty, const std::string &name = "");
value* create_fp_to_si(value *src, type *dst_ty, const std::string &name = "");
value* create_fp_to_ui(value *src, type *dst_ty, const std::string &name = "");
value* create_fp_ext(value *src, type *dst_ty, const std::string &name = "");
value* create_fp_trunc(value *src, type *dst_ty, const std::string &name = "");
value* create_int_cast(value *src, type *dst_ty, bool is_signed, const std::string &name = "");
// Phi instruction
phi_node* create_phi(type *ty, unsigned num_reserved, const std::string &name = "");
// Binary instructions
value *create_insert_nuwnswb_binop(binary_operator::op_t op, value *lhs, value *rhs, const std::string &name, bool has_nuw, bool has_nsw);
value *create_fmul(value *lhs, value *rhs, const std::string &name = "");
value *create_mul(value *lhs, value *rhs, const std::string &name = "");
value *create_fdiv(value *lhs, value *rhs, const std::string &name = "");
value *create_frem(value *lhs, value *rhs, const std::string &name = "");
value *create_fadd(value *lhs, value *rhs, const std::string &name = "");
value *create_fsub(value *lhs, value *rhs, const std::string &name = "");
value *create_mul(value *lhs, value *rhs, const std::string &name = "", bool has_nuw = false, bool has_nsw = false);
value *create_sdiv(value *lhs, value *rhs, const std::string &name = "");
value *create_udiv(value *lhs, value *rhs, const std::string &name = "");
value *create_frem(value *lhs, value *rhs, const std::string &name = "");
value *create_srem(value *lhs, value *rhs, const std::string &name = "");
value *create_urem(value *lhs, value *rhs, const std::string &name = "");
value *create_fadd(value *lhs, value *rhs, const std::string &name = "");
value *create_add(value *lhs, value *rhs, const std::string &name = "");
value *create_gep(value *lhs, const std::vector<value*> &offs, const std::string &name = "");
value *create_fsub(value *lhs, value *rhs, const std::string &name = "");
value *create_sub(value *lhs, value *rhs, const std::string &name = "");
value *create_lshr(value *lhs, value *rhs, const std::string &name = "");
value *create_ashr(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOLT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpSLT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpULT(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOGT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpSGT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpUGT(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOLE(value *lhs, value *rhs, const std::string &name = "");
value *create_add(value *lhs, value *rhs, const std::string &name = "", bool has_nuw = false, bool has_nsw = false);
value *create_sub(value *lhs, value *rhs, const std::string &name = "", bool has_nuw = false, bool has_nsw = false);
value *create_shl(value *lhs, value *rhs, const std::string &name = "", bool has_nuw = false, bool has_nsw = false);
value *create_ashr(value *lhs, value *rhs, const std::string &name = "", bool has_nuw = false, bool has_nsw = false);
// GEP
value *create_gep(value *ptr, const std::vector<value*>& idx_list, const std::string &name = "");
// Comparison (int)
value *create_icmp(cmp_inst::pred_t pred, value *lhs, value *rhs, const std::string &name = "");
value *create_icmpSLE(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpULE(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOGE(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpSLT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpSGE(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpSGT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpULE(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpULT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpUGE(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOEQ(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpUGT(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpEQ(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpONE(value *lhs, value *rhs, const std::string &name = "");
value *create_icmpNE(value *lhs, value *rhs, const std::string &name = "");
// Comparison (float)
value *create_fcmp(cmp_inst::pred_t pred, value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOLT(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOGT(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOLE(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOGE(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpOEQ(value *lhs, value *rhs, const std::string &name = "");
value *create_fcmpONE(value *lhs, value *rhs, const std::string &name = "");
// Logical
value *create_and(value *lhs, value *rhs, const std::string &name = "");
value *create_xor(value *lhs, value *rhs, const std::string &name = "");
value *create_or(value *lhs, value *rhs, const std::string &name = "");
@@ -81,6 +101,11 @@ public:
value *create_broadcast(value *arg, const std::vector<unsigned> &shapes, const std::string &name = "");
// Terminators
value *create_ret_void();
private:
context &ctx_;
basic_block *block_;
instruction *insert_point_;
};
}

View File

@@ -1,28 +1,165 @@
#ifndef TDL_INCLUDE_IR_INSTRUCTIONS_H
#define TDL_INCLUDE_IR_INSTRUCTIONS_H
#include <vector>
#include "value.h"
#include "llvm/IR/Instructions.h"
namespace tdl{
namespace ir{
/* Instructions */
class instruction: public value{
class basic_block;
//===----------------------------------------------------------------------===//
// instruction classes
//===----------------------------------------------------------------------===//
class instruction: public user{
public:
// constructors
instruction(type *ty, unsigned num_used, instruction *next = nullptr);
// parent
const basic_block *get_parent() const { return parent_;}
basic_block *get_parent() { return parent_; }
private:
basic_block *parent_;
};
//===----------------------------------------------------------------------===//
// phi_node classes
//===----------------------------------------------------------------------===//
class phi_node: public instruction{
private:
phi_node(type *ty, unsigned num_reserved);
public:
void add_incoming(value *x, basic_block *bb);
// Factory methods
static phi_node* create(type *ty, unsigned num_reserved);
private:
unsigned num_reserved_;
};
//===----------------------------------------------------------------------===//
// binary_operator classes
//===----------------------------------------------------------------------===//
class binary_operator: public instruction{
public:
typedef llvm::BinaryOperator::BinaryOps op_t;
protected:
// Constructors
binary_operator(op_t op, value *lhs, value *rhs, type *ty, const std::string &name, instruction *next);
public:
// Get operand
op_t get_op() const { return op_; }
// Factory methods
static binary_operator *create(op_t op, value *lhs, value *rhs,
const std::string &name = "", instruction *next = nullptr);
static binary_operator *create_fneg(value *arg, const std::string &name = "", instruction *next = nullptr);
static binary_operator *create_neg(value *arg, const std::string &name = "", instruction *next = nullptr);
static binary_operator *create_not(value *arg, const std::string &name = "", instruction *next = nullptr);
public:
op_t op_;
};
//===----------------------------------------------------------------------===//
// cmp_inst classes
//===----------------------------------------------------------------------===//
class cmp_inst: public instruction{
public:
typedef llvm::CmpInst::Predicate pred_t;
protected:
cmp_inst(pred_t pred, value *lhs, value *rhs, type *ty,
const std::string &name = "", instruction *next = nullptr);
private:
pred_t pred_;
};
class icmp_inst: public cmp_inst{
public:
static icmp_inst* create(pred_t pred, value *lhs, value *rhs,
const std::string &name = "", instruction *next = nullptr);
};
class fcmp_inst: public cmp_inst{
public:
static fcmp_inst* create(pred_t pred, value *lhs, value *rhs,
const std::string &name = "", instruction *next = nullptr);
};
//===----------------------------------------------------------------------===//
// cast_inst classes
//===----------------------------------------------------------------------===//
class cast_inst: public instruction{
public:
typedef llvm::CastInst::CastOps op_t;
protected:
// Constructors
cast_inst(op_t op, value *arg, type *ty, const std::string &name, instruction *next);
public:
// 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,
const std::string &name = "", instruction *next = nullptr);
private:
op_t op_;
};
//===----------------------------------------------------------------------===//
// terminator_inst classes
//===----------------------------------------------------------------------===//
class terminator_inst: public instruction{
public:
};
class return_inst: public instruction{
};
class unary_operator: public instruction{
//===----------------------------------------------------------------------===//
// branch_inst classes
//===----------------------------------------------------------------------===//
class branch_inst: public instruction{
public:
static branch_inst* create(basic_block *dest,
const std::string &name = "", instruction *next = nullptr);
static branch_inst* create(value *cond, basic_block *if_dest, basic_block *else_dest,
const std::string &name = "", instruction *next = nullptr);
};
//===----------------------------------------------------------------------===//
// getelementptr_inst classes
//===----------------------------------------------------------------------===//
class getelementptr_inst: public instruction{
public:
static getelementptr_inst* create(value *ptr, const std::vector<value*> &idx,
const std::string &name = "", instruction *next = nullptr);
};
}
}

View File

@@ -18,11 +18,11 @@ class context;
class module {
typedef std::pair<std::string, basic_block*> val_key_t;
phi_node *make_phi(type *ty, unsigned num_values, basic_block *block);
void add_phi_operands(const std::string& name, phi_node *&phi);
value *add_phi_operands(const std::string& name, phi_node *&phi);
value *get_value_recursive(const std::string& name, basic_block *block);
public:
module(const std::string &name, context *ctx);
module(const std::string &name, context &ctx);
context& get_context();
builder& get_builder();
// Setters
@@ -35,6 +35,8 @@ public:
void seal_block(basic_block *block);
private:
std::string name_;
context &context_;
builder builder_;
std::map<val_key_t, value*> values_;
std::set<basic_block*> sealed_blocks_;

View File

@@ -2,22 +2,73 @@
#define TDL_INCLUDE_IR_VALUE_H
#include <string>
#include <vector>
#include <memory>
namespace tdl{
namespace ir{
class type;
class use;
//===----------------------------------------------------------------------===//
// value class
//===----------------------------------------------------------------------===//
/* Value */
class value {
public:
// constructor
value(type *ty, const std::string &name = "");
// uses
void add_use(use *arg);
// name
void set_name(const std::string &name);
type* get_type();
type* get_type() { return ty_; }
private:
type *ty_;
std::string name_;
};
//===----------------------------------------------------------------------===//
// use class
//===----------------------------------------------------------------------===//
class use {
public:
// Implicit conversions to/from value
friend class value;
operator value *() const { return val_; }
value *get() const { return val_; }
value *operator->() { return val_; }
const value *operator->() const { return val_; }
inline void set(value *val);
inline value *operator=(value *rhs);
inline const use &operator=(const use &rhs);
private:
value *val_;
};
//===----------------------------------------------------------------------===//
// user class
//===----------------------------------------------------------------------===//
class user: public value{
public:
// Constructor
user(type *ty, unsigned num_ops, const std::string &name = "")
: value(ty, name), ops_(num_ops){ }
// Operands
void set_operand(unsigned i, value *x);
value *get_operand(unsigned i);
unsigned get_num_operands();
private:
std::vector<use> ops_;
};
}
}

View File

@@ -342,7 +342,7 @@ ir::value *binary_operator::llvm_op(ir::module *mod, ir::builder &builder, ir::v
if(op_==SUB && is_ptr)
return builder.create_gep(lhs, {builder.create_neg(rhs)});
if(op_==LEFT_SHIFT)
return builder.create_lshr(lhs, rhs, name);
return builder.create_shl(lhs, rhs, name);
if(op_==RIGHT_SHIFT)
return builder.create_ashr(lhs, rhs, name);
if(op_ == LT && is_float)

View File

@@ -0,0 +1,224 @@
#include <string>
#include "ir/basic_block.h"
#include "ir/builder.h"
#include "ir/instructions.h"
#include "llvm/IR/Instruction.h"
namespace tdl{
namespace ir{
builder::builder(context &ctx):
ctx_(ctx){}
//===----------------------------------------------------------------------===//
// insertion helpers
//===----------------------------------------------------------------------===//
void builder::set_insert_point(instruction *instr){
block_ = instr->get_parent();
insert_point_ = instr;
}
void builder::set_insert_point(basic_block *block){
block_ = block;
insert_point_ = block->end();
}
//===----------------------------------------------------------------------===//
// branch instructions
//===----------------------------------------------------------------------===//
value* builder::create_br(basic_block *dest){
return insert(branch_inst::create(dest));
}
value* builder::create_cond_br(value *cond, basic_block *if_dest, basic_block *else_dest){
return insert(branch_inst::create(cond, if_dest, else_dest));
}
//===----------------------------------------------------------------------===//
// cast instructions
//===----------------------------------------------------------------------===//
#define DEFINE_CAST_INSTR(SUFFIX, OPCODE)\
value *builder::create_ ## SUFFIX(value *src, type *dst_ty, std::string const &name){\
return create_cast(OPCODE, src, dst_ty, name);\
}
DEFINE_CAST_INSTR(si_to_fp, llvm::Instruction::SIToFP)
DEFINE_CAST_INSTR(ui_to_fp, llvm::Instruction::UIToFP)
DEFINE_CAST_INSTR(fp_to_si, llvm::Instruction::FPToSI)
DEFINE_CAST_INSTR(fp_to_ui, llvm::Instruction::FPToUI)
DEFINE_CAST_INSTR(fp_ext, llvm::Instruction::FPExt)
DEFINE_CAST_INSTR(fp_trunc, llvm::Instruction::FPTrunc)
value* builder::create_cast(cast_inst::op_t op, value *v, type *dst_ty, const std::string &name){
return insert(cast_inst::create(op, v, dst_ty), name);
}
value* builder::create_int_cast(value *src, type *dst_ty, bool is_signed, const std::string &name){
return insert(cast_inst::create_integer_cast(src, dst_ty, is_signed), name);
}
//===----------------------------------------------------------------------===//
// phi instructions
//===----------------------------------------------------------------------===//
phi_node* builder::create_phi(type *ty, unsigned num_reserved, const std::string &name){
return insert(phi_node::create(ty, num_reserved), name);
}
//===----------------------------------------------------------------------===//
// binary float instructions
//===----------------------------------------------------------------------===//
#define DEFINE_BINARY_FLOAT(SUFFIX, OPCODE)\
value *builder::create_ ## SUFFIX(value *lhs, value *rhs, const std::string &name){\
return insert(binary_operator::create(OPCODE, lhs, rhs), name);\
}
#define DEFINE_UNARY_FLOAT(SUFFIX)\
value *builder::create_ ## SUFFIX(value *arg, const std::string &name){\
return insert(binary_operator::create_ ## SUFFIX(arg), name);\
}
// Binary
DEFINE_BINARY_FLOAT(fmul, llvm::Instruction::FMul)
DEFINE_BINARY_FLOAT(fdiv, llvm::Instruction::FDiv)
DEFINE_BINARY_FLOAT(frem, llvm::Instruction::FRem)
DEFINE_BINARY_FLOAT(fadd, llvm::Instruction::FAdd)
DEFINE_BINARY_FLOAT(fsub, llvm::Instruction::FSub)
// Unary
DEFINE_UNARY_FLOAT(fneg)
//===----------------------------------------------------------------------===//
// binary int instructions
//===----------------------------------------------------------------------===//
#define DEFINE_NOWRAP_BINARY(SUFFIX, OPCODE)\
value* builder::create_ ## SUFFIX(value *lhs, value *rhs, const std::string &name, bool has_nuw, bool has_nsw){\
return create_insert_nuwnswb_binop(OPCODE, lhs, rhs, name, has_nuw, has_nsw);\
}\
#define DEFINE_BINARY_INT(SUFFIX, OPCODE)\
value *builder::create_ ## SUFFIX(value *lhs, value *rhs, const std::string &name){\
return insert(binary_operator::create(OPCODE, lhs, rhs), name);\
}
#define DEFINE_UNARY_INT(SUFFIX)\
value *builder::create_ ## SUFFIX(value *arg, const std::string &name){\
return insert(binary_operator::create_ ## SUFFIX(arg), name);\
}
// Binary
DEFINE_NOWRAP_BINARY(mul, llvm::Instruction::Mul)
DEFINE_NOWRAP_BINARY(add, llvm::Instruction::Add)
DEFINE_NOWRAP_BINARY(sub, llvm::Instruction::Sub)
DEFINE_NOWRAP_BINARY(shl, llvm::Instruction::Shl)
DEFINE_NOWRAP_BINARY(ashr, llvm::Instruction::AShr)
DEFINE_BINARY_INT(sdiv, llvm::Instruction::SDiv)
DEFINE_BINARY_INT(udiv, llvm::Instruction::UDiv)
DEFINE_BINARY_INT(srem, llvm::Instruction::SRem)
DEFINE_BINARY_INT(urem, llvm::Instruction::URem)
DEFINE_BINARY_INT(and, llvm::Instruction::And)
DEFINE_BINARY_INT(or, llvm::Instruction::Or)
DEFINE_BINARY_INT(xor, llvm::Instruction::Xor)
// Unary
DEFINE_UNARY_INT(neg)
DEFINE_UNARY_INT(not)
//===----------------------------------------------------------------------===//
// getelementptr instructions
//===----------------------------------------------------------------------===//
value* builder::create_gep(value *ptr, const std::vector<value*>& idx_list, const std::string &name){
return insert(getelementptr_inst::create(ptr, idx_list), name);
}
//===----------------------------------------------------------------------===//
// icmp instructions
//===----------------------------------------------------------------------===//
value *builder::create_icmp(cmp_inst::pred_t pred, value *lhs, value *rhs, const std::string &name){
return insert(icmp_inst::create(pred, lhs, rhs), name);
}
#define DEFINE_ICMP_INSTR(SUFFIX, OPCODE)\
value *builder::create_icmp ## SUFFIX(value *lhs, value *rhs, const std::string &name){\
return create_icmp(OPCODE, lhs, rhs, name);\
}
// Signed
DEFINE_ICMP_INSTR(SLE, llvm::ICmpInst::ICMP_SLE)
DEFINE_ICMP_INSTR(SLT, llvm::ICmpInst::ICMP_SLT)
DEFINE_ICMP_INSTR(SGE, llvm::ICmpInst::ICMP_SGE)
DEFINE_ICMP_INSTR(SGT, llvm::ICmpInst::ICMP_SGT)
// Unsigned
DEFINE_ICMP_INSTR(ULE, llvm::ICmpInst::ICMP_ULE)
DEFINE_ICMP_INSTR(ULT, llvm::ICmpInst::ICMP_ULT)
DEFINE_ICMP_INSTR(UGE, llvm::ICmpInst::ICMP_UGE)
DEFINE_ICMP_INSTR(UGT, llvm::ICmpInst::ICMP_UGT)
// General
DEFINE_ICMP_INSTR(EQ, llvm::ICmpInst::ICMP_EQ)
DEFINE_ICMP_INSTR(NE, llvm::ICmpInst::ICMP_NE)
//===----------------------------------------------------------------------===//
// fcmp instructions
//===----------------------------------------------------------------------===//
value *builder::create_fcmp(cmp_inst::pred_t pred, value *lhs, value *rhs, const std::string &name){
return insert(fcmp_inst::create(pred, lhs, rhs), name);
}
#define DEFINE_FCMP_INSTR(SUFFIX, OPCODE)\
value *builder::create_fcmp ## SUFFIX(value *lhs, value *rhs, const std::string &name){\
return create_fcmp(OPCODE, lhs, rhs, name);\
}
// Ordered
DEFINE_FCMP_INSTR(OLE, llvm::FCmpInst::FCMP_OLE)
DEFINE_FCMP_INSTR(OLT, llvm::FCmpInst::FCMP_OLT)
DEFINE_FCMP_INSTR(OGE, llvm::FCmpInst::FCMP_OGE)
DEFINE_FCMP_INSTR(OGT, llvm::FCmpInst::FCMP_OGT)
DEFINE_FCMP_INSTR(OEQ, llvm::FCmpInst::FCMP_OEQ)
DEFINE_FCMP_INSTR(ONE, llvm::FCmpInst::FCMP_ONE)
//===----------------------------------------------------------------------===//
// load instructions
//===----------------------------------------------------------------------===//
//value *builder::create_load(value *arg, const std::string &name){
//}
//===----------------------------------------------------------------------===//
// tile instructions
//===----------------------------------------------------------------------===//
//value *create_splat(value *arg, const std::vector<unsigned> &shapes, const std::string &name) {
//}
//value *create_reshape(value *arg, const std::vector<unsigned> &shapes, const std::string &name) {
//}
//value *create_broadcast(value *arg, const std::vector<unsigned> &shapes, const std::string &name) {
//}
//===----------------------------------------------------------------------===//
// terminator instructions
//===----------------------------------------------------------------------===//
//value *create_red_void() {
//}
}
}

View File

@@ -3,8 +3,5 @@
namespace tdl{
namespace ir{
/* Context */
context::context() { }
}
}

View File

@@ -0,0 +1,26 @@
#include "ir/basic_block.h"
#include "ir/instructions.h"
namespace tdl{
namespace ir{
instruction::instruction(type *ty, unsigned num_ops, instruction *next)
: user(ty, num_ops) {
if(next){
basic_block *block = next->get_parent();
assert(block && "Next instruction is not in a basic block!");
}
}
// // If requested, insert this instruction into a basic block...
// if (InsertBefore) {
// BasicBlock *BB = InsertBefore->getParent();
// assert(BB && "Instruction to insert before is not in a basic block!");
// BB->getInstList().insert(InsertBefore->getIterator(), this);
// }
}
}

View File

@@ -1,71 +1,73 @@
#include "ir/basic_block.h"
#include "ir/module.h"
namespace tdl{
namespace ir{
/* Module */
module::module(const std::string &name, context *ctx)
: handle_(name.c_str(), *ctx->handle()), builder_(*ctx->handle()) {
module::module(const std::string &name, context &ctx)
: name_(name), context_(ctx), builder_(ctx) {
sealed_blocks_.insert(nullptr);
}
Module* module::handle() {
return &handle_;
}
IRBuilder<>& module::builder() {
ir::builder& module::get_builder() {
return builder_;
}
void module::set_value(const std::string& name, BasicBlock *block, Value *value){
ir::context& module::get_context() {
return context_;
}
void module::set_value(const std::string& name, ir::basic_block *block, ir::value *value){
values_[val_key_t{name, block}] = value;
}
void module::set_value(const std::string& name, Value* value){
return set_value(name, builder_.GetInsertBlock(), value);
void module::set_value(const std::string& name, ir::value *value){
return set_value(name, builder_.get_insert_block(), value);
}
PHINode* module::make_phi(Type *type, unsigned num_values, BasicBlock *block){
Instruction* instr = block->getFirstNonPHIOrDbg();
ir::phi_node* module::make_phi(ir::type *ty, unsigned num_values, ir::basic_block *block){
ir::instruction* instr = block->get_first_non_phi_or_dbg();
if(instr)
builder_.SetInsertPoint(instr);
PHINode *res = builder_.CreatePHI(type, num_values);
builder_.set_insert_point(instr);
ir::phi_node *res = builder_.create_phi(ty, num_values);
if(instr)
builder_.SetInsertPoint(block);
builder_.set_insert_point(block);
return res;
}
Value *module::add_phi_operands(const std::string& name, PHINode *&phi){
BasicBlock *block = phi->getParent();
for(BasicBlock *pred: predecessors(block)){
Value *value = get_value(name, pred);
phi->addIncoming(value, pred);
ir::value *module::add_phi_operands(const std::string& name, ir::phi_node *&phi){
ir::basic_block *block = phi->get_parent();
for(ir::basic_block *pred: block->get_predecessors()){
ir::value *value = get_value(name, pred);
phi->add_incoming(value, pred);
}
return phi;
}
Value *module::get_value_recursive(const std::string& name, BasicBlock *block) {
Value *result;
ir::value *module::get_value_recursive(const std::string& name, ir::basic_block *block) {
ir::value *result;
auto &preds = block->get_predecessors();
if(sealed_blocks_.find(block) == sealed_blocks_.end()){
Value *pred = get_value(name, *pred_begin(block));
incomplete_phis_[block][name] = make_phi(pred->getType(), 1, block);
result = (Value*)incomplete_phis_[block][name];
ir::value *pred = get_value(name, preds.front());
incomplete_phis_[block][name] = make_phi(pred->get_type(), 1, block);
result = (ir::value*)incomplete_phis_[block][name];
}
else if(pred_size(block) <= 1){
bool has_pred = pred_size(block);
result = get_value(name, has_pred?*pred_begin(block):nullptr);
else if(preds.size() <= 1){
bool has_pred = preds.size();
result = get_value(name, has_pred?preds.front():nullptr);
}
else{
Value *pred = get_value(name, *pred_begin(block));
result = make_phi(pred->getType(), 1, block);
ir::value *pred = get_value(name, preds.front());
result = make_phi(pred->get_type(), 1, block);
set_value(name, block, result);
add_phi_operands(name, (PHINode*&)result);
add_phi_operands(name, (ir::phi_node*&)result);
}
set_value(name, block, result);
return result;
}
Value *module::get_value(const std::string& name, BasicBlock *block) {
ir::value *module::get_value(const std::string& name, ir::basic_block *block) {
val_key_t key(name, block);
if(values_.find(key) != values_.end()){
return values_.at(key);
@@ -73,11 +75,11 @@ Value *module::get_value(const std::string& name, BasicBlock *block) {
return get_value_recursive(name, block);
}
Value *module::get_value(const std::string& name) {
return get_value(name, builder_.GetInsertBlock());
ir::value *module::get_value(const std::string& name) {
return get_value(name, builder_.get_insert_block());
}
Value *module::seal_block(BasicBlock *block){
void module::seal_block(ir::basic_block *block){
for(auto &x: incomplete_phis_[block])
add_phi_operands(x.first, x.second);
sealed_blocks_.insert(block);

58
lib/ir/value.cpp Normal file
View File

@@ -0,0 +1,58 @@
#include "ir/value.h"
#include <cassert>
namespace tdl{
namespace ir{
class type;
//===----------------------------------------------------------------------===//
// value class
//===----------------------------------------------------------------------===//
value::value(type *ty, const std::string &name): ty_(ty){
set_name(name);
}
// TODO: automatic naming scheme + update symbol table
void value::set_name(const std::string &name){
name_ = name;
}
//===----------------------------------------------------------------------===//
// use class
//===----------------------------------------------------------------------===//
void use::set(value *val){
val_ = val;
}
value *use::operator=(value *rhs){
set(rhs);
return rhs;
}
const use &use::operator=(const use &rhs){
set(rhs.val_);
return rhs;
}
//===----------------------------------------------------------------------===//
// user class
//===----------------------------------------------------------------------===//
void user::set_operand(unsigned i, value *x){
assert(i < ops_.size() && "set_operand() out of range!");
ops_[i] = x;
}
value* user::get_operand(unsigned i){
assert(i < ops_.size() && "get_operand() out of range!");
return ops_[i];
}
unsigned user::get_num_operands(){
return ops_.size();
}
}
}