diff --git a/lib/core/Handles/HandlesAssign.py b/lib/core/Handles/HandlesAssign.py index 9e64ad4..680e392 100644 --- a/lib/core/Handles/HandlesAssign.py +++ b/lib/core/Handles/HandlesAssign.py @@ -569,6 +569,21 @@ class AssignHandle(BaseHandle): f"解引用赋值 '*' 的操作数必须是指针类型(类型推断退化," f"实际 {Ptr.type}){Gen._get_node_info()}" ) + # `*a = *b` is the c.Load form: copy the raw bytes (width = target + # pointee), never convert the value. Without it a bit-pun such as + # `*&bits = *&dbl` degrades to fptosi/trunc and loses the IEEE bits. + if isinstance(Node.value, ast.UnaryOp) and isinstance(Node.value.op, ast.Deref): + SrcPtr: ir.Value | None = self.HandleExprLlvm(Node.value.operand) + if SrcPtr is None: + self._RaiseUnresolvedExpr("解引用写入", Node.value.operand, Gen) + return + if not isinstance(SrcPtr.type, ir.PointerType): + raise Exception( + f"解引用赋值右侧 '*' 的操作数必须是指针类型(类型推断退化," + f"实际 {SrcPtr.type}){Gen._get_node_info()}" + ) + if self.Trans.CSpecialCallHandle.EmitRawCopyLlvm(Ptr, SrcPtr, Gen): + return DerefValue: ir.Value | None = self.HandleExprLlvm(Node.value) if DerefValue is None: self._RaiseUnresolvedExpr("解引用写入", Node.value, Gen) diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index abfafa5..f18fc6e 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -48,6 +48,16 @@ class ExprBuiltinHandle(BaseHandle): return None FuncName: str = Node.func.id + # Two-arg scalar alias form (int(v, t.CPtr) / char / bool / float / double) + # is a pointer wrap, not a scalar cast: route it to the same exit as the + # attribute form t.CInt(v, t.CPtr). Ignoring the CPtr mark would degrade + # it to a bare trunc, e.g. includes/argparse.vp get_bool() reading a + # pointer's low 32 bits instead of the stored value. + if (len(Node.args) >= 2 and FuncName in ('int', 'char', 'bool', 'float', 'double') + and self.Trans.ExprCallHandle._IsCPtrMark(Node.args[1])): + PtrCastAttr: str = 'C' + FuncName[0].upper() + FuncName[1:] + return self.Trans.TSpecialCallHandle._HandleTPtrCastLlvm(Node, PtrCastAttr) + if FuncName == 'print': return self._HandlePrintLlvm(Node) elif FuncName == 'len': diff --git a/lib/core/Handles/HandlesSpecialCall.py b/lib/core/Handles/HandlesSpecialCall.py index 2baa11f..4a9ef68 100644 --- a/lib/core/Handles/HandlesSpecialCall.py +++ b/lib/core/Handles/HandlesSpecialCall.py @@ -165,6 +165,28 @@ class CSpecialCallHandle(BaseHandle): Gen._store(ValToStore, target_ptr) return ir.Constant(ir.IntType(32), 1) + def EmitRawCopyLlvm(self, DstPtr: ir.Value, SrcPtr: ir.Value, Gen: LlvmGeneratorMixin, + NamePrefix: str = "rawcopy") -> bool: + """Emit `*dst = *src` as a raw byte copy (c.Load semantics); False if unusable. + + The width comes from the destination pointee and the source pointer is + bitcast to it, so this reinterprets memory instead of converting values + (e.g. `*&bits = *&dbl` must keep the IEEE bits, not fptosi). + """ + if not isinstance(DstPtr.type, ir.PointerType) or not isinstance(SrcPtr.type, ir.PointerType): + return False + Pointee: ir.Type = DstPtr.type.pointee + if isinstance(Pointee, ir.VoidType): + return False + TargetPtrTy: ir.PointerType = ir.PointerType(Pointee) + SrcCast: ir.Value = SrcPtr if SrcPtr.type == TargetPtrTy else Gen.builder.bitcast(SrcPtr, TargetPtrTy, name=f"{NamePrefix}_src_cast") + Loaded: ir.Value | None = Gen._load(SrcCast, name=f"{NamePrefix}_loaded") + if Loaded is None: + return False + DstCast: ir.Value = DstPtr if DstPtr.type == TargetPtrTy else Gen.builder.bitcast(DstPtr, TargetPtrTy, name=f"{NamePrefix}_dst_cast") + Gen._store(Loaded, DstCast) + return True + def _HandleCLoadLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen if len(Node.args) < 2: @@ -192,20 +214,9 @@ class CSpecialCallHandle(BaseHandle): var_ptr = Gen.variables[var_name] if isinstance(var_ptr.type, ir.PointerType): pointee = var_ptr.type.pointee - # 按 pointee 类型 bitcast src 加载,bitcast dst 存储 - if src_val.type.pointee != pointee: - src_cast = Gen.builder.bitcast(src_val, ir.PointerType(pointee), name="cLoad_src_cast") - else: - src_cast = src_val - Loaded = Gen._load(src_cast, name="cLoad_loaded") - if Loaded is None: - return ir.Constant(ir.IntType(32), 0) - if dst_val.type.pointee != pointee: - dst_cast = Gen.builder.bitcast(dst_val, ir.PointerType(pointee), name="cLoad_dst_cast") - else: - dst_cast = dst_val - Gen._store(Loaded, dst_cast) - return ir.Constant(ir.IntType(32), 1) + TargetPtrTy: ir.PointerType = ir.PointerType(pointee) + DstPtr: ir.Value = dst_val if dst_val.type == TargetPtrTy else Gen.builder.bitcast(dst_val, TargetPtrTy, name="cLoad_dst_cast") + return ir.Constant(ir.IntType(32), 1 if self.EmitRawCopyLlvm(DstPtr, src_val, Gen, "cLoad") else 0) def _HandleCDerefLlvm(self, Node: ast.Call) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen