自举实验失败,C1 编译 Test 成功,暂未达到自举收敛点
This commit is contained in:
@@ -8,6 +8,7 @@ import stdio
|
||||
import stdlib
|
||||
import sys
|
||||
import viperlib
|
||||
import w32.fileio as fileio
|
||||
import lib.core.VLogger as VLogger
|
||||
import lib.core.Handles.HandlesBase as HandlesBase
|
||||
import lib.core.Handles.HandlesTranslator as HT
|
||||
@@ -2257,13 +2258,11 @@ def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr,
|
||||
"__before_init__", storage_ptr, None, 0, trans)
|
||||
|
||||
# 如果有 __init__,调用 __init__(ptr, args...)
|
||||
# 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断
|
||||
# (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference)
|
||||
has_init_flag: int = 0
|
||||
if ctor_entry is not None:
|
||||
has_init_flag = ctor_entry.HasInit
|
||||
# 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用)
|
||||
# 但 IsOOP=1 说明类有方法,推断 HasInit=1
|
||||
if is_oop != 0 and has_init_flag == 0:
|
||||
has_init_flag = 1
|
||||
if has_init_flag != 0:
|
||||
# 翻译构造函数参数
|
||||
arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
|
||||
@@ -2283,8 +2282,9 @@ def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
_call_method_on_ptr(pool, builder, mod, class_name,
|
||||
"__init__", storage_ptr, arg_vals, real_arg_count, trans)
|
||||
else:
|
||||
# 无 __init__:逐字段 store 参数值
|
||||
elif has_new_flag == 0:
|
||||
# 无 __init__ 且无 __new__:逐字段 store 参数值
|
||||
# (有 __new__ 时参数已由 __new__ 消费,不应存入字段)
|
||||
for ai in range(can):
|
||||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg is None:
|
||||
@@ -2974,6 +2974,262 @@ def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 与 _infer_external_func_ret_ty 的默认策略保持一致
|
||||
return llvmlite.Int32(pool)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 跨模块方法返回类型查找(从 text.ll)
|
||||
#
|
||||
# Phase A 翻译每个源文件后生成 text.ll,其中 define 行包含
|
||||
# 方法的实际返回类型。当 Phase A 翻译后续文件调用跨模块方法时,
|
||||
# _infer_method_ret_ty 默认返回 i32,导致指针返回值被截断。
|
||||
# _LookupMethodRetTyFromTextLL 读取依赖模块的 text.ll,从 define
|
||||
# 行提取实际返回类型,避免指针截断。
|
||||
# ============================================================
|
||||
|
||||
_g_temp_dir: str = None
|
||||
_g_temp_dir_len: t.CSizeT = 0
|
||||
|
||||
# text.ll 读取缓冲区大小
|
||||
_TEXT_LL_READ_BUF_SIZE: t.CDefine = 262144
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SetTempDir - 设置 temp 目录路径
|
||||
#
|
||||
# 在 Phase2.py 的 Phase A 翻译前调用,使 HandlesExprCall
|
||||
# 能够读取依赖模块的 text.ll 文件。
|
||||
# ============================================================
|
||||
def SetTempDir(temp_dir: str):
|
||||
"""设置 temp 目录路径(供跨模块方法返回类型查找使用)"""
|
||||
global _g_temp_dir
|
||||
global _g_temp_dir_len
|
||||
_g_temp_dir = temp_dir
|
||||
if temp_dir is not None:
|
||||
_g_temp_dir_len = string.strlen(temp_dir)
|
||||
else:
|
||||
_g_temp_dir_len = 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType
|
||||
#
|
||||
# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容),
|
||||
# 转换为 llvmlite.LLVMType 对象。
|
||||
#
|
||||
# 支持的类型:
|
||||
# void → Void
|
||||
# i8/i16/i32/i64 → Int8/Int16/Int32/Int64
|
||||
# double → Double, float → Float
|
||||
# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址)
|
||||
#
|
||||
# Args:
|
||||
# pool: 内存池
|
||||
# buf: 包含类型字符串的缓冲区
|
||||
# start: 类型字符串起始位置
|
||||
# end: 类型字符串结束位置(不含)
|
||||
#
|
||||
# Returns:
|
||||
# LLVM 类型对象,或 None(无法解析)
|
||||
# ============================================================
|
||||
def _ParseLLVMRetTyStr(pool: memhub.MemBuddy | t.CPtr,
|
||||
buf: bytes,
|
||||
start: t.CSizeT,
|
||||
end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType"""
|
||||
if pool is None or buf is None or start >= end:
|
||||
return None
|
||||
|
||||
# 去除前导空白
|
||||
s: t.CSizeT = start
|
||||
while s < end:
|
||||
c: int = buf[s]
|
||||
if c != ' ' and c != '\t':
|
||||
break
|
||||
s += 1
|
||||
# 去除尾部空白
|
||||
e: t.CSizeT = end
|
||||
while e > s:
|
||||
c2: int = buf[e - 1]
|
||||
if c2 != ' ' and c2 != '\t':
|
||||
break
|
||||
e -= 1
|
||||
|
||||
ty_len: t.CSizeT = e - s
|
||||
if ty_len == 0:
|
||||
return None
|
||||
|
||||
# 检查是否含 * (指针类型) → 返回 i8* (通用指针)
|
||||
# 包括 i8*, i32*, %"name"*, { i32, i8 }* 等
|
||||
ci: t.CSizeT = s
|
||||
while ci < e:
|
||||
if buf[ci] == '*':
|
||||
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
ci += 1
|
||||
|
||||
# void
|
||||
if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0:
|
||||
return llvmlite.Void(pool)
|
||||
|
||||
# double
|
||||
if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0:
|
||||
return llvmlite.Double(pool)
|
||||
|
||||
# float
|
||||
if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0:
|
||||
return llvmlite.Float(pool)
|
||||
|
||||
# iN (i8, i16, i32, i64)
|
||||
if ty_len >= 2 and buf[s] == 'i':
|
||||
bits: int = 0
|
||||
di: t.CSizeT = s + 1
|
||||
valid: int = 1
|
||||
while di < e:
|
||||
d: int = buf[di]
|
||||
if d >= '0' and d <= '9':
|
||||
bits = bits * 10 + (d - '0')
|
||||
else:
|
||||
valid = 0
|
||||
break
|
||||
di += 1
|
||||
if valid != 0 and bits > 0:
|
||||
if bits == 8:
|
||||
return llvmlite.Int8(pool)
|
||||
if bits == 16:
|
||||
return llvmlite.Int16(pool)
|
||||
if bits == 32:
|
||||
return llvmlite.Int32(pool)
|
||||
if bits == 64:
|
||||
return llvmlite.Int64(pool)
|
||||
|
||||
# 无法解析
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型
|
||||
#
|
||||
# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索
|
||||
# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数,
|
||||
# 提取返回类型并转换为 llvmlite.LLVMType。
|
||||
#
|
||||
# 解决问题: _infer_method_ret_ty 默认返回 i32,导致指针返回值
|
||||
# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。
|
||||
# 本函数从 text.ll 获取实际返回类型,避免截断。
|
||||
#
|
||||
# Args:
|
||||
# pool: 内存池
|
||||
# class_sha1: 类所属模块的 SHA1
|
||||
# class_name: 类名
|
||||
# method_name: 方法名
|
||||
#
|
||||
# Returns:
|
||||
# LLVM 类型对象,或 None(未找到/text.ll 不存在)
|
||||
# ============================================================
|
||||
def _LookupMethodRetTyFromTextLL(pool: memhub.MemBuddy | t.CPtr,
|
||||
class_sha1: str,
|
||||
class_name: str,
|
||||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""从依赖模块的 text.ll 中查找方法返回类型"""
|
||||
if pool is None or class_sha1 is None or class_name is None or method_name is None:
|
||||
return None
|
||||
if _g_temp_dir is None or _g_temp_dir_len == 0:
|
||||
return None
|
||||
|
||||
sha1_len: t.CSizeT = string.strlen(class_sha1)
|
||||
if sha1_len < 2:
|
||||
return None
|
||||
|
||||
# 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll
|
||||
# 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致)
|
||||
path_len: t.CSizeT = _g_temp_dir_len + sha1_len + 14
|
||||
path_buf: bytes = stdlib.malloc(path_len)
|
||||
if path_buf is None:
|
||||
return None
|
||||
subdir_buf: bytes = stdlib.malloc(3)
|
||||
if subdir_buf is None:
|
||||
stdlib.free(path_buf)
|
||||
return None
|
||||
subdir_buf[0] = class_sha1[0]
|
||||
subdir_buf[1] = class_sha1[1]
|
||||
subdir_buf[2] = '\0'
|
||||
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
|
||||
_g_temp_dir, subdir_buf, class_sha1)
|
||||
stdlib.free(subdir_buf)
|
||||
|
||||
# 读取 text.ll
|
||||
read_buf: bytes = stdlib.malloc(_TEXT_LL_READ_BUF_SIZE)
|
||||
if read_buf is None:
|
||||
stdlib.free(path_buf)
|
||||
return None
|
||||
|
||||
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||||
if tf.closed:
|
||||
stdlib.free(path_buf)
|
||||
stdlib.free(read_buf)
|
||||
return None
|
||||
text_len: t.CInt64T = tf.read_all(read_buf, _TEXT_LL_READ_BUF_SIZE)
|
||||
tf.close()
|
||||
stdlib.free(path_buf)
|
||||
|
||||
if text_len <= 0:
|
||||
stdlib.free(read_buf)
|
||||
return None
|
||||
if text_len < _TEXT_LL_READ_BUF_SIZE:
|
||||
read_buf[text_len] = '\0'
|
||||
else:
|
||||
read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0'
|
||||
|
||||
# 构造搜索模式: "{sha1}.{class_name}.{method_name}"
|
||||
cls_len: t.CSizeT = string.strlen(class_name)
|
||||
meth_len: t.CSizeT = string.strlen(method_name)
|
||||
search_len: t.CSizeT = sha1_len + cls_len + meth_len + 3
|
||||
search_buf: bytes = stdlib.malloc(search_len)
|
||||
if search_buf is None:
|
||||
stdlib.free(read_buf)
|
||||
return None
|
||||
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
|
||||
class_sha1, class_name, method_name)
|
||||
search_str_len: t.CSizeT = string.strlen(search_buf)
|
||||
|
||||
# 在 text.ll 中搜索 define 行包含 search_buf
|
||||
buf_len: t.CSizeT = string.strlen(read_buf)
|
||||
pos: t.CSizeT = 0
|
||||
result_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
|
||||
while pos < buf_len and result_ty is None:
|
||||
ls: t.CSizeT = pos
|
||||
le: t.CSizeT = pos
|
||||
while le < buf_len:
|
||||
if read_buf[le] == '\n':
|
||||
break
|
||||
le += 1
|
||||
ll: t.CSizeT = le - ls
|
||||
|
||||
# 检查是否是 define 行
|
||||
if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0:
|
||||
# 找 @ 符号
|
||||
at_pos: t.CSizeT = ls + 7
|
||||
while at_pos < ls + ll:
|
||||
if read_buf[at_pos] == '@':
|
||||
break
|
||||
at_pos += 1
|
||||
if at_pos < ls + ll:
|
||||
# 跳过可选引号
|
||||
name_start: t.CSizeT = at_pos + 1
|
||||
if name_start < ls + ll and read_buf[name_start] == '"':
|
||||
name_start += 1
|
||||
# 检查是否匹配 search_buf
|
||||
if name_start + search_str_len <= ls + ll:
|
||||
if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0:
|
||||
# 匹配!提取返回类型: [ls+7, at_pos)
|
||||
result_ty = _ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
|
||||
|
||||
pos = le + 1
|
||||
|
||||
stdlib.free(search_buf)
|
||||
stdlib.free(read_buf)
|
||||
return result_ty
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _translate_method_call - 翻译方法调用 obj.method(args)
|
||||
#
|
||||
@@ -3069,8 +3325,14 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
if frt is not None:
|
||||
call_ret_ty = frt
|
||||
else:
|
||||
# found_func 为 None(stub 未注入):根据方法名推断返回类型
|
||||
call_ret_ty = _infer_method_ret_ty(pool, method_name)
|
||||
# found_func 为 None(stub 未注入):尝试从 text.ll 查找实际返回类型
|
||||
# 避免指针返回值被 _infer_method_ret_ty 默认为 i32 导致 inttoptr 截断
|
||||
looked_up_ty: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
|
||||
pool, cls_sha1_mc, class_name, method_name)
|
||||
if looked_up_ty is not None:
|
||||
call_ret_ty = looked_up_ty
|
||||
else:
|
||||
call_ret_ty = _infer_method_ret_ty(pool, method_name)
|
||||
|
||||
# 翻译调用参数
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
@@ -3521,6 +3783,9 @@ def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr,
|
||||
# - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*)
|
||||
# - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8)
|
||||
# - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*)
|
||||
# - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double)
|
||||
# - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32)
|
||||
# - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float)
|
||||
# ============================================================
|
||||
def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
@@ -3532,6 +3797,8 @@ def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
|
||||
target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty)
|
||||
val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty)
|
||||
target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty)
|
||||
|
||||
# 整数 → 整数: trunc/zext
|
||||
if val_bits != 0 and target_bits != 0:
|
||||
@@ -3542,12 +3809,29 @@ def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr,
|
||||
else:
|
||||
return llvmlite.build_trunc(builder, val, target_ty)
|
||||
|
||||
# 整数 → 浮点: sitofp
|
||||
if val_bits != 0 and target_fbits != 0:
|
||||
return llvmlite.build_si2fp(builder, val, target_ty)
|
||||
|
||||
# 浮点 → 整数: fptosi
|
||||
if val_fbits != 0 and target_bits != 0:
|
||||
return llvmlite.build_fp2si(builder, val, target_ty)
|
||||
|
||||
# 浮点 → 浮点: fpext/fptrunc
|
||||
if val_fbits != 0 and target_fbits != 0:
|
||||
if val_fbits == target_fbits:
|
||||
return val
|
||||
elif val_fbits < target_fbits:
|
||||
return llvmlite.build_fpext(builder, val, target_ty)
|
||||
else:
|
||||
return llvmlite.build_fptrunc(builder, val, target_ty)
|
||||
|
||||
# 指针 → 整数: ptrtoint
|
||||
if val_bits == 0 and target_bits != 0:
|
||||
if val_bits == 0 and val_fbits == 0 and target_bits != 0:
|
||||
return llvmlite.build_ptrtoint(builder, val, target_ty)
|
||||
|
||||
# 整数 → 指针: inttoptr
|
||||
if val_bits != 0 and target_bits == 0:
|
||||
# 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0)
|
||||
if val_bits != 0 and target_bits == 0 and target_fbits == 0:
|
||||
return llvmlite.build_inttoptr(builder, val, target_ty)
|
||||
|
||||
# 指针 → 指针: bitcast
|
||||
@@ -3763,6 +4047,28 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
if cargs is not None:
|
||||
can = cargs.__len__()
|
||||
|
||||
# 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32
|
||||
# 等价于 (t.CChar | t.CPtr)(x) / (t.CInt32T)(x)
|
||||
# 单参数:str(val) → bitcast val to i8*
|
||||
# int(val) → trunc/sext val to i32
|
||||
if func_name is not None and can == 1:
|
||||
if string.strcmp(func_name, "str") == 0 or string.strcmp(func_name, "bytes") == 0:
|
||||
# str(x) / bytes(x) → i8* (bitcast)
|
||||
cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
if cast_arg is not None:
|
||||
i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
return _translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin)
|
||||
return None
|
||||
elif string.strcmp(func_name, "int") == 0:
|
||||
# int(x) → i32
|
||||
cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans)
|
||||
if cast_arg_int is not None:
|
||||
i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
return _translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin)
|
||||
return None
|
||||
|
||||
# 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等
|
||||
# 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用)
|
||||
# 支持:
|
||||
@@ -3805,6 +4111,19 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
# t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL
|
||||
return None
|
||||
|
||||
# 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等
|
||||
# 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换
|
||||
# map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等)
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||||
bare_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name)
|
||||
if bare_ty is not None and can == 1:
|
||||
bare_arg_node: ast.AST | t.CPtr = cargs.get(0)
|
||||
if bare_arg_node is not None:
|
||||
bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
builder, pool, mod, bare_arg_node, None, 0, trans)
|
||||
if bare_arg_val is not None:
|
||||
return _translate_t_type_cast(pool, builder, bare_arg_val, bare_ty)
|
||||
|
||||
# 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64)
|
||||
# __sizeof__ 是内置方法,不走跨模块调用路径
|
||||
# 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__()
|
||||
@@ -3907,11 +4226,6 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针,
|
||||
# 导致 llc 报错 "base of getelementptr must be a pointer"
|
||||
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
|
||||
# 诊断: 输出节点类型信息帮助定位根本原因
|
||||
len_node_kind: int = len_at.value.kind()
|
||||
stdio.printf(
|
||||
"[LEN-DIAG] __len__ on non-ptr (kind=%d), fallback to 0\n",
|
||||
len_node_kind)
|
||||
return llvmlite.const_int64(pool, 0)
|
||||
i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||||
# 注意: 必须用 const_int64 而非 ConstInt(...,"0")
|
||||
@@ -4049,7 +4363,10 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
|
||||
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)
|
||||
ret_ty3: llvmlite.LLVMType | t.CPtr = _LookupMethodRetTyFromTextLL(
|
||||
pool, sha1_fc, cls_nm2, func_name)
|
||||
if ret_ty3 is None:
|
||||
ret_ty3 = _infer_method_ret_ty(pool, func_name)
|
||||
_ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3)
|
||||
return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user