Skip to content

feat(topic28): extend RISC-V instruction selection and f64 support - #85

Open
ForsakenDelusion wants to merge 12 commits into
ScratchV-Compiler:mainfrom
ForsakenDelusion:docs/topic28-design
Open

ForsakenDelusion wants to merge 12 commits into
ScratchV-Compiler:mainfrom
ForsakenDelusion:docs/topic28-design

Conversation

@ForsakenDelusion

@ForsakenDelusion ForsakenDelusion commented Sep 28, 2026 •

Copy link
Copy Markdown

Summary

DSL / ONNX 标量 i32、f32、f64
  → 保留类型的 IR 和优化
  → RV32IM / F / D 指令选择
  → 整数或浮点寄存器、4/8 字节保存、每函数栈空间
  → 合法汇编、独立调用者、QEMU 执行

增加除法、余数、平方根、min/max、符号操作、访存及比较分支,提供四个 DSL 示例、支持列表和使用说明。R1–R4 的 LLVM 失败处理、函数内部重名、常量编码和分配器复用问题已修复。后续 R5 也已修复:ONNX 浮点 Min/Max 在任意输入为 NaN 时返回 NaN,IR 执行器同步处理,DSL 保持既有规则。

最低 Python 版本保留为 3.8:替换不兼容注解和标准库方法,保留调度器构造行为,统一版本说明,并在现有测试任务中增加独立的 3.8 兼容检查。

Review 报告与修复记录

2026-10-14 工程复审报告:新增 R7(P1)和 R6(P2),目前尚未修复;两项规范/维护建议为 P3。

Evidence

  • 2026-10-14 对固定提交 37516a7 再跑完整回归:3826 passed,0 failed,0 skipped。独立探针仍确认 9 个 LLVM 常量错误场景和 36 个 ONNX 符号零结果差异,已有测试尚未覆盖或采用了目标预期。
  • Before: 在 77bef84 的生产代码上,新 NaN 专项测试为 156 失败、60 通过;加上纠正 ONNX 预期后的 96 项既有编码测试,共 216 失败、96 通过。
    After: 新增 216 项专项测试通过,既有编码测试继续检查位模式、ABI 和异常标志;R5 修复后的 Python 3.12 完整回归为 3826 passed,0 failed,0 skipped。
  • Python 3.8.20:NaN 专项和相关回归 917 passed,0 failed,0 skipped,包含更新后的最低版本 CI 入口 361 项。
  • 8 个 NaN 场景的 ONNX 官方参考实现、ONNX Runtime 1.30.0 和 QEMU 执行结果一致。
  • Before: 同一份 6 项兼容测试在 e061861 的生产代码和真实 Python 3.8 下全部失败,导入阶段报错。
    After: 6 项全部通过;Python 兼容性修复时最低版本 CI 入口的 145 项测试通过,包含原始课题验收 99 项和真实 RISC-V 执行。
  • Python 兼容性修复时,Python 3.8.20 完整回归:3610 passed,0 failed,0 skipped。
  • Python 兼容性修复时,Python 3.12 完整回归:3610 passed,0 failed,0 skipped;仅有已有的 TinyFive 弃用提示。
  • 使用 Clang/LLD 与 QEMU 汇编、链接、执行;git diff --check 通过。远端 Actions 结果以实际运行记录为准。
  • evidence 和 repro 文件只保留在本地,不纳入提交。

Merge Danger

Door: two-way

代码和配置可通过回退提交恢复。

Blast Radius: 编译管线

影响共享前端、IR 优化、RISC-V 选择与分配、栈布局及部分基准工具。范围为 RV32 标量和硬件 F/D;内部 encoder/emulator 仍仅支持 RV32IM。

ONNX Min/Max 的 NaN 传播问题已修复。本轮复审仍有两项待处理:R7(P1),共享 typed const 输入进入 LLVM 后,普通 f32 小数可产生无法解析的文本,f64 常量可能丢精度或负零符号;R6(P2),ONNX 正负零经 Min/Max 后接 Div 的结果与官方参考实现和 ONNX Runtime 符号相反。R6 是已复现的兼容差异,公开 ONNX 算子说明没有明文规定符号零相等时的选择规则。范围仍为 RV32 标量与硬件 F/D。

Copilot AI lite review requested due to automatic review settings September 28, 2026 15:24
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

🤖 AI Code Review

共审查 10 个变更文件
⚠️ 另有 20 个文件超过上限(最多 10 个)未审查

📁 .github/workflows/ci.yml

Code Review: .github/workflows/ci.yml

🔴 Risk: venv module availability on Python 3.8 — "$MINIMUM_PYTHON" -m venv will fail if python3.8-venv isn't installed. On GitHub-hosted ubuntu runners this is typically pre-installed, but if you ever self-host or change the runner image, this is a silent landmine. Consider adding an explicit install step or a pre-check:

