OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [cuc/] [insn.c] - Blame information for rev 903

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 879 markom
/* insn.c -- OpenRISC Custom Unit Compiler, instruction support
2
 *    Copyright (C) 2002 Marko Mlinar, markom@opencores.org
3
 *
4
 *    This file is part of OpenRISC 1000 Architectural Simulator.
5
 *
6
 *    This program is free software; you can redistribute it and/or modify
7
 *    it under the terms of the GNU General Public License as published by
8
 *    the Free Software Foundation; either version 2 of the License, or
9
 *    (at your option) any later version.
10
 *
11
 *    This program is distributed in the hope that it will be useful,
12
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *    GNU General Public License for more details.
15
 *
16
 *    You should have received a copy of the GNU General Public License
17
 *    along with this program; if not, write to the Free Software
18
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <stdarg.h>
23
#include <assert.h>
24 897 markom
#include "sim-config.h"
25 879 markom
#include "cuc.h"
26
#include "insn.h"
27
 
28
/* Table of known instructions.  Watch out for indexes I_*! */
29
const cuc_known_insn known[II_LAST + 1] = {
30
{"add", 1, "assign \1 = \2 + \3;"},
31
{"sub", 0, "assign \1 = \2 - \3;"},
32
{"and", 1, "assign \1 = \2 & \3;"},
33
{"or",  1, "assign \1 = \2 | \3;"},
34
{"xor", 1, "assign \1 = \2 ^ \3;"},
35
{"mul", 1, "assign \1 = \2 * \3;"},
36
 
37
{"srl", 0, "assign \1 = \2 >> \3;"},
38
{"sll", 0, "assign \1 = \2 << \3;"},
39
{"sra", 0, "assign \1 = ({32{\2[31]}} << (6'd32-{1'b0, \3}))\n\
40
                 | \2 >> \3;"},
41
 
42
{"lb",  0, "always @(posedge clk or posedge rst)"},
43
{"lh",  0, "always @(posedge clk or posedge rst)"},
44
{"lw",  0, "always @(posedge clk or posedge rst)"},
45
{"sb",  0, "/* mem8[\2] = \1 */"},
46
{"sh",  0, "/* mem16[\2] = \1 */"},
47
{"sw",  0, "/* mem32[\2] = \1 */"},
48
 
49
{"sfeq", 1, "assign \1 = \2 == \3;"},
50
{"sfne", 1, "assign \1 = \2 != \3;"},
51
{"sfle", 0, "assign \1 = \2 <= \3;"},
52
{"sflt", 0, "assign \1 = \2 < \3;"},
53
{"sfgt", 0, "assign \1 = \2 > \3;"},
54
{"sfge", 0, "assign \1 = \2 >= \3;"},
55
{"sfor", 1, "assign \1 = \2 || \3;"},
56
{"bf",  0, ""},
57
 
58
{"lrbb", 0,"always @(posedge clk or posedge rst)"},
59
{"cmov", 0,"assign \1 = \4 ? \2 : \3;"},
60
{"reg", 0, "always @(posedge clk or posedge rst)"},
61
 
62
{"nop", 0, NULL}};
63
 
64
/* Find known instruction and attach them to insn */
65
void change_insn_type (cuc_insn *i, int index)
66
{
67
  int j;
68
  assert (index >= 0 && index <= II_LAST);
69
  i->index = index;
70
  if (i->index == II_NOP) {
71
    for (j = 0; j < MAX_OPERANDS; j++) i->opt[j] = OPT_NONE;
72
    i->type = 0;
73
    i->dep = NULL;
74
  }
75
}
76
 
77
/* Returns instruction name */
78
const char *cuc_insn_name (cuc_insn *ii) {
79
  if (ii->index < 0 || ii->index > II_LAST) return "???";
80
  else return known[ii->index].name;
81
}
82 883 markom
 
83 897 markom
/* Prints out instructions */
84
void print_insns (cuc_insn *insn, int ninsn, int verbose)
85
{
86
  int i, j;
87
  for (i = 0; i < ninsn; i++) {
88
    dep_list *l = insn[i].dep;
89
    printf ("%4x%c %-4s ", i, insn[i].index >= 0 ? ':' : '?', cuc_insn_name (&insn[i]));
90
    if (verbose) {
91
      printf ("%-20s insn = %08x, index = %i, type = %04x ",
92
                      insn[i].disasm, insn[i].insn, insn[i].index, insn[i].type);
93
    } else printf ("type = %04x ", insn[i].type);
94
    for (j = 0; j < MAX_OPERANDS; j++) {
95
      if (insn[i].opt[j] & OPT_DEST) printf ("*");
96
      switch (insn[i].opt[j] & ~OPT_DEST) {
97
        case OPT_NONE: break;
98
        case OPT_CONST: printf ("0x%08x, ", insn[i].op[j]); break;
99
        case OPT_JUMP: printf ("J%x ", insn[i].op[j]); break;
100
        case OPT_REGISTER: printf ("r%i, ", insn[i].op[j]); break;
101
        case OPT_REF: printf ("[%x.%x], ", REF_BB(insn[i].op[j]), REF_I(insn[i].op[j])); break;
102
        case OPT_BB: printf ("BB%x, ", insn[i].op[j]); break;
103
        case OPT_LRBB: printf ("LRBB, "); break;
104
        default:
105
          fprintf (stderr, "Invalid operand type %s(%x.%x) = %x\n",
106
                         cuc_insn_name (&insn[i]), i, j, insn[i].opt[j]);
107
          assert (0);
108
      }
109
    }
110
    if (l) {
111
      printf ("\n\tdep:");
112
      while (l) {
113
        printf (" [%x.%x],", REF_BB (l->ref), REF_I (l->ref));
114
        l = l->next;
115
      }
116
    }
117
    printf ("\n");
118
  }
119
}
120
 
121
void add_dep (dep_list **list, int dep)
122
{
123
  dep_list *ndep;
124
  dep_list **tmp = list;
125
 
126
  while (*tmp) {
127
    if ((*tmp)->ref == dep) return; /* already there */
128
    tmp = &((*tmp)->next);
129
  }
130
  ndep = (dep_list *)malloc (sizeof (dep_list));
131
  ndep->ref = dep;
132
  ndep->next = NULL;
133
  *tmp = ndep;
134
}
135
 
136
void dispose_list (dep_list **list)
137
{
138
  while (*list) {
139
    dep_list *tmp = *list;
140
    *list = tmp->next;
141
    free (tmp);
142
  }
143
}
144
 
145
void add_data_dep (cuc_func *f)
146
{
147
  int b, i, j;
148
  dep_list *tmp;
149
  for (b = 0; b < f->num_bb; b++) {
150
    cuc_insn *insn = f->bb[b].insn;
151
    for (i = 0; i < f->bb[b].ninsn; i++)
152
      for (j = 0; j < MAX_OPERANDS; j++) {
153
        fflush (stdout);
154
        if (insn[i].opt[j] & OPT_REF) {
155
          /* Copy list from predecessor */
156
          dep_list *l = f->INSN(insn[i].op[j]).dep;
157
          while (l) {
158
            add_dep (&insn[i].dep, l->ref);
159
            l = l->next;
160
          }
161
          /* add predecessor */
162
          add_dep (&insn[i].dep, insn[i].op[j]);
163
        }
164
      }
165
  }
166
}
167
 
168
/* returns nonzero, if instruction was simplified */
169
int apply_edge_condition (cuc_insn *ii)
170
{
171
  unsigned int c = ii->op[2];
172
 
173
  if (ii->index == II_AND) {
174
    if (ii->opt[2] & OPT_CONST && c == 0) {
175
      change_insn_type (ii, II_ADD);
176
      ii->op[1] = 0; ii->opt[1] = OPT_CONST;
177
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
178
      return 1;
179
    }
180
  } else if (ii->index == II_OR) {
181
    if (ii->opt[2] & OPT_CONST && c == 0xffffffff) {
182
      change_insn_type (ii, II_ADD);
183
      ii->op[1] = c; ii->opt[1] = OPT_CONST;
184
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
185
      return 1;
186
    }
187
  } else if (ii->index == II_SUB) {
188
    if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) {
189
      change_insn_type (ii, II_ADD);
190
      ii->op[1] = 0; ii->opt[1] = OPT_CONST;
191
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
192
      return 1;
193
    }
194
  } else if (ii->index == II_MUL) {
195
    if (ii->opt[2] & OPT_CONST && c == 0) {
196
      change_insn_type (ii, II_ADD);
197
      ii->op[1] = 0; ii->opt[1] = OPT_CONST;
198
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
199
      return 1;
200
    } else
201
    if (ii->opt[2] & OPT_CONST && c == 1) {
202
      change_insn_type (ii, II_ADD);
203
      ii->op[1] = c; ii->opt[1] = OPT_CONST;
204
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
205
      return 1;
206
    } else
207
    if (ii->opt[2] & OPT_CONST && c == 0xffffffff) {
208
      change_insn_type (ii, II_SUB);
209
      ii->op[2] = ii->op[1]; ii->opt[2] = ii->opt[1];
210
      ii->op[1] = 0; ii->opt[1] = OPT_CONST;
211
      return 1;
212
    }
213
  } else if (ii->index == II_SRL) {
214
    if (ii->opt[2] & OPT_CONST && c == 0) {
215
      change_insn_type (ii, II_ADD);
216
      ii->op[1] = c; ii->opt[1] = OPT_CONST;
217
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
218
      return 1;
219
    } else if (ii->opt[2] & OPT_CONST && c >= 32) {
220
      change_insn_type (ii, II_ADD);
221
      ii->op[1] = 0; ii->opt[1] = OPT_CONST;
222
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
223
      return 1;
224
    }
225
  } else if (ii->index == II_SLL) {
226
    if (ii->opt[2] & OPT_CONST && c == 0) {
227
      change_insn_type (ii, II_ADD);
228
      ii->op[1] = c; ii->opt[1] = OPT_CONST;
229
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
230
      return 1;
231
    } else if (ii->opt[2] & OPT_CONST && c >= 32) {
232
      change_insn_type (ii, II_ADD);
233
      ii->op[1] = 0; ii->opt[1] = OPT_CONST;
234
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
235
      return 1;
236
    }
237
  } else if (ii->index == II_SRA) {
238
    if (ii->opt[2] & OPT_CONST && c == 0) {
239
      change_insn_type (ii, II_ADD);
240
      ii->op[1] = c; ii->opt[1] = OPT_CONST;
241
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
242
      return 1;
243
    }
244
  } else if (ii->index == II_CMOV) {
245
    if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) {
246
      change_insn_type (ii, II_ADD);
247
      ii->op[2] = 0; ii->opt[2] = OPT_CONST;
248
      ii->opt[3] = OPT_NONE;
249
      return 1;
250
    }
251
  }
