Go to file
wangfiox 5b3fcd0900 update 2024-04-19 22:54:36 +08:00
src qbqp 2024-04-19 21:53:22 +08:00
.gitignore qbqp 2024-04-19 21:53:22 +08:00
Cargo.lock qbqp 2024-04-19 21:53:22 +08:00
Cargo.toml qbqp 2024-04-19 21:53:22 +08:00
README.md update 2024-04-19 22:54:36 +08:00

README.md

QBQP 算法

寄存器分配算法。

约束方程的含义

主要就是约束方程了:


min\{ \sum_{i \le i \lt j \le n} X_i^T C_{ij} X_j + \sum_{i=1}^n X_i^T \vec{E(t_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_it_j 之间的相互影响
    • i === j? (不一定比方说在传参的时候i 可以放到 a0 但是 j 是不能放到 a0 的)
    • 但是我有一种想法: 就是我认为还是要把 32 个寄存器全部摆上台面的,如果不能用,我认为可以相应的可以设置为 \infin ,这显然可能会变成一个 稀疏矩阵,然后是不是可以进行 凸优化啥的。如果 i!=j 并且有: R_i ^ R_j \ne \phi 那这可能需要对齐,可能有点麻烦
    • 如果 i === j那么可以做一件事情c_{ij} 的对角线设置为 负数。对角线意味着: virtual reg t_it_j 是可接合的,可以分配到 同一个 physical reg 的,负数的 语义 是:鼓励接合(代价总是越小越好)
  • \vec{E(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 E(t_i)

启发式 规约求解

reduce 1

如果只有 K^2 的完全图,有两个节点 X 和 Y 那么上面的约束方程可以写成:


min\{ X^T C Y + X^T \vec{E(x)} + Y^T \vec{E(y)} \}

最终经过一通数学计算可以得到: (如何求解? 一个关键步骤是: 令 某一串式子 = 0


Y^T ( \vec{E(y)} + ( ... min\{ X + C_{,k} \}_{ 1 \le k \le i } ... )_{i} )

reduce 2

C_yz[i][j] = min{ C_xy(第i列) + C_xz(第j列) + E_x }

这里将一个向量 通过 min(reduce) 规约成一个标量

reduce N

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, :);
}

state i -> 指的是选中 C_xy 的第 i 列( y 是 x 的所有 adj -> delta(i) += C_xy(i, :)。 找到 delta(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) {
	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)