codecin 5.5.0__tar.gz → 5.5.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. {codecin-5.5.0 → codecin-5.5.3}/CHANGELOG.md +54 -0
  2. {codecin-5.5.0 → codecin-5.5.3}/MANIFEST.in +7 -1
  3. {codecin-5.5.0/codecin.egg-info → codecin-5.5.3}/PKG-INFO +93 -55
  4. {codecin-5.5.0 → codecin-5.5.3}/README.md +92 -54
  5. {codecin-5.5.0 → codecin-5.5.3}/codecin/__init__.py +1 -1
  6. {codecin-5.5.0 → codecin-5.5.3}/codecin/cin.py +28 -7
  7. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/aot/aot.go +0 -15
  8. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/compiler/codegen.go +27 -9
  9. codecin-5.5.3/codecin/native/compiler/compile_test.go +368 -0
  10. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/version_gen.go +1 -1
  11. {codecin-5.5.0 → codecin-5.5.3/codecin.egg-info}/PKG-INFO +93 -55
  12. {codecin-5.5.0 → codecin-5.5.3}/codecin.egg-info/SOURCES.txt +2 -6
  13. {codecin-5.5.0 → codecin-5.5.3}/script/gen_isa_docs.py +68 -20
  14. codecin-5.5.3/tests/test_index_subscript_type.py +142 -0
  15. {codecin-5.5.0 → codecin-5.5.3}/tests/test_isa_dispatch.py +5 -9
  16. codecin-5.5.3/tests/test_nested_subscript_codegen.py +220 -0
  17. {codecin-5.5.0 → codecin-5.5.3}/tests/test_workflows.py +37 -3
  18. codecin-5.5.0/codecin/native/compiler/compile_test.go +0 -164
  19. codecin-5.5.0/docs/BUILDING.md +0 -541
  20. codecin-5.5.0/docs/CIN_GUIDE.md +0 -723
  21. codecin-5.5.0/docs/ISA.md +0 -90
  22. codecin-5.5.0/docs/REMOTE_DEBUG.md +0 -175
  23. codecin-5.5.0/docs/SUGGESTIONS.md +0 -583
  24. codecin-5.5.0/docs/SUGGESTIONS_NEXT.md +0 -568
  25. {codecin-5.5.0 → codecin-5.5.3}/LICENSE +0 -0
  26. {codecin-5.5.0 → codecin-5.5.3}/codecin/aot.py +0 -0
  27. {codecin-5.5.0 → codecin-5.5.3}/codecin/assembler.py +0 -0
  28. {codecin-5.5.0 → codecin-5.5.3}/codecin/cache.py +0 -0
  29. {codecin-5.5.0 → codecin-5.5.3}/codecin/cli.py +0 -0
  30. {codecin-5.5.0 → codecin-5.5.3}/codecin/config.py +0 -0
  31. {codecin-5.5.0 → codecin-5.5.3}/codecin/console.py +0 -0
  32. {codecin-5.5.0 → codecin-5.5.3}/codecin/cpu.py +0 -0
  33. {codecin-5.5.0 → codecin-5.5.3}/codecin/crom.py +0 -0
  34. {codecin-5.5.0 → codecin-5.5.3}/codecin/debugger.py +0 -0
  35. {codecin-5.5.0 → codecin-5.5.3}/codecin/disasm.py +0 -0
  36. {codecin-5.5.0 → codecin-5.5.3}/codecin/errors.py +0 -0
  37. {codecin-5.5.0 → codecin-5.5.3}/codecin/isa.py +0 -0
  38. {codecin-5.5.0 → codecin-5.5.3}/codecin/jit.py +0 -0
  39. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/array.cin +0 -0
  40. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/bits.cin +0 -0
  41. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/conv.cin +0 -0
  42. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/gui.cin +0 -0
  43. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/hash.cin +0 -0
  44. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/io.cin +0 -0
  45. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/json.cin +0 -0
  46. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/math.cin +0 -0
  47. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/matrix.cin +0 -0
  48. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/queue.cin +0 -0
  49. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/rand.cin +0 -0
  50. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/sort.cin +0 -0
  51. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/stat.cin +0 -0
  52. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/str.cin +0 -0
  53. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/termux.cin +0 -0
  54. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/test.cin +0 -0
  55. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/time.cin +0 -0
  56. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/validate.cin +0 -0
  57. {codecin-5.5.0 → codecin-5.5.3}/codecin/lib/vec.cin +0 -0
  58. {codecin-5.5.0 → codecin-5.5.3}/codecin/logger.py +0 -0
  59. {codecin-5.5.0 → codecin-5.5.3}/codecin/memory.py +0 -0
  60. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/aot/stub_main.go.txt +0 -0
  61. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/build.ps1 +0 -0
  62. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/build.sh +0 -0
  63. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/compiler/parser.go +0 -0
  64. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/compiler/syscalls.go +0 -0
  65. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/compiler/tokenizer.go +0 -0
  66. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/compiler/types.go +0 -0
  67. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/audio.go +0 -0
  68. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/audio_other.go +0 -0
  69. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/audio_windows.go +0 -0
  70. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/canvas.go +0 -0
  71. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/crom.go +0 -0
  72. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/encode.go +0 -0
  73. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/engine_test.go +0 -0
  74. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/isa_gen.go +0 -0
  75. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/system.go +0 -0
  76. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/termux.go +0 -0
  77. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/engine/vm.go +0 -0
  78. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/go.mod +0 -0
  79. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/ir/ir.go +0 -0
  80. {codecin-5.5.0 → codecin-5.5.3}/codecin/native/main.go +0 -0
  81. {codecin-5.5.0 → codecin-5.5.3}/codecin/native.py +0 -0
  82. {codecin-5.5.0 → codecin-5.5.3}/codecin/registers.py +0 -0
  83. {codecin-5.5.0 → codecin-5.5.3}/codecin/stats.py +0 -0
  84. {codecin-5.5.0 → codecin-5.5.3}/codecin.egg-info/dependency_links.txt +0 -0
  85. {codecin-5.5.0 → codecin-5.5.3}/codecin.egg-info/entry_points.txt +0 -0
  86. {codecin-5.5.0 → codecin-5.5.3}/codecin.egg-info/requires.txt +0 -0
  87. {codecin-5.5.0 → codecin-5.5.3}/codecin.egg-info/top_level.txt +0 -0
  88. {codecin-5.5.0 → codecin-5.5.3}/examples/asm_constants.asm +0 -0
  89. {codecin-5.5.0 → codecin-5.5.3}/examples/bitwise_builtins.cin +0 -0
  90. {codecin-5.5.0 → codecin-5.5.3}/examples/control_flow.cin +0 -0
  91. {codecin-5.5.0 → codecin-5.5.3}/examples/literals_types.cin +0 -0
  92. {codecin-5.5.0 → codecin-5.5.3}/examples/modules_demo.cin +0 -0
  93. {codecin-5.5.0 → codecin-5.5.3}/examples/stdlib_demo.cin +0 -0
  94. {codecin-5.5.0 → codecin-5.5.3}/examples/system_interaction.cin +0 -0
  95. {codecin-5.5.0 → codecin-5.5.3}/misc/vim/ftdetect/codecin.vim +0 -0
  96. {codecin-5.5.0 → codecin-5.5.3}/misc/vim/syntax/cin.vim +0 -0
  97. {codecin-5.5.0 → codecin-5.5.3}/misc/vim/syntax/codecinasm.vim +0 -0
  98. {codecin-5.5.0 → codecin-5.5.3}/pyproject.toml +0 -0
  99. {codecin-5.5.0 → codecin-5.5.3}/script/check_paths.py +0 -0
  100. {codecin-5.5.0 → codecin-5.5.3}/script/gen_native_isa.py +0 -0
  101. {codecin-5.5.0 → codecin-5.5.3}/setup.cfg +0 -0
  102. {codecin-5.5.0 → codecin-5.5.3}/setup.py +0 -0
  103. {codecin-5.5.0 → codecin-5.5.3}/tests/test_aot.py +0 -0
  104. {codecin-5.5.0 → codecin-5.5.3}/tests/test_assembler_ext.py +0 -0
  105. {codecin-5.5.0 → codecin-5.5.3}/tests/test_cache.py +0 -0
  106. {codecin-5.5.0 → codecin-5.5.3}/tests/test_cin_host.py +0 -0
  107. {codecin-5.5.0 → codecin-5.5.3}/tests/test_cin_new_features.py +0 -0
  108. {codecin-5.5.0 → codecin-5.5.3}/tests/test_cin_syntax.py +0 -0
  109. {codecin-5.5.0 → codecin-5.5.3}/tests/test_cin_system.py +0 -0
  110. {codecin-5.5.0 → codecin-5.5.3}/tests/test_cli.py +0 -0
  111. {codecin-5.5.0 → codecin-5.5.3}/tests/test_compiler_errors.py +0 -0
  112. {codecin-5.5.0 → codecin-5.5.3}/tests/test_cpu_interpreted.py +0 -0
  113. {codecin-5.5.0 → codecin-5.5.3}/tests/test_debugger.py +0 -0
  114. {codecin-5.5.0 → codecin-5.5.3}/tests/test_examples.py +0 -0
  115. {codecin-5.5.0 → codecin-5.5.3}/tests/test_features_ab.py +0 -0
  116. {codecin-5.5.0 → codecin-5.5.3}/tests/test_features_crom_mmu.py +0 -0
  117. {codecin-5.5.0 → codecin-5.5.3}/tests/test_features_import.py +0 -0
  118. {codecin-5.5.0 → codecin-5.5.3}/tests/test_features_importloc.py +0 -0
  119. {codecin-5.5.0 → codecin-5.5.3}/tests/test_features_mmu.py +0 -0
  120. {codecin-5.5.0 → codecin-5.5.3}/tests/test_features_remote.py +0 -0
  121. {codecin-5.5.0 → codecin-5.5.3}/tests/test_isa_single_source.py +0 -0
  122. {codecin-5.5.0 → codecin-5.5.3}/tests/test_libs.py +0 -0
  123. {codecin-5.5.0 → codecin-5.5.3}/tests/test_libs_ext.py +0 -0
  124. {codecin-5.5.0 → codecin-5.5.3}/tests/test_literals_and_bom.py +0 -0
  125. {codecin-5.5.0 → codecin-5.5.3}/tests/test_memory_protection.py +0 -0
  126. {codecin-5.5.0 → codecin-5.5.3}/tests/test_native_hardening.py +0 -0
  127. {codecin-5.5.0 → codecin-5.5.3}/tests/test_native_lib_lookup.py +0 -0
  128. {codecin-5.5.0 → codecin-5.5.3}/tests/test_no_go_cli.py +0 -0
  129. {codecin-5.5.0 → codecin-5.5.3}/tests/test_packaging.py +0 -0
  130. {codecin-5.5.0 → codecin-5.5.3}/tests/test_paths_consistency.py +0 -0
  131. {codecin-5.5.0 → codecin-5.5.3}/tests/test_switch_semantics.py +0 -0
  132. {codecin-5.5.0 → codecin-5.5.3}/tests/test_three_paths.py +0 -0
  133. {codecin-5.5.0 → codecin-5.5.3}/tests/test_version.py +0 -0
