From 2de1561210d63e86bfe09679ac7ed13febb4c136 Mon Sep 17 00:00:00 2001 From: Oliveira <1350121858@qq.com> Date: Tue, 31 Mar 2026 13:56:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(irgen):=20=E5=AE=9E=E7=8E=B0=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E6=B5=81=E4=B8=8E=E9=80=BB=E8=BE=91=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=20-=20=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E5=8A=9F=E8=83=BD=E6=94=AF=E6=8C=81=EF=BC=9A=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E5=AE=9E=E7=8E=B0=20if-else,=20while,=20break,=20cont?= =?UTF-8?q?inue=20=E8=AF=AD=E5=8F=A5=E7=9A=84=20IR=20=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=8F=8A=E8=B7=B3=E5=87=BA=E5=9D=97=E7=BB=B4=E6=8A=A4=20-=20?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=8C=87=E4=BB=A4=E7=B3=BB=E7=BB=9F=EF=BC=9A?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20Cmp,=20Zext,=20Br,=20CondBr=20=E6=8C=87?= =?UTF-8?q?=E4=BB=A4=EF=BC=8C=E8=A1=A5=E9=BD=90=20Builder/Printer=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=20-=20=E6=94=AF=E6=8C=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=EF=BC=9A=E5=AE=8C=E6=88=90=20RelExp?= =?UTF-8?q?,=20EqExp,=20=E9=80=BB=E8=BE=91=E7=9F=AD=E8=B7=AF=E6=B1=82?= =?UTF-8?q?=E5=80=BC=20(LAndExp,=20LOrExp)=20=E5=8F=8A=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E9=9D=9E=E7=9A=84=E7=BF=BB=E8=AF=91=20-=20=E6=9E=B6=E6=9E=84?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9C=BA=E5=88=B6=20BUG=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=EF=BC=9A=20=20=201.=20=E4=BF=AE=E5=A4=8D=20Sema.cpp=20?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E8=A1=A8=E8=BE=BE=E5=BC=8F=20AST=20=E4=B8=A2?= =?UTF-8?q?=E5=A4=B1=E9=83=A8=E5=88=86=E5=88=86=E6=94=AF=E5=8F=98=E9=87=8F?= =?UTF-8?q?=E8=BF=BD=E8=B8=AA=E7=9A=84=E8=A7=A3=E6=9E=90=20Bug=20=20=202.?= =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=20IRGenDecl=20=E4=B8=AD=E6=89=93=E6=96=AD?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E7=BC=BA=E5=A4=B1=E5=AF=BC=E8=87=B4=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=86=97=E4=BD=99=E6=AD=BB=E5=9D=97=E7=BB=88=E6=AD=A2?= =?UTF-8?q?=E7=AC=A6=E7=9A=84=E9=97=AE=E9=A2=98=20=20=203.=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=B8=B4=E6=97=B6=E5=8F=98=E9=87=8F=E5=90=8D=E4=B8=BA?= =?UTF-8?q?=20%tN=EF=BC=8C=E8=A7=A3=E5=86=B3=E7=BA=AF=E6=95=B0=E5=80=BC?= =?UTF-8?q?=E6=A0=87=E5=8F=B7=E5=BC=95=E5=8F=91=E7=9A=84=20llc=20=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E5=BA=8F=E5=88=97=E6=A3=80=E6=9F=A5=E6=8A=A5=E9=94=99?= =?UTF-8?q?=20-=20=E6=96=87=E6=A1=A3=E6=9B=B4=E6=96=B0=EF=BC=9A=E4=BA=8E?= =?UTF-8?q?=20lab2=E5=89=A9=E4=BD=99=E4=BB=BB=E5=8A=A1=E5=88=86=E5=B7=A5.m?= =?UTF-8?q?d=20=E4=B8=AD=E6=A0=87=E8=AE=B0=E7=9B=B8=E5=85=B3=E8=BF=9B?= =?UTF-8?q?=E5=BA=A6=E4=B8=BA=E5=B7=B2=E5=AE=8C=E6=88=90=E5=B9=B6=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=B5=8B=E8=AF=95=E8=BF=90=E8=A1=8C=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/lab2剩余任务分工.md | 42 ++++++++++-- include/ir/IR.h | 44 +++++++++++- include/irgen/IRGen.h | 15 ++++ patch_IR_h.patch | 83 ++++++++++++++++++++++ src/ir/Context.cpp | 2 +- src/ir/IRBuilder.cpp | 40 +++++++++++ src/ir/IRPrinter.cpp | 73 +++++++++++++++++++- src/ir/Instruction.cpp | 61 ++++++++++++++++- src/ir/Type.cpp | 7 ++ src/ir/Value.cpp | 2 + src/irgen/IRGenDecl.cpp | 9 +-- src/irgen/IRGenExp.cpp | 125 ++++++++++++++++++++++++++++++++++ src/irgen/IRGenStmt.cpp | 119 +++++++++++++++++++++++++++----- src/sem/Sema.cpp | 8 +-- 14 files changed, 594 insertions(+), 36 deletions(-) create mode 100644 patch_IR_h.patch diff --git a/doc/lab2剩余任务分工.md b/doc/lab2剩余任务分工.md index 70e63de..8969726 100644 --- a/doc/lab2剩余任务分工.md +++ b/doc/lab2剩余任务分工.md @@ -5,7 +5,7 @@ - 任务 1.3:支持赋值表达式 - 任务 1.4:支持逗号分隔的多个变量声明 -### 人员 2:控制流支持 +### 人员 2:控制流支持(lyy,已完成) - 任务 2.1:支持 if-else 条件语句 - 任务 2.2:支持 while 循环语句 @@ -19,10 +19,6 @@ - 任务 3.3:支持函数调用生成 - 任务 3.4:支持 const 常量声明 -
- -
- ## 人员 1 完成情况详细说明(更新于 2026-03-30) ### ✅ 已完成任务 @@ -68,3 +64,39 @@ - **IR 构建**:`IRBuilder::CreateBinary`, `IRBuilder::CreateNeg`, `IRBuilder::CreateStore` 后续人员可以在此基础上扩展更复杂的功能(控制流、函数调用等)。 + +## 人员 2 完成情况详细说明(更新于 2026-03-31) + +### ✅ 已完成任务 + +人员 2 已完整实现 Lab2 IR 生成中涉及的控制流支持,包括: + +1. **IR 结构与底层辅助拓展** + - 补充 `Int1` 基础类型以及 `Value::IsInt1()`。 + - 新增 `CmpInst`, `ZextInst`, `BranchInst` 以及 `CondBranchInst` 以支持关系计算和跳转逻辑。 + - 在 `IRBuilder` 中补齐创建此类指令的便捷接口与 `IRPrinter` 适配,并修复了 `IRPrinter` 存在的块命名 `%%` 重复问题。 + - 优化 `Context::NextTemp` 分配命名使用 `%t` 前缀,解决非线性顺序下纯数字临时变量引发 `llc` 后端词法顺序验证失败问题。 +2. **比较和逻辑表达式**(任务 2.4) + - 新增实现 `visitRelExp`、`visitEqExp`。 + - 实现条件二元表达式全链路短路求值 (`visitLAndExp`、`visitLOrExp`)。短路时通过控制流跳转+利用局部栈变量分配并多次赋值记录实现栈传递,规避了 `phi` 的麻烦。 + - 利用 `visitCondUnaryExp` 增加逻辑非 `!` 判定。 +3. **控制流框架支持**(任务 2.1 - 2.3) + - 在 `visitStmt` 中完美实现了 `if-else` 条件语句(自动插入无条件跳合块)、`while` 循环语句。 + - 在 `IRGen` 实例中通过 `current_loop_cond_bb_` 等维护循环栈,实现了 `break` 与 `continue`。 + - 修复了此前框架在 `IRGenDecl.cpp` 的 `visitBlock` 中缺少终结向上传递导致的 `break` 生成不匹配死块 BUG 及重复 `Branch` 问题。 +4. **关键前序 Bug 修复** + - 发现了在原框架里 `src/sem/Sema.cpp` 进行 AST 解析时 `RelExp` 和 `EqExp` 对于非原生底层变量追踪由于左偏漏调规则导致 `null_ptr` (`变量使用缺少语义绑定:a`) 报错的问题,并做出了精修复。 + +### 🧪 测试验证 + +- **Lab2 语义分析**:修复后所有已有的语义正例验证正常。 +- **IR 生成与后端执行**:✅ 自建嵌套含复合逻辑循环脚本测试通过。 +- **验证命令**(运行含 break 和 while 的范例文件): + ```bash + cd build && make -j$(nproc) && cd .. && ./scripts/verify_ir.sh test/test_case/functional/29_break.sy --run + ``` + + **完整测试脚本** + ```bash + for f in test/test_case/functional/*.sy; do echo "Testing $f..."; ./scripts/verify_ir.sh "$f" --run > /dev/null || echo "FAILED $f"; done + ``` \ No newline at end of file diff --git a/include/ir/IR.h b/include/ir/IR.h index 6af2d96..06f837f 100644 --- a/include/ir/IR.h +++ b/include/ir/IR.h @@ -93,16 +93,18 @@ class Context { class Type { public: - enum class Kind { Void, Int32, PtrInt32 }; + enum class Kind { Void, Int1, Int32, PtrInt32 }; explicit Type(Kind k); // 使用静态共享对象获取类型。 // 同一类型可直接比较返回值是否相等,例如: // Type::GetInt32Type() == Type::GetInt32Type() static const std::shared_ptr& GetVoidType(); + static const std::shared_ptr& GetInt1Type(); static const std::shared_ptr& GetInt32Type(); static const std::shared_ptr& GetPtrInt32Type(); Kind GetKind() const; bool IsVoid() const; + bool IsInt1() const; bool IsInt32() const; bool IsPtrInt32() const; @@ -118,6 +120,7 @@ class Value { const std::string& GetName() const; void SetName(std::string n); bool IsVoid() const; + bool IsInt1() const; bool IsInt32() const; bool IsPtrInt32() const; bool IsConstant() const; @@ -153,7 +156,9 @@ class ConstantInt : public ConstantValue { // 后续还需要扩展更多指令类型。 // enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret }; -enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret }; +enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret, Cmp, Zext, Br, CondBr }; + +enum class CmpOp { Eq, Ne, Lt, Gt, Le, Ge }; // User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。 // 当前实现中只有 Instruction 继承自 User。 @@ -231,6 +236,37 @@ class StoreInst : public Instruction { Value* GetPtr() const; }; +class CmpInst : public Instruction { + public: + CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name); + CmpOp GetCmpOp() const; + Value* GetLhs() const; + Value* GetRhs() const; + + private: + CmpOp cmp_op_; +}; + +class ZextInst : public Instruction { + public: + ZextInst(std::shared_ptr dest_ty, Value* val, std::string name); + Value* GetValue() const; +}; + +class BranchInst : public Instruction { + public: + BranchInst(BasicBlock* dest); + BasicBlock* GetDest() const; +}; + +class CondBranchInst : public Instruction { + public: + CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb); + Value* GetCond() const; + BasicBlock* GetTrueBlock() const; + BasicBlock* GetFalseBlock() const; +}; + // BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。 // 当前其类型仍使用 void 作为占位,后续可替换为专门的 label type。 class BasicBlock : public Value { @@ -315,6 +351,10 @@ class IRBuilder { LoadInst* CreateLoad(Value* ptr, const std::string& name); StoreInst* CreateStore(Value* val, Value* ptr); ReturnInst* CreateRet(Value* v); + CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name); + ZextInst* CreateZext(Value* val, const std::string& name); + BranchInst* CreateBr(BasicBlock* dest); + CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb); private: Context& ctx_; diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h index 2ed1c85..fec791a 100644 --- a/include/irgen/IRGen.h +++ b/include/irgen/IRGen.h @@ -37,6 +37,12 @@ class IRGenImpl final : public SysYBaseVisitor { std::any visitAddExp(SysYParser::AddExpContext* ctx) override; std::any visitMulExp(SysYParser::MulExpContext* ctx) override; std::any visitUnaryExp(SysYParser::UnaryExpContext* ctx) override; + std::any visitRelExp(SysYParser::RelExpContext* ctx) override; + std::any visitEqExp(SysYParser::EqExpContext* ctx) override; + std::any visitLAndExp(SysYParser::LAndExpContext* ctx) override; + std::any visitLOrExp(SysYParser::LOrExpContext* ctx) override; + std::any visitCondUnaryExp(SysYParser::CondUnaryExpContext* ctx) override; + std::any visitCond(SysYParser::CondContext* ctx) override; private: enum class BlockFlow { @@ -53,6 +59,15 @@ class IRGenImpl final : public SysYBaseVisitor { ir::IRBuilder builder_; // 名称绑定由 Sema 负责;IRGen 只维护"变量名 -> 存储槽位"的代码生成状态。 std::unordered_map storage_map_; + + // 用于 break 和 continue 跳转的目标位置 + ir::BasicBlock* current_loop_cond_bb_ = nullptr; + ir::BasicBlock* current_loop_exit_bb_ = nullptr; + + int bb_cnt_ = 0; + std::string NextBlockName(const std::string& prefix = "bb") { + return prefix + "_" + std::to_string(++bb_cnt_); + } }; std::unique_ptr GenerateIR(SysYParser::CompUnitContext& tree, diff --git a/patch_IR_h.patch b/patch_IR_h.patch new file mode 100644 index 0000000..c1a32ce --- /dev/null +++ b/patch_IR_h.patch @@ -0,0 +1,83 @@ +--- include/ir/IR.h ++++ include/ir/IR.h +@@ -93,6 +93,7 @@ + class Type { + public: +- enum class Kind { Void, Int32, PtrInt32 }; ++ enum class Kind { Void, Int1, Int32, PtrInt32 }; + explicit Type(Kind k); + // 使用静态共享对象获取类型。 + // 同一类型可直接比较返回值是否相等,例如: + // Type::GetInt32Type() == Type::GetInt32Type() + static const std::shared_ptr& GetVoidType(); ++ static const std::shared_ptr& GetInt1Type(); + static const std::shared_ptr& GetInt32Type(); + static const std::shared_ptr& GetPtrInt32Type(); + Kind GetKind() const; + bool IsVoid() const; ++ bool IsInt1() const; + bool IsInt32() const; + bool IsPtrInt32() const; +@@ -118,6 +119,7 @@ + const std::string& GetName() const; + void SetName(std::string n); + bool IsVoid() const; ++ bool IsInt1() const; + bool IsInt32() const; + bool IsPtrInt32() const; + bool IsConstant() const; +@@ -153,7 +155,9 @@ + + // 后续还需要扩展更多指令类型。 +-// enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret }; +-enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret }; ++enum class Opcode { Add, Sub, Mul, Div, Mod, Neg, Alloca, Load, Store, Ret, Cmp, Zext, Br, CondBr }; ++ ++enum class CmpOp { Eq, Ne, Lt, Gt, Le, Ge }; + + // User 是所有“会使用其他 Value 作为输入”的 IR 对象的抽象基类。 +@@ -231,6 +235,33 @@ + Value* GetPtr() const; + }; + ++class CmpInst : public Instruction { ++ public: ++ CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name); ++ CmpOp GetCmpOp() const; ++ Value* GetLhs() const; ++ Value* GetRhs() const; ++ private: ++ CmpOp cmp_op_; ++}; ++ ++class ZextInst : public Instruction { ++ public: ++ ZextInst(std::shared_ptr dest_ty, Value* val, std::string name); ++ Value* GetValue() const; ++}; ++ ++class BranchInst : public Instruction { ++ public: ++ BranchInst(BasicBlock* dest); ++ BasicBlock* GetDest() const; ++}; ++ ++class CondBranchInst : public Instruction { ++ public: ++ CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb); ++ Value* GetCond() const; ++ BasicBlock* GetTrueBlock() const; ++ BasicBlock* GetFalseBlock() const; ++}; ++ + // BasicBlock 已纳入 Value 体系,便于后续向更完整 IR 类图靠拢。 +@@ -315,6 +346,10 @@ + LoadInst* CreateLoad(Value* ptr, const std::string& name); + StoreInst* CreateStore(Value* val, Value* ptr); + ReturnInst* CreateRet(Value* v); ++ CmpInst* CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name); ++ ZextInst* CreateZext(Value* val, const std::string& name); ++ BranchInst* CreateBr(BasicBlock* dest); ++ CondBranchInst* CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb); + + private: diff --git a/src/ir/Context.cpp b/src/ir/Context.cpp index 16c982c..5f32c65 100644 --- a/src/ir/Context.cpp +++ b/src/ir/Context.cpp @@ -17,7 +17,7 @@ ConstantInt* Context::GetConstInt(int v) { std::string Context::NextTemp() { std::ostringstream oss; - oss << "%" << ++temp_index_; + oss << "%t" << ++temp_index_; return oss.str(); } diff --git a/src/ir/IRBuilder.cpp b/src/ir/IRBuilder.cpp index 54cc5d2..3569ab6 100644 --- a/src/ir/IRBuilder.cpp +++ b/src/ir/IRBuilder.cpp @@ -104,4 +104,44 @@ UnaryInst* IRBuilder::CreateNeg(Value* operand, const std::string& name) { return insert_block_->Append(Opcode::Neg, Type::GetInt32Type(), operand, name); } +CmpInst* IRBuilder::CreateCmp(CmpOp op, Value* lhs, Value* rhs, const std::string& name) { + if (!insert_block_) { + throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点")); + } + if (!lhs || !rhs) { + throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCmp 缺少操作数")); + } + return insert_block_->Append(op, lhs, rhs, name); +} + +ZextInst* IRBuilder::CreateZext(Value* val, const std::string& name) { + if (!insert_block_) { + throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点")); + } + if (!val) { + throw std::runtime_error(FormatError("ir", "IRBuilder::CreateZext 缺少操作数")); + } + return insert_block_->Append(Type::GetInt32Type(), val, name); +} + +BranchInst* IRBuilder::CreateBr(BasicBlock* dest) { + if (!insert_block_) { + throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点")); + } + if (!dest) { + throw std::runtime_error(FormatError("ir", "IRBuilder::CreateBr 缺少操作数")); + } + return insert_block_->Append(dest); +} + +CondBranchInst* IRBuilder::CreateCondBr(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb) { + if (!insert_block_) { + throw std::runtime_error(FormatError("ir", "IRBuilder 未设置插入点")); + } + if (!cond || !true_bb || !false_bb) { + throw std::runtime_error(FormatError("ir", "IRBuilder::CreateCondBr 缺少操作数")); + } + return insert_block_->Append(cond, true_bb, false_bb); +} + } // namespace ir diff --git a/src/ir/IRPrinter.cpp b/src/ir/IRPrinter.cpp index 3716751..40cfc77 100644 --- a/src/ir/IRPrinter.cpp +++ b/src/ir/IRPrinter.cpp @@ -16,6 +16,8 @@ static const char* TypeToString(const Type& ty) { switch (ty.GetKind()) { case Type::Kind::Void: return "void"; + case Type::Kind::Int1: + return "i1"; case Type::Kind::Int32: return "i32"; case Type::Kind::PtrInt32: @@ -46,6 +48,31 @@ static const char* OpcodeToString(Opcode op) { return "store"; case Opcode::Ret: return "ret"; + case Opcode::Cmp: + return "icmp"; + case Opcode::Zext: + return "zext"; + case Opcode::Br: + case Opcode::CondBr: + return "br"; + } + return "?"; +} + +static const char* CmpOpToString(CmpOp op) { + switch (op) { + case CmpOp::Eq: + return "eq"; + case CmpOp::Ne: + return "ne"; + case CmpOp::Lt: + return "slt"; + case CmpOp::Gt: + return "sgt"; + case CmpOp::Le: + return "sle"; + case CmpOp::Ge: + return "sge"; } return "?"; } @@ -57,6 +84,21 @@ static std::string ValueToString(const Value* v) { return v ? v->GetName() : ""; } +static std::string PrintLabel(const Value* bb) { + if (!bb) return ""; + std::string name = bb->GetName(); + if (name.empty()) return ""; + if (name[0] == '%') return name; + return "%" + name; +} + +static std::string PrintLabelDef(const Value* bb) { + if (!bb) return ""; + std::string name = bb->GetName(); + if (!name.empty() && name[0] == '%') return name.substr(1); + return name; +} + void IRPrinter::Print(const Module& module, std::ostream& os) { for (const auto& func : module.GetFunctions()) { os << "define " << TypeToString(*func->GetType()) << " @" << func->GetName() @@ -65,7 +107,7 @@ void IRPrinter::Print(const Module& module, std::ostream& os) { if (!bb) { continue; } - os << bb->GetName() << ":\n"; + os << PrintLabelDef(bb.get()) << ":\n"; for (const auto& instPtr : bb->GetInstructions()) { const auto* inst = instPtr.get(); switch (inst->GetOpcode()) { @@ -113,6 +155,35 @@ void IRPrinter::Print(const Module& module, std::ostream& os) { << ValueToString(ret->GetValue()) << "\n"; break; } + case Opcode::Cmp: { + auto* cmp = static_cast(inst); + os << " " << cmp->GetName() << " = icmp " + << CmpOpToString(cmp->GetCmpOp()) << " " + << TypeToString(*cmp->GetLhs()->GetType()) << " " + << ValueToString(cmp->GetLhs()) << ", " + << ValueToString(cmp->GetRhs()) << "\n"; + break; + } + case Opcode::Zext: { + auto* zext = static_cast(inst); + os << " " << zext->GetName() << " = zext " + << TypeToString(*zext->GetOperand(0)->GetType()) << " " + << ValueToString(zext->GetOperand(0)) << " to " + << TypeToString(*zext->GetType()) << "\n"; + break; + } + case Opcode::Br: { + auto* br = static_cast(inst); + os << " br label " << PrintLabel(br->GetDest()) << "\n"; + break; + } + case Opcode::CondBr: { + auto* cbr = static_cast(inst); + os << " br i1 " << ValueToString(cbr->GetCond()) + << ", label " << PrintLabel(cbr->GetTrueBlock()) + << ", label " << PrintLabel(cbr->GetFalseBlock()) << "\n"; + break; + } } } } diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp index 199b123..9ae696c 100644 --- a/src/ir/Instruction.cpp +++ b/src/ir/Instruction.cpp @@ -52,7 +52,7 @@ Instruction::Instruction(Opcode op, std::shared_ptr ty, std::string name) Opcode Instruction::GetOpcode() const { return opcode_; } -bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret; } +bool Instruction::IsTerminator() const { return opcode_ == Opcode::Ret || opcode_ == Opcode::Br || opcode_ == Opcode::CondBr; } BasicBlock* Instruction::GetParent() const { return parent_; } @@ -172,4 +172,63 @@ Value* StoreInst::GetValue() const { return GetOperand(0); } Value* StoreInst::GetPtr() const { return GetOperand(1); } +CmpInst::CmpInst(CmpOp cmp_op, Value* lhs, Value* rhs, std::string name) + : Instruction(Opcode::Cmp, Type::GetInt1Type(), std::move(name)), cmp_op_(cmp_op) { + if (!lhs || !rhs) { + throw std::runtime_error(FormatError("ir", "CmpInst 缺少操作数")); + } + if (!lhs->GetType() || !rhs->GetType()) { + throw std::runtime_error(FormatError("ir", "CmpInst 缺少操作数类型信息")); + } + if (lhs->GetType()->GetKind() != rhs->GetType()->GetKind()) { + throw std::runtime_error(FormatError("ir", "CmpInst 操作数类型不匹配")); + } + AddOperand(lhs); + AddOperand(rhs); +} + +CmpOp CmpInst::GetCmpOp() const { return cmp_op_; } +Value* CmpInst::GetLhs() const { return GetOperand(0); } +Value* CmpInst::GetRhs() const { return GetOperand(1); } + +ZextInst::ZextInst(std::shared_ptr dest_ty, Value* val, std::string name) + : Instruction(Opcode::Zext, std::move(dest_ty), std::move(name)) { + if (!val) { + throw std::runtime_error(FormatError("ir", "ZextInst 缺少操作数")); + } + if (!type_->IsInt32() || !val->GetType()->IsInt1()) { + throw std::runtime_error(FormatError("ir", "ZextInst 当前只支持 i1 到 i32")); + } + AddOperand(val); +} + +Value* ZextInst::GetValue() const { return GetOperand(0); } + +BranchInst::BranchInst(BasicBlock* dest) + : Instruction(Opcode::Br, Type::GetVoidType(), "") { + if (!dest) { + throw std::runtime_error(FormatError("ir", "BranchInst 缺少目的块")); + } + AddOperand(dest); +} + +BasicBlock* BranchInst::GetDest() const { return static_cast(GetOperand(0)); } + +CondBranchInst::CondBranchInst(Value* cond, BasicBlock* true_bb, BasicBlock* false_bb) + : Instruction(Opcode::CondBr, Type::GetVoidType(), "") { + if (!cond || !true_bb || !false_bb) { + throw std::runtime_error(FormatError("ir", "CondBranchInst 缺少连边操作数")); + } + if (!cond->GetType()->IsInt1()) { + throw std::runtime_error(FormatError("ir", "CondBranchInst 必须使用 i1 作为条件")); + } + AddOperand(cond); + AddOperand(true_bb); + AddOperand(false_bb); +} + +Value* CondBranchInst::GetCond() const { return GetOperand(0); } +BasicBlock* CondBranchInst::GetTrueBlock() const { return static_cast(GetOperand(1)); } +BasicBlock* CondBranchInst::GetFalseBlock() const { return static_cast(GetOperand(2)); } + } // namespace ir diff --git a/src/ir/Type.cpp b/src/ir/Type.cpp index 3e1684d..c32d640 100644 --- a/src/ir/Type.cpp +++ b/src/ir/Type.cpp @@ -10,6 +10,11 @@ const std::shared_ptr& Type::GetVoidType() { return type; } +const std::shared_ptr& Type::GetInt1Type() { + static const std::shared_ptr type = std::make_shared(Kind::Int1); + return type; +} + const std::shared_ptr& Type::GetInt32Type() { static const std::shared_ptr type = std::make_shared(Kind::Int32); return type; @@ -24,6 +29,8 @@ Type::Kind Type::GetKind() const { return kind_; } bool Type::IsVoid() const { return kind_ == Kind::Void; } +bool Type::IsInt1() const { return kind_ == Kind::Int1; } + bool Type::IsInt32() const { return kind_ == Kind::Int32; } bool Type::IsPtrInt32() const { return kind_ == Kind::PtrInt32; } diff --git a/src/ir/Value.cpp b/src/ir/Value.cpp index 2e9f4c1..12a06b4 100644 --- a/src/ir/Value.cpp +++ b/src/ir/Value.cpp @@ -18,6 +18,8 @@ void Value::SetName(std::string n) { name_ = std::move(n); } bool Value::IsVoid() const { return type_ && type_->IsVoid(); } +bool Value::IsInt1() const { return type_ && type_->IsInt1(); } + bool Value::IsInt32() const { return type_ && type_->IsInt32(); } bool Value::IsPtrInt32() const { return type_ && type_->IsPtrInt32(); } diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp index df7ccf9..1cd0db8 100644 --- a/src/irgen/IRGenDecl.cpp +++ b/src/irgen/IRGenDecl.cpp @@ -10,15 +10,16 @@ std::any IRGenImpl::visitBlock(SysYParser::BlockContext* ctx) { if (!ctx) { throw std::runtime_error(FormatError("irgen", "缺少语句块")); } + bool terminated = false; for (auto* item : ctx->blockItem()) { if (item) { if (VisitBlockItemResult(*item) == BlockFlow::Terminated) { - // 当前语法要求 return 为块内最后一条语句;命中后可停止生成。 + terminated = true; break; } } } - return {}; + return terminated ? BlockFlow::Terminated : BlockFlow::Continue; } IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult( @@ -66,7 +67,7 @@ std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) { var_def->accept(this); } } - return {}; + return BlockFlow::Continue; } @@ -102,5 +103,5 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) { init = builder_.CreateConstInt(0); } builder_.CreateStore(init, slot); - return {}; + return BlockFlow::Continue; } diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp index 55c3cc2..4565c6e 100644 --- a/src/irgen/IRGenExp.cpp +++ b/src/irgen/IRGenExp.cpp @@ -201,4 +201,129 @@ std::any IRGenImpl::visitMulExp(SysYParser::MulExpContext* ctx) { return static_cast( builder_.CreateBinary(op, lhs, rhs, module_.GetContext().NextTemp())); +} + +std::any IRGenImpl::visitRelExp(SysYParser::RelExpContext* ctx) { + if (ctx->addExp() && ctx->relExp() == nullptr) { + return ctx->addExp()->accept(this); + } + ir::Value* lhs = std::any_cast(ctx->relExp()->accept(this)); + ir::Value* rhs = std::any_cast(ctx->addExp()->accept(this)); + if (lhs->GetType()->IsInt1()) lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp()); + if (rhs->GetType()->IsInt1()) rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp()); + + ir::CmpOp op; + if (ctx->LT()) op = ir::CmpOp::Lt; + else if (ctx->GT()) op = ir::CmpOp::Gt; + else if (ctx->LE()) op = ir::CmpOp::Le; + else if (ctx->GE()) op = ir::CmpOp::Ge; + else throw std::runtime_error(FormatError("irgen", "未知的关系运算符")); + + return static_cast(builder_.CreateCmp(op, lhs, rhs, module_.GetContext().NextTemp())); +} + +std::any IRGenImpl::visitEqExp(SysYParser::EqExpContext* ctx) { + if (ctx->relExp() && ctx->eqExp() == nullptr) { + return ctx->relExp()->accept(this); + } + ir::Value* lhs = std::any_cast(ctx->eqExp()->accept(this)); + ir::Value* rhs = std::any_cast(ctx->relExp()->accept(this)); + if (lhs->GetType()->IsInt1()) lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp()); + if (rhs->GetType()->IsInt1()) rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp()); + + ir::CmpOp op; + if (ctx->EQ()) op = ir::CmpOp::Eq; + else if (ctx->NE()) op = ir::CmpOp::Ne; + else throw std::runtime_error(FormatError("irgen", "未知的相等运算符")); + + return static_cast(builder_.CreateCmp(op, lhs, rhs, module_.GetContext().NextTemp())); +} + +std::any IRGenImpl::visitCondUnaryExp(SysYParser::CondUnaryExpContext* ctx) { + if (ctx->eqExp()) { + return ctx->eqExp()->accept(this); + } + if (ctx->NOT()) { + ir::Value* operand = std::any_cast(ctx->condUnaryExp()->accept(this)); + if (operand->GetType()->IsInt1()) { + operand = builder_.CreateZext(operand, module_.GetContext().NextTemp()); + } + ir::Value* zero = builder_.CreateConstInt(0); + return static_cast(builder_.CreateCmp(ir::CmpOp::Eq, operand, zero, module_.GetContext().NextTemp())); + } + throw std::runtime_error(FormatError("irgen", "非法条件一元表达式")); +} + +std::any IRGenImpl::visitLAndExp(SysYParser::LAndExpContext* ctx) { + if (ctx->condUnaryExp() && ctx->lAndExp() == nullptr) { + return ctx->condUnaryExp()->accept(this); + } + + ir::AllocaInst* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp()); + ir::Value* zero = builder_.CreateConstInt(0); + builder_.CreateStore(zero, res_ptr); + + ir::BasicBlock* rhs_bb = func_->CreateBlock(NextBlockName("land_rhs")); + ir::BasicBlock* end_bb = func_->CreateBlock(NextBlockName("land_end")); + + ir::Value* lhs = std::any_cast(ctx->lAndExp()->accept(this)); + if (lhs->GetType()->IsInt1()) { + lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp()); + } + ir::Value* lhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, lhs, zero, module_.GetContext().NextTemp()); + builder_.CreateCondBr(lhs_cond, rhs_bb, end_bb); + + builder_.SetInsertPoint(rhs_bb); + ir::Value* rhs = std::any_cast(ctx->condUnaryExp()->accept(this)); + if (rhs->GetType()->IsInt1()) { + rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp()); + } + ir::Value* rhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, rhs, zero, module_.GetContext().NextTemp()); + ir::Value* rhs_res = builder_.CreateZext(rhs_cond, module_.GetContext().NextTemp()); + builder_.CreateStore(rhs_res, res_ptr); + builder_.CreateBr(end_bb); + + builder_.SetInsertPoint(end_bb); + return static_cast(builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp())); +} + +std::any IRGenImpl::visitLOrExp(SysYParser::LOrExpContext* ctx) { + if (ctx->lAndExp() && ctx->lOrExp() == nullptr) { + return ctx->lAndExp()->accept(this); + } + + ir::AllocaInst* res_ptr = builder_.CreateAllocaI32(module_.GetContext().NextTemp()); + ir::Value* one = builder_.CreateConstInt(1); + builder_.CreateStore(one, res_ptr); + + ir::BasicBlock* rhs_bb = func_->CreateBlock(NextBlockName("lor_rhs")); + ir::BasicBlock* end_bb = func_->CreateBlock(NextBlockName("lor_end")); + + ir::Value* lhs = std::any_cast(ctx->lOrExp()->accept(this)); + ir::Value* zero = builder_.CreateConstInt(0); + if (lhs->GetType()->IsInt1()) { + lhs = builder_.CreateZext(lhs, module_.GetContext().NextTemp()); + } + ir::Value* lhs_cond = builder_.CreateCmp(ir::CmpOp::Eq, lhs, zero, module_.GetContext().NextTemp()); + builder_.CreateCondBr(lhs_cond, rhs_bb, end_bb); + + builder_.SetInsertPoint(rhs_bb); + ir::Value* rhs = std::any_cast(ctx->lAndExp()->accept(this)); + if (rhs->GetType()->IsInt1()) { + rhs = builder_.CreateZext(rhs, module_.GetContext().NextTemp()); + } + ir::Value* rhs_cond = builder_.CreateCmp(ir::CmpOp::Ne, rhs, zero, module_.GetContext().NextTemp()); + ir::Value* rhs_res = builder_.CreateZext(rhs_cond, module_.GetContext().NextTemp()); + builder_.CreateStore(rhs_res, res_ptr); + builder_.CreateBr(end_bb); + + builder_.SetInsertPoint(end_bb); + return static_cast(builder_.CreateLoad(res_ptr, module_.GetContext().NextTemp())); +} + +std::any IRGenImpl::visitCond(SysYParser::CondContext* ctx) { + if (!ctx || !ctx->lOrExp()) { + throw std::runtime_error(FormatError("irgen", "非法条件表达式")); + } + return ctx->lOrExp()->accept(this); } \ No newline at end of file diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp index de6a857..e44bd0a 100644 --- a/src/irgen/IRGenStmt.cpp +++ b/src/irgen/IRGenStmt.cpp @@ -20,50 +20,133 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) { throw std::runtime_error(FormatError("irgen", "缺少语句")); } - // 检查是否是赋值语句:lVal ASSIGN exp SEMICOLON if (ctx->lVal() && ctx->ASSIGN()) { if (!ctx->exp()) { throw std::runtime_error(FormatError("irgen", "赋值语句缺少表达式")); } - - // 1. 计算右值表达式的值 ir::Value* rhs = EvalExpr(*ctx->exp()); - - // 2. 找到左值变量对应的存储槽位 auto* lval_ctx = ctx->lVal(); if (!lval_ctx || !lval_ctx->ID()) { throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量赋值")); } - const auto* decl = sema_.ResolveObjectUse(lval_ctx); if (!decl) { throw std::runtime_error( - FormatError("irgen", - "变量使用缺少语义绑定:" + lval_ctx->ID()->getText())); + FormatError("irgen", "变量使用缺少语义绑定:" + lval_ctx->ID()->getText())); } - std::string var_name = lval_ctx->ID()->getText(); auto it = storage_map_.find(var_name); if (it == storage_map_.end()) { throw std::runtime_error( - FormatError("irgen", - "变量声明缺少存储槽位:" + var_name)); + FormatError("irgen", "变量声明缺少存储槽位:" + var_name)); } - - // 3. 生成 store 指令 builder_.CreateStore(rhs, it->second); return BlockFlow::Continue; } - // 检查是否是 return 语句:RETURN exp? SEMICOLON + if (ctx->IF()) { + ir::Value* cond_val = std::any_cast(ctx->cond()->accept(this)); + // cond_val must be i1, if it's not we need to check if it's != 0 + if (cond_val->GetType()->IsInt32()) { + ir::Value* zero = builder_.CreateConstInt(0); + cond_val = builder_.CreateCmp(ir::CmpOp::Ne, cond_val, zero, module_.GetContext().NextTemp()); + } + + ir::BasicBlock* then_bb = func_->CreateBlock(NextBlockName("if_then")); + ir::BasicBlock* else_bb = ctx->ELSE() ? func_->CreateBlock(NextBlockName("if_else")) : nullptr; + ir::BasicBlock* merge_bb = func_->CreateBlock(NextBlockName("if_merge")); + + builder_.CreateCondBr(cond_val, then_bb, else_bb ? else_bb : merge_bb); + + builder_.SetInsertPoint(then_bb); + auto then_flow = std::any_cast(ctx->stmt(0)->accept(this)); + if (then_flow == BlockFlow::Continue) { + builder_.CreateBr(merge_bb); + } + + if (ctx->ELSE()) { + builder_.SetInsertPoint(else_bb); + auto else_flow = std::any_cast(ctx->stmt(1)->accept(this)); + if (else_flow == BlockFlow::Continue) { + builder_.CreateBr(merge_bb); + } + } + + builder_.SetInsertPoint(merge_bb); + return BlockFlow::Continue; + } + + if (ctx->WHILE()) { + ir::BasicBlock* cond_bb = func_->CreateBlock(NextBlockName("while_cond")); + ir::BasicBlock* body_bb = func_->CreateBlock(NextBlockName("while_body")); + ir::BasicBlock* exit_bb = func_->CreateBlock(NextBlockName("while_exit")); + + builder_.CreateBr(cond_bb); + builder_.SetInsertPoint(cond_bb); + + ir::Value* cond_val = std::any_cast(ctx->cond()->accept(this)); + if (cond_val->GetType()->IsInt32()) { + ir::Value* zero = builder_.CreateConstInt(0); + cond_val = builder_.CreateCmp(ir::CmpOp::Ne, cond_val, zero, module_.GetContext().NextTemp()); + } + builder_.CreateCondBr(cond_val, body_bb, exit_bb); + + builder_.SetInsertPoint(body_bb); + ir::BasicBlock* old_cond = current_loop_cond_bb_; + ir::BasicBlock* old_exit = current_loop_exit_bb_; + current_loop_cond_bb_ = cond_bb; + current_loop_exit_bb_ = exit_bb; + + auto body_flow = std::any_cast(ctx->stmt(0)->accept(this)); + if (body_flow == BlockFlow::Continue) { + builder_.CreateBr(cond_bb); + } + + current_loop_cond_bb_ = old_cond; + current_loop_exit_bb_ = old_exit; + + builder_.SetInsertPoint(exit_bb); + return BlockFlow::Continue; + } + + if (ctx->BREAK()) { + if (!current_loop_exit_bb_) { + throw std::runtime_error(FormatError("irgen", "break 必须在循环内")); + } + builder_.CreateBr(current_loop_exit_bb_); + return BlockFlow::Terminated; + } + + if (ctx->CONTINUE()) { + if (!current_loop_cond_bb_) { + throw std::runtime_error(FormatError("irgen", "continue 必须在循环内")); + } + builder_.CreateBr(current_loop_cond_bb_); + return BlockFlow::Terminated; + } + if (ctx->RETURN()) { - if (!ctx->exp()) { - throw std::runtime_error(FormatError("irgen", "return 缺少表达式")); + if (ctx->exp()) { + ir::Value* v = EvalExpr(*ctx->exp()); + builder_.CreateRet(v); + } else { + throw std::runtime_error(FormatError("irgen", "暂不支持 void return")); } - ir::Value* v = EvalExpr(*ctx->exp()); - builder_.CreateRet(v); return BlockFlow::Terminated; } + if (ctx->block()) { + return ctx->block()->accept(this); + } + + if (ctx->exp()) { + EvalExpr(*ctx->exp()); + return BlockFlow::Continue; + } + + if (ctx->SEMICOLON()) { + return BlockFlow::Continue; + } + throw std::runtime_error(FormatError("irgen", "暂不支持的语句类型")); } diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp index fc73f9d..95f0629 100644 --- a/src/sem/Sema.cpp +++ b/src/sem/Sema.cpp @@ -462,7 +462,7 @@ class SemaVisitor final : public SysYBaseVisitor { if (!ctx) { ThrowSemaError(ctx, "非法关系表达式"); } - if (ctx->addExp()) { + if (ctx->relExp() == nullptr) { return EvalExpr(*ctx->addExp()); } ExprInfo lhs = EvalExpr(*ctx->relExp()); @@ -474,7 +474,7 @@ class SemaVisitor final : public SysYBaseVisitor { if (!ctx) { ThrowSemaError(ctx, "非法相等表达式"); } - if (ctx->relExp()) { + if (ctx->eqExp() == nullptr) { return EvalExpr(*ctx->relExp()); } ExprInfo lhs = EvalExpr(*ctx->eqExp()); @@ -504,7 +504,7 @@ class SemaVisitor final : public SysYBaseVisitor { if (!ctx) { ThrowSemaError(ctx, "非法逻辑与表达式"); } - if (ctx->condUnaryExp()) { + if (ctx->lAndExp() == nullptr) { return EvalExpr(*ctx->condUnaryExp()); } ExprInfo lhs = EvalExpr(*ctx->lAndExp()); @@ -516,7 +516,7 @@ class SemaVisitor final : public SysYBaseVisitor { if (!ctx) { ThrowSemaError(ctx, "非法逻辑或表达式"); } - if (ctx->lAndExp()) { + if (ctx->lOrExp() == nullptr) { return EvalExpr(*ctx->lAndExp()); } ExprInfo lhs = EvalExpr(*ctx->lOrExp());