fix(CallGen): Function 的 Param 形参链与 llvmlite.Func 的 ParamNode 构造链不可互传(Vipeye 329/401/1065)

① 新增 CallGenBase._FuncTyFromFunction(pool, f_ref):Function.Params 是 Param 链(__function.vp),LLVMType.Func 的类型构造链是 ParamNode 链(__types.vp,new_param_node/paramnode_set_next),两者是不相关 class ⇒ 严格指针规则下 Func(pool, ret, p_head, cnt) 的实参传递直接报错。改为逐个 new_param_node 重建 ParamNode 链(语义等价,只取各参数类型)。CallGenCBuiltin 329/401 + ExprGenOps 878(第 3 处同型缺陷)三处统一走该 helper。

② CallGenCBuiltin 1065 asm-out 全局变量回退:原把 find_global_in_module 的 GlobalVariable* 直接赋给 llvmlite.Value* 变量(不相关类;且 GlobalVariable 字段序为 Name→Ty,Value 为 Ty→Name,旧无条件 bitcast 会让 .Ty 读到 Name,后续 alloca.Ty.Pointee 全是错位数据)⇒ 改走 c.Addr(模块全局) 分支同款写法 make_global_ref(pool, Name, Ty) 构造带引号的 Ptr(Ty) Value 引用,同时修掉该错位读取。
This commit is contained in:
TermiNexus committed 2026-09-28 17:16:57 +08:00
1 parent 23428b63a5
commit eb1065f387
3 files changed
+48 -24

No files matched your search

