现场:Test/WebTest 编译 includes/socket.vp:121 报
CastError: 非基本类型的值/指针隐式转换已禁止(构造物化除外):
不能把指针类型隐式转为非基本类型值(Foo* → Foo)
源类型 %"56d0ee99ecf0a0b5.SocketAddr"* → 目标值类型 %"56d0ee99ecf0a0b5.SocketAddr"
现场代码:
class SocketAddr: family: u16 / port: u16 / addr: u32 / zero: u64 # 纯结构体,无 __new__、无方法
def _MakeAddr(host: str, port: INT) -> SocketAddr:
addr: SocketAddr # 结构体值局部变量
string.memset(c.Addr(addr), 0, 16)
...
return addr # ← 第 121 行报错
根因:ExprGenName.translate_name_value 对"结构体值局部变量"的右值**恒返回 alloca 地址**
(原实现,注释解释为"对象即指针"语义,避免 ptrtoint %Struct 非法指令);而 _MakeAddr
的返回类型经 resolve_annotation_type 解析为**结构体值**。translate_return 会把函数返回
类型作为 target_ty 下传给 translate_value(StmtGenCifMixin.vp:557-558),于是 `addr`
求值出 %SocketAddr* → coerce_to_type 的"指针 → 非基本类型值"分支
(ExprGenBase.vp:954-970)只对"构造物化"豁免 → 报错。
标量局部变量无此问题(同函数内非 Struct 分支会 build_load 出值),属结构体值局部变量
独有的表示差异。
改动:ExprGenName.translate_name_value 的 Struct 分支增加 target_ty 判据——使用处
**明确要求同一非基本类型(非指针)**时(_same_agg_ty 判据:与"构造物化豁免"同一类型
匹配真源 AssignGen._stg_ty_equal),像标量一样 build_load 出值;否则维持既有"返回地址"。
- target_ty 为指针时不命中(裸类形参 lowering 为 Ptr(struct),见 FuncGenDef)⇒
Test/StructTest 的 point_sum(p) 这类实参传址行为不变。
- 字段访问基座(ExprGenAttr.vp:743-744,直接 lookup_var 取地址)、c.Addr 取址
(CallGenCBuiltin.vp:293)、方法接收者均不经本函数取地址,不受影响。
- 同时修正该处已失真的注释(原文举例 `x: Cls | t.CPtr` 实际解析为 Ptr(struct),
并非 Struct 值局部变量)。
待验证:重编译 TransPyV(自举两遍)→ WebTest / StructTest / ClassArrayTest / JsonTest。
1236 lines
85 KiB
Plaintext
1236 lines
85 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import viperlib
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
|
||
|
||
import lib.core.Gen.Expr.ExprGenBase as ExprGenBase
|
||
import lib.core.Gen.GenApi as GenApi
|
||
|
||
|
||
# ============================================================
|
||
# ExprGenName - ExprGenMixin 拆分(阶段 D):Name/Subscript/下标访问
|
||
# ============================================================
|
||
novirtual class ExprGenName(ExprGenBase.ExprGenBase):
|
||
"""Name/Subscript/下标访问"""
|
||
|
||
def _cut_from_import_mod(self, pool: memhub.MemBuddy*,
|
||
raw: str) -> str:
|
||
"""截断 lookup_from_import 返回的模块名到独立缓冲
|
||
|
||
lookup_from_import 返回指向 from_imports 内部的指针(非 NUL 结尾,
|
||
后随空格分隔的其他条目,如 "ast.tokens TokenType:ast.tokens ...")。
|
||
不截断则 LookupSha1ByModName 收到整串查不到 → mangle 退化裸名 →
|
||
全局引用不带 SHA1 前缀 → 链接 undefined symbol(_op_head 根因,
|
||
对齐 ExprGenCdef._lookup_cross_module_cdefine 的截断逻辑)。
|
||
截断到空格/冒号/NUL;raw 无效返回 None。
|
||
"""
|
||
if raw is None: return None
|
||
mbl_c: sizet = 0
|
||
while raw[mbl_c] != ' ' and raw[mbl_c] != '\0' and raw[mbl_c] != ':':
|
||
mbl_c += 1
|
||
if mbl_c == 0: return None
|
||
buf_c: str = pool.alloc(mbl_c + 1)
|
||
if buf_c is None: return None
|
||
string.strncpy(buf_c, raw, mbl_c)
|
||
buf_c[mbl_c] = '\0'
|
||
return buf_c
|
||
|
||
def translate_name_value(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
node: ast.AST*,
|
||
trans: HT.Translator* = None,
|
||
target_ty: llvmlite.LLVMType* = None,
|
||
use_ctx: str = None) -> llvmlite.Value*:
|
||
"""翻译变量引用(Name 节点)→ load
|
||
|
||
target_ty:调用方(translate_value)下传的**使用处类型**(赋值目标 /
|
||
形参类型 / 返回类型)。被两处读取:① 下方 CDefine 整数常量物化点
|
||
(决定物化宽度);② **结构体值局部变量**在使用处明确要求同型结构体值时
|
||
改为 load 出值(见下方 Struct 分支说明)。其余变量 load 逐字沿用原有逻辑。
|
||
use_ctx:使用处**真实站点种类**标签,仅透传给宽度不足报文(见
|
||
cdefine_use_width_value),不参与任何判定。
|
||
"""
|
||
# mod 必须取自 trans.Module:函数签名无 mod 参数,若用裸名 mod 会被
|
||
# 解析为 None → create_global_string 的 module_add_global(None, gv) 被
|
||
# add_global 的 `if self is None: return` 静默丢弃 → 字符串 CDefine 的
|
||
# global 定义丢失但 _label_counter/IR 引用已生成 → llc 报
|
||
# "use of undefined value '@.str.{sha1}.N'(SysLibTest _cleanup 根因)"
|
||
mod: llvmlite.LLVMModule* = trans.Module
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm is None: return None
|
||
nm_id: str = nm.id
|
||
if nm_id is None: return None
|
||
# CDefine 编译期常量:返回常量值(浮点 CDefine → double 常量,整数 → i32;否则 double 函数里 return 会生成 ret i32 0 报错)。注意同名变量优先——当前作用域已存在变量时不得被 CDefine 表条目遮蔽(vpi stub 注入会把依赖模块的 CDefine 注册进导入方表,可能误解析局部变量为常量),守卫与下方跨模块 CDefine 查找的 lookup_var 检查一致
|
||
cdef_val_d: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
if trans is None or self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) is None:
|
||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
|
||
# 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"):
|
||
# 返回 global string(i8*),供 return ZLIB_VERSION 等使用。
|
||
cdef_sv: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id)
|
||
if cdef_sv is not None:
|
||
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv, trans)
|
||
self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
|
||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d)
|
||
# 整数 CDefine:重新查表取 64 位全精度值(double 往返会丢精度,
|
||
# 9223372036854775807 → 9.223372036854776e18 舍入错位,生成错常量)
|
||
cdef_val_c: int64 = self.Gen.TypeGenCDef.lookup_cdefine_constant(nm_id)
|
||
# 使用处宽度(经 translate_value 的 target_ty 下传;站点种类由
|
||
# use_ctx 携带,仅供报文使用):
|
||
# 更宽 ⇒ 就地升宽物化;更窄 ⇒ fail-fast;取不到 ⇒ 既有默认 32/64。
|
||
uw_val: llvmlite.Value* = self.Gen.ExprGenCdef.cdefine_use_width_value(pool, node, nm_id, cdef_val_c, target_ty, use_ctx)
|
||
if uw_val is not None:
|
||
return uw_val
|
||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val_c)
|
||
|
||
# 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致)
|
||
# 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找,
|
||
# 避免对普通变量名(mb/name/ptr/pool/self 等)误触发,造成严重性能损耗
|
||
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0:
|
||
if trans is not None:
|
||
# ALL_CAPS 也可能是普通变量(如 Gargantua 的
|
||
# CAM/FWD/RIGHT/UP: V3|t.CPtr 模块级全局)。若当前作用域
|
||
# (含模块级 Root,lookup_var 逐级上溯)已存在同名变量,
|
||
# 优先按变量处理,跳过跨模块 CDefine 查找——否则 ALL_CAPS
|
||
# 命中 star-import 模块(from stdint import *)→ 无谓读源
|
||
# 文件,且多 includes 目录下还可能触发 XMOD-CD 误报
|
||
# (ExprGenCdef._build_source_path_from_sha1 拼错路径)。
|
||
if self.Gen.VarGen.lookup_var(trans.SymTab, nm_id) is None:
|
||
cdef_val: int64 = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, nm_id, trans._from_imports, trans._imported_modules, 0, node)
|
||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||
if self.Gen.TypeGenCDef.is_cdefine_str() != 0:
|
||
cdef_sv2: str = self.Gen.TypeGenCDef.lookup_cdefine_string(nm_id)
|
||
if cdef_sv2 is not None:
|
||
return self.Gen.ExprGenConst.create_global_string(builder, pool, mod, cdef_sv2, trans)
|
||
self.Gen.TypeGenErr.fatal_error(node, f"CDefine 字符串值缺失: {nm_id}", "InternalCompilerError")
|
||
# 跨模块浮点 CDefine 已缓存为 double(is_cdefine_double),
|
||
# 需返回浮点常量而非截断的整数
|
||
dchk_nm: double = self.Gen.TypeGenCDef.lookup_cdefine_double(nm_id)
|
||
if self.Gen.TypeGenCDef.is_cdefine_double() != 0:
|
||
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), dchk_nm)
|
||
# 使用处宽度同口径(跨模块 CDefine)
|
||
uw_x: llvmlite.Value* = self.Gen.ExprGenCdef.cdefine_use_width_value(pool, node, nm_id, cdef_val, target_ty, use_ctx)
|
||
if uw_x is not None:
|
||
return uw_x
|
||
return self.Gen.ExprGenCdef._const_int_for_cdefine(pool, cdef_val)
|
||
|
||
# CDefine 查找失败:from-import 的模块级全局变量(如
|
||
# from Phase1 import PYI_BUF_SIZE;PYI_BUF_SIZE: sizet = 262144 是
|
||
# i64 全局、非宏,语义同 C 的 extern size_t PYI_BUF_SIZE)。from-import
|
||
# 确认名称确实来自某模块后,按后缀匹配查找该全局并加载。
|
||
if trans is not None and trans._from_imports is not None:
|
||
fi_mod_raw: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, nm_id, 0)
|
||
if fi_mod_raw is not None:
|
||
# 带源模块 SHA1 前缀精确查找,避免多模块同名全局后缀匹配串扰。
|
||
# fi_mod_raw 非 NUL 结尾,先截断再查 SHA1(否则整串查不到退化裸名)
|
||
fi_mod_cut: str = self._cut_from_import_mod(pool, fi_mod_raw)
|
||
if fi_mod_cut is None:
|
||
fi_mod_cut = fi_mod_raw
|
||
fi_gv_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1(StubMergerStore.LookupSha1ByModName(fi_mod_cut), nm_id)
|
||
fi_gv: llvmlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(trans.Module, fi_gv_q)
|
||
if fi_gv is not None and fi_gv.Ty is not None:
|
||
fi_ref: llvmlite.Value* = self.Gen.ExprGenAttr.make_global_ref(pool, fi_gv.Name, fi_gv.Ty)
|
||
if fi_ref is not None and fi_ref.Ty is not None:
|
||
fi_pty: llvmlite.LLVMType* = fi_ref.Ty.Pointee
|
||
if fi_pty is not None:
|
||
match fi_pty:
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
# 数组全局按 C 语义退化为基址(对齐 L3383-3388)
|
||
return fi_ref
|
||
case _:
|
||
pass
|
||
return llvmlite.build_load(builder, fi_pty, fi_ref)
|
||
|
||
# global 变量:从模块作用域查找(global 声明优先级最高)
|
||
if trans is not None:
|
||
if GenApi.is_global_name(trans, nm_id) != 0:
|
||
mod_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm_id)
|
||
if mod_alloca is not None:
|
||
load_ty: llvmlite.LLVMType* = None
|
||
if mod_alloca.Ty is not None:
|
||
load_ty = mod_alloca.Ty.Pointee
|
||
if load_ty is None:
|
||
# fail-fast:global 变量存储类型缺失,立即终止编译(暴露上游根因)
|
||
self.Gen.TypeGenErr.fatal_error(node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
|
||
# 全局数组(如 pyzlib.pyzlib_error_msg: CArray[char, 512]):
|
||
# 按 C 语义衰减为基址返回(对齐下方局部数组分支 L3383-3388)。
|
||
# 否则 load [512 x i8] 数组值当 i8* 传 → set_error 的 strncpy
|
||
# dest 是数组值(栈拷贝)而非数组基址 → 写入丢失 → get_error
|
||
# 为空(test_pyzlib "error message is empty" 根因)。
|
||
match load_ty:
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
return mod_alloca
|
||
case _:
|
||
pass
|
||
# t.CVolatile 全局:load 带 volatile 限定符(禁优化器消除重复读)
|
||
vol_g: int = 0
|
||
if trans is not None:
|
||
ve_g: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_id)
|
||
vol_g = self.Gen.VarGen.var_is_volatile(ve_g)
|
||
return llvmlite.build_load(builder, load_ty, mod_alloca, vol_g)
|
||
|
||
# nonlocal 变量:通过闭包 env 访问
|
||
if GenApi.is_nonlocal_name(trans, nm_id) != 0:
|
||
return self.Gen.StmtGenDecl.load_nonlocal_var(trans, nm_id)
|
||
|
||
# *args va_list:变量名直接解析为指向 24 字节 va_list 缓冲区的 i8* 地址
|
||
# (对齐 TPC _direct_values[vararg_name] = va_list_ptr;不 load 缓冲区内容,
|
||
# 转发时按值传该地址即可,如 sprintf → vsnprintf(..., args))
|
||
if trans is not None and trans._vararg_name is not None:
|
||
if nm_id is not None and string.strcmp(nm_id, trans._vararg_name) == 0:
|
||
if trans._va_list_ptr is not None:
|
||
return trans._va_list_ptr
|
||
|
||
# 局部变量查找(必须先于模块别名检查)
|
||
# 否则与模块同名的局部变量(如 `import t, c` 后的局部变量 c)会被误判为模块别名,
|
||
# 导致 SymTab 已注册的局部变量查找不到(rhs_val is None bug 根因)
|
||
alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm_id)
|
||
if alloca is not None:
|
||
load_ty: llvmlite.LLVMType* = None
|
||
if alloca.Ty is not None:
|
||
load_ty = alloca.Ty.Pointee
|
||
if load_ty is None:
|
||
# fail-fast:局部变量存储类型缺失,立即终止编译(暴露上游根因)
|
||
self.Gen.TypeGenErr.fatal_error(node, f"变量 '{nm_id}' 存储类型缺失", "TypeError")
|
||
# 结构体值变量(alloca 类型为 Struct,如 `addr: SocketAddr`):
|
||
# 右值默认按"对象即指针"语义返回其地址(alloca 指针),而非加载结构体值——
|
||
# 加载值后无法参与 ptrtoint/方法接收者等地址相关操作
|
||
# (会造成 `ptrtoint %Struct … to i64` 无效指令,llc invalid cast opcode)。
|
||
# 使用处**明确要求同型结构体值**时才 load 出值,见下方 Struct 分支。
|
||
match load_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
# 结构体值局部变量的右值默认返回 alloca 地址("对象即指针"语义;
|
||
# 字段访问基座 / c.Addr 取址 / 方法接收者都在**别的**路径直接取地址,
|
||
# 不经此处)。但使用处**明确要求同型的非指针结构体值**时必须像标量
|
||
# 一样 load 出值,否则调用方 coerce_to_type 会以
|
||
# 「非基本类型的值/指针隐式转换已禁止(构造物化除外)」拒绝:
|
||
# 现场 includes/socket.vp:121 `return addr` —— _MakeAddr 的返回类型
|
||
# 是结构体值 SocketAddr,而 addr 是结构体值局部变量,
|
||
# 源 %"…SocketAddr"* → 目标 %"…SocketAddr"。
|
||
# 判据用 _same_agg_ty(同一非基本类型),保证 load 后类型与使用处
|
||
# 完全一致;target_ty 为指针时(裸类形参 = Ptr(struct))不命中,
|
||
# 故 point_sum(p) 这类实参传址行为不变。
|
||
if target_ty is not None:
|
||
if self.Gen.ExprGenBase._same_agg_ty(pool, load_ty, target_ty) != 0:
|
||
vol_s: int = 0
|
||
if trans is not None:
|
||
ve_s: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_id)
|
||
vol_s = self.Gen.VarGen.var_is_volatile(ve_s)
|
||
return llvmlite.build_load(builder, load_ty, alloca, vol_s)
|
||
return alloca
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
# 数组变量按 C 语义退化为指针(返回数组基址),而非整体
|
||
# load 数组值——如 printf("%s", str_arr) 应传数组首地址,
|
||
# load [N x i8] 值传给 %s 会读到错误数据崩溃
|
||
# (ClassArrayTest TestCharArray 运行时崩溃根因)。
|
||
return alloca
|
||
# t.CVolatile 局部变量:load 带 volatile 限定符
|
||
vol_l: int = 0
|
||
if trans is not None:
|
||
ve_l: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_id)
|
||
vol_l = self.Gen.VarGen.var_is_volatile(ve_l)
|
||
return llvmlite.build_load(builder, load_ty, alloca, vol_l)
|
||
|
||
# REPL 模式(M2)会话变量:局部表未命中的名字若是会话变量,从 ctx 槽按类型读回。
|
||
# 位置在两处:① 局部查找之后(片段自己声明的局部名/参数优先,走原路径);
|
||
# ② 模块别名/模块函数引用之前(会话名不得被 printf 等本模块 declare 抢走)。
|
||
# 非 REPL(trans.ReplCtx is None)时 repl_try_read 立即返回 None ⇒ 原路径逐字不变。
|
||
if trans is not None and trans.ReplCtx is not None:
|
||
sess_val: llvmlite.Value* = self.Gen.VarGen.repl_try_read(trans, nm_id, node)
|
||
if sess_val is not None:
|
||
return sess_val
|
||
|
||
# 模块别名检查:SymTab 查找失败后才检查
|
||
# 如果 nm_id 是已导入模块名(如 win32file, fileio)且未被声明为局部变量,
|
||
# 返回 None 让上层处理(用于属性访问 win32file.CreateFileA)
|
||
if trans is not None and trans._imported_modules is not None:
|
||
if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, nm_id) != 0:
|
||
return None
|
||
|
||
# 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。
|
||
# 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移
|
||
# (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。
|
||
# 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)——
|
||
# Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到
|
||
# Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR;
|
||
# 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表,
|
||
# 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的
|
||
# RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。
|
||
if trans is not None and trans.Module is not None:
|
||
fn_ref: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(trans.Module, nm_id)
|
||
if fn_ref is not None:
|
||
fn_name: str = llvmlite.function_get_name(fn_ref)
|
||
if fn_name is None:
|
||
return None
|
||
# 构造函数类型:ret_ty + 参数 ParamNode 链表
|
||
fn_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(fn_ref)
|
||
if fn_ret_ty is None:
|
||
# fail-fast:函数返回类型缺失,无法构造函数指针(暴露上游根因)
|
||
self.Gen.TypeGenErr.fatal_error(node, f"函数 '{nm_id}' 返回类型缺失,无法构造函数指针", "TypeError")
|
||
fn_pp: llvmlite.Param* = llvmlite.function_get_param_head(fn_ref)
|
||
fn_first_node: llvmlite.ParamNode* = None
|
||
fn_prev_node: llvmlite.ParamNode* = None
|
||
fn_pcount: int = 0
|
||
while fn_pp is not None:
|
||
fn_pty: llvmlite.LLVMType* = llvmlite.param_get_ty(fn_pp)
|
||
fn_pn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, fn_pty)
|
||
if fn_pn is not None:
|
||
if fn_first_node is None:
|
||
fn_first_node = fn_pn
|
||
if fn_prev_node is not None:
|
||
llvmlite.paramnode_set_next(fn_prev_node, fn_pn)
|
||
fn_prev_node = fn_pn
|
||
fn_pcount += 1
|
||
fn_pp = llvmlite.param_get_next(fn_pp)
|
||
fn_ty: llvmlite.LLVMType* = llvmlite.Func(pool, fn_ret_ty, fn_first_node, fn_pcount)
|
||
if fn_ty is None:
|
||
return None
|
||
# 构造函数指针 Value(new_value 包装,避免触碰 Function.Next)
|
||
fn_ref_v: llvmlite.Value* = llvmlite.new_value(pool)
|
||
if fn_ref_v is None:
|
||
return None
|
||
llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty))
|
||
llvmlite.value_set_isconst(fn_ref_v, 1)
|
||
fn_ref_name: str = pool.alloc(256)
|
||
if fn_ref_name is not None:
|
||
fn_ref_name[0] = '\0'
|
||
if self.Gen.ClassGenVTable._vtable_name_needs_quote(fn_name) != 0:
|
||
viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name)
|
||
else:
|
||
viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name)
|
||
llvmlite.value_set_name(fn_ref_v, fn_ref_name)
|
||
fn_i8ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty)
|
||
|
||
# ============================================================
|
||
# 跨模块 from-import 全局变量读取(如 from .tokens import _op_head)
|
||
# 根因:模块级全局(非 CDefine/非函数)from-import 后无本模块 SymTab
|
||
# 条目,所有查找路径未命中 → translate_name_value 返回 None → 赋值被
|
||
# 静默跳过 → 变量未初始化 → 垃圾指针解引用崩溃(AstTest 的
|
||
# _read_operator 里 `cur = _op_head` 丢失导致 while 循环读未初始化 %6)。
|
||
# 语义对齐模块属性全局(sys._mbuddy):external @{全局名} 引用 + load,
|
||
# 定义由源模块提供(COFF 按名链接)。别名导入用源模块内真实名。
|
||
# ============================================================
|
||
if trans is not None and trans._from_imports is not None:
|
||
if trans.Module is not None:
|
||
# 是 from-import 名称(禁用 star 回退,避免误归 star 模块)
|
||
fi_mod: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, nm_id, 0)
|
||
if fi_mod is not None:
|
||
# 排除已注册类名/枚举名:这些是类型,不作为全局变量值读取
|
||
fi_is_class: int = 0
|
||
if self.Gen.StructGen.get_struct_type(nm_id) is not None:
|
||
fi_is_class = 1
|
||
# 排除 ALL_CAPS CDefine(上方已处理本地+跨模块查找)
|
||
if self.Gen.ExprGenCdef._is_cdefine_name_pattern(nm_id) != 0:
|
||
fi_is_class = 1
|
||
if fi_is_class == 0:
|
||
fi_gname: str = nm_id
|
||
fi_orig: str = self.Gen.ImportsGen.lookup_from_import_original(trans._from_imports, nm_id)
|
||
if fi_orig is not None:
|
||
og_len_fi: sizet = 0
|
||
while fi_orig[og_len_fi] != ' ' and fi_orig[og_len_fi] != '\0':
|
||
og_len_fi += 1
|
||
if og_len_fi > 0:
|
||
og_buf_fi: str = pool.alloc(og_len_fi + 1)
|
||
if og_buf_fi is not None:
|
||
string.strncpy(og_buf_fi, fi_orig, og_len_fi)
|
||
og_buf_fi[og_len_fi] = '\0'
|
||
fi_gname = og_buf_fi
|
||
# stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast
|
||
# (不再创建 external i8* 声明,否则 llc 报 "use of undefined value",
|
||
# 静默回退掩盖 stub 未注入的上游根因)
|
||
# 带源模块 SHA1 前缀精确查找(避免多模块同名全局后缀匹配串扰);
|
||
# fi_mod 非 NUL 结尾,先截断再查 SHA1(否则退化裸名 → undefined)
|
||
fi_mod_cut2: str = self._cut_from_import_mod(pool, fi_mod)
|
||
if fi_mod_cut2 is None:
|
||
fi_mod_cut2 = fi_mod
|
||
gv_fi_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1(StubMergerStore.LookupSha1ByModName(fi_mod_cut2), fi_gname)
|
||
gv_fi: llvmlite.GlobalVariable* = self.Gen.ExprGenAttr.find_global_in_module(trans.Module, gv_fi_q)
|
||
ref_fi: llvmlite.Value* = None
|
||
if gv_fi is not None and gv_fi.Ty is not None:
|
||
ref_fi = self.Gen.ExprGenAttr.make_global_ref(pool, gv_fi.Name, gv_fi.Ty)
|
||
else:
|
||
# 依赖模块 vpi/stub 未注入:Phase A 按文件序翻译时依赖模块
|
||
# (如 lexer 先于 ast.tokens)可能晚于本文件,其 .vpi 尚未生成
|
||
# (LoadDepVpiIntoModule 无从注入)→ 返回 None,不在此
|
||
# fail-fast——否则清缓存后 lexer 先于 tokens 翻译必然误报
|
||
# "stub 未注入"。
|
||
return None
|
||
if ref_fi is not None and ref_fi.Ty is not None:
|
||
lty_fi: llvmlite.LLVMType* = ref_fi.Ty.Pointee
|
||
if lty_fi is not None:
|
||
return llvmlite.build_load(builder, lty_fi, ref_fi)
|
||
return ref_fi
|
||
|
||
# 所有查找路径均失败
|
||
# fail-fast:未定义名称立即终止编译(NameError,暴露上游根因),
|
||
# 不再静默返回 None(否则下游 store/call 到 None 崩溃,掩盖名称查找失败)。
|
||
# 豁免:关键字/内建名(self/pool/true/false/None/match 上下文关键字、_、
|
||
# CIf 系等特殊名字)——这些名字不注册 SymTab 属正常,调用方有合法语义
|
||
# 处理路径(如 CIf 未定义名特判走 else),保持返回 None 不报错。
|
||
if nm_id is None:
|
||
return None
|
||
if string.strcmp(nm_id, "self") == 0 or string.strcmp(nm_id, "pool") == 0 \
|
||
or string.strcmp(nm_id, "true") == 0 or string.strcmp(nm_id, "false") == 0 \
|
||
or string.strcmp(nm_id, "None") == 0 or string.strcmp(nm_id, "match") == 0 \
|
||
or string.strcmp(nm_id, "_") == 0 \
|
||
or string.strcmp(nm_id, "CIf") == 0 or string.strcmp(nm_id, "CIfdef") == 0 \
|
||
or string.strcmp(nm_id, "CIfndef") == 0:
|
||
return None
|
||
self.Gen.TypeGenErr.fatal_error(node, f"未定义名称 '{nm_id}'", "NameError")
|
||
return None
|
||
# ============================================================
|
||
# list_getitem_inline — 内联生成 list[T] __getitem__ 逻辑
|
||
#
|
||
# list 结构布局 (6 字段 × 8 字节):
|
||
# __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40)
|
||
# 返回元素地址 (i8*),调用方根据元素类型 load 正确的值
|
||
# ============================================================
|
||
def list_getitem_inline(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
lm_obj: llvmlite.Value*,
|
||
idx_val: llvmlite.Value*,
|
||
node: ast.AST* = None) -> llvmlite.Value*:
|
||
"""内联生成 list __getitem__ 逻辑,返回元素地址 (i8*)"""
|
||
if builder is None or pool is None or lm_obj is None or idx_val is None:
|
||
return None
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
# 加载 __data__ (偏移 0, index 0)
|
||
g_idx0: llvmlite.Value* = llvmlite.const_int64(pool, 0)
|
||
g_dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0)
|
||
if g_dpp is None:
|
||
return None
|
||
g_data: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, g_dpp)
|
||
# 加载 __elem_size__ (偏移 32, index 4)
|
||
g_idx4: llvmlite.Value* = llvmlite.const_int64(pool, 4)
|
||
g_epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4)
|
||
if g_epp is None:
|
||
return None
|
||
g_esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, g_epp)
|
||
if g_data is None or g_esize is None:
|
||
return None
|
||
g_idx_i64: llvmlite.Value* = self.coerce_to_type(builder, idx_val, i64_ty, node)
|
||
if g_idx_i64 is None:
|
||
return None
|
||
g_offset: llvmlite.Value* = llvmlite.build_mul(builder, g_idx_i64, g_esize)
|
||
if g_offset is None:
|
||
return None
|
||
# 返回元素地址 (i8*),不 load
|
||
return llvmlite.build_gep(builder, i8_ty, g_data, g_offset)
|
||
# ============================================================
|
||
# _list_elem_type_from_name — 从 list 类型名提取元素 LLVM 类型
|
||
#
|
||
# 类型名格式: <sha1>.list[<elem_type>]
|
||
# 用 strstr 检查完整模式,避免子串提取
|
||
# 支持: list[int]→i32, list[str]/list[bytes]→i8*, list[CInt]→i32 等
|
||
# 默认: i32
|
||
# ============================================================
|
||
def _list_elem_type_from_name(self, pool: memhub.MemBuddy*,
|
||
struct_name: str) -> llvmlite.LLVMType*:
|
||
"""从 list 类型名提取元素 LLVM 类型"""
|
||
if pool is None or struct_name is None:
|
||
return None
|
||
# 用 strstr 检查完整模式
|
||
if string.strstr(struct_name, "list[int]") is not None:
|
||
return llvmlite.Int32(pool)
|
||
if string.strstr(struct_name, "list[CInt]") is not None:
|
||
return llvmlite.Int32(pool)
|
||
if string.strstr(struct_name, "list[CInt8T]") is not None:
|
||
return llvmlite.Int8(pool)
|
||
if string.strstr(struct_name, "list[CInt16T]") is not None:
|
||
return llvmlite.Int16(pool)
|
||
if string.strstr(struct_name, "list[CInt32T]") is not None:
|
||
return llvmlite.Int32(pool)
|
||
if string.strstr(struct_name, "list[CInt64T]") is not None:
|
||
return llvmlite.Int64(pool)
|
||
if string.strstr(struct_name, "list[CSizeT]") is not None:
|
||
return llvmlite.Int64(pool)
|
||
if string.strstr(struct_name, "list[CDouble]") is not None:
|
||
return llvmlite.Double(pool)
|
||
if string.strstr(struct_name, "list[CFloat]") is not None:
|
||
return llvmlite.Float(pool)
|
||
if string.strstr(struct_name, "list[CChar]") is not None:
|
||
return llvmlite.Int8(pool)
|
||
# str/bytes/CPtr 等已知指针元素类型 → i8*(元素存储为 8 字节地址)
|
||
i8_ty_d: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
if string.strstr(struct_name, "list[str]") is not None:
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
if string.strstr(struct_name, "list[bytes]") is not None:
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
if string.strstr(struct_name, "list[CPtr]") is not None:
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
# 未知 list[T] 元素类型(自定义结构体元素,如
|
||
# list[rawptr[7565e081d88517ac.AST]] / list[sha1.Foo|t.CPtr]):
|
||
# 元素槽存对象指针(8 字节)。从元素类型文本还原对象指针 LLVM 类型
|
||
# Ptr(%Struct),使 list.get/__getitem__/pop 内联返回值的 LLVM 类型
|
||
# 携带元素原型类——链式方法调用(mod.children.get(0).kind())的接收者
|
||
# 才能经 LLVM 类型解析出类名 AST(T29 修复);否则统一 Ptr(i8) 丢失
|
||
# 类名,.kind() 被当未绑定外部函数(AstTest NewAstTest fatal: 'kind'
|
||
# 根因:list 元素类名没有沿 get(0) 调用结果值类型传播到后续分派)。
|
||
elem_obj_ty_l: llvmlite.LLVMType* = \
|
||
self._list_elem_obj_ty_from_struct_name(pool, struct_name)
|
||
if elem_obj_ty_l is not None:
|
||
return elem_obj_ty_l
|
||
# 结构体未注册(依赖模块未就绪等):回退 Ptr(i8)(8 字节槽位宽一致,
|
||
# load 值正确),由 AnnotClassName/方法分派回退机制保证语义。
|
||
# 禁止 fail-fast(误杀合法自定义类元素列表的访问)。
|
||
return llvmlite.Ptr(pool, i8_ty_d)
|
||
# ============================================================
|
||
# _list_elem_obj_ty_from_struct_name — 从 list 特化类型名还原元素对象指针类型
|
||
#
|
||
# struct_name 形如 "{_list_sha1}.list[rawptr[{sha1}.AST]]" 或
|
||
# "{_list_sha1}.list[{sha1}.AST|t.CPtr]"(联合元素)。取 '[' 与最后 ']'
|
||
# 之间的元素描述文本:剥 rawptr[...] 包装、按 '|' 联合分段、去首尾空白,
|
||
# 逐段按已注册结构体还原(元素类带模块 SHA1 前缀时 find_struct 走
|
||
# find_struct_by_module 精确匹配,规避跨模块同名歧义);命中返回
|
||
# llvmlite.Ptr(entry.Ty)(list 元素槽 8 字节存对象指针)。全部未命中
|
||
# 返回 None(调用方回退 Ptr(i8) 旧行为,不影响已支持的内置元素)。
|
||
# ============================================================
|
||
def _list_elem_obj_ty_from_struct_name(self, pool: memhub.MemBuddy*,
|
||
struct_name: str) -> llvmlite.LLVMType*:
|
||
"""从 list 特化类型名还原元素对象指针 LLVM 类型,失败返回 None"""
|
||
if pool is None or struct_name is None:
|
||
return None
|
||
lb_e: str = string.strchr(struct_name, '[')
|
||
if lb_e is None:
|
||
return None
|
||
rb_e: str = string.strrchr(struct_name, ']')
|
||
if rb_e is None:
|
||
return None
|
||
elen_e: sizet = sizet(uint64(rb_e) - uint64(lb_e)) - 1
|
||
if elen_e == 0 or elen_e > 512:
|
||
return None
|
||
elem_buf_e: str = pool.alloc(elen_e + 1)
|
||
if elem_buf_e is None:
|
||
return None
|
||
string.strncpy(elem_buf_e, lb_e + 1, elen_e)
|
||
elem_buf_e[elen_e] = '\0'
|
||
# 剥 rawptr[...] 包装(元素声明为对象指针,如 rawptr[sha1.AST])
|
||
cur_e: str = elem_buf_e
|
||
if string.strncmp(cur_e, "rawptr[", 7) == 0:
|
||
cur_e = cur_e + 7
|
||
# 按 '|' 联合分段(A|B),段内去首尾空白/尾部 ']'/引号;段文本直接
|
||
# 交给 find_struct(内置名 CPtr/str/int 等不注册 struct → 天然返回
|
||
# None 跳过;带 "sha1.Class" 前缀走模块归属精确匹配)
|
||
total_e: sizet = string.strlen(cur_e)
|
||
seg_s_e: sizet = 0
|
||
i_e: sizet = 0
|
||
while i_e <= total_e:
|
||
hit_e: int = 0
|
||
if i_e == total_e:
|
||
hit_e = 1
|
||
elif cur_e[i_e] == '|':
|
||
hit_e = 1
|
||
if hit_e == 0:
|
||
i_e += 1
|
||
continue
|
||
b_e: sizet = i_e
|
||
a_e: sizet = seg_s_e
|
||
# 尾部另需剥 '*':实参归一后元素文本是 `T*` 形(如 "{sha}.AST*",
|
||
# 见 TypeGenResolve._norm_type_arg_name 的指针书写归一),而
|
||
# find_struct 只认类名本身;不剥则对象元素还原失败、静默退回 Ptr(i8)
|
||
# 丢元素类名(链式 .get(0).kind() 分派回退根因)。
|
||
while b_e > a_e and (cur_e[b_e - 1] == ' ' or cur_e[b_e - 1] == ']' \
|
||
or cur_e[b_e - 1] == '\'' or cur_e[b_e - 1] == '"' \
|
||
or cur_e[b_e - 1] == '*'):
|
||
b_e -= 1
|
||
while a_e < b_e and (cur_e[a_e] == ' ' or cur_e[a_e] == '\'' \
|
||
or cur_e[a_e] == '"'):
|
||
a_e += 1
|
||
if b_e > a_e:
|
||
seg_len_e: sizet = b_e - a_e
|
||
if seg_len_e < 256:
|
||
seg_buf_e: str = pool.alloc(seg_len_e + 1)
|
||
if seg_buf_e is not None:
|
||
string.strncpy(seg_buf_e, cur_e + a_e, seg_len_e)
|
||
seg_buf_e[seg_len_e] = '\0'
|
||
s_entry_e: GenTypes.StructEntry* = \
|
||
self.Gen.StructGen.find_struct(seg_buf_e)
|
||
if s_entry_e is not None and s_entry_e.Ty is not None:
|
||
return llvmlite.Ptr(pool, s_entry_e.Ty)
|
||
if i_e == total_e:
|
||
break
|
||
seg_s_e = i_e + 1
|
||
i_e += 1
|
||
return None
|
||
# ============================================================
|
||
# list_setitem_inline — 内联生成 list[T] __setitem__ 逻辑
|
||
#
|
||
# 直接存储 rhs_val 到元素地址 (coerce 为 i8* 后 store)
|
||
# ============================================================
|
||
def list_setitem_inline(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
lm_obj: llvmlite.Value*,
|
||
idx_val: llvmlite.Value*,
|
||
rhs_val: llvmlite.Value*,
|
||
node: ast.AST* = None) -> int:
|
||
"""内联生成 list __setitem__ 逻辑,返回 0"""
|
||
if builder is None or pool is None or lm_obj is None or idx_val is None or rhs_val is None:
|
||
return 0
|
||
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
|
||
# 加载 __data__ (偏移 0, index 0)
|
||
s_idx0: llvmlite.Value* = llvmlite.const_int64(pool, 0)
|
||
s_dpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0)
|
||
if s_dpp is None:
|
||
return 0
|
||
s_data: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, s_dpp)
|
||
# 加载 __elem_size__ (偏移 32, index 4)
|
||
s_idx4: llvmlite.Value* = llvmlite.const_int64(pool, 4)
|
||
s_epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4)
|
||
if s_epp is None:
|
||
return 0
|
||
s_esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, s_epp)
|
||
if s_data is None or s_esize is None:
|
||
return 0
|
||
s_idx_i64: llvmlite.Value* = self.coerce_to_type(builder, idx_val, i64_ty, node)
|
||
if s_idx_i64 is None:
|
||
return 0
|
||
s_offset: llvmlite.Value* = llvmlite.build_mul(builder, s_idx_i64, s_esize)
|
||
if s_offset is None:
|
||
return 0
|
||
s_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s_data, s_offset)
|
||
if s_addr is None:
|
||
return 0
|
||
# 元素类型 T:从 list 特化类型名解析(list[int]→i32、list[str]→i8*)。
|
||
# 此前固定 i8*(8 字节)store(inttoptr 值)覆盖相邻元素——与
|
||
# CallGenMixin list 内置分支同根因(ListTest pop FAILED expect 30)。
|
||
s_sty: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(lm_obj)
|
||
s_name: str = None
|
||
if s_sty is not None:
|
||
s_name = llvmlite.get_struct_name(s_sty)
|
||
s_elem_ty: llvmlite.LLVMType* = None
|
||
if s_name is not None:
|
||
s_elem_ty = self._list_elem_type_from_name(pool, s_name)
|
||
if s_elem_ty is None:
|
||
s_elem_ty = i8_ptr_ty
|
||
s_val_ptr: llvmlite.Value* = self.coerce_to_type(builder, rhs_val, s_elem_ty, node)
|
||
if s_val_ptr is None:
|
||
return 0
|
||
s_ep: llvmlite.Value* = llvmlite.build_bitcast(builder, s_addr, llvmlite.Ptr(pool, s_elem_ty))
|
||
if s_ep is not None:
|
||
llvmlite.build_store(builder, s_val_ptr, s_ep)
|
||
return 0
|
||
# ============================================================
|
||
# is_list_subscript — 检查 Subscript 节点是否是 list[T] 类型
|
||
#
|
||
# 返回 list 对象指针 (Ptr(list[T])) 或 None
|
||
# ============================================================
|
||
def is_list_subscript(self, node: ast.AST*,
|
||
trans: HT.Translator*) -> llvmlite.Value*:
|
||
"""检查 Subscript 节点是否是 list[T] 类型,返回 list 对象指针或 None"""
|
||
if node is None or trans is None:
|
||
return None
|
||
sub: ast.Subscript* = ast.Subscript*(node)
|
||
if sub is None or sub.value is None:
|
||
return None
|
||
if sub.value.kind() != ast.ASTKind.Name:
|
||
return None
|
||
nm: ast.Name* = ast.Name*(sub.value)
|
||
if nm is None or nm.id is None:
|
||
return None
|
||
alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is None or alloca.Ty is None:
|
||
return None
|
||
if self.is_ptr_type(alloca.Ty) == 0:
|
||
return None
|
||
pointee: llvmlite.LLVMType* = alloca.Ty.Pointee
|
||
if pointee is None:
|
||
return None
|
||
# 检查 pointee 是否是 Ptr(Struct)
|
||
inner_ty: llvmlite.LLVMType* = None
|
||
match pointee:
|
||
case llvmlite.LLVMType.Ptr(it):
|
||
inner_ty = it
|
||
case _:
|
||
return None
|
||
if inner_ty is None:
|
||
return None
|
||
# 检查 inner_ty 是否是 Struct 且名称包含 "list["
|
||
struct_name: str = None
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, sname):
|
||
struct_name = sname
|
||
case _:
|
||
return None
|
||
if struct_name is None:
|
||
return None
|
||
if string.strstr(struct_name, "list[") is None:
|
||
return None
|
||
# 是 list 类型: load 出 list 对象指针
|
||
builder: llvmlite.IRBuilder* = trans._cur_builder
|
||
return llvmlite.build_load(builder, pointee, alloca)
|
||
# _nonlocal_subscript_ptr:nonlocal 数组/指针的下标元素指针——嵌套(提升)函数体内访问 nonlocal 变量时,其实际存储是运行时共享堆(env[ni] 存堆地址),不能 lookup_var 找外层函数 alloca(其 SSA 编号属外层函数,当前函数引用会错乱崩溃)。正确路径:从 env 读堆地址(_load_raw_var_ptr)→ bitcast → GEP
|
||
def _nonlocal_subscript_ptr(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
trans: HT.Translator*,
|
||
nm_id: str,
|
||
idx_val: llvmlite.Value*) -> llvmlite.Value*:
|
||
"""nonlocal 数组/指针下标:从 env 读堆地址 → bitcast → GEP,返回元素指针"""
|
||
if trans is None or nm_id is None or idx_val is None:
|
||
return None
|
||
nl_ty: llvmlite.LLVMType* = GenApi.get_nonlocal_type(trans, nm_id)
|
||
if nl_ty is None:
|
||
return None
|
||
raw_nl: llvmlite.Value* = self.Gen.StmtGenDecl._load_raw_var_ptr(trans, nm_id)
|
||
if raw_nl is None:
|
||
return None
|
||
match nl_ty:
|
||
case llvmlite.LLVMType.Array(elem_ty_nl, _cnt_nl):
|
||
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))
|
||
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
|
||
return llvmlite.build_gep(builder, inner_nl, arr_ptr_nl2, idx_val)
|
||
case _:
|
||
arr_ptr_nl3: llvmlite.Value* = llvmlite.build_bitcast(builder, raw_nl, llvmlite.Ptr(pool, nl_ty))
|
||
if arr_ptr_nl3 is None: return None
|
||
return llvmlite.build_gep(builder, nl_ty, arr_ptr_nl3, idx_val)
|
||
return None
|
||
# ============================================================
|
||
# 翻译下标表达式 Subscript(value, slice, ctx) — ptr[i] / arr[i]
|
||
#
|
||
# 指针遍历: ptr 是指针变量,load 出指针值后 GEP + load
|
||
# 数组遍历: arr 是数组变量,用 alloca 指针做双索引 GEP [0, i] + load
|
||
# list[T]: 泛型类不注册 struct,subscript 走 __getitem__ 内联路径
|
||
# ============================================================
|
||
def translate_subscript(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
node: ast.AST*,
|
||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||
"""翻译下标表达式,返回加载的元素值"""
|
||
if node is None or builder is None:
|
||
return None
|
||
sub: ast.Subscript* = ast.Subscript*(node)
|
||
if sub is None:
|
||
return None
|
||
|
||
# 切片形式 a[start:end](如 path[n:]):返回 i8* 基指针 + start 偏移。
|
||
# 此前 Slice AST 被当作单索引 translate_value → 无 Slice 分支返回 None →
|
||
# 作为函数实参时整个参数被丢弃(spawn_elf 的
|
||
# create_process(path[n:], entry) 丢 name → entry 错位成第一参数 →
|
||
# p.entry 垃圾 → 用户进程 iretq 到垃圾地址 → PF)。
|
||
if sub.slice is not None and sub.slice.kind() == ast.ASTKind.Slice:
|
||
slc: rawptr[ast.Slice] = rawptr[ast.Slice](sub.slice)
|
||
base_v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.value, None, 0, trans)
|
||
if base_v is None: return None
|
||
if slc.lower is None: return base_v
|
||
start_v: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, slc.lower, None, 0, trans)
|
||
if start_v is None: return None
|
||
i64_sc: llvmlite.LLVMType* = llvmlite.Int64(pool)
|
||
start_w: llvmlite.Value* = start_v
|
||
if start_v.Ty is not None:
|
||
bt_sc: int = self.Gen.ExprGenBase.get_llvm_type_bits(start_v.Ty)
|
||
if bt_sc != 0 and bt_sc < 64:
|
||
start_w = llvmlite.build_sext(builder, start_v, i64_sc)
|
||
if start_w is None:
|
||
return None
|
||
i8_sc: llvmlite.LLVMType* = llvmlite.Int8(pool)
|
||
return llvmlite.build_gep(builder, i8_sc, base_v, start_w)
|
||
|
||
# 翻译索引
|
||
idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.slice, None, 0, trans)
|
||
if idx_val is None: return None
|
||
|
||
# 嵌套下标读取: a[i][j] —— 递归取内层指针后 load
|
||
# (与 get_subscript_ptr 嵌套分支对称;如 gfx.vp 的
|
||
# a.m[i][k] * b.m[k][j],内层 translate_value 会把行加载为
|
||
# Array 值(非指针)→ 通用路径失败 → "rhs 翻译失败")
|
||
if sub.value is not None and sub.value.kind() == ast.ASTKind.Subscript:
|
||
inner_ptr_r: llvmlite.Value* = self.get_subscript_ptr(builder, pool, mod, sub.value, trans)
|
||
if inner_ptr_r is None or inner_ptr_r.Ty is None: return None
|
||
inner_elem_r: llvmlite.LLVMType* = inner_ptr_r.Ty.Pointee
|
||
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))
|
||
if elem_ptr_r is not None:
|
||
return llvmlite.build_load(builder, arr_ie_r, elem_ptr_r)
|
||
return None
|
||
case _:
|
||
elem_ptr_r2: llvmlite.Value* = llvmlite.build_gep(builder, inner_elem_r, inner_ptr_r, idx_val)
|
||
if elem_ptr_r2 is not None:
|
||
return llvmlite.build_load(builder, inner_elem_r, elem_ptr_r2)
|
||
return None
|
||
|
||
# 如果 value 是 Name,尝试从 alloca 类型推断
|
||
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(sub.value)
|
||
if nm.id is not None and trans is not None:
|
||
# rawptr[t.CVolatile | T] 变量(volatile 指针指向物):本分支内
|
||
# 的**元素 load**(p[i] 解引用)带 volatile;仅读取指针值自身的
|
||
# load(alloca → 指针值)不带(那是指针变量而非所指物)。
|
||
vol_sub_rd: int = self.Gen.VarGen.var_pointee_is_volatile(self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id))
|
||
# nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能
|
||
# lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃)
|
||
# 读路径:元素指针 load 出元素值
|
||
if GenApi.is_nonlocal_name(trans, nm.id) != 0:
|
||
nl_ptr_r: llvmlite.Value* = self._nonlocal_subscript_ptr(builder, pool, trans, nm.id, idx_val)
|
||
if nl_ptr_r is not None and nl_ptr_r.Ty is not None:
|
||
nl_elem_ty: llvmlite.LLVMType* = nl_ptr_r.Ty.Pointee
|
||
if nl_elem_ty is not None:
|
||
return llvmlite.build_load(builder, nl_elem_ty, nl_ptr_r)
|
||
return None
|
||
alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is not None and alloca.Ty is not None:
|
||
if self.is_ptr_type(alloca.Ty) != 0:
|
||
pointee: llvmlite.LLVMType* = alloca.Ty.Pointee
|
||
if pointee is not None:
|
||
# 不调用 pointee.kind() 避免跨模块引用 LLVMType.kind 符号
|
||
# 用 match 检查 pointee 类型
|
||
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))
|
||
if elem_ptr is not None:
|
||
return llvmlite.build_load(builder, elem_ty, elem_ptr)
|
||
return None
|
||
case llvmlite.LLVMType.Struct(_fs_v, _fc_v, lsn_v):
|
||
# list[T] 值变量(无注解赋值 rhs 返回 list 值,
|
||
# 如 parts = s1.split(','):split 的 define 返回
|
||
# %list[str] 结构体值,alloca 直接存 list 对象)。
|
||
# alloca 即 list*,直接走 list 内联 __getitem__
|
||
#(对齐 Ptr(Ptr(list)) 变量路径,修复 parts[0] 崩溃)
|
||
if lsn_v is not None:
|
||
if string.strstr(lsn_v, "list[") is not None:
|
||
elem_addr_v: llvmlite.Value* = self.list_getitem_inline(builder, pool, alloca, idx_val, node)
|
||
if elem_addr_v is not None:
|
||
elem_ty_v: llvmlite.LLVMType* = self._list_elem_type_from_name(pool, lsn_v)
|
||
if elem_ty_v is not None:
|
||
elem_ptr_ty_v: llvmlite.LLVMType* = llvmlite.Ptr(pool, elem_ty_v)
|
||
casted_v: llvmlite.Value* = \
|
||
llvmlite.build_bitcast(builder, elem_addr_v, elem_ptr_ty_v)
|
||
if casted_v is not None:
|
||
return llvmlite.build_load(builder, elem_ty_v, casted_v)
|
||
return None
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
# 检查 inner_ty 是否是 list[T] 类型(泛型类不注册 struct)
|
||
# list 的 subscript 应该走 __getitem__ 内联路径,而非指针遍历
|
||
list_struct_name: str = None
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, lsn):
|
||
list_struct_name = lsn
|
||
case _:
|
||
pass
|
||
if list_struct_name is not None:
|
||
if string.strstr(list_struct_name, "list[") is not None:
|
||
# list[T] 类型: 内联生成 __getitem__ 逻辑
|
||
ptr_val_list: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_list is not None:
|
||
elem_addr_list: llvmlite.Value* = self.list_getitem_inline(builder, pool, ptr_val_list, idx_val, node)
|
||
if elem_addr_list is not None:
|
||
# 根据类型名提取元素类型,bitcast 后 load
|
||
elem_ty_list: llvmlite.LLVMType* = self._list_elem_type_from_name(pool, list_struct_name)
|
||
if elem_ty_list is not None:
|
||
elem_ptr_ty_list: llvmlite.LLVMType* = llvmlite.Ptr(pool, elem_ty_list)
|
||
casted_addr_list: llvmlite.Value* = llvmlite.build_bitcast(builder, elem_addr_list, elem_ptr_ty_list)
|
||
if casted_addr_list is not None:
|
||
return llvmlite.build_load(builder, elem_ty_list, casted_addr_list)
|
||
return None
|
||
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针 Ptr(Ptr(Ptr(...))),
|
||
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
|
||
# 此时 [i] 应该是指针解引用 (步长 sizeof(ptr)=8), 而非调用
|
||
# 结构体的 __getitem__ 方法 (会错误生成 AST.__getitem__ 调用)。
|
||
# 对比 HashTable|t.CPtr: alloca.Ty=HashTable**, inner_ty=Struct(HashTable)
|
||
# (非 Ptr), 仍走下面的方法调用转发路径。
|
||
if self.is_ptr_type(inner_ty) != 0:
|
||
ptr_val_pp: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_pp is not None:
|
||
elem_ptr_pp: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val_pp, idx_val)
|
||
if elem_ptr_pp is not None:
|
||
# volatile 指针指向物:解引用 load 带 volatile
|
||
return llvmlite.build_load(builder, inner_ty, elem_ptr_pp, vol_sub_rd)
|
||
return None
|
||
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
|
||
# 仅当类定义了 __getitem__(当前模块定义或跨模块 stub declare 注入)
|
||
# 才转发方法调用;否则普通结构体指针按下标做 GEP 数组访问
|
||
# (对齐 TPC _HandleSubscriptLlvm: if ClassName and has_function(__getitem__))
|
||
cls_nm_rd_ptr: str = self._get_custom_struct_cls_nm(pool, inner_ty)
|
||
if not (cls_nm_rd_ptr is None):
|
||
gi_lookup_rd: str = pool.alloc(128)
|
||
if gi_lookup_rd is not None:
|
||
viperlib.snprintf(gi_lookup_rd, 128, "%s.__getitem__", cls_nm_rd_ptr)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_rd) is not None:
|
||
obj_ptr_rd: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if not (obj_ptr_rd is None):
|
||
arg_vals_rd_p: sizet* = pool.alloc(8)
|
||
if not (arg_vals_rd_p is None):
|
||
arg_vals_rd_p[0] = sizet(idx_val)
|
||
ret_rd_p: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, cls_nm_rd_ptr, "__getitem__", obj_ptr_rd, arg_vals_rd_p, 1, trans, sub)
|
||
if not (ret_rd_p is None):
|
||
return ret_rd_p
|
||
# 无 __getitem__:结构体指针数组访问(GEP + load)
|
||
ptr_val_rd_g: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_rd_g is not None:
|
||
elem_rd_g: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val_rd_g, idx_val)
|
||
if elem_rd_g is not None:
|
||
# volatile 指针指向物:解引用 load 带 volatile
|
||
return llvmlite.build_load(builder, inner_ty, elem_rd_g, vol_sub_rd)
|
||
return None
|
||
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
|
||
# 直接 GEP 按 i8* 步长(8 字节),load i8*
|
||
# 仅当 inner_ty 不是自定义结构体时才走指针遍历
|
||
if trans is not None:
|
||
ve_pe_ts: GenTypes.VarEntry* = \
|
||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||
if self.Gen.VarGen.var_is_ptr_element(ve_pe_ts) != 0:
|
||
# bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值(i8*),
|
||
# elem[i] 语义 = load [指针值 + i*8](8 字节指针元素)。
|
||
# 必须先 load alloca 得指针值,再 GEP i8*(步长 8)——
|
||
# 否则 GEP base 用 alloca(&elem_ptr)读到栈变量而非数据区,
|
||
# list.get 返回"元素地址"而非"元素值"(dump 虚调用读错 vtable)。
|
||
ptr_val_pe_ts: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_pe_ts is not None:
|
||
elem_ptr_ts: llvmlite.Value* = llvmlite.build_gep(builder, pointee, ptr_val_pe_ts, idx_val)
|
||
if elem_ptr_ts is not None:
|
||
# volatile 指针指向物:解引用 load 带 volatile
|
||
return llvmlite.build_load(builder, pointee, elem_ptr_ts, vol_sub_rd)
|
||
return None
|
||
# 普通指针遍历: 先 load 指针值,再 GEP
|
||
ptr_val: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val is not None:
|
||
elem_ptr2: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val, idx_val)
|
||
if elem_ptr2 is not None:
|
||
# volatile 指针指向物:解引用 load 带 volatile
|
||
return llvmlite.build_load(builder, inner_ty, elem_ptr2, vol_sub_rd)
|
||
return None
|
||
case _:
|
||
# 联合类型变量(IsPtrElement=1,如 _list.vp 的
|
||
# elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但
|
||
# 元素是 8 字节指针,须按 i8* 步长 GEP + load i8*——
|
||
# 否则 list.get 只读 1 字节,指针截断 inttoptr 崩溃。
|
||
if trans is not None:
|
||
ve_pe_rd: GenTypes.VarEntry* = \
|
||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||
if self.Gen.VarGen.var_is_ptr_element(ve_pe_rd) != 0:
|
||
match pointee:
|
||
case llvmlite.LLVMType.Int(bits_rd):
|
||
if bits_rd == 8:
|
||
i8_ptr_rd: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
elem_ptr_rd: llvmlite.Value* = llvmlite.build_gep(builder, i8_ptr_rd, alloca, idx_val)
|
||
if elem_ptr_rd is not None:
|
||
return llvmlite.build_load(builder, i8_ptr_rd, elem_ptr_rd)
|
||
case _:
|
||
pass
|
||
# 自定义类(结构体类型): 仅当类定义了 __getitem__
|
||
# (当前模块定义或跨模块 stub declare 注入)才转发方法调用;
|
||
# 否则普通结构体指针按下标做 GEP 数组访问
|
||
cls_nm_sub: str = self.Gen.StructGen.get_class_name_by_type(pool, pointee)
|
||
if not (cls_nm_sub is None):
|
||
gi_lookup_sub: str = pool.alloc(128)
|
||
if gi_lookup_sub is not None:
|
||
viperlib.snprintf(gi_lookup_sub, 128, "%s.__getitem__", cls_nm_sub)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_sub) is not None:
|
||
obj_val_sub: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if not (obj_val_sub is None):
|
||
arg_vals_sub: sizet* = pool.alloc(8)
|
||
if not (arg_vals_sub is None):
|
||
arg_vals_sub[0] = sizet(idx_val)
|
||
ret_sub: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, cls_nm_sub, "__getitem__", obj_val_sub, arg_vals_sub, 1, trans, sub)
|
||
if not (ret_sub is None):
|
||
return ret_sub
|
||
# 无 __getitem__:结构体指针数组访问(GEP + load)
|
||
ptr_val_sub_g: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_sub_g is not None:
|
||
elem_sub_g: llvmlite.Value* = llvmlite.build_gep(builder, pointee, ptr_val_sub_g, idx_val)
|
||
if elem_sub_g is not None:
|
||
# volatile 指针指向物:解引用 load 带 volatile
|
||
return llvmlite.build_load(builder, pointee, elem_sub_g, vol_sub_rd)
|
||
return None
|
||
pass
|
||
|
||
# 通用路径:翻译 value 获取指针
|
||
ptr_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.value, None, 0, trans)
|
||
if ptr_val is None or ptr_val.Ty is None:
|
||
return None
|
||
|
||
# 检查是否是指针类型
|
||
if self.is_ptr_type(ptr_val.Ty) != 0:
|
||
# 通用路径基址(如 self.ptr / 复杂表达式):仅当基址可解析到
|
||
# VarEntry/FieldEntry 且其为 rawptr[t.CVolatile|T] 时,元素 load 带 volatile;
|
||
# 其余基址解析返回 0(明确不支持,见限制清单)。守卫为 0 时文本不变。
|
||
vol_sub_gen: int = self.Gen.ExprGenAttr.base_pointee_is_volatile(pool, trans, sub.value)
|
||
elem_ty2: llvmlite.LLVMType* = ptr_val.Ty.Pointee
|
||
if elem_ty2 is not None:
|
||
# 数组类型: 双索引 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))
|
||
if elem_ptr3 is not None:
|
||
return llvmlite.build_load(builder, arr_elem_ty2, elem_ptr3, vol_sub_gen)
|
||
return None
|
||
case _:
|
||
pass
|
||
# 64-bit scalar pointer fields (e.g. `sizet*`, `uint64*`, written as
|
||
# `t.CUInt64T | t.CPtr`) keep the declared element type here: the slot is
|
||
# a u64, so it is read as i64 -- same element type the write path uses
|
||
# (see get_subscript_ptr). Loading it as i8* fabricated a pointer value
|
||
# out of an integer slot and forced the caller through an implicit
|
||
# ptrtoint / inttoptr, which the language forbids (it also made
|
||
# `MemBuddy.free_lists[i]` mis-type its element). Sources that store or
|
||
# read a pointer through such a slot must cast explicitly.
|
||
# 自定义结构体 (如 self._ht[key]): 仅当类定义了 __getitem__ 才转发方法调用;
|
||
# 否则普通结构体指针按下标做 GEP 数组访问
|
||
cls_nm_rd_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2)
|
||
if not (cls_nm_rd_gen is None):
|
||
gi_lookup_gen: str = pool.alloc(128)
|
||
if gi_lookup_gen is not None:
|
||
viperlib.snprintf(gi_lookup_gen, 128, "%s.__getitem__", cls_nm_rd_gen)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, gi_lookup_gen) is not None:
|
||
arg_vals_rd_g: sizet* = pool.alloc(8)
|
||
if not (arg_vals_rd_g is None):
|
||
arg_vals_rd_g[0] = sizet(idx_val)
|
||
ret_rd_g: llvmlite.Value* = self.Gen.CallGenCall._call_method_on_ptr(pool, builder, mod, cls_nm_rd_gen, "__getitem__", ptr_val, arg_vals_rd_g, 1, trans, sub)
|
||
if not (ret_rd_g is None):
|
||
return ret_rd_g
|
||
# 无 __getitem__:结构体指针数组访问(GEP + load)
|
||
elem_ptr_gen: llvmlite.Value* = llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val)
|
||
if elem_ptr_gen is not None:
|
||
return llvmlite.build_load(builder, elem_ty2, elem_ptr_gen, vol_sub_gen)
|
||
return None
|
||
# 指针类型: 单索引 GEP + load
|
||
elem_ptr4: llvmlite.Value* = llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val)
|
||
if elem_ptr4 is not None:
|
||
return llvmlite.build_load(builder, elem_ty2, elem_ptr4, vol_sub_gen)
|
||
return None
|
||
# ============================================================
|
||
# 获取下标表达式的元素指针(不加载值,用于赋值)
|
||
# ============================================================
|
||
def _annot_is_64bit_scalar(self, annot: str) -> int:
|
||
"""注解是否为 64 位标量 | t.CPtr 联合(AnnotClassName 为提取出的
|
||
非 CPtr 侧类型名,如 int64|t.CPtr → "CInt64T")。此类联合的
|
||
8 字节单元格存 i64 标量,下标元素类型应为 Int64 而非指针。"""
|
||
if annot is None: return 0
|
||
if string.strstr(annot, "CInt64T") is not None: return 1
|
||
if string.strstr(annot, "CUInt64T") is not None: return 1
|
||
if string.strstr(annot, "CSizeT") is not None: return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# subscript_base_store_kind - 下标基座的**存储形态**(只读,不生成 IR)
|
||
#
|
||
# 用于区分「数组槽」与「指针所指对象」,只有前者才允许"整对象赋值":
|
||
# 1 = 数组存储:t.CArray[T,N] / 内建 Array 形态。元素槽按 sizeof(T) 布局,
|
||
# `v[i] = <指向 T 的指针>`(如构造函数返回的临时对象地址)是合法的
|
||
# 整对象复制,不拦。
|
||
# 0 = 指针存储:rawptr[T] 形态(基座元素类型是 Ptr(T),T 为对象)。
|
||
# 元素即所指对象,`p[i] = <指向 T 的指针>` 会静默整对象拷贝
|
||
# (写 sizeof(T) 字节而非 8 字节指针)——可能写穿按 8 字节排布的
|
||
# 缓冲/空闲链表,由调用方 fail-fast。
|
||
# -1 = 无法判定(基座不是可静态定型的 Name / 单层 Attribute):不作为判据,
|
||
# 调用方保持既有行为(不误伤,也不新增静默降级)。
|
||
# 分派与 get_subscript_ptr 同源:Name 取变量/全局存储的元素类型,
|
||
# Attribute 取字段类型。
|
||
# ============================================================
|
||
def subscript_base_store_kind(self, pool: memhub.MemBuddy*,
|
||
trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""下标基座存储形态:1=数组 / 0=指针 / -1=无法判定"""
|
||
if node is None or trans is None: return -1
|
||
sub_bk: ast.Subscript* = ast.Subscript*(node)
|
||
if sub_bk is None or sub_bk.value is None: return -1
|
||
base_ty_bk: llvmlite.LLVMType* = None
|
||
if sub_bk.value.kind() == ast.ASTKind.Name:
|
||
nm_bk: ast.Name* = ast.Name*(sub_bk.value)
|
||
if nm_bk.id is None: return -1
|
||
alloca_bk: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm_bk.id)
|
||
if alloca_bk is None:
|
||
alloca_bk = self.Gen.VarGen.lookup_module_var(trans.SymTab, nm_bk.id)
|
||
if alloca_bk is None or alloca_bk.Ty is None: return -1
|
||
if self.is_ptr_type(alloca_bk.Ty) == 0: return -1
|
||
base_ty_bk = alloca_bk.Ty.Pointee
|
||
elif sub_bk.value.kind() == ast.ASTKind.Attribute:
|
||
# 单层 obj.field(如 self.arr):非 fatal 只读解析字段类型
|
||
fe_bk: GenTypes.FieldEntry* = self.Gen.ExprGenAttr._resolve_attr_field_entry(pool, trans, sub_bk.value)
|
||
if fe_bk is None or fe_bk.Ty is None: return -1
|
||
base_ty_bk = fe_bk.Ty
|
||
else:
|
||
return -1
|
||
if base_ty_bk is None: return -1
|
||
# 基座自身是数组值 → 数组存储
|
||
if self.is_array_type(base_ty_bk) != 0: return 1
|
||
if self.is_ptr_type(base_ty_bk) != 0:
|
||
inner_bk: llvmlite.LLVMType* = base_ty_bk.Pointee
|
||
if inner_bk is None: return -1
|
||
# Ptr(Array) → t.CArray[T,N] 局部/字段(数组存储)
|
||
if self.is_array_type(inner_bk) != 0: return 1
|
||
# Ptr(Struct) → rawptr[T](指针存储)
|
||
if inner_bk.kind() == llvmlite.LLVMType.Struct: return 0
|
||
return -1
|
||
|
||
def get_subscript_ptr(self, builder: llvmlite.IRBuilder*,
|
||
pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
node: ast.AST*,
|
||
trans: HT.Translator* = None) -> llvmlite.Value*:
|
||
"""获取下标表达式的元素指针(用于赋值 lhs)"""
|
||
if node is None or builder is None: return None
|
||
sub: ast.Subscript* = ast.Subscript*(node)
|
||
if sub is None: return None
|
||
|
||
# 翻译索引
|
||
idx_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.slice, None, 0, trans)
|
||
if idx_val is None: return None
|
||
|
||
# 嵌套下标: a[i][j] = v —— 递归解析内层下标指针后 GEP
|
||
# (如 gfx.vp Mat4.m: t.CArray[t.CArray[float, 4], 4] 的 m.m[0][0] = 1;
|
||
# 外层 Subscript 的 value 是内层 Subscript,通用路径 translate_value
|
||
# 会把内层元素加载为值(Array 类型)→ is_ptr_type 失败 → 返回 None →
|
||
# "subscript ptr is None" fail-fast。递归取内层指针再 GEP 根治。)
|
||
if sub.value is not None and sub.value.kind() == ast.ASTKind.Subscript:
|
||
inner_ptr: llvmlite.Value* = self.get_subscript_ptr(builder, pool, mod, sub.value, trans)
|
||
if inner_ptr is None or inner_ptr.Ty is None: return None
|
||
inner_elem: llvmlite.LLVMType* = inner_ptr.Ty.Pointee
|
||
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))
|
||
case _:
|
||
return llvmlite.build_gep(builder, inner_elem, inner_ptr, idx_val)
|
||
|
||
# 如果 value 是 Name,尝试从 alloca 类型推断
|
||
if sub.value is not None and sub.value.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(sub.value)
|
||
if nm.id is not None and trans is not None:
|
||
# nonlocal 数组/指针:从 env 读共享堆地址(提升函数内不能
|
||
# lookup_var 外层 alloca——SSA 编号跨函数错乱崩溃)
|
||
if GenApi.is_nonlocal_name(trans, nm.id) != 0:
|
||
return self._nonlocal_subscript_ptr(builder, pool, trans, nm.id, idx_val)
|
||
alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is not None and alloca.Ty is not None:
|
||
if self.is_ptr_type(alloca.Ty) != 0:
|
||
pointee: llvmlite.LLVMType* = alloca.Ty.Pointee
|
||
if pointee is not None:
|
||
# 用 match 检查 pointee 类型
|
||
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))
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
# inner_ty 是 Ptr 说明 alloca.Ty 是三重指针,
|
||
# 即 X|t.CPtr 当 X 本身是指针类型 (如 T=AST|t.CPtr, T|t.CPtr=AST**)。
|
||
# 此时 [i]=val 应该是指针解引用赋值, 而非调用 __setitem__。
|
||
if self.is_ptr_type(inner_ty) != 0:
|
||
ptr_val_gsp: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_gsp is not None:
|
||
return llvmlite.build_gep(builder, inner_ty, ptr_val_gsp, idx_val)
|
||
return None
|
||
# 自定义结构体 (如 HashTable|t.CPtr, JsonValue|t.CPtr):
|
||
# 仅当类定义了 __setitem__(当前模块定义或跨模块 stub declare 注入)
|
||
# 才返回 None 触发 __setitem__ 重载;否则普通结构体指针按下标
|
||
# 做 GEP 数组访问(走下方指针遍历路径)
|
||
cls_nm_ptr_chk: str = self._get_custom_struct_cls_nm(pool, inner_ty)
|
||
if not (cls_nm_ptr_chk is None):
|
||
si_lookup_gsp: str = pool.alloc(128)
|
||
if si_lookup_gsp is not None:
|
||
viperlib.snprintf(si_lookup_gsp, 128, "%s.__setitem__", cls_nm_ptr_chk)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_gsp) is not None:
|
||
return None
|
||
# bytes|t.CPtr / str|t.CPtr: alloca 是 i8**,
|
||
# 直接 GEP 按 i8* 步长(8 字节),不 load
|
||
# 仅当 inner_ty 不是自定义结构体时才走指针遍历
|
||
if trans is not None:
|
||
ve_pe: GenTypes.VarEntry* = \
|
||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||
if self.Gen.VarGen.var_is_ptr_element(ve_pe) != 0:
|
||
# bytes|t.CPtr / str|t.CPtr / T|t.CPtr:变量存指针值,
|
||
# 下标语义 = [指针值 + i*8](8 字节指针元素)。必须先 load
|
||
# alloca 得指针值,再 GEP——否则 GEP base 用 alloca(&elem_ptr)
|
||
# 读到栈变量而非数据区,赋值写不进 list 数据
|
||
# (data 全 0xbaadf00d,dump 虚调用读错 vtable 崩溃)。
|
||
ptr_val_pe: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_pe is not None:
|
||
# [FIX 2026-08-30] 64 位标量联合(int64|t.CPtr /
|
||
# uint64|t.CPtr / sizet|t.CPtr):8 字节单元格存
|
||
# i64 标量(viperlib %n 的 np[0]=write_count 是解引用写入,
|
||
# 语义 *np=(i64)x)。GEP 元素必须用 Int64(标量)而非指针,
|
||
# 否则元素类型为指针 → i64 存储触发整数隐式转指针
|
||
# fail-fast(把解引用写入误判为 int→ptr)。
|
||
pe_annot: str = self.Gen.VarGen.var_annot_class_name(ve_pe)
|
||
if pe_annot is not None and self._annot_is_64bit_scalar(pe_annot) != 0:
|
||
return llvmlite.build_gep(builder, llvmlite.Int64(pool), ptr_val_pe, idx_val)
|
||
match pointee:
|
||
case llvmlite.LLVMType.Int(bits_pe):
|
||
if bits_pe == 8:
|
||
i8_ptr_pe: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
return llvmlite.build_gep(builder, i8_ptr_pe, ptr_val_pe, idx_val)
|
||
case _:
|
||
pass
|
||
return llvmlite.build_gep(builder, pointee, ptr_val_pe, idx_val)
|
||
return None
|
||
# 普通指针遍历: 先 load 指针值,再 GEP
|
||
ptr_val: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val is None:
|
||
return None
|
||
gep_r: llvmlite.Value* = llvmlite.build_gep(builder, inner_ty, ptr_val, idx_val)
|
||
return gep_r
|
||
case _:
|
||
# pointee 是普通标量类型 (如 i64, i32, i8):
|
||
# alloca 是 Ptr(标量), 直接 GEP 获取第 idx 个元素指针
|
||
# 支持 arg_vals[i] = val 这类参数数组下标赋值
|
||
# 联合类型变量(IsPtrElement=1,如 _list.vp 的
|
||
# elem_ptr: T | t.CPtr 退化为 i8*):pointee=i8 但
|
||
# 元素是 8 字节指针,须按 i8* 步长 GEP(防只写 1 字节截断)
|
||
if trans is not None:
|
||
ve_pe_cs: GenTypes.VarEntry* = \
|
||
self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm.id)
|
||
if self.Gen.VarGen.var_is_ptr_element(ve_pe_cs) != 0:
|
||
# T|t.CPtr(退化为 i8*,如 _list.vp 的 elem_ptr)变量
|
||
# 存数据区指针,元素为 8 字节指针:必须先 load alloca
|
||
# 得指针值,再按 i8* 步长 GEP——否则 GEP base 用 alloca
|
||
# (&elem_ptr)算到栈地址,赋值写不进 list 数据区
|
||
# (append 只增 count、data 全 0xbaadf00d)。
|
||
ptr_val_cs: llvmlite.Value* = llvmlite.build_load(builder, pointee, alloca)
|
||
if ptr_val_cs is not None:
|
||
match pointee:
|
||
case llvmlite.LLVMType.Int(bits_cs):
|
||
if bits_cs == 8:
|
||
i8_ptr_cs: llvmlite.LLVMType* = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
return llvmlite.build_gep(builder, i8_ptr_cs, ptr_val_cs, idx_val)
|
||
case _:
|
||
pass
|
||
return llvmlite.build_gep(builder, pointee, ptr_val_cs, idx_val)
|
||
return None
|
||
return llvmlite.build_gep(builder, pointee, alloca, idx_val)
|
||
|
||
# 通用路径
|
||
ptr_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, sub.value, None, 0, trans)
|
||
if ptr_val is None or ptr_val.Ty is None:
|
||
return None
|
||
if self.is_ptr_type(ptr_val.Ty) != 0:
|
||
elem_ty2: llvmlite.LLVMType* = ptr_val.Ty.Pointee
|
||
if elem_ty2 is not None:
|
||
# 数组类型: 双索引 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))
|
||
case _:
|
||
pass
|
||
# 自定义结构体 (如 self._ht[key]): 仅当类定义了 __setitem__
|
||
# 才返回 None 触发 HandlesAssign 的 __setitem__ 重载;
|
||
# 否则普通结构体指针按下标做 GEP 数组访问
|
||
cls_nm_gen: str = self._get_custom_struct_cls_nm(pool, elem_ty2)
|
||
if not (cls_nm_gen is None):
|
||
si_lookup_gen: str = pool.alloc(128)
|
||
if si_lookup_gen is not None:
|
||
viperlib.snprintf(si_lookup_gen, 128, "%s.__setitem__", cls_nm_gen)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, si_lookup_gen) is not None:
|
||
return None
|
||
# 指针类型: 单索引 GEP (getelementptr ty, ptr, idx)
|
||
return llvmlite.build_gep(builder, elem_ty2, ptr_val, idx_val)
|
||
return None |