master
mayiyang 2 weeks ago
parent 8dd9db7a74
commit 8f0c2e3919

@ -7,12 +7,12 @@ set -euo pipefail
# bash scripts/test_lab2.sh
# Optional env vars:
# COMPILER=./build/bin/compiler
# CASE_DIR=test/test_case/functional
# CASE_DIR=test/test_case
# OUT_DIR=test/test_result/lab2_ir
# LOG_FILE=test/test_result/lab2_test.log
COMPILER="${COMPILER:-./build/bin/compiler}"
CASE_DIR="${CASE_DIR:-test/test_case/functional}"
CASE_DIR="${CASE_DIR:-test/test_case}"
OUT_DIR="${OUT_DIR:-test/test_result/lab2_ir}"
LOG_FILE="${LOG_FILE:-test/test_result/lab2_test.log}"
VERIFY_SCRIPT="./scripts/verify_ir.sh"
@ -67,7 +67,10 @@ echo "out dir : $OUT_DIR" | tee -a "$LOG_FILE"
echo "[Step 1] single sample check: simple_add.sy" | tee -a "$LOG_FILE"
sample_input="$(find "$CASE_DIR" -type f -name "simple_add.sy" -print -quit)"
if [[ -z "$sample_input" ]]; then
echo "single sample: FAIL (simple_add.sy not found under $CASE_DIR)" | tee -a "$LOG_FILE"
sample_input="$(find "$CASE_DIR" -type f -name "*.sy" | sort | head -n 1)"
fi
if [[ -z "$sample_input" ]]; then
echo "single sample: FAIL (no .sy case found under $CASE_DIR)" | tee -a "$LOG_FILE"
echo "stop here. see log: $LOG_FILE" >&2
exit 1
fi
@ -79,7 +82,7 @@ else
exit 1
fi
echo "[Step 2] full functional regression" | tee -a "$LOG_FILE"
echo "[Step 2] full Lab2 regression" | tee -a "$LOG_FILE"
pass=0
fail=0
@ -117,5 +120,5 @@ if [[ $fail -gt 0 ]]; then
exit 1
fi
echo "All functional cases passed. Lab2 target (functional regression) is met." | tee -a "$LOG_FILE"
echo "All Lab2 cases passed. Lab2 target regression is met." | tee -a "$LOG_FILE"
echo "see details in $LOG_FILE"

@ -47,20 +47,28 @@ expected_file="$input_dir/$stem.out"
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
echo "未找到 clang无法编译可执行文件。请安装 LLVM/Clang。" >&2
exit 1
fi
obj="$out_dir/$stem.o"
exe="$out_dir/$stem"
stdout_file="$out_dir/$stem.stdout"
actual_file="$out_dir/$stem.actual.out"
llc -filetype=obj "$out_file" -o "$obj"
clang "$obj" sylib/sylib.c -o "$exe"
actual_norm="$out_dir/$stem.actual.norm"
expected_norm="$out_dir/$stem.expected.norm"
# 直接让 clang 优化 .ll可显著降低大规模 Lab2 performance 用例运行时间。
# -fwrapv 保持有符号整数按补码回绕,避免与当前 IR 的测试语义偏离。
if ! clang -O2 -fwrapv -Wno-override-module "$out_file" sylib/sylib.c -o "$exe"; then
if ! command -v llc >/dev/null 2>&1; then
echo "未找到 llc且 clang 直接编译 IR 失败,无法运行 IR。" >&2
exit 1
fi
obj="$out_dir/$stem.o"
llc -filetype=obj "$out_file" -o "$obj"
clang "$obj" sylib/sylib.c -o "$exe"
fi
echo "运行 $exe ..."
set +e
if [[ -f "$stdin_file" ]]; then
@ -81,7 +89,9 @@ if [[ "$run_exec" == true ]]; then
} > "$actual_file"
if [[ -f "$expected_file" ]]; then
if diff -u "$expected_file" "$actual_file"; then
perl -0pe 's/\r\n/\n/g; s/\r/\n/g; s/\n?\z//' "$expected_file" > "$expected_norm"
perl -0pe 's/\r\n/\n/g; s/\r/\n/g; s/\n?\z//' "$actual_file" > "$actual_norm"
if diff -u "$expected_norm" "$actual_norm"; then
echo "输出匹配: $expected_file"
else
echo "输出不匹配: $expected_file" >&2