+32
View File
@@ -560,6 +560,38 @@ novirtual class CallGenBase:
return sha1
def _FuncTyFromFunction(self, pool: memhub.MemBuddy*,
f_ref: llvmlite.Function*) -> llvmlite.LLVMType*:
"""由 llvmlite.Function 的形参链表(Param 链)构造 LLVMType.Func 类型。
为什么不能直接把 Param 链交给 llvmlite.Func:`Function.Params` 是 **Param** 链
(__function.vp,`Param.Ty: rawptr[LLVMType]`),而 `LLVMType.Func` 的类型构造链表是
**ParamNode** 链(__types.vp,由 new_param_node 建、paramnode_set_next 串)。两者是
互不相关的 class —— 严格指针规则下不可互传(旧的无条件 bitcast 掩盖了这点,且两者
字段顺序不同,bitcast 后读 Ty/Name 都是错位数据)。
这里逐个 new_param_node 重建 ParamNode 链再交给 Func:语义等价(两侧都只取各参数的
类型),类型也对得上 Func(params: rawptr[ParamNode]) 的形参。
"""
pn_head: llvmlite.ParamNode* = None
pn_prev: llvmlite.ParamNode* = None
p_cnt: sizet = 0
p_cur: llvmlite.Param* = llvmlite.function_get_param_head(f_ref)
while p_cur is not None:
p_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(p_cur)
if p_ty is None:
return None
pn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, p_ty)
if pn is None:
return None
if pn_head is None:
pn_head = pn
if pn_prev is not None:
llvmlite.paramnode_set_next(pn_prev, pn)
pn_prev = pn
p_cnt += 1
p_cur = llvmlite.param_get_next(p_cur)
return llvmlite.Func(pool, f_ref.RetTy, pn_head, p_cnt)
def find_func_in_module(self, mod: llvmlite.LLVMModule*,
name: str,
owner_sha1: str = None) -> llvmlite.Function*:
+13 -17
View File
@@ -320,13 +320,9 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
if f_addr_ref is not None:
f_addr_name: str = llvmlite.function_get_name(f_addr_ref)
if f_addr_name is not None:
p_head_ca: llvmlite.Param* = llvmlite.function_get_param_head(f_addr_ref)
p_cnt_ca: sizet = 0
p_cur_ca: llvmlite.Param* = p_head_ca
while p_cur_ca is not None:
p_cnt_ca += 1
p_cur_ca = llvmlite.param_get_next(p_cur_ca)
fn_ty_ca: llvmlite.LLVMType* = llvmlite.Func(pool, f_addr_ref.RetTy, p_head_ca, p_cnt_ca)
# 形参链是 Param 链(__function.vp),而 llvmlite.Func 的类型构造链是
# ParamNode 链(__types.vp)——不相关类,统一经 _FuncTyFromFunction 重建。
fn_ty_ca: llvmlite.LLVMType* = self.Gen.CallGenBase._FuncTyFromFunction(pool, f_addr_ref)
# 函数引用名需按需加引号(数字开头/含 '.' 的 sha1 前缀名
# 必须 @\"...\",否则 llc "expected 'to' after cast value",
# uhci.vp c.Addr(_on_int_complete) 根因)。
@@ -392,13 +388,8 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
fname2: str = llvmlite.function_get_name(f_ref2)
if fname2 is not None:
# 构造带 @ 名的 SSAValue(Ptr(FuncTy)):直接返回 Function 节点会被 IRBuilder 格式化成 RetTy(void)→ "bitcast void to i8*"。Function 无 Ty 字段,用 RetTy+Params 重建函数类型;Params 是 GSList,必须经 function_get_param_head 取链表头(当 Param 直接遍历会读出垃圾参数类型)
p_head2: llvmlite.Param* = llvmlite.function_get_param_head(f_ref2)
p_cnt2: sizet = 0
p_cur2: llvmlite.Param* = p_head2
while p_cur2 is not None:
p_cnt2 += 1
p_cur2 = llvmlite.param_get_next(p_cur2)
fn_ty2: llvmlite.LLVMType* = llvmlite.Func(pool, f_ref2.RetTy, p_head2, p_cnt2)
# 同上:Function 的 Param 形参链 → 重建 ParamNode 链再交 Func
fn_ty2: llvmlite.LLVMType* = self.Gen.CallGenBase._FuncTyFromFunction(pool, f_ref2)
# 函数引用名按需加引号(数字开头/含 '.' 的
# sha1 前缀名必须 @\"...\")。
fnlen2: sizet = string.strlen(fname2)
@@ -1060,9 +1051,14 @@ class CallGenCBuiltin(CallGenBase.CallGenBase):
# isr.s .comm):lookup_var 只查局部 → 全局
# 落空 → 操作数缺失 → asm 模板 "$0" 空 →
# "mov , cr3" llc unknown token in expression。
# 回退查模块全局(精确+后缀),全局 Value
# (@name,类型 i64*)直接当 store 目标。
alloca = self.Gen.ExprGenAttr.find_global_in_module(mod, nm.id)
# 回退查模块全局,并**经 make_global_ref 转成 Value 引用**:
# GlobalVariable 与 Value 是不相关类(不可互转,且字段顺序不同
# —— GlobalVariable.Name 在 Ty 之前,旧的无条件 bitcast 会让
# .Ty 读到 Name),必须按 c.Addr(模块全局) 分支的同一写法构造
# 带引号的 Ptr(Ty) 引用(见 L309 注释)。
gv_asm: llvmlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(mod, nm.id)
if gv_asm is not None and gv_asm.Name is not None and gv_asm.Ty is not None:
alloca = self.Gen.ExprGenAttr.make_global_ref(pool, gv_asm.Name, gv_asm.Ty)
elif val_node.kind() == ast.ASTKind.Attribute:
# AsmOut(p.pml4_root)(p 为 Process 指针):
# GEP 到字段地址(对齐 translate_c_addr Attribute
+3 -7
View File
@@ -869,13 +869,9 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
if f_ao is not None:
fname_ao: str = llvmlite.function_get_name(f_ao)
if fname_ao is not None:
p_head_ao: llvmlite.Param* = llvmlite.function_get_param_head(f_ao)
p_cnt_ao: sizet = 0
p_cur_ao: llvmlite.Param* = p_head_ao
while p_cur_ao is not None:
p_cnt_ao += 1
p_cur_ao = llvmlite.param_get_next(p_cur_ao)
fn_ty_ao: llvmlite.LLVMType* = llvmlite.Func(pool, f_ao.RetTy, p_head_ao, p_cnt_ao)
# 形参链是 Param 链,而 llvmlite.Func 的类型构造链是 ParamNode 链
# (不相关类)→ 经 _FuncTyFromFunction 重建(同 CallGenCBuiltin)。
fn_ty_ao: llvmlite.LLVMType* = self.Gen.CallGenBase._FuncTyFromFunction(pool, f_ao)
# 函数引用名按需加引号(数字开头/含 '.' 的 sha1 前缀名)
fnlen_ao: sizet = string.strlen(fname_ao)
needs_q_ao: int = self.Gen.ClassGenVTable._vtable_name_needs_quote(fname_ao)