snapshot before regression test
This commit is contained in:
301
includes/llvmlite/README.md
Normal file
301
includes/llvmlite/README.md
Normal 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)与具体 opcode(Add/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+union(Rust 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: ...
|
||||
```
|
||||
|
||||
### 指令 opcode(CEnum)
|
||||
|
||||
```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 而非胖节点)
|
||||
1220
includes/llvmlite/__builder.py
Normal file
1220
includes/llvmlite/__builder.py
Normal file
File diff suppressed because it is too large
Load Diff
456
includes/llvmlite/__function.py
Normal file
456
includes/llvmlite/__function.py
Normal 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
|
||||
403
includes/llvmlite/__init__.py
Normal file
403
includes/llvmlite/__init__.py
Normal 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 字符串,不含末尾 NUL,NUL 由本函数自动添加)
|
||||
|
||||
返回: 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)
|
||||
504
includes/llvmlite/__module.py
Normal file
504
includes/llvmlite/__module.py
Normal 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/Count,O(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 # 完整 IR(stub + 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 模式:仅输出 declare(IsDeclared==1)
|
||||
if func.IsDeclared == 1:
|
||||
FunctionPrint(buf, size, func, pool)
|
||||
_append_cstr(buf, size, "\n")
|
||||
elif mode == OUTPUT_TEXT:
|
||||
# text 模式:仅输出 define(IsDeclared==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'
|
||||
524
includes/llvmlite/__types.py
Normal file
524
includes/llvmlite/__types.py
Normal 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
|
||||
|
||||
|
||||
|
||||
212
includes/llvmlite/__values.py
Normal file
212
includes/llvmlite/__values.py
Normal 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'
|
||||
396
includes/llvmlite/__verify.py
Normal file
396
includes/llvmlite/__verify.py
Normal 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
|
||||
Reference in New Issue
Block a user