Commit da409e47 authored by lxq's avatar lxq

Merge branch 'lab2-publish'

parent 690006c6
BasedOnStyle: LLVM
IndentWidth: 4
\ No newline at end of file
build/
.cache/
.vscode
.DS_store
\ No newline at end of file
......@@ -51,3 +51,4 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_BINARY_DIR})
add_subdirectory(src)
add_subdirectory(tests)
......@@ -7,19 +7,5 @@
## 测试脚本使用方法
eval_phase1.sh: 测试phase1 词法分析器+语法分析器部分
-all: 测试所有测试集 (easy, normal, hard, testcases_general)
easy/normal/hard/testcases_general + yes/no/verbose: 测试单个测试集
yes: 使用diff判断正确性
no: 不使用diff判断正确性
verbose: 使用diff判断正确性,并看到更详细的输出
eval_phase2.sh: 测试phase2 syntax_tree -> ast 部分
使用方法与eval_phase1.sh完全相同, 会自动跳过生成syntax_tree fail的样例
\ No newline at end of file
eval_lab2.sh:
没有参数,直接运行即可,结果会生成在 eval_result 下
\ No newline at end of file
#pragma once
#include "BasicBlock.hpp"
#include "Constant.hpp"
#include "Function.hpp"
#include "IRBuilder.hpp"
#include "Module.hpp"
#include "Type.hpp"
#include "ast.hpp"
#include <map>
#include <memory>
class Scope {
public:
// enter a new scope
void enter() { inner.emplace_back(); }
// exit a scope
void exit() { inner.pop_back(); }
bool in_global() { return inner.size() == 1; }
// push a name to scope
// return true if successful
// return false if this name already exits
bool push(const std::string& name, Value *val) {
auto result = inner[inner.size() - 1].insert({name, val});
return result.second;
}
Value *find(const std::string& name) {
for (auto s = inner.rbegin(); s != inner.rend(); s++) {
auto iter = s->find(name);
if (iter != s->end()) {
return iter->second;
}
}
// Name not found: handled here?
assert(false && "Name not found in scope");
return nullptr;
}
private:
std::vector<std::map<std::string, Value *>> inner;
};
class CminusfBuilder : public ASTVisitor {
public:
CminusfBuilder() {
module = std::make_unique<Module>();
builder = std::make_unique<IRBuilder>(nullptr, module.get());
auto *TyVoid = module->get_void_type();
auto *TyInt32 = module->get_int32_type();
auto *TyFloat = module->get_float_type();
auto *input_type = FunctionType::get(TyInt32, {});
auto *input_fun = Function::create(input_type, "input", module.get());
std::vector<Type *> output_params;
output_params.push_back(TyInt32);
auto *output_type = FunctionType::get(TyVoid, output_params);
auto *output_fun = Function::create(output_type, "output", module.get());
std::vector<Type *> output_float_params;
output_float_params.push_back(TyFloat);
auto *output_float_type = FunctionType::get(TyVoid, output_float_params);
auto *output_float_fun =
Function::create(output_float_type, "outputFloat", module.get());
auto *neg_idx_except_type = FunctionType::get(TyVoid, {});
auto *neg_idx_except_fun = Function::create(
neg_idx_except_type, "neg_idx_except", module.get());
scope.enter();
scope.push("input", input_fun);
scope.push("output", output_fun);
scope.push("outputFloat", output_float_fun);
scope.push("neg_idx_except", neg_idx_except_fun);
}
std::unique_ptr<Module> getModule() { return std::move(module); }
private:
virtual Value *visit(ASTProgram &) override final;
virtual Value *visit(ASTNum &) override final;
virtual Value *visit(ASTVarDeclaration &) override final;
virtual Value *visit(ASTFunDeclaration &) override final;
virtual Value *visit(ASTParam &) override final;
virtual Value *visit(ASTCompoundStmt &) override final;
virtual Value *visit(ASTExpressionStmt &) override final;
virtual Value *visit(ASTSelectionStmt &) override final;
virtual Value *visit(ASTIterationStmt &) override final;
virtual Value *visit(ASTReturnStmt &) override final;
virtual Value *visit(ASTAssignExpression &) override final;
virtual Value *visit(ASTSimpleExpression &) override final;
virtual Value *visit(ASTAdditiveExpression &) override final;
virtual Value *visit(ASTVar &) override final;
virtual Value *visit(ASTTerm &) override final;
virtual Value *visit(ASTCall &) override final;
std::unique_ptr<IRBuilder> builder;
Scope scope;
std::unique_ptr<Module> module;
struct {
// function that is being built
Function *func = nullptr;
// TODO: you should add more fields to store state
} context;
};
#pragma once
#include <cstdarg>
extern "C" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char *input);
}
#include "User.hpp"
#include <memory>
#include <string>
#include <vector>
......@@ -83,12 +85,12 @@ class AST {
};
struct ASTNode {
virtual void accept(ASTVisitor &) = 0;
virtual Value* accept(ASTVisitor &) = 0;
virtual ~ASTNode() = default;
};
struct ASTProgram : ASTNode {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
virtual ~ASTProgram() = default;
std::vector<std::shared_ptr<ASTDeclaration>> declarations;
};
......@@ -104,7 +106,7 @@ struct ASTFactor : ASTNode {
};
struct ASTNum : ASTFactor {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
CminusType type;
union {
int i_val;
......@@ -113,18 +115,18 @@ struct ASTNum : ASTFactor {
};
struct ASTVarDeclaration : ASTDeclaration {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTNum> num;
};
struct ASTFunDeclaration : ASTDeclaration {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::vector<std::shared_ptr<ASTParam>> params;
std::shared_ptr<ASTCompoundStmt> compound_stmt;
};
struct ASTParam : ASTNode {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
CminusType type;
std::string id;
// true if it is array param
......@@ -136,18 +138,18 @@ struct ASTStatement : ASTNode {
};
struct ASTCompoundStmt : ASTStatement {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::vector<std::shared_ptr<ASTVarDeclaration>> local_declarations;
std::vector<std::shared_ptr<ASTStatement>> statement_list;
};
struct ASTExpressionStmt : ASTStatement {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTExpression> expression;
};
struct ASTSelectionStmt : ASTStatement {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTExpression> expression;
std::shared_ptr<ASTStatement> if_statement;
// should be nullptr if no else structure exists
......@@ -155,13 +157,13 @@ struct ASTSelectionStmt : ASTStatement {
};
struct ASTIterationStmt : ASTStatement {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTExpression> expression;
std::shared_ptr<ASTStatement> statement;
};
struct ASTReturnStmt : ASTStatement {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
// should be nullptr if return void
std::shared_ptr<ASTExpression> expression;
};
......@@ -169,83 +171,83 @@ struct ASTReturnStmt : ASTStatement {
struct ASTExpression : ASTFactor {};
struct ASTAssignExpression : ASTExpression {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTVar> var;
std::shared_ptr<ASTExpression> expression;
};
struct ASTSimpleExpression : ASTExpression {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTAdditiveExpression> additive_expression_l;
std::shared_ptr<ASTAdditiveExpression> additive_expression_r;
RelOp op;
};
struct ASTVar : ASTFactor {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::string id;
// nullptr if var is of int type
std::shared_ptr<ASTExpression> expression;
};
struct ASTAdditiveExpression : ASTNode {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTAdditiveExpression> additive_expression;
AddOp op;
std::shared_ptr<ASTTerm> term;
};
struct ASTTerm : ASTNode {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTTerm> term;
MulOp op;
std::shared_ptr<ASTFactor> factor;
};
struct ASTCall : ASTFactor {
virtual void accept(ASTVisitor &) override final;
virtual Value* accept(ASTVisitor &) override final;
std::string id;
std::vector<std::shared_ptr<ASTExpression>> args;
};
class ASTVisitor {
public:
virtual void visit(ASTProgram &) = 0;
virtual void visit(ASTNum &) = 0;
virtual void visit(ASTVarDeclaration &) = 0;
virtual void visit(ASTFunDeclaration &) = 0;
virtual void visit(ASTParam &) = 0;
virtual void visit(ASTCompoundStmt &) = 0;
virtual void visit(ASTExpressionStmt &) = 0;
virtual void visit(ASTSelectionStmt &) = 0;
virtual void visit(ASTIterationStmt &) = 0;
virtual void visit(ASTReturnStmt &) = 0;
virtual void visit(ASTAssignExpression &) = 0;
virtual void visit(ASTSimpleExpression &) = 0;
virtual void visit(ASTAdditiveExpression &) = 0;
virtual void visit(ASTVar &) = 0;
virtual void visit(ASTTerm &) = 0;
virtual void visit(ASTCall &) = 0;
virtual Value* visit(ASTProgram &) = 0;
virtual Value* visit(ASTNum &) = 0;
virtual Value* visit(ASTVarDeclaration &) = 0;
virtual Value* visit(ASTFunDeclaration &) = 0;
virtual Value* visit(ASTParam &) = 0;
virtual Value* visit(ASTCompoundStmt &) = 0;
virtual Value* visit(ASTExpressionStmt &) = 0;
virtual Value* visit(ASTSelectionStmt &) = 0;
virtual Value* visit(ASTIterationStmt &) = 0;
virtual Value* visit(ASTReturnStmt &) = 0;
virtual Value* visit(ASTAssignExpression &) = 0;
virtual Value* visit(ASTSimpleExpression &) = 0;
virtual Value* visit(ASTAdditiveExpression &) = 0;
virtual Value* visit(ASTVar &) = 0;
virtual Value* visit(ASTTerm &) = 0;
virtual Value* visit(ASTCall &) = 0;
};
class ASTPrinter : public ASTVisitor {
public:
virtual void visit(ASTProgram &) override final;
virtual void visit(ASTNum &) override final;
virtual void visit(ASTVarDeclaration &) override final;
virtual void visit(ASTFunDeclaration &) override final;
virtual void visit(ASTParam &) override final;
virtual void visit(ASTCompoundStmt &) override final;
virtual void visit(ASTExpressionStmt &) override final;
virtual void visit(ASTSelectionStmt &) override final;
virtual void visit(ASTIterationStmt &) override final;
virtual void visit(ASTReturnStmt &) override final;
virtual void visit(ASTAssignExpression &) override final;
virtual void visit(ASTSimpleExpression &) override final;
virtual void visit(ASTAdditiveExpression &) override final;
virtual void visit(ASTVar &) override final;
virtual void visit(ASTTerm &) override final;
virtual void visit(ASTCall &) override final;
virtual Value* visit(ASTProgram &) override final;
virtual Value* visit(ASTNum &) override final;
virtual Value* visit(ASTVarDeclaration &) override final;
virtual Value* visit(ASTFunDeclaration &) override final;
virtual Value* visit(ASTParam &) override final;
virtual Value* visit(ASTCompoundStmt &) override final;
virtual Value* visit(ASTExpressionStmt &) override final;
virtual Value* visit(ASTSelectionStmt &) override final;
virtual Value* visit(ASTIterationStmt &) override final;
virtual Value* visit(ASTReturnStmt &) override final;
virtual Value* visit(ASTAssignExpression &) override final;
virtual Value* visit(ASTSimpleExpression &) override final;
virtual Value* visit(ASTAdditiveExpression &) override final;
virtual Value* visit(ASTVar &) override final;
virtual Value* visit(ASTTerm &) override final;
virtual Value* visit(ASTCall &) override final;
void add_depth() { depth += 2; }
void remove_depth() { depth -= 2; }
......
#ifndef LOGGING_HPP
#define LOGGING_HPP
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <cstdlib>
enum LogLevel
{
DEBUG = 0,
INFO,
WARNING,
ERROR
};
struct LocationInfo
{
LocationInfo(std::string file, int line, const char *func) : file_(file), line_(line), func_(func) {}
enum LogLevel { DEBUG = 0, INFO, WARNING, ERROR };
struct LocationInfo {
LocationInfo(std::string file, int line, const char *func)
: file_(file), line_(line), func_(func) {}
~LocationInfo() = default;
std::string file_;
......@@ -24,46 +18,38 @@ struct LocationInfo
class LogStream;
class LogWriter;
class LogWriter
{
public:
class LogWriter {
public:
LogWriter(LocationInfo location, LogLevel loglevel)
: location_(location), log_level_(loglevel)
{
: location_(location), log_level_(loglevel) {
char *logv = std::getenv("LOGV");
if (logv)
{
if (logv) {
std::string string_logv = logv;
env_log_level = std::stoi(logv);
}
else
{
} else {
env_log_level = 4;
}
};
void operator<(const LogStream &stream);
private:
private:
void output_log(const std::ostringstream &g);
LocationInfo location_;
LogLevel log_level_;
int env_log_level;
};
class LogStream
{
public:
template <typename T>
LogStream &operator<<(const T &val) noexcept
{
class LogStream {
public:
template <typename T> LogStream &operator<<(const T &val) noexcept {
sstream_ << val;
return *this;
}
friend class LogWriter;
private:
private:
std::stringstream sstream_{};
};
......@@ -72,7 +58,8 @@ std::string get_short_name(const char *file_path);
#define __FILESHORTNAME__ get_short_name(__FILE__)
#define LOG_IF(level) \
LogWriter(LocationInfo(__FILESHORTNAME__, __LINE__, __FUNCTION__), level) < LogStream()
LogWriter(LocationInfo(__FILESHORTNAME__, __LINE__, __FUNCTION__), \
level) < LogStream()
#define LOG(level) LOG_##level
#define LOG_DEBUG LOG_IF(DEBUG)
#define LOG_INFO LOG_IF(INFO)
......
......@@ -6,26 +6,26 @@
#define SYNTAX_TREE_NODE_NAME_MAX 30
struct _syntax_tree_node {
struct _syntax_tree_node * parent;
struct _syntax_tree_node * children[10];
struct _syntax_tree_node *parent;
struct _syntax_tree_node *children[10];
int children_num;
char name[SYNTAX_TREE_NODE_NAME_MAX];
};
typedef struct _syntax_tree_node syntax_tree_node;
syntax_tree_node * new_anon_syntax_tree_node();
syntax_tree_node * new_syntax_tree_node(const char * name);
int syntax_tree_add_child(syntax_tree_node * parent, syntax_tree_node * child);
void del_syntax_tree_node(syntax_tree_node * node, int recursive);
syntax_tree_node *new_anon_syntax_tree_node();
syntax_tree_node *new_syntax_tree_node(const char *name);
int syntax_tree_add_child(syntax_tree_node *parent, syntax_tree_node *child);
void del_syntax_tree_node(syntax_tree_node *node, int recursive);
struct _syntax_tree {
syntax_tree_node * root;
syntax_tree_node *root;
};
typedef struct _syntax_tree syntax_tree;
syntax_tree* new_syntax_tree();
void del_syntax_tree(syntax_tree * tree);
void print_syntax_tree(FILE * fout, syntax_tree * tree);
syntax_tree *new_syntax_tree();
void del_syntax_tree(syntax_tree *tree);
void print_syntax_tree(FILE *fout, syntax_tree *tree);
#endif /* SyntaxTree.h */
#pragma once
#include "Instruction.hpp"
#include "Value.hpp"
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <set>
#include <string>
class Function;
class Instruction;
class Module;
class BasicBlock : public Value, public llvm::ilist_node<BasicBlock> {
public:
~BasicBlock() = default;
static BasicBlock *create(Module *m, const std::string &name,
Function *parent) {
auto prefix = name.empty() ? "" : "label_";
return new BasicBlock(m, prefix + name, parent);
}
/****************api about cfg****************/
std::list<BasicBlock *> &get_pre_basic_blocks() { return pre_bbs_; }
std::list<BasicBlock *> &get_succ_basic_blocks() { return succ_bbs_; }
void add_pre_basic_block(BasicBlock *bb) { pre_bbs_.push_back(bb); }
void add_succ_basic_block(BasicBlock *bb) { succ_bbs_.push_back(bb); }
void remove_pre_basic_block(BasicBlock *bb) { pre_bbs_.remove(bb); }
void remove_succ_basic_block(BasicBlock *bb) { succ_bbs_.remove(bb); }
// If the Block is terminated by ret/br
bool is_terminated() const;
// Get terminator, only accept valid case use
Instruction *get_terminator();
/****************api about Instruction****************/
void add_instruction(Instruction *instr);
void add_instr_begin(Instruction *instr) { instr_list_.push_front(instr); }
void erase_instr(Instruction *instr) { instr_list_.erase(instr); }
void remove_instr(Instruction *instr) { instr_list_.remove(instr); }
llvm::ilist<Instruction> &get_instructions() { return instr_list_; }
bool empty() const { return instr_list_.empty(); }
int get_num_of_instr() const { return instr_list_.size(); }
/****************api about accessing parent****************/
Function *get_parent() { return parent_; }
Module *get_module();
void erase_from_parent();
virtual std::string print() override;
private:
BasicBlock(const BasicBlock &) = delete;
explicit BasicBlock(Module *m, const std::string &name, Function *parent);
std::list<BasicBlock *> pre_bbs_;
std::list<BasicBlock *> succ_bbs_;
llvm::ilist<Instruction> instr_list_;
Function *parent_;
};
#pragma once
#include "Type.hpp"
#include "User.hpp"
#include "Value.hpp"
class Constant : public User {
private:
// int value;
public:
Constant(Type *ty, const std::string &name = "") : User(ty, name) {}
~Constant() = default;
};
class ConstantInt : public Constant {
private:
int value_;
ConstantInt(Type *ty, int val) : Constant(ty, ""), value_(val) {}
public:
int get_value() { return value_; }
static ConstantInt *get(int val, Module *m);
static ConstantInt *get(bool val, Module *m);
virtual std::string print() override;
};
class ConstantArray : public Constant {
private:
std::vector<Constant *> const_array;
ConstantArray(ArrayType *ty, const std::vector<Constant *> &val);
public:
~ConstantArray() = default;
Constant *get_element_value(int index);
unsigned get_size_of_array() { return const_array.size(); }
static ConstantArray *get(ArrayType *ty,
const std::vector<Constant *> &val);
virtual std::string print() override;
};
class ConstantZero : public Constant {
private:
ConstantZero(Type *ty) : Constant(ty, "") {}
public:
static ConstantZero *get(Type *ty, Module *m);
virtual std::string print() override;
};
class ConstantFP : public Constant {
private:
float val_;
ConstantFP(Type *ty, float val) : Constant(ty, ""), val_(val) {}
public:
static ConstantFP *get(float val, Module *m);
float get_value() { return val_; }
virtual std::string print() override;
};
#pragma once
#include "BasicBlock.hpp"
#include "Type.hpp"
#include "User.hpp"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <map>
#include <memory>
class Module;
class Argument;
class Type;
class FunctionType;
class Function : public Value, public llvm::ilist_node<Function> {
public:
Function(const Function &) = delete;
Function(FunctionType *ty, const std::string &name, Module *parent);
~Function() = default;
static Function *create(FunctionType *ty, const std::string &name,
Module *parent);
FunctionType *get_function_type() const;
Type *get_return_type() const;
void add_basic_block(BasicBlock *bb);
unsigned get_num_of_args() const;
unsigned get_num_basic_blocks() const;
Module *get_parent() const;
void remove(BasicBlock *bb);
BasicBlock *get_entry_block() { return &*basic_blocks_.begin(); }
llvm::ilist<BasicBlock> &get_basic_blocks() { return basic_blocks_; }
std::list<Argument> &get_args() { return arguments_; }
bool is_declaration() { return basic_blocks_.empty(); }
void set_instr_name();
std::string print();
private:
llvm::ilist<BasicBlock> basic_blocks_;
std::list<Argument> arguments_;
Module *parent_;
unsigned seq_cnt_; // print use
};
// Argument of Function, does not contain actual value
class Argument : public Value {
public:
Argument(const Argument &) = delete;
explicit Argument(Type *ty, const std::string &name = "",
Function *f = nullptr, unsigned arg_no = 0)
: Value(ty, name), parent_(f), arg_no_(arg_no) {}
virtual ~Argument() {}
inline const Function *get_parent() const { return parent_; }
inline Function *get_parent() { return parent_; }
/// For example in "void foo(int a, float b)" a is 0 and b is 1.
unsigned get_arg_no() const {
assert(parent_ && "can't get number of unparented arg");
return arg_no_;
}
virtual std::string print() override;
private:
Function *parent_;
unsigned arg_no_; // argument No.
};
#pragma once
#include "Constant.hpp"
#include "User.hpp"
#include <llvm/ADT/ilist_node.h>
class Module;
class GlobalVariable : public User, public llvm::ilist_node<GlobalVariable> {
private:
bool is_const_;
Constant *init_val_;
GlobalVariable(std::string name, Module *m, Type *ty, bool is_const,
Constant *init = nullptr);
public:
GlobalVariable(const GlobalVariable &) = delete;
static GlobalVariable *create(std::string name, Module *m, Type *ty,
bool is_const, Constant *init);
virtual ~GlobalVariable() = default;
Constant *get_init() { return init_val_; }
bool is_const() { return is_const_; }
std::string print();
};
#pragma once
#include "BasicBlock.hpp"
#include "Function.hpp"
#include "Instruction.hpp"
#include "Value.hpp"
class IRBuilder {
private:
BasicBlock *BB_;
Module *m_;
public:
IRBuilder(BasicBlock *bb, Module *m) : BB_(bb), m_(m){};
~IRBuilder() = default;
Module *get_module() { return m_; }
BasicBlock *get_insert_block() { return this->BB_; }
void set_insert_point(BasicBlock *bb) {
this->BB_ = bb;
} // 在某个基本块中插入指令
IBinaryInst *create_iadd(Value *lhs, Value *rhs) {
return IBinaryInst::create_add(lhs, rhs, this->BB_);
} // 创建加法指令(以及其他算术指令)
IBinaryInst *create_isub(Value *lhs, Value *rhs) {
return IBinaryInst::create_sub(lhs, rhs, this->BB_);
}
IBinaryInst *create_imul(Value *lhs, Value *rhs) {
return IBinaryInst::create_mul(lhs, rhs, this->BB_);
}
IBinaryInst *create_isdiv(Value *lhs, Value *rhs) {
return IBinaryInst::create_sdiv(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_eq(Value *lhs, Value *rhs) {
return ICmpInst::create_eq(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_ne(Value *lhs, Value *rhs) {
return ICmpInst::create_ne(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_gt(Value *lhs, Value *rhs) {
return ICmpInst::create_gt(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_ge(Value *lhs, Value *rhs) {
return ICmpInst::create_ge(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_lt(Value *lhs, Value *rhs) {
return ICmpInst::create_lt(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_le(Value *lhs, Value *rhs) {
return ICmpInst::create_le(lhs, rhs, this->BB_);
}
CallInst *create_call(Value *func, std::vector<Value *> args) {
return CallInst::create_call(static_cast<Function *>(func), args,
this->BB_);
}
BranchInst *create_br(BasicBlock *if_true) {
return BranchInst::create_br(if_true, this->BB_);
}
BranchInst *create_cond_br(Value *cond, BasicBlock *if_true,
BasicBlock *if_false) {
return BranchInst::create_cond_br(cond, if_true, if_false, this->BB_);
}
ReturnInst *create_ret(Value *val) {
return ReturnInst::create_ret(val, this->BB_);
}
ReturnInst *create_void_ret() {
return ReturnInst::create_void_ret(this->BB_);
}
GetElementPtrInst *create_gep(Value *ptr, std::vector<Value *> idxs) {
return GetElementPtrInst::create_gep(ptr, idxs, this->BB_);
}
StoreInst *create_store(Value *val, Value *ptr) {
return StoreInst::create_store(val, ptr, this->BB_);
}
LoadInst *create_load(Value *ptr) {
assert(ptr->get_type()->is_pointer_type() &&
"ptr must be pointer type");
return LoadInst::create_load(ptr, this->BB_);
}
AllocaInst *create_alloca(Type *ty) {
return AllocaInst::create_alloca(ty, this->BB_);
}
ZextInst *create_zext(Value *val, Type *ty) {
return ZextInst::create_zext(val, ty, this->BB_);
}
SiToFpInst *create_sitofp(Value *val, Type *ty) {
return SiToFpInst::create_sitofp(val, this->BB_);
}
FpToSiInst *create_fptosi(Value *val, Type *ty) {
return FpToSiInst::create_fptosi(val, ty, this->BB_);
}
FCmpInst *create_fcmp_ne(Value *lhs, Value *rhs) {
return FCmpInst::create_fne(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_lt(Value *lhs, Value *rhs) {
return FCmpInst::create_flt(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_le(Value *lhs, Value *rhs) {
return FCmpInst::create_fle(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_ge(Value *lhs, Value *rhs) {
return FCmpInst::create_fge(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_gt(Value *lhs, Value *rhs) {
return FCmpInst::create_fgt(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_eq(Value *lhs, Value *rhs) {
return FCmpInst::create_feq(lhs, rhs, this->BB_);
}
FBinaryInst *create_fadd(Value *lhs, Value *rhs) {
return FBinaryInst::create_fadd(lhs, rhs, this->BB_);
}
FBinaryInst *create_fsub(Value *lhs, Value *rhs) {
return FBinaryInst::create_fsub(lhs, rhs, this->BB_);
}
FBinaryInst *create_fmul(Value *lhs, Value *rhs) {
return FBinaryInst::create_fmul(lhs, rhs, this->BB_);
}
FBinaryInst *create_fdiv(Value *lhs, Value *rhs) {
return FBinaryInst::create_fdiv(lhs, rhs, this->BB_);
}
};
#pragma once
#include "BasicBlock.hpp"
#include "Constant.hpp"
#include "Function.hpp"
#include "GlobalVariable.hpp"
#include "Instruction.hpp"
#include "Module.hpp"
#include "Type.hpp"
#include "User.hpp"
#include "Value.hpp"
std::string print_as_op(Value *v, bool print_ty);
std::string print_instr_op_name(Instruction::OpID);
#pragma once
#include "Type.hpp"
#include "User.hpp"
#include <cstdint>
#include <llvm/ADT/ilist_node.h>
class BasicBlock;
class Function;
class Instruction : public User, public llvm::ilist_node<Instruction> {
public:
enum OpID : uint32_t {
// Terminator Instructions
ret,
br,
// Standard binary operators
add,
sub,
mul,
sdiv,
// float binary operators
fadd,
fsub,
fmul,
fdiv,
// Memory operators
alloca,
load,
store,
// Int compare operators
ge,
gt,
le,
lt,
eq,
ne,
// Float compare operators
fge,
fgt,
fle,
flt,
feq,
fne,
// Other operators
phi,
call,
getelementptr,
zext, // zero extend
fptosi,
sitofp
// float binary operators Logical operators
};
/* @parent: if parent!=nullptr, auto insert to bb
* @ty: result type */
Instruction(Type *ty, OpID id, BasicBlock *parent = nullptr);
Instruction(const Instruction &) = delete;
virtual ~Instruction() = default;
BasicBlock *get_parent() { return parent_; }
const BasicBlock *get_parent() const { return parent_; }
void set_parent(BasicBlock *parent) { this->parent_ = parent; }
// Return the function this instruction belongs to.
Function *get_function();
Module *get_module();
OpID get_instr_type() const { return op_id_; }
std::string get_instr_op_name() const;
bool is_void() {
return ((op_id_ == ret) || (op_id_ == br) || (op_id_ == store) ||
(op_id_ == call && this->get_type()->is_void_type()));
}
bool is_phi() const { return op_id_ == phi; }
bool is_store() const { return op_id_ == store; }
bool is_alloca() const { return op_id_ == alloca; }
bool is_ret() const { return op_id_ == ret; }
bool is_load() const { return op_id_ == load; }
bool is_br() const { return op_id_ == br; }
bool is_add() const { return op_id_ == add; }
bool is_sub() const { return op_id_ == sub; }
bool is_mul() const { return op_id_ == mul; }
bool is_div() const { return op_id_ == sdiv; }
bool is_fadd() const { return op_id_ == fadd; }
bool is_fsub() const { return op_id_ == fsub; }
bool is_fmul() const { return op_id_ == fmul; }
bool is_fdiv() const { return op_id_ == fdiv; }
bool is_fp2si() const { return op_id_ == fptosi; }
bool is_si2fp() const { return op_id_ == sitofp; }
bool is_cmp() const { return ge <= op_id_ and op_id_ <= ne; }
bool is_fcmp() const { return fge <= op_id_ and op_id_ <= fne; }
bool is_call() const { return op_id_ == call; }
bool is_gep() const { return op_id_ == getelementptr; }
bool is_zext() const { return op_id_ == zext; }
bool isBinary() const {
return (is_add() || is_sub() || is_mul() || is_div() || is_fadd() ||
is_fsub() || is_fmul() || is_fdiv()) &&
(get_num_operand() == 2);
}
bool isTerminator() const { return is_br() || is_ret(); }
private:
OpID op_id_;
BasicBlock *parent_;
};
template <typename Inst> class BaseInst : public Instruction {
protected:
template <typename... Args> static Inst *create(Args &&...args) {
return new Inst(std::forward<Args>(args)...);
}
template <typename... Args>
BaseInst(Args &&...args) : Instruction(std::forward<Args>(args)...) {}
};
class IBinaryInst : public BaseInst<IBinaryInst> {
friend BaseInst<IBinaryInst>;
private:
IBinaryInst(OpID id, Value *v1, Value *v2, BasicBlock *bb);
public:
static IBinaryInst *create_add(Value *v1, Value *v2, BasicBlock *bb);
static IBinaryInst *create_sub(Value *v1, Value *v2, BasicBlock *bb);
static IBinaryInst *create_mul(Value *v1, Value *v2, BasicBlock *bb);
static IBinaryInst *create_sdiv(Value *v1, Value *v2, BasicBlock *bb);
virtual std::string print() override;
};
class FBinaryInst : public BaseInst<FBinaryInst> {
friend BaseInst<FBinaryInst>;
private:
FBinaryInst(OpID id, Value *v1, Value *v2, BasicBlock *bb);
public:
static FBinaryInst *create_fadd(Value *v1, Value *v2, BasicBlock *bb);
static FBinaryInst *create_fsub(Value *v1, Value *v2, BasicBlock *bb);
static FBinaryInst *create_fmul(Value *v1, Value *v2, BasicBlock *bb);
static FBinaryInst *create_fdiv(Value *v1, Value *v2, BasicBlock *bb);
virtual std::string print() override;
};
class ICmpInst : public BaseInst<ICmpInst> {
friend BaseInst<ICmpInst>;
private:
ICmpInst(OpID id, Value *lhs, Value *rhs, BasicBlock *bb);
public:
static ICmpInst *create_ge(Value *v1, Value *v2, BasicBlock *bb);
static ICmpInst *create_gt(Value *v1, Value *v2, BasicBlock *bb);
static ICmpInst *create_le(Value *v1, Value *v2, BasicBlock *bb);
static ICmpInst *create_lt(Value *v1, Value *v2, BasicBlock *bb);
static ICmpInst *create_eq(Value *v1, Value *v2, BasicBlock *bb);
static ICmpInst *create_ne(Value *v1, Value *v2, BasicBlock *bb);
virtual std::string print() override;
};
class FCmpInst : public BaseInst<FCmpInst> {
friend BaseInst<FCmpInst>;
private:
FCmpInst(OpID id, Value *lhs, Value *rhs, BasicBlock *bb);
public:
static FCmpInst *create_fge(Value *v1, Value *v2, BasicBlock *bb);
static FCmpInst *create_fgt(Value *v1, Value *v2, BasicBlock *bb);
static FCmpInst *create_fle(Value *v1, Value *v2, BasicBlock *bb);
static FCmpInst *create_flt(Value *v1, Value *v2, BasicBlock *bb);
static FCmpInst *create_feq(Value *v1, Value *v2, BasicBlock *bb);
static FCmpInst *create_fne(Value *v1, Value *v2, BasicBlock *bb);
virtual std::string print() override;
};
class CallInst : public BaseInst<CallInst> {
friend BaseInst<CallInst>;
protected:
CallInst(Function *func, std::vector<Value *> args, BasicBlock *bb);
public:
static CallInst *create_call(Function *func, std::vector<Value *> args,
BasicBlock *bb);
FunctionType *get_function_type() const;
virtual std::string print() override;
};
class BranchInst : public BaseInst<BranchInst> {
friend BaseInst<BranchInst>;
private:
BranchInst(Value *cond, BasicBlock *if_true, BasicBlock *if_false,
BasicBlock *bb);
~BranchInst();
public:
static BranchInst *create_cond_br(Value *cond, BasicBlock *if_true,
BasicBlock *if_false, BasicBlock *bb);
static BranchInst *create_br(BasicBlock *if_true, BasicBlock *bb);
bool is_cond_br() const { return get_num_operand() == 3; }
Value *get_condition() const { return get_operand(0); }
virtual std::string print() override;
};
class ReturnInst : public BaseInst<ReturnInst> {
friend BaseInst<ReturnInst>;
private:
ReturnInst(Value *val, BasicBlock *bb);
public:
static ReturnInst *create_ret(Value *val, BasicBlock *bb);
static ReturnInst *create_void_ret(BasicBlock *bb);
bool is_void_ret() const;
virtual std::string print() override;
};
class GetElementPtrInst : public BaseInst<GetElementPtrInst> {
friend BaseInst<GetElementPtrInst>;
private:
GetElementPtrInst(Value *ptr, std::vector<Value *> idxs, BasicBlock *bb);
public:
static Type *get_element_type(Value *ptr, std::vector<Value *> idxs);
static GetElementPtrInst *create_gep(Value *ptr, std::vector<Value *> idxs,
BasicBlock *bb);
Type *get_element_type() const;
virtual std::string print() override;
};
class StoreInst : public BaseInst<StoreInst> {
friend BaseInst<StoreInst>;
private:
StoreInst(Value *val, Value *ptr, BasicBlock *bb);
public:
static StoreInst *create_store(Value *val, Value *ptr, BasicBlock *bb);
Value *get_rval() { return this->get_operand(0); }
Value *get_lval() { return this->get_operand(1); }
virtual std::string print() override;
};
class LoadInst : public BaseInst<LoadInst> {
friend BaseInst<LoadInst>;
private:
LoadInst(Value *ptr, BasicBlock *bb);
public:
static LoadInst *create_load(Value *ptr, BasicBlock *bb);
Value *get_lval() const { return this->get_operand(0); }
Type *get_load_type() const { return get_type(); };
virtual std::string print() override;
};
class AllocaInst : public BaseInst<AllocaInst> {
friend BaseInst<AllocaInst>;
private:
AllocaInst(Type *ty, BasicBlock *bb);
public:
static AllocaInst *create_alloca(Type *ty, BasicBlock *bb);
Type *get_alloca_type() const {
return get_type()->get_pointer_element_type();
};
virtual std::string print() override;
};
class ZextInst : public BaseInst<ZextInst> {
friend BaseInst<ZextInst>;
private:
ZextInst(Value *val, Type *ty, BasicBlock *bb);
public:
static ZextInst *create_zext(Value *val, Type *ty, BasicBlock *bb);
static ZextInst *create_zext_to_i32(Value *val, BasicBlock *bb);
Type *get_dest_type() const { return get_type(); };
virtual std::string print() override;
};
class FpToSiInst : public BaseInst<FpToSiInst> {
friend BaseInst<FpToSiInst>;
private:
FpToSiInst(Value *val, Type *ty, BasicBlock *bb);
public:
static FpToSiInst *create_fptosi(Value *val, Type *ty, BasicBlock *bb);
static FpToSiInst *create_fptosi_to_i32(Value *val, BasicBlock *bb);
Type *get_dest_type() const { return get_type(); };
virtual std::string print() override;
};
class SiToFpInst : public BaseInst<SiToFpInst> {
friend BaseInst<SiToFpInst>;
private:
SiToFpInst(Value *val, Type *ty, BasicBlock *bb);
public:
static SiToFpInst *create_sitofp(Value *val, BasicBlock *bb);
Type *get_dest_type() const { return get_type(); };
virtual std::string print() override;
};
class PhiInst : public BaseInst<PhiInst> {
friend BaseInst<PhiInst>;
private:
PhiInst(Type *ty, std::vector<Value *> vals,
std::vector<BasicBlock *> val_bbs, BasicBlock *bb);
public:
static PhiInst *create_phi(Type *ty, BasicBlock *bb,
std::vector<Value *> vals = {},
std::vector<BasicBlock *> val_bbs = {});
void add_phi_pair_operand(Value *val, Value *pre_bb) {
this->add_operand(val);
this->add_operand(pre_bb);
}
std::vector<std::pair<Value *, BasicBlock *>> get_phi_pairs() {
std::vector<std::pair<Value *, BasicBlock *>> res;
for (size_t i = 0; i < get_num_operand(); i += 2) {
res.push_back({this->get_operand(i),
this->get_operand(i + 1)->as<BasicBlock>()});
}
return res;
}
virtual std::string print() override;
};
#pragma once
#include "Function.hpp"
#include "GlobalVariable.hpp"
#include "Instruction.hpp"
#include "Type.hpp"
#include "Value.hpp"
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <map>
#include <memory>
#include <string>
class GlobalVariable;
class Function;
class Module {
public:
Module();
~Module() = default;
Type *get_void_type();
Type *get_label_type();
IntegerType *get_int1_type();
IntegerType *get_int32_type();
PointerType *get_int32_ptr_type();
FloatType *get_float_type();
PointerType *get_float_ptr_type();
PointerType *get_pointer_type(Type *contained);
ArrayType *get_array_type(Type *contained, unsigned num_elements);
FunctionType *get_function_type(Type *retty, std::vector<Type *> &args);
void add_function(Function *f);
llvm::ilist<Function> &get_functions();
void add_global_variable(GlobalVariable *g);
llvm::ilist<GlobalVariable> &get_global_variable();
void set_print_name();
std::string print();
private:
// The global variables in the module
llvm::ilist<GlobalVariable> global_list_;
// The functions in the module
llvm::ilist<Function> function_list_;
std::unique_ptr<IntegerType> int1_ty_;
std::unique_ptr<IntegerType> int32_ty_;
std::unique_ptr<Type> label_ty_;
std::unique_ptr<Type> void_ty_;
std::unique_ptr<FloatType> float32_ty_;
std::map<Type *, std::unique_ptr<PointerType>> pointer_map_;
std::map<std::pair<Type *, int>, std::unique_ptr<ArrayType>> array_map_;
std::map<std::pair<Type *, std::vector<Type *>>,
std::unique_ptr<FunctionType>>
function_map_;
};
#pragma once
#include <iostream>
#include <vector>
class Module;
class IntegerType;
class FunctionType;
class ArrayType;
class PointerType;
class FloatType;
class Type {
public:
enum TypeID {
VoidTyID, // Void
LabelTyID, // Labels, e.g., BasicBlock
IntegerTyID, // Integers, include 32 bits and 1 bit
FunctionTyID, // Functions
ArrayTyID, // Arrays
PointerTyID, // Pointer
FloatTyID // float
};
explicit Type(TypeID tid, Module *m);
~Type() = default;
TypeID get_type_id() const { return tid_; }
bool is_void_type() const { return get_type_id() == VoidTyID; }
bool is_label_type() const { return get_type_id() == LabelTyID; }
bool is_integer_type() const { return get_type_id() == IntegerTyID; }
bool is_function_type() const { return get_type_id() == FunctionTyID; }
bool is_array_type() const { return get_type_id() == ArrayTyID; }
bool is_pointer_type() const { return get_type_id() == PointerTyID; }
bool is_float_type() const { return get_type_id() == FloatTyID; }
bool is_int32_type() const;
bool is_int1_type() const;
// Return related data member if is the required type, else throw error
Type *get_pointer_element_type() const;
Type *get_array_element_type() const;
Module *get_module() const { return m_; }
unsigned get_size() const;
std::string print() const;
private:
TypeID tid_;
Module *m_;
};
class IntegerType : public Type {
public:
explicit IntegerType(unsigned num_bits, Module *m);
unsigned get_num_bits() const;
private:
unsigned num_bits_;
};
class FunctionType : public Type {
public:
FunctionType(Type *result, std::vector<Type *> params);
static bool is_valid_return_type(Type *ty);
static bool is_valid_argument_type(Type *ty);
static FunctionType *get(Type *result, std::vector<Type *> params);
unsigned get_num_of_args() const;
Type *get_param_type(unsigned i) const;
std::vector<Type *>::iterator param_begin() { return args_.begin(); }
std::vector<Type *>::iterator param_end() { return args_.end(); }
Type *get_return_type() const;
private:
Type *result_;
std::vector<Type *> args_;
};
class ArrayType : public Type {
public:
ArrayType(Type *contained, unsigned num_elements);
static bool is_valid_element_type(Type *ty);
static ArrayType *get(Type *contained, unsigned num_elements);
Type *get_element_type() const { return contained_; }
unsigned get_num_of_elements() const { return num_elements_; }
private:
Type *contained_; // The element type of the array.
unsigned num_elements_; // Number of elements in the array.
};
class PointerType : public Type {
public:
PointerType(Type *contained);
Type *get_element_type() const { return contained_; }
static PointerType *get(Type *contained);
private:
Type *contained_; // The element type of the ptr.
};
class FloatType : public Type {
public:
FloatType(Module *m);
static FloatType *get(Module *m);
private:
};
#pragma once
#include "Value.hpp"
#include <vector>
class User : public Value {
public:
User(Type *ty, const std::string &name = "") : Value(ty, name){};
virtual ~User() { remove_all_operands(); }
const std::vector<Value *> &get_operands() const { return operands_; }
unsigned get_num_operand() const { return operands_.size(); }
// start from 0
Value *get_operand(unsigned i) const { return operands_.at(i); };
// start from 0
void set_operand(unsigned i, Value *v);
void add_operand(Value *v);
void remove_all_operands();
void remove_operand(unsigned i);
private:
std::vector<Value *> operands_; // operands of this value
};
/* For example: op = func(a, b)
* for a: Use(op, 0)
* for b: Use(op, 1)
*/
struct Use {
User *val_; // used by whom
unsigned arg_no_; // the no. of operand
Use(User *val, unsigned no) : val_(val), arg_no_(no) {}
bool operator==(const Use &other) const {
return val_ == other.val_ and arg_no_ == other.arg_no_;
}
};
#pragma once
#include <functional>
#include <iostream>
#include <list>
#include <string>
#include <cassert>
class Type;
class Value;
class User;
struct Use;
class Value {
public:
explicit Value(Type *ty, const std::string &name = "")
: type_(ty), name_(name){};
virtual ~Value() { replace_all_use_with(nullptr); }
std::string get_name() const { return name_; };
Type *get_type() const { return type_; }
const std::list<Use> &get_use_list() const { return use_list_; }
bool set_name(std::string name);
void add_use(User *user, unsigned arg_no);
void remove_use(User *user, unsigned arg_no);
void replace_all_use_with(Value *new_val);
void replace_use_with_if(Value *new_val, std::function<bool(Use *)> pred);
virtual std::string print() = 0;
template<typename T>
T *as()
{
static_assert(std::is_base_of<Value, T>::value, "T must be a subclass of Value");
const auto ptr = dynamic_cast<T*>(this);
assert(ptr && "dynamic_cast failed");
return ptr;
}
template<typename T>
[[nodiscard]] const T* as() const {
static_assert(std::is_base_of<Value, T>::value, "T must be a subclass of Value");
const auto ptr = dynamic_cast<const T*>(this);
assert(ptr);
return ptr;
}
// is 接口
template <typename T>
[[nodiscard]] bool is() const {
static_assert(std::is_base_of<Value, T>::value, "T must be a subclass of Value");
return dynamic_cast<const T*>(this);
}
private:
Type *type_;
std::list<Use> use_list_; // who use this value
std::string name_; // should we put name field here ?
};
......@@ -2,3 +2,5 @@ add_subdirectory(parser)
add_subdirectory(common)
add_subdirectory(logging)
add_subdirectory(cminusfc)
add_subdirectory(lightir)
add_subdirectory(io)
\ No newline at end of file
add_executable(
cminusfc
main.cpp
cminusf_builder.cpp
)
target_link_libraries(
cminusfc
IR_lib
common
syntax
stdc++fs
......
#include "cminusf_builder.hpp"
#define CONST_FP(num) ConstantFP::get((float)num, module.get())
#define CONST_INT(num) ConstantInt::get(num, module.get())
// types
Type *VOID_T;
Type *INT1_T;
Type *INT32_T;
Type *INT32PTR_T;
Type *FLOAT_T;
Type *FLOATPTR_T;
/*
* use CMinusfBuilder::Scope to construct scopes
* scope.enter: enter a new scope
* scope.exit: exit current scope
* scope.push: add a new binding to current scope
* scope.find: find and return the value bound to the name
*/
Value* CminusfBuilder::visit(ASTProgram &node) {
VOID_T = module->get_void_type();
INT1_T = module->get_int1_type();
INT32_T = module->get_int32_type();
INT32PTR_T = module->get_int32_ptr_type();
FLOAT_T = module->get_float_type();
FLOATPTR_T = module->get_float_ptr_type();
Value *ret_val = nullptr;
for (auto &decl : node.declarations) {
ret_val = decl->accept(*this);
}
return ret_val;
}
Value* CminusfBuilder::visit(ASTNum &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTVarDeclaration &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTFunDeclaration &node) {
FunctionType *fun_type;
Type *ret_type;
std::vector<Type *> param_types;
if (node.type == TYPE_INT)
ret_type = INT32_T;
else if (node.type == TYPE_FLOAT)
ret_type = FLOAT_T;
else
ret_type = VOID_T;
for (auto &param : node.params) {
// TODO: Please accomplish param_types.
}
fun_type = FunctionType::get(ret_type, param_types);
auto func = Function::create(fun_type, node.id, module.get());
scope.push(node.id, func);
context.func = func;
auto funBB = BasicBlock::create(module.get(), "entry", func);
builder->set_insert_point(funBB);
scope.enter();
std::vector<Value *> args;
for (auto &arg : func->get_args()) {
args.push_back(&arg);
}
for (unsigned int i = 0; i < node.params.size(); ++i) {
// TODO: You need to deal with params and store them in the scope.
}
node.compound_stmt->accept(*this);
if (builder->get_insert_block()->get_terminator() == nullptr)
{
if (context.func->get_return_type()->is_void_type())
builder->create_void_ret();
else if (context.func->get_return_type()->is_float_type())
builder->create_ret(CONST_FP(0.));
else
builder->create_ret(CONST_INT(0));
}
scope.exit();
return nullptr;
}
Value* CminusfBuilder::visit(ASTParam &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTCompoundStmt &node) {
// TODO: This function is not complete.
// You may need to add some code here
// to deal with complex statements.
for (auto &decl : node.local_declarations) {
decl->accept(*this);
}
for (auto &stmt : node.statement_list) {
stmt->accept(*this);
if (builder->get_insert_block()->get_terminator() == nullptr)
break;
}
return nullptr;
}
Value* CminusfBuilder::visit(ASTExpressionStmt &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTSelectionStmt &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTIterationStmt &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTReturnStmt &node) {
if (node.expression == nullptr) {
builder->create_void_ret();
return nullptr;
} else {
// TODO: The given code is incomplete.
// You need to solve other return cases (e.g. return an integer).
}
return nullptr;
}
Value* CminusfBuilder::visit(ASTVar &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTAssignExpression &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTSimpleExpression &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTAdditiveExpression &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTTerm &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTCall &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
#include "Module.hpp"
#include "ast.hpp"
#include "cminusf_builder.hpp"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
using std::string;
using std::operator""s;
struct Config
{
struct Config {
string exe_name; // compiler exe name
std::filesystem::path input_file;
std::filesystem::path output_file;
bool emitast{false};
bool emitllvm{false};
Config(int argc, char **argv) : argc(argc), argv(argv)
{
Config(int argc, char **argv) : argc(argc), argv(argv) {
parse_cmd_line();
check();
}
private:
private:
int argc{-1};
char **argv{nullptr};
......@@ -32,50 +34,55 @@ private:
void print_err(const string &msg) const;
};
int main(int argc, char **argv)
{
int main(int argc, char **argv) {
Config config(argc, argv);
auto syntax_tree = parse(config.input_file.c_str());
auto ast = AST(syntax_tree);
if (config.emitast) { // if emit ast (lab1), print ast and return
ASTPrinter printer;
ast.run_visitor(printer);
} else {
std::unique_ptr<Module> m;
CminusfBuilder builder;
ast.run_visitor(builder);
m = builder.getModule();
std::ofstream output_stream(config.output_file);
if (config.emitllvm) {
auto abs_path = std::filesystem::canonical(config.input_file);
output_stream << "; ModuleID = 'cminus'\n";
output_stream << "source_filename = " << abs_path << "\n\n";
output_stream << m->print();
}
// TODO: lab3 lab4 (IR optimization or codegen)
}
return 0;
}
void Config::parse_cmd_line()
{
void Config::parse_cmd_line() {
exe_name = argv[0];
for (int i = 1; i < argc; ++i)
{
if (argv[i] == "-h"s || argv[i] == "--help"s)
{
for (int i = 1; i < argc; ++i) {
if (argv[i] == "-h"s || argv[i] == "--help"s) {
print_help();
}
else if (argv[i] == "-o"s)
{
if (output_file.empty() && i + 1 < argc)
{
} else if (argv[i] == "-o"s) {
if (output_file.empty() && i + 1 < argc) {
output_file = argv[i + 1];
i += 1;
}
else
{
} else {
print_err("bad output file");
}
}
else if (argv[i] == "-emit-ast"s)
{
} else if (argv[i] == "-emit-ast"s) {
emitast = true;
}
else
{
if (input_file.empty())
{
} else if (argv[i] == "-emit-llvm"s) {
emitllvm = true;
} else {
if (input_file.empty()) {
input_file = argv[i];
}
else
{
} else {
string err =
"unrecognized command-line option \'"s + argv[i] + "\'"s;
print_err(err);
......@@ -84,24 +91,19 @@ void Config::parse_cmd_line()
}
}
void Config::check()
{
if (input_file.empty())
{
void Config::check() {
if (input_file.empty()) {
print_err("no input file");
}
if (input_file.extension() != ".cminus")
{
if (input_file.extension() != ".cminus") {
print_err("file format not recognized");
}
if (output_file.empty())
{
if (output_file.empty()) {
output_file = input_file.stem();
}
}
void Config::print_help() const
{
void Config::print_help() const {
std::cout << "Usage: " << exe_name
<< " [-h|--help] [-o <target-file>] [-mem2reg] [-emit-llvm] [-S] "
"<input-file>"
......@@ -109,8 +111,7 @@ void Config::print_help() const
exit(0);
}
void Config::print_err(const string &msg) const
{
void Config::print_err(const string &msg) const {
std::cout << exe_name << ": " << msg << std::endl;
exit(-1);
}
......@@ -333,47 +333,29 @@ ASTNode *AST::transform_node_iter(syntax_tree_node *n) {
}
}
void ASTProgram::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
void ASTNum::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
void ASTVarDeclaration::accept(ASTVisitor &visitor) {
Value* ASTProgram::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTNum::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTVarDeclaration::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTFunDeclaration::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTParam::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTCompoundStmt::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTExpressionStmt::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTSelectionStmt::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTIterationStmt::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTReturnStmt::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTAssignExpression::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTSimpleExpression::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTAdditiveExpression::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTFunDeclaration::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTParam::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
void ASTCompoundStmt::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTExpressionStmt::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTSelectionStmt::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTIterationStmt::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTReturnStmt::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
void ASTAssignExpression::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTSimpleExpression::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTAdditiveExpression::accept(ASTVisitor &visitor) {
return visitor.visit(*this);
}
void ASTVar::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
void ASTTerm::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
void ASTCall::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
// NOTE: 打印AST的相关接口,无需修改
Value* ASTVar::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTTerm::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
Value* ASTCall::accept(ASTVisitor &visitor) { return visitor.visit(*this); }
#define _DEBUG_PRINT_N_(N) \
{ std::cout << std::string(N, '-'); }
void ASTPrinter::visit(ASTProgram &node) {
Value* ASTPrinter::visit(ASTProgram &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "program" << std::endl;
add_depth();
......@@ -381,9 +363,10 @@ void ASTPrinter::visit(ASTProgram &node) {
decl->accept(*this);
}
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTNum &node) {
Value* ASTPrinter::visit(ASTNum &node) {
_DEBUG_PRINT_N_(depth);
if (node.type == TYPE_INT) {
std::cout << "num (int): " << node.i_val << std::endl;
......@@ -392,9 +375,10 @@ void ASTPrinter::visit(ASTNum &node) {
} else {
_AST_NODE_ERROR_
}
return nullptr;
}
void ASTPrinter::visit(ASTVarDeclaration &node) {
Value* ASTPrinter::visit(ASTVarDeclaration &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "var-declaration: " << node.id;
if (node.num != nullptr) {
......@@ -402,12 +386,13 @@ void ASTPrinter::visit(ASTVarDeclaration &node) {
add_depth();
node.num->accept(*this);
remove_depth();
return;
return nullptr;
}
std::cout << std::endl;
return nullptr;
}
void ASTPrinter::visit(ASTFunDeclaration &node) {
Value* ASTPrinter::visit(ASTFunDeclaration &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "fun-declaration: " << node.id << std::endl;
add_depth();
......@@ -417,17 +402,19 @@ void ASTPrinter::visit(ASTFunDeclaration &node) {
node.compound_stmt->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTParam &node) {
Value* ASTPrinter::visit(ASTParam &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "param: " << node.id;
if (node.isarray)
std::cout << "[]";
std::cout << std::endl;
return nullptr;
}
void ASTPrinter::visit(ASTCompoundStmt &node) {
Value* ASTPrinter::visit(ASTCompoundStmt &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "compound-stmt" << std::endl;
add_depth();
......@@ -439,18 +426,20 @@ void ASTPrinter::visit(ASTCompoundStmt &node) {
stmt->accept(*this);
}
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTExpressionStmt &node) {
Value* ASTPrinter::visit(ASTExpressionStmt &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "expression-stmt" << std::endl;
add_depth();
if (node.expression != nullptr)
node.expression->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTSelectionStmt &node) {
Value* ASTPrinter::visit(ASTSelectionStmt &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "selection-stmt" << std::endl;
add_depth();
......@@ -459,18 +448,20 @@ void ASTPrinter::visit(ASTSelectionStmt &node) {
if (node.else_statement != nullptr)
node.else_statement->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTIterationStmt &node) {
Value* ASTPrinter::visit(ASTIterationStmt &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "iteration-stmt" << std::endl;
add_depth();
node.expression->accept(*this);
node.statement->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTReturnStmt &node) {
Value* ASTPrinter::visit(ASTReturnStmt &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "return-stmt";
if (node.expression == nullptr) {
......@@ -481,18 +472,20 @@ void ASTPrinter::visit(ASTReturnStmt &node) {
node.expression->accept(*this);
remove_depth();
}
return nullptr;
}
void ASTPrinter::visit(ASTAssignExpression &node) {
Value* ASTPrinter::visit(ASTAssignExpression &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "assign-expression" << std::endl;
add_depth();
node.var->accept(*this);
node.expression->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTSimpleExpression &node) {
Value* ASTPrinter::visit(ASTSimpleExpression &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "simple-expression";
if (node.additive_expression_r == nullptr) {
......@@ -521,9 +514,10 @@ void ASTPrinter::visit(ASTSimpleExpression &node) {
if (node.additive_expression_r != nullptr)
node.additive_expression_r->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTAdditiveExpression &node) {
Value* ASTPrinter::visit(ASTAdditiveExpression &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "additive-expression";
if (node.additive_expression == nullptr) {
......@@ -544,9 +538,10 @@ void ASTPrinter::visit(ASTAdditiveExpression &node) {
node.additive_expression->accept(*this);
node.term->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTVar &node) {
Value* ASTPrinter::visit(ASTVar &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "var: " << node.id;
if (node.expression != nullptr) {
......@@ -554,12 +549,13 @@ void ASTPrinter::visit(ASTVar &node) {
add_depth();
node.expression->accept(*this);
remove_depth();
return;
return nullptr;
}
std::cout << std::endl;
return nullptr;
}
void ASTPrinter::visit(ASTTerm &node) {
Value* ASTPrinter::visit(ASTTerm &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "term";
if (node.term == nullptr) {
......@@ -581,9 +577,10 @@ void ASTPrinter::visit(ASTTerm &node) {
node.factor->accept(*this);
remove_depth();
return nullptr;
}
void ASTPrinter::visit(ASTCall &node) {
Value* ASTPrinter::visit(ASTCall &node) {
_DEBUG_PRINT_N_(depth);
std::cout << "call: " << node.id << "()" << std::endl;
add_depth();
......@@ -591,4 +588,5 @@ void ASTPrinter::visit(ASTCall &node) {
arg->accept(*this);
}
remove_depth();
return nullptr;
}
......@@ -9,15 +9,11 @@ void LogWriter::operator<(const LogStream &stream) {
void LogWriter::output_log(const std::ostringstream &msg) {
if (log_level_ >= env_log_level)
std::cout << "[" << level2string(log_level_) << "] "
<< "(" << location_.file_
<< ":" << location_.line_
<< "L "<< location_.func_<<")"
<< msg.str() << std::endl;
<< "(" << location_.file_ << ":" << location_.line_ << "L "
<< location_.func_ << ")" << msg.str() << std::endl;
}
std::string level2string(LogLevel level) {
switch (level)
{
switch (level) {
case DEBUG:
return "DEBUG";
......@@ -34,9 +30,9 @@ std::string level2string(LogLevel level) {
return "";
}
}
std::string get_short_name(const char * file_path) {
std::string get_short_name(const char *file_path) {
std::string short_file_path = file_path;
int index = short_file_path.find_last_of('/');
return short_file_path.substr(index+1);
return short_file_path.substr(index + 1);
}
......@@ -3,9 +3,9 @@
#include "syntax_tree.h"
syntax_tree_node * new_syntax_tree_node(const char * name)
{
syntax_tree_node * new_node = (syntax_tree_node *)malloc(sizeof(syntax_tree_node));
syntax_tree_node *new_syntax_tree_node(const char *name) {
syntax_tree_node *new_node =
(syntax_tree_node *)malloc(sizeof(syntax_tree_node));
if (name)
strncpy(new_node->name, name, SYNTAX_TREE_NODE_NAME_MAX);
else
......@@ -14,16 +14,16 @@ syntax_tree_node * new_syntax_tree_node(const char * name)
return new_node;
}
int syntax_tree_add_child(syntax_tree_node * parent, syntax_tree_node * child)
{
if (!parent || !child) return -1;
int syntax_tree_add_child(syntax_tree_node *parent, syntax_tree_node *child) {
if (!parent || !child)
return -1;
parent->children[parent->children_num++] = child;
return parent->children_num;
}
void del_syntax_tree_node(syntax_tree_node * node, int recursive)
{
if (!node) return;
void del_syntax_tree_node(syntax_tree_node *node, int recursive) {
if (!node)
return;
int i;
if (recursive) {
......@@ -34,14 +34,13 @@ void del_syntax_tree_node(syntax_tree_node * node, int recursive)
free(node);
}
syntax_tree * new_syntax_tree()
{
syntax_tree *new_syntax_tree() {
return (syntax_tree *)malloc(sizeof(syntax_tree));
}
void del_syntax_tree(syntax_tree * tree)
{
if (!tree) return;
void del_syntax_tree(syntax_tree *tree) {
if (!tree)
return;
if (tree->root) {
del_syntax_tree_node(tree->root, 1);
......@@ -49,12 +48,12 @@ void del_syntax_tree(syntax_tree * tree)
free(tree);
}
void print_syntax_tree_node(FILE * fout, syntax_tree_node * node, int level)
{
void print_syntax_tree_node(FILE *fout, syntax_tree_node *node, int level) {
// assume fout valid now
// check if "node" empty pointer
if (!node) return;
if (!node)
return;
// print myself
int i;
......@@ -68,10 +67,9 @@ void print_syntax_tree_node(FILE * fout, syntax_tree_node * node, int level)
}
}
void print_syntax_tree(FILE * fout, syntax_tree * tree)
{
if (!fout) return;
void print_syntax_tree(FILE *fout, syntax_tree *tree) {
if (!fout)
return;
print_syntax_tree_node(fout, tree->root, 0);
}
add_library(cminus_io io.c)
install(
TARGETS cminus_io
ARCHIVE DESTINATION lib
)
#include <stdio.h>
#include <stdlib.h>
int input() {
int a;
scanf("%d", &a);
return a;
}
void output(int a) { printf("%d\n", a); }
void outputFloat(float a) { printf("%f\n", a); }
void neg_idx_except() {
printf("negative index exception\n");
exit(0);
}
int input();
void output(int a);
void outputFloat(float a);
void neg_idx_except();
#include "BasicBlock.hpp"
#include "Function.hpp"
#include "IRprinter.hpp"
#include "Module.hpp"
#include <cassert>
BasicBlock::BasicBlock(Module *m, const std::string &name = "",
Function *parent = nullptr)
: Value(m->get_label_type(), name), parent_(parent) {
assert(parent && "currently parent should not be nullptr");
parent_->add_basic_block(this);
}
Module *BasicBlock::get_module() { return get_parent()->get_parent(); }
void BasicBlock::erase_from_parent() { this->get_parent()->remove(this); }
bool BasicBlock::is_terminated() const {
if (instr_list_.empty()) {
return false;
}
switch (instr_list_.back().get_instr_type()) {
case Instruction::ret:
case Instruction::br:
return true;
default:
return false;
}
}
Instruction *BasicBlock::get_terminator() {
assert(is_terminated() &&
"Trying to get terminator from an bb which is not terminated");
return &instr_list_.back();
}
void BasicBlock::add_instruction(Instruction *instr) {
assert(not is_terminated() && "Inserting instruction to terminated bb");
instr_list_.push_back(instr);
}
std::string BasicBlock::print() {
std::string bb_ir;
bb_ir += this->get_name();
bb_ir += ":";
// print prebb
if (!this->get_pre_basic_blocks().empty()) {
bb_ir += " ; preds = ";
}
for (auto bb : this->get_pre_basic_blocks()) {
if (bb != *this->get_pre_basic_blocks().begin()) {
bb_ir += ", ";
}
bb_ir += print_as_op(bb, false);
}
// print prebb
if (!this->get_parent()) {
bb_ir += "\n";
bb_ir += "; Error: Block without parent!";
}
bb_ir += "\n";
for (auto &instr : this->get_instructions()) {
bb_ir += " ";
bb_ir += instr.print();
bb_ir += "\n";
}
return bb_ir;
}
add_library(
IR_lib STATIC
Type.cpp
User.cpp
Value.cpp
BasicBlock.cpp
Constant.cpp
Function.cpp
GlobalVariable.cpp
Instruction.cpp
Module.cpp
IRprinter.cpp
)
target_link_libraries(
IR_lib
LLVMSupport
)
#include "Constant.hpp"
#include "Module.hpp"
#include <iostream>
#include <memory>
#include <sstream>
#include <unordered_map>
struct pair_hash {
template <typename T>
std::size_t operator()(const std::pair<T, Module *> val) const {
auto lhs = std::hash<T>()(val.first);
auto rhs =
std::hash<uintptr_t>()(reinterpret_cast<uintptr_t>(val.second));
return lhs ^ rhs;
}
};
static std::unordered_map<std::pair<int, Module *>,
std::unique_ptr<ConstantInt>, pair_hash>
cached_int;
static std::unordered_map<std::pair<bool, Module *>,
std::unique_ptr<ConstantInt>, pair_hash>
cached_bool;
static std::unordered_map<std::pair<float, Module *>,
std::unique_ptr<ConstantFP>, pair_hash>
cached_float;
static std::unordered_map<Type *, std::unique_ptr<ConstantZero>> cached_zero;
ConstantInt *ConstantInt::get(int val, Module *m) {
if (cached_int.find(std::make_pair(val, m)) != cached_int.end())
return cached_int[std::make_pair(val, m)].get();
return (cached_int[std::make_pair(val, m)] = std::unique_ptr<ConstantInt>(
new ConstantInt(m->get_int32_type(), val)))
.get();
}
ConstantInt *ConstantInt::get(bool val, Module *m) {
if (cached_bool.find(std::make_pair(val, m)) != cached_bool.end())
return cached_bool[std::make_pair(val, m)].get();
return (cached_bool[std::make_pair(val, m)] = std::unique_ptr<ConstantInt>(
new ConstantInt(m->get_int1_type(), val ? 1 : 0)))
.get();
}
std::string ConstantInt::print() {
std::string const_ir;
Type *ty = this->get_type();
if (ty->is_integer_type() &&
static_cast<IntegerType *>(ty)->get_num_bits() == 1) {
// int1
const_ir += (this->get_value() == 0) ? "false" : "true";
} else {
// int32
const_ir += std::to_string(this->get_value());
}
return const_ir;
}
ConstantArray::ConstantArray(ArrayType *ty, const std::vector<Constant *> &val)
: Constant(ty, "") {
for (unsigned i = 0; i < val.size(); i++)
set_operand(i, val[i]);
this->const_array.assign(val.begin(), val.end());
}
Constant *ConstantArray::get_element_value(int index) {
return this->const_array[index];
}
ConstantArray *ConstantArray::get(ArrayType *ty,
const std::vector<Constant *> &val) {
return new ConstantArray(ty, val);
}
std::string ConstantArray::print() {
std::string const_ir;
const_ir += this->get_type()->print();
const_ir += " ";
const_ir += "[";
for (unsigned i = 0; i < this->get_size_of_array(); i++) {
Constant *element = get_element_value(i);
if (!dynamic_cast<ConstantArray *>(get_element_value(i))) {
const_ir += element->get_type()->print();
}
const_ir += element->print();
if (i < this->get_size_of_array()) {
const_ir += ", ";
}
}
const_ir += "]";
return const_ir;
}
ConstantFP *ConstantFP::get(float val, Module *m) {
if (cached_float.find(std::make_pair(val, m)) != cached_float.end())
return cached_float[std::make_pair(val, m)].get();
return (cached_float[std::make_pair(val, m)] = std::unique_ptr<ConstantFP>(
new ConstantFP(m->get_float_type(), val)))
.get();
}
std::string ConstantFP::print() {
std::stringstream fp_ir_ss;
std::string fp_ir;
double val = this->get_value();
fp_ir_ss << "0x" << std::hex << *(uint64_t *)&val << std::endl;
fp_ir_ss >> fp_ir;
return fp_ir;
}
ConstantZero *ConstantZero::get(Type *ty, Module *m) {
if (not cached_zero[ty])
cached_zero[ty] = std::unique_ptr<ConstantZero>(new ConstantZero(ty));
return cached_zero[ty].get();
}
std::string ConstantZero::print() { return "zeroinitializer"; }
#include "Function.hpp"
#include "IRprinter.hpp"
#include "Module.hpp"
Function::Function(FunctionType *ty, const std::string &name, Module *parent)
: Value(ty, name), parent_(parent), seq_cnt_(0) {
// num_args_ = ty->getNumParams();
parent->add_function(this);
// build args
for (unsigned i = 0; i < get_num_of_args(); i++) {
arguments_.emplace_back(ty->get_param_type(i), "", this, i);
}
}
Function *Function::create(FunctionType *ty, const std::string &name,
Module *parent) {
return new Function(ty, name, parent);
}
FunctionType *Function::get_function_type() const {
return static_cast<FunctionType *>(get_type());
}
Type *Function::get_return_type() const {
return get_function_type()->get_return_type();
}
unsigned Function::get_num_of_args() const {
return get_function_type()->get_num_of_args();
}
unsigned Function::get_num_basic_blocks() const { return basic_blocks_.size(); }
Module *Function::get_parent() const { return parent_; }
void Function::remove(BasicBlock *bb) {
basic_blocks_.remove(bb);
for (auto pre : bb->get_pre_basic_blocks()) {
pre->remove_succ_basic_block(bb);
}
for (auto succ : bb->get_succ_basic_blocks()) {
succ->remove_pre_basic_block(bb);
}
}
void Function::add_basic_block(BasicBlock *bb) { basic_blocks_.push_back(bb); }
void Function::set_instr_name() {
std::map<Value *, int> seq;
for (auto &arg : this->get_args()) {
if (seq.find(&arg) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (arg.set_name("arg" + std::to_string(seq_num))) {
seq.insert({&arg, seq_num});
}
}
}
for (auto &bb1 : basic_blocks_) {
auto bb = &bb1;
if (seq.find(bb) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (bb->set_name("label" + std::to_string(seq_num))) {
seq.insert({bb, seq_num});
}
}
for (auto &instr : bb->get_instructions()) {
if (!instr.is_void() && seq.find(&instr) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (instr.set_name("op" + std::to_string(seq_num))) {
seq.insert({&instr, seq_num});
}
}
}
}
seq_cnt_ += seq.size();
}
std::string Function::print() {
set_instr_name();
std::string func_ir;
if (this->is_declaration()) {
func_ir += "declare ";
} else {
func_ir += "define ";
}
func_ir += this->get_return_type()->print();
func_ir += " ";
func_ir += print_as_op(this, false);
func_ir += "(";
// print arg
if (this->is_declaration()) {
for (unsigned i = 0; i < this->get_num_of_args(); i++) {
if (i)
func_ir += ", ";
func_ir += static_cast<FunctionType *>(this->get_type())
->get_param_type(i)
->print();
}
} else {
for (auto &arg : get_args()) {
if (&arg != &*get_args().begin())
func_ir += ", ";
func_ir += arg.print();
}
}
func_ir += ")";
// print bb
if (this->is_declaration()) {
func_ir += "\n";
} else {
func_ir += " {";
func_ir += "\n";
for (auto &bb1 : this->get_basic_blocks()) {
auto bb = &bb1;
func_ir += bb->print();
}
func_ir += "}";
}
return func_ir;
}
std::string Argument::print() {
std::string arg_ir;
arg_ir += this->get_type()->print();
arg_ir += " %";
arg_ir += this->get_name();
return arg_ir;
}
#include "GlobalVariable.hpp"
#include "IRprinter.hpp"
GlobalVariable::GlobalVariable(std::string name, Module *m, Type *ty,
bool is_const, Constant *init)
: User(ty, name), is_const_(is_const), init_val_(init) {
m->add_global_variable(this);
if (init) {
this->add_operand(init);
}
} // global操作数为initval
GlobalVariable *GlobalVariable::create(std::string name, Module *m, Type *ty,
bool is_const,
Constant *init = nullptr) {
return new GlobalVariable(name, m, PointerType::get(ty), is_const, init);
}
std::string GlobalVariable::print() {
std::string global_val_ir;
global_val_ir += print_as_op(this, false);
global_val_ir += " = ";
global_val_ir += (this->is_const() ? "constant " : "global ");
global_val_ir += this->get_type()->get_pointer_element_type()->print();
global_val_ir += " ";
global_val_ir += this->get_init()->print();
return global_val_ir;
}
#include "IRprinter.hpp"
#include "Instruction.hpp"
#include <cassert>
#include <type_traits>
std::string print_as_op(Value *v, bool print_ty) {
std::string op_ir;
if (print_ty) {
op_ir += v->get_type()->print();
op_ir += " ";
}
if (dynamic_cast<GlobalVariable *>(v)) {
op_ir += "@" + v->get_name();
} else if (dynamic_cast<Function *>(v)) {
op_ir += "@" + v->get_name();
} else if (dynamic_cast<Constant *>(v)) {
op_ir += v->print();
} else {
op_ir += "%" + v->get_name();
}
return op_ir;
}
std::string print_instr_op_name(Instruction::OpID id) {
switch (id) {
case Instruction::ret:
return "ret";
case Instruction::br:
return "br";
case Instruction::add:
return "add";
case Instruction::sub:
return "sub";
case Instruction::mul:
return "mul";
case Instruction::sdiv:
return "sdiv";
case Instruction::fadd:
return "fadd";
case Instruction::fsub:
return "fsub";
case Instruction::fmul:
return "fmul";
case Instruction::fdiv:
return "fdiv";
case Instruction::alloca:
return "alloca";
case Instruction::load:
return "load";
case Instruction::store:
return "store";
case Instruction::ge:
return "sge";
case Instruction::gt:
return "sgt";
case Instruction::le:
return "sle";
case Instruction::lt:
return "slt";
case Instruction::eq:
return "eq";
case Instruction::ne:
return "ne";
case Instruction::fge:
return "uge";
case Instruction::fgt:
return "ugt";
case Instruction::fle:
return "ule";
case Instruction::flt:
return "ult";
case Instruction::feq:
return "ueq";
case Instruction::fne:
return "une";
case Instruction::phi:
return "phi";
case Instruction::call:
return "call";
case Instruction::getelementptr:
return "getelementptr";
case Instruction::zext:
return "zext";
case Instruction::fptosi:
return "fptosi";
case Instruction::sitofp:
return "sitofp";
}
assert(false && "Must be bug");
}
template <class BinInst> std::string print_binary_inst(const BinInst &inst) {
std::string instr_ir;
instr_ir += "%";
instr_ir += inst.get_name();
instr_ir += " = ";
instr_ir += inst.get_instr_op_name();
instr_ir += " ";
instr_ir += inst.get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(inst.get_operand(0), false);
instr_ir += ", ";
if (inst.get_operand(0)->get_type() == inst.get_operand(1)->get_type()) {
instr_ir += print_as_op(inst.get_operand(1), false);
} else {
instr_ir += print_as_op(inst.get_operand(1), true);
}
return instr_ir;
}
std::string IBinaryInst::print() { return print_binary_inst(*this); }
std::string FBinaryInst::print() { return print_binary_inst(*this); }
template <class CMP> std::string print_cmp_inst(const CMP &inst) {
std::string cmp_type;
if (inst.is_cmp())
cmp_type = "icmp";
else if (inst.is_fcmp())
cmp_type = "fcmp";
else
assert(false && "Unexpected case");
std::string instr_ir;
instr_ir += "%";
instr_ir += inst.get_name();
instr_ir += " = " + cmp_type + " ";
instr_ir += inst.get_instr_op_name();
instr_ir += " ";
instr_ir += inst.get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(inst.get_operand(0), false);
instr_ir += ", ";
if (inst.get_operand(0)->get_type() == inst.get_operand(1)->get_type()) {
instr_ir += print_as_op(inst.get_operand(1), false);
} else {
instr_ir += print_as_op(inst.get_operand(1), true);
}
return instr_ir;
}
std::string ICmpInst::print() { return print_cmp_inst(*this); }
std::string FCmpInst::print() { return print_cmp_inst(*this); }
std::string CallInst::print() {
std::string instr_ir;
if (!this->is_void()) {
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
}
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_function_type()->get_return_type()->print();
instr_ir += " ";
assert(dynamic_cast<Function *>(this->get_operand(0)) &&
"Wrong call operand function");
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += "(";
for (unsigned i = 1; i < this->get_num_operand(); i++) {
if (i > 1)
instr_ir += ", ";
instr_ir += this->get_operand(i)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(i), false);
}
instr_ir += ")";
return instr_ir;
}
std::string BranchInst::print() {
std::string instr_ir;
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), true);
if (is_cond_br()) {
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(1), true);
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(2), true);
}
return instr_ir;
}
std::string ReturnInst::print() {
std::string instr_ir;
instr_ir += get_instr_op_name();
instr_ir += " ";
if (!is_void_ret()) {
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
} else {
instr_ir += "void";
}
return instr_ir;
}
std::string GetElementPtrInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
assert(this->get_operand(0)->get_type()->is_pointer_type());
instr_ir +=
this->get_operand(0)->get_type()->get_pointer_element_type()->print();
instr_ir += ", ";
for (unsigned i = 0; i < this->get_num_operand(); i++) {
if (i > 0)
instr_ir += ", ";
instr_ir += this->get_operand(i)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(i), false);
}
return instr_ir;
}
std::string StoreInst::print() {
std::string instr_ir;
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(1), true);
return instr_ir;
}
std::string LoadInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
assert(this->get_operand(0)->get_type()->is_pointer_type());
instr_ir +=
this->get_operand(0)->get_type()->get_pointer_element_type()->print();
instr_ir += ",";
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), true);
return instr_ir;
}
std::string AllocaInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += get_alloca_type()->print();
return instr_ir;
}
std::string ZextInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += " to ";
instr_ir += this->get_dest_type()->print();
return instr_ir;
}
std::string FpToSiInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += " to ";
instr_ir += this->get_dest_type()->print();
return instr_ir;
}
std::string SiToFpInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += " to ";
instr_ir += this->get_dest_type()->print();
return instr_ir;
}
std::string PhiInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
for (unsigned i = 0; i < this->get_num_operand() / 2; i++) {
if (i > 0)
instr_ir += ", ";
instr_ir += "[ ";
instr_ir += print_as_op(this->get_operand(2 * i), false);
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(2 * i + 1), false);
instr_ir += " ]";
}
if (this->get_num_operand() / 2 <
this->get_parent()->get_pre_basic_blocks().size()) {
for (auto pre_bb : this->get_parent()->get_pre_basic_blocks()) {
if (std::find(this->get_operands().begin(),
this->get_operands().end(),
static_cast<Value *>(pre_bb)) ==
this->get_operands().end()) {
// find a pre_bb is not in phi
instr_ir += ", [ undef, " + print_as_op(pre_bb, false) + " ]";
}
}
}
return instr_ir;
}
#include "Instruction.hpp"
#include "BasicBlock.hpp"
#include "Function.hpp"
#include "IRprinter.hpp"
#include "Module.hpp"
#include "Type.hpp"
#include <algorithm>
#include <cassert>
#include <stdexcept>
#include <string>
#include <vector>
Instruction::Instruction(Type *ty, OpID id, BasicBlock *parent)
: User(ty, ""), op_id_(id), parent_(parent) {
if (parent)
parent->add_instruction(this);
}
Function *Instruction::get_function() { return parent_->get_parent(); }
Module *Instruction::get_module() { return parent_->get_module(); }
std::string Instruction::get_instr_op_name() const {
return print_instr_op_name(op_id_);
}
IBinaryInst::IBinaryInst(OpID id, Value *v1, Value *v2, BasicBlock *bb)
: BaseInst<IBinaryInst>(bb->get_module()->get_int32_type(), id, bb) {
assert(v1->get_type()->is_int32_type() && v2->get_type()->is_int32_type() &&
"IBinaryInst operands are not both i32");
add_operand(v1);
add_operand(v2);
}
IBinaryInst *IBinaryInst::create_add(Value *v1, Value *v2, BasicBlock *bb) {
return create(add, v1, v2, bb);
}
IBinaryInst *IBinaryInst::create_sub(Value *v1, Value *v2, BasicBlock *bb) {
return create(sub, v1, v2, bb);
}
IBinaryInst *IBinaryInst::create_mul(Value *v1, Value *v2, BasicBlock *bb) {
return create(mul, v1, v2, bb);
}
IBinaryInst *IBinaryInst::create_sdiv(Value *v1, Value *v2, BasicBlock *bb) {
return create(sdiv, v1, v2, bb);
}
FBinaryInst::FBinaryInst(OpID id, Value *v1, Value *v2, BasicBlock *bb)
: BaseInst<FBinaryInst>(bb->get_module()->get_float_type(), id, bb) {
assert(v1->get_type()->is_float_type() && v2->get_type()->is_float_type() &&
"FBinaryInst operands are not both float");
add_operand(v1);
add_operand(v2);
}
FBinaryInst *FBinaryInst::create_fadd(Value *v1, Value *v2, BasicBlock *bb) {
return create(fadd, v1, v2, bb);
}
FBinaryInst *FBinaryInst::create_fsub(Value *v1, Value *v2, BasicBlock *bb) {
return create(fsub, v1, v2, bb);
}
FBinaryInst *FBinaryInst::create_fmul(Value *v1, Value *v2, BasicBlock *bb) {
return create(fmul, v1, v2, bb);
}
FBinaryInst *FBinaryInst::create_fdiv(Value *v1, Value *v2, BasicBlock *bb) {
return create(fdiv, v1, v2, bb);
}
ICmpInst::ICmpInst(OpID id, Value *lhs, Value *rhs, BasicBlock *bb)
: BaseInst<ICmpInst>(bb->get_module()->get_int1_type(), id, bb) {
assert(lhs->get_type()->is_int32_type() &&
rhs->get_type()->is_int32_type() &&
"CmpInst operands are not both i32");
add_operand(lhs);
add_operand(rhs);
}
ICmpInst *ICmpInst::create_ge(Value *v1, Value *v2, BasicBlock *bb) {
return create(ge, v1, v2, bb);
}
ICmpInst *ICmpInst::create_gt(Value *v1, Value *v2, BasicBlock *bb) {
return create(gt, v1, v2, bb);
}
ICmpInst *ICmpInst::create_le(Value *v1, Value *v2, BasicBlock *bb) {
return create(le, v1, v2, bb);
}
ICmpInst *ICmpInst::create_lt(Value *v1, Value *v2, BasicBlock *bb) {
return create(lt, v1, v2, bb);
}
ICmpInst *ICmpInst::create_eq(Value *v1, Value *v2, BasicBlock *bb) {
return create(eq, v1, v2, bb);
}
ICmpInst *ICmpInst::create_ne(Value *v1, Value *v2, BasicBlock *bb) {
return create(ne, v1, v2, bb);
}
FCmpInst::FCmpInst(OpID id, Value *lhs, Value *rhs, BasicBlock *bb)
: BaseInst<FCmpInst>(bb->get_module()->get_int1_type(), id, bb) {
assert(lhs->get_type()->is_float_type() &&
rhs->get_type()->is_float_type() &&
"FCmpInst operands are not both float");
add_operand(lhs);
add_operand(rhs);
}
FCmpInst *FCmpInst::create_fge(Value *v1, Value *v2, BasicBlock *bb) {
return create(fge, v1, v2, bb);
}
FCmpInst *FCmpInst::create_fgt(Value *v1, Value *v2, BasicBlock *bb) {
return create(fgt, v1, v2, bb);
}
FCmpInst *FCmpInst::create_fle(Value *v1, Value *v2, BasicBlock *bb) {
return create(fle, v1, v2, bb);
}
FCmpInst *FCmpInst::create_flt(Value *v1, Value *v2, BasicBlock *bb) {
return create(flt, v1, v2, bb);
}
FCmpInst *FCmpInst::create_feq(Value *v1, Value *v2, BasicBlock *bb) {
return create(feq, v1, v2, bb);
}
FCmpInst *FCmpInst::create_fne(Value *v1, Value *v2, BasicBlock *bb) {
return create(fne, v1, v2, bb);
}
CallInst::CallInst(Function *func, std::vector<Value *> args, BasicBlock *bb)
: BaseInst<CallInst>(func->get_return_type(), call, bb) {
assert(func->get_type()->is_function_type() && "Not a function");
assert((func->get_num_of_args() == args.size()) && "Wrong number of args");
add_operand(func);
auto func_type = static_cast<FunctionType *>(func->get_type());
for (unsigned i = 0; i < args.size(); i++) {
assert(func_type->get_param_type(i) == args[i]->get_type() &&
"CallInst: Wrong arg type");
add_operand(args[i]);
}
}
CallInst *CallInst::create_call(Function *func, std::vector<Value *> args,
BasicBlock *bb) {
return create(func, args, bb);
}
FunctionType *CallInst::get_function_type() const {
return static_cast<FunctionType *>(get_operand(0)->get_type());
}
BranchInst::BranchInst(Value *cond, BasicBlock *if_true, BasicBlock *if_false,
BasicBlock *bb)
: BaseInst<BranchInst>(bb->get_module()->get_void_type(), br, bb) {
if (cond == nullptr) { // conditionless jump
assert(if_false == nullptr && "Given false-bb on conditionless jump");
add_operand(if_true);
// prev/succ
if_true->add_pre_basic_block(bb);
bb->add_succ_basic_block(if_true);
} else {
assert(cond->get_type()->is_int1_type() &&
"BranchInst condition is not i1");
add_operand(cond);
add_operand(if_true);
add_operand(if_false);
// prev/succ
if_true->add_pre_basic_block(bb);
if_false->add_pre_basic_block(bb);
bb->add_succ_basic_block(if_true);
bb->add_succ_basic_block(if_false);
}
}
BranchInst::~BranchInst() {
std::list<BasicBlock *> succs;
if (is_cond_br()) {
succs.push_back(static_cast<BasicBlock *>(get_operand(1)));
succs.push_back(static_cast<BasicBlock *>(get_operand(2)));
} else {
succs.push_back(static_cast<BasicBlock *>(get_operand(0)));
}
for (auto succ_bb : succs) {
if (succ_bb) {
succ_bb->remove_pre_basic_block(get_parent());
get_parent()->remove_succ_basic_block(succ_bb);
}
}
}
BranchInst *BranchInst::create_cond_br(Value *cond, BasicBlock *if_true,
BasicBlock *if_false, BasicBlock *bb) {
return create(cond, if_true, if_false, bb);
}
BranchInst *BranchInst::create_br(BasicBlock *if_true, BasicBlock *bb) {
return create(nullptr, if_true, nullptr, bb);
}
ReturnInst::ReturnInst(Value *val, BasicBlock *bb)
: BaseInst<ReturnInst>(bb->get_module()->get_void_type(), ret, bb) {
if (val == nullptr) {
assert(bb->get_parent()->get_return_type()->is_void_type());
} else {
assert(!bb->get_parent()->get_return_type()->is_void_type() &&
"Void function returning a value");
assert(bb->get_parent()->get_return_type() == val->get_type() &&
"ReturnInst type is different from function return type");
add_operand(val);
}
}
ReturnInst *ReturnInst::create_ret(Value *val, BasicBlock *bb) {
return create(val, bb);
}
ReturnInst *ReturnInst::create_void_ret(BasicBlock *bb) {
return create(nullptr, bb);
}
bool ReturnInst::is_void_ret() const { return get_num_operand() == 0; }
GetElementPtrInst::GetElementPtrInst(Value *ptr, std::vector<Value *> idxs,
BasicBlock *bb)
: BaseInst<GetElementPtrInst>(PointerType::get(get_element_type(ptr, idxs)),
getelementptr, bb) {
add_operand(ptr);
for (unsigned i = 0; i < idxs.size(); i++) {
Value *idx = idxs[i];
assert(idx->get_type()->is_integer_type() && "Index is not integer");
add_operand(idx);
}
}
Type *GetElementPtrInst::get_element_type(Value *ptr,
std::vector<Value *> idxs) {
assert(ptr->get_type()->is_pointer_type() &&
"GetElementPtrInst ptr is not a pointer");
Type *ty = ptr->get_type()->get_pointer_element_type();
assert(
"GetElementPtrInst ptr is wrong type" &&
(ty->is_array_type() || ty->is_integer_type() || ty->is_float_type()));
if (ty->is_array_type()) {
ArrayType *arr_ty = static_cast<ArrayType *>(ty);
for (unsigned i = 1; i < idxs.size(); i++) {
ty = arr_ty->get_element_type();
if (i < idxs.size() - 1) {
assert(ty->is_array_type() && "Index error!");
}
if (ty->is_array_type()) {
arr_ty = static_cast<ArrayType *>(ty);
}
}
}
return ty;
}
Type *GetElementPtrInst::get_element_type() const {
return get_type()->get_pointer_element_type();
}
GetElementPtrInst *GetElementPtrInst::create_gep(Value *ptr,
std::vector<Value *> idxs,
BasicBlock *bb) {
return create(ptr, idxs, bb);
}
StoreInst::StoreInst(Value *val, Value *ptr, BasicBlock *bb)
: BaseInst<StoreInst>(bb->get_module()->get_void_type(), store, bb) {
assert((ptr->get_type()->get_pointer_element_type() == val->get_type()) &&
"StoreInst ptr is not a pointer to val type");
add_operand(val);
add_operand(ptr);
}
StoreInst *StoreInst::create_store(Value *val, Value *ptr, BasicBlock *bb) {
return create(val, ptr, bb);
}
LoadInst::LoadInst(Value *ptr, BasicBlock *bb)
: BaseInst<LoadInst>(ptr->get_type()->get_pointer_element_type(), load,
bb) {
assert((get_type()->is_integer_type() or get_type()->is_float_type() or
get_type()->is_pointer_type()) &&
"Should not load value with type except int/float");
add_operand(ptr);
}
LoadInst *LoadInst::create_load(Value *ptr, BasicBlock *bb) {
return create(ptr, bb);
}
AllocaInst::AllocaInst(Type *ty, BasicBlock *bb)
: BaseInst<AllocaInst>(PointerType::get(ty), alloca, bb) {
static const std::array allowed_alloc_type = {
Type::IntegerTyID, Type::FloatTyID, Type::ArrayTyID, Type::PointerTyID};
assert(std::find(allowed_alloc_type.begin(), allowed_alloc_type.end(),
ty->get_type_id()) != allowed_alloc_type.end() &&
"Not allowed type for alloca");
}
AllocaInst *AllocaInst::create_alloca(Type *ty, BasicBlock *bb) {
return create(ty, bb);
}
ZextInst::ZextInst(Value *val, Type *ty, BasicBlock *bb)
: BaseInst<ZextInst>(ty, zext, bb) {
assert(val->get_type()->is_integer_type() &&
"ZextInst operand is not integer");
assert(ty->is_integer_type() && "ZextInst destination type is not integer");
assert((static_cast<IntegerType *>(val->get_type())->get_num_bits() <
static_cast<IntegerType *>(ty)->get_num_bits()) &&
"ZextInst operand bit size is not smaller than destination type bit "
"size");
add_operand(val);
}
ZextInst *ZextInst::create_zext(Value *val, Type *ty, BasicBlock *bb) {
return create(val, ty, bb);
}
ZextInst *ZextInst::create_zext_to_i32(Value *val, BasicBlock *bb) {
return create(val, bb->get_module()->get_int32_type(), bb);
}
FpToSiInst::FpToSiInst(Value *val, Type *ty, BasicBlock *bb)
: BaseInst<FpToSiInst>(ty, fptosi, bb) {
assert(val->get_type()->is_float_type() &&
"FpToSiInst operand is not float");
assert(ty->is_integer_type() &&
"FpToSiInst destination type is not integer");
add_operand(val);
}
FpToSiInst *FpToSiInst::create_fptosi(Value *val, Type *ty, BasicBlock *bb) {
return create(val, ty, bb);
}
FpToSiInst *FpToSiInst::create_fptosi_to_i32(Value *val, BasicBlock *bb) {
return create(val, bb->get_module()->get_int32_type(), bb);
}
SiToFpInst::SiToFpInst(Value *val, Type *ty, BasicBlock *bb)
: BaseInst<SiToFpInst>(ty, sitofp, bb) {
assert(val->get_type()->is_integer_type() &&
"SiToFpInst operand is not integer");
assert(ty->is_float_type() && "SiToFpInst destination type is not float");
add_operand(val);
}
SiToFpInst *SiToFpInst::create_sitofp(Value *val, BasicBlock *bb) {
return create(val, bb->get_module()->get_float_type(), bb);
}
PhiInst::PhiInst(Type *ty, std::vector<Value *> vals,
std::vector<BasicBlock *> val_bbs, BasicBlock *bb)
: BaseInst<PhiInst>(ty, phi) {
assert(vals.size() == val_bbs.size() && "Unmatched vals and bbs");
for (unsigned i = 0; i < vals.size(); i++) {
assert(ty == vals[i]->get_type() && "Bad type for phi");
add_operand(vals[i]);
add_operand(val_bbs[i]);
}
this->set_parent(bb);
}
PhiInst *PhiInst::create_phi(Type *ty, BasicBlock *bb,
std::vector<Value *> vals,
std::vector<BasicBlock *> val_bbs) {
return create(ty, vals, val_bbs, bb);
}
#include "Module.hpp"
#include "Function.hpp"
#include "GlobalVariable.hpp"
#include <memory>
#include <string>
Module::Module() {
void_ty_ = std::make_unique<Type>(Type::VoidTyID, this);
label_ty_ = std::make_unique<Type>(Type::LabelTyID, this);
int1_ty_ = std::make_unique<IntegerType>(1, this);
int32_ty_ = std::make_unique<IntegerType>(32, this);
float32_ty_ = std::make_unique<FloatType>(this);
}
Type *Module::get_void_type() { return void_ty_.get(); }
Type *Module::get_label_type() { return label_ty_.get(); }
IntegerType *Module::get_int1_type() { return int1_ty_.get(); }
IntegerType *Module::get_int32_type() { return int32_ty_.get(); }
FloatType *Module::get_float_type() { return float32_ty_.get(); }
PointerType *Module::get_int32_ptr_type() {
return get_pointer_type(int32_ty_.get());
}
PointerType *Module::get_float_ptr_type() {
return get_pointer_type(float32_ty_.get());
}
PointerType *Module::get_pointer_type(Type *contained) {
if (pointer_map_.find(contained) == pointer_map_.end()) {
pointer_map_[contained] = std::make_unique<PointerType>(contained);
}
return pointer_map_[contained].get();
}
ArrayType *Module::get_array_type(Type *contained, unsigned num_elements) {
if (array_map_.find({contained, num_elements}) == array_map_.end()) {
array_map_[{contained, num_elements}] =
std::make_unique<ArrayType>(contained, num_elements);
}
return array_map_[{contained, num_elements}].get();
}
FunctionType *Module::get_function_type(Type *retty,
std::vector<Type *> &args) {
if (not function_map_.count({retty, args})) {
function_map_[{retty, args}] =
std::make_unique<FunctionType>(retty, args);
}
return function_map_[{retty, args}].get();
}
void Module::add_function(Function *f) { function_list_.push_back(f); }
llvm::ilist<Function> &Module::get_functions() { return function_list_; }
void Module::add_global_variable(GlobalVariable *g) {
global_list_.push_back(g);
}
llvm::ilist<GlobalVariable> &Module::get_global_variable() {
return global_list_;
}
void Module::set_print_name() {
for (auto &func : this->get_functions()) {
func.set_instr_name();
}
return;
}
std::string Module::print() {
set_print_name();
std::string module_ir;
for (auto &global_val : this->global_list_) {
module_ir += global_val.print();
module_ir += "\n";
}
for (auto &func : this->function_list_) {
module_ir += func.print();
module_ir += "\n";
}
return module_ir;
}
#include "Type.hpp"
#include "Module.hpp"
#include <array>
#include <cassert>
#include <stdexcept>
Type::Type(TypeID tid, Module *m) {
tid_ = tid;
m_ = m;
}
bool Type::is_int1_type() const {
return is_integer_type() and
static_cast<const IntegerType *>(this)->get_num_bits() == 1;
}
bool Type::is_int32_type() const {
return is_integer_type() and
static_cast<const IntegerType *>(this)->get_num_bits() == 32;
}
Type *Type::get_pointer_element_type() const {
if (this->is_pointer_type())
return static_cast<const PointerType *>(this)->get_element_type();
assert(false and "get_pointer_element_type() called on non-pointer type");
}
Type *Type::get_array_element_type() const {
if (this->is_array_type())
return static_cast<const ArrayType *>(this)->get_element_type();
assert(false and "get_array_element_type() called on non-array type");
}
unsigned Type::get_size() const {
switch (get_type_id()) {
case IntegerTyID: {
if (is_int1_type())
return 1;
else if (is_int32_type())
return 4;
else
assert(false && "Type::get_size(): unexpected int type bits");
}
case ArrayTyID: {
auto array_type = static_cast<const ArrayType *>(this);
auto element_size = array_type->get_element_type()->get_size();
auto num_elements = array_type->get_num_of_elements();
return element_size * num_elements;
}
case PointerTyID:
return 8;
case FloatTyID:
return 4;
case VoidTyID:
case LabelTyID:
case FunctionTyID:
assert(false && "bad use on get_size()");
}
assert(false && "unreachable");
}
std::string Type::print() const {
std::string type_ir;
switch (this->get_type_id()) {
case VoidTyID:
type_ir += "void";
break;
case LabelTyID:
type_ir += "label";
break;
case IntegerTyID:
type_ir += "i";
type_ir += std::to_string(
static_cast<const IntegerType *>(this)->get_num_bits());
break;
case FunctionTyID:
type_ir +=
static_cast<const FunctionType *>(this)->get_return_type()->print();
type_ir += " (";
for (unsigned i = 0;
i < static_cast<const FunctionType *>(this)->get_num_of_args();
i++) {
if (i)
type_ir += ", ";
type_ir += static_cast<const FunctionType *>(this)
->get_param_type(i)
->print();
}
type_ir += ")";
break;
case PointerTyID:
type_ir += this->get_pointer_element_type()->print();
type_ir += "*";
break;
case ArrayTyID:
type_ir += "[";
type_ir += std::to_string(
static_cast<const ArrayType *>(this)->get_num_of_elements());
type_ir += " x ";
type_ir +=
static_cast<const ArrayType *>(this)->get_element_type()->print();
type_ir += "]";
break;
case FloatTyID:
type_ir += "float";
break;
default:
break;
}
return type_ir;
}
IntegerType::IntegerType(unsigned num_bits, Module *m)
: Type(Type::IntegerTyID, m), num_bits_(num_bits) {}
unsigned IntegerType::get_num_bits() const { return num_bits_; }
FunctionType::FunctionType(Type *result, std::vector<Type *> params)
: Type(Type::FunctionTyID, nullptr) {
assert(is_valid_return_type(result) && "Invalid return type for function!");
result_ = result;
for (auto p : params) {
assert(is_valid_argument_type(p) &&
"Not a valid type for function argument!");
args_.push_back(p);
}
}
bool FunctionType::is_valid_return_type(Type *ty) {
return ty->is_integer_type() || ty->is_void_type() || ty->is_float_type();
}
bool FunctionType::is_valid_argument_type(Type *ty) {
return ty->is_integer_type() || ty->is_pointer_type() ||
ty->is_float_type();
}
FunctionType *FunctionType::get(Type *result, std::vector<Type *> params) {
return result->get_module()->get_function_type(result, params);
}
unsigned FunctionType::get_num_of_args() const { return args_.size(); }
Type *FunctionType::get_param_type(unsigned i) const { return args_[i]; }
Type *FunctionType::get_return_type() const { return result_; }
ArrayType::ArrayType(Type *contained, unsigned num_elements)
: Type(Type::ArrayTyID, contained->get_module()),
num_elements_(num_elements) {
assert(is_valid_element_type(contained) &&
"Not a valid type for array element!");
contained_ = contained;
}
bool ArrayType::is_valid_element_type(Type *ty) {
return ty->is_integer_type() || ty->is_array_type() || ty->is_float_type();
}
ArrayType *ArrayType::get(Type *contained, unsigned num_elements) {
return contained->get_module()->get_array_type(contained, num_elements);
}
PointerType::PointerType(Type *contained)
: Type(Type::PointerTyID, contained->get_module()), contained_(contained) {
static const std::array allowed_elem_type = {
Type::IntegerTyID, Type::FloatTyID, Type::ArrayTyID, Type::PointerTyID};
auto elem_type_id = contained->get_type_id();
assert(std::find(allowed_elem_type.begin(), allowed_elem_type.end(),
elem_type_id) != allowed_elem_type.end() &&
"Not allowed type for pointer");
}
PointerType *PointerType::get(Type *contained) {
return contained->get_module()->get_pointer_type(contained);
}
FloatType::FloatType(Module *m) : Type(Type::FloatTyID, m) {}
FloatType *FloatType::get(Module *m) { return m->get_float_type(); }
#include "User.hpp"
#include <cassert>
void User::set_operand(unsigned i, Value *v) {
assert(i < operands_.size() && "set_operand out of index");
if (operands_[i]) { // old operand
operands_[i]->remove_use(this, i);
}
if (v) { // new operand
v->add_use(this, i);
}
operands_[i] = v;
}
void User::add_operand(Value *v) {
assert(v != nullptr && "bad use: add_operand(nullptr)");
v->add_use(this, operands_.size());
operands_.push_back(v);
}
void User::remove_all_operands() {
for (unsigned i = 0; i != operands_.size(); ++i) {
if (operands_[i]) {
operands_[i]->remove_use(this, i);
}
}
operands_.clear();
}
void User::remove_operand(unsigned idx) {
assert(idx < operands_.size() && "remove_operand out of index");
// influence on other operands
for (unsigned i = idx + 1; i < operands_.size(); ++i) {
operands_[i]->remove_use(this, i);
operands_[i]->add_use(this, i - 1);
}
// remove the designated operand
operands_[idx]->remove_use(this, idx);
operands_.erase(operands_.begin() + idx);
}
#include "Value.hpp"
#include "Type.hpp"
#include "User.hpp"
#include <cassert>
bool Value::set_name(std::string name) {
if (name_ == "") {
name_ = name;
return true;
}
return false;
}
void Value::add_use(User *user, unsigned arg_no) {
use_list_.emplace_back(user, arg_no);
};
void Value::remove_use(User *user, unsigned arg_no) {
auto target_use = Use(user, arg_no);
use_list_.remove_if([&](const Use &use) { return use == target_use; });
}
void Value::replace_all_use_with(Value *new_val) {
if (this == new_val)
return;
while (use_list_.size()) {
auto use = use_list_.begin();
use->val_->set_operand(use->arg_no_, new_val);
}
}
void Value::replace_use_with_if(Value *new_val,
std::function<bool(Use *)> should_replace) {
if (this == new_val)
return;
for (auto iter = use_list_.begin(); iter != use_list_.end();) {
auto use = *iter++;
if (not should_replace(&use))
continue;
use.val_->set_operand(use.arg_no_, new_val);
}
}
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<syntax_analyzer.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syntax_analyzer.h>
///
extern int lines;
......@@ -31,11 +31,11 @@ int main(int argc, const char **argv) {
}
int token;
printf("%5s\t%10s\t%s\t%s\n", "Token", "Text", "Line", "Column (Start,End)");
printf("%5s\t%10s\t%s\t%s\n", "Token", "Text", "Line",
"Column (Start,End)");
while ((token = yylex())) {
printf("%-5d\t%10s\t%d\t(%d,%d)\n",
token, yytext,
lines, pos_start, pos_end);
printf("%-5d\t%10s\t%d\t(%d,%d)\n", token, yytext, lines, pos_start,
pos_end);
}
return 0;
}
#include "syntax_tree.h"
extern syntax_tree *parse(const char*);
extern syntax_tree *parse(const char *);
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
syntax_tree *tree = NULL;
const char *input = NULL;
if (argc == 2) {
input = argv[1];
} else if(argc >= 3) {
} else if (argc >= 3) {
printf("usage: %s <cminus_file>\n", argv[0]);
return 1;
}
......
......@@ -25,7 +25,7 @@ function run_tests() {
echo "[info] Analyzing $filename"
# 生成学生的 AST 文件
"$BUILD_DIR"/cminusfc "$testcase" > "$OUTPUT_DIR/${filename%.cminus}.ast"
"$BUILD_DIR"/cminusfc -emit-ast "$testcase" > "$OUTPUT_DIR/${filename%.cminus}.ast"
# 比较当前文件的输出与标准输出
if [[ ${2:-no} != "no" ]]; then
......
3
1
4
1
5
9
2
6
5
3
5
8
9
7
9
3
2
3
8
4
6
2
6
4
3
3
8
3
2
7
9
5
0
2
8
8
4
1
9
7
1
6
9
3
9
9
3
7
5
1
0
5
8
2
0
9
7
4
9
4
4
5
9
2
3
0
7
8
1
6
4
0
6
2
8
6
2
0
8
9
9
8
6
2
8
0
3
4
8
2
5
3
4
2
1
1
7
0
6
7
9
8
2
1
4
8
0
8
6
5
1
3
2
8
2
3
0
6
6
4
7
0
9
3
8
4
4
6
0
9
5
5
0
5
8
2
2
3
1
7
2
5
3
5
9
4
0
8
1
2
8
4
8
1
1
1
7
4
5
0
2
8
4
1
0
2
7
0
1
9
3
8
5
2
1
1
0
5
5
5
9
6
4
4
6
2
2
9
4
8
9
5
4
9
3
0
3
8
1
9
6
4
4
2
8
8
1
0
9
7
5
6
6
5
9
3
3
4
4
6
1
2
8
4
7
5
6
4
8
2
3
3
7
8
6
7
8
3
1
6
5
2
7
1
2
0
1
9
0
9
1
4
5
6
4
8
5
6
6
9
2
3
4
6
0
3
4
8
6
1
0
4
5
4
3
2
6
6
4
8
2
1
3
3
9
3
6
0
7
2
6
0
2
4
9
1
4
1
2
7
3
7
2
4
5
8
7
0
0
6
6
0
6
3
1
5
5
8
8
1
7
4
8
8
1
5
2
0
9
2
0
9
6
2
8
2
9
2
5
4
0
9
1
7
1
5
3
6
4
3
6
7
8
9
2
5
9
0
3
6
0
0
1
1
3
3
0
5
3
0
5
4
8
8
2
0
4
6
6
5
2
1
3
8
4
1
4
6
9
5
1
9
4
1
5
1
1
6
0
9
4
3
3
0
5
7
2
7
0
3
6
5
7
5
9
5
9
1
9
5
3
0
9
2
1
8
6
1
1
7
3
8
1
9
3
2
6
1
1
7
9
3
1
0
5
1
1
8
5
4
8
0
7
4
4
6
2
3
7
9
9
6
2
7
4
9
5
6
7
3
5
1
8
8
5
7
5
2
7
2
4
8
9
1
2
2
7
9
3
8
1
8
3
0
1
1
9
4
9
1
2
9
8
3
3
6
7
3
3
6
2
4
4
0
6
5
6
6
4
3
0
8
6
0
2
1
3
9
4
9
4
6
3
9
5
2
2
4
7
3
7
1
9
0
7
0
2
1
7
9
8
6
0
9
4
3
7
0
2
7
7
0
5
3
9
2
1
7
1
7
6
2
9
3
1
7
6
7
5
2
3
8
4
6
7
4
8
1
8
4
6
7
6
6
9
4
0
5
1
3
2
0
0
0
5
6
8
1
2
7
1
4
5
2
6
3
5
6
0
8
2
7
7
8
5
7
7
1
3
4
2
7
5
7
7
8
9
6
0
9
1
7
3
6
3
7
1
7
8
7
2
1
4
6
8
4
4
0
9
0
1
2
2
4
9
5
3
4
3
0
1
4
6
5
4
9
5
8
5
3
7
1
0
5
0
7
9
2
2
7
9
6
8
9
2
5
8
9
2
3
5
4
2
0
1
9
9
5
6
1
1
2
1
2
9
0
2
1
9
6
0
8
6
4
0
3
4
4
1
8
1
5
9
8
1
3
6
2
9
7
7
4
7
7
1
3
0
9
9
6
0
5
1
8
7
0
7
2
1
1
3
4
9
9
9
9
9
9
8
3
7
2
9
7
8
0
4
9
9
5
1
0
5
9
7
3
1
7
3
2
8
1
6
0
9
6
3
1
8
5
#!/usr/bin/env python3
import subprocess
# 17
lv0_1 = {
"return": (3, False),
"decl_int": (2, False),
"decl_float": (2, False),
"decl_int_array": (2, False),
"decl_float_array": (2, False),
"input": (2, True),
"output_float": (2, False),
"output_int": (2, False),
}
# 18
lv0_2 = {
"num_add_int": (0.5, False),
"num_sub_int": (0.5, False),
"num_mul_int": (0.5, False),
"num_div_int": (0.5, False),
"num_add_float": (0.5, False),
"num_sub_float": (0.5, False),
"num_mul_float": (0.5, False),
"num_div_float": (0.5, False),
"num_add_mixed": (0.5, False),
"num_sub_mixed": (0.5, False),
"num_mul_mixed": (0.5, False),
"num_div_mixed": (0.5, False),
"num_comp1": (1.5, False),
"num_le_int": (0.5, False),
"num_lt_int": (0.5, False),
"num_ge_int": (0.5, False),
"num_gt_int": (0.5, False),
"num_eq_int": (0.5, False),
"num_neq_int": (0.5, False),
"num_le_float": (0.5, False),
"num_lt_float": (0.5, False),
"num_ge_float": (0.5, False),
"num_gt_float": (0.5, False),
"num_eq_float": (0.5, False),
"num_neq_float": (0.5, False),
"num_le_mixed": (0.5, False),
"num_lt_mixed": (0.5, False),
"num_ge_mixed": (0.5, False),
"num_gt_mixed": (0.5, False),
"num_eq_mixed": (0.5, False),
"num_neq_mixed": (0.5, False),
"num_comp2": (1.5, False),
}
# 31
lv1 = {
"assign_int_var_local": (1, False),
"assign_int_array_local": (2, False),
"assign_int_var_global": (1, False),
"assign_int_array_global": (2, False),
"assign_float_var_local": (1, False),
"assign_float_array_local": (2, False),
"assign_float_var_global": (1, False),
"assign_float_array_global": (2, False),
"assign_cmp": (1, False),
"innout": (1, True),
"idx_float": (1, False),
"negidx_int": (1, False),
"negidx_float": (1, False),
"negidx_intfuncall": (1, False),
"negidx_floatfuncall": (1, False),
"negidx_voidfuncall": (1, False),
"selection1": (1.5, False),
"selection2": (1.5, False),
"selection3": (1.5, False),
"iteration1": (1.5, False),
"iteration2": (1.5, False),
"scope": (1.5, False),
"transfer_float_to_int": (1, False),
"transfer_int_to_float": (1, False),
}
# 23
lv2 = {
"funcall_chain": (2, False),
"assign_chain": (2, False),
"funcall_var": (2, False),
"funcall_int_array": (2, False),
"funcall_float_array": (2, False),
"funcall_array_array": (2, False),
"return_in_middle1": (2, False),
"return_in_middle2": (2, False),
"funcall_type_mismatch1": (2, False),
"funcall_type_mismatch2": (2, False),
"return_type_mismatch1": (1.5, False),
"return_type_mismatch2": (1.5, False),
}
# 11
lv3 = {
"complex1": (3, False),
"complex2": (3, True),
"complex3": (2, True),
"complex4": (3, False),
}
suite = [
("lv0_1", lv0_1, 0),
("lv0_2", lv0_2, 0),
("lv1", lv1, 0),
("lv2", lv2, 0),
("lv3", lv3, 0)
]
def eval():
f = open("eval_result", 'w')
EXE_PATH = "../../../build/cminusfc"
TEST_BASE_PATH = "./testcases/"
ANSWER_BASE_PATH = "./answers/"
total_points = 0
for level in suite:
lv_points = 0
has_bonus = True
level_name = level[0]
bonus = level[2]
cases = level[1]
f.write('===========%s START========\n' % level_name)
for case in cases:
f.write('%s:' % case)
TEST_PATH = TEST_BASE_PATH + level_name + "/" + case
ANSWER_PATH = ANSWER_BASE_PATH + level_name + "/" + case
score = cases[case][0]
need_input = cases[case][1]
COMMAND = [TEST_PATH]
try:
result = subprocess.run([EXE_PATH, "-o", TEST_PATH + ".ll", "-emit-llvm",
TEST_PATH + ".cminus"], stderr=subprocess.PIPE, timeout=1)
except Exception as _:
f.write('\tFail\n')
continue
if result.returncode == 0:
subprocess.run(["clang", "-O0", "-w", "-no-pie", TEST_PATH +
".ll", "-o", TEST_PATH, "-L", "../../../build", "-lcminus_io"])
input_option = None
if need_input:
with open(ANSWER_PATH + ".in", "rb") as fin:
input_option = fin.read()
try:
result = subprocess.run(
COMMAND, input=input_option, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1)
with open(ANSWER_PATH + ".out", "rb") as fout:
if result.stdout == fout.read():
f.write('\tSuccess\n')
lv_points += score
else:
f.write('\tFail\n')
has_bonus = False
except Exception as _:
f.write('\tFail\n')
has_bonus = False
finally:
subprocess.call(
["rm", "-rf", TEST_PATH, TEST_PATH + ".o", TEST_PATH + ".ll"])
else:
f.write('\tFail\n')
has_bonus = False
if has_bonus:
lv_points += bonus
total_points += lv_points
f.write('points of %s is: %d\n' % (level_name, lv_points))
f.write('===========%s END========\n\n' % level_name)
f.write('total points: %d\n' % total_points)
if __name__ == "__main__":
eval()
#!/bin/bash
python3 eval_lab2.py
void main(void) {
input();
return;
}
void main(void) {
outputFloat(123.4);
return;
}
void main(void) {
output(1234);
return;
}
void main(void) {
output(100.0 + 23.4);
return;
}
void main(void) {
output(1000 + 234);
return;
}
void main(void) {
output(1000 + 23.4);
return;
}
void main(void) {
outputFloat(9 + 1.2 / (2 * 2 + 5 - 6) * 3.2 - 55);
return;
}
void main(void) {
output((1 > 2.) < 3);
output((1 > 2) < ((3 == 4) >= 0));
output(((3 == 4.) >= 0) <= (4 != 4));
output(((1 > 2) < ((3 == 4) >= 0)) <= (4. != 4));
return;
}
void main(void) {
output(24.68 / 2.);
return;
}
void main(void) {
output(2468 / 2);
return;
}
void main(void) {
output(24.68 / 2);
return;
}
void main(void) {
output(1. == 2.);
output(2. == 2.);
output(3. == 2.);
return;
}
void main(void) {
output(1 == 2);
output(2 == 2);
output(3 == 2);
return;
}
void main(void) {
output(1. == 2);
output(2. == 2);
output(3 == 2.);
return;
}
void main(void) {
output(1. >= 2.);
output(2. >= 2.);
output(3. >= 2.);
return;
}
void main(void) {
output(1 >= 2);
output(2 >= 2);
output(3 >= 2);
return;
}
void main(void) {
output(1. >= 2);
output(2. >= 2);
output(3 >= 2.);
return;
}
void main(void) {
output(1. > 2.);
output(2. > 2.);
output(3. > 2.);
return;
}
void main(void) {
output(1 > 2);
output(2 > 2);
output(3 > 2);
return;
}
void main(void) {
output(1. > 2);
output(2. > 2);
output(3 > 2.);
return;
}
void main(void) {
output(1. <= 2.);
output(2. <= 2.);
output(3. <= 2.);
return;
}
void main(void) {
output(1 <= 2);
output(2 <= 2);
output(3 <= 2);
return;
}
void main(void) {
output(1. <= 2);
output(2. <= 2);
output(3 <= 2.);
return;
}
void main(void) {
output(1. < 2.);
output(2. < 2.);
output(3. < 2.);
return;
}
void main(void) {
output(1 < 2);
output(2 < 2);
output(3 < 2);
return;
}
void main(void) {
output(1. < 2);
output(2 < 2.);
output(3. < 2);
return;
}
void main(void) {
output(2. * 61.7);
return;
}
void main(void) {
output(2 * 617);
return;
}
void main(void) {
output(2 * 61.7);
return;
}
void main(void) {
output(1. != 2.);
output(2. != 2.);
output(3. != 2.);
return;
}
void main(void) {
output(1 != 2);
output(2 != 2);
output(3 != 2);
return;
}
void main(void) {
output(1. != 2);
output(2 != 2.);
output(3 != 2.);
return;
}
void main(void) {
output(200.0 - 7.66);
return;
}
void main(void) {
output(2000 - 766);
return;
}
void main(void) {
output(2000 - 76.6);
return;
}
void main(void) {
int a;
int b;
int c;
a = 1 < 3;
b = 2 == 4;
c = 3 > 5;
output(a);
output(b);
output(c);
return;
}
float b[10];
void main(void) {
b[3] = 1234.0;
outputFloat(b[3]);
return;
}
void main(void) {
float b[10];
b[3] = 1234.0;
outputFloat(b[3]);
return;
}
float b;
void main(void) {
b = 1234.0;
outputFloat(b);
return;
}
void main(void) {
float b;
b = 1234.0;
outputFloat(b);
return;
}
int a[10];
void main(void) {
a[3] = 1234;
output(a[3]);
return;
}
void main(void) {
int a[10];
a[3] = 1234;
output(a[3]);
return;
}
int a;
void main(void) {
a = 1234;
output(a);
return;
}
void main(void) {
int a;
a = 1234;
output(a);
return;
}
void main(void) {
int a[10];
a[0] = 1024;
output(a[0.1]);
return;
}
void main(void) {
int a;
a = input();
output(a);
return;
}
void main(void) {
int i;
i = 10;
while (i) {
output(i);
i = i - 1;
}
return;
}
void main(void) {
int i;
i = 10;
while (i > 0) {
output(i);
i = i - 1;
}
return;
}
void main(void) {
int a[10];
a[2. - 3];
return;
}
float test(void) {
int a[10];
a[2 - 3];
return 2.;
}
void main(void) {
test();
return;
}
void main(void) {
int a[10];
a[2 - 3];
return;
}
int test(void) {
int a[10];
a[2 - 3];
return 2;
}
void main(void) {
test();
return;
}
void test(void) {
int a[10];
a[2 - 3];
return;
}
void main(void) {
test();
return;
}
void main(void) {
int a;
a = 3;
output(a);
{
int a;
a = 11;
output(a);
}
output(a);
return;
}
void main(void) {
int a;
a = 2;
if (a)
output(42);
output(24);
return;
}
void main(void) {
if (2 > 1)
output(42);
output(24);
if (1 > 2) {
output(1234);
}
return;
}
void main(void) {
if (2 > 1) {
output(42);
} else
output(1234);
output(24);
if (2 < 1)
output(42);
else {
output(1234);
}
return;
}
void main(void) {
int a;
a = 1.0;
output(a);
return;
}
void main(void) {
float a;
a = 1;
outputFloat(a);
return;
}
void main(void) {
int a;
int b;
int c;
a = b = c = 3;
output(a);
output(b);
output(c);
return;
}
void g(int b[]) {
output(b[3]);
return;
}
void f(int c[]) {
output(c[3]);
g(c);
return;
}
void main(void) {
int a[10];
a[3] = 1024;
f(a);
return;
}
int addone(int a) { return a + 1; }
void main(void) {
int result;
result = addone(addone(addone(addone(1230))));
output(result);
return;
}
void test(float a[]) {
output(a[3]);
return;
}
void main(void) {
float a[10];
a[3] = 3.14;
test(a);
return;
}
void test(int a[]) {
output(a[3]);
return;
}
void main(void) {
int a[10];
a[3] = 10;
test(a);
return;
}
void f(int a) {
output(a);
return;
}
void main(void) {
float a;
a = 10;
f(a);
return;
}
void f(float a) {
outputFloat(a);
return;
}
void main(void) {
int a;
a = 4.5;
f(a);
return;
}
void test(int a) {
output(a);
return;
}
void main(void) {
int a;
a = 10;
test(a);
return;
}
int result(void) {
int i;
if (1) {
i = 1;
return 0;
} else {
i = 2;
}
output(3);
return 3;
}
void main(void) {
output(result());
return;
}
int result(void) {
int i;
i = 10;
while (i > 0) {
return 0;
}
output(4);
return 1;
}
void main(void) {
output(result());
return;
}
int f(void) { return 233.3; }
void main(void) {
output(f());
return;
}
float f(void) { return 7; }
void main(void) {
outputFloat(f());
return;
}
/*
This code is adapted from Dik T. Winter at CWI
It computes pi to 800 decimal digits
*/
int mod(int a, int b) { return a - a / b * b; }
void printfour(int input) {
int a;
int b;
int c;
int d;
input = mod(input, 10000);
d = mod(input, 10);
input = input / 10;
c = mod(input, 10);
input = input / 10;
b = mod(input, 10);
input = input / 10;
a = input;
output(a);
output(b);
output(c);
output(d);
return;
}
void main(void) {
int r[2801];
int i;
int k;
int b;
int d;
int c;
c = 0;
d = 1234;
{
int mod;
mod = 0;
while (mod < 2800) {
r[mod] = 2000;
mod = mod + 1;
}
}
k = 2800;
while (k) {
int d;
d = 0;
i = k;
while (i != 0) {
d = d + r[i] * 10000;
b = 2 * i - 1;
r[i] = mod(d, b);
d = d / b;
i = i - 1;
if (i != 0) {
d = d * i;
}
}
printfour(c + d / 10000);
c = mod(d, 10000);
k = k - 14;
}
return;
}
/* this is the sample program in C- in the book "Compiler Construction" */
/* A program to perform selection sort on a 10 element array. */
float x[10];
int minloc(float a[], float low, int high) {
int i;
int x;
int k;
k = low;
x = a[low];
i = low + 1;
while (i < high) {
if (a[i] < x) {
x = a[i];
k = i;
}
i = i + 1;
}
return k;
}
void sort(float a[], int low, float high) {
int i;
int k;
i = low;
while (i < high - 1) {
int t;
k = minloc(a, i, high);
t = a[k];
a[k] = a[i];
a[i] = t;
i = i + 1;
}
return;
}
void main(void) {
int i;
i = 0;
while (i < 10) {
x[i] = input();
i = i + 1;
}
sort(x, 0, 10);
i = 0;
while (i < 10) {
output(x[i]);
i = i + 1;
}
return;
}
int gcd(int u, int v) {
if (v == 0)
return u;
else
return gcd(v, u - u / v * v);
}
void main(void) {
int x;
int y;
int temp;
x = input();
y = input();
if (x < y) {
temp = x;
x = y;
y = temp;
}
temp = gcd(x, y);
output(temp);
return;
}
float get(float a[], int x, int y, int row) { return a[x * row + y]; }
float abs(float x) {
if (x > 0)
return x;
else
return 0 - x;
}
float isZero(float t) { return abs(t) < 0.000001; }
int gauss(float vars[], float equ[], int var) {
int i;
int j;
int k;
int varone;
int maxr;
int col;
float temp;
varone = var + 1;
i = 0;
while (i < var) {
vars[i] = 0;
i = i + 1;
}
col = 0;
k = 0;
while (k < var) {
maxr = k;
i = k + 1;
while (i < var) {
if (abs(get(equ, i, col, varone)) > abs(get(equ, maxr, col, varone)))
maxr = i;
i = i + 1;
}
if (maxr != k) {
j = k;
while (j < varone) {
temp = get(equ, k, j, varone);
equ[k * varone + j] = get(equ, maxr, j, varone);
equ[maxr * varone + j] = temp;
j = j + 1;
}
}
if (isZero(get(equ, k, col, varone))) {
k = k - 1;
} else {
i = k + 1;
while (i < var) {
if (1 - isZero(get(equ, i, col, varone))) {
temp = get(equ, i, col, varone) / get(equ, k, col, varone);
j = col;
while (j < varone) {
equ[i * varone + j] = equ[i * varone + j] - get(equ, k, j, varone) * temp;
j = j + 1;
}
}
i = i + 1;
}
}
k = k + 1;
col = col + 1;
}
i = var - 1;
while (i >= 0) {
temp = get(equ, i, var, varone);
j = i + 1;
while (j < var) {
if (1 - isZero(get(equ, i, j, varone)))
temp = temp - get(equ, i, j, varone) * vars[j];
j = j + 1;
}
vars[i] = temp / get(equ, i, i, varone);
i = i - 1;
}
return 0;
}
void main(void) {
int num;
float vars[3];
float equ[12];
equ[0] = 1;
equ[1] = 2;
equ[2] = 1;
equ[3] = 1;
equ[1 * 4 + 0] = 2;
equ[1 * 4 + 1] = 3;
equ[1 * 4 + 2] = 4;
equ[1 * 4 + 3] = 3;
equ[2 * 4 + 0] = 1;
equ[2 * 4 + 1] = 1;
equ[2 * 4 + 2] = 0 - 2;
equ[2 * 4 + 3] = 0;
gauss(vars, equ, 3);
num = 0;
while (num < 3) {
outputFloat(vars[num]);
num = num + 1;
}
}
add_subdirectory(calculator)
add_executable(
gcd_array_generator
ta_gcd/gcd_array_generator.cpp
)
target_link_libraries(
gcd_array_generator
IR_lib
)
add_executable(
stu_assign_generator
stu_cpp/assign_generator.cpp
)
target_link_libraries(
stu_assign_generator
IR_lib
)
add_executable(
stu_fun_generator
stu_cpp/fun_generator.cpp
)
target_link_libraries(
stu_fun_generator
IR_lib
)
add_executable(
stu_if_generator
stu_cpp/if_generator.cpp
)
target_link_libraries(
stu_if_generator
IR_lib
)
add_executable(
stu_while_generator
stu_cpp/while_generator.cpp
)
target_link_libraries(
stu_while_generator
IR_lib
)
int main() {
int a[10];
a[0] = 10;
a[1] = a[0] * 2;
return a[1];
}
int callee(int a) { return 2 * a; }
int main() { return callee(110); }
int main() {
float a = 5.555;
if (a > 1)
return 233;
return 0;
}
int main() {
int a;
int i;
a = 10;
i = 0;
while (i < 10) {
i = i + 1;
a = a + i;
}
return a;
}
flex_target(calc_lex calculator.l ${CMAKE_CURRENT_BINARY_DIR}/calc_lex.c)
bison_target(calc_syntax calculator.y
${CMAKE_CURRENT_BINARY_DIR}/calc_syntax.c
DEFINES_FILE ${PROJECT_BINARY_DIR}/calculator.h)
add_flex_bison_dependency(calc_lex calc_syntax)
add_library(calc_syntax STATIC
${BISON_calc_syntax_OUTPUTS}
${FLEX_calc_lex_OUTPUTS}
)
add_executable(
calc
calc.cpp
calc_ast.cpp
calc_builder.cpp
)
target_link_libraries(
calc
IR_lib
calc_syntax
common
)
install(
TARGETS calc
RUNTIME DESTINATION bin
)
\ No newline at end of file
extern "C" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char *);
}
#include "calc_ast.hpp"
#include "calc_builder.hpp"
#include <cstdio>
#include <fstream>
using namespace std::literals::string_literals;
int main(int argc, char *argv[]) {
syntax_tree *tree = NULL;
const char *input = NULL;
if (argc >= 3) {
printf("usage: %s\n", argv[0]);
printf("usage: %s <cminus_file>\n", argv[0]);
return 1;
}
if (argc == 2) {
input = argv[1];
} else {
printf("Input an arithmatic expression (press Ctrl+D in a new line after you finish the expression):\n");
}
tree = parse(input);
CalcAST ast(tree);
CalcBuilder builder;
auto module = builder.build(ast);
auto IR = module->print();
std::ofstream output_stream;
auto output_file = "result.ll";
output_stream.open(output_file, std::ios::out);
output_stream << "; ModuleID = 'calculator'\n";
output_stream << IR;
output_stream.close();
auto command_string = "clang -O0 -w "s + "result.ll -o result -L. -lcminus_io";
auto ret = std::system(command_string.c_str());
if (ret) {
printf("something went wrong!\n");
} else {
printf("result and result.ll have been generated.\n");
}
return ret;
}
#include "calc_ast.hpp"
#include <cstring>
#include <iostream>
#include <stack>
#define _AST_NODE_ERROR_ \
std::cerr << "Abort due to node cast error." \
"Contact with TAs to solve your problem." \
<< std::endl; \
std::abort();
#define _STR_EQ(a, b) (strcmp((a), (b)) == 0)
void CalcAST::run_visitor(CalcASTVisitor &visitor) { root->accept(visitor); }
CalcAST::CalcAST(syntax_tree *s) {
if (s == nullptr) {
std::cerr << "empty input tree!" << std::endl;
std::abort();
}
auto node = transform_node_iter(s->root);
del_syntax_tree(s);
root = std::shared_ptr<CalcASTInput>(static_cast<CalcASTInput *>(node));
}
CalcASTNode *CalcAST::transform_node_iter(syntax_tree_node *n) {
if (_STR_EQ(n->name, "input")) {
auto node = new CalcASTInput();
auto expr_node = static_cast<CalcASTExpression *>(
transform_node_iter(n->children[0]));
node->expression = std::shared_ptr<CalcASTExpression>(expr_node);
return node;
} else if (_STR_EQ(n->name, "expression")) {
auto node = new CalcASTExpression();
if (n->children_num == 3) {
auto add_expr_node = static_cast<CalcASTExpression *>(
transform_node_iter(n->children[0]));
node->expression =
std::shared_ptr<CalcASTExpression>(add_expr_node);
auto op_name = n->children[1]->children[0]->name;
if (_STR_EQ(op_name, "+"))
node->op = OP_PLUS;
else if (_STR_EQ(op_name, "-"))
node->op = OP_MINUS;
auto term_node =
static_cast<CalcASTTerm *>(transform_node_iter(n->children[2]));
node->term = std::shared_ptr<CalcASTTerm>(term_node);
} else {
auto term_node =
static_cast<CalcASTTerm *>(transform_node_iter(n->children[0]));
node->term = std::shared_ptr<CalcASTTerm>(term_node);
}
return node;
} else if (_STR_EQ(n->name, "term")) {
auto node = new CalcASTTerm();
if (n->children_num == 3) {
auto term_node =
static_cast<CalcASTTerm *>(transform_node_iter(n->children[0]));
node->term = std::shared_ptr<CalcASTTerm>(term_node);
auto op_name = n->children[1]->children[0]->name;
if (_STR_EQ(op_name, "*"))
node->op = OP_MUL;
else if (_STR_EQ(op_name, "/"))
node->op = OP_DIV;
auto factor_node = static_cast<CalcASTFactor *>(
transform_node_iter(n->children[2]));
node->factor = std::shared_ptr<CalcASTFactor>(factor_node);
} else {
auto factor_node = static_cast<CalcASTFactor *>(
transform_node_iter(n->children[0]));
node->factor = std::shared_ptr<CalcASTFactor>(factor_node);
}
return node;
} else if (_STR_EQ(n->name, "factor")) {
if (n->children_num == 3) {
return transform_node_iter(n->children[1]);
} else {
auto num_node = new CalcASTNum();
num_node->val = std::stoi(n->children[0]->children[0]->name);
return num_node;
}
} else {
std::cerr << "[calc_ast]: transform failure!" << std::endl;
std::abort();
}
}
void CalcASTNum::accept(CalcASTVisitor &visitor) { visitor.visit(*this); }
void CalcASTTerm::accept(CalcASTVisitor &visitor) { visitor.visit(*this); }
void CalcASTExpression::accept(CalcASTVisitor &visitor) {
visitor.visit(*this);
}
void CalcASTInput::accept(CalcASTVisitor &visitor) {
expression->accept(visitor);
}
void CalcASTFactor::accept(CalcASTVisitor &visitor) {
auto expr = dynamic_cast<CalcASTExpression *>(this);
if (expr) {
expr->accept(visitor);
return;
}
auto num = dynamic_cast<CalcASTNum *>(this);
if (num) {
num->accept(visitor);
return;
}
_AST_NODE_ERROR_
}
#pragma once
extern "C" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char *input);
}
#include <memory>
#include <vector>
enum AddOp {
// +
OP_PLUS,
// -
OP_MINUS
};
enum MulOp {
// *
OP_MUL,
// /
OP_DIV
};
class CalcAST;
struct CalcASTNode;
struct CalcASTInput;
struct CalcASTExpression;
struct CalcASTNum;
struct CalcASTTerm;
struct CalcASTFactor;
class CalcASTVisitor;
class CalcAST {
public:
CalcAST() = delete;
CalcAST(syntax_tree *);
CalcAST(CalcAST &&tree) {
root = tree.root;
tree.root = nullptr;
}
CalcASTInput *get_root() { return root.get(); }
void run_visitor(CalcASTVisitor &visitor);
private:
CalcASTNode *transform_node_iter(syntax_tree_node *);
std::shared_ptr<CalcASTInput> root = nullptr;
};
struct CalcASTNode {
virtual void accept(CalcASTVisitor &) = 0;
virtual ~CalcASTNode() = default;
};
struct CalcASTInput : CalcASTNode {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression;
};
struct CalcASTFactor : CalcASTNode {
virtual void accept(CalcASTVisitor &) override;
};
struct CalcASTNum : CalcASTFactor {
virtual void accept(CalcASTVisitor &) override final;
int val;
};
struct CalcASTExpression : CalcASTFactor {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTExpression> expression;
AddOp op;
std::shared_ptr<CalcASTTerm> term;
};
struct CalcASTTerm : CalcASTNode {
virtual void accept(CalcASTVisitor &) override final;
std::shared_ptr<CalcASTTerm> term;
MulOp op;
std::shared_ptr<CalcASTFactor> factor;
};
class CalcASTVisitor {
public:
virtual void visit(CalcASTInput &) = 0;
virtual void visit(CalcASTNum &) = 0;
virtual void visit(CalcASTExpression &) = 0;
virtual void visit(CalcASTTerm &) = 0;
};
#include "calc_builder.hpp"
#include <memory>
std::unique_ptr<Module> CalcBuilder::build(CalcAST &ast) {
module = std::unique_ptr<Module>(new Module());
builder = std::make_unique<IRBuilder>(nullptr, module.get());
auto TyVoid = module->get_void_type();
TyInt32 = module->get_int32_type();
std::vector<Type *> output_params;
output_params.push_back(TyInt32);
auto output_type = FunctionType::get(TyVoid, output_params);
auto output_fun = Function::create(output_type, "output", module.get());
auto main =
Function::create(FunctionType::get(TyInt32, {}), "main", module.get());
auto bb = BasicBlock::create(module.get(), "entry", main);
builder->set_insert_point(bb);
ast.run_visitor(*this);
builder->create_call(output_fun, {val});
builder->create_ret(ConstantInt::get(0, module.get()));
return std::move(module);
}
void CalcBuilder::visit(CalcASTInput &node) { node.expression->accept(*this); }
void CalcBuilder::visit(CalcASTExpression &node) {
if (node.expression == nullptr) {
node.term->accept(*this);
} else {
node.expression->accept(*this);
auto l_val = val;
node.term->accept(*this);
auto r_val = val;
switch (node.op) {
case OP_PLUS:
val = builder->create_iadd(l_val, r_val);
break;
case OP_MINUS:
val = builder->create_isub(l_val, r_val);
break;
}
}
}
void CalcBuilder::visit(CalcASTTerm &node) {
if (node.term == nullptr) {
node.factor->accept(*this);
} else {
node.term->accept(*this);
auto l_val = val;
node.factor->accept(*this);
auto r_val = val;
switch (node.op) {
case OP_MUL:
val = builder->create_imul(l_val, r_val);
break;
case OP_DIV:
val = builder->create_isdiv(l_val, r_val);
break;
}
}
}
void CalcBuilder::visit(CalcASTNum &node) {
val = ConstantInt::get(node.val, module.get());
}
#pragma once
#include "BasicBlock.hpp"
#include "Constant.hpp"
#include "Function.hpp"
#include "IRBuilder.hpp"
#include "Module.hpp"
#include "Type.hpp"
#include "calc_ast.hpp"
#include <memory>
class CalcBuilder : public CalcASTVisitor {
public:
std::unique_ptr<Module> build(CalcAST &ast);
private:
virtual void visit(CalcASTInput &) override final;
virtual void visit(CalcASTNum &) override final;
virtual void visit(CalcASTExpression &) override final;
virtual void visit(CalcASTTerm &) override final;
std::unique_ptr<IRBuilder> builder;
Value *val;
Type *TyInt32;
std::unique_ptr<Module> module;
};
%option noyywrap
%{
/*****************声明和选项设置 begin*****************/
#include <stdio.h>
#include <stdlib.h>
#include "syntax_tree.h"
#include "calculator.h"
int lines;
int pos_start;
int pos_end;
void pass_node(char *text){
yylval.node = new_syntax_tree_node(text);
}
/*****************声明和选项设置 end*****************/
%}
%x COMMENT
%%
\+ {pos_start = pos_end; pos_end += 1; pass_node(yytext); return ADD;}
\- {pos_start = pos_end; pos_end += 1; pass_node(yytext); return SUB;}
\* {pos_start = pos_end; pos_end += 1; pass_node(yytext); return MUL;}
\/ {pos_start = pos_end; pos_end += 1; pass_node(yytext); return DIV;}
\( {pos_start = pos_end; pos_end += 1; pass_node(yytext); return LPARENTHESE;}
\) {pos_start = pos_end; pos_end += 1; pass_node(yytext); return RPARENTHESE;}
[0-9]+ { pos_start = pos_end; pos_end += strlen(yytext); pass_node(yytext); return NUM;}
\n {lines++; pos_start = 1; pos_end = 1;}
[ \t] {pos_start = pos_end; pos_end += 1;}
%%
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "syntax_tree.h"
// external functions from lex
extern int yylex();
extern int yyparse();
extern int yyrestart();
extern FILE * yyin;
// external variables from lexical_analyzer module
extern int lines;
extern char * yytext;
extern int pos_end;
extern int pos_start;
// Global syntax tree
syntax_tree *gt;
// Error reporting
void yyerror(const char *s);
syntax_tree_node *node(const char *node_name, int children_num, ...);
%}
%union {
struct _syntax_tree_node * node;
char * name;
}
%token <node> ADD
%token <node> SUB
%token <node> MUL
%token <node> DIV
%token <node> NUM
%token <node> LPARENTHESE
%token <node> RPARENTHESE
%type <node> input expression addop term mulop factor num
%start input
%%
input : expression {$$ = node( "input", 1, $1); gt->root = $$;}
;
expression : expression addop term {$$ = node( "expression", 3, $1, $2, $3);}
| term {$$ = node( "expression", 1, $1);}
;
addop : ADD {$$ = node( "addop", 1, $1);}
| SUB {$$ = node( "addop", 1, $1);}
;
term : term mulop factor {$$ = node( "term", 3, $1, $2, $3);}
| factor {$$ = node( "term", 1, $1);}
;
mulop : MUL {$$ = node( "mulop", 1, $1);}
| DIV {$$ = node( "mulop", 1, $1);}
;
factor : LPARENTHESE expression RPARENTHESE {$$ = node( "factor", 3, $1, $2, $3);}
| num {$$ = node( "factor", 1, $1);}
;
num : NUM {$$ = node( "num", 1, $1);}
%%
void yyerror(const char * s) {
fprintf(stderr, "error at line %d column %d: %s\n", lines, pos_start, s);
}
syntax_tree *parse(const char *input_path) {
if (input_path != NULL) {
if (!(yyin = fopen(input_path, "r"))) {
fprintf(stderr, "[ERR] Open input file %s failed.\n", input_path);
exit(1);
}
} else {
yyin = stdin;
}
lines = pos_start = pos_end = 1;
gt = new_syntax_tree();
yyrestart(yyin);
yyparse();
return gt;
}
syntax_tree_node *node(const char *name, int children_num, ...) {
syntax_tree_node *p = new_syntax_tree_node(name);
syntax_tree_node *child;
if (children_num == 0) {
child = new_syntax_tree_node("epsilon");
syntax_tree_add_child(p, child);
} else {
va_list ap;
va_start(ap, children_num);
for (int i = 0; i < children_num; ++i) {
child = va_arg(ap, syntax_tree_node *);
syntax_tree_add_child(p, child);
}
va_end(ap);
}
return p;
}
int main() {}
\ No newline at end of file
int main() {}
\ No newline at end of file
int main() {}
\ No newline at end of file
int x[1];
int y[1];
int gcd(int u, int v) {
if (v == 0)
return u;
else
return gcd(v, u - u / v * v);
}
int funArray(int u[], int v[]) {
int a;
int b;
int temp;
a = u[0];
b = v[0];
if (a < b) {
temp = a;
a = b;
b = temp;
}
return gcd(a, b);
}
int main(void) {
x[0] = 90;
y[0] = 18;
return funArray(x, y);
}
\ No newline at end of file
#include "BasicBlock.hpp"
#include "Constant.hpp"
#include "Function.hpp"
#include "IRBuilder.hpp"
#include "Module.hpp"
#include "Type.hpp"
#include <iostream>
#include <memory>
// 定义一个从常数值获取/创建 ConstantInt 类实例化的宏,方便多次调用
#define CONST_INT(num) ConstantInt::get(num, module)
// 定义一个从常数值获取/创建 ConstantFP 类实例化的宏,方便多次调用
#define CONST_FP(num) ConstantFP::get(num, module)
int main() {
// 创建一个 Module 实例
auto module = new Module();
// 创建一个 IRBuilder 实例(后续创建指令均使用此实例操作)
auto builder = new IRBuilder(nullptr, module);
// 从 Module 处取出 32 位整形 type 的实例
Type *Int32Type = module->get_int32_type();
// 使用取出的 32 位整形与数组长度 1,创建数组类型 [1 x i32]
auto *arrayType = ArrayType::get(Int32Type, 1);
// 创建 0 常数类实例化,用于全局变量的初始化(目前全局变量仅支持初始化为 0)
auto initializer = ConstantZero::get(Int32Type, module);
// 为全局数组变量分配空间。参数解释:名字 name,所属 module,待分配空间类型
// type,标志全局变量是否有 const 限定(cminus 中全是 false),初始化值
auto x = GlobalVariable::create("x", module, arrayType, false, initializer);
// 为另一个全局数组分配空间
auto y = GlobalVariable::create("y", module, arrayType, false, initializer);
// 接下来创建 gcd 函数
// 声明函数参数类型的 vector,此处的 vector 数组含有两个元素,每个均为
// Int32Type,表明待创建函数有两个参数,类型均为 Int32Type 实例代表的类型
std::vector<Type *> Ints(2, Int32Type);
// 创建函数类型,FunctionType::get
// 的第一个参数是函数返回值类型,第二个是函数参数类型列表
auto gcdFunTy = FunctionType::get(Int32Type, Ints);
// 通过函数类型创建函数 gcd,输入参数解释:函数类型,函数名 name,函数所属
// module
auto gcdFun = Function::create(gcdFunTy, "gcd", module);
// 为函数 gcd 创建起始 BasicBlock,参数解释:所属 module,名称
// name,所属函数
auto bb = BasicBlock::create(module, "entry", gcdFun);
// 将辅助类实例化 builder 插入指令的起始位置设置在 bb 对应的 BasicBlock
builder->set_insert_point(bb);
// 使用辅助类实例化 builder 创建了一条 alloca 指令,在栈上分配返回值的空间
auto retAlloca = builder->create_alloca(Int32Type);
// 使用辅助类实例化 builder 创建了一条 alloca 指令,在栈上分配参数 u 的空间
auto uAlloca = builder->create_alloca(Int32Type);
// 使用辅助类实例化 builder 创建了一条 alloca 指令,在栈上分配参数 u 的空间
auto vAlloca = builder->create_alloca(Int32Type);
// 获取 gcd 函数的形参,通过 Function 中的 iterator
std::vector<Value *> args;
for (auto &arg : gcdFun->get_args()) {
args.push_back(&arg);
}
// 使用辅助类实例化 builder 创建了一条 store 指令,将参数 u store 下来
builder->create_store(args[0], uAlloca);
// 使用辅助类实例化 builder 创建了一条 store 指令,将参数 v store 下来
builder->create_store(args[1], vAlloca);
// 使用辅助类实例化 builder 创建了一条 load 指令,将参数 v load 出来
auto vLoad = builder->create_load(vAlloca);
// 使用辅助类实例化 builder 创建了一条 cmp eq 指令,将 v load 出来的值与 0
// 比较
auto icmp = builder->create_icmp_eq(vLoad, CONST_INT(0));
// 为函数 gcd 创建 BasicBlock 作为 true 分支
auto trueBB = BasicBlock::create(module, "trueBB", gcdFun);
// 为函数 gcd 创建 BasicBlock 作为 false 分支
auto falseBB = BasicBlock::create(module, "falseBB", gcdFun);
// 为函数 gcd 创建 BasicBlock 作为 return 分支,提前创建,以便在 true
// 分支中可以创建跳转到 return 分支的 br 指令
auto retBB = BasicBlock::create(module, "", gcdFun); // return 分支,
// 为 entrybb 创建终结指令,条件跳转指令,使用 icmp
// 指令的返回值作为条件,trueBB 与 falseBB 作为条件跳转的两个目的 basicblock
auto br = builder->create_cond_br(icmp, trueBB, falseBB);
// 将辅助类实例化 builder 插入指令的位置调整至 trueBB 上
builder->set_insert_point(trueBB);
// 使用辅助类实例化 builder 创建了一条 load 指令,将参数 u load 出来
auto uLoad = builder->create_load(uAlloca);
// 使用辅助类实例化 builder 创建了一条 store 指令,将参数 u store
// 至为返回值分配的空间
builder->create_store(uLoad, retAlloca);
// 使用 builder 创建一条强制跳转指令,跳转到 retBB 处
builder->create_br(retBB); // br retBB
// 将辅助类实例化 builder 插入指令的位置调整至 falseBB 上
builder->set_insert_point(falseBB);
// 使用 builder 创建了一条 load 指令,将参数 u load 出来
uLoad = builder->create_load(uAlloca);
// 使用 builder 创建了一条 load 指令,将参数 v load 出来
vLoad = builder->create_load(vAlloca);
// 使用 builder 创建了一条 sdiv 指令,计算 u/v 的值
auto div = builder->create_isdiv(uLoad, vLoad);
// 使用 builder 创建了一条 imul 指令,计算 v*u/v 的值
auto mul = builder->create_imul(div, vLoad);
// 使用 builder 创建了一条 isub 指令,计算 u-v*u/v 的值
auto sub = builder->create_isub(uLoad, mul);
// 创建 call 指令,调用 gcd 函数,传入的实参为 v load 指令的结果与 sub
// 指令计算的结果
auto call = builder->create_call(gcdFun, {vLoad, sub});
// 创建 store 指令,将 call 指令的结果存至为 gcd 函数返回值分配的空间
builder->create_store(call, retAlloca);
// 创建强制跳转指令,跳转至 retBB
builder->create_br(retBB); // br retBB
// 将 builder 插入指令的位置调整至 retBB 上
builder->set_insert_point(retBB); // ret 分支
// 使用 builder 创建了一条 load 指令,将 gcd 函数返回值 load 出来
auto retLoad = builder->create_load(retAlloca);
// 使用 builder 创建了一条 ret 指令,将 gcd 返回值 load 出来的结果作为 gcd
// 函数的返回值返回
builder->create_ret(retLoad);
// 接下来创建 funArray 函数
// 获得 32 位整形的指针类型,
auto Int32PtrType = module->get_int32_ptr_type();
// 初始化 funArray 函数的参数类型列表,第一个参数与第二个参数类型均为
// Int32PtrType,及 32 位整形的指针类型
std::vector<Type *> IntPtrs(2, Int32PtrType);
// 通过返回值类型与参数类型列表创建函数类型
auto funArrayFunType = FunctionType::get(Int32Type, IntPtrs);
// 通过函数类型创建函数
auto funArrayFun = Function::create(funArrayFunType, "funArray", module);
// 创建 funArray 函数的第一个 BasicBlock
bb = BasicBlock::create(module, "entry", funArrayFun);
// 将 builder 插入指令的位置调整至 funArray 的 entryBB 上
builder->set_insert_point(bb);
// 用 builder 创建 alloca 指令,用于 u 的存放,此处开始 u,v 指的是源代码中
// funArray 函数内的参数
auto upAlloca = builder->create_alloca(Int32PtrType);
// 用 builder 创建 alloca 指令,用于 v 的存放
auto vpAlloca = builder->create_alloca(Int32PtrType);
// 用 builder 创建 alloca 指令,用于 a 的存放
auto aAlloca = builder->create_alloca(Int32Type);
// 用 builder 创建 alloca 指令,用于 b 的存放
auto bAlloca = builder->create_alloca(Int32Type);
// 用 builder 创建 alloca 指令,用于 temp 的存放
auto tempAlloca = builder->create_alloca(Int32Type);
// 获取 funArrayFun 函数的形参,通过 Function 中的 iterator
std::vector<Value *> args1;
for (auto &arg : funArrayFun->get_args()) {
args1.push_back(&arg);
}
// 用 builder 创建 store 指令将参数 u store 下来
builder->create_store(args1[0], upAlloca);
// 用 builder 创建 store 指令将参数 v store 下来
builder->create_store(args1[1], vpAlloca);
// 用 builder 创建 load 指令将参数 u 的值 load 出来
auto u0pLoad = builder->create_load(upAlloca);
// 用 builder 创建 getelementptr 指令,参数解释:第一个参数传入
// getelementptr
// 的指针参数,第二个参数传入取偏移的数组。在此条语句中,u0pLoad 为
// i32*类型的指针,且只取一次偏移,偏移值为 0,因此返回的即为 u[0] 的地址
auto u0GEP = builder->create_gep(u0pLoad, {CONST_INT(0)});
// 用 builder 创建 load 指令,将 u[0] 的数据 load 出来
auto u0Load = builder->create_load(u0GEP);
// 用 builder 创建 store 指令,将 u[0] 的数据写入 a
builder->create_store(u0Load, aAlloca);
// 接下来几条指令含义同上
auto v0pLoad = builder->create_load(vpAlloca);
auto v0GEP = builder->create_gep(v0pLoad, {CONST_INT(0)});
auto v0Load = builder->create_load(v0GEP);
builder->create_store(v0Load, bAlloca);
// 用 builder 创建两条 load 指令吗,将 a,b 的值 load 出来
auto aLoad = builder->create_load(aAlloca);
auto bLoad = builder->create_load(bAlloca);
// 用 builder 创建 icmp lt 指令,指令操作数为 a,b load 出来的值
icmp = builder->create_icmp_lt(aLoad, bLoad);
// 为 if else 分支创建两个 BasicBlock
trueBB = BasicBlock::create(module, "trueBB", funArrayFun);
falseBB = BasicBlock::create(module, "falseBB", funArrayFun);
// 用 builder 创建一条条件跳转指令,使用 icmp 指令的返回值作为条件,trueBB
// 与 falseBB 作为条件跳转的两个目的 basicblock
builder->create_cond_br(icmp, trueBB, falseBB);
// 将 builder 插入指令的位置调整至 trueBB 上
builder->set_insert_point(trueBB);
// 用 builder 创建 store 指令,将 a 的值存到 temp 处,将 b 存到 a 处,将
// temp 重新 load 后存到 b 处,对应源代码 temp=a,a=b,b=temp
builder->create_store(aLoad, tempAlloca);
builder->create_store(bLoad, aAlloca);
auto tempLoad = builder->create_load(tempAlloca);
builder->create_store(tempLoad, bAlloca);
// 创建强制跳转指令,跳转至 falseBB,注意每个 BasicBlock 都需要有终结指令
builder->create_br(falseBB);
// 将 builder 插入指令的位置调整至 falseBB 上
builder->set_insert_point(falseBB);
// 用 builder 创建两条 load 指令将 a 与 b 的值 load 出来
aLoad = builder->create_load(aAlloca);
bLoad = builder->create_load(bAlloca);
// 用 builder 创建 call 指令,调用 gcd 函数,并将 ab load 的结果作为实参传入
call = builder->create_call(gcdFun, {aLoad, bLoad});
// 使用 builder 创建了一条 ret 指令,将 gcd 返回值 load 出来的结果作为 gcd
// 函数的返回值返回
builder->create_ret(call);
// 接下来创建 main 函数
auto mainFun =
Function::create(FunctionType::get(Int32Type, {}), "main", module);
// 创建 main 函数的起始 bb
bb = BasicBlock::create(module, "entry", mainFun);
// 将 builder 插入指令的位置调整至 main 函数起始 bb 上
builder->set_insert_point(bb);
// 用 builder 创建 alloca 指令,为函数返回值分配空间
retAlloca = builder->create_alloca(Int32Type);
// main 函数默认 ret 0
builder->create_store(CONST_INT(0), retAlloca);
// 用 builder 创建 getelementptr 指令,参数解释:第一个参数传入
// getelementptr 的指针参数,第二个参数传入取偏移的数组。在此条语句中,x 为
// [1 x i32]*类型的指针,取两次偏移,两次偏移值都为 0,因此返回的即为 x[0]
// 的地址。
auto x0GEP = builder->create_gep(x, {CONST_INT(0), CONST_INT(0)});
// 用 builder 创建 store 指令,将 90 常数值存至上条语句取出的 x[0] 的地址
builder->create_store(CONST_INT(90), x0GEP);
// 此处同上创建 getelementptr 指令,返回 y[0] 的地址
auto y0GEP = builder->create_gep(y, {CONST_INT(0), CONST_INT(0)});
// 用 builder 创建 store 指令,将 18 常数值存至上条语句取出的 y[0] 的地址
builder->create_store(CONST_INT(18), y0GEP);
// 此处同上创建 getelementptr 指令,返回 x[0] 的地址
x0GEP = builder->create_gep(x, {CONST_INT(0), CONST_INT(0)});
// 此处同上创建 getelementptr 指令,返回 y[0] 的地址
y0GEP = builder->create_gep(y, {CONST_INT(0), CONST_INT(0)});
// 此处创建 call 指令,调用 funArray 函数,将上两条语句返回的 x[0],y[0]
// 的地址作为实参
call = builder->create_call(funArrayFun, {x0GEP, y0GEP});
// 使用 builder 创建了一条 ret 指令,将 funArray 返回值 load 出来的结果作为
// main 函数的返回值返回
builder->create_ret(call);
// 输出 module 中的所有 IR 指令
std::cout << module->print();
delete module;
return 0;
}
add_subdirectory("2-ir-gen/warmup")
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment