refactor(irgen): IR改成alloca和store形式
This commit is contained in:
@@ -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)"
|
||||
```
|
||||
直接查看图片即可
|
||||
|
||||
65
scripts/verify_ir_with_llvm.sh
Executable file
65
scripts/verify_ir_with_llvm.sh
Executable 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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
35
src/ir/IR.h
35
src/ir/IR.h
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user