fix(CodeGen): 裸结构体形参按 C ABI 按值、修正 |t.CPtr 指针层级,对齐 TPC 并消除签名发散
- FuncGenDef/VpiReader._AggregateParamTy: C ABI 外部声明(t.CExtern/t.State)的裸结构体形参按值 %Struct(可取完整定义时),真 opaque 降级 i64;TPV 内部函数/方法维持 Ptr(struct)。三处(定义侧/函数注入侧/方法注入侧)同口径 - TypeGenResolve/VpiReader: BinOp(A|t.CPtr) 的指针别名守卫改为 pointee 为已注册 struct 才吸收,否则追加一层 => VOIDPTR|t.CPtr 由 i8* 修正为 i8**(对齐 TPC) - 效果: SetConsoleScreenBufferSize 等 6 个符号由 i64/%COORD* 双形态收敛为按值,同符号多形态数 193->186
This commit is contained in:
1 parent
31df298341
commit
8312e653e8
4 files changed
+140
-23
No files matched your search
@@ -1400,13 +1400,29 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
|
||||
# ⇒ i64*(见 TypeGenResolve.vp BinOp(A | t.CPtr) 的 typedef 别名保真判定),
|
||||
# 本侧经同一 GenApi.resolve_typedef_or_map 命中后亦 ⇒ Ptr(i64) = i64*;
|
||||
# **两侧同型即收敛**,不再需要把 declare 侧坍缩成 i8* 去迁就定义侧。
|
||||
# 仍坍缩 i8* 的三类与定义侧对称:解析失败兜底;裸枚举名(定义侧
|
||||
# get_struct_type miss 同样落 i8*);指针别名(first_td 不置位,对应定义侧
|
||||
# td_res_is_ptr != 0 的守卫)。
|
||||
# 仍坍缩 i8* 的两类与定义侧对称:解析失败兜底;裸枚举名(定义侧
|
||||
# get_struct_type miss 同样落 i8*)。指针别名(first_td 不置位)
|
||||
# 已按下段"追加 1 层"处理(与定义侧 td_res_is_ptr 口径同步)。
|
||||
# 指针别名(first_td 不置位,如 VOIDPTR = CVoid|CPtr → i8*、
|
||||
# HANDLE = VOIDPTR → i8*):`| t.CPtr` **追加 1 层** → i8**(不吸收)。
|
||||
# 判据与定义侧 TypeGenResolve.vp BinOp(A | t.CPtr) 的指针层数口径
|
||||
# 同源(TPC HandlesTypeMerge._MergeAllComponentTypes L940-946:
|
||||
# 仅 IsStruct 时吸收 1 层):pointee 命中 find_struct_by_type
|
||||
# ⇒ 类引用语义 ⇒ 吸收(返回 first_ty 即 Ptr(struct));
|
||||
# 否则 ⇒ Ptr(first_ty)。此前无条件坍缩 i8* → 定义侧/注入侧虽同为
|
||||
# i8* 但比 TPC 短一层(TPC `VOIDPTR | t.CPtr` = i8**)。
|
||||
if first_qual != 0 or first_wl != 0 or first_td != 0:
|
||||
return llvmlite.Ptr(pool, first_ty)
|
||||
if first_ty.kind() == llvmlite.LLVMType.Struct:
|
||||
return llvmlite.Ptr(pool, first_ty)
|
||||
if first_ty.kind() == llvmlite.LLVMType.Ptr:
|
||||
match first_ty:
|
||||
case llvmlite.LLVMType.Ptr(pointee_v):
|
||||
if GenApi.find_struct_by_type(pointee_v) is not None:
|
||||
return first_ty
|
||||
case _:
|
||||
pass
|
||||
return llvmlite.Ptr(pool, first_ty)
|
||||
return i8_ptr_ty
|
||||
return i8_ptr_ty
|
||||
if has_cvoid != 0:
|
||||
@@ -2646,6 +2662,61 @@ def _ensure_full_value_types(mod: llvmlite.LLVMModule | t.CPtr,
|
||||
pass
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _AggregateParamTy - 裸结构体(聚合)形参类型统一判据
|
||||
#
|
||||
# 「裸结构体形参」(注解是结构体/类名、无 `| t.CPtr`)的 LLVM 形参类型判据,
|
||||
# 三处必须同步(同一文字、同一结果):
|
||||
# 1) 定义侧 FuncGenDef.forward_declare_functions L26x-28x 与
|
||||
# translate_function_def 的 extern 声明分支 L54x-56x;
|
||||
# 2) declare 注入侧 _inject_function_declare / _inject_method_declare(本函数);
|
||||
# 3) 调用侧:per-函数 found_func 走 ExprGenBase.coerce_to_type L491-495
|
||||
# (指针 → 非指针值 build_load 解引用);跨模块名走
|
||||
# CallGenLib._coerce_args_to_def_params(按本判据得出的形参类型 coerce)。
|
||||
# 规则(对齐 TPC:TransPyC/lib/core/Handles/HandlesTypeMerge.py L940-946
|
||||
# 「仅 IsStruct 吸收 1 层 CPtr」+ LLVMCG/TypeConvert.py L137-143
|
||||
# 「CStruct → 具名结构体值」):
|
||||
# * C ABI 外部声明(t.CExtern/t.State,本模块无 define 侧)→ 按值 %Struct:
|
||||
# 真实被调方在 DLL/CRT,形参按 C ABI 传值(TPC 定义侧 stub 同为按值,见
|
||||
# TransPyV/output/db613a1bd6a3ca26.stub.ll:346 `%COORD`)。
|
||||
# 值参数要求具名类型有**完整定义**(llvm-as 实测:opaque/未定义具名类型
|
||||
# 作值参数 ⇒ "invalid type for function argument";指针形式亦要求具名类型
|
||||
# 存在 ⇒ "use of undefined type")。判据 = 结构体在注册表可查且非 opaque
|
||||
# (find_struct_by_type 命中,先例 _ensure_full_value_types L2633;
|
||||
# opaque 哨兵 fcount<0 见 includes/llvmlite/__module.vp L466-491):
|
||||
# 命中 → 先注册完整定义(module_add_named_type,同一先例)再按值;
|
||||
# 真 opaque / 未注册 → 降级 i64:不引用任何具名类型(恒合法),Windows x64
|
||||
# ABI 小结构体(≤8 字节,如 COORD)按整数寄存器传、位兼容(同原 L2905-2908
|
||||
# 依据),且与定义侧同样降级 ⇒ 同符号签名仍逐字一致。
|
||||
# * TPV 内部函数/方法(存在 define 侧)→ Ptr(struct):与定义侧逐字一致
|
||||
# (FuncGenDef L28x/L64x、ClassGenVTable L744-750「对象即指针」),
|
||||
# 指针目标只需 opaque 声明(module_ensure_opaque_for_type 先例 L2850)。
|
||||
# ============================================================
|
||||
def _AggregateParamTy(mod: llvmlite.LLVMModule | t.CPtr,
|
||||
pool: rowptr[memhub.MemBuddy],
|
||||
ty: llvmlite.LLVMType | t.CPtr,
|
||||
is_c_abi: int) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""裸结构体形参类型(C ABI 按值 / 内部 Ptr(struct),见上方注释)"""
|
||||
if mod is None or pool is None or ty is None:
|
||||
return ty
|
||||
if is_c_abi != 0:
|
||||
# 真 opaque 哨兵:fcount < 0(includes/llvmlite/__module.vp L491)
|
||||
is_opaque_ap: int = 0
|
||||
match ty:
|
||||
case llvmlite.LLVMType.Struct(_, fcount_ap, _):
|
||||
if fcount_ap < 0:
|
||||
is_opaque_ap = 1
|
||||
case _:
|
||||
pass
|
||||
if is_opaque_ap == 0 and GenApi.find_struct_by_type(ty) is not None:
|
||||
_ensure_full_value_types(mod, pool, ty)
|
||||
return ty
|
||||
return llvmlite.Int64(pool)
|
||||
ptr_ty_ap: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, ty)
|
||||
llvmlite.module_ensure_opaque_for_type(mod, pool, ptr_ty_ap)
|
||||
return ptr_ty_ap
|
||||
|
||||
|
||||
# ============================================================
|
||||
# _inject_global_variable_declare - 从 vpi AnnAssign 创建模块级全局变量 declare
|
||||
#
|
||||
@@ -2779,6 +2850,13 @@ def _inject_function_declare(pool: rowptr[memhub.MemBuddy],
|
||||
has_extern = GenApi.has_decorator_marker(fd.returns, "CExtern")
|
||||
has_state = GenApi.has_decorator_marker(fd.returns, "State")
|
||||
has_export = GenApi.has_decorator_marker(fd.returns, "CExport")
|
||||
# 裸结构体形参判据(见 _AggregateParamTy):C ABI 外部声明(t.CExtern/
|
||||
# t.State,本模块无 define 侧)按值;其余(含 t.CExport,其 define 侧在
|
||||
# 本树内)保持 Ptr(struct)。与定义侧 FuncGenDef is_extern_decl 同源,
|
||||
# 保证注入侧 declare 与定义侧 define 同口径(三处必须同步)。
|
||||
agg_is_c_abi: int = 0
|
||||
if has_extern != 0 or has_state != 0:
|
||||
agg_is_c_abi = 1
|
||||
|
||||
# 计算 mangled name
|
||||
# CExport/CExtern/State/main 函数用裸名,其他函数用源模块 SHA1 前缀
|
||||
@@ -2893,7 +2971,9 @@ def _inject_function_declare(pool: rowptr[memhub.MemBuddy],
|
||||
if pseg_ty is not None:
|
||||
match pseg_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Int64(pool)
|
||||
# 裸结构体形参:C ABI 按值 / 内部 Ptr(struct)
|
||||
# (判据与降级见 _AggregateParamTy,三处必须同步)
|
||||
param_ty = _AggregateParamTy(mod, pool, pseg_ty, agg_is_c_abi)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
@@ -2902,14 +2982,11 @@ def _inject_function_declare(pool: rowptr[memhub.MemBuddy],
|
||||
resolved_ty: llvmlite.LLVMType | t.CPtr = GenApi.resolve_annotation_type(
|
||||
pool, ag.annotation, imported_modules, from_imports, trans)
|
||||
if resolved_ty is not None:
|
||||
# 结构体按值参数 → i64:跨模块结构体在本模块是 opaque
|
||||
# (未定义字段),LLVM 不允许 opaque struct 作为函数参数
|
||||
# (llc: invalid type for function argument)。Windows ABI
|
||||
# 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。
|
||||
# CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。
|
||||
# 裸结构体参数 → _AggregateParamTy(同一判据)。
|
||||
match resolved_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Int64(pool)
|
||||
param_ty = _AggregateParamTy(mod, pool, resolved_ty, agg_is_c_abi)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
@@ -3087,7 +3164,11 @@ def _inject_method_declare(pool: rowptr[memhub.MemBuddy],
|
||||
if pseg_ty is not None:
|
||||
match pseg_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Int64(pool)
|
||||
# 裸结构体形参:方法恒为 TPV 内部符号(mangled =
|
||||
# {sha1}.{Class}.{method},无 C ABI 外部 define),
|
||||
# 故 is_c_abi=0 → Ptr(struct),与定义侧
|
||||
# ClassGenVTable L744-750 逐字一致(三处必须同步)。
|
||||
param_ty = _AggregateParamTy(mod, pool, pseg_ty, 0)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
@@ -3096,14 +3177,11 @@ def _inject_method_declare(pool: rowptr[memhub.MemBuddy],
|
||||
resolved_ty: llvmlite.LLVMType | t.CPtr = GenApi.resolve_annotation_type(
|
||||
pool, ag.annotation, imported_modules, from_imports, trans)
|
||||
if resolved_ty is not None:
|
||||
# 结构体按值参数 → i64:跨模块结构体在本模块是 opaque
|
||||
# (未定义字段),LLVM 不允许 opaque struct 作为函数参数
|
||||
# (llc: invalid type for function argument)。Windows ABI
|
||||
# 小结构体(≤8 字节,如 COORD)按整数寄存器传,映射 i64 兼容。
|
||||
# CArray 参数 → 元素指针 ty*(C 数组衰减,与编译侧一致)。
|
||||
# 裸结构体参数 → _AggregateParamTy(同一判据,is_c_abi=0)。
|
||||
match resolved_ty:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Int64(pool)
|
||||
param_ty = _AggregateParamTy(mod, pool, resolved_ty, 0)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
|
||||
@@ -461,7 +461,9 @@ class ExprGenBase:
|
||||
return llvmlite.build_fp2si(builder, val, target_ty)
|
||||
# 聚合值 → 指针: 落栈 materialize 临时对象后传其地址
|
||||
# FuncGenDef.vp:263-271 已确认「裸类/数组形参一律 lowering 为
|
||||
# Ptr(struct/array)」——Viper 不存在"按值传结构体"的形参。故调用点的
|
||||
# Ptr(struct/array)」——TPV 内部函数/方法不存在"按值传结构体"的形参
|
||||
# (唯一例外:C ABI 外部声明(t.CExtern/t.State)的裸结构体形参按值,
|
||||
# 见 VpiReader._AggregateParamTy「三处必须同步」)。故调用点的
|
||||
# rvalue 聚合(函数调用返回值、下标元素 load 等)必须落栈取址,否则
|
||||
# 实参类型与指针形参失配(gfx.vp `eye.Sub(target).Norm()`、
|
||||
# `Mat4_Mul(m, Mat4_Translate(...))`、`DrawTriangle(.., v[i], ..)` 等
|
||||
|
||||
@@ -267,9 +267,26 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
return 0
|
||||
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
|
||||
# CArray 形参 → 元素指针 ty*(C 数组衰减,与 add_param 一致)
|
||||
# 例外(三处必须同步:本处 / translate_function_def 的 extern
|
||||
# 声明分支 / VpiReader 注入侧 _AggregateParamTy):
|
||||
# C ABI 外部声明(t.CExtern/t.State,本模块无 define 侧)的
|
||||
# 裸结构体形参按值 %Struct —— 真实被调方在 DLL/CRT,形参 ABI
|
||||
# 由 C 头决定。TPC 定义侧同为按值(TransPyC/lib/core/Handles/
|
||||
# HandlesTypeMerge.py L940-946「仅 IsStruct 吸收 1 层 CPtr」
|
||||
# + LLVMCG/TypeConvert.py L137-143「CStruct → 具名结构体值」)。
|
||||
# 值参数要求具名类型有**完整定义**(llvm-as 实测:opaque/未定义
|
||||
# 具名类型作值参数 ⇒ "invalid type for function argument"),
|
||||
# 故判据 = 该结构体在注册表可查(find_struct_by_type 命中,
|
||||
# 先例 VpiReader._ensure_full_value_types L2633),命中则先
|
||||
# 注册完整定义再按值(ensure_struct_def_in_module,先例
|
||||
# CallGenCtor.vp L478);不命中(真 opaque)保持 Ptr(struct)。
|
||||
match resolved:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty = llvmlite.Ptr(pool, resolved)
|
||||
if is_extern_decl != 0 and self.Gen.StructGen.find_struct_by_type(resolved) is not None:
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved)
|
||||
param_ty = resolved
|
||||
else:
|
||||
param_ty = llvmlite.Ptr(pool, resolved)
|
||||
case llvmlite.LLVMType.Array(aelem_ty, _):
|
||||
param_ty = llvmlite.Ptr(pool, aelem_ty)
|
||||
case _:
|
||||
@@ -529,9 +546,17 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if resolved_e is not None:
|
||||
# 裸类形参 → Ptr(struct)(对象即指针,与方法形参一致)
|
||||
# CArray 形参 → 元素指针 ty*(C 数组衰减)
|
||||
# 本分支恒为 C ABI 外部声明(is_extern_decl != 0,见
|
||||
# 上方 if):裸结构体形参按值 %Struct(判据与降级
|
||||
# 同 forward_declare_functions / VpiReader
|
||||
# _AggregateParamTy,三处必须同步)。
|
||||
match resolved_e:
|
||||
case llvmlite.LLVMType.Struct(_, _, _):
|
||||
param_ty_e = llvmlite.Ptr(pool, resolved_e)
|
||||
if self.Gen.StructGen.find_struct_by_type(resolved_e) is not None:
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved_e)
|
||||
param_ty_e = resolved_e
|
||||
else:
|
||||
param_ty_e = llvmlite.Ptr(pool, resolved_e)
|
||||
case llvmlite.LLVMType.Array(aelem_ty_e, _):
|
||||
param_ty_e = llvmlite.Ptr(pool, aelem_ty_e)
|
||||
case _:
|
||||
|
||||
@@ -2514,16 +2514,28 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
# 的类型,参与“基类型 + 指针层数”合并(对齐 TPC
|
||||
# HandlesTypeMerge._MergeAllComponentTypes L887-946:
|
||||
# sizet | t.CPtr ⇒ 基类型 i64 + 1 层指针 = i64*)。
|
||||
# 仅保留非指针结果:Ptr(...)(类 __new__ 的 Ptr(struct)、
|
||||
# 指针别名)继续走下方 get_struct_type 回退与解析失败兜底,
|
||||
# 该两条既有路径行为逐字节不变。
|
||||
# 指针层数口径(本处 / VpiReader 注入侧 / 调用侧三处必须同步):
|
||||
# `| t.CPtr` 恒为"追加 1 层指针",唯一例外是 struct 引用语义
|
||||
# (struct 变量本身即指针)时吸收这 1 层:
|
||||
# VOIDPTR(= CVoid|CPtr → i8*)| t.CPtr ⇒ i8**(不吸收)
|
||||
# CVoid|CPtr 裸用 ⇒ i8*(见上方 CVoid 分支)
|
||||
# CChar|t.CPtr ⇒ i8*、CUInt64T|t.CPtr ⇒ i64*(标量 + 1 层)
|
||||
# 类(__new__ → Ptr(struct))| t.CPtr ⇒ Ptr(struct)(吸收 1 层)
|
||||
# 依据 TPC TransPyC/lib/core/Handles/HandlesTypeMerge.py
|
||||
# L940-946:Result.PtrCount += cptr_count,仅
|
||||
# `IsStruct and base_ptr_count > 0` 时再减 1(吸收)。
|
||||
# 判据 = Ptr 的 pointee 是否为**已注册 struct**
|
||||
# (find_struct_by_type 命中 ⇒ 类引用语义 ⇒ 吸收)。
|
||||
if keep_other_ty == 0 and other_node is not None and other_node.kind() == ast.ASTKind.Name:
|
||||
other_nm_td: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node)
|
||||
if other_nm_td.id is not None:
|
||||
td_res_is_ptr: int = 0
|
||||
match other_ty:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
td_res_is_ptr = 1
|
||||
case llvmlite.LLVMType.Ptr(pointee_td):
|
||||
if self.Gen.StructGen.find_struct_by_type(pointee_td) is not None:
|
||||
td_res_is_ptr = 1
|
||||
else:
|
||||
td_res_is_ptr = 0
|
||||
case _:
|
||||
td_res_is_ptr = 0
|
||||
if td_res_is_ptr == 0:
|
||||
|
||||
Reference in new issue
Block a user