• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nickg / nvc / 12293324012

12 Dec 2024 09:18AM UTC coverage: 91.973% (+0.1%) from 91.835%
12293324012

Pull #1081

github

web-flow
Merge c7e642928 into 72b5e72f5
Pull Request #1081: Add PSL 2010 features breakdown to HTML docs.

63217 of 68734 relevant lines covered (91.97%)

621809.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.98
/src/vcode.c
1
//
2
//  Copyright (C) 2014-2024  Nick Gasson
3
//
4
//  This program is free software: you can redistribute it and/or modify
5
//  it under the terms of the GNU General Public License as published by
6
//  the Free Software Foundation, either version 3 of the License, or
7
//  (at your option) any later version.
8
//
9
//  This program is distributed in the hope that it will be useful,
10
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
//  GNU General Public License for more details.
13
//
14
//  You should have received a copy of the GNU General Public License
15
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

18
#include "util.h"
19
#include "array.h"
20
#include "common.h"
21
#include "diag.h"
22
#include "hash.h"
23
#include "lib.h"
24
#include "object.h"
25
#include "tree.h"
26
#include "vcode.h"
27

28
#include <assert.h>
29
#include <inttypes.h>
30
#include <string.h>
31
#include <stdlib.h>
32
#include <float.h>
33
#include <math.h>
34

35
DECLARE_AND_DEFINE_ARRAY(vcode_reg);
8,363,916✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
391,447✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
255,944✔
38

39
#define OP_HAS_TYPE(x)                                                  \
40
   (x == VCODE_OP_ALLOC || x == VCODE_OP_COPY                           \
41
    || x == VCODE_OP_CONST || x == VCODE_OP_CAST                        \
42
    || x == VCODE_OP_CONST_RECORD || x == VCODE_OP_CLOSURE              \
43
    || x == VCODE_OP_BIND_EXTERNAL || x == VCODE_OP_ARRAY_SCOPE         \
44
    || x == VCODE_OP_RECORD_SCOPE)
45
#define OP_HAS_ADDRESS(x)                                               \
46
   (x == VCODE_OP_LOAD || x == VCODE_OP_STORE || x == VCODE_OP_INDEX    \
47
    || x == VCODE_OP_VAR_UPREF)
48
#define OP_HAS_FUNC(x)                                                  \
49
   (x == VCODE_OP_FCALL || x == VCODE_OP_PCALL || x == VCODE_OP_RESUME  \
50
    || x == VCODE_OP_CLOSURE || x == VCODE_OP_PROTECTED_INIT            \
51
    || x == VCODE_OP_PACKAGE_INIT || x == VCODE_OP_PROCESS_INIT \
52
    || x == VCODE_OP_FUNCTION_TRIGGER)
53
#define OP_HAS_IDENT(x)                                                 \
54
   (x == VCODE_OP_LINK_VAR || x == VCODE_OP_LINK_PACKAGE                \
55
    || x == VCODE_OP_DEBUG_LOCUS)
56
#define OP_HAS_REAL(x)                                                  \
57
   (x == VCODE_OP_CONST_REAL)
58
#define OP_HAS_VALUE(x)                                                 \
59
   (x == VCODE_OP_CONST || x == VCODE_OP_CONST_REP                      \
60
    || x == VCODE_OP_DEBUG_LOCUS)
61
#define OP_HAS_DIM(x)                                                   \
62
   (x == VCODE_OP_UARRAY_LEFT || x == VCODE_OP_UARRAY_RIGHT             \
63
    || x == VCODE_OP_UARRAY_DIR || x == VCODE_OP_UARRAY_LEN)
64
#define OP_HAS_HOPS(x)                                                  \
65
   (x == VCODE_OP_VAR_UPREF || x == VCODE_OP_CONTEXT_UPREF)
66
#define OP_HAS_FIELD(x)                                                 \
67
   (x == VCODE_OP_RECORD_REF)
68
#define OP_HAS_CMP(x)                                                   \
69
   (x == VCODE_OP_CMP)
70
#define OP_HAS_TAG(x)                                                   \
71
   (x == VCODE_OP_COVER_STMT || x == VCODE_OP_COVER_BRANCH              \
72
    || x == VCODE_OP_COVER_TOGGLE || x == VCODE_OP_COVER_EXPR           \
73
    || x == VCODE_OP_COVER_STATE)
74
#define OP_HAS_COMMENT(x)                                               \
75
   (x == VCODE_OP_COMMENT)
76
#define OP_HAS_TARGET(x)                                                \
77
   (x == VCODE_OP_WAIT || x == VCODE_OP_JUMP || x == VCODE_OP_COND      \
78
    || x == VCODE_OP_PCALL || x == VCODE_OP_CASE)
79

80
typedef struct {
81
   vcode_op_t              kind;
82
   vcode_reg_t             result;
83
   vcode_reg_array_t       args;
84
   loc_t                   loc;
85
   vcode_type_t            type;      // OP_HAS_TYPE
86
   union {
87
      ident_t              func;      // OP_HAS_FUNC
88
      ident_t              ident;     // OP_HAS_IDENT
89
      vcode_var_t          address;   // OP_HAS_ADDRESS
90
   };
91
   union {
92
      vcode_cmp_t          cmp;       // OP_HAS_CMP
93
      int64_t              value;     // OP_HAS_VALUE
94
      double               real;      // OP_HAS_REAL
95
      char                *comment;   // OP_HAS_COMMENT
96
      unsigned             dim;       // OP_HAS_DIM
97
      unsigned             hops;      // OP_HAS_HOPS
98
      unsigned             field;     // OP_HAS_FIELD
99
      uint32_t             tag;       // OP_HAS_TAG
100
      vcode_block_array_t  targets;   // OP_HAS_TARGET
101
   };
102
} op_t;
103

104
DECLARE_AND_DEFINE_ARRAY(op);
12,713,086✔
105

106
typedef struct {
107
   op_array_t ops;
108
   loc_t      last_loc;
109
} block_t;
110

111
typedef struct {
112
   vcode_type_t type;
113
   vcode_type_t bounds;
114
} reg_t;
115

116
typedef struct {
117
   vtype_kind_t kind;
118
   vtype_repr_t repr;
119
   union {
120
      struct {
121
         int64_t low;
122
         int64_t high;
123
      };
124
      struct {
125
         double rlow;
126
         double rhigh;
127
      };
128
      struct {
129
         unsigned      dims;
130
         unsigned      size;
131
         vcode_type_t  elem;
132
         vcode_type_t  bounds;
133
      };
134
      vcode_type_t pointed;
135
      vcode_type_t base;
136
      struct {
137
         ident_t            name;
138
         vcode_type_array_t fields;
139
      };
140
   };
141
} vtype_t;
142

143
typedef struct {
144
   vcode_type_t      type;
145
   vcode_type_t      bounds;
146
   ident_t           name;
147
   vcode_var_flags_t flags;
148
} var_t;
149

150
typedef struct {
151
   vcode_type_t type;
152
   vcode_type_t bounds;
153
   ident_t      name;
154
   vcode_reg_t  reg;
155
} param_t;
156

157
DECLARE_AND_DEFINE_ARRAY(param);
31,211✔
158
DECLARE_AND_DEFINE_ARRAY(var);
381,235✔
159
DECLARE_AND_DEFINE_ARRAY(reg);
7,999,563✔
160
DECLARE_AND_DEFINE_ARRAY(block);
137,727✔
161
DECLARE_AND_DEFINE_ARRAY(vtype);
72,663,629✔
162

163
typedef enum {
164
   UNIT_UNDEFINED     = (1 << 1),
165
   UNIT_ESCAPING_TLAB = (1 << 2)
166
} unit_flags_t;
167

168
struct _vcode_unit {
169
   vunit_kind_t   kind;
170
   vcode_unit_t   context;
171
   ident_t        name;
172
   vcode_type_t   result;
173
   block_array_t  blocks;
174
   reg_array_t    regs;
175
   vtype_array_t  types;
176
   var_array_t    vars;
177
   param_array_t  params;
178
   unsigned       depth;
179
   unit_flags_t   flags;
180
   vcode_unit_t   children;
181
   vcode_unit_t   next;
182
   ident_t        module;
183
   ptrdiff_t      offset;
184
};
185

186
#define MASK_CONTEXT(x)   ((x) >> 24)
187
#define MASK_INDEX(x)     ((x) & 0xffffff)
188
#define MAKE_HANDLE(c, i) (((c) & 0xff) << 24 | ((i) & 0xffffff))
189

190
#define VCODE_ASSERT(expr, ...) do                                      \
191
      if (unlikely(!(expr))) {                                          \
192
         vcode_dump_with_mark(vcode_block_data()->ops.count - 1,        \
193
                              NULL, NULL);                              \
194
         fatal_trace(__VA_ARGS__);                                      \
195
      } while (0)
196

197
#define VCODE_FOR_EACH_OP(name)                                 \
198
   block_t *_b = vcode_block_data();                            \
199
   op_t *name; int _i;                                          \
200
   if (_b->ops.count > 0)                                       \
201
      for (_i = _b->ops.count - 1, name = &(_b->ops.items[_i]); \
202
           _i >= 0; name = &(_b->ops.items[--_i]))
203

204
#define VCODE_FOR_EACH_MATCHING_OP(name, k) \
205
   block_t *_b = vcode_block_data();                            \
206
   op_t *name; int _i;                                          \
207
   if (_b->ops.count > 0)                                       \
208
      for (_i = 0, name = &(_b->ops.items[_i]);                 \
209
           _i < _b->ops.count; name = &(_b->ops.items[++_i]))   \
210
         if (name->kind == (k))
211

212
#define VCODE_CHECK_UNIONS 0
213

214
static __thread vcode_unit_t  active_unit  = NULL;
215
static __thread vcode_block_t active_block = VCODE_INVALID_BLOCK;
216

217
static inline int64_t sadd64(int64_t a, int64_t b)
31,326✔
218
{
219
   int64_t result;
31,326✔
220
   if (__builtin_add_overflow(a, b, &result))
31,326✔
221
      return b < 0 ? INT64_MIN : INT64_MAX;
12,036✔
222

223
   return result;
224
}
225

226
static inline int64_t ssub64(int64_t a, int64_t b)
45,560✔
227
{
228
   int64_t result;
45,560✔
229
   if (__builtin_sub_overflow(a, b, &result))
45,560✔
230
      return b > 0 ? INT64_MIN : INT64_MAX;
4,251✔
231

232
   return result;
233
}
234

235
static inline int64_t smul64(int64_t a, int64_t b)
9,140✔
236
{
237
   int64_t result;
9,140✔
238
   if (__builtin_mul_overflow(a, b, &result))
9,140✔
239
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
4,557✔
240

241
   return result;
242
}
243

244
static vcode_reg_t vcode_add_reg(vcode_type_t type)
1,283,324✔
245
{
246
   assert(active_unit != NULL);
1,283,324✔
247

248
   vcode_reg_t reg = active_unit->regs.count;
1,283,324✔
249
   reg_t *r = reg_array_alloc(&(active_unit->regs));
1,283,324✔
250
   memset(r, '\0', sizeof(reg_t));
1,283,324✔
251
   r->type   = type;
1,283,324✔
252
   r->bounds = type;
1,283,324✔
253

254
   return reg;
1,283,324✔
255
}
256

257
static block_t *vcode_block_data(void)
5,793,430✔
258
{
259
   assert(active_unit != NULL);
5,793,430✔
260
   assert(active_block != -1);
5,793,430✔
261
   return &(active_unit->blocks.items[active_block]);
5,793,430✔
262
}
263

264
static op_t *vcode_add_op(vcode_op_t kind)
1,625,077✔
265
{
266
   assert(active_unit != NULL);
1,625,077✔
267
   assert(active_block != VCODE_INVALID_BLOCK);
1,625,077✔
268

269
   VCODE_ASSERT(
1,625,077✔
270
      !vcode_block_finished(),
271
      "attempt to add to already finished block %d", active_block);
272

273
   block_t *block = vcode_block_data();
1,625,077✔
274

275
   op_t *op = op_array_alloc(&(block->ops));
1,625,077✔
276
   memset(op, '\0', sizeof(op_t));
1,625,077✔
277
   op->kind   = kind;
1,625,077✔
278
   op->result = VCODE_INVALID_REG;
1,625,077✔
279
   op->loc    = block->last_loc;
1,625,077✔
280

281
   return op;
1,625,077✔
282
}
283

284
static void vcode_add_arg(op_t *op, vcode_reg_t arg)
2,714,306✔
285
{
286
   vcode_reg_array_add(&(op->args), arg);
2,714,306✔
287
}
2,714,306✔
288

289
static void vcode_add_target(op_t *op, vcode_block_t block)
121,917✔
290
{
291
   vcode_block_array_add(&(op->targets), block);
121,917✔
292
}
121,917✔
293

294
static op_t *vcode_op_data(int op)
11,088,009✔
295
{
296
   assert(active_unit != NULL);
11,088,009✔
297
   assert(active_block != VCODE_INVALID_BLOCK);
11,088,009✔
298

299
   block_t *b = &(active_unit->blocks.items[active_block]);
11,088,009✔
300
   return op_array_nth_ptr(&(b->ops), op);
11,088,009✔
301
}
302

303
static op_t *vcode_find_definition(vcode_reg_t reg)
1,200,378✔
304
{
305
   for (int i = active_block; i >= 0; i--) {
1,248,878✔
306
      block_t *b = &(active_unit->blocks.items[i]);
1,245,906✔
307
      for (int j = b->ops.count - 1; j >= 0; j--) {
16,266,418✔
308
         if (b->ops.items[j].result == reg)
16,217,918✔
309
            return &(b->ops.items[j]);
1,197,406✔
310
      }
311
   }
312

313
   return NULL;
314
}
315

316
#ifdef DEBUG
317
static void vcode_assert_const(vcode_reg_t reg, const char *what)
1,171,294✔
318
{
319
   op_t *defn = vcode_find_definition(reg);
1,171,294✔
320
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
1,171,294✔
321
                what, reg);
322
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
1,171,294✔
323
                || defn->kind == VCODE_OP_CONST_REAL
324
                || defn->kind == VCODE_OP_CONST_RECORD
325
                || defn->kind == VCODE_OP_CONST_ARRAY
326
                || defn->kind == VCODE_OP_CONST_REP
327
                || defn->kind == VCODE_OP_NULL
328
                || defn->kind == VCODE_OP_UNDEFINED,
329
                "constant %s argument r%d is not constant", what, reg);
330
}
1,171,294✔
331
#endif
332

333
static reg_t *vcode_reg_data(vcode_reg_t reg)
6,716,239✔
334
{
335
   assert(active_unit != NULL);
6,716,239✔
336
   assert(reg != VCODE_INVALID_REG);
6,716,239✔
337
   return reg_array_nth_ptr(&(active_unit->regs), reg);
6,716,239✔
338
}
339

340
static vtype_t *vcode_type_data(vcode_type_t type)
70,134,654✔
341
{
342
   assert(type != VCODE_INVALID_TYPE);
70,134,654✔
343
   assert(active_unit != NULL);
70,134,654✔
344
   vcode_unit_t unit = active_unit;
70,134,654✔
345

346
   int depth = MASK_CONTEXT(type);
70,134,654✔
347
   assert(depth <= unit->depth);
70,134,654✔
348
   while (depth != unit->depth)
71,774,398✔
349
      unit = unit->context;
1,639,744✔
350

351
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
70,134,654✔
352
}
353

354
static var_t *vcode_var_data(vcode_var_t var)
332,245✔
355
{
356
   assert(active_unit != NULL);
332,245✔
357
   assert(var != VCODE_INVALID_VAR);
332,245✔
358

359
   return var_array_nth_ptr(&(active_unit->vars), var);
332,245✔
360
}
361

362
void vcode_heap_allocate(vcode_reg_t reg)
20,170✔
363
{
364
   op_t *defn = vcode_find_definition(reg);
29,084✔
365
   if (defn == NULL) {
29,084✔
366
      // It is always safe to return a pointer to an argument
367
      return;
368
   }
369

370
   switch (defn->kind) {
26,112✔
371
   case VCODE_OP_CONST:
372
   case VCODE_OP_CONST_REAL:
373
   case VCODE_OP_CONST_ARRAY:
374
   case VCODE_OP_CONST_REP:
375
   case VCODE_OP_NULL:
376
   case VCODE_OP_UNDEFINED:
377
   case VCODE_OP_ADDRESS_OF:
378
   case VCODE_OP_LINK_VAR:
379
   case VCODE_OP_LINK_PACKAGE:
380
   case VCODE_OP_CONTEXT_UPREF:
381
   case VCODE_OP_PACKAGE_INIT:
382
   case VCODE_OP_BIND_EXTERNAL:
383
      break;
384

385
   case VCODE_OP_ALLOC:
386
   case VCODE_OP_REFLECT_SUBTYPE:
387
   case VCODE_OP_REFLECT_VALUE:
388
      // Always allocated in mspace
389
      break;
390

391
   case VCODE_OP_INDEX:
1,136✔
392
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,136✔
393
      active_unit->flags |= UNIT_ESCAPING_TLAB;
1,136✔
394
      break;
1,136✔
395

396
   case VCODE_OP_VAR_UPREF:
787✔
397
      {
398
         vcode_unit_t vu = vcode_active_unit();
787✔
399
         for (int i = 0; i < defn->hops; i++)
1,577✔
400
            vu = vcode_unit_context(vu);
790✔
401

402
         vcode_state_t state;
787✔
403
         vcode_state_save(&state);
787✔
404

405
         vcode_select_unit(vu);
787✔
406

407
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
787✔
408
         active_unit->flags |= UNIT_ESCAPING_TLAB;
787✔
409

410
         vcode_state_restore(&state);
787✔
411
      }
412
      break;
787✔
413

414
   case VCODE_OP_ARRAY_REF:
159✔
415
      vcode_heap_allocate(defn->args.items[0]);
159✔
416
      break;
159✔
417

418
   case VCODE_OP_WRAP:
7,988✔
419
   case VCODE_OP_UNWRAP:
420
   case VCODE_OP_RESOLVED:
421
      vcode_heap_allocate(defn->args.items[0]);
7,988✔
422
      break;
7,988✔
423

424
   case VCODE_OP_LAST_VALUE:
425
      // Returns a pointer into the C heap
426
      break;
427

428
   case VCODE_OP_LOAD:
1,892✔
429
      {
430
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
1,892✔
431
            return;
432

433
         // Any store to this variable must be heap allocated
434
         for (int i = 0; i < active_unit->blocks.count; i++) {
21,958✔
435
            block_t *b = &(active_unit->blocks.items[i]);
20,312✔
436
            for (int j = 0; j < b->ops.count; j++) {
280,821✔
437
               op_t *op = &(b->ops.items[j]);
260,509✔
438
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
260,509✔
439
                  vcode_heap_allocate(op->args.items[0]);
1,646✔
440

441
               VCODE_ASSERT(
260,509✔
442
                  op->kind != VCODE_OP_INDEX || op->address != defn->address,
443
                  "cannot heap allocate aliased pointer r%d", reg);
444
            }
445
         }
446
      }
447
      break;
448

449
   case VCODE_OP_FCALL:
450
      for (int i = 0; i < defn->args.count; i++) {
11,383✔
451
         const vtype_kind_t rkind = vcode_reg_kind(reg);
8,642✔
452
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
8,642✔
453
            // Function may return a pointer to its argument
454
            vcode_heap_allocate(defn->args.items[i]);
8,433✔
455
         }
456
      }
457
      break;
458

459
   case VCODE_OP_RECORD_REF:
24✔
460
      vcode_heap_allocate(defn->args.items[0]);
24✔
461
      break;
24✔
462

463
   case VCODE_OP_SELECT:
516✔
464
      vcode_heap_allocate(defn->args.items[1]);
516✔
465
      vcode_heap_allocate(defn->args.items[2]);
516✔
466
      break;
516✔
467

468
   case VCODE_OP_LOAD_INDIRECT:
247✔
469
      {
470
         // Always OK if scalar otherwise check the pointer source
471
         const vtype_kind_t vtkind = vcode_reg_kind(reg);
247✔
472
         if (vtkind != VCODE_TYPE_INT && vtkind != VCODE_TYPE_REAL)
247✔
473
            vcode_heap_allocate(defn->args.items[0]);
227✔
474
      }
475
      break;
476

477
   case VCODE_OP_ALL:
478
      // Must have been allocated on the heap
479
      break;
480

481
   case VCODE_OP_NEW:
482
      // On the heap by definition
483
      break;
484

485
   case VCODE_OP_SUB:
486
   case VCODE_OP_MUL:
487
   case VCODE_OP_DIV:
488
   case VCODE_OP_CAST:
489
   case VCODE_OP_CMP:
490
   case VCODE_OP_OR:
491
   case VCODE_OP_NOT:
492
   case VCODE_OP_AND:
493
   case VCODE_OP_NOR:
494
   case VCODE_OP_NAND:
495
   case VCODE_OP_XOR:
496
   case VCODE_OP_XNOR:
497
   case VCODE_OP_EVENT:
498
   case VCODE_OP_ACTIVE:
499
   case VCODE_OP_UARRAY_LEN:
500
   case VCODE_OP_UARRAY_LEFT:
501
   case VCODE_OP_UARRAY_RIGHT:
502
   case VCODE_OP_UARRAY_DIR:
503
   case VCODE_OP_LAST_EVENT:
504
   case VCODE_OP_NEG:
505
   case VCODE_OP_EXP:
506
   case VCODE_OP_ABS:
507
   case VCODE_OP_MOD:
508
   case VCODE_OP_REM:
509
   case VCODE_OP_ADD:
510
   case VCODE_OP_TRAP_ADD:
511
   case VCODE_OP_TRAP_SUB:
512
   case VCODE_OP_TRAP_MUL:
513
   case VCODE_OP_TRAP_NEG:
514
   case VCODE_OP_TRAP_EXP:
515
      // Result cannot reference pointer
516
      break;
517

518
   default:
519
      VCODE_ASSERT(false, "cannot heap allocate r%d", reg);
×
520
   }
521
}
522

523
void vcode_state_save(vcode_state_t *state)
90,140✔
524
{
525
   state->unit  = active_unit;
90,140✔
526
   state->block = active_block;
90,140✔
527
}
90,140✔
528

529
void vcode_state_restore(const vcode_state_t *state)
90,140✔
530
{
531
   active_unit  = state->unit;
90,140✔
532
   active_block = state->block;
90,140✔
533
}
90,140✔
534

535
void vcode_unit_unref(vcode_unit_t unit)
44,123✔
536
{
537
   assert(unit != NULL);
44,123✔
538

539
   if (unit == active_unit)
44,123✔
540
      vcode_close();
12,211✔
541

542
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
56,688✔
543
      assert(it->context == unit);
12,565✔
544
      it->context = NULL;
12,565✔
545
   }
546
   unit->children = NULL;
44,123✔
547

548
   if (unit->context != NULL) {
44,123✔
549
      vcode_unit_t *it = &(unit->context->children);
14,831✔
550
      for (; *it != NULL && *it != unit; it = &((*it)->next))
295,262✔
551
         ;
552
      assert(*it != NULL);
14,831✔
553
      *it = (*it)->next;
14,831✔
554
   }
555

556
   for (unsigned i = 0; i < unit->blocks.count; i++) {
181,829✔
557
      block_t *b = &(unit->blocks.items[i]);
137,706✔
558

559
      for (unsigned j = 0; j < b->ops.count; j++) {
1,686,817✔
560
         op_t *o = &(b->ops.items[j]);
1,549,111✔
561
         if (OP_HAS_COMMENT(o->kind))
1,549,111✔
562
            free(o->comment);
115,571✔
563
         if (OP_HAS_TARGET(o->kind))
1,549,111✔
564
            free(o->targets.items);
84,294✔
565
         free(o->args.items);
1,549,111✔
566
      }
567
      free(b->ops.items);
137,706✔
568
   }
569
   free(unit->blocks.items);
44,123✔
570

571
   for (unsigned i = 0; i < unit->types.count; i++) {
574,047✔
572
      vtype_t *vt = &(unit->types.items[i]);
529,924✔
573
      if (vt->kind == VCODE_TYPE_RECORD)
529,924✔
574
         free(vt->fields.items);
5,555✔
575
   }
576
   free(unit->types.items);
44,123✔
577

578
   free(unit->regs.items);
44,123✔
579
   free(unit->vars.items);
44,123✔
580
   free(unit->params.items);
44,123✔
581
   free(unit);
44,123✔
582
}
44,123✔
583

584
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
24,394✔
585
{
586
   return unit->next;
24,394✔
587
}
588

589
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
22,060✔
590
{
591
   return unit->children;
22,060✔
592
}
593

594
int vcode_count_regs(void)
41,993✔
595
{
596
   assert(active_unit != NULL);
41,993✔
597
   return active_unit->regs.count;
41,993✔
598
}
599

600
vcode_type_t vcode_reg_type(vcode_reg_t reg)
4,634,629✔
601
{
602
   return vcode_reg_data(reg)->type;
4,634,629✔
603
}
604

605
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,155,175✔
606
{
607
   return vtype_kind(vcode_reg_type(reg));
1,155,175✔
608
}
609

610
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
217,778✔
611
{
612
   return vcode_reg_data(reg)->bounds;
217,778✔
613
}
614

615
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
703,264✔
616
{
617
   reg_t *r = vcode_reg_data(reg);
703,264✔
618

619
   vtype_kind_t kind = vtype_kind(r->type);
703,264✔
620
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
703,264✔
621
      return false;
622

623
   vtype_t *bounds = vcode_type_data(r->bounds);
686,343✔
624

625
   VCODE_ASSERT(
686,343✔
626
      bounds->kind == VCODE_TYPE_INT || bounds->kind == VCODE_TYPE_OFFSET,
627
      "integer register r%d has non-integer bounds", reg);
628

629
   if (bounds->low == bounds->high) {
686,343✔
630
      if (value) *value = bounds->low;
364,419✔
631
      return true;
364,419✔
632
   }
633
   else
634
      return false;
635
}
636

637
void vcode_opt(void)
44,132✔
638
{
639
   // Prune assignments to unused registers
640

641
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
88,264✔
642

643
   int pruned = 0;
44,132✔
644
   do {
60,024✔
645
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
60,024✔
646
      pruned = 0;
60,024✔
647

648
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
284,400✔
649
         block_t *b = &(active_unit->blocks.items[i]);
224,376✔
650

651
         for (int j = b->ops.count - 1; j >= 0; j--) {
3,061,934✔
652
            op_t *o = &(b->ops.items[j]);
2,837,558✔
653

654
            switch (o->kind) {
2,837,558✔
655
            case VCODE_OP_FCALL:
58,873✔
656
               if (o->result == VCODE_INVALID_REG)
58,873✔
657
                  break;
658
            case VCODE_OP_CONST:
659
            case VCODE_OP_CONST_REAL:
660
            case VCODE_OP_CONST_ARRAY:
661
            case VCODE_OP_CONST_RECORD:
662
            case VCODE_OP_CONST_REP:
663
            case VCODE_OP_LOAD:
664
            case VCODE_OP_LOAD_INDIRECT:
665
            case VCODE_OP_VAR_UPREF:
666
            case VCODE_OP_ADD:
667
            case VCODE_OP_ARRAY_REF:
668
            case VCODE_OP_SUB:
669
            case VCODE_OP_MUL:
670
            case VCODE_OP_CMP:
671
            case VCODE_OP_INDEX:
672
            case VCODE_OP_WRAP:
673
            case VCODE_OP_EXP:
674
            case VCODE_OP_UNDEFINED:
675
            case VCODE_OP_UARRAY_LEN:
676
            case VCODE_OP_UARRAY_DIR:
677
            case VCODE_OP_UARRAY_LEFT:
678
            case VCODE_OP_UARRAY_RIGHT:
679
            case VCODE_OP_UNWRAP:
680
            case VCODE_OP_NULL:
681
            case VCODE_OP_ADDRESS_OF:
682
            case VCODE_OP_RANGE_NULL:
683
            case VCODE_OP_RANGE_LENGTH:
684
            case VCODE_OP_DEBUG_LOCUS:
685
            case VCODE_OP_SELECT:
686
            case VCODE_OP_CAST:
687
            case VCODE_OP_RESOLVED:
688
            case VCODE_OP_TRAP_ADD:
689
            case VCODE_OP_TRAP_SUB:
690
            case VCODE_OP_TRAP_MUL:
691
            case VCODE_OP_TRAP_EXP:
692
            case VCODE_OP_ALLOC:
693
            case VCODE_OP_FUNCTION_TRIGGER:
694
            case VCODE_OP_CMP_TRIGGER:
695
            case VCODE_OP_OR_TRIGGER:
696
               if (uses[o->result] == -1) {
1,866,980✔
697
                  vcode_dump_with_mark(j, NULL, NULL);
×
698
                  fatal_trace("definition of r%d does not dominate all uses",
699
                              o->result);
700
               }
701
               else if (uses[o->result] == 0) {
1,866,980✔
702
                  if (false DEBUG_ONLY(|| o->kind != VCODE_OP_CONST)) {
146,940✔
703
                     o->comment = xasprintf("Dead %s definition of r%d",
71,340✔
704
                                            vcode_op_string(o->kind),
705
                                            o->result);
706
                     o->kind = VCODE_OP_COMMENT;
71,340✔
707
                  }
708
                  else
709
                     o->kind = (vcode_op_t)-1;
75,600✔
710
                  vcode_reg_array_resize(&(o->args), 0, VCODE_INVALID_REG);
146,940✔
711
                  pruned++;
146,940✔
712
               }
713
               uses[o->result] = -1;
1,866,980✔
714
               break;
1,866,980✔
715

716
            default:
717
               break;
718
            }
719

720
            for (int k = 0; k < o->args.count; k++) {
7,694,239✔
721
               if (o->args.items[k] != VCODE_INVALID_REG)
4,856,681✔
722
                  uses[o->args.items[k]]++;
4,810,663✔
723
            }
724
         }
725
      }
726
   } while (pruned > 0);
