fix(ffilib): 为 runtime CDLL thunk 创建 entry block 并移除失败静默返回

- new_builder 的 CurBlock 初值为 None,_emit 会静默丢弃指令,导致 thunk 生成空函数体(mlir-opt: empty block)
- 补 create_block + position_at_end,随后再把全部静默 return None 改为 fatal_error
- 移除两处 [ffiprobe] 调试探针
This commit is contained in:
TermiNexus committed 2026-10-24 23:57:09 +08:00
1 parent 2caf6f0795
commit 9c3ebc8a2c
2 files changed
+57 -22

No files matched your search

+57 -20
View File
@@ -275,13 +275,17 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
if cnt_e > 0:
ptypes = stdlib.malloc(8 * cnt_e)
pnames = stdlib.malloc(8 * cnt_e)
if ptypes is None or pnames is None: return None
if ptypes is None or pnames is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': parameter scratch allocation failed", "InternalCompilerError")
return None
curp = mlirlite.function_get_param_head(existing)
ei: int = 0
while curp is not None and ei < cnt_e:
pty_e: mlirlite.LLVMType* = mlirlite.param_get_ty(curp)
pnm_e: str = mlirlite.param_get_name(curp)
if pty_e is None or pnm_e is None: return None
if pty_e is None or pnm_e is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': reused declaration has a parameter without a type or name", "InternalCompilerError")
return None
match pty_e:
case mlirlite.LLVMType.Struct(_, _, _):
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL extern '{fd.name}': struct by value is not supported yet (use a pointer)", "TypeError")
@@ -302,7 +306,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
if an > 0:
ptypes = stdlib.malloc(8 * an)
pnames = stdlib.malloc(8 * an)
if ptypes is None or pnames is None: return None
if ptypes is None or pnames is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': parameter scratch allocation failed", "InternalCompilerError")
return None
ai: sizet = 0
while ai < an:
arg: ast.Arg* = ast.Arg*(alist.get(ai))
@@ -326,7 +332,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
ty_slot[0] = sizet(pty)
# 形参名 %p0/%p1...(AST 形参名可能缺失,且与 C 名无关)
nm_buf: str = pool.alloc(16)
if nm_buf is None: return None
if nm_buf is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': parameter name allocation failed", "InternalCompilerError")
return None
viperlib.snprintf(nm_buf, 16, "%%p%d", pcount)
nm_slot: sizet* = (sizet*)(uint64(pnames) + uint64(pcount * 8))
nm_slot[0] = sizet(nm_buf)
@@ -335,7 +343,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
thunk: mlirlite.Function* = existing
if thunk is None:
thunk = mlirlite.create_function(pool, mod, fd.name, ret_ty)
if thunk is None: return None
if thunk is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': function creation failed", "InternalCompilerError")
return None
for i in range(pcount):
pty_a: mlirlite.LLVMType* = (mlirlite.LLVMType*)((sizet*)(uint64(ptypes) + uint64(i * 8))[0])
pnm_a: str = rawptr((sizet*)(uint64(pnames) + uint64(i * 8))[0])
@@ -346,34 +356,61 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
for i in range(pcount):
pty_b: mlirlite.LLVMType* = (mlirlite.LLVMType*)((sizet*)(uint64(ptypes) + uint64(i * 8))[0])
nd: mlirlite.ParamNode* = mlirlite.new_param_node(pool, pty_b)
if nd is None: return None
if nd is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': function-type parameter node allocation failed", "InternalCompilerError")
return None
if pnode_head is None: pnode_head = nd
else: pnode_tail.Next = nd
pnode_tail = nd
fn_ty: mlirlite.LLVMType* = mlirlite.Func(pool, ret_ty, pnode_head, pcount)
fn_ptr_ty: mlirlite.LLVMType* = mlirlite.Ptr(pool, fn_ty)
# 函数体
# 函数体(每一步失败都 fail-fast:静默 return None 会留下空块,
# mlir-opt 只会报 "empty block: expect at least a terminator",看不出断点)
b: mlirlite.IRBuilder* = mlirlite.new_builder(pool, thunk)
if b is None: return None
if b is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': IRBuilder creation failed", "InternalCompilerError")
return None
# 必须有 entry block 并定位插入点:IRBuilder 的 CurBlock 初值为 None,
# 而 _emit 在 CurBlock 为 None 时会静默丢弃指令(表现就是空函数体)。
entry_thunk: mlirlite.BasicBlock* = mlirlite.create_block(pool, thunk, "entry")
if entry_thunk is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': entry block creation failed", "InternalCompilerError")
return None
mlirlite.position_at_end(b, entry_thunk)
v_path: mlirlite.Value* = self.Gen.ExprGenConst.create_global_string(b, pool, mod, lib_path, trans)
if v_path is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': emitting the library-path string constant failed", "InternalCompilerError")
return None
v_name: mlirlite.Value* = self.Gen.ExprGenConst.create_global_string(b, pool, mod, fd.name, trans)
if v_path is None or v_name is None: return None
if v_name is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': emitting the symbol-name string constant failed", "InternalCompilerError")
return None
# h = Load(path)
load_sym: str = stdlib.malloc(64)
if load_sym is None: return None
if load_sym is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': symbol-name buffer allocation failed", "InternalCompilerError")
return None
viperlib.snprintf(load_sym, 64, "%s.Load", ffilib_sha1)
v_h: mlirlite.Value* = mlirlite.build_call(b, load_sym, v_path, 1, i8_ptr_ty, 0)
if v_h is None: return None
if v_h is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': call to _ffilib.Load failed", "InternalCompilerError")
return None
# p = Sym(h, name)
sym_sym: str = stdlib.malloc(64)
if sym_sym is None: return None
if sym_sym is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': symbol-name buffer allocation failed", "InternalCompilerError")
return None
viperlib.snprintf(sym_sym, 64, "%s.Sym", ffilib_sha1)
mlirlite.value_set_next(v_h, v_name)
v_p: mlirlite.Value* = mlirlite.build_call(b, sym_sym, v_h, 2, i8_ptr_ty, 0)
if v_p is None: return None
if v_p is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': call to _ffilib.Sym failed", "InternalCompilerError")
return None
# f = bitcast p to fn_ptr_ty
v_f: mlirlite.Value* = mlirlite.build_bitcast(b, v_p, fn_ptr_ty)
if v_f is None: return None
if v_f is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': bitcast to the function-pointer type failed", "InternalCompilerError")
return None
# 实参列表 = thunk 自己的形参
arg_head: mlirlite.Value* = None
arg_prev: mlirlite.Value* = None
@@ -381,7 +418,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
pty_c: mlirlite.LLVMType* = (mlirlite.LLVMType*)((sizet*)(uint64(ptypes) + uint64(i * 8))[0])
pnm_c: str = rawptr((sizet*)(uint64(pnames) + uint64(i * 8))[0])
av: mlirlite.Value* = mlirlite.SSAValue(pool, pty_c, pnm_c)
if av is None: return None
if av is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': forwarding parameter {i} failed", "InternalCompilerError")
return None
if arg_head is None: arg_head = av
else: mlirlite.value_set_next(arg_prev, av)
arg_prev = av
@@ -394,7 +433,9 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
is_void = 0
if is_void != 0: mlirlite.build_ret_void(b)
else:
if v_r is None: return None
if v_r is None:
self.Gen.TypeGenErr.fatal_error(fd, f"runtime CDLL thunk '{fd.name}': indirect call produced no value", "InternalCompilerError")
return None
mlirlite.build_ret(b, v_r)
return thunk
@@ -799,14 +840,10 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
if (has_export != 0 or has_state != 0) and trans.ModuleSha1 is not None: self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name)
if is_extern_decl != 0:
stdio.printf("[ffiprobe] extern branch '%s' ffi_lib=%s\n", fd.name, "nil" if fd.ffi_lib is None else fd.ffi_lib)
stdio.fflush(None)
# extern <lib> name(...):runtime=True 在这里也生成 thunk(Phase A 的 extern 往往不走
# forward_declare_functions,两处都挂才覆盖全部路径;另一处靠 find_func_in_module 去重)。
if fd.ffi_lib is not None:
ffi_rt_d: int = ViperBuild.FfiHandleRuntime(fd.ffi_lib)
stdio.printf("[ffiprobe] extern '%s' rt=%d\n", fd.name, ffi_rt_d)
stdio.fflush(None)
if ffi_rt_d < 0:
self.Gen.TypeGenErr.fatal_error(fd, f"extern library handle '{fd.ffi_lib}' is not a ffilib.CDLL binding (declare it with ffilib.CDLL(...) first)", "NameError")
return 0
-2
View File
@@ -994,8 +994,6 @@ def _AssignTargetName(asn: ast.Assign*) -> str:
# _HandleCDLL - 按实参形态写入静态/动态库表;list 回退形式本期 fail-fast
def _HandleCDLL(node: ast.AST*, handle: str) -> int:
"""抽取 ffilib.CDLL(...):0=成功"""
stdio.printf("[ffiprobe] _HandleCDLL enter handle=%s\n", "?" if handle is None else handle)
stdio.fflush(None)
if node is None or node.kind() != ast.ASTKind.Call: return 0
call: ast.Call* = ast.Call*(node)
args: list[ast.AST*]* = call.args