Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_executable(
aux/eliminate_ssa.c
aux/conflict_analysis.c
aux/graph_coloring.c
aux/explicit_reg.c
ir_code_gen.c
)

Expand Down
33 changes: 16 additions & 17 deletions IR/aux/conflict_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "code_gen.h"
#include "dbg.h"
#include "ir_helper.h"
#include "list.h"

int is_final(struct ir_insn *v1) {
return v1 == dst(v1);
Expand Down Expand Up @@ -62,23 +63,21 @@ void conflict_analysis(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_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));
}
array_for(pos3, bb_cg->kill) {
build_conflict(insn_dst, dst(*pos3));
struct ir_basic_block *bb = *pos;
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;
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);
struct ir_insn **pos3;
array_for(pos3, insn_cg->out) {
DBGASSERT(*pos3 == dst(*pos3));
build_conflict(insn_dst, *pos3);
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions IR/aux/eliminate_ssa.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ void remove_phi(struct ir_function *fun) {
CRITICAL("Empty Phi not removed!");
}

DBGASSERT(repr == dst(repr));

replace_all_usage(insn, ir_value_insn(repr));
erase_insn(insn);
}
Expand Down
65 changes: 65 additions & 0 deletions IR/aux/explicit_reg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Make register usage explicit
// Example:
// %x = add %y, %arg1
// arg1 is r0 at the beginning of the function
// We then add a new instruction to the beginning of the function.

#include <stdio.h>
#include "array.h"
#include "bpf_ir.h"
#include "code_gen.h"
#include "dbg.h"
#include "ir_insn.h"
#include "ir_helper.h"

void explicit_reg(struct ir_function *fun) {
// fun is still in IR form
// Before this step, users are correct
// In this step we change some dsts
// We need carefully handle the users
// dsts are NOT users
// Invariant: All operands are final values
// 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);
}
}
}
// 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) {
// Insert ASSIGN arg[i] at the beginning of the function
struct ir_insn *new_insn = create_assign_insn_bb_cg(
fun->entry, ir_value_insn(fun->cg_info.regs[i + 1]), INSERT_FRONT_AFTER_PHI);
replace_all_usage(fun->function_arg[i], ir_value_insn(new_insn));
}
}
}
7 changes: 3 additions & 4 deletions IR/aux/graph_coloring.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#include <linux/bpf.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "array.h"
#include "bpf_ir.h"
#include "code_gen.h"
Expand All @@ -28,8 +27,8 @@ void graph_coloring(struct ir_function *fun) {
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);
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);
Expand All @@ -42,7 +41,7 @@ void graph_coloring(struct ir_function *fun) {
}
}
__u8 need_spill = 1;
for (__u8 i = 0; i < __MAX_BPF_REG; i++) {
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);
Expand Down
95 changes: 58 additions & 37 deletions IR/aux/live_variable.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "bpf_ir.h"
#include "code_gen.h"
#include "dbg.h"
#include "ir_bb.h"
#include "ir_fun.h"
#include "ir_insn.h"
#include "list.h"
Expand All @@ -25,26 +26,27 @@ void gen_kill(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_bb_cg_extra *bb_cg = bb->user_data;
struct ir_basic_block *bb = *pos;
struct ir_insn *pos2;
// For each operation in reverse
list_for_each_entry_reverse(pos2, &bb->ir_insn_head, list_ptr) {
struct ir_insn *insn_dst = dst(pos2);
// For each operation
list_for_each_entry(pos2, &bb->ir_insn_head, list_ptr) {
struct ir_insn *insn_dst = dst(pos2);
struct ir_insn_cg_extra *insn_cg = pos2->user_data;
if (!is_void(pos2) && insn_dst) {
array_erase_elem(&bb_cg->gen, insn_dst);
array_push_unique(&bb_cg->kill, &insn_dst);
array_push_unique(&insn_cg->kill, &insn_dst);
}
struct array value_uses = get_operands(pos2);
struct ir_value **pos3;
array_for(pos3, value_uses) {
struct ir_value *val = *pos3;
if (val->type == IR_VALUE_INSN) {
struct ir_insn *insn = dst(val->data.insn_d);
array_push_unique(&bb_cg->gen, &insn);
array_erase_elem(&bb_cg->kill, insn);
struct ir_insn *insn = val->data.insn_d;
DBGASSERT(insn == dst(insn));
array_push_unique(&insn_cg->gen, &insn);
// array_erase_elem(&insn_cg->kill, insn);
}
}
array_free(&value_uses);
}
}
}
Expand Down Expand Up @@ -100,52 +102,71 @@ void in_out(struct ir_function *fun) {
change = 0;
struct ir_basic_block **pos;
array_for(pos, fun->reachable_bbs) {
struct ir_basic_block *bb = *pos;
struct ir_bb_cg_extra *bb_cg = bb->user_data;
struct array old_in = bb_cg->in;
struct ir_basic_block **pos2;
array_clear(&bb_cg->out);
array_for(pos2, bb->succs) {
struct ir_bb_cg_extra *bb_cg2 = (*pos2)->user_data;
merge_array(&bb_cg->out, &bb_cg2->in);
}
struct array out_kill_delta = array_delta(&bb_cg->out, &bb_cg->kill);
bb_cg->in = array_clone(&bb_cg->gen);
merge_array(&bb_cg->in, &out_kill_delta);
// Check for change
if (!equal_set(&bb_cg->in, &old_in)) {
change = 1;
struct ir_basic_block *bb = *pos;
struct ir_insn *insn;

list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) {
struct ir_insn_cg_extra *insn_cg = insn->user_data;
struct array old_in = insn_cg->in;
array_clear(&insn_cg->out);

if (get_last_insn(bb) == insn) {
// Last instruction
struct ir_basic_block **pos2;
array_for(pos2, bb->succs) {
struct ir_basic_block *bb2 = *pos2;
if (bb_empty(bb2)) {
CRITICAL("Found empty BB");
}
struct ir_insn *first = get_first_insn(bb2);
struct ir_insn_cg_extra *insn2_cg = first->user_data;
merge_array(&insn_cg->out, &insn2_cg->in);
}
} else {
// Not last instruction
struct ir_insn *next_insn =
list_entry(insn->list_ptr.next, struct ir_insn, list_ptr);
struct ir_insn_cg_extra *next_insn_cg = next_insn->user_data;
merge_array(&insn_cg->out, &next_insn_cg->in);
}
struct array out_kill_delta = array_delta(&insn_cg->out, &insn_cg->kill);
insn_cg->in = array_clone(&insn_cg->gen);
merge_array(&insn_cg->in, &out_kill_delta);
// Check for change
if (!equal_set(&insn_cg->in, &old_in)) {
change = 1;
}
// Collect grabage
array_free(&out_kill_delta);
array_free(&old_in);
}
// Collect grabage
array_free(&out_kill_delta);
array_free(&old_in);
}
}
}

