diff --git a/include/ir/IR.h b/include/ir/IR.h index 3cc880e..75ce986 100644 --- a/include/ir/IR.h +++ b/include/ir/IR.h @@ -412,6 +412,15 @@ class BasicBlock : public Value { return ptr; } + template + T* Prepend(Args&&... args) { + auto inst = std::make_unique(std::forward(args)...); + auto* ptr = inst.get(); + ptr->SetParent(this); + instructions_.insert(instructions_.begin(), std::move(inst)); + return ptr; + } + private: Function* parent_ = nullptr; std::vector> instructions_; diff --git a/include/irgen/IRGen.h b/include/irgen/IRGen.h index a18ff6a..abd8a25 100644 --- a/include/irgen/IRGen.h +++ b/include/irgen/IRGen.h @@ -58,6 +58,8 @@ class IRGenImpl final : public SysYBaseVisitor { std::shared_ptr ToIRType(const TypeDesc& ty); std::shared_ptr ToIRParamType(const TypeDesc& ty); ir::Value* DefaultValue(const TypeDesc& ty); + ir::AllocaInst* CreateEntryAlloca(std::shared_ptr ty, + const std::string& name); void InitArray(ir::Value* base_ptr, const TypeDesc& ty, SysYParser::InitValContext* init); void InitConstArray(ir::Value* base_ptr, const TypeDesc& ty, diff --git a/scripts/run_lab2.sh b/scripts/run_lab2.sh index c4adf45..4d1d351 100644 --- a/scripts/run_lab2.sh +++ b/scripts/run_lab2.sh @@ -13,7 +13,7 @@ mkdir -p "$(dirname \"$RESULT_FILE\")" cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCOMPILER_PARSE_ONLY=OFF cmake --build build -j "$(nproc)" - bash scripts/test_lab2.sh + CASE_DIR=test/test_case bash scripts/test_lab2.sh echo "[run_lab2] end: $(date '+%Y-%m-%d %H:%M:%S')" } 2>&1 | tee "$RESULT_FILE" diff --git a/scripts/test_lab2.sh b/scripts/test_lab2.sh index 5d6c8a3..91d831b 100644 --- a/scripts/test_lab2.sh +++ b/scripts/test_lab2.sh @@ -65,7 +65,13 @@ echo "cases : $CASE_DIR" | tee -a "$LOG_FILE" echo "out dir : $OUT_DIR" | tee -a "$LOG_FILE" echo "[Step 1] single sample check: simple_add.sy" | tee -a "$LOG_FILE" -if "$VERIFY_SCRIPT" "$CASE_DIR/simple_add.sy" "$OUT_DIR" --run >> "$LOG_FILE" 2>&1; then +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" + echo "stop here. see log: $LOG_FILE" >&2 + exit 1 +fi +if "$VERIFY_SCRIPT" "$sample_input" "$OUT_DIR" --run >> "$LOG_FILE" 2>&1; then echo "single sample: PASS" | tee -a "$LOG_FILE" else echo "single sample: FAIL" | tee -a "$LOG_FILE" diff --git a/src/irgen/IRGenDecl.cpp b/src/irgen/IRGenDecl.cpp index afa3156..c706771 100644 --- a/src/irgen/IRGenDecl.cpp +++ b/src/irgen/IRGenDecl.cpp @@ -108,7 +108,7 @@ std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) { if (!ty) { throw std::runtime_error(FormatError("irgen", "变量类型缺失")); } - auto* slot = builder_.CreateAlloca(ToIRType(*ty), module_.GetContext().NextTemp()); + auto* slot = CreateEntryAlloca(ToIRType(*ty), module_.GetContext().NextTemp()); var_storage_[ctx] = slot; if (ty->dims.empty()) { @@ -181,7 +181,7 @@ std::any IRGenImpl::visitConstDef(SysYParser::ConstDefContext* ctx) { if (!ty) { throw std::runtime_error(FormatError("irgen", "常量类型缺失")); } - auto* slot = builder_.CreateAlloca(ToIRType(*ty), module_.GetContext().NextTemp()); + auto* slot = CreateEntryAlloca(ToIRType(*ty), module_.GetContext().NextTemp()); const_storage_[ctx] = slot; if (ty->dims.empty()) { diff --git a/src/irgen/IRGenExp.cpp b/src/irgen/IRGenExp.cpp index 37d338f..4001137 100644 --- a/src/irgen/IRGenExp.cpp +++ b/src/irgen/IRGenExp.cpp @@ -122,54 +122,54 @@ std::any IRGenImpl::visitUnaryExp(SysYParser::UnaryExpContext* ctx) { for (size_t i = 0; i < args.size() && i < param_tys.size(); ++i) { auto* arg = args[i]; const auto& pty = param_tys[i]; - if (pty->IsPointer() && arg && arg->GetType() && arg->GetType()->IsPointer()) { - bool param_elem_array = pty->GetElementType()->IsArray(); - bool arg_elem_array = arg->GetType()->GetElementType()->IsArray(); - if (!param_elem_array && arg_elem_array) { - std::vector idx = {builder_.CreateConstInt(0), - builder_.CreateConstInt(0)}; - args[i] = builder_.CreateGep(arg, std::move(idx), - module_.GetContext().NextTemp()); - arg = args[i]; - } else if (param_elem_array && arg_elem_array) { - auto* param_elem = pty->GetElementType().get(); - auto* arg_elem = arg->GetType()->GetElementType().get(); - if (param_elem && arg_elem && arg_elem->IsArray() && - arg_elem->GetElementType()->Equals(*param_elem)) { - std::vector idx = {builder_.CreateConstInt(0)}; + if (pty->IsPointer()) { + if (arg && arg->GetType() && arg->GetType()->IsPointer()) { + bool param_elem_array = pty->GetElementType()->IsArray(); + bool arg_elem_array = arg->GetType()->GetElementType()->IsArray(); + if (!param_elem_array && arg_elem_array) { + std::vector idx = {builder_.CreateConstInt(0), + builder_.CreateConstInt(0)}; args[i] = builder_.CreateGep(arg, std::move(idx), module_.GetContext().NextTemp()); arg = args[i]; + } else if (param_elem_array && arg_elem_array) { + auto* param_elem = pty->GetElementType().get(); + auto* arg_elem = arg->GetType()->GetElementType().get(); + if (param_elem && arg_elem && arg_elem->IsArray() && + arg_elem->GetElementType()->Equals(*param_elem)) { + std::vector idx = {builder_.CreateConstInt(0)}; + args[i] = builder_.CreateGep(arg, std::move(idx), + module_.GetContext().NextTemp()); + arg = args[i]; + } + } else if (param_elem_array && !arg_elem_array) { + if (auto* gep = dynamic_cast(arg)) { + const auto& idx = gep->GetIndices(); + auto is_zero = [](ir::Value* v) { + auto* ci = dynamic_cast(v); + return ci && ci->GetValue() == 0; + }; + if (idx.size() == 2 && is_zero(idx[0]) && is_zero(idx[1])) { + auto* base = gep->GetBasePtr(); + if (base && base->GetType() && base->GetType()->IsPointer() && + base->GetType()->GetElementType()->IsArray()) { + args[i] = base; + arg = base; + } + } + } } - } else if (param_elem_array && !arg_elem_array) { - if (auto* gep = dynamic_cast(arg)) { - const auto& idx = gep->GetIndices(); - auto is_zero = [](ir::Value* v) { - auto* ci = dynamic_cast(v); - return ci && ci->GetValue() == 0; - }; - if (idx.size() == 2 && is_zero(idx[0]) && is_zero(idx[1])) { - auto* base = gep->GetBasePtr(); - if (base && base->GetType() && base->GetType()->IsPointer() && - base->GetType()->GetElementType()->IsArray()) { + } else if (arg && arg->GetType() && arg->GetType()->IsInt32()) { + if (auto* load = dynamic_cast(arg)) { + auto* base = load->GetPtr(); + if (base && base->GetType() && base->GetType()->IsPointer()) { + auto* elem = base->GetType()->GetElementType().get(); + if (elem && elem->IsPointer() && + elem->GetElementType()->Equals(*pty->GetElementType())) { args[i] = base; arg = base; } } - } else if (auto* gep = dynamic_cast(arg)) { - auto* base = gep->GetBasePtr(); - if (base && base->GetType() && base->GetType()->IsPointer() && - base->GetType()->GetElementType()->IsArray()) { - auto* base_elem = base->GetType()->GetElementType().get(); - auto* param_elem = pty->GetElementType().get(); - if (base_elem && base_elem->IsArray() && param_elem && - base_elem->GetElementType()->Equals(*param_elem)) { - std::vector idx2 = {builder_.CreateConstInt(0)}; - args[i] = builder_.CreateGep(base, std::move(idx2), - module_.GetContext().NextTemp()); - arg = args[i]; - } - } } } } @@ -329,8 +329,11 @@ std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) { throw std::runtime_error(FormatError("irgen", "无法解析左值类型")); } bool as_rvalue = true; - if (!ty->dims.empty() && ctx->LBRACK().empty()) { - as_rvalue = false; + if (!ty->dims.empty()) { + const size_t index_count = ctx->exp().size(); + if (index_count == 0 || index_count < ty->dims.size()) { + as_rvalue = false; + } } return static_cast(LoadIfNeeded(addr, *ty, as_rvalue)); } @@ -648,6 +651,18 @@ ir::Value* IRGenImpl::DefaultValue(const TypeDesc& ty) { return builder_.CreateConstInt(0); } +ir::AllocaInst* IRGenImpl::CreateEntryAlloca(std::shared_ptr ty, + const std::string& name) { + if (!func_) { + throw std::runtime_error(FormatError("irgen", "CreateEntryAlloca 缺少函数")); + } + auto* entry = func_->GetEntry(); + if (!entry) { + throw std::runtime_error(FormatError("irgen", "CreateEntryAlloca 缺少入口块")); + } + return entry->Prepend(std::move(ty), name); +} + size_t IRGenImpl::ArrayStride(const TypeDesc& ty, size_t dim) const { size_t stride = 1; for (size_t i = dim + 1; i < ty.dims.size(); ++i) { @@ -749,10 +764,14 @@ void IRGenImpl::InitArray(ir::Value* base_ptr, const TypeDesc& ty, ir::Value* addr = builder_.CreateGep(base_ptr, std::move(indices), module_.GetContext().NextTemp()); ir::Value* value = values[idx]; - if (ty.base == BaseTypeKind::Float && (value->IsInt1() || value->IsInt32())) { - value = CastToFloat(value); + if (ty.base == BaseTypeKind::Float) { + if (value->IsInt1() || value->IsInt32()) { + value = CastToFloat(value->IsInt1() ? CastToInt(value) : value); + } } else if (ty.base == BaseTypeKind::Int && value->IsFloat()) { value = CastToInt(value); + } else if (ty.base == BaseTypeKind::Int && value->IsInt1()) { + value = CastToInt(value); } builder_.CreateStore(value, addr); } @@ -777,10 +796,14 @@ void IRGenImpl::InitConstArray(ir::Value* base_ptr, const TypeDesc& ty, ir::Value* addr = builder_.CreateGep(base_ptr, std::move(indices), module_.GetContext().NextTemp()); ir::Value* value = values[idx]; - if (ty.base == BaseTypeKind::Float && (value->IsInt1() || value->IsInt32())) { - value = CastToFloat(value); + if (ty.base == BaseTypeKind::Float) { + if (value->IsInt1() || value->IsInt32()) { + value = CastToFloat(value->IsInt1() ? CastToInt(value) : value); + } } else if (ty.base == BaseTypeKind::Int && value->IsFloat()) { value = CastToInt(value); + } else if (ty.base == BaseTypeKind::Int && value->IsInt1()) { + value = CastToInt(value); } builder_.CreateStore(value, addr); } diff --git a/src/irgen/IRGenFunc.cpp b/src/irgen/IRGenFunc.cpp index 60c0b68..bbd071e 100644 --- a/src/irgen/IRGenFunc.cpp +++ b/src/irgen/IRGenFunc.cpp @@ -62,6 +62,8 @@ std::any IRGenImpl::visitCompUnit(SysYParser::CompUnitContext* ctx) { declare_builtin("putfloat", ir::Type::GetVoidType(), {f32}); declare_builtin("putfarray", ir::Type::GetVoidType(), {i32, ir::Type::GetPointerType(f32)}); + declare_builtin("starttime", ir::Type::GetVoidType(), {}); + declare_builtin("stoptime", ir::Type::GetVoidType(), {}); for (auto* funcDef : ctx->funcDef()) { if (funcDef) funcDef->accept(this); @@ -98,8 +100,8 @@ std::any IRGenImpl::visitFuncDef(SysYParser::FuncDefContext* ctx) { if (!pty) { throw std::runtime_error(FormatError("irgen", "缺少参数类型")); } - auto slot = builder_.CreateAlloca(ToIRParamType(*pty), - module_.GetContext().NextTemp()); + auto slot = CreateEntryAlloca(ToIRParamType(*pty), + module_.GetContext().NextTemp()); builder_.CreateStore(arg, slot); param_storage_[param_ctx] = slot; } diff --git a/src/irgen/IRGenStmt.cpp b/src/irgen/IRGenStmt.cpp index 80c4816..1aac9a9 100644 --- a/src/irgen/IRGenStmt.cpp +++ b/src/irgen/IRGenStmt.cpp @@ -68,10 +68,18 @@ std::any IRGenImpl::visitStmt(SysYParser::StmtContext* ctx) { if (!ty) { throw std::runtime_error(FormatError("irgen", "无法解析赋值类型")); } - if (ty->base == BaseTypeKind::Float && val->IsInt32()) { - val = CastToFloat(val); - } else if (ty->base == BaseTypeKind::Int && val->IsFloat()) { - val = CastToInt(val); + if (ty->base == BaseTypeKind::Float) { + if (val->IsInt1()) { + val = CastToFloat(CastToInt(val)); + } else if (val->IsInt32()) { + val = CastToFloat(val); + } + } else if (ty->base == BaseTypeKind::Int) { + if (val->IsFloat()) { + val = CastToInt(val); + } else if (val->IsInt1()) { + val = CastToInt(val); + } } builder_.CreateStore(val, addr); return BlockFlow::Continue; diff --git a/src/sem/Sema.cpp b/src/sem/Sema.cpp index f135a5b..9ac563a 100644 --- a/src/sem/Sema.cpp +++ b/src/sem/Sema.cpp @@ -495,7 +495,8 @@ class SemaVisitor final : public SysYBaseVisitor { std::unordered_map func_table_; const std::unordered_set builtin_funcs_ = { "getint", "getch", "getarray", "putint", "putch", "putarray", - "getfloat", "getfarray", "putfloat", "putfarray"}; + "getfloat", "getfarray", "putfloat", "putfarray", "starttime", + "stoptime"}; BaseTypeKind current_ret_ = BaseTypeKind::Void; bool seen_return_ = false; int loop_depth_ = 0; diff --git a/sylib/sylib.c b/sylib/sylib.c index d968ce0..1b357a5 100644 --- a/sylib/sylib.c +++ b/sylib/sylib.c @@ -22,10 +22,11 @@ void putint(int x) { printf("%d", x); } void putch(int x) { putchar(x); } void putarray(int n, int a[]) { - printf("%d", n); + printf("%d:", n); for (int i = 0; i < n; ++i) { printf(" %d", a[i]); } + printf("\n"); } float getfloat() { @@ -50,5 +51,11 @@ void putfarray(int n, float a[]) { for (int i = 0; i < n; ++i) { printf(" %a", a[i]); } + printf("\n"); } +// Performance timing hooks (no-op stubs for correctness testing). +void starttime() {} + +void stoptime() {} +