refactor(subscript): 删除调用侧下标 zext 与 _zext_index_to_i32,统一交给 build_gep(单一真源)

This commit is contained in:
TermiNexus committed 2026-10-03 13:35:36 +08:00
1 parent bcbc7142be
commit df1ffa4c2a
3 files changed
+15 -44

No files matched your search

+2 -3
View File
@@ -478,9 +478,8 @@ novirtual class CallGenCBuiltin(CallGenBase.CallGenBase):
if arr_val is None or arr_val.Ty is None: return None
idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub_addr.slice, None, 0, trans)
if idx_val is None: return None
# 与 ExprGenName 的指针下标路径同口径:窄整数下标(i8/i16)必须 zext
# 到 i32,否则 LLVM 按符号扩展(uint8ptr[200] → p[-56])越界。
idx_val = self.Gen.ExprGenBase._zext_index_to_i32(builder, idx_val)
# 下标 zext 由 llvmlite.build_gep / build_gep_array 内部统一处理
# (唯一真源),此处不再自行 zext。
arr_pointee_ca: llvmlite.LLVMType* = None
if self.Gen.ExprGenBase.is_ptr_type(arr_val.Ty) != 0:
arr_pointee_ca = arr_val.Ty.Pointee
-18
View File
@@ -195,24 +195,6 @@ novirtual class ExprGenBase:
case _:
return 0
# ============================================================
# _zext_index_to_i32 - 数组下标索引零扩展
#
# LLVM GEP 对窄整数索引默认符号扩展:i8 0xE2(226) 会被当成 -30,
# 导致数组下标越界读(字节 >= 128 的乱码根因)。
# 数组下标语义为非负,<32 位整数索引一律 zext 到 i32。
# 仅用于数组 GEP;指针负偏移(p[-1])不经过此路径,不受影响。
# ============================================================
def _zext_index_to_i32(self, builder: llvmlite.IRBuilder*,
idx_val: llvmlite.Value*) -> llvmlite.Value*:
"""将 <32 位整数下标零扩展到 i32(数组下标非负语义)"""
if idx_val is None or idx_val.Ty is None or builder is None:
return idx_val
idx_bits: int = self.get_llvm_type_bits(idx_val.Ty)
if idx_bits != 0 and idx_bits < 32:
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(builder.Pool)
return llvmlite.build_zext(builder, idx_val, i32_ty)
return idx_val
# ============================================================
# _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体
#
# 处理两种情况:
+13 -23
View File
@@ -691,7 +691,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
arr_ptr_nl: llvmlite.Value* = llvmlite.build_bitcast(builder, raw_nl, llvmlite.Ptr(pool, nl_ty))
if arr_ptr_nl is None:
return None
return llvmlite.build_gep_array(builder, nl_ty, elem_ty_nl, arr_ptr_nl, self._zext_index_to_i32(builder, idx_val))
return llvmlite.build_gep_array(builder, nl_ty, elem_ty_nl, arr_ptr_nl, idx_val)
case llvmlite.LLVMType.Ptr(inner_nl):
arr_ptr_nl2: llvmlite.Value* = llvmlite.build_bitcast(builder, raw_nl, llvmlite.Ptr(pool, nl_ty))
if arr_ptr_nl2 is None: return None
@@ -746,14 +746,9 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# 翻译索引
idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.slice, None, 0, trans)
if idx_val is None: return None
# 窄整数下标(i8/i16)在 GEP 中会被 LLVM 按**符号扩展**:uint8ptr[200]
# 变成 p[-56],写到数组之前 / 读越界。_zext_index_to_i32 的注释记录的
# 正是这个现象("字节 >= 128 的乱码根因"),但此前只接在数组 GEP 路径;
# 裸指针下标(UINT8PTR / INTPTR / 各类 rawptr)走 build_gep,漏了 zext
# ——zlib 的 lit_freqs[data[pos]] 漏计字节 >=128 即由此而来。
# 下标语义为非负,故在唯一入口统一 zext(i32 及以上不动,p[-1] 这类
# i32 负偏移不受影响;下游 coerce_to_type/sizet(...) 均为 i32→i64 拓宽)。
idx_val = self._zext_index_to_i32(builder, idx_val)
# 窄整数下标(i8/i16)的 zext 已下沉到 llvmlite.build_gep /
# build_gep_array 内部(唯一真源),此处不再自行 zext——否则裸指针
# 下标(build_gep)会漏掉,字节 >= 128 的索引被 LLVM 符号扩展成负数。
# 嵌套下标读取: a[i][j] —— 递归取内层指针后 load
# (与 get_subscript_ptr 嵌套分支对称;如 gfx.vp 的
@@ -766,7 +761,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
if inner_elem_r is None: return None
match inner_elem_r:
case llvmlite.LLVMType.Array(arr_ie_r, _):
elem_ptr_r: llvmlite.Value* = llvmlite.build_gep_array(builder, inner_elem_r, arr_ie_r, inner_ptr_r, self._zext_index_to_i32(builder, idx_val))
elem_ptr_r: llvmlite.Value* = llvmlite.build_gep_array(builder, inner_elem_r, arr_ie_r, inner_ptr_r, idx_val)
if elem_ptr_r is not None:
return llvmlite.build_load(builder, arr_ie_r, elem_ptr_r)
return None
@@ -804,7 +799,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
match pointee:
case llvmlite.LLVMType.Array(elem_ty, count):
# 数组遍历: getelementptr [N x elem_ty], ... , i32 0, i32 %idx
elem_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, pointee, elem_ty, alloca, self._zext_index_to_i32(builder, idx_val))
elem_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, pointee, elem_ty, alloca, idx_val)
if elem_ptr is not None:
return llvmlite.build_load(builder, elem_ty, elem_ptr)
return None
@@ -978,7 +973,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# 数组类型: 双索引 GEP + load 元素
match elem_ty2:
case llvmlite.LLVMType.Array(arr_elem_ty2, arr_count2):
elem_ptr3: llvmlite.Value* = llvmlite.build_gep_array(builder, elem_ty2, arr_elem_ty2, ptr_val, self._zext_index_to_i32(builder, idx_val))
elem_ptr3: llvmlite.Value* = llvmlite.build_gep_array(builder, elem_ty2, arr_elem_ty2, ptr_val, idx_val)
if elem_ptr3 is not None:
return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3, vol_sub_gen)
return None
@@ -1094,14 +1089,9 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# 翻译索引
idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.slice, None, 0, trans)
if idx_val is None: return None
# 窄整数下标(i8/i16)在 GEP 中会被 LLVM 按**符号扩展**:uint8ptr[200]
# 变成 p[-56],写到数组之前 / 读越界。_zext_index_to_i32 的注释记录的
# 正是这个现象("字节 >= 128 的乱码根因"),但此前只接在数组 GEP 路径;
# 裸指针下标(UINT8PTR / INTPTR / 各类 rawptr)走 build_gep,漏了 zext
# ——zlib 的 lit_freqs[data[pos]] 漏计字节 >=128 即由此而来。
# 下标语义为非负,故在唯一入口统一 zext(i32 及以上不动,p[-1] 这类
# i32 负偏移不受影响;下游 coerce_to_type/sizet(...) 均为 i32→i64 拓宽)。
idx_val = self._zext_index_to_i32(builder, idx_val)
# 窄整数下标(i8/i16)的 zext 已下沉到 llvmlite.build_gep /
# build_gep_array 内部(唯一真源),此处不再自行 zext——否则裸指针
# 下标(build_gep)会漏掉,字节 >= 128 的索引被 LLVM 符号扩展成负数。
# 嵌套下标: a[i][j] = v —— 递归解析内层下标指针后 GEP
# (如 gfx.vp Mat4.m: t.CArray[t.CArray[float, 4], 4] 的 m.m[0][0] = 1;
@@ -1115,7 +1105,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
if inner_elem is None: return None
match inner_elem:
case llvmlite.LLVMType.Array(arr_ie, _):
return llvmlite.build_gep_array(builder, inner_elem, arr_ie, inner_ptr, self._zext_index_to_i32(builder, idx_val))
return llvmlite.build_gep_array(builder, inner_elem, arr_ie, inner_ptr, idx_val)
case _:
return llvmlite.build_gep(builder, inner_elem, inner_ptr, idx_val)
@@ -1136,7 +1126,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
match pointee:
case llvmlite.LLVMType.Array(elem_ty, count):
# 数组遍历
return llvmlite.build_gep_array(builder, pointee, elem_ty, alloca, self._zext_index_to_i32(builder, idx_val))
return llvmlite.build_gep_array(builder, pointee, elem_ty, alloca, idx_val)
case llvmlite.LLVMType.Ptr(inner_ty):
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针,
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
@@ -1234,7 +1224,7 @@ novirtual class ExprGenName(ExprGenBase.ExprGenBase):
# 数组类型: 双索引 GEP (getelementptr [N x ty], ptr, i32 0, i32 idx)
match elem_ty2:
case llvmlite.LLVMType.Array(arr_elem_ty, arr_count):
return llvmlite.build_gep_array(builder, elem_ty2, arr_elem_ty, ptr_val, self._zext_index_to_i32(builder, idx_val))
return llvmlite.build_gep_array(builder, elem_ty2, arr_elem_ty, ptr_val, idx_val)
case _:
pass
# 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__