252
  return 0;
253
}
254
 
255 902 markom
/* First primary input */
256
static unsigned long tmp_op, tmp_opt;
257
 
258
/* Recursive function that searches for primary inputs;
259
   returns 0 if cmov can be replaced by add */
260
static int cmov_needed (cuc_func *f, int ref)
261
{
262
  cuc_insn *ii = &f->INSN(ref);
263
  int j;
264
 
265 903 markom
  cucdebug (4, " %x", ref);
266 902 markom
  /* mark visited, if already marked, we have a loop, ignore */
267
  if (ii->tmp) return 0;
268
  ii->tmp = 1;
269
 
270
  /* handle normal movs separately */
271
  if ((ii->index == II_ADD || !(ii->type & IT_VOLATILE))
272
    && ii->opt[2] == OPT_CONST && ii->op[2] == 0) {
273
    if (ii->opt[1] == OPT_REF) {
274
      if (cmov_needed (f, ii->op[1])) {
275
        ii->tmp = 0;
276
        return 1;
277
      }
278
    } else {
279
      if (tmp_opt == OPT_NONE) {
280
        tmp_op = ii->op[1];
281
        tmp_opt = ii->opt[1];
282
      } else if (tmp_opt != ii->opt[1] || tmp_op != ii->op[1]) {
283
        ii->tmp = 0;
284
        return 1;
285
      }
286
    }
287
    ii->tmp = 0;
288
    return 0;
289
  }
290
 
291
  /* Is this instruction CMOV? no => add to primary inputs */
292
  if (ii->index != II_CMOV || ii->type & IT_VOLATILE)
293
    if (tmp_opt == OPT_NONE) {
294
      tmp_op = ref;
295
      tmp_opt = OPT_REF;
296
      ii->tmp = 0;
297
      return 0;
298
    } else if (tmp_opt != OPT_REF || tmp_op != ref) {
299
      ii->tmp = 0;
300
      return 1;
301
    }
302
 
303
  for (j = 1; j < 3; j++) {
304 903 markom
    cucdebug (4, "(%x:%i)", ref, j);
305 902 markom
    if (ii->opt[j] == OPT_REF) {
306
      if (cmov_needed (f, ii->op[j])) {
307
        ii->tmp = 0;
308
        return 1;
309
      }
310
    } else {
311
      if (tmp_opt == OPT_NONE) {
312
        tmp_op = ii->op[j];
313
        tmp_opt = ii->opt[j];
314
      } else if (tmp_opt != ii->opt[j] || tmp_op != ii->op[j]) {
315
        ii->tmp = 0;
316
        return 1;
317
      }
318
    }
319
  }
320
 
321
  ii->tmp = 0;
322
  return 0;
323
}
324
 
