[code generation] added basic structure
This commit is contained in:
@@ -1,9 +1,45 @@
|
||||
#ifndef TDL_INCLUDE_IR_CODEGEN_STORAGE_ALLOC_H
|
||||
#define TDL_INCLUDE_IR_CODEGEN_STORAGE_ALLOC_H
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace tdl{
|
||||
|
||||
namespace ir{
|
||||
class value;
|
||||
class function;
|
||||
}
|
||||
|
||||
namespace codegen{
|
||||
|
||||
class layout;
|
||||
class target_tuner;
|
||||
class liveness;
|
||||
class loop_info;
|
||||
|
||||
class allocation {
|
||||
public:
|
||||
// accessors
|
||||
unsigned get_num_bytes(ir::value *x) const;
|
||||
unsigned get_offset(ir::value *x) const { return offsets_.at(x); }
|
||||
unsigned get_allocated_size() const { return allocated_size_; }
|
||||
bool has_double_buffer(ir::value *x) const { return double_buffer_.find(x) != double_buffer_.end(); }
|
||||
|
||||
// run
|
||||
void run(ir::function &fn);
|
||||
|
||||
private:
|
||||
std::map<ir::value*, unsigned> offsets_;
|
||||
std::set<ir::value*> double_buffer_;
|
||||
std::map<ir::value*, unsigned> num_bytes_;
|
||||
size_t allocated_size_;
|
||||
// dependences
|
||||
liveness *liveness_;
|
||||
layout *layout_;
|
||||
loop_info *loop_info_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,44 @@
|
||||
#ifndef TDL_INCLUDE_IR_CODEGEN_LAYOUT_H
|
||||
#define TDL_INCLUDE_IR_CODEGEN_LAYOUT_H
|
||||
|
||||
namespace tdl{
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace tdl {
|
||||
|
||||
namespace ir {
|
||||
class function;
|
||||
class instruction;
|
||||
class value;
|
||||
}
|
||||
|
||||
namespace codegen{
|
||||
|
||||
struct shared_view_info{
|
||||
ir::value *usr;
|
||||
bool has_dedicated_storage;
|
||||
};
|
||||
|
||||
class layout {
|
||||
private:
|
||||
typedef std::vector<shared_view_info> shared_view_val_t;
|
||||
|
||||
void add_phi_nodes(ir::value *v);
|
||||
void add_shared_views(ir::value *v);
|
||||
|
||||
public:
|
||||
// accessors
|
||||
unsigned get_num_shared_views(ir::value *v);
|
||||
shared_view_info get_shared_view(ir::value *v, unsigned idx);
|
||||
|
||||
// run
|
||||
bool run(ir::function &fn);
|
||||
|
||||
private:
|
||||
std::map<ir::value*, shared_view_val_t> shared_views_;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,61 @@
|
||||
#ifndef TDL_INCLUDE_IR_CODEGEN_LIVENESS_H
|
||||
#define TDL_INCLUDE_IR_CODEGEN_LIVENESS_H
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace tdl{
|
||||
|
||||
namespace ir{
|
||||
class value;
|
||||
class function;
|
||||
}
|
||||
|
||||
namespace codegen{
|
||||
|
||||
class layout;
|
||||
|
||||
typedef unsigned slot_index;
|
||||
|
||||
struct segment {
|
||||
slot_index start;
|
||||
slot_index end;
|
||||
|
||||
bool contains(slot_index idx) const {
|
||||
return start <= idx && idx < end;
|
||||
}
|
||||
|
||||
bool intersect(const segment &Other){
|
||||
return contains(Other.start) || Other.contains(start);
|
||||
}
|
||||
};
|
||||
|
||||
class liveness {
|
||||
private:
|
||||
typedef std::map<ir::value*, slot_index> indices_map_t;
|
||||
typedef std::map<ir::value*, segment> intervals_map_t;
|
||||
typedef std::map<ir::value*, bool> has_storage_map_t;
|
||||
|
||||
public:
|
||||
/// Intervals iterators...
|
||||
using iterator = intervals_map_t::iterator;
|
||||
using const_iterator = intervals_map_t::const_iterator;
|
||||
|
||||
public:
|
||||
|
||||
// accessors
|
||||
const intervals_map_t& intervals() const { return intervals_; }
|
||||
segment get_interval(ir::value* v) const { return intervals_.at(v); }
|
||||
|
||||
// run
|
||||
void run(ir::function *fn);
|
||||
|
||||
private:
|
||||
has_storage_map_t has_dedicated_storage_;
|
||||
indices_map_t indices_;
|
||||
intervals_map_t intervals_;
|
||||
layout* layouts_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -9,191 +9,35 @@
|
||||
#include "ir/type.h"
|
||||
|
||||
|
||||
namespace llvm{
|
||||
class Type;
|
||||
class Value;
|
||||
class Instruction;
|
||||
class Constant;
|
||||
class LLVMContext;
|
||||
}
|
||||
|
||||
namespace tdl{
|
||||
namespace codegen{
|
||||
|
||||
using namespace llvm;
|
||||
class selection{
|
||||
typedef std::map<ir::value *, llvm::Value *> vmap_t;
|
||||
typedef std::map<ir::basic_block *, llvm::BasicBlock *> bmap_t;
|
||||
|
||||
/* convert ir::type to Type */
|
||||
Type *llvm_type(ir::type *ty, LLVMContext &ctx) {
|
||||
// function
|
||||
if(auto* tt = dynamic_cast<ir::function_type*>(ty)){
|
||||
Type *return_ty = llvm_type(tt->get_return_ty(), ctx);
|
||||
std::vector<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 FunctionType::get(return_ty, param_tys, false);
|
||||
}
|
||||
// pointer
|
||||
if(ty->is_pointer_ty()){
|
||||
Type *elt_ty = llvm_type(ty->get_pointer_element_ty(), ctx);
|
||||
unsigned addr_space = ty->get_pointer_address_space();
|
||||
return PointerType::get(elt_ty, addr_space);
|
||||
}
|
||||
// integer
|
||||
if(ty->is_integer_ty()){
|
||||
unsigned bitwidth = ty->get_integer_bitwidth();
|
||||
return IntegerType::get(ctx, bitwidth);
|
||||
}
|
||||
// primitive types
|
||||
switch(ty->get_type_id()){
|
||||
case ir::type::VoidTyID: return Type::getVoidTy(ctx);
|
||||
case ir::type::HalfTyID: return Type::getHalfTy(ctx);
|
||||
case ir::type::FloatTyID: return Type::getFloatTy(ctx);
|
||||
case ir::type::DoubleTyID: return Type::getDoubleTy(ctx);
|
||||
case ir::type::X86_FP80TyID: return Type::getX86_FP80Ty(ctx);
|
||||
case ir::type::PPC_FP128TyID: return Type::getPPC_FP128Ty(ctx);
|
||||
case ir::type::LabelTyID: return Type::getLabelTy(ctx);
|
||||
case ir::type::MetadataTyID: return Type::getMetadataTy(ctx);
|
||||
case ir::type::TokenTyID: return Type::getTokenTy(ctx);
|
||||
default: break;
|
||||
}
|
||||
// unknown type
|
||||
throw std::runtime_error("unknown conversion from ir::type to Type");
|
||||
}
|
||||
private:
|
||||
llvm::Type* llvm_type(ir::type *ty, llvm::LLVMContext &ctx);
|
||||
llvm::Value* llvm_value(ir::value *v,llvm:: LLVMContext &ctx);
|
||||
llvm::Instruction* llvm_inst(ir::instruction *inst, llvm::LLVMContext &ctx);
|
||||
llvm::Constant* llvm_constant(ir::constant *cst, llvm::LLVMContext &ctx);
|
||||
|
||||
Value* llvm_value(ir::value *v, LLVMContext &ctx,
|
||||
std::map<ir::value*, Value*> &vmap,
|
||||
std::map<ir::basic_block*, BasicBlock*> &bmap);
|
||||
public:
|
||||
void run(ir::module &src, llvm::Module &dst);
|
||||
|
||||
/* convert ir::constant to Constant */
|
||||
Constant *llvm_constant(ir::constant *cst, LLVMContext &ctx) {
|
||||
Type *dst_ty = llvm_type(cst->get_type(), ctx);
|
||||
if(auto* cc = dynamic_cast<ir::constant_int*>(cst))
|
||||
return ConstantInt::get(dst_ty, cc->get_value());
|
||||
if(auto* cc = dynamic_cast<ir::constant_fp*>(cst))
|
||||
return ConstantFP::get(dst_ty, cc->get_value());
|
||||
// unknown constant
|
||||
throw std::runtime_error("unknown conversion from ir::constant to Constant");
|
||||
}
|
||||
|
||||
|
||||
/* convert ir::instruction to Instruction */
|
||||
Instruction *llvm_inst(ir::instruction *inst, LLVMContext & ctx,
|
||||
std::map<ir::value*, Value*> &vmap,
|
||||
std::map<ir::basic_block*, BasicBlock*> &bmap) {
|
||||
auto value = [&](ir::value *x) { return llvm_value(x, ctx, vmap, bmap); };
|
||||
auto block = [&](ir::basic_block *x) { return bmap.at(x); };
|
||||
auto type = [&](ir::type *x) { return llvm_type(x, ctx); };
|
||||
if(auto* ii = dynamic_cast<ir::cond_branch_inst*>(inst)){
|
||||
BasicBlock *true_dest = block(ii->get_true_dest());
|
||||
BasicBlock *false_dest = block(ii->get_false_dest());
|
||||
Value *cond = value(ii->get_cond());
|
||||
return BranchInst::Create(true_dest, false_dest, cond);
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::uncond_branch_inst*>(inst)){
|
||||
BasicBlock *dest = block(ii->get_dest());
|
||||
return BranchInst::Create(dest);
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::phi_node*>(inst)){
|
||||
Type *ty = type(ii->get_type());
|
||||
unsigned num_ops = ii->get_num_operands();
|
||||
return PHINode::Create(ty, num_ops, ii->get_name());
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::return_inst*>(inst)){
|
||||
ir::value *ret_val = ii->get_return_value();
|
||||
return ReturnInst::Create(ctx, ret_val?value(ret_val):nullptr);
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::binary_operator*>(inst)){
|
||||
Value *lhs = value(ii->get_operand(0));
|
||||
Value *rhs = value(ii->get_operand(1));
|
||||
return BinaryOperator::Create(ii->get_op(), lhs, rhs, ii->get_name());
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::icmp_inst*>(inst)){
|
||||
CmpInst::Predicate pred = ii->get_pred();
|
||||
Value *lhs = value(ii->get_operand(0));
|
||||
Value *rhs = value(ii->get_operand(1));
|
||||
return CmpInst::Create(Instruction::ICmp, pred, lhs, rhs, ii->get_name());
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::fcmp_inst*>(inst)){
|
||||
CmpInst::Predicate pred = ii->get_pred();
|
||||
Value *lhs = value(ii->get_operand(0));
|
||||
Value *rhs = value(ii->get_operand(1));
|
||||
return FCmpInst::Create(Instruction::FCmp, pred, lhs, rhs, ii->get_name());
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::cast_inst*>(inst)){
|
||||
Value *arg = value(ii->get_operand(0));
|
||||
Type *dst_ty = type(ii->get_type());
|
||||
return CastInst::Create(ii->get_op(), arg, dst_ty, ii->get_name());
|
||||
}
|
||||
if(auto* ii = dynamic_cast<ir::getelementptr_inst*>(inst)){
|
||||
std::vector<Value*> idx_vals;
|
||||
std::transform(ii->idx_begin(), ii->idx_end(), std::back_inserter(idx_vals),
|
||||
[&value](ir::value* x){ return value(x);});
|
||||
Type *source_ty = type(ii->get_source_elt_ty());
|
||||
Value *arg = value(ii->get_operand(0));
|
||||
return GetElementPtrInst::Create(source_ty, arg, idx_vals, ii->get_name());
|
||||
}
|
||||
if(ir::load_inst* ii = dynamic_cast<ir::load_inst*>(inst)){
|
||||
Value *ptr = value(ii->get_pointer_operand());
|
||||
return new LoadInst(ptr, ii->get_name());
|
||||
}
|
||||
// unknown instruction
|
||||
throw std::runtime_error("unknown conversion from ir::type to Type");
|
||||
}
|
||||
|
||||
Value* llvm_value(ir::value *v, LLVMContext &ctx,
|
||||
std::map<ir::value*, Value*> &vmap,
|
||||
std::map<ir::basic_block*, BasicBlock*> &bmap) {
|
||||
if(vmap.find(v) != vmap.end())
|
||||
return vmap.at(v);
|
||||
// create operands
|
||||
if(auto *uu = dynamic_cast<ir::user*>(v))
|
||||
for(ir::value* u: uu->ops())
|
||||
vmap[u] = llvm_value(u, ctx, vmap, bmap);
|
||||
if(auto *cc = dynamic_cast<ir::constant*>(v))
|
||||
return llvm_constant(cc, ctx);
|
||||
// instruction
|
||||
if(auto *ii = dynamic_cast<ir::instruction*>(v))
|
||||
return llvm_inst(ii, ctx, vmap, bmap);
|
||||
// unknown value
|
||||
throw std::runtime_error("unknown conversion from ir::value to Value");
|
||||
}
|
||||
|
||||
void lowering(ir::module &src, Module &dst){
|
||||
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
|
||||
FunctionType *fn_ty = (FunctionType*)llvm_type(fn->get_fn_type(), dst_ctx);
|
||||
Function *dst_fn = Function::Create(fn_ty, Function::ExternalLinkage, "kernel", &dst);
|
||||
// std::cout << ((FunctionType*)fn_ty)->getNumParams() << std::endl;
|
||||
// map parameters
|
||||
for(unsigned i = 0; i < fn->args().size(); i++)
|
||||
vmap[fn->args()[i]] = &*(dst_fn->arg_begin() + i);
|
||||
// create blocks
|
||||
for(ir::basic_block *block: fn->blocks()) {
|
||||
BasicBlock *dst_block = BasicBlock::Create(dst_ctx, block->get_name(), dst_fn);
|
||||
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;
|
||||
dst_builder.Insert(dst_inst);
|
||||
}
|
||||
}
|
||||
// add phi operands
|
||||
for(ir::basic_block *block: fn->blocks())
|
||||
for(ir::instruction *inst: block->get_inst_list())
|
||||
if(auto *phi = dynamic_cast<ir::phi_node*>(inst)){
|
||||
PHINode *dst_phi = (PHINode*)vmap.at(phi);
|
||||
for(unsigned i = 0; i < phi->get_num_incoming(); i++){
|
||||
ir::value *inc_val = phi->get_incoming_value(i);
|
||||
ir::basic_block *inc_block = phi->get_incoming_block(i);
|
||||
Value *llvm_inc_val = llvm_value(inc_val, dst_ctx, vmap, bmap);
|
||||
BasicBlock *llvm_block = bmap[inc_block];
|
||||
dst_phi->addIncoming(llvm_inc_val, llvm_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
vmap_t vmap_;
|
||||
bmap_t bmap_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,10 +1,56 @@
|
||||
#ifndef TDL_INCLUDE_IR_CODEGEN_TUNE_H
|
||||
#define TDL_INCLUDE_IR_CODEGEN_TUNE_H
|
||||
//#ifndef TDL_INCLUDE_IR_CODEGEN_TUNE_H
|
||||
//#define TDL_INCLUDE_IR_CODEGEN_TUNE_H
|
||||
|
||||
namespace tdl{
|
||||
namespace codegen{
|
||||
//namespace tdl{
|
||||
//namespace codegen{
|
||||
|
||||
}
|
||||
}
|
||||
//// Layout binding pass
|
||||
//class TLVMAddTunerParams: public FunctionPass {
|
||||
//private:
|
||||
// enum CType{
|
||||
// Layout = 0, Shape = 1
|
||||
// };
|
||||
// // Params pool
|
||||
// SmallVector<MDNode*, 8> LParamsPool;
|
||||
// // Constraints
|
||||
// typedef std::pair<Value*, unsigned> CNodeType;
|
||||
// typedef DenseMap<CNodeType, DenseSet<CNodeType>> CGraphType;
|
||||
// // Layout constraints
|
||||
// CGraphType LCGraph;
|
||||
// DenseSet<CNodeType> LCNodes;
|
||||
// // Shape constraints
|
||||
// CGraphType SCGraph;
|
||||
// DenseSet<CNodeType> SCNodes;
|
||||
// // Relational
|
||||
// std::map<std::pair<Value*, std::string>, std::function<unsigned* ()>> ExtraParams;
|
||||
// DenseSet<unsigned> Constants;
|
||||
|
||||
#endif
|
||||
// void addConstraint(CNodeType X, CNodeType Y, CType CT);
|
||||
// void initCPhi(Instruction *I);
|
||||
// void initCGraph(Instruction *V);
|
||||
// void connectedComponents(CNodeType X, ArrayRef<MDNode *> Vals, CType CT, DenseSet<CNodeType> &Nodes, CGraphType &Graph);
|
||||
|
||||
//public:
|
||||
// static char ID;
|
||||
// TLVMAddTunerParams(): FunctionPass(ID){ }
|
||||
|
||||
// void getAnalysisUsage(AnalysisUsage & AU) const override;
|
||||
// bool runOnFunction(Function &F) override;
|
||||
|
||||
//private:
|
||||
// std::map<std::pair<Instruction*, std::string>, Constant*> KnownParams;
|
||||
//};
|
||||
|
||||
//class TLVMAddTunerConstraints: public FunctionPass {
|
||||
//public:
|
||||
// static char ID;
|
||||
// TLVMAddTunerConstraints(): FunctionPass(ID){ }
|
||||
|
||||
// void getAnalysisUsage(AnalysisUsage & AU) const override;
|
||||
// bool runOnFunction(Function &F) override;
|
||||
//};
|
||||
|
||||
//}
|
||||
//}
|
||||
|
||||
//#endif
|
||||
|
Reference in New Issue
Block a user