BURG(自底向上重写生成器)

概述

BURG 是编译器后端指令选择的经典工具。

它的核心思想是:给定一棵 IR 表达式树和一组带代价的机器指令模式,用动态规划找到覆盖整棵树的最小代价方案。

BURG 要解决什么问题?

问题场景

假设我们有以下 IR 表达式树(表示 (a + 5) * b):

其中:

  • a 是内存中的变量
  • b 是内存中的变量
  • 5 是常量

机器提供以下指令(每条指令 = 一个模式 + 代价):

规则 模式 指令 代价
R1 add(reg, reg) ADD rd, rs1, rs2 1
R2 add(reg, imm) ADDI rd, rs1, imm 1
R3 mul(reg, reg) MUL rd, rs1, rs2 3
R4 load(addr) LOAD rd, addr 2
R5 const(imm) LOADI rd, imm 1

目标:用这些指令覆盖整棵树,总代价最小。

BURG 的两步算法

Label 阶段(自底向上)

从叶子到根,给每个节点标注"用哪条规则、代价是多少"。

节点 a(叶子,内存变量):

text 复制代码
规则 R4:load(addr)
代价 = 2

标注:a 的最优代价 = 2(用 LOAD)

节点 5(叶子,常量):

text 复制代码
规则 R5:const(imm)
代价 = 1

标注:5 的最优代价 = 1(用 LOADI)

节点 +(内部节点,子节点是 a 和 5):

text 复制代码
候选规则 1:R1(add(reg, reg))
  需要 a 在寄存器中,5 在寄存器中
  代价 = cost(a) + cost(5) + 1 = 2 + 1 + 1 = 4

候选规则 2:R2(add(reg, imm))
  需要 a 在寄存器中,5 作为立即数
  代价 = cost(a) + 1 = 2 + 1 = 3

取最小:代价 = 3(用 ADDI)
标注:+ 的最优代价 = 3

节点 b(叶子,内存变量):

text 复制代码
规则 R4:load(addr)
代价 = 2

标注:b 的最优代价 = 2

节点 * (根节点,子节点是 + 和 b):

text 复制代码
候选规则:R3(mul(reg, reg))
  需要 + 的结果在寄存器中,b 在寄存器中
  代价 = cost(+) + cost(b) + 3 = 3 + 2 + 3 = 8

标注:* 的最优代价 = 8

Label 阶段结果汇总:

节点 最优规则 代价
a LOAD 2
5 LOADI 1
+ ADDI 3
b LOAD 2
* MUL 8

Select 阶段(自顶向下)

从根到叶,每步选择到达目标最便宜的路径。

根节点*:

text 复制代码
选择规则:R3(MUL)
需要:+ 的结果在寄存器中,b 在寄存器中

节点 +(被 * 需要,必须在寄存器中):

text 复制代码
选择规则:R2(ADDI)
需要:a 在寄存器中,5 作为立即数

节点 a(被 + 需要,必须在寄存器中):

text 复制代码
选择规则:R4(LOAD)
生成:LOAD r1, a

节点 5(被 + 作为立即数使用):

text 复制代码
不单独生成指令,直接作为 ADDI 的立即数

节点 b(被 * 需要,必须在寄存器中):

text 复制代码
选择规则:R4(LOAD)
生成:LOAD r2, b

节点 +(生成指令):

text 复制代码
生成:ADDI r1, r1, 5

节点 * (生成指令):

text 复制代码
生成:MUL r3, r1, r2

最终生成的汇编

assembly 复制代码
LOAD r1, a        ; 代价 2
ADDI r1, r1, 5    ; 代价 1
LOAD r2, b        ; 代价 2
MUL r3, r1, r2    ; 代价 3
; 总代价 = 8

验证:如果不用 ADDI 而用 ADD,需要额外加载 5 到寄存器:

assembly 复制代码
LOAD r1, a        ; 2
LOADI r4, 5       ; 1
ADD r1, r1, r4    ; 1
LOAD r2, b        ; 2
MUL r3, r1, r2    ; 3
; 总代价 = 9

BURG 选择了代价 8 的方案,比 9 更优。

BURG 与 Maximal Munch 的区别

算法 策略 最优性
Maximal Munch 从根到叶,每次选覆盖最多节点的瓦片 贪心,不一定最优
BURG 从叶到根计算代价,再从根到叶选择 动态规划,保证最优

Maximal Munch 可能错过的例子

假设树是 (a + 5) * b,但规则是:

规则 模式 代价
R1 mul(add(reg, imm), reg) 4(一条指令完成加法和乘法)
R2 add(reg, imm) 1
R3 mul(reg, reg) 3

