refactor(gen): CallGenMixin 阶段 C 拆 translate_call 检测段(Dispatch 6 helper)+ 辅助方法(Lib),顶层降至 1119 行

This commit is contained in:
TermiNexus committed 2026-08-17 06:59:14 +08:00
1 parent 38e32fdeb1
commit 9f19bb3666
5 files changed
+2164 -1908

No files matched your search

File diff suppressed because it is too large. Load diff
+578
View File
@@ -0,0 +1,578 @@
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.Handles.HandlesFunctions as HandlesFunctions
import lib.core.StubMerger as StubMerger
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Gen.CallGenBase as CallGenBase
# ============================================================
# CallGenLib - CallGenMixin 拆分(阶段 C):C 库声明 / 返回类型推断 /
# 变长参数 / memcpy / kwargs 调用辅助方法
#
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
# @t.NoVTable:静态绑定。
# ============================================================
@t.NoVTable
class CallGenLib(CallGenBase.CallGenBase):
"""C 库声明 / 返回类型推断 / kwargs 调用辅助(继承 Base)"""
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
# GetCommandLineA/W 返回 LPSTR(i8*):缺则 64 位指针被截成 i32 →
# inttoptr 后 strlen 读到无效地址(SysLibTest argv 段 ASAN 崩溃,
# 非 ASAN 环境随机表现:IDE 0xC0000005 / 部分环境侥幸可读)。
if string.strcmp(func_name, "GetCommandLineA") == 0:
return i8_ptr_ty
if string.strcmp(func_name, "GetCommandLineW") == 0:
return i8_ptr_ty
# gethostbyname 返回 hostent*(i8*)
if string.strcmp(func_name, "gethostbyname") == 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 会被截断
# --nowarn-register 可抑制此 WARN(自举编译中大量出现,刷屏影响日志收敛)
if VLogger.nowarn_register() == 0:
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 = len(win32_apis)
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 _is_sha1_mangled_call(self, call_name: str) -> int:
"""判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式)
C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0,
不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。
"""
if call_name is None:
return 0
first_dot: str = string.strchr(call_name, '.')
if first_dot is None:
return 0
pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name))
if pre_len != 16:
return 0
for hx in range(16):
ch: int = call_name[hx]
if ch < 48 or ch > 57:
if ch < 97 or ch > 102:
if ch < 65 or ch > 70:
return 0
return 1
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
# ============================================================
# _translate_call_with_kwargs — 带关键字参数的函数调用
#
# 支持两种语法:
# add(b=4, a=3) — 全关键字乱序
# greet("Hello", name="World") — 位置 + 关键字混合
#
# 策略: 遍历 found_func.Params 链表,对每个参数:
# 1. 若位置参数仍有剩余(param_idx < can),取位置参数
# 2. 否则按参数名匹配关键字参数
# 3. 按参数顺序构建调用参数链表
# ============================================================
# ============================================================
# _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: str = 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 HandlesExprCall._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: str = 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)
File diff suppressed because it is too large. Load diff
+3
View File
@@ -16,6 +16,8 @@ import lib.core.Gen.CallGenProp as CallGenProp
import lib.core.Gen.CallGenFd as CallGenFd
import lib.core.Gen.CallGenVt as CallGenVt
import lib.core.Gen.CallGenVa as CallGenVa
import lib.core.Gen.CallGenLib as CallGenLib
import lib.core.Gen.CallGenDispatch as CallGenDispatch
import lib.core.Gen.FuncGenMixin as FuncGenMixin
import lib.core.Gen.ClassGenMixin as ClassGenMixin
import lib.core.Gen.ImportsGenMixin as ImportsGenMixin
@@ -47,6 +49,7 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
CallGenCtor.CallGenCtor, CallGenCall.CallGenCall,
CallGenProp.CallGenProp, CallGenFd.CallGenFd,
CallGenVt.CallGenVt, CallGenVa.CallGenVa,
CallGenLib.CallGenLib, CallGenDispatch.CallGenDispatch,
FuncGenMixin.FuncGenMixin,
ClassGenMixin.ClassGenMixin, ImportsGenMixin.ImportsGenMixin,
StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin,
+112
View File
@@ -1869,3 +1869,115 @@ def _translate_super_call(pool: memhub.MemBuddy | t.CPtr,
if g is not None:
return g._translate_super_call(pool, builder, mod, cl, method_name, trans)
return None
# ============================================================
# translate_call 前置检测 helper(阶段 C:CallGenMixin 拆分后顶层经委托
# 调用 CallGenDispatch 方法。每个返回 Value|CPtr,None = 未命中继续主路径)
# ============================================================
def _tc_h1_super_ctraits(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""super()/ctraits 编译期检测(委托到 gen._tc_h1_super_ctraits)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._tc_h1_super_ctraits(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can)
return None
def _tc_h2_c_special(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""c.Deref/Asm/LLVMIR 等特殊调用(委托到 gen._tc_h2_c_special)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._tc_h2_c_special(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can)
return None
def _tc_h3_stdarg_cast(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""stdarg 糖 + str/int/bool 内置强转(委托到 gen._tc_h3_stdarg_cast)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._tc_h3_stdarg_cast(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can)
return None
def _tc_h4_type_casts(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""t.XXX / typedef 类型转换(委托到 gen._tc_h4_type_casts)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._tc_h4_type_casts(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can)
return None
def _tc_h5_sizeof_len_isinst(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""__sizeof__/len/isinstance 内置(委托到 gen._tc_h5_sizeof_len_isinst)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._tc_h5_sizeof_len_isinst(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can)
return None
def _tc_h6_method_dispatch(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""静态类/方法调用/表达式接收者/self.field/list 内置(委托到 gen._tc_h6_method_dispatch)"""
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._tc_h6_method_dispatch(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can)
return None