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

nickg / nvc / 16552692117

27 Jul 2025 11:44AM UTC coverage: 92.398% (+0.02%) from 92.381%
16552692117

push

github

nickg
Rename global event callbacks to phase callbacks

30 of 33 new or added lines in 6 files covered. (90.91%)

542 existing lines in 7 files now uncovered.

71921 of 77838 relevant lines covered (92.4%)

559922.87 hits per line

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

96.78
/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);
13,264,407✔
36
DECLARE_AND_DEFINE_ARRAY(vcode_block);
463,999✔
37
DECLARE_AND_DEFINE_ARRAY(vcode_type);
105,536✔
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                                       \
43
    || x == VCODE_OP_BIND_EXTERNAL || x == VCODE_OP_ARRAY_SCOPE         \
44
    || x == VCODE_OP_RECORD_SCOPE || x == VCODE_OP_SYSCALL)
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 || x == VCODE_OP_SYSCALL)
53
#define OP_HAS_IDENT(x)                                                 \
54
   (x == VCODE_OP_LINK_VAR || x == VCODE_OP_LINK_PACKAGE                \
55
    || x == VCODE_OP_DEBUG_LOCUS || x == VCODE_OP_BIND_EXTERNAL)
56
#define OP_HAS_OBJECT(x)                                                 \
57
   (x == VCODE_OP_DEBUG_LOCUS)
58
#define OP_HAS_REAL(x)                                                  \
59
   (x == VCODE_OP_CONST_REAL)
60
#define OP_HAS_VALUE(x)                                                 \
61
   (x == VCODE_OP_CONST || x == VCODE_OP_CONST_REP)
62
#define OP_HAS_DIM(x)                                                   \
63
   (x == VCODE_OP_UARRAY_LEFT || x == VCODE_OP_UARRAY_RIGHT             \
64
    || x == VCODE_OP_UARRAY_DIR || x == VCODE_OP_UARRAY_LEN)
65
#define OP_HAS_HOPS(x)                                                  \
66
   (x == VCODE_OP_VAR_UPREF || x == VCODE_OP_CONTEXT_UPREF)
67
#define OP_HAS_FIELD(x)                                                 \
68
   (x == VCODE_OP_RECORD_REF)
69
#define OP_HAS_CMP(x)                                                   \
70
   (x == VCODE_OP_CMP)
71
#define OP_HAS_TAG(x)                                                   \
72
   (x == VCODE_OP_COVER_STMT || x == VCODE_OP_COVER_BRANCH              \
73
    || x == VCODE_OP_COVER_TOGGLE || x == VCODE_OP_COVER_EXPR           \
74
    || x == VCODE_OP_COVER_STATE)
75
#define OP_HAS_COMMENT(x)                                               \
76
   (x == VCODE_OP_COMMENT)
77
#define OP_HAS_TARGET(x)                                                \
78
   (x == VCODE_OP_WAIT || x == VCODE_OP_JUMP || x == VCODE_OP_COND      \
79
    || x == VCODE_OP_PCALL || x == VCODE_OP_CASE)
80

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

106
DECLARE_AND_DEFINE_ARRAY(op);
15,823,678✔
107

108
typedef struct {
109
   op_array_t ops;
110
   loc_t      last_loc;
111
} block_t;
112

113
typedef struct {
114
   vcode_type_t type;
115
   vcode_type_t bounds;
116
} reg_t;
117

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

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

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

159
DECLARE_AND_DEFINE_ARRAY(param);
47,411✔
160
DECLARE_AND_DEFINE_ARRAY(var);
568,050✔
161
DECLARE_AND_DEFINE_ARRAY(reg);
12,761,859✔
162
DECLARE_AND_DEFINE_ARRAY(block);
188,600✔
163
DECLARE_AND_DEFINE_ARRAY(vtype);
112,281,714✔
164

165
typedef enum {
166
   UNIT_UNDEFINED     = (1 << 1),
167
} unit_flags_t;
168

169
struct _vcode_unit {
170
   vunit_kind_t   kind;
171
   vcode_unit_t   context;
172
   ident_t        name;
173
   vcode_type_t   result;
174
   block_array_t  blocks;
175
   reg_array_t    regs;
176
   vtype_array_t  types;
177
   var_array_t    vars;
178
   param_array_t  params;
179
   unsigned       depth;
180
   unit_flags_t   flags;
181
   vcode_unit_t   children;
182
   vcode_unit_t   next;
183
   object_t      *object;
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)
47,792✔
218
{
219
   int64_t result;
47,792✔
220
   if (__builtin_add_overflow(a, b, &result))
47,792✔
221
      return b < 0 ? INT64_MIN : INT64_MAX;
10,407✔
222

223
   return result;
224
}
225

226
static inline int64_t ssub64(int64_t a, int64_t b)
86,732✔
227
{
228
   int64_t result;
86,732✔
229
   if (__builtin_sub_overflow(a, b, &result))
86,732✔
230
      return b > 0 ? INT64_MIN : INT64_MAX;
1,166✔
231

232
   return result;
233
}
234

235
static inline int64_t smul64(int64_t a, int64_t b)
15,368✔
236
{
237
   int64_t result;
15,368✔
238
   if (__builtin_mul_overflow(a, b, &result))
15,368✔
239
      return (a > 0 && b > 0) || (a < 0 && b < 0) ? INT64_MAX : INT64_MIN;
2,221✔
240

241
   return result;
242
}
243

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

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

254
   return reg;
1,962,298✔
255
}
256

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

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

269
   VCODE_ASSERT(
2,505,566✔
270
      !vcode_block_finished(),
271
      "attempt to add to already finished block %d", active_block);
272

273
   block_t *block = vcode_block_data();
2,505,566✔
274

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

281
   return op;
2,505,566✔
282
}
283

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

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

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

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

303
static op_t *vcode_find_definition(vcode_reg_t reg)
2,139,202✔
304
{
305
   for (int i = active_block; i >= 0; i--) {
2,189,144✔
306
      block_t *b = &(active_unit->blocks.items[i]);
2,186,858✔
307
      for (int j = b->ops.count - 1; j >= 0; j--) {
42,052,570✔
308
         if (b->ops.items[j].result == reg)
42,002,628✔
309
            return &(b->ops.items[j]);
2,136,916✔
310
      }
311
   }
312

313
   return NULL;
314
}
315

316
#ifdef DEBUG
317
static void vcode_assert_const(vcode_reg_t reg, const char *what)
2,114,333✔
318
{
319
   op_t *defn = vcode_find_definition(reg);
2,114,333✔
320
   VCODE_ASSERT(defn != NULL, "constant %s uses parameter r%d",
2,114,333✔
321
                what, reg);
322
   VCODE_ASSERT(defn->kind == VCODE_OP_CONST
2,114,333✔
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
}
2,114,333✔
331
#endif
332

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

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

346
   int depth = MASK_CONTEXT(type);
107,843,498✔
347
   assert(depth <= unit->depth);
107,843,498✔
348
   while (depth != unit->depth)
109,454,520✔
349
      unit = unit->context;
1,611,022✔
350

351
   return vtype_array_nth_ptr(&(unit->types), MASK_INDEX(type));
107,843,498✔
352
}
353

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

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

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

370
   switch (defn->kind) {
22,583✔
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,638✔
392
      vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,638✔
393
      break;
1,638✔
394

395
   case VCODE_OP_VAR_UPREF:
1,010✔
396
      {
397
         vcode_unit_t vu = vcode_active_unit();
1,010✔
398
         for (int i = 0; i < defn->hops; i++)
2,024✔
399
            vu = vcode_unit_context(vu);
1,014✔
400

401
         vcode_state_t state;
1,010✔
402
         vcode_state_save(&state);
1,010✔
403

404
         vcode_select_unit(vu);
1,010✔
405

406
         vcode_var_data(defn->address)->flags |= VAR_HEAP;
1,010✔
407

408
         vcode_state_restore(&state);
1,010✔
409
      }
410
      break;
1,010✔
411

412
   case VCODE_OP_ARRAY_REF:
691✔
413
      vcode_heap_allocate(defn->args.items[0]);
691✔
414
      break;
691✔
415

416
   case VCODE_OP_WRAP:
6,665✔
417
   case VCODE_OP_UNWRAP:
418
   case VCODE_OP_RESOLVED:
419
      vcode_heap_allocate(defn->args.items[0]);
6,665✔
420
      break;
6,665✔
421

422
   case VCODE_OP_LAST_VALUE:
423
      // Returns a pointer into the C heap
424
      break;
425

426
   case VCODE_OP_LOAD:
1,929✔
427
      {
428
         if (vcode_reg_kind(reg) != VCODE_TYPE_UARRAY)
1,929✔
429
            return;
430

431
         // Any store to this variable must be heap allocated
432
         for (int i = 0; i < active_unit->blocks.count; i++) {
29,436✔
433
            block_t *b = &(active_unit->blocks.items[i]);
27,569✔
434
            for (int j = 0; j < b->ops.count; j++) {
372,851✔
435
               op_t *op = &(b->ops.items[j]);
345,282✔
436
               if (op->kind == VCODE_OP_STORE && op->address == defn->address)
345,282✔
437
                  vcode_heap_allocate(op->args.items[0]);
1,867✔
438

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

447
   case VCODE_OP_FCALL:
448
      for (int i = 0; i < defn->args.count; i++) {
9,720✔
449
         const vtype_kind_t rkind = vcode_reg_kind(reg);
7,201✔
450
         if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY) {
7,201✔
451
            // Function may return a pointer to its argument
452
            vcode_heap_allocate(defn->args.items[i]);
7,025✔
453
         }
454
      }
455
      break;
456

457
   case VCODE_OP_RECORD_REF:
32✔
458
      vcode_heap_allocate(defn->args.items[0]);
32✔
459
      break;
32✔
460

461
   case VCODE_OP_SELECT:
59✔
462
      vcode_heap_allocate(defn->args.items[1]);
59✔
463
      vcode_heap_allocate(defn->args.items[2]);
59✔
464
      break;
59✔
465

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

475
   case VCODE_OP_ALL:
476
      // Must have been allocated on the heap
477
      break;
478

479
   case VCODE_OP_NEW:
480
      // On the heap by definition
481
      break;
482

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

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

521
void vcode_state_save(vcode_state_t *state)
51,566✔
522
{
523
   state->unit  = active_unit;
51,566✔
524
   state->block = active_block;
51,566✔
525
}
51,566✔
526

527
void vcode_state_restore(const vcode_state_t *state)
51,566✔
528
{
529
   active_unit  = state->unit;
51,566✔
530
   active_block = state->block;
51,566✔
531
}
51,566✔
532

533
void vcode_unit_unref(vcode_unit_t unit)
69,985✔
534
{
535
   assert(unit != NULL);
69,985✔
536

537
   if (unit == active_unit)
69,985✔
538
      vcode_close();
15,500✔
539

540
   for (vcode_unit_t it = unit->children; it != NULL; it = it->next) {
92,003✔
541
      assert(it->context == unit);
22,018✔
542
      it->context = NULL;
22,018✔
543
   }
544
   unit->children = NULL;
69,985✔
545

546
   if (unit->context != NULL) {
69,985✔
547
      vcode_unit_t *it = &(unit->context->children);
18,350✔
548
      for (; *it != NULL && *it != unit; it = &((*it)->next))
54,257✔
549
         ;
550
      assert(*it != NULL);
18,350✔
551
      *it = (*it)->next;
18,350✔
552
   }
553

554
   for (unsigned i = 0; i < unit->blocks.count; i++) {
258,547✔
555
      block_t *b = &(unit->blocks.items[i]);
188,562✔
556

557
      for (unsigned j = 0; j < b->ops.count; j++) {
2,574,263✔
558
         op_t *o = &(b->ops.items[j]);
2,385,701✔
559
         if (OP_HAS_COMMENT(o->kind))
2,385,701✔
560
            free(o->comment);
263,718✔
561
         if (OP_HAS_TARGET(o->kind))
2,385,701✔
562
            free(o->targets.items);
109,818✔
563
         free(o->args.items);
2,385,701✔
564
      }
565
      free(b->ops.items);
188,562✔
566
   }
567
   free(unit->blocks.items);
69,985✔
568

569
   for (unsigned i = 0; i < unit->types.count; i++) {
965,075✔
570
      vtype_t *vt = &(unit->types.items[i]);
895,090✔
571
      if (vt->kind == VCODE_TYPE_RECORD)
895,090✔
572
         free(vt->fields.items);
7,382✔
573
   }
574
   free(unit->types.items);
69,985✔
575

576
   free(unit->regs.items);
69,985✔
577
   free(unit->vars.items);
69,985✔
578
   free(unit->params.items);
69,985✔
579
   free(unit);
69,985✔
580
}
69,985✔
581

582
vcode_unit_t vcode_unit_next(vcode_unit_t unit)
23,367✔
583
{
584
   return unit->next;
23,367✔
585
}
586

587
vcode_unit_t vcode_unit_child(vcode_unit_t unit)
21,028✔
588
{
589
   return unit->children;
21,028✔
590
}
591

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

598
vcode_type_t vcode_reg_type(vcode_reg_t reg)
7,194,605✔
599
{
600
   return vcode_reg_data(reg)->type;
7,194,605✔
601
}
602

603
vtype_kind_t vcode_reg_kind(vcode_reg_t reg)
1,864,052✔
604
{
605
   return vtype_kind(vcode_reg_type(reg));
1,864,052✔
606
}
607

608
vcode_type_t vcode_reg_bounds(vcode_reg_t reg)
594,895✔
609
{
610
   return vcode_reg_data(reg)->bounds;
594,895✔
611
}
612

613
bool vcode_reg_const(vcode_reg_t reg, int64_t *value)
1,182,983✔
614
{
615
   reg_t *r = vcode_reg_data(reg);
1,182,983✔
616

617
   vtype_kind_t kind = vtype_kind(r->type);
1,182,983✔
618
   if (kind != VCODE_TYPE_INT && kind != VCODE_TYPE_OFFSET)
1,182,983✔
619
      return false;
620

621
   vtype_t *bounds = vcode_type_data(r->bounds);
1,140,737✔
622

623
   VCODE_ASSERT(
1,140,737✔
624
      bounds->kind == VCODE_TYPE_INT || bounds->kind == VCODE_TYPE_OFFSET,
625
      "integer register r%d has non-integer bounds", reg);
626

627
   if (bounds->low == bounds->high) {
1,140,737✔
628
      if (value) *value = bounds->low;
655,689✔
629
      return true;
655,689✔
630
   }
631
   else
632
      return false;
633
}
634

635
void vcode_opt(void)
70,007✔
636
{
637
   // Prune assignments to unused registers
638

639
   int *uses LOCAL = xmalloc_array(active_unit->regs.count, sizeof(int));
140,014✔
640

641
   int pruned = 0;
70,007✔
642
   do {
99,999✔
643
      memset(uses, '\0', active_unit->regs.count * sizeof(int));
99,999✔
644
      pruned = 0;
99,999✔
645

646
      for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
411,764✔
647
         block_t *b = &(active_unit->blocks.items[i]);
311,765✔
648

649
         for (int j = b->ops.count - 1; j >= 0; j--) {
4,769,983✔
650
            op_t *o = &(b->ops.items[j]);
4,458,218✔
651

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

714
            default:
715
               break;
716
            }
717

718
            for (int k = 0; k < o->args.count; k++) {
12,427,551✔
719
               if (o->args.items[k] != VCODE_INVALID_REG)
7,969,333✔
720
                  uses[o->args.items[k]]++;
7,905,936✔
721
            }
722
         }
723
      }
724
   } while (pruned > 0);
99,999✔
725

726
   for (int i = active_unit->blocks.count - 1; i >= 0; i--) {
258,607✔
727
      block_t *b = &(active_unit->blocks.items[i]);
188,600✔
728
      op_t *dst = &(b->ops.items[0]);
188,600✔
729
      size_t copied = 0;
188,600✔
730
      for (int j = 0; j < b->ops.count; j++) {
2,694,166✔
731
         const op_t *src = &(b->ops.items[j]);
2,505,566✔
732
         if (src->kind != (vcode_op_t)-1) {
2,505,566✔
733
            if (src != dst) {
2,386,206✔
734
               assert(dst < src);
798,670✔
735
               *dst = *src;
798,670✔
736
            }
737
            dst++;
2,386,206✔
738
            copied++;
2,386,206✔
739
         }
740
      }
741

742
      assert(copied <= b->ops.count);
188,600✔
743
      b->ops.count = copied;
188,600✔
744
   }
745
}
70,007✔
746

747
void vcode_close(void)
40,999✔
748
{
749
   active_unit  = NULL;
40,999✔
750
   active_block = -1;
40,999✔
751
}
40,999✔
752

753
int vcode_count_blocks(void)
90,891✔
754
{
755
   assert(active_unit != NULL);
90,891✔
756
   return active_unit->blocks.count;
90,891✔
757
}
758

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

766
int vcode_count_vars(void)
69,611✔
767
{
768
   assert(active_unit != NULL);
69,611✔
769
   return active_unit->vars.count;
69,611✔
770
}
771

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

780
   return VCODE_INVALID_VAR;
781
}
782

783
ident_t vcode_var_name(vcode_var_t var)
95,617✔
784
{
785
   return vcode_var_data(var)->name;
95,617✔
786
}
787

788
vcode_type_t vcode_var_type(vcode_var_t var)
96,699✔
789
{
790
   return vcode_var_data(var)->type;
96,699✔
791
}
792

793
vcode_type_t vcode_var_bounds(vcode_var_t var)
4,525✔
794
{
795
   return vcode_var_data(var)->bounds;
4,525✔
796
}
797

798
vcode_var_flags_t vcode_var_flags(vcode_var_t var)
98,471✔
799
{
800
   return vcode_var_data(var)->flags;
98,471✔
801
}
802

803
vcode_op_t vcode_get_op(int op)
3,189,224✔
804
{
805
   return vcode_op_data(op)->kind;
3,189,224✔
806
}
807

808
ident_t vcode_get_func(int op)
126,042✔
809
{
810
   op_t *o = vcode_op_data(op);
126,042✔
811
   assert(OP_HAS_FUNC(o->kind));
126,042✔
812
   return o->func;
126,042✔
813
}
814

815
ident_t vcode_get_ident(int op)
24,762✔
816
{
817
   op_t *o = vcode_op_data(op);
24,762✔
818
   assert(OP_HAS_IDENT(o->kind));
24,762✔
819
   return o->ident;
24,762✔
820
}
821

822
object_t *vcode_get_object(int op)
101,024✔
823
{
824
   op_t *o = vcode_op_data(op);
101,024✔
825
   assert(OP_HAS_IDENT(o->kind));
101,024✔
826
   return o->object;
101,024✔
827
}
828

829
int64_t vcode_get_value(int op)
480,110✔
830
{
831
   op_t *o = vcode_op_data(op);
480,110✔
832
   assert(OP_HAS_VALUE(o->kind));
480,110✔
833
   return o->value;
480,110✔
834
}
835

836
double vcode_get_real(int op)
29,651✔
837
{
838
   op_t *o = vcode_op_data(op);
29,651✔
839
   assert(OP_HAS_REAL(o->kind));
29,651✔
840
   return o->real;
29,651✔
841
}
842

843
vcode_var_t vcode_get_address(int op)
239,491✔
844
{
845
   op_t *o = vcode_op_data(op);
239,491✔
846
   assert(OP_HAS_ADDRESS(o->kind));
239,491✔
847
   return o->address;
239,491✔
848
}
849

850
unsigned vcode_get_dim(int op)
90,448✔
851
{
852
   op_t *o = vcode_op_data(op);
90,448✔
853
   assert(OP_HAS_DIM(o->kind));
90,448✔
854
   return o->dim;
90,448✔
855
}
856

857
int vcode_get_hops(int op)
77,317✔
858
{
859
   op_t *o = vcode_op_data(op);
77,317✔
860
   assert(OP_HAS_HOPS(o->kind));
77,317✔
861
   return o->hops;
77,317✔
862
}
863

864
int vcode_get_field(int op)
47,265✔
865
{
866
   op_t *o = vcode_op_data(op);
47,265✔
867
   assert(OP_HAS_FIELD(o->kind));
47,265✔
868
   return o->field;
47,265✔
869
}
870

871
vcode_var_t vcode_get_type(int op)
87,209✔
872
{
873
   op_t *o = vcode_op_data(op);
87,209✔
874
   assert(OP_HAS_TYPE(o->kind));
87,209✔
875
   return o->type;
87,209✔
876
}
877

878
int vcode_count_args(int op)
324,435✔
879
{
880
   return vcode_op_data(op)->args.count;
324,435✔
881
}
882

883
vcode_reg_t vcode_get_arg(int op, int arg)
4,281,598✔
884
{
885
   op_t *o = vcode_op_data(op);
4,281,598✔
886
   return vcode_reg_array_nth(&(o->args), arg);
4,281,598✔
887
}
888

889
vcode_reg_t vcode_get_result(int op)
1,637,138✔
890
{
891
   op_t *o = vcode_op_data(op);
1,637,138✔
892
   return o->result;
1,637,138✔
893
}
894

895
vcode_cmp_t vcode_get_cmp(int op)
44,748✔
896
{
897
   op_t *o = vcode_op_data(op);
44,748✔
898
   assert(OP_HAS_CMP(o->kind));
44,748✔
899
   return o->cmp;
44,748✔
900
}
901

902
uint32_t vcode_get_tag(int op)
3,624✔
903
{
904
   op_t *o = vcode_op_data(op);
3,624✔
905
   assert(OP_HAS_TAG(o->kind));
3,624✔
906
   return o->tag;
3,624✔
907
}
908

909
const loc_t *vcode_get_loc(int op)
2,379,233✔
910
{
911
   op_t *o = vcode_op_data(op);
2,379,233✔
912
   return &(o->loc);
2,379,233✔
913
}
914

915
vcode_block_t vcode_get_target(int op, int nth)
154,793✔
916
{
917
   op_t *o = vcode_op_data(op);
154,793✔
918
   assert(OP_HAS_TARGET(o->kind));
154,793✔
919
   return vcode_block_array_nth(&(o->targets), nth);
154,793✔
920
}
921

922
bool vcode_block_empty(void)
×
923
{
924
   assert(active_unit != NULL);
×
925
   assert(active_block != VCODE_INVALID_BLOCK);
×
926

927
   return active_unit->blocks.items[active_block].ops.count == 0;
×
928
}
929

930
bool vcode_block_finished(void)
2,666,199✔
931
{
932
   assert(active_unit != NULL);
2,666,199✔
933
   assert(active_block != VCODE_INVALID_BLOCK);
2,666,199✔
934

935
   const block_t *b = &(active_unit->blocks.items[active_block]);
2,666,199✔
936
   if (b->ops.count == 0)
2,666,199✔
937
      return false;
938
   else {
939
      vcode_op_t kind = b->ops.items[b->ops.count - 1].kind;
2,409,540✔
940
      return kind == VCODE_OP_WAIT || kind == VCODE_OP_JUMP
2,409,540✔
941
         || kind == VCODE_OP_COND || kind == VCODE_OP_PCALL
2,409,516✔
942
         || kind == VCODE_OP_RETURN || kind == VCODE_OP_CASE
943
         || kind == VCODE_OP_UNREACHABLE;
4,819,056✔
944
   }
945
}
946

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

984
LCOV_EXCL_START
985
static int vcode_dump_reg(vcode_reg_t reg)
986
{
987
   if (reg == VCODE_INVALID_REG)
988
      return color_printf("$red$invalid$$");
989
   else
990
      return color_printf("$green$r%d$$", reg);
991
}
992

993
static int vcode_pretty_print_int(int64_t n)
994
{
995
   if (n == INT64_MAX)
996
      return printf("2^63-1");
997
   else if (n == INT64_MIN)
998
      return printf("-2^63");
999
   else if (n == INT32_MAX)
1000
      return printf("2^31-1");
1001
   else if (n == INT32_MIN)
1002
      return printf("-2^31");
1003
   else
1004
      return printf("%"PRIi64, n);
1005
}
1006

1007
static int vcode_dump_one_type(vcode_type_t type)
1008
{
1009
   int col = 0;
1010
   vtype_t *vt = vcode_type_data(type);
1011
   switch (vt->kind) {
1012
   case VCODE_TYPE_INT:
1013
      if (vt->low != vt->high) {
1014
         col += vcode_pretty_print_int(vt->low);
1015
         col += printf("..");
1016
         col += vcode_pretty_print_int(vt->high);
1017
      }
1018
      else
1019
         col += vcode_pretty_print_int(vt->low);
1020
      break;
1021

1022
   case VCODE_TYPE_REAL:
1023
      if (vt->rlow == -DBL_MAX && vt->rhigh == DBL_MAX)
1024
         col += printf("%%");
1025
      else if (vt->rlow == vt->rhigh)
1026
         col += printf("%f", vt->rlow);
1027
      else
1028
         col += printf("%f..%f", vt->rlow, vt->rhigh);
1029
      break;
1030

1031
   case VCODE_TYPE_CARRAY:
1032
      {
1033
         col += printf("[%u] : ", vt->size);
1034
         col += vcode_dump_one_type(vt->elem);
1035
         if (!vtype_eq(vt->elem, vt->bounds)) {
1036
            col += printf(" => ");
1037
            col += vcode_dump_one_type(vt->bounds);
1038
         }
1039
      }
1040
      break;
1041

1042
   case VCODE_TYPE_UARRAY:
1043
      {
1044
         col += printf("[");
1045
         for (unsigned i = 0; i < vt->dims; i++)
1046
            col += printf("%s*", i > 0 ? ", " : "");
1047
         col += printf("] : ");
1048
         col += vcode_dump_one_type(vt->elem);
1049
         if (!vtype_eq(vt->elem, vt->bounds)) {
1050
            col += printf(" => ");
1051
            col += vcode_dump_one_type(vt->bounds);
1052
         }
1053
      }
1054
      break;
1055

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

1062
   case VCODE_TYPE_ACCESS:
1063
      col += printf("A<");
1064
      col += vcode_dump_one_type(vt->pointed);
1065
      col += printf(">");
1066
      break;
1067

1068
   case VCODE_TYPE_SIGNAL:
1069
      col += printf("$<");
1070
      col += vcode_dump_one_type(vt->base);
1071
      col += printf(">");
1072
      break;
1073

1074
   case VCODE_TYPE_OFFSET:
1075
      col += printf("#");
1076
      break;
1077

1078
   case VCODE_TYPE_RECORD:
1079
      col += printf("%s{}", istr(vt->name));
1080
      break;
1081

1082
   case VCODE_TYPE_FILE:
1083
      col += printf("F<");
1084
      col += vcode_dump_one_type(vt->base);
1085
      col += printf(">");
1086
      break;
1087

1088
   case VCODE_TYPE_OPAQUE:
1089
      col += printf("?");
1090
      break;
1091

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

1098
   case VCODE_TYPE_CLOSURE:
1099
      col += printf("C<");
1100
      col += vcode_dump_one_type(vt->base);
1101
      col += printf(">");
1102
      break;
1103

1104
   case VCODE_TYPE_CONTEXT:
1105
      col += printf("P<%s>", istr(vt->name));
1106
      break;
1107

1108
   case VCODE_TYPE_DEBUG_LOCUS:
1109
      col += printf("D<>");
1110
      break;
1111

1112
   case VCODE_TYPE_TRIGGER:
1113
      col += printf("T<>");
1114
      break;
1115

1116
   case VCODE_TYPE_CONVERSION:
1117
      col += printf("X<>");
1118
      break;
1119
   }
1120

1121
   return col;
1122
}
1123

1124
static void vcode_dump_tab(int col, int to_col)
1125
{
1126
   if (col >= to_col)
1127
      printf(" ");
1128
   else {
1129
      while (col < to_col)
1130
         col += printf(" ");
1131
   }
1132
}
1133

