From 1eb0e8daa9dad23a240af38a290b5be3cbbd1fd6 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 "user_t". "user_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. --- src/defs.h | 12 ++++- src/ssa.c | 136 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 109 insertions(+), 39 deletions(-) diff --git a/src/defs.h b/src/defs.h index a51cd8a0..87745263 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; +} user_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 */ + user_t *users_head; + user_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..e7cf4203 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -401,6 +401,49 @@ void build_rdf() free(args); } +void users_add_tail(insn_t *i, var_t *var) +{ + user_t *u = calloc(1, sizeof(user_t)); + 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(user_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 +1213,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 +1220,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 +1227,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; - } + user_t *rs1_delete_user = NULL; + user_t *rs2_delete_user = NULL; + for (user_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 +1526,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 */