feat(gen): 支持 t.BigEndian / t.LittleEndian 字节序描述符(注解识别 X|marker 并把字节序登记到 FieldEntry.ByteOrder,暂不生成 bswap)

This commit is contained in:
TermiNexus committed 2026-10-13 12:17:02 +08:00
1 parent 3ca2165fd9
commit 5d15d01e21
5 files changed
+53

No files matched your search

+17
View File
@@ -162,9 +162,13 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
# Field const-object flag buffer (1 = annotation has t.CConst and the type is not
# a pointer), parallel to field_volatile_buf with values 0/1.
field_const_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
# Field byte-order buffer (0 = native, 1 = t.BigEndian, 2 = t.LittleEndian), parallel
# to field_volatile_buf; from the `X | t.BigEndian` annotation union.
field_byteorder_buf: sizet* = pool.alloc(8 * GenTypes.FIELD_MAX)
if field_names_buf is None or field_types_buf is None or field_defaults_buf is None: return 0
if field_annot_buf is None or field_volatile_buf is None: return 0
if field_pointee_volatile_buf is None or field_const_buf is None: return 0
if field_byteorder_buf is None: return 0
string.memset(field_names_buf, 0, 8 * GenTypes.FIELD_MAX)
string.memset(field_types_buf, 0, 8 * GenTypes.FIELD_MAX)
string.memset(field_defaults_buf, 0, 8 * GenTypes.FIELD_MAX)
@@ -172,6 +176,7 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
string.memset(field_volatile_buf, 0, 8 * GenTypes.FIELD_MAX)
string.memset(field_pointee_volatile_buf, 0, 8 * GenTypes.FIELD_MAX)
string.memset(field_const_buf, 0, 8 * GenTypes.FIELD_MAX)
string.memset(field_byteorder_buf, 0, 8 * GenTypes.FIELD_MAX)
field_count: int = 0
@@ -221,6 +226,8 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
field_pointee_volatile_buf[field_count] = sizet(pfe.PointeeVolatile)
# Inherit the const-object flag (unchanged after flattening)
field_const_buf[field_count] = sizet(pfe.IsConst)
# Inherit the byte-order flag (unchanged after flattening)
field_byteorder_buf[field_count] = sizet(pfe.ByteOrder)
field_count += 1
children: list[ast.AST*]* = cd.children
@@ -340,11 +347,17 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
# through the object fail-fasts, matching TPC's Gen.field_const_flags.
if self.Gen.TypeGenErr.is_const_object_marker(aa.annotation, field_ty) != 0: field_const_buf[field_count] = 1
else: field_const_buf[field_count] = 0
# Byte-order marker (t.BigEndian / t.LittleEndian) -> 1 / 2; annotation `|`
# means "and", so `X | t.BigEndian` is a BigEndian-encoded X field.
if self.Gen.TypeGenErr.has_decorator_marker(aa.annotation, "BigEndian", 0) != 0: field_byteorder_buf[field_count] = 1
elif self.Gen.TypeGenErr.has_decorator_marker(aa.annotation, "LittleEndian", 0) != 0: field_byteorder_buf[field_count] = 2
else: field_byteorder_buf[field_count] = 0
else:
field_annot_buf[field_count] = 0
field_volatile_buf[field_count] = 0
field_pointee_volatile_buf[field_count] = 0
field_const_buf[field_count] = 0
field_byteorder_buf[field_count] = 0
field_count += 1
if field_count == 0:
@@ -518,6 +531,10 @@ novirtual class ClassGenDef(ClassGenBase.ClassGenBase):
if fidx_add >= 0 and field_pointee_volatile_buf[fi] != 0:
fe_pv: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(entry, fidx_add)
if fe_pv is not None: fe_pv.PointeeVolatile = 1
# byte-order field flag (field_byteorder_buf[fi] corresponds 1:1 with add_field order)
if fidx_add >= 0 and field_byteorder_buf[fi] != 0:
fe_bo: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(entry, fidx_add)
if fe_bo is not None: fe_bo.ByteOrder = int(field_byteorder_buf[fi])
# const object field flag (field_const_buf[fi] corresponds 1:1 with add_field order)
if fidx_add >= 0 and field_const_buf[fi] != 0:
fe_c: GenTypes.FieldEntry* = self.Gen.StructGen._get_field_entry(entry, fidx_add)
+4
View File
@@ -106,6 +106,10 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
if string.strcmp(name, "CRef") == 0: return 1
if string.strcmp(name, "CTempRef") == 0: return 1
if string.strcmp(name, "CAutoPtr") == 0: return 1
# Byte-order markers (t.BigEndian / t.LittleEndian): decorator markers used as
# `X | t.BigEndian`; recognized here so they are not taken for an unregistered class.
if string.strcmp(name, "BigEndian") == 0: return 1
if string.strcmp(name, "LittleEndian") == 0: return 1
return 0
def _attr_module_path_str(self, pool: memhub.MemBuddy*, node: ast.AST*) -> str:
"""Convert a module-reference AST into a dotted module path; None for non-module forms."""
+4
View File
@@ -121,6 +121,10 @@ class FieldEntry:
# 1=this field is a const object (annotation has t.CConst and the type is not a pointer):
# assigning it via an object fails fast, same as VarEntry.IsConst.
IsConst: int
# Byte order of this field, from the `X | t.BigEndian` / `X | t.LittleEndian` annotation
# union: 0=native (no marker), 1=BigEndian, 2=LittleEndian. Appended at the end so offsets
# are unchanged; consumers bswap on field load/store when 1 (16/32/64-bit ints only).
ByteOrder: int
# ============================================================
+2
View File
@@ -2493,6 +2493,8 @@ novirtual class StructGenMixin:
# Explicitly zero the const flag (not relying on the entry's zero-init): ClassGenDef sets it to 1 only for a confirmed const object, so explicit zeroing prevents a false "uninitialized read as 1".
fe.IsConst = 0
# Byte order is filled in by ClassGenDef from the field annotation (0 = native here).
fe.ByteOrder = 0
struct_entry.FieldCount = idx + 1
return idx
+26
View File
@@ -1443,6 +1443,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
return mlirlite.Int1(pool)
# ptrdiff_t
elif string.strcmp(type_name, "CPtrDiffT") == 0: return mlirlite.Int64(pool)
# Byte-order markers written alone (no real type on the other side) degrade to CInt,
# matching TPC: `t.BigEndian` alone -> BaseType=CInt() + ByteOrder='big'.
elif string.strcmp(type_name, "BigEndian") == 0: return mlirlite.Int32(pool)
elif string.strcmp(type_name, "LittleEndian") == 0: return mlirlite.Int32(pool)
# stdint.vp aliases (INT/BYTE/DWORD/int8_t/size_t/_Bool ...) now come from its
# CTypedef declarations; lowercase bare char/float/double stay here, int/bool use Name.
@@ -1486,6 +1490,11 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if self._is_t_attr(node, "CRef", imported_modules) != 0: return 1
if self._is_t_attr(node, "CTempRef", imported_modules) != 0: return 1
return 0
def _is_byteorder_marker(self, node: ast.AST*, imported_modules: str) -> int:
"""Whether a node is a byte-order marker: 0=none / 1=BigEndian / 2=LittleEndian."""
if self._is_t_attr(node, "BigEndian", imported_modules) != 0: return 1
if self._is_t_attr(node, "LittleEndian", imported_modules) != 0: return 2
return 0
def _ref_marker_name_mode(self, node: ast.AST*) -> int:
"""Syntactic value-reference marker test (no import context): 0=none / 1=CRef / 2=CTempRef."""
if node is None: return 0
@@ -1640,6 +1649,10 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if string.strcmp(name, "CExport") == 0: return 1
if string.strcmp(name, "CExtern") == 0: return 1
if string.strcmp(name, "CInline") == 0: return 1
# Byte-order markers are decorators, not types: never let them be extracted as a
# class name (which would make the field degrade to an unknown struct lookup).
if string.strcmp(name, "BigEndian") == 0: return 1
if string.strcmp(name, "LittleEndian") == 0: return 1
return 0
def extract_class_name_from_annotation(self, node: ast.AST*, imported_modules: str, pool: memhub.MemBuddy* = None, from_imports: str = None) -> str:
@@ -2332,6 +2345,19 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
if k == ast.ASTKind.BinOp:
bop: ast.BinOp* = ast.BinOp*(node)
if bop.op == ast.OpKind.BitOr:
# Byte-order markers: annotation `|` means "and", so `ActualType | t.BigEndian`
# yields the actual type; the byte order itself is recorded on the field entry
# (see ClassGenDef field_byteorder_buf), not carried in the LLVM type.
left_bo: int = self._is_byteorder_marker(bop.left, imported_modules)
right_bo: int = self._is_byteorder_marker(bop.right, imported_modules)
if left_bo != 0 or right_bo != 0:
other_node_bo: ast.AST* = bop.right
if right_bo != 0: other_node_bo = bop.left
if other_node_bo is not None:
other_ty_bo: mlirlite.LLVMType* = self.resolve_annotation_type(pool, other_node_bo, imported_modules, from_imports, trans, depth + 1)
if other_ty_bo is not None: return other_ty_bo
# Markers on both sides (e.g. `t.BigEndian | t.LittleEndian`) -> CInt.
return mlirlite.Int32(pool)
# Detect the t.CPtr marker (supports t.CPtr and the bare from t import CPtr name).
# CRef/CTempRef (value-reference parameter markers) resolve identically here: the
# parameter ABI is Ptr(other); the ref/temp distinction only drives call-site auto-address.