1134
static void vcode_dump_comment(int col)
1135
{
1136
   vcode_dump_tab(col, 40);
1137
   color_printf("$cyan$// ");
1138
}
1139

1140
static void vcode_dump_type(int col, vcode_type_t type, vcode_type_t bounds)
1141
{
1142
   vcode_dump_comment(col);
1143
   vcode_dump_one_type(type);
1144
   if (!vtype_eq(type, bounds)) {
1145
      printf(" => ");
1146
      vcode_dump_one_type(bounds);
1147
   }
1148
}
1149

1150
static void vcode_dump_result_type(int col, const op_t *op)
1151
{
1152
   if (op->result != VCODE_INVALID_REG) {
1153
      reg_t *r = vcode_reg_data(op->result);
1154
      vcode_dump_type(col, r->type, r->bounds);
1155
   }
1156
}
1157

1158
static int vcode_dump_var(vcode_var_t var, int hops)
1159
{
1160
   vcode_unit_t owner = active_unit;
1161
   while (owner && hops--)
1162
      owner = owner->context;
1163

1164
   if (owner == NULL || var >= owner->vars.count)
1165
      return color_printf("$red$invalid$$");
1166
   else {
1167
      var_t *v = var_array_nth_ptr(&(owner->vars), var);
1168
      return color_printf("$magenta$%s$$", istr(v->name));
1169
   }
1170
}
1171

1172
void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg)
1173
{
1174
   assert(active_unit != NULL);
1175

1176
   const vcode_unit_t vu = active_unit;
1177
   vcode_block_t old_block = active_block;
1178

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

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

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

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

1234
   if (vu->result != VCODE_INVALID_TYPE) {
1235
      color_printf("Result     $cyan$");
1236
      vcode_dump_one_type(vu->result);
1237
      color_printf("$$\n");
1238
   }
1239

1240
   if (vu->kind == VCODE_UNIT_FUNCTION
1241
       || vu->kind == VCODE_UNIT_PROCEDURE
1242
       || vu->kind == VCODE_UNIT_PROPERTY
1243
       || (vu->kind == VCODE_UNIT_PROTECTED && vu->params.count > 0)) {
1244

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

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

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

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

1289
         case VCODE_OP_CONST:
1290
            {
1291
               col += vcode_dump_reg(op->result);
1292
               col += printf(" := %s %"PRIi64"",
1293
                             vcode_op_string(op->kind),
1294
                             op->value);
1295
               vcode_dump_result_type(col, op);
1296
            }
1297
            break;
1298

1299
         case VCODE_OP_CONST_REAL:
1300
            {
1301
               col += vcode_dump_reg(op->result);
1302
               col += printf(" := %s %g",
1303
                             vcode_op_string(op->kind),
1304
                             op->real);
1305
               vcode_dump_result_type(col, op);
1306
            }
1307
            break;
1308

1309
         case VCODE_OP_ALLOC:
1310
            {
1311
               col += vcode_dump_reg(op->result);
1312
               col += printf(" := %s ", vcode_op_string(op->kind));
1313
               col += vcode_dump_reg(op->args.items[0]);
1314
               vcode_dump_result_type(col, op);
1315
            }
1316
            break;
1317

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

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

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

1369
         case VCODE_OP_DRIVE_SIGNAL:
1370
            {
1371
               printf("%s ", vcode_op_string(op->kind));
1372
               vcode_dump_reg(op->args.items[0]);
1373
               printf(" count ");
1374
               vcode_dump_reg(op->args.items[1]);
1375
            }
1376
            break;
1377

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

1393
         case VCODE_OP_RESOLVE_SIGNAL:
1394
            {
1395
               printf("%s ", vcode_op_string(op->kind));
1396
               vcode_dump_reg(op->args.items[0]);
1397
               printf(" resolution ");
1398
               vcode_dump_reg(op->args.items[1]);
1399
            }
1400
            break;
1401

1402
         case VCODE_OP_PACKAGE_SCOPE:
1403
         case VCODE_OP_ARRAY_SCOPE:
1404
         case VCODE_OP_RECORD_SCOPE:
1405
            {
1406
               col += printf("%s locus ", vcode_op_string(op->kind));
1407
               col += vcode_dump_reg(op->args.items[0]);
1408
               vcode_dump_type(col, op->type, op->type);
1409
            }
1410
            break;
1411

1412
         case VCODE_OP_POP_SCOPE:
1413
            {
1414
               printf("%s", vcode_op_string(op->kind));
1415
            }
1416
            break;
1417

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1709
               putchar(op->kind == VCODE_OP_CONST_ARRAY ? ']' : '}');
1710
               vcode_dump_result_type(col + 1, op);
1711
            }
1712
            break;
1713

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2127
         case VCODE_OP_DIR_CHECK:
2128
            {
2129
               col += printf("%s ", vcode_op_string(op->kind));
2130
               col += vcode_dump_reg(op->args.items[0]);
2131
               col += printf(" == ");
2132
               col += vcode_dump_reg(op->args.items[1]);
2133
               col += printf(" locus ");
2134
               col += vcode_dump_reg(op->args.items[2]);
2135
            }
2136
            break;
2137

2138
         case VCODE_OP_DEBUG_OUT:
2139
            {
2140
               col += printf("%s ", vcode_op_string(op->kind));
2141
               col += vcode_dump_reg(op->args.items[0]);
2142
            }
2143
            break;
2144

2145
         case VCODE_OP_COVER_STMT:
2146
         case VCODE_OP_COVER_BRANCH:
2147
         case VCODE_OP_COVER_EXPR:
2148
            {
2149
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2150
            }
2151
            break;
2152

2153
         case VCODE_OP_COVER_TOGGLE:
2154
         case VCODE_OP_COVER_STATE:
2155
            {
2156
               printf("%s %u ", vcode_op_string(op->kind), op->tag);
2157
               vcode_dump_reg(op->args.items[0]);
2158
            }
2159
            break;
2160

2161
         case VCODE_OP_UNDEFINED:
2162
            {
2163
               col += vcode_dump_reg(op->result);
2164
               col += printf(" := %s", vcode_op_string(op->kind));
2165
               vcode_dump_result_type(col, op);
2166
            }
2167
            break;
2168

2169
         case VCODE_OP_RANGE_LENGTH:
2170
         case VCODE_OP_RANGE_NULL:
2171
            {
2172
               col += vcode_dump_reg(op->result);
2173
               col += printf(" := %s left ", vcode_op_string(op->kind));
2174
               vcode_dump_reg(op->args.items[0]);
2175
               col += printf(" right ");
2176
               vcode_dump_reg(op->args.items[1]);
2177
               col += printf(" dir ");
2178
               col += vcode_dump_reg(op->args.items[2]);
2179
               vcode_dump_result_type(col, op);
2180
            }
2181
            break;
2182

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

2196
         case VCODE_OP_LINK_VAR:
2197
            {
2198
               col += vcode_dump_reg(op->result);
2199
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2200
               col += vcode_dump_reg(op->args.items[0]);
2201
               col += color_printf(" $magenta$%s$$", istr(op->ident));
2202
               vcode_dump_result_type(col, op);
2203
            }
2204
            break;
2205

2206
         case VCODE_OP_UNREACHABLE:
2207
            {
2208
               printf("%s", vcode_op_string(op->kind));
2209
               if (op->args.count > 0) {
2210
                  printf(" ");
2211
                  vcode_dump_reg(op->args.items[0]);
2212
               }
2213
            }
2214
            break;
2215

2216
         case VCODE_OP_DEBUG_LOCUS:
2217
            {
2218
               col += vcode_dump_reg(op->result);
2219
               col += color_printf(" := %s $magenta$",
2220
                                   vcode_op_string(op->kind));
2221

2222
               tree_t t = tree_from_object(op->object);
2223
               if (t != NULL)
2224
                  col += printf("%s@", tree_kind_str(tree_kind(t)));
2225

2226
               col += color_printf("%p$$", op->object);
2227
               vcode_dump_result_type(col, op);
2228
            }
2229
            break;
2230

2231
         case VCODE_OP_ENTER_STATE:
2232
            {
2233
               printf("%s ", vcode_op_string(op->kind));
2234
               vcode_dump_reg(op->args.items[0]);
2235
               if (op->args.count > 1) {
2236
                  printf(" strong ");
2237
                  vcode_dump_reg(op->args.items[1]);
2238
               }
2239
            }
2240
            break;
2241

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

2259
         case VCODE_OP_REFLECT_SUBTYPE:
2260
            {
2261
               col += vcode_dump_reg(op->result);
2262
               col += printf(" := %s context ", vcode_op_string(op->kind));
2263
               vcode_dump_reg(op->args.items[0]);
2264
               col += printf(" locus ");
2265
               col += vcode_dump_reg(op->args.items[1]);
2266
               if (op->args.count > 2) {
2267
                  col += printf(" bounds ");
2268
                  col += vcode_dump_reg(op->args.items[2]);
2269
               }
2270
               vcode_dump_result_type(col, op);
2271
            }
2272
            break;
2273

2274
         case VCODE_OP_FUNCTION_TRIGGER:
2275
            {
2276
               col += vcode_dump_reg(op->result);
2277
               col += color_printf(" := %s $magenta$%s$$ ",
2278
                                   vcode_op_string(op->kind), istr(op->func));
2279
               for (int i = 0; i < op->args.count; i++) {
2280
                  if (i > 0) col += printf(", ");
2281
                  col += vcode_dump_reg(op->args.items[i]);
2282
               }
2283
               vcode_dump_result_type(col, op);
2284
            }
2285
            break;
2286

2287
         case VCODE_OP_OR_TRIGGER:
2288
         case VCODE_OP_CMP_TRIGGER:
2289
            {
2290
               col += vcode_dump_reg(op->result);
2291
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2292
               col += vcode_dump_reg(op->args.items[0]);
2293
               if (op->kind == VCODE_OP_OR_TRIGGER)
2294
                  col += printf(" || ");
2295
               else
2296
                  col += printf(" == ");
2297
               col += vcode_dump_reg(op->args.items[1]);
2298
               vcode_dump_result_type(col, op);
2299
            }
2300
            break;
2301

2302
         case VCODE_OP_ADD_TRIGGER:
2303
            {
2304
               printf("%s ", vcode_op_string(op->kind));
2305
               vcode_dump_reg(op->args.items[0]);
2306
            }
2307
            break;
2308

2309
         case VCODE_OP_PUT_CONVERSION:
2310
            {
2311
               color_printf("%s ", vcode_op_string(op->kind));
2312
               vcode_dump_reg(op->args.items[0]);
2313
               printf(" signal ");
2314
               vcode_dump_reg(op->args.items[1]);
2315
               printf(" count ");
2316
               vcode_dump_reg(op->args.items[2]);
2317
               printf(" values ");
2318
               vcode_dump_reg(op->args.items[3]);
2319
            }
2320
            break;
2321

2322
         case VCODE_OP_PORT_CONVERSION:
2323
            {
2324
               col += vcode_dump_reg(op->result);
2325
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2326
               col += vcode_dump_reg(op->args.items[0]);
2327
               if (op->args.count > 1) {
2328
                  col += printf(" effective ");
2329
                  col += vcode_dump_reg(op->args.items[1]);
2330
               }
2331
               vcode_dump_result_type(col, op);
2332
            }
2333
            break;
2334

2335
         case VCODE_OP_CONVERT_IN:
2336
         case VCODE_OP_CONVERT_OUT:
2337
            {
2338
               color_printf("%s ", vcode_op_string(op->kind));
2339
               vcode_dump_reg(op->args.items[0]);
2340
               printf(" signal ");
2341
               vcode_dump_reg(op->args.items[1]);
2342
               printf(" count ");
2343
               vcode_dump_reg(op->args.items[2]);
2344
            }
2345
            break;
2346

2347
         case VCODE_OP_BIND_FOREIGN:
2348
            {
2349
               color_printf("%s ", vcode_op_string(op->kind));
2350
               vcode_dump_reg(op->args.items[0]);
2351
               printf(" length ");
2352
               vcode_dump_reg(op->args.items[1]);
2353
               if (op->args.count > 2) {
2354
                  printf(" locus ");
2355
                  vcode_dump_reg(op->args.items[1]);
2356
               }
2357
            }
2358
            break;
2359

2360
         case VCODE_OP_INSTANCE_NAME:
2361
         case VCODE_OP_BIND_EXTERNAL:
2362
            {
2363
               col += vcode_dump_reg(op->result);
2364
               col += color_printf(" := %s ", vcode_op_string(op->kind));
2365
               col += vcode_dump_reg(op->args.items[0]);
2366
               col += color_printf(" scope $magenta$%s$$", istr(op->ident));
2367
               vcode_dump_result_type(col, op);
2368
            }
2369
            break;
2370
         }
2371

2372
         if (j == mark_op && i == old_block)
2373
            color_printf("\t $red$<----$$");
2374

2375
         color_printf("$$\n");
2376

2377
         if (callback != NULL)
2378
            (*callback)(j, arg);
2379
      }
2380

2381
      if (b->ops.count == 0)
2382
         color_printf("  $yellow$%2d:$$ $red$Empty basic block$$\n", i);
2383
   }
2384

2385
   printf("\n");
2386
   fflush(stdout);
2387

2388
   active_block = old_block;
2389
}
2390
LCOV_EXCL_STOP
2391

2392
bool vtype_eq(vcode_type_t a, vcode_type_t b)
52,575,912✔
2393
{
2394
   assert(active_unit != NULL);
53,358,263✔
2395

2396
   if (a == b)
53,358,263✔
2397
      return true;
2398
   else {
2399
      const vtype_t *at = vcode_type_data(a);
48,672,450✔
2400
      const vtype_t *bt = vcode_type_data(b);
48,672,450✔
2401

2402
      if (at->kind != bt->kind)
48,672,450✔
2403
         return false;
2404

2405
      switch (at->kind) {
21,495,555✔
2406
      case VCODE_TYPE_INT:
18,503,711✔
2407
         return (at->low == bt->low) && (at->high == bt->high);
34,455,524✔
2408
      case VCODE_TYPE_REAL:
1,312,211✔
2409
         return (at->rlow == bt->rlow) && (at->rhigh == bt->rhigh);
2,529,620✔
2410
      case VCODE_TYPE_CARRAY:
125,615✔
2411
         return at->size == bt->size && vtype_eq(at->elem, bt->elem);
138,081✔
2412
      case VCODE_TYPE_UARRAY:
108,247✔
2413
         return at->dims == bt->dims && vtype_eq(at->elem, bt->elem);
136,458✔
2414
      case VCODE_TYPE_POINTER:
645,848✔
2415
      case VCODE_TYPE_ACCESS:
2416
         return vtype_eq(at->pointed, bt->pointed);
645,848✔
2417
      case VCODE_TYPE_OFFSET:
2418
      case VCODE_TYPE_OPAQUE:
2419
      case VCODE_TYPE_DEBUG_LOCUS:
2420
      case VCODE_TYPE_TRIGGER:
2421
      case VCODE_TYPE_CONVERSION:
2422
         return true;
2423
      case VCODE_TYPE_RESOLUTION:
136,503✔
2424
      case VCODE_TYPE_CLOSURE:
2425
      case VCODE_TYPE_SIGNAL:
2426
      case VCODE_TYPE_FILE:
2427
         return vtype_eq(at->base, bt->base);
136,503✔
2428
      case VCODE_TYPE_RECORD:
120,508✔
2429
      case VCODE_TYPE_CONTEXT:
2430
         return at->name == bt->name;
120,508✔
2431
      }
2432

UNCOV
2433
      return false;
×
2434
   }
2435
}
2436

UNCOV
2437
void vcode_dump(void)
×
2438
{
UNCOV
2439
   vcode_dump_with_mark(-1, NULL, NULL);
×
2440
}
×
2441

2442
static vcode_type_t vtype_new(vtype_t *new)
4,438,216✔
2443
{
2444
   int index = active_unit->types.count - 1;
4,438,216✔
2445
   vcode_type_t type = MAKE_HANDLE(active_unit->depth, index);
4,438,216✔
2446

2447
   for (int i = 0; i < index; i++) {
48,241,473✔
2448
      vcode_type_t this = MAKE_HANDLE(active_unit->depth, i);
47,346,120✔
2449
      if (vtype_eq(this, type)) {
47,346,120✔
2450
         active_unit->types.count--;
3,542,863✔
2451
         return this;
3,542,863✔
2452
      }
2453
   }
2454

2455
   return type;
2456
}
2457

2458
vcode_type_t vtype_int(int64_t low, int64_t high)
3,046,033✔
2459
{
2460
   assert(active_unit != NULL);
3,046,033✔
2461

2462
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
3,046,033✔
2463
   n->kind = VCODE_TYPE_INT;
3,046,033✔
2464
   n->low  = low;
3,046,033✔
2465
   n->high = high;
3,046,033✔
2466

2467
   switch (bits_for_range(low, high)) {
3,046,033✔
2468
   case 64:
171,196✔
2469
      n->repr = low < 0 ? VCODE_REPR_I64 : VCODE_REPR_U64;
171,196✔
2470
      break;
171,196✔
2471
   case 32:
859,668✔
2472
      n->repr = low < 0 ? VCODE_REPR_I32 : VCODE_REPR_U32;
859,668✔
2473
      break;
859,668✔
2474
   case 16:
5,775✔
2475
      n->repr = low < 0 ? VCODE_REPR_I16 : VCODE_REPR_U16;
5,775✔
2476
      break;
5,775✔
2477
   case 8:
1,137,636✔
2478
      n->repr = low < 0 ? VCODE_REPR_I8 : VCODE_REPR_U8;
1,137,636✔
2479
      break;
1,137,636✔
2480
   case 1:
871,757✔
2481
      n->repr = VCODE_REPR_U1;
871,757✔
2482
      break;
871,757✔
2483
   case 0:
1✔
2484
      n->repr = VCODE_REPR_I64;    // Null range
1✔
2485
      break;
1✔
UNCOV
2486
   default:
×
2487
      fatal_trace("cannot represent %"PRIi64"..%"PRIi64, low, high);
2488
   }
2489

2490
   return vtype_new(n);
3,046,033✔
2491
}
2492

2493
vcode_type_t vtype_bool(void)
444,784✔
2494
{
2495
   return vtype_int(0, 1);
444,784✔
2496
}
2497

2498
vcode_type_t vtype_carray(int size, vcode_type_t elem, vcode_type_t bounds)
68,560✔
2499
{
2500
   assert(active_unit != NULL);
68,560✔
2501

2502
   const vtype_kind_t ekind = vtype_kind(elem);
68,560✔
2503
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
68,560✔
2504
                "array types may not be nested");
2505

2506
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
68,560✔
2507
   memset(n, '\0', sizeof(vtype_t));
68,560✔
2508
   n->kind   = VCODE_TYPE_CARRAY;
68,560✔
2509
   n->elem   = elem;
68,560✔
2510
   n->bounds = bounds;
68,560✔
2511
   n->size   = MAX(size, 0);
68,560✔
2512

2513
   return vtype_new(n);
68,560✔
2514
}
2515

2516
vcode_type_t vtype_find_named_record(ident_t name)
48,343✔
2517
{
2518
   assert(active_unit != NULL);
48,343✔
2519

2520
   for (int i = 0; i < active_unit->types.count; i++) {
630,014✔
2521
      vtype_t *other = &(active_unit->types.items[i]);
615,250✔
2522
      if (other->kind == VCODE_TYPE_RECORD && other->name == name)
615,250✔
2523
         return MAKE_HANDLE(active_unit->depth, i);
33,579✔
2524
   }
2525

2526
   return VCODE_INVALID_TYPE;
2527
}
2528

2529
vcode_type_t vtype_named_record(ident_t name, const vcode_type_t *field_types,
14,764✔
2530
                                int nfields)
2531
{
2532
   assert(active_unit != NULL);
14,764✔
2533

2534
   vtype_t *data = NULL;
14,764✔
2535
   vcode_type_t handle = vtype_find_named_record(name);
14,764✔
2536
   if (handle == VCODE_INVALID_TYPE) {
14,764✔
2537
      data = vtype_array_alloc(&(active_unit->types));
7,382✔
2538
      memset(data, '\0', sizeof(vtype_t));
7,382✔
2539
      data->kind = VCODE_TYPE_RECORD;
7,382✔
2540
      data->name = name;
7,382✔
2541

2542
      handle = vtype_new(data);
7,382✔
2543
   }
2544
   else {
2545
      data = vcode_type_data(handle);
7,382✔
2546
      VCODE_ASSERT(data->fields.count == 0,
7,382✔
2547
                    "record type %s already defined", istr(name));
2548
   }
2549

2550
   vcode_type_array_resize(&(data->fields), 0, VCODE_INVALID_TYPE);
14,764✔
2551
   for (int i = 0; i < nfields; i++)
39,908✔
2552
      vcode_type_array_add(&(data->fields), field_types[i]);
25,144✔
2553

2554
   return handle;
14,764✔
2555
}
2556

2557
vcode_type_t vtype_uarray(int ndim, vcode_type_t elem, vcode_type_t bounds)
103,309✔
2558
{
2559
   assert(active_unit != NULL);
103,309✔
2560

2561
   const vtype_kind_t ekind = vtype_kind(elem);
103,309✔
2562
   VCODE_ASSERT(ekind != VCODE_TYPE_CARRAY && ekind != VCODE_TYPE_UARRAY,
103,309✔
2563
                "array types may not be nested");
2564

2565
   VCODE_ASSERT(ndim > 0, "uarray must have at least one dimension");
103,309✔
2566

2567
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
103,309✔
2568
   memset(n, '\0', sizeof(vtype_t));
103,309✔
2569
   n->kind   = VCODE_TYPE_UARRAY;
103,309✔
2570
   n->elem   = elem;
103,309✔
2571
   n->bounds = bounds;
103,309✔
2572
   n->dims   = ndim;
103,309✔
2573

2574
   return vtype_new(n);
103,309✔
2575
}
2576

2577
vcode_type_t vtype_pointer(vcode_type_t to)
273,265✔
2578
{
2579
   assert(active_unit != NULL);
273,265✔
2580

2581
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
273,265✔
2582
   n->kind    = VCODE_TYPE_POINTER;
273,265✔
2583
   n->pointed = to;
273,265✔
2584

2585
   VCODE_ASSERT(vtype_kind(to) != VCODE_TYPE_CARRAY,
273,265✔
2586
                "cannot get pointer to carray type");
2587

2588
   return vtype_new(n);
273,265✔
2589
}
2590

2591
vcode_type_t vtype_access(vcode_type_t to)
12,538✔
2592
{
2593
   assert(active_unit != NULL);
12,538✔
2594

2595
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
12,538✔
2596
   n->kind    = VCODE_TYPE_ACCESS;
12,538✔
2597
   n->pointed = to;
12,538✔
2598

2599
   return vtype_new(n);
12,538✔
2600
}
2601

2602
vcode_type_t vtype_signal(vcode_type_t base)
51,193✔
2603
{
2604
   assert(active_unit != NULL);
51,193✔
2605

2606
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
51,193✔
2607
   n->kind = VCODE_TYPE_SIGNAL;
51,193✔
2608
   n->base = base;
51,193✔
2609

2610
   VCODE_ASSERT(vtype_is_scalar(base), "signal base type must be scalar");
51,193✔
2611

2612
   return vtype_new(n);
51,193✔
2613
}
2614

2615
vcode_type_t vtype_resolution(vcode_type_t base)
10,081✔
2616
{
2617
   assert(active_unit != NULL);
10,081✔
2618

2619
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
10,081✔
2620
   n->kind = VCODE_TYPE_RESOLUTION;
10,081✔
2621
   n->base = base;
10,081✔
2622

2623
   return vtype_new(n);
10,081✔
2624
}
2625

2626
vcode_type_t vtype_closure(vcode_type_t result)
6,444✔
2627
{
2628
   assert(active_unit != NULL);
6,444✔
2629

2630
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
6,444✔
2631
   n->kind = VCODE_TYPE_CLOSURE;
6,444✔
2632
   n->base = result;
6,444✔
2633

2634
   return vtype_new(n);
6,444✔
2635
}
2636

2637
vcode_type_t vtype_context(ident_t name)
90,699✔
2638
{
2639
   assert(active_unit != NULL);
90,699✔
2640
   assert(name != NULL);
90,699✔
2641

2642
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
90,699✔
2643
   n->kind = VCODE_TYPE_CONTEXT;
90,699✔
2644
   n->name = name;
90,699✔
2645

2646
   return vtype_new(n);
90,699✔
2647
}
2648

2649
vcode_type_t vtype_file(vcode_type_t base)
2,355✔
2650
{
2651
   assert(active_unit != NULL);
2,355✔
2652

2653
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
2,355✔
2654
   n->kind = VCODE_TYPE_FILE;
2,355✔
2655
   n->base = base;
2,355✔
2656

2657
   return vtype_new(n);
2,355✔
2658
}
2659

2660
vcode_type_t vtype_offset(void)
403,741✔
2661
{
2662
   assert(active_unit != NULL);
403,741✔
2663

2664
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
403,741✔
2665
   n->kind = VCODE_TYPE_OFFSET;
403,741✔
2666
   n->low  = INT64_MIN;
403,741✔
2667
   n->high = INT64_MAX;
403,741✔
2668
   n->repr = VCODE_REPR_I64;
403,741✔
2669

2670
   return vtype_new(n);
403,741✔
2671
}
2672

2673
vcode_type_t vtype_time(void)
22,823✔
2674
{
2675
   return vtype_int(INT64_MIN, INT64_MAX);
22,823✔
2676
}
2677

2678
vcode_type_t vtype_char(void)
9,864✔
2679
{
2680
   return vtype_int(0, 255);
9,864✔
2681
}
2682

2683
vcode_type_t vtype_opaque(void)
4,623✔
2684
{
2685
   assert(active_unit != NULL);
4,623✔
2686

2687
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
4,623✔
2688
   n->kind = VCODE_TYPE_OPAQUE;
4,623✔
2689

2690
   return vtype_new(n);
4,623✔
2691
}
2692

2693
vcode_type_t vtype_debug_locus(void)
208,076✔
2694
{
2695
   assert(active_unit != NULL);
208,076✔
2696

2697
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
208,076✔
2698
   n->kind = VCODE_TYPE_DEBUG_LOCUS;
208,076✔
2699

2700
   return vtype_new(n);
208,076✔
2701
}
2702

2703
vcode_type_t vtype_trigger(void)
524✔
2704
{
2705
   assert(active_unit != NULL);
524✔
2706

2707
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
524✔
2708
   n->kind = VCODE_TYPE_TRIGGER;
524✔
2709

2710
   return vtype_new(n);
524✔
2711
}
2712

2713
vcode_type_t vtype_conversion(void)
568✔
2714
{
2715
   assert(active_unit != NULL);
568✔
2716

2717
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
568✔
2718
   n->kind = VCODE_TYPE_CONVERSION;
568✔
2719

2720
   return vtype_new(n);
568✔
2721
}
2722

2723
vcode_type_t vtype_real(double low, double high)
148,825✔
2724
{
2725
   assert(active_unit != NULL);
148,825✔
2726

2727
   vtype_t *n = vtype_array_alloc(&(active_unit->types));
148,825✔
2728
   n->kind  = VCODE_TYPE_REAL;
148,825✔
2729
   n->rlow  = low;
148,825✔
2730
   n->rhigh = high;
148,825✔
2731

2732
   return vtype_new(n);
148,825✔
2733
}
2734

2735
vtype_kind_t vtype_kind(vcode_type_t type)
6,501,381✔
2736
{
2737
   vtype_t *vt = vcode_type_data(type);
6,501,381✔
2738
   return vt->kind;
6,501,381✔
2739
}
2740

2741
vtype_repr_t vtype_repr(vcode_type_t type)
71,104✔
2742
{
2743
   vtype_t *vt = vcode_type_data(type);
71,104✔
2744
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
71,104✔
2745
   return vt->repr;
71,104✔
2746
}
2747

