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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [gimple-low.c] - Blame information for rev 20

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

Line No. Rev Author Line
1 12 jlechner
/* Tree lowering pass.  Lowers GIMPLE into unstructured form.
2
 
3
   Copyright (C) 2003, 2005 Free Software Foundation, Inc.
4
 
5
This file is part of GCC.
6
 
7
GCC is free software; you can redistribute it and/or modify it under
8
the terms of the GNU General Public License as published by the Free
9
Software Foundation; either version 2, or (at your option) any later
10
version.
11
 
12
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13
WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15
for more details.
16
 
17
You should have received a copy of the GNU General Public License
18
along with GCC; see the file COPYING.  If not, write to the Free
19
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
20
02110-1301, USA.  */
21
 
22
#include "config.h"
23
#include "system.h"
24
#include "coretypes.h"
25
#include "tm.h"
26
#include "tree.h"
27
#include "rtl.h"
28
#include "varray.h"
29
#include "tree-gimple.h"
30
#include "tree-inline.h"
31
#include "diagnostic.h"
32
#include "langhooks.h"
33
#include "langhooks-def.h"
34
#include "tree-flow.h"
35
#include "timevar.h"
36
#include "except.h"
37
#include "hashtab.h"
38
#include "flags.h"
39
#include "function.h"
40
#include "expr.h"
41
#include "toplev.h"
42
#include "tree-pass.h"
43
 
44
struct lower_data
45
{
46
  /* Block the current statement belongs to.  */
47
  tree block;
48
 
49
  /* A TREE_LIST of label and return statements to be moved to the end
50
     of the function.  */
51
  tree return_statements;
52
};
53
 
54
static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
55
static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *);
56
static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *);
57
static void lower_return_expr (tree_stmt_iterator *, struct lower_data *);
58
static bool expand_var_p (tree);
59
 
60
/* Lowers the body of current_function_decl.  */
61
 
62
static void
63
lower_function_body (void)
64
{
65
  struct lower_data data;
66
  tree *body_p = &DECL_SAVED_TREE (current_function_decl);
67
  tree bind = *body_p;
68
  tree_stmt_iterator i;
69
  tree t, x;
70
 
71
  gcc_assert (TREE_CODE (bind) == BIND_EXPR);
72
 
73
  data.block = DECL_INITIAL (current_function_decl);
74
  BLOCK_SUBBLOCKS (data.block) = NULL_TREE;
75
  BLOCK_CHAIN (data.block) = NULL_TREE;
76
  TREE_ASM_WRITTEN (data.block) = 1;
77
 
78
  data.return_statements = NULL_TREE;
79
 
80
  *body_p = alloc_stmt_list ();
81
  i = tsi_start (*body_p);
82
  tsi_link_after (&i, bind, TSI_NEW_STMT);
83
  lower_bind_expr (&i, &data);
84
 
85
  i = tsi_last (*body_p);
86
 
87
  /* If the function falls off the end, we need a null return statement.
88
     If we've already got one in the return_statements list, we don't
89
     need to do anything special.  Otherwise build one by hand.  */
90
  if (block_may_fallthru (*body_p)
91
      && (data.return_statements == NULL
92
          || TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL))
93
    {
94
      x = build (RETURN_EXPR, void_type_node, NULL);
95
      SET_EXPR_LOCATION (x, cfun->function_end_locus);
96
      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
97
    }
98
 
99
  /* If we lowered any return statements, emit the representative
100
     at the end of the function.  */
101
  for (t = data.return_statements ; t ; t = TREE_CHAIN (t))
102
    {
103
      x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
104
      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
105
 
106
      /* Remove the line number from the representative return statement.
107
         It now fills in for many such returns.  Failure to remove this
108
         will result in incorrect results for coverage analysis.  */
109
      x = TREE_VALUE (t);
110
#ifdef USE_MAPPED_LOCATION
111
      SET_EXPR_LOCATION (x, UNKNOWN_LOCATION);
112
#else
113
      SET_EXPR_LOCUS (x, NULL);
114
#endif
115
      tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
116
    }
117
 
118
  gcc_assert (data.block == DECL_INITIAL (current_function_decl));
119
  BLOCK_SUBBLOCKS (data.block)
120
    = blocks_nreverse (BLOCK_SUBBLOCKS (data.block));
121
 
122
  clear_block_marks (data.block);
123
}
124
 
125
struct tree_opt_pass pass_lower_cf =
126
{
127
  "lower",                              /* name */
128
  NULL,                                 /* gate */
129
  lower_function_body,                  /* execute */
130
  NULL,                                 /* sub */
131
  NULL,                                 /* next */
132
  0,                                     /* static_pass_number */
133
  0,                                     /* tv_id */
134
  PROP_gimple_any,                      /* properties_required */
135
  PROP_gimple_lcf,                      /* properties_provided */
136
  PROP_gimple_any,                      /* properties_destroyed */
137
  0,                                     /* todo_flags_start */
138
  TODO_dump_func,                       /* todo_flags_finish */
139
 
140
};
141
 
142
 
143
/* Lowers the EXPR.  Unlike gimplification the statements are not relowered
144
   when they are changed -- if this has to be done, the lowering routine must
145
   do it explicitly.  DATA is passed through the recursion.  */
146
 
147
static void
148
lower_stmt_body (tree expr, struct lower_data *data)
149
{
150
  tree_stmt_iterator tsi;
151
 
152
  for (tsi = tsi_start (expr); !tsi_end_p (tsi); )
153
    lower_stmt (&tsi, data);
154
}
155
 
156
/* Lowers statement TSI.  DATA is passed through the recursion.  */
157
 
158
static void
159
lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
160
{
161
  tree stmt = tsi_stmt (*tsi);
162
 
163
  if (EXPR_HAS_LOCATION (stmt) && data)
164
    TREE_BLOCK (stmt) = data->block;
165
 
166
  switch (TREE_CODE (stmt))
167
    {
168
    case BIND_EXPR:
169
      lower_bind_expr (tsi, data);
170
      return;
171
    case COND_EXPR:
172
      lower_cond_expr (tsi, data);
173
      return;
174
    case RETURN_EXPR:
175
      lower_return_expr (tsi, data);
176
      return;
177
 
178
    case TRY_FINALLY_EXPR:
179
    case TRY_CATCH_EXPR:
180
      lower_stmt_body (TREE_OPERAND (stmt, 0), data);
181
      lower_stmt_body (TREE_OPERAND (stmt, 1), data);
182
      break;
183
    case CATCH_EXPR:
184
      lower_stmt_body (CATCH_BODY (stmt), data);
185
      break;
186
    case EH_FILTER_EXPR:
187
      lower_stmt_body (EH_FILTER_FAILURE (stmt), data);
188
      break;
189
 
190
    case NOP_EXPR:
191
    case ASM_EXPR:
192
    case MODIFY_EXPR:
193
    case CALL_EXPR:
194
    case GOTO_EXPR:
195
    case LABEL_EXPR:
196
    case SWITCH_EXPR:
197
      break;
198
 
199
    default:
200
#ifdef ENABLE_CHECKING
201
      print_node_brief (stderr, "", stmt, 0);
202
      internal_error ("unexpected node");
203
#endif
204
    case COMPOUND_EXPR:
205
      gcc_unreachable ();
206
    }
207
 
208
  tsi_next (tsi);
209
}
210
 
211
/* Lowers a bind_expr TSI.  DATA is passed through the recursion.  */
212
 
