diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index a4ede0f..b4991b1 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -896,13 +896,14 @@ class AnnAssignHandle(BaseHandle): if isinstance(VarPtr.type, ir.PointerType): TargetType: ir.Type = VarPtr.type.pointee if InitValue.type != TargetType: - if isinstance(InitValue.type, ir.IntType) and isinstance(TargetType, ir.IntType): - if TargetType.width > InitValue.type.width: - InitValue = Gen.builder.zext(InitValue, TargetType, name=f"zext_{VarName}") - elif TargetType.width < InitValue.type.width: - InitValue = Gen.builder.trunc(InitValue, TargetType, name=f"trunc_{VarName}") - elif isinstance(InitValue.type, ir.PointerType) and isinstance(TargetType, ir.PointerType): - InitValue = Gen.builder.bitcast(InitValue, TargetType, name=f"cast_{VarName}") + # 统一走 `_coerce_value`(隐式转换的唯一收敛点): + # 此前这里手写 `zext/trunc`,整型加宽一律 zext ⇒ 负常量被当无符号 + # 处理(现场:`b: int64 = -196608` 落成 0x00000000FFFD0000 大正数, + # IntWidthTest Test 5/6 的 FAIL)。`_coerce_value` 对 i32→i64 用 + # `sext` 保持符号,隐式窄化亦按规则 fail-fast。 + _coerced: ir.Value | None = Gen._coerce_value(InitValue, TargetType, Node) + if _coerced is not None: + InitValue = _coerced Gen._store(InitValue, VarPtr) except Exception as _e: if _config_mode == "strict": @@ -1070,10 +1071,14 @@ class AnnAssignHandle(BaseHandle): InitValue = (ir.Constant(VarType, None) if isinstance(VarType, ir.PointerType) else Gen._ZeroConst(VarType)) elif isinstance(InitValue.type, ir.IntType) and isinstance(VarType, ir.IntType): - if VarType.width > InitValue.type.width: - InitValue = Gen.builder.zext(InitValue, VarType, name=f"zext_{VarName}") - elif VarType.width < InitValue.type.width: - InitValue = Gen.builder.trunc(InitValue, VarType, name=f"trunc_{VarName}") + # 统一走 `_coerce_value`(隐式转换的唯一收敛点):此处原先手写 + # `zext`,整型加宽一律零扩展 ⇒ 负常量被当无符号处理。 + # 现场:`b: int64 = -196608` 落成 4294770688(0x00000000FFFD0000) + # ⇒ 随后 `b >> 1` 呈现“逻辑右移”假象(IntWidthTest Test 5/6)。 + # `_coerce_value` 对 i32→i64 用 `sext` 保符号;隐式窄化按其规则 fail-fast。 + _coerced_i: ir.Value | None = Gen._coerce_value(InitValue, VarType, Node.value) + if _coerced_i is not None: + InitValue = _coerced_i elif isinstance(InitValue.type, ir.PointerType) and isinstance(VarType, ir.PointerType): Allowed: bool Reason: str diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 1697b1a..fa5a5a3 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -1886,7 +1886,10 @@ class ExprCallHandle(BaseHandle): if expected_type.width < val.type.width: return Gen.builder.trunc(val, expected_type) else: - return Gen.builder.zext(val, expected_type) + # 整型加宽必须**保符号**(i32/i64 按有符号语义):此前一律 zext,会把负值 + # 当无符号处理。现场:`int64(-1)` 里 `-1` 的 i32 位型被 zext 成 4294967295 + # ⇒ `x ^ int64(-1)` 变号 ⇒ IntWidthTest Test 5 第三条(循环不收敛)FAIL。 + return Gen.builder.sext(val, expected_type) if isinstance(val.type, ir.PointerType) and isinstance(expected_type, ir.IntType): if expected_type.width == 64: return Gen.builder.ptrtoint(val, expected_type) @@ -2470,10 +2473,13 @@ class ExprCallHandle(BaseHandle): if ArgVal.type == TargetType: return ArgVal if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType): - if ArgVal.type.width < TargetType.width: - return Gen.builder.zext(ArgVal, TargetType, name=f"zext_{TypedefName}_cast") - elif ArgVal.type.width > TargetType.width: - return Gen.builder.trunc(ArgVal, TargetType, name=f"trunc_{TypedefName}_cast") + # 统一走 `_coerce_value`(隐式/显式转换的唯一收敛点):此前手写 `zext`, + # 整型加宽一律零扩展 ⇒ 负值被当无符号(现场:`int64(-1)` 里 -1 的 i32 位型 + # 变成 4294967295 ⇒ `x ^ int64(-1)` 变号 ⇒ IntWidthTest Test 5 第三条 + # 循环不收敛)。`_coerce_value` 加宽用 `sext` 保符号,窄化按其规则 fail-fast。 + _coerced_td: ir.Value | None = Gen._coerce_value(ArgVal, TargetType, Node) + if _coerced_td is not None: + return _coerced_td return ArgVal if isinstance(TargetType, ir.PointerType): if isinstance(ArgVal.type, ir.PointerType): @@ -2535,12 +2541,13 @@ class ExprCallHandle(BaseHandle): if ArgVal.type == TargetType: return ArgVal if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.IntType): - # builtins typedef 数值转换(int64(bool) / uint64(i32) 等):按宽度 - # zext/trunc,与 _HandleTypedefCastLlvm 的语义一致。 - if ArgVal.type.width < TargetType.width: - return Gen.builder.zext(ArgVal, TargetType, name="zext_typedef_cast") - elif ArgVal.type.width > TargetType.width: - return Gen.builder.trunc(ArgVal, TargetType, name="trunc_typedef_cast") + # 统一走 `_coerce_value`(隐式/显式转换的唯一收敛点):此前手写 `zext`, + # 整型加宽一律零扩展 ⇒ 负值被当无符号。 + # 现场:`int64(-1)` → i64 4294967295 ⇒ `x ^ int64(-1)` 变号、循环不收敛 + # (IntWidthTest Test 5 第三条);`_coerce_value` 加宽用 `sext` 保符号。 + _coerced_b: ir.Value | None = Gen._coerce_value(ArgVal, TargetType, Node) + if _coerced_b is not None: + return _coerced_b return ArgVal if isinstance(TargetType, ir.PointerType): if isinstance(ArgVal.type, ir.PointerType): diff --git a/lib/core/Handles/HandlesExprOps.py b/lib/core/Handles/HandlesExprOps.py index 476a7d4..2917500 100644 --- a/lib/core/Handles/HandlesExprOps.py +++ b/lib/core/Handles/HandlesExprOps.py @@ -287,6 +287,15 @@ class ExprOpsHandle(BaseHandle): and not isinstance(Node.operand.value, bool): RequireIntLiteralStorable(Gen, self.Trans, Node, -Node.operand.value) if isinstance(OperandVal.type, ir.IntType): + # 常量直接折叠成常量(保持有符号位型):此前无条件发运行期 neg,常量 `-1` + # 变成一条 `neg i32` 指令,随后加宽时被零扩展 ⇒ 4294967295 + # (现场:`int64(-1)` ⇒ `x ^ int64(-1)` 变号、循环不收敛; + # IntWidthTest Test 5 第三条)。 + if isinstance(OperandVal, ir.Constant) and isinstance(getattr(OperandVal, 'constant', None), int): + _uw: int = OperandVal.type.width + _uv: int = int(OperandVal.constant) & ((1 << _uw) - 1) + _sv: int = _uv - (1 << _uw) if _uv >= (1 << (_uw - 1)) else _uv + return ir.Constant(OperandVal.type, -_sv) return Gen.builder.neg(OperandVal, name="neg_result") elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)): return Gen.builder.fneg(OperandVal, name="fneg_result")