wangfiox 36985b42e9 | ||
---|---|---|
src | ||
.gitignore | ||
Cargo.lock | ||
Cargo.toml | ||
README.md |
README.md
QBQP 算法
寄存器分配算法。
约束方程的含义
主要就是约束方程了:
min\{ \sum_{i \le i \lt j \le n} X_i^T C_{ij} X_j + \sum_{i=1}^n s_i X_i \}
X_i = (x_{i, sp}, x_{i, r_1}, x_{i, r_2}, ..., x_{i, r_K})^T
- 这里
x_{i, sp}
表示将t_i
spill -> stack 的代价。 X_i = (x, xxx, ..., x)^T
只有一个 分量=1,其他都是 0- K 表示
t_i
有 K 个可选的寄存器(不一定是所有的 physical reg,这是显然的,比方说不想要破坏到 callee-saved 寄存器)。
- 这里
C_{ij}
量化了t_i
和t_j
之间的相互影响- i === j? (不一定,比方说在传参的时候,i 可以放到 a0, 但是 j 是不能放到 a0 的)
- 但是我有一种想法: 就是我认为还是要把 32 个寄存器全部摆上台面的,如果不能用,我认为可以相应的可以设置为
\infin
,这显然可能会变成一个 稀疏矩阵,然后是不是可以进行 凸优化啥的。如果 i!=j 并且有:R_i
^R_j \ne \phi
那这可能需要对齐,可能有点麻烦 - 如果 i === j,那么可以做一件事情:将
c_{ij}
的对角线设置为 负数。对角线意味着: virtual regt_i
和t_j
是可接合的,可以分配到 同一个 physical reg 的,负数的 语义 是:鼓励接合(代价总是越小越好)
s_i = (\vec{cost(i)}, \vec0, ..., \vec0)
\vec{cost(t_i)}
:t_i
(virtual reg) 溢出的代价。如果每个t_i
都选择了 spill ,那么相当于是:\forall t_i, X_i = (1, 0, ..., 0)
,那么\sum_{i=1}^n s_i X_i = \sum_{i=1}^n cost(t_i)
伪代码
伪代码 ( from 华保健 ) 如下:
void reduce_1(vertex x) {
y = adj(x);
for (i = 1; i < len(E_y); i++) {
delta(i) = min(C_xy(i, :) + E_x);
}
E_y += delta;
remote_vertex(x);
}
void reduce_2(vertex x) {
y, z = adj(x);
for (i = 1; i < len(E_y); i++) {
for (j = 1; j < len(E_z); j++) {
delta(i) = min(C_xy(i, :) + C_xz(j, :) + E_x);
}
}
C_yz += delta;
remote_vertex(x);
}
void reduce_N(vertex x) {
y, z = adj(x);
for (i = 1; i < len(E_y); i++) {
delta(i) = 0;
for (j = 1; j < len(E_z); j++) {
delta(i) = min(C_xy(i, :) + E_y);
}
}
min_index = get_min_index(delta);
for y : vertex in adj(x) {
E_y += C_xy(min_index, :);
}
remote_vertex(x);
}
void solve_PBQP(graph pbqp_model) {
while (pbqp_model still has edges) {
simplify(pbqp_model);
while (there exists any vertex x of degree 1) {
reduce_1(x);
}
while (there exists any vertex x of degree 2) {
reduce_2(x);
}
while (there exists any vertex x of degree >= 2) {
reduce_N(x);
}
}
}
rust
看 src/main.rs (from gpt)