fix(gen): 跨模块函数作值时不再伪造同名外部全局
`serial.puts` 这类模块属性指向的是函数(elf.vp 的 _resolve_symbol 返回它作 函数指针),属性兜底路径却为它造了一个 llvm.mlir.global external @<sha1>.puts, 与已有的 llvm.func @<sha1>.puts 同名,mlir-opt 报 redefinition of symbol named。 改为在伪造之前先精确匹配函数符号(目标模块 sha1 前缀过的函数名与 Function.Name 逐字符相等,避免误命中他模块同名函数),命中则返回函数符号引用本身 (@<mangled>,类型 Ptr(Func),与同模块 &f 分支同一形态),并让属性读路径跳过 对该值的 load(函数地址即值,load 会去读函数体)。 EOF
This commit is contained in:
1 parent
edca6c3760
commit
3b4bd1c6dc
1 file changed
+27
-2
@@ -188,6 +188,26 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
# build the reference from gv.Name (full name, matching the definition when SHA1-prefixed),
|
||||
# avoiding an undefined symbol for a bare @_mbuddy under per-module prefixed definitions
|
||||
return self.make_global_ref(pool, gv.Name, gv.Ty)
|
||||
# A module function used as a value (`return serial.puts`, `cb = serial.puts`): the symbol
|
||||
# is already declared in this module as `llvm.func @<sha1>.puts`, so manufacturing an
|
||||
# external global under the same name makes mlir-opt reject the module with "redefinition
|
||||
# of symbol named '<sha1>.puts'". Hand back the function symbol itself instead: a Value
|
||||
# whose text is the reference `@<mangled>` typed Ptr(Func), the same shape the same-module
|
||||
# `&f` branch (ExprGenOps.translate_unaryop) produces -- the caller must not load it.
|
||||
if gv_q is not None:
|
||||
fn_ma: mlirlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, at.attr)
|
||||
if fn_ma is not None:
|
||||
fname_ma: str = mlirlite.function_get_name(fn_ma)
|
||||
# exact match only: a bare suffix hit could be another module's same-name function
|
||||
if fname_ma is not None and string.strcmp(fname_ma, gv_q) == 0:
|
||||
fn_ty_ma: mlirlite.LLVMType* = self.Gen.CallGenBase._FuncTyFromFunction(pool, fn_ma)
|
||||
if fn_ty_ma is not None:
|
||||
fnlen_ma: sizet = string.strlen(fname_ma)
|
||||
fbuf_ma: str = pool.alloc(fnlen_ma + 4)
|
||||
if fbuf_ma is not None:
|
||||
if self.Gen.ClassGenVTable._vtable_name_needs_quote(fname_ma) != 0: viperlib.snprintf(fbuf_ma, fnlen_ma + 4, "@\"%s\"", fname_ma)
|
||||
else: viperlib.snprintf(fbuf_ma, fnlen_ma + 4, "@%s", fname_ma)
|
||||
return mlirlite.SSAValue(pool, mlirlite.Ptr(pool, fn_ty_ma), fbuf_ma)
|
||||
# not found: create an external global declaration and add it to the module; otherwise only
|
||||
# an @_argc reference is emitted with no declaration (LLVM: "use of undefined value").
|
||||
use_ty: mlirlite.LLVMType* = ty_hint
|
||||
@@ -469,10 +489,15 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if mod_gv_ref is not None and mod_gv_ref.Ty is not None:
|
||||
load_ty_mod: mlirlite.LLVMType* = mod_gv_ref.Ty.Pointee
|
||||
if load_ty_mod is not None:
|
||||
# module-level global array (e.g. zdef.zdeflate_len_base: CArray[T, N]):
|
||||
# decay to the base address per C semantics; loading [N x T] cannot be GEP base.
|
||||
# A module function used as a value is already the address (Ptr(Func),
|
||||
# the symbol reference itself): loading it would read the function body,
|
||||
# so return the reference unchanged.
|
||||
match load_ty_mod:
|
||||
case mlirlite.LLVMType.Func(_, _, _):
|
||||
return mod_gv_ref
|
||||
case mlirlite.LLVMType.Array(_, _):
|
||||
# module-level global array (e.g. zdef.zdeflate_len_base: CArray[T, N]):
|
||||
# decay to the base address per C semantics; loading [N x T] cannot be GEP base.
|
||||
return mod_gv_ref
|
||||
case _:
|
||||
pass
|
||||
|
||||
Reference in new issue
Block a user