213
static void
214
lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data)
215
{
216
  tree old_block = data->block;
217
  tree stmt = tsi_stmt (*tsi);
218
  tree new_block = BIND_EXPR_BLOCK (stmt);
219
 
220
  if (new_block)
221
    {
222
      if (new_block == old_block)
223
        {
224
          /* The outermost block of the original function may not be the
225
             outermost statement chain of the gimplified function.  So we
226
             may see the outermost block just inside the function.  */
227
          gcc_assert (new_block == DECL_INITIAL (current_function_decl));
228
          new_block = NULL;
229
        }
230
      else
231
        {
232
          /* We do not expect to handle duplicate blocks.  */
233
          gcc_assert (!TREE_ASM_WRITTEN (new_block));
234
          TREE_ASM_WRITTEN (new_block) = 1;
235
 
236
          /* Block tree may get clobbered by inlining.  Normally this would
237
             be fixed in rest_of_decl_compilation using block notes, but
238
             since we are not going to emit them, it is up to us.  */
239
          BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (old_block);
240
          BLOCK_SUBBLOCKS (old_block) = new_block;
241
          BLOCK_SUBBLOCKS (new_block) = NULL_TREE;
242
          BLOCK_SUPERCONTEXT (new_block) = old_block;
243
 
244
          data->block = new_block;
245
        }
246
    }
247
 
248
  record_vars (BIND_EXPR_VARS (stmt));
249
  lower_stmt_body (BIND_EXPR_BODY (stmt), data);
250
 
251
  if (new_block)
252
    {
253
      gcc_assert (data->block == new_block);
254
 
255
      BLOCK_SUBBLOCKS (new_block)
256
        = blocks_nreverse (BLOCK_SUBBLOCKS (new_block));
257
      data->block = old_block;
258
    }
259
 
260
  /* The BIND_EXPR no longer carries any useful information -- kill it.  */
261
  tsi_link_before (tsi, BIND_EXPR_BODY (stmt), TSI_SAME_STMT);
262
  tsi_delink (tsi);
263
}
264
 
265
/* Try to determine whether a TRY_CATCH expression can fall through.
266
   This is a subroutine of block_may_fallthru.  */
267
 
268
static bool
269
try_catch_may_fallthru (tree stmt)
270
{
271
  tree_stmt_iterator i;
272
 
273
  /* If the TRY block can fall through, the whole TRY_CATCH can
274
     fall through.  */
275
  if (block_may_fallthru (TREE_OPERAND (stmt, 0)))
276
    return true;
277
 
278
  i = tsi_start (TREE_OPERAND (stmt, 1));
279
  switch (TREE_CODE (tsi_stmt (i)))
280
    {
281
    case CATCH_EXPR:
282
      /* We expect to see a sequence of CATCH_EXPR trees, each with a
283
         catch expression and a body.  The whole TRY_CATCH may fall
284
         through iff any of the catch bodies falls through.  */
285
      for (; !tsi_end_p (i); tsi_next (&i))
286
        {
287
          if (block_may_fallthru (CATCH_BODY (tsi_stmt (i))))
288
            return true;
289
        }
290
      return false;
291
 
292
    case EH_FILTER_EXPR:
293
      /* The exception filter expression only matters if there is an
294
         exception.  If the exception does not match EH_FILTER_TYPES,
295
         we will execute EH_FILTER_FAILURE, and we will fall through
296
         if that falls through.  If the exception does match
297
         EH_FILTER_TYPES, the stack unwinder will continue up the
298
         stack, so we will not fall through.  We don't know whether we
299
         will throw an exception which matches EH_FILTER_TYPES or not,
300
         so we just ignore EH_FILTER_TYPES and assume that we might
301
         throw an exception which doesn't match.  */
302
      return block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i)));
303
 
304
    default:
305
      /* This case represents statements to be executed when an
306
         exception occurs.  Those statements are implicitly followed
307
         by a RESX_EXPR to resume execution after the exception.  So
308
         in this case the TRY_CATCH never falls through.  */
309
      return false;
310
    }
311
}
312
 
313
/* Try to determine if we can fall out of the bottom of BLOCK.  This guess
314
   need not be 100% accurate; simply be conservative and return true if we
315
   don't know.  This is used only to avoid stupidly generating extra code.
316
   If we're wrong, we'll just delete the extra code later.  */
317
 
318
bool
319
block_may_fallthru (tree block)
320
{
321
  tree stmt = expr_last (block);
322
 
323
  switch (stmt ? TREE_CODE (stmt) : ERROR_MARK)
324
    {
325
    case GOTO_EXPR:
326
    case RETURN_EXPR:
327
    case RESX_EXPR:
328
      /* Easy cases.  If the last statement of the block implies
329
         control transfer, then we can't fall through.  */
330
      return false;
331
 
332
    case SWITCH_EXPR:
333
      /* If SWITCH_LABELS is set, this is lowered, and represents a
334
         branch to a selected label and hence can not fall through.
335
         Otherwise SWITCH_BODY is set, and the switch can fall
336
         through.  */
337
      return SWITCH_LABELS (stmt) == NULL_TREE;
338
 
339
    case COND_EXPR:
340
      if (block_may_fallthru (COND_EXPR_THEN (stmt)))
341
        return true;
342
      return block_may_fallthru (COND_EXPR_ELSE (stmt));
343
 
344
    case BIND_EXPR:
345
      return block_may_fallthru (BIND_EXPR_BODY (stmt));
346
 
347
    case TRY_CATCH_EXPR:
348
      return try_catch_may_fallthru (stmt);
349
 
350
    case TRY_FINALLY_EXPR:
351
      /* The finally clause is always executed after the try clause,
352
         so if it does not fall through, then the try-finally will not
353
         fall through.  Otherwise, if the try clause does not fall
354
         through, then when the finally clause falls through it will
355
         resume execution wherever the try clause was going.  So the
356
         whole try-finally will only fall through if both the try
357
         clause and the finally clause fall through.  */
358
      return (block_may_fallthru (TREE_OPERAND (stmt, 0))
359
              && block_may_fallthru (TREE_OPERAND (stmt, 1)));
360
 
361
    case MODIFY_EXPR:
362
      if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR)
363
        stmt = TREE_OPERAND (stmt, 1);
364
      else
365
        return true;
366
      /* FALLTHRU */
367
 
368
    case CALL_EXPR:
369
      /* Functions that do not return do not fall through.  */
370
      return (call_expr_flags (stmt) & ECF_NORETURN) == 0;
371
 
372
    case CLEANUP_POINT_EXPR:
373
      return block_may_fallthru (TREE_OPERAND (stmt, 0));
374
 
375
    default:
376
      return true;
377
    }
378
}
379
 
380
/* Lowers a cond_expr TSI.  DATA is passed through the recursion.  */
381
 
