refactor(gen): CallGenMixin 阶段 C 拆 translate_call 检测段(Dispatch 6 helper)+ 辅助方法(Lib),顶层降至 1119 行
This commit is contained in:
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
@@ -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)
|
||||
+38
-1908
File diff suppressed because it is too large.
Load diff
@@ -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,
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user