aboutsummaryrefslogtreecommitdiffhomepage
path: root/optmem.c
blob: ba81cd247263a6917fce0888e90e586d86118b08 (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
94
95
96
97
98
99
#include "ir.h"

static const uchar loadszcls[] = {
   [Oloads1 - Oloads1] = 1|KI4<<4, [Oloadu1 - Oloads1] = 1|KI4<<4,
   [Oloads2 - Oloads1] = 2|KI4<<4, [Oloadu2 - Oloads1] = 2|KI4<<4,
   [Oloads4 - Oloads1] = 4|KI4<<4, [Oloadu4 - Oloads1] = 4|KI4<<4,
   [Oloadi8 - Oloads1] = 8|KI8<<4,
   [Oloadf4 - Oloads1] = 4|KF4<<4,
   [Oloadf8 - Oloads1] = 8|KF8<<4,
};
static const uchar load2ext[] = {
   [Oloads1 - Oloads1] = Oexts1, [Oloadu1 - Oloads1] = Oextu1,
   [Oloads2 - Oloads1] = Oexts2, [Oloadu2 - Oloads1] = Oextu2,
   [Oloads4 - Oloads1] = Oexts4, [Oloadu4 - Oloads1] = Oextu4,
   [Oloadi8 - Oloads1] = Ocopy,
};
#define loadsz(o) (loadszcls[(o) - Oloads1] & 0xF)
#define loadcls(o) (loadszcls[(o) - Oloads1] >> 4)
#define load2ext(o) (load2ext[(o) - Oloads1])
#define storesz(o) (1 << ((o) - Ostore1))

void
mem2reg(struct function *fn)
{
   extern int ninstr;
   struct uses *uses = ssauses(fn);
   struct block *blk = fn->entry;

   do {
      for (int i = 0; i < blk->ins.n; ++i) {
         struct use *use, *uend;
         union ref var;
         enum irclass k = 0;
         int sz = 0, ndef = 0;
         enum op ext;
         int t = blk->ins.p[i];
         struct instr *ins = &instrtab[t];
         
         if (!oisalloca(ins->op)) continue;
         for (use = uses[t].use, uend = &uses[t].use[uses[t].nuse]; use < uend; ++use) {
            struct instr *m;
            
            if (use->isjmp) goto Next;
            m = &instrtab[use->ins];
            if (oisload(m->op) && (!sz || sz == loadsz(m->op))) {
               sz = loadsz(m->op);
               k = loadcls(m->op);
               if (sz < 4) ext = load2ext(m->op);
               continue;
            }
            if (oisstore(m->op) && m->l.bits == mkref(RTMP, t).bits
            && (!sz || sz == storesz(m->op))) {
               sz = storesz(m->op);
               ++ndef;
               continue;
            }
            goto Next;
         }
         if (!ndef) /* slot is read from but never written to */
            goto Next;

         if (ndef>1) /* TODO phi construction */
            goto Next;

         /* remove alloca */
         *ins = mkinstr(Onop, 0,);
         
         var.t = 0;
         for (use = uses[t].use; use < uend; ++use) {
            struct instr *m = &instrtab[use->ins];

            if (oisstore(m->op)) {
               if (sz < 4) {
                  *m = mkinstr(ext, KI4, m->r);
                  var = mkref(RTMP, use->ins);
               } else {
                  var = m->r;
                  *m = mkinstr(Onop,0,);
               }
            } else if (oisload(m->op)) {
               if (!var.t) /* use before def */
                  goto Next;
               *m = mkinstr(Ocopy, k, var);
            }
         }
         
      Next:;
      }
   } while ((blk = blk->lnext) != fn->entry);

   freeuses(uses, ninstr);
   if (ccopt.dbg.m) {
      efmt("<< After mem2reg >>\n");
      irdump(fn);
   }
}


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