325
/* Search and optimize complex cmov assignments */
326
void optimize_cmovs (cuc_func *f)
327
{
328
  int b, i, j;
329
 
330
  /* Mark all instructions unvisited */
331
  for (b = 0; b < f->num_bb; b++) if (!(f->bb[b].type & BB_DEAD))
332
    for (i = 0; i < f->bb[b].ninsn; i++) f->bb[b].insn[i].tmp = 0;
333
 
334
  for (b = 0; b < f->num_bb; b++) if (!(f->bb[b].type & BB_DEAD)) {
335
    for (i = 0; i < f->bb[b].ninsn; i++) {
336
      cuc_insn *ii = &f->bb[b].insn[i];
337
      if (ii->index == II_CMOV && !(ii->type & IT_VOLATILE)) {
338
        tmp_opt = OPT_NONE;
339 903 markom
        cucdebug (4, "\n");
340 902 markom
        if (!cmov_needed (f, REF(b, i))) {
341
          assert (tmp_opt != OPT_NONE);
342
          change_insn_type (ii, II_ADD);
343
          ii->op[1] = tmp_op; ii->opt[1] = tmp_opt;
344
          ii->op[2] = 0; ii->opt[2] = OPT_CONST;
345
          ii->opt[3] = OPT_NONE;
346
        }
347
      }
348
    }
349
  }
350
}
351
 
