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:
1 parent
397bab1360
commit
59378e6a2a
3 files changed
+50
-14
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user