Skip to content

Commit 6cc9f3f

Browse files
committed
Implement def-use chain
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 ```
1 parent 16484f2 commit 6cc9f3f

File tree

2 files changed

+114
-39
lines changed

2 files changed

+114
-39
lines changed

src/defs.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ struct ref_block_list {
157157

158158
typedef struct ref_block_list ref_block_list_t;
159159

160+
typedef struct insn insn_t;
161+
162+
typedef struct use_chain_node {
163+
insn_t *insn;
164+
struct use_chain_node *next;
165+
struct use_chain_node *prev;
166+
} use_chain_t;
167+
160168
struct var {
161169
char type_name[MAX_TYPE_LEN];
162170
char var_name[MAX_VAR_LEN];
@@ -174,6 +182,8 @@ struct var {
174182
int subscripts_idx;
175183
rename_t rename;
176184
ref_block_list_t ref_block_list; /* blocks which kill variable */
185+
use_chain_t *users_head;
186+
use_chain_t *users_tail;
177187
struct insn *last_assign;
178188
int consumed;
179189
bool is_ternary_ret;
@@ -316,8 +326,6 @@ struct insn {
316326
char str[64];
317327
};
318328

319-
typedef struct insn insn_t;
320-
321329
typedef struct {
322330
insn_t *head;
323331
insn_t *tail;

src/ssa.c

+104-37
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,54 @@ void build_rdf()
401401
free(args);
402402
}
403403

404+
void use_chain_add_tail(insn_t *i, var_t *var)
405+
{
406+
use_chain_t *u = calloc(1, sizeof(use_chain_t));
407+
if (!u) {
408+
printf("calloc failed\n");
409+
abort();
410+
}
411+
412+
u->insn = i;
413+
if (!var->users_head)
414+
var->users_head = u;
415+
else
416+
var->users_tail->next = u;
417+
u->prev = var->users_tail;
418+
var->users_tail = u;
419+
}
420+
421+
void use_chain_delete(use_chain_t *u, var_t *var)
422+
{
423+
if (u->prev)
424+
u->prev->next = u->next;
425+
else {
426+
var->users_head = u->next;
427+
u->next->prev = NULL;
428+
}
429+
if (u->next)
430+
u->next->prev = u->prev;
431+
else {
432+
var->users_tail = u->prev;
433+
u->prev->next = NULL;
434+
}
435+
free(u);
436+
}
437+
438+
void use_chain_build()
439+
{
440+
for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) {
441+
for (basic_block_t *bb = fn->bbs; bb; bb = bb->rpo_next) {
442+
for (insn_t *i = bb->insn_list.head; i; i = i->next) {
443+
if (i->rs1)
444+
use_chain_add_tail(i, i->rs1);
445+
if (i->rs2)
446+
use_chain_add_tail(i, i->rs2);
447+
}
448+
}
449+
}
450+
}
451+
404452
bool var_check_killed(var_t *var, basic_block_t *bb)
405453
{
406454
for (int i = 0; i < bb->live_kill_idx; i++) {
@@ -1170,63 +1218,80 @@ void ssa_build(int dump_ir)
11701218
}
11711219

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

11801227
insn_t *prev = insn->prev;
1181-
11821228
if (!prev)
11831229
return false;
11841230
if (prev->opcode != OP_add)
11851231
return false;
11861232
if (prev->rd != insn->rs1)
11871233
return false;
11881234

1189-
var_t *def = NULL, *base = prev->rs1, *idx = prev->rs2;
1235+
var_t *def = insn->rd, *base = prev->rs1, *idx = prev->rs2;
11901236
if (base->is_global || idx->is_global)
11911237
return false;
11921238

1193-
insn_t *i = prev;
1194-
for (basic_block_t *b = bb;; b = b->idom) {
1195-
if (!i)
1196-
i = b->insn_list.tail;
1197-
1198-
for (; i; i = i->prev) {
1199-
if (i == prev)
1200-
continue;
1201-
if (i->opcode != OP_add)
1202-
continue;
1203-
if (!i->next)
1204-
continue;
1205-
if (i->next->opcode != OP_read)
1206-
continue;
1207-
if (i->rs1 != base || i->rs2 != idx)
1208-
continue;
1209-
def = i->next->rd;
1210-
}
1211-
if (def)
1212-
break;
1213-
if (b->idom == b)
1214-
break;
1215-
}
1239+
use_chain_t *rs1_delete_user = NULL;
1240+
use_chain_t *rs2_delete_user = NULL;
1241+
for (use_chain_t *user = base->users_head; user; user = user->next) {
1242+
insn_t *i = user->insn;
12161243

1217-
if (!def)
1218-
return false;
1244+
/* Delete the use chain nodes found in the last loop */
1245+
if (rs1_delete_user) {
1246+
use_chain_delete(rs1_delete_user, rs1_delete_user->insn->rs1);
1247+
rs1_delete_user = NULL;
1248+
}
1249+
if (rs2_delete_user) {
1250+
use_chain_delete(rs2_delete_user, rs2_delete_user->insn->rs2);
1251+
rs2_delete_user = NULL;
1252+
}
1253+
if (i == prev)
1254+
continue;
1255+
if (i->opcode != OP_add)
1256+
continue;
1257+
if (!i->next)
1258+
continue;
1259+
if (i->next->opcode != OP_read)
1260+
continue;
1261+
if (i->rs1 != base || i->rs2 != idx)
1262+
continue;
1263+
basic_block_t *i_bb = i->belong_to;
1264+
bool check_dom = 0;
1265+
/* Check if the instructions are under the same dominate tree */
1266+
for (;; i_bb = i_bb->idom) {
1267+
if (i_bb == bb) {
1268+
check_dom = true;
1269+
break;
1270+
}
1271+
if (i_bb == i_bb->idom)
1272+
break;
1273+
}
1274+
if (!check_dom)
1275+
continue;
12191276

1220-
if (prev->prev) {
1221-
insn->prev = prev->prev;
1222-
prev->prev->next = insn;
1223-
} else {
1224-
bb->insn_list.head = insn;
1225-
insn->prev = NULL;
1277+
i->next->opcode = OP_assign;
1278+
i->next->rs1 = def;
1279+
if (i->prev) {
1280+
i->prev->next = i->next;
1281+
i->next->prev = i->prev;
1282+
} else {
1283+
i->belong_to->insn_list.head = i->next;
1284+
i->next->prev = NULL;
1285+
}
1286+
i->next->opcode = OP_assign;
1287+
i->next->rs1 = def;
1288+
/* Prepare information for deleting use chain nodes */
1289+
rs1_delete_user = user;
1290+
for (rs2_delete_user = i->rs2->users_head;
1291+
rs2_delete_user->insn != rs1_delete_user->insn;
1292+
rs2_delete_user = rs2_delete_user->next)
1293+
;
12261294
}
1227-
1228-
insn->opcode = OP_assign;
1229-
insn->rs1 = def;
12301295
return true;
12311296
}
12321297

@@ -1466,6 +1531,8 @@ void optimize()
14661531
build_rdom();
14671532
build_rdf();
14681533

1534+
use_chain_build();
1535+
14691536
for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) {
14701537
/* basic block level (control flow) optimizations */
14711538

0 commit comments

Comments
 (0)