void print_bb_extra(struct ir_basic_block *bb) {
struct ir_bb_cg_extra *bb_cg = bb->user_data;
if (bb->user_data == NULL) {
void print_insn_extra(struct ir_insn *insn) {
struct ir_insn_cg_extra *insn_cg = insn->user_data;
if (insn_cg == NULL) {
CRITICAL("NULL user data");
}
printf("--\nGen:");
struct ir_insn **pos;
array_for(pos, bb_cg->gen) {
array_for(pos, insn_cg->gen) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
}
printf("\nKill:");
array_for(pos, bb_cg->kill) {
array_for(pos, insn_cg->kill) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
}
printf("\nIn:");
array_for(pos, bb_cg->in) {
array_for(pos, insn_cg->in) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
}
printf("\nOut:");
array_for(pos, bb_cg->out) {
array_for(pos, insn_cg->out) {
struct ir_insn *insn = *pos;
printf(" %%%zu", insn->_insn_id);
}
Expand All @@ -157,6 +178,6 @@ void liveness_analysis(struct ir_function *fun) {
gen_kill(fun);
in_out(fun);
printf("--------------\n");
print_ir_prog_advanced(fun, print_bb_extra, print_ir_dst);
print_ir_prog_advanced(fun, NULL, print_ir_dst);
print_ir_prog_advanced(fun, NULL, print_insn_extra, print_ir_dst);
print_ir_prog_advanced(fun, NULL, NULL, print_ir_dst);
}
73 changes: 73 additions & 0 deletions IR/aux/prog_check.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,81 @@
#include "array.h"
#include "bpf_ir.h"
#include "dbg.h"
#include "ir_insn.h"
#include "list.h"

void check_insn_users_use_insn(struct ir_insn *insn) {
struct ir_insn **pos;
array_for(pos, insn->users) {
struct ir_insn *user = *pos;
// Check if the user actually uses this instruction
struct array operands = get_operands(user);
struct ir_value **val;
int found = 0;
array_for(val, operands) {
struct ir_value *v = *val;
if (v->type == IR_VALUE_INSN && v->data.insn_d == insn) {
// Found the user
found = 1;
break;
}
}
array_free(&operands);
if (!found) {
// Error!
CRITICAL("User does not use the instruction");
}
}
}

void check_insn_operand(struct ir_insn *insn) {
struct array operands = get_operands(insn);
struct ir_value **val;
array_for(val, operands) {
struct ir_value *v = *val;
if (v->type == IR_VALUE_INSN) {
// Check if the operand actually is used by this instruction
struct ir_insn **pos2;
int found = 0;
array_for(pos2, v->data.insn_d->users) {
struct ir_insn *user = *pos2;
if (user == insn) {
// Found the user
found = 1;
break;
}
}
if (!found) {
// Error!
CRITICAL("Operand is not used by the instruction");
}
}
}
array_free(&operands);
}

// Check if the users are correct (only applicable to SSA IR form)
void check_users(struct ir_function *fun) {
// Check FunctionCallArgument Instructions
for (__u8 i = 0; i < MAX_FUNC_ARG; ++i) {
struct ir_insn *insn = fun->function_arg[i];
check_insn_users_use_insn(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) {
// Check users of this instruction
check_insn_users_use_insn(insn);
// Check operands of this instruction
check_insn_operand(insn);
}
}
}

void check_jumping(struct ir_function *fun) {}

// Check if the PHI nodes are at the beginning of the BB
void check_phi(struct ir_function *fun) {
struct ir_basic_block **pos;
Expand Down
Loading