fix(codegen): 新规范迁移暴露的 4 类解析/代码生成缺陷
1) HandlesExpr._HandleConstantLlvm 引号判定用 AST lineno 直查磁盘行,漏了 _inject_auto_imports 注入行的偏移 N,取到错行;改用 _DiskLineno 还原,并把 col_offset(UTF-8 字节偏移)转字符偏移后再切片。2) Phase2Translator 新增 _DedupComdatDecls:_dso.ll 由各依赖片段拼接,每片段各带同名 comdat 声明,llc 报 redefinition of comdat;在 _AddWeakComdat 入口与两处落盘点去重。3) LLVMTypeMapper._resolve_name 补存储类/类型限定符标记分支(CExport/CExtern/CConst… 返回空串,由 _resolve_bitor 取另一侧真实类型),与 _resolve_attribute 同口径。4) 短别名(int/int64/sizet/char…)在 typedef 右值与类型转换调用处解析不到:SymbolTypeResolver._resolve_typedef_from_value 与 LLVMTypeMapper.resolve_typedef_value_type 的 ast.Name 分支补 builtins typedef / BuiltinTypeMap 兜底(BaseType 可能是 CType 实例,须取 type(x).__name__),HandlesExprCall 的类型转换求值补 _lookup_builtins_typedef 回退并保留双参数 CPtr 指针包装。验证:TransPyV 自举 includes 52/52 + App 76/76 全通过;TPV 顺序回归 77/77。
This commit is contained in:
1 parent
65f0e87193
commit
07ba7a4fe5
5 files changed
+141
-11
No files matched your search
@@ -1089,6 +1089,33 @@ def _count_braces_outside_strings(text: str) -> int:
|
||||
_LLVM_UNQUOTED_NAME_RE: re.Pattern[str] = re.compile(
|
||||
r'[-a-zA-Z$._][-a-zA-Z$._0-9]*\Z')
|
||||
|
||||
# comdat 声明行:`$name = comdat any` / `$"name" = comdat any`(允许行首缩进)
|
||||
_RE_COMDAT_DECL: re.Pattern[str] = re.compile(r'^\s*\$("?)([^"=\s]+)\1\s*=\s*comdat\b')
|
||||
|
||||
|
||||
def _DedupComdatDecls(ll_content: str) -> str:
|
||||
"""删除重复的 `$name = comdat any` 声明(保留首次出现)。
|
||||
|
||||
落盘的 `_dso.ll` 是「本模块 + 各依赖 .stub.ll/.text.ll 片段」拼接而成,
|
||||
每个片段各自带一份同名 comdat 声明(片段生成时也会各自补 comdat)。同名
|
||||
声明出现两次即 llc 报 `redefinition of comdat '$…'`(现场:泛型特化
|
||||
`list[<sha1>.AST*].__before_init__` 在同一文件里出现 4 次)。comdat 声明
|
||||
在顶层可位于任意位置,保留首次出现即可,语义不变。
|
||||
"""
|
||||
if '= comdat' not in ll_content:
|
||||
return ll_content
|
||||
seen: set[str] = set()
|
||||
kept: list[str] = []
|
||||
for line in ll_content.splitlines(True):
|
||||
m = _RE_COMDAT_DECL.match(line)
|
||||
if m is not None:
|
||||
name: str = m.group(2)
|
||||
if name in seen:
|
||||
continue
|
||||
seen.add(name)
|
||||
kept.append(line)
|
||||
return ''.join(kept)
|
||||
|
||||
|
||||
def _AddWeakComdat(ll_content: str) -> str:
|
||||
"""为 weak/linkonce 系列 函数/全局 定义补 COMDAT(COFF/PE 必需)。
|
||||
@@ -1096,13 +1123,15 @@ def _AddWeakComdat(ll_content: str) -> str:
|
||||
COFF 下无 COMDAT 的 weak/linkonce 定义会被 llc 展开成强符号
|
||||
`.weak.<name>.default`(weak external 的实现副本)。同一弱定义出现在
|
||||
多个模块时(泛型特化方法如 `e94ef9e139461915.list[rawptr[AST]].
|
||||
__before_init__`、跨模块共享常量如 PYI_BUF_SIZE),副本同名 →
|
||||
__before_init__`、`linkonce`/`weak` 标注的跨模块共享常量),副本同名 →
|
||||
ld.lld 报 duplicate symbol。补 COMDAT(any) 后 llc 输出单一 COMDAT
|
||||
成员,链接器自动去重(llc/ld.lld 端到端已实验验证)。
|
||||
"""
|
||||
if (' linkonce ' not in ll_content and ' linkonce_odr ' not in ll_content
|
||||
and ' weak_odr ' not in ll_content and ' weak ' not in ll_content):
|
||||
return ll_content
|
||||
return _DedupComdatDecls(ll_content)
|
||||
# 拼接而来的片段可能各自已带同名 comdat 声明 ⇒ 先去重,再做本次补全
|
||||
ll_content = _DedupComdatDecls(ll_content)
|
||||
weak_links = 'linkonce|linkonce_odr|weak|weak_odr|extern_weak'
|
||||
comdat_names: list[str] = []
|
||||
|
||||
@@ -2968,6 +2997,9 @@ class Phase2Translator:
|
||||
# 都会报 "Metadata id is already used"。规整后盘上产物本身即合法 IR,
|
||||
# _llc_compile 内的规整随之成为幂等 no-op。
|
||||
ll_content = SanitizeIRMetadata(ll_content)
|
||||
# 拼接片段各自带一份同名 comdat 声明 ⇒ 落盘前统一去重:
|
||||
# llc 对同一 comdat 声明出现两次即报 redefinition of comdat
|
||||
ll_content = _DedupComdatDecls(ll_content)
|
||||
dso_ll_path = ll_path[:-3] + '_dso.ll'
|
||||
with open(dso_ll_path, 'w', encoding='utf-8') as f:
|
||||
f.write(ll_content)
|
||||
@@ -3878,6 +3910,8 @@ class Phase2Translator:
|
||||
# 同 App 路径:写盘前规整元数据(拼接片段各自带 !0..!N 的 DI 元数据),
|
||||
# 让盘上产物本身即合法 IR,不依赖 _llc_compile 里那次事后规整。
|
||||
ll_content = SanitizeIRMetadata(ll_content)
|
||||
# 同 App 路径:拼接片段各自带一份同名 comdat 声明 ⇒ 落盘前统一去重
|
||||
ll_content = _DedupComdatDecls(ll_content)
|
||||
dso_ll_path = ll_path[:-3] + '_dso.ll'
|
||||
with open(dso_ll_path, 'w', encoding='utf-8') as f:
|
||||
f.write(ll_content)
|
||||
|
||||
Reference in new issue
Block a user