import t, c from stdint import * import string import viperlib import memhub import stdio from linkedlist import GSListNode, GSList from .__types import LLVMType, ParamNode, TypePrint # ============================================================ # Line: 指令文本行 # # 每条 LLVM IR 指令序列化为一行文本,通过链表组织。 # 继承 GSListNode[Line] 获取强类型 Next: Line|CPtr # # 注意: 必须加 @t.NoVTable。否则 TransPyC 为子类添加 vtable 指针(T*), # 但完全丢失父类 GSListNode[T] 的 Next 字段,导致 struct 布局错位, # 所有字段访问读取垃圾值(见续 XV 会话根因分析)。 # ============================================================ @t.NoVTable class Line(GSListNode[Line]): Buf: t.CChar | t.CPtr # 行文本(NUL 结尾) Len: t.CSizeT # 文本长度(不含 NUL) # ============================================================ # BasicBlock: 基本块 # # 持有名称 + 指令行链表 + 终止指令标志。 # 继承 GSListNode[BasicBlock] 获取强类型 Next: BasicBlock|CPtr # Lines 为 GSList[Line] 指针,提供 O(1) 追加。 # # 注意: 必须加 @t.NoVTable(理由同 Line)。 # ============================================================ @t.NoVTable class BasicBlock(GSListNode[BasicBlock]): Name: t.CChar | t.CPtr # 块名(如 "entry"/"if.then") Lines: GSList[Line] | t.CPtr # 指令行链表容器(Head/Tail/Count) IsTerminated: t.CInt # 1=已有终止指令(br/ret) # ============================================================ # Param: 函数参数 # # 继承 GSListNode[Param] 获取强类型 Next: Param|CPtr # Attrs 存储参数属性文本(如 "noundef"/"nocapture"/"readonly"),None=无属性 # # 注意: 必须加 @t.NoVTable(理由同 Line)。 # ============================================================ @t.NoVTable class Param(GSListNode[Param]): Ty: LLVMType | t.CPtr # 参数类型 Name: t.CChar | t.CPtr # 参数名(如 "%0"/"%a") Attrs: t.CChar | t.CPtr # 参数属性文本(None=无属性) # ============================================================ # Function: 函数 # # 持有名称 + 返回类型 + 参数链表 + 基本块链表。 # 继承 GSListNode[Function] 获取强类型 Next: Function|CPtr # Params/Blocks 为 GSList 指针,提供 O(1) 追加。 # Attrs 存储函数级属性文本(如 "nounwind"/"noinline"),None=无属性 # # 注意: 必须加 @t.NoVTable(理由同 Line)。 # ============================================================ @t.NoVTable class Function(GSListNode[Function]): Name: t.CChar | t.CPtr # 函数名 RetTy: LLVMType | t.CPtr # 返回类型 Params: GSList[Param] | t.CPtr # 参数链表容器 Blocks: GSList[BasicBlock] | t.CPtr # 基本块链表容器 IsDeclared: t.CInt # 1=仅声明(declare), 0=定义(define) IsVarArg: t.CInt # 1=变参函数(...) Attrs: t.CChar | t.CPtr # 函数属性文本(None=无属性) # ============================================================ # 工厂函数 # ============================================================ # Line 硬编码大小: Next(8) + Buf(8) + Len(8) = 24 字节 LINE_SIZE: t.CDefine = 24 def new_line(pool: memhub.MemBuddy | t.CPtr, text: t.CChar | t.CPtr) -> Line | t.CPtr: """创建一个指令行,复制 text 到新分配的缓冲区""" ptr: Line | t.CPtr = pool.alloc(LINE_SIZE) if ptr is None: return None string.memset(ptr, 0, LINE_SIZE) if text is not None: slen: t.CSizeT = string.strlen(text) buf: t.CChar | t.CPtr = pool.alloc(slen + 1) if buf is not None: string.strcpy(buf, text) ptr.Buf = buf ptr.Len = slen return ptr def _new_gslist(pool: memhub.MemBuddy | t.CPtr, list_size: t.CSizeT) -> t.CPtr: """从 pool 分配并零初始化一个 GSList 容器(Head/Tail/Count 全零)""" gsl: t.CPtr = pool.alloc(list_size) if gsl is None: return None string.memset(gsl, 0, list_size) return gsl # BasicBlock 硬编码大小: Next(8) + Name(8) + Lines(8) + IsTerminated(4) = 32 字节 BLOCK_SIZE: t.CDefine = 32 def new_basic_block(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr) -> BasicBlock | t.CPtr: """创建一个基本块""" ptr: BasicBlock | t.CPtr = pool.alloc(BLOCK_SIZE) if ptr is None: return None string.memset(ptr, 0, BLOCK_SIZE) ptr.Name = name ptr.Lines = _new_gslist(pool, 24) # GSList: Head+Tail+Count ptr.IsTerminated = 0 return ptr # Param 硬编码大小: Next(8) + Ty(8) + Name(8) + Attrs(8) = 32 字节 PARAM_SIZE: t.CDefine = 32 def new_param(pool: memhub.MemBuddy | t.CPtr, ty: LLVMType | t.CPtr, name: t.CChar | t.CPtr) -> Param | t.CPtr: """创建一个函数参数""" ptr: Param | t.CPtr = pool.alloc(PARAM_SIZE) if ptr is None: return None string.memset(ptr, 0, PARAM_SIZE) ptr.Ty = ty ptr.Name = name ptr.Attrs = None return ptr # Function 硬编码大小: Next(8) + Name(8) + RetTy(8) + Params(8) + Blocks(8) + IsDeclared(4) + IsVarArg(4) + Attrs(8) = 56 字节 FUNC_SIZE: t.CDefine = 56 def new_function(pool: memhub.MemBuddy | t.CPtr, name: t.CChar | t.CPtr, ret_ty: LLVMType | t.CPtr) -> Function | t.CPtr: """创建一个函数""" ptr: Function | t.CPtr = pool.alloc(FUNC_SIZE) if ptr is None: return None string.memset(ptr, 0, FUNC_SIZE) ptr.Name = name ptr.RetTy = ret_ty ptr.Params = _new_gslist(pool, 24) # GSList: Head+Tail+Count ptr.Blocks = _new_gslist(pool, 24) ptr.IsDeclared = 0 ptr.Attrs = None return ptr # ============================================================ # 链表操作(委托 GSList.append) # ============================================================ def function_add_param(func: Function | t.CPtr, param: Param | t.CPtr): """将参数追加到函数参数链表""" if func is None or param is None: return if func.Params is None: return func.Params.append(param) def function_add_block(func: Function | t.CPtr, block: BasicBlock | t.CPtr): """将基本块追加到函数块链表""" if func is None or block is None: return if func.Blocks is None: return func.Blocks.append(block) def function_move_block_to_end(func: Function | t.CPtr, block: BasicBlock | t.CPtr): """将 block 移动到函数块链表末尾(保证 BB 文本顺序与控制流顺序一致)。 用于解决 SSA 名非单调问题:BB 按创建顺序排列,但指令按控制流顺序生成, 导致 SSA 编号在文本输出时非单调递增,llc 报错。 在 position_at_end 时调用此函数,使 BB 顺序与 position 顺序一致。 注意:必须使用 GSList[BasicBlock] 带类型参数,否则 TransPyC 创建不完整 struct 类型,导致 blocks.Head/Tail/Count 字段访问读取垃圾值。 """ if func is None or block is None: return blocks: GSList[BasicBlock] | t.CPtr = func.Blocks if blocks is None: return # 已经是 Tail,无需移动 if blocks.Tail is block: return # 从链表中移除 block if blocks.Head is block: # block 是 Head,直接后移 Head blocks.Head = block.Next else: # 遍历找前驱 prev: BasicBlock | t.CPtr = blocks.Head while prev is not None and prev.Next is not block: prev = prev.Next if prev is None: # block 不在链表中,直接 append blocks.append(block) return prev.Next = block.Next # block.Next 由移除逻辑处理,重置为 None block.Next = None # append 到末尾(不调用 blocks.append 以避免 Count 重复递增) if blocks.Tail is not None: blocks.Tail.Next = block blocks.Tail = block def block_append_line(block: BasicBlock | t.CPtr, line: Line | t.CPtr): """将指令行追加到基本块""" if block is None or line is None: return if block.Lines is None: return block.Lines.append(line) def block_append_text(pool: memhub.MemBuddy | t.CPtr, block: BasicBlock | t.CPtr, text: t.CChar | t.CPtr): """创建指令行并追加到基本块""" if block is None or text is None: return line: Line | t.CPtr = new_line(pool, text) if line is not None: block_append_line(block, line) # ============================================================ # 属性设置 # ============================================================ def function_set_attrs(func: Function | t.CPtr, attrs: t.CChar | t.CPtr): """设置函数级属性文本(如 "nounwind"/"noinline")""" if func is None: return func.Attrs = attrs def param_set_attrs(param: Param | t.CPtr, attrs: t.CChar | t.CPtr): """设置参数属性文本(如 "noundef"/"nocapture"/"readonly")""" if param is None: return param.Attrs = attrs # ============================================================ # _ll_name_needs_quote - 检查 LLVM 标识符是否需要加引号 # # LLVM IR 规范:标识符合法字符集为 [-a-zA-Z$._][-a-zA-Z$._0-9]* # 以数字开头或含非合法字符(如 '['、']'、' '、'@' 等)时必须用双引号包围。 # '.' 是合法字符,不需要加引号(如 @.str、@llvm.memcpy 都不加引号)。 # SHA1 命名空间的函数名(如 "4dad2ba72ed7ba09.GSListNode[Param]")含 '['、']', # 需要加引号;但纯 hex+点 的名字(如 "abc.def")不需要。 # ============================================================ def _ll_name_needs_quote(name: str) -> t.CInt: """检查 LLVM 标识符是否需要加引号(以数字开头或含非合法字符) LLVM IR 合法字符:a-z, A-Z, 0-9, -, $, ., _ 首字符是数字时需要加引号(LLVM 要求局部/全局标识符首字符非数字,除非加引号)。 含其他字符(如 '['、']'、空格)时需要加引号。 """ if name is None: return 0 c0: t.CChar = name[0] if c0 >= '0' and c0 <= '9': return 1 name_len: t.CSizeT = string.strlen(name) i: t.CSizeT = 0 while i < name_len: ch: t.CChar = name[i] # 合法字符:a-z, A-Z, 0-9, -, $, ., _ if not ((ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or (ch >= '0' and ch <= '9') or ch == '-' or ch == '$' or ch == '.' or ch == '_'): return 1 i += 1 return 0 # ============================================================ # FunctionPrint: 将函数序列化为 IR 文本 # # 格式: # define @() { # : # # # : # # } # ============================================================ def FunctionPrint(buf: t.CChar | t.CPtr, size: t.CSizeT, func: Function | t.CPtr, pool: memhub.MemBuddy | t.CPtr): """将函数 func 序列化为 IR 文本写入 buf""" if func is None or buf is None or size == 0: return ty_buf: t.CChar | t.CPtr = pool.alloc(128) if ty_buf is None: return ty_buf[0] = '\0' # define @() if func.IsDeclared == 1: _append_cstr(buf, size, "declare ") else: _append_cstr(buf, size, "define ") ty_buf[0] = '\0' TypePrint(ty_buf, 128, func.RetTy, pool) _append_cstr(buf, size, ty_buf) _append_cstr(buf, size, " @") if func.Name is not None: if _ll_name_needs_quote(func.Name) != 0: _append_cstr(buf, size, "\"") _append_cstr(buf, size, func.Name) _append_cstr(buf, size, "\"") else: _append_cstr(buf, size, func.Name) _append_cstr(buf, size, "(") # 参数列表(从 GSList[Param].Head 遍历) cur: Param | t.CPtr = None if func.Params is not None: cur = func.Params.Head first: t.CInt = 1 while cur is not None: if first == 0: _append_cstr(buf, size, ", ") # 参数属性(如 "noundef"/"nocapture")在类型之前 if cur.Attrs is not None: _append_cstr(buf, size, cur.Attrs) _append_cstr(buf, size, " ") ty_buf[0] = '\0' TypePrint(ty_buf, 128, cur.Ty, pool) _append_cstr(buf, size, ty_buf) # declare 和 define 都打印参数名(如果有) if cur.Name is not None: _append_cstr(buf, size, " ") # LLVM IR 要求参数名以 % 开头 if cur.Name[0] != '%': _append_cstr(buf, size, "%") _append_cstr(buf, size, cur.Name) cur = cur.Next first = 0 # 变参函数追加 ... if func.IsVarArg == 1: if func.Params is not None and func.Params.Head is not None: _append_cstr(buf, size, ", ...") else: _append_cstr(buf, size, "...") _append_cstr(buf, size, ")") # 函数级属性(如 "nounwind"/"noinline")在 ) 之后 if func.Attrs is not None: _append_cstr(buf, size, " ") _append_cstr(buf, size, func.Attrs) if func.IsDeclared == 1: _append_cstr(buf, size, "\n") return # 函数体 _append_cstr(buf, size, " {\n") blk: BasicBlock | t.CPtr = None if func.Blocks is not None: blk = func.Blocks.Head while blk is not None: # 块标签 if blk.Name is not None: _append_cstr(buf, size, blk.Name) _append_cstr(buf, size, ":\n") # 指令行(从 GSList[Line].Head 遍历) line: Line | t.CPtr = None if blk.Lines is not None: line = blk.Lines.Head while line is not None: if line.Buf is not None: _append_cstr(buf, size, " ") _append_cstr(buf, size, line.Buf) _append_cstr(buf, size, "\n") line = line.Next blk = blk.Next _append_cstr(buf, size, "}\n") # ============================================================ # 内部辅助 # ============================================================ 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) 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' # ============================================================ # 字段访问器(供其他模块绕过 stub 类型限制使用) # # 跨模块编译时,使用方模块只有 Function/Param 的 stub 类型 # (字段不足且字段类型可能错误),导致 TransPyC 静默跳过 # 字段访问(不生成 GEP,不报错),字段值永远为 null。 # # 这些访问器在拥有完整类型定义的本模块内执行,能正确访问 # 所有字段。其他模块通过函数调用获取字段值,绕过 stub 限制。 # ============================================================ def function_get_name(func: Function | t.CPtr) -> t.CChar | t.CPtr: """获取函数名""" if func is None: return None return func.Name def function_get_ret_ty(func: Function | t.CPtr) -> LLVMType | t.CPtr: """获取函数返回类型""" if func is None: return None return func.RetTy def function_get_params(func: Function | t.CPtr) -> GSList[Param] | t.CPtr: """获取函数参数链表容器""" if func is None: return None return func.Params def function_get_param_head(func: Function | t.CPtr) -> Param | t.CPtr: """获取函数参数链表头节点(一步到位,避免调用方访问 GSList.Head)""" if func is None: return None if func.Params is None: return None return func.Params.Head def function_get_next(func: Function | t.CPtr) -> Function | t.CPtr: """获取链表下一个函数""" if func is None: return None return func.Next def function_is_declared(func: Function | t.CPtr) -> t.CInt: """获取函数是否为声明(1=declare 仅声明, 0=define 定义)""" if func is None: return 0 return func.IsDeclared def param_get_name(param: Param | t.CPtr) -> t.CChar | t.CPtr: """获取参数名""" if param is None: return None return param.Name def param_get_ty(param: Param | t.CPtr) -> LLVMType | t.CPtr: """获取参数类型""" if param is None: return None return param.Ty def param_get_next(param: Param | t.CPtr) -> Param | t.CPtr: """获取链表下一个参数""" if param is None: return None return param.Next