@@ -5,6 +5,60 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## [5.5.3] - 2026-09-26
9
+
10
+ 以「消除静默算错地址」为主线的一次修复发布:两个会**读错/写错内存且不报错**的
11
+ 代码生成缺陷,配套文档站独立与 CI 适配。
12
+
13
+ ### 修复 (Fixed)
14
+
15
+ #### 嵌套下标算错基址(静默读写错误内存)
16
+ - **`A[B[i]]` 一类的嵌套下标把外层基址弄丢**。编译器约定是"任何跨子表达式存活
17
+ 的临时值都存栈",但 `_gen_index` 把数组/字符串基址暂存在 `x3` 才去求下标;
18
+ 内层下标自己也要用 `x3` 存基址,于是外层 `ADD` 用的是**内层数组的基址**:
19
+ `A[B[i]]` 被算成 `&B[0]`,读取静默得到错值、赋值静默写到别的变量内存上
20
+ (不越界、不报错)。实测 11 个用例里 10 个算错。
21
+ 现在基址改为入栈(`PUSH`/`POP`),Python 与 Go 两个编译器同步修复。
22
+ - **同类缺陷一并修掉**:`_gen_assign` 把待写入的值放在 `x2` 之后才求左值地址
23
+ (`A[f(i)] = v` 会存错值);`gen_init_2d_literal` 把行指针数组 `x4`、当前行
24
+ `x5` 跨元素表达式存活(`int[][] m = {{g(1), g(2)}, ...}` 元素含函数调用时写错行)。
25
+ 两处均改为求值前入栈。
26
+
27
+ #### 浮点下标被当成字节偏移
28
+ - **`G_C[(lo + hi) / 2]` 抛 `address 379800000000000 out of bounds`**
29
+ (issue #1)。`/` 恒为浮点除法,所以下标类型是 float,而 `_gen_index` 是唯一
30
+ 漏掉"int 上下文隐式截断"的地方:float 的 IEEE-754 位模式被直接当作字节偏移
31
+ 乘 8(249.5 的位模式 × 8 = `0x0379_8000_0000_0000`,正是报告里那个恒定高位
32
+ `0x3798`)。标准 Hoare 快排因此完全无法运行。现在数组与字符串下标都会先按
33
+ 与 `int x = 1.9` 一致的规则向零截断,且截断发生在边界检查之前。
34
+
35
+ ### 变更 (Changed)
36
+
37
+ - **文档站迁至独立仓库** [Code-CIN-Docs](https://github.com/ByUsiStudio/Code-CIN-Docs):
38
+ 本仓库不再内嵌 `docs/` 子模块(`.gitmodules` 不再使用),README 相应改为单独克隆;
39
+ ISA 指令表文档一致性由文档仓库自己保证(`script/gen_isa_docs.py` 保留为生成器)。
40
+ - **CI 适配 Node 20 下线**(GitHub 于 2026-09-23 移除 Node 20 运行时):工作流里
41
+ 全部动作升级到 Node 24 版本 —— `checkout@v6`、`setup-python@v7`、`setup-go@v7`、
42
+ `upload-artifact@v7`、`download-artifact@v7`、`softprops/action-gh-release@v3`。
43
+ - **修复 `release.yml` 的非法工作流**:4 个 checkout 步骤各写了两个 `with:` 键,
44
+ GitHub 会判 `Invalid workflow file`(发布流程此前根本跑不起来)。同时移除所有
45
+ `submodules: recursive` 与已失效的文档一致性检查步骤。
46
+ - **`requirements-dev.txt` 补 `PyYAML`**:`tests/test_workflows.py` 用
47
+ `pytest.importorskip('yaml')`,缺依赖时整块门禁被静默跳过 —— 上面那个重复键
48
+ 错误就是这样漏过 CI 的。该文件现在还会检测**同层重复键**(PyYAML 默认静默
49
+ 后者覆盖前者)。
50
+ - **`.gitignore`/leak-check 排除表**补 `.gotmp`、`.gocache`、`pytest-cache-*`
51
+ (都是记录在案的临时/构建目录);`MANIFEST.in` 去掉已不存在的 `docs/` 条目。
52
+
53
+ ### 测试 (Tests)
54
+ - 新增 `tests/test_nested_subscript_codegen.py`:17 个嵌套下标用例 × 解释器/JIT/
55
+ 原生三条路径,另有"写 `A[B[i]]` 不得触碰 `B` 的内存"用例;回退修复后 52 条中
56
+ 46 条失败。
57
+ - `codecin/native/compiler/compile_test.go` 新增同类 Go 侧用例(编译后直接在
58
+ Go VM 中执行)。
59
+
60
+ ---
61
+
8
62
  ## [5.5.0] - 2026-09-24
9
63
 
10
64
  以「Python 只做 CLI、Go 是唯一实现」为主线的架构收敛,配套标准库打包修复与 AOT 依赖加固。
@@ -7,7 +7,13 @@ recursive-include codecin/lib *.cin
7
7
  recursive-include codecin/native *.go *.txt go.mod go.sum build.sh build.ps1
8
8
  # 注: 不 include 预编译原生库 (*.dll/*.so/*.dylib) —— 它们在用户安装时由
9
9
  # setup.py 现场编译, 见 pyproject.toml 的 package-data 说明。
10
- recursive-include docs *.md
10
+ # 注: 文档站已迁至独立仓库 Code-CIN-Docs, 本仓库不再有 docs/ —— 这里不收
11
+ # docs 内容, 以免本地残留的文档检出 (node_modules 里有大量 *.md) 被误打进 sdist。
12
+ # 注: Go 构建缓存 (AOT 构建器在只读 HOME 下的回退目录) 不属于源码。
13
+ prune codecin/native/.gocache
14
+ # 兜底: 任何本地编译出的预编译库都不得进入 sdist —— 即使 egg-info/SOURCES.txt
15
+ # 里残留了历史条目 (setuptools 会保留已存在文件的旧清单), 这里也强制排除。
16
+ global-exclude *.dll *.so *.dylib
11
17
  recursive-include misc *
12
18
  recursive-include examples *.cin *.asm *.pl
13
19
  recursive-include script *.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codecin
3
- Version: 5.5.0
3
+ Version: 5.5.3
4
4
  Summary: Code CIN - 高级语言与运行时 (CIN/PL/ASM 工具链 + Go 原生 VM + ARM64/RISC-V/FP/Vector 指令集)
5
5
  Author: ByUsi Studio, 北啊呢
6
6
  License-Expression: MIT
@@ -36,12 +36,35 @@ Code CIN 是一门简洁的类 C 高级语言及其跨平台运行时(VM)。
36
36
 
37
37
  ## 文档
38
38
 
39
+ **官方文档站**位于独立仓库
40
+ [Code-CIN-Docs](https://github.com/ByUsiStudio/Code-CIN-Docs) (VitePress +
41
+ vitepress-plugin-tabs); 线上站点即由该仓库构建。本仓库不再内嵌 `docs/`
42
+ (子模块已移除), 需要本地预览时请**单独克隆该仓库**:
43
+
44
+ ```bash
45
+ git clone https://github.com/ByUsiStudio/Code-CIN-Docs.git
46
+ cd Code-CIN-Docs
47
+ npm install
48
+ npm run docs:dev # 本地预览 (http://localhost:5173)
49
+ npm run docs:build # 构建静态站点到 .vitepress/dist
50
+ ```
51
+
52
+ 站点内容划分: `guide/` (安装/快速开始/命令行/执行路径/架构/示例/FAQ)、`language/` (CIN 语言)、
53
+ `asm/` (汇编与 ISA)、`stdlib/` (内置标准库参考)、`runtime/` (原生/JIT/格式/AOT)、
54
+ `tools/` (调试器/远程调试/日志/性能/内存缓存)、`reference/` (ISA 编码表/寄存器与内存/Python API/更新日志)、
55
+ `dev/` (项目结构/构建/测试/打包/扩展/贡献)。
56
+
57
+ 仓库的开发用文档**全部在独立仓库** [Code-CIN-Docs](https://github.com/ByUsiStudio/Code-CIN-Docs)
58
+ (不进站点, 供源码树内直接查阅):
59
+
39
60
  | 文档 | 说明 |
40
61
  |------|------|
41
- | [指令集参考 (ISA)](docs/ISA.md) | 由 `codecin/isa.py` 自动生成的逐条指令表 (唯一真源) |
42
- | [开发者编译文档 (BUILDING)](docs/BUILDING.md) | 环境搭建、Go 原生库编译、构建产物、打包、日志系统、扩展指南 |
43
- | [CIN 编程指南 (CIN_GUIDE)](docs/CIN_GUIDE.md) | CIN 高级语言完整语法:类型/函数/struct/数组/字符串/内建函数 |
44
- | [远程调试协议 (REMOTE_DEBUG)](docs/REMOTE_DEBUG.md) | `--debug-server` 换行文本协议:命令/响应/状态机/示例会话 |
62
+ | [指令集参考 (ISA)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/ISA.md) | 由 `codecin/isa.py` 自动生成的逐条指令表 (唯一真源; 站点版为 `reference/isa.md`) |
63
+ | [开发者编译文档 (BUILDING)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/BUILDING.md) | 环境搭建、Go 原生库编译、构建产物、打包、日志系统、扩展指南 |
64
+ | [CIN 编程指南 (CIN_GUIDE)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/CIN_GUIDE.md) | CIN 高级语言完整语法:类型/函数/struct/数组/字符串/内建函数 |
65
+ | [远程调试协议 (REMOTE_DEBUG)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/REMOTE_DEBUG.md) | `--debug-server` 换行文本协议:命令/响应/状态机/示例会话 |
66
+
67
+ > 这些文件不在本仓库内: 需要时单独 `git clone` 上述文档仓库即可。
45
68
 
46
69
  ---
47
70
 
@@ -229,7 +252,8 @@ pie title Code CIN 指令集组成
229
252
  ```
230
253
 
231
254
  > 指令总数与分组由 `python script/gen_isa_docs.py` 依据 `codecin/isa.py` 自动生成/校验;
232
- > 完整的逐条指令表见 [docs/ISA.md](docs/ISA.md)。ARM64 的 WFE/WFI/SEV 无事件模型, 语义等同 NOP。
255
+ > 完整的逐条指令表见 [ISA.md](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/ISA.md)
256
+ > (文档站已在独立仓库)。ARM64 的 WFE/WFI/SEV 无事件模型, 语义等同 NOP。
233
257
 
234
258
  ### 指令分类
235
259
 
@@ -430,7 +454,6 @@ codecin --version
430
454
 
431
455
  ```bash
432
456
  python -m pytest # 指令黄金 / 三路径一致性 / 断点回归 / 内存保护 / CLI
433
- python script/gen_isa_docs.py --check # docs/ISA.md 与指令集同步
434
457
  python script/gen_native_isa.py --check # Go 原生常量与指令集同步
435
458
  ruff check codecin cpu.py script tests
436
459
  ```
@@ -438,7 +461,8 @@ ruff check codecin cpu.py script tests
438
461
  仓库内置 GitHub Actions CI (`.github/workflows/ci.yml`): 多 Python 版本测试、ruff、Go 构建校验,
439
462
  一个 `integration` 作业会**真实编译原生库**后跑全量测试 (带覆盖率门槛),
440
463
  以及一个 `dist` 作业断言 wheel/sdist 里确实带有内置标准库。
441
- 完整逐条指令表由 `script/gen_isa_docs.py` 从 `codecin/isa.py` 生成至 [docs/ISA.md](docs/ISA.md)。
464
+ 完整逐条指令表由 `script/gen_isa_docs.py` 从 `codecin/isa.py` 生成到文档仓库
465
+ ([ISA.md](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/ISA.md))。
442
466
 
443
467
  ### 执行路径
444
468
 
@@ -817,67 +841,81 @@ function main() {
817
841
 
818
842
  ### 斐波那契 (PL)
819
843
 
820
- ```
844
+ ```asm
821
845
  .text
822
- set x0, 10 // n = 10
823
- call fibonacci
824
- out x0
825
- halt
826
-
827
- fibonacci:
828
- cmp x0, 1
829
- jle base_case
846
+ main:
847
+ set x0, 10 ; n = 10
848
+ call fib
849
+ sys #22 ; ITOA: x0 -> 十进制字符串
850
+ sys #24 ; PRINT_STR
851
+ output #10
852
+ stop
853
+
854
+ fib: ; 入口 x0 = n, 返回 x0 = fib(n)
855
+ compare x0, 1
856
+ jump_greater recurse
857
+ set x0, 1
858
+ return
859
+
860
+ recurse:
830
861
  push x0
831
- sub x0, 1
832
- call fibonacci
862
+ decrement x0
863
+ call fib
833
864
  pop x1
834
865
  push x0
866
+ set x0, x1
867
+ decrement x0
868
+ decrement x0
869
+ call fib
870
+ pop x1
835
871
  add x0, x1
836
- ret
837
-
838
- base_case:
839
- set x0, 1
840
- ret
872
+ return
841
873
  ```
842
874
 
843
- ### 快速排序 (ASM)
875
+ > 注意: 本 ISA **没有 `jle` / `jge`** 这类指令, 比较请用 `CMP` + `JG`/`JL`/`JE`
876
+ > (PL 风格: `compare` + `jump_greater`/`jump_less`/`jump_equal`), 或 ARM64 的 `B.<cond>`。
877
+ > 上面这段实测输出 `89`; 完整语法与逐条语义见文档站 (仓库内路径 `docs/asm/`)。
844
878
 
845
- ```
846
- ; 快速排序实现
879
+ ### 循环求和 + 字符串打印 (ASM, 见 `test_asm.asm`)
880
+
881
+ ```asm
847
882
  .text
848
883
  main:
849
- ldr x0, =array
850
- ldr x1, =size
851
- bl quicksort
852
- halt
853
-
854
- quicksort:
855
- cmp x0, x1
856
- bge done
857
-
858
- ; Partition
859
- ldr x2, [x0] ; pivot
860
- mov x3, x0
861
- mov x4, x1
862
-
863
- partition:
864
- cmp x3, x4
865
- bge swap_pivot
866
-
867
- ldr x5, [x3]
868
- cmp x5, x2
869
- ble swap_left
870
-
871
- ; ... 更多代码
872
-
873
- done:
874
- ret
884
+ MOV x0, #msg
885
+ SYS #24 ; PRINT_STR
886
+
887
+ MOV x1, #0 ; sum
888
+ MOV x2, #1 ; i
889
+ loop:
890
+ ADD x1, x2
891
+ INC x2
892
+ CMP x2, #11
893
+ B.NE loop
894
+
895
+ MOV x0, x1
896
+ SYS #22 ; ITOA -> x0 = 缓冲
897
+ SYS #24 ; PRINT_STR
898
+ OUT #10 ; 换行
899
+
900
+ MOV x3, #nums
901
+ SD x1, [x3] ; 存回数据段
902
+ LD x4, [x3]
903
+ ADDI x4, x4, #100
904
+ MOV x0, x4
905
+ SYS #22
906
+ SYS #24
907
+ OUT #10
908
+
909
+ HALT
875
910
 
876
911
  .data
877
- array: .word 5, 3, 8, 1, 9, 2, 7, 4, 6
878
- size: .word 9
912
+ msg: ASCIZ "Sum 1..10 = "
913
+ nums: DQ 0
879
914
  ```
880
915
 
916
+ > 实测输出: `Sum 1..10 = 55` 与 `155` (退出码 0)。更多汇编示例 (递归、数组遍历、
917
+ > 立即数与表达式、条件后缀) 见文档站 `docs/asm/` 与 `docs/guide/examples.md`。
918
+
881
919
  ---
882
920
 
883
921
  ## 技术栈
@@ -18,12 +18,35 @@ Code CIN 是一门简洁的类 C 高级语言及其跨平台运行时(VM)。
18
18
 
19
19
  ## 文档
20
20
 
21
+ **官方文档站**位于独立仓库
22
+ [Code-CIN-Docs](https://github.com/ByUsiStudio/Code-CIN-Docs) (VitePress +
23
+ vitepress-plugin-tabs); 线上站点即由该仓库构建。本仓库不再内嵌 `docs/`
24
+ (子模块已移除), 需要本地预览时请**单独克隆该仓库**:
25
+
26
+ ```bash
27
+ git clone https://github.com/ByUsiStudio/Code-CIN-Docs.git
28
+ cd Code-CIN-Docs
29
+ npm install
30
+ npm run docs:dev # 本地预览 (http://localhost:5173)
31
+ npm run docs:build # 构建静态站点到 .vitepress/dist
32
+ ```
33
+
34
+ 站点内容划分: `guide/` (安装/快速开始/命令行/执行路径/架构/示例/FAQ)、`language/` (CIN 语言)、
35
+ `asm/` (汇编与 ISA)、`stdlib/` (内置标准库参考)、`runtime/` (原生/JIT/格式/AOT)、
36
+ `tools/` (调试器/远程调试/日志/性能/内存缓存)、`reference/` (ISA 编码表/寄存器与内存/Python API/更新日志)、
37
+ `dev/` (项目结构/构建/测试/打包/扩展/贡献)。
38
+
39
+ 仓库的开发用文档**全部在独立仓库** [Code-CIN-Docs](https://github.com/ByUsiStudio/Code-CIN-Docs)
40
+ (不进站点, 供源码树内直接查阅):
41
+
21
42
  | 文档 | 说明 |
22
43
  |------|------|
23
- | [指令集参考 (ISA)](docs/ISA.md) | 由 `codecin/isa.py` 自动生成的逐条指令表 (唯一真源) |
24
- | [开发者编译文档 (BUILDING)](docs/BUILDING.md) | 环境搭建、Go 原生库编译、构建产物、打包、日志系统、扩展指南 |
25
- | [CIN 编程指南 (CIN_GUIDE)](docs/CIN_GUIDE.md) | CIN 高级语言完整语法:类型/函数/struct/数组/字符串/内建函数 |
26
- | [远程调试协议 (REMOTE_DEBUG)](docs/REMOTE_DEBUG.md) | `--debug-server` 换行文本协议:命令/响应/状态机/示例会话 |
44
+ | [指令集参考 (ISA)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/ISA.md) | 由 `codecin/isa.py` 自动生成的逐条指令表 (唯一真源; 站点版为 `reference/isa.md`) |
45
+ | [开发者编译文档 (BUILDING)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/BUILDING.md) | 环境搭建、Go 原生库编译、构建产物、打包、日志系统、扩展指南 |
46
+ | [CIN 编程指南 (CIN_GUIDE)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/CIN_GUIDE.md) | CIN 高级语言完整语法:类型/函数/struct/数组/字符串/内建函数 |
47
+ | [远程调试协议 (REMOTE_DEBUG)](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/REMOTE_DEBUG.md) | `--debug-server` 换行文本协议:命令/响应/状态机/示例会话 |
48
+
49
+ > 这些文件不在本仓库内: 需要时单独 `git clone` 上述文档仓库即可。
27
50
 
28
51
  ---
29
52
 
@@ -211,7 +234,8 @@ pie title Code CIN 指令集组成
211
234
  ```
212
235
 
213
236
  > 指令总数与分组由 `python script/gen_isa_docs.py` 依据 `codecin/isa.py` 自动生成/校验;
214
- > 完整的逐条指令表见 [docs/ISA.md](docs/ISA.md)。ARM64 的 WFE/WFI/SEV 无事件模型, 语义等同 NOP。
237
+ > 完整的逐条指令表见 [ISA.md](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/ISA.md)
238
+ > (文档站已在独立仓库)。ARM64 的 WFE/WFI/SEV 无事件模型, 语义等同 NOP。
215
239
 
216
240
  ### 指令分类
217
241
 
@@ -412,7 +436,6 @@ codecin --version
412
436
 
413
437
  ```bash
414
438
  python -m pytest # 指令黄金 / 三路径一致性 / 断点回归 / 内存保护 / CLI
415
- python script/gen_isa_docs.py --check # docs/ISA.md 与指令集同步
416
439
  python script/gen_native_isa.py --check # Go 原生常量与指令集同步
417
440
  ruff check codecin cpu.py script tests
418
441
  ```
@@ -420,7 +443,8 @@ ruff check codecin cpu.py script tests
420
443
  仓库内置 GitHub Actions CI (`.github/workflows/ci.yml`): 多 Python 版本测试、ruff、Go 构建校验,
421
444
  一个 `integration` 作业会**真实编译原生库**后跑全量测试 (带覆盖率门槛),
422
445
  以及一个 `dist` 作业断言 wheel/sdist 里确实带有内置标准库。
423
- 完整逐条指令表由 `script/gen_isa_docs.py` 从 `codecin/isa.py` 生成至 [docs/ISA.md](docs/ISA.md)。
446
+ 完整逐条指令表由 `script/gen_isa_docs.py` 从 `codecin/isa.py` 生成到文档仓库
447
+ ([ISA.md](https://github.com/ByUsiStudio/Code-CIN-Docs/blob/main/ISA.md))。
424
448
 
425
449
  ### 执行路径
426
450
 
@@ -799,67 +823,81 @@ function main() {
799
823
 
800
824
  ### 斐波那契 (PL)
801
825
 
802
- ```
826
+ ```asm
803
827
  .text
804
- set x0, 10 // n = 10
805
- call fibonacci
806
- out x0
807
- halt
808
-
809
- fibonacci:
810
- cmp x0, 1
811
- jle base_case
828
+ main:
829
+ set x0, 10 ; n = 10
830
+ call fib
831
+ sys #22 ; ITOA: x0 -> 十进制字符串
832
+ sys #24 ; PRINT_STR
833
+ output #10
834
+ stop
835
+
836
+ fib: ; 入口 x0 = n, 返回 x0 = fib(n)
837
+ compare x0, 1
838
+ jump_greater recurse
839
+ set x0, 1
840
+ return
841
+
842
+ recurse:
812
843
  push x0
813
- sub x0, 1
814
- call fibonacci
844
+ decrement x0
845
+ call fib
815
846
  pop x1
816
847
  push x0
848
+ set x0, x1
849
+ decrement x0
850
+ decrement x0
851
+ call fib
852
+ pop x1
817
853
  add x0, x1
818
- ret
819
-
820
- base_case:
821
- set x0, 1
822
- ret
854
+ return
823
855
  ```
824
856
 
825
- ### 快速排序 (ASM)
857
+ > 注意: 本 ISA **没有 `jle` / `jge`** 这类指令, 比较请用 `CMP` + `JG`/`JL`/`JE`
858
+ > (PL 风格: `compare` + `jump_greater`/`jump_less`/`jump_equal`), 或 ARM64 的 `B.<cond>`。
859
+ > 上面这段实测输出 `89`; 完整语法与逐条语义见文档站 (仓库内路径 `docs/asm/`)。
826
860
 
827
- ```
828
- ; 快速排序实现
861
+ ### 循环求和 + 字符串打印 (ASM, 见 `test_asm.asm`)
862
+
863
+ ```asm
829
864
  .text
830
865
  main:
831
- ldr x0, =array
832
- ldr x1, =size
833
- bl quicksort
834
- halt
835
-
836
- quicksort:
837
- cmp x0, x1
838
- bge done
839
-
840
- ; Partition
841
- ldr x2, [x0] ; pivot
842
- mov x3, x0
843
- mov x4, x1
844
-
845
- partition:
846
- cmp x3, x4
847
- bge swap_pivot
848
-
849
- ldr x5, [x3]
850
- cmp x5, x2
851
- ble swap_left
852
-
853
- ; ... 更多代码
854
-
855
- done:
856
- ret
866
+ MOV x0, #msg
867
+ SYS #24 ; PRINT_STR
868
+
869
+ MOV x1, #0 ; sum
870
+ MOV x2, #1 ; i
871
+ loop:
872
+ ADD x1, x2
873
+ INC x2
874
+ CMP x2, #11
875
+ B.NE loop
876
+
877
+ MOV x0, x1
878
+ SYS #22 ; ITOA -> x0 = 缓冲
879
+ SYS #24 ; PRINT_STR
880
+ OUT #10 ; 换行
881
+
882
+ MOV x3, #nums
883
+ SD x1, [x3] ; 存回数据段
884
+ LD x4, [x3]
885
+ ADDI x4, x4, #100
886
+ MOV x0, x4
887
+ SYS #22
888
+ SYS #24
889
+ OUT #10
890
+
891
+ HALT
857
892
 
858
893
  .data
859
- array: .word 5, 3, 8, 1, 9, 2, 7, 4, 6
860
- size: .word 9
894
+ msg: ASCIZ "Sum 1..10 = "
895
+ nums: DQ 0
861
896
  ```
862
897
 
898
+ > 实测输出: `Sum 1..10 = 55` 与 `155` (退出码 0)。更多汇编示例 (递归、数组遍历、
899
+ > 立即数与表达式、条件后缀) 见文档站 `docs/asm/` 与 `docs/guide/examples.md`。
900
+
863
901
  ---
864
902
 
865
903
  ## 技术栈
@@ -1,4 +1,4 @@
1
- __version__ = "5.5.0"
1
+ __version__ = "5.5.3"
2
2
  __author__ = "ByUsi Studio"
3
3
 
4
4
  from .config import Config
@@ -1664,9 +1664,15 @@ class CodeGen:
1664
1664
  self.emit('ADDI', self.reg(0), self.reg(0), self.imm(i * 8))
1665
1665
  self.emit('SD', self.reg(5), ('mem', 0, 0))
1666
1666
  for j, elem in enumerate(row):
1667
+ # x4 (outer) 与 x5 (当前行) 要跨元素表达式求值存活, 而元素里
1668
+ # 可能有函数调用/嵌套下标 (会覆盖 x1..x6), 因此先存栈。
1669
+ self.emit('PUSH', self.reg(4))
1670
+ self.emit('PUSH', self.reg(5))
1667
1671
  vt = self.gen_value(elem)
1668
1672
  self._convert(vt, 'int')
1669
- self.emit('MOV', self.reg(2), self.reg(0))
1673
+ self.emit('MOV', self.reg(2), self.reg(0)) # x2 = value
1674
+ self.emit('POP', self.reg(5)) # 恢复当前行
1675
+ self.emit('POP', self.reg(4)) # 恢复 outer
1670
1676
  self.emit('MOV', self.reg(0), self.reg(5))
1671
1677
  if j:
1672
1678
  self.emit('ADDI', self.reg(0), self.reg(0), self.imm(j * 8))
@@ -1907,8 +1913,12 @@ class CodeGen:
1907
1913
  if lvalue:
1908
1914
  raise CompilerError(
1909
1915
  "Cannot assign to string element (strings are immutable)")
1910
- self.emit('MOV', self.reg(3), self.reg(0)) # x3 = 字符串基址
1911
- self.gen_value(idx_node) # x0 = index
1916
+ # 基址必须存栈: 下标表达式里可能有嵌套下标/函数调用, 它们会覆盖
1917
+ # x1..x6。s[B[i]] 曾因此把字符串基址弄丢, 读出错误内存。
1918
+ self.emit('PUSH', self.reg(0)) # 保存字符串基址
1919
+ idx_t = self.gen_value(idx_node) # x0 = index
1920
+ self._convert(idx_t, 'int') # 下标是 int 上下文
1921
+ self.emit('POP', self.reg(3)) # x3 = 字符串基址
1912
1922
  self.emit('ADD', self.reg(0), self.reg(3)) # x0 = base + i (字节偏移)
1913
1923
  self.emit('LB', self.reg(0), ('mem', 0, 0)) # 读 1 字节 (符号扩展)
1914
1924
  self.emit('ANDI', self.reg(0), self.reg(0), self.imm(0xFF)) # 0..255
@@ -1918,9 +1928,17 @@ class CodeGen:
1918
1928
  else:
1919
1929
  raise CompilerError(f"Indexing non-array type: {base_t}")
1920
1930
 
1921
- # x0 = base pointer; 计算 elem 地址
1922
- self.emit('MOV', self.reg(3), self.reg(0)) # x3 = base
1923
- self.gen_value(idx_node) # x0 = index
1931
+ # x0 = base pointer; 计算 elem 地址。
1932
+ # 基址必须存栈, 不能用寄存器"暂存": 下标表达式里可能有嵌套下标或函数
1933
+ # 调用, 它们会覆盖 x1..x6。此前 base 放在 x3, 于是 A[B[i]] 的内层下标
1934
+ # 把 x3 改成 B 的基址, 外层 ADD 用 B 的基址当 A 的 —— 读错地址, 写的
1935
+ # 时候直接写坏别的内存 (静默, 不报错)。
1936
+ self.emit('PUSH', self.reg(0)) # 保存 base
1937
+ idx_t = self.gen_value(idx_node) # x0 = index
1938
+ # 下标是 int 上下文 (与赋值/传参/返回一致): float 隐式截断为 int。
1939
+ # 缺这一步时 float 的 IEEE-754 位模式会被当作字节偏移直接乘 8,
1940
+ # 产生 0x0379_8000_0000_0000 之类的高位垃圾地址 (issue #1)。
1941
+ self._convert(idx_t, 'int')
1924
1942
 
1925
1943
  # A1 --bounds-check: 定长数组索引 0 <= i < size
1926
1944
  if self._bounds and _is_fixed_array(base_t):
@@ -1939,6 +1957,7 @@ class CodeGen:
1939
1957
  scale = _type_slots(elem_t) * 8
1940
1958
  self.emit('MOV', self.reg(1), self.imm(scale))
1941
1959
  self.emit('MUL', self.reg(0), self.reg(1)) # x0 = index * scale
1960
+ self.emit('POP', self.reg(3)) # x3 = base (存栈时压入的)
1942
1961
  self.emit('ADD', self.reg(0), self.reg(3)) # x0 = elem 地址
1943
1962
 
1944
1963
  if lvalue:
@@ -1971,8 +1990,10 @@ class CodeGen:
1971
1990
  # 目标类型
1972
1991
  tt = self._expr_type(target)
1973
1992
  self._convert(vt, tt)
1974
- self.emit('MOV', self.reg(2), self.reg(0)) # value
1993
+ # 左值地址求值可能覆盖 x1..x6 (例如 A[f(i)] = v), 值必须存栈。
1994
+ self.emit('PUSH', self.reg(0)) # 保存 value
1975
1995
  self._gen_lvalue_addr(target) # x0 = addr
1996
+ self.emit('POP', self.reg(2)) # x2 = value
1976
1997
  self.emit('SD', self.reg(2), ('mem', 0, 0))
1977
1998
  return tt
1978
1999
 
@@ -1,15 +1,3 @@
1
- // Package aot 提供 AOT 构建: 把 CIN 程序编译成**独立静态可执行文件**。
2
- //
3
- // 产物不依赖 Python、不依赖 Go 工具链、不依赖任何动态库:
4
- // 字节码与初始内存镜像被嵌入二进制, 由内置的 Go VM 执行
5
- // (构建时 CGO_ENABLED=0, 因此 Windows / Linux / macOS 均为静态链接)。
6
- //
7
- // 构建流程 (Build):
8
- // 1. 在 codecin-native 模块内创建临时包目录 .aotbuild-<rand>/
9
- // (Go 工具链会忽略以 '.' 开头的目录, 因此不影响 go build ./...);
10
- // 2. 写入 main.go (由共享模板 stub_main.go.txt 提供) 与两个资源文件;
11
- // 3. CGO_ENABLED=0 + GOOS/GOARCH 交叉编译出目标平台可执行文件;
12
- // 4. 删除临时目录。
13
1
  package aot
14
2
 
15
3
  import (
@@ -21,9 +9,6 @@ import (
21
9
  "codecin-native/engine"
22
10
  )
23
11
 
24
- // StubSource 是生成的 main.go 模板, 与 Python 侧 codecin/aot.py 共用同一份
25
- // 文件 (codecin/native/aot/stub_main.go.txt), 避免两处模板漂移。
26
- //
27
12
  //go:embed stub_main.go.txt
28
13
  var stubSource string
29
14
 
@@ -12,8 +12,6 @@ import (
12
12
  "codecin-native/ir"
13
13
  )
14
14
 
15
- // ---------------- 代码生成 ----------------
16
-
17
15
  // hostBuiltin 宿主能力内建 (表驱动): 名称 -> (SYS 号, 参数个数, 返回类型)。
18
16
  type hostBuiltin struct {
19
17
  sysID int64
@@ -647,9 +645,15 @@ func (c *compiler) genInit2dLiteral(name string, t *Type, lit *Node) {
647
645
  c.emit("ADDI", c.reg(0), c.reg(0), c.imm(int64(i*8)))
648
646
  c.emit("SD", c.reg(5), ir.Mem(0, 0))
649
647
  for j, elem := range row {
648
+ // x4 (outer) 与 x5 (当前行) 要跨元素表达式求值存活, 而元素里
649
+ // 可能有函数调用/嵌套下标 (会覆盖 x1..x6), 因此先存栈。
650
+ c.emit("PUSH", c.reg(4))
651
+ c.emit("PUSH", c.reg(5))
650
652
  vt := c.genValue(elem)
651
653
  c.convert(vt, scalarT(kInt))
652
- c.emit("MOV", c.reg(2), c.reg(0))
654
+ c.emit("MOV", c.reg(2), c.reg(0)) // x2 = value
655
+ c.emit("POP", c.reg(5))
656
+ c.emit("POP", c.reg(4))
653
657
  c.emit("MOV", c.reg(0), c.reg(5))
654
658
  if j != 0 {
655
659
  c.emit("ADDI", c.reg(0), c.reg(0), c.imm(int64(j*8)))
@@ -963,8 +967,12 @@ func (c *compiler) genIndex(baseNode, idxNode *Node, lvalue bool) *Type {
963
967
  c.failf("Cannot assign to string index")
964
968
  return nil
965
969
  }
966
- c.emit("MOV", c.reg(3), c.reg(0))
967
- c.genValue(idxNode)
970
+ // 基址必须存栈: 下标表达式里可能有嵌套下标/函数调用, 它们会覆盖
971
+ // x1..x6。s[B[i]] 曾因此把字符串基址弄丢, 读出错误内存。
972
+ c.emit("PUSH", c.reg(0))
973
+ idxT := c.genValue(idxNode)
974
+ c.convert(idxT, scalarT(kInt)) // 下标是 int 上下文
975
+ c.emit("POP", c.reg(3))
968
976
  c.emit("ADD", c.reg(0), c.reg(3))
969
977
  c.emit("LB", c.reg(0), ir.Mem(0, 0))
970
978
  c.emit("ANDI", c.reg(0), c.reg(0), c.imm(0xFF))
@@ -976,9 +984,16 @@ func (c *compiler) genIndex(baseNode, idxNode *Node, lvalue bool) *Type {
976
984
  }
977
985
  elemT := baseT.Elem
978
986
 
979
- c.emit("MOV", c.reg(3), c.reg(0))
980
- c.genValue(idxNode)
981
-
987
+ // 基址必须存栈, 不能用寄存器"暂存": 下标表达式里可能有嵌套下标或函数
988
+ // 调用, 它们会覆盖 x1..x6。此前 base 放在 x3, 于是 A[B[i]] 的内层下标
989
+ // 把 x3 改成 B 的基址, 外层 ADD 用 B 的基址当 A 的 —— 读错地址, 写的
990
+ // 时候直接写坏别的内存 (静默, 不报错)。
991
+ c.emit("PUSH", c.reg(0))
992
+ idxT := c.genValue(idxNode)
993
+ // 下标是 int 上下文 (与赋值/传参/返回一致): float 隐式截断为 int。
994
+ // 缺这一步时 float 的 IEEE-754 位模式会被当作字节偏移直接乘 8,
995
+ // 产生 0x0379_8000_0000_0000 之类的高位垃圾地址 (issue #1)。
996
+ c.convert(idxT, scalarT(kInt))
982
997
  if c.bounds && isFixedArray(baseT) {
983
998
  size := baseT.Size
984
999
  lGe := c.newLabel("bndok")
@@ -996,6 +1011,7 @@ func (c *compiler) genIndex(baseNode, idxNode *Node, lvalue bool) *Type {
996
1011
  scale := typeSlots(elemT) * 8
997
1012
  c.emit("MOV", c.reg(1), c.imm(int64(scale)))
998
1013
  c.emit("MUL", c.reg(0), c.reg(1))
1014
+ c.emit("POP", c.reg(3)) // x3 = base (存栈时压入的)
999
1015
  c.emit("ADD", c.reg(0), c.reg(3))
1000
1016
 
1001
1017
  if lvalue {
@@ -1026,8 +1042,10 @@ func (c *compiler) genAssign(target, valueNode *Node) *Type {
1026
1042
  vt := c.genValue(valueNode)
1027
1043
  tt := c.exprType(target)
1028
1044
  c.convert(vt, tt)
1029
- c.emit("MOV", c.reg(2), c.reg(0))
1045
+ // 左值地址求值可能覆盖 x1..x6 (例如 A[f(i)] = v), 值必须存栈。
1046
+ c.emit("PUSH", c.reg(0))
1030
1047
  c.genLvalueAddr(target)
1048
+ c.emit("POP", c.reg(2))
1031
1049
  c.emit("SD", c.reg(2), ir.Mem(0, 0))
1032
1050
  return tt
1033
1051
  }