fix(codegen): 内建标量别名双参指针包装 + 解引用赋值按 c.Load 原样拷贝

HandlesExprBuiltin: int/char/bool/float/double(v, t.CPtr) 不再被标量分支吞掉第二参,改由 TSpecialCallHandle._HandleTPtrCastLlvm 处理(等价 t.CInt(v, t.CPtr));此前退化为 ptrtoint+trunc,includes/argparse.vp get_bool 因此恒真,--version/--project 一律打印帮助。

HandlesAssign: 目标与右值同为解引用(*a = *b)时按 c.Load 语义做原样字节拷贝,抽出 CSpecialCallHandle.EmitRawCopyLlvm 复用;此前按 fptosi/trunc 转换,mlirlite ConstFloat 的位双关 *&fv_bits = *&val 会把 double 位模式截断为整数,浮点字面量全部错误。
This commit is contained in:
TermiNexus committed 2026-10-05 14:14:25 +08:00
1 parent 397bab1360
commit 59378e6a2a
3 files changed
+50 -14

No files matched your search

+15
View File
@@ -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)
+10
View File
@@ -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':
+25 -14
View File
@@ -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