2748
vcode_type_t vtype_elem(vcode_type_t type)
201,257✔
2749
{
2750
   vtype_t *vt = vcode_type_data(type);
201,257✔
2751
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
201,257✔
2752
   return vt->elem;
201,257✔
2753
}
2754

2755
vcode_type_t vtype_base(vcode_type_t type)
68,548✔
2756
{
2757
   vtype_t *vt = vcode_type_data(type);
68,548✔
2758
   assert(vt->kind == VCODE_TYPE_SIGNAL || vt->kind == VCODE_TYPE_FILE
68,548✔
2759
          || vt->kind == VCODE_TYPE_RESOLUTION
2760
          || vt->kind == VCODE_TYPE_CLOSURE);
2761
   return vt->base;
68,548✔
2762
}
2763

2764
vcode_type_t vtype_bounds(vcode_type_t type)
29,165✔
2765
{
2766
   vtype_t *vt = vcode_type_data(type);
29,165✔
2767
   assert(vt->kind == VCODE_TYPE_CARRAY || vt->kind == VCODE_TYPE_UARRAY);
29,165✔
2768
   return vt->bounds;
29,165✔
2769
}
2770

2771
unsigned vtype_dims(vcode_type_t type)
57,211✔
2772
{
2773
   vtype_t *vt = vcode_type_data(type);
57,211✔
2774
   assert(vt->kind == VCODE_TYPE_UARRAY);
57,211✔
2775
   return vt->dims;
57,211✔
2776
}
2777

2778
unsigned vtype_size(vcode_type_t type)
64,838✔
2779
{
2780
   vtype_t *vt = vcode_type_data(type);
64,838✔
2781
   assert(vt->kind == VCODE_TYPE_CARRAY);
64,838✔
2782
   return vt->size;
64,838✔
2783
}
2784

2785
int vtype_fields(vcode_type_t type)
10,295✔
2786
{
2787
   vtype_t *vt = vcode_type_data(type);
10,295✔
2788
   assert(vt->kind == VCODE_TYPE_RECORD);
10,295✔
2789
   return vt->fields.count;
10,295✔
2790
}
2791

2792
vcode_type_t vtype_field(vcode_type_t type, int field)
40,484✔
2793
{
2794
   vtype_t *vt = vcode_type_data(type);
40,484✔
2795
   assert(vt->kind == VCODE_TYPE_RECORD);
40,484✔
2796
   return vcode_type_array_nth(&(vt->fields), field);
40,484✔
2797
}
2798

2799
ident_t vtype_name(vcode_type_t type)
33,760✔
2800
{
2801
   vtype_t *vt = vcode_type_data(type);
33,760✔
2802
   assert(vt->kind == VCODE_TYPE_RECORD || vt->kind == VCODE_TYPE_CONTEXT);
33,760✔
2803
   return vt->name;
33,760✔
2804
}
2805

2806
vcode_type_t vtype_pointed(vcode_type_t type)
463,104✔
2807
{
2808
   vtype_t *vt = vcode_type_data(type);
463,104✔
2809
   assert(vt->kind == VCODE_TYPE_POINTER || vt->kind == VCODE_TYPE_ACCESS);
463,104✔
2810
   return vt->pointed;
463,104✔
2811
}
2812

2813
int64_t vtype_low(vcode_type_t type)
320,085✔
2814
{
2815
   vtype_t *vt = vcode_type_data(type);
320,085✔
2816
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
320,085✔
2817
   return vt->low;
320,085✔
2818
}
2819

2820
int64_t vtype_high(vcode_type_t type)
316,358✔
2821
{
2822
   vtype_t *vt = vcode_type_data(type);
316,358✔
2823
   assert(vt->kind == VCODE_TYPE_INT || vt->kind == VCODE_TYPE_OFFSET);
316,358✔
2824
   return vt->high;
316,358✔
2825
}
2826

2827
static bool vtype_is_pointer(vcode_type_t type, vtype_kind_t to)
2,009✔
2828
{
2829
   return vtype_kind(type) == VCODE_TYPE_POINTER
2,009✔
2830
      && vtype_kind(vtype_pointed(type)) == to;
2,009✔
2831
}
2832

2833
bool vtype_is_scalar(vcode_type_t type)
565,908✔
2834
{
2835
   const vtype_kind_t kind = vtype_kind(type);
565,908✔
2836
   return kind == VCODE_TYPE_INT || kind == VCODE_TYPE_OFFSET
565,908✔
2837
      || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_POINTER
233,029✔
2838
      || kind == VCODE_TYPE_FILE || kind == VCODE_TYPE_ACCESS
2839
      || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_SIGNAL
2840
      || kind == VCODE_TYPE_CONTEXT || kind == VCODE_TYPE_TRIGGER
2841
      || kind == VCODE_TYPE_RESOLUTION;
565,908✔
2842
}
2843

2844
bool vtype_is_composite(vcode_type_t type)
39,264✔
2845
{
2846
   const vtype_kind_t kind = vtype_kind(type);
39,264✔
2847
   return kind == VCODE_TYPE_RECORD || kind == VCODE_TYPE_CARRAY;
39,264✔
2848
}
2849

2850
bool vtype_is_signal(vcode_type_t type)
219,229✔
2851
{
2852
   vtype_t *vt = vcode_type_data(type);
386,857✔
2853
   switch (vt->kind) {
386,857✔
2854
   case VCODE_TYPE_SIGNAL:
2855
      return true;
2856
   case VCODE_TYPE_POINTER:
99,046✔
2857
      return vtype_is_signal(vt->pointed);
99,046✔
2858
   case VCODE_TYPE_RECORD:
2859
      for (int i = 0; i < vt->fields.count; i++) {
45,700✔
2860
         if (vtype_is_signal(vt->fields.items[i]))
36,165✔
2861
            return true;
2862
      }
2863
      return false;
2864
   case VCODE_TYPE_UARRAY:
68,582✔
2865
   case VCODE_TYPE_CARRAY:
2866
      return vtype_is_signal(vt->elem);
68,582✔
2867
   default:
171,412✔
2868
      return false;
171,412✔
2869
   }
2870
}
2871

UNCOV
2872
int vtype_repr_bits(vtype_repr_t repr)
×
2873
{
UNCOV
2874
   switch (repr) {
×
2875
   case VCODE_REPR_U1: return 1;
2876
   case VCODE_REPR_U8: case VCODE_REPR_I8: return 8;
2877
   case VCODE_REPR_U16: case VCODE_REPR_I16: return 16;
2878
   case VCODE_REPR_U32: case VCODE_REPR_I32: return 32;
2879
   case VCODE_REPR_U64: case VCODE_REPR_I64: return 64;
2880
   default: return -1;
2881
   }
2882
}
2883

UNCOV
2884
bool vtype_repr_signed(vtype_repr_t repr)
×
2885
{
UNCOV
2886
   return repr == VCODE_REPR_I8 || repr == VCODE_REPR_I16
×
2887
      || repr == VCODE_REPR_I32 || repr == VCODE_REPR_I64;
×
2888
}
2889

2890
static int64_t vtype_repr_low(vtype_repr_t repr)
15,742✔
2891
{
2892
   switch (repr) {
15,742✔
2893
   case VCODE_REPR_U1:
2894
   case VCODE_REPR_U8:
2895
   case VCODE_REPR_U16:
2896
   case VCODE_REPR_U32:
2897
   case VCODE_REPR_U64: return 0;
2898
   case VCODE_REPR_I8:  return INT8_MIN;
2899
   case VCODE_REPR_I16: return INT16_MIN;
2900
   case VCODE_REPR_I32: return INT32_MIN;
2901
   case VCODE_REPR_I64: return INT64_MIN;
2902
   default:             return 0;
2903
   }
2904
}
2905

2906
static uint64_t vtype_repr_high(vtype_repr_t repr)
15,742✔
2907
{
2908
   switch (repr) {
15,742✔
2909
   case VCODE_REPR_U1:  return 1;
2910
   case VCODE_REPR_U8:  return UINT8_MAX;
2911
   case VCODE_REPR_U16: return UINT16_MAX;
2912
   case VCODE_REPR_U32: return UINT32_MAX;
2913
   case VCODE_REPR_U64: return UINT64_MAX;
2914
   case VCODE_REPR_I8:  return INT8_MAX;
2915
   case VCODE_REPR_I16: return INT16_MAX;
2916
   case VCODE_REPR_I32: return INT32_MAX;
2917
   case VCODE_REPR_I64: return INT64_MAX;
2918
   default:             return 0;
2919
   }
2920
}
2921

2922
static bool vtype_clamp_to_repr(vtype_repr_t repr, int64_t *low, int64_t *high)
15,742✔
2923
{
2924
   int64_t clamp_low = vtype_repr_low(repr);
15,742✔
2925
   uint64_t clamp_high = vtype_repr_high(repr);
15,742✔
2926

2927
   if (*low >= clamp_low && *high <= clamp_high)
15,742✔
2928
      return true;
2929
   else {
2930
      *low = MAX(clamp_low, *low);
7,790✔
2931
      *high = MIN(clamp_high, *high);
7,790✔
2932
      return false;
7,790✔
2933
   }
2934
}
2935

2936
int vcode_count_params(void)
18,722✔
2937
{
2938
   assert(active_unit != NULL);
18,722✔
2939
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
18,722✔
2940
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2941
          || active_unit->kind == VCODE_UNIT_PROPERTY
2942
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2943

2944
   return active_unit->params.count;
18,722✔
2945
}
2946

2947
vcode_type_t vcode_param_type(int param)
46,200✔
2948
{
2949
   assert(active_unit != NULL);
46,200✔
2950
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
46,200✔
2951
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2952
          || active_unit->kind == VCODE_UNIT_PROPERTY
2953
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2954
   assert(param < active_unit->params.count);
46,200✔
2955

2956
   return active_unit->params.items[param].type;
46,200✔
2957
}
2958

2959
ident_t vcode_param_name(int param)
46,200✔
2960
{
2961
   assert(active_unit != NULL);
46,200✔
2962
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
46,200✔
2963
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2964
          || active_unit->kind == VCODE_UNIT_PROPERTY
2965
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2966
   assert(param < active_unit->params.count);
46,200✔
2967

2968
   return active_unit->params.items[param].name;
46,200✔
2969
}
2970

2971
vcode_reg_t vcode_param_reg(int param)
46,200✔
2972
{
2973
   assert(active_unit != NULL);
46,200✔
2974
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
46,200✔
2975
          || active_unit->kind == VCODE_UNIT_PROCEDURE
2976
          || active_unit->kind == VCODE_UNIT_PROPERTY
2977
          || active_unit->kind == VCODE_UNIT_PROTECTED);
2978
   assert(param < active_unit->params.count);
46,200✔
2979

2980
   return active_unit->params.items[param].reg;
46,200✔
2981
}
2982

2983
vcode_block_t emit_block(void)
188,600✔
2984
{
2985
   assert(active_unit != NULL);
188,600✔
2986

2987
   vcode_block_t bnum = active_unit->blocks.count;
188,600✔
2988

2989
   block_t *bptr = block_array_alloc(&(active_unit->blocks));
188,600✔
2990
   memset(bptr, '\0', sizeof(block_t));
188,600✔
2991

2992
   if (active_block != VCODE_INVALID_BLOCK)
188,600✔
2993
      bptr->last_loc = active_unit->blocks.items[active_block].last_loc;
118,593✔
2994
   else
2995
      bptr->last_loc = LOC_INVALID;
70,007✔
2996

2997
   return bnum;
188,600✔
2998
}
2999

3000
void vcode_select_unit(vcode_unit_t unit)
244,732✔
3001
{
3002
   active_unit  = unit;
244,732✔
3003
   active_block = VCODE_INVALID_BLOCK;
244,732✔
3004
}
244,732✔
3005

3006
void vcode_select_block(vcode_block_t block)
440,335✔
3007
{
3008
   assert(active_unit != NULL);
440,335✔
3009
   active_block = block;
440,335✔
3010
}
440,335✔
3011

3012
vcode_block_t vcode_active_block(void)
903✔
3013
{
3014
   assert(active_unit != NULL);
903✔
3015
   assert(active_block != -1);
903✔
3016
   return active_block;
903✔
3017
}
3018

3019
const loc_t *vcode_last_loc(void)
1,520,477✔
3020
{
3021
   return &(vcode_block_data()->last_loc);
1,520,477✔
3022
}
3023

3024
vcode_unit_t vcode_active_unit(void)
1,097✔
3025
{
3026
   assert(active_unit != NULL);
1,097✔
3027
   return active_unit;
1,097✔
3028
}
3029

3030
ident_t vcode_unit_name(vcode_unit_t vu)
204,354✔
3031
{
3032
   assert(vu != NULL);
204,354✔
3033
   return vu->name;
204,354✔
3034
}
3035

3036
bool vcode_unit_has_undefined(vcode_unit_t vu)
15,489✔
3037
{
3038
   assert(vu != NULL);
15,489✔
3039
   return !!(vu->flags & UNIT_UNDEFINED);
15,489✔
3040
}
3041

UNCOV
3042
int vcode_unit_depth(vcode_unit_t vu)
×
3043
{
UNCOV
3044
   assert(vu != NULL);
×
3045
   return vu->depth;
×
3046
}
3047

3048
void vcode_set_result(vcode_type_t type)
30,357✔
3049
{
3050
   assert(active_unit != NULL);
30,357✔
3051
   assert(active_unit->kind == VCODE_UNIT_FUNCTION
30,357✔
3052
          || active_unit->kind == VCODE_UNIT_THUNK);
3053

3054
   active_unit->result = type;
30,357✔
3055
}
30,357✔
3056

3057
vcode_type_t vcode_unit_result(vcode_unit_t vu)
32,548✔
3058
{
3059
   assert(vu != NULL);
32,548✔
3060
   assert(vu->kind == VCODE_UNIT_FUNCTION || vu->kind == VCODE_UNIT_THUNK);
32,548✔
3061
   return vu->result;
32,548✔
3062
}
3063

3064
vunit_kind_t vcode_unit_kind(vcode_unit_t vu)
194,119✔
3065
{
3066
   assert(vu != NULL);
194,119✔
3067
   return vu->kind;
194,119✔
3068
}
3069

3070
vcode_unit_t vcode_unit_context(vcode_unit_t vu)
133,659✔
3071
{
3072
   assert(vu != NULL);
133,659✔
3073
   return vu->context;
133,659✔
3074
}
3075

3076
object_t *vcode_unit_object(vcode_unit_t vu)
120,838✔
3077
{
3078
   assert(vu != NULL);
120,838✔
3079
   return vu->object;
120,838✔
3080
}
3081

3082
static unsigned vcode_unit_calc_depth(vcode_unit_t unit)
85,512✔
3083
{
3084
   int hops = 0;
85,512✔
3085
   for (; (unit = unit->context); hops++)
233,503✔
3086
      ;
3087
   return hops;
85,512✔
3088
}
3089

3090
static void vcode_add_child(vcode_unit_t context, vcode_unit_t child)
40,372✔
3091
{
3092
   assert(context->kind != VCODE_UNIT_THUNK);
40,372✔
3093

3094
   child->next = NULL;
40,372✔
3095
   if (context->children == NULL)
40,372✔
3096
      context->children = child;
18,238✔
3097
   else {
3098
      vcode_unit_t it;
3099
      for (it = context->children; it->next != NULL; it = it->next)
109,950✔
3100
         ;
3101
      it->next = child;
22,134✔
3102
   }
3103
}
40,372✔
3104

3105
vcode_unit_t emit_function(ident_t name, object_t *obj, vcode_unit_t context)
17,447✔
3106
{
3107
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
17,447✔
3108
   vu->kind     = VCODE_UNIT_FUNCTION;
17,447✔
3109
   vu->name     = name;
17,447✔
3110
   vu->context  = context;
17,447✔
3111
   vu->result   = VCODE_INVALID_TYPE;
17,447✔
3112
   vu->depth    = vcode_unit_calc_depth(vu);
17,447✔
3113
   vu->object   = obj;
17,447✔
3114

3115
   vcode_add_child(context, vu);
17,447✔
3116

3117
   vcode_select_unit(vu);
17,447✔
3118
   vcode_select_block(emit_block());
17,447✔
3119
   emit_debug_info(&(obj->loc));
17,447✔
3120

3121
   return vu;
17,447✔
3122
}
3123

3124
vcode_unit_t emit_procedure(ident_t name, object_t *obj, vcode_unit_t context)
274✔
3125
{
3126
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
274✔
3127
   vu->kind     = VCODE_UNIT_PROCEDURE;
274✔
3128
   vu->name     = name;
274✔
3129
   vu->context  = context;
274✔
3130
   vu->result   = VCODE_INVALID_TYPE;
274✔
3131
   vu->depth    = vcode_unit_calc_depth(vu);
274✔
3132
   vu->object   = obj;
274✔
3133

3134
   vcode_add_child(context, vu);
274✔
3135

3136
   vcode_select_unit(vu);
274✔
3137
   vcode_select_block(emit_block());
274✔
3138
   emit_debug_info(&(obj->loc));
274✔
3139

3140
   return vu;
274✔
3141
}
3142

3143
vcode_unit_t emit_process(ident_t name, object_t *obj, vcode_unit_t context)
12,162✔
3144
{
3145
   assert(context->kind == VCODE_UNIT_INSTANCE);
12,162✔
3146

3147
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,162✔
3148
   vu->kind     = VCODE_UNIT_PROCESS;
12,162✔
3149
   vu->name     = name;
12,162✔
3150
   vu->context  = context;
12,162✔
3151
   vu->depth    = vcode_unit_calc_depth(vu);
12,162✔
3152
   vu->result   = VCODE_INVALID_TYPE;
12,162✔
3153
   vu->object   = obj;
12,162✔
3154

3155
   vcode_add_child(context, vu);
12,162✔
3156

3157
   vcode_select_unit(vu);
12,162✔
3158
   vcode_select_block(emit_block());
12,162✔
3159
   emit_debug_info(&(obj->loc));
12,162✔
3160

3161
   return vu;
12,162✔
3162
}
3163

3164
vcode_unit_t emit_instance(ident_t name, object_t *obj, vcode_unit_t context)
12,804✔
3165
{
3166
   assert(context == NULL || context->kind == VCODE_UNIT_INSTANCE);
12,804✔
3167

3168
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
12,804✔
3169
   vu->kind     = VCODE_UNIT_INSTANCE;
12,804✔
3170
   vu->name     = name;
12,804✔
3171
   vu->context  = context;
12,804✔
3172
   vu->depth    = vcode_unit_calc_depth(vu);
12,804✔
3173
   vu->result   = VCODE_INVALID_TYPE;
12,804✔
3174
   vu->object   = obj;
12,804✔
3175

3176
   if (context != NULL)
12,804✔
3177
      vcode_add_child(context, vu);
8,035✔
3178

3179
   vcode_select_unit(vu);
12,804✔
3180
   vcode_select_block(emit_block());
12,804✔
3181
   emit_debug_info(&(obj->loc));
12,804✔
3182

3183
   return vu;
12,804✔
3184
}
3185

3186
vcode_unit_t emit_package(ident_t name, object_t *obj, vcode_unit_t context)
10,814✔
3187
{
3188
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
10,814✔
3189
   vu->kind     = VCODE_UNIT_PACKAGE;
10,814✔
3190
   vu->name     = name;
10,814✔
3191
   vu->context  = context;
10,814✔
3192
   vu->depth    = vcode_unit_calc_depth(vu);
10,814✔
3193
   vu->result   = VCODE_INVALID_TYPE;
10,814✔
3194
   vu->object   = obj;
10,814✔
3195

3196
   if (context != NULL)
10,814✔
3197
      vcode_add_child(context, vu);
242✔
3198

3199
   vcode_select_unit(vu);
10,814✔
3200
   vcode_select_block(emit_block());
10,814✔
3201
   emit_debug_info(&(obj->loc));
10,814✔
3202

3203
   return vu;
10,814✔
3204
}
3205

3206
vcode_unit_t emit_protected(ident_t name, object_t *obj, vcode_unit_t context)
705✔
3207
{
3208
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
705✔
3209
   vu->kind     = VCODE_UNIT_PROTECTED;
705✔
3210
   vu->name     = name;
705✔
3211
   vu->context  = context;
705✔
3212
   vu->depth    = vcode_unit_calc_depth(vu);
705✔
3213
   vu->result   = VCODE_INVALID_TYPE;
705✔
3214
   vu->object   = obj;
705✔
3215

3216
   if (context != NULL)
705✔
3217
      vcode_add_child(context, vu);
705✔
3218

3219
   vcode_select_unit(vu);
705✔
3220
   vcode_select_block(emit_block());
705✔
3221
   emit_debug_info(&(obj->loc));
705✔
3222

3223
   return vu;
705✔
3224
}
3225

3226
vcode_unit_t emit_property(ident_t name, object_t *obj, vcode_unit_t context)
296✔
3227
{
3228
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
296✔
3229
   vu->kind     = VCODE_UNIT_PROPERTY;
296✔
3230
   vu->name     = name;
296✔
3231
   vu->context  = context;
296✔
3232
   vu->depth    = vcode_unit_calc_depth(vu);
296✔
3233
   vu->result   = VCODE_INVALID_TYPE;
296✔
3234
   vu->object   = obj;
296✔
3235

3236
   if (context != NULL)
296✔
3237
      vcode_add_child(context, vu);
296✔
3238

3239
   vcode_select_unit(vu);
296✔
3240
   vcode_select_block(emit_block());
296✔
3241
   emit_debug_info(&(obj->loc));
296✔
3242

3243
   return vu;
296✔
3244
}
3245

3246
vcode_unit_t emit_thunk(ident_t name, object_t *obj, vcode_unit_t context)
15,505✔
3247
{
3248
   vcode_unit_t vu = xcalloc(sizeof(struct _vcode_unit));
15,505✔
3249
   vu->kind     = VCODE_UNIT_THUNK;
15,505✔
3250
   vu->name     = name;
15,505✔
3251
   vu->context  = context;
15,505✔
3252
   vu->depth    = vcode_unit_calc_depth(vu);
15,505✔
3253
   vu->result   = VCODE_INVALID_TYPE;
15,505✔
3254
   vu->depth    = vcode_unit_calc_depth(vu);
15,505✔
3255
   vu->object   = obj;
15,505✔
3256

3257
   if (context != NULL)
15,505✔
3258
      vcode_add_child(context, vu);
1,211✔
3259

3260
   vcode_select_unit(vu);
15,505✔
3261
   vcode_select_block(emit_block());
15,505✔
3262

3263
   return vu;
15,505✔
3264
}
3265

3266
void emit_assert(vcode_reg_t value, vcode_reg_t message, vcode_reg_t length,
18,832✔
3267
                 vcode_reg_t severity, vcode_reg_t locus, vcode_reg_t hint_left,
3268
                 vcode_reg_t hint_right)
3269
{
3270
   int64_t value_const;
18,832✔
3271
   if (vcode_reg_const(value, &value_const) && value_const != 0) {
18,832✔
3272
      emit_comment("Always true assertion on r%d", value);
40✔
3273
      return;
40✔
3274
   }
3275

3276
   op_t *op = vcode_add_op(VCODE_OP_ASSERT);
18,792✔
3277
   vcode_add_arg(op, value);
18,792✔
3278
   vcode_add_arg(op, severity);
18,792✔
3279
   vcode_add_arg(op, message);
18,792✔
3280
   vcode_add_arg(op, length);
18,792✔
3281
   vcode_add_arg(op, locus);
18,792✔
3282

3283
   if (hint_left != VCODE_INVALID_REG) {
18,792✔
3284
      vcode_add_arg(op, hint_left);
7,974✔
3285
      vcode_add_arg(op, hint_right);
7,974✔
3286

3287
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_left)),
7,974✔
3288
                   "left hint must be scalar");
3289
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(hint_right)),
7,974✔
3290
                   "right hint must be scalar");
3291
   }
3292

3293
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
18,792✔
3294
                "value parameter to assert is not bool");
3295
   VCODE_ASSERT(message == VCODE_INVALID_REG
18,792✔
3296
                || vcode_reg_kind(message) == VCODE_TYPE_POINTER,
3297
                "message parameter to assert is not a pointer");
3298
   VCODE_ASSERT(vtype_eq(vcode_reg_type(value), vtype_bool()),
18,792✔
3299
                "value parameter to assert is not bool");
3300
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
18,792✔
3301
                "locus argument to report must be a debug locus");
3302
}
3303

3304
void emit_report(vcode_reg_t message, vcode_reg_t length, vcode_reg_t severity,
2,675✔
3305
                 vcode_reg_t locus)
3306
{
3307
   op_t *op = vcode_add_op(VCODE_OP_REPORT);
2,675✔
3308
   vcode_add_arg(op, severity);
2,675✔
3309
   vcode_add_arg(op, message);
2,675✔
3310
   vcode_add_arg(op, length);
2,675✔
3311
   vcode_add_arg(op, locus);
2,675✔
3312

3313
   VCODE_ASSERT(vcode_reg_kind(message) == VCODE_TYPE_POINTER,
2,675✔
3314
                "message parameter to report is not a pointer");
3315
   VCODE_ASSERT(vtype_eq(vtype_pointed(vcode_reg_type(message)), vtype_char()),
2,675✔
3316
                "message parameter to report is not a character pointer");
3317
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,675✔
3318
                "locus argument to report must be a debug locus");
3319
}
2,675✔
3320

3321
vcode_reg_t emit_cmp(vcode_cmp_t cmp, vcode_reg_t lhs, vcode_reg_t rhs)
45,577✔
3322
{
3323
   if (lhs == rhs) {
45,577✔
3324
      if (cmp == VCODE_CMP_EQ)
200✔
3325
         return emit_const(vtype_bool(), 1);
184✔
3326
      else if (cmp == VCODE_CMP_NEQ)
16✔
UNCOV
3327
         return emit_const(vtype_bool(), 0);
×
3328
      else if (cmp == VCODE_CMP_LEQ || cmp == VCODE_CMP_GEQ)
16✔
UNCOV
3329
         return emit_const(vtype_bool(), 1);
×
3330
      else if (cmp == VCODE_CMP_LT || cmp == VCODE_CMP_GT)
16✔
3331
         return emit_const(vtype_bool(), 0);
16✔
3332
   }
3333

3334
   int64_t lconst, rconst;
45,377✔
3335
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)) {
45,377✔
3336
      switch (cmp) {
410✔
3337
      case VCODE_CMP_EQ:
397✔
3338
         return emit_const(vtype_bool(), lconst == rconst);
397✔
3339
      case VCODE_CMP_NEQ:
4✔
3340
         return emit_const(vtype_bool(), lconst != rconst);
4✔
3341
      case VCODE_CMP_LT:
4✔
3342
         return emit_const(vtype_bool(), lconst < rconst);
4✔
3343
      case VCODE_CMP_GT:
5✔
3344
         return emit_const(vtype_bool(), lconst > rconst);
5✔
UNCOV
3345
      case VCODE_CMP_LEQ:
×
3346
         return emit_const(vtype_bool(), lconst <= rconst);
×
3347
      case VCODE_CMP_GEQ:
×
3348
         return emit_const(vtype_bool(), lconst >= rconst);
×
3349
      default:
×
3350
         fatal_trace("cannot fold comparison %d", cmp);
3351
      }
3352
   }
3353

3354
   // Reuse any previous operation in this block with the same arguments
3355
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CMP) {
888,364✔
3356
      if (other->args.count == 2 && other->args.items[0] == lhs
31,500✔
3357
          && other->args.items[1] == rhs && other->cmp == cmp)
2,702✔
3358
         return other->result;
257✔
3359
   }
3360

3361
   op_t *op = vcode_add_op(VCODE_OP_CMP);
44,710✔
3362
   vcode_add_arg(op, lhs);
