Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
9fd2a0b
bug: conflict analysis not printing Reg correctly
linsyking Aug 14, 2024
14751e6
fix: print error
linsyking Aug 19, 2024
63abc08
fix: allocated
linsyking Aug 19, 2024
5729edc
fix: coloring
linsyking Aug 19, 2024
fa76069
feat: simple coaleasing
linsyking Aug 19, 2024
a6de70f
feat: spill
linsyking Aug 19, 2024
6016125
chore: optimize format script
linsyking Aug 19, 2024
4b32f0b
chore: optimize
linsyking Aug 19, 2024
cd60d29
feat: init spill
linsyking Aug 19, 2024
ba1725f
feat: spill
linsyking Aug 19, 2024
304fc6d
feat: spill draft
linsyking Aug 19, 2024
d09b810
feat: spill
linsyking Aug 19, 2024
2ea0b13
feat: explicit reg for ret
linsyking Aug 19, 2024
71b3be2
fix: 1 to 1 translation
linsyking Aug 19, 2024
91fbad0
chore: format
linsyking Aug 19, 2024
e60e7dc
feat: start translating
linsyking Aug 19, 2024
75d92eb
docs: bpf ISA
linsyking Aug 19, 2024
1875827
feat: caller saved register
linsyking Aug 19, 2024
4fe4b9c
feat: init callee save
linsyking Aug 19, 2024
61c8dfb
fix: clear all var
linsyking Aug 19, 2024
f5cfa9f
feat: save callee at the beginning
linsyking Aug 19, 2024
4321a57
fix: function signature
linsyking Aug 20, 2024
4d14627
chore: format
linsyking Aug 20, 2024
4114620
feat: restructure passes
linsyking Aug 20, 2024
980dcf0
feat: end bb
linsyking Aug 20, 2024
59af112
fix: reg
linsyking Aug 20, 2024
1c5dc87
feat: spill
linsyking Aug 20, 2024
2ab0291
chore: format
linsyking Aug 20, 2024
e7d6d4a
feat: start translating
linsyking Aug 20, 2024
96cb602
feat: translate
linsyking Aug 20, 2024
a847c02
feat: spill ALU
linsyking Aug 20, 2024
e321fcc
fix: spill
linsyking Aug 20, 2024
8024d58
feat: spill ALU, stack access
linsyking Aug 20, 2024
261671c
feat: spill
linsyking Aug 21, 2024
8006eec
feat: ALU
linsyking Aug 21, 2024
573520d
feat: spill JMP
linsyking Aug 21, 2024
44c4f04
feat: stack check
linsyking Aug 21, 2024
8d242a0
fix: translate
linsyking Aug 21, 2024
a166cae
fix: spill memory access
linsyking Aug 21, 2024
5d38f79
feat: start normalization
linsyking Aug 21, 2024
1c65a6c
feat: normalization
linsyking Aug 21, 2024
399642e
feat: normalization done
linsyking Aug 21, 2024
1536fd8
fix: normalize ASSIGN
linsyking Aug 21, 2024
2cabc50
fix: normalize ALU
linsyking Aug 21, 2024
79e93a4
feat: add imm type to pre_ir_insn
linsyking Aug 21, 2024
6cf22c3
feat: ALU const translation
linsyking Aug 21, 2024
46dfe8a
feat: load
linsyking Aug 21, 2024
e1723a2
fix: pointer
linsyking Aug 21, 2024
fddcf29
fix: loadraw
linsyking Aug 21, 2024
6f021bf
fix: no sign of VR type
linsyking Aug 21, 2024
6ec2094
feat: translate
linsyking Aug 21, 2024
8d2fa54
feat: load addr to reg
linsyking Aug 21, 2024
0e597e8
fix: bb succ order
linsyking Aug 21, 2024
685eab3
feat: start relocating
linsyking Aug 21, 2024
ad83175
chore: format
linsyking Aug 21, 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
16 changes: 16 additions & 0 deletions IR/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/build/read",
"args": ["tests/loop1.o"],
"cwd": "${workspaceFolder}"
}
]
}
9 changes: 8 additions & 1 deletion IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ add_executable(
passes/add_counter_pass.c
passes/add_constraint_pass.c
passes/cut_bb_pass.c
aux/add_stack_offset.c
passes/end_bb.c
aux/live_variable.c
aux/prog_check.c
aux/eliminate_ssa.c
aux/conflict_analysis.c
aux/graph_coloring.c
aux/explicit_reg.c
aux/coaleasing.c
aux/spill.c
aux/translate.c
aux/stack_alloc.c
aux/normalize.c
aux/fix_bb_succ.c
aux/relocate.c
ir_code_gen.c
)

Expand Down
6 changes: 6 additions & 0 deletions IR/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ To start with, a simple constaint would be "range constraint", meaning a registe

One opinion, one benefit of designing the raw constraint from is that our runtime-check system will not depend heavily on the current linux verifier and will be portable to other verifiers.