352 897 markom
/* Optimizes dataflow tree */
353
void optimize_tree (cuc_func *f)
354
{
355
  int b, i, j;
356
  int modified;
357
 
358
  do {
359
    modified = 0;
360
    for (b = 0; b < f->num_bb; b++) if (!(f->bb[b].type & BB_DEAD)) {
361
      for (i = 0; i < f->bb[b].ninsn; i++) {
362
        cuc_insn *ii = &f->bb[b].insn[i];
363
        /* We tend to have the third parameter const if instruction is cumutative */
364
        if ((ii->opt[1] & OPT_CONST) && !(ii->opt[2] & OPT_CONST)
365
            && known[ii->index].comutative) {
366
          unsigned long t = ii->opt[1];
367
          ii->opt[1] = ii->opt[2];
368
          ii->opt[2] = t;
369
          t = ii->op[1];
370
          ii->op[1] = ii->op[2];
371
          ii->op[2] = t;
372
          modified = 1; cucdebug (2, "%08x:<>\n", REF(b, i));
373
        }
374
 
375
        /* Try to do the promotion */
376
        /* We have two consecutive expressions, containing constants,
377
         * if previous is a simple expression we can handle it simply: */
378
        for (j = 0; j < MAX_OPERANDS; j++)
379
          if (ii->opt[j] & OPT_REF) {
380
            cuc_insn *t = &f->INSN(ii->op[j]);
381
            if (f->INSN(ii->op[j]).index == II_ADD
382
             && f->INSN(ii->op[j]).opt[2] & OPT_CONST
383
             && f->INSN(ii->op[j]).op[2] == 0
384
             && !(ii->type & IT_MEMORY && t->type & IT_MEMADD)
385
             && !(ii->type & IT_BRANCH) && !(t->type & IT_COND)) {
386
            /* do not promote through add-mem, and branches */
387
              modified = 1; cucdebug (2, "%8x:promote%i %8x %8x\n", REF (b, i), j, ii->op[j], t->op[1]);
388
              ii->op[j] = t->op[1]; ii->opt[j] = t->opt[1];
389
            }
390
          }
391
 
392
        /* In case of x = cmov x, y; or x = cmov y, x; we have
393
           asynchroneous loop -> remove it */
394
        if (ii->index == II_CMOV) {
395
          int f = 0;
396
          if ((ii->opt[1] & OPT_REF) && ii->op[1] == REF (b, i)) f = 1;
397
          if ((ii->opt[2] & OPT_REF) && ii->op[2] == REF (b, i)) f = 2;
398
          if (ii->opt[1] == ii->opt[2] && ii->op[1] == ii->op[2]) f = 2;
399
          if (f) {
400
            change_insn_type (ii, II_ADD);
401
            cucdebug (2, "%8x:cmov     %i\n", REF(b, i), f);
402
            ii->opt[f] = OPT_CONST;
403
            ii->op[f] = 0;
404
            ii->opt[3] = OPT_NONE;
405
            modified = 1;
406
            continue;
407
          }
408
        }
409
 
410
        /* Do nothing to volatile instructions */
411
        if (ii->type & IT_VOLATILE) continue;
412
 
413
        /* Check whether we can simplify the instruction */
414
        if (apply_edge_condition (ii)) {
415
          modified = 1;
416
          continue;
417
        }
418
        /* We cannot do anything more if at least one is not constant */
419
        if (!(ii->opt[2] & OPT_CONST)) continue;
420
 
421
        if (ii->opt[1] & OPT_CONST) { /* We have constant expression */
422
          unsigned long value;
423
          int ok = 1;
424
          /* Was constant expression already? */
425
          if (ii->index == II_ADD && !ii->op[2]) continue;
426
 
427
          if (ii->index == II_ADD) value = ii->op[1] + ii->op[2];
428
          else if (ii->index == II_SUB) value = ii->op[1] - ii->op[2];
429
          else if (ii->index == II_SLL) value = ii->op[1] << ii->op[2];
430
          else if (ii->index == II_SRL) value = ii->op[1] >> ii->op[2];
431
          else if (ii->index == II_MUL) value = ii->op[1] * ii->op[2];
432
          else if (ii->index == II_OR) value = ii->op[1] | ii->op[2];
433
          else if (ii->index == II_XOR) value = ii->op[1] ^ ii->op[2];
434
          else if (ii->index == II_AND) value = ii->op[1] & ii->op[2];
435
          else ok = 0;
436
          if (ok) {
437
            change_insn_type (ii, II_ADD);
438
            ii->op[0] = -1; ii->opt[0] = OPT_REGISTER | OPT_DEST;
439
            ii->op[1] = value; ii->opt[1] = OPT_CONST;
440
            ii->op[2] = 0; ii->opt[2] = OPT_CONST;
441
            modified = 1; cucdebug (2, "%8x:const\n", REF (b, i));
442
          }
443
        } else if (ii->opt[1] & OPT_REF) {
444
          cuc_insn *prev = &f->INSN(ii->op[1]);
445
          /* Is this just a link? */
446
          if (ii->index == II_ADD
447
           && !(ii->type & IT_MEMADD) && ii->op[2] == 0) {
448
            int b1, i1, j1;
449
            cucdebug (2, "%8x:link      %8x: ", REF(b, i), ii->op[1]);
450
            for (b1 = 0; b1 < f->num_bb; b1++) if (!(f->bb[b1].type & BB_DEAD))
451
              for (i1 = 0; i1 < f->bb[b1].ninsn; i1++)
452
                for (j1 = 0; j1 < MAX_OPERANDS; j1++)
453
                  if ((f->bb[b1].insn[i1].opt[j1] & OPT_REF)
454
                   && f->bb[b1].insn[i1].op[j1] == REF(b, i)) {
455
                    cucdebug (2, "%x ", REF (b1, i1));
456
                    f->bb[b1].insn[i1].op[j1] = ii->op[1];
457
                  }
458
            cucdebug (2, "\n");
459
            change_insn_type (ii, II_NOP);
460
          } else if (prev->opt[2] & OPT_CONST) {
461
            /* Handle some common cases */
462
            /* add - add joining */
463
            if (ii->index == II_ADD && prev->index == II_ADD) {
464
              ii->op[1] = prev->op[1]; ii->opt[1] = prev->opt[1];
465
              ii->op[2] += prev->op[2];
466
              modified = 1; cucdebug (2, "%8x: add-add\n", REF(b, i));
467
            } else /* add - sub joining */
468
            if (ii->index == II_ADD && prev->index == II_SUB) {
469
              change_insn_type (&insn[i], II_SUB);
470
              ii->op[1] = prev->op[1]; ii->opt[1] = prev->opt[1];
471
              ii->op[2] += prev->op[2];
472
              modified = 1; cucdebug (2, "%8x: add-sub\n", REF(b, i));
473
            } else /* sub - add joining */
474
            if (ii->index == II_SUB && prev->index == II_ADD) {
475
              ii->op[1] = prev->op[1]; ii->opt[1] = prev->opt[1];
476
              ii->op[2] += prev->op[2];
477
              modified = 1; cucdebug (2, "%8x: sub-add\n", REF(b, i));
478
            }
479
          }
480
        }
481
      }
482
    }
483
  } while (modified);
484
}
485
 
486
/* Remove nop instructions */
487
void remove_nops (cuc_func *f)
488
{
489
  int b;
490
  for (b = 0; b < f->num_bb; b++) {
491
    int c, d = 0, i, j;
492
    cuc_insn *insn = f->bb[b].insn;
493
    for (i = 0; i < f->bb[b].ninsn; i++)
494
      if (insn[i].index != II_NOP) {
495
        reloc [i] = d;
496
        insn[d++] = insn[i];
497
      } else {
498
        reloc[i] = d; /* For jumps only */
499
      }
500
    f->bb[b].ninsn = d;
501
 
502
    /* Relocate references from all basic blocks */
503
    for (c = 0; c < f->num_bb; c++)
504
      for (i = 0; i < f->bb[c].ninsn; i++) {
505
        dep_list *d = f->bb[c].insn[i].dep;
506
        for (j = 0; j < MAX_OPERANDS; j++)
507
          if ((f->bb[c].insn[i].opt[j] & OPT_REF)
508
            && REF_BB(f->bb[c].insn[i].op[j]) == b)
509
            f->bb[c].insn[i].op[j] = REF (b, reloc[REF_I (f->bb[c].insn[i].op[j])]);
510
 
511
        while (d) {
512
          if (REF_BB(d->ref) == b) d->ref = REF (b, reloc[REF_I (d->ref)]);
513
          d = d->next;
514
        }
515
      }
516
  }
517
}
518
 
