diff --git a/include/lightir/BasicBlock.hpp b/include/lightir/BasicBlock.hpp index 1d1d3e174149816b5433831d639b1cbba94d2ef4..01d07d825981458c5a001e8f49575e60570eeabc 100644 --- a/include/lightir/BasicBlock.hpp +++ b/include/lightir/BasicBlock.hpp @@ -30,6 +30,7 @@ class BasicBlock : public Value, public llvm::ilist_node { 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); } + BasicBlock* get_entry_block_of_same_function(); // If the Block is terminated by ret/br bool is_terminated() const; diff --git a/include/lightir/Function.hpp b/include/lightir/Function.hpp index c7825e75c74413934fe85653bfb712321604a91a..0959e1fe520384adb401f0cc2712c4788674f090 100644 --- a/include/lightir/Function.hpp +++ b/include/lightir/Function.hpp @@ -46,6 +46,8 @@ class Function : public Value, public llvm::ilist_node { void set_instr_name(); std::string print(); + // 用于检查函数的基本块是否存在问题 + void check_for_block_relation_error(); private: llvm::ilist basic_blocks_; diff --git a/include/lightir/IRBuilder.hpp b/include/lightir/IRBuilder.hpp index 7774641e0b8d2430d684bc248e1f4997250d8756..0ca7dd9fc6269902a8c8c955f74859de35cfc0aa 100644 --- a/include/lightir/IRBuilder.hpp +++ b/include/lightir/IRBuilder.hpp @@ -86,6 +86,9 @@ class IRBuilder { AllocaInst *create_alloca(Type *ty) { return AllocaInst::create_alloca(ty, this->BB_); } + AllocaInst *create_alloca_begin(Type *ty) { + return AllocaInst::create_alloca_begin(ty, this->BB_); + } ZextInst *create_zext(Value *val, Type *ty) { return ZextInst::create_zext(val, ty, this->BB_); } diff --git a/include/lightir/Instruction.hpp b/include/lightir/Instruction.hpp index 184ebd5d8f1e81093ccc81cf1049a3cd65fddf02..6e6897523d754049c7fae6277f00125e703a6240 100644 --- a/include/lightir/Instruction.hpp +++ b/include/lightir/Instruction.hpp @@ -289,7 +289,8 @@ class AllocaInst : public BaseInst { public: static AllocaInst *create_alloca(Type *ty, BasicBlock *bb); - + static AllocaInst *create_alloca_begin(Type *ty, BasicBlock *bb); + Type *get_alloca_type() const { return get_type()->get_pointer_element_type(); }; diff --git a/src/cminusfc/main.cpp b/src/cminusfc/main.cpp index 456ec388bf5f595e0e91071b5e1ae6eb9a4e1688..1c1591f9033669d421997aca641732704ae3e75a 100644 --- a/src/cminusfc/main.cpp +++ b/src/cminusfc/main.cpp @@ -95,9 +95,11 @@ void Config::check() { if (input_file.empty()) { print_err("no input file"); } + /* if (input_file.extension() != ".cminus") { print_err("file format not recognized"); } + */ if (output_file.empty()) { output_file = input_file.stem(); } diff --git a/src/lightir/BasicBlock.cpp b/src/lightir/BasicBlock.cpp index 5f7daebe472bda5015e808a39022d15f17f2e071..ff671eb52ecb62b2f3dccfc5c693b0f3cc017ddb 100644 --- a/src/lightir/BasicBlock.cpp +++ b/src/lightir/BasicBlock.cpp @@ -69,3 +69,8 @@ std::string BasicBlock::print() { return bb_ir; } + +BasicBlock* BasicBlock::get_entry_block_of_same_function(){ + assert((not (parent_ == nullptr)) && "bb have no parent function"); + return parent_->get_entry_block(); +} \ No newline at end of file diff --git a/src/lightir/Function.cpp b/src/lightir/Function.cpp index e48e57579c970e559058eff5b37af180506ebf7e..dfb79a43963470cb7e96a038e8ccdcbaa87f4f3b 100644 --- a/src/lightir/Function.cpp +++ b/src/lightir/Function.cpp @@ -1,6 +1,10 @@ #include "Function.hpp" #include "IRprinter.hpp" #include "Module.hpp" +#include "Instruction.hpp" +#include +#include +#include Function::Function(FunctionType *ty, const std::string &name, Module *parent) : Value(ty, name), parent_(parent), seq_cnt_(0) { @@ -129,3 +133,103 @@ std::string Argument::print() { arg_ir += this->get_name(); return arg_ir; } + + +void Function::check_for_block_relation_error() +{ + // 检查函数的基本块表是否包含所有且仅包含 get_parent 是本函数的基本块 + std::unordered_set bbs; + for (auto& bb : basic_blocks_) + { + bbs.emplace(&bb); + } + for (auto& bb : basic_blocks_) + { + assert((bb.get_parent() == this) && "函数 F 的基本块表中包含基本块 a, 但 a 的 get_parent 方法不返回 F"); + for (auto i: bb.get_succ_basic_blocks()) + { + assert((bbs.count(i)) && "函数 F 的基本块表中包含基本块 a, a 的后继块表中的某基本块 b 不在 F 的基本块表中"); + } + for (auto i: bb.get_pre_basic_blocks()) + { + assert((bbs.count(i)) && "函数 F 的基本块表中包含基本块 a, a 的前驱块表中的某基本块 b 不在 F 的基本块表中"); + } + } + // 检查基本块的前驱和后继表不包含重复的基本块 + for (auto& bb : basic_blocks_) + { + bbs.clear(); + for(auto suc: bb.get_succ_basic_blocks()){ + assert((!bbs.count(suc)) && "基本块的后继表中包含重复项目"); + bbs.emplace(suc); + } + for(auto suc: bb.get_pre_basic_blocks()){ + assert((!bbs.count(suc)) && "基本块的前驱表中包含重复项目"); + bbs.emplace(suc); + } + } + // 检查基本块基本信息 + for (auto& bb : basic_blocks_) + { + assert((!bb.get_instructions().empty()) && "发现了空基本块"); + auto b = &bb.get_instructions().back(); + assert((b->is_br() || b->is_ret()) && "发现了无 terminator 基本块"); + assert((b->is_br() || bb.get_succ_basic_blocks().empty()) && "某基本块末尾是 ret 指令但是后继块表不是空的, 或者末尾是 br 但后继表为空"); + } + // 检查基本块前驱后继关系是否是与 branch 指令对应 + for (auto& bb : basic_blocks_) + { + if(!bb.get_succ_basic_blocks().empty()){ + std::unordered_set suc_table; + std::unordered_set br_get; + for (auto suc : bb.get_succ_basic_blocks()) + suc_table.emplace(suc); + auto& ops = bb.get_instructions().back().get_operands(); + for (auto i : ops) + { + auto bb2 = dynamic_cast(i); + if(bb2 != nullptr) br_get.emplace(bb2); + } + for(auto i : suc_table) + assert(br_get.count(i) && "基本块 A 的后继块有 B,但 B 并未在 A 的 br 指令中出现"); + for(auto i : br_get) + assert(suc_table.count(i) && "基本块 A 的后继块没有 B,但 B 在 A 的 br 指令中出现了"); + for(auto i : suc_table) { + bool ok = false; + for(auto j : i->get_pre_basic_blocks()) { + if(j == i){ + ok = true; + break; + } + } + assert(ok && "基本块 A 的后继块表中有 B,但 B 的前驱表中没有 A"); + } + } + } + // 检查基本块前驱后继关系是否是与 branch 指令对应 + for (auto& bb : basic_blocks_) + { + for (auto pre : bb.get_pre_basic_blocks()) + { + bool ok = false; + for (auto i : pre->get_succ_basic_blocks()) + { + if (i == &bb) + { + ok = true; + break; + } + } + if (!ok) + assert(false && "基本块 A 的后继块表中没有 B,但 B 的前驱表中有 A"); + } + } + // 检查指令 parent 设置 + for (auto& bb : basic_blocks_) + { + for (auto& inst : bb.get_instructions()) + { + assert ((inst.get_parent() == &bb) && "基本块 A 指令表包含指令 b, 但是 b 的 get_parent 函数不返回 A"); + } + } +} diff --git a/src/lightir/Instruction.cpp b/src/lightir/Instruction.cpp index 383b21f30153a8c97c542e3f794dd9719fb1b019..693655e3ac2852530d22c5052fbc5f83d4bc08e3 100644 --- a/src/lightir/Instruction.cpp +++ b/src/lightir/Instruction.cpp @@ -298,6 +298,16 @@ AllocaInst *AllocaInst::create_alloca(Type *ty, BasicBlock *bb) { return create(ty, bb); } +AllocaInst *AllocaInst::create_alloca_begin(Type *ty, BasicBlock *bb) { + auto ret = create(ty, nullptr); + if(bb != nullptr) + { + ret->set_parent(bb); + bb->add_instr_begin(ret); + } + return ret; +} + ZextInst::ZextInst(Value *val, Type *ty, BasicBlock *bb) : BaseInst(ty, zext, bb) { assert(val->get_type()->is_integer_type() && diff --git a/tests/2-ir-gen/autogen/answers/lv2/alloca_in_loop.out b/tests/2-ir-gen/autogen/answers/lv2/alloca_in_loop.out new file mode 100644 index 0000000000000000000000000000000000000000..573541ac9702dd3969c9bc859d2b91ec1f7e6e56 --- /dev/null +++ b/tests/2-ir-gen/autogen/answers/lv2/alloca_in_loop.out @@ -0,0 +1 @@ +0 diff --git a/tests/2-ir-gen/autogen/testcases/lv2/alloca_in_loop.cminus b/tests/2-ir-gen/autogen/testcases/lv2/alloca_in_loop.cminus new file mode 100644 index 0000000000000000000000000000000000000000..c58ed244ce0dff02f00c17247fac510866a941b7 --- /dev/null +++ b/tests/2-ir-gen/autogen/testcases/lv2/alloca_in_loop.cminus @@ -0,0 +1,11 @@ +void main(void) { + int i; + i = 0; + while (i < 16384) { + int a[16384]; + a[1] = i; + i = i + 1; + } + output(0); + return; +} diff --git a/tests/2-ir-gen/warmup/ta_gcd/gcd_array.ll b/tests/2-ir-gen/warmup/ta_gcd/gcd_array.ll new file mode 100644 index 0000000000000000000000000000000000000000..e2e27c217b41e74594ac88e96e24fa4537b99538 --- /dev/null +++ b/tests/2-ir-gen/warmup/ta_gcd/gcd_array.ll @@ -0,0 +1,85 @@ +@x = global [1 x i32] zeroinitializer +@y = global [1 x i32] zeroinitializer + +define i32 @gcd(i32 %0, i32 %1) { + %3 = alloca i32 + %4 = alloca i32 + %5 = alloca i32 + store i32 %0, i32* %4 + store i32 %1, i32* %5 + %6 = load i32, i32* %5 + %7 = icmp eq i32 %6, 0 + br i1 %7, label %8, label %10 + +8: + %9 = load i32, i32* %4 + store i32 %9, i32* %3 + br label %20 + +10: + %11 = load i32, i32* %5 + %12 = load i32, i32* %4 + %13 = load i32, i32* %4 + %14 = load i32, i32* %5 + %15 = sdiv i32 %13, %14 + %16 = load i32, i32* %5 + %17 = mul i32 %15, %16 + %18 = sub i32 %12, %17 + %19 = call i32 @gcd(i32 %11, i32 %18) + store i32 %19, i32* %3 + br label %20 + +20: + %21 = load i32, i32* %3 + ret i32 %21 +} + +define i32 @funArray(i32* %0, i32* %1) { + %3 = alloca i32* + %4 = alloca i32* + %5 = alloca i32 + %6 = alloca i32 + %7 = alloca i32 + store i32* %0, i32** %3 + store i32* %1, i32** %4 + %8 = load i32*, i32** %3 + %9 = getelementptr i32, i32* %8, i64 0 + %10 = load i32, i32* %9 + store i32 %10, i32* %5 + %11 = load i32*, i32** %4 + %12 = getelementptr i32, i32* %11, i64 0 + %13 = load i32, i32* %12 + store i32 %13, i32* %6 + %14 = load i32, i32* %5 + %15 = load i32, i32* %6 + %16 = icmp slt i32 %14, %15 + br i1 %16, label %17, label %21 + +17: + %18 = load i32, i32* %5 + store i32 %18, i32* %7 + %19 = load i32, i32* %6 + store i32 %19, i32* %5 + %20 = load i32, i32* %7 + store i32 %20, i32* %6 + br label %21 + +21: + %22 = load i32, i32* %5 + %23 = load i32, i32* %6 + %24 = call i32 @gcd(i32 %22, i32 %23) + ret i32 %24 +} + +define i32 @main() { + %1 = alloca i32 + store i32 0, i32* %1 + %2 = getelementptr [1 x i32], [1 x i32]* @x, i64 0, i64 0 + store i32 90, i32* %2 + %3 = getelementptr [1 x i32], [1 x i32]* @y, i64 0, i64 0 + store i32 18, i32* %3 + %4 = getelementptr [1 x i32], [1 x i32]* @x, i64 0, i64 0 + %5 = getelementptr [1 x i32], [1 x i32]* @y, i64 0, i64 0 + %6 = call i32 @funArray(i32* %4, i32* %5) + ret i32 %6 +} \ No newline at end of file