Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c2333f0
docs: add IR spec
linsyking Jul 22, 2024
24a9c7b
feat: check prog
linsyking Jul 24, 2024
8ef096f
docs: IR
linsyking Jul 24, 2024
bf24fe2
docs: more instructions
linsyking Jul 24, 2024
7f28fd0
docs: IR instructions
linsyking Jul 24, 2024
e43ec3f
fix: reachable IR
linsyking Jul 27, 2024
8d3e835
feat: init live
linsyking Jul 28, 2024
db2fe87
feat: insn check
linsyking Jul 29, 2024
00fcb54
feat: in out set
linsyking Jul 29, 2024
8725287
feat: log
linsyking Jul 29, 2024
30e27ea
feat: add bb users
linsyking Jul 29, 2024
3a4ef08
fix: bb users
linsyking Jul 30, 2024
fc9123a
fix: void instructions
linsyking Jul 30, 2024
8679959
fix: LA
linsyking Jul 30, 2024
7d07eb5
feat: restructure
linsyking Aug 5, 2024
097b4a1
feat: check phi
linsyking Aug 5, 2024
2d0e9d0
feat: elim ssa
linsyking Aug 5, 2024
bcb26e6
feat: extend insn constructor
linsyking Aug 5, 2024
e6623d2
feat: add more ir
linsyking Aug 5, 2024
d73e235
feat: phi
linsyking Aug 5, 2024
15b2039
fix: phi constructor
linsyking Aug 5, 2024
68ca6e4
feat: val remove/add user
linsyking Aug 5, 2024
86d4683
feat: elim ssa
linsyking Aug 5, 2024
2de420d
refactor: rename
linsyking Aug 5, 2024
95dde7e
fix: code gen
linsyking Aug 5, 2024
2070d4a
feat: res management
linsyking Aug 5, 2024
ea6a2b8
feat: cg pipeline
linsyking Aug 5, 2024
7083721
feat: remove phi
linsyking Aug 5, 2024
414a782
fix: match
linsyking Aug 5, 2024
60824e0
feat: start live
linsyking Aug 6, 2024
5f689c8
fix: use dst
linsyking Aug 6, 2024
f0e4122
feat: finish liveness analysis
linsyking Aug 6, 2024
b6919b9
feat: CA
linsyking Aug 6, 2024
1951bbc
feat: init CA data
linsyking Aug 6, 2024
6f204b6
feat: init CA data type
linsyking Aug 6, 2024
2540c2a
feat: tag
linsyking Aug 6, 2024
3ea779d
feat: print interference graph
linsyking Aug 6, 2024
633fe5a
feat: finish interference graph
linsyking Aug 6, 2024
c23f5de
fix: graph coloring PEO
linsyking Aug 6, 2024
dd87930
feat: PEO
linsyking Aug 6, 2024
1341725
feat: color
linsyking Aug 7, 2024
7404d41
chore: format
linsyking Aug 7, 2024
d5e6e94
chore: format
linsyking Aug 7, 2024
0fc9d4a
feat: graph coloring
linsyking Aug 7, 2024
6ad1c0c
feat: finish reg alloc
linsyking Aug 7, 2024
28888ed
chore: format
linsyking Aug 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,18 @@ add_executable(
ir_helper.c
ir_bb.c
ir_insn.c
phi_pass.c
reachable_bb.c
add_counter_pass.c
add_stack_offset.c
add_constraint_pass.c
passes/phi_pass.c
passes/reachable_bb.c
passes/add_counter_pass.c
passes/add_constraint_pass.c
passes/cut_bb_pass.c
aux/add_stack_offset.c
aux/live_variable.c
aux/prog_check.c
aux/eliminate_ssa.c
aux/conflict_analysis.c
aux/graph_coloring.c
ir_code_gen.c
)

add_executable(probe probe.c read.c array.c)
Expand Down
17 changes: 17 additions & 0 deletions IR/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ void array_erase(struct array *arr, size_t idx) {
arr->num_elem--;
}

void array_clear(struct array *arr) {
__free(arr->data);
arr->data = __malloc(arr->elem_size * 4);
arr->max_elem = 4;
arr->num_elem = 0;
}

