From 99d2dacc7da2659bf4eb1e98091ce91218e3e023 Mon Sep 17 00:00:00 2001 From: Yu-Hui Wu Date: Thu, 17 Oct 2024 15:38:42 +0800 Subject: [PATCH] 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 disable. ``` 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 ``` --- src/defs.h | 12 ++++- src/ssa.c | 141 +++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 114 insertions(+), 39 deletions(-) diff --git a/src/defs.h b/src/defs.h index a51cd8a0..040b1a72 100644 --- a/src/defs.h +++ b/src/defs.h @@ -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]; @@ -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; @@ -316,8 +326,6 @@ struct insn { char str[64]; }; -typedef struct insn insn_t; - typedef struct { insn_t *head; insn_t *tail; diff --git a/src/ssa.c b/src/ssa.c index 8a860a5a..0c6c83bf 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -401,6 +401,54 @@ void build_rdf() free(args); } +void users_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 users_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 build_users() +{ + 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) + users_add_tail(i, i->rs1); + if (i->rs2) + users_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++) { @@ -1170,7 +1218,6 @@ 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) { @@ -1178,7 +1225,6 @@ bool cse(insn_t *insn, basic_block_t *bb) return false; insn_t *prev = insn->prev; - if (!prev) return false; if (prev->opcode != OP_add) @@ -1186,47 +1232,66 @@ bool cse(insn_t *insn, basic_block_t *bb) 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) { + users_delete(rs1_delete_user, rs1_delete_user->insn->rs1); + rs1_delete_user = NULL; + } + if (rs2_delete_user) { + users_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; } @@ -1466,6 +1531,8 @@ void optimize() build_rdom(); build_rdf(); + build_users(); + for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) { /* basic block level (control flow) optimizations */