44,710✔
3363
   vcode_add_arg(op, rhs);
44,710✔
3364
   op->cmp    = cmp;
44,710✔
3365
   op->result = vcode_add_reg(vtype_bool());
44,710✔
3366

3367
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vcode_reg_type(rhs)),
44,710✔
3368
                "arguments to cmp are not the same type");
3369

3370
   return op->result;
3371
}
3372

3373
vcode_reg_t emit_fcall(ident_t func, vcode_type_t type, vcode_type_t bounds,
46,423✔
3374
                       const vcode_reg_t *args, int nargs)
3375
{
3376
   op_t *o = vcode_add_op(VCODE_OP_FCALL);
46,423✔
3377
   o->func = func;
46,423✔
3378
   o->type = type;
46,423✔
3379
   for (int i = 0; i < nargs; i++)
175,932✔
3380
      vcode_add_arg(o, args[i]);
129,509✔
3381

3382
   for (int i = 0; i < nargs; i++)
175,932✔
3383
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
129,509✔
3384
                   "invalid argument to function");
3385

3386
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
46,423✔
3387
                "first argument to VHDL function must be context pointer");
3388

3389
   if (type == VCODE_INVALID_TYPE)
46,423✔
3390
      return (o->result = VCODE_INVALID_REG);
6,794✔
3391
   else {
3392
      o->result = vcode_add_reg(type);
39,629✔
3393

3394
      reg_t *rr = vcode_reg_data(o->result);
39,629✔
3395
      rr->bounds = bounds;
39,629✔
3396

3397
      return o->result;
39,629✔
3398
   }
3399
}
3400

3401
void emit_pcall(ident_t func, const vcode_reg_t *args, int nargs,
1,089✔
3402
                vcode_block_t resume_bb)
3403
{
3404
   op_t *o = vcode_add_op(VCODE_OP_PCALL);
1,089✔
3405
   o->func = func;
1,089✔
3406
   for (int i = 0; i < nargs; i++)
3,694✔
3407
      vcode_add_arg(o, args[i]);
2,605✔
3408

3409
   vcode_block_array_add(&(o->targets), resume_bb);
1,089✔
3410

3411
   for (int i = 0; i < nargs; i++)
3,694✔
3412
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG,
2,605✔
3413
                   "invalid argument to procedure");
3414

3415
   VCODE_ASSERT(nargs > 0 && vcode_reg_kind(args[0]) == VCODE_TYPE_CONTEXT,
1,089✔
3416
                "first argument to VHDL procedure must be context pointer");
3417
}
1,089✔
3418

UNCOV
3419
vcode_reg_t emit_syscall(ident_t func, vcode_type_t type, vcode_type_t bounds,
×
3420
                         vcode_reg_t locus, const vcode_reg_t *args, int nargs)
3421
{
UNCOV
3422
   op_t *o = vcode_add_op(VCODE_OP_SYSCALL);
×
3423
   o->func = func;
×
3424
   o->type = type;
×
3425
   vcode_add_arg(o, locus);
×
3426
   for (int i = 0; i < nargs; i++)
×
3427
      vcode_add_arg(o, args[i]);
×
3428

UNCOV
3429
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
×
3430
                "locus argument to syscall must be a debug locus");
3431

UNCOV
3432
   for (int i = 0; i < nargs; i++)
×
3433
      VCODE_ASSERT(args[i] != VCODE_INVALID_REG, "invalid argument to syscall");
×
3434

UNCOV
3435
   if (type == VCODE_INVALID_TYPE)
×
3436
      return (o->result = VCODE_INVALID_REG);
×
3437
   else {
UNCOV
3438
      o->result = vcode_add_reg(type);
×
3439

UNCOV
3440
      reg_t *rr = vcode_reg_data(o->result);
×
3441
      rr->bounds = bounds;
×
3442

UNCOV
3443
      return o->result;
×
3444
   }
3445
}
3446

3447
vcode_reg_t emit_alloc(vcode_type_t type, vcode_type_t bounds,
9,292✔
3448
                       vcode_reg_t count)
3449
{
3450
   op_t *op = vcode_add_op(VCODE_OP_ALLOC);
9,292✔
3451
   op->type    = type;
9,292✔
3452
   op->result  = vcode_add_reg(vtype_pointer(type));
9,292✔
3453
   vcode_add_arg(op, count);
9,292✔
3454

3455
   const vtype_kind_t tkind = vtype_kind(type);
9,292✔
3456
   VCODE_ASSERT(tkind != VCODE_TYPE_CARRAY && tkind != VCODE_TYPE_UARRAY,
9,292✔
3457
                "alloca element type cannot be array");
3458
   VCODE_ASSERT(count != VCODE_INVALID_REG,
9,292✔
3459
                "alloca must have valid count argument");
3460

3461
   reg_t *r = vcode_reg_data(op->result);
9,292✔
3462
   r->bounds = bounds;
9,292✔
3463

3464
   return op->result;
9,292✔
3465
}
3466

3467
vcode_reg_t emit_const(vcode_type_t type, int64_t value)
1,879,292✔
3468
{
3469
   // Reuse any previous constant in this block with the same type and value
3470
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST) {
42,077,805✔
3471
      if (other->value == value && vtype_eq(type, other->type))
15,031,808✔
3472
         return other->result;
1,279,161✔
3473
   }
3474

3475
   op_t *op = vcode_add_op(VCODE_OP_CONST);
600,131✔
3476
   op->value  = value;
600,131✔
3477
   op->type   = type;
600,131✔
3478
   op->result = vcode_add_reg(type);
600,131✔
3479

3480
   vtype_kind_t type_kind = vtype_kind(type);
600,131✔
3481
   VCODE_ASSERT(type_kind == VCODE_TYPE_INT || type_kind == VCODE_TYPE_OFFSET,
600,131✔
3482
                "constant must have integer or offset type");
3483

3484
   reg_t *r = vcode_reg_data(op->result);
600,131✔
3485
   r->bounds = vtype_int(value, value);
600,131✔
3486

3487
   return op->result;
600,131✔
3488
}
3489

3490
vcode_reg_t emit_const_real(vcode_type_t type, double value)
91,196✔
3491
{
3492
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REAL) {
2,644,292✔
3493
      if (other->real == value && other->type == type)
1,255,108✔
3494
         return other->result;
36,442✔
3495
   }
3496

3497
   op_t *op = vcode_add_op(VCODE_OP_CONST_REAL);
54,754✔
3498
   op->real   = value;
54,754✔
3499
   op->type   = type;
54,754✔
3500
   op->result = vcode_add_reg(op->type);
54,754✔
3501

3502
   reg_t *r = vcode_reg_data(op->result);
54,754✔
3503
   r->bounds = vtype_real(value, value);
54,754✔
3504

3505
   return op->result;
54,754✔
3506
}
3507

3508
vcode_reg_t emit_const_array(vcode_type_t type, vcode_reg_t *values, int num)
45,848✔
3509
{
3510
   vtype_kind_t kind = vtype_kind(type);
45,848✔
3511

3512
   // Reuse any previous operation in this block with the same arguments
3513
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_ARRAY) {
2,419,547✔
3514
      if (other->args.count != num)
189,787✔
3515
         continue;
112,408✔
3516
      else if (!vtype_eq(vcode_reg_type(other->result), type))
77,379✔
3517
         continue;
2,894✔
3518

3519
      bool match = true;
3520
      for (int i = 0; match && i < num; i++) {
562,118✔
3521
         if (other->args.items[i] != values[i])
487,633✔
3522
            match = false;
65,871✔
3523
      }
3524

3525
      if (match) return other->result;
74,485✔
3526
   }
3527

3528
   op_t *op = vcode_add_op(VCODE_OP_CONST_ARRAY);
37,234✔
3529
   op->result = vcode_add_reg(type);
37,234✔
3530

3531
   for (int i = 0; i < num; i++)
2,143,225✔
3532
      vcode_add_arg(op, values[i]);
2,105,991✔
3533

3534
   VCODE_ASSERT(kind == VCODE_TYPE_CARRAY,
37,234✔
3535
                "constant array must have constrained array type");
3536
   VCODE_ASSERT(vtype_size(type) == num, "expected %d elements but have %d",
37,234✔
3537
                vtype_size(type), num);
3538

3539
#ifdef DEBUG
3540
   vcode_type_t elem = vtype_elem(type);
37,234✔
3541
   for (int i = 0; i < num; i++) {
2,143,225✔
3542
      VCODE_ASSERT(vtype_eq(vcode_reg_type(values[i]), elem),
2,105,991✔
3543
                   "wrong element type for item %d", i);
3544
      vcode_assert_const(values[i], "array");
2,105,991✔
3545
   }
3546
#endif
3547

3548
   reg_t *r = vcode_reg_data(op->result);
37,234✔
3549
   r->bounds = vtype_elem(type);
37,234✔
3550

3551
   return op->result;
37,234✔
3552
}
3553

3554
vcode_reg_t emit_const_rep(vcode_type_t type, vcode_reg_t value, int rep)
759✔
3555
{
3556
   // Reuse any previous operation in this block with the same arguments
3557
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_REP) {
11,615✔
3558
      if (other->args.items[0] == value && other->value == rep)
1,065✔
3559
         return other->result;
320✔
3560
   }
3561

3562
   op_t *op = vcode_add_op(VCODE_OP_CONST_REP);
439✔
3563
   op->value = rep;
439✔
3564
   vcode_add_arg(op, value);
439✔
3565

3566
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CARRAY,
439✔
3567
                "constant array must have constrained array type");
3568
   VCODE_ASSERT(rep >= 0, "repeat count must be non-negative");
439✔
3569

3570
   DEBUG_ONLY(vcode_assert_const(value, "repeat"));
439✔
3571

3572
   op->result = vcode_add_reg(type);
439✔
3573

3574
   reg_t *r = vcode_reg_data(op->result);
439✔
3575
   r->bounds = vtype_bounds(type);
439✔
3576

3577
   return op->result;
439✔
3578
}
3579

3580
vcode_reg_t emit_const_record(vcode_type_t type, vcode_reg_t *values, int num)
3,298✔
3581
{
3582
   // Reuse any previous constant in this block with the same type and value
3583
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONST_RECORD) {
52,131✔
3584
      if (other->args.count == num && vtype_eq(type, other->type)) {
2,093✔
3585
         bool same_regs = true;
3586
         for (int i = 0; same_regs && i < num; i++)
3,333✔
3587
            same_regs = other->args.items[i] == values[i];
1,946✔
3588

3589
         if (same_regs)
1,387✔
3590
            return other->result;
252✔
3591
      }
3592
   }
3593

3594
   op_t *op = vcode_add_op(VCODE_OP_CONST_RECORD);
3,046✔
3595
   op->type   = type;
3,046✔
3596
   op->result = vcode_add_reg(type);
3,046✔
3597

3598
   for (int i = 0; i < num; i++)
10,949✔
3599
      vcode_add_arg(op, values[i]);
7,903✔
3600

3601
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_RECORD,
3,046✔
3602
                "constant record must have record type");
3603

3604
   VCODE_ASSERT(vtype_fields(type) == num, "expected %d fields but have %d",
3,046✔
3605
                vtype_fields(type), num);
3606

3607
#ifdef DEBUG
3608
   for (int i = 0; i < num; i++) {
10,949✔
3609
      VCODE_ASSERT(vtype_eq(vtype_field(type, i), vcode_reg_type(values[i])),
7,903✔
3610
                   "wrong type for field %d", i);
3611
      vcode_assert_const(values[i], "record");
7,903✔
3612
   }
3613
#endif
3614

3615
   return op->result;
3,046✔
3616
}
3617

3618
vcode_reg_t emit_address_of(vcode_reg_t value)
47,892✔
3619
{
3620
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ADDRESS_OF) {
2,508,755✔
3621
      if (other->args.items[0] == value)
191,161✔
3622
         return other->result;
8,628✔
3623
   }
3624

3625
   op_t *op = vcode_add_op(VCODE_OP_ADDRESS_OF);
39,264✔
3626
   vcode_add_arg(op, value);
39,264✔
3627

3628
   vcode_type_t type = vcode_reg_type(value);
39,264✔
3629
   VCODE_ASSERT(vtype_is_composite(type),
39,264✔
3630
                "address of argument must be record or array");
3631

3632
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
39,264✔
3633
      vcode_type_t elem = vtype_elem(type);
36,941✔
3634
      op->result = vcode_add_reg(vtype_pointer(elem));
36,941✔
3635

3636
      reg_t *rr = vcode_reg_data(op->result);
36,941✔
3637
      rr->bounds = elem;
36,941✔
3638

3639
      return op->result;
36,941✔
3640
   }
3641
   else
3642
      return (op->result = vcode_add_reg(vtype_pointer(type)));
2,323✔
3643
}
3644

3645
void emit_wait(vcode_block_t target, vcode_reg_t time)
17,877✔
3646
{
3647
   op_t *op = vcode_add_op(VCODE_OP_WAIT);
17,877✔
3648
   vcode_add_target(op, target);
17,877✔
3649
   vcode_add_arg(op, time);
17,877✔
3650

3651
   VCODE_ASSERT(time == VCODE_INVALID_REG
17,877✔
3652
                || vcode_reg_kind(time) == VCODE_TYPE_INT,
3653
                "wait time must have integer type");
3654
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_PROCEDURE
17,877✔
3655
                || active_unit->kind == VCODE_UNIT_PROCESS,
3656
                "wait only allowed in process or procedure");
3657
}
17,877✔
3658

3659
void emit_jump(vcode_block_t target)
49,084✔
3660
{
3661
   op_t *op = vcode_add_op(VCODE_OP_JUMP);
49,084✔
3662
   vcode_add_target(op, target);
49,084✔
3663

3664
   VCODE_ASSERT(target != VCODE_INVALID_BLOCK, "invalid jump target");
49,084✔
3665
}
49,084✔
3666

3667
vcode_var_t emit_var(vcode_type_t type, vcode_type_t bounds, ident_t name,
90,380✔
3668
                     vcode_var_flags_t flags)
3669
{
3670
   assert(active_unit != NULL);
90,380✔
3671

3672
   vcode_var_t var = active_unit->vars.count;
90,380✔
3673
   var_t *v = var_array_alloc(&(active_unit->vars));
90,380✔
3674
   memset(v, '\0', sizeof(var_t));
90,380✔
3675
   v->type     = type;
90,380✔
3676
   v->bounds   = bounds;
90,380✔
3677
   v->name     = name;
90,380✔
3678
   v->flags    = flags;
90,380✔
3679

3680
   return var;
90,380✔
3681
}
3682

3683
vcode_reg_t emit_param(vcode_type_t type, vcode_type_t bounds, ident_t name)
47,411✔
3684
{
3685
   assert(active_unit != NULL);
47,411✔
3686

3687
   param_t *p = param_array_alloc(&(active_unit->params));
47,411✔
3688
   memset(p, '\0', sizeof(param_t));
47,411✔
3689
   p->type   = type;
47,411✔
3690
   p->bounds = bounds;
47,411✔
3691
   p->name   = name;
47,411✔
3692
   p->reg    = vcode_add_reg(type);
47,411✔
3693

3694
   reg_t *rr = vcode_reg_data(p->reg);
47,411✔
3695
   rr->bounds = bounds;
47,411✔
3696

3697
   return p->reg;
47,411✔
3698
}
3699

3700
vcode_reg_t emit_load(vcode_var_t var)
79,124✔
3701
{
3702
   // Try scanning backwards through the block for another load or store to
3703
   // this variable
3704
   enum { EAGER, CONSERVATIVE, UNSAFE } state = EAGER;
79,124✔
3705
   vcode_reg_t fold = VCODE_INVALID_REG;
79,124✔
3706
   VCODE_FOR_EACH_OP(other) {
1,152,320✔
3707
      switch (state) {
1,094,709✔
3708
      case EAGER:
440,307✔
3709
         if (other->kind == VCODE_OP_LOAD && other->address == var)
440,307✔
3710
            return other->result;
4,888✔
3711
         else if (other->kind == VCODE_OP_STORE && other->address == var)
435,419✔
3712
            return other->args.items[0];
16,625✔
3713
         else if (other->kind == VCODE_OP_FCALL
418,794✔
3714
                  || other->kind == VCODE_OP_PCALL
418,794✔
3715
                  || other->kind == VCODE_OP_FILE_READ
3716
                  || other->kind == VCODE_OP_FILE_OPEN
3717
                  || other->kind == VCODE_OP_STORE_INDIRECT
3718
                  || other->kind == VCODE_OP_DEALLOCATE)
3719
            state = CONSERVATIVE;   // May write to variable
13,145✔
3720
         break;
3721

3722
      case CONSERVATIVE:
616,848✔
3723
         if (other->kind == VCODE_OP_LOAD && other->address == var
616,848✔
3724
             && fold == VCODE_INVALID_REG)
6,405✔
3725
            fold = other->result;
5,234✔
3726
         else if (other->kind == VCODE_OP_STORE && other->address == var
611,614✔
3727
                  && fold == VCODE_INVALID_REG)
3,202✔
3728
            fold = other->args.items[0];
3,014✔
3729
         else if (other->kind == VCODE_OP_INDEX && other->address == var)
608,600✔
3730
            state = UNSAFE;
3731
         else if (other->kind == VCODE_OP_CONTEXT_UPREF && other->hops == 0)
607,035✔
3732
            state = UNSAFE;   // Nested call captures variables
135✔
3733
         break;
3734

3735
      case UNSAFE:
3736
         break;
3737
      }
3738
   }
3739

3740
   if (fold != VCODE_INVALID_REG && state != UNSAFE)
57,611✔
3741
      return fold;
3742

3743
   var_t *v = vcode_var_data(var);
49,860✔
3744

3745
   op_t *op = vcode_add_op(VCODE_OP_LOAD);
49,860✔
3746
   op->address = var;
49,860✔
3747
   op->result  = vcode_add_reg(v->type);
49,860✔
3748

3749
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot load non-scalar type");
49,860✔
3750

3751
   reg_t *r = vcode_reg_data(op->result);
49,860✔
3752
   r->bounds = v->bounds;
49,860✔
3753

3754
   return op->result;
49,860✔
3755
}
3756

3757
vcode_reg_t emit_load_indirect(vcode_reg_t reg)
127,273✔
3758
{
3759
   VCODE_FOR_EACH_OP(other) {
1,481,496✔
3760
      if (other->kind == VCODE_OP_LOAD_INDIRECT
1,389,418✔
3761
          && other->args.items[0] == reg) {
208,784✔
3762
         return other->result;
9,750✔
3763
      }
3764
      else if (other->kind == VCODE_OP_FCALL
1,379,668✔
3765
               || other->kind == VCODE_OP_PCALL
1,379,668✔
3766
               || other->kind == VCODE_OP_STORE
3767
               || other->kind == VCODE_OP_STORE_INDIRECT
3768
               || other->kind == VCODE_OP_MEMSET
3769
               || other->kind == VCODE_OP_COPY
3770
               || other->kind == VCODE_OP_FILE_READ)
3771
         break;   // May write to this pointer
3772
   }
3773

3774
   op_t *op = vcode_add_op(VCODE_OP_LOAD_INDIRECT);
117,523✔
3775
   vcode_add_arg(op, reg);
117,523✔
3776

3777
   vcode_type_t rtype = vcode_reg_type(reg);
117,523✔
3778

3779
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
117,523✔
3780
                "load indirect with non-pointer argument");
3781

3782
   vcode_type_t deref = vtype_pointed(rtype);
117,523✔
3783
   op->result = vcode_add_reg(deref);
117,523✔
3784

3785
   VCODE_ASSERT(vtype_is_scalar(deref), "cannot load non-scalar type");
117,523✔
3786

3787
   vcode_reg_data(op->result)->bounds = vcode_reg_data(reg)->bounds;
117,523✔
3788

3789
   return op->result;
117,523✔
3790
}
3791

3792
void emit_store(vcode_reg_t reg, vcode_var_t var)
96,403✔
3793
{
3794
   // Any previous store to this variable in this block is dead
3795
   VCODE_FOR_EACH_OP(other) {
2,093,921✔
3796
      if (other->kind == VCODE_OP_STORE && other->address == var) {
2,015,818✔
3797
         other->kind = VCODE_OP_COMMENT;
378✔
3798
         other->comment =
756✔
3799
            xasprintf("Dead store to %s", istr(vcode_var_name(var)));
378✔
3800
         vcode_reg_array_resize(&(other->args), 0, VCODE_INVALID_REG);
378✔
3801
      }
3802
      else if (other->kind == VCODE_OP_FCALL || other->kind == VCODE_OP_PCALL)
2,015,440✔
3803
         break;   // Needs to get variable for display
3804
      else if ((other->kind == VCODE_OP_INDEX || other->kind == VCODE_OP_LOAD)
2,007,810✔
3805
               && other->address == var)
47,983✔
3806
         break;   // Previous value may be used
3807
   }
3808

3809
   var_t *v = vcode_var_data(var);
96,403✔
3810
   reg_t *r = vcode_reg_data(reg);
96,403✔
3811

3812
   op_t *op = vcode_add_op(VCODE_OP_STORE);
96,403✔
3813
   vcode_add_arg(op, reg);
96,403✔
3814
   op->address = var;
96,403✔
3815

3816
   VCODE_ASSERT(vtype_eq(v->type, r->type),
96,403✔
3817
                "variable and stored value do not have same type");
3818
   VCODE_ASSERT(vtype_is_scalar(v->type), "cannot store non-scalar type");
96,403✔
3819
}
96,403✔
3820

3821
void emit_store_indirect(vcode_reg_t reg, vcode_reg_t ptr)
19,369✔
3822
{
3823
   reg_t *p = vcode_reg_data(ptr);
19,369✔
3824
   reg_t *r = vcode_reg_data(reg);
19,369✔
3825

3826
   op_t *op = vcode_add_op(VCODE_OP_STORE_INDIRECT);
19,369✔
3827
   vcode_add_arg(op, reg);
19,369✔
3828
   vcode_add_arg(op, ptr);
19,369✔
3829

3830
   VCODE_ASSERT(vtype_kind(p->type) == VCODE_TYPE_POINTER,
19,369✔
3831
                "store indirect target is not a pointer");
3832
   VCODE_ASSERT(vtype_eq(vtype_pointed(p->type), r->type),
19,369✔
3833
                "pointer and stored value do not have same type");
3834
   VCODE_ASSERT(vtype_is_scalar(r->type), "cannot store non-scalar type");
19,369✔
3835
}
19,369✔
3836

3837
static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs,
85,863✔
3838
                              vcode_reg_t locus)
3839
{
3840
   // Reuse any previous operation in this block with the same arguments
3841
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
1,978,652✔
3842
      if (other->args.items[0] == lhs && other->args.items[1] == rhs)
99,389✔
3843
         return other->result;
6,106✔
3844
   }
3845

3846
   op_t *op = vcode_add_op(kind);
79,757✔
3847
   vcode_add_arg(op, lhs);
79,757✔
3848
   vcode_add_arg(op, rhs);
79,757✔
3849
   if (locus != VCODE_INVALID_REG)
79,757✔
3850
      vcode_add_arg(op, locus);
8,268✔
3851

3852
   op->result = vcode_add_reg(vcode_reg_type(lhs));
79,757✔
3853

3854
   vcode_type_t lhs_type = vcode_reg_type(lhs);
79,757✔
3855
   vcode_type_t rhs_type = vcode_reg_type(rhs);
79,757✔
3856

3857
   VCODE_ASSERT(vtype_eq(lhs_type, rhs_type),
79,757✔
3858
                "arguments to %s are not the same type", vcode_op_string(kind));
3859

3860
   return op->result;
3861
}
3862

3863
static vcode_reg_t emit_mul_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
65,156✔
3864
                               vcode_reg_t locus)
3865
{
3866
   int64_t lconst, rconst;
65,156✔
3867
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
65,156✔
3868
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
65,156✔
3869
   if (l_is_const && r_is_const)
65,156✔
3870
      return emit_const(vcode_reg_type(lhs), lconst * rconst);
34,188✔
3871
   else if (r_is_const && rconst == 1)
30,968✔
3872
      return lhs;
3873
   else if (l_is_const && lconst == 1)
5,542✔
3874
      return rhs;
3875
   else if ((r_is_const && rconst == 0) || (l_is_const && lconst == 0))
4,884✔
3876
      return emit_const(vcode_reg_type(lhs), 0);
76✔
3877

3878
   reg_t *lhs_r = vcode_reg_data(lhs);
4,808✔
3879
   reg_t *rhs_r = vcode_reg_data(rhs);
4,808✔
3880

3881
   vtype_t *bl = vcode_type_data(lhs_r->bounds);
4,808✔
3882
   vtype_t *br = vcode_type_data(rhs_r->bounds);
4,808✔
3883

3884
   vcode_type_t vbounds;
4,808✔
3885
   if (vcode_reg_kind(lhs) == VCODE_TYPE_REAL) {
4,808✔
3886
      const double ll = bl->rlow * br->rlow;
966✔
3887
      const double lh = bl->rlow * br->rhigh;
966✔
3888
      const double hl = bl->rhigh * br->rlow;
966✔
3889
      const double hh = bl->rhigh * br->rhigh;
966✔
3890

3891
      double min = MIN(MIN(ll, lh), MIN(hl, hh));
2,155✔
3892
      double max = MAX(MAX(ll, lh), MAX(hl, hh));
2,349✔
3893

3894
      vbounds = vtype_real(min, max);
966✔
3895
   }
3896
   else {
3897
      const int64_t ll = smul64(bl->low, br->low);
3,842✔
3898
      const int64_t lh = smul64(bl->low, br->high);
3,842✔
3899
      const int64_t hl = smul64(bl->high, br->low);
3,842✔
3900
      const int64_t hh = smul64(bl->high, br->high);
3,842✔
3901

3902
      int64_t min = MIN(MIN(ll, lh), MIN(hl, hh));
3,842✔
3903
      int64_t max = MAX(MAX(ll, lh), MAX(hl, hh));
3,842✔
3904

3905
      vtype_repr_t repr = vtype_repr(lhs_r->type);
3,842✔
3906
      if (op == VCODE_OP_TRAP_MUL && vtype_clamp_to_repr(repr, &min, &max)) {
3,842✔
3907
         op = VCODE_OP_MUL;   // Cannot overflow
657✔
3908
         locus = VCODE_INVALID_REG;
657✔
3909
      }
3910

3911
      vbounds = vtype_int(min, max);
3,842✔
3912
   }
3913

3914
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
4,808✔
3915

3916
   if (vbounds != VCODE_INVALID_TYPE)
4,808✔
3917
      vcode_reg_data(reg)->bounds = vbounds;
4,808✔
3918

3919
   return reg;
3920
}
3921

3922
vcode_reg_t emit_mul(vcode_reg_t lhs, vcode_reg_t rhs)
63,802✔
3923
{
3924
   return emit_mul_op(VCODE_OP_MUL, lhs, rhs, VCODE_INVALID_REG);
63,802✔
3925
}
3926

3927
vcode_reg_t emit_trap_mul(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
1,354✔
3928
{
3929
   vcode_reg_t result = emit_mul_op(VCODE_OP_TRAP_MUL, lhs, rhs, locus);
1,354✔
3930

3931
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
1,354✔
3932
                "trapping add may only be used with integer types");
3933

3934
   return result;
1,354✔
3935
}
3936

