aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/memops.c
diff options
Diffstat (limited to 'memops.c')
-rw-r--r--memops.c100
1 files changed, 62 insertions, 38 deletions
diff --git a/memops.c b/memops.c
index ff54208e..bfcdc198 100644
--- a/memops.c
+++ b/memops.c
@@ -17,23 +17,20 @@
#include "simplify.h"
#include "flow.h"
-/*
- * We should probably sort the phi list just to make it easier to compare
- * later for equality.
- */
static void rewrite_load_instruction(struct instruction *insn, struct pseudo_list *dominators)
{
- pseudo_t new, phi;
+ pseudo_t new = NULL;
+ pseudo_t phi;
/*
* Check for somewhat common case of duplicate
* phi nodes.
*/
- new = first_pseudo(dominators)->def->phi_src;
FOR_EACH_PTR(dominators, phi) {
- if (new != phi->def->phi_src)
+ if (!new)
+ new = phi->def->phi_src;
+ else if (new != phi->def->phi_src)
goto complex_phi;
- new->ident = new->ident ? : phi->ident;
} END_FOR_EACH_PTR(phi);
/*
@@ -48,9 +45,7 @@ static void rewrite_load_instruction(struct instruction *insn, struct pseudo_lis
goto end;
complex_phi:
- /* We leave symbol pseudos with a bogus usage list here */
- if (insn->src->type != PSEUDO_SYM)
- kill_use(&insn->src);
+ kill_use(&insn->src);
insn->opcode = OP_PHI;
insn->phi_list = dominators;
@@ -58,15 +53,15 @@ end:
repeat_phase |= REPEAT_CSE;
}
-static int find_dominating_parents(pseudo_t pseudo, struct instruction *insn,
- struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators,
+static int find_dominating_parents(struct instruction *insn,
+ struct basic_block *bb, struct pseudo_list **dominators,
int local)
{
struct basic_block *parent;
FOR_EACH_PTR(bb->parents, parent) {
+ struct instruction *phisrc;
struct instruction *one;
- struct instruction *br;
pseudo_t phi;
FOR_EACH_PTR_REVERSE(parent->insns, one) {
@@ -75,7 +70,7 @@ static int find_dominating_parents(pseudo_t pseudo, struct instruction *insn,
continue;
if (one == insn)
goto no_dominance;
- dominance = dominates(pseudo, insn, one, local);
+ dominance = dominates(insn, one, local);
if (dominance < 0) {
if (one->opcode == OP_LOAD)
continue;
@@ -86,21 +81,21 @@ static int find_dominating_parents(pseudo_t pseudo, struct instruction *insn,
goto found_dominator;
} END_FOR_EACH_PTR_REVERSE(one);
no_dominance:
- if (parent->generation == generation)
+ if (parent->generation == bb->generation)
continue;
- parent->generation = generation;
+ parent->generation = bb->generation;
- if (!find_dominating_parents(pseudo, insn, parent, generation, dominators, local))
+ if (!find_dominating_parents(insn, parent, dominators, local))
return 0;
continue;
found_dominator:
- br = delete_last_instruction(&parent->insns);
- phi = alloc_phi(parent, one->target, one->type);
+ phisrc = alloc_phisrc(one->target, one->type);
+ phisrc->phi_node = insn;
+ insert_last_instruction(parent, phisrc);
+ phi = phisrc->target;
phi->ident = phi->ident ? : one->target->ident;
- add_instruction(&parent->insns, br);
use_pseudo(insn, phi, add_pseudo(dominators, phi));
- phi->def->phi_node = insn;
} END_FOR_EACH_PTR(parent);
return 1;
}
@@ -146,7 +141,6 @@ static void simplify_loads(struct basic_block *bb)
pseudo_t pseudo = insn->src;
int local = local_pseudo(pseudo);
struct pseudo_list *dominators;
- unsigned long generation;
if (insn->is_volatile)
continue;
@@ -160,7 +154,7 @@ static void simplify_loads(struct basic_block *bb)
int dominance;
if (!dom->bb)
continue;
- dominance = dominates(pseudo, insn, dom, local);
+ dominance = dominates(insn, dom, local);
if (dominance) {
/* possible partial dominance? */
if (dominance < 0) {
@@ -177,10 +171,9 @@ static void simplify_loads(struct basic_block *bb)
} END_FOR_EACH_PTR_REVERSE(dom);
/* OK, go find the parents */
- generation = ++bb_generation;
- bb->generation = generation;
+ bb->generation = ++bb_generation;
dominators = NULL;
- if (find_dominating_parents(pseudo, insn, bb, generation, &dominators, local)) {
+ if (find_dominating_parents(insn, bb, &dominators, local)) {
/* This happens with initial assignments to structures etc.. */
if (!dominators) {
if (local) {
@@ -204,6 +197,30 @@ next_load:
} END_FOR_EACH_PTR_REVERSE(insn);
}
+static bool try_to_kill_store(struct instruction *insn,
+ struct instruction *dom, int local)
+{
+ int dominance = dominates(insn, dom, local);
+
+ if (dominance) {
+ /* possible partial dominance? */
+ if (dominance < 0)
+ return false;
+ if (insn->target == dom->target && insn->bb == dom->bb) {
+ // found a memop which makes the store redundant
+ kill_instruction_force(insn);
+ return false;
+ }
+ if (dom->opcode == OP_LOAD)
+ return false;
+ if (dom->is_volatile)
+ return false;
+ /* Yeehaa! Found one! */
+ kill_instruction_force(dom);
+ }
+ return true;
+}
+
static void kill_dominated_stores(struct basic_block *bb)
{
struct instruction *insn;
@@ -212,6 +229,7 @@ static void kill_dominated_stores(struct basic_block *bb)
if (!insn->bb)
continue;
if (insn->opcode == OP_STORE) {
+ struct basic_block *par;
struct instruction *dom;
pseudo_t pseudo = insn->src;
int local;
@@ -223,22 +241,28 @@ static void kill_dominated_stores(struct basic_block *bb)
local = local_pseudo(pseudo);
RECURSE_PTR_REVERSE(insn, dom) {
- int dominance;
if (!dom->bb)
continue;
- dominance = dominates(pseudo, insn, dom, local);
- if (dominance) {
- /* possible partial dominance? */
- if (dominance < 0)
- goto next_store;
- if (dom->opcode == OP_LOAD)
- goto next_store;
- /* Yeehaa! Found one! */
- kill_instruction_force(dom);
- }
+ if (!try_to_kill_store(insn, dom, local))
+ goto next_store;
} END_FOR_EACH_PTR_REVERSE(dom);
/* OK, we should check the parents now */
+ FOR_EACH_PTR(bb->parents, par) {
+
+ if (bb_list_size(par->children) != 1)
+ goto next_parent;
+ FOR_EACH_PTR(par->insns, dom) {
+ if (!dom->bb)
+ continue;
+ if (dom == insn)
+ goto next_parent;
+ if (!try_to_kill_store(insn, dom, local))
+ goto next_parent;
+ } END_FOR_EACH_PTR(dom);
+next_parent:
+ ;
+ } END_FOR_EACH_PTR(par);
}
next_store:
/* Do the next one */;