From 4b759d977a1b8ab3a0e89db8c9b006f71aa79667 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 "uc_node_t". "uc_node_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_use_chain" 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, 110 insertions(+), 38 deletions(-) diff --git a/src/defs.h b/src/defs.h index a51cd8a0..3f94acf9 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; +} uc_node_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 */ + uc_node_t *use_chain_head; + uc_node_t *use_chain_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..b7fd1d23 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -401,6 +401,49 @@ void build_rdf() free(args); } +void use_chain_add_tail(insn_t *i, var_t *var) +{ + uc_node_t *n = calloc(1, sizeof(uc_node_t)); + n->insn = i; + if (!var->use_chain_head) + var->use_chain_head = n; + else + var->use_chain_tail->next = n; + n->prev = var->use_chain_tail; + var->use_chain_tail = n; +} + +void use_chain_delete(uc_node_t *node, var_t *var) +{ + if (node->prev) + node->prev->next = node->next; + else { + var->use_chain_head = node->next; + node->next->prev = NULL; + } + if (node->next) + node->next->prev = node->prev; + else { + var->use_chain_tail = node->prev; + node->prev->next = NULL; + } + free(node); +} + +void build_use_chain() +{ + 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++) { @@ -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,68 @@ 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) { + uc_node_t *rs1_delete_node = NULL; + uc_node_t *rs2_delete_node = NULL; + for (uc_node_t *node = base->use_chain_head; node; node = node->next) { + insn_t *i = node->insn; + + /* Delete the use chain nodes found in the last loop */ + if (rs1_delete_node) { + use_chain_delete(rs1_delete_node, rs1_delete_node->insn->rs1); + rs1_delete_node = NULL; + } + if (rs2_delete_node) { + use_chain_delete(rs2_delete_node, rs2_delete_node->insn->rs2); + rs2_delete_node = NULL; + } 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; + continue; + 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 (def) - break; - if (b->idom == b) - break; - } - - if (!def) - return false; + 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_node = node; + for (rs2_delete_node = i->rs2->use_chain_head; + rs2_delete_node->insn != rs1_delete_node->insn; + rs2_delete_node = rs2_delete_node->next) + ; } - - insn->opcode = OP_assign; - insn->rs1 = def; return true; } @@ -1466,6 +1528,8 @@ void optimize() build_rdom(); build_rdf(); + build_use_chain(); + for (fn_t *fn = FUNC_LIST.head; fn; fn = fn->next) { /* basic block level (control flow) optimizations */