Skip to content

Commit

Permalink
Implement def-use chain
Browse files Browse the repository at this point in the history
Implement a new structure for def-use chain called "use_chain_t".
"use_chain_t" is stored within "struct var", includes "insn" element
that records the instruction using the variable which the use chain
belongs to.

Simplify CSE procedure with use chain information. We build the def-use
chain information by "build_users" function before the optimizing phase.
In addtion, When the instructions are eliminated by CSE, we delete its
use chain nodes from both variables("rs1", "rs2") at the same time.

The CSE method has been modified. When the first pair of instructions is
found, the use chain is utilized to search for identical ADD
instructions. Subsequently, the next instruction is verified to ensure
it match our target. After removing the instruction, utilize the use
chain to find the next target instruction.

Use the following code as an example. Note that it should be compiled
with option "--no-libc" and the DCE should be disabled.
```
int main()
{
    char arr[1];
    int i, t, pos = 0;
    for (i = 0; i < 10000000; i++)
        t = arr[pos] + arr[pos];
    return 0;
}
```
The difference between before and after CSE:

```
 ldr  r0, [sp, #4]
 ldr  r1, [sp, #9]
 add  r2, r0, r1
 ldrb r3, [r2]
-add  r2, r0, r1
-ldrb r4, [r2]
+mov  r2, r3
```
  • Loading branch information
nosba0957 committed Nov 6, 2024
1 parent 16484f2 commit 6cc9f3f
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 39 deletions.
12 changes: 10 additions & 2 deletions src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ struct ref_block_list {

typedef struct ref_block_list ref_block_list_t;

typedef struct insn insn_t;

typedef struct use_chain_node {
insn_t *insn;
struct use_chain_node *next;
struct use_chain_node *prev;
} use_chain_t;

struct var {
char type_name[MAX_TYPE_LEN];
char var_name[MAX_VAR_LEN];
Expand All @@ -174,6 +182,8 @@ struct var {
int subscripts_idx;
rename_t rename;
ref_block_list_t ref_block_list; /* blocks which kill variable */
use_chain_t *users_head;
use_chain_t *users_tail;
struct insn *last_assign;
int consumed;
bool is_ternary_ret;
Expand Down Expand Up @@ -316,8 +326,6 @@ struct insn {
char str[64];
};

typedef struct insn insn_t;

typedef struct {
insn_t *head;
insn_t *tail;
Expand Down
141 changes: 104 additions & 37 deletions src/ssa.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,54 @@ void build_rdf()
free(args);
}

void use_chain_add_tail(insn_t *i, var_t *var)
{
use_chain_t *u = calloc(1, sizeof(use_chain_t));
if (!u) {
printf("calloc failed\n");
abort();
}

u->insn = i;
if (!var->users_head)
var->users_head = u;
else
var->users_tail->next = u;
u->prev = var->users_tail;
var->users_tail = u;
}

void use_chain_delete(use_chain_t *u, var_t *var)
{
if (u->prev)
u->prev->next = u->next;
else {
var->users_head = u->next;
u->next->prev = NULL;
}
if (u->next)
u->next->prev = u->prev;
else {
var->users_tail = u->prev;
u->prev->next = NULL;
}
free(u);
}

void use_chain_build()
{
for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) {
for (basic_block_t *bb = fn->bbs; bb; bb = bb->rpo_next) {
for (insn_t *i = bb->insn_list.head; i; i = i->next) {
if (i->rs1)
use_chain_add_tail(i, i->rs1);
if (i->rs2)
use_chain_add_tail(i, i->rs2);
}
}
}
}

bool var_check_killed(var_t *var, basic_block_t *bb)
{
for (int i = 0; i < bb->live_kill_idx; i++) {
Expand Down Expand Up @@ -1170,63 +1218,80 @@ void ssa_build(int dump_ir)
}

/* Common Subexpression Elimination (CSE) */
/* TODO: simplify with def-use chain */
/* TODO: release detached insns node */
bool cse(insn_t *insn, basic_block_t *bb)
{
if (insn->opcode != OP_read)
return false;

insn_t *prev = insn->prev;

if (!prev)
return false;
if (prev->opcode != OP_add)
return false;
if (prev->rd != insn->rs1)
return false;

var_t *def = NULL, *base = prev->rs1, *idx = prev->rs2;
var_t *def = insn->rd, *base = prev->rs1, *idx = prev->rs2;
if (base->is_global || idx->is_global)
return false;

insn_t *i = prev;
for (basic_block_t *b = bb;; b = b->idom) {
if (!i)
i = b->insn_list.tail;

for (; i; i = i->prev) {
if (i == prev)
continue;
if (i->opcode != OP_add)
continue;
if (!i->next)
continue;
if (i->next->opcode != OP_read)
continue;
if (i->rs1 != base || i->rs2 != idx)
continue;
def = i->next->rd;
}
if (def)
break;
if (b->idom == b)
break;
}
use_chain_t *rs1_delete_user = NULL;
use_chain_t *rs2_delete_user = NULL;
for (use_chain_t *user = base->users_head; user; user = user->next) {
insn_t *i = user->insn;

if (!def)
return false;
/* Delete the use chain nodes found in the last loop */
if (rs1_delete_user) {
use_chain_delete(rs1_delete_user, rs1_delete_user->insn->rs1);
rs1_delete_user = NULL;
}
if (rs2_delete_user) {
use_chain_delete(rs2_delete_user, rs2_delete_user->insn->rs2);
rs2_delete_user = NULL;
}
if (i == prev)
continue;
if (i->opcode != OP_add)
continue;
if (!i->next)
continue;
if (i->next->opcode != OP_read)
continue;
if (i->rs1 != base || i->rs2 != idx)
continue;
basic_block_t *i_bb = i->belong_to;
bool check_dom = 0;
/* Check if the instructions are under the same dominate tree */
for (;; i_bb = i_bb->idom) {
if (i_bb == bb) {
check_dom = true;
break;
}
if (i_bb == i_bb->idom)
break;
}
if (!check_dom)
continue;

if (prev->prev) {
insn->prev = prev->prev;
prev->prev->next = insn;
} else {
bb->insn_list.head = insn;
insn->prev = NULL;
i->next->opcode = OP_assign;
i->next->rs1 = def;
if (i->prev) {
i->prev->next = i->next;
i->next->prev = i->prev;
} else {
i->belong_to->insn_list.head = i->next;
i->next->prev = NULL;
}
i->next->opcode = OP_assign;
i->next->rs1 = def;
/* Prepare information for deleting use chain nodes */
rs1_delete_user = user;
for (rs2_delete_user = i->rs2->users_head;
rs2_delete_user->insn != rs1_delete_user->insn;
rs2_delete_user = rs2_delete_user->next)
;
}

insn->opcode = OP_assign;
insn->rs1 = def;
return true;
}

Expand Down Expand Up @@ -1466,6 +1531,8 @@ void optimize()
build_rdom();
build_rdf();

use_chain_build();

for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) {
/* basic block level (control flow) optimizations */

Expand Down

0 comments on commit 6cc9f3f

Please sign in to comment.