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
