diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..5bf2f83a84dc2685f853e92cf8ebd15c6d729687 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: LLVM +IndentWidth: 4 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5b79a5415be450374d4fd7937805c31124ee120f..85903c474a9f972028f58f03dd9499dd2a507806 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ build/ -.cache/ \ No newline at end of file +.cache/ +.vscode +.DS_store \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 340b494f9cba1f1b4a5392d7666098074ccf6200..65ba81d6156c3b086d6d12ec1965b21420803ed9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/README.md b/README.md index 1f3b2246b60ef464a1b6cdc26e36ba55ca32978b..9306c890e9506bb7220014fcef6244832194189b 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/include/cminusfc/cminusf_builder.hpp b/include/cminusfc/cminusf_builder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..30c724b852c44aad3f684f1c74c5322105604529 --- /dev/null +++ b/include/cminusfc/cminusf_builder.hpp @@ -0,0 +1,113 @@ +#pragma once + +#include "BasicBlock.hpp" +#include "Constant.hpp" +#include "Function.hpp" +#include "IRBuilder.hpp" +#include "Module.hpp" +#include "Type.hpp" +#include "ast.hpp" + +#include +#include + +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> inner; +}; + +class CminusfBuilder : public ASTVisitor { + public: + CminusfBuilder() { + module = std::make_unique(); + builder = std::make_unique(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 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 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 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 builder; + Scope scope; + std::unique_ptr module; + + struct { + // function that is being built + Function *func = nullptr; + // TODO: you should add more fields to store state + } context; +}; diff --git a/include/common/ast.hpp b/include/common/ast.hpp index 059ce970899b9bafb58ed35efaeccc91e1954371..560944159fa1e6020acb685d40bb8a49bba9f1aa 100644 --- a/include/common/ast.hpp +++ b/include/common/ast.hpp @@ -1,9 +1,11 @@ #pragma once +#include extern "C" { #include "syntax_tree.h" extern syntax_tree *parse(const char *input); } +#include "User.hpp" #include #include #include @@ -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> 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 num; }; struct ASTFunDeclaration : ASTDeclaration { - virtual void accept(ASTVisitor &) override final; + virtual Value* accept(ASTVisitor &) override final; std::vector> params; std::shared_ptr 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> local_declarations; std::vector> statement_list; }; struct ASTExpressionStmt : ASTStatement { - virtual void accept(ASTVisitor &) override final; + virtual Value* accept(ASTVisitor &) override final; std::shared_ptr expression; }; struct ASTSelectionStmt : ASTStatement { - virtual void accept(ASTVisitor &) override final; + virtual Value* accept(ASTVisitor &) override final; std::shared_ptr expression; std::shared_ptr 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 expression; std::shared_ptr 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 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 var; std::shared_ptr expression; }; struct ASTSimpleExpression : ASTExpression { - virtual void accept(ASTVisitor &) override final; + virtual Value* accept(ASTVisitor &) override final; std::shared_ptr additive_expression_l; std::shared_ptr 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 expression; }; struct ASTAdditiveExpression : ASTNode { - virtual void accept(ASTVisitor &) override final; + virtual Value* accept(ASTVisitor &) override final; std::shared_ptr additive_expression; AddOp op; std::shared_ptr term; }; struct ASTTerm : ASTNode { - virtual void accept(ASTVisitor &) override final; + virtual Value* accept(ASTVisitor &) override final; std::shared_ptr term; MulOp op; std::shared_ptr factor; }; struct ASTCall : ASTFactor { - virtual void accept(ASTVisitor &) override final; + virtual Value* accept(ASTVisitor &) override final; std::string id; std::vector> 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; } diff --git a/include/common/logging.hpp b/include/common/logging.hpp index 032e8d465291742ed90af66975989d2baf4811e5..d70ac41bf09939a3106a7533aac0d2585d98c783 100644 --- a/include/common/logging.hpp +++ b/include/common/logging.hpp @@ -1,20 +1,14 @@ #ifndef LOGGING_HPP #define LOGGING_HPP +#include #include #include -#include -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 - LogStream &operator<<(const T &val) noexcept - { +class LogStream { + public: + template 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) diff --git a/include/common/syntax_tree.h b/include/common/syntax_tree.h index 6eea3c1898d2ae673da043b8134c5d3f389fa65c..78ec91c4915aedfdb6c84129a0f176afc000734d 100644 --- a/include/common/syntax_tree.h +++ b/include/common/syntax_tree.h @@ -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 */ diff --git a/include/lightir/BasicBlock.hpp b/include/lightir/BasicBlock.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1d1d3e174149816b5433831d639b1cbba94d2ef4 --- /dev/null +++ b/include/lightir/BasicBlock.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "Instruction.hpp" +#include "Value.hpp" + +#include +#include +#include +#include +#include + +class Function; +class Instruction; +class Module; + +class BasicBlock : public Value, public llvm::ilist_node { + 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 &get_pre_basic_blocks() { return pre_bbs_; } + std::list &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 &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 pre_bbs_; + std::list succ_bbs_; + llvm::ilist instr_list_; + Function *parent_; +}; diff --git a/include/lightir/Constant.hpp b/include/lightir/Constant.hpp new file mode 100644 index 0000000000000000000000000000000000000000..786a00e0a5c7d743f1ec7baaa739f5d14ae93d90 --- /dev/null +++ b/include/lightir/Constant.hpp @@ -0,0 +1,64 @@ +#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 const_array; + + ConstantArray(ArrayType *ty, const std::vector &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 &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; +}; diff --git a/include/lightir/Function.hpp b/include/lightir/Function.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c7825e75c74413934fe85653bfb712321604a91a --- /dev/null +++ b/include/lightir/Function.hpp @@ -0,0 +1,80 @@ +#pragma once + +#include "BasicBlock.hpp" +#include "Type.hpp" +#include "User.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +class Module; +class Argument; +class Type; +class FunctionType; + +class Function : public Value, public llvm::ilist_node { + 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 &get_basic_blocks() { return basic_blocks_; } + std::list &get_args() { return arguments_; } + + bool is_declaration() { return basic_blocks_.empty(); } + + void set_instr_name(); + std::string print(); + + private: + llvm::ilist basic_blocks_; + std::list 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. +}; diff --git a/include/lightir/GlobalVariable.hpp b/include/lightir/GlobalVariable.hpp new file mode 100644 index 0000000000000000000000000000000000000000..50c0891e6bf374510fc1cf9cc6365c179c81586a --- /dev/null +++ b/include/lightir/GlobalVariable.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "Constant.hpp" +#include "User.hpp" + +#include +class Module; +class GlobalVariable : public User, public llvm::ilist_node { + 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(); +}; diff --git a/include/lightir/IRBuilder.hpp b/include/lightir/IRBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7774641e0b8d2430d684bc248e1f4997250d8756 --- /dev/null +++ b/include/lightir/IRBuilder.hpp @@ -0,0 +1,131 @@ +#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 args) { + return CallInst::create_call(static_cast(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 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_); + } +}; diff --git a/include/lightir/IRprinter.hpp b/include/lightir/IRprinter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..be4f965f196bc504dba5f3da4e74da8182e7d59d --- /dev/null +++ b/include/lightir/IRprinter.hpp @@ -0,0 +1,14 @@ +#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); diff --git a/include/lightir/Instruction.hpp b/include/lightir/Instruction.hpp new file mode 100644 index 0000000000000000000000000000000000000000..184ebd5d8f1e81093ccc81cf1049a3cd65fddf02 --- /dev/null +++ b/include/lightir/Instruction.hpp @@ -0,0 +1,369 @@ +#pragma once + +#include "Type.hpp" +#include "User.hpp" + +#include +#include + +class BasicBlock; +class Function; + +class Instruction : public User, public llvm::ilist_node { + 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 class BaseInst : public Instruction { + protected: + template static Inst *create(Args &&...args) { + return new Inst(std::forward(args)...); + } + + template + BaseInst(Args &&...args) : Instruction(std::forward(args)...) {} +}; + +class IBinaryInst : public BaseInst { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + protected: + CallInst(Function *func, std::vector args, BasicBlock *bb); + + public: + static CallInst *create_call(Function *func, std::vector args, + BasicBlock *bb); + FunctionType *get_function_type() const; + + virtual std::string print() override; +}; + +class BranchInst : public BaseInst { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + private: + GetElementPtrInst(Value *ptr, std::vector idxs, BasicBlock *bb); + + public: + static Type *get_element_type(Value *ptr, std::vector idxs); + static GetElementPtrInst *create_gep(Value *ptr, std::vector idxs, + BasicBlock *bb); + Type *get_element_type() const; + + virtual std::string print() override; +}; + +class StoreInst : public BaseInst { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + 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 { + friend BaseInst; + + private: + PhiInst(Type *ty, std::vector vals, + std::vector val_bbs, BasicBlock *bb); + + public: + static PhiInst *create_phi(Type *ty, BasicBlock *bb, + std::vector vals = {}, + std::vector val_bbs = {}); + + void add_phi_pair_operand(Value *val, Value *pre_bb) { + this->add_operand(val); + this->add_operand(pre_bb); + } + std::vector> get_phi_pairs() { + std::vector> 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()}); + } + return res; + } + virtual std::string print() override; +}; diff --git a/include/lightir/Module.hpp b/include/lightir/Module.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b154b08a3c35cecfb13cfa16bc916f47dff24212 --- /dev/null +++ b/include/lightir/Module.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include "Function.hpp" +#include "GlobalVariable.hpp" +#include "Instruction.hpp" +#include "Type.hpp" +#include "Value.hpp" + +#include +#include +#include +#include +#include +#include + +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 &args); + + void add_function(Function *f); + llvm::ilist &get_functions(); + void add_global_variable(GlobalVariable *g); + llvm::ilist &get_global_variable(); + + void set_print_name(); + std::string print(); + + private: + // The global variables in the module + llvm::ilist global_list_; + // The functions in the module + llvm::ilist function_list_; + + std::unique_ptr int1_ty_; + std::unique_ptr int32_ty_; + std::unique_ptr label_ty_; + std::unique_ptr void_ty_; + std::unique_ptr float32_ty_; + std::map> pointer_map_; + std::map, std::unique_ptr> array_map_; + std::map>, + std::unique_ptr> + function_map_; +}; diff --git a/include/lightir/Type.hpp b/include/lightir/Type.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5d456a77d10318617bcf0547f8fa75aac3a09b83 --- /dev/null +++ b/include/lightir/Type.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include + +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 params); + + static bool is_valid_return_type(Type *ty); + static bool is_valid_argument_type(Type *ty); + + static FunctionType *get(Type *result, std::vector params); + + unsigned get_num_of_args() const; + + Type *get_param_type(unsigned i) const; + std::vector::iterator param_begin() { return args_.begin(); } + std::vector::iterator param_end() { return args_.end(); } + Type *get_return_type() const; + + private: + Type *result_; + std::vector 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: +}; diff --git a/include/lightir/User.hpp b/include/lightir/User.hpp new file mode 100644 index 0000000000000000000000000000000000000000..50bffc81f1e86cf63dd964f7017b6e638df2274d --- /dev/null +++ b/include/lightir/User.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include "Value.hpp" + +#include + +class User : public Value { + public: + User(Type *ty, const std::string &name = "") : Value(ty, name){}; + virtual ~User() { remove_all_operands(); } + + const std::vector &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 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_; + } +}; diff --git a/include/lightir/Value.hpp b/include/lightir/Value.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7e805a51b071c31ec9a36e83b772c4a468d54000 --- /dev/null +++ b/include/lightir/Value.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include +#include + +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 &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 pred); + + virtual std::string print() = 0; + + template + T *as() + { + static_assert(std::is_base_of::value, "T must be a subclass of Value"); + const auto ptr = dynamic_cast(this); + assert(ptr && "dynamic_cast failed"); + return ptr; + } + template + [[nodiscard]] const T* as() const { + static_assert(std::is_base_of::value, "T must be a subclass of Value"); + const auto ptr = dynamic_cast(this); + assert(ptr); + return ptr; + } + // is 接口 + template + [[nodiscard]] bool is() const { + static_assert(std::is_base_of::value, "T must be a subclass of Value"); + return dynamic_cast(this); + } + + private: + Type *type_; + std::list use_list_; // who use this value + std::string name_; // should we put name field here ? +}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67f7a885c76e8f058c4bc7b38a70345eba17a119..a1ec57b1a3101f0c8e18a4ab8035c8d6b509b352 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/cminusfc/CMakeLists.txt b/src/cminusfc/CMakeLists.txt index 948fa79fe7cf76cc5ca18d954921b690dc53c106..3e54d07f7f8a7fbb57d956d02a333118541207e6 100644 --- a/src/cminusfc/CMakeLists.txt +++ b/src/cminusfc/CMakeLists.txt @@ -1,10 +1,12 @@ add_executable( cminusfc main.cpp + cminusf_builder.cpp ) target_link_libraries( cminusfc + IR_lib common syntax stdc++fs diff --git a/src/cminusfc/cminusf_builder.cpp b/src/cminusfc/cminusf_builder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cb34ac50717d52bc2780c29a7f867b791db6aa59 --- /dev/null +++ b/src/cminusfc/cminusf_builder.cpp @@ -0,0 +1,178 @@ +#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 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 ¶m : 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 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; +} diff --git a/src/cminusfc/main.cpp b/src/cminusfc/main.cpp index ae74c583a960d2ab0341e29d98c338685ea0be3a..456ec388bf5f595e0e91071b5e1ae6eb9a4e1688 100644 --- a/src/cminusfc/main.cpp +++ b/src/cminusfc/main.cpp @@ -1,27 +1,29 @@ +#include "Module.hpp" #include "ast.hpp" +#include "cminusf_builder.hpp" #include +#include #include #include 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 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 ] [-mem2reg] [-emit-llvm] [-S] " "" @@ -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); } diff --git a/src/common/ast.cpp b/src/common/ast.cpp index acafd5afd14577a36a86c3f0858ce62500663763..da76f874b9f33b1c5e50db32858e1be71e9b409a 100644 --- a/src/common/ast.cpp +++ b/src/common/ast.cpp @@ -333,262 +333,260 @@ 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) { - return visitor.visit(*this); +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) { - _DEBUG_PRINT_N_(depth); - std::cout << "program" << std::endl; - add_depth(); - for (auto decl : node.declarations) { - decl->accept(*this); - } - remove_depth(); -} - -void ASTPrinter::visit(ASTNum &node) { - _DEBUG_PRINT_N_(depth); - if (node.type == TYPE_INT) { - std::cout << "num (int): " << node.i_val << std::endl; - } else if (node.type == TYPE_FLOAT) { - std::cout << "num (float): " << node.f_val << std::endl; - } else { - _AST_NODE_ERROR_ - } -} + { std::cout << std::string(N, '-'); } -void ASTPrinter::visit(ASTVarDeclaration &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "var-declaration: " << node.id; - if (node.num != nullptr) { - std::cout << "[]" << std::endl; +Value* ASTPrinter::visit(ASTProgram &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "program" << std::endl; add_depth(); - node.num->accept(*this); + for (auto decl : node.declarations) { + decl->accept(*this); + } remove_depth(); - return; - } - std::cout << std::endl; + return nullptr; } -void ASTPrinter::visit(ASTFunDeclaration &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "fun-declaration: " << node.id << std::endl; - add_depth(); - for (auto param : node.params) { - param->accept(*this); - } - - node.compound_stmt->accept(*this); - remove_depth(); +Value* ASTPrinter::visit(ASTNum &node) { + _DEBUG_PRINT_N_(depth); + if (node.type == TYPE_INT) { + std::cout << "num (int): " << node.i_val << std::endl; + } else if (node.type == TYPE_FLOAT) { + std::cout << "num (float): " << node.f_val << std::endl; + } else { + _AST_NODE_ERROR_ + } + return nullptr; } -void ASTPrinter::visit(ASTParam &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "param: " << node.id; - if (node.isarray) - std::cout << "[]"; - std::cout << std::endl; +Value* ASTPrinter::visit(ASTVarDeclaration &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "var-declaration: " << node.id; + if (node.num != nullptr) { + std::cout << "[]" << std::endl; + add_depth(); + node.num->accept(*this); + remove_depth(); + return nullptr; + } + std::cout << std::endl; + return nullptr; } -void ASTPrinter::visit(ASTCompoundStmt &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "compound-stmt" << std::endl; - add_depth(); - for (auto decl : node.local_declarations) { - decl->accept(*this); - } +Value* ASTPrinter::visit(ASTFunDeclaration &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "fun-declaration: " << node.id << std::endl; + add_depth(); + for (auto param : node.params) { + param->accept(*this); + } - for (auto stmt : node.statement_list) { - stmt->accept(*this); - } - remove_depth(); + node.compound_stmt->accept(*this); + remove_depth(); + return nullptr; } -void 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(); +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(ASTSelectionStmt &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "selection-stmt" << std::endl; - add_depth(); - node.expression->accept(*this); - node.if_statement->accept(*this); - if (node.else_statement != nullptr) - node.else_statement->accept(*this); - remove_depth(); +Value* ASTPrinter::visit(ASTCompoundStmt &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "compound-stmt" << std::endl; + add_depth(); + for (auto decl : node.local_declarations) { + decl->accept(*this); + } + + for (auto stmt : node.statement_list) { + stmt->accept(*this); + } + remove_depth(); + return nullptr; } -void 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(); +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(ASTReturnStmt &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "return-stmt"; - if (node.expression == nullptr) { - std::cout << ": void" << std::endl; - } else { - std::cout << std::endl; +Value* ASTPrinter::visit(ASTSelectionStmt &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "selection-stmt" << std::endl; add_depth(); node.expression->accept(*this); + node.if_statement->accept(*this); + if (node.else_statement != nullptr) + node.else_statement->accept(*this); remove_depth(); - } + return nullptr; } -void 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(); +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(ASTSimpleExpression &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "simple-expression"; - if (node.additive_expression_r == nullptr) { - std::cout << std::endl; - } else { - std::cout << ": "; - if (node.op == OP_LT) { - std::cout << "<"; - } else if (node.op == OP_LE) { - std::cout << "<="; - } else if (node.op == OP_GE) { - std::cout << ">="; - } else if (node.op == OP_GT) { - std::cout << ">"; - } else if (node.op == OP_EQ) { - std::cout << "=="; - } else if (node.op == OP_NEQ) { - std::cout << "!="; +Value* ASTPrinter::visit(ASTReturnStmt &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "return-stmt"; + if (node.expression == nullptr) { + std::cout << ": void" << std::endl; } else { - std::abort(); + std::cout << std::endl; + add_depth(); + node.expression->accept(*this); + remove_depth(); } - std::cout << std::endl; - } - add_depth(); - node.additive_expression_l->accept(*this); - if (node.additive_expression_r != nullptr) - node.additive_expression_r->accept(*this); - remove_depth(); + return nullptr; } -void ASTPrinter::visit(ASTAdditiveExpression &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "additive-expression"; - if (node.additive_expression == nullptr) { - std::cout << std::endl; - } else { - std::cout << ": "; - if (node.op == OP_PLUS) { - std::cout << "+"; - } else if (node.op == OP_MINUS) { - std::cout << "-"; +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; +} + +Value* ASTPrinter::visit(ASTSimpleExpression &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "simple-expression"; + if (node.additive_expression_r == nullptr) { + std::cout << std::endl; } else { - std::abort(); + std::cout << ": "; + if (node.op == OP_LT) { + std::cout << "<"; + } else if (node.op == OP_LE) { + std::cout << "<="; + } else if (node.op == OP_GE) { + std::cout << ">="; + } else if (node.op == OP_GT) { + std::cout << ">"; + } else if (node.op == OP_EQ) { + std::cout << "=="; + } else if (node.op == OP_NEQ) { + std::cout << "!="; + } else { + std::abort(); + } + std::cout << std::endl; } - std::cout << std::endl; - } - add_depth(); - if (node.additive_expression != nullptr) - node.additive_expression->accept(*this); - node.term->accept(*this); - remove_depth(); + add_depth(); + node.additive_expression_l->accept(*this); + if (node.additive_expression_r != nullptr) + node.additive_expression_r->accept(*this); + remove_depth(); + return nullptr; } -void ASTPrinter::visit(ASTVar &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "var: " << node.id; - if (node.expression != nullptr) { - std::cout << "[]" << std::endl; +Value* ASTPrinter::visit(ASTAdditiveExpression &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "additive-expression"; + if (node.additive_expression == nullptr) { + std::cout << std::endl; + } else { + std::cout << ": "; + if (node.op == OP_PLUS) { + std::cout << "+"; + } else if (node.op == OP_MINUS) { + std::cout << "-"; + } else { + std::abort(); + } + std::cout << std::endl; + } add_depth(); - node.expression->accept(*this); + if (node.additive_expression != nullptr) + node.additive_expression->accept(*this); + node.term->accept(*this); remove_depth(); - return; - } - std::cout << std::endl; + return nullptr; } -void ASTPrinter::visit(ASTTerm &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "term"; - if (node.term == nullptr) { +Value* ASTPrinter::visit(ASTVar &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "var: " << node.id; + if (node.expression != nullptr) { + std::cout << "[]" << std::endl; + add_depth(); + node.expression->accept(*this); + remove_depth(); + return nullptr; + } std::cout << std::endl; - } else { - std::cout << ": "; - if (node.op == OP_MUL) { - std::cout << "*"; - } else if (node.op == OP_DIV) { - std::cout << "/"; + return nullptr; +} + +Value* ASTPrinter::visit(ASTTerm &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "term"; + if (node.term == nullptr) { + std::cout << std::endl; } else { - std::abort(); + std::cout << ": "; + if (node.op == OP_MUL) { + std::cout << "*"; + } else if (node.op == OP_DIV) { + std::cout << "/"; + } else { + std::abort(); + } + std::cout << std::endl; } - std::cout << std::endl; - } - add_depth(); - if (node.term != nullptr) - node.term->accept(*this); + add_depth(); + if (node.term != nullptr) + node.term->accept(*this); - node.factor->accept(*this); - remove_depth(); + node.factor->accept(*this); + remove_depth(); + return nullptr; } -void ASTPrinter::visit(ASTCall &node) { - _DEBUG_PRINT_N_(depth); - std::cout << "call: " << node.id << "()" << std::endl; - add_depth(); - for (auto arg : node.args) { - arg->accept(*this); - } - remove_depth(); +Value* ASTPrinter::visit(ASTCall &node) { + _DEBUG_PRINT_N_(depth); + std::cout << "call: " << node.id << "()" << std::endl; + add_depth(); + for (auto arg : node.args) { + arg->accept(*this); + } + remove_depth(); + return nullptr; } diff --git a/src/common/logging.cpp b/src/common/logging.cpp index 9d508956a1b2b051adfa19da833bb6ad9a3dec13..e733833efcdfce9b814e3f2f39abd7e543de7089 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -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); } diff --git a/src/common/syntax_tree.c b/src/common/syntax_tree.c index 0ac6e6bdd1e1b2a656d64363bb80a12129bb9cfa..1e9b35e89660735594de53befc0c6304551e9d32 100644 --- a/src/common/syntax_tree.c +++ b/src/common/syntax_tree.c @@ -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); +} diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3517289a664e381948d00149c869837d4a980430 --- /dev/null +++ b/src/io/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(cminus_io io.c) + +install( + TARGETS cminus_io + ARCHIVE DESTINATION lib +) diff --git a/src/io/io.c b/src/io/io.c new file mode 100644 index 0000000000000000000000000000000000000000..11b25c0bb5373ebe838c1d9631d749f9ae8c69c0 --- /dev/null +++ b/src/io/io.c @@ -0,0 +1,16 @@ +#include +#include +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); +} diff --git a/src/io/io.h b/src/io/io.h new file mode 100644 index 0000000000000000000000000000000000000000..0b0473953f10bb196d21262b5781dc56953af393 --- /dev/null +++ b/src/io/io.h @@ -0,0 +1,7 @@ +int input(); + +void output(int a); + +void outputFloat(float a); + +void neg_idx_except(); diff --git a/src/lightir/BasicBlock.cpp b/src/lightir/BasicBlock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f7daebe472bda5015e808a39022d15f17f2e071 --- /dev/null +++ b/src/lightir/BasicBlock.cpp @@ -0,0 +1,71 @@ +#include "BasicBlock.hpp" + +#include "Function.hpp" +#include "IRprinter.hpp" +#include "Module.hpp" + +#include + +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; +} diff --git a/src/lightir/CMakeLists.txt b/src/lightir/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..c519e4926e4dd7746fd6144c15d3860fb42470c8 --- /dev/null +++ b/src/lightir/CMakeLists.txt @@ -0,0 +1,18 @@ +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 +) diff --git a/src/lightir/Constant.cpp b/src/lightir/Constant.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dcdbd45300dbc1da791f97f19ac6b3947c4d8d0 --- /dev/null +++ b/src/lightir/Constant.cpp @@ -0,0 +1,116 @@ +#include "Constant.hpp" +#include "Module.hpp" + +#include +#include +#include +#include + +struct pair_hash { + template + std::size_t operator()(const std::pair val) const { + auto lhs = std::hash()(val.first); + auto rhs = + std::hash()(reinterpret_cast(val.second)); + return lhs ^ rhs; + } +}; + +static std::unordered_map, + std::unique_ptr, pair_hash> + cached_int; +static std::unordered_map, + std::unique_ptr, pair_hash> + cached_bool; +static std::unordered_map, + std::unique_ptr, pair_hash> + cached_float; +static std::unordered_map> 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( + 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( + 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(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 &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 &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(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( + 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(new ConstantZero(ty)); + return cached_zero[ty].get(); +} + +std::string ConstantZero::print() { return "zeroinitializer"; } diff --git a/src/lightir/Function.cpp b/src/lightir/Function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e48e57579c970e559058eff5b37af180506ebf7e --- /dev/null +++ b/src/lightir/Function.cpp @@ -0,0 +1,131 @@ +#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(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 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(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; +} diff --git a/src/lightir/GlobalVariable.cpp b/src/lightir/GlobalVariable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..906141bbdea71e8f961fba97b1a6959eb24ccfcc --- /dev/null +++ b/src/lightir/GlobalVariable.cpp @@ -0,0 +1,28 @@ +#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; +} diff --git a/src/lightir/IRprinter.cpp b/src/lightir/IRprinter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7eb40d633a37c1f35f4679029988c00126199bbc --- /dev/null +++ b/src/lightir/IRprinter.cpp @@ -0,0 +1,335 @@ +#include "IRprinter.hpp" +#include "Instruction.hpp" +#include +#include + +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(v)) { + op_ir += "@" + v->get_name(); + } else if (dynamic_cast(v)) { + op_ir += "@" + v->get_name(); + } else if (dynamic_cast(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 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 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(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(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; +} diff --git a/src/lightir/Instruction.cpp b/src/lightir/Instruction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..383b21f30153a8c97c542e3f794dd9719fb1b019 --- /dev/null +++ b/src/lightir/Instruction.cpp @@ -0,0 +1,364 @@ +#include "Instruction.hpp" +#include "BasicBlock.hpp" +#include "Function.hpp" +#include "IRprinter.hpp" +#include "Module.hpp" +#include "Type.hpp" + +#include +#include +#include +#include +#include + +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(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(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(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(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 args, BasicBlock *bb) + : BaseInst(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(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 args, + BasicBlock *bb) { + return create(func, args, bb); +} + +FunctionType *CallInst::get_function_type() const { + return static_cast(get_operand(0)->get_type()); +} + +BranchInst::BranchInst(Value *cond, BasicBlock *if_true, BasicBlock *if_false, + BasicBlock *bb) + : BaseInst(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 succs; + if (is_cond_br()) { + succs.push_back(static_cast(get_operand(1))); + succs.push_back(static_cast(get_operand(2))); + } else { + succs.push_back(static_cast(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(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 idxs, + BasicBlock *bb) + : BaseInst(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 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(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(ty); + } + } + } + return ty; +} + +Type *GetElementPtrInst::get_element_type() const { + return get_type()->get_pointer_element_type(); +} + +GetElementPtrInst *GetElementPtrInst::create_gep(Value *ptr, + std::vector idxs, + BasicBlock *bb) { + return create(ptr, idxs, bb); +} + +StoreInst::StoreInst(Value *val, Value *ptr, BasicBlock *bb) + : BaseInst(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(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(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(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(val->get_type())->get_num_bits() < + static_cast(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(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(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 vals, + std::vector val_bbs, BasicBlock *bb) + : BaseInst(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 vals, + std::vector val_bbs) { + return create(ty, vals, val_bbs, bb); +} diff --git a/src/lightir/Module.cpp b/src/lightir/Module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..daf62e475a95f962647f145bbdc1eb164a01eac2 --- /dev/null +++ b/src/lightir/Module.cpp @@ -0,0 +1,80 @@ +#include "Module.hpp" +#include "Function.hpp" +#include "GlobalVariable.hpp" + +#include +#include + +Module::Module() { + void_ty_ = std::make_unique(Type::VoidTyID, this); + label_ty_ = std::make_unique(Type::LabelTyID, this); + int1_ty_ = std::make_unique(1, this); + int32_ty_ = std::make_unique(32, this); + float32_ty_ = std::make_unique(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(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(contained, num_elements); + } + return array_map_[{contained, num_elements}].get(); +} + +FunctionType *Module::get_function_type(Type *retty, + std::vector &args) { + if (not function_map_.count({retty, args})) { + function_map_[{retty, args}] = + std::make_unique(retty, args); + } + return function_map_[{retty, args}].get(); +} + +void Module::add_function(Function *f) { function_list_.push_back(f); } +llvm::ilist &Module::get_functions() { return function_list_; } +void Module::add_global_variable(GlobalVariable *g) { + global_list_.push_back(g); +} +llvm::ilist &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; +} diff --git a/src/lightir/Type.cpp b/src/lightir/Type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30a0313558af4f8897c1702efba44f80c53d9644 --- /dev/null +++ b/src/lightir/Type.cpp @@ -0,0 +1,181 @@ +#include "Type.hpp" +#include "Module.hpp" + +#include +#include +#include + +Type::Type(TypeID tid, Module *m) { + tid_ = tid; + m_ = m; +} + +bool Type::is_int1_type() const { + return is_integer_type() and + static_cast(this)->get_num_bits() == 1; +} +bool Type::is_int32_type() const { + return is_integer_type() and + static_cast(this)->get_num_bits() == 32; +} + +Type *Type::get_pointer_element_type() const { + if (this->is_pointer_type()) + return static_cast(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(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(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(this)->get_num_bits()); + break; + case FunctionTyID: + type_ir += + static_cast(this)->get_return_type()->print(); + type_ir += " ("; + for (unsigned i = 0; + i < static_cast(this)->get_num_of_args(); + i++) { + if (i) + type_ir += ", "; + type_ir += static_cast(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(this)->get_num_of_elements()); + type_ir += " x "; + type_ir += + static_cast(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 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 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(); } diff --git a/src/lightir/User.cpp b/src/lightir/User.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c0f0a5a7d0382c0cd1e480736f862eacb1bc64f --- /dev/null +++ b/src/lightir/User.cpp @@ -0,0 +1,41 @@ +#include "User.hpp" + +#include + +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); +} diff --git a/src/lightir/Value.cpp b/src/lightir/Value.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90b8c6ed34f11dd430254366aacbba19ab05dc83 --- /dev/null +++ b/src/lightir/Value.cpp @@ -0,0 +1,43 @@ +#include "Value.hpp" +#include "Type.hpp" +#include "User.hpp" + +#include + +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 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); + } +} diff --git a/src/parser/lexer.c b/src/parser/lexer.c index 7920b92602a7fd1453814465e9ffec8f321a73b2..526456badab742ef959afe0ba64e39798e542324 100755 --- a/src/parser/lexer.c +++ b/src/parser/lexer.c @@ -1,7 +1,7 @@ -#include -#include -#include -#include +#include +#include +#include +#include /// 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; } diff --git a/src/parser/parser.c b/src/parser/parser.c index e73874676daf7422cab2e5c516a859288447b0d9..174e3922ae45e3d3bacda5e836fa3f44bef8d0af 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -1,14 +1,13 @@ #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 \n", argv[0]); return 1; } diff --git a/tests/1-parser/eval_phase2.sh b/tests/1-parser/eval_phase2.sh index b9aa9c4ac2d9df857c16bc4bda93c55053aab52a..74626feaca71c5c16a895269f8eed66008e395c2 100755 --- a/tests/1-parser/eval_phase2.sh +++ b/tests/1-parser/eval_phase2.sh @@ -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 diff --git a/tests/2-ir-gen/autogen/.gitignore b/tests/2-ir-gen/autogen/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b524e95fe1be30a6a5ebb41e96a8e60fb95ff923 --- /dev/null +++ b/tests/2-ir-gen/autogen/.gitignore @@ -0,0 +1 @@ +eval_result diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/decl_float.out b/tests/2-ir-gen/autogen/answers/lv0_1/decl_float.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/decl_float_array.out b/tests/2-ir-gen/autogen/answers/lv0_1/decl_float_array.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/decl_int.out b/tests/2-ir-gen/autogen/answers/lv0_1/decl_int.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/decl_int_array.out b/tests/2-ir-gen/autogen/answers/lv0_1/decl_int_array.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/input.in b/tests/2-ir-gen/autogen/answers/lv0_1/input.in new file mode 100644 index 0000000000000000000000000000000000000000..b8626c4cff2849624fb67f87cd0ad72b163671ad --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_1/input.in @@ -0,0 +1 @@ +4 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/input.out b/tests/2-ir-gen/autogen/answers/lv0_1/input.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/output_float.out b/tests/2-ir-gen/autogen/answers/lv0_1/output_float.out new file mode 100644 index 0000000000000000000000000000000000000000..306e815ee0dc74207d8a1e817de0dda839af7bac --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_1/output_float.out @@ -0,0 +1 @@ +123.400002 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/output_int.out b/tests/2-ir-gen/autogen/answers/lv0_1/output_int.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_1/output_int.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv0_1/return.out b/tests/2-ir-gen/autogen/answers/lv0_1/return.out new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_add_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_add_float.out new file mode 100644 index 0000000000000000000000000000000000000000..190a18037c64c43e6b11489df4bf0b9eb6d2c9bf --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_add_float.out @@ -0,0 +1 @@ +123 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_add_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_add_int.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_add_int.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_add_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_add_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..b70608fe859d50b66977fb9a0ed9374877353128 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_add_mixed.out @@ -0,0 +1 @@ +1023 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_comp1.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_comp1.out new file mode 100644 index 0000000000000000000000000000000000000000..216134747c6b49517b32e75225cfedd95ac9dd23 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_comp1.out @@ -0,0 +1 @@ +-44.720001 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_comp2.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_comp2.out new file mode 100644 index 0000000000000000000000000000000000000000..d9ff83f194985daf47a3f5f8160f991b8feab351 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_comp2.out @@ -0,0 +1,4 @@ +1 +1 +0 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_div_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_div_float.out new file mode 100644 index 0000000000000000000000000000000000000000..48082f72f087ce7e6fa75b9c41d7387daecd447b --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_div_float.out @@ -0,0 +1 @@ +12 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_div_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_div_int.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_div_int.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_div_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_div_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..48082f72f087ce7e6fa75b9c41d7387daecd447b --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_div_mixed.out @@ -0,0 +1 @@ +12 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_float.out new file mode 100644 index 0000000000000000000000000000000000000000..7938dcdde861e064110513be9b948f63d726d024 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_float.out @@ -0,0 +1,3 @@ +0 +1 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_int.out new file mode 100644 index 0000000000000000000000000000000000000000..7938dcdde861e064110513be9b948f63d726d024 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_int.out @@ -0,0 +1,3 @@ +0 +1 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..7938dcdde861e064110513be9b948f63d726d024 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_eq_mixed.out @@ -0,0 +1,3 @@ +0 +1 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_float.out new file mode 100644 index 0000000000000000000000000000000000000000..986394f7c0fa05e52a94a3d93dee7085ed84cca4 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_float.out @@ -0,0 +1,3 @@ +0 +1 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_int.out new file mode 100644 index 0000000000000000000000000000000000000000..986394f7c0fa05e52a94a3d93dee7085ed84cca4 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_int.out @@ -0,0 +1,3 @@ +0 +1 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..986394f7c0fa05e52a94a3d93dee7085ed84cca4 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_ge_mixed.out @@ -0,0 +1,3 @@ +0 +1 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_float.out new file mode 100644 index 0000000000000000000000000000000000000000..bb5ee5c21ebeadb60f37f55e05206c18a219be58 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_float.out @@ -0,0 +1,3 @@ +0 +0 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_int.out new file mode 100644 index 0000000000000000000000000000000000000000..bb5ee5c21ebeadb60f37f55e05206c18a219be58 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_int.out @@ -0,0 +1,3 @@ +0 +0 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..bb5ee5c21ebeadb60f37f55e05206c18a219be58 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_gt_mixed.out @@ -0,0 +1,3 @@ +0 +0 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_le_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_le_float.out new file mode 100644 index 0000000000000000000000000000000000000000..2f1465d1598d82611e4e9081f6a149dcaf57f937 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_le_float.out @@ -0,0 +1,3 @@ +1 +1 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_le_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_le_int.out new file mode 100644 index 0000000000000000000000000000000000000000..2f1465d1598d82611e4e9081f6a149dcaf57f937 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_le_int.out @@ -0,0 +1,3 @@ +1 +1 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_le_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_le_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..2f1465d1598d82611e4e9081f6a149dcaf57f937 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_le_mixed.out @@ -0,0 +1,3 @@ +1 +1 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_float.out new file mode 100644 index 0000000000000000000000000000000000000000..e22493782f088a61eee427426ee46732c94f5238 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_float.out @@ -0,0 +1,3 @@ +1 +0 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_int.out new file mode 100644 index 0000000000000000000000000000000000000000..e22493782f088a61eee427426ee46732c94f5238 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_int.out @@ -0,0 +1,3 @@ +1 +0 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..e22493782f088a61eee427426ee46732c94f5238 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_lt_mixed.out @@ -0,0 +1,3 @@ +1 +0 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_float.out new file mode 100644 index 0000000000000000000000000000000000000000..190a18037c64c43e6b11489df4bf0b9eb6d2c9bf --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_float.out @@ -0,0 +1 @@ +123 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_int.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_int.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..190a18037c64c43e6b11489df4bf0b9eb6d2c9bf --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_mul_mixed.out @@ -0,0 +1 @@ +123 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_float.out new file mode 100644 index 0000000000000000000000000000000000000000..16db301bb512cb809eb9cc31acf34eb98cb19541 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_float.out @@ -0,0 +1,3 @@ +1 +0 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_int.out new file mode 100644 index 0000000000000000000000000000000000000000..16db301bb512cb809eb9cc31acf34eb98cb19541 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_int.out @@ -0,0 +1,3 @@ +1 +0 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..16db301bb512cb809eb9cc31acf34eb98cb19541 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_neq_mixed.out @@ -0,0 +1,3 @@ +1 +0 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_float.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_float.out new file mode 100644 index 0000000000000000000000000000000000000000..86a0307199419a10492c4e4a044feb9f6580c607 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_float.out @@ -0,0 +1 @@ +192 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_int.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_int.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_int.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_mixed.out b/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_mixed.out new file mode 100644 index 0000000000000000000000000000000000000000..1862496d6f86193d05ecb82454f8f834302b23e4 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv0_2/num_sub_mixed.out @@ -0,0 +1 @@ +1923 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_cmp.out b/tests/2-ir-gen/autogen/answers/lv1/assign_cmp.out new file mode 100644 index 0000000000000000000000000000000000000000..e22493782f088a61eee427426ee46732c94f5238 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_cmp.out @@ -0,0 +1,3 @@ +1 +0 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_float_array_global.out b/tests/2-ir-gen/autogen/answers/lv1/assign_float_array_global.out new file mode 100644 index 0000000000000000000000000000000000000000..16b42d8960ddee4fe712a0b6c73b9b15eb63c190 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_float_array_global.out @@ -0,0 +1 @@ +1234.000000 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_float_array_local.out b/tests/2-ir-gen/autogen/answers/lv1/assign_float_array_local.out new file mode 100644 index 0000000000000000000000000000000000000000..16b42d8960ddee4fe712a0b6c73b9b15eb63c190 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_float_array_local.out @@ -0,0 +1 @@ +1234.000000 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_float_var_global.out b/tests/2-ir-gen/autogen/answers/lv1/assign_float_var_global.out new file mode 100644 index 0000000000000000000000000000000000000000..16b42d8960ddee4fe712a0b6c73b9b15eb63c190 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_float_var_global.out @@ -0,0 +1 @@ +1234.000000 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_float_var_local.out b/tests/2-ir-gen/autogen/answers/lv1/assign_float_var_local.out new file mode 100644 index 0000000000000000000000000000000000000000..16b42d8960ddee4fe712a0b6c73b9b15eb63c190 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_float_var_local.out @@ -0,0 +1 @@ +1234.000000 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_int_array_global.out b/tests/2-ir-gen/autogen/answers/lv1/assign_int_array_global.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_int_array_global.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_int_array_local.out b/tests/2-ir-gen/autogen/answers/lv1/assign_int_array_local.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_int_array_local.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_int_var_global.out b/tests/2-ir-gen/autogen/answers/lv1/assign_int_var_global.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_int_var_global.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv1/assign_int_var_local.out b/tests/2-ir-gen/autogen/answers/lv1/assign_int_var_local.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/assign_int_var_local.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv1/idx_float.out b/tests/2-ir-gen/autogen/answers/lv1/idx_float.out new file mode 100644 index 0000000000000000000000000000000000000000..d7b1c440c0f3f8d42eff097800b88ac5d40263d3 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/idx_float.out @@ -0,0 +1 @@ +1024 diff --git a/tests/2-ir-gen/autogen/answers/lv1/innout.in b/tests/2-ir-gen/autogen/answers/lv1/innout.in new file mode 100644 index 0000000000000000000000000000000000000000..ec635144f60048986bc560c5576355344005e6e7 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/innout.in @@ -0,0 +1 @@ +9 diff --git a/tests/2-ir-gen/autogen/answers/lv1/innout.out b/tests/2-ir-gen/autogen/answers/lv1/innout.out new file mode 100644 index 0000000000000000000000000000000000000000..ec635144f60048986bc560c5576355344005e6e7 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/innout.out @@ -0,0 +1 @@ +9 diff --git a/tests/2-ir-gen/autogen/answers/lv1/iteration1.out b/tests/2-ir-gen/autogen/answers/lv1/iteration1.out new file mode 100644 index 0000000000000000000000000000000000000000..f4c0c86b6fd53583791a06fd72c2e2c67e231bf9 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/iteration1.out @@ -0,0 +1,10 @@ +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv1/iteration2.out b/tests/2-ir-gen/autogen/answers/lv1/iteration2.out new file mode 100644 index 0000000000000000000000000000000000000000..f4c0c86b6fd53583791a06fd72c2e2c67e231bf9 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/iteration2.out @@ -0,0 +1,10 @@ +10 +9 +8 +7 +6 +5 +4 +3 +2 +1 diff --git a/tests/2-ir-gen/autogen/answers/lv1/negidx_float.out b/tests/2-ir-gen/autogen/answers/lv1/negidx_float.out new file mode 100644 index 0000000000000000000000000000000000000000..d01226530903c1342e53189ffd82b4a86392a98d --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/negidx_float.out @@ -0,0 +1 @@ +negative index exception diff --git a/tests/2-ir-gen/autogen/answers/lv1/negidx_floatfuncall.out b/tests/2-ir-gen/autogen/answers/lv1/negidx_floatfuncall.out new file mode 100644 index 0000000000000000000000000000000000000000..d01226530903c1342e53189ffd82b4a86392a98d --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/negidx_floatfuncall.out @@ -0,0 +1 @@ +negative index exception diff --git a/tests/2-ir-gen/autogen/answers/lv1/negidx_int.out b/tests/2-ir-gen/autogen/answers/lv1/negidx_int.out new file mode 100644 index 0000000000000000000000000000000000000000..d01226530903c1342e53189ffd82b4a86392a98d --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/negidx_int.out @@ -0,0 +1 @@ +negative index exception diff --git a/tests/2-ir-gen/autogen/answers/lv1/negidx_intfuncall.out b/tests/2-ir-gen/autogen/answers/lv1/negidx_intfuncall.out new file mode 100644 index 0000000000000000000000000000000000000000..d01226530903c1342e53189ffd82b4a86392a98d --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/negidx_intfuncall.out @@ -0,0 +1 @@ +negative index exception diff --git a/tests/2-ir-gen/autogen/answers/lv1/negidx_voidfuncall.out b/tests/2-ir-gen/autogen/answers/lv1/negidx_voidfuncall.out new file mode 100644 index 0000000000000000000000000000000000000000..d01226530903c1342e53189ffd82b4a86392a98d --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/negidx_voidfuncall.out @@ -0,0 +1 @@ +negative index exception diff --git a/tests/2-ir-gen/autogen/answers/lv1/scope.out b/tests/2-ir-gen/autogen/answers/lv1/scope.out new file mode 100644 index 0000000000000000000000000000000000000000..1089b4f241a1b6986fc68fc931515a151ca44dd2 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/scope.out @@ -0,0 +1,3 @@ +3 +11 +3 diff --git a/tests/2-ir-gen/autogen/answers/lv1/selection1.out b/tests/2-ir-gen/autogen/answers/lv1/selection1.out new file mode 100644 index 0000000000000000000000000000000000000000..be6d407beda8e0edce6c5c577bb020e6bdc94172 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/selection1.out @@ -0,0 +1,2 @@ +42 +24 diff --git a/tests/2-ir-gen/autogen/answers/lv1/selection2.out b/tests/2-ir-gen/autogen/answers/lv1/selection2.out new file mode 100644 index 0000000000000000000000000000000000000000..be6d407beda8e0edce6c5c577bb020e6bdc94172 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/selection2.out @@ -0,0 +1,2 @@ +42 +24 diff --git a/tests/2-ir-gen/autogen/answers/lv1/selection3.out b/tests/2-ir-gen/autogen/answers/lv1/selection3.out new file mode 100644 index 0000000000000000000000000000000000000000..b34401c781e9c1aa80b761d3c1b9d3f6b093444a --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/selection3.out @@ -0,0 +1,3 @@ +42 +24 +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv1/transfer_float_to_int.out b/tests/2-ir-gen/autogen/answers/lv1/transfer_float_to_int.out new file mode 100644 index 0000000000000000000000000000000000000000..d00491fd7e5bb6fa28c517a0bb32b8b506539d4d --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/transfer_float_to_int.out @@ -0,0 +1 @@ +1 diff --git a/tests/2-ir-gen/autogen/answers/lv1/transfer_int_to_float.out b/tests/2-ir-gen/autogen/answers/lv1/transfer_int_to_float.out new file mode 100644 index 0000000000000000000000000000000000000000..961b372472a1809353ba4658ea88ca265d88b75c --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv1/transfer_int_to_float.out @@ -0,0 +1 @@ +1.000000 diff --git a/tests/2-ir-gen/autogen/answers/lv2/assign_chain.out b/tests/2-ir-gen/autogen/answers/lv2/assign_chain.out new file mode 100644 index 0000000000000000000000000000000000000000..1f242fa6f000425d17a7f6c74f77c4908e6b4ef4 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/assign_chain.out @@ -0,0 +1,3 @@ +3 +3 +3 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_array.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_array.out new file mode 100644 index 0000000000000000000000000000000000000000..f599e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_array.out @@ -0,0 +1 @@ +10 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_array_array.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_array_array.out new file mode 100644 index 0000000000000000000000000000000000000000..f4b3c38237507bd6fbf815484b32f2b924496596 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_array_array.out @@ -0,0 +1,2 @@ +1024 +1024 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_chain.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_chain.out new file mode 100644 index 0000000000000000000000000000000000000000..81c545efebe5f57d4cab2ba9ec294c4b0cadf672 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_chain.out @@ -0,0 +1 @@ +1234 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_float_array.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_float_array.out new file mode 100644 index 0000000000000000000000000000000000000000..00750edc07d6415dcc07ae0351e9397b0222b7ba --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_float_array.out @@ -0,0 +1 @@ +3 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_int_array.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_int_array.out new file mode 100644 index 0000000000000000000000000000000000000000..f599e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_int_array.out @@ -0,0 +1 @@ +10 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_type_mismatch1.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_type_mismatch1.out new file mode 100644 index 0000000000000000000000000000000000000000..f599e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_type_mismatch1.out @@ -0,0 +1 @@ +10 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_type_mismatch2.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_type_mismatch2.out new file mode 100644 index 0000000000000000000000000000000000000000..9406425c60fc6c56a6ddcfaec9467d926c62225b --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_type_mismatch2.out @@ -0,0 +1 @@ +4.000000 diff --git a/tests/2-ir-gen/autogen/answers/lv2/funcall_var.out b/tests/2-ir-gen/autogen/answers/lv2/funcall_var.out new file mode 100644 index 0000000000000000000000000000000000000000..f599e28b8ab0d8c9c57a486c89c4a5132dcbd3b2 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/funcall_var.out @@ -0,0 +1 @@ +10 diff --git a/tests/2-ir-gen/autogen/answers/lv2/return_in_middle1.out b/tests/2-ir-gen/autogen/answers/lv2/return_in_middle1.out new file mode 100644 index 0000000000000000000000000000000000000000..573541ac9702dd3969c9bc859d2b91ec1f7e6e56 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/return_in_middle1.out @@ -0,0 +1 @@ +0 diff --git a/tests/2-ir-gen/autogen/answers/lv2/return_in_middle2.out b/tests/2-ir-gen/autogen/answers/lv2/return_in_middle2.out new file mode 100644 index 0000000000000000000000000000000000000000..573541ac9702dd3969c9bc859d2b91ec1f7e6e56 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/return_in_middle2.out @@ -0,0 +1 @@ +0 diff --git a/tests/2-ir-gen/autogen/answers/lv2/return_type_mismatch1.out b/tests/2-ir-gen/autogen/answers/lv2/return_type_mismatch1.out new file mode 100644 index 0000000000000000000000000000000000000000..0c56bea59441a7abdd96a7cfe49438eaf701beb4 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/return_type_mismatch1.out @@ -0,0 +1 @@ +233 diff --git a/tests/2-ir-gen/autogen/answers/lv2/return_type_mismatch2.out b/tests/2-ir-gen/autogen/answers/lv2/return_type_mismatch2.out new file mode 100644 index 0000000000000000000000000000000000000000..273675e2a8dfe3d520991c9f6e04d483ab9a32d8 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/return_type_mismatch2.out @@ -0,0 +1 @@ +7.000000 diff --git a/tests/2-ir-gen/autogen/answers/lv3/complex1.out b/tests/2-ir-gen/autogen/answers/lv3/complex1.out new file mode 100644 index 0000000000000000000000000000000000000000..b652fb0369622b4422aea4b471a1e30b6994b8ce --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv3/complex1.out @@ -0,0 +1,800 @@ +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 diff --git a/tests/2-ir-gen/autogen/answers/lv3/complex2.in b/tests/2-ir-gen/autogen/answers/lv3/complex2.in new file mode 100644 index 0000000000000000000000000000000000000000..ba6e481592b31ff68ad338a32ff6f4fdff724f12 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv3/complex2.in @@ -0,0 +1,10 @@ +9 +8 +7 +6 +5 +4 +3 +2 +1 +0 diff --git a/tests/2-ir-gen/autogen/answers/lv3/complex2.out b/tests/2-ir-gen/autogen/answers/lv3/complex2.out new file mode 100644 index 0000000000000000000000000000000000000000..8b1acc12b635c26f3decadeaa251729d3ce512e9 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv3/complex2.out @@ -0,0 +1,10 @@ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/tests/2-ir-gen/autogen/answers/lv3/complex3.in b/tests/2-ir-gen/autogen/answers/lv3/complex3.in new file mode 100644 index 0000000000000000000000000000000000000000..50a3a30207190ecbfc3889b758bec1dc4cac547a --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv3/complex3.in @@ -0,0 +1,2 @@ +78 +117 diff --git a/tests/2-ir-gen/autogen/answers/lv3/complex3.out b/tests/2-ir-gen/autogen/answers/lv3/complex3.out new file mode 100644 index 0000000000000000000000000000000000000000..a2720097dccb441015beb4f75766b9908ad46f5a --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv3/complex3.out @@ -0,0 +1 @@ +39 diff --git a/tests/2-ir-gen/autogen/answers/lv3/complex4.out b/tests/2-ir-gen/autogen/answers/lv3/complex4.out new file mode 100644 index 0000000000000000000000000000000000000000..b8136f43701c3d6ba46dc1ec64a3ae4d8867bd15 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv3/complex4.out @@ -0,0 +1,3 @@ +1.000000 +-0.200000 +0.400000 diff --git a/tests/2-ir-gen/autogen/eval_lab2.py b/tests/2-ir-gen/autogen/eval_lab2.py new file mode 100755 index 0000000000000000000000000000000000000000..e25399f0f2f0b601643fee0463247db7270cfb3e --- /dev/null +++ b/tests/2-ir-gen/autogen/eval_lab2.py @@ -0,0 +1,180 @@ +#!/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() diff --git a/tests/2-ir-gen/autogen/eval_lab2.sh b/tests/2-ir-gen/autogen/eval_lab2.sh new file mode 100755 index 0000000000000000000000000000000000000000..20fefb1918343f32bcee908a58a97b305400e78b --- /dev/null +++ b/tests/2-ir-gen/autogen/eval_lab2.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +python3 eval_lab2.py diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/decl_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..61949dfbea293c310dddadffff473ba0d1eb53a7 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_float.cminus @@ -0,0 +1,4 @@ +void main(void) { + float a; + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/decl_float_array.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_float_array.cminus new file mode 100644 index 0000000000000000000000000000000000000000..bd2895274d14e525cd98797b54f69c8921f2e4ab --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_float_array.cminus @@ -0,0 +1,4 @@ +void main(void) { + float a[10]; + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/decl_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..b4f1e348f4c38dff38af682a7d5be7dc7d53376f --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_int.cminus @@ -0,0 +1,4 @@ +void main(void) { + int a; + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/decl_int_array.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_int_array.cminus new file mode 100644 index 0000000000000000000000000000000000000000..249926a0c8a34c4a37191343224bbe5909247950 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/decl_int_array.cminus @@ -0,0 +1,4 @@ +void main(void) { + int a[10]; + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/input.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/input.cminus new file mode 100644 index 0000000000000000000000000000000000000000..6c1ef312529f5a15334fea07427cde39a4706d24 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/input.cminus @@ -0,0 +1,4 @@ +void main(void) { + input(); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/output_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/output_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..deef7f7dd69ac9166df247538c0d7d12cb6ceeed --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/output_float.cminus @@ -0,0 +1,4 @@ +void main(void) { + outputFloat(123.4); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/output_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/output_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..c135600b942aa9aaab4330d0c0a9b83afc1cfbfb --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/output_int.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(1234); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_1/return.cminus b/tests/2-ir-gen/autogen/testcases/lv0_1/return.cminus new file mode 100644 index 0000000000000000000000000000000000000000..464e22a87038092c2d4e4aeb431643e36df98bb5 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_1/return.cminus @@ -0,0 +1 @@ +void main(void) { return; } diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..75d9c3e473f2cf7acda0520a90ab0b95159248f3 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_float.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(100.0 + 23.4); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..026d14d38f20609d6881f4ddf25bcc95e06d8255 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_int.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(1000 + 234); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..e6f1aa5b1fee3b6918bbc4ad2bb88d84865d33f4 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_add_mixed.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(1000 + 23.4); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_comp1.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_comp1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..9cecb1e558012c3a116ce46a1479d23d2d459ca3 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_comp1.cminus @@ -0,0 +1,4 @@ +void main(void) { + outputFloat(9 + 1.2 / (2 * 2 + 5 - 6) * 3.2 - 55); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_comp2.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_comp2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..4aa5fbbfc530a5baa0b5386abd2b220ea773e4c4 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_comp2.cminus @@ -0,0 +1,7 @@ +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; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..c1c10b45f9c8729a8b64a82a51197b8e9e62d6ab --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_float.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(24.68 / 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..933a0d8204f1e780e9430e819cfe59d9bd32e124 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_int.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(2468 / 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..19eba765d2dc3fca2d31b980043f7520eb4dd20d --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_div_mixed.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(24.68 / 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..68551d25451d1feb727776ecc6ec74c4c28da0f0 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. == 2.); + output(2. == 2.); + output(3. == 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..2a0fceb3eb7cc8a5fa46552a4ca2d5e3d8842b33 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_int.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1 == 2); + output(2 == 2); + output(3 == 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..10a4f12060debab4289f960596178a395f945106 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_eq_mixed.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. == 2); + output(2. == 2); + output(3 == 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..e2eeeea59f9cde221458e79ff685a98d40c08915 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. >= 2.); + output(2. >= 2.); + output(3. >= 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..2536fc8287478f0e1ad15405feeb7c51e7284634 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_int.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1 >= 2); + output(2 >= 2); + output(3 >= 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..f5a2eba36603bca2380d4be1f3856b3f4a4675f8 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_ge_mixed.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. >= 2); + output(2. >= 2); + output(3 >= 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..b272fc2c4393017c3cff72d392ec0a923f893e66 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. > 2.); + output(2. > 2.); + output(3. > 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..e4b6009e04ef54af10e990a19ca36d78884c7259 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_int.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1 > 2); + output(2 > 2); + output(3 > 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..c3e6d7cc89f8f8918e21c6bc8cd137cb93a78bf0 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_gt_mixed.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. > 2); + output(2. > 2); + output(3 > 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..905440c0cedb0d2f65c751a4107784d6228c21e0 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. <= 2.); + output(2. <= 2.); + output(3. <= 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..320bd5bef05f010cdf5b814f1f83eae3ec6f4b35 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_int.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1 <= 2); + output(2 <= 2); + output(3 <= 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..f29aecf8f4d943f9a26b707e2971d1d5021368db --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_le_mixed.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. <= 2); + output(2. <= 2); + output(3 <= 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..a3ccf1b5b3c6299915dd84ad0cfe8f99114c4072 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. < 2.); + output(2. < 2.); + output(3. < 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..d96006418d5b0d7fb491b866c075e78d71a9149e --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_int.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1 < 2); + output(2 < 2); + output(3 < 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..be284822e293d9160b44d1e1dd81c020245366ec --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_lt_mixed.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. < 2); + output(2 < 2.); + output(3. < 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..124e3b1eeeb1404ec10997e07e695b3cc8e9b03e --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_float.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(2. * 61.7); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..b6e454a276b13fbb9e54406b992e1a81e7dff5c1 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_int.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(2 * 617); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..619596753c5c9b877d6cab925bf34889b6c29838 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_mul_mixed.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(2 * 61.7); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..1c0f9fcbce5236b05a3782d78d437b6e02400165 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. != 2.); + output(2. != 2.); + output(3. != 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..78020d86a065eccfdec9e39093a9b29a80d5a291 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_int.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1 != 2); + output(2 != 2); + output(3 != 2); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..8076ae8eba79f80b3216d095cf1e4fc00ad06310 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_neq_mixed.cminus @@ -0,0 +1,6 @@ +void main(void) { + output(1. != 2); + output(2 != 2.); + output(3 != 2.); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_float.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..2f4f89a7e1f463c39bde3229ce66126b4b159cfd --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_float.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(200.0 - 7.66); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_int.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..24ef9fcaffad11dc0cdb9813670d1aafd1cce45e --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_int.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(2000 - 766); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_mixed.cminus b/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_mixed.cminus new file mode 100644 index 0000000000000000000000000000000000000000..1ca099f65e3f574c81513ef7a48e745fefb5874d --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv0_2/num_sub_mixed.cminus @@ -0,0 +1,4 @@ +void main(void) { + output(2000 - 76.6); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_cmp.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_cmp.cminus new file mode 100644 index 0000000000000000000000000000000000000000..0bc93cf0fcc947e1482c0b53436e34d713e495ac --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_cmp.cminus @@ -0,0 +1,12 @@ +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; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_float_array_global.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_array_global.cminus new file mode 100644 index 0000000000000000000000000000000000000000..bd094b1a702293dd2aa5fe25dbd90a67adf28653 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_array_global.cminus @@ -0,0 +1,6 @@ +float b[10]; +void main(void) { + b[3] = 1234.0; + outputFloat(b[3]); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_float_array_local.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_array_local.cminus new file mode 100644 index 0000000000000000000000000000000000000000..bbccb00383a874ccc0fdab1a2a3843ff81d99935 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_array_local.cminus @@ -0,0 +1,6 @@ +void main(void) { + float b[10]; + b[3] = 1234.0; + outputFloat(b[3]); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_float_var_global.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_var_global.cminus new file mode 100644 index 0000000000000000000000000000000000000000..3890958296e438c681d185ce4774168479af250d --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_var_global.cminus @@ -0,0 +1,6 @@ +float b; +void main(void) { + b = 1234.0; + outputFloat(b); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_float_var_local.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_var_local.cminus new file mode 100644 index 0000000000000000000000000000000000000000..fa08600bde592cb50e80285458fe546bd019b1c6 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_float_var_local.cminus @@ -0,0 +1,6 @@ +void main(void) { + float b; + b = 1234.0; + outputFloat(b); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_int_array_global.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_array_global.cminus new file mode 100644 index 0000000000000000000000000000000000000000..625125290b8ba62656a81e22871ed6e17c0b1565 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_array_global.cminus @@ -0,0 +1,6 @@ +int a[10]; +void main(void) { + a[3] = 1234; + output(a[3]); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_int_array_local.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_array_local.cminus new file mode 100644 index 0000000000000000000000000000000000000000..283e0d31b671c855f59b6dfe815c8d6803139afa --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_array_local.cminus @@ -0,0 +1,6 @@ +void main(void) { + int a[10]; + a[3] = 1234; + output(a[3]); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_int_var_global.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_var_global.cminus new file mode 100644 index 0000000000000000000000000000000000000000..ecaa8ad18aa3ab71d7a0a53d947e494b16d4289e --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_var_global.cminus @@ -0,0 +1,6 @@ +int a; +void main(void) { + a = 1234; + output(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/assign_int_var_local.cminus b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_var_local.cminus new file mode 100644 index 0000000000000000000000000000000000000000..0b688c8a7ec0b444f2bb060ad61c40711d9876d1 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/assign_int_var_local.cminus @@ -0,0 +1,6 @@ +void main(void) { + int a; + a = 1234; + output(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/idx_float.cminus b/tests/2-ir-gen/autogen/testcases/lv1/idx_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..f214eacd2826ef8f722bb60e093d0e0687f3eb1a --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/idx_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + int a[10]; + a[0] = 1024; + output(a[0.1]); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/innout.cminus b/tests/2-ir-gen/autogen/testcases/lv1/innout.cminus new file mode 100644 index 0000000000000000000000000000000000000000..eaabfe999a8f935592f0ed99d3854d9c8ef4bb23 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/innout.cminus @@ -0,0 +1,6 @@ +void main(void) { + int a; + a = input(); + output(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/iteration1.cminus b/tests/2-ir-gen/autogen/testcases/lv1/iteration1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..379f27fc362db7537eb9c6a968c50225d6f08446 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/iteration1.cminus @@ -0,0 +1,9 @@ +void main(void) { + int i; + i = 10; + while (i) { + output(i); + i = i - 1; + } + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/iteration2.cminus b/tests/2-ir-gen/autogen/testcases/lv1/iteration2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..ec17bb3e29fdba02618faa6b8f0a9b9c4cab109c --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/iteration2.cminus @@ -0,0 +1,9 @@ +void main(void) { + int i; + i = 10; + while (i > 0) { + output(i); + i = i - 1; + } + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/negidx_float.cminus b/tests/2-ir-gen/autogen/testcases/lv1/negidx_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..94558abd8def1e28fe5703e617e96eea7937783e --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/negidx_float.cminus @@ -0,0 +1,5 @@ +void main(void) { + int a[10]; + a[2. - 3]; + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/negidx_floatfuncall.cminus b/tests/2-ir-gen/autogen/testcases/lv1/negidx_floatfuncall.cminus new file mode 100644 index 0000000000000000000000000000000000000000..24c27f73e1b2b838a23bc3eddc76c7a93c7a8c16 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/negidx_floatfuncall.cminus @@ -0,0 +1,9 @@ +float test(void) { + int a[10]; + a[2 - 3]; + return 2.; +} +void main(void) { + test(); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/negidx_int.cminus b/tests/2-ir-gen/autogen/testcases/lv1/negidx_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..509baeded09a093836b9ecef0e8e14b7db9548f6 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/negidx_int.cminus @@ -0,0 +1,5 @@ +void main(void) { + int a[10]; + a[2 - 3]; + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/negidx_intfuncall.cminus b/tests/2-ir-gen/autogen/testcases/lv1/negidx_intfuncall.cminus new file mode 100644 index 0000000000000000000000000000000000000000..508a6be7fd87b9baa4dfb39ea2ef703de2f82982 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/negidx_intfuncall.cminus @@ -0,0 +1,9 @@ +int test(void) { + int a[10]; + a[2 - 3]; + return 2; +} +void main(void) { + test(); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/negidx_voidfuncall.cminus b/tests/2-ir-gen/autogen/testcases/lv1/negidx_voidfuncall.cminus new file mode 100644 index 0000000000000000000000000000000000000000..f1e1bec25b4bd746f341795619918adb93302e72 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/negidx_voidfuncall.cminus @@ -0,0 +1,9 @@ +void test(void) { + int a[10]; + a[2 - 3]; + return; +} +void main(void) { + test(); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/scope.cminus b/tests/2-ir-gen/autogen/testcases/lv1/scope.cminus new file mode 100644 index 0000000000000000000000000000000000000000..deecaea0102d32b7771575e5124d518bbd0ab04b --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/scope.cminus @@ -0,0 +1,12 @@ +void main(void) { + int a; + a = 3; + output(a); + { + int a; + a = 11; + output(a); + } + output(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/selection1.cminus b/tests/2-ir-gen/autogen/testcases/lv1/selection1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..57be8c8b7508fff2228b3861a2ec7351924ffb1d --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/selection1.cminus @@ -0,0 +1,8 @@ +void main(void) { + int a; + a = 2; + if (a) + output(42); + output(24); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/selection2.cminus b/tests/2-ir-gen/autogen/testcases/lv1/selection2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..065d863fcbbeacd01f17a90b87ee90f537a446f8 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/selection2.cminus @@ -0,0 +1,9 @@ +void main(void) { + if (2 > 1) + output(42); + output(24); + if (1 > 2) { + output(1234); + } + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/selection3.cminus b/tests/2-ir-gen/autogen/testcases/lv1/selection3.cminus new file mode 100644 index 0000000000000000000000000000000000000000..73ad4de3485e6fc8376ea44f1bcc8dff31f333dc --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/selection3.cminus @@ -0,0 +1,15 @@ +void main(void) { + if (2 > 1) { + output(42); + } else + output(1234); + + output(24); + + if (2 < 1) + output(42); + else { + output(1234); + } + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/transfer_float_to_int.cminus b/tests/2-ir-gen/autogen/testcases/lv1/transfer_float_to_int.cminus new file mode 100644 index 0000000000000000000000000000000000000000..99096fb78f5e10104a93eeffb7c5478d3b59d6dc --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/transfer_float_to_int.cminus @@ -0,0 +1,6 @@ +void main(void) { + int a; + a = 1.0; + output(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv1/transfer_int_to_float.cminus b/tests/2-ir-gen/autogen/testcases/lv1/transfer_int_to_float.cminus new file mode 100644 index 0000000000000000000000000000000000000000..ae281e7cd7c7494071c6d274151c83f74fe241d5 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv1/transfer_int_to_float.cminus @@ -0,0 +1,6 @@ +void main(void) { + float a; + a = 1; + outputFloat(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/assign_chain.cminus b/tests/2-ir-gen/autogen/testcases/lv2/assign_chain.cminus new file mode 100644 index 0000000000000000000000000000000000000000..8bac001e9279ca86f2cb74a5e61f77cf944b8aa7 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/assign_chain.cminus @@ -0,0 +1,10 @@ +void main(void) { + int a; + int b; + int c; + a = b = c = 3; + output(a); + output(b); + output(c); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/funcall_array_array.cminus b/tests/2-ir-gen/autogen/testcases/lv2/funcall_array_array.cminus new file mode 100644 index 0000000000000000000000000000000000000000..86760650aa1d4217293daec6a8907b05474b8e51 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/funcall_array_array.cminus @@ -0,0 +1,17 @@ +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; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/funcall_chain.cminus b/tests/2-ir-gen/autogen/testcases/lv2/funcall_chain.cminus new file mode 100644 index 0000000000000000000000000000000000000000..1253e6421abc2e0d7721a22c9c33ea64bf4cfc06 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/funcall_chain.cminus @@ -0,0 +1,7 @@ +int addone(int a) { return a + 1; } +void main(void) { + int result; + result = addone(addone(addone(addone(1230)))); + output(result); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/funcall_float_array.cminus b/tests/2-ir-gen/autogen/testcases/lv2/funcall_float_array.cminus new file mode 100644 index 0000000000000000000000000000000000000000..ea1c5247b15dae27fcdd7f0cc42473f3f84d21a4 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/funcall_float_array.cminus @@ -0,0 +1,11 @@ +void test(float a[]) { + output(a[3]); + return; +} + +void main(void) { + float a[10]; + a[3] = 3.14; + test(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/funcall_int_array.cminus b/tests/2-ir-gen/autogen/testcases/lv2/funcall_int_array.cminus new file mode 100644 index 0000000000000000000000000000000000000000..1772fad1501a093857a12787dc7bb38b1e5217ab --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/funcall_int_array.cminus @@ -0,0 +1,11 @@ +void test(int a[]) { + output(a[3]); + return; +} + +void main(void) { + int a[10]; + a[3] = 10; + test(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/funcall_type_mismatch1.cminus b/tests/2-ir-gen/autogen/testcases/lv2/funcall_type_mismatch1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..68010f21aa22f7233163af2628239bae4ba5606a --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/funcall_type_mismatch1.cminus @@ -0,0 +1,11 @@ +void f(int a) { + output(a); + return; +} + +void main(void) { + float a; + a = 10; + f(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/funcall_type_mismatch2.cminus b/tests/2-ir-gen/autogen/testcases/lv2/funcall_type_mismatch2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..74c9096927a8dbfb8d94c8756b658ef4847fd3cf --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/funcall_type_mismatch2.cminus @@ -0,0 +1,11 @@ +void f(float a) { + outputFloat(a); + return; +} + +void main(void) { + int a; + a = 4.5; + f(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/funcall_var.cminus b/tests/2-ir-gen/autogen/testcases/lv2/funcall_var.cminus new file mode 100644 index 0000000000000000000000000000000000000000..0bc2d84afb53efa8b2e7e1e619e5b4ed26baae30 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/funcall_var.cminus @@ -0,0 +1,11 @@ +void test(int a) { + output(a); + return; +} + +void main(void) { + int a; + a = 10; + test(a); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/return_in_middle1.cminus b/tests/2-ir-gen/autogen/testcases/lv2/return_in_middle1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..b71cb2726c8becd9f366c5cf5e831a6b364c4b74 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/return_in_middle1.cminus @@ -0,0 +1,16 @@ +int result(void) { + int i; + if (1) { + i = 1; + return 0; + } else { + i = 2; + } + output(3); + return 3; +} + +void main(void) { + output(result()); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/return_in_middle2.cminus b/tests/2-ir-gen/autogen/testcases/lv2/return_in_middle2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..9412aefc6dddcb9b5840579b4086ff22db19b539 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/return_in_middle2.cminus @@ -0,0 +1,14 @@ +int result(void) { + int i; + i = 10; + while (i > 0) { + return 0; + } + output(4); + return 1; +} + +void main(void) { + output(result()); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/return_type_mismatch1.cminus b/tests/2-ir-gen/autogen/testcases/lv2/return_type_mismatch1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..ae7047de1893a1fe63646a0a917d5e9690148361 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/return_type_mismatch1.cminus @@ -0,0 +1,6 @@ +int f(void) { return 233.3; } + +void main(void) { + output(f()); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv2/return_type_mismatch2.cminus b/tests/2-ir-gen/autogen/testcases/lv2/return_type_mismatch2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..4d8b0cda9548163fb8c14309a9c53c835180272a --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/return_type_mismatch2.cminus @@ -0,0 +1,6 @@ +float f(void) { return 7; } + +void main(void) { + outputFloat(f()); + return; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv3/complex1.cminus b/tests/2-ir-gen/autogen/testcases/lv3/complex1.cminus new file mode 100644 index 0000000000000000000000000000000000000000..b489c94b919fcf17dfe5ccec55cc62d05ba1af2a --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv3/complex1.cminus @@ -0,0 +1,71 @@ +/* + 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; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv3/complex2.cminus b/tests/2-ir-gen/autogen/testcases/lv3/complex2.cminus new file mode 100644 index 0000000000000000000000000000000000000000..2a7e064864849224ea05707922c5279d036cf421 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv3/complex2.cminus @@ -0,0 +1,50 @@ +/* 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; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv3/complex3.cminus b/tests/2-ir-gen/autogen/testcases/lv3/complex3.cminus new file mode 100644 index 0000000000000000000000000000000000000000..aa8fd0885908b9bfe4f4ccbf540d43e72f01a279 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv3/complex3.cminus @@ -0,0 +1,22 @@ +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; +} diff --git a/tests/2-ir-gen/autogen/testcases/lv3/complex4.cminus b/tests/2-ir-gen/autogen/testcases/lv3/complex4.cminus new file mode 100644 index 0000000000000000000000000000000000000000..db09eb0a191546d6f87cc027f38a2635ce3d69e6 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv3/complex4.cminus @@ -0,0 +1,105 @@ +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; + } +} diff --git a/tests/2-ir-gen/warmup/CMakeLists.txt b/tests/2-ir-gen/warmup/CMakeLists.txt new file mode 100755 index 0000000000000000000000000000000000000000..cf5bb42e679c6ff3a7a75a0b5facc93ebf85356d --- /dev/null +++ b/tests/2-ir-gen/warmup/CMakeLists.txt @@ -0,0 +1,45 @@ +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 +) diff --git a/tests/2-ir-gen/warmup/c_cases/assign.c b/tests/2-ir-gen/warmup/c_cases/assign.c new file mode 100644 index 0000000000000000000000000000000000000000..49ba5969259c7546226ebcf9bb63ba511b0195fe --- /dev/null +++ b/tests/2-ir-gen/warmup/c_cases/assign.c @@ -0,0 +1,6 @@ +int main() { + int a[10]; + a[0] = 10; + a[1] = a[0] * 2; + return a[1]; +} diff --git a/tests/2-ir-gen/warmup/c_cases/fun.c b/tests/2-ir-gen/warmup/c_cases/fun.c new file mode 100644 index 0000000000000000000000000000000000000000..7ab3a4b286996d74b93da65fe97fef83c387da46 --- /dev/null +++ b/tests/2-ir-gen/warmup/c_cases/fun.c @@ -0,0 +1,2 @@ +int callee(int a) { return 2 * a; } +int main() { return callee(110); } diff --git a/tests/2-ir-gen/warmup/c_cases/if.c b/tests/2-ir-gen/warmup/c_cases/if.c new file mode 100644 index 0000000000000000000000000000000000000000..9c3b3edb0ba4474a624b78fad0e657b98d75de17 --- /dev/null +++ b/tests/2-ir-gen/warmup/c_cases/if.c @@ -0,0 +1,6 @@ +int main() { + float a = 5.555; + if (a > 1) + return 233; + return 0; +} diff --git a/tests/2-ir-gen/warmup/c_cases/while.c b/tests/2-ir-gen/warmup/c_cases/while.c new file mode 100644 index 0000000000000000000000000000000000000000..dbd2479d47af4a3d6dd63aed4ed1613ca297533e --- /dev/null +++ b/tests/2-ir-gen/warmup/c_cases/while.c @@ -0,0 +1,11 @@ +int main() { + int a; + int i; + a = 10; + i = 0; + while (i < 10) { + i = i + 1; + a = a + i; + } + return a; +} diff --git a/tests/2-ir-gen/warmup/calculator/CMakeLists.txt b/tests/2-ir-gen/warmup/calculator/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..98c4d4729266ac92a8116729c0125e468f710f5a --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/CMakeLists.txt @@ -0,0 +1,27 @@ +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 diff --git a/tests/2-ir-gen/warmup/calculator/calc.cpp b/tests/2-ir-gen/warmup/calculator/calc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a156a2fd9081aa2500550b1fdac6ad004d193bc --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/calc.cpp @@ -0,0 +1,48 @@ +extern "C" { +#include "syntax_tree.h" +extern syntax_tree *parse(const char *); +} +#include "calc_ast.hpp" +#include "calc_builder.hpp" + +#include +#include +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 \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; +} diff --git a/tests/2-ir-gen/warmup/calculator/calc_ast.cpp b/tests/2-ir-gen/warmup/calculator/calc_ast.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0701dfa8468ffc2004e5a7dbbef24d513ffdc9f4 --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/calc_ast.cpp @@ -0,0 +1,115 @@ +#include "calc_ast.hpp" + +#include +#include +#include +#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(static_cast(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( + transform_node_iter(n->children[0])); + node->expression = std::shared_ptr(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( + transform_node_iter(n->children[0])); + node->expression = + std::shared_ptr(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(transform_node_iter(n->children[2])); + node->term = std::shared_ptr(term_node); + } else { + auto term_node = + static_cast(transform_node_iter(n->children[0])); + node->term = std::shared_ptr(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(transform_node_iter(n->children[0])); + node->term = std::shared_ptr(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( + transform_node_iter(n->children[2])); + node->factor = std::shared_ptr(factor_node); + } else { + auto factor_node = static_cast( + transform_node_iter(n->children[0])); + node->factor = std::shared_ptr(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(this); + if (expr) { + expr->accept(visitor); + return; + } + + auto num = dynamic_cast(this); + if (num) { + num->accept(visitor); + return; + } + + _AST_NODE_ERROR_ +} diff --git a/tests/2-ir-gen/warmup/calculator/calc_ast.hpp b/tests/2-ir-gen/warmup/calculator/calc_ast.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e9281e690a11a2dc6bc5cfb1418a0fc57951e770 --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/calc_ast.hpp @@ -0,0 +1,90 @@ +#pragma once + +extern "C" { +#include "syntax_tree.h" +extern syntax_tree *parse(const char *input); +} +#include +#include + +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 root = nullptr; +}; + +struct CalcASTNode { + virtual void accept(CalcASTVisitor &) = 0; + virtual ~CalcASTNode() = default; +}; + +struct CalcASTInput : CalcASTNode { + virtual void accept(CalcASTVisitor &) override final; + std::shared_ptr 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 expression; + AddOp op; + std::shared_ptr term; +}; + +struct CalcASTTerm : CalcASTNode { + virtual void accept(CalcASTVisitor &) override final; + std::shared_ptr term; + MulOp op; + std::shared_ptr factor; +}; + +class CalcASTVisitor { + public: + virtual void visit(CalcASTInput &) = 0; + virtual void visit(CalcASTNum &) = 0; + virtual void visit(CalcASTExpression &) = 0; + virtual void visit(CalcASTTerm &) = 0; +}; diff --git a/tests/2-ir-gen/warmup/calculator/calc_builder.cpp b/tests/2-ir-gen/warmup/calculator/calc_builder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37140ee3c01a1c1c5101ed9d82d3a958967abe57 --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/calc_builder.cpp @@ -0,0 +1,63 @@ +#include "calc_builder.hpp" +#include +std::unique_ptr CalcBuilder::build(CalcAST &ast) { + module = std::unique_ptr(new Module()); + builder = std::make_unique(nullptr, module.get()); + auto TyVoid = module->get_void_type(); + TyInt32 = module->get_int32_type(); + + std::vector 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()); +} diff --git a/tests/2-ir-gen/warmup/calculator/calc_builder.hpp b/tests/2-ir-gen/warmup/calculator/calc_builder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b2fe0d535aab10a3393be4b0a7631bc1b5eb274d --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/calc_builder.hpp @@ -0,0 +1,26 @@ +#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 + +class CalcBuilder : public CalcASTVisitor { + public: + std::unique_ptr 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 builder; + Value *val; + Type *TyInt32; + std::unique_ptr module; +}; diff --git a/tests/2-ir-gen/warmup/calculator/calculator.l b/tests/2-ir-gen/warmup/calculator/calculator.l new file mode 100644 index 0000000000000000000000000000000000000000..210e73a948f9cf4502362572c9316b40c7b51c94 --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/calculator.l @@ -0,0 +1,36 @@ +%option noyywrap +%{ +/*****************声明和选项设置 begin*****************/ +#include +#include + +#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;} +%% diff --git a/tests/2-ir-gen/warmup/calculator/calculator.y b/tests/2-ir-gen/warmup/calculator/calculator.y new file mode 100644 index 0000000000000000000000000000000000000000..b94d8a71b648435b8439091ecf521e48ee06cce3 --- /dev/null +++ b/tests/2-ir-gen/warmup/calculator/calculator.y @@ -0,0 +1,108 @@ +%{ +#include +#include +#include +#include + +#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 ADD +%token SUB +%token MUL +%token DIV +%token NUM +%token LPARENTHESE +%token RPARENTHESE +%type 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; +} diff --git a/tests/2-ir-gen/warmup/stu_cpp/assign_generator.cpp b/tests/2-ir-gen/warmup/stu_cpp/assign_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c272dabaeb6829b5ded592b4b37194ef3af364dd --- /dev/null +++ b/tests/2-ir-gen/warmup/stu_cpp/assign_generator.cpp @@ -0,0 +1 @@ +int main() {} \ No newline at end of file diff --git a/tests/2-ir-gen/warmup/stu_cpp/fun_generator.cpp b/tests/2-ir-gen/warmup/stu_cpp/fun_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c272dabaeb6829b5ded592b4b37194ef3af364dd --- /dev/null +++ b/tests/2-ir-gen/warmup/stu_cpp/fun_generator.cpp @@ -0,0 +1 @@ +int main() {} \ No newline at end of file diff --git a/tests/2-ir-gen/warmup/stu_cpp/if_generator.cpp b/tests/2-ir-gen/warmup/stu_cpp/if_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c272dabaeb6829b5ded592b4b37194ef3af364dd --- /dev/null +++ b/tests/2-ir-gen/warmup/stu_cpp/if_generator.cpp @@ -0,0 +1 @@ +int main() {} \ No newline at end of file diff --git a/tests/2-ir-gen/warmup/stu_cpp/while_generator.cpp b/tests/2-ir-gen/warmup/stu_cpp/while_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..237c8ce181774d991a9dbdd8cacf1a5fb9f199f1 --- /dev/null +++ b/tests/2-ir-gen/warmup/stu_cpp/while_generator.cpp @@ -0,0 +1 @@ +int main() {} diff --git a/tests/2-ir-gen/warmup/stu_ll/assign_hand.ll b/tests/2-ir-gen/warmup/stu_ll/assign_hand.ll new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/warmup/stu_ll/fun_hand.ll b/tests/2-ir-gen/warmup/stu_ll/fun_hand.ll new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/warmup/stu_ll/if_hand.ll b/tests/2-ir-gen/warmup/stu_ll/if_hand.ll new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/warmup/stu_ll/while_hand.ll b/tests/2-ir-gen/warmup/stu_ll/while_hand.ll new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/2-ir-gen/warmup/ta_gcd/gcd_array.c b/tests/2-ir-gen/warmup/ta_gcd/gcd_array.c new file mode 100644 index 0000000000000000000000000000000000000000..033ccbaca9a9907714a8966b05f7923732ca2ab2 --- /dev/null +++ b/tests/2-ir-gen/warmup/ta_gcd/gcd_array.c @@ -0,0 +1,29 @@ +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 diff --git a/tests/2-ir-gen/warmup/ta_gcd/gcd_array_generator.cpp b/tests/2-ir-gen/warmup/ta_gcd/gcd_array_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a1e9fe50af8a8b87008d152046c87f22d75d5c9 --- /dev/null +++ b/tests/2-ir-gen/warmup/ta_gcd/gcd_array_generator.cpp @@ -0,0 +1,230 @@ +#include "BasicBlock.hpp" +#include "Constant.hpp" +#include "Function.hpp" +#include "IRBuilder.hpp" +#include "Module.hpp" +#include "Type.hpp" + +#include +#include + +// 定义一个从常数值获取/创建 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 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 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 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 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; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ca25a59f65041c6bb171755b92e522d9907043bf --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory("2-ir-gen/warmup") \ No newline at end of file