519
/* Remove unused assignments */
520
void remove_dead (cuc_func *f)
521
{
522
  int b, i, j;
523
  for (b = 0; b < f->num_bb; b++)
524
    for (i = 0; i < f->bb[b].ninsn; i++)
525
      if (!(f->bb[b].insn[i].type & (IT_VOLATILE | IT_OUTPUT)))
526
        f->bb[b].insn[i].type |= IT_UNUSED;
527
 
528
  for (b = 0; b < f->num_bb; b++) {
529
    for (i = 0; i < f->bb[b].ninsn; i++)
530
      for (j = 0; j < MAX_OPERANDS; j++)
531
        if (f->bb[b].insn[i].opt[j] & OPT_REF) {
532
          f->INSN(f->bb[b].insn[i].op[j]).type &= ~IT_UNUSED;
533
        }
534
  }
535
 
536
  for (b = 0; b < f->num_bb; b++)
537
    for (i = 0; i < f->bb[b].ninsn; i++)
538
      if (f->bb[b].insn[i].type & IT_UNUSED) {
539
        change_insn_type (&f->bb[b].insn[i], II_NOP);
540
      }
541
 
542
  remove_nops (f);
543
}
544
 
545
/* Removes trivial register assignments */
546
void remove_trivial_regs (cuc_func *f)
547
{
548
  int b, i;
549
  for (i = 0; i < MAX_REGS; i++) f->saved_regs[i] = call_saved[i];
550
 
551
  for (b = 0; b < f->num_bb; b++) {
552
    cuc_insn *insn = f->bb[b].insn;
553
    for (i = 0; i < f->bb[b].ninsn; i++) {
554
      if (insn[i].index == II_ADD
555
        && insn[i].opt[0] & OPT_REGISTER
556
        && insn[i].opt[1] & OPT_REGISTER && insn[i].op[0] == insn[i].op[1]
557
        && insn[i].opt[2] & OPT_CONST && insn[i].op[2] == 0) {
558
          if (insn[i].type & IT_OUTPUT) f->saved_regs[insn[i].op[0]] = 1;
559
          change_insn_type (&insn[i], II_NOP);
560
        }
561
    }
562
  }
563
  if (cuc_debug >= 2) {
564
    printf ("saved regs ");
565
    for (i = 0; i < MAX_REGS; i++) printf ("%i:%i ", i, f->saved_regs[i]);
566
    printf ("\n");
567
  }
568
  remove_nops (f);
569
}
570
 
571
/* Determine inputs and outputs */
572
void set_io (cuc_func *f)
573
{
574
  int b, i, j;
575
  /* Determine register usage */
576
  for (i = 0; i < MAX_REGS; i++) {
577
    f->lur[i] = -1;
578
    f->used_regs[i] = 0;
579
  }
580 902 markom
  if (cuc_debug > 5) print_cuc_bb (f, "SET_IO");
581 897 markom
  for (b = 0; b < f->num_bb; b++) {
582
    for (i = 0; i < f->bb[b].ninsn; i++)
583
      for (j = 0; j < MAX_OPERANDS; j++)
584
        if (f->bb[b].insn[i].opt[j] & OPT_REGISTER && f->bb[b].insn[i].op[j] >= 0)
585
          if (f->bb[b].insn[i].opt[j] & OPT_DEST) f->lur[f->bb[b].insn[i].op[j]] = REF (b, i);
586
          else f->used_regs[f->bb[b].insn[i].op[j]] = 1;
587
  }
588
}
589
 
590
/* relocate all accesses inside of BB b to back/fwd */
591
static void relocate_bb (cuc_bb *bb, int b, int back, int fwd)
592
{
593
  int i, j;
594
  for (i = 0; i < bb->ninsn; i++)
595
    for (j = 0; j < MAX_OPERANDS; j++)
596
      if (bb->insn[i].opt[j] & OPT_REF
597
       && REF_BB (bb->insn[i].op[j]) == b) {
598
        int t = REF_I (bb->insn[i].op[j]);
599
        if (t < i) bb->insn[i].op[j] = REF (back, t);
600
        else bb->insn[i].op[j] = REF (fwd, t);
601
      }
602
}
603
 
604
/* Latch outputs in loops */
605
void add_latches (cuc_func *f)
606
{
607
  int b, i, j;
608
 
609
  //print_cuc_bb (f, "ADD_LATCHES a");
610
  /* Cuts the tree and marks registers */
611
  mark_cut (f);
612
 
613
  /* Split BBs with more than one group */
614
  for (b = 0; b < f->num_bb; b++) expand_bb (f, b);
615
  remove_nops (f);
616
  //print_cuc_bb (f, "ADD_LATCHES 0");
617
 
618
  /* Convert accesses in BB_INLOOP type block to latched */
619
  for (b = 0; b < f->num_bb; b++) {
620
    int j;
621
    for (i = 0; i < f->bb[b].ninsn; i++)
622
      for (j = 0; j < MAX_OPERANDS; j++) if (f->bb[b].insn[i].opt[j] == OPT_REF) {
623
        int t = f->bb[b].insn[i].op[j];
624
        /* If we are pointing to a INLOOP block from outside, or forward
625
           (= previous loop iteration) we must register that data */
626
        if ((f->bb[REF_BB(t)].type & BB_INLOOP || config.cuc.no_multicycle)
627
         && !(f->INSN(t).type & (IT_BRANCH | IT_COND))
628
         && (REF_BB(t) != b || REF_I(t) >= i)) {
629
          f->INSN(t).type |= IT_LATCHED;
630
        }
631
      }
632
  }
633
  //print_cuc_bb (f, "ADD_LATCHES 1");
634
 
635
  /* Add latches at the end of blocks as needed */
636
  for (b = 0; b < f->num_bb; b++) {
637
    int nreg = 0;
638
    cuc_insn *insn;
639
    for (i = 0; i < f->bb[b].ninsn; i++)
640
      if (f->bb[b].insn[i].type & IT_LATCHED) nreg++;
641
    if (nreg) {
642
      insn = (cuc_insn *) malloc (sizeof (cuc_insn) * (f->bb[b].ninsn + nreg));
643
      j = 0;
644
      for (i = 0; i < f->bb[b].ninsn; i++) {
645
        insn[i] = f->bb[b].insn[i];
646
        if (insn[i].type & IT_LATCHED) {
647
          cuc_insn *ii = &insn[f->bb[b].ninsn + j++];
648
          change_insn_type (ii, II_REG);
649
          ii->op[0] = -1; ii->opt[0] = OPT_DEST | OPT_REGISTER;
650
          ii->op[1] = REF (b, i); ii->opt[1] = OPT_REF;
651
          ii->opt[2] = ii->opt[3] = OPT_NONE;
652
          ii->dep = NULL;
653
          ii->type = IT_VOLATILE;
654
          sprintf (ii->disasm, "reg %i_%i", b, i);
655
        }
656
      }
657
      f->bb[b].ninsn += nreg;
658
      free (f->bb[b].insn);
659
      f->bb[b].insn = insn;
660
    }
661
  }
662
  //print_cuc_bb (f, "ADD_LATCHES 2");
663
 
664
  /* Repair references */
665
  for (b = 0; b < f->num_bb; b++)
666
    for (i = 0; i < f->bb[b].ninsn; i++)
667
      for (j = 0; j < MAX_OPERANDS; j++)
668
        /* If destination instruction is latched, use register instead */
669
        if (f->bb[b].insn[i].opt[j] == OPT_REF
670
         && f->INSN(f->bb[b].insn[i].op[j]).type & IT_LATCHED) {
671
          int b1, i1;
672
          b1 = REF_BB (f->bb[b].insn[i].op[j]);
673
          //cucdebug (2, "%i.%i.%i %x\n", b, i, j, f->bb[b].insn[i].op[j]);
674
          if (b1 != b || REF_I(f->bb[b].insn[i].op[j]) >= i) {
675
            for (i1 = f->bb[b1].ninsn - 1; i1 >= 0; i1--) {
676
              assert (f->bb[b1].insn[i1].index == II_REG);
677
              if (f->bb[b1].insn[i1].op[1] == f->bb[b].insn[i].op[j]) {
678
                f->bb[b].insn[i].op[j] = REF (b1, i1);
679
                break;
680
              }
681
            }
682
          }
683
        }
684
}
685
 
