import lib.core.Gen.Generator as Generator import t, c from stdint import * import ast import llvmlite import memhub import string import stdio import viperlib import lib.core.VLogger as VLogger import lib.core.Gen.Translator as HT import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.GenApi as GenApi # ============================================================ # TranslatorGenMixin - 翻译驱动 Mixin # # 职责:模块级翻译入口(translate_children/create_wrapper_main/ # handle_module_level_var 等)与 global/nonlocal 名称管理辅助。 # 容量常量 MAX_VARS/MAX_FUNCS/MAX_GLOBAL_NAMES 不在此定义(本文件无使用点), # 统一经 HT. 引用 Translator.vp 的唯一真源(与 FuncGenMixin 同一引用路径)。 # @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。 # ============================================================ # ============================================================ # TranslatorGenMixin - 翻译驱动(模块级翻译入口 + 作用域名称管理) # ============================================================ novirtual class TranslatorGenMixin: """翻译驱动 Mixin""" # ============================================================ # _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数 # # 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的 # CExport 函数无法被先翻译的模块正确识别为裸名调用。 # Phase 1a 预注册所有 CExport/State 函数名到全局表。 # ============================================================ Gen: Generator.Generator* def _register_cexport_from_funcdef(self, trans: HT.Translator*, node: ast.AST*) -> int: """预注册 CExport/State 函数到全局表(仅注册,不生成 IR)""" fd: ast.FunctionDef* = ast.FunctionDef*(node) if fd is None or fd.name is None: return 0 if trans is None or trans.ModuleSha1 is None: return 0 # 检查返回类型是否有 CExport 或 State 标记 has_export: int = 0 has_state: int = 0 if fd.returns is not None: has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport", 0) has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0) if has_export != 0 or has_state != 0: self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name) return 0 # ============================================================ # translate_children - 遍历 AST 子节点并分派翻译 # # 对应 TransPyC translator._translate_children() # 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans # ============================================================ def translate_children(self, trans: HT.Translator*, tree: ast.AST*) -> int: """遍历 tree.children 并翻译每个子节点 Args: trans: 翻译器(含所有共享状态) tree: AST 模块节点 Returns: int: 新增的变量数 """ ch: list[ast.AST*]* = tree.children if ch is None: return 0 cn_count: sizet = len(ch) added_total: int = 0 for ci in range(cn_count): child: ast.AST* = ch.get(ci) if child is None: continue kd: int = child.kind() # _declare_only == 0 时,_translate_module_level 已预处理导入语句, # 此处跳过避免重复处理(from_imports 条目重复) if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom): continue if kd == ast.ASTKind.Import: self.Gen.ImportsGen.translate_import(trans, child) elif kd == ast.ASTKind.ImportFrom: self.Gen.ImportsGen.translate_import_from_module(trans, child) self.Gen.ImportsGen.translate_import_from_names(trans, child) elif kd == ast.ASTKind.FunctionDef: # Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖) # Phase 1b 全量翻译:正常翻译函数体 if trans._declare_only == 0: added: int = self.Gen.FuncGenDef.translate_function_def(trans, child) added_total += added elif trans._declare_only == 1: self._register_cexport_from_funcdef(trans, child) # 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like # 签名 ndarray[t.CDouble] → 特化结构体注册)。1a 阶段在 mark1 之前, # 特化结构体的 Ty/Fields 分配在 mark1 前,不被 1b 的 mark/reset 回收, # 避免 Phase2 翻译 App 文件时读悬空结构体(UAF)。 # 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。 self._prescan_funcdef_signatures(trans, child) elif kd == ast.ASTKind.ClassDef: # ClassDef 在模块级直接处理(不需要 builder) # _declare_only=2(import扫描模式)时跳过,只处理 import 依赖 if trans._declare_only != 2: self.Gen.ClassGenDef.translate_class_def(trans, child) elif trans._declare_only == 0 and trans._cur_builder is not None: # 有 builder → 委托 HandlesBody 分派 added = self.Gen.StmtGen.translate_stmt(trans, child) added_total += added elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2: # 模块级 AnnAssign # _declare_only=2(import扫描模式)时跳过 # _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断) # _declare_only=0(全量翻译)时处理所有模块级 AnnAssign added = self.handle_module_level_var(trans, child) added_total += added elif trans._declare_only == 0 and kd == ast.ASTKind.Assign: # 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式) added = self.handle_module_level_var(trans, child) added_total += added return added_total # ============================================================ # _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名 # # 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]), # 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收), # 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。 # 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。 # ============================================================ def _prescan_funcdef_signatures(self, trans: HT.Translator*, node: ast.AST*) -> None: """预解析模块级函数签名的返回/参数类型,触发泛型类特化""" if trans is None or node is None: return # 入口收基类 ast.AST*(模块级调度器只持有 ast.AST* 子节点,与同一处调用的 # translate_function_def / translate_class_def / _register_cexport_from_funcdef # 形参口径一致),在此显式窄化为 ast.FunctionDef*:基类指针传派生类形参属 # 向下转型,严格指针规则下禁止隐式转换。 fd: ast.FunctionDef* = ast.FunctionDef*(node) if fd is None: return pool: memhub.MemBuddy* = trans.Pool if pool is None: return imp: str = trans._imported_modules fi: str = trans._from_imports if fd.returns is not None: self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imp, fi, trans, 0) if fd.args is not None: ags: ast.Arguments* = ast.Arguments*(fd.args) if ags.args is not None: al: list[ast.AST*]* = ags.args an: sizet = len(al) ai: sizet for ai in range(an): ag: ast.Arg* = ast.Arg*(al.get(ai)) if ag is not None and ag.annotation is not None: self.Gen.TypeGenResolve.resolve_annotation_type(pool, ag.annotation, imp, fi, trans, 0) # ============================================================ # _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器 # # 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...] # 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器) # ============================================================ def _build_array_initializer_text(self, pool: memhub.MemBuddy*, var_ty: llvmlite.LLVMType*, list_node: ast.List*) -> str: """从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败""" if var_ty is None or list_node is None: return None # 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型 # (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr) ln: ast.List* = ast.List*(list_node) if ln is None: return None # 从 var_ty 提取数组元素类型和数量 elem_ty: llvmlite.LLVMType* = None arr_count: int = 0 match var_ty: case llvmlite.LLVMType.Array(et, cnt): elem_ty = et arr_count = cnt if elem_ty is None or arr_count <= 0: return None # 确定元素类型的 IR 表示 elem_ir_ty: str = "i8" is_int_elem: int = 1 match elem_ty: case llvmlite.LLVMType.Int(bits): is_int_elem = 1 if bits == 8: elem_ir_ty = "i8" elif bits == 16: elem_ir_ty = "i16" elif bits == 32: elem_ir_ty = "i32" elif bits == 64: elem_ir_ty = "i64" case _: is_int_elem = 0 # 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别) elts: list[ast.AST*]* = ln.elts if elts is None: return None elts_count: sizet = len(elts) # 元素数超过声明长度 → fail-fast(不按声明长度截断、静默丢弃多余元素)。 if sizet(arr_count) < elts_count: self.Gen.TypeGenErr.fatal_error(list_node, f"数组初始化元素数 {elts_count} 超过数组声明长度 {arr_count},不允许静默截断", "OverflowError") return None # 非整数元素类型(struct/指针等聚合):不存在 "%s %lld" 文本展开,仅当列表 # 全零(元素缺失按零填充)时返回整体 "zeroinitializer"——对任意聚合类型合法 # (否则会生成与声明类型不匹配的 [i8 0, ...] → llc type mismatch)。 # 含非零/非整数常量无法文本表达 → None → 调用方 fail-fast。 if is_int_elem == 0: # 嵌套数组元素(如 t.CArray[t.CArray[uint8, 16], 256]):elem_ty 是 Array → # 递归构建子数组初始化器文本,内层类型省略(由外层全局类型推断),llc 合法。 is_nested_arr: int = 0 match elem_ty: case llvmlite.LLVMType.Array(_, _): is_nested_arr = 1 case _: pass if is_nested_arr != 0: cnt_total_n: sizet = sizet(arr_count) buf_size_n: sizet = 128 + cnt_total_n * 192 buf_n: str = pool.alloc(buf_size_n) if buf_n is None: return None written_n: int = viperlib.snprintf(buf_n, buf_size_n, "[") pos_n: sizet = sizet(written_n) # 子数组元素类型前缀(如 "[16 x i8]"):嵌套数组初始化器内层 # 必须显式类型(llc 对省略内层类型的 [[i8 0,...],...] 报 # "expected number in address space";用户规范要求 # [[16 x i8][i8 0, ...], ...] 形式)。TypePrint 序列化 elem_ty。 elem_ty_str_n: str = pool.alloc(96) if elem_ty_str_n is None: return None llvmlite.TypePrint(elem_ty_str_n, 96, elem_ty, pool) i_n: sizet = 0 while i_n < cnt_total_n: sub_n: str = None if i_n < elts_count: en_n: ast.AST* = elts.get(i_n) if en_n is not None: ek_n: int = en_n.kind() if ek_n == ast.ASTKind.List: sub_n = self._build_array_initializer_text(pool, elem_ty, ast.List*(en_n)) elif ek_n == ast.ASTKind.Set: # 花括号行字面量(如点阵字库 {0x00, ...}):Set.elts # 与 List 同构,包装为临时 List 递归生成子数组文本 se_n: rawptr[ast.Set] = rawptr[ast.Set](en_n) if se_n is not None and se_n.elts is not None: sub_n = self._build_array_initializer_text(pool, elem_ty, ast.List(pool, se_n.elts, ast.ASTCtx.Load)) if sub_n is None: # 元素缺失/无法展开:子数组整体零初始化 sub_n = "zeroinitializer" if i_n > 0: written_n = viperlib.snprintf(buf_n + pos_n, buf_size_n - pos_n, ", ") pos_n += sizet(written_n) written_n = viperlib.snprintf(buf_n + pos_n, buf_size_n - pos_n, "%s%s", elem_ty_str_n, sub_n) pos_n += sizet(written_n) i_n += 1 viperlib.snprintf(buf_n + pos_n, buf_size_n - pos_n, "]") return buf_n for zi in range(elts_count): ze: ast.AST* = elts.get(zi) if ze is None: continue zk: int = ze.kind() if zk == ast.ASTKind.Constant: zc: ast.Constant* = ast.Constant*(ze) if zc is None: continue # None(CONST_NONE)视为零:函数指针数组 # irq_handlers: t.CArray[irq_handler_t, 16] = [None] 表示 # 全空(idt.vp L387)——CONST_NONE 不是 CONST_INT,此前 # 被拒 → "初始化器构建失败" fail-fast。None 归一零填充。 if zc.const_kind == ast.CONST_NONE: continue if zc.const_kind != ast.CONST_INT or zc.int_val != 0: return None elif zk == ast.ASTKind.UnaryOp: if self.Gen.AssignGen.extract_cdefine_int_value(ze) != 0: return None else: return None return "zeroinitializer" # 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符 # 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count) cnt_total: sizet = sizet(arr_count) buf_size: sizet = 64 + cnt_total * 32 buf: str = pool.alloc(buf_size) if buf is None: return None # 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表) written: int = viperlib.snprintf(buf, buf_size, "[") pos: sizet = sizet(written) # 逐个元素写入:元素数必须与数组声明长度 arr_count 一致, # 列表元素不足时补零(如 g_arr: t.CArray[int, 4] = [0] → # [i32 0, i32 0, i32 0, i32 0]),否则 llc 报 # "constant expression type mismatch: got type '[1 x i32]' but expected '[4 x i32]'" i: sizet = 0 while i < cnt_total: elem_val: int64 = 0 if i < elts_count: elem_node: ast.AST* = elts.get(i) # 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 int 截断) if elem_node is not None: ek: int = elem_node.kind() if ek == ast.ASTKind.Constant: ec: ast.Constant* = ast.Constant*(elem_node) # CONST_CHAR 字符字面量(如 `_ps2_set1 = ['\x1b', '1', ...]`): # int_val 即字符码(不识别则字符元素全编成 0)。 if ec is not None and (ec.const_kind == ast.CONST_INT or ec.const_kind == ast.CONST_CHAR): elem_val = ec.int_val # CONST_STR 单字符(双引号如 "'" / '"'):parser 把双引号一律判为 # CONST_STR,strlen == 1 时取首字符码;多字符字符串无法表达为整型 # 元素 → 保持 0(由下方按声明长度补零)。 elif ec is not None and ec.const_kind == ast.CONST_STR: if ec.str_val is not None and string.strlen(ec.str_val) == 1: elem_val = int64(ec.str_val[0]) elif ek == ast.ASTKind.UnaryOp: # 负数: UnaryOp(USub, Constant) elem_val = self.Gen.AssignGen.extract_cdefine_int_value(elem_node) if i > 0: written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") pos += sizet(written) written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val) pos += sizet(written) i += 1 # 写入后缀 "]" viperlib.snprintf(buf + pos, buf_size - pos, "]") return buf # _build_string_array_initializer_text - 字符串字面量初始化数组全局 # t.CArray[char, N] = "..." → [i8 b0, i8 b1, ..., i8 0, ...](字符串字节 + # 零填充到数组长度;空串返回 zeroinitializer)。 # 不能用字符串指针 GEP 初始化器:会导致 @g = global [N x i8] 类型不匹配。 def _build_string_array_initializer_text(self, pool: memhub.MemBuddy*, var_ty: llvmlite.LLVMType*, str_val: str) -> str: """字符串字面量初始化数组全局,返回初始化器文本或 None""" if var_ty is None or str_val is None: return None arr_count: int = 0 match var_ty: case llvmlite.LLVMType.Array(_, cnt): arr_count = cnt if arr_count <= 0: return None slen: sizet = string.strlen(str_val) if slen == 0: return "zeroinitializer" buf_size: sizet = 64 + sizet(arr_count) * 16 buf: str = pool.alloc(buf_size) if buf is None: return None written: int = viperlib.snprintf(buf, buf_size, "[") pos: sizet = sizet(written) i: sizet = 0 while i < sizet(arr_count): if i > 0: written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") pos += sizet(written) bv: int64 = 0 if i < slen: bv = int64(str_val[i]) written = viperlib.snprintf(buf + pos, buf_size - pos, "i8 %lld", bv) pos += sizet(written) i += 1 viperlib.snprintf(buf + pos, buf_size - pos, "]") return buf # ============================================================ # _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量 # # 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00" # 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0) # 用于 b64_tab: t.CArray[char, None] = "ABC..." 等字符串初始化指针类型 # ============================================================ def _build_string_ptr_initializer(self, pool: memhub.MemBuddy*, mod: llvmlite.LLVMModule*, var_name: str, str_val: str) -> str: """为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败""" if str_val is None or var_name is None: return None # 构造内部字符串常量名称: .str.{var_name} str_name_buf: str = pool.alloc(64) if str_name_buf is None: return None viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name) # 调用 llvmlite.create_global_string 创建字符串常量全局 str_gv: llvmlite.GlobalVariable* = llvmlite.create_global_string(pool, mod, str_name_buf, str_val) if str_gv is None: return None # 生成 GEP 初始化器文本 str_len: sizet = string.strlen(str_val) init_buf: str = pool.alloc(128) if init_buf is None: return None viperlib.snprintf(init_buf, 128, "getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)", str_len + 1, str_len + 1, str_name_buf) return init_buf def _stg_field_zero_text(self, pool: memhub.MemBuddy*, fty: llvmlite.LLVMType*, ty_str: str) -> str: """按 LLVM 类型生成 storage struct 字段的零值初始化器文本 LLVM struct 初始化器必须列全所有字段(部分初始化 llc 报 "initializer with struct type has wrong # elements")。 Ptr→null、Int→0、Float→0.0、Array/Struct→zeroinitializer。 """ if fty is None or ty_str is None: return None buf: str = pool.alloc(160) if buf is None: return None match fty: case llvmlite.LLVMType.Ptr(_): viperlib.snprintf(buf, 160, "%s null", ty_str) case llvmlite.LLVMType.Int(_): viperlib.snprintf(buf, 160, "%s 0", ty_str) case llvmlite.LLVMType.Float(_): viperlib.snprintf(buf, 160, "%s 0.0", ty_str) case _: # Array / Struct 等 aggregate → zeroinitializer viperlib.snprintf(buf, 160, "%s zeroinitializer", ty_str) return buf # ============================================================ # _default_val_const_text - 字段默认值 → LLVM 常量元素文本 # # 仅处理可常量折叠的整型默认值(CONST_INT/CONST_CHAR 及负号字面量); # 其余(浮点/字符串/None/名字/表达式)返回 None,由调用方按零值兜底。 # ============================================================ def _default_val_const_text(self, pool: memhub.MemBuddy*, fty: llvmlite.LLVMType*, ty_str: str, dval: ast.AST*) -> str: """字段默认值 → "ty 值" 文本;不可折叠返回 None""" if dval is None or fty is None or ty_str is None: return None is_int: int = 0 dv_int: int64 = 0 if dval.kind() == ast.ASTKind.Constant: dc: ast.Constant* = ast.Constant*(dval) if dc is not None: if dc.const_kind == ast.CONST_INT or dc.const_kind == ast.CONST_CHAR: dv_int = dc.int_val is_int = 1 elif dval.kind() == ast.ASTKind.UnaryOp: # 负数/按位取反字面量(如 -1 / 0xFFFFFFFFFFFFFFFF) dv_int = self.Gen.AssignGen.extract_cdefine_int_value(dval) is_int = 1 if is_int == 0: return None # 仅整型字段可写整数常量(浮点/指针/聚合交给零值兜底) match fty: case llvmlite.LLVMType.Int(_): pass case _: return None buf: str = pool.alloc(48) if buf is None: return None viperlib.snprintf(buf, 48, "%s %lld", ty_str, dv_int) return buf # _build_stg_struct_body_text - storage struct 字段元素文本(不含大括号) # 生成 "elem0, elem1, ..."(含字段默认值折叠,缺失处按类型零值兜底),供两处复用: # - _build_stg_struct_init_text:外包 "{ ... }" 作为完整初始化器; # - vtable 对象 storage:首元素为 vtable 指针,其后追加本函数结果(start_idx=1 跳过字段 0)。 # 无任何非零默认值时返回 None,调用方据此保持原零值路径(避免无谓文本)。 def _build_stg_struct_body_text(self, pool: memhub.MemBuddy*, se: GenTypes.StructEntry*, start_idx: int) -> str: """按字段默认值生成 "e0, e1, ..." 元素文本;无非零默认值返回 None""" if se is None or se.Fields is None: return None fc: int = se.FieldCount if fc <= start_idx: return None buf_size: sizet = 256 + sizet(fc) * 160 buf: str = pool.alloc(buf_size) if buf is None: return None pos: sizet = 0 first: int = 1 has_nonzero: int = 0 i: int = start_idx while i < fc: fe: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(se, i) i += 1 if fe is None or fe.Ty is None: continue ty_str: str = pool.alloc(128) if ty_str is None: continue llvmlite.TypePrint(ty_str, 128, fe.Ty, pool) elem: str = self._default_val_const_text(pool, fe.Ty, ty_str, fe.DefaultVal) is_zero: int = 0 if elem is None: elem = self._stg_field_zero_text(pool, fe.Ty, ty_str) is_zero = 1 if elem is None: continue written: int = 0 if first == 0: written = viperlib.snprintf(buf + pos, buf_size - pos, ", ") pos += sizet(written) written = viperlib.snprintf(buf + pos, buf_size - pos, "%s", elem) pos += sizet(written) first = 0 if is_zero == 0: has_nonzero = 1 if has_nonzero == 0: return None return buf # _build_stg_struct_init_text - storage struct 完整常量初始化器(含字段默认值) # 用于模块级对象全局 `X: T = T()`:按字段默认值生成完整 struct 常量 # (LLVM 要求列全每个字段);不生成则字段默认值全丢。 # 无任何非零默认值时返回 None,由调用方保持 zeroinitializer(避免无谓文本)。 def _build_stg_struct_init_text(self, pool: memhub.MemBuddy*, se: GenTypes.StructEntry*, start_idx: int) -> str: """按字段默认值生成完整 struct 初始化器;无非零默认值返回 None""" body: str = self._build_stg_struct_body_text(pool, se, start_idx) if body is None: return None body_len: sizet = sizet(string.strlen(body)) buf: str = pool.alloc(body_len + 8) if buf is None: return None viperlib.snprintf(buf, body_len + 8, "{ %s }", body) return buf # ============================================================ # 模块级全局变量 t.attr.* 属性提取 # # 语法:属性写在类型注解的联合里(`T | t.attr.section(".x")`),因为 # Assign/AnnAssign 节点没有 decorator_list(解析器对 `@c.Attribute(...)` # 后接赋值会直接报 "decorator must be followed by def/class")。 # 与函数侧口径差异:函数属性来自 decorator_list,提取为属性组文本 # `"section"="xxx"`(LLVM 字符串属性必须带引号,走 attributes #N); # 全局变量属性没有属性组,直接写入 GlobalVariable.Section/Align/Linkage # 字段,打印时由 includes/llvmlite/__module.vp 的 _print_global 补引号 # (`, section "xxx"` / `, align N`),故此处 Section 值不带引号。 # ============================================================ def _scan_global_tattr(self, node: ast.AST*, want_name: str) -> ast.AST*: """在全局变量类型注解中查找 t.attr. 节点。 注解形态是 BinOp(BitOr) 左深链(`A | B | C` = BinOp(BinOp(A,B),C)), 递归左右子节点。命中返回该 t.attr 节点(Call: t.attr.aligned(16) / Attribute: t.attr.weak),未命中返回 None。属性名识别复用类侧 ClassGenBase._tattr_name(Call→func→attr / Attribute→attr)。 """ if node is None: return None if node.kind() == ast.ASTKind.BinOp: bop: ast.BinOp* = ast.BinOp*(node) if bop.op == ast.OpKind.BitOr: hit_l: ast.AST* = self._scan_global_tattr(bop.left, want_name) if hit_l is not None: return hit_l return self._scan_global_tattr(bop.right, want_name) return None if self.Gen.ClassGenBase._tattr_name(node, want_name) != 0: return node return None def _extract_global_attr_section(self, node: ast.AST*, var_name: str) -> str: """取 `T | t.attr.section("xxx")` 的段名(不含引号)。 缺参/空段名属非法值 → fail-fast(与 handle_module_level_var 既有 TypeGenErr.fatal_error 风格一致):空段名会生成 `section ""` 这种 无意义/非法的 IR,静默忽略只会掩盖拼写错误。 """ hit: ast.AST* = self._scan_global_tattr(node, "section") if hit is None: return None sec_val: str = self.Gen.FuncGenBase._get_attr_call_arg_str(hit) if sec_val is None or sec_val[0] == 0: self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 的 t.attr.section(...) 段名缺失或为空", "ValueError") return None return sec_val def _extract_global_attr_aligned(self, node: ast.AST*, var_name: str) -> int: """取 `T | t.attr.aligned(N)` 的对齐字节数(无该属性返回 0)。 N 必须是正整数字面量:aligned(0)/aligned(-4)/aligned("x") 均属非法值 → fail-fast(llc 亦拒绝 `align 0`,静默忽略会掩盖参数错误)。 """ hit: ast.AST* = self._scan_global_tattr(node, "aligned") if hit is None: return 0 al_val: int = self.Gen.ClassGenBase._tattr_aligned_int(hit) if al_val <= 0: self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 的 t.attr.aligned(N) 需要正整数字面量 N", "ValueError") return 0 return al_val def _extract_global_attr_weak(self, node: ast.AST*) -> int: """检测 `T | t.attr.weak` / `t.attr.weak()`(1=有,0=无)""" if self._scan_global_tattr(node, "weak") is not None: return 1 return 0 # ============================================================ # handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量 # # 当用户已定义 main(无 wrapper main builder)时,模块级 # AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域 # 支持整数、列表字面量、字符串字面量初始值 # ============================================================ # ============================================================ # _RegisterStaticModuleVar - 模块级 static 变量登记 # # `static x: int = 0`(解析层已归一为 `x: t.CStatic | int`)与手写 # `x: t.CStatic | int` 均命中 → 登记 (变量名, 定义模块 SHA1) 到 static 符号表, # 供引用侧(ExprGenAttr / CallGenMixin / ImportsGenMixin)拦截跨模块使用。 # 变量无装饰器通道(@t.CStatic 只作用于 def),故只看注解。 # 时机:调用点位于 handle_module_level_var 的 `_declare_only` 提前返回之后, # 预声明遍不会走到;登记接口本身也做了幂等,重复登记无副作用。 # 独立成函数:不内联(内联新增分支会干扰调用方的类型推断)。 # ============================================================ def _RegisterStaticModuleVar(self, trans: HT.Translator*, annot_node: ast.AST*, var_name: str) -> int: if trans is None or annot_node is None or var_name is None: return 0 if trans.ModuleSha1 is None: return 0 if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CStatic", 0) == 0: return 0 self.Gen.CallGenBase.RegisterStaticSymbol(trans.ModuleSha1, var_name) return 0 def handle_module_level_var(self, trans: HT.Translator*, node: ast.AST*) -> int: """处理模块级变量声明,创建全局变量""" pool: memhub.MemBuddy* = trans.Pool mod: llvmlite.LLVMModule* = trans.Module # CDefine 注解: 编译期常量,不创建全局变量 # 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析 k: int = node.kind() if k == ast.ASTKind.AnnAssign: aa_cd: ast.AnnAssign* = ast.AnnAssign*(node) if aa_cd is not None and aa_cd.target is not None: if aa_cd.target.kind() == ast.ASTKind.Name: nm_cd: ast.Name* = ast.Name*(aa_cd.target) if nm_cd.id is not None: if self.Gen.AssignGen.is_cdefine_annotation(aa_cd.annotation) != 0: # 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI) self.Gen.AssignGen._register_cdefine_from_value(pool, nm_cd.id, aa_cd.value, aa_cd.annotation) return 0 # CTypedef 注解(如 posix.vp mode_t: t.CTypedef = uint32): # 不创建全局变量(否则生成 @mode_t 符号 → 链接 duplicate symbol)。 # 预注册阶段按需注册到 CTypedef 表:翻译期表已被 clear_ctypedefs 清空 # (每文件隔离),不注册则函数参数注解查表失败 → NameError。 if self.Gen.TypeGenCType._is_ctypedef_annotation(aa_cd.annotation) != 0: ctd_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, aa_cd.value) if ctd_str is not None: self.Gen.TypeGenCType.register_ctypedef(pool, nm_cd.id, ctd_str) return 0 # _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量 # CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过 if trans._declare_only == 1: return 0 var_name: str = None var_ty: llvmlite.LLVMType* = llvmlite.Int32(pool) resolved_stg_ty: llvmlite.LLVMType* = None # 对象类全局:静态 storage 类型(BSS 实例) resolved_stg_entry: GenTypes.StructEntry* = None # 对象类全局:对应 StructEntry(vtable 初始化用) init_val: int64 = 0 init_fval: t.CDouble = 0.0 # init_kind==4(浮点字面量)时的数值 init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str, 4=float init_str_val: str = None init_list_node: ast.List* = None # = None 显式初始化(如 tokens.vp `_kw_head: KwEntry | t.CPtr = None`): # 对象类全局的懒初始化指针语义——必须保持 NULL,不能创建 BSS storage # (storage 会让 @g = &g.stg 恒非 NULL,破坏 `if _kw_head != None` 守卫, # 懒初始化代码永不执行)。 is_none_init: int = 0 annot_node: ast.AST* = None # 类型注解节点(检测 t.CExport 标记) if k == ast.ASTKind.AnnAssign: aa: ast.AnnAssign* = ast.AnnAssign*(node) if aa is None or aa.target is None: return 0 if aa.target.kind() != ast.ASTKind.Name: return 0 nm: ast.Name* = ast.Name*(aa.target) var_name = nm.id annot_node = aa.annotation # f-string 逃逸:模块级变量的初始值是**全局**(函数外可见),而 f-string # 结果指向当前函数的栈缓冲(且模块级初始化根本没有可用的函数栈)⇒ # fail-fast;需要字面量以外的初值请用显式拷贝(GenApi.escape_fstring_copy)。 GenApi.fail_if_fstring_escape(aa.value, "全局变量初始化") # static 符号(禁止跨模块使用):模块级变量带 t.CStatic 标记 # (`static x: int = 0` 经解析层归一为 `x: t.CStatic | int`;亦覆盖 # 手写 `x: t.CStatic | int`)→ 登记 (变量名, 定义模块 SHA1)。 # 逻辑收敛在 _RegisterStaticModuleVar 内(不内联——本函数含多分支, # 内联新增分支会干扰其类型推断,与 ExprGenAttr/CallGenMixin 同款处理)。 self._RegisterStaticModuleVar(trans, annot_node, var_name) # t.Callable 模块级函数指针:登记 (变量名 → 返回类型) 签名。此路径原先 # 只创建全局变量、不登记签名,模块级 t.Callable 变量被间接调用时在 # CallGenLeafKit._translate_func_ptr_call 报"返回类型未注册(t.Callable # 注解缺失)"(CallGenLeafKit.vp:843-850)。与函数内 AnnAssign 同一登记函数 # (AssignGenMixin.vp:1465-1474),参数形态照抄该处: # (pool, 注解, trans._imported_modules, trans._from_imports, trans)。 # 时机:_translate_module_level 在 translate_children 之前先遍历全部模块级 # AnnAssign/Assign(Translator.vp:568-575,其后才是 :578 translate_children), # 故登记早于本文件任何函数体翻译;签名表本体与返回类型深拷贝都在 PermPool # (CallGenLeafKit.vp:698-699、:783-788),跨文件查找可见。 # t.CDefine/t.CTypedef 等分支已在 :675-689 提前返回,行为不变。 if annot_node is not None: ml_callable_ret: llvmlite.LLVMType* = self.Gen.TypeGenErr.try_extract_callable_ret(pool, annot_node, trans._imported_modules,trans._from_imports, trans) if ml_callable_ret is not None: # 返回值:0=成功/同类型幂等命中;非 0 已在 register_func_ptr_sig # 内部 fatal_error 终止编译,此处分支仅防御(见 AssignGenMixin 同处)。 if self.Gen.CallGenLeafKit.register_func_ptr_sig(pool, var_name, ml_callable_ret, aa) != 0: return 0 # 解析类型 if aa.annotation is not None: resolved: llvmlite.LLVMType* = self.Gen.TypeGenResolve.resolve_annotation_type(pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0) if resolved is not None: # 对象类模块级变量(@t.Object/@t.CVTable:对象即指针)→ Ptr(struct): # 裸类名注解 resolve 返回 struct 值,模块级变量此处需包装 Ptr;若建成 # 值实例,跨模块字段访问/虚表调用会按指针处理读首 8 字节当 vtable → 崩溃。 # 纯 t.CStruct(无方法无虚表无 __new__)保持值实例。 if resolved.kind() == llvmlite.LLVMType.Struct: gv_entry: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(resolved) if gv_entry is not None \ and (gv_entry.HasNew != 0 or gv_entry.HasVTable != 0 or gv_entry.IsOOP != 0): # 对象类全局(裸类名注解 → 对象即指针):记录原 Struct 值类型, # 用于创建静态 storage 全局承载对象实例(BSS);否则 @g 为 NULL, # 对象字段落在物理页 0。 resolved_stg_ty = resolved resolved_stg_entry = gv_entry resolved = llvmlite.Ptr(pool, resolved) elif resolved.kind() == llvmlite.LLVMType.Ptr: # 对象类联合注解(T | t.CPtr → T*):同样创建 storage;否则入口/方法 # 虚调用 load @g 得 NULL → 读 [NULL] 拿 vtable → #PF。 # var_ty 保持 Ptr(联合注解语义:指针全局),storage 承载对象实例。 pointee_uv: llvmlite.LLVMType* = resolved.Pointee if pointee_uv is not None and pointee_uv.kind() == llvmlite.LLVMType.Struct: gv_entry_u: GenTypes.StructEntry* = self.Gen.StructGen.find_struct_by_type(pointee_uv) if gv_entry_u is not None \ and (gv_entry_u.HasNew != 0 or gv_entry_u.HasVTable != 0 or gv_entry_u.IsOOP != 0): resolved_stg_ty = pointee_uv resolved_stg_entry = gv_entry_u var_ty = resolved else: # [S4 fail-fast] 模块级变量有注解但解析失败 → 不再静默用 i32 # (类型错会使全局存储尺寸/字段访问/ABI 全错);前向引用未注册类 # 应收敛为多遍注册而非回退 i32。 self.Gen.TypeGenErr.fatal_error(aa.annotation, f"模块级变量 '{var_name}' 类型注解解析失败", "NameError") return 0 # 解析初始值(支持整数、负数字面量、列表字面量、字符串字面量) if aa.value is not None: val_kind: int = aa.value.kind() if val_kind == ast.ASTKind.Constant: cn: ast.Constant* = ast.Constant*(aa.value) if cn.const_kind == ast.CONST_NONE: is_none_init = 1 elif cn.const_kind == ast.CONST_INT: init_val = cn.int_val init_kind = 1 elif cn.const_kind == ast.CONST_STR: init_str_val = cn.str_val init_kind = 3 elif cn.const_kind == ast.CONST_FLOAT: # 浮点字面量(如 torch `LCG_M: t.CDouble = 2147483647.0`):必须设 # init_kind,否则全局退化成 zeroinitializer、初始化值整体丢失。 # 数值不在此处取 AST 的 float_val,见下方 init_kind==4 的源文件恢复逻辑。 init_kind = 4 elif val_kind == ast.ASTKind.UnaryOp: # 负数/按位取反字面量(如 `_vblank_ok: int = -1`):AST 是 # UnaryOp(USub, Constant),不处理则全局编成 zeroinitializer、初始化值丢失。 init_val = self.Gen.AssignGen.extract_cdefine_int_value(aa.value) init_kind = 1 elif val_kind == ast.ASTKind.List: init_list_node = ast.List*(aa.value) init_kind = 2 elif k == ast.ASTKind.Assign: asgn: ast.Assign* = ast.Assign*(node) if asgn is None or asgn.targets is None: return 0 targets: list[ast.AST*]* = asgn.targets if len(targets) < 1: return 0 t0: ast.AST* = targets.get(0) if t0 is None or t0.kind() != ast.ASTKind.Name: return 0 nm2: ast.Name* = ast.Name*(t0) var_name = nm2.id if asgn.value is not None: val_kind2: int = asgn.value.kind() if val_kind2 == ast.ASTKind.Constant: cn2: ast.Constant* = ast.Constant*(asgn.value) if cn2.const_kind == ast.CONST_NONE: is_none_init = 1 elif cn2.const_kind == ast.CONST_INT: init_val = cn2.int_val init_kind = 1 elif cn2.const_kind == ast.CONST_STR: init_str_val = cn2.str_val init_kind = 3 elif cn2.const_kind == ast.CONST_FLOAT: # 无注解的模块级浮点赋值:字面量本身即类型依据,提升为 double # (默认 var_ty 是 i32,不提升会把浮点位模式写进 i32 全局) init_kind = 4 var_ty = llvmlite.Double(pool) elif val_kind2 == ast.ASTKind.UnaryOp: # 负数字面量(同 AnnAssign 分支,见上):UnaryOp(USub, Constant) init_val = self.Gen.AssignGen.extract_cdefine_int_value(asgn.value) init_kind = 1 elif val_kind2 == ast.ASTKind.List: init_list_node = ast.List*(asgn.value) init_kind = 2 elif val_kind2 == ast.ASTKind.Attribute: # 模块级 re-export 别名(如 fat32_core.vp `_read32 = types._read32`): # RHS 是函数/实体引用,无值语义可落入 LLVM 全局。不识别则 var_ty 默认 i32 # → 生成假符号 `global i32 zeroinitializer`(被引用即调用地址 0)。 # 与 __all__ 同类:别名/元数据实体不产出 LLVM 全局。 # 真正的函数别名机制(可调用 + 可 re-export)属独立特性,待后续实现。 return 0 if var_name is None: return 0 # __all__ 是 Python 模块元数据(公开名列表),无运行时语义:StubGen 的 .vpi 不为其 # 生成 stub 声明,此处同样跳过全局创建——否则无注解 list-of-strings 全局类型推断 # 缺失(var_ty 默认 i32)→ _build_array_initializer_text 返回 None → 误报 # "初始化器构建失败"。与 CDefine/CTypedef 同类:编译期/元数据实体不落入 LLVM 全局。 if string.strcmp(var_name, "__all__") == 0: return 0 # 浮点字面量初始化(init_kind==4):数值一律从当前源文件按变量名重读, # 不用 AST 节点的 float_val —— 该字段可能被后续 pool 操作覆写,且跨模块 # double 返回值传递本身有缺陷(详见 AssignGenMixin._recover_float_literal)。 # 同时校验注解类型:注解不是浮点却给浮点字面量属类型错误,直接终止, # 不静默零初始化。 if init_kind == 4: is_fty_g: int = 0 match var_ty: case llvmlite.LLVMType.Float(_): is_fty_g = 1 case _: pass if is_fty_g == 0: self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 用浮点字面量初始化,但注解不是浮点类型", "TypeError") return 0 if self.Gen.AssignGen._recover_float_literal(var_name, t.CPtr(c.Addr(init_fval)), 0) != 1: self.Gen.TypeGenErr.fatal_error(node, f"模块级浮点变量 '{var_name}' 初始化值源文件恢复失败", "InternalCompilerError") return 0 # 检查是否已注册 existing: llvmlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, var_name) if existing is not None: return 0 # 创建全局变量 @var_name # 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明 # 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报 # "use of undefined type named 'sha1.ClassName'" 错误 # (如 _mbuddy: rawptr[memhub.MemManager] → Ptr(Struct("aeb3...MemManager"))) llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty) # 模块级全局命名带 SHA1 前缀(对齐函数名 mangling):多个模块声明同名 # 全局(如 _mbuddy)时各自独立命名,消除 ld.lld duplicate symbol。 # SymTab 注册 key 保持裸名(查找逻辑零改动),LLVM 符号名用 mangled 名。 # t.CExport 标记的全局用裸名(内联汇编引用 / 外部符号对接,如 # VKernel gdt/gp/_switch_old_rsp/_coro_* 被 c.Asm 引用,带 SHA1 前缀 # 无法在 LLVM MC 中解析)。 is_global_cexport: int = 0 if annot_node is not None: is_global_cexport = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CExport", 0) # extern 全局(`extern NAME: T` → 注解含 t.State / t.CExtern):符号定义在 # 外部(C 库 / 汇编 / 其它翻译单元),本模块只生成外部声明 # `@裸名 = external global T`——external linkage、无初始值、无 storage。 # 与 export 的差别:export 是**本模块定义**(裸名导出);extern 是**仅声明**。 # `t.State` = t.CExtern | t.CExport(parser 的 `extern NAME: T` 展开产物)。 is_global_extern: int = 0 if annot_node is not None: is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CExtern", 0) if is_global_extern == 0: is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "State", 0) # 全局变量侧 t.attr.* 属性(`T | t.attr.xxx` 注解联合形态): # section→gv.Section、aligned→gv.Align、weak→gv.Linkage(见下方应用点)。 # 仅在 AnnAssign(annot_node 非 None)时存在,与 t.CExport 同一条路。 gv_attr_section: str = None gv_attr_align: int = 0 gv_attr_weak: int = 0 if annot_node is not None: gv_attr_section = self._extract_global_attr_section(annot_node, var_name) gv_attr_align = self._extract_global_attr_aligned(annot_node, var_name) gv_attr_weak = self._extract_global_attr_weak(annot_node) mangled_name: str = var_name if is_global_cexport == 0 and is_global_extern == 0: mangled_name = self.Gen.FuncGenBase._mangle_name(trans, var_name) gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, mangled_name, var_ty) if gv is None: return 0 llvmlite.module_add_global(mod, gv) # 段名:直接写字段(_print_global 会补 `, section "xxx"` 的引号)。 if gv_attr_section is not None: llvmlite.global_set_section(gv, gv_attr_section) # B5:@c.Attribute(t.attr.aligned(N)) 类的全局实例施加对齐(如 fpu_context 16 对齐, # FXSAVE 区域要求 16 字节对齐,否则 fxsave/fxrstor #GP)。 # 优先级:变量级显式 `T | t.attr.aligned(N)` 比类级(struct entry Align)更具体, # 显式值胜出;无显式属性时沿用类级对齐(既有行为不变)。 al_ty: llvmlite.LLVMType* = var_ty match var_ty: case llvmlite.LLVMType.Ptr(pointee_al): al_ty = pointee_al case _: pass al_entry: GenTypes.StructEntry* = None if al_ty is not None and al_ty.kind() == llvmlite.LLVMType.Struct: al_entry = self.Gen.StructGen.find_struct_by_type(al_ty) if gv_attr_align > 0: gv.Align = gv_attr_align elif al_entry is not None and al_entry.Align > 0: gv.Align = al_entry.Align # 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值) # extern 全局例外:保持 external(仅外部声明,绝不写初始值 / storage)。 if is_global_extern != 0: gv.Linkage = "external" else: gv.Linkage = None # t.attr.weak → weak linkage(须在 Linkage 清空之后设置)。 if gv_attr_weak != 0: llvmlite.global_set_linkage(gv, "weak") if init_kind == 1: # 整数初始值 init_buf: str = pool.alloc(48) if init_buf is not None: viperlib.snprintf(init_buf, 48, "%lld", init_val) gv.Initializer = init_buf elif init_kind == 2: # 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...] arr_init: str = self._build_array_initializer_text(pool, var_ty, init_list_node) if arr_init is not None: gv.Initializer = arr_init else: # 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") elif init_kind == 3: # 字符串字面量初始化 # 数组类型(t.CArray[char, N]):字节数组初始化器(字符串内容 + 零填充)。 # 不能用字符串指针 GEP 初始化器(@g = global [N x i8] 类型不匹配)。 is_arr_g: int = 0 match var_ty: case llvmlite.LLVMType.Array(_, _): is_arr_g = 1 case _: pass if is_arr_g != 0: arr_str_init: str = self._build_string_array_initializer_text(pool, var_ty, init_str_val) if arr_str_init is not None: gv.Initializer = arr_str_init else: self.Gen.TypeGenErr.fatal_error(node, f"模块级数组变量 '{var_name}' 字符串初始化器构建失败", "TypeError") else: # 指针类型(如 b64_tab: t.CArray[char, None] = "ABC..."): # 创建字符串常量全局 + GEP 引用 str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val) if str_init is not None: gv.Initializer = str_init else: self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError") elif init_kind == 4: # 浮点初始值:LLVM IR 的浮点常量必须写成位模式文本(0x%016llx / 0x%08x)—— # 十进制文本经 llc 解析对部分值有 ±1 ulp 误差(见 llvmlite.ConstFloat 注释)。 # 浮点分支缺失时模块级 t.CDouble 全局会退化成 zeroinitializer(值全变 0)。 fc_g: llvmlite.Value* = llvmlite.ConstFloat(pool, var_ty, init_fval) if fc_g is not None and fc_g.Name is not None: gv.Initializer = fc_g.Name else: self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 浮点初始化器构建失败", "TypeError") else: # 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer, # 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type" # 对象类全局(有 storage)的 Initializer 由下方 storage 逻辑设为 &@storage, # 此处不覆盖;但 = None 懒初始化全局(is_none_init)既无 storage 也无其他 # Initializer → 必须显式 zeroinitializer(LLVM 对指针类型输出为 null), # 否则 gv 无初始化器 → 全局声明残缺。 if (resolved_stg_ty is None or is_none_init != 0) and is_global_extern == 0: gv.Initializer = "zeroinitializer" # 对象类全局:创建静态 storage 全局(BSS)承载对象实例,@g 编译期引用它。 # 函数内 `g = T()` 构造时把对象复制到 storage(见 AssignGenMixin 全局分支), # 不再依赖栈 alloca(悬垂);c.Addr(g) load @g 得到 &storage,均非 NULL。 # 豁免:显式 `= None` 初始化(is_none_init)的懒初始化指针全局 # (如 _kw_head/_op_head)不建 storage,保持 NULL 语义。 # extern 全局(is_global_extern)同样不建 storage:外部声明无本模块实例。 if resolved_stg_ty is not None and is_none_init == 0 and is_global_extern == 0: # 值类型 storage 需要完整 struct 定义(跨模块类默认 opaque → # @g.stg = global %T zeroinitializer 报 "use of undefined type") self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved_stg_ty) # @t.CVTable 对象类:storage 首字段(vtable 指针,偏移 0)初始化为 vtable 地址, # 否则 zeroinitializer → 入口虚调用 call [vtable+0x10] → 跳 0x0 #PF。 # @t.Object(无 CVTable)/普通对象:保持 zeroinitializer(无 vtable 需求)。 stg_init_text: str = "zeroinitializer" if resolved_stg_entry is not None and resolved_stg_entry.Name is not None \ and resolved_stg_entry.HasVTable != 0: vt_name_buf: str = pool.alloc(128) if vt_name_buf is not None: viperlib.snprintf(vt_name_buf, 128, "%s.vtable", resolved_stg_entry.Name) # vtable 符号前缀必须用类定义模块的 sha1(对齐 CallGenLeafKit._make_vtable_ref_i8): # 用当前模块 _mangle_name 会使跨模块对象类全局 storage 初始化引用 # "@当前sha1.Class.vtable",而 vtable 实为定义模块的符号 → llc "use of # undefined value"。resolved_stg_entry.ModuleSha1 即定义模块,比裸名反查精确。 vt_sha1: str = None if resolved_stg_entry.ModuleSha1 is not None: vt_sha1 = resolved_stg_entry.ModuleSha1 if vt_sha1 is None: vt_sha1 = trans.ModuleSha1 vt_mangled: str = self.Gen.FuncGenBase._mangle_name_with_sha1(vt_sha1, vt_name_buf) if vt_mangled is not None: # 完整 struct 初始化器(LLVM 拒绝部分初始化): # 字段 0 = __vtable__(i8* @vtable),其余用户字段按类型零值。 init_full_len: sizet = 16384 init_full: str = pool.alloc(init_full_len) if init_full is not None: written_v: int = viperlib.snprintf(init_full, init_full_len, "{ ") pos_v: sizet = sizet(written_v) if self.Gen.ClassGenVTable._vtable_name_needs_quote(vt_mangled) != 0: written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, "i8* @\"%s\"", vt_mangled) else: written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, "i8* @%s", vt_mangled) pos_v += sizet(written_v) # 字段 1..N 优先按字段默认值折叠(vtable 对象全局 # 如 `_mbuddy: MemBuddy` 的字段默认不再丢失); # 全部默认值恰为零时回退逐字段零值,避免无谓文本。 # 两者均列全字段(LLVM 要求初始化器元素数匹配)。 rest_v: str = self._build_stg_struct_body_text(pool, resolved_stg_entry, 1) if rest_v is not None: written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, ", %s", rest_v) pos_v += sizet(written_v) else: fc_v: int = resolved_stg_entry.FieldCount for fi_v in range(1, fc_v): fe_v: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(resolved_stg_entry, fi_v) if fe_v is None or fe_v.Ty is None: continue ty_buf_v: str = pool.alloc(128) if ty_buf_v is None: continue llvmlite.TypePrint(ty_buf_v, 128, fe_v.Ty, pool) zero_v: str = self._stg_field_zero_text(pool, fe_v.Ty, ty_buf_v) if zero_v is None: continue written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, ", %s", zero_v) pos_v += sizet(written_v) viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, " }") stg_init_text = init_full elif resolved_stg_entry is not None: # 无 vtable 的对象全局(@t.Object / 普通类):按字段默认值生成常量初始化器; # 一律 zeroinitializer 会丢掉全部字段默认值(模块级 X: T = T() 的构造调用 # 不发射)。无任何非零默认值时返回 None → 保持 zeroinitializer(零开销)。 stg_default_text: str = self._build_stg_struct_init_text(pool, resolved_stg_entry, 0) if stg_default_text is not None: stg_init_text = stg_default_text stg_name_len: sizet = sizet(string.strlen(mangled_name)) + 8 stg_name_buf: str = pool.alloc(stg_name_len) if stg_name_buf is not None: viperlib.snprintf(stg_name_buf, stg_name_len, "%s.stg", mangled_name) stg_gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, stg_name_buf, resolved_stg_ty) if stg_gv is not None: llvmlite.module_add_global(mod, stg_gv) stg_gv.Linkage = None stg_gv.Initializer = stg_init_text # B5:storage(BSS 对象实例)同样施加 aligned 对齐 if resolved_stg_entry is not None and resolved_stg_entry.Align > 0: stg_gv.Align = resolved_stg_entry.Align # @g 初始值 = &@storage(对象引用指向 BSS 实例,非 NULL) stg_init_len: sizet = sizet(string.strlen(mangled_name)) + 8 stg_init_buf: str = pool.alloc(stg_init_len) if stg_init_buf is not None: if self.Gen.ClassGenVTable._vtable_name_needs_quote(stg_name_buf) != 0: viperlib.snprintf(stg_init_buf, stg_init_len, "@\"%s\"", stg_name_buf) else: viperlib.snprintf(stg_init_buf, stg_init_len, "@%s", stg_name_buf) gv.Initializer = stg_init_buf # 注册 storage 引用(key: var_name.__stg),供 AssignGenMixin # 全局赋值分支检测对象类全局并复制对象到 storage。 stg_ref: llvmlite.Value* = self.Gen.ExprGenAttr.make_global_ref(pool, stg_name_buf, resolved_stg_ty) if stg_ref is not None: stg_key_len: sizet = sizet(string.strlen(var_name)) + 8 stg_key: str = pool.alloc(stg_key_len) if stg_key is not None: viperlib.snprintf(stg_key, stg_key_len, "%s.__stg", var_name) self.Gen.VarGen.define_module_var(trans.SymTab, stg_key, stg_ref) # 创建 Value 引用(@mangled_name, 类型为 var_ty*) var_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, var_ty) ref_name: str = pool.alloc(96) if ref_name is not None: # mangled 名带 SHA1 前缀(数字开头),引用必须加引号(对齐 make_global_ref) if self.Gen.ClassGenVTable._vtable_name_needs_quote(mangled_name) != 0: viperlib.snprintf(ref_name, 96, "@\"%s\"", mangled_name) else: viperlib.snprintf(ref_name, 96, "@%s", mangled_name) gv_ref: llvmlite.Value* = llvmlite.SSAValue(pool, var_ptr_ty, ref_name) # 注册到模块作用域 if self.Gen.VarGen.define_module_var(trans.SymTab, var_name, gv_ref) == 0: # t.CVolatile 存储类标记(注解联合含 t.CVolatile)→ 标记全局变量 # volatile:所有 load/store 带 LLVM volatile,禁止优化器把忙等循环 # 的重复 load 提升/消除(如 `locked: t.CVolatile | t.CInt`)。 if annot_node is not None: # const 对象全局:注解含 t.CConst 且类型非指针 ⇒ 登记 IsConst, # 之后对该全局名的赋值/增量赋值/元素赋值 fail-fast(判据同 TPC # 的 Gen.global_const_flags,见 Debugger/type-descriptors.md)。 if self.Gen.TypeGenErr.is_const_object_marker(annot_node, var_ty) != 0: self.Gen.VarGen.set_var_const(trans.SymTab, var_name) if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CVolatile", 0) != 0: self.Gen.VarGen.set_var_volatile(trans.SymTab, var_name) # rawptr[t.CVolatile | T](volatile 指针指向物):解引用(p[i]/ # p.field/c.Deref(p))的 load/store 带 volatile。与上一分支互斥: # 前者是变量自身限定(BinOp 联合),后者是 rawptr 下标实参标记。 if self.Gen.TypeGenErr.has_pointee_volatile_marker(annot_node) != 0: self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, var_name) # 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时, # 属性访问需要通过 AnnotClassName 回退到类名查找结构体) if k == ast.ASTKind.AnnAssign: aa_ml: ast.AnnAssign* = ast.AnnAssign*(node) if aa_ml is not None and aa_ml.annotation is not None: cls_nm_ml: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(aa_ml.annotation, trans._imported_modules, pool, trans._from_imports) if cls_nm_ml is not None: self.Gen.VarGen.set_var_annot_class_name(trans.SymTab, var_name, cls_nm_ml) # 模块级 str|t.CPtr / bytes|t.CPtr 全局:标记 IsPtrElement # (i8** 语义,var[i] 按 8 字节指针步长),对齐 TPC 的 # global_var_ptr_element(_argv 等字符串指针数组)。否则 # var[i] 退化为 1 字节字符步长 GEP + load i8 截断指针。 if aa_ml.annotation.kind() == ast.ASTKind.BinOp: bop_ml: ast.BinOp* = ast.BinOp*(aa_ml.annotation) if bop_ml.op == ast.OpKind.BitOr: if self.Gen.AssignGen._annotation_contains_name(aa_ml.annotation, "str") != 0 \ or self.Gen.AssignGen._annotation_contains_name(aa_ml.annotation, "bytes") != 0: self.Gen.VarGen.set_var_ptr_element(trans.SymTab, var_name) return 1 return 0 # ============================================================ # create_wrapper_main - 创建包装 main 函数 # # 当用户未定义 main 函数时调用。 # 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder → # 预扫描 alloca → 翻译子节点 → ret 0 # ============================================================ def create_wrapper_main(self, trans: HT.Translator*, tree: ast.AST*, i32_ty: llvmlite.LLVMType*) -> int: """创建包装 main 函数并翻译所有顶层语句 Args: trans: 翻译器(含所有共享状态) tree: AST 模块节点 i32_ty: i32 LLVMType Returns: int: 新增的变量数 """ pool: memhub.MemBuddy* = trans.Pool mod: llvmlite.LLVMModule* = trans.Module main_func: llvmlite.Function* = llvmlite.create_function(pool, mod, "main", i32_ty) if main_func is None: VLogger.error("CreateFunction main returned NULL", "TR") return 0 entry_blk: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, main_func, "entry") if entry_blk is None: VLogger.error("CreateBlock returned NULL", "TR") return 0 builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, main_func) if builder is None: VLogger.error("NewBuilder returned NULL", "TR") return 0 llvmlite.position_at_end(builder, entry_blk) # 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问) trans._cur_func = main_func trans._cur_builder = builder # 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量 # 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca, # 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR) ch: list[ast.AST*]* = tree.children if ch is not None: cn_count: sizet = len(ch) for ci in range(cn_count): child: ast.AST* = ch.get(ci) if child is not None: kd: int = child.kind() if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign: self.handle_module_level_var(trans, child) # 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca # (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们) if ch is not None: for ci in range(cn_count): child: ast.AST* = ch.get(ci) if child is not None: self.Gen.StmtGenDecl.pre_scan_allocas(trans, child) # 翻译子节点 added_total: int = self.translate_children(trans, tree) # 返回 0 zero_val: llvmlite.Value* = llvmlite.const_int32(pool, 0) llvmlite.build_ret(builder, zero_val) return added_total # ============================================================ # global/nonlocal 名称管理(迁移自 HandlesTranslator.vp 模块级函数) # ============================================================ def add_global_name(self, trans: HT.Translator*, name: str): """添加一个 global 变量名""" if trans is None or name is None: return if trans._global_names is None: return # 检查是否已存在 if self.is_global_name(trans, name) != 0: return if trans._global_name_count >= HT.MAX_GLOBAL_NAMES: pool_err: memhub.MemBuddy* = trans.Pool err_buf: str = None if pool_err is not None: err_buf = pool_err.alloc(256) if err_buf is not None: viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", HT.MAX_GLOBAL_NAMES) VLogger.error(err_buf, "ScopeDecl") else: VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") return entry_addr: uint64 = uint64(trans._global_names) + trans._global_name_count * 8 slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr) slot_ptr[0] = name trans._global_name_count += 1 def is_global_name(self, trans: HT.Translator*, name: str) -> int: """检查 name 是否在当前函数的 global 集合中""" if trans is None or name is None or trans._global_names is None: return 0 for i in range(trans._global_name_count): entry_addr: uint64 = uint64(trans._global_names) + i * 8 slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr) entry: str = slot_ptr[0] if entry is not None: if string.strcmp(entry, name) == 0: return 1 return 0 def add_nonlocal_name(self, trans: HT.Translator*, name: str, var_ty: llvmlite.LLVMType* = None): """添加一个 nonlocal 变量名 Args: name: nonlocal 变量名 var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复, None 时回退为 i32) """ if trans is None or name is None: return if trans._nonlocal_names is None: return if self.is_nonlocal_name(trans, name) != 0: # 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新) # _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。 # 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致), # [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。 if var_ty is not None and trans._nonlocal_types is not None: idx: int = self.get_nonlocal_index(trans, name) if idx >= 0: ty_addr: uint64 = uint64(trans._nonlocal_types) + idx * 8 ty_slot: str | t.CPtr = (str | t.CPtr)(ty_addr) ty_slot[0] = var_ty return if trans._nonlocal_name_count >= HT.MAX_GLOBAL_NAMES: pool_err_nl: memhub.MemBuddy* = trans.Pool err_buf_nl: str = None if pool_err_nl is not None: err_buf_nl = pool_err_nl.alloc(256) if err_buf_nl is not None: viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", HT.MAX_GLOBAL_NAMES) VLogger.error(err_buf_nl, "ScopeDecl") else: VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl") return entry_addr: uint64 = uint64(trans._nonlocal_names) + trans._nonlocal_name_count * 8 slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr) slot_ptr[0] = name # 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致) if trans._nonlocal_types is not None: ty_addr2: uint64 = uint64(trans._nonlocal_types) + trans._nonlocal_name_count * 8 ty_slot2: str | t.CPtr = (str | t.CPtr)(ty_addr2) # var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32 stored_ty: llvmlite.LLVMType* = var_ty if stored_ty is None: self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError") return ty_slot2[0] = stored_ty trans._nonlocal_name_count += 1 trans._closure_env_count += 1 def get_nonlocal_type(self, trans: HT.Translator*, name: str) -> llvmlite.LLVMType*: """获取 nonlocal 变量的 LLVM 类型 Returns: 找到的类型指针,找不到返回 None """ if trans is None or name is None or trans._nonlocal_types is None: return None idx: int = self.get_nonlocal_index(trans, name) if idx < 0: return None ty_addr: uint64 = uint64(trans._nonlocal_types) + idx * 8 ty_slot: str | t.CPtr = (str | t.CPtr)(ty_addr) return (llvmlite.LLVMType*)(ty_slot[0]) def is_nonlocal_name(self, trans: HT.Translator*, name: str) -> int: """检查 name 是否在当前函数的 nonlocal 集合中""" if trans is None or name is None or trans._nonlocal_names is None: return 0 for i in range(trans._nonlocal_name_count): entry_addr: uint64 = uint64(trans._nonlocal_names) + i * 8 slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr) entry: str = slot_ptr[0] if entry is not None: if string.strcmp(entry, name) == 0: return 1 return 0 def get_nonlocal_index(self, trans: HT.Translator*, name: str) -> int: """获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1""" if trans is None or name is None or trans._nonlocal_names is None: return -1 for i in range(trans._nonlocal_name_count): entry_addr: uint64 = uint64(trans._nonlocal_names) + i * 8 slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr) entry: str = slot_ptr[0] if entry is not None: if string.strcmp(entry, name) == 0: return i return -1 def clear_scope_names(self, trans: HT.Translator*): """清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)""" if trans is None: return trans._global_name_count = 0 trans._nonlocal_name_count = 0 trans._closure_env_count = 0