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
This commit is contained in:
TermiNexus committed 2026-10-28 23:06:17 +08:00
1 parent 1adc61e3c2
commit 19f9c53a5f
10 files changed
+74 -58

No files matched your search

+11 -11
View File
@@ -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
+5 -5
View File
@@ -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).
+7 -7
View File
@@ -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
+3 -3
View File
@@ -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)
+24 -8
View File
@@ -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)
+3 -3
View File
@@ -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.
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
+8 -8
View File
@@ -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)
+11 -11
View File
@@ -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