686 883 markom
/* CSE -- common subexpression elimination */
687
void cse (cuc_func *f)
688
{
689
  int b, i, j, b1, i1, b2, i2, j2;
690
  for (b1 = 0; b1 < f->num_bb; b1++)
691
    for (i1 = 0; i1 < f->bb[b1].ninsn; i1++)
692
      for (b2 = 0; b2 < f->num_bb; b2++)
693
        for (i2 = 0; i2 < f->bb[b2].ninsn; i2++) {
694
          cuc_insn *ii1 = &f->bb[b1].insn[i1];
695
          cuc_insn *ii2 = &f->bb[b2].insn[i2];
696
 
697
          /* Do we have an exact match? */
698
          if (ii1->index == ii2->index) continue;
699
          if (ii1->type & IT_VOLATILE) continue;
700
 
701
          if (ii1->op[1] != ii2->op[1] || ii1->opt[1] != ii2->opt[1]) continue;
702
          if (ii1->op[2] != ii2->op[2] || ii1->opt[2] != ii2->opt[2]) continue;
703
          if (ii1->opt[3] != ii2->opt[3]) continue;
704
          if (ii1->opt[3] != OPT_NONE && ii1->op[3] != ii2->op[3]) continue;
705
 
706
          /* Check if we drive outputs? */
707
          if ((ii1->opt[0] & OPT_REGISTER) && ii1->op[0] >= 0)
708
            if ((ii2->opt[0] & OPT_REGISTER) && ii2->op[0] >= 0) continue;
709
            else ii2->op[0] = ii1->op[0];
710
 
711
          /* remove duplicated instruction and relink the references */
712
          change_insn_type (ii2, II_NOP);
713
          for (b = 0; b < f->num_bb; b++)
714
            for (i = 0; i < f->bb[b].ninsn; i++)
715
              for (j = 0; j < MAX_OPERANDS; j++)
716
                if (f->bb[b].insn[i].opt[j] & OPT_REF && f->bb[b].insn[i].op[j] == REF (b2, i2))
717
                  f->bb[b].insn[i].op[j] = REF (b1, i1);
718
        }
719
}
720
 
721
static int count_cmovs (cuc_insn *ii, int match)
722
{
723
  int c = 0, j;
724
  if (match & 2) {
725
    for (j = 0; j < MAX_OPERANDS; j++)
726
      if (ii->opt[j] & OPT_DEST) c++;
727
  }
728
  if (match & 1) {
729
    for (j = 0; j < MAX_OPERANDS; j++)
730
      if (!(ii->opt[j] & OPT_DEST) && ii->opt[j] & OPT_REF) c++;
731
  } else {
732
    for (j = 0; j < MAX_OPERANDS; j++)
733
      if (!(ii->opt[j] & OPT_DEST) && ii->opt[j] != OPT_NONE) c++;
734
  }
735
  return c;
736
}
737
 
738 897 markom
static void search_csm (int iter, cuc_func *f, cuc_shared_list *list);
739
static cuc_shared_list *main_list;
740 883 markom
static int *iteration;
741
 
742 897 markom
/* CSM -- common subexpression matching -- resource sharing
743
   We try to match tree of instruction inside a BB with as many
744
   matches as possible. All possibilities are collected and
745
   options, making situation worse are removed */
