From 762b3ceed4844f95ffb400a9fb1d7394fc390a53 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 1 Oct 2026 23:00:30 +0800 Subject: [PATCH] =?UTF-8?q?docs(wiki):=20=E5=85=A8=E7=AB=99=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E7=BB=9F=E4=B8=80=E4=B8=BA=E7=9F=AD=E5=90=8D=E5=88=AB?= =?UTF-8?q?=E5=90=8D=E3=80=81T*=20=E6=8C=87=E9=92=88=E4=B8=8E=20&/*=20?= =?UTF-8?q?=E7=AE=97=E5=AD=90=E7=AD=89=E6=96=B0=E8=AF=AD=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 02-type-system.md | 20 ++++--- 03-variables.md | 2 +- 08-c-operations.md | 14 ++--- 10-imports.md | 6 +- 11-builtins.md | 2 +- 12-project.md | 2 +- 14-oo-refactor.md | 4 +- README.MD | 139 +++++++++++++++++++++++---------------------- 8 files changed, 97 insertions(+), 92 deletions(-) diff --git a/02-type-system.md b/02-type-system.md index 860871f..9e49091 100644 --- a/02-type-system.md +++ b/02-type-system.md @@ -445,21 +445,23 @@ HANDLE CreateFileA(LPCSTR, ULONG, ULONG, SECURITY_ATTRIBUTES*, ULONG, ULONG, HAN ## 数组类型 -固定大小数组使用 `t.CArray[ElemType, Size]`(= `rawarray`)表示(通常用于栈上和 BSS 段上)。`Size` 可为模块级 `t.CDefine` 常量或常量表达式(如 `2*MAX`);单参 `t.CArray[Elem]` 表示静态推导长度数组(退化为 `Ptr(Elem)`);也支持多维嵌套。 +固定大小数组**推荐用前缀写法 `[N]T`**(等价 `t.CArray[T, N]` = `rawarray`,软关键字形态 `array[T, N]`)(通常用于栈上和 BSS 段上)。`N` 可为模块级 `define` 常量或常量表达式(如 `2*MAX`);省略 `N`(`[]T`)表示静态推导长度数组(退化为 `T*`);也支持多维嵌套。 -- 内建软关键字 `array[Elem, N]`(仅在类型 / 注解位置生效)与 `t.CArray[Elem, N]` 等价;裸用 `array`(无下标)、缺参 / 多参、长度非正整数常量都会 fail-fast。 +- 裸用 `array`(无下标)、缺参 / 多参、长度非正整数常量都会 fail-fast。 - **`list[T, N]` 的双参数形态是同义的定长数组写法**(第 2 实参是元素个数,编译期正整数常量);`list[T]` 单参才是泛型容器特化。因此 `list[Elem, N]` 仍是合法的定长数组,并非“旧写法”。 ```python -buf: t.CArray[t.CChar, 64] # char buf[64] -ids: t.CArray[t.CInt, 10] # int ids[10] -matrix: t.CArray[t.CFloat, 16] # float matrix[16] -entries: t.CArray[idt_entry, 256] # struct idt_entry entries[256]; -s: t.CArray[t.CChar] = [0x68, 0x69] # char s[] = {0x68, 0x69}; 由列表字面量推断长度 2 -grid: t.CArray[t.CArray[t.CFloat, 4], 8] # float grid[8][4]; 多维嵌套 -seg: t.CArray[t.CChar, BUF_SIZE] # char seg[BUF_SIZE]; Size 可为模块级 t.CDefine 常量 +buf: [64]char # char buf[64] +ids: [10]int # int ids[10] +matrix: [16]float # float matrix[16] +entries: [256]idt_entry # struct idt_entry entries[256]; +s: []char = [0x68, 0x69] # char s[] = {0x68, 0x69}; 由列表字面量推断长度 2 +grid: [8][4]float # float grid[8][4]; 多维嵌套 +seg: [BUF_SIZE]char # char seg[BUF_SIZE]; N 可为模块级 define 常量 ``` +> 旧写法 `t.CArray[t.CChar, 64]` / `array[char, 64]` 与 `[64]char` 完全等价,手写可用但不推荐。 + 等价 C 代码: ```c char buf[64]; diff --git a/03-variables.md b/03-variables.md index d08cde0..4bb6d69 100644 --- a/03-variables.md +++ b/03-variables.md @@ -129,7 +129,7 @@ y: t.CStatic | t.CInt = 0 # 等价链式标记写法 ```python extern errno: int # extern int errno;(前置软关键字,推荐) -fd: t.CExtern | t.CInt # 等价链式标记写法 +fd: t.CExtern | int # 等价链式标记写法(内部标记) ``` 模块级 `extern` 全局生成 `@裸名 = external global T`(external linkage、无初始值、无 storage),符号由外部(C 库 / 汇编 / 其它翻译单元)提供;**不允许带初始值**。 diff --git a/08-c-operations.md b/08-c-operations.md index 71eadb8..6dbc73c 100644 --- a/08-c-operations.md +++ b/08-c-operations.md @@ -72,7 +72,7 @@ __asm__("nop") # __asm__ __volatile__("nop"); 使用 f-string 和 `asmout` / `asminp` 标记操作数: ```python -saved_rdi: t.CUnsignedLong +saved_rdi: ulong __asm__(f"mov {asmout(saved_rdi, ASM_DESCR.OUTPUT_REG)}, rdi", op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RDI]) ``` @@ -264,9 +264,9 @@ Viper 的 FFI(Foreign Function Interface)通过 `extern` / `export` 关键 `extern def` 仅声明(函数体为 `pass`);`export def` 以裸名导出: ```python -extern def isr0() -> t.CVoid: pass # extern void isr0(); — 来自汇编或外部 -extern def getchar() -> t.CInt: pass # extern int getchar(); — 来自 libc -export def foo() -> t.CInt: pass # export int foo(); — 裸名导出(define) +extern def isr0() -> void: pass # extern void isr0(); — 来自汇编或外部 +extern def getchar() -> int: pass # extern int getchar(); — 来自 libc +export def foo() -> int: pass # export int foo(); — 裸名导出(define) ``` 编译为 LLVM IR: @@ -284,7 +284,7 @@ define i32 @"foo"() { ... } ; export:不加 SHA1 前缀,裸名 define ```python extern def CreateFileA(lpFileName: LPCSTR, dwDesiredAccess: ULONG, dwShareMode: ULONG, - lpSecurityAttributes: SECURITY_ATTRIBUTES | t.CPtr, + lpSecurityAttributes: SECURITY_ATTRIBUTES*, dwCreationDisposition: ULONG, dwFlagsAndAttributes: ULONG, hTemplateFile: HANDLE) -> HANDLE: @@ -317,8 +317,8 @@ HANDLE CreateFileA(LPCSTR, ULONG, ULONG, SECURITY_ATTRIBUTES*, 外部全局变量用 `extern` 软关键字声明(推荐),或等价的 `t.CExtern` 标记: ```python -extern errno: t.CInt # extern int errno;(推荐) -fd: t.CExtern | t.CInt # 等价写法 +extern errno: int # extern int errno;(推荐) +fd: t.CExtern | int # 等价写法(内部标记) ``` 模块级 `extern` 全局生成 `@裸名 = external global T`(external linkage、无初始值、无 storage),符号由外部单元提供。 diff --git a/10-imports.md b/10-imports.md index 68335cd..9791cb6 100644 --- a/10-imports.md +++ b/10-imports.md @@ -72,12 +72,12 @@ asm.BSSClean() # 清零 BSS 段 ### `string` 模块 字符串/内存操作模块,对应 C 标准库的 `string.h`: -> 确认:string 模块确实使用 Viper `c.Asm` 内联汇编进行加速(`memset`/`memcpy`/`memmove` 等,见 [includes/string.vp](../includes/string.vp))。因使用 x86_64 专有汇编,某些函数在其它架构可能需要手动重新编写。 +> 确认:string 模块确实使用 Viper `__asm__` 内联汇编进行加速(`memset`/`memcpy`/`memmove` 等,见 [includes/string.vp](../includes/string.vp))。因使用 x86_64 专有汇编,某些函数在其它架构可能需要手动重新编写。 ```python import string -string.memset(c.Addr(buf), 0, 64) # memset(&buf, 0, 64); +string.memset(&buf, 0, 64) # memset(&buf, 0, 64); string.memcpy(dst, src, size) # memcpy(dst, src, size); string.memmove(dst, src, size) # memmove(dst, src, size); string.memcmp(a, b, size) # memcmp(a, b, size); @@ -105,7 +105,7 @@ ViperOS 标准库,提供常用 C 库函数: ```python import viperlib -viperlib.snprintf(c.Addr(buf), 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42); +viperlib.snprintf(&buf, 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42); ``` ### `vpsdk` 模块 diff --git a/11-builtins.md b/11-builtins.md index a26a5ff..225e072 100644 --- a/11-builtins.md +++ b/11-builtins.md @@ -48,7 +48,7 @@ b: bool = bool(x) # x != 0 ### min / max / chr / ord -> **实现说明**:min/max/chr/ord 定义于 `includes/builtins.vp`(`ord`: `t.CChar`→`int`;`chr`: `int`→`t.CChar`;`min`/`max`: `double` 参数,`int`/`float` 实参无损提升,返回按调用侧目标类型 coerce),编译器自动关联 builtins 模块,无需显式 import。 +> **实现说明**:min/max/chr/ord 定义于 `includes/builtins.vp`(`ord`: `char`→`int`;`chr`: `int`→`char`;`min`/`max`: `double` 参数,`int`/`float` 实参无损提升,返回按调用侧目标类型 coerce),编译器自动关联 builtins 模块,无需显式 import。 ```python m: int = min(a, b) # min(a, b)(builtins.vp,double 参数,返回按目标类型 coerce) diff --git a/12-project.md b/12-project.md index fc18a82..70c1498 100644 --- a/12-project.md +++ b/12-project.md @@ -290,7 +290,7 @@ TransPyC 支持基于 SHA1 的增量编译,与两阶段编译模型紧密耦 ### SHA1 命名空间与增量编译的协同 SHA1 同时服务于命名空间隔离和增量编译: -- **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突 +- **命名空间**:未 `export` 的函数(内部非 `t.CExport`)和结构体使用 SHA1 前缀,消除符号冲突 - **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成 详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。 diff --git a/14-oo-refactor.md b/14-oo-refactor.md index 2b9298b..4ab65ad 100644 --- a/14-oo-refactor.md +++ b/14-oo-refactor.md @@ -51,7 +51,7 @@ TPV 编译器当前是"**数据对象 + 行为函数式**"架构: 1. `novirtual` + 硬编码 SIZE(`BUILDER_SIZE=32`/`pool.alloc(96)`)强耦合——**方法化不改布局则无影响**;若转 `virtual` 需全量重写 2. 16 个跨模块 stub 访问器(`value_get_ty`/`paramnode_get_ty`…)是规避 TransPyC stub 限制的产物——方法化后可逐步消除(**依赖编译器缺陷修复,非本方案范围**) -3. `LLVMType` 的 `pool.alloc(__sizeof__)` + `c.DerefAs` 构造模式——保留为构造方法 +3. `LLVMType` 的 `pool.alloc(__sizeof__)` + `*p = v`(旧 `c.DerefAs`)构造模式——保留为构造方法 ## 3. 目标架构 @@ -188,7 +188,7 @@ self.visit_call(node) # 内部用 self.Pool/self.Builder/self.Module/se | 方法簇 | 对应分支 | |---|---| | `_call_generic_ctor(node)` | 泛型类构造 `list[int](pool, n)` | -| `_call_binop_cast(node)` | `(A|t.CPtr)(val)` BinOp 强转 | +| `_call_binop_cast(node)` | `(A|t.CPtr)(val)` / 新写法 `T*(val)` BinOp 强转 | | `_call_c_special(node)` | `c.Deref/Addr/Set/Load/Asm/LLVMIR/CIf/CIfdef` 系列 | | `_call_stdarg(node)` | `va_arg/arg/va_start/va_end` | | `_call_builtin_cast(node)` | `str/bytes/int/bool(x)` | diff --git a/README.MD b/README.MD index 22eaed8..27f4932 100644 --- a/README.MD +++ b/README.MD @@ -99,15 +99,15 @@ sha1 = hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] | 源文件元素 | 存根文件中的表示 | |-----------|----------------| -| `t.CDefine` 常量 | 保留原样(含赋值):`MAX_SIZE: t.CDefine = 1024` | -| `t.CDefine` 函数(返回 `t.CDefine` 的函数) | 保留完整函数体(宏展开需要) | -| 普通函数 | 仅保留签名(不添加 `c.State`):`def foo(x: t.CInt) -> t.CVoid: pass` | -| 类定义 | 保留成员类型注解和方法签名 | -| 全局变量 | TPC 一代 `PythonToStubConverter` 会添加 `t.CExtern`(`x: t.CExtern | t.CInt`);TPV 自研 `StubGen`/`Converter.vp` 不再添加——跨模块 `external declare` 由 `VpiReader` 依 vpi 全局自动注入 | -| `c.CIfdef`/`c.CEndif()` 等预处理指令 | 保留原样 | +| `define` 常量(旧写法 `t.CDefine`) | 保留原样(含赋值):`define MAX_SIZE = 1024` | +| 宏函数(`define F(...)`,或返回 `t.CDefine`) | 保留完整函数体(宏展开需要) | +| 普通函数 | 仅保留签名:`def foo(x: int) -> void: pass` | +| 类 / `struct` 定义 | 保留成员类型注解和方法签名 | +| 全局变量 | TPC 一代 `PythonToStubConverter` 会添加 `t.CExtern`(`extern x: int` 的旧标记形态);TPV 自研 `StubGen`/`Converter.vp` 不再添加——跨模块 `external declare` 由 `VpiReader` 依 vpi 全局自动注入 | +| `c.CIfdef` 等预处理指令 | 保留原样 | | `import` 语句 | 保留原样 | -**关键设计**:`t.CDefine` 常量和 `t.CDefine` 函数在存根中**保留完整定义**(包括赋值和函数体),因为它们是编译时常量/宏,其他模块引用时需要完整展开。普通函数只保留签名、不添加 `c.State`(仅声明),因为函数体在阶段二生成。 +**关键设计**:`define` 常量与宏函数在存根中**保留完整定义**(包括赋值和函数体),因为它们是编译时常量/宏,其他模块引用时需要完整展开。普通函数只保留签名(仅声明),因为函数体在阶段二生成。 #### 步骤 3:构建结构体注册表 @@ -128,12 +128,12 @@ sha1 = hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] | 元素 | 生成的 LLVM IR | |------|---------------| -| 普通函数 | `declare void @".foo"(i32)` — 非 CExport 函数加 SHA1 前缀 | -| CExport 函数 | `declare i32 @main()` — CExport 函数不加前缀,全局可见 | +| 普通函数 | `declare void @".foo"(i32)` — 未 `export` 的函数加 SHA1 前缀 | +| `export` 函数(内部 `t.CExport`) | `declare i32 @main()` — 不加前缀,全局可见 | | 结构体 | `%".ClassName" = type { i32, i32* }` — 类型名加 SHA1 前缀 | | 全局变量 | `@varname = external global i32` | -| `t.CDefine` 常量 | **不生成声明**(编译时常量,直接内联展开) | -| `t.CTypedef` 别名 | **不生成声明**(类型别名,在类型解析时展开) | +| `define` 常量(内部 `t.CDefine`) | **不生成声明**(编译时常量,直接内联展开) | +| `typedef` 别名(内部 `t.CTypedef`) | **不生成声明**(类型别名,在类型解析时展开) | | 枚举 | 仅旧 Python `DeclarationGenerator` 行为:为每个枚举成员生成 `@__config_EnumName_member = external global i32`;现枚举由 `ClassGenEnum` 注册为编译期常量,不再生成 | **增量编译**:如果 `.vpi` 或 `.stub.ll` 已存在,则跳过生成(缓存命中)。只有源文件内容变化导致 SHA1 变化时才重新生成。 @@ -155,7 +155,7 @@ sha1 = hashlib.sha1(content.encode('utf-8')).hexdigest()[:16] #### 步骤 3:收集内联函数符号 -扫描 `includes/` 目录中被引用的模块,收集标记为 `t.CInline` 的函数。内联函数的完整 AST body 被保存,在翻译调用点时直接展开。值得注意的是,和 C 语言不同,`t.CInline` 不是优化建议,而是强制性的。 +扫描 `includes/` 目录中被引用的模块,收集标记为内联的函数(旧标记 `t.CInline`)。内联函数的完整 AST body 被保存,在翻译调用点时直接展开。值得注意的是,和 C 语言不同,这种前端内联不是优化建议,而是强制性的。 > 注:上述 `_collect_inline_symbols` 预收集机制属 TPC Python 侧实现;TransPyV 无对应实现——`t.CInline` 仅作为存储类标记,实际内联经 `@c.Attribute(t.attr.always_inline())`。 @@ -186,12 +186,12 @@ Viper 使用源文件内容的 SHA1 哈希作为命名空间前缀: ``` 源文件 A.vp(SHA1 = a1b2c3d4e5f6g7h8)中定义: - class Point: x: t.CInt; y: t.CInt - def draw(p: Point) -> t.CVoid: ... + struct Point: x: int; y: int + def draw(p: Point*) -> void: ... 源文件 B.vp(SHA1 = i9j0k1l2m3n4o5p6)中也定义: - class Point: x: t.CFloat; y: t.CFloat # 不同的结构体! - def draw(p: Point) -> t.CVoid: ... + struct Point: x: float; y: float # 不同的结构体! + def draw(p: Point*) -> void: ... 编译后: A.vp 的结构体 → %"a1b2c3d4e5f6g7h8.Point" = type { i32, i32 } @@ -203,13 +203,13 @@ Viper 使用源文件内容的 SHA1 哈希作为命名空间前缀: **没有符号冲突**——即使两个模块定义了同名类型和函数,它们的 LLVM IR 符号也是不同的。即便有两个内容完全相同的文件也不会冲突,他们会被识别为同一个文件,然后进行单次编译。 -### SHA1 前缀的豁免:`t.CExport` +### SHA1 前缀的豁免:`export` -标记为 `t.CExport` 的函数**不加 SHA1 前缀**,保持原始函数名。这是模块向外部暴露 API/ABI 的机制: +用 `export` 声明的函数(内部标记 `t.CExport`)**不加 SHA1 前缀**,保持原始函数名。这是模块向外部暴露 API/ABI 的机制: ```python # main.vp — 入口函数,必须全局可见 -def main() -> t.CInt | t.CExport: +export def main() -> int: return 0 # 编译后:define i32 @main() — 无 SHA1 前缀 @@ -217,7 +217,7 @@ def main() -> t.CInt | t.CExport: ```python # serial.vp — 驱动接口,对外暴露 -def init() -> t.CVoid | t.CExport: +export def init() -> void: serial_puts("init\n") # 编译后:define void @init() — 无 SHA1 前缀,其他模块可直接调用 @@ -232,111 +232,114 @@ SHA1 同时服务于增量编译: 理论上,如果一个未经变动的模块的依赖路径上存在变动的模块,暂时的方法是将其简单做 SHA1 替换,暨将旧 SHA1 替换为新 SHA1,但不适用于签名改变的情况,不过签名改变这个未经变动的模块必然也需要改变,但是由于宏展开的存在,不能完全保证不会发生错误情况。且依赖路径的 SHA1 替换成功性未经完整测试,可能出现未定义行为。 -## `t.CDefine` 深度解析 +## 编译期常量与宏(`define` / `t.CDefine`)深度解析 -`t.CDefine` 是 Viper 中最特殊的类型——它不是数据类型,而是**编译时元指令**,控制编译器的代码生成行为。 +`t.CDefine` 是编译时元指令(**推荐用软关键字 `define` 书写**),控制编译器的代码生成行为——它不是真实的数据类型。 -### `t.CDefine` 常量 +### `define` 常量 ```python -MAX_SIZE: t.CDefine = 1024 -PAGE_SIZE: t.CDefine = 4096 -FA_READ: t.CDefine = 0x01 -CPU_FEATURE_FPU: t.CDefine = (1 << 0) +define MAX_SIZE = 1024 +define PAGE_SIZE = 4096 +define FA_READ = 0x01 +define CPU_FEATURE_FPU = (1 << 0) ``` +> 推荐写法是软关键字 `define X = v`(等价旧写法 `X: t.CDefine = v`)。 + **编译行为**: -1. **阶段一**:存根生成器保留 `t.CDefine` 常量的完整定义(包括赋值值),因为其他模块可能引用此常量 -2. **阶段一**:`.stub.ll` 声明生成器**跳过** `t.CDefine` 常量,不生成 `external global` 声明 -3. **阶段二**:翻译器遇到 `t.CDefine` 常量的引用时,直接内联其值,不生成任何加载指令 +1. **阶段一**:存根生成器保留 CDefine 常量的完整定义(包括赋值值),因为其他模块可能引用此常量 +2. **阶段一**:`.stub.ll` 声明生成器**跳过** CDefine 常量,不生成 `external global` 声明 +3. **阶段二**:翻译器遇到 CDefine 常量的引用时,直接内联其值,不生成任何加载指令 -这意味着 `t.CDefine` 常量在 LLVM IR 层面**不存在**——它们在编译时被完全展开,等价于 C 的 `#define` 宏。 +这意味着 CDefine 常量在 LLVM IR 层面**不存在**——它们在编译时被完全展开,等价于 C 的 `#define` 宏。 -### `t.CDefine` 函数 +### 宏函数(`define F(...)`) -当函数的返回类型注解包含 `t.CDefine` 时,该函数被编译器视为**宏函数**: +当函数用 `define F(...)` 声明(或返回类型注解含 `t.CDefine`)时,被编译器视为**宏函数**: ```python -def MAKE_FLAG(bit) -> t.CDefine: +define MAKE_FLAG(bit): return (1 << bit) -def GET_PAGE_ORDER(size) -> t.CDefine: +define GET_PAGE_ORDER(size): return size // PAGE_SIZE ``` +> `define F(...)` 会自动追加 `t.CDefine` 返回注解;等价旧写法 `def F(...) -> t.CDefine:`。注意与 `define X = v`(常量)区分:带 `(` 是宏函数、带 `=` 是常量。 + **编译行为**: -1. **阶段一**:存根生成器保留 `t.CDefine` 函数的**完整函数体**(不像普通函数那样只保留签名) -2. **阶段二**:翻译器遇到 `t.CDefine` 函数的调用时,将调用内联展开为函数体的计算结果 +1. **阶段一**:存根生成器保留宏函数的**完整函数体**(不像普通函数那样只保留签名) +2. **阶段二**:翻译器遇到宏函数的调用时,将调用内联展开为函数体的计算结果 -`t.CDefine` 函数在 LLVM IR 中**不生成函数定义**——它们是纯粹的编译时宏。 +宏函数在 LLVM IR 中**不生成函数定义**——它们是纯粹的编译时宏。 -### `t.CDefine` 与类型组合 +### `define X: T = v` 与类型组合 -`t.CDefine` 可以与具体类型组合使用,为常量指定底层类型: +`define` 可以带类型注解,为常量指定底层类型(内部等价于把 `t.CDefine` 与具体类型组合): ```python -CODE_SEG: t.CDefine | t.CUInt16T = 0x08 -DATA_SEG: t.CDefine | t.CUInt16T = 0x10 +define CODE_SEG: uint16 = 0x08 +define DATA_SEG: uint16 = 0x10 ``` -这表示常量在类型检查时被视为 `t.CUInt16T`(`uint16_t`),但在代码生成时仍然内联展开。 +这表示常量在类型检查时被视为 `uint16`(`uint16_t`),但在代码生成时仍然内联展开。 -## `t.CExport` 深度解析 +> 旧写法 `CODE_SEG: t.CDefine | t.CUInt16T = 0x08` 等价,手写可用但不推荐。 -`t.CExport` 控制函数的符号可见性,是 SHA1 命名空间的豁免机制。 +## `export` 深度解析(内部标记 `t.CExport`) + +`export` 软关键字控制函数的符号可见性,是 SHA1 命名空间的豁免机制(内部改写为返回注解中的 `t.CExport` 标记)。 ### 语义 -| 修饰 | LLVM IR 函数名 | 链接可见性 | 用途 | +| 写法 | LLVM IR 函数名 | 链接可见性 | 用途 | |------|---------------|-----------|------| | 无修饰 | `@.funcname` | 模块内部 | 模块私有函数 | -| `t.CExport` | `@funcname` | 全局可见 | 对外暴露的 API | -| `t.CExtern` | `@funcname`(仅声明) | 外部定义 | 引用外部函数 | +| `export def f(...)` | `@funcname` | 全局可见 | 对外暴露的 API | +| `extern def f(...)` | `@funcname`(仅声明) | 外部定义 | 引用外部函数 | + +> 手写等价形态:`def f(...) -> T | t.CExport`(导出)、`def f(...) -> T | t.State`(外部声明)。 ### 使用场景 ```python # 入口函数 — 必须全局可见,链接器需要找到它 -def _start() -> t.CInt | t.CExport: +export def _start() -> int: return kernel_main() # 驱动接口 — 其他模块/应用需要调用 -def init() -> t.CVoid | t.CExport: +export def init() -> void: uart_init() # 内部辅助函数 — 不需要全局可见,自动加 SHA1 前缀 -def _helper() -> t.CInt: +def _helper() -> int: return 42 ``` -### `t.CExport` 在存根中的表现 +### `export` 在存根中的表现 -在 `.vpi` 存根文件中,`t.CExport` 函数与普通函数一样只保留签名(不添加 `c.State`,表示单纯声明),但 `t.CExport` 标记被保留在返回类型注解中。阶段一的 `DeclarationGenerator` 检查 `t.CExport` 标记来决定是否添加 SHA1 前缀。 +在 `.vpi` 存根文件中,`export` 函数与普通函数一样只保留签名(不添加 `extern` 存储类,表示单纯声明),但内部 `t.CExport` 标记被保留在返回类型注解中。阶段一的 `DeclarationGenerator` 检查该标记来决定是否添加 SHA1 前缀。 -## `t.CInline` 深度解析 +## `inline` 深度解析(旧标记 `t.CInline`) -`t.CInline` 标记函数为内联函数,编译器在调用点直接展开函数体。 - -### 语义 +推荐写法是 **`inline` 软关键字**:`inline def f(...)` 等价于给函数加 `@t.attr.always_inline`(LLVM `alwaysinline`)——这是**编译期提示落到 IR 函数属性**,由 LLVM 决定实际内联,**不是**“调用点展开”。 ```python -def fast_add(a: t.CInt, b: t.CInt) -> t.CInt | t.CInline: +inline def fast_add(a: int, b: int) -> int: return a + b ``` -**编译行为**: -1. **阶段二预收集**:`_collect_inline_symbols` 扫描 `includes/` 目录中被引用的模块,收集所有 `t.CInline` 函数的 AST body -2. **翻译时展开**:遇到内联函数调用时,将函数体的 AST 直接嵌入调用点,替换参数为实际值 -3. **不生成独立函数**:内联函数不生成 LLVM IR 函数定义(除非也被非内联调用) +> 旧的 `-> T | t.CInline`(`t.CInline`)**不是**内联指令、也**不产生调用点展开**,它只是一个存储类标记,已不推荐;做真正内联请用 `inline`。 -### `t.CInline` 与 `t.CDefine` 函数的区别 +### `inline` 与 `define F(...)` 的区别 -| 特性 | `t.CInline` | `t.CDefine` 函数 | -|------|------------|-----------------| -| 展开时机 | 阶段二翻译时 | 阶段二翻译时 | +| 特性 | `inline def f(...)` | `define F(...)`(宏函数) | +|------|---------------------|--------------------------| +| 展开时机 | LLVM 优化阶段(`alwaysinline` 属性) | 阶段二翻译时(前端内联) | | 类型检查 | 完整的参数和返回类型检查 | 返回类型为宏,类型检查较弱 | -| 存根表示 | 仅签名(不添加 `c.State`) | 完整函数体 | -| LLVM IR | 可能生成函数定义(如果有非内联调用) | 不生成函数定义 | +| 存根表示 | 仅签名(不添加 `extern` 存储类) | 完整函数体 | +| LLVM IR | 生成函数定义 + `alwaysinline` 属性 | 不生成函数定义 | | 适用场景 | 性能关键的短函数 | 编译时常量和宏计算 | ## 目标平台