1 /*
   2  * memops - try to combine memory ops.
   3  *
   4  * Copyright (C) 2004 Linus Torvalds
   5  */
   6 
   7 #include <string.h>
   8 #include <stdarg.h>
   9 #include <stdlib.h>
  10 #include <stdio.h>
  11 #include <stddef.h>
  12 #include <assert.h>
  13 
  14 #include "parse.h"
  15 #include "expression.h"
  16 #include "linearize.h"
  17 #include "flow.h"
  18 
  19 static int find_dominating_parents(pseudo_t pseudo, struct instruction *insn,
  20         struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators,
  21         int local)
  22 {
  23         struct basic_block *parent;
  24 
  25         FOR_EACH_PTR(bb->parents, parent) {
  26                 struct instruction *one;
  27                 struct instruction *br;
  28                 pseudo_t phi;
  29 
  30                 FOR_EACH_PTR_REVERSE(parent->insns, one) {
  31                         int dominance;
  32                         if (!one->bb)
  33                                 continue;
  34                         if (one == insn)
  35                                 goto no_dominance;
  36                         dominance = dominates(pseudo, insn, one, local);
  37                         if (dominance < 0) {
  38                                 if (one->opcode == OP_LOAD)
  39                                         continue;
  40                                 return 0;
  41                         }
  42                         if (!dominance)
  43                                 continue;
  44                         goto found_dominator;
  45                 } END_FOR_EACH_PTR_REVERSE(one);
  46 no_dominance:
  47                 if (parent->generation == generation)
  48                         continue;
  49                 parent->generation = generation;
  50 
  51                 if (!find_dominating_parents(pseudo, insn, parent, generation, dominators, local))
  52                         return 0;
  53                 continue;
  54 
  55 found_dominator:
  56                 br = delete_last_instruction(&parent->insns);
  57                 phi = alloc_phi(parent, one->target, one->size);
  58                 phi->ident = phi->ident ? : one->target->ident;
  59                 add_instruction(&parent->insns, br);
  60                 use_pseudo(insn, phi, add_pseudo(dominators, phi));
  61         } END_FOR_EACH_PTR(parent);
  62         return 1;
  63 }               
  64 
  65 static int address_taken(pseudo_t pseudo)
  66 {
  67         struct pseudo_user *pu;
  68         FOR_EACH_PTR(pseudo->users, pu) {
  69                 struct instruction *insn = pu->insn;
  70                 if (insn->bb && (insn->opcode != OP_LOAD && insn->opcode != OP_STORE))
  71                         return 1;
  72         } END_FOR_EACH_PTR(pu);
  73         return 0;
  74 }
  75 
  76 static int local_pseudo(pseudo_t pseudo)
  77 {
  78         return pseudo->type == PSEUDO_SYM
  79                 && !(pseudo->sym->ctype.modifiers & (MOD_STATIC | MOD_NONLOCAL))
  80                 && !address_taken(pseudo);
  81 }
  82 
  83 static void simplify_loads(struct basic_block *bb)
  84 {
  85         struct instruction *insn;
  86 
  87         FOR_EACH_PTR_REVERSE(bb->insns, insn) {
  88                 if (!insn->bb)
  89                         continue;
  90                 if (insn->opcode == OP_LOAD) {
  91                         struct instruction *dom;
  92                         pseudo_t pseudo = insn->src;
  93                         int local = local_pseudo(pseudo);
  94                         struct pseudo_list *dominators;
  95                         unsigned long generation;
  96 
  97                         /* Check for illegal offsets.. */
  98                         check_access(insn);
  99 
 100                         if (insn->type->ctype.modifiers & MOD_VOLATILE)
 101                                 continue;
 102 
 103                         RECURSE_PTR_REVERSE(insn, dom) {
 104                                 int dominance;
 105                                 if (!dom->bb)
 106                                         continue;
 107                                 dominance = dominates(pseudo, insn, dom, local);
 108                                 if (dominance) {
 109                                         /* possible partial dominance? */
 110                                         if (dominance < 0)  {
 111                                                 if (dom->opcode == OP_LOAD)
 112                                                         continue;
 113                                                 goto next_load;
 114                                         }
 115                                         /* Yeehaa! Found one! */
 116                                         convert_load_instruction(insn, dom->target);
 117                                         goto next_load;
 118                                 }
 119                         } END_FOR_EACH_PTR_REVERSE(dom);
 120 
 121                         /* OK, go find the parents */
 122                         generation = ++bb_generation;
 123                         bb->generation = generation;
 124                         dominators = NULL;
 125                         if (find_dominating_parents(pseudo, insn, bb, generation, &dominators, local)) {
 126                                 /* This happens with initial assignments to structures etc.. */
 127                                 if (!dominators) {
 128                                         if (local) {
 129                                                 assert(pseudo->type != PSEUDO_ARG);
 130                                                 convert_load_instruction(insn, value_pseudo(insn->type, 0));
 131                                         }
 132                                         goto next_load;
 133                                 }
 134                                 rewrite_load_instruction(insn, dominators);
 135                         }
 136                 }
 137 next_load:
 138                 /* Do the next one */;
 139         } END_FOR_EACH_PTR_REVERSE(insn);
 140 }
 141 
 142 static void kill_store(struct instruction *insn)
 143 {
 144         if (insn) {
 145                 insn->bb = NULL;
 146                 insn->opcode = OP_SNOP;
 147                 kill_use(&insn->target);
 148         }
 149 }
 150 
 151 static void kill_dominated_stores(struct basic_block *bb)
 152 {
 153         struct instruction *insn;
 154 
 155         FOR_EACH_PTR_REVERSE(bb->insns, insn) {
 156                 if (!insn->bb)
 157                         continue;
 158                 if (insn->opcode == OP_STORE) {
 159                         struct instruction *dom;
 160                         pseudo_t pseudo = insn->src;
 161                         int local = local_pseudo(pseudo);
 162 
 163                         RECURSE_PTR_REVERSE(insn, dom) {
 164                                 int dominance;
 165                                 if (!dom->bb)
 166                                         continue;
 167                                 dominance = dominates(pseudo, insn, dom, local);
 168                                 if (dominance) {
 169                                         /* possible partial dominance? */
 170                                         if (dominance < 0)
 171                                                 goto next_store;
 172                                         if (dom->opcode == OP_LOAD)
 173                                                 goto next_store;
 174                                         /* Yeehaa! Found one! */
 175                                         kill_store(dom);
 176                                 }
 177                         } END_FOR_EACH_PTR_REVERSE(dom);
 178 
 179                         /* OK, we should check the parents now */
 180                 }
 181 next_store:
 182                 /* Do the next one */;
 183         } END_FOR_EACH_PTR_REVERSE(insn);
 184 }
 185 
 186 void simplify_memops(struct entrypoint *ep)
 187 {
 188         struct basic_block *bb;
 189 
 190         FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
 191                 simplify_loads(bb);
 192         } END_FOR_EACH_PTR_REVERSE(bb);
 193 
 194         FOR_EACH_PTR_REVERSE(ep->bbs, bb) {
 195                 kill_dominated_stores(bb);
 196         } END_FOR_EACH_PTR_REVERSE(bb);
 197 }