- TypeGenMixin 新增 CDefineStrFlags/CDefineIsStr 字段与 register_cdefine_string/lookup_cdefine_string/is_cdefine_str 方法 - AssignGenMixin._register_cdefine_from_value 新增 CONST_STR 分支 - ExprGenMixin.translate_name_value CDefine 本地/跨模块均支持字符串 - Generator.InitGen / HandlesType 委托同步初始化新字段
611 lines
29 KiB
Plaintext
611 lines
29 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesType as HandlesType
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
|
||
|
||
# ============================================================
|
||
# AssignGenMixin - 赋值翻译 Mixin(P6 方法化)
|
||
#
|
||
# 从 HandlesAssign/HandlesAnnAssign/HandlesAugAssign 迁移:
|
||
# 模块级无状态函数(trans/pool 首参)→ 类方法;全局状态
|
||
# (HandlesAnnAssign._g_recover_found)→ 本类字段 RecoverFound。
|
||
#
|
||
# 迁移原则(与 P1-P5 一致,行为零变化):
|
||
# 1. 方法保留原函数签名(含 trans/pool 首参),仅函数体内的
|
||
# 本模块函数调用改为 self.xxx(...)
|
||
# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx 等)保留模块前缀
|
||
# 3. 原 Handles 模块函数保留为"委托":本地模块级单例 _g_gen
|
||
# (BuildPipeline/main 注入)cast 成 Generator 类型
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
@t.NoVTable
|
||
class AssignGenMixin:
|
||
"""赋值翻译 Mixin(P6 方法化)"""
|
||
|
||
# --- 原 HandlesAnnAssign._g_recover_found 模块级全局(迁移为实例字段) ---
|
||
RecoverFound: int
|
||
|
||
# ============================================================
|
||
# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数)
|
||
#
|
||
# 支持两种形式:
|
||
# 1. Attribute(Name('t'), 'CDefine')
|
||
# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解)
|
||
# ============================================================
|
||
def is_cdefine_annotation(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检测注解是否为 t.CDefine,返回 1 表示是,0 表示否"""
|
||
if annot is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||
if at.attr is not None and string.strcmp(at.attr, "CDefine") == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if self.is_cdefine_annotation(bop.left) != 0:
|
||
return 1
|
||
if self.is_cdefine_annotation(bop.right) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
|
||
#
|
||
# 支持的表达式形式:
|
||
# 1. Constant(INT) — 如 0x0002, 42
|
||
# 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN
|
||
# 3. Name — 引用已注册的 CDefine 常量
|
||
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
|
||
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
|
||
# ============================================================
|
||
def extract_cdefine_int_value(self, val_node: ast.AST | t.CPtr) -> int:
|
||
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp)"""
|
||
if val_node is None:
|
||
return 0
|
||
k: int = val_node.kind()
|
||
|
||
# Case 1: Constant(INT) — 如 0x0002
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||
if cn.const_kind != ast.CONST_INT:
|
||
# 非 INT 常量:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
return cn.int_val
|
||
|
||
# Case 2: BinOp — 如 FOREGROUND_RED | FOREGROUND_GREEN
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(val_node)
|
||
left_val: int = self.extract_cdefine_int_value(bop.left)
|
||
right_val: int = self.extract_cdefine_int_value(bop.right)
|
||
if bop.op == ast.OpKind.BitOr:
|
||
return left_val | right_val
|
||
if bop.op == ast.OpKind.BitAnd:
|
||
return left_val & right_val
|
||
if bop.op == ast.OpKind.Add:
|
||
return left_val + right_val
|
||
if bop.op == ast.OpKind.Sub:
|
||
return left_val - right_val
|
||
# 未知 BinOp 运算符:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# Case 3: Name — 引用已注册的 CDefine 常量
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
|
||
if nm.id is not None:
|
||
looked_up: int = HandlesType.lookup_cdefine_constant(nm.id)
|
||
if HandlesType.is_cdefine_found() != 0:
|
||
return looked_up
|
||
# 引用未注册:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# Case 4: Call — 如 t.CUnsignedLong(-11)
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(val_node)
|
||
# 必须先把属性赋给显式类型为 list[...] | t.CPtr 的局部变量再调用 __len__(),
|
||
# 否则编译器无法识别属性返回的 list 类型,GEP base 会变成 i32 0 导致 llc 报错
|
||
cl_args_list: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if cl_args_list is not None and len(cl_args_list) > 0:
|
||
first_arg: ast.AST | t.CPtr = cl_args_list.get(0)
|
||
arg_val: int = self.extract_cdefine_int_value(first_arg)
|
||
return arg_val
|
||
# Call 无参数:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# Case 5: UnaryOp — 如 -11
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(val_node)
|
||
operand_val: int = self.extract_cdefine_int_value(uop.operand)
|
||
if uop.op == ast.OpKind.USub:
|
||
return -operand_val
|
||
if uop.op == ast.OpKind.UAdd:
|
||
return operand_val
|
||
if uop.op == ast.OpKind.Invert:
|
||
return ~operand_val
|
||
# 未知 UnaryOp 运算符:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# 未知节点类型:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(val_node, "CDefine 值提取失败:无法从表达式解析编译期常量", "TypeError")
|
||
|
||
# ============================================================
|
||
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
|
||
#
|
||
# 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走
|
||
# register_cdefine_double,否则 translate_value 查表得 0 生成
|
||
# ret i32 0(llc 报错 "value doesn't match function result type")。
|
||
# ============================================================
|
||
def _register_cdefine_from_value(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str, val_node: ast.AST | t.CPtr) -> None:
|
||
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)"""
|
||
if pool is None or name is None:
|
||
return
|
||
if val_node is not None and val_node.kind() == ast.ASTKind.Constant:
|
||
cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
|
||
if cn_fp.const_kind == ast.CONST_STR:
|
||
# 字符串 CDefine(如 ZLIB_VERSION: t.CDefine = "1.3.2"):
|
||
# 注册为字符串常量,读取端返回 global string(对齐 TPC)。
|
||
HandlesType.register_cdefine_string(pool, name, cn_fp.str_val)
|
||
return
|
||
if cn_fp.const_kind == ast.CONST_FLOAT:
|
||
# 源文件重读恢复(最可靠:AST 节点 float_val 可能被 pool 操作覆写,
|
||
# 源文件文本不受影响;用输出参数绕开跨模块 double 返回值传递 bug)
|
||
use_val: double = cn_fp.float_val
|
||
rec_d: t.CDouble = 0.0
|
||
if self._recover_cdefine_float(name, t.CPtr(c.Addr(rec_d))) != 0:
|
||
use_val = rec_d
|
||
else:
|
||
# 源文件恢复失败:直接报错终止(fail-fast),避免注册被 pool 覆写的错误浮点值
|
||
HandlesType.fatal_error(val_node, "CDefine 浮点值源文件恢复失败", "InternalCompilerError")
|
||
return
|
||
HandlesType.register_cdefine_double(pool, name, use_val)
|
||
return
|
||
if val_node is None:
|
||
# CDefine 声明缺少值节点:直接报错终止(fail-fast)
|
||
HandlesType.fatal_error(None, f"CDefine 值提取失败:'{name}' 缺少初始值", "TypeError")
|
||
return
|
||
val_fp: int = self.extract_cdefine_int_value(val_node)
|
||
HandlesType.register_cdefine_constant(pool, name, val_fp)
|
||
|
||
# ============================================================
|
||
# 源文件重读恢复 CDefine 浮点值
|
||
#
|
||
# 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写
|
||
# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。
|
||
# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value——
|
||
# 源文件文本不受 pool 影响,是最可靠的恢复路径。
|
||
#
|
||
# 原模块级 _g_recover_found 全局已迁移为实例字段 self.RecoverFound。
|
||
# ============================================================
|
||
|
||
def _recover_found(self) -> int:
|
||
"""检查最近一次 _recover_cdefine_float 是否成功"""
|
||
return self.RecoverFound
|
||
|
||
def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int:
|
||
"""从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1
|
||
|
||
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
|
||
"""
|
||
self.RecoverFound = 0
|
||
fp: str = HandlesType.get_current_file()
|
||
if fp is None or name is None or out is None:
|
||
return 0
|
||
f: fileio.File | t.CPtr = fileio.File(fp, fileio.MODE.R)
|
||
if f.closed:
|
||
return 0
|
||
BUF_SZ: t.CSizeT = 1048576
|
||
buf: bytes = stdlib.malloc(BUF_SZ)
|
||
if buf is None:
|
||
f.close()
|
||
return 0
|
||
nrd: LONG = f.read_all(buf, BUF_SZ)
|
||
f.close()
|
||
if nrd <= 0:
|
||
stdlib.free(buf)
|
||
return 0
|
||
if nrd < BUF_SZ:
|
||
buf[nrd] = 0
|
||
else:
|
||
buf[BUF_SZ - 1] = 0
|
||
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
total_len: t.CSizeT = string.strlen(buf)
|
||
pos: t.CSizeT = 0
|
||
while pos < total_len:
|
||
line_start: t.CSizeT = pos
|
||
while pos < total_len and buf[pos] != '\n':
|
||
pos += 1
|
||
line_len: t.CSizeT = pos - line_start
|
||
if pos < total_len:
|
||
pos += 1
|
||
|
||
# 匹配 "name:"
|
||
if line_len < name_len + 1:
|
||
continue
|
||
match_ok: int = 1
|
||
ki: t.CSizeT
|
||
for ki in range(name_len):
|
||
if buf[line_start + ki] != name[ki]:
|
||
match_ok = 0
|
||
break
|
||
if match_ok == 0:
|
||
continue
|
||
if buf[line_start + name_len] != ':':
|
||
continue
|
||
|
||
# 行内包含 "t.CDefine"
|
||
has_cd: int = 0
|
||
ci: t.CSizeT = line_start + name_len + 1
|
||
while ci + 8 <= line_start + line_len:
|
||
if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and
|
||
buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and
|
||
buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'):
|
||
has_cd = 1
|
||
break
|
||
ci += 1
|
||
if has_cd == 0:
|
||
continue
|
||
|
||
# 找 '='
|
||
eq: t.CSizeT = line_start
|
||
while eq < line_start + line_len and buf[eq] != '=':
|
||
eq += 1
|
||
if eq >= line_start + line_len:
|
||
continue
|
||
eq += 1
|
||
while eq < line_start + line_len and buf[eq] == ' ':
|
||
eq += 1
|
||
val_start: t.CSizeT = eq
|
||
while eq < line_start + line_len and buf[eq] != ' ' and buf[eq] != '\t' \
|
||
and buf[eq] != '#' and buf[eq] != '\r' and buf[eq] != '\n':
|
||
eq += 1
|
||
if eq == val_start:
|
||
continue
|
||
|
||
val_txt: str = stdlib.malloc(eq - val_start + 1)
|
||
if val_txt is None:
|
||
stdlib.free(buf)
|
||
return 0
|
||
vi: t.CSizeT
|
||
for vi in range(eq - val_start):
|
||
val_txt[vi] = buf[val_start + vi]
|
||
val_txt[eq - val_start] = 0
|
||
stdlib.free(buf)
|
||
# 用 atof_out(输出参数)绕开跨模块 double 返回值传递 bug
|
||
if string.atof_out(val_txt, out) != 0:
|
||
self.RecoverFound = 1
|
||
return 1
|
||
return 0
|
||
|
||
stdlib.free(buf)
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _annotation_contains_name - 递归检查注解中是否包含指定名称
|
||
#
|
||
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
|
||
# ============================================================
|
||
def _annotation_contains_name(self, annot: ast.AST | t.CPtr, name: str) -> int:
|
||
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含"""
|
||
if annot is None or name is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
|
||
if at.attr is not None and string.strcmp(at.attr, name) == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
|
||
if nm.id is not None and string.strcmp(nm.id, name) == 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if self._annotation_contains_name(bop.left, name) != 0:
|
||
return 1
|
||
if self._annotation_contains_name(bop.right, name) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
|
||
#
|
||
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
|
||
#
|
||
# 规则:
|
||
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
|
||
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0
|
||
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
|
||
#
|
||
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
|
||
# ============================================================
|
||
def _is_ptr_element_annotation(self, annot: ast.AST | t.CPtr) -> int:
|
||
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式"""
|
||
if annot is None:
|
||
return 0
|
||
k: int = annot.kind()
|
||
if k != ast.ASTKind.BinOp:
|
||
return 0
|
||
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
|
||
if bop.op != ast.OpKind.BitOr:
|
||
return 0
|
||
if self._annotation_contains_name(annot, "str") != 0:
|
||
return 1
|
||
if self._annotation_contains_name(annot, "bytes") != 0:
|
||
return 1
|
||
# 泛型类型参数/嵌套联合 | t.CPtr(如 _list.vp 的 elem_ptr: T | t.CPtr):
|
||
# 先经泛型上下文解析 T 的具体类型——纯标量(int/float 等 sizeof≠8)时
|
||
# 元素按标量自身大小(list[int] elem_size=4 匹配 i32),不能按 8 字节
|
||
# 指针槽(否则 8 字节写 / 4 字节步长互相覆盖,pop 读到 0);
|
||
# 指针/嵌套联合/64 位标量/double(sizeof==8)才按 8 字节。
|
||
if self._is_generic_tp_or_nested(bop.left) != 0 or self._is_generic_tp_or_nested(bop.right) != 0:
|
||
gp_nm: str = None
|
||
if bop.left is not None and bop.left.kind() == ast.ASTKind.Name:
|
||
gp_left_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.left)
|
||
gp_nm = gp_left_nm.id
|
||
elif bop.right is not None and bop.right.kind() == ast.ASTKind.Name:
|
||
gp_right_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bop.right)
|
||
gp_nm = gp_right_nm.id
|
||
if gp_nm is not None:
|
||
# 经全局 gen 委托解析泛型参数(T → 具体类型名)。不能 self.GenericTpNames
|
||
# 直读(Mixin @t.NoVTable 静态绑定:字段声明在 TypeGenMixin,AssignGenMixin
|
||
# 访问会生成不存在的属性引用 → TPC fast-fail 编译崩溃)
|
||
gp_resolved: str = HandlesType.resolve_generic_type_name(gp_nm)
|
||
if gp_resolved is not None and string.strcmp(gp_resolved, gp_nm) != 0:
|
||
# 泛型参数解析为纯标量 → 元素按标量自身大小(非 8 字节指针槽)
|
||
if self._is_scalar_ty_name(gp_resolved) != 0:
|
||
return 0
|
||
return 1
|
||
# 64 位标量数值类型 | CPtr(如 CUInt64T | CPtr / CSizeT | CPtr):
|
||
# 联合解析后同样退化为指针表示,元素为 8 字节(i64 或指针)。
|
||
# 下标必须按 8 字节步长读写——否则 GEP 步长 1 + trunc i8 截断,
|
||
# 指针存进数组只剩低 1 字节(BuddyTest OOM/fill 的 ptrs 数组全错位:
|
||
# store i8 trunc i64、读回 inttoptr i8 丢高 56 位,free 全部无效)。
|
||
if self._is_64bit_scalar_ty(bop.left) != 0 or self._is_64bit_scalar_ty(bop.right) != 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _is_64bit_scalar_ty(self, node: ast.AST | t.CPtr) -> int:
|
||
"""判断类型节点是否为 64 位标量数值类型(CUInt64T/CInt64T/CSizeT),元素 8 字节"""
|
||
if node is None:
|
||
return 0
|
||
ty_nm: str = None
|
||
nk: int = node.kind()
|
||
if nk == ast.ASTKind.Name:
|
||
nm64: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
ty_nm = nm64.id
|
||
elif nk == ast.ASTKind.Attribute:
|
||
at64: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
|
||
ty_nm = at64.attr
|
||
if ty_nm is None:
|
||
return 0
|
||
if string.strcmp(ty_nm, "CUInt64T") == 0:
|
||
return 1
|
||
if string.strcmp(ty_nm, "CInt64T") == 0:
|
||
return 1
|
||
if string.strcmp(ty_nm, "CSizeT") == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def _is_scalar_ty_name(self, ty_name: str) -> int:
|
||
"""判断类型名是否为纯标量(不含指针标记),用于泛型 T 的联合元素类型判定
|
||
|
||
泛型 T | t.CPtr(如 _list.vp 的 elem_ptr)经 Fix A(TypeGenMixin 联合
|
||
解析保留泛型标量)后 alloca 变 Ptr(标量):T 为纯标量(int/float/double/
|
||
i64 等)时下标按标量自身大小步长,不能再按 8 字节指针槽——否则
|
||
Ptr(标量) alloca + IsPtrElement 路径(load 标量当指针)产生非法 IR。
|
||
指针/联合/str/bytes 才保持 8 字节指针槽语义。
|
||
"""
|
||
if ty_name is None:
|
||
return 0
|
||
if string.strchr(ty_name, '|') is not None:
|
||
return 0
|
||
if string.strchr(ty_name, '*') is not None:
|
||
return 0
|
||
if string.strcmp(ty_name, "str") == 0:
|
||
return 0
|
||
if string.strcmp(ty_name, "bytes") == 0:
|
||
return 0
|
||
if string.strcmp(ty_name, "t.CPtr") == 0:
|
||
return 0
|
||
if string.strcmp(ty_name, "CPtr") == 0:
|
||
return 0
|
||
if string.strstr(ty_name, "Ptr") is not None:
|
||
return 0
|
||
return 1
|
||
|
||
def _is_generic_tp_or_nested(self, node: ast.AST | t.CPtr) -> int:
|
||
"""判断注解节点是否为泛型类型参数名(单字母大写,如 T)或嵌套联合(BinOp)"""
|
||
if node is None:
|
||
return 0
|
||
nk: int = node.kind()
|
||
if nk == ast.ASTKind.BinOp:
|
||
return 1
|
||
if nk == ast.ASTKind.Name:
|
||
nm_tp: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
|
||
if nm_tp.id is None:
|
||
return 0
|
||
tp_len: t.CSizeT = string.strlen(nm_tp.id)
|
||
if tp_len == 1:
|
||
if nm_tp.id[0] >= 65 and nm_tp.id[0] <= 90:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _init_global_array_from_list — 从列表字面量初始化全局数组
|
||
#
|
||
# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。
|
||
# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。
|
||
#
|
||
# Args:
|
||
# builder: IRBuilder
|
||
# pool: 编译器内存池
|
||
# mod: LLVMModule
|
||
# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*)
|
||
# list_node: ast.List 节点
|
||
# trans: Translator 对象
|
||
#
|
||
# Returns:
|
||
# 0 成功,1 失败
|
||
# ============================================================
|
||
def _init_global_array_from_list(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
array_alloca: llvmlite.Value | t.CPtr,
|
||
list_node: ast.AST | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> int:
|
||
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store"""
|
||
if builder is None or array_alloca is None or list_node is None:
|
||
return 1
|
||
|
||
# 获取数组类型(Pointee of [N x elem_ty]*)
|
||
arr_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if array_alloca.Ty is not None:
|
||
arr_ty = array_alloca.Ty.Pointee
|
||
if arr_ty is None:
|
||
return 1
|
||
|
||
# 匹配数组类型获取元素类型
|
||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||
match arr_ty:
|
||
case llvmlite.LLVMType.Array(et, _):
|
||
elem_ty = et
|
||
if elem_ty is None:
|
||
return 1
|
||
|
||
# 获取列表元素
|
||
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
|
||
if lst is None or lst.elts is None:
|
||
return 1
|
||
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
|
||
elts_count: t.CSizeT = len(elts)
|
||
|
||
# 为每个元素生成 GEP + store
|
||
i: t.CSizeT = 0
|
||
while i < elts_count:
|
||
elem_node: ast.AST | t.CPtr = elts.get(i)
|
||
elem_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||
builder, pool, mod, elem_node, None, 0, trans)
|
||
if elem_val is None:
|
||
# 元素翻译失败:直接报错终止(fail-fast),暴露上游根因
|
||
HandlesType.fatal_error(elem_node, "全局数组初始化元素翻译失败", "TypeError")
|
||
idx_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, i)
|
||
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, arr_ty, elem_ty, array_alloca, idx_val)
|
||
if elem_ptr is not None:
|
||
# 类型转换(如 i32 → i8 截断)
|
||
store_val: llvmlite.Value | t.CPtr = elem_val
|
||
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
|
||
store_val = HandlesExpr.coerce_to_type(
|
||
builder, elem_val, elem_ptr.Ty.Pointee, elem_node)
|
||
llvmlite.build_store(builder, store_val, elem_ptr)
|
||
i += 1
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# _apply_aug_op - 应用增强赋值的二元运算
|
||
#
|
||
# 支持浮点运算、指针算术: ptr += int / ptr -= int
|
||
# 整数运算自动类型提升
|
||
# ============================================================
|
||
def _apply_aug_op(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
op: int,
|
||
lhs: llvmlite.Value | t.CPtr,
|
||
rhs: llvmlite.Value | t.CPtr,
|
||
node: ast.AST | t.CPtr = None,
|
||
trans: HT.Translator | t.CPtr = None,
|
||
lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算)"""
|
||
lhs_bits: int = HandlesExpr.get_llvm_type_bits(lhs.Ty)
|
||
rhs_bits: int = HandlesExpr.get_llvm_type_bits(rhs.Ty)
|
||
lhs_fbits: int = HandlesExpr.get_llvm_float_bits(lhs.Ty)
|
||
rhs_fbits: int = HandlesExpr.get_llvm_float_bits(rhs.Ty)
|
||
|
||
# 浮点运算: 任一操作数为浮点时,使用浮点指令(必须在指针算术之前检查,
|
||
# 因为 float 的 int bits 为 0,会被误认为指针)
|
||
if lhs_fbits != 0 or rhs_fbits != 0:
|
||
# 确定目标浮点类型(使用较大的位宽)
|
||
target_fbits: int = lhs_fbits
|
||
if rhs_fbits > target_fbits:
|
||
target_fbits = rhs_fbits
|
||
target_float_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
|
||
if target_fbits == 32:
|
||
target_float_ty = llvmlite.Float(pool)
|
||
# 将两个操作数转换为目标浮点类型(int→float via si2fp, float→float via fpext/fptrunc)
|
||
lhs = HandlesExpr.coerce_to_type(builder, lhs, target_float_ty, node)
|
||
rhs = HandlesExpr.coerce_to_type(builder, rhs, target_float_ty, node)
|
||
if op == ast.OpKind.Add:
|
||
return llvmlite.build_fadd(builder, lhs, rhs)
|
||
if op == ast.OpKind.Sub:
|
||
return llvmlite.build_fsub(builder, lhs, rhs)
|
||
if op == ast.OpKind.Mult:
|
||
return llvmlite.build_fmul(builder, lhs, rhs)
|
||
if op == ast.OpKind.Div:
|
||
return llvmlite.build_fdiv(builder, lhs, rhs)
|
||
if op == ast.OpKind.Mod:
|
||
return llvmlite.build_frem(builder, lhs, rhs)
|
||
return None
|
||
|
||
# 指针算术: ptr += int / ptr -= int → getelementptr(按元素大小缩放)
|
||
# 对齐 TPC HandlesAugAssign.py L140-149 / L170-180
|
||
if lhs_bits == 0 and rhs_bits != 0:
|
||
if op == ast.OpKind.Add or op == ast.OpKind.Sub:
|
||
return HandlesExpr.translate_ptr_arith(pool, builder, lhs, rhs, op)
|
||
return None
|
||
|
||
# 整数运算:类型提升
|
||
if lhs_bits > rhs_bits and rhs_bits > 0:
|
||
rhs = HandlesExpr.coerce_to_type(builder, rhs, lhs.Ty, node)
|
||
elif rhs_bits > lhs_bits and lhs_bits > 0:
|
||
lhs = HandlesExpr.coerce_to_type(builder, lhs, rhs.Ty, node)
|
||
|
||
if op == ast.OpKind.Add:
|
||
return llvmlite.build_add(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Sub:
|
||
return llvmlite.build_sub(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Mult:
|
||
return llvmlite.build_mul(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Div:
|
||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||
elif op == ast.OpKind.FloorDiv:
|
||
return llvmlite.build_sdiv(builder, lhs, rhs)
|
||
elif op == ast.OpKind.Mod:
|
||
return llvmlite.build_srem(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitAnd:
|
||
return llvmlite.build_and(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitOr:
|
||
return llvmlite.build_or(builder, lhs, rhs)
|
||
elif op == ast.OpKind.BitXor:
|
||
return llvmlite.build_xor(builder, lhs, rhs)
|
||
elif op == ast.OpKind.LShift:
|
||
return llvmlite.build_shl(builder, lhs, rhs)
|
||
elif op == ast.OpKind.RShift:
|
||
# 无符号 >> → lshr(逻辑右移),有符号 >> → ashr(算术右移)
|
||
# 对齐 TPC ExprGen.emit_binary_op:i8/i16 默认无符号;其余查操作数无符号性
|
||
if lhs_bits == 8 or lhs_bits == 16:
|
||
return llvmlite.build_lshr(builder, lhs, rhs)
|
||
if lhs_node is not None and trans is not None:
|
||
if HandlesExpr._node_type_unsigned(pool, lhs_node, trans) != 0:
|
||
return llvmlite.build_lshr(builder, lhs, rhs)
|
||
return llvmlite.build_ashr(builder, lhs, rhs)
|
||
return None
|