518 lines
25 KiB
Plaintext
518 lines
25 KiB
Plaintext
import lib.core.Gen.Generator as Generator
|
||
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.CompilerFactory as CompilerFactory
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.Stub.StubMerger as StubMerger
|
||
import lib.core.VLogger as VLogger
|
||
import lib.Projectrans.Config as Config
|
||
import lib.Projectrans.Utils as Utils
|
||
|
||
|
||
# ============================================================
|
||
# ExprGenBase - ExprGenMixin 拆分(阶段 D):表达式基础工具(类型判断/指针层级/coerce)
|
||
#
|
||
# 最底层 Base(ExprGenMixin/Const/Fstr/Ops/Cdef/Name/Attr/Cls 均 1 级继承本类)。
|
||
# 跨 Mixin 调用统一走 HandlesExpr 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class ExprGenBase:
|
||
"""表达式基础工具(类型判断/指针层级/coerce)"""
|
||
|
||
# --- docstring 登记表字段(__doc__ 魔法属性支持)---
|
||
Gen: Generator.Generator | t.CPtr
|
||
DocKeys: bytes
|
||
DocValues: bytes
|
||
DocCount: int
|
||
|
||
# --- OOM 诊断:跨模块 CDefine 查找调用计数(CONST_INT 参数翻译疑似循环查找) ---
|
||
DiagCDefineCount: int
|
||
# --- OOM 诊断:translate_name_value 调用计数(顶层 CDefine 查找 14593 次来源) ---
|
||
DiagNameValueCount: int
|
||
# --- OOM 诊断:translate_value 调用计数(CONST_INT 循环调用源定位) ---
|
||
DiagTranslateValueCount: int
|
||
# ============================================================
|
||
# P3 迁移方法(函数体来自 HandlesExpr.vp 模块级函数,
|
||
# 本模块函数调用改 self.,外部模块调用保留模块前缀)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
# 从 AST 节点提取函数名
|
||
# ============================================================
|
||
def get_func_name(self, func_node: ast.AST | t.CPtr) -> str:
|
||
"""从函数节点提取函数名"""
|
||
if func_node is None:
|
||
return None
|
||
k: int = func_node.kind()
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_node)
|
||
return nm.id
|
||
elif k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(func_node)
|
||
return at.attr
|
||
return None
|
||
# ============================================================
|
||
# 转义 LLVM IR 字符串字面量
|
||
# ============================================================
|
||
def escape_llvm_string(self, pool: memhub.MemBuddy | t.CPtr,
|
||
src: str) -> str:
|
||
"""将字符串转换为 LLVM IR 字符串字面量 c"...\\00" """
|
||
if src is None:
|
||
return None
|
||
slen: t.CSizeT = string.strlen(src)
|
||
alloc_size: t.CSizeT = 4 * slen + 8
|
||
buf: str = pool.alloc(alloc_size)
|
||
if buf is None:
|
||
return None
|
||
pos: t.CSizeT = 0
|
||
buf[pos] = 'c'
|
||
pos += 1
|
||
buf[pos] = '"'
|
||
pos += 1
|
||
for i in range(slen):
|
||
ch: t.CChar = src[i]
|
||
if ch == '\0':
|
||
break
|
||
if ch == '\"' or ch == '\\' or ch < 0x20:
|
||
buf[pos] = '\\'
|
||
pos += 1
|
||
hi: int = (ch >> 4) & 0xF
|
||
lo: int = ch & 0xF
|
||
buf[pos] = Utils.nibble_to_hex_char(hi, 1)
|
||
pos += 1
|
||
buf[pos] = Utils.nibble_to_hex_char(lo, 1)
|
||
pos += 1
|
||
else:
|
||
buf[pos] = ch
|
||
pos += 1
|
||
buf[pos] = '\\'
|
||
pos += 1
|
||
buf[pos] = '0'
|
||
pos += 1
|
||
buf[pos] = '0'
|
||
pos += 1
|
||
buf[pos] = '"'
|
||
pos += 1
|
||
buf[pos] = '\0'
|
||
return buf
|
||
# ============================================================
|
||
# 获取 LLVM 整数类型的位宽
|
||
# ============================================================
|
||
def get_llvm_type_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""获取 LLVM 整数类型的位宽,非整数类型返回 0"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
return bits
|
||
case _:
|
||
return 0
|
||
# ============================================================
|
||
# 获取 LLVM 浮点类型的位宽
|
||
# ============================================================
|
||
def get_llvm_float_bits(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""获取 LLVM 浮点类型的位宽,非浮点类型返回 0"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Float(bits):
|
||
return bits
|
||
case _:
|
||
return 0
|
||
# ============================================================
|
||
# is_ptr_type - 检查类型是否为 Ptr
|
||
#
|
||
# 返回 1=是, 0=否。作为类型检查工具函数被广泛使用(50+ 处调用)。
|
||
# ============================================================
|
||
def is_ptr_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""检查 ty 是否是 Ptr 类型,返回 1=是, 0=否"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
return 1
|
||
case _:
|
||
return 0
|
||
# ============================================================
|
||
# get_ptr_level - 计算指针层级
|
||
#
|
||
# 返回值:
|
||
# 0 = 非指针(数值/结构体等)
|
||
# 1 = 一级指针(如 i8*, Struct*)
|
||
# 2 = 二级指针(如 i8**, Struct**)
|
||
# 3+ = 更高级指针
|
||
#
|
||
# 用于比较运算的类型安全检查:
|
||
# - 数值(0) vs 数值(0) → 允许
|
||
# - 一级指针(1) vs 一级指针(1) → 允许
|
||
# - 数值(0) vs 指针(1+) → 禁止(fast-fail)
|
||
# - 不同级指针(1 vs 2) → 禁止(fast-fail)
|
||
# ============================================================
|
||
def get_ptr_level(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""计算指针层级,0=非指针, 1=一级指针, 2=二级指针..."""
|
||
if ty is None:
|
||
return 0
|
||
level: int = 0
|
||
cur: llvmlite.LLVMType | t.CPtr = ty
|
||
while cur is not None:
|
||
match cur:
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
level += 1
|
||
cur = pointee
|
||
case _:
|
||
break
|
||
return level
|
||
# ============================================================
|
||
# _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0
|
||
#
|
||
# 用于指针判空比较(ptr != 0 / ptr == 0):指针与字面量 0 比较时
|
||
# 0 视为 NULL,允许并转成 null 指针(比较类型检查的例外)。
|
||
# ============================================================
|
||
def _is_zero_int_literal(self, node: ast.AST | t.CPtr) -> int:
|
||
"""判断节点是否为整数字面量 0,返回 1=是 / 0=否"""
|
||
if node is None:
|
||
return 0
|
||
if node.kind() != ast.ASTKind.Constant:
|
||
return 0
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
|
||
if cn is None or cn.const_kind != ast.CONST_INT:
|
||
return 0
|
||
if cn.int_val == 0:
|
||
return 1
|
||
return 0
|
||
# ============================================================
|
||
# is_array_type - 检查类型是否为 Array
|
||
#
|
||
# 返回 1=是, 0=否。类型检查工具函数。
|
||
# ============================================================
|
||
def is_array_type(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""检查 ty 是否是 Array 类型,返回 1=是, 0=否"""
|
||
if ty is None:
|
||
return 0
|
||
match ty:
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
return 1
|
||
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 | t.CPtr,
|
||
idx_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""将 <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 | t.CPtr = llvmlite.Int32(builder.Pool)
|
||
return llvmlite.build_zext(builder, idx_val, i32_ty)
|
||
return idx_val
|
||
# ============================================================
|
||
# _get_custom_struct_cls_nm - 检查类型是否为已注册的自定义结构体
|
||
#
|
||
# 处理两种情况:
|
||
# - ty 直接是 Struct → 检查是否注册
|
||
# - ty 是 Ptr(Struct) → 检查 pointee 是否注册
|
||
#
|
||
# 返回类名字符串或 None。用于 subscript 操作中判断是否需要
|
||
# 转发到 __getitem__/__setitem__ 而非生成 GEP。
|
||
# ============================================================
|
||
def _get_custom_struct_cls_nm(self, pool: memhub.MemBuddy | t.CPtr,
|
||
ty: llvmlite.LLVMType | t.CPtr) -> str:
|
||
"""检查 ty 或 ty 的 pointee 是否是已注册的自定义结构体,返回类名或 None"""
|
||
if ty is None:
|
||
return None
|
||
# 直接检查 ty 是否是注册的结构体
|
||
cls_nm_direct: str = self.Gen.StructGen.get_class_name_by_type(pool, ty)
|
||
if cls_nm_direct is not None:
|
||
return cls_nm_direct
|
||
# 如果 ty 是 Ptr,检查 pointee
|
||
if self.is_ptr_type(ty) != 0:
|
||
pointee_cs: llvmlite.LLVMType | t.CPtr = ty.Pointee
|
||
if pointee_cs is not None:
|
||
return self.Gen.StructGen.get_class_name_by_type(pool, pointee_cs)
|
||
return None
|
||
# ============================================================
|
||
# _is_list_subscript_base - 判断下标基座是否为 list[T] 变量
|
||
#
|
||
# 属性访问的 Subscript 基座(如 lst[i].x)需要区分:
|
||
# - list[T] 变量:translate_subscript 走 __getitem__ 内联返回元素地址
|
||
# - 普通结构体指针数组(如 pts: Point | t.CPtr):get_subscript_ptr 返回元素地址
|
||
# 路由错误会让 list[T] 被当作结构体数组 GEP,访问错位崩溃。
|
||
# ============================================================
|
||
def _is_list_subscript_base(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
sub_node: ast.AST | t.CPtr) -> int:
|
||
"""判断下标基座是否为 list[T] 变量(1=是)"""
|
||
if sub_node is None or trans is None:
|
||
return 0
|
||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node)
|
||
if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||
if nm.id is None:
|
||
return 0
|
||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_var(trans.SymTab, nm.id)
|
||
if alloca is None or alloca.Ty is None:
|
||
return 0
|
||
if self.is_ptr_type(alloca.Ty) == 0:
|
||
return 0
|
||
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is None:
|
||
return 0
|
||
match pointee:
|
||
case llvmlite.LLVMType.Ptr(inner_ty):
|
||
lsn_ls: str = None
|
||
match inner_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, lsn3):
|
||
lsn_ls = lsn3
|
||
case _:
|
||
pass
|
||
if lsn_ls is not None and string.strstr(lsn_ls, "list[") is not None:
|
||
return 1
|
||
case _:
|
||
pass
|
||
return 0
|
||
# ============================================================
|
||
# _sub_base_class_name - 解析下标基座变量的结构体类名
|
||
# ============================================================
|
||
def _sub_base_class_name(self, pool: memhub.MemBuddy | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
sub_node: ast.AST | t.CPtr) -> str:
|
||
"""解析下标基座变量的结构体类名(无则 None)"""
|
||
if sub_node is None or trans is None:
|
||
return None
|
||
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sub_node)
|
||
if sub is None or sub.value is None or sub.value.kind() != ast.ASTKind.Name:
|
||
return None
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
|
||
if nm.id is None:
|
||
return None
|
||
alloca: llvmlite.Value | t.CPtr = 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 | t.CPtr = alloca.Ty.Pointee
|
||
if pointee is None:
|
||
return None
|
||
if self.is_ptr_type(pointee) != 0:
|
||
inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee
|
||
if inner is not None:
|
||
return self.Gen.StructGen.get_class_name_by_type(pool, inner)
|
||
return self.Gen.StructGen.get_class_name_by_type(pool, pointee)
|
||
# ============================================================
|
||
# _sub_base_uses_getitem - 下标基座是否应走 __getitem__ 语义
|
||
#
|
||
# 属性访问的 Subscript 基座路由依据:
|
||
# - list[T] / OOP 定义 __getitem__ 的类(如 dict[key])→ translate_value
|
||
# (translate_subscript 走 __getitem__ 内联/方法调用返回元素值或地址)
|
||
# - 普通结构体指针数组(如 pts: Point | t.CPtr)→ get_subscript_ptr
|
||
# (GEP 元素地址,避免结构体值 base=非指针 报错)
|
||
# ============================================================
|
||
def _sub_base_uses_getitem(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
trans: HT.Translator | t.CPtr,
|
||
sub_node: ast.AST | t.CPtr) -> int:
|
||
"""下标基座应走 __getitem__ 语义时返回 1,否则 0(应走 GEP 地址语义)"""
|
||
if self._is_list_subscript_base(pool, trans, sub_node) != 0:
|
||
return 1
|
||
cls_ugi: str = self._sub_base_class_name(pool, trans, sub_node)
|
||
if cls_ugi is None:
|
||
return 0
|
||
lookup_ugi: str = pool.alloc(128)
|
||
if lookup_ugi is None:
|
||
return 0
|
||
viperlib.snprintf(lookup_ugi, 128, "%s.__getitem__", cls_ugi)
|
||
if self.Gen.CallGenBase.find_func_in_module(mod, lookup_ugi) is not None:
|
||
return 1
|
||
return 0
|
||
# ============================================================
|
||
# _deref_if_ptr_ptr - 如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用
|
||
#
|
||
# 用于支持 X|t.CPtr 类型变量的属性访问:
|
||
# - 值类型变量 (cnt: Counter): alloca 类型是 Ptr(Struct) → 不解引用
|
||
# - 指针类型变量 (r: Vec2|t.CPtr): alloca 类型是 Ptr(Ptr(Struct)) → load 解引用
|
||
# ============================================================
|
||
def _deref_if_ptr_ptr(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
obj_ptr: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""如果 obj_ptr 是 Ptr(Ptr(...)),load 解引用获取内层指针"""
|
||
if obj_ptr is None or obj_ptr.Ty is None:
|
||
return obj_ptr
|
||
if self.is_ptr_type(obj_ptr.Ty) == 0:
|
||
return obj_ptr
|
||
pointee: llvmlite.LLVMType | t.CPtr = obj_ptr.Ty.Pointee
|
||
if pointee is None:
|
||
return obj_ptr
|
||
if self.is_ptr_type(pointee) == 0:
|
||
return obj_ptr
|
||
# obj_ptr 是 Ptr(Ptr(...)),load 解引用
|
||
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, obj_ptr)
|
||
if loaded is None:
|
||
return obj_ptr
|
||
return loaded
|
||
# ============================================================
|
||
# 类型强制转换:整数 sext/trunc,浮点 fpext/fptrunc,int↔float si2fp/fp2si
|
||
# ============================================================
|
||
def coerce_to_type(self, builder: llvmlite.IRBuilder | t.CPtr,
|
||
val: llvmlite.Value | t.CPtr,
|
||
target_ty: llvmlite.LLVMType | t.CPtr,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""将 val 强制转换为 target_ty
|
||
|
||
整数: sext(扩展)/ trunc(截断)
|
||
浮点: fpext(扩展)/ fptrunc(截断)
|
||
int→float: sitofp
|
||
float→int: fptosi
|
||
|
||
node: AST 节点(用于错误定位),可为 None
|
||
"""
|
||
if val is None or target_ty is None:
|
||
return val
|
||
# 函数 → 指针: bitcast(如 CreateThread(..., _thread_alloc_free, ...) 传函数指针)
|
||
# 函数 Value 的 Ty 是 Func,既不是整数也不是指针,需在整数/浮点转换之前处理
|
||
match val.Ty:
|
||
case llvmlite.LLVMType.Func(_, _, _):
|
||
if self.is_ptr_type(target_ty) != 0:
|
||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||
return val
|
||
case _:
|
||
pass
|
||
# 整数转换
|
||
val_bits: int = self.get_llvm_type_bits(val.Ty)
|
||
target_bits: int = self.get_llvm_type_bits(target_ty)
|
||
# 整数 → 指针: inttoptr(必须在纯整数转换之前检查,因为 ptr 的 bits 非零会误入 sext/trunc 路径)
|
||
# 适用于: 跨模块方法返回 i64/i32(默认推断),目标变量是指针类型
|
||
if val_bits != 0 and self.is_ptr_type(target_ty) != 0:
|
||
return llvmlite.build_inttoptr(builder, val, target_ty)
|
||
# 指针 → 整数: ptrtoint(当目标明确是整数而非指针时)
|
||
# 注意: target_bits == 8 时跳过 ptrtoint,走后面的 build_load 解引用首字符
|
||
# 修复: buf[idx] = '\0' 中 '\0' 是 CONST_STR → i8* 指针,
|
||
# ptrtoint 会截断地址低 8 位(非 0),应 load 解引用取首字符 0
|
||
if self.is_ptr_type(val.Ty) != 0 and target_bits != 0 and target_bits != 8 and self.is_ptr_type(target_ty) == 0:
|
||
return llvmlite.build_ptrtoint(builder, val, target_ty)
|
||
if val_bits != 0 and target_bits != 0:
|
||
if val_bits == target_bits:
|
||
return val
|
||
if val_bits < target_bits:
|
||
# i1 (bool) → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF...)
|
||
# 与 HandlesReturn 中 return 语句的 i1 扩展规则保持一致
|
||
if val_bits == 1:
|
||
return llvmlite.build_zext(builder, val, target_ty)
|
||
return llvmlite.build_sext(builder, val, target_ty)
|
||
return llvmlite.build_trunc(builder, val, target_ty)
|
||
# 浮点转换
|
||
val_fbits: int = self.get_llvm_float_bits(val.Ty)
|
||
target_fbits: int = self.get_llvm_float_bits(target_ty)
|
||
# float ↔ ptr: 禁止(无意义的转换,fast-fail 防止误走入 build_load 路径)
|
||
if (val_fbits != 0 and self.is_ptr_type(target_ty) != 0) or \
|
||
(self.is_ptr_type(val.Ty) != 0 and target_fbits != 0):
|
||
self.Gen.TypeGenErr.fatal_error(node, "unsupported type conversion: float <-> ptr", "CastError")
|
||
return val
|
||
if val_fbits != 0 and target_fbits != 0:
|
||
if val_fbits == target_fbits:
|
||
return val
|
||
if val_fbits < target_fbits:
|
||
return llvmlite.build_fpext(builder, val, target_ty)
|
||
return llvmlite.build_fptrunc(builder, val, target_ty)
|
||
# int → float
|
||
if val_bits != 0 and target_fbits != 0:
|
||
return llvmlite.build_si2fp(builder, val, target_ty)
|
||
# float → int
|
||
if val_fbits != 0 and target_bits != 0:
|
||
return llvmlite.build_fp2si(builder, val, target_ty)
|
||
# 指针 → 非指针值: build_load 解引用
|
||
# 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值
|
||
# 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load
|
||
if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) == 0:
|
||
return llvmlite.build_load(builder, target_ty, val)
|
||
# 指针 → 指针: bitcast (如 i8* → i8** 当目标是全局变量存储指针)
|
||
if self.is_ptr_type(val.Ty) != 0 and self.is_ptr_type(target_ty) != 0:
|
||
return llvmlite.build_bitcast(builder, val, target_ty)
|
||
return val
|
||
# ============================================================
|
||
# translate_ptr_arith - 指针算术: ptr + int / ptr - int
|
||
#
|
||
# 用 getelementptr(按 pointee 元素大小缩放索引),对齐 TPC
|
||
# ExprGen.emit_binary_op / HandlesAugAssign.py。
|
||
# 旧实现用 ptrtoint + add + inttoptr(按字节加):i8* 元素大小 1
|
||
# 恰好正确,但 i32*/struct* 等指针 `p + 3` 只前进 3 字节(应 12),
|
||
# 导致 StringIterTest Test 4/8 失败(指针偏移/指针算术)。
|
||
#
|
||
# 数组 pointee([N x ty]*)先 decay 为元素指针(GEP 0,0),
|
||
# 避免以整个数组为步长(对齐 TPC ExprGen L53-55)。
|
||
# ============================================================
|
||
def translate_ptr_arith(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
ptr_val: llvmlite.Value | t.CPtr,
|
||
int_val: llvmlite.Value | t.CPtr,
|
||
op: int) -> llvmlite.Value | t.CPtr:
|
||
"""指针算术: ptr + int / ptr - int → GEP(按元素大小缩放索引)"""
|
||
if ptr_val is None or int_val is None or ptr_val.Ty is None:
|
||
return None
|
||
# 提取 pointee 类型(非指针 → 不处理返回 None)
|
||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||
match ptr_val.Ty:
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
elem_ty = pointee
|
||
case _:
|
||
return None
|
||
if elem_ty is None:
|
||
return None
|
||
# 索引统一到 i64(对齐 TPC zext 到 i64)
|
||
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
idx: llvmlite.Value | t.CPtr = self.coerce_to_type(builder, int_val, i64_ty, None)
|
||
if idx is None:
|
||
return None
|
||
# ptr - int → 负索引(LLVM GEP 索引为加法语义)
|
||
if op == ast.OpKind.Sub:
|
||
neg_idx: llvmlite.Value | t.CPtr = llvmlite.build_sub(
|
||
builder, llvmlite.const_int64(pool, 0), idx)
|
||
if neg_idx is None:
|
||
return None
|
||
idx = neg_idx
|
||
# 数组 pointee → 先 decay 为元素指针(getelementptr [N x ty], [N x ty]* %p, i32 0, i32 0)
|
||
if self.is_array_type(elem_ty) != 0:
|
||
inner_ty: llvmlite.LLVMType | t.CPtr = None
|
||
match elem_ty:
|
||
case llvmlite.LLVMType.Array(inner, _):
|
||
inner_ty = inner
|
||
case _:
|
||
return None
|
||
if inner_ty is None:
|
||
return None
|
||
decayed: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, elem_ty, inner_ty, ptr_val, llvmlite.const_int64(pool, 0))
|
||
if decayed is None:
|
||
return None
|
||
return llvmlite.build_gep(builder, inner_ty, decayed, idx)
|
||
return llvmlite.build_gep(builder, elem_ty, ptr_val, idx)
|
||
def InitExprGen(self) -> int:
|
||
"""初始化 ExprGen 族字段(构造时由 Generator 调用)"""
|
||
if self is None:
|
||
return 1
|
||
self.DocKeys = None
|
||
self.DocValues = None
|
||
self.DocCount = 0
|
||
self.DiagCDefineCount = 0
|
||
self.DiagNameValueCount = 0
|
||
self.DiagTranslateValueCount = 0
|
||
return 0
|