382
static void
383
lower_cond_expr (tree_stmt_iterator *tsi, struct lower_data *data)
384
{
385
  tree stmt = tsi_stmt (*tsi);
386
  bool then_is_goto, else_is_goto;
387
  tree then_branch, else_branch;
388
  tree then_goto, else_goto;
389
 
390
  then_branch = COND_EXPR_THEN (stmt);
391
  else_branch = COND_EXPR_ELSE (stmt);
392
 
393
  lower_stmt_body (then_branch, data);
394
  lower_stmt_body (else_branch, data);
395
 
396
  then_goto = expr_only (then_branch);
397
  then_is_goto = then_goto && simple_goto_p (then_goto);
398
 
399
  else_goto = expr_only (else_branch);
400
  else_is_goto = else_goto && simple_goto_p (else_goto);
401
 
402
  if (!then_is_goto || !else_is_goto)
403
    {
404
      tree then_label, else_label, end_label, t;
405
 
406
      then_label = NULL_TREE;
407
      else_label = NULL_TREE;
408
      end_label = NULL_TREE;
409
 
410
      /* Replace the cond_expr with explicit gotos.  */
411
      if (!then_is_goto)
412
        {
413
          t = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
414
          if (TREE_SIDE_EFFECTS (then_branch))
415
            then_label = t;
416
          else
417
            end_label = t;
418
          then_goto = build_and_jump (&LABEL_EXPR_LABEL (t));
419
        }
420
 
421
      if (!else_is_goto)
422
        {
423
          t = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
424
          if (TREE_SIDE_EFFECTS (else_branch))
425
            else_label = t;
426
          else
427
            {
428
              /* Both THEN and ELSE can be no-ops if one or both contained an
429
                 empty BIND_EXPR that was associated with the toplevel block
430
                 of an inlined function.  In that case remove_useless_stmts
431
                 can't have cleaned things up for us; kill the whole
432
                 conditional now.  */
433
              if (end_label)
434
                {
435
                  tsi_delink (tsi);
436
                  return;
437
                }
438
              else
439
                end_label = t;
440
            }
441
          else_goto = build_and_jump (&LABEL_EXPR_LABEL (t));
442
        }
443
 
444
      if (then_label)
445
        {
446
          bool may_fallthru = block_may_fallthru (then_branch);
447
 
448
          tsi_link_after (tsi, then_label, TSI_CONTINUE_LINKING);
449
          tsi_link_after (tsi, then_branch, TSI_CONTINUE_LINKING);
450
 
451
          if (else_label && may_fallthru)
452
            {
453
              end_label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
454
              t = build_and_jump (&LABEL_EXPR_LABEL (end_label));
455
              tsi_link_after (tsi, t, TSI_CONTINUE_LINKING);
456
            }
457
        }
458
 
459
      if (else_label)
460
        {
461
          tsi_link_after (tsi, else_label, TSI_CONTINUE_LINKING);
462
          tsi_link_after (tsi, else_branch, TSI_CONTINUE_LINKING);
463
        }
464
 
465
      if (end_label)
466
        tsi_link_after (tsi, end_label, TSI_CONTINUE_LINKING);
467
    }
468
 
469
  COND_EXPR_THEN (stmt) = then_goto;
470
  COND_EXPR_ELSE (stmt) = else_goto;
471
 
472
  tsi_next (tsi);
473
}
474
 
475
static void
476
lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
477
{
478
  tree stmt = tsi_stmt (*tsi);
479
  tree value, t, label;
480
 
481
  /* Extract the value being returned.  */
482
  value = TREE_OPERAND (stmt, 0);
483
  if (value && TREE_CODE (value) == MODIFY_EXPR)
484
    value = TREE_OPERAND (value, 1);
485
 
486
  /* Match this up with an existing return statement that's been created.  */
487
  for (t = data->return_statements; t ; t = TREE_CHAIN (t))
488
    {
489
      tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0);
490
      if (tvalue && TREE_CODE (tvalue) == MODIFY_EXPR)
491
        tvalue = TREE_OPERAND (tvalue, 1);
492
 
493
      if (value == tvalue)
494
        {
495
          label = TREE_PURPOSE (t);
496
          goto found;
497
        }
498
    }
499
 
500
  /* Not found.  Create a new label and record the return statement.  */
501
  label = create_artificial_label ();
502
  data->return_statements = tree_cons (label, stmt, data->return_statements);
503
 
504
  /* Generate a goto statement and remove the return statement.  */
505
 found:
506
  t = build (GOTO_EXPR, void_type_node, label);
507
  SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
508
  tsi_link_before (tsi, t, TSI_SAME_STMT);
509
  tsi_delink (tsi);
510
}
511
 
512
 
513
/* Record the variables in VARS.  */
514
 
515
void
516
record_vars (tree vars)
517
{
518
  for (; vars; vars = TREE_CHAIN (vars))
519
    {
520
      tree var = vars;
521
 
522
      /* BIND_EXPRs contains also function/type/constant declarations
523
         we don't need to care about.  */
524
      if (TREE_CODE (var) != VAR_DECL)
525
        continue;
526
      /* Nothing to do in this case.  */
527
      if (DECL_EXTERNAL (var))
528
        continue;
529
 
530
      /* Record the variable.  */
531
      cfun->unexpanded_var_list = tree_cons (NULL_TREE, var,
532
                                             cfun->unexpanded_var_list);
533
    }
534
}
535
 
