perf(全仓库/正则): 字面量正则全部改模块级预编译常量(15 文件 / 115 个调用点)

背景(prof 基线 PROF/20260930_224857,主进程 433.69s):正则这一族合计 ≈45s ——
`re.match`(未预编译入口)被调 1970 万次 / 自身 10.70s、它内部 `Pattern.match` 占 8.06s,
`re._compile`(缓存查找)1975 万次 / 7.19s,`re._make`(真正编译)274 万次 / 7.62s
(说明 re 的 512 条缓存已被打穿,每 7 次调用就有 1 次重新编译)。
每次 `re.match(字面量, s)` 都要做"模式串哈希 → 缓存查找";预编译后这层全省掉。

改动:把 15 个文件里 97 处"字面量当模式"的 `re.match/search/sub/subn/fullmatch/
findall/finditer/split(...)` 提升为模块级 `_RE_*: re.Pattern[str] = re.compile(...)`,
共 115 个调用点(含同字面量跨处共用)。模式串与 flags 一字未改(flags 从调用处
搬进 re.compile,含原先以**位置参数**传入的 flags)。4 处拼接型动态模式按设计不动
(FuncGen 2 处、HandlesImports 2 处)。

核验(不靠肉眼):写了 AST 指纹对拍脚本,对每个文件取 HEAD 版与新工作区版,把
"旧 re.<m>(字面量, 其余实参, 关键字) + flags" 与 "新 _RE_X.<m>(实参, 关键字) +
常量 (模式, flags)" 做多重集比对 —— 15 个文件、115 个调用点全部逐一等价(0 失败),
另查无重名常量、无遗留字面量调用、GetDiagnostics 全空。
对拍过程中查出一处子代理抄写错误:`_RE_GLOBAL_DSOLOCAL_MULTILINE` 丢了行首锚 `^`
(原文注释明确"使用 ^ + MULTILINE 避免匹配字符串常量内容中的 define/declare"),已修正。

同轮经查证后**未做改动**的两项(避免把假热点当真事修):
- VLogger 的 `re.sub` 6.43s:profile 当时的 VLogger 版本里根本没有 `import re`
  (`git show 3658ab06:lib/core/VLogger.py` 已确认),属 C 帧错挂,不做。
- tokenize 274 万次:那是 `_generate_tokens_from_c_tokenizer` 的 **token 产出次数**
  (≈350 个整文件的词法量),SymbolUtils 的 4 个 tokenize 调用点 nc 仅数百,且已有
  `_EXPAND_CACHE` 去重;再加一层 token 缓存无收益,不做。
This commit is contained in:
TermiNexus committed 2026-09-30 23:47:36 +08:00
1 parent 4641777db1
commit b18d57fa38
15 files changed
+318 -96

No files matched your search

