fix(codegen): widen calls by the declared return signedness
This commit is contained in:
1 parent
425d3f2120
commit
7cbe4e93dc
9 files changed
+83
-15
No files matched your search
@@ -4099,7 +4099,7 @@ def _inject_function_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*,
|
||||
trans._func_count = cur_count + 1
|
||||
# Complete the global function-table Spec (params all added, matching FuncGenDef): without it
|
||||
# find_func_entry_global() sees an empty Spec and vtable generation fails to find the type.
|
||||
GenApi.update_global_func_spec(fd.name, func)
|
||||
GenApi.update_global_func_spec(fd.name, func, GenApi.annot_ret_sign(fd.returns))
|
||||
|
||||
|
||||
# _inject_method_declare - create a declare for a ClassDef method. Mangled name is
|
||||
@@ -4255,7 +4255,7 @@ def _inject_method_declare(pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, m_
|
||||
trans._func_count = cur_count + 1
|
||||
# Complete the global function-table Spec (matching ClassGenVTable): otherwise
|
||||
# find_func_entry_global().Spec is empty and vtable generation fails to find the method type.
|
||||
GenApi.update_global_func_spec(lookup_name, func)
|
||||
GenApi.update_global_func_spec(lookup_name, func, GenApi.annot_ret_sign(m_fd.returns))
|
||||
|
||||
|
||||
# _register_ctypedef_from_annassign - register a TypedefT from an AnnAssign node.
|
||||
|
||||
@@ -971,8 +971,13 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
return 0
|
||||
|
||||
|
||||
def update_global_func_spec(self, name: str, func: mlirlite.Function*) -> int:
|
||||
"""Update a global table entry's Spec after all its params are added"""
|
||||
def update_global_func_spec(self, name: str, func: mlirlite.Function*, ret_sign: int = 0) -> int:
|
||||
"""Update a global table entry's Spec after all its params are added.
|
||||
|
||||
ret_sign: GenTypes.FUNC_RET_SIGN_* of the declared return annotation (0 = keep the
|
||||
previously recorded value). Needed because Spec/Ret comes from the LLVM type, which
|
||||
cannot express unsignedness.
|
||||
"""
|
||||
if name is None or func is None: return 1
|
||||
# 重载:同名多条时 Spec 必须写到**这个 Function 对应**的条目上,否则第二个重载会
|
||||
# 覆盖第一个的签名,决议时所有候选看起来都是同一个签名。
|
||||
@@ -989,6 +994,7 @@ novirtual class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if entry is None: entry = self.find_func_entry_global(name)
|
||||
if entry is None: return 1
|
||||
entry.Spec = self._build_func_spec(func)
|
||||
if ret_sign != 0: entry.RetSign = ret_sign
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -768,7 +768,7 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase):
|
||||
if i1_ptr_ty_si is not None: mlirlite.add_param(pool, func, i1_ptr_ty_si, "%__stop_iter_flag__")
|
||||
|
||||
# Params done: finalize the global function-table Spec (vtable derives type text from it after reset).
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(full_name, func)
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(full_name, func, self.Gen.TypeGenResolve.annot_ret_sign(fd.returns))
|
||||
|
||||
# Forward-declaration mode: signature and table registration done, do not emit the body.
|
||||
if sig_only != 0: return 0
|
||||
|
||||
@@ -227,8 +227,12 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
# generated IR), so a u32 with bit 31 set grew 0xFFFFFFFF in the high half — a real
|
||||
# value 0x88691F61 became 0xFFFFFFFF88691F61 (stackmap pointers were mangled this way).
|
||||
fe_fn_u: GenTypes.FuncEntry* = self.Gen.CallGenLeafKit.find_func_entry_global(func_nm_u.id)
|
||||
if fe_fn_u is not None and fe_fn_u.Spec is not None:
|
||||
if TSpec.SpecIsUnsigned(fe_fn_u.Spec.Ret) != 0: return 1
|
||||
if fe_fn_u is not None:
|
||||
# Declared return annotation first: the LLVM type cannot express sign, and
|
||||
# SpecFromLLVMType marks every non-i1 int as SIGNED (so the Spec path below
|
||||
# is only a fallback for i1/bool returns).
|
||||
if fe_fn_u.RetSign == GenTypes.FUNC_RET_SIGN_UNSIGNED: return 1
|
||||
if fe_fn_u.Spec is not None and TSpec.SpecIsUnsigned(fe_fn_u.Spec.Ret) != 0: return 1
|
||||
elif fk_u == ast.ASTKind.Attribute:
|
||||
# Qualified type cast: t.CUInt16T(x) / mod.ULONG(x).
|
||||
at_u: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
@@ -384,6 +388,8 @@ novirtual class ExprGenOps(ExprGenBase.ExprGenBase):
|
||||
nm_c: ast.Name* = ast.Name*(cl.func)
|
||||
if nm_c.id is not None:
|
||||
if self._spec_sign_from_annot(nm_c.id) == TSpec.TS_SIGN_SIGNED: return 1
|
||||
fe_fn_s: GenTypes.FuncEntry* = self.Gen.CallGenLeafKit.find_func_entry_global(nm_c.id)
|
||||
if fe_fn_s is not None and fe_fn_s.RetSign == GenTypes.FUNC_RET_SIGN_SIGNED: return 1
|
||||
elif fk_s == ast.ASTKind.Attribute:
|
||||
# Qualified signed cast: t.CInt16T(x) / mod.LONG(x).
|
||||
at_c: ast.Attribute* = ast.Attribute*(cl.func)
|
||||
|
||||
@@ -567,7 +567,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
thunk_cnt: int = trans._func_count
|
||||
if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, thunk_cnt, fd.name, thunk_f, thunk_max, None, 0, 0, pool) == 0:
|
||||
trans._func_count = thunk_cnt + 1
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, thunk_f)
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, thunk_f, self.Gen.TypeGenResolve.annot_ret_sign(fd.returns))
|
||||
continue
|
||||
|
||||
# Compute the mangled name. Overload groups (same name >=2 in this module body) get the
|
||||
@@ -681,7 +681,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if ags.vararg is not None: func.IsVarArg = 1
|
||||
|
||||
# Params added; fill the global func-table Spec (lets vtable derive type text after func is reset)
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func, self.Gen.TypeGenResolve.annot_ret_sign(fd.returns))
|
||||
|
||||
# Clear the generic-func context once used (prevents leaking into later functions' annotation resolution)
|
||||
if tp_names_fd is not None: self.Gen.TypeGenBase.clear_generic_context()
|
||||
@@ -886,7 +886,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if thunk_d is None: return 0
|
||||
thunk_max_d: int = 256
|
||||
if self.Gen.CallGenLeafKit.add_func_to_table(funcs_ptr, func_count, fd.name, thunk_d, thunk_max_d, None, 0, 0, pool) == 0: trans._func_count = func_count + 1
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, thunk_d)
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, thunk_d, self.Gen.TypeGenResolve.annot_ret_sign(fd.returns))
|
||||
return 0
|
||||
# Extern declaration function: emit a declare (declare only, no definition). First check whether
|
||||
# forward_declare_functions already created it to avoid a duplicate declare.
|
||||
@@ -948,7 +948,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
if func_section_e is not None: mlirlite.function_set_attr_group(func, func_section_e)
|
||||
|
||||
# Params added; fill the global func-table Spec
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func, self.Gen.TypeGenResolve.annot_ret_sign(fd.returns))
|
||||
|
||||
return 0
|
||||
|
||||
@@ -1084,7 +1084,7 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase):
|
||||
mlirlite.add_param(pool, func, i32_ptr_ty_eh, "%__eh_code_out__")
|
||||
|
||||
# Params added; fill the global func-table Spec
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func)
|
||||
self.Gen.CallGenLeafKit.update_global_func_spec(fd.name, func, self.Gen.TypeGenResolve.annot_ret_sign(fd.returns))
|
||||
|
||||
# Create the entry block
|
||||
entry_blk: mlirlite.BasicBlock* = mlirlite.create_block(pool, func, "entry")
|
||||
|
||||
@@ -163,6 +163,13 @@ def _get_type_name_from_annotation(pool: memhub.MemBuddy*, node: ast.AST*) -> st
|
||||
return None
|
||||
|
||||
|
||||
# ---------------- annot_ret_sign (delegates to TypeGenResolve.annot_ret_sign) ----------------
|
||||
def annot_ret_sign(node: ast.AST*) -> int:
|
||||
"""Signedness code of a return annotation (FUNC_RET_SIGN_*; 0=unknown)"""
|
||||
if _g_gen is not None: return _g_gen.TypeGenResolve.annot_ret_sign(node)
|
||||
return 0
|
||||
|
||||
|
||||
# ---------------- register_ctypedef (delegates to TypeGenCType.register_ctypedef) ----------------
|
||||
def register_ctypedef(pool: memhub.MemBuddy*, name: str, type_str: str):
|
||||
"""Delegate to gen.register_ctypedef"""
|
||||
@@ -1158,7 +1165,7 @@ def clear_scope_names(trans: HT.Translator*):
|
||||
|
||||
|
||||
# ---------------- update_global_func_spec (delegates to CallGenLeafKit.update_global_func_spec) ----------------
|
||||
def update_global_func_spec(name: str, func: mlirlite.Function*) -> int:
|
||||
"""Delegate to gen.CallGenLeafKit.update_global_func_spec."""
|
||||
if _g_gen is not None: return _g_gen.CallGenLeafKit.update_global_func_spec(name, func)
|
||||
def update_global_func_spec(name: str, func: mlirlite.Function*, ret_sign: int = 0) -> int:
|
||||
"""Delegate to gen.CallGenLeafKit.update_global_func_spec (ret_sign: FUNC_RET_SIGN_*, 0=keep)."""
|
||||
if _g_gen is not None: return _g_gen.CallGenLeafKit.update_global_func_spec(name, func, ret_sign)
|
||||
return 0
|
||||
@@ -201,6 +201,17 @@ novirtual class FuncEntry:
|
||||
# TypeSpec (dual-write since S3): the full signature of Kind=TS_FUNC (Ret/Params/...)
|
||||
# built by update_global_func_spec after add_param; PermPool-resident, safe across 1b reset.
|
||||
Spec: TSpec.TypeSpec*
|
||||
# Signedness of the declared return annotation (FUNC_RET_SIGN_*): LLVM types carry no
|
||||
# sign, and SpecFromLLVMType marks every int as signed, so this is the only source of truth
|
||||
# for zext/sext at a call site.
|
||||
RetSign: int
|
||||
|
||||
|
||||
# FuncEntry.RetSign encoding. 0 must be "unset" because FuncEntry arrays are zero-initialized;
|
||||
# TSpec.TS_SIGN_UNSIGNED is 0, so the mapping is explicit.
|
||||
define FUNC_RET_SIGN_UNSET = 0
|
||||
define FUNC_RET_SIGN_UNSIGNED = 1
|
||||
define FUNC_RET_SIGN_SIGNED = 2
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import lib.core.Gen.GenTypes as GenTypes
|
||||
import lib.core.Gen.GenApi as GenApi
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
import lib.core.Gen.Type.TypeGenMixin as TypeGenMixin
|
||||
from stdint import *
|
||||
import ast
|
||||
@@ -1521,6 +1522,29 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
|
||||
return "<unknown>"
|
||||
|
||||
def annot_ret_sign(self, annot: ast.AST*) -> int:
|
||||
"""Signedness code (GenTypes.FUNC_RET_SIGN_*) of a return annotation; 0 = unknown.
|
||||
|
||||
LLVM function types carry no signedness, so this must be recorded at declaration time.
|
||||
Marker unions (`ExportT | uint16`) are scanned operand by operand; wrappers such as
|
||||
`ConstT[uint16]` / `PtrT[uint16]` go through annotation_to_str + spec_sign_of_annot.
|
||||
"""
|
||||
if annot is None: return 0
|
||||
k: int = annot.kind()
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(annot)
|
||||
if bop.op == ast.OpKind.BitOr:
|
||||
r: int = self.annot_ret_sign(bop.left)
|
||||
if r != 0: return r
|
||||
return self.annot_ret_sign(bop.right)
|
||||
return 0
|
||||
txt: str = self.annotation_to_str(annot)
|
||||
if txt is None: return 0
|
||||
s: int = self.Gen.TypeGenCType.spec_sign_of_annot(txt)
|
||||
if TSpec.SpecSignIsUnsigned(s) != 0: return GenTypes.FUNC_RET_SIGN_UNSIGNED
|
||||
if TSpec.SpecSignIsSigned(s) != 0: return GenTypes.FUNC_RET_SIGN_SIGNED
|
||||
return 0
|
||||
|
||||
def _is_storage_class_qualifier(self, name: str) -> int:
|
||||
"""Whether a name is a storage-class qualifier macro (not a type): 1=yes / 0=no."""
|
||||
if name is None: return 0
|
||||
|
||||
@@ -889,6 +889,20 @@ def SpecIsUnsigned(sp: TypeSpec*) -> int:
|
||||
return 0
|
||||
|
||||
|
||||
# Sign-code predicates. Reading TS_SIGN_UNSIGNED from another module fails: its value is 0 and
|
||||
# the cross-module DefineT cache uses 0 as "absent", so callers must use these helpers instead.
|
||||
def SpecSignIsUnsigned(sign: int) -> int:
|
||||
"""Whether a TS_SIGN_* code is unsigned."""
|
||||
if sign == TS_SIGN_UNSIGNED: return 1
|
||||
return 0
|
||||
|
||||
|
||||
def SpecSignIsSigned(sign: int) -> int:
|
||||
"""Whether a TS_SIGN_* code is signed."""
|
||||
if sign == TS_SIGN_SIGNED: return 1
|
||||
return 0
|
||||
|
||||
|
||||
def SpecBitWidth(sp: TypeSpec*) -> int:
|
||||
"""Bit width; 0 for non-integer/float"""
|
||||
if sp is None: return 0
|
||||
|
||||
Reference in new issue
Block a user