修复了一些问题
This commit is contained in:
1 parent
43e7cdd2cc
commit
6af2dea917
16 files changed
+253
-154
No files matched your search
@@ -2309,6 +2309,12 @@ class Phase2Translator:
|
||||
break
|
||||
final_lines2 = ll_content_no_types.splitlines(True)
|
||||
ll_content = ''.join(final_lines2[:header_end]) + '\n'.join(final_type_defs) + '\n' + ''.join(final_lines2[header_end:])
|
||||
# 写盘前先规整元数据:本文件的 IR 是「本模块 + 各依赖 .stub.ll/
|
||||
# .text.ll 片段」拼接而成,每份片段都自带从 !0 起编号的 DI 元数据,
|
||||
# 未规整直接落盘的话,任何读该文件的 opt/llc(含另一并发构建进程)
|
||||
# 都会报 "Metadata id is already used"。规整后盘上产物本身即合法 IR,
|
||||
# _llc_compile 内的规整随之成为幂等 no-op。
|
||||
ll_content = SanitizeIRMetadata(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)
|
||||
@@ -3127,6 +3133,9 @@ class Phase2Translator:
|
||||
insert_pos = len(other_lines)
|
||||
ll_content = ''.join(other_lines[:insert_pos]) + ''.join(type_def_lines) + ''.join(other_lines[insert_pos:])
|
||||
|
||||
# 同 App 路径:写盘前规整元数据(拼接片段各自带 !0..!N 的 DI 元数据),
|
||||
# 让盘上产物本身即合法 IR,不依赖 _llc_compile 里那次事后规整。
|
||||
ll_content = SanitizeIRMetadata(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)
|
||||
@@ -3883,7 +3892,13 @@ SECTIONS {
|
||||
_vlog().success(f" 生成: {exe_path}")
|
||||
file_size = os.path.getsize(exe_path)
|
||||
_vlog().info(f" [大小] {file_size} 字节")
|
||||
if not is_binary:
|
||||
# --dwarf 构建(含 --asan 自动开启)必须保留 DWARF:
|
||||
# 该模式存在的唯一意义是崩溃时反查 ".vp:行",
|
||||
# 而 _strip_debug_sections 会 llvm-strip --strip-debug 掉全部
|
||||
# .debug_* 段(实测 exe 体积 13378048 → 11895296,
|
||||
# llvm-symbolizer 对含 main 在内的所有地址返回 ??:0:0)。
|
||||
# 非 dwarf 构建保持原有剥离行为(产物零变化)。
|
||||
if not is_binary and not self.dwarf_enabled:
|
||||
self._strip_debug_sections(exe_path)
|
||||
else:
|
||||
_vlog().error(f" 链接失败: {result.stderr.strip()}")
|
||||
|
||||
@@ -541,32 +541,32 @@ class AnnAssignHandle(BaseHandle):
|
||||
Gen.global_struct_class[VarName] = TypeInfo.Name
|
||||
# 联合指针注解(X | t.CPtr)短名回退:resolver 对模块限定 struct
|
||||
# 段(如 llvmlite.Value)无法精确 in Gen.structs(键可能是 'Value'
|
||||
# 或带 sha1 前缀),Name 常退化为指针别名 'rowptr'(被注册成 opaque
|
||||
# struct)→ 变量 var_struct_class 登记为 rowptr → 字段访问
|
||||
# "属性 'Next' 在类 'rowptr' 中找不到"(FuncGenMixin.vp L307)。
|
||||
# 或带 sha1 前缀),Name 常退化为指针别名 'rawptr'(被注册成 opaque
|
||||
# struct)→ 变量 var_struct_class 登记为 rawptr → 字段访问
|
||||
# "属性 'Next' 在类 'rawptr' 中找不到"(FuncGenMixin.vp L307)。
|
||||
# FindStructNameInAnnotation 以 attr/短名命中,找回真实类名。
|
||||
if (isinstance(Node.annotation, ast.BinOp)
|
||||
and isinstance(Node.annotation.op, ast.BitOr)):
|
||||
_union_struct_name2: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs)
|
||||
# resolver 对模块限定 struct 联合(llvmlite.Value | t.CPtr)常给出
|
||||
# 指针占位名(如 '{sha1}.rowptr')且该占位恰好注册在 Gen.structs,
|
||||
# 指针占位名(如 '{sha1}.rawptr')且该占位恰好注册在 Gen.structs,
|
||||
# 使上方 TypeInfo.Name in Gen.structs 通过并登记错误类名 → 字段
|
||||
# 访问 "属性 'Next' 在类 'rowptr' 中找不到"。凡短名命中真实类
|
||||
# 访问 "属性 'Next' 在类 'rawptr' 中找不到"。凡短名命中真实类
|
||||
# (attr 精确 in structs),一律覆盖为真实类名(Value)。
|
||||
if _union_struct_name2 and _union_struct_name2 in Gen.structs:
|
||||
if Gen.var_struct_class.get(VarName) != _union_struct_name2:
|
||||
Gen.var_struct_class[VarName] = _union_struct_name2
|
||||
if getattr(Gen, 'global_struct_class', None) is not None:
|
||||
Gen.global_struct_class[VarName] = _union_struct_name2
|
||||
# Subscript rowptr[X] / t.CPtr[X] 注解的本地结构指针变量(如
|
||||
# includes/ast/parser.vp _fix_store_ctx 里 `tp: rowptr[Tuple] =
|
||||
# (rowptr[Tuple])(node)`,随后 `tp_elts = tp.elts`):TypeMerge 的
|
||||
# builtins 分支把 rowptr[X] 折叠为 i8*(PtrCount=1/CVoid),既不登记
|
||||
# Subscript rawptr[X] / t.CPtr[X] 注解的本地结构指针变量(如
|
||||
# includes/ast/parser.vp _fix_store_ctx 里 `tp: rawptr[Tuple] =
|
||||
# (rawptr[Tuple])(node)`,随后 `tp_elts = tp.elts`):TypeMerge 的
|
||||
# builtins 分支把 rawptr[X] 折叠为 i8*(PtrCount=1/CVoid),既不登记
|
||||
# var_struct_class 也不保留内层 X —— 单级 Name 字段取值(tp.elts)
|
||||
# 在属性访问层 ClassName 解析为 None → 求值 None → 赋值被 fail-fast
|
||||
# 拦截(parser.vp L427 bootstrap 根因)。与上方 BinOp 联合的短名回退
|
||||
# 对称:把内层 X 解析为真实 struct 键(兼容短名 / 带 class_sha1 前缀
|
||||
# 的键)并登记;仅在缺失或指针占位(rowptr…)时覆盖,不碰已精确登记值。
|
||||
# 的键)并登记;仅在缺失或指针占位(rawptr…)时覆盖,不碰已精确登记值。
|
||||
_rst_sub: ast.AST | None = None
|
||||
if isinstance(Node.annotation, ast.Subscript):
|
||||
_rst_v: ast.expr = Node.annotation.value
|
||||
@@ -575,7 +575,7 @@ class AnnAssignHandle(BaseHandle):
|
||||
_rst_nm = _rst_v.id
|
||||
elif isinstance(_rst_v, ast.Attribute) and isinstance(_rst_v.value, ast.Name):
|
||||
_rst_nm = f'{_rst_v.value.id}.{_rst_v.attr}'
|
||||
if _rst_nm in ('rowptr', 't.CPtr'):
|
||||
if _rst_nm in ('rawptr', 't.CPtr'):
|
||||
_rst_sub = Node.annotation
|
||||
if _rst_sub is not None:
|
||||
_rst_sl: ast.AST = _rst_sub.slice
|
||||
@@ -602,8 +602,8 @@ class AnnAssignHandle(BaseHandle):
|
||||
break
|
||||
if _rst_tk:
|
||||
_rst_cur: str | None = Gen.var_struct_class.get(VarName)
|
||||
_rst_need: bool = (not _rst_cur or _rst_cur == 'rowptr' or '.rowptr' in _rst_cur
|
||||
or _rst_cur.startswith('rowptr['))
|
||||
_rst_need: bool = (not _rst_cur or _rst_cur == 'rawptr' or '.rawptr' in _rst_cur
|
||||
or _rst_cur.startswith('rawptr['))
|
||||
if _rst_need and _rst_cur != _rst_tk:
|
||||
Gen.var_struct_class[VarName] = _rst_tk
|
||||
if getattr(Gen, 'global_struct_class', None) is not None:
|
||||
@@ -776,11 +776,11 @@ class AnnAssignHandle(BaseHandle):
|
||||
_cn_short: str = CN.split('.')[-1] if '.' in CN else CN
|
||||
if _IsGenericTpName(_cn_short):
|
||||
continue
|
||||
# rowptr 占位 struct('rowptr' / '{sha1}.rowptr' / 'rowptr[...]')是
|
||||
# rawptr 占位 struct('rawptr' / '{sha1}.rawptr' / 'rawptr[...]')是
|
||||
# 模块限定联合 X | t.CPtr 被 resolver 退化的产物(无真实字段),
|
||||
# 绝不能覆盖注解已解析出的真实类名(如 Value)→ env_size_val.Next
|
||||
# 报 "属性在类 'rowptr' 中找不到"(FuncGenMixin.vp L307 根因)。
|
||||
if CN == 'rowptr' or CN.endswith('.rowptr') or CN.startswith('rowptr['):
|
||||
# 报 "属性在类 'rawptr' 中找不到"(FuncGenMixin.vp L307 根因)。
|
||||
if CN == 'rawptr' or CN.endswith('.rawptr') or CN.startswith('rawptr['):
|
||||
continue
|
||||
if pointee is ST or pointee == ST:
|
||||
# 若注解是泛型特化(如 ndarray[t.CDouble] | t.CPtr),
|
||||
@@ -907,8 +907,8 @@ class AnnAssignHandle(BaseHandle):
|
||||
if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)):
|
||||
for CN, ST in Gen.structs.items():
|
||||
if pointee == ST:
|
||||
# rowptr 占位 struct 不参与覆盖(见 L706-711 说明)
|
||||
if CN == 'rowptr' or CN.endswith('.rowptr') or CN.startswith('rowptr['):
|
||||
# rawptr 占位 struct 不参与覆盖(见 L706-711 说明)
|
||||
if CN == 'rawptr' or CN.endswith('.rawptr') or CN.startswith('rawptr['):
|
||||
break
|
||||
Gen._var_to_heap_ptr[VarName] = InitValue
|
||||
# 不覆盖已设置的特化名(含 '['):opaque 基础类型(如 ndarray)
|
||||
|
||||
@@ -769,7 +769,7 @@ class BaseHandle:
|
||||
局部变量注解走 TypeMergeHandler.GetCTypeInfo(_HandleSubscript 泛型
|
||||
分支),函数参数却走 ResolveAnnotationType → Subscript 非 BinOp 直接
|
||||
CTypeInfo.FromNode → TypeAnnotationResolver 不识别泛型模板,容器
|
||||
(list[X] / rowptr[list[X]] / GSList[X] / rowptr[GSList[X]])被折叠成
|
||||
(list[X] / rawptr[list[X]] / GSList[X] / rawptr[GSList[X]])被折叠成
|
||||
i8* → 参数无 var_struct_class → 方法调用 FakeDuck 兜底错绑兄弟类
|
||||
(如 parser.vp _append_str_value 的 values.append 被编成 AST.append
|
||||
虚调用,this=list* 读 vtable 崩溃)。此处对命中泛型模板的 Subscript
|
||||
@@ -793,7 +793,7 @@ class BaseHandle:
|
||||
|
||||
def _SubscriptHitsGenericTemplate(self, annotation: ast.Subscript) -> bool:
|
||||
"""判断 Subscript 是否命中泛型模板:裸模板名(list[X]/GSList[X]),
|
||||
或 rowptr/t.CPtr 裸指针 typedef 内嵌模板名(rowptr[list[X]] 等)。"""
|
||||
或 rawptr/t.CPtr 裸指针 typedef 内嵌模板名(rawptr[list[X]] 等)。"""
|
||||
tpls: Any = getattr(getattr(self.Trans, 'ClassHandler', None), '_generic_class_templates', None)
|
||||
if not tpls:
|
||||
return False
|
||||
|
||||
@@ -821,9 +821,9 @@ class ClassHandle(BaseHandle):
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = spec_in_anno
|
||||
# Subscript 容器字段(list[X] / rowptr[list[X]]):非 BinOp 联合,
|
||||
# Subscript 容器字段(list[X] / rawptr[list[X]]):非 BinOp 联合,
|
||||
# 上面的 i8*/BinOp 分支不命中 → 容器身份丢失 → 字段方法调用
|
||||
# (get/len…)分派失败 "Undefined method 'get' in class 'rowptr'"
|
||||
# (get/len…)分派失败 "Undefined method 'get' in class 'rawptr'"
|
||||
# (Converter.vp L190)。与 HandlesImports 对称,用与特化生成端
|
||||
# 同源的 _resolve_type_arg_str 记录 element_class。
|
||||
if isinstance(item.annotation, ast.Subscript):
|
||||
@@ -833,13 +833,13 @@ class ClassHandle(BaseHandle):
|
||||
_elem_slice_c: ast.AST | None = None
|
||||
if _subname_c == 'list':
|
||||
_elem_slice_c = _ann_sub_c.slice
|
||||
elif _subname_c == 'rowptr':
|
||||
elif _subname_c == 'rawptr':
|
||||
_slice_c: ast.AST = _ann_sub_c.slice
|
||||
if isinstance(_slice_c, ast.Subscript):
|
||||
# rowptr[泛型容器](rowptr[list[X]] / rowptr[GSList[Param]]):
|
||||
# rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]):
|
||||
# 容器身份 = 泛型特化名。list 继续走 _elem_slice_c 统一登记;
|
||||
# 其余泛型容器直接登记 element_class(阻塞 B 根因链一环:
|
||||
# 原实现只认内层 list,rowptr[GSList[Param]] 在此空转并跳过
|
||||
# 原实现只认内层 list,rawptr[GSList[Param]] 在此空转并跳过
|
||||
# 裸结构分支 → element_class 缺失 → 字段/局部变量方法分派
|
||||
# 丢失容器身份,FakeDuck 错绑 LinkedNode.append 写穿)。
|
||||
_inner_sub_c: ast.Subscript = _slice_c
|
||||
@@ -858,11 +858,11 @@ class ClassHandle(BaseHandle):
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = _ec_gc
|
||||
else:
|
||||
# rowptr[裸结构](如 rowptr[Token]):跨模块 stub 会把自引用/类内
|
||||
# rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内
|
||||
# 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复
|
||||
# struct 身份走 char*→struct cast。HEAD 态 `Token | t.CPtr` 联合
|
||||
# 由上方 BinOp 分支登记;rowptr 重构后此分支补齐(阻塞 A 根因)。
|
||||
# 与 HandlesImports 的 rowptr 分支对称。
|
||||
# 由上方 BinOp 分支登记;rawptr 重构后此分支补齐(阻塞 A 根因)。
|
||||
# 与 HandlesImports 的 rawptr 分支对称。
|
||||
_slc_name_c: str | None = None
|
||||
if isinstance(_slice_c, ast.Name):
|
||||
_slc_name_c = _slice_c.id
|
||||
@@ -879,7 +879,7 @@ class ClassHandle(BaseHandle):
|
||||
else:
|
||||
# 短名模糊扫描(对齐 HandlesAnnAssign 变量侧
|
||||
# 补偿 L597-602):跨模块 `mod.Class` 形态的
|
||||
# rowptr[Class] 字段在 class_sha1_map 尚无该短名
|
||||
# rawptr[Class] 字段在 class_sha1_map 尚无该短名
|
||||
# 时上面两路全 miss → element_class 静默缺失 →
|
||||
# 字段方法调用(factory.PermPool.alloc)链尾类名
|
||||
# 丢失 → TPC 调用分派返回 i32 0 哨兵 → 误报
|
||||
|
||||
@@ -164,7 +164,14 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__")
|
||||
return str_val
|
||||
return arg_val
|
||||
return self._EmitStringFromValue(arg_val)
|
||||
# str 是类型名(= t.CChar* = i8*),str(x) ≡ (str)(x) 类型转换:
|
||||
# 整型(u64/sizet 地址、char 码)→ inttoptr,与 TPV
|
||||
# CallGenDispatch._tc_h3_stdarg_cast 的 str 分支同语义
|
||||
# (CallGenCtor._translate_t_type_cast 的「整数 → 指针: inttoptr」)。
|
||||
# 曾用 _EmitStringFromValue 把整数 snprintf 进栈缓冲并返回栈地址
|
||||
# → free/写入即 bad-free(StubMergerBuild.vp 崩溃根因)。
|
||||
if isinstance(arg_val.type, ir.IntType):
|
||||
return Gen.builder.inttoptr(arg_val, ir.IntType(8).as_pointer(), name="str_int2ptr")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
elif FuncName == 'bytes':
|
||||
# bytes() — 类型转换为 i8* 指针 (等同于 t.CPtr / str)
|
||||
@@ -567,7 +574,7 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
# len(obj.attr):obj 可为 self 或任意局部变量(VpiReader 的
|
||||
# len(simp.names) 即非 self 场景)。字段静态类型若退化为 i8*
|
||||
# (跨模块 stub 的 rowptr[list[...]],stub 不注入字段类型),通用
|
||||
# (跨模块 stub 的 rawptr[list[...]],stub 不注入字段类型),通用
|
||||
# strlen 分支会把 list 容器头当字符串扫 → 垃圾长度 → 越界 get →
|
||||
# 读任意地址(VpiReader.vp _ParseVpiIntoModuleImpl 读 -1 根因)。
|
||||
# 此处按字段的 class_member_element_class 侧信道(记录 list 特化名)
|
||||
@@ -887,26 +894,6 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _EmitStringFromValue(self, val: ir.Value) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
if isinstance(val.type, ir.IntType):
|
||||
if val.type.width == 8:
|
||||
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 2))
|
||||
null_ptr = Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 1)], name="null_byte")
|
||||
Gen.builder.store(ir.Constant(ir.IntType(8), 0), null_ptr)
|
||||
Gen.builder.store(val, buf)
|
||||
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
|
||||
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32))
|
||||
snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.IntType(64),
|
||||
ir.PointerType(ir.IntType(8))
|
||||
], var_arg=True))
|
||||
fmt_ptr = Gen.emit_constant("%d", 'string')
|
||||
Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(64), 32), fmt_ptr, val])
|
||||
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _HandleMallocLlvm(self, args: list[ast.expr]) -> ir.Value:
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||||
|
||||
@@ -481,10 +481,10 @@ class ExprCallHandle(BaseHandle):
|
||||
)
|
||||
if _p2_cptr:
|
||||
if isinstance(_tg_td, ir.PointerType):
|
||||
return self._emit_rowptr_cast(Node, Gen, _tg_td)
|
||||
return self._emit_rawptr_cast(Node, Gen, _tg_td)
|
||||
_tg_ptr_td: ir.Type = ir.PointerType(_tg_td)
|
||||
return self._emit_rowptr_cast(Node, Gen, _tg_ptr_td)
|
||||
return self._emit_rowptr_cast(Node, Gen, _tg_td)
|
||||
return self._emit_rawptr_cast(Node, Gen, _tg_ptr_td)
|
||||
return self._emit_rawptr_cast(Node, Gen, _tg_td)
|
||||
except Exception:
|
||||
pass
|
||||
raise Exception(f"Undefined function: '{FuncName}'")
|
||||
@@ -492,7 +492,7 @@ class ExprCallHandle(BaseHandle):
|
||||
# Handle list[int](mb) syntax — generic class constructor with explicit type args
|
||||
# Handle xxx[T](x) syntax — generic function call with explicit type args
|
||||
sub: ast.Subscript = Node.func
|
||||
# (rowptr[X])(expr) / (t.CPtr[X])(expr):内建裸指针转换(无泛型模板)。
|
||||
# (rawptr[X])(expr) / (t.CPtr[X])(expr):内建裸指针转换(无泛型模板)。
|
||||
# 不拦截 → 泛型模板查不到 → 落 L850 "Unsupported call expression"
|
||||
# (StubMergerCollect.vp L271 bootstrap 根因)。
|
||||
_sub_nm: str | None = None
|
||||
@@ -500,7 +500,7 @@ class ExprCallHandle(BaseHandle):
|
||||
_sub_nm = sub.value.id
|
||||
elif isinstance(sub.value, ast.Attribute) and isinstance(sub.value.value, ast.Name) and sub.value.value.id == 't' and sub.value.attr == 'CPtr':
|
||||
_sub_nm = 't.CPtr'
|
||||
if _sub_nm in ('rowptr', 't.CPtr'):
|
||||
if _sub_nm in ('rawptr', 't.CPtr'):
|
||||
return self._HandleSubscriptPtrCastLlvm(Node, sub)
|
||||
if isinstance(sub.value, ast.Name):
|
||||
FuncName: str = sub.value.id
|
||||
@@ -1990,11 +1990,11 @@ class ExprCallHandle(BaseHandle):
|
||||
return ArgVal
|
||||
|
||||
def _HandleSubscriptPtrCastLlvm(self, Node: ast.Call, sub: ast.Subscript) -> ir.Value:
|
||||
"""(rowptr[X])(expr) / (t.CPtr[X])(expr) 内建指针转换:expr → X*
|
||||
"""(rawptr[X])(expr) / (t.CPtr[X])(expr) 内建指针转换:expr → X*
|
||||
|
||||
rowptr 是编译器内建裸指针语法(无 SymbolTable typedef 条目、无泛型模板),
|
||||
rawptr 是编译器内建裸指针语法(无 SymbolTable typedef 条目、无泛型模板),
|
||||
此前 Subscript 调用仅查泛型模板 → 落空后报 "Unsupported call expression"
|
||||
(StubMergerCollect.vp `(rowptr[FileEntry])(t.CVoid(...))` bootstrap 根因)。
|
||||
(StubMergerCollect.vp `(rawptr[FileEntry])(t.CVoid(...))` bootstrap 根因)。
|
||||
目标类型经 TypeMergeHandler.GetCTypeInfo 解析 Subscript 类型节点获得。
|
||||
"""
|
||||
Gen: LlvmGeneratorMixin = self.Trans.LlvmGen
|
||||
@@ -2006,7 +2006,7 @@ class ExprCallHandle(BaseHandle):
|
||||
except Exception:
|
||||
TargetType = None
|
||||
if TargetType is None or isinstance(TargetType, ir.VoidType):
|
||||
# 回退:rowptr[X] 语义 = X*(X 为已注册 struct/类,可能模块限定名)
|
||||
# 回退:rawptr[X] 语义 = X*(X 为已注册 struct/类,可能模块限定名)
|
||||
s_name: str | None = None
|
||||
_sl = getattr(sub, 'slice', None)
|
||||
if isinstance(_sl, ast.Attribute):
|
||||
@@ -2017,9 +2017,9 @@ class ExprCallHandle(BaseHandle):
|
||||
TargetType = ir.PointerType(Gen.structs[s_name])
|
||||
else:
|
||||
TargetType = ir.PointerType(ir.IntType(8))
|
||||
return self._emit_rowptr_cast(Node, Gen, TargetType)
|
||||
return self._emit_rawptr_cast(Node, Gen, TargetType)
|
||||
|
||||
def _emit_rowptr_cast(self, Node: ast.Call, Gen: LlvmGeneratorMixin, TargetType: ir.Type) -> ir.Value:
|
||||
def _emit_rawptr_cast(self, Node: ast.Call, Gen: LlvmGeneratorMixin, TargetType: ir.Type) -> ir.Value:
|
||||
"""按 _HandleTypedefCastLlvm 的指针语义执行 bitcast/inttoptr 转换"""
|
||||
if not Node.args:
|
||||
if isinstance(TargetType, ir.PointerType):
|
||||
@@ -2040,15 +2040,15 @@ class ExprCallHandle(BaseHandle):
|
||||
return ArgVal
|
||||
if isinstance(TargetType, ir.PointerType):
|
||||
if isinstance(ArgVal.type, ir.PointerType):
|
||||
return Gen.builder.bitcast(ArgVal, TargetType, name="bitcast_rowptr_cast")
|
||||
return Gen.builder.bitcast(ArgVal, TargetType, name="bitcast_rawptr_cast")
|
||||
if isinstance(ArgVal.type, ir.IntType):
|
||||
return Gen.builder.inttoptr(ArgVal, TargetType, name="inttoptr_rowptr_cast")
|
||||
return Gen.builder.inttoptr(ArgVal, TargetType, name="inttoptr_rawptr_cast")
|
||||
if isinstance(ArgVal.type, ir.BaseStructType):
|
||||
alloca = Gen.builder.alloca(ArgVal.type, name="struct_alloca_rowptr")
|
||||
alloca = Gen.builder.alloca(ArgVal.type, name="struct_alloca_rawptr")
|
||||
Gen.builder.store(ArgVal, alloca, align=8)
|
||||
return Gen.builder.bitcast(alloca, TargetType, name="bitcast_struct_rowptr")
|
||||
return Gen.builder.bitcast(alloca, TargetType, name="bitcast_struct_rawptr")
|
||||
if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.PointerType):
|
||||
return Gen.builder.ptrtoint(ArgVal, TargetType, name="ptrtoint_rowptr_cast")
|
||||
return Gen.builder.ptrtoint(ArgVal, TargetType, name="ptrtoint_rawptr_cast")
|
||||
return ArgVal
|
||||
|
||||
def _HandleInlineExpandLlvm(self, Node: ast.Call, sym_info: CTypeInfo) -> None:
|
||||
@@ -4110,20 +4110,6 @@ class ExprCallHandle(BaseHandle):
|
||||
return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _EmitStringFromValue(self, val: ir.Value) -> ir.Value:
|
||||
Gen = self.Trans.LlvmGen
|
||||
if isinstance(val.type, ir.IntType):
|
||||
buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32))
|
||||
snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
ir.IntType(32),
|
||||
ir.PointerType(ir.IntType(8))
|
||||
]))
|
||||
fmt_ptr = Gen.emit_constant("%d", 'string')
|
||||
Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(32), 32), fmt_ptr, val])
|
||||
return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result")
|
||||
return ir.Constant(ir.IntType(8).as_pointer(), None)
|
||||
|
||||
def _HandleMallocLlvm(self, args: list[ast.AST]) -> ir.Value:
|
||||
Gen = self.Trans.LlvmGen
|
||||
malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
||||
@@ -4352,7 +4338,7 @@ class ExprCallHandle(BaseHandle):
|
||||
# pointee 不是指针类型(ptr 指向"可容纳该结构体的槽"而非指针槽)
|
||||
# → 整对象拷贝。典型:c.DerefAs(result_ty_ptr, result_ty),其中
|
||||
# result_ty = LLVMType.Ptr(...) 为 REnum boxed 值,result_ty_ptr
|
||||
# 因 rowptr[REnum] 被解析成 i32*(LLVMType 首字段 i32)而 pointee
|
||||
# 因 rawptr[REnum] 被解析成 i32*(LLVMType 首字段 i32)而 pointee
|
||||
# 非结构体,原 pointee-equal 判断失配 → 误落"存储指针值"分支
|
||||
# (只写 8 字节),导致 REnum tag/字段全部丢失。
|
||||
# 2) ptr 与 val 指向同一结构体类型(原逻辑)→ 整对象拷贝。
|
||||
|
||||
@@ -58,8 +58,8 @@ class ExprUtils:
|
||||
# 对齐 _HandleLenLlvm L3445-3454:class_member_element_class /
|
||||
# class_members 的键是裸类名,而 var_struct_class 可能带 sha1 前缀
|
||||
# (如 'd81b22c853de40a2.Call')。直查会 miss → 容器字段
|
||||
# (list[...] / rowptr[list[...]],如 ast.Call.args)方法分派失败
|
||||
# → "Undefined method 'get' in class 'rowptr'"。剥前缀 + MRO 链查
|
||||
# (list[...] / rawptr[list[...]],如 ast.Call.args)方法分派失败
|
||||
# → "Undefined method 'get' in class 'rawptr'"。剥前缀 + MRO 链查
|
||||
# element_class(list 特化名,如 list[...ASTptr])优先。
|
||||
_bare: str = BaseClass
|
||||
if len(_bare) > 17 and _bare[16] == '.':
|
||||
|
||||
@@ -1709,6 +1709,24 @@ class FunctionHandle(BaseHandle):
|
||||
EntryBlock = func.append_basic_block(name="entry")
|
||||
Gen.builder = Gen._NewIrBuilder(EntryBlock)
|
||||
Gen.func = func
|
||||
# 函数级 + 语句级 DWARF 调试元数据(--dwarf / --asan 自动开启):建
|
||||
# DISubprogram 挂 func.metadata["dbg"],并把本 builder 的默认调试位置设为
|
||||
# 入口 DILocation(line/column = 该 def 语句的位置)—— 之后本函数体内每条
|
||||
# 新建指令自动带 !dbg,逐语句位置由 Gen._set_node_info 覆盖。这样函数体内
|
||||
# 所有 call(对同模块有定义的被调函数)都有合法 !dbg,llc 不再报
|
||||
# "inlinable function call in a function with debug info must have a !dbg
|
||||
# location" 而丢弃整份 DI。declare/extern 在此之前已 return,不会被挂
|
||||
# !dbg;未启用时 _GetDebugInfo() 返回 None,不产生任何 IR 差异(零影响)。
|
||||
_DbgInfo = Gen._GetDebugInfo()
|
||||
if _DbgInfo is not None:
|
||||
try:
|
||||
_DbgInfo.PushFunction(
|
||||
Gen.builder, func, getattr(Node, 'lineno', 0) or 0,
|
||||
getattr(Node, 'col_offset', 0) + 1)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"发射调试元数据失败: {_e}", "Exception")
|
||||
Gen.variables = {}
|
||||
Gen._reg_values = {}
|
||||
Gen.global_vars = set()
|
||||
@@ -1943,22 +1961,6 @@ class FunctionHandle(BaseHandle):
|
||||
except Exception:
|
||||
pass
|
||||
raise
|
||||
# 函数级 DWARF 调试元数据(--dwarf / --asan 自动开启):为每个 define 建
|
||||
# DISubprogram 挂 func.metadata["dbg"],并在入口块第一条指令挂 DILocation
|
||||
# (line/column = 该 def 语句的位置),使 DWARF 行表至少有一条覆盖函数地址
|
||||
# 区间的行。declare/extern 在此之前已 return,不会被挂 !dbg;未启用时
|
||||
# _GetDebugInfo() 返回 None,不产生任何 IR 差异(零影响)。
|
||||
_DbgInfo = Gen._GetDebugInfo()
|
||||
if _DbgInfo is not None:
|
||||
try:
|
||||
_DbgLoc = _DbgInfo.AttachFunction(
|
||||
func, getattr(Node, 'lineno', 0) or 0, getattr(Node, 'col_offset', 0) + 1)
|
||||
if EntryBlock.instructions:
|
||||
EntryBlock.instructions[0].metadata['dbg'] = _DbgLoc
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"发射调试元数据失败: {_e}", "Exception")
|
||||
if not Gen.builder.block.is_terminated:
|
||||
if 'naked' in fn_attrs:
|
||||
Gen.builder.unreachable()
|
||||
@@ -2009,6 +2011,10 @@ class FunctionHandle(BaseHandle):
|
||||
Gen.builder.ret(ir.Constant(ActualReturnType, None))
|
||||
else:
|
||||
Gen.builder.ret_void()
|
||||
# 离开函数体:停用本 builder 的默认调试位置(含 SP 绑定),防止遗留状态
|
||||
# 被后续模块级指令误用(未启用 --dwarf 时 _DbgInfo 为 None,不做任何事)。
|
||||
if _DbgInfo is not None:
|
||||
_DbgInfo.PopFunction(Gen.builder)
|
||||
Gen.builder = None
|
||||
Gen.func = None
|
||||
Gen._current_class_name = _saved_class_name
|
||||
|
||||
@@ -18,7 +18,7 @@ from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp,
|
||||
|
||||
|
||||
# 注解里的存储类 / 限定符标记:这些名字**不是类名**(联合注解里与指针类混写,
|
||||
# 如 `t.CExtern | rowptr[CompilerFactory]`),提取"指针指向的类"时必须滤掉。
|
||||
# 如 `t.CExtern | rawptr[CompilerFactory]`),提取"指针指向的类"时必须滤掉。
|
||||
_MARKER_ANNOT_NAMES: frozenset[str] = frozenset({
|
||||
'CExtern', 'CExport', 'CStatic', 'CInline', 'CConst', 'CVolatile', 'CRegister',
|
||||
'CAuto', 'CDefine', 'CTypedef', 'CPostdefinition', 'CPtr', 'CArrayPtr', 'CVoid',
|
||||
@@ -860,7 +860,7 @@ class ImportHandle(BaseHandle):
|
||||
def _AnnotationStructName(self, annotation: ast.AST) -> str | None:
|
||||
"""从注解里提取「指针指向的类」短名(递归,0 判定返回 None)
|
||||
|
||||
覆盖形态:`X` / `mod.X` / `rowptr[X]` / `t.CPtr[X]` / 联合 `A | B`(两翼都试)。
|
||||
覆盖形态:`X` / `mod.X` / `rawptr[X]` / `t.CPtr[X]` / 联合 `A | B`(两翼都试)。
|
||||
存储类与限定符标记(`t.CExtern` / `t.CExport` / `t.CPtr` 等)不算类名,
|
||||
由 `_MARKER_ANNOT_NAMES` 过滤;返回的是**短名**,调用方再解析成
|
||||
`Gen.structs` 真实键。
|
||||
@@ -879,7 +879,7 @@ class ImportHandle(BaseHandle):
|
||||
_bn = _base.id
|
||||
elif isinstance(_base, ast.Attribute):
|
||||
_bn = _base.attr
|
||||
if _bn in ('rowptr', 'CPtr', 'CArrayPtr'):
|
||||
if _bn in ('rawptr', 'CPtr', 'CArrayPtr'):
|
||||
_sl: ast.AST = annotation.slice
|
||||
if hasattr(ast, 'Index') and isinstance(_sl, ast.Index):
|
||||
_sl = _sl.value
|
||||
@@ -901,7 +901,7 @@ class ImportHandle(BaseHandle):
|
||||
def _ResolveAnnotationStructKey(self, Gen: LlvmGeneratorMixin, name: str) -> str | None:
|
||||
"""把注解里的类短名解析为 `Gen.structs` 的真实键(0 命中返回 None)
|
||||
|
||||
三条路径与类字段侧的 `rowptr[裸结构]` 登记保持一致:裸名直查 /
|
||||
三条路径与类字段侧的 `rawptr[裸结构]` 登记保持一致:裸名直查 /
|
||||
`class_sha1_map` 加前缀 / 全量短名模糊扫描(跨模块类在
|
||||
`class_sha1_map` 尚未登记该短名时靠这条兜住)。
|
||||
"""
|
||||
@@ -928,7 +928,7 @@ class ImportHandle(BaseHandle):
|
||||
is_string_val = False
|
||||
TypeInfo = None
|
||||
# 【跨模块模块级变量的**类登记**】`CTypeInfo.FromNode` 对
|
||||
# `X | t.CPtr` / `rowptr[X]` 注解只给出指针占位(rowptr[X] 折叠成 i8*),
|
||||
# `X | t.CPtr` / `rawptr[X]` 注解只给出指针占位(rawptr[X] 折叠成 i8*),
|
||||
# 且本函数**只算类型、不登记变量类** → 消费侧 `Mod.Var.Field` 链在
|
||||
# `_get_var_class` 里解析为空:StructGenMixin.vp:139 "属性访问未能解析出
|
||||
# 目标类型/成员"、CallGenLeafKit.vp:589 / ClassGenVTable.vp:99 误报
|
||||
@@ -942,8 +942,8 @@ class ImportHandle(BaseHandle):
|
||||
_eg_tk: str | None = self._ResolveAnnotationStructKey(Gen, _eg_tn)
|
||||
if _eg_tk:
|
||||
_eg_cur: str | None = Gen.var_struct_class.get(VarName)
|
||||
if (not _eg_cur or _eg_cur == 'rowptr' or _eg_cur.endswith('.rowptr')
|
||||
or _eg_cur.startswith('rowptr[')):
|
||||
if (not _eg_cur or _eg_cur == 'rawptr' or _eg_cur.endswith('.rawptr')
|
||||
or _eg_cur.startswith('rawptr[')):
|
||||
Gen.var_struct_class[VarName] = _eg_tk
|
||||
if getattr(Gen, 'global_struct_class', None) is not None:
|
||||
Gen.global_struct_class[VarName] = _eg_tk
|
||||
@@ -1900,10 +1900,10 @@ class ImportHandle(BaseHandle):
|
||||
if ClassName not in Gen.class_member_element_class:
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = spec_in_anno
|
||||
# Subscript 容器字段(list[X] / rowptr[list[X]],如 includes/ast
|
||||
# 的 Call.args / Import.names: rowptr[list[rowptr[AST]]]):非 BinOp
|
||||
# Subscript 容器字段(list[X] / rawptr[list[X]],如 includes/ast
|
||||
# 的 Call.args / Import.names: rawptr[list[rawptr[AST]]]):非 BinOp
|
||||
# 联合,上面两分支不命中 → 容器身份丢失 → 字段方法调用(get/len…)
|
||||
# 分派失败报 "Undefined method 'get' in class 'rowptr'"(Converter.vp)。
|
||||
# 分派失败报 "Undefined method 'get' in class 'rawptr'"(Converter.vp)。
|
||||
# 用与特化生成端同源的 _resolve_type_arg_str 构造 element_class,
|
||||
# 键名与 Gen.structs 中 list 特化名保持一致。
|
||||
if isinstance(item.annotation, ast.Subscript):
|
||||
@@ -1913,13 +1913,13 @@ class ImportHandle(BaseHandle):
|
||||
_elem_slice_s: ast.AST | None = None
|
||||
if _subname_s == 'list':
|
||||
_elem_slice_s = _ann_sub_s.slice
|
||||
elif _subname_s == 'rowptr':
|
||||
elif _subname_s == 'rawptr':
|
||||
_slice_s: ast.AST = _ann_sub_s.slice
|
||||
if isinstance(_slice_s, ast.Subscript):
|
||||
# rowptr[泛型容器](rowptr[list[X]] / rowptr[GSList[Param]]):
|
||||
# rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]):
|
||||
# 容器身份 = 泛型特化名。list 继续走 _elem_slice_s 统一登记;
|
||||
# 其余泛型容器直接登记 element_class(阻塞 B 根因链一环:
|
||||
# 原实现只认内层 list,rowptr[GSList[Param]] 在此空转并跳过
|
||||
# 原实现只认内层 list,rawptr[GSList[Param]] 在此空转并跳过
|
||||
# 裸结构分支 → element_class 缺失 → 字段/局部变量方法分派
|
||||
# 丢失容器身份,FakeDuck 错绑 LinkedNode.append 写穿)。
|
||||
_inner_sub_s: ast.Subscript = _slice_s
|
||||
@@ -1938,11 +1938,11 @@ class ImportHandle(BaseHandle):
|
||||
Gen.class_member_element_class[ClassName] = {}
|
||||
Gen.class_member_element_class[ClassName][VarName] = _ec_gs
|
||||
else:
|
||||
# rowptr[裸结构](如 rowptr[Token]):跨模块 stub 会把自引用/类内
|
||||
# rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内
|
||||
# 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复
|
||||
# struct 身份走 char*→struct cast。HEAD 态 `Token | t.CPtr` 联合
|
||||
# 由上方 BinOp 分支登记;rowptr 重构后此分支补齐(阻塞 A 根因)。
|
||||
# 与 HandlesClassDef 的 rowptr 分支对称。
|
||||
# 由上方 BinOp 分支登记;rawptr 重构后此分支补齐(阻塞 A 根因)。
|
||||
# 与 HandlesClassDef 的 rawptr 分支对称。
|
||||
_slc_name_s: str | None = None
|
||||
if isinstance(_slice_s, ast.Name):
|
||||
_slc_name_s = _slice_s.id
|
||||
@@ -1959,7 +1959,7 @@ class ImportHandle(BaseHandle):
|
||||
else:
|
||||
# 短名模糊扫描(对齐 HandlesAnnAssign 变量侧
|
||||
# 补偿 L597-602):跨模块 `mod.Class` 形态的
|
||||
# rowptr[Class] 字段在 class_sha1_map 尚无该短名
|
||||
# rawptr[Class] 字段在 class_sha1_map 尚无该短名
|
||||
# 时上面两路全 miss → element_class 静默缺失 →
|
||||
# 字段方法调用(factory.PermPool.alloc)链尾类名
|
||||
# 丢失 → TPC 调用分派返回 i32 0 哨兵 → 误报
|
||||
|
||||
@@ -121,7 +121,7 @@ class HandlesTypeMerge(BaseHandle):
|
||||
Result.PtrCount = 1 # struct 变量默认为指针
|
||||
return Result
|
||||
# [builtins 最后匹配] 常规路径全部 miss 后查 includes/builtins.vp 的
|
||||
# CTypedef(size_t → t.CSizeT、rowptr → t.CPtr 内置等),对齐
|
||||
# CTypedef(size_t → t.CSizeT、rawptr → t.CPtr 内置等),对齐
|
||||
# TypeAnnotationResolver._from_node_name 兜底,避免裸名被误判为
|
||||
# 命名结构体(main2.vp `a: size_t` → alloca %...size_t 根因)。
|
||||
try:
|
||||
@@ -695,13 +695,13 @@ class HandlesTypeMerge(BaseHandle):
|
||||
if hasattr(self.Trans, 'ExprCallHandle') and self.Trans.ExprCallHandle is not None:
|
||||
self.Trans.ExprCallHandle._ResolveGenericSlice(node)
|
||||
else:
|
||||
# [修复-阻塞B] rowptr 包裹泛型特化(rowptr[GSList[Param]]):
|
||||
# [修复-阻塞B] rawptr 包裹泛型特化(rawptr[GSList[Param]]):
|
||||
# slice 是 Subscript 且内层 base 命中泛型模板时,若委托 TAR,
|
||||
# 内层 GSList[Param] 会被折叠成 i8* → declare_only 特化从不触发、
|
||||
# 变量/字段容器身份丢失 → 方法调用 FakeDuck 兜底错绑兄弟类
|
||||
# (LinkedNode.append 48B 语义写穿 24B GSList)。此处按裸泛型
|
||||
# 特化(GSList[Param])同语义解析:PtrCount=1(rowptr 与裸名
|
||||
# 同为 1 层指针,对齐 element_class 侧 rowptr[list[X]]==list[X]
|
||||
# 特化(GSList[Param])同语义解析:PtrCount=1(rawptr 与裸名
|
||||
# 同为 1 层指针,对齐 element_class 侧 rawptr[list[X]]==list[X]
|
||||
# 约定),并触发 declare_only 特化(struct + sha1 注册;方法体
|
||||
# 由方法调用时 _try_complete_generic_specialization 补发)。
|
||||
_inner_gsub: ast.Subscript | None = None
|
||||
@@ -727,9 +727,9 @@ class HandlesTypeMerge(BaseHandle):
|
||||
self.Trans.ExprCallHandle._ResolveGenericSlice(_inner_gsub)
|
||||
return ResultInfo
|
||||
# [builtins 最后匹配] base 为 builtins 指针 typedef
|
||||
# (rowptr → t.CPtr):rowptr[X] 等价 X*(对齐 TPV
|
||||
# (rawptr → t.CPtr):rawptr[X] 等价 X*(对齐 TPV
|
||||
# Subscript 语义),委托 TypeAnnotationResolver 统一解析,
|
||||
# 避免被误当作 'rowptr[X]' 结构体/数组维度处理。
|
||||
# 避免被误当作 'rawptr[X]' 结构体/数组维度处理。
|
||||
try:
|
||||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _TAR
|
||||
_tar_sub: CTypeInfo = _TAR.from_node(node, self.Trans.SymbolTable)
|
||||
|
||||
@@ -580,6 +580,18 @@ class BaseGenMixin:
|
||||
self._current_node_info = f"line {self._current_lineno}"
|
||||
if extra_info:
|
||||
self._current_node_info += f" ({extra_info})"
|
||||
# 语句/指令级 DWARF 位置(--dwarf / --asan):每进入一条语句就把当前
|
||||
# builder 的默认调试位置切到该 AST 节点的行/列(col_offset 是 0-based,
|
||||
# +1 转 1-based;无位置时为 0 → 回退函数入口 DILocation)。此后该语句生成
|
||||
# 的所有指令(含 call)自动带本函数 scope 的 !dbg,llc 不再因缺 !dbg 丢弃
|
||||
# 整份 DI。未启用时 dwarf_enabled=False,一次都不触碰 builder.debug_metadata
|
||||
# (零影响:_GetDebugInfo() 也不会被调用)。
|
||||
if self.dwarf_enabled and self.builder is not None:
|
||||
_DbgInfo = self._GetDebugInfo()
|
||||
if _DbgInfo is not None:
|
||||
_DbgInfo.SetStatement(
|
||||
self.builder, self._current_lineno,
|
||||
getattr(node, 'col_offset', -1) + 1)
|
||||
|
||||
def _set_source_info(self, filepath: str) -> None:
|
||||
self._current_source_file = filepath
|
||||
|
||||
@@ -7,10 +7,11 @@ class DebugInfoEmitter:
|
||||
"""函数级 DWARF 调试元数据发射器(llvmlite 文本 IR)。
|
||||
|
||||
每个 Module 一份 DICompileUnit + DIFile;每个 define 一份 DISubprogram
|
||||
(is_distinct=True)挂在 func.metadata["dbg"] 上;函数入口第一条指令挂
|
||||
DILocation(line=该函数 def 行,column=该行 col),使 LLVM 行表至少有一条
|
||||
覆盖函数地址区间的行 —— ASan / llvm-symbolizer 反查函数内任意地址即可得到
|
||||
"<file>.vp:函数起始行"。
|
||||
(is_distinct=True)挂在 func.metadata["dbg"] 上;函数体发射期间把 builder 的
|
||||
默认调试位置设为 "当前函数 SP + 当前语句行/列" 的 DILocation,于是每条新建
|
||||
指令(含所有 call)都自动带本函数 scope 的 !dbg —— 既有语句级粒度,又保证
|
||||
llc 的 "inlinable function call ... must have a !dbg location" 校验通过、
|
||||
不丢弃 DI。没有语句上下文时回退到函数入口位置(line=def 行、column=def 列)。
|
||||
|
||||
仅在 --dwarf(或 --asan 自动开启)时被实例化;把 Module 落成 .ll 文本之前
|
||||
必须调用 Finalize() 补模块级 !llvm.dbg.cu 与 !llvm.module.flags
|
||||
@@ -83,6 +84,88 @@ class DebugInfoEmitter:
|
||||
"scope": sp,
|
||||
})
|
||||
|
||||
# ---------- 语句/指令级位置:按 Builder 上下文管理当前 DILocation ----------
|
||||
#
|
||||
# llvmlite 的 IRBuilder 支持"预设调试位置自动挂载":IRBuilder._insert 里
|
||||
# `if self.debug_metadata is not None and 'dbg' not in instr.metadata:
|
||||
# instr.metadata['dbg'] = self.debug_metadata`
|
||||
# 即设置 builder.debug_metadata 之后,该 builder 新建的每条指令都会自动带
|
||||
# `!dbg !N`。函数带 DISubprogram 时 llc 要求函数体内每个 call(对同模块有
|
||||
# 定义的被调函数)都有 !dbg,否则报
|
||||
# inlinable function call in a function with debug info must have a !dbg
|
||||
# warning: ignoring invalid debug info in <file>
|
||||
# 并丢弃整份 DI(llvm-dwarfdump 拿不到行表)。
|
||||
#
|
||||
# 当前 SP/入口位置直接存放在 IRBuilder 对象上(_TpcDbgSp / _TpcDbgEntry),
|
||||
# 而不是发射器自身:builder 是"每函数一个"的(见 LlvmCodeGenerator.
|
||||
# _NewIrBuilder 的唯一调用点 _EmitFunctionLlvm,且已有 body 的函数被
|
||||
# existing_blocks 守卫提前返回),因此
|
||||
# * 嵌套/特化函数发射会临时换 builder,恢复后自动回到外层函数的 SP,
|
||||
# 不会把 scope 指向别的函数;
|
||||
# * 新函数 = 新 builder = debug_metadata 默认 None,天然不跨函数/模块残留,
|
||||
# 也无需在函数结束时强制清理(PopFunction 只是显式停用,防误用)。
|
||||
|
||||
def PushFunction(self, Builder: ir.IRBuilder, func: ir.Function,
|
||||
Line: int, Column: int) -> ir.DIValue:
|
||||
"""进入函数体:建 DISubprogram(func.metadata["dbg"])并把 Builder 的
|
||||
默认调试位置设为入口 DILocation(line=def 行、column=def 列)。
|
||||
|
||||
返回入口 DILocation。此后该 Builder 新建的每条指令都自动带该位置,直到
|
||||
SetStatement 覆盖 —— 保证函数体内所有 call 至少有合法 !dbg(llc 不再
|
||||
因缺 !dbg 丢弃 DI)。
|
||||
"""
|
||||
Entry: ir.DIValue = self.AttachFunction(func, Line, Column)
|
||||
Builder._TpcDbgSp = func.metadata["dbg"]
|
||||
Builder._TpcDbgEntry = Entry
|
||||
Builder.debug_metadata = Entry
|
||||
return Entry
|
||||
|
||||
def SetStatement(self, Builder: ir.IRBuilder, Line: int, Column: int) -> None:
|
||||
"""把 Builder 的默认调试位置切到(Line, Column)。
|
||||
|
||||
该语句之后新建的指令都带这个位置(scope 恒为当前函数 SP)。未 PushFunction
|
||||
过的 Builder(无 DI 的函数、模块级代码、lambda/async 自建 builder)不做
|
||||
任何事 —— 这些函数没有 DISubprogram,llc 不要求 !dbg,也绝不改动
|
||||
builder.debug_metadata 的默认值。Line<=0(AST 无位置)回退到
|
||||
CurrentOrEntry()。
|
||||
"""
|
||||
Sp: ir.DIValue | None = getattr(Builder, '_TpcDbgSp', None)
|
||||
if Sp is None:
|
||||
return
|
||||
if Line <= 0:
|
||||
Builder.debug_metadata = self.CurrentOrEntry(Builder)
|
||||
return
|
||||
Builder.debug_metadata = self.Module.add_debug_info("DILocation", {
|
||||
"line": Line,
|
||||
"column": Column if Column > 0 else 1,
|
||||
"scope": Sp,
|
||||
})
|
||||
|
||||
def CurrentOrEntry(self, Builder: ir.IRBuilder) -> ir.DIValue | None:
|
||||
"""当前默认位置;尚未设置过语句位置时回退到函数入口 DILocation。
|
||||
|
||||
(add_debug_info 自带 (kind, operands) 缓存,同 (SP, 行, 列) 复用同一
|
||||
DILocation 节点,不会因逐语句调用撑大元数据。)
|
||||
"""
|
||||
Current: ir.DIValue | None = getattr(Builder, 'debug_metadata', None)
|
||||
if Current is not None:
|
||||
return Current
|
||||
return getattr(Builder, '_TpcDbgEntry', None)
|
||||
|
||||
def Clear(self, Builder: ir.IRBuilder) -> None:
|
||||
"""停用该 Builder 的默认调试位置(debug_metadata 置回 None)。"""
|
||||
Builder.debug_metadata = None
|
||||
|
||||
def PopFunction(self, Builder: ir.IRBuilder) -> None:
|
||||
"""离开函数体:停用默认位置并作废该 Builder 的 SP 绑定。
|
||||
|
||||
Builder 随后被丢弃(或由调用方恢复为外层函数的 builder),SP 上下文不会
|
||||
跨函数残留。
|
||||
"""
|
||||
self.Clear(Builder)
|
||||
Builder._TpcDbgSp = None
|
||||
Builder._TpcDbgEntry = None
|
||||
|
||||
def Finalize(self) -> None:
|
||||
"""落 .ll 文本之前补模块级 named metadata;无任何函数时不做(no-op)。"""
|
||||
if self.Finalized or self._CompileUnit is None:
|
||||
|
||||
@@ -251,12 +251,12 @@ class FuncGenMixin:
|
||||
# 查表全部 miss 返回 None → _gep_and_Load_member 静默返回 None →
|
||||
# AnnAssign InitValue 为 None → 变量 alloca 未初始化 → 运行期读垃圾指针。
|
||||
ClassName = self._extract_short_name(ClassName)
|
||||
# rowptr[X] / t.CPtr[X] 指针包装归一:rowptr[X] 是内建裸指针类型
|
||||
# (X*),非真实类——接收者注解/类型名为 'rowptr[AST]' 时字段访问
|
||||
# rawptr[X] / t.CPtr[X] 指针包装归一:rawptr[X] 是内建裸指针类型
|
||||
# (X*),非真实类——接收者注解/类型名为 'rawptr[AST]' 时字段访问
|
||||
# (child.parent)应作用于内层 struct X,否则查 class_members 全 miss
|
||||
# → fast-fail "属性 'parent' 在类 'rowptr[AST]' 中找不到(struct=opaque)"
|
||||
# → fast-fail "属性 'parent' 在类 'rawptr[AST]' 中找不到(struct=opaque)"
|
||||
# (includes/ast/base.vp _set_parent_list bootstrap 根因)。
|
||||
if ClassName.startswith('rowptr[') or ClassName.startswith('t.CPtr['):
|
||||
if ClassName.startswith('rawptr[') or ClassName.startswith('t.CPtr['):
|
||||
_lb_rc: int = ClassName.find('[')
|
||||
if ClassName.endswith(']') and _lb_rc > 0:
|
||||
_inner_rc: str = ClassName[_lb_rc + 1:-1].strip()
|
||||
|
||||
@@ -180,12 +180,22 @@ def SanitizeIRMetadata(text: str) -> str:
|
||||
BlockIsIdentity.append(Identity)
|
||||
|
||||
# 4) 改写全文引用(定义体右值、define/指令行的 !dbg、命名元数据列表)
|
||||
# 定义行左侧的 id 是上一步刚分配的新编号,绝不能再当引用改写:本块的
|
||||
# 新编号区间可能与它自己的旧局部编号区间重叠(例如新编号恰好也是本块
|
||||
# 旧 id 843 → Mapping[843]=1686),一旦改写左侧就会出现两个定义共用同一
|
||||
# id,opt/llc 随即报 "Metadata id is already used"(本 bug 实测残留 276 个
|
||||
# 重复 id)。故定义行只改写 '=' 之后的右值。
|
||||
for k in range(LineCount):
|
||||
Index: int = Owner[k]
|
||||
if Index < 0 or BlockIsIdentity[Index] or not BlockMaps[Index]:
|
||||
continue
|
||||
Fixed: str = _RewriteReferences(Lines[k], BlockMaps[Index])
|
||||
if Fixed != Lines[k]:
|
||||
Line: str = Lines[k]
|
||||
Head: re.Match | None = _Definition.match(Line)
|
||||
if Head:
|
||||
Fixed: str = Line[:Head.end()] + _RewriteReferences(Line[Head.end():], BlockMaps[Index])
|
||||
else:
|
||||
Fixed = _RewriteReferences(Line, BlockMaps[Index])
|
||||
if Fixed != Line:
|
||||
Lines[k] = Fixed
|
||||
|
||||
# 5) 定义体索引(新 id -> 右值文本),供命名元数据判重
|
||||
|
||||
@@ -277,9 +277,9 @@ class ASTSymbolExtractor:
|
||||
value_node=node.value,
|
||||
))
|
||||
else:
|
||||
# rowptr 是编译器内置语法(TPC/TPV 双端),不可重定义:
|
||||
# 忽略任何对 rowptr 的 typedef 声明,防止覆盖内置裸指针语义
|
||||
if var_name == 'rowptr':
|
||||
# rawptr 是编译器内置语法(TPC/TPV 双端),不可重定义:
|
||||
# 忽略任何对 rawptr 的 typedef 声明,防止覆盖内置裸指针语义
|
||||
if var_name == 'rawptr':
|
||||
return
|
||||
result.typedefs.append(TypedefSymbolData(
|
||||
name=var_name,
|
||||
|
||||
@@ -18,15 +18,15 @@ if TYPE_CHECKING:
|
||||
class TypeAnnotationResolver:
|
||||
"""从 AST 节点解析类型注解,独立于 CTypeInfo 数据模型。"""
|
||||
|
||||
# 编译器内置语法:rowptr(TPC/TPV 双端内置,不可重定义)
|
||||
# rowptr[T] 固定表示"裸指针,指向原始类型 T"(等价 t.CPtr[T]);
|
||||
# 单独 rowptr 等价 t.CPtr(void*)。
|
||||
_BUILTIN_ROWPTR_NAME: str = 'rowptr'
|
||||
# 编译器内置语法:rawptr(TPC/TPV 双端内置,不可重定义)
|
||||
# rawptr[T] 固定表示"裸指针,指向原始类型 T"(等价 t.CPtr[T]);
|
||||
# 单独 rawptr 等价 t.CPtr(void*)。
|
||||
_BUILTIN_ROWPTR_NAME: str = 'rawptr'
|
||||
_BUILTIN_ROWPTR_VALUE: str = 't.CPtr'
|
||||
|
||||
@classmethod
|
||||
def _builtin_rowptr_info(cls) -> CTypeInfo:
|
||||
"""返回内置 rowptr 的 CTypeInfo(t.CPtr 语义:BaseType=CVoid, PtrCount=1)"""
|
||||
def _builtin_rawptr_info(cls) -> CTypeInfo:
|
||||
"""返回内置 rawptr 的 CTypeInfo(t.CPtr 语义:BaseType=CVoid, PtrCount=1)"""
|
||||
info: CTypeInfo = CTypeInfo()
|
||||
info.BaseType = t.CVoid()
|
||||
info.PtrCount = 1
|
||||
@@ -97,7 +97,7 @@ class TypeAnnotationResolver:
|
||||
# ============================================================
|
||||
# builtins 最后匹配(对齐 TPV TypeGenResolve._lookup_builtins_typedef):
|
||||
# 所有常规注解解析路径 miss 后,扫描 includes/builtins.vp 的
|
||||
# "NAME: t.CTypedef = TYPE" 声明作为最终兜底(rowptr/size_t 等)。
|
||||
# "NAME: t.CTypedef = TYPE" 声明作为最终兜底(rawptr/size_t 等)。
|
||||
# builtins 始终纳入编译链但不在 App 文件 import 闭包,其 typedef 不随
|
||||
# from_imports 注入,故需按源文件扫描兜底。
|
||||
# ============================================================
|
||||
@@ -259,11 +259,11 @@ class TypeAnnotationResolver:
|
||||
|
||||
@classmethod
|
||||
def builtins_typedef_value(cls, TypeName: str) -> str | None:
|
||||
"""返回 builtins.vp 中 CTypedef 声明的原始类型值(如 rowptr → 't.CPtr')
|
||||
"""返回 builtins.vp 中 CTypedef 声明的原始类型值(如 rawptr → 't.CPtr')
|
||||
|
||||
供 stub 生成 / 类型字符串消费端判断"base[arg]"下标是否为 builtins 指针
|
||||
typedef(rowptr[AST] → AST*),防止字符串化产物被误建为 phantom 结构体。
|
||||
rowptr 已内置于编译器(语法保留字):即使 builtins.vp 不再声明、
|
||||
typedef(rawptr[AST] → AST*),防止字符串化产物被误建为 phantom 结构体。
|
||||
rawptr 已内置于编译器(语法保留字):即使 builtins.vp 不再声明、
|
||||
或用户自行 typedef,也始终返回内置值(不可重定义)。
|
||||
"""
|
||||
if not TypeName:
|
||||
@@ -279,12 +279,12 @@ class TypeAnnotationResolver:
|
||||
|
||||
命中(该名字确为 builtins typedef)返回解析出的 CTypeInfo,
|
||||
miss 返回 None(交由调用方走原有兜底)。
|
||||
rowptr 为编译器内置语法:优先于一切外部声明(不可重定义)。
|
||||
rawptr 为编译器内置语法:优先于一切外部声明(不可重定义)。
|
||||
"""
|
||||
if not TypeName:
|
||||
return None
|
||||
if TypeName == cls._BUILTIN_ROWPTR_NAME:
|
||||
return cls._builtin_rowptr_info()
|
||||
return cls._builtin_rawptr_info()
|
||||
data: dict = cls._scan_builtins()
|
||||
type_str: str | None = data['typedefs'].get(TypeName)
|
||||
if type_str is None:
|
||||
@@ -301,10 +301,10 @@ class TypeAnnotationResolver:
|
||||
def _from_node_name(Node: ast.Name, SymbolTable: dict | SymbolTable) -> CTypeInfo:
|
||||
"""处理 ast.Name 节点"""
|
||||
TypeName: str = Node.id
|
||||
# 编译器内置语法 rowptr(不可重定义):单独 rowptr 等价 t.CPtr(void*),
|
||||
# 编译器内置语法 rawptr(不可重定义):单独 rawptr 等价 t.CPtr(void*),
|
||||
# 优先于 SymbolTable/任何 typedef 声明。
|
||||
if TypeName == TypeAnnotationResolver._BUILTIN_ROWPTR_NAME:
|
||||
return TypeAnnotationResolver._builtin_rowptr_info()
|
||||
return TypeAnnotationResolver._builtin_rawptr_info()
|
||||
TypeObj: type | None = CTypeHelper.GetTModuleCType(TypeName)
|
||||
if TypeObj is None:
|
||||
TypeObj = getattr(t, TypeName, None)
|
||||
@@ -454,7 +454,7 @@ class TypeAnnotationResolver:
|
||||
Result.PtrCount = 1
|
||||
return Result
|
||||
# [builtins 最后匹配] 常规路径全部 miss 后的最终兜底:
|
||||
# 扫描 includes/builtins.vp 的 CTypedef 声明(rowptr/size_t 等,
|
||||
# 扫描 includes/builtins.vp 的 CTypedef 声明(rawptr/size_t 等,
|
||||
# 对齐 TPV TypeGenResolve)。命中返回解析结果,miss 走 from_type_name。
|
||||
builtins_info: CTypeInfo | None = TypeAnnotationResolver._lookup_builtins_typedef(TypeName, SymbolTable)
|
||||
if builtins_info is not None:
|
||||
@@ -800,8 +800,8 @@ class TypeAnnotationResolver:
|
||||
ReturnTypeInfo = TypeAnnotationResolver.from_node(return_node, SymbolTable)
|
||||
Result.FuncPtrReturn = ReturnTypeInfo if ReturnTypeInfo else CTypeInfo.VoidTypeInfo()
|
||||
return Result
|
||||
# [builtins 最后匹配] 裸名 builtins typedef 下标(rowptr[int] → Ptr(int)):
|
||||
# 与 TPV Subscript 分支同口径——base 是 builtins typedef(rowptr → t.CPtr),
|
||||
# [builtins 最后匹配] 裸名 builtins typedef 下标(rawptr[int] → Ptr(int)):
|
||||
# 与 TPV Subscript 分支同口径——base 是 builtins typedef(rawptr → t.CPtr),
|
||||
# 结果 = 切片类型外包 base 的指针层数。
|
||||
if isinstance(base, ast.Name):
|
||||
base_info: CTypeInfo | None = TypeAnnotationResolver._lookup_builtins_typedef(base.id, SymbolTable)
|
||||
|
||||
Reference in new issue
Block a user