From 730280abb8bba7cb4311c6ce7cb9b25d596ae0f9 Mon Sep 17 00:00:00 2001 From: jing <3030349106@qq.com> Date: Sun, 1 Mar 2026 15:36:50 +0800 Subject: [PATCH] =?UTF-8?q?refactor(irgen):=20IR=E6=94=B9=E6=88=90alloca?= =?UTF-8?q?=E5=92=8Cstore=E5=BD=A2=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ab1-ANTLR词法语法分析实验说明.md | 6 +- scripts/verify_ir_with_llvm.sh | 65 +++++++++++++++++++ src/ir/Context.cpp | 9 ++- src/ir/IR.h | 35 +++++++++- src/ir/IRBuilder.cpp | 21 ++++++ src/ir/IRPrinter.cpp | 26 ++++++++ src/ir/Instruction.cpp | 9 +++ src/ir/Type.cpp | 2 + src/irgen/IRGenDecl.cpp | 14 +++- src/irgen/IRGenExp.cpp | 3 +- 10 files changed, 180 insertions(+), 10 deletions(-) create mode 100755 scripts/verify_ir_with_llvm.sh diff --git a/doc/Lab1-ANTLR词法语法分析实验说明.md b/doc/Lab1-ANTLR词法语法分析实验说明.md index a4cd9af..46c0df1 100644 --- a/doc/Lab1-ANTLR词法语法分析实验说明.md +++ b/doc/Lab1-ANTLR词法语法分析实验说明.md @@ -110,8 +110,4 @@ mkdir -p test/test_result/ast dot -Tpng test/test_result/ast/simple_add.ast.dot -o test/test_result/ast/simple_add.ast.png ``` -WSL 查看图片: - -```bash -explorer.exe "$(wslpath -w test/test_result/ast/simple_add.ast.png)" -``` +直接查看图片即可 diff --git a/scripts/verify_ir_with_llvm.sh b/scripts/verify_ir_with_llvm.sh new file mode 100755 index 0000000..830982a --- /dev/null +++ b/scripts/verify_ir_with_llvm.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# ./scripts/verify_ir_with_llvm.sh test/test_case/simple_add.sy --run + +set -euo pipefail + +if [[ $# -lt 1 || $# -gt 3 ]]; then + echo "用法: $0 [output_dir] [--run]" >&2 + exit 1 +fi + +input=$1 +out_dir="out/ir" +run_exec=false + +shift +while [[ $# -gt 0 ]]; do + case "$1" in + --run) + run_exec=true + ;; + *) + out_dir="$1" + ;; + esac + shift +done + +if [[ ! -f "$input" ]]; then + echo "输入文件不存在: $input" >&2 + exit 1 +fi + +compiler="./build/bin/compiler" +if [[ ! -x "$compiler" ]]; then + echo "未找到编译器: $compiler ,请先构建(如: mkdir -p build && cd build && cmake .. && make -j)" >&2 + exit 1 +fi + +mkdir -p "$out_dir" +base=$(basename "$input") +stem=${base%.sy} +out_file="$out_dir/$stem.ll" +"$compiler" --emit-ir "$input" > "$out_file" +echo "IR 已生成: $out_file" + +if [[ "$run_exec" == true ]]; then + if ! command -v llc >/dev/null 2>&1; then + echo "未找到 llc,无法运行 IR。请安装 LLVM。" >&2 + exit 1 + fi + if ! command -v clang >/dev/null 2>&1; then + echo "未找到 clang,无法链接可执行文件。请安装 LLVM/Clang。" >&2 + exit 1 + fi + obj="$out_dir/$stem.o" + exe="$out_dir/$stem.exe" + llc -filetype=obj "$out_file" -o "$obj" + clang "$obj" -o "$exe" + echo "运行 $exe ..." + set +e + "$exe" + status=$? + set -e + echo "退出码: $status" +fi diff --git a/src/ir/Context.cpp b/src/ir/Context.cpp index d8543e2..49aa9b8 100644 --- a/src/ir/Context.cpp +++ b/src/ir/Context.cpp @@ -28,6 +28,13 @@ const std::shared_ptr& Context::Int32() { return int32_; } +const std::shared_ptr& Context::PtrInt32() { + if (!ptr_i32_) { + ptr_i32_ = std::make_shared(Type::Kind::PtrInt32); + } + return ptr_i32_; +} + ConstantInt* Context::GetConstInt(int v) { auto it = const_ints_.find(v); if (it != const_ints_.end()) return it->second.get(); @@ -38,7 +45,7 @@ ConstantInt* Context::GetConstInt(int v) { std::string Context::NextTemp() { std::ostringstream oss; - oss << "%t" << temp_index_++; + oss << "%" << ++temp_index_; return oss.str(); } diff --git a/src/ir/IR.h b/src/ir/IR.h index 0c6913f..5a9e312 100644 --- a/src/ir/IR.h +++ b/src/ir/IR.h @@ -19,6 +19,7 @@ class Context { ~Context(); const std::shared_ptr& Void(); const std::shared_ptr& Int32(); + const std::shared_ptr& PtrInt32(); // 去重创建 i32 常量。 ConstantInt* GetConstInt(int v); // 生成临时名称,如 %t0、%t1 ... @@ -27,6 +28,7 @@ class Context { private: std::shared_ptr void_; std::shared_ptr int32_; + std::shared_ptr ptr_i32_; std::unordered_map> const_ints_; int temp_index_ = 0; }; @@ -35,11 +37,12 @@ Context& DefaultContext(); class Type { public: - enum class Kind { Void, Int32 }; + enum class Kind { Void, Int32, PtrInt32 }; explicit Type(Kind k) : kind_(k) {} Kind kind() const { return kind_; } static std::shared_ptr Void(); static std::shared_ptr Int32(); + static std::shared_ptr PtrInt32(); private: Kind kind_; @@ -68,7 +71,7 @@ class ConstantInt : public Value { int value_{}; }; -enum class Opcode { Add, Sub, Mul, Ret }; +enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret }; class Instruction : public Value { public: @@ -101,6 +104,31 @@ class ReturnInst : public Instruction { Value* value_; }; +class AllocaInst : public Instruction { + public: + explicit AllocaInst(std::string name); +}; + +class LoadInst : public Instruction { + public: + LoadInst(Value* ptr, std::string name); + Value* ptr() const { return ptr_; } + + private: + Value* ptr_; +}; + +class StoreInst : public Instruction { + public: + StoreInst(Value* val, Value* ptr); + Value* value() const { return value_; } + Value* ptr() const { return ptr_; } + + private: + Value* value_; + Value* ptr_; +}; + class BasicBlock { public: explicit BasicBlock(std::string name) : name_(std::move(name)) {} @@ -158,6 +186,9 @@ class IRBuilder { BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name) { return CreateBinary(Opcode::Add, lhs, rhs, name); } + AllocaInst* CreateAllocaI32(const std::string& name); + LoadInst* CreateLoad(Value* ptr, const std::string& name); + StoreInst* CreateStore(Value* val, Value* ptr); ReturnInst* CreateRet(Value* v); private: diff --git a/src/ir/IRBuilder.cpp b/src/ir/IRBuilder.cpp index bbad735..1d4c6d2 100644 --- a/src/ir/IRBuilder.cpp +++ b/src/ir/IRBuilder.cpp @@ -20,6 +20,27 @@ BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs, return insertBlock_->Append(op, Type::Int32(), lhs, rhs, name); } +AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) { + if (!insertBlock_) { + throw std::runtime_error("IRBuilder 未设置插入点"); + } + return insertBlock_->Append(name); +} + +LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) { + if (!insertBlock_) { + throw std::runtime_error("IRBuilder 未设置插入点"); + } + return insertBlock_->Append(ptr, name); +} + +StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) { + if (!insertBlock_) { + throw std::runtime_error("IRBuilder 未设置插入点"); + } + return insertBlock_->Append(val, ptr); +} + ReturnInst* IRBuilder::CreateRet(Value* v) { if (!insertBlock_) { throw std::runtime_error("IRBuilder 未设置插入点"); diff --git a/src/ir/IRPrinter.cpp b/src/ir/IRPrinter.cpp index ee0f6be..726fe70 100644 --- a/src/ir/IRPrinter.cpp +++ b/src/ir/IRPrinter.cpp @@ -15,6 +15,8 @@ static const char* TypeToString(const Type& ty) { return "void"; case Type::Kind::Int32: return "i32"; + case Type::Kind::PtrInt32: + return "i32*"; } throw std::runtime_error("未知类型"); } @@ -27,6 +29,12 @@ static const char* OpcodeToString(Opcode op) { return "sub"; case Opcode::Mul: return "mul"; + case Opcode::Alloca: + return "alloca"; + case Opcode::Load: + return "load"; + case Opcode::Store: + return "store"; case Opcode::Ret: return "ret"; } @@ -42,6 +50,7 @@ void IRPrinter::Print(const Module& module) { std::cout << "}\n"; continue; } + std::cout << "entry:\n"; for (const auto& instPtr : bb->instructions()) { const auto* inst = instPtr.get(); switch (inst->opcode()) { @@ -54,6 +63,23 @@ void IRPrinter::Print(const Module& module) { << bin->lhs()->name() << ", " << bin->rhs()->name() << "\n"; break; } + case Opcode::Alloca: { + auto* alloca = static_cast(inst); + std::cout << " " << alloca->name() << " = alloca i32\n"; + break; + } + case Opcode::Load: { + auto* load = static_cast(inst); + std::cout << " " << load->name() << " = load i32, i32* " + << load->ptr()->name() << "\n"; + break; + } + case Opcode::Store: { + auto* store = static_cast(inst); + std::cout << " store i32 " << store->value()->name() << ", i32* " + << store->ptr()->name() << "\n"; + break; + } case Opcode::Ret: { auto* ret = static_cast(inst); std::cout << " ret " << TypeToString(*ret->value()->type()) << " " diff --git a/src/ir/Instruction.cpp b/src/ir/Instruction.cpp index 82f013e..52ce796 100644 --- a/src/ir/Instruction.cpp +++ b/src/ir/Instruction.cpp @@ -12,4 +12,13 @@ BinaryInst::BinaryInst(Opcode op, std::shared_ptr ty, Value* lhs, ReturnInst::ReturnInst(Value* val) : Instruction(Opcode::Ret, Type::Void(), ""), value_(val) {} +AllocaInst::AllocaInst(std::string name) + : Instruction(Opcode::Alloca, Type::PtrInt32(), std::move(name)) {} + +LoadInst::LoadInst(Value* ptr, std::string name) + : Instruction(Opcode::Load, Type::Int32(), std::move(name)), ptr_(ptr) {} + +StoreInst::StoreInst(Value* val, Value* ptr) + : Instruction(Opcode::Store, Type::Void(), ""), value_(val), ptr_(ptr) {} + } // namespace ir diff --git a/src/ir/Type.cpp b/src/ir/Type.cpp index a1ae51e..dc6501b 100644 --- a/src/ir/Type.cpp +++ b/src/ir/Type.cpp @@ -10,4 +10,6 @@ std::shared_ptr Type::Void() { return DefaultContext().Void(); } std::shared_ptr Type::Int32() { return DefaultContext().Int32(); } +std::shared_ptr Type::PtrInt32() { return DefaultContext().PtrInt32(); } + } // namespace ir diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp index ba7bae6..a676dfa 100644 --- a/src/irgen/IRGenDecl.cpp +++ b/src/irgen/IRGenDecl.cpp @@ -5,11 +5,18 @@ #include "irgen/IRGen.h" #include +#include #include "ast/AstNodes.h" #include "ir/IR.h" void IRGenImpl::GenBlock(const ast::Block& block) { + // 先为所有局部变量创建栈槽,使 alloca 聚集在入口块前部。 + for (const auto& decl : block.varDecls) { + auto* slot = builder_.CreateAllocaI32(ir::DefaultContext().NextTemp()); + locals_[decl->name] = slot; + } + for (const auto& decl : block.varDecls) { GenVarDecl(*decl); } @@ -19,11 +26,16 @@ void IRGenImpl::GenBlock(const ast::Block& block) { } void IRGenImpl::GenVarDecl(const ast::VarDecl& decl) { + auto it = locals_.find(decl.name); + if (it == locals_.end()) { + throw std::runtime_error("变量栈槽未创建: " + decl.name); + } + ir::Value* init = nullptr; if (decl.init) { init = GenExpr(*decl.init); } else { init = ir::DefaultContext().GetConstInt(0); } - locals_[decl.name] = init; + builder_.CreateStore(init, it->second); } diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp index 1a35948..29ba2f6 100644 --- a/src/irgen/IRGenExp.cpp +++ b/src/irgen/IRGenExp.cpp @@ -18,7 +18,8 @@ ir::Value* IRGenImpl::GenExpr(const ast::Expr& expr) { if (it == locals_.end()) { throw std::runtime_error("变量未找到: " + var->name); } - return it->second; + std::string name = ir::DefaultContext().NextTemp(); + return builder_.CreateLoad(it->second, name); } if (auto bin = dynamic_cast(&expr)) { auto* lhs = GenExpr(*bin->lhs);