fix(类型转换): int→i1 目标改为真值归一化 != 0,与 bool(x)/if 条件同判据
类别:a(编译器缺陷)。TPC 侧此前对 i1 目标一律 trunc(取最低位):运行时值 2 → 最低位 0 → false,而同一值在 `if 2:` / `bool(2)`(icmp ne 0)为真 ⇒ 条件上下文与 落存储/强转两处结论相反(静默语义分裂)。 - MemoryOps._CoerceIntToI1(新增,唯一判据源):非 i1 整数 → `icmp ne x, 0`。 - MemoryOps._coerce_value:窄化且目标位宽 == 1 时走 _CoerceIntToI1。 - HandlesAnnAssign._StoreWithCoerce:同上(self.字段 / obj.字段 落存储)。 - HandlesExprCall._HandleTypeCastLlvm:显式强转目标 i1 时同上。 与 TransPyV 侧同批修复(coerce_to_type / _translate_t_type_cast)对齐。 注:TPC 的 `bool` 注解仍是 i8(t.CBool.Size=8),故 `b: bool = 2` 仍按 i8 保位存储 (int(b)=2);本次只覆盖**真 i1 目标**,双端 bool 位宽差异见 SymbolUtils.py:1218-1223 已记录的全局语义分裂。
This commit is contained in:
1 parent
3efe83f1ea
commit
7ee6ebe6b0
3 files changed
+30
-2
No files matched your search
@@ -248,7 +248,12 @@ class AnnAssignHandle(BaseHandle):
|
||||
else Gen._ZeroConst(TargetType))
|
||||
elif isinstance(TargetType, ir.IntType) and isinstance(Value.type, ir.IntType):
|
||||
if TargetType.width < Value.type.width:
|
||||
Value = Gen.builder.trunc(Value, TargetType, name="trunc")
|
||||
# 目标 i1:真值归一化 `x != 0`(与 bool(x)/if 条件同一判据),
|
||||
# 不是 trunc 取最低位(运行时值 2 会得 false,与 `if 2:` 相反)
|
||||
if TargetType.width == 1:
|
||||
Value = Gen._CoerceIntToI1(Value, name="bool_norm")
|
||||
else:
|
||||
Value = Gen.builder.trunc(Value, TargetType, name="trunc")
|
||||
else:
|
||||
Value = Gen.builder.zext(Value, TargetType, name="zext")
|
||||
elif isinstance(TargetType, ir.PointerType) and isinstance(Value.type, ir.PointerType):
|
||||
|
||||
@@ -2276,7 +2276,12 @@ class ExprCallHandle(BaseHandle):
|
||||
Gen._unsigned_results[id(result)] = True
|
||||
return result
|
||||
if val.type.width > target_type.width:
|
||||
result = Gen.builder.trunc(val, target_type, name="trunc_cast")
|
||||
# 目标 i1:真值归一化 `x != 0`(与 bool(x) 内建 / if 条件 / 落存储
|
||||
# 同一判据),不是 trunc 取最低位(运行时值 2 会得 false)
|
||||
if target_type.width == 1:
|
||||
result = Gen._CoerceIntToI1(val, name="bool_norm_cast")
|
||||
else:
|
||||
result = Gen.builder.trunc(val, target_type, name="trunc_cast")
|
||||
if is_dst_unsigned:
|
||||
Gen._unsigned_results[id(result)] = True
|
||||
return result
|
||||
|
||||
@@ -578,6 +578,21 @@ class MemoryOpsMixin:
|
||||
return self._load(GVar, name=name)
|
||||
return None
|
||||
|
||||
def _CoerceIntToI1(self, val: ir.Value, name: str = "bool_norm") -> ir.Value:
|
||||
"""整数 → **i1** 目标的真值归一化(C 6.3.1.2 `_Bool` 转换语义):`x != 0` → 1/0。
|
||||
|
||||
判据与三处真值化上下文**同一**:`bool(x)` 内建(HandlesExprBuiltin.py:74/76)、
|
||||
条件 `if/while`(HandlesIf.py:196)、`and/or` 操作数(HandlesExprOps.py:122-127)。
|
||||
此前「落存储」(本文件 `_coerce_value`、HandlesAnnAssign._StoreWithCoerce)与
|
||||
「显式强转」(HandlesExprCall._HandleTypeCastLlvm)对 i1 目标都走 `trunc`
|
||||
(取最低位)⇒ 运行时值 2 得 0 → false,与 `if 2:` 的真值结论相反
|
||||
(静默语义分裂);值 3 得 true 而同值域下 `!= 0` 亦为 true,故只在偶数非零时暴露。
|
||||
非整数 / 已是 i1 原样返回。
|
||||
"""
|
||||
if not isinstance(val.type, ir.IntType) or val.type.width == 1:
|
||||
return val
|
||||
return self.builder.icmp_signed('!=', val, self._ZeroConst(val.type), name=name)
|
||||
|
||||
def _coerce_value(self, val: ir.Value, target_type: ir.Type, Node: Any = None) -> ir.Value | None:
|
||||
if val.type == target_type:
|
||||
return val
|
||||
@@ -593,6 +608,9 @@ class MemoryOpsMixin:
|
||||
return val
|
||||
if isinstance(target_type, ir.IntType) and isinstance(val.type, ir.IntType):
|
||||
if target_type.width < val.type.width:
|
||||
# 目标 i1:真值归一化(与 bool(x)/if 条件同一判据),不是 trunc 取最低位
|
||||
if target_type.width == 1:
|
||||
return self._CoerceIntToI1(val, name="bool_norm_store")
|
||||
return self.builder.trunc(val, target_type, name="trunc_store")
|
||||
elif val.type.width == 1:
|
||||
# i1 是布尔值(来自 icmp/fcmp/__contains__ 归一化),无符号语义,
|
||||
|
||||
Reference in new issue
Block a user