Files
TransPyV/App/lib/core/Handles/HandlesExprCall.py
2026-07-19 13:18:46 +08:00

3973 lines
186 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import sys
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
# ============================================================
# 全局模块 SHA1 映射module_name → SHA1
#
# 翻译时用于跨模块函数调用名混淆:
# string.strchr(...) → call @{sha1_of_string}.strchr(...)
#
# 通过 set_module_sha1_map 设置_lookup_module_sha1 查询
# ============================================================
_g_sha1_arr: bytes = None
_g_mod_arr: bytes = None
_g_sha1_count: int = 0
def set_module_sha1_map(sha1_arr: bytes, mod_arr: bytes, count: int) -> int:
"""设置全局模块 SHA1 映射"""
global _g_sha1_arr
global _g_mod_arr
global _g_sha1_count
_g_sha1_arr = sha1_arr
_g_mod_arr = mod_arr
_g_sha1_count = count
return 0
def _lookup_module_sha1(mod_name: str) -> str:
"""查找模块名对应的 SHA1找不到返回 None"""
if mod_name is None:
return None
if _g_sha1_arr is None or _g_mod_arr is None:
return None
if _g_sha1_count <= 0:
return None
for i in range(_g_sha1_count):
idx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(_g_mod_arr + idx, mod_name) == 0:
sidx: t.CSizeT = t.CSizeT(i) * 17
return _g_sha1_arr + sidx
return None
def _lookup_module_sha1_suffix(mod_suffix: str) -> str:
"""后缀匹配查找模块 SHA1如 mod_suffix="__types" 匹配 "llvmlite.__types"
用于 from .X import Y 的相对导入impf.module 是 ".X"(带前导点),
去掉前导点后为 "X"SHA1 映射表中键是 "pkg.X",需要后缀匹配。
"""
if mod_suffix is None:
return None
if _g_sha1_arr is None or _g_mod_arr is None:
return None
if _g_sha1_count <= 0:
return None
suffix_len: t.CSizeT = string.strlen(mod_suffix)
if suffix_len == 0:
return None
for i in range(_g_sha1_count):
idx: t.CSizeT = t.CSizeT(i) * 64
mod_name: str = _g_mod_arr + idx
mod_len: t.CSizeT = string.strlen(mod_name)
if mod_len < suffix_len:
continue
# 精确匹配
if mod_len == suffix_len:
if string.strcmp(mod_name, mod_suffix) == 0:
sidx: t.CSizeT = t.CSizeT(i) * 17
return _g_sha1_arr + sidx
# 后缀匹配mod_name 以 "." + mod_suffix 结尾
if mod_len > suffix_len:
if mod_name[mod_len - suffix_len - 1] == '.':
cmp_start: str = mod_name + mod_len - suffix_len
if string.strcmp(cmp_start, mod_suffix) == 0:
sidx2: t.CSizeT = t.CSizeT(i) * 17
return _g_sha1_arr + sidx2
return None
# ============================================================
# 全局 CExport 函数表module_sha1 + func_name
#
# t.CExport 函数定义时不加 SHA1 前缀(如 @strlen
# 跨模块调用时需要查表确认目标函数是否是 CExport 函数。
# 若是,使用裸名调用(@strlen否则使用 @{sha1}.func。
# 必须包含模块 SHA1 记录,避免同名跨模块函数冲突
# (一个模块有 CExport 的 strlen→@strlen另一个没有→@{sha1}.strlen
# ============================================================
_g_cexport_sha1_arr: bytes = None
_g_cexport_func_arr: bytes = None
_g_cexport_count: int = 0
_CEXPORT_MAX: t.CDefine = 256
def register_cexport_func(sha1: str, func_name: str) -> int:
"""注册 CExport 函数到全局表sha1+func_name 二元组)"""
global _g_cexport_sha1_arr
global _g_cexport_func_arr
global _g_cexport_count
if sha1 is None or func_name is None:
return 0
if _g_cexport_sha1_arr is None:
_g_cexport_sha1_arr = stdlib.malloc(_CEXPORT_MAX * 17)
_g_cexport_func_arr = stdlib.malloc(_CEXPORT_MAX * 64)
if _g_cexport_sha1_arr is None or _g_cexport_func_arr is None:
return 0
string.memset(_g_cexport_sha1_arr, 0, _CEXPORT_MAX * 17)
string.memset(_g_cexport_func_arr, 0, _CEXPORT_MAX * 64)
if _g_cexport_count < _CEXPORT_MAX:
idx: t.CSizeT = t.CSizeT(_g_cexport_count) * 17
string.strcpy(_g_cexport_sha1_arr + idx, sha1)
idx2: t.CSizeT = t.CSizeT(_g_cexport_count) * 64
string.strcpy(_g_cexport_func_arr + idx2, func_name)
_g_cexport_count += 1
return 1
return 0
def is_cexport_func(sha1: str, func_name: str) -> int:
"""检查 (sha1, func_name) 是否是 CExport 函数"""
if sha1 is None or func_name is None:
return 0
if _g_cexport_sha1_arr is None:
return 0
for i in range(_g_cexport_count):
idx: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(_g_cexport_sha1_arr + idx, sha1) == 0:
idx2: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(_g_cexport_func_arr + idx2, func_name) == 0:
return 1
return 0
# ============================================================
# _lookup_mod_sha1 - 从 from_imports 查找类所属模块的 SHA1
#
# lookup_from_import 返回指向 from_imports 内部的指针,不是 null 终止
# (如 "namespace_defs Gadget:namespace_defs ...")。此函数手动截断
# 模块名,复制到新缓冲区,再查找 SHA1精确+后缀匹配)。
# ============================================================
def _lookup_mod_sha1(pool: memhub.MemBuddy | t.CPtr,
from_imports: str, class_name: str,
allow_star_fallback: int = 1) -> str:
"""从 from_imports 查找类所属模块的 SHA1返回 None=未找到
allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找)
"""
mod_name_raw: str = HandlesImports.lookup_from_import(
from_imports, class_name, allow_star_fallback)
if mod_name_raw is None:
return None
# 手动找到模块名结束位置(空格或 null复制到新缓冲区
mod_len: t.CSizeT = 0
while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0':
mod_len += 1
mod_name_buf: str = pool.alloc(mod_len + 1)
if mod_name_buf is None:
return None
for mi in range(mod_len):
mod_name_buf[mi] = mod_name_raw[mi]
mod_name_buf[mod_len] = '\0'
# 去掉相对导入的前导点
base_mod: str = mod_name_buf
while base_mod[0] == '.':
base_mod = base_mod + 1
sha1: str = _lookup_module_sha1(base_mod)
if sha1 is None:
sha1 = _lookup_module_sha1_suffix(base_mod)
return sha1
# ============================================================
# HandlesExprCall - 函数调用表达式处理Mixin 继承模式)
#
# 工具函数和 FuncEntry 保留为模块级ExprCallHandle 提供 trans 接口
# ============================================================
# ============================================================
# 在模块函数链表中按名称查找函数
# ============================================================
def find_func_in_module(mod: llvmlite.LLVMModule | t.CPtr,
name: str) -> llvmlite.Function | t.CPtr:
"""在模块的函数链表中按名称查找函数
查找策略:
1. 精确匹配(如 "strlen" 匹配 @strlen有 t.CExport 的函数)
2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数)
使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制
stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。
"""
if mod is None or name is None:
return None
name_len: t.CSizeT = string.strlen(name)
cur: llvmlite.Function | t.CPtr = mod.FuncHead
# 第一遍:精确匹配
while cur is not None:
cur_name: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
if cur_name is not None:
if string.strcmp(cur_name, name) == 0:
return cur
cur = llvmlite.function_get_next(cur)
# 第二遍:后缀匹配(.name
# 不跳过 declare方法 stub 也是 declare需要通过后缀匹配找到
# 调用处translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
cur = mod.FuncHead
while cur is not None:
cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
if cur_name2 is not None:
cur_len: t.CSizeT = string.strlen(cur_name2)
if cur_len > name_len + 1:
suffix_start: t.CSizeT = cur_len - name_len
if cur_name2[suffix_start - 1] == '.':
match: int = 1
for i in range(name_len):
if cur_name2[suffix_start + i] != name[i]:
match = 0
break
if match == 1:
return cur
cur = llvmlite.function_get_next(cur)
return None
# ============================================================
# _infer_external_func_ret_ty - 根据函数名推断外部函数返回类型
#
# stubs 在翻译后才注入 IR翻译时模块中无 stub 函数声明,
# 因此对 includes 库函数(如 string.strchr 返回 i8*)需根据
# 函数名推断返回类型,避免指针被截断为 i32。
#
# 覆盖 includes/string.py 所有导出函数:
# i8*: strcpy, strncpy, strchr, strrchr, strstr, memset, memset32, memcpy, memmove
# i64: strlen, atoll
# double: atof
# i8: samestr
# i32默认: strcmp, strncmp, memcmp, strspn, atoi, split
# ============================================================
def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
func_name: str) -> llvmlite.LLVMType | t.CPtr:
"""根据函数名推断外部 includes 函数的返回类型"""
if pool is None or func_name is None:
return llvmlite.Int32(pool)
# 返回 i8* 的函数(指针返回值,截断会导致错误)
if func_name == "strchr":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "strrchr":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "strstr":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "strcpy":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "strncpy":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "memset":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "memset32":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "memcpy":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "memmove":
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
# 返回 i64 的函数
if func_name == "strlen":
return llvmlite.Int64(pool)
if func_name == "atoll":
return llvmlite.Int64(pool)
# 返回 double 的函数
if func_name == "atof":
return llvmlite.Double(pool)
# 返回 i8 的函数
if func_name == "samestr":
return llvmlite.Int8(pool)
# Win32 API 返回指针VOIDPTR/HANDLE的函数
# stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
if func_name == "VirtualAlloc":
return i8_ptr_ty
if func_name == "HeapAlloc":
return i8_ptr_ty
if func_name == "HeapReAlloc":
return i8_ptr_ty
if func_name == "HeapCreate":
return i8_ptr_ty
if func_name == "GetProcessHeap":
return i8_ptr_ty
if func_name == "GlobalAlloc":
return i8_ptr_ty
if func_name == "GlobalFree":
return i8_ptr_ty
if func_name == "GlobalLock":
return i8_ptr_ty
if func_name == "LocalAlloc":
return i8_ptr_ty
if func_name == "LocalFree":
return i8_ptr_ty
if func_name == "GetProcAddress":
return i8_ptr_ty
if func_name == "GetModuleHandleA":
return i8_ptr_ty
if func_name == "GetModuleHandleW":
return i8_ptr_ty
if func_name == "LoadLibraryA":
return i8_ptr_ty
if func_name == "LoadLibraryW":
return i8_ptr_ty
# Win32 API 返回 i64 (SIZE_T) 的函数
if func_name == "VirtualQuery":
return llvmlite.Int64(pool)
if func_name == "HeapSize":
return llvmlite.Int64(pool)
if func_name == "HeapCompact":
return llvmlite.Int64(pool)
if func_name == "GlobalSize":
return llvmlite.Int64(pool)
# 默认 i32
return llvmlite.Int32(pool)
# ============================================================
# _get_external_func_param_ty - 获取外部函数第 idx 个参数的期望类型
#
# stubs 翻译时未注入,需推断参数类型以提升字面量(如 i32→i64
# 避免 declare(i64) 与 call(i32) 类型不匹配。
#
# 注意stubs 翻译时 ULONG(t.CUnsignedLong) 在 LLVM IR 中被翻译为 i64
# (因为 LLVM 中 long 是 64 位),因此 Win32 API 中所有 ULONG/DWORD/SIZE_T
# 参数在 declare 中都是 i64。call 时必须匹配,否则类型不匹配。
#
# 策略:对 Win32 API 函数的所有非指针参数(字面量)都提升为 i64
# 以匹配 declare 中 ULONG 被翻译为 i64 的情况。
#
# 指针参数VOIDPTR/HANDLE不在此处理由调用点的 inttoptr 处理。
# ============================================================
def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr,
func_name: str,
param_idx: int) -> llvmlite.LLVMType | t.CPtr:
"""获取外部函数第 param_idx 个参数的期望类型None 表示用字面量原类型
对 Win32 API 函数的所有非指针参数返回 i64匹配 declare 中
ULONG/SIZE_T 被统一翻译为 i64 的情况。
"""
if pool is None or func_name is None:
return None
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
# Win32 API 函数列表:所有非指针参数在 declare 中都是 i64
# (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64
win32_apis: list[str] | t.CPtr = [
"VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery",
"VirtualLock", "VirtualUnlock",
"HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc",
"HeapFree", "HeapSize", "HeapValidate", "HeapCompact",
"GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize",
"LocalAlloc", "LocalFree",
"GetLastError", "SetLastError",
"Sleep", "SleepEx",
"GetTickCount", "GetProcessHeap"
]
for api_name in win32_apis:
if api_name == func_name:
return i64_ty
return None
# ============================================================
# _emit_llvm_memcpy_intrinsic — 将 memcpy 调用映射到 @llvm.memcpy 内联函数
#
# 背景: string.memcpy 是 t.CExport 函数,跨模块调用生成 @memcpy 裸名调用。
# 但在 monomorphization 场景下,目标模块的 deps.txt 可能不含 string
# 导致 @memcpy 声明缺失,链接器报 undefined value。
#
# 解决: 将 memcpy 调用映射到 LLVM 内联函数 @llvm.memcpy
# 该内联函数在当前模块内声明,无需跨模块依赖。
#
# @llvm.memcpy 签名: void (i8* dst, i8* src, i64 len, i1 isvolatile)
# C memcpy 签名: i8* (i8* dst, i8* src, i64 len) — 返回 dst
#
# Args:
# args_head: 参数链表头dst, src, num通过 Value.Next 链接
# arg_count: 参数数量(应为 3
#
# Returns:
# dst 值(匹配 C memcpy 语义: 返回 dest 指针)
# ============================================================
def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
dst_val: llvmlite.Value | t.CPtr,
src_val: llvmlite.Value | t.CPtr,
num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
"""将 memcpy 调用映射到 @llvm.memcpy 内联函数
直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的
Next 字段可能被其他操作污染,导致链表断裂)。
"""
if pool is None or builder is None or mod is None:
return None
if dst_val is None or src_val is None or num_val is None:
return None
# 在函数顶部声明 void_ty避免后续遮蔽
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
# 声明 @llvm.memcpy如未声明
memcpy_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, "llvm.memcpy")
if memcpy_func is None:
memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty)
if memcpy_func is not None:
i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool)
llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst")
llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src")
llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len")
llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile")
# 类型转换: dst, src → i8*; num → i64
# 注意: 使用 value_get_ty 访问器获取 Ty避免本地 Value 类型字段索引偏移
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
# dst → i8*
dst_coerced: llvmlite.Value | t.CPtr = dst_val
dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val)
if HandlesExpr.is_ptr_type(dst_ty) != 0:
dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty)
else:
dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty)
if dst_bits != 0:
if dst_bits < 64:
dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty)
dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty)
# src → i8*
src_coerced: llvmlite.Value | t.CPtr = src_val
src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val)
if HandlesExpr.is_ptr_type(src_ty) != 0:
src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty)
else:
src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty)
if src_bits != 0:
if src_bits < 64:
src_coerced = llvmlite.build_zext(builder, src_val, i64_ty)
src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty)
# num → i64
num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty)
if dst_coerced is None or src_coerced is None or num_coerced is None:
return None
# 添加 i1 false 参数isvolatile— llvm.memcpy 需要 4 个参数
false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false")
# 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移
# f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty
llvmlite.value_set_next(dst_coerced, src_coerced)
llvmlite.value_set_next(src_coerced, num_coerced)
if false_val is not None:
llvmlite.value_set_next(num_coerced, false_val)
llvmlite.value_set_next(false_val, None)
else:
llvmlite.value_set_next(num_coerced, None)
# 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确)
# _ll_name_needs_quote 已对 llvm. 前缀豁免引号
result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0)
# 返回 dst匹配 C memcpy 语义: 返回 dest 指针)
return dst_coerced
# ============================================================
# c.Deref(ptr) — 解引用指针load i8字符遍历用例
#
# 生成: %N = load i8, i8* %ptr
# 返回 i8 值
# ============================================================
def translate_c_deref(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.Deref(ptr) → load i8 from ptr"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return None
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), None, 0, trans)
if ptr_val is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
return llvmlite.build_load(builder, i8_ty, ptr_val)
# ============================================================
# c.DerefAs(ptr, val) — 解引用写入,*ptr = val
#
# 生成: %pc = bitcast i8* %ptr to <val_ty>*
# store <val_ty> %val, <val_ty>* %pc
# ============================================================
def translate_c_derefas(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.DerefAs(ptr, val) → store val to ptrbitcast 后 store"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 2:
return None
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), None, 0, trans)
val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(1), None, 0, trans)
if ptr_val is None or val is None:
return None
# bitcast ptr 到 val.Ty* 再 store
val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty)
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty)
if casted_ptr is None:
return None
llvmlite.build_store(builder, val, casted_ptr)
return val
# ============================================================
# c.Addr(var) — 取变量地址,返回 alloca 指针(不 load
#
# 用于获取栈变量的可写地址,配合 c.DerefAs 使用
# ============================================================
def translate_c_addr(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.Addr(var) → 返回变量的 alloca 指针(不 load"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return None
arg0: ast.AST | t.CPtr = cargs.get(0)
if arg0 is None or arg0.kind() != ast.ASTKind.Name:
return None
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
if nm.id is None:
return None
return HandlesVar.lookup_var(trans.SymTab, nm.id)
# ============================================================
# c.Load(a, b) — 指针间复制: *a = *b
#
# 加载 b 指向的值,存储到 a 指向的地址。
# 生成: %pc_src = bitcast i8* %src to <ty>*
# %loaded = load <ty>, <ty>* %pc_src
# %pc_dst = bitcast i8* %dst to <ty>*
# store <ty> %loaded, <ty>* %pc_dst
# ============================================================
def translate_c_load(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.Load(a, b) → *a = *b加载 b 的值,存储到 a"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 2:
return None
dst_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), None, 0, trans)
src_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(1), None, 0, trans)
if dst_ptr is None or src_ptr is None:
return None
# 确定 pointee 类型(优先用 src 的 pointee回退到 dst 的 pointee
pointee: llvmlite.LLVMType | t.CPtr = None
if src_ptr.Ty is not None:
pointee = src_ptr.Ty.Pointee
if pointee is None and dst_ptr.Ty is not None:
pointee = dst_ptr.Ty.Pointee
if pointee is None:
return None
# bitcast src 到 pointee* 并 load
target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee)
src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty)
if src_cast is None:
return None
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast)
if loaded is None:
return None
# bitcast dst 到 pointee* 并 store
dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty)
if dst_cast is None:
return None
llvmlite.build_store(builder, loaded, dst_cast)
return loaded
# ============================================================
# c.Asm — 内联汇编支持
#
# 生成: %N = call <ret_ty> asm sideeffect "<asm>", "<constraints>"(<args>)
# 或: call void asm sideeffect "<asm>", "<constraints>"(<args>)
#
# 操作数按出现顺序编号 $0, $1, ...(用户需按输出在前写 f-string
# ============================================================
ASM_MAX_OPERANDS: t.CDefine = 16
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
ASM_CONST_BUF_SIZE: t.CDefine = 512
ASM_ARGS_BUF_SIZE: t.CDefine = 512
ASM_LINE_BUF_SIZE: t.CDefine = 4096
# ============================================================
# AsmOperand - 内联汇编操作数条目
# ============================================================
@t.NoVTable
class AsmOperand:
"""内联汇编操作数条目"""
Value: llvmlite.Value | t.CPtr # 输入值或输出 alloca
Constraint: str # 约束字符串 (如 "r", "=r")
IsOutput: int # 1=输出, 0=输入
# ============================================================
# _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾
# ============================================================
def _asm_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'
# ============================================================
# _asm_escape_for_ir — 将汇编文本转义为 LLVM IR 字符串内容
#
# \n → \0A, " → \22, \ → \5C
# ============================================================
def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr,
src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
"""转义汇编文本用于 LLVM IR 字符串字面量"""
if src is None:
return None
slen: t.CSizeT = string.strlen(src)
buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8)
if buf is None:
return None
pos: t.CSizeT = 0
for ch in src:
if ch == '\n':
buf[pos] = '\\'
pos += 1
buf[pos] = '0'
pos += 1
buf[pos] = 'A'
pos += 1
elif ch == '"':
buf[pos] = '\\'
pos += 1
buf[pos] = '2'
pos += 1
buf[pos] = '2'
pos += 1
elif ch == '\\':
buf[pos] = '\\'
pos += 1
buf[pos] = '5'
pos += 1
buf[pos] = 'C'
pos += 1
else:
buf[pos] = ch
pos += 1
buf[pos] = '\0'
return buf
# ============================================================
# _resolve_register — 将 ASM_DESCR 属性名映射到约束字符串
# ============================================================
def _resolve_register(attr_name: str) -> str:
"""将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值"""
if attr_name is None:
return ""
# Clobber 破坏描述符
if attr_name == "CLOBBER_MEMORY": return "memory"
if attr_name == "CLOBBER_CC": return "cc"
if attr_name == "CLOBBER_RAX": return "rax"
if attr_name == "CLOBBER_RBX": return "rbx"
if attr_name == "CLOBBER_RCX": return "rcx"
if attr_name == "CLOBBER_RDX": return "rdx"
if attr_name == "CLOBBER_RSI": return "rsi"
if attr_name == "CLOBBER_RDI": return "rdi"
if attr_name == "CLOBBER_RBP": return "rbp"
if attr_name == "CLOBBER_RSP": return "rsp"
if attr_name == "CLOBBER_R8": return "r8"
if attr_name == "CLOBBER_R9": return "r9"
if attr_name == "CLOBBER_R10": return "r10"
if attr_name == "CLOBBER_R11": return "r11"
if attr_name == "CLOBBER_R12": return "r12"
if attr_name == "CLOBBER_R13": return "r13"
if attr_name == "CLOBBER_R14": return "r14"
if attr_name == "CLOBBER_R15": return "r15"
if attr_name == "CLOBBER_EAX": return "eax"
if attr_name == "CLOBBER_EBX": return "ebx"
if attr_name == "CLOBBER_ECX": return "ecx"
if attr_name == "CLOBBER_EDX": return "edx"
if attr_name == "CLOBBER_ESI": return "esi"
if attr_name == "CLOBBER_EDI": return "edi"
if attr_name == "CLOBBER_DX": return "dx"
if attr_name == "CLOBBER_AX": return "ax"
if attr_name == "CLOBBER_CX": return "cx"
if attr_name == "CLOBBER_SI": return "si"
if attr_name == "CLOBBER_DI": return "di"
# Output 输出约束
if attr_name == "OUTPUT_REG": return "=r"
if attr_name == "OUTPUT_MEM": return "=m"
if attr_name == "OUTPUT_EAX": return "=a"
if attr_name == "OUTPUT_EBX": return "=b"
if attr_name == "OUTPUT_ECX": return "=c"
if attr_name == "OUTPUT_EDX": return "=d"
if attr_name == "OUTPUT_ESI": return "=S"
if attr_name == "OUTPUT_EDI": return "=D"
if attr_name == "OUTPUT_RAX": return "=a"
if attr_name == "OUTPUT_RBX": return "=b"
if attr_name == "OUTPUT_RCX": return "=c"
if attr_name == "OUTPUT_RDX": return "=d"
if attr_name == "OUTPUT_RSI": return "=S"
if attr_name == "OUTPUT_RDI": return "=D"
# Input/Register 输入约束
if attr_name == "REG_ANY": return "r"
if attr_name == "REG_EAX": return "a"
if attr_name == "REG_EBX": return "b"
if attr_name == "REG_ECX": return "c"
if attr_name == "REG_EDX": return "d"
if attr_name == "REG_ESI": return "S"
if attr_name == "REG_EDI": return "D"
if attr_name == "REG_RAX": return "a"
if attr_name == "REG_RBX": return "b"
if attr_name == "REG_RCX": return "c"
if attr_name == "REG_RDX": return "d"
if attr_name == "REG_RSI": return "S"
if attr_name == "REG_RDI": return "D"
if attr_name == "INPUT_REG": return "r"
if attr_name == "INPUT_MEM": return "m"
if attr_name == "INPUT_EAX": return "a"
if attr_name == "INPUT_EBX": return "b"
if attr_name == "INPUT_ECX": return "c"
if attr_name == "INPUT_EDX": return "d"
if attr_name == "INPUT_ESI": return "S"
if attr_name == "INPUT_EDI": return "D"
if attr_name == "INPUT_RAX": return "a"
if attr_name == "INPUT_RBX": return "b"
if attr_name == "INPUT_RCX": return "c"
if attr_name == "INPUT_RDX": return "d"
if attr_name == "INPUT_RSI": return "S"
if attr_name == "INPUT_RDI": return "D"
return ""
# ============================================================
# _resolve_asm_descr — 递归解析约束表达式
#
# 支持:
# t.ASM_DESCR.XXX → _resolve_register(XXX)
# expr | expr (BinOp BitOr) → 拼接
# "string" (Constant) → 直接返回
# ============================================================
def _resolve_asm_descr(pool: memhub.MemBuddy | t.CPtr,
node: ast.AST | t.CPtr) -> str:
"""递归解析约束表达式,返回约束字符串"""
if node is None:
return ""
k: int = node.kind()
# BinOp with BitOr: 拼接左右
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
if bop.op == ast.OpKind.BitOr:
left_str: str = _resolve_asm_descr(pool, bop.left)
right_str: str = _resolve_asm_descr(pool, bop.right)
llen: t.CSizeT = string.strlen(left_str)
rlen: t.CSizeT = string.strlen(right_str)
buf: str = pool.alloc(llen + rlen + 1)
if buf is None:
return ""
string.strcpy(buf, left_str)
for i in range(rlen):
buf[llen + i] = right_str[i]
buf[llen + rlen] = '\0'
return buf
return ""
# Attribute: t.ASM_DESCR.XXX 或 t.XXX
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
# t.ASM_DESCR.XXX
if at.value is not None and at.value.kind() == ast.ASTKind.Attribute:
inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value)
if inner.value is not None and inner.value.kind() == ast.ASTKind.Name:
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value)
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0:
if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0:
return _resolve_register(at.attr)
# t.XXX 简化形式
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0:
return _resolve_register(at.attr)
return ""
# Constant: 字符串常量
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_STR:
return cn.str_val
return ""
return ""
# ============================================================
# _asm_get_operand — 获取操作数数组中第 idx 个元素的指针
# ============================================================
def _asm_get_operand(base: AsmOperand | t.CPtr,
idx: int) -> AsmOperand | t.CPtr:
"""获取操作数数组中第 idx 个元素的指针"""
entry_size: t.CSizeT = AsmOperand.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size
return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
# ============================================================
# _asm_is_c_call — 检查 Call 节点是否是 c.XXX 调用
#
# 返回 attr_name如 "AsmInp"/"AsmOut"),不是则返回 None
# ============================================================
def _asm_is_c_call(node: ast.Call | t.CPtr) -> str:
"""检查 Call 节点是否是 c.XXX 调用,返回属性名或 None"""
if node is None or node.func is None:
return None
if node.func.kind() != ast.ASTKind.Attribute:
return None
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func)
if at.value is None or at.value.kind() != ast.ASTKind.Name:
return None
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0:
return None
return at.attr
# ============================================================
# _asm_add_operand — 添加操作数到数组
#
# 返回 1 成功, 0 失败(数组已满)
# ============================================================
def _asm_add_operand(operands: AsmOperand | t.CPtr,
count: int,
val: llvmlite.Value | t.CPtr,
constraint: str,
is_output: int) -> int:
"""添加操作数到数组,返回新计数(失败返回原计数)"""
if count >= ASM_MAX_OPERANDS:
return count
op: AsmOperand | t.CPtr = _asm_get_operand(operands, count)
op.Value = val
op.Constraint = constraint
op.IsOutput = is_output
return count + 1
# ============================================================
# translate_c_asm — 翻译 c.Asm 内联汇编
#
# 语法:
# c.Asm("nop", [t.ASM_DESCR.CLOBBER_MEMORY])
# c.Asm(f"mov rax, {c.AsmInp(val, t.ASM_DESCR.REG_ANY)}", op=[...])
# c.Asm(f"...", out=[c.AsmOut(var, t.ASM_DESCR.OUTPUT_REG)], op=[...])
# ============================================================
def translate_c_asm(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""翻译 c.Asm 内联汇编,返回结果 Value无输出时返回 None"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return None
# 分配操作数数组
operand_size: t.CSizeT = AsmOperand.__sizeof__()
operands: AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS)
if operands is None:
return None
string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS)
# 分配 clobber 名数组
clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS)
if clobbers is None:
return None
string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS)
# 分配 asm 文本缓冲区
asm_text: t.CChar | t.CPtr = pool.alloc(ASM_TEXT_BUF_SIZE)
if asm_text is None:
return None
asm_text[0] = '\0'
operand_count: int = 0
clobber_count: int = 0
fv_count: int = 0
# 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引)
fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS)
if fv_orig_indices is None:
return None
string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS)
# ============================================================
# 1. 解析汇编模板JoinedStr 或 Constant— 第一遍:收集操作数
# 不生成 asm 文本(占位符 $N 需在重排后才能确定编号)
# ============================================================
tmpl_node: ast.AST | t.CPtr = cargs.get(0)
if tmpl_node is not None:
tk: int = tmpl_node.kind()
if tk == ast.ASTKind.JoinedStr:
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node)
jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values
if jvalues is not None:
jvlen: t.CSizeT = jvalues.__len__()
for vi in range(jvlen):
part: ast.AST | t.CPtr = jvalues.get(vi)
if part is None:
continue
pk: int = part.kind()
if pk == ast.ASTKind.FormattedValue:
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
fexpr: ast.AST | t.CPtr = fv.value
if fexpr is None or fexpr.kind() != ast.ASTKind.Call:
continue
fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr)
attr_nm: str = _asm_is_c_call(fcall)
if attr_nm is None:
continue
is_out: int = 0
if string.strcmp(attr_nm, "AsmOut") == 0:
is_out = 1
elif string.strcmp(attr_nm, "AsmInp") == 0:
is_out = 0
else:
continue
fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args
if fargs is None or fargs.__len__() < 1:
continue
val_node: ast.AST | t.CPtr = fargs.get(0)
cons_str: str = ""
if fargs.__len__() >= 2:
cons_str = _resolve_asm_descr(pool, fargs.get(1))
if is_out != 0:
# 输出:获取变量 alloca
if val_node is None or val_node.kind() != ast.ASTKind.Name:
continue
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
if nm.id is None:
continue
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
if alloca is None:
continue
operand_count = _asm_add_operand(
operands, operand_count, alloca, cons_str, 1)
else:
# 输入:翻译值
ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, val_node, None, 0, trans)
if ival is None:
continue
operand_count = _asm_add_operand(
operands, operand_count, ival, cons_str, 0)
# 记录 fv 的原始操作数索引
if fv_count < ASM_MAX_OPERANDS:
fv_orig_indices[fv_count] = operand_count - 1
fv_count += 1
# ============================================================
# 2. 解析关键字参数 out=/inp=/op=/clobber=
# ============================================================
keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
if keywords is not None:
kwlen: t.CSizeT = keywords.__len__()
for ki in range(kwlen):
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
if kw is None or kw.arg is None or kw.value is None:
continue
kwk: int = kw.value.kind()
if string.strcmp(kw.arg, "out") == 0:
# 输出操作数列表
if kwk != ast.ASTKind.List:
continue
out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts
if out_elts is None:
continue
oelen: t.CSizeT = out_elts.__len__()
for oi in range(oelen):
oelt: ast.AST | t.CPtr = out_elts.get(oi)
if oelt is None or oelt.kind() != ast.ASTKind.Call:
continue
ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt)
oattr: str = _asm_is_c_call(ocall)
if oattr is None or string.strcmp(oattr, "AsmOut") != 0:
continue
oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args
if oargs is None or oargs.__len__() < 1:
continue
oval_node: ast.AST | t.CPtr = oargs.get(0)
ocons: str = ""
if oargs.__len__() >= 2:
ocons = _resolve_asm_descr(pool, oargs.get(1))
if oval_node is None or oval_node.kind() != ast.ASTKind.Name:
continue
onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node)
if onm.id is None:
continue
oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id)
if oalloca is None:
continue
operand_count = _asm_add_operand(
operands, operand_count, oalloca, ocons, 1)
elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0:
# 输入操作数列表
if kwk != ast.ASTKind.List:
continue
in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts
if in_elts is None:
continue
ielen: t.CSizeT = in_elts.__len__()
for ii in range(ielen):
ielt: ast.AST | t.CPtr = in_elts.get(ii)
if ielt is None or ielt.kind() != ast.ASTKind.Call:
continue
icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt)
iattr: str = _asm_is_c_call(icall)
if iattr is None or string.strcmp(iattr, "AsmInp") != 0:
continue
iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args
if iargs is None or iargs.__len__() < 1:
continue
ival_node: ast.AST | t.CPtr = iargs.get(0)
icons: str = ""
if iargs.__len__() >= 2:
icons = _resolve_asm_descr(pool, iargs.get(1))
ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, ival_node, None, 0, trans)
if ival2 is None:
continue
operand_count = _asm_add_operand(
operands, operand_count, ival2, icons, 0)
elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0:
# 破坏列表
if kwk != ast.ASTKind.List:
continue
cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts
if cl_elts is None:
continue
clen: t.CSizeT = cl_elts.__len__()
for ci in range(clen):
celt: ast.AST | t.CPtr = cl_elts.get(ci)
if celt is None:
continue
cstr: str = _resolve_asm_descr(pool, celt)
if cstr is None or cstr[0] == '\0':
continue
if clobber_count < ASM_MAX_OPERANDS:
cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8
cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr))
cl_ptr[0] = cstr
clobber_count += 1
# ============================================================
# 3. 解析第二个位置参数作为破坏列表
# ============================================================
if cargs.__len__() >= 2:
pos_node: ast.AST | t.CPtr = cargs.get(1)
if pos_node is not None and pos_node.kind() == ast.ASTKind.List:
pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node)
pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts
if pos_elts is not None:
plen: t.CSizeT = pos_elts.__len__()
for pi in range(plen):
pelt: ast.AST | t.CPtr = pos_elts.get(pi)
if pelt is None:
continue
pstr: str = _resolve_asm_descr(pool, pelt)
if pstr is None or pstr[0] == '\0':
continue
if clobber_count < ASM_MAX_OPERANDS:
pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8
pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr))
pcl_ptr[0] = pstr
clobber_count += 1
# ============================================================
# 4. 统计输出/输入数量,确定返回类型
# ============================================================
output_count: int = 0
input_count: int = 0
first_output_idx: int = -1
for oi2 in range(operand_count):
op2: AsmOperand | t.CPtr = _asm_get_operand(operands, oi2)
if op2.IsOutput != 0:
if first_output_idx < 0:
first_output_idx = oi2
output_count += 1
else:
input_count += 1
# 确定返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
if output_count > 0 and first_output_idx >= 0:
out_op: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx)
if out_op.Value is not None and out_op.Value.Ty is not None:
# alloca 的类型是指针Pointee 是目标类型
if out_op.Value.Ty.Pointee is not None:
ret_ty = out_op.Value.Ty.Pointee
else:
ret_ty = llvmlite.Int32(pool)
# 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题
is_void: int = 1
if output_count > 0:
is_void = 0
# ============================================================
# 4.5 重排操作数输出在前输入在后LLVM IR 要求)
#
# new_order[new_idx] = orig_idx — 新位置对应原索引
# orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号)
# ============================================================
new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
if new_order is None or orig_to_new is None:
return None
new_idx: int = 0
# 先放输出
for oi3 in range(operand_count):
op3: AsmOperand | t.CPtr = _asm_get_operand(operands, oi3)
if op3.IsOutput != 0:
new_order[new_idx] = oi3
new_idx += 1
# 再放输入
for oi4 in range(operand_count):
op4: AsmOperand | t.CPtr = _asm_get_operand(operands, oi4)
if op4.IsOutput == 0:
new_order[new_idx] = oi4
new_idx += 1
# 建立映射 orig -> new
for ni2 in range(operand_count):
orig_to_new[new_order[ni2]] = ni2
# ============================================================
# 4.6 生成汇编文本(第二遍遍历 f-string用重排后的索引生成占位符
# 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用
# ============================================================
if tmpl_node is not None:
tk2: int = tmpl_node.kind()
if tk2 == ast.ASTKind.JoinedStr:
js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node)
jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values
if jvalues2 is not None:
jvlen2: t.CSizeT = jvalues2.__len__()
fv_fi: int = 0
for vi2 in range(jvlen2):
part2: ast.AST | t.CPtr = jvalues2.get(vi2)
if part2 is None:
continue
pk2: int = part2.kind()
if pk2 == ast.ASTKind.Constant:
cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2)
if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None:
_asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val)
elif pk2 == ast.ASTKind.FormattedValue:
if fv_fi < fv_count:
orig_idx2: int = fv_orig_indices[fv_fi]
new_idx2: int = orig_to_new[orig_idx2]
ph_buf2: t.CChar | t.CPtr = pool.alloc(16)
if ph_buf2 is not None:
viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2)
_asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2)
fv_fi += 1
elif tk2 == ast.ASTKind.Constant:
cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node)
if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None:
_asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val)
# ============================================================
# 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后)
# ============================================================
const_buf: t.CChar | t.CPtr = pool.alloc(ASM_CONST_BUF_SIZE)
if const_buf is None:
return None
const_buf[0] = '\0'
first_const: int = 1
for ci2 in range(operand_count):
orig_i: int = new_order[ci2]
cop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i)
cons_val: str = cop.Constraint
if cons_val is None:
cons_val = "r"
if first_const == 0:
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
first_const = 0
if cop.IsOutput != 0:
# 输出约束:确保以 = 开头
if cons_val[0] != '=':
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=")
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val)
else:
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val)
# 追加 clobber 约束 ~{name}
for cidx in range(clobber_count):
cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8
cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0]
if cname is None or cname[0] == '\0':
continue
if first_const == 0:
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
first_const = 0
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{")
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname)
_asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}")
# ============================================================
# 6. 构建参数列表文本(仅输入操作数)
# ============================================================
args_buf: t.CChar | t.CPtr = pool.alloc(ASM_ARGS_BUF_SIZE)
if args_buf is None:
return None
args_buf[0] = '\0'
first_arg: int = 1
for ai3 in range(operand_count):
orig_i2: int = new_order[ai3]
aop: AsmOperand | t.CPtr = _asm_get_operand(operands, orig_i2)
if aop.IsOutput != 0:
continue
aval: llvmlite.Value | t.CPtr = aop.Value
if aval is None or aval.Ty is None or aval.Name is None:
continue
if first_arg == 0:
_asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ")
first_arg = 0
# 类型文本
ty_buf: t.CChar | t.CPtr = pool.alloc(64)
if ty_buf is not None:
ty_buf[0] = '\0'
llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool)
_asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf)
_asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ")
_asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name)
# ============================================================
# 7. 转义汇编文本
# ============================================================
escaped_asm: t.CChar | t.CPtr = _asm_escape_for_ir(pool, asm_text)
if escaped_asm is None:
return None
# ============================================================
# 8. 生成 IR 行并发射
# ============================================================
line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE)
if line is None:
return None
line[0] = '\0'
ssa_name: t.CChar | t.CPtr = None
if is_void == 0:
ssa_name = pool.alloc(16)
if ssa_name is not None:
viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter)
builder.Counter += 1
# 获取返回类型文本
ret_ty_buf: t.CChar | t.CPtr = pool.alloc(64)
if ret_ty_buf is not None:
ret_ty_buf[0] = '\0'
llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool)
if is_void == 1:
viperlib.snprintf(line, ASM_LINE_BUF_SIZE,
"call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)",
ret_ty_buf, escaped_asm, const_buf, args_buf)
else:
viperlib.snprintf(line, ASM_LINE_BUF_SIZE,
"%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)",
ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf)
# 发射 IR 到当前块
llvmlite.block_append_text(pool, builder.CurBlock, line)
# ============================================================
# 9. 处理输出:存储结果到输出变量
# ============================================================
if is_void == 0 and first_output_idx >= 0:
result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name)
out_op2: AsmOperand | t.CPtr = _asm_get_operand(operands, first_output_idx)
if out_op2.Value is not None:
llvmlite.build_store(builder, result_val, out_op2.Value)
return result_val
return None
# ============================================================
# c.LLVMIR — 内联 LLVM IR 支持
#
# 语法:
# c.LLVMIR(f"add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
# c.LLVMIR(f"%{c.LOut(result)} = add i32 {c.LInp(a)}, {c.LInp(b)}", t.CInt)
#
# c.LInp(expr) - 输入操作数,翻译后替换为对应的 LLVM 值
# c.LOut(expr) - 输出操作数,翻译后结果存储到该变量
#
# 支持的指令: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr
# fadd/fsub/fmul/fdiv
# icmp eq/ne/sgt/sge/slt/sle/ugt/uge/ult/ule
# fcmp oeq/one/olt/ogt/ole/oge
# zext/sext/trunc/bitcast/ptrtoint/inttoptr
# load/store
# ============================================================
LLVMIR_MAX_OPS: t.CDefine = 16
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
# ============================================================
# _llvmir_get_op — 获取第 i 个 AsmOperand 槽位
# ============================================================
def _llvmir_get_op(buf: AsmOperand | t.CPtr, i: int) -> AsmOperand | t.CPtr:
"""获取第 i 个操作数槽位"""
entry_size: t.CSizeT = AsmOperand.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(buf) + i * entry_size
return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
# ============================================================
# _llvmir_find_op_marker — 在字符串中查找 %__OP 并返回编号
#
# 返回 (位置, 编号),未找到返回 (None, 0)
# ============================================================
def _llvmir_find_op_marker(s: t.CChar | t.CPtr) -> t.CPtr:
"""查找 %__OP 标记,返回标记开始位置或 None"""
if s is None:
return None
return string.strstr(s, "%__OP")
# ============================================================
# _llvmir_parse_op_num — 从 %__OPN__ 中解析编号 N
#
# 输入: 指向 "%__OP" 的指针
# 返回: 操作数编号
# ============================================================
def _llvmir_parse_op_num(marker: t.CChar | t.CPtr) -> int:
"""%__OPN__ 标记中解析编号 N"""
if marker is None:
return -1
# 跳过 "%__OP" (5 字符)
num_start: t.CChar | t.CPtr = marker + 5
if num_start is None:
return -1
# 解析数字直到 "__"
num: int = 0
i: t.CSizeT = 0
ch: t.CChar = num_start[0]
while '0' <= ch <= '9':
num = num * 10 + (ch - '0')
i += 1
ch = num_start[i]
return num
# ============================================================
# _llvmir_match_icmp_pred — 将预测字符串转为 ICMP 常量
# ============================================================
def _llvmir_match_icmp_pred(pred: str) -> int:
"""将 icmp 预测字符串转为常量"""
if pred is None:
return 0
if string.strcmp(pred, "eq") == 0:
return 0
if string.strcmp(pred, "ne") == 0:
return 1
if string.strcmp(pred, "sgt") == 0:
return 2
if string.strcmp(pred, "sge") == 0:
return 3
if string.strcmp(pred, "slt") == 0:
return 4
if string.strcmp(pred, "sle") == 0:
return 5
if string.strcmp(pred, "ugt") == 0:
return 6
if string.strcmp(pred, "uge") == 0:
return 7
if string.strcmp(pred, "ult") == 0:
return 8
if string.strcmp(pred, "ule") == 0:
return 9
return 0
# ============================================================
# _llvmir_match_fcmp_pred — 将预测字符串转为 FCMP 常量
# ============================================================
def _llvmir_match_fcmp_pred(pred: str) -> int:
"""将 fcmp 预测字符串转为常量"""
if pred is None:
return 0
if string.strcmp(pred, "oeq") == 0:
return 0
if string.strcmp(pred, "ogt") == 0:
return 1
if string.strcmp(pred, "oge") == 0:
return 2
if string.strcmp(pred, "olt") == 0:
return 3
if string.strcmp(pred, "ole") == 0:
return 4
if string.strcmp(pred, "one") == 0:
return 5
if string.strcmp(pred, "ord") == 0:
return 6
if string.strcmp(pred, "uno") == 0:
return 7
if string.strcmp(pred, "ueq") == 0:
return 8
if string.strcmp(pred, "ugt") == 0:
return 9
if string.strcmp(pred, "uge") == 0:
return 10
if string.strcmp(pred, "ult") == 0:
return 11
if string.strcmp(pred, "ule") == 0:
return 12
if string.strcmp(pred, "une") == 0:
return 13
return 0
# ============================================================
# _llvmir_extract_two_ops — 从模板中提取两个操作数编号
#
# 通过输出参数返回 op1_num 和 op2_num
# ============================================================
def _llvmir_extract_two_ops(template: t.CChar | t.CPtr,
out_nums: int | t.CPtr) -> int:
"""从模板中提取前两个 %__OP 标记的编号
结果写入 out_nums[0] 和 out_nums[1]
返回 1 成功, 0 失败
"""
out_nums[0] = -1
out_nums[1] = -1
m1: t.CChar | t.CPtr = _llvmir_find_op_marker(template)
if m1 is None:
return 0
out_nums[0] = _llvmir_parse_op_num(m1)
# 跳过第一个标记 "%__OPN__"
next_pos: t.CChar | t.CPtr = m1 + 5 # 跳过 "%__OP"
i: t.CSizeT = 0
while next_pos[i] >= '0' and next_pos[i] <= '9':
i += 1
next_pos = next_pos + i + 2
m2: t.CChar | t.CPtr = _llvmir_find_op_marker(next_pos)
if m2 is None:
return 1
out_nums[1] = _llvmir_parse_op_num(m2)
return 1
# ============================================================
# _llvmir_resolve_op — 根据编号解析操作数值
# ============================================================
def _llvmir_resolve_op(op_num: int,
all_kinds: int | t.CPtr,
all_indices: int | t.CPtr,
input_ops: AsmOperand | t.CPtr,
output_targets: AsmOperand | t.CPtr) -> llvmlite.Value | t.CPtr:
"""根据操作数编号解析实际 Value"""
if op_num < 0 or op_num >= LLVMIR_MAX_OPS:
return None
kind: int = all_kinds[op_num]
idx: int = all_indices[op_num]
if kind == 0:
# 输入操作数
op: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, idx)
return op.Value
else:
# 输出操作数
op2: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, idx)
return op2.Value
# ============================================================
# _llvmir_store_outputs — 将结果存储到输出变量
# ============================================================
def _llvmir_store_outputs(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
result: llvmlite.Value | t.CPtr,
output_targets: AsmOperand | t.CPtr,
output_count: int) -> llvmlite.Value | t.CPtr:
"""将结果存储到所有输出变量"""
if output_count == 0:
return result
for oi in range(output_count):
op: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, oi)
if op.Value is not None and result is not None:
llvmlite.build_store(builder, result, op.Value)
return result
# ============================================================
# translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR
# ============================================================
def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""翻译 c.LLVMIR 内联 LLVM IR返回结果 Value"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return None
# 分配操作数数组
op_size: t.CSizeT = AsmOperand.__sizeof__()
input_ops: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS)
output_targets: AsmOperand | t.CPtr = pool.alloc(op_size * LLVMIR_MAX_OPS)
if input_ops is None or output_targets is None:
return None
string.memset(input_ops, 0, op_size * LLVMIR_MAX_OPS)
string.memset(output_targets, 0, op_size * LLVMIR_MAX_OPS)
# all_ops 映射: kinds[i]=0(inp)/1(out), indices[i]=在对应数组中的索引
all_kinds: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS)
all_indices: int | t.CPtr = pool.alloc(4 * LLVMIR_MAX_OPS)
if all_kinds is None or all_indices is None:
return None
string.memset(all_kinds, 0, 4 * LLVMIR_MAX_OPS)
string.memset(all_indices, 0, 4 * LLVMIR_MAX_OPS)
input_count: int = 0
output_count: int = 0
op_seq: int = 0
# 分配模板缓冲区
template: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF)
if template is None:
return None
template[0] = '\0'
# 解析返回类型(默认 i32
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if cargs.__len__() >= 2:
ret_type_node: ast.AST | t.CPtr = cargs.get(1)
if ret_type_node is not None:
resolved_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, ret_type_node, trans._imported_modules, trans._from_imports)
if resolved_ty is not None:
ret_ty = resolved_ty
# ============================================================
# 1. 解析 IR 模板JoinedStr 或 Constant— 收集操作数
# ============================================================
first_arg: ast.AST | t.CPtr = cargs.get(0)
if first_arg is None:
return None
tk: int = first_arg.kind()
if tk == ast.ASTKind.JoinedStr:
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg)
jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values
if jvalues is not None:
jvlen: t.CSizeT = jvalues.__len__()
for vi in range(jvlen):
part: ast.AST | t.CPtr = jvalues.get(vi)
if part is None:
continue
pk: int = part.kind()
if pk == ast.ASTKind.Constant:
# 字符串字面量片段
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part)
if cn.str_val is not None:
_asm_append_cstr(template, LLVMIR_TEMPLATE_BUF, cn.str_val)
elif pk == ast.ASTKind.FormattedValue:
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
fexpr: ast.AST | t.CPtr = fv.value
if fexpr is None or fexpr.kind() != ast.ASTKind.Call:
continue
fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr)
attr_nm: str = _asm_is_c_call(fcall)
if attr_nm is None:
# 非 c.LInp/c.LOut 调用,作为普通输入处理
ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, fexpr, None, 0, trans)
if ival is not None and input_count < LLVMIR_MAX_OPS:
op_in: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count)
op_in.Value = ival
all_kinds[op_seq] = 0
all_indices[op_seq] = input_count
input_count += 1
op_seq += 1
# 追加占位符
viperlib.snprintf(
template + string.strlen(template),
LLVMIR_TEMPLATE_BUF - string.strlen(template),
"%%__OP%d__", op_seq - 1)
continue
# 处理 c.LInp / c.LOut
fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args
if fargs is None or fargs.__len__() < 1:
continue
val_node: ast.AST | t.CPtr = fargs.get(0)
if string.strcmp(attr_nm, "LInp") == 0:
# 输入操作数:翻译值
inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, val_node, None, 0, trans)
if inp_val is not None and input_count < LLVMIR_MAX_OPS:
op_inp: AsmOperand | t.CPtr = _llvmir_get_op(input_ops, input_count)
op_inp.Value = inp_val
all_kinds[op_seq] = 0
all_indices[op_seq] = input_count
input_count += 1
op_seq += 1
viperlib.snprintf(
template + string.strlen(template),
LLVMIR_TEMPLATE_BUF - string.strlen(template),
"%%__OP%d__", op_seq - 1)
elif string.strcmp(attr_nm, "LOut") == 0:
# 输出操作数:获取变量 alloca
if val_node is not None and val_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
if nm.id is not None:
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
if alloca is not None and output_count < LLVMIR_MAX_OPS:
op_out: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, output_count)
op_out.Value = alloca
all_kinds[op_seq] = 1
all_indices[op_seq] = output_count
output_count += 1
op_seq += 1
viperlib.snprintf(
template + string.strlen(template),
LLVMIR_TEMPLATE_BUF - string.strlen(template),
"%%__OP%d__", op_seq - 1)
elif tk == ast.ASTKind.Constant:
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg)
if cn2.str_val is not None:
string.strcpy(template, cn2.str_val)
# ============================================================
# 2. 解析模板并生成 LLVM 指令
# ============================================================
# 检查是否为赋值形式: %__OPN__ = <指令>
# 如果是,去掉赋值前缀,记录输出操作数编号
assign_out_num: int = -1
assign_marker: t.CChar | t.CPtr = _llvmir_find_op_marker(template)
if assign_marker is not None and assign_marker == template:
# 模板以 %__OP 开头
# 查找 "=" 号
eq_pos: t.CChar | t.CPtr = string.strchr(template, 61) # '=' = 61
if eq_pos is not None:
# 确认 "%__OPN__ = " 格式
assign_out_num = _llvmir_parse_op_num(assign_marker)
# 跳过 "%__OP<digits>__ = " 到实际指令开始
# 找到 "=" 后第一个非空格字符
instr_start: t.CChar | t.CPtr = eq_pos + 1
while instr_start[0] == ' ' or instr_start[0] == '\t':
instr_start += 1
# 将剩余部分复制到新模板
tmpl2: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF)
if tmpl2 is not None:
string.strcpy(tmpl2, instr_start)
template = tmpl2
# 去除前导空格
while template[0] == ' ' or template[0] == '\t':
template += 1
# 提取指令关键字(第一个单词)
instr_kw: t.CChar | t.CPtr = pool.alloc(32)
if instr_kw is None:
return None
instr_kw[0] = '\0'
ki: t.CSizeT = 0
while template[ki] != ' ' and template[ki] != '\t' and template[ki] != '\0' and ki < 31:
instr_kw[ki] = template[ki]
ki += 1
instr_kw[ki] = '\0'
# ============================================================
# 二元运算: add/sub/mul/sdiv/udiv/srem/urem/and/or/xor/shl/lshr/ashr
# ============================================================
binop_result: llvmlite.Value | t.CPtr = None
# 提取两个操作数编号
op_nums: int | t.CPtr = pool.alloc(8)
if op_nums is not None:
string.memset(op_nums, 0, 8)
_llvmir_extract_two_ops(template, op_nums)
op1_num: int = -1
op2_num: int = -1
if op_nums is not None:
op1_num = op_nums[0]
op2_num = op_nums[1]
lhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op(
op1_num, all_kinds, all_indices, input_ops, output_targets)
rhs: llvmlite.Value | t.CPtr = _llvmir_resolve_op(
op2_num, all_kinds, all_indices, input_ops, output_targets)
if lhs is not None and rhs is not None:
if string.strcmp(instr_kw, "add") == 0:
binop_result = llvmlite.build_add(builder, lhs, rhs)
elif string.strcmp(instr_kw, "sub") == 0:
binop_result = llvmlite.build_sub(builder, lhs, rhs)
elif string.strcmp(instr_kw, "mul") == 0:
binop_result = llvmlite.build_mul(builder, lhs, rhs)
elif string.strcmp(instr_kw, "sdiv") == 0:
binop_result = llvmlite.build_sdiv(builder, lhs, rhs)
elif string.strcmp(instr_kw, "udiv") == 0:
binop_result = llvmlite.build_udiv(builder, lhs, rhs)
elif string.strcmp(instr_kw, "srem") == 0:
binop_result = llvmlite.build_srem(builder, lhs, rhs)
elif string.strcmp(instr_kw, "urem") == 0:
binop_result = llvmlite.build_urem(builder, lhs, rhs)
elif string.strcmp(instr_kw, "and") == 0:
binop_result = llvmlite.build_and(builder, lhs, rhs)
elif string.strcmp(instr_kw, "or") == 0:
binop_result = llvmlite.build_or(builder, lhs, rhs)
elif string.strcmp(instr_kw, "xor") == 0:
binop_result = llvmlite.build_xor(builder, lhs, rhs)
elif string.strcmp(instr_kw, "shl") == 0:
binop_result = llvmlite.build_shl(builder, lhs, rhs)
elif string.strcmp(instr_kw, "lshr") == 0:
binop_result = llvmlite.build_lshr(builder, lhs, rhs)
elif string.strcmp(instr_kw, "ashr") == 0:
binop_result = llvmlite.build_ashr(builder, lhs, rhs)
elif string.strcmp(instr_kw, "fadd") == 0:
binop_result = llvmlite.build_fadd(builder, lhs, rhs)
elif string.strcmp(instr_kw, "fsub") == 0:
binop_result = llvmlite.build_fsub(builder, lhs, rhs)
elif string.strcmp(instr_kw, "fmul") == 0:
binop_result = llvmlite.build_fmul(builder, lhs, rhs)
elif string.strcmp(instr_kw, "fdiv") == 0:
binop_result = llvmlite.build_fdiv(builder, lhs, rhs)
# ============================================================
# icmp 比较: icmp <pred> <ty> %__OP0__, %__OP1__
# ============================================================
if binop_result is None and string.strcmp(instr_kw, "icmp") == 0:
# 提取预测(第二个单词)
pred_start: t.CChar | t.CPtr = template + ki + 1
while pred_start[0] == ' ' or pred_start[0] == '\t':
pred_start += 1
pred_str: t.CChar | t.CPtr = pool.alloc(16)
if pred_str is not None:
pred_str[0] = '\0'
pi: t.CSizeT = 0
while pred_start[pi] != ' ' and pred_start[pi] != '\t' and pred_start[pi] != '\0' and pi < 15:
pred_str[pi] = pred_start[pi]
pi += 1
pred_str[pi] = '\0'
pred_val: int = _llvmir_match_icmp_pred(pred_str)
if lhs is not None and rhs is not None:
binop_result = llvmlite.build_icmp(builder, pred_val, lhs, rhs)
# ============================================================
# fcmp 比较: fcmp <pred> <ty> %__OP0__, %__OP1__
# ============================================================
if binop_result is None and string.strcmp(instr_kw, "fcmp") == 0:
pred_start2: t.CChar | t.CPtr = template + ki + 1
while pred_start2[0] == ' ' or pred_start2[0] == '\t':
pred_start2 += 1
pred_str2: t.CChar | t.CPtr = pool.alloc(16)
if pred_str2 is not None:
pred_str2[0] = '\0'
pi2: t.CSizeT = 0
while pred_start2[pi2] != ' ' and pred_start2[pi2] != '\t' and pred_start2[pi2] != '\0' and pi2 < 15:
pred_str2[pi2] = pred_start2[pi2]
pi2 += 1
pred_str2[pi2] = '\0'
pred_val2: int = _llvmir_match_fcmp_pred(pred_str2)
if lhs is not None and rhs is not None:
binop_result = llvmlite.build_fcmp(builder, pred_val2, lhs, rhs)
# ============================================================
# store 指令: store <ty> %__OP0__, <ty> %__OP1__
# ============================================================
if binop_result is None and string.strcmp(instr_kw, "store") == 0:
if lhs is not None and rhs is not None:
llvmlite.build_store(builder, lhs, rhs)
return None
# ============================================================
# load 指令: load <ty>, <ty> %__OP0__
# ============================================================
if binop_result is None and string.strcmp(instr_kw, "load") == 0:
if lhs is not None:
# 从指针加载,类型由 ret_ty 指定
binop_result = llvmlite.build_load(builder, ret_ty, lhs)
# ============================================================
# 类型转换: zext/sext/trunc/bitcast/ptrtoint/inttoptr
# ============================================================
if binop_result is None:
if string.strcmp(instr_kw, "zext") == 0:
if lhs is not None:
binop_result = llvmlite.build_zext(builder, lhs, ret_ty)
elif string.strcmp(instr_kw, "sext") == 0:
if lhs is not None:
binop_result = llvmlite.build_sext(builder, lhs, ret_ty)
elif string.strcmp(instr_kw, "trunc") == 0:
if lhs is not None:
binop_result = llvmlite.build_trunc(builder, lhs, ret_ty)
elif string.strcmp(instr_kw, "bitcast") == 0:
if lhs is not None:
binop_result = llvmlite.build_bitcast(builder, lhs, ret_ty)
elif string.strcmp(instr_kw, "ptrtoint") == 0:
if lhs is not None:
binop_result = llvmlite.build_ptrtoint(builder, lhs, ret_ty)
elif string.strcmp(instr_kw, "inttoptr") == 0:
if lhs is not None:
binop_result = llvmlite.build_inttoptr(builder, lhs, ret_ty)
# ============================================================
# 3. 处理输出
# ============================================================
if binop_result is not None:
# 如果有赋值形式(%__OPN__ = ...),存储到对应输出
if assign_out_num >= 0:
target: llvmlite.Value | t.CPtr = _llvmir_resolve_op(
assign_out_num, all_kinds, all_indices, input_ops, output_targets)
if target is not None:
llvmlite.build_store(builder, binop_result, target)
# 存储到所有输出操作数
_llvmir_store_outputs(pool, builder, binop_result, output_targets, output_count)
return binop_result
# 未识别的指令,返回 0
stdio.printf("[LLVMIR] unsupported instruction: %s\n", instr_kw)
return None
# ============================================================
# _apply_struct_defaults — 应用结构体字段的默认值
#
# 在 zeroinitializer 之后、显式参数之前调用
# 遍历所有字段,对有默认值的字段翻译并 store
# 显式参数(位置/关键字)后续会覆盖默认值
# ============================================================
def _apply_struct_defaults(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
tmp: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr):
"""应用结构体字段的默认值"""
# 用类型指针定位 entry规避跨模块同名 find_struct 找错
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
if entry is None:
return
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
entry, fi)
if fe is None or fe.DefaultVal is None:
continue
default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, fe.DefaultVal, None, 0, trans)
if default_val is None:
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
continue
default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty)
llvmlite.build_store(builder, default_val, field_ptr)
# ============================================================
# _translate_struct_ctor — 结构体构造函数 Point(10, 20)
#
# 生成:
# %tmp = alloca {i32, i32}
# store {i32, i32} zeroinitializer, {i32, i32}* %tmp
# %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0
# store i32 10, i32* %f0
# %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1
# store i32 20, i32* %f1
# %result = load {i32, i32}, {i32, i32}* %tmp
# ============================================================
def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""结构体构造函数:按字段顺序 store 参数值,返回结构体值
OOP 结构体alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
普通结构体alloca → zero + defaults → store 参数 → load
"""
# 创建临时 alloca
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return llvmlite.ConstZero(pool, struct_ty)
# 检查是否为 OOP 结构体(用类型指针定位 entry规避跨模块同名 find_struct 找错)
ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
is_oop: int = 0
if ctor_entry is not None:
is_oop = ctor_entry.IsOOP
if is_oop != 0:
# 存储指针:默认用 alloca如果有 __new__ 则用 __new__ 返回的指针
storage_ptr: llvmlite.Value | t.CPtr = tmp
# 如果有 __new__调用 __new__(tmp, args...) 获取实际存储指针
# __new__ 签名与 __init__ 一样self + args返回 Ptr(struct_ty)
has_new_flag: int = 0
if ctor_entry is not None:
has_new_flag = ctor_entry.HasNew
if has_new_flag != 0:
new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
if new_arg_vals is not None:
string.memset(new_arg_vals, 0, 8 * 32)
new_arg_count: int = 0
for nai in range(can):
new_arg_node: ast.AST | t.CPtr = cargs.get(nai)
if new_arg_node is None:
continue
new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, new_arg_node, None, 0, trans)
if new_av is not None:
if new_arg_count < 32:
new_arg_vals[new_arg_count] = t.CSizeT(new_av)
new_arg_count += 1
new_ptr: llvmlite.Value | t.CPtr = _call_method_on_ptr(
pool, builder, mod, class_name,
"__new__", tmp, new_arg_vals, new_arg_count, trans)
if new_ptr is not None:
storage_ptr = new_ptr
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
_call_method_on_ptr(pool, builder, mod, class_name,
"__before_init__", storage_ptr, None, 0, trans)
# 如果有 __init__调用 __init__(ptr, args...)
has_init_flag: int = 0
if ctor_entry is not None:
has_init_flag = ctor_entry.HasInit
if has_init_flag != 0:
# 翻译构造函数参数
arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
if arg_vals is not None:
string.memset(arg_vals, 0, 8 * 32)
real_arg_count: int = 0
for ai in range(can):
arg_node: ast.AST | t.CPtr = cargs.get(ai)
if arg_node is None:
continue
av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node, None, 0, trans)
if av is not None:
if real_arg_count < 32:
arg_vals[real_arg_count] = t.CSizeT(av)
real_arg_count += 1
_call_method_on_ptr(pool, builder, mod, class_name,
"__init__", storage_ptr, arg_vals, real_arg_count, trans)
else:
# 无 __init__逐字段 store 参数值
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None:
continue
fe: HandlesStruct.FieldEntry | t.CPtr = None
if ctor_entry is not None:
fe = HandlesStruct._get_field_entry(ctor_entry, ai)
else:
fe = HandlesStruct.get_field_by_index(class_name, ai)
if fe is None:
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, storage_ptr, fe.Index)
if field_ptr is None:
continue
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty)
llvmlite.build_store(builder, arg_val, field_ptr)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return storage_ptr
# 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零)
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
llvmlite.build_store(builder, zero, tmp)
# 应用默认值(显式参数会覆盖默认值)
_apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
# 逐字段 store 参数值(覆盖默认值)
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None:
continue
# 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错)
fe: HandlesStruct.FieldEntry | t.CPtr = None
if ctor_entry is not None:
fe = HandlesStruct._get_field_entry(ctor_entry, ai)
else:
fe = HandlesStruct.get_field_by_index(class_name, ai)
if fe is None:
continue
# GEP 到字段 ai
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
continue
# 类型转换并 store
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty)
llvmlite.build_store(builder, arg_val, field_ptr)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
# ============================================================
# _do_virtual_call — 通过虚表间接调用虚方法
#
# IR 模式:
# %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8**
# %2 = load i8*, i8** %1 ; i8* (vtable ptr)
# %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr
# %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8**
# %5 = load i8*, i8** %4 ; i8* (func ptr)
# %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr
# call RetTy %6(Params %self, ...)
#
# 参数:
# args_head — 已构建好的参数链表头self_ptr 为首节点)
# args_count — 参数总数(含 self
# found_func — 方法对应的 Function 对象(用于推断函数签名)
# ret_ty — 返回类型
# ============================================================
def _do_virtual_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
self_ptr: llvmlite.Value | t.CPtr,
args_head: llvmlite.Value | t.CPtr,
args_count: int,
found_func: llvmlite.Function | t.CPtr,
ret_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""通过虚表间接调用虚方法,返回 call 结果void 方法返回 None"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
if self_ptr is None or args_head is None:
return None
# 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
vc_entry: HandlesStruct.StructEntry | t.CPtr = None
struct_ty: llvmlite.LLVMType | t.CPtr = None
if self_ptr.Ty is not None:
vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr)
if vc_entry is not None:
# vc_entry 是 struct_tyLLVMType需要找 StructEntry
vc_entry = HandlesStruct.find_struct_by_type(vc_entry)
if vc_entry is not None:
struct_ty = vc_entry.Ty
if struct_ty is None:
struct_ty = HandlesStruct.get_struct_type(class_name)
if struct_ty is None:
return None
# 2. 获取方法在虚表中的索引(用 entry 直接查找)
method_index: int = -1
if vc_entry is not None and vc_entry.VTableMethods is not None:
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr))
for mi in range(vc_entry.VTableMethodCount):
mname_addr: t.CSizeT = methods_arr[mi]
if mname_addr == 0:
continue
mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
if mname is not None and string.strcmp(mname, method_name) == 0:
method_index = mi
break
else:
method_index = HandlesStruct.get_vtable_method_index(class_name, method_name)
if method_index < 0:
return None
# 3. 基础类型
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
# 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0
# vtable 指针总是在对象第一个字段,无需 GEP直接 bitcast 到 i8** 即可。
# 这样即使 struct_ty 是 opaque跨模块未加载完整定义也能正常工作。
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, self_ptr, i8_ptr_ptr_ty)
if vtable_slot is None:
return None
# 5. load vtable 指针 (i8*)
vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
if vtable_ptr is None:
return None
# 6. 构造 vtable 类型 {i8*, i8*, ...}
method_count: int = 0
if vc_entry is not None:
method_count = vc_entry.VTableMethodCount
else:
method_count = HandlesStruct.get_vtable_method_count(class_name)
if method_count <= 0:
return None
vt_first: llvmlite.ParamNode | t.CPtr = None
vt_prev: llvmlite.ParamNode | t.CPtr = None
for vi in range(method_count):
pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
if pn is None:
continue
if vt_first is None:
vt_first = pn
if vt_prev is not None:
llvmlite.paramnode_set_next(vt_prev, pn)
vt_prev = pn
vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None)
if vtable_ty is None:
return None
vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty)
# 7. bitcast i8* 到 vtable 类型指针
vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, vtable_ptr, vtable_ptr_ty)
if vtable_typed is None:
return None
# 8. GEP 到方法槽位
func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index)
if func_slot is None:
return None
# 9. load 函数指针 (i8*)
func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot)
if func_i8 is None:
return None
# 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...)
# 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_funcstub 字段偏移问题)
fp_first: llvmlite.ParamNode | t.CPtr = None
fp_prev: llvmlite.ParamNode | t.CPtr = None
fp_count: int = 0
cur_val: llvmlite.Value | t.CPtr = args_head
for vi in range(args_count):
if cur_val is None:
break
cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val)
fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty)
if fpn is not None:
if fp_first is None:
fp_first = fpn
if fp_prev is not None:
llvmlite.paramnode_set_next(fp_prev, fpn)
fp_prev = fpn
cur_val = llvmlite.value_get_next(cur_val)
fp_count += 1
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count)
if func_ty is None:
return None
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
# 11. bitcast i8* 到函数指针类型
func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty)
if func_ptr is None:
return None
# 12. 间接调用
return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty)
# ============================================================
# _call_method_on_ptr — 在结构体指针上调用方法
#
# 辅助函数:构造 ClassName.method_name 调用self 指针为首个参数
# 如果该方法在虚表中,则走虚方法分发路径(间接调用)
# ============================================================
def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
self_ptr: llvmlite.Value | t.CPtr,
extra_args: t.CSizeT | t.CPtr,
extra_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""在结构体指针上调用方法,返回 call 结果void 方法返回 None"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
if self_ptr is None:
return None
# 提前获取结构体 entry用 find_struct_by_type 规避跨模块同名 find_struct 找错)
# 用于 SHA1 查找和虚表分派
cmop_entry: HandlesStruct.StructEntry | t.CPtr = None
cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr)
if cmop_struct_ty is not None:
cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty)
if cmop_entry is None:
cmop_entry = HandlesStruct.find_struct(class_name)
# 构造方法查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
# 查找函数(支持 SHA1 后缀匹配)
found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name)
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
# found_func 为 Nonestub 未注入):用类所属模块的 SHA1 构造调用名
# 优先从 entry 获取 SHA1规避跨模块同名 find_struct 找错)
cls_sha1: str = None
if cmop_entry is not None:
cls_sha1 = cmop_entry.ModuleSha1
else:
cls_sha1 = HandlesStruct.get_struct_sha1(class_name)
if cls_sha1 is None and trans is not None:
# fallback: 从 from_imports 查找类所属模块的 SHA1含截断处理
cls_sha1 = _lookup_mod_sha1(pool, trans._from_imports, class_name)
if cls_sha1 is None:
err_msg: t.CChar | t.CPtr = pool.alloc(256)
if err_msg is not None:
viperlib.snprintf(err_msg, 256, "'%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name)
HandlesType.fatal_error(None, err_msg)
HandlesType.fatal_error(None, "找不到模块 SHA1")
mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2
mangled2: str = pool.alloc(mangled_len2)
if mangled2 is not None:
viperlib.snprintf(mangled2, mangled_len2, "%s.%s", cls_sha1, lookup_name)
call_name = mangled2
# 确定返回类型__before_init__ 和 __init__ 返回 void
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty
if found_func is not None:
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
# 构建参数链表: self_ptr → extra_args...
llvmlite.value_set_next(self_ptr, None)
head: llvmlite.Value | t.CPtr = self_ptr
tail: llvmlite.Value | t.CPtr = self_ptr
if extra_args is not None and extra_count > 0:
for ei in range(extra_count):
arg_addr: t.CSizeT = extra_args[ei]
if arg_addr == 0:
continue
av: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(arg_addr, t.CPtr))
if av is not None:
llvmlite.value_set_next(av, None)
llvmlite.value_set_next(tail, av)
tail = av
total_count: int = 1 + extra_count
# 默认参数填入:如果调用点参数少于函数定义参数,用零值填充缺失参数
# 这处理 list[int](bd) 中 elem_size=0 默认值缺失的情况
if found_func is not None:
param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_idx: int = 0
# 跳过已提供的参数
while skip_idx < total_count and param_node is not None:
param_node = llvmlite.param_get_next(param_node)
skip_idx += 1
# 为剩余参数填入零值
while param_node is not None:
missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node)
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty)
if zero_val is not None:
llvmlite.value_set_next(zero_val, None)
llvmlite.value_set_next(tail, zero_val)
tail = zero_val
total_count += 1
param_node = llvmlite.param_get_next(param_node)
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
# 复用前面已获取的 cmop_entryfind_struct_by_type 规避跨模块同名找错)
if found_func is not None:
cmop_has_vt: int = 0
cmop_method_idx: int = -1
if cmop_entry is not None:
cmop_has_vt = cmop_entry.HasVTable
if cmop_has_vt == 1 and cmop_entry.VTableMethods is not None:
cmop_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(cmop_entry.VTableMethods, t.CPtr))
for cmop_mi in range(cmop_entry.VTableMethodCount):
cmop_mname_addr: t.CSizeT = cmop_methods_arr[cmop_mi]
if cmop_mname_addr == 0:
continue
cmop_mname: str = (str | t.CPtr)(t.CVoid(cmop_mname_addr, t.CPtr))
if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0:
cmop_method_idx = cmop_mi
break
if cmop_has_vt == 1 and cmop_method_idx >= 0:
return _do_virtual_call(pool, builder, mod, class_name, method_name,
self_ptr, head, total_count, found_func, call_ret_ty)
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# ============================================================
# _infer_method_ret_ty - 根据方法名推断返回类型
#
# stub 未注入时find_func_in_module 返回 None
# 需要根据方法名推断返回类型避免指针被截断为 i32。
# ============================================================
def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr,
method_name: str) -> llvmlite.LLVMType | t.CPtr:
"""根据方法名推断返回类型stub 未注入时的回退方案)"""
if pool is None or method_name is None:
return llvmlite.Int32(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
# 返回 i8* 的方法(分配/返回指针)
if string.strcmp(method_name, "alloc") == 0:
return i8_ptr_ty
if string.strcmp(method_name, "calloc") == 0:
return i8_ptr_ty
if string.strcmp(method_name, "realloc") == 0:
return i8_ptr_ty
if string.strcmp(method_name, "alloc_buf") == 0:
return i8_ptr_ty
if string.strcmp(method_name, "_fl_pop") == 0:
return i8_ptr_ty
if string.strcmp(method_name, "_buddy_of") == 0:
return i8_ptr_ty
if string.strcmp(method_name, "_split_to_order") == 0:
return i8_ptr_ty
if string.strcmp(method_name, "__enter__") == 0:
return i8_ptr_ty
# 返回 void 的方法
if string.strcmp(method_name, "__before_init__") == 0:
return llvmlite.Void(pool)
# 默认 i32free, reset, __init__, __exit__, _fl_push 等)
return llvmlite.Int32(pool)
# ============================================================
# _translate_method_call - 翻译方法调用 obj.method(args)
#
# 生成: call <ret_ty> @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...)
#
# obj_ptr 是对象变量的 allocaPtr(StructTy)),作为 self 参数传入
# ============================================================
def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
obj_ptr: llvmlite.Value | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""翻译方法调用,返回 call 结果 Value"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
if obj_ptr is None or cl is None:
return None
# 提前获取结构体 entry用 find_struct_by_type 规避跨模块同名 find_struct 找错)
# 用于继承链遍历、SHA1 查找和虚表分派
mc_entry: HandlesStruct.StructEntry | t.CPtr = None
mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr)
if mc_struct_ty is not None:
mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty)
if mc_entry is None:
mc_entry = HandlesStruct.find_struct(class_name)
# 构造方法查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
# 查找函数(支持 SHA1 后缀匹配)
found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, lookup_name)
# 沿继承链查找父类方法(子类未覆盖时回退到父类)
if found_func is None:
cur_parent: str = None
if mc_entry is not None:
cur_parent = mc_entry.ParentName
else:
cur_parent = HandlesStruct.get_parent_name(class_name)
while cur_parent is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", cur_parent, method_name)
parent_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
break
# 后续父类按名查找(无 ParentSha1只能按名回退
cur_parent = HandlesStruct.get_parent_name(cur_parent)
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
# found_func 为 Nonestub 未注入):用类所属模块的 SHA1 构造调用名
# 沿继承链查找第一个有 SHA1 的类
cls_sha1_mc: str = None
if mc_entry is not None:
cls_sha1_mc = mc_entry.ModuleSha1
else:
cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name)
if cls_sha1_mc is None:
cur_p: str = None
if mc_entry is not None:
cur_p = mc_entry.ParentName
else:
cur_p = HandlesStruct.get_parent_name(class_name)
while cur_p is not None and cls_sha1_mc is None:
cls_sha1_mc = HandlesStruct.get_struct_sha1(cur_p)
cur_p = HandlesStruct.get_parent_name(cur_p)
if cls_sha1_mc is not None:
mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2
mangled_mc: str = pool.alloc(mangled_len_mc)
if mangled_mc is not None:
viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name)
call_name = mangled_mc
# 确定返回类型
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if found_func is not None:
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
else:
# found_func 为 Nonestub 未注入):根据方法名推断返回类型
call_ret_ty = _infer_method_ret_ty(pool, method_name)
# 翻译调用参数
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = 0
if cargs is not None:
can = cargs.__len__()
# 构建参数链表: obj_ptr → arg1 → arg2 → ...
llvmlite.value_set_next(obj_ptr, None)
head: llvmlite.Value | t.CPtr = obj_ptr
tail: llvmlite.Value | t.CPtr = obj_ptr
for ai in range(can):
arg_node: ast.AST | t.CPtr = cargs.get(ai)
if arg_node is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node, None, 0, trans)
if arg_val is None:
continue
llvmlite.value_set_next(arg_val, None)
llvmlite.value_set_next(tail, arg_val)
tail = arg_val
total_count: int = 1 + can
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
# (不依赖 found_func — 继承的虚方法可能没有子类实现)
# 复用前面已获取的 mc_entryfind_struct_by_type 规避跨模块同名找错)
mc_has_vt: int = 0
mc_method_idx: int = -1
if mc_entry is not None:
mc_has_vt = mc_entry.HasVTable
if mc_has_vt == 1 and mc_entry.VTableMethods is not None:
mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr))
for mc_mi in range(mc_entry.VTableMethodCount):
mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi]
if mc_mname_addr == 0:
continue
mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr))
if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0:
mc_method_idx = mc_mi
break
if mc_has_vt == 1 and mc_method_idx >= 0:
return _do_virtual_call(pool, builder, mod, class_name, method_name,
obj_ptr, head, total_count, found_func, call_ret_ty)
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# ============================================================
# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名
#
# 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a"
# 跳过 % 前缀后逐字符比较
# ============================================================
def _kwarg_name_matches(kw_arg: str,
param_name: t.CChar | t.CPtr) -> int:
"""检查关键字参数名 kw_arg 是否匹配参数名 param_name跳过 % 前缀)"""
if kw_arg is None or param_name is None:
return 0
start: t.CSizeT = 0
if param_name[0] == '%':
start = 1
for i, ch in enumerate(kw_arg):
c: t.CChar = param_name[start + i]
if c == '\0' or c != ch:
return 0
if param_name[start + i + 1] != '\0':
return 0
return 1
# ============================================================
# _translate_struct_ctor_kw — 结构体构造函数(关键字参数)
#
# 支持两种语法:
# Point(x=10, y=20) — 全关键字
# Point(10, y=20) — 混合(位置 + 关键字)
#
# 位置参数按字段索引赋值,关键字参数按字段名查找赋值
# ============================================================
def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
keywords: list[ast.AST | t.CPtr] | t.CPtr,
kw_count: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""结构体构造函数(关键字参数版本)"""
# 创建临时 alloca
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return llvmlite.ConstZero(pool, struct_ty)
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
# 用 find_struct_by_type 规避跨模块同名 find_struct 找错
kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
is_oop: int = 0
if kw_entry is not None:
is_oop = kw_entry.IsOOP
if is_oop != 0:
_call_method_on_ptr(pool, builder, mod, class_name,
"__before_init__", tmp, None, 0, trans)
else:
# 普通结构体store zeroinitializer + 应用默认值
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
llvmlite.build_store(builder, zero, tmp)
_apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
# 先处理位置参数(按字段索引,覆盖默认值)
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None:
continue
fe: HandlesStruct.FieldEntry | t.CPtr = None
if kw_entry is not None:
fe = HandlesStruct._get_field_entry(kw_entry, ai)
else:
fe = HandlesStruct.get_field_by_index(class_name, ai)
if fe is None:
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
continue
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty)
llvmlite.build_store(builder, arg_val, field_ptr)
# 处理关键字参数(按字段名查找)
# SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错)
kw_sha1: str = None
if kw_entry is not None:
kw_sha1 = kw_entry.ModuleSha1
for ki in range(kw_count):
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
if kw is None or kw.arg is None or kw.value is None:
continue
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class(
class_name, kw.arg, kw_sha1)
if fe is None:
continue
kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, kw.value, None, 0, trans)
if kw_val is None:
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
continue
kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty)
llvmlite.build_store(builder, kw_val, field_ptr)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
# ============================================================
# _translate_call_with_kwargs — 带关键字参数的函数调用
#
# 支持两种语法:
# add(b=4, a=3) — 全关键字乱序
# greet("Hello", name="World") — 位置 + 关键字混合
#
# 策略: 遍历 found_func.Params 链表,对每个参数:
# 1. 若位置参数仍有剩余param_idx < can取位置参数
# 2. 否则按参数名匹配关键字参数
# 3. 按参数顺序构建调用参数链表
# ============================================================
def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
func_name: str,
found_func: llvmlite.Function | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
keywords: list[ast.AST | t.CPtr] | t.CPtr,
kw_count: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""带关键字参数的函数调用,按参数顺序构建调用链表
使用 llvmlite 访问器函数绕过 stub 类型限制:
found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub
类型中字段不足,直接访问会被 TransPyC 静默跳过。
"""
head: llvmlite.Value | t.CPtr = None
tail: llvmlite.Value | t.CPtr = None
actual_count: t.CSizeT = 0
# memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染)
mc_dst1: llvmlite.Value | t.CPtr = None
mc_src1: llvmlite.Value | t.CPtr = None
mc_num1: llvmlite.Value | t.CPtr = None
# 遍历函数参数链表(使用访问器获取 Head
param_idx: t.CSizeT = 0
cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
while cur_param is not None:
arg_val: llvmlite.Value | t.CPtr = None
if param_idx < can:
# 优先使用位置参数
arg: ast.AST | t.CPtr = cargs.get(param_idx)
if arg is not None:
arg_val = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
else:
# 查找匹配的关键字参数
param_name: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param)
if param_name is not None:
for ki in range(kw_count):
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
if kw is None or kw.arg is None or kw.value is None:
continue
if _kwarg_name_matches(kw.arg, param_name) == 1:
arg_val = HandlesExpr.translate_value(
builder, pool, mod, kw.value, None, 0, trans)
break
if arg_val is not None:
# 类型转换(按参数类型,使用访问器)
param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param)
if param_ty is not None:
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, param_ty)
arg_val.Next = None
if head is None:
head = arg_val
else:
tail.Next = arg_val
tail = arg_val
# memcpy 专用: 保存前三个参数的独立引用
if actual_count == 0:
mc_dst1 = arg_val
elif actual_count == 1:
mc_src1 = arg_val
elif actual_count == 2:
mc_num1 = arg_val
actual_count += 1
param_idx += 1
cur_param = llvmlite.param_get_next(cur_param)
# 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器)
# t.CExtern/t.State/t.CExport 函数declare使用裸名不加 SHA1 前缀
call_name: str = func_name
if llvmlite.function_is_declared(found_func) == 0:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
# 返回类型(使用访问器)
call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if call_ret_ty is None:
call_ret_ty = _infer_external_func_ret_ty(pool, func_name)
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
if func_name == "memcpy" and actual_count >= 3:
return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1)
return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0)
# ============================================================
# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换
#
# 当 func 是 t.XXX 形式且 XXX 是已知类型名map_t_type 能映射)时,
# 将 value 转换为目标类型:
# - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64)
# - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*)
# - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8)
# - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*)
# ============================================================
def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
val: llvmlite.Value | t.CPtr,
target_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
"""类型转换:根据参数类型和目标类型选择转换方式"""
if val is None or target_ty is None:
return None
val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty)
# 整数 → 整数: trunc/zext
if val_bits != 0 and target_bits != 0:
if val_bits == target_bits:
return val
elif val_bits < target_bits:
return llvmlite.build_zext(builder, val, target_ty)
else:
return llvmlite.build_trunc(builder, val, target_ty)
# 指针 → 整数: ptrtoint
if val_bits == 0 and target_bits != 0:
return llvmlite.build_ptrtoint(builder, val, target_ty)
# 整数 → 指针: inttoptr
if val_bits != 0 and target_bits == 0:
return llvmlite.build_inttoptr(builder, val, target_ty)
# 指针 → 指针: bitcast
return llvmlite.build_bitcast(builder, val, target_ty)
# ============================================================
# 泛型实例化辅助:从 Subscript slice 提取类型实参名
# ============================================================
# _get_type_name_from_annotation 已移至 HandlesType.py支持 BinOp/Attribute
# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用
def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr,
slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr:
"""从 Subscript.slice 提取类型实参名列表
list[int] -> ["int"]
dict[str, int] -> ["str", "int"]
list[AST | t.CPtr] -> ["AST|t.CPtr"]
"""
if slice_node is None or pool is None:
return None
result: list[str] | t.CPtr = list[str](pool, 4)
k: int = slice_node.kind()
if k == ast.ASTKind.Tuple:
tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node)
elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts
if elts is not None:
n: t.CSizeT = elts.__len__()
i: t.CSizeT
for i in range(n):
elt: ast.AST | t.CPtr = elts.get(i)
tn: str = HandlesType._get_type_name_from_annotation(pool, elt)
if tn is not None:
result.append(tn)
else:
tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node)
if tn is not None:
result.append(tn)
return result
# ============================================================
# 翻译函数调用 Call(func, args) — 模块级版本
# ============================================================
def translate_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
node: ast.AST | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""翻译函数调用,返回 call 结果 Value"""
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
if cl is None:
return None
func_name: str = HandlesExpr.get_func_name(cl.func)
if func_name is None:
# 检查是否是 list[int](pool) 形式的泛型实例化调用
# Subscript 节点作为 Call func: 泛型类构造函数
if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None:
sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func)
if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name:
gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value)
gen_class_name: str = gen_nm_node.id
# 检查是否是泛型类模板
template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_class_name)
if template_cd is not None:
# 提取类型实参
gen_type_args: list[str] | t.CPtr = _extract_type_args_from_slice(pool, sub_node.slice)
if gen_type_args is not None and gen_type_args.__len__() > 0:
# 特化泛型类,返回特化类名
spec_name: str = HandlesClassDef._specialize_generic_class(
trans, gen_class_name, gen_type_args)
if spec_name is not None:
func_name = spec_name
else:
# 泛型类模板未找到:可能未 import 定义模块
gt_err: str = pool.alloc(256)
if gt_err is not None:
viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name)
HandlesType.fatal_error(gen_nm_node, gt_err)
HandlesType.fatal_error(gen_nm_node, "泛型类模板未找到")
if func_name is None:
# 检查是否是 (A | t.CPtr)(value) 形式的类型转换
# BinOp 节点作为 Call func: 联合类型注解用作类型转换
if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None:
binop_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, cl.func, trans._imported_modules, trans._from_imports)
if binop_ty is not None:
binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if binop_args is not None and binop_args.__len__() == 1:
binop_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans)
if binop_arg_val is not None:
return _translate_t_type_cast(pool, builder, binop_arg_val, binop_ty)
return None
# 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR不生成 call
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name:
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value)
if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0:
if string.strcmp(func_name, "Deref") == 0:
return translate_c_deref(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "DerefAs") == 0:
return translate_c_derefas(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Addr") == 0:
return translate_c_addr(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Load") == 0:
return translate_c_load(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Asm") == 0:
return translate_c_asm(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "LLVMIR") == 0:
return translate_c_llvmir(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0:
# c.LInp/c.LOut 独立调用时返回 0仅在 c.LLVMIR 的 f-string 内有意义)
return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0")
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = 0
if cargs is not None:
can = cargs.__len__()
# 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等
# 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用)
# 支持:
# 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name)
# 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name))
# t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name:
tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value)
if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0:
target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name)
if target_ty is not None:
tc_effective_can: t.CSizeT = can
# 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty)
# 注意: void* 在 LLVM 中非法CVoid* 应表示为 i8*
if can == 2:
tc_arg2_node: ast.AST | t.CPtr = cargs.get(1)
if tc_arg2_node is not None and tc_arg2_node.kind() == ast.ASTKind.Attribute:
tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node)
if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0:
if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name:
tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value)
if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0:
# CVoid* → i8*LLVM 中 void* 表示为 i8*
match target_ty:
case llvmlite.LLVMType.Void():
target_ty = llvmlite.Int8(pool)
case _:
pass
target_ty = llvmlite.Ptr(pool, target_ty)
tc_effective_can = 1
if tc_effective_can == 1:
tc_arg_node: ast.AST | t.CPtr = cargs.get(0)
if tc_arg_node is not None:
tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, tc_arg_node, None, 0, trans)
if tc_arg_val is not None:
return _translate_t_type_cast(pool, builder, tc_arg_val, target_ty)
# t.XXX 类型转换已确认但不满足参数条件:返回 None不跌落到跨模块 FATAL
return None
# 检测 ClassName.__sizeof__() — 返回结构体大小常量i64
# __sizeof__ 是内置方法,不走跨模块调用路径
# 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__()
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0:
if sz_at.value is not None and can == 0:
sz_cls_name: str = None
sz_vk: int = sz_at.value.kind()
if sz_vk == ast.ASTKind.Name:
sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value)
sz_cls_name = sz_cls_nm2.id
elif sz_vk == ast.ASTKind.Attribute:
sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value)
sz_cls_name = sz_inner_at.attr
if sz_cls_name is not None:
# 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__()
sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name)
# 联合类型(如 AST|t.CPtr按指针大小处理8 字节)
# 联合类型在 TPV 中表示指针,可以指向多种类型
# 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理
if string.strstr(sz_cls_name, "|") is not None:
return llvmlite.const_int64(pool, 8)
# 内置类型 sizeofint=4, str/bytes=8 指针, double=8 等)
sz_builtin: int = -1
if string.strcmp(sz_cls_name, "int") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "str") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "bytes") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CInt") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "CInt8T") == 0:
sz_builtin = 1
elif string.strcmp(sz_cls_name, "CInt16T") == 0:
sz_builtin = 2
elif string.strcmp(sz_cls_name, "CInt32T") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "CInt64T") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CChar") == 0:
sz_builtin = 1
elif string.strcmp(sz_cls_name, "CDouble") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CFloat") == 0:
sz_builtin = 4
elif string.strcmp(sz_cls_name, "CPtr") == 0:
sz_builtin = 8
elif string.strcmp(sz_cls_name, "CSizeT") == 0:
sz_builtin = 8
if sz_builtin >= 0:
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")
# ConstInt 的 name 参数是 IR 文本表示ValuePrint 输出时使用 Name 而非 IntVal
# 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值
return llvmlite.const_int64(pool, sz_builtin)
sz_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(
sz_cls_name)
if sz_struct_ty is not None:
sz_val: int = HandlesClassDef._get_type_size(sz_struct_ty)
if sz_val > 0:
return llvmlite.const_int64(pool, sz_val)
# 类型已注册但大小为 0opaque struct 或字段链表未填充):报错终止
stdio.printf("[FATAL][__sizeof__] 类型 '%s' 已注册但大小为 0字段链表未填充立即终止编译\n", sz_cls_name)
sys.exit(1)
# 类型未注册:报错终止,不静默返回 0会导致 malloc(0)/alloc(0) 堆溢出)
stdio.printf("[FATAL][__sizeof__] 类型 '%s' 未在结构体表中注册,无法计算大小,立即终止编译\n", sz_cls_name)
sys.exit(1)
# 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8i64
# __len__ 是 list[T] 的内置方法list 是泛型类不注册 struct
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0:
if len_at.value is not None and can == 0:
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_name_value(
builder, pool, len_at.value, trans)
if obj_val is not None:
i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")
# ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0
# 导致 GEP 索引为 0访问 __data__而非 1访问 __count__
idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty_len, obj_val, idx_one)
if count_ptr is not None:
return llvmlite.build_load(builder, i64_ty_len, count_ptr)
# 检测方法调用: obj.method(args)
# 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if method_at is not None and method_at.value is not None:
if method_at.value.kind() == ast.ASTKind.Name and trans is not None:
method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value)
if method_obj_nm.id is not None:
# 查找对象变量
obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, method_obj_nm.id)
if obj_var is not None and obj_var.Ty is not None:
# 检查是否为 Ptr(Struct(...))(结构体值变量)
# 或 Ptr(Ptr(Struct(...)))(指针变量,需 load
match obj_var.Ty:
case llvmlite.LLVMType.Ptr(obj_struct_ty):
class_nm: str = HandlesStruct.get_class_name_by_type(
pool, obj_struct_ty)
if class_nm is not None:
return _translate_method_call(
pool, builder, mod, class_nm, func_name,
obj_var, cl, trans)
# 指针变量: alloca 类型是 Ptr(Ptr(Struct))
# load 获取实际指针 Ptr(Struct) 后再查找
match obj_struct_ty:
case llvmlite.LLVMType.Ptr(inner_struct_ty):
inner_nm: str = HandlesStruct.get_class_name_by_type(
pool, inner_struct_ty)
if inner_nm is not None:
obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, obj_struct_ty, obj_var)
if obj_ptr is not None:
return _translate_method_call(
pool, builder, mod, inner_nm, func_name,
obj_ptr, cl, trans)
# AnnotClassName 回退:联合类型简化为 Ptr(i8) 时,
# 通过原始类型注解的类名查找结构体
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, method_obj_nm.id)
if var_entry is not None and var_entry.AnnotClassName is not None:
annot_val: str = var_entry.AnnotClassName
# 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy"
dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.')
cls_nm2: str = annot_val
mod_nm2: str = None
if dot_ptr is not None:
cls_nm2 = dot_ptr + 1
total_len_av: t.CSizeT = string.strlen(annot_val)
cls_len_av: t.CSizeT = string.strlen(cls_nm2)
mod_len2: t.CSizeT = total_len_av - cls_len_av - 1
mod_nm2 = pool.alloc(mod_len2 + 1)
if mod_nm2 is not None:
string.strncpy(mod_nm2, annot_val, mod_len2)
mod_nm2[mod_len2] = '\0'
# 检查结构体是否已注册
if HandlesStruct.get_struct_type(cls_nm2) is not None:
# 结构体已注册load obj_ptr 走方法调用
i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty2, obj_var)
if obj_ptr2 is not None:
return _translate_method_call(
pool, builder, mod, cls_nm2, func_name,
obj_ptr2, cl, trans)
else:
# 结构体未注册(跨模块依赖未翻译):
# 用模块名查 SHA1 构造方法调用名
sha1_fc: str = None
if mod_nm2 is not None:
sha1_fc = _lookup_module_sha1(mod_nm2)
if sha1_fc is not None:
# 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名
mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3
mangled3: str = pool.alloc(mlen3)
if mangled3 is not None:
viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name)
# load obj_ptr (self)
i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty3, obj_var)
if obj_ptr3 is not None:
# 构建参数链表: obj_ptr3 (self) → 其他参数
llvmlite.value_set_next(obj_ptr3, None)
head3: llvmlite.Value | t.CPtr = obj_ptr3
tail3: llvmlite.Value | t.CPtr = obj_ptr3
for ai3 in range(can):
arg3: ast.AST | t.CPtr = cargs.get(ai3)
if arg3 is not None:
arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg3, None, 0, trans)
if arg_val3 is not None:
llvmlite.value_set_next(arg_val3, None)
llvmlite.value_set_next(tail3, arg_val3)
tail3 = arg_val3
total3: int = 1 + can
ret_ty3: llvmlite.LLVMType | t.CPtr = _infer_method_ret_ty(pool, func_name)
return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0)
# ============================================================
# 检测 self.field.method() 调用
#
# 当 method_at.value 是 Attribute字段访问如 self.__pool__
# 翻译字段值获取对象指针,然后走方法调用路径。
#
# 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))
# 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时)
# ============================================================
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if attr_method_at is not None and attr_method_at.value is not None:
if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None:
inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value)
if inner_attr is not None and inner_attr.attr is not None:
# 翻译 self.__pool__ 获取字段值(已 load 的对象指针)
field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans)
if field_obj is not None and field_obj.Ty is not None:
field_cls_nm: str = None
# 路径1: 从字段值的 LLVM 类型获取类名
match field_obj.Ty:
case llvmlite.LLVMType.Ptr(field_struct_ty):
field_cls_nm = HandlesStruct.get_class_name_by_type(
pool, field_struct_ty)
# 路径2: 从字段注解类名回退查找
if field_cls_nm is None:
if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name:
inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value)
if inner_name_node is not None and inner_name_node.id is not None:
inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, inner_name_node.id)
if inner_var is not None and inner_var.Ty is not None:
match inner_var.Ty:
case llvmlite.LLVMType.Ptr(field_owner_struct_ty):
field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
field_owner_struct_ty, inner_attr.attr)
if field_info is not None:
field_annot: str = HandlesStruct.get_field_annot_class_name(field_info)
if field_annot is not None:
dot_p: t.CChar | t.CPtr = string.strrchr(field_annot, 46)
if dot_p is not None:
field_cls_nm = dot_p + 1
else:
field_cls_nm = field_annot
if field_cls_nm is not None:
return _translate_method_call(
pool, builder, mod, field_cls_nm, func_name,
field_obj, cl, trans)
# ============================================================
# 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__()
# list[T] 是泛型类不注册 struct方法调用处理器上方无法处理
# 需要在此特殊处理。
# list 结构布局 (6 字段 × 8 字节):
# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40)
# ============================================================
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if lm_at is not None and lm_at.attr is not None and lm_at.value is not None:
lm_name: str = lm_at.attr
# 判断是否是 list 方法名
lm_is_list: int = 0
if string.strcmp(lm_name, "get") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1
elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1
if lm_is_list == 1 and trans is not None:
# 翻译 list 对象
lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans)
if lm_obj is not None:
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# get / __getitem__: 返回 index 处的元素
if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0:
if can >= 1:
# 加载 __data__ (偏移 0)
g_idx0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 0, "0")
g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0)
g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp)
# 加载 __elem_size__ (偏移 32, index 4)
g_idx4: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 4, "0")
g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4)
g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp)
# 翻译 index
g_idx_node: ast.AST | t.CPtr = cargs.get(0)
g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, g_idx_node, None, 0, trans)
if g_data is not None and g_esize is not None and g_idx_val is not None:
g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, g_idx_val, i64_ty)
g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize)
g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset)
if g_addr is not None:
return llvmlite.build_load(builder, i8_ptr_ty, g_addr)
# set / __setitem__: 设置 index 处的元素
elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0:
if can >= 2:
s_idx0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 0, "0")
s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0)
s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp)
s_idx4: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 4, "0")
s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4)
s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp)
s_idx_node: ast.AST | t.CPtr = cargs.get(0)
s_val_node: ast.AST | t.CPtr = cargs.get(1)
s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, s_idx_node, None, 0, trans)
s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, s_val_node, None, 0, trans)
if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None:
s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, s_idx_val, i64_ty)
s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize)
s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset)
if s_addr is not None:
s_val_ptr: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, s_val_val, i8_ptr_ty)
llvmlite.build_store(builder, s_val_ptr, s_addr)
return None
# pop: 返回最后一个元素count--
elif string.strcmp(lm_name, "pop") == 0:
p_idx1: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 1, "0")
p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1)
p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp)
p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub(
builder, p_count, llvmlite.ConstInt(pool, i64_ty, 1, "0"))
llvmlite.build_store(builder, p_nc, p_cpp)
p_idx0: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 0, "0")
p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0)
p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp)
p_idx4: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 4, "0")
p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4)
p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp)
if p_data is not None and p_esize is not None and p_nc is not None:
p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize)
p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset)
if p_addr is not None:
return llvmlite.build_load(builder, i8_ptr_ty, p_addr)
# clear: count = 0
elif string.strcmp(lm_name, "clear") == 0:
c_idx1: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 1, "0")
c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1)
llvmlite.build_store(builder, llvmlite.ConstInt(pool, i64_ty, 0, "0"), c_cpp)
return None
# __iter__: iter_index = 0, return self
elif string.strcmp(lm_name, "__iter__") == 0:
it_idx5: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i64_ty, 5, "0")
it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5)
llvmlite.build_store(builder, llvmlite.ConstInt(pool, i64_ty, 0, "0"), it_ipp)
return lm_obj
# append: 直接调用 list.append(self, item)
# append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现
elif string.strcmp(lm_name, "append") == 0:
if can >= 1:
ap_sha1: str = _lookup_module_sha1("_list")
if ap_sha1 is not None:
ap_mlen: t.CSizeT = string.strlen(ap_sha1) + 13
ap_mangled: str = pool.alloc(ap_mlen)
if ap_mangled is not None:
viperlib.snprintf(ap_mangled, ap_mlen, "%s.list.append", ap_sha1)
ap_item_node: ast.AST | t.CPtr = cargs.get(0)
ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, ap_item_node, None, 0, trans)
if ap_item_val is not None:
llvmlite.value_set_next(lm_obj, None)
llvmlite.value_set_next(ap_item_val, None)
llvmlite.value_set_next(lm_obj, ap_item_val)
ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0)
# 获取关键字参数
keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
kw_count: t.CSizeT = 0
if keywords is not None:
kw_count = keywords.__len__()
# 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20)
# 命名空间隔离:严格模式下检查结构体可见性
# - 裸名 Class(): 需要 from X import Class 或本地定义
# - 模块限定 Module.Class(): 需要 import Module
# 用 find_struct_by_module 规避跨模块同名 find_struct 找错
struct_ty: llvmlite.LLVMType | t.CPtr = None
gen_ctor_entry: HandlesStruct.StructEntry | t.CPtr = None
vis: int = HandlesStruct.is_struct_visible(func_name)
if vis != 0:
if trans is not None:
gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1)
if gen_ctor_entry is None:
gen_ctor_entry = HandlesStruct.find_struct(func_name)
if gen_ctor_entry is not None:
struct_ty = gen_ctor_entry.Ty
elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name:
mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value)
imp_ok: int = HandlesImports.is_module_imported(trans._imported_modules, mod_nm_qc.id)
if imp_ok != 0:
if trans is not None:
gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1)
if gen_ctor_entry is None:
gen_ctor_entry = HandlesStruct.find_struct(func_name)
if gen_ctor_entry is not None:
struct_ty = gen_ctor_entry.Ty
if struct_ty is not None:
if can == 0 and kw_count == 0:
# OOP 结构体:即使无参数也调用 __before_init__
# 用 gen_ctor_entry 规避跨模块同名 find_struct 找错
ctor_is_oop: int = 0
if gen_ctor_entry is not None:
ctor_is_oop = gen_ctor_entry.IsOOP
if ctor_is_oop != 0:
return _translate_struct_ctor(
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
# 普通结构体:检查是否有默认值(用 entry 直接访问)
gen_has_defaults: int = 0
if gen_ctor_entry is not None:
for gdi in range(gen_ctor_entry.FieldCount):
gdf: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
gen_ctor_entry, gdi)
if gdf is not None and gdf.DefaultVal is not None:
gen_has_defaults = 1
break
else:
gen_has_defaults = HandlesStruct.struct_has_defaults(func_name)
if gen_has_defaults == 1:
# 有默认值:走构造函数路径应用默认值
return _translate_struct_ctor(
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
# 无默认值:返回 zeroinitializer
ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
return ret
if kw_count > 0:
# 有关键字参数:按字段名赋值
return _translate_struct_ctor_kw(
pool, builder, mod, struct_ty, func_name, cargs, can,
keywords, kw_count, trans)
# 仅位置参数:按字段顺序构建
return _translate_struct_ctor(
pool, builder, mod, struct_ty, func_name, cargs, can, trans)
# 查找函数:优先从函数表按裸名精确匹配(同模块函数),
# 再从模块函数链表按后缀匹配SHA1 前缀名)。
# stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None
# 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*
# 如果调用方未传 funcs_ptr/func_count如 AnnAssign 路径),从 trans 获取
actual_funcs: HandlesExprCall.FuncEntry | t.CPtr = funcs_ptr
actual_func_count: int = func_count
if actual_funcs is None and trans is not None:
actual_funcs = trans._funcs
actual_func_count = trans._func_count
found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, func_name)
# 使用访问器绕过 stub 类型限制
found_ret_ty: llvmlite.LLVMType | t.CPtr = None
found_params: t.CPtr = None
if found_func is not None:
found_ret_ty = llvmlite.function_get_ret_ty(found_func)
found_params = llvmlite.function_get_params(found_func)
if found_ret_ty is not None:
call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty
else:
call_ret_ty = _infer_external_func_ret_ty(pool, func_name)
# 如果模块中找不到函数,检查是否是变量(闭包调用)
if found_func is None:
closure_ptr: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name)
if closure_ptr is not None:
return translate_closure_call(pool, builder, mod, closure_ptr,
cargs, can)
# 翻译参数并链接
# 有关键字参数且找到函数定义时,按参数名匹配
if kw_count > 0 and found_func is not None and found_params is not None:
return _translate_call_with_kwargs(
pool, builder, mod, func_name, found_func,
cargs, can, keywords, kw_count, trans)
head: llvmlite.Value | t.CPtr = None
tail: llvmlite.Value | t.CPtr = None
# memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染)
mc_dst2: llvmlite.Value | t.CPtr = None
mc_src2: llvmlite.Value | t.CPtr = None
mc_num2: llvmlite.Value | t.CPtr = None
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is not None:
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is not None:
# 参数类型提升:当 found_func 为 Nonestub 未注入)时,
# 根据外部函数签名推断期望类型,提升字面量(如 i32→i64
# 避免 declare(i64) 与 call(i32) 类型不匹配
if found_func is None and arg_val.Ty is not None:
ext_param_ty: llvmlite.LLVMType | t.CPtr = _get_external_func_param_ty(
pool, func_name, ai)
if ext_param_ty is not None:
val_bits_ap: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
tgt_bits_ap: int = HandlesExpr.get_llvm_type_bits(ext_param_ty)
if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap:
if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap:
arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty)
else:
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, ext_param_ty)
arg_val.Next = None
if head is None:
head = arg_val
else:
tail.Next = arg_val
tail = arg_val
# memcpy 专用: 保存前三个参数的独立引用
if ai == 0:
mc_dst2 = arg_val
elif ai == 1:
mc_src2 = arg_val
elif ai == 2:
mc_num2 = arg_val
# 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi"
# t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名
# declare 函数IsDeclared=1使用裸名func_namedefine 函数使用实际名(可能带 SHA1 前缀)
call_name: str = func_name
if found_func is not None:
if llvmlite.function_is_declared(found_func) == 0:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
# 跨模块函数调用found_func 为 None 时,检查是否是模块限定调用
# 如 string.strchr(...) → @{sha1_of_string}.strchr
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if xmod_at.value is not None and xmod_at.value.kind() == ast.ASTKind.Name:
xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value)
if xmod_nm.id is not None:
mod_sha1: str = _lookup_module_sha1(xmod_nm.id)
if mod_sha1 is not None:
# CExport 函数定义用裸名(@strlen跨模块调用需用裸名而非 @{sha1}.func
if is_cexport_func(mod_sha1, func_name) != 0:
call_name = func_name
else:
mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2
mangled: str = pool.alloc(mangled_len)
if mangled is not None:
viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name)
call_name = mangled
else:
# t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用
if string.strcmp(xmod_nm.id, "t") == 0 or string.strcmp(xmod_nm.id, "c") == 0:
call_name = func_name
else:
# Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline
# 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到),
# 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导)
is_imported_mod: int = 0
if trans is not None and trans._imported_modules is not None:
is_imported_mod = HandlesImports.is_module_imported(
trans._imported_modules, xmod_nm.id)
if is_imported_mod != 0:
# 已导入模块但 SHA1 未注册:该模块未被编译,立即报错
err_msg_imp: t.CChar | t.CPtr = pool.alloc(256)
if err_msg_imp is not None:
viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_nm.id)
HandlesType.fatal_error(xmod_nm, err_msg_imp)
HandlesType.fatal_error(xmod_nm, "已导入模块 SHA1 未注册")
else:
# 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType
# LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名,
# 但 Ptr 是 __types 模块的模块级函数
# 禁用 star import 回退xmod_nm.id 是明确名称,不应回退到 star import 模块
from_sha1: str = None
if trans is not None and trans._from_imports is not None:
from_sha1 = _lookup_mod_sha1(pool, trans._from_imports, xmod_nm.id, 0)
if from_sha1 is not None:
# CExport 函数定义用裸名,跨模块调用需用裸名
if is_cexport_func(from_sha1, func_name) != 0:
call_name = func_name
else:
fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2
fmangled: str = pool.alloc(fmangled_len)
if fmangled is not None:
viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name)
call_name = fmangled
else:
err_msg2: t.CChar | t.CPtr = pool.alloc(256)
if err_msg2 is not None:
viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_nm.id, func_name)
HandlesType.fatal_error(xmod_nm, err_msg2)
HandlesType.fatal_error(xmod_nm, "跨模块调用找不到模块 SHA1")
else:
# 裸名调用(非 Attribute检查 from_imports
# 裸名调用允许 star import 回退from stdint import * 导入的名称(如 BYTEPTR需要通过 star import 查找
if trans is not None and trans._from_imports is not None:
bare_sha1: str = _lookup_mod_sha1(pool, trans._from_imports, func_name, 1)
if bare_sha1 is not None:
if is_cexport_func(bare_sha1, func_name) != 0:
call_name = func_name
else:
bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(func_name) + 2
bare_mangled: str = pool.alloc(bare_mangled_len)
if bare_mangled is not None:
viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, func_name)
call_name = bare_mangled
else:
err_msg3: t.CChar | t.CPtr = pool.alloc(256)
if err_msg3 is not None:
viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name)
HandlesType.fatal_error(node, err_msg3)
HandlesType.fatal_error(node, "裸名调用未定义且未导入")
else:
err_msg4: t.CChar | t.CPtr = pool.alloc(256)
if err_msg4 is not None:
viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name)
HandlesType.fatal_error(node, err_msg4)
HandlesType.fatal_error(node, "裸名调用未定义且未导入")
# 直接调用
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
if func_name == "memcpy" and can >= 3:
return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2)
return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, 0)
# ============================================================
# 翻译闭包调用 — 通过闭包指针间接调用
#
# 闭包结构: {i8* fn_ptr, i8* env_ptr} (16 字节)
# 调用过程:
# 1. load closure_ptr 从变量 alloca
# 2. load fn_ptr 从 offset 0
# 3. load env_ptr 从 offset 8
# 4. bitcast fn_ptr to i32 (i8*)*
# 5. call i32 %fn_typed(i8* %env_ptr)
# ============================================================
def translate_closure_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
closure_alloca: llvmlite.Value | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""通过闭包指针间接调用"""
if builder is None or closure_alloca is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 1. 加载闭包指针 (i8*)
closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca)
if closure_ptr is None:
return None
# 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8*
fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty))
if fn_ptr_addr is None:
return None
fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr)
if fn_raw is None:
return None
# 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8*
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8)
env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val)
if env_addr is None:
return None
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr)
if env_ptr is None:
return None
# 4. bitcast fn_raw to i32 (i8*)*
param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, 1)
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty)
if fn_typed is None:
return None
# 5. 间接调用: call i32 %fn_typed(i8* %env_ptr)
env_ptr.Next = None
return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty)
# ============================================================
# 翻译 printf 调用 — 模块级版本
# ============================================================
def translate_printf_call(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None):
"""翻译 printf 调用(特殊处理格式字符串)"""
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None:
return
can: t.CSizeT = cargs.__len__()
if can == 0:
return
arg0: ast.AST | t.CPtr = cargs.get(0)
if arg0 is None:
return
fmt_str: str = None
arg0_kind: int = arg0.kind()
if arg0_kind == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0)
if cn.const_kind == ast.CONST_STR:
fmt_str = cn.str_val
if fmt_str is None:
return
fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
builder, pool, mod, fmt_str, trans)
if fmt_ptr is None:
return
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 翻译额外参数并链接
prev: llvmlite.Value | t.CPtr = fmt_ptr
for ai in range(1, can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is not None:
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is not None:
# C ABI integer promotion: i8/i16 → i32printf 变参函数要求)
arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
if arg_bits != 0 and arg_bits < 32:
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, i32_ty)
# C ABI float promotion: float → doubleprintf 变参函数要求)
arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty)
if arg_fbits != 0 and arg_fbits < 64:
double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, double_ty)
arg_val.Next = None
prev.Next = arg_val
prev = arg_val
prev.Next = None
# is_variadic=1: 生成带显式函数类型签名的 call如 call i32 (i8*, ...) @printf
# 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器)
llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1)
# ============================================================
# FuncEntry 结构体(用于函数表)
# ============================================================
@t.NoVTable
class FuncEntry:
"""函数表条目"""
Name: str
Func: llvmlite.Function | t.CPtr
# ============================================================
# 初始化函数表
# ============================================================
def init_func_table(pool: memhub.MemBuddy | t.CPtr,
max_count: int) -> FuncEntry | t.CPtr:
"""分配并清零函数表数组"""
size: t.CSizeT = max_count * FuncEntry.__sizeof__()
funcs_ptr: FuncEntry | t.CPtr = pool.alloc(size)
if funcs_ptr is not None:
string.memset(funcs_ptr, 0, size)
return funcs_ptr
# ============================================================
# 查找函数
# ============================================================
def find_func_in_table(funcs: FuncEntry | t.CPtr,
func_count: int,
name: str) -> llvmlite.Function | t.CPtr:
"""在函数表中按名称查找,返回 Function 指针或 None"""
if name is None or funcs is None:
return None
entry_size: t.CSizeT = FuncEntry.__sizeof__()
for i in range(func_count):
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry.Func
return None
# ============================================================
# 添加函数到函数表
# ============================================================
def add_func_to_table(funcs: FuncEntry | t.CPtr,
func_count: int,
name: str,
func: llvmlite.Function | t.CPtr,
max_count: int) -> int:
"""添加函数到函数表,返回 0 成功"""
if name is None or func is None or funcs is None:
return 1
if func_count >= max_count:
return 1
entry_size: t.CSizeT = FuncEntry.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size
entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
entry.Name = name
entry.Func = func
# 同时注册到全局函数表(供跨模块 vtable 初始化查找)
_register_global_func(name, func)
return 0
# ============================================================
# 全局函数注册表(跨模块函数查找)
#
# 所有模块翻译的函数都会注册到此表(通过 add_func_to_table 自动注册)。
# 主要用途: vtable 初始化时查找跨模块继承方法的 Function 对象,
# 以获取函数类型信息构造 bitcast 字符串。
# ============================================================
GLOBAL_FUNC_MAX: t.CDefine = 8192
_global_funcs: FuncEntry | t.CPtr = None
_global_func_count: int = 0
def _init_global_func_table() -> int:
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)"""
global _global_funcs
global _global_func_count
if _global_funcs is not None:
return 1
size: t.CSizeT = GLOBAL_FUNC_MAX * FuncEntry.__sizeof__()
_global_funcs = stdlib.malloc(size)
if _global_funcs is None:
return 0
string.memset(_global_funcs, 0, size)
_global_func_count = 0
return 1
def _register_global_func(name: str, func: llvmlite.Function | t.CPtr) -> int:
"""注册函数到全局表(已存在则跳过),返回 0 成功
直接操作全局表,不调用 add_func_to_table避免递归。
"""
global _global_func_count
if name is None or func is None:
return 1
if _init_global_func_table() == 0:
return 1
# 已存在则跳过(避免重复)
if find_func_in_table(_global_funcs, _global_func_count, name) is not None:
return 0
if _global_func_count >= GLOBAL_FUNC_MAX:
return 1
# 直接写入全局表(不调用 add_func_to_table避免递归
entry_size: t.CSizeT = FuncEntry.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(_global_funcs) + _global_func_count * entry_size
entry: FuncEntry | t.CPtr = (FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
entry.Name = name
entry.Func = func
_global_func_count += 1
return 0
def find_func_global(name: str) -> llvmlite.Function | t.CPtr:
"""在全局函数表中按名称查找,返回 Function 指针或 None"""
if name is None or _global_funcs is None:
return None
return find_func_in_table(_global_funcs, _global_func_count, name)
# ============================================================
# ExprCallHandle - 函数调用处理器Mixin 继承模式)
#
# HandleCall / HandlePrintfCall 提供 trans 接口
# ============================================================
@t.NoVTable
class ExprCallHandle(HandlesBase.Mixin):
"""函数调用处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# HandleCall - 翻译函数调用,返回 call 结果 Value
# ============================================================
def HandleCall(self, node: ast.AST | t.CPtr) -> llvmlite.Value | t.CPtr:
"""翻译函数调用,从 self.Trans 获取共享状态"""
return translate_call(
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
node,
self.Trans._funcs, self.Trans._func_count, self.Trans)
# ============================================================
# HandlePrintfCall - 翻译 printf 调用
# ============================================================
def HandlePrintfCall(self, cl: ast.Call | t.CPtr):
"""翻译 printf 调用,从 self.Trans 获取共享状态"""
translate_printf_call(
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
cl, self.Trans)
# ============================================================
# NewExprCallHandle - 工厂函数
# ============================================================
def NewExprCallHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ExprCallHandle | t.CPtr:
h: ExprCallHandle | t.CPtr = pool.alloc(ExprCallHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, ExprCallHandle.__sizeof__())
h.Trans = trans
return h