aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ir_cse.c
blob: 8e1805dc2b09a3cf12bba8dbe9e61e42b2707d4f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "ir.h"
#include "u_hash.h"

static inline bool
pure(const Instr *ins)
{
   return oisarith(ins->op) || (oisload(ins->op) && !ins->keep);
}

static inline bool
insequ(const Instr *a, const Instr *b)
{
   if (a->op != b->op) return 0;
   enum op op = a->op;
   switch (opnoper[op]) {
   default: assert(0);
   case 2: if (a->r.bits != b->r.bits) return 0;
   case 1: if (a->l.bits != b->l.bits) return 0;
   }
   return 1;
}

static struct Ht {
   uint t;
   ushort memno, cutoff;
   Block *b;
} *insht;
static uint ninsht;

static inline size_t
hashins(const Instr *ins)
{
   return hashb(0, ins, sizeof *ins);
}

static bool
doms(Block *blk, Block *b)
{
   for (;; b = b->idom) {
      if (blk == b) return 1;
      if (blk == b->idom) return 1;
      if (blk->id > b->id) return 0;
   }
}

static int
uniq(int t, Block *blk, int cutoff, int memno)
{
   assert((uint)t < MAXINSTR);
   Instr *ins = &instrtab[t];
   if (!pure(ins)) return t;
   for (size_t h = hashins(&instrtab[t]), i = h;; ++i) {
      struct Ht *p = &insht[i &= (ninsht-1)];
      if (!p->b) Put: {
         p->b = blk;
         p->memno = memno;
         p->cutoff = cutoff;
         return p->t = t;
      } else if (insequ(&instrtab[p->t], ins)) {
         if (p->cutoff == cutoff && (!oisload(ins->op) || p->memno == memno) && doms(p->b, blk))
            return p->t;
         goto Put;
      }
   }
}

void
cselim(Function *fn)
{
   FREQUIRE(FNUSE | FNRPO | FNDOM | FNBLKID);
   extern int ninstrtab;
   for (ninsht = 32; ninsht <= ninstrtab; ninsht *= 2) ;
   insht = allocz(fn->passarena, ninsht * sizeof *insht, 0);
   int memno = 0, cutoff = 0;
   Block *blk = fn->entry;
   do {
      ++memno;
      for (int i = 0; i < blk->ins.n; ++i) {
         int t = blk->ins.p[i], q;
         if ((q = uniq(t, blk, cutoff, memno)) != t) {
            replcuses(mkref(RTMP, t), mkref(RTMP, q));
            delinstr(blk, i--);
         } else if (oisstore(instrtab[t].op)) {
            /* assume everything alias everything */
            ++memno;
         } else if (instrtab[t].op == Ocall) {
            ++cutoff;
         }
      }
   } while ((blk = blk->lnext) != fn->entry);
}

/* vim:set ts=3 sw=3 expandtab: */