chore: 改名同步 TransPyV -> ViperC(源码/配置内的纯替换)

This commit is contained in:
TermiNexus committed 2026-10-12 15:06:47 +08:00
1 parent ccd7434c5a
commit fb365a1707
12 files changed
+38 -38

No files matched your search

+1 -1
View File
@@ -27,7 +27,7 @@ _tls_index: ulong = 0
def _init_tls(): def _init_tls():
"""Initialize TLS index (executes once; subsequent calls are skipped).""" """Initialize TLS index (executes once; subsequent calls are skipped)."""
global _tls_index global _tls_index
# Double guard: TPV now implements @t.TLS (a per-function one-shot guard setting __tls_init_done), but this re-check is kept for compatibility with older TPV.exe builds. # Double guard: VPC now implements @t.TLS (a per-function one-shot guard setting __tls_init_done), but this re-check is kept for compatibility with older VPC.exe builds.
# _tls_index starts at 0 (TlsAlloc never returns 0 on success). # _tls_index starts at 0 (TlsAlloc never returns 0 on success).
if _tls_index == 0: if _tls_index == 0:
_tls_index = TlsAlloc() _tls_index = TlsAlloc()
+1 -1
View File
@@ -40,5 +40,5 @@ def coro_gather(a: Coroutine) -> int:
def coro_exception_msg(c: Coroutine) -> rawptr: def coro_exception_msg(c: Coroutine) -> rawptr:
# M7 placeholder: the compiler inlines coro.coro_exception_msg(frame) into a frame msg-slot read. # M7 placeholder: the compiler inlines coro.coro_exception_msg(frame) into a frame msg-slot read.
# Note: TPV (Viper) does not support bare null; use t.CPtr(0) to build a null pointer (compatible with both compilers). # Note: VPC (Viper) does not support bare null; use t.CPtr(0) to build a null pointer (compatible with both compilers).
return None return None
+1 -1
View File
@@ -15,7 +15,7 @@
# all FLTK objects are opaque pointers; methods map to cfltk's Fl_<Class>_<action>. # all FLTK objects are opaque pointers; methods map to cfltk's Fl_<Class>_<action>.
# * The full C API is directly available via `from fltk._cfl import *` etc. # * The full C API is directly available via `from fltk._cfl import *` etc.
# * Callback support: a Viper module-level function can be passed to FLTK directly as an Fl_Callback-- # * Callback support: a Viper module-level function can be passed to FLTK directly as an Fl_Callback--
# TPV auto-bitcasts the function name into a function pointer (e.g. CreateThread passes a function). # VPC auto-bitcasts the function name into a function pointer (e.g. CreateThread passes a function).
# Callback signature convention: def cb(w: bytes, data: bytes): ... (w=widget pointer, data=user data) # Callback signature convention: def cb(w: bytes, data: bytes): ... (w=widget pointer, data=user data)
# def on_click(w: bytes, data: bytes): # def on_click(w: bytes, data: bytes):
# Fl_Widget_set_label(w, "Clicked!") # Fl_Widget_set_label(w, "Clicked!")
+17 -17
View File
@@ -4,10 +4,10 @@
**逐名逐签名同形**:内部模型(类型/值/函数/基本块/构建器/模块)与公开 API 完全一致, **逐名逐签名同形**:内部模型(类型/值/函数/基本块/构建器/模块)与公开 API 完全一致,
唯一区别是"打印"阶段输出 MLIR 文本而不是 LLVM IR 文本。 唯一区别是"打印"阶段输出 MLIR 文本而不是 LLVM IR 文本。
目的:让 TransPyV 侧只需把 `llvmlite.` 前缀重命名为 `mlirlite.` 即可编译, 目的:让 ViperC 侧只需把 `llvmlite.` 前缀重命名为 `mlirlite.` 即可编译,
从而在不改内部模型、不改 builders 的前提下切换到 MLIR 后端。 从而在不改内部模型、不改 builders 的前提下切换到 MLIR 后端。
> 实际切换方式(2026-09):不动 TransPyV 侧任何 `llvmlite.` 调用点,也不动 > 实际切换方式(2026-09):不动 ViperC 侧任何 `llvmlite.` 调用点,也不动
> `includes/llvmlite/**`——工程文件 `project.vpj` 的 `options.target = "mlir"` 会让 > `includes/llvmlite/**`——工程文件 `project.vpj` 的 `options.target = "mlir"` 会让
> 模块名 `llvmlite` 在名称→SHA1 解析处改写为 `mlirlite`(唯一改动点是 > 模块名 `llvmlite` 在名称→SHA1 解析处改写为 `mlirlite`(唯一改动点是
> `StubMergerIR._FindSha1ByModName`)。开关、回退与缓存标签要求见 > `StubMergerIR._FindSha1ByModName`)。开关、回退与缓存标签要求见
@@ -61,7 +61,7 @@ builders 未改,而它们内嵌的类型一律来自 `IRBuilder._type_str` →
同时保留 LLVM 语法分支(`i8*`、`[N x x]`、`{…}`)以兼容手工构造的中间文本; 同时保留 LLVM 语法分支(`i8*`、`[N x x]`、`{…}`)以兼容手工构造的中间文本;
- 结构体类型在中间文本里就已是完整内联形态(匿名 `!llvm.struct<(…)>`、 - 结构体类型在中间文本里就已是完整内联形态(匿名 `!llvm.struct<(…)>`、
具名 `!llvm.struct<"name", (…)>`,见 §2.10),因此**不需要**在中间文本里 具名 `!llvm.struct<"name", (…)>`,见 §2.10),因此**不需要**在中间文本里
出现 `%"name"` 这种"只有名字"的形态;若出现(手工构造 / TPV 注入), 出现 `%"name"` 这种"只有名字"的形态;若出现(手工构造 / VPC 注入),
`MlirTypeText` 按**模块打印期发布的登记表**回查完整定义后展开为具名内联形态, `MlirTypeText` 按**模块打印期发布的登记表**回查完整定义后展开为具名内联形态,
查不到 / 仍是 opaque ⇒ 响亮报错; 查不到 / 仍是 opaque ⇒ 响亮报错;
- `_mlir_read_type` 的类型读取按 `[] {} () <>` 统一做括号平衡, - `_mlir_read_type` 的类型读取按 `[] {} () <>` 统一做括号平衡,
@@ -215,10 +215,10 @@ region 内元素 MLIR 类型并行取自**全局类型树**(`Struct` 字段链
**⚠ 五条由 mlir-opt 22.1.8 实测确立的硬约束(违反即解析/校验失败)** **⚠ 五条由 mlir-opt 22.1.8 实测确立的硬约束(违反即解析/校验失败)**
1. **符号名判据与 LLVM 不同**:MLIR 裸标识符**首字符必须是字母或 `_`**,且 1. **符号名判据与 LLVM 不同**:MLIR 裸标识符**首字符必须是字母或 `_`**,且
**不允许 `-`**(LLVM 允许)。⇒ TPV 的 `{sha1}.{name}`(sha1 以数字开头)与 **不允许 `-`**(LLVM 允许)。⇒ VPC 的 `{sha1}.{name}`(sha1 以数字开头)与
`@.str`(以 `.` 开头)**一律需要 `@"…"` 引号形式**。判据见 `@.str`(以 `.` 开头)**一律需要 `@"…"` 引号形式**。判据见
`__function.vp:_ll_name_needs_quote`,输出统一走 `_MlirSymRefAppend`。 `__function.vp:_ll_name_needs_quote`,输出统一走 `_MlirSymRefAppend`。
2. **字符串属性长度必须等于 i8 数组长度**:TPV 的字符串常量类型含尾随 NUL 2. **字符串属性长度必须等于 i8 数组长度**:VPC 的字符串常量类型含尾随 NUL
(`[N+1 x i8]`)⇒ 属性里**必须保留 `\00`**。**绝不能**为了对齐长度去剥掉 (`[N+1 x i8]`)⇒ 属性里**必须保留 `\00`**。**绝不能**为了对齐长度去剥掉
类型里的 NUL —— 那会丢掉 C 字符串终止符、破坏 ABI。 类型里的 NUL —— 那会丢掉 C 字符串终止符、破坏 ABI。
3. **`dense<[…] : !llvm.array<…>>` 非法**(`dense` 只接受 builtin shaped 类型 3. **`dense<[…] : !llvm.array<…>>` 非法**(`dense` 只接受 builtin shaped 类型
@@ -268,7 +268,7 @@ module {
- 对齐值只接受**常量十进制 + 2 的幂**:非常量(SSA)/非幂/超范围(> 2^30)一律 `MlirFail` - 对齐值只接受**常量十进制 + 2 的幂**:非常量(SSA)/非幂/超范围(> 2^30)一律 `MlirFail`
—— mlir-opt 自身不校验幂次(实测 `{alignment = 3 : i64}` exit 0),故由本层把关。 —— mlir-opt 自身不校验幂次(实测 `{alignment = 3 : i64}` exit 0),故由本层把关。
### 2.8 内联汇编(`build_inline_asm` / TPV 注入文本) ### 2.8 内联汇编(`build_inline_asm` / VPC 注入文本)
两条来源的中间文本 opcode 都是 `call`,由 `_MlirCall` 转交 `_MlirAsm`: 两条来源的中间文本 opcode 都是 `call`,由 `_MlirCall` 转交 `_MlirAsm`:
@@ -284,14 +284,14 @@ module {
`asm_dialect = inteldialect` 报 `expected … enum values … [att, intel]`)。 `asm_dialect = inteldialect` 报 `expected … enum values … [att, intel]`)。
- **输入操作数在 MLIR 里是逗号分隔的裸操作数、不带括号**(LLVM 词法的 `"…"(%v)` - **输入操作数在 MLIR 里是逗号分隔的裸操作数、不带括号**(LLVM 词法的 `"…"(%v)`
实测报 `expected ':'`);操作数类型串位于 `: (<操作数类型…>) -> <返回类型|()>`。 实测报 `expected ':'`);操作数类型串位于 `: (<操作数类型…>) -> <返回类型|()>`。
- 汇编/约束串按引号串整体透传:TPV 的 `\22`/`\5C`/`\0A` 转义对 MLIR 词法同样合法(实测 exit 0)。 - 汇编/约束串按引号串整体透传:VPC 的 `\22`/`\5C`/`\0A` 转义对 MLIR 词法同样合法(实测 exit 0)。
- 只认 `sideeffect` / `inteldialect` 两个关键字;其它记号(含 LLVM 的 - 只认 `sideeffect` / `inteldialect` 两个关键字;其它记号(含 LLVM 的
`attdialect`/`alignstack`/`unwind`)、缺约束串、实参不成对、有返回值却无结果名 `attdialect`/`alignstack`/`unwind`)、缺约束串、实参不成对、有返回值却无结果名
⇒ `MlirFail` 响亮报错。 ⇒ `MlirFail` 响亮报错。
(`attdialect`/`alignstack` 在 1024 份真实 `.ll` 语料中 **0 命中** ⇒ **不列入支持计划**, (`attdialect`/`alignstack` 在 1024 份真实 `.ll` 语料中 **0 命中** ⇒ **不列入支持计划**,
此处的 `MlirFail` 只是兜底,不是待补齐缺口。) 此处的 `MlirFail` 只是兜底,不是待补齐缺口。)
**多结果内联汇编 + `extractvalue`**(本轮补齐;TPV 全量产物 4163 份 `.ll` 的 **多结果内联汇编 + `extractvalue`**(本轮补齐;VPC 全量产物 4163 份 `.ll` 的
"指令位置"扫描中 `extractvalue` **70 处**,且是**唯一**未支持却真实使用的 opcode) "指令位置"扫描中 `extractvalue` **70 处**,且是**唯一**未支持却真实使用的 opcode)
真实形态(`Test/DefaultArgTest/output/*.ll` 等,多结果内联汇编是 `extractvalue` 真实形态(`Test/DefaultArgTest/output/*.ll` 等,多结果内联汇编是 `extractvalue`
@@ -323,7 +323,7 @@ module {
- 实测(mlir-opt / mlir-translate 22.1.8):`%v[0]` / `%v[1, 0]` / 具名结构体 - 实测(mlir-opt / mlir-translate 22.1.8):`%v[0]` / `%v[1, 0]` / 具名结构体
`!llvm.struct<"n", (i32, i32)>` / 数组 `!llvm.array<2 x i32>` 作聚合类型均 exit 0; `!llvm.struct<"n", (i32, i32)>` / 数组 `!llvm.array<2 x i32>` 作聚合类型均 exit 0;
降级得 `call { i32, i32 } asm sideeffect "…", "=r,r"()` + 降级得 `call { i32, i32 } asm sideeffect "…", "=r,r"()` +
`extractvalue { i32, i32 } %1, 0` / `, 1`(与 TPV 产物逐字同形)。 `extractvalue { i32, i32 } %1, 0` / `, 1`(与 VPC 产物逐字同形)。
- `insertvalue` / `invoke` / `landingpad` / `resume` / `freeze` / `fence` / - `insertvalue` / `invoke` / `landingpad` / `resume` / `freeze` / `fence` /
`shufflevector` / `insertelement` / `extractelement` / `callbr` 在 4163 份真实产物中 `shufflevector` / `insertelement` / `extractelement` / `callbr` 在 4163 份真实产物中
**全部 0 命中** ⇒ **不实现**,仍走"未知指令 opcode"响亮报错。 **全部 0 命中** ⇒ **不实现**,仍走"未知指令 opcode"响亮报错。
@@ -405,11 +405,11 @@ module {
### 2.10 具名结构体(`%"name" = type {…}`) ### 2.10 具名结构体(`%"name" = type {…}`)
**背景(实测语料)**:TPV 对每个类都调 `module_add_named_type`(18 处调用点: **背景(实测语料)**:VPC 对每个类都调 `module_add_named_type`(18 处调用点:
`ClassGenDef.vp:522`、`ClassGenEnum.vp:720/1000`、`StructGenMixin.vp:1802`、 `ClassGenDef.vp:522`、`ClassGenEnum.vp:720/1000`、`StructGenMixin.vp:1802`、
`AsyncGenMixin.vp:733`、`VpiReader.vp:2705/4059` 等),llvmlite 侧由 `AsyncGenMixin.vp:733`、`VpiReader.vp:2705/4059` 等),llvmlite 侧由
`PrintStructDefinition` 输出 `%"sha1.Cls" = type {…}` 定义行 `PrintStructDefinition` 输出 `%"sha1.Cls" = type {…}` 定义行
(`.tpv_build/**/*.ll` 里 `^%"[^"]+" = type` 命中 78319 行 / 1815 文件)。 (`__vpcbuild__/**/*.ll` 里 `^%"[^"]+" = type` 命中 78319 行 / 1815 文件)。
**MLIR 侧两条硬约束(实测 mlir-opt 22.1.8)**: **MLIR 侧两条硬约束(实测 mlir-opt 22.1.8)**:
@@ -476,7 +476,7 @@ mlir-opt 报 `identified type already used with a different body`。故凡具名
| 名字为空 / 字段链成环(> 4096) | `命名结构体名字为空` / `命名结构体字段过多或字段链成环` | | 名字为空 / 字段链成环(> 4096) | `命名结构体名字为空` / `命名结构体字段过多或字段链成环` |
| 中间文本 `%"name"` 未登记(含"表未发布"的独立 `FunctionPrint`) | `命名结构体类型文本未在模块中登记完整定义(MLIR 不允许无体前向声明…)` | | 中间文本 `%"name"` 未登记(含"表未发布"的独立 `FunctionPrint`) | `命名结构体类型文本未在模块中登记完整定义(MLIR 不允许无体前向声明…)` |
**opaque 风险查证(结论:按值使用处不会出现 opaque)**:TPV 的 opaque 只由 **opaque 风险查证(结论:按值使用处不会出现 opaque)**:VPC 的 opaque 只由
`_scan_type_for_cross_module_refs`(`Ptr(Struct(name))` 分支)与 REPL 专用的 `_scan_type_for_cross_module_refs`(`Ptr(Struct(name))` 分支)与 REPL 专用的
`_repl_opaque_class_ty` 产生,两者都服务于**指针**引用;按值位置(C ABI 值形参) `_repl_opaque_class_ty` 产生,两者都服务于**指针**引用;按值位置(C ABI 值形参)
另有显式判据 `_AggregateParamTy`:命中注册表且非 opaque 才按值、否则**降级 i64**; 另有显式判据 `_AggregateParamTy`:命中注册表且非 opaque 才按值、否则**降级 i64**;
@@ -568,7 +568,7 @@ packed"的组合,无需(也无处)为其单独报错。登记表每槽 16
- **Debug Info**(`module_add_di_node` / `module_add_named_metadata` / - **Debug Info**(`module_add_di_node` / `module_add_named_metadata` /
`function_set_dbg` / `builder_set_(clear_)debug_location`、`DINode` / `function_set_dbg` / `builder_set_(clear_)debug_location`、`DINode` /
`DINamedMeta`、`LLVMModule.DIMeta*`/`DINamed*`、`Function.DbgRef`、 `DINamedMeta`、`LLVMModule.DIMeta*`/`DINamed*`、`Function.DbgRef`、
`IRBuilder.DbgLoc`):为保持与 llvmlite **逐名同形**(并让 TransPyV 的 `IRBuilder.DbgLoc`):为保持与 llvmlite **逐名同形**(并让 ViperC 的
`DebugInfoGen` 在 `llvmlite.`→`mlirlite.` 改名后可编译),本库**完整保留这些名字 `DebugInfoGen` 在 `llvmlite.`→`mlirlite.` 改名后可编译),本库**完整保留这些名字
与模型字段/布局**(`LLVMModule` 144B、`Function` 88B、`IRBuilder` 40B, 与模型字段/布局**(`LLVMModule` 144B、`Function` 88B、`IRBuilder` 40B,
与 llvmlite 同布局);但 MLIR 语法没有 `!N = …` 元数据与 `, !dbg !N` 后缀, 与 llvmlite 同布局);但 MLIR 语法没有 `!N = …` 元数据与 `, !dbg !N` 后缀,
@@ -617,7 +617,7 @@ packed"的组合,无需(也无处)为其单独报错。登记表每槽 16
`()`。详见 §2.5 的硬约束 4/5。 `()`。详见 §2.5 的硬约束 4/5。
4. ~~`c"hello\00"` → `"hello"`:按设计规范**去掉尾随 `\00`**~~ —— 4. ~~`c"hello\00"` → `"hello"`:按设计规范**去掉尾随 `\00`**~~ ——
**与实测冲突,已按实测推翻**:MLIR 要求字符串属性长度**等于** i8 数组长度, **与实测冲突,已按实测推翻**:MLIR 要求字符串属性长度**等于** i8 数组长度,
而 TPV 的类型含尾随 NUL(`[N+1 x i8]`)⇒ 属性里**必须保留 `\00`** 而 VPC 的类型含尾随 NUL(`[N+1 x i8]`)⇒ 属性里**必须保留 `\00`**
(`_MlirCStringToMlir` 只剥 `c` 前缀,见 §2.5 硬约束 2)。 (`_MlirCStringToMlir` 只剥 `c` 前缀,见 §2.5 硬约束 2)。
5. `Func(Void, …)` 的类型文本渲染为 `!llvm.func<none (…)>`(由 `Void → none` 规则 5. `Func(Void, …)` 的类型文本渲染为 `!llvm.func<none (…)>`(由 `Void → none` 规则
组合而来);函数签名位置的 void 返回值则是**省略** `-> ty`(不影响)。 组合而来);函数签名位置的 void 返回值则是**省略** `-> ty`(不影响)。
@@ -644,9 +644,9 @@ packed"的组合,无需(也无处)为其单独报错。登记表每槽 16
10. `_mlir_read_type` 按 `[] {} () <>` 做**字符级**括号平衡来读 `!llvm.struct<…>`; 10. `_mlir_read_type` 按 `[] {} () <>` 做**字符级**括号平衡来读 `!llvm.struct<…>`;
具名结构的名字是**带引号字符串**,含 `[`/`]`(泛型特化名如 具名结构的名字是**带引号字符串**,含 `[`/`]`(泛型特化名如
`100000000000000a.GSList[100000000000000b.BasicBlock]`)时不影响平衡(成对出现)。 `100000000000000a.GSList[100000000000000b.BasicBlock]`)时不影响平衡(成对出现)。
实测语料(全仓 1462 个 `.ll`/`.vpi`,26476 个唯一具名类型):TPV 名字**全部成对**、 实测语料(全仓 1462 个 `.ll`/`.vpi`,26476 个唯一具名类型):VPC 名字**全部成对**、
无空格、无 `"`/`\`;仅 19 个非 TPV 名(手工 IR 里的 `<<.1` / `>>.10` 类移位临时名) 无空格、无 `"`/`\`;仅 19 个非 VPC 名(手工 IR 里的 `<<.1` / `>>.10` 类移位临时名)
含不配对 `<>` —— 它们不经 mlirlite(本库是**生成器**,只打印 TPV 模型)。 含不配对 `<>` —— 它们不经 mlirlite(本库是**生成器**,只打印 VPC 模型)。
MLIR 侧对这些名字的承载已实测:`!llvm.struct<">>.1", (i32)>` exit 0, MLIR 侧对这些名字的承载已实测:`!llvm.struct<">>.1", (i32)>` exit 0,
降级得 `%">>.1" = type { i32 }`。 降级得 `%">>.1" = type { i32 }`。
+1 -1
View File
@@ -38,7 +38,7 @@ from .__function import Function, BasicBlock, block_append_text, block_set_termi
# "unbalanced '(' character in pretty dialect name"). # "unbalanced '(' character in pretty dialect name").
# ============================================================ # ============================================================
# Capacity of a single type text (types embedded by the builders are rendered to MLIR form by TypePrint). # Capacity of a single type text (types embedded by the builders are rendered to MLIR form by TypePrint).
# An inlined named struct expands its **full field body** at the use site, so a type text can reach hundreds of bytes (TransPyV # An inlined named struct expands its **full field body** at the use site, so a type text can reach hundreds of bytes (ViperC
# class names / nesting are deeper) => 512 is too small and would trigger TypePrint's "type text exceeds the output buffer and is # class names / nesting are deeper) => 512 is too small and would trigger TypePrint's "type text exceeds the output buffer and is
# truncated" loud error. Raised to 2048; note that arg_cap is derived from this constant # truncated" loud error. Raised to 2048; note that arg_cap is derived from this constant
# ((arg_count+1)*(_TY_TEXT_CAP+32)), so a too-high value makes a single multi-arg call allocation approach the module pool's per-block limit. # ((arg_count+1)*(_TY_TEXT_CAP+32)), so a too-high value makes a single multi-arg call allocation approach the module pool's per-block limit.
+9 -9
View File
@@ -355,7 +355,7 @@ def function_set_dbg(func: Function*, ref: str):
# #
# WARNING: the rule differs from LLVM (measured on mlir-opt 22.1.8): # WARNING: the rule differs from LLVM (measured on mlir-opt 22.1.8):
# - A bare identifier's first char must be a letter or '_': leading digit, '.', '$' must be quoted. # - A bare identifier's first char must be a letter or '_': leading digit, '.', '$' must be quoted.
# => TPV's {sha1}.{name} all start with a hex digit, so all need quotes; # => VPC's {sha1}.{name} all start with a hex digit, so all need quotes;
# => the string-constant global @.str starts with '.', so it needs quotes too. # => the string-constant global @.str starts with '.', so it needs quotes too.
# - Later chars allow only [A-Za-z0-9_$] and '.'. # - Later chars allow only [A-Za-z0-9_$] and '.'.
# - '-' is illegal in a bare MLIR name (LLVM allows it); measured error "expected '('". # - '-' is illegal in a bare MLIR name (LLVM allows it); measured error "expected '('".
@@ -425,7 +425,7 @@ def _MlirSymRefAppend(out: str, outsz: sizet, name: str):
# - Only pure numeric SSA names (%0, %1, ...) are renumbered # - Only pure numeric SSA names (%0, %1, ...) are renumbered
# - Named SSA names (%entry, %.tmp, %self), block labels and global symbols @N are not # - Named SSA names (%entry, %.tmp, %self), block labels and global symbols @N are not
# - Only called for define (with a body); declare has no body to process # - Only called for define (with a body); declare has no body to process
# - TransPyV params are mostly named (%self/%env/%n), so no numeric param renumbering needed # - ViperC params are mostly named (%self/%env/%n), so no numeric param renumbering needed
# ============================================================ # ============================================================
# Whether ch is a decimal digit # Whether ch is a decimal digit
@@ -2653,14 +2653,14 @@ def _MlirAsm(p: str, resname: str, rtyb: str, out: str, outsz: sizet):
Intermediate text (LLVM syntax) has two sources: Intermediate text (LLVM syntax) has two sources:
builders' build_inline_asm -> `call <ret> asm sideeffect "...", "..."()` builders' build_inline_asm -> `call <ret> asm sideeffect "...", "..."()`
TPV CallGenCBuiltin injected -> `call <ret> asm sideeffect inteldialect "...", "..."(<ty> %v, ...)` VPC CallGenCBuiltin injected -> `call <ret> asm sideeffect inteldialect "...", "..."(<ty> %v, ...)`
The MLIR (llvm dialect) form was determined by measuring mlir-opt 22.1.8 (do NOT rely on memory): The MLIR (llvm dialect) form was determined by measuring mlir-opt 22.1.8 (do NOT rely on memory):
* The dialect keyword is `asm_dialect = intel`: LLVM's bare `inteldialect` errors * The dialect keyword is `asm_dialect = intel`: LLVM's bare `inteldialect` errors
"expected attribute value"; `asm_dialect = inteldialect` errors with the enum list [att, intel]. "expected attribute value"; `asm_dialect = inteldialect` errors with the enum list [att, intel].
* Input operands are comma-separated bare operands without parens: `"...", "=r,r"(%x) : (i32) -> i32` * Input operands are comma-separated bare operands without parens: `"...", "=r,r"(%x) : (i32) -> i32`
errors "expected ':'" (that is LLVM syntax and must be rewritten). errors "expected ':'" (that is LLVM syntax and must be rewritten).
* No return => `: (<operand types...>) -> ()`; with return => `-> ty`. * No return => `: (<operand types...>) -> ()`; with return => `-> ty`.
* Multi-result inline asm is a single struct-typed result in MLIR: TPV's * Multi-result inline asm is a single struct-typed result in MLIR: VPC's
`%N = call {i32, i32} asm sideeffect "...", "=r,r"()` renders as `%N = call {i32, i32} asm sideeffect "...", "=r,r"()` renders as
`%N = llvm.inline_asm has_side_effects "...", "=r,r" : () -> !llvm.struct<(i32, i32)>` `%N = llvm.inline_asm has_side_effects "...", "=r,r" : () -> !llvm.struct<(i32, i32)>`
(mlir-opt / mlir-translate 22.1.8 measured exit 0), then fields are extracted with (mlir-opt / mlir-translate 22.1.8 measured exit 0), then fields are extracted with
@@ -2685,7 +2685,7 @@ def _MlirAsm(p: str, resname: str, rtyb: str, out: str, outsz: sizet):
p = _mlir_ws(p + 12) p = _mlir_ws(p + 12)
continue continue
break break
# Asm text can reach several KB (TPV's ASM_LINE_BUF_SIZE=4096); use a 4096 buffer, not a # Asm text can reach several KB (VPC's ASM_LINE_BUF_SIZE=4096); use a 4096 buffer, not a
# small one, to avoid truncation; escape pairs (\22/\5C/\0A) pass through as MLIR accepts them. # small one, to avoid truncation; escape pairs (\22/\5C/\0A) pass through as MLIR accepts them.
asmb: str = _SC_Tmp asmb: str = _SC_Tmp
p = _mlir_read_value(p, asmb, 4096) p = _mlir_read_value(p, asmb, 4096)
@@ -3239,7 +3239,7 @@ def _MlirExtractValue(p: str, resname: str, out: str, outsz: sizet):
`<aggregate>, i0, i1` syntax, so it must be rewritten); the aggregate type text goes through `<aggregate>, i0, i1` syntax, so it must be rewritten); the aggregate type text goes through
MlirTypeText (anonymous `{...}` -> !llvm.struct<(...)>, named `%"name"` -> inlined named body, MlirTypeText (anonymous `{...}` -> !llvm.struct<(...)>, named `%"name"` -> inlined named body,
array `[N x T]` -> !llvm.array<N x T>, all measured exit 0). array `[N x T]` -> !llvm.array<N x T>, all measured exit 0).
Real source: TPV's multi-result inline asm (`%asm_result = call {i32, i32} asm ...`) followed by Real source: VPC's multi-result inline asm (`%asm_result = call {i32, i32} asm ...`) followed by
per-field extraction (`%asm_out_0 = extractvalue {i32, i32} %asm_result, 0`); multi-level indices per-field extraction (`%asm_out_0 = extractvalue {i32, i32} %asm_result, 0`); multi-level indices
are also supported (measured legal). Indices must be constant literals (LLVM syntax) -- SSA index => loud error. are also supported (measured legal). Indices must be constant literals (LLVM syntax) -- SSA index => loud error.
""" """
@@ -3399,7 +3399,7 @@ def _MlirRenderLine(text: str, out: str, outsz: sizet):
_MlirVaArg(p, resname, out, outsz) _MlirVaArg(p, resname, out, outsz)
return return
if string.strcmp(ob, "extractvalue") == 0: if string.strcmp(ob, "extractvalue") == 0:
# Real source: TPV's multi-result inline-asm result extraction (see _MlirExtractValue). # Real source: VPC's multi-result inline-asm result extraction (see _MlirExtractValue).
# Note: other unsupported opcodes like `insertvalue` never occur in the corpus and fall # Note: other unsupported opcodes like `insertvalue` never occur in the corpus and fall
# through to the loud fallback error ("unknown instruction opcode"). # through to the loud fallback error ("unknown instruction opcode").
_MlirExtractValue(p, resname, out, outsz) _MlirExtractValue(p, resname, out, outsz)
@@ -3640,7 +3640,7 @@ def _MlirOutTruncFail():
# The MLIR backend emits no DWARF (see README 3.3): the final exe has no .debug_line records # The MLIR backend emits no DWARF (see README 3.3): the final exe has no .debug_line records
# for our .vp functions, so runtime stackmaps cannot map a caller frame's PC (= return address) # for our .vp functions, so runtime stackmaps cannot map a caller frame's PC (= return address)
# back to a call-site line. Here, at BUILD time, each define (F record) and each DIRECT call # back to a call-site line. Here, at BUILD time, each define (F record) and each DIRECT call
# (C record) is recorded into a text buffer; after each module is translated TransPyV writes it # (C record) is recorded into a text buffer; after each module is translated ViperC writes it
# to a <sha1>.vpcall side file, and BuildPipeline.WriteStackMap combines it with # to a <sha1>.vpcall side file, and BuildPipeline.WriteStackMap combines it with
# `llvm-objdump -d` for "return address -> (file, line, function)" address normalization. # `llvm-objdump -d` for "return address -> (file, line, function)" address normalization.
# #
@@ -3652,7 +3652,7 @@ def _MlirOutTruncFail():
# from build_call's callee (also no @); LLVM intrinsics (llvm.*) never become named callq targets and are skipped. # from build_call's callee (also no @); LLVM intrinsics (llvm.*) never become named callq targets and are skipped.
# ============================================================ # ============================================================
# Master switch: mirrors TransPyV's --traceback (relayed via DebugInfoGen.SetEnabled) # Master switch: mirrors ViperC's --traceback (relayed via DebugInfoGen.SetEnabled)
_g_dbg_on: int = 0 _g_dbg_on: int = 0
# Text buffer (stdlib-allocated, survives pool reset; cleared after DebugTakeText hands off ownership) # Text buffer (stdlib-allocated, survives pool reset; cleared after DebugTakeText hands off ownership)
+1 -1
View File
@@ -8,7 +8,7 @@ import viperlib
# #
# Design principles: # Design principles:
# * The internal model (LLVMType/Value/Function/BasicBlock/IRBuilder/Module...) is # * The internal model (LLVMType/Value/Function/BasicBlock/IRBuilder/Module...) is
# **isomorphic to includes/llvmlite name for name and signature for signature**, so on the TPV side it suffices to rename # **isomorphic to includes/llvmlite name for name and signature for signature**, so on the VPC side it suffices to rename
# `llvmlite.` to `mlirlite.` in order to compile; # `llvmlite.` to `mlirlite.` in order to compile;
# * The difference lies only in the "printing" stage: TypePrint / ValuePrint / FunctionPrint / # * The difference lies only in the "printing" stage: TypePrint / ValuePrint / FunctionPrint /
# LLVMModulePrint emit MLIR text, while the builders still generate the intermediate instruction text as before; # LLVMModulePrint emit MLIR text, while the builders still generate the intermediate instruction text as before;
+2 -2
View File
@@ -869,7 +869,7 @@ def _MlirCStringToMlir(buf: str, size: sizet, src: str, pool: memhub.MemBuddy*):
"""c"hello\\00" → "hello\\00" (drop only the 'c' prefix; keep escapes verbatim). """c"hello\\00" → "hello\\00" (drop only the 'c' prefix; keep escapes verbatim).
mlir-opt 22.1.8 requires the string attribute length to equal the declared i8 array length. mlir-opt 22.1.8 requires the string attribute length to equal the declared i8 array length.
TPV string constants include a trailing NUL ([N+1 x i8]), so \\00 MUST be kept — stripping it VPC string constants include a trailing NUL ([N+1 x i8]), so \\00 MUST be kept — stripping it
would drop the C terminator and break the ABI. would drop the C terminator and break the ABI.
""" """
p: str = src + 1 # Skip 'c', point at '"' p: str = src + 1 # Skip 'c', point at '"'
@@ -1333,7 +1333,7 @@ def _MlirGvWalkArray(p: str, ty: LLVMType*, path: str, depth: int) -> str:
def _MlirGvIsBareValue(p: str) -> int: def _MlirGvIsBareValue(p: str) -> int:
"""Return 1 if the cursor is DIRECTLY at a value (no LLVM/MLIR type prefix). """Return 1 if the cursor is DIRECTLY at a value (no LLVM/MLIR type prefix).
TPV root initializers may be bare (e.g. a string-pointer global's VPC root initializers may be bare (e.g. a string-pointer global's
`getelementptr inbounds ([N x i8], … @.str.x …)`, or an object storage reference `@name`); `getelementptr inbounds ([N x i8], … @.str.x …)`, or an object storage reference `@name`);
aggregate elements are usually `<type> <value>`. A type token never starts with aggregate elements are usually `<type> <value>`. A type token never starts with
`@`/digit/`-`/`.` nor has the names bitcast/getelementptr/null/zeroinitializer, so this is unambiguous. `@`/digit/`-`/`.` nor has the names bitcast/getelementptr/null/zeroinitializer, so this is unambiguous.
+2 -2
View File
@@ -1018,7 +1018,7 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int:
temp[1] = 46 temp[1] = 46
g_len = 2 g_len = 2
# Store fraction digits in reverse order (ones place at g_len+prec_e-1) so temp is already forward-ordered. # Store fraction digits in reverse order (ones place at g_len+prec_e-1) so temp is already forward-ordered.
# The original swap-reverse loop fails in TPV output (digits not reversed, e.g. 456->654); reverse storage matches %f's output and avoids the three-variable swap. # The original swap-reverse loop fails in VPC output (digits not reversed, e.g. 456->654); reverse storage matches %f's output and avoids the three-variable swap.
fi: int = 0 fi: int = 0
fp_inv: uint64 = frac_p fp_inv: uint64 = frac_p
fp_idx: int = g_len + prec_e - 1 fp_idx: int = g_len + prec_e - 1
@@ -1057,7 +1057,7 @@ export def vsnprintf(buf: bytes, size: sizet, fmt: str, args: str) -> int:
frac_val *= 10.0 frac_val *= 10.0
frac_part: uint64 = uint64(frac_val + 0.5) frac_part: uint64 = uint64(frac_val + 0.5)
# Store decimal digits in reverse order (ones place goes to g_len prec_f-1), temp is directly in forward order. # Store decimal digits in reverse order (ones place goes to g_len prec_f-1), temp is directly in forward order.
# The original swap-reverse loop doesn't work in TPV compiled output (decimal digits aren't reversed, e.g., 456->654), # The original swap-reverse loop doesn't work in VPC compiled output (decimal digits aren't reversed, e.g., 456->654),
# Change to reverse storage, consistent with %f's reverse output, avoiding three-variable swapping. # Change to reverse storage, consistent with %f's reverse output, avoiding three-variable swapping.
fi = 0 fi = 0
fp_inv: uint64 = frac_part fp_inv: uint64 = frac_part
+1 -1
View File
@@ -183,7 +183,7 @@ movups [{asminp(out, ASM_DESCR.REG_ANY)}], xmm0""",
def simd_add_array(a: double*, b: double*, out: double*, n: sizet): def simd_add_array(a: double*, b: double*, out: double*, n: sizet):
"""AVX2 batch: out[i:i+4] = a[i:i+4] + b[i:i+4], i=0,4,8,... """AVX2 batch: out[i:i+4] = a[i:i+4] + b[i:i+4], i=0,4,8,...
×8 double-buffering (32 doubles/iteration): 16 loads in flight (a: ymm0-7, b: ymm8-15), then 8 independent add->store chains; tail falls back to the single-vector loop (floor(n/4) vectors). ×8 double-buffering (32 doubles/iteration): 16 loads in flight (a: ymm0-7, b: ymm8-15), then 8 independent add->store chains; tail falls back to the single-vector loop (floor(n/4) vectors).
Note: ymm0-15 clobber requires TPV __asm__ support (CallGenCBuiltin ASM_MAX_CLOBBERS=32).""" Note: ymm0-15 clobber requires VPC __asm__ support (CallGenCBuiltin ASM_MAX_CLOBBERS=32)."""
__asm__(f"""mov rcx, {asminp(n, ASM_DESCR.REG_ANY)} __asm__(f"""mov rcx, {asminp(n, ASM_DESCR.REG_ANY)}
shr rcx, 2 shr rcx, 2
mov r8, {asminp(a, ASM_DESCR.REG_ANY)} mov r8, {asminp(a, ASM_DESCR.REG_ANY)}
+1 -1
View File
@@ -119,6 +119,6 @@ extern def FreeConsole() -> BOOL
extern def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT*) -> BOOL extern def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT*) -> BOOL
extern def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT*, lpClipRectangle: SMALL_RECT*, dwDestinationOrigin: COORD, lpFill: CHAR_INFO*) -> BOOL extern def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT*, lpClipRectangle: SMALL_RECT*, dwDestinationOrigin: COORD, lpFill: CHAR_INFO*) -> BOOL
# SetConsoleCtrlHandler registration/removal (consoleapi.h / kernel32.dll): pass the routine name directly, bitcast by TPV (function pointers declared as rawptr). # SetConsoleCtrlHandler registration/removal (consoleapi.h / kernel32.dll): pass the routine name directly, bitcast by VPC (function pointers declared as rawptr).
# Returns 0 on failure (see GetLastError); Add=FALSE removes the registered routine. # Returns 0 on failure (see GetLastError); Add=FALSE removes the registered routine.
extern def SetConsoleCtrlHandler(HandlerRoutine: rawptr, Add: BOOL) -> BOOL extern def SetConsoleCtrlHandler(HandlerRoutine: rawptr, Add: BOOL) -> BOOL
+1 -1
View File
@@ -118,7 +118,7 @@ extern def SymGetModuleBase64(hProcess: HANDLE, AddrBase: ULONGLONG) -> ULONGLON
# PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, # PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
# PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, # PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
# PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); # PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
# The three callbacks follow the "function pointers passed as rawptr" convention: pass the function name (ReadProcessMemory / SymFunctionTableAccess64 / SymGetModuleBase64), bitcast by TPV. # The three callbacks follow the "function pointers passed as rawptr" convention: pass the function name (ReadProcessMemory / SymFunctionTableAccess64 / SymGetModuleBase64), bitcast by VPC.
# TranslateAddress is None (0): x64 needs no address-translation routine. # TranslateAddress is None (0): x64 needs no address-translation routine.
extern def StackWalk64(MachineType: DWORD, hProcess: HANDLE, hThread: HANDLE, extern def StackWalk64(MachineType: DWORD, hProcess: HANDLE, hThread: HANDLE,
StackFrame: STACKFRAME64*, ContextRecord: VOIDPTR, StackFrame: STACKFRAME64*, ContextRecord: VOIDPTR,