diff --git a/App/lib/core/Gen/Expr/ExprGenBase.vp b/App/lib/core/Gen/Expr/ExprGenBase.vp index 00dac01..fa2aaff 100644 --- a/App/lib/core/Gen/Expr/ExprGenBase.vp +++ b/App/lib/core/Gen/Expr/ExprGenBase.vp @@ -455,7 +455,7 @@ novirtual class ExprGenBase: if callee is None: return None ent: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(callee) if ent is not None and ent.Ty is not None: return ent.Ty - # REnum variant ctor `EnumType.Variant(...)`: the callee is not a struct + # REnum variant ctor `EnumType.Variant(...)`: the callee is not a struct # name, but materializes the base enum, so return that aggregate type. if cl.func.kind() == ast.ASTKind.Attribute: # Take the segment left of the variant name as the enum class name @@ -474,6 +474,24 @@ novirtual class ExprGenBase: """Are a and b the same aggregate type; 1=yes / 0=no.""" if a is None or b is None: return 0 return self.Gen.AssignGen._stg_ty_equal(pool, a, b) + # _agg_value_slot_ty - 值语义槽:源表达式的变量槽**自身**持有聚合物(`x: Foo`,Spec.PtrLevel == 0)。 + # 形参按「聚合一律按指针传」的 ABI 到达,但它在被调者里同样物化在自己的槽中,读槽即值拷贝; + # 真·指针值(`p: Foo*`,Spec.PtrLevel >= 1)返回 None,仍必须显式解引用(c.deref(p) / *p)。 + # 返回该聚合类型;不适用时 None。 + def _agg_value_slot_ty(self, node: ast.AST*, val: mlirlite.Value*, trans: HT.Translator*) -> mlirlite.LLVMType*: + """Aggregate type when the source is a variable slot holding the aggregate by value; else None.""" + n: ast.AST* = self._value_node_of(node) + if n is None or n.kind() != ast.ASTKind.Name: return None + nm: str = (ast.Name*(n)).id + if nm is None or trans is None: return None + ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm) + if ve is None or ve.Alloca is None or ve.Spec is None: return None + # 必须是槽本身(若已被加载成指针值,说明源本来就是个指针,不豁免)。 + if ve.Alloca is not val: return None + # 声明的就是 T*(PtrLevel>=1):真指针,必须显式解引用。 + if ve.Spec.PtrLevel != 0: return None + if self.is_ptr_type(ve.Alloca.Ty) == 0: return None + return ve.Alloca.Ty.Pointee # Type coercion: int sext/trunc, float fpext/fptrunc, int<->float si2fp/fp2si. def coerce_to_type(self, builder: mlirlite.IRBuilder*, val: mlirlite.Value*, target_ty: mlirlite.LLVMType*, node: ast.AST* = None, trans: HT.Translator* = None) -> mlirlite.Value*: """Coerce val to target_ty: int sext/trunc, float fpext/fptrunc, int/float conversions.""" @@ -564,7 +582,7 @@ novirtual class ExprGenBase: if val_bits != 0 and target_fbits != 0: return mlirlite.build_si2fp(builder, val, target_ty) # float -> int if val_fbits != 0 and target_bits != 0: return mlirlite.build_fp2si(builder, val, target_ty) - # Aggregate value -> pointer: spill a temp to the entry block and pass its + # Aggregate value -> pointer: spill a temp to the entry block and pass its # address (TPV never passes aggregates by value). if self.is_ptr_type(val.Ty) == 0 and self.is_ptr_type(target_ty) != 0: vk_agg: int = val.Ty.kind() @@ -596,6 +614,11 @@ novirtual class ExprGenBase: # Rule 3: implicit ptr -> value for non-basic types (Foo* -> Foo) is # forbidden, except "construction materialization" (see _ctor_call_agg_ty). ctor_p2v: mlirlite.LLVMType* = self._ctor_call_agg_ty(node) + # 值语义槽豁免:源是变量槽自身持有聚合物(`x: Foo`;形参虽按「聚合按指针传」的 + # ABI 到达,也物化在自己的槽中)时,读槽 = 值拷贝(`self.f = elem` 这类写法)。 + slot_p2v: mlirlite.LLVMType* = self._agg_value_slot_ty(node, val, trans) + if self._same_agg_ty(builder.Pool, slot_p2v, target_ty) != 0: + return mlirlite.build_load(builder, target_ty, val) if self._same_agg_ty(builder.Pool, ctor_p2v, target_ty) == 0: m_p2v: str = "implicit value/pointer conversion for non-basic types is forbidden (except construction materialization): a pointer type cannot be implicitly converted to a non-basic value (Foo* -> Foo); to dereference use c.deref(p) / *p explicitly, or cast explicitly" p2v_txt: str = GenApi.escape_fstring_copy(f"; source type {self._type_text(builder.Pool, val.Ty)} -> target value type {self._type_text(builder.Pool, target_ty)}") @@ -620,7 +643,7 @@ novirtual class ExprGenBase: if val is None or val.Ty is None: return 0 return self.Gen.ExprGenOps.should_zext_widen(pool, val, None, node, trans) - # translate_ptr_arith: ptr +/- int via getelementptr (index scaled by pointee + # translate_ptr_arith: ptr +/- int via getelementptr (index scaled by pointee # size); array pointees ([N x ty]*) decay to element pointers first. def translate_ptr_arith(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, ptr_val: mlirlite.Value*, int_val: mlirlite.Value*, op: int) -> mlirlite.Value*: """Pointer arithmetic: ptr +/- int via GEP with the index scaled by element size."""