[Intermediate Representation] Added skeleton
This commit is contained in:
@@ -1,10 +1,6 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "codegen.h"
|
|
||||||
#include "llvm/IR/IRPrintingPasses.h"
|
|
||||||
#include "llvm/IR/LegacyPassManager.h"
|
|
||||||
#include "llvm/IR/PassManager.h"
|
|
||||||
|
|
||||||
typedef struct yy_buffer_state * YY_BUFFER_STATE;
|
typedef struct yy_buffer_state * YY_BUFFER_STATE;
|
||||||
extern int yyparse();
|
extern int yyparse();
|
||||||
@@ -29,12 +25,12 @@ int main() {
|
|||||||
YY_BUFFER_STATE buffer = yy_scan_string(src);
|
YY_BUFFER_STATE buffer = yy_scan_string(src);
|
||||||
yyparse();
|
yyparse();
|
||||||
yy_delete_buffer(buffer);
|
yy_delete_buffer(buffer);
|
||||||
translation_unit *program = ast_root;
|
// translation_unit *program = ast_root;
|
||||||
tdl::context context;
|
// tdl::context context;
|
||||||
tdl::module module("matrix", &context);
|
// tdl::module module("matrix", &context);
|
||||||
program->codegen(&module);
|
// program->codegen(&module);
|
||||||
llvm::PrintModulePass print(llvm::outs());
|
// llvm::PrintModulePass print(llvm::outs());
|
||||||
llvm::AnalysisManager<llvm::Module> analysis;
|
// llvm::AnalysisManager<llvm::Module> analysis;
|
||||||
print.run(*module.handle(), analysis);
|
// print.run(*module.handle(), analysis);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -2,22 +2,22 @@
|
|||||||
#define TDL_INCLUDE_AST_H
|
#define TDL_INCLUDE_AST_H
|
||||||
|
|
||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
#include "llvm/IR/IRBuilder.h"
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace llvm{
|
|
||||||
|
|
||||||
class Function;
|
|
||||||
class Value;
|
|
||||||
class Type;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace tdl{
|
namespace tdl{
|
||||||
|
|
||||||
class module;
|
|
||||||
|
namespace ir{
|
||||||
|
class function;
|
||||||
|
class value;
|
||||||
|
class type;
|
||||||
|
class builder;
|
||||||
|
class module;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ast{
|
namespace ast{
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ class identifier;
|
|||||||
// AST
|
// AST
|
||||||
class node {
|
class node {
|
||||||
public:
|
public:
|
||||||
virtual llvm::Value* codegen(module*) const { return nullptr; }
|
virtual ir::value* codegen(ir::module *) const { return nullptr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
@@ -75,7 +75,7 @@ public:
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value* codegen(module* mod) const{
|
ir::value* codegen(ir::module * mod) const{
|
||||||
for(T x: values_){
|
for(T x: values_){
|
||||||
x->codegen(mod);
|
x->codegen(mod);
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ public:
|
|||||||
|
|
||||||
class expression: public node{
|
class expression: public node{
|
||||||
public:
|
public:
|
||||||
virtual llvm::Value* codegen(module *) const = 0;
|
virtual ir::value* codegen(ir::module *) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class postfix_expression: public expression{
|
class postfix_expression: public expression{
|
||||||
@@ -121,7 +121,7 @@ public:
|
|||||||
indexing_expression(node *id, node *ranges)
|
indexing_expression(node *id, node *ranges)
|
||||||
: id_((const identifier*)id), ranges_((const list<range*>*)ranges) {}
|
: id_((const identifier*)id), ranges_((const list<range*>*)ranges) {}
|
||||||
|
|
||||||
llvm::Value* codegen(module *) const;
|
ir::value* codegen(ir::module *) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const identifier* id_;
|
const identifier* id_;
|
||||||
@@ -140,17 +140,17 @@ private:
|
|||||||
class named_expression: public unary_expression {
|
class named_expression: public unary_expression {
|
||||||
public:
|
public:
|
||||||
named_expression(node *id): unary_expression(id){ }
|
named_expression(node *id): unary_expression(id){ }
|
||||||
llvm::Value* codegen(module* mod) const;
|
ir::value* codegen(ir::module * mod) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class binary_operator: public expression{
|
class binary_operator: public expression{
|
||||||
private:
|
private:
|
||||||
llvm::Value* llvm_op(module *mod, llvm::IRBuilder<> &bld, llvm::Value *lhs, llvm::Value *rhs, const std::string &name) const;
|
ir::value* llvm_op(ir::module *mod, ir::builder &bld, ir::value *lhs, ir::value *rhs, const std::string &name) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
binary_operator(BIN_OP_T op, node *lhs, node *rhs)
|
binary_operator(BIN_OP_T op, node *lhs, node *rhs)
|
||||||
: op_(op), lhs_((expression*)lhs), rhs_((expression*)rhs) { }
|
: op_(op), lhs_((expression*)lhs), rhs_((expression*)rhs) { }
|
||||||
llvm::Value* codegen(module *) const;
|
ir::value* codegen(ir::module *) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const BIN_OP_T op_;
|
const BIN_OP_T op_;
|
||||||
@@ -162,7 +162,7 @@ private:
|
|||||||
class constant: public expression{
|
class constant: public expression{
|
||||||
public:
|
public:
|
||||||
constant(int value): value_(value) { }
|
constant(int value): value_(value) { }
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
int value() const;
|
int value() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -173,7 +173,7 @@ private:
|
|||||||
class string_literal: public expression{
|
class string_literal: public expression{
|
||||||
public:
|
public:
|
||||||
string_literal(char *&value): value_(value) { }
|
string_literal(char *&value): value_(value) { }
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string value_;
|
std::string value_;
|
||||||
@@ -181,14 +181,14 @@ public:
|
|||||||
|
|
||||||
class unary_operator: public expression{
|
class unary_operator: public expression{
|
||||||
private:
|
private:
|
||||||
llvm::Value *llvm_op(llvm::IRBuilder<> &builder, llvm::Value *arg, const std::string &name) const;
|
ir::value *llvm_op(ir::builder &builder, ir::value *arg, const std::string &name) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unary_operator(UNARY_OP_T op, node *arg)
|
unary_operator(UNARY_OP_T op, node *arg)
|
||||||
: op_(op),
|
: op_(op),
|
||||||
arg_((expression*)arg) { }
|
arg_((expression*)arg) { }
|
||||||
|
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const UNARY_OP_T op_;
|
const UNARY_OP_T op_;
|
||||||
@@ -198,14 +198,14 @@ private:
|
|||||||
class type_name;
|
class type_name;
|
||||||
class cast_operator: public expression{
|
class cast_operator: public expression{
|
||||||
private:
|
private:
|
||||||
llvm::Value *llvm_op(llvm::IRBuilder<> &builder, llvm::Type *T, llvm::Value *arg, const std::string &name) const;
|
ir::value *llvm_op(ir::builder &builder, ir::type *T, ir::value *arg, const std::string &name) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cast_operator(node *T, node *arg):
|
cast_operator(node *T, node *arg):
|
||||||
T_((type_name*)T),
|
T_((type_name*)T),
|
||||||
arg_((expression*)arg) { }
|
arg_((expression*)arg) { }
|
||||||
|
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const type_name *T_;
|
const type_name *T_;
|
||||||
@@ -214,8 +214,8 @@ public:
|
|||||||
|
|
||||||
class conditional_expression: public expression{
|
class conditional_expression: public expression{
|
||||||
private:
|
private:
|
||||||
llvm::Value *llvm_op(llvm::IRBuilder<> &builder,
|
ir::value *llvm_op(ir::builder &builder,
|
||||||
llvm::Value *cond, llvm::Value *true_value, llvm::Value *false_value,
|
ir::value *cond, ir::value *true_value, ir::value *false_value,
|
||||||
const std::string &name) const;
|
const std::string &name) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -224,7 +224,7 @@ public:
|
|||||||
true_value_((expression*)true_value),
|
true_value_((expression*)true_value),
|
||||||
false_value_((expression*)false_value) { }
|
false_value_((expression*)false_value) { }
|
||||||
|
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const expression *cond_;
|
const expression *cond_;
|
||||||
@@ -237,7 +237,7 @@ public:
|
|||||||
assignment_expression(node *lvalue, ASSIGN_OP_T op, node *rvalue)
|
assignment_expression(node *lvalue, ASSIGN_OP_T op, node *rvalue)
|
||||||
: lvalue_((unary_expression*)lvalue), op_(op), rvalue_((expression*)rvalue) { }
|
: lvalue_((unary_expression*)lvalue), op_(op), rvalue_((expression*)rvalue) { }
|
||||||
|
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ASSIGN_OP_T op_;
|
ASSIGN_OP_T op_;
|
||||||
@@ -254,7 +254,7 @@ public:
|
|||||||
declaration(node *spec, node *init)
|
declaration(node *spec, node *init)
|
||||||
: spec_((declaration_specifier*)spec), init_((list<initializer*>*)init) { }
|
: spec_((declaration_specifier*)spec), init_((list<initializer*>*)init) { }
|
||||||
|
|
||||||
llvm::Value* codegen(module* mod) const;
|
ir::value* codegen(ir::module * mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const declaration_specifier *spec_;
|
const declaration_specifier *spec_;
|
||||||
@@ -272,7 +272,7 @@ public:
|
|||||||
compound_statement(node* decls, node* statements)
|
compound_statement(node* decls, node* statements)
|
||||||
: decls_((declarations_t)decls), statements_((statements_t)statements) {}
|
: decls_((declarations_t)decls), statements_((statements_t)statements) {}
|
||||||
|
|
||||||
llvm::Value* codegen(module* mod) const;
|
ir::value* codegen(ir::module * mod) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
declarations_t decls_;
|
declarations_t decls_;
|
||||||
@@ -284,7 +284,7 @@ public:
|
|||||||
selection_statement(node *cond, node *if_value, node *else_value = nullptr)
|
selection_statement(node *cond, node *if_value, node *else_value = nullptr)
|
||||||
: cond_(cond), then_value_(if_value), else_value_(else_value) { }
|
: cond_(cond), then_value_(if_value), else_value_(else_value) { }
|
||||||
|
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const node *cond_;
|
const node *cond_;
|
||||||
@@ -298,7 +298,7 @@ public:
|
|||||||
: init_(init), stop_(stop), exec_(exec), statements_(statements)
|
: init_(init), stop_(stop), exec_(exec), statements_(statements)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
llvm::Value* codegen(module *mod) const;
|
ir::value* codegen(ir::module *mod) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const node *init_;
|
const node *init_;
|
||||||
@@ -316,7 +316,7 @@ public:
|
|||||||
declaration_specifier(TYPE_T spec)
|
declaration_specifier(TYPE_T spec)
|
||||||
: spec_(spec) { }
|
: spec_(spec) { }
|
||||||
|
|
||||||
llvm::Type* type(module *mod) const;
|
ir::type* type(ir::module *mod) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const TYPE_T spec_;
|
const TYPE_T spec_;
|
||||||
@@ -329,7 +329,7 @@ public:
|
|||||||
: spec_((declaration_specifier*)spec),
|
: spec_((declaration_specifier*)spec),
|
||||||
decl_((declarator*)decl) { }
|
decl_((declarator*)decl) { }
|
||||||
|
|
||||||
llvm::Type* type(module *mod) const;
|
ir::type* type(ir::module *mod) const;
|
||||||
const identifier* id() const;
|
const identifier* id() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -339,13 +339,13 @@ public:
|
|||||||
|
|
||||||
/* Declarators */
|
/* Declarators */
|
||||||
class declarator: public node{
|
class declarator: public node{
|
||||||
virtual llvm::Type* type_impl(module*mod, llvm::Type *type) const = 0;
|
virtual ir::type* type_impl(ir::module *mod, ir::type *type) const = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
declarator(node *lhs)
|
declarator(node *lhs)
|
||||||
: lhs_((declarator*)lhs), ptr_(nullptr){ }
|
: lhs_((declarator*)lhs), ptr_(nullptr){ }
|
||||||
|
|
||||||
llvm::Type* type(module*mod, llvm::Type *type) const;
|
ir::type* type(ir::module *mod, ir::type *type) const;
|
||||||
|
|
||||||
const identifier* id() const {
|
const identifier* id() const {
|
||||||
return (const identifier*)lhs_;
|
return (const identifier*)lhs_;
|
||||||
@@ -362,7 +362,7 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class identifier: public declarator {
|
class identifier: public declarator {
|
||||||
llvm::Type* type_impl(module*mod, llvm::Type *type) const;
|
ir::type* type_impl(ir::module *mod, ir::type *type) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
identifier(char *&name): declarator(this), name_(name) { }
|
identifier(char *&name): declarator(this), name_(name) { }
|
||||||
@@ -374,7 +374,7 @@ private:
|
|||||||
|
|
||||||
class pointer: public declarator{
|
class pointer: public declarator{
|
||||||
private:
|
private:
|
||||||
llvm::Type* type_impl(module *mod, llvm::Type *type) const;
|
ir::type* type_impl(ir::module *mod, ir::type *type) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pointer(node *id): declarator(id) { }
|
pointer(node *id): declarator(id) { }
|
||||||
@@ -382,7 +382,7 @@ public:
|
|||||||
|
|
||||||
class tile: public declarator{
|
class tile: public declarator{
|
||||||
private:
|
private:
|
||||||
llvm::Type* type_impl(module *mod, llvm::Type *type) const;
|
ir::type* type_impl(ir::module *mod, ir::type *type) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tile(node *id, node *shapes)
|
tile(node *id, node *shapes)
|
||||||
@@ -394,13 +394,13 @@ public:
|
|||||||
|
|
||||||
class function: public declarator{
|
class function: public declarator{
|
||||||
private:
|
private:
|
||||||
llvm::Type* type_impl(module *mod, llvm::Type *type) const;
|
ir::type* type_impl(ir::module *mod, ir::type *type) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
function(node *id, node *args)
|
function(node *id, node *args)
|
||||||
: declarator(id), args_((list<parameter*>*)args) { }
|
: declarator(id), args_((list<parameter*>*)args) { }
|
||||||
|
|
||||||
void bind_parameters(module *mod, llvm::Function *fn) const;
|
void bind_parameters(ir::module *mod, ir::function *fn) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const list<parameter*>* args_;
|
const list<parameter*>* args_;
|
||||||
@@ -409,7 +409,7 @@ public:
|
|||||||
|
|
||||||
class initializer : public declarator{
|
class initializer : public declarator{
|
||||||
private:
|
private:
|
||||||
llvm::Type* type_impl(module* mod, llvm::Type *type) const;
|
ir::type* type_impl(ir::module * mod, ir::type *type) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
initializer(node *decl, node *init)
|
initializer(node *decl, node *init)
|
||||||
@@ -417,7 +417,7 @@ public:
|
|||||||
decl_((declarator*)decl), expr_((expression*)init){ }
|
decl_((declarator*)decl), expr_((expression*)init){ }
|
||||||
|
|
||||||
void specifier(const declaration_specifier *spec);
|
void specifier(const declaration_specifier *spec);
|
||||||
llvm::Value* codegen(module *) const;
|
ir::value* codegen(ir::module *) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const declaration_specifier *spec_;
|
const declaration_specifier *spec_;
|
||||||
@@ -431,7 +431,7 @@ public:
|
|||||||
type_name(node *spec, node * decl)
|
type_name(node *spec, node * decl)
|
||||||
: spec_((declaration_specifier*)spec), decl_((declarator*)decl) { }
|
: spec_((declaration_specifier*)spec), decl_((declarator*)decl) { }
|
||||||
|
|
||||||
llvm::Type *type(module *mod) const;
|
ir::type *type(ir::module *mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const declaration_specifier *spec_;
|
const declaration_specifier *spec_;
|
||||||
@@ -444,7 +444,7 @@ public:
|
|||||||
function_definition(node *spec, node *header, node *body)
|
function_definition(node *spec, node *header, node *body)
|
||||||
: spec_((declaration_specifier*)spec), header_((function *)header), body_((compound_statement*)body) { }
|
: spec_((declaration_specifier*)spec), header_((function *)header), body_((compound_statement*)body) { }
|
||||||
|
|
||||||
llvm::Value* codegen(module* mod) const;
|
ir::value* codegen(ir::module * mod) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const declaration_specifier *spec_;
|
const declaration_specifier *spec_;
|
||||||
@@ -463,7 +463,7 @@ public:
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value* codegen(module* mod) const;
|
ir::value* codegen(ir::module * mod) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
list<node*>* decls_;
|
list<node*>* decls_;
|
||||||
|
@@ -1,47 +0,0 @@
|
|||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include "ast.h"
|
|
||||||
#include "llvm/IR/LLVMContext.h"
|
|
||||||
#include "llvm/IR/IRBuilder.h"
|
|
||||||
|
|
||||||
namespace tdl
|
|
||||||
{
|
|
||||||
|
|
||||||
class context {
|
|
||||||
public:
|
|
||||||
context();
|
|
||||||
llvm::LLVMContext* handle();
|
|
||||||
|
|
||||||
private:
|
|
||||||
llvm::LLVMContext handle_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class module {
|
|
||||||
typedef std::pair<std::string, llvm::BasicBlock*> val_key_t;
|
|
||||||
llvm::PHINode *make_phi(llvm::Type *type, unsigned num_values, llvm::BasicBlock *block);
|
|
||||||
llvm::Value *add_phi_operands(const std::string& name, llvm::PHINode *&phi);
|
|
||||||
llvm::Value *get_value_recursive(const std::string& name, llvm::BasicBlock *block);
|
|
||||||
|
|
||||||
public:
|
|
||||||
module(const std::string &name, context *ctx);
|
|
||||||
llvm::Module* handle();
|
|
||||||
llvm::IRBuilder<>& builder();
|
|
||||||
// Setters
|
|
||||||
void set_value(const std::string& name, llvm::BasicBlock* block, llvm::Value *value);
|
|
||||||
void set_value(const std::string& name, llvm::Value* value);
|
|
||||||
// Getters
|
|
||||||
llvm::Value *get_value(const std::string& name, llvm::BasicBlock* block);
|
|
||||||
llvm::Value *get_value(const std::string& name);
|
|
||||||
// Seal block -- no more predecessors will be added
|
|
||||||
llvm::Value *seal_block(llvm::BasicBlock *block);
|
|
||||||
|
|
||||||
private:
|
|
||||||
llvm::Module handle_;
|
|
||||||
llvm::IRBuilder<> builder_;
|
|
||||||
std::map<val_key_t, llvm::Value*> values_;
|
|
||||||
std::set<llvm::BasicBlock*> sealed_blocks_;
|
|
||||||
std::map<llvm::BasicBlock*, std::map<std::string, llvm::PHINode*>> incomplete_phis_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
29
include/ir/basic_block.h
Normal file
29
include/ir/basic_block.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_BASIC_BLOCK_H
|
||||||
|
#define TDL_INCLUDE_IR_BASIC_BLOCK_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
class context;
|
||||||
|
class function;
|
||||||
|
|
||||||
|
/* Basic Block */
|
||||||
|
class basic_block: public value{
|
||||||
|
public:
|
||||||
|
function* get_parent();
|
||||||
|
// Factory functions
|
||||||
|
static basic_block* create(context &ctx, const std::string &name, function *parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
context &ctx_;
|
||||||
|
std::string name_;
|
||||||
|
function *parent_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
89
include/ir/builder.h
Normal file
89
include/ir/builder.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_BUILDER_H
|
||||||
|
#define TDL_INCLUDE_IR_BUILDER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
class basic_block;
|
||||||
|
class value;
|
||||||
|
class type;
|
||||||
|
class constant_int;
|
||||||
|
|
||||||
|
/* Builder */
|
||||||
|
class builder{
|
||||||
|
public:
|
||||||
|
void set_insert_point(basic_block* bb);
|
||||||
|
basic_block* get_insert_block();
|
||||||
|
// Constants
|
||||||
|
value *get_int32(unsigned val);
|
||||||
|
// Types
|
||||||
|
type *get_float_ty();
|
||||||
|
type *get_double_ty();
|
||||||
|
// Branch instructions
|
||||||
|
value* create_br(basic_block *bb);
|
||||||
|
value* create_cond_br(value *cond, basic_block* if_bb, basic_block* else_bb);
|
||||||
|
// 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);
|
||||||
|
// Binary instructions
|
||||||
|
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_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_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_icmpSGE(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_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 = "");
|
||||||
|
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 = "");
|
||||||
|
// Side effects
|
||||||
|
value *create_fneg(value *arg, const std::string &name = "");
|
||||||
|
value *create_neg(value *arg, const std::string &name = "");
|
||||||
|
value *create_load(value *arg, const std::string &name = "");
|
||||||
|
value *create_not(value *arg, const std::string &name = "");
|
||||||
|
// Tile instruction
|
||||||
|
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 = "");
|
||||||
|
// Terminators
|
||||||
|
value *create_ret_void();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
32
include/ir/constant.h
Normal file
32
include/ir/constant.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_CONSTANT_H
|
||||||
|
#define TDL_INCLUDE_IR_CONSTANT_H
|
||||||
|
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
class type;
|
||||||
|
class context;
|
||||||
|
|
||||||
|
/* Constant */
|
||||||
|
class constant: public value{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Undef value */
|
||||||
|
class undef_value: public constant{
|
||||||
|
public:
|
||||||
|
static undef_value* get(type* ty);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Data array */
|
||||||
|
class constant_data_array: public constant{
|
||||||
|
public:
|
||||||
|
static constant_data_array* get_string(context &ctx, const std::string &str);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
14
include/ir/context.h
Normal file
14
include/ir/context.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_CONTEXT_H
|
||||||
|
#define TDL_INCLUDE_IR_CONTEXT_H
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
/* Context */
|
||||||
|
class context {
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
40
include/ir/function.h
Normal file
40
include/ir/function.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_FUNCTION_H
|
||||||
|
#define TDL_INCLUDE_IR_FUNCTION_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
class function_type;
|
||||||
|
class module;
|
||||||
|
|
||||||
|
/* Argument */
|
||||||
|
class argument: public value{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Function */
|
||||||
|
class function: public value{
|
||||||
|
using arg_iterator = argument *;
|
||||||
|
using const_arg_iterator = const argument *;
|
||||||
|
|
||||||
|
public:
|
||||||
|
arg_iterator arg_begin();
|
||||||
|
arg_iterator arg_end();
|
||||||
|
const_arg_iterator arg_begin() const;
|
||||||
|
const_arg_iterator arg_end() const;
|
||||||
|
// Factory methods
|
||||||
|
static function *create(function_type *type, const std::string &name, module *mod);
|
||||||
|
|
||||||
|
private:
|
||||||
|
function_type *type_;
|
||||||
|
std::string name_;
|
||||||
|
module *mod_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
29
include/ir/instructions.h
Normal file
29
include/ir/instructions.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_INSTRUCTIONS_H
|
||||||
|
#define TDL_INCLUDE_IR_INSTRUCTIONS_H
|
||||||
|
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
/* Instructions */
|
||||||
|
class instruction: public value{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class phi_node: public instruction{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class binary_operator: public instruction{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class unary_operator: public instruction{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
47
include/ir/module.h
Normal file
47
include/ir/module.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_MODULE_H
|
||||||
|
#define TDL_INCLUDE_IR_MODULE_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include "builder.h"
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
class basic_block;
|
||||||
|
class phi_node;
|
||||||
|
class value;
|
||||||
|
class context;
|
||||||
|
|
||||||
|
/* Module */
|
||||||
|
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 *get_value_recursive(const std::string& name, basic_block *block);
|
||||||
|
|
||||||
|
public:
|
||||||
|
module(const std::string &name, context *ctx);
|
||||||
|
context& get_context();
|
||||||
|
builder& get_builder();
|
||||||
|
// Setters
|
||||||
|
void set_value(const std::string& name, basic_block* block, value *x);
|
||||||
|
void set_value(const std::string& name, value* x);
|
||||||
|
// Getters
|
||||||
|
value *get_value(const std::string& name, basic_block* block);
|
||||||
|
value *get_value(const std::string& name);
|
||||||
|
// Seal block -- no more predecessors will be added
|
||||||
|
void seal_block(basic_block *block);
|
||||||
|
|
||||||
|
private:
|
||||||
|
builder builder_;
|
||||||
|
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_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
58
include/ir/type.h
Normal file
58
include/ir/type.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_TYPE_H
|
||||||
|
#define TDL_INCLUDE_IR_TYPE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
class context;
|
||||||
|
|
||||||
|
/* Type */
|
||||||
|
class type {
|
||||||
|
public:
|
||||||
|
bool is_integer_ty() const;
|
||||||
|
bool is_pointer_ty() const;
|
||||||
|
bool is_float_ty() const;
|
||||||
|
bool is_double_ty() const;
|
||||||
|
bool is_floating_point_ty() const;
|
||||||
|
|
||||||
|
// type attributes
|
||||||
|
unsigned get_fp_mantissa_width() const;
|
||||||
|
unsigned get_integer_bit_width() const;
|
||||||
|
const std::vector<unsigned> &get_tile_shapes() const;
|
||||||
|
// Factory methods
|
||||||
|
static type* get_void_ty(context &ctx);
|
||||||
|
static type* get_float_ty(context &ctx);
|
||||||
|
static type* get_double_ty(context &ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
class integer_type: public type {
|
||||||
|
public:
|
||||||
|
static integer_type* get(context &ctx, unsigned width);
|
||||||
|
};
|
||||||
|
|
||||||
|
class tile_type: public type {
|
||||||
|
public:
|
||||||
|
static tile_type* get(type *ty, const std::vector<unsigned> &shapes);
|
||||||
|
};
|
||||||
|
|
||||||
|
class pointer_type: public type {
|
||||||
|
public:
|
||||||
|
static pointer_type* get(type *ty, unsigned address_space);
|
||||||
|
};
|
||||||
|
|
||||||
|
class function_type: public type {
|
||||||
|
public:
|
||||||
|
static function_type* get(type *ret_ty, const std::vector<type*>& param_tys);
|
||||||
|
|
||||||
|
private:
|
||||||
|
type *return_type_;
|
||||||
|
std::vector<type *> param_types_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
24
include/ir/value.h
Normal file
24
include/ir/value.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef TDL_INCLUDE_IR_VALUE_H
|
||||||
|
#define TDL_INCLUDE_IR_VALUE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
class type;
|
||||||
|
|
||||||
|
/* Value */
|
||||||
|
class value {
|
||||||
|
public:
|
||||||
|
void set_name(const std::string &name);
|
||||||
|
type* get_type();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
603
lib/codegen.cpp
603
lib/codegen.cpp
@@ -1,141 +1,42 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <algorithm>
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "codegen.h"
|
#include "ir/constant.h"
|
||||||
#include "llvm/IR/DerivedTypes.h"
|
#include "ir/function.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "ir/module.h"
|
||||||
#include "llvm/IR/CFG.h"
|
#include "ir/basic_block.h"
|
||||||
#include "llvm/IR/Instructions.h"
|
#include "ir/builder.h"
|
||||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
#include "ir/type.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
namespace tdl{
|
namespace tdl{
|
||||||
|
|
||||||
/* Nd Array utils */
|
|
||||||
inline std::vector<unsigned> array_shapes(Type *array_ty){
|
|
||||||
std::vector<unsigned> result;
|
|
||||||
Type *current = array_ty;
|
|
||||||
while(isa<ArrayType>(current)){
|
|
||||||
result.push_back(array_ty->getArrayNumElements());
|
|
||||||
current = array_ty->getArrayElementType();
|
|
||||||
printf("%d %d\n", current, current->getTypeID());
|
|
||||||
};
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Context */
|
|
||||||
context::context() { }
|
|
||||||
|
|
||||||
LLVMContext *context::handle() {
|
|
||||||
return &handle_;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Module */
|
|
||||||
module::module(const std::string &name, context *ctx)
|
|
||||||
: handle_(name.c_str(), *ctx->handle()), builder_(*ctx->handle()) {
|
|
||||||
sealed_blocks_.insert(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Module* module::handle() {
|
|
||||||
return &handle_;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::IRBuilder<>& module::builder() {
|
|
||||||
return builder_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void module::set_value(const std::string& name, BasicBlock *block, Value *value){
|
|
||||||
values_[val_key_t{name, block}] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void module::set_value(const std::string& name, llvm::Value* value){
|
|
||||||
return set_value(name, builder_.GetInsertBlock(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
PHINode* module::make_phi(Type *type, unsigned num_values, BasicBlock *block){
|
|
||||||
Instruction* instr = block->getFirstNonPHIOrDbg();
|
|
||||||
if(instr)
|
|
||||||
builder_.SetInsertPoint(instr);
|
|
||||||
PHINode *res = builder_.CreatePHI(type, num_values);
|
|
||||||
if(instr)
|
|
||||||
builder_.SetInsertPoint(block);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
Value *module::add_phi_operands(const std::string& name, PHINode *&phi){
|
|
||||||
BasicBlock *block = phi->getParent();
|
|
||||||
for(BasicBlock *pred: predecessors(block)){
|
|
||||||
llvm::Value *value = get_value(name, pred);
|
|
||||||
phi->addIncoming(value, pred);
|
|
||||||
}
|
|
||||||
return phi;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *module::get_value_recursive(const std::string& name, BasicBlock *block) {
|
|
||||||
llvm::Value *result;
|
|
||||||
if(sealed_blocks_.find(block) == sealed_blocks_.end()){
|
|
||||||
llvm::Value *pred = get_value(name, *pred_begin(block));
|
|
||||||
incomplete_phis_[block][name] = make_phi(pred->getType(), 1, block);
|
|
||||||
result = (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{
|
|
||||||
llvm::Value *pred = get_value(name, *pred_begin(block));
|
|
||||||
result = make_phi(pred->getType(), 1, block);
|
|
||||||
set_value(name, block, result);
|
|
||||||
add_phi_operands(name, (PHINode*&)result);
|
|
||||||
}
|
|
||||||
set_value(name, block, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *module::get_value(const std::string& name, BasicBlock *block) {
|
|
||||||
val_key_t key(name, block);
|
|
||||||
if(values_.find(key) != values_.end()){
|
|
||||||
return values_.at(key);
|
|
||||||
}
|
|
||||||
return get_value_recursive(name, block);
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *module::get_value(const std::string& name) {
|
|
||||||
return get_value(name, builder_.GetInsertBlock());
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value *module::seal_block(BasicBlock *block){
|
|
||||||
for(auto &x: incomplete_phis_[block])
|
|
||||||
add_phi_operands(x.first, x.second);
|
|
||||||
sealed_blocks_.insert(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ast{
|
namespace ast{
|
||||||
|
|
||||||
/* Translation unit */
|
/* Translation unit */
|
||||||
Value* translation_unit::codegen(module *mod) const{
|
ir::value* translation_unit::codegen(ir::module *mod) const{
|
||||||
decls_->codegen(mod);
|
decls_->codegen(mod);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Declaration specifier */
|
/* Declaration specifier */
|
||||||
Type* declaration_specifier::type(module *mod) const {
|
ir::type* declaration_specifier::type(ir::module *mod) const {
|
||||||
LLVMContext &ctx = mod->handle()->getContext();
|
ir::context &ctx = mod->get_context();
|
||||||
switch (spec_) {
|
switch (spec_) {
|
||||||
case VOID_T: return Type::getVoidTy(ctx);
|
case VOID_T: return ir::type::get_void_ty(ctx);
|
||||||
case INT8_T: return IntegerType::get(ctx, 8);
|
case INT8_T: return ir::integer_type::get(ctx, 8);
|
||||||
case INT16_T: return IntegerType::get(ctx, 16);
|
case INT16_T: return ir::integer_type::get(ctx, 16);
|
||||||
case INT32_T: return IntegerType::get(ctx, 32);
|
case INT32_T: return ir::integer_type::get(ctx, 32);
|
||||||
case INT64_T: return IntegerType::get(ctx, 64);
|
case INT64_T: return ir::integer_type::get(ctx, 64);
|
||||||
case FLOAT32_T: return Type::getFloatTy(ctx);
|
case FLOAT32_T: return ir::type::get_float_ty(ctx);
|
||||||
case FLOAT64_T: return Type::getDoubleTy(ctx);
|
case FLOAT64_T: return ir::type::get_double_ty(ctx);
|
||||||
default: assert(false && "unreachable"); throw;
|
default: throw std::runtime_error("unreachable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parameter */
|
/* Parameter */
|
||||||
Type* parameter::type(module *mod) const {
|
ir::type* parameter::type(ir::module *mod) const {
|
||||||
return decl_->type(mod, spec_->type(mod));
|
return decl_->type(mod, spec_->type(mod));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,14 +45,14 @@ const identifier *parameter::id() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Declarators */
|
/* Declarators */
|
||||||
Type* declarator::type(module *mod, Type *type) const{
|
ir::type* declarator::type(ir::module *mod, ir::type *type) const{
|
||||||
if(ptr_)
|
if(ptr_)
|
||||||
return type_impl(mod, ptr_->type(mod, type));
|
return type_impl(mod, ptr_->type(mod, type));
|
||||||
return type_impl(mod, type);
|
return type_impl(mod, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identifier
|
// Identifier
|
||||||
Type* identifier::type_impl(module *, Type *type) const{
|
ir::type* identifier::type_impl(ir::module *, ir::type *type) const{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,60 +61,57 @@ const std::string &identifier::name() const{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tile
|
// Tile
|
||||||
Type* tile::type_impl(module*, Type *type) const{
|
ir::type* tile::type_impl(ir::module*, ir::type *type) const{
|
||||||
Type *current = type;
|
std::vector<unsigned> shapes;
|
||||||
unsigned i = 0;
|
for(constant *cst: shapes_->values())
|
||||||
do{
|
shapes.push_back(cst->value());
|
||||||
current = ArrayType::get(current, shapes_->values()[i++]->value());
|
return ir::tile_type::get(type, shapes);
|
||||||
}while(i < shapes_->values().size());
|
|
||||||
return current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Pointer
|
// Pointer
|
||||||
Type* pointer::type_impl(module*, Type *type) const{
|
ir::type* pointer::type_impl(ir::module*, ir::type *type) const{
|
||||||
return PointerType::get(type, 1);
|
return ir::pointer_type::get(type, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function
|
// Function
|
||||||
void function::bind_parameters(module *mod, Function *fn) const{
|
void function::bind_parameters(ir::module *mod, ir::function *fn) const{
|
||||||
std::vector<llvm::Value*> args;
|
std::vector<ir::value*> args;
|
||||||
std::transform(fn->arg_begin(), fn->arg_end(), std::back_inserter(args), [&](llvm::Argument& x){ return &x;});
|
std::transform(fn->arg_begin(), fn->arg_end(), std::back_inserter(args), [&](ir::argument& x){ return &x;});
|
||||||
assert(args.size() == args_->values().size());
|
assert(args.size() == args_->values().size());
|
||||||
for(size_t i = 0; i < args.size(); i++){
|
for(size_t i = 0; i < args.size(); i++){
|
||||||
parameter *param_i = args_->values().at(i);
|
parameter *param_i = args_->values().at(i);
|
||||||
const identifier *id_i = param_i->id();
|
const identifier *id_i = param_i->id();
|
||||||
if(id_i){
|
if(id_i){
|
||||||
args[i]->setName(id_i->name());
|
args[i]->set_name(id_i->name());
|
||||||
mod->set_value(id_i->name(), nullptr, args[i]);
|
mod->set_value(id_i->name(), nullptr, args[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type* function::type_impl(module*mod, Type *type) const{
|
ir::type* function::type_impl(ir::module* mod, ir::type *type) const{
|
||||||
SmallVector<Type*, 8> types;
|
std::vector<ir::type*> types;
|
||||||
for(parameter* param: args_->values()){
|
for(parameter* param: args_->values())
|
||||||
types.push_back(param->type(mod));
|
types.push_back(param->type(mod));
|
||||||
}
|
return ir::function_type::get(type, types);
|
||||||
return FunctionType::get(type, types, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function definition */
|
/* Function definition */
|
||||||
Value* function_definition::codegen(module *mod) const{
|
ir::value* function_definition::codegen(ir::module *mod) const{
|
||||||
FunctionType *prototype = (FunctionType *)header_->type(mod, spec_->type(mod));
|
ir::function_type *prototype = (ir::function_type*)header_->type(mod, spec_->type(mod));
|
||||||
const std::string &name = header_->id()->name();
|
const std::string &name = header_->id()->name();
|
||||||
Function *fn = Function::Create(prototype, Function::ExternalLinkage, name, mod->handle());
|
ir::function *fn = ir::function::create(prototype, name, mod);
|
||||||
header_->bind_parameters(mod, fn);
|
header_->bind_parameters(mod, fn);
|
||||||
BasicBlock *entry = BasicBlock::Create(mod->handle()->getContext(), "entry", fn);
|
ir::basic_block *entry = ir::basic_block::create(mod->get_context(), "entry", fn);
|
||||||
mod->seal_block(entry);
|
mod->seal_block(entry);
|
||||||
mod->builder().SetInsertPoint(entry);
|
mod->get_builder().set_insert_point(entry);
|
||||||
body_->codegen(mod);
|
body_->codegen(mod);
|
||||||
mod->builder().CreateRetVoid();
|
mod->get_builder().create_ret_void();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Statements */
|
/* Statements */
|
||||||
Value* compound_statement::codegen(module* mod) const{
|
ir::value* compound_statement::codegen(ir::module* mod) const{
|
||||||
decls_->codegen(mod);
|
decls_->codegen(mod);
|
||||||
if(statements_)
|
if(statements_)
|
||||||
statements_->codegen(mod);
|
statements_->codegen(mod);
|
||||||
@@ -221,56 +119,56 @@ Value* compound_statement::codegen(module* mod) const{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Iteration statement */
|
/* Iteration statement */
|
||||||
Value* iteration_statement::codegen(module *mod) const{
|
ir::value* iteration_statement::codegen(ir::module *mod) const{
|
||||||
IRBuilder<> &builder = mod->builder();
|
ir::builder &builder = mod->get_builder();
|
||||||
LLVMContext &ctx = mod->handle()->getContext();
|
ir::context &ctx = mod->get_context();
|
||||||
Function *fn = builder.GetInsertBlock()->getParent();
|
ir::function *fn = builder.get_insert_block()->get_parent();
|
||||||
BasicBlock *loop_bb = BasicBlock::Create(ctx, "loop", fn);
|
ir::basic_block *loop_bb = ir::basic_block::create(ctx, "loop", fn);
|
||||||
BasicBlock *next_bb = BasicBlock::Create(ctx, "postloop", fn);
|
ir::basic_block *next_bb = ir::basic_block::create(ctx, "postloop", fn);
|
||||||
init_->codegen(mod);
|
init_->codegen(mod);
|
||||||
builder.CreateBr(loop_bb);
|
builder.create_br(loop_bb);
|
||||||
builder.SetInsertPoint(loop_bb);
|
builder.set_insert_point(loop_bb);
|
||||||
statements_->codegen(mod);
|
statements_->codegen(mod);
|
||||||
exec_->codegen(mod);
|
exec_->codegen(mod);
|
||||||
Value *cond = stop_->codegen(mod);
|
ir::value *cond = stop_->codegen(mod);
|
||||||
builder.CreateCondBr(cond, loop_bb, next_bb);
|
builder.create_cond_br(cond, loop_bb, next_bb);
|
||||||
builder.SetInsertPoint(next_bb);
|
builder.set_insert_point(next_bb);
|
||||||
mod->seal_block(loop_bb);
|
mod->seal_block(loop_bb);
|
||||||
mod->seal_block(next_bb);
|
mod->seal_block(next_bb);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Selection statement */
|
/* Selection statement */
|
||||||
Value* selection_statement::codegen(module* mod) const{
|
ir::value* selection_statement::codegen(ir::module* mod) const{
|
||||||
IRBuilder<> &builder = mod->builder();
|
ir::builder &builder = mod->get_builder();
|
||||||
LLVMContext &ctx = mod->handle()->getContext();
|
ir::context &ctx = mod->get_context();
|
||||||
Function *fn = builder.GetInsertBlock()->getParent();
|
ir::function *fn = builder.get_insert_block()->get_parent();
|
||||||
Value *cond = cond_->codegen(mod);
|
ir::value *cond = cond_->codegen(mod);
|
||||||
BasicBlock *then_bb = BasicBlock::Create(ctx, "then", fn);
|
ir::basic_block *then_bb = ir::basic_block::create(ctx, "then", fn);
|
||||||
BasicBlock *else_bb = else_value_?BasicBlock::Create(ctx, "else", fn):nullptr;
|
ir::basic_block *else_bb = else_value_?ir::basic_block::create(ctx, "else", fn):nullptr;
|
||||||
BasicBlock *endif_bb = BasicBlock::Create(ctx, "endif", fn);
|
ir::basic_block *endif_bb = ir::basic_block::create(ctx, "endif", fn);
|
||||||
// Branch
|
// Branch
|
||||||
if(else_value_)
|
if(else_value_)
|
||||||
builder.CreateCondBr(cond, then_bb, else_bb);
|
builder.create_cond_br(cond, then_bb, else_bb);
|
||||||
else
|
else
|
||||||
builder.CreateCondBr(cond, then_bb, endif_bb);
|
builder.create_cond_br(cond, then_bb, endif_bb);
|
||||||
// Then
|
// Then
|
||||||
builder.SetInsertPoint(then_bb);
|
builder.set_insert_point(then_bb);
|
||||||
then_value_->codegen(mod);
|
then_value_->codegen(mod);
|
||||||
if(else_value_)
|
if(else_value_)
|
||||||
builder.CreateBr(endif_bb);
|
builder.create_br(endif_bb);
|
||||||
// Else
|
// Else
|
||||||
if(else_value_){
|
if(else_value_){
|
||||||
builder.SetInsertPoint(else_bb);
|
builder.set_insert_point(else_bb);
|
||||||
else_value_->codegen(mod);
|
else_value_->codegen(mod);
|
||||||
builder.CreateBr(endif_bb);
|
builder.create_br(endif_bb);
|
||||||
}
|
}
|
||||||
// Endif
|
// Endif
|
||||||
builder.SetInsertPoint(endif_bb);
|
builder.set_insert_point(endif_bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Declaration */
|
/* Declaration */
|
||||||
Value* declaration::codegen(module* mod) const{
|
ir::value* declaration::codegen(ir::module* mod) const{
|
||||||
for(initializer *init: init_->values())
|
for(initializer *init: init_->values())
|
||||||
init->specifier(spec_);
|
init->specifier(spec_);
|
||||||
init_->codegen(mod);
|
init_->codegen(mod);
|
||||||
@@ -278,7 +176,7 @@ Value* declaration::codegen(module* mod) const{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Initializer */
|
/* Initializer */
|
||||||
Type* initializer::type_impl(module *mod, Type *type) const{
|
ir::type* initializer::type_impl(ir::module *mod, ir::type *type) const{
|
||||||
return decl_->type(mod, type);
|
return decl_->type(mod, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,15 +184,15 @@ void initializer::specifier(const declaration_specifier *spec) {
|
|||||||
spec_ = spec;
|
spec_ = spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* initializer::codegen(module * mod) const{
|
ir::value* initializer::codegen(ir::module * mod) const{
|
||||||
Type *ty = decl_->type(mod, spec_->type(mod));
|
ir::type *ty = decl_->type(mod, spec_->type(mod));
|
||||||
std::string name = decl_->id()->name();
|
std::string name = decl_->id()->name();
|
||||||
Value *value;
|
ir::value *value;
|
||||||
if(expr_)
|
if(expr_)
|
||||||
value = expr_->codegen(mod);
|
value = expr_->codegen(mod);
|
||||||
else
|
else
|
||||||
value = llvm::UndefValue::get(ty);
|
value = ir::undef_value::get(ty);
|
||||||
value->setName(name);
|
value->set_name(name);
|
||||||
mod->set_value(name, value);
|
mod->set_value(name, value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@@ -302,97 +200,87 @@ Value* initializer::codegen(module * mod) const{
|
|||||||
/*------------------*/
|
/*------------------*/
|
||||||
/* Expression */
|
/* Expression */
|
||||||
/*------------------*/
|
/*------------------*/
|
||||||
llvm::Value *llvm_cast(llvm::IRBuilder<> &builder, Value *src, Type *dst_ty){
|
ir::value *llvm_cast(ir::builder &builder, ir::value *src, ir::type *dst_ty){
|
||||||
Type *src_ty = src->getType();
|
ir::type *src_ty = src->get_type();
|
||||||
bool src_signed = false;
|
bool src_signed = false;
|
||||||
bool dst_signed = false;
|
bool dst_signed = false;
|
||||||
if(src_ty == dst_ty)
|
if(src_ty == dst_ty)
|
||||||
return src;
|
return src;
|
||||||
else if(src_ty->isIntegerTy() && src_signed && dst_ty->isFloatingPointTy())
|
else if(src_ty->is_integer_ty() && src_signed && dst_ty->is_floating_point_ty())
|
||||||
return builder.CreateSIToFP(src, dst_ty);
|
return builder.create_si_to_fp(src, dst_ty);
|
||||||
|
|
||||||
else if(src_ty->isIntegerTy() && !src_signed && dst_ty->isFloatingPointTy())
|
else if(src_ty->is_integer_ty() && !src_signed && dst_ty->is_floating_point_ty())
|
||||||
return builder.CreateUIToFP(src, dst_ty);
|
return builder.create_ui_to_fp(src, dst_ty);
|
||||||
|
|
||||||
else if(src_ty->isFloatingPointTy() && dst_ty->isIntegerTy() && dst_signed)
|
else if(src_ty->is_floating_point_ty() && dst_ty->is_integer_ty() && dst_signed)
|
||||||
return builder.CreateFPToSI(src, dst_ty);
|
return builder.create_fp_to_si(src, dst_ty);
|
||||||
|
|
||||||
else if(src_ty->isFloatingPointTy() && dst_ty->isIntegerTy() && !dst_signed)
|
else if(src_ty->is_floating_point_ty() && dst_ty->is_integer_ty() && !dst_signed)
|
||||||
return builder.CreateFPToUI(src, dst_ty);
|
return builder.create_fp_to_ui(src, dst_ty);
|
||||||
|
|
||||||
else if(src_ty->isFloatingPointTy() && dst_ty->isFloatingPointTy() &&
|
else if(src_ty->is_floating_point_ty() && dst_ty->is_floating_point_ty() &&
|
||||||
src_ty->getFPMantissaWidth() < dst_ty->getFPMantissaWidth())
|
src_ty->get_fp_mantissa_width() < dst_ty->get_fp_mantissa_width())
|
||||||
return builder.CreateFPExt(src, dst_ty);
|
return builder.create_fp_ext(src, dst_ty);
|
||||||
|
|
||||||
else if(src_ty->isFloatingPointTy() && dst_ty->isFloatingPointTy() &&
|
else if(src_ty->is_floating_point_ty() && dst_ty->is_floating_point_ty() &&
|
||||||
src_ty->getFPMantissaWidth() > dst_ty->getFPMantissaWidth())
|
src_ty->get_fp_mantissa_width() > dst_ty->get_fp_mantissa_width())
|
||||||
return builder.CreateFPTrunc(src, dst_ty);
|
return builder.create_fp_trunc(src, dst_ty);
|
||||||
|
|
||||||
else if(src_ty->isIntegerTy() && dst_ty->isIntegerTy() &&
|
else if(src_ty->is_integer_ty() && dst_ty->is_integer_ty() &&
|
||||||
src_ty->getIntegerBitWidth())
|
src_ty->get_integer_bit_width())
|
||||||
return builder.CreateIntCast(src, dst_ty, dst_signed);
|
return builder.create_int_cast(src, dst_ty, dst_signed);
|
||||||
|
|
||||||
else{
|
else
|
||||||
assert(false && "unreachable");
|
throw std::runtime_error("unreachable");
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void implicit_cast(llvm::IRBuilder<> &builder, Value *&lhs, Value *&rhs,
|
inline void implicit_cast(ir::builder &builder, ir::value *&lhs, ir::value *&rhs,
|
||||||
bool &is_float, bool &is_ptr, bool &is_int, bool &is_signed){
|
bool &is_float, bool &is_ptr, bool &is_int, bool &is_signed){
|
||||||
// Input types
|
// Input types
|
||||||
Type *left_ty = lhs->getType();
|
ir::type *left_ty = lhs->get_type();
|
||||||
Type *right_ty = rhs->getType();
|
ir::type *right_ty = rhs->get_type();
|
||||||
// One operand is pointer
|
// One operand is pointer
|
||||||
if(left_ty->isPointerTy()){
|
if(left_ty->is_pointer_ty()){
|
||||||
is_ptr = true;
|
is_ptr = true;
|
||||||
}
|
}
|
||||||
// One operand is double
|
// One operand is double
|
||||||
else if(left_ty->isDoubleTy() || right_ty->isDoubleTy()){
|
else if(left_ty->is_double_ty() || right_ty->is_double_ty()){
|
||||||
Value *&to_convert = left_ty->isDoubleTy()?rhs:lhs;
|
ir::value *&to_convert = left_ty->is_double_ty()?rhs:lhs;
|
||||||
to_convert = llvm_cast(builder, to_convert, builder.getDoubleTy());
|
to_convert = llvm_cast(builder, to_convert, builder.get_double_ty());
|
||||||
is_float = true;
|
is_float = true;
|
||||||
}
|
}
|
||||||
// One operand is float
|
// One operand is float
|
||||||
else if(left_ty->isFloatTy() || right_ty->isFloatTy()){
|
else if(left_ty->is_float_ty() || right_ty->is_float_ty()){
|
||||||
Value *&to_convert = left_ty->isFloatTy()?rhs:lhs;
|
ir::value *&to_convert = left_ty->is_float_ty()?rhs:lhs;
|
||||||
to_convert = llvm_cast(builder, to_convert, builder.getFloatTy());
|
to_convert = llvm_cast(builder, to_convert, builder.get_float_ty());
|
||||||
is_float = true;
|
is_float = true;
|
||||||
}
|
}
|
||||||
// Both operands are integers
|
// Both operands are integers
|
||||||
else if(left_ty->isIntegerTy() && right_ty->isIntegerTy()){
|
else if(left_ty->is_integer_ty() && right_ty->is_integer_ty()){
|
||||||
is_int = true;
|
is_int = true;
|
||||||
is_signed = false;
|
is_signed = false;
|
||||||
if(left_ty->getIntegerBitWidth() != right_ty->getIntegerBitWidth()){
|
if(left_ty->get_integer_bit_width() != right_ty->get_integer_bit_width()){
|
||||||
Value *&to_convert = (left_ty->getIntegerBitWidth() > right_ty->getIntegerBitWidth())?rhs:lhs;
|
ir::value *&to_convert = (left_ty->get_integer_bit_width() > right_ty->get_integer_bit_width())?rhs:lhs;
|
||||||
Type *dst_ty = (to_convert==lhs)?right_ty:left_ty;
|
ir::type *dst_ty = (to_convert==lhs)?right_ty:left_ty;
|
||||||
to_convert = llvm_cast(builder, to_convert, dst_ty);
|
to_convert = llvm_cast(builder, to_convert, dst_ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not reachable
|
// Not reachable
|
||||||
else{
|
else
|
||||||
assert(false);
|
throw std::runtime_error("unreachable");
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void implicit_broadcast(module *mod, llvm::IRBuilder<> &builder, Value *&lhs, Value *&rhs){
|
inline void implicit_broadcast(ir::module *mod, ir::builder &builder, ir::value *&lhs, ir::value *&rhs){
|
||||||
std::vector<unsigned> lhs_shapes = array_shapes(lhs->getType());
|
std::vector<unsigned> lhs_shapes = lhs->get_type()->get_tile_shapes();
|
||||||
std::vector<unsigned> rhs_shapes = array_shapes(rhs->getType());
|
std::vector<unsigned> rhs_shapes = rhs->get_type()->get_tile_shapes();
|
||||||
// Both are scalar
|
// Both are scalar
|
||||||
if(lhs_shapes.empty() && rhs_shapes.empty())
|
if(lhs_shapes.empty() && rhs_shapes.empty())
|
||||||
return;
|
return;
|
||||||
// One argument is scalar
|
// One argument is scalar
|
||||||
if(!lhs_shapes.empty() ^ !rhs_shapes.empty()){
|
if(!lhs_shapes.empty() ^ !rhs_shapes.empty()){
|
||||||
auto &ref_shapes = lhs_shapes.empty()?rhs_shapes:lhs_shapes;
|
auto &shapes = lhs_shapes.empty()?rhs_shapes:lhs_shapes;
|
||||||
auto &ref = lhs_shapes.empty()?rhs:lhs;
|
|
||||||
auto &target = lhs_shapes.empty()?lhs:rhs;
|
auto &target = lhs_shapes.empty()?lhs:rhs;
|
||||||
Function *splat_fn = Intrinsic::getDeclaration(mod->handle(), Intrinsic::tlvm_splat_2d, {ref->getType()});
|
target = builder.create_splat(target, shapes);
|
||||||
SmallVector<Value*, 4> args(1 + ref_shapes.size());
|
|
||||||
for(unsigned i = 0; i < ref_shapes.size(); i++)
|
|
||||||
args[1 + i] = builder.getInt32(ref_shapes[i]);
|
|
||||||
args[0] = target;
|
|
||||||
target = builder.CreateCall(splat_fn, args);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Both are arrays
|
// Both are arrays
|
||||||
@@ -407,246 +295,195 @@ inline void implicit_broadcast(module *mod, llvm::IRBuilder<> &builder, Value *&
|
|||||||
throw std::runtime_error("cannot broadcast");
|
throw std::runtime_error("cannot broadcast");
|
||||||
}
|
}
|
||||||
// Pad
|
// Pad
|
||||||
for(size_t i = 0; i < off; i++){
|
for(size_t i = 0; i < off; i++)
|
||||||
shortest.insert(shortest.begin(), 1);
|
shortest.insert(shortest.begin(), 1);
|
||||||
}
|
ir::value *&target = (lhs_dim < rhs_dim)?lhs:rhs;
|
||||||
Value *&target = (lhs_dim < rhs_dim)?lhs:rhs;
|
target = builder.create_reshape(target, shortest);
|
||||||
SmallVector<Value*, 4> args(1 + ndim);
|
// Broadcast
|
||||||
// Reshape left hand side
|
std::vector<unsigned> shapes(ndim);
|
||||||
for(size_t i = 0; i < ndim; i++)
|
for(size_t i = 0; i < ndim; i++)
|
||||||
args[1 + i] = builder.getInt32(shortest[i]);
|
shapes[i] = std::max(shortest[i], longest[i]);
|
||||||
args[0] = target;
|
lhs = builder.create_broadcast(lhs, shapes);
|
||||||
Function *reshape_fn = Intrinsic::getDeclaration(mod->handle(), Intrinsic::tlvm_reshape_2d_1d, {rhs->getType(), lhs->getType()});
|
rhs = builder.create_broadcast(rhs, shapes);
|
||||||
target = builder.CreateCall(reshape_fn, args);
|
|
||||||
// Broadcast both arguments
|
|
||||||
for(size_t i = 0; i < ndim; i++)
|
|
||||||
args[1 + i] = builder.getInt32(std::max(shortest[i], longest[i]));
|
|
||||||
Function *broadcast_fn = Intrinsic::getDeclaration(mod->handle(), Intrinsic::tlvm_broadcast_2d, {target->getType(), target->getType()});
|
|
||||||
// Broadcast lhs
|
|
||||||
args[0] = lhs;
|
|
||||||
lhs = builder.CreateCall(broadcast_fn, args);
|
|
||||||
// Broadcast rhs
|
|
||||||
args[0] = rhs;
|
|
||||||
rhs = builder.CreateCall(broadcast_fn, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Binary operator */
|
/* Binary operator */
|
||||||
Value *binary_operator::llvm_op(module *mod, llvm::IRBuilder<> &builder, Value *lhs, Value *rhs, const std::string &name) const
|
ir::value *binary_operator::llvm_op(ir::module *mod, ir::builder &builder, ir::value *lhs, ir::value *rhs, const std::string &name) const
|
||||||
{
|
{
|
||||||
bool is_float = false, is_ptr = false, is_int = false, is_signed = false;
|
bool is_float = false, is_ptr = false, is_int = false, is_signed = false;
|
||||||
// implicit_cast(builder, lhs, rhs, is_float, is_ptr, is_int, is_signed);
|
// implicit_cast(builder, lhs, rhs, is_float, is_ptr, is_int, is_signed);
|
||||||
// implicit_broadcast(mod, builder, lhs, rhs);
|
// implicit_broadcast(mod, builder, lhs, rhs);
|
||||||
// Mul
|
|
||||||
if(op_==MUL && is_float)
|
if(op_==MUL && is_float)
|
||||||
return builder.CreateFMul(lhs, rhs, name);
|
return builder.create_fmul(lhs, rhs, name);
|
||||||
if(op_==MUL && is_int)
|
if(op_==MUL && is_int)
|
||||||
return builder.CreateMul(lhs, rhs, name);
|
return builder.create_mul(lhs, rhs, name);
|
||||||
// Div
|
|
||||||
if(op_==DIV && is_float)
|
if(op_==DIV && is_float)
|
||||||
return builder.CreateFDiv(lhs, rhs, name);
|
return builder.create_fdiv(lhs, rhs, name);
|
||||||
if(op_==DIV && is_int && is_signed)
|
if(op_==DIV && is_int && is_signed)
|
||||||
return builder.CreateSDiv(lhs, rhs, name);
|
return builder.create_sdiv(lhs, rhs, name);
|
||||||
if(op_==DIV && is_int && !is_signed)
|
if(op_==DIV && is_int && !is_signed)
|
||||||
return builder.CreateUDiv(lhs, rhs, name);
|
return builder.create_udiv(lhs, rhs, name);
|
||||||
// Mod
|
|
||||||
if(op_==MOD && is_float)
|
if(op_==MOD && is_float)
|
||||||
return builder.CreateFRem(lhs, rhs, name);
|
return builder.create_frem(lhs, rhs, name);
|
||||||
if(op_==MOD && is_int && is_signed)
|
if(op_==MOD && is_int && is_signed)
|
||||||
return builder.CreateSRem(lhs, rhs, name);
|
return builder.create_srem(lhs, rhs, name);
|
||||||
if(op_==MOD && is_int && !is_signed)
|
if(op_==MOD && is_int && !is_signed)
|
||||||
return builder.CreateURem(lhs, rhs, name);
|
return builder.create_urem(lhs, rhs, name);
|
||||||
// Add
|
|
||||||
if(op_==ADD && is_float)
|
if(op_==ADD && is_float)
|
||||||
return builder.CreateFAdd(lhs, rhs, name);
|
return builder.create_fadd(lhs, rhs, name);
|
||||||
if(op_==ADD && is_int)
|
if(op_==ADD && is_int)
|
||||||
return builder.CreateAdd(lhs, rhs);
|
return builder.create_add(lhs, rhs);
|
||||||
if(op_==ADD && is_ptr)
|
if(op_==ADD && is_ptr)
|
||||||
return builder.CreateGEP(lhs, {rhs});
|
return builder.create_gep(lhs, {rhs});
|
||||||
// Sub
|
|
||||||
if(op_==SUB && is_float)
|
if(op_==SUB && is_float)
|
||||||
return builder.CreateFSub(lhs, rhs, name);
|
return builder.create_fsub(lhs, rhs, name);
|
||||||
if(op_==SUB && is_int)
|
if(op_==SUB && is_int)
|
||||||
return builder.CreateSub(lhs, rhs, name);
|
return builder.create_sub(lhs, rhs, name);
|
||||||
if(op_==SUB && is_ptr)
|
if(op_==SUB && is_ptr)
|
||||||
return builder.CreateGEP(lhs, {builder.CreateNeg(rhs)});
|
return builder.create_gep(lhs, {builder.create_neg(rhs)});
|
||||||
// Left shift
|
if(op_==LEFT_SHIFT)
|
||||||
if(op_==LEFT_SHIFT){
|
return builder.create_lshr(lhs, rhs, name);
|
||||||
assert(is_int);
|
if(op_==RIGHT_SHIFT)
|
||||||
return builder.CreateLShr(lhs, rhs, name);
|
return builder.create_ashr(lhs, rhs, name);
|
||||||
}
|
|
||||||
// Right shift
|
|
||||||
if(op_==RIGHT_SHIFT){
|
|
||||||
assert(is_int);
|
|
||||||
return builder.CreateAShr(lhs, rhs, name);
|
|
||||||
}
|
|
||||||
// LT
|
|
||||||
if(op_ == LT && is_float)
|
if(op_ == LT && is_float)
|
||||||
return builder.CreateFCmpOLT(lhs, rhs, name);
|
return builder.create_fcmpOLT(lhs, rhs, name);
|
||||||
if(op_ == LT && is_int && is_signed)
|
if(op_ == LT && is_int && is_signed)
|
||||||
return builder.CreateICmpSLT(lhs, rhs, name);
|
return builder.create_icmpSLT(lhs, rhs, name);
|
||||||
if(op_ == LT && is_int && !is_signed)
|
if(op_ == LT && is_int && !is_signed)
|
||||||
return builder.CreateICmpULT(lhs, rhs, name);
|
return builder.create_icmpULT(lhs, rhs, name);
|
||||||
// GT
|
|
||||||
if(op_ == GT && is_float)
|
if(op_ == GT && is_float)
|
||||||
return builder.CreateFCmpOGT(lhs, rhs, name);
|
return builder.create_fcmpOGT(lhs, rhs, name);
|
||||||
if(op_ == GT && is_int && is_signed)
|
if(op_ == GT && is_int && is_signed)
|
||||||
return builder.CreateICmpSGT(lhs, rhs, name);
|
return builder.create_icmpSGT(lhs, rhs, name);
|
||||||
if(op_ == GT && is_int && !is_signed)
|
if(op_ == GT && is_int && !is_signed)
|
||||||
return builder.CreateICmpUGT(lhs, rhs, name);
|
return builder.create_icmpUGT(lhs, rhs, name);
|
||||||
// LE
|
|
||||||
if(op_ == LE && is_float)
|
if(op_ == LE && is_float)
|
||||||
return builder.CreateFCmpOLE(lhs, rhs, name);
|
return builder.create_fcmpOLE(lhs, rhs, name);
|
||||||
if(op_ == LE && is_int && is_signed)
|
if(op_ == LE && is_int && is_signed)
|
||||||
return builder.CreateICmpSLE(lhs, rhs, name);
|
return builder.create_icmpSLE(lhs, rhs, name);
|
||||||
if(op_ == LE && is_int && !is_signed)
|
if(op_ == LE && is_int && !is_signed)
|
||||||
return builder.CreateICmpULE(lhs, rhs, name);
|
return builder.create_icmpULE(lhs, rhs, name);
|
||||||
// GE
|
|
||||||
if(op_ == GE && is_float)
|
if(op_ == GE && is_float)
|
||||||
return builder.CreateFCmpOGE(lhs, rhs, name);
|
return builder.create_fcmpOGE(lhs, rhs, name);
|
||||||
if(op_ == GE && is_int && is_signed)
|
if(op_ == GE && is_int && is_signed)
|
||||||
return builder.CreateICmpSGE(lhs, rhs, name);
|
return builder.create_icmpSGE(lhs, rhs, name);
|
||||||
if(op_ == GE && is_int && !is_signed)
|
if(op_ == GE && is_int && !is_signed)
|
||||||
return builder.CreateICmpUGE(lhs, rhs, name);
|
return builder.create_icmpUGE(lhs, rhs, name);
|
||||||
// EQ
|
|
||||||
if(op_ == EQ && is_float)
|
if(op_ == EQ && is_float)
|
||||||
return builder.CreateFCmpOEQ(lhs, rhs, name);
|
return builder.create_fcmpOEQ(lhs, rhs, name);
|
||||||
if(op_ == EQ && is_int)
|
if(op_ == EQ && is_int)
|
||||||
return builder.CreateICmpEQ(lhs, rhs, name);
|
return builder.create_icmpEQ(lhs, rhs, name);
|
||||||
// NE
|
|
||||||
if(op_ == NE && is_float)
|
if(op_ == NE && is_float)
|
||||||
return builder.CreateFCmpONE(lhs, rhs, name);
|
return builder.create_fcmpONE(lhs, rhs, name);
|
||||||
if(op_ == NE && is_int)
|
if(op_ == NE && is_int)
|
||||||
return builder.CreateICmpNE(lhs, rhs, name);
|
return builder.create_icmpNE(lhs, rhs, name);
|
||||||
// AND
|
if(op_ == AND)
|
||||||
if(op_ == AND){
|
return builder.create_and(lhs, rhs, name);
|
||||||
assert(is_int);
|
if(op_ == XOR)
|
||||||
return builder.CreateAnd(lhs, rhs, name);
|
return builder.create_xor(lhs, rhs, name);
|
||||||
}
|
if(op_ == OR)
|
||||||
if(op_ == XOR){
|
return builder.create_or(lhs, rhs, name);
|
||||||
assert(is_int);
|
if(op_ == LAND)
|
||||||
return builder.CreateXor(lhs, rhs, name);
|
return builder.create_and(lhs, rhs, name);
|
||||||
}
|
if(op_ == LOR)
|
||||||
if(op_ == OR){
|
return builder.create_or(lhs, rhs, name);
|
||||||
assert(is_int);
|
throw std::runtime_error("unreachable");
|
||||||
return builder.CreateOr(lhs, rhs, name);
|
|
||||||
}
|
|
||||||
if(op_ == LAND){
|
|
||||||
assert(is_int);
|
|
||||||
return builder.CreateAnd(lhs, rhs, name);
|
|
||||||
}
|
|
||||||
if(op_ == LOR){
|
|
||||||
assert(is_int);
|
|
||||||
return builder.CreateOr(lhs, rhs, name);
|
|
||||||
}
|
|
||||||
assert(false && "unreachable");
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* binary_operator::codegen(module *mod) const{
|
ir::value* binary_operator::codegen(ir::module *mod) const{
|
||||||
Value *lhs = lhs_->codegen(mod);
|
ir::value *lhs = lhs_->codegen(mod);
|
||||||
Value *rhs = rhs_->codegen(mod);
|
ir::value *rhs = rhs_->codegen(mod);
|
||||||
Value *result = llvm_op(mod, mod->builder(), lhs, rhs, "");
|
ir::value *result = llvm_op(mod, mod->get_builder(), lhs, rhs, "");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Postfix expression */
|
/* Postfix expression */
|
||||||
Value* indexing_expression::codegen(module *mod) const{
|
ir::value* indexing_expression::codegen(ir::module *mod) const{
|
||||||
Value *in = mod->get_value(id_->name());
|
ir::value *in = mod->get_value(id_->name());
|
||||||
std::vector<range_enum_t> ranges;
|
const std::vector<range*> &ranges = ranges_->values();
|
||||||
for(range *x: ranges_->values())
|
std::vector<unsigned> in_shapes = in->get_type()->get_tile_shapes();
|
||||||
ranges.push_back(x->type());
|
std::vector<unsigned> out_shapes(ranges.size());
|
||||||
// Type information
|
size_t current = 0;
|
||||||
Function* reshape;
|
for(size_t i = 0; i < out_shapes.size(); i++)
|
||||||
Type *in_type = in->getType();
|
out_shapes[i] = (ranges[i]->type()==NEWAXIS)?1:in_shapes[current++];
|
||||||
size_t in_dim = in_type->getTileNumDimensions();
|
return mod->get_builder().create_reshape(in, out_shapes);
|
||||||
size_t out_dim = ranges.size();
|
|
||||||
Type *out_type = TileType::get(in_type->getTileElementType(), out_dim);
|
|
||||||
// Intrinsic function
|
|
||||||
Function *reshape_fn = Intrinsic::getDeclaration(mod->handle(), Intrinsic::tlvm_reshape_2d_1d, {out_type, in_type});
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unary operator */
|
/* Unary operator */
|
||||||
Value *unary_operator::llvm_op(llvm::IRBuilder<> &builder, Value *arg, const std::string &name) const{
|
ir::value *unary_operator::llvm_op(ir::builder &builder, ir::value *arg, const std::string &name) const{
|
||||||
Type *atype = arg->getType();
|
ir::type *atype = arg->get_type();
|
||||||
bool is_float = atype->isFloatingPointTy();
|
bool is_float = atype->is_floating_point_ty();
|
||||||
bool is_int = atype->isIntegerTy();
|
bool is_int = atype->is_integer_ty();
|
||||||
if(op_ == INC){
|
if(op_ == INC)
|
||||||
assert(is_int);
|
return builder.create_add(arg, builder.get_int32(1), name);
|
||||||
return builder.CreateAdd(arg, builder.getInt32(1), name);
|
if(op_ == DEC)
|
||||||
}
|
return builder.create_sub(arg, builder.get_int32(1), name);
|
||||||
if(op_ == DEC){
|
|
||||||
assert(is_int);
|
|
||||||
return builder.CreateSub(arg, builder.getInt32(1), name);
|
|
||||||
}
|
|
||||||
if(op_ == PLUS)
|
if(op_ == PLUS)
|
||||||
return arg;
|
return arg;
|
||||||
if(op_ == MINUS && is_float)
|
if(op_ == MINUS && is_float)
|
||||||
return builder.CreateFNeg(arg, name);
|
return builder.create_fneg(arg, name);
|
||||||
if(op_ == MINUS && is_int)
|
if(op_ == MINUS && is_int)
|
||||||
return builder.CreateNeg(arg, name);
|
return builder.create_neg(arg, name);
|
||||||
if(op_ == ADDR)
|
if(op_ == ADDR)
|
||||||
throw std::runtime_error("not supported");
|
throw std::runtime_error("not supported");
|
||||||
if(op_ == DEREF)
|
if(op_ == DEREF)
|
||||||
return builder.CreateLoad(arg, name);
|
return builder.create_load(arg, name);
|
||||||
if(op_ == COMPL)
|
if(op_ == COMPL)
|
||||||
throw std::runtime_error("not supported");
|
throw std::runtime_error("not supported");
|
||||||
if(op_ == NOT)
|
if(op_ == NOT)
|
||||||
return builder.CreateNot(arg, name);
|
return builder.create_not(arg, name);
|
||||||
assert(false && "unrechable");
|
throw std::runtime_error("unreachable");
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* unary_operator::codegen(module *mod) const{
|
ir::value* unary_operator::codegen(ir::module *mod) const{
|
||||||
Value *arg = arg_->codegen(mod);
|
ir::value *arg = arg_->codegen(mod);
|
||||||
Value *result = llvm_op(mod->builder(), arg, "");
|
ir::value *result = llvm_op(mod->get_builder(), arg, "");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Cast operator */
|
/* Cast operator */
|
||||||
Value *cast_operator::llvm_op(IRBuilder<> &builder, Type *T, Value *arg, const std::string &name) const{
|
ir::value *cast_operator::llvm_op(ir::builder &builder, ir::type *T, ir::value *arg, const std::string &name) const{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value* cast_operator::codegen(module *mod) const{
|
ir::value* cast_operator::codegen(ir::module *mod) const{
|
||||||
Value *arg = arg_->codegen(mod);
|
ir::value *arg = arg_->codegen(mod);
|
||||||
Type *T = T_->type(mod);
|
ir::type *T = T_->type(mod);
|
||||||
return llvm_op(mod->builder(), T, arg, "");
|
return llvm_op(mod->get_builder(), T, arg, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Conditional expression */
|
/* Conditional expression */
|
||||||
Value *conditional_expression::llvm_op(IRBuilder<> &builder, Value *cond, Value *true_value, Value *false_value, const std::string &name) const{
|
ir::value *conditional_expression::llvm_op(ir::builder &builder, ir::value *cond, ir::value *true_value, ir::value *false_value, const std::string &name) const{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *conditional_expression::codegen(module *mod) const{
|
ir::value *conditional_expression::codegen(ir::module *mod) const{
|
||||||
Value *cond = cond_->codegen(mod);
|
ir::value *cond = cond_->codegen(mod);
|
||||||
Value *true_value = true_value_->codegen(mod);
|
ir::value *true_value = true_value_->codegen(mod);
|
||||||
Value *false_value = false_value_->codegen(mod);
|
ir::value *false_value = false_value_->codegen(mod);
|
||||||
return llvm_op(mod->builder(), cond, true_value, false_value, "");
|
return llvm_op(mod->get_builder(), cond, true_value, false_value, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assignment expression */
|
/* Assignment expression */
|
||||||
Value *assignment_expression::codegen(module *mod) const{
|
ir::value *assignment_expression::codegen(ir::module *mod) const{
|
||||||
Value *rvalue = rvalue_->codegen(mod);
|
ir::value *rvalue = rvalue_->codegen(mod);
|
||||||
mod->set_value(lvalue_->id()->name(), rvalue);
|
mod->set_value(lvalue_->id()->name(), rvalue);
|
||||||
return rvalue;
|
return rvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Type name */
|
/* Type name */
|
||||||
llvm::Type *type_name::type(module *mod) const{
|
ir::type *type_name::type(ir::module *mod) const{
|
||||||
return decl_->type(mod, spec_->type(mod));
|
return decl_->type(mod, spec_->type(mod));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* String literal */
|
/* String literal */
|
||||||
llvm::Value* string_literal::codegen(module *mod) const{
|
ir::value* string_literal::codegen(ir::module *mod) const{
|
||||||
return ConstantDataArray::getString(mod->handle()->getContext(), value_);
|
return ir::constant_data_array::get_string(mod->get_context(), value_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Constant */
|
/* Constant */
|
||||||
llvm::Value* constant::codegen(module *mod) const{
|
ir::value* constant::codegen(ir::module *mod) const{
|
||||||
return mod->builder().getInt32(value_);
|
return mod->get_builder().get_int32(value_);
|
||||||
}
|
}
|
||||||
|
|
||||||
int constant::value() const{
|
int constant::value() const{
|
||||||
@@ -660,7 +497,7 @@ const identifier* unary_expression::id() const{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Named */
|
/* Named */
|
||||||
llvm::Value* named_expression::codegen(module *mod) const{
|
ir::value* named_expression::codegen(ir::module *mod) const{
|
||||||
const std::string &name = id()->name();
|
const std::string &name = id()->name();
|
||||||
return mod->get_value(name);
|
return mod->get_value(name);
|
||||||
}
|
}
|
||||||
|
0
lib/ir/basic_block.cpp
Normal file
0
lib/ir/basic_block.cpp
Normal file
0
lib/ir/builder.cpp
Normal file
0
lib/ir/builder.cpp
Normal file
0
lib/ir/constant.cpp
Normal file
0
lib/ir/constant.cpp
Normal file
10
lib/ir/context.cpp
Normal file
10
lib/ir/context.cpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include "ir/context.h"
|
||||||
|
|
||||||
|
namespace tdl{
|
||||||
|
namespace ir{
|
||||||
|
|
||||||
|
/* Context */
|
||||||
|
context::context() { }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
0
lib/ir/function.cpp
Normal file
0
lib/ir/function.cpp
Normal file
0
lib/ir/instructions.cpp
Normal file
0
lib/ir/instructions.cpp
Normal file
0
lib/ir/ir.cpp
Normal file
0
lib/ir/ir.cpp
Normal file
87
lib/ir/module.cpp
Normal file
87
lib/ir/module.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#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()) {
|
||||||
|
sealed_blocks_.insert(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Module* module::handle() {
|
||||||
|
return &handle_;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRBuilder<>& module::builder() {
|
||||||
|
return builder_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void module::set_value(const std::string& name, BasicBlock *block, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
PHINode* module::make_phi(Type *type, unsigned num_values, BasicBlock *block){
|
||||||
|
Instruction* instr = block->getFirstNonPHIOrDbg();
|
||||||
|
if(instr)
|
||||||
|
builder_.SetInsertPoint(instr);
|
||||||
|
PHINode *res = builder_.CreatePHI(type, num_values);
|
||||||
|
if(instr)
|
||||||
|
builder_.SetInsertPoint(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);
|
||||||
|
}
|
||||||
|
return phi;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *module::get_value_recursive(const std::string& name, BasicBlock *block) {
|
||||||
|
Value *result;
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
else if(pred_size(block) <= 1){
|
||||||
|
bool has_pred = pred_size(block);
|
||||||
|
result = get_value(name, has_pred?*pred_begin(block):nullptr);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
Value *pred = get_value(name, *pred_begin(block));
|
||||||
|
result = make_phi(pred->getType(), 1, block);
|
||||||
|
set_value(name, block, result);
|
||||||
|
add_phi_operands(name, (PHINode*&)result);
|
||||||
|
}
|
||||||
|
set_value(name, block, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *module::get_value(const std::string& name, BasicBlock *block) {
|
||||||
|
val_key_t key(name, block);
|
||||||
|
if(values_.find(key) != values_.end()){
|
||||||
|
return values_.at(key);
|
||||||
|
}
|
||||||
|
return get_value_recursive(name, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *module::get_value(const std::string& name) {
|
||||||
|
return get_value(name, builder_.GetInsertBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *module::seal_block(BasicBlock *block){
|
||||||
|
for(auto &x: incomplete_phis_[block])
|
||||||
|
add_phi_operands(x.first, x.second);
|
||||||
|
sealed_blocks_.insert(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
0
lib/ir/type.cpp
Normal file
0
lib/ir/type.cpp
Normal file
Reference in New Issue
Block a user