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

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_37/] [or1ksim/] [cuc/] [insn.c] - Blame information for rev 905

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

powered by: WebSVN 2.1.0

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