60,024✔
727

728
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
181,859✔
729
      block_t *b = &(active_unit->blocks.items[i]);
137,727✔
730
      op_t *dst = &(b->ops.items[0]);
137,727✔
731
      size_t copied = 0;
137,727✔
732
      for (int j = 0; j < b->ops.count; j++) {
1,762,804✔
733
         const op_t *src = &(b->ops.items[j]);
1,625,077✔
734
         if (src->kind != (vcode_op_t)-1) {
1,625,077✔
735
            if (src != dst) {
1,549,477✔
736
               assert(dst < src);
426,013✔
737
               *dst = *src;
426,013✔
738
            }
739
            dst++;
1,549,477✔
740
            copied++;
1,549,477✔
741
         }
742
      }
743

744
      assert(copied <= b->ops.count);
137,727✔
745
      b->ops.count = copied;
137,727✔
746
   }
747
}
44,132✔
748

749
void vcode_close(void)
30,999✔
750
{
751
   active_unit  = NULL;
30,999✔
752
   active_block = -1;
30,999✔
753
}
30,999✔
754

755
int vcode_count_blocks(void)
117,183✔
756
{
757
   assert(active_unit != NULL);
117,183✔
758
   return active_unit->blocks.count;
117,183✔
759
}
760

761
int vcode_count_ops(void)
415,885✔
762
{
763
   assert(active_unit != NULL);
415,885✔
764
   assert(active_block != VCODE_INVALID_BLOCK);
415,885✔
765
   return active_unit->blocks.items[active_block].ops.count;
415,885✔
766
}
767

768
int vcode_count_vars(void)
83,999✔
769
{
770
   assert(active_unit != NULL);
83,999✔
771
   return active_unit->vars.count;
83,999✔
772
}
773

774
vcode_var_t vcode_find_var(ident_t name)
12✔
775
{
776
   assert(active_unit != NULL);
12✔
777
   for (int i = 0; i < active_unit->vars.count; i++) {
24✔
778
      if (active_unit->vars.items[i].name == name)
12✔
779
         return i;
×
780
   }
781

782
   return VCODE_INVALID_VAR;
783
}
784

785
ident_t vcode_var_name(vcode_var_t var)
38,498✔
786
{
787
   return vcode_var_data(var)->name;
38,498✔
788
}
789

790
vcode_type_t vcode_var_type(vcode_var_t var)
144,193✔
791
{
792
   return vcode_var_data(var)->type;
144,193✔
793
}
794

795
vcode_type_t vcode_var_bounds(vcode_var_t var)
3,752✔
796
{
797
   return vcode_var_data(var)->bounds;
3,752✔
798
}
799

800
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
37,271✔
801
{
802
   return vcode_var_data(var)->flags;
37,271✔
803
}
804

805
vcode_op_t vcode_get_op(int op)
4,446,507✔
806
{
807
   return vcode_op_data(op)->kind;
4,446,507✔
808
}
809

810
ident_t vcode_get_func(int op)
108,172✔
811
{
812
   op_t *o = vcode_op_data(op);
108,172✔
813
   assert(OP_HAS_FUNC(o->kind));
108,172✔
814
   return o->func;
108,172✔
815
}
816

817
ident_t vcode_get_ident(int op)
86,899✔
818
{
819
   op_t *o = vcode_op_data(op);
86,899✔
820
   assert(OP_HAS_IDENT(o->kind));
86,899✔
821
   return o->ident;
86,899✔
822
}
823

824
int64_t vcode_get_value(int op)
375,991✔
825
{
826
   op_t *o = vcode_op_data(op);
375,991✔
827
   assert(OP_HAS_VALUE(o->kind));
375,991✔
828
   return o->value;
375,991✔
829
}
830

831
double vcode_get_real(int op)
20,701✔
832
{
833
   op_t *o = vcode_op_data(op);
20,701✔
834
   assert(OP_HAS_REAL(o->kind));
20,701✔
835
   return o->real;
20,701✔
836
}
837

838
vcode_var_t vcode_get_address(int op)
147,845✔
839
{
840
   op_t *o = vcode_op_data(op);
147,845✔
841
   assert(OP_HAS_ADDRESS(o->kind));
147,845✔
842
   return o->address;
147,845✔
843
}
844

845
unsigned vcode_get_dim(int op)
69,316✔
846
{
847
   op_t *o = vcode_op_data(op);
69,316✔
848
   assert(OP_HAS_DIM(o->kind));
69,316✔
849
   return o->dim;
69,316✔
850
}
851

852
int vcode_get_hops(int op)
61,377✔
853
{
854
   op_t *o = vcode_op_data(op);
61,377✔
855
   assert(OP_HAS_HOPS(o->kind));
61,377✔
856
   return o->hops;
61,377✔
857
}
858

859
int vcode_get_field(int op)
35,496✔
860
{
861
   op_t *o = vcode_op_data(op);
35,496✔
862
   assert(OP_HAS_FIELD(o->kind));
35,496✔
863
   return o->field;
35,496✔
864
}
865

866
vcode_var_t vcode_get_type(int op)
18,069✔
867
{
868
   op_t *o = vcode_op_data(op);
18,069✔
869
   assert(OP_HAS_TYPE(o->kind));
18,069✔
870
   return o->type;
18,069✔
871
}
872

873
int vcode_count_args(int op)
191,182✔
874
{
875
   return vcode_op_data(op)->args.count;
191,182✔
876
}
877

878
vcode_reg_t vcode_get_arg(int op, int arg)
2,788,103✔
879
{
880
   op_t *o = vcode_op_data(op);
2,788,103✔
881
   return vcode_reg_array_nth(&(o->args), arg);
2,788,103✔
882
}
883

884
vcode_reg_t vcode_get_result(int op)
1,121,952✔
885
{
886
   op_t *o = vcode_op_data(op);
1,121,952✔
887
   return o->result;
1,121,952✔
888
}
889

890
vcode_cmp_t vcode_get_cmp(int op)
33,262✔
891
{
892
   op_t *o = vcode_op_data(op);
33,262✔
893
   assert(OP_HAS_CMP(o->kind));
33,262✔
894
   return o->cmp;
33,262✔
895
}
896

897
uint32_t vcode_get_tag(int op)
2,626✔
898
{
899
   op_t *o = vcode_op_data(op);
2,626✔
900
   assert(OP_HAS_TAG(o->kind));
2,626✔
901
   return o->tag;
2,626✔
902
}
903

904
const loc_t *vcode_get_loc(int op)
1,434,634✔
905
{
906
   op_t *o = vcode_op_data(op);
1,434,634✔
907
   return &(o->loc);
1,434,634✔
908
}
909

910
vcode_block_t vcode_get_target(int op, int nth)
145,877✔
911
{
912
   op_t *o = vcode_op_data(op);
145,877✔
913
   assert(OP_HAS_TARGET(o->kind));
145,877✔
914
   return vcode_block_array_nth(&(o->targets), nth);
145,877✔
915
}
916

917
bool vcode_block_empty(void)
×
918
{
919
   assert(active_unit != NULL);
×
920
   assert(active_block != VCODE_INVALID_BLOCK);
×
921

922
   return active_unit->blocks.items[active_block].ops.count == 0;
×
923
}
924

925
bool vcode_block_finished(void)
1,729,709✔
926
{
927
   assert(active_unit != NULL);
1,729,709✔
928
   assert(active_block != VCODE_INVALID_BLOCK);
1,729,709✔
929

930
   const block_t *b = &(active_unit->blocks.items[active_block]);
1,729,709✔
931
   if (b->ops.count == 0)
1,729,709✔
932
      return false;
933
   else {
934
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
1,548,004✔
935
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
1,548,004✔
936
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
1,547,980✔
937
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
938
         || kind == VCODE_OP_UNREACHABLE;
3,095,984✔
939
   }
940
}
941

942
const char *vcode_op_string(vcode_op_t op)
71,340✔
943
{
944
   static const char *strs[] = {
71,340✔
945
      "cmp", "fcall", "wait", "const", "assert", "jump", "load", "store",
946
      "mul", "add", "comment", "const array", "index", "sub", "cast",
947
      "load indirect", "store indirect", "return", "sched waveform",
948
      "cond", "report", "div", "neg", "exp", "abs", "mod", "rem", "alloc",
949
      "select", "or", "wrap", "uarray left", "uarray right", "uarray dir",
950
      "unwrap", "not", "and", "event", "active", "const record", "record ref",
951
      "copy", "sched event", "pcall", "resume", "xor", "xnor", "nand", "nor",
952
      "memset", "case", "file open", "file write",
953
      "file read", "null", "new", "null check", "deallocate", "all",
954
      "const real", "last event", "debug out", "cover stmt", "cover branch",
955
      "cover toggle", "cover expr", "cover state", "uarray len", "undefined",
956
      "range null", "var upref", "resolved", "last value", "init signal",
957
      "map signal", "drive signal", "link var", "resolution wrapper",
958
      "last active", "driving", "driving value", "address of", "closure",
959
      "protected init", "context upref", "const rep", "protected free",
960
      "implicit signal", "disconnect", "link package",
961
      "index check", "debug locus", "length check", "range check", "array ref",
962
      "range length", "exponent check", "zero check", "map const",
963
      "resolve signal", "package scope", "pop scope", "alias signal",
964
      "trap add", "trap sub", "trap mul", "force", "release",
965
      "unreachable", "package init", "trap neg", "process init", "clear event",
966
      "trap exp", "enter state", "reflect value", "reflect subtype",
967
      "function trigger", "add trigger", "transfer signal",
968
      "port conversion", "convert in", "convert out", "bind foreign",
969
      "or trigger", "cmp trigger", "instance name", "deposit signal",
970
      "map implicit", "bind external", "array scope", "record scope", "syscall",
971
   };
972
   if ((unsigned)op >= ARRAY_LEN(strs))
71,340✔
973
      return "???";
974
   else
975
      return strs[op];
71,340✔
976
}
977

978
LCOV_EXCL_START
979
static int vcode_dump_reg(vcode_reg_t reg)
980
{
981
   if (reg == VCODE_INVALID_REG)
982
      return color_printf("$red$invalid$$");
983
   else
984
      return color_printf("$green$r%d$$", reg);
985
}
986

987
static int vcode_pretty_print_int(int64_t n)
988
{
989
   if (n == INT64_MAX)
990
      return printf("2^63-1");
991
   else if (n == INT64_MIN)
992
      return printf("-2^63");
993
   else if (n == INT32_MAX)
994
      return printf("2^31-1");
995
   else if (n == INT32_MIN)
996
      return printf("-2^31");
997
   else
998
      return printf("%"PRIi64, n);
999
}
1000

1001
static int vcode_dump_one_type(vcode_type_t type)
1002
{
1003
   int col = 0;
1004
   vtype_t *vt = vcode_type_data(type);
1005
   switch (vt->kind) {
1006
   case VCODE_TYPE_INT:
1007
      if (vt->low != vt->high) {
1008
         col += vcode_pretty_print_int(vt->low);
1009
         col += printf("..");
1010
         col += vcode_pretty_print_int(vt->high);
1011
      }
1012
      else
1013
         col += vcode_pretty_print_int(vt->low);
1014
      break;
1015

1016
   case VCODE_TYPE_REAL:
1017
      if (vt->rlow == -DBL_MAX && vt->rhigh == DBL_MAX)
1018
         col += printf("%%");
1019
      else if (vt->rlow == vt->rhigh)
1020
         col += printf("%f", vt->rlow);
1021
      else
1022
         col += printf("%f..%f", vt->rlow, vt->rhigh);
1023
      break;
1024

1025
   case VCODE_TYPE_CARRAY:
1026
      {
1027
         col += printf("[%u] : ", vt->size);
1028
         col += vcode_dump_one_type(vt->elem);
1029
         if (!vtype_eq(vt->elem, vt->bounds)) {
1030
            col += printf(" => ");
1031
            col += vcode_dump_one_type(vt->bounds);
1032
         }
1033
      }
1034
      break;
1035

1036
   case VCODE_TYPE_UARRAY:
1037
      {
1038
         col += printf("[");
1039
         for (unsigned i = 0; i < vt->dims; i++)
1040
            col += printf("%s*", i > 0 ? ", " : "");
1041
         col += printf("] : ");
1042
         col += vcode_dump_one_type(vt->elem);
1043
         if (!vtype_eq(vt->elem, vt->bounds)) {
1044
            col += printf(" => ");
1045
            col += vcode_dump_one_type(vt->bounds);
1046
         }
1047
      }
1048
      break;
1049

1050
   case VCODE_TYPE_POINTER:
1051
      col += printf("@<");
1052
      col += vcode_dump_one_type(vt->pointed);
1053
      col += printf(">");
1054
      break;
1055

1056
   case VCODE_TYPE_ACCESS:
1057
      col += printf("A<");
1058
      col += vcode_dump_one_type(vt->pointed);
1059
      col += printf(">");
1060
      break;
1061

1062
   case VCODE_TYPE_SIGNAL:
1063
      col += printf("$<");
1064
      col += vcode_dump_one_type(vt->base);
1065
      col += printf(">");
1066
      break;
1067

1068
   case VCODE_TYPE_OFFSET:
1069
      col += printf("#");
1070
      break;
1071

1072
   case VCODE_TYPE_RECORD:
1073
      col += printf("%s{}", istr(vt->name));
1074
      break;
1075

1076
   case VCODE_TYPE_FILE:
1077
      col += printf("F<");
1078
      col += vcode_dump_one_type(vt->base);
1079
      col += printf(">");
1080
      break;
1081

1082
   case VCODE_TYPE_OPAQUE:
1083
      col += printf("?");
1084
      break;
1085

1086
   case VCODE_TYPE_RESOLUTION:
1087
      col += printf("R<");
1088
      col += vcode_dump_one_type(vt->base);
1089
      col += printf(">");
1090
      break;
1091

1092
   case VCODE_TYPE_CLOSURE:
1093
      col += printf("C<");
1094
      col += vcode_dump_one_type(vt->base);
1095
      col += printf(">");
1096
      break;
1097

1098
   case VCODE_TYPE_CONTEXT:
1099
      col += printf("P<%s>", istr(vt->name));
1100
      break;
1101

1102
   case VCODE_TYPE_DEBUG_LOCUS:
1103
      col += printf("D<>");
1104
      break;
1105

1106
   case VCODE_TYPE_TRIGGER:
1107
      col += printf("T<>");
1108
      break;
1109

1110
   case VCODE_TYPE_CONVERSION:
1111
      col += printf("X<>");
1112
      break;
1113
   }
1114

1115
   return col;
1116
}
1117

1118
static void vcode_dump_tab(int col, int to_col)
1119
{
1120
   if (col >= to_col)
1121
      printf(" ");
1122
   else {
1123
      while (col < to_col)
1124
         col += printf(" ");
1125
   }
1126
}
1127

1128
static void vcode_dump_comment(int col)
1129
{
1130
   vcode_dump_tab(col, 40);
1131
   color_printf("$cyan$// ");
1132
}
1133

1134
static void vcode_dump_type(int col, vcode_type_t type, vcode_type_t bounds)
1135
{
1136
   vcode_dump_comment(col);
1137
   vcode_dump_one_type(type);
1138
   if (!vtype_eq(type, bounds)) {
1139
      printf(" => ");
1140
      vcode_dump_one_type(bounds);
1141
   }
1142
}
1143

1144
static void vcode_dump_result_type(int col, const op_t *op)
1145
{
1146
   if (op->result != VCODE_INVALID_REG) {
1147
      reg_t *r = vcode_reg_data(op->result);
1148
      vcode_dump_type(col, r->type, r->bounds);
1149
   }
1150
}
1151

1152
static int vcode_dump_var(vcode_var_t var, int hops)
1153
{
1154
   vcode_unit_t owner = active_unit;
1155
   while (owner && hops--)
1156
      owner = owner->context;
1157

1158
   if (owner == NULL || var >= owner->vars.count)
1159
      return color_printf("$red$invalid$$");
1160
   else {
1161
      var_t *v = var_array_nth_ptr(&(owner->vars), var);
1162
      return color_printf("$magenta$%s$$", istr(v->name));
1163
   }
1164
}
1165