746 883 markom
void csm (cuc_func *f)
747
{
748
  int b, i, j;
749
  int cnt;
750 897 markom
  cuc_shared_list *list;
751 883 markom
  cuc_timings timings;
752
 
753
  analyse_timings (f, &timings);
754
  main_list = NULL;
755
  for (b = 0; b < f->num_bb; b++) {
756
    assert (iteration = (int *)malloc (sizeof (int) * f->bb[b].ninsn));
757
    for (i = 0; i < f->bb[b].ninsn; i++) {
758
      int cnt = 0, cntc = 0;
759
      double size = 0., sizec = 0.;
760
      int j2 = 0;
761
      for (j = 0; j < f->bb[b].ninsn; j++)
762
        if (f->bb[b].insn[i].index == f->bb[b].insn[j].index) {
763
          int ok = 1;
764
          for (j2 = 0; j2 < MAX_OPERANDS; j2++) if (!(f->bb[b].insn[j].opt[j2] & OPT_REF))
765
            if (f->bb[b].insn[j].opt[j2] != f->bb[b].insn[i].opt[j2]
766
             || f->bb[b].insn[j].op[j2] != f->bb[b].insn[i].opt[j2]) {
767
              ok = 0;
768
              break;
769
            }
770
          if (ok) {
771
            cntc++;
772
            sizec = sizec + insn_size (&f->bb[b].insn[j]);
773
          } else {
774
            cnt++;
775
            size = size + insn_size (&f->bb[b].insn[j]);
776
          }
777
          iteration[j] = 0;
778
        } else iteration[j] = -1;
779
      if (cntc > 1) {
780 897 markom
        assert (list = (cuc_shared_list *)malloc (sizeof (cuc_shared_list)));
781 883 markom
        list->next = main_list;
782
        list->from = NULL;
783
        list->ref = REF (b, i);
784
        list->cnt = cnt;
785
        list->cmatch = 1;
786
        list->cmovs = count_cmovs (&f->bb[b].insn[i], 3);
787
        list->osize = sizec;
788
        list->size = ii_size (f->bb[b].insn[i].index, 1);
789
        main_list = list;
790
        search_csm (0, f, list);
791
      }
792
      if (cnt > 1) {
793 897 markom
        assert (list = (cuc_shared_list *)malloc (sizeof (cuc_shared_list)));
794 883 markom
        list->next = main_list;
795
        list->from = NULL;
796
        list->ref = REF (b, i);
797
        list->cnt = cnt + cntc;
798
        list->cmatch = 0;
799
        list->cmovs = count_cmovs (&f->bb[b].insn[i], 2);
800
        list->osize = size + sizec;
801
        list->size = ii_size (f->bb[b].insn[i].index, 0);
802
        main_list = list;
803
        search_csm (0, f, list);
804
      }
805
    }
806
    free (iteration);
807
  }
808
 
809
  for (list = main_list; list; list = list->next) list->dead = 0;
810
  cnt = 0;
811
  for (list = main_list; list; list = list->next) if (!list->dead) cnt++;
812
  cucdebug (1, "noptions = %i\n", cnt);
813
 
814
  /* Now we will check the real size of the 'improvements'; if the size
815
     actually increases, we abandom the option */
816
  for (list = main_list; list; list = list->next)
817
    if (list->cmovs * ii_size (II_CMOV, 0) * (list->cnt - 1) + list->size >= list->osize) list->dead = 1;
818
 
819
  cnt = 0;
820
  for (list = main_list; list; list = list->next) if (!list->dead) cnt++;
821
  cucdebug (1, "noptions = %i\n", cnt);
822
 
823
  /* Count number of instructions grouped */
824
  for (list = main_list; list; list = list->next) {
825 897 markom
    cuc_shared_list *l = list;
826 883 markom
    int c = 0;
827
    while (l) {
828
      c++;
829
      if (f->INSN(l->ref).type & (IT_VOLATILE | IT_MEMORY | IT_MEMADD)) list->dead = 1;
830
      l = l->from;
831
    }
832
    list->ninsn = c;
833
  }
834
 
835
  cnt = 0;
836
  for (list = main_list; list; list = list->next)
837
    if (!list->dead) cnt++;
838
  cucdebug (1, "noptions = %i\n", cnt);
839
 
840
#if 1
841
  /* We can get a lot of options here, so we will delete duplicates */
842
  for (list = main_list; list; list = list->next) if (!list->dead) {
843 897 markom
    cuc_shared_list *l;
844 883 markom
    for (l = list->next; l; l = l->next) if (!l->dead) {
845
      int ok = 1;
846 897 markom
      cuc_shared_list *t1 = list;
847
      cuc_shared_list *t2 = l;
848 883 markom
      while (ok && t1 && t2) {
849
        if (f->INSN(t1->ref).index == f->INSN(t2->ref).index) {
850
          /* If other operands are matching, we must check for them also */
851
          if (t1->cmatch) {
852
            int j;
853
            for (j = 0; j < MAX_OPERANDS; j++)
854
              if (!(f->INSN(t1->ref).opt[j] & OPT_REF) || !(f->INSN(t2->ref).opt[j] & OPT_REF)
855
               || f->INSN(t1->ref).opt[j] != f->INSN(t2->ref).opt[j]
856
               || f->INSN(t1->ref).op[j] != f->INSN(t2->ref).op[j]) {
857
                ok = 0;
858
                break;
859
              }
860
          }
861
 
862
          /* This option is duplicate, remove */
863
          if (ok) t1->dead = 1;
864
        }
865
        t1 = t1->from;
866
        t2 = t2->from;
867
      }
868
    }
869
  }
870
  cnt = 0;
871
  for (list = main_list; list; list = list->next) if (!list->dead) cnt++;
872
  cucdebug (1, "noptions = %i\n", cnt);
873
#endif
874
  /* Print out */
875
  for (list = main_list; list; list = list->next) if (!list->dead) {
876 897 markom
    cuc_shared_list *l = list;
877 883 markom
    cucdebug (1, "%-4s cnt %3i ninsn %3i size %8.1f osize %8.1f cmovs %3i @",
878
           cuc_insn_name (&f->INSN(list->ref)), list->cnt, list->ninsn,
879
           list->cmovs * ii_size (II_CMOV, 0) * (list->cnt - 1) + list->size, list->osize, list->cmovs);
880
    while (l) {
881
      cucdebug (1, "%c%x,", l->cmatch ? '.' : '!', l->ref);
882
      l = l->from;
883
    }
884
    cucdebug (1, "\n");
885
  }
886
 
887
  /* Calculate estimated timings */
888
  for (b = 0; b < f->num_bb; b++) {
889
    cnt = 0;
890
    for (list = main_list; list; list = list->next)
891
      if (!list->dead && REF_BB(list->ref) == b) cnt++;
892
 
893
    f->bb[b].ntim = cnt;
894
    if (!cnt) {
895
      f->bb[b].tim = NULL;
896
      continue;
897
    }
898
    assert (f->bb[b].tim = (cuc_timings *)malloc (sizeof (cuc_timings) * cnt));
899
 
900
    cnt = 0;
901
    for (list = main_list; list; list = list->next) if (!list->dead && REF_BB(list->ref) == b) {
902 897 markom
      cuc_shared_list *l = list;
903 883 markom
      f->bb[b].tim[cnt].b = b;
904
      f->bb[b].tim[cnt].preroll = f->bb[b].tim[cnt].unroll = 1;
905
      f->bb[b].tim[cnt].nshared = list->ninsn;
906 897 markom
      assert (f->bb[b].tim[cnt].shared = (cuc_shared_item *)
907
            malloc (sizeof(cuc_shared_item) * list->ninsn));
908
      for (i =  0; i < list->ninsn; i++, l = l->from) {
909
        f->bb[b].tim[cnt].shared[i].ref = l->ref;
910
        f->bb[b].tim[cnt].shared[i].cmatch = l->cmatch;
911
      }
912 883 markom
      f->bb[b].tim[cnt].new_time = timings.new_time + f->bb[b].cnt * (list->cnt - 1);
913 897 markom
      f->bb[b].tim[cnt].size = timings.size +
914
             list->cmovs * ii_size (II_CMOV, 0) * (list->cnt - 1) + list->size - list->osize;
915 883 markom
      cnt++;
916
    }
917
  }
918
}
919
 
