diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 43f578d..a081f37 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -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