1166
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1167
{
1168
   assert(active_unit != NULL);
1169

1170
   const vcode_unit_t vu = active_unit;
1171
   vcode_block_t old_block = active_block;
1172

1173
   printf("\n");
1174
   if (vu->name != NULL)
1175
      color_printf("Name       $cyan$%s$$\n", istr(vu->name));
1176
   color_printf("Kind       $cyan$");
1177
   switch (vu->kind) {
1178
   case VCODE_UNIT_PROCESS:   printf("process"); break;
1179
   case VCODE_UNIT_FUNCTION:  printf("function"); break;
1180
   case VCODE_UNIT_PROCEDURE: printf("procedure"); break;
1181
   case VCODE_UNIT_INSTANCE:  printf("instance"); break;
1182
   case VCODE_UNIT_THUNK:     printf("thunk"); break;
1183
   case VCODE_UNIT_PACKAGE:   printf("package"); break;
1184
   case VCODE_UNIT_PROTECTED: printf("protected"); break;
1185
   case VCODE_UNIT_PROPERTY:  printf("property"); break;
1186
   case VCODE_UNIT_SHAPE:     printf("shape"); break;
1187
   }
1188
   color_printf("$$\n");
1189
   if (vu->context != NULL)
1190
      color_printf("Context    $cyan$%s$$\n", istr(vu->context->name));
1191
   printf("Blocks     %d\n", vu->blocks.count);
1192
   printf("Registers  %d\n", vu->regs.count);
1193
   printf("Types      %d\n", vu->types.count);
1194

1195
   for (int i = 0; i < vu->types.count; i++) {
1196
      const vtype_t *t = &(vu->types.items[i]);
1197
      if (t->kind == VCODE_TYPE_RECORD) {
1198
         int col = 0;
1199
         col += color_printf("  $magenta$%s$$", istr(t->name));
1200
         vcode_dump_tab(col, 40);
1201
         color_printf("$cyan${");
1202
         for (unsigned i = 0; i < t->fields.count; i++) {
1203
            if (i > 0)
1204
               printf(", ");
1205
            vcode_dump_one_type(t->fields.items[i]);
1206
         }
1207
         color_printf("}$$\n");
1208
      }
1209
   }
1210

1211
   printf("Variables  %d\n", vu->vars.count);
1212

1213
   for (int i = 0; i < vu->vars.count; i++) {
1214
      const var_t *v = &(vu->vars.items[i]);
1215
      int col = printf("  ");
1216
      col += color_printf("$magenta$%s$$", istr(v->name));
1217
      vcode_dump_type(col, v->type, v->bounds);
1218
      if (v->flags & VAR_SIGNAL)
1219
         col += printf(", signal");
1220
      if (v->flags & VAR_HEAP)
1221
         col += printf(", heap");
1222
      if (v->flags & VAR_CONST)
1223
         col += printf(", constant");
1224
      if (v->flags & VAR_TEMP)
1225
         col += printf(", temp");
1226
      color_printf("$$\n");
1227
   }
1228

1229
   if (vu->result != VCODE_INVALID_TYPE) {
1230
      color_printf("Result     $cyan$");
1231
      vcode_dump_one_type(vu->result);
1232
      color_printf("$$\n");
1233
   }
1234

1235
   if (vu->kind == VCODE_UNIT_FUNCTION
1236
       || vu->kind == VCODE_UNIT_PROCEDURE
1237
       || vu->kind == VCODE_UNIT_PROPERTY
1238
       || (vu->kind == VCODE_UNIT_PROTECTED && vu->params.count > 0)) {
1239

1240
      printf("Parameters %d\n", vu->params.count);
1241

1242
      for (size_t i = 0; i < vu->params.count; i++) {
1243
         const param_t *p = &(vu->params.items[i]);
1244
         int col = printf("  ");
1245
         col += vcode_dump_reg(p->reg);
1246
         while (col < 8)
1247
            col += printf(" ");
1248
         col += color_printf("$magenta$%s$$", istr(p->name));
1249
         vcode_dump_type(col, p->type, p->bounds);
1250
         color_printf("$$\n");
1251
      }
1252
   }
1253

1254
   printf("Begin\n");
1255
   for (int i = 0; i < vu->blocks.count; i++) {
1256
      active_block = i;
1257
      const block_t *b = &(vu->blocks.items[i]);
1258
      for (int j = 0; j < b->ops.count; j++) {
1259
         int col = 0;
1260
         if (j == 0)
1261
            col += color_printf("  $yellow$%2d:$$ ", i);
1262
         else
1263
            col += printf("      ");
1264

1265
         const op_t *op = &(b->ops.items[j]);
1266
         switch (op->kind) {
1267
         case VCODE_OP_CMP:
1268
            {
1269
               vcode_dump_reg(op->result);
1270
               printf(" := %s ", vcode_op_string(op->kind));
1271
               vcode_dump_reg(op->args.items[0]);
1272
               switch (op->cmp) {
1273
               case VCODE_CMP_EQ:  printf(" == "); break;
1274
               case VCODE_CMP_NEQ: printf(" != "); break;
1275
               case VCODE_CMP_LT:  printf(" < "); break;
1276
               case VCODE_CMP_GT:  printf(" > "); break;
1277
               case VCODE_CMP_LEQ: printf(" <= "); break;
1278
               case VCODE_CMP_GEQ: printf(" >= "); break;
1279
               }
1280
               vcode_dump_reg(op->args.items[1]);
1281
            }
1282
            break;
1283

1284
         case VCODE_OP_CONST:
1285
            {
1286
               col += vcode_dump_reg(op->result);
1287
               col += printf(" := %s %"PRIi64"",
1288
                             vcode_op_string(op->kind),
1289
                             op->value);
1290
               vcode_dump_result_type(col, op);
1291
            }
1292
            break;
1293

1294
         case VCODE_OP_CONST_REAL:
1295
            {
1296
               col += vcode_dump_reg(op->result);
1297
               col += printf(" := %s %g",
1298
                             vcode_op_string(op->kind),
1299
                             op->real);
1300
               vcode_dump_result_type(col, op);
1301
            }
1302
            break;
1303

1304
         case VCODE_OP_ALLOC:
1305
            {
1306
               col += vcode_dump_reg(op->result);
1307
               col += printf(" := %s ", vcode_op_string(op->kind));
1308
               col += vcode_dump_reg(op->args.items[0]);
1309
               vcode_dump_result_type(col, op);
1310
            }
1311
            break;
1312

1313
         case VCODE_OP_FCALL:
1314
            {
1315
               if (op->result != VCODE_INVALID_REG) {
1316
                  col += vcode_dump_reg(op->result);
1317
                  col += printf(" := ");
1318
               }
1319
               col += color_printf("%s $magenta$%s$$ ",
1320
                                   vcode_op_string(op->kind),
1321
                                   istr(op->func));
1322
               for (int i = 0; i < op->args.count; i++) {
1323
                  if (i > 0)
1324
                     col += printf(", ");
1325
                  col += vcode_dump_reg(op->args.items[i]);
1326
               }
1327
               vcode_dump_result_type(col, op);
1328
            }
1329
            break;
1330

1331
         case VCODE_OP_SYSCALL:
1332
            {
1333
               if (op->result != VCODE_INVALID_REG) {
1334
                  col += vcode_dump_reg(op->result);
1335
                  col += printf(" := ");
1336
               }
1337
               col += color_printf("%s $magenta$%s$$ ",
1338
                                   vcode_op_string(op->kind),
1339
                                   istr(op->func));
1340
               for (int i = 1; i < op->args.count; i++) {
1341
                  if (i > 1) col += printf(", ");
1342
                  col += vcode_dump_reg(op->args.items[i]);
1343
               }
1344
               if (op->args.count > 1) col += printf(" ");
1345
               col += color_printf("locus ");
1346
               col += vcode_dump_reg(op->args.items[0]);
1347
               vcode_dump_result_type(col, op);
1348
            }
1349
            break;
1350

1351
         case VCODE_OP_MAP_CONST:
1352
         case VCODE_OP_MAP_SIGNAL:
1353
         case VCODE_OP_MAP_IMPLICIT:
1354
            {
1355
               printf("%s ", vcode_op_string(op->kind));
1356
               vcode_dump_reg(op->args.items[0]);
1357
               printf(" to ");
1358
               vcode_dump_reg(op->args.items[1]);
1359
               printf(" count ");
1360
               vcode_dump_reg(op->args.items[2]);
1361
            }
1362
            break;
1363

1364
         case VCODE_OP_DRIVE_SIGNAL:
1365
            {
1366
               printf("%s ", vcode_op_string(op->kind));
1367
               vcode_dump_reg(op->args.items[0]);
1368
               printf(" count ");
1369
               vcode_dump_reg(op->args.items[1]);
1370
            }
1371
            break;
1372

1373
         case VCODE_OP_TRANSFER_SIGNAL:
1374
            {
1375
               printf("%s ", vcode_op_string(op->kind));
1376
               vcode_dump_reg(op->args.items[0]);
1377
               printf(" to ");
1378
               vcode_dump_reg(op->args.items[1]);
1379
               printf(" count ");
1380
               vcode_dump_reg(op->args.items[2]);
1381
               printf(" reject ");
1382
               vcode_dump_reg(op->args.items[3]);
1383
               printf(" after ");
1384
               vcode_dump_reg(op->args.items[4]);
1385
            }
1386
            break;
1387

1388
         case VCODE_OP_RESOLVE_SIGNAL:
1389
            {
1390
               printf("%s ", vcode_op_string(op->kind));
1391
               vcode_dump_reg(op->args.items[0]);
1392
               printf(" resolution ");
1393
               vcode_dump_reg(op->args.items[1]);
1394
            }
1395
            break;
1396

1397
         case VCODE_OP_PACKAGE_SCOPE:
1398
         case VCODE_OP_ARRAY_SCOPE:
1399
         case VCODE_OP_RECORD_SCOPE:
1400
            {
1401
               col += printf("%s locus ", vcode_op_string(op->kind));
1402
               col += vcode_dump_reg(op->args.items[0]);
1403
               vcode_dump_type(col, op->type, op->type);
1404
            }
1405
            break;
1406

1407
         case VCODE_OP_POP_SCOPE:
1408
            {
1409
               printf("%s", vcode_op_string(op->kind));
1410
            }
1411
            break;
1412

1413
         case VCODE_OP_INIT_SIGNAL:
1414
            {
1415
               col += vcode_dump_reg(op->result);
1416
               col += printf(" := ");
1417
               col += printf("%s count ", vcode_op_string(op->kind));
1418
               col += vcode_dump_reg(op->args.items[0]);
1419
               col += printf(" size ");
1420
               col += vcode_dump_reg(op->args.items[1]);
1421
               col += printf(" value ");
1422
               col += vcode_dump_reg(op->args.items[2]);
1423
               col += printf(" flags ");
1424
               col += vcode_dump_reg(op->args.items[3]);
1425
               col += printf(" locus ");
1426
               col += vcode_dump_reg(op->args.items[4]);
1427
               if (op->args.count > 5) {
1428
                  col += printf(" offset ");
1429
                  col += vcode_dump_reg(op->args.items[5]);
1430
               }
1431
               vcode_dump_result_type(col, op);
1432
            }
1433
            break;
1434

1435
         case VCODE_OP_IMPLICIT_SIGNAL:
1436
            {
1437
               col += vcode_dump_reg(op->result);
1438
               col += printf(" := %s count ", vcode_op_string(op->kind));
1439
               col += vcode_dump_reg(op->args.items[0]);
1440
               col += printf(" size ");
1441
               col += vcode_dump_reg(op->args.items[1]);
1442
               col += printf(" locus ");
1443
               col += vcode_dump_reg(op->args.items[2]);
1444
               col += printf(" kind ");
1445
               col += vcode_dump_reg(op->args.items[3]);
1446
               col += printf(" closure ");
1447
               col += vcode_dump_reg(op->args.items[4]);
1448
            }
1449
            break;
1450

1451
         case VCODE_OP_RESOLUTION_WRAPPER:
1452
            {
1453
               col += vcode_dump_reg(op->result);
1454
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1455
               col += vcode_dump_reg(op->args.items[0]);
1456
               col += printf(" ileft ");
1457
               col += vcode_dump_reg(op->args.items[1]);
1458
               col += printf(" nlits ");
1459
               col += vcode_dump_reg(op->args.items[2]);
1460
               vcode_dump_result_type(col, op);
1461
            }
1462
            break;
1463

1464
         case VCODE_OP_CLOSURE:
1465
         case VCODE_OP_PROTECTED_INIT:
1466
            {
1467
               col += vcode_dump_reg(op->result);
1468
               col += color_printf(" := %s $magenta$%s$$ context ",
1469
                                   vcode_op_string(op->kind), istr(op->func));
1470
               col += vcode_dump_reg(op->args.items[0]);
1471
               if (op->args.count >= 3) {
1472
                  col += printf(" path " );
1473
                  col += vcode_dump_reg(op->args.items[1]);
1474
                  col += printf(" instance " );
1475
                  col += vcode_dump_reg(op->args.items[2]);
1476
               }
1477
               vcode_dump_result_type(col, op);
1478
            }
1479
            break;
1480

1481
         case VCODE_OP_PACKAGE_INIT:
1482
            {
1483
               col += vcode_dump_reg(op->result);
1484
               col += color_printf(" := %s $magenta$%s$$",
1485
                                   vcode_op_string(op->kind), istr(op->func));
1486
               if (op->args.count > 0) {
1487
                  col += printf(" context " );
1488
                  col += vcode_dump_reg(op->args.items[0]);
1489
               }
1490
               vcode_dump_result_type(col, op);
1491
            }
1492
            break;
1493

1494
         case VCODE_OP_PROCESS_INIT:
1495
            {
1496
               color_printf("%s $magenta$%s$$ locus ",
1497
                            vcode_op_string(op->kind), istr(op->func));
1498
               vcode_dump_reg(op->args.items[0]);
1499
            }
1500
            break;
1501

1502
         case VCODE_OP_PROTECTED_FREE:
1503
            {
1504
               printf("%s ", vcode_op_string(op->kind));
1505
               vcode_dump_reg(op->args.items[0]);
1506
            }
1507
            break;
1508

1509
         case VCODE_OP_WAIT:
1510
            {
1511
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1512
                            op->targets.items[0]);
1513
               if (op->args.items[0] != VCODE_INVALID_REG) {
1514
                  printf(" for ");
1515
                  vcode_dump_reg(op->args.items[0]);
1516
               }
1517
            }
1518
            break;
1519

1520
         case VCODE_OP_JUMP:
1521
            {
1522
               color_printf("%s $yellow$%d$$", vcode_op_string(op->kind),
1523
                            op->targets.items[0]);
1524
            }
1525
            break;
1526

1527
         case VCODE_OP_COND:
1528
            {
1529
               printf("%s ", vcode_op_string(op->kind));
1530
               vcode_dump_reg(op->args.items[0]);
1531
               color_printf(" then $yellow$%d$$ else $yellow$%d$$",
1532
                            op->targets.items[0], op->targets.items[1]);
1533
            }
1534
            break;
1535

1536
         case VCODE_OP_ASSERT:
1537
            {
1538
               printf("%s ", vcode_op_string(op->kind));
1539
               vcode_dump_reg(op->args.items[0]);
1540
               if (op->args.items[2] != VCODE_INVALID_REG) {
1541
                  printf(" report ");
1542
                  vcode_dump_reg(op->args.items[2]);
1543
                  printf(" length ");
1544
                  vcode_dump_reg(op->args.items[3]);
1545
               }
1546
               printf(" severity ");
1547
               vcode_dump_reg(op->args.items[1]);
1548
               printf(" locus ");
1549
               vcode_dump_reg(op->args.items[4]);
1550
               if (op->args.count > 5) {
1551
                  printf(" hint ");
1552
                  vcode_dump_reg(op->args.items[5]);
1553
                  printf(" ");
1554
                  vcode_dump_reg(op->args.items[6]);
1555
               }
1556
            }
1557
            break;
1558

1559
         case VCODE_OP_REPORT:
1560
            {
1561
               printf("%s ", vcode_op_string(op->kind));
1562
               vcode_dump_reg(op->args.items[1]);
1563
               printf(" length ");
1564
               vcode_dump_reg(op->args.items[2]);
1565
               printf(" severity ");
1566
               vcode_dump_reg(op->args.items[0]);
1567
               printf(" locus ");
1568
               vcode_dump_reg(op->args.items[3]);
1569
            }
1570
            break;
1571

1572
         case VCODE_OP_LOAD:
1573
            {
1574
               col += vcode_dump_reg(op->result);
1575
               col += printf(" := %s ", vcode_op_string(op->kind));
1576
               col += vcode_dump_var(op->address, 0);
1577
               vcode_dump_result_type(col, op);
1578
            }
1579
            break;
1580

1581
         case VCODE_OP_LOAD_INDIRECT:
1582
            {
1583
               col += vcode_dump_reg(op->result);
1584
               col += color_printf(" := %s ", vcode_op_string(op->kind));
1585
               col += vcode_dump_reg(op->args.items[0]);
1586
               vcode_dump_result_type(col, op);
1587
            }
1588
            break;
1589

1590
         case VCODE_OP_STORE:
1591
            {
1592
               vcode_dump_var(op->address, 0);
1593
               printf(" := %s ", vcode_op_string(op->kind));
1594
               vcode_dump_reg(op->args.items[0]);
1595
            }
1596
            break;
1597

1598
         case VCODE_OP_STORE_INDIRECT:
1599
            {
1600
               vcode_dump_reg(op->args.items[1]);
1601
               printf(" := %s ", vcode_op_string(op->kind));
1602
               vcode_dump_reg(op->args.items[0]);
1603
            }
1604
            break;
1605

1606
         case VCODE_OP_INDEX:
1607
            {
1608
               col += vcode_dump_reg(op->result);
1609
               col += printf(" := %s ", vcode_op_string(op->kind));
1610
               col += vcode_dump_var(op->address, 0);
1611
               if (op->args.count > 0) {
1612
                  col += printf(" + ");
1613
                  col += vcode_dump_reg(op->args.items[0]);
1614
               }
1615
               vcode_dump_result_type(col, op);
1616
            }
1617
            break;
1618

1619
         case VCODE_OP_MUL:
1620
         case VCODE_OP_ADD:
1621
         case VCODE_OP_SUB:
1622
         case VCODE_OP_DIV:
1623
         case VCODE_OP_EXP:
1624
         case VCODE_OP_MOD:
1625
         case VCODE_OP_REM:
1626
         case VCODE_OP_OR:
1627
         case VCODE_OP_AND:
1628
         case VCODE_OP_XOR:
1629
         case VCODE_OP_XNOR:
1630
         case VCODE_OP_NAND:
1631
         case VCODE_OP_NOR:
1632
            {
1633
               col += vcode_dump_reg(op->result);
1634
               col += printf(" := %s ", vcode_op_string(op->kind));
1635
               col += vcode_dump_reg(op->args.items[0]);
1636
               switch (op->kind) {
1637
               case VCODE_OP_MUL:  col += printf(" * "); break;
1638
               case VCODE_OP_ADD:  col += printf(" + "); break;
1639
               case VCODE_OP_SUB:  col += printf(" - "); break;
1640
               case VCODE_OP_DIV:  col += printf(" / "); break;
1641
               case VCODE_OP_EXP:  col += printf(" ** "); break;
1642
               case VCODE_OP_MOD:  col += printf(" %% "); break;
1643
               case VCODE_OP_REM:  col += printf(" %% "); break;
1644
               case VCODE_OP_OR:   col += printf(" || "); break;
1645
               case VCODE_OP_AND:  col += printf(" && "); break;
1646
               case VCODE_OP_XOR:  col += printf(" ^ "); break;
1647
               case VCODE_OP_XNOR: col += printf(" !^ "); break;
1648
               case VCODE_OP_NAND: col += printf(" !& "); break;
1649
               case VCODE_OP_NOR:  col += printf(" !| "); break;
1650
               default: break;
1651
               }
1652
               col += vcode_dump_reg(op->args.items[1]);
1653
               vcode_dump_result_type(col, op);
1654
            }
1655
            break;
1656

1657
         case VCODE_OP_TRAP_ADD:
1658
         case VCODE_OP_TRAP_SUB:
1659
         case VCODE_OP_TRAP_MUL:
1660
         case VCODE_OP_TRAP_EXP:
1661
            {
1662
               col += vcode_dump_reg(op->result);
1663
               col += printf(" := %s ", vcode_op_string(op->kind));
1664
               col += vcode_dump_reg(op->args.items[0]);
1665
               switch (op->kind) {
1666
               case VCODE_OP_TRAP_ADD: col += printf(" + "); break;
1667
               case VCODE_OP_TRAP_SUB: col += printf(" - "); break;
1668
               case VCODE_OP_TRAP_MUL: col += printf(" * "); break;
1669
               case VCODE_OP_TRAP_EXP: col += printf(" ** "); break;
1670
               default: break;
1671
               }
1672
               col += vcode_dump_reg(op->args.items[1]);
1673
               col += printf(" locus ");
1674
               col += vcode_dump_reg(op->args.items[2]);
1675
               vcode_dump_result_type(col, op);
1676
            }
1677
            break;
1678

1679
         case VCODE_OP_NOT:
1680
            {
1681
               col += vcode_dump_reg(op->result);
1682
               col += printf(" := %s ", vcode_op_string(op->kind));
1683
               col += vcode_dump_reg(op->args.items[0]);
1684
               vcode_dump_result_type(col, op);
1685
            }
1686
            break;
1687

1688
         case VCODE_OP_COMMENT:
1689
            {
1690
               color_printf("$cyan$// %s$$ ", op->comment);
1691
            }
1692
            break;
1693

1694
         case VCODE_OP_CONST_ARRAY:
1695
         case VCODE_OP_CONST_RECORD:
1696
            {
1697
               col += vcode_dump_reg(op->result);
1698
               col += printf(" := const %c",
1699
                             op->kind == VCODE_OP_CONST_ARRAY ? '[' : '{');
1700
               for (int k = 0; k < op->args.count; k++) {
1701
                  if (k > 0)
1702
                     col += printf(",");
1703
                  col += vcode_dump_reg(op->args.items[k]);
1704
               }
1705

1706
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1707
               vcode_dump_result_type(col + 1, op);
1708
            }
1709
            break;
1710

1711
         case VCODE_OP_CONST_REP:
1712
            {
1713
               col += vcode_dump_reg(op->result);
1714
               col += printf(" := const [");
1715
               col += vcode_dump_reg(op->args.items[0]);
1716
               col += printf("]*%"PRIi64, op->value);
1717
               vcode_dump_result_type(col, op);
1718
            }
1719
            break;
1720

1721
         case VCODE_OP_ADDRESS_OF:
1722
         case VCODE_OP_CAST:
1723
            {
1724
               col += vcode_dump_reg(op->result);
1725
               col += printf(" := %s ", vcode_op_string(op->kind));
1726
               col += vcode_dump_reg(op->args.items[0]);
1727
               vcode_dump_result_type(col, op);
1728
            }
1729
            break;
1730

1731
         case VCODE_OP_RETURN:
1732
            {
1733
               printf("%s ", vcode_op_string(op->kind));
1734
               if (op->args.count > 0)
1735
                  vcode_dump_reg(op->args.items[0]);
1736
            }
1737
            break;
1738

1739
         case VCODE_OP_SCHED_WAVEFORM:
1740
            {
1741
               printf("%s ", vcode_op_string(op->kind));
1742
               vcode_dump_reg(op->args.items[0]);
1743
               printf(" count ");
1744
               vcode_dump_reg(op->args.items[1]);
1745
               printf(" values ");
1746
               vcode_dump_reg(op->args.items[2]);
1747
               printf(" reject ");
1748
               vcode_dump_reg(op->args.items[3]);
1749
               printf(" after ");
1750
               vcode_dump_reg(op->args.items[4]);
1751
            }
1752
            break;
1753

1754
         case VCODE_OP_FORCE:
1755
         case VCODE_OP_RELEASE:
1756
         case VCODE_OP_DEPOSIT_SIGNAL:
1757
            {
1758
               printf("%s ", vcode_op_string(op->kind));
1759
               vcode_dump_reg(op->args.items[0]);
1760
               printf(" count ");
1761
               vcode_dump_reg(op->args.items[1]);
1762
               if (op->args.count > 2) {
1763
                  printf(" values ");
1764
                  vcode_dump_reg(op->args.items[2]);
1765
               }
1766
            }
1767
            break;
1768

1769
         case VCODE_OP_DISCONNECT:
1770
            {
1771
               printf("%s ", vcode_op_string(op->kind));
1772
               vcode_dump_reg(op->args.items[0]);
1773
               printf(" count ");
1774
               vcode_dump_reg(op->args.items[1]);
1775
               printf(" reject ");
1776
               vcode_dump_reg(op->args.items[2]);
1777
               printf(" after ");
1778
               vcode_dump_reg(op->args.items[3]);
1779
            }
1780
            break;
1781

1782
         case VCODE_OP_NEG:
1783
         case VCODE_OP_TRAP_NEG:
1784
         case VCODE_OP_ABS:
1785
         case VCODE_OP_RESOLVED:
1786
         case VCODE_OP_LAST_VALUE:
1787
            {
1788
               col += vcode_dump_reg(op->result);
1789
               col += printf(" := %s ", vcode_op_string(op->kind));
1790
               col += vcode_dump_reg(op->args.items[0]);
1791
               if (op->args.count > 1) {
1792
                  col += printf(" locus ");
1793
                  col += vcode_dump_reg(op->args.items[1]);
1794
               }
1795
               vcode_dump_result_type(col, op);
1796
            }
1797
            break;
1798

1799
         case VCODE_OP_SELECT:
1800
            {
1801
               col += vcode_dump_reg(op->result);
1802
               col += printf(" := %s ", vcode_op_string(op->kind));
1803
               col += vcode_dump_reg(op->args.items[0]);
1804
               col += printf(" then ");
1805
               col += vcode_dump_reg(op->args.items[1]);
1806
               col += printf(" else ");
1807
               col += vcode_dump_reg(op->args.items[2]);
1808
               vcode_dump_result_type(col, op);
1809
            }
1810
            break;
1811

1812
         case VCODE_OP_WRAP:
1813
            {
1814
               col += vcode_dump_reg(op->result);
1815
               col += printf(" := %s ", vcode_op_string(op->kind));
1816
               col += vcode_dump_reg(op->args.items[0]);
1817
               col += printf(" [");
1818
               for (int i = 1; i < op->args.count; i += 3) {
1819
                  if (i > 1)
1820
                     col += printf(", ");
1821
                  col += vcode_dump_reg(op->args.items[i + 0]);
1822
                  col += printf(" ");
1823
                  col += vcode_dump_reg(op->args.items[i + 1]);
1824
                  col += printf(" ");
1825
                  col += vcode_dump_reg(op->args.items[i + 2]);
1826
               }
1827
               col += printf("]");
1828
               vcode_dump_result_type(col, op);
1829
            }
1830
            break;
1831

1832
         case VCODE_OP_UARRAY_LEFT:
1833
         case VCODE_OP_UARRAY_RIGHT:
1834
         case VCODE_OP_UARRAY_DIR:
1835
         case VCODE_OP_UARRAY_LEN:
1836
            {
1837
               col += vcode_dump_reg(op->result);
1838
               col += printf(" := %s ", vcode_op_string(op->kind));
1839
               col += vcode_dump_reg(op->args.items[0]);
1840
               col += printf(" dim %d", op->dim);
1841
               vcode_dump_result_type(col, op);
1842
            }
1843
            break;
1844

1845
         case VCODE_OP_UNWRAP:
1846
            {
1847
               col += vcode_dump_reg(op->result);
1848
               col += printf(" := %s ", vcode_op_string(op->kind));
1849
               col += vcode_dump_reg(op->args.items[0]);
1850
               vcode_dump_result_type(col, op);
1851
            }
1852
            break;
1853

1854
         case VCODE_OP_VAR_UPREF:
1855
            {
1856
               col += vcode_dump_reg(op->result);
1857
               col += printf(" := %s %d, ", vcode_op_string(op->kind),
1858
                             op->hops);
1859
               col += vcode_dump_var(op->address, op->hops);
1860
               vcode_dump_result_type(col, op);
1861
            }
1862
            break;
1863

1864
         case VCODE_OP_CONTEXT_UPREF:
1865
            {
1866
               col += vcode_dump_reg(op->result);
1867
               col += printf(" := %s %d", vcode_op_string(op->kind), op->hops);
1868
               vcode_dump_result_type(col, op);
1869
            }
1870
            break;
1871

1872
         case VCODE_OP_ACTIVE:
1873
         case VCODE_OP_EVENT:
1874
         case VCODE_OP_DRIVING:
1875
            {
1876
               col += vcode_dump_reg(op->result);
1877
               col += printf(" := %s ", vcode_op_string(op->kind));
1878
               col += vcode_dump_reg(op->args.items[0]);
1879
               col += printf(" length ");
1880
               col += vcode_dump_reg(op->args.items[1]);
1881
               vcode_dump_result_type(col, op);
1882
            }
1883
            break;
1884

1885
         case VCODE_OP_RECORD_REF:
1886
            {
1887
               col += vcode_dump_reg(op->result);
1888
               col += printf(" := %s ", vcode_op_string(op->kind));
1889
               col += vcode_dump_reg(op->args.items[0]);
1890
               col += printf(" field %d", op->field);
1891
               vcode_dump_result_type(col, op);
1892
            }
1893
            break;
1894

1895
         case VCODE_OP_ARRAY_REF:
1896
            {
1897
               col += vcode_dump_reg(op->result);
1898
               col += printf(" := %s ", vcode_op_string(op->kind));
1899
               col += vcode_dump_reg(op->args.items[0]);
1900
               col += printf(" offset ");
1901
               col += vcode_dump_reg(op->args.items[1]);
1902
               vcode_dump_result_type(col, op);
1903
            }
1904
            break;
1905

1906
         case VCODE_OP_COPY:
1907
            {
1908
               vcode_dump_reg(op->args.items[0]);
1909
               printf(" := %s ", vcode_op_string(op->kind));
1910
               vcode_dump_reg(op->args.items[1]);
1911
               if (op->args.count > 2) {
1912
                  printf(" count " );
1913
                  vcode_dump_reg(op->args.items[2]);
1914
               }
1915
            }
1916
            break;
1917

1918
         case VCODE_OP_SCHED_EVENT:
1919
         case VCODE_OP_CLEAR_EVENT:
1920
            {
1921
               printf("%s on ", vcode_op_string(op->kind));
1922
               vcode_dump_reg(op->args.items[0]);
1923
               printf(" count ");
1924
               vcode_dump_reg(op->args.items[1]);
1925
            }
1926
            break;
1927

1928
         case VCODE_OP_PCALL:
1929
            {
1930
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1931
                            istr(op->func));
1932
               for (int i = 0; i < op->args.count; i++) {
1933
                  printf("%s", i > 0 ? ", " : " ");
1934
                  vcode_dump_reg(op->args.items[i]);
1935
               }
1936
               if (op->targets.count > 0)
1937
                  color_printf(" resume $yellow$%d$$", op->targets.items[0]);
1938
            }
1939
            break;
1940

1941
         case VCODE_OP_RESUME:
1942
            {
1943
               color_printf("%s $magenta$%s$$", vcode_op_string(op->kind),
1944
                            istr(op->func));
1945
            }
1946
            break;
1947

1948
         case VCODE_OP_MEMSET:
1949
            {
1950
               vcode_dump_reg(op->args.items[0]);
1951
               printf(" := %s ", vcode_op_string(op->kind));
1952
               vcode_dump_reg(op->args.items[1]);
1953
               printf(" length ");
1954
               vcode_dump_reg(op->args.items[2]);
1955
            }
1956
            break;
1957

1958
         case VCODE_OP_CASE:
1959
            {
1960
               printf("%s ", vcode_op_string(op->kind));
1961
               vcode_dump_reg(op->args.items[0]);
1962
               color_printf(" default $yellow$%d$$", op->targets.items[0]);
1963
               for (int i = 1; i < op->args.count; i++) {
1964
                  printf(" [");
1965
                  vcode_dump_reg(op->args.items[i]);
1966
                  color_printf(" $yellow$%d$$]", op->targets.items[i]);
1967
               }
1968
            }
1969
            break;
1970

1971
         case VCODE_OP_FILE_OPEN:
1972
            {
1973
               printf("%s ", vcode_op_string(op->kind));
1974
               vcode_dump_reg(op->args.items[0]);
1975
               printf(" name ");
1976
               vcode_dump_reg(op->args.items[1]);
1977
               printf(" length ");
1978
               vcode_dump_reg(op->args.items[2]);
1979
               printf(" kind ");
1980
               vcode_dump_reg(op->args.items[3]);
1981
               if (op->args.count == 5) {
1982
                  printf(" status ");
1983
                  vcode_dump_reg(op->args.items[4]);
1984
               }
1985
            }
1986
            break;
1987

1988
         case VCODE_OP_FILE_WRITE:
1989
            {
1990
               printf("%s ", vcode_op_string(op->kind));
1991
               vcode_dump_reg(op->args.items[0]);
1992
               printf(" value ");
1993
               vcode_dump_reg(op->args.items[1]);
1994
               if (op->args.count == 3) {
1995
                  printf(" length ");
1996
                  vcode_dump_reg(op->args.items[2]);
1997
               }
1998
            }
1999
            break;
2000

2001
         case VCODE_OP_FILE_READ:
2002
            {
2003
               printf("%s ", vcode_op_string(op->kind));
2004
               vcode_dump_reg(op->args.items[0]);
2005
               printf(" ptr ");
2006
               vcode_dump_reg(op->args.items[1]);
2007
               if (op->args.count >= 3) {
2008
                  printf(" inlen ");
2009
                  vcode_dump_reg(op->args.items[2]);
2010
                  if (op->args.count >= 4) {
2011
                     printf(" outlen ");
2012
                     vcode_dump_reg(op->args.items[3]);
2013
                  }
2014
               }
2015
            }
2016
            break;
2017

2018
         case VCODE_OP_NULL:
2019
         case VCODE_OP_NEW:
2020
            {
2021
               col += vcode_dump_reg(op->result);
2022
               col += printf(" := %s", vcode_op_string(op->kind));
2023
               if (op->args.count == 1) {
2024
                  col += printf(" length ");
2025
                  col += vcode_dump_reg(op->args.items[0]);
2026
               }
2027
               vcode_dump_result_type(col, op);
2028
            }
2029
            break;
2030

2031
         case VCODE_OP_NULL_CHECK:
2032
            {
2033
               col += printf("%s ", vcode_op_string(op->kind));
2034
               col += vcode_dump_reg(op->args.items[0]);
2035
               col += printf(" locus ");
2036
               col += vcode_dump_reg(op->args.items[1]);
2037
            }
2038
            break;
2039

2040
         case VCODE_OP_DEALLOCATE:
2041
            {
2042
               col += printf("%s ", vcode_op_string(op->kind));
2043
               col += vcode_dump_reg(op->args.items[0]);
2044
            }
2045
            break;
2046

2047
         case VCODE_OP_ALL:
2048
            {
2049
               col += vcode_dump_reg(op->result);
2050
               col += printf(" := %s ", vcode_op_string(op->kind));
2051
               col += vcode_dump_reg(op->args.items[0]);
2052
               vcode_dump_result_type(col, op);
2053
            }
2054
            break;
2055

2056
         case VCODE_OP_LAST_EVENT:
2057
         case VCODE_OP_LAST_ACTIVE:
2058
         case VCODE_OP_DRIVING_VALUE:
2059
            {
2060
               col += vcode_dump_reg(op->result);
2061
               col += printf(" := %s ", vcode_op_string(op->kind));
2062
               col += vcode_dump_reg(op->args.items[0]);
2063
               if (op->args.count > 1) {
2064
                  col += printf(" length ");
2065
                  col += vcode_dump_reg(op->args.items[1]);
2066
               }
2067
               vcode_dump_result_type(col, op);
2068
            }
2069
            break;
2070

2071
         case VCODE_OP_ALIAS_SIGNAL:
2072
            {
2073
               printf("%s ", vcode_op_string(op->kind));
2074
               vcode_dump_reg(op->args.items[0]);
2075
               printf(" locus ");
2076
               vcode_dump_reg(op->args.items[1]);
2077
            }
2078
            break;
2079

2080
         case VCODE_OP_LENGTH_CHECK:
2081
            {
2082
               col += printf("%s left ", vcode_op_string(op->kind));
2083
               col += vcode_dump_reg(op->args.items[0]);
2084
               col += printf(" == right ");
2085
               col += vcode_dump_reg(op->args.items[1]);
2086
               col += printf(" locus ");
2087
               col += vcode_dump_reg(op->args.items[2]);
2088
               if (op->args.count > 3) {
2089
                  col += printf(" dim ");
2090
                  col += vcode_dump_reg(op->args.items[3]);
2091
               }
2092
            }
2093
            break;
2094

2095
         case VCODE_OP_EXPONENT_CHECK:
2096
         case VCODE_OP_ZERO_CHECK:
2097
            {
2098
               col += printf("%s ", vcode_op_string(op->kind));
2099
               col += vcode_dump_reg(op->args.items[0]);
2100
               col += printf(" locus ");
2101
               col += vcode_dump_reg(op->args.items[1]);
2102
            }
2103
            break;
2104

2105
         case VCODE_OP_INDEX_CHECK:
2106
         case VCODE_OP_RANGE_CHECK:
2107
            {
2108
               col += printf("%s ", vcode_op_string(op->kind));
2109
               col += vcode_dump_reg(op->args.items[0]);
2110
               col += printf(" left ");
2111
               col += vcode_dump_reg(op->args.items[1]);
2112
               col += printf(" right ");
2113
               col += vcode_dump_reg(op->args.items[2]);
2114
               col += printf(" dir ");
2115
               col += vcode_dump_reg(op->args.items[3]);
2116
               col += printf(" locus ");
2117
               col += vcode_dump_reg(op->args.items[4]);
2118
               if (op->args.items[5] != op->args.items[4]) {
2119
                  col += printf(" hint ");
2120
                  col += vcode_dump_reg(op->args.items[5]);
2121
               }
2122
            }
2123
            break;
2124

2125
         case VCODE_OP_DEBUG_OUT:
2126
            {
2127
               col += printf("%s ", vcode_op_string(op->kind));
2128
               col += vcode_dump_reg(op->args.items[0]);
2129
            }
2130
            break;
2131

2132
         case VCODE_OP_COVER_STMT:
2133
         case VCODE_OP_COVER_BRANCH:
2134
         case VCODE_OP_COVER_EXPR:
2135
            {
2136
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2137
            }
2138
            break;
2139

2140
         case VCODE_OP_COVER_TOGGLE:
2141
         case VCODE_OP_COVER_STATE:
2142
            {
2143
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2144
               vcode_dump_reg(op->args.items[0]);
2145
            }
2146
            break;
2147

2148
         case VCODE_OP_UNDEFINED:
2149
            {
2150
               col += vcode_dump_reg(op->result);
2151
               col += printf(" := %s", vcode_op_string(op->kind));
2152
               vcode_dump_result_type(col, op);
2153
            }
2154
            break;
2155

2156
         case VCODE_OP_RANGE_LENGTH:
2157
         case VCODE_OP_RANGE_NULL:
2158
            {
2159
               col += vcode_dump_reg(op->result);
2160
               col += printf(" := %s left ", vcode_op_string(op->kind));
2161
               vcode_dump_reg(op->args.items[0]);
2162
               col += printf(" right ");
2163
               vcode_dump_reg(op->args.items[1]);
2164
               col += printf(" dir ");
2165
               col += vcode_dump_reg(op->args.items[2]);
2166
               vcode_dump_result_type(col, op);
2167
            }
2168
            break;
2169

2170
         case VCODE_OP_LINK_PACKAGE:
2171
            {
2172
               col += vcode_dump_reg(op->result);
2173
               col += color_printf(" := %s $magenta$%s$$",
2174
                                   vcode_op_string(op->kind), istr(op->ident));
2175
               if (op->args.count > 0) {
2176
                  col += printf(" locus ");
2177
                  col += vcode_dump_reg(op->args.items[0]);
2178
               }
2179
               vcode_dump_result_type(col, op);
2180
            }
2181
            break;
2182

2183
         case VCODE_OP_LINK_VAR:
2184
            {
2185
               col += vcode_dump_reg(op->result);
2186
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2187
               col += vcode_dump_reg(op->args.items[0]);
2188
               col += color_printf(" $magenta$%s$$", istr(op->ident));
2189
               vcode_dump_result_type(col, op);
2190
            }
2191
            break;
2192

2193
         case VCODE_OP_UNREACHABLE:
2194
            {
2195
               printf("%s", vcode_op_string(op->kind));
2196
               if (op->args.count > 0) {
2197
                  printf(" ");
2198
                  vcode_dump_reg(op->args.items[0]);
2199
               }
2200
            }
2201
            break;
2202

2203
         case VCODE_OP_DEBUG_LOCUS:
2204
            {
2205
               col += vcode_dump_reg(op->result);
2206
               col += color_printf(" := %s $magenta$%s$$%+"PRIi64,
2207
                                   vcode_op_string(op->kind),
2208
                                   istr(op->ident), op->value);
2209
               vcode_dump_result_type(col, op);
2210
            }
2211
            break;
2212

2213
         case VCODE_OP_ENTER_STATE:
2214
            {
2215
               printf("%s ", vcode_op_string(op->kind));
2216
               vcode_dump_reg(op->args.items[0]);
2217
               if (op->args.count > 1) {
2218
                  printf(" strong ");
2219
                  vcode_dump_reg(op->args.items[1]);
2220
               }
2221
            }
2222
            break;
2223

2224
         case VCODE_OP_REFLECT_VALUE:
2225
            {
2226
               col += vcode_dump_reg(op->result);
2227
               col += printf(" := %s ", vcode_op_string(op->kind));
2228
               vcode_dump_reg(op->args.items[0]);
2229
               col += printf(" context ");
2230
               vcode_dump_reg(op->args.items[1]);
2231
               col += printf(" locus ");
2232
               col += vcode_dump_reg(op->args.items[2]);
2233
               if (op->args.count > 3) {
2234
                  col += printf(" bounds ");
2235
                  col += vcode_dump_reg(op->args.items[3]);
2236
               }
2237
               vcode_dump_result_type(col, op);
2238
            }
2239
            break;
2240

2241
         case VCODE_OP_REFLECT_SUBTYPE:
2242
            {
2243
               col += vcode_dump_reg(op->result);
2244
               col += printf(" := %s context ", vcode_op_string(op->kind));
2245
               vcode_dump_reg(op->args.items[0]);
2246
               col += printf(" locus ");
2247
               col += vcode_dump_reg(op->args.items[1]);
2248
               if (op->args.count > 2) {
2249
                  col += printf(" bounds ");
2250
                  col += vcode_dump_reg(op->args.items[2]);
2251
               }
2252
               vcode_dump_result_type(col, op);
2253
            }
2254
            break;
2255

2256
         case VCODE_OP_FUNCTION_TRIGGER:
2257
            {
2258
               col += vcode_dump_reg(op->result);
2259
               col += color_printf(" := %s $magenta$%s$$ ",
2260
                                   vcode_op_string(op->kind), istr(op->func));
2261
               for (int i = 0; i < op->args.count; i++) {
2262
                  if (i > 0) col += printf(", ");
2263
                  col += vcode_dump_reg(op->args.items[i]);
2264
               }
2265
               vcode_dump_result_type(col, op);
2266
            }
2267
            break;
2268

2269
         case VCODE_OP_OR_TRIGGER:
2270
         case VCODE_OP_CMP_TRIGGER:
2271
            {
2272
               col += vcode_dump_reg(op->result);
2273
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2274
               col += vcode_dump_reg(op->args.items[0]);
2275
               if (op->kind == VCODE_OP_OR_TRIGGER)
2276
                  col += printf(" || ");
2277
               else
2278
                  col += printf(" == ");
2279
               col += vcode_dump_reg(op->args.items[1]);
2280
               vcode_dump_result_type(col, op);
2281
            }
2282
            break;
2283

2284
         case VCODE_OP_ADD_TRIGGER:
2285
            {
2286
               printf("%s ", vcode_op_string(op->kind));
2287
               vcode_dump_reg(op->args.items[0]);
2288
            }
2289
            break;
2290

2291
         case VCODE_OP_PORT_CONVERSION:
2292
            {
2293
               col += vcode_dump_reg(op->result);
2294
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2295
               col += vcode_dump_reg(op->args.items[0]);
2296
               if (op->args.count > 1) {
2297
                  col += printf(" effective ");
2298
                  col += vcode_dump_reg(op->args.items[1]);
2299
               }
2300
               vcode_dump_result_type(col, op);
2301
            }
2302
            break;
2303

2304
         case VCODE_OP_CONVERT_IN:
2305
         case VCODE_OP_CONVERT_OUT:
2306
            {
2307
               color_printf("%s ", vcode_op_string(op->kind));
2308
               vcode_dump_reg(op->args.items[0]);
2309
               printf(" signal ");
2310
               vcode_dump_reg(op->args.items[1]);
2311
               printf(" count ");
2312
               vcode_dump_reg(op->args.items[2]);
2313
            }
2314
            break;
2315

2316
         case VCODE_OP_BIND_FOREIGN:
2317
            {
2318
               color_printf("%s ", vcode_op_string(op->kind));
2319
               vcode_dump_reg(op->args.items[0]);
2320
               printf(" length ");
2321
               vcode_dump_reg(op->args.items[1]);
2322
               if (op->args.count > 2) {
2323
                  printf(" locus ");
2324
                  vcode_dump_reg(op->args.items[1]);
2325
               }
2326
            }
2327
            break;
2328

2329
         case VCODE_OP_INSTANCE_NAME:
2330
         case VCODE_OP_BIND_EXTERNAL:
2331
            {
2332
               col += vcode_dump_reg(op->result);
2333
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2334
               col += vcode_dump_reg(op->args.items[0]);
2335
               vcode_dump_result_type(col, op);
2336
            }
2337
            break;
2338
         }
2339

2340
         if (j == mark_op && i == old_block)
2341
            color_printf("\t $red$<----$$");
2342

2343
         color_printf("$$\n");
2344

2345
         if (callback != NULL)
2346
            (*callback)(j, arg);
2347
      }
