feat(gen): 字节序 bswap 改为按目标端序判断(BigEndian/LittleEndian 都相对目标),原语改名 apply_byte_order_bswap
This commit is contained in:
1 parent
444e87dd7d
commit
cb2dc4cb3a
5 files changed
+51
-27
No files matched your search
@@ -1429,7 +1429,7 @@ novirtual class AssignGenMixin:
|
||||
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)
|
||||
# BigEndian array: store each element byte-swapped (pairs the un-swap on element read).
|
||||
store_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, store_val, byte_order)
|
||||
store_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, store_val, byte_order)
|
||||
mlirlite.build_store(builder, store_val, elem_ptr)
|
||||
|
||||
return 0
|
||||
@@ -1588,7 +1588,7 @@ novirtual class AssignGenMixin:
|
||||
if cur_val is None:
|
||||
# fail-fast: attribute current value load failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "cannot load the current value of the attribute", "TypeError")
|
||||
cur_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, cur_val, bo_fa)
|
||||
cur_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, cur_val, bo_fa)
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
@@ -1609,7 +1609,7 @@ novirtual class AssignGenMixin:
|
||||
self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError")
|
||||
# BigEndian field: re-swap the result so the slot keeps the byte-swapped pattern
|
||||
# (pairs the un-swap of cur_val above, keeping memory big-endian).
|
||||
result = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, result, bo_fa)
|
||||
result = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, result, bo_fa)
|
||||
mlirlite.build_store(builder, result, field_ptr, vol_fa)
|
||||
return 0
|
||||
|
||||
@@ -1661,7 +1661,7 @@ novirtual class AssignGenMixin:
|
||||
if cur_val is None:
|
||||
# fail-fast: element current value load failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "cannot load the current value of the subscript element", "TypeError")
|
||||
cur_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, cur_val, bo_sa)
|
||||
cur_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, cur_val, bo_sa)
|
||||
|
||||
# 3. Translate the RHS value
|
||||
rhs_val: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, aug.value, None, 0, trans)
|
||||
@@ -1681,7 +1681,7 @@ novirtual class AssignGenMixin:
|
||||
# fail-fast: type coercion failed
|
||||
self.Gen.TypeGenErr.fatal_error(target, "type coercion failed", "TypeError")
|
||||
# BigEndian array element: re-swap the result so the slot stays byte-swapped (pairs cur_val above).
|
||||
result = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, result, bo_sa)
|
||||
result = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, result, bo_sa)
|
||||
mlirlite.build_store(builder, result, elem_ptr, vol_sa)
|
||||
return 0
|
||||
|
||||
@@ -1770,7 +1770,7 @@ novirtual class AssignGenMixin:
|
||||
target_ty = target_alloca.Ty.Pointee
|
||||
cur_val = mlirlite.build_load(builder, target_ty, target_alloca, vol_aa)
|
||||
# BigEndian local: un-swap the loaded slot value before the arithmetic (paired with the store below).
|
||||
cur_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, cur_val, bo_aa)
|
||||
cur_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, cur_val, bo_aa)
|
||||
|
||||
if cur_val is None:
|
||||
# fail-fast: target variable current value load failed
|
||||
@@ -1838,7 +1838,7 @@ novirtual class AssignGenMixin:
|
||||
# Ordinary local variable
|
||||
if target_alloca is not None:
|
||||
# BigEndian local: re-swap the result so the slot keeps the byte-swapped pattern (pairs the load above).
|
||||
result = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, result, bo_aa)
|
||||
result = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, result, bo_aa)
|
||||
mlirlite.build_store(builder, result, target_alloca, vol_aa)
|
||||
|
||||
return 0
|
||||
@@ -2466,7 +2466,7 @@ novirtual class AssignGenMixin:
|
||||
# BigEndian local: store the byte-swapped value so the slot is big-endian in memory
|
||||
# (pairs the un-swap done by ExprGenName.translate_name_value on the read path).
|
||||
decl_bo: int = self.Gen.VarGen.var_byte_order(self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
rhs_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, rhs_val, decl_bo)
|
||||
rhs_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, rhs_val, decl_bo)
|
||||
mlirlite.build_store(builder, rhs_val, alloca, vol_laa)
|
||||
# P2 willFree:带注解声明/赋值后清除失效态(新变量本就为 0;复用槽兜底)
|
||||
self.Gen.VarGen.clear_var_freed(trans.SymTab, nm.id)
|
||||
@@ -2569,7 +2569,7 @@ novirtual class AssignGenMixin:
|
||||
if sub_lv_b.value is not None and sub_lv_b.value.kind() == ast.ASTKind.Name:
|
||||
sub_nm_lv: ast.Name* = ast.Name*(sub_lv_b.value)
|
||||
if sub_nm_lv.id is not None: bo_lv = self.Gen.VarGen.var_byte_order(self.Gen.VarGen.lookup_var_entry(trans.SymTab, sub_nm_lv.id))
|
||||
store_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, store_val, bo_lv)
|
||||
store_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, store_val, bo_lv)
|
||||
# t.CVolatile 字段 / rawptr[t.CVolatile|T] 基址:写出同样带 volatile。
|
||||
vol_lv: int = 0
|
||||
if is_attr != 0:
|
||||
@@ -2794,7 +2794,7 @@ novirtual class AssignGenMixin:
|
||||
if sub_wr is not None and sub_wr.value is not None and sub_wr.value.kind() == ast.ASTKind.Name:
|
||||
sub_nm_sw: ast.Name* = ast.Name*(sub_wr.value)
|
||||
if sub_nm_sw.id is not None: bo_sw = self.Gen.VarGen.var_byte_order(self.Gen.VarGen.lookup_var_entry(trans.SymTab, sub_nm_sw.id))
|
||||
store_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, store_val, bo_sw)
|
||||
store_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, store_val, bo_sw)
|
||||
# rawptr[t.CVolatile|T] base: p[i] = v stores with volatile when the base is resolvable
|
||||
vol_sw: int = 0
|
||||
if sub_wr is not None: vol_sw = self.Gen.ExprGenAttr.base_pointee_is_volatile(pool, trans, sub_wr.value)
|
||||
@@ -2932,7 +2932,7 @@ novirtual class AssignGenMixin:
|
||||
# BigEndian field: store the byte-swapped value so the slot is big-endian in memory
|
||||
# (pairs the un-swap done by ExprGenAttr.translate_attribute on the load path).
|
||||
bo_fw: int = self.Gen.ExprGenAttr.attr_field_byte_order(pool, trans, target)
|
||||
store_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, store_val, bo_fw)
|
||||
store_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, store_val, bo_fw)
|
||||
# t.CVolatile field: store with the volatile qualifier
|
||||
vol_fw: int = self.Gen.ExprGenAttr.attr_field_is_volatile(pool, trans, target)
|
||||
# rawptr[t.CVolatile|T] base: p.field = v also stores with volatile
|
||||
@@ -3045,7 +3045,7 @@ novirtual class AssignGenMixin:
|
||||
# BigEndian local variable: store the byte-swapped value so the slot is big-endian in
|
||||
# memory (pairs the un-swap done by ExprGenName.translate_name_value on the read path).
|
||||
bo_las: int = self.Gen.VarGen.var_byte_order(self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
store_val = self.Gen.ExprGenBase.apply_bswap_if_big(pool, builder, store_val, bo_las)
|
||||
store_val = self.Gen.ExprGenBase.apply_byte_order_bswap(pool, builder, store_val, bo_las)
|
||||
# t.CVolatile local variable: store with the volatile qualifier
|
||||
vol_las: int = self.Gen.VarGen.var_is_volatile(self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
# M3 所有权记账:必须先记账再写值(覆盖释放要读到旧值);
|
||||
|
||||
@@ -651,10 +651,10 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if cast_ptr_rn is not None:
|
||||
rn_alias_val: mlirlite.Value* = mlirlite.build_load(builder, decl_ty_rn, cast_ptr_rn)
|
||||
# BigEndian REnum payload alias: un-swap the load (pairing the write side).
|
||||
return self.apply_bswap_if_big(pool, builder, rn_alias_val, alias_fe.ByteOrder)
|
||||
return self.apply_byte_order_bswap(pool, builder, rn_alias_val, alias_fe.ByteOrder)
|
||||
rn_slot_val: mlirlite.Value* = mlirlite.build_load(builder, alias_fe.Ty, alias_ptr, vol_ba_rd)
|
||||
# BigEndian REnum slot: un-swap the load (pairing the write side).
|
||||
return self.apply_bswap_if_big(pool, builder, rn_slot_val, alias_fe.ByteOrder)
|
||||
return self.apply_byte_order_bswap(pool, builder, rn_slot_val, alias_fe.ByteOrder)
|
||||
# property getter fallback: when obj.attr is a @property/@x.getter method, emit a call
|
||||
# (try before reporting a field-not-found error, to avoid a misleading message)
|
||||
if field_info is None and at.value is not None and trans is not None:
|
||||
@@ -717,7 +717,7 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if casted is not None:
|
||||
union_val_rd: mlirlite.Value* = mlirlite.build_load(builder, field_ty, casted, field_vol_rd)
|
||||
# BigEndian field: the slot holds the byte-swapped pattern, so un-swap the load.
|
||||
return self.apply_bswap_if_big(pool, builder, union_val_rd, field_info.ByteOrder)
|
||||
return self.apply_byte_order_bswap(pool, builder, union_val_rd, field_info.ByteOrder)
|
||||
return None
|
||||
# normal struct: GEP + load
|
||||
field_idx: int = field_info.Index
|
||||
@@ -735,14 +735,14 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
|
||||
if cast_ptr_rd is not None:
|
||||
rn_val_rd: mlirlite.Value* = mlirlite.build_load(builder, decl_ty_rd, cast_ptr_rd, field_vol_rd)
|
||||
# BigEndian REnum payload slot: un-swap the load, pairing with the write side.
|
||||
return self.apply_bswap_if_big(pool, builder, rn_val_rd, field_info.ByteOrder)
|
||||
return self.apply_byte_order_bswap(pool, builder, rn_val_rd, field_info.ByteOrder)
|
||||
# an array-typed field cannot be loaded as an SSA value; return the field pointer for
|
||||
# later indexing: self.state[0] → GEP the state field → GEP the array element
|
||||
if self.is_array_type(field_ty) != 0: return field_ptr
|
||||
loaded_val: mlirlite.Value* = mlirlite.build_load(builder, field_ty, field_ptr, field_vol_rd)
|
||||
# BigEndian field: the memory slot holds the byte-swapped pattern, so un-swap the
|
||||
# loaded value; a no-op for non-16/32/64-bit ints (pointers/aggregates unaffected).
|
||||
loaded_val = self.apply_bswap_if_big(pool, builder, loaded_val, field_info.ByteOrder)
|
||||
loaded_val = self.apply_byte_order_bswap(pool, builder, loaded_val, field_info.ByteOrder)
|
||||
# a union-typed field (e.g. Token*) is compiled as i8*; when AnnotClassName points to a
|
||||
# concrete struct type, bitcast the loaded pointer (value→pointer bitcast would be invalid).
|
||||
fc_annot: str = self.Gen.StructGen.get_field_annot_class_name(field_info)
|
||||
|
||||
@@ -149,20 +149,26 @@ novirtual class ExprGenBase:
|
||||
string.memset(ty, 0, mlirlite.LLVMType.__sizeof__())
|
||||
*ty = *mlirlite.LLVMType.Int(bits)
|
||||
return ty
|
||||
# apply_bswap_if_big - byte-order bswap primitive (TPC parity: BaseGen._apply_bswap_if_big).
|
||||
# Only BigEndian (byte_order==1) on a 16/32/64-bit integer emits `llvm.bswap`; every other case
|
||||
# returns val unchanged. byte_order==0 (native) must be zero-cost: no IR is emitted at all, and
|
||||
# 2 (LittleEndian) also returns unchanged because the host is little-endian (same as TPC, which
|
||||
# only swaps for 'big'), so the in-memory slot stays little-endian and no swap is needed.
|
||||
# apply_byte_order_bswap - byte-order bswap primitive (TPC parity: BaseGen._apply_bswap_if_big,
|
||||
# extended to judge BOTH markers against the target's native order).
|
||||
# Swapping is needed only when the declared encoding differs from the target's native order,
|
||||
# so: BigEndian field on a little-endian target -> swap; LittleEndian field on a big-endian
|
||||
# target -> swap; declared order == target order -> no swap. byte_order==0 (unspecified)
|
||||
# means native and is always zero-cost: no IR is emitted at all. 16/32/64-bit integers only,
|
||||
# matching TPC (i8/floats/pointers/aggregates are never swapped).
|
||||
# Call name: bare "llvm.bswap" (no width suffix). build_call emits `call i32 @llvm.bswap(i32 %x)`;
|
||||
# __function.vp:2607 detects a bare `@llvm.*` (non-`llvm.mlir.`) callee and renders it as
|
||||
# `llvm.call_intrinsic "llvm.bswap"(...)`, and mlir-translate mangles the name from the operand
|
||||
# type to `llvm.bswap.i32` (README.md:367-378, the same path used by CallGenVa.vp:123 `llvm.va_start`
|
||||
# -> `llvm.va_start.p0`). Passing `llvm.bswap.i32` explicitly is unnecessary and would break the
|
||||
# uniform mangle path, so the un-suffixed name is used.
|
||||
def apply_bswap_if_big(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, val: mlirlite.Value*, byte_order: int) -> mlirlite.Value*:
|
||||
"""Return llvm.bswap(val) when byte_order==1 and val is a 16/32/64-bit int; else val unchanged."""
|
||||
if byte_order != 1: return val
|
||||
def apply_byte_order_bswap(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, val: mlirlite.Value*, byte_order: int) -> mlirlite.Value*:
|
||||
"""Return llvm.bswap(val) when val's declared byte_order differs from the target order; else val."""
|
||||
if byte_order == 0: return val
|
||||
# 1=BigEndian, 2=LittleEndian; compare against the target's native order.
|
||||
want_big: int = 0
|
||||
if byte_order == 1: want_big = 1
|
||||
if want_big == self.Gen.TypeGenResolve.target_is_big_endian(): return val
|
||||
if val is None or val.Ty is None: return val
|
||||
bits: int = self.get_llvm_type_bits(val.Ty)
|
||||
if bits != 16 and bits != 32 and bits != 64: return val
|
||||
|
||||
@@ -180,7 +180,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
bo_l = self.Gen.VarGen.var_byte_order(ve_l)
|
||||
local_val_l: mlirlite.Value* = mlirlite.build_load(builder, load_ty, alloca, vol_l)
|
||||
# BigEndian local: the slot is byte-swapped, so un-swap the load (pairs the store in AssignGenMixin).
|
||||
return self.apply_bswap_if_big(pool, builder, local_val_l, bo_l)
|
||||
return self.apply_byte_order_bswap(pool, builder, local_val_l, bo_l)
|
||||
|
||||
# REPL session variables: a name missing from the local table is read back from its ctx slot,
|
||||
# checked after locals and before module aliases; non-REPL behavior is unchanged.
|
||||
@@ -571,7 +571,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||||
# on load (pairs the element store in AssignGenMixin). Non-Name bases are
|
||||
# not covered (matches TPC, which also keys off the base Name).
|
||||
bo_arr_rd: int = self.Gen.VarGen.var_byte_order(self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||||
return self.apply_bswap_if_big(pool, builder, arr_val_rd, bo_arr_rd)
|
||||
return self.apply_byte_order_bswap(pool, builder, arr_val_rd, bo_arr_rd)
|
||||
return None
|
||||
case mlirlite.LLVMType.Struct(_fs_v, _fc_v, lsn_v):
|
||||
# list[T] value variable (an unannotated assignment rhs returns a list
|
||||
|
||||
@@ -1495,6 +1495,24 @@ novirtual class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
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 target_is_big_endian(self) -> int:
|
||||
"""Whether the compilation target is big-endian (1) or little-endian (0).
|
||||
The configured data layout wins: LLVM's first data-layout field is the endianness
|
||||
marker ('e' = little, 'E' = big; omitted means little). Without a data layout, fall
|
||||
back to the triple's `_be` arch suffix (e.g. aarch64_be-...); otherwise little, which
|
||||
is the default target. Both byte-order markers are judged against this: a `t.BigEndian`
|
||||
field on a big-endian target needs no swap, and a `t.LittleEndian` field on a
|
||||
big-endian target does."""
|
||||
dl: str = Config.TargetDataLayout
|
||||
if dl is not None and dl[0] != '\0':
|
||||
if dl[0] == 'E': return 1
|
||||
if dl[0] == 'e': return 0
|
||||
tr: str = Config.TargetTriple
|
||||
if tr is not None:
|
||||
ei: int = 0
|
||||
while tr[ei] != '\0' and tr[ei] != '-': ei += 1
|
||||
if ei >= 3 and tr[ei - 3] == '_' and tr[ei - 2] == 'b' and tr[ei - 1] == 'e': return 1
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user