@ -118,6 +118,24 @@ static std::string FloatToString(float v) {
return oss.str();
}
static bool IsZeroInitializer(const ConstantValue* c) {
if (auto* ci = dynamic_cast<const ConstantInt*>(c)) {
return ci->GetValue() == 0;
}
if (auto* cf = dynamic_cast<const ConstantFloat*>(c)) {
return cf->GetValue() == 0.0f;
}
if (auto* ca = dynamic_cast<const ConstantArray*>(c)) {
for (auto* elem : ca->GetElements()) {
if (!elem || !IsZeroInitializer(elem)) {
return false;
}
}
return true;
}
return false;
}
static std::string ConstantToString(const ConstantValue* c) {
if (auto* ci = dynamic_cast<const ConstantInt*>(c)) {
return std::to_string(ci->GetValue());
@ -126,6 +144,9 @@ static std::string ConstantToString(const ConstantValue* c) {
return FloatToString(cf->GetValue());
}
if (auto* ca = dynamic_cast<const ConstantArray*>(c)) {
if (IsZeroInitializer(ca)) {
return "zeroinitializer";
}
std::ostringstream oss;
oss << "[";
const auto& elems = ca->GetElements();

@ -121,9 +121,50 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
} else {
init = DefaultValue(*ty);
}
if (ty->base == BaseTypeKind::Float) {
if (init->IsInt1() || init->IsInt32()) {
init = CastToFloat(init->IsInt1() ? CastToInt(init) : init);
}
} else if (ty->base == BaseTypeKind::Int) {
if (init->IsFloat() || init->IsInt1()) {
init = CastToInt(init);
}
}
builder_.CreateStore(init, slot);
} else {
InitArray(slot, *ty, ctx->initVal());
if (!ctx->initVal() && ty->dims.size() == 1 && ty->dims[0] >= 1024) {
auto* idx_slot = CreateEntryAlloca(ir::Type::GetInt32Type(),
module_.GetContext().NextTemp());
builder_.CreateStore(builder_.CreateConstInt(0), idx_slot);
auto* cond_bb = func_->CreateBlock("arr.zero.cond");
auto* body_bb = func_->CreateBlock("arr.zero.body");
auto* end_bb = func_->CreateBlock("arr.zero.end");
builder_.CreateBr(cond_bb);
builder_.SetInsertPoint(cond_bb);
auto* idx = builder_.CreateLoad(idx_slot, module_.GetContext().NextTemp());
auto* bound = builder_.CreateConstInt(ty->dims[0]);
auto* cmp = builder_.CreateICmp(ir::ICmpPredicate::Slt, idx, bound,
module_.GetContext().NextTemp());
builder_.CreateCondBr(cmp, body_bb, end_bb);
builder_.SetInsertPoint(body_bb);
std::vector<ir::Value*> indices;
indices.push_back(builder_.CreateConstInt(0));
indices.push_back(idx);
auto* elem_addr = builder_.CreateGep(slot, std::move(indices),
module_.GetContext().NextTemp());
builder_.CreateStore(DefaultValue(*ty), elem_addr);
auto* next = builder_.CreateAdd(idx, builder_.CreateConstInt(1),
module_.GetContext().NextTemp());
builder_.CreateStore(next, idx_slot);
builder_.CreateBr(cond_bb);
builder_.SetInsertPoint(end_bb);
} else {
InitArray(slot, *ty, ctx->initVal());
}
}
return {};
}
@ -194,6 +235,15 @@ std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) {
} else {
init = DefaultValue(*ty);
}
if (ty->base == BaseTypeKind::Float) {
if (init->IsInt1() || init->IsInt32()) {
init = CastToFloat(init->IsInt1() ? CastToInt(init) : init);
}
} else if (ty->base == BaseTypeKind::Int) {
if (init->IsFloat() || init->IsInt1()) {
init = CastToInt(init);
}
}
builder_.CreateStore(init, slot);
} else {
InitConstArray(slot, *ty, ctx->constInitVal());

@ -270,8 +270,14 @@ std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) {
if (!ctx || !ctx->ID()) {
throw std::runtime_error(FormatError("irgen", "非法左值"));
}
ir::Value* addr = GetLValAddress(ctx);
BoundDecl bound = sema_.ResolveVarUse(ctx);
if ((bound.kind == BoundDecl::Kind::Var && !bound.var_decl) ||
(bound.kind == BoundDecl::Kind::Const && !bound.const_decl) ||
(bound.kind == BoundDecl::Kind::Param && !bound.param_decl)) {
throw std::runtime_error(
FormatError("irgen", "左值缺少语义绑定: " + ctx->getText()));
}
ir::Value* addr = GetLValAddress(ctx);
const TypeDesc* ty = nullptr;
if (bound.kind == BoundDecl::Kind::Var && bound.var_decl) {
ty = sema_.GetVarType(bound.var_decl);
@ -280,52 +286,6 @@ std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) {
} else if (bound.kind == BoundDecl::Kind::Param && bound.param_decl) {
ty = sema_.GetParamType(bound.param_decl);
}
if (!ty && ctx->ID()) {
const auto name = ctx->ID()->getText();
for (const auto& kv : var_storage_) {
auto* def = const_cast<SysYParser::VarDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetVarType(kv.first);
break;
}
}
if (!ty) {
for (const auto& kv : const_storage_) {
auto* def = const_cast<SysYParser::ConstDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetConstType(kv.first);
break;
}
}
}
if (!ty) {
for (const auto& kv : param_storage_) {
auto* def = const_cast<SysYParser::FuncFParamContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetParamType(kv.first);
break;
}
}
}
if (!ty) {
for (const auto& kv : global_var_storage_) {
auto* def = const_cast<SysYParser::VarDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetVarType(kv.first);
break;
}
}
}
if (!ty) {
for (const auto& kv : global_const_storage_) {
auto* def = const_cast<SysYParser::ConstDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetConstType(kv.first);
break;
}
}
}
}
if (!ty) {
throw std::runtime_error(FormatError("irgen", "无法解析左值类型"));
}
@ -514,13 +474,22 @@ ir::Value* IRGenImpl::GetLValAddress(SysYParser::LValContext* ctx) {
const TypeDesc* ty = nullptr;
if (bound.kind == BoundDecl::Kind::Var && bound.var_decl) {
ty = sema_.GetVarType(bound.var_decl);
base_ptr = var_storage_[bound.var_decl];
auto it = var_storage_.find(bound.var_decl);
if (it != var_storage_.end()) {
base_ptr = it->second;
}
} else if (bound.kind == BoundDecl::Kind::Const && bound.const_decl) {
ty = sema_.GetConstType(bound.const_decl);
base_ptr = const_storage_[bound.const_decl];
auto it = const_storage_.find(bound.const_decl);
if (it != const_storage_.end()) {
base_ptr = it->second;
}
} else if (bound.kind == BoundDecl::Kind::Param && bound.param_decl) {
ty = sema_.GetParamType(bound.param_decl);
base_ptr = param_storage_[bound.param_decl];
auto it = param_storage_.find(bound.param_decl);
if (it != param_storage_.end()) {
base_ptr = it->second;
}
}
if (!base_ptr && bound.kind == BoundDecl::Kind::Var && bound.var_decl) {
auto it = global_var_storage_.find(bound.var_decl);
@ -536,57 +505,6 @@ ir::Value* IRGenImpl::GetLValAddress(SysYParser::LValContext* ctx) {
base_ptr = it->second;
}
}
if (!base_ptr && ctx && ctx->ID()) {
const auto name = ctx->ID()->getText();
for (const auto& kv : var_storage_) {
auto* def = const_cast<SysYParser::VarDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetVarType(kv.first);
base_ptr = kv.second;
break;
}
}
if (!base_ptr) {
for (const auto& kv : const_storage_) {
auto* def = const_cast<SysYParser::ConstDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetConstType(kv.first);
base_ptr = kv.second;
break;
}
}
}
if (!base_ptr) {
for (const auto& kv : param_storage_) {
auto* def = const_cast<SysYParser::FuncFParamContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetParamType(kv.first);
base_ptr = kv.second;
break;
}
}
}
if (!base_ptr) {
for (const auto& kv : global_var_storage_) {
auto* def = const_cast<SysYParser::VarDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetVarType(kv.first);
base_ptr = kv.second;
break;
}
}
}
if (!base_ptr) {
for (const auto& kv : global_const_storage_) {
auto* def = const_cast<SysYParser::ConstDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetConstType(kv.first);
base_ptr = kv.second;
break;
}
}
}
}
if (!base_ptr || !ty) {
throw std::runtime_error(FormatError("irgen", "左值未绑定"));
}

