Files
TransPyC/lib/core/Handles/HandlesExpr.py
T
TermiNexus f19d25782f refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建
删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
2026-10-18 13:00:58 +08:00

622 lines
38 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from lib.core.translator import Translator
from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
import vast as ast
import re
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import BaseHandle
from lib.constants.config import mode as _config_mode
from lib.core.TypeSystem import CTypeRegistry as _CR
from lib.core.SymbolUtils import (RequireDefineUseWidthAt, RequireIntLiteralStorable, RequireNameDefined,
RequireExplicitWidthLiteral,
DefineDeclTypeValue, GlobalDeclShadowsDefine)
# ---------------------------------------------------------------
# 注解/常量折叠里的正则**预编译**(性能:避免每次 `re.match`/`re.search(字面量, ...)`
# 的"模式串哈希 → re 模块级缓存查找"。语义与逐字写法完全一致,模式串一字未改)。
# ---------------------------------------------------------------
# 从 `list[...]` 注解串里取出元素类型与可选长度
_RE_LIST_ELEM_TYPE: re.Pattern[str] = re.compile(r'list\[([^,\]]+)(?:,\s*(\d+))?\]')
# LLVM 整型类型名 `i8`/`i32`/... 的位宽提取
_RE_LLVM_INT_TYPE: re.Pattern[str] = re.compile(r'^i(\d+)$')
def DefineUseWidthFromLLVMType(Ty: object) -> int | None:
"""LLVM 类型 → CDefine 常量的"使用处位宽"提示;其余 → None。
只认 i8/i16/i32/i64(与 SymbolUtils.DEFINE_WIDTH_LADDER 同集合):
i1(比较/逻辑结果)与指针不构成"整数使用处宽度",必须落回"取不到 ⇒
默认 32/64",否则 `C == 0` 之类会拿到位宽 1 而误报"使用处宽度不足"。
"""
if isinstance(Ty, ir.IntType) and Ty.width in (8, 16, 32, 64):
return int(Ty.width)
return None
class ExprHandle(BaseHandle):
# list 元素类型 → (字节大小, LLVM 元素类型) 映射表
# 用于 _HandleListLlvm 中 alloc_size / byte_offset / elem_ptr 类型统一查表,
# 消除原代码三处重复的 if-elif 链。
_ELEM_TYPE_INFO: dict[str, tuple[int, ir.Type]] = {
'i8': (1, ir.IntType(8)),
'i16': (2, ir.IntType(16)),
'i32': (4, ir.IntType(32)),
'float': (4, ir.FloatType()),
'double': (8, ir.DoubleType()),
}
def __init__(self, translator: "Translator") -> None:
super().__init__(translator)
def GetOpSymbol(self, Op: ast.cmpop | ast.operator | ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetOpSymbol(Op)
def GetUnaryOpSymbol(self, Op: ast.unaryoperator) -> str | None:
return self.Trans.ExprUtils.GetUnaryOpSymbol(Op)
def GetComparatorSymbol(self, Op: ast.cmpop) -> str | None:
return self.Trans.ExprUtils.GetComparatorSymbol(Op)
def _get_var_class(self, node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
return self.Trans.ExprUtils._get_var_class(node, Gen)
def _try_operator_overLoad(self, ClassName: str, op_name: str, obj_val: ir.Value, Gen: LlvmCodeGenerator, other_val: ir.Value | None = None) -> ir.Value | None:
return self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, obj_val, Gen, other_val)
def _get_llvm_member_offset(self, field_name: str, ClassName: str, Gen: LlvmCodeGenerator) -> int | None:
return self.Trans.ExprAttrHandle._get_llvm_member_offset(field_name, ClassName, Gen)
def HandleExprLlvm(self, Node: ast.AST, VarType: ir.Type | str | None = None,
ConstWidthHint: int | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
if not Gen or not Gen.builder:
return None
if isinstance(Node, ast.Constant):
return self._HandleConstantLlvm(Node, VarType)
elif isinstance(Node, ast.Name):
# ConstWidthHint 是**窄通道**:只有 Name(CDefine 常量物化)读取它,
# 其余分支(字面量/列表/运算…)逐字沿用既有 VarType 语义 ⇒ 非常量
# 路径的既有 IR 不变。
return self._HandleNameLlvm(Node, VarType, ConstWidthHint)
elif isinstance(Node, ast.BinOp):
return self.Trans.ExprOpsHandle._HandleBinOpLlvm(Node, VarType)
elif isinstance(Node, ast.BoolOp):
return self.Trans.ExprOpsHandle._HandleBoolOpLlvm(Node)
elif isinstance(Node, ast.UnaryOp):
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(Node)
elif isinstance(Node, ast.Starred):
# `*p` 出现在值位置(典型:调用实参 `f(*p)`):C/Python 解析器都按
# Python `*args` 语义归类为 Starred(Load)(vast_c.c ParseCallTail、
# ExprParser.py:543-548)。Viper 未实现解包 ⇒ 与 `*p` 读侧对齐,一律
# 归一为 UnaryOp(Deref) 解引用读取(与 ViperC ExprGenMixin 的同类归一
# 逐字同口径)。此前无本分支 ⇒ 落到函数末尾兜底 `return i32 0`,
# 把 `f(*p)` 静默变成 `f(0)`。
StarredInner: ast.expr | None = Node.value
if StarredInner is None:
raise Exception(f"值位置的单目 '*' 缺少操作数{Gen._get_node_info()}")
return self.Trans.ExprOpsHandle._HandleUnaryOpLlvm(
ast.UnaryOp(op=ast.Deref(), operand=StarredInner))
elif isinstance(Node, ast.Call):
return self.Trans.ExprCallHandle._HandleCallLlvm(Node)
elif isinstance(Node, ast.New):
# Viper `new [描述符...] T(args)`:取存储 + 构造(见 _HandleNewExprLlvm)
return self.Trans.ExprCallHandle._HandleNewExprLlvm(Node)
elif isinstance(Node, ast.Await):
return self.Trans.AsyncHandler._HandleAwaitLlvm(Node, Gen)
elif isinstance(Node, ast.Compare):
return self.Trans.ExprOpsHandle._HandleCompareLlvm(Node)
elif isinstance(Node, ast.Attribute):
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(Node)
elif isinstance(Node, ast.Subscript):
return self.Trans.ExprAttrHandle._HandleSubscriptLlvm(Node)
elif isinstance(Node, ast.IfExp):
return self.Trans.ExprLambdaHandle._HandleIfExpLlvm(Node)
elif isinstance(Node, ast.NamedExpr):
return self.Trans.ExprLambdaHandle._HandleNamedExprLlvm(Node)
elif isinstance(Node, ast.JoinedStr):
return self.Trans.ExprFormatHandle._HandleJoinedStrLlvm(Node)
elif isinstance(Node, ast.Lambda):
return self.Trans.ExprLambdaHandle._HandleLambdaLlvm(Node)
elif isinstance(Node, ast.List):
return self._HandleListLlvm(Node, VarType)
return ir.Constant(ir.IntType(32), 0)
def _HandleListLlvm(self, Node: ast.List, VarType: ir.Type | str | None = None) -> ir.Value | None:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
elements: list[ast.expr] = Node.elts
if not elements:
return ir.Constant(ir.IntType(8).as_pointer(), None)
array_len: int = len(elements)
elem_type: str = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
match: re.Match | None = _RE_LIST_ELEM_TYPE.search(VarType)
if match:
type_str: str = match.group(1).strip()
if match.group(2):
array_len = int(match.group(2))
if 'CChar' in type_str or 'char' in type_str.lower():
elem_type = 'i8'
elif 'CFloat' in type_str or type_str.lower() == 'float':
elem_type = 'float'
elif 'CDouble' in type_str or type_str.lower() == 'double':
elem_type = 'double'
elif 'CInt' in type_str or ('int' in type_str.lower() and 'unsigned' not in type_str.lower()):
elem_type = 'i32'
elif 'CUnsignedInt' in type_str or 'unsigned' in type_str.lower():
elem_type = 'i32'
elif 'CUnsignedChar' in type_str or 'unsigned char' in type_str.lower():
elem_type = 'i8'
elif 'CShort' in type_str or 'short' in type_str.lower():
elem_type = 'i16'
elif 'CUnsignedShort' in type_str:
elem_type = 'i16'
elif elements and all(isinstance(e, (ast.Constant,)) and isinstance(getattr(e, 'value', None), float) for e in elements):
elem_type = 'float'
alloc_size: int = array_len
elem_info: tuple[int, ir.Type] = self._ELEM_TYPE_INFO.get(elem_type, (1, ir.IntType(8)))
elem_size: int = elem_info[0]
elem_llvm_type: ir.Type = elem_info[1]
alloc_size *= elem_size
malloc_fn: Any = None
malloc_arg_type: ir.IntType = ir.IntType(64)
for fn in Gen.module.global_values:
if fn.name == 'malloc':
malloc_fn = fn
func_ftype: Any = getattr(fn, 'ftype', None)
if func_ftype and getattr(func_ftype, 'args', None):
if func_ftype.args:
malloc_arg_type = fn.ftype.args[0]
break
if not malloc_fn:
try:
malloc_fn_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
malloc_fn = Gen._CreateOrReuseFuncDecl('malloc', malloc_fn_type)
Gen.functions['malloc'] = malloc_fn
except Exception as _e: # 回退:malloc 函数创建失败时返回 null
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
if isinstance(_e, _FFE):
raise
return ir.Constant(ir.IntType(8).as_pointer(), None)
alloc_ptr: Any = Gen.builder.call(malloc_fn, [ir.Constant(malloc_arg_type, alloc_size)])
cast_ptr: Any = Gen.builder.bitcast(alloc_ptr, ir.PointerType(ir.IntType(8)))
for i, elem in enumerate(elements):
if i >= array_len:
break
elem_val: Any = self.HandleExprLlvm(elem, VarType=elem_type)
if elem_val is None:
continue
# None(空值常量)允许隐式转换为任意元素类型 ⇒ 物化为目标元素类型零值。
if Gen._IsNoneValue(elem_val, elem):
elem_val = Gen._ZeroConst(elem_llvm_type)
byte_offset: int = i
if elem_type == 'i32':
byte_offset = i * 4
elif elem_type == 'i16':
byte_offset = i * 2
elif elem_type == 'float':
byte_offset = i * 4
elif elem_type == 'double':
byte_offset = i * 8
# 元素地址:以 i8* 基址按字节 GEP,再转成元素指针类型
# (不再 ptr→uint64 手动加偏移再 inttoptr,见新规范第 10 条)
elem_addr: Any = Gen.builder.gep(cast_ptr, [ir.Constant(ir.IntType(64), byte_offset)], name=f"elem_addr_{i}")
if elem_type == 'i32':
elem_ptr: Any = Gen.builder.bitcast(elem_addr, ir.PointerType(ir.IntType(32)))
elif elem_type == 'i16':
elem_ptr = Gen.builder.bitcast(elem_addr, ir.PointerType(ir.IntType(16)))
elif elem_type == 'float':
elem_ptr = Gen.builder.bitcast(elem_addr, ir.PointerType(ir.FloatType()))
elif elem_type == 'double':
elem_ptr = Gen.builder.bitcast(elem_addr, ir.PointerType(ir.DoubleType()))
else:
elem_ptr = elem_addr
if elem_type == 'i8':
if isinstance(elem_val.type, ir.IntType) and elem_val.type.width > 8:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(8), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
# 指针 → 整数:隐式转换一律禁止(元素值是指针、元素类型是整数)
# (None 已在上方短路为零值,不会落到这里)。
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
f"指针隐式转整数已禁止:数组字面量第 {i} 个元素是指针类型 {elem_val.type},"
f"但目标元素类型是 i8;如需转换请显式 cast(如 CUInt64T(p) / CInt(p))"
f"{Gen._DescribeValueNode(elem)}"
)
elif elem_type == 'i32':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 32:
elem_val = Gen.builder.zext(elem_val, ir.IntType(32), name=f"zext_elem_{i}")
elif elem_val.type.width > 32:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(32), name=f"trunc_elem_{i}")
elif isinstance(elem_val.type, ir.PointerType):
# 指针 → 整数:隐式转换一律禁止(ptrtoint 到 i32 还会截断地址)
# (None 已在上方短路为零值,不会落到这里)。
from lib.core.LLVMCG.FuncGen import FailFastError
raise FailFastError(
f"指针隐式转整数已禁止:数组字面量第 {i} 个元素是指针类型 {elem_val.type},"
f"但目标元素类型是 i32;如需转换请显式 cast(如 CUInt64T(p) / CInt(p))"
f"{Gen._DescribeValueNode(elem)}"
)
elif elem_type == 'i16':
if isinstance(elem_val.type, ir.IntType):
if elem_val.type.width < 16:
elem_val = Gen.builder.zext(elem_val, ir.IntType(16), name=f"zext_elem_{i}")
elif elem_val.type.width > 16:
elem_val = Gen.builder.trunc(elem_val, ir.IntType(16), name=f"trunc_elem_{i}")
elif elem_type == 'float':
if isinstance(elem_val.type, ir.DoubleType):
elem_val = Gen.builder.fptrunc(elem_val, ir.FloatType(), name=f"fptrunc_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.FloatType(), name=f"sitofp_elem_{i}")
elif elem_type == 'double':
if isinstance(elem_val.type, ir.FloatType):
elem_val = Gen.builder.fpext(elem_val, ir.DoubleType(), name=f"fpext_elem_{i}")
elif isinstance(elem_val.type, ir.IntType):
elem_val = Gen.builder.sitofp(elem_val, ir.DoubleType(), name=f"sitofp_elem_{i}")
Gen.builder.store(elem_val, elem_ptr)
if elem_type in ('float', 'double'):
return Gen.builder.bitcast(alloc_ptr, ir.PointerType(elem_llvm_type), name=f"list_{elem_type}_ptr")
return cast_ptr
def _HandleConstantLlvm(self, Node: ast.Constant, VarType: ir.Type | str | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
Value: Any = Node.value
if Value is None:
if VarType is not None and isinstance(VarType, ir.PointerType):
return ir.Constant(VarType, None)
return ir.Constant(ir.IntType(8).as_pointer(), None)
elif isinstance(Value, bool):
return ir.Constant(ir.IntType(32), 1 if Value else 0)
elif isinstance(Value, int):
# 整数字面量越界 fail-fast(字面量本身无符号,0..2^64-1):与 VPC 词法层
# `_lex_int_exceeds_u64` 同口径。负数侧由"一元减 + 字面量"的联合判定负责
# (HandlesExprOps._HandleUnaryOpLlvm),此处只判字面量本身。
RequireIntLiteralStorable(Gen, self.Trans, Node, Value)
# 显式宽度字面量(_int<N>/_uint<N>/_i<N>/_u<N>):先严格校验「不截断」,再按声明宽度出常量
ExpW: int = int(getattr(Node, 'int_width', 0) or 0)
if ExpW > 0:
ExpU: int = int(getattr(Node, 'int_unsigned', 0) or 0)
RequireExplicitWidthLiteral(Gen, self.Trans, Node, Value, ExpW, ExpU)
return ir.Constant(ir.IntType(ExpW), Value & ((1 << ExpW) - 1))
if VarType is not None:
if isinstance(VarType, ir.IntType):
return ir.Constant(VarType, Value & ((1 << VarType.width) - 1))
if isinstance(VarType, ir.PointerType):
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, (ir.FloatType, ir.DoubleType)):
return ir.Constant(VarType, float(Value))
if isinstance(VarType, str) and '*' in VarType:
return ir.Constant(ir.IntType(64), Value)
if isinstance(VarType, str):
resolved: Any = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls: type = resolved[0] if isinstance(resolved, tuple) else resolved
inst: Any = ctype_cls()
size: int = getattr(inst, 'Size', 32)
is_unsigned: bool = getattr(inst, 'IsSigned', True) is False
mask: int = (1 << size) - 1
return ir.Constant(ir.IntType(size), Value & mask)
llvm_match: re.Match | None = _RE_LLVM_INT_TYPE.match(VarType)
if llvm_match:
width: int = int(llvm_match.group(1))
return ir.Constant(ir.IntType(width), Value & ((1 << width) - 1))
if Value < 0 or Value > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), Value)
return ir.Constant(ir.IntType(32), Value & 0xFFFFFFFF)
elif isinstance(Value, float):
if VarType and isinstance(VarType, ir.FloatType):
return ir.Constant(VarType, Value)
elif VarType and isinstance(VarType, ir.DoubleType):
return ir.Constant(VarType, Value)
return ir.Constant(ir.DoubleType(), Value)
elif isinstance(Value, str):
is_wide: bool = getattr(Node, 'kind', None) == 'u'
# 引号类型推断:单引号单字符 → i8,双引号/多字符/三重 → i8*,空 → 0(None)
quote_char: str | None = None
is_triple: bool = False
if not is_wide:
col_offset: int = getattr(Node, 'col_offset', 0)
node_lineno: int = getattr(Node, 'lineno', 0)
# AST 的 lineno 可能不准确(常量节点可能指向下一行),
# 因此在 lineno 和 lineno-1 两行中查找引号
for try_lineno in (node_lineno, node_lineno - 1):
# AST 行号含 _inject_auto_imports 注入的 N 行,须经 _DiskLineno
# 还原成磁盘行号,否则取到 N 行之后的错行:引号判定只靠"错行同列
# 恰好也是引号"的巧合命中,一旦源码行数变动(单行化/增删行)就会
# 把 'x' 误判成字符串(i8*)→ 传给 int 形参时 fail-fast。
source_line: str | None = Gen._get_source_line(Gen._DiskLineno(try_lineno))
if not source_line:
continue
# col_offset 是 UTF-8 字节偏移(vast Tokenizer 口径)→ 转字符偏移;
# 前缀含多字节字符时二者不等,直接按字节偏移取字符会取错列。
char_col: int = len(source_line.encode('utf-8')[:col_offset].decode('utf-8', 'ignore'))
if char_col < len(source_line):
ch: str = source_line[char_col]
if ch in ("'", '"'):
quote_char = ch
if char_col + 2 < len(source_line) and source_line[char_col:char_col + 3] in ("'''", '"""'):
is_triple = True
break
# 空字符串 → 创建指向 \0 的全局变量 (而非 null, 避免 strcmp 解引用空指针崩溃)
# 走与非空字符串相同的路径, 由下方 else 分支处理
# 单引号单字符(非三重)→ i8
is_char_literal: bool = (not is_triple) and (quote_char == "'") and (len(Value) == 1) and not is_wide
if is_char_literal:
if VarType is not None and isinstance(VarType, ir.PointerType):
pass # 类型不匹配:目标是 ptr 但值是 char,走 string 路径
elif isinstance(VarType, ir.IntType):
return ir.Constant(VarType, ord(Value[0]))
elif isinstance(VarType, str):
resolved = _CR.ResolveName(VarType) or _CR.LLVMToCType(VarType)
if resolved:
ctype_cls = resolved[0] if isinstance(resolved, tuple) else resolved
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
return ir.Constant(ir.IntType(size), ord(Value[0]))
llvm_match = _RE_LLVM_INT_TYPE.match(VarType)
if llvm_match:
return ir.Constant(ir.IntType(int(llvm_match.group(1))), ord(Value[0]))
elif VarType is not None:
return ir.Constant(ir.IntType(8), ord(Value[0]))
else:
# 无类型提示:单引号单字符默认为 i8
return ir.Constant(ir.IntType(8), ord(Value[0]))
if is_wide:
str_value: str = Value + '\x00'
wide_chars: list[int] = [ord(c) for c in str_value]
target_count: int = len(wide_chars)
str_type: ir.ArrayType = ir.ArrayType(ir.IntType(16), target_count)
gv_name: str = f"str_const_{Gen.string_const_counter}"
gv: ir.GlobalVariable = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, wide_chars)
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr: Any = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
else:
str_value = Value + '\x00'
str_bytes: bytes = str_value.encode('utf-8')
target_count = len(str_bytes)
if isinstance(VarType, ir.ArrayType) and isinstance(VarType.element, ir.IntType) and VarType.element.width == 8:
target_count = VarType.count
if len(str_bytes) < target_count:
str_bytes = str_bytes + b'\x00' * (target_count - len(str_bytes))
else:
str_bytes = str_bytes[:target_count]
str_type = ir.ArrayType(ir.IntType(8), target_count)
gv_name = f"str_const_{Gen.string_const_counter}"
gv = ir.GlobalVariable(Gen.module, str_type, name=gv_name)
gv.initializer = ir.Constant(str_type, bytearray(str_bytes))
gv.linkage = 'internal'
Gen.string_const_counter += 1
ptr = Gen.builder.gep(gv, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"{gv_name}_cast")
return ptr
return ir.Constant(ir.IntType(32), 0)
def _HandleNameLlvm(self, Node: ast.Name, VarType: ir.Type | str | None = None,
ConstWidthHint: int | None = None) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
VarName: str = Node.id
# 治本修复:不把 module.globals 的 initializer 注入 _define_constants。
# 原因:CDefine(CDefine 注解)在 AnnAssign/Assign 处理时已注册到
# _define_constants 且不创建 LLVM global(不在 module.globals);
# module.globals 里全是可变全局变量(如 _sha1_store_count,有 += 写入),
# 若把其 initializer 当常量传播,会导致 range(_sha1_store_count) 被求值成
# range(0)、printf 印 0 等问题(读取处不生成 load)。
# CDefine 的本模块优先靠下方 _define_constants 查询保证,双点 bug 不复发。
define_constants: dict[str, Any] = getattr(Gen, '_define_constants', {})
# 治本防护:module.globals 里的都是可变全局变量(CDefine 不创建 LLVM global,
# 仅注册到 _define_constants)。可变全局有 += 等写入,不能当常量传播,
# 跳过 _define_constants 查询,直接走下方 variables/global_vars/module.globals 的 load。
if VarName in define_constants and not (hasattr(Gen, 'module') and VarName in Gen.module.globals):
val: Any = define_constants[VarName]
# CDefine 常量注册值(用于使用处宽度判据;下方 _gvar 覆盖是"同名全局变量"
# 的既有特例,不应把变量值当常量做宽度判据)
_cdefine_val: Any = val
# 治本修复:本模块全局变量初始化值优先,避免跨模块同名 CDefine 通过
# 共享 _define_constants 覆盖本模块常量
# (VpiReader.SHA1_LEN=16 被 Phase1.SHA1_LEN=17 覆盖导致双点符号 bug)
_gvar: Any = None
try:
if hasattr(Gen, 'module') and VarName in Gen.module.globals:
_gvar = Gen.module.globals[VarName]
except Exception:
_gvar = None
if _gvar is not None and getattr(_gvar, 'initializer', None) is not None:
_init: Any = _gvar.initializer
if isinstance(_init, ir.Constant) and isinstance(_init.constant, (int, float, str)):
val = _init.constant
if isinstance(val, int):
# 使用处宽度(唯一判据 SymbolUtils.RequireDefineUseWidth):
# 上下文(赋值目标 / 形参 / 返回注解 / 运算对象…)给出的位宽更宽 ⇒
# 就地按该宽度物化(立即数升宽无损);更窄 ⇒ fail-fast(替换此前的
# `val & mask` 静默截断)。
# 宽度来源优先级:**窄通道 ConstWidthHint**(仅常量物化读取,由调用
# 装配处按形参/返回类型下传)> 既有尽宽通道 VarType(赋值目标 /
# 二元运算对象)。两者都取不到 ⇒ 落到下方既有 32/64 二值口径。
_use_ty: ir.Type | None = None
# 报文的"使用处"标签按**通道**取真实站点种类(不再写笼统的
# "由调用方下传的类型提示"):窄通道 ConstWidthHint 只由
# 调用装配处(形参)与返回处下传;既有 VarType 通道承载的是
# 赋值目标 / 二元运算对象类型。
_use_ctx: str = '赋值目标 / 运算对象类型'
if ConstWidthHint in (8, 16, 32, 64):
_use_ty = ir.IntType(int(ConstWidthHint))
_use_ctx = '形参 / 返回注解'
elif VarType is not None and isinstance(VarType, ir.IntType):
_use_ty = VarType
if isinstance(_use_ty, ir.IntType):
RequireDefineUseWidthAt(Gen, self.Trans, Node, _cdefine_val,
int(_use_ty.width), VarName, _use_ctx)
return ir.Constant(_use_ty, val & ((1 << _use_ty.width) - 1))
# 带类型注册:无使用处宽度提示时,按 define 的**声明类型**物化
# (`define X: DWORD = -11` → i32 位型 0xFFFFFFF5,而不是按值大小猜 i64)。
_dtv: tuple[int, int] | None = DefineDeclTypeValue(
getattr(Gen, '_define_decl_types', None) or getattr(self.Trans, '_define_decl_types', None), VarName, val)
if _dtv is not None:
return ir.Constant(ir.IntType(_dtv[0]), _dtv[1])
if VarName in Gen.var_signedness and Gen.var_signedness[VarName]:
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
# 治本修复(方案C):CDefine 不通过共享 SymbolTable 跨模块裸名共享。
# 此处不再消费 SymbolTable 中的 IsDefine 符号,避免其他模块 CDefine
# 覆盖本模块同名全局变量(VpiReader.SHA1_LEN=16 被 Phase1.SHA1_LEN=17 覆盖)。
# 本模块 CDefine 已在步骤1(_define_constants)解析;
# 跨模块 CDefine 通过 _RegisterFromImportAliases 显式导入注册到 _define_constants。
# 治本修复:如果符号表也没有,回退查询 _all_define_constants
# _all_define_constants 由 Phase2Translator 从所有 .pyi 文件预提取,
# 包含跨模块导入的 CDefine 常量(如 FOREGROUND_GREEN、STD_OUTPUT_HANDLE)
if VarName not in define_constants and VarName not in Gen.variables and not GlobalDeclShadowsDefine(Gen, VarName):
all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
if VarName in all_dc:
val: Any = all_dc[VarName]
if isinstance(val, int):
# 跨模块 CDefine 常量同口径:窄通道 ConstWidthHint(形参/返回
# 类型下传)优先,其次既有 VarType;更宽 ⇒ 按该宽度物化,
# 更窄 ⇒ fail-fast(判据唯一源 SymbolUtils.RequireDefineUseWidth)
_use_ty2: ir.Type | None = None
_use_ctx2: str = '赋值目标 / 运算对象类型'
if ConstWidthHint in (8, 16, 32, 64):
_use_ty2 = ir.IntType(int(ConstWidthHint))
_use_ctx2 = '形参 / 返回注解'
elif VarType is not None and isinstance(VarType, ir.IntType):
_use_ty2 = VarType
if isinstance(_use_ty2, ir.IntType):
RequireDefineUseWidthAt(Gen, self.Trans, Node, val,
int(_use_ty2.width), VarName, _use_ctx2)
return ir.Constant(_use_ty2, val & ((1 << _use_ty2.width) - 1))
# 带类型注册:同本模块路径——按声明类型物化(见上)。
_dtv2: tuple[int, int] | None = DefineDeclTypeValue(
getattr(Gen, '_define_decl_types', None) or getattr(self.Trans, '_define_decl_types', None), VarName, val)
if _dtv2 is not None:
return ir.Constant(ir.IntType(_dtv2[0]), _dtv2[1])
if val < -(1 << 31) or val > 0xFFFFFFFF:
return ir.Constant(ir.IntType(64), val & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val & 0xFFFFFFFF)
elif isinstance(val, float):
return ir.Constant(ir.DoubleType(), val)
elif isinstance(val, str):
return Gen._create_string_global(val)
# 优先检查 variables(alloca),因为变量可能已被 += 等操作迁移到 variables
if VarName in Gen.variables and Gen.variables[VarName] is not None:
VarPtr: Any = Gen.variables[VarName]
if isinstance(VarPtr, ir.GlobalVariable) and isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
if isinstance(VarPtr.type, ir.PointerType) and isinstance(VarPtr.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
return VarPtr
# 防御性恢复:对于 double-pointer(如 ndarray**,pointee 是 PointerType)
# 或其他非结构体类型,若 global_struct_class 已记录该变量的类名,
# 也恢复 var_struct_class。这确保方法调用能查找到正确的特化类
# (如 ndarray[double]),而非 fallback 到 opaque 基础类型。
if VarName in Gen.global_struct_class and VarName not in Gen.var_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
loaded: ir.Value = Gen._load(VarPtr, name=VarName)
# 大端局部变量:读取时 bswap 还原
loaded = Gen._apply_bswap_if_big(loaded, getattr(Gen, 'local_var_byteorders', {}).get(VarName, ""), f"bswap_load_{VarName}")
return loaded
if VarName in Gen._reg_values:
return Gen._reg_values[VarName]
if VarName in Gen._direct_values:
return Gen._direct_values[VarName]
if VarName in Gen.global_vars and VarName in Gen.module.globals:
GVar: Any = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName in Gen.module.globals:
GVar = Gen.module.globals[VarName]
Gen.variables[VarName] = GVar
if isinstance(GVar, ir.Function):
return GVar
if VarName in Gen.global_struct_class:
Gen.var_struct_class[VarName] = Gen.global_struct_class[VarName]
if isinstance(GVar.type, ir.PointerType) and isinstance(GVar.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
return GVar
return Gen._load(GVar, name=VarName)
if VarName == 'self':
# 治本修复:方法名为 _get_var_ptr(小写),原 GetVarPtr 不存在会抛 AttributeError。
# 当 self 未注册到 variables 时(如 opaque struct 参数走了 else 分支),
# 通过 _get_var_ptr 兜底返回 None,由调用方处理。
SelfPtr: ir.Value | None = Gen._get_var_ptr('self')
if SelfPtr is not None:
return SelfPtr
# 最终兜底:若 _get_var_ptr 返回 None(self 既不在 _reg_values 也不在 variables),
# 直接返回函数参数本身(LLVM Argument)。这避免了 AttributeError 导致的异常路径。
for arg in getattr(Gen.func, 'args', []):
if getattr(arg, 'name', None) == 'self':
return arg
return ir.Constant(ir.IntType(32), 0)
if Gen._has_function(VarName):
func: Any = Gen._get_function(VarName)
if func:
return Gen.builder.bitcast(func, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
if VarName in Gen.class_methods:
return ir.Constant(ir.IntType(8).as_pointer(), None)
if VarName == 'True' or VarName == 'False':
return ir.Constant(ir.IntType(32), 1 if VarName == 'True' else 0)
SymInfo: Any = self.Trans.SymbolTable.lookup(VarName)
if SymInfo:
if SymInfo.IsEnumMember and isinstance(SymInfo.value, int):
return ir.Constant(Gen._enum_int_type(SymInfo.EnumName, SymInfo), SymInfo.value)
if SymInfo.IsFunction or SymInfo.IsFuncPtr:
MangledName: str = Gen._mangle_func_name(VarName)
if MangledName in Gen.module.globals:
g: Any = Gen.module.globals[MangledName]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
for sha1 in Gen.ModuleSha1Map.values():
prefixed: str = f"{sha1}.{VarName}"
if prefixed in Gen.module.globals:
g = Gen.module.globals[prefixed]
if isinstance(g, ir.Function):
Gen.functions[VarName] = g
return Gen.builder.bitcast(g, ir.IntType(8).as_pointer(), name=f"funcptr_{VarName}")
t_c_imported: dict[str, tuple[str, str]] = getattr(self.Trans, '_from_import_aliases', {})
if VarName in t_c_imported:
src_module: str
src_name: str
src_module, src_name = t_c_imported[VarName]
virtual_attr: ast.Attribute = ast.Attribute(
value=ast.Name(id=src_module, ctx=ast.Load()),
attr=src_name,
ctx=ast.Load()
)
ast.copy_location(virtual_attr, Node)
return self.Trans.ExprAttrHandle._HandleAttributeLlvm(virtual_attr)
# fail-fast: 未定义名称禁止静默物化为 i32 0(会把常量名写错 / define 丢失 /
# 变量漏声明这类上游缺陷藏到运行期,见 RequireNameDefined 的头注释)。
RequireNameDefined(Gen, self.Trans, Node, VarName)
return ir.Constant(ir.IntType(32), 0)