diff --git a/App/lib/core/Gen/CallGenCBuiltin.vp b/App/lib/core/Gen/CallGenCBuiltin.vp index 7ccd0a0..1cbae0f 100644 --- a/App/lib/core/Gen/CallGenCBuiltin.vp +++ b/App/lib/core/Gen/CallGenCBuiltin.vp @@ -40,6 +40,38 @@ import lib.core.Gen.CallGenBase as CallGenBase # ============================================================ +# ============================================================ +# _IsTypeExpr / _IsCastWrappingDeref - c.Deref 加载宽度推断的转换包裹判定 +# (镜像 TPC HandlesSpecialCall:转换链包裹 Deref 时允许从赋值注解推断 +# 加载宽度;ifexp/binop 包裹不放行,避免 i8* 错 bitcast 成其他位宽读) +# ============================================================ +def _IsTypeExpr(node: ast.AST | t.CPtr) -> int: + """节点是否为类型表达式(Name/Attribute/Subscript/BinOp|)""" + if node is None: + return 0 + k: int = node.kind() + if k == ast.ASTKind.Name or k == ast.ASTKind.Attribute or k == ast.ASTKind.Subscript: + return 1 + if k == ast.ASTKind.BinOp: + bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node) + if bop.op == ast.OpKind.BitOr: + return 1 + return 0 + + +def _IsCastWrappingDeref(rhs: ast.AST | t.CPtr, deref_node: ast.AST | t.CPtr) -> int: + """rhs 是否为"类型转换链包裹 c.Deref"(如 (T | t.CPtr)(t.CPtr(c.Deref(p))))""" + if rhs is None: + return 0 + if t.CUInt64T(rhs) == t.CUInt64T(deref_node): + return 1 + if rhs.kind() == ast.ASTKind.Call: + cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(rhs) + if cl.args is not None and len(cl.args) == 1 and _IsTypeExpr(cl.func) != 0: + return _IsCastWrappingDeref(cl.args.get(0), deref_node) + return 0 + + # ============================================================ # 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug) # ============================================================ @@ -98,25 +130,33 @@ class CallGenCBuiltin(CallGenBase.CallGenBase): # 掩盖了缺陷。 match pointee: case llvmlite.LLVMType.Int(pointee_width): - # 仅当 c.Deref 是赋值语句的直接 RHS(如 v: int = c.Deref(p)) - # 时才用注解推断读取宽度(对齐 TPC _infer_deref_target_type - # 的直接 RHS 检查);嵌套在 while 条件/比较/binop/类型转换 - # 调用中(如 while c.Deref(p) != 0、total += t.CInt(c.Deref(p))) - # 不推断,否则 i8* 会被残留 CurAssignAnnot 误判为 i32* - # 读 4 字节 → StringIterTest ASCII sum/manual strcmp 失败。 - if pointee_width == 8 and trans is not None \ - and trans.CurAssignAnnot is not None \ - and trans.CurAssignNode is not None \ - and t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode): + # 允许推断:c.Deref 是赋值语句直接 RHS(v: int = c.Deref(p)) + # 或处于类型转换链包裹中(如 vt: t.CVoid | t.CPtr = + # t.CVoid(c.Deref(p)))。嵌套在 while 条件/比较/binop/ + # 其他调用中(如 while c.Deref(p) != 0、total += + # t.CInt(c.Deref(p)))不推断,否则 i8* 会被残留 + # CurAssignAnnot 误判为 i32* 读 4 字节 → StringIterTest + # ASCII sum/manual strcmp 失败。 + allow_infer: int = 0 + if trans is not None and trans.CurAssignNode is not None: + if t.CUInt64T(cl) == t.CUInt64T(trans.CurAssignNode): + allow_infer = 1 + elif _IsCastWrappingDeref(trans.CurAssignNode, cl) != 0: + allow_infer = 1 + if pointee_width == 8 and allow_infer != 0 \ + and trans is not None and trans.CurAssignAnnot is not None: dref_ty: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( trans.Pool, trans.CurAssignAnnot, trans._imported_modules, trans._from_imports, trans) if dref_ty is not None: dref_bits: int = HandlesExpr.get_llvm_type_bits(dref_ty) dref_fbits: int = HandlesExpr.get_llvm_float_bits(dref_ty) - # 仅整数/浮点目标(struct 值目标不推断,保持 i8 读) + dref_is_ptr: int = HandlesExpr.is_ptr_type(dref_ty) + # 整数/浮点/指针目标均推断(指针 → bitcast 后 + # load 8 字节;struct 值目标不推断,保持 i8 读) dref_ptr: llvmlite.Value | t.CPtr = None - if (dref_bits != 0 or dref_fbits != 0) and dref_bits != 8: + if (dref_bits != 0 or dref_fbits != 0 or dref_is_ptr != 0) \ + and dref_bits != 8: dref_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, dref_ty) dref_ptr = llvmlite.build_bitcast( builder, ptr_val, dref_ptr_ty)