2348

2349
      if (b->ops.count == 0)
2350
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2351
   }
2352

2353
   printf("\n");
2354
   fflush(stdout);
2355

2356
   active_block = old_block;
2357
}
2358
LCOV_EXCL_STOP
2359

2360
bool vtype_eq(vcode_type_t a, vcode_type_t b)
32,733,800✔
2361
{
2362
   assert(active_unit != NULL);
33,263,593✔
2363

2364
   if (a == b)
33,263,593✔
2365
      return true;
2366
   else {
2367
      const vtype_t *at = vcode_type_data(a);
30,647,130✔
2368
      const vtype_t *bt = vcode_type_data(b);
30,647,130✔
2369

2370
      if (at->kind != bt->kind)
30,647,130✔
2371
         return false;
2372

2373
      switch (at->kind) {
13,353,191✔
2374
      case VCODE_TYPE_INT:
11,287,076✔
2375
         return (at->low == bt->low) && (at->high == bt->high);
21,188,151✔
2376
      case VCODE_TYPE_REAL:
978,020✔
2377
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
1,904,896✔
2378
      case VCODE_TYPE_CARRAY:
73,484✔
2379
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
80,026✔
2380
      case VCODE_TYPE_UARRAY:
90,571✔
2381
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
112,910✔
2382
      case VCODE_TYPE_POINTER:
446,625✔
2383
      case VCODE_TYPE_ACCESS:
2384
         return vtype_eq(at->pointed, bt->pointed);
446,625✔
2385
      case VCODE_TYPE_OFFSET:
2386
      case VCODE_TYPE_OPAQUE:
2387
      case VCODE_TYPE_DEBUG_LOCUS:
2388
      case VCODE_TYPE_TRIGGER:
2389
      case VCODE_TYPE_CONVERSION:
2390
         return true;
2391
      case VCODE_TYPE_RESOLUTION:
83,168✔
2392
      case VCODE_TYPE_CLOSURE:
2393
      case VCODE_TYPE_SIGNAL:
2394
      case VCODE_TYPE_FILE:
2395
         return vtype_eq(at->base, bt->base);
83,168✔
2396
      case VCODE_TYPE_RECORD:
64,746✔
2397
      case VCODE_TYPE_CONTEXT:
2398
         return at->name == bt->name;
64,746✔
2399
      }
2400

2401
      return false;
×
2402
   }
2403
}
2404

2405
void vcode_dump(void)
×
2406
{
2407
   vcode_dump_with_mark(-1, NULL, NULL);
×
2408
}
×
2409

2410
static vcode_type_t vtype_new(vtype_t *new)
2,528,975✔
2411
{
2412
   int index = active_unit->types.count - 1;
2,528,975✔
2413
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
2,528,975✔
2414

2415
   for (int i = 0; i < index; i++) {
30,357,230✔
2416
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
29,827,114✔
2417
      if (vtype_eq(this, type)) {
29,827,114✔
2418
         active_unit->types.count--;
1,998,859✔
2419
         return this;
1,998,859✔
2420
      }
2421
   }
2422

2423
   return type;
2424
}
2425

2426
vcode_type_t vtype_int(int64_t low, int64_t high)
1,668,998✔
2427
{
2428
   assert(active_unit != NULL);
1,668,998✔
2429

2430
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,668,998✔
2431
   n->kind = VCODE_TYPE_INT;
1,668,998✔
2432
   n->low  = low;
1,668,998✔
2433
   n->high = high;
1,668,998✔
2434

2435
   switch (bits_for_range(low, high)) {
1,668,998✔
2436
   case 64:
127,977✔
2437
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
127,977✔
2438
      break;
127,977✔
2439
   case 32:
513,854✔
2440
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
513,854✔
2441
      break;
513,854✔
2442
   case 16:
3,459✔
2443
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
3,459✔
2444
      break;
3,459✔
2445
   case 8:
442,386✔
2446
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
442,386✔
2447
      break;
442,386✔
2448
   case 1:
581,321✔
2449
      n->repr = VCODE_REPR_U1;
581,321✔
2450
      break;
581,321✔
2451
   case 0:
1✔
2452
      n->repr = VCODE_REPR_I64;    // Null range
1✔
2453
      break;
1✔
2454
   default:
×
2455
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2456
   }
2457

2458
   return vtype_new(n);
1,668,998✔
2459
}
2460

2461
vcode_type_t vtype_bool(void)
292,896✔
2462
{
2463
   return vtype_int(0, 1);
292,896✔
2464
}
2465

2466
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
37,261✔
2467
{
2468
   assert(active_unit != NULL);
37,261✔
2469

2470
   const vtype_kind_t ekind = vtype_kind(elem);
37,261✔
2471
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
37,261✔
2472
                "array types may not be nested");
2473

2474
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
37,261✔
2475
   memset(n, '\0', sizeof(vtype_t));
37,261✔
2476
   n->kind   = VCODE_TYPE_CARRAY;
37,261✔
2477
   n->elem   = elem;
37,261✔
2478
   n->bounds = bounds;
37,261✔
2479
   n->size   = MAX(size, 0);
37,261✔
2480

2481
   return vtype_new(n);
37,261✔
2482
}
2483

2484
vcode_type_t vtype_find_named_record(ident_t name)
37,419✔
2485
{
2486
   assert(active_unit != NULL);
37,419✔
2487

2488
   for (int i = 0; i < active_unit->types.count; i++) {
486,439✔
2489
      vtype_t *other = &(active_unit->types.items[i]);
475,348✔
2490
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
475,348✔
2491
         return MAKE_HANDLE(active_unit->depth, i);
26,328✔
2492
   }
2493

2494
   return VCODE_INVALID_TYPE;
2495
}
2496

2497
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
11,091✔
2498
                                int nfields)
2499
{
2500
   assert(active_unit != NULL);
11,091✔
2501

2502
   vtype_t *data = NULL;
11,091✔
2503
   vcode_type_t handle = vtype_find_named_record(name);
11,091✔
2504
   if (handle == VCODE_INVALID_TYPE) {
11,091✔
2505
      data = vtype_array_alloc(&(active_unit->types));
5,555✔
2506
      memset(data, '\0', sizeof(vtype_t));
5,555✔
2507
      data->kind = VCODE_TYPE_RECORD;
5,555✔
2508
      data->name = name;
5,555✔
2509

2510
      handle = vtype_new(data);
5,555✔
2511
   }
2512
   else {
2513
      data = vcode_type_data(handle);
5,536✔
2514
      VCODE_ASSERT(data->fields.count == 0,
5,536✔
2515
                    "record type %s already defined", istr(name));
2516
   }
2517

2518
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
11,091✔
2519
   for (int i = 0; i < nfields; i++)
29,782✔
2520
      vcode_type_array_add(&(data->fields), field_types[i]);
18,691✔
2521

2522
   return handle;
11,091✔
2523
}
2524

2525
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
84,999✔
2526
{
2527
   assert(active_unit != NULL);
84,999✔
2528

2529
   const vtype_kind_t ekind = vtype_kind(elem);
84,999✔
2530
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
84,999✔
2531
                "array types may not be nested");
2532

2533
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
84,999✔
2534

2535
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
84,999✔
2536
   memset(n, '\0', sizeof(vtype_t));
84,999✔
2537
   n->kind   = VCODE_TYPE_UARRAY;
84,999✔
2538
   n->elem   = elem;
84,999✔
2539
   n->bounds = bounds;
84,999✔
2540
   n->dims   = ndim;
84,999✔
2541

2542
   return vtype_new(n);
84,999✔
2543
}
2544

2545
vcode_type_t vtype_pointer(vcode_type_t to)
185,636✔
2546
{
2547
   assert(active_unit != NULL);
185,636✔
2548

2549
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
185,636✔
2550
   n->kind    = VCODE_TYPE_POINTER;
185,636✔
2551
   n->pointed = to;
185,636✔
2552

2553
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
185,636✔
2554
                "cannot get pointer to carray type");
2555

2556
   return vtype_new(n);
185,636✔
2557
}
2558

2559
vcode_type_t vtype_access(vcode_type_t to)
4,934✔
2560
{
2561
   assert(active_unit != NULL);
4,934✔
2562

2563
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,934✔
2564
   n->kind    = VCODE_TYPE_ACCESS;
4,934✔
2565
   n->pointed = to;
4,934✔
2566

2567
   return vtype_new(n);
4,934✔
2568
}
2569

2570
vcode_type_t vtype_signal(vcode_type_t base)
34,250✔
2571
{
2572
   assert(active_unit != NULL);
34,250✔
2573

2574
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
34,250✔
2575
   n->kind = VCODE_TYPE_SIGNAL;
34,250✔
2576
   n->base = base;
34,250✔
2577

2578
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
34,250✔
2579

2580
   return vtype_new(n);
34,250✔
2581
}
2582

2583
vcode_type_t vtype_resolution(vcode_type_t base)
870✔
2584
{
2585
   assert(active_unit != NULL);
870✔
2586

2587
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
870✔
2588
   n->kind = VCODE_TYPE_RESOLUTION;
870✔
2589
   n->base = base;
870✔
2590

2591
   return vtype_new(n);
870✔
2592
}
2593

2594
vcode_type_t vtype_closure(vcode_type_t result)
1,150✔
2595
{
2596
   assert(active_unit != NULL);
1,150✔
2597

2598
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,150✔
2599
   n->kind = VCODE_TYPE_CLOSURE;
1,150✔
2600
   n->base = result;
1,150✔
2601

2602
   return vtype_new(n);
1,150✔
2603
}
2604

2605
vcode_type_t vtype_context(ident_t name)
51,538✔
2606
{
2607
   assert(active_unit != NULL);
51,538✔
2608
   assert(name != NULL);
51,538✔
2609

2610
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
51,538✔
2611
   n->kind = VCODE_TYPE_CONTEXT;
51,538✔
2612
   n->name = name;
51,538✔
2613

2614
   return vtype_new(n);
51,538✔
2615
}
2616

2617
vcode_type_t vtype_file(vcode_type_t base)
616✔
2618
{
2619
   assert(active_unit != NULL);
616✔
2620

2621
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
616✔
2622
   n->kind = VCODE_TYPE_FILE;
616✔
2623
   n->base = base;
616✔
2624

2625
   return vtype_new(n);
616✔
2626
}
2627

2628
vcode_type_t vtype_offset(void)
262,862✔
2629
{
2630
   assert(active_unit != NULL);
262,862✔
2631

2632
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
262,862✔
2633
   n->kind = VCODE_TYPE_OFFSET;
262,862✔
2634
   n->low  = INT64_MIN;
262,862✔
2635
   n->high = INT64_MAX;
262,862✔
2636
   n->repr = VCODE_REPR_I64;
262,862✔
2637

2638
   return vtype_new(n);
262,862✔
2639
}
2640

2641
vcode_type_t vtype_time(void)
17,146✔
2642
{
2643
   return vtype_int(INT64_MIN, INT64_MAX);
17,146✔
2644
}
2645

2646
vcode_type_t vtype_char(void)
9,210✔
2647
{
2648
   return vtype_int(0, 255);
9,210✔
2649
}
2650

2651
vcode_type_t vtype_opaque(void)
1,178✔
2652
{
2653
   assert(active_unit != NULL);
1,178✔
2654

2655
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
1,178✔
2656
   n->kind = VCODE_TYPE_OPAQUE;
1,178✔
2657

2658
   return vtype_new(n);
1,178✔
2659
}
2660

2661
vcode_type_t vtype_debug_locus(void)
108,656✔
2662
{
2663
   assert(active_unit != NULL);
108,656✔
2664

2665
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
108,656✔
2666
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
108,656✔
2667

2668
   return vtype_new(n);
108,656✔
2669
}
2670

2671
vcode_type_t vtype_trigger(void)
359✔
2672
{
2673
   assert(active_unit != NULL);
359✔
2674

2675
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
359✔
2676
   n->kind = VCODE_TYPE_TRIGGER;
359✔
2677

2678
   return vtype_new(n);
359✔
2679
}
2680

2681
vcode_type_t vtype_conversion(void)
255✔
2682
{
2683
   assert(active_unit != NULL);
255✔
2684

2685
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
255✔
2686
   n->kind = VCODE_TYPE_CONVERSION;
255✔
2687

2688
   return vtype_new(n);
255✔
2689
}
2690

2691
vcode_type_t vtype_real(double low, double high)
79,858✔
2692
{
2693
   assert(active_unit != NULL);
79,858✔
2694

2695
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
79,858✔
2696
   n->kind  = VCODE_TYPE_REAL;
79,858✔
2697
   n->rlow  = low;
79,858✔
2698
   n->rhigh = high;
79,858✔
2699

2700
   return vtype_new(n);
79,858✔
2701
}
2702

2703
vtype_kind_t vtype_kind(vcode_type_t type)
5,709,629✔
2704
{
2705
   vtype_t *vt = vcode_type_data(type);
5,709,629✔
2706
   return vt->kind;
5,709,629✔
2707
}
2708

2709
vtype_repr_t vtype_repr(vcode_type_t type)
466,787✔
2710
{
2711
   vtype_t *vt = vcode_type_data(type);
466,787✔
2712
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
466,787✔
2713
   return vt->repr;
466,787✔
2714
}
2715

2716
vcode_type_t vtype_elem(vcode_type_t type)
357,478✔
2717
{
2718
   vtype_t *vt = vcode_type_data(type);
357,478✔
2719
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
357,478✔
2720
   return vt->elem;
357,478✔
2721
}
2722

2723
vcode_type_t vtype_base(vcode_type_t type)
14,836✔
2724
{
2725
   vtype_t *vt = vcode_type_data(type);
14,836✔
2726
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
14,836✔
2727
          || vt->kind == VCODE_TYPE_RESOLUTION
2728
          || vt->kind == VCODE_TYPE_CLOSURE);
2729
   return vt->base;
14,836✔
2730
}
2731

2732
vcode_type_t vtype_bounds(vcode_type_t type)
13,168✔
2733
{
2734
   vtype_t *vt = vcode_type_data(type);
13,168✔
2735
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
13,168✔
2736
   return vt->bounds;
13,168✔
2737
}
2738

2739
unsigned vtype_dims(vcode_type_t type)
138,344✔
2740
{
2741
   vtype_t *vt = vcode_type_data(type);
138,344✔
2742
   assert(vt->kind == VCODE_TYPE_UARRAY);
138,344✔
2743
   return vt->dims;
138,344✔
2744
}
2745

2746
unsigned vtype_size(vcode_type_t type)
77,141✔
2747
{
2748
   vtype_t *vt = vcode_type_data(type);
77,141✔
2749
   assert(vt->kind == VCODE_TYPE_CARRAY);
77,141✔
2750
   return vt->size;
77,141✔
2751
}
2752

2753
int vtype_fields(vcode_type_t type)
26,317✔
2754
{
2755
   vtype_t *vt = vcode_type_data(type);
26,317✔
2756
   assert(vt->kind == VCODE_TYPE_RECORD);
26,317✔
2757
   return vt->fields.count;
26,317✔
2758
}
2759

2760
vcode_type_t vtype_field(vcode_type_t type, int field)
207,471✔
2761
{
2762
   vtype_t *vt = vcode_type_data(type);
207,471✔
2763
   assert(vt->kind == VCODE_TYPE_RECORD);
207,471✔
2764
   return vcode_type_array_nth(&(vt->fields), field);
207,471✔
2765
}
2766

2767
ident_t vtype_name(vcode_type_t type)
2,666✔
2768
{
2769
   vtype_t *vt = vcode_type_data(type);
2,666✔
2770
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
2,666✔
2771
   return vt->name;
2,666✔
2772
}
2773

2774
vcode_type_t vtype_pointed(vcode_type_t type)
383,734✔
2775
{
2776
   vtype_t *vt = vcode_type_data(type);
383,734✔
2777
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
383,734✔
2778
   return vt->pointed;
383,734✔
2779
}
2780

2781
int64_t vtype_low(vcode_type_t type)
58,403✔
2782
{
2783
   vtype_t *vt = vcode_type_data(type);
58,403✔
2784
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
58,403✔
2785
   return vt->low;
58,403✔
2786
}
2787

2788
int64_t vtype_high(vcode_type_t type)
56,255✔
2789
{
2790
   vtype_t *vt = vcode_type_data(type);
56,255✔
2791
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
56,255✔
2792
   return vt->high;
56,255✔
2793
}
2794

2795
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
460✔
2796
{
2797
   return vtype_kind(type) == VCODE_TYPE_POINTER
460✔
2798
      && vtype_kind(vtype_pointed(type)) == to;
460✔
2799
}
2800

2801
bool vtype_is_scalar(vcode_type_t type)
392,898✔
2802
{
2803
   const vtype_kind_t kind = vtype_kind(type);
392,898✔
2804
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
392,898✔
2805
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
158,580✔
2806
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2807
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2808
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER;
392,898✔
2809
}
2810

2811
bool vtype_is_composite(vcode_type_t type)
23,581✔
2812
{
2813
   const vtype_kind_t kind = vtype_kind(type);
23,581✔
2814
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
23,581✔
2815
}
2816

2817
bool vtype_is_signal(vcode_type_t type)
169,482✔
2818
{
2819
   vtype_t *vt = vcode_type_data(type);
301,177✔
2820
   switch (vt->kind) {
301,177✔
2821
   case VCODE_TYPE_SIGNAL:
2822
      return true;
2823
   case VCODE_TYPE_POINTER:
73,007✔
2824
      return vtype_is_signal(vt->pointed);
73,007✔
2825
   case VCODE_TYPE_RECORD:
2826
      for (int i = 0; i < vt->fields.count; i++) {
36,248✔
2827
         if (vtype_is_signal(vt->fields.items[i]))
28,303✔
2828
            return true;
2829
      }
2830
      return false;
2831
   case VCODE_TYPE_UARRAY:
58,688✔
2832
   case VCODE_TYPE_CARRAY:
2833
      return vtype_is_signal(vt->elem);
58,688✔
2834
   default:
139,075✔
2835
      return false;
139,075✔
2836
   }
2837
}
2838

2839
int vtype_repr_bits(vtype_repr_t repr)
369,441✔
2840
{
2841
   switch (repr) {
369,441✔
2842
   case VCODE_REPR_U1: return 1;
2843
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2844
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2845
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2846
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2847
   default: return -1;
2848
   }
2849
}
2850

2851
bool vtype_repr_signed(vtype_repr_t repr)
46,671✔
2852
{
2853
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
46,671✔
2854
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
46,671✔
2855
}
2856

2857
static int64_t vtype_repr_low(vtype_repr_t repr)
8,881✔
2858
{
2859
   switch (repr) {
8,881✔
2860
   case VCODE_REPR_U1:
2861
   case VCODE_REPR_U8:
2862
   case VCODE_REPR_U16:
2863
   case VCODE_REPR_U32:
2864
   case VCODE_REPR_U64: return 0;
2865
   case VCODE_REPR_I8:  return INT8_MIN;
2866
   case VCODE_REPR_I16: return INT16_MIN;
2867
   case VCODE_REPR_I32: return INT32_MIN;
2868
   case VCODE_REPR_I64: return INT64_MIN;
2869
   default:             return 0;
2870
   }
2871
}
2872

2873
static uint64_t vtype_repr_high(vtype_repr_t repr)
8,881✔
2874
{
2875
   switch (repr) {
8,881✔
2876
   case VCODE_REPR_U1:  return 1;
2877
   case VCODE_REPR_U8:  return UINT8_MAX;
2878
   case VCODE_REPR_U16: return UINT16_MAX;
2879
   case VCODE_REPR_U32: return UINT32_MAX;
2880
   case VCODE_REPR_U64: return UINT64_MAX;
2881
   case VCODE_REPR_I8:  return INT8_MAX;
2882
   case VCODE_REPR_I16: return INT16_MAX;
2883
   case VCODE_REPR_I32: return INT32_MAX;
2884
   case VCODE_REPR_I64: return INT64_MAX;
2885
   default:             return 0;
2886
   }
2887
}
2888

2889
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
8,881✔
2890
{
2891
   int64_t clamp_low = vtype_repr_low(repr);
8,881✔
2892
   uint64_t clamp_high = vtype_repr_high(repr);
8,881✔
2893

2894
   if (*low >= clamp_low && *high <= clamp_high)
8,881✔
2895
      return true;
2896
   else {
2897
      *low = MAX(clamp_low, *low);
4,686✔
2898
      *high = MIN(clamp_high, *high);
4,686✔
2899
      return false;
4,686✔
2900
   }
2901
}
2902

2903
int vcode_count_params(void)
11,229✔
2904
{
2905
   assert(active_unit != NULL);
11,229✔
2906
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
11,229✔
2907
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2908
          || active_unit->kind == VCODE_UNIT_PROPERTY
2909
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2910

2911
   return active_unit->params.count;
11,229✔
2912
}
2913

2914
vcode_type_t vcode_param_type(int param)
29,350✔
2915
{
2916
   assert(active_unit != NULL);
29,350✔
2917
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
29,350✔
2918
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2919
          || active_unit->kind == VCODE_UNIT_PROPERTY
2920
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2921
   assert(param < active_unit->params.count);
29,350✔
2922

2923
   return active_unit->params.items[param].type;
29,350✔
2924
}
2925

2926
vcode_reg_t vcode_param_reg(int param)
38,110✔
2927
{
2928
   assert(active_unit != NULL);
38,110✔
2929
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
38,110✔
2930
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2931
          || active_unit->kind == VCODE_UNIT_PROPERTY
2932
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2933
   assert(param < active_unit->params.count);
38,110✔
2934

2935
   return active_unit->params.items[param].reg;
38,110✔
2936
}
2937

2938
vcode_block_t emit_block(void)
137,727✔
2939
{
2940
   assert(active_unit != NULL);
137,727✔
2941

2942
   vcode_block_t bnum = active_unit->blocks.count;
137,727✔
2943

2944
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
137,727✔
2945
   memset(bptr, '\0', sizeof(block_t));
137,727✔
2946

2947
   if (active_block != VCODE_INVALID_BLOCK)
137,727✔
2948
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
93,595✔
2949
   else
2950
      bptr->last_loc = LOC_INVALID;
44,132✔
2951

2952
   return bnum;
137,727✔
2953
}
2954

2955
void vcode_select_unit(vcode_unit_t unit)
176,055✔
2956
{
2957
   active_unit  = unit;
176,055✔
2958
   active_block = VCODE_INVALID_BLOCK;
176,055✔
2959
}
176,055✔
2960

2961
void vcode_select_block(vcode_block_t block)
572,964✔
2962
{
2963
   assert(active_unit != NULL);
572,964✔
2964
   active_block = block;
572,964✔
2965
}
572,964✔
2966

2967
vcode_block_t vcode_active_block(void)
1,468,041✔
2968
{
2969
   assert(active_unit != NULL);
1,468,041✔
2970
   assert(active_block != -1);
1,468,041✔
2971
   return active_block;
1,468,041✔
2972
}
2973

2974
const loc_t *vcode_last_loc(void)
660,597✔
2975
{
2976
   return &(vcode_block_data()->last_loc);
660,597✔
2977
}
2978

2979
vcode_unit_t vcode_active_unit(void)
867✔
2980
{
2981
   assert(active_unit != NULL);
867✔
2982
   return active_unit;
867✔
2983
}
2984

2985
ident_t vcode_unit_name(vcode_unit_t vu)
160,795✔
2986
{
2987
   assert(vu != NULL);
160,795✔
2988
   return vu->name;
160,795✔
2989
}
2990