3937
vcode_reg_t emit_div(vcode_reg_t lhs, vcode_reg_t rhs)
2,210✔
3938
{
3939
   int64_t lconst, rconst;
2,210✔
3940
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
2,210✔
3941
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
2,210✔
3942
   if (l_is_const && r_is_const && rconst != 0)
2,210✔
3943
      return emit_const(vcode_reg_type(lhs), lconst / rconst);
39✔
3944
   else if (r_is_const && rconst == 1)
2,171✔
3945
      return lhs;
3946

3947
   vcode_reg_t reg = emit_arith(VCODE_OP_DIV, lhs, rhs, VCODE_INVALID_REG);
2,167✔
3948

3949
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
2,167✔
3950

3951
   if (bl->kind == VCODE_TYPE_INT && r_is_const && rconst != 0) {
2,167✔
3952
      reg_t *rr = vcode_reg_data(reg);
1,605✔
3953
      rr->bounds = vtype_int(bl->low / rconst, bl->high / rconst);
1,605✔
3954
   }
3955
   else if (bl->kind == VCODE_TYPE_REAL) {
562✔
3956
      reg_t *rr = vcode_reg_data(reg);
462✔
3957
      rr->bounds = vtype_real(-INFINITY, INFINITY);
462✔
3958
   }
3959

3960
   return reg;
3961
}
3962

3963
vcode_reg_t emit_exp(vcode_reg_t lhs, vcode_reg_t rhs)
184✔
3964
{
3965
   return emit_arith(VCODE_OP_EXP, lhs, rhs, VCODE_INVALID_REG);
184✔
3966
}
3967

3968
vcode_reg_t emit_trap_exp(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
1,062✔
3969
{
3970
   int64_t rconst;
1,062✔
3971
   if (vcode_reg_const(rhs, &rconst)) {
1,062✔
3972
      if (rconst == 0)
942✔
3973
         return emit_const(vcode_reg_type(lhs), 1);
297✔
3974
      else if (rconst == 1)
645✔
3975
         return lhs;
3976
   }
3977

3978
   vcode_reg_t result = emit_arith(VCODE_OP_TRAP_EXP, lhs, rhs, locus);
700✔
3979

3980
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
700✔
3981
                "trapping exp may only be used with integer types");
3982

3983
   return result;
3984
}
3985

3986
vcode_reg_t emit_mod(vcode_reg_t lhs, vcode_reg_t rhs)
277✔
3987
{
3988
   int64_t lconst, rconst;
277✔
3989
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
277✔
3990
       && lconst > 0 && rconst > 0)
19✔
3991
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
4✔
3992

3993
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
273✔
3994
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
273✔
3995

3996
   if (bl->low >= 0 && br->low >= 0) {
273✔
3997
      // If both arguments are non-negative then rem is equivalent and
3998
      // cheaper to compute
3999
      vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
96✔
4000

4001
      reg_t *rr = vcode_reg_data(reg);
96✔
4002
      rr->bounds = vtype_int(0, MAX(0, br->high - 1));
96✔
4003

4004
      return reg;
96✔
4005
   }
4006
   else
4007
      return emit_arith(VCODE_OP_MOD, lhs, rhs, VCODE_INVALID_REG);
177✔
4008
}
4009

4010
vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs)
888✔
4011
{
4012
   int64_t lconst, rconst;
888✔
4013
   if (vcode_reg_const(lhs, &lconst) && vcode_reg_const(rhs, &rconst)
888✔
4014
       && lconst > 0 && rconst > 0)
2✔
UNCOV
4015
      return emit_const(vcode_reg_type(lhs), lconst % rconst);
×
4016

4017
   vcode_reg_t reg = emit_arith(VCODE_OP_REM, lhs, rhs, VCODE_INVALID_REG);
888✔
4018

4019
   vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds);
888✔
4020
   vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds);
888✔
4021

4022
   if (bl->low >= 0 && br->low >= 0) {
888✔
4023
      reg_t *rr = vcode_reg_data(reg);
373✔
4024
      rr->bounds = vtype_int(0, br->high - 1);
373✔
4025
   }
4026

4027
   return reg;
4028
}
4029

4030
static vcode_reg_t emit_add_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
65,909✔
4031
                               vcode_reg_t locus)
4032
{
4033
   int64_t lconst, rconst;
65,909✔
4034
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
65,909✔
4035
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
65,909✔
4036
   if (l_is_const && r_is_const)
65,909✔
4037
      return emit_const(vcode_reg_type(lhs), lconst + rconst);
20,515✔
4038
   else if (r_is_const && rconst == 0)
45,394✔
4039
      return lhs;
4040
   else if (l_is_const && lconst == 0)
45,222✔
4041
      return rhs;
4042

4043
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
24,400✔
4044
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
24,400✔
4045
      reg_t *lhs_r = vcode_reg_data(lhs);
23,896✔
4046
      reg_t *rhs_r = vcode_reg_data(rhs);
23,896✔
4047

4048
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
23,896✔
4049
      vtype_t *br = vcode_type_data(rhs_r->bounds);
23,896✔
4050

4051
      int64_t rbl = sadd64(bl->low, br->low);
23,896✔
4052
      int64_t rbh = sadd64(bl->high, br->high);
23,896✔
4053

4054
      vtype_repr_t repr = vtype_repr(lhs_r->type);
23,896✔
4055
      if (op == VCODE_OP_TRAP_ADD && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
23,896✔
4056
         op = VCODE_OP_ADD;   // Cannot overflow
1,152✔
4057
         locus = VCODE_INVALID_REG;
1,152✔
4058
      }
4059

4060
      vbounds = vtype_int(rbl, rbh);
23,896✔
4061
   }
4062

4063
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
24,400✔
4064

4065
   if (vbounds != VCODE_INVALID_TYPE)
24,400✔
4066
      vcode_reg_data(reg)->bounds = vbounds;
23,896✔
4067

4068
   return reg;
4069
}
4070

4071
vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs)
59,312✔
4072
{
4073
   return emit_add_op(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG);
59,312✔
4074
}
4075

4076
vcode_reg_t emit_trap_add(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
6,597✔
4077
{
4078
   vcode_reg_t result = emit_add_op(VCODE_OP_TRAP_ADD, lhs, rhs, locus);
6,597✔
4079

4080
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
6,597✔
4081
                "trapping add may only be used with integer types");
4082

4083
   return result;
6,597✔
4084
}
4085

4086
static vcode_reg_t emit_sub_op(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs,
66,467✔
4087
                               vcode_reg_t locus)
4088
{
4089
   int64_t lconst, rconst;
66,467✔
4090
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
66,467✔
4091
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
66,467✔
4092
   if (l_is_const && r_is_const)
66,467✔
4093
      return emit_const(vcode_reg_type(lhs), lconst - rconst);
16,245✔
4094
   else if (r_is_const && rconst == 0)
50,222✔
4095
      return lhs;
4096
   else if (l_is_const && lconst == 0)
45,411✔
4097
      return emit_neg(rhs);
1,519✔
4098

4099
   vcode_type_t vbounds = VCODE_INVALID_TYPE;
43,892✔
4100
   if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) {
43,892✔
4101
      reg_t *lhs_r = vcode_reg_data(lhs);
43,366✔
4102
      reg_t *rhs_r = vcode_reg_data(rhs);
43,366✔
4103

4104
      vtype_t *bl = vcode_type_data(lhs_r->bounds);
43,366✔
4105
      vtype_t *br = vcode_type_data(rhs_r->bounds);
43,366✔
4106

4107
      int64_t rbl = ssub64(bl->low, br->high);
43,366✔
4108
      int64_t rbh = ssub64(bl->high, br->low);
43,366✔
4109

4110
      vtype_repr_t repr = vtype_repr(lhs_r->type);
43,366✔
4111
      if (op == VCODE_OP_TRAP_SUB && vtype_clamp_to_repr(repr, &rbl, &rbh)) {
43,366✔
4112
         op = VCODE_OP_SUB;   // Cannot overflow
6,143✔
4113
         locus = VCODE_INVALID_REG;
6,143✔
4114
      }
4115

4116
      vbounds = vtype_int(rbl, rbh);
43,366✔
4117
   }
4118

4119
   vcode_reg_t reg = emit_arith(op, lhs, rhs, locus);
43,892✔
4120

4121
   if (vbounds != VCODE_INVALID_TYPE)
43,892✔
4122
      vcode_reg_data(reg)->bounds = vbounds;
43,366✔
4123

4124
   return reg;
4125
}
4126

4127
vcode_reg_t emit_sub(vcode_reg_t lhs, vcode_reg_t rhs)
57,685✔
4128
{
4129
   return emit_sub_op(VCODE_OP_SUB, lhs, rhs, VCODE_INVALID_REG);
57,685✔
4130
}
4131

4132
vcode_reg_t emit_trap_sub(vcode_reg_t lhs, vcode_reg_t rhs, vcode_reg_t locus)
8,782✔
4133
{
4134
   vcode_reg_t result = emit_sub_op(VCODE_OP_TRAP_SUB, lhs, rhs, locus);
8,782✔
4135

4136
   VCODE_ASSERT(vcode_reg_kind(result) == VCODE_TYPE_INT,
8,782✔
4137
                "trapping sub may only be used with integer types");
4138

4139
   return result;
8,782✔
4140
}
4141

4142
static void vcode_calculate_var_index_type(op_t *op, var_t *var)
95,139✔
4143
{
4144
   switch (vtype_kind(var->type)) {
95,139✔
4145
   case VCODE_TYPE_CARRAY:
28,622✔
4146
      op->type = vtype_pointer(vtype_elem(var->type));
28,622✔
4147
      op->result = vcode_add_reg(op->type);
28,622✔
4148
      vcode_reg_data(op->result)->bounds = vtype_bounds(var->type);
28,622✔
4149
      break;
28,622✔
4150

4151
   case VCODE_TYPE_RECORD:
7,819✔
4152
      op->type = vtype_pointer(var->type);
7,819✔
4153
      op->result = vcode_add_reg(op->type);
7,819✔
4154
      break;
7,819✔
4155

4156
   case VCODE_TYPE_INT:
58,698✔
4157
   case VCODE_TYPE_FILE:
4158
   case VCODE_TYPE_ACCESS:
4159
   case VCODE_TYPE_REAL:
4160
   case VCODE_TYPE_UARRAY:
4161
   case VCODE_TYPE_POINTER:
4162
   case VCODE_TYPE_SIGNAL:
4163
   case VCODE_TYPE_CONTEXT:
4164
   case VCODE_TYPE_OFFSET:
4165
   case VCODE_TYPE_TRIGGER:
4166
   case VCODE_TYPE_RESOLUTION:
4167
      op->type = vtype_pointer(var->type);
58,698✔
4168
      op->result = vcode_add_reg(op->type);
58,698✔
4169
      vcode_reg_data(op->result)->bounds = var->bounds;
58,698✔
4170
      break;
58,698✔
4171

4172
   default:
UNCOV
4173
      VCODE_ASSERT(false, "variable %s cannot be indexed",
×
4174
                   istr(var->name));
4175
   }
4176
}
95,139✔
4177

4178
vcode_reg_t emit_index(vcode_var_t var, vcode_reg_t offset)
42,904✔
4179
{
4180
   // Try to find a previous index of this var by this offset
4181
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_INDEX) {
1,755,953✔
4182
      if (other->address == var
105,290✔
4183
          && ((offset == VCODE_INVALID_REG && other->args.count == 0)
9,457✔
UNCOV
4184
              || (offset != VCODE_INVALID_REG
×
4185
                  && other->args.items[0] == offset)))
×
4186
         return other->result;
9,457✔
4187
   }
4188

4189
   op_t *op = vcode_add_op(VCODE_OP_INDEX);
33,447✔
4190
   op->address = var;
33,447✔
4191

4192
   if (offset != VCODE_INVALID_REG)
33,447✔
UNCOV
4193
      vcode_add_arg(op, offset);
×
4194

4195
   vcode_calculate_var_index_type(op, vcode_var_data(var));
33,447✔
4196

4197
   if (offset != VCODE_INVALID_REG)
33,447✔
UNCOV
4198
      VCODE_ASSERT(vtype_kind(vcode_reg_type(offset)) == VCODE_TYPE_OFFSET,
×
4199
                   "index offset r%d does not have offset type", offset);
4200

4201
   return op->result;
33,447✔
4202
}
4203

4204
vcode_reg_t emit_cast(vcode_type_t type, vcode_type_t bounds, vcode_reg_t reg)
332,651✔
4205
{
4206
   if (vtype_eq(vcode_reg_type(reg), type))
332,651✔
4207
      return reg;
332,651✔
4208

4209
   vtype_kind_t from = vtype_kind(vcode_reg_type(reg));
117,946✔
4210
   vtype_kind_t to   = vtype_kind(type);
117,946✔
4211

4212
   const bool integral =
235,892✔
4213
      (from == VCODE_TYPE_OFFSET || from == VCODE_TYPE_INT)
117,946✔
4214
      && (to == VCODE_TYPE_OFFSET || to == VCODE_TYPE_INT);
117,946✔
4215

4216
   int64_t value;
117,946✔
4217
   if (integral && vcode_reg_const(reg, &value))
117,946✔
4218
      return emit_const(type, value);
21,733✔
4219

4220
   // Try to find a previous cast of this register to this type
4221
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CAST) {
1,862,303✔
4222
      if (vtype_eq(other->type, type) && other->args.items[0] == reg)
196,685✔
4223
         return other->result;
21,078✔
4224
   }
4225

4226
   op_t *op = vcode_add_op(VCODE_OP_CAST);
75,135✔
4227
   vcode_add_arg(op, reg);
75,135✔
4228
   op->type   = type;
75,135✔
4229
   op->result = vcode_add_reg(type);
75,135✔
4230

4231
   static const vcode_type_t allowed[][2] = {
75,135✔
4232
      { VCODE_TYPE_INT,    VCODE_TYPE_OFFSET  },
4233
      { VCODE_TYPE_OFFSET, VCODE_TYPE_INT     },
4234
      { VCODE_TYPE_INT,    VCODE_TYPE_INT     },
4235
      { VCODE_TYPE_INT,    VCODE_TYPE_REAL    },
4236
      { VCODE_TYPE_REAL,   VCODE_TYPE_INT     },
4237
      { VCODE_TYPE_REAL,   VCODE_TYPE_REAL    },
4238
      { VCODE_TYPE_ACCESS, VCODE_TYPE_ACCESS  },
4239
   };
4240

4241
   if (integral) {
75,135✔
4242
      vtype_t *vt = vcode_type_data(type);
74,002✔
4243
      int64_t low = vt->low, high = vt->high;
74,002✔
4244

4245
      vtype_t *rt = vcode_type_data(vcode_reg_bounds(reg));
74,002✔
4246
      low = MAX(low, rt->low);
74,002✔
4247
      high = MIN(high, rt->high);
74,002✔
4248

4249
      if (bounds != VCODE_INVALID_REG) {
74,002✔
4250
         vtype_t *bt = vcode_type_data(bounds);
46,107✔
4251
         low = MAX(low, bt->low);
46,107✔
4252
         high = MIN(high, bt->high);
46,107✔
4253
      }
4254

4255
      reg_t *rr = vcode_reg_data(op->result);
74,002✔
4256
      rr->bounds = vtype_int(low, high);
74,002✔
4257
   }
4258
   else if (bounds != VCODE_INVALID_REG)
1,133✔
4259
      vcode_reg_data(op->result)->bounds = bounds;
1,133✔
4260

4261
   for (size_t i = 0; i < ARRAY_LEN(allowed); i++) {
132,445✔
4262
      if (from == allowed[i][0] && to == allowed[i][1])
132,445✔
4263
         return op->result;
75,135✔
4264
   }
4265

UNCOV
4266
   VCODE_ASSERT(false, "invalid type conversion in cast");
×
4267
}
4268

4269
void emit_return(vcode_reg_t reg)
77,047✔
4270
{
4271
   op_t *op = vcode_add_op(VCODE_OP_RETURN);
77,047✔
4272
   if (reg != VCODE_INVALID_REG) {
77,047✔
4273
      vcode_add_arg(op, reg);
34,966✔
4274

4275
      const vtype_kind_t rkind = vcode_reg_kind(reg);
34,966✔
4276
      if (rkind == VCODE_TYPE_POINTER || rkind == VCODE_TYPE_UARRAY)
34,966✔
4277
         vcode_heap_allocate(reg);
6,585✔
4278

4279
      VCODE_ASSERT(active_unit->kind == VCODE_UNIT_FUNCTION
34,966✔
4280
                   || active_unit->kind == VCODE_UNIT_THUNK
4281
                   || active_unit->kind == VCODE_UNIT_PROPERTY,
4282
                   "returning value fron non-function unit");
4283
      VCODE_ASSERT((active_unit->kind == VCODE_UNIT_PROPERTY
34,966✔
4284
                    && rkind == VCODE_TYPE_INT)
4285
                   || vtype_eq(active_unit->result, vcode_reg_type(reg))
4286
                   || (vtype_kind(active_unit->result) == VCODE_TYPE_ACCESS
4287
                       && rkind == VCODE_TYPE_ACCESS),
4288
                   "return value incorrect type");
4289
   }
4290
}
77,047✔
4291

4292
void emit_sched_waveform(vcode_reg_t nets, vcode_reg_t nnets,
14,270✔
4293
                         vcode_reg_t values, vcode_reg_t reject,
4294
                         vcode_reg_t after)
4295
{
4296
   int64_t nconst;
14,270✔
4297
   if (vcode_reg_const(nnets, &nconst) && nconst == 0) {
14,270✔
4298
      emit_comment("Skip empty waveform");
12✔
4299
      return;
12✔
4300
   }
4301

4302
   op_t *op = vcode_add_op(VCODE_OP_SCHED_WAVEFORM);
14,258✔
4303
   vcode_add_arg(op, nets);
14,258✔
4304
   vcode_add_arg(op, nnets);
14,258✔
4305
   vcode_add_arg(op, values);
14,258✔
4306
   vcode_add_arg(op, reject);
14,258✔
4307
   vcode_add_arg(op, after);
14,258✔
4308

4309
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
14,258✔
4310
                "sched_waveform target is not signal");
4311
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
14,258✔
4312
                "sched_waveform net count is not offset type");
4313
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
14,258✔
4314
                "signal cannot be values argument for sched_waveform");
4315
}
4316

4317
void emit_force(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t values)
84✔
4318
{
4319
   op_t *op = vcode_add_op(VCODE_OP_FORCE);
84✔
4320
   vcode_add_arg(op, nets);
84✔
4321
   vcode_add_arg(op, nnets);
84✔
4322
   vcode_add_arg(op, values);
84✔
4323

4324
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
84✔
4325
                "force target is not signal");
4326
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
84✔
4327
                "force net count is not offset type");
4328
}
84✔
4329

4330
void emit_release(vcode_reg_t nets, vcode_reg_t nnets)
40✔
4331
{
4332
   op_t *op = vcode_add_op(VCODE_OP_RELEASE);
40✔
4333
   vcode_add_arg(op, nets);
40✔
4334
   vcode_add_arg(op, nnets);
40✔
4335

4336
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
40✔
4337
                "release target is not signal");
4338
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
40✔
4339
                "release net count is not offset type");
4340
}
40✔
4341

4342
void emit_disconnect(vcode_reg_t nets, vcode_reg_t nnets, vcode_reg_t reject,
32✔
4343
                     vcode_reg_t after)
4344
{
4345
   op_t *op = vcode_add_op(VCODE_OP_DISCONNECT);
32✔
4346
   vcode_add_arg(op, nets);
32✔
4347
   vcode_add_arg(op, nnets);
32✔
4348
   vcode_add_arg(op, reject);
32✔
4349
   vcode_add_arg(op, after);
32✔
4350

4351
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
32✔
4352
                "disconnect target is not signal");
4353
   VCODE_ASSERT(vcode_reg_kind(nnets) == VCODE_TYPE_OFFSET,
32✔
4354
                "disconnect net count is not offset type");
4355
}
32✔
4356

4357
void emit_cond(vcode_reg_t test, vcode_block_t btrue, vcode_block_t bfalse)
43,634✔
4358
{
4359
   int64_t tconst;
43,634✔
4360
   if (vcode_reg_const(test, &tconst)) {
43,634✔
4361
      emit_jump(!!tconst ? btrue : bfalse);
5,208✔
4362
      return;
2,653✔
4363
   }
4364

4365
   op_t *op = vcode_add_op(VCODE_OP_COND);
40,981✔
4366
   vcode_add_arg(op, test);
40,981✔
4367
   vcode_add_target(op, btrue);
40,981✔
4368
   vcode_add_target(op, bfalse);
40,981✔
4369

4370
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
40,981✔
4371
                "cond test is not a bool");
4372
   VCODE_ASSERT(btrue != VCODE_INVALID_BLOCK && bfalse != VCODE_INVALID_BLOCK,
40,981✔
4373
                "invalid cond targets");
4374
}
4375

4376
vcode_reg_t emit_neg(vcode_reg_t lhs)
9,182✔
4377
{
4378
   int64_t lconst;
9,182✔
4379
   if (vcode_reg_const(lhs, &lconst))
9,182✔
UNCOV
4380
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4381

4382
   op_t *op = vcode_add_op(VCODE_OP_NEG);
9,182✔
4383
   vcode_add_arg(op, lhs);
9,182✔
4384
   op->result = vcode_add_reg(vcode_reg_type(lhs));
9,182✔
4385

4386
   return op->result;
9,182✔
4387
}
4388

4389
vcode_reg_t emit_trap_neg(vcode_reg_t lhs, vcode_reg_t locus)
624✔
4390
{
4391
   int64_t lconst;
624✔
4392
   if (vcode_reg_const(lhs, &lconst) && lconst >= 0)
624✔
UNCOV
4393
      return emit_const(vcode_reg_type(lhs), -lconst);
×
4394
   else if (vcode_type_data(vcode_reg_data(lhs)->bounds)->low >= 0)
624✔
4395
      return emit_neg(lhs);   // Cannot overflow
280✔
4396

4397
   op_t *op = vcode_add_op(VCODE_OP_TRAP_NEG);
344✔
4398
   vcode_add_arg(op, lhs);
344✔
4399
   vcode_add_arg(op, locus);
344✔
4400

4401
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
344✔
4402
                "locus argument to trap neg must be a debug locus");
4403
   VCODE_ASSERT(vcode_reg_kind(lhs) == VCODE_TYPE_INT,
344✔
4404
                "trapping neg may only be used with integer types");
4405

4406
   return (op->result = vcode_add_reg(vcode_reg_type(lhs)));
344✔
4407
}
4408

4409
vcode_reg_t emit_abs(vcode_reg_t lhs)
993✔
4410
{
4411
   int64_t lconst;
993✔
4412
   if (vcode_reg_const(lhs, &lconst))
993✔
4413
      return emit_const(vcode_reg_type(lhs), llabs(lconst));
1✔
4414

4415
   op_t *op = vcode_add_op(VCODE_OP_ABS);
992✔
4416
   vcode_add_arg(op, lhs);
992✔
4417
   op->result = vcode_add_reg(vcode_reg_type(lhs));
992✔
4418

4419
   return op->result;
992✔
4420
}
4421

4422
void emit_comment(const char *fmt, ...)
103,907✔
4423
{
4424
#ifndef NDEBUG
4425
   va_list ap;
103,907✔
4426
   va_start(ap, fmt);
103,907✔
4427

4428
   char *buf = xvasprintf(fmt, ap);
103,907✔
4429
   for (char *p = buf + strlen(buf) - 1;
103,907✔
4430
        p >= buf && isspace_iso88591(*p); p--)
103,907✔
UNCOV
4431
      *p = '\0';
×
4432

4433
   vcode_add_op(VCODE_OP_COMMENT)->comment = buf;
103,907✔
4434
   va_end(ap);
103,907✔
4435
#endif
4436
}
103,907✔
4437

4438
vcode_reg_t emit_select(vcode_reg_t test, vcode_reg_t rtrue,
25,988✔
4439
                        vcode_reg_t rfalse)
4440
{
4441
   int64_t tconst;
25,988✔
4442
   if (vcode_reg_const(test, &tconst))
25,988✔
4443
      return !!tconst ? rtrue : rfalse;
6,104✔
4444
   else if (rtrue == rfalse)
19,884✔
4445
      return rtrue;
4446

4447
   // Find a previous identical select
4448
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_SELECT) {
422,902✔
4449
      if (other->args.items[0] == test && other->args.items[1] == rtrue
15,258✔
4450
          && other->args.items[2] == rfalse)
1,021✔
4451
         return other->result;
883✔
4452
   }
4453

4454
   op_t *op = vcode_add_op(VCODE_OP_SELECT);
18,723✔
4455
   vcode_add_arg(op, test);
18,723✔
4456
   vcode_add_arg(op, rtrue);
18,723✔
4457
   vcode_add_arg(op, rfalse);
18,723✔
4458
   op->result = vcode_add_reg(vcode_reg_type(rtrue));
18,723✔
4459

4460
   VCODE_ASSERT(vtype_eq(vcode_reg_type(test), vtype_bool()),
18,723✔
4461
                "select test must have bool type");
4462
   VCODE_ASSERT(vtype_eq(vcode_reg_type(rtrue), vcode_reg_type(rfalse)),
18,723✔
4463
                "select arguments are not the same type");
4464

4465
   return op->result;
18,723✔
4466
}
4467

4468
static vcode_reg_t emit_logical_identity(vcode_op_t op, vcode_reg_t reg, bool b)
517✔
4469
{
4470
   switch (op) {
517✔
4471
   case VCODE_OP_AND:  return b ? reg : emit_const(vtype_bool(), 0);
32✔
4472
   case VCODE_OP_OR:   return b ? emit_const(vtype_bool(), 1) : reg;
421✔
4473
   case VCODE_OP_XOR:  return b ? emit_not(reg) : reg;
16✔
4474
   case VCODE_OP_XNOR: return b ? reg : emit_not(reg);
16✔
4475
   case VCODE_OP_NAND: return b ? emit_not(reg) : emit_const(vtype_bool(), 1);
16✔
4476
   case VCODE_OP_NOR:  return b ? emit_const(vtype_bool(), 0) : emit_not(reg);
16✔
UNCOV
4477
   default:
×
4478
      fatal_trace("missing logicial identity for %s", vcode_op_string(op));
4479
   }
4480
}
4481

4482
static vcode_reg_t emit_logical(vcode_op_t op, vcode_reg_t lhs, vcode_reg_t rhs)
9,112✔
4483
{
4484
   vcode_type_t vtbool = vtype_bool();
9,112✔
4485

4486
   int64_t lconst, rconst;
9,112✔
4487
   const bool l_is_const = vcode_reg_const(lhs, &lconst);
9,112✔
4488
   const bool r_is_const = vcode_reg_const(rhs, &rconst);
9,112✔
4489
   if (l_is_const && r_is_const) {
9,112✔
4490
      switch (op) {
8✔
UNCOV
4491
      case VCODE_OP_AND:  return emit_const(vtbool, lconst && rconst);
×
4492
      case VCODE_OP_OR:   return emit_const(vtbool, lconst || rconst);
×
4493
      case VCODE_OP_XOR:  return emit_const(vtbool, lconst ^ rconst);
×
4494
      case VCODE_OP_XNOR: return emit_const(vtbool, !(lconst ^ rconst));
8✔
UNCOV
4495
      case VCODE_OP_NAND: return emit_const(vtbool, !(lconst && rconst));
×
4496
      case VCODE_OP_NOR:  return emit_const(vtbool, !(lconst || rconst));
×
4497
      default:
×
4498
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4499
      }
4500
   }
4501
   else if (l_is_const)
9,104✔
4502
      return emit_logical_identity(op, rhs, !!lconst);
412✔
4503
   else if (r_is_const)
8,692✔
4504
      return emit_logical_identity(op, lhs, !!rconst);
105✔
4505
   else if (lhs == rhs) {
8,587✔
4506
      switch (op) {
36✔
4507
      case VCODE_OP_AND:
4508
      case VCODE_OP_OR:
4509
         return lhs;
4510
      case VCODE_OP_NAND:
8✔
4511
      case VCODE_OP_NOR:
4512
         return emit_not(lhs);
8✔
4513
      case VCODE_OP_XOR:
4✔
4514
         return emit_const(vtbool, 0);
4✔
UNCOV
4515
      case VCODE_OP_XNOR:
×
4516
         return emit_const(vtbool, 1);
×
4517
      default:
×
4518
         fatal_trace("cannot constant fold logical %s", vcode_op_string(op));
4519
      }
4520
   }
4521

4522
   vcode_reg_t result = emit_arith(op, lhs, rhs, VCODE_INVALID_REG);
8,551✔
4523

4524
   VCODE_ASSERT(vtype_eq(vcode_reg_type(lhs), vtbool)
8,551✔
4525
                && vtype_eq(vcode_reg_type(rhs), vtbool),
4526
                "arguments to %s are not boolean", vcode_op_string(op));
4527

4528
   return result;
4529
}
4530

