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

Subversion Repositories or1k

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

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

powered by: WebSVN 2.1.0

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