## Roadmap

- [x] Register spilling
- [x] Caller-saved/callee-saved register
- [ ] Translation

# TODO

- More instructions
Expand Down
7 changes: 7 additions & 0 deletions IR/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,10 @@ void array_free(struct array *arr) {
__free(arr->data);
*arr = array_null();
}

void *array_get_void(struct array *arr, size_t idx) {
if (idx >= arr->num_elem) {
return NULL;
}
return (char *)(arr->data) + arr->elem_size * idx;
}
30 changes: 30 additions & 0 deletions IR/aux/coaleasing.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include <stdio.h>
#include "bpf_ir.h"
#include "code_gen.h"
#include "dbg.h"
#include "ir_fun.h"
#include "ir_insn.h"
#include "list.h"

void coaleasing(struct ir_function *fun) {
struct ir_basic_block **pos;
// For each BB
array_for(pos, fun->reachable_bbs) {
struct ir_basic_block *bb = *pos;
struct ir_insn *pos2, *tmp;
// For each operation
list_for_each_entry_safe(pos2, tmp, &bb->ir_insn_head, list_ptr) {
struct ir_insn *insn_dst = dst(pos2);
if (pos2->op == IR_INSN_ASSIGN) {
if (pos2->values[0].type == IR_VALUE_INSN) {
struct ir_insn *src = pos2->values[0].data.insn_d;
DBGASSERT(src == dst(src));
if (insn_cg(src)->alloc_reg == insn_cg(insn_dst)->alloc_reg) {
// Remove
erase_insn_raw(pos2);
}
}
}
}
}
}
46 changes: 40 additions & 6 deletions IR/aux/conflict_analysis.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <linux/bpf.h>
#include <stdio.h>
#include "array.h"
#include "bpf_ir.h"
Expand Down Expand Up @@ -27,35 +28,50 @@ void print_interference_graph(struct ir_function *fun) {
struct ir_insn **pos;
array_for(pos, fun->cg_info.all_var) {
struct ir_insn *insn = *pos;
if (insn->op == IR_INSN_REG) {
CRITICAL("Pre-colored register should not be in all_var");
}
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) {
// Allocated VR
printf("%%%zu(", insn->_insn_id);
if (extra->spilled) {
printf("sp-%zu", extra->spilled * 8);
} else {
printf("r%u", extra->alloc_reg);
}
printf("): ");
printf("):");
} else {
printf("%%%zu: ", insn->_insn_id);
// Pre-colored registers or unallocated VR
print_insn_ptr_base(insn);
printf(":");
}
struct ir_insn **pos2;
array_for(pos2, insn_cg(insn)->adj) {
struct ir_insn *adj_insn = *pos2;
if (!is_final(insn)) {
if (!is_final(adj_insn)) {
// Not final value, give up
CRITICAL("Not Final Value!");
}
printf("%%%zu, ", adj_insn->_insn_id);
printf(" ");
print_insn_ptr_base(adj_insn);
}
printf("\n");
}
}

void caller_constraint(struct ir_function *fun, struct ir_insn *insn) {
for (__u8 i = BPF_REG_0; i < BPF_REG_6; ++i) {
// R0-R5 are caller saved register
DBGASSERT(fun->cg_info.regs[i] == dst(fun->cg_info.regs[i]));
build_conflict(fun->cg_info.regs[i], insn);
}
}

