fix(gen/call): 跨模块调用 SSA 整型实参按定义侧形参扩宽
declare 由调用点实参链建立,而 _coerce_arg_value_to_ty 对非常量(SSA)整型此前原样返回,导致 declare/call 停在调用点窄宽度(string.strncpy 第三参 i32),与定义侧(vpi 注解 n: t.CSizeT => i64)不一致,并经 .stub.ll 传播到未调用该函数的消费方模块 现按源符号性 zext/sext 扩宽(真源 ExprGenBase._zext_or_sext_val,先例 CallGenCtor._translate_t_type_cast),实参 AST/trans 下传;self_off 模块级 0、方法 1 效果: WebTest 危险级签名不一致 1 => 0
This commit is contained in:
1 parent
31b8dccffd
commit
a83d183abb
4 files changed
+61
-12
No files matched your search
@@ -1716,7 +1716,7 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||
# 先按 vpi 定义侧形参 coerce 实参(宽度对齐),再建 declare(ABI 通用化)
|
||||
head = self.Gen.CallGenLib._coerce_args_to_def_params(
|
||||
pool, builder, call_name, head, total_count)
|
||||
pool, builder, call_name, head, total_count, cargs, 1, trans)
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||||
# 检查变长函数 + C ABI 提升(cargs 是实参 AST,self_offset=1 跳过 self)
|
||||
is_variadic_3441: int = self.Gen.CallGenVa._check_and_promote_variadic_call(
|
||||
|
||||
@@ -1430,7 +1430,8 @@ class CallGenDispatch(CallGenBase.CallGenBase):
|
||||
ret_ty3 = llvmlite.Int32(pool)
|
||||
# 先按 vpi 定义侧形参 coerce 实参(宽度对齐),再建 declare
|
||||
head3 = self.Gen.CallGenLib._coerce_args_to_def_params(
|
||||
pool, builder, mangled3, head3, total3)
|
||||
pool, builder, mangled3, head3, total3,
|
||||
cargs, 1, trans)
|
||||
self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3)
|
||||
return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0)
|
||||
else:
|
||||
|
||||
@@ -214,8 +214,17 @@ class CallGenLib(CallGenBase.CallGenBase):
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
call_name: str,
|
||||
head: llvmlite.Value | t.CPtr,
|
||||
count: int) -> llvmlite.Value | t.CPtr:
|
||||
"""把跨模块调用实参 coerce 到 vpi 定义侧形参类型,返回重建的实参链"""
|
||||
count: int,
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = None,
|
||||
self_off: int = 0,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""把跨模块调用实参 coerce 到 vpi 定义侧形参类型,返回重建的实参链
|
||||
|
||||
cargs/self_off/trans:实参 AST 列表与其在实参链中的偏移(模块级函数 0、
|
||||
方法 1——链首元素是 self,而 vpi 段 0 即 self 占位段)。仅用于非常量
|
||||
(SSA)整型扩宽时的**源符号性**判定(与 ExprGenBase._zext_or_sext_val
|
||||
同源);缺省时该判定退化为有符号(sext),与 coerce_to_type 默认一致。
|
||||
"""
|
||||
if pool is None or builder is None or call_name is None or head is None:
|
||||
return head
|
||||
if self._is_sha1_mangled_call(call_name) == 0:
|
||||
@@ -270,7 +279,13 @@ class CallGenLib(CallGenBase.CallGenBase):
|
||||
tgt_ty: llvmlite.LLVMType | t.CPtr = VpiReader._resolve_vpi_param_annot_seg(
|
||||
pool, sha1_buf, cls_nm, meth_nm, idx, i32_ty, i8_ptr_ty)
|
||||
if tgt_ty is not None and cur.Ty is not None:
|
||||
node_v = self._coerce_arg_value_to_ty(pool, builder, cur, tgt_ty)
|
||||
# 实参 AST(源符号性判定用):链下标 idx 减 self 偏移即 AST 下标
|
||||
arg_idx: int = idx - self_off
|
||||
arg_node: ast.AST | t.CPtr = None
|
||||
if cargs is not None and arg_idx >= 0 and arg_idx < len(cargs):
|
||||
arg_node = cargs.get(arg_idx)
|
||||
node_v = self._coerce_arg_value_to_ty(
|
||||
pool, builder, cur, tgt_ty, arg_node, trans)
|
||||
if new_head is None:
|
||||
new_head = node_v
|
||||
else:
|
||||
@@ -290,8 +305,11 @@ class CallGenLib(CallGenBase.CallGenBase):
|
||||
# - 同宽 → 原样;
|
||||
# - 窄化(目标更窄,本簇主场景 i32→i8/i16)→ 常量按目标宽度重建常量,
|
||||
# SSA 用 trunc(trunc 与符号无关,窄化安全);
|
||||
# - 扩宽交由 _ensure_method_declare 既有"定义侧更宽才采用"逻辑 + 下遍
|
||||
# 收敛时按形参 coerce(需 AST 判定符号性,本函数无 AST,不越权处理)。
|
||||
# - 扩宽(定义侧形参更宽)→ 常量按目标宽度重建常量;SSA 按**源**符号性
|
||||
# 扩宽(zext/sext,真源 ExprGenBase._zext_or_sext_val;同规则先例
|
||||
# ExprGenBase.coerce_to_type / CallGenCtor._translate_t_type_cast /
|
||||
# CallGenLib._promote_clib_call_args)→ declare 由扩宽后的实参链建立,
|
||||
# declare/call/define 三者同宽(此前 SSA 原样返回 → 与定义侧宽度不一致)。
|
||||
# 指针:实参与目标皆指针且"泛型 i8* 性"不同时 bitcast(如 i32*→i8*),
|
||||
# 使 declare 指针类型与 define 一致;同为 i8* 或同为具体 struct 指针
|
||||
# 则原样保留(避免把 list*/Struct* 无谓降级为 i8* 的 IR 噪声)。
|
||||
@@ -300,8 +318,14 @@ class CallGenLib(CallGenBase.CallGenBase):
|
||||
def _coerce_arg_value_to_ty(self, pool: rowptr[memhub.MemBuddy],
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
val: llvmlite.Value | t.CPtr,
|
||||
tgt_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||||
"""把单个实参 Value 转换到目标形参类型,无法安全转换时原样返回"""
|
||||
tgt_ty: llvmlite.LLVMType | t.CPtr,
|
||||
node: ast.AST | t.CPtr = None,
|
||||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||||
"""把单个实参 Value 转换到目标形参类型,无法安全转换时原样返回
|
||||
|
||||
node/trans:实参 AST 与其翻译器(仅 SSA 整型扩宽的源符号性判定用,
|
||||
委托 ExprGenBase._zext_or_sext_val;缺省退化为有符号 sext)。
|
||||
"""
|
||||
if pool is None or builder is None or val is None or tgt_ty is None or val.Ty is None:
|
||||
return val
|
||||
match val.Ty:
|
||||
@@ -327,13 +351,37 @@ class CallGenLib(CallGenBase.CallGenBase):
|
||||
# 仅编译期常量在此重建:const_int 按十进制值打印,
|
||||
# i32 -1 → i64 -1(sext 语义)、i32 4294967295 →
|
||||
# i64 4294967295(zext 语义),各自保持原类型数值,
|
||||
# 无需 AST 判符号性;SSA 值(非常量)判符号性需 AST,
|
||||
# 交由上游 coerce_to_type(本函数无 AST,不越权处理)。
|
||||
# 无需 AST 判符号性。
|
||||
if val.IsConst != 0:
|
||||
nv_w: llvmlite.Value | t.CPtr = llvmlite.const_int(
|
||||
pool, bits_b, val.IntVal)
|
||||
if nv_w is not None:
|
||||
return nv_w
|
||||
return val
|
||||
# 非常量(SSA)扩宽:此前原样返回,declare 与 call 保持
|
||||
# 调用点窄宽度,而定义侧(vpi 形参注解)更宽 → 同一
|
||||
# 符号 declare/call 与 define 宽度不一致(includes/
|
||||
# requests/__init__.vp `string.strncpy(..., host_len)`
|
||||
# 3 参 i32 而 string.vp 定义 `n: t.CSizeT`=i64;同模块/
|
||||
# 同依赖的 strncpy 常量实参分支已扩宽成 i64,SSA 实参
|
||||
# 分支未扩宽 → 同一模块两条 declare 宽度不同)。
|
||||
# 扩宽方向由**源**符号性决定(与 coerce_to_type /
|
||||
# CallGenCtor 同一真源 ExprGenBase._zext_or_sext_val:
|
||||
# i1/i8、无符号源 → zext;否则 sext),与目标类型无关。
|
||||
# 扩宽后 declare 由本函数返回的新实参链建立(param_head
|
||||
# → _ensure_method_declare),declare/call/define 三者同宽。
|
||||
if bits_b > bits_a:
|
||||
if self.Gen.ExprGenBase._zext_or_sext_val(
|
||||
pool, val, node, trans) != 0:
|
||||
nv_zw: llvmlite.Value | t.CPtr = llvmlite.build_zext(
|
||||
builder, val, tgt_ty)
|
||||
if nv_zw is not None:
|
||||
return nv_zw
|
||||
else:
|
||||
nv_sw: llvmlite.Value | t.CPtr = llvmlite.build_sext(
|
||||
builder, val, tgt_ty)
|
||||
if nv_sw is not None:
|
||||
return nv_sw
|
||||
return val
|
||||
case _:
|
||||
pass
|
||||
|
||||
@@ -1637,7 +1637,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# call 实参 / declare / define 三者宽度一致(B3 同族通用化;反例:
|
||||
# su8250.putchar 定义 (i16,i8) 而调用点字面量 1016=i32 固化宽)。
|
||||
head = self.Gen.CallGenLib._coerce_args_to_def_params(
|
||||
pool, builder, call_name, head, can)
|
||||
pool, builder, call_name, head, can, cargs, 0, trans)
|
||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
||||
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
||||
|
||||
Reference in new issue
Block a user