920
/* Recursive function for searching through instruction graph */
921 897 markom
static void search_csm (int iter, cuc_func *f, cuc_shared_list *list)
922 883 markom
{
923
  int b, i, j, i1;
924 897 markom
  cuc_shared_list *l;
925 883 markom
  b = REF_BB(list->ref);
926
  i = REF_I(list->ref);
927
 
928
  for (j = 0; j < MAX_OPERANDS; j++) if (f->bb[b].insn[i].opt[j] & OPT_REF) {
929
    int t = f->bb[b].insn[i].op[j];
930
    int cnt = 0, cntc = 0;
931
    double size = 0., sizec = 0.;
932
 
933
    /* Mark neighbours */
934
    for (i1 = 0; i1 < f->bb[b].ninsn; i1++) {
935
      if (iteration[i1] == iter && f->bb[b].insn[i1].opt[j] & OPT_REF) {
936
        int t2 = f->bb[b].insn[i1].op[j];
937
        if (f->INSN(t).index == f->INSN(t2).index && f->INSN(t2).opt[j] & OPT_REF) {
938
          int j2;
939
          int ok = 1;
940
          iteration[REF_I(t2)] = iter + 1;
941
          for (j2 = 0; j2 < MAX_OPERANDS; j2++) if (!(f->bb[b].insn[i1].opt[j2] & OPT_REF))
942
            if (f->bb[b].insn[i1].opt[j2] != f->bb[b].insn[i].opt[j2]
943
             || f->bb[b].insn[i1].op[j2] != f->bb[b].insn[i].opt[j2]) {
944
              ok = 0;
945
              break;
946
            }
947
          if (ok) {
948
            cntc++;
949
            sizec = sizec + insn_size (&f->bb[b].insn[i1]);
950
          } else {
951
            cnt++;
952
            size = size + insn_size (&f->bb[b].insn[i1]);
953
          }
954
        }
955
      }
956
    }
957
 
958
    if (cntc > 1) {
959 897 markom
      assert (l = (cuc_shared_list *)malloc (sizeof (cuc_shared_list)));
960 883 markom
      l->next = main_list;
961
      main_list = l;
962
      l->from = list;
963
      l->ref = t;
964
      l->cnt = cnt;
965
      l->cmatch = 1;
966
      l->cmovs = list->cmovs + count_cmovs (&f->bb[b].insn[i], 1) - 1;
967
      l->size = list->size + ii_size (f->bb[b].insn[i].index, 1);
968
      l->osize = sizec;
969
      search_csm (iter + 1, f, l);
970
    }
971
    if (cnt > 1) {
972 897 markom
      assert (l = (cuc_shared_list *)malloc (sizeof (cuc_shared_list)));
973 883 markom
      l->next = main_list;
974
      main_list = l;
975
      l->from = list;
976
      l->ref = t;
977
      l->cnt = cnt + cntc;
978
      l->cmatch = 0;
979
      l->osize = size + sizec;
980
      l->cmovs = list->cmovs + count_cmovs (&f->bb[b].insn[i], 0) - 1;
981
      l->size = list->size + ii_size (f->bb[b].insn[i].index, 0);
982
      search_csm (iter + 1, f, l);
983
    }
984
 
985
    /* Unmark them back */
986
    for (i1 = 0; i1 < f->bb[b].ninsn; i1++) if (iteration[i1] > iter) iteration[i1] = -1;
987
  }
988
}
989
 
990 897 markom
/* Displays shared instructions */
991
void print_shared (cuc_func *rf, cuc_shared_item *shared, int nshared)
992
{
993
  int i, first = 1;
994
  for (i = 0; i < nshared; i++) {
995
    printf ("%s%s%s", first ? "" : "-", cuc_insn_name (rf->INSN(shared[i].ref).index),
996
                    shared[i].cmatch ? "!" : "");
997
    first = 0;
998
  }
999
}
1000
 
1001
/* Common subexpression matching -- resource sharing, generation pass
1002
 
1003
   Situation here is much simpler than with analysis -- we know the instruction sequence
1004
   we are going to share, but we are going to do this on whole function, not just one BB.
1005
   We can find sequence in reference function, as pointed from "shared" */
1006
void csm_gen (cuc_func *f, cuc_func *rf, cuc_shared_item *shared, int nshared)
1007
{
1008
  int b, i, j, cnt = 0;
1009
#warning   some code here (2)
1010
  printf ("Replacing: ");
1011
  print_shared (rf, shared, nshared);
1012
 
1013
  for (b = 0; b < f->num_bb; b++)
1014
    for (i = 0; i < f->bb[b].ninsn; i++) {
1015
    }
1016
 
1017
  printf ("\nFound %i matches.\n", cnt);
1018
}
1019
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.