删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
622 lines
38 KiB
Python
622 lines
38 KiB
Python
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) |