struct array array_clone(struct array *arr) {
struct array res;
res.num_elem = arr->num_elem;
res.max_elem = arr->max_elem;
res.elem_size = arr->elem_size;
res.data = __malloc(arr->max_elem * arr->elem_size);
memcpy(res.data, arr->data, arr->num_elem * arr->elem_size);
return res;
}

void array_free(struct array *arr) {
__free(arr->data);
*arr = array_null();
Expand Down
2 changes: 1 addition & 1 deletion IR/add_stack_offset.c → IR/aux/add_stack_offset.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ void add_stack_offset(struct ir_function *fun, __s16 offset) {
insn->addr_val.offset += offset;
continue;
}
struct array value_uses = find_value_uses(insn);
struct array value_uses = get_operands(insn);
struct ir_value **pos2;
array_for(pos2, value_uses) {
struct ir_value *val = *pos2;
Expand Down
82 changes: 82 additions & 0 deletions IR/aux/conflict_analysis.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include <stdio.h>
#include "array.h"
#include "bpf_ir.h"
#include "code_gen.h"
#include "dbg.h"
#include "ir_helper.h"

int is_final(struct ir_insn *v1) {
return v1 == dst(v1);
}

void build_conflict(struct ir_insn *v1, struct ir_insn *v2) {
if (!is_final(v1) || !is_final(v2)) {
CRITICAL("Can only build conflict on final values");
}
if (v1 == v2) {
return;
}
array_push_unique(&insn_cg(v1)->adj, &v2);
array_push_unique(&insn_cg(v2)->adj, &v1);
}

void print_interference_graph(struct ir_function *fun) {
// Tag the IR to have the actual number to print
tag_ir(fun);
struct ir_insn **pos;
array_for(pos, fun->cg_info.all_var) {
struct ir_insn *insn = *pos;
if (!is_final(insn)) {
// Not final value, give up
CRITICAL("Not Final Value!");
}
struct ir_insn_cg_extra *extra = insn_cg(insn);
if (extra->allocated) {
printf("%%%zu(", insn->_insn_id);
if (extra->spilled) {
printf("sp-%zu", extra->spilled * 8);
} else {
printf("r%u", extra->alloc_reg);
}
printf("): ");
} else {
printf("%%%zu: ", insn->_insn_id);
}
struct ir_insn **pos2;
array_for(pos2, insn_cg(insn)->adj) {
struct ir_insn *adj_insn = *pos2;
if (!is_final(insn)) {
// Not final value, give up
CRITICAL("Not Final Value!");
}
printf("%%%zu, ", adj_insn->_insn_id);
}
printf("\n");
}
}

void conflict_analysis(struct ir_function *fun) {
// Basic conflict:
// For every x in KILL set, x is conflict with every element in OUT set.

struct ir_basic_block **pos;
// For each BB
array_for(pos, fun->reachable_bbs) {
struct ir_basic_block *bb = *pos;
struct ir_bb_cg_extra *bb_cg = bb->user_data;
struct ir_insn **pos2;
array_for(pos2, bb_cg->out) {
struct ir_insn *insn_dst = dst(*pos2);
// Add the variable to the "all variable set"
array_push_unique(&fun->cg_info.all_var, &insn_dst);
}
array_for(pos2, bb_cg->kill) {
struct ir_insn *insn_dst = dst(*pos2);
array_push_unique(&fun->cg_info.all_var, &insn_dst);
struct ir_insn **pos3;
array_for(pos3, bb_cg->out) {
build_conflict(insn_dst, dst(*pos3));
}
}
}
}
90 changes: 90 additions & 0 deletions IR/aux/eliminate_ssa.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include "code_gen.h"
#include "array.h"
#include "bpf_ir.h"
#include "dbg.h"
#include "ir_fun.h"
#include "ir_insn.h"

// Convert from TSSA to CSSA
// Using "Method I" in paper "Translating Out of Static Single Assignment Form"
void to_cssa(struct ir_function *fun) {
struct array phi_insns = INIT_ARRAY(struct ir_insn *);

struct ir_basic_block **pos;
array_for(pos, fun->reachable_bbs) {
struct ir_basic_block *bb = *pos;
struct ir_insn *insn;
list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) {
if (insn->op == IR_INSN_PHI) {
array_push(&phi_insns, &insn);
} else {
break;
}
}
}

struct ir_insn **pos2;
array_for(pos2, phi_insns) {
struct ir_insn *insn = *pos2;
// Create the moved PHI insn
struct ir_insn *new_phi = create_phi_insn(insn, INSERT_FRONT);
struct phi_value *pos3;
array_for(pos3, insn->phi) {
struct ir_insn *new_insn =
create_assign_insn_bb(pos3->bb, pos3->value, INSERT_BACK_BEFORE_JMP);
// Remove use
val_remove_user(pos3->value, insn);
phi_add_operand(new_phi, pos3->bb, ir_value_insn(new_insn));
}

array_free(&insn->phi);
insn->op = IR_INSN_ASSIGN;
struct ir_value val = ir_value_insn(new_phi);
insn->values[0] = val;
insn->value_num = 1;
val_add_user(val, insn);
}

array_free(&phi_insns);
}

// Remove PHI insn
void remove_phi(struct ir_function *fun) {
// dst information ready
struct array phi_insns = INIT_ARRAY(struct ir_insn *);

struct ir_basic_block **pos;
array_for(pos, fun->reachable_bbs) {
struct ir_basic_block *bb = *pos;
struct ir_insn *insn;
list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) {
if (insn->op == IR_INSN_PHI) {
array_push(&phi_insns, &insn);
} else {
break;
}
}
}

struct ir_insn **pos2;
array_for(pos2, phi_insns) {
struct ir_insn *insn = *pos2;
struct ir_insn *repr = NULL;
struct phi_value *pos3;
array_for(pos3, insn->phi) {
if (!repr) {
repr = pos3->value.data.insn_d;
} else {
insn_cg(pos3->value.data.insn_d)->dst = repr;
}
}
if (!repr) {
CRITICAL("Empty Phi not removed!");
}

replace_all_usage(insn, ir_value_insn(repr));
erase_insn(insn);
}

array_free(&phi_insns);
}
75 changes: 75 additions & 0 deletions IR/aux/graph_coloring.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <linux/bpf.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "array.h"
#include "bpf_ir.h"
#include "code_gen.h"
#include "dbg.h"
#include "ir_helper.h"