536
/* Check whether to expand a variable VAR.  */
537
 
538
static bool
539
expand_var_p (tree var)
540
{
541
  struct var_ann_d *ann;
542
 
543
  if (TREE_CODE (var) != VAR_DECL)
544
    return true;
545
 
546
  /* Leave statics and externals alone.  */
547
  if (TREE_STATIC (var) || DECL_EXTERNAL (var))
548
    return true;
549
 
550
  /* Remove all unused local variables.  */
551
  ann = var_ann (var);
552
  if (!ann || !ann->used)
553
    return false;
554
 
555
  return true;
556
}
557
 
558
/* Throw away variables that are unused.  */
559
 
560
static void
561
remove_useless_vars (void)
562
{
563
  tree var, *cell;
564
  FILE *df = NULL;
565
 
566
  if (dump_file && (dump_flags & TDF_DETAILS))
567
    {
568
      df = dump_file;
569
      fputs ("Discarding as unused:\n", df);
570
    }
571
 
572
  for (cell = &cfun->unexpanded_var_list; *cell; )
573
    {
574
      var = TREE_VALUE (*cell);
575
 
576
      if (!expand_var_p (var))
577
        {
578
          if (df)
579
            {
580
              fputs ("  ", df);
581
              print_generic_expr (df, var, dump_flags);
582
              fputc ('\n', df);
583
            }
584
 
585
          *cell = TREE_CHAIN (*cell);
586
          continue;
587
        }
588
 
589
      cell = &TREE_CHAIN (*cell);
590
    }
591
 
592
  if (df)
593
    fputc ('\n', df);
594
}
595
 
596
struct tree_opt_pass pass_remove_useless_vars =
597
{
598
  "vars",                               /* name */
599
  NULL,                                 /* gate */
600
  remove_useless_vars,                  /* execute */
601
  NULL,                                 /* sub */
602
  NULL,                                 /* next */
603
  0,                                     /* static_pass_number */
604
  0,                                     /* tv_id */
605
  0,                                     /* properties_required */
606
  0,                                     /* properties_provided */
607
  0,                                     /* properties_destroyed */
608
  0,                                     /* todo_flags_start */
609
  TODO_dump_func,                       /* todo_flags_finish */
610
 
611
};
612
 
613
/* Mark BLOCK used if it has a used variable in it, then recurse over its
614
   subblocks.  */
615
 
616
static void
617
mark_blocks_with_used_vars (tree block)
618
{
619
  tree var;
620
  tree subblock;
621
 
622
  if (!TREE_USED (block))
623
    {
624
      for (var = BLOCK_VARS (block);
625
           var;
626
           var = TREE_CHAIN (var))
627
        {
628
          if (TREE_USED (var))
629
            {
630
              TREE_USED (block) = true;
631
              break;
632
            }
633
        }
634
    }
635
  for (subblock = BLOCK_SUBBLOCKS (block);
636
       subblock;
637
       subblock = BLOCK_CHAIN (subblock))
638
    mark_blocks_with_used_vars (subblock);
639
}
640
 
641
/* Mark the used attribute on blocks correctly.  */
642
 
643
static void
644
mark_used_blocks (void)
645
{
646
  mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl));
647
}
648
 
649
 
650
struct tree_opt_pass pass_mark_used_blocks =
651
{
652
  "blocks",                             /* name */
653
  NULL,                                 /* gate */
654
  mark_used_blocks,                     /* execute */
655
  NULL,                                 /* sub */
656
  NULL,                                 /* next */
657
  0,                                     /* static_pass_number */
658
  0,                                     /* tv_id */
659
  0,                                     /* properties_required */
660
  0,                                     /* properties_provided */
661
  0,                                     /* properties_destroyed */
662
  0,                                     /* todo_flags_start */
663
  TODO_dump_func,                       /* todo_flags_finish */
664
 
665
};

powered by: WebSVN 2.1.0

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