2991
bool vcode_unit_has_undefined(vcode_unit_t vu)
12,413✔
2992
{
2993
   assert(vu != NULL);
12,413✔
2994
   return !!(vu->flags & UNIT_UNDEFINED);
12,413✔
2995
}
2996

2997
bool vcode_unit_has_escaping_tlab(vcode_unit_t vu)
4,722✔
2998
{
2999
   return !!(vu->flags & UNIT_ESCAPING_TLAB);
4,722✔
3000
}
3001

3002
int vcode_unit_depth(vcode_unit_t vu)
×
3003
{
3004
   assert(vu != NULL);
×
3005
   return vu->depth;
×
3006
}
3007

3008
void vcode_set_result(vcode_type_t type)
21,929✔
3009
{
3010
   assert(active_unit != NULL);
21,929✔
3011
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
21,929✔
3012
          || active_unit->kind == VCODE_UNIT_THUNK);
3013

3014
   active_unit->result = type;
21,929✔
3015
}
21,929✔
3016

3017
vcode_type_t vcode_unit_result(vcode_unit_t vu)
32,328✔
3018
{
3019
   assert(vu != NULL);
32,328✔
3020
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
32,328✔
3021
   return vu->result;
32,328✔
3022
}
3023

3024
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
364,678✔
3025
{
3026
   assert(vu != NULL);
364,678✔
3027
   return vu->kind;
364,678✔
3028
}
3029

3030
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
135,194✔
3031
{
3032
   assert(vu != NULL);
135,194✔
3033
   return vu->context;
135,194✔
3034
}
3035

3036
void vcode_unit_object(vcode_unit_t vu, ident_t *module, ptrdiff_t *offset)
76,427✔
3037
{
3038
   assert(vu != NULL);
76,427✔
3039
   *module = vu->module;
76,427✔
3040
   *offset = vu->offset;
76,427✔
3041
}
76,427✔
3042

3043
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
56,554✔
3044
{
3045
   int hops = 0;
56,554✔
3046
   for (; (unit = unit->context); hops++)
143,431✔
3047
      ;
3048
   return hops;
56,554✔
3049
}
3050

3051
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
27,399✔
3052
{
3053
   assert(context->kind != VCODE_UNIT_THUNK);
27,399✔
3054

3055
   child->next = NULL;
27,399✔
3056
   if (context->children == NULL)
27,399✔
3057
      context->children = child;
11,110✔
3058
   else {
3059
      vcode_unit_t it;
3060
      for (it = context->children; it->next != NULL; it = it->next)
753,432✔
3061
         ;
3062
      it->next = child;
16,289✔
3063
   }
3064
}
27,399✔
3065

3066
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
10,961✔
3067
{
3068
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
10,961✔
3069
   vu->kind     = VCODE_UNIT_FUNCTION;
10,961✔
3070
   vu->name     = name;
10,961✔
3071
   vu->context  = context;
10,961✔
3072
   vu->result   = VCODE_INVALID_TYPE;
10,961✔
3073
   vu->depth    = vcode_unit_calc_depth(vu);
10,961✔
3074

3075
   object_locus(obj, &vu->module, &vu->offset);
10,961✔
3076

3077
   vcode_add_child(context, vu);
10,961✔
3078

3079
   vcode_select_unit(vu);
10,961✔
3080
   vcode_select_block(emit_block());
10,961✔
3081
   emit_debug_info(&(obj->loc));
10,961✔
3082

3083
   return vu;
10,961✔
3084
}
3085

3086
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
251✔
3087
{
3088
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
251✔
3089
   vu->kind     = VCODE_UNIT_PROCEDURE;
251✔
3090
   vu->name     = name;
251✔
3091
   vu->context  = context;
251✔
3092
   vu->result   = VCODE_INVALID_TYPE;
251✔
3093
   vu->depth    = vcode_unit_calc_depth(vu);
251✔
3094

3095
   object_locus(obj, &vu->module, &vu->offset);
251✔
3096

3097
   vcode_add_child(context, vu);
251✔
3098

3099
   vcode_select_unit(vu);
251✔
3100
   vcode_select_block(emit_block());
251✔
3101
   emit_debug_info(&(obj->loc));
251✔
3102

3103
   return vu;
251✔
3104
}
3105

3106
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
9,090✔
3107
{
3108
   assert(context->kind == VCODE_UNIT_INSTANCE
9,090✔
3109
          || context->kind == VCODE_UNIT_SHAPE);
3110

3111
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,090✔
3112
   vu->kind     = VCODE_UNIT_PROCESS;
9,090✔
3113
   vu->name     = name;
9,090✔
3114
   vu->context  = context;
9,090✔
3115
   vu->depth    = vcode_unit_calc_depth(vu);
9,090✔
3116
   vu->result   = VCODE_INVALID_TYPE;
9,090✔
3117

3118
   object_locus(obj, &vu->module, &vu->offset);
9,090✔
3119

3120
   vcode_add_child(context, vu);
9,090✔
3121

3122
   vcode_select_unit(vu);
9,090✔
3123
   vcode_select_block(emit_block());
9,090✔
3124
   emit_debug_info(&(obj->loc));
9,090✔
3125

3126
   return vu;
9,090✔
3127
}
3128

3129
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
9,178✔
3130
{
3131
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
9,178✔
3132

3133
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
9,178✔
3134
   vu->kind     = VCODE_UNIT_INSTANCE;
9,178✔
3135
   vu->name     = name;
9,178✔
3136
   vu->context  = context;
9,178✔
3137
   vu->depth    = vcode_unit_calc_depth(vu);
9,178✔
3138
   vu->result   = VCODE_INVALID_TYPE;
9,178✔
3139

3140
   object_locus(obj, &vu->module, &vu->offset);
9,178✔
3141

3142
   if (context != NULL)
9,178✔
3143
      vcode_add_child(context, vu);
5,651✔
3144

3145
   vcode_select_unit(vu);
9,178✔
3146
   vcode_select_block(emit_block());
9,178✔
3147
   emit_debug_info(&(obj->loc));
9,178✔
3148

3149
   return vu;
9,178✔
3150
}
3151

3152
vcode_unit_t emit_shape(ident_t name, object_t *obj, vcode_unit_t context)
83✔
3153
{
3154
   assert(context == NULL || context->kind == VCODE_UNIT_SHAPE);
83✔
3155

3156
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
83✔
3157
   vu->kind     = VCODE_UNIT_SHAPE;
83✔
3158
   vu->name     = name;
83✔
3159
   vu->context  = context;
83✔
3160
   vu->depth    = vcode_unit_calc_depth(vu);
83✔
3161
   vu->result   = VCODE_INVALID_TYPE;
83✔
3162

3163
   object_locus(obj, &vu->module, &vu->offset);
83✔
3164

3165
   if (context != NULL)
83✔
3166
      vcode_add_child(context, vu);
×
3167

3168
   vcode_select_unit(vu);
83✔
3169
   vcode_select_block(emit_block());
83✔
3170
   emit_debug_info(&(obj->loc));
83✔
3171

3172
   return vu;
83✔
3173
}
3174

3175
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
1,795✔
3176
{
3177
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
1,795✔
3178
   vu->kind     = VCODE_UNIT_PACKAGE;
1,795✔
3179
   vu->name     = name;
1,795✔
3180
   vu->context  = context;
1,795✔
3181
   vu->depth    = vcode_unit_calc_depth(vu);
1,795✔
3182
   vu->result   = VCODE_INVALID_TYPE;
1,795✔
3183

3184
   object_locus(obj, &vu->module, &vu->offset);
1,795✔
3185

3186
   if (context != NULL)
1,795✔
3187
      vcode_add_child(context, vu);
182✔
3188

3189
   vcode_select_unit(vu);
1,795✔
3190
   vcode_select_block(emit_block());
1,795✔
3191
   emit_debug_info(&(obj->loc));
1,795✔
3192

3193
   return vu;
1,795✔
3194
}
3195

3196
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
175✔
3197
{
3198
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
175✔
3199
   vu->kind     = VCODE_UNIT_PROTECTED;
175✔
3200
   vu->name     = name;
175✔
3201
   vu->context  = context;
175✔
3202
   vu->depth    = vcode_unit_calc_depth(vu);
175✔
3203
   vu->result   = VCODE_INVALID_TYPE;
175✔
3204

3205
   object_locus(obj, &vu->module, &vu->offset);
175✔
3206

3207
   if (context != NULL)
175✔
3208
      vcode_add_child(context, vu);
175✔
3209

3210
   vcode_select_unit(vu);
175✔
3211
   vcode_select_block(emit_block());
175✔
3212
   emit_debug_info(&(obj->loc));
175✔
3213

3214
   return vu;
175✔
3215
}
3216

3217
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
177✔
3218
{
3219
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
177✔
3220
   vu->kind     = VCODE_UNIT_PROPERTY;
177✔
3221
   vu->name     = name;
177✔
3222
   vu->context  = context;
177✔
3223
   vu->depth    = vcode_unit_calc_depth(vu);
177✔
3224
   vu->result   = VCODE_INVALID_TYPE;
177✔
3225

3226
   object_locus(obj, &vu->module, &vu->offset);
177✔
3227

3228
   if (context != NULL)
177✔
3229
      vcode_add_child(context, vu);
177✔
3230

3231
   vcode_select_unit(vu);
177✔
3232
   vcode_select_block(emit_block());
177✔
3233
   emit_debug_info(&(obj->loc));
177✔
3234

3235
   return vu;
177✔
3236
}
3237

3238
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
12,422✔
3239
{
3240
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,422✔
3241
   vu->kind     = VCODE_UNIT_THUNK;
12,422✔
3242
   vu->name     = name;
12,422✔
3243
   vu->context  = context;
12,422✔
3244
   vu->depth    = vcode_unit_calc_depth(vu);
12,422✔
3245
   vu->result   = VCODE_INVALID_TYPE;
12,422✔
3246
   vu->depth    = vcode_unit_calc_depth(vu);
12,422✔
3247

3248
   object_locus(obj, &vu->module, &vu->offset);
12,422✔
3249

3250
   if (context != NULL)
12,422✔
3251
      vcode_add_child(context, vu);
912✔
3252

3253
   vcode_select_unit(vu);
12,422✔
3254
   vcode_select_block(emit_block());
12,422✔
3255

3256
   return vu;
12,422✔
3257
}
3258

3259
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
13,944✔
3260
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3261
                 vcode_reg_t hint_right)
3262
{
3263
   int64_t value_const;
13,944✔
3264
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
13,944✔
3265
      emit_comment("Always true assertion on r%d", value);
30✔
3266
      return;
30✔
3267
   }
3268

3269
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
13,914✔
3270
   vcode_add_arg(op, value);
13,914✔
3271
   vcode_add_arg(op, severity);
13,914✔
3272
   vcode_add_arg(op, message);
13,914✔
3273
   vcode_add_arg(op, length);
13,914✔
3274
   vcode_add_arg(op, locus);
13,914✔
3275

3276
   if (hint_left != VCODE_INVALID_REG) {
13,914✔
3277
      vcode_add_arg(op, hint_left);
5,689✔
3278
      vcode_add_arg(op, hint_right);
5,689✔
3279

3280
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
5,689✔
3281
                   "left hint must be scalar");
3282
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
5,689✔
3283
                   "right hint must be scalar");
3284
   }
3285

3286
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
13,914✔
3287
                "value parameter to assert is not bool");
3288
   VCODE_ASSERT(message == VCODE_INVALID_REG
13,914✔
3289
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3290
                "message parameter to assert is not a pointer");
3291
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
13,914✔
3292
                "value parameter to assert is not bool");
3293
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
13,914✔
3294
                "locus argument to report must be a debug locus");
3295
}
3296

3297
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,252✔
3298
                 vcode_reg_t locus)
3299
{
3300
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,252✔
3301
   vcode_add_arg(op, severity);
2,252✔
3302
   vcode_add_arg(op, message);
2,252✔
3303
   vcode_add_arg(op, length);
2,252✔
3304
   vcode_add_arg(op, locus);
2,252✔
3305

3306
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,252✔
3307
                "message parameter to report is not a pointer");
3308
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,252✔
3309
                "message parameter to report is not a character pointer");
3310
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,252✔
3311
                "locus argument to report must be a debug locus");
3312
}
2,252✔
3313

3314
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
38,398✔
3315
{
3316
   if (lhs == rhs) {
38,398✔
3317
      if (cmp == VCODE_CMP_EQ)
928✔
3318
         return emit_const(vtype_bool(), 1);
921✔
3319
      else if (cmp == VCODE_CMP_NEQ)
7✔
3320
         return emit_const(vtype_bool(), 0);
×
3321
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
7✔
3322
         return emit_const(vtype_bool(), 1);
×
3323
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
7✔
3324
         return emit_const(vtype_bool(), 0);
7✔
3325
   }
3326

3327
   int64_t lconst, rconst;
37,470✔
3328
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
37,470✔
3329
      switch (cmp) {
482✔
3330
      case VCODE_CMP_EQ:
301✔
3331
         return emit_const(vtype_bool(), lconst == rconst);
301✔
3332
      case VCODE_CMP_NEQ:
3✔
3333
         return emit_const(vtype_bool(), lconst != rconst);
3✔
3334
      case VCODE_CMP_LT:
3✔
3335
         return emit_const(vtype_bool(), lconst < rconst);
3✔
3336
      case VCODE_CMP_GT:
175✔
3337
         return emit_const(vtype_bool(), lconst > rconst);
175✔
3338
      case VCODE_CMP_LEQ:
×
3339
         return emit_const(vtype_bool(), lconst <= rconst);
×
3340
      case VCODE_CMP_GEQ:
×
3341
         return emit_const(vtype_bool(), lconst >= rconst);
×
3342
      default:
×
3343
         fatal_trace("cannot fold comparison %d", cmp);
3344
      }
3345
   }
3346

3347
   // Reuse any previous operation in this block with the same arguments
3348
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
656,985✔
3349
      if (other->args.count == 2 && other->args.items[0] == lhs
27,397✔
3350
          && other->args.items[1] == rhs && other->cmp == cmp)
1,179✔
3351
         return other->result;
196✔
3352
   }
3353

3354
   op_t *op = vcode_add_op(VCODE_OP_CMP);
36,792✔
3355
   vcode_add_arg(op, lhs);
36,792✔
3356
   vcode_add_arg(op, rhs);
36,792✔
3357
   op->cmp    = cmp;
36,792✔
3358
   op->result = vcode_add_reg(vtype_bool());
36,792✔
3359

3360
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
36,792✔
3361
                "arguments to cmp are not the same type");
3362

3363
   return op->result;
3364
}
3365

3366
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
36,248✔
3367
                       const vcode_reg_t *args, int nargs)
3368
{
3369
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
36,248✔
3370
   o->func = func;
36,248✔
3371
   o->type = type;
36,248✔
3372
   for (int i = 0; i < nargs; i++)
142,258✔
3373
      vcode_add_arg(o, args[i]);
106,010✔
3374

3375
   for (int i = 0; i < nargs; i++)
142,258✔
3376
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
106,010✔
3377
                   "invalid argument to function");
3378

3379
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
36,248✔
3380
                "first argument to VHDL function must be context pointer");
3381

3382
   if (type == VCODE_INVALID_TYPE)
36,248✔
3383
      return (o->result = VCODE_INVALID_REG);
5,010✔
3384
   else {
3385
      o->result = vcode_add_reg(type);
31,238✔
3386

3387
      reg_t *rr = vcode_reg_data(o->result);
31,238✔
3388
      rr->bounds = bounds;
31,238✔
3389

3390
      return o->result;
31,238✔
3391
   }
3392
}
3393

3394
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
868✔
3395
                vcode_block_t resume_bb)
3396
{
3397
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
868✔
3398
   o->func = func;
868✔
3399
   for (int i = 0; i < nargs; i++)
3,085✔
3400
      vcode_add_arg(o, args[i]);
2,217✔
3401

3402
   vcode_block_array_add(&(o->targets), resume_bb);
868✔
3403

3404
   for (int i = 0; i < nargs; i++)
3,085✔
3405
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,217✔
3406
                   "invalid argument to procedure");
3407

3408
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
868✔
3409
                "first argument to VHDL procedure must be context pointer");
3410
}
868✔
3411

3412
vcode_reg_t emit_syscall(ident_t func, vcode_type_t type, vcode_type_t bounds,
345✔
3413
                         vcode_reg_t locus, const vcode_reg_t *args, int nargs)
3414
{
3415
   op_t *o = vcode_add_op(VCODE_OP_SYSCALL);
345✔
3416
   o->func = func;
345✔
3417
   o->type = type;
345✔
3418
   vcode_add_arg(o, locus);
345✔
3419
   for (int i = 0; i < nargs; i++)
420✔
3420
      vcode_add_arg(o, args[i]);
75✔
3421

3422
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
345✔
3423
                "locus argument to syscall must be a debug locus");
3424

3425
   for (int i = 0; i < nargs; i++)
420✔
3426
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG, "invalid argument to syscall");
75✔
3427

3428
   if (type == VCODE_INVALID_TYPE)
345✔
3429
      return (o->result = VCODE_INVALID_REG);
306✔
3430
   else {
3431
      o->result = vcode_add_reg(type);
39✔
3432

3433
      reg_t *rr = vcode_reg_data(o->result);
39✔
3434
      rr->bounds = bounds;
39✔
3435

3436
      return o->result;
39✔
3437
   }
3438
}
3439

3440
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
7,628✔
3441
                       vcode_reg_t count)
3442
{
3443
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
7,628✔
3444
   op->type    = type;
7,628✔
3445
   op->result  = vcode_add_reg(vtype_pointer(type));
7,628✔
3446
   vcode_add_arg(op, count);
7,628✔
3447

3448
   const vtype_kind_t tkind = vtype_kind(type);
7,628✔
3449
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
7,628✔
3450
                "alloca element type cannot be array");
3451
   VCODE_ASSERT(count != VCODE_INVALID_REG,
7,628✔
3452
                "alloca must have valid count argument");
3453

3454
   reg_t *r = vcode_reg_data(op->result);
7,628✔
3455
   r->bounds = bounds;
7,628✔
3456

3457
   return op->result;
7,628✔
3458
}
3459

3460
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
975,139✔
3461
{
3462
   // Reuse any previous constant in this block with the same type and value
3463
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
20,484,434✔
3464
      if (other->value == value && vtype_eq(type, other->type))
7,673,801✔
3465
         return other->result;
579,831✔
3466
   }
3467

3468
   op_t *op = vcode_add_op(VCODE_OP_CONST);
395,308✔
3469
   op->value  = value;
395,308✔
3470
   op->type   = type;
395,308✔
3471
   op->result = vcode_add_reg(type);
395,308✔
3472

3473
   vtype_kind_t type_kind = vtype_kind(type);
395,308✔
3474
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
395,308✔
3475
                "constant must have integer or offset type");
3476

3477
   reg_t *r = vcode_reg_data(op->result);
395,308✔
3478
   r->bounds = vtype_int(value, value);
395,308✔
3479

3480
   return op->result;
395,308✔
3481
}
3482

3483
vcode_reg_t emit_const_real(vcode_type_t type, double value)
39,186✔
3484
{
3485
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
1,431,435✔
3486
      if (other->real == value && other->type == type)
932,188✔
3487
         return other->result;
12,829✔
3488
   }
3489

3490
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
26,357✔
3491
   op->real   = value;
26,357✔
3492
   op->type   = type;
26,357✔
3493
   op->result = vcode_add_reg(op->type);
26,357✔
3494

3495
   reg_t *r = vcode_reg_data(op->result);
26,357✔
3496
   r->bounds = vtype_real(value, value);
26,357✔
3497

3498
   return op->result;
26,357✔
3499
}
3500

3501
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
27,393✔
3502
{
3503
   vtype_kind_t kind = vtype_kind(type);
27,393✔
3504

3505
   // Reuse any previous operation in this block with the same arguments
3506
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
1,157,059✔
3507
      if (other->args.count != num)
116,889✔
3508
         continue;
69,708✔
3509
      else if (!vtype_eq(vcode_reg_type(other->result), type))
47,181✔
3510
         continue;
650✔
3511

3512
      bool match = true;
3513
      for (int i = 0; match && i < num; i++) {
294,930✔
3514
         if (other->args.items[i] != values[i])
248,399✔
3515
            match = false;
40,470✔
3516
      }
3517

3518
      if (match) return other->result;
46,531✔
3519
   }
3520

3521
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
21,332✔
3522
   op->result = vcode_add_reg(type);
21,332✔
3523

3524
   for (int i = 0; i < num; i++)
1,184,543✔
3525
      vcode_add_arg(op, values[i]);
1,163,211✔
3526

3527
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
21,332✔
3528
                "constant array must have constrained array type");
3529
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
21,332✔
3530
                vtype_size(type), num);
3531

3532
#ifdef DEBUG
3533
   vcode_type_t elem = vtype_elem(type);
21,332✔
3534
   for (int i = 0; i < num; i++) {
1,184,543✔
3535
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
1,163,211✔
3536
                   "wrong element type for item %d", i);
3537
      vcode_assert_const(values[i], "array");
1,163,211✔
3538
   }
3539
#endif
3540

3541
   reg_t *r = vcode_reg_data(op->result);
21,332✔
3542
   r->bounds = vtype_elem(type);
21,332✔
3543

3544
   return op->result;
21,332✔
3545
}
3546

3547
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
1,073✔
3548
{
3549
   // Reuse any previous operation in this block with the same arguments
3550
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
22,097✔
3551
      if (other->args.items[0] == value && other->value == rep)
1,023✔
3552
         return other->result;
306✔
3553
   }
3554

3555
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
767✔
3556
   op->value = rep;
767✔
3557
   vcode_add_arg(op, value);
767✔
3558

3559
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
767✔
3560
                "constant array must have constrained array type");
3561

3562
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
767✔
3563

3564
   op->result = vcode_add_reg(type);
767✔
3565

3566
   reg_t *r = vcode_reg_data(op->result);
767✔
3567
   r->bounds = vtype_bounds(type);
767✔
3568

3569
   return op->result;
767✔
3570
}
3571

3572
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
2,823✔
3573
{
3574
   // Reuse any previous constant in this block with the same type and value
3575
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
57,377✔
3576
      if (other->args.count == num && vtype_eq(type, other->type)) {
1,628✔
3577
         bool same_regs = true;
3578
         for (int i = 0; same_regs && i < num; i++)
2,450✔
3579
            same_regs = other->args.items[i] == values[i];
1,466✔
3580

3581
         if (same_regs)
984✔
3582
            return other->result;
220✔
3583
      }
3584
   }
3585

3586
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
2,603✔
3587
   op->type   = type;
2,603✔
3588
   op->result = vcode_add_reg(type);
2,603✔
3589

3590
   for (int i = 0; i < num; i++)
9,919✔
3591
      vcode_add_arg(op, values[i]);
7,316✔
3592

3593
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
2,603✔
3594
                "constant record must have record type");
3595

3596
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
2,603✔
3597
                vtype_fields(type), num);
3598

3599
#ifdef DEBUG
3600
   for (int i = 0; i < num; i++) {
9,919✔
3601
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
7,316✔
3602
                   "wrong type for field %d", i);
3603
      vcode_assert_const(values[i], "record");
7,316✔
3604
   }
3605
#endif
3606

3607
   return op->result;
2,603✔
3608
}
3609

3610
vcode_reg_t emit_address_of(vcode_reg_t value)
29,694✔
3611
{
3612
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
1,253,125✔
3613
      if (other->args.items[0] == value)
118,222✔
3614
         return other->result;
6,113✔
3615
   }
3616

3617
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
23,581✔
3618
   vcode_add_arg(op, value);
23,581✔
3619

3620
   vcode_type_t type = vcode_reg_type(value);
23,581✔
3621
   VCODE_ASSERT(vtype_is_composite(type),
23,581✔
3622
                "address of argument must be record or array");
3623

3624
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
23,581✔
3625
      vcode_type_t elem = vtype_elem(type);
21,527✔
3626
      op->result = vcode_add_reg(vtype_pointer(elem));
21,527✔
3627

3628
      reg_t *rr = vcode_reg_data(op->result);
21,527✔
3629
      rr->bounds = elem;
21,527✔
3630

3631
      return op->result;
21,527✔
3632
   }
3633
   else
3634
      return (op->result = vcode_add_reg(vtype_pointer(type)));
2,054✔
3635
}
3636

3637
void emit_wait(vcode_block_t target, vcode_reg_t time)
13,475✔
3638
{
3639
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
13,475✔
3640
   vcode_add_target(op, target);
13,475✔
3641
   vcode_add_arg(op, time);
13,475✔
3642

3643
   VCODE_ASSERT(time == VCODE_INVALID_REG
13,475✔
3644
                || vcode_reg_kind(time) == VCODE_TYPE_INT,
3645
                "wait time must have integer type");
3646
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
13,475✔
3647
                || active_unit->kind == VCODE_UNIT_PROCESS,
3648
                "wait only allowed in process or procedure");
3649
}
13,475✔
3650

3651
void emit_jump(vcode_block_t target)
35,358✔
3652
{
3653
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
35,358✔
3654
   vcode_add_target(op, target);
35,358✔
3655

3656
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
35,358✔
3657
}
35,358✔
3658

3659
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
48,434✔
3660
                     vcode_var_flags_t flags)
3661
{
3662
   assert(active_unit != NULL);
48,434✔
3663

3664
   vcode_var_t var = active_unit->vars.count;
48,434✔
3665
   var_t *v = var_array_alloc(&(active_unit->vars));
48,434✔
3666
   memset(v, '\0', sizeof(var_t));
48,434✔
3667
   v->type     = type;
48,434✔
3668
   v->bounds   = bounds;
48,434✔
3669
   v->name     = name;
48,434✔
3670
   v->flags    = flags;
48,434✔
3671

3672
   return var;
48,434✔
3673
}
3674

3675
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
31,211✔
3676
{
3677
   assert(active_unit != NULL);
31,211✔
3678

3679
   param_t *p = param_array_alloc(&(active_unit->params));
31,211✔
3680
   memset(p, '\0', sizeof(param_t));
31,211✔
3681
   p->type   = type;
31,211✔
3682
   p->bounds = bounds;
31,211✔
3683
   p->name   = name;
31,211✔
3684
   p->reg    = vcode_add_reg(type);
31,211✔
3685

3686
   reg_t *rr = vcode_reg_data(p->reg);
31,211✔
3687
   rr->bounds = bounds;
31,211✔
3688

3689
   return p->reg;
31,211✔
3690
}
3691

3692
vcode_reg_t emit_load(vcode_var_t var)
53,716✔
3693
{
3694
   // Try scanning backwards through the block for another load or store to
3695
   // this variable
3696
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
53,716✔
3697
   vcode_reg_t fold = VCODE_INVALID_REG;
53,716✔
3698
   VCODE_FOR_EACH_OP(other) {
621,327✔
3699
      switch (state) {
584,417✔
3700
      case EAGER:
308,204✔
3701
         if (other->kind == VCODE_OP_LOAD && other->address == var)
308,204✔
3702
            return other->result;
3,119✔
3703
         else if (other->kind == VCODE_OP_STORE && other->address == var)
305,085✔
3704
            return other->args.items[0];
13,687✔
3705
         else if (other->kind == VCODE_OP_FCALL
291,398✔
3706
                  || other->kind == VCODE_OP_PCALL
291,398✔
3707
                  || other->kind == VCODE_OP_FILE_READ
3708
                  || other->kind == VCODE_OP_FILE_OPEN
3709
                  || other->kind == VCODE_OP_STORE_INDIRECT
3710
                  || other->kind == VCODE_OP_DEALLOCATE)
3711
            state = CONSERVATIVE;   // May write to variable
7,961✔
3712
         break;
3713

3714
      case CONSERVATIVE:
251,666✔
3715
         if (other->kind == VCODE_OP_LOAD && other->address == var
251,666✔
3716
             && fold == VCODE_INVALID_REG)
4,276✔
3717
            fold = other->result;
3,429✔
3718
         else if (other->kind == VCODE_OP_STORE && other->address == var
248,237✔
3719
                  && fold == VCODE_INVALID_REG)
1,607✔
3720
            fold = other->args.items[0];
1,476✔
3721
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
246,761✔
3722
            state = UNSAFE;
3723
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
245,767✔
3724
            state = UNSAFE;   // Nested call captures variables
80✔
3725
         break;
3726

3727
      case UNSAFE:
3728
         break;
3729
      }
3730
   }
3731

3732
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
36,910✔
3733
      return fold;
3734

3735
   var_t *v = vcode_var_data(var);
32,352✔
3736

3737
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
32,352✔
3738
   op->address = var;
32,352✔
3739
   op->result  = vcode_add_reg(v->type);
32,352✔
3740

3741
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
32,352✔
3742

3743
   reg_t *r = vcode_reg_data(op->result);
32,352✔
3744
   r->bounds = v->bounds;
32,352✔
3745

3746
   return op->result;
32,352✔
3747
}
3748