int compare_insn(const void *a, const void *b) {
struct ir_insn *ap = *(struct ir_insn **)a;
struct ir_insn *bp = *(struct ir_insn **)b;
return ap->_insn_id > bp->_insn_id;
}

void graph_coloring(struct ir_function *fun) {
// Using the Chaitin's Algorithm
// Using the simple dominance heuristic (Simple traversal of BB)
tag_ir(fun);
struct array *all_var = &fun->cg_info.all_var;
qsort(all_var->data, all_var->num_elem, all_var->elem_size, &compare_insn);
// all_var is now PEO
struct ir_insn **pos;
array_for(pos, (*all_var)) {
// Allocate register for *pos
struct ir_insn *insn = *pos;
struct ir_insn_cg_extra *extra = insn_cg(insn);
struct ir_insn **pos2;

int used_reg[__MAX_BPF_REG] = {0};
struct array used_spill = INIT_ARRAY(size_t);
array_for(pos2, extra->adj) {
struct ir_insn *insn2 = *pos2; // Adj instruction
struct ir_insn_cg_extra *extra2 = insn_cg(insn2);
if (extra2->allocated) {
if (extra2->spilled) {
array_push_unique(&used_spill, &extra2->spilled);
} else {
used_reg[extra2->alloc_reg] = 1;
}
}
}
__u8 need_spill = 1;
for (__u8 i = 0; i < __MAX_BPF_REG; i++) {
if (!used_reg[i]) {
extra->allocated = 1;
printf("Allocate r%u for %zu\n", i, insn->_insn_id);
extra->alloc_reg = i;
need_spill = 0;
break;
}
}
if (need_spill) {
size_t sp = 1;
while (1) {
__u8 found = 1;
size_t *pos3;
array_for(pos3, used_spill) {
if (*pos3 == sp) {
sp++;
found = 0;
break;
}
}
if (found) {
extra->allocated = 1;
extra->spilled = sp;
break;
}
}
}
array_free(&used_spill);
}
}
Loading