Maximal Munch :从根 * 开始,最大瓦片是 R1(覆盖 * + + + 5),代价 4。

然后处理 a(LOAD,代价 2)和 b(LOAD,代价 2)。

总代价 = 4 + 2 + 2 = 8。

BURG:会计算所有可能组合,发现 R1 的总代价 8,而 R2 + R3 的总代价是 1 + 3 + 2 + 2 = 8。两者相同。

但如果 R1 的代价是 5,Maximal Munch 会选 R1(代价 5+2+2=9),而 BURG 会选 R2+R3(代价 8),更优。

结论:Maximal Munch 贪心,可能不是最优;BURG 用动态规划,保证最优。

BURG 的输入与输出

输入:模式描述

BURG 的输入是一个 .burg 文件,描述每条指令的模式和代价:

burg 复制代码
%term ADD=1 MUL=2 ADDI=3 LOAD=4 LOADI=5
%start reg

reg: ADD(reg, reg)    1
reg: ADDI(reg, imm)   1
reg: MUL(reg, reg)    3
reg: LOAD(addr)       2
reg: LOADI(imm)       1
  • %term:定义终结符(操作符)
  • %start reg:目标非终结符reg: ADD(reg, reg) 1:规则
  • "reg → ADD(reg, reg)",代价 1

输出:匹配器

BURG 生成一个 C/C++ 函数,输入是 IR 树,输出是最优覆盖方案:

c 复制代码
int burg_label(Node *node);   // Label 阶段
void burg_select(Node *node, int goal);  // Select 阶段

BURG 的完整工作流程

text 复制代码
输入:
  IR 树 + 模式描述(.burg 文件)

BURG 生成器:
  解析 .burg 文件
  生成状态机(自动机)
  生成 label() 和 select() 函数

编译器使用:
  ① 对 IR 树调用 label() → 每个节点标注最优规则和代价
  ② 对 IR 树调用 select() → 自顶向下选择规则,生成指令
  ③ 输出汇编代码

总结

概念 含义
BURG Bottom-Up Rewrite Generator,自底向上重写生成器
输入 模式描述(.burg 文件),每条模式有代价
输出 匹配器(label + select 函数)
Label 自底向上遍历,给每个节点标注最优规则和代价
Select 自顶向下遍历,每步选择到达目标最便宜的路径
核心算法 动态规划,保证找到最小代价覆盖
与 Maximal Munch 的区别 Maximal Munch 贪心,BURG 动态规划保证最优

一句话:BURG 是编译器指令选择的经典工具。

它把"用机器指令覆盖 IR 树"转化为"动态规划求最小代价覆盖",通过 Label(自底向上计算代价)和 Select(自顶向下选择规则)两步,保证生成的指令序列总代价最小。

相关推荐
Yuzhiyuxia几秒前
【AI Agent面试系列】AI Agent实战设计
人工智能·面试·职场和发展
syso_稻草人4 分钟前
qwen-image-2.1 PE 增强编辑:QwenImage21_EditPromptRewrite 一句话中文扩写成完整编辑指令
人工智能·stable diffusion·prompt·comfyui·qwen-image2.1
byte轻骑兵26 分钟前
时序数据库选型指南:Apache IoTDB 社区版实践与踩坑
数据库·人工智能·apache·时序数据库·iotdb
逐梦苍穹28 分钟前
DeepInfer 推理框架源码精讲:逐行读 DeepSeek 开源的推理引擎(2 小时 20 分视频+文字版)
人工智能·开源·ai编程·deepseek·claudecode·deepinfer·deepseekinfer
水如烟32 分钟前
孤能子视角:微软宕机是“极化”在数字基础设施层的显影——效率驱动下强关系集中到单一节点,弱关系备份被淘汰,可折返性丧失
人工智能
芯门1 小时前
GitHub「用好 AI」工具生态全景:2409 个仓库 Star 排行调研(2026-11)
人工智能·github
黄连木笛1 小时前
Redis Insight 汉化教程:Windows / macOS / Linux 设置中文界面(附繁體、教程汉化、关闭自动更新)
数据库·redis·缓存
nice_lcj5201 小时前
MySQL 存储引擎入门:InnoDB 和 MyISAM 到底怎么选
java·数据库·mysql·面试·innodb·存储引擎·myisam
say_fall2 小时前
【Linux网络编程】UDP套接字编程:系统编程组件、基础回显服务、InetAddr与地址转换、翻译服务与线程池聊天室
linux·服务器·网络·udp·vr
lucas_AI2 小时前
RAG 给你的答案,其实先「筛」过了你的证据——这个工具把黑箱拆开给你看
人工智能