"$MINIMUM_PYTHON" -c "import ensurepip" || sudo apt-get install -y python3.8-venv

🟡 Hardcoded test file list is fragile — Six individual test files listed. If tests are renamed or moved, this breaks silently. Consider a glob or directory-level invocation:

"$COMPAT_PYTHON" -m pytest tests/test_topic28_*.py tests/test_regalloc_result_reuse.py

If the explicit list is intentional for pinning scope, add a comment explaining why — currently it's unclear.

🟡 Unpinned pip install -e . causes CI flakiness — Each run resolves dependencies fresh against current PyPI. If a transitive dep breaks Python 3.8 compatibility, CI turns red with no diff. Consider committing a lock file or pinning key deps:

"$COMPAT_PYTHON" -m pip install -e . "pytest>=7,<9" -c constraints-py38.txt

🟡 No timeout on the test step — A hung test (e.g., waiting on RISC-V execution) blocks the entire job. Add a step-level timeout:

timeout-minutes: 10

💭 Redundant diagnostic output — clang --version, ld.lld --version, qemu-riscv32 --version dump full multi-line output every CI run. If the intent is just to capture versions for debugging, consider logging to a file and uploading as an artifact only on failure:

{ clang --version; ld.lld --version; qemu-riscv32 --version; } > "$RUNNER_TEMP/toolchain_versions.txt"

💭 PYTHONHASHSEED only set here — If other test steps don't set it, results may differ between runs within the same job. Consider setting it at the job level for consistency.


📁 CLAUDE.md

Review: CLAUDE.md Python 版本要求变更

🟡 **EOL 风险提示** — Python 3.8 已于 2024-10 EOL。
  作为项目规范文档,此处未说明 3.8 仅为临时兼容窗口还是有长期维护计划。
  建议补充截止条件(如 "Python 3.8 兼容至 YYYY-MM,届时移除"),
  否则后续开发者无法判断何时可以放弃 3.8 支持。

🟡 **引用依赖未落地** — "版本与注解规则以 CONTRIBUTING.md 为准"
  如果 CONTRIBUTING.md 当前不存在或尚未包含对应规则,
  此引用成为空指针,开发者照此执行会得到矛盾指令。
  建议:要么先确保 CONTRIBUTING.md 就绪,要么在此处内联关键约束。

🟡 **CI 声明需与实际一致** — "CI 主环境使用 3.12,Topic 28 另有 3.8 兼容测试"
  将此作为规范写入前,应确认 CI 配置(GitHub Actions / GitLab CI)
  确实已包含 3.8 矩阵测试。文档先于基础设施落地会导致开发者信任偏差。

💭 **单条信息密度偏高** — 第二行同时包含版本号、验证要求、CI 版本、Topic 编号、
  测试分工。考虑拆为两条(一条说要求,一条说验证方式),降低认知负荷。

📁 README.md

🟡 Verify actual minimum Python version — Changing the badge from 3.12+ to 3.8+ is a significant claim. Confirm pyproject.toml / setup.cfg / CI matrix actually supports 3.8. If code uses 3.9+ features (dict|dict merge, match/case, X | None union syntax), a 3.8 badge misleads users and breaks their installs.

💭 If 3.8 support is intentional, consider whether transitive dependencies also support it — the badge alone isn't enough to guarantee compatibility.


📁 benchmarks/bench_cnn_schedule.py

无问题。 这是一个合理的重构,将路径解析逻辑从三元表达式提取到 try/except 块中,逻辑等价(.relative_to() 在非相对路径时抛出 ValueError,与原代码的 is_relative_to 判断结果一致),且兼容 Python < 3.9。

仅一个可选建议:

