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

master
jing 3 weeks ago
parent 29bf99727f
commit 730280abb8

@ -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)"
```
直接查看图片即可

@ -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

@ -28,6 +28,13 @@ const std::shared_ptr<Type>& Context::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) {
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();
}

@ -19,6 +19,7 @@ class Context {
~Context();
const std::shared_ptr<Type>& Void();
const std::shared_ptr<Type>& Int32();
const std::shared_ptr<Type>& PtrInt32();
// 去重创建 i32 常量。
ConstantInt* GetConstInt(int v);
// 生成临时名称,如 %t0、%t1 ...
@ -27,6 +28,7 @@ class Context {
private:
std::shared_ptr<Type> void_;
std::shared_ptr<Type> int32_;
std::shared_ptr<Type> ptr_i32_;
std::unordered_map<int, std::unique_ptr<ConstantInt>> 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<Type> Void();
static std::shared_ptr<Type> Int32();
static std::shared_ptr<Type> 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:

@ -20,6 +20,27 @@ BinaryInst* IRBuilder::CreateBinary(Opcode op, Value* lhs, Value* rhs,
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) {
if (!insertBlock_) {
throw std::runtime_error("IRBuilder 未设置插入点");

@ -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<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: {
auto* ret = static_cast<const ReturnInst*>(inst);
std::cout << " ret " << TypeToString(*ret->value()->type()) << " "

@ -12,4 +12,13 @@ BinaryInst::BinaryInst(Opcode op, std::shared_ptr<Type> 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

@ -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::PtrInt32() { return DefaultContext().PtrInt32(); }
} // namespace ir

@ -5,11 +5,18 @@
#include "irgen/IRGen.h"
#include <memory>
#include <stdexcept>
#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);
}

@ -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<const ast::BinaryExpr*>(&expr)) {
auto* lhs = GenExpr(*bin->lhs);

Loading…
Cancel
Save