6666 lines
365 KiB
Plaintext
6666 lines
365 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import sys
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.VLogger as VLogger
|
||
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.HandlesNonlocal as HandlesNonlocal
|
||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||
import lib.core.Handles.HandlesImports as HandlesImports
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
import lib.core.StubMerger as StubMerger
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
|
||
|
||
# ============================================================
|
||
# CallGenMixin - 调用分派 Mixin(对象化 P4,wiki/14-oo-refactor.md)
|
||
#
|
||
# 从 HandlesExprCall.vp(7043 行,本仓库最大文件)迁移:
|
||
# 模块级纯函数(translate_call/translate_c_*/_translate_method_call/
|
||
# _do_virtual_call/va_arg 系列/函数表/默认参数表等)→ 类方法
|
||
# 全局状态(_g_cexport_*/_g_llvmir_reg_seq/_g_temp_dir/
|
||
# _g_closure_*/_g_funcptr_*/_global_funcs/_global_defaults)→ 本类字段
|
||
#
|
||
# 迁移原则(与 P2/P3 一致,行为零变化):
|
||
# 1. 方法保留原函数签名(含 pool/builder/mod 首参),仅函数体内的
|
||
# 本模块函数调用改为 self.xxx(...)
|
||
# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx/StubMerger.xxx 等)
|
||
# 保留模块前缀
|
||
# 3. AsmOperand/FuncEntry/FuncDefaultsEntry 类保留在 HandlesExprCall.vp
|
||
# 4. HandlesExprCall.vp 原函数保留为"委托":本地模块级单例 _g_gen
|
||
# (BuildPipeline/main 注入)cast 成 Generator 类型
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesExprCall 保持一致)
|
||
# ============================================================
|
||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||
_CEXPORT_MAX: t.CDefine = 256
|
||
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
|
||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||
# text.ll 读取缓冲区大小(原 HandlesExprCall 模块级常量)
|
||
_TEXT_LL_READ_BUF_SIZE: t.CDefine = 262144
|
||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||
|
||
|
||
# ============================================================
|
||
# CallGenMixin - 调用分派/类型转换/c.*/stdarg/函数表
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenMixin:
|
||
"""调用分派 Mixin(状态从 HandlesExprCall 全局变量迁入)"""
|
||
|
||
# --- c.cexport 注册表(原 _g_cexport_sha1_arr/_g_cexport_func_arr/_g_cexport_count) ---
|
||
CexportSha1Arr: bytes
|
||
CexportFuncArr: bytes
|
||
CexportCount: int
|
||
|
||
# --- LLVMIR 寄存器序号(原 _g_llvmir_reg_seq) ---
|
||
LLVMIRRegSeq: int
|
||
|
||
# --- temp 目录(原 _g_temp_dir/_g_temp_dir_len) ---
|
||
TempDir: str
|
||
TempDirLen: t.CSizeT
|
||
|
||
# --- 闭包名表(原 _g_closure_names/_g_closure_count) ---
|
||
ClosureNames: t.CChar | t.CPtr
|
||
ClosureCount: int
|
||
|
||
# --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) ---
|
||
FuncptrNames: t.CChar | t.CPtr
|
||
FuncptrRets: t.CUInt64T | t.CPtr
|
||
FuncptrCount: int
|
||
|
||
# --- 全局函数注册表(原 _global_funcs/_global_func_count) ---
|
||
GlobalFuncs: HandlesExprCall.FuncEntry | t.CPtr
|
||
GlobalFuncCount: int
|
||
|
||
# --- 全局默认参数表(原 _global_defaults/_global_defaults_count) ---
|
||
GlobalDefaults: HandlesExprCall.FuncDefaultsEntry | t.CPtr
|
||
GlobalDefaultsCount: int
|
||
|
||
def InitCallGen(self) -> int:
|
||
"""初始化调用 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
|
||
if self is None:
|
||
return 1
|
||
self.CexportSha1Arr = None
|
||
self.CexportFuncArr = None
|
||
self.CexportCount = 0
|
||
self.LLVMIRRegSeq = 0
|
||
self.TempDir = None
|
||
self.TempDirLen = 0
|
||
self.ClosureNames = None
|
||
self.ClosureCount = 0
|
||
self.FuncptrNames = None
|
||
self.FuncptrRets = None
|
||
self.FuncptrCount = 0
|
||
self.GlobalFuncs = None
|
||
self.GlobalFuncCount = 0
|
||
self.GlobalDefaults = None
|
||
self.GlobalDefaultsCount = 0
|
||
return 0
|
||
|
||
# ============================================================
|
||
# P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp:
|
||
# 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR)
|
||
# 本模块函数调用改 self.,外部模块调用保留模块前缀
|
||
# ============================================================
|
||
|
||
def _lookup_module_sha1(self, mod_name: str) -> str:
|
||
"""查找模块名对应的 SHA1,找不到返回 None
|
||
|
||
委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。
|
||
"""
|
||
return StubMerger.LookupSha1ByModName(mod_name)
|
||
|
||
def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str:
|
||
"""后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types"
|
||
|
||
用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点),
|
||
去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。
|
||
委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。
|
||
"""
|
||
return StubMerger.LookupSha1ByModNameSuffix(mod_suffix)
|
||
|
||
def register_cexport_func(self, sha1: str, func_name: str) -> int:
|
||
"""注册 CExport 函数到全局表(sha1+func_name 二元组)"""
|
||
if sha1 is None or func_name is None:
|
||
return 0
|
||
if self.CexportSha1Arr is None:
|
||
self.CexportSha1Arr = stdlib.malloc(_CEXPORT_MAX * 17)
|
||
self.CexportFuncArr = stdlib.malloc(_CEXPORT_MAX * 64)
|
||
if self.CexportSha1Arr is None or self.CexportFuncArr is None:
|
||
return 0
|
||
string.memset(self.CexportSha1Arr, 0, _CEXPORT_MAX * 17)
|
||
string.memset(self.CexportFuncArr, 0, _CEXPORT_MAX * 64)
|
||
if self.CexportCount < _CEXPORT_MAX:
|
||
idx: t.CSizeT = t.CSizeT(self.CexportCount) * 17
|
||
string.strcpy(self.CexportSha1Arr + idx, sha1)
|
||
idx2: t.CSizeT = t.CSizeT(self.CexportCount) * 64
|
||
string.strcpy(self.CexportFuncArr + idx2, func_name)
|
||
self.CexportCount += 1
|
||
return 1
|
||
return 0
|
||
|
||
def is_cexport_func(self, sha1: str, func_name: str) -> int:
|
||
"""检查 (sha1, func_name) 是否是 CExport 函数"""
|
||
if sha1 is None or func_name is None:
|
||
return 0
|
||
if self.CexportSha1Arr is None:
|
||
return 0
|
||
for i in range(self.CexportCount):
|
||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||
if string.strcmp(self.CexportSha1Arr + idx, sha1) == 0:
|
||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||
if string.strcmp(self.CexportFuncArr + idx2, func_name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _lookup_mod_sha1(self, 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
|
||
return self._lookup_sha1_from_modname_raw(pool, mod_name_raw)
|
||
|
||
def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod_name_raw: str) -> str:
|
||
"""从原始模块名查找 SHA1,返回 None=未找到"""
|
||
# 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区
|
||
mod_len: t.CSizeT = 0
|
||
while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':':
|
||
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 = self._lookup_module_sha1(base_mod)
|
||
if sha1 is None:
|
||
sha1 = self._lookup_module_sha1_suffix(base_mod)
|
||
return sha1
|
||
|
||
def find_func_in_module(self, 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
|
||
|
||
def _ensure_c_lib_declare(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
name: str) -> llvmlite.Function | t.CPtr:
|
||
"""为已知的 C 库函数创建 declare 声明"""
|
||
if pool is None or mod is None or name is None:
|
||
return None
|
||
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
|
||
ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||
params: int = 0 # 参数数量
|
||
|
||
if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0:
|
||
ret_ty = i64_ty
|
||
params = 1
|
||
elif string.strcmp(name, "memset") == 0:
|
||
ret_ty = i8_ptr_ty
|
||
params = 3
|
||
elif string.strcmp(name, "memcpy") == 0:
|
||
ret_ty = i8_ptr_ty
|
||
params = 3
|
||
elif string.strcmp(name, "memmove") == 0:
|
||
ret_ty = i8_ptr_ty
|
||
params = 3
|
||
elif string.strcmp(name, "memcmp") == 0:
|
||
ret_ty = i32_ty
|
||
params = 3
|
||
elif string.strcmp(name, "strcmp") == 0:
|
||
ret_ty = i32_ty
|
||
params = 2
|
||
elif string.strcmp(name, "strncmp") == 0:
|
||
ret_ty = i32_ty
|
||
params = 3
|
||
elif string.strcmp(name, "strcpy") == 0:
|
||
ret_ty = i8_ptr_ty
|
||
params = 2
|
||
elif string.strcmp(name, "strncpy") == 0:
|
||
ret_ty = i8_ptr_ty
|
||
params = 3
|
||
elif string.strcmp(name, "strcat") == 0:
|
||
ret_ty = i8_ptr_ty
|
||
params = 2
|
||
elif string.strcmp(name, "puts") == 0:
|
||
ret_ty = i32_ty
|
||
params = 1
|
||
elif string.strcmp(name, "atoi") == 0:
|
||
ret_ty = i32_ty
|
||
params = 1
|
||
elif string.strcmp(name, "atol") == 0:
|
||
ret_ty = i64_ty
|
||
params = 1
|
||
elif string.strcmp(name, "abs") == 0:
|
||
ret_ty = i32_ty
|
||
params = 1
|
||
elif string.strcmp(name, "labs") == 0:
|
||
ret_ty = i64_ty
|
||
params = 1
|
||
else:
|
||
return None
|
||
|
||
# 创建 declare
|
||
fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty)
|
||
if fn is None:
|
||
return None
|
||
# 添加参数
|
||
if params == 1:
|
||
if string.strcmp(name, "abs") == 0:
|
||
llvmlite.add_param(pool, fn, i32_ty, "n")
|
||
elif string.strcmp(name, "labs") == 0:
|
||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||
else:
|
||
llvmlite.add_param(pool, fn, i8_ptr_ty, "s")
|
||
elif params == 2:
|
||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||
llvmlite.add_param(pool, fn, i8_ptr_ty, "src")
|
||
elif params == 3:
|
||
if string.strcmp(name, "memset") == 0:
|
||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||
llvmlite.add_param(pool, fn, i32_ty, "c")
|
||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||
else:
|
||
llvmlite.add_param(pool, fn, i8_ptr_ty, "dst")
|
||
llvmlite.add_param(pool, fn, i8_ptr_ty, "src")
|
||
llvmlite.add_param(pool, fn, i64_ty, "n")
|
||
return fn
|
||
|
||
def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr,
|
||
func_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""根据函数名推断外部 includes 函数的返回类型
|
||
|
||
支持三种函数名形式:
|
||
1. 裸名: "parse", "strlen"
|
||
2. 别名: "json_parse"(from X import parse as json_parse)
|
||
3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name)
|
||
"""
|
||
if pool is None or func_name is None:
|
||
return llvmlite.Int32(pool)
|
||
|
||
# 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse")
|
||
# SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔
|
||
bare_name: str = func_name
|
||
dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.')
|
||
if dot_pos is not None:
|
||
# '.' 后的部分是裸函数名
|
||
bare_name = dot_pos + 1
|
||
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
|
||
# 返回 i8* 的函数(指针返回值,截断会导致错误)
|
||
if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0:
|
||
return i8_ptr_ty
|
||
# JSON 解析函数返回 JsonValue*(指针)
|
||
# from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖
|
||
if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0:
|
||
return i8_ptr_ty
|
||
# MemBuddy 方法(当类型信息丢失时可能走外部函数路径)
|
||
if string.strcmp(func_name, "alloc") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
if string.strcmp(func_name, "calloc") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
if string.strcmp(func_name, "realloc") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
if string.strcmp(func_name, "alloc_buf") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
# VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃)
|
||
if string.strcmp(func_name, "get_logger") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
if string.strcmp(func_name, "fmt_buf") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
# Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏)
|
||
if string.strcmp(func_name, "get_includes_binary_dir") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
# HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断)
|
||
if string.strcmp(bare_name, "_parse_type_string") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
|
||
# 返回 i64 的函数
|
||
if string.strcmp(func_name, "strlen") == 0:
|
||
return llvmlite.Int64(pool)
|
||
if string.strcmp(func_name, "atoll") == 0:
|
||
return llvmlite.Int64(pool)
|
||
|
||
# 返回 double 的函数
|
||
if string.strcmp(func_name, "atof") == 0:
|
||
return llvmlite.Double(pool)
|
||
|
||
# 返回 i8 的函数
|
||
if string.strcmp(func_name, "samestr") == 0:
|
||
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 string.strcmp(func_name, "VirtualAlloc") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "HeapAlloc") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "HeapReAlloc") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "HeapCreate") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "GetProcessHeap") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "GlobalAlloc") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "GlobalFree") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "GlobalLock") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "LocalAlloc") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "LocalFree") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "GetProcAddress") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "GetModuleHandleA") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "GetModuleHandleW") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "LoadLibraryA") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "LoadLibraryW") == 0:
|
||
return i8_ptr_ty
|
||
# Win32 Handle 返回函数(HANDLE = void* = i8*)
|
||
if string.strcmp(func_name, "GetStdHandle") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "CreateFileA") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "CreateFileW") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "FindFirstFileA") == 0:
|
||
return i8_ptr_ty
|
||
if string.strcmp(func_name, "FindFirstFileW") == 0:
|
||
return i8_ptr_ty
|
||
|
||
# Win32 API 返回 i64 (SIZE_T) 的函数
|
||
if string.strcmp(func_name, "VirtualQuery") == 0:
|
||
return llvmlite.Int64(pool)
|
||
if string.strcmp(func_name, "HeapSize") == 0:
|
||
return llvmlite.Int64(pool)
|
||
if string.strcmp(func_name, "HeapCompact") == 0:
|
||
return llvmlite.Int64(pool)
|
||
if string.strcmp(func_name, "GlobalSize") == 0:
|
||
return llvmlite.Int64(pool)
|
||
|
||
# llvmlite build_* 函数返回类型推断
|
||
# stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32
|
||
# 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void
|
||
if string.strncmp(func_name, "build_", 6) == 0:
|
||
# 返回 void 的 build_* 函数(终止指令和无返回值指令)
|
||
if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \
|
||
string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \
|
||
string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \
|
||
string.strcmp(func_name, "build_switch") == 0:
|
||
return llvmlite.Void(pool)
|
||
# 其他 build_* 函数返回 Value*(指针)
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
|
||
# llvmlite 类型工厂函数返回 LLVMType*(指针)
|
||
# Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label
|
||
# new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针)
|
||
# const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针)
|
||
# function_get_name/param_get_ty 等访问器返回指针
|
||
if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \
|
||
string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \
|
||
string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \
|
||
string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \
|
||
string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \
|
||
string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \
|
||
string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \
|
||
string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \
|
||
string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \
|
||
string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \
|
||
string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \
|
||
string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \
|
||
string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0:
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
|
||
# 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324)
|
||
# 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出
|
||
# 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配
|
||
# x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致
|
||
# WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断
|
||
VLogger.warning(
|
||
f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}",
|
||
"HandlesExprCall")
|
||
return llvmlite.Int32(pool)
|
||
|
||
def _get_external_func_param_ty(self, 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"
|
||
]
|
||
|
||
# list 迭代不支持,用 range + get 替代
|
||
api_count: t.CSizeT = win32_apis.__len__()
|
||
for ai in range(api_count):
|
||
api_name: str = win32_apis.get(ai)
|
||
if string.strcmp(api_name, func_name) == 0:
|
||
return i64_ty
|
||
|
||
return None
|
||
|
||
def _emit_llvm_memcpy_intrinsic(self, 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 = self.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
|
||
|
||
def translate_c_deref(self, 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 按 ptr 的 pointee 类型"""
|
||
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
|
||
|
||
# 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容)
|
||
if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0:
|
||
pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||
if pointee is not None:
|
||
return llvmlite.build_load(builder, pointee, ptr_val)
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
return llvmlite.build_load(builder, i8_ty, ptr_val)
|
||
|
||
def translate_c_derefas(self, 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 ptr(bitcast 后 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
|
||
|
||
# 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val),
|
||
# 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要:
|
||
# LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值,
|
||
# 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。
|
||
# 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。
|
||
if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0 and HandlesExpr.is_ptr_type(val.Ty) != 0:
|
||
ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
|
||
val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee
|
||
if ptr_pointee is not None and val_pointee is not None:
|
||
# ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断)
|
||
if HandlesStruct.find_struct_by_type(ptr_pointee) is not None:
|
||
if ptr_pointee is val_pointee:
|
||
# 同一结构体类型:load 值再 store(结构体拷贝)
|
||
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(
|
||
builder, val_pointee, val)
|
||
if loaded is not None:
|
||
# bitcast ptr 到结构体指针再 store
|
||
struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, ptr_pointee)
|
||
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, ptr_val, struct_ptr_ty)
|
||
if casted_ptr is not None:
|
||
llvmlite.build_store(builder, loaded, casted_ptr)
|
||
return val
|
||
|
||
# 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
|
||
|
||
def translate_c_set(self, 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.Set(a, b) → a = 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
|
||
a_node: ast.AST | t.CPtr = cargs.get(0)
|
||
b_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, cargs.get(1), None, 0, trans)
|
||
if b_val is None:
|
||
return None
|
||
|
||
# 形态 1: c.Set(c.Deref(ptr), b) → *ptr = b
|
||
if a_node is not None and a_node.kind() == ast.ASTKind.Call:
|
||
d_call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(a_node)
|
||
if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute:
|
||
d_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(d_call.func)
|
||
if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0:
|
||
d_args: list[ast.AST | t.CPtr] | t.CPtr = d_call.args
|
||
if d_args is not None and d_args.__len__() >= 1:
|
||
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, d_args.get(0), None, 0, trans)
|
||
if ptr_val is not None:
|
||
val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty)
|
||
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, ptr_val, val_ptr_ty)
|
||
if casted_ptr is not None:
|
||
llvmlite.build_store(builder, b_val, casted_ptr)
|
||
return b_val
|
||
# 其他 Call 形态不可作左值
|
||
return b_val
|
||
|
||
# 形态 2: Name 变量赋值
|
||
if a_node is not None and a_node.kind() == ast.ASTKind.Name and trans is not None:
|
||
nm_set: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a_node)
|
||
if nm_set.id is not None:
|
||
if HT.is_global_name(trans, nm_set.id) != 0:
|
||
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
|
||
trans.SymTab, nm_set.id)
|
||
if mod_alloca is not None:
|
||
tg_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if mod_alloca.Ty is not None:
|
||
tg_ty = mod_alloca.Ty.Pointee
|
||
sv: llvmlite.Value | t.CPtr = b_val
|
||
if tg_ty is not None:
|
||
sv = HandlesExpr.coerce_to_type(builder, b_val, tg_ty, a_node)
|
||
llvmlite.build_store(builder, sv, mod_alloca)
|
||
return b_val
|
||
if HT.is_nonlocal_name(trans, nm_set.id) != 0:
|
||
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
|
||
trans, nm_set.id)
|
||
if nl_ptr is not None:
|
||
nl_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if nl_ptr.Ty is not None:
|
||
nl_ty = nl_ptr.Ty.Pointee
|
||
sv2: llvmlite.Value | t.CPtr = b_val
|
||
if nl_ty is not None:
|
||
sv2 = HandlesExpr.coerce_to_type(builder, b_val, nl_ty, a_node)
|
||
llvmlite.build_store(builder, sv2, nl_ptr)
|
||
return b_val
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
|
||
trans.SymTab, pool, builder, nm_set.id, b_val.Ty)
|
||
if alloca is not None:
|
||
ac_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if alloca.Ty is not None:
|
||
ac_ty = alloca.Ty.Pointee
|
||
sv3: llvmlite.Value | t.CPtr = b_val
|
||
if ac_ty is not None:
|
||
sv3 = HandlesExpr.coerce_to_type(builder, b_val, ac_ty, a_node)
|
||
llvmlite.build_store(builder, sv3, alloca)
|
||
return b_val
|
||
return b_val
|
||
|
||
# 形态 3: Attribute 字段赋值
|
||
if a_node is not None and a_node.kind() == ast.ASTKind.Attribute:
|
||
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
|
||
builder, pool, mod, a_node, trans)
|
||
if field_ptr is not None:
|
||
fd_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if field_ptr.Ty is not None:
|
||
fd_ty = field_ptr.Ty.Pointee
|
||
sv4: llvmlite.Value | t.CPtr = b_val
|
||
if fd_ty is not None:
|
||
sv4 = HandlesExpr.coerce_to_type(builder, b_val, fd_ty, a_node)
|
||
llvmlite.build_store(builder, sv4, field_ptr)
|
||
return b_val
|
||
|
||
return b_val
|
||
|
||
def translate_c_addr(self, 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:
|
||
return None
|
||
|
||
# Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load)
|
||
if arg0.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
|
||
if nm.id is None:
|
||
return None
|
||
if trans is not None:
|
||
# self/cls 对象引用:c.Addr(self) 返回对象指针本身(Ptr(Struct)),
|
||
# 而非指针变量的地址(Ptr(Ptr(Struct)))。方法与 Attribute 分支
|
||
# (c.Addr(self.field) 先 load self)语义一致,供
|
||
# return t.CVoid(c.Addr(self), CPtr) 返回 this 使用。
|
||
if string.strcmp(nm.id, "self") == 0 or string.strcmp(nm.id, "cls") == 0:
|
||
self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, nm.id)
|
||
if self_entry is not None and self_entry.Alloca is not None and self_entry.Alloca.Ty is not None:
|
||
match self_entry.Alloca.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner1):
|
||
match inner1:
|
||
case llvmlite.LLVMType.Ptr(inner2):
|
||
obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2)
|
||
return llvmlite.build_load(builder, obj_ty, self_entry.Alloca)
|
||
case _:
|
||
pass
|
||
case _:
|
||
pass
|
||
return HandlesVar.lookup_var(trans.SymTab, nm.id)
|
||
|
||
# Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load)
|
||
# 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作
|
||
if arg0.kind() == ast.ASTKind.Attribute:
|
||
if trans is None:
|
||
return None
|
||
at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
|
||
if at_addr is None or at_addr.attr is None or at_addr.value is None:
|
||
return None
|
||
# 解析 self(Name)→ 查找 alloca
|
||
if at_addr.value.kind() != ast.ASTKind.Name:
|
||
return None
|
||
self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value)
|
||
if self_nm.id is None:
|
||
return None
|
||
self_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, self_nm.id)
|
||
if self_alloca is None or self_alloca.Ty is None:
|
||
return None
|
||
# 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct)))
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = None
|
||
self_is_ptr_ptr: int = 0
|
||
match self_alloca.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner1):
|
||
match inner1:
|
||
case llvmlite.LLVMType.Ptr(inner2):
|
||
struct_ty = inner2
|
||
self_is_ptr_ptr = 1
|
||
case _:
|
||
struct_ty = inner1
|
||
case _:
|
||
return None
|
||
# 查找字段
|
||
fe_addr: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
|
||
struct_ty, at_addr.attr)
|
||
if fe_addr is None:
|
||
return None
|
||
# self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针
|
||
obj_ptr: llvmlite.Value | t.CPtr = self_alloca
|
||
if self_is_ptr_ptr == 1:
|
||
self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca)
|
||
if obj_ptr is None:
|
||
return None
|
||
# GEP 到字段地址
|
||
return llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index)
|
||
|
||
def translate_c_load(self, 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
|
||
|
||
def _asm_append_cstr(self, 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'
|
||
|
||
def _asm_escape_for_ir(self, 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
|
||
|
||
def _resolve_register(self, attr_name: str) -> str:
|
||
"""将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值"""
|
||
if attr_name is None:
|
||
return ""
|
||
|
||
# Clobber 破坏描述符
|
||
if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory"
|
||
if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc"
|
||
if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax"
|
||
if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx"
|
||
if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx"
|
||
if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx"
|
||
if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi"
|
||
if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi"
|
||
if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp"
|
||
if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp"
|
||
if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8"
|
||
if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9"
|
||
if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10"
|
||
if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11"
|
||
if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12"
|
||
if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13"
|
||
if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14"
|
||
if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15"
|
||
if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax"
|
||
if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx"
|
||
if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx"
|
||
if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx"
|
||
if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi"
|
||
if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi"
|
||
if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx"
|
||
if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax"
|
||
if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx"
|
||
if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si"
|
||
if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di"
|
||
|
||
# Output 输出约束
|
||
if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r"
|
||
if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m"
|
||
if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a"
|
||
if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b"
|
||
if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c"
|
||
if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d"
|
||
if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S"
|
||
if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D"
|
||
if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a"
|
||
if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b"
|
||
if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c"
|
||
if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d"
|
||
if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S"
|
||
if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D"
|
||
|
||
# Input/Register 输入约束
|
||
if string.strcmp(attr_name, "REG_ANY") == 0: return "r"
|
||
if string.strcmp(attr_name, "REG_EAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "REG_EBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "REG_ECX") == 0: return "c"
|
||
if string.strcmp(attr_name, "REG_EDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "REG_ESI") == 0: return "S"
|
||
if string.strcmp(attr_name, "REG_EDI") == 0: return "D"
|
||
if string.strcmp(attr_name, "REG_RAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "REG_RBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "REG_RCX") == 0: return "c"
|
||
if string.strcmp(attr_name, "REG_RDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "REG_RSI") == 0: return "S"
|
||
if string.strcmp(attr_name, "REG_RDI") == 0: return "D"
|
||
|
||
if string.strcmp(attr_name, "INPUT_REG") == 0: return "r"
|
||
if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m"
|
||
if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c"
|
||
if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S"
|
||
if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D"
|
||
if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a"
|
||
if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b"
|
||
if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c"
|
||
if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d"
|
||
if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S"
|
||
if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D"
|
||
|
||
return ""
|
||
|
||
def _resolve_asm_descr(self, 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 = self._resolve_asm_descr(pool, bop.left)
|
||
right_str: str = self._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 self._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 self._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 ""
|
||
|
||
def _asm_get_operand(self, base: HandlesExprCall.AsmOperand | t.CPtr,
|
||
idx: int) -> HandlesExprCall.AsmOperand | t.CPtr:
|
||
"""获取操作数数组中第 idx 个元素的指针"""
|
||
entry_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size
|
||
return (HandlesExprCall.AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
|
||
def _asm_is_c_call(self, 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
|
||
|
||
def _asm_add_operand(self, operands: HandlesExprCall.AsmOperand | t.CPtr,
|
||
count: int,
|
||
val: llvmlite.Value | t.CPtr,
|
||
constraint: str,
|
||
is_output: int) -> int:
|
||
"""添加操作数到数组,返回新计数(失败返回原计数)"""
|
||
if count >= ASM_MAX_OPERANDS:
|
||
return count
|
||
op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, count)
|
||
op.Value = val
|
||
op.Constraint = constraint
|
||
op.IsOutput = is_output
|
||
return count + 1
|
||
|
||
def translate_c_asm(self, 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 = HandlesExprCall.AsmOperand.__sizeof__()
|
||
operands: HandlesExprCall.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 = self._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 = self._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 = self._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 = self._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 = self._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 = self._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 = self._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 = self._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 = self._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 = self._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 = self._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 = self._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: HandlesExprCall.AsmOperand | t.CPtr = self._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: HandlesExprCall.AsmOperand | t.CPtr = self._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: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi3)
|
||
if op3.IsOutput != 0:
|
||
new_order[new_idx] = oi3
|
||
new_idx += 1
|
||
# 再放输入
|
||
for oi4 in range(operand_count):
|
||
op4: HandlesExprCall.AsmOperand | t.CPtr = self._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:
|
||
self._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)
|
||
self._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:
|
||
self._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: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i)
|
||
cons_val: str = cop.Constraint
|
||
if cons_val is None:
|
||
cons_val = "r"
|
||
|
||
if first_const == 0:
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
|
||
first_const = 0
|
||
|
||
if cop.IsOutput != 0:
|
||
# 输出约束:确保以 = 开头
|
||
if cons_val[0] != '=':
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=")
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val)
|
||
else:
|
||
self._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:
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
|
||
first_const = 0
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{")
|
||
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname)
|
||
self._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: HandlesExprCall.AsmOperand | t.CPtr = self._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:
|
||
self._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)
|
||
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf)
|
||
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ")
|
||
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name)
|
||
|
||
# ============================================================
|
||
# 7. 转义汇编文本
|
||
# ============================================================
|
||
escaped_asm: t.CChar | t.CPtr = self._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: HandlesExprCall.AsmOperand | t.CPtr = self._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
|
||
|
||
def translate_c_llvmir(self, 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:无返回值,直接嵌入原始 IR 文本
|
||
|
||
不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text
|
||
嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果,
|
||
嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。
|
||
"""
|
||
if cl is None or builder is None or pool is None or trans is None:
|
||
return None
|
||
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None or cargs.__len__() < 1:
|
||
HandlesType.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError")
|
||
|
||
# LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个
|
||
out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS)
|
||
out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS)
|
||
if out_alloca is None or out_regname is None:
|
||
return None
|
||
string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS)
|
||
string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS)
|
||
out_count: int = 0
|
||
|
||
# 模板文本缓冲区
|
||
text: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF)
|
||
if text is None:
|
||
return None
|
||
text[0] = '\0'
|
||
|
||
# ============================================================
|
||
# 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本
|
||
# ============================================================
|
||
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:
|
||
self._asm_append_cstr(text, 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:
|
||
continue
|
||
# 检测 c.LInp / c.LOut
|
||
if fexpr.kind() == ast.ASTKind.Call:
|
||
fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr)
|
||
attr_nm: str = self._asm_is_c_call(fcall)
|
||
if attr_nm is not None:
|
||
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:
|
||
# 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本)
|
||
inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, val_node, None, 0, trans)
|
||
if inp_val is not None and inp_val.Name is not None:
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name)
|
||
|
||
elif string.strcmp(attr_nm, "LOut") == 0:
|
||
# 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN,
|
||
# 记录写回(模板嵌入后 store 到变量 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 None or out_count >= LLVMIR_MAX_OPS:
|
||
HandlesType.fatal_error(
|
||
fcall,
|
||
f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}",
|
||
"TypeError")
|
||
self.LLVMIRRegSeq += 1
|
||
reg_buf: str = pool.alloc(32)
|
||
if reg_buf is not None:
|
||
viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", self.LLVMIRRegSeq)
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf)
|
||
out_alloca[out_count] = t.CSizeT(alloca)
|
||
out_regname[out_count] = t.CSizeT(reg_buf)
|
||
out_count += 1
|
||
continue
|
||
# 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本
|
||
ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, fexpr, None, 0, trans)
|
||
if ival is not None and ival.Name is not None:
|
||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name)
|
||
|
||
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(text, cn2.str_val)
|
||
|
||
# ============================================================
|
||
# 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回
|
||
# ============================================================
|
||
llvmlite.block_append_text(pool, builder.CurBlock, text)
|
||
|
||
# LOut 写回: store <ty> %llvmirN, <ty>* %var
|
||
oi: int
|
||
for oi in range(out_count):
|
||
oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr))
|
||
rn: str = (t.CChar | t.CPtr)(t.CVoid(out_regname[oi], t.CPtr))
|
||
if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None:
|
||
continue
|
||
reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool)
|
||
if reg_val is None:
|
||
continue
|
||
reg_val.Ty = oa.Ty.Pointee
|
||
reg_val.Name = rn
|
||
reg_val.IsConst = 0
|
||
llvmlite.build_store(builder, reg_val, oa)
|
||
|
||
return None
|
||
|
||
# ============================================================
|
||
# _apply_struct_defaults — 应用结构体字段的默认值
|
||
#
|
||
# 在 zeroinitializer 之后、显式参数之前调用
|
||
# 遍历所有字段,对有默认值的字段翻译并 store
|
||
# 显式参数(位置/关键字)后续会覆盖默认值
|
||
# ============================================================
|
||
def _apply_struct_defaults(self, 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:
|
||
# fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化
|
||
VLogger.error(
|
||
f"结构体类型未注册,无法应用默认值: {class_name}",
|
||
"HandlesExprCall")
|
||
return
|
||
for fi in range(entry.FieldCount):
|
||
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
|
||
entry, fi)
|
||
if fe is None:
|
||
# fast-fail: 字段索引越界(entry.FieldCount 与实际不一致)
|
||
VLogger.error(
|
||
f"字段索引越界,无法获取字段 entry: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
if 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:
|
||
# fast-fail: 默认值翻译失败(如引用了未定义符号)
|
||
VLogger.error(
|
||
f"字段默认值翻译失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, struct_ty, fe.Ty, tmp, fe.Index)
|
||
if field_ptr is None:
|
||
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
|
||
VLogger.error(
|
||
f"字段 GEP 失败,类型不匹配: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal)
|
||
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(self, 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
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
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
|
||
|
||
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
|
||
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
|
||
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
|
||
if is_oop == 0 and class_name is not None:
|
||
init_lookup_name: t.CChar | t.CPtr = pool.alloc(128)
|
||
if init_lookup_name is not None:
|
||
viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name)
|
||
# 方案1: 检查当前模块的函数声明
|
||
init_found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, init_lookup_name)
|
||
if init_found_func is not None:
|
||
is_oop = 1
|
||
if ctor_entry is not None:
|
||
ctor_entry.IsOOP = 1
|
||
ctor_entry.HasInit = 1
|
||
else:
|
||
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
|
||
init_defaults_entry: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(init_lookup_name)
|
||
if init_defaults_entry is not None:
|
||
is_oop = 1
|
||
if ctor_entry is not None:
|
||
ctor_entry.IsOOP = 1
|
||
ctor_entry.HasInit = 1
|
||
|
||
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
|
||
# 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法)
|
||
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 = self._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
|
||
# __new__ 只保证返回"实例存储指针",声明类型通常是
|
||
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
|
||
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
|
||
# obj.method(如 parser.add_argument)get_class_name_by_type
|
||
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
|
||
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
|
||
if new_ptr.Ty is not None:
|
||
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
|
||
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
|
||
if nw_bc is not None:
|
||
storage_ptr = nw_bc
|
||
|
||
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
|
||
self._call_method_on_ptr(pool, builder, mod, class_name,
|
||
"__before_init__", storage_ptr, None, 0, trans)
|
||
|
||
# 如果有 __init__,调用 __init__(ptr, args...)
|
||
# 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断
|
||
# (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference)
|
||
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
|
||
|
||
self._call_method_on_ptr(pool, builder, mod, class_name,
|
||
"__init__", storage_ptr, arg_vals, real_arg_count, trans)
|
||
elif has_new_flag == 0:
|
||
# 无 __init__ 且无 __new__:逐字段 store 参数值
|
||
# (有 __new__ 时参数已由 __new__ 消费,不应存入字段)
|
||
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:
|
||
# fast-fail: 参数翻译失败
|
||
VLogger.error(
|
||
f"构造函数参数翻译失败: {class_name}",
|
||
"HandlesExprCall")
|
||
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:
|
||
# fast-fail: 字段索引越界(用户传了多余参数)
|
||
VLogger.error(
|
||
f"构造函数参数过多,字段索引越界: {class_name}",
|
||
"HandlesExprCall")
|
||
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:
|
||
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
|
||
VLogger.error(
|
||
f"构造函数字段 GEP 失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg)
|
||
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)
|
||
|
||
# 应用默认值(显式参数会覆盖默认值)
|
||
self._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:
|
||
# fast-fail: 参数翻译失败
|
||
VLogger.error(
|
||
f"构造函数参数翻译失败: {class_name}",
|
||
"HandlesExprCall")
|
||
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:
|
||
# fast-fail: 字段索引越界(用户传了多余参数)
|
||
VLogger.error(
|
||
f"构造函数参数过多,字段索引越界: {class_name}",
|
||
"HandlesExprCall")
|
||
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:
|
||
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
|
||
VLogger.error(
|
||
f"构造函数字段 GEP 失败: {class_name}",
|
||
"HandlesExprCall")
|
||
continue
|
||
# 类型转换并 store
|
||
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg)
|
||
llvmlite.build_store(builder, arg_val, field_ptr)
|
||
|
||
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
|
||
return tmp
|
||
|
||
# ============================================================
|
||
# _translate_renum_construct — REnum 变体构造函数
|
||
#
|
||
# 语法: ClassName.VariantName(args...)
|
||
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1
|
||
#
|
||
# 生成 IR:
|
||
# %tmp = alloca {i32, i32, ...} ; REnum 类型
|
||
# store zeroinitializer, %tmp ; 清零
|
||
# %tag_ptr = gep %tmp, 0, 0 ; __tag 字段
|
||
# store i32 <tag_value>, %tag_ptr ; 写入 tag
|
||
# %p1_ptr = gep %tmp, 0, 1 ; _p1 字段
|
||
# store <coerced_arg0>, %p1_ptr ; 写入 payload[0]
|
||
# ... (更多 payload 字段)
|
||
# return %tmp ; 返回指针
|
||
#
|
||
# 对应 TPC 的 _HandleREnumConstructLlvm
|
||
# ============================================================
|
||
def _translate_renum_construct(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
variant_name: str,
|
||
tag_value: int,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""构造 REnum 变体实例,返回指向 alloca 的指针
|
||
|
||
class_name: REnum 类名(如 "LLVMType")
|
||
variant_name: 变体名(如 "Int")
|
||
tag_value: 变体的 tag 值(变体在类中的索引)
|
||
cargs: 参数 AST 列表
|
||
can: 参数数量
|
||
"""
|
||
if pool is None or builder is None or class_name is None:
|
||
return None
|
||
|
||
# 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名)
|
||
renum_entry: HandlesStruct.StructEntry | t.CPtr = None
|
||
if trans is not None:
|
||
renum_entry = HandlesStruct.find_struct_by_module(class_name, trans.ModuleSha1)
|
||
if renum_entry is None:
|
||
renum_entry = HandlesStruct.find_struct(class_name)
|
||
if renum_entry is None:
|
||
fb_re: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fb_re is not None:
|
||
viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name)
|
||
VLogger.error(fb_re, "RENUM")
|
||
return None
|
||
|
||
renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty
|
||
if renum_ty is None:
|
||
return None
|
||
|
||
# alloca REnum 类型
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||
HandlesStruct.ensure_struct_def_in_module(pool, mod, renum_ty)
|
||
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty)
|
||
if tmp is None:
|
||
return llvmlite.ConstZero(pool, renum_ty)
|
||
|
||
# 清零(确保未赋值的 payload 位置为零)
|
||
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty)
|
||
llvmlite.build_store(builder, zero, tmp)
|
||
|
||
# 写入 __tag 字段(索引 0)
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
tag_name_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||
if tag_name_buf is not None:
|
||
viperlib.snprintf(tag_name_buf, 32, "%d", tag_value)
|
||
tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
|
||
pool, i32_ty, tag_value,
|
||
tag_name_buf if tag_name_buf is not None else "0")
|
||
tag_field: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(renum_entry, 0)
|
||
tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||
if tag_field is not None and tag_field.Ty is not None:
|
||
tag_field_ty = tag_field.Ty
|
||
tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, renum_ty, tag_field_ty, tmp, 0)
|
||
if tag_ptr is not None:
|
||
llvmlite.build_store(builder, tag_const, tag_ptr)
|
||
|
||
# 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...)
|
||
# 参数按位置顺序填充 payload,跳过 __tag(索引 0)
|
||
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
|
||
# payload 字段索引 = ai + 1(跳过 __tag)
|
||
payload_idx: int = ai + 1
|
||
if payload_idx >= renum_entry.FieldCount:
|
||
break
|
||
pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
|
||
renum_entry, payload_idx)
|
||
if pfe is None:
|
||
continue
|
||
payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, renum_ty, pfe.Ty, tmp, payload_idx)
|
||
if payload_ptr is None:
|
||
continue
|
||
# 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce)
|
||
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, pfe.Ty, arg)
|
||
llvmlite.build_store(builder, arg_val, payload_ptr)
|
||
|
||
# 返回指针(与 _translate_struct_ctor 一致,赋值时由 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(self, 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_ty(LLVMType),需要找 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_func(stub 字段偏移问题)
|
||
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(self, 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,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""在结构体指针上调用方法,返回 call 结果(void 方法返回 None)
|
||
|
||
node: 触发本次调用的 AST 节点(如 Subscript 下标节点),用于 fatal_error
|
||
准确报告出错行号(传 None 时行号显示 0,不利于定位)。"""
|
||
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)
|
||
# fallback: 若 cmop_struct_ty 为 None 但 entry 存在,从 entry 获取类型
|
||
# 用于跨模块调用时 self_ptr 类型信息丢失的情况
|
||
if cmop_struct_ty is None and cmop_entry is not None:
|
||
cmop_struct_ty = cmop_entry.Ty
|
||
|
||
# 构造方法查找名: 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 = self.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 为 None(stub 未注入):用类所属模块的 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 = self._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(node, err_msg)
|
||
HandlesType.fatal_error(node, "找不到模块 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
|
||
elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0:
|
||
# fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着
|
||
# stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。
|
||
err_cm1: t.CChar | t.CPtr = pool.alloc(256)
|
||
if err_cm1 is not None:
|
||
viperlib.snprintf(err_cm1, 256,
|
||
"方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name)
|
||
HandlesType.fatal_error(node, err_cm1)
|
||
HandlesType.fatal_error(node, "方法返回类型无法确定")
|
||
else:
|
||
# found_func 为 None(跨模块调用 stub 未注入):无法从 declare 获取返回类型。
|
||
# __new__ 返回 Ptr(struct_ty)(构造函数返回自身指针,可推断)。
|
||
# __getitem__ 返回类型无法从 self 推断(可返回 i8* 如 HashTable.__getitem__
|
||
# -> t.CPtr,或 Ptr(JsonValue) 如 JsonValue.__getitem__)——推断 Ptr(cmop_struct_ty)
|
||
# 会与 define 返回类型不匹配,调用侧按错误类型读取返回值导致指针截断崩溃。
|
||
# fail-fast:__getitem__ 无 stub declare 立即报错,暴露依赖模块 vpi 缺失或
|
||
# 拓扑顺序错误(依赖模块未先翻译生成 vpi/text.ll)。
|
||
if string.strcmp(method_name, "__new__") == 0:
|
||
if cmop_struct_ty is not None:
|
||
call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty)
|
||
else:
|
||
err_cm2: t.CChar | t.CPtr = pool.alloc(256)
|
||
if err_cm2 is not None:
|
||
viperlib.snprintf(err_cm2, 256,
|
||
"方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name)
|
||
HandlesType.fatal_error(node, err_cm2)
|
||
HandlesType.fatal_error(node, "self 结构体类型未知")
|
||
elif string.strcmp(method_name, "__getitem__") == 0:
|
||
err_cm3: t.CChar | t.CPtr = pool.alloc(256)
|
||
if err_cm3 is not None:
|
||
viperlib.snprintf(err_cm3, 256,
|
||
"方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型",
|
||
class_name)
|
||
HandlesType.fatal_error(node, err_cm3)
|
||
HandlesType.fatal_error(node, "__getitem__ stub declare 未注入")
|
||
|
||
# 构建参数链表: 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
|
||
|
||
# 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数
|
||
# 优先用函数定义的默认值,无默认值时用零值兜底
|
||
# 查找函数的 defaults 信息
|
||
mdf_defaults: t.CVoid | t.CPtr = None
|
||
mdf_default_count: int = 0
|
||
mdf_param_count: int = 0
|
||
if trans is not None and trans._funcs is not None:
|
||
mdf_entry: FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_in_table(
|
||
trans._funcs, trans._func_count, lookup_name)
|
||
if mdf_entry is not None:
|
||
mdf_defaults = mdf_entry.Defaults
|
||
mdf_default_count = mdf_entry.DefaultCount
|
||
mdf_param_count = mdf_entry.ParamCount
|
||
if mdf_defaults is None:
|
||
mdf_gd: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(lookup_name)
|
||
if mdf_gd is not None:
|
||
mdf_defaults = mdf_gd.Defaults
|
||
mdf_default_count = mdf_gd.DefaultCount
|
||
mdf_param_count = mdf_gd.ParamCount
|
||
|
||
# 计算需要填充的参数(不含 self)
|
||
# extra_count = 已提供的非 self 参数数量
|
||
# mdf_param_count = 函数定义的非 self 参数数量
|
||
if mdf_param_count > extra_count:
|
||
mdf_offset: int = mdf_param_count - mdf_default_count
|
||
mdf_pi: int = extra_count
|
||
while mdf_pi < mdf_param_count:
|
||
# 优先用默认值
|
||
if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset:
|
||
mdf_di: int = mdf_pi - mdf_offset
|
||
if mdf_di < mdf_default_count:
|
||
# 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收,
|
||
# 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST)
|
||
mdf_val: llvmlite.Value | t.CPtr = None
|
||
if mdf_gd is not None:
|
||
mdf_val = HandlesExprCall._build_const_from_snapshot(
|
||
pool, mod, mdf_gd, mdf_di, trans, builder)
|
||
if mdf_val is None:
|
||
HandlesType.fatal_error(
|
||
cl,
|
||
f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}",
|
||
"TypeError")
|
||
continue
|
||
llvmlite.value_set_next(mdf_val, None)
|
||
llvmlite.value_set_next(tail, mdf_val)
|
||
tail = mdf_val
|
||
total_count += 1
|
||
mdf_pi += 1
|
||
continue
|
||
# 无默认值时用零值兜底(需要 found_func 获取参数类型)
|
||
if found_func is not None:
|
||
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
skip_z: int = 0
|
||
while skip_z <= mdf_pi and param_node_z is not None:
|
||
param_node_z = llvmlite.param_get_next(param_node_z)
|
||
skip_z += 1
|
||
if param_node_z is not None:
|
||
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
|
||
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_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
|
||
mdf_pi += 1
|
||
elif found_func is not None:
|
||
# 无默认参数信息但有 found_func:用零值填充(保留原有逻辑)
|
||
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_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty)
|
||
if zero_val2 is not None:
|
||
llvmlite.value_set_next(zero_val2, None)
|
||
llvmlite.value_set_next(tail, zero_val2)
|
||
tail = zero_val2
|
||
total_count += 1
|
||
param_node = llvmlite.param_get_next(param_node)
|
||
|
||
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0)
|
||
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
|
||
# 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾,
|
||
# 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。
|
||
if found_func is not None and head is not None:
|
||
pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
# 跳过 self 参数(索引 0)
|
||
if pc_param is not None:
|
||
pc_param = llvmlite.param_get_next(pc_param)
|
||
pc_node: llvmlite.Value | t.CPtr = head.Next
|
||
new_tail: llvmlite.Value | t.CPtr = head
|
||
if head is not None:
|
||
head.Next = None
|
||
while pc_node is not None:
|
||
pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next
|
||
coerced_pc: llvmlite.Value | t.CPtr = pc_node
|
||
if pc_param is not None:
|
||
pty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pc_param)
|
||
if pty_pc is not None:
|
||
c_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
|
||
builder, pc_node, pty_pc, None)
|
||
if c_pc is not None:
|
||
coerced_pc = c_pc
|
||
pc_param = llvmlite.param_get_next(pc_param)
|
||
coerced_pc.Next = None
|
||
new_tail.Next = coerced_pc
|
||
new_tail = coerced_pc
|
||
pc_node = pc_next_save
|
||
|
||
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
|
||
# 复用前面已获取的 cmop_entry(find_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 self._do_virtual_call(pool, builder, mod, class_name, method_name,
|
||
self_ptr, head, total_count, found_func, call_ret_ty)
|
||
|
||
# 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value
|
||
if found_func is None:
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||
|
||
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
|
||
|
||
# ============================================================
|
||
# _ensure_method_declare - 为跨模块方法调用创建 declare 声明
|
||
#
|
||
# 当 found_func 为 None(stub 未注入或跨模块调用)时,
|
||
# 在当前模块中创建函数声明,避免 llc 报 undefined value。
|
||
# ============================================================
|
||
def _ensure_method_declare(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
call_name: str,
|
||
ret_ty: llvmlite.LLVMType | t.CPtr,
|
||
param_head: llvmlite.ParamNode | t.CPtr,
|
||
param_count: int):
|
||
"""为跨模块方法调用创建 declare 声明
|
||
|
||
若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的
|
||
stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失
|
||
参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。
|
||
已存在的 define 不修改(其参数由定义决定)。
|
||
"""
|
||
if pool is None or mod is None or call_name is None:
|
||
return
|
||
# 检查模块中是否已有同名函数(declare 或 define)
|
||
existing: llvmlite.Function | t.CPtr = mod.FuncHead
|
||
while existing is not None:
|
||
if existing.Name is not None:
|
||
if string.strcmp(existing.Name, call_name) == 0:
|
||
# 已存在:仅当是 declare 且参数数量不足时追加缺失参数
|
||
if existing.IsDeclared == 1:
|
||
# 变长函数(*args,IsVarArg=1)不追加参数:多余实参由
|
||
# 变参机制(...)承接,追加有类型参数会导致调用侧把变参
|
||
# 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。
|
||
if existing.IsVarArg == 1:
|
||
return
|
||
# 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断)
|
||
cur_count: int = 0
|
||
cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing)
|
||
while cur_p is not None:
|
||
cur_count += 1
|
||
cur_p = cur_p.Next
|
||
# 只追加缺失的参数(cur_count < param_count 时)
|
||
if cur_count < param_count:
|
||
# 定位到 param_head 的第 cur_count 个节点开始追加
|
||
pnode2: llvmlite.ParamNode | t.CPtr = param_head
|
||
pi2: int = 0
|
||
# 跳过已有的 cur_count 个参数
|
||
while pnode2 is not None and pi2 < cur_count:
|
||
pnode2 = pnode2.Next
|
||
pi2 += 1
|
||
# 追加剩余参数
|
||
while pnode2 is not None and pi2 < param_count:
|
||
if pnode2.Ty is not None:
|
||
param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None)
|
||
if param2 is not None:
|
||
llvmlite.function_add_param(existing, param2)
|
||
pnode2 = pnode2.Next
|
||
pi2 += 1
|
||
return
|
||
existing = existing.Next
|
||
# 创建函数声明
|
||
func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty)
|
||
if func is None:
|
||
return
|
||
func.IsDeclared = 1
|
||
# 添加参数(declare 中参数名无意义,设为 None 只输出类型)
|
||
pnode: llvmlite.ParamNode | t.CPtr = param_head
|
||
pi: int = 0
|
||
while pnode is not None and pi < param_count:
|
||
if pnode.Ty is not None:
|
||
param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None)
|
||
if param is not None:
|
||
llvmlite.function_add_param(func, param)
|
||
pnode = pnode.Next
|
||
pi += 1
|
||
llvmlite.module_add_function(mod, func)
|
||
|
||
# ============================================================
|
||
# _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型
|
||
#
|
||
# 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc →
|
||
# "t.CChar | t.CPtr")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
|
||
# 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。
|
||
# 无需硬编码白名单——返回类型始终来自方法定义处。
|
||
# ============================================================
|
||
def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy | t.CPtr,
|
||
cls_sha1: str,
|
||
cls_name: str,
|
||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None"""
|
||
if VpiReader.VPI_DEBUG_ENABLE != 0:
|
||
stdio.printf("[VPI-CALL] lookup sha1=%s cls=%s m=%s tdlen=%d\n",
|
||
cls_sha1, cls_name, method_name, self.TempDirLen)
|
||
if pool is None or cls_sha1 is None or method_name is None:
|
||
return None
|
||
# 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环
|
||
import lib.StubGen.VpiReader as VpiReader
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
# 按需加载:缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi
|
||
# 覆盖"模块自身翻译时 stub 尚未注入"(同模块方法调用,定义在后)的场景
|
||
if self.TempDir is not None and self.TempDirLen > 0:
|
||
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.TempDir)
|
||
annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name)
|
||
if annot is None:
|
||
if VpiReader.VPI_DEBUG_ENABLE != 0:
|
||
stdio.printf("[VPI-CALL] annot=NONE\n")
|
||
return None
|
||
if VpiReader.VPI_DEBUG_ENABLE != 0:
|
||
stdio.printf("[VPI-CALL] annot=%s\n", annot)
|
||
return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty)
|
||
|
||
# ============================================================
|
||
# _special_method_ret_ty - 编译器内置特殊方法的固定返回类型
|
||
#
|
||
# __before_init__ / __init__:编译器生成/约定返回 void
|
||
# __new__:返回 Ptr(StructTy)(存储空间指针)
|
||
#
|
||
# 这些方法不存在于源码(vpi stub 无条目),跨模块调用时
|
||
# found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器
|
||
# 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致),
|
||
# 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。
|
||
# ============================================================
|
||
def _special_method_ret_ty(self, pool: memhub.MemBuddy | t.CPtr,
|
||
class_name: str,
|
||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""编译器内置特殊方法的固定返回类型;非特殊返回 None"""
|
||
if pool is None or method_name is None:
|
||
return None
|
||
if string.strcmp(method_name, "__before_init__") == 0 or \
|
||
string.strcmp(method_name, "__init__") == 0:
|
||
return llvmlite.Void(pool)
|
||
if string.strcmp(method_name, "__new__") == 0:
|
||
if class_name is not None:
|
||
sp_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
|
||
if sp_struct_ty is not None:
|
||
return llvmlite.Ptr(pool, sp_struct_ty)
|
||
return None
|
||
return None
|
||
|
||
# ============================================================
|
||
# _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast
|
||
#
|
||
# 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。
|
||
# 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。
|
||
#
|
||
# node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位)
|
||
# ============================================================
|
||
def _fail_method_ret_ty(self, method_name: str,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr:
|
||
"""方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈)
|
||
|
||
返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。
|
||
全部未命中说明方法定义缺失或 stub 损坏,立即终止暴露,绝不静默默认 i32。
|
||
"""
|
||
VLogger.error(
|
||
f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}",
|
||
"HandlesExprCall")
|
||
HandlesType.fatal_error(
|
||
node,
|
||
f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}",
|
||
"TypeError")
|
||
return None
|
||
|
||
# ============================================================
|
||
# SetTempDir - 设置 temp 目录路径
|
||
#
|
||
# 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin
|
||
# 能够读取依赖模块的 text.ll 文件。
|
||
# ============================================================
|
||
def SetTempDir(self, temp_dir: str):
|
||
"""设置 temp 目录路径(供跨模块方法返回类型查找使用)"""
|
||
self.TempDir = temp_dir
|
||
if temp_dir is not None:
|
||
self.TempDirLen = string.strlen(temp_dir)
|
||
else:
|
||
self.TempDirLen = 0
|
||
|
||
# ============================================================
|
||
# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType
|
||
#
|
||
# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容),
|
||
# 转换为 llvmlite.LLVMType 对象。
|
||
#
|
||
# 支持的类型:
|
||
# void → Void
|
||
# i8/i16/i32/i64 → Int8/Int16/Int32/Int64
|
||
# double → Double, float → Float
|
||
# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址)
|
||
#
|
||
# Args:
|
||
# pool: 内存池
|
||
# buf: 包含类型字符串的缓冲区
|
||
# start: 类型字符串起始位置
|
||
# end: 类型字符串结束位置(不含)
|
||
#
|
||
# Returns:
|
||
# LLVM 类型对象,或 None(无法解析)
|
||
# ============================================================
|
||
def _ParseLLVMRetTyStr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
buf: bytes,
|
||
start: t.CSizeT,
|
||
end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr:
|
||
"""将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType"""
|
||
if pool is None or buf is None or start >= end:
|
||
return None
|
||
|
||
# 去除前导空白
|
||
s: t.CSizeT = start
|
||
while s < end:
|
||
c: int = buf[s]
|
||
if c != ' ' and c != '\t':
|
||
break
|
||
s += 1
|
||
# 去除尾部空白
|
||
e: t.CSizeT = end
|
||
while e > s:
|
||
c2: int = buf[e - 1]
|
||
if c2 != ' ' and c2 != '\t':
|
||
break
|
||
e -= 1
|
||
|
||
ty_len: t.CSizeT = e - s
|
||
if ty_len == 0:
|
||
return None
|
||
|
||
# 检查是否含 * (指针类型) → 返回 i8* (通用指针)
|
||
# 包括 i8*, i32*, %"name"*, { i32, i8 }* 等
|
||
ci: t.CSizeT = s
|
||
while ci < e:
|
||
if buf[ci] == '*':
|
||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
ci += 1
|
||
|
||
# void
|
||
if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0:
|
||
return llvmlite.Void(pool)
|
||
|
||
# double
|
||
if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0:
|
||
return llvmlite.Double(pool)
|
||
|
||
# float
|
||
if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0:
|
||
return llvmlite.Float(pool)
|
||
|
||
# iN (i8, i16, i32, i64)
|
||
if ty_len >= 2 and buf[s] == 'i':
|
||
bits: int = 0
|
||
di: t.CSizeT = s + 1
|
||
valid: int = 1
|
||
while di < e:
|
||
d: int = buf[di]
|
||
if d >= '0' and d <= '9':
|
||
bits = bits * 10 + (d - '0')
|
||
else:
|
||
valid = 0
|
||
break
|
||
di += 1
|
||
if valid != 0 and bits > 0:
|
||
if bits == 8:
|
||
return llvmlite.Int8(pool)
|
||
if bits == 16:
|
||
return llvmlite.Int16(pool)
|
||
if bits == 32:
|
||
return llvmlite.Int32(pool)
|
||
if bits == 64:
|
||
return llvmlite.Int64(pool)
|
||
|
||
# 无法解析
|
||
return None
|
||
|
||
# ============================================================
|
||
# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型
|
||
#
|
||
# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索
|
||
# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数,
|
||
# 提取返回类型并转换为 llvmlite.LLVMType。
|
||
#
|
||
# 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值
|
||
# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。
|
||
# 本函数从 text.ll 获取实际返回类型,避免截断。
|
||
#
|
||
# Args:
|
||
# pool: 内存池
|
||
# class_sha1: 类所属模块的 SHA1
|
||
# class_name: 类名
|
||
# method_name: 方法名
|
||
#
|
||
# Returns:
|
||
# LLVM 类型对象,或 None(未找到/text.ll 不存在)
|
||
# ============================================================
|
||
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr,
|
||
class_sha1: str,
|
||
class_name: str,
|
||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""从依赖模块的 text.ll 中查找方法返回类型"""
|
||
if pool is None or class_sha1 is None or class_name is None or method_name is None:
|
||
return None
|
||
if self.TempDir is None or self.TempDirLen == 0:
|
||
return None
|
||
|
||
sha1_len: t.CSizeT = string.strlen(class_sha1)
|
||
if sha1_len < 2:
|
||
return None
|
||
|
||
# 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll
|
||
# 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致)
|
||
path_len: t.CSizeT = self.TempDirLen + sha1_len + 14
|
||
path_buf: bytes = stdlib.malloc(path_len)
|
||
if path_buf is None:
|
||
return None
|
||
subdir_buf: bytes = stdlib.malloc(3)
|
||
if subdir_buf is None:
|
||
stdlib.free(path_buf)
|
||
return None
|
||
subdir_buf[0] = class_sha1[0]
|
||
subdir_buf[1] = class_sha1[1]
|
||
subdir_buf[2] = '\0'
|
||
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
|
||
self.TempDir, subdir_buf, class_sha1)
|
||
stdlib.free(subdir_buf)
|
||
|
||
# 读取 text.ll
|
||
read_buf: bytes = stdlib.malloc(_TEXT_LL_READ_BUF_SIZE)
|
||
if read_buf is None:
|
||
stdlib.free(path_buf)
|
||
return None
|
||
|
||
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||
if tf.closed:
|
||
stdlib.free(path_buf)
|
||
stdlib.free(read_buf)
|
||
return None
|
||
text_len: t.CInt64T = tf.read_all(read_buf, _TEXT_LL_READ_BUF_SIZE)
|
||
tf.close()
|
||
stdlib.free(path_buf)
|
||
|
||
if text_len <= 0:
|
||
stdlib.free(read_buf)
|
||
return None
|
||
if text_len < _TEXT_LL_READ_BUF_SIZE:
|
||
read_buf[text_len] = '\0'
|
||
else:
|
||
read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0'
|
||
|
||
# 构造搜索模式: "{sha1}.{class_name}.{method_name}"
|
||
cls_len: t.CSizeT = string.strlen(class_name)
|
||
meth_len: t.CSizeT = string.strlen(method_name)
|
||
search_len: t.CSizeT = sha1_len + cls_len + meth_len + 3
|
||
search_buf: bytes = stdlib.malloc(search_len)
|
||
if search_buf is None:
|
||
stdlib.free(read_buf)
|
||
return None
|
||
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
|
||
class_sha1, class_name, method_name)
|
||
search_str_len: t.CSizeT = string.strlen(search_buf)
|
||
|
||
# 在 text.ll 中搜索 define 行包含 search_buf
|
||
buf_len: t.CSizeT = string.strlen(read_buf)
|
||
pos: t.CSizeT = 0
|
||
result_ty: llvmlite.LLVMType | t.CPtr = None
|
||
|
||
while pos < buf_len and result_ty is None:
|
||
ls: t.CSizeT = pos
|
||
le: t.CSizeT = pos
|
||
while le < buf_len:
|
||
if read_buf[le] == '\n':
|
||
break
|
||
le += 1
|
||
ll: t.CSizeT = le - ls
|
||
|
||
# 检查是否是 define 行
|
||
if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0:
|
||
# 找 @ 符号
|
||
at_pos: t.CSizeT = ls + 7
|
||
while at_pos < ls + ll:
|
||
if read_buf[at_pos] == '@':
|
||
break
|
||
at_pos += 1
|
||
if at_pos < ls + ll:
|
||
# 跳过可选引号
|
||
name_start: t.CSizeT = at_pos + 1
|
||
if name_start < ls + ll and read_buf[name_start] == '"':
|
||
name_start += 1
|
||
# 检查是否匹配 search_buf
|
||
if name_start + search_str_len <= ls + ll:
|
||
if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0:
|
||
# 匹配!提取返回类型: [ls+7, at_pos)
|
||
result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
|
||
|
||
pos = le + 1
|
||
|
||
stdlib.free(search_buf)
|
||
stdlib.free(read_buf)
|
||
return result_ty
|
||
|
||
# ============================================================
|
||
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
|
||
#
|
||
# 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充,
|
||
# 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method()
|
||
# 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# _translate_property_call — 翻译属性方法调用
|
||
#
|
||
# 与 _translate_method_call 的调用名/返回类型解析逻辑一致:
|
||
# 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入)
|
||
# 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名
|
||
# 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32)
|
||
#
|
||
# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数)
|
||
# ============================================================
|
||
def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
method_name: str,
|
||
call_head: llvmlite.Value | t.CPtr,
|
||
call_count: int,
|
||
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
|
||
|
||
# 构造查找名: 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)
|
||
|
||
# 查找函数(精确/后缀匹配)
|
||
found_func: llvmlite.Function | t.CPtr = self.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:
|
||
# 未找到:用类所属模块的 SHA1 构造调用名
|
||
cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name)
|
||
if cls_sha1_pc is not None:
|
||
mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2
|
||
mangled_pc: str = pool.alloc(mlen_pc)
|
||
if mangled_pc is not None:
|
||
viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name)
|
||
call_name = mangled_pc
|
||
|
||
# 确定返回类型
|
||
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:
|
||
sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
|
||
if sp_ty1 is not None:
|
||
call_ret_ty = sp_ty1
|
||
else:
|
||
cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name)
|
||
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||
pool, cls_sha1_rt, class_name, method_name)
|
||
if looked_up_ty is not None:
|
||
call_ret_ty = looked_up_ty
|
||
else:
|
||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||
pool, cls_sha1_rt, class_name, method_name)
|
||
if vpi_ret_ty is not None:
|
||
call_ret_ty = vpi_ret_ty
|
||
else:
|
||
call_ret_ty = self._fail_method_ret_ty(method_name)
|
||
|
||
# 确保 declare 存在,然后调用
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count)
|
||
return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0)
|
||
|
||
# ============================================================
|
||
# _resolve_obj_class_name — 解析对象表达式的类名(短名)
|
||
#
|
||
# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"),
|
||
# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。
|
||
# 供属性访问/赋值/删除识别 property 时使用。
|
||
# ============================================================
|
||
def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
obj_node: ast.AST | t.CPtr) -> str:
|
||
"""解析对象表达式的类名(短名),失败返回 None"""
|
||
if pool is None or trans is None or obj_node is None:
|
||
return None
|
||
if obj_node.kind() == ast.ASTKind.Name:
|
||
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node)
|
||
if obj_nm.id is not None:
|
||
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||
trans.SymTab, obj_nm.id)
|
||
if var_entry is not None and var_entry.AnnotClassName is not None:
|
||
annot_val: str = var_entry.AnnotClassName
|
||
dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.')
|
||
if dot_ptr is not None:
|
||
return dot_ptr + 1
|
||
return annot_val
|
||
return None
|
||
|
||
# ============================================================
|
||
# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用
|
||
#
|
||
# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法;
|
||
# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。
|
||
# ============================================================
|
||
def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
at_node: ast.Attribute | t.CPtr,
|
||
obj_ptr: llvmlite.Value | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
fallback_class_name: str = None) -> llvmlite.Value | t.CPtr:
|
||
"""尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None
|
||
|
||
fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。
|
||
"""
|
||
if at_node is None or at_node.attr is None or obj_ptr is None or trans is None:
|
||
return None
|
||
class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value)
|
||
if class_name is None:
|
||
class_name = fallback_class_name
|
||
if class_name is None:
|
||
return None
|
||
meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr)
|
||
if meta & HandlesClassDef.META_PROP_GETTER == 0:
|
||
return None
|
||
# 单参数调用: obj → getter
|
||
llvmlite.value_set_next(obj_ptr, None)
|
||
return self._translate_property_call(
|
||
pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans)
|
||
|
||
# ============================================================
|
||
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
|
||
#
|
||
# 检查 obj 的类是否有 @x.setter 的 attr 方法;
|
||
# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。
|
||
# ============================================================
|
||
def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
target_attr: ast.Attribute | t.CPtr,
|
||
rhs_val: llvmlite.Value | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> int:
|
||
"""尝试 property setter 赋值,返回 1=已处理(生成调用)"""
|
||
if pool is None or builder is None or mod is None or trans is None:
|
||
return 0
|
||
if target_attr is None or target_attr.attr is None or rhs_val is None:
|
||
return 0
|
||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||
if class_name is None:
|
||
return 0
|
||
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
|
||
if meta & HandlesClassDef.META_PROP_SETTER == 0:
|
||
return 0
|
||
# 翻译对象值(self 参数)
|
||
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||
if obj_val is None:
|
||
return 0
|
||
# 构建参数链表: obj → rhs
|
||
llvmlite.value_set_next(obj_val, None)
|
||
llvmlite.value_set_next(rhs_val, None)
|
||
llvmlite.value_set_next(obj_val, rhs_val)
|
||
# setter 函数名带 $set 后缀
|
||
setter_name_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||
if setter_name_buf is None:
|
||
return 0
|
||
viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr)
|
||
self._translate_property_call(pool, builder, mod, class_name,
|
||
setter_name_buf, obj_val, 2, trans)
|
||
return 1
|
||
|
||
# ============================================================
|
||
# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用
|
||
#
|
||
# 检查 obj 的类是否有 @x.deleter 的 attr 方法;
|
||
# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。
|
||
# ============================================================
|
||
def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
target_attr: ast.Attribute | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> int:
|
||
"""尝试 property deleter 删除,返回 1=已处理(生成调用)"""
|
||
if pool is None or builder is None or mod is None or trans is None:
|
||
return 0
|
||
if target_attr is None or target_attr.attr is None:
|
||
return 0
|
||
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
|
||
if class_name is None:
|
||
return 0
|
||
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
|
||
if meta & HandlesClassDef.META_PROP_DELETER == 0:
|
||
return 0
|
||
# 翻译对象值(self 参数)
|
||
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, target_attr.value, None, 0, trans)
|
||
if obj_val is None:
|
||
return 0
|
||
llvmlite.value_set_next(obj_val, None)
|
||
# deleter 函数名带 $del 后缀
|
||
del_name_buf: t.CChar | t.CPtr = pool.alloc(128)
|
||
if del_name_buf is None:
|
||
return 0
|
||
viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr)
|
||
self._translate_property_call(pool, builder, mod, class_name,
|
||
del_name_buf, obj_val, 1, trans)
|
||
return 1
|
||
|
||
# ============================================================
|
||
# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用
|
||
#
|
||
# @staticmethod: 直接 call Class.method(args...),无 self
|
||
# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致)
|
||
# ============================================================
|
||
def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
method_name: str,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None"""
|
||
if pool is None or builder is None or mod is None or trans is None:
|
||
return None
|
||
if class_name is None or method_name is None or cl is None:
|
||
return None
|
||
meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name)
|
||
is_static: int = 0
|
||
is_class: int = 0
|
||
if meta & HandlesClassDef.META_STATIC != 0:
|
||
is_static = 1
|
||
if meta & HandlesClassDef.META_CLASS != 0:
|
||
is_class = 1
|
||
if is_static == 0 and is_class == 0:
|
||
return None
|
||
|
||
# 构建参数链表
|
||
head: llvmlite.Value | t.CPtr = None
|
||
total_count: int = 0
|
||
|
||
# @classmethod: 插入栈上分配的类实例指针作为 cls 参数
|
||
if is_class != 0:
|
||
struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
|
||
if struct_ty_cc is None:
|
||
return None
|
||
cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc)
|
||
if cls_ptr is None:
|
||
return None
|
||
llvmlite.value_set_next(cls_ptr, None)
|
||
head = cls_ptr
|
||
total_count = 1
|
||
|
||
# 翻译调用参数
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = cargs.__len__()
|
||
tail: llvmlite.Value | t.CPtr = head
|
||
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)
|
||
if head is None:
|
||
head = arg_val
|
||
tail = arg_val
|
||
else:
|
||
llvmlite.value_set_next(tail, arg_val)
|
||
tail = arg_val
|
||
total_count += 1
|
||
|
||
if head is None:
|
||
return None
|
||
|
||
return self._translate_property_call(pool, builder, mod, class_name,
|
||
method_name, head, total_count, trans)
|
||
|
||
# ============================================================
|
||
# _translate_method_call - 翻译方法调用 obj.method(args)
|
||
#
|
||
# 生成: call <ret_ty> @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...)
|
||
#
|
||
# obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入
|
||
# ============================================================
|
||
def _translate_method_call(self, 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 = self.find_func_in_module(mod, lookup_name)
|
||
|
||
# 泛型模板类方法:特化函数名带类型参数({sha1}.list[int].get),
|
||
# "ClassName.method" 短名匹配不到。特化由触发方(通常即调用方)模块完成,
|
||
# 用对象实际特化名(mc_entry.Name)构造后缀匹配,获得精确返回类型。
|
||
if found_func is None and mc_entry is not None and mc_entry.Name is not None:
|
||
if string.strcmp(mc_entry.Name, class_name) != 0:
|
||
spec_lookup: t.CChar | t.CPtr = pool.alloc(160)
|
||
if spec_lookup is not None:
|
||
viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name)
|
||
found_func = self.find_func_in_module(mod, spec_lookup)
|
||
|
||
# 沿 MRO 祖先链查找父类方法(子类未覆盖时回退到父类,先声明父类优先)
|
||
mc_anc: str = None # 方法实际定义类(多继承 this 调整用)
|
||
if found_func is None:
|
||
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||
mi: int = 1
|
||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||
if anc 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", anc, method_name)
|
||
parent_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, parent_lookup)
|
||
if parent_func is not None:
|
||
found_func = parent_func
|
||
mc_anc = anc
|
||
break
|
||
mi += 1
|
||
|
||
# 确定调用名
|
||
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 为 None(stub 未注入):用类所属模块的 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:
|
||
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
|
||
mj: int = 1
|
||
while mro_p is not None and mro_p[mj] != 0 and cls_sha1_mc is None:
|
||
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
|
||
if anc_p is not None:
|
||
cls_sha1_mc = HandlesStruct.get_struct_sha1(anc_p)
|
||
mj += 1
|
||
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 为 None(stub 未注入):先处理编译器内置特殊方法
|
||
sp_ty2: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
|
||
if sp_ty2 is not None:
|
||
call_ret_ty = sp_ty2
|
||
else:
|
||
# 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用
|
||
# list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入),
|
||
# 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。
|
||
gen_done: int = 0
|
||
if class_name is not None:
|
||
lbkt_g: str = string.strchr(class_name, '[')
|
||
if lbkt_g is not None:
|
||
rbkt_g: str = string.strrchr(class_name, ']')
|
||
if rbkt_g is not None and rbkt_g > lbkt_g:
|
||
base_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_g) - t.CUInt64T(class_name))
|
||
arg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_g) - t.CUInt64T(lbkt_g) - 1)
|
||
if base_len_g > 0 and arg_len_g > 0:
|
||
base_buf_g: str = pool.alloc(base_len_g + 1)
|
||
arg_buf_g: str = pool.alloc(arg_len_g + 1)
|
||
if base_buf_g is not None and arg_buf_g is not None:
|
||
string.strncpy(base_buf_g, class_name, base_len_g)
|
||
base_buf_g[base_len_g] = '\0'
|
||
string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g)
|
||
arg_buf_g[arg_len_g] = '\0'
|
||
ta_list_g: list[str] | t.CPtr = list[str](pool, 4)
|
||
if ta_list_g is not None:
|
||
# 逗号分隔多类型实参(list[X] / dict[K, V])
|
||
cur_arg_g: str = arg_buf_g
|
||
while cur_arg_g is not None:
|
||
comma_g: str = string.strchr(cur_arg_g, ',')
|
||
if comma_g is None:
|
||
ta_list_g.append(cur_arg_g)
|
||
break
|
||
seg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(comma_g) - t.CUInt64T(cur_arg_g))
|
||
seg_buf_g: str = pool.alloc(seg_len_g + 1)
|
||
if seg_buf_g is not None:
|
||
string.strncpy(seg_buf_g, cur_arg_g, seg_len_g)
|
||
seg_buf_g[seg_len_g] = '\0'
|
||
ta_list_g.append(seg_buf_g)
|
||
cur_arg_g = comma_g + 1
|
||
spec_name_g: str = HandlesClassDef._specialize_generic_class(
|
||
trans, base_buf_g, ta_list_g)
|
||
if spec_name_g is not None:
|
||
# 特化后重新查找特化函数(特化名 = 调用点类名)
|
||
spec_lk_g: str = pool.alloc(
|
||
string.strlen(class_name) + string.strlen(method_name) + 2)
|
||
if spec_lk_g is not None:
|
||
viperlib.snprintf(spec_lk_g,
|
||
string.strlen(class_name) + string.strlen(method_name) + 2,
|
||
"%s.%s", class_name, method_name)
|
||
spec_found_g: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, spec_lk_g)
|
||
if spec_found_g is not None:
|
||
frt_g: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(spec_found_g)
|
||
if frt_g is not None:
|
||
call_ret_ty = frt_g
|
||
found_func = spec_found_g
|
||
gen_done = 1
|
||
if gen_done == 0:
|
||
# 尝试从 text.ll 查找实际返回类型
|
||
# 避免指针返回值被默认 i32 导致 inttoptr 截断
|
||
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||
pool, cls_sha1_mc, class_name, method_name)
|
||
if looked_up_ty is not None:
|
||
call_ret_ty = looked_up_ty
|
||
else:
|
||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||
pool, cls_sha1_mc, class_name, method_name)
|
||
if vpi_ret_ty is not None:
|
||
call_ret_ty = vpi_ret_ty
|
||
else:
|
||
call_ret_ty = self._fail_method_ret_ty(method_name, cl)
|
||
|
||
# 翻译调用参数
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = cargs.__len__()
|
||
kw_calls: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
|
||
kwc: t.CSizeT = 0
|
||
if kw_calls is not None:
|
||
kwc = kw_calls.__len__()
|
||
|
||
# 多继承 this 调整:继承方法定义在"无 vtable 的父类"且该父类字段区在子类中
|
||
# 偏移 > 0 时(如 C(A,B).get_b,B 的字段区在 C 中从 b 开始),父类方法按自身
|
||
# 布局读 self.field@0 会读到前面父类的字段。调整:GEP 到父类第一个用户字段
|
||
# 在子类中的位置,bitcast 成父类指针作为 self。
|
||
# 有 vtable 的父类布局是子类布局前缀(vptr 共享),self 无需调整。
|
||
self_arg: llvmlite.Value | t.CPtr = obj_ptr
|
||
if mc_anc is not None and string.strcmp(mc_anc, class_name) != 0:
|
||
anc_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(mc_anc)
|
||
if anc_entry_th is not None and anc_entry_th.HasVTable == 0 and anc_entry_th.FieldCount > 0:
|
||
anc_first_name_th: str = None
|
||
afi_th: int = 0
|
||
while afi_th < anc_entry_th.FieldCount:
|
||
afe_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
|
||
anc_entry_th, afi_th)
|
||
if afe_th is not None:
|
||
afn_th: str = HandlesStruct.get_field_name_ptr(afe_th)
|
||
if afn_th is not None and string.strcmp(afn_th, "__vtable__") != 0:
|
||
anc_first_name_th = afn_th
|
||
break
|
||
afi_th += 1
|
||
if anc_first_name_th is not None:
|
||
sub_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
|
||
class_name)
|
||
if sub_entry_th is not None:
|
||
sub_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
|
||
sub_entry_th.Ty, anc_first_name_th)
|
||
if sub_field_th is not None and sub_field_th.Index > 0:
|
||
anc_ptr_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_th.Ty)
|
||
adj_th: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, sub_entry_th.Ty, sub_field_th.Ty, obj_ptr, sub_field_th.Index)
|
||
self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th)
|
||
# 构建参数链表: self → arg1 → arg2 → ...
|
||
llvmlite.value_set_next(self_arg, None)
|
||
head: llvmlite.Value | t.CPtr = self_arg
|
||
tail: llvmlite.Value | t.CPtr = self_arg
|
||
arg_count_eff: int = 0
|
||
|
||
if kwc > 0 and found_func is not None:
|
||
# 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配
|
||
# 缺失参数用零值兜底,保持 call 参数数量与 define 一致
|
||
cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
if cur_param_k is not None:
|
||
cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self
|
||
pi_k: int = 0
|
||
while cur_param_k is not None:
|
||
arg_node_k: ast.AST | t.CPtr = None
|
||
if pi_k < can:
|
||
arg_node_k = cargs.get(pi_k)
|
||
else:
|
||
pname_k: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param_k)
|
||
if pname_k is not None:
|
||
ki_k: int
|
||
for ki_k in range(kwc):
|
||
kw_k: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_calls.get(ki_k))
|
||
if kw_k is None or kw_k.arg is None or kw_k.value is None:
|
||
continue
|
||
if self._kwarg_name_matches(kw_k.arg, pname_k) == 1:
|
||
arg_node_k = kw_k.value
|
||
break
|
||
arg_val_k: llvmlite.Value | t.CPtr = None
|
||
if arg_node_k is not None:
|
||
arg_val_k = HandlesExpr.translate_value(
|
||
builder, pool, mod, arg_node_k, None, 0, trans)
|
||
if arg_val_k is None:
|
||
# 缺失参数:零值兜底(保持参数数量匹配)
|
||
pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
|
||
if pty_k is not None:
|
||
arg_val_k = llvmlite.ConstZero(pool, pty_k)
|
||
if arg_val_k is not None:
|
||
pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
|
||
if pty_k2 is not None:
|
||
arg_val_k = HandlesExpr.coerce_to_type(
|
||
builder, arg_val_k, pty_k2, arg_node_k)
|
||
llvmlite.value_set_next(arg_val_k, None)
|
||
llvmlite.value_set_next(tail, arg_val_k)
|
||
tail = arg_val_k
|
||
arg_count_eff += 1
|
||
pi_k += 1
|
||
cur_param_k = llvmlite.param_get_next(cur_param_k)
|
||
else:
|
||
# 位置参数(原逻辑)
|
||
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
|
||
# 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
|
||
# 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT)
|
||
# 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃
|
||
if found_func is not None:
|
||
pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
pi: int = 0
|
||
while pp is not None and pi < ai + 1:
|
||
if pi == ai + 1:
|
||
break
|
||
pp = llvmlite.param_get_next(pp)
|
||
pi += 1
|
||
if pp is not None:
|
||
pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp)
|
||
if pty is not None:
|
||
arg_val = HandlesExpr.coerce_to_type(
|
||
builder, arg_val, pty, arg_node)
|
||
llvmlite.value_set_next(arg_val, None)
|
||
llvmlite.value_set_next(tail, arg_val)
|
||
tail = arg_val
|
||
arg_count_eff += 1
|
||
|
||
total_count: int = 1 + arg_count_eff
|
||
|
||
# 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数
|
||
# 查找函数的 defaults 信息
|
||
mdf_defaults: t.CVoid | t.CPtr = None
|
||
mdf_default_count: int = 0
|
||
mdf_param_count: int = 0
|
||
if trans is not None and trans._funcs is not None:
|
||
mdf_entry: FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_in_table(
|
||
trans._funcs, trans._func_count, lookup_name)
|
||
if mdf_entry is not None:
|
||
mdf_defaults = mdf_entry.Defaults
|
||
mdf_default_count = mdf_entry.DefaultCount
|
||
mdf_param_count = mdf_entry.ParamCount
|
||
if mdf_defaults is None:
|
||
mdf_gd: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(lookup_name)
|
||
if mdf_gd is not None:
|
||
mdf_defaults = mdf_gd.Defaults
|
||
mdf_default_count = mdf_gd.DefaultCount
|
||
mdf_param_count = mdf_gd.ParamCount
|
||
|
||
# 计算需要填充的参数(不含 self)
|
||
# arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建)
|
||
# mdf_param_count = 函数定义的非 self 参数数量
|
||
if mdf_param_count > arg_count_eff:
|
||
mdf_offset: int = mdf_param_count - mdf_default_count
|
||
mdf_pi: int = arg_count_eff
|
||
while mdf_pi < mdf_param_count:
|
||
# 优先用默认值
|
||
if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset:
|
||
mdf_di: int = mdf_pi - mdf_offset
|
||
if mdf_di < mdf_default_count:
|
||
# 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收,
|
||
# 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST)
|
||
mdf_val: llvmlite.Value | t.CPtr = None
|
||
if mdf_gd is not None:
|
||
mdf_val = HandlesExprCall._build_const_from_snapshot(
|
||
pool, mod, mdf_gd, mdf_di, trans, builder)
|
||
if mdf_val is None:
|
||
HandlesType.fatal_error(
|
||
cl,
|
||
f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}",
|
||
"TypeError")
|
||
continue
|
||
llvmlite.value_set_next(mdf_val, None)
|
||
llvmlite.value_set_next(tail, mdf_val)
|
||
tail = mdf_val
|
||
total_count += 1
|
||
mdf_pi += 1
|
||
continue
|
||
# 无默认值时用零值兜底(需要 found_func 获取参数类型)
|
||
if found_func is not None:
|
||
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
skip_z: int = 0
|
||
while skip_z <= mdf_pi and param_node_z is not None:
|
||
param_node_z = llvmlite.param_get_next(param_node_z)
|
||
skip_z += 1
|
||
if param_node_z is not None:
|
||
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
|
||
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_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
|
||
mdf_pi += 1
|
||
|
||
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
|
||
# (不依赖 found_func — 继承的虚方法可能没有子类实现)
|
||
# 复用前面已获取的 mc_entry(find_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 self._do_virtual_call(pool, builder, mod, class_name, method_name,
|
||
obj_ptr, head, total_count, found_func, call_ret_ty)
|
||
|
||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||
# 检查变长函数 + C ABI 提升
|
||
is_variadic_3441: int = HandlesExprCall._check_and_promote_variadic_call(pool, builder, mod, call_name, head, total_count)
|
||
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, is_variadic_3441)
|
||
|
||
# ============================================================
|
||
# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名
|
||
#
|
||
# 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a")
|
||
# 跳过 % 前缀后逐字符比较
|
||
# ============================================================
|
||
def _kwarg_name_matches(self, 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(self, 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
|
||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
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
|
||
|
||
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
|
||
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
|
||
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
|
||
if is_oop == 0 and class_name is not None:
|
||
kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128)
|
||
if kw_init_lookup is not None:
|
||
viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name)
|
||
# 方案1: 检查当前模块的函数声明
|
||
kw_init_found: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, kw_init_lookup)
|
||
if kw_init_found is not None:
|
||
is_oop = 1
|
||
if kw_entry is not None:
|
||
kw_entry.IsOOP = 1
|
||
kw_entry.HasInit = 1
|
||
else:
|
||
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
|
||
kw_init_defaults: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(kw_init_lookup)
|
||
if kw_init_defaults is not None:
|
||
is_oop = 1
|
||
if kw_entry is not None:
|
||
kw_entry.IsOOP = 1
|
||
kw_entry.HasInit = 1
|
||
|
||
if is_oop != 0:
|
||
self._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)
|
||
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
|
||
|
||
# OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store
|
||
# 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行
|
||
# (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃)
|
||
has_init_flag: int = 0
|
||
has_new_flag: int = 0
|
||
if kw_entry is not None:
|
||
has_init_flag = kw_entry.HasInit
|
||
has_new_flag = kw_entry.HasNew
|
||
|
||
# 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用)
|
||
# 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在)
|
||
# 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法)
|
||
if is_oop != 0 and has_init_flag == 0:
|
||
has_init_flag = 1
|
||
|
||
if is_oop != 0 and has_init_flag != 0:
|
||
# 有 __init__:构建参数数组并调用 __init__
|
||
storage_ptr: llvmlite.Value | t.CPtr = tmp
|
||
|
||
# 如果有 __new__,调用 __new__ 获取实际存储指针
|
||
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__
|
||
for nki in range(kw_count):
|
||
nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki))
|
||
if nkw is None or nkw.value is None:
|
||
continue
|
||
nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, nkw.value, None, 0, trans)
|
||
if nkw_av is not None:
|
||
if new_arg_count < 32:
|
||
new_arg_vals[new_arg_count] = t.CSizeT(nkw_av)
|
||
new_arg_count += 1
|
||
new_ptr: llvmlite.Value | t.CPtr = self._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
|
||
# __new__ 只保证返回"实例存储指针",声明类型通常是
|
||
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
|
||
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
|
||
# obj.method(如 parser.add_argument)get_class_name_by_type
|
||
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
|
||
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
|
||
if new_ptr.Ty is not None:
|
||
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
|
||
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
|
||
if nw_bc is not None:
|
||
storage_ptr = nw_bc
|
||
|
||
# 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加
|
||
init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||
if init_arg_vals is not None:
|
||
string.memset(init_arg_vals, 0, 8 * 32)
|
||
init_arg_count: int = 0
|
||
# 位置参数
|
||
for ai_init in range(can):
|
||
arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init)
|
||
if arg_node_init is None:
|
||
continue
|
||
av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, arg_node_init, None, 0, trans)
|
||
if av_init is not None:
|
||
if init_arg_count < 32:
|
||
init_arg_vals[init_arg_count] = t.CSizeT(av_init)
|
||
init_arg_count += 1
|
||
# 关键字参数(追加到末尾,按出现顺序)
|
||
for ki_init in range(kw_count):
|
||
kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init))
|
||
if kw_init is None or kw_init.value is None:
|
||
continue
|
||
kw_av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, kw_init.value, None, 0, trans)
|
||
if kw_av_init is not None:
|
||
if init_arg_count < 32:
|
||
init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init)
|
||
init_arg_count += 1
|
||
|
||
# 调用 __init__(storage_ptr, *args)
|
||
self._call_method_on_ptr(pool, builder, mod, class_name,
|
||
"__init__", storage_ptr, init_arg_vals, init_arg_count, trans)
|
||
|
||
# 返回指针
|
||
return storage_ptr
|
||
|
||
# 无 __init__(或非 OOP):逐字段 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 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, arg)
|
||
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, kw.value)
|
||
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(self, 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 self._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 前缀,使用访问器)
|
||
# declare 和 define 统一用 found_func.Name:
|
||
# - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name)
|
||
# - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名
|
||
# 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀,
|
||
# 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference
|
||
call_name: str = func_name
|
||
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 = self._infer_external_func_ret_ty(pool, func_name)
|
||
|
||
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
|
||
if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3:
|
||
return self._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*)
|
||
# - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double)
|
||
# - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32)
|
||
# - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float)
|
||
# ============================================================
|
||
def _translate_t_type_cast(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
val: llvmlite.Value | t.CPtr,
|
||
target_ty: llvmlite.LLVMType | t.CPtr,
|
||
target_name: str = None,
|
||
src_node: ast.AST | t.CPtr = None,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""类型转换:根据参数类型和目标类型选择转换方式
|
||
|
||
整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737):
|
||
源 i1(bool)→ zext
|
||
目标类型无符号(target_name 命中 CUIntXXT 等)→ zext
|
||
源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext
|
||
否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE)
|
||
"""
|
||
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)
|
||
val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty)
|
||
target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty)
|
||
|
||
# 整数 → 整数: trunc/zext/sext
|
||
if val_bits != 0 and target_bits != 0:
|
||
if val_bits == target_bits:
|
||
return val
|
||
elif val_bits < target_bits:
|
||
if val_bits == 1:
|
||
# i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext
|
||
return llvmlite.build_zext(builder, val, target_ty)
|
||
# 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737);
|
||
# 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为)
|
||
need_sext: int = 0
|
||
if target_name is not None and HandlesExpr._type_name_unsigned(target_name) == 0:
|
||
if src_node is None or HandlesExpr._node_type_unsigned(pool, src_node, trans) == 0:
|
||
need_sext = 1
|
||
if need_sext != 0:
|
||
return llvmlite.build_sext(builder, val, target_ty)
|
||
return llvmlite.build_zext(builder, val, target_ty)
|
||
else:
|
||
return llvmlite.build_trunc(builder, val, target_ty)
|
||
|
||
# 整数 → 浮点: sitofp
|
||
if val_bits != 0 and target_fbits != 0:
|
||
return llvmlite.build_si2fp(builder, val, target_ty)
|
||
|
||
# 浮点 → 整数: fptosi
|
||
if val_fbits != 0 and target_bits != 0:
|
||
return llvmlite.build_fp2si(builder, val, target_ty)
|
||
|
||
# 浮点 → 浮点: fpext/fptrunc
|
||
if val_fbits != 0 and target_fbits != 0:
|
||
if val_fbits == target_fbits:
|
||
return val
|
||
elif val_fbits < target_fbits:
|
||
return llvmlite.build_fpext(builder, val, target_ty)
|
||
else:
|
||
return llvmlite.build_fptrunc(builder, val, target_ty)
|
||
|
||
# 指针 → 整数: ptrtoint
|
||
if val_bits == 0 and val_fbits == 0 and target_bits != 0:
|
||
return llvmlite.build_ptrtoint(builder, val, target_ty)
|
||
|
||
# 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0)
|
||
if val_bits != 0 and target_bits == 0 and target_fbits == 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(self, 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
|
||
# elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节
|
||
# 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃
|
||
result: list[str] | t.CPtr = list[str](pool, 8)
|
||
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
|
||
|
||
# ============================================================
|
||
# 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__
|
||
#
|
||
# 复用 translate_list_literal 的构造逻辑:
|
||
# 1. alloca tmp(特化类临时空间,作为 __new__ 的 self)
|
||
# 2. 翻译 cl.args 为参数指针数组
|
||
# 3. call __new__(tmp, *args) → storage_ptr
|
||
# 4. call __before_init__(storage_ptr)
|
||
# 5. call __init__(storage_ptr, *args)
|
||
# 6. return storage_ptr
|
||
#
|
||
# 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名,
|
||
# 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1
|
||
# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。
|
||
# ============================================================
|
||
def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr,
|
||
arg_node: ast.AST | t.CPtr) -> str:
|
||
"""从构造实参 AST 推断泛型类型实参名;无法推断时默认 "int"(与 TPC 一致)
|
||
|
||
裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。
|
||
对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。
|
||
注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。
|
||
"""
|
||
if pool is None or arg_node is None:
|
||
return "int"
|
||
k: int = arg_node.kind()
|
||
# 常量: 42→int, 3.14→double, "abc"→str
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node)
|
||
if cn.const_kind == ast.CONST_FLOAT:
|
||
return "double"
|
||
if cn.const_kind == ast.CONST_STR:
|
||
return "str"
|
||
return "int"
|
||
# 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...)
|
||
if k == ast.ASTKind.Call:
|
||
cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node)
|
||
if cl_f.func is not None:
|
||
if cl_f.func.kind() == ast.ASTKind.Name:
|
||
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func)
|
||
if fn_nm.id is not None:
|
||
if string.strcmp(fn_nm.id, "float") == 0:
|
||
return "double"
|
||
if string.strcmp(fn_nm.id, "int") == 0:
|
||
return "int"
|
||
elif cl_f.func.kind() == ast.ASTKind.Attribute:
|
||
fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func)
|
||
if fn_at.attr is not None:
|
||
if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None:
|
||
return "double"
|
||
if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None:
|
||
return "int"
|
||
return "int"
|
||
|
||
def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
spec_name: str,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__"""
|
||
if pool is None or builder is None or mod is None or spec_name is None or cl is None:
|
||
return None
|
||
|
||
# 查找 struct entry 获取类型
|
||
struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
|
||
if struct_entry is None:
|
||
HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册")
|
||
return None
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty
|
||
if struct_ty is None:
|
||
return None
|
||
|
||
# 确保结构体定义在当前模块中可用(供 alloca 分配空间)
|
||
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||
|
||
# alloca tmp(self 指针)
|
||
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
|
||
if tmp is None:
|
||
return None
|
||
|
||
# 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针)
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = cargs.__len__()
|
||
|
||
extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||
if extra_args is None:
|
||
return None
|
||
string.memset(extra_args, 0, 8 * 32)
|
||
|
||
ai: t.CSizeT = 0
|
||
while ai < can:
|
||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg_node is not None:
|
||
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, arg_node, None, 0, trans)
|
||
if arg_val is not None:
|
||
extra_args[ai] = t.CSizeT(arg_val)
|
||
ai += 1
|
||
|
||
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
|
||
# __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用
|
||
# (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明)
|
||
storage_ptr: llvmlite.Value | t.CPtr = tmp
|
||
has_new_flag: int = 0
|
||
if struct_entry is not None:
|
||
has_new_flag = struct_entry.HasNew
|
||
if has_new_flag != 0:
|
||
new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr(
|
||
pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans)
|
||
if new_ptr is not None:
|
||
storage_ptr = new_ptr
|
||
# __new__ 只保证返回"实例存储指针",声明类型通常是
|
||
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
|
||
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
|
||
# obj.method(如 parser.add_argument)get_class_name_by_type
|
||
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
|
||
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
|
||
if new_ptr.Ty is not None:
|
||
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
|
||
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
|
||
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
|
||
if nw_bc is not None:
|
||
storage_ptr = nw_bc
|
||
|
||
# call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充)
|
||
self._call_method_on_ptr(
|
||
pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)
|
||
|
||
# call __init__(storage_ptr, *args)
|
||
self._call_method_on_ptr(
|
||
pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans)
|
||
|
||
return storage_ptr
|
||
|
||
# ============================================================
|
||
# 翻译函数调用 Call(func, args) — 模块级版本
|
||
# ============================================================
|
||
def translate_call(self, 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 = self._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:
|
||
# 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__
|
||
# 不能直接用 spec_name 作为 func_name(会走裸名调用路径,
|
||
# 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀)
|
||
return self._translate_generic_ctor_call(
|
||
pool, builder, mod, spec_name, cl, trans)
|
||
else:
|
||
# 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x)
|
||
# (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化,
|
||
# 泛型函数按普通函数编译,类型参数 [T] 仅在函数定义处消费)。
|
||
# 检查当前模块是否已定义同名函数(def double[T] 编译后即普通函数
|
||
# double),若是则丢弃 [t.CInt] 显式类型参数,退回普通函数调用。
|
||
if self.find_func_in_module(mod, gen_class_name) is not None:
|
||
func_name = gen_class_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, trans)
|
||
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 self._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 self.translate_c_deref(pool, builder, mod, cl, trans)
|
||
elif string.strcmp(func_name, "DerefAs") == 0:
|
||
return self.translate_c_derefas(pool, builder, mod, cl, trans)
|
||
elif string.strcmp(func_name, "Addr") == 0:
|
||
return self.translate_c_addr(pool, builder, mod, cl, trans)
|
||
elif string.strcmp(func_name, "Set") == 0:
|
||
# c.Set(a, b) = a = b(赋值语义,非指针解引用)。
|
||
# 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。
|
||
return self.translate_c_set(pool, builder, mod, cl, trans)
|
||
elif string.strcmp(func_name, "Load") == 0:
|
||
return self.translate_c_load(pool, builder, mod, cl, trans)
|
||
elif string.strcmp(func_name, "Asm") == 0:
|
||
return self.translate_c_asm(pool, builder, mod, cl, trans)
|
||
elif string.strcmp(func_name, "LLVMIR") == 0:
|
||
return self.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")
|
||
elif string.strcmp(func_name, "CIf") == 0:
|
||
# 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1
|
||
# 对齐 TPC HandlesExprCall.py L2434-2444
|
||
cif_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cif_args is not None and cif_args.__len__() >= 1:
|
||
cif_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans)
|
||
if cif_arg_val is not None:
|
||
cif_bits: int = HandlesExpr.get_llvm_type_bits(cif_arg_val.Ty)
|
||
if cif_bits == 1:
|
||
return cif_arg_val
|
||
if HandlesExpr.is_ptr_type(cif_arg_val.Ty) != 0:
|
||
cif_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
|
||
pool, cif_arg_val.Ty, "null")
|
||
return llvmlite.build_icmp(
|
||
builder, llvmlite.ICMP_NE, cif_arg_val, cif_null)
|
||
cif_zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
return llvmlite.build_icmp(
|
||
builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero)
|
||
return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0")
|
||
elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0:
|
||
# 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真
|
||
# 对齐 TPC HandlesExprCall.py L2445-2446
|
||
return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1")
|
||
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = cargs.__len__()
|
||
|
||
# ============================================================
|
||
# stdarg 糖函数处理: va_arg / arg / va_start / va_end
|
||
# 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理:
|
||
# va_arg(ap, type) → %N = va_arg <ap_ty> <ap>, <type> (LLVM 指令)
|
||
# va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32)
|
||
# arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr)
|
||
# va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic)
|
||
# va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic)
|
||
# ============================================================
|
||
if func_name is not None and trans is not None:
|
||
if string.strcmp(func_name, "va_arg") == 0:
|
||
return HandlesExprCall._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can,
|
||
funcs_ptr, func_count, trans)
|
||
elif string.strcmp(func_name, "arg") == 0:
|
||
return HandlesExprCall._translate_arg_sugar(pool, builder, mod, cl, cargs, can,
|
||
funcs_ptr, func_count, trans)
|
||
elif string.strcmp(func_name, "va_start") == 0:
|
||
return HandlesExprCall._translate_va_start_sugar(pool, builder, mod, cargs, can,
|
||
funcs_ptr, func_count, trans)
|
||
elif string.strcmp(func_name, "va_end") == 0:
|
||
return HandlesExprCall._translate_va_end_sugar(pool, builder, mod, cargs, can,
|
||
funcs_ptr, func_count, trans)
|
||
|
||
# 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32
|
||
# 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x)
|
||
# 单参数:str(val) → bitcast val to i8*
|
||
# int(val) → trunc/sext val to i32
|
||
# 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名
|
||
# (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、
|
||
# combine[T1,T2] 的 T1(b) 依赖此路径)
|
||
if func_name is not None and can == 1:
|
||
cast_fn_name: str = HandlesType.resolve_generic_type_name(func_name)
|
||
if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0:
|
||
# str(x) / bytes(x) → i8* (bitcast)
|
||
cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||
if cast_arg is not None:
|
||
i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
return self._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin)
|
||
return None
|
||
elif string.strcmp(cast_fn_name, "int") == 0:
|
||
# int(x) → i32
|
||
cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||
if cast_arg_int is not None:
|
||
i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
return self._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin)
|
||
return None
|
||
elif string.strcmp(cast_fn_name, "bool") == 0:
|
||
# bool(x) → i1(严格 != 0 归一化)
|
||
# 整数: icmp ne x, 0 → i1
|
||
# 浮点: fcmp one x, 0.0 → i1
|
||
# 指针: icmp ne x, null → i1
|
||
cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||
if cast_arg_bool is not None:
|
||
arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty)
|
||
arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty)
|
||
# 整数: icmp ne x, 0
|
||
if arg_bits != 0:
|
||
zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0)
|
||
if zero_int is not None:
|
||
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int)
|
||
return None
|
||
# 浮点: fcmp one x, 0.0
|
||
if arg_fbits != 0:
|
||
zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty
|
||
zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0)
|
||
if zero_flt is not None:
|
||
return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt)
|
||
return None
|
||
# 指针: icmp ne x, null
|
||
ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null")
|
||
if ptr_null is not None:
|
||
return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null)
|
||
return None
|
||
return None
|
||
|
||
# 检测 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)
|
||
tc_arg2_is_cptr: int = 0
|
||
if tc_arg2_node is not None:
|
||
# 形式 1: t.CPtr(Attribute 形式)
|
||
if 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:
|
||
tc_arg2_is_cptr = 1
|
||
# 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr))
|
||
elif tc_arg2_node.kind() == ast.ASTKind.Name:
|
||
tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node)
|
||
if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0:
|
||
tc_arg2_is_cptr = 1
|
||
if tc_arg2_is_cptr != 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 self._translate_t_type_cast(
|
||
pool, builder, tc_arg_val, target_ty,
|
||
func_name, tc_arg_node, trans)
|
||
# t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL
|
||
return None
|
||
|
||
# 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等
|
||
# 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换
|
||
# map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等)
|
||
# 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体
|
||
# 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、
|
||
# combine[T1,T2] 的 T1(b) 依赖此路径)
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
bare_fn_name: str = HandlesType.resolve_generic_type_name(func_name)
|
||
bare_ty: llvmlite.LLVMType | t.CPtr = None
|
||
# 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble,
|
||
# 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致)
|
||
if string.strcmp(bare_fn_name, "double") == 0:
|
||
bare_ty = llvmlite.Double(pool)
|
||
elif string.strcmp(bare_fn_name, "float") == 0:
|
||
bare_ty = llvmlite.Float(pool)
|
||
else:
|
||
bare_ty = HandlesType.map_t_type(pool, bare_fn_name)
|
||
# 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名),
|
||
# 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。
|
||
# GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。
|
||
if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0:
|
||
gp_ast: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, bare_fn_name, 0)
|
||
if gp_ast is not None:
|
||
imp_gp: str = None
|
||
fi_gp: str = None
|
||
if trans is not None:
|
||
imp_gp = trans._imported_modules
|
||
fi_gp = trans._from_imports
|
||
bare_ty = HandlesType.resolve_annotation_type(
|
||
pool, gp_ast, imp_gp, fi_gp, trans)
|
||
if bare_ty is not None and can == 1:
|
||
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
|
||
if bare_arg_node is not None:
|
||
bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, bare_arg_node, None, 0, trans)
|
||
if bare_arg_val is not None:
|
||
return self._translate_t_type_cast(
|
||
pool, builder, bare_arg_val, bare_ty,
|
||
bare_fn_name, bare_arg_node, trans)
|
||
|
||
# 检测 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
|
||
# 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj)
|
||
sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None
|
||
sz_resolved_name: str = sz_cls_name
|
||
if sz_cls_name is not None:
|
||
# 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__()
|
||
sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name)
|
||
sz_resolved_name = sz_cls_name
|
||
# 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt")
|
||
# 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量
|
||
# "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA"
|
||
dot_pos: str = string.strrchr(sz_cls_name, '.')
|
||
if dot_pos is not None:
|
||
sz_cls_name = dot_pos + 1
|
||
# 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节)
|
||
# 联合类型在 TPV 中表示指针,可以指向多种类型
|
||
# 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理
|
||
if string.strstr(sz_cls_name, "|") is not None:
|
||
return llvmlite.const_int64(pool, 8)
|
||
# 内置类型 sizeof(int=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
|
||
elif string.strcmp(sz_cls_name, "CBool") == 0:
|
||
sz_builtin = 1
|
||
elif string.strcmp(sz_cls_name, "bool") == 0:
|
||
sz_builtin = 1
|
||
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_resolved_ty = HandlesStruct.get_struct_type(sz_cls_name)
|
||
# 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小
|
||
# (GenericTest2 Stack.type_size 依赖此路径)
|
||
if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript:
|
||
sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value)
|
||
if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name:
|
||
gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value)
|
||
if gen_nm_sz.id is not None:
|
||
gen_args_sz: list[str] | t.CPtr = self._extract_type_args_from_slice(pool, sub_sz.slice)
|
||
if gen_args_sz is not None and gen_args_sz.__len__() > 0:
|
||
gargs_resolved: list[str] | t.CPtr = list[str](pool, 8)
|
||
if gargs_resolved is not None:
|
||
gai_sz: t.CSizeT = gen_args_sz.__len__()
|
||
gai2_sz: t.CSizeT = 0
|
||
for gai2_sz in range(gai_sz):
|
||
gres_sz: str = HandlesType.resolve_generic_type_name(
|
||
gen_args_sz.get(gai2_sz))
|
||
gargs_resolved.append(gres_sz)
|
||
spec_sz: str = HandlesClassDef._specialize_generic_class(
|
||
trans, gen_nm_sz.id, gargs_resolved)
|
||
if spec_sz is not None:
|
||
sz_resolved_name = spec_sz
|
||
sz_resolved_ty = HandlesStruct.get_struct_type(spec_sz)
|
||
# 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型
|
||
# (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int]))
|
||
if sz_resolved_ty is None:
|
||
inst_sz_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, sz_at.value, None, 0, trans)
|
||
if inst_sz_val is not None and inst_sz_val.Ty is not None:
|
||
match inst_sz_val.Ty:
|
||
case llvmlite.LLVMType.Ptr(inst_inner_sz):
|
||
match inst_inner_sz:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
sz_resolved_ty = inst_inner_sz
|
||
case _:
|
||
pass
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
sz_resolved_ty = inst_sz_val.Ty
|
||
case _:
|
||
pass
|
||
if sz_resolved_ty is not None:
|
||
sz_val: int = HandlesClassDef._get_type_size(sz_resolved_ty)
|
||
if sz_val > 0:
|
||
return llvmlite.const_int64(pool, sz_val)
|
||
# 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止
|
||
HandlesType.fatal_error(
|
||
sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小",
|
||
"TypeError")
|
||
# 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出)
|
||
if sz_resolved_name is None:
|
||
sz_resolved_name = "(unknown)"
|
||
HandlesType.fatal_error(
|
||
sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小",
|
||
"TypeError")
|
||
|
||
# 检测 obj.__len__() — 返回 list 对象的 __count__ 字段(偏移 8,i64)
|
||
# __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct
|
||
# 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value
|
||
# 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点,
|
||
# 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer)
|
||
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_value(
|
||
builder, pool, mod, len_at.value, funcs_ptr, func_count, trans)
|
||
if obj_val is not None and obj_val.Ty is not None:
|
||
# 防御性类型检查: obj_val 必须是指针类型才能做 GEP
|
||
# 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、
|
||
# 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针,
|
||
# 导致 llc 报错 "base of getelementptr must be a pointer"
|
||
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
|
||
return llvmlite.const_int64(pool, 0)
|
||
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)
|
||
|
||
# 检测 len() 内置函数调用 — 转换为 strlen 调用
|
||
# len(s) 对 str 类型调用 strlen,返回 i64
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
if func_name is not None and string.strcmp(func_name, "len") == 0:
|
||
if can == 1:
|
||
len_arg_node: ast.AST | t.CPtr = cargs.get(0)
|
||
if len_arg_node is not None:
|
||
len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, len_arg_node, None, 0, trans)
|
||
if len_val is not None:
|
||
# 确保 strlen 在模块中有声明
|
||
strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen")
|
||
if strlen_fn is None:
|
||
i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln)
|
||
if strlen_fn is not None:
|
||
llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s")
|
||
# 参数类型转换为 i8*
|
||
i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val)
|
||
len_coerced: llvmlite.Value | t.CPtr = len_val
|
||
if HandlesExpr.is_ptr_type(len_arg_ty) != 0:
|
||
len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2)
|
||
# 构建单参数链表并调用 strlen
|
||
len_coerced.Next = None
|
||
i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0)
|
||
|
||
# 检测类名静态/类方法调用: ClassName.method(args)
|
||
# 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时,
|
||
# 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if st_at is not None and st_at.value is not None and trans is not None:
|
||
if st_at.value.kind() == ast.ASTKind.Name:
|
||
st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value)
|
||
if st_nm.id is not None:
|
||
# 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法
|
||
st_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, st_nm.id)
|
||
if st_var is None and HandlesStruct.get_struct_type(st_nm.id) is not None:
|
||
st_res: llvmlite.Value | t.CPtr = self._translate_static_class_call(
|
||
pool, builder, mod, st_nm.id, func_name, cl, trans)
|
||
if st_res is not None:
|
||
return st_res
|
||
|
||
# 检测方法调用: 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 self._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 self._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 self._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 = self._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 = self._special_method_ret_ty(
|
||
pool, cls_nm2, func_name)
|
||
if ret_ty3 is None:
|
||
ret_ty3 = self._LookupMethodRetTyFromTextLL(
|
||
pool, sha1_fc, cls_nm2, func_name)
|
||
if ret_ty3 is None:
|
||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||
ret_ty3 = self._lookup_method_ret_ty_via_vpi(
|
||
pool, sha1_fc, cls_nm2, func_name)
|
||
if ret_ty3 is None:
|
||
ret_ty3 = self._fail_method_ret_ty(func_name)
|
||
self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3)
|
||
return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0)
|
||
|
||
# ============================================================
|
||
# 检测表达式接收者方法调用: (expr).method(args)
|
||
#
|
||
# 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时
|
||
# (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者,
|
||
# 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。
|
||
# ============================================================
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if expr_method_at is not None and expr_method_at.value is not None and trans is not None:
|
||
evk: int = expr_method_at.value.kind()
|
||
if evk != ast.ASTKind.Name and evk != ast.ASTKind.Attribute:
|
||
# 翻译接收者表达式(求值结果应为 Ptr(Struct))
|
||
expr_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans)
|
||
if expr_obj is not None and expr_obj.Ty is not None:
|
||
expr_cls_nm: str = None
|
||
match expr_obj.Ty:
|
||
case llvmlite.LLVMType.Ptr(expr_struct_ty):
|
||
expr_cls_nm = HandlesStruct.get_class_name_by_type(
|
||
pool, expr_struct_ty)
|
||
if expr_cls_nm is not None:
|
||
return self._translate_method_call(
|
||
pool, builder, mod, expr_cls_nm, func_name,
|
||
expr_obj, cl, trans)
|
||
|
||
# ============================================================
|
||
# 检测 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 self._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:
|
||
# 防御性类型检查: lm_obj 必须是指针类型才能做 GEP
|
||
# translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性)
|
||
# 可能返回 i32 0 (非指针),直接 GEP 会导致
|
||
# "base of getelementptr must be a pointer" 错误
|
||
if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0:
|
||
lm_node_kind: int = lm_at.value.kind()
|
||
fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||
if fb_lm is not None:
|
||
viperlib.snprintf(fb_lm, 1024,
|
||
"list 方法 '%s' 的目标对象非指针 (node kind=%d),"
|
||
"translate_value 类型推断失败",
|
||
lm_name, lm_node_kind)
|
||
VLogger.critical(fb_lm, "LIST-METHOD")
|
||
return 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.const_int64(pool, 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.const_int64(pool, 4)
|
||
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_idx_node)
|
||
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.const_int64(pool, 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.const_int64(pool, 4)
|
||
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_idx_node)
|
||
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, s_val_node)
|
||
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.const_int64(pool, 1)
|
||
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.const_int64(pool, 1))
|
||
llvmlite.build_store(builder, p_nc, p_cpp)
|
||
p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 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.const_int64(pool, 4)
|
||
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.const_int64(pool, 1)
|
||
c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1)
|
||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 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.const_int64(pool, 5)
|
||
it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5)
|
||
llvmlite.build_store(builder, llvmlite.const_int64(pool, 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 = self._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)
|
||
self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2)
|
||
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
|
||
# 别名导入的类构造: from X import Class as Alias → Alias(args)
|
||
# 可见性列表按别名注册(HandleImportFromNames 用 local_name=asname),但结构体
|
||
# 按原名注册(如 Keyword as KwNode → 可见 "KwNode"、注册名 "Keyword")。
|
||
# 直接按别名 find_struct 查不到 → 误走普通函数路径生成 @sha1.Keyword 调用
|
||
# (该函数不存在)→ 链接期 undefined reference。此处解析别名→原名再查结构体。
|
||
if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
if trans._from_imports is not None:
|
||
ctor_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||
if ctor_sha1 is not None:
|
||
ctor_orig: str = HandlesImports.lookup_from_import_original(
|
||
trans._from_imports, func_name)
|
||
if ctor_orig is not None:
|
||
# 复制到独立 null 终止缓冲区(from_imports 内部缓冲未终止)
|
||
co_len: t.CSizeT = 0
|
||
while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0':
|
||
co_len += 1
|
||
co_buf: str = pool.alloc(co_len + 1)
|
||
if co_buf is not None:
|
||
for co_i in range(co_len):
|
||
co_buf[co_i] = ctor_orig[co_i]
|
||
co_buf[co_len] = '\0'
|
||
# 原名结构体查找(可见性已由别名保证,原名无需再查)
|
||
gen_ctor_entry = HandlesStruct.find_struct_by_module(co_buf, ctor_sha1)
|
||
if gen_ctor_entry is None:
|
||
gen_ctor_entry = HandlesStruct.find_struct(co_buf)
|
||
if gen_ctor_entry is not None:
|
||
struct_ty = gen_ctor_entry.Ty
|
||
func_name = co_buf
|
||
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 self._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 self._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 self._translate_struct_ctor_kw(
|
||
pool, builder, mod, struct_ty, func_name, cargs, can,
|
||
keywords, kw_count, trans)
|
||
# 仅位置参数:按字段顺序构建
|
||
return self._translate_struct_ctor(
|
||
pool, builder, mod, struct_ty, func_name, cargs, can, trans)
|
||
|
||
# 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造
|
||
# (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5
|
||
# Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb)
|
||
# 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。)
|
||
if struct_ty is None and gen_ctor_entry is None and trans is not None:
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
template_cd_bare: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(func_name)
|
||
if template_cd_bare is not None and template_cd_bare.type_params is not None:
|
||
tp_bare: list[str] | t.CPtr = template_cd_bare.type_params
|
||
tp_count_bare: t.CSizeT = tp_bare.__len__()
|
||
if tp_count_bare > 0:
|
||
inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8)
|
||
if inferred_args_bare is not None:
|
||
tpi_bare: t.CSizeT = 0
|
||
for tpi_bare in range(tp_count_bare):
|
||
ta_bare: str = "int"
|
||
if tpi_bare < can:
|
||
ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare))
|
||
inferred_args_bare.append(ta_bare)
|
||
spec_name_bare: str = HandlesClassDef._specialize_generic_class(
|
||
trans, func_name, inferred_args_bare)
|
||
if spec_name_bare is not None:
|
||
return self._translate_generic_ctor_call(
|
||
pool, builder, mod, spec_name_bare, cl, trans)
|
||
|
||
# REnum 变体构造检测: ClassName.VariantName(args...)
|
||
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体
|
||
# 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名
|
||
# 对应 TPC HandlesExprCall.py:585-644 的三条检测路径之一
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
rc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name:
|
||
rc_cls_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rc_at.value)
|
||
if rc_cls_node.id is not None:
|
||
rc_cls_name: str = rc_cls_node.id
|
||
# 检查 ClassName 是否是已注册的 REnum 类
|
||
if HandlesClassDef._is_renum_class_name(rc_cls_name) != 0:
|
||
# 在该 REnum 类中查找变体名 func_name
|
||
rc_tag: int = HandlesClassDef._lookup_renum_variant_in_class(
|
||
rc_cls_name, func_name)
|
||
if rc_tag >= 0:
|
||
return self._translate_renum_construct(
|
||
pool, builder, mod, rc_cls_name, func_name,
|
||
rc_tag, cargs, can, trans)
|
||
|
||
# 查找函数:优先从函数表按裸名精确匹配(同模块函数),
|
||
# 再从模块函数链表按后缀匹配(SHA1 前缀名)。
|
||
# 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配——
|
||
# "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被
|
||
# 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data),
|
||
# 传入句柄数组等指针时把句柄值当地址写入直接崩溃。
|
||
# 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。
|
||
# 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 = None
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
# 裸名调用:允许精确 + 后缀匹配
|
||
found_func = self.find_func_in_module(mod, func_name)
|
||
else:
|
||
# 模块限定/属性调用:精确匹配优先,后缀匹配仅接受模块函数。
|
||
# 后缀匹配命中的"方法"(SHA1.Class.method,Class 是已注册类)必须拒绝——
|
||
# 短方法名(free/reset/close 等)会误命中其他模块的方法
|
||
# (如 stdlib.free 命中 viperio.Buf.free,普通指针被当 Buf 释放崩溃;
|
||
# 且 atom.__atomic_test_and_set 若被误拒,返回类型从 i1 推断成 i32,
|
||
# 调用按 i32 读 i1 返回值读到垃圾高位,spinlock 恒非 0 卡死)。
|
||
# 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。
|
||
found_func = self.find_func_in_module(mod, func_name)
|
||
if found_func is not None:
|
||
ff_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
|
||
if ff_name is not None:
|
||
ff_dots: int = 0
|
||
ffi2: t.CSizeT = 0
|
||
while ff_name[ffi2] != '\0':
|
||
if ff_name[ffi2] == '.':
|
||
ff_dots += 1
|
||
ffi2 += 1
|
||
if ff_dots >= 2:
|
||
# 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod)
|
||
seg2: t.CChar | t.CPtr = pool.alloc(64)
|
||
if seg2 is not None:
|
||
seg2[0] = '\0'
|
||
si: t.CSizeT = 0
|
||
while ff_name[si] != '\0' and si < 17:
|
||
si += 1
|
||
seg_start: t.CSizeT = si
|
||
seg_end: t.CSizeT = si
|
||
while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.':
|
||
seg_end += 1
|
||
seg_len: t.CSizeT = seg_end - seg_start
|
||
if seg_len > 0 and seg_len < 63:
|
||
string.strncpy(seg2, ff_name + seg_start, seg_len)
|
||
seg2[seg_len] = '\0'
|
||
# 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径)
|
||
if HandlesStruct.get_struct_type(seg2) is not None:
|
||
found_func = None
|
||
# C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare
|
||
# 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用
|
||
if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
found_func = self._ensure_c_lib_declare(pool, mod, func_name)
|
||
# builtins 自动关联:C 库未命中时,自动关联 builtins 模块的内置函数(ord/chr 等)。
|
||
# builtins 已由编译链预加入(StubMerger 预加入列表)。PhaseA 期 builtins 尚未编译,
|
||
# 因此按约定签名创建 {builtins_sha1}.{name} 的 mangled declare(链接时解析到
|
||
# builtins.vp 的真实定义);签名与 builtins.vp 保持一致:ord(i8)->i32, chr(i32)->i8。
|
||
if found_func is None:
|
||
bi_sha1: str = self._lookup_module_sha1("builtins")
|
||
if bi_sha1 is not None:
|
||
bi_ret: llvmlite.LLVMType | t.CPtr = None
|
||
bi_p1: llvmlite.LLVMType | t.CPtr = None
|
||
if string.strcmp(func_name, "ord") == 0:
|
||
bi_ret = llvmlite.Int32(pool)
|
||
bi_p1 = llvmlite.Int8(pool)
|
||
elif string.strcmp(func_name, "chr") == 0:
|
||
bi_ret = llvmlite.Int8(pool)
|
||
bi_p1 = llvmlite.Int32(pool)
|
||
if bi_ret is not None:
|
||
bi_sym: str = func_name
|
||
if self.is_cexport_func(bi_sha1, func_name) == 0:
|
||
bi_sym_len: t.CSizeT = string.strlen(bi_sha1) + string.strlen(func_name) + 2
|
||
bi_sym_buf: str = pool.alloc(bi_sym_len)
|
||
if bi_sym_buf is not None:
|
||
viperlib.snprintf(bi_sym_buf, bi_sym_len, "%s.%s", bi_sha1, func_name)
|
||
bi_sym = bi_sym_buf
|
||
bi_decl: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||
pool, mod, bi_sym, bi_ret)
|
||
if bi_decl is not None:
|
||
llvmlite.add_param(pool, bi_decl, bi_p1, "v")
|
||
found_func = bi_decl
|
||
# 使用访问器绕过 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 = self._infer_external_func_ret_ty(pool, func_name)
|
||
|
||
# 如果模块中找不到函数,检查是否是变量(函数指针 / 闭包调用)
|
||
if found_func is None:
|
||
fp_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name)
|
||
if fp_alloca is not None:
|
||
# 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用
|
||
if HandlesExprCall.is_closure_name(func_name) != 0:
|
||
return HandlesExprCall.translate_closure_call(pool, builder, mod, fp_alloca,
|
||
cargs, can)
|
||
# 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用
|
||
if HandlesExprCall._is_func_ptr_alloca(fp_alloca) != 0:
|
||
return HandlesExprCall._translate_func_ptr_call(pool, builder, mod, fp_alloca,
|
||
func_name, cargs, can, trans)
|
||
# 其他 i8* 变量按闭包调用路径处理
|
||
return HandlesExprCall.translate_closure_call(pool, builder, mod, fp_alloca,
|
||
cargs, can)
|
||
|
||
# 翻译参数并链接
|
||
# 有关键字参数且找到函数定义时,按参数名匹配
|
||
if kw_count > 0 and found_func is not None and found_params is not None:
|
||
return self._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 为 None(stub 未注入)时,
|
||
# 根据外部函数签名推断期望类型,提升字面量(如 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 = self._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)
|
||
elif found_func is not None:
|
||
# found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT))
|
||
# 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配
|
||
fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
fpi: int = 0
|
||
while fp is not None and fpi < ai:
|
||
fp = llvmlite.param_get_next(fp)
|
||
fpi += 1
|
||
if fp is not None:
|
||
fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp)
|
||
if fpty is not None:
|
||
arg_val = HandlesExpr.coerce_to_type(
|
||
builder, arg_val, fpty, arg)
|
||
elif found_func.IsVarArg == 1:
|
||
# Win64 变参 8 字节槽位:<64 位整数按 i64 传(sext 符号扩展),
|
||
# f32 提升为 f64。若按原窄类型传,调用点只写 4 字节进 8 字节槽,
|
||
# 高 4 字节残留旧栈数据,va_arg(i64) 读到垃圾(如 DefineTest
|
||
# PAGE=%d 读到 0x400921FB00001000,高位是 PI 残留)。
|
||
# 对齐 TPC FuncGen/Python-llvmlite 的 ABI 自动提升。
|
||
ab_va: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
|
||
af_va: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty)
|
||
i64_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
if ab_va != 0 and ab_va < 64:
|
||
arg_val = llvmlite.build_sext(builder, arg_val, i64_va)
|
||
elif af_va == 32:
|
||
arg_val = llvmlite.build_fpext(
|
||
builder, arg_val, llvmlite.Double(pool))
|
||
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
|
||
|
||
# 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数
|
||
# defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count
|
||
if can > 0 or (can == 0 and cargs is not None):
|
||
df_defaults: t.CVoid | t.CPtr = None
|
||
df_default_count: int = 0
|
||
df_param_count: int = 0
|
||
# 先从当前模块函数表查找 FuncEntry
|
||
if trans is not None and trans._funcs is not None:
|
||
df_entry: FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_in_table(
|
||
trans._funcs, trans._func_count, func_name)
|
||
if df_entry is not None:
|
||
df_defaults = df_entry.Defaults
|
||
df_default_count = df_entry.DefaultCount
|
||
df_param_count = df_entry.ParamCount
|
||
# 如果当前模块没有,从全局默认参数表查找(跨模块)
|
||
if df_defaults is None:
|
||
gd_entry: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(func_name)
|
||
if gd_entry is not None:
|
||
df_defaults = gd_entry.Defaults
|
||
df_default_count = gd_entry.DefaultCount
|
||
df_param_count = gd_entry.ParamCount
|
||
# 填充缺失参数
|
||
if df_defaults is not None and df_default_count > 0 and can < df_param_count:
|
||
df_offset: int = df_param_count - df_default_count
|
||
df_di: int = 0
|
||
while df_di < df_default_count:
|
||
df_param_idx: int = df_offset + df_di
|
||
if df_param_idx >= can:
|
||
# 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收)
|
||
df_arg_val: llvmlite.Value | t.CPtr = None
|
||
if gd_entry is not None:
|
||
df_arg_val = HandlesExprCall._build_const_from_snapshot(
|
||
pool, mod, gd_entry, df_di, trans, builder)
|
||
if df_arg_val is None:
|
||
df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr))
|
||
df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di)
|
||
if df_default_node is not None:
|
||
df_arg_val = HandlesExpr.translate_value(
|
||
builder, pool, mod, df_default_node, None, 0, trans)
|
||
if df_arg_val is not None:
|
||
df_arg_val.Next = None
|
||
if head is None:
|
||
head = df_arg_val
|
||
else:
|
||
tail.Next = df_arg_val
|
||
tail = df_arg_val
|
||
df_di += 1
|
||
|
||
# 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi")
|
||
# t.CExtern/t.State/t.CExport 函数不加 SHA1 前缀,使用裸名
|
||
# declare 和 define 统一用 found_func.Name:
|
||
# - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name)
|
||
# - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名
|
||
# 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀,
|
||
# 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference
|
||
call_name: str = func_name
|
||
# 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse")
|
||
# 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败
|
||
orig_func_name: str = None
|
||
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 为 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 = self._lookup_module_sha1(xmod_nm.id)
|
||
if mod_sha1 is not None:
|
||
# fast-fail: 模块限定调用要求模块已被当前文件 import。
|
||
# 全局 SHA1 存储包含所有被扫描的 includes,未导入的模块
|
||
# (如 this.this() 但 import this 被注释)也会命中存储,
|
||
# 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。
|
||
is_xmod_imported: int = 1
|
||
if trans is not None and trans._imported_modules is not None:
|
||
is_xmod_imported = HandlesImports.is_module_imported(
|
||
trans._imported_modules, xmod_nm.id)
|
||
if is_xmod_imported == 0:
|
||
err_ni: t.CChar | t.CPtr = pool.alloc(256)
|
||
if err_ni is not None:
|
||
viperlib.snprintf(err_ni, 256,
|
||
"跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)",
|
||
xmod_nm.id, func_name, xmod_nm.id, xmod_nm.id)
|
||
HandlesType.fatal_error(xmod_nm, err_ni)
|
||
HandlesType.fatal_error(xmod_nm, "跨模块调用:模块未导入")
|
||
# 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer)
|
||
reexport_src: str = HandlesImports.lookup_reexport(mod_sha1, func_name)
|
||
if reexport_src is not None:
|
||
reexport_sha1: str = self._lookup_module_sha1(reexport_src)
|
||
if reexport_sha1 is not None:
|
||
mod_sha1 = reexport_sha1
|
||
# CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func
|
||
if self.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:
|
||
# 别名导入(import X as Y):Y 在 _imported_modules 中,
|
||
# 但 _lookup_module_sha1("Y") 精确匹配失败(mod_arr 只存文件名)。
|
||
# 先尝试 from_imports 查找别名→完整模块名→后缀匹配 SHA1。
|
||
# allow_star_fallback=0 避免被 star import 回退误导。
|
||
alias_sha1: str = None
|
||
if trans is not None and trans._from_imports is not None:
|
||
alias_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_nm.id, 0)
|
||
if alias_sha1 is not None:
|
||
if self.is_cexport_func(alias_sha1, func_name) != 0:
|
||
call_name = func_name
|
||
else:
|
||
AliasMangledLen: t.CSizeT = string.strlen(alias_sha1) + string.strlen(func_name) + 2
|
||
alias_mangled: str = pool.alloc(AliasMangledLen)
|
||
if alias_mangled is not None:
|
||
viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name)
|
||
call_name = alias_mangled
|
||
else:
|
||
# 已导入模块但 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 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_nm.id, 0)
|
||
if from_sha1 is not None:
|
||
# CExport 函数定义用裸名,跨模块调用需用裸名
|
||
if self.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 回退(allow_star_fallback=0)。
|
||
# star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数;
|
||
# 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号
|
||
# (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成
|
||
# f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。
|
||
# 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。
|
||
if trans is not None and trans._from_imports is not None:
|
||
bare_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||
if bare_sha1 is not None:
|
||
# 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名
|
||
# 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse
|
||
bare_orig: str = HandlesImports.lookup_from_import_original(
|
||
trans._from_imports, func_name)
|
||
bare_func_name: str = func_name
|
||
if bare_orig is not None:
|
||
# bare_orig 指向 from_imports 内部缓冲区,未 null 终止
|
||
# 需复制到独立缓冲区(截断于空格或 null)
|
||
bo_len: t.CSizeT = 0
|
||
while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0':
|
||
bo_len += 1
|
||
bo_buf: str = pool.alloc(bo_len + 1)
|
||
if bo_buf is not None:
|
||
for bo_i in range(bo_len):
|
||
bo_buf[bo_i] = bare_orig[bo_i]
|
||
bo_buf[bo_len] = '\0'
|
||
bare_func_name = bo_buf
|
||
# 记录原始函数名,供后续重新推断返回类型
|
||
# 例如 from json.__parser import parse as json_parse
|
||
# func_name="json_parse", bare_func_name="parse"
|
||
# _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32
|
||
orig_func_name = bare_func_name
|
||
if self.is_cexport_func(bare_sha1, bare_func_name) != 0:
|
||
call_name = bare_func_name
|
||
else:
|
||
bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_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, bare_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 string.strcmp(func_name, "memcpy") == 0 and can >= 3:
|
||
return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2)
|
||
# 别名导入重新推断返回类型:
|
||
# from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32
|
||
# 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*)
|
||
# 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃
|
||
if orig_func_name is not None and orig_func_name != func_name:
|
||
re_inferred_ty: llvmlite.LLVMType | t.CPtr = self._infer_external_func_ret_ty(pool, orig_func_name)
|
||
if re_inferred_ty is not None:
|
||
call_ret_ty = re_inferred_ty
|
||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
||
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
||
is_variadic_call: int = HandlesExprCall._check_and_promote_variadic_call(pool, builder, mod, call_name, head, can)
|
||
return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, is_variadic_call)
|
||
|
||
# ============================================================
|
||
# P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp:
|
||
# 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表)
|
||
# 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段
|
||
# ============================================================
|
||
|
||
def translate_closure_call(self, 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)
|
||
|
||
def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int:
|
||
"""判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否"""
|
||
if alloca is None or alloca.Ty is None:
|
||
return 0
|
||
if HandlesExpr.is_ptr_type(alloca.Ty) == 0:
|
||
return 0
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is None or HandlesExpr.is_ptr_type(pointee) == 0:
|
||
return 0
|
||
inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee
|
||
if inner is None or HandlesExpr.is_ptr_type(inner) != 0:
|
||
return 0
|
||
return 1
|
||
|
||
def _ensure_closure_names(self) -> int:
|
||
"""确保闭包名表已分配,0 失败"""
|
||
if self.ClosureNames is not None:
|
||
return 1
|
||
self.ClosureNames = stdlib.malloc(64 * MAX_CLOSURE_NAMES)
|
||
if self.ClosureNames is None:
|
||
return 0
|
||
string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES)
|
||
return 1
|
||
|
||
def register_closure_name(self, name: str) -> int:
|
||
"""注册嵌套函数(闭包变量)名,0 成功"""
|
||
if name is None:
|
||
return 1
|
||
if self._ensure_closure_names() == 0:
|
||
return 1
|
||
if self.ClosureCount >= MAX_CLOSURE_NAMES:
|
||
return 1
|
||
idx: t.CSizeT = t.CSizeT(self.ClosureCount) * 64
|
||
string.strncpy(self.ClosureNames + idx, name, 63)
|
||
self.ClosureCount += 1
|
||
return 0
|
||
|
||
def is_closure_name(self, name: str) -> int:
|
||
"""检查 name 是否已注册为闭包变量名,1=是 / 0=否"""
|
||
if name is None or self.ClosureNames is None:
|
||
return 0
|
||
i: t.CSizeT
|
||
for i in range(self.ClosureCount):
|
||
if string.strcmp(self.ClosureNames + i * 64, name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _ensure_funcptr_sigs(self) -> int:
|
||
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
|
||
if self.FuncptrNames is not None:
|
||
return 1
|
||
self.FuncptrNames = stdlib.malloc(64 * MAX_FUNC_PTR_SIGS)
|
||
self.FuncptrRets = stdlib.malloc(8 * MAX_FUNC_PTR_SIGS)
|
||
if self.FuncptrNames is None or self.FuncptrRets is None:
|
||
return 0
|
||
string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS)
|
||
return 1
|
||
|
||
def register_func_ptr_sig(self, name: str,
|
||
ret_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""注册函数指针变量的返回类型签名,0 成功"""
|
||
if name is None or ret_ty is None:
|
||
return 1
|
||
if self._ensure_funcptr_sigs() == 0:
|
||
return 1
|
||
if self.FuncptrCount >= MAX_FUNC_PTR_SIGS:
|
||
return 1
|
||
idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64
|
||
string.strcpy(self.FuncptrNames + idx, name)
|
||
self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty)
|
||
self.FuncptrCount += 1
|
||
return 0
|
||
|
||
def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""查函数指针变量的返回类型,None=未注册(调用时默认 i32)"""
|
||
if name is None or self.FuncptrNames is None:
|
||
return None
|
||
for i in range(self.FuncptrCount):
|
||
idx: t.CSizeT = t.CSizeT(i) * 64
|
||
if string.strcmp(self.FuncptrNames + idx, name) == 0:
|
||
return (llvmlite.LLVMType | t.CPtr)(
|
||
t.CVoid(self.FuncptrRets[i], t.CPtr))
|
||
return None
|
||
|
||
def _translate_func_ptr_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
fp_alloca: llvmlite.Value | t.CPtr,
|
||
func_name: str,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""函数指针变量间接调用,返回结果 Value"""
|
||
if builder is None or fp_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. load 函数地址 (i8*)
|
||
fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca)
|
||
if fn_i8 is None:
|
||
return None
|
||
|
||
# 2. 翻译实参并链接为 Value 链表
|
||
head: llvmlite.Value | t.CPtr = None
|
||
tail: llvmlite.Value | t.CPtr = None
|
||
arg_count: int = 0
|
||
ai: t.CSizeT
|
||
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:
|
||
arg_val.Next = None
|
||
if head is None:
|
||
head = arg_val
|
||
else:
|
||
tail.Next = arg_val
|
||
tail = arg_val
|
||
arg_count += 1
|
||
|
||
# 3. 按实参类型 + 注册的返回类型构造签名(未注册返回类型时默认 i32)
|
||
ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name)
|
||
if ret_ty is None:
|
||
ret_ty = i32_ty
|
||
fp_first: llvmlite.ParamNode | t.CPtr = None
|
||
fp_prev: llvmlite.ParamNode | t.CPtr = None
|
||
cur_v: llvmlite.Value | t.CPtr = head
|
||
for pi in range(arg_count):
|
||
if cur_v is None:
|
||
break
|
||
cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v)
|
||
pn2: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty)
|
||
if pn2 is not None:
|
||
if fp_first is None:
|
||
fp_first = pn2
|
||
if fp_prev is not None:
|
||
llvmlite.paramnode_set_next(fp_prev, pn2)
|
||
fp_prev = pn2
|
||
cur_v = llvmlite.value_get_next(cur_v)
|
||
|
||
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count)
|
||
if func_ty is None:
|
||
return None
|
||
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
|
||
|
||
# 4. bitcast i8* → 函数指针类型,间接调用
|
||
fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty)
|
||
if fn_typed is None:
|
||
return None
|
||
return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty)
|
||
|
||
def translate_printf_call(self, 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 → i32(printf 变参函数要求)
|
||
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, arg)
|
||
# C ABI float promotion: float → double(printf 变参函数要求)
|
||
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)
|
||
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)
|
||
|
||
def translate_print_call(self, 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):
|
||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cargs is None:
|
||
return
|
||
|
||
FMT_BUF_SIZE: t.CSizeT = 256
|
||
fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE)
|
||
if fmt_buf is None:
|
||
return
|
||
fmt_buf[0] = '\0'
|
||
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
dbl_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
|
||
can: t.CSizeT = cargs.__len__()
|
||
arg_head: llvmlite.Value | t.CPtr = None
|
||
arg_tail: llvmlite.Value | t.CPtr = None
|
||
arg_count: int = 1 # 格式串本身是第 1 个 printf 参数
|
||
|
||
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 or arg_val.Ty is None:
|
||
# 参数翻译失败 → "(null)"(与 TPC 一致,不传参)
|
||
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16:
|
||
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "(null)")
|
||
continue
|
||
|
||
# 数组名(如 print(l),l: t.CArray[t.CChar, N]):
|
||
# translate_value 会 load 出数组值([N x T]),print 无法格式化;
|
||
# 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容),
|
||
# 其他元素类型 → 0x%llx(打印数组地址)。
|
||
array_ptr: llvmlite.Value | t.CPtr = None
|
||
array_elem_bits: int = 0
|
||
if arg.kind() == ast.ASTKind.Name and trans is not None:
|
||
anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg)
|
||
if anm.id is not None:
|
||
arr_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||
trans.SymTab, anm.id)
|
||
if arr_alloca is not None and arr_alloca.Ty is not None \
|
||
and HandlesExpr.is_ptr_type(arr_alloca.Ty) != 0:
|
||
arr_pointee: llvmlite.LLVMType | t.CPtr = arr_alloca.Ty.Pointee
|
||
if arr_pointee is not None:
|
||
match arr_pointee:
|
||
case llvmlite.LLVMType.Array(arr_et, arr_n):
|
||
array_ptr = arr_alloca
|
||
array_elem_bits = HandlesExpr.get_llvm_type_bits(arr_et)
|
||
case _:
|
||
pass
|
||
|
||
token: t.CChar | t.CPtr = None
|
||
chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本
|
||
arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
|
||
arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty)
|
||
|
||
if array_ptr is not None:
|
||
# 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx
|
||
if array_elem_bits == 8:
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
token = "%s"
|
||
arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty)
|
||
else:
|
||
token = "0x%llx"
|
||
arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty)
|
||
elif HandlesExpr.is_ptr_type(arg_val.Ty) != 0:
|
||
# i8*(str/bytes)→ %s;其他指针 → 0x%llx
|
||
pointee: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee
|
||
if pointee is not None and HandlesExpr.get_llvm_type_bits(pointee) == 8:
|
||
token = "%s"
|
||
else:
|
||
token = "0x%llx"
|
||
arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty)
|
||
elif arg_bits != 0:
|
||
if arg_bits == 1:
|
||
token = "%d"
|
||
arg_val = llvmlite.build_zext(builder, arg_val, i32_ty)
|
||
elif arg_bits == 8:
|
||
token = "%d"
|
||
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
|
||
elif arg_bits == 16:
|
||
token = "%d"
|
||
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
|
||
elif arg_bits == 32:
|
||
token = "%d"
|
||
else:
|
||
token = "%lld"
|
||
elif arg_fbits != 0:
|
||
token = "%f"
|
||
if arg_fbits < 64:
|
||
arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty)
|
||
else:
|
||
# 结构体值/数组/函数等 → "(unknown)",不传参
|
||
token = "(unknown)"
|
||
chain_arg = 0
|
||
|
||
# 追加格式 token
|
||
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16:
|
||
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token)
|
||
# 链接参数
|
||
if chain_arg != 0:
|
||
arg_val.Next = None
|
||
if arg_tail is None:
|
||
arg_head = arg_val
|
||
else:
|
||
arg_tail.Next = arg_val
|
||
arg_tail = arg_val
|
||
arg_count += 1
|
||
|
||
# 追加默认换行(Python print 默认 end="\n")
|
||
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2:
|
||
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n")
|
||
|
||
fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
|
||
builder, pool, mod, fmt_buf, trans)
|
||
stdlib.free(fmt_buf)
|
||
if fmt_ptr is None:
|
||
return
|
||
fmt_ptr.Next = arg_head
|
||
# is_variadic=1: 带显式函数类型签名(C ABI 变参调用)
|
||
llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1)
|
||
|
||
def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
arg_node: ast.AST | t.CPtr,
|
||
funcs_ptr: t.CPtr,
|
||
func_count: int,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""获取 va_list 变量的 alloca 指针(不 load)
|
||
|
||
va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针),
|
||
而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca;
|
||
否则用 translate_value 翻译(调用者负责确保传入的是指针)。
|
||
"""
|
||
if arg_node is None:
|
||
return None
|
||
# Name 节点:直接查符号表获取 alloca 指针(不 load)
|
||
if arg_node.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node)
|
||
if nm.id is not None:
|
||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is not None:
|
||
return alloca
|
||
# 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况)
|
||
return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans)
|
||
|
||
def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||
type_node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||
"""解析 va_arg/arg 的类型参数为 LLVMType
|
||
|
||
支持的类型表达式:
|
||
t.CInt / t.CInt32T → i32
|
||
t.CInt64T → i64
|
||
t.CDouble → double
|
||
t.CPtr / t.CChar | t.CPtr → i8*
|
||
str / bytes → i8*
|
||
无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32)
|
||
"""
|
||
if type_node is None:
|
||
return llvmlite.Int32(pool)
|
||
# 使用 HandlesType.resolve_annotation_type 解析类型表达式
|
||
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
|
||
pool, type_node, trans._imported_modules, trans._from_imports, trans)
|
||
if resolved is not None:
|
||
return resolved
|
||
# 回退为 i32
|
||
return llvmlite.Int32(pool)
|
||
|
||
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
funcs_ptr: t.CPtr,
|
||
func_count: int,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""va_arg(ap, type) / va_arg(ap) → %N = va_arg <ap_ty> <ap>, <type>
|
||
|
||
生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。
|
||
"""
|
||
if can == 0 or cargs is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
# 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm)
|
||
# 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址;
|
||
# 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。
|
||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||
ap_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, ap_node, None, 0, trans)
|
||
if ap_val is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
ap_ptr: llvmlite.Value | t.CPtr = ap_val
|
||
|
||
# 第二个参数:目标类型(可选,默认 i32)
|
||
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
if can >= 2:
|
||
type_node: ast.AST | t.CPtr = cargs.get(1)
|
||
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
|
||
|
||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73)
|
||
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
|
||
abits_va: int = HandlesExpr.get_llvm_type_bits(arg_ty)
|
||
if abits_va != 0 and abits_va < 64:
|
||
read_ty = llvmlite.Int64(pool)
|
||
|
||
# 生成 va_arg 指令
|
||
return llvmlite.build_va_arg(builder, ap_ptr, read_ty)
|
||
|
||
def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
funcs_ptr: t.CPtr,
|
||
func_count: int,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""arg(type) → %N = va_arg <va_list_ty> <trans._va_list_ptr>, <type>
|
||
|
||
使用当前函数的隐式 va_list(trans._va_list_ptr),
|
||
简化 *args 函数体内的 va_arg 调用。
|
||
"""
|
||
if trans._va_list_ptr is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
# 第一个参数:目标类型(可选,默认 i32)
|
||
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
if can >= 1 and cargs is not None:
|
||
type_node: ast.AST | t.CPtr = cargs.get(0)
|
||
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
|
||
|
||
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致)
|
||
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
|
||
abits_arg: int = HandlesExpr.get_llvm_type_bits(arg_ty)
|
||
if abits_arg != 0 and abits_arg < 64:
|
||
read_ty = llvmlite.Int64(pool)
|
||
|
||
# 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址)
|
||
return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty)
|
||
|
||
def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
funcs_ptr: t.CPtr,
|
||
func_count: int,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap)
|
||
|
||
初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。
|
||
"""
|
||
if can == 0 or cargs is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
# 第一个参数:va_list 指针(获取 alloca,不 load)
|
||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
|
||
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||
if ap_ptr is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
# bitcast 到 i8*(@llvm.va_start 接受 i8*)
|
||
i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs)
|
||
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs)
|
||
if ap_i8 is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||
llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0)
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr,
|
||
can: t.CSizeT,
|
||
funcs_ptr: t.CPtr,
|
||
func_count: int,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""va_end(ap) → call void @llvm.va_end(i8* %ap)
|
||
|
||
清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。
|
||
"""
|
||
if can == 0 or cargs is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
# 第一个参数:va_list 指针(获取 alloca,不 load)
|
||
ap_node: ast.AST | t.CPtr = cargs.get(0)
|
||
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
|
||
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
|
||
if ap_ptr is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
# bitcast 到 i8*(@llvm.va_end 接受 i8*)
|
||
i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve)
|
||
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve)
|
||
if ap_i8 is None:
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||
llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0)
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int:
|
||
"""获取函数的固定参数数量(遍历 Params 链表)"""
|
||
if func is None:
|
||
return 0
|
||
count: int = 0
|
||
param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||
while param is not None:
|
||
count += 1
|
||
param = llvmlite.param_get_next(param)
|
||
return count
|
||
|
||
def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
call_name: str,
|
||
head: llvmlite.Value | t.CPtr,
|
||
can: t.CSizeT) -> int:
|
||
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升
|
||
|
||
返回: is_variadic (1=变长调用, 0=普通调用)
|
||
副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升)
|
||
"""
|
||
if mod is None or call_name is None or head is None:
|
||
return 0
|
||
# 查找函数对象
|
||
func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||
if func is None:
|
||
return 0
|
||
if func.IsVarArg != 1:
|
||
return 0
|
||
|
||
# 获取固定参数数量
|
||
fixed_count: int = self._get_func_fixed_param_count(func)
|
||
|
||
# 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1
|
||
if can <= fixed_count:
|
||
return 1
|
||
|
||
# 遍历到第 fixed_count 个节点(固定参数的最后一个)
|
||
cur: llvmlite.Value | t.CPtr = head
|
||
prev: llvmlite.Value | t.CPtr = None
|
||
idx: int = 0
|
||
while cur is not None and idx < fixed_count:
|
||
prev = cur
|
||
cur = cur.Next
|
||
idx += 1
|
||
|
||
# cur 指向第 fixed_count+1 个节点(第一个变长参数)
|
||
# 对变长参数进行 C ABI 提升
|
||
i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
while cur is not None:
|
||
next_node: llvmlite.Value | t.CPtr = cur.Next
|
||
promoted: llvmlite.Value | t.CPtr = cur
|
||
# C ABI integer promotion: i8/i16 → i32
|
||
arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty)
|
||
if arg_bits != 0 and arg_bits < 32:
|
||
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
|
||
if promoted is not None:
|
||
promoted.Next = next_node
|
||
if prev is not None:
|
||
prev.Next = promoted
|
||
# C ABI float promotion: float → double
|
||
arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty)
|
||
if arg_fbits != 0 and arg_fbits < 64:
|
||
promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None)
|
||
if promoted is not None:
|
||
promoted.Next = next_node
|
||
if prev is not None:
|
||
prev.Next = promoted
|
||
prev = promoted
|
||
cur = next_node
|
||
|
||
return 1
|
||
|
||
def init_func_table(self, pool: memhub.MemBuddy | t.CPtr,
|
||
max_count: int) -> HandlesExprCall.FuncEntry | t.CPtr:
|
||
"""分配并清零函数表数组"""
|
||
size: t.CSizeT = max_count * HandlesExprCall.FuncEntry.__sizeof__()
|
||
funcs_ptr: HandlesExprCall.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(self, funcs: HandlesExprCall.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 = HandlesExprCall.FuncEntry.__sizeof__()
|
||
for i in range(func_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
|
||
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.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(self, funcs: HandlesExprCall.FuncEntry | t.CPtr,
|
||
func_count: int,
|
||
name: str,
|
||
func: llvmlite.Function | t.CPtr,
|
||
max_count: int,
|
||
defaults: t.CVoid | t.CPtr = None,
|
||
default_count: int = 0,
|
||
param_count: int = 0,
|
||
pool: memhub.MemBuddy | t.CPtr = None) -> int:
|
||
"""添加函数到函数表,返回 0 成功
|
||
|
||
Args:
|
||
defaults: ast.Arguments.defaults 列表节点指针,None=无默认值
|
||
default_count: 默认值数量(len(defaults))
|
||
param_count: 形参数量(不含 self,len(args.args))
|
||
pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象)
|
||
"""
|
||
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 = HandlesExprCall.FuncEntry.__sizeof__()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size
|
||
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
entry.Name = name
|
||
entry.Func = func
|
||
entry.Defaults = defaults
|
||
entry.DefaultCount = default_count
|
||
entry.ParamCount = param_count
|
||
# 同时注册到全局函数表(供跨模块 vtable 初始化查找)
|
||
self._register_global_func(name, func, pool)
|
||
# 同时注册到全局默认参数表(供跨模块调用时填充默认值)
|
||
if default_count > 0:
|
||
self._register_global_defaults(name, defaults, default_count, param_count)
|
||
return 0
|
||
|
||
def _init_global_func_table(self) -> int:
|
||
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)"""
|
||
if self.GlobalFuncs is not None:
|
||
return 1
|
||
size: t.CSizeT = GLOBAL_FUNC_MAX * HandlesExprCall.FuncEntry.__sizeof__()
|
||
self.GlobalFuncs = stdlib.malloc(size)
|
||
if self.GlobalFuncs is None:
|
||
return 0
|
||
string.memset(self.GlobalFuncs, 0, size)
|
||
self.GlobalFuncCount = 0
|
||
return 1
|
||
|
||
def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr,
|
||
func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr:
|
||
"""生成函数类型文本(stdlib 分配)"""
|
||
if func is None:
|
||
return None
|
||
# 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲
|
||
ty_buf: t.CChar | t.CPtr = pool.alloc(1024)
|
||
if ty_buf is None:
|
||
return None
|
||
ty_buf[0] = '\0'
|
||
|
||
# 返回类型
|
||
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
|
||
ret_part: t.CChar | t.CPtr = pool.alloc(512)
|
||
if ret_part is not None and ret_ty is not None:
|
||
ret_part[0] = '\0'
|
||
llvmlite.TypePrint(ret_part, 512, ret_ty, pool)
|
||
string.strcat(ty_buf, ret_part)
|
||
string.strcat(ty_buf, " (")
|
||
|
||
# 参数类型
|
||
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||
first: int = 1
|
||
param_part: t.CChar | t.CPtr = pool.alloc(512)
|
||
while cur is not None:
|
||
if first == 0:
|
||
string.strcat(ty_buf, ", ")
|
||
if param_part is not None:
|
||
param_part[0] = '\0'
|
||
param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur)
|
||
if param_ty is not None:
|
||
llvmlite.TypePrint(param_part, 512, param_ty, pool)
|
||
string.strcat(ty_buf, param_part)
|
||
cur = llvmlite.param_get_next(cur)
|
||
first = 0
|
||
string.strcat(ty_buf, ")")
|
||
|
||
# 深拷贝到 stdlib 区(TypeStr 跨文件永久存活)
|
||
ts_len: t.CSizeT = string.strlen(ty_buf)
|
||
ts_copy: t.CChar | t.CPtr = stdlib.malloc(ts_len + 1)
|
||
if ts_copy is None:
|
||
return None
|
||
string.strcpy(ts_copy, ty_buf)
|
||
return ts_copy
|
||
|
||
def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr = None) -> int:
|
||
"""注册函数到全局表(已存在则跳过),返回 0 成功
|
||
|
||
直接操作全局表,不调用 add_func_to_table,避免递归。
|
||
pool 用于生成 TypeStr(None 时 TypeStr 为空)。
|
||
"""
|
||
if name is None or func is None:
|
||
return 1
|
||
if self._init_global_func_table() == 0:
|
||
return 1
|
||
# 已存在则跳过(避免重复)
|
||
if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None:
|
||
return 0
|
||
if self.GlobalFuncCount >= GLOBAL_FUNC_MAX:
|
||
return 1
|
||
# 直接写入全局表(不调用 add_func_to_table,避免递归)
|
||
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + self.GlobalFuncCount * entry_size
|
||
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
# Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件
|
||
# reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃)
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
|
||
if name_copy is None:
|
||
return 1
|
||
string.strcpy(name_copy, name)
|
||
entry.Name = name_copy
|
||
entry.Func = func
|
||
# TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加,
|
||
# 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。
|
||
self.GlobalFuncCount += 1
|
||
return 0
|
||
|
||
def update_global_func_typestr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str,
|
||
func: llvmlite.Function | t.CPtr) -> int:
|
||
"""更新全局函数表的 TypeStr(在函数参数全部添加完成后调用)
|
||
|
||
调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。
|
||
生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝),
|
||
供 vtable 生成在 func 被 1b reset 后使用。
|
||
"""
|
||
if name is None or func is None:
|
||
return 1
|
||
entry: HandlesExprCall.FuncEntry | t.CPtr = self.find_func_entry_global(name)
|
||
if entry is None:
|
||
return 1
|
||
entry.TypeStr = self._build_func_type_str(pool, func)
|
||
return 0
|
||
|
||
def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr:
|
||
"""在全局函数表中按名称查找,返回 Function 指针或 None"""
|
||
if name is None or self.GlobalFuncs is None:
|
||
return None
|
||
return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name)
|
||
|
||
def find_func_entry_global(self, name: str) -> HandlesExprCall.FuncEntry | t.CPtr:
|
||
"""在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None"""
|
||
if name is None or self.GlobalFuncs is None:
|
||
return None
|
||
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
|
||
for i in range(self.GlobalFuncCount):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + i * entry_size
|
||
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
def _init_global_defaults_table(self) -> int:
|
||
"""初始化全局默认参数表"""
|
||
if self.GlobalDefaults is not None:
|
||
return 1
|
||
size: t.CSizeT = GLOBAL_DEFAULTS_MAX * HandlesExprCall.FuncDefaultsEntry.__sizeof__()
|
||
self.GlobalDefaults = stdlib.malloc(size)
|
||
if self.GlobalDefaults is None:
|
||
return 0
|
||
string.memset(self.GlobalDefaults, 0, size)
|
||
self.GlobalDefaultsCount = 0
|
||
return 1
|
||
|
||
def _register_global_defaults(self, name: str,
|
||
defaults: t.CVoid | t.CPtr,
|
||
default_count: int,
|
||
param_count: int) -> int:
|
||
"""注册函数默认参数到全局表,返回 0 成功
|
||
|
||
注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs),
|
||
跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。
|
||
"""
|
||
if name is None or defaults is None:
|
||
return 1
|
||
if self._init_global_defaults_table() == 0:
|
||
return 1
|
||
# 已存在则跳过
|
||
if self.find_func_defaults(name) is not None:
|
||
return 0
|
||
if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX:
|
||
return 1
|
||
entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__()
|
||
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size
|
||
entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
# Name 深拷贝到 stdlib(全局表跨文件永久存活)
|
||
nm_len: t.CSizeT = string.strlen(name)
|
||
nm_copy: t.CChar | t.CPtr = stdlib.malloc(nm_len + 1)
|
||
if nm_copy is None:
|
||
return 1
|
||
string.strcpy(nm_copy, name)
|
||
entry.Name = nm_copy
|
||
entry.Defaults = defaults
|
||
entry.DefaultCount = default_count
|
||
entry.ParamCount = param_count
|
||
# 提取常量快照到 stdlib
|
||
if default_count > 0:
|
||
kinds: t.CInt | t.CPtr = stdlib.malloc(default_count * 4)
|
||
ints: t.CInt64T | t.CPtr = stdlib.malloc(default_count * 8)
|
||
strs: t.CSizeT | t.CPtr = stdlib.malloc(default_count * 8)
|
||
if kinds is not None and ints is not None and strs is not None:
|
||
string.memset(kinds, 0, default_count * 4)
|
||
string.memset(ints, 0, default_count * 8)
|
||
string.memset(strs, 0, default_count * 8)
|
||
dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(defaults), t.CPtr))
|
||
di: int
|
||
for di in range(default_count):
|
||
dnode: ast.AST | t.CPtr = dl.get(di)
|
||
if dnode is not None and dnode.kind() == ast.ASTKind.Constant:
|
||
dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode)
|
||
kinds[di] = dcn.const_kind
|
||
ints[di] = dcn.int_val
|
||
if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None:
|
||
slen: t.CSizeT = string.strlen(dcn.str_val)
|
||
scopy: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
|
||
if scopy is not None:
|
||
string.strcpy(scopy, dcn.str_val)
|
||
strs[di] = t.CSizeT(scopy)
|
||
entry.ConstKinds = kinds
|
||
entry.ConstInts = ints
|
||
entry.ConstStrs = strs
|
||
self.GlobalDefaultsCount += 1
|
||
return 0
|
||
|
||
def find_func_defaults(self, name: str) -> HandlesExprCall.FuncDefaultsEntry | t.CPtr:
|
||
"""按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None"""
|
||
if name is None or self.GlobalDefaults is None:
|
||
return None
|
||
entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__()
|
||
i: int = 0
|
||
while i < self.GlobalDefaultsCount:
|
||
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + i * entry_size
|
||
entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
i += 1
|
||
return None
|
||
|
||
def _build_const_from_snapshot(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
gd_entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr,
|
||
di: int,
|
||
trans: HT.Translator | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""从快照重建第 di 个默认值常量 IR"""
|
||
if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None:
|
||
return None
|
||
if di < 0 or di >= gd_entry.DefaultCount:
|
||
return None
|
||
kind: t.CInt = gd_entry.ConstKinds[di]
|
||
ival: t.CInt64T = gd_entry.ConstInts[di]
|
||
if kind == ast.CONST_INT:
|
||
if ival > 2147483647 or ival < -2147483648:
|
||
return llvmlite.const_int64(pool, ival)
|
||
return llvmlite.const_int32(pool, ival)
|
||
elif kind == ast.CONST_BOOL:
|
||
if ival != 0:
|
||
return llvmlite.const_int32(pool, 1)
|
||
return llvmlite.const_int32(pool, 0)
|
||
elif kind == ast.CONST_NONE:
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
|
||
elif kind == ast.CONST_STR:
|
||
if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0:
|
||
sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr))
|
||
return HandlesExpr.create_global_string(builder, pool, mod, sv, trans)
|
||
# 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST
|
||
return None
|
||
|
||
def find_func_entry_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr,
|
||
func_count: int,
|
||
name: str) -> HandlesExprCall.FuncEntry | t.CPtr:
|
||
"""在函数表中按名称查找,返回完整 FuncEntry 或 None"""
|
||
if name is None or funcs is None:
|
||
return None
|
||
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
|
||
i: int = 0
|
||
while i < func_count:
|
||
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
|
||
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||
if entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
i += 1
|
||
return None
|
||
|
||
def NewExprCallHandle(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> HandlesExprCall.ExprCallHandle | t.CPtr:
|
||
h: HandlesExprCall.ExprCallHandle | t.CPtr = pool.alloc(HandlesExprCall.ExprCallHandle.__sizeof__())
|
||
if h is None:
|
||
return None
|
||
string.memset(h, 0, HandlesExprCall.ExprCallHandle.__sizeof__())
|
||
h.Trans = trans
|
||
return h
|