💭 Narrow the exception scope — Line 273: except ValueError is fine, but if you want to be extra defensive (and it's a benchmark file worth keeping robust), you could add a brief comment explaining the intent:

try:
    input_path = model_path.relative_to(ROOT).as_posix()
except ValueError:
    # Fallback: model_path is not under ROOT (e.g. symlink or temp dir)
    input_path = str(model_path)

这有助于未来的读者理解为什么捕获 ValueError 而不是使用 is_relative_to。


总结:变更正确、安全、可读性更好。可以合并。


📁 benchmarks/bench_dsl_diagnostics.py

🟡 Suggestion — No functional issues; the try/except fallback is correct and idiomatic for pre-3.9 compatibility.

Minor note: if this file has a consistent Python version target, a comment (e.g., # Python 3.9+ has is_relative_to; fallback for <3.9) would help future readers understand why the more verbose form is used.


📁 benchmarks/compare_schedule_disabled.py

🟡 Exception breadth — Catching bare ValueError is fine here, but relative_to() raises ValueError for any reason the path isn't relative. A comment noting this is intentional (vs. e.g. a real path error) would help future readers distinguish the catch from a typo.

# ValueError raised only when path is not relative to root
try:
    Path(compiler.__file__).resolve().relative_to(root)
except ValueError:
    raise RuntimeError(...) from None

💭 Otherwise the change is correct — semantically equivalent to is_relative_to(), improves Python 3.9 compatibility, and from None cleanly suppresses the inner traceback.


📁 benchmarks/generate_models.py

No issues. Clean, zero-risk change — enables PEP 563 (deferred annotation evaluation) without side effects.


📁 benchmarks/test_regalloc/bench_cnn.py

💭 No issues — from __future__ import annotations is a safe, idiomatic addition (PEP 563). Enables forward references and X | Y union syntax on older runtimes without runtime cost. Good practice.

Only note: confirm no runtime-evaluated annotations exist in this file (e.g., pydantic.BaseModel, dataclasses with __future__ quirks, or explicit typing.get_type_hints() calls), since those need live values rather than strings. Given this is a benchmark harness, that's unlikely — LGTM.


📁 benchmarks/test_regalloc/bench_dense.py

This is a trivial, safe change — no issues found.

from __future__ import annotations is a no-op at runtime (just sets __annotations__ to strings), safe to add any time, and enables forward references and PEP 604-style unions (X | None) on older Python versions. 👍


📁 benchmarks/test_regalloc/bench_regalloc_linear.py

No issues found.

from __future__ import annotations (PEP 563) defers annotation evaluation to strings — a safe, additive change with no functional impact for a benchmarking script. 👍



⚠️ 未审查的文件

  • benchmarks/test_regalloc/bench_simple.py
  • benchmarks/test_regalloc/bench_utils.py
  • benchmarks/topic28/f32_sum.dsl
  • benchmarks/topic28/f64_dot.dsl
  • benchmarks/topic28/f64_sum.dsl
  • benchmarks/topic28/i32_div_rem.dsl
  • docs/topics/28-扩展指令选择/28-README.md
  • docs/topics/28-扩展指令选择/28-交付与验收.md
  • docs/topics/28-扩展指令选择/28-代码Review报告-2026-10-12.md
  • docs/topics/28-扩展指令选择/28-复审报告-2026-10-14.md
  • docs/topics/28-扩展指令选择/28-扩展指令选择-设计文档.md
  • docs/topics/28-扩展指令选择/28-扩展指令选择.md
  • memory/memory.md
  • scratchv/analysis/ir_verifier.py
  • scratchv/backend/abi_frame.py
  • scratchv/backend/allocation.py
  • scratchv/backend/asm_beautifier.py
  • scratchv/backend/asm_emit.py
  • scratchv/backend/asm_parser_for_beautifier.py
  • scratchv/backend/cycle_estimator.py

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The design contains unresolved type-validation and floating-point spill/reload issues, plus configuration and ordering ambiguities.

Review effort: Lite
Findings: None

What changed in this PR

Adds a technical design for Topic 28 instruction selection and links it from the topic page.

Changes:

  • Defines typed IR, integer/F/D floating-point lowering, register allocation, ABI, and constant folding.
  • Adds CLI integration, testing, acceptance criteria, and phased implementation planning.
  • Links the new design document from the topic page.
File Summary
docs/​topics/​28-扩展指令选择/​28-扩展指令选择.md Adds the design document link.
docs/​topics/​28-扩展指令选择/​28-扩展指令选择-设计文档.md Adds the comprehensive instruction-selection design. Findings: unknown ONNX types must fail instead of silently becoming FLOAT32 (critical, 1 vote); FPR spill/reload needs value-width/type propagation (moderate, 1 vote); rounding_mode requires validation (moderate, 1 vote); candidate priority direction should be defined (nit, 1 vote).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@ForsakenDelusion

Copy link
Copy Markdown
Author

@copilot code review

@ForsakenDelusion ForsakenDelusion changed the title docs(topic28): add instruction selection design docs(topic28): specify instruction selection design and APIs Oct 11, 2026
@ForsakenDelusion ForsakenDelusion changed the title docs(topic28): specify instruction selection design and APIs feat(topic28): extend RISC-V instruction selection and f64 support Oct 11, 2026
Add independent-function regressions and expand LLVM integer input rejection tests, recording before/after validation in the review report.
Decode constant storage bits consistently at load and operand boundaries, preserving instruction-only encodings within each function. Add bit-level regression tests and document before/after validation.
Explain the findings and fixes in plain language, mark all four issues as resolved, and retain reproduction examples and validation results.
Use minimum-version annotations and standard-library APIs, preserve frozen scheduler construction, and align Python support documentation.

Add real Python 3.8 coverage to the existing CI test job and keep ONNX test fixtures consistent across supported NumPy and ONNX versions.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants