fix(viperc): 解引用赋值补位拷贝(*a = *b 按位重解释,不做数值转换)
现场(math.vp sin/cos):
u: uint64 = 0; xv: double = x
*&u = *&xv # 位拷贝,应为 movq %xmm0, %rax
ef: uint64 = (u >> 52) & 0x7FF
生成:404084 cvttsd2si %xmm0, %rax ← 把 double 数值截断成 int64
代价:u 成了数值截断结果 ⇒ ef/neg 全错;x 为负时(-1.5 → u = -1)ef 命中 0x7FF
⇒ 直接 return x - x = NaN ⇒ sin/cos 负参全废。
VPC 的 `*p = v` 目标路径无条件 coerce_to_type(rhs, pointee);TPC 侧早有该判据
(HandlesAssign.py:592 调 HandlesSpecialCall.EmitRawCopyLlvm,注释明确"位拷贝,绝不转换"),
VPC 漏了 ⇒ 本次按同口径补齐。
- RHS 为 UnaryOp(Deref)(`*p`)且两侧是**等宽标量**时:按**源自身类型** load(类型与槽的
存储类型一致),再 bitcast 成目的类型存回 —— 不做任何数值转换;
- 不用"按目的类型重解释的 load"(`load i64, ptr %xv`):文本层 T2「store→load 转发」按**名字**
替换,会把 `store double %x, ptr %xv` 的 %x 顶进这条 i64 行,报
`use of value '%x' expects different type than prior uses: 'i64' vs 'f64'`;
- 源操作数限定非调用形状,避免与前面 rhs_val 的求值重复;源不是指针 ⇒ fail-fast;
- 两侧位宽不等或含聚合 ⇒ 不做位拷贝,交回 coerce 路径(等价改动前行为,聚合位拷贝未支持)。
This commit is contained in:
1 parent
5ea0ce094e
commit
217f5f021d
1 file changed
+47
@@ -1348,6 +1348,20 @@ novirtual class AssignGenMixin:
|
||||
if string.strcmp(at.attr, "Ptr") == 0: return 1
|
||||
return 0
|
||||
|
||||
def _DerefPunBits(self, pool: memhub.MemBuddy*, ty: mlirlite.LLVMType*) -> int:
|
||||
"""位型 pun(`*a = *b`)的标量位宽:浮点取浮点位宽、整数取整型位宽、指针按 64、其余返回 0。
|
||||
|
||||
只对**两侧等宽**的标量做位拷贝(double↔u64 / float↔u32 / half↔u16 / ptr↔u64 …);
|
||||
返回 0 表示该侧不是标量(聚合等)或位宽未知 ⇒ 调用方不做位拷贝,交回 coerce 路径。
|
||||
"""
|
||||
if ty is None: return 0
|
||||
fb: int = self.Gen.ExprGenBase.get_llvm_float_bits(ty)
|
||||
if fb != 0: return fb
|
||||
ib: int = self.Gen.ExprGenBase.get_llvm_type_bits(ty)
|
||||
if ib != 0: return ib
|
||||
if self.Gen.ExprGenBase.is_ptr_type(ty) != 0: return 64
|
||||
return 0
|
||||
|
||||
def _is_64bit_scalar_ty(self, node: ast.AST*) -> int:
|
||||
"""Return 1 for a 64-bit scalar type (CUInt64T/CInt64T/CSizeT)."""
|
||||
if node is None: return 0
|
||||
@@ -3065,6 +3079,39 @@ novirtual class AssignGenMixin:
|
||||
pointee_w: mlirlite.LLVMType* = ptr_w.Ty.Pointee
|
||||
if pointee_w is None:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "deref write target type missing (pointee is empty)", "TypeError")
|
||||
# `*a = *b` 是 c.Load 语义的**位拷贝**(type-pun):把源内存按**源自身类型**读出来,
|
||||
# 再按位重解释(bitcast)成目的类型存回去 —— **绝不做数值转换**。缺了它
|
||||
# `*&u = *&xv`(double → uint64)会退化成 fptosi(现场 `cvttsd2si %xmm0, %rax`)
|
||||
# ⇒ IEEE 位型丢失(isnan/isinf、sin/cos 的 ef/neg 全错)。
|
||||
# 判据/口径与 TPC HandlesSpecialCall.EmitRawCopyLlvm 一致(位宽必须匹配目的)。
|
||||
# 注意**不能**写成"按目的类型重解释的 load"(`load i64, ptr %xv`):文本层 T2
|
||||
# 「store→load 转发」是按**名字**替换的,会把 `store double %x, ptr %xv` 的 `%x`
|
||||
# 顶进这条 i64 行 ⇒ `use of value '%x' expects different type ... 'i64' vs 'f64'`。
|
||||
# 按源自身类型 load(类型与槽的存储类型一致)就不会踩这个问题。
|
||||
if asgn.value is not None and asgn.value.kind() == ast.ASTKind.UnaryOp:
|
||||
uo_r: ast.UnaryOp* = ast.UnaryOp*(asgn.value)
|
||||
# 源操作数限定为非调用形状(`&x` / `p` / `a.b` / `arr[i]` …):调用形状的指针源
|
||||
# 已被前面的 rhs_val 翻译求值过一次,这里再译会重复求值(位拷贝语义下无意义)。
|
||||
if uo_r.op == ast.OpKind.Deref and uo_r.operand is not None and uo_r.operand.kind() != ast.ASTKind.Call:
|
||||
src_ptr_w: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, uo_r.operand, None, 0, trans)
|
||||
if src_ptr_w is None or src_ptr_w.Ty is None or self.Gen.ExprGenBase.is_ptr_type(src_ptr_w.Ty) == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(asgn.value, "the operand of unary '*' on the right-hand side of a deref bit-copy must be a pointer type (type inference degraded)", "TypeError")
|
||||
src_pointee_w: mlirlite.LLVMType* = src_ptr_w.Ty.Pointee
|
||||
if src_pointee_w is None:
|
||||
self.Gen.TypeGenErr.fatal_error(asgn.value, "deref bit-copy source pointee type missing", "TypeError")
|
||||
dst_bits_w: int = self._DerefPunBits(pool, pointee_w)
|
||||
src_bits_w: int = self._DerefPunBits(pool, src_pointee_w)
|
||||
if dst_bits_w != 0 and dst_bits_w == src_bits_w:
|
||||
native_w: mlirlite.Value* = mlirlite.build_load(builder, src_pointee_w, src_ptr_w)
|
||||
if native_w is None:
|
||||
self.Gen.TypeGenErr.fatal_error(asgn.value, "deref bit-copy failed to load from the source pointer", "InternalCompilerError")
|
||||
bits_w: mlirlite.Value* = mlirlite.build_bitcast(builder, native_w, pointee_w)
|
||||
if bits_w is None:
|
||||
self.Gen.TypeGenErr.fatal_error(asgn.value, "deref bit-copy failed to reinterpret the loaded value", "InternalCompilerError")
|
||||
mlirlite.build_store(builder, bits_w, ptr_w)
|
||||
continue
|
||||
# 两侧位宽不等(或含聚合):这里不做位拷贝,交回下面的 coerce 路径
|
||||
# (fail-safe,即等价于改动前行为;聚合位拷贝尚未支持)。
|
||||
sv_w: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, pointee_w, node, trans)
|
||||
mlirlite.build_store(builder, sv_w, ptr_w)
|
||||
continue
|
||||
|
||||
Reference in new issue
Block a user