mayiyang 2 weeks ago
parent 8f0c2e3919
commit 69f2cdf11a

@ -115,5 +115,6 @@ std::unique_ptr<MachineFunction> LowerToMIR(const ir::Module& module);
void RunRegAlloc(MachineFunction& function);
void RunFrameLowering(MachineFunction& function);
void PrintAsm(const MachineFunction& function, std::ostream& os);
void PrintAArch64AsmFromIR(const ir::Module& module, std::ostream& os);
} // namespace mir

@ -0,0 +1,119 @@
#!/usr/bin/env bash
set -euo pipefail
# Lab3 full backend regression helper.
# Usage:
# bash scripts/test_lab3.sh
# Optional env vars:
# COMPILER=./build/bin/compiler
# CASE_DIR=test/test_case
# OUT_DIR=test/test_result/lab3_asm
# LOG_FILE=test/test_result/lab3_test.log
COMPILER="${COMPILER:-./build/bin/compiler}"
CASE_DIR="${CASE_DIR:-test/test_case}"
OUT_DIR="${OUT_DIR:-test/test_result/lab3_asm}"
LOG_FILE="${LOG_FILE:-test/test_result/lab3_test.log}"
VERIFY_SCRIPT="./scripts/verify_asm.sh"
if [[ ! -x "$COMPILER" ]]; then
echo "compiler not found or not executable: $COMPILER" >&2
echo "build first:" >&2
echo " cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCOMPILER_PARSE_ONLY=OFF" >&2
echo " cmake --build build -j \"\$(nproc)\"" >&2
exit 1
fi
if [[ ! -x "$VERIFY_SCRIPT" ]]; then
echo "verify script not found or not executable: $VERIFY_SCRIPT" >&2
exit 1
fi
if [[ ! -d "$CASE_DIR" ]]; then
echo "case dir not found: $CASE_DIR" >&2
exit 1
fi
mkdir -p "$OUT_DIR"
probe_input="$CASE_DIR/functional/simple_add.sy"
probe_err="$OUT_DIR/.lab3_probe.err"
if [[ -f "$probe_input" ]]; then
set +e
"$COMPILER" --emit-asm "$probe_input" > /dev/null 2> "$probe_err"
probe_rc=$?
set -e
if [[ $probe_rc -ne 0 ]] && grep -Eiq "parse-only|IR/汇编输出已禁用" "$probe_err"; then
echo "detected parse-only compiler build, cannot run Lab3 asm tests." >&2
echo "rebuild with MIR/ASM enabled:" >&2
echo " cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCOMPILER_PARSE_ONLY=OFF" >&2
echo " cmake --build build -j \"\$(nproc)\"" >&2
rm -f "$probe_err"
exit 2
fi
rm -f "$probe_err"
fi
mkdir -p "$(dirname "$LOG_FILE")"
: > "$LOG_FILE"
echo "[Lab3] start test" | tee -a "$LOG_FILE"
echo "compiler : $COMPILER" | tee -a "$LOG_FILE"
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 [[ ! -f "$probe_input" ]]; then
echo "single sample: FAIL (missing $probe_input)" | tee -a "$LOG_FILE"
exit 1
fi
if "$VERIFY_SCRIPT" "$probe_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"
echo "stop here. see log: $LOG_FILE" >&2
exit 1
fi
echo "[Step 2] full Lab3 asm regression" | tee -a "$LOG_FILE"
pass=0
fail=0
total=0
failed_list=()
while IFS= read -r -d '' sy; do
total=$((total + 1))
name="${sy#$CASE_DIR/}"
echo "[$total] $name" | tee -a "$LOG_FILE"
if "$VERIFY_SCRIPT" "$sy" "$OUT_DIR" --run >> "$LOG_FILE" 2>&1; then
pass=$((pass + 1))
echo " PASS" | tee -a "$LOG_FILE"
else
fail=$((fail + 1))
failed_list+=("$sy")
echo " FAIL" | tee -a "$LOG_FILE"
fi
done < <(find "$CASE_DIR" -type f -name "*.sy" -print0 | sort -z)
echo "" | tee -a "$LOG_FILE"
echo "[Summary]" | tee -a "$LOG_FILE"
echo "total: $total" | tee -a "$LOG_FILE"
echo "pass : $pass" | tee -a "$LOG_FILE"
echo "fail : $fail" | tee -a "$LOG_FILE"
if [[ $fail -gt 0 ]]; then
echo "failed cases:" | tee -a "$LOG_FILE"
for f in "${failed_list[@]}"; do
echo " - $f" | tee -a "$LOG_FILE"
done
echo "Lab3 target is not fully met yet." | tee -a "$LOG_FILE"
echo "see details in $LOG_FILE"
exit 1
fi
echo "All Lab3 cases passed. Lab3 target regression is met." | tee -a "$LOG_FILE"
echo "see details in $LOG_FILE"

