自举实验失败,C1 编译 Test 成功,暂未达到自举收敛点
This commit is contained in:
@@ -420,7 +420,14 @@ def _infer_elem_type_from_value(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 依次尝试 "pool", "_mbuddy", "mbuddy", "mb"
|
||||
# ============================================================
|
||||
def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""查找上下文中的 pool 变量,返回 alloca 或 None"""
|
||||
"""查找上下文中的 pool 变量,返回 alloca 或 None
|
||||
|
||||
查找顺序: pool → _mbuddy → mbuddy → mb
|
||||
兜底: 若都未找到,注册外部全局 @_mbuddy (i8*) 供函数内动态 list 创建使用。
|
||||
注意: 模块级 t.CArray 初始化不走此路径(由 _init_global_array_from_list 处理),
|
||||
此兜底仅用于函数内的动态 list 字面量(如 op=[...])。
|
||||
@_mbuddy 由入口模块(如 Phase2.py)定义并初始化,其他模块以 external 引用。
|
||||
"""
|
||||
if trans is None:
|
||||
return None
|
||||
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, "pool")
|
||||
@@ -435,7 +442,32 @@ def _find_pool_var(trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
alloca = HandlesVar.lookup_var(trans.SymTab, "mb")
|
||||
if alloca is not None:
|
||||
return alloca
|
||||
return None
|
||||
# 兜底: 创建外部全局 @_mbuddy 引用(i8** 类型)
|
||||
# 仅用于函数内动态 list 字面量,@_mbuddy 由入口模块定义并初始化
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
if pool is None or trans.Module is None or trans.SymTab is None:
|
||||
return None
|
||||
# 先检查是否已注册到模块作用域(避免重复创建全局变量)
|
||||
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(trans.SymTab, "_mbuddy")
|
||||
if existing is not None:
|
||||
return existing
|
||||
# 创建 i8* 类型(t.CVoid | t.CPtr = i8*)
|
||||
i8_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_fb)
|
||||
# 创建外部全局 @_mbuddy(external linkage,无初始值)
|
||||
gv_ext: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, "_mbuddy", i8_ptr_ty_fb)
|
||||
if gv_ext is not None:
|
||||
gv_ext.Linkage = "external"
|
||||
llvmlite.module_add_global(trans.Module, gv_ext)
|
||||
# 创建 Value 引用(@_mbuddy, 类型为 i8**)
|
||||
i8_ptr_ptr_ty_fb: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty_fb)
|
||||
ref_name_fb: t.CChar | t.CPtr = pool.alloc(16)
|
||||
if ref_name_fb is not None:
|
||||
string.strcpy(ref_name_fb, "@_mbuddy")
|
||||
gv_ref_fb: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, i8_ptr_ptr_ty_fb, ref_name_fb)
|
||||
# 注册到模块作用域,避免重复创建
|
||||
HandlesVar.define_module_var(trans.SymTab, "_mbuddy", gv_ref_fb)
|
||||
return gv_ref_fb
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -781,15 +813,32 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
comparators: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
|
||||
if comparators is None or comparators.__len__() == 0:
|
||||
return None
|
||||
rhs_node: ast.AST | t.CPtr = comparators.get(0)
|
||||
rhs: llvmlite.Value | t.CPtr = translate_value(
|
||||
builder, pool, mod, comparators.get(0), None, 0, trans)
|
||||
builder, pool, mod, rhs_node, None, 0, trans)
|
||||
if rhs is None:
|
||||
return None
|
||||
|
||||
# === None 比较优化: x == None / x != None 走身份比较(icmp eq/ne null)===
|
||||
# 避免对结构体指针生成无效的 __eq__/__ne__ 调用(方法未定义但类有 SHA1 时
|
||||
# try_operator_overload 会误生成 call void @...__eq__(...) 导致链接错误)
|
||||
# 语义依据: Python 中 == None / != None 默认走身份比较,不调用 __eq__/__ne__
|
||||
lhs_node: ast.AST | t.CPtr = cmp.left
|
||||
cmp_with_none: int = 0
|
||||
if op == ast.OpKind.Eq or op == ast.OpKind.Ne:
|
||||
if rhs_node is not None and rhs_node.kind() == ast.ASTKind.Constant:
|
||||
rhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(rhs_node)
|
||||
if rhs_cn is not None and rhs_cn.const_kind == ast.CONST_NONE:
|
||||
cmp_with_none = 1
|
||||
if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Constant:
|
||||
lhs_cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(lhs_node)
|
||||
if lhs_cn is not None and lhs_cn.const_kind == ast.CONST_NONE:
|
||||
cmp_with_none = 1
|
||||
|
||||
# === 比较运算符重载路径 1: lhs 是 Name 且对应结构体变量 ===
|
||||
# 对于值类型变量(如 cnt: Counter),用 alloca 指针尝试重载
|
||||
lhs_node: ast.AST | t.CPtr = cmp.left
|
||||
if lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
|
||||
# None 比较跳过重载(走身份比较)
|
||||
if cmp_with_none == 0 and lhs_node is not None and lhs_node.kind() == ast.ASTKind.Name and trans is not None:
|
||||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(lhs_node)
|
||||
if nm is not None and nm.id is not None:
|
||||
lhs_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
|
||||
@@ -808,10 +857,12 @@ def translate_compare(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
|
||||
# === 比较运算符重载路径 2: lhs 是 Ptr(Struct) ===
|
||||
# Is/IsNot 不在 _cmpop_to_dunder 映射中,会自动返回 None 回退原生比较
|
||||
ovl_result2: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload(
|
||||
pool, builder, mod, lhs, rhs, op, trans, 1)
|
||||
if ovl_result2 is not None:
|
||||
return ovl_result2
|
||||
# None 比较跳过重载(走身份比较)
|
||||
if cmp_with_none == 0:
|
||||
ovl_result2: llvmlite.Value | t.CPtr = HandlesExprOps.try_operator_overload(
|
||||
pool, builder, mod, lhs, rhs, op, trans, 1)
|
||||
if ovl_result2 is not None:
|
||||
return ovl_result2
|
||||
|
||||
predicate: int = llvmlite.ICMP_SLT
|
||||
if op == ast.OpKind.Lt:
|
||||
@@ -875,8 +926,12 @@ def translate_unaryop(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
return None
|
||||
|
||||
if uo.op == ast.OpKind.USub:
|
||||
# -x = 0 - x
|
||||
# 根据 operand 类型选择零值常量(避免 i32 与 i64 类型不匹配)
|
||||
# -x
|
||||
# 浮点类型用 fneg(直接生成 fneg 指令,避免 0.0 - x 的类型不匹配)
|
||||
operand_fbits: int = get_llvm_float_bits(operand.Ty)
|
||||
if operand_fbits > 0:
|
||||
return llvmlite.build_fneg(builder, operand)
|
||||
# 整数类型:-x = 0 - x,根据位宽选择零值常量(避免 i32 与 i64 类型不匹配)
|
||||
operand_bits: int = get_llvm_type_bits(operand.Ty)
|
||||
zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||||
if operand_bits == 64:
|
||||
@@ -1115,29 +1170,73 @@ def _build_source_path_from_sha1(sha1: str) -> str:
|
||||
# ============================================================
|
||||
def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str,
|
||||
from_imports: str) -> int:
|
||||
"""跨模块查找 CDefine 常量,返回值或 -1(未找到)"""
|
||||
if name is None or from_imports is None:
|
||||
stdio.printf("[XMCD] FAIL name=%s reason=from_imports_is_none\n", name)
|
||||
from_imports: str,
|
||||
imported_modules: str = None) -> int:
|
||||
"""跨模块查找 CDefine 常量,返回值或 -1(未找到)
|
||||
|
||||
查找顺序:
|
||||
1. from_imports 精确匹配(from X import NAME)
|
||||
2. from_imports star 回退(from X import *)
|
||||
3. imported_modules 遍历(import X):当通过 import X 导入模块时,
|
||||
模块中定义的 CDefine 常量可通过此路径找到(如方法签名默认参数引用)
|
||||
"""
|
||||
if name is None:
|
||||
return -1
|
||||
if from_imports is None:
|
||||
from_imports = ""
|
||||
|
||||
# 1. 从 from_imports 查找名称对应的模块名
|
||||
# 先尝试精确匹配(allow_star_fallback=0),避免 CDefine 常量被 star import 误导
|
||||
mod_name_raw: str = HandlesImports.lookup_from_import(from_imports, name, 0)
|
||||
if mod_name_raw is None:
|
||||
# 精确匹配失败:尝试 star import 回退
|
||||
# CDefine 常量(如 INVALID_HANDLE_VALUE)通过 from w32.win32base import * 导入,
|
||||
# 不会作为精确条目出现在 from_imports 中,而是作为 *:w32.win32base 条目。
|
||||
mod_name_raw = HandlesImports.lookup_from_import(from_imports, name, 1)
|
||||
if mod_name_raw is None:
|
||||
stdio.printf("[XMCD] FAIL name=%s reason=lookup_from_import_returned_none\n", name)
|
||||
|
||||
# 2. from_imports 查找失败:直接回退到 imported_modules 遍历(步骤 9.6)
|
||||
# 注意:star fallback 可能返回错误模块(如 stdint),常量实际不在其中,
|
||||
# 步骤 9.6 会在该模块查找失败后继续遍历 imported_modules
|
||||
if mod_name_raw is None:
|
||||
# from_imports 完全没有匹配(精确和 star 都失败)
|
||||
# 直接进入 imported_modules 遍历(步骤 9.6)
|
||||
if imported_modules is None:
|
||||
return -1
|
||||
stdio.printf("[XMCD] star_fallback name=%s mod=%s\n", name, mod_name_raw)
|
||||
# 打印 from_imports 用于诊断精确匹配失败原因
|
||||
fi_len: t.CSizeT = string.strlen(from_imports)
|
||||
stdio.printf("[XMCD] from_imports (len=%d): %s\n", fi_len, from_imports)
|
||||
else:
|
||||
stdio.printf("[XMCD] exact_match name=%s mod=%s\n", name, mod_name_raw)
|
||||
# 跳过 from_imports 模块读取,直接走步骤 9.6 的 imported_modules 遍历
|
||||
# 设置 result_found=0 跳过步骤 3-9,直接到 9.6
|
||||
HandlesType.set_cdefine_found(0)
|
||||
# 直接遍历 imported_modules
|
||||
im_len: t.CSizeT = string.strlen(imported_modules)
|
||||
im_ci: t.CSizeT = 0
|
||||
while im_ci < im_len:
|
||||
while im_ci < im_len and imported_modules[im_ci] == ' ':
|
||||
im_ci += 1
|
||||
if im_ci >= im_len:
|
||||
break
|
||||
im_start: t.CSizeT = im_ci
|
||||
while im_ci < im_len and imported_modules[im_ci] != ' ':
|
||||
im_ci += 1
|
||||
im_end: t.CSizeT = im_ci
|
||||
im_nlen: t.CSizeT = im_end - im_start
|
||||
if im_nlen > 0 and im_nlen < 256:
|
||||
im_buf: str = pool.alloc(im_nlen + 1)
|
||||
if im_buf is not None:
|
||||
mk: t.CSizeT = 0
|
||||
while mk < im_nlen:
|
||||
im_buf[mk] = imported_modules[im_start + mk]
|
||||
mk += 1
|
||||
im_buf[im_nlen] = '\0'
|
||||
sub_fi: str = pool.alloc(im_nlen + 3)
|
||||
if sub_fi is not None:
|
||||
sub_fi[0] = '*'
|
||||
sub_fi[1] = ':'
|
||||
mk2: t.CSizeT = 0
|
||||
while mk2 < im_nlen:
|
||||
sub_fi[2 + mk2] = im_buf[mk2]
|
||||
mk2 += 1
|
||||
sub_fi[2 + im_nlen] = '\0'
|
||||
sub_val: int = _lookup_cross_module_cdefine(pool, name, sub_fi, None)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
return sub_val
|
||||
return -1
|
||||
|
||||
# 2. 复制模块名到新缓冲区(lookup_from_import 返回的是内部指针)
|
||||
# 截断于空格、null、或 ':'(别名格式的分隔符)
|
||||
@@ -1161,7 +1260,6 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
if sha1 is None:
|
||||
sha1 = HandlesExprCall._lookup_module_sha1_suffix(base_mod)
|
||||
if sha1 is None:
|
||||
stdio.printf("[XMCD] FAIL name=%s base_mod=%s reason=sha1_not_found\n", name, base_mod)
|
||||
return -1
|
||||
|
||||
# 5. 获取 temp_dir
|
||||
@@ -1529,6 +1627,45 @@ def _lookup_cross_module_cdefine(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
stdlib.free(pyi_buf)
|
||||
|
||||
# 9.6 from_imports star fallback 模块中未找到:回退到 imported_modules 遍历
|
||||
# 当 `from stdint import *` 导致 star fallback 返回 stdint,但目标常量
|
||||
# (如 SHARE_READ)实际在 `import w32.fileio` 导入的模块中时,
|
||||
# 需要遍历 imported_modules 逐个查找
|
||||
if result_found == 0 and imported_modules is not None:
|
||||
im2_len: t.CSizeT = string.strlen(imported_modules)
|
||||
im2_ci: t.CSizeT = 0
|
||||
while im2_ci < im2_len and result_found == 0:
|
||||
while im2_ci < im2_len and imported_modules[im2_ci] == ' ':
|
||||
im2_ci += 1
|
||||
if im2_ci >= im2_len:
|
||||
break
|
||||
im2_start: t.CSizeT = im2_ci
|
||||
while im2_ci < im2_len and imported_modules[im2_ci] != ' ':
|
||||
im2_ci += 1
|
||||
im2_end: t.CSizeT = im2_ci
|
||||
im2_nlen: t.CSizeT = im2_end - im2_start
|
||||
if im2_nlen > 0 and im2_nlen < 256:
|
||||
im2_buf: str = pool.alloc(im2_nlen + 1)
|
||||
if im2_buf is not None:
|
||||
mk3: t.CSizeT = 0
|
||||
while mk3 < im2_nlen:
|
||||
im2_buf[mk3] = imported_modules[im2_start + mk3]
|
||||
mk3 += 1
|
||||
im2_buf[im2_nlen] = '\0'
|
||||
sub_fi2: str = pool.alloc(im2_nlen + 3)
|
||||
if sub_fi2 is not None:
|
||||
sub_fi2[0] = '*'
|
||||
sub_fi2[1] = ':'
|
||||
mk4: t.CSizeT = 0
|
||||
while mk4 < im2_nlen:
|
||||
sub_fi2[2 + mk4] = im2_buf[mk4]
|
||||
mk4 += 1
|
||||
sub_fi2[2 + im2_nlen] = '\0'
|
||||
sub_val2: int = _lookup_cross_module_cdefine(pool, name, sub_fi2, None)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
result_val = sub_val2
|
||||
result_found = 1
|
||||
|
||||
# 10. 缓存到当前模块的 CDefine 表中
|
||||
if result_found != 0:
|
||||
HandlesType.register_cdefine_constant(pool, name, result_val)
|
||||
@@ -1592,8 +1729,9 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
# 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找,
|
||||
# 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗
|
||||
if _is_cdefine_name_pattern(nm_id) != 0:
|
||||
if trans is not None and trans._from_imports is not None:
|
||||
cdef_val = _lookup_cross_module_cdefine(pool, nm_id, trans._from_imports)
|
||||
if trans is not None:
|
||||
cdef_val = _lookup_cross_module_cdefine(
|
||||
pool, nm_id, trans._from_imports, trans._imported_modules)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
return llvmlite.const_int32(pool, cdef_val)
|
||||
|
||||
@@ -2121,6 +2259,92 @@ def make_global_ref(pool: memhub.MemBuddy | t.CPtr,
|
||||
# ty_hint: 类型提示 (写路径用 rhs 类型, 读路径用 i8* 回退)
|
||||
# 返回: Value 指针 (类型为 ty*),未识别为模块属性返回 None
|
||||
# ============================================================
|
||||
def _is_t_type_object_name(name: str) -> int:
|
||||
"""检查 name 是否是 t.py 中的类型对象名(CPtr/CInt/CDouble 等)
|
||||
|
||||
这些类型对象在运行时作为全局变量 @CPtr/@CInt 等被引用,
|
||||
但 t.py 不被编译,需要在使用处生成带 null 初值的定义。
|
||||
"""
|
||||
if name is None:
|
||||
return 0
|
||||
# t.py 中的类型对象名(PascalCase,首字母大写)
|
||||
if string.strcmp(name, "CPtr") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CInt") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CChar") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CShort") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CLong") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CLongLong") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CDouble") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CFloat") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CBool") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CVoid") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CInt8T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CInt16T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CInt32T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CInt64T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUInt8T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUInt16T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUInt32T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUInt64T") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUnsigned") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUnsignedInt") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUnsignedChar") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUnsignedShort") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUnsignedLong") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUnsignedLongLong") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CSizeT") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CIntPtrT") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CUIntPtrT") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CPtrDiffT") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CType") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CDefine") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CStatic") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CExport") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CArray") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CTypedef") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CNoVTable") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CNeedPtr") == 0:
|
||||
return 1
|
||||
if string.strcmp(name, "CAutoPtr") == 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr,
|
||||
@@ -2150,10 +2374,33 @@ def _resolve_module_attribute_global(pool: memhub.MemBuddy | t.CPtr,
|
||||
use_ty = llvmlite.Int8(pool)
|
||||
# 确保 use_ty 中的跨模块结构体类型有 opaque 声明
|
||||
llvmlite.module_ensure_opaque_for_type(mod, pool, use_ty)
|
||||
# 特殊处理: t.py 中的类型对象(CPtr/CInt/CDouble 等)
|
||||
# t.py 不被编译,但这些类型对象在运行时被引用(如 va_arg(ap, t.CPtr))。
|
||||
# 创建带 null 初值的 linkonce_odr 全局变量定义,避免链接时 undefined reference。
|
||||
# LLVM 22+ 不允许 external linkage 全局变量带初值,使用 linkonce_odr 替代。
|
||||
is_t_type_obj: int = 0
|
||||
if string.strcmp(mod_nm.id, "t") == 0:
|
||||
is_t_type_obj = _is_t_type_object_name(at.attr)
|
||||
ext_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, at.attr, use_ty)
|
||||
if ext_gv is not None:
|
||||
ext_gv.Linkage = "external"
|
||||
ext_gv.Initializer = None
|
||||
if is_t_type_obj != 0:
|
||||
# t.CPtr 等类型对象: 创建带 null 初值的定义(linkonce_odr)
|
||||
ext_gv.Linkage = "linkonce_odr"
|
||||
# i8* null 的初值文本
|
||||
null_init: bytes = pool.alloc(8)
|
||||
if null_init is not None:
|
||||
null_init[0] = 'n'
|
||||
null_init[1] = 'u'
|
||||
null_init[2] = 'l'
|
||||
null_init[3] = 'l'
|
||||
null_init[4] = '\0'
|
||||
ext_gv.Initializer = null_init
|
||||
else:
|
||||
ext_gv.Initializer = None
|
||||
else:
|
||||
# 普通模块属性: external 声明(由其他模块提供定义)
|
||||
ext_gv.Linkage = "external"
|
||||
ext_gv.Initializer = None
|
||||
llvmlite.module_add_global(mod, ext_gv)
|
||||
return make_global_ref(pool, at.attr, use_ty)
|
||||
|
||||
@@ -2302,6 +2549,24 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
is_submod = 1
|
||||
if is_submod != 0:
|
||||
return None # 是子模块,交给嵌套属性访问路径
|
||||
# 特殊处理: t.ASM_DESCR 不是 CDefine,是内联汇编约束命名空间
|
||||
# t.ASM_DESCR.XXX 由 HandlesExprCall 的 _asm_resolve_constraint 处理
|
||||
# 此处返回 None,让上层嵌套属性访问路径处理
|
||||
if string.strcmp(nm_ma.id, "t") == 0 and string.strcmp(at.attr, "ASM_DESCR") == 0:
|
||||
return None
|
||||
# CDefine 未找到且属性名符合 ALL_CAPS 约定: 报 FATAL 错误
|
||||
# 不再创建未定义的外部全局变量引用(否则 llc 报 "use of undefined value")
|
||||
if _is_cdefine_name_pattern(at.attr) != 0:
|
||||
err_buf_sma: str = pool.alloc(256)
|
||||
if err_buf_sma is not None:
|
||||
cur_sha1_sma: str = "(unknown)"
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
cur_sha1_sma = trans.ModuleSha1
|
||||
viperlib.snprintf(err_buf_sma, 256,
|
||||
"[CD] FATAL: Module attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n",
|
||||
nm_ma.id, at.attr, cur_sha1_sma)
|
||||
VLogger.error(err_buf_sma, "CD")
|
||||
return None
|
||||
# 非 CDefine: 使用 i8* 作为类型提示 (模块级变量通常存储指针)
|
||||
i8_ptr_hint: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
mod_gv_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
|
||||
@@ -2347,14 +2612,21 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
cdef_val_nested = _lookup_cross_module_cdefine(pool, at.attr, tmp_fi)
|
||||
if HandlesType.is_cdefine_found() != 0:
|
||||
return llvmlite.const_int32(pool, cdef_val_nested)
|
||||
# CDefine 未找到: 创建前向引用 (CDefine 通常是 i32)
|
||||
i32_ty_fwd: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||||
gv_ref_fwd: llvmlite.Value | t.CPtr = make_global_ref(
|
||||
pool, at.attr, i32_ty_fwd)
|
||||
if gv_ref_fwd is not None and gv_ref_fwd.Ty is not None:
|
||||
load_ty_fwd: llvmlite.LLVMType | t.CPtr = gv_ref_fwd.Ty.Pointee
|
||||
if load_ty_fwd is not None:
|
||||
return llvmlite.build_load(builder, load_ty_fwd, gv_ref_fwd)
|
||||
# CDefine 未找到: 报 FATAL 错误(不再创建未定义的全局变量引用)
|
||||
# 之前此处创建 @INVALID_HANDLE_VALUE 等前向引用,但全局未定义,
|
||||
# 导致 llc 报 "use of undefined value" 错误。
|
||||
# 正确做法是报错终止,让开发者修复跨模块 CDefine 查找失败的根本原因。
|
||||
if _is_cdefine_name_pattern(at.attr) != 0:
|
||||
err_buf_ma: str = pool.alloc(256)
|
||||
if err_buf_ma is not None:
|
||||
cur_sha1_ma: str = "(unknown)"
|
||||
if trans is not None and trans.ModuleSha1 is not None:
|
||||
cur_sha1_ma = trans.ModuleSha1
|
||||
viperlib.snprintf(err_buf_ma, 256,
|
||||
"[CD] FATAL: Nested attr '%s.%s' NOT found (CDefine cross-module lookup failed) in module sha1=%s\n",
|
||||
qual_buf, at.attr, cur_sha1_ma)
|
||||
VLogger.error(err_buf_ma, "CD")
|
||||
return None
|
||||
|
||||
# 对于 Name 类型的 obj,直接查找 alloca(不 load 结构体)
|
||||
obj_ptr: llvmlite.Value | t.CPtr = None
|
||||
@@ -2401,7 +2673,7 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
builder, struct_ty, alias_fe.Ty, obj_ptr, alias_idx)
|
||||
if alias_ptr is not None:
|
||||
return llvmlite.build_load(builder, alias_fe.Ty, alias_ptr)
|
||||
# 回退: 类型指针比较失败时,通过 AnnotClassName 按类名查找
|
||||
# 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找
|
||||
# 传递 SHA1 以区分跨模块同名类
|
||||
if field_info is None:
|
||||
if at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||||
@@ -2413,7 +2685,7 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
cur_sha1: str = trans.ModuleSha1
|
||||
field_info = HandlesStruct.lookup_field_by_class(
|
||||
var_entry.AnnotClassName, at.attr, cur_sha1)
|
||||
# 回退 1 成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
|
||||
# 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
|
||||
# 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)),
|
||||
# 需用实际结构体类型做 GEP,否则 GEP i8 失败
|
||||
if field_info is not None:
|
||||
@@ -2427,33 +2699,11 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
if casted_ptr is not None:
|
||||
obj_ptr = casted_ptr
|
||||
struct_ty = annot_se.Ty
|
||||
# 回退 1 更新 struct_ty 后,需重新确保
|
||||
# 按需过滤更新 struct_ty 后,需重新确保
|
||||
# 注解类型结构体定义在当前模块可用
|
||||
# (原始 struct_ty 可能是 i8,ensure 无效)
|
||||
HandlesStruct.ensure_struct_def_in_module(
|
||||
pool, mod, annot_se.Ty)
|
||||
# 回退 2: 子类搜索 — 注解类型是基类但实际值是派生类
|
||||
# 如 node: AST | t.CPtr = If(...),访问 node.orelse
|
||||
if field_info is None:
|
||||
sub_entry: HandlesStruct.StructEntry | t.CPtr = \
|
||||
HandlesStruct.find_subclass_with_field(
|
||||
var_entry.AnnotClassName, at.attr)
|
||||
if sub_entry is not None and sub_entry.Ty is not None:
|
||||
sub_field: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct.lookup_field(sub_entry.Ty, at.attr)
|
||||
if sub_field is not None:
|
||||
sub_ptr_ty: llvmlite.LLVMType | t.CPtr = \
|
||||
llvmlite.Ptr(pool, sub_entry.Ty)
|
||||
casted_ptr: llvmlite.Value | t.CPtr = \
|
||||
llvmlite.build_bitcast(builder, obj_ptr, sub_ptr_ty)
|
||||
if casted_ptr is not None:
|
||||
sub_field_ptr: llvmlite.Value | t.CPtr = \
|
||||
llvmlite.build_gep_struct(
|
||||
builder, sub_entry.Ty, sub_field.Ty,
|
||||
casted_ptr, sub_field.Index)
|
||||
if sub_field_ptr is not None:
|
||||
return llvmlite.build_load(
|
||||
builder, sub_field.Ty, sub_field_ptr)
|
||||
if field_info is not None:
|
||||
field_ty: llvmlite.LLVMType | t.CPtr = field_info.Ty
|
||||
# 联合体:bitcast obj_ptr 到 field_ty* 后 load
|
||||
@@ -2483,6 +2733,28 @@ def translate_attribute(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty)
|
||||
return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty)
|
||||
return loaded_val
|
||||
# fast-fail: 字段未找到,打印诊断信息
|
||||
if trans is not None:
|
||||
diag_annot: str = None
|
||||
diag_var_nm: str = None
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
dnm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
diag_var_nm = dnm.id
|
||||
if dnm.id is not None:
|
||||
dve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, dnm.id)
|
||||
if dve is not None:
|
||||
diag_annot = dve.AnnotClassName
|
||||
fb_attr: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_attr is not None:
|
||||
viperlib.snprintf(fb_attr, 1024,
|
||||
"属性访问失败: .%s (var=%s annot=%s sha1=%s:%d)",
|
||||
at.attr,
|
||||
diag_var_nm if diag_var_nm is not None else "?",
|
||||
diag_annot if diag_annot is not None else "None",
|
||||
trans.ModuleSha1 if trans.ModuleSha1 is not None else "?",
|
||||
at.lineno if at.lineno is not None else 0)
|
||||
VLogger.error(fb_attr, "ATTR")
|
||||
return None
|
||||
case _:
|
||||
return None
|
||||
@@ -2620,6 +2892,15 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
if obj_ptr is None and at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||||
nm_wma: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
if nm_wma.id is not None:
|
||||
# CDefine 常量不可写: 报 FATAL 错误,不创建未定义全局
|
||||
if _is_cdefine_name_pattern(at.attr) != 0:
|
||||
err_buf_wma: str = pool.alloc(256)
|
||||
if err_buf_wma is not None:
|
||||
viperlib.snprintf(err_buf_wma, 256,
|
||||
"[CD] FATAL: Cannot assign to CDefine constant '%s.%s'\n",
|
||||
nm_wma.id, at.attr)
|
||||
VLogger.error(err_buf_wma, "CD")
|
||||
return None
|
||||
# 使用 i8* 作为类型提示 (模块级变量通常存储指针)
|
||||
i8_ptr_w: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||||
wma_ref: llvmlite.Value | t.CPtr = _resolve_module_attribute_global(
|
||||
@@ -2645,7 +2926,7 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||||
field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
|
||||
struct_ty, at.attr)
|
||||
# 回退 1: 类型指针比较失败时,通过 AnnotClassName 按类名查找
|
||||
# 按需过滤: struct_ty 为 i8(简化联合类型)时,通过 AnnotClassName 按类名查找
|
||||
# 传递 SHA1 以区分跨模块同名类
|
||||
if field_info is None:
|
||||
if at.value.kind() == ast.ASTKind.Name and trans is not None:
|
||||
@@ -2659,7 +2940,7 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
cur_sha1 = trans.ModuleSha1
|
||||
field_info = HandlesStruct.lookup_field_by_class(
|
||||
var_entry.AnnotClassName, at.attr, cur_sha1)
|
||||
# 回退 1 成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
|
||||
# 按需过滤成功:bitcast obj_ptr 到 AnnotClassName 对应的结构体类型
|
||||
# 原始 struct_ty 可能是 i8(X|t.CPtr 简化为 Ptr(i8)),
|
||||
# 需用实际结构体类型做 GEP,否则 GEP i8 失败
|
||||
if field_info is not None:
|
||||
@@ -2673,32 +2954,10 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
if casted_ptr is not None:
|
||||
obj_ptr = casted_ptr
|
||||
struct_ty = annot_se.Ty
|
||||
# 回退 1 更新 struct_ty 后,需重新确保
|
||||
# 按需过滤更新 struct_ty 后,需重新确保
|
||||
# 注解类型结构体定义在当前模块可用
|
||||
HandlesStruct.ensure_struct_def_in_module(
|
||||
pool, mod, annot_se.Ty)
|
||||
# 回退 2: 子类搜索 — 注解类型是基类但实际值是派生类
|
||||
# 如 node: AST | t.CPtr = If(...),访问 node.orelse
|
||||
# orelse 在 If 上不在 AST 上,需搜索 AST 的子类
|
||||
if field_info is None:
|
||||
sub_entry: HandlesStruct.StructEntry | t.CPtr = \
|
||||
HandlesStruct.find_subclass_with_field(
|
||||
var_entry.AnnotClassName, at.attr)
|
||||
if sub_entry is not None and sub_entry.Ty is not None:
|
||||
sub_field: HandlesStruct.FieldEntry | t.CPtr = \
|
||||
HandlesStruct.lookup_field(sub_entry.Ty, at.attr)
|
||||
if sub_field is not None:
|
||||
sub_ptr_ty: llvmlite.LLVMType | t.CPtr = \
|
||||
llvmlite.Ptr(pool, sub_entry.Ty)
|
||||
casted_ptr: llvmlite.Value | t.CPtr = \
|
||||
llvmlite.build_bitcast(builder, obj_ptr, sub_ptr_ty)
|
||||
if casted_ptr is not None:
|
||||
# 确保子类结构体定义在当前模块可用
|
||||
HandlesStruct.ensure_struct_def_in_module(
|
||||
pool, mod, sub_entry.Ty)
|
||||
return llvmlite.build_gep_struct(
|
||||
builder, sub_entry.Ty, sub_field.Ty,
|
||||
casted_ptr, sub_field.Index)
|
||||
if field_info is not None:
|
||||
# 联合体:bitcast obj_ptr 到 field_ty*(字段指针用于 store)
|
||||
if HandlesStruct.is_union_by_type(struct_ty) == 1:
|
||||
@@ -2707,6 +2966,28 @@ def get_attribute_ptr(builder: llvmlite.IRBuilder | t.CPtr,
|
||||
# 普通结构体:GEP 获取字段指针
|
||||
return llvmlite.build_gep_struct(
|
||||
builder, struct_ty, field_info.Ty, obj_ptr, field_info.Index)
|
||||
# fast-fail: 字段未找到,打印诊断信息
|
||||
if trans is not None:
|
||||
diag_annot_g: str = None
|
||||
diag_var_nm_g: str = None
|
||||
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
|
||||
dnm_g: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
|
||||
diag_var_nm_g = dnm_g.id
|
||||
if dnm_g.id is not None:
|
||||
dve_g: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
|
||||
trans.SymTab, dnm_g.id)
|
||||
if dve_g is not None:
|
||||
diag_annot_g = dve_g.AnnotClassName
|
||||
fb_attr_g: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_attr_g is not None:
|
||||
viperlib.snprintf(fb_attr_g, 1024,
|
||||
"属性写入失败: .%s (var=%s annot=%s sha1=%s:%d)",
|
||||
at.attr,
|
||||
diag_var_nm_g if diag_var_nm_g is not None else "?",
|
||||
diag_annot_g if diag_annot_g is not None else "None",
|
||||
trans.ModuleSha1 if trans.ModuleSha1 is not None else "?",
|
||||
at.lineno if at.lineno is not None else 0)
|
||||
VLogger.error(fb_attr_g, "ATTR")
|
||||
return None
|
||||
case _:
|
||||
return None
|
||||
|
||||
Reference in New Issue
Block a user