3749
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
91,550✔
3750
{
3751
   VCODE_FOR_EACH_OP(other) {
1,058,751✔
3752
      if (other->kind == VCODE_OP_LOAD_INDIRECT
993,653✔
3753
          && other->args.items[0] == reg) {
144,000✔
3754
         return other->result;
7,113✔
3755
      }
3756
      else if (other->kind == VCODE_OP_FCALL
986,540✔
3757
               || other->kind == VCODE_OP_PCALL
986,540✔
3758
               || other->kind == VCODE_OP_STORE
3759
               || other->kind == VCODE_OP_STORE_INDIRECT
3760
               || other->kind == VCODE_OP_MEMSET
3761
               || other->kind == VCODE_OP_COPY
3762
               || other->kind == VCODE_OP_FILE_READ)
3763
         break;   // May write to this pointer
3764
   }
3765

3766
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
84,437✔
3767
   vcode_add_arg(op, reg);
84,437✔
3768

3769
   vcode_type_t rtype = vcode_reg_type(reg);
84,437✔
3770

3771
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
84,437✔
3772
                "load indirect with non-pointer argument");
3773

3774
   vcode_type_t deref = vtype_pointed(rtype);
84,437✔
3775
   op->result = vcode_add_reg(deref);
84,437✔
3776

3777
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
84,437✔
3778

3779
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
84,437✔
3780

3781
   return op->result;
84,437✔
3782
}
3783

3784
void emit_store(vcode_reg_t reg, vcode_var_t var)
58,531✔
3785
{
3786
   // Any previous store to this variable in this block is dead
3787
   VCODE_FOR_EACH_OP(other) {
1,111,973✔
3788
      if (other->kind == VCODE_OP_STORE && other->address == var) {
1,065,238✔
3789
         other->kind = VCODE_OP_COMMENT;
261✔
3790
         other->comment =
522✔
3791
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
261✔
3792
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
261✔
3793
      }
3794
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
1,064,977✔
3795
         break;   // Needs to get variable for display
3796
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
1,059,071✔
3797
               && other->address == var)
24,070✔
3798
         break;   // Previous value may be used
3799
   }
3800

3801
   var_t *v = vcode_var_data(var);
58,531✔
3802
   reg_t *r = vcode_reg_data(reg);
58,531✔
3803

3804
   op_t *op = vcode_add_op(VCODE_OP_STORE);
58,531✔
3805
   vcode_add_arg(op, reg);
58,531✔
3806
   op->address = var;
58,531✔
3807

3808
   VCODE_ASSERT(vtype_eq(v->type, r->type),
58,531✔
3809
                "variable and stored value do not have same type");
3810
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
58,531✔
3811
}
58,531✔
3812

3813
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
12,394✔
3814
{
3815
   reg_t *p = vcode_reg_data(ptr);
12,394✔
3816
   reg_t *r = vcode_reg_data(reg);
12,394✔
3817

3818
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
12,394✔
3819
   vcode_add_arg(op, reg);
12,394✔
3820
   vcode_add_arg(op, ptr);
12,394✔
3821

3822
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
12,394✔
3823
                "store indirect target is not a pointer");
3824
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
12,394✔
3825
                "pointer and stored value do not have same type");
3826
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
12,394✔
3827
}
12,394✔
3828

3829
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
50,626✔
3830
                              vcode_reg_t locus)
3831
{
3832
   // Reuse any previous operation in this block with the same arguments
3833
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,052,699✔
3834
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
59,388✔
3835
         return other->result;
3,000✔
3836
   }
3837

3838
   op_t *op = vcode_add_op(kind);
47,626✔
3839
   vcode_add_arg(op, lhs);
47,626✔
3840
   vcode_add_arg(op, rhs);
47,626✔
3841
   if (locus != VCODE_INVALID_REG)
47,626✔
3842
      vcode_add_arg(op, locus);
4,991✔
3843

3844
   op->result = vcode_add_reg(vcode_reg_type(lhs));
47,626✔
3845

3846
   vcode_type_t lhs_type = vcode_reg_type(lhs);
47,626✔
3847
   vcode_type_t rhs_type = vcode_reg_type(rhs);
47,626✔
3848

3849
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
47,626✔
3850
                "arguments to %s are not the same type", vcode_op_string(kind));
3851

3852
   return op->result;
3853
}
3854

3855
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
34,653✔
3856
                               vcode_reg_t locus)
3857
{
3858
   int64_t lconst, rconst;
34,653✔
3859
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
34,653✔
3860
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
34,653✔
3861
   if (l_is_const && r_is_const)
34,653✔
3862
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
19,421✔
3863
   else if (r_is_const && rconst == 1)
15,232✔
3864
      return lhs;
3865
   else if (l_is_const && lconst == 1)
3,548✔
3866
      return rhs;
3867
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
3,076✔
3868
      return emit_const(vcode_reg_type(lhs), 0);
51✔
3869

3870
   reg_t *lhs_r = vcode_reg_data(lhs);
3,025✔
3871
   reg_t *rhs_r = vcode_reg_data(rhs);
3,025✔
3872

3873
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
3,025✔
3874
   vtype_t *br = vcode_type_data(rhs_r->bounds);
3,025✔
3875

3876
   vcode_type_t vbounds;
3,025✔
3877
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
3,025✔
3878
      const double ll = bl->rlow * br->rlow;
740✔
3879
      const double lh = bl->rlow * br->rhigh;
740✔
3880
      const double hl = bl->rhigh * br->rlow;
740✔
3881
      const double hh = bl->rhigh * br->rhigh;
740✔
3882

3883
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
1,596✔
3884
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
1,818✔
3885

3886
      vbounds = vtype_real(min, max);
740✔
3887
   }
3888
   else {
3889
      const int64_t ll = smul64(bl->low, br->low);
2,285✔
3890
      const int64_t lh = smul64(bl->low, br->high);
2,285✔
3891
      const int64_t hl = smul64(bl->high, br->low);
2,285✔
3892
      const int64_t hh = smul64(bl->high, br->high);
2,285✔
3893

3894
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
2,285✔
3895
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
2,285✔
3896

3897
      vtype_repr_t repr = vtype_repr(lhs_r->type);
2,285✔
3898
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
2,285✔
3899
         op = VCODE_OP_MUL;   // Cannot overflow
400✔
3900
         locus = VCODE_INVALID_REG;
400✔
3901
      }
3902

3903
      vbounds = vtype_int(min, max);
2,285✔
3904
   }
3905

3906
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
3,025✔
3907

3908
   if (vbounds != VCODE_INVALID_TYPE)
3,025✔
3909
      vcode_reg_data(reg)->bounds = vbounds;
3,025✔
3910

3911
   return reg;
3912
}
3913

3914
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
33,753✔
3915
{
3916
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
33,753✔
3917
}
3918

3919
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
900✔
3920
{
3921
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
900✔
3922

3923
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
900✔
3924
                "trapping add may only be used with integer types");
3925

3926
   return result;
900✔
3927
}
3928

3929
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
1,025✔
3930
{
3931
   int64_t lconst, rconst;
1,025✔
3932
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
1,025✔
3933
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
1,025✔
3934
   if (l_is_const && r_is_const && rconst != 0)
1,025✔
3935
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
32✔
3936
   else if (r_is_const && rconst == 1)
993✔
3937
      return lhs;
3938

3939
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
992✔
3940

3941
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
992✔
3942

3943
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
992✔
3944
      reg_t *rr = vcode_reg_data(reg);
699✔
3945
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
699✔
3946
   }
3947
   else if (bl->kind == VCODE_TYPE_REAL) {
293✔
3948
      reg_t *rr = vcode_reg_data(reg);
225✔
3949
      rr->bounds = vtype_real(-INFINITY, INFINITY);
225✔
3950
   }
3951

3952
   return reg;
3953
}
3954

3955
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
79✔
3956
{
3957
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
79✔
3958
}
3959

3960
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
1,572✔
3961
{
3962
   int64_t rconst;
1,572✔
3963
   if (vcode_reg_const(rhs, &rconst)) {
1,572✔
3964
      if (rconst == 0)
1,463✔
3965
         return emit_const(vcode_reg_type(lhs), 1);
799✔
3966
      else if (rconst == 1)
664✔
3967
         return lhs;
3968
   }
3969

3970
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
580✔
3971

3972
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
580✔
3973
                "trapping exp may only be used with integer types");
3974

3975
   return result;
3976
}
3977

3978
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
222✔
3979
{
3980
   int64_t lconst, rconst;
222✔
3981
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
222✔
3982
       && lconst > 0 && rconst > 0)
15✔
3983
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
3✔
3984

3985
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
219✔
3986
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
219✔
3987

3988
   if (bl->low >= 0 && br->low >= 0) {
219✔
3989
      // If both arguments are non-negative then rem is equivalent and
3990
      // cheaper to compute
3991
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
48✔
3992

3993
      reg_t *rr = vcode_reg_data(reg);
48✔
3994
      rr->bounds = vtype_int(0, MAX(0, br->high - 1));
48✔
3995

3996
      return reg;
48✔
3997
   }
3998
   else
3999
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
171✔
4000
}
4001

4002
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
95✔
4003
{
4004
   int64_t lconst, rconst;
95✔
4005
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
95✔
4006
       && lconst > 0 && rconst > 0)
2✔
4007
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4008

4009
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
95✔
4010

4011
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
95✔
4012
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
95✔
4013

4014
   if (bl->low >= 0 && br->low >= 0) {
95✔
4015
      reg_t *rr = vcode_reg_data(reg);
36✔
4016
      rr->bounds = vtype_int(0, br->high - 1);
36✔
4017
   }
4018

4019
   return reg;
4020
}
4021

4022
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
43,187✔
4023
                               vcode_reg_t locus)
4024
{
4025
   int64_t lconst, rconst;
43,187✔
4026
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
43,187✔
4027
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
43,187✔
4028
   if (l_is_const && r_is_const)
43,187✔
4029
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
17,358✔
4030
   else if (r_is_const && rconst == 0)
25,829✔
4031
      return lhs;
4032
   else if (l_is_const && lconst == 0)
25,823✔
4033
      return rhs;
4034

4035
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
15,950✔
4036
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
15,950✔
4037
      reg_t *lhs_r = vcode_reg_data(lhs);
15,663✔
4038
      reg_t *rhs_r = vcode_reg_data(rhs);
15,663✔
4039

4040
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
15,663✔
4041
      vtype_t *br = vcode_type_data(rhs_r->bounds);
15,663✔
4042

4043
      int64_t rbl = sadd64(bl->low, br->low);
15,663✔
4044
      int64_t rbh = sadd64(bl->high, br->high);
15,663✔
4045

4046
      vtype_repr_t repr = vtype_repr(lhs_r->type);
15,663✔
4047
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
15,663✔
4048
         op = VCODE_OP_ADD;   // Cannot overflow
776✔
4049
         locus = VCODE_INVALID_REG;
776✔
4050
      }
4051

4052
      vbounds = vtype_int(rbl, rbh);
15,663✔
4053
   }
4054

4055
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
15,950✔
4056

4057
   if (vbounds != VCODE_INVALID_TYPE)
15,950✔
4058
      vcode_reg_data(reg)->bounds = vbounds;
15,663✔
4059

4060
   return reg;
4061
}
4062

4063
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
40,327✔
4064
{
4065
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
40,327✔
4066
}
4067

4068
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
2,860✔
4069
{
4070
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
2,860✔
4071

4072
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
2,860✔
4073
                "trapping add may only be used with integer types");
4074

4075
   return result;
2,860✔
4076
}
4077

4078
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
40,036✔
4079
                               vcode_reg_t locus)
4080
{
4081
   int64_t lconst, rconst;
40,036✔
4082
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
40,036✔
4083
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
40,036✔
4084
   if (l_is_const && r_is_const)
40,036✔
4085
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
13,464✔
4086
   else if (r_is_const && rconst == 0)
26,572✔
4087
      return lhs;
4088
   else if (l_is_const && lconst == 0)
24,388✔
4089
      return emit_neg(rhs);
1,302✔
4090

4091
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
23,086✔
4092
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
23,086✔
4093
      reg_t *lhs_r = vcode_reg_data(lhs);
22,780✔
4094
      reg_t *rhs_r = vcode_reg_data(rhs);
22,780✔
4095

4096
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
22,780✔
4097
      vtype_t *br = vcode_type_data(rhs_r->bounds);
22,780✔
4098

4099
      int64_t rbl = ssub64(bl->low, br->high);
22,780✔
4100
      int64_t rbh = ssub64(bl->high, br->low);
22,780✔
4101

4102
      vtype_repr_t repr = vtype_repr(lhs_r->type);
22,780✔
4103
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
22,780✔
4104
         op = VCODE_OP_SUB;   // Cannot overflow
3,019✔
4105
         locus = VCODE_INVALID_REG;
3,019✔
4106
      }
4107

4108
      vbounds = vtype_int(rbl, rbh);
22,780✔
4109
   }
4110

4111
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
23,086✔
4112

4113
   if (vbounds != VCODE_INVALID_TYPE)
23,086✔
4114
      vcode_reg_data(reg)->bounds = vbounds;
22,780✔
4115

4116
   return reg;
4117
}
4118

4119
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
33,414✔
4120
{
4121
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
33,414✔
4122
}
4123

4124
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
6,622✔
4125
{
4126
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
6,622✔
4127

4128
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
6,622✔
4129
                "trapping sub may only be used with integer types");
4130

4131
   return result;
6,622✔
4132
}
4133

4134
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
60,813✔
4135
{
4136
   switch (vtype_kind(var->type)) {
60,813✔
4137
   case VCODE_TYPE_CARRAY:
12,322✔
4138
      op->type = vtype_pointer(vtype_elem(var->type));
12,322✔
4139
      op->result = vcode_add_reg(op->type);
12,322✔
4140
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
12,322✔
4141
      break;
12,322✔
4142

4143
   case VCODE_TYPE_RECORD:
6,218✔
4144
      op->type = vtype_pointer(var->type);
6,218✔
4145
      op->result = vcode_add_reg(op->type);
6,218✔
4146
      break;
6,218✔
4147

4148
   case VCODE_TYPE_INT:
42,273✔
4149
   case VCODE_TYPE_FILE:
4150
   case VCODE_TYPE_ACCESS:
4151
   case VCODE_TYPE_REAL:
4152
   case VCODE_TYPE_UARRAY:
4153
   case VCODE_TYPE_POINTER:
4154
   case VCODE_TYPE_SIGNAL:
4155
   case VCODE_TYPE_CONTEXT:
4156
   case VCODE_TYPE_OFFSET:
4157
   case VCODE_TYPE_TRIGGER:
4158
      op->type = vtype_pointer(var->type);
42,273✔
4159
      op->result = vcode_add_reg(op->type);
42,273✔
4160
      vcode_reg_data(op->result)->bounds = var->bounds;
42,273✔
4161
      break;
42,273✔
4162

4163
   default:
4164
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4165
                   istr(var->name));
4166
   }
4167
}
60,813✔
4168

4169
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
23,225✔
4170
{
4171
   // Try to find a previous index of this var by this offset
4172
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
783,859✔
4173
      if (other->address == var
50,701✔
4174
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
7,500✔
4175
              || (offset != VCODE_INVALID_REG
×
4176
                  && other->args.items[0] == offset)))
×
4177
         return other->result;
7,500✔
4178
   }
4179

4180
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
15,725✔
4181
   op->address = var;
15,725✔
4182

4183
   if (offset != VCODE_INVALID_REG)
15,725✔
4184
      vcode_add_arg(op, offset);
×
4185

4186
   vcode_calculate_var_index_type(op, vcode_var_data(var));
15,725✔
4187

4188
   if (offset != VCODE_INVALID_REG)
15,725✔
4189
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4190
                   "index offset r%d does not have offset type", offset);
4191

4192
   return op->result;
15,725✔
4193
}
4194

4195
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
208,237✔
4196
{
4197
   if (vtype_eq(vcode_reg_type(reg), type))
208,237✔
4198
      return reg;
208,237✔
4199

4200
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
77,389✔
4201
   vtype_kind_t to   = vtype_kind(type);
77,389✔
4202

4203
   const bool integral =
154,778✔
4204
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
77,389✔
4205
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
77,389✔
4206

4207
   int64_t value;
77,389✔
4208
   if (integral && vcode_reg_const(reg, &value))
77,389✔
4209
      return emit_const(type, value);
15,163✔
4210

4211
   // Try to find a previous cast of this register to this type
4212
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,221,512✔
4213
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
137,906✔
4214
         return other->result;
14,434✔
4215
   }
4216

4217
   op_t *op = vcode_add_op(VCODE_OP_CAST);
47,792✔
4218
   vcode_add_arg(op, reg);
47,792✔
4219
   op->type   = type;
47,792✔
4220
   op->result = vcode_add_reg(type);
47,792✔
4221

4222
   static const vcode_type_t allowed[][2] = {
47,792✔
4223
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4224
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4225
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4226
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4227
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4228
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4229
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4230
   };
4231

4232
   if (from == VCODE_TYPE_INT && bounds == VCODE_INVALID_TYPE) {
47,792✔
4233
      reg_t *rr = vcode_reg_data(op->result);
10,287✔
4234
      rr->bounds = vcode_reg_bounds(reg);
10,287✔
4235
   }
4236
   else if (to == VCODE_TYPE_INT && bounds != VCODE_INVALID_TYPE) {
37,505✔
4237
      reg_t *rr = vcode_reg_data(op->result);
31,116✔
4238
      rr->bounds = bounds;
31,116✔
4239
   }
4240

4241
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
87,289✔
4242
      if (from == allowed[i][0] && to == allowed[i][1])
87,289✔
4243
         return op->result;
4244
   }
4245

4246
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4247
}
4248

4249
void emit_return(vcode_reg_t reg)
52,838✔
4250
{
4251
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
52,838✔
4252
   if (reg != VCODE_INVALID_REG) {
52,838✔
4253
      vcode_add_arg(op, reg);
28,596✔
4254

4255
      const vtype_kind_t rkind = vcode_reg_kind(reg);
28,596✔
4256
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
28,596✔
4257
         vcode_heap_allocate(reg);
8,226✔
4258
         active_unit->flags |= UNIT_ESCAPING_TLAB;
8,226✔
4259
      }
4260

4261
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
28,596✔
4262
                   || active_unit->kind == VCODE_UNIT_THUNK
4263
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4264
                   "returning value fron non-function unit");
4265
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
28,596✔
4266
                    && rkind == VCODE_TYPE_INT)
4267
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4268
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4269
                       && rkind == VCODE_TYPE_ACCESS),
4270
                   "return value incorrect type");
4271
   }
4272
}
52,838✔
4273

4274
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
10,594✔
4275
                         vcode_reg_t values, vcode_reg_t reject,
4276
                         vcode_reg_t after)
4277
{
4278
   int64_t nconst;
10,594✔
4279
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
10,594✔
4280
      emit_comment("Skip empty waveform");
6✔
4281
      return;
6✔
4282
   }
4283

4284
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
10,588✔
4285
   vcode_add_arg(op, nets);
10,588✔
4286
   vcode_add_arg(op, nnets);
10,588✔
4287
   vcode_add_arg(op, values);
10,588✔
4288
   vcode_add_arg(op, reject);
10,588✔
4289
   vcode_add_arg(op, after);
10,588✔
4290

4291
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
10,588✔
4292
                "sched_waveform target is not signal");
4293
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
10,588✔
4294
                "sched_waveform net count is not offset type");
4295
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
10,588✔
4296
                "signal cannot be values argument for sched_waveform");
4297
}
4298

4299
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
60✔
4300
{
4301
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
60✔
4302
   vcode_add_arg(op, nets);
60✔
4303
   vcode_add_arg(op, nnets);
60✔
4304
   vcode_add_arg(op, values);
60✔
4305

4306
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
60✔
4307
                "force target is not signal");
4308
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
60✔
4309
                "force net count is not offset type");
4310
}
60✔
4311

4312
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
30✔
4313
{
4314
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
30✔
4315
   vcode_add_arg(op, nets);
30✔
4316
   vcode_add_arg(op, nnets);
30✔
4317

4318
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
30✔
4319
                "release target is not signal");
4320
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
30✔
4321
                "release net count is not offset type");
4322
}
30✔
4323

4324
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
21✔
4325
                     vcode_reg_t after)
4326
{
4327
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
21✔
4328
   vcode_add_arg(op, nets);
21✔
4329
   vcode_add_arg(op, nnets);
21✔
4330
   vcode_add_arg(op, reject);
21✔
4331
   vcode_add_arg(op, after);
21✔
4332

4333
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
21✔
4334
                "disconnect target is not signal");
4335
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
21✔
4336
                "disconnect net count is not offset type");
4337
}
21✔
4338

4339
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
36,847✔
4340
{
4341
   int64_t tconst;
36,847✔
4342
   if (vcode_reg_const(test, &tconst)) {
36,847✔
4343
      emit_jump(!!tconst ? btrue : bfalse);
4,830✔
4344
      return;
2,852✔
4345
   }
4346

4347
   op_t *op = vcode_add_op(VCODE_OP_COND);
33,995✔
4348
   vcode_add_arg(op, test);
33,995✔
4349
   vcode_add_target(op, btrue);
33,995✔
4350
   vcode_add_target(op, bfalse);
33,995✔
4351

4352
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
33,995✔
4353
                "cond test is not a bool");
4354
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
33,995✔
4355
                "invalid cond targets");
4356
}
4357

4358
vcode_reg_t emit_neg(vcode_reg_t lhs)
7,478✔
4359
{
4360
   int64_t lconst;
7,478✔
4361
   if (vcode_reg_const(lhs, &lconst))
7,478✔
4362
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4363

4364
   op_t *op = vcode_add_op(VCODE_OP_NEG);
7,478✔
4365
   vcode_add_arg(op, lhs);
7,478✔
4366
   op->result = vcode_add_reg(vcode_reg_type(lhs));
7,478✔
4367

4368
   return op->result;
7,478✔
4369
}
4370

4371
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
785✔
4372
{
4373
   int64_t lconst;
785✔
4374
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
785✔
4375
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4376
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
785✔
4377
      return emit_neg(lhs);   // Cannot overflow
219✔
4378

4379
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
566✔
4380
   vcode_add_arg(op, lhs);
566✔
4381
   vcode_add_arg(op, locus);
566✔
4382

4383
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
566✔
4384
                "locus argument to trap neg must be a debug locus");
4385
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
566✔
4386
                "trapping neg may only be used with integer types");
4387

4388
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
566✔
4389
}
4390

4391
vcode_reg_t emit_abs(vcode_reg_t lhs)
245✔
4392
{
4393
   int64_t lconst;
245✔
4394
   if (vcode_reg_const(lhs, &lconst))
245✔
4395
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4396

4397
   op_t *op = vcode_add_op(VCODE_OP_ABS);
244✔
4398
   vcode_add_arg(op, lhs);
244✔
4399
   op->result = vcode_add_reg(vcode_reg_type(lhs));
244✔
4400

4401
   return op->result;
244✔
4402
}
4403

4404
void emit_comment(const char *fmt, ...)
43,985✔
4405
{
4406
#ifndef NDEBUG
4407
   va_list ap;
43,985✔
4408
   va_start(ap, fmt);
43,985✔
4409

4410
   char *buf = xvasprintf(fmt, ap);
43,985✔
4411
   for (char *p = buf + strlen(buf) - 1;
43,985✔
4412
        p >= buf && isspace_iso88591(*p); p--)
43,985✔
4413
      *p = '\0';
×
4414

4415
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
43,985✔
4416
   va_end(ap);
43,985✔
4417
#endif
4418
}
43,985✔
4419

4420
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
18,390✔
4421
                        vcode_reg_t rfalse)
4422
{
4423
   int64_t tconst;
18,390✔
4424
   if (vcode_reg_const(test, &tconst))
18,390✔
4425
      return !!tconst ? rtrue : rfalse;
4,390✔
4426
   else if (rtrue == rfalse)
14,000✔
4427
      return rtrue;
4428

4429
   // Find a previous identical select
4430
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
301,866✔
4431
      if (other->args.items[0] == test && other->args.items[1] == rtrue
12,487✔
4432
          && other->args.items[2] == rfalse)
702✔
4433
         return other->result;
641✔
4434
   }
4435

4436
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
13,123✔
4437
   vcode_add_arg(op, test);
13,123✔
4438
   vcode_add_arg(op, rtrue);
13,123✔
4439
   vcode_add_arg(op, rfalse);
13,123✔
4440
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
13,123✔
4441

4442
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
13,123✔
4443
                "select test must have bool type");
4444
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
13,123✔
4445
                "select arguments are not the same type");
4446

4447
   return op->result;
13,123✔
4448
}
4449

4450
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
388✔
4451
{
4452
   switch (op) {
388✔
4453
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
24✔
4454
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
316✔
4455
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
12✔
4456
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
12✔
4457
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
12✔
4458
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
12✔
4459
   default:
×
4460
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4461
   }
4462
}
4463

4464
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
7,021✔
4465
{
4466
   vcode_type_t vtbool = vtype_bool();
7,021✔
4467

4468
   int64_t lconst, rconst;
7,021✔
4469
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
7,021✔
4470
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
7,021✔
4471
   if (l_is_const && r_is_const) {
7,021✔
4472
      switch (op) {
6✔
4473
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4474
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4475
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4476
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
6✔
4477
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
4478
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
4479
      default:
×
4480
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4481
      }
4482
   }
4483
   else if (l_is_const)
7,015✔
4484
      return emit_logical_identity(op, rhs, !!lconst);
309✔
4485
   else if (r_is_const)
6,706✔
4486
      return emit_logical_identity(op, lhs, !!rconst);
79✔
4487
   else if (lhs == rhs) {
6,627✔
4488
      switch (op) {
27✔
4489
      case VCODE_OP_AND:
4490
      case VCODE_OP_OR:
4491
         return lhs;
4492
      case VCODE_OP_NAND:
6✔
4493
      case VCODE_OP_NOR:
4494
         return emit_not(lhs);
6✔
4495
      case VCODE_OP_XOR:
3✔
4496
         return emit_const(vtbool, 0);
3✔
4497
      case VCODE_OP_XNOR:
×
4498
         return emit_const(vtbool, 1);
×
4499
      default:
×
4500
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4501
      }
4502
   }
4503

4504
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
6,600✔
4505

4506
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
6,600✔
4507
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4508
                "arguments to %s are not boolean", vcode_op_string(op));
4509

4510
   return result;
4511
}
4512

4513
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
2,136✔
4514
{
4515
   return emit_logical(VCODE_OP_OR, lhs, rhs);
2,136✔
4516
}
4517

4518
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
4,517✔
4519
{
4520
   return emit_logical(VCODE_OP_AND, lhs, rhs);
4,517✔
4521
}
4522

4523
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
80✔
4524
{
4525
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
80✔
4526
}
4527

4528
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
81✔
4529
{
4530
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
81✔
4531
}
4532

4533
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
122✔
4534
{
4535
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
122✔
4536
}
4537

4538
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
85✔
4539
{
4540
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
85✔
4541
}
4542

4543
vcode_reg_t emit_not(vcode_reg_t arg)
2,721✔
4544
{
4545
   int64_t cval;
2,721✔
4546
   if (vcode_reg_const(arg, &cval))
2,721✔
4547
      return emit_const(vtype_bool(), !cval);
27✔
4548

4549
   op_t *op = vcode_add_op(VCODE_OP_NOT);
2,694✔
4550
   vcode_add_arg(op, arg);
2,694✔
4551

4552
   vcode_type_t vtbool = vtype_bool();
2,694✔
4553
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
2,694✔
4554
                "argument to not is not boolean");
4555

4556
   return (op->result = vcode_add_reg(vtbool));
2,694✔
4557
}
4558

4559
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
46,673✔
4560
{
4561
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
1,556,727✔
4562
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
145,067✔
4563
         bool match = true;
4564
         for (int i = 0; match && i < ndims; i++) {
20,935✔
4565
            match = other->args.items[i*3 + 1] == dims[i].left
10,495✔
4566
               && other->args.items[i*3 + 2] == dims[i].right
9,036✔
4567
               && other->args.items[i*3 + 3] == dims[i].dir;
19,424✔
4568
         }
4569
         if (match)
10,440✔
4570
            return other->result;
8,874✔
4571
      }
4572
   }
4573

4574
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
37,799✔
4575
   vcode_add_arg(op, data);
37,799✔
4576
   for (int i = 0; i < ndims; i++) {
76,087✔
4577
      vcode_add_arg(op, dims[i].left);
38,288✔
4578
      vcode_add_arg(op, dims[i].right);
38,288✔
4579
      vcode_add_arg(op, dims[i].dir);
38,288✔
4580
   }
4581

4582
   vcode_type_t ptr_type = vcode_reg_type(data);
37,799✔
4583
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
37,799✔
4584
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
37,799✔
4585
                "wrapped data is not pointer or signal");
4586

