From b18d57fa384e8a417086e4e8471f2a6d838674b1 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 30 Sep 2026 23:47:36 +0800 Subject: [PATCH] =?UTF-8?q?perf(=E5=85=A8=E4=BB=93=E5=BA=93/=E6=AD=A3?= =?UTF-8?q?=E5=88=99):=20=E5=AD=97=E9=9D=A2=E9=87=8F=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E5=85=A8=E9=83=A8=E6=94=B9=E6=A8=A1=E5=9D=97=E7=BA=A7=E9=A2=84?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=B8=B8=E9=87=8F=EF=BC=8815=20=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20/=20115=20=E4=B8=AA=E8=B0=83=E7=94=A8=E7=82=B9?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 背景(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.(字面量, 其余实参, 关键字) + flags" 与 "新 _RE_X.(实参, 关键字) + 常量 (模式, 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 缓存无收益,不做。 --- lib/Projectrans/DeclarationGenerator.py | 15 +++-- lib/Projectrans/Phase2Translator.py | 87 +++++++++++++++++++------ lib/StubGen/Converter.py | 8 ++- lib/StubGen/Generator.py | 9 ++- lib/core/Handles/HandlesExpr.py | 16 ++++- lib/core/Handles/HandlesExprAsm.py | 17 ++++- lib/core/Handles/HandlesExprCall.py | 64 +++++++++++++----- lib/core/Handles/HandlesExprFormat.py | 11 +++- lib/core/Handles/HandlesImports.py | 59 ++++++++++++----- lib/core/LLVMCG/StructGen.py | 9 ++- lib/core/LLVMCG/TypeConvert.py | 12 +++- lib/core/SymbolUtils.py | 15 ++++- lib/core/Translator/LlvmGenerator.py | 27 +++++--- lib/core/TypeAnnotationResolver.py | 10 ++- lib/core/stub_generator.py | 55 ++++++++++++---- 15 files changed, 318 insertions(+), 96 deletions(-) diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py index 48c7894..d340f8c 100644 --- a/lib/Projectrans/DeclarationGenerator.py +++ b/lib/Projectrans/DeclarationGenerator.py @@ -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 diff --git a/lib/Projectrans/Phase2Translator.py b/lib/Projectrans/Phase2Translator.py index 4856850..829e94d 100644 --- a/lib/Projectrans/Phase2Translator.py +++ b/lib/Projectrans/Phase2Translator.py @@ -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) diff --git a/lib/StubGen/Converter.py b/lib/StubGen/Converter.py index ef9e585..03c1a9c 100644 --- a/lib/StubGen/Converter.py +++ b/lib/StubGen/Converter.py @@ -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) diff --git a/lib/StubGen/Generator.py b/lib/StubGen/Generator.py index 867b711..192969e 100644 --- a/lib/StubGen/Generator.py +++ b/lib/StubGen/Generator.py @@ -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' diff --git a/lib/core/Handles/HandlesExpr.py b/lib/core/Handles/HandlesExpr.py index d58044d..581fa04 100644 --- a/lib/core/Handles/HandlesExpr.py +++ b/lib/core/Handles/HandlesExpr.py @@ -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: diff --git a/lib/core/Handles/HandlesExprAsm.py b/lib/core/Handles/HandlesExprAsm.py index 8cdb71c..61622cd 100644 --- a/lib/core/Handles/HandlesExprAsm.py +++ b/lib/core/Handles/HandlesExprAsm.py @@ -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 diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index f4131ea..09be28f 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -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: diff --git a/lib/core/Handles/HandlesExprFormat.py b/lib/core/Handles/HandlesExprFormat.py index 1722395..4b71e1a 100644 --- a/lib/core/Handles/HandlesExprFormat.py +++ b/lib/core/Handles/HandlesExprFormat.py @@ -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 diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index bf7ff8c..179a275 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -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 里 `%.Name = type <...>` 结构体定义行 +_RE_STRUCT_TYPE_DEF: re.Pattern[str] = re.compile(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)') +# `[N x ]` 数组类型 +_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[.AST](少一层指针)并 declare_only 特化出无方法体的 # 假类型 → 调用点引用未定义的 <模sha1>.list[.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() diff --git a/lib/core/LLVMCG/StructGen.py b/lib/core/LLVMCG/StructGen.py index e707830..b714b1a 100644 --- a/lib/core/LLVMCG/StructGen.py +++ b/lib/core/LLVMCG/StructGen.py @@ -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() diff --git a/lib/core/LLVMCG/TypeConvert.py b/lib/core/LLVMCG/TypeConvert.py index ecd510f..86e8328 100644 --- a/lib/core/LLVMCG/TypeConvert.py +++ b/lib/core/LLVMCG/TypeConvert.py @@ -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() diff --git a/lib/core/SymbolUtils.py b/lib/core/SymbolUtils.py index 3c2796c..25f937f 100644 --- a/lib/core/SymbolUtils.py +++ b/lib/core/SymbolUtils.py @@ -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 diff --git a/lib/core/Translator/LlvmGenerator.py b/lib/core/Translator/LlvmGenerator.py index 16a162a..28e257d 100644 --- a/lib/core/Translator/LlvmGenerator.py +++ b/lib/core/Translator/LlvmGenerator.py @@ -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 diff --git a/lib/core/TypeAnnotationResolver.py b/lib/core/TypeAnnotationResolver.py index fc63c69..ad4e734 100644 --- a/lib/core/TypeAnnotationResolver.py +++ b/lib/core/TypeAnnotationResolver.py @@ -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 diff --git a/lib/core/stub_generator.py b/lib/core/stub_generator.py index aa71085..d4becba 100644 --- a/lib/core/stub_generator.py +++ b/lib/core/stub_generator.py @@ -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)