4531
vcode_reg_t emit_or(vcode_reg_t lhs, vcode_reg_t rhs)
3,044✔
4532
{
4533
   return emit_logical(VCODE_OP_OR, lhs, rhs);
3,044✔
4534
}
4535

4536
vcode_reg_t emit_and(vcode_reg_t lhs, vcode_reg_t rhs)
5,756✔
4537
{
4538
   return emit_logical(VCODE_OP_AND, lhs, rhs);
5,756✔
4539
}
4540

4541
vcode_reg_t emit_nand(vcode_reg_t lhs, vcode_reg_t rhs)
69✔
4542
{
4543
   return emit_logical(VCODE_OP_NAND, lhs, rhs);
69✔
4544
}
4545

4546
vcode_reg_t emit_nor(vcode_reg_t lhs, vcode_reg_t rhs)
70✔
4547
{
4548
   return emit_logical(VCODE_OP_NOR, lhs, rhs);
70✔
4549
}
4550

4551
vcode_reg_t emit_xor(vcode_reg_t lhs, vcode_reg_t rhs)
96✔
4552
{
4553
   return emit_logical(VCODE_OP_XOR, lhs, rhs);
96✔
4554
}
4555

4556
vcode_reg_t emit_xnor(vcode_reg_t lhs, vcode_reg_t rhs)
77✔
4557
{
4558
   return emit_logical(VCODE_OP_XNOR, lhs, rhs);
77✔
4559
}
4560

4561
vcode_reg_t emit_not(vcode_reg_t arg)
3,209✔
4562
{
4563
   int64_t cval;
3,209✔
4564
   if (vcode_reg_const(arg, &cval))
3,209✔
4565
      return emit_const(vtype_bool(), !cval);
36✔
4566

4567
   op_t *op = vcode_add_op(VCODE_OP_NOT);
3,173✔
4568
   vcode_add_arg(op, arg);
3,173✔
4569

4570
   vcode_type_t vtbool = vtype_bool();
3,173✔
4571
   VCODE_ASSERT(vtype_eq(vcode_reg_type(arg), vtbool),
3,173✔
4572
                "argument to not is not boolean");
4573

4574
   return (op->result = vcode_add_reg(vtbool));
3,173✔
4575
}
4576

4577
vcode_reg_t emit_wrap(vcode_reg_t data, const vcode_dim_t *dims, int ndims)
60,829✔
4578
{
4579
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_WRAP) {
2,259,503✔
4580
      if (other->args.count == ndims*3 + 1 && other->args.items[0] == data) {
204,085✔
4581
         bool match = true;
4582
         for (int i = 0; match && i < ndims; i++) {
26,099✔
4583
            match = other->args.items[i*3 + 1] == dims[i].left
13,092✔
4584
               && other->args.items[i*3 + 2] == dims[i].right
11,170✔
4585
               && other->args.items[i*3 + 3] == dims[i].dir;
23,906✔
4586
         }
4587
         if (match)
13,007✔
4588
            return other->result;
10,729✔
4589
      }
4590
   }
4591

4592
   op_t *op = vcode_add_op(VCODE_OP_WRAP);
50,100✔
4593
   vcode_add_arg(op, data);
50,100✔
4594
   for (int i = 0; i < ndims; i++) {
101,014✔
4595
      vcode_add_arg(op, dims[i].left);
50,914✔
4596
      vcode_add_arg(op, dims[i].right);
50,914✔
4597
      vcode_add_arg(op, dims[i].dir);
50,914✔
4598
   }
4599

4600
   vcode_type_t ptr_type = vcode_reg_type(data);
50,100✔
4601
   const vtype_kind_t ptrkind = vtype_kind(ptr_type);
50,100✔
4602
   VCODE_ASSERT(ptrkind == VCODE_TYPE_POINTER || ptrkind == VCODE_TYPE_SIGNAL,
50,100✔
4603
                "wrapped data is not pointer or signal");
4604

4605
#ifdef DEBUG
4606
   for (int i = 0; i < ndims; i++) {
101,014✔
4607
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].left)),
50,914✔
4608
                   "dimension %d left bound must be scalar", i + 1);
4609
      VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(dims[i].right)),
50,914✔
4610
                   "dimension %d right bound must be scalar", i + 1);
4611
      VCODE_ASSERT(vtype_eq(vtype_bool(), vcode_reg_type(dims[i].dir)),
50,914✔
4612
                   "dimension %d direction must be bool", i + 1);
4613
   }
4614
#endif
4615

4616
   vcode_type_t elem = (ptrkind == VCODE_TYPE_POINTER)
100,200✔
4617
      ? vtype_pointed(ptr_type) : ptr_type;
50,100✔
4618

4619
   op->result = vcode_add_reg(
50,100✔
4620
      vtype_uarray(ndims, elem, vcode_reg_bounds(data)));
4621

4622
   return op->result;
50,100✔
4623
}
4624

4625
static vcode_reg_t emit_uarray_op(vcode_op_t o, vcode_type_t rtype,
146,640✔
4626
                                  vcode_reg_t array, unsigned dim,
4627
                                  unsigned arg_index)
4628
{
4629
   // Reuse any previous operation in this block with the same arguments
4630
   VCODE_FOR_EACH_OP(other) {
1,650,994✔
4631
      if (other->kind == o && other->args.items[0] == array && other->dim == dim
1,586,377✔
4632
          && (rtype == VCODE_INVALID_TYPE
34,370✔
4633
              || vtype_eq(rtype, vcode_reg_type(other->result))))
14,984✔
4634
         return other->result;
34,370✔
4635
      else if (other->kind == VCODE_OP_WRAP && other->result == array)
1,552,007✔
4636
         return other->args.items[1 + (dim * 3) + arg_index];
47,653✔
4637
   }
4638

4639
   op_t *op = vcode_add_op(o);
64,617✔
4640
   vcode_add_arg(op, array);
64,617✔
4641
   op->dim = dim;
64,617✔
4642

4643
   vcode_type_t atype = vcode_reg_type(array);
64,617✔
4644
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
64,617✔
4645
                "cannot use %s with non-uarray type", vcode_op_string(o));
4646

4647
   vtype_t *vt = vcode_type_data(atype);
64,617✔
4648
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
64,617✔
4649

4650
   if (rtype == VCODE_INVALID_TYPE)
64,617✔
4651
      rtype = vtype_offset();
41,740✔
4652

4653
   return (op->result = vcode_add_reg(rtype));
64,617✔
4654
}
4655

4656
vcode_reg_t emit_uarray_left(vcode_reg_t array, unsigned dim)
54,235✔
4657
{
4658
   return emit_uarray_op(VCODE_OP_UARRAY_LEFT, VCODE_INVALID_TYPE,
54,235✔
4659
                         array, dim, 0);
4660
}
4661

4662
vcode_reg_t emit_uarray_right(vcode_reg_t array, unsigned dim)
38,592✔
4663
{
4664
   return emit_uarray_op(VCODE_OP_UARRAY_RIGHT, VCODE_INVALID_TYPE,
38,592✔
4665
                         array, dim, 1);
4666
}
4667

4668
vcode_reg_t emit_uarray_dir(vcode_reg_t array, unsigned dim)
53,813✔
4669
{
4670
   return emit_uarray_op(VCODE_OP_UARRAY_DIR, vtype_bool(),
53,813✔
4671
                         array, dim, 2);
4672
}
4673

4674
vcode_reg_t emit_uarray_len(vcode_reg_t array, unsigned dim)
62,119✔
4675
{
4676
   VCODE_FOR_EACH_OP(other) {
887,165✔
4677
      if (other->kind == VCODE_OP_UARRAY_LEN) {
857,855✔
4678
         if (other->args.items[0] == array && other->dim == dim)
55,950✔
4679
            return other->result;
13,245✔
4680
      }
4681
      else if (other->kind == VCODE_OP_WRAP && other->result == array) {
801,905✔
4682
         VCODE_ASSERT(dim < (other->args.count - 1) / 3,
19,564✔
4683
                      "array dimension %d out of bounds", dim);
4684

4685
         vcode_reg_t left_reg = other->args.items[dim * 3 + 1];
19,564✔
4686
         vcode_reg_t right_reg = other->args.items[dim * 3 + 2];
19,564✔
4687
         vcode_reg_t dir_reg = other->args.items[dim * 3 + 3];
19,564✔
4688
         return emit_range_length(left_reg, right_reg, dir_reg);
19,564✔
4689
      }
4690
   }
4691

4692
   op_t *op = vcode_add_op(VCODE_OP_UARRAY_LEN);
29,310✔
4693
   vcode_add_arg(op, array);
29,310✔
4694
   op->dim = dim;
29,310✔
4695

4696
   vcode_type_t atype = vcode_reg_type(array);
29,310✔
4697
   VCODE_ASSERT(vtype_kind(atype) == VCODE_TYPE_UARRAY,
29,310✔
4698
                "cannot use uarray len with non-uarray type");
4699

4700
   vtype_t *vt = vcode_type_data(atype);
29,310✔
4701
   VCODE_ASSERT(dim < vt->dims, "invalid dimension %d", dim);
29,310✔
4702

4703
   op->result = vcode_add_reg(vtype_offset());
29,310✔
4704

4705
   reg_t *rr = vcode_reg_data(op->result);
29,310✔
4706
   rr->bounds = vtype_int(0, INT64_MAX);
29,310✔
4707

4708
   return op->result;
29,310✔
4709
}
4710

4711
vcode_reg_t emit_unwrap(vcode_reg_t array)
49,206✔
4712
{
4713
   VCODE_FOR_EACH_OP(other) {
2,085,484✔
4714
      if (other->kind == VCODE_OP_WRAP && other->result == array)
2,050,549✔
4715
         return other->args.items[0];
11,726✔
4716
      else if (other->kind == VCODE_OP_UNWRAP && other->args.items[0] == array)
2,038,823✔
4717
         return other->result;
2,545✔
4718
   }
4719

4720
   op_t *op = vcode_add_op(VCODE_OP_UNWRAP);
34,935✔
4721
   vcode_add_arg(op, array);
34,935✔
4722

4723
   vtype_t *vt = vcode_type_data(vcode_reg_type(array));
34,935✔
4724
   VCODE_ASSERT(vt->kind == VCODE_TYPE_UARRAY,
34,935✔
4725
                "unwrap can only only be used with uarray types");
4726

4727
   vcode_type_t elem = vt->elem;
34,935✔
4728

4729
   vcode_type_t rtype = (vtype_kind(elem) == VCODE_TYPE_SIGNAL)
34,935✔
4730
      ? elem : vtype_pointer(elem);
34,935✔
4731

4732
   op->result = vcode_add_reg(rtype);
34,935✔
4733

4734
   reg_t *rr = vcode_reg_data(op->result);
34,935✔
4735
   rr->bounds = elem;
34,935✔
4736

4737
   return op->result;
34,935✔
4738
}
4739

4740
vcode_reg_t emit_range_null(vcode_reg_t left, vcode_reg_t right,
38,079✔
4741
                            vcode_reg_t dir)
4742
{
4743
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RANGE_NULL) {
1,783,332✔
UNCOV
4744
      if (other->args.items[0] == left
×
4745
          && other->args.items[1] == right
×
4746
          && other->args.items[2] == dir)
×
4747
         return other->result;
×
4748
   }
4749

4750
   int64_t dir_const;
38,079✔
4751
   if (vcode_reg_const(dir, &dir_const)) {
38,079✔
4752
      vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
33,774✔
4753
      vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
33,774✔
4754

4755
      if (dir_const == RANGE_TO && lbounds->low > rbounds->high)
33,774✔
4756
         return emit_const(vtype_bool(), 1);
84✔
4757
      else if (dir_const == RANGE_TO && lbounds->high <= rbounds->low)
33,690✔
4758
         return emit_const(vtype_bool(), 0);
23,295✔
4759
      else if (dir_const == RANGE_DOWNTO && rbounds->low > lbounds->high)
10,395✔
4760
         return emit_const(vtype_bool(), 1);
795✔
4761
      else if (dir_const == RANGE_DOWNTO && rbounds->high <= lbounds->low)
9,600✔
4762
         return emit_const(vtype_bool(), 0);
2,369✔
4763
      else if (dir_const == RANGE_TO)
7,231✔
4764
         return emit_cmp(VCODE_CMP_GT, left, right);
3,163✔
4765
      else
4766
         return emit_cmp(VCODE_CMP_GT, right, left);
4,068✔
4767
   }
4768

4769
   op_t *op = vcode_add_op(VCODE_OP_RANGE_NULL);
4,305✔
4770
   vcode_add_arg(op, left);
4,305✔
4771
   vcode_add_arg(op, right);
4,305✔
4772
   vcode_add_arg(op, dir);
4,305✔
4773

4774
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
4,305✔
4775
                "range left and right have different types");
4776
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
4,305✔
4777
                "dir argument to range length is not int");
4778

4779
   return (op->result = vcode_add_reg(vtype_bool()));
4,305✔
4780
}
4781

4782
vcode_reg_t emit_range_length(vcode_reg_t left, vcode_reg_t right,
19,606✔
4783
                              vcode_reg_t dir)
4784
{
4785
   vcode_reg_t left_array = VCODE_INVALID_REG,
19,606✔
4786
      right_array = VCODE_INVALID_REG,
19,606✔
4787
      dir_array = VCODE_INVALID_REG;
19,606✔
4788
   int left_dim = -1, right_dim = -1, dir_dim = -1;
19,606✔
4789

4790
   VCODE_FOR_EACH_OP(other) {
387,251✔
4791
      if (other->kind == VCODE_OP_RANGE_LENGTH
374,734✔
4792
          && other->args.items[0] == left
9,629✔
4793
          && other->args.items[1] == right
7,528✔
4794
          && other->args.items[2] == dir)
7,089✔
4795
         return other->result;
7,089✔
4796
      else if (other->kind == VCODE_OP_UARRAY_LEFT && other->result == left) {
367,645✔
4797
         left_array = other->args.items[0];
469✔
4798
         left_dim = other->dim;
469✔
4799
      }
4800
      else if (other->kind == VCODE_OP_UARRAY_RIGHT && other->result == right) {
367,176✔
4801
         right_array = other->args.items[0];
469✔
4802
         right_dim = other->dim;
469✔
4803
      }
4804
      else if (other->kind == VCODE_OP_UARRAY_DIR && other->result == dir) {
366,707✔
4805
         dir_array = other->args.items[0];
935✔
4806
         dir_dim = other->dim;
935✔
4807
      }
4808
   }
4809

4810
   if (left_array != VCODE_INVALID_REG && left_array == right_array
12,517✔
4811
       && right_array == dir_array && left_dim == right_dim
469✔
4812
       && right_dim == dir_dim)
469✔
4813
      return emit_uarray_len(left_array, left_dim);
469✔
4814

4815
   int64_t lconst, rconst, dconst;
12,048✔
4816
   if (vcode_reg_const(dir, &dconst) && vcode_reg_const(left, &lconst)
12,048✔
4817
       && vcode_reg_const(right, &rconst)) {
6,549✔
4818

4819
      int64_t diff;
2,912✔
4820
      if (dconst == RANGE_TO)
2,912✔
4821
         diff = rconst - lconst;
2,601✔
4822
      else
4823
         diff = lconst - rconst;
311✔
4824

4825
      return emit_const(vtype_offset(), diff < 0 ? 0 : diff + 1);
2,912✔
4826
   }
4827

4828
   op_t *op = vcode_add_op(VCODE_OP_RANGE_LENGTH);
9,136✔
4829
   vcode_add_arg(op, left);
9,136✔
4830
   vcode_add_arg(op, right);
9,136✔
4831
   vcode_add_arg(op, dir);
9,136✔
4832

4833
   VCODE_ASSERT(vtype_eq(vcode_reg_type(left), vcode_reg_type(right)),
9,136✔
4834
                "range left and right have different types");
4835
   VCODE_ASSERT(vcode_reg_kind(dir) == VCODE_TYPE_INT,
9,136✔
4836
                "dir argument to range length is not int");
4837

4838
   op->result = vcode_add_reg(vtype_offset());
9,136✔
4839

4840
   reg_t *rr = vcode_reg_data(op->result);
9,136✔
4841
   rr->bounds = vtype_int(0, INT64_MAX);
9,136✔
4842

4843
   return op->result;
9,136✔
4844
}
4845

4846
vcode_reg_t emit_var_upref(int hops, vcode_var_t var)
72,542✔
4847
{
4848
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_VAR_UPREF) {
633,300✔
4849
      if (other->hops == hops && other->address == var)
83,379✔
4850
         return other->result;
10,850✔
4851
   }
4852

4853
   op_t *op = vcode_add_op(VCODE_OP_VAR_UPREF);
61,692✔
4854
   op->hops    = hops;
61,692✔
4855
   op->address = var;
61,692✔
4856

4857
   VCODE_ASSERT(hops > 0, "invalid hop count");
61,692✔
4858

4859
   vcode_unit_t vu = active_unit;
61,692✔
4860
   for (int i = 0; i < hops; i++) {
137,817✔
4861
      vu = vu->context;
76,125✔
4862
      VCODE_ASSERT(vu, "hop count is greater than depth");
76,125✔
4863
   }
4864

4865
   VCODE_ASSERT(var < vu->vars.count, "upref %d is not a variable", var);
61,692✔
4866

4867
   vcode_calculate_var_index_type(op, &(vu->vars.items[var]));
61,692✔
4868

4869
   return op->result;
61,692✔
4870
}
4871

4872
vcode_reg_t emit_init_signal(vcode_type_t type, vcode_reg_t count,
20,957✔
4873
                             vcode_reg_t size, vcode_reg_t value,
4874
                             vcode_reg_t flags, vcode_reg_t locus,
4875
                             vcode_reg_t offset)
4876
{
4877
   op_t *op = vcode_add_op(VCODE_OP_INIT_SIGNAL);
20,957✔
4878
   vcode_add_arg(op, count);
20,957✔
4879
   vcode_add_arg(op, size);
20,957✔
4880
   vcode_add_arg(op, value);
20,957✔
4881
   vcode_add_arg(op, flags);
20,957✔
4882
   vcode_add_arg(op, locus);
20,957✔
4883
   if (offset != VCODE_INVALID_REG)
20,957✔
4884
      vcode_add_arg(op, offset);
7,499✔
4885

4886
   vcode_type_t vtype = vcode_reg_type(value);
20,957✔
4887
   VCODE_ASSERT(vtype_is_scalar(type), "signal type must be scalar");
20,957✔
4888
   VCODE_ASSERT(vtype_eq(vtype, type)
20,957✔
4889
                || vtype_kind(vtype) == VCODE_TYPE_POINTER,
4890
                "init signal value type does not match signal type");
4891
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
20,957✔
4892
                "locus argument to init signal must be a debug locus");
4893
   VCODE_ASSERT(offset == VCODE_INVALID_REG
20,957✔
4894
                || vcode_reg_kind(offset) == VCODE_TYPE_POINTER,
4895
                "init signal offset argument must have pointer type");
4896

4897
   return (op->result = vcode_add_reg(vtype_signal(type)));
20,957✔
4898
}
4899

4900
void emit_resolve_signal(vcode_reg_t signal, vcode_reg_t resolution)
4,324✔
4901
{
4902
   op_t *op = vcode_add_op(VCODE_OP_RESOLVE_SIGNAL);
4,324✔
4903
   vcode_add_arg(op, signal);
4,324✔
4904
   vcode_add_arg(op, resolution);
4,324✔
4905

4906
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
4,324✔
4907
                "signal argument has wrong type");
4908

4909
   vcode_type_t rtype = vcode_reg_type(resolution);
4,324✔
4910
   VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER,
4,324✔
4911
                "resolution wrapper argument must be pointer");
4912
   VCODE_ASSERT(vtype_kind(vtype_pointed(rtype)) == VCODE_TYPE_RESOLUTION,
4,324✔
4913
                "resolution wrapper argument has wrong type");
4914
}
4,324✔
4915

4916
vcode_reg_t emit_implicit_signal(vcode_type_t type, vcode_reg_t count,
108✔
4917
                                 vcode_reg_t size, vcode_reg_t locus,
4918
                                 vcode_reg_t kind, vcode_reg_t closure,
4919
                                 vcode_reg_t delay)
4920
{
4921
   op_t *op = vcode_add_op(VCODE_OP_IMPLICIT_SIGNAL);
108✔
4922
   vcode_add_arg(op, count);
108✔
4923
   vcode_add_arg(op, size);
108✔
4924
   vcode_add_arg(op, locus);
108✔
4925
   vcode_add_arg(op, kind);
108✔
4926
   vcode_add_arg(op, closure);
108✔
4927
   vcode_add_arg(op, delay);
108✔
4928

4929
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
108✔
4930
                "count argument to implicit signal is not offset");
4931
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
108✔
4932
                "kind argument to implicit signal is not offset");
4933
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
108✔
4934
                "closure argument to implicit signal is not a closure");
4935
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
108✔
4936
                "locus argument to implicit signal must be a debug locus");
4937
   VCODE_ASSERT(vcode_reg_kind(delay) == VCODE_TYPE_INT,
108✔
4938
                "delay argument to implicit signal must be time");
4939

4940
   return (op->result = vcode_add_reg(vtype_signal(type)));
108✔
4941
}
4942

4943
void emit_map_signal(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
7,108✔
4944
{
4945
   op_t *op = vcode_add_op(VCODE_OP_MAP_SIGNAL);
7,108✔
4946
   vcode_add_arg(op, src);
7,108✔
4947
   vcode_add_arg(op, dst);
7,108✔
4948
   vcode_add_arg(op, count);
7,108✔
4949

4950
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
7,108✔
4951
                "src argument to map signal is not a signal");
4952
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
7,108✔
4953
                "dst argument to map signal is not a signal");
4954
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
7,108✔
4955
                "count argument type to map signal is not offset");
4956
}
7,108✔
4957

4958
void emit_map_const(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
248✔
4959
{
4960
   op_t *op = vcode_add_op(VCODE_OP_MAP_CONST);
248✔
4961
   vcode_add_arg(op, src);
248✔
4962
   vcode_add_arg(op, dst);
248✔
4963
   vcode_add_arg(op, count);
248✔
4964

4965
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
248✔
4966
                "dst argument to map const is not a signal");
4967
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
248✔
4968
                "count argument type to map const is not offset");
4969
}
248✔
4970

4971
void emit_map_implicit(vcode_reg_t src, vcode_reg_t dst, vcode_reg_t count)
84✔
4972
{
4973
   op_t *op = vcode_add_op(VCODE_OP_MAP_IMPLICIT);
84✔
4974
   vcode_add_arg(op, src);
84✔
4975
   vcode_add_arg(op, dst);
84✔
4976
   vcode_add_arg(op, count);
84✔
4977

4978
   VCODE_ASSERT(vcode_reg_kind(src) == VCODE_TYPE_SIGNAL,
84✔
4979
                "src argument to map implicit is not a signal");
4980
   VCODE_ASSERT(vcode_reg_kind(dst) == VCODE_TYPE_SIGNAL,
84✔
4981
                "dst argument to map implicit is not a signal");
4982
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
84✔
4983
                "count argument type to map implicit is not offset");
4984
}
84✔
4985

4986
void emit_drive_signal(vcode_reg_t target, vcode_reg_t count)
12,390✔
4987
{
4988
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DRIVE_SIGNAL) {
152,316✔
4989
      if (other->args.items[0] == target && other->args.items[1] == count)
18,357✔
4990
         return;
4991
   }
4992

4993
   op_t *op = vcode_add_op(VCODE_OP_DRIVE_SIGNAL);
12,386✔
4994
   vcode_add_arg(op, target);
12,386✔
4995
   vcode_add_arg(op, count);
12,386✔
4996

4997
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
12,386✔
4998
                "target argument to drive signal is not a signal");
4999
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
12,386✔
5000
                "count argument type to drive signal is not offset");
5001
}
5002

5003
void emit_transfer_signal(vcode_reg_t target, vcode_reg_t source,
1,606✔
5004
                          vcode_reg_t count, vcode_reg_t reject,
5005
                          vcode_reg_t after)
5006
{
5007
   op_t *op = vcode_add_op(VCODE_OP_TRANSFER_SIGNAL);
1,606✔
5008
   vcode_add_arg(op, target);
1,606✔
5009
   vcode_add_arg(op, source);
1,606✔
5010
   vcode_add_arg(op, count);
1,606✔
5011
   vcode_add_arg(op, reject);
1,606✔
5012
   vcode_add_arg(op, after);
1,606✔
5013

5014
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
1,606✔
5015
                "target argument to transfer signal is not a signal");
5016
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
1,606✔
5017
                "count argument type to transfer signal is not offset");
5018
   VCODE_ASSERT(vcode_reg_kind(source) == VCODE_TYPE_SIGNAL,
1,606✔
5019
                "source argument to transfer signal is not a signal");
5020
}
1,606✔
5021

5022
vcode_reg_t emit_resolution_wrapper(vcode_type_t type, vcode_reg_t closure,
6,040✔
5023
                                    vcode_reg_t nlits)
5024
{
5025
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RESOLUTION_WRAPPER) {
101,075✔
5026
      if (other->args.items[0] == closure && other->args.items[1] == nlits)
13,419✔
UNCOV
5027
         return other->result;
×
5028
   }
5029

5030
   VCODE_ASSERT(vcode_reg_kind(closure) == VCODE_TYPE_CLOSURE,
6,040✔
5031
                "first argument to resolution wrapper must be closure");
5032

5033
   op_t *op = vcode_add_op(VCODE_OP_RESOLUTION_WRAPPER);
6,040✔
5034
   vcode_add_arg(op, closure);
6,040✔
5035
   vcode_add_arg(op, nlits);
6,040✔
5036

5037
   return (op->result = vcode_add_reg(vtype_resolution(type)));
6,040✔
5038
}
5039

5040
vcode_reg_t emit_closure(ident_t func, vcode_reg_t context, vcode_type_t rtype)
6,444✔
5041
{
5042
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CLOSURE) {
104,011✔
5043
      if (other->func == func && other->args.items[0] == context)
13,703✔
UNCOV
5044
         return other->result;
×
5045
   }
5046

5047
   op_t *op = vcode_add_op(VCODE_OP_CLOSURE);
6,444✔
5048
   vcode_add_arg(op, context);
6,444✔
5049
   op->func = func;
6,444✔
5050

5051
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
6,444✔
5052
                "invalid closure context argument");
5053

5054
   return (op->result = vcode_add_reg(vtype_closure(rtype)));
6,444✔
5055
}
5056

5057
vcode_reg_t emit_package_init(ident_t name, vcode_reg_t context)
56,762✔
5058
{
5059
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_PACKAGE_INIT) {
104,750✔
5060
      if (other->func == name)
44,974✔
5061
         return other->result;
22,277✔
5062
   }
5063

5064
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_INIT);
34,485✔
5065
   op->func = name;
34,485✔
5066
   if (context != VCODE_INVALID_REG)
34,485✔
5067
      vcode_add_arg(op, context);
243✔
5068

5069
   VCODE_ASSERT(context == VCODE_INVALID_REG
34,485✔
5070
                || vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5071
                "invalid protected init context argument");