@ -13,6 +13,12 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
ir::Value* addr = GetLValAddress(ctx->lVal());
ir::Value* val = EvalExp(ctx->exp());
BoundDecl bound = sema_.ResolveVarUse(ctx->lVal());
if ((bound.kind == BoundDecl::Kind::Var && !bound.var_decl) ||
(bound.kind == BoundDecl::Kind::Const && !bound.const_decl) ||
(bound.kind == BoundDecl::Kind::Param && !bound.param_decl)) {
throw std::runtime_error(FormatError(
"irgen", "赋值左值缺少语义绑定: " + ctx->lVal()->getText()));
}
const TypeDesc* ty = nullptr;
if (bound.kind == BoundDecl::Kind::Var && bound.var_decl) {
ty = sema_.GetVarType(bound.var_decl);
@ -21,50 +27,6 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) {
} else if (bound.kind == BoundDecl::Kind::Const) {
throw std::runtime_error(FormatError("irgen", "不能给常量赋值"));
}
if (!ty && ctx->lVal()->ID()) {
const auto name = ctx->lVal()->ID()->getText();
for (const auto& kv : var_storage_) {
auto* def = const_cast<SysYParser::VarDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetVarType(kv.first);
break;
}
}
if (!ty) {
for (const auto& kv : const_storage_) {
auto* def = const_cast<SysYParser::ConstDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
throw std::runtime_error(FormatError("irgen", "不能给常量赋值"));
}
}
}
if (!ty) {
for (const auto& kv : param_storage_) {
auto* def = const_cast<SysYParser::FuncFParamContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetParamType(kv.first);
break;
}
}
}
if (!ty) {
for (const auto& kv : global_var_storage_) {
auto* def = const_cast<SysYParser::VarDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
ty = sema_.GetVarType(kv.first);
break;
}
}
}
if (!ty) {
for (const auto& kv : global_const_storage_) {
auto* def = const_cast<SysYParser::ConstDefContext*>(kv.first);
if (def && def->ID() && def->ID()->getText() == name) {
throw std::runtime_error(FormatError("irgen", "不能给常量赋值"));
}
}
}
}
if (!ty) {
throw std::runtime_error(FormatError("irgen", "无法解析赋值类型"));
}

@ -379,6 +379,11 @@ class SemaVisitor final : public SysYBaseVisitor {
bound.param_decl = entry->param_decl;
}
sema_.BindVarUse(ctx, bound);
for (auto* exp : ctx->exp()) {
if (exp) {
exp->accept(this);
}
}
return {};
}

Loading…
Cancel
Save