QBE
load.c
См. документацию.
1 #include "all.h"
2 
3 #define MASK(w) (BIT(8*(w)-1)*2-1) /* must work when w==8 */
4 
5 typedef struct Loc Loc;
6 typedef struct Slice Slice;
7 typedef struct Insert Insert;
8 
9 
10 struct Loc {
11  enum {
12  LRoot, /* right above the original load */
13  LLoad, /* inserting a load is allowed */
14  LNoLoad, /* only scalar operations allowed */
15  } type;
17  Blk *blk;
18 };
19 
20 struct Slice {
22  short sz;
23  short cls; /* load class */
24 };
25 
26 struct Insert {
28  uint num:31;
31  union {
33  struct {
35  Phi *p;
36  } phi;
37  } new;
38 };
39 
40 static Fn *curf;
41 static uint inum; /* current insertion number */
42 static Insert *ilog; /* global insertion log */
43 static uint nlog; /* number of entries in the log */
44 
45 int
47 {
48  switch (l->op) {
49  case Oloadsb: case Oloadub: return 1;
50  case Oloadsh: case Oloaduh: return 2;
51  case Oloadsw: case Oloaduw: return 4;
52  case Oload: return KWIDE(l->cls) ? 8 : 4;
53  }
54  die("unreachable");
55 }
56 
57 int
59 {
60  switch (s->op) {
61  case Ostoreb: return 1;
62  case Ostoreh: return 2;
63  case Ostorew: case Ostores: return 4;
64  case Ostorel: case Ostored: return 8;
65  }
66  die("unreachable");
67 }
68 
69 static Ref
70 iins(int cls, int op, Ref a0, Ref a1, Loc *l)
71 {
72  Insert *ist;
73 
74  vgrow(&ilog, ++nlog);
75  ist = &ilog[nlog-1];
76  ist->isphi = 0;
77  ist->num = inum++;
78  ist->bid = l->blk->id;
79  ist->off = l->off;
80  ist->new.ins = (Ins){op, R, {a0, a1}, cls};
81  return ist->new.ins.to = newtmp("ld", cls, curf);
82 }
83 
84 static void
85 cast(Ref *r, int cls, Loc *l)
86 {
87  int cls0;
88 
89  if (rtype(*r) == RCon)
90  return;
91  assert(rtype(*r) == RTmp);
92  cls0 = curf->tmp[r->val].cls;
93  if (cls0 == cls || (cls == Kw && cls0 == Kl))
94  return;
95  assert(!KWIDE(cls0) || KWIDE(cls));
96  if (KWIDE(cls) == KWIDE(cls0))
97  *r = iins(cls, Ocast, *r, R, l);
98  else {
99  assert(cls == Kl);
100  if (cls0 == Ks)
101  *r = iins(Kw, Ocast, *r, R, l);
102  *r = iins(Kl, Oextuw, *r, R, l);
103  }
104 }
105 
106 static inline void
107 mask(int cls, Ref *r, bits msk, Loc *l)
108 {
109  cast(r, cls, l);
110  *r = iins(cls, Oand, *r, getcon(msk, curf), l);
111 }
112 
113 static Ref
114 load(Slice sl, bits msk, Loc *l)
115 {
116  Alias *a;
117  Ref r, r1;
118  int ld, cls, all, c;
119 
120  ld = (int[]){
121  [1] = Oloadub,
122  [2] = Oloaduh,
123  [4] = Oloaduw,
124  [8] = Oload
125  }[sl.sz];
126  all = msk == MASK(sl.sz);
127  if (all)
128  cls = sl.cls;
129  else
130  cls = sl.sz > 4 ? Kl : Kw;
131  r = sl.ref;
132  /* sl.ref might not be live here,
133  * but its alias base ref will be
134  * (see killsl() below) */
135  if (rtype(r) == RTmp) {
136  a = &curf->tmp[r.val].alias;
137  switch (a->type) {
138  default:
139  die("unreachable");
140  case ALoc:
141  case AEsc:
142  case AUnk:
143  r = a->base;
144  if (!a->offset)
145  break;
146  r1 = getcon(a->offset, curf);
147  r = iins(Kl, Oadd, r, r1, l);
148  break;
149  case ACon:
150  case ASym:
151  c = curf->ncon++;
152  vgrow(&curf->con, curf->ncon);
153  curf->con[c].type = CAddr;
154  curf->con[c].label = a->label;
155  curf->con[c].bits.i = a->offset;
156  curf->con[c].local = 0;
157  r = CON(c);
158  break;
159  }
160  }
161  r = iins(cls, ld, r, R, l);
162  if (!all)
163  mask(cls, &r, msk, l);
164  return r;
165 }
166 
167 static int
168 killsl(Ref r, Slice sl)
169 {
170  Alias *a;
171 
172  if (rtype(sl.ref) != RTmp)
173  return 0;
174  a = &curf->tmp[sl.ref.val].alias;
175  switch (a->type) {
176  default: die("unreachable");
177  case ALoc:
178  case AEsc:
179  case AUnk: return req(a->base, r);
180  case ACon:
181  case ASym: return 0;
182  }
183 }
184 
185 /* returns a ref containing the contents of the slice
186  * passed as argument, all the bits set to 0 in the
187  * mask argument are zeroed in the result;
188  * the returned ref has an integer class when the
189  * mask does not cover all the bits of the slice,
190  * otherwise, it has class sl.cls
191  * the procedure returns R when it fails */
192 static Ref
193 def(Slice sl, bits msk, Blk *b, Ins *i, Loc *il)
194 {
195  Blk *bp;
196  bits msk1, msks;
197  int off, cls, cls1, op, sz, ld;
198  uint np, oldl, oldt;
199  Ref r, r1;
200  Phi *p;
201  Insert *ist;
202  Loc l;
203 
204  /* invariants:
205  * -1- b dominates il->blk; so we can use
206  * temporaries of b in il->blk
207  * -2- if il->type != LNoLoad, then il->blk
208  * postdominates the original load; so it
209  * is safe to load in il->blk
210  * -3- if il->type != LNoLoad, then b
211  * postdominates il->blk (and by 2, the
212  * original load)
213  */
214  assert(dom(b, il->blk));
215  oldl = nlog;
216  oldt = curf->ntmp;
217  if (0) {
218  Load:
219  curf->ntmp = oldt;
220  nlog = oldl;
221  if (il->type != LLoad)
222  return R;
223  return load(sl, msk, il);
224  }
225 
226  if (!i)
227  i = &b->ins[b->nins];
228  cls = sl.sz > 4 ? Kl : Kw;
229  msks = MASK(sl.sz);
230 
231  while (i > b->ins) {
232  --i;
233  if (killsl(i->to, sl)
234  || (i->op == Ocall && escapes(sl.ref, curf)))
235  goto Load;
236  ld = isload(i->op);
237  if (ld) {
238  sz = loadsz(i);
239  r1 = i->arg[0];
240  r = i->to;
241  } else if (isstore(i->op)) {
242  sz = storesz(i);
243  r1 = i->arg[1];
244  r = i->arg[0];
245  } else
246  continue;
247  switch (alias(sl.ref, sl.sz, r1, sz, &off, curf)) {
248  case MustAlias:
249  if (off < 0) {
250  off = -off;
251  msk1 = (MASK(sz) << 8*off) & msks;
252  op = Oshl;
253  } else {
254  msk1 = (MASK(sz) >> 8*off) & msks;
255  op = Oshr;
256  }
257  if ((msk1 & msk) == 0)
258  break;
259  if (off) {
260  cls1 = cls;
261  if (op == Oshr && off + sl.sz > 4)
262  cls1 = Kl;
263  cast(&r, cls1, il);
264  r1 = getcon(8*off, curf);
265  r = iins(cls1, op, r, r1, il);
266  }
267  if ((msk1 & msk) != msk1 || off + sz < sl.sz)
268  mask(cls, &r, msk1 & msk, il);
269  if ((msk & ~msk1) != 0) {
270  r1 = def(sl, msk & ~msk1, b, i, il);
271  if (req(r1, R))
272  goto Load;
273  r = iins(cls, Oor, r, r1, il);
274  }
275  if (msk == msks)
276  cast(&r, sl.cls, il);
277  return r;
278  case MayAlias:
279  if (ld)
280  break;
281  else
282  goto Load;
283  case NoAlias:
284  break;
285  default:
286  die("unreachable");
287  }
288  }
289 
290  for (ist=ilog; ist<&ilog[nlog]; ++ist)
291  if (ist->isphi && ist->bid == b->id)
292  if (req(ist->new.phi.m.ref, sl.ref))
293  if (ist->new.phi.m.sz == sl.sz) {
294  r = ist->new.phi.p->to;
295  if (msk != msks)
296  mask(cls, &r, msk, il);
297  else
298  cast(&r, sl.cls, il);
299  return r;
300  }
301 
302  for (p=b->phi; p; p=p->link)
303  if (killsl(p->to, sl))
304  /* scanning predecessors in that
305  * case would be unsafe */
306  goto Load;
307 
308  if (b->npred == 0)
309  goto Load;
310  if (b->npred == 1) {
311  bp = b->pred[0];
312  assert(bp->loop >= il->blk->loop);
313  l = *il;
314  if (bp->s2)
315  l.type = LNoLoad;
316  r1 = def(sl, msk, bp, 0, &l);
317  if (req(r1, R))
318  goto Load;
319  return r1;
320  }
321 
322  r = newtmp("ld", sl.cls, curf);
323  p = alloc(sizeof *p);
324  vgrow(&ilog, ++nlog);
325  ist = &ilog[nlog-1];
326  ist->isphi = 1;
327  ist->bid = b->id;
328  ist->new.phi.m = sl;
329  ist->new.phi.p = p;
330  p->to = r;
331  p->cls = sl.cls;
332  p->narg = b->npred;
333  for (np=0; np<b->npred; ++np) {
334  bp = b->pred[np];
335  if (!bp->s2
336  && il->type != LNoLoad
337  && bp->loop < il->blk->loop)
338  l.type = LLoad;
339  else
340  l.type = LNoLoad;
341  l.blk = bp;
342  l.off = bp->nins;
343  r1 = def(sl, msks, bp, 0, &l);
344  if (req(r1, R))
345  goto Load;
346  p->arg[np] = r1;
347  p->blk[np] = bp;
348  }
349  if (msk != msks)
350  mask(cls, &r, msk, il);
351  return r;
352 }
353 
354 static int
355 icmp(const void *pa, const void *pb)
356 {
357  Insert *a, *b;
358  int c;
359 
360  a = (Insert *)pa;
361  b = (Insert *)pb;
362  if ((c = a->bid - b->bid))
363  return c;
364  if (a->isphi && b->isphi)
365  return 0;
366  if (a->isphi)
367  return -1;
368  if (b->isphi)
369  return +1;
370  if ((c = a->off - b->off))
371  return c;
372  return a->num - b->num;
373 }
374 
375 /* require rpo ssa alias */
376 void
378 {
379  Ins *i, *ib;
380  Blk *b;
381  int sz;
382  uint n, ni, ext, nt;
383  Insert *ist;
384  Slice sl;
385  Loc l;
386 
387  curf = fn;
388  ilog = vnew(0, sizeof ilog[0], Pheap);
389  nlog = 0;
390  inum = 0;
391  for (b=fn->start; b; b=b->link)
392  for (i=b->ins; i<&b->ins[b->nins]; ++i) {
393  if (!isload(i->op))
394  continue;
395  sz = loadsz(i);
396  sl = (Slice){i->arg[0], sz, i->cls};
397  l = (Loc){LRoot, i-b->ins, b};
398  i->arg[1] = def(sl, MASK(sz), b, i, &l);
399  }
400  qsort(ilog, nlog, sizeof ilog[0], icmp);
401  vgrow(&ilog, nlog+1);
402  ilog[nlog].bid = fn->nblk; /* add a sentinel */
403  ib = vnew(0, sizeof(Ins), Pheap);
404  for (ist=ilog, n=0; n<fn->nblk; ++n) {
405  b = fn->rpo[n];
406  for (; ist->bid == n && ist->isphi; ++ist) {
407  ist->new.phi.p->link = b->phi;
408  b->phi = ist->new.phi.p;
409  }
410  ni = 0;
411  nt = 0;
412  for (;;) {
413  if (ist->bid == n && ist->off == ni)
414  i = &ist++->new.ins;
415  else {
416  if (ni == b->nins)
417  break;
418  i = &b->ins[ni++];
419  if (isload(i->op)
420  && !req(i->arg[1], R)) {
421  ext = Oextsb + i->op - Oloadsb;
422  switch (i->op) {
423  default:
424  die("unreachable");
425  case Oloadsb:
426  case Oloadub:
427  case Oloadsh:
428  case Oloaduh:
429  i->op = ext;
430  break;
431  case Oloadsw:
432  case Oloaduw:
433  if (i->cls == Kl) {
434  i->op = ext;
435  break;
436  }
437  case Oload:
438  i->op = Ocopy;
439  break;
440  }
441  i->arg[0] = i->arg[1];
442  i->arg[1] = R;
443  }
444  }
445  vgrow(&ib, ++nt);
446  ib[nt-1] = *i;
447  }
448  b->nins = nt;
449  idup(&b->ins, ib, nt);
450  }
451  vfree(ib);
452  vfree(ilog);
453  if (debug['M']) {
454  fprintf(stderr, "\n> After load elimination:\n");
455  printfn(fn, stderr);
456  }
457 }
Definition: all.h:215
Ref base
Definition: all.h:316
enum Alias::@8 type
unsigned int uint
Definition: all.h:12
int escapes(Ref r, Fn *fn)
Definition: alias.c:83
#define CON(x)
Definition: all.h:94
#define MASK(w)
Definition: load.c:3
struct Slice Slice
Definition: load.c:6
Blk * start
Указатель на блок функции, являющийся её входной точкой
Definition: all.h:385
short sz
Definition: load.c:22
int ncon
Размер массива con.
Definition: all.h:390
Blk ** pred
Definition: all.h:274
uint narg
Definition: all.h:246
Definition: all.h:303
Структура, хранящая информацию об инструкциях.
Definition: all.h:235
uint off
Definition: load.c:16
Definition: all.h:251
Definition: all.h:275
#define KWIDE(k)
Definition: all.h:219
Definition: all.h:256
Definition: all.h:242
#define isstore(o)
Definition: all.h:204
Definition: all.h:245
Definition: all.h:84
void * vnew(ulong, size_t, Pool)
Definition: util.c:111
Definition: all.h:191
Definition: all.h:238
Phi * link
Definition: all.h:248
void vfree(void *)
Definition: util.c:129
Definition: all.h:214
uint off
Definition: load.c:30
Definition: load.c:26
Con * con
Массив используемых функцией констант
Definition: all.h:387
Definition: load.c:20
uint num
Definition: load.c:28
Ref arg[NPred]
Definition: all.h:244
Definition: all.h:213
Структура, хранящая описание переменных (более подробное описание переменной ищите в Tmp)...
Definition: all.h:77
Tmp * tmp
Массив используемых функцией переменных
Definition: all.h:386
uint32_t label
Definition: all.h:317
Definition: all.h:303
struct Ins Ins
Definition: all.h:19
Alias alias
Definition: all.h:340
Ref to
Definition: all.h:243
int ntmp
Размер массива tmp.
Definition: all.h:389
Blk * s2
Definition: all.h:263
Непосредственно информация о базовом блоке.
Definition: all.h:254
void * alloc(size_t)
Definition: util.c:77
Definition: all.h:246
Ins ins
Definition: load.c:32
uint bid
Definition: load.c:29
Phi * p
Definition: load.c:35
Definition: all.h:186
void idup(Ins **, Ins *, ulong)
Definition: util.c:246
void printfn(Fn *, FILE *)
Definition: parse.c:1160
Ref getcon(int64_t, Fn *)
Definition: util.c:351
Blk * link
Definition: all.h:264
enum Con::@11 type
uint nins
Definition: all.h:257
Definition: all.h:237
short cls
Definition: all.h:333
int64_t offset
Definition: all.h:318
int loop
Definition: all.h:278
Ref to
Definition: all.h:237
void vgrow(void *, ulong)
Definition: util.c:142
Definition: all.h:235
enum Loc::@19 type
Definition: all.h:247
char local
Definition: all.h:366
short cls
Definition: load.c:23
uint nblk
Количество блоков в функции
Definition: all.h:392
struct Loc Loc
Definition: load.c:5
int64_t i
Definition: all.h:361
uint npred
Definition: all.h:275
#define isload(o)
Definition: all.h:205
Ins * ins
Definition: all.h:256
Phi * phi
Definition: all.h:255
Blk ** rpo
Ссылка на массив блоков, пронумерованных в порядке Reverse-Post Order, заполняется функцией fillrpo...
Definition: all.h:395
void loadopt(Fn *fn)
Definition: load.c:377
Definition: all.h:264
Definition: all.h:459
union Insert::@20 new
Ref arg[2]
Definition: all.h:238
Definition: all.h:248
#define die(...)
Definition: all.h:9
Definition: all.h:240
uint val
Definition: all.h:80
Definition: all.h:179
int loadsz(Ins *l)
Definition: load.c:46
Definition: all.h:301
Definition: all.h:306
Definition: all.h:85
uint id
Definition: all.h:266
int alias(Ref p, int sp, Ref q, int sq, int *delta, Fn *fn)
Definition: alias.c:31
Definition: all.h:239
Definition: all.h:244
Slice m
Definition: load.c:34
struct Insert::@20::@21 phi
int storesz(Ins *s)
Definition: load.c:58
Definition: all.h:190
int cls
Definition: all.h:247
Ref newtmp(char *, int, Fn *)
Definition: util.c:326
Definition: all.h:187
Definition: all.h:302
#define R
Definition: all.h:92
Definition: load.c:10
Blk * blk
Definition: load.c:17
uint isphi
Definition: load.c:27
union Con::@12 bits
uint cls
Definition: all.h:239
Definition: all.h:243
Definition: all.h:236
int cls
Definition: rega.c:23
Ref ref
Definition: load.c:21
Blk * blk[NPred]
Definition: all.h:245
int dom(Blk *, Blk *)
Definition: cfg.c:198
uint32_t label
Definition: all.h:359
Структура, хранящая в себе информацию о функции
Definition: all.h:384
uint op
Definition: all.h:236
char debug['Z'+1]
unsigned long long bits
Definition: all.h:14
Definition: all.h:242