5072
   VCODE_ASSERT(active_unit->kind == VCODE_UNIT_INSTANCE
34,485✔
5073
                || active_unit->kind == VCODE_UNIT_PACKAGE
5074
                || active_unit->kind == VCODE_UNIT_THUNK,
5075
                "cannot use package init here");
5076
   VCODE_ASSERT(name != active_unit->name, "cyclic package init");
34,485✔
5077

5078
   return (op->result = vcode_add_reg(vtype_context(name)));
34,485✔
5079
}
5080

5081
vcode_reg_t emit_protected_init(vcode_type_t type, vcode_reg_t context,
719✔
5082
                                vcode_reg_t path_name, vcode_reg_t inst_name)
5083
{
5084
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_INIT);
719✔
5085
   vcode_add_arg(op, context);
719✔
5086
   op->func = vtype_name(type);
719✔
5087

5088
   if (path_name != VCODE_INVALID_REG && inst_name != VCODE_INVALID_REG) {
719✔
5089
      vcode_add_arg(op, path_name);
548✔
5090
      vcode_add_arg(op, inst_name);
548✔
5091

5092
      VCODE_ASSERT(vcode_reg_kind(path_name) == VCODE_TYPE_UARRAY,
548✔
5093
                   "path name argument must be uarray");
5094
      VCODE_ASSERT(vcode_reg_kind(inst_name) == VCODE_TYPE_UARRAY,
548✔
5095
                   "inst name argument must be uarray");
5096
   }
5097

5098
   VCODE_ASSERT(vtype_kind(type) == VCODE_TYPE_CONTEXT,
719✔
5099
                "protected init type must be context");
5100
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
719✔
5101
                "invalid protected init context argument");
5102

5103
   return (op->result = vcode_add_reg(type));
719✔
5104
}
5105

5106
void emit_process_init(ident_t name, vcode_reg_t locus)
154✔
5107
{
5108
   op_t *op = vcode_add_op(VCODE_OP_PROCESS_INIT);
154✔
5109
   vcode_add_arg(op, locus);
154✔
5110
   op->func = name;
154✔
5111

5112
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
154✔
5113
                "locus argument to process init must be a debug locus");
5114
}
154✔
5115

5116
void emit_protected_free(vcode_reg_t obj)
411✔
5117
{
5118
   op_t *op = vcode_add_op(VCODE_OP_PROTECTED_FREE);
411✔
5119
   vcode_add_arg(op, obj);
411✔
5120

5121
   VCODE_ASSERT(vcode_reg_kind(obj) == VCODE_TYPE_CONTEXT,
411✔
5122
                "protected object type must be context");
5123
}
411✔
5124

5125
vcode_reg_t emit_context_upref(int hops)
27,320✔
5126
{
5127
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_CONTEXT_UPREF) {
216,713✔
5128
      if (other->hops == hops)
11,889✔
5129
         return other->result;
11,825✔
5130
   }
5131

5132
   op_t *op = vcode_add_op(VCODE_OP_CONTEXT_UPREF);
15,495✔
5133
   op->hops = hops;
15,495✔
5134

5135
   VCODE_ASSERT(hops >= 0, "invalid hop count");
15,495✔
5136

5137
   vcode_unit_t vu = active_unit;
15,495✔
5138
   for (int i = 0; i < hops; i++) {
27,856✔
5139
      vu = vu->context;
12,361✔
5140
      VCODE_ASSERT(vu, "hop count is greater than depth");
12,361✔
5141
   }
5142

5143
   return (op->result = vcode_add_reg(vtype_context(vu->name)));
15,495✔
5144
}
5145

5146
static vcode_reg_t emit_signal_flag(vcode_op_t opkind, vcode_reg_t nets,
823✔
5147
                                    vcode_reg_t len)
5148
{
5149
   op_t *op = vcode_add_op(opkind);
823✔
5150
   vcode_add_arg(op, nets);
823✔
5151
   vcode_add_arg(op, len);
823✔
5152

5153
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
823✔
5154
                "argument to %s is not a signal", vcode_op_string(opkind));
5155

5156
   return (op->result = vcode_add_reg(vtype_bool()));
823✔
5157
}
5158

5159
vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len)
530✔
5160
{
5161
   return emit_signal_flag(VCODE_OP_EVENT, nets, len);
530✔
5162
}
5163

5164
vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len)
293✔
5165
{
5166
   return emit_signal_flag(VCODE_OP_ACTIVE, nets, len);
293✔
5167
}
5168

5169
vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field)
52,354✔
5170
{
5171
   // Try scanning backwards through the block for another record ref
5172
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_RECORD_REF) {
3,658,712✔
5173
      if (other->args.items[0] == record && other->field == field)
687,205✔
5174
         return other->result;
5,110✔
5175
   }
5176

5177
   op_t *op = vcode_add_op(VCODE_OP_RECORD_REF);
47,244✔
5178
   op->field = field;
47,244✔
5179
   vcode_add_arg(op, record);
47,244✔
5180

5181
   vtype_t *rptype = vcode_type_data(vcode_reg_type(record));
47,244✔
5182

5183
   VCODE_ASSERT(rptype->kind == VCODE_TYPE_POINTER,
47,244✔
5184
                "argument to record ref must be a pointer");
5185

5186
   vtype_t *rtype = vcode_type_data(rptype->pointed);
47,244✔
5187
   VCODE_ASSERT(rtype->kind == VCODE_TYPE_RECORD,
47,244✔
5188
                "argument must be pointer to record or record signal");
5189

5190
   VCODE_ASSERT(field < rtype->fields.count, "invalid field %d", field);
47,244✔
5191

5192
   vcode_type_t field_type  = rtype->fields.items[field];
47,244✔
5193
   vcode_type_t bounds_type = field_type;
47,244✔
5194
   vcode_type_t result_type = field_type;
47,244✔
5195

5196
   const vtype_kind_t fkind = vtype_kind(field_type);
47,244✔
5197
   if (fkind == VCODE_TYPE_CARRAY)
47,244✔
5198
      result_type = bounds_type = vtype_elem(field_type);
6,064✔
5199
   else if (fkind == VCODE_TYPE_UARRAY) {
41,180✔
5200
      bounds_type = vtype_elem(field_type);
3,755✔
5201
      result_type = field_type;
3,755✔
5202
   }
5203

5204
   op->result = vcode_add_reg(vtype_pointer(result_type));
47,244✔
5205

5206
   reg_t *rr = vcode_reg_data(op->result);
47,244✔
5207
   rr->bounds = bounds_type;
47,244✔
5208

5209
   return op->result;
47,244✔
5210
}
5211

5212
vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset)
46,575✔
5213
{
5214
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) {
2,259,669✔
5215
      if (other->args.items[0] == array && other->args.items[1] == offset)
140,346✔
5216
         return other->result;
1,762✔
5217
   }
5218

5219
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF);
44,813✔
5220
   vcode_add_arg(op, array);
44,813✔
5221
   vcode_add_arg(op, offset);
44,813✔
5222

5223
   vcode_type_t rtype = vcode_reg_type(array);
44,813✔
5224
   VCODE_ASSERT((vtype_kind(rtype) == VCODE_TYPE_POINTER
44,813✔
5225
                 && vtype_kind(vtype_pointed(rtype)) != VCODE_TYPE_UARRAY)
5226
                || vtype_kind(rtype) == VCODE_TYPE_SIGNAL,
5227
                "argument to array ref must be a pointer or signal");
5228
   VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET,
44,813✔
5229
                "array ref offset argument must have offset type");
5230

5231
   op->result = vcode_add_reg(rtype);
44,813✔
5232

5233
   reg_t *rr = vcode_reg_data(op->result);
44,813✔
5234
   rr->bounds = vcode_reg_bounds(array);
44,813✔
5235

5236
   return op->result;
44,813✔
5237
}
5238

5239
void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count)
38,227✔
5240
{
5241
   int64_t cconst;
38,227✔
5242
   if (count != VCODE_INVALID_REG && vcode_reg_const(count, &cconst)
38,227✔
5243
       && cconst == 0)
25,133✔
5244
      return;
7,264✔
5245
   else if (dest == src)
37,251✔
5246
      return;
5247

5248
   op_t *op = vcode_add_op(VCODE_OP_COPY);
30,963✔
5249
   vcode_add_arg(op, dest);
30,963✔
5250
   vcode_add_arg(op, src);
30,963✔
5251
   if (count != VCODE_INVALID_REG)
30,963✔
5252
      vcode_add_arg(op, count);
28,908✔
5253

5254
   vcode_type_t dtype = vcode_reg_type(dest);
30,963✔
5255
   vcode_type_t stype = vcode_reg_type(src);
30,963✔
5256

5257
   vtype_kind_t dkind = vtype_kind(dtype);
30,963✔
5258
   vtype_kind_t skind = vtype_kind(stype);
30,963✔
5259

5260
   VCODE_ASSERT(dkind == VCODE_TYPE_POINTER || dkind == VCODE_TYPE_ACCESS,
30,963✔
5261
                "destination type is not a pointer or access");
5262
   VCODE_ASSERT(skind == VCODE_TYPE_POINTER || skind == VCODE_TYPE_ACCESS,
30,963✔
5263
                "source type is not a pointer or access");
5264
   VCODE_ASSERT(vtype_eq(dtype, stype),
30,963✔
5265
                "source and destination types do not match");
5266
   VCODE_ASSERT(count == VCODE_INVALID_REG
30,963✔
5267
                || vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
5268
                "count is not offset type");
5269

5270
   op->type = vtype_pointed(dtype);
30,963✔
5271
}
5272

5273
void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems)
7,888✔
5274
{
5275
   VCODE_FOR_EACH_OP(other) {
133,390✔
5276
      if (other->kind == VCODE_OP_CLEAR_EVENT)
125,574✔
5277
         break;
5278
      else if (other->kind == VCODE_OP_SCHED_EVENT
125,510✔
5279
               && other->args.items[0] == nets
6,509✔
5280
               && other->args.items[1] == n_elems)
12✔
5281
         return;
5282
   }
5283

5284
   op_t *op = vcode_add_op(VCODE_OP_SCHED_EVENT);
7,880✔
5285
   vcode_add_arg(op, nets);
7,880✔
5286
   vcode_add_arg(op, n_elems);
7,880✔
5287

5288
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
7,880✔
5289
                "nets argument to sched event must be signal");
5290
}
5291

5292
void emit_clear_event(vcode_reg_t nets, vcode_reg_t n_elems)
706✔
5293
{
5294
   VCODE_FOR_EACH_OP(other) {
3,255✔
5295
      if (other->kind == VCODE_OP_SCHED_EVENT)
2,549✔
5296
         break;
5297
      else if (other->kind == VCODE_OP_CLEAR_EVENT
2,549✔
5298
               && other->args.items[0] == nets
52✔
UNCOV
5299
               && other->args.items[1] == n_elems)
×
5300
         return;
5301
   }
5302

5303
   op_t *op = vcode_add_op(VCODE_OP_CLEAR_EVENT);
706✔
5304
   vcode_add_arg(op, nets);
706✔
5305
   vcode_add_arg(op, n_elems);
706✔
5306

5307
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
706✔
5308
                "nets argument to clear event must be signal");
5309
}
5310

5311
void emit_resume(ident_t func)
1,089✔
5312
{
5313
   op_t *op = vcode_add_op(VCODE_OP_RESUME);
1,089✔
5314
   op->func = func;
1,089✔
5315

5316
   block_t *b = &(active_unit->blocks.items[active_block]);
1,089✔
5317
   VCODE_ASSERT(b->ops.count == 1, "resume must be first op in a block");
1,089✔
5318
}
1,089✔
5319

5320
void emit_memset(vcode_reg_t ptr, vcode_reg_t value, vcode_reg_t len)
7,693✔
5321
{
5322
   int64_t lconst;
7,693✔
5323
   if (vcode_reg_const(len, &lconst) && lconst == 0)
7,693✔
5324
      return;
42✔
5325

5326
   op_t *op = vcode_add_op(VCODE_OP_MEMSET);
7,651✔
5327
   vcode_add_arg(op, ptr);
7,651✔
5328
   vcode_add_arg(op, value);
7,651✔
5329
   vcode_add_arg(op, len);
7,651✔
5330

5331
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
7,651✔
5332
                "target of memset must have pointer type");
5333
   VCODE_ASSERT(vtype_is_scalar(vcode_reg_type(value)),
7,651✔
5334
                "value of memset must have scalar type");
5335
   VCODE_ASSERT(vtype_kind(vcode_reg_type(len)) == VCODE_TYPE_OFFSET,
7,651✔
5336
                "length of memset must have offset type");
5337
}
5338

5339
void emit_case(vcode_reg_t value, vcode_block_t def, const vcode_reg_t *cases,
807✔
5340
               const vcode_block_t *blocks, int ncases)
5341
{
5342
   int64_t cval1, cval2;
807✔
5343
   bool is_const = vcode_reg_const(value, &cval1);
807✔
5344

5345
   for (int i = 0; i < ncases; i++) {
4,595✔
5346
      bool can_fold = false;
3,792✔
5347
      if (cases[i] == value)
3,792✔
5348
         can_fold = true;
5349
      else if (is_const && vcode_reg_const(cases[i], &cval2))
3,792✔
5350
         can_fold = (cval1 == cval2);
4✔
5351

5352
      if (can_fold) {
4✔
5353
         emit_jump(blocks[i]);
4✔
5354
         return;
8✔
5355
      }
5356
   }
5357

5358
   if (is_const) {
803✔
UNCOV
5359
      emit_jump(def);
×
5360
      return;
×
5361
   }
5362

5363
   op_t *op = vcode_add_op(VCODE_OP_CASE);
803✔
5364
   vcode_add_arg(op, value);
803✔
5365
   vcode_add_target(op, def);
803✔
5366

5367
   for (int i = 0; i < ncases; i++) {
4,591✔
5368
      vcode_add_arg(op, cases[i]);
3,788✔
5369
      vcode_add_target(op, blocks[i]);
3,788✔
5370

5371
#ifdef DEBUG
5372
      for (int j = 0; j < i; j++)
19,622✔
5373
         VCODE_ASSERT(cases[i] != cases[j], "duplicate case choice");
15,834✔
5374
#endif
5375
   }
5376
}
5377

5378
void emit_file_open(vcode_reg_t file, vcode_reg_t name, vcode_reg_t length,
1,550✔
5379
                    vcode_reg_t kind, vcode_reg_t status)
5380
{
5381
   op_t *op = vcode_add_op(VCODE_OP_FILE_OPEN);
1,550✔
5382
   vcode_add_arg(op, file);
1,550✔
5383
   vcode_add_arg(op, name);
1,550✔
5384
   vcode_add_arg(op, length);
1,550✔
5385
   vcode_add_arg(op, kind);
1,550✔
5386
   if (status != VCODE_INVALID_REG)
1,550✔
5387
      vcode_add_arg(op, status);
33✔
5388

5389
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
1,550✔
5390
                "file open first argument must have file pointer type");
5391
}
1,550✔
5392

5393
void emit_file_write(vcode_reg_t file, vcode_reg_t value, vcode_reg_t length)
339✔
5394
{
5395
   op_t *op = vcode_add_op(VCODE_OP_FILE_WRITE);
339✔
5396
   vcode_add_arg(op, file);
339✔
5397
   vcode_add_arg(op, value);
339✔
5398
   if (length != VCODE_INVALID_REG)
339✔
5399
      vcode_add_arg(op, length);
263✔
5400

5401
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
339✔
5402
                "file write first argument must have file pointer type");
5403
}
339✔
5404

5405
void emit_file_read(vcode_reg_t file, vcode_reg_t ptr,
120✔
5406
                    vcode_reg_t inlen, vcode_reg_t outlen)
5407
{
5408
   op_t *op = vcode_add_op(VCODE_OP_FILE_READ);
120✔
5409
   vcode_add_arg(op, file);
120✔
5410
   vcode_add_arg(op, ptr);
120✔
5411
   if (inlen != VCODE_INVALID_REG) {
120✔
5412
      vcode_add_arg(op, inlen);
56✔
5413
      if (outlen != VCODE_INVALID_REG)
56✔
5414
         vcode_add_arg(op, outlen);
44✔
5415
   }
5416

5417
   VCODE_ASSERT(vtype_is_pointer(vcode_reg_type(file), VCODE_TYPE_FILE),
120✔
5418
                "file read first argument must have file pointer type");
5419
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_POINTER,
120✔
5420
                "file read pointer argument must have pointer type");
5421
   VCODE_ASSERT(outlen == VCODE_INVALID_REG
120✔
5422
                || vtype_kind(vcode_reg_type(outlen)) == VCODE_TYPE_POINTER,
5423
                "file read outlen argument must have pointer type");
5424
}
120✔
5425

5426
vcode_reg_t emit_null(vcode_type_t type)
18,201✔
5427
{
5428
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_NULL) {
367,253✔
5429
      if (vtype_eq(vcode_reg_type(other->result), type))
10,058✔
5430
         return other->result;
5,275✔
5431
   }
5432

5433
   op_t *op = vcode_add_op(VCODE_OP_NULL);
12,926✔
5434
   op->result = vcode_add_reg(type);
12,926✔
5435

5436
   vtype_kind_t kind = vtype_kind(type);
12,926✔
5437
   VCODE_ASSERT(kind == VCODE_TYPE_POINTER || kind == VCODE_TYPE_FILE
12,926✔
5438
                || kind == VCODE_TYPE_ACCESS || kind == VCODE_TYPE_CONTEXT,
5439
                "null type must be file, access, context, or pointer");
5440

5441
   return op->result;
5442
}
5443

5444
vcode_reg_t emit_new(vcode_type_t type, vcode_reg_t length)
854✔
5445
{
5446
   op_t *op = vcode_add_op(VCODE_OP_NEW);
854✔
5447
   if (length != VCODE_INVALID_REG)
854✔
5448
      vcode_add_arg(op, length);
736✔
5449

5450
   op->result = vcode_add_reg(vtype_access(type));
854✔
5451

5452
   vtype_kind_t kind = vtype_kind(type);
854✔
5453
   VCODE_ASSERT(kind == VCODE_TYPE_INT || kind == VCODE_TYPE_RECORD
854✔
5454
                || kind == VCODE_TYPE_UARRAY || kind == VCODE_TYPE_ACCESS
5455
                || kind == VCODE_TYPE_REAL || kind == VCODE_TYPE_CONTEXT,
5456
                "new type must be int, real, record, access, or uarray");
5457
   VCODE_ASSERT(length == VCODE_INVALID_REG
854✔
5458
                || vtype_kind(vcode_reg_type(length)) == VCODE_TYPE_OFFSET,
5459
                "new length must have offset type");
5460

5461
   return op->result;
854✔
5462
}
5463

5464
void emit_null_check(vcode_reg_t ptr, vcode_reg_t locus)
3,919✔
5465
{
5466
   VCODE_FOR_EACH_OP(other) {
161,701✔
5467
      if (other->kind == VCODE_OP_NULL_CHECK && other->args.items[0] == ptr)
158,800✔
5468
         return;
5469
      else if (other->kind == VCODE_OP_NEW && other->result == ptr)
158,225✔
5470
         return;
5471
   }
5472

5473
   op_t *op = vcode_add_op(VCODE_OP_NULL_CHECK);
2,901✔
5474
   vcode_add_arg(op, ptr);
2,901✔
5475
   vcode_add_arg(op, locus);
2,901✔
5476

5477
   VCODE_ASSERT(vtype_kind(vcode_reg_type(ptr)) == VCODE_TYPE_ACCESS,
2,901✔
5478
                "null check argument must be an access");
5479
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,901✔
5480
                "locus argument to null check must be a debug locus");
5481
}
5482

5483
void emit_deallocate(vcode_reg_t ptr)
459✔
5484
{
5485
   op_t *op = vcode_add_op(VCODE_OP_DEALLOCATE);
459✔
5486
   vcode_add_arg(op, ptr);
459✔
5487

5488
   vcode_type_t ptype = vcode_reg_type(ptr);
459✔
5489
   VCODE_ASSERT(vtype_kind(ptype) == VCODE_TYPE_POINTER
459✔
5490
                && vtype_kind(vtype_pointed(ptype)) == VCODE_TYPE_ACCESS,
5491
                "deallocate argument must be pointer to access");
5492
}
459✔
5493

5494
vcode_reg_t emit_all(vcode_reg_t reg)
4,773✔
5495
{
5496
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ALL) {
226,287✔
5497
      if (other->args.items[0] == reg)
13,736✔
5498
         return other->result;
1,018✔
5499
   }
5500

5501
   op_t *op = vcode_add_op(VCODE_OP_ALL);
3,755✔
5502
   vcode_add_arg(op, reg);
3,755✔
5503

5504
   vcode_type_t vtype = vcode_reg_type(reg);
3,755✔
5505

5506
   VCODE_ASSERT(vtype_kind(vtype) == VCODE_TYPE_ACCESS,
3,755✔
5507
                "all argument must be an access");
5508

5509
   vcode_type_t pointed = vtype_pointed(vtype);
3,755✔
5510
   op->result = vcode_add_reg(vtype_pointer(pointed));
3,755✔
5511

5512
   reg_t *rr = vcode_reg_data(op->result);
3,755✔
5513
   rr->bounds = pointed;
3,755✔
5514

5515
   VCODE_ASSERT(vtype_kind(pointed) != VCODE_TYPE_OPAQUE,
3,755✔
5516
                "cannot dereference opaque type");
5517

5518
   return op->result;
5519
}
5520

5521
static vcode_reg_t emit_signal_data_op(vcode_op_t kind, vcode_reg_t sig)
19,706✔
5522
{
5523
   block_t *b = &(active_unit->blocks.items[active_block]);
19,706✔
5524
   for (int i = b->ops.count - 1; i >= 0; i--) {
483,558✔
5525
      const op_t *other = &(b->ops.items[i]);
464,591✔
5526
      if (other->kind == kind && other->args.items[0] == sig)
464,591✔
5527
         return other->result;
739✔
5528
   }
5529

5530
   op_t *op = vcode_add_op(kind);
18,967✔
5531
   vcode_add_arg(op, sig);
18,967✔
5532

5533
   vcode_type_t stype = vcode_reg_type(sig);
18,967✔
5534
   op->type = stype;
18,967✔
5535

5536
   VCODE_ASSERT(vtype_kind(stype) == VCODE_TYPE_SIGNAL,
18,967✔
5537
                "argument r%d to resolved is not a signal", sig);
5538

5539
   vcode_type_t rtype = vtype_base(stype);
18,967✔
5540

5541
   const vtype_kind_t rkind = vtype_kind(rtype);
18,967✔
5542
   if (rkind == VCODE_TYPE_CARRAY || rkind == VCODE_TYPE_UARRAY)
18,967✔
UNCOV
5543
      rtype = vtype_elem(rtype);
×
5544

5545
   VCODE_ASSERT(vtype_is_scalar(rtype),
18,967✔
5546
                "resolved signal base type must be scalar");
5547

5548
   op->result = vcode_add_reg(vtype_pointer(rtype));
18,967✔
5549

5550
   reg_t *rr = vcode_reg_data(op->result);
18,967✔
5551
   rr->bounds = rtype;
18,967✔
5552

5553
   return op->result;
18,967✔
5554
}
5555

5556
vcode_reg_t emit_resolved(vcode_reg_t sig, vcode_reg_t count)
19,481✔
5557
{
5558
   return emit_signal_data_op(VCODE_OP_RESOLVED, sig);
19,481✔
5559
}
5560

5561
vcode_reg_t emit_last_value(vcode_reg_t sig, vcode_reg_t count)
225✔
5562
{
5563
   return emit_signal_data_op(VCODE_OP_LAST_VALUE, sig);
225✔
5564
}
5565

5566
vcode_reg_t emit_last_event(vcode_reg_t signal, vcode_reg_t len)
44✔
5567
{
5568
   op_t *op = vcode_add_op(VCODE_OP_LAST_EVENT);
44✔
5569
   vcode_add_arg(op, signal);
44✔
5570
   if (len != VCODE_INVALID_REG)
44✔
5571
      vcode_add_arg(op, len);
12✔
5572

5573
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
44✔
5574
                "signal argument to last event must have signal type");
5575
   VCODE_ASSERT(len == VCODE_INVALID_REG
44✔
5576
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5577
                "length argument to last event must have offset type");
5578

5579
   return (op->result = vcode_add_reg(vtype_time()));
44✔
5580
}
5581

5582
vcode_reg_t emit_last_active(vcode_reg_t signal, vcode_reg_t len)
48✔
5583
{
5584
   op_t *op = vcode_add_op(VCODE_OP_LAST_ACTIVE);
48✔
5585
   vcode_add_arg(op, signal);
48✔
5586
   if (len != VCODE_INVALID_REG)
48✔
5587
      vcode_add_arg(op, len);
8✔
5588

5589
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
48✔
5590
                "signal argument to last active must have signal type");
5591
   VCODE_ASSERT(len == VCODE_INVALID_REG
48✔
5592
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5593
                "length argument to last active must have offset type");
5594

5595
   return (op->result = vcode_add_reg(vtype_time()));
48✔
5596
}
5597

5598
void emit_alias_signal(vcode_reg_t signal, vcode_reg_t locus)
5,578✔
5599
{
5600
   op_t *op = vcode_add_op(VCODE_OP_ALIAS_SIGNAL);
5,578✔
5601
   vcode_add_arg(op, signal);
5,578✔
5602
   vcode_add_arg(op, locus);
5,578✔
5603

5604
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
5,578✔
5605
                "signal argument must have signal type");
5606
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
5,578✔
5607
                "locus argument must have debug locus type");
5608
}
5,578✔
5609

5610
vcode_reg_t emit_driving_flag(vcode_reg_t signal, vcode_reg_t len)
48✔
5611
{
5612
   op_t *op = vcode_add_op(VCODE_OP_DRIVING);
48✔
5613
   vcode_add_arg(op, signal);
48✔
5614
   vcode_add_arg(op, len);
48✔
5615

5616
   VCODE_ASSERT(vcode_reg_kind(signal) == VCODE_TYPE_SIGNAL,
48✔
5617
                "signal argument to last active must have signal type");
5618
   VCODE_ASSERT(vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
48✔
5619
                "length argument to last active must have offset type");
5620

5621
   return (op->result = vcode_add_reg(vtype_bool()));
48✔
5622
}
5623

5624
vcode_reg_t emit_driving_value(vcode_reg_t signal, vcode_reg_t len)
160✔
5625
{
5626
   op_t *op = vcode_add_op(VCODE_OP_DRIVING_VALUE);
160✔
5627
   vcode_add_arg(op, signal);
160✔
5628
   if (len != VCODE_INVALID_REG)
160✔
5629
      vcode_add_arg(op, len);
48✔
5630

5631
   vcode_type_t signal_type = vcode_reg_type(signal);
160✔
5632

5633
   VCODE_ASSERT(vtype_kind(signal_type) == VCODE_TYPE_SIGNAL,
160✔
5634
                "signal argument to last active must have signal type");
5635
   VCODE_ASSERT(len == VCODE_INVALID_REG
160✔
5636
                || vcode_reg_kind(len) == VCODE_TYPE_OFFSET,
5637
                "length argument to last active must have offset type");
5638

5639
   vcode_type_t base_type = vtype_base(signal_type);
160✔
5640
   op->result = vcode_add_reg(vtype_pointer(base_type));
160✔
5641

5642
   reg_t *rr = vcode_reg_data(op->result);
160✔
5643
   rr->bounds = base_type;
160✔
5644

5645
   return op->result;
160✔
5646
}
5647

5648
void emit_length_check(vcode_reg_t llen, vcode_reg_t rlen, vcode_reg_t locus,
42,357✔
5649
                       vcode_reg_t dim)