void conflict_analysis(struct ir_function *fun) {
// Basic conflict:
// For every x in KILL set, x is conflict with every element in OUT set.
Expand All @@ -67,12 +83,30 @@ void conflict_analysis(struct ir_function *fun) {
struct ir_insn *insn;
// For each operation
list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) {
struct ir_insn **pos2;
struct ir_insn_cg_extra *insn_cg = insn->user_data;
if (insn->op == IR_INSN_CALL) {
// Add caller saved register constraints
struct ir_insn **pos2;
array_for(pos2, insn_cg->in) {
DBGASSERT(*pos2 == dst(*pos2));
struct ir_insn **pos3;
array_for(pos3, insn_cg->out) {
DBGASSERT(*pos3 == dst(*pos3));
if (*pos2 == *pos3) {
// Live across CALL!
printf("Found a VR live across CALL!\n");
caller_constraint(fun, *pos2);
}
}
}
}
struct ir_insn **pos2;
array_for(pos2, insn_cg->kill) {
struct ir_insn *insn_dst = *pos2;
DBGASSERT(insn_dst == dst(insn_dst));
array_push_unique(&fun->cg_info.all_var, &insn_dst);
if (insn_dst->op != IR_INSN_REG) {
array_push_unique(&fun->cg_info.all_var, &insn_dst);
}
struct ir_insn **pos3;
array_for(pos3, insn_cg->out) {
DBGASSERT(*pos3 == dst(*pos3));
Expand Down
50 changes: 27 additions & 23 deletions IR/aux/explicit_reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,41 @@ void explicit_reg(struct ir_function *fun) {
// Final value: v == dst(v)
struct ir_basic_block **pos;
// Maximum number of functions: MAX_FUNC_ARG
struct array call_insns = INIT_ARRAY(struct ir_insn *);
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_CALL) {
array_push(&call_insns, &insn);
for (__u8 i = 0; i < insn->value_num; ++i) {
struct ir_value val = insn->values[i];
struct ir_insn *new_insn = create_assign_insn_cg(insn, val, INSERT_FRONT);
insn_cg(new_insn)->dst = fun->cg_info.regs[i + 1];
val_remove_user(val, insn);
}
insn->value_num = 0; // Remove all operands
struct ir_insn_cg_extra *extra = insn_cg(insn);
extra->dst = NULL;
if (insn->users.num_elem == 0) {
continue;
}
struct ir_insn *new_insn =
create_assign_insn_cg(insn, ir_value_insn(fun->cg_info.regs[0]), INSERT_BACK);
replace_all_usage(insn, ir_value_insn(new_insn));
}

if (insn->op == IR_INSN_RET) {
// ret x
// ==>
// R0 = x
// ret
struct ir_insn *new_insn =
create_assign_insn_cg(insn, insn->values[0], INSERT_FRONT);
val_remove_user(insn->values[0], insn);
insn_cg(new_insn)->dst = fun->cg_info.regs[0];
insn->value_num = 0;
}
}
}
// Functions that are called
struct ir_insn **pos2;
array_for(pos2, call_insns) {
struct ir_insn *insn = *pos2;
for (__u8 i = 0; i < insn->value_num; ++i) {
struct ir_value val = insn->values[i];
struct ir_insn *new_insn = create_assign_insn_cg(insn, val, INSERT_FRONT);
insn_cg(new_insn)->dst = fun->cg_info.regs[i + 1];
val_remove_user(val, insn);
}
insn->value_num = 0; // Remove all operands
struct ir_insn_cg_extra *extra = insn_cg(insn);
extra->dst = NULL;
if (insn->users.num_elem == 0) {
continue;
}
struct ir_insn *new_insn =
create_assign_insn_cg(insn, ir_value_insn(fun->cg_info.regs[0]), INSERT_BACK);
replace_all_usage(insn, ir_value_insn(new_insn));
}
array_free(&call_insns);
// Arg
for (__u8 i = 0; i < MAX_FUNC_ARG; ++i) {
if (fun->function_arg[i]->users.num_elem > 0) {
Expand Down
19 changes: 19 additions & 0 deletions IR/aux/fix_bb_succ.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "bpf_ir.h"
#include "dbg.h"
#include "ir_bb.h"
#include "ir_fun.h"

void fix_bb_succ(struct ir_function *fun) {
struct ir_basic_block **pos;
array_for(pos, fun->all_bbs) {
struct ir_basic_block *bb = *pos;
struct ir_insn *insn = get_last_insn(bb);
if (insn && insn->op >= IR_INSN_JEQ && insn->op < IR_INSN_PHI) {
// Conditional jmp
struct ir_basic_block **s1 = array_get(&bb->succs, 0, struct ir_basic_block *);
struct ir_basic_block **s2 = array_get(&bb->succs, 1, struct ir_basic_block *);
*s1 = insn->bb1;
*s2 = insn->bb2;
}
}
}
7 changes: 5 additions & 2 deletions IR/aux/graph_coloring.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ void graph_coloring(struct ir_function *fun) {
struct ir_insn **pos;
array_for(pos, (*all_var)) {
// Allocate register for *pos
struct ir_insn *insn = *pos;
struct ir_insn *insn = *pos;
if (insn->op == IR_INSN_REG) {
CRITICAL("Pre-colored register should not be in all_var");
}
struct ir_insn_cg_extra *extra = insn_cg(insn);
struct ir_insn **pos2;

Expand All @@ -44,7 +47,7 @@ void graph_coloring(struct ir_function *fun) {
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);
printf("Allocate r%u for %%%zu\n", i, insn->_insn_id);
extra->alloc_reg = i;
need_spill = 0;
break;
Expand Down
12 changes: 8 additions & 4 deletions IR/aux/live_variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,22 +153,26 @@ void print_insn_extra(struct ir_insn *insn) {
struct ir_insn **pos;
array_for(pos, insn_cg->gen) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
printf(" ");
print_insn_ptr_base(insn);
}
printf("\nKill:");
array_for(pos, insn_cg->kill) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
printf(" ");
print_insn_ptr_base(insn);
}
printf("\nIn:");
array_for(pos, insn_cg->in) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
printf(" ");
print_insn_ptr_base(insn);
}
printf("\nOut:");
array_for(pos, insn_cg->out) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
printf(" ");
print_insn_ptr_base(insn);
}
printf("\n-------------\n");
}
Expand Down
Loading