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:
1 parent
2caf6f0795
commit
9c3ebc8a2c
2 files changed
+57
-22
No files matched your search
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user