4587
#ifdef DEBUG
4588
   for (int i = 0; i < ndims; i++) {
76,087✔
4589
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
38,288✔
4590
                   "dimension %d left bound must be scalar", i + 1);
4591
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
38,288✔
4592
                   "dimension %d right bound must be scalar", i + 1);
4593
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
38,288✔
4594
                   "dimension %d direction must be bool", i + 1);
4595
   }
4596
#endif
4597

4598
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
75,598✔
4599
      ? vtype_pointed(ptr_type) : ptr_type;
37,799✔
4600

4601
   op->result = vcode_add_reg(
37,799✔
4602
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4603

4604
   return op->result;
37,799✔
4605
}
4606

4607
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
109,481✔
4608
                                  vcode_reg_t array, unsigned dim,
4609
                                  unsigned arg_index)
4610
{
4611
   // Reuse any previous operation in this block with the same arguments
4612
   VCODE_FOR_EACH_OP(other) {
1,187,879✔
4613
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,137,600✔
4614
          && (rtype == VCODE_INVALID_TYPE
23,044✔
4615
              || vtype_eq(rtype, vcode_reg_type(other->result))))
9,694✔
4616
         return other->result;
23,044✔
4617
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,114,556✔
4618
         return other->args.items[1 + (dim * 3) + arg_index];
36,158✔
4619
   }
4620

4621
   op_t *op = vcode_add_op(o);
50,279✔
4622
   vcode_add_arg(op, array);
50,279✔
4623
   op->dim = dim;
50,279✔
4624

4625
   vcode_type_t atype = vcode_reg_type(array);
50,279✔
4626
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
50,279✔
4627
                "cannot use %s with non-uarray type", vcode_op_string(o));
4628

4629
   vtype_t *vt = vcode_type_data(atype);
50,279✔
4630
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
50,279✔
4631

4632
   if (rtype == VCODE_INVALID_TYPE)
50,279✔
4633
      rtype = vtype_offset();
32,744✔
4634

4635
   return (op->result = vcode_add_reg(rtype));
50,279✔
4636
}
4637

4638
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
39,646✔
4639
{
4640
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
39,646✔
4641
                         array, dim, 0);
4642
}
4643

4644
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
30,508✔
4645
{
4646
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
30,508✔
4647
                         array, dim, 1);
4648
}
4649

4650
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
39,327✔
4651
{
4652
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
39,327✔
4653
                         array, dim, 2);
4654
}
4655

4656
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
50,260✔
4657
{
4658
   VCODE_FOR_EACH_OP(other) {
521,143✔
4659
      if (other->kind == VCODE_OP_UARRAY_LEN) {
497,061✔
4660
         if (other->args.items[0] == array && other->dim == dim)
34,851✔
4661
            return other->result;
11,185✔
4662
      }
4663
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
462,210✔
4664
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
14,993✔
4665
                      "array dimension %d out of bounds", dim);
4666

4667
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
14,993✔
4668
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
14,993✔
4669
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
14,993✔
4670
         return emit_range_length(left_reg, right_reg, dir_reg);
14,993✔
4671
      }
4672
   }
4673

4674
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
24,082✔
4675
   vcode_add_arg(op, array);
24,082✔
4676
   op->dim = dim;
24,082✔
4677

4678
   vcode_type_t atype = vcode_reg_type(array);
24,082✔
4679
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
24,082✔
4680
                "cannot use uarray len with non-uarray type");
4681

4682
   vtype_t *vt = vcode_type_data(atype);
24,082✔
4683
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
24,082✔
4684

4685
   return (op->result = vcode_add_reg(vtype_offset()));
24,082✔
4686
}
4687

4688
vcode_reg_t emit_unwrap(vcode_reg_t array)
38,024✔
4689
{
4690
   VCODE_FOR_EACH_OP(other) {
1,532,019✔
4691
      if (other->kind == VCODE_OP_WRAP && other->result == array)
1,504,937✔
4692
         return other->args.items[0];
9,504✔
4693
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
1,495,433✔
4694
         return other->result;
1,438✔
4695
   }
4696

4697
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
27,082✔
4698
   vcode_add_arg(op, array);
27,082✔
4699

4700
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
27,082✔
4701
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
27,082✔
4702
                "unwrap can only only be used with uarray types");
4703

4704
   vcode_type_t elem = vt->elem;
27,082✔
4705

4706
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
27,082✔
4707
      ? elem : vtype_pointer(elem);
27,082✔
4708

4709
   op->result = vcode_add_reg(rtype);
27,082✔
4710

4711
   reg_t *rr = vcode_reg_data(op->result);
27,082✔
4712
   rr->bounds = elem;
27,082✔
4713

4714
   return op->result;
27,082✔
4715
}
4716

4717
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
17,676✔
4718
                            vcode_reg_t dir)
4719
{
4720
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
549,146✔
4721
      if (other->args.items[0] == left
×
4722
          && other->args.items[1] == right
×
4723
          && other->args.items[2] == dir)
×
4724
         return other->result;
×
4725
   }
4726

4727
   int64_t dir_const;
17,676✔
4728
   if (vcode_reg_const(dir, &dir_const)) {
17,676✔
4729
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
12,989✔
4730
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
12,989✔
4731

4732
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
12,989✔
4733
         return emit_const(vtype_bool(), 1);
50✔
4734
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
12,939✔
4735
         return emit_const(vtype_bool(), 0);
6,273✔
4736
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
6,666✔
4737
         return emit_const(vtype_bool(), 1);
110✔
4738
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
6,556✔
4739
         return emit_const(vtype_bool(), 0);
1,702✔
4740
      else if (dir_const == RANGE_TO)
4,854✔
4741
         return emit_cmp(VCODE_CMP_GT, left, right);
1,494✔
4742
      else
4743
         return emit_cmp(VCODE_CMP_GT, right, left);
3,360✔
4744
   }
4745

4746
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,687✔
4747
   vcode_add_arg(op, left);
4,687✔
4748
   vcode_add_arg(op, right);
4,687✔
4749
   vcode_add_arg(op, dir);
4,687✔
4750

4751
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,687✔
4752
                "range left and right have different types");
4753
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,687✔
4754
                "dir argument to range length is not int");
4755

4756
   return (op->result = vcode_add_reg(vtype_bool()));
4,687✔
4757
}
4758

4759
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
15,028✔
4760
                              vcode_reg_t dir)
4761
{
4762
   vcode_reg_t left_array = VCODE_INVALID_REG,
15,028✔
4763
      right_array = VCODE_INVALID_REG,
15,028✔
4764
      dir_array = VCODE_INVALID_REG;
15,028✔
4765
   int left_dim = -1, right_dim = -1, dir_dim = -1;
15,028✔
4766

4767
   VCODE_FOR_EACH_OP(other) {
325,508✔
4768
      if (other->kind == VCODE_OP_RANGE_LENGTH
314,958✔
4769
          && other->args.items[0] == left
5,999✔
4770
          && other->args.items[1] == right
4,836✔
4771
          && other->args.items[2] == dir)
4,478✔
4772
         return other->result;
4,478✔
4773
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
310,480✔
4774
         left_array = other->args.items[0];
311✔
4775
         left_dim = other->dim;
311✔
4776
      }
4777
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
310,169✔
4778
         right_array = other->args.items[0];
311✔
4779
         right_dim = other->dim;
311✔
4780
      }
4781
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
309,858✔
4782
         dir_array = other->args.items[0];
1,045✔
4783
         dir_dim = other->dim;
1,045✔
4784
      }
4785
   }
4786

4787
   if (left_array != VCODE_INVALID_REG && left_array == right_array
10,550✔
4788
       && right_array == dir_array && left_dim == right_dim
311✔
4789
       && right_dim == dir_dim)
311✔
4790
      return emit_uarray_len(left_array, left_dim);
311✔
4791

4792
   int64_t lconst, rconst, dconst;
10,239✔
4793
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
10,239✔
4794
       && vcode_reg_const(right, &rconst)) {
6,044✔
4795

4796
      int64_t diff;
3,912✔
4797
      if (dconst == RANGE_TO)
3,912✔
4798
         diff = rconst - lconst;
3,580✔
4799
      else
4800
         diff = lconst - rconst;
332✔
4801

4802
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
3,912✔
4803
   }
4804

4805
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
6,327✔
4806
   vcode_add_arg(op, left);
6,327✔
4807
   vcode_add_arg(op, right);
6,327✔
4808
   vcode_add_arg(op, dir);
6,327✔
4809

4810
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
6,327✔
4811
                "range left and right have different types");
4812
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
6,327✔
4813
                "dir argument to range length is not int");
4814

4815
   return (op->result = vcode_add_reg(vtype_offset()));
6,327✔
4816
}
4817

4818
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
52,520✔
4819
{
4820
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
454,782✔
4821
      if (other->hops == hops && other->address == var)
61,283✔
4822
         return other->result;
7,432✔
4823
   }
4824

4825
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
45,088✔
4826
   op->hops    = hops;
45,088✔
4827
   op->address = var;
45,088✔
4828

4829
   VCODE_ASSERT(hops > 0, "invalid hop count");
45,088✔
4830

4831
   vcode_unit_t vu = active_unit;
45,088✔
4832
   for (int i = 0; i < hops; i++) {
100,661✔
4833
      vu = vu->context;
55,573✔
4834
      VCODE_ASSERT(vu, "hop count is greater than depth");
55,573✔
4835
   }
4836

4837
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
45,088✔
4838

4839
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
45,088✔
4840

4841
   return op->result;
45,088✔
4842
}
4843

4844
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
11,700✔
4845
                             vcode_reg_t size, vcode_reg_t value,
4846
                             vcode_reg_t flags, vcode_reg_t locus,
4847
                             vcode_reg_t offset)
4848
{
4849
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
11,700✔
4850
   vcode_add_arg(op, count);
11,700✔
4851
   vcode_add_arg(op, size);
11,700✔
4852
   vcode_add_arg(op, value);
11,700✔
4853
   vcode_add_arg(op, flags);
11,700✔
4854
   vcode_add_arg(op, locus);
11,700✔
4855
   if (offset != VCODE_INVALID_REG)
11,700✔
4856
      vcode_add_arg(op, offset);
4,409✔
4857

4858
   vcode_type_t vtype = vcode_reg_type(value);
11,700✔
4859
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
11,700✔
4860
   VCODE_ASSERT(vtype_eq(vtype, type)
11,700✔
4861
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4862
                "init signal value type does not match signal type");
4863
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
11,700✔
4864
                "locus argument to init signal must be a debug locus");
4865
   VCODE_ASSERT(offset == VCODE_INVALID_REG
11,700✔
4866
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4867
                "init signal offset argument must have pointer type");
4868

4869
   return (op->result = vcode_add_reg(vtype_signal(type)));
11,700✔
4870
}
4871

4872
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
3,103✔
4873
{
4874
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
3,103✔
4875
   vcode_add_arg(op, signal);
3,103✔
4876
   vcode_add_arg(op, resolution);
3,103✔
4877

4878
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
3,103✔
4879
                "signal argument has wrong type");
4880
   VCODE_ASSERT(vcode_reg_kind(resolution) == VCODE_TYPE_RESOLUTION,
3,103✔
4881
                "resolution wrapper argument has wrong type");
4882
}
3,103✔
4883

4884
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
75✔
4885
                                 vcode_reg_t size, vcode_reg_t locus,
4886
                                 vcode_reg_t kind, vcode_reg_t closure,
4887
                                 vcode_reg_t delay)
4888
{
4889
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
75✔
4890
   vcode_add_arg(op, count);
75✔
4891
   vcode_add_arg(op, size);
75✔
4892
   vcode_add_arg(op, locus);
75✔
4893
   vcode_add_arg(op, kind);
75✔
4894
   vcode_add_arg(op, closure);
75✔
4895
   vcode_add_arg(op, delay);
75✔
4896

4897
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
75✔
4898
                "count argument to implicit signal is not offset");
4899
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
75✔
4900
                "kind argument to implicit signal is not offset");
4901
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
75✔
4902
                "closure argument to implicit signal is not a closure");
4903
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
75✔
4904
                "locus argument to implicit signal must be a debug locus");
4905
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
75✔
4906
                "delay argument to implicit signal must be time");
4907

4908
   return (op->result = vcode_add_reg(vtype_signal(type)));
75✔
4909
}
4910

4911
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
1,333✔
4912
{
4913
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
1,333✔
4914
   vcode_add_arg(op, src);
1,333✔
4915
   vcode_add_arg(op, dst);
1,333✔
4916
   vcode_add_arg(op, count);
1,333✔
4917

4918
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
1,333✔
4919
                "src argument to map signal is not a signal");
4920
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
1,333✔
4921
                "dst argument to map signal is not a signal");
4922
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,333✔
4923
                "count argument type to map signal is not offset");
4924
}
1,333✔
4925

4926
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
4,177✔
4927
{
4928
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
4,177✔
4929
   vcode_add_arg(op, src);
4,177✔
4930
   vcode_add_arg(op, dst);
4,177✔
4931
   vcode_add_arg(op, count);
4,177✔
4932

4933
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
4,177✔
4934
                "dst argument to map const is not a signal");
4935
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
4,177✔
4936
                "count argument type to map const is not offset");
4937
}
4,177✔
4938

4939
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
57✔
4940
{
4941
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
57✔
4942
   vcode_add_arg(op, src);
57✔
4943
   vcode_add_arg(op, dst);
57✔
4944
   vcode_add_arg(op, count);
57✔
4945

4946
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
57✔
4947
                "src argument to map implicit is not a signal");
4948
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
57✔
4949
                "dst argument to map implicit is not a signal");
4950
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
57✔
4951
                "count argument type to map implicit is not offset");
4952
}
57✔
4953

4954
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
9,271✔
4955
{
4956
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
114,209✔
4957
      if (other->args.items[0] == target && other->args.items[1] == count)
13,808✔
4958
         return;
4959
   }
4960

4961
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
9,247✔
4962
   vcode_add_arg(op, target);
9,247✔
4963
   vcode_add_arg(op, count);
9,247✔
4964

4965
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
9,247✔
4966
                "target argument to drive signal is not a signal");
4967
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
9,247✔
4968
                "count argument type to drive signal is not offset");
4969
}
4970

4971
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,209✔
4972
                          vcode_reg_t count, vcode_reg_t reject,
4973
                          vcode_reg_t after)
4974
{
4975
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,209✔
4976
   vcode_add_arg(op, target);
1,209✔
4977
   vcode_add_arg(op, source);
1,209✔
4978
   vcode_add_arg(op, count);
1,209✔
4979
   vcode_add_arg(op, reject);
1,209✔
4980
   vcode_add_arg(op, after);
1,209✔
4981

4982
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,209✔
4983
                "target argument to transfer signal is not a signal");
4984
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,209✔
4985
                "count argument type to transfer signal is not offset");
4986
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,209✔
4987
                "source argument to transfer signal is not a signal");
4988
}
1,209✔
4989

4990
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
2,989✔
4991
                                    vcode_reg_t ileft, vcode_reg_t nlits)
4992
{
4993
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
129,716✔
4994
      if (other->args.items[0] == closure
2,122✔
4995
          && other->args.items[1] == ileft
2,119✔
4996
          && other->args.items[2] == nlits)
2,119✔
4997
         return other->result;
2,119✔
4998
   }
4999

5000
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
870✔
5001
                "first argument to resolution wrapper must be closure");
5002

5003
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
870✔
5004
   vcode_add_arg(op, closure);
870✔
5005
   vcode_add_arg(op, ileft);
870✔
5006
   vcode_add_arg(op, nlits);
870✔
5007

5008
   return (op->result = vcode_add_reg(vtype_resolution(type)));
870✔
5009
}
5010

5011
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t atype,
3,337✔
5012
                         vcode_type_t rtype)
5013
{
5014
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
134,770✔
5015
      if (other->func == func && other->args.items[0] == context)
2,487✔
5016
         return other->result;
2,187✔
5017
   }
5018

5019
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
1,150✔
5020
   vcode_add_arg(op, context);
1,150✔
5021
   op->func = func;
1,150✔
5022
   op->type = atype;
1,150✔
5023

5024
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
1,150✔
5025
                "invalid closure context argument");
5026

5027
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
1,150✔
5028
}
5029

5030
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
30,434✔
5031
{
5032
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
46,473✔
5033
      if (other->func == name)
23,168✔
5034
         return other->result;
12,796✔
5035
   }
5036

5037
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
17,638✔
5038
   op->func = name;
17,638✔
5039
   if (context != VCODE_INVALID_REG)
17,638✔
5040
      vcode_add_arg(op, context);
182✔
5041

5042
   VCODE_ASSERT(context == VCODE_INVALID_REG
17,638✔
5043
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5044
                "invalid protected init context argument");
5045
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
17,638✔
5046
                || active_unit->kind == VCODE_UNIT_PACKAGE
5047
                || active_unit->kind == VCODE_UNIT_THUNK,
5048
                "cannot use package init here");
5049
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
17,638✔
5050

5051
   return (op->result = vcode_add_reg(vtype_context(name)));
17,638✔
5052
}
5053

5054
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
163✔
5055
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5056
{
5057
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
163✔
5058
   vcode_add_arg(op, context);
163✔
5059
   op->func = vtype_name(type);
163✔
5060

5061
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
163✔
5062
      vcode_add_arg(op, path_name);
38✔
5063
      vcode_add_arg(op, inst_name);
38✔
5064

5065
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
38✔
5066
                   "path name argument must be uarray");
5067
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
38✔
5068
                   "inst name argument must be uarray");
5069
   }
5070

5071
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
163✔
5072
                "protected init type must be context");
5073
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
163✔
5074
                "invalid protected init context argument");
5075

5076
   return (op->result = vcode_add_reg(type));
163✔
5077
}
5078

5079
void emit_process_init(ident_t name, vcode_reg_t locus)
97✔
5080
{
5081
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
97✔
5082
   vcode_add_arg(op, locus);
97✔
5083
   op->func = name;
97✔
5084

5085
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
97✔
5086
                "locus argument to process init must be a debug locus");
5087
}
97✔
5088

5089
void emit_protected_free(vcode_reg_t obj)
7✔
5090
{
5091
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
7✔
5092
   vcode_add_arg(op, obj);
7✔
5093

5094
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
7✔
5095
                "protected object type must be context");
5096
}
7✔
5097

5098
vcode_reg_t emit_context_upref(int hops)
15,391✔
5099
{
5100
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
103,015✔
5101
      if (other->hops == hops)
6,902✔
5102
         return other->result;
6,843✔
5103
   }
5104

5105
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
8,548✔
5106
   op->hops = hops;
8,548✔
5107

5108
   VCODE_ASSERT(hops >= 0, "invalid hop count");
8,548✔
5109

5110
   vcode_unit_t vu = active_unit;
8,548✔
5111
   for (int i = 0; i < hops; i++) {
16,359✔
5112
      vu = vu->context;
7,811✔
5113
      VCODE_ASSERT(vu, "hop count is greater than depth");
7,811✔
5114
   }
5115

5116
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
8,548✔
5117
}
5118

5119
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
629✔
5120
                                    vcode_reg_t len)
5121
{
5122
   op_t *op = vcode_add_op(opkind);
629✔
5123
   vcode_add_arg(op, nets);
629✔
5124
   vcode_add_arg(op, len);
629✔
5125

5126
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
629✔
5127
                "argument to %s is not a signal", vcode_op_string(opkind));
5128

5129
   return (op->result = vcode_add_reg(vtype_bool()));
629✔
5130
}
5131

5132
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
427✔
5133
{
5134
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
427✔
5135
}
5136

5137
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
202✔
5138
{
5139
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
202✔
5140
}
5141

5142
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
38,435✔
5143
{
5144
   // Try scanning backwards through the block for another record ref
5145
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
2,326,605✔
5146
      if (other->args.items[0] == record && other->field == field)
478,810✔
5147
         return other->result;
2,752✔
5148
   }
5149

5150
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
35,683✔
5151
   op->field = field;
35,683✔
5152
   vcode_add_arg(op, record);
35,683✔
5153

5154
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
35,683✔
5155

5156
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
35,683✔
5157
                "argument to record ref must be a pointer");
5158

5159
   vtype_t *rtype = vcode_type_data(rptype->pointed);
35,683✔
5160
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
35,683✔
5161
                "argument must be pointer to record or record signal");
5162

5163
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
35,683✔
5164

5165
   vcode_type_t field_type  = rtype->fields.items[field];
35,683✔
5166
   vcode_type_t bounds_type = field_type;
35,683✔
5167
   vcode_type_t result_type = field_type;
35,683✔
5168

5169
   const vtype_kind_t fkind = vtype_kind(field_type);
35,683✔
5170
   if (fkind == VCODE_TYPE_CARRAY)
35,683✔
5171
      result_type = bounds_type = vtype_elem(field_type);
4,958✔
5172
   else if (fkind == VCODE_TYPE_UARRAY) {
30,725✔
5173
      bounds_type = vtype_elem(field_type);
2,672✔
5174
      result_type = field_type;
2,672✔
5175
   }
5176

5177
   op->result = vcode_add_reg(vtype_pointer(result_type));
35,683✔
5178

5179
   reg_t *rr = vcode_reg_data(op->result);
35,683✔
5180
   rr->bounds = bounds_type;
35,683✔
5181

5182
   return op->result;
35,683✔
5183
}
5184

5185
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
35,523✔
5186
{
5187
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
1,663,912✔
5188
      if (other->args.items[0] == array && other->args.items[1] == offset)
98,366✔
5189
         return other->result;
1,189✔
5190
   }
5191

5192
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
34,334✔
5193
   vcode_add_arg(op, array);
34,334✔
5194
   vcode_add_arg(op, offset);
34,334✔
5195

5196
   vcode_type_t rtype = vcode_reg_type(array);
34,334✔
5197
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
34,334✔
5198
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5199
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5200
                "argument to array ref must be a pointer or signal");
5201
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
34,334✔
5202
                "array ref offset argument must have offset type");
5203

5204
   op->result = vcode_add_reg(rtype);
34,334✔
5205

5206
   reg_t *rr = vcode_reg_data(op->result);
34,334✔
5207
   rr->bounds = vcode_reg_bounds(array);
34,334✔
5208

5209
   return op->result;
34,334✔
5210
}
5211

5212
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
21,054✔
5213
{
5214
   int64_t cconst;
21,054✔
5215
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
21,054✔
5216
       && cconst == 0)
10,613✔
5217
      return;
4,959✔
5218
   else if (dest == src)
20,891✔
5219
      return;
5220

5221
   op_t *op = vcode_add_op(VCODE_OP_COPY);
16,095✔
5222
   vcode_add_arg(op, dest);
16,095✔
5223
   vcode_add_arg(op, src);
16,095✔
5224
   if (count != VCODE_INVALID_REG)
16,095✔
5225
      vcode_add_arg(op, count);
14,140✔
5226

5227
   vcode_type_t dtype = vcode_reg_type(dest);
16,095✔
5228
   vcode_type_t stype = vcode_reg_type(src);
16,095✔
5229

5230
   vtype_kind_t dkind = vtype_kind(dtype);
16,095✔
5231
   vtype_kind_t skind = vtype_kind(stype);
16,095✔
5232

5233
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
16,095✔
5234
                "destination type is not a pointer or access");
5235
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
16,095✔
5236
                "source type is not a pointer or access");
5237
   VCODE_ASSERT(vtype_eq(dtype, stype),
16,095✔
5238
                "source and destination types do not match");
5239
   VCODE_ASSERT(count == VCODE_INVALID_REG
16,095✔
5240
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5241
                "count is not offset type");
5242

5243
   op->type = vtype_pointed(dtype);
16,095✔
5244
}
5245

5246
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
5,829✔
5247
{
5248
   VCODE_FOR_EACH_OP(other) {
98,005✔
5249
      if (other->kind == VCODE_OP_CLEAR_EVENT)
92,212✔
5250
         break;
5251
      else if (other->kind == VCODE_OP_SCHED_EVENT
92,182✔
5252
               && other->args.items[0] == nets
4,771✔
5253
               && other->args.items[1] == n_elems)
9✔
5254
         return;
5255
   }
5256

5257
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
5,823✔
5258
   vcode_add_arg(op, nets);
5,823✔
5259
   vcode_add_arg(op, n_elems);
5,823✔
5260

5261
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
5,823✔
5262
                "nets argument to sched event must be signal");
5263
}
5264

5265
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
501✔
5266
{
5267
   VCODE_FOR_EACH_OP(other) {
2,307✔
5268
      if (other->kind == VCODE_OP_SCHED_EVENT)
1,806✔
5269
         break;
5270
      else if (other->kind == VCODE_OP_CLEAR_EVENT
1,806✔
5271
               && other->args.items[0] == nets
39✔
5272
               && other->args.items[1] == n_elems)
×
5273
         return;
5274
   }
5275

5276
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
501✔
5277
   vcode_add_arg(op, nets);
501✔
5278
   vcode_add_arg(op, n_elems);
501✔
5279

5280
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
501✔
5281
                "nets argument to clear event must be signal");
5282
}
5283

5284
void emit_resume(ident_t func)
868✔
5285
{
5286
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
868✔
5287
   op->func = func;
868✔
5288

5289
   block_t *b = &(active_unit->blocks.items[active_block]);
868✔
5290
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
868✔
5291
}
868✔
5292

5293
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
5,963✔
5294
{
5295
   int64_t lconst;
5,963✔
5296
   if (vcode_reg_const(len, &lconst) && lconst == 0)
5,963✔
5297
      return;
29✔
5298

5299
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
5,934✔
5300
   vcode_add_arg(op, ptr);
5,934✔
5301
   vcode_add_arg(op, value);
5,934✔
5302
   vcode_add_arg(op, len);
5,934✔
5303

5304
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
5,934✔
5305
                "target of memset must have pointer type");
5306
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
5,934✔
5307
                "value of memset must have scalar type");
5308
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
5,934✔
5309
                "length of memset must have offset type");
5310
}
5311

5312
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
614✔
5313
               const vcode_block_t *blocks, int ncases)
5314
{
5315
   int64_t cval1, cval2;
614✔
5316
   bool is_const = vcode_reg_const(value, &cval1);
614✔
5317

5318
   for (int i = 0; i < ncases; i++) {
5,098✔
5319
      bool can_fold = false;
4,488✔
5320
      if (cases[i] == value)
4,488✔
5321
         can_fold = true;
5322
      else if (is_const && vcode_reg_const(cases[i], &cval2))
4,488✔
5323
         can_fold = (cval1 == cval2);
4✔
5324

5325
      if (can_fold) {
4✔
5326
         emit_jump(blocks[i]);
4✔
5327
         return;
8✔
5328
      }
5329
   }
5330

5331
   if (is_const) {
610✔
5332
      emit_jump(def);
×
5333
      return;
×
5334
   }
5335

5336
   op_t *op = vcode_add_op(VCODE_OP_CASE);
610✔
5337
   vcode_add_arg(op, value);
610✔
5338
   vcode_add_target(op, def);
610✔
5339

5340
   for (int i = 0; i < ncases; i++) {
5,094✔
5341
      vcode_add_arg(op, cases[i]);
4,484✔
5342
      vcode_add_target(op, blocks[i]);
4,484✔
5343

5344
#ifdef DEBUG
5345
      for (int j = 0; j < i; j++)
244,467✔
5346
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
239,983✔
5347
#endif
5348
   }
5349
}
5350

5351
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
260✔
5352
                    vcode_reg_t kind, vcode_reg_t status)
5353
{
5354
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
260✔
5355
   vcode_add_arg(op, file);
260✔
5356
   vcode_add_arg(op, name);
260✔
5357
   vcode_add_arg(op, length);
260✔
5358
   vcode_add_arg(op, kind);
260✔
5359
   if (status != VCODE_INVALID_REG)
260✔
5360
      vcode_add_arg(op, status);
26✔
5361

5362
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
260✔
5363
                "file open first argument must have file pointer type");
5364
}
260✔
5365

5366
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
125✔
5367
{
5368
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
125✔
5369
   vcode_add_arg(op, file);
125✔
5370
   vcode_add_arg(op, value);
125✔
5371
   if (length != VCODE_INVALID_REG)
125✔
5372
      vcode_add_arg(op, length);
68✔
5373

5374
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
125✔
5375
                "file write first argument must have file pointer type");
5376
}
125✔
5377

5378
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
75✔
5379
                    vcode_reg_t inlen, vcode_reg_t outlen)
5380
{
5381
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
75✔
5382
   vcode_add_arg(op, file);
75✔
5383
   vcode_add_arg(op, ptr);
75✔
5384
   if (inlen != VCODE_INVALID_REG) {
75✔
5385
      vcode_add_arg(op, inlen);
27✔
5386
      if (outlen != VCODE_INVALID_REG)
27✔
5387
         vcode_add_arg(op, outlen);
18✔
5388
   }
5389

5390
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
75✔
5391
                "file read first argument must have file pointer type");
5392
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
75✔
5393
                "file read pointer argument must have pointer type");
5394
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
75✔
5395
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5396
                "file read outlen argument must have pointer type");
5397
}
75✔
5398

