Tags
codec++
Created
May 29, 2025 1:37 AM
与C++内存布局及调用约定深度兼容的动态脚本语言,通过自研编译器实现即时编译与无缝嵌入,尝试在保留脚本灵活性的同时,尽可能贴近C++的原生性能,为性能与效率的平衡提供了轻量化解决方案
- 前端:
- 词法分析:字符流->记号流(Tokens),使用 Flex,根据自定义的正则表达式规则,自动生成词法分析的扫描器
- 语法分析:记号流->抽象语法树(AST),采用Bison来实现,Bison可以与Flex进行协作,根据上下文无关文法(CFG)对输入的 tokens 序列进行分析,验证其是否符合某种语言的语法规则,并构建对应的抽象语法树
- 语义分析、生成中间代码:抽象语法树->中间代码,使用了LLVM IR作为中间代码语言,它介于高级语言和目标代码之间,既能表达高级语言的抽象概念,又能适应底层机器代码的生成需求
- 作用域解析:追踪变量/函数的作用域(如块级作用域、全局作用域)。
- 符号绑定:将标识符与其声明关联(如变量类型、函数签名)。
- 重复定义检查:禁止同一作用域内同名符号的重复声明。
- 类型推断与检查:验证表达式和操作的合法性,如 int a = "str"; 类型不匹配。
- 隐式类型转换:处理类型提升,如 int + float 自动转为浮点运算。
- 函数签名匹配:检查实参与形参的个数、类型一致性。
- 语句上下文检查:确保 break 仅在循环内、 return 与函数返回类型一致。
- 可达性分析:检测不可达代码(如 return 后的语句)。
- 优化常量计算(如 const x = 2 + 3*4; 直接计算为 14 )。
- 用于数组长度、条件编译等需编译期确定值的场景。
- 优化器(中端):通过一系列LLVM预置的优化遍(Pass)
- 后端:负责将中间代码转换成目标机器的的机器码
- 使用 LLVM 的 ORC JIT 作为即时编译器的实现,支持在程序运行时编译脚本,并通过查找函数地址的方式执行脚本
- 编译器最终输出为x86_64平台的可执行二进制,以JIT实例的方式常驻内存,通过入口函数地址执行
符号表管理
类型系统校验
控制流合法性
常量表达式求值
数据流分析
| 死代码消除 (DCE)
| 通过数据流分析,LLVM 能够精确地识别和删除这些无用的指令。
|
全局值编号(GVN)
| 检测并消除等价的冗余表达式,减少重复计算。
| |
循环优化
| 循环展开
(Loop Unrolling)
| 通过展开循环体中的指令,减少循环控制的开销,并增加指令级并行性。
|
循环分割
(Loop Split)
| 将复杂的循环拆分为多个更简单的循环,以便更好地优化每个循环。
| |
循环不变代码外提
(LICM)
| 将循环中不变的计算移出循环体,从而减少不必要的重复计算。
| |
控制流优化
| 条件合并
(Conditional Merging)
| 合并控制流中多余的条件判断,从而简化分支结构。
|
跳转线程化
(Jump Threading)
| 在控制流图中,将多个条件判断组合为一个单一的跳转,以减少不必要的分支。
| |
尾调用优化 (TCO)
| 优化递归函数调用,使得尾递归调用能够直接重用当前栈帧,从而避免栈溢出。
| |
内存访问优化
| 内存别名分析
(Alias Analysis)
| 确定不同指针是否指向相同的内存位置,从而帮助优化器在内存访问上进行优化,如消除冗余的内存加载和存储操作。
|
堆栈分配优化
(Stack Allocation Optimization)
| 通过分析栈上变量的生命周期,减少不必要的内存分配和释放,或者将栈分配的变量优化到寄存器中。
|