import t, c from stdint import * import string import stdio import stdlib import viperlib import memhub from linkedlist import GSList, GSListNode from .__types import LLVMType, TypePrint, Array, PrintStructDefinition, get_struct_name, Struct, ParamNode from .__function import Function, FunctionPrint, _ll_name_needs_quote, Param # ============================================================ # GlobalVariable: LLVM IR 全局变量 # # 持有名称 + 类型 + 初始化值 + 常量标志 + 链接类型。 # 继承 GSListNode[GlobalVariable] 获取强类型 Next。 # ============================================================ @t.NoVTable class GlobalVariable(GSListNode[GlobalVariable]): Name: t.CChar | t.CPtr # 全局变量名(如 ".str" / "my_global") Ty: LLVMType | t.CPtr # 变量类型 Initializer: t.CVoid | t.CPtr # 初始化值 Value*(None = 无初始化) IsConstant: t.CInt # 1=constant, 0=variable Linkage: t.CChar | t.CPtr # 链接类型("private"/"internal"/"external"/...) Section: t.CChar | t.CPtr # 段名(None = 默认) UnnamedAddr: t.CInt # 1=unnamed_addr, 2=local_unnamed_addr, 0=none # ============================================================ # NamedTypeNode: 命名结构体类型链表节点 # # 持有 LLVMType* 指针(必须是命名 Struct 类型)。 # 继承 GSListNode[NamedTypeNode] 获取强类型 Next。 # ============================================================ @t.NoVTable class NamedTypeNode(GSListNode[NamedTypeNode]): Ty: LLVMType | t.CPtr # 命名结构体类型指针 # ============================================================ # LLVMModule: LLVM IR 模块容器 # # 使用嵌入式 Head/Tail/Count 字段代替 GSList 指针, # 避免泛型 GSList 的 __sizeof__ 返回 0 和 vtable 偏移不一致问题。 # LLVMModulePrint 输出完整 .ll 文件内容。 # 注意: 类名必须为 LLVMModule 而非 Module,避免与 ast.Module 命名冲突 # ============================================================ @t.NoVTable class LLVMModule: Name: t.CChar | t.CPtr # 模块名 FuncHead: Function | t.CPtr # 函数链表头 FuncTail: Function | t.CPtr # 函数链表尾 FuncCount: t.CSizeT # 函数计数 GlobalHead: GlobalVariable | t.CPtr # 全局变量链表头 GlobalTail: GlobalVariable | t.CPtr # 全局变量链表尾 GlobalCount: t.CSizeT # 全局变量计数 TargetTriple: t.CChar | t.CPtr # 目标三元组(如 "x86_64-pc-linux-gnu") DataLayout: t.CChar | t.CPtr # 数据布局(如 "e-m:e-p270:32:32-...") NamedTypeHead: NamedTypeNode | t.CPtr # 命名结构体类型链表头 NamedTypeTail: NamedTypeNode | t.CPtr # 命名结构体类型链表尾 NamedTypeCount: t.CSizeT # 命名结构体类型计数 # 总计: 12 字段 * 8 = 96 字节(无 vtable) # ============================================================ # 实例方法(对象化重构:原 module_* 顶层函数改写为方法, # 原顶层函数保留为一行委托) # ============================================================ # ---- 链表操作 ---- def add_function(self, func: Function | t.CPtr): """将函数追加到模块函数链表(O(1))""" if self is None or func is None: return func.Next = None if self.FuncHead is None: self.FuncHead = func else: self.FuncTail.Next = func self.FuncTail = func self.FuncCount += 1 def add_global(self, gv: GlobalVariable | t.CPtr): """将全局变量追加到模块全局变量链表(O(1))""" if self is None or gv is None: return gv.Next = None if self.GlobalHead is None: self.GlobalHead = gv else: self.GlobalTail.Next = gv self.GlobalTail = gv self.GlobalCount += 1 # ---- 目标属性 ---- def set_target(self, triple: t.CChar | t.CPtr): """设置目标三元组""" if self is None: return self.TargetTriple = triple def set_datalayout(self, layout: t.CChar | t.CPtr): """设置数据布局""" if self is None: return self.DataLayout = layout # ---- 命名结构体类型管理 ---- def add_named_type(self, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr): """将命名结构体类型添加到模块(用于输出 %"name" = type { ... } 定义行) 非命名结构体(Name 为 None 或非 Struct 类型)会被忽略。 按 Name 去重;同名时 opaque 声明可被完整定义替换(供跨模块值类型 alloca)。 """ if self is None or pool is None or ty is None: return name: t.CChar | t.CPtr = get_struct_name(ty) if name is None: return # 去重检查(opaque 声明可被完整定义替换) cur: NamedTypeNode | t.CPtr = self.NamedTypeHead cnt_dedup: t.CInt = 0 while cur is not None: # 步数守卫:NamedTypeHead 链表成环(内存损坏/插入 bug)会导致 # 无限遍历挂起(G3 编译 LinkedNode.prepend 挂起根因)。 # 正常链表节点数远小于此上限,超限即链表损坏 → 立即报错终止。 cnt_dedup += 1 if cnt_dedup > 100000: stdio.printf("[ANT-LOOP] NamedTypeHead 链表疑似成环, name=%s, 遍历节点=%d, 强制终止\n", name if name is not None else "(null)", cnt_dedup) stdlib.exit(1) if cur.Ty is not None: existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty) if existing_name is not None: if string.strcmp(existing_name, name) == 0: # 已有完整定义则无需替换 if _is_opaque_struct(cur.Ty) == 0: return # 已有 opaque,新类型也是 opaque 则不重复 if _is_opaque_struct(ty) != 0: return # 用完整定义替换 opaque 声明(原地替换 Ty 指针) cur.Ty = ty return cur = cur.Next # 创建新节点 node: NamedTypeNode | t.CPtr = pool.alloc(NAMED_TYPE_NODE_SIZE) if node is None: return string.memset(node, 0, NAMED_TYPE_NODE_SIZE) node.Ty = ty # opaque 类型插入链表头部,确保在引用它的完整定义之前声明。 # 例如 TypeRegistry{HashTable*, ...} 中,HashTable 的 opaque 声明 # 必须在 TypeRegistry 定义之前,否则 llc 报 "use of undefined type"。 # 完整定义追加到链表尾部,保持原有顺序。 if _is_opaque_struct(ty) != 0: node.Next = self.NamedTypeHead if self.NamedTypeHead is None: self.NamedTypeTail = node self.NamedTypeHead = node else: node.Next = None if self.NamedTypeHead is None: self.NamedTypeHead = node else: self.NamedTypeTail.Next = node self.NamedTypeTail = node self.NamedTypeCount += 1 def _is_type_defined_in_module(self, name: t.CChar | t.CPtr) -> int: """检查模块中是否已定义指定名称的结构体类型,返回 1=已定义 / 0=未定义""" if self is None or name is None: return 0 cur: NamedTypeNode | t.CPtr = self.NamedTypeHead cnt_tdm: t.CInt = 0 while cur is not None: # 步数守卫:同上,防 NamedTypeHead 链表成环无限遍历 cnt_tdm += 1 if cnt_tdm > 100000: stdio.printf("[TDM-LOOP] NamedTypeHead 链表疑似成环, name=%s, 强制终止\n", name if name is not None else "(null)") stdlib.exit(1) if cur.Ty is not None: existing_name: t.CChar | t.CPtr = get_struct_name(cur.Ty) if existing_name is not None: if string.strcmp(existing_name, name) == 0: return 1 cur = cur.Next return 0 def ensure_opaque_for_type(self, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr): """为类型中的跨模块结构体引用添加 opaque 声明 当类型引用了 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时, 如果该名称未在模块中定义,则添加 opaque 声明。 """ _scan_type_for_cross_module_refs(pool, self, ty) # ---- 打印 ---- def PrintModule(self, buf: t.CChar | t.CPtr, size: t.CSizeT, pool: memhub.MemBuddy | t.CPtr, mode: t.CInt): """将模块序列化为 .ll 文本写入 buf""" if self is None or buf is None or size == 0: return # 头部注释(stub 和 full 模式输出,text 模式不输出) if mode == OUTPUT_FULL or mode == OUTPUT_STUB: _append_cstr(buf, size, "; ModuleID = '") if self.Name is not None: _append_cstr(buf, size, self.Name) _append_cstr(buf, size, "'\n") # 目标三元组 if self.TargetTriple is not None: _append_cstr(buf, size, "target triple = \"") _append_cstr(buf, size, self.TargetTriple) _append_cstr(buf, size, "\"\n") # 数据布局 if self.DataLayout is not None: _append_cstr(buf, size, "target datalayout = \"") _append_cstr(buf, size, self.DataLayout) _append_cstr(buf, size, "\"\n") # 空行 _append_cstr(buf, size, "\n") # 命名结构体类型定义(stub 和 full 模式输出,text 模式不输出) if mode == OUTPUT_FULL or mode == OUTPUT_STUB: # 扫描所有函数签名,为跨模块结构体引用添加 opaque 定义 # 确保 stub.ll 包含被 declare/define 引用的跨模块类型定义 # 修复:alloc_buf 返回 viperio.Buf,但 Buf 类型未在 NamedTypeHead 中注册 func_scan: Function | t.CPtr = self.FuncHead while func_scan is not None: if func_scan.RetTy is not None: self.ensure_opaque_for_type(pool, func_scan.RetTy) if func_scan.Params is not None: param_scan: Param | t.CPtr = func_scan.Params.Head while param_scan is not None: if param_scan.Ty is not None: self.ensure_opaque_for_type(pool, param_scan.Ty) param_scan = param_scan.Next func_scan = func_scan.Next nt: NamedTypeNode | t.CPtr = self.NamedTypeHead # 结构体定义缓冲区:48 字段 × ~50 字节/字段类型名 ≈ 2400 字节,4096 足够 # 在循环外分配一次并复用,减少 pool 碎片 ty_buf: t.CChar | t.CPtr = pool.alloc(4096) while nt is not None: if nt.Ty is not None: if ty_buf is not None: ty_buf[0] = '\0' PrintStructDefinition(ty_buf, 4096, nt.Ty, pool) _append_cstr(buf, size, ty_buf) _append_cstr(buf, size, "\n") nt = nt.Next if self.NamedTypeHead is not None: _append_cstr(buf, size, "\n") # 全局变量 gv: GlobalVariable | t.CPtr = self.GlobalHead if mode == OUTPUT_STUB: # stub 模式:输出 external global(无初值) while gv is not None: _print_global_stub(buf, size, gv, pool) _append_cstr(buf, size, "\n") gv = gv.Next else: # full 和 text 模式:输出完整全局变量 # text 模式跳过无初值的全局变量(纯声明) gv_idx: t.CInt = 0 while gv is not None: if mode == OUTPUT_TEXT and gv.Initializer is None: gv = gv.Next gv_idx += 1 continue _print_global(buf, size, gv, pool) _append_cstr(buf, size, "\n") gv = gv.Next gv_idx += 1 if self.GlobalHead is not None and (mode == OUTPUT_FULL or mode == OUTPUT_STUB): _append_cstr(buf, size, "\n") elif self.GlobalHead is not None and mode == OUTPUT_TEXT: # text 模式下如果输出了全局变量,也加空行 had_global: t.CInt = 0 gv2: GlobalVariable | t.CPtr = self.GlobalHead while gv2 is not None: if gv2.Initializer is not None: had_global = 1 break gv2 = gv2.Next if had_global != 0: _append_cstr(buf, size, "\n") # 遍历函数 func: Function | t.CPtr = self.FuncHead func_idx: t.CInt = 0 while func is not None: if mode == OUTPUT_STUB: # stub 模式:仅输出 declare(IsDeclared==1) if func.IsDeclared == 1: FunctionPrint(buf, size, func, pool) _append_cstr(buf, size, "\n") elif mode == OUTPUT_TEXT: # text 模式:仅输出 define(IsDeclared==0) if func.IsDeclared == 0: FunctionPrint(buf, size, func, pool) _append_cstr(buf, size, "\n") else: # full 模式:输出所有函数 FunctionPrint(buf, size, func, pool) _append_cstr(buf, size, "\n") func = func.Next func_idx += 1 # ============================================================ # 工厂函数 # ============================================================ def new_module(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> LLVMModule | t.CPtr: """创建一个模块""" # 硬编码 96 字节:12 字段 * 8 字节(无 vtable,@t.NoVTable) ptr: LLVMModule | t.CPtr = pool.alloc(96) if ptr is None: return None string.memset(ptr, 0, 96) ptr.Name = name ptr.FuncHead = None ptr.FuncTail = None ptr.FuncCount = 0 ptr.GlobalHead = None ptr.GlobalTail = None ptr.GlobalCount = 0 ptr.TargetTriple = None ptr.DataLayout = None ptr.NamedTypeHead = None ptr.NamedTypeTail = None ptr.NamedTypeCount = 0 return ptr # GlobalVariable 硬编码大小: Next(8) + Name(8) + Ty(8) + Initializer(8) + IsConstant(4) + Linkage(8) + Section(8) + UnnamedAddr(4) = 64 字节 GV_SIZE: t.CDefine = 64 # NamedTypeNode 硬编码大小: Next(8) + Ty(8) = 16 字节 NAMED_TYPE_NODE_SIZE: t.CDefine = 16 def new_global_variable(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr, ty: LLVMType | t.CPtr) -> GlobalVariable | t.CPtr: """创建一个全局变量""" ptr: GlobalVariable | t.CPtr = pool.alloc(GV_SIZE) if ptr is None: return None string.memset(ptr, 0, GV_SIZE) ptr.Name = name ptr.Ty = ty ptr.Initializer = None ptr.IsConstant = 0 ptr.Linkage = "external" ptr.Section = None ptr.UnnamedAddr = 0 return ptr # ============================================================ # 链表操作(嵌入式 Head/Tail/Count,O(1) 追加) # ============================================================ def module_add_function(mod: LLVMModule | t.CPtr, func: Function | t.CPtr): return mod.add_function(func) def module_add_global(mod: LLVMModule | t.CPtr, gv: GlobalVariable | t.CPtr): return mod.add_global(gv) def module_set_target(mod: LLVMModule | t.CPtr, triple: t.CChar | t.CPtr): return mod.set_target(triple) def module_set_datalayout(mod: LLVMModule | t.CPtr, layout: t.CChar | t.CPtr): return mod.set_datalayout(layout) # ============================================================ # 命名结构体类型管理 # ============================================================ # ============================================================ # _is_opaque_struct - 检查类型是否是 opaque 结构体 # # opaque 结构体特征: Struct 类型,fcount == -1(哨兵标记,跨模块前向 # 声明,仅名称无字段定义)。通过 Struct(pool, None, -1, name) 创建, # IR 输出为 %"name" = type opaque。注意区分空结构体(fcount==0, # fields==None,无字段类)——它是合法完整定义(= type {},可 alloca)。 # 用于在 module_add_named_type 中区分 opaque 声明和完整定义, # 确保 opaque 声明插入链表头部(在使用之前声明)。 # # Returns: 1=是 opaque / 0=否 # ============================================================ def _is_opaque_struct(ty: LLVMType | t.CPtr) -> int: """检查类型是否是 opaque 结构体 opaque 是跨模块前向声明(仅名称无字段定义),由 _scan_type_for_cross_module_refs 创建,fcount=-1 哨兵标记。 空结构体(fcount==0, fields==None,无字段类)是合法完整定义 (LLVM {} 类型,可 alloca),必须与 opaque 区分——此前混淆导致 空类结构体被输出为 "= type opaque",alloca 报 Cannot allocate unsized type。 """ if ty is None: return 0 match ty: case LLVMType.Struct(fields, fcount, name): # opaque: fcount == -1(哨兵) if fcount < 0: return 1 return 0 case _: return 0 def module_add_named_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr): return mod.add_named_type(pool, ty) # ============================================================ # module_ensure_opaque_for_type - 为类型中的跨模块结构体引用添加 opaque 声明 # # 递归扫描 LLVMType 树,当遇到 Ptr(Struct(name)) 且 name 包含 '.'(SHA1 限定名)时, # 如果该名称未在模块中定义,则添加 opaque 声明(%"name" = type opaque)。 # 这解决了跨模块结构体引用导致的 llc "use of undefined type" 错误。 # ============================================================ def _is_type_defined_in_module(mod: LLVMModule | t.CPtr, name: t.CChar | t.CPtr) -> int: return mod._is_type_defined_in_module(name) def _scan_type_for_cross_module_refs(pool: memhub.MemBuddy | t.CPtr, mod: LLVMModule | t.CPtr, ty: LLVMType | t.CPtr, depth: t.CInt = 0): """递归扫描类型树,为跨模块结构体引用添加 opaque 声明""" if ty is None or mod is None or pool is None: return # 深度守卫:自引用结构体(链表/树节点,如 Node{...; Ptr(Node) next}) # 会无限递归栈溢出,与其他递归(TypePrint/DeepCopyType)一致设上限 if depth >= 100: return match ty: case LLVMType.Ptr(pointee): if pointee is not None: match pointee: case LLVMType.Struct(sfields, sfcount, sname): if sname is not None: # 检查是否为跨模块引用(名称包含 '.') if string.strchr(sname, 46) is not None: # 检查是否已在模块中定义 if _is_type_defined_in_module(mod, sname) == 0: # 创建 opaque 类型并添加到模块 # fcount=-1 哨兵标记 opaque(区别于空结构体 {}, # 后者 fcount==0 是合法完整定义,可 alloca) opaque_ty: LLVMType | t.CPtr = Struct(pool, None, -1, sname) if opaque_ty is not None: module_add_named_type(mod, pool, opaque_ty) # 递归扫描结构体字段中的跨模块引用 # 例如 TypeRegistry{HashTable*, MemManager*} 中的 HashTable 引用 if sfields is not None: fld: ParamNode | t.CPtr = sfields while fld is not None: if fld.Ty is not None: _scan_type_for_cross_module_refs(pool, mod, fld.Ty, depth + 1) fld = fld.Next case _: _scan_type_for_cross_module_refs(pool, mod, pointee, depth + 1) case LLVMType.Struct(sfields2, sfcount2, sname2): # 顶层结构体(非指针):递归扫描字段 if sfields2 is not None: fld2: ParamNode | t.CPtr = sfields2 while fld2 is not None: if fld2.Ty is not None: _scan_type_for_cross_module_refs(pool, mod, fld2.Ty, depth + 1) fld2 = fld2.Next case LLVMType.Array(elem_ty, acount): if elem_ty is not None: _scan_type_for_cross_module_refs(pool, mod, elem_ty, depth + 1) case _: pass def module_ensure_opaque_for_type(mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr): return mod.ensure_opaque_for_type(pool, ty) # ============================================================ # 全局变量属性设置 # ============================================================ def global_set_constant(gv: GlobalVariable | t.CPtr, is_const: t.CInt): """设置全局变量是否为常量""" if gv is None: return gv.IsConstant = is_const def global_set_linkage(gv: GlobalVariable | t.CPtr, linkage: t.CChar | t.CPtr): """设置链接类型 (private/internal/external/... )""" if gv is None: return gv.Linkage = linkage def global_set_unnamed_addr(gv: GlobalVariable | t.CPtr, level: t.CInt): """设置 unnamed_addr 属性 (0=none, 1=unnamed_addr, 2=local_unnamed_addr)""" if gv is None: return gv.UnnamedAddr = level def global_set_section(gv: GlobalVariable | t.CPtr, section: t.CChar | t.CPtr): """设置段名""" if gv is None: return gv.Section = section # ============================================================ # 输出模式常量 # ============================================================ OUTPUT_FULL: t.CDefine = 0 # 完整 IR(stub + text) OUTPUT_STUB: t.CDefine = 1 # 仅声明(header + 类型定义 + declare + external global) OUTPUT_TEXT: t.CDefine = 2 # 仅代码(define + global 带初值) # ============================================================ # LLVMModulePrint: 将模块序列化为 .ll 文本 # # mode: OUTPUT_FULL=完整, OUTPUT_STUB=仅声明, OUTPUT_TEXT=仅代码 # ============================================================ def LLVMModulePrint(buf: t.CChar | t.CPtr, size: t.CSizeT, mod: LLVMModule | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mode: t.CInt): return mod.PrintModule(buf, size, pool, mode) # ============================================================ # 全局变量打印 # ============================================================ def _print_global(buf: t.CChar | t.CPtr, size: t.CSizeT, gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr): """打印单个全局变量: @ = [linkage] [unnamed_addr] [constant] """ if gv is None: return _append_cstr(buf, size, "@") if gv.Name is not None: if _ll_name_needs_quote(gv.Name) != 0: _append_cstr(buf, size, "\"") _append_cstr(buf, size, gv.Name) _append_cstr(buf, size, "\"") else: _append_cstr(buf, size, gv.Name) _append_cstr(buf, size, " = ") # 链接类型(有初始值时不输出 external,因为 external + 初始值是非法 IR) if gv.Linkage is not None: if gv.Initializer is not None and string.strcmp(gv.Linkage, "external") == 0: pass else: _append_cstr(buf, size, gv.Linkage) _append_cstr(buf, size, " ") # unnamed_addr if gv.UnnamedAddr == 1: _append_cstr(buf, size, "unnamed_addr ") elif gv.UnnamedAddr == 2: _append_cstr(buf, size, "local_unnamed_addr ") # constant / global if gv.IsConstant == 1: _append_cstr(buf, size, "constant ") else: _append_cstr(buf, size, "global ") # 类型 ty_buf: t.CChar | t.CPtr = pool.alloc(512) if ty_buf is not None: ty_buf[0] = '\0' TypePrint(ty_buf, 512, gv.Ty, pool) _append_cstr(buf, size, ty_buf) # 初始化值 if gv.Initializer is not None: _append_cstr(buf, size, " ") _append_cstr(buf, size, gv.Initializer) # 段名 if gv.Section is not None: _append_cstr(buf, size, ", section \"") _append_cstr(buf, size, gv.Section) _append_cstr(buf, size, "\"") # ============================================================ # _print_global_stub - 打印全局变量的声明形式(external global,无初值) # ============================================================ def _print_global_stub(buf: t.CChar | t.CPtr, size: t.CSizeT, gv: GlobalVariable | t.CPtr, pool: memhub.MemBuddy | t.CPtr): """打印全局变量声明: @ = external global """ if gv is None: return _append_cstr(buf, size, "@") if gv.Name is not None: if _ll_name_needs_quote(gv.Name) != 0: _append_cstr(buf, size, "\"") _append_cstr(buf, size, gv.Name) _append_cstr(buf, size, "\"") else: _append_cstr(buf, size, gv.Name) _append_cstr(buf, size, " = external global ") # 类型 ty_buf: t.CChar | t.CPtr = pool.alloc(512) if ty_buf is not None: ty_buf[0] = '\0' TypePrint(ty_buf, 512, gv.Ty, pool) _append_cstr(buf, size, ty_buf) # ============================================================ # 内部辅助 # ============================================================ def _append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT, src: t.CChar | t.CPtr): """将 C 字符串 src 追加到 dst 末尾""" if dst is None or src is None: return dlen: t.CSizeT = string.strlen(dst) # 无符号下溢防护:dlen 超过缓冲大小时(缓冲已被破坏/悬空)直接返回, # 否则 remain = dst_size - dlen 下溢成巨值会把 dst[dlen+i] 写穿到缓冲外 if dlen >= dst_size: return slen: t.CSizeT = string.strlen(src) remain: t.CSizeT = dst_size - dlen if remain <= 0: return i: t.CSizeT = 0 while i < slen and i + 1 < remain: dst[dlen + i] = src[i] i += 1 dst[dlen + i] = '\0'