5399
vcode_reg_t emit_null(vcode_type_t type)
9,744✔
5400
{
5401
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
221,732✔
5402
      if (vtype_eq(vcode_reg_type(other->result), type))
5,424✔
5403
         return other->result;
3,087✔
5404
   }
5405

5406
   op_t *op = vcode_add_op(VCODE_OP_NULL);
6,657✔
5407
   op->result = vcode_add_reg(type);
6,657✔
5408

5409
   vtype_kind_t kind = vtype_kind(type);
6,657✔
5410
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
6,657✔
5411
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5412
                "null type must be file, access, context, or pointer");
5413

5414
   return op->result;
5415
}
5416

5417
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
428✔
5418
{
5419
   op_t *op = vcode_add_op(VCODE_OP_NEW);
428✔
5420
   if (length != VCODE_INVALID_REG)
428✔
5421
      vcode_add_arg(op, length);
337✔
5422

5423
   op->result = vcode_add_reg(vtype_access(type));
428✔
5424

5425
   vtype_kind_t kind = vtype_kind(type);
428✔
5426
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
428✔
5427
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5428
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5429
                "new type must be int, real, record, access, or uarray");
5430
   VCODE_ASSERT(length == VCODE_INVALID_REG
428✔
5431
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5432
                "new length must have offset type");
5433

5434
   return op->result;
428✔
5435
}
5436

5437
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
1,755✔
5438
{
5439
   VCODE_FOR_EACH_OP(other) {
104,961✔
5440
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
103,838✔
5441
         return;
5442
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
103,461✔
5443
         return;
5444
   }
5445

5446
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
1,123✔
5447
   vcode_add_arg(op, ptr);
1,123✔
5448
   vcode_add_arg(op, locus);
1,123✔
5449

5450
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
1,123✔
5451
                "null check argument must be an access");
5452
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,123✔
5453
                "locus argument to null check must be a debug locus");
5454
}
5455

5456
void emit_deallocate(vcode_reg_t ptr)
207✔
5457
{
5458
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
207✔
5459
   vcode_add_arg(op, ptr);
207✔
5460

5461
   vcode_type_t ptype = vcode_reg_type(ptr);
207✔
5462
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
207✔
5463
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5464
                "deallocate argument must be pointer to access");
5465
}
207✔
5466

5467
vcode_reg_t emit_all(vcode_reg_t reg)
2,183✔
5468
{
5469
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
146,087✔
5470
      if (other->args.items[0] == reg)
9,251✔
5471
         return other->result;
632✔
5472
   }
5473

5474
   op_t *op = vcode_add_op(VCODE_OP_ALL);
1,551✔
5475
   vcode_add_arg(op, reg);
1,551✔
5476

5477
   vcode_type_t vtype = vcode_reg_type(reg);
1,551✔
5478

5479
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
1,551✔
5480
                "all argument must be an access");
5481

5482
   vcode_type_t pointed = vtype_pointed(vtype);
1,551✔
5483
   op->result = vcode_add_reg(vtype_pointer(pointed));
1,551✔
5484

5485
   reg_t *rr = vcode_reg_data(op->result);
1,551✔
5486
   rr->bounds = pointed;
1,551✔
5487

5488
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
1,551✔
5489
                "cannot dereference opaque type");
5490

5491
   return op->result;
5492
}
5493

5494
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
14,497✔
5495
{
5496
   block_t *b = &(active_unit->blocks.items[active_block]);
14,497✔
5497
   for (int i = b->ops.count - 1; i >= 0; i--) {
361,846✔
5498
      const op_t *other = &(b->ops.items[i]);
347,904✔
5499
      if (other->kind == kind && other->args.items[0] == sig)
347,904✔
5500
         return other->result;
555✔
5501
   }
5502

5503
   op_t *op = vcode_add_op(kind);
13,942✔
5504
   vcode_add_arg(op, sig);
13,942✔
5505

5506
   vcode_type_t stype = vcode_reg_type(sig);
13,942✔
5507
   op->type = stype;
13,942✔
5508

5509
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
13,942✔
5510
                "argument r%d to resolved is not a signal", sig);
5511

5512
   vcode_type_t rtype = vtype_base(stype);
13,942✔
5513

5514
   const vtype_kind_t rkind = vtype_kind(rtype);
13,942✔
5515
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
13,942✔
5516
      rtype = vtype_elem(rtype);
×
5517

5518
   VCODE_ASSERT(vtype_is_scalar(rtype),
13,942✔
5519
                "resolved signal base type must be scalar");
5520

5521
   op->result = vcode_add_reg(vtype_pointer(rtype));
13,942✔
5522

5523
   reg_t *rr = vcode_reg_data(op->result);
13,942✔
5524
   rr->bounds = rtype;
13,942✔
5525

5526
   return op->result;
13,942✔
5527
}
5528

5529
vcode_reg_t emit_resolved(vcode_reg_t sig)
14,402✔
5530
{
5531
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
14,402✔
5532
}
5533

5534
vcode_reg_t emit_last_value(vcode_reg_t sig)
95✔
5535
{
5536
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
95✔
5537
}
5538

5539
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
21✔
5540
{
5541
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
21✔
5542
   vcode_add_arg(op, signal);
21✔
5543
   if (len != VCODE_INVALID_REG)
21✔
5544
      vcode_add_arg(op, len);
9✔
5545

5546
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
21✔
5547
                "signal argument to last event must have signal type");
5548
   VCODE_ASSERT(len == VCODE_INVALID_REG
21✔
5549
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5550
                "length argument to last event must have offset type");
5551

5552
   return (op->result = vcode_add_reg(vtype_time()));
21✔
5553
}
5554

5555
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
15✔
5556
{
5557
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
15✔
5558
   vcode_add_arg(op, signal);
15✔
5559
   if (len != VCODE_INVALID_REG)
15✔
5560
      vcode_add_arg(op, len);
6✔
5561

5562
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
15✔
5563
                "signal argument to last active must have signal type");
5564
   VCODE_ASSERT(len == VCODE_INVALID_REG
15✔
5565
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5566
                "length argument to last active must have offset type");
5567

5568
   return (op->result = vcode_add_reg(vtype_time()));
15✔
5569
}
5570

5571
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
7,035✔
5572
{
5573
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
7,035✔
5574
   vcode_add_arg(op, signal);
7,035✔
5575
   vcode_add_arg(op, locus);
7,035✔
5576

5577
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
7,035✔
5578
                "signal argument must have signal type");
5579
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
7,035✔
5580
                "locus argument must have debug locus type");
5581
}
7,035✔
5582

5583
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
30✔
5584
{
5585
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
30✔
5586
   vcode_add_arg(op, signal);
30✔
5587
   vcode_add_arg(op, len);
30✔
5588

5589
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
30✔
5590
                "signal argument to last active must have signal type");
5591
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
30✔
5592
                "length argument to last active must have offset type");
5593

5594
   return (op->result = vcode_add_reg(vtype_bool()));
30✔
5595
}
5596

5597
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
24✔
5598
{
5599
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
24✔
5600
   vcode_add_arg(op, signal);
24✔
5601
   if (len != VCODE_INVALID_REG)
24✔
5602
      vcode_add_arg(op, len);
3✔
5603

5604
   vcode_type_t signal_type = vcode_reg_type(signal);
24✔
5605

5606
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
24✔
5607
                "signal argument to last active must have signal type");
5608
   VCODE_ASSERT(len == VCODE_INVALID_REG
24✔
5609
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5610
                "length argument to last active must have offset type");
5611

5612
   vcode_type_t base_type = vtype_base(signal_type);
24✔
5613
   op->result = vcode_add_reg(vtype_pointer(base_type));
24✔
5614

5615
   reg_t *rr = vcode_reg_data(op->result);
24✔
5616
   rr->bounds = base_type;
24✔
5617

5618
   return op->result;
24✔
5619
}
5620

5621
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
22,624✔
5622
                       vcode_reg_t dim)
5623
{
5624
   if (rlen == llen)
22,624✔
5625
      return;
5626

5627
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
184,509✔
5628
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
2,823✔
5629
         return;
5630
   }
5631

5632
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
6,797✔
5633
   vcode_add_arg(op, llen);
6,797✔
5634
   vcode_add_arg(op, rlen);
6,797✔
5635
   vcode_add_arg(op, locus);
6,797✔
5636
   if (dim != VCODE_INVALID_REG)
6,797✔
5637
      vcode_add_arg(op, dim);
24✔
5638

5639
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6,797✔
5640
                "locus argument to length check must be a debug locus");
5641
}
5642

5643
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
1,572✔
5644
{
5645
   int64_t cval;
1,572✔
5646
   if (vcode_reg_const(exp, &cval) && cval >= 0)
1,572✔
5647
      return;
1,055✔
5648

5649
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
3,254✔
5650
      if (other->args.items[0] == exp)
12✔
5651
         return;
5652
   }
5653

5654
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
517✔
5655
   vcode_add_arg(op, exp);
517✔
5656
   vcode_add_arg(op, locus);
517✔
5657

5658
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
517✔
5659
                "exp argument to exponent check must be a integer");
5660
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
517✔
5661
                "locus argument to exponent check must be a debug locus");
5662
}
5663

5664
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
1,081✔
5665
{
5666
   int64_t cval;
1,081✔
5667
   if (vcode_reg_const(denom, &cval) && cval != 0)
1,081✔
5668
      return;
978✔
5669

5670
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
2,886✔
5671
      if (other->args.items[0] == denom)
56✔
5672
         return;
5673
   }
5674

5675
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
103✔
5676
   vcode_add_arg(op, denom);
103✔
5677
   vcode_add_arg(op, locus);
103✔
5678

5679
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
103✔
5680
                "denom argument to zero check must be a integer");
5681
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
103✔
5682
                "locus argument to zero check must be a debug locus");
5683
}
5684

5685
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
48,679✔
5686
                                   vcode_reg_t right, vcode_reg_t dir)
5687
{
5688
   int64_t dconst;
48,679✔
5689
   if (vcode_reg_const(dir, &dconst)) {
48,679✔
5690
      int64_t lconst, rconst;
39,751✔
5691
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
39,751✔
5692
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
30,132✔
5693
            || (dconst == RANGE_DOWNTO && rconst > lconst);
63,679✔
5694

5695
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
33,548✔
5696

5697
         const bool ok_static =
67,096✔
5698
            (dconst == RANGE_TO
5699
             && bounds->low >= lconst && bounds->high <= rconst)
30,132✔
5700
            || (dconst == RANGE_DOWNTO
7,923✔
5701
                && bounds->low >= rconst && bounds->high <= lconst)
3,416✔
5702
            || (!is_null && (reg == left || reg == right));
38,265✔
5703

5704
         return ok_static;
38,953✔
5705
      }
5706
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
6,203✔
5707
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
5,811✔
5708
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
5,811✔
5709

5710
         assert(lbounds->kind == VCODE_TYPE_REAL);
5,811✔
5711
         assert(rbounds->kind == VCODE_TYPE_REAL);
5,811✔
5712

5713
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
5,811✔
5714
         assert(bounds->kind == VCODE_TYPE_REAL);
5,811✔
5715

5716
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
5,811✔
5717
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
5,405✔
5718
            // Covers the complete double range so can never overflow
5719
            return true;
5720
         }
5721
      }
5722
   }
5723

5724
   return false;
5725
}
5726

5727
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
49,264✔
5728
                              vcode_reg_t left, vcode_reg_t right,
5729
                              vcode_reg_t dir, vcode_reg_t locus,
5730
                              vcode_reg_t hint)
5731
{
5732
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
2,305,338✔
5733
      if (other->args.items[0] == reg && other->args.items[1] == left
13,509✔
5734
          && other->args.items[2] == right && other->args.items[3] == dir)
591✔
5735
         return;
5736
   }
5737

5738
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
48,679✔
5739
      emit_comment("Elided bounds check for r%d", reg);
34,236✔
5740
      return;
34,236✔
5741
   }
5742

5743
   op_t *op = vcode_add_op(kind);
14,443✔
5744
   vcode_add_arg(op, reg);
14,443✔
5745
   vcode_add_arg(op, left);
14,443✔
5746
   vcode_add_arg(op, right);
14,443✔
5747
   vcode_add_arg(op, dir);
14,443✔
5748
   vcode_add_arg(op, locus);
14,443✔
5749
   vcode_add_arg(op, hint);
14,443✔
5750

5751
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
14,443✔
5752
                "locus argument to bounds check must be a debug locus");
5753
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
14,443✔
5754
                "hint argument to bounds check must be a debug locus");
5755
}
5756

5757
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
8,549✔
5758
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5759
{
5760
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
8,549✔
5761
}
8,549✔
5762

5763
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
40,715✔
5764
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5765
{
5766
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
40,715✔
5767
}
40,715✔
5768

5769
void emit_package_scope(vcode_reg_t locus)
46✔
5770
{
5771
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
46✔
5772
   vcode_add_arg(op, locus);
46✔
5773

5774
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
46✔
5775
                "locus argument to package scope must be a debug locus");
5776
}
46✔
5777

5778
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
609✔
5779
{
5780
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
609✔
5781
   vcode_add_arg(op, locus);
609✔
5782
   op->type = type;
609✔
5783

5784
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
609✔
5785
                "locus argument to array scope must be a debug locus");
5786
}
609✔
5787

5788
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
1,418✔
5789
{
5790
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
1,418✔
5791
   vcode_add_arg(op, locus);
1,418✔
5792
   op->type = type;
1,418✔
5793

5794
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
1,418✔
5795
                "locus argument to record scope must be a debug locus");
5796
}
1,418✔
5797

5798
void emit_pop_scope(void)
2,073✔
5799
{
5800
   vcode_add_op(VCODE_OP_POP_SCOPE);
2,073✔
5801
}
2,073✔
5802

5803
vcode_reg_t emit_debug_locus(ident_t unit, ptrdiff_t offset)
121,452✔
5804
{
5805
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
6,268,649✔
5806
      if (other->ident == unit && other->value == offset)
956,491✔
5807
         return other->result;
12,842✔
5808
   }
5809

5810
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
108,610✔
5811
   op->ident = unit;
108,610✔
5812
   op->value = offset;
108,610✔
5813

5814
   return (op->result = vcode_add_reg(vtype_debug_locus()));
108,610✔
5815
}
5816

5817
void emit_debug_out(vcode_reg_t reg)
×
5818
{
5819
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5820
   vcode_add_arg(op, reg);
×
5821
}
×
5822

5823
void emit_cover_stmt(uint32_t tag)
994✔
5824
{
5825
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
994✔
5826
   op->tag = tag;
994✔
5827
}
994✔
5828

5829
void emit_cover_branch(uint32_t tag)
495✔
5830
{
5831
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
495✔
5832
   op->tag = tag;
495✔
5833
}
495✔
5834

5835
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
313✔
5836
{
5837
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
313✔
5838
   vcode_add_arg(op, signal);
313✔
5839
   op->tag = tag;
313✔
5840
}
313✔
5841

5842
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
12✔
5843
{
5844
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
12✔
5845
   vcode_add_arg(op, signal);
12✔
5846
   vcode_add_arg(op, low);
12✔
5847
   op->tag = tag;
12✔
5848
}
12✔
5849

5850
void emit_cover_expr(uint32_t tag)
856✔
5851
{
5852
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
856✔
5853
   op->tag = tag;
856✔
5854
}
856✔
5855

5856
void emit_unreachable(vcode_reg_t locus)
583✔
5857
{
5858
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
583✔
5859
   if (locus != VCODE_INVALID_REG)
583✔
5860
      vcode_add_arg(op, locus);
137✔
5861
}
583✔
5862

5863
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
1,476✔
5864
{
5865
   active_unit->flags |= UNIT_UNDEFINED;
1,476✔
5866

5867
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
1,476✔
5868
   op->result = vcode_add_reg(type);
1,476✔
5869
   vcode_reg_data(op->result)->bounds = bounds;
1,476✔
5870

5871
   return op->result;
1,476✔
5872
}
5873

5874
void emit_debug_info(const loc_t *loc)
1,375,946✔
5875
{
5876
   if (!loc_invalid_p(loc))
1,375,946✔
5877
      vcode_block_data()->last_loc = *loc;
1,349,000✔
5878
}
1,375,946✔
5879

5880
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
4,144✔
5881
{
5882
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
155,036✔
5883
      if (other->args.items[0] == context && other->ident == name)
8,855✔
5884
         return other->result;
1,631✔
5885
   }
5886

5887
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
2,513✔
5888
   vcode_add_arg(op, context);
2,513✔
5889
   op->ident = name;
2,513✔
5890

5891
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
2,513✔
5892
                "first argument to link var must be context");
5893

5894
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
2,513✔
5895
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
79✔
5896
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
79✔
5897
   }
5898
   else {
5899
      op->result = vcode_add_reg(vtype_pointer(type));
2,434✔
5900
      vcode_reg_data(op->result)->bounds = type;
2,434✔
5901
   }
5902

5903
   return op->result;
2,513✔
5904
}
5905

5906
vcode_reg_t emit_link_package(ident_t name)
24,631✔
5907
{
5908
   VCODE_FOR_EACH_OP(other) {
1,115,471✔
5909
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
1,104,078✔
5910
         return other->result;
7,950✔
5911
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
1,096,128✔
5912
         return other->result;
5,288✔
5913
   }
5914

5915
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
11,393✔
5916
   op->ident = name;
11,393✔
5917

5918
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
11,393✔
5919

5920
   return (op->result = vcode_add_reg(vtype_context(name)));
11,393✔
5921
}
5922

5923
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
708✔
5924
{
5925
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
1,656✔
5926
      if (other->args.items[0] == state)
×
5927
         return;
5928
   }
5929

5930
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
708✔
5931
   vcode_add_arg(op, state);
708✔
5932
   if (strong != VCODE_INVALID_REG)
708✔
5933
      vcode_add_arg(op, strong);
18✔
5934

5935
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
708✔
5936
                "state must have integer type");
5937
   VCODE_ASSERT(strong == VCODE_INVALID_REG
708✔
5938
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
5939
                "strong argument not is not boolean");
5940
}
5941

5942
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
45✔
5943
                               vcode_reg_t locus, vcode_reg_t bounds)
5944
{
5945
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
45✔
5946
   vcode_add_arg(op, value);
45✔
5947
   vcode_add_arg(op, context);
45✔
5948
   vcode_add_arg(op, locus);
45✔
5949
   if (bounds != VCODE_INVALID_REG)
45✔
5950
      vcode_add_arg(op, bounds);
6✔
5951

5952
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
45✔
5953
                "invalid reflect value context argument");
5954
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
45✔
5955
                "locus argument to reflect value must be a debug locus");
5956

5957
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
45✔
5958
}
5959

5960
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
42✔
5961
                                 vcode_reg_t bounds)
5962
{
5963
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
42✔
5964
   vcode_add_arg(op, context);
42✔
5965
   vcode_add_arg(op, locus);
42✔
5966
   if (bounds != VCODE_INVALID_REG)
42✔
5967
      vcode_add_arg(op, bounds);
×
5968

5969
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
42✔
5970
                "invalid reflect value context argument");
5971
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
42✔
5972
                "locus argument to reflect value must be a debug locus");
5973

5974
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
42✔
5975
}
5976

5977
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
205✔
5978
                                  int nargs)
5979
{
5980
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
205✔
5981
   op->func = func;
205✔
5982

5983
   for (int i = 0; i < nargs; i++)
555✔
5984
      vcode_add_arg(op, args[i]);
350✔
5985

5986
   return (op->result = vcode_add_reg(vtype_trigger()));
205✔
5987
}
5988

5989
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
34✔
5990
{
5991
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
34✔
5992
   vcode_add_arg(op, left);
34✔
5993
   vcode_add_arg(op, right);
34✔
5994

5995
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
34✔
5996
                "or trigger left argument must be trigger");
5997
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
34✔
5998
                "or trigger right argument must be trigger");
5999

6000
   return (op->result = vcode_add_reg(vtype_trigger()));
34✔
6001
}
6002

6003
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
63✔
6004
{
6005
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
63✔
6006
   vcode_add_arg(op, left);
63✔
6007
   vcode_add_arg(op, right);
63✔
6008

6009
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
63✔
6010
                "cmp trigger left argument must be signal");
6011
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
63✔
6012
                "cmp trigger right argument must be integer");
6013

6014
   return (op->result = vcode_add_reg(vtype_trigger()));
63✔
6015
}
6016

6017
void emit_add_trigger(vcode_reg_t trigger)
335✔
6018
{
6019
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
335✔
6020
   vcode_add_arg(op, trigger);
335✔
6021

6022
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
335✔
6023
                "add trigger argument must be trigger");
6024
}
335✔
6025

6026
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
255✔
6027
{
6028
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
255✔
6029
   vcode_add_arg(op, driving);
255✔
6030
   if (effective != VCODE_INVALID_REG && effective != driving)
255✔
6031
      vcode_add_arg(op, effective);
18✔
6032

6033
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
255✔
6034
                "port conversion argument must be a closure");
6035
   VCODE_ASSERT(effective == VCODE_INVALID_REG
255✔
6036
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6037
                "port conversion argument must be a closure");
6038

6039
   return (op->result = vcode_add_reg(vtype_conversion()));
255✔
6040
}
6041

6042
vcode_reg_t emit_bind_external(vcode_reg_t locus, vcode_type_t type,
196✔
6043
                               vcode_type_t bounds)
6044
{
6045
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
196✔
6046
   vcode_add_arg(op, locus);
196✔
6047
   op->type = type;
196✔
6048

6049
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
196✔
6050
                "bind external argument must be locus");
6051

6052
   switch (vtype_kind(type)) {
196✔
6053
   case VCODE_TYPE_UARRAY:
167✔
6054
   case VCODE_TYPE_SIGNAL:
6055
      op->result = vcode_add_reg(type);
167✔
6056
      break;
167✔
6057
   default:
29✔
6058
      op->result = vcode_add_reg(vtype_pointer(type));
29✔
6059
      break;
29✔
6060
   }
6061

6062
   vcode_reg_data(op->result)->bounds = bounds;
196✔
6063
   return op->result;
196✔
6064
}
6065

6066
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
330✔
6067
{
6068
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
330✔
6069
   vcode_add_arg(op, conv);
330✔
6070
   vcode_add_arg(op, nets);
330✔
6071
   vcode_add_arg(op, count);
330✔
6072

6073
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
330✔
6074
                "conv argument to convert must be a port conversion");
6075
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
330✔
6076
                "nets argument to convert must be a signal");
6077
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
330✔
6078
                "count argument to convert must be offset");
6079
}
330✔
6080

6081
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
372✔
6082
{
6083
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
372✔
6084
   vcode_add_arg(op, conv);
372✔
6085
   vcode_add_arg(op, nets);
372✔
6086
   vcode_add_arg(op, count);
372✔
6087

6088
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
372✔
6089
                "conv argument to convert must be a port conversion");
6090
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
372✔
6091
                "nets argument to convert must be a signal");
6092
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
372✔
6093
                "count argument to convert must be offset");
6094
}
372✔
6095

6096
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
275✔
6097
{
6098
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
275✔
6099
   vcode_add_arg(op, spec);
275✔
6100
   vcode_add_arg(op, length);
275✔
6101
   if (locus != VCODE_INVALID_REG)
275✔
6102
      vcode_add_arg(op, locus);
140✔
6103

6104
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
275✔
6105
                "spec argument to bind foreign must be a pointer");
6106
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
275✔
6107
                "length argument to bind foreign must be offset");
6108
   VCODE_ASSERT(locus == VCODE_INVALID_REG
275✔
6109
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6110
                "locus argument to bind foreign value must be a debug locus");
6111
}
275✔
6112

6113
vcode_reg_t emit_instance_name(vcode_reg_t kind)
797✔
6114
{
6115
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
797✔
6116
   vcode_add_arg(op, kind);
797✔
6117

6118
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
797✔
6119
                "kind argument to instance name must be offset");
6120

6121
   vcode_type_t vchar = vtype_char();
797✔
6122
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
797✔
6123
}
6124

6125
void emit_deposit_signal(vcode_reg_t signal, vcode_reg_t count,
174✔
6126
                         vcode_reg_t values)
6127
{
6128
   op_t *op = vcode_add_op(VCODE_OP_DEPOSIT_SIGNAL);
174✔
6129
   vcode_add_arg(op, signal);
174✔
6130
   vcode_add_arg(op, count);
174✔
6131
   vcode_add_arg(op, values);
174✔
6132

6133
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
174✔
6134
                "deposit signal target is not signal");
6135
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
174✔
6136
                "deposit signal count is not offset type");
6137
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
174✔
6138
                "signal cannot be values argument for deposit signal");
6139
}
174✔
6140

6141
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
29,171✔
6142
{
6143
   vcode_state_t state;
29,171✔
6144
   vcode_state_save(&state);
29,171✔
6145

6146
   vcode_select_unit(vu);
29,171✔
6147

6148
   const int nblocks = vcode_count_blocks();
29,171✔
6149
   for (int i = 0; i < nblocks; i++) {
138,027✔
6150
      vcode_select_block(i);
108,856✔
6151

6152
      const int nops = vcode_count_ops();
108,856✔
6153
      for (int op = 0; op < nops; op++) {
1,496,132✔
6154
         switch (vcode_get_op(op)) {
1,387,276✔
6155
         case VCODE_OP_LINK_PACKAGE:
9,506✔
6156
            (*fn)(vcode_get_ident(op), ctx);
9,506✔
6157
            break;
9,506✔
6158
         case VCODE_OP_FCALL:
51,955✔
6159
         case VCODE_OP_PCALL:
6160
         case VCODE_OP_CLOSURE:
6161
         case VCODE_OP_PROTECTED_INIT:
6162
         case VCODE_OP_PACKAGE_INIT:
6163
         case VCODE_OP_FUNCTION_TRIGGER:
6164
            (*fn)(vcode_get_func(op), ctx);
51,955✔
6165
            break;
51,955✔
6166
         default:
6167
            break;
6168
         }
6169
      }
6170
   }
6171

6172
   vcode_state_restore(&state);
29,171✔
6173
}
29,171✔
6174

6175
#ifdef DEBUG
6176
static void shape_mismatch(vcode_unit_t vu, vcode_unit_t shape,
×
6177
                           const char *fmt, ...)
6178
{
6179
   vcode_select_unit(vu);
×
6180
   vcode_dump();
×
6181

6182
   vcode_select_unit(shape);
×
6183
   vcode_dump();
×
6184

6185
   va_list ap;
×
6186
   va_start(ap, fmt);
×
6187

6188
   diag_t *d = diag_new(DIAG_FATAL, NULL);
×
6189
   diag_printf(d, "instance %s does not match shape %s", istr(vu->name),
×
6190
               istr(shape->name));
6191
   diag_stacktrace(d, true);
×
6192
   diag_vhint(d, NULL, fmt, ap);
×
6193
   diag_emit(d);
×
6194

6195
   va_end(ap);
×
6196

6197
   fatal_exit(1);
×
6198
}
6199
#endif
6200

6201
void vcode_check_shape(vcode_unit_t vu, vcode_unit_t shape)
84✔
6202
{
6203
#ifdef DEBUG
6204
   assert(shape->kind == VCODE_UNIT_SHAPE);
84✔
6205
   assert(vu->kind == VCODE_UNIT_INSTANCE);
84✔
6206

6207
   if (shape->vars.count <= vu->vars.count) {
84✔
6208
      for (int i = 0; i < shape->vars.count; i++) {
362✔
6209
         var_t *v = var_array_nth_ptr(&(vu->vars), i);
278✔
6210
         var_t *s = var_array_nth_ptr(&(shape->vars), i);
278✔
6211

6212
         if (v->name != s->name)
278✔
6213
            shape_mismatch(vu, shape, "var %d name %s != %s", i, istr(v->name),
×
6214
                           istr(s->name));
6215
         else if (v->flags != s->flags)
278✔
6216
            shape_mismatch(vu, shape, "var %d flags %x != %x", i, v->flags,
×
6217
                           s->flags);
6218
         // XXX: not possible to compare types at the moment
6219
      }
6220
   }
6221
   else
6222
      shape_mismatch(vu, shape, "shape vars %d > unit vars %d",
×
6223
                     shape->vars.count, vu->vars.count);
6224

6225
   if (shape->context != NULL)
84✔
6226
      vcode_check_shape(vu->context, shape->context);
×
6227
#endif
6228
}
84✔
6229

6230
#if VCODE_CHECK_UNIONS
6231
#define OP_USE_COUNT_U0(x)                                              \
6232
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6233
#define OP_USE_COUNT_U1(x)                                              \
6234
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6235
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6236
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6237

6238
__attribute__((constructor))
6239
static void vcode_check_unions(void)
6240
{
6241
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6242
   for (int i = 0; i < 256; i++) {
6243
      assert(OP_USE_COUNT_U0(i) <= 1);
6244
      assert(OP_USE_COUNT_U1(i) <= 1);
6245
   }
6246
}
6247
#endif  // VCODE_CHECK_UNIONS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc