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/
\ No newline at end of file
.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_{};
};
......@@ -71,8 +57,9 @@ std::string level2string(LogLevel level);
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()
#define LOG_IF(level) \
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];
int children_num;
struct _syntax_tree_node *parent;
struct _syntax_tree_node *children[10];
int children_num;
char name[SYNTAX_TREE_NODE_NAME_MAX];
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);
This diff is collapsed.
#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);
ASTPrinter printer;
ast.run_visitor(printer);
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);
}
This diff is collapsed.
......@@ -8,35 +8,31 @@ 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;
std::cout << "[" << level2string(log_level_) << "] "
<< "(" << location_.file_ << ":" << location_.line_ << "L "
<< location_.func_ << ")" << msg.str() << std::endl;
}
std::string level2string(LogLevel level) {
switch (level)
{
case DEBUG:
return "DEBUG";
case INFO:
return "INFO";
switch (level) {
case DEBUG:
return "DEBUG";
case INFO:
return "INFO";
case WARNING:
return "WARNING";
case WARNING:
return "WARNING";
case ERROR:
return "ERROR";
case ERROR:
return "ERROR";
default:
return "";
default:
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,75 +3,73 @@
#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));
if (name)
strncpy(new_node->name, name, SYNTAX_TREE_NODE_NAME_MAX);
else
new_node->name[0] = '\0';
new_node->children_num = 0;
return new_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
new_node->name[0] = '\0';
new_node->children_num = 0;
return new_node;
}
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;
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) {
for (i = 0; i < node->children_num; i++) {
del_syntax_tree_node(node->children[i], 1);
}
}
free(node);
int i;
if (recursive) {
for (i = 0; i < node->children_num; i++) {
del_syntax_tree_node(node->children[i], 1);
}
}
free(node);
}
syntax_tree * new_syntax_tree()
{
return (syntax_tree *)malloc(sizeof(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);
}
free(tree);
if (tree->root) {
del_syntax_tree_node(tree->root, 1);
}
free(tree);
}
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;
// print myself
int i;
for (i = 0; i < level; i++) {
fprintf(fout, "| ");
}
fprintf(fout, ">--%s %s\n", (node->children_num ? "+" : "*"), node->name);
void print_syntax_tree_node(FILE *fout, syntax_tree_node *node, int level) {
// assume fout valid now
for (i = 0; i < node->children_num; i++) {
print_syntax_tree_node(fout, node->children[i], level + 1);
}
}
// check if "node" empty pointer
if (!node)
return;
// print myself
int i;
for (i = 0; i < level; i++) {
fprintf(fout, "| ");
}
fprintf(fout, ">--%s %s\n", (node->children_num ? "+" : "*"), node->name);
void print_syntax_tree(FILE * fout, syntax_tree * tree)
{
if (!fout) return;
print_syntax_tree_node(fout, tree->root, 0);
for (i = 0; i < node->children_num; i++) {
print_syntax_tree_node(fout, node->children[i], level + 1);
}
}
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;
}
This diff is collapsed.
#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;
......@@ -18,24 +18,24 @@ YYSTYPE yylval;
///
int main(int argc, const char **argv) {
if (argc != 2) {
printf("usage: lexer input_file\n");
return 0;
}
if (argc != 2) {
printf("usage: lexer input_file\n");
return 0;
}
const char *input_file = argv[1];
yyin = fopen(input_file, "r");
if (!yyin) {
fprintf(stderr, "cannot open file: %s\n", input_file);
return 1;
}
const char *input_file = argv[1];
yyin = fopen(input_file, "r");
if (!yyin) {
fprintf(stderr, "cannot open file: %s\n", input_file);
return 1;
}
int token;
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);
}
return 0;
int token;
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);
}
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
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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