5650
{
5651
   if (rlen == llen)
42,357✔
5652
      return;
5653

5654
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LENGTH_CHECK) {
253,386✔
5655
      if (other->args.items[0] == llen && other->args.items[1] == rlen)
3,545✔
5656
         return;
5657
   }
5658

5659
   op_t *op = vcode_add_op(VCODE_OP_LENGTH_CHECK);
9,620✔
5660
   vcode_add_arg(op, llen);
9,620✔
5661
   vcode_add_arg(op, rlen);
9,620✔
5662
   vcode_add_arg(op, locus);
9,620✔
5663
   if (dim != VCODE_INVALID_REG)
9,620✔
5664
      vcode_add_arg(op, dim);
36✔
5665

5666
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
9,620✔
5667
                "locus argument to length check must be a debug locus");
5668
}
5669

5670
void emit_exponent_check(vcode_reg_t exp, vcode_reg_t locus)
1,062✔
5671
{
5672
   int64_t cval;
1,062✔
5673
   if (vcode_reg_const(exp, &cval) && cval >= 0)
1,062✔
5674
      return;
398✔
5675

5676
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_EXPONENT_CHECK) {
4,537✔
5677
      if (other->args.items[0] == exp)
16✔
5678
         return;
5679
   }
5680

5681
   op_t *op = vcode_add_op(VCODE_OP_EXPONENT_CHECK);
664✔
5682
   vcode_add_arg(op, exp);
664✔
5683
   vcode_add_arg(op, locus);
664✔
5684

5685
   VCODE_ASSERT(vcode_reg_kind(exp) == VCODE_TYPE_INT,
664✔
5686
                "exp argument to exponent check must be a integer");
5687
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
664✔
5688
                "locus argument to exponent check must be a debug locus");
5689
}
5690

5691
void emit_zero_check(vcode_reg_t denom, vcode_reg_t locus)
2,894✔
5692
{
5693
   int64_t cval;
2,894✔
5694
   if (vcode_reg_const(denom, &cval) && cval != 0)
2,894✔
5695
      return;
2,775✔
5696

5697
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ZERO_CHECK) {
3,066✔
5698
      if (other->args.items[0] == denom)
64✔
5699
         return;
5700
   }
5701

5702
   op_t *op = vcode_add_op(VCODE_OP_ZERO_CHECK);
119✔
5703
   vcode_add_arg(op, denom);
119✔
5704
   vcode_add_arg(op, locus);
119✔
5705

5706
   VCODE_ASSERT(vcode_reg_kind(denom) == VCODE_TYPE_INT,
119✔
5707
                "denom argument to zero check must be a integer");
5708
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
119✔
5709
                "locus argument to zero check must be a debug locus");
5710
}
5711

5712
static bool vcode_can_elide_bounds(vcode_reg_t reg, vcode_reg_t left,
115,204✔
5713
                                   vcode_reg_t right, vcode_reg_t dir)
5714
{
5715
   int64_t dconst;
115,204✔
5716
   if (vcode_reg_const(dir, &dconst)) {
115,204✔
5717
      int64_t lconst, rconst;
100,665✔
5718
      if (vcode_reg_const(left, &lconst) && vcode_reg_const(right, &rconst)) {
100,665✔
5719
         const bool is_null = (dconst == RANGE_TO && lconst > rconst)
66,391✔
5720
            || (dconst == RANGE_DOWNTO && rconst > lconst);
137,460✔
5721

5722
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
71,070✔
5723

5724
         const bool ok_static =
142,140✔
5725
            (dconst == RANGE_TO
5726
             && bounds->low >= lconst && bounds->high <= rconst)
66,391✔
5727
            || (dconst == RANGE_DOWNTO
12,941✔
5728
                && bounds->low >= rconst && bounds->high <= lconst)
4,679✔
5729
            || (!is_null && (reg == left || reg == right));
79,620✔
5730

5731
         return ok_static;
96,779✔
5732
      }
5733
      else if (vcode_reg_kind(reg) == VCODE_TYPE_REAL) {
29,595✔
5734
         vtype_t *lbounds = vcode_type_data(vcode_reg_bounds(left));
26,900✔
5735
         vtype_t *rbounds = vcode_type_data(vcode_reg_bounds(right));
26,900✔
5736

5737
         assert(lbounds->kind == VCODE_TYPE_REAL);
26,900✔
5738
         assert(rbounds->kind == VCODE_TYPE_REAL);
26,900✔
5739

5740
         vtype_t *bounds = vcode_type_data(vcode_reg_bounds(reg));
26,900✔
5741
         assert(bounds->kind == VCODE_TYPE_REAL);
26,900✔
5742

5743
         if (isfinite(bounds->rlow) && lbounds->rlow == -DBL_MAX
26,900✔
5744
             && isfinite(bounds->rhigh) && rbounds->rhigh == DBL_MAX) {
25,709✔
5745
            // Covers the complete double range so can never overflow
5746
            return true;
5747
         }
5748
      }
5749
   }
5750

5751
   return false;
5752
}
5753

5754
static void emit_bounds_check(vcode_op_t kind, vcode_reg_t reg,
116,453✔
5755
                              vcode_reg_t left, vcode_reg_t right,
5756
                              vcode_reg_t dir, vcode_reg_t locus,
5757
                              vcode_reg_t hint)
5758
{
5759
   VCODE_FOR_EACH_MATCHING_OP(other, kind) {
4,724,360✔
5760
      if (other->args.items[0] == reg && other->args.items[1] == left
26,942✔
5761
          && other->args.items[2] == right && other->args.items[3] == dir)
1,467✔
5762
         return;
5763
   }
5764

5765
   if (vcode_can_elide_bounds(reg, left, right, dir)) {
115,204✔
5766
      emit_comment("Elided bounds check for r%d", reg);
88,229✔
5767
      return;
88,229✔
5768
   }
5769

5770
   op_t *op = vcode_add_op(kind);
26,975✔
5771
   vcode_add_arg(op, reg);
26,975✔
5772
   vcode_add_arg(op, left);
26,975✔
5773
   vcode_add_arg(op, right);
26,975✔
5774
   vcode_add_arg(op, dir);
26,975✔
5775
   vcode_add_arg(op, locus);
26,975✔
5776
   vcode_add_arg(op, hint);
26,975✔
5777

5778
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
26,975✔
5779
                "locus argument to bounds check must be a debug locus");
5780
   VCODE_ASSERT(vcode_reg_kind(hint) == VCODE_TYPE_DEBUG_LOCUS,
26,975✔
5781
                "hint argument to bounds check must be a debug locus");
5782
}
5783

5784
void emit_range_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
31,793✔
5785
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5786
{
5787
   emit_bounds_check(VCODE_OP_RANGE_CHECK, reg, left, right, dir, locus, hint);
31,793✔
5788
}
31,793✔
5789

5790
void emit_index_check(vcode_reg_t reg, vcode_reg_t left, vcode_reg_t right,
84,660✔
5791
                      vcode_reg_t dir, vcode_reg_t locus, vcode_reg_t hint)
5792
{
5793
   emit_bounds_check(VCODE_OP_INDEX_CHECK, reg, left, right, dir, locus, hint);
84,660✔
5794
}
84,660✔
5795

5796
void emit_dir_check(vcode_reg_t reg, vcode_reg_t dir, vcode_reg_t locus)
4,348✔
5797
{
5798
   if (reg == dir)
4,348✔
5799
      return;
5800

5801
   op_t *op = vcode_add_op(VCODE_OP_DIR_CHECK);
2,968✔
5802
   vcode_add_arg(op, reg);
2,968✔
5803
   vcode_add_arg(op, dir);
2,968✔
5804
   vcode_add_arg(op, locus);
2,968✔
5805

5806
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,968✔
5807
                "locus argument to dir check must be a debug locus");
5808
}
5809

5810
void emit_package_scope(vcode_reg_t locus)
59✔
5811
{
5812
   op_t *op = vcode_add_op(VCODE_OP_PACKAGE_SCOPE);
59✔
5813
   vcode_add_arg(op, locus);
59✔
5814

5815
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
59✔
5816
                "locus argument to package scope must be a debug locus");
5817
}
59✔
5818

5819
void emit_array_scope(vcode_reg_t locus, vcode_type_t type)
841✔
5820
{
5821
   op_t *op = vcode_add_op(VCODE_OP_ARRAY_SCOPE);
841✔
5822
   vcode_add_arg(op, locus);
841✔
5823
   op->type = type;
841✔
5824

5825
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
841✔
5826
                "locus argument to array scope must be a debug locus");
5827
}
841✔
5828

5829
void emit_record_scope(vcode_reg_t locus, vcode_type_t type)
2,155✔
5830
{
5831
   op_t *op = vcode_add_op(VCODE_OP_RECORD_SCOPE);
2,155✔
5832
   vcode_add_arg(op, locus);
2,155✔
5833
   op->type = type;
2,155✔
5834

5835
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
2,155✔
5836
                "locus argument to record scope must be a debug locus");
5837
}
2,155✔
5838

5839
void emit_pop_scope(void)
3,055✔
5840
{
5841
   vcode_add_op(VCODE_OP_POP_SCOPE);
3,055✔
5842
}
3,055✔
5843

5844
vcode_reg_t emit_debug_locus(object_t *obj)
232,074✔
5845
{
5846
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_DEBUG_LOCUS) {
8,571,959✔
5847
      if (other->object == obj)
1,057,922✔
5848
         return other->result;
24,059✔
5849
   }
5850

5851
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_LOCUS);
208,015✔
5852
   op->object = obj;
208,015✔
5853

5854
   return (op->result = vcode_add_reg(vtype_debug_locus()));
208,015✔
5855
}
5856

UNCOV
5857
void emit_debug_out(vcode_reg_t reg)
×
5858
{
UNCOV
5859
   op_t *op = vcode_add_op(VCODE_OP_DEBUG_OUT);
×
5860
   vcode_add_arg(op, reg);
×
5861
}
×
5862

5863
void emit_cover_stmt(uint32_t tag)
1,374✔
5864
{
5865
   op_t *op = vcode_add_op(VCODE_OP_COVER_STMT);
1,374✔
5866
   op->tag = tag;
1,374✔
5867
}
1,374✔
5868

5869
void emit_cover_branch(uint32_t tag)
657✔
5870
{
5871
   op_t *op = vcode_add_op(VCODE_OP_COVER_BRANCH);
657✔
5872
   op->tag = tag;
657✔
5873
}
657✔
5874

5875
void emit_cover_toggle(vcode_reg_t signal, uint32_t tag)
416✔
5876
{
5877
   op_t *op = vcode_add_op(VCODE_OP_COVER_TOGGLE);
416✔
5878
   vcode_add_arg(op, signal);
416✔
5879
   op->tag = tag;
416✔
5880
}
416✔
5881

5882
void emit_cover_state(vcode_reg_t signal, vcode_reg_t low, uint32_t tag)
16✔
5883
{
5884
   op_t *op = vcode_add_op(VCODE_OP_COVER_STATE);
16✔
5885
   vcode_add_arg(op, signal);
16✔
5886
   vcode_add_arg(op, low);
16✔
5887
   op->tag = tag;
16✔
5888
}
16✔
5889

5890
void emit_cover_expr(uint32_t tag)
1,142✔
5891
{
5892
   op_t *op = vcode_add_op(VCODE_OP_COVER_EXPR);
1,142✔
5893
   op->tag = tag;
1,142✔
5894
}
1,142✔
5895

5896
void emit_unreachable(vcode_reg_t locus)
1,719✔
5897
{
5898
   op_t *op = vcode_add_op(VCODE_OP_UNREACHABLE);
1,719✔
5899
   if (locus != VCODE_INVALID_REG)
1,719✔
5900
      vcode_add_arg(op, locus);
129✔
5901
}
1,719✔
5902

5903
vcode_reg_t emit_undefined(vcode_type_t type, vcode_type_t bounds)
599✔
5904
{
5905
   active_unit->flags |= UNIT_UNDEFINED;
599✔
5906

5907
   op_t *op = vcode_add_op(VCODE_OP_UNDEFINED);
599✔
5908
   op->result = vcode_add_reg(type);
599✔
5909
   vcode_reg_data(op->result)->bounds = bounds;
599✔
5910

5911
   return op->result;
599✔
5912
}
5913

5914
void emit_debug_info(const loc_t *loc)
3,155,183✔
5915
{
5916
   if (!loc_invalid_p(loc))
3,155,183✔
5917
      vcode_block_data()->last_loc = *loc;
3,081,716✔
5918
}
3,155,183✔
5919

5920
vcode_reg_t emit_link_var(vcode_reg_t context, ident_t name, vcode_type_t type)
10,655✔
5921
{
5922
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_LINK_VAR) {
379,812✔
5923
      if (other->args.items[0] == context && other->ident == name)
15,290✔
5924
         return other->result;
4,949✔
5925
   }
5926

5927
   op_t *op = vcode_add_op(VCODE_OP_LINK_VAR);
5,706✔
5928
   vcode_add_arg(op, context);
5,706✔
5929
   op->ident = name;
5,706✔
5930

5931
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
5,706✔
5932
                "first argument to link var must be context");
5933

5934
   if (vtype_kind(type) == VCODE_TYPE_CARRAY) {
5,706✔
5935
      op->result = vcode_add_reg(vtype_pointer(vtype_elem(type)));
104✔
5936
      vcode_reg_data(op->result)->bounds = vtype_bounds(type);
104✔
5937
   }
5938
   else {
5939
      op->result = vcode_add_reg(vtype_pointer(type));
5,602✔
5940
      vcode_reg_data(op->result)->bounds = type;
5,602✔
5941
   }
5942

5943
   return op->result;
5,706✔
5944
}
5945

5946
vcode_reg_t emit_link_package(ident_t name)
26,151✔
5947
{
5948
   VCODE_FOR_EACH_OP(other) {
828,617✔
5949
      if (other->kind == VCODE_OP_LINK_PACKAGE && other->ident == name)
814,805✔
5950
         return other->result;
10,079✔
5951
      else if (other->kind == VCODE_OP_PACKAGE_INIT && other->func == name)
804,726✔
5952
         return other->result;
2,260✔
5953
   }
5954

5955
   op_t *op = vcode_add_op(VCODE_OP_LINK_PACKAGE);
13,812✔
5956
   op->ident = name;
13,812✔
5957

5958
   VCODE_ASSERT(name != active_unit->name, "cannot link the current unit");
13,812✔
5959

5960
   return (op->result = vcode_add_reg(vtype_context(name)));
13,812✔
5961
}
5962

5963
void emit_enter_state(vcode_reg_t state, vcode_reg_t strong)
1,040✔
5964
{
5965
   VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ENTER_STATE) {
2,496✔
UNCOV
5966
      if (other->args.items[0] == state)
×
5967
         return;
5968
   }
5969

5970
   op_t *op = vcode_add_op(VCODE_OP_ENTER_STATE);
1,040✔
5971
   vcode_add_arg(op, state);
1,040✔
5972
   if (strong != VCODE_INVALID_REG)
1,040✔
5973
      vcode_add_arg(op, strong);
24✔
5974

5975
   VCODE_ASSERT(vcode_reg_kind(state) == VCODE_TYPE_INT,
1,040✔
5976
                "state must have integer type");
5977
   VCODE_ASSERT(strong == VCODE_INVALID_REG
1,040✔
5978
                || vtype_eq(vcode_reg_type(strong), vtype_bool()),
5979
                "strong argument not is not boolean");
5980
}
5981

5982
vcode_reg_t emit_reflect_value(vcode_reg_t value, vcode_reg_t context,
64✔
5983
                               vcode_reg_t locus, vcode_reg_t bounds)
5984
{
5985
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_VALUE);
64✔
5986
   vcode_add_arg(op, value);
64✔
5987
   vcode_add_arg(op, context);
64✔
5988
   vcode_add_arg(op, locus);
64✔
5989
   if (bounds != VCODE_INVALID_REG)
64✔
5990
      vcode_add_arg(op, bounds);
8✔
5991

5992
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
64✔
5993
                "invalid reflect value context argument");
5994
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
64✔
5995
                "locus argument to reflect value must be a debug locus");
5996

5997
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
64✔
5998
}
5999

6000
vcode_reg_t emit_reflect_subtype(vcode_reg_t context, vcode_reg_t locus,
56✔
6001
                                 vcode_reg_t bounds)
6002
{
6003
   op_t *op = vcode_add_op(VCODE_OP_REFLECT_SUBTYPE);
56✔
6004
   vcode_add_arg(op, context);
56✔
6005
   vcode_add_arg(op, locus);
56✔
6006
   if (bounds != VCODE_INVALID_REG)
56✔
UNCOV
6007
      vcode_add_arg(op, bounds);
×
6008

6009
   VCODE_ASSERT(vcode_reg_kind(context) == VCODE_TYPE_CONTEXT,
56✔
6010
                "invalid reflect value context argument");
6011
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
56✔
6012
                "locus argument to reflect value must be a debug locus");
6013

6014
   return (op->result = vcode_add_reg(vtype_access(vtype_opaque())));
56✔
6015
}
6016

6017
vcode_reg_t emit_function_trigger(ident_t func, const vcode_reg_t *args,
292✔
6018
                                  int nargs)
6019
{
6020
   op_t *op = vcode_add_op(VCODE_OP_FUNCTION_TRIGGER);
292✔
6021
   op->func = func;
292✔
6022

6023
   for (int i = 0; i < nargs; i++)
772✔
6024
      vcode_add_arg(op, args[i]);
480✔
6025

6026
   return (op->result = vcode_add_reg(vtype_trigger()));
292✔
6027
}
6028

6029
vcode_reg_t emit_or_trigger(vcode_reg_t left, vcode_reg_t right)
45✔
6030
{
6031
   op_t *op = vcode_add_op(VCODE_OP_OR_TRIGGER);
45✔
6032
   vcode_add_arg(op, left);
45✔
6033
   vcode_add_arg(op, right);
45✔
6034

6035
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_TRIGGER,
45✔
6036
                "or trigger left argument must be trigger");
6037
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_TRIGGER,
45✔
6038
                "or trigger right argument must be trigger");
6039

6040
   return (op->result = vcode_add_reg(vtype_trigger()));
45✔
6041
}
6042

6043
vcode_reg_t emit_cmp_trigger(vcode_reg_t left, vcode_reg_t right)
87✔
6044
{
6045
   op_t *op = vcode_add_op(VCODE_OP_CMP_TRIGGER);
87✔
6046
   vcode_add_arg(op, left);
87✔
6047
   vcode_add_arg(op, right);
87✔
6048

6049
   VCODE_ASSERT(vcode_reg_kind(left) == VCODE_TYPE_SIGNAL,
87✔
6050
                "cmp trigger left argument must be signal");
6051
   VCODE_ASSERT(vcode_reg_kind(right) == VCODE_TYPE_INT,
87✔
6052
                "cmp trigger right argument must be integer");
6053

6054
   return (op->result = vcode_add_reg(vtype_trigger()));
87✔
6055
}
6056

6057
void emit_add_trigger(vcode_reg_t trigger)
501✔
6058
{
6059
   op_t *op = vcode_add_op(VCODE_OP_ADD_TRIGGER);
501✔
6060
   vcode_add_arg(op, trigger);
501✔
6061

6062
   VCODE_ASSERT(vcode_reg_kind(trigger) == VCODE_TYPE_TRIGGER,
501✔
6063
                "add trigger argument must be trigger");
6064
}
501✔
6065

6066
vcode_reg_t emit_port_conversion(vcode_reg_t driving, vcode_reg_t effective)
272✔
6067
{
6068
   op_t *op = vcode_add_op(VCODE_OP_PORT_CONVERSION);
272✔
6069
   vcode_add_arg(op, driving);
272✔
6070
   if (effective != VCODE_INVALID_REG && effective != driving)
272✔
6071
      vcode_add_arg(op, effective);
24✔
6072

6073
   VCODE_ASSERT(vcode_reg_kind(driving) == VCODE_TYPE_CLOSURE,
272✔
6074
                "port conversion argument must be a closure");
6075
   VCODE_ASSERT(effective == VCODE_INVALID_REG
272✔
6076
                || vcode_reg_kind(effective) == VCODE_TYPE_CLOSURE,
6077
                "port conversion argument must be a closure");
6078

6079
   return (op->result = vcode_add_reg(vtype_conversion()));
272✔
6080
}
6081

6082
vcode_reg_t emit_bind_external(vcode_reg_t locus, ident_t scope,
261✔
6083
                               vcode_type_t type, vcode_type_t bounds)
6084
{
6085
   op_t *op = vcode_add_op(VCODE_OP_BIND_EXTERNAL);
261✔
6086
   vcode_add_arg(op, locus);
261✔
6087
   op->type  = type;
261✔
6088
   op->ident = scope;
261✔
6089

6090
   VCODE_ASSERT(vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
261✔
6091
                "bind external argument must be locus");
6092

6093
   op->result = vcode_add_reg(vtype_pointer(type));
261✔
6094
   vcode_reg_data(op->result)->bounds = bounds;
261✔
6095
   return op->result;
261✔
6096
}
6097

6098
void emit_put_conversion(vcode_reg_t cf, vcode_reg_t target, vcode_reg_t count,
456✔
6099
                         vcode_reg_t values)
6100
{
6101
   op_t *op = vcode_add_op(VCODE_OP_PUT_CONVERSION);
456✔
6102
   vcode_add_arg(op, cf);
456✔
6103
   vcode_add_arg(op, target);
456✔
6104
   vcode_add_arg(op, count);
456✔
6105
   vcode_add_arg(op, values);
456✔
6106

6107
   VCODE_ASSERT(vcode_reg_kind(target) == VCODE_TYPE_SIGNAL,
456✔
6108
                "put conversion target is not signal");
6109
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
456✔
6110
                "put conversion net count is not offset type");
6111
   VCODE_ASSERT(vcode_reg_kind(values) != VCODE_TYPE_SIGNAL,
456✔
6112
                "signal cannot be values argument for put conversion");
6113
   VCODE_ASSERT(vcode_reg_kind(cf) == VCODE_TYPE_CONVERSION,
456✔
6114
                "cf argument to put conversion must be conversion function");
6115
}
456✔
6116

6117
void emit_convert_in(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
376✔
6118
{
6119
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_IN);
376✔
6120
   vcode_add_arg(op, conv);
376✔
6121
   vcode_add_arg(op, nets);
376✔
6122
   vcode_add_arg(op, count);
376✔
6123

6124
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
376✔
6125
                "conv argument to convert must be a port conversion");
6126
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
376✔
6127
                "nets argument to convert must be a signal");
6128
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
376✔
6129
                "count argument to convert must be offset");
6130
}
376✔
6131

6132
void emit_convert_out(vcode_reg_t conv, vcode_reg_t nets, vcode_reg_t count)
432✔
6133
{
6134
   op_t *op = vcode_add_op(VCODE_OP_CONVERT_OUT);
432✔
6135
   vcode_add_arg(op, conv);
432✔
6136
   vcode_add_arg(op, nets);
432✔
6137
   vcode_add_arg(op, count);
432✔
6138

6139
   VCODE_ASSERT(vcode_reg_kind(conv) == VCODE_TYPE_CONVERSION,
432✔
6140
                "conv argument to convert must be a port conversion");
6141
   VCODE_ASSERT(vcode_reg_kind(nets) == VCODE_TYPE_SIGNAL,
432✔
6142
                "nets argument to convert must be a signal");
6143
   VCODE_ASSERT(vcode_reg_kind(count) == VCODE_TYPE_OFFSET,
432✔
6144
                "count argument to convert must be offset");
6145
}
432✔
6146

6147
void emit_bind_foreign(vcode_reg_t spec, vcode_reg_t length, vcode_reg_t locus)
1,302✔
6148
{
6149
   op_t *op = vcode_add_op(VCODE_OP_BIND_FOREIGN);
1,302✔
6150
   vcode_add_arg(op, spec);
1,302✔
6151
   vcode_add_arg(op, length);
1,302✔
6152
   if (locus != VCODE_INVALID_REG)
1,302✔
6153
      vcode_add_arg(op, locus);
1,070✔
6154

6155
   VCODE_ASSERT(vcode_reg_kind(spec) == VCODE_TYPE_POINTER,
1,302✔
6156
                "spec argument to bind foreign must be a pointer");
6157
   VCODE_ASSERT(vcode_reg_kind(length) == VCODE_TYPE_OFFSET,
1,302✔
6158
                "length argument to bind foreign must be offset");
6159
   VCODE_ASSERT(locus == VCODE_INVALID_REG
1,302✔
6160
                || vcode_reg_kind(locus) == VCODE_TYPE_DEBUG_LOCUS,
6161
                "locus argument to bind foreign value must be a debug locus");
6162
}
1,302✔
6163

6164
vcode_reg_t emit_instance_name(vcode_reg_t kind)
1,018✔
6165
{
6166
   op_t *op = vcode_add_op(VCODE_OP_INSTANCE_NAME);
1,018✔
6167
   vcode_add_arg(op, kind);
1,018✔
6168

6169
   VCODE_ASSERT(vcode_reg_kind(kind) == VCODE_TYPE_OFFSET,
1,018✔
6170
                "kind argument to instance name must be offset");
6171

6172
   vcode_type_t vchar = vtype_char();
1,018✔
6173
   return (op->result = vcode_add_reg(vtype_uarray(1, vchar, vchar)));
1,018✔
6174
}
6175

6176
void vcode_walk_dependencies(vcode_unit_t vu, vcode_dep_fn_t fn, void *ctx)
21,028✔
6177
{
6178
   vcode_state_t state;
21,028✔
6179
   vcode_state_save(&state);
21,028✔
6180

6181
   vcode_select_unit(vu);
21,028✔
6182

6183
   const int nblocks = vcode_count_blocks();
21,028✔
6184
   for (int i = 0; i < nblocks; i++) {
74,032✔
6185
      vcode_select_block(i);
53,004✔
6186

6187
      const int nops = vcode_count_ops();
53,004✔
6188
      for (int op = 0; op < nops; op++) {
859,858✔
6189
         switch (vcode_get_op(op)) {
806,854✔
6190
         case VCODE_OP_LINK_PACKAGE:
4,993✔
6191
            (*fn)(vcode_get_ident(op), ctx);
4,993✔
6192
            break;
4,993✔
6193
         case VCODE_OP_FCALL:
36,694✔
6194
         case VCODE_OP_PCALL:
6195
         case VCODE_OP_CLOSURE:
6196
         case VCODE_OP_PROTECTED_INIT:
6197
         case VCODE_OP_PACKAGE_INIT:
6198
         case VCODE_OP_FUNCTION_TRIGGER:
6199
            (*fn)(vcode_get_func(op), ctx);
36,694✔
6200
            break;
36,694✔
6201
         default:
6202
            break;
6203
         }
6204
      }
6205
   }
6206

6207
   vcode_state_restore(&state);
21,028✔
6208
}
21,028✔
6209

6210
#if VCODE_CHECK_UNIONS
6211
#define OP_USE_COUNT_U0(x)                                              \
6212
   (OP_HAS_IDENT(x) + OP_HAS_FUNC(x) + OP_HAS_ADDRESS(x))
6213
#define OP_USE_COUNT_U1(x)                                              \
6214
   (OP_HAS_CMP(x) + OP_HAS_VALUE(x) + OP_HAS_REAL(x) +                  \
6215
    OP_HAS_COMMENT(x) + OP_HAS_DIM(x) + OP_HAS_TARGET(x) +              \
6216
    OP_HAS_HOPS(x) + OP_HAS_FIELD(x) + OP_HAS_TAG(x))
6217

6218
__attribute__((constructor))
6219
static void vcode_check_unions(void)
6220
{
6221
   printf("sizeof(op_t) = %ld\n", sizeof(op_t));
6222
   for (int i = 0; i < 256; i++) {
6223
      assert(OP_USE_COUNT_U0(i) <= 1);
6224
      assert(OP_USE_COUNT_U1(i) <= 1);
6225
   }
6226
}
6227
#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