snapshot before regression test

This commit is contained in:
t
2026-07-18 19:25:40 +08:00
commit 796222a300
2295 changed files with 206453 additions and 0 deletions

301
includes/llvmlite/README.md Normal file
View File

@@ -0,0 +1,301 @@
# llvmlite 设计方案
用 TransPyC 自身实现的轻量级 LLVM IR 文本生成库,替代 Python `llvmlite` 依赖,为自举(见 `wiki/13-bootstrapping.md` 路径 B铺路。
## 1. 目标与定位
- **输入**:类型/值/指令的语义对象
- **输出**:合法的 LLVM IR 文本(`.ll`),可直接喂给 `llc`
- **不做什么**:不解析 IR、不做优化、不绑定 LLVM C API纯文本生成
- **自举约束**:本库必须能用当前 TransPyC 编译器完整编译,不得依赖任何 Python 运行时
## 2. 核心设计决策
### 2.1 类型系统用 `t.REnum`tagged union
LLVM 类型变体少、无通用字段、字段都是指针/小整数、操作主要通过 `match` 分派 —— 完全契合 REnum 的 tag+union 模型。
### 2.2 指令 opcode 用 `t.CEnum`
指令类别Binary/Unary/Cast/Memory/Terminator/Compare与具体 opcodeAdd/Sub/Load/Store/Br/Ret/...)用 `t.CEnum` 组织,类型安全且零开销。
### 2.3 IR 文本生成用 `viperlib.snprintf`
所有 IR 文本通过 `viperlib.snprintf(buf, size, fmt, *args)` 格式化写入缓冲区,避免手写逐字符拼接。`snprintf` 已支持宽度/精度/符号/`%s`/`%d`/`%x` 等,足够覆盖 IR 语法。
### 2.4 对象分配用普通类 + `mpool`
`mbuddy` 一样用普通类(无 `__new__`),由调用方注入 `mpool.MPool` 做批量分配。库内部不持有全局 `mbuddy`,遵循项目约定(`_mbuddy` 指针由 `os.py` 或调用方设置)。
---
## 3. 为什么 AST 不用 REnum而 llvmlite 用?
用户质疑REnum 是 tag+unionRust enum配合 `match` 模式匹配,按理很适合 AST。下面解释两者的适配性差异。
### 3.1 REnum 的硬限制(来自 `HandlesClassDef._EmitREnumLlvm`
1. **无通用字段共享**:每个 variant 独立声明字段,通用字段(如 `lineno`/`child`/`next`)必须在每 variant 重复声明。
2. **共享最大变体尺寸**:布局为 `{ i32 __tag, <max_variant_payload> }`,小变体浪费内存。
3. **payload 仅位置绑定**`match` 通过位置绑定 payload不能直接 `node.child` 属性访问 payload 字段。
4. **无方法**variant 不能挂方法。
### 3.2 AST 不适合 REnum 的四个原因
| 维度 | AST 需求 | REnum 限制 | 冲突 |
|------|----------|------------|------|
| 变体数量 | 70+ 节点类型 | 共享最大变体尺寸 | 内存膨胀(每节点都占最大变体空间) |
| 通用字段 | lineno/child/next/parent 等 ~8 个字段全节点共享 | 无通用字段共享 | 要么每 variant 重复声明(冗长),要么放弃统一访问 |
| 访问模式 | 频繁直接 `node.child`/`node.next`/`node.lineno` | payload 仅位置绑定,需 match 分派 | 遍历代码爆炸(每次访问都要 match |
| 字段复用 | `int_val`/`str_val`/`op` 等字段按 vtype 复用语义 | 每 variant 独立 payload | 无法复用 |
AST 采用"胖节点"设计(所有节点共用一个 `AST` struct`vtype` 区分):一次 `malloc`、统一链表遍历(`child`/`next`)、字段复用。这与 REnum"每变体独立 payload"的哲学根本冲突。
### 3.3 llvmlite 的 LLVMType 适合 REnum 的原因
| 维度 | LLVMType 需求 | REnum 特性 | 契合度 |
|------|---------------|------------|--------|
| 变体数量 | ~10 个Int/Ptr/Func/Array/Struct/Void/Float/Label/... | 共享最大变体尺寸 | 浪费可接受(最大变体 ~24 字节) |
| 通用字段 | 无(每变体字段不同) | 无通用字段共享 | 完美匹配 |
| 访问模式 | 类型操作天然通过 match 分派("是 Int 取 bits是 Ptr 取 pointee" | payload 位置绑定 + match | 天然契合 |
| 字段尺寸 | 都是指针(8B)或小整数(4B) | 共享最大变体 | 浪费小 |
**结论**REnum 是"少变体、无共性、match 分派"场景的最佳工具 —— llvmlite 类型系统正好如此AST 正好相反。
---
## 4. 文件结构
```
includes/llvmlite/
├── __init__.py # 公共导出 + 便捷工厂函数
├── __types.py # LLVMType (REnum) + 类型构造/打印
├── __values.py # Value/Constant/SSA 值表示
├── __module.py # Module 容器(函数列表 + 目标三元组 + 输出 .ll
├── __function.py # Function + BasicBlock + 参数管理
├── __builder.py # IRBuilder指令发射 + SSA 命名 + 块跳转)
└── README.md # 本文件
```
### 职责划分
- `__types.py``LLVMType` REnum 定义 + `TypePrint(buf, ty)` 将类型序列化为 IR 文本(如 `i32`/`i32*`/`{i32, i8*}`
- `__values.py``Value` 表示一个 SSA 值(`%0`/`%result`/常量),含类型指针 + 名字 + 是否常量
- `__module.py``Module` 持有函数链表 + 目标三元组 + 数据布局,`ModulePrint` 输出完整 `.ll`
- `__function.py``Function` 持有基本块链表 + 参数 + 返回类型;`BasicBlock` 持有指令文本缓冲
- `__builder.py``IRBuilder` 游标式 API`build_add`/`build_load`/`build_br`/... 发射指令到当前块
---
## 5. 类型系统设计REnum
```python
import t
from stdint import *
class LLVMType(t.REnum):
# 变体 Int整数类型
IntBits: t.CInt # 位宽 1/8/16/32/64/128
# 变体 Ptr指针类型
PtrPointee: LLVMType | t.CPtr # 指向的类型(自引用用指针)
# 变体 Func函数类型
FuncRet: LLVMType | t.CPtr # 返回类型
FuncParams: LLVMType | t.CPtr # 参数类型链表头
FuncPCount: t.CInt # 参数数量
# 变体 Array数组类型
ArrayElem: LLVMType | t.CPtr # 元素类型
ArrayCount: t.CInt # 元素数量
# 变体 Struct结构体类型
StructHead: LLVMType | t.CPtr # 字段类型链表头
StructCount: t.CInt # 字段数量
# 变体 Float浮点类型
FloatBits: t.CInt # 16/32/64/128
# 变体 Void / Label / Metadata无 payload
# REnum 允许空变体,仅靠 __tag 区分)
```
### 类型工厂(`__init__.py` 导出)
```python
def Int1() -> LLVMType | t.CPtr: ... # i1
def Int8() -> LLVMType | t.CPtr: ... # i8
def Int32() -> LLVMType | t.CPtr: ... # i32
def Int64() -> LLVMType | t.CPtr: ... # i64
def Ptr(pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr: ...
def Func(ret: LLVMType | t.CPtr, params: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr: ...
def Void() -> LLVMType | t.CPtr: ...
```
### 类型打印match 分派)
```python
def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr):
match ty:
case LLVMType.Int: # 位置绑定 IntBits
viperlib.snprintf(buf, size, "i%d", ty.IntBits)
case LLVMType.Ptr: # 位置绑定 PtrPointee
TypePrint(inner, size2, ty.PtrPointee)
# 拼接 "*"
case LLVMType.Func:
# 打印 ret (params)
case LLVMType.Void:
string.strcpy(buf, "void")
...
```
---
## 6. Value / SSA 设计
```python
class Value:
Ty: LLVMType | t.CPtr # 值的类型
Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本
IsConst: t.CInt # 1=常量字面量0=SSA 临时值
Next: Value | t.CPtr # 链表(函数内的值池)
```
`IRBuilder` 维护一个递增的 `%N` 计数器,每发射一条产生结果的指令就分配一个新名。
---
## 7. IRBuilder 设计
游标式 API跟踪当前 `BasicBlock`,发射指令文本到块的缓冲区。
```python
class IRBuilder:
Func: Function | t.CPtr # 所属函数
CurBlock: BasicBlock | t.CPtr # 当前插入点
Counter: t.CInt # SSA 名计数器
def build_add(self, lhs: Value | t.CPtr, rhs: Value | t.CPtr) -> Value | t.CPtr:
# 1. 分配 SSA 名 %N
# 2. snprintf(buf, size, " %%%d = add %s %s, %s\n", N, ty, lhs, rhs)
# 3. 追加到 CurBlock 缓冲
# 4. 返回新 Value
def build_load(self, ty: LLVMType | t.CPtr, ptr: Value | t.CPtr) -> Value | t.CPtr: ...
def build_store(self, val: Value | t.CPtr, ptr: Value | t.CPtr): ...
def build_br(self, target: BasicBlock | t.CPtr): ...
def build_cond_br(self, cond: Value | t.CPtr, then: BasicBlock | t.CPtr, else_: BasicBlock | t.CPtr): ...
def build_ret(self, val: Value | t.CPtr): ...
def build_alloca(self, ty: LLVMType | t.CPtr) -> Value | t.CPtr: ...
def build_gep(self, ptr: Value | t.CPtr, idx: Value | t.CPtr) -> Value | t.CPtr: ...
def build_call(self, callee: t.CChar | t.CPtr, args: Value | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Value | t.CPtr: ...
```
### 指令 opcodeCEnum
```python
class IROp(t.CEnum):
# Terminator
Ret: t.CEnum = 1
Br: t.CEnum = 2
CondBr: t.CEnum = 3
Switch: t.CEnum = 4
# Binary
Add: t.CEnum = 10
Sub: t.CEnum = 11
Mul: t.CEnum = 12
SDiv: t.CEnum = 13
# Memory
Load: t.CEnum = 20
Store: t.CEnum = 21
Alloca: t.CEnum = 22
Gep: t.CEnum = 23
# Cast
BitCast: t.CEnum = 30
SExt: t.CEnum = 31
Trunc: t.CEnum = 32
# Compare
ICmp: t.CEnum = 40
# Call
Call: t.CEnum = 50
```
---
## 8. IR 文本生成snprintf 用法)
每条指令发射用 `viperlib.snprintf` 格式化到块缓冲区。示例:
```python
import viperlib
def _emit_add(block: BasicBlock | t.CPtr, name: t.CChar | t.CPtr,
ty_str: t.CChar | t.CPtr, lhs: t.CChar | t.CPtr, rhs: t.CChar | t.CPtr):
line: t.CChar | t.CPtr = mpool.alloc(128) # 行缓冲
viperlib.snprintf(line, 128, " %s = add %s %s, %s\n", name, ty_str, lhs, rhs)
_block_append(block, line)
```
### Module 输出
```python
def ModulePrint(mod: Module | t.CPtr, out_path: t.CChar | t.CPtr):
# 1. 写头部target triple / datalayout
# 2. 遍历函数,写 declare/define
# 3. 每函数:签名 + 基本块 + 指令
# 用 snprintf 拼接写到文件viperio 或 w32/win32file
```
---
## 9. 内存管理
- 库内所有对象从 `mpool.MPool` 分配(像 `ast` 库一样)
- `IRBuilder`/`Module`/`Function` 不持有 `mbuddy`,由调用方传入 `mpool`
- 文本缓冲区按行分配每指令一行128 字节起步),避免频繁 realloc
---
## 10. 基础构建范围(第一阶段)
最小可用集,能生成一个完整的小程序 IR
1. **类型**`IntType`(1/8/16/32/64) + `PointerType` + `FunctionType` + `VoidType` + `StructType`
2. **值**`Value` + 常量整数字面量
3. **Module/Function/BasicBlock**:容器与链表
4. **IRBuilder** 指令子集:
- `alloca` / `load` / `store`
- `add` / `sub` / `mul` / `sdiv`
- `icmp` (eq/ne/sgt/sge/slt/sle)
- `br` / `cond_br` / `ret`
- `call`(外部函数)
- `bitcast` / `sext` / `trunc`
- `getelementptr`
5. **ModulePrint**:输出完整 `.ll` 文件
### 后续扩展路线
- **第二阶段**:浮点指令、`phi` 节点、`switch`、字符串常量全局、属性(`nounwind`/`nocapture`
- **第三阶段**:内联汇编、`atomic` 指令、`va_arg`、精确的 SSA 验证支配边界、phi 完整性)
- **第四阶段**:对接 TransPyC 的 `LLVMCG`,替换 Python `llvmlite`,完成路径 B 自举
---
## 11. 测试计划
独立测试项目(`Test/LLvmLiteTest/`
1. **类型打印测试**:构造各 `LLVMType``TypePrint` 输出,对比预期字符串
2. **小函数生成**:用 `IRBuilder` 生成 `i32 add(i32 a, i32 b) { ret i32 %r }``ModulePrint``.ll`,用 `llc` 编译验证语法合法
3. **match 分派测试**:构造各变体 `LLVMType``match` 正确绑定 payload
4. **snprintf 格式测试**:验证 `%d`/`%s`/`%x` 在 IR 文本中的正确性
---
## 12. 与现有架构的对接点
- **`lib/core/Codegen/LLVMCG.py`**:当前用 Python `llvmlite` 生成 IR自举时改用本库
- **`includes/viperlib.py`**:提供 `snprintf` / `sprintf`
- **`includes/mpool.py`**:提供 `MPool` 内存池
- **`includes/string.py`**:提供 `strcpy`/`strlen`/`memcpy`
- **`includes/ast/`**:参考其"胖节点 + mpool + CEnum 常量"的组织方式(但类型系统用 REnum 而非胖节点)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,456 @@
import t, c
from stdint import *
import string
import viperlib
import memhub
import stdio
from linkedlist import GSListNode, GSList
from .__types import LLVMType, ParamNode, TypePrint
# ============================================================
# Line: 指令文本行
#
# 每条 LLVM IR 指令序列化为一行文本,通过链表组织。
# 继承 GSListNode[Line] 获取强类型 Next: Line|CPtr
# ============================================================
class Line(GSListNode[Line]):
Buf: t.CChar | t.CPtr # 行文本NUL 结尾)
Len: t.CSizeT # 文本长度(不含 NUL
# ============================================================
# BasicBlock: 基本块
#
# 持有名称 + 指令行链表 + 终止指令标志。
# 继承 GSListNode[BasicBlock] 获取强类型 Next: BasicBlock|CPtr
# Lines 为 GSList[Line] 指针,提供 O(1) 追加。
# ============================================================
class BasicBlock(GSListNode[BasicBlock]):
Name: t.CChar | t.CPtr # 块名(如 "entry"/"if.then"
Lines: GSList[Line] | t.CPtr # 指令行链表容器Head/Tail/Count
IsTerminated: t.CInt # 1=已有终止指令br/ret
# ============================================================
# Param: 函数参数
#
# 继承 GSListNode[Param] 获取强类型 Next: Param|CPtr
# Attrs 存储参数属性文本(如 "noundef"/"nocapture"/"readonly"None=无属性
# ============================================================
class Param(GSListNode[Param]):
Ty: LLVMType | t.CPtr # 参数类型
Name: t.CChar | t.CPtr # 参数名(如 "%0"/"%a"
Attrs: t.CChar | t.CPtr # 参数属性文本None=无属性)
# ============================================================
# Function: 函数
#
# 持有名称 + 返回类型 + 参数链表 + 基本块链表。
# 继承 GSListNode[Function] 获取强类型 Next: Function|CPtr
# Params/Blocks 为 GSList 指针,提供 O(1) 追加。
# Attrs 存储函数级属性文本(如 "nounwind"/"noinline"None=无属性
# ============================================================
class Function(GSListNode[Function]):
Name: t.CChar | t.CPtr # 函数名
RetTy: LLVMType | t.CPtr # 返回类型
Params: GSList[Param] | t.CPtr # 参数链表容器
Blocks: GSList[BasicBlock] | t.CPtr # 基本块链表容器
IsDeclared: t.CInt # 1=仅声明(declare), 0=定义(define)
IsVarArg: t.CInt # 1=变参函数(...)
Attrs: t.CChar | t.CPtr # 函数属性文本None=无属性)
# ============================================================
# 工厂函数
# ============================================================
# Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节
LINE_SIZE: t.CDefine = 24
def new_line(pool: memhub.MemBuddy | t.CPtr, text: t.CChar | t.CPtr) -> Line | t.CPtr:
"""创建一个指令行,复制 text 到新分配的缓冲区"""
ptr: Line | t.CPtr = pool.alloc(LINE_SIZE)
if ptr is None: return None
string.memset(ptr, 0, LINE_SIZE)
if text is not None:
slen: t.CSizeT = string.strlen(text)
buf: t.CChar | t.CPtr = pool.alloc(slen + 1)
if buf is not None:
string.strcpy(buf, text)
ptr.Buf = buf
ptr.Len = slen
return ptr
def _new_gslist(pool: memhub.MemBuddy | t.CPtr, list_size: t.CSizeT) -> t.CPtr:
"""从 pool 分配并零初始化一个 GSList 容器Head/Tail/Count 全零)"""
gsl: t.CPtr = pool.alloc(list_size)
if gsl is None: return None
string.memset(gsl, 0, list_size)
return gsl
# BasicBlock 硬编码大小: Next(8) + Name(8) + Lines(8) + IsTerminated(4) = 32 字节
BLOCK_SIZE: t.CDefine = 32
def new_basic_block(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr:
"""创建一个基本块"""
ptr: BasicBlock | t.CPtr = pool.alloc(BLOCK_SIZE)
if ptr is None: return None
string.memset(ptr, 0, BLOCK_SIZE)
ptr.Name = name
ptr.Lines = _new_gslist(pool, 24) # GSList: Head+Tail+Count
ptr.IsTerminated = 0
return ptr
# Param 硬编码大小: Next(8) + Ty(8) + Name(8) + Attrs(8) = 32 字节
PARAM_SIZE: t.CDefine = 32
def new_param(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Param | t.CPtr:
"""创建一个函数参数"""
ptr: Param | t.CPtr = pool.alloc(PARAM_SIZE)
if ptr is None: return None
string.memset(ptr, 0, PARAM_SIZE)
ptr.Ty = ty
ptr.Name = name
ptr.Attrs = None
return ptr
# Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) = 56 字节
FUNC_SIZE: t.CDefine = 56
def new_function(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr,
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建一个函数"""
ptr: Function | t.CPtr = pool.alloc(FUNC_SIZE)
if ptr is None: return None
string.memset(ptr, 0, FUNC_SIZE)
ptr.Name = name
ptr.RetTy = ret_ty
ptr.Params = _new_gslist(pool, 24) # GSList: Head+Tail+Count
ptr.Blocks = _new_gslist(pool, 24)
ptr.IsDeclared = 0
ptr.Attrs = None
return ptr
# ============================================================
# 链表操作(委托 GSList.append
# ============================================================
def function_add_param(func: Function | t.CPtr, param: Param | t.CPtr):
"""将参数追加到函数参数链表"""
if func is None or param is None: return
if func.Params is None: return
func.Params.append(param)
def function_add_block(func: Function | t.CPtr, block: BasicBlock | t.CPtr):
"""将基本块追加到函数块链表"""
if func is None or block is None: return
if func.Blocks is None: return
func.Blocks.append(block)
def function_move_block_to_end(func: Function | t.CPtr, block: BasicBlock | t.CPtr):
"""将 block 移动到函数块链表末尾(保证 BB 文本顺序与控制流顺序一致)。
用于解决 SSA 名非单调问题BB 按创建顺序排列,但指令按控制流顺序生成,
导致 SSA 编号在文本输出时非单调递增llc 报错。
在 position_at_end 时调用此函数,使 BB 顺序与 position 顺序一致。
"""
if func is None or block is None: return
blocks: GSList | t.CPtr = func.Blocks
if blocks is None: return
# 已经是 Tail无需移动
if blocks.Tail is block:
return
# 从链表中移除 block
if blocks.Head is block:
# block 是 Head直接后移 Head
blocks.Head = block.Next
else:
# 遍历找前驱
prev: BasicBlock | t.CPtr = blocks.Head
while prev is not None and prev.Next is not block:
prev = prev.Next
if prev is None:
# block 不在链表中,直接 append
blocks.append(block)
return
prev.Next = block.Next
# block.Next 由移除逻辑处理,重置为 None
block.Next = None
# append 到末尾(不调用 blocks.append 以避免 Count 重复递增)
if blocks.Tail is not None:
blocks.Tail.Next = block
blocks.Tail = block
def block_append_line(block: BasicBlock | t.CPtr, line: Line | t.CPtr):
"""将指令行追加到基本块"""
if block is None or line is None: return
if block.Lines is None: return
block.Lines.append(line)
def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr,
text: t.CChar | t.CPtr):
"""创建指令行并追加到基本块"""
if block is None or text is None: return
line: Line | t.CPtr = new_line(pool, text)
if line is not None:
block_append_line(block, line)
# ============================================================
# 属性设置
# ============================================================
def function_set_attrs(func: Function | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置函数级属性文本(如 "nounwind"/"noinline""""
if func is None: return
func.Attrs = attrs
def param_set_attrs(param: Param | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置参数属性文本(如 "noundef"/"nocapture"/"readonly""""
if param is None: return
param.Attrs = attrs
# ============================================================
# _ll_name_needs_quote - 检查 LLVM 标识符是否需要加引号
#
# LLVM IR 规范:标识符以数字开头或含特殊字符(如 '.')时必须
# 用双引号包围。SHA1 命名空间的函数名格式为 "sha1hex.funcname"
# (含 '.'),以 hex 字符开头(可能以数字开头),因此需要加引号。
# 普通函数名(如 printf/malloc/main不含特殊字符不加引号。
# ============================================================
def _ll_name_needs_quote(name: str) -> t.CInt:
"""检查 LLVM 标识符是否需要加引号(以数字开头或含 '.'
例外: LLVM 内联函数名(如 llvm.memcpy/llvm.memset'llvm.' 开头,
虽含 '.',但不能加引号——加引号后 LLVM 解析器不识别为内联函数,
导致 declare/call 签名不匹配Intrinsic called with incompatible signature
"""
if name is None:
return 0
c0: t.CChar = name[0]
if c0 >= '0' and c0 <= '9':
return 1
name_len: t.CSizeT = string.strlen(name)
# 豁免 llvm.* 前缀的内联函数名
if name_len >= 5:
if name[0] == 'l' and name[1] == 'l' and name[2] == 'v' and name[3] == 'm' and name[4] == '.':
return 0
i: t.CSizeT = 0
while i < name_len:
if name[i] == '.':
return 1
i += 1
return 0
# ============================================================
# FunctionPrint: 将函数序列化为 IR 文本
#
# 格式:
# define <ret_ty> @<name>(<params>) {
# <block_name>:
# <instruction>
# <instruction>
# <block_name>:
# <instruction>
# }
# ============================================================
def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""将函数 func 序列化为 IR 文本写入 buf"""
if func is None or buf is None or size == 0: return
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
if ty_buf is None: return
ty_buf[0] = '\0'
# define <ret_ty> @<name>(<params>)
if func.IsDeclared == 1:
_append_cstr(buf, size, "declare ")
else:
_append_cstr(buf, size, "define ")
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, func.RetTy, pool)
_append_cstr(buf, size, ty_buf)
_append_cstr(buf, size, " @")
if func.Name is not None:
if _ll_name_needs_quote(func.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, func.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, func.Name)
_append_cstr(buf, size, "(")
# 参数列表(从 GSList[Param].Head 遍历)
cur: Param | t.CPtr = None
if func.Params is not None:
cur = func.Params.Head
first: t.CInt = 1
while cur is not None:
if first == 0:
_append_cstr(buf, size, ", ")
# 参数属性(如 "noundef"/"nocapture")在类型之前
if cur.Attrs is not None:
_append_cstr(buf, size, cur.Attrs)
_append_cstr(buf, size, " ")
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, cur.Ty, pool)
_append_cstr(buf, size, ty_buf)
# declare 声明不打印参数名
if func.IsDeclared == 0 and cur.Name is not None:
_append_cstr(buf, size, " ")
# LLVM IR 要求参数名以 % 开头
if cur.Name[0] != '%':
_append_cstr(buf, size, "%")
_append_cstr(buf, size, cur.Name)
cur = cur.Next
first = 0
# 变参函数追加 ...
if func.IsVarArg == 1:
if func.Params is not None and func.Params.Head is not None:
_append_cstr(buf, size, ", ...")
else:
_append_cstr(buf, size, "...")
_append_cstr(buf, size, ")")
# 函数级属性(如 "nounwind"/"noinline")在 ) 之后
if func.Attrs is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, func.Attrs)
if func.IsDeclared == 1:
_append_cstr(buf, size, "\n")
return
# 函数体
_append_cstr(buf, size, " {\n")
blk: BasicBlock | t.CPtr = None
if func.Blocks is not None:
blk = func.Blocks.Head
while blk is not None:
# 块标签
if blk.Name is not None:
_append_cstr(buf, size, blk.Name)
_append_cstr(buf, size, ":\n")
# 指令行(从 GSList[Line].Head 遍历)
line: Line | t.CPtr = None
if blk.Lines is not None:
line = blk.Lines.Head
while line is not None:
if line.Buf is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, line.Buf)
_append_cstr(buf, size, "\n")
line = line.Next
blk = blk.Next
_append_cstr(buf, size, "}\n")
# ============================================================
# 内部辅助
# ============================================================
def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 C 字符串 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
# ============================================================
# 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型
# (字段不足且字段类型可能错误),导致 TransPyC 静默跳过
# 字段访问(不生成 GEP不报错字段值永远为 null。
#
# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问
# 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。
# ============================================================
def function_get_name(func: Function | t.CPtr) -> t.CChar | t.CPtr:
"""获取函数名"""
if func is None:
return None
return func.Name
def function_get_ret_ty(func: Function | t.CPtr) -> LLVMType | t.CPtr:
"""获取函数返回类型"""
if func is None:
return None
return func.RetTy
def function_get_params(func: Function | t.CPtr) -> GSList[Param] | t.CPtr:
"""获取函数参数链表容器"""
if func is None:
return None
return func.Params
def function_get_param_head(func: Function | t.CPtr) -> Param | t.CPtr:
"""获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head"""
if func is None:
return None
if func.Params is None:
return None
return func.Params.Head
def function_get_next(func: Function | t.CPtr) -> Function | t.CPtr:
"""获取链表下一个函数"""
if func is None:
return None
return func.Next
def function_is_declared(func: Function | t.CPtr) -> t.CInt:
"""获取函数是否为声明1=declare 仅声明, 0=define 定义)"""
if func is None:
return 0
return func.IsDeclared
def param_get_name(param: Param | t.CPtr) -> t.CChar | t.CPtr:
"""获取参数名"""
if param is None:
return None
return param.Name
def param_get_ty(param: Param | t.CPtr) -> LLVMType | t.CPtr:
"""获取参数类型"""
if param is None:
return None
return param.Ty
def param_get_next(param: Param | t.CPtr) -> Param | t.CPtr:
"""获取链表下一个参数"""
if param is None:
return None
return param.Next

View File

@@ -0,0 +1,403 @@
import t, c
from stdint import *
import memhub
import string
import viperlib
# 导入子模块
from .__types import (
LLVMType, ParamNode, LLVMTypeCore,
Int1, Int8, Int16, Int32, Int64, Ptr, Func, Void, Array, Struct,
Half, Float, Double, FP128, Label,
new_param_node, param_list_append,
paramnode_get_ty, paramnode_get_next, paramnode_set_ty, paramnode_set_next,
TypePrint, PrintStructDefinition, get_struct_name,
)
from .__values import (
Value, new_value, ConstInt, ConstNull, ConstZero, ConstFloat, SSAValue, ValuePrint,
value_get_ty, value_get_next,
value_set_ty, value_set_next, value_set_name, value_set_isconst,
)
from .__function import (
Line, BasicBlock, Param, Function,
new_line, new_basic_block, new_param, new_function,
function_add_param, function_add_block,
block_append_line, block_append_text,
function_set_attrs, param_set_attrs,
function_get_name, function_get_ret_ty, function_get_params,
function_get_param_head, function_get_next, function_is_declared,
param_get_name, param_get_ty, param_get_next,
FunctionPrint,
)
from .__module import (
LLVMModule, GlobalVariable, NamedTypeNode, new_module, new_global_variable,
module_add_function, module_add_global, module_add_named_type,
module_set_target, module_set_datalayout,
global_set_constant, global_set_linkage, global_set_unnamed_addr, global_set_section,
LLVMModulePrint, OUTPUT_FULL, OUTPUT_STUB, OUTPUT_TEXT,
module_ensure_opaque_for_type,
)
from .__builder import (
IRBuilder, new_builder, position_at_end,
build_alloca, build_load, build_store,
build_add, build_sub, build_mul, build_sdiv, build_udiv, build_srem, build_urem,
build_and, build_or, build_xor, build_shl, build_lshr, build_ashr,
build_fadd, build_fsub, build_fmul, build_fdiv, build_frem, build_fneg,
build_icmp, build_fcmp,
build_br, build_cond_br, build_ret, build_ret_void,
build_call, build_call_indirect, build_bitcast, build_sext, build_trunc, build_zext,
build_ptrtoint, build_inttoptr,
build_fpext, build_fptrunc, build_fp2si, build_si2fp, build_fp2ui, build_ui2fp,
build_gep, build_gep_array, build_gep_struct,
build_phi, build_switch, build_select, build_unreachable,
build_atomicrmw, build_cmpxchg, build_inline_asm,
PhiIncoming, new_phi_incoming, SwitchCase, new_switch_case,
ICMP_EQ, ICMP_NE, ICMP_SGT, ICMP_SGE, ICMP_SLT, ICMP_SLE,
ICMP_UGT, ICMP_UGE, ICMP_ULT, ICMP_ULE,
FCMP_FALSE, FCMP_OEQ, FCMP_OGT, FCMP_OGE, FCMP_OLT, FCMP_OLE,
FCMP_ONE, FCMP_ORD, FCMP_UNO, FCMP_UEQ, FCMP_UGT, FCMP_UGE,
FCMP_ULT, FCMP_ULE, FCMP_UNE, FCMP_TRUE,
ATOMIC_XCHG, ATOMIC_ADD, ATOMIC_SUB, ATOMIC_AND, ATOMIC_NAND,
ATOMIC_OR, ATOMIC_XOR, ATOMIC_MAX, ATOMIC_MIN, ATOMIC_UMAX, ATOMIC_UMIN,
ATOMIC_ORDER_NOTATOMIC, ATOMIC_ORDER_UNORDERED, ATOMIC_ORDER_MONOTONIC,
ATOMIC_ORDER_ACQUIRE, ATOMIC_ORDER_RELEASE, ATOMIC_ORDER_ACQ_REL,
ATOMIC_ORDER_SEQ_CST,
)
from .__verify import (
VerifyResult, NameEntry,
verify_function, verify_module,
VERIFY_OK, VERIFY_ERR_NO_TERMINATOR, VERIFY_ERR_DUPLICATE_DEF,
VERIFY_ERR_UNDEFINED_USE, VERIFY_ERR_PHI_NOT_FIRST,
_new_verify_result,
)
# ============================================================
# 便捷工厂: 字符串复制
# ============================================================
def _str_dup(pool: memhub.MemBuddy | t.CPtr, src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
"""从 pool 分配并复制一个 C 字符串"""
if src is None: return None
slen: t.CSizeT = string.strlen(src)
buf: t.CChar | t.CPtr = pool.alloc(slen + 1)
if buf is None: return None
string.strcpy(buf, src)
return buf
# ============================================================
# 便捷工厂: 创建带名称的基本块
# ============================================================
def create_block(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr,
name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr:
"""创建基本块并添加到函数"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
blk: BasicBlock | t.CPtr = new_basic_block(pool, name_dup)
if blk is not None:
function_add_block(func, blk)
return blk
# ============================================================
# 便捷工厂: 创建整数常量值
# ============================================================
def const_int(pool: memhub.MemBuddy | t.CPtr, bits: t.CInt,
val: t.CInt64T) -> Value | t.CPtr:
"""创建整数常量值(自动创建类型 + 名字文本)
参数:
bits: 位宽 (1/8/16/32/64)
val: 整数值
"""
# 创建类型
ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if ty is None: return None
string.memset(ty, 0, LLVMType.__sizeof__())
c.DerefAs(ty, LLVMType.Int(bits))
# 创建名字文本
name: t.CChar | t.CPtr = pool.alloc(32)
if name is None: return None
viperlib.snprintf(name, 32, "%lld", val)
return ConstInt(pool, ty, val, name)
def const_int32(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr:
"""便捷: 创建 i32 整数常量"""
return const_int(pool, 32, val)
def const_int64(pool: memhub.MemBuddy | t.CPtr, val: t.CInt64T) -> Value | t.CPtr:
"""便捷: 创建 i64 整数常量"""
return const_int(pool, 64, val)
# ============================================================
# 便捷工厂: 创建函数并添加到模块
# ============================================================
def create_function(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建函数并添加到模块"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
func: Function | t.CPtr = new_function(pool, name_dup, ret_ty)
if func is not None:
module_add_function(mod, func)
return func
def add_param(pool: memhub.MemBuddy | t.CPtr, func: Function | t.CPtr,
ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Param | t.CPtr:
"""创建参数并添加到函数"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
param: Param | t.CPtr = new_param(pool, ty, name_dup)
if param is not None:
function_add_param(func, param)
return param
# ============================================================
# 便捷工厂: 创建函数声明declare
# ============================================================
def create_declare(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建函数声明declare无函数体并添加到模块
与 create_function 不同,声明不生成函数体,仅生成:
declare <ret_ty> @<name>(<params>)
"""
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
func: Function | t.CPtr = new_function(pool, name_dup, ret_ty)
if func is not None:
func.IsDeclared = 1
module_add_function(mod, func)
return func
# ============================================================
# 便捷工厂: 创建字符串常量全局变量
#
# 生成 LLVM IR:
# @.str = private unnamed_addr constant [N x i8] c"contents\00"
# ============================================================
def create_global_string(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建字符串常量全局变量并添加到模块
参数:
name: 全局变量名(如 ".str"
text: 字符串内容C 字符串,不含末尾 NULNUL 由本函数自动添加)
返回: GlobalVariable 指针,其类型为 [len+1 x i8]
"""
if text is None: return None
slen: t.CSizeT = string.strlen(text)
count: t.CInt = slen + 1 # 含末尾 NUL
# 创建 i8 类型
i8_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if i8_ty is None: return None
string.memset(i8_ty, 0, LLVMType.__sizeof__())
c.DerefAs(i8_ty, LLVMType.Int(8))
# 创建 [count x i8] 数组类型
arr_ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if arr_ty is None: return None
string.memset(arr_ty, 0, LLVMType.__sizeof__())
c.DerefAs(arr_ty, LLVMType.Array(i8_ty, count))
# 创建全局变量
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, arr_ty)
if gv is None: return None
# 设置属性: private + unnamed_addr + constant
global_set_linkage(gv, "private")
global_set_unnamed_addr(gv, 1)
global_set_constant(gv, 1)
# 构造初始化值文本: c"contents\00"
# LLVM IR 字符串字面量格式: c"<chars>" 其中非打印字符用 \xx 转义
# 这里简单处理: 直接复制原始字节,末尾加 \00
init_buf: t.CChar | t.CPtr = pool.alloc(slen + 8) # c"..." + \00 + "
if init_buf is None: return None
pos: t.CSizeT = 0
init_buf[pos] = 'c'
pos += 1
init_buf[pos] = '"'
pos += 1
i: t.CSizeT = 0
while i < slen:
init_buf[pos] = text[i]
pos += 1
i += 1
# 末尾 NUL 字节
init_buf[pos] = '\\'
pos += 1
init_buf[pos] = '0'
pos += 1
init_buf[pos] = '0'
pos += 1
init_buf[pos] = '"'
pos += 1
init_buf[pos] = '\0'
gv.Initializer = init_buf
module_add_global(mod, gv)
return gv
# ============================================================
# 便捷工厂: 创建带初始化值的整数全局变量
# ============================================================
def create_global_int(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr,
name: t.CChar | t.CPtr, bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr:
"""创建整数全局变量并添加到模块
生成 LLVM IR:
@<name> = global i<bits> <val>
"""
# 创建整数类型
ty: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if ty is None: return None
string.memset(ty, 0, LLVMType.__sizeof__())
c.DerefAs(ty, LLVMType.Int(bits))
name_dup: t.CChar | t.CPtr = _str_dup(pool, name)
gv: GlobalVariable | t.CPtr = new_global_variable(pool, name_dup, ty)
if gv is None: return None
# 构造初始化值文本: "42" (类型由 _print_global 单独打印)
init_buf: t.CChar | t.CPtr = pool.alloc(48)
if init_buf is None: return None
viperlib.snprintf(init_buf, 48, "%lld", val)
gv.Initializer = init_buf
module_add_global(mod, gv)
return gv
# ============================================================
# LLVMModuleCore: 模块/函数/值创建核心,封装 pool 避免重复传参
#
# 用法:
# mcore: LLVMModuleCore | t.CPtr = LLVMModuleCore(pool)
# mod: LLVMModule | t.CPtr = mcore.NewModule("test")
# func: Function | t.CPtr = mcore.CreateFunction(mod, "add", ty_i32)
# val: Value | t.CPtr = mcore.ConstInt32(42)
# ============================================================
@t.NoVTable
class LLVMModuleCore:
"""模块/函数/值创建核心,封装 pool 避免每次创建都传 pool"""
Pool: memhub.MemBuddy | t.CPtr
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
self.Pool = pool
# ---- 模块操作 ----
def NewModule(self, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr:
return new_module(self.Pool, name)
def CreateFunction(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
return create_function(self.Pool, mod, name, ret_ty)
def CreateDeclare(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr:
"""创建函数声明declare无函数体"""
return create_declare(self.Pool, mod, name, ret_ty)
def AddParam(self, func: Function | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Param | t.CPtr:
return add_param(self.Pool, func, ty, name)
def FunctionSetAttrs(self, func: Function | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置函数级属性文本"""
function_set_attrs(func, attrs)
def ParamSetAttrs(self, param: Param | t.CPtr, attrs: t.CChar | t.CPtr):
"""设置参数属性文本"""
param_set_attrs(param, attrs)
def CreateBlock(self, func: Function | t.CPtr,
name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr:
return create_block(self.Pool, func, name)
def NewBuilder(self, func: Function | t.CPtr) -> IRBuilder | t.CPtr:
return new_builder(self.Pool, func)
# ---- 全局变量 ----
def NewGlobal(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建全局变量并添加到模块"""
name_dup: t.CChar | t.CPtr = _str_dup(self.Pool, name)
gv: GlobalVariable | t.CPtr = new_global_variable(self.Pool, name_dup, ty)
if gv is not None:
module_add_global(mod, gv)
return gv
def CreateGlobalString(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
text: t.CChar | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建字符串常量全局变量"""
return create_global_string(self.Pool, mod, name, text)
def CreateGlobalInt(self, mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr,
bits: t.CInt, val: t.CInt64T) -> GlobalVariable | t.CPtr:
"""创建带初始化值的整数全局变量"""
return create_global_int(self.Pool, mod, name, bits, val)
def GlobalSetConstant(self, gv: GlobalVariable | t.CPtr, is_const: t.CInt):
global_set_constant(gv, is_const)
def GlobalSetLinkage(self, gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr):
global_set_linkage(gv, linkage)
def GlobalSetUnnamedAddr(self, gv: GlobalVariable | t.CPtr, level: t.CInt):
global_set_unnamed_addr(gv, level)
def GlobalSetSection(self, gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr):
global_set_section(gv, section)
# ---- 值创建 ----
def ConstInt(self, bits: t.CInt, val: t.CInt64T) -> Value | t.CPtr:
return const_int(self.Pool, bits, val)
def ConstInt32(self, val: t.CInt64T) -> Value | t.CPtr:
return const_int32(self.Pool, val)
def ConstInt64(self, val: t.CInt64T) -> Value | t.CPtr:
return const_int64(self.Pool, val)
def ConstFloat(self, ty: LLVMType | t.CPtr, val: t.CDouble) -> Value | t.CPtr:
return ConstFloat(self.Pool, ty, val)
def SSAValue(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr:
return SSAValue(self.Pool, ty, name)
def ConstNull(self, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Value | t.CPtr:
return ConstNull(self.Pool, ty, name)
# ---- 打印 ----
def PrintValue(self, buf: t.CChar | t.CPtr, size: t.CSizeT, val: Value | t.CPtr):
ValuePrint(buf, size, val, self.Pool)
def PrintFunction(self, buf: t.CChar | t.CPtr, size: t.CSizeT, func: Function | t.CPtr):
FunctionPrint(buf, size, func, self.Pool)
def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, mod: LLVMModule | t.CPtr):
LLVMModulePrint(buf, size, mod, self.Pool, OUTPUT_FULL)
# ---- SSA 验证 ----
def NewVerifyResult(self, buf_size: t.CSizeT) -> VerifyResult | t.CPtr:
"""创建验证结果对象buf_size 为错误消息缓冲区大小)"""
return _new_verify_result(self.Pool, buf_size)
def VerifyFunction(self, func: Function | t.CPtr,
result: VerifyResult | t.CPtr) -> t.CInt:
"""验证单个函数的 SSA 正确性返回错误数0=通过)"""
return verify_function(self.Pool, func, result)
def VerifyModule(self, mod: LLVMModule | t.CPtr,
result: VerifyResult | t.CPtr) -> t.CInt:
"""验证模块中所有函数的 SSA 正确性返回错误数0=通过)"""
return verify_module(self.Pool, mod, result)

View File

@@ -0,0 +1,504 @@
import t, c
from stdint import *
import string
import stdio
import viperlib
import memhub
from linkedlist import GSList, GSListNode
from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct
from .__function import Function, FunctionPrint, _ll_name_needs_quote, Param
# ============================================================
# GlobalVariable: LLVM IR 全局变量
#
# 持有名称 + 类型 + 初始化值 + 常量标志 + 链接类型。
# 继承 GSListNode[GlobalVariable] 获取强类型 Next。
# ============================================================
@t.NoVTable
class GlobalVariable(GSListNode[GlobalVariable]):
Name: t.CChar | t.CPtr # 全局变量名(如 ".str" / "my_global"
Ty: LLVMType | t.CPtr # 变量类型
Initializer: t.CVoid | t.CPtr # 初始化值 Value*None = 无初始化)
IsConstant: t.CInt # 1=constant, 0=variable
Linkage: t.CChar | t.CPtr # 链接类型("private"/"internal"/"external"/...
Section: t.CChar | t.CPtr # 段名None = 默认)
UnnamedAddr: t.CInt # 1=unnamed_addr, 2=local_unnamed_addr, 0=none
# ============================================================
# NamedTypeNode: 命名结构体类型链表节点
#
# 持有 LLVMType* 指针(必须是命名 Struct 类型)。
# 继承 GSListNode[NamedTypeNode] 获取强类型 Next。
# ============================================================
@t.NoVTable
class NamedTypeNode(GSListNode[NamedTypeNode]):
Ty: LLVMType | t.CPtr # 命名结构体类型指针
# ============================================================
# LLVMModule: LLVM IR 模块容器
#
# 使用嵌入式 Head/Tail/Count 字段代替 GSList 指针,
# 避免泛型 GSList 的 __sizeof__ 返回 0 和 vtable 偏移不一致问题。
# LLVMModulePrint 输出完整 .ll 文件内容。
# 注意: 类名必须为 LLVMModule 而非 Module避免与 ast.Module 命名冲突
# ============================================================
@t.NoVTable
class LLVMModule:
Name: t.CChar | t.CPtr # 模块名
FuncHead: Function | t.CPtr # 函数链表头
FuncTail: Function | t.CPtr # 函数链表尾
FuncCount: t.CSizeT # 函数计数
GlobalHead: GlobalVariable | t.CPtr # 全局变量链表头
GlobalTail: GlobalVariable | t.CPtr # 全局变量链表尾
GlobalCount: t.CSizeT # 全局变量计数
TargetTriple: t.CChar | t.CPtr # 目标三元组(如 "x86_64-pc-linux-gnu"
DataLayout: t.CChar | t.CPtr # 数据布局(如 "e-m:e-p270:32:32-...")
NamedTypeHead: NamedTypeNode | t.CPtr # 命名结构体类型链表头
NamedTypeTail: NamedTypeNode | t.CPtr # 命名结构体类型链表尾
NamedTypeCount: t.CSizeT # 命名结构体类型计数
# 总计: 12 字段 * 8 = 96 字节(无 vtable
# ============================================================
# 工厂函数
# ============================================================
def new_module(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr:
"""创建一个模块"""
# 硬编码 96 字节12 字段 * 8 字节(无 vtable@t.NoVTable
ptr: LLVMModule | t.CPtr = pool.alloc(96)
if ptr is None: return None
string.memset(ptr, 0, 96)
ptr.Name = name
ptr.FuncHead = None
ptr.FuncTail = None
ptr.FuncCount = 0
ptr.GlobalHead = None
ptr.GlobalTail = None
ptr.GlobalCount = 0
ptr.TargetTriple = None
ptr.DataLayout = None
ptr.NamedTypeHead = None
ptr.NamedTypeTail = None
ptr.NamedTypeCount = 0
return ptr
# GlobalVariable 硬编码大小: Next(8) + Name(8) + Ty(8) + Initializer(8) + IsConstant(4) + Linkage(8) + Section(8) + UnnamedAddr(4) = 64 字节
GV_SIZE: t.CDefine = 64
# NamedTypeNode 硬编码大小: Next(8) + Ty(8) = 16 字节
NAMED_TYPE_NODE_SIZE: t.CDefine = 16
def new_global_variable(pool: memhub.MemBuddy | t.CPtr,
name: t.CChar | t.CPtr, ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr:
"""创建一个全局变量"""
ptr: GlobalVariable | t.CPtr = pool.alloc(GV_SIZE)
if ptr is None: return None
string.memset(ptr, 0, GV_SIZE)
ptr.Name = name
ptr.Ty = ty
ptr.Initializer = None
ptr.IsConstant = 0
ptr.Linkage = "external"
ptr.Section = None
ptr.UnnamedAddr = 0
return ptr
# ============================================================
# 链表操作(嵌入式 Head/Tail/CountO(1) 追加)
# ============================================================
def module_add_function(mod: LLVMModule | t.CPtr, func: Function | t.CPtr):
"""将函数追加到模块函数链表O(1)"""
if mod is None or func is None: return
func.Next = None
if mod.FuncHead is None:
mod.FuncHead = func
else:
mod.FuncTail.Next = func
mod.FuncTail = func
mod.FuncCount += 1
def module_add_global(mod: LLVMModule | t.CPtr, gv: GlobalVariable | t.CPtr):
"""将全局变量追加到模块全局变量链表O(1)"""
if mod is None or gv is None: return
gv.Next = None
if mod.GlobalHead is None:
mod.GlobalHead = gv
else:
mod.GlobalTail.Next = gv
mod.GlobalTail = gv
mod.GlobalCount += 1
def module_set_target(mod: LLVMModule | t.CPtr, triple: t.CChar | t.CPtr):
"""设置目标三元组"""
if mod is None: return
mod.TargetTriple = triple
def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr):
"""设置数据布局"""
if mod is None: return
mod.DataLayout = layout
# ============================================================
# 命名结构体类型管理
# ============================================================
def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr):
"""将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行)
非命名结构体Name 为 None 或非 Struct 类型)会被忽略。
按 Name 去重,相同名称的类型只保留第一个。
"""
if mod is None or pool is None or ty is None:
return
name: t.CChar | t.CPtr = get_struct_name(ty)
if name is None:
return
# 去重检查
cur: NamedTypeNode | t.CPtr = mod.NamedTypeHead
while cur is not None:
if cur.Ty is not None:
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
if existing_name is not None:
if string.strcmp(existing_name, name) == 0:
return
cur = cur.Next
# 创建新节点并追加到链表尾部
node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE)
if node is None:
return
string.memset(node, 0, NAMED_TYPE_NODE_SIZE)
node.Ty = ty
node.Next = None
if mod.NamedTypeHead is None:
mod.NamedTypeHead = node
else:
mod.NamedTypeTail.Next = node
mod.NamedTypeTail = node
mod.NamedTypeCount += 1
# ============================================================
# module_ensure_opaque_for_type - 为类型中的跨模块结构体引用添加 opaque 声明
#
# 递归扫描 LLVMType 树,当遇到 Ptr(Struct(name)) 且 name 包含 '.'SHA1 限定名)时,
# 如果该名称未在模块中定义,则添加 opaque 声明(%"name" = type opaque
# 这解决了跨模块结构体引用导致的 llc "use of undefined type" 错误。
# ============================================================
def _is_type_defined_in_module(mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr) -> int:
"""检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义"""
if mod is None or name is None:
return 0
cur: NamedTypeNode | t.CPtr = mod.NamedTypeHead
while cur is not None:
if cur.Ty is not None:
existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty)
if existing_name is not None:
if string.strcmp(existing_name, name) == 0:
return 1
cur = cur.Next
return 0
def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr,
mod: LLVMModule | t.CPtr,
ty: LLVMType | t.CPtr):
"""递归扫描类型树,为跨模块结构体引用添加 opaque 声明"""
if ty is None or mod is None or pool is None:
return
match ty:
case LLVMType.Ptr(pointee):
if pointee is not None:
match pointee:
case LLVMType.Struct(sfields, sfcount, sname):
if sname is not None:
# 检查是否为跨模块引用(名称包含 '.'
if string.strchr(sname, 46) is not None:
# 检查是否已在模块中定义
if _is_type_defined_in_module(mod, sname) == 0:
# 创建 opaque 类型并添加到模块
opaque_ty: LLVMType | t.CPtr = Struct(pool, None, 0, sname)
if opaque_ty is not None:
module_add_named_type(mod, pool, opaque_ty)
case _:
_scan_type_for_cross_module_refs(pool, mod, pointee)
case LLVMType.Array(elem_ty, acount):
if elem_ty is not None:
_scan_type_for_cross_module_refs(pool, mod, elem_ty)
case _:
pass
def module_ensure_opaque_for_type(mod: LLVMModule | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
ty: LLVMType | t.CPtr):
"""为类型中的跨模块结构体引用添加 opaque 声明
当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'SHA1 限定名)时,
如果该名称未在模块中定义,则添加 opaque 声明。
"""
_scan_type_for_cross_module_refs(pool, mod, ty)
# ============================================================
# 全局变量属性设置
# ============================================================
def global_set_constant(gv: GlobalVariable | t.CPtr, is_const: t.CInt):
"""设置全局变量是否为常量"""
if gv is None: return
gv.IsConstant = is_const
def global_set_linkage(gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr):
"""设置链接类型 (private/internal/external/... )"""
if gv is None: return
gv.Linkage = linkage
def global_set_unnamed_addr(gv: GlobalVariable | t.CPtr, level: t.CInt):
"""设置 unnamed_addr 属性 (0=none, 1=unnamed_addr, 2=local_unnamed_addr)"""
if gv is None: return
gv.UnnamedAddr = level
def global_set_section(gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr):
"""设置段名"""
if gv is None: return
gv.Section = section
# ============================================================
# 输出模式常量
# ============================================================
OUTPUT_FULL: t.CDefine = 0 # 完整 IRstub + text
OUTPUT_STUB: t.CDefine = 1 # 仅声明header + 类型定义 + declare + external global
OUTPUT_TEXT: t.CDefine = 2 # 仅代码define + global 带初值)
# ============================================================
# LLVMModulePrint: 将模块序列化为 .ll 文本
#
# mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码
# ============================================================
def LLVMModulePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr,
mode: t.CInt):
"""将模块 mod 序列化为 .ll 文本写入 buf"""
if mod is None or buf is None or size == 0: return
# 头部注释stub 和 full 模式输出text 模式不输出)
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
_append_cstr(buf, size, "; ModuleID = '")
if mod.Name is not None:
_append_cstr(buf, size, mod.Name)
_append_cstr(buf, size, "'\n")
# 目标三元组
if mod.TargetTriple is not None:
_append_cstr(buf, size, "target triple = \"")
_append_cstr(buf, size, mod.TargetTriple)
_append_cstr(buf, size, "\"\n")
# 数据布局
if mod.DataLayout is not None:
_append_cstr(buf, size, "target datalayout = \"")
_append_cstr(buf, size, mod.DataLayout)
_append_cstr(buf, size, "\"\n")
# 空行
_append_cstr(buf, size, "\n")
# 命名结构体类型定义stub 和 full 模式输出text 模式不输出)
if mode == OUTPUT_FULL or mode == OUTPUT_STUB:
# 扫描所有函数签名,为跨模块结构体引用添加 opaque 定义
# 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义
# 修复alloc_buf 返回 viperio.Buf但 Buf 类型未在 NamedTypeHead 中注册
func_scan: Function | t.CPtr = mod.FuncHead
while func_scan is not None:
if func_scan.RetTy is not None:
module_ensure_opaque_for_type(mod, pool, func_scan.RetTy)
if func_scan.Params is not None:
param_scan: Param | t.CPtr = func_scan.Params.Head
while param_scan is not None:
if param_scan.Ty is not None:
module_ensure_opaque_for_type(mod, pool, param_scan.Ty)
param_scan = param_scan.Next
func_scan = func_scan.Next
nt: NamedTypeNode | t.CPtr = mod.NamedTypeHead
while nt is not None:
if nt.Ty is not None:
ty_buf: t.CChar | t.CPtr = pool.alloc(256)
if ty_buf is not None:
ty_buf[0] = '\0'
PrintStructDefinition(ty_buf, 256, nt.Ty, pool)
_append_cstr(buf, size, ty_buf)
_append_cstr(buf, size, "\n")
nt = nt.Next
if mod.NamedTypeHead is not None:
_append_cstr(buf, size, "\n")
# 全局变量
gv: GlobalVariable | t.CPtr = mod.GlobalHead
if mode == OUTPUT_STUB:
# stub 模式:输出 external global无初值
while gv is not None:
_print_global_stub(buf, size, gv, pool)
_append_cstr(buf, size, "\n")
gv = gv.Next
else:
# full 和 text 模式:输出完整全局变量
# text 模式跳过无初值的全局变量(纯声明)
gv_idx: t.CInt = 0
while gv is not None:
if mode == OUTPUT_TEXT and gv.Initializer is None:
gv = gv.Next
gv_idx += 1
continue
_print_global(buf, size, gv, pool)
_append_cstr(buf, size, "\n")
gv = gv.Next
gv_idx += 1
if mod.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB):
_append_cstr(buf, size, "\n")
elif mod.GlobalHead is not None and mode == OUTPUT_TEXT:
# text 模式下如果输出了全局变量,也加空行
had_global: t.CInt = 0
gv2: GlobalVariable | t.CPtr = mod.GlobalHead
while gv2 is not None:
if gv2.Initializer is not None:
had_global = 1
break
gv2 = gv2.Next
if had_global != 0:
_append_cstr(buf, size, "\n")
# 遍历函数
func: Function | t.CPtr = mod.FuncHead
func_idx: t.CInt = 0
while func is not None:
if mode == OUTPUT_STUB:
# stub 模式:仅输出 declareIsDeclared==1
if func.IsDeclared == 1:
FunctionPrint(buf, size, func, pool)
_append_cstr(buf, size, "\n")
elif mode == OUTPUT_TEXT:
# text 模式:仅输出 defineIsDeclared==0
if func.IsDeclared == 0:
FunctionPrint(buf, size, func, pool)
_append_cstr(buf, size, "\n")
else:
# full 模式:输出所有函数
FunctionPrint(buf, size, func, pool)
_append_cstr(buf, size, "\n")
func = func.Next
func_idx += 1
# ============================================================
# 全局变量打印
# ============================================================
def _print_global(buf: t.CChar | t.CPtr, size: t.CSizeT,
gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""打印单个全局变量: @<name> = [linkage] [unnamed_addr] [constant] <ty> <init>"""
if gv is None: return
_append_cstr(buf, size, "@")
if gv.Name is not None:
if _ll_name_needs_quote(gv.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, " = ")
# 链接类型(有初始值时不输出 external因为 external + 初始值是非法 IR
if gv.Linkage is not None:
if gv.Initializer is not None and string.strcmp(gv.Linkage, "external") == 0:
pass
else:
_append_cstr(buf, size, gv.Linkage)
_append_cstr(buf, size, " ")
# unnamed_addr
if gv.UnnamedAddr == 1:
_append_cstr(buf, size, "unnamed_addr ")
elif gv.UnnamedAddr == 2:
_append_cstr(buf, size, "local_unnamed_addr ")
# constant / global
if gv.IsConstant == 1:
_append_cstr(buf, size, "constant ")
else:
_append_cstr(buf, size, "global ")
# 类型
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
if ty_buf is not None:
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, gv.Ty, pool)
_append_cstr(buf, size, ty_buf)
# 初始化值
if gv.Initializer is not None:
_append_cstr(buf, size, " ")
_append_cstr(buf, size, gv.Initializer)
# 段名
if gv.Section is not None:
_append_cstr(buf, size, ", section \"")
_append_cstr(buf, size, gv.Section)
_append_cstr(buf, size, "\"")
# ============================================================
# _print_global_stub - 打印全局变量的声明形式external global无初值
# ============================================================
def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT,
gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""打印全局变量声明: @<name> = external global <ty>"""
if gv is None: return
_append_cstr(buf, size, "@")
if gv.Name is not None:
if _ll_name_needs_quote(gv.Name) != 0:
_append_cstr(buf, size, "\"")
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, "\"")
else:
_append_cstr(buf, size, gv.Name)
_append_cstr(buf, size, " = external global ")
# 类型
ty_buf: t.CChar | t.CPtr = pool.alloc(128)
if ty_buf is not None:
ty_buf[0] = '\0'
TypePrint(ty_buf, 128, gv.Ty, pool)
_append_cstr(buf, size, ty_buf)
# ============================================================
# 内部辅助
# ============================================================
def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 C 字符串 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'

View File

@@ -0,0 +1,524 @@
import t, c
from stdint import *
import viperlib
import string
import memhub
from linkedlist import GSListNode
# ============================================================
# ParamNode: 函数参数类型链表节点
# 继承 GSListNode[ParamNode] 获取强类型 Next: ParamNode|CPtr
# Ty 用 t.CVoid | t.CPtr 前向引用,使用时转型为 (LLVMType | t.CPtr)
# ============================================================
class ParamNode(GSListNode[ParamNode]):
Ty: t.CVoid | t.CPtr # LLVMType*(前向引用,使用时转型)
# ============================================================
# LLVMType: LLVM IR 类型系统t.REnum tagged union
#
# 变体少、无通用字段、操作通过 match 分派 —— 契合 REnum 模型。
# 布局: { i32 __tag, <max_variant_payload> }
# ============================================================
class LLVMType(t.REnum):
# 整数类型: i1/i8/i16/i32/i64
class Int:
Bits: t.CInt
# 指针类型: pointee*
class Ptr:
Pointee: LLVMType | t.CPtr
# 函数类型: ret (params)
class Func:
Ret: LLVMType | t.CPtr
Params: ParamNode | t.CPtr
PCount: t.CInt
# 数组类型: [N x elem_ty]
class Array:
ElemTy: LLVMType | t.CPtr
Count: t.CInt
# 结构体类型: {ty1, ty2, ...} 或 %"name" = type {ty1, ty2, ...}
# Fields 复用 ParamNode 链表ParamNode.Ty 即字段类型)
# Name 非 None 时为命名结构体TypePrint 输出 %"name" 而非 {...}
class Struct:
Fields: ParamNode | t.CPtr
FCount: t.CInt
Name: t.CChar | t.CPtr
# 浮点类型: half/float/double/fp128
class Float:
Bits: t.CInt # 16=half, 32=float, 64=double, 128=fp128
# 无值类型
class Void:
pass
# 标签类型
class Label:
pass
# 元数据类型
class Metadata:
pass
# ============================================================
# 内部分配辅助
# ============================================================
def _new_type(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""从 mpool 分配一个零初始化的 LLVMType"""
ptr: LLVMType | t.CPtr = pool.alloc(LLVMType.__sizeof__())
if ptr:
string.memset(ptr, 0, LLVMType.__sizeof__())
return ptr
# ============================================================
# 类型工厂函数
# ============================================================
def Int1(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(1))
return ptr
def Int8(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(8))
return ptr
def Int16(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(16))
return ptr
def Int32(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(32))
return ptr
def Int64(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Int(64))
return ptr
def Ptr(pool: memhub.MemBuddy | t.CPtr, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Ptr(pointee))
return ptr
def Func(pool: memhub.MemBuddy | t.CPtr, ret: LLVMType | t.CPtr,
params: ParamNode | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Func(ret, params, count))
return ptr
def Void(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Void())
return ptr
def Array(pool: memhub.MemBuddy | t.CPtr, elem_ty: LLVMType | t.CPtr,
count: t.CInt) -> LLVMType | t.CPtr:
"""创建数组类型 [count x elem_ty]"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Array(elem_ty, count))
return ptr
def Struct(pool: memhub.MemBuddy | t.CPtr, fields: ParamNode | t.CPtr,
fcount: t.CInt, name: t.CChar | t.CPtr) -> LLVMType | t.CPtr:
"""创建结构体类型 {ty1, ty2, ...}
fields 为 ParamNode 链表头fcount 为字段数量。
name 非 None 时为命名结构体(如 "sha1.ClassName"TypePrint 输出 %"name"
name 为 None 时为匿名结构体TypePrint 输出 {ty1, ty2, ...}。
"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Struct(fields, fcount, name))
return ptr
def Half(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建半精度浮点类型 half (16-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(16))
return ptr
def Float(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建单精度浮点类型 float (32-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(32))
return ptr
def Double(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建双精度浮点类型 double (64-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(64))
return ptr
def FP128(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建四精度浮点类型 fp128 (128-bit)"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Float(128))
return ptr
def Label(pool: memhub.MemBuddy | t.CPtr) -> LLVMType | t.CPtr:
"""创建标签类型 label"""
ptr: LLVMType | t.CPtr = _new_type(pool)
if ptr is None: return None
c.DerefAs(ptr, LLVMType.Label())
return ptr
# ============================================================
# ParamNode 辅助
# ============================================================
# ParamNode 硬编码大小: Next(8) + Ty(8) = 16 字节
PNODE_SIZE: t.CDefine = 16
def new_param_node(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr:
"""创建一个参数节点Ty 设为给定类型指针"""
ptr: ParamNode | t.CPtr = pool.alloc(PNODE_SIZE)
if ptr is None: return None
string.memset(ptr, 0, PNODE_SIZE)
ptr.Ty = ty
ptr.Next = None
return ptr
def param_list_append(head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr,
node: ParamNode | t.CPtr) -> ParamNode | t.CPtr:
"""将 node 追加到参数链表尾部,返回 head 和更新后的 tail"""
if node is None: return head
node.Next = None
if head is None:
return node
if tail is not None:
tail.Next = node
return node
# ============================================================
# ParamNode 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 ParamNode 的 stub 类型,
# 导致 TransPyC 静默跳过字段访问。这些访问器在拥有完整类型定义的
# 本模块内执行,能正确访问所有字段。
# ============================================================
def paramnode_get_ty(node: ParamNode | t.CPtr) -> LLVMType | t.CPtr:
"""获取参数节点的类型"""
if node is None:
return None
return (LLVMType | t.CPtr)(node.Ty)
def paramnode_get_next(node: ParamNode | t.CPtr) -> ParamNode | t.CPtr:
"""获取链表下一个参数节点"""
if node is None:
return None
return node.Next
def paramnode_set_ty(node: ParamNode | t.CPtr, ty: LLVMType | t.CPtr):
"""设置参数节点的类型"""
if node is None:
return
node.Ty = ty
def paramnode_set_next(node: ParamNode | t.CPtr, nxt: ParamNode | t.CPtr):
"""设置链表下一个参数节点"""
if node is None:
return
node.Next = nxt
# ============================================================
# LLVMTypeCore: 类型创建核心,封装 pool 避免重复传参
#
# 用法:
# core: LLVMTypeCore | t.CPtr = LLVMTypeCore(pool)
# ty_i32: LLVMType | t.CPtr = core.Int32()
# ty_ptr: LLVMType | t.CPtr = core.Ptr(ty_i32)
# ty_void: LLVMType | t.CPtr = core.Void()
# ============================================================
@t.NoVTable
class LLVMTypeCore:
"""类型创建核心,封装 pool 避免每次创建类型都传 pool"""
Pool: memhub.MemBuddy | t.CPtr
def __init__(self, pool: memhub.MemBuddy | t.CPtr):
self.Pool = pool
def Int1(self) -> LLVMType | t.CPtr:
return Int1(self.Pool)
def Int8(self) -> LLVMType | t.CPtr:
return Int8(self.Pool)
def Int16(self) -> LLVMType | t.CPtr:
return Int16(self.Pool)
def Int32(self) -> LLVMType | t.CPtr:
return Int32(self.Pool)
def Int64(self) -> LLVMType | t.CPtr:
return Int64(self.Pool)
def Ptr(self, pointee: LLVMType | t.CPtr) -> LLVMType | t.CPtr:
return Ptr(self.Pool, pointee)
def Func(self, ret: LLVMType | t.CPtr, params: ParamNode | t.CPtr,
count: t.CInt) -> LLVMType | t.CPtr:
return Func(self.Pool, ret, params, count)
def Array(self, elem_ty: LLVMType | t.CPtr, count: t.CInt) -> LLVMType | t.CPtr:
return Array(self.Pool, elem_ty, count)
def Struct(self, fields: ParamNode | t.CPtr, fcount: t.CInt,
name: t.CChar | t.CPtr) -> LLVMType | t.CPtr:
return Struct(self.Pool, fields, fcount, name)
def Void(self) -> LLVMType | t.CPtr:
return Void(self.Pool)
def Half(self) -> LLVMType | t.CPtr:
return Half(self.Pool)
def Float(self) -> LLVMType | t.CPtr:
return Float(self.Pool)
def Double(self) -> LLVMType | t.CPtr:
return Double(self.Pool)
def FP128(self) -> LLVMType | t.CPtr:
return FP128(self.Pool)
def Label(self) -> LLVMType | t.CPtr:
return Label(self.Pool)
def NewParamNode(self, ty: LLVMType | t.CPtr) -> ParamNode | t.CPtr:
return new_param_node(self.Pool, ty)
# ---- 链表辅助 ----
def ParamListAppend(self, head: ParamNode | t.CPtr, tail: ParamNode | t.CPtr,
node: ParamNode | t.CPtr) -> ParamNode | t.CPtr:
"""将 node 追加到参数/字段链表,返回新的 tail"""
return param_list_append(head, tail, node)
# ---- 打印 ----
def PrintType(self, buf: t.CChar | t.CPtr, size: t.CSizeT, ty: LLVMType | t.CPtr):
TypePrint(buf, size, ty, self.Pool)
# ============================================================
# TypePrint: 将 LLVMType 序列化为 IR 文本
#
# 示例:
# Int(32) -> "i32"
# Int(8) -> "i8"
# Ptr(Int(32)) -> "i32*"
# Void -> "void"
# Array(Int(32),4) -> "[4 x i32]"
# Struct(...) -> "{i32, i8*}"
# Func(...) -> "i32 (i32, i8*)"
#
# pool 用于复杂类型Array/Struct/Func递归打印子类型时分配临时缓冲区。
# ============================================================
def TypePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""将类型 ty 序列化为 IR 文本写入 buf容量 size
pool 用于递归打印子类型时分配临时缓冲区。
"""
if ty is None or buf is None or size == 0:
return
buf[0] = '\0'
match ty:
case LLVMType.Int(bits):
viperlib.snprintf(buf, size, "i%d", bits)
case LLVMType.Ptr(pointee):
# 先打印 pointee再追加 '*'
TypePrint(buf, size, pointee, pool)
pos: t.CSizeT = string.strlen(buf)
if pos + 1 < size:
buf[pos] = '*'
buf[pos + 1] = '\0'
case LLVMType.Array(elem_ty, count):
# [N x elem_ty]
viperlib.snprintf(buf, size, "[%d x ", count)
tmp: t.CChar | t.CPtr = pool.alloc(128)
if tmp is not None:
TypePrint(tmp, 128, elem_ty, pool)
_strappend(buf, size, tmp)
_strappend(buf, size, "]")
case LLVMType.Struct(fields, fcount, name):
if name is not None:
# 命名结构体: %"name"
buf[0] = '%'
buf[1] = '"'
buf[2] = '\0'
_strappend(buf, size, name)
_strappend(buf, size, "\"")
else:
# 匿名结构体: {ty1, ty2, ...}
_print_struct_body(buf, size, fields, pool)
case LLVMType.Func(ret, params, count):
# ret (ty1, ty2, ...)
TypePrint(buf, size, ret, pool)
_strappend(buf, size, " (")
cur2: ParamNode | t.CPtr = params
first2: t.CInt = 1
tmp3: t.CChar | t.CPtr = pool.alloc(128)
while cur2 is not None:
if first2 == 0:
_strappend(buf, size, ", ")
if tmp3 is not None:
TypePrint(tmp3, 128, cur2.Ty, pool)
_strappend(buf, size, tmp3)
cur2 = cur2.Next
first2 = 0
_strappend(buf, size, ")")
case LLVMType.Void():
string.strcpy(buf, "void")
case LLVMType.Label():
string.strcpy(buf, "label")
case LLVMType.Metadata():
string.strcpy(buf, "metadata")
case LLVMType.Float(bits):
if bits == 16:
string.strcpy(buf, "half")
elif bits == 32:
string.strcpy(buf, "float")
elif bits == 64:
string.strcpy(buf, "double")
elif bits == 128:
string.strcpy(buf, "fp128")
else:
viperlib.snprintf(buf, size, "float%x", bits)
case _:
string.strcpy(buf, "void")
# ============================================================
# 内部辅助
# ============================================================
def _strappend(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 src 追加到 dst 末尾(不超过 dst_size"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
# ============================================================
# _print_struct_body - 打印结构体字段部分 {ty1, ty2, ...}
#
# 供 TypePrint匿名结构体和 PrintStructDefinition命名结构体定义行复用
# ============================================================
def _print_struct_body(buf: t.CChar | t.CPtr, size: t.CSizeT,
fields: ParamNode | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""打印 {ty1, ty2, ...} 到 buf追加模式不覆盖已有内容"""
if buf is None or size == 0:
return
_strappend(buf, size, "{")
cur: ParamNode | t.CPtr = fields
first: t.CInt = 1
tmp: t.CChar | t.CPtr = pool.alloc(128)
while cur is not None:
if first == 0:
_strappend(buf, size, ", ")
if tmp is not None:
TypePrint(tmp, 128, cur.Ty, pool)
_strappend(buf, size, tmp)
cur = cur.Next
first = 0
_strappend(buf, size, "}")
# ============================================================
# PrintStructDefinition - 打印命名结构体类型定义行
#
# 输出格式: %"name" = type { ty1, ty2, ... }
# 供 LLVMModulePrint 在全局变量/函数之前输出类型定义
# ============================================================
def PrintStructDefinition(buf: t.CChar | t.CPtr, size: t.CSizeT,
ty: LLVMType | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""打印命名结构体类型定义行 %"name" = type { ty1, ty2, ... }
当 fcount==0 且 fields is None 时,输出 opaque 声明: %"name" = type opaque
"""
if ty is None or buf is None or size == 0:
return
match ty:
case LLVMType.Struct(fields, fcount, name):
if name is None:
return
buf[0] = '%'
buf[1] = '"'
buf[2] = '\0'
_strappend(buf, size, name)
# opaque 类型: fcount==0 且 fields is None跨模块前向声明
if fcount == 0 and fields is None:
_strappend(buf, size, "\" = type opaque")
else:
_strappend(buf, size, "\" = type ")
_print_struct_body(buf, size, fields, pool)
case _:
return
# ============================================================
# get_struct_name - 获取命名结构体的名称
#
# 返回 Name 字段(如 "sha1.ClassName"),非 Struct 类型或匿名 Struct 返回 None
# 供 module_add_named_type 检查是否为命名结构体及去重
# ============================================================
def get_struct_name(ty: LLVMType | t.CPtr) -> t.CChar | t.CPtr:
"""获取命名结构体的名称,非命名结构体返回 None"""
if ty is None:
return None
match ty:
case LLVMType.Struct(fields, fcount, name):
return name
case _:
return None

View File

@@ -0,0 +1,212 @@
import t, c
from stdint import *
import string
import viperlib
import memhub
from linkedlist import GSListNode
from .__types import LLVMType, TypePrint
# ============================================================
# Value: SSA 值表示
#
# 表示一个 LLVM IR 值SSA 临时值(%0/%result或常量字面量42/0
# 每个值有类型指针、名字、是否常量标志。
# 继承 GSListNode[Value] 获取强类型 Next: Value|CPtr值池链表
# ============================================================
class Value(GSListNode[Value]):
Ty: LLVMType | t.CPtr # 值的类型
Name: t.CChar | t.CPtr # SSA 名("%0"/"%result")或常量文本("42"/"1.5e+00"
IsConst: t.CInt # 1=常量字面量, 0=SSA 临时值
IntVal: t.CInt64T # 整数常量值(当 IsConst=1 时使用)
FloatVal: t.CDouble # 浮点常量值(当 IsConst=1 且 Ty 为 Float 时使用)
# ============================================================
# 工厂函数
# ============================================================
# Value 硬编码大小: Next(8) + Ty(8) + Name(8) + IsConst(4) + IntVal(8) + FloatVal(8) = 48 字节
VALUE_SIZE: t.CDefine = 48
def new_value(pool: memhub.MemBuddy | t.CPtr) -> Value | t.CPtr:
"""从 mpool 分配一个零初始化的 Value"""
ptr: Value | t.CPtr = pool.alloc(VALUE_SIZE)
if ptr:
string.memset(ptr, 0, VALUE_SIZE)
return ptr
def ConstInt(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
val: t.CInt64T, name: t.CChar | t.CPtr) -> Value | t.CPtr:
"""创建整数常量值
参数:
ty: 整数类型Int1/Int8/Int32/Int64
val: 整数值
name: 常量文本(如 "42"),由调用方提供
"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 1
v.IntVal = val
return v
def ConstNull(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Value | t.CPtr:
"""创建 null 指针常量"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 1
v.IntVal = 0
return v
def ConstZero(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr) -> Value | t.CPtr:
"""创建 zeroinitializer 常量(零初始化聚合类型:结构体/数组)"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = "zeroinitializer"
v.IsConst = 1
v.IntVal = 0
return v
def ConstFloat(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
val: t.CDouble) -> Value | t.CPtr:
"""创建浮点常量值
参数:
ty: 浮点类型Half/Float/Double/FP128
val: 浮点数值
名字自动格式化为 LLVM IR 科学计数法文本(如 "1.500000e+00")。
"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.IsConst = 1
v.FloatVal = val
v.IntVal = 0
# 格式化名字: LLVM IR 使用 "%e" 科学计数法6 位小数)
name_buf: t.CChar | t.CPtr = pool.alloc(32)
if name_buf is not None:
viperlib.snprintf(name_buf, 32, "%e", val)
v.Name = name_buf
return v
def SSAValue(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr,
name: t.CChar | t.CPtr) -> Value | t.CPtr:
"""创建 SSA 临时值
参数:
ty: 值类型
name: SSA 名(如 "%0"/"%result"),由调用方提供
"""
v: Value | t.CPtr = new_value(pool)
if v is None: return None
v.Ty = ty
v.Name = name
v.IsConst = 0
v.IntVal = 0
return v
# ============================================================
# ValuePrint: 将值序列化为 IR 文本
#
# 示例:
# ConstInt(i32, 42, "42") -> "i32 42"
# SSAValue(i32, "%0") -> "i32 %0"
# ============================================================
def ValuePrint(buf: t.CChar | t.CPtr, size: t.CSizeT,
val: Value | t.CPtr, pool: memhub.MemBuddy | t.CPtr):
"""将值 val 序列化为 IR 文本写入 buf
格式: <type> <name>
pool 用于复杂类型Array/Struct/Func递归打印时分配临时缓冲区。
"""
if val is None or buf is None or size == 0:
return
# 先写类型
TypePrint(buf, size, val.Ty, pool)
# 追加空格
pos: t.CSizeT = string.strlen(buf)
if pos + 1 < size:
buf[pos] = ' '
buf[pos + 1] = '\0'
# 追加名字
if val.Name is not None:
pos = string.strlen(buf)
_append_str(buf, size, val.Name)
# ============================================================
# Value 字段访问器(供其他模块绕过 stub 类型限制使用)
#
# 跨模块编译时,使用方模块只有 Value 的 stub 类型(字段不足或偏移错误),
# 导致 TransPyC 静默跳过字段访问(不生成 GEP不报错
# 这些访问器在拥有完整类型定义的本模块内执行,能正确访问所有字段。
# ============================================================
def value_get_ty(val: Value | t.CPtr) -> LLVMType | t.CPtr:
"""获取值的类型"""
if val is None:
return None
return val.Ty
def value_get_next(val: Value | t.CPtr) -> Value | t.CPtr:
"""获取链表下一个值"""
if val is None:
return None
return val.Next
def value_set_ty(val: Value | t.CPtr, ty: LLVMType | t.CPtr):
"""设置值的类型"""
if val is None:
return
val.Ty = ty
def value_set_next(val: Value | t.CPtr, nxt: Value | t.CPtr):
"""设置链表下一个值"""
if val is None:
return
val.Next = nxt
def value_set_name(val: Value | t.CPtr, name: t.CChar | t.CPtr):
"""设置值的名字"""
if val is None:
return
val.Name = name
def value_set_isconst(val: Value | t.CPtr, is_const: t.CInt):
"""设置是否为常量"""
if val is None:
return
val.IsConst = is_const
# ============================================================
# 内部辅助
# ============================================================
def _append_str(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'

View File

@@ -0,0 +1,396 @@
import t, c
from stdint import *
import string
import viperlib
import memhub
from linkedlist import GSListNode, GSList
from .__function import Function, BasicBlock, Line, Param
from .__module import LLVMModule
# ============================================================
# SSA 验证器
#
# 检查项:
# 1. 块终止: 每个基本块必须以终止指令结尾 (ret/br/switch/unreachable)
# 2. SSA 唯一性: 每个 %name 只能被定义一次
# 3. 未定义引用: 所有 %name 使用必须有对应定义
# 4. Phi 位置: phi 指令只能出现在块首(非 phi 指令之前)
# ============================================================
# 错误码
VERIFY_OK: t.CDefine = 0
VERIFY_ERR_NO_TERMINATOR: t.CDefine = 1
VERIFY_ERR_DUPLICATE_DEF: t.CDefine = 2
VERIFY_ERR_UNDEFINED_USE: t.CDefine = 3
VERIFY_ERR_PHI_NOT_FIRST: t.CDefine = 4
# ============================================================
# NameEntry: 已定义 SSA 名条目(链表节点)
# ============================================================
class NameEntry(GSListNode[NameEntry]):
Name: t.CChar | t.CPtr # SSA 名(如 "%0"/"%result"
# ============================================================
# VerifyResult: 验证结果
# ============================================================
class VerifyResult:
ErrorCount: t.CInt # 错误总数
WarningCount: t.CInt # 警告总数
ErrorCode: t.CInt # 第一个错误码
ErrorBuf: t.CChar | t.CPtr # 错误消息缓冲区
ErrorBufSize: t.CSizeT # 缓冲区大小
# ============================================================
# 辅助函数
# ============================================================
def _new_verify_result(pool: memhub.MemBuddy | t.CPtr,
buf_size: t.CSizeT) -> VerifyResult | t.CPtr:
"""创建验证结果对象"""
ptr: VerifyResult | t.CPtr = pool.alloc(VerifyResult.__sizeof__())
if ptr is None: return None
string.memset(ptr, 0, VerifyResult.__sizeof__())
ptr.ErrorCount = 0
ptr.WarningCount = 0
ptr.ErrorCode = VERIFY_OK
buf: t.CChar | t.CPtr = pool.alloc(buf_size)
if buf is not None:
buf[0] = '\0'
ptr.ErrorBuf = buf
ptr.ErrorBufSize = buf_size
return ptr
def _report_error(result: VerifyResult | t.CPtr, code: t.CInt, msg: t.CChar | t.CPtr):
"""记录一个错误"""
if result is None: return
result.ErrorCount += 1
if result.ErrorCode == VERIFY_OK:
result.ErrorCode = code
if result.ErrorBuf is not None and msg is not None:
_append_cstr(result.ErrorBuf, result.ErrorBufSize, msg)
_append_cstr(result.ErrorBuf, result.ErrorBufSize, "\n")
def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr):
"""将 src 追加到 dst 末尾"""
if dst is None or src is None: return
dlen: t.CSizeT = string.strlen(dst)
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0: return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
# ============================================================
# SSA 名表操作
# ============================================================
def _new_name_table(pool: memhub.MemBuddy | t.CPtr) -> GSList[NameEntry] | t.CPtr:
"""创建空名表"""
gsl: GSList[NameEntry] | t.CPtr = pool.alloc(24) # GSList: Head+Tail+Count
if gsl is None: return None
string.memset(gsl, 0, 24)
return gsl
# NameEntry 硬编码大小: Next(8) + Name(8) = 16 字节
NENTRY_SIZE: t.CDefine = 16
def _name_table_add(table: GSList[NameEntry] | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
name: t.CChar | t.CPtr) -> t.CInt:
"""添加名到表。返回 1=重复, 0=成功添加"""
if table is None or name is None: return 0
# 检查重复
cur: NameEntry | t.CPtr = table.Head
while cur is not None:
if string.strcmp(cur.Name, name) == 0:
return 1
cur = cur.Next
# 添加新条目
entry: NameEntry | t.CPtr = pool.alloc(NENTRY_SIZE)
if entry is None: return 0
string.memset(entry, 0, NENTRY_SIZE)
entry.Name = name
table.append(entry)
return 0
def _name_table_contains(table: GSList[NameEntry] | t.CPtr,
name: t.CChar | t.CPtr) -> t.CInt:
"""检查名是否在表中。返回 1=存在, 0=不存在"""
if table is None or name is None: return 0
cur: NameEntry | t.CPtr = table.Head
while cur is not None:
if string.strcmp(cur.Name, name) == 0:
return 1
cur = cur.Next
return 0
# ============================================================
# 文本分析辅助
# ============================================================
def _is_char_name(ch: t.CChar) -> t.CInt:
"""判断字符是否为 SSA 名字符 [a-zA-Z0-9._]"""
if ch >= 'a' and ch <= 'z': return 1
if ch >= 'A' and ch <= 'Z': return 1
if ch >= '0' and ch <= '9': return 1
if ch == '.' or ch == '_': return 1
return 0
def _extract_def_name(pool: memhub.MemBuddy | t.CPtr,
text: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
"""从定义行提取被定义的 SSA 名。
定义行格式: "%<name> = <instruction>"
返回分配的 NUL 结尾名串(如 "%0"),或 None 若非定义行。
"""
if text is None: return None
if text[0] != '%': return None
# 扫描 " = " 模式
i: t.CInt = 1
while text[i] != '\0':
if text[i] == ' ' and text[i + 1] == '=' and text[i + 2] == ' ':
# 找到 " = " 在位置 i
name_len: t.CInt = i
name: t.CChar | t.CPtr = pool.alloc(name_len + 1)
if name is None: return None
j: t.CInt = 0
while j < name_len:
name[j] = text[j]
j += 1
name[name_len] = '\0'
return name
i += 1
return None
def _is_terminator(text: t.CChar | t.CPtr) -> t.CInt:
"""判断文本是否为终止指令"""
if text is None: return 0
if string.strncmp(text, "ret", 3) == 0: return 1
if string.strncmp(text, "br ", 3) == 0: return 1
if string.strncmp(text, "switch ", 7) == 0: return 1
if string.strncmp(text, "unreachable", 11) == 0: return 1
if string.strncmp(text, "indirectbr ", 11) == 0: return 1
if string.strncmp(text, "resume ", 7) == 0: return 1
return 0
def _is_phi(text: t.CChar | t.CPtr) -> t.CInt:
"""判断文本是否为 phi 指令"""
if text is None: return 0
if string.strstr(text, " = phi ") is not None: return 1
return 0
def _check_uses_in_line(table: GSList[NameEntry] | t.CPtr,
text: t.CChar | t.CPtr,
def_name: t.CChar | t.CPtr) -> t.CInt:
"""检查行中所有 SSA 名使用是否已定义。
跳过 def_name定义位置的名字
返回未定义使用数量。
"""
if text is None: return 0
i: t.CInt = 0
undef_count: t.CInt = 0
while text[i] != '\0':
if text[i] == '%':
# 提取名
name_start: t.CInt = i
i += 1
while text[i] != '\0' and _is_char_name(text[i]) == 1:
i += 1
name_len: t.CInt = i - name_start
if name_len > 1:
# 构建临时名串进行比较
# 由于无法在栈上分配,用 strstr 进行简化检查
# 这里采用逐字符比较方式
if _name_matches_at(text, name_start, name_len, table) == 0:
# 检查是否是 def_name定义本身的位置
if def_name is not None:
if _str_matches_at(text, name_start, name_len, def_name) == 0:
undef_count += 1
else:
undef_count += 1
else:
i += 1
return undef_count
def _name_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt,
table: GSList[NameEntry] | t.CPtr) -> t.CInt:
"""检查 text[start:start+length] 是否匹配名表中的某个条目。
返回 1=匹配, 0=不匹配
"""
if table is None: return 0
cur: NameEntry | t.CPtr = table.Head
while cur is not None:
if cur.Name is not None:
if _str_matches_at(text, start, length, cur.Name) == 1:
return 1
cur = cur.Next
return 0
def _str_matches_at(text: t.CChar | t.CPtr, start: t.CInt, length: t.CInt,
target: t.CChar | t.CPtr) -> t.CInt:
"""检查 text[start:start+length] 是否等于 target 字符串。
返回 1=匹配, 0=不匹配
"""
if text is None or target is None: return 0
# 检查 target 长度
target_len: t.CInt = string.strlen(target)
if target_len != length: return 0
i: t.CInt = 0
while i < length:
if text[start + i] != target[i]: return 0
i += 1
return 1
# ============================================================
# 主验证函数
# ============================================================
def verify_function(pool: memhub.MemBuddy | t.CPtr,
func: Function | t.CPtr,
result: VerifyResult | t.CPtr) -> t.CInt:
"""验证函数的 SSA 正确性。
参数:
pool: 内存池
func: 要验证的函数
result: 验证结果(调用前需用 _new_verify_result 创建)
返回: 错误数量0 = 验证通过)
"""
if func is None or result is None: return 1
# 创建名表
name_table: GSList[NameEntry] | t.CPtr = _new_name_table(pool)
if name_table is None: return 1
# 1. 将函数参数加入名表(参数是已定义的)
param: Param | t.CPtr = None
if func.Params is not None:
param = func.Params.Head
while param is not None:
if param.Name is not None:
_name_table_add(name_table, pool, param.Name)
param = param.Next
# 1b. 将基本块名加入名表(块标签如 %then 是 br/phi 的合法引用目标)
blk_iter: BasicBlock | t.CPtr = None
if func.Blocks is not None:
blk_iter = func.Blocks.Head
while blk_iter is not None:
if blk_iter.Name is not None:
blk_name_len: t.CSizeT = string.strlen(blk_iter.Name)
blk_ref: t.CChar | t.CPtr = pool.alloc(blk_name_len + 2)
if blk_ref is not None:
# 构造 "%<name>" 字符串
blk_ref[0] = '%'
k: t.CSizeT = 0
while k < blk_name_len:
blk_ref[k + 1] = blk_iter.Name[k]
k += 1
blk_ref[blk_name_len + 1] = '\0'
_name_table_add(name_table, pool, blk_ref)
blk_iter = blk_iter.Next
# 2. 遍历所有块
blk: BasicBlock | t.CPtr = None
if func.Blocks is not None:
blk = func.Blocks.Head
while blk is not None:
# 检查终止指令
if blk.IsTerminated == 0:
# 进一步检查最后一行是否为终止指令
has_term: t.CInt = 0
line_check: Line | t.CPtr = None
if blk.Lines is not None:
line_check = blk.Lines.Head
while line_check is not None:
if line_check.Buf is not None:
if _is_terminator(line_check.Buf) == 1:
has_term = 1
line_check = line_check.Next
if has_term == 0:
blk_name: t.CChar | t.CPtr = "<unnamed>"
if blk.Name is not None:
blk_name = blk.Name
err_buf: t.CChar | t.CPtr = pool.alloc(128)
if err_buf is not None:
viperlib.snprintf(err_buf, 128, "ERROR: block '%s' missing terminator", blk_name)
_report_error(result, VERIFY_ERR_NO_TERMINATOR, err_buf)
# 遍历块内指令行
seen_non_phi: t.CInt = 0
line: Line | t.CPtr = None
if blk.Lines is not None:
line = blk.Lines.Head
while line is not None:
if line.Buf is not None:
text: t.CChar | t.CPtr = line.Buf
# 检查 phi 位置
if _is_phi(text) == 1:
if seen_non_phi == 1:
phi_err: t.CChar | t.CPtr = pool.alloc(128)
if phi_err is not None:
viperlib.snprintf(phi_err, 128, "ERROR: phi not at block start")
_report_error(result, VERIFY_ERR_PHI_NOT_FIRST, phi_err)
else:
# 非空行且非 phi 标记为已见非 phi
if string.strlen(text) > 0:
seen_non_phi = 1
# 提取定义名
def_name: t.CChar | t.CPtr = _extract_def_name(pool, text)
if def_name is not None:
# 检查重复定义
dup: t.CInt = _name_table_add(name_table, pool, def_name)
if dup == 1:
dup_err: t.CChar | t.CPtr = pool.alloc(128)
if dup_err is not None:
viperlib.snprintf(dup_err, 128, "ERROR: duplicate definition '%s'", def_name)
_report_error(result, VERIFY_ERR_DUPLICATE_DEF, dup_err)
# 检查未定义使用
undef: t.CInt = _check_uses_in_line(name_table, text, def_name)
if undef > 0:
use_err: t.CChar | t.CPtr = pool.alloc(128)
if use_err is not None:
viperlib.snprintf(use_err, 128, "ERROR: %d undefined use(s) in: %s", undef, text)
_report_error(result, VERIFY_ERR_UNDEFINED_USE, use_err)
line = line.Next
blk = blk.Next
return result.ErrorCount
def verify_module(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, result: VerifyResult | t.CPtr) -> t.CInt:
"""验证模块中所有函数的 SSA 正确性。
返回: 错误总数
"""
if mod is None or result is None: return 1
func: Function | t.CPtr = mod.FuncHead
while func is not None:
if func.IsDeclared == 0:
# 只验证有函数体的定义,跳过声明
verify_function(pool, func, result)
func = func.Next
return result.ErrorCount