+10 -5
View File
@@ -11,9 +11,14 @@ from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import (
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode,
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr,
EnumClassIntWidth, ClassHasFuncLevelCVTable)
EnumClassIntWidth, ClassHasFuncLevelCVTable)
# 泛型特化(`_SubstituteTypeArgs`)把 `%"SHA1.T"` / `%"SHA1.T"*` 替换为 i8* 用的
# **预编译**正则(性能:字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_T_TYPE_PTR: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"\*')
_RE_T_TYPE: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"')
class DeclarationGenerator:
"""从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)"""
@@ -1060,9 +1065,9 @@ class DeclarationGenerator:
for mt in member_types:
new_mt: str = mt
# 将 %"SHA1.T"* 替换为 i8*(不透明指针)
new_mt = re.sub(r'%"[a-f0-9]+\.T"\*', 'i8*', new_mt)
new_mt = _RE_T_TYPE_PTR.sub('i8*', new_mt)
# 将 %"SHA1.T"(非指针,如 embedded struct)替换为 i8*
new_mt = re.sub(r'%"[a-f0-9]+\.T"', 'i8*', new_mt)
new_mt = _RE_T_TYPE.sub('i8*', new_mt)
result.append(new_mt)
return result
+67 -20
View File
@@ -235,6 +235,53 @@ _RE_AT_EXTERNAL: re.Pattern[str] = re.compile(r'@\S+\s*=\s*external\s+')
_RE_DECLARE_FULL: re.Pattern[str] = re.compile(
r'^declare\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(')
# 其余字面量正则的模块级预编译(同一性能理由:省掉每次调用的"模式串哈希 →
# re 缓存查找";模式串一字未改,flags 原样保留)。凡模式串不同或 flags 不同
# (有/无 re.MULTILINE)之处都各自独立成常量,保证匹配语义逐字不变。
# `_AddWeakComdat`:定位函数头第一个元数据(`!...`)附着点 / 全局定义尾部属性插入点
_RE_METADATA_ATTACH: re.Pattern[str] = re.compile(r'\s![\w.]')
_RE_COMDAT_TAIL_ATTRS: re.Pattern[str] = re.compile(r',\s*(?:align|section|partition|code_model)\b')
# LLVM 22+ external global 带初值 → linkonce(带行首锚 + MULTILINE)
_RE_EXTERNAL_GLOBAL_VALUE: re.Pattern[str] = re.compile(
r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$',
re.MULTILINE)
# 同上但**不带行首锚**(opt 内联后整段内容替换处)
_RE_EXTERNAL_GLOBAL_VALUE_PLAIN: re.Pattern[str] = re.compile(
r'(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$',
re.MULTILINE)
# define/declare 后跟显式链接性关键字 → 其后补 dso_local
_RE_DEFINE_DECLARE_LINKAGE: re.Pattern[str] = re.compile(
r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+',
re.MULTILINE)
# define/declare 后无链接性/dso_local(含 `@` 分支)→ 直接补 dso_local
_RE_DEFINE_DECLARE_NO_LINKAGE_AT: re.Pattern[str] = re.compile(
r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)',
re.MULTILINE)
# 同上但**无 `@` 分支**(traceback include 模块专用)
_RE_DEFINE_DECLARE_NO_LINKAGE: re.Pattern[str] = re.compile(
r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)',
re.MULTILINE)
# 全局定义(非 llvm.*)带链接性关键字 → 补 dso_local(无 MULTILINE)
_RE_GLOBAL_LINKAGE: re.Pattern[str] = re.compile(
r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)')
# 同上但带 MULTILINE
_RE_GLOBAL_LINKAGE_MULTILINE: re.Pattern[str] = re.compile(
r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)',
re.MULTILINE)
# 全局定义无链接性 → 补 dso_local(无 MULTILINE)
_RE_GLOBAL_DSOLOCAL: re.Pattern[str] = re.compile(
r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)')
# 同上但带 MULTILINE(原文此处带行首锚 `^`:避免匹配到字符串常量内容里的 global/constant)
_RE_GLOBAL_DSOLOCAL_MULTILINE: re.Pattern[str] = re.compile(
r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)',
re.MULTILINE)
# 收集已定义函数名(define 头)
_RE_DEFINE_HEAD: re.Pattern[str] = re.compile(
r'^define\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(',
re.MULTILINE)
# 判定 IR 是否含 define 行(traceback 警告)
_RE_DEFINE_LINE: re.Pattern[str] = re.compile(r'^define ', re.MULTILINE)
def _ParseDwarfLineRows(dump_text: str) -> list[tuple[int, str, int]]:
"""从 llvm-dwarfdump 输出解析出 [(地址, 文件绝对路径, 行号)]。
@@ -989,7 +1036,7 @@ def _AddWeakComdat(ll_content: str) -> str:
# "expected '{' in function body"(`[^{]*` 会跨行吞掉换行,--dwarf 给
# 每个 define 行尾加了 !dbg 后插入点就落到了附着之后)。故插入点前移到
# 第一个元数据附着之前。
attach = re.search(r'\s![\w.]', head)
attach = _RE_METADATA_ATTACH.search(head)
if attach is None:
return head + ' comdat ' + m.group(4)
return head[:attach.start()] + ' comdat' + head[attach.start():] + m.group(4)
@@ -1004,7 +1051,7 @@ def _AddWeakComdat(ll_content: str) -> str:
if ' comdat' in line:
return line
comdat_names.append(m.group(3))
ins = re.search(r',\s*(?:align|section|partition|code_model)\b', line)
ins = _RE_COMDAT_TAIL_ATTRS.search(line)
if ins:
return line[:ins.start()] + ', comdat' + line[ins.start():]
return line + ', comdat'
@@ -2285,7 +2332,7 @@ class Phase2Translator:
'--traceback: traceback 模块未注入 @llvm.global_ctors '
'(模块级收尾钩子未生效,不静默降级)')
# 修复 LLVM 22+: external global 不能有初值,改为 linkonce
result = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', result, flags=re.MULTILINE)
result = _RE_EXTERNAL_GLOBAL_VALUE.sub(r'\1 = linkonce global \2 \3', result)
# 后处理:添加 llvmlite 不支持的 LLVM 属性(如 willreturn, mustprogress)
pending_str_attrs = getattr(trans.translator.LlvmGen, '_pending_str_attrs', None)
if pending_str_attrs:
@@ -2524,12 +2571,12 @@ class Phase2Translator:
else:
_vlog().info(" [内联] 跨模块内联优化完成")
opt_content = _ReadTextCached(optimized_ll)
opt_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', opt_content, flags=re.MULTILINE)
opt_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', opt_content, flags=re.MULTILINE)
opt_content = _RE_DEFINE_DECLARE_LINKAGE.sub(r'\1 \2 dso_local ', opt_content)
opt_content = _RE_DEFINE_DECLARE_NO_LINKAGE_AT.sub(r'\1 dso_local ', opt_content)
# LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义
opt_content = re.sub(r'(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', opt_content, flags=re.MULTILINE)
opt_content = re.sub(r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', opt_content)
opt_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', opt_content)
opt_content = _RE_EXTERNAL_GLOBAL_VALUE_PLAIN.sub(r'\1 = linkonce global \2 \3', opt_content)
opt_content = _RE_GLOBAL_LINKAGE.sub(r'\1 = \2 dso_local \3', opt_content)
opt_content = _RE_GLOBAL_DSOLOCAL.sub(r'\1 = dso_local \2', opt_content)
opt_content = _AddWeakComdat(opt_content)
with open(optimized_ll, 'w', encoding='utf-8') as f:
f.write(opt_content)
@@ -2756,16 +2803,16 @@ class Phase2Translator:
break
ll_lines = ll_content.splitlines(True)
ll_content = ''.join(ll_lines[:header_end]) + stub_prefix + ''.join(ll_lines[header_end:])
ll_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = _RE_DEFINE_DECLARE_LINKAGE.sub(r'\1 \2 dso_local ', ll_content)
ll_content = _RE_DEFINE_DECLARE_NO_LINKAGE_AT.sub(r'\1 dso_local ', ll_content)
# LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义
ll_content = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content, flags=re.MULTILINE)
ll_content = _RE_EXTERNAL_GLOBAL_VALUE.sub(r'\1 = linkonce global \2 \3', ll_content)
ll_content = _RE_GLOBAL_LINKAGE_MULTILINE.sub(r'\1 = \2 dso_local \3', ll_content)
ll_content = _RE_GLOBAL_DSOLOCAL_MULTILINE.sub(r'\1 = dso_local \2', ll_content)
ll_content = _AddWeakComdat(ll_content)
# LLVM 22+: 移除同一模块中已有 define 的 declare 语句(LLVM 22 将 declare+define 视为重复定义)
defined_funcs: set[str] = set()
for m in re.finditer(r'^define\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(', ll_content, re.MULTILINE):
for m in _RE_DEFINE_HEAD.finditer(ll_content):
defined_funcs.add(m.group(1))
if defined_funcs:
lines: list[str] = ll_content.splitlines(True)
@@ -3622,19 +3669,19 @@ class Phase2Translator:
# **只警告、不报错**:像 includes/stdarg.vp 这类模块的 define 是"合成"的
# (由 extern/sugar 派生、无 .vp 函数体),本就不会有源级 DI —— 按 fail-fast
# 报错会把这类模块全部误杀;而"行号缺失"只降低可读性,不是编译正确性问题。
if self.traceback_enabled and re.search(r'^define ', ll_content, re.MULTILINE) \
if self.traceback_enabled and _RE_DEFINE_LINE.search(ll_content) \
and '!llvm.dbg.cu' not in ll_content:
_vlog().warning(
f"--traceback: include 模块 {module_name}.py 发射了 define 但 IR 未携带 "
f"DWARF (!llvm.dbg.cu)——该模块内联帧在 Ctrl+C 栈里将只显示地址: {ll_path}")
# dso_local 正则标注(使用 ^ + MULTILINE 避免匹配字符串常量内容中的 define/declare)
ll_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)', r'\1 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = _RE_DEFINE_DECLARE_LINKAGE.sub(r'\1 \2 dso_local ', ll_content)
ll_content = _RE_DEFINE_DECLARE_NO_LINKAGE.sub(r'\1 dso_local ', ll_content)
# LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义
ll_content = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content, flags=re.MULTILINE)
ll_content = _RE_EXTERNAL_GLOBAL_VALUE.sub(r'\1 = linkonce global \2 \3', ll_content)
ll_content = _RE_GLOBAL_LINKAGE_MULTILINE.sub(r'\1 = \2 dso_local \3', ll_content)
ll_content = _RE_GLOBAL_DSOLOCAL_MULTILINE.sub(r'\1 = dso_local \2', ll_content)
ll_content = _AddWeakComdat(ll_content)
# stub_decls 注入(复用预收集的 stub_decls)
+6 -2
View File
@@ -14,6 +14,10 @@ from lib.core.SymbolUtils import IsListAnnotation, ExpandSoftKeywords
_ConvertResultCache: dict[tuple[str, str], str] = {}
_ConvertCacheMaxSize: int = 4096
# 提取 import 语句行尾注释(`_GetImportString` / `_GetImportFromString`)用的
# **预编译**正则(性能:字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_LINE_COMMENT: re.Pattern[str] = re.compile(r'#.*$')
class PythonToStubConverter:
"""将 Python 文件转换为存根格式"""
@@ -883,7 +887,7 @@ class PythonToStubConverter:
LineIdx: int = node.lineno - 1
if 0 <= LineIdx < len(SourceLines):
line: str = SourceLines[LineIdx]
CommentMatch: re.Match | None = re.search(r'#.*$', line)
CommentMatch: re.Match | None = _RE_LINE_COMMENT.search(line)
if CommentMatch:
result += ' ' + CommentMatch.group(0)
@@ -918,7 +922,7 @@ class PythonToStubConverter:
LineIdx = node.lineno - 1
if 0 <= LineIdx < len(SourceLines):
line = SourceLines[LineIdx]
CommentMatch: re.Match | None = re.search(r'#.*$', line)
CommentMatch: re.Match | None = _RE_LINE_COMMENT.search(line)
if CommentMatch:
comment = ' ' + CommentMatch.group(0)
+7 -2
View File
@@ -14,6 +14,11 @@ from lib.core.stub_generator import CHeaderParser, PythonStubGenerator, CTypeMap
from lib.StubGen.Config import StubGenConfig
from lib.StubGen.Converter import PythonToStubConverter
# `_GenerateGuardName` 生成宏守卫名用的**预编译**正则
# (性能:字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_NON_GUARD_CHAR: re.Pattern[str] = re.compile(r'[^a-zA-Z0-9_]')
_RE_MULTI_UNDERSCORE: re.Pattern[str] = re.compile(r'_+')
class StubGen:
"""存根生成器主类"""
@@ -90,8 +95,8 @@ class StubGen:
BaseName: str = os.path.splitext(os.path.basename(FilePath))[0]
# 转换为大写,替换特殊字符为下划线
guard: str = re.sub(r'[^a-zA-Z0-9_]', '_', BaseName).upper()
guard = re.sub(r'_+', '_', guard) # 合并多个下划线
guard: str = _RE_NON_GUARD_CHAR.sub('_', BaseName).upper()
guard = _RE_MULTI_UNDERSCORE.sub('_', guard) # 合并多个下划线
guard = guard.strip('_')
return f'{guard}_DEFINE_H'
+13 -3
View File
@@ -12,6 +12,16 @@ from lib.includes.t import CTypeRegistry as _CR
from lib.core.SymbolUtils import RequireDefineUseWidthAt, RequireIntLiteralStorable, RequireNameDefined
# ---------------------------------------------------------------
# 注解/常量折叠里的正则**预编译**(性能:避免每次 `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。
@@ -120,7 +130,7 @@ class ExprHandle(BaseHandle):
elem_type: str = 'i8'
if VarType and isinstance(VarType, str) and 'list[' in VarType:
match: re.Match | None = re.search(r'list\[([^,\]]+)(?:,\s*(\d+))?\]', VarType)
match: re.Match | None = _RE_LIST_ELEM_TYPE.search(VarType)
if match:
type_str: str = match.group(1).strip()
if match.group(2):
@@ -292,7 +302,7 @@ class ExprHandle(BaseHandle):
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.match(r'^i(\d+)$', VarType)
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))
@@ -340,7 +350,7 @@ class ExprHandle(BaseHandle):
inst = ctype_cls()
size = getattr(inst, 'Size', 32)
return ir.Constant(ir.IntType(size), ord(Value[0]))
llvm_match = re.match(r'^i(\d+)$', VarType)
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:
+14 -3
View File
@@ -10,6 +10,17 @@ from lib.core.Handles.HandlesBase import BaseHandle
from lib.core.SymbolUtils import IsTModule
from lib.includes import t
# ---------------------------------------------------------------
# asm 模板重写用的正则**预编译**(性能:避免每次 `re.sub(字面量, ...)` 都要做
# "模式串哈希 → re 模块级缓存查找"。语义与逐字写法完全一致,模式串一字未改)。
# ---------------------------------------------------------------
# Intel 语法模板里的 `%0`/`%1` 占位操作数 → `$0`/`$1`
_RE_INTEL_FMT_OPERAND: re.Pattern[str] = re.compile(r'%(\d+)')
# Intel 语法模板里的 `%name` 具名操作数 → 去掉前缀 `%`
_RE_INTEL_FMT_NAMED: re.Pattern[str] = re.compile(r'%([a-zA-Z][a-zA-Z0-9]*)')
# asm 模板里 `call <符号>` 的函数名重写(保留 `call ` 前缀,只改写符号名)
_RE_ASM_CALL: re.Pattern[str] = re.compile(r'(call\s+)(\w+)')
# 猴子补丁 llvmlite.ir.InlineAsm 以支持 asm_dialect 参数
# 添加保护避免重复补丁
_InlineAsmPatched = getattr(ir.InlineAsm, '_transpyc_patched', False)
@@ -182,8 +193,8 @@ class ExprAsmHandle(BaseHandle):
return None
def _prepare_intel_asm(self, template: str) -> str:
template = re.sub(r'%(\d+)', r'$\1', template)
template = re.sub(r'%([a-zA-Z][a-zA-Z0-9]*)', r'\1', template)
template = _RE_INTEL_FMT_OPERAND.sub(r'$\1', template)
template = _RE_INTEL_FMT_NAMED.sub(r'\1', template)
return template
def _normalize_asm_template(self, template: str) -> str:
@@ -323,7 +334,7 @@ class ExprAsmHandle(BaseHandle):
return f'{prefix}\\22{mangled}\\22'
return f"{prefix}{mangled}"
return re.sub(r'(call\s+)(\w+)', replace_call, template)
return _RE_ASM_CALL.sub(replace_call, template)
def _HandleAsmWithOpLlvm(self, asm_template_arg: ast.AST, op_arg: ast.AST | None = None, input_arg: ast.AST | None = None, output_arg: ast.AST | None = None, asm_format: str = 'Intel') -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
+49 -15
View File
@@ -28,6 +28,40 @@ _LEN_SUPPORTED_HINT: str = (
)
# PROF 热点:_EmitLLVMIRInstruction 对每条 IR 模板都要做多次 re.match / re.split,
# 未预编译的模块级入口每次都要「模式串哈希 → re 缓存查找 → 未命中就重新编译」,
# 512 条缓存被打穿后开销巨大。这些模式全是字面量 → 提升为模块级预编译常量。
# 模式串与调用点处的字面量逐字一致,语义不变。
# _EmitLLVMIRInstruction 用:剥离 IR 模板前置的结果赋值 `%__OPn__ = `
_RE_OP_ASSIGN: re.Pattern[str] = re.compile(r'%__OP(\d+)__\s*=\s*(.+)')
# _EmitLLVMIRInstruction 用:整数比较指令 icmp
_RE_ICMP: re.Pattern[str] = re.compile(r'icmp\s+(\w+)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:浮点比较指令 fcmp
_RE_FCMP: re.Pattern[str] = re.compile(r'fcmp\s+([\w\s]+?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:select 指令
_RE_SELECT: re.Pattern[str] = re.compile(r'select\s+i1\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:Load 指令
_RE_LOAD: re.Pattern[str] = re.compile(r'Load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:store 指令
_RE_STORE: re.Pattern[str] = re.compile(r'store\s+(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:getelementptr 指令
_RE_GEP: re.Pattern[str] = re.compile(r'getelementptr\s+(?:inbounds\s+)?(\w+),\s*(\w+)\s+%__OP(\d+)__,\s*(.+)')
# _EmitLLVMIRInstruction 用:单个 %__OPn__ 操作数占位引用
_RE_OP_REF: re.Pattern[str] = re.compile(r'%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:取负形式 sub 指令
_RE_NEG: re.Pattern[str] = re.compile(r'sub\s+(\w+)\s+(\d+),\s*%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:按位取反形式 xor 指令
_RE_NOT: re.Pattern[str] = re.compile(r'xor\s+(\w+)\s+(-1|\d+),\s*%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:call 指令
_RE_CALL: re.Pattern[str] = re.compile(r'call\s+(\w+)\s+@([\w.]+)\((.+)\)')
# _EmitLLVMIRInstruction 用:调用参数中的「类型 %__OPn__」片段
_RE_TYPED_OP: re.Pattern[str] = re.compile(r'(\w+\*?)\s+%__OP(\d+)__')
# _EmitLLVMIRInstruction 用:调用参数中的「类型 常量」片段
_RE_CONST: re.Pattern[str] = re.compile(r'(\w+)\s+(-?\d+)')
# _EmitLLVMIRInstruction 用:以逗号切分操作数列表(逗号 + 任意空白)
_RE_COMMA_WS: re.Pattern[str] = re.compile(r',\s*')
def _safe_ptr_type(ty: ir.Type) -> ir.Type:
"""LLVM IR 中不允许 void* 指针,Ptr(VoidType) 统一替换为 i8*(对应 C 的 void* 语义)"""
if isinstance(ty, ir.PointerType):
@@ -1520,7 +1554,7 @@ class ExprCallHandle(BaseHandle):
return output_targets[local_idx]
return None
assign_match = re.match(r'%__OP(\d+)__\s*=\s*(.+)', template)
assign_match = _RE_OP_ASSIGN.match(template)
if assign_match:
template = assign_match.group(2).strip()
@@ -1532,7 +1566,7 @@ class ExprCallHandle(BaseHandle):
'and': 'and_', 'or': 'or_', 'xor': 'xor_',
}
icmp_match = re.match(r'icmp\s+(\w+)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template)
icmp_match = _RE_ICMP.match(template)
if icmp_match:
pred: str = icmp_match.group(1)
op1 = resolve_op(int(icmp_match.group(3)))
@@ -1556,7 +1590,7 @@ class ExprCallHandle(BaseHandle):
result = icmp_method(llvmlite_pred, op1, op2, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
fcmp_match = re.match(r'fcmp\s+([\w\s]+?)\s+(\w+)\s+%__OP(\d+)__,\s*%__OP(\d+)__', template)
fcmp_match = _RE_FCMP.match(template)
if fcmp_match:
pred_raw: str = fcmp_match.group(1).strip()
# 分离 fast 修饰符(可能是 "oeq fast" 或 "fast oeq")
@@ -1599,7 +1633,7 @@ class ExprCallHandle(BaseHandle):
result = method(op1, op2, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
select_match = re.match(r'select\s+i1\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template)
select_match = _RE_SELECT.match(template)
if select_match:
cond = resolve_op(int(select_match.group(1)))
true_val = resolve_op(int(select_match.group(3)))
@@ -1627,14 +1661,14 @@ class ExprCallHandle(BaseHandle):
result = method(src_val, dest_type, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
Load_match = re.match(r'Load\s+(\w+),\s*(\w+)\s+%__OP(\d+)__', template)
Load_match = _RE_LOAD.match(template)
if Load_match:
ptr_val = resolve_op(int(Load_match.group(3)))
if ptr_val:
result = Gen.builder.load(ptr_val, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
store_match = re.match(r'store\s+(\w+)\s+%__OP(\d+)__,\s*(\w+)\s+%__OP(\d+)__', template)
store_match = _RE_STORE.match(template)
if store_match:
val = resolve_op(int(store_match.group(2)))
ptr = resolve_op(int(store_match.group(4)))
@@ -1642,15 +1676,15 @@ class ExprCallHandle(BaseHandle):
Gen.builder.store(val, ptr)
return ir.Constant(ir.IntType(32), 0)
gep_match = re.match(r'getelementptr\s+(?:inbounds\s+)?(\w+),\s*(\w+)\s+%__OP(\d+)__,\s*(.+)', template)
gep_match = _RE_GEP.match(template)
if gep_match:
ptr_val = resolve_op(int(gep_match.group(3)))
indices_str = gep_match.group(4)
if ptr_val:
indices = []
for idx_part in re.split(r',\s*', indices_str):
for idx_part in _RE_COMMA_WS.split(indices_str):
idx_part = idx_part.strip()
idx_m = re.match(r'%__OP(\d+)__', idx_part)
idx_m = _RE_OP_REF.match(idx_part)
if idx_m:
idx_op = resolve_op(int(idx_m.group(1)))
if idx_op:
@@ -1664,7 +1698,7 @@ class ExprCallHandle(BaseHandle):
result = Gen.builder.gep(ptr_val, indices, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
neg_match = re.match(r'sub\s+(\w+)\s+(\d+),\s*%__OP(\d+)__', template)
neg_match = _RE_NEG.match(template)
if neg_match:
op = resolve_op(int(neg_match.group(3)))
if op:
@@ -1672,7 +1706,7 @@ class ExprCallHandle(BaseHandle):
result = Gen.builder.sub(zero, op, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
not_match = re.match(r'xor\s+(\w+)\s+(-1|\d+),\s*%__OP(\d+)__', template)
not_match = _RE_NOT.match(template)
if not_match:
op = resolve_op(int(not_match.group(3)))
if op:
@@ -1680,15 +1714,15 @@ class ExprCallHandle(BaseHandle):
result = Gen.builder.xor_(op, mask, name="llvmir_result")
return self._StoreLLVMIROutputs(Gen, result, output_targets)
call_match = re.match(r'call\s+(\w+)\s+@([\w.]+)\((.+)\)', template)
call_match = _RE_CALL.match(template)
if call_match:
call_ret_str = call_match.group(1)
func_name = call_match.group(2)
args_str = call_match.group(3)
call_args = []
for arg_part in re.split(r',\s*', args_str):
for arg_part in _RE_COMMA_WS.split(args_str):
arg_part = arg_part.strip()
typed_op = re.match(r'(\w+\*?)\s+%__OP(\d+)__', arg_part)
typed_op = _RE_TYPED_OP.match(arg_part)
if typed_op:
expected_type_str = typed_op.group(1)
op_idx = int(typed_op.group(2))
@@ -1698,7 +1732,7 @@ class ExprCallHandle(BaseHandle):
if val:
call_args.append(val)
else:
const_m = re.match(r'(\w+)\s+(-?\d+)', arg_part)
const_m = _RE_CONST.match(arg_part)
if const_m:
const_type = self._ParseLLVMType(Gen, const_m.group(1))
if const_type:
+10 -1
View File
@@ -9,6 +9,15 @@ import re
import llvmlite.ir as ir
# ---------------------------------------------------------------
# `_parse_format_spec` 的格式说明符解析正则**预编译**(性能:避免每次
# `re.match(字面量, ...)` 的"模式串哈希 → re 模块级缓存查找"。
# 语义与逐字写法完全一致,模式串一字未改)。
# ---------------------------------------------------------------
# Python 格式说明符 `[[fill]align][sign][#][0][width][,][.precision][type]`
_RE_FORMAT_SPEC: re.Pattern[str] = re.compile(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$')
class ExprFormatHandle(BaseHandle):
def _HandleJoinedStrLlvm(self, Node: ast.JoinedStr) -> ir.Value:
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
@@ -149,7 +158,7 @@ class ExprFormatHandle(BaseHandle):
if not spec_str:
return None
m: Any = re.match(r'^(.?[<>=^])?([+\- ])?(#)?(0)?(\d+)?(,)?(\.\d+)?([bcdeEfFgGnosxX%])?$', spec_str)
m: Any = _RE_FORMAT_SPEC.match(spec_str)
if not m:
return None
+44 -15
View File
@@ -49,6 +49,35 @@ _LLVM_PRIMITIVE_TYPE_MAP: dict[str, ir.Type] = {
}
# 字面量正则的模块级预编译(性能:这些调用点做逐行扫描/逐条解析,命中次数极高;
# 每次 `re.match(字面量, s)` 都要做"模式串哈希 → re 缓存查找"。预编译成模块级常量
# 后省掉该查找,且匹配路径更短。模式串一字未改。
# 解析异常报文里兜底取 `at line N`
_RE_AT_LINE: re.Pattern[str] = re.compile(r'at line (\d+)')
# stub 里 `%<sha1>.Name = type <...>` 结构体定义行
_RE_STRUCT_TYPE_DEF: re.Pattern[str] = re.compile(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)')
# `[N x <T>]` 数组类型
_RE_ARRAY_TYPE: re.Pattern[str] = re.compile(r'\[(\d+)\s*x\s+(.+)\]')
# declare 行(函数名限定 `[\w.]+` 字符集)
_RE_DECLARE_SIMPLE: re.Pattern[str] = re.compile(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$')
# declare 行(函数名允许任意非括号字符)
_RE_DECLARE_GENERIC: re.Pattern[str] = re.compile(r'declare\s+(.+?)\s+@("?[^()]+"?)\s*\((.*)\)$')
# 剥离 LLVM IR 参数名:`\s+%name` 或 `\s+%"quoted.name"` 结尾
_RE_PARAM_NAME_TRAILING: re.Pattern[str] = re.compile(r'\s+%("[^"]*"|[\w.]+)\s*$')
# 剥离 LLVM IR 参数名:`\s+%name`(无引号形式)
_RE_PARAM_NAME_PLAIN: re.Pattern[str] = re.compile(r'\s+%[\w.]+\s*$')
# stub 里引用到的 sha1 前缀 `%<16hex>.`
_RE_SHA1_PREFIX_REF: re.Pattern[str] = re.compile(r'%\"?([a-f0-9]{16})\.')
# `@name = external global <...>` 全局变量定义行
_RE_EXTERNAL_GLOBAL_DEF: re.Pattern[str] = re.compile(r'@("?)(?:([a-f0-9]{16})\.)?([\w.\[\]]+)\1\s*=\s*external\s+global\s+(\S.*)')
# 去掉全局类型尾部 zeroinitializer
_RE_STRIP_ZEROINIT: re.Pattern[str] = re.compile(r'\s+zeroinitializer.*$')
# 去掉全局类型尾部 `, align N`
_RE_STRIP_ALIGN: re.Pattern[str] = re.compile(r'\s*,\s*align\s+\d+.*$')
# struct 定义名(不强制 `= type ...` 后缀)
_RE_STRUCT_NAME: re.Pattern[str] = re.compile(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]*]+)"?')
def _HasRealParentClass(Node: ast.ClassDef) -> bool:
"""类是否声明了**真实父类**(排除 Object/CVTable/NoVTable/CEnum/... 标记基类)。"""
for base in getattr(Node, 'bases', None) or []:
@@ -106,7 +135,7 @@ def _ParseFailureSite(Exc: BaseException) -> str:
Line: int = int(getattr(Exc, 'lineno', 0) or 0)
Col: int = int(getattr(Exc, 'offset', 0) or 0)
if not Line:
Matched: re.Match | None = re.search(r'at line (\d+)', str(Exc))
Matched: re.Match | None = _RE_AT_LINE.search(str(Exc))
if Matched:
Line = int(Matched.group(1))
if not Line:
@@ -2921,7 +2950,7 @@ class ImportHandle(BaseHandle):
content = f.read()
for line in content.splitlines():
stripped = line.strip()
match = re.match(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)', stripped)
match = _RE_STRUCT_TYPE_DEF.match(stripped)
if match:
full_name = match.group(1)
short_name = match.group(2)
@@ -3593,7 +3622,7 @@ class ImportHandle(BaseHandle):
stub_func_name = name_match[1].split('(', 1)[0].strip().strip('"')
match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', stripped)
match = _RE_DECLARE_SIMPLE.match(stripped)
if match:
stub_ret = match.group(1).strip()
stub_params = match.group(3).strip()
@@ -3646,7 +3675,7 @@ class ImportHandle(BaseHandle):
"""剥离 LLVM IR 参数字符串中的参数名,仅保留类型部分"""
param_str = param_str.strip()
# 支持 %name 和 %"quoted.name" 两种参数名形式
result = re.sub(r'\s+%("[^"]*"|[\w.]+)\s*$', '', param_str)
result = _RE_PARAM_NAME_TRAILING.sub('', param_str)
return result.strip()
def _parse_simple_llvm_type(self, type_str: str) -> ir.Type | None:
@@ -3676,7 +3705,7 @@ class ImportHandle(BaseHandle):
return ir.PointerType(ir.IntType(8))
if type_str.startswith('[') and ']' in type_str:
arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str)
arr_match = _RE_ARRAY_TYPE.match(type_str)
if arr_match:
size = int(arr_match.group(1))
elem_type = self._parse_simple_llvm_type(arr_match.group(2).strip())
@@ -3727,10 +3756,10 @@ class ImportHandle(BaseHandle):
for line in content.splitlines():
stripped = line.strip()
if stripped.startswith('%') and '=' in stripped and 'type' in stripped:
for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
for m in _RE_SHA1_PREFIX_REF.finditer(stripped):
needed_sha1s.add(m.group(1))
elif stripped.startswith('declare '):
for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
for m in _RE_SHA1_PREFIX_REF.finditer(stripped):
needed_sha1s.add(m.group(1))
except Exception as _e:
if _config_mode == "strict":
@@ -3757,7 +3786,7 @@ class ImportHandle(BaseHandle):
stripped = line.strip()
if stripped.startswith('%') and '=' in stripped and 'type' in stripped:
struct_def_match = re.match(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)', stripped)
struct_def_match = _RE_STRUCT_TYPE_DEF.match(stripped)
if struct_def_match:
raw_name = struct_def_match.group(1)
# 治本修复:从 raw_name 提取类型定义的实际 sha1 前缀,
@@ -3807,14 +3836,14 @@ class ImportHandle(BaseHandle):
# Gen.module.globals → _lookup_module_global 恒 None → store/load
# 全部丢失 → memset(null) 崩溃。此处兼容裸名 + sha1 前缀两种格式,
# 名称与定义一致(temp/*.text.ll 均为裸名)。
_gv_match = re.match(r'@("?)(?:([a-f0-9]{16})\.)?([\w.\[\]]+)\1\s*=\s*external\s+global\s+(\S.*)', stripped)
_gv_match = _RE_EXTERNAL_GLOBAL_DEF.match(stripped)
if _gv_match:
_gv_name: str = _gv_match.group(3)
_gv_sha1: str | None = _gv_match.group(2)
_gv_type_str: str = _gv_match.group(4).strip()
# 去掉尾部修饰(zeroinitializer / , align N),只保留类型
_gv_type_str = re.sub(r'\s+zeroinitializer.*$', '', _gv_type_str)
_gv_type_str = re.sub(r'\s*,\s*align\s+\d+.*$', '', _gv_type_str)
_gv_type_str = _RE_STRIP_ZEROINIT.sub('', _gv_type_str)
_gv_type_str = _RE_STRIP_ALIGN.sub('', _gv_type_str)
if _gv_name not in Gen.module.globals:
_gv_ty: ir.Type | None = self._parse_llvm_type(_gv_type_str, Gen, source_sha1=source_sha1)
if _gv_ty is not None:
@@ -4002,7 +4031,7 @@ class ImportHandle(BaseHandle):
def _parse_llvm_declare(self, declare_line: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None:
"""解析 LLVM declare 语句"""
match = re.match(r'declare\s+(.+?)\s+@("?[^()]+"?)\s*\((.*)\)$', declare_line)
match = _RE_DECLARE_GENERIC.match(declare_line)
if not match:
return None
@@ -4146,7 +4175,7 @@ class ImportHandle(BaseHandle):
return ir.PointerType(ir.IntType(8))
if type_str.startswith('[') and ']' in type_str:
arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str)
arr_match = _RE_ARRAY_TYPE.match(type_str)
if arr_match:
size = int(arr_match.group(1))
elem_type = self._parse_llvm_type(arr_match.group(2).strip(), Gen, source_sha1=source_sha1, create_structs=create_structs)
@@ -4160,7 +4189,7 @@ class ImportHandle(BaseHandle):
# list[<sha1>.AST](少一层指针)并 declare_only 特化出无方法体的
# 假类型 → 调用点引用未定义的 <模sha1>.list[<sha1>.AST].__len__
# (链接期 undefined symbol 根因)。
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]*]+)"?', type_str)
struct_match = _RE_STRUCT_NAME.match(type_str)
if struct_match:
raw_name = struct_match.group(1)
actual_source_sha1 = source_sha1
@@ -4240,5 +4269,5 @@ class ImportHandle(BaseHandle):
'i32' -> 'i32'
"""
param_str = param_str.strip()
stripped = re.sub(r'\s+%[\w.]+\s*$', '', param_str)
stripped = _RE_PARAM_NAME_PLAIN.sub('', param_str)
return stripped.strip()
+7 -2
View File
@@ -13,6 +13,11 @@ from lib.core.VLogger import get_logger as _vlog
# (profile:`_TypedPointerType.__init__` 3,750,259 次中有一份来自这里)。
_I8_PTR: ir.Type = ir.PointerType(ir.IntType(8))
# `_strip_unnecessary_quotes` 识别 LLVM IR 裸标识符 / 给引用名去引号用的**预编译**正则
# (性能:该函数对整段 IR 文本做替换,字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_IR_IDENTIFIER: re.Pattern[str] = re.compile(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$')
_RE_QUOTED_IR_NAME: re.Pattern[str] = re.compile(r'([@%])"([^"]+)"')
class StructGenMixin:
@@ -185,10 +190,10 @@ class StructGenMixin:
name: str = m.group(2)
if '.' in name:
return m.group(0)
if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name):
if _RE_IR_IDENTIFIER.match(name):
return prefix + name
return m.group(0)
return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str)
return _RE_QUOTED_IR_NAME.sub(_unquote, ir_str)
def finalize(self) -> str:
self._set_Vtable_initializers()
+9 -3
View File
@@ -11,6 +11,12 @@ from lib.constants.config import mode as _config_mode
from lib.core.VLogger import get_logger as _vlog
from lib.core.SymbolUtils import IsTModule
# `_type_str_to_llvm_impl` / `_type_str_to_llvm_base` 解析类型字符串用的**预编译**正则
# (性能:类型字符串解析在热路径上频繁调用,字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_ARRAY_DIM: re.Pattern[str] = re.compile(r'\[(\d+)\]')
_RE_ARRAY_DIM_STRIP: re.Pattern[str] = re.compile(r'\s*\[\d+\]')
_RE_SUBSCRIPT_TYPE: re.Pattern[str] = re.compile(r'([A-Za-z_][A-Za-z0-9_.]*)\[([^\]]+)\]')
class TypeConvertMixin:
@@ -329,10 +335,10 @@ class TypeConvertMixin:
def _type_str_to_llvm_impl(self, type_str: str, IsPtr: bool = False) -> ir.Type:
array_dims: list[int] = []
dim_match: list[str] = re.findall(r'\[(\d+)\]', type_str)
dim_match: list[str] = _RE_ARRAY_DIM.findall(type_str)
if dim_match:
array_dims = [int(d) for d in dim_match]
type_str = re.sub(r'\s*\[\d+\]', '', type_str).strip()
type_str = _RE_ARRAY_DIM_STRIP.sub('', type_str).strip()
result: ir.Type = self._type_str_to_llvm_base(type_str, IsPtr)
for dim in reversed(array_dims):
result = ir.ArrayType(result, dim)
@@ -349,7 +355,7 @@ class TypeConvertMixin:
# base 为 builtins 指针 typedef(rawptr → t.CPtr)时等价"指向切片类型",
# 直接转 arg*,防止 stub/ToString 字符串化产物被误建为 'rawptr[AST]'
# phantom 结构体(class_members 为空 → 属性访问 fail-fast KeyError)。
_sub_m: re.Match | None = re.fullmatch(r'([A-Za-z_][A-Za-z0-9_.]*)\[([^\]]+)\]', type_str)
_sub_m: re.Match | None = _RE_SUBSCRIPT_TYPE.fullmatch(type_str)
if _sub_m:
_sub_base: str = _sub_m.group(1)
_sub_arg: str = _sub_m.group(2).strip()
+13 -2
View File
@@ -50,6 +50,17 @@ _ENUM_MEMBER_SKIP: frozenset[str] = frozenset({
})
# ---------------------------------------------------------------
# `_AttributeMarkerText` 的属性实参形态判定正则**预编译**(性能:避免每次
# `re.fullmatch`/`re.match(字面量, ...)` 的"模式串哈希 → re 模块级缓存查找"。
# 语义与逐字写法完全一致,模式串一字未改)。
# ---------------------------------------------------------------
# 裸标识符(`always_inline` 形态)
_RE_ATTR_BARE_IDENT: re.Pattern[str] = re.compile(r'[A-Za-z_][A-Za-z0-9_]*')
# 标识符后紧跟调用括号(`section(...)` 形态)
_RE_ATTR_CALL_IDENT: re.Pattern[str] = re.compile(r'^[A-Za-z_][A-Za-z0-9_]*\s*\(')
def _ExpandEnumBlocks(Code: str) -> str:
"""把 `enum Name:` 块展开为等价的 `class Name(t.CEnum):` 块(行号不变)。
@@ -914,9 +925,9 @@ def _AttributeMarkerText(ArgText: str) -> str:
T: str = (ArgText or '').strip()
if not T:
return T
if re.fullmatch(r'[A-Za-z_][A-Za-z0-9_]*', T) is not None:
if _RE_ATTR_BARE_IDENT.fullmatch(T) is not None:
return f'{_ATTR_MARKER_PREFIX}{T}'
if re.match(r'^[A-Za-z_][A-Za-z0-9_]*\s*\(', T) is not None:
if _RE_ATTR_CALL_IDENT.match(T) is not None:
return f'{_ATTR_MARKER_PREFIX}{T}'
return T
+19 -8
View File
@@ -17,6 +17,17 @@ from lib.core.SymbolUtils import (
# 治本修复:导入 ConstEvaluator 用于预扫描 CDefine 常量的复杂表达式求值
from lib.core.ConstEvaluator import ConstEvaluator
# `_InsertModuleLevelLLVMIR` 解析模块级 LLVM IR 文本用的**预编译**正则
# (性能:该函数逐行解析 IR,字面量正则在调用点每次都要做模式串哈希与 re 缓存查找)。
_RE_MODULE_FLAGS: re.Pattern[str] = re.compile(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}')
_RE_METADATA_DEF: re.Pattern[str] = re.compile(r'(!\d+)\s*=\s*!\{(.+)\}')
_RE_METADATA_FIELD_SEP: re.Pattern[str] = re.compile(r',\s*')
_RE_METADATA_FIELD_I32: re.Pattern[str] = re.compile(r'^i32\s+(\d+)$')
_RE_METADATA_FIELD_STR: re.Pattern[str] = re.compile(r'^"([^"]*)"$')
_RE_METADATA_FIELD_MDSTR: re.Pattern[str] = re.compile(r'^!"([^"]*)"$')
_RE_METADATA_FIELD_INT: re.Pattern[str] = re.compile(r'^(\d+)$')
_RE_METADATA_FIELD_REF: re.Pattern[str] = re.compile(r'^(!\d+)$')
class LlvmGeneratorMixin:
"""LLVM IR 生成 Mixin
@@ -307,39 +318,39 @@ class LlvmGeneratorMixin:
line = line.strip()
if not line:
continue
module_flags_match: re.Match[str] | None = re.match(r'!llvm\.module\.flags\s*=\s*!\{(!\d+)\}', line)
module_flags_match: re.Match[str] | None = _RE_MODULE_FLAGS.match(line)
if module_flags_match:
ref: str = module_flags_match.group(1)
if not hasattr(Gen, '_pending_module_flags'):
Gen._pending_module_flags: list = []
Gen._pending_module_flags_refs: str = ref
continue
metadata_match: re.Match[str] | None = re.match(r'(!\d+)\s*=\s*!\{(.+)\}', line)
metadata_match: re.Match[str] | None = _RE_METADATA_DEF.match(line)
if metadata_match:
md_id: str = metadata_match.group(1)
md_body: str = metadata_match.group(2)
fields: list[ir.Constant | ir.MetaDataString | str] = []
for field_str in re.split(r',\s*', md_body):
for field_str in _RE_METADATA_FIELD_SEP.split(md_body):
field_str = field_str.strip()
if not field_str:
continue
int_m: re.Match[str] | None = re.match(r'^i32\s+(\d+)$', field_str)
int_m: re.Match[str] | None = _RE_METADATA_FIELD_I32.match(field_str)
if int_m:
fields.append(ir.Constant(ir.IntType(32), int(int_m.group(1))))
continue
str_m: re.Match[str] | None = re.match(r'^"([^"]*)"$', field_str)
str_m: re.Match[str] | None = _RE_METADATA_FIELD_STR.match(field_str)
if str_m:
fields.append(ir.MetaDataString(Gen.module, str_m.group(1)))
continue
mdstr_m: re.Match[str] | None = re.match(r'^!"([^"]*)"$', field_str)
mdstr_m: re.Match[str] | None = _RE_METADATA_FIELD_MDSTR.match(field_str)
if mdstr_m:
fields.append(ir.MetaDataString(Gen.module, mdstr_m.group(1)))
continue
int_m2: re.Match[str] | None = re.match(r'^(\d+)$', field_str)
int_m2: re.Match[str] | None = _RE_METADATA_FIELD_INT.match(field_str)
if int_m2:
fields.append(ir.Constant(ir.IntType(32), int(int_m2.group(1))))
continue
ref_m: re.Match[str] | None = re.match(r'^(!\d+)$', field_str)
ref_m: re.Match[str] | None = _RE_METADATA_FIELD_REF.match(field_str)
if ref_m:
fields.append(ref_m.group(1))
continue
+9 -1
View File
@@ -18,6 +18,14 @@ if TYPE_CHECKING:
from lib.core.SymbolTable import SymbolTable
# ---------------------------------------------------------------
# `_scan_builtins` 的 `import X as Y` 解析正则**预编译**(性能:避免每次
# `re.match(字面量, ...)` 的"模式串哈希 → re 模块级缓存查找"。
# 语义与逐字写法完全一致,模式串一字未改)。
# ---------------------------------------------------------------
_RE_IMPORT_AS: re.Pattern[str] = re.compile(r'import\s+([^\s]+)\s+as\s+([^\s]+)')
class TypeAnnotationResolver:
"""从 AST 节点解析类型注解,独立于 CTypeInfo 数据模型。"""
@@ -204,7 +212,7 @@ class TypeAnnotationResolver:
continue
# import X as Y → 别名表(__stdint → stdint)
if stripped.startswith('import '):
m: re.Match | None = re.match(r'import\s+([^\s]+)\s+as\s+([^\s]+)', stripped)
m: re.Match | None = _RE_IMPORT_AS.match(stripped)
if m:
aliases[m.group(2)] = m.group(1)
continue
+41 -14
View File
@@ -14,6 +14,33 @@ from typing import Any
from lib.core.VLogger import get_logger as _vlog
# PROF 热点:C 头文件解析阶段对每一行 / 每个成员反复调用未预编译的 re.match /
# re.finditer(模块级入口),每次都要「模式串哈希 → re 缓存查找 → 未命中就重新编译」。
# 这些模式全是字面量 → 提升为模块级预编译常量(模式串与调用点字面量逐字一致)。
# _ParseDefines 用:#define 指令(含可选值),模式带 re.MULTILINE
_RE_DEFINE: re.Pattern[str] = re.compile(r'#define\s+(\w+)(?:\s+(.+?))?\s*$', re.MULTILINE)
# _ParseTypedefStructs / _ParseTypedefEnums / _ParseTypedefUnions 用:typedef 结尾的 `别名;`
_RE_ALIAS: re.Pattern[str] = re.compile(r'(\w+)\s*;')
# _ParseFunctions 用:返回类型是否以数字开头
_RE_DIGIT_START: re.Pattern[str] = re.compile(r'^\d')
# _ParseFunctions / _ParseVariables 用:标识符是否以字母或下划线开头
_RE_IDENT_START: re.Pattern[str] = re.compile(r'^[A-Za-z_]')
# _ParseVariables 用:排除 C 关键字作为变量名
_RE_C_KEYWORD: re.Pattern[str] = re.compile(r'^(if|else|while|for|return|switch|case|break|continue|do|goto)$')
# _ParseStructMembers 用:结构体数组成员
_RE_STRUCT_ARRAY_MEMBER: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s+(\w+)\s*\[(\d*)\]')
# _ParseStructMembers 用:结构体指针成员
_RE_STRUCT_PTR_MEMBER: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s*\*\s*(\w+)')
# _ParseStructMembers 用:结构体普通成员
_RE_STRUCT_SIMPLE_MEMBER: re.Pattern[str] = re.compile(r'([\w\s]+?)\s+(\w+)')
# _ParseEnumValues 用:枚举项名是否合法
_RE_ENUM_NAME: re.Pattern[str] = re.compile(r'^[A-Za-z_]\w*$')
# _ParseFuncParams 用:函数指针参数
_RE_FUNC_PTR_PARAM: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s*\(\s*\*\s*(\w*)\s*\)\s*\([^)]*\)')
# _ParseFuncParams 用:数组参数
_RE_ARRAY_PARAM: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s+(\w+)\s*\[\d*\]')
class CTypeMapper:
# 硬编码 C 类型名 → Python 类型映射表
@@ -229,7 +256,7 @@ class CHeaderParser:
return result
def _ParseDefines(self, content: str) -> None:
for match in re.finditer(r'#define\s+(\w+)(?:\s+(.+?))?\s*$', content, re.MULTILINE):
for match in _RE_DEFINE.finditer(content):
Name: str = match.group(1)
Value: str | None = match.group(2)
if Name.startswith('_') and Name.endswith('_'):
@@ -250,7 +277,7 @@ class CHeaderParser:
continue
body: str = content[brace_start + 1:brace_end]
rest: str = content[brace_end + 1:].lstrip()
AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest)
AliasMatch: re.Match[str] | None = _RE_ALIAS.match(rest)
if not AliasMatch:
continue
AliasName: str = AliasMatch.group(1)
@@ -273,7 +300,7 @@ class CHeaderParser:
continue
body: str = content[brace_start + 1:brace_end]
rest: str = content[brace_end + 1:].lstrip()
AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest)
AliasMatch: re.Match[str] | None = _RE_ALIAS.match(rest)
if not AliasMatch:
continue
AliasName: str = AliasMatch.group(1)
@@ -296,7 +323,7 @@ class CHeaderParser:
continue
body: str = content[brace_start + 1:brace_end]
rest: str = content[brace_end + 1:].lstrip()
AliasMatch: re.Match[str] | None = re.match(r'(\w+)\s*;', rest)
AliasMatch: re.Match[str] | None = _RE_ALIAS.match(rest)
if not AliasMatch:
continue
AliasName: str = AliasMatch.group(1)
@@ -415,9 +442,9 @@ class CHeaderParser:
continue
if ReturnType in ('struct', 'union', 'enum', 'typedef'):
continue
if re.match(r'^\d', ReturnType):
if _RE_DIGIT_START.match(ReturnType):
continue
if not re.match(r'^[A-Za-z_]', FuncName):
if not _RE_IDENT_START.match(FuncName):
continue
params: list[dict[str, Any]] = self._ParseFuncParams(ParamsStr)
self.functions[FuncName] = {
@@ -442,9 +469,9 @@ class CHeaderParser:
continue
if TypeStr in ('struct', 'union', 'enum', 'typedef'):
continue
if re.match(r'^(if|else|while|for|return|switch|case|break|continue|do|goto)$', VarName):
if _RE_C_KEYWORD.match(VarName):
continue
if not re.match(r'^[A-Za-z_]', VarName):
if not _RE_IDENT_START.match(VarName):
continue
IsPtr: bool = '*' in TypeStr
IsArray: bool = ArraySize is not None
@@ -462,7 +489,7 @@ class CHeaderParser:
line = line.strip()
if not line:
continue
arr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[(\d*)\]', line)
arr_match: re.Match[str] | None = _RE_STRUCT_ARRAY_MEMBER.match(line)
if arr_match:
MemberType: str = arr_match.group(1).strip()
MemberName: str = arr_match.group(2)
@@ -474,7 +501,7 @@ class CHeaderParser:
'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None,
})
continue
ptr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s*\*\s*(\w+)', line)
ptr_match: re.Match[str] | None = _RE_STRUCT_PTR_MEMBER.match(line)
if ptr_match:
MemberType: str = ptr_match.group(1).strip() + ' *'
MemberName: str = ptr_match.group(2)
@@ -484,7 +511,7 @@ class CHeaderParser:
'IsPtr': True,
})
continue
simple_match: re.Match[str] | None = re.match(r'([\w\s]+?)\s+(\w+)', line)
simple_match: re.Match[str] | None = _RE_STRUCT_SIMPLE_MEMBER.match(line)
if simple_match:
MemberType: str = simple_match.group(1).strip()
MemberName: str = simple_match.group(2)
@@ -507,7 +534,7 @@ class CHeaderParser:
else:
Name = item.strip()
Value = None
if Name and re.match(r'^[A-Za-z_]\w*$', Name):
if Name and _RE_ENUM_NAME.match(Name):
values.append({'name': Name, 'value': Value})
return values
@@ -519,7 +546,7 @@ class CHeaderParser:
param = param.strip()
if not param:
continue
func_ptr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s*\(\s*\*\s*(\w*)\s*\)\s*\([^)]*\)', param)
func_ptr_match: re.Match[str] | None = _RE_FUNC_PTR_PARAM.match(param)
if func_ptr_match:
RetType: str = func_ptr_match.group(1).strip()
ParamName: str = func_ptr_match.group(2) or 'callback'
@@ -529,7 +556,7 @@ class CHeaderParser:
'is_func_ptr': True,
})
continue
arr_match: re.Match[str] | None = re.match(r'([\w\s\*]+?)\s+(\w+)\s*\[\d*\]', param)
arr_match: re.Match[str] | None = _RE_ARRAY_PARAM.match(param)
if arr_match:
ParamType: str = arr_match.group(1).strip()
ParamName: str = arr_match.group(2)