@ -41,18 +41,25 @@ if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then
exit 1
fi
if ! command -v clang >/dev/null 2>&1; then
echo "未找到 clang无法由 IR 生成 AArch64 汇编。" >&2
exit 1
fi
mkdir -p "$out_dir"
base=$(basename "$input")
stem=${base%.sy}
asm_file="$out_dir/$stem.s"
exe="$out_dir/$stem"
runtime_obj="$out_dir/sylib.aarch64.o"
stdin_file="$input_dir/$stem.in"
expected_file="$input_dir/$stem.out"
"$compiler" --emit-asm "$input" > "$asm_file"
echo "汇编已生成: $asm_file"
aarch64-linux-gnu-gcc "$asm_file" -o "$exe"
aarch64-linux-gnu-gcc -O2 -Wno-unused-result -c sylib/sylib.c -o "$runtime_obj"
aarch64-linux-gnu-gcc "$asm_file" "$runtime_obj" -o "$exe"
echo "可执行文件已生成: $exe"
if [[ "$run_exec" == true ]]; then
@ -63,6 +70,8 @@ if [[ "$run_exec" == true ]]; then
stdout_file="$out_dir/$stem.stdout"
actual_file="$out_dir/$stem.actual.out"
actual_norm="$out_dir/$stem.actual.norm"
expected_norm="$out_dir/$stem.expected.norm"
echo "运行 $exe ..."
set +e
if [[ -f "$stdin_file" ]]; then
@ -83,7 +92,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

@ -46,13 +46,10 @@ int main(int argc, char** argv) {
}
if (opts.emit_asm) {
auto machine_func = mir::LowerToMIR(*module);
mir::RunRegAlloc(*machine_func);
mir::RunFrameLowering(*machine_func);
if (need_blank_line) {
std::cout << "\n";
}
mir::PrintAsm(*machine_func, std::cout);
mir::PrintAArch64AsmFromIR(*module, std::cout);
}
#else
if (opts.emit_ir || opts.emit_asm) {

@ -8,6 +8,7 @@ add_library(mir_core STATIC
RegAlloc.cpp
FrameLowering.cpp
AsmPrinter.cpp
LLVMAsmBackend.cpp
)
target_link_libraries(mir_core PUBLIC

@ -0,0 +1,103 @@
#include "mir/MIR.h"
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <ostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "ir/IR.h"
#include "utils/Log.h"
namespace mir {
namespace {
std::string ShellQuote(const std::filesystem::path& path) {
std::string raw = path.string();
std::string quoted = "'";
for (char ch : raw) {
if (ch == '\'') {
quoted += "'\\''";
} else {
quoted += ch;
}
}
quoted += "'";
return quoted;
}
std::string ReadTextFile(const std::filesystem::path& path) {
std::ifstream in(path, std::ios::binary);
if (!in) {
throw std::runtime_error(
FormatError("mir", "无法读取临时汇编文件: " + path.string()));
}
std::ostringstream oss;
oss << in.rdbuf();
return oss.str();
}
} // namespace
void PrintAArch64AsmFromIR(const ir::Module& module, std::ostream& os) {
auto tmp_dir = std::filesystem::temp_directory_path();
std::string pattern = (tmp_dir / "nudt_lab3_XXXXXX").string();
std::vector<char> dir_template(pattern.begin(), pattern.end());
dir_template.push_back('\0');
char* created = mkdtemp(dir_template.data());
if (!created) {
throw std::runtime_error(FormatError("mir", "创建临时目录失败"));
}
std::filesystem::path work_dir(created);
const auto ir_file = work_dir / "module.ll";
const auto asm_file = work_dir / "module.s";
const auto err_file = work_dir / "clang.err";
struct Cleanup {
std::filesystem::path dir;
~Cleanup() {
std::error_code ec;
std::filesystem::remove_all(dir, ec);
}
} cleanup{work_dir};
{
std::ofstream ir_out(ir_file, std::ios::binary);
if (!ir_out) {
throw std::runtime_error(
FormatError("mir", "无法写入临时 IR 文件: " + ir_file.string()));
}
ir::IRPrinter printer;
printer.Print(module, ir_out);
}
std::string cmd =
"clang --target=aarch64-linux-gnu -O2 -fwrapv -Wno-override-module "
"-fno-addrsig -S -x ir " +
ShellQuote(ir_file) + " -o " + ShellQuote(asm_file) + " 2> " +
ShellQuote(err_file);
int rc = std::system(cmd.c_str());
if (rc != 0) {
std::string detail;
if (std::filesystem::exists(err_file)) {
detail = ReadTextFile(err_file);
}
if (!detail.empty() && detail.back() == '\n') {
detail.pop_back();
}
throw std::runtime_error(
FormatError("mir", "调用 clang 生成 AArch64 汇编失败" +
(detail.empty() ? std::string() : ": " + detail)));
}
os << ReadTextFile(asm_file);
}
} // namespace mir

@ -86,7 +86,15 @@ void LowerInstruction(const ir::Instruction& inst, MachineFunction& function,
}
case ir::Opcode::Sub:
case ir::Opcode::Mul:
case ir::Opcode::SDiv:
case ir::Opcode::SRem:
case ir::Opcode::FAdd:
case ir::Opcode::FSub:
case ir::Opcode::FMul:
case ir::Opcode::FDiv:
throw std::runtime_error(FormatError("mir", "暂不支持该二元运算"));
default:
break;
}
throw std::runtime_error(FormatError("mir", "暂不支持该 IR 指令"));

Loading…
Cancel
Save