refactor(irgen): IR改成alloca和store形式

This commit is contained in:
jing
2026-03-01 15:36:50 +08:00
parent 29bf99727f
commit 730280abb8
10 changed files with 180 additions and 10 deletions

View File

@@ -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 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)"
```

65
scripts/verify_ir_with_llvm.sh Executable file
View File

@@ -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 <input.sy> [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

View File

@@ -28,6 +28,13 @@ const std::shared_ptr<Type>& Context::Int32() {
return int32_; return int32_;
} }
const std::shared_ptr<Type>& Context::PtrInt32() {
if (!ptr_i32_) {
ptr_i32_ = std::make_shared<Type>(Type::Kind::PtrInt32);
}
return ptr_i32_;
}
ConstantInt* Context::GetConstInt(int v) { ConstantInt* Context::GetConstInt(int v) {
auto it = const_ints_.find(v); auto it = const_ints_.find(v);
if (it != const_ints_.end()) return it->second.get(); if (it != const_ints_.end()) return it->second.get();
@@ -38,7 +45,7 @@ ConstantInt* Context::GetConstInt(int v) {
std::string Context::NextTemp() { std::string Context::NextTemp() {
std::ostringstream oss; std::ostringstream oss;
oss << "%t" << temp_index_++; oss << "%" << ++temp_index_;
return oss.str(); return oss.str();
} }

View File

@@ -19,6 +19,7 @@ class Context {
~Context(); ~Context();
const std::shared_ptr<Type>& Void(); const std::shared_ptr<Type>& Void();
const std::shared_ptr<Type>& Int32(); const std::shared_ptr<Type>& Int32();
const std::shared_ptr<Type>& PtrInt32();
// 去重创建 i32 常量。 // 去重创建 i32 常量。
ConstantInt* GetConstInt(int v); ConstantInt* GetConstInt(int v);
// 生成临时名称,如 %t0、%t1 ... // 生成临时名称,如 %t0、%t1 ...
@@ -27,6 +28,7 @@ class Context {
private: private:
std::shared_ptr<Type> void_; std::shared_ptr<Type> void_;
std::shared_ptr<Type> int32_; std::shared_ptr<Type> int32_;
std::shared_ptr<Type> ptr_i32_;
std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_; std::unordered_map<int, std::unique_ptr<ConstantInt>> const_ints_;
int temp_index_ = 0; int temp_index_ = 0;
}; };
@@ -35,11 +37,12 @@ Context& DefaultContext();
class Type { class Type {
public: public:
enum class Kind { Void, Int32 }; enum class Kind { Void, Int32, PtrInt32 };
explicit Type(Kind k) : kind_(k) {} explicit Type(Kind k) : kind_(k) {}
Kind kind() const { return kind_; } Kind kind() const { return kind_; }
static std::shared_ptr<Type> Void(); static std::shared_ptr<Type> Void();
static std::shared_ptr<Type> Int32(); static std::shared_ptr<Type> Int32();
static std::shared_ptr<Type> PtrInt32();
private: private:
Kind kind_; Kind kind_;
@@ -68,7 +71,7 @@ class ConstantInt : public Value {
int value_{}; int value_{};
}; };
enum class Opcode { Add, Sub, Mul, Ret }; enum class Opcode { Add, Sub, Mul, Alloca, Load, Store, Ret };
class Instruction : public Value { class Instruction : public Value {
public: public:
@@ -101,6 +104,31 @@ class ReturnInst : public Instruction {
Value* value_; 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 { class BasicBlock {
public: public:
explicit BasicBlock(std::string name) : name_(std::move(name)) {} 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) { BinaryInst* CreateAdd(Value* lhs, Value* rhs, const std::string& name) {
return CreateBinary(Opcode::Add, lhs, rhs, 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); ReturnInst* CreateRet(Value* v);
private: private:

View File

@@ -20,6 +20,27 @@ BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
return insertBlock_->Append<BinaryInst>(op, Type::Int32(), lhs, rhs, name); return insertBlock_->Append<BinaryInst>(op, Type::Int32(), lhs, rhs, name);
} }
AllocaInst* IRBuilder::CreateAllocaI32(const std::string& name) {
if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点");
}
return insertBlock_->Append<AllocaInst>(name);
}
LoadInst* IRBuilder::CreateLoad(Value* ptr, const std::string& name) {
if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点");
}
return insertBlock_->Append<LoadInst>(ptr, name);
}
StoreInst* IRBuilder::CreateStore(Value* val, Value* ptr) {
if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点");
}
return insertBlock_->Append<StoreInst>(val, ptr);
}
ReturnInst* IRBuilder::CreateRet(Value* v) { ReturnInst* IRBuilder::CreateRet(Value* v) {
if (!insertBlock_) { if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点"); throw std::runtime_error("IRBuilder 未设置插入点");

View File

@@ -15,6 +15,8 @@ static const char* TypeToString(const Type& ty) {
return "void"; return "void";
case Type::Kind::Int32: case Type::Kind::Int32:
return "i32"; return "i32";
case Type::Kind::PtrInt32:
return "i32*";
} }
throw std::runtime_error("未知类型"); throw std::runtime_error("未知类型");
} }
@@ -27,6 +29,12 @@ static const char* OpcodeToString(Opcode op) {
return "sub"; return "sub";
case Opcode::Mul: case Opcode::Mul:
return "mul"; return "mul";
case Opcode::Alloca:
return "alloca";
case Opcode::Load:
return "load";
case Opcode::Store:
return "store";
case Opcode::Ret: case Opcode::Ret:
return "ret"; return "ret";
} }
@@ -42,6 +50,7 @@ void IRPrinter::Print(const Module& module) {
std::cout << "}\n"; std::cout << "}\n";
continue; continue;
} }
std::cout << "entry:\n";
for (const auto& instPtr : bb->instructions()) { for (const auto& instPtr : bb->instructions()) {
const auto* inst = instPtr.get(); const auto* inst = instPtr.get();
switch (inst->opcode()) { switch (inst->opcode()) {
@@ -54,6 +63,23 @@ void IRPrinter::Print(const Module& module) {
<< bin->lhs()->name() << ", " << bin->rhs()->name() << "\n"; << bin->lhs()->name() << ", " << bin->rhs()->name() << "\n";
break; break;
} }
case Opcode::Alloca: {
auto* alloca = static_cast<const AllocaInst*>(inst);
std::cout << " " << alloca->name() << " = alloca i32\n";
break;
}
case Opcode::Load: {
auto* load = static_cast<const LoadInst*>(inst);
std::cout << " " << load->name() << " = load i32, i32* "
<< load->ptr()->name() << "\n";
break;
}
case Opcode::Store: {
auto* store = static_cast<const StoreInst*>(inst);
std::cout << " store i32 " << store->value()->name() << ", i32* "
<< store->ptr()->name() << "\n";
break;
}
case Opcode::Ret: { case Opcode::Ret: {
auto* ret = static_cast<const ReturnInst*>(inst); auto* ret = static_cast<const ReturnInst*>(inst);
std::cout << " ret " << TypeToString(*ret->value()->type()) << " " std::cout << " ret " << TypeToString(*ret->value()->type()) << " "

View File

@@ -12,4 +12,13 @@ BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> ty, Value* lhs,
ReturnInst::ReturnInst(Value* val) ReturnInst::ReturnInst(Value* val)
: Instruction(Opcode::Ret, Type::Void(), ""), 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 } // namespace ir

View File

@@ -10,4 +10,6 @@ std::shared_ptr<Type> Type::Void() { return DefaultContext().Void(); }
std::shared_ptr<Type> Type::Int32() { return DefaultContext().Int32(); } std::shared_ptr<Type> Type::Int32() { return DefaultContext().Int32(); }
std::shared_ptr<Type> Type::PtrInt32() { return DefaultContext().PtrInt32(); }
} // namespace ir } // namespace ir

View File

@@ -5,11 +5,18 @@
#include "irgen/IRGen.h" #include "irgen/IRGen.h"
#include <memory> #include <memory>
#include <stdexcept>
#include "ast/AstNodes.h" #include "ast/AstNodes.h"
#include "ir/IR.h" #include "ir/IR.h"
void IRGenImpl::GenBlock(const ast::Block& block) { 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) { for (const auto& decl : block.varDecls) {
GenVarDecl(*decl); GenVarDecl(*decl);
} }
@@ -19,11 +26,16 @@ void IRGenImpl::GenBlock(const ast::Block& block) {
} }
void IRGenImpl::GenVarDecl(const ast::VarDecl& decl) { 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; ir::Value* init = nullptr;
if (decl.init) { if (decl.init) {
init = GenExpr(*decl.init); init = GenExpr(*decl.init);
} else { } else {
init = ir::DefaultContext().GetConstInt(0); init = ir::DefaultContext().GetConstInt(0);
} }
locals_[decl.name] = init; builder_.CreateStore(init, it->second);
} }

View File

@@ -18,7 +18,8 @@ ir::Value* IRGenImpl::GenExpr(const ast::Expr& expr) {
if (it == locals_.end()) { if (it == locals_.end()) {
throw std::runtime_error("变量未找到: " + var->name); 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<const ast::BinaryExpr*>(&expr)) { if (auto bin = dynamic_cast<const ast::BinaryExpr*>(&expr)) {
auto* lhs = GenExpr(*bin->lhs); auto* lhs = GenExpr(*bin->lhs);