[intermediate representation] improved skeleton
This commit is contained in:
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
//}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,5 @@
|
||||
namespace tdl{
|
||||
namespace ir{
|
||||
|
||||
/* Context */
|
||||
context::context() { }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
58
lib/ir/value.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user