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