fix(viperc): CDefine 常量按位宽处理时不再把可容正值翻转成负数,修常量算式折错
现场:Gargantua _start 的 string.memset(fb, 0, GW * GH * 4)(GW=160, GH=90)应折叠为 57600,实际生成 movl \(= -34560)作为 memset 长度 → 从 0x457ca0 写 4GB → 越界写撞到映射区末尾 0x467000,用户态 #PF err=0x7(cr2 与反汇编逐字对上)。根因:define GW = 160 的位宽按值推断为 8(无符号可容),而 _cdefine_bits_value/_normalize_cdefine_bits 无条件 '(value<<56)>>56' 重解释为有符号 → 160 变 -96(=-96*90*4=-34560)。现只在两种解释都装不下时才截断;位型不变(const_int 本就按位宽截断),仅不再翻转可容正值的语义。
This commit is contained in:
1 parent
a143c2de0c
commit
dc4468593c
2 files changed
+38
-18
No files matched your search
@@ -189,17 +189,27 @@ novirtual class AssignGenMixin:
|
||||
return 0
|
||||
|
||||
def _normalize_cdefine_bits(self, value: int64, bits: int) -> int64:
|
||||
"""把值按位宽**截断**后再重解释为该位宽的有符号表示(与 ExprGenCdef._cdefine_bits_value 同口径)。
|
||||
"""把值按位宽处理:**只有在当前位宽的两种解释下都装不下时才截断**,否则原样保留
|
||||
(与 ExprGenCdef._cdefine_bits_value 同口径)。
|
||||
|
||||
「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0),
|
||||
不是直接把原值搬过来、也不是只对"刚好越界一点"的值做重解释。
|
||||
实现用左移后算术右移,而不是 `value & 0xFFFFFFFF` 这类大掩码字面量:
|
||||
掩码字面量(如 4294967295)超出 int32 范围,其加宽方向在 TPC/VPC 上可能判成 sext,
|
||||
会得到 0xFFFFFFFFFFFFFFFF 而不是 0xFFFFFFFF,导致截断失效。
|
||||
「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0)。
|
||||
但**不**把"无符号可容、有符号装不下"的正值重解释成负数:旧实现无条件
|
||||
`(value << 56) >> 56`,8 位下的 160 变成 -96,正值静默变负,常量算式随之算错
|
||||
(现场:Gargantua `GW * GH * 4` = 57600 被折成 -34560)。
|
||||
实现仍避开大掩码字面量(见下)。
|
||||
"""
|
||||
if bits == 8: return (value << 56) >> 56
|
||||
if bits == 16: return (value << 48) >> 48
|
||||
if bits == 32: return (value << 32) >> 32
|
||||
if bits == 8:
|
||||
if value >= -128 and value <= 127: return value
|
||||
if value > 127 and (value >> 8) == 0: return value
|
||||
return (value << 56) >> 56
|
||||
if bits == 16:
|
||||
if value >= -32768 and value <= 32767: return value
|
||||
if value > 32767 and (value >> 16) == 0: return value
|
||||
return (value << 48) >> 48
|
||||
if bits == 32:
|
||||
if value >= -2147483647 - 1 and value <= 2147483647: return value
|
||||
if value > 2147483647 and (value >> 32) == 0: return value
|
||||
return (value << 32) >> 32
|
||||
return value
|
||||
|
||||
def cdefine_decl_bits(self, pool: memhub.MemBuddy*, annot: ast.AST*, value_node: ast.AST*) -> int:
|
||||
|
||||
@@ -842,17 +842,27 @@ novirtual class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
# ============================================================
|
||||
# cdefine_use_width_value - materialize CDefine constants at the use-site width (TPC-aligned)
|
||||
def _cdefine_bits_value(self, value: int64, bits: int) -> int64:
|
||||
"""把值按位宽**截断**后再重解释为该位宽的有符号表示(与 AssignGenMixin._normalize_cdefine_bits 同口径)。
|
||||
"""把值按位宽处理:**只有在当前位宽的两种解释下都装不下时才截断**,否则原样保留。
|
||||
|
||||
「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(WORD(0x80000000) → 0),
|
||||
而不是只对"刚好越界一点"的值做重解释。
|
||||
实现用左移后算术右移,而不是 `value & 0xFFFFFFFF` 这类大掩码字面量:
|
||||
掩码字面量(如 4294967295)超出 int32 范围,其加宽方向在 TPC/VPC 上可能判成 sext,
|
||||
会得到 0xFFFFFFFFFFFFFFFF 而不是 0xFFFFFFFF,导致截断失效。
|
||||
「左侧只会看到截断了的数据」:超宽的值先按 bits 取低位(如 WORD(0x80000000) → 0)。
|
||||
但不该把"无符号可容、有符号装不下"的**正值**重解释成负数:旧实现无条件
|
||||
`(value << 56) >> 56`,8 位下的 160 被读成 -96,正值静默变负 —— 现场
|
||||
Gargantua `_start` 的 `string.memset(fb, 0, GW * GH * 4)`(GW=160, GH=90)
|
||||
被折成 -34560,作为长度写穿映射区 → #PF。位型不变(const_int 本就按位宽截断),
|
||||
只是不再翻转可容正值的语义。实现仍避开大掩码字面量(见下)。
|
||||
"""
|
||||
if bits == 8: return (value << 56) >> 56
|
||||
if bits == 16: return (value << 48) >> 48
|
||||
if bits == 32: return (value << 32) >> 32
|
||||
if bits == 8:
|
||||
if value >= -128 and value <= 127: return value
|
||||
if value > 127 and (value >> 8) == 0: return value
|
||||
return (value << 56) >> 56
|
||||
if bits == 16:
|
||||
if value >= -32768 and value <= 32767: return value
|
||||
if value > 32767 and (value >> 16) == 0: return value
|
||||
return (value << 48) >> 48
|
||||
if bits == 32:
|
||||
if value >= -2147483647 - 1 and value <= 2147483647: return value
|
||||
if value > 2147483647 and (value >> 32) == 0: return value
|
||||
return (value << 32) >> 32
|
||||
return value
|
||||
|
||||
def cdefine_use_width_value(self, pool: memhub.MemBuddy*, node: ast.AST*, name: str, value: int64, target_ty: mlirlite.LLVMType*, use_ctx: str = None) -> mlirlite.Value*:
|
||||
|
||||
Reference in new issue
Block a user