From 19f9c53a5f6eab9d9bdd4e6be9a1e5bbfefbd183 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 28 Oct 2026 23:06:17 +0800 Subject: [PATCH] fix(codegen): zero-extend unsigned 16-bit widening in every coercion path A uint16 value that is widened to int/uint32/uint64 must be zero-extended (movzwl), and an int16 value must be sign-extended (movswl). coerce_to_type picks the direction from the source AST node's declared signedness, which requires the translator; several call sites omitted it and therefore fell back to sext, so a big-endian uint16 such as 0xDCBC became 0xFFFF...DCBC (numGlyphs 56508 read as -9028 and every glyph range collapsed to zero). - pass trans at the assignment, annotated-assignment, augmented-assignment, global-array initializer, index, element-store, constructor-argument, conditional-expression and return coercion sites - printf argument promotion now receives the argument expression and trans, so uint16/uint8 promote with zext like any other widening - print selects the format token and extension from the source signedness (%u/%llu + zext for unsigned, %d/%lld + sext for signed) instead of a hardcoded %d + sext for 8/16-bit values --- App/lib/core/Gen/AssignGenMixin.vp | 22 ++++++++-------- App/lib/core/Gen/Call/CallGenCall.vp | 10 ++++---- App/lib/core/Gen/Call/CallGenCtor.vp | 14 +++++------ App/lib/core/Gen/Call/CallGenDispatch.vp | 6 ++--- App/lib/core/Gen/Call/CallGenLeafKit.vp | 32 ++++++++++++++++++------ App/lib/core/Gen/Call/CallGenMixin.vp | 6 ++--- App/lib/core/Gen/Call/CallGenProp.vp | 2 +- App/lib/core/Gen/Class/ClassGenVTable.vp | 2 +- App/lib/core/Gen/Expr/ExprGenOps.vp | 16 ++++++------ App/lib/core/Gen/Stmt/StmtGenCifMixin.vp | 22 ++++++++-------- 10 files changed, 74 insertions(+), 58 deletions(-) diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 2ab0e30..a8e2db0 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1947,7 +1947,7 @@ novirtual class AssignGenMixin: bp_s: mlirlite.Value* = mlirlite.build_gep_array(builder, arr_ty, elem_ty, array_alloca, bidx_s) if bp_s is None: break bvv: mlirlite.Value* = mlirlite.const_int32(pool, sv_s[bi_s]) - bsv: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, bvv, elem_ty, e0_s) + bsv: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, bvv, elem_ty, e0_s, trans) mlirlite.build_store(builder, bsv, bp_s) return 0 @@ -1999,7 +1999,7 @@ novirtual class AssignGenMixin: self.Gen.TypeGenErr.fatal_error(elem_node, "global array initializer element translation failed", "TypeError") # Type coercion (e.g. i32 -> i8); Pointee is statically i64 so compare with != 0 store_val: mlirlite.Value* = elem_val - if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee != 0: store_val = self.Gen.ExprGenBase.coerce_to_type(builder, elem_val, elem_ptr.Ty.Pointee, elem_node) + if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee != 0: store_val = self.Gen.ExprGenBase.coerce_to_type(builder, elem_val, elem_ptr.Ty.Pointee, elem_node, trans) # BigEndian array: store each element byte-swapped (pairs the un-swap on element read). store_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, store_val, byte_order) mlirlite.build_store(builder, store_val, elem_ptr) @@ -2039,8 +2039,8 @@ novirtual class AssignGenMixin: target_float_ty: mlirlite.LLVMType* = mlirlite.Double(pool) if target_fbits == 32: target_float_ty = mlirlite.Float(pool) # Coerce both operands to the target float type - lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, target_float_ty, node) - rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, target_float_ty, node) + lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, target_float_ty, node, trans) + rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, target_float_ty, node, trans) if op == ast.OpKind.Add: return mlirlite.build_fadd(builder, lhs, rhs) if op == ast.OpKind.Sub: return mlirlite.build_fsub(builder, lhs, rhs) if op == ast.OpKind.Mult: return mlirlite.build_fmul(builder, lhs, rhs) @@ -2232,7 +2232,7 @@ novirtual class AssignGenMixin: self.Gen.TypeGenErr.fatal_error(target, f"attribute binary op failed op={aug.op}", "TypeError") # 5. Coerce the type and store - result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node) + result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node, trans) if result is None: # fail-fast: type coercion failed self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError") @@ -2307,7 +2307,7 @@ novirtual class AssignGenMixin: self.Gen.TypeGenErr.fatal_error(target, f"subscript binary op failed op={aug.op}", "TypeError") # 5. Coerce the type and store - result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node) + result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node, trans) if result is None: # fail-fast: type coercion failed self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError") @@ -2455,7 +2455,7 @@ novirtual class AssignGenMixin: self.Gen.TypeGenErr.fatal_error(target, f"applying binary op to variable '{nm.id}' failed op={aug.op}", "TypeError") # 5. Store the result - result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node) + result = self.Gen.ExprGenBase.coerce_to_type(builder, result, target_ty, node, trans) if result is None: # fail-fast: type coercion failed self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError") @@ -2919,7 +2919,7 @@ novirtual class AssignGenMixin: trans.CurAssignNode = None return 0 self.Gen.ExprGenBase.fail_if_str_annot_ast_agg_ptr(rhs_val, aa.annotation, node) - rhs_coerced: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, nl_target_ty, node) + rhs_coerced: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, nl_target_ty, node, trans) mlirlite.build_store(builder, rhs_coerced, nl_ptr) # Clear the assignment context (all four branches must stay in sync) trans.CurAssignAnnot = None @@ -2970,7 +2970,7 @@ novirtual class AssignGenMixin: if target_ty_mg is not None: # str/bytes is not a generic pointer: bare str/bytes annotation with an aggregate-pointer RHS self.Gen.ExprGenBase.fail_if_str_annot_ast_agg_ptr(rhs_val_mg, aa.annotation, node) - rhs_val_mg = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node) + rhs_val_mg = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node, trans) # t.VolatileT module-level global: the initializing store carries volatile vol_mga: int = self.Gen.VarGen.var_is_volatile(self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)) mlirlite.build_store(builder, rhs_val_mg, mod_glob, vol_mga) @@ -3689,7 +3689,7 @@ novirtual class AssignGenMixin: case _: elem_ptr_gen = mlirlite.build_gep(builder, elem_gen, obj_val_gen, key_val_gen) if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None: - if elem_ptr_gen.Ty.Pointee != 0: store_val_gen = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, elem_ptr_gen.Ty.Pointee, node) + if elem_ptr_gen.Ty.Pointee != 0: store_val_gen = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, elem_ptr_gen.Ty.Pointee, node, trans) mlirlite.build_store(builder, store_val_gen, elem_ptr_gen) setitem_done = 1 if setitem_done == 0: self.Gen.TypeGenErr.fatal_error(target, "subscript ptr is None") @@ -3768,7 +3768,7 @@ novirtual class AssignGenMixin: if fd_fe_w is not None and fd_fe_w.Ty is not None: fd_fp_w: mlirlite.Value* = mlirlite.build_gep_struct(builder, fd_sty_w, fd_fe_w.Ty, fd_meta_vw, fd_fe_w.Index) if fd_fp_w is not None: - sv_fd: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, fd_fe_w.Ty, node) + sv_fd: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, rhs_val, fd_fe_w.Ty, node, trans) mlirlite.build_store(builder, sv_fd, fd_fp_w) continue # VTABLE write: obj.method = func writes the vtable slot instead of a field diff --git a/App/lib/core/Gen/Call/CallGenCall.vp b/App/lib/core/Gen/Call/CallGenCall.vp index 3f629a6..1371ad5 100644 --- a/App/lib/core/Gen/Call/CallGenCall.vp +++ b/App/lib/core/Gen/Call/CallGenCall.vp @@ -526,7 +526,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): if pc_param is not None: pty_pc: mlirlite.LLVMType* = mlirlite.param_get_ty(pc_param) if pty_pc is not None: - c_pc: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, pc_node, pty_pc, pc_arg_node) + c_pc: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, pc_node, pty_pc, pc_arg_node, trans) if c_pc is not None: coerced_pc = c_pc pc_param = mlirlite.param_get_next(pc_param) coerced_pc.Next = None @@ -1429,7 +1429,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): g_idx_node: ast.AST* = cargs.get(0) g_idx_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, g_idx_node, None, 0, trans) if g_data is not None and g_esize is not None and g_idx_val is not None: - g_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, g_idx_val, i64_ty, g_idx_node) + g_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, g_idx_val, i64_ty, g_idx_node, trans) g_offset: mlirlite.Value* = mlirlite.build_mul(builder, g_idx_i64, g_esize) g_addr: mlirlite.Value* = mlirlite.build_gep(builder, i8_ty, g_data, g_offset) if g_addr is not None: @@ -1450,11 +1450,11 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): s_idx_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, s_idx_node, None, 0, trans) s_val_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, s_val_node, None, 0, trans) if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: - s_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_idx_val, i64_ty, s_idx_node) + s_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_idx_val, i64_ty, s_idx_node, trans) s_offset: mlirlite.Value* = mlirlite.build_mul(builder, s_idx_i64, s_esize) s_addr: mlirlite.Value* = mlirlite.build_gep(builder, i8_ty, s_data, s_offset) if s_addr is not None: - s_val_elem: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_val_val, lm_elem_ty, s_val_node) + s_val_elem: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_val_val, lm_elem_ty, s_val_node, trans) s_ep: mlirlite.Value* = mlirlite.build_bitcast(builder, s_addr, mlirlite.Ptr(pool, lm_elem_ty)) if s_ep is not None: mlirlite.build_store(builder, s_val_elem, s_ep) @@ -1698,7 +1698,7 @@ novirtual class CallGenCall(CallGenBase.CallGenBase): # before the coercion below (cross-module vpi addressing is applied in bulk for the whole chain). arg_val_sp: mlirlite.Value* = self.Gen.CallGenBase.translate_call_arg(builder, pool, mod, trans, call_name, int(ai_sp) + 1, arg_node_sp, pty_sp, None) if arg_val_sp is None: continue - if pty_sp is not None: arg_val_sp = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val_sp, pty_sp, arg_node_sp) + if pty_sp is not None: arg_val_sp = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val_sp, pty_sp, arg_node_sp, trans) else: # found_func=None: decay array args to element pointers per C semantics # (consistent with _translate_method_call). diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index 2546cfd..116f064 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -103,7 +103,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): # fail-fast: GEP failed (struct_ty and fe.Ty mismatch) VLogger.error(f"Field GEP failed, type mismatch: {class_name}", "HandlesExprCall") continue - default_val = self.Gen.ExprGenBase.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal) + default_val = self.Gen.ExprGenBase.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal, trans) mlirlite.build_store(builder, default_val, field_ptr, is_volatile) # _translate_struct_ctor - struct constructor Point(10, 20): alloca, zeroinit, per-field # GEP + store (or __new__/__before_init__/__init__ for OOP structs), then load. @@ -288,7 +288,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): # fail-fast: GEP failed (struct_ty and fe.Ty mismatch) VLogger.error(f"Constructor field GEP failed: {class_name}", "HandlesExprCall") continue - arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg) + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg, trans) mlirlite.build_store(builder, arg_val, field_ptr, is_volatile) # return a pointer (not a struct value); coerce_to_type decides whether to load on assign @@ -327,7 +327,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): VLogger.error(f"Constructor field GEP failed: {class_name}", "HandlesExprCall") continue # coerce and store - arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg) + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg, trans) mlirlite.build_store(builder, arg_val, field_ptr, is_volatile) # return a pointer (not a struct value); coerce_to_type decides whether to load on assign @@ -398,7 +398,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): if casted_arg is None: continue arg_val = casted_arg # coerce and store (the payload slot may be i32 or i64; coerce by field type) - arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, pfe.Ty, arg) + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, pfe.Ty, arg, trans) mlirlite.build_store(builder, arg_val, payload_ptr, is_volatile) # return a pointer (same as _translate_struct_ctor; coerce_to_type decides whether to load) @@ -813,7 +813,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): if arg_val is None: continue field_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, fe.Ty, tmp, fe.Index) if field_ptr is None: continue - arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg) + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, fe.Ty, arg, trans) mlirlite.build_store(builder, arg_val, field_ptr, is_volatile) # Handle keyword args (lookup by field name). @@ -832,7 +832,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): if kw_val is None: continue field_ptr: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, fe.Ty, tmp, fe.Index) if field_ptr is None: continue - kw_val = self.Gen.ExprGenBase.coerce_to_type(builder, kw_val, fe.Ty, kw.value) + kw_val = self.Gen.ExprGenBase.coerce_to_type(builder, kw_val, fe.Ty, kw.value, trans) mlirlite.build_store(builder, kw_val, field_ptr, is_volatile) # return a pointer (not a struct value); coerce_to_type decides whether to load on assign @@ -1286,7 +1286,7 @@ novirtual class CallGenCtor(CallGenBase.CallGenBase): if av_sf is None: continue fp_sf: mlirlite.Value* = mlirlite.build_gep_struct(builder, struct_ty, fe_sf.Ty, storage_ptr, fe_sf.Index) if fp_sf is None: continue - av_sf = self.Gen.ExprGenBase.coerce_to_type(builder, av_sf, fe_sf.Ty, arg_sf) + av_sf = self.Gen.ExprGenBase.coerce_to_type(builder, av_sf, fe_sf.Ty, arg_sf, trans) mlirlite.build_store(builder, av_sf, fp_sf, gc_volatile) return storage_ptr \ No newline at end of file diff --git a/App/lib/core/Gen/Call/CallGenDispatch.vp b/App/lib/core/Gen/Call/CallGenDispatch.vp index 5f55b38..ab4af66 100644 --- a/App/lib/core/Gen/Call/CallGenDispatch.vp +++ b/App/lib/core/Gen/Call/CallGenDispatch.vp @@ -1313,7 +1313,7 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): g_idx_node: ast.AST* = cargs.get(0) g_idx_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, g_idx_node, None, 0, trans) if g_data is not None and g_esize is not None and g_idx_val is not None: - g_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, g_idx_val, i64_ty, g_idx_node) + g_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, g_idx_val, i64_ty, g_idx_node, trans) g_offset: mlirlite.Value* = mlirlite.build_mul(builder, g_idx_i64, g_esize) g_addr: mlirlite.Value* = mlirlite.build_gep(builder, i8_ty, g_data, g_offset) if g_addr is not None: @@ -1334,11 +1334,11 @@ novirtual class CallGenDispatch(CallGenBase.CallGenBase): s_idx_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, s_idx_node, None, 0, trans) s_val_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, s_val_node, None, 0, trans) if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: - s_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_idx_val, i64_ty, s_idx_node) + s_idx_i64: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_idx_val, i64_ty, s_idx_node, trans) s_offset: mlirlite.Value* = mlirlite.build_mul(builder, s_idx_i64, s_esize) s_addr: mlirlite.Value* = mlirlite.build_gep(builder, i8_ty, s_data, s_offset) if s_addr is not None: - s_val_elem: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_val_val, lm_elem_ty, s_val_node) + s_val_elem: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, s_val_val, lm_elem_ty, s_val_node, trans) s_ep: mlirlite.Value* = mlirlite.build_bitcast(builder, s_addr, mlirlite.Ptr(pool, lm_elem_ty)) if s_ep is not None: mlirlite.build_store(builder, s_val_elem, s_ep) diff --git a/App/lib/core/Gen/Call/CallGenLeafKit.vp b/App/lib/core/Gen/Call/CallGenLeafKit.vp index 9e17335..3d3e6c6 100644 --- a/App/lib/core/Gen/Call/CallGenLeafKit.vp +++ b/App/lib/core/Gen/Call/CallGenLeafKit.vp @@ -700,9 +700,11 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): # pure_str value: printf consumes the payload, not the struct. ps_pv: mlirlite.Value* = self.Gen.ExprGenBase._pure_str_payload(builder, pool, arg_val) if ps_pv is not None: arg_val = ps_pv - # C ABI integer promotion: i8/i16 -> i32 (required by printf varargs) + # C ABI integer promotion: i8/i16 -> i32 (required by printf varargs). + # Pass the argument expression and trans so uint16/uint8 zext (movzwl) instead + # of the default sext: the source signedness comes from the AST annotation. arg_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty) - if arg_bits != 0 and arg_bits < 32: arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, i32_ty, arg) + if arg_bits != 0 and arg_bits < 32: arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, i32_ty, arg, trans) # C ABI float promotion: float -> double (required by printf varargs) arg_fbits: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty) if arg_fbits != 0 and arg_fbits < 64: @@ -798,17 +800,31 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): token = "0x%llx" arg_val = mlirlite.build_ptrtoint(builder, arg_val, i64_ty) elif arg_bits != 0: + # Format/extension follow the source signedness: a uint16/uint8 printed with %d + # plus sext shows negative values (-9028 for 0xDCBC), so unsigned sources use + # %u/%llu and zext. + is_u_pr: int = 0 + if arg is not None and trans is not None: + if self.Gen.ExprGenOps._node_type_unsigned(pool, arg, trans) != 0: is_u_pr = 1 if arg_bits == 1: token = "%d" arg_val = mlirlite.build_zext(builder, arg_val, i32_ty) elif arg_bits == 8: - token = "%d" - arg_val = mlirlite.build_sext(builder, arg_val, i32_ty) + if is_u_pr != 0: + token = "%u" + arg_val = mlirlite.build_zext(builder, arg_val, i32_ty) + else: + token = "%d" + arg_val = mlirlite.build_sext(builder, arg_val, i32_ty) elif arg_bits == 16: - token = "%d" - arg_val = mlirlite.build_sext(builder, arg_val, i32_ty) - elif arg_bits == 32: token = "%d" - else: token = "%lld" + if is_u_pr != 0: + token = "%u" + arg_val = mlirlite.build_zext(builder, arg_val, i32_ty) + else: + token = "%d" + arg_val = mlirlite.build_sext(builder, arg_val, i32_ty) + elif arg_bits == 32: token = "%u" if is_u_pr != 0 else "%d" + else: token = "%llu" if is_u_pr != 0 else "%lld" elif arg_fbits != 0: token = "%f" if arg_fbits < 64: arg_val = mlirlite.build_fpext(builder, arg_val, dbl_ty) diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index 0e2c3b5..fc9276d 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -1159,7 +1159,7 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # Known vararg C functions (snprintf/sprintf/vsprintf): coerce fixed args by signature # (C ABI requires i64 size), else call/declare mismatch and Win64 leaves stack garbage in the high 4 bytes. kvc_ty: mlirlite.LLVMType* = self.Gen.CallGenVa._get_known_vararg_cfunc_param_ty(pool, func_name, ai) - if kvc_ty is not None: arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, kvc_ty, arg) + if kvc_ty is not None: arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, kvc_ty, arg, trans) # Prefer the definition-side vpi param annotation for module-qualified calls: the # whitelist treats all non-pointer Win32 args as i64, but ULONG is now i32 (call/declare mismatch). ext_param_ty: mlirlite.LLVMType* = None @@ -1188,10 +1188,10 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # pointer targets through coerce_to_type too: it materializes the compile-time constant # 0 as a null pointer and fails fast on any other implicit int<->ptr conversion. if self.Gen.ExprGenBase.is_ptr_type(ext_param_ty) != 0: - arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg) + arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg, trans) elif val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap: if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap: arg_val = mlirlite.build_zext(builder, arg_val, ext_param_ty) - else: arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg) + else: arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg, trans) elif found_func is not None: # found_func present: coerce to the param type (e.g. stdlib.malloc(size: sizet)); a # DefineT/i32 literal passed to an i64 param would otherwise leave call(i32) vs define(i64) mismatched. diff --git a/App/lib/core/Gen/Call/CallGenProp.vp b/App/lib/core/Gen/Call/CallGenProp.vp index 103ce84..ef8e0de 100644 --- a/App/lib/core/Gen/Call/CallGenProp.vp +++ b/App/lib/core/Gen/Call/CallGenProp.vp @@ -105,7 +105,7 @@ novirtual class CallGenProp(CallGenBase.CallGenBase): while cur_arg_pc is not None and cur_param_pc is not None: param_ty_pc: mlirlite.LLVMType* = mlirlite.param_get_ty(cur_param_pc) if param_ty_pc is not None and cur_arg_pc.Ty is not None: - coerced_pc: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, cur_arg_pc, param_ty_pc) + coerced_pc: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, cur_arg_pc, param_ty_pc, None, trans) if coerced_pc is not None and coerced_pc != cur_arg_pc: # Keep the list intact: the new Value inherits the node's Next; predecessor points to it mlirlite.value_set_next(coerced_pc, cur_arg_pc.Next) diff --git a/App/lib/core/Gen/Class/ClassGenVTable.vp b/App/lib/core/Gen/Class/ClassGenVTable.vp index a7fc513..8e0c168 100644 --- a/App/lib/core/Gen/Class/ClassGenVTable.vp +++ b/App/lib/core/Gen/Class/ClassGenVTable.vp @@ -1200,7 +1200,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase): field_ptr: mlirlite.Value* = mlirlite.build_gep_struct(func_builder, struct_ty, fe.Ty, self_val, fe.Index) if field_ptr is None: continue # Coerce and store. - default_val = self.Gen.ExprGenBase.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal) + default_val = self.Gen.ExprGenBase.coerce_to_type(func_builder, default_val, fe.Ty, fe.DefaultVal, trans) mlirlite.build_store(func_builder, default_val, field_ptr) # 3. ret void diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index e5496cd..b6a506d 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -81,30 +81,30 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): # Ptr.bits == 0 skips the next three branches. body_val.Ty becomes phi_ty and orelse_val is coerced to it. if body_is_ptr != orelse_is_ptr: mlirlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node, trans) elif body_bits > orelse_bits and orelse_bits > 0: # 宽侧是「能无损落进窄侧」的编译期常量时,把**常量**降到窄侧(与二元运算同一口径), # 避免 `tab[..] if c else '='`(i8 元素 vs i32 字符字面量)被抬成 i32、再赋回 i8 时误报窄化。 if self._const_fits_int_type(body_val, orelse_val.Ty) != 0: mlirlite.position_at_end(builder, then_blk_for_phi) - body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node) + body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node, trans) else: mlirlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node, trans) elif orelse_bits > body_bits and body_bits > 0: # 同口径:宽侧(orelse)是能落进窄侧的常量时,把它降下来(在 else 块内完成强转) if self._const_fits_int_type(orelse_val, body_val.Ty) != 0: mlirlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node, trans) else: mlirlite.position_at_end(builder, then_blk_for_phi) - body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node) + body_val = self.coerce_to_type(builder, body_val, orelse_val.Ty, node, trans) elif body_bits == orelse_bits and body_bits > 0: # Same bits but different types (e.g. i64 vs Ptr): null cannot be used in an i64 PHI. # This branch should not trigger (case 0 covers it); kept as a defensive guard. if self.is_ptr_type(body_val.Ty) != self.is_ptr_type(orelse_val.Ty): mlirlite.position_at_end(builder, else_blk_for_phi) - orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node) + orelse_val = self.coerce_to_type(builder, orelse_val, body_val.Ty, node, trans) # Now br to merge from the then/else blocks (after type coercion) mlirlite.position_at_end(builder, then_blk_for_phi) @@ -1506,8 +1506,8 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase): target_float_ty: mlirlite.LLVMType* = mlirlite.Double(pool) if target_fbits == 32: target_float_ty = mlirlite.Float(pool) # Convert both operands to the target float type (int->float via si2fp, float->float via fpext/fptrunc) - lhs = self.coerce_to_type(builder, lhs, target_float_ty, node) - rhs = self.coerce_to_type(builder, rhs, target_float_ty, node) + lhs = self.coerce_to_type(builder, lhs, target_float_ty, node, trans) + rhs = self.coerce_to_type(builder, rhs, target_float_ty, node, trans) if op == ast.OpKind.Add: return mlirlite.build_fadd(builder, lhs, rhs) if op == ast.OpKind.Sub: return mlirlite.build_fsub(builder, lhs, rhs) if op == ast.OpKind.Mult: return mlirlite.build_fmul(builder, lhs, rhs) diff --git a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index 662091c..9029c1e 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -645,7 +645,7 @@ novirtual class StmtGenCifMixin: match ret_ty_rt: case mlirlite.LLVMType.Ptr(r_inner): ret_pointee = r_inner - if val_pointee is not None and ret_pointee is not None and uint64(val_pointee) != uint64(ret_pointee): val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node) + if val_pointee is not None and ret_pointee is not None and uint64(val_pointee) != uint64(ret_pointee): val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans) elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits: if val_bits == 1 and val_bits < ret_bits: val = mlirlite.build_zext(builder, val, ret_ty_rt) else: @@ -1441,9 +1441,9 @@ novirtual class StmtGenCifMixin: r1_start = mlirlite.const_int(pool, r1_bits, 0) r1_step = mlirlite.const_int(pool, r1_bits, 1) r1_stop = mlirlite.const_int(pool, r1_bits, 0) - if a1 is not None: r1_stop = self.Gen.ExprGenBase.coerce_to_type(builder, a1, r1_wty, cargs1.get(0)) - if b1 is not None: r1_start = self.Gen.ExprGenBase.coerce_to_type(builder, b1, r1_wty, cargs1.get(1)) - if c1 is not None: r1_step = self.Gen.ExprGenBase.coerce_to_type(builder, c1, r1_wty, cargs1.get(2)) + if a1 is not None: r1_stop = self.Gen.ExprGenBase.coerce_to_type(builder, a1, r1_wty, cargs1.get(0), trans) + if b1 is not None: r1_start = self.Gen.ExprGenBase.coerce_to_type(builder, b1, r1_wty, cargs1.get(1), trans) + if c1 is not None: r1_step = self.Gen.ExprGenBase.coerce_to_type(builder, c1, r1_wty, cargs1.get(2), trans) elif kind1 == GenTypes.SEQ_KIND_STR: elem1_ty = i8_ty s1_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src1, trans._funcs, trans._func_count, trans) @@ -1504,9 +1504,9 @@ novirtual class StmtGenCifMixin: r2_start = mlirlite.const_int(pool, r2_bits, 0) r2_step = mlirlite.const_int(pool, r2_bits, 1) r2_stop = mlirlite.const_int(pool, r2_bits, 0) - if a2 is not None: r2_stop = self.Gen.ExprGenBase.coerce_to_type(builder, a2, r2_wty, cargs2.get(0)) - if b2 is not None: r2_start = self.Gen.ExprGenBase.coerce_to_type(builder, b2, r2_wty, cargs2.get(1)) - if c2 is not None: r2_step = self.Gen.ExprGenBase.coerce_to_type(builder, c2, r2_wty, cargs2.get(2)) + if a2 is not None: r2_stop = self.Gen.ExprGenBase.coerce_to_type(builder, a2, r2_wty, cargs2.get(0), trans) + if b2 is not None: r2_start = self.Gen.ExprGenBase.coerce_to_type(builder, b2, r2_wty, cargs2.get(1), trans) + if c2 is not None: r2_step = self.Gen.ExprGenBase.coerce_to_type(builder, c2, r2_wty, cargs2.get(2), trans) elif kind2 == GenTypes.SEQ_KIND_STR: elem2_ty = i8_ty s2_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src2, trans._funcs, trans._func_count, trans) @@ -1618,11 +1618,11 @@ novirtual class StmtGenCifMixin: mlirlite.build_store(builder, idx32, t1_alloca) if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None: t2_ty: mlirlite.LLVMType* = t2_alloca.Ty.Pointee - v1c: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t2_ty, src1) + v1c: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t2_ty, src1, trans) mlirlite.build_store(builder, v1c, t2_alloca) else: if v1 is not None: - v1c: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t1_ty, src1) + v1c: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t1_ty, src1, trans) mlirlite.build_store(builder, v1c, t1_alloca) # source-2 element → t2 v2: mlirlite.Value* = None @@ -1640,7 +1640,7 @@ novirtual class StmtGenCifMixin: v2 = mlirlite.build_load(builder, i8_ptr_ty, addr2) if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None: t2_ty2: mlirlite.LLVMType* = t2_alloca.Ty.Pointee - v2c: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v2, t2_ty2, src2) + v2c: mlirlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v2, t2_ty2, src2, trans) mlirlite.build_store(builder, v2c, t2_alloca) # save the old loop context and set break/continue targets @@ -1975,7 +1975,7 @@ novirtual class StmtGenCifMixin: self.Gen.TypeGenErr.fatal_error(for_node, f"list literal iteration encountered an [INVALID OBJECT] AST element (vptr is 0): element {i} pointer is nonzero" f"(address {uint64(el_node)}) but the first word of its object (vtable pointer) is 0, element count {elts_count};" f"something upstream produced an [uninitialized vptr AST node] (typical source: a deep copy that moved fields but not the vptr), compilation aborted.", "ValueError") el_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, el_node, trans._funcs, trans._func_count, trans) if el_val is not None: - el_val = self.Gen.ExprGenBase.coerce_to_type(builder, el_val, elem_ty, el_node) + el_val = self.Gen.ExprGenBase.coerce_to_type(builder, el_val, elem_ty, el_node, trans) el_ptr: mlirlite.Value* = mlirlite.build_gep_array(builder, arr_ty, elem_ty, tmp_alloca, mlirlite.const_int32(pool, i)) if el_ptr is not None: mlirlite.build_store(builder, el_val, el_ptr) i += 1